use thermark::errors::PrinterFault;
use thermark::geometry::{LabelMm, PX_PER_MM};
use thermark::label::{
QrLabelOptions, TextSide, make_qr_label_opts, max_qr_side, render_qr_square,
};
use thermark::packet::Packet;
use thermark::print_task::PrintTask;
use thermark::printer::{Pacing, PrinterClient};
use thermark::protocol::{self, Model};
use thermark::types::Density;
#[test]
fn b1_print_start_roundtrip() {
let p = PrintTask::B1.print_start(1);
assert_eq!(p.cmd, 0x01);
assert_eq!(p.data.len(), 7);
assert_eq!(&p.data[0..2], &1u16.to_be_bytes());
let enc = p.encode().unwrap();
let dec = Packet::decode(&enc).unwrap();
assert_eq!(dec, p);
}
#[test]
fn b1_page_size_matches_50x30() {
let profile = thermark::profile_for_model(Model::B1);
let lp = LabelMm::parse("50x30")
.unwrap()
.to_pixels(profile.max_width_px, profile.pixels_per_mm());
let p = PrintTask::B1.set_page_size(lp.height_px as u16, lp.width_px as u16, 1);
assert_eq!(p.cmd, 0x13);
assert_eq!(p.data.len(), 6);
let rows = u16::from_be_bytes([p.data[0], p.data[1]]);
let cols = u16::from_be_bytes([p.data[2], p.data[3]]);
let copies = u16::from_be_bytes([p.data[4], p.data[5]]);
assert_eq!(rows, 240);
assert_eq!(cols, 384);
assert_eq!(copies, 1);
Packet::decode(&p.encode().unwrap()).unwrap();
}
#[test]
fn density_and_label_type_packets() {
let d = protocol::set_density(4);
assert_eq!(d.encode().unwrap()[2], 0x21);
let t = protocol::set_label_type(1);
assert_eq!(t.encode().unwrap()[2], 0x23);
}
#[test]
fn error_codes_cover_and_paper() {
assert_eq!(PrinterFault::from_u8(0x01), PrinterFault::COVER_OPEN);
assert_eq!(PrinterFault::from_u8(0x02), PrinterFault::NO_PAPER);
let s = format!("{}", PrinterFault::from_u8(0x01));
assert!(s.contains("Cover") || s.contains("open") || s.contains("0x01"));
}
#[test]
fn model_max_widths() {
assert_eq!(thermark::profile_for_model(Model::B1).max_width_px, 384);
assert_eq!(thermark::profile_for_model(Model::D11).max_width_px, 96);
assert_eq!(Model::parse("b1"), Some(Model::B1));
assert_eq!(Model::parse("B21PRO"), Some(Model::B21Pro));
assert!(Model::parse("nope").is_none());
}
#[test]
fn qr_label_exact_canvas_and_square_qr() {
let lp = LabelMm::parse("50x30").unwrap().to_pixels(384, 8.0);
let img = make_qr_label_opts(&QrLabelOptions {
url: "https://www.youtube.com".into(),
side_text: "ABC\n123".into(),
label: lp,
safe: thermark::geometry::SafeArea::default(),
text_side: TextSide::Right,
border: false,
font_path: Some(
std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/fonts/DejaVuSans.ttf"),
),
font_name: None,
font_size: None,
})
.expect("layout");
assert_eq!(img.dimensions(), (384, 240));
let safe = thermark::geometry::SafeArea::default();
let printable_h = lp.height_px - safe.top - safe.bottom;
let side = max_qr_side(lp, safe);
assert!(
side >= printable_h - 16,
"QR should use most of the printable height {printable_h}, got {side}"
);
assert!(
side <= printable_h,
"QR {side} must not exceed the printable height {printable_h}"
);
let qr = render_qr_square("https://example.com", side).unwrap();
assert_eq!(qr.dimensions(), (side, side));
}
#[test]
fn px_per_mm_constant() {
assert!((PX_PER_MM - 8.0).abs() < f64::EPSILON);
assert_eq!(LabelMm::new(50.0, 30.0).to_pixels(384, 8.0).width_px, 384);
}
#[test]
fn packet_buffer_resync() {
let good = Packet::new(0x40, vec![0x0b]).encode().unwrap();
let mut buf = vec![0x00, 0xFF];
buf.extend_from_slice(&good);
let pkts = Packet::drain_buffer(&mut buf);
assert_eq!(pkts.len(), 1);
assert_eq!(pkts[0].cmd, 0x40);
}
#[tokio::test]
async fn low_level_commands_require_the_explicit_raw_api() {
let mut client =
PrinterClient::new(thermark::MockTransport::new(), Model::B1).with_pacing(Pacing::INSTANT);
assert!(client.raw().set_density(Density::DARK).await.unwrap());
assert_eq!(client.transport().tx_cmds(), [0x21]);
}