From f3b2550b25ef9de64096f2378ed54f62b37b2e66 Mon Sep 17 00:00:00 2001 From: Simon Bigelmayr Date: Fri, 26 May 2023 13:26:26 +0200 Subject: [PATCH] feat: Add `isConsecutive()` method to `AbstractMicroplate` --- CHANGELOG.md | 6 ++++ src/AbstractMicroplate.php | 18 ++++++++++ tests/Unit/MicroplateTest.php | 64 +++++++++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e81b130..1983893 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## v5.2.0 + +### Added + +- Add `isConsecutive()` method to `AbstractMicroplate` + ## v5.1.0 ### Changed diff --git a/src/AbstractMicroplate.php b/src/AbstractMicroplate.php index 821c87d..132d20c 100644 --- a/src/AbstractMicroplate.php +++ b/src/AbstractMicroplate.php @@ -139,4 +139,22 @@ public function toWellWithCoordinateMapper(): callable Coordinate::fromString($coordinateString, $this->coordinateSystem) ); } + + /** + * Are all filled wells placed in a single connected block without gaps between them? + * + * Returns `false` if all wells are empty. + */ + public function isConsecutive(FlowDirection $flowDirection): bool + { + $positions = $this->filledWells() + /** + * @param TWell $content + */ + ->map( + fn ($content, string $coordinateString): int => Coordinate::fromString($coordinateString, $this->coordinateSystem)->position($flowDirection) + ); + + return ($positions->max() - $positions->min() + 1) === $positions->count(); + } } diff --git a/tests/Unit/MicroplateTest.php b/tests/Unit/MicroplateTest.php index b057780..a9a53e5 100644 --- a/tests/Unit/MicroplateTest.php +++ b/tests/Unit/MicroplateTest.php @@ -210,6 +210,70 @@ public function testThrowsPlateFullException(): void $microplate->nextFreeWellCoordinate(FlowDirection::ROW()); } + public function testIsConsecutiveForColumn(): void + { + $coordinateSystem = new CoordinateSystem96Well(); + $microplate = new Microplate($coordinateSystem); + + $data = [ + 'A1', 'B1', 'C1', + ]; + foreach ($data as $wellData) { + $microplateCoordinate = Coordinate::fromString($wellData, $coordinateSystem); + $microplate->addWell($microplateCoordinate, 'test'); + } + + self::assertTrue($microplate->isConsecutive(FlowDirection::COLUMN())); + self::assertFalse($microplate->isConsecutive(FlowDirection::ROW())); + + // is not consecutive anymore after adding a gap at E1 + $microplate->addWell(Coordinate::fromString('E1', $coordinateSystem), 'test'); + self::assertFalse($microplate->isConsecutive(FlowDirection::COLUMN())); + } + + public function testIsConsecutiveForRow(): void + { + $coordinateSystem = new CoordinateSystem96Well(); + $microplate = new Microplate($coordinateSystem); + + $data = [ + 'A1', 'A2', 'A3', + ]; + foreach ($data as $wellData) { + $microplateCoordinate = Coordinate::fromString($wellData, $coordinateSystem); + $microplate->addWell($microplateCoordinate, 'test'); + } + + self::assertTrue($microplate->isConsecutive(FlowDirection::ROW())); + self::assertFalse($microplate->isConsecutive(FlowDirection::COLUMN())); + + // is not consecutive anymore after adding a gap at A5 + $microplate->addWell(Coordinate::fromString('A5', $coordinateSystem), 'test'); + self::assertFalse($microplate->isConsecutive(FlowDirection::ROW())); + } + + public function testIsConsecutiveForEmptyPlate(): void + { + $coordinateSystem = new CoordinateSystem96Well(); + $microplate = new Microplate($coordinateSystem); + + self::assertFalse($microplate->isConsecutive(FlowDirection::ROW())); + self::assertFalse($microplate->isConsecutive(FlowDirection::COLUMN())); + } + + public function testIsConsecutiveForFullPlate(): void + { + $coordinateSystem = new CoordinateSystem96Well(); + $microplate = new Microplate($coordinateSystem); + + foreach ($coordinateSystem->all() as $coordinate) { + $microplate->addWell($coordinate, 'test'); + } + + self::assertTrue($microplate->isConsecutive(FlowDirection::ROW())); + self::assertTrue($microplate->isConsecutive(FlowDirection::COLUMN())); + } + /** * @return list */