Skip to main content

domi_server/http/
args.rs

1use std::path::PathBuf;
2
3use clap::Parser;
4
5#[derive(Parser, Debug, Clone)]
6#[command(name = "domi-server", version, about = "DOMicile live feedback server")]
7pub struct Args {
8    #[arg(long, default_value = "4173", value_parser = clap::value_parser!(u16).range(0..=65535))]
9    pub port: u16,
10    #[arg(long, default_value = "127.0.0.1")]
11    pub host: String,
12    #[arg(long, default_value = ".domi/output")]
13    pub root: PathBuf,
14    #[arg(long, default_value = ".domi/state")]
15    pub state: PathBuf,
16    #[arg(long)]
17    pub library_root: Option<PathBuf>,
18    #[arg(long, default_value = "info")]
19    pub log_level: String,
20}
21
22#[cfg(test)]
23mod tests {
24    use super::*;
25
26    #[test]
27    fn defaults_apply_when_no_flags() {
28        let a = Args::try_parse_from(["domi-server"]).unwrap();
29        assert_eq!(a.port, 4173);
30        assert_eq!(a.host, "127.0.0.1");
31        assert_eq!(a.root, PathBuf::from(".domi/output"));
32        assert_eq!(a.state, PathBuf::from(".domi/state"));
33        assert_eq!(a.log_level, "info");
34    }
35
36    #[test]
37    fn overrides_parse() {
38        let a = Args::try_parse_from([
39            "domi-server",
40            "--port",
41            "9000",
42            "--host",
43            "0.0.0.0",
44            "--root",
45            "/tmp/root",
46            "--state",
47            "/tmp/state",
48            "--log-level",
49            "debug",
50        ])
51        .unwrap();
52        assert_eq!(a.port, 9000);
53        assert_eq!(a.host, "0.0.0.0");
54        assert_eq!(a.root, PathBuf::from("/tmp/root"));
55        assert_eq!(a.state, PathBuf::from("/tmp/state"));
56        assert_eq!(a.log_level, "debug");
57    }
58
59    #[test]
60    fn invalid_port_rejected() {
61        let r = Args::try_parse_from(["domi-server", "--port", "not-a-number"]);
62        assert!(r.is_err(), "expected parse error for non-numeric port");
63    }
64    /// Phase 2d Task 1: `--port 0` must be accepted so the verify script can
65    /// let the kernel pick an ephemeral port. Lifted lower bound from `1..`
66    /// to `0..=65535` (full `u16` range).
67    #[test]
68    fn port_zero_accepted() {
69        let a = Args::try_parse_from(["domi-server", "--port", "0"]).expect("--port 0 must parse");
70        assert_eq!(a.port, 0);
71    }
72
73    #[test]
74    fn library_root_defaults_to_none() {
75        let a = Args::try_parse_from(["domi-server"]).unwrap();
76        assert!(a.library_root.is_none(), "library_root must default to None");
77    }
78
79    #[test]
80    fn library_root_accepts_path() {
81        let a = Args::try_parse_from(["domi-server", "--library-root", "/tmp/lib"]).unwrap();
82        assert_eq!(a.library_root, Some(PathBuf::from("/tmp/lib")));
83    }
84
85    #[test]
86    fn library_root_can_be_omitted_alongside_other_flags() {
87        let a = Args::try_parse_from([
88            "domi-server",
89            "--port", "9000",
90            "--root", "/tmp/r",
91            "--state", "/tmp/s",
92        ])
93        .unwrap();
94        assert!(a.library_root.is_none());
95        assert_eq!(a.port, 9000);
96    }
97}