Added test worker programs for Java, Python, C; added batch tester in Python.

This commit is contained in:
Project Nayuki 2017-04-21 00:15:07 +00:00
parent 55c5510057
commit 6c5f8d087b
4 changed files with 423 additions and 0 deletions

111
c/qrcodegen-worker.c Normal file
View File

@ -0,0 +1,111 @@
/*
* QR Code generator test worker (C)
*
* This program reads data and encoding parameters from standard input and writes
* QR Code bitmaps to standard output. The I/O format is one integer per line.
* Run with no command line arguments. The program is intended for automated
* batch testing of end-to-end functionality of this QR Code generator library.
*
* 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 <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "qrcodegen.h"
// The main application program.
int main(void) {
// Start loop
while (true) {
// Read data length or exit
int length;
scanf("%d", &length);
if (length == -1)
break;
// Read data bytes
bool isAscii = true;
uint8_t *data = malloc(length * sizeof(uint8_t));
if (data == NULL) {
perror("malloc");
return EXIT_FAILURE;
}
for (int i = 0; i < length; i++) {
int b;
scanf("%d", &b);
data[i] = (uint8_t)b;
isAscii &= 0 < b && b < 128;
}
// Read encoding parameters
int errCorLvl, minVersion, maxVersion, mask, boostEcl;
scanf("%d %d %d %d %d", &errCorLvl, &minVersion, &maxVersion, &mask, &boostEcl);
// Allocate memory for QR Code
int bufferLen = qrcodegen_BUFFER_LEN_FOR_VERSION(maxVersion);
uint8_t *qrcode = malloc(bufferLen * sizeof(uint8_t));
uint8_t *tempBuffer = malloc(bufferLen * sizeof(uint8_t));
if (qrcode == NULL || tempBuffer == NULL) {
perror("malloc");
return EXIT_FAILURE;
}
// Try to make QR Code symbol
int version;
if (isAscii) {
char *text = malloc((length + 1) * sizeof(char));
for (int i = 0; i < length; i++)
text[i] = (char)data[i];
text[length] = '\0';
version = qrcodegen_encodeText(text, tempBuffer, qrcode, (enum qrcodegen_Ecc)errCorLvl,
minVersion, maxVersion, (enum qrcodegen_Mask)mask, boostEcl == 1);
free(text);
} else if (length <= bufferLen) {
for (int i = 0; i < length; i++)
tempBuffer[i] = data[i];
version = qrcodegen_encodeBinary(tempBuffer, (size_t)length, qrcode, (enum qrcodegen_Ecc)errCorLvl,
minVersion, maxVersion, (enum qrcodegen_Mask)mask, boostEcl == 1);
} else
version = 0;
free(data);
free(tempBuffer);
// Print grid of modules
if (version == 0)
printf("-1\n");
else {
printf("%d\n", version);
int size = qrcodegen_getSize(version);
for (int y = 0; y < size; y++) {
for (int x = 0; x < size; x++)
printf("%d\n", qrcodegen_getModule(qrcode, version, x, y) ? 1 : 0);
}
}
free(qrcode);
fflush(stdout);
}
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,104 @@
/*
* QR Code generator test worker (Java)
*
* This program reads data and encoding parameters from standard input and writes
* QR Code bitmaps to standard output. The I/O format is one integer per line.
* Run with no command line arguments. The program is intended for automated
* batch testing of end-to-end functionality of this QR Code generator library.
*
* 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.
*/
package io.nayuki.qrcodegen;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;
public final class QrCodeGeneratorWorker {
public static void main(String[] args) {
// Set up input stream and start loop
Scanner input = new Scanner(System.in, "US-ASCII");
input.useDelimiter("\r\n|\n|\r");
while (true) {
// Read data length or exit
int length = input.nextInt();
if (length == -1)
break;
if (length > Short.MAX_VALUE)
throw new RuntimeException();
// Read data bytes
boolean isAscii = true;
byte[] data = new byte[length];
for (int i = 0; i < data.length; i++) {
int b = input.nextInt();
if (b < 0 || b > 255)
throw new RuntimeException();
data[i] = (byte)b;
isAscii &= b < 128;
}
// Read encoding parameters
int errCorLvl = input.nextInt();
int minVersion = input.nextInt();
int maxVersion = input.nextInt();
int mask = input.nextInt();
int boostEcl = input.nextInt();
if (!(0 <= errCorLvl && errCorLvl <= 3) || !(-1 <= mask && mask <= 7) || (boostEcl >>> 1) != 0
|| !(1 <= minVersion && minVersion <= maxVersion && maxVersion <= 40))
throw new RuntimeException();
// Make segments for encoding
List<QrSegment> segs;
if (isAscii)
segs = QrSegment.makeSegments(new String(data, StandardCharsets.US_ASCII));
else
segs = Arrays.asList(QrSegment.makeBytes(data));
// Try to make QR Code symbol
QrCode qr;
try {
qr = QrCode.encodeSegments(segs, QrCode.Ecc.values()[errCorLvl], minVersion, maxVersion, mask, boostEcl != 0);
} catch (IllegalArgumentException e) {
if (e.getMessage().equals("Data too long")) {
System.out.println(-1);
System.out.flush();
continue;
} else
throw e;
}
// Print grid of modules
System.out.println(qr.version);
for (int y = 0; y < qr.size; y++) {
for (int x = 0; x < qr.size; x++)
System.out.println(qr.getModule(x, y));
}
System.out.flush();
}
}
}

