diff --git a/src/asciicast.rs b/src/asciicast.rs index 6ffc347..98e9121 100644 --- a/src/asciicast.rs +++ b/src/asciicast.rs @@ -274,6 +274,11 @@ mod tests { assert_eq!(version, 1); assert_eq!((header.term_cols, header.term_rows), (100, 50)); + let mut expected_env = HashMap::new(); + expected_env.insert("SHELL".to_owned(), "/bin/bash".to_owned()); + expected_env.insert("TERM".to_owned(), "xterm-256color".to_owned()); + assert_eq!(header.env.unwrap(), expected_env); + assert_eq!(events[0].time, Duration::from_micros(1)); assert!(matches!(events[0].data, EventData::Output(ref s) if s == "ż")); @@ -284,6 +289,18 @@ mod tests { assert!(matches!(events[2].data, EventData::Output(ref s) if s == "\r\n")); } + #[test] + fn open_v1_with_nulls_in_header() { + let Asciicast { + version, header, .. + } = super::open_from_path("tests/casts/nulls-v1.json").unwrap(); + assert_eq!(version, 1); + + let mut expected_env = HashMap::new(); + expected_env.insert("SHELL".to_owned(), "/bin/bash".to_owned()); + assert_eq!(header.env.unwrap(), expected_env); + } + #[test] fn open_v2_minimal() { let Asciicast { @@ -319,6 +336,11 @@ mod tests { assert_eq!(theme.bg, RGB8::new(0xff, 0xff, 0xff)); assert_eq!(theme.palette[0], RGB8::new(0x24, 0x1f, 0x31)); + let mut expected_env = HashMap::new(); + expected_env.insert("SHELL".to_owned(), "/bin/bash".to_owned()); + expected_env.insert("TERM".to_owned(), "xterm-256color".to_owned()); + assert_eq!(header.env.unwrap(), expected_env); + assert_eq!(events[0].time, Duration::from_micros(1)); assert!(matches!(events[0].data, EventData::Output(ref s) if s == "ż")); @@ -338,6 +360,18 @@ mod tests { assert!(matches!(events[4].data, EventData::Output(ref s) if s == "\r\n")); } + #[test] + fn open_v2_with_nulls_in_header() { + let Asciicast { + version, header, .. + } = super::open_from_path("tests/casts/nulls-v2.cast").unwrap(); + assert_eq!(version, 2); + + let mut expected_env = HashMap::new(); + expected_env.insert("SHELL".to_owned(), "/bin/bash".to_owned()); + assert_eq!(header.env.unwrap(), expected_env); + } + #[test] fn open_v3_minimal() { let Asciicast { diff --git a/src/asciicast/v1.rs b/src/asciicast/v1.rs index e2b6124..ebb696e 100644 --- a/src/asciicast/v1.rs +++ b/src/asciicast/v1.rs @@ -14,7 +14,7 @@ struct V1 { height: u16, command: Option, title: Option, - env: Option>, + env: Option>>, stdout: Vec, } @@ -35,8 +35,16 @@ pub fn load(json: String) -> Result> { let term_type = asciicast .env .as_ref() - .and_then(|env| env.get("TERM")) - .cloned(); + .map(|env| env.get("TERM")) + .unwrap_or_default() + .cloned() + .unwrap_or_default(); + + let env = asciicast.env.map(|env| { + env.into_iter() + .filter_map(|(k, v)| v.map(|v| (k, v))) + .collect() + }); let header = Header { term_cols: asciicast.width, @@ -48,7 +56,7 @@ pub fn load(json: String) -> Result> { idle_time_limit: None, command: asciicast.command.clone(), title: asciicast.title.clone(), - env: asciicast.env.clone(), + env, }; let events = Box::new(asciicast.stdout.into_iter().scan( diff --git a/src/asciicast/v2.rs b/src/asciicast/v2.rs index 848f304..bd3358c 100644 --- a/src/asciicast/v2.rs +++ b/src/asciicast/v2.rs @@ -18,7 +18,7 @@ struct V2Header { idle_time_limit: Option, command: Option, title: Option, - env: Option>, + env: Option>>, theme: Option, } @@ -70,9 +70,22 @@ pub fn open(header_line: &str) -> Result { impl Parser { pub fn parse<'a, I: Iterator> + 'a>(self, lines: I) -> Asciicast<'a> { - let term_type = self.0.env.as_ref().and_then(|env| env.get("TERM").cloned()); + let term_type = self + .0 + .env + .as_ref() + .map(|env| env.get("TERM").cloned()) + .unwrap_or_default() + .unwrap_or_default(); + let term_theme = self.0.theme.as_ref().map(|t| t.into()); + let env = self.0.env.map(|env| { + env.into_iter() + .filter_map(|(k, v)| v.map(|v| (k, v))) + .collect() + }); + let header = Header { term_cols: self.0.width, term_rows: self.0.height, @@ -83,7 +96,7 @@ impl Parser { idle_time_limit: self.0.idle_time_limit, command: self.0.command.clone(), title: self.0.title.clone(), - env: self.0.env.clone(), + env, }; let events = Box::new(lines.filter_map(parse_line)); @@ -367,6 +380,11 @@ impl serde::Serialize for V2Palette { impl From<&Header> for V2Header { fn from(header: &Header) -> Self { + let env = header + .env + .clone() + .map(|env| env.into_iter().map(|(k, v)| (k, Some(v))).collect()); + V2Header { version: 2, width: header.term_cols, @@ -375,7 +393,7 @@ impl From<&Header> for V2Header { idle_time_limit: header.idle_time_limit, command: header.command.clone(), title: header.title.clone(), - env: header.env.clone(), + env, theme: header.term_theme.as_ref().map(|t| t.into()), } } diff --git a/tests/casts/nulls-v1.json b/tests/casts/nulls-v1.json new file mode 100644 index 0000000..0982c1b --- /dev/null +++ b/tests/casts/nulls-v1.json @@ -0,0 +1,15 @@ +{ + "version": 1, + "width": 100, + "height": 50, + "env": { + "SHELL": "/bin/bash", + "TERM": null + }, + "stdout": [ + [ + 1.230000, + "hello" + ] + ] +} diff --git a/tests/casts/nulls-v2.cast b/tests/casts/nulls-v2.cast new file mode 100644 index 0000000..afd225c --- /dev/null +++ b/tests/casts/nulls-v2.cast @@ -0,0 +1,2 @@ +{"version":2,"width":100,"height":50,"env":{"TERM":null,"SHELL":"/bin/bash"}} +[1.23, "o", "hello"]