ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
PrimitivesTest.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
22
23use Closure;
29use PHPUnit\Framework\TestCase;
30use Exception;
31
32class PrimitivesTest extends TestCase
33{
34 public function testSimpleEither(): void
35 {
36 $primitives = new Primitives();
37
38 $parse = $primitives->simpleEither([
39 'a', // False.
40 "\x0", // True.
41 ]);
42
43 $intermediate = $this->getMockBuilder(Intermediate::class)->disableOriginalConstructor()->getMock();
44 $intermediate->expects(self::exactly(2))->method('value')->willReturn(ord("\x0"));
45 $intermediate->method('accept')->willReturn(new Ok($intermediate));
46 $intermediate->method('reject')->willReturn(new Error('Failed'));
47
48 $result = $parse($intermediate, static fn(Result $x): Result => $x);
49
50 $this->assertTrue($result->isOk());
51 $this->assertEquals($intermediate, $result->value());
52 }
53
54 public function testSimpleSequence(): void
55 {
56 $primitives = new Primitives();
57
58 $parse = $primitives->simpleSequence(['a', 'd']);
59
60 $intermediate = $this->getMockBuilder(Intermediate::class)->disableOriginalConstructor()->getMock();
61 $intermediate->expects(self::exactly(2))->method('value')->willReturnOnConsecutiveCalls(ord('a'), ord('d'));
62 $intermediate->method('accept')->willReturn(new Ok($intermediate));
63
64 $result = $parse($intermediate, static fn(Result $x): Result => $x);
65
66 $this->assertTrue($result->isOk());
67 $this->assertEquals($intermediate, $result->value());
68 }
69
70 public function testUntilZero(): void
71 {
72 $primitives = new Primitives();
73 $parser = $primitives->until(0, static function (): void {
74 throw new Exception('Should not be called.');
75 });
76
77 $intermediate = $this->getMockBuilder(Intermediate::class)->disableOriginalConstructor()->getMock();
78
79 $result = $parser($intermediate, static fn(Result $x): Result => $x);
80 $this->assertTrue($result->isOk());
81 $this->assertEquals($intermediate, $result->value());
82 }
83
84 public function testUntilN(): void
85 {
86 $n = 8;
87 foreach (array_fill(0, $n + 1, null) as $i => $_) {
88 $primitives = new Primitives();
89 $called = 0;
90 $end_called = 0;
91 $parser = $primitives->until($n, static function (Intermediate $x, Closure $cc) use (&$called): Result {
92 $called++;
93 return $cc(new Ok($x));
94 });
95
96 $intermediate = $this->getMockBuilder(Intermediate::class)->disableOriginalConstructor()->getMock();
97
98 $result = $parser($intermediate, static function (Result $x) use (&$end_called, $i): Result {
99 $end_called++;
100 return $end_called <= $i ? new Error('Failed') : $x;
101 });
102 if ($i > $n) {
103 $this->assertEquals($i, $n);
104 $this->assertFalse($result->isOk());
105 } else {
106 $this->assertEquals($i, $called);
107 $this->assertEquals($i + 1, $end_called);
108 $this->assertTrue($result->isOk());
109 $this->assertEquals($intermediate, $result->value());
110 }
111 }
112 }
113
114 public function testUntilSuccess(): void
115 {
116 $success_after = 20;
117 $primitives = new Primitives();
118 $called = 0;
119 $end_called = 0;
120 $parser = $primitives->until(null, static function (Intermediate $x, Closure $cc) use (&$called): Result {
121 $called++;
122 return $cc(new Ok($x));
123 });
124
125 $intermediate = $this->getMockBuilder(Intermediate::class)->disableOriginalConstructor()->getMock();
126
127 $result = $parser($intermediate, static function (Result $x) use (&$end_called, $success_after): Result {
128 $end_called++;
129 return $end_called <= $success_after ? new Error('Failed') : $x;
130 });
131 $this->assertEquals($success_after, $called);
132 $this->assertEquals($success_after + 1, $end_called);
133 $this->assertTrue($result->isOk());
134 $this->assertEquals($intermediate, $result->value());
135 }
136
137 public function testUntilChildFails(): void
138 {
139 $fail_after = 20;
140 $primitives = new Primitives();
141 $called = 0;
142 $end_called = 0;
143 $parser = $primitives->until(null, static function (Intermediate $x, Closure $cc) use (&$called, $fail_after): Result {
144 $called++;
145 return $called <= $fail_after ? $cc(new Ok($x)) : $cc(new Error('Failed.'));
146 });
147
148 $intermediate = $this->getMockBuilder(Intermediate::class)->disableOriginalConstructor()->getMock();
149
150 $result = $parser($intermediate, static function (Result $x) use (&$end_called): Result {
151 $end_called++;
152 return new Error('Failed.');
153 });
154 $this->assertEquals($fail_after + 1, $called);
155 $this->assertEquals(($fail_after + 1) * 2, $end_called);
156 $this->assertFalse($result->isOk());
157 }
158
159 public function testParserFromParser(): void
160 {
161 $primitives = new Primitives();
162
163 $parser = static function (): void {
164 throw new Exception('Should not be called.');
165 };
166
167 $this->assertEquals($parser, $primitives->parserFrom($parser));
168 }
169
170 public function testParserFromString(): void
171 {
172 $primitives = new Primitives();
173
174 $intermediate = $this->getMockBuilder(Intermediate::class)->disableOriginalConstructor()->getMock();
175 $intermediate->method('value')->willReturnOnConsecutiveCalls(ord('h'), ord('e'), ord('l'), ord('l'), ord('o'));
176 $intermediate->method('accept')->willReturn(new Ok($intermediate));
177
178 $parser = $primitives->parserFrom('hello');
179
180 $result = $parser($intermediate, static fn(Result $x): Result => $x);
181 $this->assertTrue($result->isOk());
182 }
183
184 public function testParserFromEmptyString(): void
185 {
186 $primitives = new Primitives();
187
188 $intermediate = $this->getMockBuilder(Intermediate::class)->disableOriginalConstructor()->getMock();
189 $intermediate->expects(self::never())->method('value');
190 $intermediate->expects(self::never())->method('accept');
191 $intermediate->expects(self::never())->method('reject');
192
193 $parser = $primitives->parserFrom('');
194
195 $result = $parser($intermediate, fn($x) => $x);
196 $this->assertTrue($result->isOk());
197 $this->assertEquals($intermediate, $result->value());
198 }
199}
A result encapsulates a value or an error and simplifies the handling of those.
Definition: Ok.php:31
@phpstan-type Continuation Closure(Result<Intermediate>): Result<Intermediate> @phpstan-type Parser C...
Definition: Primitives.php:33
A result encapsulates a value or an error and simplifies the handling of those.
Definition: Result.php:29