Skip to content

Commit 8ef5708

Browse files
committed
Add locale parsing tests
1 parent d979416 commit 8ef5708

File tree

1 file changed

+73
-15
lines changed

1 file changed

+73
-15
lines changed

src/desktop/locale.rs

Lines changed: 73 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,31 @@ use std::ffi::CStr;
33
use once_cell::sync::OnceCell;
44
use regex::Regex;
55

6+
#[cfg_attr(test, derive(Debug, PartialEq, Eq))]
67
pub struct Locale<'a> {
78
lang: Option<&'a str>,
89
country: Option<&'a str>,
910
modifier: Option<&'a str>,
1011
}
1112

13+
const LOCALE_REGEX: &str = r#"(?x)
14+
^
15+
([[:alpha:]]+) # lang
16+
(?:_([[:alpha:]]+))? # country
17+
(?:\.[^@]*)? # encoding
18+
(?:@(.*))? # modifier
19+
$"#;
20+
21+
impl<'a> Locale<'a> {
22+
fn from_caputres(s: &'a str, captures: regex::Captures<'_>) -> Self {
23+
Self {
24+
lang: captures.get(1).map(|m| &s[m.range()]),
25+
country: captures.get(2).map(|m| &s[m.range()]),
26+
modifier: captures.get(3).map(|m| &s[m.range()]),
27+
}
28+
}
29+
}
30+
1231
impl Locale<'static> {
1332
pub fn current<'a>() -> &'a Self {
1433
static LOCALE: OnceCell<Option<Locale<'static>>> = OnceCell::new();
@@ -24,24 +43,11 @@ impl Locale<'static> {
2443
.to_str()
2544
.ok()?;
2645

27-
let re = Regex::new(
28-
r#"(?x)
29-
^
30-
([[:alpha:]]+) # lang
31-
(?:_([[:alpha:]]+))? # country
32-
(?:\.[^@]*)? # encoding
33-
(?:@(.*))? # modifier
34-
$"#,
35-
)
36-
.unwrap();
46+
let re = Regex::new(LOCALE_REGEX).unwrap();
3747

3848
let c = re.captures(s)?;
3949

40-
Some(Self {
41-
lang: c.get(1).map(|m| &s[m.range()]),
42-
country: c.get(2).map(|m| &s[m.range()]),
43-
modifier: c.get(3).map(|m| &s[m.range()]),
44-
})
50+
Some(Self::from_caputres(s, c))
4551
})
4652
.as_ref()
4753
.unwrap_or(&Self {
@@ -75,3 +81,55 @@ impl Locale<'static> {
7581
.into_iter()
7682
}
7783
}
84+
85+
#[cfg(test)]
86+
mod tests {
87+
use super::*;
88+
89+
use test_case::test_case;
90+
91+
#[test]
92+
fn regex_compiles() {
93+
let _ = Regex::new(LOCALE_REGEX).unwrap();
94+
}
95+
96+
#[test]
97+
fn regex_doesnt_match_empty() {
98+
let re = Regex::new(LOCALE_REGEX).unwrap();
99+
assert!(re.captures("").is_none());
100+
}
101+
102+
impl Locale<'static> {
103+
fn new(
104+
lang: impl Into<Option<&'static str>>,
105+
country: impl Into<Option<&'static str>>,
106+
modifier: impl Into<Option<&'static str>>,
107+
) -> Self {
108+
Self {
109+
lang: lang.into(),
110+
country: country.into(),
111+
modifier: modifier.into(),
112+
}
113+
}
114+
}
115+
116+
#[test_case("qw", Locale::new("qw", None, None); "lang")]
117+
#[test_case("qw_ER", Locale::new("qw", "ER", None); "lang, country")]
118+
#[test_case("qw_ER.ty", Locale::new("qw", "ER", None); "lang, country, encoding")]
119+
#[test_case(
120+
"qw_ER.ty@ui",
121+
Locale::new("qw", "ER", "ui");
122+
"lang, country, encoding, modifier"
123+
)]
124+
#[test_case("qw@ui", Locale::new("qw", None, "ui"); "lang, modifier")]
125+
fn regex_compiles(s: &str, x: Locale<'static>) {
126+
let re = Regex::new(LOCALE_REGEX).unwrap();
127+
let c = re.captures(s).unwrap();
128+
129+
let m = c.get(0).unwrap();
130+
assert_eq!(m.start(), 0);
131+
assert_eq!(m.end(), s.len());
132+
133+
assert_eq!(Locale::from_caputres(s, c), x);
134+
}
135+
}

0 commit comments

Comments
 (0)