Add tests for TextureController

This commit is contained in:
Pig Fang 2017-11-17 07:40:29 +08:00
parent b19565bf8b
commit a413927980
5 changed files with 308 additions and 19 deletions

View File

@ -58,7 +58,7 @@ class TextureController extends Controller
'Content-Length' => Storage::disk('textures')->size($hash),
]);
} else {
abort(404);
return abort(404);
}
}
@ -88,7 +88,7 @@ class TextureController extends Controller
return $player->getBinaryTexture('cape');
}
public function avatar($base64_email, $size = 128, UserRepository $users)
public function avatar($base64_email, UserRepository $users, $size = 128)
{
$user = $users->get(base64_decode($base64_email), 'email');
@ -97,33 +97,39 @@ class TextureController extends Controller
if ($t = Texture::find($tid)) {
if (Storage::disk('textures')->has($t->hash)) {
$responses = Event::fire(new GetAvatarPreview($t, $size));
$responses = event(new GetAvatarPreview($t, $size));
if (isset($responses[0]) && $responses[0] instanceof \Symfony\Component\HttpFoundation\Response) {
return $responses[0];
return $responses[0]; // @codeCoverageIgnore
} else {
$filename = storage_path("textures/{$t->hash}");
$filename = config('filesystems.disks.textures.root').'/'.$t->hash;
$png = Minecraft::generateAvatarFromSkin($filename, $size);
ob_start();
imagepng($png);
imagedestroy($png);
$image = ob_get_contents();
ob_end_clean();
return Response::png();
return Response::png($image);
}
}
}
}
$png = imagecreatefromstring(base64_decode(static::getDefaultAvatar()));
ob_start();
imagepng($png);
imagedestroy($png);
$image = ob_get_contents();
ob_end_clean();
return Response::png();
return Response::png($image);
}
public function avatarWithSize($size, $base64_email, UserRepository $users)
{
return $this->avatar($base64_email, $size, $users);
return $this->avatar($base64_email, $users, $size);
}
public function preview($tid, $size = 250)
@ -131,33 +137,42 @@ class TextureController extends Controller
// output image directly
if ($t = Texture::find($tid)) {
if (Storage::disk('textures')->has($t->hash)) {
$responses = Event::fire(new GetSkinPreview($t, $size));
$responses = event(new GetSkinPreview($t, $size));
if (isset($responses[0]) && $responses[0] instanceof \Symfony\Component\HttpFoundation\Response) {
return $responses[0];
return $responses[0]; // @codeCoverageIgnore
} else {
$filename = storage_path("textures/{$t->hash}");
$filename = config('filesystems.disks.textures.root').'/'.$t->hash;
if ($t->type == "cape") {
$png = Minecraft::generatePreviewFromCape($filename, $size);
ob_start();
imagepng($png);
imagedestroy($png);
$image = ob_get_contents();
ob_end_clean();
} else {
$png = Minecraft::generatePreviewFromSkin($filename, $size);
ob_start();
imagepng($png);
imagedestroy($png);
$image = ob_get_contents();
ob_end_clean();
}
return Response::png();
return Response::png($image);
}
}
}
$png = imagecreatefromstring(base64_decode(static::getBrokenPreview()));
ob_start();
imagepng($png);
imagedestroy($png);
$image = ob_get_contents();
ob_end_clean();
return Response::png();
return Response::png($image);
}
public function previewWithSize($size, $tid)
@ -171,10 +186,10 @@ class TextureController extends Controller
if (Storage::disk('textures')->has($t->hash)) {
return Response::png(Storage::disk('textures')->get($t->hash));
} else {
abort(404, trans('general.texture-deleted'));
return abort(404, trans('general.texture-deleted'));
}
} else {
abort(404, trans('skinlib.non-existent'));
return abort(404, trans('skinlib.non-existent'));
}
}
@ -183,9 +198,6 @@ class TextureController extends Controller
{
$player = Player::where('player_name', $player_name)->first();
if (!$player)
abort(404, trans('general.unexistent-player'));
if ($player->isBanned())
abort(404, trans('general.player-banned'));

View File

@ -146,7 +146,6 @@ class Player extends Model
{
if ($this->getTexture($type)) {
$hash = $this->getTexture($type);
$path = storage_path("textures/$hash");
if (Storage::disk('textures')->has($hash)) {
// Cache friendly

3
storage/testing/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
*
!textures
!.gitignore

2
storage/testing/textures/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*
!.gitignore

View File

@ -0,0 +1,273 @@
<?php
use App\Models\User;
use App\Models\Player;
use App\Models\Texture;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class TextureControllerTest extends TestCase
{
use DatabaseTransactions;
protected function setUp()
{
parent::setUp();
config(['filesystems.disks.textures.root' => storage_path('testing/textures')]);
}
protected function tearDown()
{
collect(Storage::disk('textures')->files())
->reject(function ($filename) {
return $filename == '.gitignore';
})
->each(function ($filename) {
Storage::disk('textures')->delete($filename);
});
parent::tearDown();
}
public function testJson()
{
$steve = factory(Texture::class)->create();
// Player is not existed
$this->get('/nope.json')
->see(trans('general.unexistent-player'))
->assertResponseStatus(404);
// Player is banned
$player = factory(Player::class)->create(['tid_steve' => $steve->tid]);
User::find($player->uid)->setPermission(User::BANNED);
$this->get("/{$player->player_name}.json")
->see(trans('general.player-banned'))
->assertResponseStatus(404);
User::find($player->uid)->setPermission(User::NORMAL);
// Default API is CSL API
$this->get("/{$player->player_name}.json")
->seeJson([
'username' => $player->player_name,
'skins' => [
'default' => $steve->hash,
'slim' => null
],
'cape' => null
])->seeHeader('Last-Modified');
}
public function testJsonWithApi()
{
$steve = factory(Texture::class)->create();
$player = factory(Player::class)->create(['tid_steve' => $steve->tid]);
// CSL API
$this->get("/csl/{$player->player_name}.json")
->seeJson([
'username' => $player->player_name,
'skins' => [
'default' => $steve->hash,
'slim' => null
],
'cape' => null
])->seeHeader('Last-Modified');
// USM API
$this->get("/usm/{$player->player_name}.json")
->seeJson([
'player_name' => $player->player_name,
'model_preference' => ['default', 'slim'],
'skins' => [
'default' => $steve->hash,
'slim' => null
],
'cape' => null
])->seeHeader('Last-Modified');
}
public function testTexture()
{
$steve = factory(Texture::class)->create();
Storage::disk('textures')->put($steve->hash, '');
$this->get('/textures/nope')
->see('404');
$this->get('/textures/'.$steve->hash)
->seeHeader('Content-Type', 'image/png')
->seeHeader('Last-Modified')
->seeHeader('Accept-Ranges', 'bytes')
->seeHeader('Content-Length', Storage::disk('textures')->size($steve->hash))
->assertResponseStatus(200);
}
public function testTextureWithApi()
{
$steve = factory(Texture::class)->create();
Storage::disk('textures')->put($steve->hash, '');
$this->get('/csl/textures/'.$steve->hash)
->seeHeader('Content-Type', 'image/png')
->seeHeader('Last-Modified')
->seeHeader('Accept-Ranges', 'bytes')
->seeHeader('Content-Length', Storage::disk('textures')->size($steve->hash))
->assertResponseStatus(200);
$this->get('/usm/textures/'.$steve->hash)
->seeHeader('Content-Type', 'image/png')
->seeHeader('Last-Modified')
->seeHeader('Accept-Ranges', 'bytes')
->seeHeader('Content-Length', Storage::disk('textures')->size($steve->hash))
->assertResponseStatus(200);
}
public function testSkin()
{
$steve = factory(Texture::class)->create();
$player = factory(Player::class)->create([
'preference' => 'slim',
'tid_steve' => $steve->tid,
'tid_alex' => 0
]);
$this->get("/skin/{$player->player_name}.png")
->see(trans('general.texture-not-uploaded', ['type' => 'alex']));
$player->setPreference('default');
$this->get("/skin/{$player->player_name}.png")
->see(trans('general.texture-deleted'));
Storage::disk('textures')->put($steve->hash, '');
$this->get("/skin/{$player->player_name}.png")
->seeHeader('Content-Type', 'image/png')
->seeHeader('Last-Modified')
->seeHeader('Accept-Ranges', 'bytes')
->seeHeader('Content-Length', Storage::disk('textures')->size($steve->hash))
->assertResponseStatus(200);
}
public function testSkinWithModel()
{
$steve = factory(Texture::class)->create();
$player = factory(Player::class)->create([
'preference' => 'slim',
'tid_steve' => $steve->tid,
'tid_alex' => 0
]);
$this->get("/skin/alex/{$player->player_name}.png")
->see(trans('general.texture-not-uploaded', ['type' => 'alex']));
$player->setPreference('default');
$this->get("/skin/steve/{$player->player_name}.png")
->see(trans('general.texture-deleted'));
}
public function testCape()
{
$cape = factory(Texture::class, 'cape')->create();
$player = factory(Player::class)->create([
'tid_cape' => $cape->tid
]);
$this->get("/cape/{$player->player_name}.png")
->see(trans('general.texture-deleted'));
}
public function testAvatar()
{
$base64_email = base64_encode('a@b.c');
$this->get("/avatar/$base64_email.png")
->seeHeader('Content-Type', 'image/png');
$steve = factory(Texture::class)->create();
$png = base64_decode(\App\Http\Controllers\TextureController::getDefaultSkin());
Storage::disk('textures')->put($steve->hash, $png);
$user = factory(User::class)->create(['avatar' => $steve->tid]);
$mock = Mockery::mock('overload:Minecraft');
$mock->shouldReceive('generateAvatarFromSkin')
->once()
->andReturn(imagecreatefromstring($png));
$this->expectsEvents(\App\Events\GetAvatarPreview::class);
$this->get('/avatar/'.base64_encode($user->email).'.png')
->seeHeader('Content-Type', 'image/png');
}
public function testAvatarWithSize()
{
$steve = factory(Texture::class)->create();
$png = base64_decode(\App\Http\Controllers\TextureController::getDefaultSkin());
Storage::disk('textures')->put($steve->hash, $png);
$user = factory(User::class)->create(['avatar' => $steve->tid]);
$mock = Mockery::mock('overload:Minecraft');
$mock->shouldReceive('generateAvatarFromSkin')
->once()
->andReturn(imagecreatefromstring($png));
$this->expectsEvents(\App\Events\GetAvatarPreview::class);
$this->get('/avatar/50/'.base64_encode($user->email).'.png')
->seeHeader('Content-Type', 'image/png');
}
public function testPreview()
{
$steve = factory(Texture::class)->create();
$cape = factory(Texture::class, 'cape')->create();
$this->get('/preview/0.png')
->seeHeader('Content-Type', 'image/png');
$this->get("/preview/{$steve->tid}.png")
->seeHeader('Content-Type', 'image/png');
$png = base64_decode(\App\Http\Controllers\TextureController::getDefaultSkin());
Storage::disk('textures')->put($steve->hash, $png);
Storage::disk('textures')->put($cape->hash, $png);
$mock = Mockery::mock('overload:Minecraft');
$mock->shouldReceive('generatePreviewFromSkin')
->once()
->andReturn(imagecreatefromstring($png));
$this->expectsEvents(\App\Events\GetSkinPreview::class);
$this->get("/preview/{$steve->tid}.png")
->seeHeader('Content-Type', 'image/png');
$mock->shouldReceive('generatePreviewFromCape')
->once()
->andReturn(imagecreatefromstring($png));
$this->get("/preview/{$cape->tid}.png")
->seeHeader('Content-Type', 'image/png');
}
public function testPreviewWithSize()
{
$this->get('/preview/200/0.png')
->seeHeader('Content-Type', 'image/png');
}
public function testRaw()
{
$steve = factory(Texture::class)->create();
Storage::disk('textures')->put($steve->hash, '');
// Not found
$this->get('/raw/0.png')
->see(trans('skinlib.non-existent'));
// Success
$this->get("/raw/{$steve->tid}.png")
->seeHeader('Content-Type', 'image/png');
// Texture is deleted
Storage::disk('textures')->delete($steve->hash);
$this->get("/raw/{$steve->tid}.png")
->see(trans('general.texture-deleted'));
}
}