1use {
16 anyhow::anyhow,
17 rust_icu_common as common,
18 rust_icu_common::buffered_string_method_with_retry,
19 rust_icu_sys as sys,
20 rust_icu_sys::versioned_function,
21 rust_icu_sys::*,
22 rust_icu_uenum::Enumeration,
23 rust_icu_ustring as ustring,
24 rust_icu_ustring::buffered_uchar_method_with_retry,
25 std::{
26 cmp::Ordering,
27 collections::HashMap,
28 convert::{From, TryFrom, TryInto},
29 ffi, fmt,
30 os::raw,
31 },
32};
33
34const LOCALE_CAPACITY: usize = 158;
37
38#[derive(Debug, Clone)]
48pub struct ULocMut {
49 base: ULoc,
50 unicode_keyvalues: HashMap<String, String>,
51 other_keyvalues: HashMap<String, String>,
52}
53
54impl From<ULoc> for ULocMut {
55 fn from(l: ULoc) -> Self {
57 let all_keywords = l.keywords();
58 let mut unicode_keyvalues: HashMap<String, String> = HashMap::new();
59 let mut other_keyvalues: HashMap<String, String> = HashMap::new();
60 for kw in all_keywords {
61 let ukw = to_unicode_locale_key(&kw);
64 match ukw {
65 None => {
66 let v = l.keyword_value(&kw).unwrap().unwrap();
67 other_keyvalues.insert(kw, v);
68 }
69 Some(u) => {
70 let v = l.unicode_keyword_value(&u).unwrap().unwrap();
71 unicode_keyvalues.insert(u, v);
72 }
73 }
74 }
75 let locmut = ULocMut {
77 base: l.base_name(),
78 unicode_keyvalues,
79 other_keyvalues,
80 };
81 locmut
82 }
83}
84
85impl From<ULocMut> for ULoc {
86 fn from(lm: ULocMut) -> Self {
88 let mut unicode_extensions_vec = lm
90 .unicode_keyvalues
91 .iter()
92 .map(|(k, v)| format!("{}-{}", k, v))
93 .collect::<Vec<String>>();
94 unicode_extensions_vec.sort();
95 let unicode_extensions: String = unicode_extensions_vec
96 .join("-");
97 let unicode_extension: String = if unicode_extensions.len() > 0 {
98 vec!["u-".to_string(), unicode_extensions]
99 .into_iter()
100 .collect()
101 } else {
102 "".to_string()
103 };
104 let mut all_extensions: Vec<String> = lm
106 .other_keyvalues
107 .iter()
108 .map(|(k, v)| format!("{}-{}", k, v))
109 .collect();
110 if unicode_extension.len() > 0 {
111 all_extensions.push(unicode_extension);
112 }
113 let base_tag = lm.base.to_language_tag(true)
116 .expect("should be known-good");
117 let mut everything_vec: Vec<String> = vec![base_tag];
118 if !all_extensions.is_empty() {
119 all_extensions.sort();
120 let extension_string = all_extensions.join("-");
121 everything_vec.push(extension_string);
122 }
123 let everything = everything_vec.join("-").to_lowercase();
124 ULoc::for_language_tag(&everything).unwrap()
125 }
126}
127
128impl ULocMut {
129 pub fn set_unicode_keyvalue(&mut self, key: &str, value: &str) -> Option<String> {
132 if let None = to_unicode_locale_key(key) {
133 return None;
134 }
135 self.unicode_keyvalues
136 .insert(key.to_string(), value.to_string())
137 }
138
139 pub fn remove_unicode_keyvalue(&mut self, key: &str) -> Option<String> {
143 if let None = to_unicode_locale_key(key) {
144 return None;
145 }
146 self.unicode_keyvalues.remove(key)
147 }
148}
149
150#[derive(Debug, Clone, Eq, PartialEq, Hash)]
157pub struct ULoc {
158 repr: String,
160}
161
162impl fmt::Display for ULoc {
166 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
167 write!(f, "{}", self.repr)
168 }
169}
170
171impl TryFrom<&str> for ULoc {
172 type Error = common::Error;
173 fn try_from(s: &str) -> Result<Self, Self::Error> {
177 let s = String::from(s);
178 ULoc { repr: s }.canonicalize()
179 }
180}
181
182impl TryFrom<&ffi::CStr> for ULoc {
183 type Error = common::Error;
184
185 fn try_from(s: &ffi::CStr) -> Result<Self, Self::Error> {
187 let repr = s.to_str()?;
188 ULoc {
189 repr: String::from(repr),
190 }
191 .canonicalize()
192 }
193}
194
195impl ULoc {
196 pub fn language(&self) -> Option<String> {
198 self.call_buffered_string_method_to_option(versioned_function!(uloc_getLanguage))
199 }
200
201 pub fn script(&self) -> Option<String> {
203 self.call_buffered_string_method_to_option(versioned_function!(uloc_getScript))
204 }
205
206 pub fn country(&self) -> Option<String> {
208 self.call_buffered_string_method_to_option(versioned_function!(uloc_getCountry))
209 }
210
211 pub fn variant(&self) -> Option<String> {
213 self.call_buffered_string_method_to_option(versioned_function!(uloc_getVariant))
214 }
215
216 pub fn name(&self) -> Option<String> {
218 self.call_buffered_string_method_to_option(versioned_function!(uloc_getName))
219 }
220
221 pub fn canonicalize(&self) -> Result<ULoc, common::Error> {
223 self.call_buffered_string_method(versioned_function!(uloc_canonicalize))
224 .map(|repr| ULoc { repr })
225 }
226
227 pub fn iso3_language(&self) -> Option<String> {
229 let lang = unsafe {
230 ffi::CStr::from_ptr(
231 versioned_function!(uloc_getISO3Language)(self.as_c_str().as_ptr())
232 ).to_str()
233 };
234 let value = lang.unwrap();
235 if value.is_empty() {
236 None
237 } else {
238 Some(value.to_string())
239 }
240 }
241
242 pub fn iso3_country(&self) -> Option<String> {
244 let country = unsafe {
245 ffi::CStr::from_ptr(
246 versioned_function!(uloc_getISO3Country)(self.as_c_str().as_ptr())
247 ).to_str()
248 };
249 let value = country.unwrap();
250 if value.is_empty() {
251 None
252 } else {
253 Some(value.to_string())
254 }
255 }
256
257 pub fn display_language(&self, display_locale: &ULoc) -> Result<ustring::UChar, common::Error> {
259 buffered_uchar_method_with_retry!(
260 display_language_impl,
261 LOCALE_CAPACITY,
262 [locale: *const raw::c_char, display_locale: *const raw::c_char,],
263 []
264 );
265 display_language_impl(
266 versioned_function!(uloc_getDisplayLanguage),
267 self.as_c_str().as_ptr(),
268 display_locale.as_c_str().as_ptr(),
269 )
270 }
271
272 pub fn display_script(&self, display_locale: &ULoc) -> Result<ustring::UChar, common::Error> {
274 buffered_uchar_method_with_retry!(
275 display_script_impl,
276 LOCALE_CAPACITY,
277 [locale: *const raw::c_char, display_locale: *const raw::c_char,],
278 []
279 );
280 display_script_impl(
281 versioned_function!(uloc_getDisplayScript),
282 self.as_c_str().as_ptr(),
283 display_locale.as_c_str().as_ptr(),
284 )
285 }
286
287 pub fn display_country(&self, display_locale: &ULoc) -> Result<ustring::UChar, common::Error> {
289 buffered_uchar_method_with_retry!(
290 display_country_impl,
291 LOCALE_CAPACITY,
292 [locale: *const raw::c_char, display_locale: *const raw::c_char,],
293 []
294 );
295 display_country_impl(
296 versioned_function!(uloc_getDisplayCountry),
297 self.as_c_str().as_ptr(),
298 display_locale.as_c_str().as_ptr(),
299 )
300 }
301
302 pub fn display_variant(&self, display_locale: &ULoc) -> Result<ustring::UChar, common::Error> {
304 buffered_uchar_method_with_retry!(
305 display_variant_impl,
306 LOCALE_CAPACITY,
307 [locale: *const raw::c_char, display_locale: *const raw::c_char,],
308 []
309 );
310 display_variant_impl(
311 versioned_function!(uloc_getDisplayCountry),
312 self.as_c_str().as_ptr(),
313 display_locale.as_c_str().as_ptr(),
314 )
315 }
316
317 pub fn display_keyword(keyword: &String, display_locale: &ULoc) -> Result<ustring::UChar, common::Error> {
319 buffered_uchar_method_with_retry!(
320 display_keyword_impl,
321 LOCALE_CAPACITY,
322 [keyword: *const raw::c_char, display_locale: *const raw::c_char,],
323 []
324 );
325 let keyword = ffi::CString::new(keyword.as_str()).unwrap();
326 display_keyword_impl(
327 versioned_function!(uloc_getDisplayKeyword),
328 keyword.as_ptr(),
329 display_locale.as_c_str().as_ptr(),
330 )
331 }
332
333 pub fn display_keyword_value(&self, keyword: &String, display_locale: &ULoc) -> Result<ustring::UChar, common::Error> {
335 buffered_uchar_method_with_retry!(
336 display_keyword_value_impl,
337 LOCALE_CAPACITY,
338 [keyword: *const raw::c_char, value: *const raw::c_char, display_locale: *const raw::c_char,],
339 []
340 );
341 let keyword = ffi::CString::new(keyword.as_str()).unwrap();
342 display_keyword_value_impl(
343 versioned_function!(uloc_getDisplayKeywordValue),
344 self.as_c_str().as_ptr(),
345 keyword.as_ptr(),
346 display_locale.as_c_str().as_ptr(),
347 )
348 }
349
350 pub fn display_name(&self, display_locale: &ULoc) -> Result<ustring::UChar, common::Error> {
352 buffered_uchar_method_with_retry!(
353 display_name_impl,
354 LOCALE_CAPACITY,
355 [locale: *const raw::c_char, display_locale: *const raw::c_char,],
356 []
357 );
358 display_name_impl(
359 versioned_function!(uloc_getDisplayName),
360 self.as_c_str().as_ptr(),
361 display_locale.as_c_str().as_ptr(),
362 )
363 }
364
365 pub fn count_available() -> i32 {
367 let count = unsafe { versioned_function!(uloc_countAvailable)() };
368 count
369 }
370
371 pub fn get_available(n: i32) -> Result<ULoc, common::Error> {
373 if (0 > n) || (n >= Self::count_available()) {
374 panic!("{} is negative or greater than or equal to the value returned from count_available()", n);
375 }
376 let ptr = unsafe { versioned_function!(uloc_getAvailable)(n) };
377 if ptr == std::ptr::null() {
378 return Err(common::Error::Wrapper(anyhow!("uloc_getAvailable() returned a null pointer")));
379 }
380 let label = unsafe { ffi::CStr::from_ptr(ptr).to_str().unwrap() };
381 ULoc::try_from(label)
382 }
383
384 pub fn get_available_locales() -> Vec<ULoc> {
386 let count = ULoc::count_available();
387 let mut vec = Vec::with_capacity(count as usize);
388 let mut index: i32 = 0;
389 while index < count {
390 let locale = Self::get_available(index).unwrap();
391 vec.push(locale);
392 index += 1;
393 }
394 vec
395 }
396
397 #[cfg(feature = "icu_version_67_plus")]
399 pub fn open_available_by_type(locale_type: ULocAvailableType) -> Result<Enumeration, common::Error> {
400 let mut status = common::Error::OK_CODE;
401 unsafe {
402 let iter = Enumeration::from_raw_parts(None, versioned_function!(uloc_openAvailableByType)(locale_type, &mut status));
403 common::Error::ok_or_warning(status)?;
404 Ok(iter)
405 }
406 }
407
408 #[cfg(feature = "icu_version_67_plus")]
410 pub fn get_available_locales_by_type(locale_type: ULocAvailableType) -> Vec<ULoc> {
411 if locale_type == ULocAvailableType::ULOC_AVAILABLE_COUNT {
412 panic!("ULOC_AVAILABLE_COUNT is for internal use only");
413 }
414 Self::open_available_by_type(locale_type).unwrap().map(|x| ULoc::try_from(x.unwrap().as_str()).unwrap()).collect()
415 }
416
417 pub fn add_likely_subtags(&self) -> Result<ULoc, common::Error> {
419 self.call_buffered_string_method(versioned_function!(uloc_addLikelySubtags))
420 .map(|repr| ULoc { repr })
421 }
422
423 pub fn minimize_subtags(&self) -> Result<ULoc, common::Error> {
425 self.call_buffered_string_method(versioned_function!(uloc_minimizeSubtags))
426 .map(|repr| ULoc { repr })
427 }
428
429 pub fn to_language_tag(&self, strict: bool) -> Result<String, common::Error> {
431 let locale_id = self.as_c_str();
432 let strict = if strict { 1 } else { 0 };
434 buffered_string_method_with_retry(
435 |buf, len, error| unsafe {
436 versioned_function!(uloc_toLanguageTag)(
437 locale_id.as_ptr(),
438 buf,
439 len,
440 strict,
441 error,
442 )
443 },
444 LOCALE_CAPACITY,
445 )
446 }
447
448 pub fn open_keywords(&self) -> Result<Enumeration, common::Error> {
449 let mut status = common::Error::OK_CODE;
450 let asciiz_locale = self.as_c_str();
451 let raw_enum = unsafe {
452 assert!(common::Error::is_ok(status));
453 versioned_function!(uloc_openKeywords)(asciiz_locale.as_ptr(), &mut status)
454 };
455 common::Error::ok_or_warning(status)?;
456 if raw_enum.is_null() {
458 Ok(Enumeration::empty())
459 } else {
460 Ok(unsafe { Enumeration::from_raw_parts(None, raw_enum) })
461 }
462 }
463
464 pub fn keywords(&self) -> impl Iterator<Item = String> {
466 self.open_keywords()
467 .unwrap()
468 .map(|result| result.unwrap())
469 }
470
471 pub fn unicode_keywords(&self) -> impl Iterator<Item = String> {
473 self.keywords().filter_map(|s| to_unicode_locale_key(&s))
474 }
475
476 pub fn keyword_value(&self, keyword: &str) -> Result<Option<String>, common::Error> {
478 let locale_id = self.as_c_str();
479 let keyword_name = str_to_cstring(keyword);
480 buffered_string_method_with_retry(
481 |buf, len, error| unsafe {
482 versioned_function!(uloc_getKeywordValue)(
483 locale_id.as_ptr(),
484 keyword_name.as_ptr(),
485 buf,
486 len,
487 error,
488 )
489 },
490 LOCALE_CAPACITY,
491 )
492 .map(|value| if value.is_empty() { None } else { Some(value) })
493 }
494
495 pub fn unicode_keyword_value(
497 &self,
498 unicode_keyword: &str,
499 ) -> Result<Option<String>, common::Error> {
500 let legacy_keyword = to_legacy_key(unicode_keyword);
501 match legacy_keyword {
502 Some(legacy_keyword) => match self.keyword_value(&legacy_keyword) {
503 Ok(Some(legacy_value)) => {
504 Ok(to_unicode_locale_type(&legacy_keyword, &legacy_value))
505 }
506 Ok(None) => Ok(None),
507 Err(e) => Err(e),
508 },
509 None => Ok(None),
510 }
511 }
512
513 pub fn label(&self) -> &str {
515 &self.repr
516 }
517
518 pub fn as_c_str(&self) -> ffi::CString {
520 ffi::CString::new(self.repr.clone()).expect("ULoc contained interior NUL bytes")
521 }
522
523 pub fn for_language_tag(tag: &str) -> Result<ULoc, common::Error> {
528 let tag = str_to_cstring(tag);
529 let locale_id = buffered_string_method_with_retry(
530 |buf, len, error| unsafe {
531 versioned_function!(uloc_forLanguageTag)(
532 tag.as_ptr(),
533 buf,
534 len,
535 std::ptr::null_mut(),
536 error
537 )
538 },
539 LOCALE_CAPACITY,
540 )?;
541 ULoc::try_from(&locale_id[..])
542 }
543
544 fn call_buffered_string_method(
546 &self,
547 uloc_method: unsafe extern "C" fn(
548 *const raw::c_char,
549 *mut raw::c_char,
550 i32,
551 *mut UErrorCode,
552 ) -> i32,
553 ) -> Result<String, common::Error> {
554 let asciiz = self.as_c_str();
555 buffered_string_method_with_retry(
556 |buf, len, error| unsafe { uloc_method(asciiz.as_ptr(), buf, len, error) },
557 LOCALE_CAPACITY,
558 )
559 }
560
561 fn call_buffered_string_method_to_option(
564 &self,
565 uloc_method: unsafe extern "C" fn(
566 *const raw::c_char,
567 *mut raw::c_char,
568 i32,
569 *mut UErrorCode,
570 ) -> i32,
571 ) -> Option<String> {
572 let value: String = self.call_buffered_string_method(uloc_method).unwrap();
573 if value.is_empty() {
574 None
575 } else {
576 Some(value)
577 }
578 }
579
580 pub fn base_name(self) -> Self {
582 let result = self
583 .call_buffered_string_method(versioned_function!(uloc_getBaseName))
584 .expect("should be able to produce a shorter locale");
585 ULoc::try_from(&result[..]).expect("should be able to convert to locale")
586 }
587}
588
589impl Ord for ULoc {
593 fn cmp(&self, other: &Self) -> Ordering {
594 fn compare_keywords(
597 this: &ULoc,
598 self_keyword: &Option<String>,
599 other: &ULoc,
600 other_keyword: &Option<String>,
601 ) -> Option<Ordering> {
602 match (self_keyword, other_keyword) {
603 (Some(self_keyword), Some(other_keyword)) => {
604 match self_keyword.cmp(&other_keyword) {
606 Ordering::Equal => {
607 let self_val = this.keyword_value(&self_keyword[..]).unwrap();
609 let other_val = other.keyword_value(&other_keyword[..]).unwrap();
610 Some(self_val.cmp(&other_val))
611 }
612 unequal_ordering => Some(unequal_ordering),
613 }
614 }
615 (Some(_), _) => Some(Ordering::Greater),
617 (_, Some(_)) => Some(Ordering::Less),
619 (_, _) => None,
621 }
622 }
623
624 self.language()
625 .cmp(&other.language())
626 .then_with(|| self.script().cmp(&other.script()))
627 .then_with(|| self.country().cmp(&other.country()))
628 .then_with(|| self.variant().cmp(&other.variant()))
629 .then_with(|| {
630 let mut self_keywords = self.keywords();
631 let mut other_keywords = other.keywords();
632
633 while let Some(keyword_ordering) =
634 compare_keywords(self, &self_keywords.next(), other, &other_keywords.next())
635 {
636 match keyword_ordering {
637 Ordering::Equal => {}
638 unequal_ordering => {
639 return unequal_ordering;
640 }
641 }
642 }
643
644 Ordering::Equal
646 })
647 }
648}
649
650impl PartialOrd for ULoc {
651 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
652 Some(self.cmp(other))
653 }
654}
655
656pub fn get_default() -> ULoc {
660 let loc = unsafe { versioned_function!(uloc_getDefault)() };
661 let uloc_cstr = unsafe { ffi::CStr::from_ptr(loc) };
662 crate::ULoc::try_from(uloc_cstr).expect("could not convert default locale to ULoc")
663}
664
665pub fn set_default(loc: &ULoc) -> Result<(), common::Error> {
669 let mut status = common::Error::OK_CODE;
670 let asciiz = str_to_cstring(&loc.repr);
671 unsafe { versioned_function!(uloc_setDefault)(asciiz.as_ptr(), &mut status) };
672 common::Error::ok_or_warning(status)
673}
674
675pub fn accept_language(
677 accept_list: impl IntoIterator<Item = impl Into<ULoc>>,
678 available_locales: impl IntoIterator<Item = impl Into<ULoc>>,
679) -> Result<(Option<ULoc>, UAcceptResult), common::Error> {
680 let mut accept_result: UAcceptResult = UAcceptResult::ULOC_ACCEPT_FAILED;
681 let mut accept_list_cstrings: Vec<ffi::CString> = vec![];
682 let mut accept_list: Vec<*const raw::c_char> = accept_list
684 .into_iter()
685 .map(|item| {
686 let uloc: ULoc = item.into();
687 accept_list_cstrings.push(uloc.as_c_str());
688 accept_list_cstrings
689 .last()
690 .expect("non-empty list")
691 .as_ptr()
692 })
693 .collect();
694
695 let available_locales: Vec<ULoc> = available_locales
696 .into_iter()
697 .map(|item| item.into())
698 .collect();
699 let available_locales: Vec<&str> = available_locales.iter().map(|uloc| uloc.label()).collect();
700 let mut available_locales = Enumeration::try_from(&available_locales[..])?;
701
702 let matched_locale = buffered_string_method_with_retry(
703 |buf, len, error| unsafe {
704 versioned_function!(uloc_acceptLanguage)(
705 buf,
706 len,
707 &mut accept_result,
708 accept_list.as_mut_ptr(),
709 accept_list.len() as i32,
710 available_locales.repr(),
711 error,
712 )
713 },
714 LOCALE_CAPACITY,
715 );
716
717 if accept_result == UAcceptResult::ULOC_ACCEPT_FAILED {
719 return Ok((None, accept_result));
720 }
721
722 matched_locale
723 .and_then(|s| ULoc::try_from(s.as_str()))
724 .map(|uloc| (Some(uloc), accept_result))
725}
726
727pub fn to_unicode_locale_key(legacy_keyword: &str) -> Option<String> {
729 let legacy_keyword = str_to_cstring(legacy_keyword);
730 let unicode_keyword: Option<ffi::CString> = unsafe {
731 let ptr = versioned_function!(uloc_toUnicodeLocaleKey)(legacy_keyword.as_ptr());
732 ptr.as_ref().map(|ptr| ffi::CStr::from_ptr(ptr).to_owned())
733 };
734 unicode_keyword.map(|cstring| cstring_to_string(&cstring))
735}
736
737pub fn to_unicode_locale_type(legacy_keyword: &str, legacy_value: &str) -> Option<String> {
739 let legacy_keyword = str_to_cstring(legacy_keyword);
740 let legacy_value = str_to_cstring(legacy_value);
741 let unicode_value: Option<ffi::CString> = unsafe {
742 let ptr = versioned_function!(uloc_toUnicodeLocaleType)(
743 legacy_keyword.as_ptr(),
744 legacy_value.as_ptr(),
745 );
746 ptr.as_ref().map(|ptr| ffi::CStr::from_ptr(ptr).to_owned())
747 };
748 unicode_value.map(|cstring| cstring_to_string(&cstring))
749}
750
751pub fn to_legacy_key(unicode_keyword: &str) -> Option<String> {
753 let unicode_keyword = str_to_cstring(unicode_keyword);
754 let legacy_keyword: Option<ffi::CString> = unsafe {
755 let ptr = versioned_function!(uloc_toLegacyKey)(unicode_keyword.as_ptr());
756 ptr.as_ref().map(|ptr| ffi::CStr::from_ptr(ptr).to_owned())
757 };
758 legacy_keyword.map(|cstring| cstring_to_string(&cstring))
759}
760
761fn str_to_cstring(input: &str) -> ffi::CString {
764 ffi::CString::new(input)
765 .unwrap_or_else(|e| ffi::CString::new(&input[0..e.nul_position()]).unwrap())
766}
767
768fn cstring_to_string(input: &ffi::CString) -> String {
771 input.to_string_lossy().to_string()
772}
773
774#[cfg(test)]
775mod tests {
776 use {super::*, anyhow::Error};
777
778 #[test]
779 fn test_language() -> Result<(), Error> {
780 let loc = ULoc::try_from("es-CO")?;
781 assert_eq!(loc.language(), Some("es".to_string()));
782 Ok(())
783 }
784
785 #[test]
786 fn test_language_absent() -> Result<(), Error> {
787 let loc = ULoc::for_language_tag("und-CO")?;
788 assert_eq!(loc.language(), None);
789 Ok(())
790 }
791
792 #[test]
794 fn test_long_language_tag() -> Result<(), Error> {
795 let mut language_tag: String = "und-CO".to_owned();
796 let language_tag_rest = (0..500).map(|_| " ").collect::<String>();
797 language_tag.push_str(&language_tag_rest);
798 let _loc = ULoc::for_language_tag(&language_tag)?;
799 Ok(())
800 }
801
802 #[test]
803 fn test_script() -> Result<(), Error> {
804 let loc = ULoc::try_from("sr-Cyrl")?;
805 assert_eq!(loc.script(), Some("Cyrl".to_string()));
806 Ok(())
807 }
808
809 #[test]
810 fn test_script_absent() -> Result<(), Error> {
811 let loc = ULoc::try_from("sr")?;
812 assert_eq!(loc.script(), None);
813 Ok(())
814 }
815
816 #[test]
817 fn test_country() -> Result<(), Error> {
818 let loc = ULoc::try_from("es-CO")?;
819 assert_eq!(loc.country(), Some("CO".to_string()));
820 Ok(())
821 }
822
823 #[test]
824 fn test_country_absent() -> Result<(), Error> {
825 let loc = ULoc::try_from("es")?;
826 assert_eq!(loc.country(), None);
827 Ok(())
828 }
829
830 #[cfg(feature = "icu_version_64_plus")]
833 #[test]
834 fn test_variant() -> Result<(), Error> {
835 let loc = ULoc::try_from("zh-Latn-pinyin")?;
836 assert_eq!(
837 loc.variant(),
838 Some("PINYIN".to_string()),
839 "locale was: {:?}",
840 loc
841 );
842 Ok(())
843 }
844
845 #[test]
846 fn test_variant_absent() -> Result<(), Error> {
847 let loc = ULoc::try_from("zh-Latn")?;
848 assert_eq!(loc.variant(), None);
849 Ok(())
850 }
851
852 #[cfg(feature = "icu_version_64_plus")]
853 #[test]
854 fn test_name() -> Result<(), Error> {
855 let loc = ULoc::try_from("en-US")?;
856 match loc.name() {
857 None => assert!(false),
858 Some(name) => assert_eq!(name, "en_US"),
859 }
860 let loc = ULoc::try_from("und")?;
861 assert_eq!(loc.name(), None);
862 let loc = ULoc::try_from("")?;
863 assert_eq!(loc.name(), None);
864 Ok(())
865 }
866
867 #[test]
868 fn test_default_locale() {
869 let loc = ULoc::try_from("fr-fr").expect("get fr_FR locale");
870 set_default(&loc).expect("successful set of locale");
871 assert_eq!(get_default().label(), loc.label());
872 assert_eq!(loc.label(), "fr_FR", "The locale should get canonicalized");
873 let loc = ULoc::try_from("en-us").expect("get en_US locale");
874 set_default(&loc).expect("successful set of locale");
875 assert_eq!(get_default().label(), loc.label());
876 }
877
878 #[test]
879 fn test_add_likely_subtags() {
880 let loc = ULoc::try_from("en-US").expect("get en_US locale");
881 let with_likely_subtags = loc.add_likely_subtags().expect("should add likely subtags");
882 let expected = ULoc::try_from("en_Latn_US").expect("get en_Latn_US locale");
883 assert_eq!(with_likely_subtags.label(), expected.label());
884 }
885
886 #[test]
887 fn test_minimize_subtags() {
888 let loc = ULoc::try_from("sr_Cyrl_RS").expect("get sr_Cyrl_RS locale");
889 let minimized_subtags = loc.minimize_subtags().expect("should minimize subtags");
890 let expected = ULoc::try_from("sr").expect("get sr locale");
891 assert_eq!(minimized_subtags.label(), expected.label());
892 }
893
894 #[test]
895 fn test_to_language_tag() {
896 let loc = ULoc::try_from("sr_Cyrl_RS").expect("get sr_Cyrl_RS locale");
897 let language_tag = loc
898 .to_language_tag(true)
899 .expect("should convert to language tag");
900 assert_eq!(language_tag, "sr-Cyrl-RS".to_string());
901 }
902
903 #[test]
904 fn test_keywords() -> Result<(), Error> {
905 let loc = ULoc::for_language_tag("az-Cyrl-AZ-u-ca-hebrew-fw-sunday-nu-deva-tz-usnyc")?;
906 let keywords: Vec<String> = loc.keywords().collect();
907 assert_eq!(
908 keywords,
909 vec![
910 "calendar".to_string(),
911 "fw".to_string(),
912 "numbers".to_string(),
913 "timezone".to_string()
914 ]
915 );
916 Ok(())
917 }
918
919 #[test]
920 fn test_keywords_nounicode() -> Result<(), Error> {
921 let loc = ULoc::for_language_tag("az-Cyrl-AZ-u-ca-hebrew-t-it-x-whatever")?;
922 let keywords: Vec<String> = loc.keywords().collect();
923 assert_eq!(
924 keywords,
925 vec!["calendar".to_string(), "t".to_string(), "x".to_string(),]
926 );
927 assert_eq!(loc.keyword_value("t")?.unwrap(), "it");
928 assert_eq!(loc.keyword_value("x")?.unwrap(), "whatever");
929 Ok(())
930 }
931
932 #[test]
933 fn test_keywords_empty() -> Result<(), Error> {
934 let loc = ULoc::for_language_tag("az-Cyrl-AZ")?;
935 let keywords: Vec<String> = loc.keywords().collect();
936 assert!(keywords.is_empty());
937 Ok(())
938 }
939
940 #[test]
941 fn test_unicode_keywords() -> Result<(), Error> {
942 let loc = ULoc::for_language_tag("az-Cyrl-AZ-u-ca-hebrew-fw-sunday-nu-deva-tz-usnyc")?;
943 let keywords: Vec<String> = loc.unicode_keywords().collect();
944 assert_eq!(
945 keywords,
946 vec![
947 "ca".to_string(),
948 "fw".to_string(),
949 "nu".to_string(),
950 "tz".to_string()
951 ]
952 );
953 Ok(())
954 }
955
956 #[test]
957 fn test_unicode_keywords_empty() -> Result<(), Error> {
958 let loc = ULoc::for_language_tag("az-Cyrl-AZ")?;
959 let keywords: Vec<String> = loc.unicode_keywords().collect();
960 assert!(keywords.is_empty());
961 Ok(())
962 }
963
964 #[test]
965 fn test_keyword_value() -> Result<(), Error> {
966 let loc = ULoc::for_language_tag("az-Cyrl-AZ-u-ca-hebrew-fw-sunday-nu-deva-tz-usnyc")?;
967 assert_eq!(loc.keyword_value("calendar")?, Some("hebrew".to_string()));
968 assert_eq!(loc.keyword_value("collation")?, None);
969 Ok(())
970 }
971
972 #[test]
973 fn test_unicode_keyword_value() -> Result<(), Error> {
974 let loc = ULoc::for_language_tag("az-Cyrl-AZ-u-ca-hebrew-fw-sunday-nu-deva-tz-usnyc")?;
975 assert_eq!(loc.unicode_keyword_value("ca")?, Some("hebrew".to_string()));
976 assert_eq!(loc.unicode_keyword_value("fw")?, Some("sunday".to_string()));
977 assert_eq!(loc.unicode_keyword_value("co")?, None);
978 Ok(())
979 }
980
981 #[test]
982 fn test_order() -> Result<(), Error> {
983 assert!(ULoc::for_language_tag("az")? < ULoc::for_language_tag("az-Cyrl")?);
984 assert!(ULoc::for_language_tag("az-Cyrl")? < ULoc::for_language_tag("az-Cyrl-AZ")?);
985 assert!(
986 ULoc::for_language_tag("az-Cyrl-AZ")? < ULoc::for_language_tag("az-Cyrl-AZ-variant")?
987 );
988 assert!(
989 ULoc::for_language_tag("az-Cyrl-AZ-variant")?
990 < ULoc::for_language_tag("az-Cyrl-AZ-variant-u-nu-arab")?
991 );
992 assert!(
993 ULoc::for_language_tag("az-u-ca-gregory")? < ULoc::for_language_tag("az-u-fw-fri")?
994 );
995 assert!(
996 ULoc::for_language_tag("az-u-ca-buddhist")?
997 < ULoc::for_language_tag("az-u-ca-chinese")?
998 );
999 assert!(ULoc::for_language_tag("az-u-fw-mon")? < ULoc::for_language_tag("az-u-fw-tue")?);
1000 assert!(
1001 ULoc::for_language_tag("az-u-fw-mon")? < ULoc::for_language_tag("az-u-fw-mon-nu-arab")?
1002 );
1003 assert!(
1004 ULoc::for_language_tag("az-u-fw-mon-nu-arab")? > ULoc::for_language_tag("az-u-fw-mon")?
1005 );
1006
1007 let loc = ULoc::for_language_tag("az-Cyrl-AZ-variant-u-nu-arab")?;
1008 assert_eq!(loc.cmp(&loc), Ordering::Equal,);
1009 Ok(())
1010 }
1011
1012 #[test]
1013 fn test_accept_language_fallback() {
1014 let accept_list: Result<Vec<_>, _> = vec!["es_MX", "ar_EG", "fr_FR"]
1015 .into_iter()
1016 .map(ULoc::try_from)
1017 .collect();
1018 let accept_list = accept_list.expect("make accept_list");
1019
1020 let available_locales: Result<Vec<_>, _> =
1021 vec!["de_DE", "en_US", "es", "nl_NL", "sr_RS_Cyrl"]
1022 .into_iter()
1023 .map(ULoc::try_from)
1024 .collect();
1025 let available_locales = available_locales.expect("make available_locales");
1026
1027 let actual = accept_language(accept_list, available_locales).expect("call accept_language");
1028 assert_eq!(
1029 actual,
1030 (
1031 ULoc::try_from("es").ok(),
1032 UAcceptResult::ULOC_ACCEPT_FALLBACK
1033 )
1034 );
1035 }
1036
1037 #[cfg(not(feature = "icu_version_67_plus"))]
1039 #[test]
1040 fn test_accept_language_exact_match() {
1041 let accept_list: Result<Vec<_>, _> = vec!["es_ES", "ar_EG", "fr_FR"]
1042 .into_iter()
1043 .map(ULoc::try_from)
1044 .collect();
1045 let accept_list = accept_list.expect("make accept_list");
1046
1047 let available_locales: Result<Vec<_>, _> = vec!["de_DE", "en_US", "es_MX", "ar_EG"]
1048 .into_iter()
1049 .map(ULoc::try_from)
1050 .collect();
1051 let available_locales = available_locales.expect("make available_locales");
1052
1053 let actual = accept_language(accept_list, available_locales).expect("call accept_language");
1054 assert_eq!(
1055 actual,
1056 (
1057 ULoc::try_from("ar_EG").ok(),
1059 UAcceptResult::ULOC_ACCEPT_VALID
1060 )
1061 );
1062 }
1063
1064 #[cfg(feature = "icu_version_67_plus")]
1065 #[test]
1066 fn test_accept_language_exact_match() {
1067 let accept_list: Result<Vec<_>, _> = vec!["es_ES", "ar_EG", "fr_FR"]
1068 .into_iter()
1069 .map(ULoc::try_from)
1070 .collect();
1071 let accept_list = accept_list.expect("make accept_list");
1072
1073 let available_locales: Result<Vec<_>, _> = vec!["de_DE", "en_US", "es_MX", "ar_EG"]
1074 .into_iter()
1075 .map(ULoc::try_from)
1076 .collect();
1077 let available_locales = available_locales.expect("make available_locales");
1078
1079 let actual = accept_language(accept_list, available_locales).expect("call accept_language");
1080 assert_eq!(
1081 actual,
1082 (
1083 ULoc::try_from("es_MX").ok(),
1084 UAcceptResult::ULOC_ACCEPT_FALLBACK,
1085 )
1086 );
1087 }
1088
1089 #[test]
1090 fn test_accept_language_no_match() {
1091 let accept_list: Result<Vec<_>, _> = vec!["es_ES", "ar_EG", "fr_FR"]
1092 .into_iter()
1093 .map(ULoc::try_from)
1094 .collect();
1095 let accept_list = accept_list.expect("make accept_list");
1096
1097 let available_locales: Result<Vec<_>, _> =
1098 vec!["el_GR"].into_iter().map(ULoc::try_from).collect();
1099 let available_locales = available_locales.expect("make available_locales");
1100
1101 let actual = accept_language(accept_list, available_locales).expect("call accept_language");
1102 assert_eq!(actual, (None, UAcceptResult::ULOC_ACCEPT_FAILED))
1103 }
1104
1105 #[test]
1106 fn test_to_unicode_locale_key() -> Result<(), Error> {
1107 let actual = to_unicode_locale_key("calendar");
1108 assert_eq!(actual, Some("ca".to_string()));
1109 Ok(())
1110 }
1111
1112 #[test]
1113 fn test_to_unicode_locale_type() -> Result<(), Error> {
1114 let actual = to_unicode_locale_type("co", "phonebook");
1115 assert_eq!(actual, Some("phonebk".to_string()));
1116 Ok(())
1117 }
1118
1119 #[test]
1120 fn test_to_legacy_key() -> Result<(), Error> {
1121 let actual = to_legacy_key("ca");
1122 assert_eq!(actual, Some("calendar".to_string()));
1123 Ok(())
1124 }
1125
1126 #[test]
1127 fn test_str_to_cstring() -> Result<(), Error> {
1128 assert_eq!(str_to_cstring("abc"), ffi::CString::new("abc")?);
1129 assert_eq!(str_to_cstring("abc\0def"), ffi::CString::new("abc")?);
1130
1131 Ok(())
1132 }
1133
1134 #[test]
1135 fn test_base_name() -> Result<(), Error> {
1136 assert_eq!(
1137 ULoc::try_from("en-u-tz-uslax-x-foo")?.base_name(),
1138 ULoc::try_from("en")?
1139 );
1140 Ok(())
1141 }
1142
1143 #[test]
1144 fn test_uloc_mut() -> Result<(), Error> {
1145 let loc = ULoc::for_language_tag("en-t-it-u-tz-uslax-x-foo")?;
1146 let loc_mut = ULocMut::from(loc);
1147 let loc = ULoc::from(loc_mut);
1148 assert_eq!(ULoc::for_language_tag("en-t-it-u-tz-uslax-x-foo")?, loc);
1149 Ok(())
1150 }
1151
1152 #[test]
1153 fn test_uloc_mut_changes() -> Result<(), Error> {
1154 let loc = ULoc::for_language_tag("en-t-it-u-tz-uslax-x-foo")?;
1155 let mut loc_mut = ULocMut::from(loc);
1156 loc_mut.remove_unicode_keyvalue("tz");
1157 let loc = ULoc::from(loc_mut);
1158 assert_eq!(ULoc::for_language_tag("en-t-it-x-foo")?, loc);
1159
1160 let loc = ULoc::for_language_tag("en-u-tz-uslax")?;
1161 let mut loc_mut = ULocMut::from(loc);
1162 loc_mut.remove_unicode_keyvalue("tz");
1163 let loc = ULoc::from(loc_mut);
1164 assert_eq!(ULoc::for_language_tag("en")?, loc);
1165 Ok(())
1166 }
1167
1168 #[test]
1169 fn test_uloc_mut_overrides() -> Result<(), Error> {
1170 let loc = ULoc::for_language_tag("en-t-it-u-tz-uslax-x-foo")?;
1171 let mut loc_mut = ULocMut::from(loc);
1172 loc_mut.set_unicode_keyvalue("tz", "usnyc");
1173 let loc = ULoc::from(loc_mut);
1174 assert_eq!(ULoc::for_language_tag("en-t-it-u-tz-usnyc-x-foo")?, loc);
1175
1176 let loc = ULoc::for_language_tag("en-t-it-u-tz-uslax-x-foo")?;
1177 let mut loc_mut = ULocMut::from(loc);
1178 loc_mut.set_unicode_keyvalue("tz", "usnyc");
1179 loc_mut.set_unicode_keyvalue("nu", "arabic");
1180 let loc = ULoc::from(loc_mut);
1181 assert_eq!(ULoc::for_language_tag("en-t-it-u-nu-arabic-tz-usnyc-x-foo")?, loc);
1182 assert_eq!(ULoc::for_language_tag("en-t-it-u-tz-usnyc-nu-arabic-x-foo")?, loc);
1183 Ok(())
1184 }
1185
1186 #[test]
1187 fn test_uloc_mut_add_unicode_extension() -> Result<(), Error> {
1188 let loc = ULoc::for_language_tag("en-t-it-x-foo")?;
1189 let mut loc_mut = ULocMut::from(loc);
1190 loc_mut.set_unicode_keyvalue("tz", "usnyc");
1191 let loc = ULoc::from(loc_mut);
1192 assert_eq!(ULoc::for_language_tag("en-t-it-u-tz-usnyc-x-foo")?, loc);
1193 Ok(())
1194 }
1195
1196 #[test]
1197 fn test_round_trip_from_uloc_plain() -> Result<(), Error> {
1198 let loc = ULoc::for_language_tag("sr")?;
1199 let loc = ULocMut::from(loc);
1200 let loc = ULoc::from(loc);
1201 assert_eq!(ULoc::try_from("sr")?, loc);
1202 Ok(())
1203 }
1204
1205 #[test]
1206 fn test_round_trip_from_uloc_with_country() -> Result<(), Error> {
1207 let loc = ULoc::for_language_tag("sr-rs")?;
1208 let loc = ULoc::from(ULocMut::from(loc));
1209 assert_eq!(ULoc::try_from("sr-rs")?, loc);
1210 Ok(())
1211 }
1212
1213 #[test]
1214 fn test_equivalence() {
1215 let loc = ULoc::try_from("sr@timezone=America/Los_Angeles").unwrap();
1216 assert_eq!(ULoc::for_language_tag("sr-u-tz-uslax").unwrap(), loc);
1217 }
1218
1219 #[cfg(feature = "icu_version_64_plus")]
1220 #[test]
1221 fn test_for_language_error() {
1222 let loc = ULoc::for_language_tag("en_US").unwrap();
1223 assert_eq!(loc.language(), None);
1224 assert_eq!(loc.country(), None);
1225 }
1226
1227 #[cfg(feature = "icu_version_64_plus")]
1228 #[test]
1229 fn test_iso3_language() {
1230 let loc = ULoc::for_language_tag("en-US").unwrap();
1231 let iso_lang = loc.iso3_language();
1232 assert_eq!(iso_lang, Some("eng".to_string()));
1233 let loc = ULoc::for_language_tag("und").unwrap();
1234 let iso_lang = loc.iso3_language();
1235 assert_eq!(iso_lang, None);
1236 }
1237
1238 #[cfg(feature = "icu_version_64_plus")]
1239 #[test]
1240 fn test_iso3_country() {
1241 let loc = ULoc::for_language_tag("en-US").unwrap();
1242 let iso_country = loc.iso3_country();
1243 assert_eq!(iso_country, Some("USA".to_string()));
1244 let loc = ULoc::for_language_tag("und").unwrap();
1245 let iso_country = loc.iso3_country();
1246 assert_eq!(iso_country, None);
1247 }
1248
1249 #[cfg(feature = "icu_version_64_plus")]
1250 #[test]
1251 fn test_display_language() {
1252 let english_locale = ULoc::for_language_tag("en").unwrap();
1253 let french_locale = ULoc::for_language_tag("fr").unwrap();
1254 let english_in_french = english_locale.display_language(&french_locale);
1255 assert!(english_in_french.is_ok());
1256 assert_eq!(english_in_french.unwrap().as_string_debug(), "anglais");
1257 let root_locale = ULoc::for_language_tag("und").unwrap();
1258 assert_eq!(root_locale.display_language(&french_locale).unwrap().as_string_debug(), "langue indéterminée");
1259 let root_locale = ULoc::for_language_tag("en_US").unwrap();
1260 assert_eq!(root_locale.display_language(&french_locale).unwrap().as_string_debug(), "langue indéterminée");
1261 }
1262
1263 #[cfg(feature = "icu_version_64_plus")]
1264 #[test]
1265 fn test_display_script() {
1266 let english_latin_locale = ULoc::for_language_tag("en-latg").unwrap();
1267 let french_locale = ULoc::for_language_tag("fr").unwrap();
1268 let latin_script_in_french = english_latin_locale.display_script(&french_locale);
1269 assert!(latin_script_in_french.is_ok());
1270 assert_eq!(latin_script_in_french.unwrap().as_string_debug(), "latin (variante gaélique)");
1271 let english_locale = ULoc::for_language_tag("en").unwrap();
1272 assert_eq!(english_locale.display_script(&french_locale).unwrap().as_string_debug(), "");
1273 }
1274
1275 #[test]
1276 fn test_display_country() {
1277 let usa_locale = ULoc::for_language_tag("en-US").unwrap();
1278 let french_locale = ULoc::for_language_tag("fr").unwrap();
1279 let usa_in_french = usa_locale.display_country(&french_locale);
1280 assert!(usa_in_french.is_ok());
1281 assert_eq!(usa_in_french.unwrap().as_string_debug(), "États-Unis");
1282 let english_locale = ULoc::for_language_tag("en").unwrap();
1283 assert_eq!(english_locale.display_script(&french_locale).unwrap().as_string_debug(), "");
1284 }
1285
1286 #[test]
1287 fn test_display_keyword() {
1288 let french_locale = ULoc::for_language_tag("fr").unwrap();
1289 let currency_in_french = ULoc::display_keyword(&"currency".to_string(), &french_locale);
1290 assert!(currency_in_french.is_ok());
1291 assert_eq!(currency_in_french.unwrap().as_string_debug(), "devise");
1292 }
1293
1294 #[test]
1295 fn test_display_keyword_value() {
1296 let locale_w_calendar = ULoc::for_language_tag("az-Cyrl-AZ-u-ca-hebrew-t-it-x-whatever").unwrap();
1297 let french_locale = ULoc::for_language_tag("fr").unwrap();
1298 let calendar_value_in_french = locale_w_calendar.display_keyword_value(
1299 &"calendar".to_string(), &french_locale);
1300 assert!(calendar_value_in_french.is_ok());
1301 assert_eq!(calendar_value_in_french.unwrap().as_string_debug(), "calendrier hébraïque");
1302 }
1303
1304 #[cfg(feature = "icu_version_64_plus")]
1305 #[test]
1306 fn test_display_name() {
1307 let loc = ULoc::for_language_tag("az-Cyrl-AZ-u-ca-hebrew-t-it-x-whatever").unwrap();
1308 let french_locale = ULoc::for_language_tag("fr").unwrap();
1309 let display_name_in_french = loc.display_name(&french_locale);
1310 assert!(display_name_in_french.is_ok());
1311 assert_eq!(
1312 display_name_in_french.unwrap().as_string_debug(),
1313 "azerbaïdjanais (cyrillique, Azerbaïdjan, calendrier=calendrier hébraïque, t=it, usage privé=whatever)"
1314 );
1315 }
1316
1317 #[test]
1318 #[should_panic(expected = "-1 is negative or greater than or equal to the value returned from count_available()")]
1319 fn test_get_available_negative() {
1320 let _ = ULoc::get_available(-1);
1321 }
1322
1323 #[test]
1324 fn test_get_available_overrun() {
1325 let index = ULoc::count_available();
1326 let result = std::panic::catch_unwind(|| ULoc::get_available(index));
1327 assert!(result.is_err());
1328 }
1329
1330 #[test]
1331 fn test_get_available_locales() {
1332 let locales = ULoc::get_available_locales();
1333 assert!(locales.contains(&ULoc::try_from("en").unwrap()));
1334 assert!(locales.contains(&ULoc::try_from("en-US").unwrap()));
1335 assert!(locales.contains(&ULoc::try_from("fr").unwrap()));
1336 assert!(locales.contains(&ULoc::try_from("fr-FR").unwrap()));
1337 assert_eq!(ULoc::count_available() as usize, locales.capacity());
1338 assert_eq!(locales.len(), locales.capacity());
1339 }
1340
1341 #[cfg(feature = "icu_version_67_plus")]
1342 #[test]
1343 fn test_get_available_locales_by_type() {
1344 let locales1 = ULoc::get_available_locales_by_type(ULocAvailableType::ULOC_AVAILABLE_DEFAULT);
1345 let locales2 = ULoc::get_available_locales();
1346 assert_eq!(locales1, locales2);
1347 let alias_locales = ULoc::get_available_locales_by_type(ULocAvailableType::ULOC_AVAILABLE_ONLY_LEGACY_ALIASES);
1348 let all_locales = ULoc::get_available_locales_by_type(ULocAvailableType::ULOC_AVAILABLE_WITH_LEGACY_ALIASES);
1349 for locale in &alias_locales {
1350 assert!(all_locales.contains(&locale));
1351 assert!(!locales1.contains(&locale));
1352 }
1353 for locale in &locales1 {
1354 assert!(all_locales.contains(&locale));
1355 assert!(!alias_locales.contains(&locale));
1356 }
1357 assert!(alias_locales.len() > 0);
1358 assert!(locales1.len() > alias_locales.len());
1359 assert!(all_locales.len() > locales1.len());
1360 assert!(alias_locales.contains(&ULoc::try_from("iw").unwrap()));
1361 assert!(alias_locales.contains(&ULoc::try_from("mo").unwrap()));
1362 assert!(alias_locales.contains(&ULoc::try_from("zh-CN").unwrap()));
1363 assert!(alias_locales.contains(&ULoc::try_from("sr-BA").unwrap()));
1364 assert!(alias_locales.contains(&ULoc::try_from("ars").unwrap()));
1365 }
1366
1367 #[cfg(feature = "icu_version_67_plus")]
1368 #[test]
1369 #[should_panic(expected = "ULOC_AVAILABLE_COUNT is for internal use only")]
1370 fn test_get_available_locales_by_type_panic() {
1371 ULoc::get_available_locales_by_type(ULocAvailableType::ULOC_AVAILABLE_COUNT);
1372 }
1373
1374 #[cfg(feature = "icu_version_67_plus")]
1375 #[test]
1376 fn test_get_available_locales_by_type_error() {
1377 assert!(!ULoc::open_available_by_type(ULocAvailableType::ULOC_AVAILABLE_COUNT).is_ok());
1378 }
1379}