mirror of
https://github.com/storytold/bevy-mocap.git
synced 2026-10-09 00:09:45 +00:00
early passing tests
This commit is contained in:
+64
-13
@@ -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<MorphID, f32>,
|
||||
pub timestamp: RelativeFrameTime,
|
||||
pub morphs: HashMap<MorphID, f32>,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct CSVAnimation {
|
||||
frames: Vec<CSVFrame>,
|
||||
morph_names: Vec<String>
|
||||
pub frames: Vec<CSVFrame>,
|
||||
pub morph_names: Vec<String>
|
||||
}
|
||||
|
||||
#[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<CSVAnimation, CSVParseError> {
|
||||
Err(CSVParseError::NoData)
|
||||
pub fn parse(csv: &str) -> Result<CSVAnimation, CSVParseError> {
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user