|
1 | 1 | <?php |
2 | 2 |
|
3 | | -namespace STS\Phpinfo\Tests; |
4 | | - |
5 | | -use InvalidArgumentException; |
6 | | -use PHPUnit\Framework\Attributes\Test; |
7 | | -use PHPUnit\Framework\TestCase; |
8 | 3 | use STS\Phpinfo\Info; |
9 | 4 | use STS\Phpinfo\Parsers\HtmlParser; |
10 | 5 | use STS\Phpinfo\PhpInfo; |
11 | 6 |
|
12 | | -class HtmlParserTest extends TestCase |
| 7 | +function htmlInfo(): PhpInfo |
13 | 8 | { |
14 | | - private static ?PhpInfo $info = null; |
15 | | - |
16 | | - private static function info(): PhpInfo |
17 | | - { |
18 | | - if (self::$info === null) { |
19 | | - self::$info = Info::fromHtml( |
20 | | - file_get_contents(__DIR__.'/fixtures/html-php83.html') |
21 | | - ); |
22 | | - } |
| 9 | + static $info = null; |
23 | 10 |
|
24 | | - return self::$info; |
25 | | - } |
| 11 | + return $info ??= Info::fromHtml( |
| 12 | + file_get_contents(__DIR__.'/fixtures/html-php83.html') |
| 13 | + ); |
| 14 | +} |
26 | 15 |
|
27 | | - #[Test] |
28 | | - public function it_can_detect_html_content(): void |
29 | | - { |
30 | | - $html = file_get_contents(__DIR__.'/fixtures/html-php83.html'); |
| 16 | +it('can detect html content', function () { |
| 17 | + $html = file_get_contents(__DIR__.'/fixtures/html-php83.html'); |
31 | 18 |
|
32 | | - $this->assertTrue(HtmlParser::canParse($html)); |
33 | | - $this->assertFalse(HtmlParser::canParse('not phpinfo')); |
34 | | - $this->assertFalse(HtmlParser::canParse('')); |
35 | | - } |
| 19 | + expect(HtmlParser::canParse($html))->toBeTrue() |
| 20 | + ->and(HtmlParser::canParse('not phpinfo'))->toBeFalse() |
| 21 | + ->and(HtmlParser::canParse(''))->toBeFalse(); |
| 22 | +}); |
36 | 23 |
|
37 | | - #[Test] |
38 | | - public function it_rejects_invalid_content(): void |
39 | | - { |
40 | | - $this->expectException(InvalidArgumentException::class); |
41 | | - Info::fromHtml('not phpinfo content'); |
42 | | - } |
| 24 | +it('rejects invalid content', function () { |
| 25 | + Info::fromHtml('not phpinfo content'); |
| 26 | +})->throws(InvalidArgumentException::class); |
43 | 27 |
|
44 | | - #[Test] |
45 | | - public function it_returns_phpinfo_instance(): void |
46 | | - { |
47 | | - $this->assertInstanceOf(PhpInfo::class, self::info()); |
48 | | - } |
| 28 | +it('returns phpinfo instance', function () { |
| 29 | + expect(htmlInfo())->toBeInstanceOf(PhpInfo::class); |
| 30 | +}); |
49 | 31 |
|
50 | | - #[Test] |
51 | | - public function it_parses_php_version(): void |
52 | | - { |
53 | | - $this->assertNotEmpty(self::info()->version()); |
54 | | - $this->assertMatchesRegularExpression('/^\d+\.\d+\.\d+/', self::info()->version()); |
55 | | - } |
| 32 | +it('parses php version', function () { |
| 33 | + expect(htmlInfo()->version()) |
| 34 | + ->not->toBeEmpty() |
| 35 | + ->toMatch('/^\d+\.\d+\.\d+/'); |
| 36 | +}); |
56 | 37 |
|
57 | | - #[Test] |
58 | | - public function it_parses_modules(): void |
59 | | - { |
60 | | - $modules = self::info()->modules(); |
| 38 | +it('parses modules', function () { |
| 39 | + $modules = htmlInfo()->modules(); |
61 | 40 |
|
62 | | - $this->assertGreaterThan(5, $modules->count()); |
63 | | - $this->assertEquals('General', $modules->first()->name()); |
64 | | - } |
| 41 | + expect($modules->count())->toBeGreaterThan(5) |
| 42 | + ->and($modules->first()->name())->toBe('General'); |
| 43 | +}); |
65 | 44 |
|
66 | | - #[Test] |
67 | | - public function it_has_general_module_with_configs(): void |
68 | | - { |
69 | | - $general = self::info()->module('General'); |
| 45 | +it('has general module with configs', function () { |
| 46 | + $general = htmlInfo()->module('General'); |
70 | 47 |
|
71 | | - $this->assertNotNull($general); |
72 | | - $this->assertGreaterThan(0, $general->configs()->count()); |
73 | | - } |
| 48 | + expect($general)->not->toBeNull() |
| 49 | + ->and($general->configs()->count())->toBeGreaterThan(0); |
| 50 | +}); |
74 | 51 |
|
75 | | - #[Test] |
76 | | - public function has_module_is_case_insensitive(): void |
77 | | - { |
78 | | - $firstModuleName = self::info()->modules()->skip(1)->first()->name(); |
| 52 | +it('has case insensitive module lookup', function () { |
| 53 | + $name = htmlInfo()->modules()->skip(1)->first()->name(); |
79 | 54 |
|
80 | | - $this->assertTrue(self::info()->hasModule($firstModuleName)); |
81 | | - $this->assertTrue(self::info()->hasModule(strtolower($firstModuleName))); |
82 | | - $this->assertTrue(self::info()->hasModule(strtoupper($firstModuleName))); |
83 | | - } |
| 55 | + expect(htmlInfo()->hasModule($name))->toBeTrue() |
| 56 | + ->and(htmlInfo()->hasModule(strtolower($name)))->toBeTrue() |
| 57 | + ->and(htmlInfo()->hasModule(strtoupper($name)))->toBeTrue(); |
| 58 | +}); |
84 | 59 |
|
85 | | - #[Test] |
86 | | - public function it_returns_null_for_missing_module(): void |
87 | | - { |
88 | | - $this->assertNull(self::info()->module('nonexistent_module_xyz')); |
89 | | - $this->assertFalse(self::info()->hasModule('nonexistent_module_xyz')); |
90 | | - } |
| 60 | +it('returns null for missing module', function () { |
| 61 | + expect(htmlInfo()->module('nonexistent_module_xyz'))->toBeNull() |
| 62 | + ->and(htmlInfo()->hasModule('nonexistent_module_xyz'))->toBeFalse(); |
| 63 | +}); |
91 | 64 |
|
92 | | - #[Test] |
93 | | - public function it_parses_configs(): void |
94 | | - { |
95 | | - $this->assertGreaterThan(50, self::info()->configs()->count()); |
96 | | - } |
| 65 | +it('parses configs', function () { |
| 66 | + expect(htmlInfo()->configs()->count())->toBeGreaterThan(50); |
| 67 | +}); |
97 | 68 |
|
98 | | - #[Test] |
99 | | - public function it_can_query_individual_configs(): void |
100 | | - { |
101 | | - $this->assertTrue(self::info()->hasConfig('System')); |
102 | | - $this->assertNotNull(self::info()->config('System')); |
103 | | - } |
| 69 | +it('can query individual configs', function () { |
| 70 | + expect(htmlInfo()->hasConfig('System'))->toBeTrue() |
| 71 | + ->and(htmlInfo()->config('System'))->not->toBeNull(); |
| 72 | +}); |
104 | 73 |
|
105 | | - #[Test] |
106 | | - public function it_returns_null_for_missing_config(): void |
107 | | - { |
108 | | - $this->assertNull(self::info()->config('nonexistent_config_xyz')); |
109 | | - $this->assertFalse(self::info()->hasConfig('nonexistent_config_xyz')); |
110 | | - } |
| 74 | +it('returns null for missing config', function () { |
| 75 | + expect(htmlInfo()->config('nonexistent_config_xyz'))->toBeNull() |
| 76 | + ->and(htmlInfo()->hasConfig('nonexistent_config_xyz'))->toBeFalse(); |
| 77 | +}); |
| 78 | + |
| 79 | +it('has working convenience methods', function () { |
| 80 | + $os = htmlInfo()->os(); |
| 81 | + $hostname = htmlInfo()->hostname(); |
111 | 82 |
|
112 | | - #[Test] |
113 | | - public function convenience_methods_work(): void |
114 | | - { |
115 | | - $os = self::info()->os(); |
116 | | - $hostname = self::info()->hostname(); |
| 83 | + expect($os)->not->toBeNull() |
| 84 | + ->and($hostname)->not->toBeNull() |
| 85 | + ->and(htmlInfo()->config('System'))->toStartWith($os); |
| 86 | +}); |
117 | 87 |
|
118 | | - $this->assertNotNull($os); |
119 | | - $this->assertNotNull($hostname); |
| 88 | +it('handles local and master values', function () { |
| 89 | + $config = htmlInfo()->configs()->first(fn ($c) => $c->hasMasterValue()); |
120 | 90 |
|
121 | | - $system = self::info()->config('System'); |
122 | | - $this->assertStringStartsWith($os, $system); |
| 91 | + if ($config) { |
| 92 | + expect(htmlInfo()->config($config->name(), 'local'))->not->toBeNull(); |
123 | 93 | } |
124 | 94 |
|
125 | | - #[Test] |
126 | | - public function it_handles_local_and_master_values(): void |
127 | | - { |
128 | | - $configWithMaster = self::info()->configs() |
129 | | - ->first(fn ($config) => $config->hasMasterValue()); |
| 95 | + expect(true)->toBeTrue(); |
| 96 | +}); |
130 | 97 |
|
131 | | - if ($configWithMaster) { |
132 | | - $name = $configWithMaster->name(); |
133 | | - $this->assertNotNull(self::info()->config($name, 'local')); |
134 | | - } |
| 98 | +it('parses groups with headings', function () { |
| 99 | + $groupWithHeadings = null; |
135 | 100 |
|
136 | | - $this->assertTrue(true); |
137 | | - } |
138 | | - |
139 | | - #[Test] |
140 | | - public function it_parses_groups_with_headings(): void |
141 | | - { |
142 | | - $groupWithHeadings = null; |
143 | | - |
144 | | - foreach (self::info()->modules() as $module) { |
145 | | - foreach ($module->groups() as $group) { |
146 | | - if ($group->hasHeadings()) { |
147 | | - $groupWithHeadings = $group; |
148 | | - break 2; |
149 | | - } |
| 101 | + foreach (htmlInfo()->modules() as $module) { |
| 102 | + foreach ($module->groups() as $group) { |
| 103 | + if ($group->hasHeadings()) { |
| 104 | + $groupWithHeadings = $group; |
| 105 | + break 2; |
150 | 106 | } |
151 | 107 | } |
152 | | - |
153 | | - if ($groupWithHeadings) { |
154 | | - $this->assertGreaterThan(0, $groupWithHeadings->headings()->count()); |
155 | | - $this->assertNotNull($groupWithHeadings->heading(0)); |
156 | | - } |
157 | | - |
158 | | - $this->assertTrue(true); |
159 | 108 | } |
160 | 109 |
|
161 | | - #[Test] |
162 | | - public function it_handles_svg_elements_in_html(): void |
163 | | - { |
164 | | - $infoWithSvg = Info::fromHtml(file_get_contents(__DIR__.'/fixtures/html-php83-with-svg.html')); |
165 | | - $infoWithout = Info::fromHtml(file_get_contents(__DIR__.'/fixtures/html-php83.html')); |
166 | | - |
167 | | - $this->assertEquals( |
168 | | - $infoWithout->modules()->count(), |
169 | | - $infoWithSvg->modules()->count() |
170 | | - ); |
171 | | - $this->assertEquals( |
172 | | - $infoWithout->configs()->count(), |
173 | | - $infoWithSvg->configs()->count() |
174 | | - ); |
| 110 | + if ($groupWithHeadings) { |
| 111 | + expect($groupWithHeadings->headings()->count())->toBeGreaterThan(0) |
| 112 | + ->and($groupWithHeadings->heading(0))->not->toBeNull(); |
175 | 113 | } |
176 | 114 |
|
177 | | - #[Test] |
178 | | - public function it_parses_credits(): void |
179 | | - { |
180 | | - $credits = self::info()->module('PHP Credits'); |
| 115 | + expect(true)->toBeTrue(); |
| 116 | +}); |
181 | 117 |
|
182 | | - $this->assertNotNull($credits); |
183 | | - $this->assertNotEmpty($credits->name()); |
184 | | - $this->assertGreaterThan(0, $credits->groups()->count()); |
185 | | - } |
| 118 | +it('handles svg elements in html', function () { |
| 119 | + $infoWithSvg = Info::fromHtml(file_get_contents(__DIR__.'/fixtures/html-php83-with-svg.html')); |
| 120 | + $infoWithout = Info::fromHtml(file_get_contents(__DIR__.'/fixtures/html-php83.html')); |
186 | 121 |
|
187 | | - #[Test] |
188 | | - public function it_parses_license(): void |
189 | | - { |
190 | | - $license = self::info()->module('PHP License'); |
| 122 | + expect($infoWithSvg->modules()->count())->toBe($infoWithout->modules()->count()) |
| 123 | + ->and($infoWithSvg->configs()->count())->toBe($infoWithout->configs()->count()); |
| 124 | +}); |
191 | 125 |
|
192 | | - $this->assertNotNull($license); |
193 | | - $this->assertNotEmpty($license->name()); |
194 | | - $this->assertGreaterThan(0, $license->groups()->count()); |
195 | | - } |
| 126 | +it('parses credits', function () { |
| 127 | + $credits = htmlInfo()->module('PHP Credits'); |
196 | 128 |
|
197 | | - #[Test] |
198 | | - public function it_is_json_serializable(): void |
199 | | - { |
200 | | - $json = json_encode(self::info()); |
| 129 | + expect($credits)->not->toBeNull() |
| 130 | + ->and($credits->name())->not->toBeEmpty() |
| 131 | + ->and($credits->groups()->count())->toBeGreaterThan(0); |
| 132 | +}); |
201 | 133 |
|
202 | | - $this->assertNotFalse($json); |
| 134 | +it('parses license', function () { |
| 135 | + $license = htmlInfo()->module('PHP License'); |
203 | 136 |
|
204 | | - $data = json_decode($json, true); |
205 | | - $this->assertArrayHasKey('version', $data); |
206 | | - $this->assertArrayHasKey('modules', $data); |
207 | | - $this->assertIsArray($data['modules']); |
208 | | - $this->assertGreaterThan(0, count($data['modules'])); |
| 137 | + expect($license)->not->toBeNull() |
| 138 | + ->and($license->name())->not->toBeEmpty() |
| 139 | + ->and($license->groups()->count())->toBeGreaterThan(0); |
| 140 | +}); |
209 | 141 |
|
210 | | - $firstModule = $data['modules'][0]; |
211 | | - $this->assertArrayHasKey('key', $firstModule); |
212 | | - $this->assertArrayHasKey('name', $firstModule); |
213 | | - $this->assertArrayHasKey('groups', $firstModule); |
214 | | - } |
| 142 | +it('is json serializable', function () { |
| 143 | + $json = json_encode(htmlInfo()); |
| 144 | + $data = json_decode($json, true); |
215 | 145 |
|
216 | | - #[Test] |
217 | | - public function modules_have_unique_keys(): void |
218 | | - { |
219 | | - $keys = self::info()->modules()->map(fn ($m) => $m->key()); |
220 | | - $uniqueKeys = $keys->unique(); |
| 146 | + expect($json)->not->toBeFalse() |
| 147 | + ->and($data)->toHaveKeys(['version', 'modules']) |
| 148 | + ->and($data['modules'])->toBeArray()->not->toBeEmpty() |
| 149 | + ->and($data['modules'][0])->toHaveKeys(['key', 'name', 'groups']); |
| 150 | +}); |
221 | 151 |
|
222 | | - $this->assertEquals($keys->count(), $uniqueKeys->count()); |
223 | | - } |
224 | | -} |
| 152 | +it('has unique module keys', function () { |
| 153 | + $keys = htmlInfo()->modules()->map(fn ($m) => $m->key()); |
| 154 | + |
| 155 | + expect($keys->unique()->count())->toBe($keys->count()); |
| 156 | +}); |
0 commit comments