diff options
author | Aleksey Kladov <[email protected]> | 2021-03-08 17:27:08 +0000 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2021-03-08 17:37:20 +0000 |
commit | da73c93c7f6d841496e75a16531d9be4aa23cada (patch) | |
tree | 360aae1dc872b22a71014f253e3a98f21a3502a6 /crates | |
parent | d57c9f79801762aa23adc21adbb638678268e96b (diff) |
Don't punish every crate with serde-json
Diffstat (limited to 'crates')
-rw-r--r-- | crates/rust-analyzer/tests/rust-analyzer/support.rs | 97 | ||||
-rw-r--r-- | crates/test_utils/Cargo.toml | 1 | ||||
-rw-r--r-- | crates/test_utils/src/lib.rs | 96 |
3 files changed, 96 insertions, 98 deletions
diff --git a/crates/rust-analyzer/tests/rust-analyzer/support.rs b/crates/rust-analyzer/tests/rust-analyzer/support.rs index 6b774073d..cd0c91481 100644 --- a/crates/rust-analyzer/tests/rust-analyzer/support.rs +++ b/crates/rust-analyzer/tests/rust-analyzer/support.rs | |||
@@ -13,7 +13,7 @@ use project_model::ProjectManifest; | |||
13 | use rust_analyzer::{config::Config, lsp_ext, main_loop}; | 13 | use rust_analyzer::{config::Config, lsp_ext, main_loop}; |
14 | use serde::Serialize; | 14 | use serde::Serialize; |
15 | use serde_json::{json, to_string_pretty, Value}; | 15 | use serde_json::{json, to_string_pretty, Value}; |
16 | use test_utils::{find_mismatch, Fixture}; | 16 | use test_utils::Fixture; |
17 | use vfs::AbsPathBuf; | 17 | use vfs::AbsPathBuf; |
18 | 18 | ||
19 | use crate::testdir::TestDir; | 19 | use crate::testdir::TestDir; |
@@ -279,3 +279,98 @@ fn recv_timeout(receiver: &Receiver<Message>) -> Result<Option<Message>, Timeout | |||
279 | recv(after(timeout)) -> _ => Err(Timeout), | 279 | recv(after(timeout)) -> _ => Err(Timeout), |
280 | } | 280 | } |
281 | } | 281 | } |
282 | |||
283 | // Comparison functionality borrowed from cargo: | ||
284 | |||
285 | /// Compares JSON object for approximate equality. | ||
286 | /// You can use `[..]` wildcard in strings (useful for OS dependent things such | ||
287 | /// as paths). You can use a `"{...}"` string literal as a wildcard for | ||
288 | /// arbitrary nested JSON. Arrays are sorted before comparison. | ||
289 | fn find_mismatch<'a>(expected: &'a Value, actual: &'a Value) -> Option<(&'a Value, &'a Value)> { | ||
290 | match (expected, actual) { | ||
291 | (Value::Number(l), Value::Number(r)) if l == r => None, | ||
292 | (Value::Bool(l), Value::Bool(r)) if l == r => None, | ||
293 | (Value::String(l), Value::String(r)) if lines_match(l, r) => None, | ||
294 | (Value::Array(l), Value::Array(r)) => { | ||
295 | if l.len() != r.len() { | ||
296 | return Some((expected, actual)); | ||
297 | } | ||
298 | |||
299 | let mut l = l.iter().collect::<Vec<_>>(); | ||
300 | let mut r = r.iter().collect::<Vec<_>>(); | ||
301 | |||
302 | l.retain(|l| match r.iter().position(|r| find_mismatch(l, r).is_none()) { | ||
303 | Some(i) => { | ||
304 | r.remove(i); | ||
305 | false | ||
306 | } | ||
307 | None => true, | ||
308 | }); | ||
309 | |||
310 | if !l.is_empty() { | ||
311 | assert!(!r.is_empty()); | ||
312 | Some((&l[0], &r[0])) | ||
313 | } else { | ||
314 | assert_eq!(r.len(), 0); | ||
315 | None | ||
316 | } | ||
317 | } | ||
318 | (Value::Object(l), Value::Object(r)) => { | ||
319 | fn sorted_values(obj: &serde_json::Map<String, Value>) -> Vec<&Value> { | ||
320 | let mut entries = obj.iter().collect::<Vec<_>>(); | ||
321 | entries.sort_by_key(|it| it.0); | ||
322 | entries.into_iter().map(|(_k, v)| v).collect::<Vec<_>>() | ||
323 | } | ||
324 | |||
325 | let same_keys = l.len() == r.len() && l.keys().all(|k| r.contains_key(k)); | ||
326 | if !same_keys { | ||
327 | return Some((expected, actual)); | ||
328 | } | ||
329 | |||
330 | let l = sorted_values(l); | ||
331 | let r = sorted_values(r); | ||
332 | |||
333 | l.into_iter().zip(r).filter_map(|(l, r)| find_mismatch(l, r)).next() | ||
334 | } | ||
335 | (Value::Null, Value::Null) => None, | ||
336 | // magic string literal "{...}" acts as wildcard for any sub-JSON | ||
337 | (Value::String(l), _) if l == "{...}" => None, | ||
338 | _ => Some((expected, actual)), | ||
339 | } | ||
340 | } | ||
341 | |||
342 | /// Compare a line with an expected pattern. | ||
343 | /// - Use `[..]` as a wildcard to match 0 or more characters on the same line | ||
344 | /// (similar to `.*` in a regex). | ||
345 | fn lines_match(expected: &str, actual: &str) -> bool { | ||
346 | // Let's not deal with / vs \ (windows...) | ||
347 | // First replace backslash-escaped backslashes with forward slashes | ||
348 | // which can occur in, for example, JSON output | ||
349 | let expected = expected.replace(r"\\", "/").replace(r"\", "/"); | ||
350 | let mut actual: &str = &actual.replace(r"\\", "/").replace(r"\", "/"); | ||
351 | for (i, part) in expected.split("[..]").enumerate() { | ||
352 | match actual.find(part) { | ||
353 | Some(j) => { | ||
354 | if i == 0 && j != 0 { | ||
355 | return false; | ||
356 | } | ||
357 | actual = &actual[j + part.len()..]; | ||
358 | } | ||
359 | None => return false, | ||
360 | } | ||
361 | } | ||
362 | actual.is_empty() || expected.ends_with("[..]") | ||
363 | } | ||
364 | |||
365 | #[test] | ||
366 | fn lines_match_works() { | ||
367 | assert!(lines_match("a b", "a b")); | ||
368 | assert!(lines_match("a[..]b", "a b")); | ||
369 | assert!(lines_match("a[..]", "a b")); | ||
370 | assert!(lines_match("[..]", "a b")); | ||
371 | assert!(lines_match("[..]b", "a b")); | ||
372 | |||
373 | assert!(!lines_match("[..]b", "c")); | ||
374 | assert!(!lines_match("b", "c")); | ||
375 | assert!(!lines_match("b", "cb")); | ||
376 | } | ||
diff --git a/crates/test_utils/Cargo.toml b/crates/test_utils/Cargo.toml index 2a65000b8..87bab7a08 100644 --- a/crates/test_utils/Cargo.toml +++ b/crates/test_utils/Cargo.toml | |||
@@ -13,7 +13,6 @@ doctest = false | |||
13 | # Avoid adding deps here, this crate is widely used in tests it should compile fast! | 13 | # Avoid adding deps here, this crate is widely used in tests it should compile fast! |
14 | dissimilar = "1.0.2" | 14 | dissimilar = "1.0.2" |
15 | text-size = "1.0.0" | 15 | text-size = "1.0.0" |
16 | serde_json = "1.0.48" | ||
17 | rustc-hash = "1.1.0" | 16 | rustc-hash = "1.1.0" |
18 | 17 | ||
19 | stdx = { path = "../stdx", version = "0.0.0" } | 18 | stdx = { path = "../stdx", version = "0.0.0" } |
diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs index 5be4a64fc..27b05e34b 100644 --- a/crates/test_utils/src/lib.rs +++ b/crates/test_utils/src/lib.rs | |||
@@ -18,7 +18,6 @@ use std::{ | |||
18 | }; | 18 | }; |
19 | 19 | ||
20 | use profile::StopWatch; | 20 | use profile::StopWatch; |
21 | use serde_json::Value; | ||
22 | use stdx::lines_with_ends; | 21 | use stdx::lines_with_ends; |
23 | use text_size::{TextRange, TextSize}; | 22 | use text_size::{TextRange, TextSize}; |
24 | 23 | ||
@@ -281,101 +280,6 @@ fn main() { | |||
281 | ); | 280 | ); |
282 | } | 281 | } |
283 | 282 | ||
284 | // Comparison functionality borrowed from cargo: | ||
285 | |||
286 | /// Compare a line with an expected pattern. | ||
287 | /// - Use `[..]` as a wildcard to match 0 or more characters on the same line | ||
288 | /// (similar to `.*` in a regex). | ||
289 | pub fn lines_match(expected: &str, actual: &str) -> bool { | ||
290 | // Let's not deal with / vs \ (windows...) | ||
291 | // First replace backslash-escaped backslashes with forward slashes | ||
292 | // which can occur in, for example, JSON output | ||
293 | let expected = expected.replace(r"\\", "/").replace(r"\", "/"); | ||
294 | let mut actual: &str = &actual.replace(r"\\", "/").replace(r"\", "/"); | ||
295 | for (i, part) in expected.split("[..]").enumerate() { | ||
296 | match actual.find(part) { | ||
297 | Some(j) => { | ||
298 | if i == 0 && j != 0 { | ||
299 | return false; | ||
300 | } | ||
301 | actual = &actual[j + part.len()..]; | ||
302 | } | ||
303 | None => return false, | ||
304 | } | ||
305 | } | ||
306 | actual.is_empty() || expected.ends_with("[..]") | ||
307 | } | ||
308 | |||
309 | #[test] | ||
310 | fn lines_match_works() { | ||
311 | assert!(lines_match("a b", "a b")); | ||
312 | assert!(lines_match("a[..]b", "a b")); | ||
313 | assert!(lines_match("a[..]", "a b")); | ||
314 | assert!(lines_match("[..]", "a b")); | ||
315 | assert!(lines_match("[..]b", "a b")); | ||
316 | |||
317 | assert!(!lines_match("[..]b", "c")); | ||
318 | assert!(!lines_match("b", "c")); | ||
319 | assert!(!lines_match("b", "cb")); | ||
320 | } | ||
321 | |||
322 | /// Compares JSON object for approximate equality. | ||
323 | /// You can use `[..]` wildcard in strings (useful for OS dependent things such | ||
324 | /// as paths). You can use a `"{...}"` string literal as a wildcard for | ||
325 | /// arbitrary nested JSON. Arrays are sorted before comparison. | ||
326 | pub fn find_mismatch<'a>(expected: &'a Value, actual: &'a Value) -> Option<(&'a Value, &'a Value)> { | ||
327 | match (expected, actual) { | ||
328 | (Value::Number(l), Value::Number(r)) if l == r => None, | ||
329 | (Value::Bool(l), Value::Bool(r)) if l == r => None, | ||
330 | (Value::String(l), Value::String(r)) if lines_match(l, r) => None, | ||
331 | (Value::Array(l), Value::Array(r)) => { | ||
332 | if l.len() != r.len() { | ||
333 | return Some((expected, actual)); | ||
334 | } | ||
335 | |||
336 | let mut l = l.iter().collect::<Vec<_>>(); | ||
337 | let mut r = r.iter().collect::<Vec<_>>(); | ||
338 | |||
339 | l.retain(|l| match r.iter().position(|r| find_mismatch(l, r).is_none()) { | ||
340 | Some(i) => { | ||
341 | r.remove(i); | ||
342 | false | ||
343 | } | ||
344 | None => true, | ||
345 | }); | ||
346 | |||
347 | if !l.is_empty() { | ||
348 | assert!(!r.is_empty()); | ||
349 | Some((&l[0], &r[0])) | ||
350 | } else { | ||
351 | assert_eq!(r.len(), 0); | ||
352 | None | ||
353 | } | ||
354 | } | ||
355 | (Value::Object(l), Value::Object(r)) => { | ||
356 | fn sorted_values(obj: &serde_json::Map<String, Value>) -> Vec<&Value> { | ||
357 | let mut entries = obj.iter().collect::<Vec<_>>(); | ||
358 | entries.sort_by_key(|it| it.0); | ||
359 | entries.into_iter().map(|(_k, v)| v).collect::<Vec<_>>() | ||
360 | } | ||
361 | |||
362 | let same_keys = l.len() == r.len() && l.keys().all(|k| r.contains_key(k)); | ||
363 | if !same_keys { | ||
364 | return Some((expected, actual)); | ||
365 | } | ||
366 | |||
367 | let l = sorted_values(l); | ||
368 | let r = sorted_values(r); | ||
369 | |||
370 | l.into_iter().zip(r).filter_map(|(l, r)| find_mismatch(l, r)).next() | ||
371 | } | ||
372 | (Value::Null, Value::Null) => None, | ||
373 | // magic string literal "{...}" acts as wildcard for any sub-JSON | ||
374 | (Value::String(l), _) if l == "{...}" => None, | ||
375 | _ => Some((expected, actual)), | ||
376 | } | ||
377 | } | ||
378 | |||
379 | /// Returns `false` if slow tests should not run, otherwise returns `true` and | 283 | /// Returns `false` if slow tests should not run, otherwise returns `true` and |
380 | /// also creates a file at `./target/.slow_tests_cookie` which serves as a flag | 284 | /// also creates a file at `./target/.slow_tests_cookie` which serves as a flag |
381 | /// that slow tests did run. | 285 | /// that slow tests did run. |