1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
|
// Author: cirakg & claude ai
// Summary: Tests for the linear barcode encoders: zxing-cpp reference rows, validation messages, and a dump for decoding.
import Toybox.Lang;
import Toybox.Test;
(:test)
module LinearFixtures {
function moduleText(m as ByteArray) as String {
var s = "";
for (var i = 0; i < m.size(); i++) {
s += m[i] == 1 ? "1" : "0";
}
return s;
}
// The error message for payload, or "" when it encodes.
function errorOf(symbology as Number, payload as String, options as Number) as String {
var r = Codes.encode(symbology, payload, options);
return r instanceof Codes.CodeError ? r.message : "";
}
function opts(check as Number) as Number {
return Codes.OPT_SHOW_TEXT | (check << Codes.OPT_CHECK_SHIFT) | 1;
}
}
// README 12.4 check 1: identical modules to zxing-cpp for every row.
(:test)
function linearCodesMatchTheReference(logger as Test.Logger) as Boolean {
var rows = CodeVectors.LINEAR;
for (var i = 0; i < rows.size(); i++) {
var row = rows[i] as Array;
var symbology = row[0] as Number;
var payload = row[1] as String;
var result = Codes.encode(symbology, payload, row[2] as Number);
if (result instanceof Codes.CodeError) {
logger.error("row " + i + " (" + Codes.name(symbology) + " '" + payload + "'): " + result.message);
return false;
}
var got = LinearFixtures.moduleText(result.modules);
var expected = row[3] as String;
if (symbology == Codes.CODE128) {
// zxing-cpp 3 writes Code 128 through zint, whose optimal encoder
// breaks ties between equally short encodings differently (for
// example set C for a final digit pair). Both are optimal: the
// length must match, and the code is decoded by check_codes.py.
logger.debug("CODEDUMP " + symbology + " " + Bytes.toHex(Bytes.fromUtf8(result.text)) + " " + got);
if (got.length() != expected.length()) {
logger.error("row " + i + " (Code 128 '" + payload + "') has " + got.length() + " modules, zxing-cpp "
+ expected.length());
return false;
}
continue;
}
if (!got.equals(expected)) {
logger.error("row " + i + " (" + Codes.name(symbology) + " '" + payload + "') differs:\n got " + got + "\n exp " + expected);
return false;
}
}
logger.debug("CODES reference rows=" + rows.size());
return true;
}
(:test)
function linearCheckDigitModes(logger as Test.Logger) as Boolean {
var add = LinearFixtures.opts(Codes.CHECK_ADD_VERIFY);
var fix = LinearFixtures.opts(Codes.CHECK_FIX);
var off = LinearFixtures.opts(Codes.CHECK_OFF);
var added = Codes.encode(Codes.EAN13, "590123412345", add) as Codes.LinearCode;
var fixed = Codes.encode(Codes.EAN13, "5901234123450", fix) as Codes.LinearCode;
var kept = Codes.encode(Codes.EAN13, "5901234123450", off) as Codes.LinearCode;
var wrong = LinearFixtures.errorOf(Codes.EAN13, "5901234123450", add);
var offShort = LinearFixtures.errorOf(Codes.EAN13, "590123412345", off);
return added.text.equals("5901234123457") && added.note != null
&& fixed.text.equals("5901234123457") && (fixed.note as String).find("was 0") != null
&& kept.text.equals("5901234123450")
&& wrong.find("check digit should be 7, got 0") != null && wrong.find("Fix if wrong") != null
&& offShort.find("needs all 13 digits") != null;
}
(:test)
function linearValidationMessages(logger as Test.Logger) as Boolean {
var o = LinearFixtures.opts(Codes.CHECK_ADD_VERIFY);
var off = LinearFixtures.opts(Codes.CHECK_OFF);
var cases = [
[Codes.EAN13, "59012341234a", o, "digits only"],
[Codes.EAN13, "123", o, "needs 12 or 13 digits"],
[Codes.UPCA, "1234", o, "UPC-A needs 11 or 12"],
[Codes.EAN8, "12345678", o, "check digit should be"],
[Codes.UPCE, "2123456", o, "number system must be 0 or 1"],
[Codes.UPCE, "0502553", o, "not a valid zero suppression"],
[Codes.UPCE, "12345", o, "6, 7 or 8 digits"],
[Codes.ITF, "123", off, "even number of digits"],
[Codes.ITF, "1234", o, "odd number of digits"],
[Codes.CODE39, "abc", o, "isn't allowed"],
[Codes.CODE128, "Ünï", o, "printable ASCII"],
[Codes.CODE128, "", o, "needs some text"],
[Codes.CODABAR, "A123", o, "both ends or at neither"],
[Codes.CODABAR, "A1B2A", o, "isn't allowed there"],
[Codes.QR, "hello", o, "not supported yet"]
];
for (var i = 0; i < cases.size(); i++) {
var c = cases[i] as Array;
var message = LinearFixtures.errorOf(c[0] as Number, c[1] as String, c[2] as Number);
if (message.find(c[3] as String) == null) {
logger.error("case " + i + ": got '" + message + "'");
return false;
}
}
var codabar = Codes.encode(Codes.CODABAR, "40156", o) as Codes.LinearCode;
return codabar.text.equals("A40156A") && codabar.note != null;
}
// README 12.4 check 2: dumps encoder outputs for seeded random payloads;
// tools/check_codes.py decodes them with zxing-cpp after the test run.
(:test)
function linearDumpForDecoding(logger as Test.Logger) as Boolean {
var seed = 12345;
var count = 0;
var symbologies = [Codes.EAN13, Codes.EAN8, Codes.UPCA, Codes.UPCE, Codes.CODE128, Codes.CODE39, Codes.ITF, Codes.CODABAR];
var o = LinearFixtures.opts(Codes.CHECK_ADD_VERIFY);
for (var i = 0; i < 160; i++) {
var symbology = symbologies[i % symbologies.size()] as Number;
var length = [12, 7, 11, 7, 10, 8, 10, 8][i % symbologies.size()] as Number;
var alphabet = ["0123456789", "0123456789", "0123456789", "0123456789",
"0123456789 AZaz!#$%&()*+,-./:;<=>?@", "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%", "0123456789", "0123456789-$:/.+"][i % symbologies.size()] as String;
var text = "";
for (var k = 0; k < length; k++) {
seed = (seed * 1103515245 + 12345) & 0x7FFFFFFF;
var at = (seed >> 8) % alphabet.length();
text += alphabet.substring(at, at + 1);
}
if (symbology == Codes.UPCE) {
text = "0" + text.substring(1, 7);
}
var result = Codes.encode(symbology, text, o);
if (result instanceof Codes.CodeError) {
continue; // invalid random UPC-E suppressions are expected
}
logger.debug("CODEDUMP " + symbology + " " + Bytes.toHex(Bytes.fromUtf8(result.text)) + " " + LinearFixtures.moduleText(result.modules));
count++;
}
return count > 120;
}
|