move tests to the module they test
This commit is contained in:
parent
c8a38870d1
commit
7cd26cd50e
17 changed files with 628 additions and 502 deletions
|
|
@ -35,9 +35,7 @@ fn main() {
|
|||
.expect("could not connect to display");
|
||||
|
||||
if cli.clear {
|
||||
connection
|
||||
.send(ClearCommand)
|
||||
.expect("sending clear failed");
|
||||
connection.send(ClearCommand).expect("sending clear failed");
|
||||
}
|
||||
|
||||
let text = cli.text.join("\n");
|
||||
|
|
@ -45,7 +43,5 @@ fn main() {
|
|||
origin: Origin::ZERO,
|
||||
grid: CharGrid::wrap_str(TILE_WIDTH, &text),
|
||||
};
|
||||
connection
|
||||
.send(command)
|
||||
.expect("sending text failed");
|
||||
connection.send(command).expect("sending text failed");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{
|
||||
commands::TryFromPacketError, command_code::CommandCode,
|
||||
command_code::CommandCode, commands::TryFromPacketError,
|
||||
compression::into_compressed, compression::into_decompressed, Bitmap,
|
||||
CompressionCode, Grid, Header, Origin, Packet, Pixels, TypedCommand,
|
||||
TILE_SIZE,
|
||||
|
|
@ -150,8 +150,64 @@ impl BitmapCommand {
|
|||
tile_w as usize * TILE_SIZE,
|
||||
pixel_h as usize,
|
||||
&payload,
|
||||
).unwrap(),
|
||||
)
|
||||
.unwrap(),
|
||||
compression,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::command_code::CommandCode;
|
||||
use crate::{
|
||||
commands, Bitmap, BitmapCommand, CompressionCode, Header, Origin,
|
||||
Packet, TryFromPacketError, TypedCommand,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn command_code() {
|
||||
assert_eq!(
|
||||
BitmapCommand::try_from(Packet {
|
||||
payload: vec![],
|
||||
header: Header {
|
||||
command_code: CommandCode::Brightness.into(),
|
||||
..Default::default()
|
||||
}
|
||||
}),
|
||||
Err(TryFromPacketError::InvalidCommand(
|
||||
CommandCode::Brightness.into()
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_decompression_failed_win() {
|
||||
for compression in CompressionCode::ALL {
|
||||
let p: Packet = commands::BitmapCommand {
|
||||
origin: Origin::new(16, 8),
|
||||
bitmap: Bitmap::new(8, 8).unwrap(),
|
||||
compression,
|
||||
}
|
||||
.into();
|
||||
|
||||
let Packet {
|
||||
header,
|
||||
mut payload,
|
||||
} = p;
|
||||
|
||||
// mangle it
|
||||
for byte in payload.iter_mut() {
|
||||
*byte -= *byte / 2;
|
||||
}
|
||||
|
||||
let p = Packet { header, payload };
|
||||
let result = TypedCommand::try_from(p);
|
||||
if compression != CompressionCode::Uncompressed {
|
||||
assert_eq!(result, Err(TryFromPacketError::DecompressionFailed))
|
||||
} else {
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use crate::{
|
||||
commands::check_command_code_only, commands::TryFromPacketError,
|
||||
command_code::CommandCode, Packet, TypedCommand,
|
||||
command_code::CommandCode, commands::check_command_code_only,
|
||||
commands::TryFromPacketError, Packet, TypedCommand,
|
||||
};
|
||||
use std::fmt::Debug;
|
||||
|
||||
|
|
@ -49,3 +49,31 @@ impl From<BitmapLegacyCommand> for TypedCommand {
|
|||
Self::BitmapLegacy(command)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(deprecated)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::commands::tests::round_trip;
|
||||
use crate::Header;
|
||||
|
||||
#[test]
|
||||
fn invalid_fields() {
|
||||
assert_eq!(
|
||||
BitmapLegacyCommand::try_from(Packet {
|
||||
header: Header {
|
||||
command_code: CommandCode::BitmapLegacy.into(),
|
||||
a: 1,
|
||||
..Default::default()
|
||||
},
|
||||
payload: vec![],
|
||||
}),
|
||||
Err(TryFromPacketError::ExtraneousHeaderValues)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip_bitmap_legacy() {
|
||||
round_trip(BitmapLegacyCommand.into());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,9 +25,9 @@ pub enum BinaryOperation {
|
|||
/// once the starting row is full, overwriting will continue on column 0.
|
||||
///
|
||||
/// The [BinaryOperation] will be applied on the display comparing old and sent bit.
|
||||
///
|
||||
///
|
||||
/// `new_bit = old_bit op sent_bit`
|
||||
///
|
||||
///
|
||||
/// For example, [BinaryOperation::Or] can be used to turn on some pixels without affecting other pixels.
|
||||
///
|
||||
/// The contained [BitVec] is always uncompressed.
|
||||
|
|
@ -131,3 +131,186 @@ impl From<BitVecCommand> for TypedCommand {
|
|||
Self::BitVec(command)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::commands::tests::round_trip;
|
||||
use crate::{commands, Bitmap, BitmapCommand, Origin};
|
||||
|
||||
#[test]
|
||||
fn command_code() {
|
||||
assert_eq!(
|
||||
BitVecCommand::try_from(Packet {
|
||||
payload: vec![],
|
||||
header: Header {
|
||||
command_code: CommandCode::Brightness.into(),
|
||||
..Default::default()
|
||||
}
|
||||
}),
|
||||
Err(TryFromPacketError::InvalidCommand(
|
||||
CommandCode::Brightness.into()
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip_bitmap_linear() {
|
||||
for compression in CompressionCode::ALL {
|
||||
for operation in [
|
||||
BinaryOperation::Overwrite,
|
||||
BinaryOperation::And,
|
||||
BinaryOperation::Or,
|
||||
BinaryOperation::Xor,
|
||||
] {
|
||||
round_trip(
|
||||
BitVecCommand {
|
||||
offset: 23,
|
||||
bitvec: BitVec::repeat(false, 40),
|
||||
compression,
|
||||
operation,
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
round_trip(
|
||||
BitmapCommand {
|
||||
origin: Origin::ZERO,
|
||||
bitmap: Bitmap::max_sized(),
|
||||
compression,
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_decompression_failed_and() {
|
||||
for compression in CompressionCode::ALL {
|
||||
let p: Packet = commands::BitVecCommand {
|
||||
offset: 0,
|
||||
bitvec: BitVec::repeat(false, 8),
|
||||
compression,
|
||||
operation: BinaryOperation::Overwrite,
|
||||
}
|
||||
.into();
|
||||
let Packet {
|
||||
header,
|
||||
mut payload,
|
||||
} = p;
|
||||
|
||||
// mangle it
|
||||
for byte in payload.iter_mut() {
|
||||
*byte -= *byte / 2;
|
||||
}
|
||||
|
||||
let p = Packet { header, payload };
|
||||
let result = TypedCommand::try_from(p);
|
||||
if compression != CompressionCode::Uncompressed {
|
||||
assert_eq!(result, Err(TryFromPacketError::DecompressionFailed))
|
||||
} else {
|
||||
// when not compressing, there is no way to detect corrupted data
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_reserved_used() {
|
||||
let Packet { header, payload } = commands::BitVecCommand {
|
||||
offset: 0,
|
||||
bitvec: BitVec::repeat(false, 8),
|
||||
compression: CompressionCode::Uncompressed,
|
||||
operation: BinaryOperation::Or,
|
||||
}
|
||||
.into();
|
||||
let Header {
|
||||
command_code: command,
|
||||
a: offset,
|
||||
b: length,
|
||||
c: sub,
|
||||
d: _reserved,
|
||||
} = header;
|
||||
let p = Packet {
|
||||
header: Header {
|
||||
command_code: command,
|
||||
a: offset,
|
||||
b: length,
|
||||
c: sub,
|
||||
d: 69,
|
||||
},
|
||||
payload,
|
||||
};
|
||||
assert_eq!(
|
||||
TypedCommand::try_from(p),
|
||||
Err(TryFromPacketError::ExtraneousHeaderValues)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_invalid_compression() {
|
||||
let Packet { header, payload } = commands::BitVecCommand {
|
||||
offset: 0,
|
||||
bitvec: BitVec::repeat(false, 8),
|
||||
compression: CompressionCode::Uncompressed,
|
||||
operation: BinaryOperation::And,
|
||||
}
|
||||
.into();
|
||||
let Header {
|
||||
command_code: command,
|
||||
a: offset,
|
||||
b: length,
|
||||
c: _sub,
|
||||
d: reserved,
|
||||
} = header;
|
||||
let p = Packet {
|
||||
header: Header {
|
||||
command_code: command,
|
||||
a: offset,
|
||||
b: length,
|
||||
c: 42,
|
||||
d: reserved,
|
||||
},
|
||||
payload,
|
||||
};
|
||||
assert_eq!(
|
||||
TypedCommand::try_from(p),
|
||||
Err(TryFromPacketError::InvalidCompressionCode(42))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_unexpected_size() {
|
||||
let Packet { header, payload } = commands::BitVecCommand {
|
||||
offset: 0,
|
||||
bitvec: BitVec::repeat(false, 8),
|
||||
compression: CompressionCode::Uncompressed,
|
||||
operation: BinaryOperation::Xor,
|
||||
}
|
||||
.into();
|
||||
let Header {
|
||||
command_code: command,
|
||||
a: offset,
|
||||
b: length,
|
||||
c: compression,
|
||||
d: reserved,
|
||||
} = header;
|
||||
let p = Packet {
|
||||
header: Header {
|
||||
command_code: command,
|
||||
a: offset,
|
||||
b: 420,
|
||||
c: compression,
|
||||
d: reserved,
|
||||
},
|
||||
payload,
|
||||
};
|
||||
assert_eq!(
|
||||
TypedCommand::try_from(p),
|
||||
Err(TryFromPacketError::UnexpectedPayloadSize(
|
||||
420,
|
||||
length as usize,
|
||||
))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use crate::{
|
||||
commands::TryFromPacketError, command_code::CommandCode, Brightness, Header,
|
||||
Packet, TypedCommand,
|
||||
command_code::CommandCode, commands::TryFromPacketError, Brightness,
|
||||
Header, Packet, TypedCommand,
|
||||
};
|
||||
|
||||
/// Set the brightness of all tiles to the same value.
|
||||
|
|
@ -81,13 +81,94 @@ impl From<Brightness> for BrightnessCommand {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{Brightness, BrightnessCommand};
|
||||
use crate::command_code::CommandCode;
|
||||
use crate::commands::tests::round_trip;
|
||||
use crate::{
|
||||
commands, Brightness, BrightnessCommand, Header, Packet,
|
||||
TryFromPacketError, TypedCommand,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn brightness_as_command() {
|
||||
assert_eq!(
|
||||
BrightnessCommand { brightness: Brightness::MAX },
|
||||
BrightnessCommand {
|
||||
brightness: Brightness::MAX
|
||||
},
|
||||
Brightness::MAX.into()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip_brightness() {
|
||||
round_trip(
|
||||
BrightnessCommand {
|
||||
brightness: Brightness::try_from(6).unwrap(),
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_extraneous_header_values() {
|
||||
let p = Packet {
|
||||
header: Header {
|
||||
command_code: CommandCode::Brightness.into(),
|
||||
a: 0x00,
|
||||
b: 0x13,
|
||||
c: 0x37,
|
||||
d: 0x00,
|
||||
},
|
||||
payload: vec![5],
|
||||
};
|
||||
let result = TypedCommand::try_from(p);
|
||||
assert!(matches!(
|
||||
result,
|
||||
Err(TryFromPacketError::ExtraneousHeaderValues)
|
||||
))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unexpected_payload_size_brightness() {
|
||||
assert_eq!(
|
||||
TypedCommand::try_from(Packet {
|
||||
header: Header {
|
||||
command_code: CommandCode::Brightness.into(),
|
||||
a: 0,
|
||||
b: 0,
|
||||
c: 0,
|
||||
d: 0,
|
||||
},
|
||||
payload: vec!()
|
||||
}),
|
||||
Err(TryFromPacketError::UnexpectedPayloadSize(1, 0))
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
TypedCommand::try_from(Packet {
|
||||
header: Header {
|
||||
command_code: CommandCode::Brightness.into(),
|
||||
a: 0,
|
||||
b: 0,
|
||||
c: 0,
|
||||
d: 0,
|
||||
},
|
||||
payload: vec!(0, 0)
|
||||
}),
|
||||
Err(TryFromPacketError::UnexpectedPayloadSize(1, 2))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn packet_into_brightness_invalid() {
|
||||
let mut packet: Packet = commands::BrightnessCommand {
|
||||
brightness: Brightness::MAX,
|
||||
}
|
||||
.into();
|
||||
let slot = packet.payload.get_mut(0).unwrap();
|
||||
*slot = 42;
|
||||
assert_eq!(
|
||||
TypedCommand::try_from(packet),
|
||||
Err(TryFromPacketError::InvalidBrightness(42))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{
|
||||
commands::TryFromPacketError, command_code::CommandCode, BrightnessGrid,
|
||||
command_code::CommandCode, commands::TryFromPacketError, BrightnessGrid,
|
||||
ByteGrid, Header, Origin, Packet, Tiles, TypedCommand,
|
||||
};
|
||||
|
||||
|
|
@ -56,3 +56,39 @@ impl From<BrightnessGridCommand> for TypedCommand {
|
|||
Self::BrightnessGrid(command)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::commands::tests::round_trip;
|
||||
use crate::{
|
||||
commands, BrightnessGrid, BrightnessGridCommand, Origin, Packet,
|
||||
TryFromPacketError, TypedCommand,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn round_trip_char_brightness() {
|
||||
round_trip(
|
||||
BrightnessGridCommand {
|
||||
origin: Origin::new(5, 2),
|
||||
grid: BrightnessGrid::new(7, 5),
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn packet_into_char_brightness_invalid() {
|
||||
let grid = BrightnessGrid::new(2, 2);
|
||||
let command = commands::BrightnessGridCommand {
|
||||
origin: Origin::ZERO,
|
||||
grid,
|
||||
};
|
||||
let mut packet: Packet = command.into();
|
||||
let slot = packet.payload.get_mut(1).unwrap();
|
||||
*slot = 23;
|
||||
assert_eq!(
|
||||
TypedCommand::try_from(packet),
|
||||
Err(TryFromPacketError::InvalidBrightness(23))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{
|
||||
commands::TryFromPacketError, command_code::CommandCode, CharGrid, Header,
|
||||
command_code::CommandCode, commands::TryFromPacketError, CharGrid, Header,
|
||||
Origin, Packet, Tiles, TypedCommand,
|
||||
};
|
||||
|
||||
|
|
@ -62,3 +62,20 @@ impl From<CharGridCommand> for TypedCommand {
|
|||
Self::CharGrid(command)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::commands::tests::round_trip;
|
||||
use crate::{CharGrid, CharGridCommand, Origin};
|
||||
|
||||
#[test]
|
||||
fn round_trip_utf8_data() {
|
||||
round_trip(
|
||||
CharGridCommand {
|
||||
origin: Origin::new(5, 2),
|
||||
grid: CharGrid::new(7, 5),
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use crate::{
|
||||
commands::check_command_code_only, commands::TryFromPacketError,
|
||||
command_code::CommandCode, Packet, TypedCommand,
|
||||
command_code::CommandCode, commands::check_command_code_only,
|
||||
commands::TryFromPacketError, Packet, TypedCommand,
|
||||
};
|
||||
use std::fmt::Debug;
|
||||
|
||||
|
|
@ -39,3 +39,33 @@ impl From<ClearCommand> for TypedCommand {
|
|||
Self::Clear(command)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::Header;
|
||||
|
||||
#[test]
|
||||
fn round_trip_clear() {
|
||||
crate::commands::tests::round_trip(ClearCommand.into());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_extraneous_header_values_clear() {
|
||||
let p = Packet {
|
||||
header: Header {
|
||||
command_code: CommandCode::Clear.into(),
|
||||
a: 0x05,
|
||||
b: 0x00,
|
||||
c: 0x00,
|
||||
d: 0x00,
|
||||
},
|
||||
payload: vec![],
|
||||
};
|
||||
let result = TypedCommand::try_from(p);
|
||||
assert!(matches!(
|
||||
result,
|
||||
Err(TryFromPacketError::ExtraneousHeaderValues)
|
||||
))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{
|
||||
commands::TryFromPacketError, command_code::CommandCode, Cp437Grid, Header,
|
||||
command_code::CommandCode, commands::TryFromPacketError, Cp437Grid, Header,
|
||||
Origin, Packet, Tiles, TypedCommand,
|
||||
};
|
||||
|
||||
|
|
@ -71,3 +71,20 @@ impl From<Cp437GridCommand> for TypedCommand {
|
|||
Self::Cp437Grid(command)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::commands::tests::round_trip;
|
||||
|
||||
#[test]
|
||||
fn round_trip_cp437_data() {
|
||||
round_trip(
|
||||
Cp437GridCommand {
|
||||
origin: Origin::new(5, 2),
|
||||
grid: Cp437Grid::new(7, 5),
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use crate::{
|
||||
commands::check_command_code_only, commands::TryFromPacketError,
|
||||
command_code::CommandCode, Packet, TypedCommand,
|
||||
command_code::CommandCode, commands::check_command_code_only,
|
||||
commands::TryFromPacketError, Packet, TypedCommand,
|
||||
};
|
||||
use std::fmt::Debug;
|
||||
|
||||
|
|
@ -41,3 +41,55 @@ impl From<FadeOutCommand> for TypedCommand {
|
|||
Self::FadeOut(command)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::command_code::CommandCode;
|
||||
use crate::commands::tests::round_trip;
|
||||
use crate::{
|
||||
FadeOutCommand, Header, Packet, TryFromPacketError, TypedCommand,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn round_trip_fade_out() {
|
||||
round_trip(FadeOutCommand.into());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_extraneous_header_fade_out() {
|
||||
let p = Packet {
|
||||
header: Header {
|
||||
command_code: CommandCode::FadeOut.into(),
|
||||
a: 0x10,
|
||||
b: 0x00,
|
||||
c: 0x00,
|
||||
d: 0x01,
|
||||
},
|
||||
payload: vec![],
|
||||
};
|
||||
let result = TypedCommand::try_from(p);
|
||||
assert!(matches!(
|
||||
result,
|
||||
Err(TryFromPacketError::ExtraneousHeaderValues)
|
||||
))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_unexpected_payload() {
|
||||
let p = Packet {
|
||||
header: Header {
|
||||
command_code: CommandCode::FadeOut.into(),
|
||||
a: 0x00,
|
||||
b: 0x00,
|
||||
c: 0x00,
|
||||
d: 0x00,
|
||||
},
|
||||
payload: vec![5, 7],
|
||||
};
|
||||
let result = TypedCommand::try_from(p);
|
||||
assert!(matches!(
|
||||
result,
|
||||
Err(TryFromPacketError::UnexpectedPayloadSize(0, 2))
|
||||
))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use crate::{
|
||||
commands::check_command_code_only, commands::TryFromPacketError,
|
||||
command_code::CommandCode, Packet, TypedCommand,
|
||||
command_code::CommandCode, commands::check_command_code_only,
|
||||
commands::TryFromPacketError, Packet, TypedCommand,
|
||||
};
|
||||
use std::fmt::Debug;
|
||||
|
||||
|
|
@ -42,3 +42,34 @@ impl From<HardResetCommand> for TypedCommand {
|
|||
Self::HardReset(command)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::commands::tests::round_trip;
|
||||
use crate::Header;
|
||||
|
||||
#[test]
|
||||
fn round_trip_hard_reset() {
|
||||
round_trip(HardResetCommand.into());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_extraneous_header() {
|
||||
let p = Packet {
|
||||
header: Header {
|
||||
command_code: CommandCode::HardReset.into(),
|
||||
a: 0x00,
|
||||
b: 0x00,
|
||||
c: 0x00,
|
||||
d: 0x01,
|
||||
},
|
||||
payload: vec![],
|
||||
};
|
||||
let result = TypedCommand::try_from(p);
|
||||
assert!(matches!(
|
||||
result,
|
||||
Err(TryFromPacketError::ExtraneousHeaderValues)
|
||||
))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
mod bitmap;
|
||||
mod bitmap_legacy;
|
||||
mod bitvec;
|
||||
mod brightness;
|
||||
mod brightness_grid;
|
||||
mod char_grid;
|
||||
mod clear;
|
||||
mod cp437_grid;
|
||||
mod fade_out;
|
||||
mod brightness;
|
||||
mod hard_reset;
|
||||
mod typed;
|
||||
mod char_grid;
|
||||
|
||||
use crate::command_code::CommandCode;
|
||||
use crate::*;
|
||||
|
|
@ -17,14 +17,14 @@ use std::fmt::Debug;
|
|||
pub use bitmap::*;
|
||||
pub use bitmap_legacy::*;
|
||||
pub use bitvec::*;
|
||||
pub use brightness::*;
|
||||
pub use brightness_grid::*;
|
||||
pub use char_grid::*;
|
||||
pub use clear::*;
|
||||
pub use cp437_grid::*;
|
||||
pub use fade_out::*;
|
||||
pub use brightness::*;
|
||||
pub use hard_reset::*;
|
||||
pub use typed::*;
|
||||
pub use char_grid::*;
|
||||
|
||||
/// This trait represents a command that can be sent to the display.
|
||||
///
|
||||
|
|
@ -112,7 +112,7 @@ mod tests {
|
|||
use crate::commands::{BinaryOperation, TryFromPacketError};
|
||||
use crate::*;
|
||||
|
||||
fn round_trip(original: TypedCommand) {
|
||||
pub(crate) fn round_trip(original: TypedCommand) {
|
||||
let packet: Packet = original.clone().into();
|
||||
let copy: TypedCommand = match TypedCommand::try_from(packet) {
|
||||
Ok(command) => command,
|
||||
|
|
@ -120,443 +120,4 @@ mod tests {
|
|||
};
|
||||
assert_eq!(copy, original);
|
||||
}
|
||||
|
||||
fn all_compressions<'t>() -> &'t [CompressionCode] {
|
||||
&[
|
||||
CompressionCode::Uncompressed,
|
||||
#[cfg(feature = "compression_lzma")]
|
||||
CompressionCode::Lzma,
|
||||
#[cfg(feature = "compression_bzip2")]
|
||||
CompressionCode::Bzip2,
|
||||
#[cfg(feature = "compression_zlib")]
|
||||
CompressionCode::Zlib,
|
||||
#[cfg(feature = "compression_zstd")]
|
||||
CompressionCode::Zstd,
|
||||
]
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip_clear() {
|
||||
round_trip(ClearCommand.into());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip_hard_reset() {
|
||||
round_trip(HardResetCommand.into());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip_fade_out() {
|
||||
round_trip(FadeOutCommand.into());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip_brightness() {
|
||||
round_trip(
|
||||
BrightnessCommand {
|
||||
brightness: Brightness::try_from(6).unwrap(),
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(deprecated)]
|
||||
fn round_trip_bitmap_legacy() {
|
||||
round_trip(BitmapLegacyCommand.into());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip_char_brightness() {
|
||||
round_trip(
|
||||
BrightnessGridCommand {
|
||||
origin: Origin::new(5, 2),
|
||||
grid: BrightnessGrid::new(7, 5),
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip_cp437_data() {
|
||||
round_trip(Cp437GridCommand {
|
||||
origin: Origin::new(5, 2),
|
||||
grid: Cp437Grid::new(7, 5),
|
||||
}.into());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip_utf8_data() {
|
||||
round_trip(CharGridCommand {
|
||||
origin: Origin::new(5, 2),
|
||||
grid: CharGrid::new(7, 5),
|
||||
}.into());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip_bitmap_linear() {
|
||||
for compression in all_compressions().iter().copied() {
|
||||
for operation in [
|
||||
BinaryOperation::Overwrite,
|
||||
BinaryOperation::And,
|
||||
BinaryOperation::Or,
|
||||
BinaryOperation::Xor,
|
||||
] {
|
||||
round_trip(BitVecCommand {
|
||||
offset: 23,
|
||||
bitvec: BitVec::repeat(false, 40),
|
||||
compression,
|
||||
operation,
|
||||
}.into());
|
||||
}
|
||||
round_trip(BitmapCommand {
|
||||
origin: Origin::ZERO,
|
||||
bitmap: Bitmap::max_sized(),
|
||||
compression,
|
||||
}.into());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_invalid_command() {
|
||||
let p = Packet {
|
||||
header: Header {
|
||||
command_code: 0xFF,
|
||||
a: 0x00,
|
||||
b: 0x00,
|
||||
c: 0x00,
|
||||
d: 0x00,
|
||||
},
|
||||
payload: vec![],
|
||||
};
|
||||
let result = TypedCommand::try_from(p);
|
||||
assert!(matches!(
|
||||
result,
|
||||
Err(TryFromPacketError::InvalidCommand(0xFF))
|
||||
))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_extraneous_header_values_clear() {
|
||||
let p = Packet {
|
||||
header: Header {
|
||||
command_code: CommandCode::Clear.into(),
|
||||
a: 0x05,
|
||||
b: 0x00,
|
||||
c: 0x00,
|
||||
d: 0x00,
|
||||
},
|
||||
payload: vec![],
|
||||
};
|
||||
let result = TypedCommand::try_from(p);
|
||||
assert!(matches!(
|
||||
result,
|
||||
Err(TryFromPacketError::ExtraneousHeaderValues)
|
||||
))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_extraneous_header_values_brightness() {
|
||||
let p = Packet {
|
||||
header: Header {
|
||||
command_code: CommandCode::Brightness.into(),
|
||||
a: 0x00,
|
||||
b: 0x13,
|
||||
c: 0x37,
|
||||
d: 0x00,
|
||||
},
|
||||
payload: vec![5],
|
||||
};
|
||||
let result = TypedCommand::try_from(p);
|
||||
assert!(matches!(
|
||||
result,
|
||||
Err(TryFromPacketError::ExtraneousHeaderValues)
|
||||
))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_extraneous_header_hard_reset() {
|
||||
let p = Packet {
|
||||
header: Header {
|
||||
command_code: CommandCode::HardReset.into(),
|
||||
a: 0x00,
|
||||
b: 0x00,
|
||||
c: 0x00,
|
||||
d: 0x01,
|
||||
},
|
||||
payload: vec![],
|
||||
};
|
||||
let result = TypedCommand::try_from(p);
|
||||
assert!(matches!(
|
||||
result,
|
||||
Err(TryFromPacketError::ExtraneousHeaderValues)
|
||||
))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_extraneous_header_fade_out() {
|
||||
let p = Packet {
|
||||
header: Header {
|
||||
command_code: CommandCode::FadeOut.into(),
|
||||
a: 0x10,
|
||||
b: 0x00,
|
||||
c: 0x00,
|
||||
d: 0x01,
|
||||
},
|
||||
payload: vec![],
|
||||
};
|
||||
let result = TypedCommand::try_from(p);
|
||||
assert!(matches!(
|
||||
result,
|
||||
Err(TryFromPacketError::ExtraneousHeaderValues)
|
||||
))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_unexpected_payload() {
|
||||
let p = Packet {
|
||||
header: Header {
|
||||
command_code: CommandCode::FadeOut.into(),
|
||||
a: 0x00,
|
||||
b: 0x00,
|
||||
c: 0x00,
|
||||
d: 0x00,
|
||||
},
|
||||
payload: vec![5, 7],
|
||||
};
|
||||
let result = TypedCommand::try_from(p);
|
||||
assert!(matches!(
|
||||
result,
|
||||
Err(TryFromPacketError::UnexpectedPayloadSize(0, 2))
|
||||
))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_decompression_failed_win() {
|
||||
for compression in all_compressions().iter().copied() {
|
||||
let p: Packet = commands::BitmapCommand {
|
||||
origin: Origin::new(16, 8),
|
||||
bitmap: Bitmap::new(8, 8).unwrap(),
|
||||
compression,
|
||||
}
|
||||
.into();
|
||||
|
||||
let Packet {
|
||||
header,
|
||||
mut payload,
|
||||
} = p;
|
||||
|
||||
// mangle it
|
||||
for byte in payload.iter_mut() {
|
||||
*byte -= *byte / 2;
|
||||
}
|
||||
|
||||
let p = Packet { header, payload };
|
||||
let result = TypedCommand::try_from(p);
|
||||
if compression != CompressionCode::Uncompressed {
|
||||
assert_eq!(result, Err(TryFromPacketError::DecompressionFailed))
|
||||
} else {
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_decompression_failed_and() {
|
||||
for compression in all_compressions().iter().copied() {
|
||||
let p: Packet = commands::BitVecCommand {
|
||||
offset: 0,
|
||||
bitvec: BitVec::repeat(false, 8),
|
||||
compression,
|
||||
operation: BinaryOperation::Overwrite,
|
||||
}
|
||||
.into();
|
||||
let Packet {
|
||||
header,
|
||||
mut payload,
|
||||
} = p;
|
||||
|
||||
// mangle it
|
||||
for byte in payload.iter_mut() {
|
||||
*byte -= *byte / 2;
|
||||
}
|
||||
|
||||
let p = Packet { header, payload };
|
||||
let result = TypedCommand::try_from(p);
|
||||
if compression != CompressionCode::Uncompressed {
|
||||
assert_eq!(result, Err(TryFromPacketError::DecompressionFailed))
|
||||
} else {
|
||||
// when not compressing, there is no way to detect corrupted data
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unexpected_payload_size_brightness() {
|
||||
assert_eq!(
|
||||
TypedCommand::try_from(Packet {
|
||||
header: Header {
|
||||
command_code: CommandCode::Brightness.into(),
|
||||
a: 0,
|
||||
b: 0,
|
||||
c: 0,
|
||||
d: 0,
|
||||
},
|
||||
payload: vec!()
|
||||
}),
|
||||
Err(TryFromPacketError::UnexpectedPayloadSize(1, 0))
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
TypedCommand::try_from(Packet {
|
||||
header: Header {
|
||||
command_code: CommandCode::Brightness.into(),
|
||||
a: 0,
|
||||
b: 0,
|
||||
c: 0,
|
||||
d: 0,
|
||||
},
|
||||
payload: vec!(0, 0)
|
||||
}),
|
||||
Err(TryFromPacketError::UnexpectedPayloadSize(1, 2))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_reserved_used() {
|
||||
let Packet { header, payload } = commands::BitVecCommand {
|
||||
offset: 0,
|
||||
bitvec: BitVec::repeat(false, 8),
|
||||
compression: CompressionCode::Uncompressed,
|
||||
operation: BinaryOperation::Or,
|
||||
}
|
||||
.into();
|
||||
let Header {
|
||||
command_code: command,
|
||||
a: offset,
|
||||
b: length,
|
||||
c: sub,
|
||||
d: _reserved,
|
||||
} = header;
|
||||
let p = Packet {
|
||||
header: Header {
|
||||
command_code: command,
|
||||
a: offset,
|
||||
b: length,
|
||||
c: sub,
|
||||
d: 69,
|
||||
},
|
||||
payload,
|
||||
};
|
||||
assert_eq!(
|
||||
TypedCommand::try_from(p),
|
||||
Err(TryFromPacketError::ExtraneousHeaderValues)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_invalid_compression() {
|
||||
let Packet { header, payload } = commands::BitVecCommand {
|
||||
offset: 0,
|
||||
bitvec: BitVec::repeat(false, 8),
|
||||
compression: CompressionCode::Uncompressed,
|
||||
operation: BinaryOperation::And,
|
||||
}
|
||||
.into();
|
||||
let Header {
|
||||
command_code: command,
|
||||
a: offset,
|
||||
b: length,
|
||||
c: _sub,
|
||||
d: reserved,
|
||||
} = header;
|
||||
let p = Packet {
|
||||
header: Header {
|
||||
command_code: command,
|
||||
a: offset,
|
||||
b: length,
|
||||
c: 42,
|
||||
d: reserved,
|
||||
},
|
||||
payload,
|
||||
};
|
||||
assert_eq!(
|
||||
TypedCommand::try_from(p),
|
||||
Err(TryFromPacketError::InvalidCompressionCode(42))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_unexpected_size() {
|
||||
let Packet { header, payload } = commands::BitVecCommand {
|
||||
offset: 0,
|
||||
bitvec: BitVec::repeat(false, 8),
|
||||
compression: CompressionCode::Uncompressed,
|
||||
operation: BinaryOperation::Xor,
|
||||
}
|
||||
.into();
|
||||
let Header {
|
||||
command_code: command,
|
||||
a: offset,
|
||||
b: length,
|
||||
c: compression,
|
||||
d: reserved,
|
||||
} = header;
|
||||
let p = Packet {
|
||||
header: Header {
|
||||
command_code: command,
|
||||
a: offset,
|
||||
b: 420,
|
||||
c: compression,
|
||||
d: reserved,
|
||||
},
|
||||
payload,
|
||||
};
|
||||
assert_eq!(
|
||||
TypedCommand::try_from(p),
|
||||
Err(TryFromPacketError::UnexpectedPayloadSize(
|
||||
420,
|
||||
length as usize,
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn origin_add() {
|
||||
assert_eq!(
|
||||
Origin::<Pixels>::new(4, 2),
|
||||
Origin::new(1, 0) + Origin::new(3, 2)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn packet_into_char_brightness_invalid() {
|
||||
let grid = BrightnessGrid::new(2, 2);
|
||||
let command = commands::BrightnessGridCommand {
|
||||
origin: Origin::ZERO,
|
||||
grid,
|
||||
};
|
||||
let mut packet: Packet = command.into();
|
||||
let slot = packet.payload.get_mut(1).unwrap();
|
||||
*slot = 23;
|
||||
assert_eq!(
|
||||
TypedCommand::try_from(packet),
|
||||
Err(TryFromPacketError::InvalidBrightness(23))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn packet_into_brightness_invalid() {
|
||||
let mut packet: Packet = commands::BrightnessCommand {
|
||||
brightness: Brightness::MAX,
|
||||
}
|
||||
.into();
|
||||
let slot = packet.payload.get_mut(0).unwrap();
|
||||
*slot = 42;
|
||||
assert_eq!(
|
||||
TypedCommand::try_from(packet),
|
||||
Err(TryFromPacketError::InvalidBrightness(42))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,7 @@
|
|||
use crate::{
|
||||
command_code::CommandCode,
|
||||
BitVecCommand,
|
||||
BitmapCommand,
|
||||
BrightnessCommand,
|
||||
BrightnessGridCommand,
|
||||
CharGridCommand,
|
||||
ClearCommand,
|
||||
Cp437GridCommand,
|
||||
FadeOutCommand,
|
||||
HardResetCommand,
|
||||
Header,
|
||||
Packet
|
||||
command_code::CommandCode, BitVecCommand, BitmapCommand, BrightnessCommand,
|
||||
BrightnessGridCommand, CharGridCommand, ClearCommand, Cp437GridCommand,
|
||||
FadeOutCommand, HardResetCommand, Header, Packet,
|
||||
};
|
||||
|
||||
/// This enum contains all commands provided by the library.
|
||||
|
|
@ -94,25 +85,25 @@ impl TryFrom<Packet> for TypedCommand {
|
|||
CommandCode::Brightness => TypedCommand::Brightness(
|
||||
crate::BrightnessCommand::try_from(packet)?,
|
||||
),
|
||||
CommandCode::HardReset => {
|
||||
TypedCommand::HardReset(crate::HardResetCommand::try_from(packet)?)
|
||||
}
|
||||
CommandCode::HardReset => TypedCommand::HardReset(
|
||||
crate::HardResetCommand::try_from(packet)?,
|
||||
),
|
||||
CommandCode::FadeOut => {
|
||||
TypedCommand::FadeOut(crate::FadeOutCommand::try_from(packet)?)
|
||||
}
|
||||
CommandCode::Cp437Data => {
|
||||
TypedCommand::Cp437Grid(crate::Cp437GridCommand::try_from(packet)?)
|
||||
}
|
||||
CommandCode::CharBrightness => {
|
||||
TypedCommand::BrightnessGrid(crate::BrightnessGridCommand::try_from(packet)?)
|
||||
}
|
||||
CommandCode::Utf8Data => {
|
||||
TypedCommand::CharGrid(crate::CharGridCommand::try_from(packet)?)
|
||||
}
|
||||
CommandCode::Cp437Data => TypedCommand::Cp437Grid(
|
||||
crate::Cp437GridCommand::try_from(packet)?,
|
||||
),
|
||||
CommandCode::CharBrightness => TypedCommand::BrightnessGrid(
|
||||
crate::BrightnessGridCommand::try_from(packet)?,
|
||||
),
|
||||
CommandCode::Utf8Data => TypedCommand::CharGrid(
|
||||
crate::CharGridCommand::try_from(packet)?,
|
||||
),
|
||||
#[allow(deprecated)]
|
||||
CommandCode::BitmapLegacy => {
|
||||
TypedCommand::BitmapLegacy(crate::BitmapLegacyCommand::try_from(packet)?)
|
||||
}
|
||||
CommandCode::BitmapLegacy => TypedCommand::BitmapLegacy(
|
||||
crate::BitmapLegacyCommand::try_from(packet)?,
|
||||
),
|
||||
CommandCode::BitmapLinear
|
||||
| CommandCode::BitmapLinearOr
|
||||
| CommandCode::BitmapLinearAnd
|
||||
|
|
@ -158,4 +149,28 @@ impl From<TypedCommand> for Packet {
|
|||
TypedCommand::BitmapLegacy(c) => c.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{Header, Packet, TryFromPacketError, TypedCommand};
|
||||
|
||||
#[test]
|
||||
fn error_invalid_command() {
|
||||
let p = Packet {
|
||||
header: Header {
|
||||
command_code: 0xFF,
|
||||
a: 0x00,
|
||||
b: 0x00,
|
||||
c: 0x00,
|
||||
d: 0x00,
|
||||
},
|
||||
payload: vec![],
|
||||
};
|
||||
let result = TypedCommand::try_from(p);
|
||||
assert!(matches!(
|
||||
result,
|
||||
Err(TryFromPacketError::InvalidCommand(0xFF))
|
||||
))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,21 @@ pub enum CompressionCode {
|
|||
Zstd = 0x7a73,
|
||||
}
|
||||
|
||||
impl CompressionCode {
|
||||
/// All available compression codes (depending on features).
|
||||
pub const ALL: [CompressionCode; 5] = [
|
||||
Self::Uncompressed,
|
||||
#[cfg(feature = "compression_zlib")]
|
||||
Self::Zlib,
|
||||
#[cfg(feature = "compression_bzip2")]
|
||||
Self::Bzip2,
|
||||
#[cfg(feature = "compression_lzma")]
|
||||
Self::Lzma,
|
||||
#[cfg(feature = "compression_zstd")]
|
||||
Self::Zstd,
|
||||
];
|
||||
}
|
||||
|
||||
impl From<CompressionCode> for u16 {
|
||||
fn from(value: CompressionCode) -> Self {
|
||||
value as u16
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{Brightness, Grid, ByteGrid, ValueGrid};
|
||||
use crate::{Brightness, ByteGrid, Grid, ValueGrid};
|
||||
|
||||
/// A grid containing brightness values.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -65,17 +65,17 @@ pub use crate::origin::{Origin, Pixels, Tiles};
|
|||
pub use crate::packet::{Header, Packet, Payload};
|
||||
|
||||
mod brightness;
|
||||
mod commands;
|
||||
mod command_code;
|
||||
mod commands;
|
||||
mod compression;
|
||||
mod compression_code;
|
||||
mod connections;
|
||||
mod constants;
|
||||
mod containers;
|
||||
mod origin;
|
||||
mod packet;
|
||||
#[cfg(feature = "cp437")]
|
||||
mod cp437;
|
||||
mod origin;
|
||||
mod packet;
|
||||
|
||||
#[cfg(feature = "cp437")]
|
||||
pub use crate::cp437::Cp437Converter;
|
||||
|
|
|
|||
|
|
@ -119,4 +119,12 @@ mod tests {
|
|||
let pixel: Origin<Pixels> = Origin::new(7, 16);
|
||||
let _: Origin<Tiles> = Origin::try_from(&pixel).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn origin_add() {
|
||||
assert_eq!(
|
||||
Origin::<Pixels>::new(4, 2),
|
||||
Origin::new(1, 0) + Origin::new(3, 2)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue