#![allow(clippy::expect_used)]
use std::path::Path;
use std::path::PathBuf;
use std::process::Command;
use std::process::Output;
fn workspace_root() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR"))
.parent()
.expect("parent of crates/polyplugc")
.parent()
.expect("workspace root")
.to_path_buf()
}
fn test_api_toml() -> PathBuf {
workspace_root()
.join("tests")
.join("fixtures")
.join("test_api.toml")
}
fn test_bundle_toml() -> PathBuf {
workspace_root()
.join("tests")
.join("fixtures")
.join("test_bundle.toml")
}
fn run_polyplugc(args: &[&str]) -> Output {
Command::new(env!("CARGO_BIN_EXE_polyplugc"))
.args(args)
.output()
.expect("failed to spawn polyplugc")
}
fn assert_failure_contains(output: &Output, needle: &str) {
assert!(
!output.status.success(),
"expected failure but process succeeded.\nstdout: {}\nstderr: {}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr),
);
let stderr: String = String::from_utf8_lossy(&output.stderr).into_owned();
let stdout: String = String::from_utf8_lossy(&output.stdout).into_owned();
assert!(
stderr.contains(needle) || stdout.contains(needle),
"expected output to contain {:?}\nstdout: {}\nstderr: {}",
needle,
stdout,
stderr,
);
}
fn assert_success(output: &Output) {
assert!(
output.status.success(),
"expected success but process failed.\nstdout: {}\nstderr: {}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr),
);
}
#[test]
fn generate_missing_api_and_bundle_fails() {
let out_dir: PathBuf =
PathBuf::from(env!("CARGO_TARGET_TMPDIR")).join("cli_val_generate_missing_api_bundle");
let output: Output = run_polyplugc(&[
"generate",
"--lang",
"rust",
"--out",
out_dir.to_str().expect("out_dir utf8"),
]);
assert_failure_contains(&output, "Must specify --api or --bundle");
}
#[test]
fn generate_invalid_lang_fails() {
let out_dir: PathBuf =
PathBuf::from(env!("CARGO_TARGET_TMPDIR")).join("cli_val_generate_invalid_lang");
let api_toml: PathBuf = test_api_toml();
let output: Output = run_polyplugc(&[
"generate",
"--api",
api_toml.to_str().expect("api_toml utf8"),
"--lang",
"cobol",
"--out",
out_dir.to_str().expect("out_dir utf8"),
]);
assert_failure_contains(&output, "Unknown language");
}
#[test]
fn generate_invalid_lang_empty_string_fails() {
let out_dir: PathBuf =
PathBuf::from(env!("CARGO_TARGET_TMPDIR")).join("cli_val_generate_invalid_lang_empty");
let api_toml: PathBuf = test_api_toml();
let output: Output = run_polyplugc(&[
"generate",
"--api",
api_toml.to_str().expect("api_toml utf8"),
"--lang",
"",
"--out",
out_dir.to_str().expect("out_dir utf8"),
]);
assert_failure_contains(&output, "Unknown language");
}
fn assert_lang_alias_accepted(alias: &str) {
let out_dir: PathBuf =
PathBuf::from(env!("CARGO_TARGET_TMPDIR")).join(format!("cli_val_alias_{alias}"));
let api_toml: PathBuf = test_api_toml();
let output: Output = run_polyplugc(&[
"generate",
"--api",
api_toml.to_str().expect("api_toml utf8"),
"--lang",
alias,
"--out",
out_dir.to_str().expect("out_dir utf8"),
]);
let stderr: String = String::from_utf8_lossy(&output.stderr).into_owned();
let stdout: String = String::from_utf8_lossy(&output.stdout).into_owned();
assert!(
!stderr.contains("Unknown language") && !stdout.contains("Unknown language"),
"alias {:?} was rejected as unknown language\nstdout: {}\nstderr: {}",
alias,
stdout,
stderr,
);
}
#[test]
fn generate_lang_alias_cpp_accepted() {
assert_lang_alias_accepted("cpp");
}
#[test]
fn generate_lang_alias_cpp_plus_accepted() {
assert_lang_alias_accepted("c++");
}
#[test]
fn generate_lang_alias_csharp_accepted() {
assert_lang_alias_accepted("csharp");
}
#[test]
fn generate_lang_alias_c_hash_accepted() {
assert_lang_alias_accepted("c#");
}
#[test]
fn generate_lang_alias_python_accepted() {
assert_lang_alias_accepted("python");
}
#[test]
fn generate_lang_alias_py_accepted() {
assert_lang_alias_accepted("py");
}
#[test]
fn generate_lang_alias_lua_accepted() {
assert_lang_alias_accepted("lua");
}
#[test]
fn generate_lang_alias_js_quickjs_accepted() {
assert_lang_alias_accepted("js-quickjs");
}
#[test]
fn generate_api_and_bundle_conflict_fails() {
let out_dir: PathBuf =
PathBuf::from(env!("CARGO_TARGET_TMPDIR")).join("cli_val_generate_conflict");
let api_toml: PathBuf = test_api_toml();
let bundle_toml: PathBuf = test_bundle_toml();
let output: Output = run_polyplugc(&[
"generate",
"--api",
api_toml.to_str().expect("api_toml utf8"),
"--bundle",
bundle_toml.to_str().expect("bundle_toml utf8"),
"--lang",
"rust",
"--out",
out_dir.to_str().expect("out_dir utf8"),
]);
assert_failure_contains(&output, "cannot be used with");
}
#[test]
fn generate_nonexistent_api_path_fails() {
let out_dir: PathBuf =
PathBuf::from(env!("CARGO_TARGET_TMPDIR")).join("cli_val_generate_nonexistent_api");
let output: Output = run_polyplugc(&[
"generate",
"--api",
"/nonexistent/path/to/api.toml",
"--lang",
"rust",
"--out",
out_dir.to_str().expect("out_dir utf8"),
]);
assert!(
!output.status.success(),
"expected failure for non-existent --api path\nstdout: {}\nstderr: {}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr),
);
}
#[test]
fn generate_missing_out_fails() {
let api_toml: PathBuf = test_api_toml();
let output: Output = run_polyplugc(&[
"generate",
"--api",
api_toml.to_str().expect("api_toml utf8"),
"--lang",
"rust",
]);
assert!(
!output.status.success(),
"expected failure when --out is omitted\nstdout: {}\nstderr: {}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr),
);
}
#[test]
fn validate_missing_api_and_bundle_fails() {
let output: Output = run_polyplugc(&["validate"]);
assert_failure_contains(&output, "Must specify --api, --bundle, or --bundle-dir");
}
#[test]
fn validate_api_and_bundle_conflict_fails() {
let api_toml: PathBuf = test_api_toml();
let bundle_toml: PathBuf = test_bundle_toml();
let output: Output = run_polyplugc(&[
"validate",
"--api",
api_toml.to_str().expect("api_toml utf8"),
"--bundle",
bundle_toml.to_str().expect("bundle_toml utf8"),
]);
assert_failure_contains(&output, "cannot be used with");
}
#[test]
fn validate_nonexistent_api_path_fails() {
let output: Output = run_polyplugc(&["validate", "--api", "/nonexistent/path/to/api.toml"]);
assert!(
!output.status.success(),
"expected failure for non-existent --api path\nstdout: {}\nstderr: {}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr),
);
}
#[test]
fn validate_valid_api_toml_succeeds() {
let api_toml: PathBuf = test_api_toml();
let output: Output = run_polyplugc(&[
"validate",
"--api",
api_toml.to_str().expect("api_toml utf8"),
]);
assert_success(&output);
let stdout: String = String::from_utf8_lossy(&output.stdout).into_owned();
assert!(stdout.contains("OK"), "expected OK in stdout: {stdout}");
}
#[test]
fn validate_bundle_dir_conflicts_with_api() {
let api_toml: PathBuf = test_api_toml();
let output: Output = run_polyplugc(&[
"validate",
"--api",
api_toml.to_str().expect("api_toml utf8"),
"--bundle-dir",
"/tmp/some-dir",
]);
assert!(
!output.status.success(),
"--api and --bundle-dir must conflict\nstdout: {}\nstderr: {}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr),
);
}
#[test]
fn validate_bundle_dir_nonexistent_fails() {
let output: Output = run_polyplugc(&[
"validate",
"--bundle-dir",
"/nonexistent/path/to/bundle-dir",
]);
assert!(
!output.status.success(),
"validate --bundle-dir on a missing dir must fail\nstdout: {}\nstderr: {}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr),
);
}
#[test]
fn unknown_subcommand_fails() {
let output: Output = run_polyplugc(&["frobnicate"]);
assert!(
!output.status.success(),
"expected failure for unknown subcommand\nstdout: {}\nstderr: {}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr),
);
}
#[test]
fn no_arguments_fails() {
let output: Output = run_polyplugc(&[]);
assert!(
!output.status.success(),
"expected failure when no arguments given\nstdout: {}\nstderr: {}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr),
);
}