From c61c267b0257293ed6be792e49e1a8c7d3a7e746 Mon Sep 17 00:00:00 2001 From: Vinzenz Schroeter Date: Fri, 17 May 2024 21:02:50 +0200 Subject: [PATCH] add more unit tests --- examples/announce/src/main.rs | 3 +- examples/game_of_life/src/main.rs | 2 +- examples/moving_line/src/main.rs | 6 +- examples/random_brightness/src/main.rs | 4 +- servicepoint2/src/bit_vec.rs | 15 +++ servicepoint2/src/command.rs | 153 ++++++++++++++++++++++--- servicepoint2/src/compression.rs | 7 +- shell.nix | 4 + 8 files changed, 167 insertions(+), 27 deletions(-) create mode 100644 shell.nix diff --git a/examples/announce/src/main.rs b/examples/announce/src/main.rs index fea8c07..ff604af 100644 --- a/examples/announce/src/main.rs +++ b/examples/announce/src/main.rs @@ -1,4 +1,5 @@ use clap::Parser; + use servicepoint2::{ByteGrid, Command, Connection, Origin}; #[derive(Parser, Debug)] @@ -43,6 +44,6 @@ fn main() { } connection - .send(Command::Cp437Data(Origin::top_left(), chars).into()) + .send(Command::Cp437Data(Origin(0, 0), chars).into()) .unwrap(); } diff --git a/examples/game_of_life/src/main.rs b/examples/game_of_life/src/main.rs index 49cc4ca..faa44db 100644 --- a/examples/game_of_life/src/main.rs +++ b/examples/game_of_life/src/main.rs @@ -25,7 +25,7 @@ fn main() { connection .send( Command::BitmapLinearWin( - Origin::top_left(), + Origin(0, 0), field.clone(), CompressionCode::Bzip2, ) diff --git a/examples/moving_line/src/main.rs b/examples/moving_line/src/main.rs index ad4e740..31b9a84 100644 --- a/examples/moving_line/src/main.rs +++ b/examples/moving_line/src/main.rs @@ -4,8 +4,8 @@ use std::time::Duration; use clap::Parser; use servicepoint2::{ - Command, CompressionCode, Connection, Origin, PixelGrid, PIXEL_HEIGHT, - PIXEL_WIDTH, + Command, CompressionCode, Connection, Origin, PIXEL_HEIGHT, PIXEL_WIDTH, + PixelGrid, }; #[derive(Parser, Debug)] @@ -29,7 +29,7 @@ fn main() { connection .send( Command::BitmapLinearWin( - Origin::top_left(), + Origin(0, 0), pixels.clone(), CompressionCode::Lzma, ) diff --git a/examples/random_brightness/src/main.rs b/examples/random_brightness/src/main.rs index ea36370..a8a388f 100644 --- a/examples/random_brightness/src/main.rs +++ b/examples/random_brightness/src/main.rs @@ -3,11 +3,11 @@ use std::time::Duration; use clap::Parser; use rand::Rng; -use servicepoint2::Command::{BitmapLinearWin, Brightness, CharBrightness}; use servicepoint2::{ ByteGrid, CompressionCode, Connection, Origin, PixelGrid, TILE_HEIGHT, TILE_WIDTH, }; +use servicepoint2::Command::{BitmapLinearWin, Brightness, CharBrightness}; #[derive(Parser, Debug)] struct Cli { @@ -32,7 +32,7 @@ fn main() { filled_grid.fill(true); let command = BitmapLinearWin( - Origin::top_left(), + Origin(0, 0), filled_grid, CompressionCode::Lzma, ); diff --git a/servicepoint2/src/bit_vec.rs b/servicepoint2/src/bit_vec.rs index 449865e..ebb9499 100644 --- a/servicepoint2/src/bit_vec.rs +++ b/servicepoint2/src/bit_vec.rs @@ -285,4 +285,19 @@ mod tests { let vec = BitVec::new(0); assert!(vec.is_empty()); } + + #[test] + fn get_returns_old() { + let mut vec = BitVec::new(8); + assert_eq!(vec.set(1, true), false); + assert_eq!(vec.set(1, true), true); + assert_eq!(vec.set(1, false), true); + assert_eq!(vec.set(1, false), false); + } + + #[test] + fn debug_print() { + let vec = BitVec::new(8 * 3); + format!("{vec:?}"); + } } diff --git a/servicepoint2/src/command.rs b/servicepoint2/src/command.rs index 7832228..8d7c34d 100644 --- a/servicepoint2/src/command.rs +++ b/servicepoint2/src/command.rs @@ -1,19 +1,13 @@ -use crate::command_code::CommandCode; -use crate::compression::{into_compressed, into_decompressed}; use crate::{ BitVec, ByteGrid, CompressionCode, Header, Packet, PixelGrid, TILE_SIZE, }; +use crate::command_code::CommandCode; +use crate::compression::{into_compressed, into_decompressed}; /// An origin marks the top left position of a window sent to the display. #[derive(Debug, Clone, Copy, PartialEq)] pub struct Origin(pub u16, pub u16); -impl Origin { - pub fn top_left() -> Self { - Self(0, 0) - } -} - /// Size defines the width and height of a window #[derive(Debug, Clone, Copy)] pub struct Size(pub u16, pub u16); @@ -164,6 +158,7 @@ impl From for Packet { #[derive(Debug)] /// Err values for `Command::try_from`. +#[derive(PartialEq)] pub enum TryFromPacketError { /// the contained command code does not correspond to a known command InvalidCommand(u16), @@ -526,9 +521,9 @@ pub mod c_api { #[cfg(test)] mod tests { - use crate::{ - BitVec, ByteGrid, Command, CompressionCode, Origin, Packet, PixelGrid, - }; + use crate::{BitVec, ByteGrid, Command, CompressionCode, Header, Origin, Packet, PixelGrid}; + use crate::command::TryFromPacketError; + use crate::command_code::CommandCode; fn round_trip(original: Command) { let packet: Packet = original.clone().into(); @@ -539,6 +534,16 @@ mod tests { assert_eq!(copy, original); } + fn all_compressions() -> [CompressionCode; 5] { + [ + CompressionCode::Uncompressed, + CompressionCode::Lzma, + CompressionCode::Bzip2, + CompressionCode::Zlib, + CompressionCode::Zstd, + ] + } + #[test] fn round_trip_clear() { round_trip(Command::Clear); @@ -577,14 +582,7 @@ mod tests { #[test] fn round_trip_bitmap_linear() { - let codes = [ - CompressionCode::Uncompressed, - CompressionCode::Lzma, - CompressionCode::Bzip2, - CompressionCode::Zlib, - CompressionCode::Zstd, - ]; - for compression in codes { + for compression in all_compressions() { round_trip(Command::BitmapLinear(23, BitVec::new(40), compression)); round_trip(Command::BitmapLinearAnd( 23, @@ -608,4 +606,121 @@ mod tests { )); } } + + #[test] + fn error_invalid_command() { + let p = Packet(Header(0xFF, 0x00, 0x00, 0x00, 0x00), vec!()); + let result = Command::try_from(p); + assert!(matches!(result, Err(TryFromPacketError::InvalidCommand(0xFF)))) + } + + #[test] + fn error_extraneous_header_values_clear() { + let p = Packet(Header(CommandCode::Clear.into(), 0x05, 0x00, 0x00, 0x00), vec!()); + let result = Command::try_from(p); + assert!(matches!(result, Err(TryFromPacketError::ExtraneousHeaderValues))) + } + + #[test] + fn error_extraneous_header_values_brightness() { + let p = Packet(Header(CommandCode::Brightness.into(), 0x00, 0x13, 0x37, 0x00), vec!(5)); + let result = Command::try_from(p); + assert!(matches!(result, Err(TryFromPacketError::ExtraneousHeaderValues))) + } + + #[test] + fn error_extraneous_header_hard_reset() { + let p = Packet(Header(CommandCode::HardReset.into(), 0x00, 0x00, 0x00, 0x01), vec!()); + let result = Command::try_from(p); + assert!(matches!(result, Err(TryFromPacketError::ExtraneousHeaderValues))) + } + + #[test] + fn error_extraneous_header_fade_out() { + let p = Packet(Header(CommandCode::FadeOut.into(), 0x10, 0x00, 0x00, 0x01), vec!()); + let result = Command::try_from(p); + assert!(matches!(result, Err(TryFromPacketError::ExtraneousHeaderValues))) + } + + #[test] + fn error_unexpected_payload() { + let p = Packet(Header(CommandCode::FadeOut.into(), 0x00, 0x00, 0x00, 0x00), vec!(5, 7)); + let result = Command::try_from(p); + assert!(matches!(result, Err(TryFromPacketError::UnexpectedPayloadSize(0, 2)))) + } + + #[test] + fn error_decompression_failed_win() { + for compression in all_compressions() { + let p: Packet = Command::BitmapLinearWin(Origin(16, 8), PixelGrid::new(8, 8), compression).into(); + let Packet(header, mut payload) = p; + + // mangle it + for i in 0..payload.len() { + payload[i] -= payload[i] / 2; + } + + let p = Packet(header, payload); + let result = Command::try_from(p); + if compression != CompressionCode::Uncompressed { + assert_eq!(result, Err(TryFromPacketError::DecompressionFailed)) + } else { + assert!(matches!(result, Ok(_))); + } + } + } + + #[test] + fn error_decompression_failed_and() { + for compression in all_compressions() { + let p: Packet = Command::BitmapLinearAnd(0, BitVec::new(8), compression).into(); + let Packet(header, mut payload) = p; + + // mangle it + for i in 0..payload.len() { + payload[i] -= payload[i] / 2; + } + + let p = Packet(header, payload); + let result = Command::try_from(p); + if compression != CompressionCode::Uncompressed { + assert_eq!(result, Err(TryFromPacketError::DecompressionFailed)) + } else { + assert!(matches!(result, Ok(_))); + } + } + } + + #[test] + fn unexpected_payload_size_brightness() { + assert_eq!( + Command::try_from(Packet(Header(CommandCode::Brightness.into(), 0, 0, 0, 0), vec!())), + Err(TryFromPacketError::UnexpectedPayloadSize(1, 0))); + + assert_eq!( + Command::try_from(Packet(Header(CommandCode::Brightness.into(), 0, 0, 0, 0), vec!(0, 0))), + Err(TryFromPacketError::UnexpectedPayloadSize(1, 2))); + } + + /* TODO unexpected payload size + + /// Set the brightness of tiles + CharBrightness(Origin, crate::byte_grid::ByteGrid), + /// Set pixel data starting at the offset. + /// The contained BitVec is always uncompressed. + BitmapLinear(Offset, crate::bit_vec::BitVec, crate::compression_code::CompressionCode), + /// Set pixel data according to an and-mask starting at the offset. + /// The contained BitVec is always uncompressed. + BitmapLinearAnd(Offset, crate::bit_vec::BitVec, crate::compression_code::CompressionCode), + /// Set pixel data according to an or-mask starting at the offset. + /// The contained BitVec is always uncompressed. + BitmapLinearOr(Offset, crate::bit_vec::BitVec, crate::compression_code::CompressionCode), + /// Set pixel data according to an xor-mask starting at the offset. + /// The contained BitVec is always uncompressed. + BitmapLinearXor(Offset, crate::bit_vec::BitVec, crate::compression_code::CompressionCode), + /// Show text on the screen. Note that the byte data has to be CP437 encoded. + Cp437Data(Origin, crate::byte_grid::ByteGrid), + /// Sets a window of pixels to the specified values + BitmapLinearWin(Origin, crate::pixel_grid::PixelGrid, crate::compression_code::CompressionCode), + */ } diff --git a/servicepoint2/src/compression.rs b/servicepoint2/src/compression.rs index a0a78b0..3ed90d4 100644 --- a/servicepoint2/src/compression.rs +++ b/servicepoint2/src/compression.rs @@ -48,7 +48,12 @@ pub(crate) fn into_decompressed( } } #[cfg(feature = "compression_lzma")] - CompressionCode::Lzma => Some(lzma::decompress(&payload).unwrap()), + CompressionCode::Lzma => { + match lzma::decompress(&payload) { + Err(_) => None, + Ok(decompressed) => Some(decompressed), + } + } #[cfg(feature = "compression_zstd")] CompressionCode::Zstd => { let mut decoder = match ZstdDecoder::new(&*payload) { diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..c961482 --- /dev/null +++ b/shell.nix @@ -0,0 +1,4 @@ +{ pkgs ? import {} }: + pkgs.mkShell { + nativeBuildInputs = with pkgs.buildPackages; [ rustup pkg-config xe lzma cargo-tarpaulin ]; +}