Skip to content

Commit ad074ab

Browse files
committed
Auto merge of #14576 - epage:tests, r=weihanglo
test: Remove the last of our custom json assertions ### What does this PR try to resolve? This is part of #14039 and consolidates us down to only one way of doing json assertions, using snapbox. ### How should we test and review this PR? ### Additional information
2 parents e1179b5 + c3f19a8 commit ad074ab

File tree

7 files changed

+380
-844
lines changed

7 files changed

+380
-844
lines changed

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ sha2 = "0.10.8"
9393
shell-escape = "0.1.5"
9494
similar = "2.6.0"
9595
supports-hyperlinks = "3.0.0"
96-
snapbox = { version = "0.6.17", features = ["diff", "dir", "term-svg", "regex", "json"] }
96+
snapbox = { version = "0.6.18", features = ["diff", "dir", "term-svg", "regex", "json"] }
9797
tar = { version = "0.4.42", default-features = false }
9898
tempfile = "3.10.1"
9999
thiserror = "1.0.63"

crates/cargo-test-support/src/compare.rs

Lines changed: 1 addition & 155 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,7 @@
4444
use crate::cross_compile::try_alternate;
4545
use crate::paths;
4646
use crate::{diff, rustc_host};
47-
use anyhow::{bail, Context, Result};
48-
use serde_json::Value;
47+
use anyhow::{bail, Result};
4948
use std::fmt;
5049
use std::path::Path;
5150
use std::str;
@@ -654,159 +653,6 @@ pub(crate) fn match_with_without(
654653
}
655654
}
656655

