From 2d6c95e7d737de7be9d9c953c742c311352de2f5 Mon Sep 17 00:00:00 2001 From: GrosQuildu Date: Tue, 9 Jan 2024 12:44:53 +0100 Subject: [PATCH 01/30] init rust chapter --- content/docs/languages/_index.md | 15 + content/docs/languages/rust/00-unit-tests.md | 261 ++++++++++++++++++ .../docs/languages/rust/10-static-analysis.md | 54 ++++ .../languages/rust/20-dynamic-analysis.md | 44 +++ content/docs/languages/rust/_index.md | 16 ++ 5 files changed, 390 insertions(+) create mode 100644 content/docs/languages/_index.md create mode 100644 content/docs/languages/rust/00-unit-tests.md create mode 100644 content/docs/languages/rust/10-static-analysis.md create mode 100644 content/docs/languages/rust/20-dynamic-analysis.md create mode 100644 content/docs/languages/rust/_index.md diff --git a/content/docs/languages/_index.md b/content/docs/languages/_index.md new file mode 100644 index 00000000..871af99a --- /dev/null +++ b/content/docs/languages/_index.md @@ -0,0 +1,15 @@ +--- +weight: 2 +bookFlatSection: true +title: "Languages" +--- + +# Languages + +This section presents language-specific tools. For each programming language we cover topics such as: + +- Advanced unit testing +- Static analysis +- Dynamic analysis + +{{< section >}} diff --git a/content/docs/languages/rust/00-unit-tests.md b/content/docs/languages/rust/00-unit-tests.md new file mode 100644 index 00000000..306836ac --- /dev/null +++ b/content/docs/languages/rust/00-unit-tests.md @@ -0,0 +1,261 @@ +--- +title: "Unit tests" +slug: unit-tests +summary: "This section describes tricks for Rust unit testing" +weight: 1 +--- + +# Unit tests + +This is the most basic type of testing that every project should have. Unit tests are easy to execute, low-effort to implement, and catch a lot of simple mistakes. + + +## Installation and first steps + +The standard and ultimate tool for executing unit and integration tests for Rust codebases is the `cargo test`. The basic setup and usage of `cargo test` is well-known, so we will skip the introduction. + +```rust +#[cfg(test)] +mod tests { + #[test] + fn true_dilemma() { + assert_ne!(true, false); + } +} +``` + +Once you have your tests written and all of them passes, lets improve. + + +## Advanced usage + +### Randomization + +First lets make sure that tests do not depend on a global state and that there are no unwanted dependencies between them. + +For that you can run tests multiple times, taking adventage of the enabled-by-default parallel execution. However, this approach is not optimal. That is because tests are executed in basically alphabetical order, even when multi-threaded. + +Better to run tests in a random order without parallel execution. +```sh +cargo test -- -Z unstable-options --test-threads 1 --shuffle +``` + +Execute command above multiple times. If any run reported a failed test use the displayed "shuffle seed" to reliably repeat the error: +```sh +cargo test -- -Z unstable-options --test-threads 1 --shuffle-seed 7331 +``` + +{{< details "Example to try" >}} + +Tests below fail randomly when run with `cargo test`. To get reproducible failure run: +```sh +cargo test -- -Z unstable-options --test-threads 1 --shuffle-seed 1337 +``` + +```rust +fn main() { println!("Hello, world!"); } + +static mut glob_var: i32 = 2; + +unsafe fn global_var_set(arg: i32) { + glob_var = arg; +} + +#[cfg(test)] +mod tests { + use crate::{glob_var, global_var_set}; + + #[test] + fn a_true_dilemma() { + unsafe { assert_eq!(glob_var, 2); } + unsafe { global_var_set(5); } + unsafe { assert_eq!(glob_var, 5); } + assert_ne!(true, false); + } + + #[test] + fn not_true_dilemma() { + unsafe { assert_eq!(glob_var, 2); } + assert_ne!(true, false); + } +} +``` +{{< /details >}} + + +When you are happy with the results, randomize features using [`cargo hack`](https://github.com/taiki-e/cargo-hack). Start with testing your code against all the features taken separately, then combine multiple features in one run: + +```sh +cargo +stable install cargo-hack --locked +cargo hack test -Z avoid-dev-deps --each-feature +cargo hack test -Z avoid-dev-deps --feature-powerset --depth 2 +``` + +{{< details "Example to try" >}} + +The test below passes when run with `cargo test`. Also passes with `cargo hack test --each-feature`. To find the code path that makes the test fail run: +```sh +cargo hack test --feature-powerset --depth 2 +``` + +```rust +fn main() { println!("Hello, world!"); } + +fn feauture_one() -> i32 { + #[cfg(all(feature = "fone", feature = "fthree", not(feature = "ftwo")))] + { + return 3; + } + #[cfg(feature = "fone")] { + return 1; + } + #[cfg(feature = "ftwo")] { + return 2; + } + return 0; +} + + +#[cfg(test)] +mod tests { + use crate::{feauture_one}; + + #[test] + fn feature_test1() { + let z = feauture_one(); + assert!(z < 3); + } +} +``` +{{< /details >}} + +### Integer overflows + +While some integer overflows are detected with [the `overflow-checks` flag](https://doc.rust-lang.org/rustc/codegen-options/index.html#overflow-checks), overflows in explicit casts are not. To make our tests detect overflows in `expr as T` expressions we must use [`cast_checks`](https://github.com/trailofbits/cast_checks). + +Add relevant dependency to `Cargo.toml`: +```toml +[dependencies] +cast_checks = "0.1.4" +``` + +Now mark functions where you expect overflows with `#[cast_checks::enable]` and run tests as always. + +Alternatively, enable `inner atributes` feature with `#![feature(custom_inner_attributes, proc_macro_hygiene)]` and put `#![cast_checks::enable]` attribute in relevant modules. When doing so add `RUSTFLAGS='--cfg procmacro2_semver_exempt'` to cargo commands. + +{{< details "Example to try" >}} + +The `int_overflow_simple` test always passes, as arithmetic overflows are detected with standard `overflow-checks`. However, to detect overflow in the `int_overflow_in_cast` we must use `cast_checks`. + +```rust +#![feature(custom_inner_attributes, proc_macro_hygiene)] + +fn main() { println!("Hello, world!"); } + +mod lib { + #![cast_checks::enable] + + pub(crate) fn do_overflow(a: i32) -> i32 { + return a * 8; + } + + pub(crate) fn as_u16(z: i32) -> u16 { + z as u16 + } +} + +#[cfg(test)] +mod tests { + use crate::{lib::as_u16, lib::do_overflow}; + + #[should_panic] + #[test] + fn int_overflow_simple() { + let y_str = "2147483647"; + let y = y_str.parse::().unwrap(); + let x = do_overflow(y); + } + + #[should_panic] + #[test] + fn int_overflow_in_cast() { + let y_str = "2147483647"; + let y = y_str.parse::().unwrap(); + println!("{}", y); + let a = as_u16(y); + } +} +``` +{{< /details >}} + +### Sanitizers + +While Rust is memory-safe, one may open a gate to the `unsafe` world and introduce all the well known vulnerabilities like use-after-free or reading of uninitialized memory. Moreover, Rust compiler does not prevent memory leaks and data races (TODO). + +To find deep bugs we can enhance our tests with [various sanitizers](https://doc.rust-lang.org/beta/unstable-book/compiler-flags/sanitizer.html): +* AddressSanitizer +* LeakSanitizer +* MemorySanitizer +* ThreadSanitizer + +To enable them: +```sh +RUSTFLAGS='-Z sanitizer=address' cargo test +RUSTFLAGS='-Z sanitizer=leak' cargo test --target x86_64-unknown-linux-gnu +RUSTFLAGS='-Z sanitizer=memory' cargo test --target aarch64-unknown-linux-gnu +RUSTFLAGS='-Z sanitizer=thread' cargo test +``` + +Not all targets are created equal, so check which are supported by the given sanitizer. + +{{< details "Example to try" >}} + +The test below passes. Only AddressSanitizer can help us. +```sh +RUSTFLAGS='-Z sanitizer=address' cargo test +``` + +```rust +fn main() { println!("Hello, world!"); } + +#[cfg(test)] +mod tests { + #[test] + fn uaf() { + let a = vec![7, 3, 3, 1]; + let b = a.as_ptr(); + drop(a); + let z = unsafe { *b }; + } +} +``` +{{< /details >}} + + +### Coverage + +It is critically important to know how much coverage your tests have. To gather coverage information use one of: + +* [`cargo-llvm-cov`](https://github.com/taiki-e/cargo-llvm-cov) +* [`cargo-tarpaulin`](https://github.com/xd009642/tarpaulin) +* [`grcov`](https://github.com/mozilla/grcov) + + +### Validation of tests + +Who tests tests? What if your critical test has a bug that makes it to pass incorrectly? + +To find issues in your tests [use `necessist`](https://github.com/trailofbits/necessist). + +```sh +cargo install necessist +necessist . +``` + +## CI/CD integration + +Describe how to setup and use `` in CI/CD + +## Resources + +* ["The Rust Programming Language", chapter 11. Testing](https://web.mit.edu/rust-lang_v1.25/arch/amd64_ubuntu1404/share/doc/rust/html/book/second-edition/ch11-00-testing.html) - the basics of unit and integration testing in Rust diff --git a/content/docs/languages/rust/10-static-analysis.md b/content/docs/languages/rust/10-static-analysis.md new file mode 100644 index 00000000..8066d659 --- /dev/null +++ b/content/docs/languages/rust/10-static-analysis.md @@ -0,0 +1,54 @@ +--- +title: "Static analysis" +slug: rust-static-analysis +summary: "This section provides overview of static analysis tooling for Rust" +weight: 10 +--- + +# Static Analysis + +Analyze source code without executing it. + +## Clippy + +Clippy is the basic linter. Just use it. + +```sh +cargo clippy -- -W clippy::pedantic +``` + +## Dylint + +To write your own lints and to take adventage of not-standarized lints of others people [use `dylint`](https://github.com/trailofbits/dylint/). + +### Quick start + +Add the following to `Cargo.toml`: +```toml +[workspace.metadata.dylint] +libraries = [ + { git = "https://github.com/trailofbits/dylint", pattern = "examples/general/*" }, + { git = "https://github.com/trailofbits/dylint", pattern = "examples/supplementary/*" }, +] +``` + +And run: +```sh +cargo install cargo-dylint dylint-link +cargo dylint --all --workspace +``` + +### Writing your own lints + +TODO + +## MIRI +* detects certain classes of undefined behavior and memory leaks + +## Prusti +* based on [Viper](https://www.pm.inf.ethz.ch/research/viper.html) +* detects panics and integer overflows + +## Semgrep + +Check the [semgrep page](/docs/static-analysis/semgrep/). diff --git a/content/docs/languages/rust/20-dynamic-analysis.md b/content/docs/languages/rust/20-dynamic-analysis.md new file mode 100644 index 00000000..9dbe977d --- /dev/null +++ b/content/docs/languages/rust/20-dynamic-analysis.md @@ -0,0 +1,44 @@ +--- +title: "Property testing" +slug: rust-property-testing +summary: "This section describes nuances of Rust property testing" +weight: 20 +--- + +# Basic property testing tools + +- Use [proptest](https://docs.rs/proptest/latest/proptest/) + * inspired by QuickCheck + * write "randomized" unit tests +- Use [Kani](https://github.com/model-checking/kani) + * frontend for [cbmc](https://www.cprover.org/cbmc/) + * write "randomized" unit tests +- Use [Creusot](https://github.com/xldenis/creusot) + * based on [Why3](https://why3.lri.fr/) + * annotate functions with "contract expressions" (requires, ensures, invariant and variant) + +# Advanced property testing tools + +- Use [Crux](https://github.com/GaloisInc/crucible/blob/master/crux-mir/README.md) + * symbolic analysis + * write "symbolized" unit tests +- Use [Flux](https://github.com/flux-rs/flux) + * refinement type checker + * annotate functions with complex conditions +- Use [MIRAI](https://github.com/facebookexperimental/MIRAI) + * implements abstract interpretation, taint analysis, and constant time analysis + * experimantal stuff + * requires heavy dev work to implement something usefull +- Use [Stateright](https://www.stateright.rs/title-page.html) + * TLA+ for rust + * lets you model state machine of a system and test properties on it + * heavy stuff + +# Concurrency testing tools + +- Run [`Shuttle`](https://github.com/awslabs/shuttle) + * randomized and lightweight testing + +- Run [`Loom`](https://docs.rs/loom/latest/loom/) + * sound but slow testing + diff --git a/content/docs/languages/rust/_index.md b/content/docs/languages/rust/_index.md new file mode 100644 index 00000000..b0c9da0c --- /dev/null +++ b/content/docs/languages/rust/_index.md @@ -0,0 +1,16 @@ +--- +title: "Rust" +weight: 2 +summary: "Rust is a multi-paradigm, general-purpose, memory-safe programming language." +draft: true +# bookFlatSection: false +# bookToc: true +# bookHidden: false +bookCollapseSection: true +# bookComments: false +# bookSearchExclude: false +--- + +## Rust + +TODO \ No newline at end of file From 2d2ec31001cd3f0961fcd09fa6da84726fcc2302 Mon Sep 17 00:00:00 2001 From: GrosQuildu Date: Tue, 9 Jan 2024 18:37:13 +0100 Subject: [PATCH 02/30] rust chapter - necessist --- content/docs/languages/_index.md | 1 + content/docs/languages/rust/00-unit-tests.md | 53 ++++++++++++++++++-- content/docs/languages/rust/_index.md | 2 +- 3 files changed, 52 insertions(+), 4 deletions(-) diff --git a/content/docs/languages/_index.md b/content/docs/languages/_index.md index 871af99a..fbd86362 100644 --- a/content/docs/languages/_index.md +++ b/content/docs/languages/_index.md @@ -12,4 +12,5 @@ This section presents language-specific tools. For each programming language we - Static analysis - Dynamic analysis + {{< section >}} diff --git a/content/docs/languages/rust/00-unit-tests.md b/content/docs/languages/rust/00-unit-tests.md index 306836ac..8b31e359 100644 --- a/content/docs/languages/rust/00-unit-tests.md +++ b/content/docs/languages/rust/00-unit-tests.md @@ -190,7 +190,7 @@ mod tests { ### Sanitizers -While Rust is memory-safe, one may open a gate to the `unsafe` world and introduce all the well known vulnerabilities like use-after-free or reading of uninitialized memory. Moreover, Rust compiler does not prevent memory leaks and data races (TODO). +While Rust is memory-safe, one may open a gate to the `unsafe` world and introduce all the well known vulnerabilities like use-after-free or reading of uninitialized memory. Moreover, Rust compiler does not prevent memory leaks and data races. To find deep bugs we can enhance our tests with [various sanitizers](https://doc.rust-lang.org/beta/unstable-book/compiler-flags/sanitizer.html): * AddressSanitizer @@ -210,7 +210,7 @@ Not all targets are created equal, so check which are supported by the given san {{< details "Example to try" >}} -The test below passes. Only AddressSanitizer can help us. +The test below passes. But the AddressSanitizer can help us find the bug. ```sh RUSTFLAGS='-Z sanitizer=address' cargo test ``` @@ -249,9 +249,55 @@ To find issues in your tests [use `necessist`](https://github.com/trailofbits/ne ```sh cargo install necessist -necessist . +necessist ``` +Necessist works by mutating tests - removing certain instructions from them - and executing them. +A mutated test that passed with an instruction removed is shown as: +``` +filename:line-line `removed code` passed +``` +It requires manual investigation if a finding really revealed a bug in a testcase (or in the code being tested). + +The tool produces a `necessist.db` file that can be used to resume an interrupted run. + +{{< details "Example to try" >}} + +Necessist should report that the `parser_detects_errors` test passes even if one line is removed from it. +It indicates that either magic number in the example or in the `validate_data` is incorrect, preventing the "real" +bug from being tested properly. +```rust +fn validate_data(data: &Data) -> Result<(), ()> { + if !data.magic.eq(&[0x13, 0x37]) { return Err(()) } + if data.len as usize != data.content.len() { return Err(()) } + return Ok(()); +} + +struct Data { + magic: [u8; 2], + len: u8, + content: String +} + +#[cfg(test)] +mod tests { + use crate::{Data, validate_data}; + + #[test] + fn parser_detects_errors() { + let mut blob = Data{ + magic: [0x73, 0x31], + len: 2, + content: "AB".parse().unwrap(), + }; + blob.content = blob.content + "Y"; + let result = validate_data(&blob); + assert!(result.is_err()); + } +} +``` +{{< /details >}} + ## CI/CD integration Describe how to setup and use `` in CI/CD @@ -259,3 +305,4 @@ Describe how to setup and use `` in CI/CD ## Resources * ["The Rust Programming Language", chapter 11. Testing](https://web.mit.edu/rust-lang_v1.25/arch/amd64_ubuntu1404/share/doc/rust/html/book/second-edition/ch11-00-testing.html) - the basics of unit and integration testing in Rust +* [Ed Page's "Iterating on Testing in Rust"](https://epage.github.io/blog/2023/06/iterating-on-test/) - potential issues with `cargo test` diff --git a/content/docs/languages/rust/_index.md b/content/docs/languages/rust/_index.md index b0c9da0c..b272186c 100644 --- a/content/docs/languages/rust/_index.md +++ b/content/docs/languages/rust/_index.md @@ -13,4 +13,4 @@ bookCollapseSection: true ## Rust -TODO \ No newline at end of file +Rust is a multi-paradigm, general-purpose, memory-safe programming language. \ No newline at end of file From 0a66285e6c21a61f227901ffda208c0e42b0fba8 Mon Sep 17 00:00:00 2001 From: GrosQuildu Date: Wed, 10 Jan 2024 16:23:41 +0100 Subject: [PATCH 03/30] rust chapter - coverage --- content/docs/languages/rust/00-unit-tests.md | 66 +++++++++++++++++++- 1 file changed, 63 insertions(+), 3 deletions(-) diff --git a/content/docs/languages/rust/00-unit-tests.md b/content/docs/languages/rust/00-unit-tests.md index 8b31e359..b96c3f1e 100644 --- a/content/docs/languages/rust/00-unit-tests.md +++ b/content/docs/languages/rust/00-unit-tests.md @@ -24,6 +24,8 @@ mod tests { } ``` +Please note that [`docs tests` don't work in binary targets](https://github.com/rust-lang/rust/issues/50784). + Once you have your tests written and all of them passes, lets improve. @@ -236,9 +238,67 @@ mod tests { It is critically important to know how much coverage your tests have. To gather coverage information use one of: -* [`cargo-llvm-cov`](https://github.com/taiki-e/cargo-llvm-cov) -* [`cargo-tarpaulin`](https://github.com/xd009642/tarpaulin) -* [`grcov`](https://github.com/mozilla/grcov) +| Feature | [`cargo-llvm-cov`](https://github.com/taiki-e/cargo-llvm-cov) | [`cargo-tarpaulin`](https://github.com/xd009642/tarpaulin) | [`grcov`](https://github.com/mozilla/grcov) +| -----------| ----------- | ----------- | ----------- | +| Backends | LLVM | LLVM, ptrace | ? | +| Output format | console, html | html | ? | +| Coverage | console, html | html | ? | +| Merge | console, html | html | ? | +| Exclude files | console, html | html | ? | +| Exclude functions | console, html | html | ? | +| Exclude tests' coverage | console, html | html | ? | +| Coverage for C/C++ | console, html | html | ? | + +* +``` +cargo llvm-cov # console +cargo llvm-cov --open # html + +backend: llvm + +# coverage: function, lines, region; no branch cov + +# merge +cargo llvm-cov clean --workspace # remove artifacts that may affect the coverage results +cargo llvm-cov --no-report --features a +cargo llvm-cov --no-report --features b +cargo llvm-cov report --lcov # generate report without tests + +# show change in coverge - no + +# support for C/C++ code - yes +# exclude file - --ignore-filename-regex +# exclude function - (unstable) #[cfg_attr(coverage_nightly, coverage(off))] +# exclude test code - https://github.com/taiki-e/coverage-helper/tree/v0.2.0 +``` + +* +``` +cargo tarpaulin # console +cargo tarpaulin --out html # html + +backend: llvm, ptrace + +# cove: lines; no branch, function, regions cov + +--no-fail-fast + --ignore-panics should_panic + +# show change in coverge - yes + +# support for C/C++ code - --follow-exec ? +# exclude file - #[cfg(not(tarpaulin_include))] +# exclude test code - #[cfg_attr(tarpaulin, ignore)] +# exclude test code - --ignore-tests +``` + +* +``` +html - yes +console - no + +# cove: lines, function, branches +``` ### Validation of tests From 104f5b027aa6efe4583cbeab8d7c9fb1b4bdbadc Mon Sep 17 00:00:00 2001 From: GrosQuildu Date: Wed, 10 Jan 2024 20:02:44 +0100 Subject: [PATCH 04/30] rust chapter - coverage 2 --- content/docs/languages/_index.md | 1 - content/docs/languages/rust/00-unit-tests.md | 101 ++++++------------ .../docs/languages/rust/10-static-analysis.md | 4 + .../languages/rust/20-dynamic-analysis.md | 37 ++++--- content/docs/languages/rust/_index.md | 2 +- 5 files changed, 56 insertions(+), 89 deletions(-) diff --git a/content/docs/languages/_index.md b/content/docs/languages/_index.md index fbd86362..871af99a 100644 --- a/content/docs/languages/_index.md +++ b/content/docs/languages/_index.md @@ -12,5 +12,4 @@ This section presents language-specific tools. For each programming language we - Static analysis - Dynamic analysis - {{< section >}} diff --git a/content/docs/languages/rust/00-unit-tests.md b/content/docs/languages/rust/00-unit-tests.md index b96c3f1e..f336ccf1 100644 --- a/content/docs/languages/rust/00-unit-tests.md +++ b/content/docs/languages/rust/00-unit-tests.md @@ -9,7 +9,6 @@ weight: 1 This is the most basic type of testing that every project should have. Unit tests are easy to execute, low-effort to implement, and catch a lot of simple mistakes. - ## Installation and first steps The standard and ultimate tool for executing unit and integration tests for Rust codebases is the `cargo test`. The basic setup and usage of `cargo test` is well-known, so we will skip the introduction. @@ -28,21 +27,22 @@ Please note that [`docs tests` don't work in binary targets](https://github.com/ Once you have your tests written and all of them passes, lets improve. - ## Advanced usage ### Randomization First lets make sure that tests do not depend on a global state and that there are no unwanted dependencies between them. -For that you can run tests multiple times, taking adventage of the enabled-by-default parallel execution. However, this approach is not optimal. That is because tests are executed in basically alphabetical order, even when multi-threaded. +For that you can run tests multiple times, taking advantage of the enabled-by-default parallel execution. However, this approach is not optimal. That is because tests are executed in basically alphabetical order, even when multi-threaded. Better to run tests in a random order without parallel execution. + ```sh cargo test -- -Z unstable-options --test-threads 1 --shuffle ``` -Execute command above multiple times. If any run reported a failed test use the displayed "shuffle seed" to reliably repeat the error: +Execute command above multiple times. If any run reported a failed test use the displayed "shuffle seed" to reliably repeat the error: + ```sh cargo test -- -Z unstable-options --test-threads 1 --shuffle-seed 7331 ``` @@ -50,6 +50,7 @@ cargo test -- -Z unstable-options --test-threads 1 --shuffle-seed 7331 {{< details "Example to try" >}} Tests below fail randomly when run with `cargo test`. To get reproducible failure run: + ```sh cargo test -- -Z unstable-options --test-threads 1 --shuffle-seed 1337 ``` @@ -82,8 +83,8 @@ mod tests { } } ``` -{{< /details >}} +{{< /details >}} When you are happy with the results, randomize features using [`cargo hack`](https://github.com/taiki-e/cargo-hack). Start with testing your code against all the features taken separately, then combine multiple features in one run: @@ -96,6 +97,7 @@ cargo hack test -Z avoid-dev-deps --feature-powerset --depth 2 {{< details "Example to try" >}} The test below passes when run with `cargo test`. Also passes with `cargo hack test --each-feature`. To find the code path that makes the test fail run: + ```sh cargo hack test --feature-powerset --depth 2 ``` @@ -129,6 +131,7 @@ mod tests { } } ``` + {{< /details >}} ### Integer overflows @@ -136,6 +139,7 @@ mod tests { While some integer overflows are detected with [the `overflow-checks` flag](https://doc.rust-lang.org/rustc/codegen-options/index.html#overflow-checks), overflows in explicit casts are not. To make our tests detect overflows in `expr as T` expressions we must use [`cast_checks`](https://github.com/trailofbits/cast_checks). Add relevant dependency to `Cargo.toml`: + ```toml [dependencies] cast_checks = "0.1.4" @@ -188,19 +192,22 @@ mod tests { } } ``` + {{< /details >}} ### Sanitizers -While Rust is memory-safe, one may open a gate to the `unsafe` world and introduce all the well known vulnerabilities like use-after-free or reading of uninitialized memory. Moreover, Rust compiler does not prevent memory leaks and data races. +While Rust is memory-safe, one may open a gate to the `unsafe` world and introduce all the well known vulnerabilities like use-after-free or reading of uninitialized memory. Moreover, Rust compiler does not prevent memory leaks and data races. To find deep bugs we can enhance our tests with [various sanitizers](https://doc.rust-lang.org/beta/unstable-book/compiler-flags/sanitizer.html): + * AddressSanitizer * LeakSanitizer * MemorySanitizer * ThreadSanitizer To enable them: + ```sh RUSTFLAGS='-Z sanitizer=address' cargo test RUSTFLAGS='-Z sanitizer=leak' cargo test --target x86_64-unknown-linux-gnu @@ -213,6 +220,7 @@ Not all targets are created equal, so check which are supported by the given san {{< details "Example to try" >}} The test below passes. But the AddressSanitizer can help us find the bug. + ```sh RUSTFLAGS='-Z sanitizer=address' cargo test ``` @@ -231,75 +239,32 @@ mod tests { } } ``` -{{< /details >}} +{{< /details >}} ### Coverage It is critically important to know how much coverage your tests have. To gather coverage information use one of: | Feature | [`cargo-llvm-cov`](https://github.com/taiki-e/cargo-llvm-cov) | [`cargo-tarpaulin`](https://github.com/xd009642/tarpaulin) | [`grcov`](https://github.com/mozilla/grcov) -| -----------| ----------- | ----------- | ----------- | -| Backends | LLVM | LLVM, ptrace | ? | -| Output format | console, html | html | ? | -| Coverage | console, html | html | ? | -| Merge | console, html | html | ? | -| Exclude files | console, html | html | ? | -| Exclude functions | console, html | html | ? | -| Exclude tests' coverage | console, html | html | ? | -| Coverage for C/C++ | console, html | html | ? | - -* -``` -cargo llvm-cov # console -cargo llvm-cov --open # html - -backend: llvm - -# coverage: function, lines, region; no branch cov +| ----------- | ----------- | ----------- | ----------- | +| Backends | LLVM (profraw) | LLVM (profraw), ptrace | LLVM (profraw), gcov-based (gcno, gcda) | +| Coverage | Lines, functions, regions | Lines | Lines, functions, branches | +| Output format | Text, lcov, JSON, HTML, cobertura, codecov | Text, lcov, JSON, HTML, xml | Lcov, JSON, HTML, cobertura, coveralls+, markdown, ade | +| Merge data from multiple runs | [Yes](https://github.com/taiki-e/cargo-llvm-cov?tab=readme-ov-file#merge-coverages-generated-under-different-test-conditions) | [Yes/No](https://github.com/xd009642/tarpaulin?tab=readme-ov-file#command-line) (only shows delta) | No | +| Exclude files | [`--ignore-filename-regex`](https://github.com/taiki-e/cargo-llvm-cov?tab=readme-ov-file#exclude-file-from-coverage) | `--exclude-files` | `--ignore` | +| Exclude functions | [With attributes](https://github.com/taiki-e/cargo-llvm-cov?tab=readme-ov-file#exclude-function-from-coverage) | [With attributes](https://github.com/xd009642/tarpaulin?tab=readme-ov-file#ignoring-code-in-files) | With in-code markers & regexes | +| Exclude tests' coverage | [With external module](https://github.com/taiki-e/coverage-helper/tree/v0.2.0) | `--ignore-tests` | No | +| Coverage for C/C++ | [`--include-ffi`](https://github.com/taiki-e/cargo-llvm-cov?tab=readme-ov-file#get-coverage-of-cc-code-linked-to-rust-librarybinary) | `--follow-exec` | ? | -# merge -cargo llvm-cov clean --workspace # remove artifacts that may affect the coverage results -cargo llvm-cov --no-report --features a -cargo llvm-cov --no-report --features b -cargo llvm-cov report --lcov # generate report without tests - -# show change in coverge - no - -# support for C/C++ code - yes -# exclude file - --ignore-filename-regex -# exclude function - (unstable) #[cfg_attr(coverage_nightly, coverage(off))] -# exclude test code - https://github.com/taiki-e/coverage-helper/tree/v0.2.0 -``` - -* -``` -cargo tarpaulin # console -cargo tarpaulin --out html # html - -backend: llvm, ptrace - -# cove: lines; no branch, function, regions cov - ---no-fail-fast - --ignore-panics should_panic - -# show change in coverge - yes - -# support for C/C++ code - --follow-exec ? -# exclude file - #[cfg(not(tarpaulin_include))] -# exclude test code - #[cfg_attr(tarpaulin, ignore)] -# exclude test code - --ignore-tests ``` +TODO +fail fast? --no-fail-fast +panics --ignore-panics should_panic -* +gcno - compile time, gcna - runtime +profraw - ? ``` -html - yes -console - no - -# cove: lines, function, branches -``` - ### Validation of tests @@ -314,9 +279,11 @@ necessist Necessist works by mutating tests - removing certain instructions from them - and executing them. A mutated test that passed with an instruction removed is shown as: + ``` filename:line-line `removed code` passed ``` + It requires manual investigation if a finding really revealed a bug in a testcase (or in the code being tested). The tool produces a `necessist.db` file that can be used to resume an interrupted run. @@ -326,6 +293,7 @@ The tool produces a `necessist.db` file that can be used to resume an interrupte Necessist should report that the `parser_detects_errors` test passes even if one line is removed from it. It indicates that either magic number in the example or in the `validate_data` is incorrect, preventing the "real" bug from being tested properly. + ```rust fn validate_data(data: &Data) -> Result<(), ()> { if !data.magic.eq(&[0x13, 0x37]) { return Err(()) } @@ -356,11 +324,8 @@ mod tests { } } ``` -{{< /details >}} -## CI/CD integration - -Describe how to setup and use `` in CI/CD +{{< /details >}} ## Resources diff --git a/content/docs/languages/rust/10-static-analysis.md b/content/docs/languages/rust/10-static-analysis.md index 8066d659..abe1691f 100644 --- a/content/docs/languages/rust/10-static-analysis.md +++ b/content/docs/languages/rust/10-static-analysis.md @@ -24,6 +24,7 @@ To write your own lints and to take adventage of not-standarized lints of others ### Quick start Add the following to `Cargo.toml`: + ```toml [workspace.metadata.dylint] libraries = [ @@ -33,6 +34,7 @@ libraries = [ ``` And run: + ```sh cargo install cargo-dylint dylint-link cargo dylint --all --workspace @@ -43,9 +45,11 @@ cargo dylint --all --workspace TODO ## MIRI + * detects certain classes of undefined behavior and memory leaks ## Prusti + * based on [Viper](https://www.pm.inf.ethz.ch/research/viper.html) * detects panics and integer overflows diff --git a/content/docs/languages/rust/20-dynamic-analysis.md b/content/docs/languages/rust/20-dynamic-analysis.md index 9dbe977d..ac415813 100644 --- a/content/docs/languages/rust/20-dynamic-analysis.md +++ b/content/docs/languages/rust/20-dynamic-analysis.md @@ -8,37 +8,36 @@ weight: 20 # Basic property testing tools - Use [proptest](https://docs.rs/proptest/latest/proptest/) - * inspired by QuickCheck - * write "randomized" unit tests + - inspired by QuickCheck + - write "randomized" unit tests - Use [Kani](https://github.com/model-checking/kani) - * frontend for [cbmc](https://www.cprover.org/cbmc/) - * write "randomized" unit tests + - frontend for [cbmc](https://www.cprover.org/cbmc/) + - write "randomized" unit tests - Use [Creusot](https://github.com/xldenis/creusot) - * based on [Why3](https://why3.lri.fr/) - * annotate functions with "contract expressions" (requires, ensures, invariant and variant) + - based on [Why3](https://why3.lri.fr/) + - annotate functions with "contract expressions" (requires, ensures, invariant and variant) # Advanced property testing tools - Use [Crux](https://github.com/GaloisInc/crucible/blob/master/crux-mir/README.md) - * symbolic analysis - * write "symbolized" unit tests + - symbolic analysis + - write "symbolized" unit tests - Use [Flux](https://github.com/flux-rs/flux) - * refinement type checker - * annotate functions with complex conditions + - refinement type checker + - annotate functions with complex conditions - Use [MIRAI](https://github.com/facebookexperimental/MIRAI) - * implements abstract interpretation, taint analysis, and constant time analysis - * experimantal stuff - * requires heavy dev work to implement something usefull + - implements abstract interpretation, taint analysis, and constant time analysis + - experimantal stuff + - requires heavy dev work to implement something usefull - Use [Stateright](https://www.stateright.rs/title-page.html) - * TLA+ for rust - * lets you model state machine of a system and test properties on it - * heavy stuff + - TLA+ for rust + - lets you model state machine of a system and test properties on it + - heavy stuff # Concurrency testing tools - Run [`Shuttle`](https://github.com/awslabs/shuttle) - * randomized and lightweight testing + - randomized and lightweight testing - Run [`Loom`](https://docs.rs/loom/latest/loom/) - * sound but slow testing - + - sound but slow testing diff --git a/content/docs/languages/rust/_index.md b/content/docs/languages/rust/_index.md index b272186c..53702f90 100644 --- a/content/docs/languages/rust/_index.md +++ b/content/docs/languages/rust/_index.md @@ -13,4 +13,4 @@ bookCollapseSection: true ## Rust -Rust is a multi-paradigm, general-purpose, memory-safe programming language. \ No newline at end of file +Rust is a multi-paradigm, general-purpose, memory-safe programming language. From 04dc4b7374a0aa6bc9c507f7b4a3488f0a761548 Mon Sep 17 00:00:00 2001 From: GrosQuildu Date: Thu, 11 Jan 2024 17:54:54 +0100 Subject: [PATCH 05/30] rust chapter - coverage files --- samples/rust_coverage/Cargo.toml | 4 + samples/rust_coverage/Dockerfile | 20 +++++ samples/rust_coverage/README.md | 19 +++++ samples/rust_coverage/get_coverage.sh | 47 +++++++++++ samples/rust_coverage/src/main.rs | 107 ++++++++++++++++++++++++++ samples/rust_coverage/src/second.rs | 7 ++ 6 files changed, 204 insertions(+) create mode 100644 samples/rust_coverage/Cargo.toml create mode 100644 samples/rust_coverage/Dockerfile create mode 100644 samples/rust_coverage/README.md create mode 100644 samples/rust_coverage/get_coverage.sh create mode 100644 samples/rust_coverage/src/main.rs create mode 100644 samples/rust_coverage/src/second.rs diff --git a/samples/rust_coverage/Cargo.toml b/samples/rust_coverage/Cargo.toml new file mode 100644 index 00000000..ef8459ea --- /dev/null +++ b/samples/rust_coverage/Cargo.toml @@ -0,0 +1,4 @@ +[package] +name = "tmp" +version = "0.1.0" +edition = "2021" diff --git a/samples/rust_coverage/Dockerfile b/samples/rust_coverage/Dockerfile new file mode 100644 index 00000000..19a75781 --- /dev/null +++ b/samples/rust_coverage/Dockerfile @@ -0,0 +1,20 @@ +FROM rust:1.74.0-slim-bullseye + +RUN apt update +RUN apt install -y pkg-config libssl-dev lcov +RUN cargo install cargo-tarpaulin +RUN cargo install cargo-llvm-cov --locked +RUN cargo install llvm-cov-pretty +RUN rustup component add llvm-tools-preview +RUN cargo install grcov + +WORKDIR /home/test + +COPY ./Cargo.toml /home/test/ +COPY ./src /home/test/src +COPY ./get_coverage.sh /home/test/ +RUN mkdir /home/test/outputs + +RUN /bin/bash ./get_coverage.sh + +CMD /bin/bash \ No newline at end of file diff --git a/samples/rust_coverage/README.md b/samples/rust_coverage/README.md new file mode 100644 index 00000000..d46862d2 --- /dev/null +++ b/samples/rust_coverage/README.md @@ -0,0 +1,19 @@ +# Rust coverage + +A simple Rust project and a script for generating HTML coverage reports using various tools. + +Build and run docker container: +```sh +docker build -t tob_cov_test . +docker run -it --name tob_cov_test tob_cov_test bash +``` + +Copy content from the container: +```sh +docker cp tob_cov_test:/home/test/outputs . +``` + +Review results opening relevant HTML files: +```sh +find . -name 'index.html' -or -name tarpaulin-report.html +``` diff --git a/samples/rust_coverage/get_coverage.sh b/samples/rust_coverage/get_coverage.sh new file mode 100644 index 00000000..789ae3a0 --- /dev/null +++ b/samples/rust_coverage/get_coverage.sh @@ -0,0 +1,47 @@ +#!/bin/bash + +# gather coverage + +# llvm-cov +cargo llvm-cov --html --show-instantiations && \ +mv ./target/llvm-cov/html ./outputs/llvm_cov && \ +cargo clean + +cargo llvm-cov --json | llvm-cov-pretty --output-dir ./outputs/llvm_cov_pretty && \ +cargo clean + +# tarpaulin +cargo tarpaulin --ignore-tests --count --engine llvm --out html --force-clean && \ +mv tarpaulin-report.html ./outputs && \ +cargo clean + +# MUST RUN MANUALLY with insecure docker settings: +# docker run -it --security-opt seccomp=unconfined tob_cov_test bash +# cargo tarpaulin --ignore-tests --count --engine ptrace --out html --force-clean && \ +# mv tarpaulin-report.html ./outputs && \ +# cargo clean + +# grcov llvm +export RUSTFLAGS="-Cinstrument-coverage" && \ +cargo build && \ +export LLVM_PROFILE_FILE="tob_test-%p-%m.profraw" && \ +cargo test && \ +grcov . -s . --binary-path ./target/debug/ -t html --branch --ignore-not-existing -o ./outputs/grcov_llvm && \ +mkdir ./outputs/grcov_llvm_lcov && \ +grcov . -s . --binary-path ./target/debug/ -t lcov --branch --ignore-not-existing -o ./outputs/grcov_llvm_lcov && \ +genhtml -o ./outputs/grcov_llvm_lcov --show-details --highlight --ignore-errors source --legend ./outputs/grcov_llvm_lcov/lcov && \ +cargo clean && \ +find . -name '*.profraw' -exec rm '{}' \; && \ +unset LLVM_PROFILE_FILE RUSTFLAGS + +# grcov +export RUSTC_BOOTSTRAP=1 +export CARGO_INCREMENTAL=0 +export RUSTFLAGS="-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort" +export RUSTDOCFLAGS="-Cpanic=abort" +cargo build && \ +cargo test && \ +grcov . -s . --binary-path ./target/debug/ -t html --branch --ignore-not-existing -o ./outputs/grcov +mkdir ./outputs/grcov_lcov && \ +grcov . -s . --binary-path ./target/debug/ -t lcov --branch --ignore-not-existing -o ./outputs/grcov_lcov && \ +genhtml -o ./outputs/grcov_lcov --show-details --highlight --ignore-errors source --legend ./outputs/grcov_lcov/lcov \ No newline at end of file diff --git a/samples/rust_coverage/src/main.rs b/samples/rust_coverage/src/main.rs new file mode 100644 index 00000000..4a653baa --- /dev/null +++ b/samples/rust_coverage/src/main.rs @@ -0,0 +1,107 @@ +mod second; + +fn main() { println!("Hello, world!"); } + +fn validate_data_simple(data: &Data) -> Result<(), ()> { + if !data.magic.eq(&[0x13, 0x37]) { return Err(()) } + if data.len as usize != data.content.len() { return Err(()) } + return Ok(()); +} + +fn validate_data_match(data: &Data) -> i32 { + let x: u32 = match data.content.parse::() { + Ok(_x) => { + let y = 2 * _x; + if y < 6 { + y + } else { + y * 2 + } + } + Err(_) => 0 + }; + if x == 0 { + -1 + } else { + (x as i32) + 1 + } +} + +// https://doc.rust-lang.org/book/ch10-01-syntax.html +fn largest(list: &[T]) -> &T { + let mut largest = &list[0]; + for item in list { + if item > largest { + largest = item; + } + } + largest +} + +fn validate_data_generics(data: &Data) { + let number_list = vec![34, 50, 25, 100, 65]; + + let result = largest(&number_list); + println!("The largest number is {}", result); + + let char_list = vec!['y', 'm', 'a', 'q']; + + let result = largest(&char_list); + println!("The largest char is {}", result); + + let result = largest(data.content.as_bytes()); + println!("The largest content char is {}", result); +} + +struct Data { + magic: [u8; 2], + len: u8, + content: String +} + +#[cfg(test)] +mod tests { + use crate::second::validate_data_panic; + use crate::{Data, validate_data_generics, validate_data_match, validate_data_simple}; + + #[test] + fn parser_detects_errors() { + let mut blob = Data{ magic: [0x73, 0x31], len: 2, content: "AB".parse().unwrap() }; + blob.content = blob.content + "Y"; + let result = validate_data_simple(&blob); + assert!(result.is_err()); + } + + #[test] + fn check_match() { + let blob = Data{ magic: [0x73, 0x31], len: 2, content: "XX".parse().unwrap() }; + let x = validate_data_match(&blob); + assert_eq!(x, -1); + } + + #[test] + fn check_match2() { + let blob = Data{ magic: [0x73, 0x31], len: 2, content: "40".parse().unwrap() }; + let x = validate_data_match(&blob); + assert_eq!(x, 81); + } + + #[test] + fn check_generic() { + let blob = Data{ magic: [0x73, 0x31], len: 2, content: "QWE".parse().unwrap() }; + validate_data_generics(&blob); + } + + #[test] + #[should_panic] + fn check_panic() { + let blob = Data{ magic: [0x73, 0x31], len: 0, content: "4".parse().unwrap() }; + validate_data_panic(&blob); + } + + #[test] + fn check_not_panic() { + let blob = Data{ magic: [0x73, 0x31], len: 2, content: "4".parse().unwrap() }; + validate_data_panic(&blob); + } +} \ No newline at end of file diff --git a/samples/rust_coverage/src/second.rs b/samples/rust_coverage/src/second.rs new file mode 100644 index 00000000..0f11a808 --- /dev/null +++ b/samples/rust_coverage/src/second.rs @@ -0,0 +1,7 @@ +use crate::Data; + +pub(crate) fn validate_data_panic(data: &Data) { + if data.len == 0 { + panic!("panic") + } +} \ No newline at end of file From 08b6d7b3ff259258aca6db49cf26d151e231152a Mon Sep 17 00:00:00 2001 From: GrosQuildu Date: Thu, 11 Jan 2024 17:55:25 +0100 Subject: [PATCH 06/30] rust chapter - coverage done --- content/docs/languages/rust/00-unit-tests.md | 52 +++++++++++++++----- 1 file changed, 39 insertions(+), 13 deletions(-) diff --git a/content/docs/languages/rust/00-unit-tests.md b/content/docs/languages/rust/00-unit-tests.md index f336ccf1..dee51c19 100644 --- a/content/docs/languages/rust/00-unit-tests.md +++ b/content/docs/languages/rust/00-unit-tests.md @@ -244,27 +244,53 @@ mod tests { ### Coverage -It is critically important to know how much coverage your tests have. To gather coverage information use one of: +It is critically important to know how much coverage your tests have. Coverage gathering consists of three steps: -| Feature | [`cargo-llvm-cov`](https://github.com/taiki-e/cargo-llvm-cov) | [`cargo-tarpaulin`](https://github.com/xd009642/tarpaulin) | [`grcov`](https://github.com/mozilla/grcov) +* compile-time instrumentation +* execution of tests, producing "raw" data +* convertion of "raw" data to an usable format + +There are three common instrumentation backends (engines): + +* GCC's `gcov` + * produces `gcno` (during compilation) and `gcda` (during execution) raw data +* LLVM's `SanitizerCoverage` + * produces `profraw` raw data + * can produce `gcno`&`gcda` raw data - not supported in the tooling below +* `ptrace`-based + * produces `profraw` raw data + +There are three popular tools wrapping the above engines for easier consumption in Rust projects. +Instead of them you can directly use [the tools described in the fuzzing chapter](#) (TODO: link). + +| Feature \ Tool | [`cargo-llvm-cov`](https://github.com/taiki-e/cargo-llvm-cov) | [`cargo-tarpaulin`](https://github.com/xd009642/tarpaulin) | [`grcov`](https://github.com/mozilla/grcov) | ----------- | ----------- | ----------- | ----------- | -| Backends | LLVM (profraw) | LLVM (profraw), ptrace | LLVM (profraw), gcov-based (gcno, gcda) | +| Backends | LLVM | LLVM, ptrace | LLVM, gcov | | Coverage | Lines, functions, regions | Lines | Lines, functions, branches | | Output format | Text, lcov, JSON, HTML, cobertura, codecov | Text, lcov, JSON, HTML, xml | Lcov, JSON, HTML, cobertura, coveralls+, markdown, ade | -| Merge data from multiple runs | [Yes](https://github.com/taiki-e/cargo-llvm-cov?tab=readme-ov-file#merge-coverages-generated-under-different-test-conditions) | [Yes/No](https://github.com/xd009642/tarpaulin?tab=readme-ov-file#command-line) (only shows delta) | No | | Exclude files | [`--ignore-filename-regex`](https://github.com/taiki-e/cargo-llvm-cov?tab=readme-ov-file#exclude-file-from-coverage) | `--exclude-files` | `--ignore` | | Exclude functions | [With attributes](https://github.com/taiki-e/cargo-llvm-cov?tab=readme-ov-file#exclude-function-from-coverage) | [With attributes](https://github.com/xd009642/tarpaulin?tab=readme-ov-file#ignoring-code-in-files) | With in-code markers & regexes | | Exclude tests' coverage | [With external module](https://github.com/taiki-e/coverage-helper/tree/v0.2.0) | `--ignore-tests` | No | | Coverage for C/C++ | [`--include-ffi`](https://github.com/taiki-e/cargo-llvm-cov?tab=readme-ov-file#get-coverage-of-cc-code-linked-to-rust-librarybinary) | `--follow-exec` | ? | - -``` -TODO -fail fast? --no-fail-fast -panics --ignore-panics should_panic - -gcno - compile time, gcna - runtime -profraw - ? -``` +| Merge data from multiple runs | [Yes](https://github.com/taiki-e/cargo-llvm-cov?tab=readme-ov-file#merge-coverages-generated-under-different-test-conditions) | [Yes/No](https://github.com/xd009642/tarpaulin?tab=readme-ov-file#command-line) (only shows delta) | No | +| HTML output properties | +| Handles Rust's constructions | Yes | Yes | Yes | +| Expands Rust's generics | `--show-instantiations` | No | No | +| Number of hits | Yes | No | Yes | +| Multi-file output | Yes | No | Yes | + +For post-processing (generating HTML reports, like merging files from multiple runs, and excluding selected files, ..) +of `lcov` outputs you can use: +* [The `lcov` tool's `genhtml` utility](https://github.com/linux-test-project/lcov): +* [`llvm-cov-pretty`](https://github.com/dnaka91/llvm-cov-pretty) + +Our recommendations are: +* Use `cargo-llvm-cov` (with `llvm-cov-pretty`) for rapid testing: easiest to run, can resolve generics +* Use either `cargo-llvm-cov` or `grcov` for complex projects: both are decent, unique, and produce multi-file HTML output +* Use `cargo-tarpaulin` when other tools works incorrectly. [Authors claim](https://github.com/xd009642/tarpaulin?tab=readme-ov-file#nuances-with-llvm-coverage) that these can happen when: + * the code panic unexpecteadly + * there are race conditions + * the code forks ### Validation of tests From 2e8e231e649228152517eaaea90a60c2cc2c5ad5 Mon Sep 17 00:00:00 2001 From: GrosQuildu Date: Thu, 11 Jan 2024 19:03:35 +0100 Subject: [PATCH 07/30] rust chapter - miri --- content/docs/languages/rust/00-unit-tests.md | 38 ++++++++++++++++--- .../docs/languages/rust/10-static-analysis.md | 20 ++++++++-- samples/rust_coverage/src/main.rs | 4 +- 3 files changed, 51 insertions(+), 11 deletions(-) diff --git a/content/docs/languages/rust/00-unit-tests.md b/content/docs/languages/rust/00-unit-tests.md index dee51c19..59b2dbd6 100644 --- a/content/docs/languages/rust/00-unit-tests.md +++ b/content/docs/languages/rust/00-unit-tests.md @@ -11,7 +11,11 @@ This is the most basic type of testing that every project should have. Unit test ## Installation and first steps -The standard and ultimate tool for executing unit and integration tests for Rust codebases is the `cargo test`. The basic setup and usage of `cargo test` is well-known, so we will skip the introduction. +The standard and ultimate tool for executing unit and integration tests for Rust codebases is the `cargo test`. +The basic setup and usage of `cargo test` is well-known, so we will skip the introduction. + +You can also try [the `cargo-nextest`](https://nexte.st/index.html) - a new test runner. + ```rust #[cfg(test)] @@ -23,6 +27,7 @@ mod tests { } ``` + Please note that [`docs tests` don't work in binary targets](https://github.com/rust-lang/rust/issues/50784). Once you have your tests written and all of them passes, lets improve. @@ -242,7 +247,24 @@ mod tests { {{< /details >}} -### Coverage +### MIRI + +[Miri](https://github.com/rust-lang/miri) is an interpreter for Rust "mid-level intermediate representation ". You can run your tests through Miri with: + +``` +rustup +nightly component add miri +cargo miri test +``` + +Miri detects: +* undefined behavior +* memory corruption bugs +* uses of uninitialized data +* memory alignment issues +* issues with aliasing for reference types +* data races + +## Coverage It is critically important to know how much coverage your tests have. Coverage gathering consists of three steps: @@ -281,7 +303,7 @@ Instead of them you can directly use [the tools described in the fuzzing chapter For post-processing (generating HTML reports, like merging files from multiple runs, and excluding selected files, ..) of `lcov` outputs you can use: -* [The `lcov` tool's `genhtml` utility](https://github.com/linux-test-project/lcov): +* [The `lcov` tool's `genhtml` utility](https://github.com/linux-test-project/lcov) * [`llvm-cov-pretty`](https://github.com/dnaka91/llvm-cov-pretty) Our recommendations are: @@ -292,7 +314,13 @@ Our recommendations are: * there are race conditions * the code forks -### Validation of tests +{{< details title="Example to try" open=true >}} +Go to the [Testing Handbook's repository `samples/rust_coverage`](https://github.com/trailofbits/testing-handbook/tree/main/samples/rust_coverage/) folder. + +There you will find Dockerfile generating HTML reports using the described tools. +{{< /details >}} + +## Validation of tests Who tests tests? What if your critical test has a bug that makes it to pass incorrectly? @@ -356,4 +384,4 @@ mod tests { ## Resources * ["The Rust Programming Language", chapter 11. Testing](https://web.mit.edu/rust-lang_v1.25/arch/amd64_ubuntu1404/share/doc/rust/html/book/second-edition/ch11-00-testing.html) - the basics of unit and integration testing in Rust -* [Ed Page's "Iterating on Testing in Rust"](https://epage.github.io/blog/2023/06/iterating-on-test/) - potential issues with `cargo test` +* [Ed Page's "Iterating on Testing in Rust"](https://epage.github.io/blog/2023/06/iterating-on-test/) - lists potential issues with `cargo test` and introduces `cargo-nextest` diff --git a/content/docs/languages/rust/10-static-analysis.md b/content/docs/languages/rust/10-static-analysis.md index abe1691f..b0e87607 100644 --- a/content/docs/languages/rust/10-static-analysis.md +++ b/content/docs/languages/rust/10-static-analysis.md @@ -13,13 +13,22 @@ Analyze source code without executing it. Clippy is the basic linter. Just use it. +```sh +cargo clippy +``` + +Being pedantic won't hurt. ```sh cargo clippy -- -W clippy::pedantic ``` +A nice list of lints can be found at [rust-lang.github.io](https://rust-lang.github.io/rust-clippy/master/index.html). + ## Dylint -To write your own lints and to take adventage of not-standarized lints of others people [use `dylint`](https://github.com/trailofbits/dylint/). +Clippy is nice, but [creating custom lints](https://doc.rust-lang.org/nightly/clippy/development/adding_lints.html) is [a bit of a pain](https://blog.trailofbits.com/2021/11/09/write-rust-lints-without-forking-clippy/). + +To write your own lints and to take adventage of not-standarized lints of others people [use `dylint`](https://github.com/trailofbits/dylint/) - dynamic linter. ### Quick start @@ -42,11 +51,14 @@ cargo dylint --all --workspace ### Writing your own lints -TODO +TODO! + +```sh +cargo dylint --new +``` -## MIRI +Now implement the `LateLintPass` trait and accommodate the symbols asking to be filled in. -* detects certain classes of undefined behavior and memory leaks ## Prusti diff --git a/samples/rust_coverage/src/main.rs b/samples/rust_coverage/src/main.rs index 4a653baa..f93f4018 100644 --- a/samples/rust_coverage/src/main.rs +++ b/samples/rust_coverage/src/main.rs @@ -1,4 +1,4 @@ -mod second; +samples/rust_coverage/src/main.rsmod second; fn main() { println!("Hello, world!"); } @@ -83,7 +83,7 @@ mod tests { fn check_match2() { let blob = Data{ magic: [0x73, 0x31], len: 2, content: "40".parse().unwrap() }; let x = validate_data_match(&blob); - assert_eq!(x, 81); + assert_eq!(x, 161); } #[test] From b4d9097ae535b408290d08e0231dff37c80906ca Mon Sep 17 00:00:00 2001 From: GrosQuildu Date: Fri, 12 Jan 2024 12:28:33 +0100 Subject: [PATCH 08/30] rust chapter - coverage code fix --- samples/rust_coverage/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/rust_coverage/src/main.rs b/samples/rust_coverage/src/main.rs index f93f4018..9ec9f3eb 100644 --- a/samples/rust_coverage/src/main.rs +++ b/samples/rust_coverage/src/main.rs @@ -1,4 +1,4 @@ -samples/rust_coverage/src/main.rsmod second; +mod second; fn main() { println!("Hello, world!"); } From 0228bfbe37e0269f87d81e6015d615c710056945 Mon Sep 17 00:00:00 2001 From: GrosQuildu Date: Fri, 12 Jan 2024 20:19:57 +0100 Subject: [PATCH 09/30] rust chapter - add static content for coverage --- .../grcov/badges/flat.svg | 23 + .../grcov/badges/flat_square.svg | 13 + .../grcov/badges/for_the_badge.svg | 13 + .../grcov/badges/plastic.svg | 25 + .../grcov/badges/social.svg | 27 + .../samples_rust_coverage/grcov/coverage.json | 1 + static/samples_rust_coverage/grcov/index.html | 88 + .../grcov/src/index.html | 115 ++ .../grcov/src/main.rs.html | 1762 +++++++++++++++++ .../grcov/src/second.rs.html | 162 ++ .../grcov_lcov/amber.png | Bin 0 -> 141 bytes .../grcov_lcov/emerald.png | Bin 0 -> 141 bytes .../samples_rust_coverage/grcov_lcov/gcov.css | 519 +++++ .../grcov_lcov/glass.png | Bin 0 -> 167 bytes .../grcov_lcov/index-sort-f.html | 102 + .../grcov_lcov/index-sort-l.html | 102 + .../grcov_lcov/index.html | 102 + static/samples_rust_coverage/grcov_lcov/lcov | 182 ++ .../samples_rust_coverage/grcov_lcov/ruby.png | Bin 0 -> 141 bytes .../samples_rust_coverage/grcov_lcov/snow.png | Bin 0 -> 141 bytes .../grcov_lcov/src/index-detail-sort-f.html | 128 ++ .../grcov_lcov/src/index-detail-sort-l.html | 128 ++ .../grcov_lcov/src/index-detail.html | 128 ++ .../grcov_lcov/src/index-sort-f.html | 112 ++ .../grcov_lcov/src/index-sort-l.html | 112 ++ .../grcov_lcov/src/index.html | 112 ++ .../grcov_lcov/src/main.rs.func-sort-c.html | 148 ++ .../grcov_lcov/src/main.rs.func.html | 148 ++ .../grcov_lcov/src/main.rs.gcov.html | 191 ++ .../grcov_lcov/src/second.rs.func-sort-c.html | 84 + .../grcov_lcov/src/second.rs.func.html | 84 + .../grcov_lcov/src/second.rs.gcov.html | 91 + .../grcov_lcov/updown.png | Bin 0 -> 117 bytes .../grcov_llvm/badges/flat.svg | 23 + .../grcov_llvm/badges/flat_square.svg | 13 + .../grcov_llvm/badges/for_the_badge.svg | 13 + .../grcov_llvm/badges/plastic.svg | 25 + .../grcov_llvm/badges/social.svg | 27 + .../grcov_llvm/coverage.json | 1 + .../grcov_llvm/index.html | 88 + .../grcov_llvm/src/index.html | 115 ++ .../grcov_llvm/src/main.rs.html | 1762 +++++++++++++++++ .../grcov_llvm/src/second.rs.html | 162 ++ .../grcov_llvm_lcov/amber.png | Bin 0 -> 141 bytes .../grcov_llvm_lcov/emerald.png | Bin 0 -> 141 bytes .../grcov_llvm_lcov/gcov.css | 519 +++++ .../grcov_llvm_lcov/glass.png | Bin 0 -> 167 bytes .../grcov_llvm_lcov/index-sort-f.html | 102 + .../grcov_llvm_lcov/index-sort-l.html | 102 + .../grcov_llvm_lcov/index.html | 102 + .../grcov_llvm_lcov/lcov | 148 ++ .../grcov_llvm_lcov/ruby.png | Bin 0 -> 141 bytes .../grcov_llvm_lcov/snow.png | Bin 0 -> 141 bytes .../src/index-detail-sort-f.html | 128 ++ .../src/index-detail-sort-l.html | 128 ++ .../grcov_llvm_lcov/src/index-detail.html | 128 ++ .../grcov_llvm_lcov/src/index-sort-f.html | 112 ++ .../grcov_llvm_lcov/src/index-sort-l.html | 112 ++ .../grcov_llvm_lcov/src/index.html | 112 ++ .../src/main.rs.func-sort-c.html | 160 ++ .../grcov_llvm_lcov/src/main.rs.func.html | 160 ++ .../grcov_llvm_lcov/src/main.rs.gcov.html | 191 ++ .../src/second.rs.func-sort-c.html | 84 + .../grcov_llvm_lcov/src/second.rs.func.html | 84 + .../grcov_llvm_lcov/src/second.rs.gcov.html | 91 + .../grcov_llvm_lcov/updown.png | Bin 0 -> 117 bytes .../coverage/home/test/src/main.rs.html | 1 + .../coverage/home/test/src/second.rs.html | 1 + .../samples_rust_coverage/llvm_cov/index.html | 1 + .../samples_rust_coverage/llvm_cov/style.css | 143 ++ .../llvm_cov_pretty/index.html | 1 + .../llvm_cov_pretty/src/main.rs.html | 1 + .../llvm_cov_pretty/src/second.rs.html | 1 + .../llvm_cov_pretty/style.css | 1 + .../llvm_cov_pretty/syntax.css | 1 + .../tarpaulin-report.html | 660 ++++++ 76 files changed, 10205 insertions(+) create mode 100644 static/samples_rust_coverage/grcov/badges/flat.svg create mode 100644 static/samples_rust_coverage/grcov/badges/flat_square.svg create mode 100644 static/samples_rust_coverage/grcov/badges/for_the_badge.svg create mode 100644 static/samples_rust_coverage/grcov/badges/plastic.svg create mode 100644 static/samples_rust_coverage/grcov/badges/social.svg create mode 100644 static/samples_rust_coverage/grcov/coverage.json create mode 100644 static/samples_rust_coverage/grcov/index.html create mode 100644 static/samples_rust_coverage/grcov/src/index.html create mode 100644 static/samples_rust_coverage/grcov/src/main.rs.html create mode 100644 static/samples_rust_coverage/grcov/src/second.rs.html create mode 100644 static/samples_rust_coverage/grcov_lcov/amber.png create mode 100644 static/samples_rust_coverage/grcov_lcov/emerald.png create mode 100644 static/samples_rust_coverage/grcov_lcov/gcov.css create mode 100644 static/samples_rust_coverage/grcov_lcov/glass.png create mode 100644 static/samples_rust_coverage/grcov_lcov/index-sort-f.html create mode 100644 static/samples_rust_coverage/grcov_lcov/index-sort-l.html create mode 100644 static/samples_rust_coverage/grcov_lcov/index.html create mode 100644 static/samples_rust_coverage/grcov_lcov/lcov create mode 100644 static/samples_rust_coverage/grcov_lcov/ruby.png create mode 100644 static/samples_rust_coverage/grcov_lcov/snow.png create mode 100644 static/samples_rust_coverage/grcov_lcov/src/index-detail-sort-f.html create mode 100644 static/samples_rust_coverage/grcov_lcov/src/index-detail-sort-l.html create mode 100644 static/samples_rust_coverage/grcov_lcov/src/index-detail.html create mode 100644 static/samples_rust_coverage/grcov_lcov/src/index-sort-f.html create mode 100644 static/samples_rust_coverage/grcov_lcov/src/index-sort-l.html create mode 100644 static/samples_rust_coverage/grcov_lcov/src/index.html create mode 100644 static/samples_rust_coverage/grcov_lcov/src/main.rs.func-sort-c.html create mode 100644 static/samples_rust_coverage/grcov_lcov/src/main.rs.func.html create mode 100644 static/samples_rust_coverage/grcov_lcov/src/main.rs.gcov.html create mode 100644 static/samples_rust_coverage/grcov_lcov/src/second.rs.func-sort-c.html create mode 100644 static/samples_rust_coverage/grcov_lcov/src/second.rs.func.html create mode 100644 static/samples_rust_coverage/grcov_lcov/src/second.rs.gcov.html create mode 100644 static/samples_rust_coverage/grcov_lcov/updown.png create mode 100644 static/samples_rust_coverage/grcov_llvm/badges/flat.svg create mode 100644 static/samples_rust_coverage/grcov_llvm/badges/flat_square.svg create mode 100644 static/samples_rust_coverage/grcov_llvm/badges/for_the_badge.svg create mode 100644 static/samples_rust_coverage/grcov_llvm/badges/plastic.svg create mode 100644 static/samples_rust_coverage/grcov_llvm/badges/social.svg create mode 100644 static/samples_rust_coverage/grcov_llvm/coverage.json create mode 100644 static/samples_rust_coverage/grcov_llvm/index.html create mode 100644 static/samples_rust_coverage/grcov_llvm/src/index.html create mode 100644 static/samples_rust_coverage/grcov_llvm/src/main.rs.html create mode 100644 static/samples_rust_coverage/grcov_llvm/src/second.rs.html create mode 100644 static/samples_rust_coverage/grcov_llvm_lcov/amber.png create mode 100644 static/samples_rust_coverage/grcov_llvm_lcov/emerald.png create mode 100644 static/samples_rust_coverage/grcov_llvm_lcov/gcov.css create mode 100644 static/samples_rust_coverage/grcov_llvm_lcov/glass.png create mode 100644 static/samples_rust_coverage/grcov_llvm_lcov/index-sort-f.html create mode 100644 static/samples_rust_coverage/grcov_llvm_lcov/index-sort-l.html create mode 100644 static/samples_rust_coverage/grcov_llvm_lcov/index.html create mode 100644 static/samples_rust_coverage/grcov_llvm_lcov/lcov create mode 100644 static/samples_rust_coverage/grcov_llvm_lcov/ruby.png create mode 100644 static/samples_rust_coverage/grcov_llvm_lcov/snow.png create mode 100644 static/samples_rust_coverage/grcov_llvm_lcov/src/index-detail-sort-f.html create mode 100644 static/samples_rust_coverage/grcov_llvm_lcov/src/index-detail-sort-l.html create mode 100644 static/samples_rust_coverage/grcov_llvm_lcov/src/index-detail.html create mode 100644 static/samples_rust_coverage/grcov_llvm_lcov/src/index-sort-f.html create mode 100644 static/samples_rust_coverage/grcov_llvm_lcov/src/index-sort-l.html create mode 100644 static/samples_rust_coverage/grcov_llvm_lcov/src/index.html create mode 100644 static/samples_rust_coverage/grcov_llvm_lcov/src/main.rs.func-sort-c.html create mode 100644 static/samples_rust_coverage/grcov_llvm_lcov/src/main.rs.func.html create mode 100644 static/samples_rust_coverage/grcov_llvm_lcov/src/main.rs.gcov.html create mode 100644 static/samples_rust_coverage/grcov_llvm_lcov/src/second.rs.func-sort-c.html create mode 100644 static/samples_rust_coverage/grcov_llvm_lcov/src/second.rs.func.html create mode 100644 static/samples_rust_coverage/grcov_llvm_lcov/src/second.rs.gcov.html create mode 100644 static/samples_rust_coverage/grcov_llvm_lcov/updown.png create mode 100644 static/samples_rust_coverage/llvm_cov/coverage/home/test/src/main.rs.html create mode 100644 static/samples_rust_coverage/llvm_cov/coverage/home/test/src/second.rs.html create mode 100644 static/samples_rust_coverage/llvm_cov/index.html create mode 100644 static/samples_rust_coverage/llvm_cov/style.css create mode 100644 static/samples_rust_coverage/llvm_cov_pretty/index.html create mode 100644 static/samples_rust_coverage/llvm_cov_pretty/src/main.rs.html create mode 100644 static/samples_rust_coverage/llvm_cov_pretty/src/second.rs.html create mode 100644 static/samples_rust_coverage/llvm_cov_pretty/style.css create mode 100644 static/samples_rust_coverage/llvm_cov_pretty/syntax.css create mode 100644 static/samples_rust_coverage/tarpaulin-report.html diff --git a/static/samples_rust_coverage/grcov/badges/flat.svg b/static/samples_rust_coverage/grcov/badges/flat.svg new file mode 100644 index 00000000..03e135bf --- /dev/null +++ b/static/samples_rust_coverage/grcov/badges/flat.svg @@ -0,0 +1,23 @@ + + coverage: 94% + + + + + + + + + + + + + + + coverage + + 94% + + + \ No newline at end of file diff --git a/static/samples_rust_coverage/grcov/badges/flat_square.svg b/static/samples_rust_coverage/grcov/badges/flat_square.svg new file mode 100644 index 00000000..b7a4567a --- /dev/null +++ b/static/samples_rust_coverage/grcov/badges/flat_square.svg @@ -0,0 +1,13 @@ + + coverage: 94% + + + + + + coverage + 94% + + + \ No newline at end of file diff --git a/static/samples_rust_coverage/grcov/badges/for_the_badge.svg b/static/samples_rust_coverage/grcov/badges/for_the_badge.svg new file mode 100644 index 00000000..70b55d30 --- /dev/null +++ b/static/samples_rust_coverage/grcov/badges/for_the_badge.svg @@ -0,0 +1,13 @@ + + COVERAGE: 94% + + + + + + COVERAGE + 94% + + + \ No newline at end of file diff --git a/static/samples_rust_coverage/grcov/badges/plastic.svg b/static/samples_rust_coverage/grcov/badges/plastic.svg new file mode 100644 index 00000000..c84a8cee --- /dev/null +++ b/static/samples_rust_coverage/grcov/badges/plastic.svg @@ -0,0 +1,25 @@ + + coverage: 94% + + + + + + + + + + + + + + + + + coverage + + 94% + + + \ No newline at end of file diff --git a/static/samples_rust_coverage/grcov/badges/social.svg b/static/samples_rust_coverage/grcov/badges/social.svg new file mode 100644 index 00000000..da39da47 --- /dev/null +++ b/static/samples_rust_coverage/grcov/badges/social.svg @@ -0,0 +1,27 @@ + + Coverage: 94% + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/static/samples_rust_coverage/grcov/coverage.json b/static/samples_rust_coverage/grcov/coverage.json new file mode 100644 index 00000000..c0a27736 --- /dev/null +++ b/static/samples_rust_coverage/grcov/coverage.json @@ -0,0 +1 @@ +{"schemaVersion":1,"label":"coverage","message":"94.03%","color":"green"} \ No newline at end of file diff --git a/static/samples_rust_coverage/grcov/index.html b/static/samples_rust_coverage/grcov/index.html new file mode 100644 index 00000000..19571c04 --- /dev/null +++ b/static/samples_rust_coverage/grcov/index.html @@ -0,0 +1,88 @@ + + + + + Grcov report - top_level + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DirectoryLine CoverageFunctionsBranches
src + + 94.03% + + + 94.03% + + 63 / 67 + 68.97%20 / 29 67.5%27 / 40
+
+
+

