strategy = static::getContainer()->get(ComposantSyncStrategy::class); } public function testSupportsComponentCategory(): void { $mt = $this->createModelType('Comp Cat', 'CC-001', ModelCategory::COMPONENT); $this->assertTrue($this->strategy->supports($mt)); } public function testPreviewNoImpactWhenNoComposants(): void { $mt = $this->createModelType('Comp Cat', 'CC-001', ModelCategory::COMPONENT); $result = $this->strategy->preview($mt, ['pieces' => [], 'products' => [], 'subcomponents' => [], 'customFields' => []]); $this->assertSame(0, $result->itemCount); $this->assertFalse($result->hasImpact()); } public function testPreviewDetectsNewPieceSlot(): void { $mt = $this->createModelType('Comp Cat', 'CC-001', ModelCategory::COMPONENT); $pieceType = $this->createModelType('Piece Type', 'PT-001', ModelCategory::PIECE); $this->createComposant('C1', $mt); $result = $this->strategy->preview($mt, [ 'pieces' => [['typePieceId' => $pieceType->getId(), 'position' => 0]], 'products' => [], 'subcomponents' => [], 'customFields' => [], ]); $this->assertSame(1, $result->itemCount); $this->assertSame(1, $result->additions['pieceSlots']); } public function testPreviewDetectsSlotDeletion(): void { $mt = $this->createModelType('Comp Cat', 'CC-001', ModelCategory::COMPONENT); $pieceType = $this->createModelType('Piece Type', 'PT-001', ModelCategory::PIECE); $composant = $this->createComposant('C1', $mt); $this->createComposantPieceSlot($composant, $pieceType, null, 1, 0); $result = $this->strategy->preview($mt, [ 'pieces' => [], 'products' => [], 'subcomponents' => [], 'customFields' => [], ]); $this->assertSame(1, $result->deletions['pieceSlots']); } public function testPreviewNoImpactWhenSlotsMatch(): void { $mt = $this->createModelType('Comp Cat', 'CC-001', ModelCategory::COMPONENT); $pieceType = $this->createModelType('Piece Type', 'PT-001', ModelCategory::PIECE); $composant = $this->createComposant('C1', $mt); $this->createComposantPieceSlot($composant, $pieceType, null, 1, 0); $result = $this->strategy->preview($mt, [ 'pieces' => [['typePieceId' => $pieceType->getId(), 'position' => 0]], 'products' => [], 'subcomponents' => [], 'customFields' => [], ]); $this->assertFalse($result->hasImpact()); } public function testExecuteAddsMissingSlots(): void { $mt = $this->createModelType('Comp Cat', 'CC-001', ModelCategory::COMPONENT); $pieceType = $this->createModelType('Piece Type', 'PT-001', ModelCategory::PIECE); $composant = $this->createComposant('C1', $mt); $em = $this->getEntityManager(); $req = new SkeletonPieceRequirement(); $req->setModelType($mt); $req->setTypePiece($pieceType); $req->setPosition(0); $em->persist($req); $em->flush(); $result = $this->strategy->execute($mt, new SyncConfirmation()); $this->assertSame(1, $result->itemsUpdated); $this->assertSame(1, $result->additions['pieceSlots']); $em->refresh($composant); $this->assertSame(2, $composant->getVersion()); } public function testExecutePreservesExistingSelections(): void { $mt = $this->createModelType('Comp Cat', 'CC-001', ModelCategory::COMPONENT); $pieceType = $this->createModelType('Piece Type', 'PT-001', ModelCategory::PIECE); $composant = $this->createComposant('C1', $mt); $piece = $this->createPiece('P1', 'P1-REF', $pieceType); $slot = $this->createComposantPieceSlot($composant, $pieceType, $piece, 5, 0); $em = $this->getEntityManager(); $req = new SkeletonPieceRequirement(); $req->setModelType($mt); $req->setTypePiece($pieceType); $req->setPosition(0); $em->persist($req); $em->flush(); $result = $this->strategy->execute($mt, new SyncConfirmation()); // No changes — slot already matches $this->assertSame(0, $result->itemsUpdated); // Selection and quantity preserved $em->refresh($slot); $this->assertSame($piece->getId(), $slot->getSelectedPiece()->getId()); $this->assertSame(5, $slot->getQuantity()); } public function testExecuteDeletesSlotsOnlyWithConfirmation(): void { $mt = $this->createModelType('Comp Cat', 'CC-001', ModelCategory::COMPONENT); $pieceType = $this->createModelType('Piece Type', 'PT-001', ModelCategory::PIECE); $composant = $this->createComposant('C1', $mt); $this->createComposantPieceSlot($composant, $pieceType, null, 1, 0); // No skeleton requirements -> slot should be deleted $result = $this->strategy->execute($mt, new SyncConfirmation(confirmDeletions: false)); $this->assertSame(0, $result->deletions['pieceSlots']); // With confirmation $result = $this->strategy->execute($mt, new SyncConfirmation(confirmDeletions: true)); $this->assertSame(1, $result->deletions['pieceSlots']); } public function testExecuteIsIdempotent(): void { $mt = $this->createModelType('Comp Cat', 'CC-001', ModelCategory::COMPONENT); $pieceType = $this->createModelType('Piece Type', 'PT-001', ModelCategory::PIECE); $composant = $this->createComposant('C1', $mt); $em = $this->getEntityManager(); $req = new SkeletonPieceRequirement(); $req->setModelType($mt); $req->setTypePiece($pieceType); $req->setPosition(0); $em->persist($req); $em->flush(); $result1 = $this->strategy->execute($mt, new SyncConfirmation()); $this->assertSame(1, $result1->additions['pieceSlots']); $em->refresh($composant); $result2 = $this->strategy->execute($mt, new SyncConfirmation()); $this->assertSame(0, $result2->itemsUpdated); } }