packages/ztd-query-core/tests/Unit/Shadow/Mutation/RowConstraintsTest.php
1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Shadow\Mutation;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use PHPUnit\Framework\Attributes\UsesClass;
9use PHPUnit\Framework\TestCase;
10use ZtdQuery\Exception\DuplicateKeyException;
11use ZtdQuery\Exception\NotNullViolationException;
12use ZtdQuery\Schema\TableDefinition;
13use ZtdQuery\Shadow\Mutation\RowConstraints;
14
15#[CoversClass(RowConstraints::class)]
16#[UsesClass(TableDefinition::class)]
17#[UsesClass(DuplicateKeyException::class)]
18#[UsesClass(NotNullViolationException::class)]
19final class RowConstraintsTest extends TestCase
20{
21 public function testAssertNoNullWhereNoneIsAllowedRefusesANullInSuchAColumn(): void
22 {
23 $constraints = new RowConstraints(
24 new TableDefinition(['id', 'name'], [], ['id'], ['name'], []),
25 'users',
26 'INSERT INTO users VALUES (1, NULL)',
27 );
28
29 $this->expectException(NotNullViolationException::class);
30
31 $constraints->assertNoNullWhereNoneIsAllowed(['id' => 1, 'name' => null]);
32 }
33
34 public function testAssertNoNullWhereNoneIsAllowedLetsAColumnTheRowNeverWroteThrough(): void
35 {
36 $constraints = new RowConstraints(
37 new TableDefinition(['id', 'name'], [], ['id'], ['name'], []),
38 'users',
39 'INSERT INTO users (id) VALUES (1)',
40 );
41
42 $this->expectNotToPerformAssertions();
43
44 $constraints->assertNoNullWhereNoneIsAllowed(['id' => 1]);
45 }
46
47 public function testAssertNoNullWhereNoneIsAllowedLetsEverythingThroughForATableNothingDescribes(): void
48 {
49 $constraints = new RowConstraints(null, 'users', 'INSERT INTO users VALUES (NULL)');
50
51 $this->expectNotToPerformAssertions();
52
53 $constraints->assertNoNullWhereNoneIsAllowed(['name' => null]);
54 }
55
56 public function testAssertNoDuplicateUniqueKeyRefusesARowCollidingWithOneAlreadyThere(): void
57 {
58 $constraints = new RowConstraints(
59 new TableDefinition(['id', 'email'], [], ['id'], [], ['email' => ['email']]),
60 'users',
61 'INSERT INTO users VALUES (2, "a@example.com")',
62 );
63
64 $this->expectException(DuplicateKeyException::class);
65
66 $constraints->assertNoDuplicateUniqueKey(
67 ['id' => 2, 'email' => 'a@example.com'],
68 [['id' => 1, 'email' => 'a@example.com']],
69 );
70 }
71
72 public function testAssertNoDuplicateUniqueKeyLetsARowNotCollideWithItself(): void
73 {
74 $constraints = new RowConstraints(
75 new TableDefinition(['id', 'email'], [], ['id'], [], ['email' => ['email']]),
76 'users',
77 'UPDATE users SET email = "a@example.com" WHERE id = 1',
78 );
79
80 $this->expectNotToPerformAssertions();
81
82 $constraints->assertNoDuplicateUniqueKey(
83 ['id' => 1, 'email' => 'a@example.com'],
84 [['id' => 1, 'email' => 'a@example.com']],
85 ['id'],
86 );
87 }
88
89 public function testAssertNoDuplicateUniqueKeyLetsTwoNullsThroughBecauseNeitherCollides(): void
90 {
91 $constraints = new RowConstraints(
92 new TableDefinition(['id', 'email'], [], ['id'], [], ['email' => ['email']]),
93 'users',
94 'INSERT INTO users VALUES (2, NULL)',
95 );
96
97 $this->expectNotToPerformAssertions();
98
99 $constraints->assertNoDuplicateUniqueKey(
100 ['id' => 2, 'email' => null],
101 [['id' => 1, 'email' => null]],
102 );
103 }
104
105 public function testCarriesNullInReportsAColumnTheRowLeftNull(): void
106 {
107 $constraints = new RowConstraints(null, 'users', '');
108
109 self::assertTrue($constraints->carriesNullIn(['email' => null], ['email']));
110 }
111
112 public function testCarriesNullInReportsAColumnTheRowNeverWrote(): void
113 {
114 $constraints = new RowConstraints(null, 'users', '');
115
116 self::assertTrue($constraints->carriesNullIn(['id' => 1], ['email']));
117 }
118
119 public function testCarriesNullInIsFalseWhereEveryColumnCarriesSomething(): void
120 {
121 $constraints = new RowConstraints(null, 'users', '');
122
123 self::assertFalse($constraints->carriesNullIn(['email' => 'a@example.com'], ['email']));
124 }
125
126 public function testAgreeOnReportsTwoRowsCarryingTheSameValuesThere(): void
127 {
128 $constraints = new RowConstraints(null, 'users', '');
129
130 self::assertTrue($constraints->agreeOn(['id' => 1], ['id' => 1, 'name' => 'a'], ['id']));
131 }
132
133 public function testAgreeOnIsFalseWhereTheRowAlreadyThereCarriesNothing(): void
134 {
135 $constraints = new RowConstraints(null, 'users', '');
136
137 self::assertFalse($constraints->agreeOn(['id' => 1], ['id' => null], ['id']));
138 }
139
140 public function testKeyValuesReadsWhatTheRowCarriesUnderTheColumnNames(): void
141 {
142 $constraints = new RowConstraints(null, 'users', '');
143
144 self::assertSame(['id' => 1, 'email' => null], $constraints->keyValues(['id' => 1], ['id', 'email']));
145 }
146}
147