cargo_tarpaulin/
args.rs

1use std::path::PathBuf;
2
3use clap::{Args, Parser};
4use glob::Pattern;
5
6#[cfg(feature = "coveralls")]
7use crate::config::Ci;
8use crate::config::{Color, Mode, OutputFile, RunType, TraceEngine};
9
10#[derive(Debug, Parser)]
11#[command(name = "cargo-tarpaulin")]
12#[command(bin_name = "cargo")]
13#[command(author, version, about, long_about = None)]
14pub enum CargoTarpaulinCli {
15    Tarpaulin(TarpaulinCli),
16}
17
18impl CargoTarpaulinCli {
19    pub fn from_args() -> TarpaulinCli {
20        match TarpaulinCli::try_parse() {
21            Ok(tarpaulin_cli) => tarpaulin_cli,
22            Err(err) if !err.use_stderr() => err.exit(),
23            Err(_) => match CargoTarpaulinCli::parse() {
24                CargoTarpaulinCli::Tarpaulin(tarpaulin_cli) => tarpaulin_cli,
25            },
26        }
27    }
28}
29
30#[derive(Debug, Parser)]
31#[command(name = "tarpaulin")]
32#[command(author, version, about, long_about = None)]
33pub struct TarpaulinCli {
34    #[clap(flatten)]
35    pub print_flags: PrintFlagsArgs,
36    #[clap(flatten)]
37    pub config: ConfigArgs,
38}
39
40#[derive(Debug, Clone, Args)]
41pub struct ConfigArgs {
42    #[clap(flatten)]
43    pub logging: LoggingArgs,
44    #[clap(flatten)]
45    pub run_types: RunTypesArgs,
46
47    /// Path to a toml file specifying a list of options this will override any other options set
48    #[arg(long, value_name = "FILE")]
49    pub config: Option<PathBuf>,
50    /// Ignore any project config files
51    #[arg(long)]
52    pub ignore_config: bool,
53    /// Test only the specified binary
54    #[arg(long, value_name = "NAME", num_args = 0..)]
55    pub bin: Vec<String>,
56    /// Test only the specified example
57    #[arg(long, value_name = "NAME", num_args = 0..)]
58    pub example: Vec<String>,
59    /// Test only the specified test target
60    #[arg(long, value_name = "NAME", num_args = 0..)]
61    pub test: Vec<String>,
62    /// Test only the specified bench target
63    #[arg(long, value_name = "NAME", num_args = 0..)]
64    pub bench: Vec<String>,
65    /// Run all tests regardless of failure
66    #[arg(long)]
67    pub no_fail_fast: bool,
68    /// Build artefacts with the specified profile
69    #[arg(long, value_name = "NAME")]
70    pub profile: Option<String>,
71    /// Ignore lines of test functions when collecting coverage (default)
72    #[arg(long)]
73    pub ignore_tests: bool,
74    /// Stops tarpaulin from building projects with -Clink-dead-code
75    #[arg(long)]
76    pub no_dead_code: bool,
77    /// Include lines of test functions when collecting coverage
78    #[arg(long)]
79    pub include_tests: bool,
80    /// Ignore panic macros in tests
81    #[arg(long)]
82    pub ignore_panics: bool,
83    /// Counts the number of hits during coverage
84    #[arg(long)]
85    pub count: bool,
86    /// Run ignored tests as well
87    #[arg(long, short)]
88    pub ignored: bool,
89    /// Line coverage
90    #[arg(long, short)]
91    pub line: bool,
92    /// The opposite of --force-clean
93    #[arg(long)]
94    pub skip_clean: bool,
95    /// Adds a clean stage to work around cargo bugs that may affect coverage results
96    #[arg(long)]
97    pub force_clean: bool,
98    /// Sets a percentage threshold for failure ranging from 0-100, if coverage is below exit with a non-zero code
99    #[arg(long, value_name = "PERCENTAGE")]
100    pub fail_under: Option<f64>,
101    /// Branch coverage: NOT IMPLEMENTED
102    #[arg(long, short)]
103    pub branch: bool,
104    /// Forwards unexpected signals to test. This is now the default behaviour
105    #[arg(long, short)]
106    pub forward: bool,
107    /// Coveralls key, either the repo token, or if you're using travis use $TRAVIS_JOB_ID and specify travis-{ci|pro} in --ciserver
108    #[arg(long, value_name = "KEY")]
109    pub coveralls: Option<String>,
110    /// URI to send report to, only used if the option --coveralls is used
111    #[arg(long, value_name = "URI")]
112    pub report_uri: Option<String>,
113    /// Do not include default features
114    #[arg(long)]
115    pub no_default_features: bool,
116    /// Features to be included in the target project
117    #[arg(long, value_name = "FEATURES", num_args = 0..)]
118    pub features: Vec<String>,
119    /// Build all available features
120    #[arg(long)]
121    pub all_features: bool,
122    /// Alias for --workspace (deprecated)
123    #[arg(long)]
124    pub all: bool,
125    /// Test all packages in the workspace
126    #[arg(long)]
127    pub workspace: bool,
128    /// Package id specifications for which package should be build. See cargo help pkgid for more info
129    #[arg(long, short, alias = "package", value_name = "PACKAGE", num_args = 0..)]
130    pub packages: Vec<String>,
131    /// Package id specifications to exclude from coverage. See cargo help pkgid for more info
132    #[arg(long, short, value_name = "PACKAGE", num_args = 0..)]
133    pub exclude: Vec<String>,
134    /// Exclude given files from coverage results has * wildcard
135    #[arg(long, value_name = "FILE", num_args = 0..)]
136    pub exclude_files: Vec<Pattern>,
137    /// Include only given files in coverage results. Can have a * wildcard
138    #[arg(long, value_name = "FILE", num_args = 0..)]
139    pub include_files: Vec<Pattern>,
140    /// Integer for the maximum time in seconds without response from test before timeout (default is 1 minute).
141    #[arg(long, short, value_name = "SECONDS")]
142    pub timeout: Option<u64>,
143    /// Delay after test to collect coverage profiles
144    #[arg(long, value_name = "SECONDS")]
145    pub post_test_delay: Option<u64>,
146    /// Follow executed processes capturing coverage information if they're part of your project.
147    #[arg(long)]
148    pub follow_exec: bool,
149    /// Build in release mode.
150    #[arg(long)]
151    pub release: bool,
152    /// Compile tests but don't run coverage
153    #[arg(long)]
154    pub no_run: bool,
155    /// 'Don't supply an explicit `--test-threads` argument to test executable. By default tarpaulin will infer the default rustc would pick if not ran via tarpaulin and set it
156    #[arg(long)]
157    pub implicit_test_threads: bool,
158    /// Do not update Cargo.lock
159    #[arg(long)]
160    pub locked: bool,
161    /// Do not update Cargo.lock or any caches
162    #[arg(long)]
163    pub frozen: bool,
164    /// Compilation target triple
165    #[arg(long, value_name = "TRIPLE")]
166    pub target: Option<String>,
167    /// Directory for all generated artifacts
168    #[arg(long, value_name = "DIR")]
169    pub target_dir: Option<PathBuf>,
170    /// Run without accessing the network
171    #[arg(long)]
172    pub offline: bool,
173    /// Remove --cfg=tarpaulin from the RUSTFLAG
174    #[arg(long)]
175    pub avoid_cfg_tarpaulin: bool,
176    /// Number of parallel jobs, defaults to # of CPUs
177    #[arg(long, short, value_name = "N")]
178    pub jobs: Option<usize>,
179    /// Rustflags to add when building project (can also be set via RUSTFLAGS env var)
180    #[arg(long, value_name = "FLAGS")]
181    pub rustflags: Option<String>,
182    /// Other object files to load which contain information for llvm coverage - must have been compiled with llvm coverage instrumentation (ignored for ptrace)
183    #[arg(long, value_name = "objects", num_args = 0..)]
184    pub objects: Vec<PathBuf>,
185    /// List of unstable nightly only flags
186    #[arg(short = 'Z', value_name = "FEATURES", num_args = 0..)]
187    pub unstable_features: Vec<String>,
188    /// Output format of coverage report
189    #[arg(long, short, value_enum, value_name = "FMT", num_args = 0.., ignore_case = true)]
190    pub out: Vec<OutputFile>,
191    /// Coverage tracing backend to use
192    #[arg(long, value_enum, value_name = "ENGINE", ignore_case = true)]
193    pub engine: Option<TraceEngine>,
194    /// Specify a custom directory to write report files
195    #[arg(long, value_name = "PATH")]
196    pub output_dir: Option<PathBuf>,
197    /// cargo subcommand to run. So far only test and build are supported
198    #[arg(long, value_enum, value_name = "CMD", ignore_case = true)]
199    pub command: Option<Mode>,
200    /// Calculates relative paths to root directory. If --manifest-path isn't specified it will look for a Cargo.toml in root
201    #[arg(long, short, value_name = "DIR")]
202    pub root: Option<PathBuf>,
203    /// Path to Cargo.toml
204    #[arg(long, value_name = "PATH")]
205    pub manifest_path: Option<PathBuf>,
206    #[cfg(feature = "coveralls")]
207    /// CI server being used, if unspecified tarpaulin may automatically infer for coveralls uploads
208    #[arg(long, value_name = "SERVICE")]
209    pub ciserver: Option<Ci>,
210    /// Option to fail immediately after a single test fails
211    #[arg(long)]
212    pub fail_immediately: bool,
213    /// Arguments to be passed to the test executables can be used to filter or skip certain tests
214    #[arg(last = true)]
215    pub args: Vec<String>,
216}
217
218#[derive(Debug, Clone, Copy, Args)]
219pub struct LoggingArgs {
220    /// Coloring: auto, always, never
221    #[arg(long, value_enum, value_name = "WHEN", ignore_case = true)]
222    pub color: Option<Color>,
223    /// Show debug output - this is used for diagnosing issues with tarpaulin
224    #[arg(long)]
225    pub debug: bool,
226    /// Show extra output
227    #[arg(long, short)]
228    pub verbose: bool,
229    /// Log tracing events and save to a json file. Also, enabled when --debug is used
230    #[arg(long)]
231    pub dump_traces: bool,
232    /// Print tarpaulin logs to stderr instead - test output will still be printed to stdout
233    #[arg(long)]
234    pub stderr: bool,
235}
236
237#[derive(Debug, Clone, Copy, Args)]
238pub struct PrintFlagsArgs {
239    /// Print the RUSTFLAGS options that tarpaulin will compile your program with and exit
240    #[arg(long)]
241    pub print_rust_flags: bool,
242    /// Print the RUSTDOCFLAGS options that tarpaulin will compile any doctests with and exit
243    #[arg(long)]
244    pub print_rustdoc_flags: bool,
245}
246
247#[derive(Debug, Clone, Args)]
248pub struct RunTypesArgs {
249    /// Type of the coverage run
250    #[arg(long, value_enum, value_name = "TYPE", ignore_case = true)]
251    pub run_types: Vec<RunType>,
252    /// Test all benches
253    #[arg(long)]
254    pub benches: bool,
255    /// Test only this library's documentation
256    #[arg(long)]
257    pub doc: bool,
258    /// Test all targets (excluding doctests)
259    #[arg(long)]
260    pub all_targets: bool,
261    /// Test only this package's library unit tests
262    #[arg(long)]
263    pub lib: bool,
264    /// Test all binaries
265    #[arg(long)]
266    pub bins: bool,
267    /// Test all examples
268    #[arg(long)]
269    pub examples: bool,
270    /// Test all tests
271    #[arg(long)]
272    pub tests: bool,
273}
274
275impl RunTypesArgs {
276    pub fn collect(self) -> Vec<RunType> {
277        let mut run_types = self.run_types;
278        if self.lib && !run_types.contains(&RunType::Lib) {
279            run_types.push(RunType::Lib);
280        }
281        if self.all_targets && !run_types.contains(&RunType::AllTargets) {
282            run_types.push(RunType::AllTargets);
283        }
284        if self.benches && !run_types.contains(&RunType::Benchmarks) {
285            run_types.push(RunType::Benchmarks);
286        }
287        if self.bins && !run_types.contains(&RunType::Bins) {
288            run_types.push(RunType::Bins);
289        }
290        if self.examples && !run_types.contains(&RunType::Examples) {
291            run_types.push(RunType::Examples);
292        }
293        if self.doc && !run_types.contains(&RunType::Doctests) {
294            run_types.push(RunType::Doctests);
295        }
296        if self.tests && !run_types.contains(&RunType::Tests) {
297            run_types.push(RunType::Tests);
298        }
299        run_types
300    }
301}
302
303#[cfg(test)]
304mod tests {
305    use clap::CommandFactory;
306
307    use super::CargoTarpaulinCli;
308
309    #[test]
310    fn verify_args() {
311        CargoTarpaulinCli::command().debug_assert()
312    }
313
314    #[test]
315    #[ignore = "Manual use only"]
316    fn show_help() {
317        let help = CargoTarpaulinCli::command().render_help();
318        println!("{help}");
319    }
320}