Added test cases for C function appendErrorCorrection().
This commit is contained in:
parent
d11707d06a
commit
a712ccc230
|
@ -43,8 +43,11 @@ static int numTestCases = 0;
|
||||||
|
|
||||||
|
|
||||||
// Prototypes of private functions under test
|
// Prototypes of private functions under test
|
||||||
|
extern const int8_t ECC_CODEWORDS_PER_BLOCK[4][41];
|
||||||
|
extern const int8_t NUM_ERROR_CORRECTION_BLOCKS[4][41];
|
||||||
int getTextProperties(const char *text, bool *isNumeric, bool *isAlphanumeric, int *textBits);
|
int getTextProperties(const char *text, bool *isNumeric, bool *isAlphanumeric, int *textBits);
|
||||||
void appendBitsToBuffer(unsigned int val, int numBits, uint8_t buffer[], int *bitLen);
|
void appendBitsToBuffer(unsigned int val, int numBits, uint8_t buffer[], int *bitLen);
|
||||||
|
void appendErrorCorrection(uint8_t data[], int version, enum qrcodegen_Ecc ecl, uint8_t result[]);
|
||||||
int getNumDataCodewords(int version, enum qrcodegen_Ecc ecl);
|
int getNumDataCodewords(int version, enum qrcodegen_Ecc ecl);
|
||||||
int getNumRawDataModules(int version);
|
int getNumRawDataModules(int version);
|
||||||
void calcReedSolomonGenerator(int degree, uint8_t result[]);
|
void calcReedSolomonGenerator(int degree, uint8_t result[]);
|
||||||
|
@ -158,6 +161,73 @@ static void testAppendBitsToBuffer(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Ported from the Java version of the code.
|
||||||
|
static uint8_t *appendErrorCorrectionReference(const uint8_t *data, int version, enum qrcodegen_Ecc ecl) {
|
||||||
|
// Calculate parameter numbers
|
||||||
|
int numBlocks = NUM_ERROR_CORRECTION_BLOCKS[(int)ecl][version];
|
||||||
|
int blockEccLen = ECC_CODEWORDS_PER_BLOCK[(int)ecl][version];
|
||||||
|
int rawCodewords = getNumRawDataModules(version) / 8;
|
||||||
|
int numShortBlocks = numBlocks - rawCodewords % numBlocks;
|
||||||
|
int shortBlockLen = rawCodewords / numBlocks;
|
||||||
|
|
||||||
|
// Split data into blocks and append ECC to each block
|
||||||
|
uint8_t **blocks = malloc(numBlocks * sizeof(uint8_t*));
|
||||||
|
uint8_t *generator = malloc(blockEccLen * sizeof(uint8_t));
|
||||||
|
calcReedSolomonGenerator(blockEccLen, generator);
|
||||||
|
for (int i = 0, k = 0; i < numBlocks; i++) {
|
||||||
|
uint8_t *block = malloc((shortBlockLen + 1) * sizeof(uint8_t));
|
||||||
|
int blockDataLen = shortBlockLen - blockEccLen + (i < numShortBlocks ? 0 : 1);
|
||||||
|
memcpy(block, &data[k], blockDataLen * sizeof(uint8_t));
|
||||||
|
calcReedSolomonRemainder(&data[k], blockDataLen, generator, blockEccLen, &block[shortBlockLen + 1 - blockEccLen]);
|
||||||
|
k += blockDataLen;
|
||||||
|
blocks[i] = block;
|
||||||
|
}
|
||||||
|
free(generator);
|
||||||
|
|
||||||
|
// Interleave (not concatenate) the bytes from every block into a single sequence
|
||||||
|
uint8_t *result = malloc(rawCodewords * sizeof(uint8_t));
|
||||||
|
for (int i = 0, k = 0; i < shortBlockLen + 1; i++) {
|
||||||
|
for (int j = 0; j < numBlocks; j++) {
|
||||||
|
// Skip the padding byte in short blocks
|
||||||
|
if (i != shortBlockLen - blockEccLen || j >= numShortBlocks) {
|
||||||
|
result[k] = blocks[j][i];
|
||||||
|
k++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; i < numBlocks; i++)
|
||||||
|
free(blocks[i]);
|
||||||
|
free(blocks);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void testAppendErrorCorrection(void) {
|
||||||
|
for (int version = 1; version <= 40; version++) {
|
||||||
|
for (int ecl = 0; ecl < 4; ecl++) {
|
||||||
|
int dataLen = getNumDataCodewords(version, (enum qrcodegen_Ecc)ecl);
|
||||||
|
uint8_t *pureData = malloc(dataLen * sizeof(uint8_t));
|
||||||
|
for (int i = 0; i < dataLen; i++)
|
||||||
|
pureData[i] = rand() % 256;
|
||||||
|
uint8_t *expectOutput = appendErrorCorrectionReference(pureData, version, (enum qrcodegen_Ecc)ecl);
|
||||||
|
|
||||||
|
int dataAndEccLen = getNumRawDataModules(version) / 8;
|
||||||
|
uint8_t *paddedData = malloc(dataAndEccLen * sizeof(uint8_t));
|
||||||
|
memcpy(paddedData, pureData, dataLen * sizeof(uint8_t));
|
||||||
|
uint8_t *actualOutput = malloc(dataAndEccLen * sizeof(uint8_t));
|
||||||
|
appendErrorCorrection(paddedData, version, (enum qrcodegen_Ecc)ecl, actualOutput);
|
||||||
|
|
||||||
|
assert(memcmp(actualOutput, expectOutput, dataAndEccLen * sizeof(uint8_t)) == 0);
|
||||||
|
free(pureData);
|
||||||
|
free(expectOutput);
|
||||||
|
free(paddedData);
|
||||||
|
free(actualOutput);
|
||||||
|
numTestCases++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void testGetNumDataCodewords(void) {
|
static void testGetNumDataCodewords(void) {
|
||||||
int cases[][3] = {
|
int cases[][3] = {
|
||||||
{ 3, 1, 44},
|
{ 3, 1, 44},
|
||||||
|
@ -492,6 +562,7 @@ int main(void) {
|
||||||
srand(time(NULL));
|
srand(time(NULL));
|
||||||
testGetTextProperties();
|
testGetTextProperties();
|
||||||
testAppendBitsToBuffer();
|
testAppendBitsToBuffer();
|
||||||
|
testAppendErrorCorrection();
|
||||||
testGetNumDataCodewords();
|
testGetNumDataCodewords();
|
||||||
testGetNumRawDataModules();
|
testGetNumRawDataModules();
|
||||||
testCalcReedSolomonGenerator();
|
testCalcReedSolomonGenerator();
|
||||||
|
|
|
@ -60,7 +60,7 @@ static void encodeQrCodeTail(uint8_t dataAndQrcode[], int bitLen, uint8_t tempBu
|
||||||
int version, enum qrcodegen_Ecc ecl, enum qrcodegen_Mask mask, bool boostEcl);
|
int version, enum qrcodegen_Ecc ecl, enum qrcodegen_Mask mask, bool boostEcl);
|
||||||
testable void appendBitsToBuffer(unsigned int val, int numBits, uint8_t buffer[], int *bitLen);
|
testable void appendBitsToBuffer(unsigned int val, int numBits, uint8_t buffer[], int *bitLen);
|
||||||
|
|
||||||
static void appendErrorCorrection(uint8_t data[], int version, enum qrcodegen_Ecc ecl, uint8_t result[]);
|
testable void appendErrorCorrection(uint8_t data[], int version, enum qrcodegen_Ecc ecl, uint8_t result[]);
|
||||||
testable int getNumDataCodewords(int version, enum qrcodegen_Ecc ecl);
|
testable int getNumDataCodewords(int version, enum qrcodegen_Ecc ecl);
|
||||||
testable int getNumRawDataModules(int version);
|
testable int getNumRawDataModules(int version);
|
||||||
|
|
||||||
|
@ -90,7 +90,7 @@ testable void setModuleBounded(uint8_t qrcode[], int x, int y, bool isBlack);
|
||||||
static const char *ALPHANUMERIC_CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:";
|
static const char *ALPHANUMERIC_CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:";
|
||||||
|
|
||||||
// For generating error correction codes.
|
// For generating error correction codes.
|
||||||
static const int8_t ECC_CODEWORDS_PER_BLOCK[4][41] = {
|
testable const int8_t ECC_CODEWORDS_PER_BLOCK[4][41] = {
|
||||||
// Version: (note that index 0 is for padding, and is set to an illegal value)
|
// Version: (note that index 0 is for padding, and is set to an illegal value)
|
||||||
//0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level
|
//0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level
|
||||||
{-1, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28, 28, 28, 28, 30, 30, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // Low
|
{-1, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28, 28, 28, 28, 30, 30, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // Low
|
||||||
|
@ -100,7 +100,7 @@ static const int8_t ECC_CODEWORDS_PER_BLOCK[4][41] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
// For generating error correction codes.
|
// For generating error correction codes.
|
||||||
const int8_t NUM_ERROR_CORRECTION_BLOCKS[4][41] = {
|
testable const int8_t NUM_ERROR_CORRECTION_BLOCKS[4][41] = {
|
||||||
// Version: (note that index 0 is for padding, and is set to an illegal value)
|
// Version: (note that index 0 is for padding, and is set to an illegal value)
|
||||||
//0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level
|
//0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level
|
||||||
{-1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25}, // Low
|
{-1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25}, // Low
|
||||||
|
@ -356,7 +356,7 @@ testable void appendBitsToBuffer(unsigned int val, int numBits, uint8_t buffer[]
|
||||||
// from the blocks and stores them in the result array. data[0 : rawCodewords - totalEcc] contains
|
// from the blocks and stores them in the result array. data[0 : rawCodewords - totalEcc] contains
|
||||||
// the input data. data[rawCodewords - totalEcc : rawCodewords] is used as a temporary work area
|
// the input data. data[rawCodewords - totalEcc : rawCodewords] is used as a temporary work area
|
||||||
// and will be clobbered by this function. The final answer is stored in result[0 : rawCodewords].
|
// and will be clobbered by this function. The final answer is stored in result[0 : rawCodewords].
|
||||||
static void appendErrorCorrection(uint8_t data[], int version, enum qrcodegen_Ecc ecl, uint8_t result[]) {
|
testable void appendErrorCorrection(uint8_t data[], int version, enum qrcodegen_Ecc ecl, uint8_t result[]) {
|
||||||
// Calculate parameter numbers
|
// Calculate parameter numbers
|
||||||
assert(0 <= (int)ecl && (int)ecl < 4 && qrcodegen_VERSION_MIN <= version && version <= qrcodegen_VERSION_MAX);
|
assert(0 <= (int)ecl && (int)ecl < 4 && qrcodegen_VERSION_MIN <= version && version <= qrcodegen_VERSION_MAX);
|
||||||
int numBlocks = NUM_ERROR_CORRECTION_BLOCKS[(int)ecl][version];
|
int numBlocks = NUM_ERROR_CORRECTION_BLOCKS[(int)ecl][version];
|
||||||
|
|
Loading…
Reference in New Issue