diff --git a/lib/core/error-correction-code.js b/lib/core/error-correction-code.js index 7a4aeae..5f2fceb 100755 --- a/lib/core/error-correction-code.js +++ b/lib/core/error-correction-code.js @@ -1,135 +1,135 @@ -const ECLevel = require('./error-correction-level') - -const EC_BLOCKS_TABLE = [ -// L M Q H - 1, 1, 1, 1, - 1, 1, 1, 1, - 1, 1, 2, 2, - 1, 2, 2, 4, - 1, 2, 4, 4, - 2, 4, 4, 4, - 2, 4, 6, 5, - 2, 4, 6, 6, - 2, 5, 8, 8, - 4, 5, 8, 8, - 4, 5, 8, 11, - 4, 8, 10, 11, - 4, 9, 12, 16, - 4, 9, 16, 16, - 6, 10, 12, 18, - 6, 10, 17, 16, - 6, 11, 16, 19, - 6, 13, 18, 21, - 7, 14, 21, 25, - 8, 16, 20, 25, - 8, 17, 23, 25, - 9, 17, 23, 34, - 9, 18, 25, 30, - 10, 20, 27, 32, - 12, 21, 29, 35, - 12, 23, 34, 37, - 12, 25, 34, 40, - 13, 26, 35, 42, - 14, 28, 38, 45, - 15, 29, 40, 48, - 16, 31, 43, 51, - 17, 33, 45, 54, - 18, 35, 48, 57, - 19, 37, 51, 60, - 19, 38, 53, 63, - 20, 40, 56, 66, - 21, 43, 59, 70, - 22, 45, 62, 74, - 24, 47, 65, 77, - 25, 49, 68, 81 -] - -const EC_CODEWORDS_TABLE = [ -// L M Q H - 7, 10, 13, 17, - 10, 16, 22, 28, - 15, 26, 36, 44, - 20, 36, 52, 64, - 26, 48, 72, 88, - 36, 64, 96, 112, - 40, 72, 108, 130, - 48, 88, 132, 156, - 60, 110, 160, 192, - 72, 130, 192, 224, - 80, 150, 224, 264, - 96, 176, 260, 308, - 104, 198, 288, 352, - 120, 216, 320, 384, - 132, 240, 360, 432, - 144, 280, 408, 480, - 168, 308, 448, 532, - 180, 338, 504, 588, - 196, 364, 546, 650, - 224, 416, 600, 700, - 224, 442, 644, 750, - 252, 476, 690, 816, - 270, 504, 750, 900, - 300, 560, 810, 960, - 312, 588, 870, 1050, - 336, 644, 952, 1110, - 360, 700, 1020, 1200, - 390, 728, 1050, 1260, - 420, 784, 1140, 1350, - 450, 812, 1200, 1440, - 480, 868, 1290, 1530, - 510, 924, 1350, 1620, - 540, 980, 1440, 1710, - 570, 1036, 1530, 1800, - 570, 1064, 1590, 1890, - 600, 1120, 1680, 1980, - 630, 1204, 1770, 2100, - 660, 1260, 1860, 2220, - 720, 1316, 1950, 2310, - 750, 1372, 2040, 2430 -] - -/** - * Returns the number of error correction block that the QR Code should contain - * for the specified version and error correction level. - * - * @param {Number} version QR Code version - * @param {Number} errorCorrectionLevel Error correction level - * @return {Number} Number of error correction blocks - */ -exports.getBlocksCount = function getBlocksCount (version, errorCorrectionLevel) { - switch (errorCorrectionLevel) { - case ECLevel.L: - return EC_BLOCKS_TABLE[(version - 1) * 4 + 0] - case ECLevel.M: - return EC_BLOCKS_TABLE[(version - 1) * 4 + 1] - case ECLevel.Q: - return EC_BLOCKS_TABLE[(version - 1) * 4 + 2] - case ECLevel.H: - return EC_BLOCKS_TABLE[(version - 1) * 4 + 3] - default: - return undefined - } -} - -/** - * Returns the number of error correction codewords to use for the specified - * version and error correction level. - * - * @param {Number} version QR Code version - * @param {Number} errorCorrectionLevel Error correction level - * @return {Number} Number of error correction codewords - */ -exports.getTotalCodewordsCount = function getTotalCodewordsCount (version, errorCorrectionLevel) { - switch (errorCorrectionLevel) { - case ECLevel.L: - return EC_CODEWORDS_TABLE[(version - 1) * 4 + 0] - case ECLevel.M: - return EC_CODEWORDS_TABLE[(version - 1) * 4 + 1] - case ECLevel.Q: - return EC_CODEWORDS_TABLE[(version - 1) * 4 + 2] - case ECLevel.H: - return EC_CODEWORDS_TABLE[(version - 1) * 4 + 3] - default: - return undefined - } -} +const ECLevel = require('./error-correction-level') + +const EC_BLOCKS_TABLE = [ +// L M Q H + 1, 1, 1, 1, + 1, 1, 1, 1, + 1, 1, 2, 2, + 1, 2, 2, 4, + 1, 2, 4, 4, + 2, 4, 4, 4, + 2, 4, 6, 5, + 2, 4, 6, 6, + 2, 5, 8, 8, + 4, 5, 8, 8, + 4, 5, 8, 11, + 4, 8, 10, 11, + 4, 9, 12, 16, + 4, 9, 16, 16, + 6, 10, 12, 18, + 6, 10, 17, 16, + 6, 11, 16, 19, + 6, 13, 18, 21, + 7, 14, 21, 25, + 8, 16, 20, 25, + 8, 17, 23, 25, + 9, 17, 23, 34, + 9, 18, 25, 30, + 10, 20, 27, 32, + 12, 21, 29, 35, + 12, 23, 34, 37, + 12, 25, 34, 40, + 13, 26, 35, 42, + 14, 28, 38, 45, + 15, 29, 40, 48, + 16, 31, 43, 51, + 17, 33, 45, 54, + 18, 35, 48, 57, + 19, 37, 51, 60, + 19, 38, 53, 63, + 20, 40, 56, 66, + 21, 43, 59, 70, + 22, 45, 62, 74, + 24, 47, 65, 77, + 25, 49, 68, 81 +] + +const EC_CODEWORDS_TABLE = [ +// L M Q H + 7, 10, 13, 17, + 10, 16, 22, 28, + 15, 26, 36, 44, + 20, 36, 52, 64, + 26, 48, 72, 88, + 36, 64, 96, 112, + 40, 72, 108, 130, + 48, 88, 132, 156, + 60, 110, 160, 192, + 72, 130, 192, 224, + 80, 150, 224, 264, + 96, 176, 260, 308, + 104, 198, 288, 352, + 120, 216, 320, 384, + 132, 240, 360, 432, + 144, 280, 408, 480, + 168, 308, 448, 532, + 180, 338, 504, 588, + 196, 364, 546, 650, + 224, 416, 600, 700, + 224, 442, 644, 750, + 252, 476, 690, 816, + 270, 504, 750, 900, + 300, 560, 810, 960, + 312, 588, 870, 1050, + 336, 644, 952, 1110, + 360, 700, 1020, 1200, + 390, 728, 1050, 1260, + 420, 784, 1140, 1350, + 450, 812, 1200, 1440, + 480, 868, 1290, 1530, + 510, 924, 1350, 1620, + 540, 980, 1440, 1710, + 570, 1036, 1530, 1800, + 570, 1064, 1590, 1890, + 600, 1120, 1680, 1980, + 630, 1204, 1770, 2100, + 660, 1260, 1860, 2220, + 720, 1316, 1950, 2310, + 750, 1372, 2040, 2430 +] + +/** + * Returns the number of error correction block that the QR Code should contain + * for the specified version and error correction level. + * + * @param {Number} version QR Code version + * @param {Number} errorCorrectionLevel Error correction level + * @return {Number} Number of error correction blocks + */ +exports.getBlocksCount = function getBlocksCount (version, errorCorrectionLevel) { + switch (errorCorrectionLevel) { + case ECLevel.L: + return EC_BLOCKS_TABLE[(version - 1) * 4 + 0] + case ECLevel.M: + return EC_BLOCKS_TABLE[(version - 1) * 4 + 1] + case ECLevel.Q: + return EC_BLOCKS_TABLE[(version - 1) * 4 + 2] + case ECLevel.H: + return EC_BLOCKS_TABLE[(version - 1) * 4 + 3] + default: + return undefined + } +} + +/** + * Returns the number of error correction codewords to use for the specified + * version and error correction level. + * + * @param {Number} version QR Code version + * @param {Number} errorCorrectionLevel Error correction level + * @return {Number} Number of error correction codewords + */ +exports.getTotalCodewordsCount = function getTotalCodewordsCount (version, errorCorrectionLevel) { + switch (errorCorrectionLevel) { + case ECLevel.L: + return EC_CODEWORDS_TABLE[(version - 1) * 4 + 0] + case ECLevel.M: + return EC_CODEWORDS_TABLE[(version - 1) * 4 + 1] + case ECLevel.Q: + return EC_CODEWORDS_TABLE[(version - 1) * 4 + 2] + case ECLevel.H: + return EC_CODEWORDS_TABLE[(version - 1) * 4 + 3] + default: + return undefined + } +} diff --git a/test/unit/core/mask-pattern.test.js b/test/unit/core/mask-pattern.test.js index 40fc501..32a6fc0 100755 --- a/test/unit/core/mask-pattern.test.js +++ b/test/unit/core/mask-pattern.test.js @@ -1,291 +1,291 @@ -const test = require('tap').test -const BitMatrix = require('core/bit-matrix') -const MaskPattern = require('core/mask-pattern') - -test('Mask pattern - Pattern references', function (t) { - const patternsCount = Object.keys(MaskPattern.Patterns).length - t.equal(patternsCount, 8, 'Should return 8 patterns') - - t.end() -}) - -const expectedPattern000 = [ - 1, 0, 1, 0, 1, 0, - 0, 1, 0, 1, 0, 1, - 1, 0, 1, 0, 1, 0, - 0, 1, 0, 1, 0, 1, - 1, 0, 1, 0, 1, 0, - 0, 1, 0, 1, 0, 1 -] - -const expectedPattern001 = [ - 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0 -] - -const expectedPattern010 = [ - 1, 0, 0, 1, 0, 0, - 1, 0, 0, 1, 0, 0, - 1, 0, 0, 1, 0, 0, - 1, 0, 0, 1, 0, 0, - 1, 0, 0, 1, 0, 0, - 1, 0, 0, 1, 0, 0 -] - -const expectedPattern011 = [ - 1, 0, 0, 1, 0, 0, - 0, 0, 1, 0, 0, 1, - 0, 1, 0, 0, 1, 0, - 1, 0, 0, 1, 0, 0, - 0, 0, 1, 0, 0, 1, - 0, 1, 0, 0, 1, 0 -] - -const expectedPattern100 = [ - 1, 1, 1, 0, 0, 0, - 1, 1, 1, 0, 0, 0, - 0, 0, 0, 1, 1, 1, - 0, 0, 0, 1, 1, 1, - 1, 1, 1, 0, 0, 0, - 1, 1, 1, 0, 0, 0 -] - -const expectedPattern101 = [ - 1, 1, 1, 1, 1, 1, - 1, 0, 0, 0, 0, 0, - 1, 0, 0, 1, 0, 0, - 1, 0, 1, 0, 1, 0, - 1, 0, 0, 1, 0, 0, - 1, 0, 0, 0, 0, 0 -] - -const expectedPattern110 = [ - 1, 1, 1, 1, 1, 1, - 1, 1, 1, 0, 0, 0, - 1, 1, 0, 1, 1, 0, - 1, 0, 1, 0, 1, 0, - 1, 0, 1, 1, 0, 1, - 1, 0, 0, 0, 1, 1 -] - -const expectedPattern111 = [ - 1, 0, 1, 0, 1, 0, - 0, 0, 0, 1, 1, 1, - 1, 0, 0, 0, 1, 1, - 0, 1, 0, 1, 0, 1, - 1, 1, 1, 0, 0, 0, - 0, 1, 1, 1, 0, 0 -] - -test('MaskPattern validity', function (t) { - t.notOk(MaskPattern.isValid(), 'Should return false if no input') - t.notOk(MaskPattern.isValid(''), 'Should return false if value is not a number') - t.notOk(MaskPattern.isValid(-1), 'Should return false if value is not in range') - t.notOk(MaskPattern.isValid(8), 'Should return false if value is not in range') - - t.end() -}) - -test('MaskPattern from value', function (t) { - t.equal(MaskPattern.from(5), 5, 'Should return correct mask pattern from a number') - t.equal(MaskPattern.from('5'), 5, 'Should return correct mask pattern from a string') - t.equal(MaskPattern.from(-1), undefined, 'Should return undefined if value is invalid') - t.equal(MaskPattern.from(null), undefined, 'Should return undefined if value is null') - - t.end() -}) - -test('Mask pattern - Apply mask', function (t) { - const patterns = Object.keys(MaskPattern.Patterns).length - const expectedPatterns = [ - expectedPattern000, expectedPattern001, expectedPattern010, expectedPattern011, - expectedPattern100, expectedPattern101, expectedPattern110, expectedPattern111 - ] - - for (let p = 0; p < patterns; p++) { - const matrix = new BitMatrix(6) - MaskPattern.applyMask(p, matrix) - t.same(matrix.data, new Uint8Array(expectedPatterns[p]), 'Should return correct pattern') - } - - const matrix = new BitMatrix(2) - matrix.set(0, 0, false, true) - matrix.set(0, 1, false, true) - matrix.set(1, 0, false, true) - matrix.set(1, 1, false, true) - MaskPattern.applyMask(0, matrix) - - t.same(matrix.data, new Uint8Array([false, false, false, false]), 'Should leave reserved bit unchanged') - - t.throws(function () { MaskPattern.applyMask(-1, new BitMatrix(1)) }, 'Should throw if pattern is invalid') - - t.end() -}) - -test('Mask pattern - Penalty N1', function (t) { - let matrix = new BitMatrix(11) - matrix.data = [ - 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, - 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, - 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, - 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, - 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, - 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, - 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, - 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1 - ] - - t.equal(MaskPattern.getPenaltyN1(matrix), 59, - 'Should return correct penalty points') - - matrix = new BitMatrix(6) - matrix.data = expectedPattern000 - - t.equal(MaskPattern.getPenaltyN1(matrix), 0, - 'Should return correct penalty points') - - matrix.data = expectedPattern001 - - t.equal(MaskPattern.getPenaltyN1(matrix), 24, - 'Should return correct penalty points') - - matrix.data = expectedPattern010 - - t.equal(MaskPattern.getPenaltyN1(matrix), 24, - 'Should return correct penalty points') - - matrix.data = expectedPattern101 - - t.equal(MaskPattern.getPenaltyN1(matrix), 20, - 'Should return correct penalty points') - - t.end() -}) - -test('Mask pattern - Penalty N2', function (t) { - let matrix = new BitMatrix(8) - matrix.data = [ - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 0, 0, 0, 1, 1, - 0, 1, 1, 1, 0, 0, 1, 1, - 1, 0, 0, 0, 1, 1, 0, 1, - 0, 0, 0, 0, 0, 0, 0, 0, - 1, 0, 1, 1, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 0, 0, 0, - 1, 1, 0, 0, 1, 0, 1, 1 - ] - - t.equal(MaskPattern.getPenaltyN2(matrix), 45, - 'Should return correct penalty points') - - matrix = new BitMatrix(6) - matrix.data = expectedPattern000 - - t.equal(MaskPattern.getPenaltyN2(matrix), 0, - 'Should return correct penalty points') - - matrix.data = expectedPattern010 - - t.equal(MaskPattern.getPenaltyN2(matrix), 30, - 'Should return correct penalty points') - - matrix.data = expectedPattern100 - - t.equal(MaskPattern.getPenaltyN2(matrix), 36, - 'Should return correct penalty points') - - t.end() -}) - -test('Mask pattern - Penalty N3', function (t) { - const matrix = new BitMatrix(11) - matrix.data = [ - 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, - 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, - 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, - 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, - 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, - 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, - 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, - 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, - 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0 - ] - - t.equal(MaskPattern.getPenaltyN3(matrix), 160, - 'Should return correct penalty points') - - matrix.data = [ - 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, - 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, - 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, - 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, - 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, - 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, - 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, - 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, - 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, - 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1 - ] - - t.equal(MaskPattern.getPenaltyN3(matrix), 280, - 'Should return correct penalty points') - - t.end() -}) - -test('Mask pattern - Penalty N4', function (t) { - const matrix = new BitMatrix(10) - matrix.data = new Array(50).fill(1).concat(new Array(50).fill(0)) - - t.equal(MaskPattern.getPenaltyN4(matrix), 0, - 'Should return correct penalty points') - - const matrix2 = new BitMatrix(21) - matrix2.data = new Array(190).fill(1).concat(new Array(251).fill(0)) - - t.equal(MaskPattern.getPenaltyN4(matrix2), 10, - 'Should return correct penalty points') - - const matrix3 = new BitMatrix(10) - matrix3.data = new Array(22).fill(1).concat(new Array(78).fill(0)) - - t.equal(MaskPattern.getPenaltyN4(matrix3), 50, - 'Should return correct penalty points') - - t.end() -}) - -test('Mask pattern - Best mask', function (t) { - const matrix = new BitMatrix(11) - matrix.data = [ - 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, - 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, - 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, - 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, - 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, - 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, - 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, - 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, - 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0 - ] - - const mask = MaskPattern.getBestMask(matrix, function () {}) - t.ok(!isNaN(mask), 'Should return a number') - - t.ok(mask >= 0 && mask < 8, - 'Should return a number in range 0,7') - - t.end() -}) +const test = require('tap').test +const BitMatrix = require('core/bit-matrix') +const MaskPattern = require('core/mask-pattern') + +test('Mask pattern - Pattern references', function (t) { + const patternsCount = Object.keys(MaskPattern.Patterns).length + t.equal(patternsCount, 8, 'Should return 8 patterns') + + t.end() +}) + +const expectedPattern000 = [ + 1, 0, 1, 0, 1, 0, + 0, 1, 0, 1, 0, 1, + 1, 0, 1, 0, 1, 0, + 0, 1, 0, 1, 0, 1, + 1, 0, 1, 0, 1, 0, + 0, 1, 0, 1, 0, 1 +] + +const expectedPattern001 = [ + 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0 +] + +const expectedPattern010 = [ + 1, 0, 0, 1, 0, 0, + 1, 0, 0, 1, 0, 0, + 1, 0, 0, 1, 0, 0, + 1, 0, 0, 1, 0, 0, + 1, 0, 0, 1, 0, 0, + 1, 0, 0, 1, 0, 0 +] + +const expectedPattern011 = [ + 1, 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 1, + 0, 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 1, + 0, 1, 0, 0, 1, 0 +] + +const expectedPattern100 = [ + 1, 1, 1, 0, 0, 0, + 1, 1, 1, 0, 0, 0, + 0, 0, 0, 1, 1, 1, + 0, 0, 0, 1, 1, 1, + 1, 1, 1, 0, 0, 0, + 1, 1, 1, 0, 0, 0 +] + +const expectedPattern101 = [ + 1, 1, 1, 1, 1, 1, + 1, 0, 0, 0, 0, 0, + 1, 0, 0, 1, 0, 0, + 1, 0, 1, 0, 1, 0, + 1, 0, 0, 1, 0, 0, + 1, 0, 0, 0, 0, 0 +] + +const expectedPattern110 = [ + 1, 1, 1, 1, 1, 1, + 1, 1, 1, 0, 0, 0, + 1, 1, 0, 1, 1, 0, + 1, 0, 1, 0, 1, 0, + 1, 0, 1, 1, 0, 1, + 1, 0, 0, 0, 1, 1 +] + +const expectedPattern111 = [ + 1, 0, 1, 0, 1, 0, + 0, 0, 0, 1, 1, 1, + 1, 0, 0, 0, 1, 1, + 0, 1, 0, 1, 0, 1, + 1, 1, 1, 0, 0, 0, + 0, 1, 1, 1, 0, 0 +] + +test('MaskPattern validity', function (t) { + t.notOk(MaskPattern.isValid(), 'Should return false if no input') + t.notOk(MaskPattern.isValid(''), 'Should return false if value is not a number') + t.notOk(MaskPattern.isValid(-1), 'Should return false if value is not in range') + t.notOk(MaskPattern.isValid(8), 'Should return false if value is not in range') + + t.end() +}) + +test('MaskPattern from value', function (t) { + t.equal(MaskPattern.from(5), 5, 'Should return correct mask pattern from a number') + t.equal(MaskPattern.from('5'), 5, 'Should return correct mask pattern from a string') + t.equal(MaskPattern.from(-1), undefined, 'Should return undefined if value is invalid') + t.equal(MaskPattern.from(null), undefined, 'Should return undefined if value is null') + + t.end() +}) + +test('Mask pattern - Apply mask', function (t) { + const patterns = Object.keys(MaskPattern.Patterns).length + const expectedPatterns = [ + expectedPattern000, expectedPattern001, expectedPattern010, expectedPattern011, + expectedPattern100, expectedPattern101, expectedPattern110, expectedPattern111 + ] + + for (let p = 0; p < patterns; p++) { + const matrix = new BitMatrix(6) + MaskPattern.applyMask(p, matrix) + t.same(matrix.data, new Uint8Array(expectedPatterns[p]), 'Should return correct pattern') + } + + const matrix = new BitMatrix(2) + matrix.set(0, 0, false, true) + matrix.set(0, 1, false, true) + matrix.set(1, 0, false, true) + matrix.set(1, 1, false, true) + MaskPattern.applyMask(0, matrix) + + t.same(matrix.data, new Uint8Array([false, false, false, false]), 'Should leave reserved bit unchanged') + + t.throws(function () { MaskPattern.applyMask(-1, new BitMatrix(1)) }, 'Should throw if pattern is invalid') + + t.end() +}) + +test('Mask pattern - Penalty N1', function (t) { + let matrix = new BitMatrix(11) + matrix.data = [ + 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, + 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, + 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, + 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, + 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, + 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, + 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, + 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1 + ] + + t.equal(MaskPattern.getPenaltyN1(matrix), 59, + 'Should return correct penalty points') + + matrix = new BitMatrix(6) + matrix.data = expectedPattern000 + + t.equal(MaskPattern.getPenaltyN1(matrix), 0, + 'Should return correct penalty points') + + matrix.data = expectedPattern001 + + t.equal(MaskPattern.getPenaltyN1(matrix), 24, + 'Should return correct penalty points') + + matrix.data = expectedPattern010 + + t.equal(MaskPattern.getPenaltyN1(matrix), 24, + 'Should return correct penalty points') + + matrix.data = expectedPattern101 + + t.equal(MaskPattern.getPenaltyN1(matrix), 20, + 'Should return correct penalty points') + + t.end() +}) + +test('Mask pattern - Penalty N2', function (t) { + let matrix = new BitMatrix(8) + matrix.data = [ + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 0, 0, 0, 1, 1, + 0, 1, 1, 1, 0, 0, 1, 1, + 1, 0, 0, 0, 1, 1, 0, 1, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 1, 1, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, 0, 0, + 1, 1, 0, 0, 1, 0, 1, 1 + ] + + t.equal(MaskPattern.getPenaltyN2(matrix), 45, + 'Should return correct penalty points') + + matrix = new BitMatrix(6) + matrix.data = expectedPattern000 + + t.equal(MaskPattern.getPenaltyN2(matrix), 0, + 'Should return correct penalty points') + + matrix.data = expectedPattern010 + + t.equal(MaskPattern.getPenaltyN2(matrix), 30, + 'Should return correct penalty points') + + matrix.data = expectedPattern100 + + t.equal(MaskPattern.getPenaltyN2(matrix), 36, + 'Should return correct penalty points') + + t.end() +}) + +test('Mask pattern - Penalty N3', function (t) { + const matrix = new BitMatrix(11) + matrix.data = [ + 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, + 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, + 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, + 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, + 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, + 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, + 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, + 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, + 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0 + ] + + t.equal(MaskPattern.getPenaltyN3(matrix), 160, + 'Should return correct penalty points') + + matrix.data = [ + 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, + 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, + 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, + 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, + 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, + 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, + 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, + 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, + 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1 + ] + + t.equal(MaskPattern.getPenaltyN3(matrix), 280, + 'Should return correct penalty points') + + t.end() +}) + +test('Mask pattern - Penalty N4', function (t) { + const matrix = new BitMatrix(10) + matrix.data = new Array(50).fill(1).concat(new Array(50).fill(0)) + + t.equal(MaskPattern.getPenaltyN4(matrix), 0, + 'Should return correct penalty points') + + const matrix2 = new BitMatrix(21) + matrix2.data = new Array(190).fill(1).concat(new Array(251).fill(0)) + + t.equal(MaskPattern.getPenaltyN4(matrix2), 10, + 'Should return correct penalty points') + + const matrix3 = new BitMatrix(10) + matrix3.data = new Array(22).fill(1).concat(new Array(78).fill(0)) + + t.equal(MaskPattern.getPenaltyN4(matrix3), 50, + 'Should return correct penalty points') + + t.end() +}) + +test('Mask pattern - Best mask', function (t) { + const matrix = new BitMatrix(11) + matrix.data = [ + 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, + 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, + 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, + 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, + 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, + 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, + 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, + 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, + 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0 + ] + + const mask = MaskPattern.getBestMask(matrix, function () {}) + t.ok(!isNaN(mask), 'Should return a number') + + t.ok(mask >= 0 && mask < 8, + 'Should return a number in range 0,7') + + t.end() +})