Skip to content

Commit 0caeab6

Browse files
committed
test(date): validate locale formats via runtime expansion
Replace literal format code checks with validation of expanded output. Fixes test failures on macOS 15.7.2 where nl_langinfo returns composite format codes instead of explicit ones. Fixes #9654
1 parent 502f3b1 commit 0caeab6

File tree

2 files changed

+76
-23
lines changed

2 files changed

+76
-23
lines changed

.vscode/cspell.dictionaries/jargon.wordlist.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ shortcodes
136136
siginfo
137137
sigusr
138138
strcasecmp
139+
strtime
139140
subcommand
140141
subexpression
141142
submodule

src/uu/date/src/locale.rs

Lines changed: 75 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,28 @@ mod tests {
112112
cfg_langinfo! {
113113
use super::*;
114114

115+
/// Helper function to expand a format string with a known test date
116+
///
117+
/// Uses a fixed test date: Monday, January 15, 2024, 14:30:45 UTC
118+
/// This allows us to validate format strings by checking their expanded output
119+
/// rather than looking for literal format codes.
120+
fn expand_format_with_test_date(format: &str) -> String {
121+
use jiff::civil::date;
122+
use jiff::fmt::strtime;
123+
124+
// Create test timestamp: Monday, January 15, 2024, 14:30:45 UTC
125+
let test_date = match date(2024, 1, 15).at(14, 30, 45, 0).in_tz("UTC") {
126+
Ok(zoned) => zoned,
127+
Err(_) => return String::new(),
128+
};
129+
130+
// Expand the format string with the test date
131+
match strtime::format(format, &test_date) {
132+
Ok(expanded) => expanded,
133+
Err(_) => String::new(),
134+
}
135+
}
136+
115137
#[test]
116138
fn test_locale_detection() {
117139
// Just verify the function doesn't panic
@@ -121,10 +143,31 @@ mod tests {
121143
#[test]
122144
fn test_default_format_contains_valid_codes() {
123145
let format = get_locale_default_format();
124-
assert!(format.contains("%a")); // abbreviated weekday
125-
assert!(format.contains("%b")); // abbreviated month
126-
assert!(format.contains("%Y") || format.contains("%y")); // year (4-digit or 2-digit)
127-
assert!(format.contains("%Z")); // timezone
146+
147+
let expanded = expand_format_with_test_date(&format);
148+
149+
// Verify expanded output contains expected components
150+
// Test date: Monday, January 15, 2024, 14:30:45
151+
assert!(
152+
expanded.contains("Mon") || expanded.contains("Monday"),
153+
"Expanded format should contain weekday name, got: {}", expanded
154+
);
155+
156+
assert!(
157+
expanded.contains("Jan") || expanded.contains("January"),
158+
"Expanded format should contain month name, got: {}", expanded
159+
);
160+
161+
assert!(
162+
expanded.contains("2024") || expanded.contains("24"),
163+
"Expanded format should contain year, got: {}", expanded
164+
);
165+
166+
// Keep literal %Z check - this is enforced by ensure_timezone_in_format()
167+
assert!(
168+
format.contains("%Z"),
169+
"Format string must contain %Z timezone (enforced by ensure_timezone_in_format)"
170+
);
128171
}
129172

130173
#[test]
@@ -135,25 +178,34 @@ mod tests {
135178
// The format should not be empty
136179
assert!(!format.is_empty(), "Locale format should not be empty");
137180

138-
// Should contain date/time components
139-
let has_date_component = format.contains("%a")
140-
|| format.contains("%A")
141-
|| format.contains("%b")
142-
|| format.contains("%B")
143-
|| format.contains("%d")
144-
|| format.contains("%e");
145-
assert!(has_date_component, "Format should contain date components");
146-
147-
// Should contain time component (hour)
148-
let has_time_component = format.contains("%H")
149-
|| format.contains("%I")
150-
|| format.contains("%k")
151-
|| format.contains("%l")
152-
|| format.contains("%r")
153-
|| format.contains("%R")
154-
|| format.contains("%T")
155-
|| format.contains("%X");
156-
assert!(has_time_component, "Format should contain time components");
181+
let expanded = expand_format_with_test_date(&format);
182+
183+
// Verify expanded output contains date components
184+
// Test date: Monday, January 15, 2024
185+
let has_date_component = expanded.contains("15") // day
186+
|| expanded.contains("Jan") // month name
187+
|| expanded.contains("January") // full month
188+
|| expanded.contains("Mon") // weekday
189+
|| expanded.contains("Monday"); // full weekday
190+
191+
assert!(
192+
has_date_component,
193+
"Expanded format should contain date components, got: {}", expanded
194+
);
195+
196+
// Verify expanded output contains time components
197+
// Test time: 14:30:45
198+
let has_time_component = expanded.contains("14") // 24-hour
199+
|| expanded.contains("02") // 12-hour
200+
|| expanded.contains("30") // minutes
201+
|| expanded.contains(":") // time separator
202+
|| expanded.contains("PM") // AM/PM indicator
203+
|| expanded.contains("pm");
204+
205+
assert!(
206+
has_time_component,
207+
"Expanded format should contain time components, got: {}", expanded
208+
);
157209
}
158210

159211
#[test]

0 commit comments

Comments
 (0)