aboutsummaryrefslogtreecommitdiff
path: root/test/codes/LinearTest.mc
diff options
context:
space:
mode:
Diffstat (limited to 'test/codes/LinearTest.mc')
-rw-r--r--test/codes/LinearTest.mc146
1 files changed, 146 insertions, 0 deletions
diff --git a/test/codes/LinearTest.mc b/test/codes/LinearTest.mc
new file mode 100644
index 0000000..ed42ccf
--- /dev/null
+++ b/test/codes/LinearTest.mc
@@ -0,0 +1,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;
+}