packages/requirements/tests/Unit/Config/Markdown/Render/MetadataWriterTest.php
1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Config\Markdown\Render;
6
7use JsonException;
8use PHPUnit\Framework\Attributes\CoversClass;
9use PHPUnit\Framework\Attributes\DataProvider;
10use PHPUnit\Framework\Attributes\Small;
11use PHPUnit\Framework\Attributes\UsesClass;
12use PHPUnit\Framework\TestCase;
13use Requirements\Config\Markdown\Nodes;
14use Requirements\Config\Markdown\Render\MetadataWriter;
15use Requirements\Input\Fields;
16use Requirements\Input\InvalidInputException;
17use stdClass;
18
19#[CoversClass(MetadataWriter::class)]
20#[UsesClass(Nodes::class)]
21#[UsesClass(Fields::class)]
22#[Small]
23final class MetadataWriterTest extends TestCase
24{
25 /**
26 * @throws JsonException
27 */
28 #[DataProvider('providerMetadata')]
29 public function testWriteWritesNestedLists(mixed $data, string $expected): void
30 {
31 self::assertSame($expected, (new MetadataWriter())->write($data));
32 }
33
34 /**
35 * @return array<string, array{mixed, string}>
36 */
37 public static function providerMetadata(): array
38 {
39 return [
40 'empty mapping' => [new stdClass(), '{}'],
41 'empty sequence' => [[], '[]'],
42 'scalars' => [(object) ['owner' => 'Parser team', 'reviewed' => true, 'priority' => 2, 'ratio' => 1.5, 'none' => null], "- **owner:** Parser team\n- **reviewed:** true\n- **priority:** 2\n- **ratio:** 1\\.5\n- **none:** null\n"],
43 'strings that are JSON text' => [(object) ['text' => 'true', 'null' => 'null', 'number' => '0', 'empty' => ''], "- **text:** \"true\"\n- **null:** \"null\"\n- **number:** \"0\"\n- **empty:** \"\"\n"],
44 'sequence' => [['stable', 1], "- stable\n- 1\n"],
45 'nested sequence' => [(object) ['values' => ['stable', 1]], "- **values:**\n - stable\n - 1\n"],
46 'sequence of sequences' => [[['a']], "- []\n - a\n"],
47 'sequence of mappings' => [[(object) ['value' => null]], "- []\n - **value:** null\n"],
48 'empty nested values' => [(object) ['empty' => new stdClass(), 'array' => []], "- **empty:** {}\n- **array:** \\[\\]\n"],
49 'empty values in a sequence' => [[new stdClass(), []], "- {}\n- \\[\\]\n"],
50 'escaped text' => [(object) ['a*b' => '1. <tokens> & more'], "- **a\\*b:** 1\\. \\<tokens\\> \\& more\n"],
51 'unicode and slashes' => [(object) ['path' => ['日本語/a']], "- **path:**\n - 日本語/a\n"],
52 'string with a line break' => [(object) ['lines' => "a\nb"], "- **lines:** a\nb\n"],
53 ];
54 }
55
56 /**
57 * @throws JsonException
58 */
59 public function testWriteIndentsANestedLevel(): void
60 {
61 self::assertSame(" - a\n - **b:** 1\n", (new MetadataWriter())->write(['a'], 4) . (new MetadataWriter())->write((object) ['b' => 1], 4));
62 }
63
64 /**
65 * @throws JsonException
66 */
67 public function testWriteRejectsASequenceThatIsNotAList(): void
68 {
69 $this->expectException(InvalidInputException::class);
70 $this->expectExceptionMessage('metadata sequence must be a list.');
71 (new MetadataWriter())->write(['a' => 1]);
72 }
73
74 /**
75 * @throws JsonException
76 */
77 public function testWriteRejectsAScalarAtTheTop(): void
78 {
79 $this->expectException(InvalidInputException::class);
80 $this->expectExceptionMessage('metadata sequence must be a list.');
81 (new MetadataWriter())->write('text');
82 }
83
84 /**
85 * @throws JsonException
86 */
87 public function testWriteRejectsAValueJsonCannotEncode(): void
88 {
89 $this->expectException(JsonException::class);
90 (new MetadataWriter())->write([NAN]);
91 }
92}
93