Browse Source

DateTimeFormat helpers (#2064)

This Pull Request adds several helpers to resolve #1562.

It adds the following subroutines:

- toDateTimeOptions
- GetOption
- GetNumberOption
- DefaultNumberOption
pull/2073/head
NorbertGarfield 3 years ago
parent
commit
5a0ff9116b
  1. 120
      boa_engine/src/builtins/intl/date_time_format.rs
  2. 114
      boa_engine/src/builtins/intl/mod.rs
  3. 362
      boa_engine/src/builtins/intl/tests.rs

120
boa_engine/src/builtins/intl/date_time_format.rs

@ -114,3 +114,123 @@ impl DateTimeFormat {
Ok(date_time_format.into())
}
}
/// Represents the `required` and `defaults` arguments in the abstract operation
/// `toDateTimeOptions`.
///
/// Since `required` and `defaults` differ only in the `any` and `all` variants,
/// we combine both in a single variant `AnyAll`.
#[allow(unused)]
#[derive(Debug, PartialEq)]
pub(crate) enum DateTimeReqs {
Date,
Time,
AnyAll,
}
/// The abstract operation `toDateTimeOptions` is called with arguments `options`, `required` and
/// `defaults`.
///
/// More information:
/// - [ECMAScript reference][spec]
///
/// [spec]: https://tc39.es/ecma402/#sec-todatetimeoptions
#[allow(unused)]
pub(crate) fn to_date_time_options(
options: &JsValue,
required: &DateTimeReqs,
defaults: &DateTimeReqs,
context: &mut Context,
) -> JsResult<JsObject> {
// 1. If options is undefined, let options be null;
// otherwise let options be ? ToObject(options).
// 2. Let options be ! OrdinaryObjectCreate(options).
let options = if options.is_undefined() {
None
} else {
Some(options.to_object(context)?)
};
let options = JsObject::from_proto_and_data(options, ObjectData::ordinary());
// 3. Let needDefaults be true.
let mut need_defaults = true;
// 4. If required is "date" or "any", then
if [DateTimeReqs::Date, DateTimeReqs::AnyAll].contains(required) {
// a. For each property name prop of « "weekday", "year", "month", "day" », do
for property in ["weekday", "year", "month", "day"] {
// i. Let value be ? Get(options, prop).
let value = options.get(property, context)?;
// ii. If value is not undefined, let needDefaults be false.
if !value.is_undefined() {
need_defaults = false;
}
}
}
// 5. If required is "time" or "any", then
if [DateTimeReqs::Time, DateTimeReqs::AnyAll].contains(required) {
// a. For each property name prop of « "dayPeriod", "hour", "minute", "second",
// "fractionalSecondDigits" », do
for property in [
"dayPeriod",
"hour",
"minute",
"second",
"fractionalSecondDigits",
] {
// i. Let value be ? Get(options, prop).
let value = options.get(property, context)?;
// ii. If value is not undefined, let needDefaults be false.
if !value.is_undefined() {
need_defaults = false;
}
}
}
// 6. Let dateStyle be ? Get(options, "dateStyle").
let date_style = options.get("dateStyle", context)?;
// 7. Let timeStyle be ? Get(options, "timeStyle").
let time_style = options.get("timeStyle", context)?;
// 8. If dateStyle is not undefined or timeStyle is not undefined, let needDefaults be false.
if !date_style.is_undefined() || !time_style.is_undefined() {
need_defaults = false;
}
// 9. If required is "date" and timeStyle is not undefined, then
if required == &DateTimeReqs::Date && !time_style.is_undefined() {
// a. Throw a TypeError exception.
return context.throw_type_error("'date' is required, but timeStyle was defined");
}
// 10. If required is "time" and dateStyle is not undefined, then
if required == &DateTimeReqs::Time && !date_style.is_undefined() {
// a. Throw a TypeError exception.
return context.throw_type_error("'time' is required, but dateStyle was defined");
}
// 11. If needDefaults is true and defaults is either "date" or "all", then
if need_defaults && [DateTimeReqs::Date, DateTimeReqs::AnyAll].contains(defaults) {
// a. For each property name prop of « "year", "month", "day" », do
for property in ["year", "month", "day"] {
// i. Perform ? CreateDataPropertyOrThrow(options, prop, "numeric").
options.create_data_property_or_throw(property, "numeric", context)?;
}
}
// 12. If needDefaults is true and defaults is either "time" or "all", then
if need_defaults && [DateTimeReqs::Time, DateTimeReqs::AnyAll].contains(defaults) {
// a. For each property name prop of « "hour", "minute", "second" », do
for property in ["hour", "minute", "second"] {
// i. Perform ? CreateDataPropertyOrThrow(options, prop, "numeric").
options.create_data_property_or_throw(property, "numeric", context)?;
}
}
// 13. Return options.
Ok(options)
}

