• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * QR Code generator test suite (C)
3  *
4  * When compiling this program, the library qrcodegen.c needs QRCODEGEN_TEST
5  * to be defined. Run this command line program with no arguments.
6  *
7  * Copyright (c) Project Nayuki. (MIT License)
8  * https://www.nayuki.io/page/qr-code-generator-library
9  *
10  * Permission is hereby granted, free of charge, to any person obtaining a copy of
11  * this software and associated documentation files (the "Software"), to deal in
12  * the Software without restriction, including without limitation the rights to
13  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
14  * the Software, and to permit persons to whom the Software is furnished to do so,
15  * subject to the following conditions:
16  * - The above copyright notice and this permission notice shall be included in
17  *   all copies or substantial portions of the Software.
18  * - The Software is provided "as is", without warranty of any kind, express or
19  *   implied, including but not limited to the warranties of merchantability,
20  *   fitness for a particular purpose and noninfringement. In no event shall the
21  *   authors or copyright holders be liable for any claim, damages or other
22  *   liability, whether in an action of contract, tort or otherwise, arising from,
23  *   out of or in connection with the Software or the use or other dealings in the
24  *   Software.
25  */
26 
27 #include <assert.h>
28 #include <limits.h>
29 #include <stdbool.h>
30 #include <stddef.h>
31 #include <stdint.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <time.h>
36 #include "qrcodegen.h"
37 
38 #define ARRAY_LENGTH(name)  (sizeof(name) / sizeof(name[0]))
39 
40 
41 // Global variables
42 static int numTestCases = 0;
43 
44 
45 // Prototypes of private functions under test
46 extern const int8_t ECC_CODEWORDS_PER_BLOCK[4][41];
47 extern const int8_t NUM_ERROR_CORRECTION_BLOCKS[4][41];
48 void appendBitsToBuffer(unsigned int val, int numBits, uint8_t buffer[], int *bitLen);
49 void addEccAndInterleave(uint8_t data[], int version, enum qrcodegen_Ecc ecl, uint8_t result[]);
50 int getNumDataCodewords(int version, enum qrcodegen_Ecc ecl);
51 int getNumRawDataModules(int version);
52 void reedSolomonComputeDivisor(int degree, uint8_t result[]);
53 void reedSolomonComputeRemainder(const uint8_t data[], int dataLen, const uint8_t generator[], int degree, uint8_t result[]);
54 uint8_t reedSolomonMultiply(uint8_t x, uint8_t y);
55 void initializeFunctionModules(int version, uint8_t qrcode[]);
56 int getAlignmentPatternPositions(int version, uint8_t result[7]);
57 bool getModule(const uint8_t qrcode[], int x, int y);
58 void setModule(uint8_t qrcode[], int x, int y, bool isDark);
59 void setModuleBounded(uint8_t qrcode[], int x, int y, bool isDark);
60 int calcSegmentBitLength(enum qrcodegen_Mode mode, size_t numChars);
61 int getTotalBits(const struct qrcodegen_Segment segs[], size_t len, int version);
62 
63 
64 /*---- Test cases ----*/
65 
testAppendBitsToBuffer(void)66 static void testAppendBitsToBuffer(void) {
67 	{
68 		uint8_t buf[1] = {0};
69 		int bitLen = 0;
70 		appendBitsToBuffer(0, 0, buf, &bitLen);
71 		assert(bitLen == 0);
72 		assert(buf[0] == 0);
73 		appendBitsToBuffer(1, 1, buf, &bitLen);
74 		assert(bitLen == 1);
75 		assert(buf[0] == 0x80);
76 		appendBitsToBuffer(0, 1, buf, &bitLen);
77 		assert(bitLen == 2);
78 		assert(buf[0] == 0x80);
79 		appendBitsToBuffer(5, 3, buf, &bitLen);
80 		assert(bitLen == 5);
81 		assert(buf[0] == 0xA8);
82 		appendBitsToBuffer(6, 3, buf, &bitLen);
83 		assert(bitLen == 8);
84 		assert(buf[0] == 0xAE);
85 		numTestCases++;
86 	}
87 	{
88 		uint8_t buf[6] = {0};
89 		int bitLen = 0;
90 		appendBitsToBuffer(16942, 16, buf, &bitLen);
91 		assert(bitLen == 16);
92 		assert(buf[0] == 0x42 && buf[1] == 0x2E && buf[2] == 0x00 && buf[3] == 0x00 && buf[4] == 0x00 && buf[5] == 0x00);
93 		appendBitsToBuffer(10, 7, buf, &bitLen);
94 		assert(bitLen == 23);
95 		assert(buf[0] == 0x42 && buf[1] == 0x2E && buf[2] == 0x14 && buf[3] == 0x00 && buf[4] == 0x00 && buf[5] == 0x00);
96 		appendBitsToBuffer(15, 4, buf, &bitLen);
97 		assert(bitLen == 27);
98 		assert(buf[0] == 0x42 && buf[1] == 0x2E && buf[2] == 0x15 && buf[3] == 0xE0 && buf[4] == 0x00 && buf[5] == 0x00);
99 		appendBitsToBuffer(26664, 15, buf, &bitLen);
100 		assert(bitLen == 42);
101 		assert(buf[0] == 0x42 && buf[1] == 0x2E && buf[2] == 0x15 && buf[3] == 0xFA && buf[4] == 0x0A && buf[5] == 0x00);
102 		numTestCases++;
103 	}
104 }
105 
106 
107 // Ported from the Java version of the code.
addEccAndInterleaveReference(const uint8_t * data,int version,enum qrcodegen_Ecc ecl)108 static uint8_t *addEccAndInterleaveReference(const uint8_t *data, int version, enum qrcodegen_Ecc ecl) {
109 	// Calculate parameter numbers
110 	size_t numBlocks = (size_t)NUM_ERROR_CORRECTION_BLOCKS[(int)ecl][version];
111 	size_t blockEccLen = (size_t)ECC_CODEWORDS_PER_BLOCK[(int)ecl][version];
112 	size_t rawCodewords = (size_t)getNumRawDataModules(version) / 8;
113 	size_t numShortBlocks = numBlocks - rawCodewords % numBlocks;
114 	size_t shortBlockLen = rawCodewords / numBlocks;
115 
116 	// Split data into blocks and append ECC to each block
117 	uint8_t **blocks = malloc(numBlocks * sizeof(uint8_t*));
118 	uint8_t *generator = malloc(blockEccLen * sizeof(uint8_t));
119 	reedSolomonComputeDivisor((int)blockEccLen, generator);
120 	for (size_t i = 0, k = 0; i < numBlocks; i++) {
121 		uint8_t *block = malloc((shortBlockLen + 1) * sizeof(uint8_t));
122 		size_t datLen = shortBlockLen - blockEccLen + (i < numShortBlocks ? 0 : 1);
123 		memcpy(block, &data[k], datLen * sizeof(uint8_t));
124 		reedSolomonComputeRemainder(&data[k], (int)datLen, generator, (int)blockEccLen, &block[shortBlockLen + 1 - blockEccLen]);
125 		k += datLen;
126 		blocks[i] = block;
127 	}
128 	free(generator);
129 
130 	// Interleave (not concatenate) the bytes from every block into a single sequence
131 	uint8_t *result = malloc(rawCodewords * sizeof(uint8_t));
132 	for (size_t i = 0, k = 0; i < shortBlockLen + 1; i++) {
133 		for (size_t j = 0; j < numBlocks; j++) {
134 			// Skip the padding byte in short blocks
135 			if (i != shortBlockLen - blockEccLen || j >= numShortBlocks) {
136 				result[k] = blocks[j][i];
137 				k++;
138 			}
139 		}
140 	}
141 	for (size_t i = 0; i < numBlocks; i++)
142 		free(blocks[i]);
143 	free(blocks);
144 	return result;
145 }
146 
147 
testAddEccAndInterleave(void)148 static void testAddEccAndInterleave(void) {
149 	for (int version = 1; version <= 40; version++) {
150 		for (int ecl = 0; ecl < 4; ecl++) {
151 			size_t dataLen = (size_t)getNumDataCodewords(version, (enum qrcodegen_Ecc)ecl);
152 			uint8_t *pureData = malloc(dataLen * sizeof(uint8_t));
153 			for (size_t i = 0; i < dataLen; i++)
154 				pureData[i] = (uint8_t)(rand() % 256);
155 			uint8_t *expectOutput = addEccAndInterleaveReference(pureData, version, (enum qrcodegen_Ecc)ecl);
156 
157 			size_t dataAndEccLen = (size_t)getNumRawDataModules(version) / 8;
158 			uint8_t *paddedData = malloc(dataAndEccLen * sizeof(uint8_t));
159 			memcpy(paddedData, pureData, dataLen * sizeof(uint8_t));
160 			uint8_t *actualOutput = malloc(dataAndEccLen * sizeof(uint8_t));
161 			addEccAndInterleave(paddedData, version, (enum qrcodegen_Ecc)ecl, actualOutput);
162 
163 			assert(memcmp(actualOutput, expectOutput, dataAndEccLen * sizeof(uint8_t)) == 0);
164 			free(pureData);
165 			free(expectOutput);
166 			free(paddedData);
167 			free(actualOutput);
168 			numTestCases++;
169 		}
170 	}
171 }
172 
173 
testGetNumDataCodewords(void)174 static void testGetNumDataCodewords(void) {
175 	const int cases[][3] = {
176 		{ 3, 1,   44},
177 		{ 3, 2,   34},
178 		{ 3, 3,   26},
179 		{ 6, 0,  136},
180 		{ 7, 0,  156},
181 		{ 9, 0,  232},
182 		{ 9, 1,  182},
183 		{12, 3,  158},
184 		{15, 0,  523},
185 		{16, 2,  325},
186 		{19, 3,  341},
187 		{21, 0,  932},
188 		{22, 0, 1006},
189 		{22, 1,  782},
190 		{22, 3,  442},
191 		{24, 0, 1174},
192 		{24, 3,  514},
193 		{28, 0, 1531},
194 		{30, 3,  745},
195 		{32, 3,  845},
196 		{33, 0, 2071},
197 		{33, 3,  901},
198 		{35, 0, 2306},
199 		{35, 1, 1812},
200 		{35, 2, 1286},
201 		{36, 3, 1054},
202 		{37, 3, 1096},
203 		{39, 1, 2216},
204 		{40, 1, 2334},
205 	};
206 	for (size_t i = 0; i < ARRAY_LENGTH(cases); i++) {
207 		const int *tc = cases[i];
208 		assert(getNumDataCodewords(tc[0], (enum qrcodegen_Ecc)tc[1]) == tc[2]);
209 		numTestCases++;
210 	}
211 }
212 
213 
testGetNumRawDataModules(void)214 static void testGetNumRawDataModules(void) {
215 	const int cases[][2] = {
216 		{ 1,   208},
217 		{ 2,   359},
218 		{ 3,   567},
219 		{ 6,  1383},
220 		{ 7,  1568},
221 		{12,  3728},
222 		{15,  5243},
223 		{18,  7211},
224 		{22, 10068},
225 		{26, 13652},
226 		{32, 19723},
227 		{37, 25568},
228 		{40, 29648},
229 	};
230 	for (size_t i = 0; i < ARRAY_LENGTH(cases); i++) {
231 		const int *tc = cases[i];
232 		assert(getNumRawDataModules(tc[0]) == tc[1]);
233 		numTestCases++;
234 	}
235 }
236 
237 
testReedSolomonComputeDivisor(void)238 static void testReedSolomonComputeDivisor(void) {
239 	uint8_t generator[30];
240 
241 	reedSolomonComputeDivisor(1, generator);
242 	assert(generator[0] == 0x01);
243 	numTestCases++;
244 
245 	reedSolomonComputeDivisor(2, generator);
246 	assert(generator[0] == 0x03);
247 	assert(generator[1] == 0x02);
248 	numTestCases++;
249 
250 	reedSolomonComputeDivisor(5, generator);
251 	assert(generator[0] == 0x1F);
252 	assert(generator[1] == 0xC6);
253 	assert(generator[2] == 0x3F);
254 	assert(generator[3] == 0x93);
255 	assert(generator[4] == 0x74);
256 	numTestCases++;
257 
258 	reedSolomonComputeDivisor(30, generator);
259 	assert(generator[ 0] == 0xD4);
260 	assert(generator[ 1] == 0xF6);
261 	assert(generator[ 5] == 0xC0);
262 	assert(generator[12] == 0x16);
263 	assert(generator[13] == 0xD9);
264 	assert(generator[20] == 0x12);
265 	assert(generator[27] == 0x6A);
266 	assert(generator[29] == 0x96);
267 	numTestCases++;
268 }
269 
270 
testReedSolomonComputeRemainder(void)271 static void testReedSolomonComputeRemainder(void) {
272 	{
273 		uint8_t data[1];
274 		uint8_t generator[3];
275 		uint8_t remainder[ARRAY_LENGTH(generator)];
276 		reedSolomonComputeDivisor(ARRAY_LENGTH(generator), generator);
277 		reedSolomonComputeRemainder(data, 0, generator, ARRAY_LENGTH(generator), remainder);
278 		assert(remainder[0] == 0);
279 		assert(remainder[1] == 0);
280 		assert(remainder[2] == 0);
281 		numTestCases++;
282 	}
283 	{
284 		uint8_t data[2] = {0, 1};
285 		uint8_t generator[4];
286 		uint8_t remainder[ARRAY_LENGTH(generator)];
287 		reedSolomonComputeDivisor(ARRAY_LENGTH(generator), generator);
288 		reedSolomonComputeRemainder(data, ARRAY_LENGTH(data), generator, ARRAY_LENGTH(generator), remainder);
289 		assert(remainder[0] == generator[0]);
290 		assert(remainder[1] == generator[1]);
291 		assert(remainder[2] == generator[2]);
292 		assert(remainder[3] == generator[3]);
293 		numTestCases++;
294 	}
295 	{
296 		uint8_t data[5] = {0x03, 0x3A, 0x60, 0x12, 0xC7};
297 		uint8_t generator[5];
298 		uint8_t remainder[ARRAY_LENGTH(generator)];
299 		reedSolomonComputeDivisor(ARRAY_LENGTH(generator), generator);
300 		reedSolomonComputeRemainder(data, ARRAY_LENGTH(data), generator, ARRAY_LENGTH(generator), remainder);
301 		assert(remainder[0] == 0xCB);
302 		assert(remainder[1] == 0x36);
303 		assert(remainder[2] == 0x16);
304 		assert(remainder[3] == 0xFA);
305 		assert(remainder[4] == 0x9D);
306 		numTestCases++;
307 	}
308 	{
309 		uint8_t data[43] = {
310 			0x38, 0x71, 0xDB, 0xF9, 0xD7, 0x28, 0xF6, 0x8E, 0xFE, 0x5E,
311 			0xE6, 0x7D, 0x7D, 0xB2, 0xA5, 0x58, 0xBC, 0x28, 0x23, 0x53,
312 			0x14, 0xD5, 0x61, 0xC0, 0x20, 0x6C, 0xDE, 0xDE, 0xFC, 0x79,
313 			0xB0, 0x8B, 0x78, 0x6B, 0x49, 0xD0, 0x1A, 0xAD, 0xF3, 0xEF,
314 			0x52, 0x7D, 0x9A,
315 		};
316 		uint8_t generator[30];
317 		uint8_t remainder[ARRAY_LENGTH(generator)];
318 		reedSolomonComputeDivisor(ARRAY_LENGTH(generator), generator);
319 		reedSolomonComputeRemainder(data, ARRAY_LENGTH(data), generator, ARRAY_LENGTH(generator), remainder);
320 		assert(remainder[ 0] == 0xCE);
321 		assert(remainder[ 1] == 0xF0);
322 		assert(remainder[ 2] == 0x31);
323 		assert(remainder[ 3] == 0xDE);
324 		assert(remainder[ 8] == 0xE1);
325 		assert(remainder[12] == 0xCA);
326 		assert(remainder[17] == 0xE3);
327 		assert(remainder[19] == 0x85);
328 		assert(remainder[20] == 0x50);
329 		assert(remainder[24] == 0xBE);
330 		assert(remainder[29] == 0xB3);
331 		numTestCases++;
332 	}
333 }
334 
335 
testReedSolomonMultiply(void)336 static void testReedSolomonMultiply(void) {
337 	const uint8_t cases[][3] = {
338 		{0x00, 0x00, 0x00},
339 		{0x01, 0x01, 0x01},
340 		{0x02, 0x02, 0x04},
341 		{0x00, 0x6E, 0x00},
342 		{0xB2, 0xDD, 0xE6},
343 		{0x41, 0x11, 0x25},
344 		{0xB0, 0x1F, 0x11},
345 		{0x05, 0x75, 0xBC},
346 		{0x52, 0xB5, 0xAE},
347 		{0xA8, 0x20, 0xA4},
348 		{0x0E, 0x44, 0x9F},
349 		{0xD4, 0x13, 0xA0},
350 		{0x31, 0x10, 0x37},
351 		{0x6C, 0x58, 0xCB},
352 		{0xB6, 0x75, 0x3E},
353 		{0xFF, 0xFF, 0xE2},
354 	};
355 	for (size_t i = 0; i < ARRAY_LENGTH(cases); i++) {
356 		const uint8_t *tc = cases[i];
357 		assert(reedSolomonMultiply(tc[0], tc[1]) == tc[2]);
358 		numTestCases++;
359 	}
360 }
361 
362 
testInitializeFunctionModulesEtc(void)363 static void testInitializeFunctionModulesEtc(void) {
364 	for (int ver = 1; ver <= 40; ver++) {
365 		uint8_t *qrcode = malloc((size_t)qrcodegen_BUFFER_LEN_FOR_VERSION(ver) * sizeof(uint8_t));
366 		assert(qrcode != NULL);
367 		initializeFunctionModules(ver, qrcode);
368 
369 		int size = qrcodegen_getSize(qrcode);
370 		if (ver == 1)
371 			assert(size == 21);
372 		else if (ver == 40)
373 			assert(size == 177);
374 		else
375 			assert(size == ver * 4 + 17);
376 
377 		bool hasLight = false;
378 		bool hasDark = false;
379 		for (int y = 0; y < size; y++) {
380 			for (int x = 0; x < size; x++) {
381 				bool color = qrcodegen_getModule(qrcode, x, y);
382 				if (color)
383 					hasDark = true;
384 				else
385 					hasLight = true;
386 			}
387 		}
388 		assert(hasLight && hasDark);
389 		free(qrcode);
390 		numTestCases++;
391 	}
392 }
393 
394 
testGetAlignmentPatternPositions(void)395 static void testGetAlignmentPatternPositions(void) {
396 	const int cases[][9] = {
397 		{ 1, 0,  -1,  -1,  -1,  -1,  -1,  -1,  -1},
398 		{ 2, 2,   6,  18,  -1,  -1,  -1,  -1,  -1},
399 		{ 3, 2,   6,  22,  -1,  -1,  -1,  -1,  -1},
400 		{ 6, 2,   6,  34,  -1,  -1,  -1,  -1,  -1},
401 		{ 7, 3,   6,  22,  38,  -1,  -1,  -1,  -1},
402 		{ 8, 3,   6,  24,  42,  -1,  -1,  -1,  -1},
403 		{16, 4,   6,  26,  50,  74,  -1,  -1,  -1},
404 		{25, 5,   6,  32,  58,  84, 110,  -1,  -1},
405 		{32, 6,   6,  34,  60,  86, 112, 138,  -1},
406 		{33, 6,   6,  30,  58,  86, 114, 142,  -1},
407 		{39, 7,   6,  26,  54,  82, 110, 138, 166},
408 		{40, 7,   6,  30,  58,  86, 114, 142, 170},
409 	};
410 	for (size_t i = 0; i < ARRAY_LENGTH(cases); i++) {
411 		const int *tc = cases[i];
412 		uint8_t pos[7];
413 		int num = getAlignmentPatternPositions(tc[0], pos);
414 		assert(num == tc[1]);
415 		for (int j = 0; j < num; j++)
416 			assert(pos[j] == tc[2 + j]);
417 		numTestCases++;
418 	}
419 }
420 
421 
testGetSetModule(void)422 static void testGetSetModule(void) {
423 	uint8_t qrcode[qrcodegen_BUFFER_LEN_FOR_VERSION(23)];
424 	initializeFunctionModules(23, qrcode);
425 	int size = qrcodegen_getSize(qrcode);
426 
427 	for (int y = 0; y < size; y++) {  // Clear all to light
428 		for (int x = 0; x < size; x++)
429 			setModule(qrcode, x, y, false);
430 	}
431 	for (int y = 0; y < size; y++) {  // Check all light
432 		for (int x = 0; x < size; x++)
433 			assert(qrcodegen_getModule(qrcode, x, y) == false);
434 	}
435 	for (int y = 0; y < size; y++) {  // Set all to dark
436 		for (int x = 0; x < size; x++)
437 			setModule(qrcode, x, y, true);
438 	}
439 	for (int y = 0; y < size; y++) {  // Check all dark
440 		for (int x = 0; x < size; x++)
441 			assert(qrcodegen_getModule(qrcode, x, y) == true);
442 	}
443 
444 	// Set some out of bounds modules to light
445 	setModuleBounded(qrcode, -1, -1, false);
446 	setModuleBounded(qrcode, -1, 0, false);
447 	setModuleBounded(qrcode, 0, -1, false);
448 	setModuleBounded(qrcode, size, 5, false);
449 	setModuleBounded(qrcode, 72, size, false);
450 	setModuleBounded(qrcode, size, size, false);
451 	for (int y = 0; y < size; y++) {  // Check all dark
452 		for (int x = 0; x < size; x++)
453 			assert(qrcodegen_getModule(qrcode, x, y) == true);
454 	}
455 
456 	// Set some modules to light
457 	setModule(qrcode, 3, 8, false);
458 	setModule(qrcode, 61, 49, false);
459 	for (int y = 0; y < size; y++) {  // Check most dark
460 		for (int x = 0; x < size; x++) {
461 			bool light = (x == 3 && y == 8) || (x == 61 && y == 49);
462 			assert(qrcodegen_getModule(qrcode, x, y) != light);
463 		}
464 	}
465 	numTestCases++;
466 }
467 
468 
testGetSetModuleRandomly(void)469 static void testGetSetModuleRandomly(void) {
470 	uint8_t qrcode[qrcodegen_BUFFER_LEN_FOR_VERSION(1)];
471 	initializeFunctionModules(1, qrcode);
472 	int size = qrcodegen_getSize(qrcode);
473 
474 	bool modules[21][21];
475 	for (int y = 0; y < size; y++) {
476 		for (int x = 0; x < size; x++)
477 			modules[y][x] = qrcodegen_getModule(qrcode, x, y);
478 	}
479 
480 	long trials = 100000;
481 	for (long i = 0; i < trials; i++) {
482 		int x = rand() % (size * 2) - size / 2;
483 		int y = rand() % (size * 2) - size / 2;
484 		bool isInBounds = 0 <= x && x < size && 0 <= y && y < size;
485 		bool oldColor = isInBounds && modules[y][x];
486 		if (isInBounds)
487 			assert(getModule(qrcode, x, y) == oldColor);
488 		assert(qrcodegen_getModule(qrcode, x, y) == oldColor);
489 
490 		bool newColor = rand() % 2 == 0;
491 		if (isInBounds)
492 			modules[y][x] = newColor;
493 		if (isInBounds && rand() % 2 == 0)
494 			setModule(qrcode, x, y, newColor);
495 		else
496 			setModuleBounded(qrcode, x, y, newColor);
497 	}
498 	numTestCases++;
499 }
500 
501 
testIsAlphanumeric(void)502 static void testIsAlphanumeric(void) {
503 	struct TestCase {
504 		bool answer;
505 		const char *text;
506 	};
507 	const struct TestCase cases[] = {
508 		{true, ""},
509 		{true, "0"},
510 		{true, "A"},
511 		{false, "a"},
512 		{true, " "},
513 		{true, "."},
514 		{true, "*"},
515 		{false, ","},
516 		{false, "|"},
517 		{false, "@"},
518 		{true, "XYZ"},
519 		{false, "XYZ!"},
520 		{true, "79068"},
521 		{true, "+123 ABC$"},
522 		{false, "\x01"},
523 		{false, "\x7F"},
524 		{false, "\x80"},
525 		{false, "\xC0"},
526 		{false, "\xFF"},
527 	};
528 	for (size_t i = 0; i < ARRAY_LENGTH(cases); i++) {
529 		assert(qrcodegen_isAlphanumeric(cases[i].text) == cases[i].answer);
530 		numTestCases++;
531 	}
532 }
533 
534 
testIsNumeric(void)535 static void testIsNumeric(void) {
536 	struct TestCase {
537 		bool answer;
538 		const char *text;
539 	};
540 	const struct TestCase cases[] = {
541 		{true, ""},
542 		{true, "0"},
543 		{false, "A"},
544 		{false, "a"},
545 		{false, " "},
546 		{false, "."},
547 		{false, "*"},
548 		{false, ","},
549 		{false, "|"},
550 		{false, "@"},
551 		{false, "XYZ"},
552 		{false, "XYZ!"},
553 		{true, "79068"},
554 		{false, "+123 ABC$"},
555 		{false, "\x01"},
556 		{false, "\x7F"},
557 		{false, "\x80"},
558 		{false, "\xC0"},
559 		{false, "\xFF"},
560 	};
561 	for (size_t i = 0; i < ARRAY_LENGTH(cases); i++) {
562 		assert(qrcodegen_isNumeric(cases[i].text) == cases[i].answer);
563 		numTestCases++;
564 	}
565 }
566 
567 
testCalcSegmentBufferSize(void)568 static void testCalcSegmentBufferSize(void) {
569 	{
570 		const size_t cases[][2] = {
571 			{0, 0},
572 			{1, 1},
573 			{2, 1},
574 			{3, 2},
575 			{4, 2},
576 			{5, 3},
577 			{6, 3},
578 			{1472, 614},
579 			{2097, 874},
580 			{5326, 2220},
581 			{9828, 4095},
582 			{9829, 4096},
583 			{9830, 4096},
584 			{9831, SIZE_MAX},
585 			{9832, SIZE_MAX},
586 			{12000, SIZE_MAX},
587 			{28453, SIZE_MAX},
588 			{55555, SIZE_MAX},
589 			{SIZE_MAX / 6, SIZE_MAX},
590 			{SIZE_MAX / 4, SIZE_MAX},
591 			{SIZE_MAX / 2, SIZE_MAX},
592 			{SIZE_MAX / 1, SIZE_MAX},
593 		};
594 		for (size_t i = 0; i < ARRAY_LENGTH(cases); i++) {
595 			assert(qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_NUMERIC, cases[i][0]) == cases[i][1]);
596 			numTestCases++;
597 		}
598 	}
599 	{
600 		const size_t cases[][2] = {
601 			{0, 0},
602 			{1, 1},
603 			{2, 2},
604 			{3, 3},
605 			{4, 3},
606 			{5, 4},
607 			{6, 5},
608 			{1472, 1012},
609 			{2097, 1442},
610 			{5326, 3662},
611 			{5955, 4095},
612 			{5956, 4095},
613 			{5957, 4096},
614 			{5958, SIZE_MAX},
615 			{5959, SIZE_MAX},
616 			{12000, SIZE_MAX},
617 			{28453, SIZE_MAX},
618 			{55555, SIZE_MAX},
619 			{SIZE_MAX / 10, SIZE_MAX},
620 			{SIZE_MAX / 8, SIZE_MAX},
621 			{SIZE_MAX / 5, SIZE_MAX},
622 			{SIZE_MAX / 2, SIZE_MAX},
623 			{SIZE_MAX / 1, SIZE_MAX},
624 		};
625 		for (size_t i = 0; i < ARRAY_LENGTH(cases); i++) {
626 			assert(qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_ALPHANUMERIC, cases[i][0]) == cases[i][1]);
627 			numTestCases++;
628 		}
629 	}
630 	{
631 		const size_t cases[][2] = {
632 			{0, 0},
633 			{1, 1},
634 			{2, 2},
635 			{3, 3},
636 			{1472, 1472},
637 			{2097, 2097},
638 			{4094, 4094},
639 			{4095, 4095},
640 			{4096, SIZE_MAX},
641 			{4097, SIZE_MAX},
642 			{5957, SIZE_MAX},
643 			{12000, SIZE_MAX},
644 			{28453, SIZE_MAX},
645 			{55555, SIZE_MAX},
646 			{SIZE_MAX / 16 + 1, SIZE_MAX},
647 			{SIZE_MAX / 14, SIZE_MAX},
648 			{SIZE_MAX / 9, SIZE_MAX},
649 			{SIZE_MAX / 7, SIZE_MAX},
650 			{SIZE_MAX / 4, SIZE_MAX},
651 			{SIZE_MAX / 3, SIZE_MAX},
652 			{SIZE_MAX / 2, SIZE_MAX},
653 			{SIZE_MAX / 1, SIZE_MAX},
654 		};
655 		for (size_t i = 0; i < ARRAY_LENGTH(cases); i++) {
656 			assert(qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_BYTE, cases[i][0]) == cases[i][1]);
657 			numTestCases++;
658 		}
659 	}
660 	{
661 		const size_t cases[][2] = {
662 			{0, 0},
663 			{1, 2},
664 			{2, 4},
665 			{3, 5},
666 			{1472, 2392},
667 			{2097, 3408},
668 			{2519, 4094},
669 			{2520, 4095},
670 			{2521, SIZE_MAX},
671 			{5957, SIZE_MAX},
672 			{2522, SIZE_MAX},
673 			{12000, SIZE_MAX},
674 			{28453, SIZE_MAX},
675 			{55555, SIZE_MAX},
676 			{SIZE_MAX / 13 + 1, SIZE_MAX},
677 			{SIZE_MAX / 12, SIZE_MAX},
678 			{SIZE_MAX / 9, SIZE_MAX},
679 			{SIZE_MAX / 4, SIZE_MAX},
680 			{SIZE_MAX / 3, SIZE_MAX},
681 			{SIZE_MAX / 2, SIZE_MAX},
682 			{SIZE_MAX / 1, SIZE_MAX},
683 		};
684 		for (size_t i = 0; i < ARRAY_LENGTH(cases); i++) {
685 			assert(qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_KANJI, cases[i][0]) == cases[i][1]);
686 			numTestCases++;
687 		}
688 	}
689 	{
690 		assert(qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_ECI, 0) == 3);
691 		numTestCases++;
692 	}
693 }
694 
695 
testCalcSegmentBitLength(void)696 static void testCalcSegmentBitLength(void) {
697 	struct TestCase {
698 		size_t numChars;
699 		int result;
700 	};
701 	{
702 		const struct TestCase CASES[] = {
703 			{0, 0},
704 			{1, 4},
705 			{2, 7},
706 			{3, 10},
707 			{4, 14},
708 			{5, 17},
709 			{6, 20},
710 			{1472, 4907},
711 			{2097, 6990},
712 			{5326, 17754},
713 			{9828, 32760},
714 			{9829, 32764},
715 			{9830, 32767},
716 			{9831, -1},
717 			{9832, -1},
718 			{12000, -1},
719 			{28453, -1},
720 			{SIZE_MAX / 6, -1},
721 			{SIZE_MAX / 3, -1},
722 			{SIZE_MAX / 2, -1},
723 			{SIZE_MAX / 1, -1},
724 		};
725 		for (size_t i = 0; i < ARRAY_LENGTH(CASES); i++) {
726 			assert(calcSegmentBitLength(qrcodegen_Mode_NUMERIC, CASES[i].numChars) == CASES[i].result);
727 			numTestCases++;
728 		}
729 	}
730 	{
731 		const struct TestCase CASES[] = {
732 			{0, 0},
733 			{1, 6},
734 			{2, 11},
735 			{3, 17},
736 			{4, 22},
737 			{5, 28},
738 			{6, 33},
739 			{1472, 8096},
740 			{2097, 11534},
741 			{5326, 29293},
742 			{5955, 32753},
743 			{5956, 32758},
744 			{5957, 32764},
745 			{5958, -1},
746 			{5959, -1},
747 			{12000, -1},
748 			{28453, -1},
749 			{SIZE_MAX / 10, -1},
750 			{SIZE_MAX / 5, -1},
751 			{SIZE_MAX / 2, -1},
752 			{SIZE_MAX / 1, -1},
753 		};
754 		for (size_t i = 0; i < ARRAY_LENGTH(CASES); i++) {
755 			assert(calcSegmentBitLength(qrcodegen_Mode_ALPHANUMERIC, CASES[i].numChars) == CASES[i].result);
756 			numTestCases++;
757 		}
758 	}
759 	{
760 		const struct TestCase CASES[] = {
761 			{0, 0},
762 			{1, 8},
763 			{2, 16},
764 			{3, 24},
765 			{1472, 11776},
766 			{2097, 16776},
767 			{4094, 32752},
768 			{4095, 32760},
769 			{4096, -1},
770 			{4097, -1},
771 			{5957, -1},
772 			{12000, -1},
773 			{28453, -1},
774 			{SIZE_MAX / 15, -1},
775 			{SIZE_MAX / 12, -1},
776 			{SIZE_MAX / 7, -1},
777 			{SIZE_MAX / 3, -1},
778 			{SIZE_MAX / 1, -1},
779 		};
780 		for (size_t i = 0; i < ARRAY_LENGTH(CASES); i++) {
781 			assert(calcSegmentBitLength(qrcodegen_Mode_BYTE, CASES[i].numChars) == CASES[i].result);
782 			numTestCases++;
783 		}
784 	}
785 	{
786 		const struct TestCase CASES[] = {
787 			{0, 0},
788 			{1, 13},
789 			{2, 26},
790 			{3, 39},
791 			{1472, 19136},
792 			{2097, 27261},
793 			{2519, 32747},
794 			{2520, 32760},
795 			{2521, -1},
796 			{5957, -1},
797 			{2522, -1},
798 			{12000, -1},
799 			{28453, -1},
800 			{SIZE_MAX / 25, -1},
801 			{SIZE_MAX / 20, -1},
802 			{SIZE_MAX / 11, -1},
803 			{SIZE_MAX / 4, -1},
804 			{SIZE_MAX / 2, -1},
805 			{SIZE_MAX / 1, -1},
806 		};
807 		for (size_t i = 0; i < ARRAY_LENGTH(CASES); i++) {
808 			assert(calcSegmentBitLength(qrcodegen_Mode_KANJI, CASES[i].numChars) == CASES[i].result);
809 			numTestCases++;
810 		}
811 	}
812 	{
813 		assert(calcSegmentBitLength(qrcodegen_Mode_ECI, 0) == 24);
814 		numTestCases++;
815 	}
816 }
817 
818 
testMakeBytes(void)819 static void testMakeBytes(void) {
820 	{
821 		struct qrcodegen_Segment seg = qrcodegen_makeBytes(NULL, 0, NULL);
822 		assert(seg.mode == qrcodegen_Mode_BYTE);
823 		assert(seg.numChars == 0);
824 		assert(seg.bitLength == 0);
825 		numTestCases++;
826 	}
827 	{
828 		const uint8_t data[] = {0x00};
829 		uint8_t buf[1];
830 		struct qrcodegen_Segment seg = qrcodegen_makeBytes(data, 1, buf);
831 		assert(seg.numChars == 1);
832 		assert(seg.bitLength == 8);
833 		assert(seg.data[0] == 0x00);
834 		numTestCases++;
835 	}
836 	{
837 		const uint8_t data[] = {0xEF, 0xBB, 0xBF};
838 		uint8_t buf[3];
839 		struct qrcodegen_Segment seg = qrcodegen_makeBytes(data, 3, buf);
840 		assert(seg.numChars == 3);
841 		assert(seg.bitLength == 24);
842 		assert(seg.data[0] == 0xEF);
843 		assert(seg.data[1] == 0xBB);
844 		assert(seg.data[2] == 0xBF);
845 		numTestCases++;
846 	}
847 }
848 
849 
testMakeNumeric(void)850 static void testMakeNumeric(void) {
851 	{
852 		struct qrcodegen_Segment seg = qrcodegen_makeNumeric("", NULL);
853 		assert(seg.mode == qrcodegen_Mode_NUMERIC);
854 		assert(seg.numChars == 0);
855 		assert(seg.bitLength == 0);
856 		numTestCases++;
857 	}
858 	{
859 		uint8_t buf[1];
860 		struct qrcodegen_Segment seg = qrcodegen_makeNumeric("9", buf);
861 		assert(seg.numChars == 1);
862 		assert(seg.bitLength == 4);
863 		assert(seg.data[0] == 0x90);
864 		numTestCases++;
865 	}
866 	{
867 		uint8_t buf[1];
868 		struct qrcodegen_Segment seg = qrcodegen_makeNumeric("81", buf);
869 		assert(seg.numChars == 2);
870 		assert(seg.bitLength == 7);
871 		assert(seg.data[0] == 0xA2);
872 		numTestCases++;
873 	}
874 	{
875 		uint8_t buf[2];
876 		struct qrcodegen_Segment seg = qrcodegen_makeNumeric("673", buf);
877 		assert(seg.numChars == 3);
878 		assert(seg.bitLength == 10);
879 		assert(seg.data[0] == 0xA8);
880 		assert(seg.data[1] == 0x40);
881 		numTestCases++;
882 	}
883 	{
884 		uint8_t buf[5];
885 		struct qrcodegen_Segment seg = qrcodegen_makeNumeric("3141592653", buf);
886 		assert(seg.numChars == 10);
887 		assert(seg.bitLength == 34);
888 		assert(seg.data[0] == 0x4E);
889 		assert(seg.data[1] == 0x89);
890 		assert(seg.data[2] == 0xF4);
891 		assert(seg.data[3] == 0x24);
892 		assert(seg.data[4] == 0xC0);
893 		numTestCases++;
894 	}
895 }
896 
897 
testMakeAlphanumeric(void)898 static void testMakeAlphanumeric(void) {
899 	{
900 		struct qrcodegen_Segment seg = qrcodegen_makeAlphanumeric("", NULL);
901 		assert(seg.mode == qrcodegen_Mode_ALPHANUMERIC);
902 		assert(seg.numChars == 0);
903 		assert(seg.bitLength == 0);
904 		numTestCases++;
905 	}
906 	{
907 		uint8_t buf[1];
908 		struct qrcodegen_Segment seg = qrcodegen_makeAlphanumeric("A", buf);
909 		assert(seg.numChars == 1);
910 		assert(seg.bitLength == 6);
911 		assert(seg.data[0] == 0x28);
912 		numTestCases++;
913 	}
914 	{
915 		uint8_t buf[2];
916 		struct qrcodegen_Segment seg = qrcodegen_makeAlphanumeric("%:", buf);
917 		assert(seg.numChars == 2);
918 		assert(seg.bitLength == 11);
919 		assert(seg.data[0] == 0xDB);
920 		assert(seg.data[1] == 0x40);
921 		numTestCases++;
922 	}
923 	{
924 		uint8_t buf[3];
925 		struct qrcodegen_Segment seg = qrcodegen_makeAlphanumeric("Q R", buf);
926 		assert(seg.numChars == 3);
927 		assert(seg.bitLength == 17);
928 		assert(seg.data[0] == 0x96);
929 		assert(seg.data[1] == 0xCD);
930 		assert(seg.data[2] == 0x80);
931 		numTestCases++;
932 	}
933 }
934 
935 
testMakeEci(void)936 static void testMakeEci(void) {
937 	{
938 		uint8_t buf[1];
939 		struct qrcodegen_Segment seg = qrcodegen_makeEci(127, buf);
940 		assert(seg.mode == qrcodegen_Mode_ECI);
941 		assert(seg.numChars == 0);
942 		assert(seg.bitLength == 8);
943 		assert(seg.data[0] == 0x7F);
944 		numTestCases++;
945 	}
946 	{
947 		uint8_t buf[2];
948 		struct qrcodegen_Segment seg = qrcodegen_makeEci(10345, buf);
949 		assert(seg.numChars == 0);
950 		assert(seg.bitLength == 16);
951 		assert(seg.data[0] == 0xA8);
952 		assert(seg.data[1] == 0x69);
953 		numTestCases++;
954 	}
955 	{
956 		uint8_t buf[3];
957 		struct qrcodegen_Segment seg = qrcodegen_makeEci(999999, buf);
958 		assert(seg.numChars == 0);
959 		assert(seg.bitLength == 24);
960 		assert(seg.data[0] == 0xCF);
961 		assert(seg.data[1] == 0x42);
962 		assert(seg.data[2] == 0x3F);
963 		numTestCases++;
964 	}
965 }
966 
967 
testGetTotalBits(void)968 static void testGetTotalBits(void) {
969 	{
970 		assert(getTotalBits(NULL, 0, 1) == 0);
971 		numTestCases++;
972 		assert(getTotalBits(NULL, 0, 40) == 0);
973 		numTestCases++;
974 	}
975 	{
976 		struct qrcodegen_Segment segs[] = {
977 			{qrcodegen_Mode_BYTE, 3, NULL, 24},
978 		};
979 		assert(getTotalBits(segs, ARRAY_LENGTH(segs), 2) == 36);
980 		numTestCases++;
981 		assert(getTotalBits(segs, ARRAY_LENGTH(segs), 10) == 44);
982 		numTestCases++;
983 		assert(getTotalBits(segs, ARRAY_LENGTH(segs), 39) == 44);
984 		numTestCases++;
985 	}
986 	{
987 		struct qrcodegen_Segment segs[] = {
988 			{qrcodegen_Mode_ECI, 0, NULL, 8},
989 			{qrcodegen_Mode_NUMERIC, 7, NULL, 24},
990 			{qrcodegen_Mode_ALPHANUMERIC, 1, NULL, 6},
991 			{qrcodegen_Mode_KANJI, 4, NULL, 52},
992 		};
993 		assert(getTotalBits(segs, ARRAY_LENGTH(segs), 9) == 133);
994 		numTestCases++;
995 		assert(getTotalBits(segs, ARRAY_LENGTH(segs), 21) == 139);
996 		numTestCases++;
997 		assert(getTotalBits(segs, ARRAY_LENGTH(segs), 27) == 145);
998 		numTestCases++;
999 	}
1000 	{
1001 		struct qrcodegen_Segment segs[] = {
1002 			{qrcodegen_Mode_BYTE, 4093, NULL, 32744},
1003 		};
1004 		assert(getTotalBits(segs, ARRAY_LENGTH(segs), 1) == -1);
1005 		numTestCases++;
1006 		assert(getTotalBits(segs, ARRAY_LENGTH(segs), 10) == 32764);
1007 		numTestCases++;
1008 		assert(getTotalBits(segs, ARRAY_LENGTH(segs), 27) == 32764);
1009 		numTestCases++;
1010 	}
1011 	{
1012 		struct qrcodegen_Segment segs[] = {
1013 			{qrcodegen_Mode_NUMERIC, 2047, NULL, 6824},
1014 			{qrcodegen_Mode_NUMERIC, 2047, NULL, 6824},
1015 			{qrcodegen_Mode_NUMERIC, 2047, NULL, 6824},
1016 			{qrcodegen_Mode_NUMERIC, 2047, NULL, 6824},
1017 			{qrcodegen_Mode_NUMERIC, 1617, NULL, 5390},
1018 		};
1019 		assert(getTotalBits(segs, ARRAY_LENGTH(segs), 1) == -1);
1020 		numTestCases++;
1021 		assert(getTotalBits(segs, ARRAY_LENGTH(segs), 10) == 32766);
1022 		numTestCases++;
1023 		assert(getTotalBits(segs, ARRAY_LENGTH(segs), 27) == -1);
1024 		numTestCases++;
1025 	}
1026 	{
1027 		struct qrcodegen_Segment segs[] = {
1028 			{qrcodegen_Mode_KANJI, 255, NULL, 3315},
1029 			{qrcodegen_Mode_KANJI, 255, NULL, 3315},
1030 			{qrcodegen_Mode_KANJI, 255, NULL, 3315},
1031 			{qrcodegen_Mode_KANJI, 255, NULL, 3315},
1032 			{qrcodegen_Mode_KANJI, 255, NULL, 3315},
1033 			{qrcodegen_Mode_KANJI, 255, NULL, 3315},
1034 			{qrcodegen_Mode_KANJI, 255, NULL, 3315},
1035 			{qrcodegen_Mode_KANJI, 255, NULL, 3315},
1036 			{qrcodegen_Mode_KANJI, 255, NULL, 3315},
1037 			{qrcodegen_Mode_ALPHANUMERIC, 511, NULL, 2811},
1038 		};
1039 		assert(getTotalBits(segs, ARRAY_LENGTH(segs), 9) == 32767);
1040 		numTestCases++;
1041 		assert(getTotalBits(segs, ARRAY_LENGTH(segs), 26) == -1);
1042 		numTestCases++;
1043 		assert(getTotalBits(segs, ARRAY_LENGTH(segs), 40) == -1);
1044 		numTestCases++;
1045 	}
1046 }
1047 
1048 
1049 /*---- Main runner ----*/
1050 
main(void)1051 int main(void) {
1052 	srand((unsigned int)time(NULL));
1053 	testAppendBitsToBuffer();
1054 	testAddEccAndInterleave();
1055 	testGetNumDataCodewords();
1056 	testGetNumRawDataModules();
1057 	testReedSolomonComputeDivisor();
1058 	testReedSolomonComputeRemainder();
1059 	testReedSolomonMultiply();
1060 	testInitializeFunctionModulesEtc();
1061 	testGetAlignmentPatternPositions();
1062 	testGetSetModule();
1063 	testGetSetModuleRandomly();
1064 	testIsAlphanumeric();
1065 	testIsNumeric();
1066 	testCalcSegmentBufferSize();
1067 	testCalcSegmentBitLength();
1068 	testMakeBytes();
1069 	testMakeNumeric();
1070 	testMakeAlphanumeric();
1071 	testMakeEci();
1072 	testGetTotalBits();
1073 	printf("All %d test cases passed\n", numTestCases);
1074 	return EXIT_SUCCESS;
1075 }
1076