From 46826ea7c64445c44030c3a45b0e000f366da9e7 Mon Sep 17 00:00:00 2001 From: Luca Barbato Date: Wed, 14 Dec 2022 15:39:51 +0100 Subject: [PATCH 1/6] Make sure the submodules are populated before running cargo test --- .taskcluster.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.taskcluster.yml b/.taskcluster.yml index 31bea92a6..f891604cd 100644 --- a/.taskcluster.yml +++ b/.taskcluster.yml @@ -47,6 +47,7 @@ tasks: git clone --quiet ${repository} && cd rust-code-analysis && git -c advice.detachedHead=false checkout ${head_rev} && + git submodule update --init && pip3 install --quiet pre-commit && pre-commit run -a --show-diff-on-failure && pre-commit run --show-diff-on-failure -c .pre-commit-audit-config.yaml && @@ -113,6 +114,7 @@ tasks: git clone --quiet ${repository} && cd rust-code-analysis && git -c advice.detachedHead=false checkout ${head_rev} && + git submodule update --init && cargo test --workspace --verbose --all-features --target x86_64-unknown-linux-gnu && ../grcov . --binary-path ./target/ -s . -t lcov --llvm --branch --ignore-not-existing --ignore '/*' -o lcov.info && bash <(curl -s https://codecov.io/bash) -f lcov.info" @@ -143,6 +145,7 @@ tasks: - git clone --quiet ${repository} - cd rust-code-analysis - git -c advice.detachedHead=false checkout ${head_rev} + - git submodule update --init - cargo test --workspace --verbose --all-features mounts: - content: From 198e6bc6fea5842bd0ecd2b32e72a9ccb7be77c3 Mon Sep 17 00:00:00 2001 From: Luca Barbato Date: Mon, 12 Dec 2022 21:55:48 +0100 Subject: [PATCH 2/6] Remove rust std from the tests --- .gitmodules | 3 --- tests/repositories/rust | 1 - tests/test.rs | 5 ----- 3 files changed, 9 deletions(-) delete mode 160000 tests/repositories/rust diff --git a/.gitmodules b/.gitmodules index 2461c52e7..eeb18ad01 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,9 +4,6 @@ [submodule "tests/repositories/DeepSpeech"] path = tests/repositories/DeepSpeech url = https://github.com/mozilla/DeepSpeech -[submodule "tests/repositories/rust"] - path = tests/repositories/rust - url = https://github.com/rust-lang/rust.git [submodule "tests/repositories/pdf.js"] path = tests/repositories/pdf.js url = https://github.com/mozilla/pdf.js diff --git a/tests/repositories/rust b/tests/repositories/rust deleted file mode 160000 index f1edd0429..000000000 --- a/tests/repositories/rust +++ /dev/null @@ -1 +0,0 @@ -Subproject commit f1edd0429582dd29cccacaf50fd134b05593bd9c diff --git a/tests/test.rs b/tests/test.rs index b3c8645a7..529134405 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -211,8 +211,3 @@ fn test_deepspeech() { fn test_pdfjs() { compare_rca_output_with_files("pdf.js", &["*.js"]); } - -#[test] -fn test_rust_library() { - compare_rca_output_with_files("rust", &["*/library/*.rs"]); -} From bd7a79d211471b13de6ade8e11b9c822bad33a72 Mon Sep 17 00:00:00 2001 From: Luca Barbato Date: Tue, 6 Dec 2022 12:49:07 +0100 Subject: [PATCH 3/6] Use insta --- Cargo.lock | 55 +++++++++++- Cargo.toml | 8 +- README.md | 9 ++ tests/repositories/rca-output | 2 +- tests/test.rs | 154 +++------------------------------- 5 files changed, 80 insertions(+), 148 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a75f0ec95..659c74a18 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -382,6 +382,19 @@ dependencies = [ "os_str_bytes", ] +[[package]] +name = "console" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c050367d967ced717c04b65d8c619d863ef9292ce0c5760028655a2fb298718c" +dependencies = [ + "encode_unicode", + "lazy_static", + "libc", + "terminal_size", + "winapi", +] + [[package]] name = "convert_case" version = "0.4.0" @@ -534,6 +547,12 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + [[package]] name = "encoding_rs" version = "0.8.29" @@ -805,6 +824,20 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "insta" +version = "1.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e48b08a091dfe5b09a6a9688c468fdd5b4396e92ce09e2eb932f0884b02788a4" +dependencies = [ + "console", + "lazy_static", + "linked-hash-map", + "serde", + "similar", + "yaml-rust", +] + [[package]] name = "itoa" version = "0.4.8" @@ -846,9 +879,9 @@ checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" [[package]] name = "linked-hash-map" -version = "0.5.4" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "local-channel" @@ -1268,6 +1301,7 @@ dependencies = [ "crossbeam", "fxhash", "globset", + "insta", "lazy_static", "num", "num-derive", @@ -1278,7 +1312,6 @@ dependencies = [ "pretty_assertions", "regex", "serde", - "serde_json", "termcolor", "tree-sitter 0.19.3", "tree-sitter-ccomment", @@ -1455,6 +1488,12 @@ dependencies = [ "libc", ] +[[package]] +name = "similar" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "420acb44afdae038210c99e69aae24109f32f15500aa708e81d46c9f29d55fcf" + [[package]] name = "slab" version = "0.4.5" @@ -1503,6 +1542,16 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "terminal_size" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "time" version = "0.3.11" diff --git a/Cargo.toml b/Cargo.toml index a4d484055..fc2c98e8b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,8 +39,14 @@ tree-sitter-mozcpp = { path = "./tree-sitter-mozcpp", version = "=0.20.1" } tree-sitter-mozjs = { path = "./tree-sitter-mozjs", version = "=0.19.0" } [dev-dependencies] +insta = { version = "1.22.0", features = ["yaml"] } pretty_assertions = "^1.0" -serde_json = { version = "^1.0", features = ["arbitrary_precision"] } + +[profile.dev.package.insta] +opt-level = 3 + +[profile.dev.package.similar] +opt-level = 3 [workspace] members = ["rust-code-analysis-cli", "rust-code-analysis-web"] diff --git a/README.md b/README.md index 5836205c4..01d3e0112 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,15 @@ To verify whether all tests pass, run the `cargo test` command. cargo test --workspace --all-features --verbose ``` +### Updating insta tests +We use [insta](https://insta.rs), to update the snapshot tests you should install [cargo insta](https://crates.io/crates/cargo-insta) + +``` console +cargo insta test --review +``` + +Will run the tests, generate the new snapshot references and let you review them. + # Contributing If you want to contribute to the development of this software, have a look at the diff --git a/tests/repositories/rca-output b/tests/repositories/rca-output index 16033b9fd..9dd5fcd0d 160000 --- a/tests/repositories/rca-output +++ b/tests/repositories/rca-output @@ -1 +1 @@ -Subproject commit 16033b9fd6f4e0ce866df88d127e8c5180f0d0ed +Subproject commit 9dd5fcd0d4cd73c58d1a669351ecd1dbbca15848 diff --git a/tests/test.rs b/tests/test.rs index 529134405..01cd47d02 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -3,8 +3,6 @@ use globset::{Glob, GlobSetBuilder}; use once_cell::sync::Lazy; use rust_code_analysis::LANG; use rust_code_analysis::*; -use std::fs::*; -use std::io::BufReader; use std::path::Path; use std::path::PathBuf; use std::process; @@ -12,7 +10,6 @@ use std::process; #[derive(Debug)] struct Config { language: Option, - output_folder: PathBuf, } fn act_on_file(path: PathBuf, cfg: &Config) -> std::io::Result<()> { @@ -32,146 +29,20 @@ fn act_on_file(path: PathBuf, cfg: &Config) -> std::io::Result<()> { return Ok(()); }; - // Build json file path - let mut file_path = cfg.output_folder.join(path.strip_prefix("./").unwrap()); - file_path.set_extension("json"); + // Get FuncSpace struct + let funcspace_struct = get_function_spaces(&language, source, &path, None).unwrap(); - // Produce and compare metrics only if json file exists - if file_path.exists() { - // Get FuncSpace struct - let funcspace_struct = get_function_spaces(&language, source, &path, None).unwrap(); + let mut settings = insta::Settings::new(); - // Get Value struct from json file - let file = File::open(file_path)?; - let reader = BufReader::new(file); - let value_struct = serde_json::from_reader(reader)?; - - // Compare the 2 structs - compare_structs(&funcspace_struct, &value_struct); - } - - Ok(()) -} - -/// Compares a FuncSpace and a Value field by field -fn compare_structs(funcspace: &FuncSpace, value: &serde_json::Value) { - let fsname = funcspace - .name - .as_deref() - .unwrap_or_default() - .replace('\r', ""); - let name1 = Path::new(&fsname); - let name2 = Path::new(value["name"].as_str().unwrap_or_default()); - assert_eq!(name1, name2); - - let start_line1 = funcspace.start_line; - let start_line2 = value["start_line"].as_u64().unwrap() as usize; - assert_eq!(start_line1, start_line2); - - let end_line1 = funcspace.end_line; - let end_line2 = value["end_line"].as_u64().unwrap() as usize; - assert_eq!(end_line1, end_line2); - - let kind1 = &format!("{}", funcspace.kind); - let kind2 = value["kind"].as_str().unwrap_or_default(); - assert_eq!(kind1, kind2); - - let metrics1 = &funcspace.metrics; - let metrics2 = &value["metrics"]; - - let nargs1 = &metrics1.nargs; - let nargs2 = &metrics2["nargs"]; - compare_f64(nargs1.fn_args_sum(), &nargs2["total_functions"]); - compare_f64(nargs1.closure_args_sum(), &nargs2["total_closures"]); - compare_f64(nargs1.fn_args_average(), &nargs2["average_functions"]); - compare_f64(nargs1.closure_args_average(), &nargs2["average_closures"]); - compare_f64(nargs1.nargs_total(), &nargs2["total"]); - compare_f64(nargs1.nargs_average(), &nargs2["average"]); - compare_f64(nargs1.fn_args_min(), &nargs2["functions_min"]); - compare_f64(nargs1.fn_args_max(), &nargs2["functions_max"]); - compare_f64(nargs1.closure_args_min(), &nargs2["closures_min"]); - compare_f64(nargs1.closure_args_max(), &nargs2["closures_max"]); - - let nexits1 = &metrics1.nexits; - let nexits2 = &metrics2["nexits"]; - compare_f64(nexits1.exit(), &nexits2["sum"]); - compare_f64(nexits1.exit_average(), &nexits2["average"]); - compare_f64(nexits1.exit(), &nexits2["min"]); - compare_f64(nexits1.exit_average(), &nexits2["max"]); - - let cognitive1 = &metrics1.cognitive; - let cognitive2 = &metrics2["cognitive"]; - compare_f64(cognitive1.cognitive_sum(), &cognitive2["sum"]); - compare_f64(cognitive1.cognitive_average(), &cognitive2["average"]); - compare_f64(cognitive1.cognitive_min(), &cognitive2["min"]); - compare_f64(cognitive1.cognitive_max(), &cognitive2["max"]); - - let cyclomatic1 = &metrics1.cyclomatic; - let cyclomatic2 = &metrics2["cyclomatic"]; - compare_f64(cyclomatic1.cyclomatic_sum(), &cyclomatic2["sum"]); - compare_f64(cyclomatic1.cyclomatic_average(), &cyclomatic2["average"]); - compare_f64(cyclomatic1.cyclomatic_min(), &cyclomatic2["min"]); - compare_f64(cyclomatic1.cyclomatic_max(), &cyclomatic2["max"]); - - let halstead1 = &metrics1.halstead; - let halstead2 = &metrics2["halstead"]; - compare_f64(halstead1.u_operators(), &halstead2["n1"]); - compare_f64(halstead1.operators(), &halstead2["N1"]); - compare_f64(halstead1.u_operands(), &halstead2["n2"]); - compare_f64(halstead1.operands(), &halstead2["N2"]); - compare_f64(halstead1.length(), &halstead2["length"]); - compare_f64( - halstead1.estimated_program_length(), - &halstead2["estimated_program_length"], + settings.set_snapshot_path( + Path::new("./repositories/rca-output/snapshots").join(path.strip_prefix(*REPO).unwrap()), ); - compare_f64(halstead1.purity_ratio(), &halstead2["purity_ratio"]); - compare_f64(halstead1.vocabulary(), &halstead2["vocabulary"]); - compare_f64(halstead1.volume(), &halstead2["volume"]); - compare_f64(halstead1.difficulty(), &halstead2["difficulty"]); - compare_f64(halstead1.level(), &halstead2["level"]); - compare_f64(halstead1.effort(), &halstead2["effort"]); - compare_f64(halstead1.time(), &halstead2["time"]); - compare_f64(halstead1.bugs(), &halstead2["bugs"]); - - let loc1 = &metrics1.loc; - let loc2 = &metrics2["loc"]; - compare_f64(loc1.sloc(), &loc2["sloc"]); - compare_f64(loc1.ploc(), &loc2["ploc"]); - compare_f64(loc1.lloc(), &loc2["lloc"]); - compare_f64(loc1.cloc(), &loc2["cloc"]); - compare_f64(loc1.blank(), &loc2["blank"]); - - let nom1 = &metrics1.nom; - let nom2 = &metrics2["nom"]; - compare_f64(nom1.functions_sum(), &nom2["functions"]); - compare_f64(nom1.closures_sum(), &nom2["closures"]); - compare_f64(nom1.total(), &nom2["total"]); - compare_f64(nom1.functions_min(), &nom2["functions_min"]); - compare_f64(nom1.functions_max(), &nom2["functions_max"]); - compare_f64(nom1.closures_min(), &nom2["closures_min"]); - compare_f64(nom1.closures_max(), &nom2["closures_max"]); - - let mi1 = &metrics1.mi; - let mi2 = &metrics2["mi"]; - compare_f64(mi1.mi_original(), &mi2["mi_original"]); - compare_f64(mi1.mi_sei(), &mi2["mi_sei"]); - compare_f64(mi1.mi_visual_studio(), &mi2["mi_visual_studio"]); - - // Recursion - for (pos, s) in funcspace.spaces.iter().enumerate() { - compare_structs(s, &value["spaces"][pos]); - } -} + settings.set_snapshot_suffix(path.to_string_lossy()); + settings.bind(|| { + insta::assert_debug_snapshot!(funcspace_struct); + }); -/// Compares two f64 values truncated to 3 decimals -fn compare_f64(f1: f64, f2: &serde_json::Value) { - if f1.is_nan() || f1.is_infinite() { - assert!(f2.is_null()); - } else { - let ft1 = f64::trunc(f1 * 1000.0) / 1000.0; - let ft2 = f64::trunc(f2.as_f64().unwrap() * 1000.0) / 1000.0; - assert!(ft1.total_cmp(&ft2) == std::cmp::Ordering::Equal); - } + Ok(()) } static REPO: Lazy<&Path> = Lazy::new(|| Path::new("./tests/repositories")); @@ -180,10 +51,7 @@ static REPO: Lazy<&Path> = Lazy::new(|| Path::new("./tests/repositories")); fn compare_rca_output_with_files(repo_name: &str, include: &[&str]) { let num_jobs = 4; - let cfg = Config { - language: None, - output_folder: REPO.join("rca-output"), - }; + let cfg = Config { language: None }; let mut gsbi = GlobSetBuilder::new(); for file in include { From 4bd636fe9273e2ba94021f6db8bd7eb58634a30f Mon Sep 17 00:00:00 2001 From: Luca Barbato Date: Wed, 14 Dec 2022 14:09:58 +0100 Subject: [PATCH 4/6] Add a rust integration test using serde sources --- .gitmodules | 3 +++ tests/repositories/rca-output | 2 +- tests/repositories/serde | 1 + tests/test.rs | 5 +++++ 4 files changed, 10 insertions(+), 1 deletion(-) create mode 160000 tests/repositories/serde diff --git a/.gitmodules b/.gitmodules index eeb18ad01..d822240ab 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "tests/repositories/pdf.js"] path = tests/repositories/pdf.js url = https://github.com/mozilla/pdf.js +[submodule "tests/repositories/serde"] + path = tests/repositories/serde + url = https://github.com/serde-rs/serde diff --git a/tests/repositories/rca-output b/tests/repositories/rca-output index 9dd5fcd0d..dfc547a8b 160000 --- a/tests/repositories/rca-output +++ b/tests/repositories/rca-output @@ -1 +1 @@ -Subproject commit 9dd5fcd0d4cd73c58d1a669351ecd1dbbca15848 +Subproject commit dfc547a8b7e01f1d4872519db88314d4194404eb diff --git a/tests/repositories/serde b/tests/repositories/serde new file mode 160000 index 000000000..d493649f5 --- /dev/null +++ b/tests/repositories/serde @@ -0,0 +1 @@ +Subproject commit d493649f5299106b66dfb7a99d61b38d9599f972 diff --git a/tests/test.rs b/tests/test.rs index 01cd47d02..e958e741a 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -79,3 +79,8 @@ fn test_deepspeech() { fn test_pdfjs() { compare_rca_output_with_files("pdf.js", &["*.js"]); } + +#[test] +fn test_serde() { + compare_rca_output_with_files("serde", &["*.rs"]); +} From d98ff3a60c1142086506bb5ef6ec5d7b9e9c6d4b Mon Sep 17 00:00:00 2001 From: Luca Barbato Date: Thu, 15 Dec 2022 15:03:05 +0100 Subject: [PATCH 5/6] Change the snapshots layout And omit the FuncSpace::name --- tests/repositories/rca-output | 2 +- tests/test.rs | 20 +++++++++++++++++--- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/tests/repositories/rca-output b/tests/repositories/rca-output index dfc547a8b..8542185fa 160000 --- a/tests/repositories/rca-output +++ b/tests/repositories/rca-output @@ -1 +1 @@ -Subproject commit dfc547a8b7e01f1d4872519db88314d4194404eb +Subproject commit 8542185fa08a298d81dd0b302c7100ed270fd649 diff --git a/tests/test.rs b/tests/test.rs index e958e741a..a3106e206 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -35,11 +35,25 @@ fn act_on_file(path: PathBuf, cfg: &Config) -> std::io::Result<()> { let mut settings = insta::Settings::new(); settings.set_snapshot_path( - Path::new("./repositories/rca-output/snapshots").join(path.strip_prefix(*REPO).unwrap()), + Path::new("./repositories/rca-output/snapshots") + .join(path.strip_prefix(*REPO).unwrap()) + .parent() + .unwrap(), ); - settings.set_snapshot_suffix(path.to_string_lossy()); settings.bind(|| { - insta::assert_debug_snapshot!(funcspace_struct); + // Redact away the name since paths are different on windows. + let value = format!( + "{:#.3?}", + FuncSpace { + name: None, + ..funcspace_struct + } + ); + insta::assert_snapshot!( + path.file_name().unwrap().to_string_lossy().as_ref(), + value, + "funcspace_struct" + ); }); Ok(()) From cc1148ea8bd9277c30f0ee332a35194b77c594e6 Mon Sep 17 00:00:00 2001 From: Luca Barbato Date: Fri, 16 Dec 2022 16:10:48 +0100 Subject: [PATCH 6/6] Remove excess whitespace from the names --- src/spaces.rs | 4 +++- tests/repositories/rca-output | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/spaces.rs b/src/spaces.rs index ad3ea2c6b..385388b23 100644 --- a/src/spaces.rs +++ b/src/spaces.rs @@ -164,8 +164,10 @@ impl FuncSpace { node.object().end_position().row + 1, ), }; + Self { - name: T::get_func_space_name(node, code).map(|name| name.to_string()), + name: T::get_func_space_name(node, code) + .map(|name| name.split_whitespace().collect::>().join(" ")), spaces: Vec::new(), metrics: CodeMetrics::default(), kind, diff --git a/tests/repositories/rca-output b/tests/repositories/rca-output index 8542185fa..c649aed4d 160000 --- a/tests/repositories/rca-output +++ b/tests/repositories/rca-output @@ -1 +1 @@ -Subproject commit 8542185fa08a298d81dd0b302c7100ed270fd649 +Subproject commit c649aed4d2ff64a8c891acb8b4b53b961db58db5