/ cli / src / test / error.rs
error.rs
 1  use std::io::Write;
 2  
 3  use colored::Colorize;
 4  use serde_json::Value;
 5  use similar_asserts::serde_impl::Debug as SimilarAssertsDebug;
 6  use similar_asserts::SimpleDiff;
 7  use tracing::warn;
 8  
 9  const TRUNCATE_THRESHOLD: usize = 1000;
10  const DIFF_TRUNCATE_THRESHOLD: usize = 2000;
11  
12  fn truncate(s: &str, threshold: usize, write_tempfile: bool) -> String {
13      if s.chars().count() <= threshold {
14          return s.to_owned();
15      }
16  
17      let mut full_output_hint = "".to_owned();
18  
19      if write_tempfile {
20          match tempfile::Builder::new()
21              .prefix("apibara-test-diff-")
22              .suffix(".patch")
23              .tempfile()
24              .map_err(|err| err.to_string())
25              .and_then(|keep| keep.keep().map_err(|err| err.to_string()))
26              .and_then(|(mut file, path)| match file.write_all(s.as_bytes()) {
27                  Ok(_) => Ok(path),
28                  Err(err) => Err(err.to_string()),
29              }) {
30              Ok(path) => full_output_hint = format!(", full output written to `{}`", path.display()),
31              Err(err) => {
32                  warn!(err =? err, "Cannot create tempfile to save long diff");
33              }
34          }
35      }
36  
37      let start = &s[..threshold / 2];
38      let end = &s[s.len() - threshold / 2..];
39  
40      let truncated_prefix = format!("<truncated{}>\n", full_output_hint).yellow();
41  
42      let truncated_msg = format!(
43          "\n ... \n {} chars truncated{}\n ... \n",
44          s.chars().count() - threshold,
45          full_output_hint,
46      )
47      .yellow();
48  
49      format!("{truncated_prefix} {start} {truncated_msg} {end}")
50  }
51  
52  pub fn get_assertion_error(expected_outputs: &[Value], found_outputs: &[Value]) -> String {
53      let left = format!("{:#?}", SimilarAssertsDebug(&expected_outputs));
54      let right = format!("{:#?}", SimilarAssertsDebug(&found_outputs));
55  
56      let left_label = "expected";
57      let right_label = "found";
58      let label_padding = left_label.chars().count().max(right_label.chars().count());
59  
60      let diff = SimpleDiff::from_str(left.as_str(), right.as_str(), left_label, right_label);
61  
62      let assert_fail = format!(
63          "assertion failed: `({} == {})`'\n {:<label_padding$}: `{:?}`\n {:<label_padding$}: `{:?}`",
64          left_label,
65          right_label,
66          left_label,
67          truncate(&left, TRUNCATE_THRESHOLD, false),
68          right_label,
69          truncate(&right, TRUNCATE_THRESHOLD, false),
70          label_padding = label_padding,
71      )
72      .bright_red();
73  
74      let diff_str = truncate(&diff.to_string(), DIFF_TRUNCATE_THRESHOLD, true);
75  
76      format!("{}\n\n{}", &assert_fail, &diff_str)
77  }