|  | <?php | 
        
          |  |  | 
        
          |  | use Codeception\Stub\Expected; | 
        
          |  | use Codeception\Test\Unit; | 
        
          |  |  | 
        
          |  | class SynchronizedCollectionTest extends TestUnit | 
        
          |  | { | 
        
          |  | /** | 
        
          |  | * @var UnitTester | 
        
          |  | */ | 
        
          |  | protected $tester; | 
        
          |  |  | 
        
          |  | /** | 
        
          |  | * @test | 
        
          |  | */ | 
        
          |  | public function itShouldReturnEntryCollectionIfAnotherCollectionIsTheSame() | 
        
          |  | { | 
        
          |  | $entry = [ | 
        
          |  | ['id' => 1, 'name' => 'John'], | 
        
          |  | ['id' => 2, 'name' => 'Wane'] | 
        
          |  | ]; | 
        
          |  |  | 
        
          |  | $matcher = fn($prop, $origin) => $prop['id'] === $origin['id']; | 
        
          |  |  | 
        
          |  | $mockedPolicy = $this->makeEmpty(SynchronizationPolicy::class, [ | 
        
          |  | 'handleAdd' => Expected::never(), | 
        
          |  | 'handleUpdate' => Expected::exactly(2, fn ($origin, $updateData) => array_merge($origin, $updateData)), | 
        
          |  | 'handleRemove' => Expected::never(), | 
        
          |  | ]); | 
        
          |  |  | 
        
          |  | $collection = new SynchronizedCollection($entry, $mockedPolicy); | 
        
          |  |  | 
        
          |  | $synchronized = $collection->sync([ | 
        
          |  | ['id' => 1, 'name' => 'John'], | 
        
          |  | ['id' => 2, 'name' => 'Wane'] | 
        
          |  | ], $matcher); | 
        
          |  |  | 
        
          |  | $this->assertEquals([ | 
        
          |  | ['id' => 1, 'name' => 'John'], | 
        
          |  | ['id' => 2, 'name' => 'Wane'] | 
        
          |  | ], $synchronized->toArray()); | 
        
          |  | } | 
        
          |  |  | 
        
          |  | /** | 
        
          |  | * @test | 
        
          |  | */ | 
        
          |  | public function itShouldAddNewElementToSynchronizedCollection() | 
        
          |  | { | 
        
          |  | $entry = [ | 
        
          |  | ['id' => 1, 'name' => 'John'], | 
        
          |  | ['id' => 2, 'name' => 'Wane'] | 
        
          |  | ]; | 
        
          |  |  | 
        
          |  | $matcher = fn($prop, $origin) => isset($prop['id']) && $prop['id'] === $origin['id']; | 
        
          |  |  | 
        
          |  | $mockedPolicy = $this->makeEmpty(SynchronizationPolicy::class, [ | 
        
          |  | 'handleAdd' => Expected::once(fn ($newData) => array_merge(['id' => 3], $newData)), | 
        
          |  | 'handleUpdate' => Expected::exactly(2, fn ($origin, $updateData) => array_merge($origin, $updateData)), | 
        
          |  | 'handleRemove' => Expected::never(), | 
        
          |  | ]); | 
        
          |  |  | 
        
          |  | $collection = new SynchronizedCollection($entry, $mockedPolicy); | 
        
          |  |  | 
        
          |  | $synchronized = $collection->sync([ | 
        
          |  | ['id' => 1, 'name' => 'John'], | 
        
          |  | ['id' => 2, 'name' => 'Wane'], | 
        
          |  | ['name' => 'Marry'] | 
        
          |  | ], $matcher); | 
        
          |  |  | 
        
          |  | $this->assertEquals([ | 
        
          |  | ['id' => 1, 'name' => 'John'], | 
        
          |  | ['id' => 2, 'name' => 'Wane'], | 
        
          |  | ['id' => 3, 'name' => 'Marry'], | 
        
          |  | ], $synchronized->toArray()); | 
        
          |  | } | 
        
          |  |  | 
        
          |  | /** | 
        
          |  | * @test | 
        
          |  | */ | 
        
          |  | public function itShouldRemoveExistingElementFromSynchronizedCollection() | 
        
          |  | { | 
        
          |  | $entry = [ | 
        
          |  | ['id' => 1, 'name' => 'John'], | 
        
          |  | ['id' => 2, 'name' => 'Wane'] | 
        
          |  | ]; | 
        
          |  |  | 
        
          |  | $matcher = fn($prop, $origin) => isset($prop['id']) && $prop['id'] === $origin['id']; | 
        
          |  |  | 
        
          |  | $mockedPolicy = $this->makeEmpty(SynchronizationPolicy::class, [ | 
        
          |  | 'handleAdd' => Expected::never(), | 
        
          |  | 'handleUpdate' => Expected::exactly(1, fn ($origin, $updateData) => array_merge($origin, $updateData)), | 
        
          |  | 'handleRemove' => Expected::once(), | 
        
          |  | ]); | 
        
          |  |  | 
        
          |  | $collection = new SynchronizedCollection($entry, $mockedPolicy); | 
        
          |  |  | 
        
          |  | $synchronized = $collection->sync([ | 
        
          |  | ['id' => 2, 'name' => 'Wane'] | 
        
          |  | ], $matcher); | 
        
          |  |  | 
        
          |  | $this->assertEquals([ | 
        
          |  | ['id' => 2, 'name' => 'Wane'] | 
        
          |  | ], $synchronized->toArray()); | 
        
          |  | } | 
        
          |  |  | 
        
          |  | /** | 
        
          |  | * @test | 
        
          |  | */ | 
        
          |  | public function itShouldAddNewElementAndRemoveExistingElementFromSynchronizedCollection() | 
        
          |  | { | 
        
          |  | $entry = [ | 
        
          |  | ['id' => 1, 'name' => 'John'], | 
        
          |  | ['id' => 2, 'name' => 'Wane'] | 
        
          |  | ]; | 
        
          |  |  | 
        
          |  | $matcher = fn($prop, $origin) => isset($prop['id']) && $prop['id'] === $origin['id']; | 
        
          |  |  | 
        
          |  | $mockedPolicy = $this->makeEmpty(SynchronizationPolicy::class, [ | 
        
          |  | 'handleAdd' => Expected::once(fn ($newData) => array_merge(['id' => 3], $newData)), | 
        
          |  | 'handleUpdate' => Expected::exactly(1, fn ($origin, $updateData) => array_merge($origin, $updateData)), | 
        
          |  | 'handleRemove' => Expected::once(), | 
        
          |  | ]); | 
        
          |  |  | 
        
          |  | $collection = new SynchronizedCollection($entry, $mockedPolicy); | 
        
          |  |  | 
        
          |  | $synchronized = $collection->sync([ | 
        
          |  | ['name' => 'Tim'], | 
        
          |  | ['id' => 2, 'name' => 'Wane'] | 
        
          |  | ], $matcher); | 
        
          |  |  | 
        
          |  | $this->assertEquals([ | 
        
          |  | ['id' => 2, 'name' => 'Wane'], | 
        
          |  | ['id' => 3, 'name' => 'Tim'] | 
        
          |  | ], $synchronized->toArray()); | 
        
          |  | } | 
        
          |  |  | 
        
          |  | /** | 
        
          |  | * @test | 
        
          |  | */ | 
        
          |  | public function itShouldUpdateElementAndAddNewElementAndRemoveExistingElementFromSynchronizedCollection() | 
        
          |  | { | 
        
          |  | $entry = [ | 
        
          |  | ['id' => 1, 'name' => 'John'], | 
        
          |  | ['id' => 2, 'name' => 'Wane'] | 
        
          |  | ]; | 
        
          |  |  | 
        
          |  | $matcher = fn($prop, $origin) => isset($prop['id']) && $prop['id'] === $origin['id']; | 
        
          |  |  | 
        
          |  | $mockedPolicy = $this->makeEmpty(SynchronizationPolicy::class, [ | 
        
          |  | 'handleAdd' => Expected::once(fn ($newData) => array_merge(['id' => 3], $newData)), | 
        
          |  | 'handleUpdate' => Expected::exactly(1, fn ($origin, $updateData) => array_merge($origin, $updateData)), | 
        
          |  | 'handleRemove' => Expected::once(), | 
        
          |  | ]); | 
        
          |  |  | 
        
          |  | $collection = new SynchronizedCollection($entry, $mockedPolicy); | 
        
          |  |  | 
        
          |  | $synchronized = $collection->sync([ | 
        
          |  | ['name' => 'Tim'], | 
        
          |  | ['id' => 2, 'name' => 'Wane_UPDATED'] | 
        
          |  | ], $matcher); | 
        
          |  |  | 
        
          |  | $this->assertEquals([ | 
        
          |  | ['id' => 2, 'name' => 'Wane_UPDATED'], | 
        
          |  | ['id' => 3, 'name' => 'Tim'] | 
        
          |  | ], $synchronized->toArray()); | 
        
          |  | } | 
        
          |  |  | 
        
          |  | /** | 
        
          |  | * @test | 
        
          |  | */ | 
        
          |  | public function itShouldThrowExceptionIfProvidedArrayContainsAmbiguousElement() | 
        
          |  | { | 
        
          |  | $entry = [ | 
        
          |  | ['id' => 2, 'name' => 'Wane'] | 
        
          |  | ]; | 
        
          |  |  | 
        
          |  | $matcher = fn($prop, $origin) => isset($prop['id']) && $prop['id'] === $origin['id']; | 
        
          |  |  | 
        
          |  | $mockedPolicy = $this->makeEmpty(SynchronizationPolicy::class, [ | 
        
          |  | 'handleAdd' => Expected::never(), | 
        
          |  | 'handleUpdate' => Expected::never(), | 
        
          |  | 'handleRemove' => Expected::never() | 
        
          |  | ]); | 
        
          |  |  | 
        
          |  | $collection = new SynchronizedCollection($entry, $mockedPolicy); | 
        
          |  |  | 
        
          |  | $this->tester->expectThrowable(AmbiguousElementException::class, function () use ($collection, $matcher) { | 
        
          |  | $collection->sync([ | 
        
          |  | ['id' => 2, 'name' => 'Wane'], | 
        
          |  | ['id' => 2, 'name' => 'Tim'] | 
        
          |  | ], $matcher); | 
        
          |  | }); | 
        
          |  | } | 
        
          |  | } |