*/ private array $tempFiles = []; public function testHandleValidFile(): void { $xml = <<<'XML' god@foundation.edu Hari Seldon picard@federation.earth Jean-Luc Picard jackwithapostrophe@sgc.mil Jack O'Neill XML; $createContactCommand = $this->createCreateContactCommandMock( 1, ['god@foundation.edu', 'picard@federation.earth', 'jackwithapostrophe@sgc.mil'], new BatchResult(0, 0, 3), ); $processImportState = $this->createMock(ProcessImportState::class); $processImportState->expects($this->exactly(1))->method('start'); $processImportState->expects($this->exactly(1))->method('finish'); $processImportState->expects($this->exactly(1))->method('contactFail')->with(0); $processImportState->expects($this->exactly(1))->method('contactDuplicate')->with(0); $processImportState->expects($this->exactly(1))->method('contactSuccess')->with(3); $processImportState->method('uuid')->willReturn(Uuid::uuid7()); $job = new ProcessImport( $this->createTempFile($xml), $processImportState, ); $job->handle($createContactCommand); } public function testHandleMultipleTextNodes(): void { $xml = <<<'XML' god@on.edu Hari Seldon XML; $createContactCommand = $this->createCreateContactCommandMock( 1, ['god@foundation.edu'], new BatchResult(0, 0, 1), ); $processImportState = $this->createMock(ProcessImportState::class); $processImportState->expects($this->exactly(1))->method('start'); $processImportState->expects($this->exactly(1))->method('finish'); $processImportState->expects($this->exactly(1))->method('contactFail')->with(0); $processImportState->expects($this->exactly(1))->method('contactDuplicate')->with(0); $processImportState->expects($this->exactly(1))->method('contactSuccess')->with(1); $processImportState->method('uuid')->willReturn(Uuid::uuid7()); $job = new ProcessImport( $this->createTempFile($xml), $processImportState, ); $job->handle($createContactCommand); } public function testHandleValidMultipleBatches(): void { $xml = ''; $emails = []; for ($i = 0; $i <= 5001; $i++) { $xml .= ' god' . $i . '@foundation.edu Hari Seldon '; $emails[] = 'god@foundation.edu' . $i; } $xml .= ''; $createContactCommand = $this->createCreateContactCommandMock( 2, [], [ new BatchResult(0, 0, 5000), new BatchResult(0, 0, 1), ], ); $processImportState = $this->createMock(ProcessImportState::class); $processImportState->expects($this->exactly(1))->method('start'); $processImportState->expects($this->exactly(1))->method('finish'); $processImportState->expects($this->exactly(2))->method('contactFail')->with(0); $processImportState->expects($this->exactly(2)) ->method('contactDuplicate') ->with($this->callback(static fn (int $duplicates): bool => $duplicates === 0 || $duplicates === 1)); $processImportState->expects($this->exactly(2)) ->method('contactSuccess') ->with($this->callback(static fn (int $processed): bool => $processed === 5000 || $processed === 1)); $processImportState->method('uuid')->willReturn(Uuid::uuid7()); $job = new ProcessImport( $this->createTempFile($xml), $processImportState, ); $job->handle($createContactCommand); } public function testHandleInvalidFile(): void { $xml = <<<'XML' Hari Seldon XML; $processImportState = $this->createMock(ProcessImportState::class); $processImportState->expects($this->exactly(1))->method('start'); $processImportState->expects($this->exactly(1))->method('finish'); $failCallsWithOne = 0; $processImportState->expects($this->atLeastOnce()) ->method('contactFail') ->willReturnCallback(function (int $count) use (&$failCallsWithOne): void { if ($count === 1) { $failCallsWithOne++; } }); $processImportState->expects($this->exactly(1))->method('contactDuplicate')->with(0); $processImportState->expects($this->exactly(1))->method('contactSuccess')->with(0); $processImportState->method('uuid')->willReturn(Uuid::uuid7()); $job = new ProcessImport( $this->createTempFile($xml), $processImportState, ); $job->handle($this->createCreateContactCommandMock()); $this->assertGreaterThan(0, $failCallsWithOne); } public function testHandleInvalidStructure(): void { $xml = <<<'XML' god@foundation.edu Hari Seldon anubis@badguy.space No-imported Anubis XML; $createContactCommand = $this->createCreateContactCommandMock( 1, ['god@foundation.edu'], new BatchResult(0, 0, 1), ); $processImportState = $this->createMock(ProcessImportState::class); $processImportState->expects($this->exactly(1))->method('start'); $processImportState->expects($this->exactly(1))->method('finish'); $processImportState->expects($this->exactly(1))->method('contactFail')->with(0); $processImportState->expects($this->exactly(1))->method('contactDuplicate')->with(0); $processImportState->expects($this->exactly(1))->method('contactSuccess')->with(1); $job = new ProcessImport( $this->createTempFile($xml), $processImportState, ); $job->handle($createContactCommand); } public function testHandleReallyBadXml(): void { $xml = 'NOT XML'; $createContactCommand = $this->createCreateContactCommandMock( 1, [], new BatchResult(0, 0, 0), ); $processImportState = $this->createMock(ProcessImportState::class); $processImportState->expects($this->exactly(1))->method('start'); $processImportState->expects($this->exactly(1))->method('finish'); $processImportState->expects($this->exactly(1))->method('contactFail')->with(0); $processImportState->expects($this->exactly(1))->method('contactDuplicate')->with(0); $processImportState->expects($this->exactly(1))->method('contactSuccess')->with(0); $job = new ProcessImport( $this->createTempFile($xml), $processImportState, ); $job->handle($createContactCommand); } protected function tearDown(): void { Storage::disk('local')->delete($this->tempFiles); $this->tempFiles = []; parent::tearDown(); } private function createTempFile(string $contents): string { $path = 'process-import/' . Uuid::uuid7()->toString() . '.xml'; Storage::disk('local')->put($path, $contents); $this->tempFiles[] = $path; return $path; } private function createCreateContactCommandMock( ?int $expectedCalls = null, array $emails = [], BatchResult|array|null $batchResult = null, ): CreateContactCommand { $createContactCommand = $this->createMock(CreateContactCommand::class); $expectation = $expectedCalls !== null ? $createContactCommand->expects($this->exactly($expectedCalls))->method('multipleExecute') : $createContactCommand->method('multipleExecute'); if ($expectedCalls !== null) { $expectation ->with($this->callback(function (array $intents) use ($emails): bool { if ($emails === []) { return true; } $argEmails = array_map( static fn (CreateContactIntent $intent): string => $intent->email, $intents, ); sort($argEmails); sort($emails); return $argEmails === $emails; })); } if (is_array($batchResult)) { $expectation->willReturnOnConsecutiveCalls(...$batchResult); } elseif ($batchResult instanceof BatchResult) { $expectation->willReturn($batchResult); } else { $expectation->willReturn(new BatchResult(0, 0, 0)); } return $createContactCommand; } }