packages/requirements/tests/Unit/Ears/LiteralMaskTest.php
1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Ears;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use PHPUnit\Framework\Attributes\DataProvider;
9use PHPUnit\Framework\Attributes\Small;
10use PHPUnit\Framework\TestCase;
11use Requirements\Ears\LiteralMask;
12use Requirements\Input\InvalidInputException;
13
14#[CoversClass(LiteralMask::class)]
15#[Small]
16final class LiteralMaskTest extends TestCase
17{
18 #[DataProvider('providerApplyMasksLiterals')]
19 public function testApplyMasksLiterals(string $text, string $expected): void
20 {
21 self::assertSame($expected, (new LiteralMask())->apply($text));
22 }
23
24 /**
25 * @return array<string, array{string, string}>
26 */
27 public static function providerApplyMasksLiterals(): array
28 {
29 return [
30 'no literal' => ['The reader shall read.', 'The reader shall read.'],
31 'empty' => ['', ''],
32 'double quotes' => ['emit "shall, then" now', 'emit xxxxxxxxxxxxx now'],
33 'single quotes' => ["emit 'a, b' now", 'emit xxxxxx now'],
34 'backticks' => ['emit `shall` now', 'emit xxxxxxx now'],
35 'two literals' => ['"a" and "b"', 'xxx and xxx'],
36 'escaped quote' => ['"a\"b" c', 'xxxxxx c'],
37 'escaped backslash' => ['"a\\\\" c', 'xxxxx c'],
38 'other quote inside' => ['"it\'s" c', 'xxxxxx c'],
39 'apostrophe after letter' => ["the user's input", "the user's input"],
40 'apostrophe after digit' => ["the 90's", "the 90's"],
41 'quote at start' => ["'abc' d", 'xxxxx d'],
42 'quote after space' => ["a 'b' c", 'a xxx c'],
43 'quote after punctuation' => ["(='b')", '(=xxx)'],
44 'multibyte literal' => ['"é" x', 'xxxx x'],
45 ];
46 }
47
48 #[DataProvider('providerApplyRejectsUnclosedLiterals')]
49 public function testApplyRejectsUnclosedLiterals(string $text): void
50 {
51 $this->expectException(InvalidInputException::class);
52 $this->expectExceptionMessage('EARS: close quoted or code literals.');
53 (new LiteralMask())->apply($text);
54 }
55
56 /**
57 * @return array<string, array{string}>
58 */
59 public static function providerApplyRejectsUnclosedLiterals(): array
60 {
61 return [
62 'double quote' => ['The reader shall emit a "token.'],
63 'backtick' => ['The reader shall emit `code.'],
64 'single quote' => ["The reader shall emit 'token."],
65 'escaped closing quote' => ['emit "a\"'],
66 'trailing backslash' => ['emit "a\\'],
67 'mismatched quotes' => ['emit "a\' now'],
68 ];
69 }
70}
71