Date: 2024-01-12 19:04

+
+
+ + diff --git a/static/samples_rust_coverage/grcov/src/index.html b/static/samples_rust_coverage/grcov/src/index.html new file mode 100644 index 00000000..9b2c6a1f --- /dev/null +++ b/static/samples_rust_coverage/grcov/src/index.html @@ -0,0 +1,115 @@ + + + + + Grcov report - src + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileLine CoverageFunctionsBranches
main.rs + + 93.75% + + + 93.75% + + 60 / 64 + 70.37%19 / 27 65.79%25 / 38
second.rs + + 100% + + + 100% + + 3 / 3 + 50%1 / 2 100%2 / 2
+
+
+

Date: 2024-01-12 19:04

+
+
+ + diff --git a/static/samples_rust_coverage/grcov/src/main.rs.html b/static/samples_rust_coverage/grcov/src/main.rs.html new file mode 100644 index 00000000..59773bc9 --- /dev/null +++ b/static/samples_rust_coverage/grcov/src/main.rs.html @@ -0,0 +1,1762 @@ + + + + + Grcov report - main.rs + + +
+ + + +
+
+ 1 +
+
+ 8 +
+
+
mod second;
+
+
+
+ 2 +
+
+ +
+
+

+            
+
+
+ 3 +
+
+ +
+
+
fn main() { println!("Hello, world!"); }
+
+
+
+ 4 +
+
+ +
+
+

