createWithContent('meeting.mp3', 'identical-audio-bytes'); $duplicate = UploadedFile::fake()->createWithContent('meeting-copy.mp3', 'identical-audio-bytes'); $this->post(route('recordings.store'), [ 'audio' => [$first], ])->assertRedirect(); $this->assertSame(1, Recording::query()->count()); Bus::assertDispatched(TranscribeRecording::class, 1); $response = $this->post(route('recordings.store'), [ 'audio' => [$duplicate], ]); $response->assertRedirect(route('recordings.create')); $response->assertSessionHas('error'); $this->assertSame(1, Recording::query()->count()); Bus::assertDispatched(TranscribeRecording::class, 1); } public function test_batch_upload_skips_duplicate_content_within_request(): void { Storage::fake('local'); Bus::fake(); $one = UploadedFile::fake()->createWithContent('one.mp3', 'same-bytes'); $two = UploadedFile::fake()->createWithContent('two.mp3', 'same-bytes'); $three = UploadedFile::fake()->createWithContent('three.mp3', 'different-bytes'); $response = $this->post(route('recordings.store'), [ 'audio' => [$one, $two, $three], ]); $response->assertRedirect(route('recordings.index')); $response->assertSessionHas('success'); $this->assertStringContainsString('Skipped 1 duplicate', session('success')); $this->assertSame(2, Recording::query()->count()); Bus::assertDispatched(TranscribeRecording::class, 2); } public function test_upload_page_includes_existing_fingerprints_for_client_dedupe(): void { Recording::query()->create([ 'title' => 'Existing', 'original_filename' => 'note.mp3', 'file_path' => 'recordings/note.mp3', 'file_size_bytes' => 2048, 'content_hash' => str_repeat('a', 64), 'transcription_status' => 'done', ]); $this->get(route('recordings.create')) ->assertOk() ->assertSee('note.mp3:2048', false) ->assertSee('Duplicate files', false); } public function test_duplicate_filename_and_size_is_skipped_without_content_hash(): void { Storage::fake('local'); Bus::fake(); Recording::query()->create([ 'title' => 'Legacy', 'original_filename' => 'legacy.mp3', 'file_path' => 'recordings/legacy.mp3', 'file_size_bytes' => strlen('legacy-audio'), 'content_hash' => null, 'transcription_status' => 'done', ]); $response = $this->post(route('recordings.store'), [ 'audio' => [UploadedFile::fake()->createWithContent('legacy.mp3', 'legacy-audio')], ]); $response->assertRedirect(route('recordings.create')); $response->assertSessionHas('error'); $this->assertSame(1, Recording::query()->count()); Bus::assertNothingDispatched(); } }