diff --git a/.gitignore b/.gitignore index 3772306..ed5d8fe 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,6 @@ /**/target/ /.direnv /.idea/ +/front/build +/front/worktree /tarpaulin* diff --git a/src/alejandra/tests/fmt.rs b/src/alejandra/tests/fmt.rs index 42ac5fc..f628f71 100644 --- a/src/alejandra/tests/fmt.rs +++ b/src/alejandra/tests/fmt.rs @@ -1,5 +1,6 @@ use std::collections::HashMap; use std::io::Write; +use std::path::PathBuf; use alejandra::config::Config; use alejandra::config::Indentation; @@ -11,28 +12,28 @@ fn cases() { let configs = HashMap::from([ ("default", Config::default()), - ("indentation-tabs", Config { - indentation: Indentation::Tabs, - ..Default::default() - }), + ("indentation-tabs", Config { indentation: Indentation::Tabs }), ]); + let cases_path = PathBuf::new().join("tests").join("cases"); + for (config_name, config) in configs { - let cases: Vec = - std::fs::read_dir(format!("tests/cases/{}", config_name)) - .unwrap() - .map(|entry| entry.unwrap().file_name().into_string().unwrap()) - .collect(); + let config_cases_path = cases_path.join(config_name); + + let cases: Vec = std::fs::read_dir(&config_cases_path) + .unwrap() + .map(|entry| entry.unwrap().file_name().into_string().unwrap()) + .collect(); for case in cases { - let path_in = - format!("tests/cases/{}/{}/in.nix", config_name, case); + let case_path = config_cases_path.join(&case); + + let path_in = case_path.join("in.nix"); let content_in = std::fs::read_to_string(&path_in).unwrap(); - let path_out = - format!("tests/cases/{}/{}/out.nix", config_name, case); + let path_out = case_path.join("out.nix"); let content_got = alejandra::format::in_memory( - path_in.clone(), + path_in.to_str().unwrap().to_owned(), content_in.clone(), config, ) @@ -45,14 +46,12 @@ fn cases() { .unwrap(); } - let content_out = - std::fs::read_to_string(path_out.clone()).unwrap(); + let content_out = std::fs::read_to_string(&path_out).unwrap(); assert_eq!( content_out, content_got, - "Test case `{}/{}` failed; see \ - `src/alejandra/tests/cases/{}/{}/`", - config_name, case, config_name, case, + "Test case `{:?}` failed", + case_path ); } } diff --git a/src/alejandra_cli/tests/cli.rs b/src/alejandra_cli/tests/cli.rs new file mode 100644 index 0000000..bab0a02 --- /dev/null +++ b/src/alejandra_cli/tests/cli.rs @@ -0,0 +1,167 @@ +use std::fmt::Write as _; +use std::io::Write as _; +use std::path::PathBuf; +use std::process::Command; +use std::process::Stdio; + +#[derive(Debug)] +struct TestCase { + args: &'static [&'static str], + stdin: Option<&'static str>, +} + +const CASES: &[TestCase] = &[ + TestCase { args: &["--help"], stdin: None }, + TestCase { args: &["--version"], stdin: None }, + TestCase { args: &[], stdin: None }, + TestCase { args: &["--quiet"], stdin: Some("[]") }, + TestCase { args: &["--quiet", "--quiet"], stdin: Some("[]") }, + TestCase { args: &["--check", "--quiet"], stdin: Some("[]\n") }, + TestCase { args: &["--check", "--quiet"], stdin: Some("[\t]") }, + TestCase { args: &["--check", "--quiet", "--quiet"], stdin: Some("[]\n") }, + TestCase { args: &["--check", "--quiet", "--quiet"], stdin: Some("[\t]") }, + TestCase { args: &["--quiet"], stdin: Some("[") }, + TestCase { args: &["--quiet", "--quiet"], stdin: Some("[") }, + TestCase { args: &[".", "--exclude", ".", "--quiet"], stdin: None }, + TestCase { + args: &["--exclude", ".", "--quiet", "--quiet", "--", "."], + stdin: None, + }, + TestCase { + args: &["--check", "tests/inputs/changed.nix", "--quiet"], + stdin: None, + }, + TestCase { + args: &[ + "-c", + "tests/inputs/changed.nix", + "-q", + "-e", + "tests/changed.nix", + ], + stdin: None, + }, + TestCase { + args: &["--check", "tests/inputs/changed.nix", "-qq"], + stdin: None, + }, + TestCase { + args: &["--check", "tests/inputs/unchanged.nix", "-q"], + stdin: None, + }, + TestCase { + args: &["--check", "tests/inputs/unchanged.nix", "-qq"], + stdin: None, + }, + TestCase { + args: &["--check", "tests/inputs/error.nix", "-q"], + stdin: None, + }, + TestCase { + args: &["--check", "tests/inputs/error.nix", "-qq"], + stdin: None, + }, + TestCase { + args: &[ + "--check", + "tests/inputs/unchanged.nix", + "--experimental-config", + "../../alejandra.toml", + "--threads", + "1", + ], + stdin: None, + }, + TestCase { + args: &[ + "--check", + "tests/inputs/unchanged.nix", + "--experimental-config", + "tests/configs/empty_config.toml", + "-t", + "1", + ], + stdin: None, + }, + TestCase { + args: &[ + "--check", + "tests/inputs/unchanged.nix", + "--experimental-config", + "tests/configs/wrong_key.toml", + ], + stdin: None, + }, +]; + +#[test] +fn cases() { + let should_update = std::env::var("UPDATE").is_ok(); + + let output_path = PathBuf::new().join("tests").join("output.txt"); + + let mut output_got = String::new(); + + for case in CASES { + output_got.push_str("===\n"); + output_got.push_str(&format!("args: {:?}\n", case.args)); + + let mut child = Command::new("cargo") + .args(["run", "--quiet", "--"]) + .args(case.args) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn() + .expect("command failed"); + + if let Some(stdin) = case.stdin { + output_got.push_str(&format!("stdin: {:?}\n", stdin)); + + child + .stdin + .take() + .unwrap() + .write_all(stdin.as_bytes()) + .expect("unable to write to child stdin"); + } + + let output = child.wait_with_output().expect("child command failed"); + + let stdout = String::from_utf8(output.stdout).expect("invalid utf-8"); + if !stdout.is_empty() { + output_got + .push_str(&format!("stdout:\n{}\n", indent_and_clean(&stdout))); + } + + let stderr = String::from_utf8(output.stderr).expect("invalid utf-8"); + if !stderr.is_empty() { + output_got + .push_str(&format!("stderr:\n{}\n", indent_and_clean(&stderr))); + } + + output_got + .push_str(&format!("exit code: {:?}\n", output.status.code())); + } + + if should_update { + std::fs::File::create(&output_path) + .unwrap() + .write_all(output_got.as_bytes()) + .unwrap(); + } + + let output_expected = std::fs::read_to_string(&output_path).unwrap(); + + assert_eq!(output_expected, output_got); +} + +fn indent_and_clean(data: &str) -> String { + data.lines().filter(|line| !line.starts_with(['👏', '🤟', '⭐'])).fold( + String::new(), + |mut output, line| { + let _ = writeln!(output, " {}", line); + output + }, + ) +} diff --git a/src/alejandra_cli/tests/configs/empty_config.toml b/src/alejandra_cli/tests/configs/empty_config.toml new file mode 100644 index 0000000..e69de29 diff --git a/src/alejandra_cli/tests/configs/wrong_key.toml b/src/alejandra_cli/tests/configs/wrong_key.toml new file mode 100644 index 0000000..dcd869d --- /dev/null +++ b/src/alejandra_cli/tests/configs/wrong_key.toml @@ -0,0 +1 @@ +asdf = "asdf" diff --git a/src/alejandra_cli/tests/inputs/changed.nix b/src/alejandra_cli/tests/inputs/changed.nix new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/src/alejandra_cli/tests/inputs/changed.nix @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/src/alejandra_cli/tests/inputs/error.nix b/src/alejandra_cli/tests/inputs/error.nix new file mode 100644 index 0000000..8e2f0be --- /dev/null +++ b/src/alejandra_cli/tests/inputs/error.nix @@ -0,0 +1 @@ +[ \ No newline at end of file diff --git a/src/alejandra_cli/tests/inputs/unchanged.nix b/src/alejandra_cli/tests/inputs/unchanged.nix new file mode 100644 index 0000000..fe51488 --- /dev/null +++ b/src/alejandra_cli/tests/inputs/unchanged.nix @@ -0,0 +1 @@ +[] diff --git a/src/alejandra_cli/tests/output.txt b/src/alejandra_cli/tests/output.txt new file mode 100644 index 0000000..4ce495d --- /dev/null +++ b/src/alejandra_cli/tests/output.txt @@ -0,0 +1,190 @@ +=== +args: ["--help"] +stdout: + Alejandra 3.1.0 + The Uncompromising Nix Code Formatter + + USAGE: + alejandra [OPTIONS] [INCLUDE]... + + ARGS: + ... Files or directories, or a single "-" (or leave empty) + to format stdin + + OPTIONS: + -c, --check + Check if the input is already formatted and disable writing in-place + the modified content + + -e, --exclude + Files or directories to exclude from formatting + + --experimental-config + [Experimental] Path to a config file. If not provided, it'll default + to `alejandra.toml` in the current directory. If not found, it'll + use the default style + + -h, --help + Print help information + + -q, --quiet + Use once to hide informational messages, twice to hide error + messages + + -t, --threads + Number of formatting threads to spawn. Defaults to the number of + physical CPUs + + -V, --version + Print version information + + Alejandra will exit with status code: + 1, if any error occurs. + 2, if --check was used and any file requires formatting. + 0, otherwise. + +exit code: Some(0) +=== +args: ["--version"] +stdout: + Alejandra 3.1.0 + +exit code: Some(0) +=== +args: [] +stderr: + Formatting stdin. + Use --help to see all command line options. + use --quiet to suppress this and other messages. + + Failed! 1 error found at: + - : unexpected end of file + +exit code: Some(1) +=== +args: ["--quiet"] +stdin: "[]" +stdout: + [] + +exit code: Some(0) +=== +args: ["--quiet", "--quiet"] +stdin: "[]" +stdout: + [] + +exit code: Some(0) +=== +args: ["--check", "--quiet"] +stdin: "[]\n" +stdout: + [] + +exit code: Some(0) +=== +args: ["--check", "--quiet"] +stdin: "[\t]" +stdout: + [] + +exit code: Some(2) +=== +args: ["--check", "--quiet", "--quiet"] +stdin: "[]\n" +stdout: + [] + +exit code: Some(0) +=== +args: ["--check", "--quiet", "--quiet"] +stdin: "[\t]" +stdout: + [] + +exit code: Some(2) +=== +args: ["--quiet"] +stdin: "[" +stdout: + [ + +stderr: + + Failed! 1 error found at: + - : unexpected end of file + +exit code: Some(1) +=== +args: ["--quiet", "--quiet"] +stdin: "[" +stdout: + [ + +exit code: Some(1) +=== +args: [".", "--exclude", ".", "--quiet"] +exit code: Some(0) +=== +args: ["--exclude", ".", "--quiet", "--quiet", "--", "."] +exit code: Some(0) +=== +args: ["--check", "tests/inputs/changed.nix", "--quiet"] +exit code: Some(2) +=== +args: ["-c", "tests/inputs/changed.nix", "-q", "-e", "tests/changed.nix"] +exit code: Some(2) +=== +args: ["--check", "tests/inputs/changed.nix", "-qq"] +exit code: Some(2) +=== +args: ["--check", "tests/inputs/unchanged.nix", "-q"] +exit code: Some(0) +=== +args: ["--check", "tests/inputs/unchanged.nix", "-qq"] +exit code: Some(0) +=== +args: ["--check", "tests/inputs/error.nix", "-q"] +stderr: + + Failed! 1 error found at: + - tests/inputs/error.nix: unexpected end of file + +exit code: Some(1) +=== +args: ["--check", "tests/inputs/error.nix", "-qq"] +exit code: Some(1) +=== +args: ["--check", "tests/inputs/unchanged.nix", "--experimental-config", "../../alejandra.toml", "--threads", "1"] +stderr: + Using config from: ../../alejandra.toml + Checking style in 1 file using 1 thread. + + + Congratulations! Your code complies with the Alejandra style. + + +exit code: Some(0) +=== +args: ["--check", "tests/inputs/unchanged.nix", "--experimental-config", "tests/configs/empty_config.toml", "-t", "1"] +stderr: + Using config from: tests/configs/empty_config.toml + Checking style in 1 file using 1 thread. + + + Congratulations! Your code complies with the Alejandra style. + + +exit code: Some(0) +=== +args: ["--check", "tests/inputs/unchanged.nix", "--experimental-config", "tests/configs/wrong_key.toml"] +stderr: + Using config from: tests/configs/wrong_key.toml + Errors found in config: TOML parse error at line 1, column 1 + | + 1 | asdf = "asdf" + | ^^^^ + unknown field `asdf`, expected `indentation` + + +exit code: Some(1)