mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 05:57:44 +00:00
LibJS: Implement Temporal.Duration.from()
...with ParseTemporalDurationString currently TODO()'d.
This commit is contained in:
parent
7355c23e17
commit
5c77885873
9 changed files with 236 additions and 0 deletions
|
@ -199,6 +199,7 @@ namespace Temporal {
|
||||||
class PrototypeName;
|
class PrototypeName;
|
||||||
JS_ENUMERATE_TEMPORAL_OBJECTS
|
JS_ENUMERATE_TEMPORAL_OBJECTS
|
||||||
#undef __JS_ENUMERATE
|
#undef __JS_ENUMERATE
|
||||||
|
struct TemporalDuration;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
|
|
|
@ -169,6 +169,7 @@
|
||||||
M(TemporalInvalidCalendarIdentifier, "Invalid calendar identifier '{}'") \
|
M(TemporalInvalidCalendarIdentifier, "Invalid calendar identifier '{}'") \
|
||||||
M(TemporalInvalidDuration, "Invalid duration") \
|
M(TemporalInvalidDuration, "Invalid duration") \
|
||||||
M(TemporalInvalidDurationLikeObject, "Invalid duration-like object") \
|
M(TemporalInvalidDurationLikeObject, "Invalid duration-like object") \
|
||||||
|
M(TemporalInvalidDurationPropertyValue, "Invalid value for duration property '{}': must be an integer, got {}") \
|
||||||
M(TemporalInvalidEpochNanoseconds, "Invalid epoch nanoseconds value, must be in range -86400 * 10^17 to 86400 * 10^17") \
|
M(TemporalInvalidEpochNanoseconds, "Invalid epoch nanoseconds value, must be in range -86400 * 10^17 to 86400 * 10^17") \
|
||||||
M(TemporalInvalidISODate, "Invalid ISO date") \
|
M(TemporalInvalidISODate, "Invalid ISO date") \
|
||||||
M(TemporalInvalidTime, "Invalid time") \
|
M(TemporalInvalidTime, "Invalid time") \
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org>
|
* Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org>
|
||||||
|
* Copyright (c) 2021, Linus Groh <linusg@serenityos.org>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
@ -7,6 +8,7 @@
|
||||||
#include <AK/CharacterTypes.h>
|
#include <AK/CharacterTypes.h>
|
||||||
#include <AK/DateTimeLexer.h>
|
#include <AK/DateTimeLexer.h>
|
||||||
#include <LibJS/Runtime/Temporal/AbstractOperations.h>
|
#include <LibJS/Runtime/Temporal/AbstractOperations.h>
|
||||||
|
#include <LibJS/Runtime/Temporal/Duration.h>
|
||||||
#include <LibJS/Runtime/Temporal/PlainDate.h>
|
#include <LibJS/Runtime/Temporal/PlainDate.h>
|
||||||
#include <LibJS/Runtime/Temporal/PlainTime.h>
|
#include <LibJS/Runtime/Temporal/PlainTime.h>
|
||||||
#include <LibJS/Runtime/Temporal/TimeZone.h>
|
#include <LibJS/Runtime/Temporal/TimeZone.h>
|
||||||
|
@ -301,6 +303,7 @@ Optional<ISODateTime> parse_iso_date_time(GlobalObject& global_object, [[maybe_u
|
||||||
Optional<StringView> fraction_part;
|
Optional<StringView> fraction_part;
|
||||||
Optional<StringView> calendar_part;
|
Optional<StringView> calendar_part;
|
||||||
TODO();
|
TODO();
|
||||||
|
|
||||||
// 3. Let year be the part of isoString produced by the DateYear production.
|
// 3. Let year be the part of isoString produced by the DateYear production.
|
||||||
// 4. If the first code unit of year is 0x2212 (MINUS SIGN), replace it with the code unit 0x002D (HYPHEN-MINUS).
|
// 4. If the first code unit of year is 0x2212 (MINUS SIGN), replace it with the code unit 0x002D (HYPHEN-MINUS).
|
||||||
String normalized_year;
|
String normalized_year;
|
||||||
|
@ -420,10 +423,19 @@ Optional<TemporalInstant> parse_temporal_instant_string(GlobalObject& global_obj
|
||||||
return TemporalInstant { .year = result->year, .month = result->month, .day = result->day, .hour = result->hour, .minute = result->minute, .second = result->second, .millisecond = result->millisecond, .microsecond = result->microsecond, .nanosecond = result->nanosecond, .time_zone_offset = move(time_zone_result->offset) };
|
return TemporalInstant { .year = result->year, .month = result->month, .day = result->day, .hour = result->hour, .minute = result->minute, .second = result->second, .millisecond = result->millisecond, .microsecond = result->microsecond, .nanosecond = result->nanosecond, .time_zone_offset = move(time_zone_result->offset) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 13.40 ParseTemporalDurationString ( isoString ), https://tc39.es/proposal-temporal/#sec-temporal-parsetemporaldurationstring
|
||||||
|
Optional<TemporalDuration> parse_temporal_duration_string(GlobalObject& global_object, String const& iso_string)
|
||||||
|
{
|
||||||
|
(void)global_object;
|
||||||
|
(void)iso_string;
|
||||||
|
TODO();
|
||||||
|
}
|
||||||
|
|
||||||
// 13.43 ParseTemporalTimeZoneString ( isoString ), https://tc39.es/proposal-temporal/#sec-temporal-parsetemporaltimezonestring
|
// 13.43 ParseTemporalTimeZoneString ( isoString ), https://tc39.es/proposal-temporal/#sec-temporal-parsetemporaltimezonestring
|
||||||
Optional<TemporalTimeZone> parse_temporal_time_zone_string(GlobalObject& global_object, [[maybe_unused]] String const& iso_string)
|
Optional<TemporalTimeZone> parse_temporal_time_zone_string(GlobalObject& global_object, [[maybe_unused]] String const& iso_string)
|
||||||
{
|
{
|
||||||
auto& vm = global_object.vm();
|
auto& vm = global_object.vm();
|
||||||
|
|
||||||
// 1. Assert: Type(isoString) is String.
|
// 1. Assert: Type(isoString) is String.
|
||||||
|
|
||||||
// 2. If isoString does not satisfy the syntax of a TemporalTimeZoneString (see 13.33), then
|
// 2. If isoString does not satisfy the syntax of a TemporalTimeZoneString (see 13.33), then
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org>
|
* Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org>
|
||||||
|
* Copyright (c) 2021, Linus Groh <linusg@serenityos.org>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
@ -8,6 +9,7 @@
|
||||||
|
|
||||||
#include <AK/Forward.h>
|
#include <AK/Forward.h>
|
||||||
#include <AK/String.h>
|
#include <AK/String.h>
|
||||||
|
#include <LibJS/Forward.h>
|
||||||
#include <LibJS/Runtime/GlobalObject.h>
|
#include <LibJS/Runtime/GlobalObject.h>
|
||||||
|
|
||||||
namespace JS::Temporal {
|
namespace JS::Temporal {
|
||||||
|
@ -58,6 +60,7 @@ Optional<String> to_smallest_temporal_unit(GlobalObject&, Object& normalized_opt
|
||||||
BigInt* round_number_to_increment(GlobalObject&, BigInt const&, u64 increment, String const& rounding_mode);
|
BigInt* round_number_to_increment(GlobalObject&, BigInt const&, u64 increment, String const& rounding_mode);
|
||||||
Optional<ISODateTime> parse_iso_date_time(GlobalObject&, String const& iso_string);
|
Optional<ISODateTime> parse_iso_date_time(GlobalObject&, String const& iso_string);
|
||||||
Optional<TemporalInstant> parse_temporal_instant_string(GlobalObject&, String const& iso_string);
|
Optional<TemporalInstant> parse_temporal_instant_string(GlobalObject&, String const& iso_string);
|
||||||
|
Optional<TemporalDuration> parse_temporal_duration_string(GlobalObject&, String const& iso_string);
|
||||||
Optional<TemporalTimeZone> parse_temporal_time_zone_string(GlobalObject&, String const& iso_string);
|
Optional<TemporalTimeZone> parse_temporal_time_zone_string(GlobalObject&, String const& iso_string);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
|
|
||||||
#include <LibJS/Runtime/AbstractOperations.h>
|
#include <LibJS/Runtime/AbstractOperations.h>
|
||||||
#include <LibJS/Runtime/GlobalObject.h>
|
#include <LibJS/Runtime/GlobalObject.h>
|
||||||
|
#include <LibJS/Runtime/Object.h>
|
||||||
|
#include <LibJS/Runtime/Temporal/AbstractOperations.h>
|
||||||
#include <LibJS/Runtime/Temporal/Duration.h>
|
#include <LibJS/Runtime/Temporal/Duration.h>
|
||||||
#include <LibJS/Runtime/Temporal/DurationConstructor.h>
|
#include <LibJS/Runtime/Temporal/DurationConstructor.h>
|
||||||
|
|
||||||
|
@ -27,6 +29,114 @@ Duration::Duration(double years, double months, double weeks, double days, doubl
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 7.5.1 ToTemporalDuration ( item ), https://tc39.es/proposal-temporal/#sec-temporal-totemporalduration
|
||||||
|
Duration* to_temporal_duration(GlobalObject& global_object, Value item)
|
||||||
|
{
|
||||||
|
auto& vm = global_object.vm();
|
||||||
|
|
||||||
|
Optional<TemporalDuration> result;
|
||||||
|
|
||||||
|
// 1. If Type(item) is Object, then
|
||||||
|
if (item.is_object()) {
|
||||||
|
// a. If item has an [[InitializedTemporalDuration]] internal slot, then
|
||||||
|
if (is<Duration>(item.as_object())) {
|
||||||
|
// i. Return item.
|
||||||
|
return &static_cast<Duration&>(item.as_object());
|
||||||
|
}
|
||||||
|
// b. Let result be ? ToTemporalDurationRecord(item).
|
||||||
|
result = to_temporal_duration_record(global_object, item.as_object());
|
||||||
|
if (vm.exception())
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
// 2. Else,
|
||||||
|
else {
|
||||||
|
// a. Let string be ? ToString(item).
|
||||||
|
auto string = item.to_string(global_object);
|
||||||
|
if (vm.exception())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
// b. Let result be ? ParseTemporalDurationString(string).
|
||||||
|
result = parse_temporal_duration_string(global_object, string);
|
||||||
|
if (vm.exception())
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Return ? CreateTemporalDuration(result.[[Years]], result.[[Months]], result.[[Weeks]], result.[[Days]], result.[[Hours]], result.[[Minutes]], result.[[Seconds]], result.[[Milliseconds]], result.[[Microseconds]], result.[[Nanoseconds]]).
|
||||||
|
return create_temporal_duration(global_object, result->years, result->months, result->weeks, result->days, result->hours, result->minutes, result->seconds, result->milliseconds, result->microseconds, result->nanoseconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7.5.2 ToTemporalDurationRecord ( temporalDurationLike ), https://tc39.es/proposal-temporal/#sec-temporal-totemporaldurationrecord
|
||||||
|
TemporalDuration to_temporal_duration_record(GlobalObject& global_object, Object& temporal_duration_like)
|
||||||
|
{
|
||||||
|
auto& vm = global_object.vm();
|
||||||
|
|
||||||
|
// 1. Assert: Type(temporalDurationLike) is Object.
|
||||||
|
|
||||||
|
// 2. If temporalDurationLike has an [[InitializedTemporalDuration]] internal slot, then
|
||||||
|
if (is<Duration>(temporal_duration_like)) {
|
||||||
|
auto& duration = static_cast<Duration&>(temporal_duration_like);
|
||||||
|
|
||||||
|
// a. Return the Record { [[Years]]: temporalDurationLike.[[Years]], [[Months]]: temporalDurationLike.[[Months]], [[Weeks]]: temporalDurationLike.[[Weeks]], [[Days]]: temporalDurationLike.[[Days]], [[Hours]]: temporalDurationLike.[[Hours]], [[Minutes]]: temporalDurationLike.[[Minutes]], [[Seconds]]: temporalDurationLike.[[Seconds]], [[Milliseconds]]: temporalDurationLike.[[Milliseconds]], [[Microseconds]]: temporalDurationLike.[[Microseconds]], [[Nanoseconds]]: temporalDurationLike.[[Nanoseconds]] }.
|
||||||
|
return TemporalDuration { .years = duration.years(), .months = duration.months(), .weeks = duration.weeks(), .days = duration.days(), .hours = duration.hours(), .minutes = duration.minutes(), .seconds = duration.seconds(), .milliseconds = duration.milliseconds(), .microseconds = duration.microseconds(), .nanoseconds = duration.nanoseconds() };
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Let result be a new Record with all the internal slots given in the Internal Slot column in Table 7.
|
||||||
|
auto result = TemporalDuration {};
|
||||||
|
|
||||||
|
// 4. Let any be false.
|
||||||
|
auto any = false;
|
||||||
|
|
||||||
|
// 5. For each row of Table 7, except the header row, in table order, do
|
||||||
|
for (auto& [internal_slot, property] : temporal_duration_like_properties<TemporalDuration, double>(vm)) {
|
||||||
|
// a. Let prop be the Property value of the current row.
|
||||||
|
|
||||||
|
// b. Let val be ? Get(temporalDurationLike, prop).
|
||||||
|
auto value = temporal_duration_like.get(property);
|
||||||
|
if (vm.exception())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
// c. If val is not undefined, then
|
||||||
|
if (!value.is_undefined()) {
|
||||||
|
// i. Set any to true.
|
||||||
|
any = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: This is not in the spec but it seems to be implied, and is also what the polyfill does.
|
||||||
|
// I think the steps d, e, and f should be conditional based on c - otherwise we call ToNumber(undefined),
|
||||||
|
// get NaN and immediately fail the floor(val) ≠ val check, making the `any` flag pointless. See:
|
||||||
|
// - https://github.com/tc39/proposal-temporal/blob/4b4dbd427d4b0468a3b064ca7082f25b209923bc/polyfill/lib/ecmascript.mjs#L556-L607
|
||||||
|
// - https://github.com/tc39/proposal-temporal/blob/4b4dbd427d4b0468a3b064ca7082f25b209923bc/polyfill/lib/ecmascript.mjs#L876-L893
|
||||||
|
else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// d. Let val be ? ToNumber(val).
|
||||||
|
value = value.to_number(global_object);
|
||||||
|
if (vm.exception())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
// e. If floor(val) ≠ val, then
|
||||||
|
if (floor(value.as_double()) != value.as_double()) {
|
||||||
|
// i. Throw a RangeError exception.
|
||||||
|
vm.throw_exception<RangeError>(global_object, ErrorType::TemporalInvalidDurationPropertyValue, property.as_string(), value.to_string_without_side_effects());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// f. Set result's internal slot whose name is the Internal Slot value of the current row to val.
|
||||||
|
result.*internal_slot = value.as_double();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. If any is false, then
|
||||||
|
if (!any) {
|
||||||
|
// a. Throw a TypeError exception.
|
||||||
|
vm.throw_exception<TypeError>(global_object, ErrorType::TemporalInvalidDurationLikeObject);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7. Return result.
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// 7.5.3 DurationSign ( years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds )
|
// 7.5.3 DurationSign ( years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds )
|
||||||
i8 duration_sign(double years, double months, double weeks, double days, double hours, double minutes, double seconds, double milliseconds, double microseconds, double nanoseconds)
|
i8 duration_sign(double years, double months, double weeks, double days, double hours, double minutes, double seconds, double milliseconds, double microseconds, double nanoseconds)
|
||||||
{
|
{
|
||||||
|
|
|
@ -44,6 +44,21 @@ private:
|
||||||
double m_nanoseconds; // [[Nanoseconds]]
|
double m_nanoseconds; // [[Nanoseconds]]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Used by ToTemporalDurationRecord to temporarily hold values
|
||||||
|
struct TemporalDuration {
|
||||||
|
double years;
|
||||||
|
double months;
|
||||||
|
double weeks;
|
||||||
|
double days;
|
||||||
|
double hours;
|
||||||
|
double minutes;
|
||||||
|
double seconds;
|
||||||
|
double milliseconds;
|
||||||
|
double microseconds;
|
||||||
|
double nanoseconds;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Used by ToPartialDuration to temporarily hold values
|
||||||
struct PartialDuration {
|
struct PartialDuration {
|
||||||
Optional<double> years;
|
Optional<double> years;
|
||||||
Optional<double> months;
|
Optional<double> months;
|
||||||
|
@ -82,6 +97,8 @@ auto temporal_duration_like_properties = [](VM& vm) {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Duration* to_temporal_duration(GlobalObject&, Value item);
|
||||||
|
TemporalDuration to_temporal_duration_record(GlobalObject&, Object& temporal_duration_like);
|
||||||
i8 duration_sign(double years, double months, double weeks, double days, double hours, double minutes, double seconds, double milliseconds, double microseconds, double nanoseconds);
|
i8 duration_sign(double years, double months, double weeks, double days, double hours, double minutes, double seconds, double milliseconds, double microseconds, double nanoseconds);
|
||||||
bool is_valid_duration(double years, double months, double weeks, double days, double hours, double minutes, double seconds, double milliseconds, double microseconds, double nanoseconds);
|
bool is_valid_duration(double years, double months, double weeks, double days, double hours, double minutes, double seconds, double milliseconds, double microseconds, double nanoseconds);
|
||||||
PartialDuration to_partial_duration(GlobalObject&, Value temporal_duration_like);
|
PartialDuration to_partial_duration(GlobalObject&, Value temporal_duration_like);
|
||||||
|
|
|
@ -25,6 +25,9 @@ void DurationConstructor::initialize(GlobalObject& global_object)
|
||||||
// 7.2.1 Temporal.Duration.prototype, https://tc39.es/proposal-temporal/#sec-temporal-duration-prototype
|
// 7.2.1 Temporal.Duration.prototype, https://tc39.es/proposal-temporal/#sec-temporal-duration-prototype
|
||||||
define_direct_property(vm.names.prototype, global_object.temporal_duration_prototype(), 0);
|
define_direct_property(vm.names.prototype, global_object.temporal_duration_prototype(), 0);
|
||||||
|
|
||||||
|
u8 attr = Attribute::Writable | Attribute::Configurable;
|
||||||
|
define_native_function(vm.names.from, from, 1, attr);
|
||||||
|
|
||||||
define_direct_property(vm.names.length, Value(0), Attribute::Configurable);
|
define_direct_property(vm.names.length, Value(0), Attribute::Configurable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,4 +102,21 @@ Value DurationConstructor::construct(FunctionObject& new_target)
|
||||||
return create_temporal_duration(global_object, y, mo, w, d, h, m, s, ms, mis, ns, &new_target);
|
return create_temporal_duration(global_object, y, mo, w, d, h, m, s, ms, mis, ns, &new_target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 7.2.2 Temporal.Duration.from ( item ), https://tc39.es/proposal-temporal/#sec-temporal.duration.from
|
||||||
|
JS_DEFINE_NATIVE_FUNCTION(DurationConstructor::from)
|
||||||
|
{
|
||||||
|
auto item = vm.argument(0);
|
||||||
|
|
||||||
|
// 1. If Type(item) is Object and item has an [[InitializedTemporalDuration]] internal slot, then
|
||||||
|
if (item.is_object() && is<Duration>(item.as_object())) {
|
||||||
|
auto& duration = static_cast<Duration&>(item.as_object());
|
||||||
|
|
||||||
|
// a. Return ? CreateTemporalDuration(item.[[Years]], item.[[Months]], item.[[Weeks]], item.[[Days]], item.[[Hours]], item.[[Minutes]], item.[[Seconds]], item.[[Milliseconds]], item.[[Microseconds]], item.[[Nanoseconds]]).
|
||||||
|
return create_temporal_duration(global_object, duration.years(), duration.months(), duration.weeks(), duration.days(), duration.hours(), duration.minutes(), duration.seconds(), duration.milliseconds(), duration.microseconds(), duration.nanoseconds());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Return ? ToTemporalDuration(item).
|
||||||
|
return to_temporal_duration(global_object, item);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,8 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual bool has_constructor() const override { return true; }
|
virtual bool has_constructor() const override { return true; }
|
||||||
|
|
||||||
|
JS_DECLARE_NATIVE_FUNCTION(from);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
const expectDurationOneToTen = duration => {
|
||||||
|
expect(duration.years).toBe(1);
|
||||||
|
expect(duration.months).toBe(2);
|
||||||
|
expect(duration.weeks).toBe(3);
|
||||||
|
expect(duration.days).toBe(4);
|
||||||
|
expect(duration.hours).toBe(5);
|
||||||
|
expect(duration.minutes).toBe(6);
|
||||||
|
expect(duration.seconds).toBe(7);
|
||||||
|
expect(duration.milliseconds).toBe(8);
|
||||||
|
expect(duration.microseconds).toBe(9);
|
||||||
|
expect(duration.nanoseconds).toBe(10);
|
||||||
|
};
|
||||||
|
|
||||||
|
describe("correct behavior", () => {
|
||||||
|
test("length is 1", () => {
|
||||||
|
expect(Temporal.Duration.from).toHaveLength(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Duration instance argument", () => {
|
||||||
|
const duration = Temporal.Duration.from(
|
||||||
|
new Temporal.Duration(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
|
||||||
|
);
|
||||||
|
expectDurationOneToTen(duration);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Duration-like object argument", () => {
|
||||||
|
const duration = Temporal.Duration.from({
|
||||||
|
years: 1,
|
||||||
|
months: 2,
|
||||||
|
weeks: 3,
|
||||||
|
days: 4,
|
||||||
|
hours: 5,
|
||||||
|
minutes: 6,
|
||||||
|
seconds: 7,
|
||||||
|
milliseconds: 8,
|
||||||
|
microseconds: 9,
|
||||||
|
nanoseconds: 10,
|
||||||
|
});
|
||||||
|
expectDurationOneToTen(duration);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Un-skip once ParseTemporalDurationString is implemented
|
||||||
|
test.skip("Duration string argument", () => {
|
||||||
|
const duration = Temporal.Duration.from("TODO");
|
||||||
|
expectDurationOneToTen(duration);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("errors", () => {
|
||||||
|
test("Invalid duration-like object", () => {
|
||||||
|
expect(() => {
|
||||||
|
Temporal.Duration.from({});
|
||||||
|
}).toThrowWithMessage(TypeError, "Invalid duration-like object");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Invalid duration property value", () => {
|
||||||
|
expect(() => {
|
||||||
|
Temporal.Duration.from({ years: 1.23 });
|
||||||
|
}).toThrowWithMessage(
|
||||||
|
RangeError,
|
||||||
|
"Invalid value for duration property 'years': must be an integer, got 1.2" // ...29999999999999 - let's not include that in the test :^)
|
||||||
|
);
|
||||||
|
expect(() => {
|
||||||
|
Temporal.Duration.from({ years: "foo" });
|
||||||
|
}).toThrowWithMessage(
|
||||||
|
RangeError,
|
||||||
|
"Invalid value for duration property 'years': must be an integer, got NaN"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
Loading…
Add table
Add a link
Reference in a new issue