diff --git a/src/Framework/Environment.php b/src/Framework/Environment.php index e9d9f8d4..29a05a3f 100644 --- a/src/Framework/Environment.php +++ b/src/Framework/Environment.php @@ -27,6 +27,9 @@ class Environment /** Thread number when run tests in multi threads */ public const THREAD = 'NETTE_TESTER_THREAD'; + /** Should Tester update snapshots? */ + public const UPDATE_SNAPSHOTS = 'NETTE_TESTER_UPDATE_SNAPSHOTS'; + /** @var bool used for debugging Tester itself */ public static $debugMode = true; @@ -108,6 +111,11 @@ public static function setupErrors(): void self::removeOutputBuffers(); echo "\nFatal error: $error[message] in $error[file] on line $error[line]\n"; } + } elseif (getenv(self::UPDATE_SNAPSHOTS) && Snapshot::$updatedSnapshots) { + self::removeOutputBuffers(); + echo "\nThe following snapshots were updated, please make sure they are correct:\n" + . implode("\n", Snapshot::$updatedSnapshots) . "\n"; + exit(Runner\Job::CODE_FAIL); } elseif (self::$checkAssertions && !Assert::$counter) { self::removeOutputBuffers(); echo "\nError: This test forgets to execute an assertion.\n"; diff --git a/src/Framework/Snapshot.php b/src/Framework/Snapshot.php new file mode 100644 index 00000000..5fa74ce5 --- /dev/null +++ b/src/Framework/Snapshot.php @@ -0,0 +1,91 @@ +setEnvironmentVariable(Environment::COVERAGE, $coverageFile); } + if ($this->options['--update-snapshots']) { + $runner->setEnvironmentVariable(Environment::UPDATE_SNAPSHOTS, '1'); + } if ($this->options['-o'] !== null) { ob_clean(); @@ -117,6 +120,7 @@ private function loadOptions(): CommandLine --colors [1|0] Enable or disable colors. --coverage Generate code coverage report to file. --coverage-src Path to source code. + --update-snapshots Create or update snapshot files. Tests with snapshot changes will be marked as skipped. -h | --help This help. XX diff --git a/src/bootstrap.php b/src/bootstrap.php index 7c6b9a90..f43a16d8 100644 --- a/src/bootstrap.php +++ b/src/bootstrap.php @@ -16,6 +16,7 @@ require __DIR__ . '/Framework/TestCase.php'; require __DIR__ . '/Framework/DomQuery.php'; require __DIR__ . '/Framework/FileMutator.php'; +require __DIR__ . '/Framework/Snapshot.php'; require __DIR__ . '/CodeCoverage/Collector.php'; require __DIR__ . '/Runner/Job.php'; diff --git a/tests/Framework/.gitignore b/tests/Framework/.gitignore new file mode 100644 index 00000000..373f5f3d --- /dev/null +++ b/tests/Framework/.gitignore @@ -0,0 +1 @@ +snapshots/ diff --git a/tests/Framework/Snapshot.match.phpt b/tests/Framework/Snapshot.match.phpt new file mode 100644 index 00000000..266247ad --- /dev/null +++ b/tests/Framework/Snapshot.match.phpt @@ -0,0 +1,21 @@ + 42], 'existingSnapshot'); + +Assert::exception(function () { + Snapshot::match(['answer' => 43], 'existingSnapshot'); +}, AssertException::class, "Snapshot existingSnapshot: %a% should be equal to %a%"); + +Assert::exception(function () { + Snapshot::match('value', 'nonExistingSnapshot'); +}, AssertException::class, "Missing snapshot file '%A%', use --update-snapshots option to generate it."); diff --git a/tests/Framework/Snapshot.update.phpt b/tests/Framework/Snapshot.update.phpt new file mode 100644 index 00000000..b8db4a6b --- /dev/null +++ b/tests/Framework/Snapshot.update.phpt @@ -0,0 +1,43 @@ + 42], 'newSnapshot'); +Assert::true(file_exists(Snapshot::$snapshotDir . '/Snapshot.update.newSnapshot.phps')); +Assert::contains('42', file_get_contents(Snapshot::$snapshotDir . '/Snapshot.update.newSnapshot.phps')); + +// existing + +file_put_contents( + Snapshot::$snapshotDir . '/Snapshot.update.updatedSnapshot.phps', + ' 43);' . PHP_EOL +); + +Assert::true(file_exists(Snapshot::$snapshotDir . '/Snapshot.update.updatedSnapshot.phps')); +Snapshot::match(['answer' => 42], 'updatedSnapshot'); +Assert::true(file_exists(Snapshot::$snapshotDir . '/Snapshot.update.updatedSnapshot.phps')); +Assert::contains('42', file_get_contents(Snapshot::$snapshotDir . '/Snapshot.update.updatedSnapshot.phps')); + +// Snapshot::$updatedSnapshots + +Assert::equal([ + Snapshot::$snapshotDir . '/Snapshot.update.newSnapshot.phps', + Snapshot::$snapshotDir . '/Snapshot.update.updatedSnapshot.phps', +], Snapshot::$updatedSnapshots); + +// reset the env variable so that the test does not fail due to updated snapshots +putenv(Environment::UPDATE_SNAPSHOTS . '=0'); diff --git a/tests/Framework/fixtures/Snapshot.match.existingSnapshot.phps b/tests/Framework/fixtures/Snapshot.match.existingSnapshot.phps new file mode 100644 index 00000000..a7d8f5b1 --- /dev/null +++ b/tests/Framework/fixtures/Snapshot.match.existingSnapshot.phps @@ -0,0 +1 @@ + 42]; diff --git a/tests/Runner/Runner.snapshots.phpt b/tests/Runner/Runner.snapshots.phpt new file mode 100644 index 00000000..70fc6885 --- /dev/null +++ b/tests/Runner/Runner.snapshots.phpt @@ -0,0 +1,80 @@ +results[basename($test->getFile())] = [$test->getResult(), $test->message]; + } + + + public function begin(): void + { + } + + + public function end(): void + { + } +} + + +Tester\Helpers::purge(__DIR__ . '/snapshots/snapshots'); + + +// first run, without update -> fail + +$runner = new Tester\Runner\Runner(createInterpreter()); +$runner->paths[] = __DIR__ . '/snapshots/*.phptx'; +$runner->outputHandlers[] = $logger = new Logger; +$runner->run(); + +Assert::same(Test::FAILED, $logger->results['update-snapshots.phptx'][0]); +Assert::match( + "Failed: Missing snapshot file '%a%', use --update-snapshots option to generate it.\n%A%", + trim(Dumper::removeColors($logger->results['update-snapshots.phptx'][1])) +); + +// second run, with update -> skipped + +$runner = new Tester\Runner\Runner(createInterpreter()); +$runner->paths[] = __DIR__ . '/snapshots/*.phptx'; +$runner->outputHandlers[] = $logger = new Logger; +$runner->setEnvironmentVariable(Tester\Environment::UPDATE_SNAPSHOTS, '1'); +$runner->run(); + +Assert::same(Test::FAILED, $logger->results['update-snapshots.phptx'][0]); +Assert::match( + "The following snapshots were updated, please make sure they are correct:\n%a%.snapshot.phps", + trim(Dumper::removeColors($logger->results['update-snapshots.phptx'][1])) +); + +// third run, without update -> pass + +$runner = new Tester\Runner\Runner(createInterpreter()); +$runner->paths[] = __DIR__ . '/snapshots/*.phptx'; +$runner->outputHandlers[] = $logger = new Logger; +$runner->run(); + +Assert::same(Test::PASSED, $logger->results['update-snapshots.phptx'][0]); diff --git a/tests/Runner/snapshots/.gitignore b/tests/Runner/snapshots/.gitignore new file mode 100644 index 00000000..373f5f3d --- /dev/null +++ b/tests/Runner/snapshots/.gitignore @@ -0,0 +1 @@ +snapshots/ diff --git a/tests/Runner/snapshots/update-snapshots.phptx b/tests/Runner/snapshots/update-snapshots.phptx new file mode 100644 index 00000000..5a6467f2 --- /dev/null +++ b/tests/Runner/snapshots/update-snapshots.phptx @@ -0,0 +1,8 @@ +