From e43250a465cc863c98601894dab3a3dfae704cd7 Mon Sep 17 00:00:00 2001 From: Lee-Orr Date: Wed, 7 Feb 2024 19:36:22 -0500 Subject: [PATCH] early passing tests --- src/lib.rs | 77 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 64 insertions(+), 13 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 84cb9ca..8a78917 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,12 +5,11 @@ use serde::{Deserialize, Serialize}; #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct MorphID { - id: usize, - + pub id: usize, } #[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Serialize, Deserialize)] -pub struct RelativeFrameTime(f32); +pub struct RelativeFrameTime(pub f32); impl MorphID { pub fn new(id: usize) -> Self { @@ -22,20 +21,21 @@ impl MorphID { #[derive(Clone, Debug, Serialize, Deserialize)] pub struct CSVFrame { - timestamp: RelativeFrameTime, - morphs: HashMap, + pub timestamp: RelativeFrameTime, + pub morphs: HashMap, } #[derive(Clone, Debug, Serialize, Deserialize)] pub struct CSVAnimation { - frames: Vec, - morph_names: Vec + pub frames: Vec, + pub morph_names: Vec } -#[derive(Debug, PartialEq, Eq, Clone, Copy)] +#[derive(Debug)] pub enum CSVParseError { - NoData + NoData, + InvalidCSV(csv::Error) } impl std::fmt::Display for CSVParseError { @@ -46,9 +46,46 @@ impl std::fmt::Display for CSVParseError { impl std::error::Error for CSVParseError {} +const TIMECODE_COLUMN_ID : usize = 0; +const MORPH_COLUMNS_START_ID : usize = 2; + impl CSVAnimation { - pub fn parse(csv: &str) -> Result { - Err(CSVParseError::NoData) + pub fn parse(csv: &str) -> Result { + if csv.is_empty() { + return Err(CSVParseError::NoData); + } + + let mut buffer = csv.as_bytes(); + + let mut csv_content = csv::ReaderBuilder::new().has_headers(false).from_reader(buffer); + + let mut records = csv_content.records(); + + let first_row = match records.next() { + Some(Ok(v)) => v, + Some(Err(e)) => { + return Err(CSVParseError::InvalidCSV(e)); + }, + None => { + return Err(CSVParseError::NoData); + } + }; + + let morph_names = first_row.iter().enumerate().filter_map(|(i, v)| if i >= MORPH_COLUMNS_START_ID { Some(v.trim().to_string()) } else { None }).collect(); + + for result in csv_content.records() { + let record = match result { + Ok(value) => value, + Err(error) => { + return Err(CSVParseError::InvalidCSV(error)); + } + }; + } + + Ok(CSVAnimation { + frames: vec![], + morph_names, + }) } } @@ -57,7 +94,21 @@ mod tests { use crate::{CSVAnimation, CSVParseError}; #[test] - fn given_no_data_the_csv_doesnt_parse() { - assert_eq!(CSVAnimation::parse("").err().unwrap(), CSVParseError::NoData) + fn given_no_data_it_emits_a_no_data_error() { + assert!(matches!(CSVAnimation::parse("").err().unwrap(), CSVParseError::NoData)) + } + + #[test] + fn given_an_invalid_csv_it_emits_an_invalid_csv_error() { + assert!(matches!(CSVAnimation::parse("an invalid csv file + seems to be here... right now? + I wonder, will it be caught"), Err(CSVParseError::InvalidCSV(_)))) + } + + #[test] + fn given_a_header_row_it_sets_correct_headers() { + let result = CSVAnimation::parse("timecode, blendshapecount, shape_1, shape_2").unwrap(); + assert_eq!(result.morph_names.get(0).unwrap(), "shape_1"); + assert_eq!(result.morph_names.get(1).unwrap(), "shape_2"); } }