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