657-
/// Checks that the given string of JSON objects match the given set of
658-
/// expected JSON objects.
659-
///
660-
/// See [`crate::Execs::with_json`] for more details.
661-
pub(crate) fn match_json(expected: &str, actual: &str, cwd: Option<&Path>) -> Result<()> {
662-
let (exp_objs, act_objs) = collect_json_objects(expected, actual)?;
663-
if exp_objs.len() != act_objs.len() {
664-
bail!(
665-
"expected {} json lines, got {}, stdout:\n{}",
666-
exp_objs.len(),
667-
act_objs.len(),
668-
actual
669-
);
670-
}
671-
for (exp_obj, act_obj) in exp_objs.iter().zip(act_objs) {
672-
find_json_mismatch(exp_obj, &act_obj, cwd)?;
673-
}
674-
Ok(())
675-
}
676-
677-
/// Checks that the given string of JSON objects match the given set of
678-
/// expected JSON objects, ignoring their order.
679-
///
680-
/// See [`crate::Execs::with_json_contains_unordered`] for more details and
681-
/// cautions when using.
682-
pub(crate) fn match_json_contains_unordered(
683-
expected: &str,
684-
actual: &str,
685-
cwd: Option<&Path>,
686-
) -> Result<()> {
687-
let (exp_objs, mut act_objs) = collect_json_objects(expected, actual)?;
688-
for exp_obj in exp_objs {
689-
match act_objs
690-
.iter()
691-
.position(|act_obj| find_json_mismatch(&exp_obj, act_obj, cwd).is_ok())
692-
{
693-
Some(index) => act_objs.remove(index),
694-
None => {
695-
bail!(
696-
"Did not find expected JSON:\n\
697-
{}\n\
698-
Remaining available output:\n\
699-
{}\n",
700-
serde_json::to_string_pretty(&exp_obj).unwrap(),
701-
itertools::join(
702-
act_objs.iter().map(|o| serde_json::to_string(o).unwrap()),
703-
"\n"
704-
)
705-
);
706-
}
707-
};
708-
}
709-
Ok(())
710-
}
711-
712-
fn collect_json_objects(
713-
expected: &str,
714-
actual: &str,
715-
) -> Result<(Vec<serde_json::Value>, Vec<serde_json::Value>)> {
716-
let expected_objs: Vec<_> = expected
717-
.split("\n\n")
718-
.map(|expect| {
719-
expect
720-
.parse()
721-
.with_context(|| format!("failed to parse expected JSON object:\n{}", expect))
722-
})
723-
.collect::<Result<_>>()?;
724-
let actual_objs: Vec<_> = actual
725-
.lines()
726-
.filter(|line| line.starts_with('{'))
727-
.map(|line| {
728-
line.parse()
729-
.with_context(|| format!("failed to parse JSON object:\n{}", line))
730-
})
731-
.collect::<Result<_>>()?;
732-
Ok((expected_objs, actual_objs))
733-
}
734-
735-
/// Compares JSON object for approximate equality.
736-
/// You can use `[..]` wildcard in strings (useful for OS-dependent things such
737-
/// as paths). You can use a `"{...}"` string literal as a wildcard for
738-
/// arbitrary nested JSON (useful for parts of object emitted by other programs
739-
/// (e.g., rustc) rather than Cargo itself).
740-
pub(crate) fn find_json_mismatch(
741-
expected: &Value,
742-
actual: &Value,
743-
cwd: Option<&Path>,
744-
) -> Result<()> {
745-
match find_json_mismatch_r(expected, actual, cwd) {
746-
Some((expected_part, actual_part)) => bail!(
747-
"JSON mismatch\nExpected:\n{}\nWas:\n{}\nExpected part:\n{}\nActual part:\n{}\n",
748-
serde_json::to_string_pretty(expected).unwrap(),
749-
serde_json::to_string_pretty(&actual).unwrap(),
750-
serde_json::to_string_pretty(expected_part).unwrap(),
751-
serde_json::to_string_pretty(actual_part).unwrap(),
752-
),
753-
None => Ok(()),
754-
}
755-
}
756-
757-
fn find_json_mismatch_r<'a>(
758-
expected: &'a Value,
759-
actual: &'a Value,
760-
cwd: Option<&Path>,
761-
) -> Option<(&'a Value, &'a Value)> {
762-
use serde_json::Value::*;
763-
match (expected, actual) {
764-
(&Number(ref l), &Number(ref r)) if l == r => None,
765-
(&Bool(l), &Bool(r)) if l == r => None,
766-
(&String(ref l), _) if l == "{...}" => None,
767-
(&String(ref l), &String(ref r)) => {
768-
if match_exact(l, r, "", "", cwd).is_err() {
769-
Some((expected, actual))
770-
} else {
771-
None
772-
}
773-
}
774-
(&Array(ref l), &Array(ref r)) => {
775-
if l.len() != r.len() {
776-
return Some((expected, actual));
777-
}
778-
779-
l.iter()
780-
.zip(r.iter())
781-
.filter_map(|(l, r)| find_json_mismatch_r(l, r, cwd))
782-
.next()
783-
}
784-
(&Object(ref l), &Object(ref r)) => {
785-
let mut expected_entries = l.iter();
786-
let mut actual_entries = r.iter();
787-
788-
loop {
789-
match (expected_entries.next(), actual_entries.next()) {
790-
(None, None) => return None,
791-
(Some((expected_key, expected_value)), Some((actual_key, actual_value)))
792-
if expected_key == actual_key =>
793-
{
794-
if let mismatch @ Some(_) =
795-
find_json_mismatch_r(expected_value, actual_value, cwd)
796-
{
797-
return mismatch;
798-
}
799-
}
800-
_ => return Some((expected, actual)),
801-
}
802-
}
803-
}
804-
(&Null, &Null) => None,
805-
// Magic string literal `"{...}"` acts as wildcard for any sub-JSON.
806-
_ => Some((expected, actual)),
807-
}
808-
}
809-
810656
/// A single line string that supports `[..]` wildcard matching.
811657
pub(crate) struct WildStr<'a> {
812658
has_meta: bool,

crates/cargo-test-support/src/lib.rs

