packages/sql-faker/tests/Unit/MySql/Generation/Rewrite/Partition/ValueShapeTest.php
1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\SqlFaker\MySql\Generation\Rewrite\Partition;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use PHPUnit\Framework\Attributes\DataProvider;
9use PHPUnit\Framework\Attributes\UsesClass;
10use PHPUnit\Framework\TestCase;
11use SqlFaker\Generation\Token\TerminalOccurrence;
12use SqlFaker\Generation\Token\TerminalSequence;
13use SqlFaker\MySql\Generation\Rewrite\Partition\ValueShape;
14
15#[CoversClass(ValueShape::class)]
16#[UsesClass(TerminalOccurrence::class)]
17#[UsesClass(TerminalSequence::class)]
18final class ValueShapeTest extends TestCase
19{
20 #[DataProvider('providerShapes')]
21 public function testResizePreservesExpressionsWhileMatchingTheRequiredWidth(string $input, bool $list, int $width, string $expected): void
22 {
23 $tokens = TerminalSequence::fromNames(explode(' ', $input))->terminals;
24 $result = (new ValueShape())->resize($tokens, $list, $width);
25 self::assertSame(explode(' ', $expected), array_column($result, 'name'));
26 $retained = array_values(array_filter($result, static fn (TerminalOccurrence $token): bool => $token->id !== PHP_INT_MIN));
27 self::assertSame(array_map(static fn (TerminalOccurrence $token): TerminalOccurrence => $tokens[$token->id], $retained), $retained);
28 }
29
30 /**
31 * @return list<array{string, bool, int, string}>
32 */
33 public static function providerShapes(): array
34 {
35 return [
36 ['MAX_VALUE_SYM', false, 1, 'MAX_VALUE_SYM'],
37 ['MAX_VALUE_SYM', false, 3, '( MAX_VALUE_SYM , MAX_VALUE_SYM , MAX_VALUE_SYM )'],
38 ['( NUM , NULL_SYM )', false, 1, '( NUM )'],
39 ['( NUM )', false, 2, '( NUM , NUM )'],
40 ['( NUM , NULL_SYM )', true, 1, '( NUM , NULL_SYM )'],
41 ['( ( NUM ) , ( NULL_SYM , NUM ) )', true, 1, '( NUM , NULL_SYM , NUM )'],
42 ['( ( NUM ) , ( NULL_SYM , NUM , NUM ) )', true, 2, '( ( NUM , NUM ) , ( NULL_SYM , NUM ) )'],
43 ['( NUM , NULL_SYM )', true, 2, '( ( NUM , NUM ) , ( NULL_SYM , NUM ) )'],
44 ['( + ( NUM + NUM ) , NUM )', true, 2, '( ( + ( NUM + NUM ) , NUM ) , ( NUM , NUM ) )'],
45 ];
46 }
47
48 public function testSplitAndJoinHandleEmptyListsAndNestedCommas(): void
49 {
50 $shape = new ValueShape();
51 self::assertSame([], $shape->split([]));
52 self::assertSame([], $shape->join([], false));
53 $tokens = TerminalSequence::fromNames(['NUM', ',', '(', 'NUM', ',', 'NUM', ')'])->terminals;
54 self::assertSame([[$tokens[0]], array_slice($tokens, 2)], $shape->split($tokens));
55 }
56
57 public function testRowsDistinguishesScalarListsAndTuples(): void
58 {
59 $tokens = TerminalSequence::fromNames(['(', 'NUM', ',', 'NULL_SYM', ')'])->terminals;
60 self::assertSame([[[$tokens[1]], [$tokens[3]]]], (new ValueShape())->rows($tokens, false));
61 self::assertSame([[[$tokens[1]]], [[$tokens[3]]]], (new ValueShape())->rows($tokens, true));
62 }
63
64 public function testJoinUsesNewPunctuationAndRetainsValueIdentity(): void
65 {
66 $value = new TerminalOccurrence('NUM', 7);
67 $joined = (new ValueShape())->join([[$value], [$value]], true);
68 self::assertSame(['(', 'NUM', ',', 'NUM', ')'], array_column($joined, 'name'));
69 self::assertSame($value, $joined[1]);
70 self::assertSame($value, $joined[3]);
71 }
72
73 public function testTokenReservesAnIdentityOutsideTheDerivation(): void
74 {
75 $token = (new ValueShape())->token(',');
76 self::assertSame(',', $token->name);
77 self::assertSame(PHP_INT_MIN, $token->id);
78 }
79}
80