use anyd::codes::databar::{DataBarDecoder, DataBarEncoder, DataBarMeta, DataBarVariant};
use anyd::output::Encoding;
use anyd::segment::Mode;
use anyd::symbol::SymbolMeta;
use anyd::symbology::Symbology;
use anyd::traits::{Decode, Encode};
fn bits(encoding: &Encoding) -> String {
let Encoding::Linear(p) = encoding else {
panic!("expected a linear pattern");
};
p.modules
.iter()
.map(|&d| if d { '1' } else { '0' })
.collect()
}
#[test]
fn expanded_reference_vectors() {
let enc = DataBarEncoder::new();
let cases: &[(&[u8], &str)] = &[
(
b"1012A",
"010100000110100000101111111100001010001000000010110101111100100111001011110000000010011101111111010101",
),
(
b"25595011015340010123456789",
"0100011000110001011011111111000010100000010101100001100001100111001010111110000001100100001110100001001000011011111010001111110000101001011111100111011001000111100100101111111100111011111001100100110010011100010111100011110000001010",
),
(
b"01095011015300031714070410AB-123",
"01010111110000100110111111110000101110000111011001010000001101101000101111100000011001101000000100110001110100010001100011111100001010100000111100100100100111000001001011111111001110000011011001000100010000101000011000110000000010110000110011010001101100111000001010111111111001101",
),
(
b"2559501101534001\x1d171605313902050",
"01011001000110011110111111110000101000000101011000011000011001110010101111100000011001000011101000010010000110111110100011111100001010010111111001110111000010010100001011111111001110000100001100110100010000001101001000110000000010111010011110011101110010110001100010111111111001101",
),
];
for (reduced, expected) in cases {
let symbol = enc.build_expanded(reduced).unwrap();
let encoding = enc.encode(&symbol).unwrap();
assert_eq!(
&bits(&encoding),
expected,
"expanded module pattern mismatch for {reduced:?}"
);
}
}
#[test]
fn build_stores_reduced_byte_segment() {
let enc = DataBarEncoder::new();
let symbol = enc.build_expanded(b"1012A").unwrap();
assert_eq!(symbol.symbology, Symbology::DataBarExpanded);
assert_eq!(symbol.segments.len(), 1);
assert_eq!(symbol.segments[0].mode, Mode::Byte);
assert_eq!(symbol.segments[0].data, b"1012A");
assert_eq!(
symbol.meta,
SymbolMeta::DataBar(DataBarMeta::new(DataBarVariant::Expanded))
);
}
fn assert_roundtrip(reduced: &[u8]) {
let enc = DataBarEncoder::new();
let dec = DataBarDecoder::new();
let symbol = enc.build_expanded(reduced).unwrap();
let encoding = enc.encode(&symbol).unwrap();
let decoded = dec.decode(&encoding).unwrap();
assert_eq!(
decoded.symbology,
Symbology::DataBarExpanded,
"symbology ({reduced:?})"
);
assert_eq!(
decoded.segments, symbol.segments,
"segments differ ({reduced:?})"
);
assert_eq!(decoded.meta, symbol.meta, "meta differs ({reduced:?})");
assert_eq!(
enc.encode(&decoded).unwrap(),
encoding,
"re-encode not identical ({reduced:?})"
);
}
#[test]
fn roundtrip_numeric() {
assert_roundtrip(b"0100000000000017"); assert_roundtrip(b"25595011015340010123456789");
assert_roundtrip(b"100000000000"); assert_roundtrip(b"1012"); assert_roundtrip(b"10123"); }
#[test]
fn roundtrip_alphanumeric() {
assert_roundtrip(b"1012A");
assert_roundtrip(b"10ABCDEFG");
assert_roundtrip(b"10AB-123");
assert_roundtrip(b"10A1B2C3D4"); assert_roundtrip(b"10ABC123XYZ789");
}
#[test]
fn roundtrip_isoiec646() {
assert_roundtrip(b"10abcdef"); assert_roundtrip(b"10a1b2c3");
assert_roundtrip(b"10Aa!Bb?"); assert_roundtrip(b"10x=y_z:w");
}
#[test]
fn roundtrip_mixed_and_fnc1() {
assert_roundtrip(b"01095011015300031714070410AB-123");
assert_roundtrip(b"2559501101534001\x1d171605313902050");
assert_roundtrip(b"10ABC\x1d213456"); assert_roundtrip(b"10abc\x1d213456"); assert_roundtrip(b"3712\x1d10ABCabc123"); }
#[test]
fn roundtrip_method1_variants() {
assert_roundtrip(b"0100000000000017"); assert_roundtrip(b"010950110153000317140704"); assert_roundtrip(b"01095011015300031012345"); assert_roundtrip(b"0109501101530003102ABC"); }
#[test]
fn roundtrip_sweep() {
let alphabet: &[u8] = b"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz*-. :?_";
let mut state: u64 = 0x1234_5678_9abc_def1;
let mut next = || {
state = state
.wrapping_mul(6_364_136_223_846_793_005)
.wrapping_add(1_442_695_040_888_963_407);
(state >> 33) as usize
};
let enc = DataBarEncoder::new();
let mut exercised = 0;
for _ in 0..3000 {
let len = 1 + next() % 40;
let payload: Vec<u8> = (0..len)
.map(|_| alphabet[next() % alphabet.len()])
.collect();
if enc.build_expanded(&payload).is_ok() {
assert_roundtrip(&payload);
exercised += 1;
}
}
assert!(
exercised > 2000,
"sweep exercised too few payloads: {exercised}"
);
}
#[test]
fn symbol_grows_with_data() {
let enc = DataBarEncoder::new();
let payloads: [Vec<u8>; 4] = [
b"10".to_vec(),
[b"10".as_slice(), &[b'0'; 20]].concat(),
[b"10".as_slice(), &[b'0'; 40]].concat(),
[b"10".as_slice(), &[b'0'; 60]].concat(),
];
let mut prev = 0;
let mut widths = Vec::new();
for n in &payloads {
let Encoding::Linear(p) = enc.encode(&enc.build_expanded(n).unwrap()).unwrap() else {
panic!("linear");
};
assert!(
p.modules.len() >= prev,
"expected non-decreasing width: {} vs {}",
p.modules.len(),
prev
);
prev = p.modules.len();
widths.push(p.modules.len());
}
assert!(widths.last().unwrap() > widths.first().unwrap());
}
#[test]
fn rejects_bad_gtin_check_digit() {
let enc = DataBarEncoder::new();
assert!(enc.build_expanded(b"0100000000000010").is_err());
}
#[test]
fn rejects_invalid_character() {
let enc = DataBarEncoder::new();
assert!(enc.build_expanded(b"10ABC`123").is_err());
}
#[test]
fn rejects_empty_payload() {
let enc = DataBarEncoder::new();
assert!(enc.build_expanded(b"").is_err());
}
#[test]
fn decode_rejects_corrupted_expanded() {
let enc = DataBarEncoder::new();
let dec = DataBarDecoder::new();
let symbol = enc.build_expanded(b"25595011015340010123456789").unwrap();
let Encoding::Linear(mut p) = enc.encode(&symbol).unwrap() else {
panic!("expected linear");
};
for i in [30, 31, 60, 61, 90] {
p.modules[i] = !p.modules[i];
}
assert!(dec.decode(&Encoding::Linear(p)).is_err());
}