Просмотр исходного кода

:octocat: +several coverage tests & cleanup

smiley 3 лет назад
Родитель
Сommit
9db842d6ca

+ 1 - 1
src/Common/BitBuffer.php

@@ -112,7 +112,7 @@ final class BitBuffer{
 	 */
 	public function read(int $numBits):int{
 
-		if($numBits < 1 || $numBits > 32 || $numBits > $this->available()){
+		if($numBits < 1 || $numBits > $this->available()){
 			throw new QRCodeException('invalid $numBits: '.$numBits);
 		}
 

+ 1 - 1
src/Common/EccLevel.php

@@ -33,7 +33,7 @@ final class EccLevel{
 	/**
 	 * ISO/IEC 18004:2000 Tables 7-11 - Number of symbol characters and input data capacity for versions 1 to 40
 	 *
-	 * @var int [][]
+	 * @var int[][]
 	 */
 	private const MAX_BITS = [
 	//	[    L,     M,     Q,     H]  // v  => modules

+ 8 - 1
src/Common/Mode.php

@@ -90,9 +90,16 @@ final class Mode{
 
 	/**
 	 * returns the array of length bits for the given mode
+	 *
+	 * @throws \chillerlan\QRCode\QRCodeException
 	 */
 	public static function getLengthBitsForMode(int $mode):array{
-		return self::LENGTH_BITS[$mode];
+
+		if(isset(self::LENGTH_BITS[$mode])){
+			return self::LENGTH_BITS[$mode];
+		}
+
+		throw new QRCodeException('invalid mode given');
 	}
 
 }

+ 1 - 1
src/Common/Version.php

@@ -217,7 +217,7 @@ final class Version{
 	public function __construct(int $version){
 
 		if($version < 1 || $version > 40){
-			throw new QRCodeException('invalid version number');
+			throw new QRCodeException('invalid version given');
 		}
 
 		$this->version = $version;

+ 2 - 2
src/Data/AlphaNum.php

@@ -109,7 +109,7 @@ final class AlphaNum extends QRDataModeAbstract{
 		while($length > 1){
 
 			if($bitBuffer->available() < 11){
-				throw new QRCodeDataException('not enough bits available');
+				throw new QRCodeDataException('not enough bits available'); // @codeCoverageIgnore
 			}
 
 			$nextTwoCharsBits = $bitBuffer->read(11);
@@ -121,7 +121,7 @@ final class AlphaNum extends QRDataModeAbstract{
 		if($length === 1){
 			// special case: one character left
 			if($bitBuffer->available() < 6){
-				throw new QRCodeDataException('not enough bits available');
+				throw new QRCodeDataException('not enough bits available'); // @codeCoverageIgnore
 			}
 
 			$result .= $toAlphaNumericChar($bitBuffer->read(6));

+ 1 - 1
src/Data/Byte.php

@@ -70,7 +70,7 @@ final class Byte extends QRDataModeAbstract{
 		$length = $bitBuffer->read(self::getLengthBits($versionNumber));
 
 		if($bitBuffer->available() < 8 * $length){
-			throw new QRCodeDataException('not enough bits available');
+			throw new QRCodeDataException('not enough bits available'); // @codeCoverageIgnore
 		}
 
 		$readBytes = '';

+ 1 - 1
src/Data/Kanji.php

@@ -119,7 +119,7 @@ final class Kanji extends QRDataModeAbstract{
 		$length = $bitBuffer->read(self::getLengthBits($versionNumber));
 
 		if($bitBuffer->available() < $length * 13){
-			throw new QRCodeDataException('not enough bits available');
+			throw new QRCodeDataException('not enough bits available');  // @codeCoverageIgnore
 		}
 
 		$buffer = [];

+ 3 - 3
src/Data/Number.php

@@ -126,7 +126,7 @@ final class Number extends QRDataModeAbstract{
 		while($length >= 3){
 			// Each 10 bits encodes three digits
 			if($bitBuffer->available() < 10){
-				throw new QRCodeDataException('not enough bits available');
+				throw new QRCodeDataException('not enough bits available'); // @codeCoverageIgnore
 			}
 
 			$threeDigitsBits = $bitBuffer->read(10);
@@ -145,7 +145,7 @@ final class Number extends QRDataModeAbstract{
 		if($length === 2){
 			// Two digits left over to read, encoded in 7 bits
 			if($bitBuffer->available() < 7){
-				throw new QRCodeDataException('not enough bits available');
+				throw new QRCodeDataException('not enough bits available'); // @codeCoverageIgnore
 			}
 
 			$twoDigitsBits = $bitBuffer->read(7);
@@ -160,7 +160,7 @@ final class Number extends QRDataModeAbstract{
 		elseif($length === 1){
 			// One digit left over to read
 			if($bitBuffer->available() < 4){
-				throw new QRCodeDataException('not enough bits available');
+				throw new QRCodeDataException('not enough bits available'); // @codeCoverageIgnore
 			}
 
 			$digitBits = $bitBuffer->read(4);

+ 6 - 6
src/Data/QRMatrix.php

@@ -534,17 +534,17 @@ class QRMatrix{
 			throw new QRCodeDataException('ECC level "H" required to add logo space');
 		}
 
-		// if width and height happen to be exactly 0 (default value), just return - nothing to do
-		if($width === 0 || $height === 0){
-			return $this;
+		// if width and height happen to be negative or 0 (default value), just return - nothing to do
+		if($width <= 0 || $height <= 0){
+			return $this; // @codeCoverageIgnore
 		}
 
 		// $this->moduleCount includes the quiet zone (if created), we need the QR size here
 		$length = $this->version->getDimension();
 
-		// throw if the size is negative or exceeds the qrcode size
-		if($width < 0 || $height < 0 || $width > $length || $height > $length){
-			throw new QRCodeDataException('invalid logo dimensions');
+		// throw if the size is exceeds the qrcode size
+		if($width > $length || $height > $length){
+			throw new QRCodeDataException('logo dimensions exceed matrix size');
 		}
 
 		// we need uneven sizes to center the logo space, adjust if needed

+ 1 - 1
src/Decoder/Binarizer.php

@@ -103,7 +103,7 @@ final class Binarizer{
 		// If there is too little contrast in the image to pick a meaningful black point, throw rather
 		// than waste time trying to decode the image, and risk false positives.
 		if($secondPeak - $firstPeak <= $numBuckets / 16){
-			throw new QRCodeDecoderException('no meaningful dark point found');
+			throw new QRCodeDecoderException('no meaningful dark point found'); // @codeCoverageIgnore
 		}
 
 		// Find a valley between them that is low and closer to the white peak.

+ 9 - 0
tests/Common/BitBufferTest.php

@@ -11,6 +11,7 @@
 namespace chillerlan\QRCodeTest\Common;
 
 use chillerlan\QRCode\Common\{BitBuffer, Mode};
+use chillerlan\QRCode\QRCodeException;
 use PHPUnit\Framework\TestCase;
 
 /**
@@ -42,4 +43,12 @@ final class BitBufferTest extends TestCase{
 		$this::assertSame(4, $this->bitBuffer->getLength());
 	}
 
+	public function testReadException():void{
+		$this->expectException(QRCodeException::class);
+		$this->expectExceptionMessage('invalid $numBits');
+
+		$this->bitBuffer->put(Mode::KANJI, 4);
+		$this->bitBuffer->read($this->bitBuffer->available() + 1);
+	}
+
 }

+ 60 - 0
tests/Common/EccLevelTest.php

@@ -0,0 +1,60 @@
+<?php
+/**
+ * Class EccLevelTest
+ *
+ * @created      25.07.2022
+ * @author       smiley <smiley@chillerlan.net>
+ * @copyright    2022 smiley
+ * @license      MIT
+ */
+
+namespace chillerlan\QRCodeTest\Common;
+
+use chillerlan\QRCode\Common\EccLevel;
+use chillerlan\QRCode\Common\MaskPattern;
+use chillerlan\QRCode\QRCodeException;
+use PHPUnit\Framework\TestCase;
+
+/**
+ * EccLevel coverage test
+ */
+final class EccLevelTest extends TestCase{
+
+	public function testConstructInvalidEccException():void{
+		$this->expectException(QRCodeException::class);
+		$this->expectExceptionMessage('invalid ECC level');
+
+		$ecc = new EccLevel(69);
+	}
+
+	public function testToString():void{
+		$ecc = new EccLevel(EccLevel::L);
+
+		$this::assertSame('L', (string)$ecc);
+	}
+
+	public function testGetLevel():void{
+		$ecc = new EccLevel(EccLevel::L);
+
+		$this::assertSame(EccLevel::L, $ecc->getLevel());
+	}
+
+	public function testGetOrdinal():void{
+		$ecc = new EccLevel(EccLevel::L);
+
+		$this::assertSame(0, $ecc->getOrdinal());
+	}
+
+	public function testGetformatPattern():void{
+		$ecc = new EccLevel(EccLevel::Q);
+
+		$this::assertSame(0b010010010110100, $ecc->getformatPattern(new MaskPattern(4)));
+	}
+
+	public function getMaxBits():void{
+		$ecc = new EccLevel(EccLevel::Q);
+
+		$this::assertSame(4096, $ecc->getMaxBits()[21]);
+	}
+
+}

+ 64 - 0
tests/Common/ModeTest.php

@@ -0,0 +1,64 @@
+<?php
+/**
+ * Class ModeTest
+ *
+ * @created      25.07.2022
+ * @author       smiley <smiley@chillerlan.net>
+ * @copyright    2022 smiley
+ * @license      MIT
+ */
+
+namespace chillerlan\QRCodeTest\Common;
+
+use chillerlan\QRCode\Common\Mode;
+use chillerlan\QRCode\QRCodeException;
+use PHPUnit\Framework\TestCase;
+
+/**
+ * Mode coverage test
+ */
+final class ModeTest extends TestCase{
+
+	/**
+	 * version breakpoints for numeric mode
+	 */
+	public function versionProvider():array{
+		return [
+			[ 1, 10],
+			[ 9, 10],
+			[10, 12],
+			[26, 12],
+			[27, 14],
+			[40, 14],
+		];
+	}
+
+	/**
+	 * @dataProvider versionProvider
+	 */
+	public function testGetLengthBitsForVersionBreakpoints(int $version, int $expected):void{
+		$this::assertSame($expected, Mode::getLengthBitsForVersion(Mode::NUMBER, $version));
+	}
+
+	public function testGetLengthBitsForVersionInvalidModeException():void{
+		$this->expectException(QRCodeException::class);
+		$this->expectExceptionMessage('invalid mode given');
+
+		$bits = Mode::getLengthBitsForVersion(42, 69);
+	}
+
+	public function testGetLengthBitsForVersionInvalidVersionException():void{
+		$this->expectException(QRCodeException::class);
+		$this->expectExceptionMessage('invalid version number');
+
+		$bits = Mode::getLengthBitsForVersion(Mode::BYTE, 69);
+	}
+
+	public function testGetLengthBitsForModeInvalidModeException():void{
+		$this->expectException(QRCodeException::class);
+		$this->expectExceptionMessage('invalid mode given');
+
+		$bits = Mode::getLengthBitsForMode(42);
+	}
+
+}

+ 67 - 0
tests/Common/VersionTest.php

@@ -0,0 +1,67 @@
+<?php
+/**
+ * Class VersionTest
+ *
+ * @created      25.07.2022
+ * @author       smiley <smiley@chillerlan.net>
+ * @copyright    2022 smiley
+ * @license      MIT
+ */
+
+namespace chillerlan\QRCodeTest\Common;
+
+use chillerlan\QRCode\Common\EccLevel;
+use chillerlan\QRCode\Common\Mode;
+use chillerlan\QRCode\Common\Version;
+use chillerlan\QRCode\QRCodeException;
+use PHPUnit\Framework\TestCase;
+
+/**
+ * Version coverage test
+ */
+final class VersionTest extends TestCase{
+
+	private Version $version;
+
+	protected function setUp():void{
+		$this->version = new Version(7);
+	}
+
+	public function testToString():void{
+		$this::assertSame('7', (string)$this->version);
+	}
+
+	public function testGetVersionNumber():void{
+		$this::assertSame(7, $this->version->getVersionNumber());
+	}
+
+	public function testGetDimension():void{
+		$this::assertSame(45, $this->version->getDimension());
+	}
+
+	public function testGetVersionPattern():void{
+		$this::assertSame(0b000111110010010100, $this->version->getVersionPattern());
+		// no pattern for version < 7
+		$this::assertNull((new Version(6))->getVersionPattern());
+	}
+
+	public function testGetAlignmentPattern():void{
+		$this::assertSame([6, 22, 38], $this->version->getAlignmentPattern());
+	}
+
+	public function testGetRSBlocks():void{
+		$this::assertSame([18, [[2, 14], [4, 15]]], $this->version->getRSBlocks(new EccLevel(EccLevel::Q)));
+	}
+
+	public function testGetTotalCodewords():void{
+		$this::assertSame(196, $this->version->getTotalCodewords());
+	}
+
+	public function testConstructInvalidVersion():void{
+		$this->expectException(QRCodeException::class);
+		$this->expectExceptionMessage('invalid version given');
+
+		$version = new Version(69);
+	}
+
+}

+ 109 - 0
tests/Data/QRMatrixTest.php

@@ -155,6 +155,10 @@ final class QRMatrixTest extends TestCase{
 		$this->matrix->set(20, 20, false, QRMatrix::M_TEST);
 		$this::assertSame(QRMatrix::M_TEST, $this->matrix->get(20, 20));
 		$this::assertFalse($this->matrix->check(20, 20));
+
+		// out of range
+		$this::assertFalse($this->matrix->check(-1, -1));
+		$this::assertSame(-1, $this->matrix->get(-1, -1));
 	}
 
 	/**
@@ -413,6 +417,20 @@ final class QRMatrixTest extends TestCase{
 		(new QRCode)->addByteSegment('testdata')->getMatrix()->setLogoSpace(50, 50);
 	}
 
+	/**
+	 * Tests whether an exception is thrown when width or height exceed the matrix size
+	 */
+	public function testSetLogoSpaceExceedsException():void{
+		$this->expectException(QRCodeDataException::class);
+		$this->expectExceptionMessage('logo dimensions exceed matrix size');
+
+		$o = new QROptions;
+		$o->version  = 5;
+		$o->eccLevel = EccLevel::H;
+
+		(new QRCode($o))->addByteSegment('testdata')->getMatrix()->setLogoSpace(69, 1);
+	}
+
 	/**
 	 * Tests whether an exception is thrown when the logo space size exceeds the maximum ECC capacity
 	 */
@@ -450,4 +468,95 @@ final class QRMatrixTest extends TestCase{
 		$this::assertSame(QRMatrix::M_DARKMODULE | QRMatrix::IS_DARK, $this->matrix->get($x, $y));
 	}
 
+	/**
+	 * Tests checking whether the M_TYPE of a module is not one of an array of M_TYPES
+	 */
+	public function testCheckTypeNotIn():void{
+		$this->matrix->set(10, 10, true, QRMatrix::M_QUIETZONE);
+
+		$this::assertTrue($this->matrix->checkTypeNotIn(10, 10, [QRMatrix::M_DATA, QRMatrix::M_FINDER]));
+		$this::assertFalse($this->matrix->checkTypeNotIn(10, 10, [QRMatrix::M_QUIETZONE, QRMatrix::M_FINDER]));
+	}
+
+	/**
+	 * Tests checking the adjacent modules
+	 */
+	public function testCheckNeighbours():void{
+
+		$this->matrix
+			->setFinderPattern()
+			->setAlignmentPattern()
+		;
+
+		/*
+		 * center of finder pattern (surrounded by all dark)
+		 *
+		 *   # # # # # # #
+		 *   #           #
+		 *   #   # # #   #
+		 *   #   # 0 #   #
+		 *   #   # # #   #
+		 *   #           #
+		 *   # # # # # # #
+		 */
+		$this::assertSame(0b11111111, $this->matrix->checkNeighbours(3, 3));
+
+		/*
+		 * center of alignment pattern (surrounded by all light)
+		 *
+		 *   # # # # #
+		 *   #       #
+		 *   #   0   #
+		 *   #       #
+		 *   # # # # #
+		 */
+		$this::assertSame(0b00000000, $this->matrix->checkNeighbours(30, 30));
+
+		/*
+		 * top left light block of finder pattern
+		 *
+		 *   # # #
+		 *   # 0
+		 *   #   #
+		 */
+		$this::assertSame(0b11010111, $this->matrix->checkNeighbours(1, 1));
+
+		/*
+		 * bottom left light block of finder pattern
+		 *
+		 *   #   #
+		 *   # 0
+		 *   # # #
+		 */
+		$this::assertSame(0b11110101, $this->matrix->checkNeighbours(1, 5));
+
+		/*
+		 * top right light block of finder pattern
+		 *
+		 *   # # #
+		 *     0 #
+		 *   #   #
+		 */
+		$this::assertSame(0b01011111, $this->matrix->checkNeighbours(5, 1));
+
+		/*
+		 * bottom right light block of finder pattern
+		 *
+		 *   #   #
+		 *     0 #
+		 *   # # #
+		 */
+		$this::assertSame(0b01111101, $this->matrix->checkNeighbours(5, 5));
+
+
+		/*
+		 * M_TYPE check
+		 *
+		 *   # # #
+		 *     0
+		 *   X X X
+		 */
+		$this::assertSame(0b00000111, $this->matrix->checkNeighbours(3, 1, QRMatrix::M_FINDER));
+		$this::assertSame(0b01110000, $this->matrix->checkNeighbours(3, 1, QRMatrix::M_FINDER_DOT));
+	}
 }