smart-package-tracker 0.4.0

Generate package tracking IDs, render them as Code 128 barcodes (PNG and SVG), and read them back out of images
Documentation
//! End-to-end tests exercising the crate the way a consumer would.

#![cfg(feature = "code128")]

use smart_package_tracker::{Barcode, IdGenerator, Length, RenderOptions, TrackingId};

/// The workflow from the README: mint, encode, export.
#[test]
#[cfg(all(feature = "os-rng", feature = "png", feature = "svg"))]
fn documented_workflow_end_to_end() {
    let id = TrackingId::generate().expect("system entropy available");
    assert!(id.as_str().starts_with("PKG-"));
    assert_eq!(id.body().len(), 8);

    let barcode = Barcode::code128(&id).expect("ids are always encodable");
    let options = RenderOptions::default();

    let png = barcode.to_png(&options).expect("png renders");
    let svg = barcode.to_svg(&options).expect("svg renders");

    assert_eq!(&png[..8], b"\x89PNG\r\n\x1a\n");
    assert!(svg.contains("<svg"));
    assert_eq!(barcode.decode().unwrap(), id.as_str());
}

#[test]
#[cfg(feature = "os-rng")]
fn ids_survive_a_storage_round_trip() {
    use smart_package_tracker::Checksum;

    let generator = IdGenerator::builder()
        .entropy_bits(64)
        .checksum(Checksum::Iso7064Mod37_36)
        .build()
        .unwrap();

    let original = generator.generate().unwrap();
    let stored = original.to_string();
    let restored: TrackingId = stored.parse().unwrap();

    assert_eq!(original, restored);
    generator.validate(&restored).unwrap();
}

#[test]
fn a_scanner_reads_back_what_was_encoded() {
    // Payloads a carrier integration might realistically produce.
    for payload in [
        "PKG-9ED9285C",
        "PKG-FFFFFFFFFFFFFFFFZ",
        "1Z999AA10123456784",     // UPS-style
        "770123456789",           // FedEx-style, pure digits
        "9400111899223197428490", // USPS-style, 22 digits
    ] {
        let barcode = Barcode::code128(payload).unwrap();
        assert_eq!(barcode.decode().unwrap(), payload, "failed for {payload}");
    }
}

#[test]
#[cfg(all(feature = "png", feature = "svg"))]
fn png_and_svg_agree_on_geometry() {
    let barcode = Barcode::code128("PKG-9ED9285C").unwrap();
    let options = RenderOptions::default();
    let layout = options.layout(barcode.symbol()).unwrap();

    let svg = barcode.to_svg(&options).unwrap();
    assert!(svg.contains(&format!(
        "viewBox=\"0 0 {} {}\"",
        layout.width_px, layout.height_px
    )));

    let png = barcode.to_png(&options).unwrap();
    let mut reader = png::Decoder::new(std::io::Cursor::new(&png[..]))
        .read_info()
        .unwrap();
    let info = reader
        .next_frame(&mut vec![0; reader.output_buffer_size().unwrap()])
        .unwrap();
    assert_eq!(
        (info.width, info.height),
        (layout.width_px, layout.height_px)
    );
}

#[test]
#[cfg(all(feature = "png", feature = "svg"))]
fn renderers_are_usable_through_the_trait() {
    use smart_package_tracker::render::{Png, Svg};

    let barcode = Barcode::code128("PKG-9ED9285C").unwrap();
    let options = RenderOptions::default();

    let via_trait: Vec<u8> = barcode.render(&Png, &options).unwrap();
    let via_helper = barcode.to_png(&options).unwrap();
    assert_eq!(via_trait, via_helper);

    let via_trait: String = barcode.render(&Svg, &options).unwrap();
    assert_eq!(via_trait, barcode.to_svg(&options).unwrap());
}

#[test]
#[cfg(feature = "os-rng")]
fn a_thousand_ids_at_64_bits_are_all_distinct() {
    let generator = IdGenerator::builder().entropy_bits(64).build().unwrap();
    let ids: std::collections::HashSet<String> = (0..1000)
        .map(|_| generator.generate().unwrap().into_string())
        .collect();
    assert_eq!(ids.len(), 1000);
}

#[test]
fn label_geometry_matches_a_300_dpi_thermal_printer() {
    let barcode = Barcode::code128("PKG-9ED9285C").unwrap();
    let options = RenderOptions::builder()
        .module_width(Length::Mils(13.0))
        .height(Length::Mm(25.0))
        .dpi(300)
        .build()
        .unwrap();

    let layout = options.layout(barcode.symbol()).unwrap();

    // 13 mil at 300 dpi is 3.9 px, snapped to 4.
    assert_eq!(layout.module_px, 4);
    // 25 mm at 300 dpi is 295.3 px.
    assert_eq!(layout.symbol_h_px, 295);
    // The whole label must fit across a standard 4-inch (1200 px) label.
    assert!(
        layout.width_px < 1200,
        "label is {} px wide, wider than a 4 inch label",
        layout.width_px
    );
}

#[test]
fn errors_are_reported_rather_than_panicking() {
    assert!(TrackingId::parse("not a tracking id").is_err());
    assert!(Barcode::code128("").is_err());
    assert!(IdGenerator::builder().entropy_bits(3).build().is_err());
    assert!(RenderOptions::builder().dpi(0).build().is_err());

    let barcode = Barcode::code128("PKG-9ED9285C").unwrap();
    let absurd = RenderOptions::builder()
        .module_width(Length::Inch(100.0))
        .build()
        .unwrap();
    assert!(absurd.layout(barcode.symbol()).is_err());
    #[cfg(feature = "png")]
    assert!(barcode.to_png(&absurd).is_err());
    #[cfg(feature = "svg")]
    assert!(barcode.to_svg(&absurd).is_err());
}

#[test]
fn quiet_zone_default_meets_the_specification() {
    let barcode = Barcode::code128("PKG-9ED9285C").unwrap();
    let layout = RenderOptions::default().layout(barcode.symbol()).unwrap();
    assert_eq!(
        layout.quiet_x_px,
        10 * layout.module_px,
        "Code 128 requires a 10-module quiet zone"
    );
}

#[test]
#[cfg(feature = "png")]
fn output_is_deterministic_across_runs() {
    use smart_package_tracker::{Color, QuietZone};

    let barcode = Barcode::code128("PKG-9ED9285C").unwrap();
    let options = RenderOptions::builder()
        .colors(Color::BLACK, Color::WHITE)
        .quiet_zone(QuietZone::Standard)
        .build()
        .unwrap();

    let a = barcode.to_png(&options).unwrap();
    let b = Barcode::code128("PKG-9ED9285C")
        .unwrap()
        .to_png(&options)
        .unwrap();
    assert_eq!(a, b, "identical inputs must produce identical bytes");
}