19 declare(strict_types=1);
37 $this->assertInstanceOf(Brick::class,
new Brick());
43 $ok = $this->getMockBuilder(Result::class)->getMock();
44 $ok->method(
'isOk')->willReturn(
true);
45 $ok->method(
'value')->willReturn($expected);
46 $intermediate = $this->getMockBuilder(Intermediate::class)->disableOriginalConstructor()->getMock();
47 $intermediate->method(
'done')->willReturn(
true);
48 $intermediate->method(
'transform')->willReturnCallback(fn() => $ok);
51 $cc(
new Ok($intermediate))
54 $this->assertTrue($result->isOk());
55 $this->assertEquals($expected, $result->value());
60 $intermediate = $this->getMockBuilder(Intermediate::class)->disableOriginalConstructor()->getMock();
61 $intermediate->expects(self::once())->method(
'done')->willReturn(
false);
62 $intermediate->expects(self::never())->method(
'transform');
66 $cc(
new Ok($intermediate))
69 $this->assertFalse($result->isOk());
76 $cc(
new Error(
'something happened'))
79 $this->assertFalse($result->isOk());
85 $parser = $brick->sequence([
'foo']);
86 $transformation = $brick->toTransformation($parser);
87 $this->assertInstanceOf(Transformation::class, $transformation);
88 $result = $transformation->applyTo(
new Ok(
'foo'));
89 $this->assertTrue($result->isOk());
90 $this->assertEquals(
'foo', $result->value());
96 $parser = $brick->sequence([
'foo']);
97 $transformation = $brick->toTransformation($parser);
98 $this->assertInstanceOf(Transformation::class, $transformation);
99 $result = $transformation->applyTo(
new Ok(
'fox'));
100 $this->assertFalse($result->isOk());
105 $brick =
new Brick();
107 $parse = $brick->range(0, 0x14);
109 foreach (array_fill(0, 0x14 + 1,
null) as $i => $_) {
110 $result = $brick->apply($parse, chr($i));
111 $this->assertTrue($result->isOk());
112 $this->assertEquals(chr($i), $result->value());
118 $brick =
new Brick();
120 $parse = $brick->range(1, 0x14);
122 $this->assertFalse($brick->apply($parse,
"\x0")->isOk());
123 $this->assertFalse($brick->apply($parse,
"\x15")->isOk());
128 $brick =
new Brick();
130 $parse = $brick->either([
131 'a' => $brick->range(0x10, 0x20),
132 $brick->range(0x21, 0x30),
133 'b' => $brick->range(0x0, 0x5),
136 $result = $brick->apply($parse,
"\x0");
138 $this->assertTrue($result->isOk());
139 $this->assertEquals(
"\x0", $result->value()[
'b']);
144 $brick =
new Brick();
146 $parse = $brick->sequence([
147 'first' => $brick->range(ord(
'a'), ord(
'b')),
148 'second' => $brick->range(ord(
'c'), ord(
'd')),
151 $result = $brick->apply($parse,
'ad');
153 $this->assertTrue($result->isOk());
154 $this->assertEquals(
'a', $result->value()[
'first']);
155 $this->assertEquals(
'd', $result->value()[
'second']);
158 #[DataProvider('repeatProvider')] 159 public function testRepeat(
int $min, ?
int $max, array $succeed, array $fail): void
161 $brick =
new Brick();
162 $parse = $brick->repeat($min, $max, $brick->range(ord(
'a'), ord(
'z')));
164 foreach ($succeed as $input) {
165 $result = $brick->apply($parse, $input);
167 $this->assertTrue($result->isOk());
168 $this->assertEquals($input, $result->value());
171 foreach ($fail as $input) {
172 $result = $brick->apply($parse, $input);
173 $this->assertFalse($result->isOk());
180 'Ranges are inclusive' => [3, 3, [
'abc'], [
'ab',
'abcd']],
181 'Null is used for infinity' => [0,
null, [
'',
'abcdefghijklmop'], []],
182 'Minimum is 0' => [-1, 3, [
'',
'a',
'ab',
'abc'], [
'abcd']],
183 'Minimum of the end range is the start range' => [3, 2, [
'abc'], [
'ab',
'abcd']],
187 #[DataProvider('characterProvider')] 190 $brick =
new Brick();
192 $parse = $brick->either(str_split($input));
194 $parse = $brick->repeat(0,
null, $brick->$method());
197 $result = $brick->apply($parse, $input);
199 $this->assertEquals($isOk, $result->isOk());
201 $this->assertEquals($input, $result->value());
207 $len = (
int) floor(strlen($break_me) / $x);
210 fn($i) => substr($break_me, $i * $len, $len),
211 range(0, $x - !(strlen($break_me) % $x))
217 $alpha = array_fill(ord(
'a'), ord(
'z') - ord(
'a') + 1,
'');
218 array_walk($alpha,
function (&$value,
int $i) {
221 $alpha = implode(
'', $alpha);
222 $alpha .= strtoupper($alpha);
225 $alpha_parts = self::breakIntoPieces(3, $alpha);
227 $digits =
'1234567890';
230 'Accepts all digits.' => [
'digit', $digits,
true],
231 'Accepts no characters from a-z or A-Z.' => [
'digit', $alpha,
false],
232 'Accepts characters from a-z and A-Z (Part 1).' => [
'alpha', $alpha_parts[0],
true],
233 'Accepts characters from a-z and A-Z (Part 2).' => [
'alpha', $alpha_parts[1],
true],
234 'Accepts characters from a-z and A-Z (Part 3).' => [
'alpha', $alpha_parts[2],
true],
235 'Accepts no digits.' => [
'alpha', $digits,
false],
239 #[DataProvider('emptyStringProvider')] 242 $brick =
new Brick();
244 $parse = $brick->sequence([
'']);
245 $result = $brick->apply($parse, $input);
247 $this->assertEquals($isOk, $result->isOk());
253 'Test empty input' => [
'',
true],
254 'Test non empty input' => [
'x',
false],
260 $brick =
new Brick();
262 $intermediate = $this->getMockBuilder(Intermediate::class)->disableOriginalConstructor()->getMock();
263 $intermediate->method(
'done')->willReturn(
true);
265 $ok = $this->getMockBuilder(Result::class)->getMock();
266 $ok->method(
'isOk')->willReturn(
true);
267 $ok->method(
'value')->willReturn($intermediate);
268 $ok->method(
'map')->willReturn($ok);
269 $ok->method(
'then')->willReturn($ok);
270 $ok->method(
'except')->willReturn($ok);
272 $transformation = $this->getMockBuilder(Transformation::class)->getMock();
273 $transformation->expects(self::once())->method(
'applyTo')->willReturn($ok);
275 $parser = $brick->transformation($transformation, fn($x, $cc) => $cc(
new Ok($x)));
277 $result = $brick->apply($parser,
'a');
279 $this->assertEquals($ok, $result);
284 return static function (
string $string):
Ok {
285 return new Ok($string);
testToTransformationFailed()
testRepeat(int $min, ?int $max, array $succeed, array $fail)
static breakIntoPieces(int $x, string $break_me)
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
testEmptyString(string $input, bool $isOk)
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)
-type Continuation Closure(Result<Intermediate>): Result<Intermediate> -type Parser Closure(Intermedi...