diff --git a/Cargo.toml b/Cargo.toml index 0ff1556..71a5403 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,4 +11,4 @@ serde = "1.0" thiserror = "1.0" [dev_dependencies] -batch_run = "1.0" \ No newline at end of file +batch_run = "1.2" \ No newline at end of file diff --git a/src/ser.rs b/src/ser.rs index 64b0c03..4c55b92 100644 --- a/src/ser.rs +++ b/src/ser.rs @@ -18,15 +18,20 @@ impl Corona { } fn start_sub(&mut self) -> &mut Self { - self.inside = true; + self.inside = false; self } - fn serialize_item(&mut self, item: impl ser::Serialize) -> SerResult { + fn comma(&mut self) -> SerResult { if self.inside { write!(self.writer, ",")?; } self.inside = true; + Ok(()) + } + + fn serialize_item(&mut self, item: impl ser::Serialize) -> SerResult { + self.comma()?; item.serialize(self)?; Ok(()) } @@ -45,67 +50,67 @@ impl ser::Serializer for &mut Corona { type SerializeStructVariant = Self; fn serialize_bool(self, v: bool) -> SerResult { - write!(self.writer, "{}", v.to_string())?; + write!(self.writer, "{}", v)?; Ok(()) } fn serialize_i8(self, v: i8) -> SerResult { - write!(self.writer, "{}", v.to_string())?; + write!(self.writer, "{}", v)?; Ok(()) } fn serialize_i16(self, v: i16) -> SerResult { - write!(self.writer, "{}", v.to_string())?; + write!(self.writer, "{}", v)?; Ok(()) } fn serialize_i32(self, v: i32) -> SerResult { - write!(self.writer, "{}", v.to_string())?; + write!(self.writer, "{}", v)?; Ok(()) } fn serialize_i64(self, v: i64) -> SerResult { - write!(self.writer, "{}", v.to_string())?; + write!(self.writer, "{}", v)?; Ok(()) } fn serialize_i128(self, v: i128) -> SerResult { - write!(self.writer, "{}", v.to_string())?; + write!(self.writer, "{}", v)?; Ok(()) } fn serialize_u8(self, v: u8) -> SerResult { - write!(self.writer, "{}", v.to_string())?; + write!(self.writer, "{}", v)?; Ok(()) } fn serialize_u16(self, v: u16) -> SerResult { - write!(self.writer, "{}", v.to_string())?; + write!(self.writer, "{}", v)?; Ok(()) } fn serialize_u32(self, v: u32) -> SerResult { - write!(self.writer, "{}", v.to_string())?; + write!(self.writer, "{}", v)?; Ok(()) } fn serialize_u64(self, v: u64) -> SerResult { - write!(self.writer, "{}", v.to_string())?; + write!(self.writer, "{}", v)?; Ok(()) } fn serialize_u128(self, v: u128) -> SerResult { - write!(self.writer, "{}", v.to_string())?; + write!(self.writer, "{}", v)?; Ok(()) } fn serialize_f32(self, v: f32) -> SerResult { - write!(self.writer, "{}", v.to_string())?; + write!(self.writer, "{}", v)?; Ok(()) } fn serialize_f64(self, v: f64) -> SerResult { - write!(self.writer, "{}", v.to_string())?; + write!(self.writer, "{}", v)?; Ok(()) } @@ -115,7 +120,7 @@ impl ser::Serializer for &mut Corona { } fn serialize_str(self, v: &str) -> SerResult { - write!(self.writer, "\"{}\"", v)?; + write!(self.writer, "\"{}\".into()", v)?; Ok(()) } @@ -313,8 +318,8 @@ impl ser::SerializeMap for &mut Corona { where T: serde::Serialize, { - // a little hack for code reuse - self.serialize_item("(")?; + self.comma()?; + write!(self.writer, "(")?; key.serialize(&mut **self)?; write!(self.writer, ",")?; Ok(()) @@ -346,7 +351,8 @@ impl ser::SerializeStruct for &mut Corona { where T: serde::Serialize, { - self.serialize_item(format!("{}:", key))?; + self.comma()?; + write!(self.writer, "{}:", key)?; value.serialize(&mut **self)?; Ok(()) } @@ -368,7 +374,8 @@ impl ser::SerializeStructVariant for &mut Corona { where T: serde::Serialize, { - self.serialize_item(format!("{}:", key))?; + self.comma()?; + write!(self.writer, "{}:", key)?; value.serialize(&mut **self)?; Ok(()) } diff --git a/test_fixtures/.gitignore b/test_fixtures/.gitignore new file mode 100644 index 0000000..34c70f8 --- /dev/null +++ b/test_fixtures/.gitignore @@ -0,0 +1,2 @@ +*.rs +*.snapshot \ No newline at end of file diff --git a/test_fixtures/source.data b/test_fixtures/source.data new file mode 100644 index 0000000..3f1d26f --- /dev/null +++ b/test_fixtures/source.data @@ -0,0 +1,73 @@ +simple + +Simple + +#[derive(PartialEq, Debug, Serialize)] +pub struct Simple { + pub integer: i32, + pub float: f32, + pub string: String, + pub boolean: bool, +} + +definition::Simple { + integer: 123, + float: std::f32::consts::PI, + string: "text string".into(), + boolean: false +} + +nested + +Nested,Inner + +#[derive(PartialEq, Debug, Serialize)] +pub struct Nested { + pub inner: Inner, +} +#[derive(PartialEq, Debug, Serialize)] +pub struct Inner { + pub value: i32, +} + +definition::Nested { + inner: definition::Inner { + value: 123 + } +} + +complex + +Complex + +use std::collections::HashMap; +#[derive(PartialEq, Debug, Serialize)] +pub struct Complex { + pub tuple: (i32, f32, String), + pub vector: Vec, + pub map: HashMap, +} + +{ + let mut map = std::collections::HashMap::new(); + map.insert(0, "test".into()); + map.insert(120, "test longer".into()); + definition::Complex { + tuple: (1, 1.0, "tuple entry".into()), + vector: vec![1, 2, 3, 4, 5, -1, -2, -3, -4, -5], + map + } +} + +floats + +Floats + +#[derive(PartialEq, Debug, Serialize)] +pub struct Floats(pub Vec); + +definition::Floats(vec![ + 123456789e30, + 123456789e-30, + 12345.6789 +]) \ No newline at end of file diff --git a/tests/definition.tpl b/tests/definition.tpl new file mode 100644 index 0000000..4869328 --- /dev/null +++ b/tests/definition.tpl @@ -0,0 +1,3 @@ +use serde::Serialize; + +{definition} \ No newline at end of file diff --git a/tests/generate_and_use.rs b/tests/generate_and_use.rs new file mode 100644 index 0000000..8ef8e16 --- /dev/null +++ b/tests/generate_and_use.rs @@ -0,0 +1,111 @@ +use batch_run::Batch; +use std::{ + fs::{create_dir, File}, + io::BufRead, + io::Write, + path::PathBuf, +}; + +#[derive(Default)] +struct Data { + name: String, + types: String, + definition: String, + value: String, +} + +impl Data { + fn write(&mut self, path: &mut PathBuf) { + path.push(&self.name); + if !path.exists() { + create_dir(&path).unwrap(); + } + path.push("dummy"); // a hack, so that folder isn't overwritten with file name + write!( + File::create(&path.with_file_name(format!("{}-main.rs", self.name))).unwrap(), + include_str!("main.tpl"), + name = self.name, + value = self.value + ) + .unwrap(); + write!( + File::create(&path.with_file_name("definition.rs")).unwrap(), + include_str!("definition.tpl"), + definition = self.definition + ) + .unwrap(); + write!( + File::create(&path.with_file_name(format!("{}-user.rs", self.name))).unwrap(), + include_str!("user.tpl"), + types = self.types, + ser_type = self.types.split(",").next().unwrap(), + value = self.value + ).unwrap(); + write!( + File::create(&path.with_file_name(format!("{}-main.snapshot", self.name))).unwrap(), + include_str!("main.snapshot.tpl"), + name = self.name + ).unwrap(); + write!( + File::create(&path.with_file_name(format!("{}-user.snapshot", self.name))).unwrap(), + include_str!("user.snapshot.tpl"), + ).unwrap(); + path.pop(); + path.pop(); + + self.name.clear(); + self.types.clear(); + self.definition.clear(); + self.value.clear(); + } +} + +#[derive(PartialEq, Eq)] +enum State { + Name, + Types, + Definition, + Value, +} + +impl State { + fn forward(&mut self) { + use State::*; + *self = match self { + Name => Self::Types, + Types => Self::Definition, + Definition => Self::Value, + Value => Self::Name, + } + } +} + +#[test] +fn main() { + let data = File::open("test_fixtures/source.data").unwrap(); + let mut out = Data::default(); + let mut state: State = State::Name; + let mut path: PathBuf = ["test_fixtures"].iter().collect(); + for line in std::io::BufReader::new(data).lines() { + let line = line.unwrap(); + if line.trim().is_empty() { + state.forward(); + if state == State::Name { + out.write(&mut path); + } + } else { + match state { + State::Name => out.name = line.trim().to_string(), + State::Types => out.types = line.trim().to_string(), + State::Definition => out.definition += &(line + "\n"), + State::Value => out.value += &(line + "\n"), + } + } + } + // flush anything already here + out.write(&mut path); + + let b = Batch::new(); + b.run_match("test_fixtures/**/*-main.rs"); + b.run().unwrap().assert_all_ok(); +} diff --git a/tests/main.snapshot.tpl b/tests/main.snapshot.tpl new file mode 100644 index 0000000..738180f --- /dev/null +++ b/tests/main.snapshot.tpl @@ -0,0 +1,10 @@ +( + status: 0, + stdout: [ + "", + "", + ], + stderr: [ + "batch entry {name}-user.rs [should run and generate output] ... ok", + ], +) \ No newline at end of file diff --git a/tests/main.tpl b/tests/main.tpl new file mode 100644 index 0000000..cd91fbc --- /dev/null +++ b/tests/main.tpl @@ -0,0 +1,11 @@ +use corona::to_file; +use batch_run::{{Batch, config::Config}}; + +mod definition; + +fn main() {{ + to_file({value}, "test_fixtures/{name}/generated.rs").unwrap(); + let b = Batch::new(); + b.run_match("test_fixtures/{name}/{name}-user.rs"); + b.run_with_config(Config::from_env().unwrap().with_stderr_no_color()).unwrap().assert_all_ok(); +}} \ No newline at end of file diff --git a/tests/user.snapshot.tpl b/tests/user.snapshot.tpl new file mode 100644 index 0000000..82e4dfc --- /dev/null +++ b/tests/user.snapshot.tpl @@ -0,0 +1,5 @@ +( + status: 0, + stdout: [], + stderr: [], +) \ No newline at end of file diff --git a/tests/user.tpl b/tests/user.tpl new file mode 100644 index 0000000..736938a --- /dev/null +++ b/tests/user.tpl @@ -0,0 +1,7 @@ +mod definition; +use definition::{{{types}}}; + +fn main() {{ + let item: {ser_type} = include!("generated.rs"); + assert_eq!(item, {value}); +}} \ No newline at end of file