packages/bison-parser/tests/Unit/Scanner/CursorTest.php

1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Scanner;
6
7use BisonParser\Ast\Location;
8use BisonParser\Scanner\Cursor;
9use PHPUnit\Framework\Attributes\CoversClass;
10use PHPUnit\Framework\Attributes\Small;
11use PHPUnit\Framework\Attributes\UsesClass;
12use PHPUnit\Framework\TestCase;
13
14#[CoversClass(Cursor::class)]
15#[UsesClass(Location::class)]
16#[Small]
17final class CursorTest extends TestCase
18{
19    public function testEof(): void
20    {
21        $cursor = new Cursor('ab');
22
23        self::assertFalse($cursor->eof());
24        $cursor->take(2);
25        self::assertTrue($cursor->eof());
26        self::assertTrue((new Cursor(''))->eof());
27    }
28
29    public function testPeek(): void
30    {
31        $cursor = new Cursor('abc');
32
33        self::assertSame('a', $cursor->peek());
34        self::assertSame('c', $cursor->peek(2));
35        self::assertSame('', $cursor->peek(3));
36    }
37
38    public function testOffset(): void
39    {
40        $cursor = new Cursor("a\nbc");
41
42        self::assertSame(0, $cursor->offset());
43        $cursor->take(3);
44        self::assertSame(3, $cursor->offset());
45    }
46
47    public function testLocation(): void
48    {
49        $cursor = new Cursor("ab\ncd\n\nef");
50
51        self::assertSame('1:1', (string) $cursor->location());
52        $cursor->take(1);
53        self::assertSame('1:2', (string) $cursor->location());
54        $cursor->take(3);
55        self::assertSame('2:2', (string) $cursor->location());
56        $cursor->take(4);
57        self::assertSame('4:2', (string) $cursor->location());
58    }
59
60    public function testStartsWith(): void
61    {
62        $cursor = new Cursor('%%rest');
63
64        self::assertTrue($cursor->startsWith('%%'));
65        self::assertFalse($cursor->startsWith('%{'));
66        $cursor->take(2);
67        self::assertTrue($cursor->startsWith('rest'));
68        self::assertFalse($cursor->startsWith('rest and more'));
69    }
70
71    public function testTake(): void
72    {
73        $cursor = new Cursor('abc');
74
75        self::assertSame('ab', $cursor->take(2));
76        self::assertSame('c', $cursor->take(5));
77        self::assertSame('', $cursor->take(1));
78        self::assertSame(3, $cursor->offset());
79    }
80
81    public function testMatch(): void
82    {
83        $cursor = new Cursor('foo~bar 12');
84
85        self::assertNull($cursor->match('[0-9]+'));
86        self::assertSame('foo~bar', $cursor->match('[a-z]+~[a-z]+'));
87        self::assertSame(7, $cursor->offset());
88        self::assertSame(' ', $cursor->take(1));
89        self::assertSame('12', $cursor->match('[0-9]+'));
90    }
91
92    public function testLookingAt(): void
93    {
94        $cursor = new Cursor('ab12');
95
96        self::assertTrue($cursor->lookingAt('[a-z]{2}'));
97        self::assertFalse($cursor->lookingAt('[0-9]'));
98        self::assertSame(0, $cursor->offset());
99        self::assertTrue((new Cursor('a~b'))->lookingAt('a~b'));
100    }
101
102    public function testTakeUntil(): void
103    {
104        $cursor = new Cursor("/* a\nb */ tail");
105
106        self::assertSame('/* a', $cursor->takeUntil("\n"));
107        self::assertSame('b ', $cursor->takeUntil('*/'));
108        self::assertSame('2:5', (string) $cursor->location());
109        self::assertNull($cursor->takeUntil('*/'));
110        self::assertSame(' tail', $cursor->take(5));
111    }
112}
113