Skip to content

Commit

Permalink
test: add round trip tests
Browse files Browse the repository at this point in the history
- Some formats cannot round trip with some serde features so add tests
  to determine when we break things because of features used.
- Needs both json and ron because json supports most things so we can
  separate problems we make from problems with the format.
  • Loading branch information
c-git committed Feb 11, 2024
1 parent 8048028 commit 27eb317
Showing 1 changed file with 83 additions and 8 deletions.
91 changes: 83 additions & 8 deletions src/app/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ impl TryFrom<&str> for Data {

#[cfg(test)]
mod tests {
use std::fmt::{Debug, Display};

use insta::glob;
use pretty_assertions::assert_eq;
use rstest::{fixture, rstest};
Expand All @@ -88,6 +90,16 @@ mod tests {
const PATH_PROJECT_ROOT: &str = "../../";
const PATH_TEST_SAMPLES: &str = "tests/sample_logs/*.*";

/// Formats to test serializing with
///
/// Even though in the application only RON is used for serialization we do round
/// trip testing on Json because it helps identify problems that are format specific
/// and avoid unnecessary debugging
enum SerdeFormat {
Ron,
Json,
}

#[fixture]
pub(crate) fn insta_settings() -> insta::Settings {
let mut result = insta::Settings::clone_current();
Expand All @@ -113,22 +125,85 @@ mod tests {
}

#[rstest]
fn round_trip() {
#[case::ron(SerdeFormat::Ron)]
#[case::json(SerdeFormat::Json)]
fn round_trip_from_samples(#[case] serde_format: SerdeFormat) {
// Function needed because rustfmt doesn't play nicely with formatting long strings in macros
fn fail_with(path: impl Debug, row: usize, e: impl Debug, s: impl Display) -> LogRow {
panic!(
"failed to deserialize back into struct.\nFile: {path:?}\nRow: {row}\nError: {e:?}\nSerialized Data: {s}"
)
}

glob!(PATH_PROJECT_ROOT, PATH_TEST_SAMPLES, |path| {
let input = std::fs::read_to_string(path).unwrap();
let rows_before = Data::try_from(&input[..]).unwrap();

// Test single row
for row_before in rows_before.rows() {
let as_ron = ron::to_string(&row_before).unwrap();
let row_after: LogRow = ron::from_str(&dbg!(as_ron)).unwrap();
// Test individual rows
for (i, row_before) in rows_before.rows().iter().enumerate() {
let as_string = match serde_format {
SerdeFormat::Ron => ron::to_string(&row_before).unwrap(),
SerdeFormat::Json => serde_json::to_string(&row_before).unwrap(),
};

let row_after: LogRow = match serde_format {
SerdeFormat::Ron => ron::from_str(&as_string)
.unwrap_or_else(|e| fail_with(path, i, e, as_string)),
SerdeFormat::Json => serde_json::from_str(&as_string)
.unwrap_or_else(|e| fail_with(path, i, e, as_string)),
};
assert_eq!(&row_after, row_before);
}

// Test all rows
let as_ron = ron::to_string(&rows_before).unwrap();
let rows_after: Data = ron::from_str(&dbg!(as_ron)).unwrap();
// Test composition of all rows
let as_string = match serde_format {
SerdeFormat::Ron => ron::to_string(&rows_before).unwrap(),
SerdeFormat::Json => serde_json::to_string(&rows_before).unwrap(),
};
let rows_after: Data = match serde_format {
SerdeFormat::Ron => ron::from_str(&dbg!(as_string)).unwrap(),
SerdeFormat::Json => serde_json::from_str(&dbg!(as_string)).unwrap(),
};
assert_eq!(rows_after, rows_before);
});
}

fn create_log_row_no_extra() -> LogRow {
LogRow {
time: Some("time value".to_string()),
request_id: None,
otel_name: Some("otel value".to_string()),
msg: None,
extra: BTreeMap::new(),
}
}

fn create_log_row_with_extra() -> LogRow {
let mut result = LogRow {
time: Some("time value".to_string()),
request_id: None,
otel_name: Some("otel value".to_string()),
msg: None,
extra: BTreeMap::new(),
};
result.extra.insert("key".into(), "value".into());
result
}

#[rstest]
fn round_trip_from_manual(
#[values(SerdeFormat::Ron, SerdeFormat::Json)] serde_format: SerdeFormat,
#[values(create_log_row_no_extra(), create_log_row_with_extra())] before: LogRow,
) {
let as_string = match serde_format {
SerdeFormat::Ron => ron::to_string(&before).unwrap(),
SerdeFormat::Json => serde_json::to_string(&before).unwrap(),
};
println!("Serialized data:\n{as_string}");
let after: LogRow = match serde_format {
SerdeFormat::Ron => ron::from_str(&as_string).unwrap(),
SerdeFormat::Json => serde_json::from_str(&as_string).unwrap(),
};
assert_eq!(after, before);
}
}

0 comments on commit 27eb317

Please sign in to comment.