Skip to content

Commit c565ed9

Browse files
committed
fix(cli): enforce strict status filtering metadata requirement
1 parent d297df0 commit c565ed9

2 files changed

Lines changed: 93 additions & 0 deletions

File tree

langcodec-cli/src/main.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,13 @@ fn is_custom_input_extension(input: &str) -> bool {
335335
|| input.ends_with(".langcodec")
336336
}
337337

338+
fn input_supports_explicit_status_metadata(input: &str) -> bool {
339+
std::path::Path::new(input)
340+
.extension()
341+
.and_then(|ext| ext.to_str())
342+
.is_some_and(|ext| ext.eq_ignore_ascii_case("xcstrings"))
343+
}
344+
338345
fn load_codec_for_readonly_command(
339346
input: &str,
340347
lang: &Option<String>,
@@ -545,6 +552,13 @@ fn main() {
545552
std::process::exit(1);
546553
}
547554

555+
if strict && status.is_some() && !input_supports_explicit_status_metadata(&input) {
556+
eprintln!(
557+
"❌ Strict mode with --status requires explicit status metadata. Supported in v1: .xcstrings"
558+
);
559+
std::process::exit(1);
560+
}
561+
548562
let codec = match load_codec_for_readonly_command(&input, &lang, strict) {
549563
Ok(codec) => codec,
550564
Err(e) => {

langcodec-cli/tests/view_status_cli_tests.rs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,85 @@ fn write_xcstrings_partial_match_fixture(path: &std::path::Path) {
110110
fs::write(path, xcstrings).unwrap();
111111
}
112112

113+
fn write_android_strings_fixture(path: &std::path::Path) {
114+
let xml = r#"<?xml version="1.0" encoding="utf-8"?>
115+
<resources>
116+
<string name="translated_key">Hello</string>
117+
<string name="needs_review_key">Needs review</string>
118+
</resources>
119+
"#;
120+
121+
fs::write(path, xml).unwrap();
122+
}
123+
124+
#[test]
125+
fn test_view_status_strict_rejects_android_strings_without_status_metadata() {
126+
let temp_dir = TempDir::new().unwrap();
127+
let input_file = temp_dir.path().join("strings.xml");
128+
write_android_strings_fixture(&input_file);
129+
130+
let output = langcodec_cmd()
131+
.args([
132+
"--strict",
133+
"view",
134+
"-i",
135+
input_file.to_str().unwrap(),
136+
"--lang",
137+
"en",
138+
"--status",
139+
"translated",
140+
])
141+
.output()
142+
.unwrap();
143+
144+
assert!(
145+
!output.status.success(),
146+
"CLI unexpectedly succeeded. stdout: {}",
147+
String::from_utf8_lossy(&output.stdout)
148+
);
149+
150+
let stderr = String::from_utf8_lossy(&output.stderr);
151+
assert!(
152+
stderr.contains("explicit status metadata"),
153+
"Expected strict status metadata guard error. stderr: {}",
154+
stderr
155+
);
156+
}
157+
158+
#[test]
159+
fn test_view_status_strict_allows_xcstrings_with_status_metadata() {
160+
let temp_dir = TempDir::new().unwrap();
161+
let input_file = temp_dir.path().join("Localizable.xcstrings");
162+
write_xcstrings_fixture(&input_file);
163+
164+
let output = langcodec_cmd()
165+
.args([
166+
"--strict",
167+
"view",
168+
"-i",
169+
input_file.to_str().unwrap(),
170+
"--lang",
171+
"en",
172+
"--status",
173+
"needs_review",
174+
])
175+
.output()
176+
.unwrap();
177+
178+
assert!(
179+
output.status.success(),
180+
"CLI failed: {}",
181+
String::from_utf8_lossy(&output.stderr)
182+
);
183+
184+
let stdout = String::from_utf8_lossy(&output.stdout);
185+
assert!(
186+
stdout.contains("needs_review_key"),
187+
"Expected filtered entry in output. stdout: {}",
188+
stdout
189+
);
190+
}
191+
113192
#[test]
114193
fn test_view_status_filters_single_status_for_lang() {
115194
let temp_dir = TempDir::new().unwrap();

0 commit comments

Comments
 (0)