Skip to content
This repository has been archived by the owner on Apr 24, 2024. It is now read-only.

Commit

Permalink
feat: Add isValidRawContent-method to class TecanScanner (#10)
Browse files Browse the repository at this point in the history
* feat: Add isValidRawContent-method to class TecanScanner
---------

Co-authored-by: Simon Bigelmayr <[email protected]>
  • Loading branch information
simbig and Simon Bigelmayr authored Feb 9, 2023
1 parent f37ed86 commit 4cac541
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 8 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Unreleased

## v4.1.0

### Added

- Add `isValidRawContent`-method to class `TecanScanner`

## v4.0.0

### Removed
Expand Down
3 changes: 2 additions & 1 deletion src/FluidXPlate/FluidXPlate.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@

final class FluidXPlate
{
public const FLUIDX_BARCODE_REGEX = /* @lang RegExp */ '/[A-Z]{2}(\d){8}/';
public const FLUIDX_BARCODE_REGEX = /* @lang RegExp */ '/' . self::FLUIDX_BARCODE_REGEX_WITHOUT_DELIMITER . '/';
public const FLUIDX_BARCODE_REGEX_WITHOUT_DELIMITER = '[A-Z]{2}(\d){8}';

public string $rackId;

Expand Down
28 changes: 26 additions & 2 deletions src/TecanScanner/TecanScanner.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
final class TecanScanner
{
public const NO_READ = 'NO READ';
public const RACKID_IDENTIFIER = 'rackid,';

public static function parseRawContent(string $rawContent): FluidXPlate
{
Expand All @@ -25,17 +26,18 @@ public static function parseRawContent(string $rawContent): FluidXPlate

$firstLineWithRackId = $lines->shift();

if (! is_string($firstLineWithRackId) || ! Str::startsWith($firstLineWithRackId, 'rackid,')) {
if (! is_string($firstLineWithRackId) || ! Str::startsWith($firstLineWithRackId, self::RACKID_IDENTIFIER)) {
throw new NoRackIdException();
}
$rackId = Str::substr($firstLineWithRackId, strlen(self::RACKID_IDENTIFIER));

$expectedCount = FluidXPlate::coordinateSystem()->positionsCount();
$actualCount = $lines->count();
if ($expectedCount !== $actualCount) {
throw new WrongNumberOfWells($expectedCount, $actualCount);
}

$plate = new FluidXPlate(Str::substr($firstLineWithRackId, 7));
$plate = new FluidXPlate($rackId);

foreach ($lines as $line) {
$barcode = Str::after($line, ',');
Expand All @@ -55,4 +57,26 @@ public static function parseRawContent(string $rawContent): FluidXPlate

return $plate;
}

/**
* Checks if a string can be parsed into a FluidXPlate.
*/
public static function isValidRawContent(string $rawContent): bool
{
$lines = explode("\n", $rawContent);

if (97 !== count($lines)) {
return false;
}
if (0 === \Safe\preg_match(/* @lang RegExp */ '/^' . self::RACKID_IDENTIFIER . FluidXPlate::FLUIDX_BARCODE_REGEX_WITHOUT_DELIMITER . '$/', array_shift($lines))) {
return false;
}
foreach ($lines as $line) {
if (1 !== \Safe\preg_match(/* @lang RegExp */ '/^[A-H][1-12],' . FluidXPlate::FLUIDX_BARCODE_REGEX_WITHOUT_DELIMITER . '|' . self::NO_READ . '$/', $line)) {
return false;
}
}

return true;
}
}
24 changes: 19 additions & 5 deletions tests/Unit/TecanScanner/TecanScannerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,32 +13,45 @@ final class TecanScannerTest extends TestCase
{
public function testCreateFromStringEmpty(): void
{
$rawContent = '';
self::assertFalse(TecanScanner::isValidRawContent($rawContent));

$this->expectExceptionObject(new TecanScanEmptyException());
TecanScanner::parseRawContent('');
TecanScanner::parseRawContent($rawContent);
}

public function testCreateFromUnexpectedLineCount(): void
{
$rawContent = "rackid,SA00411242\nA1,FD13945423\nB1,FD32807353";
self::assertFalse(TecanScanner::isValidRawContent($rawContent));

$this->expectExceptionObject(new WrongNumberOfWells(96, 2));
TecanScanner::parseRawContent("rackid,SA00411242\nA1,FD13945423\nB1,FD32807353");
TecanScanner::parseRawContent($rawContent);
}

public function testMicroplateHandlesDuplicateCoordinate(): void
{
$rawContent = "rackid,SA00411242\nA1,FD13945423\nA1,FD32807353\nC1,NO READ\nD1,NO READ\nE1,NO READ\nF1,NO READ\nG1,NO READ\nH1,NO READ\nA2,NO READ\nB2,NO READ\nC2,NO READ\nD2,NO READ\nE2,NO READ\nF2,NO READ\nG2,NO READ\nH2,NO READ\nA3,NO READ\nB3,NO READ\nC3,NO READ\nD3,NO READ\nE3,NO READ\nF3,NO READ\nG3,NO READ\nH3,NO READ\nA4,NO READ\nB4,NO READ\nC4,NO READ\nD4,NO READ\nE4,NO READ\nF4,NO READ\nG4,NO READ\nH4,NO READ\nA5,NO READ\nB5,NO READ\nC5,NO READ\nD5,NO READ\nE5,NO READ\nF5,NO READ\nG5,NO READ\nH5,NO READ\nA6,NO READ\nB6,NO READ\nC6,NO READ\nD6,NO READ\nE6,NO READ\nF6,NO READ\nG6,NO READ\nH6,NO READ\nA7,NO READ\nB7,NO READ\nC7,NO READ\nD7,NO READ\nE7,NO READ\nF7,NO READ\nG7,NO READ\nH7,NO READ\nA8,NO READ\nB8,NO READ\nC8,NO READ\nD8,NO READ\nE8,NO READ\nF8,NO READ\nG8,NO READ\nH8,NO READ\nA9,NO READ\nB9,NO READ\nC9,NO READ\nD9,NO READ\nE9,NO READ\nF9,NO READ\nG9,NO READ\nH9,NO READ\nA10,NO READ\nB10,NO READ\nC10,NO READ\nD10,NO READ\nE10,NO READ\nF10,NO READ\nG10,NO READ\nH10,NO READ\nA11,NO READ\nB11,NO READ\nC11,NO READ\nD11,NO READ\nE11,NO READ\nF11,NO READ\nG11,NO READ\nH11,NO READ\nA12,NO READ\nB12,NO READ\nC12,NO READ\nD12,NO READ\nE12,NO READ\nF12,NO READ\nG12,NO READ\nH12,NO READ";
self::assertTrue(TecanScanner::isValidRawContent($rawContent));

$this->expectExceptionObject(new WellNotEmptyException('Well with coordinate "A1" is not empty. Use setWell() to overwrite the coordinate. Well content "s:10:"FD32807353";" was not added.'));
TecanScanner::parseRawContent("rackid,SA00411242\nA1,FD13945423\nA1,FD32807353\nC1,NO READ\nD1,NO READ\nE1,NO READ\nF1,NO READ\nG1,NO READ\nH1,NO READ\nA2,NO READ\nB2,NO READ\nC2,NO READ\nD2,NO READ\nE2,NO READ\nF2,NO READ\nG2,NO READ\nH2,NO READ\nA3,NO READ\nB3,NO READ\nC3,NO READ\nD3,NO READ\nE3,NO READ\nF3,NO READ\nG3,NO READ\nH3,NO READ\nA4,NO READ\nB4,NO READ\nC4,NO READ\nD4,NO READ\nE4,NO READ\nF4,NO READ\nG4,NO READ\nH4,NO READ\nA5,NO READ\nB5,NO READ\nC5,NO READ\nD5,NO READ\nE5,NO READ\nF5,NO READ\nG5,NO READ\nH5,NO READ\nA6,NO READ\nB6,NO READ\nC6,NO READ\nD6,NO READ\nE6,NO READ\nF6,NO READ\nG6,NO READ\nH6,NO READ\nA7,NO READ\nB7,NO READ\nC7,NO READ\nD7,NO READ\nE7,NO READ\nF7,NO READ\nG7,NO READ\nH7,NO READ\nA8,NO READ\nB8,NO READ\nC8,NO READ\nD8,NO READ\nE8,NO READ\nF8,NO READ\nG8,NO READ\nH8,NO READ\nA9,NO READ\nB9,NO READ\nC9,NO READ\nD9,NO READ\nE9,NO READ\nF9,NO READ\nG9,NO READ\nH9,NO READ\nA10,NO READ\nB10,NO READ\nC10,NO READ\nD10,NO READ\nE10,NO READ\nF10,NO READ\nG10,NO READ\nH10,NO READ\nA11,NO READ\nB11,NO READ\nC11,NO READ\nD11,NO READ\nE11,NO READ\nF11,NO READ\nG11,NO READ\nH11,NO READ\nA12,NO READ\nB12,NO READ\nC12,NO READ\nD12,NO READ\nE12,NO READ\nF12,NO READ\nG12,NO READ\nH12,NO READ");
TecanScanner::parseRawContent($rawContent);
}

public function testNoBarcode(): void
{
$rawContent = "A1,FD13945423\nB1,FD32807353\nC1,NO READ\nD1,NO READ\nE1,NO READ\nF1,NO READ\nG1,NO READ\nH1,NO READ\nA2,NO READ\nB2,NO READ\nC2,NO READ\nD2,NO READ\nE2,NO READ\nF2,NO READ\nG2,NO READ\nH2,NO READ\nA3,NO READ\nB3,NO READ\nC3,NO READ\nD3,NO READ\nE3,NO READ\nF3,NO READ\nG3,NO READ\nH3,NO READ\nA4,NO READ\nB4,NO READ\nC4,NO READ\nD4,NO READ\nE4,NO READ\nF4,NO READ\nG4,NO READ\nH4,NO READ\nA5,NO READ\nB5,NO READ\nC5,NO READ\nD5,NO READ\nE5,NO READ\nF5,NO READ\nG5,NO READ\nH5,NO READ\nA6,NO READ\nB6,NO READ\nC6,NO READ\nD6,NO READ\nE6,NO READ\nF6,NO READ\nG6,NO READ\nH6,NO READ\nA7,NO READ\nB7,NO READ\nC7,NO READ\nD7,NO READ\nE7,NO READ\nF7,NO READ\nG7,NO READ\nH7,NO READ\nA8,NO READ\nB8,NO READ\nC8,NO READ\nD8,NO READ\nE8,NO READ\nF8,NO READ\nG8,NO READ\nH8,NO READ\nA9,NO READ\nB9,NO READ\nC9,NO READ\nD9,NO READ\nE9,NO READ\nF9,NO READ\nG9,NO READ\nH9,NO READ\nA10,NO READ\nB10,NO READ\nC10,NO READ\nD10,NO READ\nE10,NO READ\nF10,NO READ\nG10,NO READ\nH10,NO READ\nA11,NO READ\nB11,NO READ\nC11,NO READ\nD11,NO READ\nE11,NO READ\nF11,NO READ\nG11,NO READ\nH11,NO READ\nA12,NO READ\nB12,NO READ\nC12,NO READ\nD12,NO READ\nE12,NO READ\nF12,NO READ\nG12,NO READ\nH12,NO READ";
self::assertFalse(TecanScanner::isValidRawContent($rawContent));

$this->expectExceptionObject(new NoRackIdException());
TecanScanner::parseRawContent("A1,FD13945423\nB1,FD32807353\nC1,NO READ\nD1,NO READ\nE1,NO READ\nF1,NO READ\nG1,NO READ\nH1,NO READ\nA2,NO READ\nB2,NO READ\nC2,NO READ\nD2,NO READ\nE2,NO READ\nF2,NO READ\nG2,NO READ\nH2,NO READ\nA3,NO READ\nB3,NO READ\nC3,NO READ\nD3,NO READ\nE3,NO READ\nF3,NO READ\nG3,NO READ\nH3,NO READ\nA4,NO READ\nB4,NO READ\nC4,NO READ\nD4,NO READ\nE4,NO READ\nF4,NO READ\nG4,NO READ\nH4,NO READ\nA5,NO READ\nB5,NO READ\nC5,NO READ\nD5,NO READ\nE5,NO READ\nF5,NO READ\nG5,NO READ\nH5,NO READ\nA6,NO READ\nB6,NO READ\nC6,NO READ\nD6,NO READ\nE6,NO READ\nF6,NO READ\nG6,NO READ\nH6,NO READ\nA7,NO READ\nB7,NO READ\nC7,NO READ\nD7,NO READ\nE7,NO READ\nF7,NO READ\nG7,NO READ\nH7,NO READ\nA8,NO READ\nB8,NO READ\nC8,NO READ\nD8,NO READ\nE8,NO READ\nF8,NO READ\nG8,NO READ\nH8,NO READ\nA9,NO READ\nB9,NO READ\nC9,NO READ\nD9,NO READ\nE9,NO READ\nF9,NO READ\nG9,NO READ\nH9,NO READ\nA10,NO READ\nB10,NO READ\nC10,NO READ\nD10,NO READ\nE10,NO READ\nF10,NO READ\nG10,NO READ\nH10,NO READ\nA11,NO READ\nB11,NO READ\nC11,NO READ\nD11,NO READ\nE11,NO READ\nF11,NO READ\nG11,NO READ\nH11,NO READ\nA12,NO READ\nB12,NO READ\nC12,NO READ\nD12,NO READ\nE12,NO READ\nF12,NO READ\nG12,NO READ\nH12,NO READ");
TecanScanner::parseRawContent($rawContent);
}

public function testSuccess(): void
{
$fluidXPlate = TecanScanner::parseRawContent("rackid,SA00411242\nA1,FD13945423\nB1,FD32807353\nC1,NO READ\nD1,NO READ\nE1,NO READ\nF1,NO READ\nG1,NO READ\nH1,NO READ\nA2,NO READ\nB2,NO READ\nC2,NO READ\nD2,NO READ\nE2,NO READ\nF2,NO READ\nG2,NO READ\nH2,NO READ\nA3,NO READ\nB3,NO READ\nC3,NO READ\nD3,NO READ\nE3,NO READ\nF3,NO READ\nG3,NO READ\nH3,NO READ\nA4,NO READ\nB4,NO READ\nC4,NO READ\nD4,NO READ\nE4,NO READ\nF4,NO READ\nG4,NO READ\nH4,NO READ\nA5,NO READ\nB5,NO READ\nC5,NO READ\nD5,NO READ\nE5,NO READ\nF5,NO READ\nG5,NO READ\nH5,NO READ\nA6,NO READ\nB6,NO READ\nC6,NO READ\nD6,NO READ\nE6,NO READ\nF6,NO READ\nG6,NO READ\nH6,NO READ\nA7,NO READ\nB7,NO READ\nC7,NO READ\nD7,NO READ\nE7,NO READ\nF7,NO READ\nG7,NO READ\nH7,NO READ\nA8,NO READ\nB8,NO READ\nC8,NO READ\nD8,NO READ\nE8,NO READ\nF8,NO READ\nG8,NO READ\nH8,NO READ\nA9,NO READ\nB9,NO READ\nC9,NO READ\nD9,NO READ\nE9,NO READ\nF9,NO READ\nG9,NO READ\nH9,NO READ\nA10,NO READ\nB10,NO READ\nC10,NO READ\nD10,NO READ\nE10,NO READ\nF10,NO READ\nG10,NO READ\nH10,NO READ\nA11,NO READ\nB11,NO READ\nC11,NO READ\nD11,NO READ\nE11,NO READ\nF11,NO READ\nG11,NO READ\nH11,NO READ\nA12,NO READ\nB12,NO READ\nC12,NO READ\nD12,NO READ\nE12,NO READ\nF12,NO READ\nG12,NO READ\nH12,NO READ");
$rawContent = "rackid,SA00411242\nA1,FD13945423\nB1,FD32807353\nC1,NO READ\nD1,NO READ\nE1,NO READ\nF1,NO READ\nG1,NO READ\nH1,NO READ\nA2,NO READ\nB2,NO READ\nC2,NO READ\nD2,NO READ\nE2,NO READ\nF2,NO READ\nG2,NO READ\nH2,NO READ\nA3,NO READ\nB3,NO READ\nC3,NO READ\nD3,NO READ\nE3,NO READ\nF3,NO READ\nG3,NO READ\nH3,NO READ\nA4,NO READ\nB4,NO READ\nC4,NO READ\nD4,NO READ\nE4,NO READ\nF4,NO READ\nG4,NO READ\nH4,NO READ\nA5,NO READ\nB5,NO READ\nC5,NO READ\nD5,NO READ\nE5,NO READ\nF5,NO READ\nG5,NO READ\nH5,NO READ\nA6,NO READ\nB6,NO READ\nC6,NO READ\nD6,NO READ\nE6,NO READ\nF6,NO READ\nG6,NO READ\nH6,NO READ\nA7,NO READ\nB7,NO READ\nC7,NO READ\nD7,NO READ\nE7,NO READ\nF7,NO READ\nG7,NO READ\nH7,NO READ\nA8,NO READ\nB8,NO READ\nC8,NO READ\nD8,NO READ\nE8,NO READ\nF8,NO READ\nG8,NO READ\nH8,NO READ\nA9,NO READ\nB9,NO READ\nC9,NO READ\nD9,NO READ\nE9,NO READ\nF9,NO READ\nG9,NO READ\nH9,NO READ\nA10,NO READ\nB10,NO READ\nC10,NO READ\nD10,NO READ\nE10,NO READ\nF10,NO READ\nG10,NO READ\nH10,NO READ\nA11,NO READ\nB11,NO READ\nC11,NO READ\nD11,NO READ\nE11,NO READ\nF11,NO READ\nG11,NO READ\nH11,NO READ\nA12,NO READ\nB12,NO READ\nC12,NO READ\nD12,NO READ\nE12,NO READ\nF12,NO READ\nG12,NO READ\nH12,NO READ";

$fluidXPlate = TecanScanner::parseRawContent($rawContent);
self::assertCount(96, $fluidXPlate->wells());
self::assertCount(94, $fluidXPlate->freeWells());
self::assertSame('SA00411242', $fluidXPlate->rackId);
Expand All @@ -47,5 +60,6 @@ public function testSuccess(): void
'A1' => 'FD13945423',
'B1' => 'FD32807353',
], $fluidXPlate->filledWells()->toArray());
self::assertTrue(TecanScanner::isValidRawContent($rawContent));
}
}

0 comments on commit 4cac541

Please sign in to comment.