2
0

test 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. #!/usr/bin/php
  2. <?php
  3. use Depo\UniTester\Console\Output;
  4. use Depo\UniTester\Exception\AssertionFailureException;
  5. use Depo\UniTester\TestCase;
  6. use Depo\UniTester\TestExecutor;
  7. use Depo\UniTester\TestFinder;
  8. use Depo\UniTester\TestRunnerCli;
  9. use Test\Depo\UniTester\AssertionTest;
  10. use Test\Depo\UniTester\ComparisonTest;
  11. use Test\Depo\UniTester\ExceptionHandlingTest;
  12. use Test\Depo\UniTester\PerformanceFileTest;
  13. use function Depo\UniTester\assert_empty;
  14. use function Depo\UniTester\assert_equals;
  15. use function Depo\UniTester\assert_not_strict_equals;
  16. use function Depo\UniTester\assert_strict_equals;
  17. use function Depo\UniTester\assert_false;
  18. use function Depo\UniTester\assert_instanceof;
  19. use function Depo\UniTester\assert_negative_int;
  20. use function Depo\UniTester\assert_not_empty;
  21. use function Depo\UniTester\assert_not_equals;
  22. use function Depo\UniTester\assert_not_null;
  23. use function Depo\UniTester\assert_null;
  24. use function Depo\UniTester\assert_positive_int;
  25. use function Depo\UniTester\assert_similar;
  26. use function Depo\UniTester\assert_string_contains;
  27. use function Depo\UniTester\assert_string_ends_with;
  28. use function Depo\UniTester\assert_string_length;
  29. use function Depo\UniTester\assert_string_starts_with;
  30. use function Depo\UniTester\assert_true;
  31. use function Depo\UniTester\assert_count;
  32. use function Depo\UniTester\assert_array_has_key;
  33. use function Depo\UniTester\assert_execution_time_less_than;
  34. use function Depo\UniTester\assert_memory_usage_less_than;
  35. use function Depo\UniTester\assert_file_exists;
  36. use function Depo\UniTester\assert_file_not_exists;
  37. use function Depo\UniTester\assert_directory_exists;
  38. use function Depo\UniTester\assert_is_readable;
  39. use function Depo\UniTester\assert_is_writable;
  40. use function Depo\UniTester\fail;
  41. if (file_exists(dirname(__DIR__) . '/vendor/autoload.php')) {
  42. $composer = require dirname(__DIR__) . '/vendor/autoload.php';
  43. } else {
  44. die(
  45. 'You need to set up the project dependencies using the following commands:' . PHP_EOL .
  46. 'curl -sS https://getcomposer.org/installer | php' . PHP_EOL .
  47. 'php composer.phar install' . PHP_EOL
  48. );
  49. }
  50. final class SelfTest
  51. {
  52. private static array $listOfTestClasses = [AssertionTest::class, ComparisonTest::class, ExceptionHandlingTest::class, PerformanceFileTest::class];
  53. public static function run(): void
  54. {
  55. try {
  56. self::log('');
  57. self::log('Running self tests...');
  58. self::log('========================');
  59. self::log('');
  60. self::log('--- Starting Assertions Tests ---');
  61. self::testAsserts();
  62. self::log('--- ✅ Assertions Tests Passed ---');
  63. self::log('');
  64. self::log('--- Starting TestFinder Tests ---');
  65. self::testFinder();
  66. self::log('--- ✅ TestFinder Tests Passed ---');
  67. self::log('');
  68. self::log('--- Starting TestCase Tests ---');
  69. self::testTestCase();
  70. self::log('--- ✅ TestCase Tests Passed ---');
  71. self::log('');
  72. self::log('--- Starting TestExecutor Tests ---');
  73. self::testTestExecutor();
  74. self::log('--- ✅ TestExecutor Tests Passed ---');
  75. self::log('');
  76. self::log('--- Starting TestRunner Tests ---');
  77. self::testTestRunner();
  78. self::log('--- ✅ TestRunner Tests Passed ---');
  79. self::log('');
  80. self::log('✅ All tests passed successfully!');
  81. exit(0);
  82. } catch (RuntimeException $e) {
  83. self::log(sprintf('❌ Critical error in %s: %s', get_class($e), $e->getMessage()), true);
  84. self::log('Stack trace:', true);
  85. self::log($e->getTraceAsString(), true);
  86. exit(1);
  87. }
  88. }
  89. public static function testAsserts(): void
  90. {
  91. // Test assertions
  92. $hello = 'Hello';
  93. try {
  94. assert_strict_equals(5, 5);
  95. assert_equals(5, '5');
  96. assert_not_strict_equals(true, 1);
  97. assert_not_equals(5, 6);
  98. assert_similar($hello, $hello);
  99. assert_true(true);
  100. assert_false(false);
  101. assert_null(null);
  102. assert_not_null(5);
  103. assert_not_null('');
  104. assert_empty([]);
  105. assert_empty(null);
  106. assert_empty('');
  107. assert_not_empty([1, 2, 3]);
  108. assert_instanceof(StdClass::class, new stdClass());
  109. assert_string_length($hello, 5);
  110. assert_string_contains($hello, 'll');
  111. assert_string_starts_with($hello, 'He');
  112. assert_string_ends_with($hello, 'lo');
  113. assert_positive_int(5);
  114. assert_negative_int(-5);
  115. assert_count(2, [1, 2]);
  116. assert_array_has_key('id', ['id' => 1]);
  117. assert_execution_time_less_than(1000, function () {
  118. usleep(1000);
  119. });
  120. assert_memory_usage_less_than(1000000, function () {
  121. $a = 'a';
  122. });
  123. $tempFile = sys_get_temp_dir() . '/unitester_test_file';
  124. file_put_contents($tempFile, 'content');
  125. try {
  126. assert_file_exists($tempFile);
  127. assert_is_readable($tempFile);
  128. assert_is_writable($tempFile);
  129. } finally {
  130. @unlink($tempFile);
  131. }
  132. assert_file_not_exists($tempFile);
  133. assert_directory_exists(__DIR__);
  134. } catch (Throwable $e) {
  135. throw new RuntimeException($e->getMessage());
  136. }
  137. // Test exceptions
  138. $throwMessage = 'Expected exception not thrown. : ' . AssertionFailureException::class;
  139. try {
  140. assert_strict_equals(true, 1);
  141. throw new RuntimeException(sprintf('Line %d: %s', __LINE__, $throwMessage));
  142. } catch (AssertionFailureException $e) {
  143. }
  144. try {
  145. assert_equals(5, 6);
  146. throw new RuntimeException(sprintf('Line %d: %s', __LINE__, $throwMessage));
  147. } catch (AssertionFailureException $e) {
  148. }
  149. try {
  150. assert_not_strict_equals(false, false);
  151. throw new RuntimeException(sprintf('Line %d: %s', __LINE__, $throwMessage));
  152. } catch (AssertionFailureException $e) {
  153. }
  154. try {
  155. assert_not_equals(5, 5);
  156. throw new RuntimeException(sprintf('Line %d: %s', __LINE__, $throwMessage));
  157. } catch (AssertionFailureException $e) {
  158. }
  159. try {
  160. assert_similar($hello, 'hello');
  161. throw new RuntimeException(sprintf('Line %d: %s', __LINE__, $throwMessage));
  162. } catch (AssertionFailureException $e) {
  163. }
  164. try {
  165. assert_true(false);
  166. throw new RuntimeException(sprintf('Line %d: %s', __LINE__, $throwMessage));
  167. } catch (AssertionFailureException $e) {
  168. }
  169. try {
  170. assert_false(true);
  171. throw new RuntimeException(sprintf('Line %d: %s', __LINE__, $throwMessage));
  172. } catch (AssertionFailureException $e) {
  173. }
  174. try {
  175. assert_null('');
  176. throw new RuntimeException(sprintf('Line %d: %s', __LINE__, $throwMessage));
  177. } catch (AssertionFailureException $e) {
  178. }
  179. try {
  180. assert_not_null(null);
  181. throw new RuntimeException(sprintf('Line %d: %s', __LINE__, $throwMessage));
  182. } catch (AssertionFailureException $e) {
  183. }
  184. try {
  185. assert_empty(' ');
  186. throw new RuntimeException(sprintf('Line %d: %s', __LINE__, $throwMessage));
  187. } catch (AssertionFailureException $e) {
  188. }
  189. try {
  190. assert_not_empty([]);
  191. throw new RuntimeException(sprintf('Line %d: %s', __LINE__, $throwMessage));
  192. } catch (AssertionFailureException $e) {
  193. }
  194. try {
  195. assert_instanceof(self::class, new stdClass());
  196. throw new RuntimeException(sprintf('Line %d: %s', __LINE__, $throwMessage));
  197. } catch (AssertionFailureException $e) {
  198. }
  199. try {
  200. assert_string_length($hello, 6);
  201. throw new RuntimeException(sprintf('Line %d: %s', __LINE__, $throwMessage));
  202. } catch (AssertionFailureException $e) {
  203. }
  204. }
  205. public static function testFinder(): void
  206. {
  207. try {
  208. $testFinder = new TestFinder(dirname(__DIR__) . '/tests');
  209. $foundTests = $testFinder->find();
  210. self::expected(count($foundTests) === 4, 'Expected 4 tests, got ' . count($foundTests));
  211. foreach ($testFinder->find() as $test) {
  212. self::expected(in_array($test, self::$listOfTestClasses), 'Expected ' . implode(', ', self::$listOfTestClasses) . ', got ' . is_string($test) ? $test : gettype($test));
  213. }
  214. } catch (Throwable $e) {
  215. throw new RuntimeException($e->getMessage());
  216. }
  217. }
  218. public static function testTestCase(): void
  219. {
  220. /**
  221. * @var TestCase $test
  222. */
  223. foreach (self::$listOfTestClasses as $testClass) {
  224. $test = new $testClass();
  225. $test->run();
  226. switch ($testClass) {
  227. case ComparisonTest::class:
  228. case AssertionTest::class:
  229. self::expected($test->getAssertions() === 2, 'Expected 2 assertions, got ' . $test->getAssertions());
  230. break;
  231. case ExceptionHandlingTest::class:
  232. self::expected($test->getAssertions() === 1, 'Expected 1 assertions, got ' . $test->getAssertions());
  233. break;
  234. case PerformanceFileTest::class:
  235. self::expected($test->getAssertions() === 7, 'Expected 7 assertions, got ' . $test->getAssertions());
  236. break;
  237. default:
  238. throw new RuntimeException('Unexpected test class ' . $testClass);
  239. }
  240. }
  241. }
  242. private static function testTestExecutor(): void
  243. {
  244. $output = new Output(function (string $message) {
  245. });
  246. $testExecutor = new TestExecutor(self::$listOfTestClasses, $output);
  247. $code = $testExecutor->run();
  248. self::expected($code === 0, 'Expected code 0, got ' . $code);
  249. $wrongTestClass = new class extends TestCase {
  250. protected function setUp(): void
  251. {
  252. }
  253. protected function tearDown(): void
  254. {
  255. }
  256. protected function execute(): void
  257. {
  258. $this->assertNotNull(null);
  259. }
  260. };
  261. $testExecutor = new TestExecutor([$wrongTestClass], $output);
  262. $code = $testExecutor->run();
  263. self::expected($code === 1, 'Expected code 1, got ' . $code);
  264. }
  265. private static function testTestRunner(): void
  266. {
  267. $line = 0;
  268. $output = new Output(static function (string $message) use (&$line) {
  269. ++$line;
  270. if ($line === 1) {
  271. self::expected($message === 'Usage PHP UniTester : [options] [folder]', 'Expected "Usage PHP UniTester : [options] [folder]", got "' . $message . '"');
  272. }
  273. });
  274. $code = TestRunnerCli::run($output, ['', '--help']);
  275. self::expected($code === 0, 'Expected code 0, got ' . $code);
  276. $line = 0;
  277. $waitingLineMessage = sprintf('PHP UniTester version %s', TestRunnerCli::VERSION);
  278. $output = new Output(static function (string $message) use (&$line, $waitingLineMessage) {
  279. ++$line;
  280. if ($line === 1) {
  281. self::expected($message === $waitingLineMessage, sprintf('Expected "%s", got "%s"', $waitingLineMessage, $message));
  282. }
  283. });
  284. $code = TestRunnerCli::run($output, ['', '--version']);
  285. self::expected($code === 0, 'Expected code 0, got ' . $code);
  286. $output = new Output(function (string $message) {
  287. });
  288. $code = TestRunnerCli::run($output, ['', '--not-exists-option']);
  289. self::expected($code === 1, 'Expected code 1, got ' . $code);
  290. $output = new Output(function (string $message) {
  291. });
  292. $code = TestRunnerCli::run($output, ['', 'argument1', 'argument2']);
  293. self::expected($code === 1, 'Expected code 1, got ' . $code);
  294. $output = new Output(function (string $message) {
  295. });
  296. $code = TestRunnerCli::run($output, ['', 'folder/not/exists']);
  297. self::expected($code === 1, 'Expected code 1, got ' . $code);
  298. $output = new Output(function (string $message) {
  299. });
  300. $code = TestRunnerCli::run($output, ['', dirname(__DIR__) . '/tests']);
  301. self::expected($code === 0, 'Expected code 0, got ' . $code);
  302. }
  303. private static function expected($condition, string $errorMessage = null): void
  304. {
  305. if (!$condition) {
  306. throw new RuntimeException($errorMessage);
  307. }
  308. }
  309. private static function log(string $message, bool $isError = false): void
  310. {
  311. fwrite($isError ? STDERR : STDOUT, $message . PHP_EOL);
  312. }
  313. }
  314. SelfTest::run();