Added C test cases for 5 functions.
This commit is contained in:
parent
822c339b4e
commit
9b57973245
|
@ -26,9 +26,11 @@
|
|||
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "qrcodegen.h"
|
||||
|
||||
#define ARRAY_LENGTH(name) (sizeof(name) / sizeof(name[0]))
|
||||
|
@ -39,13 +41,91 @@ static int numTestCases = 0;
|
|||
|
||||
|
||||
// Prototypes of private functions under test
|
||||
int getTextProperties(const char *text, bool *isNumeric, bool *isAlphanumeric, int *textBits);
|
||||
int getNumDataCodewords(int version, enum qrcodegen_Ecc ecl);
|
||||
int getNumRawDataModules(int version);
|
||||
void calcReedSolomonGenerator(int degree, uint8_t result[]);
|
||||
void calcReedSolomonRemainder(const uint8_t data[], int dataLen, const uint8_t generator[], int degree, uint8_t result[]);
|
||||
uint8_t finiteFieldMultiply(uint8_t x, uint8_t y);
|
||||
int getAlignmentPatternPositions(int version, uint8_t result[7]);
|
||||
|
||||
|
||||
/*---- Test cases ----*/
|
||||
|
||||
static void testSize(void) {
|
||||
int cases[][2] = {
|
||||
{ 1, 21},
|
||||
{ 6, 41},
|
||||
{20, 97},
|
||||
{33, 149},
|
||||
{40, 177},
|
||||
};
|
||||
for (size_t i = 0; i < ARRAY_LENGTH(cases); i++) {
|
||||
int *tc = cases[i];
|
||||
assert(qrcodegen_getSize(tc[0]) == tc[1]);
|
||||
numTestCases++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void testGetTextProperties(void) {
|
||||
bool isNumeric, isAlphanumeric;
|
||||
int textLen, textBits;
|
||||
|
||||
textLen = getTextProperties("", &isNumeric, &isAlphanumeric, &textBits);
|
||||
assert(textLen == 0 && isNumeric && isAlphanumeric && textBits == 0);
|
||||
numTestCases++;
|
||||
|
||||
textLen = getTextProperties("0", &isNumeric, &isAlphanumeric, &textBits);
|
||||
assert(textLen == 1 && isNumeric && isAlphanumeric && textBits == 4);
|
||||
numTestCases++;
|
||||
|
||||
textLen = getTextProperties("768", &isNumeric, &isAlphanumeric, &textBits);
|
||||
assert(textLen == 3 && isNumeric && isAlphanumeric && textBits == 10);
|
||||
numTestCases++;
|
||||
|
||||
textLen = getTextProperties("A1", &isNumeric, &isAlphanumeric, &textBits);
|
||||
assert(textLen == 2 && !isNumeric && isAlphanumeric && textBits == 11);
|
||||
numTestCases++;
|
||||
|
||||
textLen = getTextProperties("THE: QUICK+/*BROWN$FOX.", &isNumeric, &isAlphanumeric, &textBits);
|
||||
assert(textLen == 23 && !isNumeric && isAlphanumeric && textBits == 127);
|
||||
numTestCases++;
|
||||
|
||||
textLen = getTextProperties("aB 9", &isNumeric, &isAlphanumeric, &textBits);
|
||||
assert(textLen == 4 && !isNumeric && !isAlphanumeric && textBits == 32);
|
||||
numTestCases++;
|
||||
|
||||
char text[32769];
|
||||
|
||||
memset(text, '5', sizeof(text));
|
||||
text[32768] = '\0';
|
||||
textLen = getTextProperties(text, &isNumeric, &isAlphanumeric, &textBits);
|
||||
assert(textLen < 0);
|
||||
numTestCases++;
|
||||
|
||||
memset(text, '1', sizeof(text));
|
||||
text[32767] = '\0';
|
||||
textLen = getTextProperties(text, &isNumeric, &isAlphanumeric, &textBits);
|
||||
assert((109224L > INT_MAX && textLen < 0) ||
|
||||
(109224L <= INT_MAX && textLen == 32767 && isNumeric && isAlphanumeric && textBits == 109224L));
|
||||
numTestCases++;
|
||||
|
||||
memset(text, 'a', sizeof(text));
|
||||
text[4095] = '\0';
|
||||
textLen = getTextProperties(text, &isNumeric, &isAlphanumeric, &textBits);
|
||||
assert(textLen == 4095 && !isNumeric && !isAlphanumeric && textBits == 32760);
|
||||
numTestCases++;
|
||||
|
||||
memset(text, 'a', sizeof(text));
|
||||
text[32767] = '\0';
|
||||
textLen = getTextProperties(text, &isNumeric, &isAlphanumeric, &textBits);
|
||||
assert((262136L > INT_MAX && textLen < 0) ||
|
||||
(262136L <= INT_MAX && textLen == 32767 && !isNumeric && !isAlphanumeric && textBits == 262136L));
|
||||
numTestCases++;
|
||||
}
|
||||
|
||||
|
||||
static void testGetNumDataCodewords(void) {
|
||||
int cases[][3] = {
|
||||
{ 3, 1, 44},
|
||||
|
@ -110,6 +190,104 @@ static void testGetNumRawDataModules(void) {
|
|||
}
|
||||
|
||||
|
||||
static void testCalcReedSolomonGenerator(void) {
|
||||
uint8_t generator[30];
|
||||
|
||||
calcReedSolomonGenerator(1, generator);
|
||||
assert(generator[0] == 0x01);
|
||||
numTestCases++;
|
||||
|
||||
calcReedSolomonGenerator(2, generator);
|
||||
assert(generator[0] == 0x03);
|
||||
assert(generator[1] == 0x02);
|
||||
numTestCases++;
|
||||
|
||||
calcReedSolomonGenerator(5, generator);
|
||||
assert(generator[0] == 0x1F);
|
||||
assert(generator[1] == 0xC6);
|
||||
assert(generator[2] == 0x3F);
|
||||
assert(generator[3] == 0x93);
|
||||
assert(generator[4] == 0x74);
|
||||
numTestCases++;
|
||||
|
||||
calcReedSolomonGenerator(30, generator);
|
||||
assert(generator[ 0] == 0xD4);
|
||||
assert(generator[ 1] == 0xF6);
|
||||
assert(generator[ 5] == 0xC0);
|
||||
assert(generator[12] == 0x16);
|
||||
assert(generator[13] == 0xD9);
|
||||
assert(generator[20] == 0x12);
|
||||
assert(generator[27] == 0x6A);
|
||||
assert(generator[29] == 0x96);
|
||||
numTestCases++;
|
||||
}
|
||||
|
||||
|
||||
static void testCalcReedSolomonRemainder(void) {
|
||||
{
|
||||
uint8_t data[1];
|
||||
uint8_t generator[3];
|
||||
uint8_t remainder[ARRAY_LENGTH(generator)];
|
||||
calcReedSolomonGenerator(ARRAY_LENGTH(generator), generator);
|
||||
calcReedSolomonRemainder(data, 0, generator, ARRAY_LENGTH(generator), remainder);
|
||||
assert(remainder[0] == 0);
|
||||
assert(remainder[1] == 0);
|
||||
assert(remainder[2] == 0);
|
||||
numTestCases++;
|
||||
}
|
||||
{
|
||||
uint8_t data[2] = {0, 1};
|
||||
uint8_t generator[4];
|
||||
uint8_t remainder[ARRAY_LENGTH(generator)];
|
||||
calcReedSolomonGenerator(ARRAY_LENGTH(generator), generator);
|
||||
calcReedSolomonRemainder(data, ARRAY_LENGTH(data), generator, ARRAY_LENGTH(generator), remainder);
|
||||
assert(remainder[0] == generator[0]);
|
||||
assert(remainder[1] == generator[1]);
|
||||
assert(remainder[2] == generator[2]);
|
||||
assert(remainder[3] == generator[3]);
|
||||
numTestCases++;
|
||||
}
|
||||
{
|
||||
uint8_t data[5] = {0x03, 0x3A, 0x60, 0x12, 0xC7};
|
||||
uint8_t generator[5];
|
||||
uint8_t remainder[ARRAY_LENGTH(generator)];
|
||||
calcReedSolomonGenerator(ARRAY_LENGTH(generator), generator);
|
||||
calcReedSolomonRemainder(data, ARRAY_LENGTH(data), generator, ARRAY_LENGTH(generator), remainder);
|
||||
assert(remainder[0] == 0xCB);
|
||||
assert(remainder[1] == 0x36);
|
||||
assert(remainder[2] == 0x16);
|
||||
assert(remainder[3] == 0xFA);
|
||||
assert(remainder[4] == 0x9D);
|
||||
numTestCases++;
|
||||
}
|
||||
{
|
||||
uint8_t data[43] = {
|
||||
0x38, 0x71, 0xDB, 0xF9, 0xD7, 0x28, 0xF6, 0x8E, 0xFE, 0x5E,
|
||||
0xE6, 0x7D, 0x7D, 0xB2, 0xA5, 0x58, 0xBC, 0x28, 0x23, 0x53,
|
||||
0x14, 0xD5, 0x61, 0xC0, 0x20, 0x6C, 0xDE, 0xDE, 0xFC, 0x79,
|
||||
0xB0, 0x8B, 0x78, 0x6B, 0x49, 0xD0, 0x1A, 0xAD, 0xF3, 0xEF,
|
||||
0x52, 0x7D, 0x9A,
|
||||
};
|
||||
uint8_t generator[30];
|
||||
uint8_t remainder[ARRAY_LENGTH(generator)];
|
||||
calcReedSolomonGenerator(ARRAY_LENGTH(generator), generator);
|
||||
calcReedSolomonRemainder(data, ARRAY_LENGTH(data), generator, ARRAY_LENGTH(generator), remainder);
|
||||
assert(remainder[ 0] == 0xCE);
|
||||
assert(remainder[ 1] == 0xF0);
|
||||
assert(remainder[ 2] == 0x31);
|
||||
assert(remainder[ 3] == 0xDE);
|
||||
assert(remainder[ 8] == 0xE1);
|
||||
assert(remainder[12] == 0xCA);
|
||||
assert(remainder[17] == 0xE3);
|
||||
assert(remainder[19] == 0x85);
|
||||
assert(remainder[20] == 0x50);
|
||||
assert(remainder[24] == 0xBE);
|
||||
assert(remainder[29] == 0xB3);
|
||||
numTestCases++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void testFiniteFieldMultiply(void) {
|
||||
uint8_t cases[][3] = {
|
||||
{0x00, 0x00, 0x00},
|
||||
|
@ -137,12 +315,44 @@ static void testFiniteFieldMultiply(void) {
|
|||
}
|
||||
|
||||
|
||||
static void testGetAlignmentPatternPositions(void) {
|
||||
int cases[][9] = {
|
||||
{ 1, 0, -1, -1, -1, -1, -1, -1, -1},
|
||||
{ 2, 2, 6, 18, -1, -1, -1, -1, -1},
|
||||
{ 3, 2, 6, 22, -1, -1, -1, -1, -1},
|
||||
{ 6, 2, 6, 34, -1, -1, -1, -1, -1},
|
||||
{ 7, 3, 6, 22, 38, -1, -1, -1, -1},
|
||||
{ 8, 3, 6, 24, 42, -1, -1, -1, -1},
|
||||
{16, 4, 6, 26, 50, 74, -1, -1, -1},
|
||||
{25, 5, 6, 32, 58, 84, 110, -1, -1},
|
||||
{32, 6, 6, 34, 60, 86, 112, 138, -1},
|
||||
{33, 6, 6, 30, 58, 86, 114, 142, -1},
|
||||
{39, 7, 6, 26, 54, 82, 110, 138, 166},
|
||||
{40, 7, 6, 30, 58, 86, 114, 142, 170},
|
||||
};
|
||||
for (size_t i = 0; i < ARRAY_LENGTH(cases); i++) {
|
||||
int *tc = cases[i];
|
||||
uint8_t pos[7];
|
||||
int num = getAlignmentPatternPositions(tc[0], pos);
|
||||
assert(num == tc[1]);
|
||||
for (int j = 0; j < num; j++)
|
||||
assert(pos[j] == tc[2 + j]);
|
||||
numTestCases++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*---- Main runner ----*/
|
||||
|
||||
int main(void) {
|
||||
testSize();
|
||||
testGetTextProperties();
|
||||
testGetNumDataCodewords();
|
||||
testGetNumRawDataModules();
|
||||
testCalcReedSolomonGenerator();
|
||||
testCalcReedSolomonRemainder();
|
||||
testFiniteFieldMultiply();
|
||||
testGetAlignmentPatternPositions();
|
||||
printf("All %d test cases passed\n", numTestCases);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
// Also, each of these functions allocate only a small constant amount of memory on the stack,
|
||||
// they don't allocate or free anything on the heap, and they are thread-safe.
|
||||
|
||||
static int getTextProperties(const char *text, bool *isNumeric, bool *isAlphanumeric, int *textBits);
|
||||
testable int getTextProperties(const char *text, bool *isNumeric, bool *isAlphanumeric, int *textBits);
|
||||
static int fitVersionToData(int minVersion, int maxVersion, enum qrcodegen_Ecc ecl, int dataLen, int dataBitLen, int ver1To9LenBits, int ver10To26LenBits, int ver27To40LenBits);
|
||||
static void encodeQrCodeTail(uint8_t dataAndQrcode[], int bitLen, uint8_t tempBuffer[], int version, enum qrcodegen_Ecc ecl, enum qrcodegen_Mask mask, bool boostEcl);
|
||||
static void appendBitsToBuffer(unsigned int val, int numBits, uint8_t buffer[], int *bitLen);
|
||||
|
@ -52,14 +52,14 @@ static void appendErrorCorrection(uint8_t data[], int version, enum qrcodegen_Ec
|
|||
testable int getNumDataCodewords(int version, enum qrcodegen_Ecc ecl);
|
||||
testable int getNumRawDataModules(int version);
|
||||
|
||||
static void calcReedSolomonGenerator(int degree, uint8_t result[]);
|
||||
static void calcReedSolomonRemainder(const uint8_t data[], int dataLen, const uint8_t generator[], int degree, uint8_t result[]);
|
||||
testable void calcReedSolomonGenerator(int degree, uint8_t result[]);
|
||||
testable void calcReedSolomonRemainder(const uint8_t data[], int dataLen, const uint8_t generator[], int degree, uint8_t result[]);
|
||||
testable uint8_t finiteFieldMultiply(uint8_t x, uint8_t y);
|
||||
|
||||
static void initializeFunctionModules(int version, uint8_t qrcode[]);
|
||||
static void drawWhiteFunctionModules(uint8_t qrcode[], int version);
|
||||
static void drawFormatBits(enum qrcodegen_Ecc ecl, enum qrcodegen_Mask mask, uint8_t qrcode[], int qrsize);
|
||||
static int getAlignmentPatternPositions(int version, uint8_t result[7]);
|
||||
testable int getAlignmentPatternPositions(int version, uint8_t result[7]);
|
||||
static void fillRectangle(int left, int top, int width, int height, uint8_t qrcode[], int qrsize);
|
||||
|
||||
static void drawCodewords(const uint8_t data[], int dataLen, uint8_t qrcode[], int qrsize);
|
||||
|
@ -207,7 +207,7 @@ int qrcodegen_encodeBinary(uint8_t dataAndTemp[], size_t dataLen, uint8_t qrcode
|
|||
// Returns a negative number if the length would exceed INT16_MAX or textBits would exceed INT_MAX.
|
||||
// Note that INT16_MAX <= 32767 <= INT_MAX and INT16_MAX < 65535 <= SIZE_MAX.
|
||||
// If the return value is negative, then the pointees of output arguments might not be set.
|
||||
static int getTextProperties(const char *text, bool *isNumeric, bool *isAlphanumeric, int *textBits) {
|
||||
testable int getTextProperties(const char *text, bool *isNumeric, bool *isAlphanumeric, int *textBits) {
|
||||
int textLen = 0;
|
||||
*isNumeric = true;
|
||||
*isAlphanumeric = true;
|
||||
|
@ -401,7 +401,7 @@ testable int getNumRawDataModules(int version) {
|
|||
/*---- Reed-Solomon ECC generator functions ----*/
|
||||
|
||||
// Calculates the Reed-Solomon generator polynomial of the given degree, storing in result[0 : degree].
|
||||
static void calcReedSolomonGenerator(int degree, uint8_t result[]) {
|
||||
testable void calcReedSolomonGenerator(int degree, uint8_t result[]) {
|
||||
// Start with the monomial x^0
|
||||
assert(1 <= degree && degree <= 30);
|
||||
memset(result, 0, degree * sizeof(result[0]));
|
||||
|
@ -425,7 +425,7 @@ static void calcReedSolomonGenerator(int degree, uint8_t result[]) {
|
|||
|
||||
// Calculates the remainder of the polynomial data[0 : dataLen] when divided by the generator[0 : degree], where all
|
||||
// polynomials are in big endian and the generator has an implicit leading 1 term, storing the result in result[0 : degree].
|
||||
static void calcReedSolomonRemainder(const uint8_t data[], int dataLen, const uint8_t generator[], int degree, uint8_t result[]) {
|
||||
testable void calcReedSolomonRemainder(const uint8_t data[], int dataLen, const uint8_t generator[], int degree, uint8_t result[]) {
|
||||
// Perform polynomial division
|
||||
assert(1 <= degree && degree <= 30);
|
||||
memset(result, 0, degree * sizeof(result[0]));
|
||||
|
@ -595,7 +595,7 @@ static void drawFormatBits(enum qrcodegen_Ecc ecl, enum qrcodegen_Mask mask, uin
|
|||
|
||||
// Calculates the positions of alignment patterns in ascending order for the given version number,
|
||||
// storing them to the given array and returning an array length in the range [0, 7].
|
||||
static int getAlignmentPatternPositions(int version, uint8_t result[7]) {
|
||||
testable int getAlignmentPatternPositions(int version, uint8_t result[7]) {
|
||||
if (version == 1)
|
||||
return 0;
|
||||
int qrsize = qrcodegen_getSize(version);
|
||||
|
|
Loading…
Reference in New Issue