1use std::path::Path;
23use std::process::Command;
24
25pub const NIX_EXPERIMENTAL_FEATURES: &str = "nix-command flakes";
29
30#[must_use]
34fn nix_base(nix_bin: &Path, subcommand: &[&str]) -> Command {
35 let mut cmd = Command::new(nix_bin);
36 cmd.args(subcommand);
37 cmd.args(["--extra-experimental-features", NIX_EXPERIMENTAL_FEATURES]);
38 cmd
39}
40
41#[must_use]
45fn sui_base(sui_bin: &Path, subcommand: &[&str]) -> Command {
46 let mut cmd = Command::new(sui_bin);
47 cmd.args(subcommand);
48 cmd
49}
50
51pub mod nix_cli {
55 use super::*;
56
57 #[must_use]
60 pub fn eval_expr(nix_bin: &Path, expr: &str) -> Command {
61 let mut cmd = nix_base(nix_bin, &["eval", "--impure", "--json"]);
62 cmd.args(["--expr", expr]);
63 cmd
64 }
65
66 #[must_use]
69 pub fn eval_installable(nix_bin: &Path, installable: &str) -> Command {
70 let mut cmd = nix_base(nix_bin, &["eval", "--impure", "--json"]);
71 cmd.arg(installable);
72 cmd
73 }
74
75 #[must_use]
78 pub fn flake_show(nix_bin: &Path, flake_ref: &str) -> Command {
79 let mut cmd = nix_base(nix_bin, &["flake", "show", "--json"]);
80 cmd.arg(flake_ref);
81 cmd
82 }
83
84 #[must_use]
86 pub fn flake_check(nix_bin: &Path, flake_ref: &str) -> Command {
87 let mut cmd = nix_base(nix_bin, &["flake", "check"]);
88 cmd.arg(flake_ref);
89 cmd
90 }
91
92 #[must_use]
96 pub fn build_dry_run(nix_bin: &Path, installable: &str) -> Command {
97 let mut cmd = nix_base(
98 nix_bin,
99 &["build", "--dry-run", "--print-out-paths", "--no-link"],
100 );
101 cmd.arg(installable);
102 cmd
103 }
104}
105
106pub mod sui_cli {
108 use super::*;
109
110 #[must_use]
114 pub fn eval_expr(sui_bin: &Path, expr: &str) -> Command {
115 let mut cmd = sui_base(sui_bin, &["eval", "--json"]);
116 cmd.arg(expr);
117 cmd
118 }
119
120 #[must_use]
123 pub fn eval_installable(sui_bin: &Path, installable: &str) -> Command {
124 let mut cmd = sui_base(sui_bin, &["eval", "--json"]);
125 cmd.arg(installable);
126 cmd
127 }
128
129 #[must_use]
133 pub fn eval_expr_explicit(sui_bin: &Path, expr: &str) -> Command {
134 let mut cmd = sui_base(sui_bin, &["eval", "--impure", "--json"]);
135 cmd.args(["--expr", expr]);
136 cmd
137 }
138
139 #[must_use]
141 pub fn flake_show(sui_bin: &Path, flake_ref: &str) -> Command {
142 let mut cmd = sui_base(sui_bin, &["flake", "show", "--json"]);
143 cmd.arg(flake_ref);
144 cmd
145 }
146
147 #[must_use]
149 pub fn flake_check(sui_bin: &Path, flake_ref: &str) -> Command {
150 let mut cmd = sui_base(sui_bin, &["flake", "check"]);
151 cmd.arg(flake_ref);
152 cmd
153 }
154
155 #[must_use]
157 pub fn build_dry_run(sui_bin: &Path, installable: &str) -> Command {
158 let mut cmd = sui_base(
159 sui_bin,
160 &["build", "--dry-run", "--print-out-paths", "--no-link"],
161 );
162 cmd.arg(installable);
163 cmd
164 }
165}
166
167#[cfg(test)]
168mod tests {
169 use super::*;
170 use crate::exec::command_argv;
171 use std::path::PathBuf;
172
173 fn nix_path() -> PathBuf {
174 PathBuf::from("/usr/local/bin/nix")
175 }
176
177 fn sui_path() -> PathBuf {
178 PathBuf::from("/usr/local/bin/sui")
179 }
180
181 #[test]
182 fn nix_eval_expr_includes_experimental_features() {
183 let cmd = nix_cli::eval_expr(&nix_path(), "1 + 2");
184 let argv = command_argv(&cmd);
185 assert_eq!(argv[0], "/usr/local/bin/nix");
186 assert!(argv.iter().any(|a| a == "--extra-experimental-features"));
187 assert!(argv.iter().any(|a| a == NIX_EXPERIMENTAL_FEATURES));
188 assert!(argv.iter().any(|a| a == "--expr"));
189 assert!(argv.iter().any(|a| a == "1 + 2"));
190 assert!(argv.iter().any(|a| a == "--impure"));
191 assert!(argv.iter().any(|a| a == "--json"));
192 }
193
194 #[test]
195 fn nix_flake_show_includes_experimental_features_and_ref() {
196 let cmd = nix_cli::flake_show(&nix_path(), "path:/tmp/myflake");
197 let argv = command_argv(&cmd);
198 assert!(argv.windows(2).any(|w| w == ["flake", "show"]));
199 assert!(argv.iter().any(|a| a == "--json"));
200 assert!(argv.iter().any(|a| a == "--extra-experimental-features"));
201 assert!(argv.iter().any(|a| a == "path:/tmp/myflake"));
202 }
203
204 #[test]
205 fn nix_build_dry_run_carries_all_flags() {
206 let cmd = nix_cli::build_dry_run(&nix_path(), "path:/tmp/f#x.y");
207 let argv = command_argv(&cmd);
208 for required in ["--dry-run", "--print-out-paths", "--no-link"] {
209 assert!(
210 argv.iter().any(|a| a == required),
211 "build_dry_run missing {required}; argv: {argv:?}",
212 );
213 }
214 }
215
216 #[test]
217 fn sui_eval_expr_is_positional() {
218 let cmd = sui_cli::eval_expr(&sui_path(), "1 + 2");
219 let argv = command_argv(&cmd);
220 assert_eq!(argv[0], "/usr/local/bin/sui");
221 assert_eq!(argv[1], "eval");
222 assert_eq!(argv[2], "--json");
223 assert_eq!(argv[3], "1 + 2");
224 assert!(!argv.iter().any(|a| a == "--extra-experimental-features"));
226 }
227
228 #[test]
229 fn sui_eval_expr_explicit_uses_dash_dash_expr() {
230 let cmd = sui_cli::eval_expr_explicit(&sui_path(), "1 + 2");
231 let argv = command_argv(&cmd);
232 assert!(argv.iter().any(|a| a == "--expr"));
233 assert!(argv.iter().any(|a| a == "1 + 2"));
234 assert!(argv.iter().any(|a| a == "--impure"));
235 }
236
237 #[test]
238 fn sui_flake_show_and_check() {
239 let show = sui_cli::flake_show(&sui_path(), "path:/tmp/f");
240 let check = sui_cli::flake_check(&sui_path(), "path:/tmp/f");
241 let show_argv = command_argv(&show);
242 let check_argv = command_argv(&check);
243 assert!(show_argv.windows(2).any(|w| w == ["flake", "show"]));
244 assert!(check_argv.windows(2).any(|w| w == ["flake", "check"]));
245 assert!(show_argv.iter().any(|a| a == "--json"));
246 assert!(!check_argv.iter().any(|a| a == "--json")); }
248
249 #[test]
250 fn symmetric_signatures() {
251 let p = "path:/tmp/f";
256 let n = nix_cli::flake_show(&nix_path(), p);
257 let s = sui_cli::flake_show(&sui_path(), p);
258 let na = command_argv(&n);
260 let sa = command_argv(&s);
261 assert!(na.iter().any(|a| a == p) && sa.iter().any(|a| a == p));
262 assert!(na.iter().any(|a| a == "--json") && sa.iter().any(|a| a == "--json"));
263 }
264}