Files
SealShare/tests/Feature/ShareDownloadTest.php
T
Andreas Reinhold / reiniandClaude Opus 4.8 9f929c7a78 Apply Pint 1.29 formatting
The Laravel 13 upgrade pulled Pint 1.27.1 to 1.29.3, which changed the
laravel preset's default rules. composer lint and the CI lint job fail
without this, so it is required rather than cosmetic.

Formatting only, applied by `vendor/bin/pint`. The rules that fired were
fully_qualified_strict_types, ordered_imports, single_blank_line_at_eof,
unary_operator_spaces, not_operator_with_successor_space, braces_position,
single_line_empty_body, single_line_after_imports and no_extra_blank_lines.

Kept separate from the upgrade commit to keep that diff reviewable.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 11:16:59 +02:00

213 lines
6.2 KiB
PHP

<?php
use App\Livewire\ShareDownload;
use App\Models\Share;
use App\Services\FileEncryptionService;
use App\Services\ShareService;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Livewire\Livewire;
test('share download page renders for valid share', function () {
Storage::fake('shares');
$share = createShareWithFile();
$response = $this->get(route('share.download', $share));
$response->assertOk();
});
test('share download page returns 404 for expired share', function () {
$share = Share::factory()->expired()->create();
$response = $this->get(route('share.download', $share));
$response->assertNotFound();
});
test('share download page returns 404 when download limit reached', function () {
$share = Share::factory()->withMaxDownloads(1)->create(['download_count' => 1]);
$response = $this->get(route('share.download', $share));
$response->assertNotFound();
});
test('share download page shows password form for password-protected share', function () {
Storage::fake('shares');
$share = createShareWithFile('secret-pass');
$response = $this->get(route('share.download', $share));
$response->assertOk();
$response->assertSee('password');
});
test('password verification works for protected share', function () {
Storage::fake('shares');
$share = createShareWithFile('my-password');
Livewire::test(ShareDownload::class, ['share' => $share])
->assertSet('authenticated', false)
->set('password', 'my-password')
->call('verifyPassword')
->assertSet('authenticated', true)
->assertHasNoErrors();
});
test('wrong password is rejected', function () {
Storage::fake('shares');
$share = createShareWithFile('my-password');
Livewire::test(ShareDownload::class, ['share' => $share])
->set('password', 'wrong-password')
->call('verifyPassword')
->assertSet('authenticated', false)
->assertHasErrors(['password']);
});
test('non-password share shows files directly', function () {
Storage::fake('shares');
$share = createShareWithFile();
Livewire::test(ShareDownload::class, ['share' => $share])
->assertSet('authenticated', true);
});
test('download counter increments on zip download', function () {
Storage::fake('shares');
$share = createShareWithFile();
$share->load('files');
$encryptionService = app(FileEncryptionService::class);
$key = $share->encryption_key;
$content = 'test content';
foreach ($share->files as $file) {
$dir = Storage::disk('shares')->path($share->token);
if (! is_dir($dir)) {
mkdir($dir, 0755, true);
}
$encryptedPath = $dir.'/'.basename($file->stored_path);
$tempSource = tempnam(sys_get_temp_dir(), 'test');
file_put_contents($tempSource, $content);
$encryptionService->encryptFile($tempSource, $encryptedPath, $key);
unlink($tempSource);
$file->update(['file_size' => strlen($content)]);
}
$response = $this->withSession(['share_password_'.$share->token => null])
->get(route('share.download.all', $share));
$response->assertDownload();
expect($share->fresh()->download_count)->toBe(1);
});
test('zip download produces a valid archive', function () {
Storage::fake('shares');
$share = createShareWithFile();
$share->load('files');
$encryptionService = app(FileEncryptionService::class);
$key = $share->encryption_key;
$content = 'hello zip content';
foreach ($share->files as $file) {
$dir = Storage::disk('shares')->path($share->token);
if (! is_dir($dir)) {
mkdir($dir, 0755, true);
}
$encryptedPath = $dir.'/'.basename($file->stored_path);
$tempSource = tempnam(sys_get_temp_dir(), 'test');
file_put_contents($tempSource, $content);
$encryptionService->encryptFile($tempSource, $encryptedPath, $key);
unlink($tempSource);
$file->update(['file_size' => strlen($content)]);
}
$response = $this->get(route('share.download.all', $share));
$response->assertDownload();
$zipPath = $response->getFile()->getPathname();
$zip = new ZipArchive;
$result = $zip->open($zipPath);
expect($result)->toBe(true);
expect($zip->numFiles)->toBe(1);
expect($zip->statIndex(0)['size'])->toBe(strlen($content));
$zip->close();
});
test('last download streams successfully before auto-delete', function () {
Storage::fake('shares');
$share = createShareWithFile();
$share->update(['max_downloads' => 1]);
$share->load('files');
$encryptionService = app(FileEncryptionService::class);
$key = $share->encryption_key;
$content = 'last download content';
foreach ($share->files as $file) {
$dir = Storage::disk('shares')->path($share->token);
if (! is_dir($dir)) {
mkdir($dir, 0755, true);
}
$encryptedPath = $dir.'/'.basename($file->stored_path);
$tempSource = tempnam(sys_get_temp_dir(), 'test');
file_put_contents($tempSource, $content);
$encryptionService->encryptFile($tempSource, $encryptedPath, $key);
unlink($tempSource);
$file->update(['file_size' => strlen($content)]);
}
$response = $this->get(route('share.download.all', $share));
$response->assertDownload();
// Share was deleted after download
expect(Share::query()->find($share->id))->toBeNull();
});
test('share auto-deletes after reaching download limit', function () {
Storage::fake('shares');
$service = app(ShareService::class);
$file = UploadedFile::fake()->create('file.txt', 100);
$share = $service->createShare([
['file' => $file, 'relativePath' => null],
], [
'max_downloads' => 1,
]);
$service->recordDownload($share);
expect(Share::query()->find($share->id))->toBeNull();
});
/**
* Helper to create a share with an actual encrypted file.
*/
function createShareWithFile(?string $password = null): Share
{
$service = app(ShareService::class);
$file = UploadedFile::fake()->create('testfile.txt', 100);
return $service->createShare([
['file' => $file, 'relativePath' => null],
], [
'password' => $password,
]);
}