DataInterfaceTestAbstract.php 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. <?php
  2. /**
  3. * Class DataInterfaceTestAbstract
  4. *
  5. * @created 24.11.2017
  6. * @author Smiley <smiley@chillerlan.net>
  7. * @copyright 2017 Smiley
  8. * @license MIT
  9. */
  10. namespace chillerlan\QRCodeTest\Data;
  11. use chillerlan\QRCode\Common\{MaskPattern, Version};
  12. use chillerlan\QRCode\QROptions;
  13. use PHPUnit\Framework\TestCase;
  14. use chillerlan\QRCode\Data\{Hanzi, QRCodeDataException, QRData, QRDataModeInterface, QRMatrix};
  15. use ReflectionClass;
  16. use function hex2bin;
  17. use function str_repeat;
  18. /**
  19. * The data interface test abstract
  20. */
  21. abstract class DataInterfaceTestAbstract extends TestCase{
  22. protected ReflectionClass $reflection;
  23. protected QRData $QRData;
  24. protected string $FQN;
  25. protected string $testdata;
  26. protected function setUp():void{
  27. $this->QRData = new QRData(new QROptions);
  28. $this->reflection = new ReflectionClass($this->QRData);
  29. }
  30. /**
  31. * Verifies the QRData instance
  32. */
  33. public function testInstance():void{
  34. $this::assertInstanceOf(QRData::class, $this->QRData);
  35. }
  36. /**
  37. * Verifies the QRDataModeInterface instance
  38. */
  39. public function testDataModeInstance():void{
  40. $datamode = new $this->FQN($this->testdata);
  41. $this::assertInstanceOf(QRDataModeInterface::class, $datamode);
  42. }
  43. /**
  44. * @see testInitMatrix()
  45. * @return int[][]
  46. */
  47. public function maskPatternProvider():array{
  48. return [[0], [1], [2], [3], [4], [5], [6], [7]];
  49. }
  50. /**
  51. * Tests initializing the data matrix
  52. *
  53. * @dataProvider maskPatternProvider
  54. */
  55. public function testInitMatrix(int $maskPattern):void{
  56. $this->QRData->setData([new $this->FQN($this->testdata)]);
  57. $matrix = $this->QRData->writeMatrix(new MaskPattern($maskPattern));
  58. $this::assertInstanceOf(QRMatrix::class, $matrix);
  59. $this::assertSame($maskPattern, $matrix->maskPattern()->getPattern());
  60. }
  61. /**
  62. * Tests getting the minimum QR version for the given data
  63. */
  64. public function testGetMinimumVersion():void{
  65. $this->QRData->setData([new $this->FQN($this->testdata)]);
  66. $getMinimumVersion = $this->reflection->getMethod('getMinimumVersion');
  67. $getMinimumVersion->setAccessible(true);
  68. /** @var \chillerlan\QRCode\Common\Version $version */
  69. $version = $getMinimumVersion->invoke($this->QRData);
  70. $this::assertInstanceOf(Version::class, $version);
  71. $this::assertSame(1, $version->getVersionNumber());
  72. }
  73. abstract public function stringValidateProvider():array;
  74. /**
  75. * Tests if a string is properly validated for the respective data mode
  76. *
  77. * @dataProvider stringValidateProvider
  78. */
  79. public function testValidateString(string $string, bool $expected):void{
  80. /** @noinspection PhpUndefinedMethodInspection */
  81. $this::assertSame($expected, $this->FQN::validateString($string));
  82. }
  83. /**
  84. * Tests if a binary string is properly validated as false
  85. *
  86. * @see https://github.com/chillerlan/php-qrcode/issues/182
  87. */
  88. public function testBinaryStringInvalid():void{
  89. /** @noinspection PhpUndefinedMethodInspection */
  90. $this::assertFalse($this->FQN::validateString(hex2bin('01015989f47dff8e852122117e04c90b9f15defc1c36477b1fe1')));
  91. }
  92. /**
  93. * returns versions within the version breakpoints 1-9, 10-26 and 27-40
  94. */
  95. public function versionBreakpointProvider():array{
  96. return ['1-9' => [7], '10-26' => [15], '27-40' => [30]];
  97. }
  98. /**
  99. * Tests decoding a data segment from a given BitBuffer
  100. *
  101. * @dataProvider versionBreakpointProvider
  102. */
  103. public function testDecodeSegment(int $version):void{
  104. $options = new QROptions;
  105. $options->version = $version;
  106. // invoke a datamode interface
  107. /** @var \chillerlan\QRCode\Data\QRDataModeInterface $datamodeInterface */
  108. $datamodeInterface = new $this->FQN($this->testdata);
  109. // invoke a QRData instance and write data
  110. $this->QRData = new QRData($options, [$datamodeInterface]);
  111. // get the filled bitbuffer
  112. $bitBuffer = $this->QRData->getBitBuffer();
  113. // read the first 4 bits
  114. $this::assertTrue($bitBuffer->read(4) === $datamodeInterface->getDataMode());
  115. // hanzi mode starts with a subset indicator
  116. if($datamodeInterface instanceof Hanzi){
  117. $this::assertTrue($bitBuffer->read(4) === Hanzi::GB2312_SUBSET);
  118. }
  119. // decode the data
  120. /** @noinspection PhpUndefinedMethodInspection */
  121. $this::assertSame($this->testdata, $this->FQN::decodeSegment($bitBuffer, $options->version));
  122. }
  123. /**
  124. * Tests if an exception is thrown when the data exceeds the maximum version while auto detecting
  125. */
  126. public function testGetMinimumVersionException():void{
  127. $this->expectException(QRCodeDataException::class);
  128. $this->expectExceptionMessage('data exceeds');
  129. $this->QRData->setData([new $this->FQN(str_repeat($this->testdata, 1337))]);
  130. }
  131. /**
  132. * Tests if an exception is thrown on data overflow
  133. */
  134. public function testCodeLengthOverflowException():void{
  135. $this->expectException(QRCodeDataException::class);
  136. $this->expectExceptionMessage('code length overflow');
  137. $this->QRData = new QRData(
  138. new QROptions(['version' => 4]),
  139. [new $this->FQN(str_repeat($this->testdata, 1337))]
  140. );
  141. }
  142. /**
  143. * Tests if an exception is thrown when an invalid character is encountered
  144. */
  145. public function testInvalidDataException():void{
  146. $this->expectException(QRCodeDataException::class);
  147. $this->expectExceptionMessage('invalid data');
  148. /** @phan-suppress-next-line PhanNoopNew */
  149. new $this->FQN('##');
  150. }
  151. /**
  152. * Tests if an exception is thrown if the given string is empty
  153. */
  154. public function testInvalidDataOnEmptyException():void{
  155. $this->expectException(QRCodeDataException::class);
  156. $this->expectExceptionMessage('invalid data');
  157. /** @phan-suppress-next-line PhanNoopNew */
  158. new $this->FQN('');
  159. }
  160. }