| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369 |
- <?php
- namespace think\tests;
- use Closure;
- use Mockery as m;
- use Mockery\MockInterface;
- use PHPUnit\Framework\TestCase;
- use think\helper\Str;
- use think\Request;
- use think\response\Redirect;
- use think\response\View;
- use think\Route;
- class RouteTest extends TestCase
- {
- use InteractsWithApp;
- /** @var Route|MockInterface */
- protected $route;
- protected function tearDown(): void
- {
- m::close();
- }
- protected function setUp(): void
- {
- $this->prepareApp();
- $this->config->shouldReceive('get')->with('route')->andReturn(['url_route_must' => true]);
- $this->route = new Route($this->app);
- }
- /**
- * @param $path
- * @param string $method
- * @param string $host
- * @return m\Mock|Request
- */
- protected function makeRequest($path, $method = 'GET', $host = 'localhost')
- {
- $request = m::mock(Request::class)->makePartial();
- $request->shouldReceive('host')->andReturn($host);
- $request->shouldReceive('pathinfo')->andReturn($path);
- $request->shouldReceive('url')->andReturn('/' . $path);
- $request->shouldReceive('method')->andReturn(strtoupper($method));
- return $request;
- }
- public function testSimpleRequest()
- {
- $this->route->get('foo', function () {
- return 'get-foo';
- });
- $this->route->put('foo', function () {
- return 'put-foo';
- });
- $this->route->group(function () {
- $this->route->post('foo', function () {
- return 'post-foo';
- });
- });
- $request = $this->makeRequest('foo', 'post');
- $response = $this->route->dispatch($request);
- $this->assertEquals(200, $response->getCode());
- $this->assertEquals('post-foo', $response->getContent());
- $request = $this->makeRequest('foo', 'get');
- $response = $this->route->dispatch($request);
- $this->assertEquals(200, $response->getCode());
- $this->assertEquals('get-foo', $response->getContent());
- }
- public function testGroup()
- {
- $this->route->group(function () {
- $this->route->group('foo', function () {
- $this->route->post('bar', function () {
- return 'hello,world!';
- });
- });
- });
- $request = $this->makeRequest('foo/bar', 'post');
- $response = $this->route->dispatch($request);
- $this->assertEquals(200, $response->getCode());
- $this->assertEquals('hello,world!', $response->getContent());
- }
- public function testAllowCrossDomain()
- {
- $this->route->get('foo', function () {
- return 'get-foo';
- })->allowCrossDomain(['some' => 'bar']);
- $request = $this->makeRequest('foo', 'get');
- $response = $this->route->dispatch($request);
- $this->assertEquals('bar', $response->getHeader('some'));
- $this->assertArrayHasKey('Access-Control-Allow-Credentials', $response->getHeader());
- //$this->expectException(RouteNotFoundException::class);
- $request = $this->makeRequest('foo2', 'options');
- $this->route->dispatch($request);
- }
- public function testControllerDispatch()
- {
- $this->route->get('foo', 'foo/bar');
- $controller = m::Mock(\stdClass::class);
- $this->app->shouldReceive('parseClass')->with('controller', 'Foo')->andReturn($controller->mockery_getName());
- $this->app->shouldReceive('make')->with($controller->mockery_getName(), [], true)->andReturn($controller);
- $controller->shouldReceive('bar')->andReturn('bar');
- $request = $this->makeRequest('foo');
- $response = $this->route->dispatch($request);
- $this->assertEquals('bar', $response->getContent());
- }
- public function testEmptyControllerDispatch()
- {
- $this->route->get('foo', 'foo/bar');
- $controller = m::Mock(\stdClass::class);
- $this->app->shouldReceive('parseClass')->with('controller', 'Error')->andReturn($controller->mockery_getName());
- $this->app->shouldReceive('make')->with($controller->mockery_getName(), [], true)->andReturn($controller);
- $controller->shouldReceive('bar')->andReturn('bar');
- $request = $this->makeRequest('foo');
- $response = $this->route->dispatch($request);
- $this->assertEquals('bar', $response->getContent());
- }
- protected function createMiddleware($times = 1)
- {
- $middleware = m::mock(Str::random(5));
- $middleware->shouldReceive('handle')->times($times)->andReturnUsing(function ($request, Closure $next) {
- return $next($request);
- });
- $this->app->shouldReceive('make')->with($middleware->mockery_getName())->andReturn($middleware);
- return $middleware;
- }
- public function testControllerWithMiddleware()
- {
- $this->route->get('foo', 'foo/bar');
- $controller = m::mock(FooClass::class);
- $controller->middleware = [
- $this->createMiddleware()->mockery_getName() . ":params1:params2",
- $this->createMiddleware(0)->mockery_getName() => ['except' => 'bar'],
- $this->createMiddleware()->mockery_getName() => ['only' => 'bar'],
- [
- 'middleware' => [$this->createMiddleware()->mockery_getName(), [new \stdClass()]],
- 'options' => ['only' => 'bar'],
- ],
- ];
- $this->app->shouldReceive('parseClass')->with('controller', 'Foo')->andReturn($controller->mockery_getName());
- $this->app->shouldReceive('make')->with($controller->mockery_getName(), [], true)->andReturn($controller);
- $controller->shouldReceive('bar')->once()->andReturn('bar');
- $request = $this->makeRequest('foo');
- $response = $this->route->dispatch($request);
- $this->assertEquals('bar', $response->getContent());
- }
- public function testRedirectDispatch()
- {
- $this->route->redirect('foo', 'http://localhost', 302);
- $request = $this->makeRequest('foo');
- $this->app->shouldReceive('make')->with(Request::class)->andReturn($request);
- $response = $this->route->dispatch($request);
- $this->assertInstanceOf(Redirect::class, $response);
- $this->assertEquals(302, $response->getCode());
- $this->assertEquals('http://localhost', $response->getData());
- }
- public function testViewDispatch()
- {
- $this->route->view('foo', 'index/hello', ['city' => 'shanghai']);
- $request = $this->makeRequest('foo');
- $response = $this->route->dispatch($request);
- $this->assertInstanceOf(View::class, $response);
- $this->assertEquals(['city' => 'shanghai'], $response->getVars());
- $this->assertEquals('index/hello', $response->getData());
- }
- public function testDomainBindResponse()
- {
- $this->route->domain('test', function () {
- $this->route->get('/', function () {
- return 'Hello,ThinkPHP';
- });
- });
- $request = $this->makeRequest('', 'get', 'test.domain.com');
- $response = $this->route->dispatch($request);
- $this->assertEquals('Hello,ThinkPHP', $response->getContent());
- $this->assertEquals(200, $response->getCode());
- }
- public function testResourceRouting()
- {
- // Test basic resource registration (returns ResourceRegister when not lazy)
- $resource = $this->route->resource('users', 'Users');
- $this->assertTrue($resource instanceof \think\route\Resource || $resource instanceof \think\route\ResourceRegister);
-
- // Test REST methods configuration
- $restMethods = $this->route->getRest();
- $this->assertIsArray($restMethods);
- $this->assertArrayHasKey('index', $restMethods);
- $this->assertArrayHasKey('create', $restMethods);
- $this->assertArrayHasKey('save', $restMethods);
- $this->assertArrayHasKey('read', $restMethods);
- $this->assertArrayHasKey('edit', $restMethods);
- $this->assertArrayHasKey('update', $restMethods);
- $this->assertArrayHasKey('delete', $restMethods);
-
- // Test custom REST method modification
- $this->route->rest('custom', ['get', '/custom', 'customAction']);
- $customMethod = $this->route->getRest('custom');
- $this->assertEquals(['get', '/custom', 'customAction'], $customMethod);
- }
- public function testUrlGeneration()
- {
- $this->route->get('user/<id>', 'User/detail')->name('user.detail');
- $this->route->post('user', 'User/save')->name('user.save');
- $urlBuild = $this->route->buildUrl('user.detail', ['id' => 123]);
- $this->assertInstanceOf(\think\route\Url::class, $urlBuild);
- $urlBuild = $this->route->buildUrl('user.save');
- $this->assertInstanceOf(\think\route\Url::class, $urlBuild);
- }
- public function testRouteParameterBinding()
- {
- $this->route->get('user/<id>', function ($id) {
- return "User ID: $id";
- });
- $request = $this->makeRequest('user/123', 'get');
- $response = $this->route->dispatch($request);
- $this->assertEquals('User ID: 123', $response->getContent());
- // Test multiple parameters
- $this->route->get('post/<year>/<month>', function ($year, $month) {
- return "Year: $year, Month: $month";
- });
- $request = $this->makeRequest('post/2024/12', 'get');
- $response = $this->route->dispatch($request);
- $this->assertEquals('Year: 2024, Month: 12', $response->getContent());
- }
- public function testRoutePatternValidation()
- {
- $this->route->get('user/<id>', function ($id) {
- return "User ID: $id";
- })->pattern(['id' => '\d+']);
- // Valid numeric ID
- $request = $this->makeRequest('user/123', 'get');
- $response = $this->route->dispatch($request);
- $this->assertEquals('User ID: 123', $response->getContent());
- // Test pattern with name validation
- $this->route->get('profile/<name>', function ($name) {
- return "Profile: $name";
- })->pattern(['name' => '[a-zA-Z]+']);
- $request = $this->makeRequest('profile/john', 'get');
- $response = $this->route->dispatch($request);
- $this->assertEquals('Profile: john', $response->getContent());
- }
- public function testMissRoute()
- {
- $this->route->get('home', function () {
- return 'home page';
- });
- $this->route->miss(function () {
- return 'Page not found';
- });
- // Test existing route
- $request = $this->makeRequest('home', 'get');
- $response = $this->route->dispatch($request);
- $this->assertEquals('home page', $response->getContent());
- // Test miss route
- $request = $this->makeRequest('nonexistent', 'get');
- $response = $this->route->dispatch($request);
- $this->assertEquals('Page not found', $response->getContent());
- }
- public function testRouteMiddleware()
- {
- $middleware = $this->createMiddleware();
-
- $this->route->get('protected', function () {
- return 'protected content';
- })->middleware($middleware->mockery_getName());
- $request = $this->makeRequest('protected', 'get');
- $response = $this->route->dispatch($request);
- $this->assertEquals('protected content', $response->getContent());
- }
- public function testRouteOptions()
- {
- $this->route->get('api/<version>/users', function ($version) {
- return "API Version: $version";
- })->option(['version' => '1.0']);
- $request = $this->makeRequest('api/v2/users', 'get');
- $response = $this->route->dispatch($request);
- $this->assertEquals('API Version: v2', $response->getContent());
- }
- public function testRouteCache()
- {
- // Test route configuration
- $config = $this->route->config();
- $this->assertIsArray($config);
-
- $caseConfig = $this->route->config('url_case_sensitive');
- $this->assertIsBool($caseConfig);
-
- // Test route name management
- $this->route->get('test', function () {
- return 'test';
- })->name('test.route');
-
- $names = $this->route->getName('test.route');
- $this->assertIsArray($names);
- }
- }
- class FooClass
- {
- public $middleware = [];
- public function bar()
- {
- }
- }
|