migration1 = $this->createMockMigration('2024_01_01_120000', 'First migration'); $this->migration2 = $this->createMockMigration('2024_01_02_120000', 'Second migration'); $this->migration3 = $this->createMockMigration('2024_01_03_120000', 'Third migration'); } #[Test] public function constructor_creates_empty_collection(): void { $collection = new MigrationCollection(); $this->assertTrue($collection->isEmpty()); $this->assertSame(0, $collection->count()); } #[Test] public function constructor_accepts_variadic_migrations(): void { $collection = new MigrationCollection( $this->migration1, $this->migration2, $this->migration3 ); $this->assertFalse($collection->isEmpty()); $this->assertSame(3, $collection->count()); } #[Test] public function fromArray_creates_collection_from_array(): void { $migrations = [$this->migration1, $this->migration2, $this->migration3]; $collection = MigrationCollection::fromArray($migrations); $this->assertSame(3, $collection->count()); } #[Test] public function getIterator_allows_foreach_iteration(): void { $collection = new MigrationCollection($this->migration1, $this->migration2); $iterations = 0; foreach ($collection as $migration) { $this->assertInstanceOf(Migration::class, $migration); $iterations++; } $this->assertSame(2, $iterations); } #[Test] public function getByVersion_returns_migration_with_matching_version(): void { $collection = new MigrationCollection($this->migration1, $this->migration2); $version = MigrationVersion::fromTimestamp('2024_01_01_120000'); $result = $collection->getByVersion($version); $this->assertSame($this->migration1, $result); } #[Test] public function getByVersion_returns_null_when_not_found(): void { $collection = new MigrationCollection($this->migration1); $version = MigrationVersion::fromTimestamp('2024_01_99_999999'); $result = $collection->getByVersion($version); $this->assertNull($result); } #[Test] public function getByVersionString_returns_migration_with_matching_version_string(): void { $collection = new MigrationCollection($this->migration1, $this->migration2); $result = $collection->getByVersionString('2024_01_02_120000'); $this->assertSame($this->migration2, $result); } #[Test] public function getByVersionString_returns_null_when_not_found(): void { $collection = new MigrationCollection($this->migration1); $result = $collection->getByVersionString('2024_01_99_999999'); $this->assertNull($result); } #[Test] public function hasVersion_returns_true_when_version_exists(): void { $collection = new MigrationCollection($this->migration1, $this->migration2); $version = MigrationVersion::fromTimestamp('2024_01_01_120000'); $result = $collection->hasVersion($version); $this->assertTrue($result); } #[Test] public function hasVersion_returns_false_when_version_does_not_exist(): void { $collection = new MigrationCollection($this->migration1); $version = MigrationVersion::fromTimestamp('2024_01_99_999999'); $result = $collection->hasVersion($version); $this->assertFalse($result); } #[Test] public function hasVersionString_returns_true_when_version_string_exists(): void { $collection = new MigrationCollection($this->migration1, $this->migration2); $result = $collection->hasVersionString('2024_01_02_120000'); $this->assertTrue($result); } #[Test] public function hasVersionString_returns_false_when_version_string_does_not_exist(): void { $collection = new MigrationCollection($this->migration1); $result = $collection->hasVersionString('2024_01_99_999999'); $this->assertFalse($result); } #[Test] public function getVersions_returns_migration_version_collection(): void { $collection = new MigrationCollection($this->migration1, $this->migration2); $versions = $collection->getVersions(); $this->assertSame(2, $versions->count()); $this->assertTrue($versions->containsString('2024_01_01_120000')); $this->assertTrue($versions->containsString('2024_01_02_120000')); } #[Test] public function sorted_returns_collection_sorted_by_version_ascending(): void { // Create collection in reverse order $collection = new MigrationCollection($this->migration3, $this->migration1, $this->migration2); $sorted = $collection->sorted(); $migrations = $sorted->toArray(); $this->assertSame($this->migration1, $migrations[0]); $this->assertSame($this->migration2, $migrations[1]); $this->assertSame($this->migration3, $migrations[2]); } #[Test] public function sortedDescending_returns_collection_sorted_by_version_descending(): void { $collection = new MigrationCollection($this->migration1, $this->migration2, $this->migration3); $sorted = $collection->sortedDescending(); $migrations = $sorted->toArray(); $this->assertSame($this->migration3, $migrations[0]); $this->assertSame($this->migration2, $migrations[1]); $this->assertSame($this->migration1, $migrations[2]); } #[Test] public function filter_returns_collection_with_filtered_migrations(): void { $collection = new MigrationCollection($this->migration1, $this->migration2, $this->migration3); $filtered = $collection->filter(function (Migration $migration) { return str_contains($migration->getDescription(), 'Second'); }); $this->assertSame(1, $filtered->count()); $this->assertSame($this->migration2, $filtered->toArray()[0]); } #[Test] public function after_returns_migrations_after_specified_version(): void { $collection = new MigrationCollection($this->migration1, $this->migration2, $this->migration3); $version = MigrationVersion::fromTimestamp('2024_01_01_120000'); $filtered = $collection->after($version); $this->assertSame(2, $filtered->count()); $migrations = $filtered->toArray(); $this->assertSame($this->migration2, $migrations[0]); $this->assertSame($this->migration3, $migrations[1]); } #[Test] public function upTo_returns_migrations_up_to_and_including_specified_version(): void { $collection = new MigrationCollection($this->migration1, $this->migration2, $this->migration3); $version = MigrationVersion::fromTimestamp('2024_01_02_120000'); $filtered = $collection->upTo($version); $this->assertSame(2, $filtered->count()); $migrations = $filtered->toArray(); $this->assertSame($this->migration1, $migrations[0]); $this->assertSame($this->migration2, $migrations[1]); } #[Test] public function first_returns_first_migration_by_version(): void { $collection = new MigrationCollection($this->migration3, $this->migration1, $this->migration2); $first = $collection->first(); $this->assertSame($this->migration1, $first); } #[Test] public function first_returns_null_for_empty_collection(): void { $collection = new MigrationCollection(); $first = $collection->first(); $this->assertNull($first); } #[Test] public function last_returns_last_migration_by_version(): void { $collection = new MigrationCollection($this->migration1, $this->migration3, $this->migration2); $last = $collection->last(); $this->assertSame($this->migration3, $last); } #[Test] public function last_returns_null_for_empty_collection(): void { $collection = new MigrationCollection(); $last = $collection->last(); $this->assertNull($last); } #[Test] public function toArray_returns_migrations_as_array(): void { $collection = new MigrationCollection($this->migration1, $this->migration2); $array = $collection->toArray(); $this->assertIsArray($array); $this->assertSame(2, count($array)); $this->assertSame($this->migration1, $array[0]); $this->assertSame($this->migration2, $array[1]); } #[Test] public function collection_is_immutable(): void { $collection = new MigrationCollection($this->migration1); $filtered = $collection->filter(fn () => true); $sorted = $collection->sorted(); // Original collection should be unchanged $this->assertSame(1, $collection->count()); $this->assertNotSame($collection, $filtered); $this->assertNotSame($collection, $sorted); } private function createMockMigration(string $version, string $description): Migration { $migration = $this->createMock(Migration::class); $migration->method('getVersion') ->willReturn(MigrationVersion::fromTimestamp($version)); $migration->method('getDescription') ->willReturn($description); return $migration; } }