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