|
|
@@ -0,0 +1,362 @@
|
|
|
+#!/usr/bin/php
|
|
|
+<?php
|
|
|
+
|
|
|
+use Depo\UniTester\Console\Output;
|
|
|
+use Depo\UniTester\Exception\AssertionFailureException;
|
|
|
+use Depo\UniTester\TestCase;
|
|
|
+use Depo\UniTester\TestExecutor;
|
|
|
+use Depo\UniTester\TestFinder;
|
|
|
+use Depo\UniTester\TestRunnerCli;
|
|
|
+use Test\Depo\UniTester\AssertionTest;
|
|
|
+use Test\Depo\UniTester\ComparisonTest;
|
|
|
+use Test\Depo\UniTester\ExceptionHandlingTest;
|
|
|
+use Test\Depo\UniTester\PerformanceFileTest;
|
|
|
+use function Depo\UniTester\assert_empty;
|
|
|
+use function Depo\UniTester\assert_equals;
|
|
|
+use function Depo\UniTester\assert_not_strict_equals;
|
|
|
+use function Depo\UniTester\assert_strict_equals;
|
|
|
+use function Depo\UniTester\assert_false;
|
|
|
+use function Depo\UniTester\assert_instanceof;
|
|
|
+use function Depo\UniTester\assert_negative_int;
|
|
|
+use function Depo\UniTester\assert_not_empty;
|
|
|
+use function Depo\UniTester\assert_not_equals;
|
|
|
+use function Depo\UniTester\assert_not_null;
|
|
|
+use function Depo\UniTester\assert_null;
|
|
|
+use function Depo\UniTester\assert_positive_int;
|
|
|
+use function Depo\UniTester\assert_similar;
|
|
|
+use function Depo\UniTester\assert_string_contains;
|
|
|
+use function Depo\UniTester\assert_string_ends_with;
|
|
|
+use function Depo\UniTester\assert_string_length;
|
|
|
+use function Depo\UniTester\assert_string_starts_with;
|
|
|
+use function Depo\UniTester\assert_true;
|
|
|
+use function Depo\UniTester\assert_count;
|
|
|
+use function Depo\UniTester\assert_array_has_key;
|
|
|
+use function Depo\UniTester\assert_execution_time_less_than;
|
|
|
+use function Depo\UniTester\assert_memory_usage_less_than;
|
|
|
+use function Depo\UniTester\assert_file_exists;
|
|
|
+use function Depo\UniTester\assert_file_not_exists;
|
|
|
+use function Depo\UniTester\assert_directory_exists;
|
|
|
+use function Depo\UniTester\assert_is_readable;
|
|
|
+use function Depo\UniTester\assert_is_writable;
|
|
|
+use function Depo\UniTester\fail;
|
|
|
+
|
|
|
+if (file_exists(dirname(__DIR__) . '/vendor/autoload.php')) {
|
|
|
+ $composer = require dirname(__DIR__) . '/vendor/autoload.php';
|
|
|
+} else {
|
|
|
+ die(
|
|
|
+ 'You need to set up the project dependencies using the following commands:' . PHP_EOL .
|
|
|
+ 'curl -sS https://getcomposer.org/installer | php' . PHP_EOL .
|
|
|
+ 'php composer.phar install' . PHP_EOL
|
|
|
+ );
|
|
|
+}
|
|
|
+
|
|
|
+final class SelfTest
|
|
|
+{
|
|
|
+ private static array $listOfTestClasses = [AssertionTest::class, ComparisonTest::class, ExceptionHandlingTest::class, PerformanceFileTest::class];
|
|
|
+
|
|
|
+ public static function run(): void
|
|
|
+ {
|
|
|
+ try {
|
|
|
+ self::log('');
|
|
|
+ self::log('Running self tests...');
|
|
|
+ self::log('========================');
|
|
|
+ self::log('');
|
|
|
+
|
|
|
+ self::log('--- Starting Assertions Tests ---');
|
|
|
+ self::testAsserts();
|
|
|
+ self::log('--- ✅ Assertions Tests Passed ---');
|
|
|
+ self::log('');
|
|
|
+
|
|
|
+ self::log('--- Starting TestFinder Tests ---');
|
|
|
+ self::testFinder();
|
|
|
+ self::log('--- ✅ TestFinder Tests Passed ---');
|
|
|
+ self::log('');
|
|
|
+
|
|
|
+ self::log('--- Starting TestCase Tests ---');
|
|
|
+ self::testTestCase();
|
|
|
+ self::log('--- ✅ TestCase Tests Passed ---');
|
|
|
+ self::log('');
|
|
|
+
|
|
|
+ self::log('--- Starting TestExecutor Tests ---');
|
|
|
+ self::testTestExecutor();
|
|
|
+ self::log('--- ✅ TestExecutor Tests Passed ---');
|
|
|
+ self::log('');
|
|
|
+
|
|
|
+ self::log('--- Starting TestRunner Tests ---');
|
|
|
+ self::testTestRunner();
|
|
|
+ self::log('--- ✅ TestRunner Tests Passed ---');
|
|
|
+ self::log('');
|
|
|
+
|
|
|
+ self::log('✅ All tests passed successfully!');
|
|
|
+ exit(0);
|
|
|
+ } catch (RuntimeException $e) {
|
|
|
+ self::log(sprintf('❌ Critical error in %s: %s', get_class($e), $e->getMessage()), true);
|
|
|
+ self::log('Stack trace:', true);
|
|
|
+ self::log($e->getTraceAsString(), true);
|
|
|
+ exit(1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public static function testAsserts(): void
|
|
|
+ {
|
|
|
+ // Test assertions
|
|
|
+
|
|
|
+ $hello = 'Hello';
|
|
|
+ try {
|
|
|
+ assert_strict_equals(5, 5);
|
|
|
+ assert_equals(5, '5');
|
|
|
+ assert_not_strict_equals(true, 1);
|
|
|
+ assert_not_equals(5, 6);
|
|
|
+ assert_similar($hello, $hello);
|
|
|
+ assert_true(true);
|
|
|
+ assert_false(false);
|
|
|
+ assert_null(null);
|
|
|
+ assert_not_null(5);
|
|
|
+ assert_not_null('');
|
|
|
+ assert_empty([]);
|
|
|
+ assert_empty(null);
|
|
|
+ assert_empty('');
|
|
|
+ assert_not_empty([1, 2, 3]);
|
|
|
+ assert_instanceof(StdClass::class, new stdClass());
|
|
|
+ assert_string_length($hello, 5);
|
|
|
+ assert_string_contains($hello, 'll');
|
|
|
+ assert_string_starts_with($hello, 'He');
|
|
|
+ assert_string_ends_with($hello, 'lo');
|
|
|
+ assert_positive_int(5);
|
|
|
+ assert_negative_int(-5);
|
|
|
+ assert_count(2, [1, 2]);
|
|
|
+ assert_array_has_key('id', ['id' => 1]);
|
|
|
+ assert_execution_time_less_than(1000, function () {
|
|
|
+ usleep(1000);
|
|
|
+ });
|
|
|
+ assert_memory_usage_less_than(1000000, function () {
|
|
|
+ $a = 'a';
|
|
|
+ });
|
|
|
+
|
|
|
+ $tempFile = sys_get_temp_dir() . '/unitester_test_file';
|
|
|
+ file_put_contents($tempFile, 'content');
|
|
|
+ try {
|
|
|
+ assert_file_exists($tempFile);
|
|
|
+ assert_is_readable($tempFile);
|
|
|
+ assert_is_writable($tempFile);
|
|
|
+ } finally {
|
|
|
+ @unlink($tempFile);
|
|
|
+ }
|
|
|
+ assert_file_not_exists($tempFile);
|
|
|
+ assert_directory_exists(__DIR__);
|
|
|
+ } catch (Throwable $e) {
|
|
|
+ throw new RuntimeException($e->getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
+ // Test exceptions
|
|
|
+ $throwMessage = 'Expected exception not thrown. : ' . AssertionFailureException::class;
|
|
|
+ try {
|
|
|
+ assert_strict_equals(true, 1);
|
|
|
+ throw new RuntimeException(sprintf('Line %d: %s', __LINE__, $throwMessage));
|
|
|
+ } catch (AssertionFailureException $e) {
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ assert_equals(5, 6);
|
|
|
+ throw new RuntimeException(sprintf('Line %d: %s', __LINE__, $throwMessage));
|
|
|
+ } catch (AssertionFailureException $e) {
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ assert_not_strict_equals(false, false);
|
|
|
+ throw new RuntimeException(sprintf('Line %d: %s', __LINE__, $throwMessage));
|
|
|
+ } catch (AssertionFailureException $e) {
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ assert_not_equals(5, 5);
|
|
|
+ throw new RuntimeException(sprintf('Line %d: %s', __LINE__, $throwMessage));
|
|
|
+ } catch (AssertionFailureException $e) {
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ assert_similar($hello, 'hello');
|
|
|
+ throw new RuntimeException(sprintf('Line %d: %s', __LINE__, $throwMessage));
|
|
|
+ } catch (AssertionFailureException $e) {
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ assert_true(false);
|
|
|
+ throw new RuntimeException(sprintf('Line %d: %s', __LINE__, $throwMessage));
|
|
|
+ } catch (AssertionFailureException $e) {
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ assert_false(true);
|
|
|
+ throw new RuntimeException(sprintf('Line %d: %s', __LINE__, $throwMessage));
|
|
|
+ } catch (AssertionFailureException $e) {
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ assert_null('');
|
|
|
+ throw new RuntimeException(sprintf('Line %d: %s', __LINE__, $throwMessage));
|
|
|
+ } catch (AssertionFailureException $e) {
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ assert_not_null(null);
|
|
|
+ throw new RuntimeException(sprintf('Line %d: %s', __LINE__, $throwMessage));
|
|
|
+ } catch (AssertionFailureException $e) {
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ assert_empty(' ');
|
|
|
+ throw new RuntimeException(sprintf('Line %d: %s', __LINE__, $throwMessage));
|
|
|
+ } catch (AssertionFailureException $e) {
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ assert_not_empty([]);
|
|
|
+ throw new RuntimeException(sprintf('Line %d: %s', __LINE__, $throwMessage));
|
|
|
+ } catch (AssertionFailureException $e) {
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ assert_instanceof(self::class, new stdClass());
|
|
|
+ throw new RuntimeException(sprintf('Line %d: %s', __LINE__, $throwMessage));
|
|
|
+ } catch (AssertionFailureException $e) {
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ assert_string_length($hello, 6);
|
|
|
+ throw new RuntimeException(sprintf('Line %d: %s', __LINE__, $throwMessage));
|
|
|
+ } catch (AssertionFailureException $e) {
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public static function testFinder(): void
|
|
|
+ {
|
|
|
+ try {
|
|
|
+ $testFinder = new TestFinder(dirname(__DIR__) . '/tests');
|
|
|
+ $foundTests = $testFinder->find();
|
|
|
+
|
|
|
+ self::expected(count($foundTests) === 4, 'Expected 4 tests, got ' . count($foundTests));
|
|
|
+
|
|
|
+ foreach ($testFinder->find() as $test) {
|
|
|
+ self::expected(in_array($test, self::$listOfTestClasses), 'Expected ' . implode(', ', self::$listOfTestClasses) . ', got ' . is_string($test) ? $test : gettype($test));
|
|
|
+ }
|
|
|
+ } catch (Throwable $e) {
|
|
|
+ throw new RuntimeException($e->getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public static function testTestCase(): void
|
|
|
+ {
|
|
|
+ /**
|
|
|
+ * @var TestCase $test
|
|
|
+ */
|
|
|
+ foreach (self::$listOfTestClasses as $testClass) {
|
|
|
+ $test = new $testClass();
|
|
|
+ $test->run();
|
|
|
+
|
|
|
+ switch ($testClass) {
|
|
|
+ case ComparisonTest::class:
|
|
|
+ case AssertionTest::class:
|
|
|
+ self::expected($test->getAssertions() === 2, 'Expected 2 assertions, got ' . $test->getAssertions());
|
|
|
+ break;
|
|
|
+ case ExceptionHandlingTest::class:
|
|
|
+ self::expected($test->getAssertions() === 1, 'Expected 1 assertions, got ' . $test->getAssertions());
|
|
|
+ break;
|
|
|
+ case PerformanceFileTest::class:
|
|
|
+ self::expected($test->getAssertions() === 7, 'Expected 7 assertions, got ' . $test->getAssertions());
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ throw new RuntimeException('Unexpected test class ' . $testClass);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private static function testTestExecutor(): void
|
|
|
+ {
|
|
|
+ $output = new Output(function (string $message) {
|
|
|
+ });
|
|
|
+ $testExecutor = new TestExecutor(self::$listOfTestClasses, $output);
|
|
|
+ $code = $testExecutor->run();
|
|
|
+ self::expected($code === 0, 'Expected code 0, got ' . $code);
|
|
|
+
|
|
|
+ $wrongTestClass = new class extends TestCase {
|
|
|
+ protected function setUp(): void
|
|
|
+ {
|
|
|
+ }
|
|
|
+
|
|
|
+ protected function tearDown(): void
|
|
|
+ {
|
|
|
+ }
|
|
|
+
|
|
|
+ protected function execute(): void
|
|
|
+ {
|
|
|
+ $this->assertNotNull(null);
|
|
|
+ }
|
|
|
+ };
|
|
|
+ $testExecutor = new TestExecutor([$wrongTestClass], $output);
|
|
|
+ $code = $testExecutor->run();
|
|
|
+ self::expected($code === 1, 'Expected code 1, got ' . $code);
|
|
|
+ }
|
|
|
+
|
|
|
+ private static function testTestRunner(): void
|
|
|
+ {
|
|
|
+ $line = 0;
|
|
|
+ $output = new Output(static function (string $message) use (&$line) {
|
|
|
+ ++$line;
|
|
|
+ if ($line === 1) {
|
|
|
+ self::expected($message === 'Usage PHP UniTester : [options] [folder]', 'Expected "Usage PHP UniTester : [options] [folder]", got "' . $message . '"');
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ $code = TestRunnerCli::run($output, ['', '--help']);
|
|
|
+ self::expected($code === 0, 'Expected code 0, got ' . $code);
|
|
|
+
|
|
|
+
|
|
|
+ $line = 0;
|
|
|
+ $waitingLineMessage = sprintf('PHP UniTester version %s', TestRunnerCli::VERSION);
|
|
|
+ $output = new Output(static function (string $message) use (&$line, $waitingLineMessage) {
|
|
|
+ ++$line;
|
|
|
+ if ($line === 1) {
|
|
|
+ self::expected($message === $waitingLineMessage, sprintf('Expected "%s", got "%s"', $waitingLineMessage, $message));
|
|
|
+ }
|
|
|
+ });
|
|
|
+ $code = TestRunnerCli::run($output, ['', '--version']);
|
|
|
+ self::expected($code === 0, 'Expected code 0, got ' . $code);
|
|
|
+
|
|
|
+ $output = new Output(function (string $message) {
|
|
|
+ });
|
|
|
+ $code = TestRunnerCli::run($output, ['', '--not-exists-option']);
|
|
|
+ self::expected($code === 1, 'Expected code 1, got ' . $code);
|
|
|
+
|
|
|
+ $output = new Output(function (string $message) {
|
|
|
+ });
|
|
|
+ $code = TestRunnerCli::run($output, ['', 'argument1', 'argument2']);
|
|
|
+ self::expected($code === 1, 'Expected code 1, got ' . $code);
|
|
|
+
|
|
|
+ $output = new Output(function (string $message) {
|
|
|
+ });
|
|
|
+ $code = TestRunnerCli::run($output, ['', 'folder/not/exists']);
|
|
|
+ self::expected($code === 1, 'Expected code 1, got ' . $code);
|
|
|
+
|
|
|
+ $output = new Output(function (string $message) {
|
|
|
+ });
|
|
|
+ $code = TestRunnerCli::run($output, ['', dirname(__DIR__) . '/tests']);
|
|
|
+ self::expected($code === 0, 'Expected code 0, got ' . $code);
|
|
|
+ }
|
|
|
+
|
|
|
+ private static function expected($condition, string $errorMessage = null): void
|
|
|
+ {
|
|
|
+ if (!$condition) {
|
|
|
+ throw new RuntimeException($errorMessage);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private static function log(string $message, bool $isError = false): void
|
|
|
+ {
|
|
|
+ fwrite($isError ? STDERR : STDOUT, $message . PHP_EOL);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+SelfTest::run();
|
|
|
+
|
|
|
+
|