1use std::ops::{Deref, DerefMut};
2use std::path::PathBuf;
3use std::process::Command;
4
5use clap::{ArgAction, Parser};
6
7#[cfg(feature = "serde")]
8use serde::{Deserialize, Serialize};
9
10use crate::common::CommonOptions;
11use crate::heading;
12
13#[derive(Clone, Debug, Default, Parser)]
15#[command(
16 display_order = 1,
17 after_help = "Run `cargo help test` for more detailed information.\nRun `cargo test -- --help` for test binary options."
18)]
19#[group(skip)]
20#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
21pub struct Test {
22 #[command(flatten)]
23 #[cfg_attr(feature = "serde", serde(flatten))]
24 pub common: CommonOptions,
25
26 #[arg(long, value_name = "PATH", help_heading = heading::MANIFEST_OPTIONS)]
28 #[cfg_attr(feature = "serde", serde(default))]
29 pub manifest_path: Option<PathBuf>,
30
31 #[arg(short = 'r', long, help_heading = heading::COMPILATION_OPTIONS)]
33 #[cfg_attr(feature = "serde", serde(default))]
34 pub release: bool,
35
36 #[arg(long)]
38 #[cfg_attr(feature = "serde", serde(default))]
39 pub ignore_rust_version: bool,
40
41 #[arg(long, help_heading = heading::COMPILATION_OPTIONS)]
43 #[cfg_attr(feature = "serde", serde(default))]
44 pub unit_graph: bool,
45
46 #[arg(
48 short = 'p',
49 long = "package",
50 value_name = "SPEC",
51 action = ArgAction::Append,
52 num_args=0..=1,
53 help_heading = heading::PACKAGE_SELECTION,
54 )]
55 #[cfg_attr(feature = "serde", serde(default))]
56 pub packages: Vec<String>,
57
58 #[arg(long, help_heading = heading::PACKAGE_SELECTION)]
60 #[cfg_attr(feature = "serde", serde(default))]
61 pub workspace: bool,
62
63 #[arg(
65 long,
66 value_name = "SPEC",
67 action = ArgAction::Append,
68 help_heading = heading::PACKAGE_SELECTION,
69 )]
70 #[cfg_attr(feature = "serde", serde(default))]
71 pub exclude: Vec<String>,
72
73 #[arg(long, help_heading = heading::PACKAGE_SELECTION)]
75 #[cfg_attr(feature = "serde", serde(default))]
76 pub all: bool,
77
78 #[arg(long, help_heading = heading::TARGET_SELECTION)]
80 #[cfg_attr(feature = "serde", serde(default))]
81 pub lib: bool,
82
83 #[arg(
85 long,
86 value_name = "NAME",
87 action = ArgAction::Append,
88 num_args=0..=1,
89 help_heading = heading::TARGET_SELECTION,
90 )]
91 #[cfg_attr(feature = "serde", serde(default))]
92 pub bin: Vec<String>,
93
94 #[arg(long, help_heading = heading::TARGET_SELECTION)]
96 #[cfg_attr(feature = "serde", serde(default))]
97 pub bins: bool,
98
99 #[arg(
101 long,
102 value_name = "NAME",
103 action = ArgAction::Append,
104 num_args=0..=1,
105 help_heading = heading::TARGET_SELECTION,
106 )]
107 #[cfg_attr(feature = "serde", serde(default))]
108 pub example: Vec<String>,
109
110 #[arg(long, help_heading = heading::TARGET_SELECTION)]
112 #[cfg_attr(feature = "serde", serde(default))]
113 pub examples: bool,
114
115 #[arg(
117 long,
118 value_name = "NAME",
119 action = ArgAction::Append,
120 help_heading = heading::TARGET_SELECTION,
121 )]
122 #[cfg_attr(feature = "serde", serde(default))]
123 pub test: Vec<String>,
124
125 #[arg(long, help_heading = heading::TARGET_SELECTION)]
127 #[cfg_attr(feature = "serde", serde(default))]
128 pub tests: bool,
129
130 #[arg(
132 long,
133 value_name = "NAME",
134 action = ArgAction::Append,
135 help_heading = heading::TARGET_SELECTION,
136 )]
137 #[cfg_attr(feature = "serde", serde(default))]
138 pub bench: Vec<String>,
139
140 #[arg(long, help_heading = heading::TARGET_SELECTION)]
142 #[cfg_attr(feature = "serde", serde(default))]
143 pub benches: bool,
144
145 #[arg(long, help_heading = heading::TARGET_SELECTION)]
147 #[cfg_attr(feature = "serde", serde(default))]
148 pub all_targets: bool,
149
150 #[arg(long)]
152 #[cfg_attr(feature = "serde", serde(default))]
153 pub doc: bool,
154
155 #[arg(long)]
157 #[cfg_attr(feature = "serde", serde(default))]
158 pub no_run: bool,
159
160 #[arg(long)]
162 #[cfg_attr(feature = "serde", serde(default))]
163 pub no_fail_fast: bool,
164
165 #[arg(long)]
167 #[cfg_attr(feature = "serde", serde(default))]
168 pub future_incompat_report: bool,
169
170 #[arg(value_name = "TESTNAME")]
172 #[cfg_attr(feature = "serde", serde(default))]
173 pub test_name: Option<String>,
174
175 #[arg(value_name = "args", trailing_var_arg = true, num_args = 0..)]
177 #[cfg_attr(feature = "serde", serde(default))]
178 pub args: Vec<String>,
179}
180
181impl Test {
182 pub fn command(&self) -> Command {
184 let mut cmd = CommonOptions::cargo_command();
185 cmd.arg("test");
186
187 self.common.apply(&mut cmd);
188
189 if let Some(path) = self.manifest_path.as_ref() {
190 cmd.arg("--manifest-path").arg(path);
191 }
192 if self.release {
193 cmd.arg("--release");
194 }
195 if self.ignore_rust_version {
196 cmd.arg("--ignore-rust-version");
197 }
198 if self.unit_graph {
199 cmd.arg("--unit-graph");
200 }
201 for pkg in &self.packages {
202 cmd.arg("--package").arg(pkg);
203 }
204 if self.workspace {
205 cmd.arg("--workspace");
206 }
207 for item in &self.exclude {
208 cmd.arg("--exclude").arg(item);
209 }
210 if self.all {
211 cmd.arg("--all");
212 }
213 if self.lib {
214 cmd.arg("--lib");
215 }
216 for bin in &self.bin {
217 cmd.arg("--bin").arg(bin);
218 }
219 if self.bins {
220 cmd.arg("--bins");
221 }
222 for example in &self.example {
223 cmd.arg("--example").arg(example);
224 }
225 if self.examples {
226 cmd.arg("--examples");
227 }
228 for test in &self.test {
229 cmd.arg("--test").arg(test);
230 }
231 if self.tests {
232 cmd.arg("--tests");
233 }
234 for bench in &self.bench {
235 cmd.arg("--bench").arg(bench);
236 }
237 if self.benches {
238 cmd.arg("--benches");
239 }
240 if self.all_targets {
241 cmd.arg("--all-targets");
242 }
243 if self.doc {
244 cmd.arg("--doc");
245 }
246 if self.no_run {
247 cmd.arg("--no-run");
248 }
249 if self.no_fail_fast {
250 cmd.arg("--no-fail-fast");
251 }
252 if self.future_incompat_report {
253 cmd.arg("--future-incompat-report");
254 }
255 cmd.arg("--");
256 if let Some(test_name) = self.test_name.as_ref() {
257 cmd.arg(test_name);
258 }
259 cmd.args(&self.args);
260
261 cmd
262 }
263}
264
265impl Deref for Test {
266 type Target = CommonOptions;
267
268 fn deref(&self) -> &Self::Target {
269 &self.common
270 }
271}
272
273impl DerefMut for Test {
274 fn deref_mut(&mut self) -> &mut Self::Target {
275 &mut self.common
276 }
277}
278
279#[cfg(test)]
280mod tests {
281 use super::Test;
282 use clap::CommandFactory;
283
284 #[test]
285 fn verify_cli() {
286 <Test as CommandFactory>::command().debug_assert()
287 }
288}