19 declare(strict_types=1);
36 $this->assertInstanceOf(Brick::class,
new Brick());
42 $ok = $this->getMockBuilder(Result::class)->getMock();
43 $ok->method(
'isOk')->willReturn(
true);
44 $ok->method(
'value')->willReturn($expected);
45 $intermediate = $this->getMockBuilder(Intermediate::class)->disableOriginalConstructor()->getMock();
46 $intermediate->method(
'done')->willReturn(
true);
47 $intermediate->method(
'transform')->willReturnCallback(fn() => $ok);
50 $cc(
new Ok($intermediate))
53 $this->assertTrue($result->isOk());
54 $this->assertEquals($expected, $result->value());
59 $intermediate = $this->getMockBuilder(Intermediate::class)->disableOriginalConstructor()->getMock();
60 $intermediate->expects(self::once())->method(
'done')->willReturn(
false);
61 $intermediate->expects(self::never())->method(
'transform');
65 $cc(
new Ok($intermediate))
68 $this->assertFalse($result->isOk());
75 $cc(
new Error(
'something happened'))
78 $this->assertFalse($result->isOk());
84 $parser = $brick->sequence([
'foo']);
85 $transformation = $brick->toTransformation($parser);
86 $this->assertInstanceOf(Transformation::class, $transformation);
87 $result = $transformation->applyTo(
new Ok(
'foo'));
88 $this->assertTrue($result->isOk());
89 $this->assertEquals(
'foo', $result->value());
95 $parser = $brick->sequence([
'foo']);
96 $transformation = $brick->toTransformation($parser);
97 $this->assertInstanceOf(Transformation::class, $transformation);
98 $result = $transformation->applyTo(
new Ok(
'fox'));
99 $this->assertFalse($result->isOk());
104 $brick =
new Brick();
106 $parse = $brick->range(0, 0x14);
108 foreach (array_fill(0, 0x14 + 1,
null) as $i => $_) {
109 $result = $brick->apply($parse, chr($i));
110 $this->assertTrue($result->isOk());
111 $this->assertEquals(chr($i), $result->value());
117 $brick =
new Brick();
119 $parse = $brick->range(1, 0x14);
121 $this->assertFalse($brick->apply($parse,
"\x0")->isOk());
122 $this->assertFalse($brick->apply($parse,
"\x15")->isOk());
127 $brick =
new Brick();
129 $parse = $brick->either([
130 'a' => $brick->range(0x10, 0x20),
131 $brick->range(0x21, 0x30),
132 'b' => $brick->range(0x0, 0x5),
135 $result = $brick->apply($parse,
"\x0");
137 $this->assertTrue($result->isOk());
138 $this->assertEquals(
"\x0", $result->value()[
'b']);
143 $brick =
new Brick();
145 $parse = $brick->sequence([
146 'first' => $brick->range(ord(
'a'), ord(
'b')),
147 'second' => $brick->range(ord(
'c'), ord(
'd')),
150 $result = $brick->apply($parse,
'ad');
152 $this->assertTrue($result->isOk());
153 $this->assertEquals(
'a', $result->value()[
'first']);
154 $this->assertEquals(
'd', $result->value()[
'second']);
160 public function testRepeat(
int $min, ?
int $max, array $succeed, array $fail): void
162 $brick =
new Brick();
163 $parse = $brick->repeat($min, $max, $brick->range(ord(
'a'), ord(
'z')));
165 foreach ($succeed as $input) {
166 $result = $brick->apply($parse, $input);
168 $this->assertTrue($result->isOk());
169 $this->assertEquals($input, $result->value());
172 foreach ($fail as $input) {
173 $result = $brick->apply($parse, $input);
174 $this->assertFalse($result->isOk());
181 'Ranges are inclusive' => [3, 3, [
'abc'], [
'ab',
'abcd']],
182 'Null is used for infinity' => [0,
null, [
'',
'abcdefghijklmop'], []],
183 'Minimum is 0' => [-1, 3, [
'',
'a',
'ab',
'abc'], [
'abcd']],
184 'Minimum of the end range is the start range' => [3, 2, [
'abc'], [
'ab',
'abcd']],
193 $brick =
new Brick();
195 $parse = $brick->either(str_split($input));
197 $parse = $brick->repeat(0,
null, $brick->$method());
200 $result = $brick->apply($parse, $input);
202 $this->assertEquals($isOk, $result->isOk());
204 $this->assertEquals($input, $result->value());
210 $len = (
int) floor(strlen($break_me) / $x);
213 fn($i) => substr($break_me, $i * $len, $len),
214 range(0, $x - !(strlen($break_me) % $x))
220 $alpha = array_fill(ord(
'a'), ord(
'z') - ord(
'a') + 1,
'');
221 array_walk($alpha,
function (&$value,
int $i) {
224 $alpha = implode(
'', $alpha);
225 $alpha .= strtoupper($alpha);
228 $alpha_parts = self::breakIntoPieces(3, $alpha);
230 $digits =
'1234567890';
233 'Accepts all digits.' => [
'digit', $digits,
true],
234 'Accepts no characters from a-z or A-Z.' => [
'digit', $alpha,
false],
235 'Accepts characters from a-z and A-Z (Part 1).' => [
'alpha', $alpha_parts[0],
true],
236 'Accepts characters from a-z and A-Z (Part 2).' => [
'alpha', $alpha_parts[1],
true],
237 'Accepts characters from a-z and A-Z (Part 3).' => [
'alpha', $alpha_parts[2],
true],
238 'Accepts no digits.' => [
'alpha', $digits,
false],
247 $brick =
new Brick();
249 $parse = $brick->sequence([
'']);
250 $result = $brick->apply($parse, $input);
252 $this->assertEquals($isOk, $result->isOk());
258 'Test empty input' => [
'',
true],
259 'Test non empty input' => [
'x',
false],
265 $brick =
new Brick();
267 $intermediate = $this->getMockBuilder(Intermediate::class)->disableOriginalConstructor()->getMock();
268 $intermediate->method(
'done')->willReturn(
true);
270 $ok = $this->getMockBuilder(Result::class)->getMock();
271 $ok->method(
'isOk')->willReturn(
true);
272 $ok->method(
'value')->willReturn($intermediate);
273 $ok->method(
'map')->willReturn($ok);
274 $ok->method(
'then')->willReturn($ok);
275 $ok->method(
'except')->willReturn($ok);
277 $transformation = $this->getMockBuilder(Transformation::class)->getMock();
278 $transformation->expects(self::once())->method(
'applyTo')->willReturn($ok);
280 $parser = $brick->transformation($transformation, fn($x, $cc) => $cc(
new Ok($x)));
282 $result = $brick->apply($parser,
'a');
284 $this->assertEquals($ok, $result);
289 return static function (
string $string):
Ok {
290 return new Ok($string);
testToTransformationFailed()
testRepeat(int $min, ?int $max, array $succeed, array $fail)
repeatProvider
static breakIntoPieces(int $x, string $break_me)
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
testEmptyString(string $input, bool $isOk)
emptyStringProvider
static characterProvider()
A result encapsulates a value or an error and simplifies the handling of those.
static emptyStringProvider()
testThatAllInputMustBeConsumed()
testCharacters(string $method, string $input, bool $isOk)
characterProvider
-type Continuation Closure(Result<Intermediate>): Result<Intermediate> -type Parser Closure(Intermedi...