View File

@ -0,0 +1,115 @@
#
# QR Code generator batch test (Python 3)
#
# Runs various versions of the QR Code generator test worker as subprocesses,
# feeds each one the same random input, and compares their output for equality.
#
# 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.
#
from __future__ import print_function
import itertools, random, subprocess, sys
if sys.version_info.major < 3:
raise RuntimeError("Requires Python 3+")
CHILD_PROGRAMS = [
["python", "qrcodegen-worker.py"],
["java", "io/nayuki/qrcodegen/QrCodeGeneratorWorker"],
["./qrcodegen-worker"],
]
def main():
global subprocs
subprocs = [subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, universal_newlines=True) for args in CHILD_PROGRAMS]
for i in itertools.count():
print("Trial {}: ".format(i), end="")
do_trial()
print()
def do_trial():
mode = random.randrange(4)
if mode == 0: # Numeric
length = max(round((2 * 7089) ** random.random()), 1)
data = [random.randrange(48, 58) for _ in range(length)]
elif mode == 1: # Alphanumeric
length = max(round((2 * 4296) ** random.random()), 1)
data = [ord(random.choice("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:")) for _ in range(length)]
elif mode == 2: # ASCII
length = max(round((2 * 2953) ** random.random()), 1)
data = [random.randrange(128) for _ in range(length)]
elif mode == 3: # Byte
length = max(round((2 * 2953) ** random.random()), 1)
data = [random.randrange(256) for _ in range(length)]
else:
raise AssertionError()
write_all(length)
for b in data:
write_all(b)
errcorlvl = random.randrange(4)
minversion = random.randint(1, 40)
maxversion = random.randint(1, 40)
if minversion > maxversion:
minversion, maxversion = maxversion, minversion
mask = -1
if random.random() < 0.5:
mask = random.randrange(8)
boostecl = int(random.random() < 0.2)
print("mode={} len={} ecl={} minv={} maxv={} mask={} boost={}".format(mode, length, errcorlvl, minversion, maxversion, mask, boostecl), end="")
write_all(errcorlvl)
write_all(minversion)
write_all(maxversion)
write_all(mask)
write_all(boostecl)
flush_all()
version = read_verify()
print(" version={}".format(version), end="")
if version == -1:
return
size = version * 4 + 17
for _ in range(size**2):
read_verify()
def write_all(val):
for proc in subprocs:
print(val, file=proc.stdin)
def flush_all():
for proc in subprocs:
proc.stdin.flush()
def read_verify():
val = subprocs[0].stdout.readline().rstrip("\r\n")
for proc in subprocs[1 : ]:
if proc.stdout.readline().rstrip("\r\n") != val:
raise ValueError("Mismatch")
return int(val)
if __name__ == "__main__":
main()

View File

@ -0,0 +1,93 @@
#
# QR Code generator test worker (Python 2, 3)
#
# This program reads data and encoding parameters from standard input and writes
# QR Code bitmaps to standard output. The I/O format is one integer per line.
# Run with no command line arguments. The program is intended for automated
# batch testing of end-to-end functionality of this QR Code generator library.
#
# 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.
#
from __future__ import print_function
import sys
import qrcodegen
py3 = sys.version_info.major >= 3
def read_int():
return int((input if py3 else raw_input)())
def main():
# Start loop
while True:
# Read data or exit
length = read_int()
if length == -1:
break
data = [read_int() for _ in range(length)]
# Read encoding parameters
errcorlvl = read_int()
minversion = read_int()
maxversion = read_int()
mask = read_int()
boostecl = read_int()
# Make segments for encoding
if all((b < 128) for b in data): # Is ASCII
segs = qrcodegen.QrSegment.make_segments("".join(chr(b) for b in data))
elif py3:
segs = [qrcodegen.QrSegment.make_bytes(bytes(data))]
else:
segs = [qrcodegen.QrSegment.make_bytes("".join(chr(b) for b in data))]
# Try to make QR Code symbol
try:
qr = qrcodegen.QrCode.encode_segments(segs, ECC_LEVELS[errcorlvl], minversion, maxversion, mask, boostecl != 0)
except ValueError as e:
if e.args[0] == "Data too long":
print(-1)
sys.stdout.flush()
continue
else:
raise
# Print grid of modules
print(qr.get_version())
for y in range(qr.get_size()):
for x in range(qr.get_size()):
print(qr.get_module(x, y))
sys.stdout.flush()
ECC_LEVELS = (
qrcodegen.QrCode.Ecc.LOW,
qrcodegen.QrCode.Ecc.MEDIUM,
qrcodegen.QrCode.Ecc.QUARTILE,
qrcodegen.QrCode.Ecc.HIGH,
)
if __name__ == "__main__":
main()