1use anyhow::Result;
4use clap::Parser;
5use std::path::PathBuf;
6
7#[derive(Parser)]
9pub struct TestCommand {
10 #[arg(long)]
12 pub watch: bool,
13
14 #[arg(long)]
16 pub unit: bool,
17
18 #[arg(long)]
20 pub integration: bool,
21
22 #[arg(long)]
24 pub performance: bool,
25
26 #[arg(long)]
28 pub coverage: bool,
29
30 #[arg(long)]
32 pub report: bool,
33
34 #[arg(long = "update-snapshots")]
36 pub update_snapshots: bool,
37
38 #[arg(long)]
40 pub verbose: bool,
41
42 #[arg(long = "dir", short = 'd')]
44 pub project_dir: Option<PathBuf>,
45}
46
47impl TestCommand {
48 pub fn execute(&self) -> Result<()> {
50 use console::style;
51 use std::process::Command;
52
53 let project_dir = self
55 .project_dir
56 .clone()
57 .unwrap_or_else(|| std::env::current_dir().unwrap());
58
59 println!(
60 "{} Looking for tests in {}",
61 style("[1/4]").bold().dim(),
62 style(project_dir.display()).underlined()
63 );
64
65 let is_orbit_project = std::fs::metadata(project_dir.join("orbit.config.toml")).is_ok()
67 || std::fs::metadata(project_dir.join("Cargo.toml")).is_ok();
68
69 if !is_orbit_project {
70 println!(
71 "⚠️ {} This directory does not appear to be an Orbit project.",
72 style("Warning:").yellow().bold()
73 );
74 println!(" Looking for orbit.config.toml or Cargo.toml...");
75 }
76
77 println!(
79 "\n{}",
80 style("🚧 The `orbiton test` command is under active development.")
81 .yellow()
82 .bold()
83 );
84 println!("Some advanced testing features are planned for future releases.");
85 println!();
86 println!("{}:", style("Planned features").bold());
87 println!(" • Unit testing for components");
88 println!(" • Integration testing for applications");
89 println!(" • Performance testing and benchmarking");
90 println!(" • Coverage reporting");
91 println!(" • Snapshot testing");
92 println!(" • Watch mode for test-driven development");
93
94 println!(
96 "\n{} Running tests with current implementation:",
97 style("[2/4]").bold().dim()
98 );
99
100 let mut cmd_args = vec!["test"];
102
103 if self.verbose {
104 cmd_args.push("--verbose");
105 }
106
107 if self.unit && !self.integration {
108 cmd_args.push("--lib");
109 } else if self.integration && !self.unit {
110 cmd_args.push("--test");
111 }
112
113 println!(
114 "{} Executing: cargo {}",
115 style("[3/4]").bold().dim(),
116 cmd_args.join(" ")
117 );
118
119 let status = Command::new("cargo")
121 .args(&cmd_args)
122 .current_dir(&project_dir)
123 .status();
124
125 match status {
126 Ok(exit_status) => {
127 if exit_status.success() {
128 println!(
129 "\n{} {}",
130 style("✅ Success:").green().bold(),
131 style("All tests passed!").bold()
132 );
133 } else {
134 println!(
135 "\n{} {}",
136 style("❌ Error:").red().bold(),
137 style("Some tests failed.").bold()
138 );
139 }
140 }
141 Err(e) => {
142 println!(
143 "\n{} Failed to execute cargo test: {}",
144 style("❌ Error:").red().bold(),
145 e
146 );
147 }
148 }
149
150 println!(
151 "\n{} {}",
152 style("[4/4]").bold().dim(),
153 style("For more information on testing strategies, see:").italic()
154 );
155 println!(" https://docs.orbitrs.dev/guides/testing-strategies");
156
157 Ok(())
159 }
160}
161
162#[cfg(test)]
163mod tests {
164 use super::*;
165
166 #[test]
167 fn test_command_creation() {
168 let cmd = TestCommand {
169 watch: true,
170 unit: false,
171 integration: true,
172 performance: false,
173 coverage: true,
174 report: true,
175 update_snapshots: false,
176 verbose: true,
177 project_dir: None,
178 };
179
180 assert!(cmd.watch);
181 assert!(!cmd.unit);
182 assert!(cmd.integration);
183 assert!(!cmd.performance);
184 assert!(cmd.coverage);
185 assert!(cmd.report);
186 assert!(!cmd.update_snapshots);
187 assert!(cmd.verbose);
188 assert_eq!(cmd.project_dir, None);
189 }
190
191 #[test]
192 fn test_build_cmd_args() {
193 let cmd = TestCommand {
195 watch: false,
196 unit: true,
197 integration: false,
198 performance: false,
199 coverage: false,
200 report: false,
201 update_snapshots: false,
202 verbose: true,
203 project_dir: None,
204 };
205
206 let args = build_test_command_args(&cmd);
209
210 assert!(args.contains(&"test"));
211 assert!(args.contains(&"--verbose"));
212 assert!(args.contains(&"--lib"));
213 assert!(!args.contains(&"--test"));
214 }
215
216 #[cfg(test)]
218 fn build_test_command_args(cmd: &TestCommand) -> Vec<&'static str> {
219 let mut args = vec!["test"];
220
221 if cmd.verbose {
222 args.push("--verbose");
223 }
224
225 if cmd.unit && !cmd.integration {
226 args.push("--lib");
227 } else if cmd.integration && !cmd.unit {
228 args.push("--test");
229 }
230
231 args
232 }
233}