ReedSolomonCodecTest.php 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. <?php
  2. /**
  3. * BaconQrCode
  4. *
  5. * @link http://github.com/Bacon/BaconQrCode For the canonical source repository
  6. * @copyright 2013 Ben 'DASPRiD' Scholzen
  7. * @license http://opensource.org/licenses/BSD-2-Clause Simplified BSD License
  8. */
  9. namespace BaconQrCode\Common;
  10. use PHPUnit_Framework_TestCase as TestCase;
  11. use SplFixedArray;
  12. class ReedSolomonTest extends TestCase
  13. {
  14. public static function tabProvider()
  15. {
  16. return array(
  17. array(2, 0x7, 1, 1, 1),
  18. array(3, 0xb, 1, 1, 2),
  19. array(4, 0x13, 1, 1, 4),
  20. array(5, 0x25, 1, 1, 6),
  21. array(6, 0x43, 1, 1, 8),
  22. array(7, 0x89, 1, 1, 10),
  23. array(8, 0x11d, 1, 1, 32),
  24. );
  25. }
  26. /**
  27. * @dataProvider tabProvider
  28. * @param integer $symbolSize
  29. * @param integer $generatorPoly
  30. * @param integer $firstRoot
  31. * @param integer $primitive
  32. * @param integer $numRoots
  33. * @return void
  34. */
  35. public function testCodec($symbolSize, $generatorPoly, $firstRoot, $primitive, $numRoots)
  36. {
  37. if (defined('MT_RAND_PHP')) {
  38. mt_srand(0xdeadbeef, MT_RAND_PHP);
  39. } else {
  40. mt_srand(0xdeadbeef);
  41. }
  42. $blockSize = (1 << $symbolSize) - 1;
  43. $dataSize = $blockSize - $numRoots;
  44. $codec = new ReedSolomonCodec($symbolSize, $generatorPoly, $firstRoot, $primitive, $numRoots, 0);
  45. for ($errors = 0; $errors <= $numRoots / 2; $errors++) {
  46. // Load block with random data and encode
  47. $block = SplFixedArray::fromArray(array_fill(0, $blockSize, 0), false);
  48. for ($i = 0; $i < $dataSize; $i++) {
  49. $block[$i] = mt_rand(0, $blockSize);
  50. }
  51. // Make temporary copy
  52. $tBlock = clone $block;
  53. $parity = SplFixedArray::fromArray(array_fill(0, $numRoots, 0), false);
  54. $errorLocations = SplFixedArray::fromArray(array_fill(0, $blockSize, 0), false);
  55. $erasures = array();
  56. // Create parity
  57. $codec->encode($block, $parity);
  58. // Copy parity into test blocks
  59. for ($i = 0; $i < $numRoots; $i++) {
  60. $block[$i + $dataSize] = $parity[$i];
  61. $tBlock[$i + $dataSize] = $parity[$i];
  62. }
  63. // Seed with errors
  64. for ($i = 0; $i < $errors; $i++) {
  65. $errorValue = mt_rand(1, $blockSize);
  66. do {
  67. $errorLocation = mt_rand(0, $blockSize);
  68. } while ($errorLocations[$errorLocation] !== 0);
  69. $errorLocations[$errorLocation] = 1;
  70. if (mt_rand(0, 1)) {
  71. $erasures[] = $errorLocation;
  72. }
  73. $tBlock[$errorLocation] ^= $errorValue;
  74. }
  75. $erasures = SplFixedArray::fromArray($erasures, false);
  76. // Decode the errored block
  77. $foundErrors = $codec->decode($tBlock, $erasures);
  78. if ($errors > 0 && $foundErrors === null) {
  79. $this->assertEquals($block, $tBlock, 'Decoder failed to correct errors');
  80. }
  81. $this->assertEquals($errors, $foundErrors, 'Found errors do not equal expected errors');
  82. for ($i = 0; $i < $foundErrors; $i++) {
  83. if ($errorLocations[$erasures[$i]] === 0) {
  84. $this->fail(sprintf('Decoder indicates error in location %d without error', $erasures[$i]));
  85. }
  86. }
  87. $this->assertEquals($block, $tBlock, 'Decoder did not correct errors');
  88. }
  89. }
  90. }