1use crate::{Error, Result};
3use clap::Args;
4
5#[derive(Args)]
7#[command(group = clap::ArgGroup::new("question-id").args(&["id", "daily"]).required(true))]
8pub struct TestArgs {
9 #[arg(value_parser = clap::value_parser!(i32))]
11 pub id: Option<i32>,
12
13 pub testcase: Option<String>,
15
16 #[arg(short = 'd', long)]
18 pub daily: bool,
19
20 #[arg(short, long)]
22 pub watch: bool,
23}
24
25impl TestArgs {
26 pub async fn run(&self) -> Result<()> {
28 use crate::cache::{Cache, Run};
29 use crate::helper::code_path;
30 use notify::{Config as NotifyConfig, RecommendedWatcher, RecursiveMode, Watcher};
31 use std::path::Path;
32 use std::sync::mpsc::channel;
33 use std::time::{Duration, Instant};
34
35 let cache = Cache::new()?;
36 let daily_id = if self.daily {
37 Some(cache.get_daily_problem_id().await?)
38 } else {
39 None
40 };
41
42 let id = self.id.or(daily_id).ok_or(Error::NoneError)?;
43
44 let case_str: Option<String> = self.testcase.as_ref().map(|case| case.replace("\\n", "\n"));
45
46 if self.watch {
47 let problem = cache.get_problem(id)?;
48 let path_str = code_path(&problem, None)?;
49 let path = Path::new(&path_str);
50 let parent = path
51 .parent()
52 .ok_or_else(|| anyhow::anyhow!("Could not get parent directory"))?;
53
54 let (tx, rx) = channel();
55 let mut watcher = RecommendedWatcher::new(tx, NotifyConfig::default())
56 .map_err(|e| anyhow::anyhow!("Failed to create watcher: {}", e))?;
57
58 watcher
60 .watch(parent, RecursiveMode::NonRecursive)
61 .map_err(|e| anyhow::anyhow!("Failed to watch parent directory: {}", e))?;
62
63 if path.exists() {
64 println!("Watching for changes in {}...", path_str);
65 let res = cache.exec_problem(id, Run::Test, case_str.clone()).await?;
66 println!("{}", res);
67 } else {
68 println!("File {} does not exist. Waiting for creation...", path_str);
69 }
70
71 let mut last_run = Instant::now() - Duration::from_secs(1);
72 while let Ok(res_event) = rx.recv() {
73 match res_event {
74 Ok(event) if event.paths.iter().any(|p| p == path) => {
75 if event.kind.is_create() {
76 println!("File created, watching for changes...");
77 } else if event.kind.is_modify() {
78 if last_run.elapsed() < Duration::from_millis(500) {
80 continue;
81 }
82
83 std::thread::sleep(Duration::from_millis(200));
85 while rx.try_recv().is_ok() {}
87
88 if !path.exists() {
89 continue;
90 }
91 println!("File changed, testing again...");
92 match cache.exec_problem(id, Run::Test, case_str.clone()).await {
93 Ok(res) => println!("{}", res),
94 Err(e) => println!("Error: {}", e),
95 }
96 last_run = Instant::now();
97 }
98 }
99 Err(e) => println!("watch error: {:?}", e),
100 _ => {}
101 }
102 }
103 } else {
104 let res = cache.exec_problem(id, Run::Test, case_str).await?;
105 println!("{}", res);
106 }
107 Ok(())
108 }
109}