diff --git a/.gitignore b/.gitignore index 28b4abc7..06024100 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ .env .sass-cache coverage +.idea/ vendor/* plugins/* storage/textures/* diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index 758296ac..1a54216b 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -36,7 +36,7 @@ class Handler extends ExceptionHandler */ public function report(Exception $e) { - return parent::report($e); + parent::report($e); } /** @@ -56,7 +56,7 @@ class Handler extends ExceptionHandler abort(403, 'Method not allowed.'); } - if ($e instanceof PrettyPageException && PHP_SAPI != "cli") { + if ($e instanceof PrettyPageException) { return $e->showErrorPage(); } @@ -84,19 +84,21 @@ class Handler extends ExceptionHandler * Render an exception using Whoops. * * @param \Exception $e + * @param int $code + * @param array $headers * @return \Illuminate\Http\Response */ - protected function renderExceptionWithWhoops(Exception $e) + protected function renderExceptionWithWhoops(Exception $e, $code = 200, $headers = []) { $whoops = new \Whoops\Run; - $handler = ($_SERVER['REQUEST_METHOD'] == "GET") ? + $handler = (request()->isMethod('GET')) ? new \Whoops\Handler\PrettyPageHandler : new \Whoops\Handler\PlainTextHandler; $whoops->pushHandler($handler); return new \Illuminate\Http\Response( $whoops->handleException($e), - $e->getStatusCode(), - $e->getHeaders() + $code, + $headers ); } @@ -108,7 +110,7 @@ class Handler extends ExceptionHandler */ protected function renderExceptionInBrief(Exception $e) { - if ($_SERVER['REQUEST_METHOD'] == "GET" && !app('request')->ajax()) { + if (request()->isMethod('GET') && !request()->ajax()) { return response()->view('errors.exception', ['message' => $e->getMessage()]); } else { return $e->getMessage(); diff --git a/app/Http/Middleware/CheckPlayerExist.php b/app/Http/Middleware/CheckPlayerExist.php index f098d3bc..e1e0126d 100644 --- a/app/Http/Middleware/CheckPlayerExist.php +++ b/app/Http/Middleware/CheckPlayerExist.php @@ -18,10 +18,10 @@ class CheckPlayerExist $player_name = urldecode($matches[1]); - $responses = Event::fire(new CheckPlayerExists($player_name)); + $responses = event(new CheckPlayerExists($player_name)); foreach ($responses as $r) { - if ($r) return $next($request); + if ($r) return $next($request); // @codeCoverageIgnore } if (!Player::where('player_name', $player_name)->get()->isEmpty()) @@ -34,7 +34,7 @@ class CheckPlayerExist 'msg' => 'Player Not Found.' ])->header('Cache-Control', 'public, max-age='.option('cache_expire_time')); } else { - abort(404, trans('general.unexistent-player')); + return abort(404, trans('general.unexistent-player')); } } diff --git a/app/Http/Middleware/RedirectIfAuthenticated.php b/app/Http/Middleware/RedirectIfAuthenticated.php index b0545716..6c0295e8 100644 --- a/app/Http/Middleware/RedirectIfAuthenticated.php +++ b/app/Http/Middleware/RedirectIfAuthenticated.php @@ -12,7 +12,7 @@ class RedirectIfAuthenticated { if (session()->has('uid')) { if (session('token') != app('users')->get(session('uid'))->getToken()) { - Session::put('msg', trans('auth.check.token')); + Session::put('msg', trans('auth.check.token')); // @codeCoverageIgnore } else { return redirect('user'); } diff --git a/database/factories/PlayerModelFactory.php b/database/factories/PlayerModelFactory.php new file mode 100644 index 00000000..8a685f2f --- /dev/null +++ b/database/factories/PlayerModelFactory.php @@ -0,0 +1,21 @@ +define(Player::class, function (Faker\Generator $faker) { + return [ + 'uid' => factory(App\Models\User::class)->create()->uid, + 'player_name' => $faker->firstName, + 'preference' => 'default', + 'last_modified' => $faker->dateTime + ]; +}); + +$factory->defineAs(Player::class, 'slim', function (Faker\Generator $faker) { + return [ + 'uid' => factory(App\Models\User::class)->create()->uid, + 'player_name' => $faker->firstName, + 'preference' => 'slim', + 'last_modified' => $faker->dateTime + ]; +}); diff --git a/database/factories/UserModelFactory.php b/database/factories/UserModelFactory.php new file mode 100644 index 00000000..8359104b --- /dev/null +++ b/database/factories/UserModelFactory.php @@ -0,0 +1,59 @@ +define(User::class, function (Faker\Generator $faker) { + return [ + 'email' => $faker->email, + 'nickname' => $faker->name, + 'score' => 1000, + 'avatar' => 0, + 'password' => app('cipher')->hash(str_random(10), config('secure.salt')), + 'ip' => '127.0.0.1', + 'permission' => 0, + 'last_sign_at' => $faker->dateTime, + 'register_at' => $faker->dateTime + ]; +}); + +$factory->defineAs(User::class, 'admin', function (Faker\Generator $faker) { + return [ + 'email' => $faker->email, + 'nickname' => $faker->name, + 'score' => 1000, + 'avatar' => 0, + 'password' => app('cipher')->hash(str_random(10), config('secure.salt')), + 'ip' => '127.0.0.1', + 'permission' => 1, + 'last_sign_at' => $faker->dateTime, + 'register_at' => $faker->dateTime + ]; +}); + +$factory->defineAs(User::class, 'superAdmin', function (Faker\Generator $faker) { + return [ + 'email' => $faker->email, + 'nickname' => $faker->name, + 'score' => 1000, + 'avatar' => 0, + 'password' => app('cipher')->hash(str_random(10), config('secure.salt')), + 'ip' => '127.0.0.1', + 'permission' => 2, + 'last_sign_at' => $faker->dateTime, + 'register_at' => $faker->dateTime + ]; +}); + +$factory->defineAs(User::class, 'banned', function (Faker\Generator $faker) { + return [ + 'email' => $faker->email, + 'nickname' => $faker->name, + 'score' => 1000, + 'avatar' => 0, + 'password' => app('cipher')->hash(str_random(10), config('secure.salt')), + 'ip' => '127.0.0.1', + 'permission' => -1, + 'last_sign_at' => $faker->dateTime, + 'register_at' => $faker->dateTime + ]; +}); diff --git a/phpunit.xml b/phpunit.xml index 3e884d17..115360a2 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -23,6 +23,7 @@ + diff --git a/tests/HomeControllerTest.php b/tests/HomeControllerTest.php new file mode 100644 index 00000000..fa4d2345 --- /dev/null +++ b/tests/HomeControllerTest.php @@ -0,0 +1,23 @@ +get('/') + ->see(option('site_name')) + ->see(option('site_description')) + ->assertViewHas('home_pic_url', option('home_pic_url')); + + $this->visit('/')->click('Log In')->seePageIs('/auth/login'); + $this->visit('/')->click('#btn-register')->seePageIs('/auth/register'); + + // Nav bar + $this->visit('/')->click('Homepage')->seePageIs('/'); + $this->visit('/')->click('Skin Library')->seePageIs('/skinlib'); + } +} diff --git a/tests/MiddlewareTest.php b/tests/MiddlewareTest.php new file mode 100644 index 00000000..0fb5ab42 --- /dev/null +++ b/tests/MiddlewareTest.php @@ -0,0 +1,141 @@ +visit('/user')->seePageIs('/auth/login'); + + // Normal user + $this->actAs('normal') + ->visit('/user') + ->seePageIs('/user') + ->assertResponseStatus(200); + + // Banned User + $this->actAs('banned') + ->get('/user') // Do not use `visit` method here. + ->see('banned') + ->dontSee('User Center') + ->assertResponseStatus(403); + + // Binding email + $noEmailUser = factory(App\Models\User::class)->create(['email' => '']); + $this->withSession([ + 'uid' => $noEmailUser->uid, + 'token' => $noEmailUser->getToken() + ])->visit('/user')->see('Bind')->dontSee('User Center'); + + // Without token + $this->withSession([ + 'uid' => 0 + ])->visit('/user')->seePageIs('/auth/login'); + + // Without invalid token + $this->withSession([ + 'uid' => 0, + 'token' => 'invalid' + ])->visit('/user')->seePageIs('/auth/login'); + } + + public function testCheckAdministrator() + { + // Without logged in + $this->get('/admin')->assertRedirectedTo('/auth/login'); + + // Normal user + $this->actAs('normal') + ->get('/admin') + ->assertResponseStatus(403); + + // Admin + $this->actAs('admin') + ->visit('/admin') + ->seePageIs('/admin') + ->assertResponseStatus(200); + + // Super admin + $this->actAs('superAdmin') + ->visit('/admin') + ->seePageIs('/admin') + ->assertResponseStatus(200); + } + + public function testCheckInstallation() + { + $this->visit('/setup')->see('Already installed'); + + $tables = [ + 'closets', 'migrations', 'options', 'players', 'textures', 'users' + ]; + array_walk($tables, function ($table) { + Schema::dropIfExists($table); + }); + $this->visit('/setup')->see(trans( + 'setup.wizard.welcome.text', + ['version' => config('app.version')] + )); + } + + public function testCheckPlayerExist() + { + $this->get('/nope.json') + ->assertResponseStatus(404) + ->see('Un-existent player'); + + $this->get('/skin/nope.png') + ->assertResponseStatus(404) + ->see('Un-existent player'); + + Option::set('return_200_when_notfound', true); + $this->get('/nope.json') + ->assertResponseStatus(200) + ->seeJson([ + 'player_name' => 'nope', + 'errno' => 404, + 'msg' => 'Player Not Found.' + ]); + + $player = factory(App\Models\Player::class)->create(); + $this->get("/{$player->player_name}.json") + ->seeJson(['username' => $player->player_name]); // Default is CSL API + + $this->expectsEvents(\App\Events\CheckPlayerExists::class); + $this->get("/{$player->player_name}.json"); + } + + public function testRedirectIfAuthenticated() + { + $this->visit('/auth/login') + ->seePageIs('/auth/login') + ->dontSee('User Center'); + + $user = factory(\App\Models\User::class)->create(); + + $this->withSession(['uid' => $user->uid]) + ->visit('/auth/login') + ->see('Invalid token'); + + $this->withSession(['uid' => $user->uid, 'token' => 'nothing']) + ->visit('/auth/login') + ->seePageIs('/auth/login') + ->see(trans('auth.check.token')); + + $this->actAs('normal') + ->visit('/auth/login') + ->seePageIs('/user'); + } + + public function testRedirectIfUrlEndsWithSlash() + { + $this->visit('/auth/login/')->seePageIs('/auth/login'); + } +} diff --git a/tests/TestCase.php b/tests/TestCase.php index 8578b17e..8ee286f8 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -20,6 +20,24 @@ class TestCase extends Illuminate\Foundation\Testing\TestCase $app->make(Illuminate\Contracts\Console\Kernel::class)->bootstrap(); + Artisan::call('migrate'); + return $app; } + + /** + * @param \App\Models\User|string $role + * @return $this + */ + public function actAs($role) + { + if (is_string($role)) { + if ($role == 'normal') { + $role = factory(\App\Models\User::class)->create(); + } else { + $role = factory(\App\Models\User::class, $role)->create(); + } + } + return $this->withSession(['uid' => $role->uid, 'token' => $role->getToken()]); + } } diff --git a/tests/UtilsTest.php b/tests/UtilsTest.php deleted file mode 100644 index cafa5ed3..00000000 --- a/tests/UtilsTest.php +++ /dev/null @@ -1,18 +0,0 @@ -assertTrue(true); - } -}