expect(fn () => new Router()) ->toBeInstanceOf(Router::class); it('initializes with basic strategy') ->expect((new Router())->getStrategy()) ->toBeInstanceOf(BasicStrategy::class); it('can set strategy', function () { $router = new Router(); $s = new BasicStrategy(); expect($router->getStrategy())->not->toBe($s); $router->setStrategy($s); expect($router->getStrategy())->toBe($s); }); 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(); }); it('returns null when finding route') ->expect(fn () => (new Router())->findRoute(HttpMethod::Get, '/')) ->toBeNull(); it('finds a route', function () { $router = new Router(); $seg = $router->root()->child('testing'); $route = new Route(HttpMethod::Get, fn () => null); $seg->addRoute($route); $result = $router->findRoute(HttpMethod::Get, '/testing'); expect($result) ->toBeInstanceOf(RouteMatch::class) ->segmentMatch->segment->toBe($seg) ->route->toBe($route); }); it('finds any method route', function () { $router = new Router(); $router->root()->child('testing')->addRoute(new Route( HttpMethod::Any, fn () => null )); $result = $router->findRoute(HttpMethod::Get, '/testing'); expect($result)->toBeInstanceOf(RouteMatch::class); }); it('finds route method case insenitively', function () { $router = new Router(); $router->root()->child('testing')->addRoute(new Route( HttpMethod::Get, fn () => null )); $result = $router->findRoute('gET', '/testing'); expect($result)->toBeInstanceOf(RouteMatch::class); }); it('calls strategy notFound with dispatch', function () { $router = new Router(); $factory = new Psr17Factory(); $request = $factory->createServerRequest(HttpMethod::Get->value, '/testing/testing'); $response = $factory->createResponse(); $strat = Mockery::mock(Strategy::class); $strat->shouldReceive('notFound') ->with($request) ->andReturn($response); $router->setStrategy($strat); $result = $router->dispatch($request); expect($result)->toBe($response); }); it('calls strategy runRoute with dispatch on match', function () { $router = new Router(); $router->root()->child('testing')->addRoute(new Route( HttpMethod::Get, fn () => null, )); $factory = new Psr17Factory(); $request = $factory->createServerRequest(HttpMethod::Get->value, '/testing'); $response = $factory->createResponse(); $strat = Mockery::mock(Strategy::class); $strat->shouldReceive('runRoute') ->with(Mockery::type(RouteCall::class)) ->andReturn($response); $router->setStrategy($strat); $result = $router->dispatch($request); expect($result)->toBe($response); }); it('make a route', function () { $router = new Router(); $router->route(HttpMethod::Get, '/test1/test2/test3', fn () => null); expect($router->findRoute(HttpMethod::Get, '/test1/test2/test3')) ->toBeInstanceOf(RouteMatch::class); }); it('makes a get route', function () { $router = new Router(); $router->get('/test1/test2', fn () => null); expect($router->findRoute(HttpMethod::Get, '/test1/test2')) ->toBeInstanceOf(RouteMatch::class); }); it('makes a post route', function () { $router = new Router(); $router->post('/test1/test2', fn () => null); expect($router->findRoute(HttpMethod::Post, '/test1/test2')) ->toBeInstanceOf(RouteMatch::class); }); it('makes a :dataset route') ->with(function (): Generator { foreach (HttpMethod::cases() as $m) { yield $m->value => $m; } }) ->expect(function (HttpMethod $m) { $router = new Router(); $router->{$m->value}($p = '/test1/test2', fn () => null); return $router->findRoute($m, $p); }) ->toBeInstanceOf(RouteMatch::class);