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(
33 short = 'r',
34 long,
35 conflicts_with = "profile",
36 help_heading = heading::COMPILATION_OPTIONS,
37 )]
38 #[cfg_attr(feature = "serde", serde(default))]
39 pub release: bool,
40
41 #[arg(long, help_heading = heading::MANIFEST_OPTIONS)]
43 #[cfg_attr(feature = "serde", serde(default))]
44 pub ignore_rust_version: bool,
45
46 #[arg(long, help_heading = heading::COMPILATION_OPTIONS)]
48 #[cfg_attr(feature = "serde", serde(default))]
49 pub unit_graph: bool,
50
51 #[arg(
53 short = 'p',
54 long = "package",
55 value_name = "SPEC",
56 action = ArgAction::Append,
57 num_args=0..=1,
58 help_heading = heading::PACKAGE_SELECTION,
59 )]
60 #[cfg_attr(feature = "serde", serde(default))]
61 pub packages: Vec<String>,
62
63 #[arg(long, help_heading = heading::PACKAGE_SELECTION)]
65 #[cfg_attr(feature = "serde", serde(default))]
66 pub workspace: bool,
67
68 #[arg(
70 long,
71 value_name = "SPEC",
72 action = ArgAction::Append,
73 help_heading = heading::PACKAGE_SELECTION,
74 )]
75 #[cfg_attr(feature = "serde", serde(default))]
76 pub exclude: Vec<String>,
77
78 #[arg(long, help_heading = heading::PACKAGE_SELECTION)]
80 #[cfg_attr(feature = "serde", serde(default))]
81 pub all: bool,
82
83 #[arg(long, help_heading = heading::TARGET_SELECTION)]
85 #[cfg_attr(feature = "serde", serde(default))]
86 pub lib: bool,
87
88 #[arg(
90 long,
91 value_name = "NAME",
92 action = ArgAction::Append,
93 num_args=0..=1,
94 help_heading = heading::TARGET_SELECTION,
95 )]
96 #[cfg_attr(feature = "serde", serde(default))]
97 pub bin: Vec<String>,
98
99 #[arg(long, help_heading = heading::TARGET_SELECTION)]
101 #[cfg_attr(feature = "serde", serde(default))]
102 pub bins: bool,
103
104 #[arg(
106 long,
107 value_name = "NAME",
108 action = ArgAction::Append,
109 num_args=0..=1,
110 help_heading = heading::TARGET_SELECTION,
111 )]
112 #[cfg_attr(feature = "serde", serde(default))]
113 pub example: Vec<String>,
114
115 #[arg(long, help_heading = heading::TARGET_SELECTION)]
117 #[cfg_attr(feature = "serde", serde(default))]
118 pub examples: bool,
119
120 #[arg(
122 long,
123 value_name = "NAME",
124 action = ArgAction::Append,
125 help_heading = heading::TARGET_SELECTION,
126 )]
127 #[cfg_attr(feature = "serde", serde(default))]
128 pub test: Vec<String>,
129
130 #[arg(long, help_heading = heading::TARGET_SELECTION)]
132 #[cfg_attr(feature = "serde", serde(default))]
133 pub tests: bool,
134
135 #[arg(
137 long,
138 value_name = "NAME",
139 action = ArgAction::Append,
140 help_heading = heading::TARGET_SELECTION,
141 )]
142 #[cfg_attr(feature = "serde", serde(default))]
143 pub bench: Vec<String>,
144
145 #[arg(long, help_heading = heading::TARGET_SELECTION)]
147 #[cfg_attr(feature = "serde", serde(default))]
148 pub benches: bool,
149
150 #[arg(long, help_heading = heading::TARGET_SELECTION)]
152 #[cfg_attr(feature = "serde", serde(default))]
153 pub all_targets: bool,
154
155 #[arg(long, help_heading = heading::TARGET_SELECTION)]
157 #[cfg_attr(feature = "serde", serde(default))]
158 pub doc: bool,
159
160 #[arg(long)]
162 #[cfg_attr(feature = "serde", serde(default))]
163 pub no_run: bool,
164
165 #[arg(long)]
167 #[cfg_attr(feature = "serde", serde(default))]
168 pub no_fail_fast: bool,
169
170 #[arg(long)]
172 #[cfg_attr(feature = "serde", serde(default))]
173 pub future_incompat_report: bool,
174
175 #[arg(value_name = "TESTNAME")]
177 #[cfg_attr(feature = "serde", serde(default))]
178 pub test_name: Option<String>,
179
180 #[arg(value_name = "ARGS", last = true, num_args = 0..)]
182 #[cfg_attr(feature = "serde", serde(default))]
183 pub args: Vec<String>,
184}
185
186impl Test {
187 pub fn command(&self) -> Command {
189 let mut cmd = CommonOptions::cargo_command();
190 cmd.arg("test");
191
192 self.common.apply(&mut cmd);
193
194 if let Some(path) = self.manifest_path.as_ref() {
195 cmd.arg("--manifest-path").arg(path);
196 }
197 if self.release {
198 cmd.arg("--release");
199 }
200 if self.ignore_rust_version {
201 cmd.arg("--ignore-rust-version");
202 }
203 if self.unit_graph {
204 cmd.arg("--unit-graph");
205 }
206 for pkg in &self.packages {
207 cmd.arg("--package").arg(pkg);
208 }
209 if self.workspace {
210 cmd.arg("--workspace");
211 }
212 for item in &self.exclude {
213 cmd.arg("--exclude").arg(item);
214 }
215 if self.all {
216 cmd.arg("--all");
217 }
218 if self.lib {
219 cmd.arg("--lib");
220 }
221 for bin in &self.bin {
222 cmd.arg("--bin").arg(bin);
223 }
224 if self.bins {
225 cmd.arg("--bins");
226 }
227 for example in &self.example {
228 cmd.arg("--example").arg(example);
229 }
230 if self.examples {
231 cmd.arg("--examples");
232 }
233 for test in &self.test {
234 cmd.arg("--test").arg(test);
235 }
236 if self.tests {
237 cmd.arg("--tests");
238 }
239 for bench in &self.bench {
240 cmd.arg("--bench").arg(bench);
241 }
242 if self.benches {
243 cmd.arg("--benches");
244 }
245 if self.all_targets {
246 cmd.arg("--all-targets");
247 }
248 if self.doc {
249 cmd.arg("--doc");
250 }
251 if self.no_run {
252 cmd.arg("--no-run");
253 }
254 if self.no_fail_fast {
255 cmd.arg("--no-fail-fast");
256 }
257 if self.future_incompat_report {
258 cmd.arg("--future-incompat-report");
259 }
260 if self.test_name.is_some() || !self.args.is_empty() {
261 cmd.arg("--");
262 if let Some(test_name) = self.test_name.as_ref() {
263 cmd.arg(test_name);
264 }
265 }
266 cmd.args(&self.args);
267
268 cmd
269 }
270}
271
272impl Deref for Test {
273 type Target = CommonOptions;
274
275 fn deref(&self) -> &Self::Target {
276 &self.common
277 }
278}
279
280impl DerefMut for Test {
281 fn deref_mut(&mut self) -> &mut Self::Target {
282 &mut self.common
283 }
284}
285
286#[cfg(test)]
287mod tests {
288 use super::Test;
289 use clap::CommandFactory;
290
291 #[test]
292 fn verify_cli() {
293 <Test as CommandFactory>::command().debug_assert()
294 }
295}