Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add extension for phpunit >= 10 #45

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions src/Extension/TestFinishedSubscriber.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

declare(strict_types=1);

namespace VCR\PHPUnit\TestListener\Extension;

use PHPUnit\Event\Test\Finished;
use PHPUnit\Event\Test\FinishedSubscriber;
use VCR\PHPUnit\TestListener\VCRTestHandler;

final class TestFinishedSubscriber implements FinishedSubscriber
{
public function notify(Finished $event): void
{
VCRTestHandler::onEnd();
}
}
23 changes: 23 additions & 0 deletions src/Extension/TestPreparationStartedSubscriber.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace VCR\PHPUnit\TestListener\Extension;

use PHPUnit\Event\Code\TestMethod;
use PHPUnit\Event\Test\PreparationStarted;
use PHPUnit\Event\Test\PreparationStartedSubscriber;
use VCR\PHPUnit\TestListener\VCRTestHandler;

final class TestPreparationStartedSubscriber implements PreparationStartedSubscriber
{
public function notify(PreparationStarted $event): void
{
$testMethod = $event->test();
if (!$testMethod instanceof TestMethod) {
return;
}

VCRTestHandler::onStart($testMethod->className(), $testMethod->name());
}
}
32 changes: 32 additions & 0 deletions src/Extension/VCRExtension.php
Copy link
Author

@marmichalski marmichalski Jan 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not entirely sure how to go on about testing this.

I can create github actions that install different phpunit versions to test that both TestListener and Extension work.

Alternatively, just drop the TestListener within this PR and test and require phpunit >= 10.

Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

declare(strict_types=1);

namespace VCR\PHPUnit\TestListener\Extension;

use PHPUnit\Runner\Extension\Extension;
use PHPUnit\Runner\Extension\Facade;
use PHPUnit\Runner\Extension\ParameterCollection;
use PHPUnit\TextUI\Configuration\Configuration;

/**
* An Extension that integrates with PHP-VCR.
*
* Here is an example XML configuration for activating this listener in PHPUnit >= 10.
*
* <code>
* <extensions>
* <bootstrap class="VCR\PHPUnit\TestListener\VcrExtension" />
* </extensions>
* </code>
*/
final class VCRExtension implements Extension
{
public function bootstrap(Configuration $configuration, Facade $facade, ParameterCollection $parameters): void
{
$facade->registerSubscribers(
new TestPreparationStartedSubscriber(),
new TestFinishedSubscriber()
);
}
}
74 changes: 74 additions & 0 deletions src/VCRTestHandler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<?php
declare(strict_types=1);

namespace VCR\PHPUnit\TestListener;

use PHPUnit\Framework\AssertionFailedError;
use PHPUnit\Framework\Test;
use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\TestListener;
use PHPUnit\Framework\TestSuite;
use PHPUnit\Framework\Warning;
use VCR\VCR;

final class VCRTestHandler
{
private function __construct() {}

public static function onStart(string $class, string $method): void
{
if (!method_exists($class, $method)) {
return;
}

$reflection = new \ReflectionMethod($class, $method);
$docBlock = $reflection->getDocComment();

// Use regex to parse the doc_block for a specific annotation
$parsed = self::parseDocBlock($docBlock, '@vcr');
$cassetteName = array_pop($parsed);

if (empty($cassetteName)) {
return;
}

// If the cassette name ends in .json, then use the JSON storage format
if (substr($cassetteName, -5) === '.json') {
VCR::configure()->setStorage('json');
}

VCR::turnOn();
VCR::insertCassette($cassetteName);
}

public static function onEnd(): void
{
VCR::turnOff();
}

private static function parseDocBlock($docBlock, $tag): array
{
$matches = [];

if (empty($docBlock)) {
return $matches;
}

$regex = "/{$tag} (.*)(\\r\\n|\\r|\\n)/U";
preg_match_all($regex, $docBlock, $matches);

if (empty($matches[1])) {
return array();
}

// Removed extra index
$matches = $matches[1];

// Trim the results, array item by array item
foreach ($matches as $ix => $match) {
$matches[$ix] = trim($match);
}

return $matches;
}
}
54 changes: 3 additions & 51 deletions src/VCRTestListener.php
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@
/**
* A TestListener that integrates with PHP-VCR.
*
* Here is an example XML configuration for activating this listener:
* Here is an example XML configuration for activating this listener in PHPUnit < 10.
*
* <code>
* <listeners>
@@ -32,61 +32,13 @@ public function startTest(Test $test): void
{
$class = \get_class($test);
\assert($test instanceof TestCase);
$method = $test->getName(false);

if (!method_exists($class, $method)) {
return;
}

$reflection = new \ReflectionMethod($class, $method);
$docBlock = $reflection->getDocComment();

// Use regex to parse the doc_block for a specific annotation
$parsed = self::parseDocBlock($docBlock, '@vcr');
$cassetteName = array_pop($parsed);

if (empty($cassetteName)) {
return;
}

// If the cassette name ends in .json, then use the JSON storage format
if (substr($cassetteName, -5) === '.json') {
VCR::configure()->setStorage('json');
}

VCR::turnOn();
VCR::insertCassette($cassetteName);
}

private static function parseDocBlock($docBlock, $tag): array
{
$matches = [];

if (empty($docBlock)) {
return $matches;
}

$regex = "/{$tag} (.*)(\\r\\n|\\r|\\n)/U";
preg_match_all($regex, $docBlock, $matches);

if (empty($matches[1])) {
return array();
}

// Removed extra index
$matches = $matches[1];

// Trim the results, array item by array item
foreach ($matches as $ix => $match) {
$matches[$ix] = trim($match);
}

return $matches;
VCRTestHandler::onStart($class, $test->getName(false));
}

public function endTest(Test $test, float $time): void
{
VCR::turnOff();
VCRTestHandler::onEnd();
}

public function addError(Test $test, \Throwable $t, float $time): void