diff --git a/.github/workflows/code_analysis.yaml b/.github/workflows/code_analysis.yaml index 7a9374bc..abf35b6d 100644 --- a/.github/workflows/code_analysis.yaml +++ b/.github/workflows/code_analysis.yaml @@ -36,6 +36,10 @@ jobs: name: 'Tests' run: vendor/bin/phpunit + - + name: 'Bench' + run: php bench/does_not_perform_assertion_lifecycle_bench.php + name: ${{ matrix.actions.name }} runs-on: ubuntu-latest timeout-minutes: 10 diff --git a/bench/does_not_perform_assertion_lifecycle_bench.php b/bench/does_not_perform_assertion_lifecycle_bench.php new file mode 100644 index 00000000..dbfa0808 --- /dev/null +++ b/bench/does_not_perform_assertion_lifecycle_bench.php @@ -0,0 +1,137 @@ +prepare{$level}();\n }\n\n"; + $methods .= " protected function tearDown(): void\n {\n \$this->cleanup = null;\n parent::tearDown();\n }\n\n"; + $methods .= " public function testInherited(): void\n {\n \$value = {$level};\n }\n\n"; + $methods .= " private function prepare{$level}(): void\n {\n \$this->ready = true;\n }\n\n"; + + for ($filler = 0; $filler < FILLER_METHODS; ++$filler) { + $methods .= " protected function helper{$filler}(array \$items): array\n {\n return array_map(fn (\$item) => \$item * {$filler}, \$items);\n }\n\n"; + } + + $writeClass( + $className, + "abstract class {$className} extends {$parentClassName}\n{\n protected \$ready;\n protected \$cleanup;\n\n{$methods}}\n" + ); + + $parentClassName = $className; + } + + for ($test = 0; $test < TESTS_PER_CHAIN; ++$test) { + $className = sprintf('Chain%dTest%d', $chain, $test); + + $methods = " public function testInherited(): void\n {\n parent::testInherited();\n }\n\n"; + for ($testMethod = 0; $testMethod < TEST_METHODS; ++$testMethod) { + $methods .= " public function testSomething{$testMethod}(): void\n {\n \$value = \$this->helper{$testMethod}([1, 2, 3]);\n }\n\n"; + } + + $testFilePaths[] = $writeClass( + $className, + "final class {$className} extends {$parentClassName}\n{\n{$methods}}\n" + ); + } +} + +$rectorConfig = (new LazyContainerFactory())->create(); +$rectorConfig->boot(); + +/** @var TestingParser $testingParser */ +$testingParser = $rectorConfig->make(TestingParser::class); + +/** @var BetterNodeFinder $betterNodeFinder */ +$betterNodeFinder = $rectorConfig->make(BetterNodeFinder::class); + +$rector = $rectorConfig->make(AddDoesNotPerformAssertionToNonAssertingTestRector::class); + +// parse test files up front, parent files are left for the rule to resolve +$classMethods = []; +foreach ($testFilePaths as $testFilePath) { + $stmts = $testingParser->parseFileToDecoratedNodes($testFilePath); + $classMethods = [...$classMethods, ...$betterNodeFinder->findInstanceOf($stmts, ClassMethod::class)]; +} + +$cpuSeconds = static function (): float { + $usage = getrusage(); + return $usage['ru_utime.tv_sec'] + $usage['ru_utime.tv_usec'] / 1_000_000 + + $usage['ru_stime.tv_sec'] + $usage['ru_stime.tv_usec'] / 1_000_000; +}; + +$wallStart = microtime(true); +$cpuStart = $cpuSeconds(); + +$changedCount = 0; +foreach ($classMethods as $classMethod) { + if ($rector->refactor($classMethod) instanceof ClassMethod) { + ++$changedCount; + } +} + +$cpu = $cpuSeconds() - $cpuStart; +$wall = microtime(true) - $wallStart; + +array_map('unlink', glob($directory . '/*.php')); +@rmdir($directory); + +printf('test classes: %d, test methods: %d, changed: %d%s', count($testFilePaths), count($classMethods), $changedCount, PHP_EOL); +printf('CPU: %.4f s (%.3f ms/method)%s', $cpu, $cpu / count($classMethods) * 1000, PHP_EOL); +printf('wall: %.4f s%s', $wall, PHP_EOL); + +if ($cpu > MAX_CPU_SECONDS) { + printf('CPU %.4f s is over the %.1f s limit%s', $cpu, MAX_CPU_SECONDS, PHP_EOL); + exit(1); +}