use clap::Parser;
use fluent::FluentArgs;
use rust_unique_pass::{GenerationError, RupassArgs, get_translation, initialize_bundle};
type TestResult<T> = std::result::Result<T, String>;
#[test]
fn test_parse_args_short_aliases() {
let args = vec!["test_app", "-L", "eng", "-p", "20", "-n", "-u", "-w", "-s"];
let parsed = parse_args_from_iter(args);
assert_eq!(parsed.language.as_deref(), Some("eng"));
assert_eq!(parsed.password_length, Some(20));
assert!(parsed.numbers);
assert!(parsed.uppercase);
assert!(parsed.lowercase);
assert!(parsed.symbols);
}
#[test]
fn test_parse_args_negative_flags() {
let args = vec![
"test_app",
"--no-numbers",
"--no-uppercase",
"--no-lowercase",
"--no-symbols",
];
let parsed = parse_args_from_iter(args);
assert!(parsed.no_numbers);
assert!(parsed.no_uppercase);
assert!(parsed.no_lowercase);
assert!(parsed.no_symbols);
assert!(!parsed.numbers);
assert!(!parsed.uppercase);
assert!(!parsed.lowercase);
assert!(!parsed.symbols);
}
fn parse_args_from_iter<I, T>(iter: I) -> RupassArgs
where
I: IntoIterator<Item = T>,
T: Into<std::ffi::OsString> + Clone,
{
rust_unique_pass::RupassArgs::parse_from(iter)
}
#[test]
fn test_initialize_bundle_unsupported_language() {
let args = RupassArgs {
language: Some("xxx".to_string()),
password_length: None,
all: false,
no_prompt: false,
numbers: false,
no_numbers: false,
uppercase: false,
no_uppercase: false,
lowercase: false,
no_lowercase: false,
symbols: false,
no_symbols: false,
symbols_set: None,
timeout_ms: 150,
min_score: 4,
strict: false,
show_strength: false,
quiet: false,
};
let result = initialize_bundle(&args);
assert!(matches!(result, Err(GenerationError::UnsupportedLanguage)));
}
#[test]
fn test_get_translation_missing_key() -> TestResult<()> {
let args = RupassArgs {
language: None,
password_length: None,
all: false,
no_prompt: false,
numbers: false,
no_numbers: false,
uppercase: false,
no_uppercase: false,
lowercase: false,
no_lowercase: false,
symbols: false,
no_symbols: false,
symbols_set: None,
timeout_ms: 150,
min_score: 4,
strict: false,
show_strength: false,
quiet: false,
};
let bundle = initialize_bundle(&args).map_err(|e| format!("bundle init failed: {e:?}"))?;
let res = get_translation(&bundle, "this_key_does_not_exist", None);
assert!(matches!(res, Err(GenerationError::TranslationMissing(_))));
Ok(())
}
#[test]
fn test_get_translation_with_args() -> TestResult<()> {
let args = RupassArgs {
language: None,
password_length: None,
all: false,
no_prompt: false,
numbers: false,
no_numbers: false,
uppercase: false,
no_uppercase: false,
lowercase: false,
no_lowercase: false,
symbols: false,
no_symbols: false,
symbols_set: None,
timeout_ms: 150,
min_score: 4,
strict: false,
show_strength: false,
quiet: false,
};
let bundle = initialize_bundle(&args).map_err(|e| format!("bundle init failed: {e:?}"))?;
let mut fluent_args = FluentArgs::new();
fluent_args.set("specialChars", "!@#$");
let text = get_translation(&bundle, "default_special_chars_message", Some(&fluent_args))
.map_err(|e| format!("translation failed: {e:?}"))?;
assert!(
text.contains("!@#$"),
"Should contain the special chars in the message"
);
Ok(())
}
#[test]
fn test_initialize_bundle_jpn() -> TestResult<()> {
let args = RupassArgs {
language: Some("jpn".to_string()),
password_length: None,
all: false,
no_prompt: false,
numbers: false,
no_numbers: false,
uppercase: false,
no_uppercase: false,
lowercase: false,
no_lowercase: false,
symbols: false,
no_symbols: false,
symbols_set: None,
timeout_ms: 150,
min_score: 4,
strict: false,
show_strength: false,
quiet: false,
};
let bundle = initialize_bundle(&args).map_err(|e| format!("bundle init failed: {e:?}"))?;
let question_special_chars = get_translation(&bundle, "question_special_chars", None)
.map_err(|e| format!("translation failed: {e:?}"))?;
assert!(
question_special_chars.contains("特殊文字を含めますか?"),
"Should contain Japanese text"
);
Ok(())
}
#[test]
fn test_initialize_bundle_en_alias() -> TestResult<()> {
let args = RupassArgs {
language: Some("en".to_string()),
password_length: None,
all: false,
no_prompt: false,
numbers: false,
no_numbers: false,
uppercase: false,
no_uppercase: false,
lowercase: false,
no_lowercase: false,
symbols: false,
no_symbols: false,
symbols_set: None,
timeout_ms: 150,
min_score: 4,
strict: false,
show_strength: false,
quiet: false,
};
let bundle = initialize_bundle(&args).map_err(|e| format!("bundle init failed: {e:?}"))?;
let message = get_translation(&bundle, "generated_password", None)
.map_err(|e| format!("translation failed: {e:?}"))?;
assert!(
message.contains("Password Generation Result"),
"English translation should be returned for alias en"
);
Ok(())
}
#[test]
fn test_jpn_translation_error_message() -> TestResult<()> {
let args = RupassArgs {
language: Some("jpn".to_string()),
password_length: None,
all: false,
no_prompt: false,
numbers: false,
no_numbers: false,
uppercase: false,
no_uppercase: false,
lowercase: false,
no_lowercase: false,
symbols: false,
no_symbols: false,
symbols_set: None,
timeout_ms: 150,
min_score: 4,
strict: false,
show_strength: false,
quiet: false,
};
let bundle = initialize_bundle(&args).map_err(|e| format!("bundle init failed: {e:?}"))?;
let too_short = get_translation(&bundle, "error_password_too_short", None)
.map_err(|e| format!("translation failed: {e:?}"))?;
assert!(
too_short.contains("パスワードは15文字以上を推奨します。"),
"Japanese short password error message should match"
);
Ok(())
}
#[test]
fn test_compare_eng_and_jpn_translations() -> TestResult<()> {
let eng_args = RupassArgs {
language: Some("eng".to_string()),
password_length: None,
all: false,
no_prompt: false,
numbers: false,
no_numbers: false,
uppercase: false,
no_uppercase: false,
lowercase: false,
no_lowercase: false,
symbols: false,
no_symbols: false,
symbols_set: None,
timeout_ms: 150,
min_score: 4,
strict: false,
show_strength: false,
quiet: false,
};
let jpn_args = RupassArgs {
language: Some("jpn".to_string()),
password_length: None,
all: false,
no_prompt: false,
numbers: false,
no_numbers: false,
uppercase: false,
no_uppercase: false,
lowercase: false,
no_lowercase: false,
symbols: false,
no_symbols: false,
symbols_set: None,
timeout_ms: 150,
min_score: 4,
strict: false,
show_strength: false,
quiet: false,
};
let eng_bundle =
initialize_bundle(&eng_args).map_err(|e| format!("bundle init failed: {e:?}"))?;
let jpn_bundle =
initialize_bundle(&jpn_args).map_err(|e| format!("bundle init failed: {e:?}"))?;
let eng_text = get_translation(&eng_bundle, "error_no_charset_selected", None)
.map_err(|e| format!("translation failed: {e:?}"))?;
let jpn_text = get_translation(&jpn_bundle, "error_no_charset_selected", None)
.map_err(|e| format!("translation failed: {e:?}"))?;
assert_ne!(
eng_text, jpn_text,
"English and Japanese messages for the same key should differ"
);
assert!(
eng_text.contains("Error: No character set selected"),
"English error_no_charset_selected should contain the English phrase"
);
assert!(
jpn_text.contains("エラー: 文字セットが選択されていません"),
"Japanese error_no_charset_selected should contain the Japanese phrase"
);
Ok(())
}
#[test]
fn test_default_language_is_eng() -> TestResult<()> {
let args = RupassArgs {
language: None,
password_length: None,
all: false,
no_prompt: false,
numbers: false,
no_numbers: false,
uppercase: false,
no_uppercase: false,
lowercase: false,
no_lowercase: false,
symbols: false,
no_symbols: false,
symbols_set: None,
timeout_ms: 150,
min_score: 4,
strict: false,
show_strength: false,
quiet: false,
};
let bundle = initialize_bundle(&args).map_err(|e| format!("bundle init failed: {e:?}"))?;
let eng_text = get_translation(&bundle, "question_change_special_chars", None)
.map_err(|e| format!("translation failed: {e:?}"))?;
assert!(
eng_text.contains("Change the special characters used?"),
"Default language (eng) message should contain 'Change the special characters used?'"
);
Ok(())
}