+            
+
+
+ 5 +
+
+ 1 +
+
+
fn validate_data_simple(data: &Data) -> Result<(), ()> {
+
+
+
+ 6 +
+
+ 1 +
+
+
    if !data.magic.eq(&[0x13, 0x37]) { return Err(()) }
+
+
+
+ 7 +
+
+ +
+
+
    if data.len as usize != data.content.len() { return Err(()) }
+
+
+
+ 8 +
+
+ +
+
+
    return Ok(());
+
+
+
+ 9 +
+
+ 1 +
+
+
}
+
+
+
+ 10 +
+
+ +
+
+

+            
+
+
+ 11 +
+
+ 2 +
+
+
fn validate_data_match(data: &Data) -> i32 {
+
+
+
+ 12 +
+
+ 2 +
+
+
    let x: u32 = match data.content.parse::<u32>() {
+
+
+
+ 13 +
+
+ 1 +
+
+
        Ok(_x) => {
+
+
+
+ 14 +
+
+ 1 +
+
+
            let y = 2 * _x;
+
+
+
+ 15 +
+
+ 1 +
+
+
            if y < 6 {
+
+
+
+ 16 +
+
+ +
+
+
                y
+
+
+
+ 17 +
+
+ +
+
+
            } else {
+
+
+
+ 18 +
+
+ 1 +
+
+
                y * 2
+
+
+
+ 19 +
+
+ +
+
+
            }
+
+
+
+ 20 +
+
+ +
+
+
        }
+
+
+
+ 21 +
+
+ 1 +
+
+
        Err(_) => 0
+
+
+
+ 22 +
+
+ +
+
+
    };
+
+
+
+ 23 +
+
+ 2 +
+
+
    if x == 0 {
+
+
+
+ 24 +
+
+ 1 +
+
+
        -1
+
+
+
+ 25 +
+
+ +
+
+
    } else {
+
+
+
+ 26 +
+
+ 1 +
+
+
        (x as i32) + 1
+
+
+
+ 27 +
+
+ +
+
+
    }
+
+
+
+ 28 +
+
+ 2 +
+
+
}
+
+
+
+ 29 +
+
+ +
+
+

+            
+
+
+ 30 +
+
+ +
+
+
// https://doc.rust-lang.org/book/ch10-01-syntax.html
+
+
+
+ 31 +
+
+ 3 +
+
+
fn largest<T: PartialOrd>(list: &[T]) -> &T {
+
+
+
+ 32 +
+
+ 3 +
+
+
    let mut largest = &list[0];
+
+
+
+ 33 +
+
+ 15 +
+
+
    for item in list {
+
+
+
+ 34 +
+
+ 12 +
+
+
        if item > largest {
+
+
+
+ 35 +
+
+ 3 +
+
+
            largest = item;
+
+
+
+ 36 +
+
+ +
+
+
        }
+
+
+
+ 37 +
+
+ +
+
+
    }
+
+
+
+ 38 +
+
+ 3 +
+
+
    largest
+
+
+
+ 39 +
+
+ 3 +
+
+
}
+
+
+
+ 40 +
+
+ +
+
+

+            
+
+
+ 41 +
+
+ 1 +
+
+
fn validate_data_generics(data: &Data) {
+
+
+
+ 42 +
+
+ 1 +
+
+
    let number_list = vec![34, 50, 25, 100, 65];
+
+
+
+ 43 +
+
+ +
+
+

+            
+
+
+ 44 +
+
+ 1 +
+
+
    let result = largest(&number_list);
+
+
+
+ 45 +
+
+ 1 +
+
+
    println!("The largest number is {}", result);
+
+
+
+ 46 +
+
+ +
+
+

+            
+
+
+ 47 +
+
+ 1 +
+
+
    let char_list = vec!['y', 'm', 'a', 'q'];
+
+
+
+ 48 +
+
+ +
+
+

+            
+
+
+ 49 +
+
+ 1 +
+
+
    let result = largest(&char_list);
+
+
+
+ 50 +
+
+ 1 +
+
+
    println!("The largest char is {}", result);
+
+
+
+ 51 +
+
+ +
+
+

+            
+
+
+ 52 +
+
+ 1 +
+
+
    let result = largest(data.content.as_bytes());
+
+
+
+ 53 +
+
+ 1 +
+
+
    println!("The largest content char is {}", result);
+
+
+
+ 54 +
+
+ 1 +
+
+
}
+
+
+
+ 55 +
+
+ +
+
+

+            
+
+
+ 56 +
+
+ +
+
+
struct Data {
+
+
+
+ 57 +
+
+ +
+
+
    magic: [u8; 2],
+
+
+
+ 58 +
+
+ +
+
+
    len: u8,
+
+
+
+ 59 +
+
+ +
+
+
    content: String
+
+
+
+ 60 +
+
+ +
+
+
}
+
+
+
+ 61 +
+
+ +
+
+

+            
+
+
+ 62 +
+
+ +
+
+
#[cfg(test)]
+
+
+
+ 63 +
+
+ +
+
+
mod tests {
+
+
+
+ 64 +
+
+ +
+
+
    use crate::second::validate_data_panic;
+
+
+
+ 65 +
+
+ +
+
+
    use crate::{Data, validate_data_generics, validate_data_match, validate_data_simple};
+
+
+
+ 66 +
+
+ +
+
+

+            
+
+
+ 67 +
+
+ +
+
+
    #[test]
+
+
+
+ 68 +
+
+ 2 +
+
+
    fn parser_detects_errors() {
+
+
+
+ 69 +
+
+ 1 +
+
+
        let mut blob = Data{ magic: [0x73, 0x31], len: 2, content: "AB".parse().unwrap() };
+
+
+
+ 70 +
+
+ 1 +
+
+
        blob.content = blob.content + "Y";
+
+
+
+ 71 +
+
+ 1 +
+
+
        let result = validate_data_simple(&blob);
+
+
+
+ 72 +
+
+ 1 +
+
+
        assert!(result.is_err());
+
+
+
+ 73 +
+
+ 2 +
+
+
    }
+
+
+
+ 74 +
+
+ +
+
+

+            
+
+
+ 75 +
+
+ +
+
+
    #[test]
+
+
+
+ 76 +
+
+ 2 +
+
+
    fn check_match() {
+
+
+
+ 77 +
+
+ 1 +
+
+
        let blob = Data{ magic: [0x73, 0x31], len: 2, content: "XX".parse().unwrap() };
+
+
+
+ 78 +
+
+ 1 +
+
+
        let x = validate_data_match(&blob);
+
+
+
+ 79 +
+
+ 1 +
+
+
        assert_eq!(x, -1);
+
+
+
+ 80 +
+
+ 2 +
+
+
    }
+
+
+
+ 81 +
+
+ +
+
+

+            
+
+
+ 82 +
+
+ +
+
+
    #[test]
+
+
+
+ 83 +
+
+ 2 +
+
+
    fn check_match2() {
+
+
+
+ 84 +
+
+ 1 +
+
+
        let blob = Data{ magic: [0x73, 0x31], len: 2, content: "40".parse().unwrap() };
+
+
+
+ 85 +
+
+ 1 +
+
+
        let x = validate_data_match(&blob);
+
+
+
+ 86 +
+
+ 1 +
+
+
        assert_eq!(x, 161);
+
+
+
+ 87 +
+
+ 2 +
+
+
    }
+
+
+
+ 88 +
+
+ +
+
+

+            
+
+
+ 89 +
+
+ +
+
+
    #[test]
+
+
+
+ 90 +
+
+ 2 +
+
+
    fn check_generic() {
+
+
+
+ 91 +
+
+ 1 +
+
+
        let blob = Data{ magic: [0x73, 0x31], len: 2, content: "QWE".parse().unwrap() };
+
+
+
+ 92 +
+
+ 1 +
+
+
        validate_data_generics(&blob);
+
+
+
+ 93 +
+
+ 2 +
+
+
    }
+
+
+
+ 94 +
+
+ +
+
+

+            
+
+
+ 95 +
+
+ +
+
+
    #[test]
+
+
+
+ 96 +
+
+ +
+
+
    #[should_panic]
+
+
+
+ 97 +
+
+ 2 +
+
+
    fn check_panic() {
+
+
+
+ 98 +
+
+ 1 +
+
+
        let blob = Data{ magic: [0x73, 0x31], len: 0, content: "4".parse().unwrap() };
+
+
+
+ 99 +
+
+ 1 +
+
+
        validate_data_panic(&blob);
+
+
+
+ 100 +
+
+ 2 +
+
+
    }
+
+
+
+ 101 +
+
+ +
+
+

+            
+
+
+ 102 +
+
+ +
+
+
    #[test]
+
+
+
+ 103 +
+
+ 2 +
+
+
    fn check_not_panic() {
+
+
+
+ 104 +
+
+ 1 +
+
+
        let blob = Data{ magic: [0x73, 0x31], len: 2, content: "4".parse().unwrap() };
+
+
+
+ 105 +
+
+ 1 +
+
+
        validate_data_panic(&blob);
+
+
+
+ 106 +
+
+ 2 +
+
+
    }
+
+
+
+ 107 +
+
+ +
+
+
}
+
+
+
+
+
+

Date: 2024-01-12 19:04

+
+
+ + diff --git a/static/samples_rust_coverage/grcov/src/second.rs.html b/static/samples_rust_coverage/grcov/src/second.rs.html new file mode 100644 index 00000000..aa02939b --- /dev/null +++ b/static/samples_rust_coverage/grcov/src/second.rs.html @@ -0,0 +1,162 @@ + + + + + Grcov report - second.rs + + +
+ + + +
+
+ 1 +
+
+ +
+
+
use crate::Data;
+
+
+
+ 2 +
+
+ +
+
+

+            
+
+
+ 3 +
+
+ 2 +
+
+
pub(crate) fn validate_data_panic(data: &Data) {
+
+
+
+ 4 +
+
+ 2 +
+
+
    if data.len == 0 {
+
+
+
+ 5 +
+
+ 1 +
+
+
        panic!("panic")
+
+
+
+ 6 +
+
+ +
+
+
    }
+
+
+
+ 7 +
+
+ +
+
+
}
+
+
+
+
+
+

Date: 2024-01-12 19:04