Lines changed: 0 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -655,8 +655,6 @@ pub struct Execs {
655655
expect_stdout_unordered: Vec<String>,
656656
expect_stderr_unordered: Vec<String>,
657657
expect_stderr_with_without: Vec<(Vec<String>, Vec<String>)>,
658-
expect_json: Option<String>,
659-
expect_json_contains_unordered: Option<String>,
660658
stream_output: bool,
661659
assert: snapbox::Assert,
662660
}
@@ -824,56 +822,6 @@ impl Execs {
824822
self.expect_stderr_with_without.push((with, without));
825823
self
826824
}
827-
828-
/// Verifies the JSON output matches the given JSON.
829-
///
830-
/// This is typically used when testing cargo commands that emit JSON.
831-
/// Each separate JSON object should be separated by a blank line.
832-
/// Example:
833-
///
834-
/// ```rust,ignore
835-
/// assert_that(
836-
/// p.cargo("metadata"),
837-
/// execs().with_json(r#"
838-
/// {"example": "abc"}
839-
///
840-
/// {"example": "def"}
841-
/// "#)
842-
/// );
843-
/// ```
844-
///
845-
/// - Objects should match in the order given.
846-
/// - The order of arrays is ignored.
847-
/// - Strings support patterns described in [`compare`].
848-
/// - Use `"{...}"` to match any object.
849-
#[deprecated(
850-
note = "replaced with `Execs::with_stdout_data(expected.is_json().against_jsonlines())`"
851-
)]
852-
pub fn with_json(&mut self, expected: &str) -> &mut Self {
853-
self.expect_json = Some(expected.to_string());
854-
self
855-
}
856-
857-
/// Verifies JSON output contains the given objects (in any order) somewhere
858-
/// in its output.
859-
///
860-
/// CAUTION: Be very careful when using this. Make sure every object is
861-
/// unique (not a subset of one another). Also avoid using objects that
862-
/// could possibly match multiple output lines unless you're very sure of
863-
/// what you are doing.
864-
///
865-
/// See `with_json` for more detail.
866-
#[deprecated]
867-
pub fn with_json_contains_unordered(&mut self, expected: &str) -> &mut Self {
868-
match &mut self.expect_json_contains_unordered {
869-
None => self.expect_json_contains_unordered = Some(expected.to_string()),
870-
Some(e) => {
871-
e.push_str("\n\n");
872-
e.push_str(expected);
873-
}
874-
}
875-
self
876-
}
877825
}
878826

879827
/// # Configure the process
@@ -1050,8 +998,6 @@ impl Execs {
1050998
&& self.expect_stdout_unordered.is_empty()
1051999
&& self.expect_stderr_unordered.is_empty()
10521000
&& self.expect_stderr_with_without.is_empty()
1053-
&& self.expect_json.is_none()
1054-
&& self.expect_json_contains_unordered.is_none()
10551001
{
10561002
panic!(
10571003
"`with_status()` is used, but no output is checked.\n\
@@ -1175,14 +1121,6 @@ impl Execs {
11751121
for (with, without) in self.expect_stderr_with_without.iter() {
11761122
compare::match_with_without(stderr, with, without, cwd)?;
11771123
}
1178-
1179-
if let Some(ref expect_json) = self.expect_json {
1180-
compare::match_json(expect_json, stdout, cwd)?;
1181-
}
1182-
1183-
if let Some(ref expected) = self.expect_json_contains_unordered {
1184-
compare::match_json_contains_unordered(expected, stdout, cwd)?;
1185-
}
11861124
Ok(())
11871125
}
11881126
}
@@ -1212,8 +1150,6 @@ pub fn execs() -> Execs {
12121150
expect_stdout_unordered: Vec::new(),
12131151
expect_stderr_unordered: Vec::new(),
12141152
expect_stderr_with_without: Vec::new(),
1215-
expect_json: None,
1216-
expect_json_contains_unordered: None,
12171153
stream_output: false,
12181154
assert: compare::assert_e2e(),
12191155
}

crates/cargo-test-support/src/publish.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,10 @@
5757
//! );
5858
//! ```
5959
60-
use crate::compare::{assert_match_exact, find_json_mismatch};
60+
use crate::compare::assert_match_exact;
6161
use crate::registry::{self, alt_api_path, FeatureMap};
6262
use flate2::read::GzDecoder;
63+
use snapbox::prelude::*;
6364
use std::collections::{HashMap, HashSet};
6465
use std::fs;
6566
use std::fs::File;
@@ -133,12 +134,8 @@ fn _validate_upload(
133134
let json_sz = read_le_u32(&mut f).expect("read json length");
134135
let mut json_bytes = vec![0; json_sz as usize];
135136
f.read_exact(&mut json_bytes).expect("read JSON data");
136-
let actual_json = serde_json::from_slice(&json_bytes).expect("uploaded JSON should be valid");
137-
let expected_json = serde_json::from_str(expected_json).expect("expected JSON does not parse");
138137

139-
if let Err(e) = find_json_mismatch(&expected_json, &actual_json, None) {
140-
panic!("{}", e);
141-
}
138+
snapbox::assert_data_eq!(json_bytes, expected_json.is_json());
142139

143140
// 32-bit little-endian integer of length of crate file.
144141
let crate_sz = read_le_u32(&mut f).expect("read crate length");

0 commit comments

Comments
 (0)