diff --git a/src/Common/MaskPattern.php b/src/Common/MaskPattern.php index 1c151cfe1..810797ed5 100644 --- a/src/Common/MaskPattern.php +++ b/src/Common/MaskPattern.php @@ -10,11 +10,16 @@ namespace chillerlan\QRCode\Common; +use chillerlan\QRCode\Data\QRData; use chillerlan\QRCode\QRCodeException; use Closure; +use function abs, array_search, count, min; /** * ISO/IEC 18004:2000 Section 8.8.1 + * ISO/IEC 18004:2000 Section 8.8.2 - Evaluation of masking results + * + * @see http://www.thonky.com/qr-code-tutorial/data-masking */ final class MaskPattern{ @@ -95,4 +100,198 @@ final class MaskPattern{ ][$this->maskPattern]; } + /** + * Evaluates the matrix of the given data interface and returns a new mask pattern instance for the best result + */ + public static function getBestPattern(QRData $dataInterface):self{ + $penalties = []; + + foreach(self::PATTERNS as $pattern){ + $matrix = $dataInterface->writeMatrix(new self($pattern))->matrix(true); + $penalty = 0; + + for($level = 1; $level <= 4; $level++){ + $penalty += self::{'testRule'.$level}($matrix, count($matrix), count($matrix[0])); + } + + $penalties[$pattern] = (int)$penalty; + } + + return new self(array_search(min($penalties), $penalties, true)); + } + + /** + * Apply mask penalty rule 1 and return the penalty. Find repetitive cells with the same color and + * give penalty to them. Example: 00000 or 11111. + */ + public static function testRule1(array $matrix, int $height, int $width):int{ + return self::applyRule1($matrix, $height, $width, true) + self::applyRule1($matrix, $height, $width, false); + } + + private static function applyRule1(array $matrix, int $height, int $width, bool $isHorizontal):int{ + $penalty = 0; + $iLimit = $isHorizontal ? $height : $width; + $jLimit = $isHorizontal ? $width : $height; + + for($i = 0; $i < $iLimit; $i++){ + $numSameBitCells = 0; + $prevBit = -1; + + for($j = 0; $j < $jLimit; $j++){ + $bit = $isHorizontal ? $matrix[$i][$j] : $matrix[$j][$i]; + + if($bit === $prevBit){ + $numSameBitCells++; + } + else{ + + if($numSameBitCells >= 5){ + $penalty += 3 + ($numSameBitCells - 5); + } + + $numSameBitCells = 1; // Include the cell itself. + $prevBit = $bit; + } + } + if($numSameBitCells >= 5){ + $penalty += 3 + ($numSameBitCells - 5); + } + } + + return $penalty; + } + + /** + * Apply mask penalty rule 2 and return the penalty. Find 2x2 blocks with the same color and give + * penalty to them. This is actually equivalent to the spec's rule, which is to find MxN blocks and give a + * penalty proportional to (M-1)x(N-1), because this is the number of 2x2 blocks inside such a block. + */ + public static function testRule2(array $matrix, int $height, int $width):int{ + $penalty = 0; + + foreach($matrix as $y => $row){ + + if($y > $height - 2){ + break; + } + + foreach($row as $x => $val){ + + if($x > $width - 2){ + break; + } + + if( + $val === $row[$x + 1] + && $val === $matrix[$y + 1][$x] + && $val === $matrix[$y + 1][$x + 1] + ){ + $penalty++; + } + } + } + + return 3 * $penalty; + } + + /** + * Apply mask penalty rule 3 and return the penalty. Find consecutive runs of 1:1:3:1:1:4 + * starting with black, or 4:1:1:3:1:1 starting with white, and give penalty to them. If we + * find patterns like 000010111010000, we give penalty once. + */ + public static function testRule3(array $matrix, int $height, int $width):int{ + $penalties = 0; + + foreach($matrix as $y => $row){ + foreach($row as $x => $val){ + + if( + $x + 6 < $width + && $val + && !$row[$x + 1] + && $row[$x + 2] + && $row[$x + 3] + && $row[$x + 4] + && !$row[$x + 5] + && $row[$x + 6] + && ( + self::isWhiteHorizontal($row, $width, $x - 4, $x) + || self::isWhiteHorizontal($row, $width, $x + 7, $x + 11) + ) + ){ + $penalties++; + } + + if( + $y + 6 < $height + && $val + && !$matrix[$y + 1][$x] + && $matrix[$y + 2][$x] + && $matrix[$y + 3][$x] + && $matrix[$y + 4][$x] + && !$matrix[$y + 5][$x] + && $matrix[$y + 6][$x] + && ( + self::isWhiteVertical($matrix, $height, $x, $y - 4, $y) + || self::isWhiteVertical($matrix, $height, $x, $y + 7, $y + 11) + ) + ){ + $penalties++; + } + + } + } + + return $penalties * 40; + } + + private static function isWhiteHorizontal(array $row, int $width, int $from, int $to):bool{ + + if($from < 0 || $width < $to){ + return false; + } + + for($x = $from; $x < $to; $x++){ + if($row[$x]){ + return false; + } + } + + return true; + } + + private static function isWhiteVertical(array $matrix, int $height, int $x, int $from, int $to):bool{ + + if($from < 0 || $height < $to){ + return false; + } + + for($y = $from; $y < $to; $y++){ + if($matrix[$y][$x]){ + return false; + } + } + + return true; + } + + /** + * Apply mask penalty rule 4 and return the penalty. Calculate the ratio of dark cells and give + * penalty if the ratio is far from 50%. It gives 10 penalty for 5% distance. + */ + public static function testRule4(array $matrix, int $height, int $width):int{ + $darkCells = 0; + $totalCells = $height * $width; + + foreach($matrix as $row){ + foreach($row as $val){ + if($val){ + $darkCells++; + } + } + } + + return (int)(abs($darkCells * 2 - $totalCells) * 10 / $totalCells) * 10; + } + } diff --git a/src/Common/MaskPatternTester.php b/src/Common/MaskPatternTester.php deleted file mode 100644 index c35203c7e..000000000 --- a/src/Common/MaskPatternTester.php +++ /dev/null @@ -1,208 +0,0 @@ - - * @copyright 2017 Smiley - * @license MIT - * - * @noinspection PhpUnused - */ - -namespace chillerlan\QRCode\Common; - -use chillerlan\QRCode\Data\QRData; -use function abs, array_search, call_user_func_array, min; - -/** - * Receives a QRData object and runs the mask pattern tests on it. - * - * ISO/IEC 18004:2000 Section 8.8.2 - Evaluation of masking results - * - * @see http://www.thonky.com/qr-code-tutorial/data-masking - */ -final class MaskPatternTester{ - - /** - * The data interface that contains the data matrix to test - */ - private QRData $qrData; - - /** - * Receives the QRData object - * - * @see \chillerlan\QRCode\QROptions::$maskPattern - * @see \chillerlan\QRCode\Data\QRMatrix::$maskPattern - */ - public function __construct(QRData $qrData){ - $this->qrData = $qrData; - } - - /** - * shoves a QRMatrix through the MaskPatternTester to find the lowest penalty mask pattern - * - * @see \chillerlan\QRCode\Data\MaskPatternTester - */ - public function getBestMaskPattern():MaskPattern{ - $penalties = []; - - foreach(MaskPattern::PATTERNS as $pattern){ - $penalties[$pattern] = $this->testPattern(new MaskPattern($pattern)); - } - - return new MaskPattern(array_search(min($penalties), $penalties, true)); - } - - /** - * Returns the penalty for the given mask pattern - * - * @see \chillerlan\QRCode\QROptions::$maskPattern - * @see \chillerlan\QRCode\Data\QRMatrix::$maskPattern - */ - public function testPattern(MaskPattern $pattern):int{ - $matrix = $this->qrData->writeMatrix($pattern, true); - $penalty = 0; - - for($level = 1; $level <= 4; $level++){ - $penalty += call_user_func_array([$this, 'testLevel'.$level], [$matrix->matrix(true), $matrix->size()]); - } - - return (int)$penalty; - } - - /** - * Apply mask penalty rule 1 and return the penalty. Find repetitive cells with the same color and - * give penalty to them. Example: 00000 or 11111. - */ - private function testLevel1(array $m, int $size):int{ - $penalty = 0; - - foreach($m as $y => $row){ - foreach($row as $x => $val){ - $count = 0; - - for($ry = -1; $ry <= 1; $ry++){ - - if($y + $ry < 0 || $size <= $y + $ry){ - continue; - } - - for($rx = -1; $rx <= 1; $rx++){ - - if(($ry === 0 && $rx === 0) || (($x + $rx) < 0 || $size <= ($x + $rx))){ - continue; - } - - if($m[$y + $ry][$x + $rx] === $val){ - $count++; - } - - } - } - - if($count > 5){ - $penalty += (3 + $count - 5); - } - - } - } - - return $penalty; - } - - /** - * Apply mask penalty rule 2 and return the penalty. Find 2x2 blocks with the same color and give - * penalty to them. This is actually equivalent to the spec's rule, which is to find MxN blocks and give a - * penalty proportional to (M-1)x(N-1), because this is the number of 2x2 blocks inside such a block. - */ - private function testLevel2(array $m, int $size):int{ - $penalty = 0; - - foreach($m as $y => $row){ - - if($y > $size - 2){ - break; - } - - foreach($row as $x => $val){ - - if($x > $size - 2){ - break; - } - - if( - $val === $row[$x + 1] - && $val === $m[$y + 1][$x] - && $val === $m[$y + 1][$x + 1] - ){ - $penalty++; - } - } - } - - return 3 * $penalty; - } - - /** - * Apply mask penalty rule 3 and return the penalty. Find consecutive runs of 1:1:3:1:1:4 - * starting with black, or 4:1:1:3:1:1 starting with white, and give penalty to them. If we - * find patterns like 000010111010000, we give penalty once. - */ - private function testLevel3(array $m, int $size):int{ - $penalties = 0; - - foreach($m as $y => $row){ - foreach($row as $x => $val){ - - if( - $x + 6 < $size - && $val - && !$row[$x + 1] - && $row[$x + 2] - && $row[$x + 3] - && $row[$x + 4] - && !$row[$x + 5] - && $row[$x + 6] - ){ - $penalties++; - } - - if( - $y + 6 < $size - && $val - && !$m[$y + 1][$x] - && $m[$y + 2][$x] - && $m[$y + 3][$x] - && $m[$y + 4][$x] - && !$m[$y + 5][$x] - && $m[$y + 6][$x] - ){ - $penalties++; - } - - } - } - - return $penalties * 40; - } - - /** - * Apply mask penalty rule 4 and return the penalty. Calculate the ratio of dark cells and give - * penalty if the ratio is far from 50%. It gives 10 penalty for 5% distance. - */ - private function testLevel4(array $m, int $size):float{ - $count = 0; - - foreach($m as $y => $row){ - foreach($row as $x => $val){ - if($val){ - $count++; - } - } - } - - return (abs(100 * $count / $size / $size - 50) / 5) * 10; - } - -} diff --git a/src/Data/QRData.php b/src/Data/QRData.php index e8bf2884b..8ab359b3e 100644 --- a/src/Data/QRData.php +++ b/src/Data/QRData.php @@ -93,12 +93,12 @@ final class QRData{ /** * returns a fresh matrix object with the data written for the given $maskPattern */ - public function writeMatrix(MaskPattern $maskPattern, bool $test = null):QRMatrix{ + public function writeMatrix(MaskPattern $maskPattern):QRMatrix{ $data = (new ReedSolomonEncoder)->interleaveEcBytes($this->bitBuffer, $this->version, $this->eccLevel); return (new QRMatrix($this->version, $this->eccLevel)) ->initFunctionalPatterns() - ->initFormatInfo($maskPattern, $test) + ->initFormatInfo($maskPattern) ->mapData($data) ->mask($maskPattern) ; diff --git a/src/Data/QRMatrix.php b/src/Data/QRMatrix.php index 088e8a5e9..ae2636c98 100755 --- a/src/Data/QRMatrix.php +++ b/src/Data/QRMatrix.php @@ -105,10 +105,10 @@ final class QRMatrix{ /** * shortcut to set format and version info */ - public function initFormatInfo(MaskPattern $maskPattern, bool $test = null):self{ + public function initFormatInfo(MaskPattern $maskPattern):self{ return $this - ->setVersionNumber($test) - ->setFormatInfo($maskPattern, $test) + ->setVersionNumber() + ->setFormatInfo($maskPattern) ; } @@ -347,7 +347,7 @@ final class QRMatrix{ * * ISO/IEC 18004:2000 Section 8.10 */ - public function setVersionNumber(bool $test = null):self{ + public function setVersionNumber():self{ $bits = $this->version->getVersionPattern(); if($bits !== null){ @@ -355,7 +355,7 @@ final class QRMatrix{ for($i = 0; $i < 18; $i++){ $a = (int)($i / 3); $b = $i % 3 + $this->moduleCount - 8 - 3; - $v = !$test && (($bits >> $i) & 1) === 1; + $v = (($bits >> $i) & 1) === 1; $this->set($b, $a, $v, $this::M_VERSION); // ne $this->set($a, $b, $v, $this::M_VERSION); // sw @@ -371,11 +371,11 @@ final class QRMatrix{ * * ISO/IEC 18004:2000 Section 8.9 */ - public function setFormatInfo(MaskPattern $maskPattern, bool $test = null):self{ + public function setFormatInfo(MaskPattern $maskPattern):self{ $bits = $this->eccLevel->getformatPattern($maskPattern); for($i = 0; $i < 15; $i++){ - $v = !$test && (($bits >> $i) & 1) === 1; + $v = (($bits >> $i) & 1) === 1; if($i < 6){ $this->set(8, $i, $v, $this::M_FORMAT); diff --git a/src/QRCode.php b/src/QRCode.php index 0786590b1..da5c67ae6 100755 --- a/src/QRCode.php +++ b/src/QRCode.php @@ -10,7 +10,7 @@ namespace chillerlan\QRCode; -use chillerlan\QRCode\Common\{EccLevel, ECICharset, MaskPattern, MaskPatternTester, Mode}; +use chillerlan\QRCode\Common\{EccLevel, ECICharset, MaskPattern, Mode}; use chillerlan\QRCode\Data\{AlphaNum, Byte, ECI, Kanji, Number, QRData, QRCodeDataException, QRDataModeInterface, QRMatrix}; use chillerlan\QRCode\Decoder\{Decoder, DecoderResult, LuminanceSourceInterface}; use chillerlan\QRCode\Output\{QRCodeOutputException, QRFpdf, QRImage, QRImagick, QRMarkup, QROutputInterface, QRString}; @@ -101,11 +101,6 @@ class QRCode{ */ protected SettingsContainerInterface $options; - /** - * The selected data interface (Number, AlphaNum, Kanji, Byte) - */ - protected QRData $dataInterface; - /** * A collection of one or more data segments of [classname, data] to write * @@ -159,13 +154,12 @@ class QRCode{ throw new QRCodeDataException('QRCode::getMatrix() No data given.'); } - $this->dataInterface = new QRData($this->options, $this->dataSegments); - - $maskPattern = $this->options->maskPattern === $this::MASK_PATTERN_AUTO - ? (new MaskPatternTester($this->dataInterface))->getBestMaskPattern() + $dataInterface = new QRData($this->options, $this->dataSegments); + $maskPattern = $this->options->maskPattern === $this::MASK_PATTERN_AUTO + ? MaskPattern::getBestPattern($dataInterface) : new MaskPattern($this->options->maskPattern); - $matrix = $this->dataInterface->writeMatrix($maskPattern); + $matrix = $dataInterface->writeMatrix($maskPattern); if($this->options->addQuietzone){ $matrix->setQuietZone($this->options->quietzoneSize); diff --git a/tests/Common/MaskPatternTest.php b/tests/Common/MaskPatternTest.php index fa3924259..96ae86625 100644 --- a/tests/Common/MaskPatternTest.php +++ b/tests/Common/MaskPatternTest.php @@ -120,4 +120,38 @@ final class MaskPatternTest extends TestCase{ $maskPattern = new MaskPattern(42); } + public function testPenaltyRule1():void{ + // horizontal + $this::assertSame(0, MaskPattern::testRule1([[0, 0, 0, 0]], 1, 4)); + $this::assertSame(3, MaskPattern::testRule1([[0, 0, 0, 0, 0, 1]], 1, 6)); + $this::assertSame(4, MaskPattern::testRule1([[0, 0, 0, 0, 0, 0]], 1, 6)); + // vertical + $this::assertSame(0, MaskPattern::testRule1([[0], [0], [0], [0]], 4, 1)); + $this::assertSame(3, MaskPattern::testRule1([[0], [0], [0], [0], [0], [1]], 6, 1)); + $this::assertSame(4, MaskPattern::testRule1([[0], [0], [0], [0], [0], [0]], 6, 1)); + } + + public function testPenaltyRule2():void{ + $this::assertSame(0, MaskPattern::testRule2([[0]], 1, 1)); + $this::assertSame(0, MaskPattern::testRule2([[0, 0], [0, 1]], 2, 2)); + $this::assertSame(3, MaskPattern::testRule2([[0, 0], [0, 0]], 2, 2)); + $this::assertSame(12, MaskPattern::testRule2([[0, 0, 0], [0, 0, 0], [0, 0, 0]], 3, 3)); + } + + public function testPenaltyRule3():void{ + // horizontal + $this::assertSame(40, MaskPattern::testRule3([[0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1]], 1, 11)); + $this::assertSame(40, MaskPattern::testRule3([[1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0]], 1, 11)); + $this::assertSame(0, MaskPattern::testRule3([[1, 0, 1, 1, 1, 0, 1]], 1, 7)); + // vertical + $this::assertSame(40, MaskPattern::testRule3([[0], [0], [0], [0], [1], [0], [1], [1], [1], [0], [1]], 11, 1)); + $this::assertSame(40, MaskPattern::testRule3([[1], [0], [1], [1], [1], [0], [1], [0], [0], [0], [0]], 11, 1)); + $this::assertSame(0, MaskPattern::testRule3([[1], [0], [1], [1], [1], [0], [1]], 7, 1)); + } + + public function testPenaltyRule4():void{ + $this::assertSame(100, MaskPattern::testRule4([[0]], 1, 1)); + $this::assertSame(0, MaskPattern::testRule4([[0, 1]], 1, 2)); + $this::assertSame(30, MaskPattern::testRule4([[0, 1, 1, 1, 1, 0]], 1, 6)); + } } diff --git a/tests/Common/MaskPatternTesterTest.php b/tests/Common/MaskPatternTesterTest.php deleted file mode 100644 index d08889255..000000000 --- a/tests/Common/MaskPatternTesterTest.php +++ /dev/null @@ -1,41 +0,0 @@ - - * @copyright 2017 Smiley - * @license MIT - */ - -namespace chillerlan\QRCodeTest\Common; - -use chillerlan\QRCode\Common\{MaskPattern, MaskPatternTester}; -use chillerlan\QRCode\Data\{Byte, QRData}; -use chillerlan\QRCode\QROptions; -use PHPUnit\Framework\TestCase; - -/** - * MaskPatternTester coverage test - */ -final class MaskPatternTesterTest extends TestCase{ - - /** - * Tests getting the best mask pattern - */ - public function testMaskpattern():void{ - $dataInterface = new QRData(new QROptions(['version' => 10]), [new Byte('test')]); - - $this::assertSame(3, (new MaskPatternTester($dataInterface))->getBestMaskPattern()->getPattern()); - } - - /** - * Tests getting the penalty value for a given mask pattern - */ - public function testMaskpatternID():void{ - $dataInterface = new QRData(new QROptions(['version' => 10]), [new Byte('test')]); - - $this::assertSame(4243, (new MaskPatternTester($dataInterface))->testPattern(new MaskPattern(MaskPattern::PATTERN_011))); - } - -} diff --git a/tests/Data/QRMatrixTest.php b/tests/Data/QRMatrixTest.php index 53e554135..d8e019899 100755 --- a/tests/Data/QRMatrixTest.php +++ b/tests/Data/QRMatrixTest.php @@ -14,21 +14,18 @@ use chillerlan\QRCode\Common\{EccLevel, MaskPattern, Version}; use chillerlan\QRCode\{QRCode, QROptions}; use chillerlan\QRCode\Data\{QRCodeDataException, QRMatrix}; use PHPUnit\Framework\TestCase; +use Generator; /** * Tests the QRMatix class */ final class QRMatrixTest extends TestCase{ - /** @internal */ protected const version = 40; - /** @internal */ protected QRMatrix $matrix; /** * invokes a QRMatrix object - * - * @internal */ protected function setUp():void{ $this->matrix = $this->getMatrix($this::version); @@ -36,8 +33,6 @@ final class QRMatrixTest extends TestCase{ /** * shortcut - * - * @internal */ protected function getMatrix(int $version):QRMatrix{ return new QRMatrix(new Version($version), new EccLevel(EccLevel::L)); @@ -80,7 +75,7 @@ final class QRMatrixTest extends TestCase{ $matrix = (new QRCode)->addByteSegment('testdata')->getMatrix(); $this::assertInstanceOf(MaskPattern::class, $matrix->maskPattern()); - $this::assertSame(MaskPattern::PATTERN_010, $matrix->maskPattern()->getPattern()); + $this::assertSame(MaskPattern::PATTERN_100, $matrix->maskPattern()->getPattern()); } /** @@ -98,18 +93,11 @@ final class QRMatrixTest extends TestCase{ /** * Version data provider for several pattern tests - * - * @return int[][] - * @internal */ - public function versionProvider():array{ - $versions = []; - - for($i = 1; $i <= 40; $i++){ - $versions[] = [$i]; + public function versionProvider():Generator{ + foreach(range(1, 40) as $i){ + yield 'version: '.$i => [$i]; } - - return $versions; } /** @@ -158,10 +146,7 @@ final class QRMatrixTest extends TestCase{ public function testSetAlignmentPattern(int $version):void{ if($version === 1){ - $this->markTestSkipped('N/A'); - - /** @noinspection PhpUnreachableStatementInspection */ - return; + $this->markTestSkipped('N/A (Version 1 has no alignment pattern)'); } $matrix = $this @@ -175,8 +160,8 @@ final class QRMatrixTest extends TestCase{ foreach($alignmentPattern as $py){ foreach($alignmentPattern as $px){ - if($matrix->get($px, $py) === (QRMatrix::M_FINDER | QRMatrix::IS_DARK)){ - $this::assertSame(QRMatrix::M_FINDER | QRMatrix::IS_DARK, $matrix->get($px, $py), 'skipped finder pattern'); + if($matrix->checkType($px, $py, QRMatrix::M_FINDER)){ + // skip finder pattern continue; } @@ -203,14 +188,13 @@ final class QRMatrixTest extends TestCase{ for($i = 7; $i < $size - 7; $i++){ if($i % 2 === 0){ - $p1 = $matrix->get(6, $i); - if($p1 === (QRMatrix::M_ALIGNMENT | QRMatrix::IS_DARK)){ - $this::assertSame(QRMatrix::M_ALIGNMENT | QRMatrix::IS_DARK, $p1, 'skipped alignment pattern'); + if($matrix->checkType(6, $i, QRMatrix::M_ALIGNMENT)){ + // skip alignment pattern continue; } - $this::assertSame(QRMatrix::M_TIMING | QRMatrix::IS_DARK, $p1); + $this::assertSame(QRMatrix::M_TIMING | QRMatrix::IS_DARK, $matrix->get(6, $i)); $this::assertSame(QRMatrix::M_TIMING | QRMatrix::IS_DARK, $matrix->get($i, 6)); } } @@ -224,18 +208,18 @@ final class QRMatrixTest extends TestCase{ public function testSetVersionNumber(int $version):void{ if($version < 7){ - $this->markTestSkipped('N/A'); + $this->markTestSkipped('N/A (Version < 7)'); /** @noinspection PhpUnreachableStatementInspection */ return; } - $matrix = $this->getMatrix($version)->setVersionNumber(true); + $matrix = $this->getMatrix($version)->setVersionNumber(); - $this::assertSame(QRMatrix::M_VERSION, $matrix->get($matrix->size() - 9, 0)); - $this::assertSame(QRMatrix::M_VERSION, $matrix->get($matrix->size() - 11, 5)); - $this::assertSame(QRMatrix::M_VERSION, $matrix->get(0, $matrix->size() - 9)); - $this::assertSame(QRMatrix::M_VERSION, $matrix->get(5, $matrix->size() - 11)); + $this::assertTrue($matrix->checkType($matrix->size() - 9, 0, QRMatrix::M_VERSION)); + $this::assertTrue($matrix->checkType($matrix->size() - 11, 5, QRMatrix::M_VERSION)); + $this::assertTrue($matrix->checkType(0, $matrix->size() - 9, QRMatrix::M_VERSION)); + $this::assertTrue($matrix->checkType(5, $matrix->size() - 11, QRMatrix::M_VERSION)); } /** @@ -244,12 +228,12 @@ final class QRMatrixTest extends TestCase{ * @dataProvider versionProvider */ public function testSetFormatInfo(int $version):void{ - $matrix = $this->getMatrix($version)->setFormatInfo(new MaskPattern(MaskPattern::PATTERN_000), true); + $matrix = $this->getMatrix($version)->setFormatInfo(new MaskPattern(MaskPattern::PATTERN_000)); - $this::assertSame(QRMatrix::M_FORMAT, $matrix->get(8, 0)); - $this::assertSame(QRMatrix::M_FORMAT, $matrix->get(0, 8)); - $this::assertSame(QRMatrix::M_FORMAT, $matrix->get($matrix->size() - 1, 8)); - $this::assertSame(QRMatrix::M_FORMAT, $matrix->get($matrix->size() - 8, 8)); + $this::assertTrue($matrix->checkType(8, 0, QRMatrix::M_FORMAT)); + $this::assertTrue($matrix->checkType(0, 8, QRMatrix::M_FORMAT)); + $this::assertTrue($matrix->checkType($matrix->size() - 1, 8, QRMatrix::M_FORMAT)); + $this::assertTrue($matrix->checkType($matrix->size() - 8, 8, QRMatrix::M_FORMAT)); } /** @@ -272,15 +256,15 @@ final class QRMatrixTest extends TestCase{ $this::assertCount($size + 2 * $q, $matrix->matrix()[$size - 1]); $size = $matrix->size(); - $this::assertSame(QRMatrix::M_QUIETZONE, $matrix->get(0, 0)); - $this::assertSame(QRMatrix::M_QUIETZONE, $matrix->get($size - 1, $size - 1)); + $this::assertTrue($matrix->checkType(0, 0, QRMatrix::M_QUIETZONE)); + $this::assertTrue($matrix->checkType($size - 1, $size - 1, QRMatrix::M_QUIETZONE)); $this::assertSame(QRMatrix::M_TEST | QRMatrix::IS_DARK, $matrix->get($q, $q)); $this::assertSame(QRMatrix::M_TEST | QRMatrix::IS_DARK, $matrix->get($size - 1 - $q, $size - 1 - $q)); } /** - * Tests if an exception is thrown in an attempt to create it before data was written + * Tests if an exception is thrown in an attempt to create the quiet zone before data was written */ public function testSetQuietZoneException():void{ $this->expectException(QRCodeDataException::class); @@ -289,6 +273,9 @@ final class QRMatrixTest extends TestCase{ $this->matrix->setQuietZone(); } + /** + * Tests the auto orientation of the logo space + */ public function testSetLogoSpaceOrientation():void{ $o = new QROptions; $o->version = 10; @@ -300,14 +287,17 @@ final class QRMatrixTest extends TestCase{ $matrix->setLogoSpace(20, 14); // NW corner - $this::assertNotSame(QRMatrix::M_LOGO, $matrix->get(17, 20)); - $this::assertSame(QRMatrix::M_LOGO, $matrix->get(18, 21)); + $this::assertFalse($matrix->checkType(17, 20, QRMatrix::M_LOGO)); + $this::assertTrue($matrix->checkType(18, 21, QRMatrix::M_LOGO)); // SE corner - $this::assertSame(QRMatrix::M_LOGO, $matrix->get(38, 35)); - $this::assertNotSame(QRMatrix::M_LOGO, $matrix->get(39, 36)); + $this::assertTrue($matrix->checkType(38, 35, QRMatrix::M_LOGO)); + $this::assertFalse($matrix->checkType(39, 36, QRMatrix::M_LOGO)); } + /** + * Tests the manual positioning of the logo space + */ public function testSetLogoSpacePosition():void{ $o = new QROptions; $o->version = 10; @@ -336,6 +326,9 @@ final class QRMatrixTest extends TestCase{ $this::assertSame(QRMatrix::M_QUIETZONE, $m->get(67, 67)); } + /** + * Tests whether an exception is thrown when an ECC level other than "H" is set when attempting to add logo space + */ public function testSetLogoSpaceInvalidEccException():void{ $this->expectException(QRCodeDataException::class); $this->expectExceptionMessage('ECC level "H" required to add logo space'); @@ -343,6 +336,9 @@ final class QRMatrixTest extends TestCase{ (new QRCode)->addByteSegment('testdata')->getMatrix()->setLogoSpace(50, 50); } + /** + * Tests whether an exception is thrown when the logo space size exceeds the maximum ECC capacity + */ public function testSetLogoSpaceMaxSizeException():void{ $this->expectException(QRCodeDataException::class); $this->expectExceptionMessage('logo space exceeds the maximum error correction capacity');