/* * Copyright 2014 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Tests {@link Code128Writer}. */ const FNC1: &str = "11110101110"; const FNC2: &str = "11110101000"; const FNC3: &str = "10111100010"; const FNC4A: &str = "11101011110"; const FNC4B: &str = "10111101110"; const START_CODE_A: &str = "11010000100"; const START_CODE_B: &str = "11010010000"; const START_CODE_C: &str = "11010011100"; const SWITCH_CODE_A: &str = "11101011110"; const SWITCH_CODE_B: &str = "10111101110"; const QUIET_SPACE: &str = "00000"; const STOP: &str = "1100011101011"; const LF: &str = "10000110010"; use std::collections::HashMap; use once_cell::sync::Lazy; use crate::{ common::{bit_matrix_test_case, BitMatrix}, oned::{Code128Reader, OneDReader}, BarcodeFormat, EncodeHintType, EncodeHintValue, EncodingHintDictionary, Exceptions, Writer, }; use super::Code128Writer; static WRITER: Lazy = Lazy::new(Code128Writer::default); #[test] fn testEncodeWithFunc3() { let toEncode = "\u{00f3}123"; let expected = format!( "{}{}{}{}{}{}{}{}{}", QUIET_SPACE, START_CODE_B, FNC3, // "1" "2" "3" check digit 51 "10011100110", "11001110010", "11001011100", "11101000110", STOP, QUIET_SPACE ); let result = encode(toEncode, false, "123").expect("encode"); let actual = bit_matrix_test_case::matrix_to_string(&result); assert_eq!(expected, actual); let width = result.getWidth(); let result = encode(toEncode, true, "123").expect("encode"); assert_eq!(width, result.getWidth()); } #[test] fn testEncodeWithFunc2() { let toEncode = "\u{00f2}123"; let expected = format!( "{}{}{}{}{}{}{}{}{}", QUIET_SPACE, START_CODE_B, FNC2, // "1" "2" "3" check digit 56 "10011100110", "11001110010", "11001011100", "11100010110", STOP, QUIET_SPACE ); let result = encode(toEncode, false, "123").expect("encode"); let actual = bit_matrix_test_case::matrix_to_string(&result); assert_eq!(expected, actual); let width = result.getWidth(); let result = encode(toEncode, true, "123").expect("encode"); assert_eq!(width, result.getWidth()); } #[test] fn testEncodeWithFunc1() { let toEncode = "\u{00f1}123"; let expected = format!( "{}{}{}{}{}{}{}{}{}", QUIET_SPACE, START_CODE_C, FNC1, // "12" "3" check digit 92 "10110011100", SWITCH_CODE_B, "11001011100", "10101111000", STOP, QUIET_SPACE ); let result = encode(toEncode, false, "123").expect("encode"); let actual = bit_matrix_test_case::matrix_to_string(&result); assert_eq!(expected, actual); let width = result.getWidth(); let result = encode(toEncode, true, "123").expect("encode"); assert_eq!(width, result.getWidth()); } #[test] fn testRoundtrip() { let toEncode = concat!("\u{00f1}", "10958", "\u{00f1}", "17160526"); let expected = "1095817160526"; let encRXingResult = encode(toEncode, false, expected).expect("encode"); let width = encRXingResult.getWidth(); let encRXingResult = encode(toEncode, true, expected).expect("encode"); //Compact encoding has one latch less and encodes as STARTA,FNC1,1,CODEC,09,58,FNC1,17,16,05,26 assert_eq!(width, encRXingResult.getWidth() + 11); } #[test] fn testLongCompact() { //test longest possible input let toEncode = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; encode(toEncode, true, toEncode).expect("encode"); } #[test] fn testShift() { //compare fast to compact let toEncode = "a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"; let result = encode(toEncode, false, toEncode).expect("encode"); let width = result.getWidth(); let result = encode(toEncode, true, toEncode).expect("encode"); //big difference since the fast algoritm doesn't make use of SHIFT assert_eq!(width, result.getWidth() + 253); } #[test] fn testDigitMixCompaction() { //compare fast to compact let toEncode = "A1A12A123A1234A12345AA1AA12AA123AA1234AA1235"; let result = encode(toEncode, false, toEncode).expect("encode"); let width = result.getWidth(); let result = encode(toEncode, true, toEncode).expect("encode"); //very good, no difference assert_eq!(width, result.getWidth()); } #[test] fn testCompaction1() { //compare fast to compact let toEncode = "AAAAAAAAAAA12AAAAAAAAA"; let result = encode(toEncode, false, toEncode).expect("encode"); let width = result.getWidth(); let result = encode(toEncode, true, toEncode).expect("encode"); //very good, no difference assert_eq!(width, result.getWidth()); } #[test] fn testCompaction2() { //compare fast to compact let toEncode = "AAAAAAAAAAA1212aaaaaaaaa"; let result = encode(toEncode, false, toEncode).expect("encode"); let width = result.getWidth(); let result = encode(toEncode, true, toEncode).expect("encode"); //very good, no difference assert_eq!(width, result.getWidth()); } #[test] fn testEncodeWithFunc4() { let toEncode = concat!("\u{00f4}", "123"); let expected = format!( "{}{}{}{}{}{}{}{}{}", QUIET_SPACE, START_CODE_B, FNC4B, // "1" "2" "3" check digit 59 "10011100110", "11001110010", "11001011100", "11100011010", STOP, QUIET_SPACE ); let result = encode(toEncode, false, "").expect("encode"); let actual = bit_matrix_test_case::matrix_to_string(&result); assert_eq!(expected, actual); let width = result.getWidth(); let result = encode(toEncode, true, "").expect("encode"); assert_eq!(width, result.getWidth()); } #[test] fn testEncodeWithFncsAndNumberInCodesetA() { let toEncode = concat!("\n", "\u{00f1}", "\u{00f4}", "1", "\n"); let expected = format!( "{}{}{}{}{}{}{}{}{}{}", QUIET_SPACE, START_CODE_A, LF, FNC1, FNC4A, "10011100110", LF, "10101111000", STOP, QUIET_SPACE ); let result = encode(toEncode, false, "").expect("encode"); let actual = bit_matrix_test_case::matrix_to_string(&result); assert_eq!(expected, actual); let width = result.getWidth(); let result = encode(toEncode, true, "").expect("encode"); assert_eq!(width, result.getWidth()); } #[test] fn testEncodeSwitchBetweenCodesetsAAndB() { // start with A switch to B and back to A testEncode( "\0ABab\u{0010}", &format!( "{}{}{}{}{}{}{}{}{}{}{}{}{}", QUIET_SPACE, START_CODE_A, // "\0" "A" "B" Switch to B "a" "b" "10100001100", "10100011000", "10001011000", SWITCH_CODE_B, "10010110000", "10010000110", // Switch to A "\u0010" check digit SWITCH_CODE_A, "10100111100", "11001110100", STOP, QUIET_SPACE ), ); // start with B switch to A and back to B // the compact encoder encodes this shorter as STARTB,a,b,SHIFT,NUL,a,b testEncode( "ab\0ab", &format!( "{}{}{}{}{}{}{}{}{}{}{}{}", QUIET_SPACE, START_CODE_B, // "a" "b" Switch to A "\0" Switch to B "10010110000", "10010000110", SWITCH_CODE_A, "10100001100", SWITCH_CODE_B, // "a" "b" check digit "10010110000", "10010000110", "11010001110", STOP, QUIET_SPACE ), ); } fn testEncode(toEncode: &str, expected: &str) { let result = encode(toEncode, false, toEncode).expect("encode"); let actual = bit_matrix_test_case::matrix_to_string(&result); assert_eq!(expected, actual, "{}", toEncode); let width = result.getWidth(); let result = encode(toEncode, true, toEncode).expect("encode"); assert!(result.getWidth() <= width); } #[test] #[should_panic] fn testEncodeWithForcedCodeSetFailureCodeSetABadCharacter() { // Lower case characters should not be accepted when the code set is forced to A. let toEncode = "ASDFx0123"; let mut hints = HashMap::new(); //new EnumMap<>(EncodeHintType.class); hints.insert( EncodeHintType::FORCE_CODE_SET, EncodeHintValue::ForceCodeSet("A".to_string()), ); WRITER .encode_with_hints(toEncode, &BarcodeFormat::CODE_128, 0, 0, &hints) .expect("encode"); } #[test] #[should_panic] fn testEncodeWithForcedCodeSetFailureCodeSetBBadCharacter() { let toEncode = "ASdf\00123"; // \0 (ascii value 0) // Characters with ASCII value below 32 should not be accepted when the code set is forced to B. let mut hints = HashMap::new(); //new EnumMap<>(EncodeHintType.class); hints.insert( EncodeHintType::FORCE_CODE_SET, EncodeHintValue::ForceCodeSet("B".to_string()), ); // let hints = new EnumMap<>(EncodeHintType.class); // hints.put(EncodeHintType.FORCE_CODE_SET, "B"); WRITER .encode_with_hints(toEncode, &BarcodeFormat::CODE_128, 0, 0, &hints) .expect("encode"); } #[test] #[should_panic] fn testEncodeWithForcedCodeSetFailureCodeSetCBadCharactersNonNum() { let toEncode = "123a5678"; // Non-digit characters should not be accepted when the code set is forced to C. let mut hints = HashMap::new(); //new EnumMap<>(EncodeHintType.class); hints.insert( EncodeHintType::FORCE_CODE_SET, EncodeHintValue::ForceCodeSet("C".to_string()), ); // let hints = new EnumMap<>(EncodeHintType.class); // hints.put(EncodeHintType.FORCE_CODE_SET, "C"); WRITER .encode_with_hints(toEncode, &BarcodeFormat::CODE_128, 0, 0, &hints) .expect("encode"); } #[test] #[should_panic] fn testEncodeWithForcedCodeSetFailureCodeSetCBadCharactersFncCode() { let toEncode = "123\u{00f2}a678"; // Function codes other than 1 should not be accepted when the code set is forced to C. let mut hints = HashMap::new(); //new EnumMap<>(EncodeHintType.class); hints.insert( EncodeHintType::FORCE_CODE_SET, EncodeHintValue::ForceCodeSet("C".to_string()), ); WRITER .encode_with_hints(toEncode, &BarcodeFormat::CODE_128, 0, 0, &hints) .expect("encode"); } #[test] #[should_panic] fn testEncodeWithForcedCodeSetFailureCodeSetCWrongAmountOfDigits() { let toEncode = "123456789"; // An uneven amount of digits should not be accepted when the code set is forced to C. let mut hints = HashMap::new(); //new EnumMap<>(EncodeHintType.class); hints.insert( EncodeHintType::FORCE_CODE_SET, EncodeHintValue::ForceCodeSet("C".to_string()), ); WRITER .encode_with_hints(toEncode, &BarcodeFormat::CODE_128, 0, 0, &hints) .expect("encode"); } #[test] fn testEncodeWithForcedCodeSetFailureCodeSetA() { let toEncode = "AB123"; // would default to B "A" "B" "1" let expected = format!( "{}{}{}{}{}{}{}{}{}{}", QUIET_SPACE, START_CODE_A, "10100011000", "10001011000", "10011100110", // "2" "3" check digit 10 "11001110010", "11001011100", "11001000100", STOP, QUIET_SPACE ); // let hints = new EnumMap<>(EncodeHintType.class); // hints.put(EncodeHintType.FORCE_CODE_SET, "A"); let mut hints = HashMap::new(); //new EnumMap<>(EncodeHintType.class); hints.insert( EncodeHintType::FORCE_CODE_SET, EncodeHintValue::ForceCodeSet("A".to_string()), ); let result = WRITER .encode_with_hints(toEncode, &BarcodeFormat::CODE_128, 0, 0, &hints) .expect("encode"); let actual = bit_matrix_test_case::matrix_to_string(&result); assert_eq!(expected, actual); } #[test] fn testEncodeWithForcedCodeSetFailureCodeSetB() { let toEncode = "1234"; // would default to C "1" "2" "3" let expected = format!( "{}{}{}{}{}{}{}{}{}", QUIET_SPACE, START_CODE_B, "10011100110", "11001110010", "11001011100", // "4" check digit 88 "11001001110", "11110010010", STOP, QUIET_SPACE ); // let hints = new EnumMap<>(EncodeHintType.class); // hints.put(EncodeHintType.FORCE_CODE_SET, "B"); let mut hints = HashMap::new(); //new EnumMap<>(EncodeHintType.class); hints.insert( EncodeHintType::FORCE_CODE_SET, EncodeHintValue::ForceCodeSet("B".to_string()), ); let result = WRITER .encode_with_hints(toEncode, &BarcodeFormat::CODE_128, 0, 0, &hints) .expect("encode"); let actual = bit_matrix_test_case::matrix_to_string(&result); assert_eq!(expected, actual); } fn encode(toEncode: &str, compact: bool, expectedLoopback: &str) -> Result { let mut reader = Code128Reader::default(); let mut hints: EncodingHintDictionary = HashMap::new(); if compact { hints.insert( EncodeHintType::CODE128_COMPACT, EncodeHintValue::Code128Compact(true), ); } let encRXingResult = WRITER.encode_with_hints(toEncode, &BarcodeFormat::CODE_128, 0, 0, &hints)?; if !expectedLoopback.is_empty() { let row = encRXingResult.getRow(0); let rtRXingResult = reader.decodeRow(0, &row, &HashMap::new())?; let actual = rtRXingResult.getText(); assert_eq!(expectedLoopback, actual); } if compact { //check that what is encoded compactly yields the same on loopback as what was encoded fast. let row = encRXingResult.getRow(0); let rtRXingResult = reader.decodeRow(0, &row, &HashMap::new())?; let actual = rtRXingResult.getText(); let encRXingResultFast = WRITER.encode(toEncode, &BarcodeFormat::CODE_128, 0, 0)?; let row = encRXingResultFast.getRow(0); let rtRXingResult = reader.decodeRow(0, &row, &HashMap::new())?; assert_eq!(rtRXingResult.getText(), actual); } Ok(encRXingResult) }