packages/sql-catalog/tests/Unit/Core/Evaluation/ArrayTermTest.php
1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Core\Evaluation;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use PHPUnit\Framework\Attributes\UsesClass;
9use PHPUnit\Framework\TestCase;
10use SqlCatalog\Core\Evaluation\ArrayEntry;
11use SqlCatalog\Core\Evaluation\ArrayTerm;
12use SqlCatalog\Core\Evaluation\Domain;
13use SqlCatalog\Core\Evaluation\LiteralTerm;
14use SqlCatalog\Core\Evaluation\OpaqueTerm;
15use SqlCatalog\Core\Text\Origin;
16use SqlCatalog\Core\Text\TextHole;
17use SqlCatalog\Core\Text\TextPattern;
18use SqlCatalog\Core\Type\TypeShape;
19
20#[CoversClass(ArrayTerm::class)]
21#[UsesClass(ArrayEntry::class)]
22#[UsesClass(Domain::class)]
23#[UsesClass(LiteralTerm::class)]
24#[UsesClass(OpaqueTerm::class)]
25#[UsesClass(TextHole::class)]
26#[UsesClass(TextPattern::class)]
27#[UsesClass(TypeShape::class)]
28final class ArrayTermTest extends TestCase
29{
30 public function testPositionalKeepsUnkeyedAndIntegerKeyedElements(): void
31 {
32 $term = new ArrayTerm([
33 new ArrayEntry(null, Domain::literal('a')),
34 new ArrayEntry(Domain::literal(1), Domain::literal('b')),
35 new ArrayEntry(Domain::literal(':x'), Domain::literal('c')),
36 ]);
37 self::assertCount(2, $term->positional());
38 self::assertSame('a', $term->positional()[0]->soleLiteral()?->value);
39 }
40
41 public function testNamedKeepsStringKeyedElements(): void
42 {
43 $term = new ArrayTerm([
44 new ArrayEntry(Domain::literal(':x'), Domain::literal('c')),
45 new ArrayEntry(null, Domain::literal('a')),
46 ]);
47 self::assertSame([':x'], array_keys($term->named()));
48 }
49
50 public function testElementFindsAnElementByItsKey(): void
51 {
52 $term = new ArrayTerm([
53 new ArrayEntry(null, Domain::literal('first')),
54 new ArrayEntry(Domain::literal('k'), Domain::literal('keyed')),
55 new ArrayEntry(null, Domain::literal('second')),
56 ]);
57 self::assertSame('first', $term->element(0)?->soleLiteral()?->value);
58 self::assertSame('first', $term->element('0')?->soleLiteral()?->value);
59 self::assertSame('second', $term->element(1)?->soleLiteral()?->value);
60 self::assertSame('keyed', $term->element('k')?->soleLiteral()?->value);
61 self::assertNull($term->element('missing'));
62 }
63
64 public function testElementNeverReadsAnElementUnderABooleanOrANullKey(): void
65 {
66 $term = new ArrayTerm([
67 new ArrayEntry(null, Domain::literal('first')),
68 new ArrayEntry(null, Domain::literal('second')),
69 new ArrayEntry(Domain::literal(''), Domain::literal('empty')),
70 ]);
71 self::assertNull($term->element(true));
72 self::assertNull($term->element(false));
73 self::assertNull($term->element(null));
74 }
75
76 public function testAnyValueIsTheUnionOfEveryElement(): void
77 {
78 $term = new ArrayTerm([
79 new ArrayEntry(Domain::literal('u'), Domain::literal('users')),
80 new ArrayEntry(Domain::literal('a'), Domain::literal('admins')),
81 new ArrayEntry(null, Domain::literal('users')),
82 ]);
83 self::assertSame('literal:string:admins|literal:string:users', $term->anyValue(Origin::Unresolved)?->signature());
84 }
85
86 public function testAnyValueOfAnArrayWithNoElementsIsNothing(): void
87 {
88 self::assertNull((new ArrayTerm([]))->anyValue(Origin::Unresolved));
89 self::assertNull((new ArrayTerm([], false))->anyValue(Origin::Unresolved));
90 }
91
92 public function testAnyValueOfAnArrayKnownOnlyInPartKeepsAGapWhereItWasRead(): void
93 {
94 $term = new ArrayTerm([new ArrayEntry(null, Domain::literal('users'))], false);
95 $values = $term->anyValue(Origin::Loop, 'iterated value');
96
97 self::assertSame('literal:string:users|opaque:mixed:loop', $values?->signature());
98 self::assertEquals(new OpaqueTerm(TypeShape::unknown(), Origin::Loop, 'iterated value'), $values->terms[1]);
99 }
100
101 public function testToPatternLeavesAGap(): void
102 {
103 self::assertSame('{$}', (new ArrayTerm([]))->toPattern()->display());
104 }
105
106 public function testTypeIsArray(): void
107 {
108 self::assertSame('array', (new ArrayTerm([]))->type()->display());
109 }
110
111 public function testSignatureRecordsWhetherEveryElementIsKnown(): void
112 {
113 self::assertNotSame((new ArrayTerm([], true))->signature(), (new ArrayTerm([], false))->signature());
114 }
115}
116