|
2 | 2 | namespace GT\WebEngine\Test\Logic; |
3 | 3 |
|
4 | 4 | use GT\WebEngine\Logic\AppAutoloader; |
5 | | -use PHPUnit\Framework\Attributes\RunInSeparateProcess; |
6 | 5 | use PHPUnit\Framework\TestCase; |
7 | 6 |
|
8 | 7 | class AppAutoloaderTest extends TestCase { |
9 | | - private string $classDir; |
| 8 | + private string $cwd; |
| 9 | + private string $relBaseDir; |
10 | 10 |
|
11 | 11 | protected function setUp():void { |
12 | | - // Use system temporary directory to avoid writing into the project tree. |
13 | | - $sysTmp = rtrim(sys_get_temp_dir(), "/\\"); |
14 | | - $this->classDir = $sysTmp . "/phpgt-webengine-test--Logic-AppAutoloader-" . uniqid(); |
15 | | - @mkdir($this->classDir, recursive: true); |
| 12 | + parent::setUp(); |
| 13 | + $this->cwd = getcwd(); |
| 14 | + $this->relBaseDir = "test-autoload-" . uniqid(); |
| 15 | + mkdir($this->relBaseDir . "/Foo", 0777, true); |
16 | 16 | } |
17 | 17 |
|
18 | 18 | protected function tearDown():void { |
19 | | - // Recursively remove the temporary directory we created. |
20 | | - $path = $this->classDir; |
21 | | - if(is_dir($path)) { |
22 | | - self::rrmdir($path); |
| 19 | + // Recursively remove created files/dirs |
| 20 | + $it = new \RecursiveIteratorIterator( |
| 21 | + new \RecursiveDirectoryIterator($this->relBaseDir, \FilesystemIterator::SKIP_DOTS), |
| 22 | + \RecursiveIteratorIterator::CHILD_FIRST |
| 23 | + ); |
| 24 | + foreach($it as $file) { |
| 25 | + $file->isDir() ? rmdir($file->getPathname()) : unlink($file->getPathname()); |
23 | 26 | } |
| 27 | + @rmdir($this->relBaseDir); |
| 28 | + parent::tearDown(); |
24 | 29 | } |
25 | 30 |
|
26 | | - private static function rrmdir(string $dir):void { |
27 | | - /** @var list<string> $items */ |
28 | | - $items = @scandir($dir) ?: []; |
29 | | - foreach($items as $item) { |
30 | | - if($item === "." || $item === "..") { |
31 | | - continue; |
32 | | - } |
33 | | - $full = $dir . "/" . $item; |
34 | | - if(is_dir($full)) { |
35 | | - self::rrmdir($full); |
36 | | - } |
37 | | - else { |
38 | | - @unlink($full); |
39 | | - } |
40 | | - } |
41 | | - @rmdir($dir); |
| 31 | + public function testSetup_noDir_doesNotRegisterOrLoad():void { |
| 32 | + $sut = new AppAutoloader('App', 'non-existent-dir-' . uniqid()); |
| 33 | + // Should not throw, and autoloader should not attempt to load anything |
| 34 | + $sut->setup(); |
| 35 | + self::assertFalse(class_exists('App\\Nope\\Thing')); |
42 | 36 | } |
43 | 37 |
|
44 | | - #[RunInSeparateProcess] |
45 | | - public function testLoadsClassFromConfiguredDirectory():void { |
46 | | - // Arrange: create a simple class file under the configured directory. |
47 | | - $ns = 'TestApp'; |
48 | | - $cls = 'Widget'; |
49 | | - $code = <<<PHP |
50 | | - <?php |
51 | | - namespace {$ns}; |
52 | | - class {$cls} { |
53 | | - public function ping(): string { return 'pong'; } |
54 | | - } |
55 | | - PHP; |
| 38 | + public function testAutoload_relativePathAndUcfirstSegments():void { |
| 39 | + // Create class file using ucfirst segment mapping: Foo/Bar.php |
| 40 | + $code = "<?php\nnamespace App\\Foo; class Bar { public static function hello(): string { return 'hi'; } }\n"; |
| 41 | + file_put_contents($this->relBaseDir . "/Foo/Bar.php", $code); |
56 | 42 |
|
57 | | - $filePath = "{$this->classDir}/{$cls}.php"; |
58 | | - file_put_contents($filePath, $code); |
59 | | - |
60 | | - $sut = new AppAutoloader(namespace: $ns, classDir: $this->classDir); |
| 43 | + $sut = new AppAutoloader('App', $this->relBaseDir); |
61 | 44 | $sut->setup(); |
62 | 45 |
|
63 | | - // Act: reference the class so the autoloader resolves it. |
64 | | - $fullClass = "\\{$ns}\\{$cls}"; |
65 | | - $instance = new $fullClass(); |
66 | | - |
67 | | - // Assert |
68 | | - self::assertSame('pong', $instance->ping()); |
| 46 | + $class = 'App\\Foo\\Bar'; |
| 47 | + self::assertTrue(class_exists($class)); |
| 48 | + self::assertSame('hi', \call_user_func([$class, 'hello'])); |
69 | 49 | } |
70 | 50 |
|
71 | | - #[RunInSeparateProcess] |
72 | | - public function testLoadsClassFromNestedNamespaceUsingUcfirstPath():void { |
73 | | - // Arrange: nested namespace parts should map to capitalised path segments. |
74 | | - $ns = 'TestApp2'; |
75 | | - $nsParts = ['foo', 'bar']; |
76 | | - $class = 'baz'; |
| 51 | + public function testAutoload_ignoresDifferentNamespace():void { |
| 52 | + // Create class that shouldn't be autoloaded by our AppAutoloader because of namespace mismatch |
| 53 | + $otherDir = $this->relBaseDir . '/Other'; |
| 54 | + mkdir($otherDir, 0777, true); |
| 55 | + file_put_contents($otherDir . '/Qux.php', "<?php\nnamespace Other\\Ns; class Qux {}\n"); |
77 | 56 |
|
78 | | - // The autoloader ucfirst()s each part, so we create directories capitalised. |
79 | | - $dir = "{$this->classDir}/" . implode('/', array_map('ucfirst', $nsParts)); |
80 | | - @mkdir($dir, recursive: true); |
81 | | - |
82 | | - $code = <<<PHP |
83 | | - <?php |
84 | | - namespace {$ns}\\foo\\bar; |
85 | | - class {$class} { public function id(): string { return 'ok'; } } |
86 | | - PHP; |
87 | | - |
88 | | - file_put_contents($dir . '/Baz.php', $code); |
89 | | - |
90 | | - $sut = new AppAutoloader(namespace: $ns, classDir: $this->classDir); |
| 57 | + $sut = new AppAutoloader('App', $this->relBaseDir); |
91 | 58 | $sut->setup(); |
92 | 59 |
|
93 | | - // Use lowercased parts to confirm ucfirst mapping works. |
94 | | - $fullClass = "\\{$ns}\\{$nsParts[0]}\\{$nsParts[1]}\\$class"; |
95 | | - $instance = new $fullClass(); |
96 | | - |
97 | | - self::assertSame('ok', $instance->id()); |
| 60 | + // Asserting that merely referencing a different namespace doesn't cause load attempt here. |
| 61 | + self::assertFalse(class_exists('Other\\Ns\\Qux', false)); |
98 | 62 | } |
99 | 63 | } |
0 commit comments