release: escpos-vfd 0.3.0
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
use escpos_vfd::codec::EpsonCodec;
|
||||
use escpos_vfd::{
|
||||
ConfigError, DisplaySettings, MAX_MARQUEE_CHARS, MAX_MARQUEE_CPS, MAX_QUEUED_RAW_BYTES,
|
||||
TextEncoding, Vfd, VfdError, VfdWorker,
|
||||
};
|
||||
use std::time::Duration;
|
||||
|
||||
#[test]
|
||||
fn public_text_api_neutralizes_controls_and_legacy_fallback_is_one_byte() {
|
||||
let display = DisplaySettings::new(8, 1, TextEncoding::Ascii);
|
||||
let mut vfd = Vfd::from_transport(Vec::<u8>::new(), display).unwrap();
|
||||
vfd.print_line(1, "A\u{1b}@B\u{0c}C").unwrap();
|
||||
assert_eq!(&vfd.into_inner()[6..], b"A @B C ");
|
||||
|
||||
for encoding in [TextEncoding::Cp866, TextEncoding::Windows1251] {
|
||||
let codec = EpsonCodec::new(DisplaySettings::new(1, 1, encoding)).unwrap();
|
||||
assert_eq!(codec.encode_text("😀"), vec![b'?']);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn public_codec_constructor_returns_geometry_errors() {
|
||||
assert!(matches!(
|
||||
EpsonCodec::new(DisplaySettings::new(usize::MAX, 1, TextEncoding::Ascii)),
|
||||
Err(ConfigError::InvalidColumns(usize::MAX))
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sync_worker_enforces_payload_and_rate_boundaries() {
|
||||
let display = DisplaySettings::new(20, 2, TextEncoding::Ascii);
|
||||
let worker = VfdWorker::from_transport(Vec::<u8>::new(), display, 2).unwrap();
|
||||
let handle = worker.handle();
|
||||
|
||||
handle.print_line(1, "x".repeat(1_000_000)).unwrap();
|
||||
handle
|
||||
.set_marquee_text("m".repeat(MAX_MARQUEE_CHARS))
|
||||
.unwrap();
|
||||
assert!(matches!(
|
||||
handle.set_marquee_text("m".repeat(MAX_MARQUEE_CHARS + 1)),
|
||||
Err(VfdError::TextTooLong { .. })
|
||||
));
|
||||
|
||||
handle.write_raw(vec![0; MAX_QUEUED_RAW_BYTES]).unwrap();
|
||||
assert!(matches!(
|
||||
handle.write_raw(vec![0; MAX_QUEUED_RAW_BYTES + 1]),
|
||||
Err(VfdError::RawPayloadTooLarge { .. })
|
||||
));
|
||||
|
||||
handle
|
||||
.start_marquee(2, MAX_MARQUEE_CPS, Duration::ZERO)
|
||||
.unwrap();
|
||||
handle.stop_marquee().unwrap();
|
||||
assert!(matches!(
|
||||
handle.start_marquee(2, MAX_MARQUEE_CPS + 1, Duration::ZERO),
|
||||
Err(VfdError::InvalidMarqueeSpeed { .. })
|
||||
));
|
||||
|
||||
let bytes = worker.shutdown().unwrap().into_inner();
|
||||
assert!(bytes.windows(20).any(|window| window == [b'x'; 20]));
|
||||
}
|
||||
|
||||
#[cfg(feature = "tokio")]
|
||||
#[tokio::test]
|
||||
async fn tokio_public_api_matches_security_boundaries() {
|
||||
use escpos_vfd::tokio::{AsyncVfd, AsyncVfdWorker};
|
||||
|
||||
let display = DisplaySettings::new(8, 1, TextEncoding::Ascii);
|
||||
let mut vfd = AsyncVfd::from_transport(Vec::<u8>::new(), display)
|
||||
.await
|
||||
.unwrap();
|
||||
vfd.print_line(1, "A\u{1b}@B\u{0c}C").await.unwrap();
|
||||
assert_eq!(&vfd.into_inner()[6..], b"A @B C ");
|
||||
|
||||
let display = DisplaySettings::new(20, 2, TextEncoding::Ascii);
|
||||
let worker = AsyncVfdWorker::from_transport(Vec::<u8>::new(), display, 2)
|
||||
.await
|
||||
.unwrap();
|
||||
let handle = worker.handle();
|
||||
assert!(matches!(
|
||||
handle
|
||||
.set_marquee_text("m".repeat(MAX_MARQUEE_CHARS + 1))
|
||||
.await,
|
||||
Err(VfdError::TextTooLong { .. })
|
||||
));
|
||||
assert!(matches!(
|
||||
handle.write_raw(vec![0; MAX_QUEUED_RAW_BYTES + 1]).await,
|
||||
Err(VfdError::RawPayloadTooLarge { .. })
|
||||
));
|
||||
assert!(matches!(
|
||||
handle
|
||||
.start_marquee(1, MAX_MARQUEE_CPS + 1, Duration::ZERO)
|
||||
.await,
|
||||
Err(VfdError::InvalidMarqueeSpeed { .. })
|
||||
));
|
||||
worker.shutdown().await.unwrap();
|
||||
}
|
||||
Reference in New Issue
Block a user