featureManager = $this->createMock(FeatureManagerInterface::class); $this->filesystem = new Filesystem(); $this->projectDir = sprintf('%s/upload-handler-%s', sys_get_temp_dir(), uniqid()); $this->filesystem->mkdir($this->projectDir.'/'.\dirname(self::REPLACEMENT_FILE)); $this->filesystem->dumpFile($this->projectDir.'/'.self::REPLACEMENT_FILE, '%PDF-1.4 stand-in'); } protected function tearDown(): void { $this->filesystem->remove($this->projectDir); } /** * The point of the whole feature: a document uploaded while testing is served as it is. */ public function testAnExistingUploadIsServedEvenWhileTheFeatureIsOn(): void { $this->featureManager->method('isActive')->with('upload_replacement')->willReturn(true); $this->filesystem->dumpFile($this->projectDir.'/'.self::UPLOAD_PATH, '%PDF-1.4 the real one'); $this->assertSame( $this->projectDir.'/'.self::UPLOAD_PATH, $this->handler()->getResolvedUploadFilepath($this->upload()) ); } public function testAMissingUploadIsReplacedWhileTheFeatureIsOn(): void { $this->featureManager->method('isActive')->with('upload_replacement')->willReturn(true); $this->assertSame( $this->projectDir.'/'.self::REPLACEMENT_FILE, $this->handler()->getResolvedUploadFilepath($this->upload()) ); } /** * Without the feature a missing file stays missing - the callers turn that into their own * error, e.g. the 404 of the download controller. */ public function testAMissingUploadIsLeftAloneWhileTheFeatureIsOff(): void { $this->featureManager->method('isActive')->with('upload_replacement')->willReturn(false); $this->assertSame( $this->projectDir.'/'.self::UPLOAD_PATH, $this->handler()->getResolvedUploadFilepath($this->upload()) ); } public function testAMissingStandInIsAMisconfigurationAndFails(): void { $this->featureManager->method('isActive')->with('upload_replacement')->willReturn(true); $this->expectException(\RuntimeException::class); $this->expectExceptionMessage($this->projectDir.'/assets/pdf/nope.pdf'); $this->handler('assets/pdf/nope.pdf')->getResolvedUploadFilepath($this->upload()); } /** * The real location is never substituted: it is what writes target. */ public function testTheUploadFilepathIgnoresTheFeature(): void { $this->featureManager->method('isActive')->with('upload_replacement')->willReturn(true); $this->assertSame( $this->projectDir.'/'.self::UPLOAD_PATH, $this->handler()->getUploadFilepath($this->upload()) ); } private function handler(string $replacementFile = self::REPLACEMENT_FILE): UploadHandler { return new UploadHandler( $this->createMock(RequestStack::class), $this->createMock(OrphanageManager::class), $this->createMock(Sanitizer::class), new NullLogger(), $this->featureManager, $this->projectDir, $replacementFile, ); } private function upload(): Upload { return (new Upload()) ->setType(Upload::TYPE_INVOICE) ->setFilename('invoice-1.pdf') ; } }