114
boa_engine/src/builtins/intl/mod.rs

@ -10,7 +10,7 @@
use crate::{
builtins::intl::date_time_format::DateTimeFormat,
builtins::{Array, BuiltIn, JsArgs},
object::ObjectInitializer,
object::{JsObject, ObjectInitializer},
property::Attribute,
symbol::WellKnownSymbols,
Context, JsResult, JsString, JsValue,
@ -653,3 +653,115 @@ fn resolve_locale(
// 12. Return result.
result
}
#[allow(unused)]
pub(crate) enum GetOptionType {
String,
Boolean,
}
/// The abstract operation `GetOption` extracts the value of the property named `property` from the
/// provided `options` object, converts it to the required `type`, checks whether it is one of a
/// `List` of allowed `values`, and fills in a `fallback` value if necessary. If `values` is
/// undefined, there is no fixed set of values and any is permitted.
///
/// More information:
/// - [ECMAScript reference][spec]
///
/// [spec]: https://tc39.es/ecma402/#sec-getoption
#[allow(unused)]
pub(crate) fn get_option(
options: &JsObject,
property: &str,
r#type: &GetOptionType,
values: &[JsString],
fallback: &JsValue,
context: &mut Context,
) -> JsResult<JsValue> {
// 1. Assert: Type(options) is Object.
// 2. Let value be ? Get(options, property).
let mut value = options.get(property, context)?;
// 3. If value is undefined, return fallback.
if value.is_undefined() {
return Ok(fallback.clone());
}
// 4. Assert: type is "boolean" or "string".
// 5. If type is "boolean", then
// a. Set value to ! ToBoolean(value).
// 6. If type is "string", then
// a. Set value to ? ToString(value).
// 7. If values is not undefined and values does not contain an element equal to value,
// throw a RangeError exception.
value = match r#type {
GetOptionType::Boolean => JsValue::Boolean(value.to_boolean()),
GetOptionType::String => {
let string_value = value.to_string(context)?;
if !values.is_empty() && !values.contains(&string_value) {
return context.throw_range_error("GetOption: values array does not contain value");
}
JsValue::String(string_value)
}
};
// 8. Return value.
Ok(value)
}
/// The abstract operation `GetNumberOption` extracts the value of the property named `property`
/// from the provided `options` object, converts it to a `Number value`, checks whether it is in
/// the allowed range, and fills in a `fallback` value if necessary.
///
/// More information:
/// - [ECMAScript reference][spec]
///
/// [spec]: https://tc39.es/ecma402/#sec-getnumberoption
#[allow(unused)]
pub(crate) fn get_number_option(
options: &JsObject,
property: &str,
minimum: f64,
maximum: f64,
fallback: Option<f64>,
context: &mut Context,
) -> JsResult<Option<f64>> {
// 1. Assert: Type(options) is Object.
// 2. Let value be ? Get(options, property).
let value = options.get(property, context)?;
// 3. Return ? DefaultNumberOption(value, minimum, maximum, fallback).
default_number_option(&value, minimum, maximum, fallback, context)
}
/// The abstract operation `DefaultNumberOption` converts `value` to a `Number value`, checks
/// whether it is in the allowed range, and fills in a `fallback` value if necessary.
///
/// More information:
/// - [ECMAScript reference][spec]
///
/// [spec]: https://tc39.es/ecma402/#sec-defaultnumberoption
#[allow(unused)]
pub(crate) fn default_number_option(
value: &JsValue,
minimum: f64,
maximum: f64,
fallback: Option<f64>,
context: &mut Context,
) -> JsResult<Option<f64>> {
// 1. If value is undefined, return fallback.
if value.is_undefined() {
return Ok(fallback);
}
// 2. Set value to ? ToNumber(value).
let value = value.to_number(context)?;
// 3. If value is NaN or less than minimum or greater than maximum, throw a RangeError exception.
if value.is_nan() || value < minimum || value > maximum {
return context.throw_range_error("DefaultNumberOption: value is out of range.");
}
// 4. Return floor(value).
Ok(Some(value.floor()))
}

