diff --git a/Cargo.toml b/Cargo.toml index 230cb27..5761aae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,3 +4,4 @@ version = "0.1.0" edition = "2021" [dependencies] +crc = "3.2.1" diff --git a/src/chunk.rs b/src/chunk.rs index e69de29..d4386e8 100644 --- a/src/chunk.rs +++ b/src/chunk.rs @@ -0,0 +1,185 @@ +use std::{fmt::Display}; +use crc::Crc; + +use crate::chunk_type::ChunkType; + +struct Chunk { + length: u32, + chunk_type: ChunkType, + chunk_data: Vec, + crc: u32, +} + +impl Chunk { + fn new(chunk_type: ChunkType, data: Vec) -> Chunk { + todo!() + } + + fn length(&self) -> u32 { + todo!() + } + + fn chunk_type(&self) -> &ChunkType { + todo!() + } + + fn data(&self) -> &[u8] { + todo!() + } + + fn crc(&self) -> u32 { + todo!() + } + + fn data_as_string(&self) -> Result { + todo!() + } + + fn as_bytes(&self) -> Vec { + todo!() + } +} + +impl TryFrom<&[u8]> for Chunk { + type Error = &'static str; + + fn try_from(chunk_data: &[u8]) -> Result { + todo!() + } +} + +impl Display for Chunk { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + todo!() + } +} + +// unit test +#[cfg(test)] +mod tests { + use super::*; + use crate::chunk_type::ChunkType; + use std::str::FromStr; + + fn testing_chunk() -> Chunk { + let data_length: u32 = 42; + let chunk_type = "RuSt".as_bytes(); + let message_bytes = "This is where your secret message will be!".as_bytes(); + let crc: u32 = 2882656334; + + let chunk_data: Vec = data_length + .to_be_bytes() + .iter() + .chain(chunk_type.iter()) + .chain(message_bytes.iter()) + .chain(crc.to_be_bytes().iter()) + .copied() + .collect(); + + Chunk::try_from(chunk_data.as_ref()).unwrap() + } + + #[test] + fn test_new_chunk() { + let chunk_type = ChunkType::from_str("RuSt").unwrap(); + let data = "This is where your secret message will be!".as_bytes().to_vec(); + let chunk = Chunk::new(chunk_type, data); + assert_eq!(chunk.length(), 42); + assert_eq!(chunk.crc(), 2882656334); + } + + #[test] + fn test_chunk_length() { + let chunk = testing_chunk(); + assert_eq!(chunk.length(), 42); + } + + #[test] + fn test_chunk_type() { + let chunk = testing_chunk(); + assert_eq!(chunk.chunk_type().to_string(), String::from("RuSt")); + } + + #[test] + fn test_chunk_string() { + let chunk = testing_chunk(); + let chunk_string = chunk.data_as_string().unwrap(); + let expected_chunk_string = String::from("This is where your secret message will be!"); + assert_eq!(chunk_string, expected_chunk_string); + } + + #[test] + fn test_chunk_crc() { + let chunk = testing_chunk(); + assert_eq!(chunk.crc(), 2882656334); + } + + #[test] + fn test_valid_chunk_from_bytes() { + let data_length: u32 = 42; + let chunk_type = "RuSt".as_bytes(); + let message_bytes = "This is where your secret message will be!".as_bytes(); + let crc: u32 = 2882656334; + + let chunk_data: Vec = data_length + .to_be_bytes() + .iter() + .chain(chunk_type.iter()) + .chain(message_bytes.iter()) + .chain(crc.to_be_bytes().iter()) + .copied() + .collect(); + + let chunk = Chunk::try_from(chunk_data.as_ref()).unwrap(); + + let chunk_string = chunk.data_as_string().unwrap(); + let expected_chunk_string = String::from("This is where your secret message will be!"); + + assert_eq!(chunk.length(), 42); + assert_eq!(chunk.chunk_type().to_string(), String::from("RuSt")); + assert_eq!(chunk_string, expected_chunk_string); + assert_eq!(chunk.crc(), 2882656334); + } + + #[test] + fn test_invalid_chunk_from_bytes() { + let data_length: u32 = 42; + let chunk_type = "RuSt".as_bytes(); + let message_bytes = "This is where your secret message will be!".as_bytes(); + let crc: u32 = 2882656333; + + let chunk_data: Vec = data_length + .to_be_bytes() + .iter() + .chain(chunk_type.iter()) + .chain(message_bytes.iter()) + .chain(crc.to_be_bytes().iter()) + .copied() + .collect(); + + let chunk = Chunk::try_from(chunk_data.as_ref()); + + assert!(chunk.is_err()); + } + + #[test] + pub fn test_chunk_trait_impls() { + let data_length: u32 = 42; + let chunk_type = "RuSt".as_bytes(); + let message_bytes = "This is where your secret message will be!".as_bytes(); + let crc: u32 = 2882656334; + + let chunk_data: Vec = data_length + .to_be_bytes() + .iter() + .chain(chunk_type.iter()) + .chain(message_bytes.iter()) + .chain(crc.to_be_bytes().iter()) + .copied() + .collect(); + + let chunk: Chunk = TryFrom::try_from(chunk_data.as_ref()).unwrap(); + + let _chunk_string = format!("{}", chunk); + } +} diff --git a/src/chunk_type.rs b/src/chunk_type.rs index ec8ab30..41d013b 100644 --- a/src/chunk_type.rs +++ b/src/chunk_type.rs @@ -1,5 +1,5 @@ use core::str; -use std::{error::Error, fmt::{write, Display}, str::FromStr, u8}; +use std::{str::FromStr, u8}; fn byte_to_bits(byte: u8) -> [u8; 8] { let mut bits = [0u8; 8]; @@ -18,7 +18,7 @@ fn byte_to_bits(byte: u8) -> [u8; 8] { /// the "property bit". I have named the bytes with their /// property bit name. #[derive(Debug, PartialEq, Eq)] -struct ChunkType { +pub struct ChunkType { ancillary_byte: u8, private_byte: u8, reserved_byte: u8,