Added simple test program and suite of cases for C library.

pull/11/head
Project Nayuki 8 years ago
parent e1596c3b07
commit 822c339b4e

@ -0,0 +1,148 @@
/*
* QR Code generator test suite (C)
*
* Compile with QRCODEGEN_TEST defined. Run this command line program with no arguments.
*
* Copyright (c) Project Nayuki
* https://www.nayuki.io/page/qr-code-generator-library
*
* (MIT License)
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
* - The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* - The Software is provided "as is", without warranty of any kind, express or
* implied, including but not limited to the warranties of merchantability,
* fitness for a particular purpose and noninfringement. In no event shall the
* authors or copyright holders be liable for any claim, damages or other
* liability, whether in an action of contract, tort or otherwise, arising from,
* out of or in connection with the Software or the use or other dealings in the
* Software.
*/
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "qrcodegen.h"
#define ARRAY_LENGTH(name) (sizeof(name) / sizeof(name[0]))
// Global variables
static int numTestCases = 0;
// Prototypes of private functions under test
int getNumDataCodewords(int version, enum qrcodegen_Ecc ecl);
int getNumRawDataModules(int version);
uint8_t finiteFieldMultiply(uint8_t x, uint8_t y);
/*---- Test cases ----*/
static void testGetNumDataCodewords(void) {
int cases[][3] = {
{ 3, 1, 44},
{ 3, 2, 34},
{ 3, 3, 26},
{ 6, 0, 136},
{ 7, 0, 156},
{ 9, 0, 232},
{ 9, 1, 182},
{12, 3, 158},
{15, 0, 523},
{16, 2, 325},
{19, 3, 341},
{21, 0, 932},
{22, 0, 1006},
{22, 1, 782},
{22, 3, 442},
{24, 0, 1174},
{24, 3, 514},
{28, 0, 1531},
{30, 3, 745},
{32, 3, 845},
{33, 0, 2071},
{33, 3, 901},
{35, 0, 2306},
{35, 1, 1812},
{35, 2, 1286},
{36, 3, 1054},
{37, 3, 1096},
{39, 1, 2216},
{40, 1, 2334},
};
for (size_t i = 0; i < ARRAY_LENGTH(cases); i++) {
int *tc = cases[i];
assert(getNumDataCodewords(tc[0], (enum qrcodegen_Ecc)tc[1]) == tc[2]);
numTestCases++;
}
}
static void testGetNumRawDataModules(void) {
int cases[][2] = {
{ 1, 208},
{ 2, 359},
{ 3, 567},
{ 6, 1383},
{ 7, 1568},
{12, 3728},
{15, 5243},
{18, 7211},
{22, 10068},
{26, 13652},
{32, 19723},
{37, 25568},
{40, 29648},
};
for (size_t i = 0; i < ARRAY_LENGTH(cases); i++) {
int *tc = cases[i];
assert(getNumRawDataModules(tc[0]) == tc[1]);
numTestCases++;
}
}
static void testFiniteFieldMultiply(void) {
uint8_t cases[][3] = {
{0x00, 0x00, 0x00},
{0x01, 0x01, 0x01},
{0x02, 0x02, 0x04},
{0x00, 0x6E, 0x00},
{0xB2, 0xDD, 0xE6},
{0x41, 0x11, 0x25},
{0xB0, 0x1F, 0x11},
{0x05, 0x75, 0xBC},
{0x52, 0xB5, 0xAE},
{0xA8, 0x20, 0xA4},
{0x0E, 0x44, 0x9F},
{0xD4, 0x13, 0xA0},
{0x31, 0x10, 0x37},
{0x6C, 0x58, 0xCB},
{0xB6, 0x75, 0x3E},
{0xFF, 0xFF, 0xE2},
};
for (size_t i = 0; i < ARRAY_LENGTH(cases); i++) {
uint8_t *tc = cases[i];
assert(finiteFieldMultiply(tc[0], tc[1]) == tc[2]);
numTestCases++;
}
}
/*---- Main runner ----*/
int main(void) {
testGetNumDataCodewords();
testGetNumRawDataModules();
testFiniteFieldMultiply();
printf("All %d test cases passed\n", numTestCases);
return EXIT_SUCCESS;
}

@ -28,6 +28,12 @@
#include <string.h> #include <string.h>
#include "qrcodegen.h" #include "qrcodegen.h"
#ifdef QRCODEGEN_TEST
#define testable // Expose private functions
#else
#define testable static // Keep functions private
#endif
/*---- Forward declarations for private functions ----*/ /*---- Forward declarations for private functions ----*/
@ -43,12 +49,12 @@ static void encodeQrCodeTail(uint8_t dataAndQrcode[], int bitLen, uint8_t tempBu
static void appendBitsToBuffer(unsigned int val, int numBits, uint8_t buffer[], int *bitLen); static 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[]); static void appendErrorCorrection(uint8_t data[], int version, enum qrcodegen_Ecc ecl, uint8_t result[]);
static int getNumDataCodewords(int version, enum qrcodegen_Ecc ecl); testable int getNumDataCodewords(int version, enum qrcodegen_Ecc ecl);
static int getNumRawDataModules(int version); testable int getNumRawDataModules(int version);
static void calcReedSolomonGenerator(int degree, uint8_t result[]); 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[]); static void calcReedSolomonRemainder(const uint8_t data[], int dataLen, const uint8_t generator[], int degree, uint8_t result[]);
static uint8_t finiteFieldMultiply(uint8_t x, uint8_t y); testable uint8_t finiteFieldMultiply(uint8_t x, uint8_t y);
static void initializeFunctionModules(int version, uint8_t qrcode[]); static void initializeFunctionModules(int version, uint8_t qrcode[]);
static void drawWhiteFunctionModules(uint8_t qrcode[], int version); static void drawWhiteFunctionModules(uint8_t qrcode[], int version);
@ -369,7 +375,7 @@ static void appendErrorCorrection(uint8_t data[], int version, enum qrcodegen_Ec
// Returns the number of 8-bit codewords that can be used for storing data (not ECC), // Returns the number of 8-bit codewords that can be used for storing data (not ECC),
// for the given version number and error correction level. The result is in the range [9, 2956]. // for the given version number and error correction level. The result is in the range [9, 2956].
static int getNumDataCodewords(int version, enum qrcodegen_Ecc ecl) { testable int getNumDataCodewords(int version, enum qrcodegen_Ecc ecl) {
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);
return getNumRawDataModules(version) / 8 - ECC_CODEWORDS_PER_BLOCK[(int)ecl][version] * NUM_ERROR_CORRECTION_BLOCKS[(int)ecl][version]; return getNumRawDataModules(version) / 8 - ECC_CODEWORDS_PER_BLOCK[(int)ecl][version] * NUM_ERROR_CORRECTION_BLOCKS[(int)ecl][version];
} }
@ -378,7 +384,7 @@ static int getNumDataCodewords(int version, enum qrcodegen_Ecc ecl) {
// Returns the number of data bits that can be stored in a QR Code of the given version number, after // Returns the number of data bits that can be stored in a QR Code of the given version number, after
// all function modules are excluded. This includes remainder bits, so it might not be a multiple of 8. // all function modules are excluded. This includes remainder bits, so it might not be a multiple of 8.
// The result is in the range [208, 29648]. // The result is in the range [208, 29648].
static int getNumRawDataModules(int version) { testable int getNumRawDataModules(int version) {
assert(qrcodegen_VERSION_MIN <= version && version <= qrcodegen_VERSION_MAX); assert(qrcodegen_VERSION_MIN <= version && version <= qrcodegen_VERSION_MAX);
int result = (16 * version + 128) * version + 64; int result = (16 * version + 128) * version + 64;
if (version >= 2) { if (version >= 2) {
@ -434,7 +440,7 @@ static void calcReedSolomonRemainder(const uint8_t data[], int dataLen, const ui
// Returns the product of the two given field elements modulo GF(2^8/0x11D). All argument values are valid. // Returns the product of the two given field elements modulo GF(2^8/0x11D). All argument values are valid.
static uint8_t finiteFieldMultiply(uint8_t x, uint8_t y) { testable uint8_t finiteFieldMultiply(uint8_t x, uint8_t y) {
// Russian peasant multiplication // Russian peasant multiplication
uint8_t z = 0; uint8_t z = 0;
for (int i = 7; i >= 0; i--) { for (int i = 7; i >= 0; i--) {

Loading…
Cancel
Save