cargo_is_tested/lib.rs
1//!<h1 align="center">cargo-is-tested</h1>
2//!<div align="center">
3//! <a href="https://github.com/blyxyas/cargo-is-tested">
4//! <img src="https://img.shields.io/badge/github--9cf?style=for-the-badge&logo=github" />
5//! </a>
6//! <a href="https://crates.io/crates/cargo-is-tested">
7//! <img src="https://img.shields.io/badge/Crates.io--fc8d62?style=for-the-badge&labelColor=555555&logo=rust">
8//! </a>
9//! <a href="https://docs.rs/cargo-is-tested">
10//! <img src="https://img.shields.io/badge/Docs.rs--66c2a5?style=for-the-badge&logo=docs.rs">
11//! </a>
12//! <a href="https://blyxyas.github.io/cargo-is-tested">
13//! <img src="https://img.shields.io/badge/Book--B597FC?style=for-the-badge&logo=mdbook">
14//! </a>
15//!</div>
16//!<br>
17//!
18//!`cargo-is-tested` is a way to check which of your items are tested in which aren't, very configurable and with a scripting-friendly API ready to use with your Git hooks.
19//!
20//!Also, is uses *✨ pretty colors ✨* for error reporting.
21//!
22//! #### You can also [read the book](https://blyxyas.github.io/cargo-is-tested) for a more user-friendly guide.
23//!
24//!## Example
25//!
26//!To check if all functions are tested in the current directory.
27//!
28//!```bash
29//!$ cargo is-tested .
30//!```
31//!
32//!```toml
33//!# Cargo.toml
34//!# [...]
35//!
36//![dependencies]
37//!is_tested = "0.1.1" # Check crates.io for the current version of the crate.
38//!
39//!# [...]
40//!```
41//!
42//!```rust, ignore
43//!// src/main.rs
44//!
45//!#! is-tested emptiness
46//!// Yes, it uses shebangs to enable testing and flags!
47//!
48//!use is_tested::is_tested;
49//!
50//!#[is_tested("test/myfunction_testing_path.rs")]
51//!fn my_function() {
52//! // [...]
53//!}
54//!```
55//!
56//!Then, it will check if `test/myfunction_testing_path.rs` exists, if it doesn't, it will output an error.
57//!
58//!If the file exists, the program checks all lints against your test, assuring the best quality possible.
59//!
60//!<div align="center">
61//!<img src="./assets/output-screenshot.png" height="300" width="auto" />
62//!</div>
63//!
64//!## Installation and usage
65//!
66//!##### ⚠️ Installation isn't currently possible because the project isn't published yet.
67//!
68//!To get started using `cargo-is-tested`, install the binary.
69//!
70//!```bash
71//!$ cargo install cargo-is-tested
72//!```
73//!
74//!Now [document yourself](https://docs.rs/cargo-is-tested/latest/cargo-is-tested/lints) about all the lints you can apply to your tests.
75//!
76//!* *strict* (Activates all lints, default)
77//!* [*emptiness*](https://docs.rs/cargo-is-tested/latest/cargo-is-tested/lints/emptiness)
78//!* [*validness*](https://docs.rs/cargo-is-tested/latest/cargo-is-tested/lints/validness)
79//!
80//!More lints will be added with time.
81//!
82//!---
83//!
84//!Once you know the lints you want to apply, import the attribute `is_tested`, then choose a struct, function or any item that you want to test, and add to that item the attribute `#[is_tested("<path to the test>.rs")]`
85//!
86//!The result should be something like:
87//!
88//!```rust, ignore
89//!#! is-tested strict
90//!
91//!use is_tested::is_tested;
92//!
93//!#[is_tested("tests/mystruct.rs")]
94//!struct MyStruct<'a> {
95//! string: &'a str
96//!}
97//!```
98//!
99//!Don't worry, the attribute won't change anything in your code, it's just a marker for a later-parser to know that you're testing the item.
100//!
101//!---
102//!
103//!It's time to run the parser, it will read check that all tested items are tested, and with the correct code quality dicted using the lints.
104//!
105//!```rust, ignore
106//!// tests/mystruct.rs
107//!
108//!use mycrate::MyStruct;
109//!
110//!fn main() {
111//! // [...]
112//!}
113//!```
114//!
115//!```bash
116//!$ cargo is-tested .
117//!```
118//!
119//!This will check that all tests are well written. You can use flags to customize your experience, for example, use `--structs` to check that all structs have tests associated, or use `--test` to, if all tests are confirmed, run `cargo test` automatically.
120
121pub mod error;
122pub mod flags;
123pub mod lints;
124
125#[cfg(feature = "suggestions")]
126pub fn did_you_mean<'a, T, I>(field: &str, alternatives: I) -> Option<String>
127where
128 T: AsRef<str> + 'a,
129 I: IntoIterator<Item = &'a T>,
130{
131 let mut candidate: Option<(f64, &str)> = None;
132 for pv in alternatives {
133 let confidence = ::strsim::jaro_winkler(field, pv.as_ref());
134 if confidence > 0.8 && (candidate.is_none() || (candidate.as_ref().unwrap().0 < confidence))
135 {
136 candidate = Some((confidence, pv.as_ref()));
137 }
138 }
139 candidate.map(|(_, candidate)| candidate.into())
140}
141
142#[cfg(not(feature = "suggestions"))]
143pub fn did_you_mean<'a, T, I>(field: &str, alternatives: I) -> Option<String>
144where
145 T: AsRef<str> + 'a,
146 I: IntoIterator<Item = &'a T>,
147{
148 None
149}
150
151#[macro_export]
152macro_rules! impl_warn {
153 ($ty: ty) => {
154 impl ::miette::ReportHandler for $ty {
155 fn debug(
156 &self,
157 error: &(dyn Diagnostic),
158 f: &mut core::fmt::Formatter<'_>,
159 ) -> core::fmt::Result {
160 if f.alternate() {
161 return core::fmt::Debug::fmt(error, f);
162 }
163 write!(f, "{}", error)?;
164 Ok(())
165 }
166 }
167 };
168}
169
170#[macro_export]
171macro_rules! maybe_warn {
172 ($e: expr, $args: expr) => {
173 if $e.severity() == Some(Severity::Warning) && !$args.deny_warnings {
174 println!("WARN: {:?}", $e);
175 } else {
176 return Err($e);
177 }
178 };
179}