+
+
+ + diff --git a/static/samples_rust_coverage/grcov_lcov/amber.png b/static/samples_rust_coverage/grcov_lcov/amber.png new file mode 100644 index 0000000000000000000000000000000000000000..2cab170d8359081983a4e343848dfe06bc490f12 GIT binary patch literal 141 zcmeAS@N?(olHy`uVBq!ia0vp^j3CU&3?x-=hn)ga>?NMQuI!iC1^G2tW}LqE04T&+ z;1OBOz`!j8!i<;h*8KqrvZOouIx;Y9?C1WI$O`1M1^9%x{(levWG?NMQuI!iC1^Jb!lvI6;R0X`wF(yt=9xVZRt1vCRixIA4P dLn>}1Cji+@42)0J?}79&c)I$ztaD0e0sy@GAL0N2 literal 0 HcmV?d00001 diff --git a/static/samples_rust_coverage/grcov_lcov/gcov.css b/static/samples_rust_coverage/grcov_lcov/gcov.css new file mode 100644 index 00000000..bfd0a83e --- /dev/null +++ b/static/samples_rust_coverage/grcov_lcov/gcov.css @@ -0,0 +1,519 @@ +/* All views: initial background and text color */ +body +{ + color: #000000; + background-color: #FFFFFF; +} + +/* All views: standard link format*/ +a:link +{ + color: #284FA8; + text-decoration: underline; +} + +/* All views: standard link - visited format */ +a:visited +{ + color: #00CB40; + text-decoration: underline; +} + +/* All views: standard link - activated format */ +a:active +{ + color: #FF0040; + text-decoration: underline; +} + +/* All views: main title format */ +td.title +{ + text-align: center; + padding-bottom: 10px; + font-family: sans-serif; + font-size: 20pt; + font-style: italic; + font-weight: bold; +} + +/* All views: header item format */ +td.headerItem +{ + text-align: right; + padding-right: 6px; + font-family: sans-serif; + font-weight: bold; + vertical-align: top; + white-space: nowrap; +} + +/* All views: header item value format */ +td.headerValue +{ + text-align: left; + color: #284FA8; + font-family: sans-serif; + font-weight: bold; + white-space: nowrap; +} + +/* All views: header item coverage table heading */ +td.headerCovTableHead +{ + text-align: center; + padding-right: 6px; + padding-left: 6px; + padding-bottom: 0px; + font-family: sans-serif; + font-size: 80%; + white-space: nowrap; +} + +/* All views: header item coverage table entry */ +td.headerCovTableEntry +{ + text-align: right; + color: #284FA8; + font-family: sans-serif; + font-weight: bold; + white-space: nowrap; + padding-left: 12px; + padding-right: 4px; + background-color: #DAE7FE; +} + +/* All views: header item coverage table entry for high coverage rate */ +td.headerCovTableEntryHi +{ + text-align: right; + color: #000000; + font-family: sans-serif; + font-weight: bold; + white-space: nowrap; + padding-left: 12px; + padding-right: 4px; + background-color: #A7FC9D; +} + +/* All views: header item coverage table entry for medium coverage rate */ +td.headerCovTableEntryMed +{ + text-align: right; + color: #000000; + font-family: sans-serif; + font-weight: bold; + white-space: nowrap; + padding-left: 12px; + padding-right: 4px; + background-color: #FFEA20; +} + +/* All views: header item coverage table entry for ow coverage rate */ +td.headerCovTableEntryLo +{ + text-align: right; + color: #000000; + font-family: sans-serif; + font-weight: bold; + white-space: nowrap; + padding-left: 12px; + padding-right: 4px; + background-color: #FF0000; +} + +/* All views: header legend value for legend entry */ +td.headerValueLeg +{ + text-align: left; + color: #000000; + font-family: sans-serif; + font-size: 80%; + white-space: nowrap; + padding-top: 4px; +} + +/* All views: color of horizontal ruler */ +td.ruler +{ + background-color: #6688D4; +} + +/* All views: version string format */ +td.versionInfo +{ + text-align: center; + padding-top: 2px; + font-family: sans-serif; + font-style: italic; +} + +/* Directory view/File view (all)/Test case descriptions: + table headline format */ +td.tableHead +{ + text-align: center; + color: #FFFFFF; + background-color: #6688D4; + font-family: sans-serif; + font-size: 120%; + font-weight: bold; + white-space: nowrap; + padding-left: 4px; + padding-right: 4px; +} + +span.tableHeadSort +{ + padding-right: 4px; +} + +/* Directory view/File view (all): filename entry format */ +td.coverFile +{ + text-align: left; + padding-left: 10px; + padding-right: 20px; + color: #284FA8; + background-color: #DAE7FE; + font-family: monospace; +} + +/* Directory view/File view (all): bar-graph entry format*/ +td.coverBar +{ + padding-left: 10px; + padding-right: 10px; + background-color: #DAE7FE; +} + +/* Directory view/File view (all): bar-graph outline color */ +td.coverBarOutline +{ + background-color: #000000; +} + +/* Directory view/File view (all): percentage entry for files with + high coverage rate */ +td.coverPerHi +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #A7FC9D; + font-weight: bold; + font-family: sans-serif; +} + +/* Directory view/File view (all): line count entry for files with + high coverage rate */ +td.coverNumHi +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #A7FC9D; + white-space: nowrap; + font-family: sans-serif; +} + +/* Directory view/File view (all): percentage entry for files with + medium coverage rate */ +td.coverPerMed +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #FFEA20; + font-weight: bold; + font-family: sans-serif; +} + +/* Directory view/File view (all): line count entry for files with + medium coverage rate */ +td.coverNumMed +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #FFEA20; + white-space: nowrap; + font-family: sans-serif; +} + +/* Directory view/File view (all): percentage entry for files with + low coverage rate */ +td.coverPerLo +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #FF0000; + font-weight: bold; + font-family: sans-serif; +} + +/* Directory view/File view (all): line count entry for files with + low coverage rate */ +td.coverNumLo +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #FF0000; + white-space: nowrap; + font-family: sans-serif; +} + +/* File view (all): "show/hide details" link format */ +a.detail:link +{ + color: #B8D0FF; + font-size:80%; +} + +/* File view (all): "show/hide details" link - visited format */ +a.detail:visited +{ + color: #B8D0FF; + font-size:80%; +} + +/* File view (all): "show/hide details" link - activated format */ +a.detail:active +{ + color: #FFFFFF; + font-size:80%; +} + +/* File view (detail): test name entry */ +td.testName +{ + text-align: right; + padding-right: 10px; + background-color: #DAE7FE; + font-family: sans-serif; +} + +/* File view (detail): test percentage entry */ +td.testPer +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #DAE7FE; + font-family: sans-serif; +} + +/* File view (detail): test lines count entry */ +td.testNum +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #DAE7FE; + font-family: sans-serif; +} + +/* Test case descriptions: test name format*/ +dt +{ + font-family: sans-serif; + font-weight: bold; +} + +/* Test case descriptions: description table body */ +td.testDescription +{ + padding-top: 10px; + padding-left: 30px; + padding-bottom: 10px; + padding-right: 30px; + background-color: #DAE7FE; +} + +/* Source code view: function entry */ +td.coverFn +{ + text-align: left; + padding-left: 10px; + padding-right: 20px; + color: #284FA8; + background-color: #DAE7FE; + font-family: monospace; +} + +/* Source code view: function entry zero count*/ +td.coverFnLo +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #FF0000; + font-weight: bold; + font-family: sans-serif; +} + +/* Source code view: function entry nonzero count*/ +td.coverFnHi +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #DAE7FE; + font-weight: bold; + font-family: sans-serif; +} + +/* Source code view: source code format */ +pre.source +{ + font-family: monospace; + white-space: pre; + margin-top: 2px; +} + +/* Source code view: line number format */ +span.lineNum +{ + background-color: #EFE383; +} + +/* Source code view: format for lines which were executed */ +td.lineCov, +span.lineCov +{ + background-color: #CAD7FE; +} + +/* Source code view: format for Cov legend */ +span.coverLegendCov +{ + padding-left: 10px; + padding-right: 10px; + padding-bottom: 2px; + background-color: #CAD7FE; +} + +/* Source code view: format for lines which were not executed */ +td.lineNoCov, +span.lineNoCov +{ + background-color: #FF6230; +} + +/* Source code view: format for NoCov legend */ +span.coverLegendNoCov +{ + padding-left: 10px; + padding-right: 10px; + padding-bottom: 2px; + background-color: #FF6230; +} + +/* Source code view (function table): standard link - visited format */ +td.lineNoCov > a:visited, +td.lineCov > a:visited +{ + color: black; + text-decoration: underline; +} + +/* Source code view: format for lines which were executed only in a + previous version */ +span.lineDiffCov +{ + background-color: #B5F7AF; +} + +/* Source code view: format for branches which were executed + * and taken */ +span.branchCov +{ + background-color: #CAD7FE; +} + +/* Source code view: format for branches which were executed + * but not taken */ +span.branchNoCov +{ + background-color: #FF6230; +} + +/* Source code view: format for branches which were not executed */ +span.branchNoExec +{ + background-color: #FF6230; +} + +/* Source code view: format for the source code heading line */ +pre.sourceHeading +{ + white-space: pre; + font-family: monospace; + font-weight: bold; + margin: 0px; +} + +/* All views: header legend value for low rate */ +td.headerValueLegL +{ + font-family: sans-serif; + text-align: center; + white-space: nowrap; + padding-left: 4px; + padding-right: 2px; + background-color: #FF0000; + font-size: 80%; +} + +/* All views: header legend value for med rate */ +td.headerValueLegM +{ + font-family: sans-serif; + text-align: center; + white-space: nowrap; + padding-left: 2px; + padding-right: 2px; + background-color: #FFEA20; + font-size: 80%; +} + +/* All views: header legend value for hi rate */ +td.headerValueLegH +{ + font-family: sans-serif; + text-align: center; + white-space: nowrap; + padding-left: 2px; + padding-right: 4px; + background-color: #A7FC9D; + font-size: 80%; +} + +/* All views except source code view: legend format for low coverage */ +span.coverLegendCovLo +{ + padding-left: 10px; + padding-right: 10px; + padding-top: 2px; + background-color: #FF0000; +} + +/* All views except source code view: legend format for med coverage */ +span.coverLegendCovMed +{ + padding-left: 10px; + padding-right: 10px; + padding-top: 2px; + background-color: #FFEA20; +} + +/* All views except source code view: legend format for hi coverage */ +span.coverLegendCovHi +{ + padding-left: 10px; + padding-right: 10px; + padding-top: 2px; + background-color: #A7FC9D; +} diff --git a/static/samples_rust_coverage/grcov_lcov/glass.png b/static/samples_rust_coverage/grcov_lcov/glass.png new file mode 100644 index 0000000000000000000000000000000000000000..e1abc00680a3093c49fdb775ae6bdb6764c95af2 GIT binary patch literal 167 zcmeAS@N?(olHy`uVBq!ia0vp^j3CU&3?x-=hn)gaEa{HEjtmSN`?>!lvI6;R0X`wF z|Ns97GD8ntt^-nxB|(0{3=Yq3q=7g|-tI089jvk*Kn`btM`SSr1Gf+eGhVt|_XjA* zUgGKN%6^Gmn4d%Ph(nkFP>9RZ#WAE}PI3Z}&BVayv3^M*kj3EX>gTe~DWM4f=_Dpv literal 0 HcmV?d00001 diff --git a/static/samples_rust_coverage/grcov_lcov/index-sort-f.html b/static/samples_rust_coverage/grcov_lcov/index-sort-f.html new file mode 100644 index 00000000..4d6ce7e3 --- /dev/null +++ b/static/samples_rust_coverage/grcov_lcov/index-sort-f.html @@ -0,0 +1,102 @@ + + + + + + + LCOV - lcov + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top levelHitTotalCoverage
Test:lcovLines:636794.0 %
Date:2024-01-12 19:04:52Functions:1818100.0 %
Legend: Rating: + low: < 75 % + medium: >= 75 % + high: >= 90 % +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Directory Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
src +
94.0%94.0%
+
94.0 %63 / 67100.0 %18 / 18
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/static/samples_rust_coverage/grcov_lcov/index-sort-l.html b/static/samples_rust_coverage/grcov_lcov/index-sort-l.html new file mode 100644 index 00000000..9e74ae27 --- /dev/null +++ b/static/samples_rust_coverage/grcov_lcov/index-sort-l.html @@ -0,0 +1,102 @@ + + + + + + + LCOV - lcov + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top levelHitTotalCoverage
Test:lcovLines:636794.0 %
Date:2024-01-12 19:04:52Functions:1818100.0 %
Legend: Rating: + low: < 75 % + medium: >= 75 % + high: >= 90 % +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Directory Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
src +
94.0%94.0%
+
94.0 %63 / 67100.0 %18 / 18
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/static/samples_rust_coverage/grcov_lcov/index.html b/static/samples_rust_coverage/grcov_lcov/index.html new file mode 100644 index 00000000..b01ea368 --- /dev/null +++ b/static/samples_rust_coverage/grcov_lcov/index.html @@ -0,0 +1,102 @@ + + + + + + + LCOV - lcov + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top levelHitTotalCoverage
Test:lcovLines:636794.0 %
Date:2024-01-12 19:04:52Functions:1818100.0 %
Legend: Rating: + low: < 75 % + medium: >= 75 % + high: >= 90 % +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Directory Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
src +
94.0%94.0%
+
94.0 %63 / 67100.0 %18 / 18
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/static/samples_rust_coverage/grcov_lcov/lcov b/static/samples_rust_coverage/grcov_lcov/lcov new file mode 100644 index 00000000..c5aee163 --- /dev/null +++ b/static/samples_rust_coverage/grcov_lcov/lcov @@ -0,0 +1,182 @@ +TN: +SF:src/main.rs +FN:11,tmp::validate_data_match +FN:76,tmp::tests::check_match +FN:76,tmp::tests::check_match::{{closure}} +FN:31,tmp::largest +FN:31,tmp::largest +FN:41,tmp::validate_data_generics +FN:3,tmp::main +FN:41,tmp::validate_data_generics +FN:103,tmp::tests::check_not_panic::{{closure}} +FN:31,tmp::largest +FN:31,tmp::largest +FN:68,tmp::tests::parser_detects_errors +FN:90,tmp::tests::check_generic::{{closure}} +FN:11,tmp::validate_data_match +FN:97,tmp::tests::check_panic::{{closure}} +FN:103,tmp::tests::check_not_panic +FN:1,tmp::main +FN:83,tmp::tests::check_match2 +FN:31,tmp::largest +FN:5,tmp::validate_data_simple +FN:5,tmp::validate_data_simple +FN:3,tmp::main +FN:31,tmp::largest +FN:97,tmp::tests::check_panic +FN:90,tmp::tests::check_generic +FN:83,tmp::tests::check_match2::{{closure}} +FN:68,tmp::tests::parser_detects_errors::{{closure}} +FNDA:0,tmp::validate_data_match +FNDA:1,tmp::tests::check_match +FNDA:1,tmp::tests::check_match::{{closure}} +FNDA:0,tmp::largest +FNDA:1,tmp::largest +FNDA:0,tmp::validate_data_generics +FNDA:0,tmp::main +FNDA:1,tmp::validate_data_generics +FNDA:1,tmp::tests::check_not_panic::{{closure}} +FNDA:1,tmp::largest +FNDA:0,tmp::largest +FNDA:1,tmp::tests::parser_detects_errors +FNDA:1,tmp::tests::check_generic::{{closure}} +FNDA:1,tmp::validate_data_match +FNDA:1,tmp::tests::check_panic::{{closure}} +FNDA:1,tmp::tests::check_not_panic +FNDA:1,tmp::main +FNDA:1,tmp::tests::check_match2 +FNDA:1,tmp::largest +FNDA:0,tmp::validate_data_simple +FNDA:1,tmp::validate_data_simple +FNDA:0,tmp::main +FNDA:0,tmp::largest +FNDA:1,tmp::tests::check_panic +FNDA:1,tmp::tests::check_generic +FNDA:1,tmp::tests::check_match2::{{closure}} +FNDA:1,tmp::tests::parser_detects_errors::{{closure}} +FNF:27 +FNH:19 +BRDA:6,0,0,1 +BRDA:6,0,1,- +BRDA:7,0,0,- +BRDA:7,0,1,- +BRDA:12,0,0,1 +BRDA:12,0,1,1 +BRDA:15,0,0,1 +BRDA:15,0,1,- +BRDA:23,0,0,1 +BRDA:23,0,1,1 +BRDA:32,0,0,1 +BRDA:32,0,1,- +BRDA:32,0,2,1 +BRDA:32,0,3,- +BRDA:32,0,4,1 +BRDA:32,0,5,- +BRDA:33,0,0,1 +BRDA:33,0,1,1 +BRDA:33,0,2,1 +BRDA:33,0,3,1 +BRDA:33,0,4,1 +BRDA:33,0,5,1 +BRDA:34,0,0,1 +BRDA:34,0,1,- +BRDA:34,0,2,1 +BRDA:34,0,3,1 +BRDA:34,0,4,1 +BRDA:34,0,5,1 +BRDA:42,0,0,1 +BRDA:42,0,1,- +BRDA:47,0,0,1 +BRDA:47,0,1,- +BRDA:72,0,0,- +BRDA:72,0,1,1 +BRDA:79,0,0,- +BRDA:79,0,1,1 +BRDA:86,0,0,- +BRDA:86,0,1,1 +BRF:38 +BRH:25 +DA:1,8 +DA:3,0 +DA:5,1 +DA:6,1 +DA:7,0 +DA:8,0 +DA:9,1 +DA:11,2 +DA:12,2 +DA:13,1 +DA:14,1 +DA:15,1 +DA:16,0 +DA:18,1 +DA:21,1 +DA:23,2 +DA:24,1 +DA:26,1 +DA:28,2 +DA:31,3 +DA:32,3 +DA:33,15 +DA:34,12 +DA:35,3 +DA:38,3 +DA:39,3 +DA:41,1 +DA:42,1 +DA:44,1 +DA:45,1 +DA:47,1 +DA:49,1 +DA:50,1 +DA:52,1 +DA:53,1 +DA:54,1 +DA:68,2 +DA:69,1 +DA:70,1 +DA:71,1 +DA:72,1 +DA:73,2 +DA:76,2 +DA:77,1 +DA:78,1 +DA:79,1 +DA:80,2 +DA:83,2 +DA:84,1 +DA:85,1 +DA:86,1 +DA:87,2 +DA:90,2 +DA:91,1 +DA:92,1 +DA:93,2 +DA:97,2 +DA:98,1 +DA:99,1 +DA:100,2 +DA:103,2 +DA:104,1 +DA:105,1 +DA:106,2 +LF:64 +LH:60 +end_of_record +SF:src/second.rs +FN:3,tmp::second::validate_data_panic +FN:3,tmp::second::validate_data_panic +FNDA:0,tmp::second::validate_data_panic +FNDA:1,tmp::second::validate_data_panic +FNF:2 +FNH:1 +BRDA:4,0,0,1 +BRDA:4,0,1,1 +BRF:2 +BRH:2 +DA:3,2 +DA:4,2 +DA:5,1 +LF:3 +LH:3 +end_of_record diff --git a/static/samples_rust_coverage/grcov_lcov/ruby.png b/static/samples_rust_coverage/grcov_lcov/ruby.png new file mode 100644 index 0000000000000000000000000000000000000000..991b6d4ec9e78be165e3ef757eed1aada287364d GIT binary patch literal 141 zcmeAS@N?(olHy`uVBq!ia0vp^j3CU&3?x-=hn)ga>?NMQuI!iC1^FceV#7`HfI^%F z9+AZi4BSE>%y{W;-5;PJOS+@4BLl<6e(pbstUx|nfKQ0)e^Y%R^MdiLxj>4`)5S5Q b;#P73kj=!v_*DHKNFRfztDnm{r-UW|iOwIS literal 0 HcmV?d00001 diff --git a/static/samples_rust_coverage/grcov_lcov/snow.png b/static/samples_rust_coverage/grcov_lcov/snow.png new file mode 100644 index 0000000000000000000000000000000000000000..2cdae107fceec6e7f02ac7acb4a34a82a540caa5 GIT binary patch literal 141 zcmeAS@N?(olHy`uVBq!ia0vp^j3CU&3?x-=hn)ga>?NMQuI!iC1^MM!lvI6;R0X`wF|Ns97GD8ntt^-nBo-U3d c6}OTTfNUlP#;5A{K>8RwUHx3vIVCg!071?oo&W#< literal 0 HcmV?d00001 diff --git a/static/samples_rust_coverage/grcov_lcov/src/index-detail-sort-f.html b/static/samples_rust_coverage/grcov_lcov/src/index-detail-sort-f.html new file mode 100644 index 00000000..4eaa6b6b --- /dev/null +++ b/static/samples_rust_coverage/grcov_lcov/src/index-detail-sort-f.html @@ -0,0 +1,128 @@ + + + + + + + LCOV - lcov - src + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - srcHitTotalCoverage
Test:lcovLines:636794.0 %
Date:2024-01-12 19:04:52Functions:1818100.0 %
Legend: Rating: + low: < 75 % + medium: >= 75 % + high: >= 90 % +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage ( hide details ) Sort by line coverageFunctions Sort by function coverage
second.rs +
100.0%
+
100.0 %3 / 3100.0 %1 / 1
<unnamed>100.0 %3 / 3100.0 %1 / 1
main.rs +
93.8%93.8%
+
93.8 %60 / 64100.0 %17 / 17
<unnamed>93.8 %60 / 64100.0 %17 / 17
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/static/samples_rust_coverage/grcov_lcov/src/index-detail-sort-l.html b/static/samples_rust_coverage/grcov_lcov/src/index-detail-sort-l.html new file mode 100644 index 00000000..d60b3dc4 --- /dev/null +++ b/static/samples_rust_coverage/grcov_lcov/src/index-detail-sort-l.html @@ -0,0 +1,128 @@ + + + + + + + LCOV - lcov - src + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - srcHitTotalCoverage
Test:lcovLines:636794.0 %
Date:2024-01-12 19:04:52Functions:1818100.0 %
Legend: Rating: + low: < 75 % + medium: >= 75 % + high: >= 90 % +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage ( hide details ) Sort by line coverageFunctions Sort by function coverage
main.rs +
93.8%93.8%
+
93.8 %60 / 64100.0 %17 / 17
<unnamed>93.8 %60 / 64100.0 %17 / 17
second.rs +
100.0%
+
100.0 %3 / 3100.0 %1 / 1
<unnamed>100.0 %3 / 3100.0 %1 / 1
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/static/samples_rust_coverage/grcov_lcov/src/index-detail.html b/static/samples_rust_coverage/grcov_lcov/src/index-detail.html new file mode 100644 index 00000000..f1629cb2 --- /dev/null +++ b/static/samples_rust_coverage/grcov_lcov/src/index-detail.html @@ -0,0 +1,128 @@ + + + + + + + LCOV - lcov - src + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - srcHitTotalCoverage
Test:lcovLines:636794.0 %
Date:2024-01-12 19:04:52Functions:1818100.0 %
Legend: Rating: + low: < 75 % + medium: >= 75 % + high: >= 90 % +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage ( hide details ) Sort by line coverageFunctions Sort by function coverage
main.rs +
93.8%93.8%
+
93.8 %60 / 64100.0 %17 / 17
<unnamed>93.8 %60 / 64100.0 %17 / 17
second.rs +
100.0%
+
100.0 %3 / 3100.0 %1 / 1
<unnamed>100.0 %3 / 3100.0 %1 / 1
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/static/samples_rust_coverage/grcov_lcov/src/index-sort-f.html b/static/samples_rust_coverage/grcov_lcov/src/index-sort-f.html new file mode 100644 index 00000000..7cb1bf00 --- /dev/null +++ b/static/samples_rust_coverage/grcov_lcov/src/index-sort-f.html @@ -0,0 +1,112 @@ + + + + + + + LCOV - lcov - src + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - srcHitTotalCoverage
Test:lcovLines:636794.0 %
Date:2024-01-12 19:04:52Functions:1818100.0 %
Legend: Rating: + low: < 75 % + medium: >= 75 % + high: >= 90 % +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage ( show details ) Sort by line coverageFunctions Sort by function coverage
second.rs +
100.0%
+
100.0 %3 / 3100.0 %1 / 1
main.rs +
93.8%93.8%
+
93.8 %60 / 64100.0 %17 / 17
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/static/samples_rust_coverage/grcov_lcov/src/index-sort-l.html b/static/samples_rust_coverage/grcov_lcov/src/index-sort-l.html new file mode 100644 index 00000000..d659e9e6 --- /dev/null +++ b/static/samples_rust_coverage/grcov_lcov/src/index-sort-l.html @@ -0,0 +1,112 @@ + + + + + + + LCOV - lcov - src + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - srcHitTotalCoverage
Test:lcovLines:636794.0 %
Date:2024-01-12 19:04:52Functions:1818100.0 %
Legend: Rating: + low: < 75 % + medium: >= 75 % + high: >= 90 % +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage ( show details ) Sort by line coverageFunctions Sort by function coverage
main.rs +
93.8%93.8%
+
93.8 %60 / 64100.0 %17 / 17
second.rs +
100.0%
+
100.0 %3 / 3100.0 %1 / 1
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/static/samples_rust_coverage/grcov_lcov/src/index.html b/static/samples_rust_coverage/grcov_lcov/src/index.html new file mode 100644 index 00000000..2f58aed9 --- /dev/null +++ b/static/samples_rust_coverage/grcov_lcov/src/index.html @@ -0,0 +1,112 @@ + + + + + + + LCOV - lcov - src + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - srcHitTotalCoverage
Test:lcovLines:636794.0 %
Date:2024-01-12 19:04:52Functions:1818100.0 %
Legend: Rating: + low: < 75 % + medium: >= 75 % + high: >= 90 % +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage ( show details ) Sort by line coverageFunctions Sort by function coverage
main.rs +
93.8%93.8%
+
93.8 %60 / 64100.0 %17 / 17
second.rs +
100.0%
+
100.0 %3 / 3100.0 %1 / 1
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/static/samples_rust_coverage/grcov_lcov/src/main.rs.func-sort-c.html b/static/samples_rust_coverage/grcov_lcov/src/main.rs.func-sort-c.html new file mode 100644 index 00000000..abdc9280 --- /dev/null +++ b/static/samples_rust_coverage/grcov_lcov/src/main.rs.func-sort-c.html @@ -0,0 +1,148 @@ + + + + + + + LCOV - lcov - src/main.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - src - main.rs (source / functions)HitTotalCoverage
Test:lcovLines:606493.8 %
Date:2024-01-12 19:04:52Functions:1717100.0 %
Legend: Lines: + hit + not hit +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
tmp::main1
tmp::tests::check_generic1
tmp::tests::check_generic::{{closure}}1
tmp::tests::check_match1
tmp::tests::check_match21
tmp::tests::check_match2::{{closure}}1
tmp::tests::check_match::{{closure}}1
tmp::tests::check_not_panic1
tmp::tests::check_not_panic::{{closure}}1
tmp::tests::check_panic1
tmp::tests::check_panic::{{closure}}1
tmp::tests::parser_detects_errors1
tmp::tests::parser_detects_errors::{{closure}}1
tmp::validate_data_generics1
tmp::validate_data_match1
tmp::validate_data_simple1
tmp::largest3
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/static/samples_rust_coverage/grcov_lcov/src/main.rs.func.html b/static/samples_rust_coverage/grcov_lcov/src/main.rs.func.html new file mode 100644 index 00000000..ace030f9 --- /dev/null +++ b/static/samples_rust_coverage/grcov_lcov/src/main.rs.func.html @@ -0,0 +1,148 @@ + + + + + + + LCOV - lcov - src/main.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - src - main.rs (source / functions)HitTotalCoverage
Test:lcovLines:606493.8 %
Date:2024-01-12 19:04:52Functions:1717100.0 %
Legend: Lines: + hit + not hit +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
tmp::largest3
tmp::main1
tmp::tests::check_generic1
tmp::tests::check_generic::{{closure}}1
tmp::tests::check_match1
tmp::tests::check_match21
tmp::tests::check_match2::{{closure}}1
tmp::tests::check_match::{{closure}}1
tmp::tests::check_not_panic1
tmp::tests::check_not_panic::{{closure}}1
tmp::tests::check_panic1
tmp::tests::check_panic::{{closure}}1
tmp::tests::parser_detects_errors1
tmp::tests::parser_detects_errors::{{closure}}1
tmp::validate_data_generics1
tmp::validate_data_match1
tmp::validate_data_simple1
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/static/samples_rust_coverage/grcov_lcov/src/main.rs.gcov.html b/static/samples_rust_coverage/grcov_lcov/src/main.rs.gcov.html new file mode 100644 index 00000000..50fbfa4a --- /dev/null +++ b/static/samples_rust_coverage/grcov_lcov/src/main.rs.gcov.html @@ -0,0 +1,191 @@ + + + + + + + LCOV - lcov - src/main.rs + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - src - main.rs (source / functions)HitTotalCoverage
Test:lcovLines:606493.8 %
Date:2024-01-12 19:04:52Functions:1717100.0 %
Legend: Lines: + hit + not hit +
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1           8 : mod second;
+       2             : 
+       3           0 : fn main() { println!("Hello, world!"); }
+       4             : 
+       5           1 : fn validate_data_simple(data: &Data) -> Result<(), ()> {
+       6           1 :     if !data.magic.eq(&[0x13, 0x37]) { return Err(()) }
+       7           0 :     if data.len as usize != data.content.len() { return Err(()) }
+       8           0 :     return Ok(());
+       9           1 : }
+      10             : 
+      11           2 : fn validate_data_match(data: &Data) -> i32 {
+      12           2 :     let x: u32 = match data.content.parse::<u32>() {
+      13           1 :         Ok(_x) => {
+      14           1 :             let y = 2 * _x;
+      15           1 :             if y < 6 {
+      16           0 :                 y
+      17             :             } else {
+      18           1 :                 y * 2
+      19             :             }
+      20             :         }
+      21           1 :         Err(_) => 0
+      22             :     };
+      23           2 :     if x == 0 {
+      24           1 :         -1
+      25             :     } else {
+      26           1 :         (x as i32) + 1
+      27             :     }
+      28           2 : }
+      29             : 
+      30             : // https://doc.rust-lang.org/book/ch10-01-syntax.html
+      31           3 : fn largest<T: PartialOrd>(list: &[T]) -> &T {
+      32           3 :     let mut largest = &list[0];
+      33          15 :     for item in list {
+      34          12 :         if item > largest {
+      35           3 :             largest = item;
+      36             :         }
+      37             :     }
+      38           3 :     largest
+      39           3 : }
+      40             : 
+      41           1 : fn validate_data_generics(data: &Data) {
+      42           1 :     let number_list = vec![34, 50, 25, 100, 65];
+      43             : 
+      44           1 :     let result = largest(&number_list);
+      45           1 :     println!("The largest number is {}", result);
+      46             : 
+      47           1 :     let char_list = vec!['y', 'm', 'a', 'q'];
+      48             : 
+      49           1 :     let result = largest(&char_list);
+      50           1 :     println!("The largest char is {}", result);
+      51             : 
+      52           1 :     let result = largest(data.content.as_bytes());
+      53           1 :     println!("The largest content char is {}", result);
+      54           1 : }
+      55             : 
+      56             : struct Data {
+      57             :     magic: [u8; 2],
+      58             :     len: u8,
+      59             :     content: String
+      60             : }
+      61             : 
+      62             : #[cfg(test)]
+      63             : mod tests {
+      64             :     use crate::second::validate_data_panic;
+      65             :     use crate::{Data, validate_data_generics, validate_data_match, validate_data_simple};
+      66             : 
+      67             :     #[test]
+      68           2 :     fn parser_detects_errors() {
+      69           1 :         let mut blob = Data{ magic: [0x73, 0x31], len: 2, content: "AB".parse().unwrap() };
+      70           1 :         blob.content = blob.content + "Y";
+      71           1 :         let result = validate_data_simple(&blob);
+      72           1 :         assert!(result.is_err());
+      73           2 :     }
+      74             : 
+      75             :     #[test]
+      76           2 :     fn check_match() {
+      77           1 :         let blob = Data{ magic: [0x73, 0x31], len: 2, content: "XX".parse().unwrap() };
+      78           1 :         let x = validate_data_match(&blob);
+      79           1 :         assert_eq!(x, -1);
+      80           2 :     }
+      81             : 
+      82             :     #[test]
+      83           2 :     fn check_match2() {
+      84           1 :         let blob = Data{ magic: [0x73, 0x31], len: 2, content: "40".parse().unwrap() };
+      85           1 :         let x = validate_data_match(&blob);
+      86           1 :         assert_eq!(x, 161);
+      87           2 :     }
+      88             : 
+      89             :     #[test]
+      90           2 :     fn check_generic() {
+      91           1 :         let blob = Data{ magic: [0x73, 0x31], len: 2, content: "QWE".parse().unwrap() };
+      92           1 :         validate_data_generics(&blob);
+      93           2 :     }
+      94             : 
+      95             :     #[test]
+      96             :     #[should_panic]
+      97           2 :     fn check_panic() {
+      98           1 :         let blob = Data{ magic: [0x73, 0x31], len: 0, content: "4".parse().unwrap() };
+      99           1 :         validate_data_panic(&blob);
+     100           2 :     }
+     101             : 
+     102             :     #[test]
+     103           2 :     fn check_not_panic() {
+     104           1 :         let blob = Data{ magic: [0x73, 0x31], len: 2, content: "4".parse().unwrap() };
+     105           1 :         validate_data_panic(&blob);
+     106           2 :     }
+     107             : }
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/static/samples_rust_coverage/grcov_lcov/src/second.rs.func-sort-c.html b/static/samples_rust_coverage/grcov_lcov/src/second.rs.func-sort-c.html new file mode 100644 index 00000000..aa01274d --- /dev/null +++ b/static/samples_rust_coverage/grcov_lcov/src/second.rs.func-sort-c.html @@ -0,0 +1,84 @@ + + + + + + + LCOV - lcov - src/second.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - src - second.rs (source / functions)HitTotalCoverage
Test:lcovLines:33100.0 %
Date:2024-01-12 19:04:52Functions:11100.0 %
Legend: Lines: + hit + not hit +
+
+ +
+ + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
tmp::second::validate_data_panic1
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/static/samples_rust_coverage/grcov_lcov/src/second.rs.func.html b/static/samples_rust_coverage/grcov_lcov/src/second.rs.func.html new file mode 100644 index 00000000..a1c3f0d4 --- /dev/null +++ b/static/samples_rust_coverage/grcov_lcov/src/second.rs.func.html @@ -0,0 +1,84 @@ + + + + + + + LCOV - lcov - src/second.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - src - second.rs (source / functions)HitTotalCoverage
Test:lcovLines:33100.0 %
Date:2024-01-12 19:04:52Functions:11100.0 %
Legend: Lines: + hit + not hit +
+
+ +
+ + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
tmp::second::validate_data_panic1
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/static/samples_rust_coverage/grcov_lcov/src/second.rs.gcov.html b/static/samples_rust_coverage/grcov_lcov/src/second.rs.gcov.html new file mode 100644 index 00000000..59d584f0 --- /dev/null +++ b/static/samples_rust_coverage/grcov_lcov/src/second.rs.gcov.html @@ -0,0 +1,91 @@ + + + + + + + LCOV - lcov - src/second.rs + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - src - second.rs (source / functions)HitTotalCoverage
Test:lcovLines:33100.0 %
Date:2024-01-12 19:04:52Functions:11100.0 %
Legend: Lines: + hit + not hit +
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : use crate::Data;
+       2             : 
+       3           2 : pub(crate) fn validate_data_panic(data: &Data) {
+       4           2 :     if data.len == 0 {
+       5           1 :         panic!("panic")
+       6             :     }
+       7             : }
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/static/samples_rust_coverage/grcov_lcov/updown.png b/static/samples_rust_coverage/grcov_lcov/updown.png new file mode 100644 index 0000000000000000000000000000000000000000..aa56a238b3e6c435265250f9266cd1b8caba0f20 GIT binary patch literal 117 zcmeAS@N?(olHy`uVBq!ia0vp^AT}Qd8;}%R+`Ae`*?77*hG?8mPH5^{)z4*}Q$iB}huR`+ literal 0 HcmV?d00001 diff --git a/static/samples_rust_coverage/grcov_llvm/badges/flat.svg b/static/samples_rust_coverage/grcov_llvm/badges/flat.svg new file mode 100644 index 00000000..03e135bf --- /dev/null +++ b/static/samples_rust_coverage/grcov_llvm/badges/flat.svg @@ -0,0 +1,23 @@ + + coverage: 94% + + + + + + + + + + + + + + + coverage + + 94% + + + \ No newline at end of file diff --git a/static/samples_rust_coverage/grcov_llvm/badges/flat_square.svg b/static/samples_rust_coverage/grcov_llvm/badges/flat_square.svg new file mode 100644 index 00000000..b7a4567a --- /dev/null +++ b/static/samples_rust_coverage/grcov_llvm/badges/flat_square.svg @@ -0,0 +1,13 @@ + + coverage: 94% + + + + + + coverage + 94% + + + \ No newline at end of file diff --git a/static/samples_rust_coverage/grcov_llvm/badges/for_the_badge.svg b/static/samples_rust_coverage/grcov_llvm/badges/for_the_badge.svg new file mode 100644 index 00000000..70b55d30 --- /dev/null +++ b/static/samples_rust_coverage/grcov_llvm/badges/for_the_badge.svg @@ -0,0 +1,13 @@ + + COVERAGE: 94% + + + + + + COVERAGE + 94% + + + \ No newline at end of file diff --git a/static/samples_rust_coverage/grcov_llvm/badges/plastic.svg b/static/samples_rust_coverage/grcov_llvm/badges/plastic.svg new file mode 100644 index 00000000..c84a8cee --- /dev/null +++ b/static/samples_rust_coverage/grcov_llvm/badges/plastic.svg @@ -0,0 +1,25 @@ + + coverage: 94% + + + + + + + + + + + + + + + + + coverage + + 94% + + + \ No newline at end of file diff --git a/static/samples_rust_coverage/grcov_llvm/badges/social.svg b/static/samples_rust_coverage/grcov_llvm/badges/social.svg new file mode 100644 index 00000000..da39da47 --- /dev/null +++ b/static/samples_rust_coverage/grcov_llvm/badges/social.svg @@ -0,0 +1,27 @@ + + Coverage: 94% + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/static/samples_rust_coverage/grcov_llvm/coverage.json b/static/samples_rust_coverage/grcov_llvm/coverage.json new file mode 100644 index 00000000..4d62a96b --- /dev/null +++ b/static/samples_rust_coverage/grcov_llvm/coverage.json @@ -0,0 +1 @@ +{"schemaVersion":1,"label":"coverage","message":"94.94%","color":"green"} \ No newline at end of file diff --git a/static/samples_rust_coverage/grcov_llvm/index.html b/static/samples_rust_coverage/grcov_llvm/index.html new file mode 100644 index 00000000..9d59da38 --- /dev/null +++ b/static/samples_rust_coverage/grcov_llvm/index.html @@ -0,0 +1,88 @@ + + + + + Grcov report - top_level + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DirectoryLine CoverageFunctionsBranches
src + + 94.94% + + + 94.94% + + 75 / 79 + 73.08%19 / 26 100%0 / 0
+
+
+

Date: 2024-01-12 19:04

+
+
+ + diff --git a/static/samples_rust_coverage/grcov_llvm/src/index.html b/static/samples_rust_coverage/grcov_llvm/src/index.html new file mode 100644 index 00000000..6ebdea76 --- /dev/null +++ b/static/samples_rust_coverage/grcov_llvm/src/index.html @@ -0,0 +1,115 @@ + + + + + Grcov report - src + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileLine CoverageFunctionsBranches
main.rs + + 94.59% + + + 94.59% + + 70 / 74 + 75%18 / 24 100%0 / 0
second.rs + + 100% + + + 100% + + 5 / 5 + 50%1 / 2 100%0 / 0
+
+
+

Date: 2024-01-12 19:04

+
+
+ + diff --git a/static/samples_rust_coverage/grcov_llvm/src/main.rs.html b/static/samples_rust_coverage/grcov_llvm/src/main.rs.html new file mode 100644 index 00000000..f7698c96 --- /dev/null +++ b/static/samples_rust_coverage/grcov_llvm/src/main.rs.html @@ -0,0 +1,1762 @@ + + + + + Grcov report - main.rs + + +
+ + + +
+
+ 1 +
+
+ +
+
+
mod second;
+
+
+
+ 2 +
+
+ +
+
+

+            
+
+
+ 3 +
+
+ +
+
+
fn main() { println!("Hello, world!"); }
+
+
+
+ 4 +
+
+ +
+
+

+            
+
+
+ 5 +
+
+ 2 +
+
+
fn validate_data_simple(data: &Data) -> Result<(), ()> {
+
+
+
+ 6 +
+
+ 2 +
+
+
    if !data.magic.eq(&[0x13, 0x37]) { return Err(()) }
+
+
+
+ 7 +
+
+ +
+
+
    if data.len as usize != data.content.len() { return Err(()) }
+
+
+
+ 8 +
+
+ +
+
+
    return Ok(());
+
+
+
+ 9 +
+
+ 2 +
+
+
}
+
+
+
+ 10 +
+
+ +
+
+

+            
+
+
+ 11 +
+
+ 4 +
+
+
fn validate_data_match(data: &Data) -> i32 {
+
+
+
+ 12 +
+
+ 4 +
+
+
    let x: u32 = match data.content.parse::<u32>() {
+
+
+
+ 13 +
+
+ 2 +
+
+
        Ok(_x) => {
+
+
+
+ 14 +
+
+ 2 +
+
+
            let y = 2 * _x;
+
+
+
+ 15 +
+
+ 2 +
+
+
            if y < 6 {
+
+
+
+ 16 +
+
+ +
+
+
                y
+
+
+
+ 17 +
+
+ +
+
+
            } else {
+
+
+
+ 18 +
+
+ 2 +
+
+
                y * 2
+
+
+
+ 19 +
+
+ +
+
+
            }
+
+
+
+ 20 +
+
+ +
+
+
        }
+
+
+
+ 21 +
+
+ 2 +
+
+
        Err(_) => 0
+
+
+
+ 22 +
+
+ +
+
+
    };
+
+
+
+ 23 +
+
+ 4 +
+
+
    if x == 0 {
+
+
+
+ 24 +
+
+ 2 +
+
+
        -1
+
+
+
+ 25 +
+
+ +
+
+
    } else {
+
+
+
+ 26 +
+
+ 2 +
+
+
        (x as i32) + 1
+
+
+
+ 27 +
+
+ +
+
+
    }
+
+
+
+ 28 +
+
+ 4 +
+
+
}
+
+
+
+ 29 +
+
+ +
+
+

+            
+
+
+ 30 +
+
+ +
+
+
// https://doc.rust-lang.org/book/ch10-01-syntax.html
+
+
+
+ 31 +
+
+ 6 +
+
+
fn largest<T: PartialOrd>(list: &[T]) -> &T {
+
+
+
+ 32 +
+
+ 6 +
+
+
    let mut largest = &list[0];
+
+
+
+ 33 +
+
+ 30 +
+
+
    for item in list {
+
+
+
+ 34 +
+
+ 24 +
+
+
        if item > largest {
+
+
+
+ 35 +
+
+ 6 +
+
+
            largest = item;
+
+
+
+ 36 +
+
+ 18 +
+
+
        }
+
+
+
+ 37 +
+
+ +
+
+
    }
+
+
+
+ 38 +
+
+ 6 +
+
+
    largest
+
+
+
+ 39 +
+
+ 6 +
+
+
}
+
+
+
+ 40 +
+
+ +
+
+

+            
+
+
+ 41 +
+
+ 2 +
+
+
fn validate_data_generics(data: &Data) {
+
+
+
+ 42 +
+
+ 2 +
+
+
    let number_list = vec![34, 50, 25, 100, 65];
+
+
+
+ 43 +
+
+ 2 +
+
+

+            
+
+
+ 44 +
+
+ 2 +
+
+
    let result = largest(&number_list);
+
+
+
+ 45 +
+
+ 2 +
+
+
    println!("The largest number is {}", result);
+
+
+
+ 46 +
+
+ 2 +
+
+

+            
+
+
+ 47 +
+
+ 2 +
+
+
    let char_list = vec!['y', 'm', 'a', 'q'];
+
+
+
+ 48 +
+
+ 2 +
+
+

+            
+
+
+ 49 +
+
+ 2 +
+
+
    let result = largest(&char_list);
+
+
+
+ 50 +
+
+ 2 +
+
+
    println!("The largest char is {}", result);
+
+
+
+ 51 +
+
+ 2 +
+
+

+            
+
+
+ 52 +
+
+ 2 +
+
+
    let result = largest(data.content.as_bytes());
+
+
+
+ 53 +
+
+ 2 +
+
+
    println!("The largest content char is {}", result);
+
+
+
+ 54 +
+
+ 2 +
+
+
}
+
+
+
+ 55 +
+
+ +
+
+

+            
+
+
+ 56 +
+
+ +
+
+
struct Data {
+
+
+
+ 57 +
+
+ +
+
+
    magic: [u8; 2],
+
+
+
+ 58 +
+
+ +
+
+
    len: u8,
+
+
+
+ 59 +
+
+ +
+
+
    content: String
+
+
+
+ 60 +
+
+ +
+
+
}
+
+
+
+ 61 +
+
+ +
+
+

+            
+
+
+ 62 +
+
+ +
+
+
#[cfg(test)]
+
+
+
+ 63 +
+
+ +
+
+
mod tests {
+
+
+
+ 64 +
+
+ +
+
+
    use crate::second::validate_data_panic;
+
+
+
+ 65 +
+
+ +
+
+
    use crate::{Data, validate_data_generics, validate_data_match, validate_data_simple};
+
+
+
+ 66 +
+
+ +
+
+

+            
+
+
+ 67 +
+
+ 2 +
+
+
    #[test]
+
+
+
+ 68 +
+
+ 2 +
+
+
    fn parser_detects_errors() {
+
+
+
+ 69 +
+
+ 2 +
+
+
        let mut blob = Data{ magic: [0x73, 0x31], len: 2, content: "AB".parse().unwrap() };
+
+
+
+ 70 +
+
+ 2 +
+
+
        blob.content = blob.content + "Y";
+
+
+
+ 71 +
+
+ 2 +
+
+
        let result = validate_data_simple(&blob);
+
+
+
+ 72 +
+
+ 2 +
+
+
        assert!(result.is_err());
+
+
+
+ 73 +
+
+ 2 +
+
+
    }
+
+
+
+ 74 +
+
+ +
+
+

+            
+
+
+ 75 +
+
+ 2 +
+
+
    #[test]
+
+
+
+ 76 +
+
+ 2 +
+
+
    fn check_match() {
+
+
+
+ 77 +
+
+ 2 +
+
+
        let blob = Data{ magic: [0x73, 0x31], len: 2, content: "XX".parse().unwrap() };
+
+
+
+ 78 +
+
+ 2 +
+
+
        let x = validate_data_match(&blob);
+
+
+
+ 79 +
+
+ 2 +
+
+
        assert_eq!(x, -1);
+
+
+
+ 80 +
+
+ 2 +
+
+
    }
+
+
+
+ 81 +
+
+ +
+
+

+            
+
+
+ 82 +
+
+ 2 +
+
+
    #[test]
+
+
+
+ 83 +
+
+ 2 +
+
+
    fn check_match2() {
+
+
+
+ 84 +
+
+ 2 +
+
+
        let blob = Data{ magic: [0x73, 0x31], len: 2, content: "40".parse().unwrap() };
+
+
+
+ 85 +
+
+ 2 +
+
+
        let x = validate_data_match(&blob);
+
+
+
+ 86 +
+
+ 2 +
+
+
        assert_eq!(x, 161);
+
+
+
+ 87 +
+
+ 2 +
+
+
    }
+
+
+
+ 88 +
+
+ +
+
+

+            
+
+
+ 89 +
+
+ 2 +
+
+
    #[test]
+
+
+
+ 90 +
+
+ 2 +
+
+
    fn check_generic() {
+
+
+
+ 91 +
+
+ 2 +
+
+
        let blob = Data{ magic: [0x73, 0x31], len: 2, content: "QWE".parse().unwrap() };
+
+
+
+ 92 +
+
+ 2 +
+
+
        validate_data_generics(&blob);
+
+
+
+ 93 +
+
+ 2 +
+
+
    }
+
+
+
+ 94 +
+
+ +
+
+

+            
+
+
+ 95 +
+
+ 2 +
+
+
    #[test]
+
+
+
+ 96 +
+
+ +
+
+
    #[should_panic]
+
+
+
+ 97 +
+
+ 2 +
+
+
    fn check_panic() {
+
+
+
+ 98 +
+
+ 2 +
+
+
        let blob = Data{ magic: [0x73, 0x31], len: 0, content: "4".parse().unwrap() };
+
+
+
+ 99 +
+
+ 2 +
+
+
        validate_data_panic(&blob);
+
+
+
+ 100 +
+
+ 2 +
+
+
    }
+
+
+
+ 101 +
+
+ +
+
+

+            
+
+
+ 102 +
+
+ 2 +
+
+
    #[test]
+
+
+
+ 103 +
+
+ 2 +
+
+
    fn check_not_panic() {
+
+
+
+ 104 +
+
+ 2 +
+
+
        let blob = Data{ magic: [0x73, 0x31], len: 2, content: "4".parse().unwrap() };
+
+
+
+ 105 +
+
+ 2 +
+
+
        validate_data_panic(&blob);
+
+
+
+ 106 +
+
+ 2 +
+
+
    }
+
+
+
+ 107 +
+
+ +
+
+
}
+
+
+
+
+
+

Date: 2024-01-12 19:04

+
+
+ + diff --git a/static/samples_rust_coverage/grcov_llvm/src/second.rs.html b/static/samples_rust_coverage/grcov_llvm/src/second.rs.html new file mode 100644 index 00000000..069c1be5 --- /dev/null +++ b/static/samples_rust_coverage/grcov_llvm/src/second.rs.html @@ -0,0 +1,162 @@ + + + + + Grcov report - second.rs + + +
+ + + +
+
+ 1 +
+
+ +
+
+
use crate::Data;
+
+
+
+ 2 +
+
+ +
+
+

+            
+
+
+ 3 +
+
+ 4 +
+
+
pub(crate) fn validate_data_panic(data: &Data) {
+
+
+
+ 4 +
+
+ 4 +
+
+
    if data.len == 0 {
+
+
+
+ 5 +
+
+ 2 +
+
+
        panic!("panic")
+
+
+
+ 6 +
+
+ 2 +
+
+
    }
+
+
+
+ 7 +
+
+ 2 +
+
+
}
+
+
+
+
+
+

Date: 2024-01-12 19:04

+
+
+ + diff --git a/static/samples_rust_coverage/grcov_llvm_lcov/amber.png b/static/samples_rust_coverage/grcov_llvm_lcov/amber.png new file mode 100644 index 0000000000000000000000000000000000000000..2cab170d8359081983a4e343848dfe06bc490f12 GIT binary patch literal 141 zcmeAS@N?(olHy`uVBq!ia0vp^j3CU&3?x-=hn)ga>?NMQuI!iC1^G2tW}LqE04T&+ z;1OBOz`!j8!i<;h*8KqrvZOouIx;Y9?C1WI$O`1M1^9%x{(levWG?NMQuI!iC1^Jb!lvI6;R0X`wF(yt=9xVZRt1vCRixIA4P dLn>}1Cji+@42)0J?}79&c)I$ztaD0e0sy@GAL0N2 literal 0 HcmV?d00001 diff --git a/static/samples_rust_coverage/grcov_llvm_lcov/gcov.css b/static/samples_rust_coverage/grcov_llvm_lcov/gcov.css new file mode 100644 index 00000000..bfd0a83e --- /dev/null +++ b/static/samples_rust_coverage/grcov_llvm_lcov/gcov.css @@ -0,0 +1,519 @@ +/* All views: initial background and text color */ +body +{ + color: #000000; + background-color: #FFFFFF; +} + +/* All views: standard link format*/ +a:link +{ + color: #284FA8; + text-decoration: underline; +} + +/* All views: standard link - visited format */ +a:visited +{ + color: #00CB40; + text-decoration: underline; +} + +/* All views: standard link - activated format */ +a:active +{ + color: #FF0040; + text-decoration: underline; +} + +/* All views: main title format */ +td.title +{ + text-align: center; + padding-bottom: 10px; + font-family: sans-serif; + font-size: 20pt; + font-style: italic; + font-weight: bold; +} + +/* All views: header item format */ +td.headerItem +{ + text-align: right; + padding-right: 6px; + font-family: sans-serif; + font-weight: bold; + vertical-align: top; + white-space: nowrap; +} + +/* All views: header item value format */ +td.headerValue +{ + text-align: left; + color: #284FA8; + font-family: sans-serif; + font-weight: bold; + white-space: nowrap; +} + +/* All views: header item coverage table heading */ +td.headerCovTableHead +{ + text-align: center; + padding-right: 6px; + padding-left: 6px; + padding-bottom: 0px; + font-family: sans-serif; + font-size: 80%; + white-space: nowrap; +} + +/* All views: header item coverage table entry */ +td.headerCovTableEntry +{ + text-align: right; + color: #284FA8; + font-family: sans-serif; + font-weight: bold; + white-space: nowrap; + padding-left: 12px; + padding-right: 4px; + background-color: #DAE7FE; +} + +/* All views: header item coverage table entry for high coverage rate */ +td.headerCovTableEntryHi +{ + text-align: right; + color: #000000; + font-family: sans-serif; + font-weight: bold; + white-space: nowrap; + padding-left: 12px; + padding-right: 4px; + background-color: #A7FC9D; +} + +/* All views: header item coverage table entry for medium coverage rate */ +td.headerCovTableEntryMed +{ + text-align: right; + color: #000000; + font-family: sans-serif; + font-weight: bold; + white-space: nowrap; + padding-left: 12px; + padding-right: 4px; + background-color: #FFEA20; +} + +/* All views: header item coverage table entry for ow coverage rate */ +td.headerCovTableEntryLo +{ + text-align: right; + color: #000000; + font-family: sans-serif; + font-weight: bold; + white-space: nowrap; + padding-left: 12px; + padding-right: 4px; + background-color: #FF0000; +} + +/* All views: header legend value for legend entry */ +td.headerValueLeg +{ + text-align: left; + color: #000000; + font-family: sans-serif; + font-size: 80%; + white-space: nowrap; + padding-top: 4px; +} + +/* All views: color of horizontal ruler */ +td.ruler +{ + background-color: #6688D4; +} + +/* All views: version string format */ +td.versionInfo +{ + text-align: center; + padding-top: 2px; + font-family: sans-serif; + font-style: italic; +} + +/* Directory view/File view (all)/Test case descriptions: + table headline format */ +td.tableHead +{ + text-align: center; + color: #FFFFFF; + background-color: #6688D4; + font-family: sans-serif; + font-size: 120%; + font-weight: bold; + white-space: nowrap; + padding-left: 4px; + padding-right: 4px; +} + +span.tableHeadSort +{ + padding-right: 4px; +} + +/* Directory view/File view (all): filename entry format */ +td.coverFile +{ + text-align: left; + padding-left: 10px; + padding-right: 20px; + color: #284FA8; + background-color: #DAE7FE; + font-family: monospace; +} + +/* Directory view/File view (all): bar-graph entry format*/ +td.coverBar +{ + padding-left: 10px; + padding-right: 10px; + background-color: #DAE7FE; +} + +/* Directory view/File view (all): bar-graph outline color */ +td.coverBarOutline +{ + background-color: #000000; +} + +/* Directory view/File view (all): percentage entry for files with + high coverage rate */ +td.coverPerHi +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #A7FC9D; + font-weight: bold; + font-family: sans-serif; +} + +/* Directory view/File view (all): line count entry for files with + high coverage rate */ +td.coverNumHi +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #A7FC9D; + white-space: nowrap; + font-family: sans-serif; +} + +/* Directory view/File view (all): percentage entry for files with + medium coverage rate */ +td.coverPerMed +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #FFEA20; + font-weight: bold; + font-family: sans-serif; +} + +/* Directory view/File view (all): line count entry for files with + medium coverage rate */ +td.coverNumMed +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #FFEA20; + white-space: nowrap; + font-family: sans-serif; +} + +/* Directory view/File view (all): percentage entry for files with + low coverage rate */ +td.coverPerLo +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #FF0000; + font-weight: bold; + font-family: sans-serif; +} + +/* Directory view/File view (all): line count entry for files with + low coverage rate */ +td.coverNumLo +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #FF0000; + white-space: nowrap; + font-family: sans-serif; +} + +/* File view (all): "show/hide details" link format */ +a.detail:link +{ + color: #B8D0FF; + font-size:80%; +} + +/* File view (all): "show/hide details" link - visited format */ +a.detail:visited +{ + color: #B8D0FF; + font-size:80%; +} + +/* File view (all): "show/hide details" link - activated format */ +a.detail:active +{ + color: #FFFFFF; + font-size:80%; +} + +/* File view (detail): test name entry */ +td.testName +{ + text-align: right; + padding-right: 10px; + background-color: #DAE7FE; + font-family: sans-serif; +} + +/* File view (detail): test percentage entry */ +td.testPer +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #DAE7FE; + font-family: sans-serif; +} + +/* File view (detail): test lines count entry */ +td.testNum +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #DAE7FE; + font-family: sans-serif; +} + +/* Test case descriptions: test name format*/ +dt +{ + font-family: sans-serif; + font-weight: bold; +} + +/* Test case descriptions: description table body */ +td.testDescription +{ + padding-top: 10px; + padding-left: 30px; + padding-bottom: 10px; + padding-right: 30px; + background-color: #DAE7FE; +} + +/* Source code view: function entry */ +td.coverFn +{ + text-align: left; + padding-left: 10px; + padding-right: 20px; + color: #284FA8; + background-color: #DAE7FE; + font-family: monospace; +} + +/* Source code view: function entry zero count*/ +td.coverFnLo +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #FF0000; + font-weight: bold; + font-family: sans-serif; +} + +/* Source code view: function entry nonzero count*/ +td.coverFnHi +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #DAE7FE; + font-weight: bold; + font-family: sans-serif; +} + +/* Source code view: source code format */ +pre.source +{ + font-family: monospace; + white-space: pre; + margin-top: 2px; +} + +/* Source code view: line number format */ +span.lineNum +{ + background-color: #EFE383; +} + +/* Source code view: format for lines which were executed */ +td.lineCov, +span.lineCov +{ + background-color: #CAD7FE; +} + +/* Source code view: format for Cov legend */ +span.coverLegendCov +{ + padding-left: 10px; + padding-right: 10px; + padding-bottom: 2px; + background-color: #CAD7FE; +} + +/* Source code view: format for lines which were not executed */ +td.lineNoCov, +span.lineNoCov +{ + background-color: #FF6230; +} + +/* Source code view: format for NoCov legend */ +span.coverLegendNoCov +{ + padding-left: 10px; + padding-right: 10px; + padding-bottom: 2px; + background-color: #FF6230; +} + +/* Source code view (function table): standard link - visited format */ +td.lineNoCov > a:visited, +td.lineCov > a:visited +{ + color: black; + text-decoration: underline; +} + +/* Source code view: format for lines which were executed only in a + previous version */ +span.lineDiffCov +{ + background-color: #B5F7AF; +} + +/* Source code view: format for branches which were executed + * and taken */ +span.branchCov +{ + background-color: #CAD7FE; +} + +/* Source code view: format for branches which were executed + * but not taken */ +span.branchNoCov +{ + background-color: #FF6230; +} + +/* Source code view: format for branches which were not executed */ +span.branchNoExec +{ + background-color: #FF6230; +} + +/* Source code view: format for the source code heading line */ +pre.sourceHeading +{ + white-space: pre; + font-family: monospace; + font-weight: bold; + margin: 0px; +} + +/* All views: header legend value for low rate */ +td.headerValueLegL +{ + font-family: sans-serif; + text-align: center; + white-space: nowrap; + padding-left: 4px; + padding-right: 2px; + background-color: #FF0000; + font-size: 80%; +} + +/* All views: header legend value for med rate */ +td.headerValueLegM +{ + font-family: sans-serif; + text-align: center; + white-space: nowrap; + padding-left: 2px; + padding-right: 2px; + background-color: #FFEA20; + font-size: 80%; +} + +/* All views: header legend value for hi rate */ +td.headerValueLegH +{ + font-family: sans-serif; + text-align: center; + white-space: nowrap; + padding-left: 2px; + padding-right: 4px; + background-color: #A7FC9D; + font-size: 80%; +} + +/* All views except source code view: legend format for low coverage */ +span.coverLegendCovLo +{ + padding-left: 10px; + padding-right: 10px; + padding-top: 2px; + background-color: #FF0000; +} + +/* All views except source code view: legend format for med coverage */ +span.coverLegendCovMed +{ + padding-left: 10px; + padding-right: 10px; + padding-top: 2px; + background-color: #FFEA20; +} + +/* All views except source code view: legend format for hi coverage */ +span.coverLegendCovHi +{ + padding-left: 10px; + padding-right: 10px; + padding-top: 2px; + background-color: #A7FC9D; +} diff --git a/static/samples_rust_coverage/grcov_llvm_lcov/glass.png b/static/samples_rust_coverage/grcov_llvm_lcov/glass.png new file mode 100644 index 0000000000000000000000000000000000000000..e1abc00680a3093c49fdb775ae6bdb6764c95af2 GIT binary patch literal 167 zcmeAS@N?(olHy`uVBq!ia0vp^j3CU&3?x-=hn)gaEa{HEjtmSN`?>!lvI6;R0X`wF z|Ns97GD8ntt^-nxB|(0{3=Yq3q=7g|-tI089jvk*Kn`btM`SSr1Gf+eGhVt|_XjA* zUgGKN%6^Gmn4d%Ph(nkFP>9RZ#WAE}PI3Z}&BVayv3^M*kj3EX>gTe~DWM4f=_Dpv literal 0 HcmV?d00001 diff --git a/static/samples_rust_coverage/grcov_llvm_lcov/index-sort-f.html b/static/samples_rust_coverage/grcov_llvm_lcov/index-sort-f.html new file mode 100644 index 00000000..8f62c510 --- /dev/null +++ b/static/samples_rust_coverage/grcov_llvm_lcov/index-sort-f.html @@ -0,0 +1,102 @@ + + + + + + + LCOV - lcov + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top levelHitTotalCoverage
Test:lcovLines:757994.9 %
Date:2024-01-12 19:04:51Functions:192190.5 %
Legend: Rating: + low: < 75 % + medium: >= 75 % + high: >= 90 % +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Directory Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
src +
94.9%94.9%
+
94.9 %75 / 7990.5 %19 / 21
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/static/samples_rust_coverage/grcov_llvm_lcov/index-sort-l.html b/static/samples_rust_coverage/grcov_llvm_lcov/index-sort-l.html new file mode 100644 index 00000000..4f2d38cc --- /dev/null +++ b/static/samples_rust_coverage/grcov_llvm_lcov/index-sort-l.html @@ -0,0 +1,102 @@ + + + + + + + LCOV - lcov + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top levelHitTotalCoverage
Test:lcovLines:757994.9 %
Date:2024-01-12 19:04:51Functions:192190.5 %
Legend: Rating: + low: < 75 % + medium: >= 75 % + high: >= 90 % +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Directory Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
src +
94.9%94.9%
+
94.9 %75 / 7990.5 %19 / 21
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/static/samples_rust_coverage/grcov_llvm_lcov/index.html b/static/samples_rust_coverage/grcov_llvm_lcov/index.html new file mode 100644 index 00000000..f486b10b --- /dev/null +++ b/static/samples_rust_coverage/grcov_llvm_lcov/index.html @@ -0,0 +1,102 @@ + + + + + + + LCOV - lcov + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top levelHitTotalCoverage
Test:lcovLines:757994.9 %
Date:2024-01-12 19:04:51Functions:192190.5 %
Legend: Rating: + low: < 75 % + medium: >= 75 % + high: >= 90 % +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +

Directory Sort by nameLine Coverage Sort by line coverageFunctions Sort by function coverage
src +
94.9%94.9%
+
94.9 %75 / 7990.5 %19 / 21
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/static/samples_rust_coverage/grcov_llvm_lcov/lcov b/static/samples_rust_coverage/grcov_llvm_lcov/lcov new file mode 100644 index 00000000..8bcf8213 --- /dev/null +++ b/static/samples_rust_coverage/grcov_llvm_lcov/lcov @@ -0,0 +1,148 @@ +TN: +SF:src/main.rs +FN:31,tmp::largest:: +FN:67,tmp::tests::parser_detects_errors::{closure#0} +FN:75,tmp::tests::check_match::{closure#0} +FN:90,tmp::tests::check_generic +FN:102,tmp::tests::check_not_panic::{closure#0} +FN:5,tmp::validate_data_simple +FN:3,tmp::main +FN:11,tmp::validate_data_match +FN:31,tmp::largest:: +FN:83,tmp::tests::check_match2 +FN:76,tmp::tests::check_match +FN:68,tmp::tests::parser_detects_errors +FN:3,tmp::main +FN:31,tmp::largest:: +FN:41,tmp::validate_data_generics +FN:31,tmp::largest::<_> +FN:103,tmp::tests::check_not_panic +FN:41,tmp::validate_data_generics +FN:89,tmp::tests::check_generic::{closure#0} +FN:97,tmp::tests::check_panic +FN:11,tmp::validate_data_match +FN:82,tmp::tests::check_match2::{closure#0} +FN:5,tmp::validate_data_simple +FN:95,tmp::tests::check_panic::{closure#0} +FNDA:1,tmp::largest:: +FNDA:1,tmp::tests::parser_detects_errors::{closure#0} +FNDA:1,tmp::tests::check_match::{closure#0} +FNDA:1,tmp::tests::check_generic +FNDA:1,tmp::tests::check_not_panic::{closure#0} +FNDA:0,tmp::validate_data_simple +FNDA:0,tmp::main +FNDA:0,tmp::validate_data_match +FNDA:1,tmp::largest:: +FNDA:1,tmp::tests::check_match2 +FNDA:1,tmp::tests::check_match +FNDA:1,tmp::tests::parser_detects_errors +FNDA:0,tmp::main +FNDA:1,tmp::largest:: +FNDA:0,tmp::validate_data_generics +FNDA:0,tmp::largest::<_> +FNDA:1,tmp::tests::check_not_panic +FNDA:1,tmp::validate_data_generics +FNDA:1,tmp::tests::check_generic::{closure#0} +FNDA:1,tmp::tests::check_panic +FNDA:1,tmp::validate_data_match +FNDA:1,tmp::tests::check_match2::{closure#0} +FNDA:1,tmp::validate_data_simple +FNDA:1,tmp::tests::check_panic::{closure#0} +FNF:24 +FNH:18 +BRF:0 +BRH:0 +DA:3,0 +DA:5,2 +DA:6,2 +DA:7,0 +DA:8,0 +DA:9,2 +DA:11,4 +DA:12,4 +DA:13,2 +DA:14,2 +DA:15,2 +DA:16,0 +DA:18,2 +DA:21,2 +DA:23,4 +DA:24,2 +DA:26,2 +DA:28,4 +DA:31,6 +DA:32,6 +DA:33,30 +DA:34,24 +DA:35,6 +DA:36,18 +DA:38,6 +DA:39,6 +DA:41,2 +DA:42,2 +DA:43,2 +DA:44,2 +DA:45,2 +DA:46,2 +DA:47,2 +DA:48,2 +DA:49,2 +DA:50,2 +DA:51,2 +DA:52,2 +DA:53,2 +DA:54,2 +DA:67,2 +DA:68,2 +DA:69,2 +DA:70,2 +DA:71,2 +DA:72,2 +DA:73,2 +DA:75,2 +DA:76,2 +DA:77,2 +DA:78,2 +DA:79,2 +DA:80,2 +DA:82,2 +DA:83,2 +DA:84,2 +DA:85,2 +DA:86,2 +DA:87,2 +DA:89,2 +DA:90,2 +DA:91,2 +DA:92,2 +DA:93,2 +DA:95,2 +DA:97,2 +DA:98,2 +DA:99,2 +DA:100,2 +DA:102,2 +DA:103,2 +DA:104,2 +DA:105,2 +DA:106,2 +LF:74 +LH:70 +end_of_record +SF:src/second.rs +FN:3,tmp::second::validate_data_panic +FN:3,tmp::second::validate_data_panic +FNDA:1,tmp::second::validate_data_panic +FNDA:0,tmp::second::validate_data_panic +FNF:2 +FNH:1 +BRF:0 +BRH:0 +DA:3,4 +DA:4,4 +DA:5,2 +DA:6,2 +DA:7,2 +LF:5 +LH:5 +end_of_record diff --git a/static/samples_rust_coverage/grcov_llvm_lcov/ruby.png b/static/samples_rust_coverage/grcov_llvm_lcov/ruby.png new file mode 100644 index 0000000000000000000000000000000000000000..991b6d4ec9e78be165e3ef757eed1aada287364d GIT binary patch literal 141 zcmeAS@N?(olHy`uVBq!ia0vp^j3CU&3?x-=hn)ga>?NMQuI!iC1^FceV#7`HfI^%F z9+AZi4BSE>%y{W;-5;PJOS+@4BLl<6e(pbstUx|nfKQ0)e^Y%R^MdiLxj>4`)5S5Q b;#P73kj=!v_*DHKNFRfztDnm{r-UW|iOwIS literal 0 HcmV?d00001 diff --git a/static/samples_rust_coverage/grcov_llvm_lcov/snow.png b/static/samples_rust_coverage/grcov_llvm_lcov/snow.png new file mode 100644 index 0000000000000000000000000000000000000000..2cdae107fceec6e7f02ac7acb4a34a82a540caa5 GIT binary patch literal 141 zcmeAS@N?(olHy`uVBq!ia0vp^j3CU&3?x-=hn)ga>?NMQuI!iC1^MM!lvI6;R0X`wF|Ns97GD8ntt^-nBo-U3d c6}OTTfNUlP#;5A{K>8RwUHx3vIVCg!071?oo&W#< literal 0 HcmV?d00001 diff --git a/static/samples_rust_coverage/grcov_llvm_lcov/src/index-detail-sort-f.html b/static/samples_rust_coverage/grcov_llvm_lcov/src/index-detail-sort-f.html new file mode 100644 index 00000000..4c8e2e57 --- /dev/null +++ b/static/samples_rust_coverage/grcov_llvm_lcov/src/index-detail-sort-f.html @@ -0,0 +1,128 @@ + + + + + + + LCOV - lcov - src + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - srcHitTotalCoverage
Test:lcovLines:757994.9 %
Date:2024-01-12 19:04:51Functions:192190.5 %
Legend: Rating: + low: < 75 % + medium: >= 75 % + high: >= 90 % +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage ( hide details ) Sort by line coverageFunctions Sort by function coverage
main.rs +
94.6%94.6%
+
94.6 %70 / 7490.0 %18 / 20
<unnamed>94.6 %70 / 7490.0 %18 / 20
second.rs +
100.0%
+
100.0 %5 / 5100.0 %1 / 1
<unnamed>100.0 %5 / 5100.0 %1 / 1
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/static/samples_rust_coverage/grcov_llvm_lcov/src/index-detail-sort-l.html b/static/samples_rust_coverage/grcov_llvm_lcov/src/index-detail-sort-l.html new file mode 100644 index 00000000..a70098c8 --- /dev/null +++ b/static/samples_rust_coverage/grcov_llvm_lcov/src/index-detail-sort-l.html @@ -0,0 +1,128 @@ + + + + + + + LCOV - lcov - src + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - srcHitTotalCoverage
Test:lcovLines:757994.9 %
Date:2024-01-12 19:04:51Functions:192190.5 %
Legend: Rating: + low: < 75 % + medium: >= 75 % + high: >= 90 % +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage ( hide details ) Sort by line coverageFunctions Sort by function coverage
main.rs +
94.6%94.6%
+
94.6 %70 / 7490.0 %18 / 20
<unnamed>94.6 %70 / 7490.0 %18 / 20
second.rs +
100.0%
+
100.0 %5 / 5100.0 %1 / 1
<unnamed>100.0 %5 / 5100.0 %1 / 1
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/static/samples_rust_coverage/grcov_llvm_lcov/src/index-detail.html b/static/samples_rust_coverage/grcov_llvm_lcov/src/index-detail.html new file mode 100644 index 00000000..057dbcf8 --- /dev/null +++ b/static/samples_rust_coverage/grcov_llvm_lcov/src/index-detail.html @@ -0,0 +1,128 @@ + + + + + + + LCOV - lcov - src + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - srcHitTotalCoverage
Test:lcovLines:757994.9 %
Date:2024-01-12 19:04:51Functions:192190.5 %
Legend: Rating: + low: < 75 % + medium: >= 75 % + high: >= 90 % +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage ( hide details ) Sort by line coverageFunctions Sort by function coverage
main.rs +
94.6%94.6%
+
94.6 %70 / 7490.0 %18 / 20
<unnamed>94.6 %70 / 7490.0 %18 / 20
second.rs +
100.0%
+
100.0 %5 / 5100.0 %1 / 1
<unnamed>100.0 %5 / 5100.0 %1 / 1
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/static/samples_rust_coverage/grcov_llvm_lcov/src/index-sort-f.html b/static/samples_rust_coverage/grcov_llvm_lcov/src/index-sort-f.html new file mode 100644 index 00000000..261c980d --- /dev/null +++ b/static/samples_rust_coverage/grcov_llvm_lcov/src/index-sort-f.html @@ -0,0 +1,112 @@ + + + + + + + LCOV - lcov - src + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - srcHitTotalCoverage
Test:lcovLines:757994.9 %
Date:2024-01-12 19:04:51Functions:192190.5 %
Legend: Rating: + low: < 75 % + medium: >= 75 % + high: >= 90 % +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage ( show details ) Sort by line coverageFunctions Sort by function coverage
main.rs +
94.6%94.6%
+
94.6 %70 / 7490.0 %18 / 20
second.rs +
100.0%
+
100.0 %5 / 5100.0 %1 / 1
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/static/samples_rust_coverage/grcov_llvm_lcov/src/index-sort-l.html b/static/samples_rust_coverage/grcov_llvm_lcov/src/index-sort-l.html new file mode 100644 index 00000000..4f65d7fa --- /dev/null +++ b/static/samples_rust_coverage/grcov_llvm_lcov/src/index-sort-l.html @@ -0,0 +1,112 @@ + + + + + + + LCOV - lcov - src + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - srcHitTotalCoverage
Test:lcovLines:757994.9 %
Date:2024-01-12 19:04:51Functions:192190.5 %
Legend: Rating: + low: < 75 % + medium: >= 75 % + high: >= 90 % +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage ( show details ) Sort by line coverageFunctions Sort by function coverage
main.rs +
94.6%94.6%
+
94.6 %70 / 7490.0 %18 / 20
second.rs +
100.0%
+
100.0 %5 / 5100.0 %1 / 1
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/static/samples_rust_coverage/grcov_llvm_lcov/src/index.html b/static/samples_rust_coverage/grcov_llvm_lcov/src/index.html new file mode 100644 index 00000000..23b3224e --- /dev/null +++ b/static/samples_rust_coverage/grcov_llvm_lcov/src/index.html @@ -0,0 +1,112 @@ + + + + + + + LCOV - lcov - src + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - srcHitTotalCoverage
Test:lcovLines:757994.9 %
Date:2024-01-12 19:04:51Functions:192190.5 %
Legend: Rating: + low: < 75 % + medium: >= 75 % + high: >= 90 % +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Filename Sort by nameLine Coverage ( show details ) Sort by line coverageFunctions Sort by function coverage
main.rs +
94.6%94.6%
+
94.6 %70 / 7490.0 %18 / 20
second.rs +
100.0%
+
100.0 %5 / 5100.0 %1 / 1
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/static/samples_rust_coverage/grcov_llvm_lcov/src/main.rs.func-sort-c.html b/static/samples_rust_coverage/grcov_llvm_lcov/src/main.rs.func-sort-c.html new file mode 100644 index 00000000..dea706e2 --- /dev/null +++ b/static/samples_rust_coverage/grcov_llvm_lcov/src/main.rs.func-sort-c.html @@ -0,0 +1,160 @@ + + + + + + + LCOV - lcov - src/main.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - src - main.rs (source / functions)HitTotalCoverage
Test:lcovLines:707494.6 %
Date:2024-01-12 19:04:51Functions:182090.0 %
Legend: Lines: + hit + not hit +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
tmp::largest::<_>0
tmp::main0
tmp::largest::<char>1
tmp::largest::<i32>1
tmp::largest::<u8>1
tmp::tests::check_generic1
tmp::tests::check_generic::{closure#0}1
tmp::tests::check_match1
tmp::tests::check_match21
tmp::tests::check_match2::{closure#0}1
tmp::tests::check_match::{closure#0}1
tmp::tests::check_not_panic1
tmp::tests::check_not_panic::{closure#0}1
tmp::tests::check_panic1
tmp::tests::check_panic::{closure#0}1
tmp::tests::parser_detects_errors1
tmp::tests::parser_detects_errors::{closure#0}1
tmp::validate_data_generics1
tmp::validate_data_match1
tmp::validate_data_simple1
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/static/samples_rust_coverage/grcov_llvm_lcov/src/main.rs.func.html b/static/samples_rust_coverage/grcov_llvm_lcov/src/main.rs.func.html new file mode 100644 index 00000000..350c3bd9 --- /dev/null +++ b/static/samples_rust_coverage/grcov_llvm_lcov/src/main.rs.func.html @@ -0,0 +1,160 @@ + + + + + + + LCOV - lcov - src/main.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - src - main.rs (source / functions)HitTotalCoverage
Test:lcovLines:707494.6 %
Date:2024-01-12 19:04:51Functions:182090.0 %
Legend: Lines: + hit + not hit +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
tmp::largest::<_>0
tmp::largest::<char>1
tmp::largest::<i32>1
tmp::largest::<u8>1
tmp::main0
tmp::tests::check_generic1
tmp::tests::check_generic::{closure#0}1
tmp::tests::check_match1
tmp::tests::check_match21
tmp::tests::check_match2::{closure#0}1
tmp::tests::check_match::{closure#0}1
tmp::tests::check_not_panic1
tmp::tests::check_not_panic::{closure#0}1
tmp::tests::check_panic1
tmp::tests::check_panic::{closure#0}1
tmp::tests::parser_detects_errors1
tmp::tests::parser_detects_errors::{closure#0}1
tmp::validate_data_generics1
tmp::validate_data_match1
tmp::validate_data_simple1
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/static/samples_rust_coverage/grcov_llvm_lcov/src/main.rs.gcov.html b/static/samples_rust_coverage/grcov_llvm_lcov/src/main.rs.gcov.html new file mode 100644 index 00000000..926438e5 --- /dev/null +++ b/static/samples_rust_coverage/grcov_llvm_lcov/src/main.rs.gcov.html @@ -0,0 +1,191 @@ + + + + + + + LCOV - lcov - src/main.rs + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - src - main.rs (source / functions)HitTotalCoverage
Test:lcovLines:707494.6 %
Date:2024-01-12 19:04:51Functions:182090.0 %
Legend: Lines: + hit + not hit +
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : mod second;
+       2             : 
+       3           0 : fn main() { println!("Hello, world!"); }
+       4             : 
+       5           2 : fn validate_data_simple(data: &Data) -> Result<(), ()> {
+       6           2 :     if !data.magic.eq(&[0x13, 0x37]) { return Err(()) }
+       7           0 :     if data.len as usize != data.content.len() { return Err(()) }
+       8           0 :     return Ok(());
+       9           2 : }
+      10             : 
+      11           4 : fn validate_data_match(data: &Data) -> i32 {
+      12           4 :     let x: u32 = match data.content.parse::<u32>() {
+      13           2 :         Ok(_x) => {
+      14           2 :             let y = 2 * _x;
+      15           2 :             if y < 6 {
+      16           0 :                 y
+      17             :             } else {
+      18           2 :                 y * 2
+      19             :             }
+      20             :         }
+      21           2 :         Err(_) => 0
+      22             :     };
+      23           4 :     if x == 0 {
+      24           2 :         -1
+      25             :     } else {
+      26           2 :         (x as i32) + 1
+      27             :     }
+      28           4 : }
+      29             : 
+      30             : // https://doc.rust-lang.org/book/ch10-01-syntax.html
+      31           6 : fn largest<T: PartialOrd>(list: &[T]) -> &T {
+      32           6 :     let mut largest = &list[0];
+      33          30 :     for item in list {
+      34          24 :         if item > largest {
+      35           6 :             largest = item;
+      36          18 :         }
+      37             :     }
+      38           6 :     largest
+      39           6 : }
+      40             : 
+      41           2 : fn validate_data_generics(data: &Data) {
+      42           2 :     let number_list = vec![34, 50, 25, 100, 65];
+      43           2 : 
+      44           2 :     let result = largest(&number_list);
+      45           2 :     println!("The largest number is {}", result);
+      46           2 : 
+      47           2 :     let char_list = vec!['y', 'm', 'a', 'q'];
+      48           2 : 
+      49           2 :     let result = largest(&char_list);
+      50           2 :     println!("The largest char is {}", result);
+      51           2 : 
+      52           2 :     let result = largest(data.content.as_bytes());
+      53           2 :     println!("The largest content char is {}", result);
+      54           2 : }
+      55             : 
+      56             : struct Data {
+      57             :     magic: [u8; 2],
+      58             :     len: u8,
+      59             :     content: String
+      60             : }
+      61             : 
+      62             : #[cfg(test)]
+      63             : mod tests {
+      64             :     use crate::second::validate_data_panic;
+      65             :     use crate::{Data, validate_data_generics, validate_data_match, validate_data_simple};
+      66             : 
+      67           2 :     #[test]
+      68           2 :     fn parser_detects_errors() {
+      69           2 :         let mut blob = Data{ magic: [0x73, 0x31], len: 2, content: "AB".parse().unwrap() };
+      70           2 :         blob.content = blob.content + "Y";
+      71           2 :         let result = validate_data_simple(&blob);
+      72           2 :         assert!(result.is_err());
+      73           2 :     }
+      74             : 
+      75           2 :     #[test]
+      76           2 :     fn check_match() {
+      77           2 :         let blob = Data{ magic: [0x73, 0x31], len: 2, content: "XX".parse().unwrap() };
+      78           2 :         let x = validate_data_match(&blob);
+      79           2 :         assert_eq!(x, -1);
+      80           2 :     }
+      81             : 
+      82           2 :     #[test]
+      83           2 :     fn check_match2() {
+      84           2 :         let blob = Data{ magic: [0x73, 0x31], len: 2, content: "40".parse().unwrap() };
+      85           2 :         let x = validate_data_match(&blob);
+      86           2 :         assert_eq!(x, 161);
+      87           2 :     }
+      88             : 
+      89           2 :     #[test]
+      90           2 :     fn check_generic() {
+      91           2 :         let blob = Data{ magic: [0x73, 0x31], len: 2, content: "QWE".parse().unwrap() };
+      92           2 :         validate_data_generics(&blob);
+      93           2 :     }
+      94             : 
+      95           2 :     #[test]
+      96             :     #[should_panic]
+      97           2 :     fn check_panic() {
+      98           2 :         let blob = Data{ magic: [0x73, 0x31], len: 0, content: "4".parse().unwrap() };
+      99           2 :         validate_data_panic(&blob);
+     100           2 :     }
+     101             : 
+     102           2 :     #[test]
+     103           2 :     fn check_not_panic() {
+     104           2 :         let blob = Data{ magic: [0x73, 0x31], len: 2, content: "4".parse().unwrap() };
+     105           2 :         validate_data_panic(&blob);
+     106           2 :     }
+     107             : }
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/static/samples_rust_coverage/grcov_llvm_lcov/src/second.rs.func-sort-c.html b/static/samples_rust_coverage/grcov_llvm_lcov/src/second.rs.func-sort-c.html new file mode 100644 index 00000000..f80aaefc --- /dev/null +++ b/static/samples_rust_coverage/grcov_llvm_lcov/src/second.rs.func-sort-c.html @@ -0,0 +1,84 @@ + + + + + + + LCOV - lcov - src/second.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - src - second.rs (source / functions)HitTotalCoverage
Test:lcovLines:55100.0 %
Date:2024-01-12 19:04:51Functions:11100.0 %
Legend: Lines: + hit + not hit +
+
+ +
+ + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
tmp::second::validate_data_panic1
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/static/samples_rust_coverage/grcov_llvm_lcov/src/second.rs.func.html b/static/samples_rust_coverage/grcov_llvm_lcov/src/second.rs.func.html new file mode 100644 index 00000000..825f29d2 --- /dev/null +++ b/static/samples_rust_coverage/grcov_llvm_lcov/src/second.rs.func.html @@ -0,0 +1,84 @@ + + + + + + + LCOV - lcov - src/second.rs - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - src - second.rs (source / functions)HitTotalCoverage
Test:lcovLines:55100.0 %
Date:2024-01-12 19:04:51Functions:11100.0 %
Legend: Lines: + hit + not hit +
+
+ +
+ + + + + + + + + + +

Function Name Sort by function nameHit count Sort by hit count
tmp::second::validate_data_panic1
+
+
+ + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/static/samples_rust_coverage/grcov_llvm_lcov/src/second.rs.gcov.html b/static/samples_rust_coverage/grcov_llvm_lcov/src/second.rs.gcov.html new file mode 100644 index 00000000..937b7c96 --- /dev/null +++ b/static/samples_rust_coverage/grcov_llvm_lcov/src/second.rs.gcov.html @@ -0,0 +1,91 @@ + + + + + + + LCOV - lcov - src/second.rs + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - src - second.rs (source / functions)HitTotalCoverage
Test:lcovLines:55100.0 %
Date:2024-01-12 19:04:51Functions:11100.0 %
Legend: Lines: + hit + not hit +
+
+ + + + + + + + +

+
          Line data    Source code
+
+       1             : use crate::Data;
+       2             : 
+       3           4 : pub(crate) fn validate_data_panic(data: &Data) {
+       4           4 :     if data.len == 0 {
+       5           2 :         panic!("panic")
+       6           2 :     }
+       7           2 : }
+
+
+
+ + + + +
Generated by: LCOV version 1.14
+
+ + + diff --git a/static/samples_rust_coverage/grcov_llvm_lcov/updown.png b/static/samples_rust_coverage/grcov_llvm_lcov/updown.png new file mode 100644 index 0000000000000000000000000000000000000000..aa56a238b3e6c435265250f9266cd1b8caba0f20 GIT binary patch literal 117 zcmeAS@N?(olHy`uVBq!ia0vp^AT}Qd8;}%R+`Ae`*?77*hG?8mPH5^{)z4*}Q$iB}huR`+ literal 0 HcmV?d00001 diff --git a/static/samples_rust_coverage/llvm_cov/coverage/home/test/src/main.rs.html b/static/samples_rust_coverage/llvm_cov/coverage/home/test/src/main.rs.html new file mode 100644 index 00000000..18b2527b --- /dev/null +++ b/static/samples_rust_coverage/llvm_cov/coverage/home/test/src/main.rs.html @@ -0,0 +1 @@ +

Coverage Report

Created: 2024-01-12 19:04

/home/test/src/main.rs
Line
Count
Source (jump to first uncovered line)
1
mod second;
2
3
0
fn main() { println!("Hello, world!"); }
4
5
1
fn validate_data_simple(data: &Data) -> Result<(), ()> {
6
1
    if !data.magic.eq(&[0x13, 0x37]) { return Err(()) }
7
0
    if data.len as usize != data.content.len() { return Err(()) }
8
0
    return Ok(());
9
1
}
10
11
2
fn validate_data_match(data: &Data) -> i32 {
12
2
    let x: u32 = match data.content.parse::<u32>() {
13
1
        Ok(_x) => {
14
1
            let y = 2 * _x;
15
1
            if y < 6 {
16
0
                y
17
            } else {
18
1
                y * 2
19
            }
20
        }
21
1
        Err(_) => 0
22
    };
23
2
    if x == 0 {
24
1
        -1
25
    } else {
26
1
        (x as i32) + 1
27
    }
28
2
}
29
30
// https://doc.rust-lang.org/book/ch10-01-syntax.html
31
3
fn largest<T: PartialOrd>(list: &[T]) -> &T {
32
3
    let mut largest = &list[0];
33
15
    for 
item12
in list {
34
12
        if item > largest {
35
3
            largest = item;
36
9
        }
37
    }
38
3
    largest
39
3
}
tmp::largest::<u8>
Line
Count
Source
31
1
fn largest<T: PartialOrd>(list: &[T]) -> &T {
32
1
    let mut largest = &list[0];
33
4
    for 
item3
in list {
34
3
        if item > largest {
35
1
            largest = item;
36
2
        }
37
    }
38
1
    largest
39
1
}
tmp::largest::<i32>
Line
Count
Source
31
1
fn largest<T: PartialOrd>(list: &[T]) -> &T {
32
1
    let mut largest = &list[0];
33
6
    for 
item5
in list {
34
5
        if item > largest {
35
2
            largest = item;
36
3
        }
37
    }
38
1
    largest
39
1
}
tmp::largest::<char>
Line
Count
Source
31
1
fn largest<T: PartialOrd>(list: &[T]) -> &T {
32
1
    let mut largest = &list[0];
33
5
    for 
item4
in list {
34
4
        if item > largest {
35
0
            largest = item;
36
4
        }
37
    }
38
1
    largest
39
1
}
40
41
1
fn validate_data_generics(data: &Data) {
42
1
    let number_list = vec![34, 50, 25, 100, 65];
43
1
44
1
    let result = largest(&number_list);
45
1
    println!("The largest number is {}", result);
46
1
47
1
    let char_list = vec!['y', 'm', 'a', 'q'];
48
1
49
1
    let result = largest(&char_list);
50
1
    println!("The largest char is {}", result);
51
1
52
1
    let result = largest(data.content.as_bytes());
53
1
    println!("The largest content char is {}", result);
54
1
}
55
56
struct Data {
57
    magic: [u8; 2],
58
    len: u8,
59
    content: String
60
}
61
62
#[cfg(test)]
63
mod tests {
64
    use crate::second::validate_data_panic;
65
    use crate::{Data, validate_data_generics, validate_data_match, validate_data_simple};
66
67
1
    #[test]
68
1
    fn parser_detects_errors() {
69
1
        let mut blob = Data{ magic: [0x73, 0x31], len: 2, content: "AB".parse().unwrap() };
70
1
        blob.content = blob.content + "Y";
71
1
        let result = validate_data_simple(&blob);
72
1
        assert!(result.is_err());
73
1
    }
74
75
1
    #[test]
76
1
    fn check_match() {
77
1
        let blob = Data{ magic: [0x73, 0x31], len: 2, content: "XX".parse().unwrap() };
78
1
        let x = validate_data_match(&blob);
79
1
        assert_eq!(x, -1);
80
1
    }
81
82
1
    #[test]
83
1
    fn check_match2() {
84
1
        let blob = Data{ magic: [0x73, 0x31], len: 2, content: "40".parse().unwrap() };
85
1
        let x = validate_data_match(&blob);
86
1
        assert_eq!(x, 161);
87
1
    }
88
89
1
    #[test]
90
1
    fn check_generic() {
91
1
        let blob = Data{ magic: [0x73, 0x31], len: 2, content: "QWE".parse().unwrap() };
92
1
        validate_data_generics(&blob);
93
1
    }
94
95
1
    #[test]
96
    #[should_panic]
97
1
    fn check_panic() {
98
1
        let blob = Data{ magic: [0x73, 0x31], len: 0, content: "4".parse().unwrap() };
99
1
        validate_data_panic(&blob);
100
1
    }
101
102
1
    #[test]
103
1
    fn check_not_panic() {
104
1
        let blob = Data{ magic: [0x73, 0x31], len: 2, content: "4".parse().unwrap() };
105
1
        validate_data_panic(&blob);
106
1
    }
107
}
\ No newline at end of file diff --git a/static/samples_rust_coverage/llvm_cov/coverage/home/test/src/second.rs.html b/static/samples_rust_coverage/llvm_cov/coverage/home/test/src/second.rs.html new file mode 100644 index 00000000..eaa6faeb --- /dev/null +++ b/static/samples_rust_coverage/llvm_cov/coverage/home/test/src/second.rs.html @@ -0,0 +1 @@ +

Coverage Report

Created: 2024-01-12 19:04

/home/test/src/second.rs
Line
Count
Source
1
use crate::Data;
2
3
2
pub(crate) fn validate_data_panic(data: &Data) {
4
2
    if data.len == 0 {
5
1
        panic!("panic")
6
1
    }
7
1
}
\ No newline at end of file diff --git a/static/samples_rust_coverage/llvm_cov/index.html b/static/samples_rust_coverage/llvm_cov/index.html new file mode 100644 index 00000000..61e066ec --- /dev/null +++ b/static/samples_rust_coverage/llvm_cov/index.html @@ -0,0 +1 @@ +

Coverage Report

Created: 2024-01-12 19:04

Click here for information about interpreting this report.

FilenameFunction CoverageLine CoverageRegion CoverageBranch Coverage
main.rs
  94.12% (16/17)
  94.59% (70/74)
  88.37% (38/43)
- (0/0)
second.rs
 100.00% (1/1)
 100.00% (5/5)
 100.00% (3/3)
- (0/0)
Totals
  94.44% (17/18)
  94.94% (75/79)
  89.13% (41/46)
- (0/0)
Generated by llvm-cov -- llvm version 17.0.4-rust-1.74.0-stable
\ No newline at end of file diff --git a/static/samples_rust_coverage/llvm_cov/style.css b/static/samples_rust_coverage/llvm_cov/style.css new file mode 100644 index 00000000..d95ffe27 --- /dev/null +++ b/static/samples_rust_coverage/llvm_cov/style.css @@ -0,0 +1,143 @@ +.red { + background-color: #ffd0d0; +} +.cyan { + background-color: cyan; +} +body { + font-family: -apple-system, sans-serif; +} +pre { + margin-top: 0px !important; + margin-bottom: 0px !important; +} +.source-name-title { + padding: 5px 10px; + border-bottom: 1px solid #dbdbdb; + background-color: #eee; + line-height: 35px; +} +.centered { + display: table; + margin-left: left; + margin-right: auto; + border: 1px solid #dbdbdb; + border-radius: 3px; +} +.expansion-view { + background-color: rgba(0, 0, 0, 0); + margin-left: 0px; + margin-top: 5px; + margin-right: 5px; + margin-bottom: 5px; + border: 1px solid #dbdbdb; + border-radius: 3px; +} +table { + border-collapse: collapse; +} +.light-row { + background: #ffffff; + border: 1px solid #dbdbdb; +} +.light-row-bold { + background: #ffffff; + border: 1px solid #dbdbdb; + font-weight: bold; +} +.column-entry { + text-align: left; +} +.column-entry-bold { + font-weight: bold; + text-align: left; +} +.column-entry-yellow { + text-align: left; + background-color: #ffffd0; +} +.column-entry-yellow:hover { + background-color: #fffff0; +} +.column-entry-red { + text-align: left; + background-color: #ffd0d0; +} +.column-entry-red:hover { + background-color: #fff0f0; +} +.column-entry-green { + text-align: left; + background-color: #d0ffd0; +} +.column-entry-green:hover { + background-color: #f0fff0; +} +.line-number { + text-align: right; + color: #aaa; +} +.covered-line { + text-align: right; + color: #0080ff; +} +.uncovered-line { + text-align: right; + color: #ff3300; +} +.tooltip { + position: relative; + display: inline; + background-color: #b3e6ff; + text-decoration: none; +} +.tooltip span.tooltip-content { + position: absolute; + width: 100px; + margin-left: -50px; + color: #FFFFFF; + background: #000000; + height: 30px; + line-height: 30px; + text-align: center; + visibility: hidden; + border-radius: 6px; +} +.tooltip span.tooltip-content:after { + content: ''; + position: absolute; + top: 100%; + left: 50%; + margin-left: -8px; + width: 0; height: 0; + border-top: 8px solid #000000; + border-right: 8px solid transparent; + border-left: 8px solid transparent; +} +:hover.tooltip span.tooltip-content { + visibility: visible; + opacity: 0.8; + bottom: 30px; + left: 50%; + z-index: 999; +} +th, td { + vertical-align: top; + padding: 2px 8px; + border-collapse: collapse; + border-right: solid 1px #eee; + border-left: solid 1px #eee; + text-align: left; +} +td pre { + display: inline-block; +} +td:first-child { + border-left: none; +} +td:last-child { + border-right: none; +} +tr:hover { + background-color: #f0f0f0; +} diff --git a/static/samples_rust_coverage/llvm_cov_pretty/index.html b/static/samples_rust_coverage/llvm_cov_pretty/index.html new file mode 100644 index 00000000..6e3a619e --- /dev/null +++ b/static/samples_rust_coverage/llvm_cov_pretty/index.html @@ -0,0 +1 @@ +Index

Coverage Report

Created at 2024-01-12 19:04

FilenameLine Coverage

94.94 %

Function Coverage

94.44 %

Region Coverage

89.13 %

src/main.rs
94.59 %70 / 74
94.12 %16 / 17
88.37 %38 / 43
src/second.rs
100.00 %5 / 5
100.00 %1 / 1
100.00 %3 / 3
\ No newline at end of file diff --git a/static/samples_rust_coverage/llvm_cov_pretty/src/main.rs.html b/static/samples_rust_coverage/llvm_cov_pretty/src/main.rs.html new file mode 100644 index 00000000..fbc14725 --- /dev/null +++ b/static/samples_rust_coverage/llvm_cov_pretty/src/main.rs.html @@ -0,0 +1 @@ +src/main.rs

src/main.rs

Lines

94.59 %

Functions

94.12 %

Regions

88.37 %

LineCountSource (jump to first uncovered line)
1
mod second;
2
30
fn main() { println!("Hello, world!"); }
4
51
fn validate_data_simple(data: &Data) -> Result<(), ()> {
61
    if !data.magic.eq(&[0x13, 0x37]) { return Err(()) }
70
    if data.len as usize != data.content.len() { return Err(()) }
80
    return Ok(());
91
}
10
112
fn validate_data_match(data: &Data) -> i32 {
122
    let x: u32 = match data.content.parse::<u32>() {
131
        Ok(_x) => {
141
            let y = 2 * _x;
151
            if y < 6 {
160
                y
17
            } else {
181
                y * 2
19
            }
20
        }
211
        Err(_) => 0
22
    };
232
    if x == 0 {
241
        -1
25
    } else {
261
        (x as i32) + 1
27
    }
282
}
29
30
// https://doc.rust-lang.org/book/ch10-01-syntax.html
313
fn largest<T: PartialOrd>(list: &[T]) -> &T {
323
    let mut largest = &list[0];
3315
    for item in list {
343
        if item > largest {
353
            largest = item;
369
        }
37
    }
383
    largest
393
}
40
411
fn validate_data_generics(data: &Data) {
421
    let number_list = vec![34, 50, 25, 100, 65];
431
441
    let result = largest(&number_list);
451
    println!("The largest number is {}", result);
461
471
    let char_list = vec!['y', 'm', 'a', 'q'];
481
491
    let result = largest(&char_list);
501
    println!("The largest char is {}", result);
511
521
    let result = largest(data.content.as_bytes());
531
    println!("The largest content char is {}", result);
541
}
55
56
struct Data {
57
    magic: [u8; 2],
58
    len: u8,
59
    content: String
60
}
61
62
#[cfg(test)]
63
mod tests {
64
    use crate::second::validate_data_panic;
65
    use crate::{Data, validate_data_generics, validate_data_match, validate_data_simple};
66
671
    #[test]
681
    fn parser_detects_errors() {
691
        let mut blob = Data{ magic: [0x73, 0x31], len: 2, content: "AB".parse().unwrap() };
701
        blob.content = blob.content + "Y";
711
        let result = validate_data_simple(&blob);
721
        assert!(result.is_err());
731
    }
74
751
    #[test]
761
    fn check_match() {
771
        let blob = Data{ magic: [0x73, 0x31], len: 2, content: "XX".parse().unwrap() };
781
        let x = validate_data_match(&blob);
791
        assert_eq!(x, -1);
801
    }
81
821
    #[test]
831
    fn check_match2() {
841
        let blob = Data{ magic: [0x73, 0x31], len: 2, content: "40".parse().unwrap() };
851
        let x = validate_data_match(&blob);
861
        assert_eq!(x, 161);
871
    }
88
891
    #[test]
901
    fn check_generic() {
911
        let blob = Data{ magic: [0x73, 0x31], len: 2, content: "QWE".parse().unwrap() };
921
        validate_data_generics(&blob);
931
    }
94
951
    #[test]
96
    #[should_panic]
971
    fn check_panic() {
981
        let blob = Data{ magic: [0x73, 0x31], len: 0, content: "4".parse().unwrap() };
991
        validate_data_panic(&blob);
1001
    }
101
1021
    #[test]
1031
    fn check_not_panic() {
1041
        let blob = Data{ magic: [0x73, 0x31], len: 2, content: "4".parse().unwrap() };
1051
        validate_data_panic(&blob);
1061
    }
107
}
\ No newline at end of file diff --git a/static/samples_rust_coverage/llvm_cov_pretty/src/second.rs.html b/static/samples_rust_coverage/llvm_cov_pretty/src/second.rs.html new file mode 100644 index 00000000..00a878dd --- /dev/null +++ b/static/samples_rust_coverage/llvm_cov_pretty/src/second.rs.html @@ -0,0 +1 @@ +src/second.rs

src/second.rs

Lines

100.00 %

Functions

100.00 %

Regions

100.00 %

LineCountSource
1
use crate::Data;
2
32
pub(crate) fn validate_data_panic(data: &Data) {
42
    if data.len == 0 {
51
        panic!("panic")
61
    }
71
}
\ No newline at end of file diff --git a/static/samples_rust_coverage/llvm_cov_pretty/style.css b/static/samples_rust_coverage/llvm_cov_pretty/style.css new file mode 100644 index 00000000..b9fb4317 --- /dev/null +++ b/static/samples_rust_coverage/llvm_cov_pretty/style.css @@ -0,0 +1 @@ +/*! tailwindcss v3.3.3 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:initial;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:initial}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}body{--tw-bg-opacity:1;background-color:rgb(226 232 240/var(--tw-bg-opacity));--tw-text-opacity:1;color:rgb(15 23 42/var(--tw-text-opacity))}@media (prefers-color-scheme:dark){body{--tw-bg-opacity:1;background-color:rgb(30 41 59/var(--tw-bg-opacity));--tw-text-opacity:1;color:rgb(241 245 249/var(--tw-text-opacity))}}a{color:rgb(37 99 235/var(--tw-text-opacity))}a,a:hover{--tw-text-opacity:1}a:hover{color:rgb(29 78 216/var(--tw-text-opacity));text-decoration-line:underline}@media (prefers-color-scheme:dark){a{color:rgb(96 165 250/var(--tw-text-opacity))}a,a:hover{--tw-text-opacity:1}a:hover{color:rgb(147 197 253/var(--tw-text-opacity))}}*,::backdrop,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.index-area{margin:1rem}.index-title{padding-bottom:2rem;font-size:1.875rem;line-height:2.25rem}.index-date{padding-bottom:2rem;font-size:1.125rem;line-height:1.75rem;font-weight:700}.index-table{width:100%;border-collapse:collapse;border-radius:.25rem;--tw-bg-opacity:1;background-color:rgb(203 213 225/var(--tw-bg-opacity))}@media (prefers-color-scheme:dark){.index-table{--tw-bg-opacity:1;background-color:rgb(51 65 85/var(--tw-bg-opacity))}}.index-table td,.index-table th{border-top-width:1px;border-bottom-width:1px;--tw-border-opacity:1;border-color:rgb(100 116 139/var(--tw-border-opacity));padding-left:.5rem;padding-right:.5rem}.index-table td:hover,.index-table th:hover{background-color:#33415540}@media (prefers-color-scheme:dark){.index-table td:hover,.index-table th:hover{background-color:#cbd5e140}}.index-table tr:last-child td,.index-table tr:last-child th{border-style:none}.index-table td:not(:first-child){text-align:center}.index-table td:nth-child(2),.index-table td:nth-child(5),.index-table td:nth-child(8){visibility:collapse}@media (min-width:1024px){.index-table td:nth-child(2),.index-table td:nth-child(5),.index-table td:nth-child(8){visibility:visible}}.index-header th{padding-top:.5rem;padding-bottom:.5rem;vertical-align:top}.index-header p{font-size:1.25rem;line-height:1.75rem;font-weight:700}.progress-bar{height:.75rem;border-radius:9999px;--tw-bg-opacity:1;background-color:rgb(148 163 184/var(--tw-bg-opacity))}@media (prefers-color-scheme:dark){.progress-bar{--tw-bg-opacity:1;background-color:rgb(100 116 139/var(--tw-bg-opacity))}}@media (min-width:1024px){.progress-bar{min-width:6rem}}.progress-bar div:only-child{height:.75rem;border-radius:9999px}@media (min-width:1024px){.progress-bar div:only-child{min-width:.75rem}}.source-area{margin:1rem;-webkit-user-select:none;-moz-user-select:none;user-select:none;border-radius:.25rem;--tw-bg-opacity:1;background-color:rgb(203 213 225/var(--tw-bg-opacity))}@media (prefers-color-scheme:dark){.source-area{--tw-bg-opacity:1;background-color:rgb(51 65 85/var(--tw-bg-opacity))}}.source-path{-webkit-user-select:text;-moz-user-select:text;user-select:text;padding:1rem}.source-coverage{margin-top:1rem;margin-bottom:1rem;display:flex;flex-direction:row;justify-content:space-evenly;text-align:center;font-weight:700}.source-coverage p:first-child{font-size:.875rem;line-height:1.25rem}.source-coverage p:nth-child(2){font-size:1.25rem;line-height:1.75rem}.source-table{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:.875rem;line-height:1.25rem}.source-table td{padding:0}.source-table thead{font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji}.source-table thead th{--tw-bg-opacity:1;background-color:rgb(148 163 184/var(--tw-bg-opacity));padding:.5rem;text-align:left}@media (prefers-color-scheme:dark){.source-table thead th{--tw-bg-opacity:1;background-color:rgb(71 85 105/var(--tw-bg-opacity))}}.source-table tbody tr{padding:0}.source-table tbody tr:hover{background-color:#33415540}@media (prefers-color-scheme:dark){.source-table tbody tr:hover{background-color:#cbd5e140}}.source-table tbody tr td:first-child,.source-table tbody tr td:nth-child(2){--tw-bg-opacity:1;background-color:rgb(203 213 225/var(--tw-bg-opacity));padding-left:.5rem;padding-right:.5rem;text-align:right;vertical-align:top}@media (prefers-color-scheme:dark){.source-table tbody tr td:first-child,.source-table tbody tr td:nth-child(2){--tw-bg-opacity:1;background-color:rgb(51 65 85/var(--tw-bg-opacity))}}.source-table tbody tr td:nth-child(3){width:100%;cursor:text;-webkit-user-select:text;-moz-user-select:text;user-select:text}.source-table tbody tr td:nth-child(3) pre{padding-left:.5rem}.source-message{margin:.5rem;border-radius:.25rem;--tw-bg-opacity:1;background-color:rgb(148 163 184/var(--tw-bg-opacity));padding:.5rem}@media (prefers-color-scheme:dark){.source-message{--tw-bg-opacity:1;background-color:rgb(71 85 105/var(--tw-bg-opacity))}}.covered{--tw-bg-opacity:1;background-color:rgb(74 222 128/var(--tw-bg-opacity))}.covered:hover{--tw-bg-opacity:1;background-color:rgb(34 197 94/var(--tw-bg-opacity))}@media (prefers-color-scheme:dark){.covered{--tw-bg-opacity:1;background-color:rgb(22 101 52/var(--tw-bg-opacity))}.covered:hover{--tw-bg-opacity:1;background-color:rgb(21 128 61/var(--tw-bg-opacity))}}.uncovered{--tw-bg-opacity:1;background-color:rgb(248 113 113/var(--tw-bg-opacity))}.uncovered:hover{--tw-bg-opacity:1;background-color:rgb(239 68 68/var(--tw-bg-opacity))}@media (prefers-color-scheme:dark){.uncovered{--tw-bg-opacity:1;background-color:rgb(153 27 27/var(--tw-bg-opacity))}.uncovered:hover{--tw-bg-opacity:1;background-color:rgb(185 28 28/var(--tw-bg-opacity))}}.partially-covered{--tw-bg-opacity:1;background-color:rgb(250 204 21/var(--tw-bg-opacity))}.partially-covered:hover{--tw-bg-opacity:1;background-color:rgb(234 179 8/var(--tw-bg-opacity))}@media (prefers-color-scheme:dark){.partially-covered{--tw-bg-opacity:1;background-color:rgb(133 77 14/var(--tw-bg-opacity))}.partially-covered:hover{--tw-bg-opacity:1;background-color:rgb(161 98 7/var(--tw-bg-opacity))}}.gutter.covered{--tw-bg-opacity:1!important;background-color:rgb(74 222 128/var(--tw-bg-opacity))!important}@media (prefers-color-scheme:dark){.gutter.covered{--tw-bg-opacity:1!important;background-color:rgb(22 101 52/var(--tw-bg-opacity))!important}}.gutter.uncovered{--tw-bg-opacity:1!important;background-color:rgb(248 113 113/var(--tw-bg-opacity))!important}@media (prefers-color-scheme:dark){.gutter.uncovered{--tw-bg-opacity:1!important;background-color:rgb(153 27 27/var(--tw-bg-opacity))!important}}.gutter.partially-covered{--tw-bg-opacity:1!important;background-color:rgb(250 204 21/var(--tw-bg-opacity))!important}@media (prefers-color-scheme:dark){.gutter.partially-covered{--tw-bg-opacity:1!important;background-color:rgb(133 77 14/var(--tw-bg-opacity))!important}}.page-footer{padding-left:1rem;padding-top:1rem;font-size:.875rem;line-height:1.25rem;font-weight:700}.level-text-veryhigh{--tw-text-opacity:1;color:rgb(34 197 94/var(--tw-text-opacity))}@media (prefers-color-scheme:dark){.level-text-veryhigh{--tw-text-opacity:1;color:rgb(22 163 74/var(--tw-text-opacity))}}.level-text-high{--tw-text-opacity:1;color:rgb(234 179 8/var(--tw-text-opacity))}@media (prefers-color-scheme:dark){.level-text-high{--tw-text-opacity:1;color:rgb(202 138 4/var(--tw-text-opacity))}}.level-text-medium{--tw-text-opacity:1;color:rgb(245 158 11/var(--tw-text-opacity))}@media (prefers-color-scheme:dark){.level-text-medium{--tw-text-opacity:1;color:rgb(217 119 6/var(--tw-text-opacity))}}.level-text-low{--tw-text-opacity:1;color:rgb(239 68 68/var(--tw-text-opacity))}@media (prefers-color-scheme:dark){.level-text-low{--tw-text-opacity:1;color:rgb(220 38 38/var(--tw-text-opacity))}}.level-bg-veryhigh{--tw-bg-opacity:1;background-color:rgb(34 197 94/var(--tw-bg-opacity))}@media (prefers-color-scheme:dark){.level-bg-veryhigh{--tw-bg-opacity:1;background-color:rgb(22 163 74/var(--tw-bg-opacity))}}.level-bg-high{--tw-bg-opacity:1;background-color:rgb(234 179 8/var(--tw-bg-opacity))}@media (prefers-color-scheme:dark){.level-bg-high{--tw-bg-opacity:1;background-color:rgb(202 138 4/var(--tw-bg-opacity))}}.level-bg-medium{--tw-bg-opacity:1;background-color:rgb(245 158 11/var(--tw-bg-opacity))}@media (prefers-color-scheme:dark){.level-bg-medium{--tw-bg-opacity:1;background-color:rgb(217 119 6/var(--tw-bg-opacity))}}.level-bg-low{--tw-bg-opacity:1;background-color:rgb(239 68 68/var(--tw-bg-opacity))}@media (prefers-color-scheme:dark){.level-bg-low{--tw-bg-opacity:1;background-color:rgb(220 38 38/var(--tw-bg-opacity))}}.block{display:block}.table{display:table} \ No newline at end of file diff --git a/static/samples_rust_coverage/llvm_cov_pretty/syntax.css b/static/samples_rust_coverage/llvm_cov_pretty/syntax.css new file mode 100644 index 00000000..ed0020ed --- /dev/null +++ b/static/samples_rust_coverage/llvm_cov_pretty/syntax.css @@ -0,0 +1 @@ +.syntect-code{color:#383a42;background-color:#fafafa}.syntect-comment{color:#a0a1a7}.syntect-variable.syntect-parameter.syntect-function{color:#383a42}.syntect-keyword{color:#a626a4}.syntect-variable{color:#e45649}.syntect-entity.syntect-name.syntect-function,.syntect-meta.syntect-require,.syntect-support.syntect-function.syntect-any-method{color:#0184bc}.syntect-entity.syntect-name.syntect-class,.syntect-entity.syntect-name.syntect-type.syntect-class,.syntect-support.syntect-class{color:#c18401}.syntect-meta.syntect-class{color:#c18401}.syntect-keyword.syntect-other.syntect-special-method{color:#0184bc}.syntect-storage{color:#a626a4}.syntect-support.syntect-function{color:#0184bc}.syntect-string{color:#50a14f}.syntect-constant.syntect-numeric{color:#c18401}.syntect-none{color:#c18401}.syntect-none{color:#c18401}.syntect-constant{color:#c18401}.syntect-entity.syntect-name.syntect-tag{color:#e45649}.syntect-entity.syntect-other.syntect-attribute-name{color:#c18401}.syntect-entity.syntect-other.syntect-attribute-name.syntect-id,.syntect-punctuation.syntect-definition.syntect-entity{color:#c18401}.syntect-meta.syntect-selector{color:#a626a4}.syntect-entity.syntect-name.syntect-section,.syntect-markup.syntect-heading .syntect-punctuation.syntect-definition.syntect-heading{color:#0184bc}.syntect-markup.syntect-bold,.syntect-punctuation.syntect-definition.syntect-bold{color:#a626a4}.syntect-markup.syntect-italic,.syntect-punctuation.syntect-definition.syntect-italic{color:#a626a4}.syntect-markup.syntect-raw.syntect-inline{color:#50a14f}.syntect-meta.syntect-link{color:#50a14f}.syntect-markup.syntect-quote{color:#50a14f}.syntect-source.syntect-java .syntect-meta.syntect-class.syntect-java .syntect-meta.syntect-method.syntect-java{color:#383a42}.syntect-source.syntect-java .syntect-meta.syntect-class.syntect-java .syntect-meta.syntect-class.syntect-body.syntect-java{color:#383a42}.syntect-source.syntect-js .syntect-meta.syntect-function.syntect-js .syntect-variable.syntect-parameter.syntect-function.syntect-js{color:#e45649}.syntect-source.syntect-js .syntect-variable.syntect-other.syntect-readwrite.syntect-js{color:#e45649}.syntect-source.syntect-js .syntect-variable.syntect-other.syntect-object.syntect-js{color:#383a42}.syntect-source.syntect-js .syntect-meta.syntect-function-call.syntect-method.syntect-js .syntect-variable.syntect-other.syntect-readwrite.syntect-js{color:#e45649}.syntect-source.syntect-js .syntect-meta.syntect-block.syntect-js .syntect-variable.syntect-other.syntect-readwrite.syntect-js{color:#e45649}.syntect-source.syntect-js .syntect-meta.syntect-block.syntect-js .syntect-variable.syntect-other.syntect-object.syntect-js{color:#383a42}.syntect-source.syntect-js .syntect-meta.syntect-block.syntect-js .syntect-meta.syntect-function-call.syntect-method.syntect-js .syntect-variable.syntect-other.syntect-readwrite.syntect-js{color:#383a42}.syntect-source.syntect-js .syntect-meta.syntect-function-call.syntect-method.syntect-js .syntect-variable.syntect-function.syntect-js{color:#383a42}.syntect-source.syntect-js .syntect-meta.syntect-property.syntect-object.syntect-js .syntect-entity.syntect-name.syntect-function.syntect-js{color:#0184bc}.syntect-source.syntect-js .syntect-support.syntect-constant.syntect-prototype.syntect-js{color:#383a42}.syntect-markup.syntect-inserted{color:#98c379}.syntect-markup.syntect-deleted{color:#e06c75}.syntect-markup.syntect-changed{color:#e5c07b}.syntect-string.syntect-regexp{color:#50a14f}.syntect-constant.syntect-character.syntect-escape{color:#0997b3}.syntect-invalid.syntect-illegal{color:#fafafa;background-color:#e06c75}.syntect-invalid.syntect-broken{color:#fafafa;background-color:#e5c07b}.syntect-invalid.syntect-deprecated{color:#fafafa;background-color:#e5c07b}.syntect-invalid.syntect-unimplemented{color:#fafafa;background-color:#c678dd}@media (prefers-color-scheme:dark){.syntect-code{color:#dcdfe4;background-color:#282c34}.syntect-comment{color:#5c6370}.syntect-variable.syntect-parameter.syntect-function{color:#dcdfe4}.syntect-keyword{color:#c678dd}.syntect-variable{color:#e06c75}.syntect-entity.syntect-name.syntect-function,.syntect-meta.syntect-require,.syntect-support.syntect-function.syntect-any-method{color:#61afef}.syntect-entity.syntect-name.syntect-class,.syntect-entity.syntect-name.syntect-type.syntect-class,.syntect-support.syntect-class{color:#e5c07b}.syntect-meta.syntect-class{color:#e5c07b}.syntect-keyword.syntect-other.syntect-special-method{color:#61afef}.syntect-storage{color:#c678dd}.syntect-support.syntect-function{color:#61afef}.syntect-string{color:#98c379}.syntect-constant.syntect-numeric{color:#e5c07b}.syntect-none{color:#e5c07b}.syntect-none{color:#e5c07b}.syntect-constant{color:#e5c07b}.syntect-entity.syntect-name.syntect-tag{color:#e06c75}.syntect-entity.syntect-other.syntect-attribute-name{color:#e5c07b}.syntect-entity.syntect-other.syntect-attribute-name.syntect-id,.syntect-punctuation.syntect-definition.syntect-entity{color:#e5c07b}.syntect-meta.syntect-selector{color:#c678dd}.syntect-entity.syntect-name.syntect-section,.syntect-markup.syntect-heading .syntect-punctuation.syntect-definition.syntect-heading{color:#61afef}.syntect-markup.syntect-bold,.syntect-punctuation.syntect-definition.syntect-bold{color:#c678dd}.syntect-markup.syntect-italic,.syntect-punctuation.syntect-definition.syntect-italic{color:#c678dd}.syntect-markup.syntect-raw.syntect-inline{color:#98c379}.syntect-meta.syntect-link{color:#98c379}.syntect-markup.syntect-quote{color:#98c379}.syntect-source.syntect-java .syntect-meta.syntect-class.syntect-java .syntect-meta.syntect-method.syntect-java{color:#dcdfe4}.syntect-source.syntect-java .syntect-meta.syntect-class.syntect-java .syntect-meta.syntect-class.syntect-body.syntect-java{color:#dcdfe4}.syntect-source.syntect-js .syntect-meta.syntect-function.syntect-js .syntect-variable.syntect-parameter.syntect-function.syntect-js{color:#e06c75}.syntect-source.syntect-js .syntect-variable.syntect-other.syntect-readwrite.syntect-js{color:#e06c75}.syntect-source.syntect-js .syntect-variable.syntect-other.syntect-object.syntect-js{color:#dcdfe4}.syntect-source.syntect-js .syntect-meta.syntect-function-call.syntect-method.syntect-js .syntect-variable.syntect-other.syntect-readwrite.syntect-js{color:#e06c75}.syntect-source.syntect-js .syntect-meta.syntect-block.syntect-js .syntect-variable.syntect-other.syntect-readwrite.syntect-js{color:#e06c75}.syntect-source.syntect-js .syntect-meta.syntect-block.syntect-js .syntect-variable.syntect-other.syntect-object.syntect-js{color:#dcdfe4}.syntect-source.syntect-js .syntect-meta.syntect-block.syntect-js .syntect-meta.syntect-function-call.syntect-method.syntect-js .syntect-variable.syntect-other.syntect-readwrite.syntect-js{color:#dcdfe4}.syntect-source.syntect-js .syntect-meta.syntect-function-call.syntect-method.syntect-js .syntect-variable.syntect-function.syntect-js{color:#dcdfe4}.syntect-source.syntect-js .syntect-meta.syntect-property.syntect-object.syntect-js .syntect-entity.syntect-name.syntect-function.syntect-js{color:#61afef}.syntect-source.syntect-js .syntect-support.syntect-constant.syntect-prototype.syntect-js{color:#dcdfe4}.syntect-markup.syntect-inserted{color:#98c379}.syntect-markup.syntect-deleted{color:#e06c75}.syntect-markup.syntect-changed{color:#e5c07b}.syntect-string.syntect-regexp{color:#98c379}.syntect-constant.syntect-character.syntect-escape{color:#56b6c2}.syntect-invalid.syntect-illegal{color:#dcdfe4;background-color:#e06c75}.syntect-invalid.syntect-broken{color:#dcdfe4;background-color:#e5c07b}.syntect-invalid.syntect-deprecated{color:#dcdfe4;background-color:#e5c07b}.syntect-invalid.syntect-unimplemented{color:#dcdfe4;background-color:#c678dd}} \ No newline at end of file diff --git a/static/samples_rust_coverage/tarpaulin-report.html b/static/samples_rust_coverage/tarpaulin-report.html new file mode 100644 index 00000000..457cf2b3 --- /dev/null +++ b/static/samples_rust_coverage/tarpaulin-report.html @@ -0,0 +1,660 @@ + + + + + + + +
+ + + + + + \ No newline at end of file From 6b125c35261a94fb1300dff7091e6a54e6dfb721 Mon Sep 17 00:00:00 2001 From: GrosQuildu Date: Fri, 12 Jan 2024 20:20:53 +0100 Subject: [PATCH 10/30] rust chapter - property testing --- .../{00-unit-tests.md => 00-unit-testing.md} | 114 +++++++++++++++++- .../docs/languages/rust/10-static-analysis.md | 7 +- 2 files changed, 109 insertions(+), 12 deletions(-) rename content/docs/languages/rust/{00-unit-tests.md => 00-unit-testing.md} (75%) diff --git a/content/docs/languages/rust/00-unit-tests.md b/content/docs/languages/rust/00-unit-testing.md similarity index 75% rename from content/docs/languages/rust/00-unit-tests.md rename to content/docs/languages/rust/00-unit-testing.md index 59b2dbd6..1ef8d46a 100644 --- a/content/docs/languages/rust/00-unit-tests.md +++ b/content/docs/languages/rust/00-unit-testing.md @@ -1,6 +1,6 @@ --- -title: "Unit tests" -slug: unit-tests +title: "Unit testing" +slug: unit-testing summary: "This section describes tricks for Rust unit testing" weight: 1 --- @@ -32,7 +32,7 @@ Please note that [`docs tests` don't work in binary targets](https://github.com/ Once you have your tests written and all of them passes, lets improve. -## Advanced usage +## Improvements ### Randomization @@ -247,7 +247,7 @@ mod tests { {{< /details >}} -### MIRI +### Miri [Miri](https://github.com/rust-lang/miri) is an interpreter for Rust "mid-level intermediate representation ". You can run your tests through Miri with: @@ -256,14 +256,109 @@ rustup +nightly component add miri cargo miri test ``` -Miri detects: +Miri helps to detect: * undefined behavior * memory corruption bugs +* memory leaks * uses of uninitialized data * memory alignment issues * issues with aliasing for reference types * data races +## Property testing with Proptest + +Normal unit tests are great for testing a single scenario - you test code by providing a single, specific +value and checking if the code behaves as expected. + +But instead of using a single value, you can generate a set of inputs and execute the unit test multiple times +to check if it works correctly for every input. + +Lets use [Proptest](https://github.com/proptest-rs/proptest) tool for that task. It is a tool inspired by the famous [QuickCheck](https://hackage.haskell.org/package/QuickCheck). + +### Installation + +Simply add the dev dependency to your project. Nothing more needed. + +```toml +[dev-dependencies] +proptest = "1.0.0" +``` + +### Usage + +To use Proptest you must write unit tests. But instead of hard-coding values that are used for testing, +you define *generators* for values (called "strategies" in proptest's docs). +Proptest will execute the unit test dozen of times with randomly generated values. + +Proptest ships with a dozen of [configurable strategies](https://docs.rs/proptest/latest/proptest/): +* range-like generator for `integers` +* regex generator for `strings` +* simple generators for `bits`, `bools`, `chars` +* random-size generators for `std:collections` +* generators for `Option` and `Result` + +The generators [can be combined together](https://proptest-rs.github.io/proptest/proptest/tutorial/macro-prop-compose.html). You can also use macros to do further combine and restric generation: +* do mapping with `prop_map` +* do filtering with `prop_filter` +* create enums with `prop_oneof` +* do recursion with `prop_recursive` + +Lets see an example code: + +```rust +fn simple_thingy_dingy(a: u64, b: &str) -> u64 { + return a + match b.parse::() { + Ok(x) => x, + Err(_) => b.len() as u64, + }; +} + +#[cfg(test)] +mod tests { + use crate::simple_thingy_dingy; + use proptest::prelude::*; + + proptest! { + #![proptest_config(ProptestConfig::with_cases(100))] + #[test] + fn test_simple_thingy_dingy(a in 1337..7331u64, b in "[0-9]{1,3}") { + println!("{a} | {b}"); + let sum = simple_thingy_dingy(a, &b); + assert!(sum >= a); + assert!(sum > 1337); + } + } +} +``` + +The `simple_thingy_dingy` is function we want to unit-test. For that we need to wrap a normal `#[test]` with `proptest!` helper. +Then we use two generators for `a` and `b` values: range-like for integers and regex for strings. + +Now we just need to run `cargo test` and wait for the Proptest to finish. Running `cargo test -- --show-output` +will enable us to observe what values were generated. + +By default Proptest executes an unit test 256 times, but we can change that with `ProptestConfig::with_cases`. + +If the Proptest finds an input failing the unit test, it writes the input to the `proptest-regressions` directory. + +As can be seen, we have to write a strategy for every single value we use. However, we could instead create [a strategy for a type](https://proptest-rs.github.io/proptest/proptest/tutorial/arbitrary.html) using the `Arbitrary` trait. + +{{< hint info >}} +**You can combine Proptest with other improvements** + +Using Proptest with improvements [listed above](/docs/languages/rust/unit-tests/#improvements) +can enhance your testing even further. + +To use with Proptest with Miri you have to disable persistence (the `proptest-regressions` directory): + +```sh +PROPTEST_DISABLE_FAILURE_PERSISTENCE=true \ +MIRIFLAGS='-Zmiri-env-forward=PROPTEST_DISABLE_FAILURE_PERSISTENCE' \ +cargo miri test +``` +{{< /hint >}} + + ## Coverage It is critically important to know how much coverage your tests have. Coverage gathering consists of three steps: @@ -295,7 +390,13 @@ Instead of them you can directly use [the tools described in the fuzzing chapter | Exclude tests' coverage | [With external module](https://github.com/taiki-e/coverage-helper/tree/v0.2.0) | `--ignore-tests` | No | | Coverage for C/C++ | [`--include-ffi`](https://github.com/taiki-e/cargo-llvm-cov?tab=readme-ov-file#get-coverage-of-cc-code-linked-to-rust-librarybinary) | `--follow-exec` | ? | | Merge data from multiple runs | [Yes](https://github.com/taiki-e/cargo-llvm-cov?tab=readme-ov-file#merge-coverages-generated-under-different-test-conditions) | [Yes/No](https://github.com/xd009642/tarpaulin?tab=readme-ov-file#command-line) (only shows delta) | No | -| HTML output properties | + +While checking coverage statistics from a command line and using one of many coverage-visualizers, +HTML report is often what you need. + +| HTML output \ Tool | `cargo-llvm-cov` | `cargo-tarpaulin` | `grcov` | +| ----------- | ----------- | ----------- | ----------- | +| Examples | [Open `llvm-cov`](/samples_rust_coverage/llvm_cov/index.html), [open `llvm-cov-pretty`](/samples_rust_coverage/llvm_cov_pretty/index.html) | [Open `tarpaulin`](/samples_rust_coverage/tarpaulin-report.html) | [Open `grcov`](/samples_rust_coverage/grcov/index.html), [open `grcov` with `lcov`](/samples_rust_coverage/grcov_lcov/index.html) | | Handles Rust's constructions | Yes | Yes | Yes | | Expands Rust's generics | `--show-instantiations` | No | No | | Number of hits | Yes | No | Yes | @@ -320,6 +421,7 @@ Go to the [Testing Handbook's repository `samples/rust_coverage`](https://github There you will find Dockerfile generating HTML reports using the described tools. {{< /details >}} + ## Validation of tests Who tests tests? What if your critical test has a bug that makes it to pass incorrectly? diff --git a/content/docs/languages/rust/10-static-analysis.md b/content/docs/languages/rust/10-static-analysis.md index b0e87607..c62e4ea9 100644 --- a/content/docs/languages/rust/10-static-analysis.md +++ b/content/docs/languages/rust/10-static-analysis.md @@ -60,11 +60,6 @@ cargo dylint --new Now implement the `LateLintPass` trait and accommodate the symbols asking to be filled in. -## Prusti - -* based on [Viper](https://www.pm.inf.ethz.ch/research/viper.html) -* detects panics and integer overflows - ## Semgrep -Check the [semgrep page](/docs/static-analysis/semgrep/). +Semgrep has a beta support for Rust language. Check the [semgrep page](/docs/static-analysis/semgrep/) for more information. From 8bdc881e6e6f4b8835188e9701bbf2380d045ef3 Mon Sep 17 00:00:00 2001 From: GrosQuildu Date: Fri, 12 Jan 2024 20:21:02 +0100 Subject: [PATCH 11/30] rust chapter - model checking --- .../languages/rust/20-dynamic-analysis.md | 43 ---- .../languages/rust/90-advanced-analysis.md | 232 ++++++++++++++++++ 2 files changed, 232 insertions(+), 43 deletions(-) delete mode 100644 content/docs/languages/rust/20-dynamic-analysis.md create mode 100644 content/docs/languages/rust/90-advanced-analysis.md diff --git a/content/docs/languages/rust/20-dynamic-analysis.md b/content/docs/languages/rust/20-dynamic-analysis.md deleted file mode 100644 index ac415813..00000000 --- a/content/docs/languages/rust/20-dynamic-analysis.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -title: "Property testing" -slug: rust-property-testing -summary: "This section describes nuances of Rust property testing" -weight: 20 ---- - -# Basic property testing tools - -- Use [proptest](https://docs.rs/proptest/latest/proptest/) - - inspired by QuickCheck - - write "randomized" unit tests -- Use [Kani](https://github.com/model-checking/kani) - - frontend for [cbmc](https://www.cprover.org/cbmc/) - - write "randomized" unit tests -- Use [Creusot](https://github.com/xldenis/creusot) - - based on [Why3](https://why3.lri.fr/) - - annotate functions with "contract expressions" (requires, ensures, invariant and variant) - -# Advanced property testing tools - -- Use [Crux](https://github.com/GaloisInc/crucible/blob/master/crux-mir/README.md) - - symbolic analysis - - write "symbolized" unit tests -- Use [Flux](https://github.com/flux-rs/flux) - - refinement type checker - - annotate functions with complex conditions -- Use [MIRAI](https://github.com/facebookexperimental/MIRAI) - - implements abstract interpretation, taint analysis, and constant time analysis - - experimantal stuff - - requires heavy dev work to implement something usefull -- Use [Stateright](https://www.stateright.rs/title-page.html) - - TLA+ for rust - - lets you model state machine of a system and test properties on it - - heavy stuff - -# Concurrency testing tools - -- Run [`Shuttle`](https://github.com/awslabs/shuttle) - - randomized and lightweight testing - -- Run [`Loom`](https://docs.rs/loom/latest/loom/) - - sound but slow testing diff --git a/content/docs/languages/rust/90-advanced-analysis.md b/content/docs/languages/rust/90-advanced-analysis.md new file mode 100644 index 00000000..16548e1e --- /dev/null +++ b/content/docs/languages/rust/90-advanced-analysis.md @@ -0,0 +1,232 @@ +--- +title: "Model checking" +slug: rust-advanced-testing +summary: "This section lists advanced testing tools for Rust" +weight: 20 +--- + +# Model checking + +Model checking is about verification that a program works correctly for all possible inputs. + +Instead of testing with a single value (like with unit testing) or with a set of values (like with property testing) +we check all possible values - and hope that smart algorithms will make it possible to finish testing in a reasonable time. + +## Prusti + +[Prusti](https://github.com/viperproject/prusti-dev) is based on [Viper](https://www.pm.inf.ethz.ch/research/viper.html) - a framework for building verification tools. +It uses symbolic execution and [Z3 Theorem Prover](https://github.com/Z3Prover/z3). + +### Installation + +Authors recommend using [Visual Studio Code extension](https://marketplace.visualstudio.com/items?itemName=viper-admin.prusti-assistant). Command-line tools can be [downloaded from GitHub's Releases](https://github.com/viperproject/prusti-dev/releases) + + +### Usage + +You can simply run Prusti on your code and it will look for: +* absence of reachable panics +* absence of reachable, failing assertions +* absence of integer overflows + +Prusti detects all functions in a project (even unreachable ones) and checks them "independently". +It simply assumes that functions arguments can take any value - are bounded only by their types. + +Please note that Prusti [does not check testing code](https://viperproject.github.io/prusti-dev/user-guide/tour/testing.html). + +To restrict values, and to define more code's properties for verification, we have to +create specifications for functions. + +#### Function specifications + +The main power of Prusti lays in its ability to specify and validate functions' contracts (or specifications). +A function's specification consists of pre- and post-conditions. + +* Pre-conditions + * are checked *before* calls + * Prust verifies that all calls to the function are done with arguments meeting the pre-conditions + * Pre-condition limits set of possible values for post-condition checks +* Post-conditions + * are checked *after* function returns + * Prust verifies that post-conditions are meet at all exit-points of the function + +In the example below, conditions are implemented with Rust attributes: +`requires` (pre-) and `ensures` (post-). + +Prusti will check if all calls to `prusti_check` pass the argument that is less or equal to 20. + +Then it will check if possible return values from the `prusti_check` function are below 10 - assuming +the input is less or equal to 20. + +```rust +use prusti_contracts::*; +fn main() { + prusti_check(20); + prusti_check(11); +} + +#[requires(x <= 20)] +#[ensures(x < 10)] +fn prusti_check(x: u32) -> u32 { + if x >= 10 { + return x / 100; + } + return x; +} +``` + +If values violating conditions are found, Prusti retruns an error and can produce [an example set of values that demonstrate the problem](https://viperproject.github.io/prusti-dev/user-guide/verify/counterexample.html). + +{{< hint danger >}} +**Prusti does not support loops automatically** + +You have to specify [`body_invariant`s](https://viperproject.github.io/prusti-dev/user-guide/tour/loop_invariants.html) to enable code verification. +{{< /hint >}} + + +## Kani + +[Kani](https://github.com/model-checking/kani) is a frontend for [CBMC](https://www.cprover.org/cbmc/) (Bounded Model Checker for C and C++). + +### Installation + +You can [simply use cargo for installation](https://model-checking.github.io/kani/install-guide.html). + +```sh +cargo install --locked kani-verifier +cargo kani setup +``` + +### Basic usage + +Kani reasembles normal unit tests writing. You have to write a test and run + +```sh +cargo kani +``` + +However, instead of using concrete values, use `kani::any()` to create a "symbolic" (or unbounded or nondeterministic) variable. +Such variable can take any value (of its type). + +Runnig the test, Kani will verify absence of the following conditions for all poosible values +of the symbolic variables: +* failing assertions +* panics +* memory safety issues +* integer overflows + +If the code to test is too complex, Kani may take long time to finish or even not terminate at all. +To overcome this, we can use three features: + +* [`kani::assume`](https://model-checking.github.io/kani/tutorial-first-steps.html#assertions-assumptions-and-harnesses) - for restricting (bounding) symbolic values. It is a bit similar to [Prusti's pre-conditions](/docs/languages/rust/rust-advanced-testing/#function-specifications) +* [`kani::unwind`](https://model-checking.github.io/kani/tutorial-loop-unwinding.html) - for controlling bounds for loops. Kani will assume that loops can loop only the configured +amount of times. Greater the amount, slower the execution. But configuring the amount to be too small, Kani will fail too early. This is the mechanism that overcomes [Prusti's limitation with the `body_invariant`](http://localhost:1313/docs/languages/rust/rust-advanced-testing/#usage). +* [`kani::Arbitrary`](https://model-checking.github.io/kani/tutorial-nondeterministic-variables.html#custom-nondeterministic-types) - for defining per-type limitations for symbolic values + + +Lets see an example: + +```rust +pub struct Book { + title: String, + pages: u16 +} + +fn read_book(r: Book) -> u16 { + return if r.title == "The Black Book" { + 0 + } else { + let mut letters = 0; + for page in 0..r.pages { + if page == 13 { + panic!("Bad luck"); + } + letters += page; + } + letters + } +} + +#[cfg(kani)] +mod verification { + use crate::{Book, read_book}; + + impl kani::Arbitrary for Book { + fn any() -> Self { + let titles = vec!["The Black Book", "Lord of the ToB", + "The White Book"]; + let title_id: usize = kani::any(); + kani::assume(title_id < titles.len()); + Book { title: titles[title_id].to_string(), pages: kani::any() } + } + } + + #[kani::proof] + #[kani::unwind(18)] + fn verify_book() { + let book: Book = kani::any(); + kani::assume(book.pages < 4096); + let y = read_book(book); + assert!(y < 100); + } +} +``` + +Here we have a simple structure and a function that panics for some inputs. + +We define a new `verification` module under `cfg(kani)` attribute - this lets us disable Kani-specific code when +not needed. Then we implement `kani::Arbitrary` trait to tell Kani how to generate symbolic `Book`s: +by limiting set of `title`s to three possible values and using unbounded number the `pages` field. + +Then we use the `#[kani::proof]` attribute and write a test similar to normal unit tests. With three main differences: +* generating symbolic `book` variable (using our `kani::Arbitrary` implementation) +* restricting `book.pages` to be less than 4096 +* limiting amount of loops to 20 with `#[kani::unwind(20)]` + +[Kani documenatation recommends](https://model-checking.github.io/kani/tutorial-loop-unwinding.html) to set the `kani::unwind` experimentaly: +* start with a number a bit larger than the maximum of the expected numbers of all loops' repetitions +* if Kali takes too much time to finish - lower the `unwind` number +* if Kali errors out with `FAILURE: unwinding assertion loop X` - increase the `unwind` number + +If Kali found a `FAILURE`, then we can generate example values that will trigger the failure with one of two mthods: +* generating a normal unit test with `cargo kani --concrete-playback print -Z concrete-playback` +* generating a HTML report with `cargo kani --visualize --enable-unstable` + +{{< hint danger >}} +**Kali does not scale well for:** + +* strings with unbounded content (i.e., long strings with arbitrary data) +* structures of symbolic sizes that involves heap allocations +{{< /hint >}} + + +## Other model checkers + +#### [Creusot](https://github.com/xldenis/creusot) +- based on [Why3](https://why3.lri.fr/) +- allows to provide and verify functions specifications + +#### [Crux](https://github.com/GaloisInc/crucible/blob/master/crux-mir/README.md) +- symbolic analysis +- enables writing "symbolized" unit tests + +#### [Flux](https://github.com/flux-rs/flux) +- refinement type checker +- allows you to annotate functions with complex conditions + +#### [MIRAI](https://github.com/facebookexperimental/MIRAI) +- implements abstract interpretation, taint analysis, and constant time analysis + +#### [Stateright](https://www.stateright.rs/title-page.html) +- TLA+ for rust +- lets you model state machine of a system and test properties on it + +## Concurrency testing + +#### [`Shuttle`](https://github.com/awslabs/shuttle) +- is un-sound, but is scalable +- does random testing, analogously to the property testing + +#### [`Loom`](https://docs.rs/loom/latest/loom/) +- is sound, but slow +- works analogously to model checkers From ded78a195de67c5b46eb4a3eda46247e4a779dba Mon Sep 17 00:00:00 2001 From: GrosQuildu Date: Fri, 12 Jan 2024 20:31:48 +0100 Subject: [PATCH 12/30] rust chapter - target blank --- content/docs/languages/rust/00-unit-testing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/languages/rust/00-unit-testing.md b/content/docs/languages/rust/00-unit-testing.md index 1ef8d46a..4b898bf0 100644 --- a/content/docs/languages/rust/00-unit-testing.md +++ b/content/docs/languages/rust/00-unit-testing.md @@ -396,7 +396,7 @@ HTML report is often what you need. | HTML output \ Tool | `cargo-llvm-cov` | `cargo-tarpaulin` | `grcov` | | ----------- | ----------- | ----------- | ----------- | -| Examples | [Open `llvm-cov`](/samples_rust_coverage/llvm_cov/index.html), [open `llvm-cov-pretty`](/samples_rust_coverage/llvm_cov_pretty/index.html) | [Open `tarpaulin`](/samples_rust_coverage/tarpaulin-report.html) | [Open `grcov`](/samples_rust_coverage/grcov/index.html), [open `grcov` with `lcov`](/samples_rust_coverage/grcov_lcov/index.html) | +| Examples | [Open `llvm-cov`](/samples_rust_coverage/llvm_cov/index.html?:), [open `llvm-cov-pretty`](/samples_rust_coverage/llvm_cov_pretty/index.html?:) | [Open `tarpaulin`](/samples_rust_coverage/tarpaulin-report.html?:) | [Open `grcov`](/samples_rust_coverage/grcov/index.html?:), [open `grcov` with `lcov`](/samples_rust_coverage/grcov_lcov/index.html?:) | | Handles Rust's constructions | Yes | Yes | Yes | | Expands Rust's generics | `--show-instantiations` | No | No | | Number of hits | Yes | No | Yes | From c1e6d94901e91902e82250365779aaa9d1295cfb Mon Sep 17 00:00:00 2001 From: Maciej Domanski <38883201+ahpaleus@users.noreply.github.com> Date: Fri, 23 Feb 2024 19:48:40 +0100 Subject: [PATCH 13/30] test --- content/docs/languages/rust/00-unit-testing.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/content/docs/languages/rust/00-unit-testing.md b/content/docs/languages/rust/00-unit-testing.md index 4b898bf0..46292a3e 100644 --- a/content/docs/languages/rust/00-unit-testing.md +++ b/content/docs/languages/rust/00-unit-testing.md @@ -7,7 +7,8 @@ weight: 1 # Unit tests -This is the most basic type of testing that every project should have. Unit tests are easy to execute, low-effort to implement, and catch a lot of simple mistakes. +This is the most basic type of testing that every project should have. +Unit tests are easy to execute, low-effort to implement, and catch a lot of simple mistakes. ## Installation and first steps From 724eb51e37f0215d37f200b523b72ce21b8d0c44 Mon Sep 17 00:00:00 2001 From: Maciej Domanski <38883201+ahpaleus@users.noreply.github.com> Date: Fri, 23 Feb 2024 19:55:50 +0100 Subject: [PATCH 14/30] Update _index.md --- content/docs/languages/_index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/languages/_index.md b/content/docs/languages/_index.md index 871af99a..6a66558f 100644 --- a/content/docs/languages/_index.md +++ b/content/docs/languages/_index.md @@ -1,5 +1,5 @@ --- -weight: 2 +weight: 3 bookFlatSection: true title: "Languages" --- From 076b9e856180e32a92da4469c750b818867eca4a Mon Sep 17 00:00:00 2001 From: Maciej Domanski <38883201+ahpaleus@users.noreply.github.com> Date: Fri, 23 Feb 2024 19:58:27 +0100 Subject: [PATCH 15/30] Undraft to see in PR Preview --- content/docs/languages/rust/_index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/languages/rust/_index.md b/content/docs/languages/rust/_index.md index 53702f90..6f1d19f7 100644 --- a/content/docs/languages/rust/_index.md +++ b/content/docs/languages/rust/_index.md @@ -2,7 +2,7 @@ title: "Rust" weight: 2 summary: "Rust is a multi-paradigm, general-purpose, memory-safe programming language." -draft: true +# draft: true # bookFlatSection: false # bookToc: true # bookHidden: false From 4b9ea40244517f4a8c4ae9879f93527cdbea4424 Mon Sep 17 00:00:00 2001 From: Maciej Domanski <38883201+ahpaleus@users.noreply.github.com> Date: Fri, 23 Feb 2024 20:09:15 +0100 Subject: [PATCH 16/30] Update _index.md --- content/docs/languages/rust/_index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/languages/rust/_index.md b/content/docs/languages/rust/_index.md index 6f1d19f7..5a3e2c56 100644 --- a/content/docs/languages/rust/_index.md +++ b/content/docs/languages/rust/_index.md @@ -1,6 +1,6 @@ --- title: "Rust" -weight: 2 +weight: 3 summary: "Rust is a multi-paradigm, general-purpose, memory-safe programming language." # draft: true # bookFlatSection: false From 0ebf4105b56362719b51446e0d5ea86a5da009c0 Mon Sep 17 00:00:00 2001 From: GrosQuildu Date: Thu, 9 May 2024 19:31:41 +0200 Subject: [PATCH 17/30] [rust] start supply chain section --- .../docs/languages/rust/00-unit-testing.md | 11 ++- ...anced-analysis.md => 20-model-checking.md} | 11 +-- .../languages/rust/30-concurrency-testing.md | 17 +++++ .../rust/40-supply-chain-analysis.md | 75 +++++++++++++++++++ 4 files changed, 100 insertions(+), 14 deletions(-) rename content/docs/languages/rust/{90-advanced-analysis.md => 20-model-checking.md} (96%) create mode 100644 content/docs/languages/rust/30-concurrency-testing.md create mode 100644 content/docs/languages/rust/40-supply-chain-analysis.md diff --git a/content/docs/languages/rust/00-unit-testing.md b/content/docs/languages/rust/00-unit-testing.md index 46292a3e..4e26d272 100644 --- a/content/docs/languages/rust/00-unit-testing.md +++ b/content/docs/languages/rust/00-unit-testing.md @@ -1,11 +1,12 @@ --- title: "Unit testing" -slug: unit-testing +slug: rust-unit-testing summary: "This section describes tricks for Rust unit testing" weight: 1 --- -# Unit tests + +# Unit testing This is the most basic type of testing that every project should have. Unit tests are easy to execute, low-effort to implement, and catch a lot of simple mistakes. @@ -484,7 +485,9 @@ mod tests { {{< /details >}} +Necessist is slow and sometimes produces false positives. We recommend running it manually from time to time, instead of in a CI pipeline. The database should be kept between runs to accellerate new tests. Please report any false-positives on GitHub. + ## Resources -* ["The Rust Programming Language", chapter 11. Testing](https://web.mit.edu/rust-lang_v1.25/arch/amd64_ubuntu1404/share/doc/rust/html/book/second-edition/ch11-00-testing.html) - the basics of unit and integration testing in Rust -* [Ed Page's "Iterating on Testing in Rust"](https://epage.github.io/blog/2023/06/iterating-on-test/) - lists potential issues with `cargo test` and introduces `cargo-nextest` +* ["The Rust Programming Language", chapter 11. Testing](https://web.mit.edu/rust-lang_v1.25/arch/amd64_ubuntu1404/share/doc/rust/html/book/second-edition/ch11-00-testing.html): the basics of unit and integration testing in Rust +* [Ed Page's "Iterating on Testing in Rust"](https://epage.github.io/blog/2023/06/iterating-on-test/): lists potential issues with `cargo test` and introduces `cargo-nextest` diff --git a/content/docs/languages/rust/90-advanced-analysis.md b/content/docs/languages/rust/20-model-checking.md similarity index 96% rename from content/docs/languages/rust/90-advanced-analysis.md rename to content/docs/languages/rust/20-model-checking.md index 16548e1e..1571496c 100644 --- a/content/docs/languages/rust/90-advanced-analysis.md +++ b/content/docs/languages/rust/20-model-checking.md @@ -1,6 +1,6 @@ --- title: "Model checking" -slug: rust-advanced-testing +slug: rust-model-checking summary: "This section lists advanced testing tools for Rust" weight: 20 --- @@ -221,12 +221,3 @@ If Kali found a `FAILURE`, then we can generate example values that will trigger - TLA+ for rust - lets you model state machine of a system and test properties on it -## Concurrency testing - -#### [`Shuttle`](https://github.com/awslabs/shuttle) -- is un-sound, but is scalable -- does random testing, analogously to the property testing - -#### [`Loom`](https://docs.rs/loom/latest/loom/) -- is sound, but slow -- works analogously to model checkers diff --git a/content/docs/languages/rust/30-concurrency-testing.md b/content/docs/languages/rust/30-concurrency-testing.md new file mode 100644 index 00000000..865db516 --- /dev/null +++ b/content/docs/languages/rust/30-concurrency-testing.md @@ -0,0 +1,17 @@ +--- +title: "Concurrency testing" +slug: rust-concurrency-testing +summary: "This section lists advanced testing tools for Rust" +weight: 30 +--- + +## Concurrency testing + +#### [`Shuttle`](https://github.com/awslabs/shuttle) +- is un-sound, but is scalable +- does random testing, analogously to the property testing + +#### [`Loom`](https://docs.rs/loom/latest/loom/) +- is sound, but slow +- works analogously to model checkers + diff --git a/content/docs/languages/rust/40-supply-chain-analysis.md b/content/docs/languages/rust/40-supply-chain-analysis.md new file mode 100644 index 00000000..503c643d --- /dev/null +++ b/content/docs/languages/rust/40-supply-chain-analysis.md @@ -0,0 +1,75 @@ +--- +title: "Supply chain analysis" +slug: rust-supply-chain-analysis +summary: "This section describes tricks for Rust unit testing" +weight: 40 +--- + +# Supply chain analysis + +## Vetting + +The tools in this section are more for "understanding" than "checking." E.g., running them does not produce "bug reports", but can help you assess maturity and security of dependencies. Tools below are rather "quantitative" than "qualitative" - you will need to do manuall, in-depth review of the outputs to extract any solid evidences about the maturity. + + Run cargo-supply-chain +This reveals who you are implicitly trusting when you rely on a dependency (e.g., you want that set to be small) + Run cargo-vet +This checks if dependencies were audited by a "trusted party" +rust-crate-audits - collection of Google's audits + Run cargo-crev +This is a distrubuted core-review platform + Run cargo-deny +Cargo plugin for linting your dependencies + + + +## Looking for vulnerabilities + +The ultimate tool for detection of vulnerabilities is `cargo-audit` - you should just use it. +The [`cargo-audit` compares dependencies]() against a database with known vulnerabilities: + +```bash +cargo audit +``` + +### Old versions + +Even if a dependency doesn't have vulns, it's still worth knowing if it can be updated. + +For that task you [use `cargo-outdated` tool](https://github.com/kbknapp/cargo-outdated), which lists dependencies that have newer versions available: + +```bash +cargo outdated --workspace +``` + +{{< hint info >}} +"Removed" label in the output means that the dependency would be removed from the dependency tree if its parent was updated. +{{< /hint >}} + +Another way to detect crates with newer versions [available is to use `cargo-edit`](https://github.com/killercup/cargo-edit?tab=readme-ov-file#cargo-upgrade): +```bash +cargo upgrade --incompatible --dry-run +``` + +### Divergent versions + +It may happen that your project depends on multiple different versions of the same dependency. +While that's not necessarily a security problem, it's better to limit number of divergent versions of a crate. + +To detect dependencies with multiple versions [use the `cargo-deny`](https://github.com/EmbarkStudios/cargo-deny): + +```bash +cargo deny check bans --exclude-dev +``` + +{{< hint info >}} +Look for `warning[duplicate]` outputs. +{{< /hint >}} + + +Similarly, a dependency that is obtained from multiple sources (e.g., `crates.io` and `github.com`) may indicate some issues. +To report such offending dependencies use [cargo-vendor](https://doc.rust-lang.org/cargo/commands/cargo-vendor.html): + +```bash +cargo vendor --locked ./tmp_path +``` From bcaa89bbbd66969b065fbfd2698c8dc2bbe6f6c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20P=C5=82atek?= Date: Mon, 25 Nov 2024 13:02:03 +0100 Subject: [PATCH 18/30] Update content/docs/languages/rust/00-unit-testing.md Co-authored-by: Samuel Moelius <35515885+smoelius@users.noreply.github.com> --- content/docs/languages/rust/00-unit-testing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/languages/rust/00-unit-testing.md b/content/docs/languages/rust/00-unit-testing.md index 4e26d272..df583487 100644 --- a/content/docs/languages/rust/00-unit-testing.md +++ b/content/docs/languages/rust/00-unit-testing.md @@ -13,7 +13,7 @@ Unit tests are easy to execute, low-effort to implement, and catch a lot of simp ## Installation and first steps -The standard and ultimate tool for executing unit and integration tests for Rust codebases is the `cargo test`. +The standard and ultimate tool for executing unit and integration tests for Rust codebases is `cargo test`. The basic setup and usage of `cargo test` is well-known, so we will skip the introduction. You can also try [the `cargo-nextest`](https://nexte.st/index.html) - a new test runner. From b1034a4ce24601895aea2a5743ca2b63c52179b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20P=C5=82atek?= Date: Mon, 25 Nov 2024 13:02:26 +0100 Subject: [PATCH 19/30] Update content/docs/languages/rust/40-supply-chain-analysis.md Co-authored-by: Samuel Moelius <35515885+smoelius@users.noreply.github.com> --- content/docs/languages/rust/40-supply-chain-analysis.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/languages/rust/40-supply-chain-analysis.md b/content/docs/languages/rust/40-supply-chain-analysis.md index 503c643d..658ae0ba 100644 --- a/content/docs/languages/rust/40-supply-chain-analysis.md +++ b/content/docs/languages/rust/40-supply-chain-analysis.md @@ -17,7 +17,7 @@ This reveals who you are implicitly trusting when you rely on a dependency (e.g. This checks if dependencies were audited by a "trusted party" rust-crate-audits - collection of Google's audits Run cargo-crev -This is a distrubuted core-review platform +This is a distributed core-review platform Run cargo-deny Cargo plugin for linting your dependencies From 1b74a2d2d8c309b5f1739030dc5dee86c6d2cbfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20P=C5=82atek?= Date: Mon, 25 Nov 2024 13:02:32 +0100 Subject: [PATCH 20/30] Update content/docs/languages/rust/40-supply-chain-analysis.md Co-authored-by: Samuel Moelius <35515885+smoelius@users.noreply.github.com> --- content/docs/languages/rust/40-supply-chain-analysis.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/languages/rust/40-supply-chain-analysis.md b/content/docs/languages/rust/40-supply-chain-analysis.md index 658ae0ba..9965d764 100644 --- a/content/docs/languages/rust/40-supply-chain-analysis.md +++ b/content/docs/languages/rust/40-supply-chain-analysis.md @@ -68,7 +68,7 @@ Look for `warning[duplicate]` outputs. Similarly, a dependency that is obtained from multiple sources (e.g., `crates.io` and `github.com`) may indicate some issues. -To report such offending dependencies use [cargo-vendor](https://doc.rust-lang.org/cargo/commands/cargo-vendor.html): +To report such offending dependencies, use [cargo-vendor](https://doc.rust-lang.org/cargo/commands/cargo-vendor.html): ```bash cargo vendor --locked ./tmp_path From e04b4942202ec8ad1acd8a6edd7454645bd03043 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20P=C5=82atek?= Date: Mon, 25 Nov 2024 13:02:38 +0100 Subject: [PATCH 21/30] Update content/docs/languages/rust/40-supply-chain-analysis.md Co-authored-by: Samuel Moelius <35515885+smoelius@users.noreply.github.com> --- content/docs/languages/rust/40-supply-chain-analysis.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/languages/rust/40-supply-chain-analysis.md b/content/docs/languages/rust/40-supply-chain-analysis.md index 9965d764..9af56953 100644 --- a/content/docs/languages/rust/40-supply-chain-analysis.md +++ b/content/docs/languages/rust/40-supply-chain-analysis.md @@ -46,7 +46,7 @@ cargo outdated --workspace "Removed" label in the output means that the dependency would be removed from the dependency tree if its parent was updated. {{< /hint >}} -Another way to detect crates with newer versions [available is to use `cargo-edit`](https://github.com/killercup/cargo-edit?tab=readme-ov-file#cargo-upgrade): +Another way to detect crates with newer versions available [is to use `cargo-edit`](https://github.com/killercup/cargo-edit?tab=readme-ov-file#cargo-upgrade): ```bash cargo upgrade --incompatible --dry-run ``` From 54751d4903efc4368b867cc44a0f27f0cc817e8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20P=C5=82atek?= Date: Mon, 25 Nov 2024 13:02:44 +0100 Subject: [PATCH 22/30] Update content/docs/languages/rust/40-supply-chain-analysis.md Co-authored-by: Samuel Moelius <35515885+smoelius@users.noreply.github.com> --- content/docs/languages/rust/40-supply-chain-analysis.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/languages/rust/40-supply-chain-analysis.md b/content/docs/languages/rust/40-supply-chain-analysis.md index 9af56953..5eb1a585 100644 --- a/content/docs/languages/rust/40-supply-chain-analysis.md +++ b/content/docs/languages/rust/40-supply-chain-analysis.md @@ -36,7 +36,7 @@ cargo audit Even if a dependency doesn't have vulns, it's still worth knowing if it can be updated. -For that task you [use `cargo-outdated` tool](https://github.com/kbknapp/cargo-outdated), which lists dependencies that have newer versions available: +For that task, you [use `cargo-outdated` tool](https://github.com/kbknapp/cargo-outdated), which lists dependencies that have newer versions available: ```bash cargo outdated --workspace From bd205152e6ff31db76703bd121b514e428661495 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20P=C5=82atek?= Date: Mon, 25 Nov 2024 13:02:52 +0100 Subject: [PATCH 23/30] Update content/docs/languages/rust/00-unit-testing.md Co-authored-by: Samuel Moelius <35515885+smoelius@users.noreply.github.com> --- content/docs/languages/rust/00-unit-testing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/languages/rust/00-unit-testing.md b/content/docs/languages/rust/00-unit-testing.md index df583487..ea9ee7c2 100644 --- a/content/docs/languages/rust/00-unit-testing.md +++ b/content/docs/languages/rust/00-unit-testing.md @@ -48,7 +48,7 @@ Better to run tests in a random order without parallel execution. cargo test -- -Z unstable-options --test-threads 1 --shuffle ``` -Execute command above multiple times. If any run reported a failed test use the displayed "shuffle seed" to reliably repeat the error: +Execute command above multiple times. If any run reports a failed test, use the displayed "shuffle seed" to reliably repeat the error: ```sh cargo test -- -Z unstable-options --test-threads 1 --shuffle-seed 7331 From da5e38b308dea87b7452b497a3e395d763689865 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20P=C5=82atek?= Date: Mon, 25 Nov 2024 13:02:58 +0100 Subject: [PATCH 24/30] Update content/docs/languages/rust/00-unit-testing.md Co-authored-by: Samuel Moelius <35515885+smoelius@users.noreply.github.com> --- content/docs/languages/rust/00-unit-testing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/languages/rust/00-unit-testing.md b/content/docs/languages/rust/00-unit-testing.md index ea9ee7c2..352c3d70 100644 --- a/content/docs/languages/rust/00-unit-testing.md +++ b/content/docs/languages/rust/00-unit-testing.md @@ -38,7 +38,7 @@ Once you have your tests written and all of them passes, lets improve. ### Randomization -First lets make sure that tests do not depend on a global state and that there are no unwanted dependencies between them. +First let's make sure that tests do not depend on a global state and that there are no unwanted dependencies between them. For that you can run tests multiple times, taking advantage of the enabled-by-default parallel execution. However, this approach is not optimal. That is because tests are executed in basically alphabetical order, even when multi-threaded. From baff006d5ecf490600521c6701d4545ac7782b60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20P=C5=82atek?= Date: Mon, 25 Nov 2024 13:03:05 +0100 Subject: [PATCH 25/30] Update content/docs/languages/rust/00-unit-testing.md Co-authored-by: Samuel Moelius <35515885+smoelius@users.noreply.github.com> --- content/docs/languages/rust/00-unit-testing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/languages/rust/00-unit-testing.md b/content/docs/languages/rust/00-unit-testing.md index 352c3d70..87a1cebc 100644 --- a/content/docs/languages/rust/00-unit-testing.md +++ b/content/docs/languages/rust/00-unit-testing.md @@ -32,7 +32,7 @@ mod tests { Please note that [`docs tests` don't work in binary targets](https://github.com/rust-lang/rust/issues/50784). -Once you have your tests written and all of them passes, lets improve. +Once you have your tests written and all of them pass, let's improve. ## Improvements From f1f63dc5ffd8dc3a6b883de81a0496e57d1c5b8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20P=C5=82atek?= Date: Mon, 25 Nov 2024 13:03:11 +0100 Subject: [PATCH 26/30] Update content/docs/languages/rust/00-unit-testing.md Co-authored-by: Samuel Moelius <35515885+smoelius@users.noreply.github.com> --- content/docs/languages/rust/00-unit-testing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/languages/rust/00-unit-testing.md b/content/docs/languages/rust/00-unit-testing.md index 87a1cebc..cbc3b451 100644 --- a/content/docs/languages/rust/00-unit-testing.md +++ b/content/docs/languages/rust/00-unit-testing.md @@ -16,7 +16,7 @@ Unit tests are easy to execute, low-effort to implement, and catch a lot of simp The standard and ultimate tool for executing unit and integration tests for Rust codebases is `cargo test`. The basic setup and usage of `cargo test` is well-known, so we will skip the introduction. -You can also try [the `cargo-nextest`](https://nexte.st/index.html) - a new test runner. +You can also try [`cargo-nextest`](https://nexte.st/index.html) - a new test runner. ```rust From e4cb1c68e4906bbf8dbc86ef5757937841a3764a Mon Sep 17 00:00:00 2001 From: GrosQuildu Date: Mon, 25 Nov 2024 13:07:48 +0100 Subject: [PATCH 27/30] merge --- .../docs/languages/rust/20-model-checking.md | 3 ++ .../languages/rust/30-concurrency-testing.md | 1 + .../rust/40-supply-chain-analysis.md | 34 +++++++++++++------ 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/content/docs/languages/rust/20-model-checking.md b/content/docs/languages/rust/20-model-checking.md index 1571496c..91dc6cc8 100644 --- a/content/docs/languages/rust/20-model-checking.md +++ b/content/docs/languages/rust/20-model-checking.md @@ -12,6 +12,9 @@ Model checking is about verification that a program works correctly for all poss Instead of testing with a single value (like with unit testing) or with a set of values (like with property testing) we check all possible values - and hope that smart algorithms will make it possible to finish testing in a reasonable time. +tldr; these tools are overkill and you don't need them. If you do, then this handbook is far too less to get you started. +But read on for a nice overview. + ## Prusti [Prusti](https://github.com/viperproject/prusti-dev) is based on [Viper](https://www.pm.inf.ethz.ch/research/viper.html) - a framework for building verification tools. diff --git a/content/docs/languages/rust/30-concurrency-testing.md b/content/docs/languages/rust/30-concurrency-testing.md index 865db516..813be514 100644 --- a/content/docs/languages/rust/30-concurrency-testing.md +++ b/content/docs/languages/rust/30-concurrency-testing.md @@ -15,3 +15,4 @@ weight: 30 - is sound, but slow - works analogously to model checkers +https://github.com/BurtonQin/lockbud diff --git a/content/docs/languages/rust/40-supply-chain-analysis.md b/content/docs/languages/rust/40-supply-chain-analysis.md index 5eb1a585..e3dfb96a 100644 --- a/content/docs/languages/rust/40-supply-chain-analysis.md +++ b/content/docs/languages/rust/40-supply-chain-analysis.md @@ -11,22 +11,34 @@ weight: 40 The tools in this section are more for "understanding" than "checking." E.g., running them does not produce "bug reports", but can help you assess maturity and security of dependencies. Tools below are rather "quantitative" than "qualitative" - you will need to do manuall, in-depth review of the outputs to extract any solid evidences about the maturity. - Run cargo-supply-chain -This reveals who you are implicitly trusting when you rely on a dependency (e.g., you want that set to be small) - Run cargo-vet -This checks if dependencies were audited by a "trusted party" -rust-crate-audits - collection of Google's audits - Run cargo-crev -This is a distributed core-review platform - Run cargo-deny -Cargo plugin for linting your dependencies +This reveals who you are implicitly trusting when you rely on a dependency (e.g., you want that set to be small): +```bash +cargo-supply-chain +``` + +This checks if dependencies were audited by a "trusted party": +```bash +cargo-vet +``` + +* rust-crate-audits - collection of Google's audits + +This is a distrubuted core-review platform: +```bash +cargo-crev +``` + +Cargo plugin for linting your dependencies: +```bash +cargo-deny +``` ## Looking for vulnerabilities -The ultimate tool for detection of vulnerabilities is `cargo-audit` - you should just use it. -The [`cargo-audit` compares dependencies]() against a database with known vulnerabilities: +The ultimate tool for detection of vulnerabilities is [`cargo-audit`]() - you should just use it. +The tool compares dependencies against a database with known vulnerabilities: ```bash cargo audit From e1c7440a2a619747561f20cc052093c2e9d0e229 Mon Sep 17 00:00:00 2001 From: GrosQuildu Date: Wed, 27 Nov 2024 13:32:20 +0100 Subject: [PATCH 28/30] add code from the chapter as cargo project --- samples/rust_tests/Cargo.lock | 427 +++++++++++++++++++++++++++ samples/rust_tests/Cargo.toml | 13 + samples/rust_tests/src/main.rs | 64 ++++ samples/rust_tests/src/unit_tests.rs | 118 ++++++++ 4 files changed, 622 insertions(+) create mode 100644 samples/rust_tests/Cargo.lock create mode 100644 samples/rust_tests/Cargo.toml create mode 100644 samples/rust_tests/src/main.rs create mode 100644 samples/rust_tests/src/unit_tests.rs diff --git a/samples/rust_tests/Cargo.lock b/samples/rust_tests/Cargo.lock new file mode 100644 index 00000000..48bc4c54 --- /dev/null +++ b/samples/rust_tests/Cargo.lock @@ -0,0 +1,427 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cast_checks" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a972b2e7af7903f86a571f50d30d4646fb750ccb294d2a79c3646b1814e503e0" +dependencies = [ + "cast_checks_convert", + "cast_checks_macro", +] + +[[package]] +name = "cast_checks_convert" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2794a887efab1c03c774eb442a710bd37a605a65fb0a608472b93a0be2ba539b" + +[[package]] +name = "cast_checks_macro" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76e4ff263730893dde55b2baa124850725411705dc55e79133e6a94e1dca24cc" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "fastrand" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.166" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2ccc108bbc0b1331bd061864e7cd823c0cab660bbe6970e66e2c0614decde36" + +[[package]] +name = "libm" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro2" +version = "1.0.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proptest" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d" +dependencies = [ + "bit-set", + "bit-vec", + "bitflags", + "lazy_static", + "num-traits", + "rand", + "rand_chacha", + "rand_xorshift", + "regex-syntax", + "rusty-fork", + "tempfile", + "unarray", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "rust_tests" +version = "0.1.0" +dependencies = [ + "cast_checks", + "proptest", +] + +[[package]] +name = "rustix" +version = "0.38.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "rusty-fork" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" +dependencies = [ + "fnv", + "quick-error", + "tempfile", + "wait-timeout", +] + +[[package]] +name = "syn" +version = "2.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" +dependencies = [ + "cfg-if", + "fastrand", + "once_cell", + "rustix", + "windows-sys 0.59.0", +] + +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + +[[package]] +name = "unicode-ident" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" + +[[package]] +name = "wait-timeout" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +dependencies = [ + "libc", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/samples/rust_tests/Cargo.toml b/samples/rust_tests/Cargo.toml new file mode 100644 index 00000000..542ddaf3 --- /dev/null +++ b/samples/rust_tests/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "rust_tests" +version = "0.1.0" +edition = "2021" + +[dev-dependencies] +proptest = "1.5.0" +cast_checks = "0.1.5" + +[features] +fone = [] +ftwo = [] +fthree = [] \ No newline at end of file diff --git a/samples/rust_tests/src/main.rs b/samples/rust_tests/src/main.rs new file mode 100644 index 00000000..62780179 --- /dev/null +++ b/samples/rust_tests/src/main.rs @@ -0,0 +1,64 @@ +#![feature(custom_inner_attributes, proc_macro_hygiene)] + +mod unit_tests; + +fn main() { + println!("Hello, world!"); +} + +/* Unit Testing */ +static mut GLOB_VAR: i32 = 2; + +unsafe fn global_var_set(arg: i32) { + GLOB_VAR = arg; +} + +#[allow(unreachable_code)] +fn feature_one() -> i32 { + #[cfg(all(feature = "fone", feature = "fthree", not(feature = "ftwo")))] + { + return 3; + } + #[cfg(feature = "fone")] { + return 1; + } + #[cfg(feature = "ftwo")] { + return 2; + } + return 0; +} + +mod overflow_lib { + #![cast_checks::enable] + + pub(crate) fn do_overflow(a: i32) -> i32 { + return a * 8; + } + + pub(crate) fn as_u16(z: i32) -> u16 { + z as u16 + } +} + +fn simple_thingy_dingy(a: u64, b: &str) -> u64 { + return a + match b.parse::() { + Ok(x) => x, + Err(_) => b.len() as u64, + }; +} + +fn validate_data(data: &Data) -> Result<(), ()> { + if !data.magic.eq(&[0x13, 0x37]) { return Err(()) } + if data.len as usize != data.content.len() { return Err(()) } + return Ok(()); +} + +struct Data { + magic: [u8; 2], + len: u8, + content: String +} + +/* END Unit Testing */ + + diff --git a/samples/rust_tests/src/unit_tests.rs b/samples/rust_tests/src/unit_tests.rs new file mode 100644 index 00000000..a978e3e3 --- /dev/null +++ b/samples/rust_tests/src/unit_tests.rs @@ -0,0 +1,118 @@ +#[cfg(test)] +mod unit_tests { + #[test] + fn true_dilemma() { + assert_ne!(true, false); + } + + /* Randomization */ + #[cfg(test)] + mod tests2 { + use crate::{GLOB_VAR, global_var_set}; + + #[test] + fn a_true_dilemma() { + unsafe { assert_eq!(GLOB_VAR, 2); } + unsafe { global_var_set(5); } + unsafe { assert_eq!(GLOB_VAR, 5); } + assert_ne!(true, false); + } + + #[test] + fn not_true_dilemma() { + unsafe { assert_eq!(GLOB_VAR, 2); } + assert_ne!(true, false); + } + } + + #[cfg(test)] + mod tests3 { + use crate::{feature_one}; + + #[test] + fn feature_test1() { + let z = feature_one(); + assert!(z < 3); + } + } + /* END Randomization */ + + /* Integer overflows */ + #[cfg(test)] + #[allow(unused_variables)] + mod tests4 { + use crate::{overflow_lib::as_u16, overflow_lib::do_overflow}; + + #[should_panic] + #[test] + fn int_overflow_simple() { + let y_str = "2147483647"; + let y = y_str.parse::().unwrap(); + let x = do_overflow(y); + } + + #[should_panic] + #[test] + fn int_overflow_in_cast() { + let y_str = "2147483647"; + let y = y_str.parse::().unwrap(); + println!("{}", y); + let a = as_u16(y); + } + } + /* END Integer overflows */ + + /* Sanitizers */ + #[cfg(test)] + #[allow(unused_variables)] + mod tests5 { + #[test] + fn uaf() { + let a = vec![7, 3, 3, 1]; + let b = a.as_ptr(); + drop(a); + let z = unsafe { *b }; + } + } + /* END Sanitizers */ + + /* Proptest */ + #[cfg(test)] + mod tests6 { + use crate::simple_thingy_dingy; + use proptest::prelude::*; + + proptest! { + #![proptest_config(ProptestConfig::with_cases(100))] + #[test] + fn test_simple_thingy_dingy(a in 1337..7331u64, b in "[0-9]{1,3}") { + println!("{a} | {b}"); + let sum = simple_thingy_dingy(a, &b); + assert!(sum >= a); + assert!(sum > 1337); + } + } + } + /* END Proptest */ + + /* Necessist */ + #[cfg(test)] + mod tests7 { + use crate::{Data, validate_data}; + + #[test] + fn parser_detects_errors() { + let mut blob = Data{ + magic: [0x73, 0x31], + len: 2, + content: "AB".parse().unwrap(), + }; + blob.content = blob.content + "Y"; + let result = validate_data(&blob); + assert!(result.is_err()); + } + } + /* END Necessist */ +} + + From 7a1226b67c350fe40008d0613aa63f69e257b132 Mon Sep 17 00:00:00 2001 From: GrosQuildu Date: Tue, 31 Dec 2024 13:45:47 +0100 Subject: [PATCH 29/30] fuzz miri example --- samples/rust_tests/fuzz/Cargo.lock | 385 ++++++++++++++++++ samples/rust_tests/fuzz/Cargo.toml | 29 ++ .../fuzz/fuzz_targets/fuzz_target_1.rs | 29 ++ samples/rust_tests/src/lib.rs | 11 + samples/rust_tests/src/main.rs | 6 +- 5 files changed, 459 insertions(+), 1 deletion(-) create mode 100644 samples/rust_tests/fuzz/Cargo.lock create mode 100644 samples/rust_tests/fuzz/Cargo.toml create mode 100644 samples/rust_tests/fuzz/fuzz_targets/fuzz_target_1.rs create mode 100644 samples/rust_tests/src/lib.rs diff --git a/samples/rust_tests/fuzz/Cargo.lock b/samples/rust_tests/fuzz/Cargo.lock new file mode 100644 index 00000000..305d93ae --- /dev/null +++ b/samples/rust_tests/fuzz/Cargo.lock @@ -0,0 +1,385 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "arbitrary" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "cc" +version = "1.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d6dbb628b8f8555f86d0323c2eb39e3ec81901f4b83e091db8a6a76d316a333" +dependencies = [ + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-timer" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "glob" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" + +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" + +[[package]] +name = "indexmap" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "jobserver" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +dependencies = [ + "libc", +] + +[[package]] +name = "libc" +version = "0.2.169" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" + +[[package]] +name = "libfuzzer-sys" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b9569d2f74e257076d8c6bfa73fb505b46b851e51ddaecc825944aa3bed17fa" +dependencies = [ + "arbitrary", + "cc", +] + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "pin-project-lite" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "proc-macro-crate" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "relative-path" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" + +[[package]] +name = "rstest" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a2c585be59b6b5dd66a9d2084aa1d8bd52fbdb806eafdeffb52791147862035" +dependencies = [ + "futures", + "futures-timer", + "rstest_macros", + "rustc_version", +] + +[[package]] +name = "rstest_macros" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "825ea780781b15345a146be27eaefb05085e337e869bff01b4306a4fd4a9ad5a" +dependencies = [ + "cfg-if", + "glob", + "proc-macro-crate", + "proc-macro2", + "quote", + "regex", + "relative-path", + "rustc_version", + "syn", + "unicode-ident", +] + +[[package]] +name = "rust_tests" +version = "0.1.0" + +[[package]] +name = "rust_tests-fuzz" +version = "0.0.0" +dependencies = [ + "libfuzzer-sys", + "rstest", + "rust_tests", +] + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "semver" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba" + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "syn" +version = "2.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c786062daee0d6db1132800e623df74274a0a87322d8e183338e01b3d98d058" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" + +[[package]] +name = "toml_edit" +version = "0.22.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + +[[package]] +name = "unicode-ident" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" + +[[package]] +name = "winnow" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +dependencies = [ + "memchr", +] diff --git a/samples/rust_tests/fuzz/Cargo.toml b/samples/rust_tests/fuzz/Cargo.toml new file mode 100644 index 00000000..f8b66d35 --- /dev/null +++ b/samples/rust_tests/fuzz/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "rust_tests-fuzz" +version = "0.0.0" +publish = false +edition = "2021" + +[package.metadata] +cargo-fuzz = true + +[dependencies] +libfuzzer-sys = "0.4" +rstest = "0.23.0" + +[dependencies.rust_tests] +path = ".." + +[[bin]] +name = "fuzz_target_1" +path = "fuzz_targets/fuzz_target_1.rs" +test = false +doc = false +bench = false + +[[bin]] +name = "fuzz_target_2" +path = "fuzz_targets/fuzz_target_2.rs" +test = false +doc = false +bench = false diff --git a/samples/rust_tests/fuzz/fuzz_targets/fuzz_target_1.rs b/samples/rust_tests/fuzz/fuzz_targets/fuzz_target_1.rs new file mode 100644 index 00000000..a1ced76c --- /dev/null +++ b/samples/rust_tests/fuzz/fuzz_targets/fuzz_target_1.rs @@ -0,0 +1,29 @@ +#![cfg_attr(not(any(miri, test)), no_main)] + +use libfuzzer_sys::fuzz_target; +use rust_tests::check_buf; +fn harness(data: &[u8]) { + check_buf(data); +} + +fuzz_target!(|data: &[u8]| { + harness(data); +}); + +#[cfg(test)] +#[cfg(miri)] +mod tests { + use { + crate::{harness}, + rstest::rstest, + std::{fs::File, io::Read, path::PathBuf}, + }; + + #[rstest] + fn miri(#[files("corpus/fuzz_target_1/*")] path: PathBuf) { + let mut input = File::open(path).unwrap(); + let mut buf = Vec::new(); + input.read_to_end(&mut buf).unwrap(); + harness(&buf); + } +} \ No newline at end of file diff --git a/samples/rust_tests/src/lib.rs b/samples/rust_tests/src/lib.rs new file mode 100644 index 00000000..e2b14bae --- /dev/null +++ b/samples/rust_tests/src/lib.rs @@ -0,0 +1,11 @@ +use std::process; + +pub fn check_buf(buf: &[u8]) { + if buf.len() > 0 && buf[0] == b'a' { + if buf.len() > 1 && buf[1] == b'b' { + if buf.len() > 2 && buf[2] == b'c' { + process::abort(); + } + } + } +} \ No newline at end of file diff --git a/samples/rust_tests/src/main.rs b/samples/rust_tests/src/main.rs index 62780179..0022bd29 100644 --- a/samples/rust_tests/src/main.rs +++ b/samples/rust_tests/src/main.rs @@ -1,9 +1,13 @@ #![feature(custom_inner_attributes, proc_macro_hygiene)] +use rust_tests::check_buf; + mod unit_tests; fn main() { println!("Hello, world!"); + let buffer: &[u8] = b"123"; + check_buf(buffer); } /* Unit Testing */ @@ -29,7 +33,7 @@ fn feature_one() -> i32 { } mod overflow_lib { - #![cast_checks::enable] + // #![cast_checks::enable] pub(crate) fn do_overflow(a: i32) -> i32 { return a * 8; From da1b72d0661348cee75fe113135179880a43b683 Mon Sep 17 00:00:00 2001 From: GrosQuildu Date: Tue, 31 Dec 2024 14:46:57 +0100 Subject: [PATCH 30/30] add miri example --- .../fuzz/fuzz_targets/fuzz_target_1.rs | 2 +- samples/rust_tests/src/unit_tests.rs | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/samples/rust_tests/fuzz/fuzz_targets/fuzz_target_1.rs b/samples/rust_tests/fuzz/fuzz_targets/fuzz_target_1.rs index a1ced76c..90a8f9ad 100644 --- a/samples/rust_tests/fuzz/fuzz_targets/fuzz_target_1.rs +++ b/samples/rust_tests/fuzz/fuzz_targets/fuzz_target_1.rs @@ -18,7 +18,7 @@ mod tests { rstest::rstest, std::{fs::File, io::Read, path::PathBuf}, }; - + #[rstest] fn miri(#[files("corpus/fuzz_target_1/*")] path: PathBuf) { let mut input = File::open(path).unwrap(); diff --git a/samples/rust_tests/src/unit_tests.rs b/samples/rust_tests/src/unit_tests.rs index a978e3e3..e14c1e63 100644 --- a/samples/rust_tests/src/unit_tests.rs +++ b/samples/rust_tests/src/unit_tests.rs @@ -76,6 +76,22 @@ mod unit_tests { } /* END Sanitizers */ + /* Miri */ + #[cfg(test)] + mod tests_miri { + fn x() {} + + #[test] + fn miri_example() { + let f = x as *const usize; + let y = unsafe { + *f.map_addr(|a| a + 8) + }; + assert_eq!(y, 0x841f0f); + } + } + /* END Miri */ + /* Proptest */ #[cfg(test)] mod tests6 {