Merge #7921
7921: Don't punish every crate with serde-json r=matklad a=matklad
bors r+
🤖
Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
commit
071dde1c1d
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -1612,7 +1612,6 @@ dependencies = [
|
|||||||
"dissimilar",
|
"dissimilar",
|
||||||
"profile",
|
"profile",
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
"serde_json",
|
|
||||||
"stdx",
|
"stdx",
|
||||||
"text-size",
|
"text-size",
|
||||||
]
|
]
|
||||||
|
@ -13,7 +13,7 @@ use project_model::ProjectManifest;
|
|||||||
use rust_analyzer::{config::Config, lsp_ext, main_loop};
|
use rust_analyzer::{config::Config, lsp_ext, main_loop};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde_json::{json, to_string_pretty, Value};
|
use serde_json::{json, to_string_pretty, Value};
|
||||||
use test_utils::{find_mismatch, Fixture};
|
use test_utils::Fixture;
|
||||||
use vfs::AbsPathBuf;
|
use vfs::AbsPathBuf;
|
||||||
|
|
||||||
use crate::testdir::TestDir;
|
use crate::testdir::TestDir;
|
||||||
@ -279,3 +279,98 @@ fn recv_timeout(receiver: &Receiver<Message>) -> Result<Option<Message>, Timeout
|
|||||||
recv(after(timeout)) -> _ => Err(Timeout),
|
recv(after(timeout)) -> _ => Err(Timeout),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Comparison functionality borrowed from cargo:
|
||||||
|
|
||||||
|
/// Compares JSON object for approximate equality.
|
||||||
|
/// You can use `[..]` wildcard in strings (useful for OS dependent things such
|
||||||
|
/// as paths). You can use a `"{...}"` string literal as a wildcard for
|
||||||
|
/// arbitrary nested JSON. Arrays are sorted before comparison.
|
||||||
|
fn find_mismatch<'a>(expected: &'a Value, actual: &'a Value) -> Option<(&'a Value, &'a Value)> {
|
||||||
|
match (expected, actual) {
|
||||||
|
(Value::Number(l), Value::Number(r)) if l == r => None,
|
||||||
|
(Value::Bool(l), Value::Bool(r)) if l == r => None,
|
||||||
|
(Value::String(l), Value::String(r)) if lines_match(l, r) => None,
|
||||||
|
(Value::Array(l), Value::Array(r)) => {
|
||||||
|
if l.len() != r.len() {
|
||||||
|
return Some((expected, actual));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut l = l.iter().collect::<Vec<_>>();
|
||||||
|
let mut r = r.iter().collect::<Vec<_>>();
|
||||||
|
|
||||||
|
l.retain(|l| match r.iter().position(|r| find_mismatch(l, r).is_none()) {
|
||||||
|
Some(i) => {
|
||||||
|
r.remove(i);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
None => true,
|
||||||
|
});
|
||||||
|
|
||||||
|
if !l.is_empty() {
|
||||||
|
assert!(!r.is_empty());
|
||||||
|
Some((&l[0], &r[0]))
|
||||||
|
} else {
|
||||||
|
assert_eq!(r.len(), 0);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(Value::Object(l), Value::Object(r)) => {
|
||||||
|
fn sorted_values(obj: &serde_json::Map<String, Value>) -> Vec<&Value> {
|
||||||
|
let mut entries = obj.iter().collect::<Vec<_>>();
|
||||||
|
entries.sort_by_key(|it| it.0);
|
||||||
|
entries.into_iter().map(|(_k, v)| v).collect::<Vec<_>>()
|
||||||
|
}
|
||||||
|
|
||||||
|
let same_keys = l.len() == r.len() && l.keys().all(|k| r.contains_key(k));
|
||||||
|
if !same_keys {
|
||||||
|
return Some((expected, actual));
|
||||||
|
}
|
||||||
|
|
||||||
|
let l = sorted_values(l);
|
||||||
|
let r = sorted_values(r);
|
||||||
|
|
||||||
|
l.into_iter().zip(r).filter_map(|(l, r)| find_mismatch(l, r)).next()
|
||||||
|
}
|
||||||
|
(Value::Null, Value::Null) => None,
|
||||||
|
// magic string literal "{...}" acts as wildcard for any sub-JSON
|
||||||
|
(Value::String(l), _) if l == "{...}" => None,
|
||||||
|
_ => Some((expected, actual)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compare a line with an expected pattern.
|
||||||
|
/// - Use `[..]` as a wildcard to match 0 or more characters on the same line
|
||||||
|
/// (similar to `.*` in a regex).
|
||||||
|
fn lines_match(expected: &str, actual: &str) -> bool {
|
||||||
|
// Let's not deal with / vs \ (windows...)
|
||||||
|
// First replace backslash-escaped backslashes with forward slashes
|
||||||
|
// which can occur in, for example, JSON output
|
||||||
|
let expected = expected.replace(r"\\", "/").replace(r"\", "/");
|
||||||
|
let mut actual: &str = &actual.replace(r"\\", "/").replace(r"\", "/");
|
||||||
|
for (i, part) in expected.split("[..]").enumerate() {
|
||||||
|
match actual.find(part) {
|
||||||
|
Some(j) => {
|
||||||
|
if i == 0 && j != 0 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
actual = &actual[j + part.len()..];
|
||||||
|
}
|
||||||
|
None => return false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
actual.is_empty() || expected.ends_with("[..]")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn lines_match_works() {
|
||||||
|
assert!(lines_match("a b", "a b"));
|
||||||
|
assert!(lines_match("a[..]b", "a b"));
|
||||||
|
assert!(lines_match("a[..]", "a b"));
|
||||||
|
assert!(lines_match("[..]", "a b"));
|
||||||
|
assert!(lines_match("[..]b", "a b"));
|
||||||
|
|
||||||
|
assert!(!lines_match("[..]b", "c"));
|
||||||
|
assert!(!lines_match("b", "c"));
|
||||||
|
assert!(!lines_match("b", "cb"));
|
||||||
|
}
|
||||||
|
@ -13,7 +13,6 @@ doctest = false
|
|||||||
# Avoid adding deps here, this crate is widely used in tests it should compile fast!
|
# Avoid adding deps here, this crate is widely used in tests it should compile fast!
|
||||||
dissimilar = "1.0.2"
|
dissimilar = "1.0.2"
|
||||||
text-size = "1.0.0"
|
text-size = "1.0.0"
|
||||||
serde_json = "1.0.48"
|
|
||||||
rustc-hash = "1.1.0"
|
rustc-hash = "1.1.0"
|
||||||
|
|
||||||
stdx = { path = "../stdx", version = "0.0.0" }
|
stdx = { path = "../stdx", version = "0.0.0" }
|
||||||
|
@ -18,7 +18,6 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use profile::StopWatch;
|
use profile::StopWatch;
|
||||||
use serde_json::Value;
|
|
||||||
use stdx::lines_with_ends;
|
use stdx::lines_with_ends;
|
||||||
use text_size::{TextRange, TextSize};
|
use text_size::{TextRange, TextSize};
|
||||||
|
|
||||||
@ -281,101 +280,6 @@ fn main() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Comparison functionality borrowed from cargo:
|
|
||||||
|
|
||||||
/// Compare a line with an expected pattern.
|
|
||||||
/// - Use `[..]` as a wildcard to match 0 or more characters on the same line
|
|
||||||
/// (similar to `.*` in a regex).
|
|
||||||
pub fn lines_match(expected: &str, actual: &str) -> bool {
|
|
||||||
// Let's not deal with / vs \ (windows...)
|
|
||||||
// First replace backslash-escaped backslashes with forward slashes
|
|
||||||
// which can occur in, for example, JSON output
|
|
||||||
let expected = expected.replace(r"\\", "/").replace(r"\", "/");
|
|
||||||
let mut actual: &str = &actual.replace(r"\\", "/").replace(r"\", "/");
|
|
||||||
for (i, part) in expected.split("[..]").enumerate() {
|
|
||||||
match actual.find(part) {
|
|
||||||
Some(j) => {
|
|
||||||
if i == 0 && j != 0 {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
actual = &actual[j + part.len()..];
|
|
||||||
}
|
|
||||||
None => return false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
actual.is_empty() || expected.ends_with("[..]")
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn lines_match_works() {
|
|
||||||
assert!(lines_match("a b", "a b"));
|
|
||||||
assert!(lines_match("a[..]b", "a b"));
|
|
||||||
assert!(lines_match("a[..]", "a b"));
|
|
||||||
assert!(lines_match("[..]", "a b"));
|
|
||||||
assert!(lines_match("[..]b", "a b"));
|
|
||||||
|
|
||||||
assert!(!lines_match("[..]b", "c"));
|
|
||||||
assert!(!lines_match("b", "c"));
|
|
||||||
assert!(!lines_match("b", "cb"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Compares JSON object for approximate equality.
|
|
||||||
/// You can use `[..]` wildcard in strings (useful for OS dependent things such
|
|
||||||
/// as paths). You can use a `"{...}"` string literal as a wildcard for
|
|
||||||
/// arbitrary nested JSON. Arrays are sorted before comparison.
|
|
||||||
pub fn find_mismatch<'a>(expected: &'a Value, actual: &'a Value) -> Option<(&'a Value, &'a Value)> {
|
|
||||||
match (expected, actual) {
|
|
||||||
(Value::Number(l), Value::Number(r)) if l == r => None,
|
|
||||||
(Value::Bool(l), Value::Bool(r)) if l == r => None,
|
|
||||||
(Value::String(l), Value::String(r)) if lines_match(l, r) => None,
|
|
||||||
(Value::Array(l), Value::Array(r)) => {
|
|
||||||
if l.len() != r.len() {
|
|
||||||
return Some((expected, actual));
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut l = l.iter().collect::<Vec<_>>();
|
|
||||||
let mut r = r.iter().collect::<Vec<_>>();
|
|
||||||
|
|
||||||
l.retain(|l| match r.iter().position(|r| find_mismatch(l, r).is_none()) {
|
|
||||||
Some(i) => {
|
|
||||||
r.remove(i);
|
|
||||||
false
|
|
||||||
}
|
|
||||||
None => true,
|
|
||||||
});
|
|
||||||
|
|
||||||
if !l.is_empty() {
|
|
||||||
assert!(!r.is_empty());
|
|
||||||
Some((&l[0], &r[0]))
|
|
||||||
} else {
|
|
||||||
assert_eq!(r.len(), 0);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(Value::Object(l), Value::Object(r)) => {
|
|
||||||
fn sorted_values(obj: &serde_json::Map<String, Value>) -> Vec<&Value> {
|
|
||||||
let mut entries = obj.iter().collect::<Vec<_>>();
|
|
||||||
entries.sort_by_key(|it| it.0);
|
|
||||||
entries.into_iter().map(|(_k, v)| v).collect::<Vec<_>>()
|
|
||||||
}
|
|
||||||
|
|
||||||
let same_keys = l.len() == r.len() && l.keys().all(|k| r.contains_key(k));
|
|
||||||
if !same_keys {
|
|
||||||
return Some((expected, actual));
|
|
||||||
}
|
|
||||||
|
|
||||||
let l = sorted_values(l);
|
|
||||||
let r = sorted_values(r);
|
|
||||||
|
|
||||||
l.into_iter().zip(r).filter_map(|(l, r)| find_mismatch(l, r)).next()
|
|
||||||
}
|
|
||||||
(Value::Null, Value::Null) => None,
|
|
||||||
// magic string literal "{...}" acts as wildcard for any sub-JSON
|
|
||||||
(Value::String(l), _) if l == "{...}" => None,
|
|
||||||
_ => Some((expected, actual)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns `false` if slow tests should not run, otherwise returns `true` and
|
/// Returns `false` if slow tests should not run, otherwise returns `true` and
|
||||||
/// also creates a file at `./target/.slow_tests_cookie` which serves as a flag
|
/// also creates a file at `./target/.slow_tests_cookie` which serves as a flag
|
||||||
/// that slow tests did run.
|
/// that slow tests did run.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user