362
boa_engine/src/builtins/intl/tests.rs

@ -1,4 +1,13 @@
use crate::{Context, JsString};
use crate::{
builtins::intl::date_time_format::{to_date_time_options, DateTimeReqs},
builtins::intl::{
best_available_locale, best_fit_matcher, default_locale, default_number_option,
get_number_option, get_option, insert_unicode_extension_and_canonicalize, lookup_matcher,
resolve_locale, unicode_extension_components, DateTimeFormatRecord, GetOptionType,
},
object::JsObject,
Context, JsString, JsValue,
};
use rustc_hash::FxHashMap;
@ -7,14 +16,14 @@ fn best_avail_loc() {
let no_extensions_locale = JsString::new("en-US");
let available_locales = Vec::<JsString>::new();
assert_eq!(
crate::builtins::intl::best_available_locale(&available_locales, &no_extensions_locale,),
best_available_locale(&available_locales, &no_extensions_locale,),
None
);
let no_extensions_locale = JsString::new("de-DE");
let available_locales = vec![no_extensions_locale.clone()];
assert_eq!(
crate::builtins::intl::best_available_locale(&available_locales, &no_extensions_locale,),
best_available_locale(&available_locales, &no_extensions_locale,),
Some(no_extensions_locale)
);
@ -22,7 +31,7 @@ fn best_avail_loc() {
let no_extensions_locale = JsString::new(locale_part.clone() + &"-CA".to_string());
let available_locales = vec![JsString::new(locale_part.clone())];
assert_eq!(
crate::builtins::intl::best_available_locale(&available_locales, &no_extensions_locale,),
best_available_locale(&available_locales, &no_extensions_locale,),
Some(JsString::new(locale_part))
);
@ -31,7 +40,7 @@ fn best_avail_loc() {
let no_extensions_locale = JsString::new("ja-Kana-JP-t-it-latn-it");
let available_locales = vec![ja_kana_t.clone(), ja_kana.clone()];
assert_eq!(
crate::builtins::intl::best_available_locale(&available_locales, &no_extensions_locale,),
best_available_locale(&available_locales, &no_extensions_locale,),
Some(ja_kana)
);
}
@ -42,23 +51,23 @@ fn lookup_match() {
let available_locales = Vec::<JsString>::new();
let requested_locales = Vec::<JsString>::new();
let matcher = crate::builtins::intl::lookup_matcher(&available_locales, &requested_locales);
assert_eq!(matcher.locale, crate::builtins::intl::default_locale());
let matcher = lookup_matcher(&available_locales, &requested_locales);
assert_eq!(matcher.locale, default_locale());
assert_eq!(matcher.extension, "");
// available: [de-DE], requested: []
let available_locales = vec![JsString::new("de-DE")];
let requested_locales = Vec::<JsString>::new();
let matcher = crate::builtins::intl::lookup_matcher(&available_locales, &requested_locales);
assert_eq!(matcher.locale, crate::builtins::intl::default_locale());
let matcher = lookup_matcher(&available_locales, &requested_locales);
assert_eq!(matcher.locale, default_locale());
assert_eq!(matcher.extension, "");
// available: [fr-FR], requested: [fr-FR-u-hc-h12]
let available_locales = vec![JsString::new("fr-FR")];
let requested_locales = vec![JsString::new("fr-FR-u-hc-h12")];
let matcher = crate::builtins::intl::lookup_matcher(&available_locales, &requested_locales);
let matcher = lookup_matcher(&available_locales, &requested_locales);
assert_eq!(matcher.locale, "fr-FR");
assert_eq!(matcher.extension, "-u-hc-h12");
@ -66,7 +75,7 @@ fn lookup_match() {
let available_locales = vec![JsString::new("es-ES")];
let requested_locales = vec![JsString::new("es-ES")];
let matcher = crate::builtins::intl::best_fit_matcher(&available_locales, &requested_locales);
let matcher = best_fit_matcher(&available_locales, &requested_locales);
assert_eq!(matcher.locale, "es-ES");
assert_eq!(matcher.extension, "");
}
@ -76,21 +85,21 @@ fn insert_unicode_ext() {
let locale = JsString::new("hu-HU");
let ext = JsString::empty();
assert_eq!(
crate::builtins::intl::insert_unicode_extension_and_canonicalize(&locale, &ext),
insert_unicode_extension_and_canonicalize(&locale, &ext),
locale
);
let locale = JsString::new("hu-HU");
let ext = JsString::new("-u-hc-h12");
assert_eq!(
crate::builtins::intl::insert_unicode_extension_and_canonicalize(&locale, &ext),
insert_unicode_extension_and_canonicalize(&locale, &ext),
JsString::new("hu-HU-u-hc-h12")
);
let locale = JsString::new("hu-HU-x-PRIVATE");
let ext = JsString::new("-u-hc-h12");
assert_eq!(
crate::builtins::intl::insert_unicode_extension_and_canonicalize(&locale, &ext),
insert_unicode_extension_and_canonicalize(&locale, &ext),
JsString::new("hu-HU-u-hc-h12-x-PRIVATE")
);
}
@ -98,7 +107,7 @@ fn insert_unicode_ext() {
#[test]
fn uni_ext_comp() {
let ext = JsString::new("-u-ca-japanese-hc-h12");
let components = crate::builtins::intl::unicode_extension_components(&ext);
let components = unicode_extension_components(&ext);
assert_eq!(components.attributes.is_empty(), true);
assert_eq!(components.keywords.len(), 2);
assert_eq!(components.keywords[0].key, "ca");
@ -107,7 +116,7 @@ fn uni_ext_comp() {
assert_eq!(components.keywords[1].value, "h12");
let ext = JsString::new("-u-alias-co-phonebk-ka-shifted");
let components = crate::builtins::intl::unicode_extension_components(&ext);
let components = unicode_extension_components(&ext);
assert_eq!(components.attributes, vec![JsString::new("alias")]);
assert_eq!(components.keywords.len(), 2);
assert_eq!(components.keywords[0].key, "co");
@ -116,7 +125,7 @@ fn uni_ext_comp() {
assert_eq!(components.keywords[1].value, "shifted");
let ext = JsString::new("-u-ca-buddhist-kk-nu-thai");
let components = crate::builtins::intl::unicode_extension_components(&ext);
let components = unicode_extension_components(&ext);
assert_eq!(components.attributes.is_empty(), true);
assert_eq!(components.keywords.len(), 3);
assert_eq!(components.keywords[0].key, "ca");
@ -127,7 +136,7 @@ fn uni_ext_comp() {
assert_eq!(components.keywords[2].value, "thai");
let ext = JsString::new("-u-ca-islamic-civil");
let components = crate::builtins::intl::unicode_extension_components(&ext);
let components = unicode_extension_components(&ext);
assert_eq!(components.attributes.is_empty(), true);
assert_eq!(components.keywords.len(), 1);
assert_eq!(components.keywords[0].key, "ca");
@ -143,12 +152,12 @@ fn locale_resolution() {
let requested_locales = Vec::<JsString>::new();
let relevant_extension_keys = Vec::<JsString>::new();
let locale_data = FxHashMap::default();
let options = crate::builtins::intl::DateTimeFormatRecord {
let options = DateTimeFormatRecord {
locale_matcher: JsString::new("lookup"),
properties: FxHashMap::default(),
};
let locale_record = crate::builtins::intl::resolve_locale(
let locale_record = resolve_locale(
&available_locales,
&requested_locales,
&options,
@ -156,14 +165,8 @@ fn locale_resolution() {
&locale_data,
&mut context,
);
assert_eq!(
locale_record.locale,
crate::builtins::intl::default_locale()
);
assert_eq!(
locale_record.data_locale,
crate::builtins::intl::default_locale()
);
assert_eq!(locale_record.locale, default_locale());
assert_eq!(locale_record.data_locale, default_locale());
assert_eq!(locale_record.properties.is_empty(), true);
// test best fit
@ -171,12 +174,12 @@ fn locale_resolution() {
let requested_locales = Vec::<JsString>::new();
let relevant_extension_keys = Vec::<JsString>::new();
let locale_data = FxHashMap::default();
let options = crate::builtins::intl::DateTimeFormatRecord {
let options = DateTimeFormatRecord {
locale_matcher: JsString::new("best-fit"),
properties: FxHashMap::default(),
};
let locale_record = crate::builtins::intl::resolve_locale(
let locale_record = resolve_locale(
&available_locales,
&requested_locales,
&options,
@ -184,14 +187,8 @@ fn locale_resolution() {
&locale_data,
&mut context,
);
assert_eq!(
locale_record.locale,
crate::builtins::intl::default_locale()
);
assert_eq!(
locale_record.data_locale,
crate::builtins::intl::default_locale()
);
assert_eq!(locale_record.locale, default_locale());
assert_eq!(locale_record.data_locale, default_locale());
assert_eq!(locale_record.properties.is_empty(), true);
// available: [es-ES], requested: [es-ES]
@ -199,12 +196,12 @@ fn locale_resolution() {
let requested_locales = vec![JsString::new("es-ES")];
let relevant_extension_keys = Vec::<JsString>::new();
let locale_data = FxHashMap::default();
let options = crate::builtins::intl::DateTimeFormatRecord {
let options = DateTimeFormatRecord {
locale_matcher: JsString::new("lookup"),
properties: FxHashMap::default(),
};
let locale_record = crate::builtins::intl::resolve_locale(
let locale_record = resolve_locale(
&available_locales,
&requested_locales,
&options,
@ -221,12 +218,12 @@ fn locale_resolution() {
let requested_locales = Vec::<JsString>::new();
let relevant_extension_keys = Vec::<JsString>::new();
let locale_data = FxHashMap::default();
let options = crate::builtins::intl::DateTimeFormatRecord {
let options = DateTimeFormatRecord {
locale_matcher: JsString::new("lookup"),
properties: FxHashMap::default(),
};
let locale_record = crate::builtins::intl::resolve_locale(
let locale_record = resolve_locale(
&available_locales,
&requested_locales,
&options,
@ -234,13 +231,284 @@ fn locale_resolution() {
&locale_data,
&mut context,
);
assert_eq!(locale_record.locale, default_locale());
assert_eq!(locale_record.data_locale, default_locale());
assert_eq!(locale_record.properties.is_empty(), true);
}
#[test]
fn get_opt() {
let mut context = Context::default();
let values = Vec::<JsString>::new();
let fallback = JsValue::String(JsString::new("fallback"));
let options_obj = JsObject::empty();
let option_type = GetOptionType::String;
let get_option_result = get_option(
&options_obj,
"",
&option_type,
&values,
&fallback,
&mut context,
)
.expect("GetOption should not fail on fallback test");
assert_eq!(get_option_result, fallback);
let values = Vec::<JsString>::new();
let fallback = JsValue::String(JsString::new("fallback"));
let options_obj = JsObject::empty();
let locale_value = JsValue::String(JsString::new("en-US"));
options_obj
.set("Locale", locale_value.clone(), true, &mut context)
.expect("Setting a property should not fail");
let option_type = GetOptionType::String;
let get_option_result = get_option(
&options_obj,
"Locale",
&option_type,
&values,
&fallback,
&mut context,
)
.expect("GetOption should not fail on string test");
assert_eq!(get_option_result, locale_value);
let fallback = JsValue::String(JsString::new("fallback"));
let options_obj = JsObject::empty();
let locale_string = JsString::new("en-US");
let locale_value = JsValue::String(locale_string.clone());
let values = vec![locale_string];
options_obj
.set("Locale", locale_value.clone(), true, &mut context)
.expect("Setting a property should not fail");
let option_type = GetOptionType::String;
let get_option_result = get_option(
&options_obj,
"Locale",
&option_type,
&values,
&fallback,
&mut context,
)
.expect("GetOption should not fail on values test");
assert_eq!(get_option_result, locale_value);
let fallback = JsValue::new(false);
let options_obj = JsObject::empty();
let boolean_value = JsValue::new(true);
let values = Vec::<JsString>::new();
options_obj
.set("boolean_val", boolean_value.clone(), true, &mut context)
.expect("Setting a property should not fail");
let option_type = GetOptionType::Boolean;
let get_option_result = get_option(
&options_obj,
"boolean_val",
&option_type,
&values,
&fallback,
&mut context,
)
.expect("GetOption should not fail on boolean test");
assert_eq!(get_option_result, boolean_value);
let fallback = JsValue::String(JsString::new("fallback"));
let options_obj = JsObject::empty();
let locale_value = JsValue::String(JsString::new("en-US"));
let other_locale_str = JsString::new("de-DE");
let values = vec![other_locale_str];
options_obj
.set("Locale", locale_value.clone(), true, &mut context)
.expect("Setting a property should not fail");
let option_type = GetOptionType::String;
let get_option_result = get_option(
&options_obj,
"Locale",
&option_type,
&values,
&fallback,
&mut context,
);
assert_eq!(get_option_result.is_err(), true);
let value = JsValue::undefined();
let minimum = 1.0;
let maximum = 10.0;
let fallback_val = 5.0;
let fallback = Some(fallback_val);
let get_option_result = default_number_option(&value, minimum, maximum, fallback, &mut context);
assert_eq!(get_option_result, Ok(fallback));
let value = JsValue::nan();
let minimum = 1.0;
let maximum = 10.0;
let fallback = Some(5.0);
let get_option_result = default_number_option(&value, minimum, maximum, fallback, &mut context);
assert_eq!(get_option_result.is_err(), true);
let value = JsValue::new(0);
let minimum = 1.0;
let maximum = 10.0;
let fallback = Some(5.0);
let get_option_result = default_number_option(&value, minimum, maximum, fallback, &mut context);
assert_eq!(get_option_result.is_err(), true);
let value = JsValue::new(11);
let minimum = 1.0;
let maximum = 10.0;
let fallback = Some(5.0);
let get_option_result = default_number_option(&value, minimum, maximum, fallback, &mut context);
assert_eq!(get_option_result.is_err(), true);
let value_f64 = 7.0;
let value = JsValue::new(value_f64);
let minimum = 1.0;
let maximum = 10.0;
let fallback = Some(5.0);
let get_option_result = default_number_option(&value, minimum, maximum, fallback, &mut context);
assert_eq!(get_option_result, Ok(Some(value_f64)));
let options = JsObject::empty();
let property = "fractionalSecondDigits";
let minimum = 1.0;
let maximum = 10.0;
let fallback_val = 5.0;
let fallback = Some(fallback_val);
let get_option_result = get_number_option(
&options,
&property,
minimum,
maximum,
fallback,
&mut context,
);
assert_eq!(get_option_result, Ok(fallback));
let options = JsObject::empty();
let value_f64 = 8.0;
let value = JsValue::new(value_f64);
let property = "fractionalSecondDigits";
options
.set(property, value.clone(), true, &mut context)
.expect("Setting a property should not fail");
let minimum = 1.0;
let maximum = 10.0;
let fallback = Some(5.0);
let get_option_result = get_number_option(
&options,
&property,
minimum,
maximum,
fallback,
&mut context,
);
assert_eq!(get_option_result, Ok(Some(value_f64)));
}
#[test]
fn to_date_time_opts() {
let mut context = Context::default();
let options_obj = JsObject::empty();
options_obj
.set("timeStyle", JsObject::empty(), true, &mut context)
.expect("Setting a property should not fail");
let date_time_opts = to_date_time_options(
&JsValue::new(options_obj),
&DateTimeReqs::Date,
&DateTimeReqs::Date,
&mut context,
);
assert_eq!(date_time_opts.is_err(), true);
let options_obj = JsObject::empty();
options_obj
.set("dateStyle", JsObject::empty(), true, &mut context)
.expect("Setting a property should not fail");
let date_time_opts = to_date_time_options(
&JsValue::new(options_obj),
&DateTimeReqs::Time,
&DateTimeReqs::Time,
&mut context,
);
assert_eq!(date_time_opts.is_err(), true);
let date_time_opts = to_date_time_options(
&JsValue::undefined(),
&DateTimeReqs::Date,
&DateTimeReqs::Date,
&mut context,
)
.expect("toDateTimeOptions should not fail in date test");
let numeric_jsstring = JsValue::String(JsString::new("numeric"));
assert_eq!(
locale_record.locale,
crate::builtins::intl::default_locale()
date_time_opts.get("year", &mut context),
Ok(numeric_jsstring.clone())
);
assert_eq!(
locale_record.data_locale,
crate::builtins::intl::default_locale()
date_time_opts.get("month", &mut context),
Ok(numeric_jsstring.clone())
);
assert_eq!(
date_time_opts.get("day", &mut context),
Ok(numeric_jsstring.clone())
);
let date_time_opts = to_date_time_options(
&JsValue::undefined(),
&DateTimeReqs::Time,
&DateTimeReqs::Time,
&mut context,
)
.expect("toDateTimeOptions should not fail in time test");
let numeric_jsstring = JsValue::String(JsString::new("numeric"));
assert_eq!(
date_time_opts.get("hour", &mut context),
Ok(numeric_jsstring.clone())
);
assert_eq!(
date_time_opts.get("minute", &mut context),
Ok(numeric_jsstring.clone())
);
assert_eq!(
date_time_opts.get("second", &mut context),
Ok(numeric_jsstring.clone())
);
let date_time_opts = to_date_time_options(
&JsValue::undefined(),
&DateTimeReqs::AnyAll,
&DateTimeReqs::AnyAll,
&mut context,
)
.expect("toDateTimeOptions should not fail when testing required = 'any'");
let numeric_jsstring = JsValue::String(JsString::new("numeric"));
assert_eq!(
date_time_opts.get("year", &mut context),
Ok(numeric_jsstring.clone())
);
assert_eq!(
date_time_opts.get("month", &mut context),
Ok(numeric_jsstring.clone())
);
assert_eq!(
date_time_opts.get("day", &mut context),
Ok(numeric_jsstring.clone())
);
assert_eq!(
date_time_opts.get("hour", &mut context),
Ok(numeric_jsstring.clone())
);
assert_eq!(
date_time_opts.get("minute", &mut context),
Ok(numeric_jsstring.clone())
);
assert_eq!(
date_time_opts.get("second", &mut context),
Ok(numeric_jsstring.clone())
);
assert_eq!(locale_record.properties.is_empty(), true);
}

Loading…
Cancel
Save