#![warn(clippy::nursery)]
#![deny(
unused,
nonstandard_style,
future_incompatible,
missing_copy_implementations,
missing_debug_implementations,
clippy::pedantic,
clippy::complexity,
clippy::correctness,
clippy::perf,
clippy::style,
clippy::suspicious,
missing_docs
)]
#![allow(clippy::multiple_crate_versions, clippy::cargo)]
use clap::Parser;
use clap::CommandFactory;
use miette::Result;
use rand::prelude::*;
use std::io::stdout;
use clap_complete::generate;
use rand::rng;
mod cli;
use crate::cli::Arguments as CliArgs;
fn generate_name(args: &CliArgs) -> Result<String> {
let separator = args
.separator
.clone()
.ok_or_else(|| miette::miette!("Failed to get default value for separator"))?;
match args {
CliArgs {
suffix: true,
initial_seed: Some(seed),
..
} => Ok(
anarchist_readable_name_generator_lib::readable_name_custom_suffix(
&separator,
SmallRng::seed_from_u64(*seed),
),
),
CliArgs {
suffix: false,
initial_seed: Some(seed),
..
} => Ok(anarchist_readable_name_generator_lib::readable_name_custom(
&separator,
SmallRng::seed_from_u64(*seed),
)),
CliArgs {
suffix: true,
initial_seed: None,
..
} => Ok(
anarchist_readable_name_generator_lib::readable_name_custom_suffix(&separator, rng()),
),
CliArgs {
suffix: false,
initial_seed: None,
..
} => Ok(anarchist_readable_name_generator_lib::readable_name_custom(
&separator,
rng(),
)),
}
}
fn main() -> Result<()> {
miette::set_panic_hook();
let args: CliArgs = CliArgs::parse();
if let Some(shell) = args.completion_shell {
let mut cmd = CliArgs::command();
let name = cmd.get_name().to_string();
generate(shell, &mut cmd, name, &mut stdout());
return Ok(());
}
let name = generate_name(&args)?;
println!("{name}");
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use clap::Parser;
use std::io;
use std::panic;
use std::process::Command;
use std::str;
#[test]
fn test_completion_shell() {
let result = panic::catch_unwind(|| {
let args = CliArgs::parse_from(["program", "--completion-shell", "bash"]);
assert!(
args.completion_shell.is_some(),
"Completion shell should be set"
);
if let Some(shell) = args.completion_shell {
let mut cmd = CliArgs::command();
let name = cmd.get_name().to_string();
let mut output = Vec::new();
generate(shell, &mut cmd, name, &mut io::Cursor::new(&mut output));
assert!(
!output.is_empty(),
"Shell completion output should not be empty"
);
}
});
assert!(
result.is_ok(),
"Main function panicked unexpectedly with completion shell"
);
}
#[test]
fn default_behavior() {
let output = Command::new("cargo")
.args(["run", "--"])
.output()
.expect("Failed to execute cargo run command");
assert!(output.status.success(), "cargo run command failed");
let output_str = str::from_utf8(&output.stdout).expect("Output was not valid UTF-8");
assert!(
!output_str.trim().is_empty(),
"Application output should not be empty"
);
assert!(
output_str.contains('_'),
"Output should contain the default separator '_'"
);
}
#[test]
fn suffix_behavior() {
let output = Command::new("cargo")
.args(["run", "--quiet", "--", "--suffix"])
.output()
.expect("Failed to execute cargo run command");
assert!(output.status.success(), "cargo run command failed");
let output_str = str::from_utf8(&output.stdout).expect("Output was not valid UTF-8");
assert!(
!output_str.trim().is_empty(),
"Application output should not be empty"
);
assert!(
output_str.trim_end().ends_with(char::is_numeric),
"Output should end with a number"
);
}
#[test]
fn test_application_custom_separator() {
let output = Command::new("cargo")
.args(["run", "--"])
.output()
.expect("Failed to execute cargo run command");
let output_str = str::from_utf8(&output.stdout).expect("Output was not valid UTF-8");
let output_custom = Command::new("cargo")
.args(["run", "--", "--separator", "-"])
.output()
.expect("Failed to execute cargo run command with custom separator");
assert!(
output_custom.status.success(),
"cargo run command with custom separator failed"
);
let output_custom_str =
str::from_utf8(&output_custom.stdout).expect("Output was not valid UTF-8");
assert!(
output_custom_str.contains('-'),
"Output should contain the custom separator '-'"
);
assert_ne!(
output_str, output_custom_str,
"Different runs should produce different outputs"
);
}
#[test]
fn test_application_with_seed() {
let seed_output1 = Command::new("cargo")
.args(["run", "--", "--initial-seed", "42"])
.output()
.expect("Failed to execute cargo run command with seed");
let seed_output2 = Command::new("cargo")
.args(["run", "--", "--initial-seed", "42"])
.output()
.expect("Failed to execute cargo run command with seed");
assert!(
seed_output1.status.success(),
"cargo run command with seed failed"
);
assert!(
seed_output2.status.success(),
"cargo run command with seed failed"
);
let seed_output_str1 =
str::from_utf8(&seed_output1.stdout).expect("Output was not valid UTF-8");
let seed_output_str2 =
str::from_utf8(&seed_output2.stdout).expect("Output was not valid UTF-8");
assert!(
!seed_output_str1.trim().is_empty(),
"Application output with seed should not be empty"
);
assert!(
!seed_output_str2.trim().is_empty(),
"Application output with seed should not be empty"
);
assert_eq!(
seed_output_str1, seed_output_str2,
"Outputs generated with the same seed should be identical"
);
}
}