diff options
| author | Sam Light <sam@lightscale.co.uk> | 2026-06-10 19:00:32 +0100 |
|---|---|---|
| committer | Sam Light <sam@lightscale.co.uk> | 2026-06-10 19:00:32 +0100 |
| commit | 5fe7c87967ff29c4a8f03a9186918d8359f4887e (patch) | |
| tree | dfdd4fdc7a4e96266305f82f5846750ab2efabc9 /tests | |
| parent | 01eac9658c3bc486d2d42a18557fdb82a536348e (diff) | |
big update
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/Unit/PathSegmentTest.php | 215 | ||||
| -rw-r--r-- | tests/Unit/RouteTest.php | 48 | ||||
| -rw-r--r-- | tests/Unit/RouterTest.php | 90 |
3 files changed, 323 insertions, 30 deletions
diff --git a/tests/Unit/PathSegmentTest.php b/tests/Unit/PathSegmentTest.php index 1d19e0e..c537c38 100644 --- a/tests/Unit/PathSegmentTest.php +++ b/tests/Unit/PathSegmentTest.php @@ -2,7 +2,10 @@ declare(strict_types=1); +use Lightscale\Router\Enums\HttpMethod; +use Lightscale\Router\Enums\PathSegmentType; use Lightscale\Router\PathSegment; +use Lightscale\Router\Route; it('initializes') ->expect(fn () => new PathSegment('test')) @@ -12,11 +15,60 @@ it('can get the content') ->expect(fn () => (new PathSegment('test'))->getContent()) ->toBe('test'); -it('can get the parent') - ->expect(fn () => (new PathSegment( - 'test1', - new PathSegment('test2') - ))->getParent()) +it('can be root') + ->expect((new PathSegment(type: PathSegmentType::Root))->getType()) + ->toBe(PathSegmentType::Root); + +it('nulls value when type root') + ->expect(fn () => (new PathSegment('testing', PathSegmentType::Root))->getValue()) + ->toBeNull(); + +it('gets value for type :dataset', function (PathSegmentType $type, ?string $res) { + $seg = new PathSegment($v = 'testing', $type); + expect($seg->getValue())->toBe($res); +})->with([ + ($t = PathSegmentType::Raw)->name => [$t, 'testing'], + ($t = PathSegmentType::Root)->name => [$t, null], + ($t = PathSegmentType::Parameter)->name => [$t, 'testing'], +]); + +it('gets key for type :dataset', function (PathSegmentType $type, ?string $res) { + $seg = new PathSegment($v = 'testing', $type); + expect($seg->getKey())->toBe($res); +})->with([ + ($t = PathSegmentType::Raw)->name => [$t, 'testing'], + ($t = PathSegmentType::Root)->name => [$t, '<root>'], + ($t = PathSegmentType::Parameter)->name => [$t, '<parameter>'], +]); + +it('gets type :dataset', function (PathSegmentType $type) { + $seg = new PathSegment($v = 'testing', $type); + expect($seg->getType())->toBe($type); +})->with(function (): Generator { + foreach (PathSegmentType::cases() as $t) { + yield $t->name => $t; + } +}); + +it('defaults type to Raw') + ->expect(fn () => (new PathSegment('testing'))->getType()) + ->toBe(PathSegmentType::Raw); + +$testChain = function () { + $root = new PathSegment(type: PathSegmentType::Root); + $seg1 = new PathSegment('test1'); + $seg2 = new PathSegment('test2'); + $seg3 = new PathSegment('test3'); + + $seg3->setParent($seg2); + $seg2->setParent($seg1); + $seg1->setParent($root); + + return $seg3; +}; + +it('can have a parent') + ->expect(fn () => $testChain()->getParent()) ->toBeInstanceOf(PathSegment::class) ->getContent()->toBe('test2'); @@ -24,45 +76,154 @@ it('has null parent by default') ->expect(fn () => (new PathSegment('test'))->getParent()) ->toBeNull(); -$testChain = fn () => new PathSegment( - 'test3', - new PathSegment( - 'test2', - new PathSegment( - 'test1' - ) - ) -); - it('can get all ancestors') ->expect(fn () => $testChain()->getAncestors()) ->toBeArray() ->toContainOnlyInstancesOf(PathSegment::class) - ->toHaveCount(2); + ->toHaveCount(3); it('order all ancestors root first') ->expect(fn () => $testChain()->getAncestors()) - ->{0}->getContent()->toBe('test1') - ->{1}->getContent()->toBe('test2'); + ->{0}->getContent()->toBe('') + ->{0}->getType()->toBe(PathSegmentType::Root) + ->{1}->getContent()->toBe('test1') + ->{2}->getContent()->toBe('test2'); it('can get all ancestors and self') ->expect(fn () => $testChain()->getAncestorsAndSelf()) ->toBeArray() ->toContainOnlyInstancesOf(PathSegment::class) - ->toHaveCount(3); + ->toHaveCount(4); it('order all ancestors and self root first') ->expect(fn () => $testChain()->getAncestorsAndSelf()) - ->{0}->getContent()->toBe('test1') - ->{1}->getContent()->toBe('test2') - ->{2}->getContent()->toBe('test3'); + ->{0}->getContent()->toBe('') + ->{0}->getType()->toBe(PathSegmentType::Root) + ->{1}->getContent()->toBe('test1') + ->{2}->getContent()->toBe('test2') + ->{3}->getContent()->toBe('test3'); + +$makeWithChildren = function () { + $seg = new PathSegment('test1'); + $seg->addChild(new PathSegment('test2')); + $seg->addChild(new PathSegment('test3')); + + return $seg; +}; + +it('can have children') + ->expect(fn () => $makeWithChildren()->getChildren()) + ->toBeArray() + ->toContainOnlyInstancesOf(PathSegment::class) + ->{'test2'}->getContent()->toBe('test2') + ->{'test3'}->getContent()->toBe('test3'); -it('can have children')->todo(); +it('when adding child sets its parent') + ->expect(fn () => $makeWithChildren()->getChildren()) + ->{'test2'}->getParent()->toBeInstanceOf(PathSegment::class); -it('can build full path')->todo(); +it('gets the children count') + ->expect(fn () => $makeWithChildren()->getChildrenCount()) + ->toBe(2); -it('can have routes')->todo(); +it('can build full path') + ->expect(fn () => $testChain()->getPath()) + ->toBe('/test1/test2/test3'); -it('can get routes by method')->todo(); +it('creates new child and returns') + ->expect(fn () => (new PathSegment('test1'))->child('test2')) + ->toBeInstanceOf(PathSegment::class) + ->getContent()->toBe('test2'); -it('can get routes for all methods')->todo(); +it('creates new child added to children') + ->expect(function () { + $seg = new PathSegment('test1'); + $seg->child('test2'); + + return $seg->getChildren(); + }) + ->toHaveCount(1); + +it('does not add same child twice', function () { + $seg = new PathSegment('test1'); + $seg2 = $seg->child('test2'); + $seg3 = $seg->child('test2'); + + expect($seg2)->toBe($seg3); + expect($seg->getChildrenCount())->toBe(1); +}); + +it('can get a raw segment child', function () { + $seg = new PathSegment('test1'); + $c1 = $seg->child('test2'); + $c2 = $seg->child('test3'); + + expect($seg->findChild('test2'))->toBe($c1); + expect($seg->findChild('test3'))->toBe($c2); +}); + +it('can get a parameter segment child', function () { + $seg = new PathSegment('test1'); + $c1 = $seg->child('test2'); + $c2 = $seg->child('test3', PathSegmentType::Parameter); + + expect($seg->findChild('test2'))->toBe($c1); + expect($seg->findChild('test4'))->toBe($c2); +}); + +it('sets route segment when added', function () { + $seg = new PathSegment('test1'); + $seg->addRoute($r = new Route( + HttpMethod::Get, + fn () => null + )); + + expect($r->getSegment())->toBe($seg); +}); + +it('can have routes', function () { + $seg = new PathSegment('test'); + $seg->addRoute($r1 = new Route( + HttpMethod::Get, + fn () => null, + )); + $seg->addRoute($r2 = new Route( + HttpMethod::Post, + fn () => null, + )); + + expect($seg->getRoutes()) + ->toHaveCount(2) + ->{HttpMethod::Get->value}->toBe($r1) + ->{HttpMethod::Post->value}->toBe($r2); +}); + +it('overwrites existing routes', function () { + $seg = new PathSegment('test'); + $seg->addRoute($r1 = new Route( + HttpMethod::Get, + fn () => null, + )); + $seg->addRoute($r2 = new Route( + HttpMethod::Get, + fn () => null, + )); + + expect($seg->getRoutes()) + ->toHaveCount(1) + ->{HttpMethod::Get->value}->toBe($r2); +}); + +it('can get route by method', function () { + $seg = new PathSegment('test'); + $seg->addRoute($r = new Route( + HttpMethod::Get, + fn () => null, + )); + + expect($seg->getRoute(HttpMethod::Get))->toBe($r); +}); + +it('gets null with route method that doesn\'t exist') + ->expect(fn () => (new PathSegment('test'))->getRoute(HttpMethod::Get)) + ->toBeNull(); diff --git a/tests/Unit/RouteTest.php b/tests/Unit/RouteTest.php index 0414649..104401b 100644 --- a/tests/Unit/RouteTest.php +++ b/tests/Unit/RouteTest.php @@ -3,14 +3,56 @@ declare(strict_types=1); use Lightscale\Router\Enums\HttpMethod; -use Lightscale\Router\Enums\SpecialSegment; +use Lightscale\Router\Enums\PathSegmentType; use Lightscale\Router\PathSegment; use Lightscale\Router\Route; +use Nyholm\Psr7\Factory\Psr17Factory; +use Psr\Http\Message\RequestInterface; it('initializes') ->expect(fn () => new Route( - new PathSegment(SpecialSegment::Root), HttpMethod::Get, - fn () => null + fn () => null, + new PathSegment(type: PathSegmentType::Root), )) ->toBeInstanceOf(Route::class); + +it('gets segment') + ->expect(fn () => (new Route( + HttpMethod::Get, + fn () => null, + new PathSegment(type: PathSegmentType::Root), + ))->getSegment()) + ->toBeInstanceOf(PathSegment::class); + +it('throws getting segment without being set', function () { + $r = new Route(HttpMethod::Get, fn () => null); + $r->getSegment(); +})->throws(Error::class); + +it('can set segment') + ->expect(function () { + $r = new Route(HttpMethod::Get, fn () => null); + $r->setSegment(new PathSegment('test')); + + return $r->getSegment(); + }) + ->toBeInstanceOf(PathSegment::class) + ->getValue()->toBe('test'); + +it('gets method') + ->expect(fn () => (new Route( + HttpMethod::Get, + fn () => null, + ))->getMethod()) + ->toBe(HttpMethod::Get); + +it('can call handler') + ->expect(fn () => (new Route( + HttpMethod::Get, + fn (RequestInterface $req) => $req->getUri()->getPath() + ))( + (new Psr17Factory())->createRequest(HttpMethod::Get->value, '/testing') + ) + ) + ->toBe('/testing'); diff --git a/tests/Unit/RouterTest.php b/tests/Unit/RouterTest.php new file mode 100644 index 0000000..5d08441 --- /dev/null +++ b/tests/Unit/RouterTest.php @@ -0,0 +1,90 @@ +<?php + +declare(strict_types=1); + +use Lightscale\Router\Enums\PathSegmentType; +use Lightscale\Router\PathSegment; +use Lightscale\Router\Router; + +it('initializes') + ->expect(fn () => new Router()) + ->toBeInstanceOf(Router::class); + +it('has root') + ->expect(fn () => (new Router())->root()) + ->toBeInstanceOf(PathSegment::class) + ->getType()->toBe(PathSegmentType::Root); + +it('finds root segment with :dataset path', function (string $path) { + $router = new Router(); + expect($router->findSegment($path))->segment->toBe($router->root()); +})->with(['', '/']); + +it('finds segment one level', function () { + $router = new Router(); + $c1 = $router->root()->child($p1 = 'test1'); + $c2 = $router->root()->child($p2 = 'test2'); + + expect($router->findSegment("/{$p1}"))->segment->toBe($c1); + expect($router->findSegment("/{$p2}"))->segment->toBe($c2); +}); + +it('finds segment one level parameter', function () { + $router = new Router(); + $c1 = $router->root()->child('test2', PathSegmentType::Parameter); + + expect($router->findSegment('/anything')) + ->segment->toBe($c1) + ->parameters->{'test2'}->toBe('anything'); +}); + +it('finds segment one falls back to parameter', function () { + $router = new Router(); + $c1 = $router->root()->child($p1 = 'test1'); + $c2 = $router->root()->child('test2', PathSegmentType::Parameter); + + expect($router->findSegment("/{$p1}"))->segment->toBe($c1); + expect($router->findSegment('/anything')) + ->segment->toBe($c2) + ->parameters->{'test2'}->toBe('anything'); +}); + +it('finds segments in complex routes', function () { + $router = new Router(); + + $r = $router->root(); + + $s1 = $r->child('level1-1')->child('level2-1'); + $s2 = $r->child('level1-1')->child('level2-2'); + $s3 = $r->child('level1-2')->child('level2-3'); + $s4 = $r->child('level1-1')->child('level2-2')->child('level3-1'); + $s5 = $r->child('level1-1'); + $s6 = $r->child('level1-3')->child('level2-4', PathSegmentType::Parameter); + $s7 = $s6->child('level3-2'); + $s8 = $s6->child('level3-3'); + + expect($router->findSegment('/level1-1')?->segment)->toBe($s5); + expect($router->findSegment('/level1-2/level2-3')?->segment)->toBe($s3); + expect($router->findSegment('/level1-1/level2-2/level3-1')?->segment)->toBe($s4); + expect($router->findSegment('/level1-1/level2-1')?->segment)->toBe($s1); + expect($router->findSegment('/level1-1/level2-2')?->segment)->toBe($s2); + expect($router->findSegment('/level1-3/param1')) + ->segment->toBe($s6) + ->parameters->{'level2-4'}->toBe('param1'); + expect($router->findSegment('/level1-3/param2/level3-2')) + ->segment->toBe($s7) + ->parameters->{'level2-4'}->toBe('param2'); + expect($router->findSegment('/level1-3/param3/level3-3')) + ->segment->toBe($s8) + ->parameters->{'level2-4'}->toBe('param3'); +}); + +it('return null when segment not found', function () { + $router = new Router(); + $r = $router->root(); + $r->child('level1-1')->child('level2-1'); + $r->child('level1-1')->child('level2-2'); + $r->child('level1-2')->child('level2-3'); + + expect($router->findSegment('/testing/testing'))->toBeNull(); +}); |
