diff options
author | Petróczi Zoltán <lgnd@tutanota.com> | 2021-03-16 15:02:16 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-03-22 20:58:22 +0100 |
commit | ca49f96b7854d41c796b2c85e2193804b2e72a03 (patch) | |
tree | 926ec1ce1ae3efa9d4e9a1793082cba9d3e8112c /Userland | |
parent | d231c5e65b9c05a5743cb5d257d6d752ebd29f04 (diff) | |
download | serenity-ca49f96b7854d41c796b2c85e2193804b2e72a03.zip |
LibJS Date: Added "Invalid Date".
Setting an invalid value on a Date object now makes it invalid.
Setting it again but with correct values makes it valid again.
Diffstat (limited to 'Userland')
29 files changed, 486 insertions, 85 deletions
diff --git a/Userland/Libraries/LibJS/Runtime/Date.cpp b/Userland/Libraries/LibJS/Runtime/Date.cpp index 8644de4ad0..8b65c8db4c 100644 --- a/Userland/Libraries/LibJS/Runtime/Date.cpp +++ b/Userland/Libraries/LibJS/Runtime/Date.cpp @@ -32,15 +32,16 @@ namespace JS { -Date* Date::create(GlobalObject& global_object, Core::DateTime datetime, u16 milliseconds) +Date* Date::create(GlobalObject& global_object, Core::DateTime datetime, u16 milliseconds, bool is_invalid) { - return global_object.heap().allocate<Date>(global_object, datetime, milliseconds, *global_object.date_prototype()); + return global_object.heap().allocate<Date>(global_object, datetime, milliseconds, is_invalid, *global_object.date_prototype()); } -Date::Date(Core::DateTime datetime, u16 milliseconds, Object& prototype) +Date::Date(Core::DateTime datetime, u16 milliseconds, bool is_invalid, Object& prototype) : Object(prototype) , m_datetime(datetime) , m_milliseconds(milliseconds) + , m_is_invalid(is_invalid) { } diff --git a/Userland/Libraries/LibJS/Runtime/Date.h b/Userland/Libraries/LibJS/Runtime/Date.h index 11f50531aa..ffc68faa75 100644 --- a/Userland/Libraries/LibJS/Runtime/Date.h +++ b/Userland/Libraries/LibJS/Runtime/Date.h @@ -35,9 +35,9 @@ class Date final : public Object { JS_OBJECT(Date, Object); public: - static Date* create(GlobalObject&, Core::DateTime, u16 milliseconds); + static Date* create(GlobalObject&, Core::DateTime, u16 milliseconds, bool is_invalid = false); - Date(Core::DateTime datetime, u16 milliseconds, Object& prototype); + Date(Core::DateTime datetime, u16 milliseconds, bool is_invalid, Object& prototype); virtual ~Date() override; Core::DateTime& datetime() { return m_datetime; } @@ -54,6 +54,9 @@ public: double time() const { return datetime().timestamp() * 1000.0 + milliseconds(); } int year() const { return datetime().day(); } + bool is_invalid() const { return m_is_invalid; } + void set_is_invalid(bool value) { m_is_invalid = value; } + int utc_date() const; int utc_day() const; int utc_full_year() const; @@ -73,6 +76,9 @@ public: String time_string() const { return m_datetime.to_string("%T GMT+0000 (UTC)"); } String string() const { + if (is_invalid()) + return "Invalid Date"; + return String::formatted("{} {}", date_string(), time_string()); } @@ -94,6 +100,7 @@ private: Core::DateTime m_datetime; u16 m_milliseconds; + bool m_is_invalid { false }; }; } diff --git a/Userland/Libraries/LibJS/Runtime/DateConstructor.cpp b/Userland/Libraries/LibJS/Runtime/DateConstructor.cpp index d38101c8a8..093acbe140 100644 --- a/Userland/Libraries/LibJS/Runtime/DateConstructor.cpp +++ b/Userland/Libraries/LibJS/Runtime/DateConstructor.cpp @@ -1,6 +1,7 @@ /* * Copyright (c) 2020, Linus Groh <mail@linusgroh.de> * Copyright (c) 2020, Nico Weber <thakis@chromium.org> + * Copyright (c) 2021, Petróczi Zoltán <petroczizoltan@tutanota.com> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -176,30 +177,92 @@ Value DateConstructor::construct(Function&) auto milliseconds = static_cast<u16>(tv.tv_usec / 1000); return Date::create(global_object(), datetime, milliseconds); } + + auto create_invalid_date = [this]() { + auto datetime = Core::DateTime::from_timestamp(static_cast<time_t>(0)); + auto milliseconds = static_cast<u16>(0); + return Date::create(global_object(), datetime, milliseconds, true); + }; + if (vm.argument_count() == 1) { auto value = vm.argument(0); if (value.is_string()) value = parse_simplified_iso8601(value.as_string().string()); - // A timestamp since the epoch, in UTC. - // FIXME: This doesn't construct an "Invalid Date" object if the argument is NaN. - // FIXME: Date() probably should use a double as internal representation, so that NaN arguments and larger offsets are handled correctly. - double value_as_double = value.to_double(global_object()); + else + value = value.to_number(global_object()); + if (vm.exception()) return {}; + + if (!value.is_finite_number()) { + return create_invalid_date(); + } + + // A timestamp since the epoch, in UTC. + double value_as_double = value.as_double(); auto datetime = Core::DateTime::from_timestamp(static_cast<time_t>(value_as_double / 1000)); auto milliseconds = static_cast<u16>(fmod(value_as_double, 1000)); return Date::create(global_object(), datetime, milliseconds); } + // A date/time in components, in local time. - // FIXME: This doesn't construct an "Invalid Date" object if one of the arguments is NaN. - auto arg_or = [this, &vm](size_t i, i32 fallback) { return vm.argument_count() > i ? vm.argument(i).to_i32(global_object()) : fallback; }; - int year = vm.argument(0).to_i32(global_object()); - int month_index = vm.argument(1).to_i32(global_object()); - int day = arg_or(2, 1); - int hours = arg_or(3, 0); - int minutes = arg_or(4, 0); - int seconds = arg_or(5, 0); - int milliseconds = arg_or(6, 0); + auto arg_or = [&vm, this](size_t i, i32 fallback) { return vm.argument_count() > i ? vm.argument(i).to_number(global_object()) : Value(fallback); }; + + auto year_value = vm.argument(0).to_number(global_object()); + if (vm.exception()) + return {}; + if (!year_value.is_finite_number()) { + return create_invalid_date(); + } + auto year = year_value.as_i32(); + + auto month_index_value = vm.argument(1).to_number(global_object()); + if (vm.exception()) + return {}; + if (!month_index_value.is_finite_number()) { + return create_invalid_date(); + } + auto month_index = month_index_value.as_i32(); + + auto day_value = arg_or(2, 1); + if (vm.exception()) + return {}; + if (!day_value.is_finite_number()) { + return create_invalid_date(); + } + auto day = day_value.as_i32(); + + auto hours_value = arg_or(3, 0); + if (vm.exception()) + return {}; + if (!hours_value.is_finite_number()) { + return create_invalid_date(); + } + auto hours = hours_value.as_i32(); + + auto minutes_value = arg_or(4, 0); + if (vm.exception()) + return {}; + if (!minutes_value.is_finite_number()) { + return create_invalid_date(); + } + auto minutes = minutes_value.as_i32(); + + auto seconds_value = arg_or(5, 0); + if (vm.exception()) + return {}; + if (!seconds_value.is_finite_number()) { + return create_invalid_date(); + } + auto seconds = seconds_value.as_i32(); + + auto milliseconds_value = arg_or(6, 0); + if (vm.exception()) + return {}; + if (!milliseconds_value.is_finite_number()) { + return create_invalid_date(); + } + auto milliseconds = milliseconds_value.as_i32(); seconds += milliseconds / 1000; milliseconds %= 1000; diff --git a/Userland/Libraries/LibJS/Runtime/DatePrototype.cpp b/Userland/Libraries/LibJS/Runtime/DatePrototype.cpp index 2d98bf6adf..f3fc6dbb30 100644 --- a/Userland/Libraries/LibJS/Runtime/DatePrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/DatePrototype.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2020, Linus Groh <mail@linusgroh.de> + * Copyright (c) 2021, Petróczi Zoltán <petroczizoltan@tutanota.com> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -106,6 +107,10 @@ JS_DEFINE_NATIVE_FUNCTION(DatePrototype::get_date) auto* this_object = typed_this(vm, global_object); if (!this_object) return {}; + + if (this_object->is_invalid()) + return js_nan(); + return Value(static_cast<double>(this_object->date())); } @@ -114,6 +119,10 @@ JS_DEFINE_NATIVE_FUNCTION(DatePrototype::get_day) auto* this_object = typed_this(vm, global_object); if (!this_object) return {}; + + if (this_object->is_invalid()) + return js_nan(); + return Value(static_cast<double>(this_object->day())); } @@ -122,6 +131,10 @@ JS_DEFINE_NATIVE_FUNCTION(DatePrototype::get_full_year) auto* this_object = typed_this(vm, global_object); if (!this_object) return {}; + + if (this_object->is_invalid()) + return js_nan(); + return Value(static_cast<double>(this_object->full_year())); } @@ -130,32 +143,42 @@ JS_DEFINE_NATIVE_FUNCTION(DatePrototype::set_full_year) auto* this_object = typed_this(vm, global_object); if (!this_object) return {}; - auto new_year = vm.argument(0).to_i32(global_object); - if (vm.exception()) - return {}; auto& datetime = this_object->datetime(); - i32 new_month; - if (vm.argument_count() >= 2) { - new_month = vm.argument(1).to_i32(global_object); - if (vm.exception()) - return {}; - } else { - new_month = datetime.month(); + auto arg_or = [&vm, &global_object](size_t i, i32 fallback) { return vm.argument_count() > i ? vm.argument(i).to_number(global_object) : Value(fallback); }; + + auto new_year_value = vm.argument(0).to_number(global_object); + if (vm.exception()) + return {}; + if (!new_year_value.is_finite_number()) { + this_object->set_is_invalid(true); + return js_nan(); } + auto new_year = new_year_value.as_i32(); - i32 new_day; - if (vm.argument_count() >= 3) { - new_day = vm.argument(2).to_i32(global_object); - if (vm.exception()) - return {}; - } else { - new_day = datetime.day(); + auto new_month_value = arg_or(1, datetime.month()); + if (vm.exception()) + return {}; + if (!new_month_value.is_finite_number()) { + this_object->set_is_invalid(true); + return js_nan(); } + auto new_month = new_month_value.as_i32(); + + auto new_day_value = arg_or(2, datetime.day()); + if (vm.exception()) + return {}; + if (!new_day_value.is_finite_number()) { + this_object->set_is_invalid(true); + return js_nan(); + } + auto new_day = new_day_value.as_i32(); datetime.set_time(new_year, new_month, new_day, datetime.hour(), datetime.minute(), datetime.second()); - return Value(this_object->time()); + this_object->set_is_invalid(false); + + return Value { this_object->time() }; } JS_DEFINE_NATIVE_FUNCTION(DatePrototype::get_hours) @@ -163,6 +186,10 @@ JS_DEFINE_NATIVE_FUNCTION(DatePrototype::get_hours) auto* this_object = typed_this(vm, global_object); if (!this_object) return {}; + + if (this_object->is_invalid()) + return js_nan(); + return Value(static_cast<double>(this_object->hours())); } @@ -172,37 +199,50 @@ JS_DEFINE_NATIVE_FUNCTION(DatePrototype::set_hours) if (!this_object) return {}; - auto new_hours = vm.argument(0).to_i32(global_object); - if (vm.exception()) - return {}; + auto arg_or = [&vm, &global_object](size_t i, i32 fallback) { return vm.argument_count() > i ? vm.argument(i).to_number(global_object) : Value(fallback); }; auto& datetime = this_object->datetime(); - i32 new_minutes; - if (vm.argument_count() >= 2) { - new_minutes = vm.argument(1).to_i32(global_object); - if (vm.exception()) - return {}; - } else { - new_minutes = datetime.minute(); + auto new_hours_value = vm.argument(0).to_number(global_object); + if (vm.exception()) + return {}; + if (!new_hours_value.is_finite_number()) { + this_object->set_is_invalid(true); + return js_nan(); } + auto new_hours = new_hours_value.as_i32(); - i32 new_seconds; - if (vm.argument_count() >= 3) { - new_seconds = vm.argument(2).to_i32(global_object); - if (vm.exception()) - return {}; - } else { - new_seconds = datetime.second(); + auto new_minutes_value = arg_or(1, datetime.minute()); + if (vm.exception()) + return {}; + if (!new_minutes_value.is_finite_number()) { + this_object->set_is_invalid(true); + return js_nan(); } + auto new_minutes = new_minutes_value.as_i32(); - if (vm.argument_count() >= 4) { - auto new_milliseconds = vm.argument(3).to_i32(global_object); - if (vm.exception()) - return {}; - new_seconds += new_milliseconds / 1000; - this_object->set_milliseconds(new_milliseconds % 1000); + auto new_seconds_value = arg_or(2, datetime.second()); + if (vm.exception()) + return {}; + if (!new_seconds_value.is_finite_number()) { + this_object->set_is_invalid(true); + return js_nan(); } + auto new_seconds = new_seconds_value.as_i32(); + + auto new_milliseconds_value = arg_or(3, this_object->milliseconds()); + if (vm.exception()) + return {}; + if (!new_milliseconds_value.is_finite_number()) { + this_object->set_is_invalid(true); + return js_nan(); + } + auto new_milliseconds = new_milliseconds_value.as_i32(); + + this_object->set_is_invalid(false); + + new_seconds += new_milliseconds / 1000; + this_object->set_milliseconds(new_milliseconds % 1000); datetime.set_time(datetime.year(), datetime.month(), datetime.day(), new_hours, new_minutes, new_seconds); return Value(this_object->time()); @@ -213,6 +253,10 @@ JS_DEFINE_NATIVE_FUNCTION(DatePrototype::get_milliseconds) auto* this_object = typed_this(vm, global_object); if (!this_object) return {}; + + if (this_object->is_invalid()) + return js_nan(); + return Value(static_cast<double>(this_object->milliseconds())); } @@ -222,10 +266,17 @@ JS_DEFINE_NATIVE_FUNCTION(DatePrototype::set_milliseconds) if (!this_object) return {}; - auto new_milliseconds = vm.argument(0).to_i32(global_object); + auto new_milliseconds_value = vm.argument(0).to_number(global_object); if (vm.exception()) return {}; + if (!new_milliseconds_value.is_finite_number()) { + this_object->set_is_invalid(true); + return js_nan(); + } + + auto new_milliseconds = new_milliseconds_value.as_i32(); + this_object->set_milliseconds(new_milliseconds % 1000); auto added_seconds = new_milliseconds / 1000; @@ -234,6 +285,8 @@ JS_DEFINE_NATIVE_FUNCTION(DatePrototype::set_milliseconds) datetime.set_time(datetime.year(), datetime.month(), datetime.day(), datetime.hour(), datetime.minute(), datetime.second() + added_seconds); } + this_object->set_is_invalid(false); + return Value(this_object->time()); } @@ -242,6 +295,10 @@ JS_DEFINE_NATIVE_FUNCTION(DatePrototype::get_minutes) auto* this_object = typed_this(vm, global_object); if (!this_object) return {}; + + if (this_object->is_invalid()) + return js_nan(); + return Value(static_cast<double>(this_object->minutes())); } @@ -251,28 +308,41 @@ JS_DEFINE_NATIVE_FUNCTION(DatePrototype::set_minutes) if (!this_object) return {}; - auto new_minutes = vm.argument(0).to_i32(global_object); - if (vm.exception()) - return {}; + auto arg_or = [&vm, &global_object](size_t i, i32 fallback) { return vm.argument_count() > i ? vm.argument(i).to_number(global_object) : Value(fallback); }; auto& datetime = this_object->datetime(); - i32 new_seconds; - if (vm.argument_count() >= 2) { - new_seconds = vm.argument(1).to_i32(global_object); - if (vm.exception()) - return {}; - } else { - new_seconds = datetime.second(); + auto new_minutes_value = vm.argument(0).to_number(global_object); + if (vm.exception()) + return {}; + if (!new_minutes_value.is_finite_number()) { + this_object->set_is_invalid(true); + return js_nan(); } + auto new_minutes = new_minutes_value.as_i32(); - if (vm.argument_count() >= 3) { - auto new_milliseconds = vm.argument(2).to_i32(global_object); - if (vm.exception()) - return {}; - new_seconds += new_milliseconds / 1000; - this_object->set_milliseconds(new_milliseconds % 1000); + auto new_seconds_value = arg_or(1, datetime.second()); + if (vm.exception()) + return {}; + if (!new_seconds_value.is_finite_number()) { + this_object->set_is_invalid(true); + return js_nan(); } + auto new_seconds = new_seconds_value.as_i32(); + + auto new_milliseconds_value = arg_or(2, this_object->milliseconds()); + if (vm.exception()) + return {}; + if (!new_milliseconds_value.is_finite_number()) { + this_object->set_is_invalid(true); + return js_nan(); + } + auto new_milliseconds = new_milliseconds_value.as_i32(); + + this_object->set_is_invalid(false); + + new_seconds += new_milliseconds / 1000; + this_object->set_milliseconds(new_milliseconds % 1000); datetime.set_time(datetime.year(), datetime.month(), datetime.day(), datetime.hour(), new_minutes, new_seconds); return Value(this_object->time()); @@ -283,6 +353,10 @@ JS_DEFINE_NATIVE_FUNCTION(DatePrototype::get_month) auto* this_object = typed_this(vm, global_object); if (!this_object) return {}; + + if (this_object->is_invalid()) + return js_nan(); + return Value(static_cast<double>(this_object->month())); } @@ -291,6 +365,10 @@ JS_DEFINE_NATIVE_FUNCTION(DatePrototype::get_seconds) auto* this_object = typed_this(vm, global_object); if (!this_object) return {}; + + if (this_object->is_invalid()) + return js_nan(); + return Value(static_cast<double>(this_object->seconds())); } @@ -300,19 +378,32 @@ JS_DEFINE_NATIVE_FUNCTION(DatePrototype::set_seconds) if (!this_object) return {}; - auto new_seconds = vm.argument(0).to_i32(global_object); + auto arg_or = [&vm, &global_object](size_t i, i32 fallback) { return vm.argument_count() > i ? vm.argument(i).to_number(global_object) : Value(fallback); }; + + auto& datetime = this_object->datetime(); + + auto new_seconds_value = vm.argument(0).to_number(global_object); if (vm.exception()) return {}; + if (!new_seconds_value.is_finite_number()) { + this_object->set_is_invalid(true); + return js_nan(); + } + auto new_seconds = new_seconds_value.as_i32(); - if (vm.argument_count() >= 2) { - auto new_milliseconds = vm.argument(1).to_i32(global_object); - if (vm.exception()) - return {}; - new_seconds += new_milliseconds / 1000; - this_object->set_milliseconds(new_milliseconds % 1000); + auto new_milliseconds_value = arg_or(1, this_object->milliseconds()); + if (vm.exception()) + return {}; + if (!new_milliseconds_value.is_finite_number()) { + this_object->set_is_invalid(true); + return js_nan(); } + auto new_milliseconds = new_milliseconds_value.as_i32(); - auto& datetime = this_object->datetime(); + this_object->set_is_invalid(false); + + new_seconds += new_milliseconds / 1000; + this_object->set_milliseconds(new_milliseconds % 1000); datetime.set_time(datetime.year(), datetime.month(), datetime.day(), datetime.hour(), datetime.minute(), new_seconds); return Value(this_object->time()); @@ -323,6 +414,10 @@ JS_DEFINE_NATIVE_FUNCTION(DatePrototype::get_time) auto* this_object = typed_this(vm, global_object); if (!this_object) return {}; + + if (this_object->is_invalid()) + return js_nan(); + return Value(this_object->time()); } @@ -331,6 +426,10 @@ JS_DEFINE_NATIVE_FUNCTION(DatePrototype::get_utc_date) auto* this_object = typed_this(vm, global_object); if (!this_object) return {}; + + if (this_object->is_invalid()) + return js_nan(); + return Value(static_cast<double>(this_object->utc_date())); } @@ -339,6 +438,10 @@ JS_DEFINE_NATIVE_FUNCTION(DatePrototype::get_utc_day) auto* this_object = typed_this(vm, global_object); if (!this_object) return {}; + + if (this_object->is_invalid()) + return js_nan(); + return Value(static_cast<double>(this_object->utc_day())); } @@ -347,6 +450,10 @@ JS_DEFINE_NATIVE_FUNCTION(DatePrototype::get_utc_full_year) auto* this_object = typed_this(vm, global_object); if (!this_object) return {}; + + if (this_object->is_invalid()) + return js_nan(); + return Value(static_cast<double>(this_object->utc_full_year())); } @@ -355,6 +462,10 @@ JS_DEFINE_NATIVE_FUNCTION(DatePrototype::get_utc_hours) auto* this_object = typed_this(vm, global_object); if (!this_object) return {}; + + if (this_object->is_invalid()) + return js_nan(); + return Value(static_cast<double>(this_object->utc_hours())); } @@ -363,6 +474,10 @@ JS_DEFINE_NATIVE_FUNCTION(DatePrototype::get_utc_milliseconds) auto* this_object = typed_this(vm, global_object); if (!this_object) return {}; + + if (this_object->is_invalid()) + return js_nan(); + return Value(static_cast<double>(this_object->utc_milliseconds())); } @@ -371,6 +486,10 @@ JS_DEFINE_NATIVE_FUNCTION(DatePrototype::get_utc_month) auto* this_object = typed_this(vm, global_object); if (!this_object) return {}; + + if (this_object->is_invalid()) + return js_nan(); + return Value(static_cast<double>(this_object->utc_month())); } @@ -379,6 +498,10 @@ JS_DEFINE_NATIVE_FUNCTION(DatePrototype::get_utc_minutes) auto* this_object = typed_this(vm, global_object); if (!this_object) return {}; + + if (this_object->is_invalid()) + return js_nan(); + return Value(static_cast<double>(this_object->utc_minutes())); } @@ -387,6 +510,10 @@ JS_DEFINE_NATIVE_FUNCTION(DatePrototype::get_utc_seconds) auto* this_object = typed_this(vm, global_object); if (!this_object) return {}; + + if (this_object->is_invalid()) + return js_nan(); + return Value(static_cast<double>(this_object->utc_seconds())); } @@ -395,6 +522,10 @@ JS_DEFINE_NATIVE_FUNCTION(DatePrototype::to_date_string) auto* this_object = typed_this(vm, global_object); if (!this_object) return {}; + + if (this_object->is_invalid()) + return js_string(vm, "Invalid Date"); + auto string = this_object->date_string(); return js_string(vm, move(string)); } @@ -412,6 +543,9 @@ JS_DEFINE_NATIVE_FUNCTION(DatePrototype::to_utc_string) if (!this_object) return {}; + if (this_object->is_invalid()) + return js_string(vm, "Invalid Date"); + // HTTP dates are always expressed in GMT. auto string = this_object->gmt_date_string(); return js_string(vm, move(string)); @@ -422,6 +556,12 @@ JS_DEFINE_NATIVE_FUNCTION(DatePrototype::to_iso_string) auto* this_object = typed_this(vm, global_object); if (!this_object) return {}; + + if (this_object->is_invalid()) { + vm.throw_exception<RangeError>(global_object, ErrorType::InvalidTimeValue); + return {}; + } + auto string = this_object->iso_date_string(); return js_string(vm, move(string)); } @@ -431,6 +571,10 @@ JS_DEFINE_NATIVE_FUNCTION(DatePrototype::to_locale_date_string) auto* this_object = typed_this(vm, global_object); if (!this_object) return {}; + + if (this_object->is_invalid()) + return js_string(vm, "Invalid Date"); + // FIXME: Optional locales, options params. auto string = this_object->locale_date_string(); return js_string(vm, move(string)); @@ -441,6 +585,10 @@ JS_DEFINE_NATIVE_FUNCTION(DatePrototype::to_locale_string) auto* this_object = typed_this(vm, global_object); if (!this_object) return {}; + + if (this_object->is_invalid()) + return js_string(vm, "Invalid Date"); + // FIXME: Optional locales, options params. auto string = this_object->locale_string(); return js_string(vm, move(string)); @@ -451,6 +599,10 @@ JS_DEFINE_NATIVE_FUNCTION(DatePrototype::to_locale_time_string) auto* this_object = typed_this(vm, global_object); if (!this_object) return {}; + + if (this_object->is_invalid()) + return js_string(vm, "Invalid Date"); + // FIXME: Optional locales, options params. auto string = this_object->locale_time_string(); return js_string(vm, move(string)); @@ -461,6 +613,10 @@ JS_DEFINE_NATIVE_FUNCTION(DatePrototype::to_time_string) auto* this_object = typed_this(vm, global_object); if (!this_object) return {}; + + if (this_object->is_invalid()) + return js_string(vm, "Invalid Date"); + auto string = this_object->time_string(); return js_string(vm, move(string)); } @@ -470,6 +626,10 @@ JS_DEFINE_NATIVE_FUNCTION(DatePrototype::to_string) auto* this_object = typed_this(vm, global_object); if (!this_object) return {}; + + if (this_object->is_invalid()) + return js_string(vm, "Invalid Date"); + auto string = this_object->string(); return js_string(vm, move(string)); } diff --git a/Userland/Libraries/LibJS/Runtime/ErrorTypes.h b/Userland/Libraries/LibJS/Runtime/ErrorTypes.h index f55314261d..cadc118d16 100644 --- a/Userland/Libraries/LibJS/Runtime/ErrorTypes.h +++ b/Userland/Libraries/LibJS/Runtime/ErrorTypes.h @@ -51,6 +51,7 @@ M(InvalidIndex, "Index must be a positive integer") \ M(InvalidLeftHandAssignment, "Invalid left-hand side in assignment") \ M(InvalidLength, "Invalid {} length") \ + M(InvalidTimeValue, "Invalid time value") \ M(InvalidRadix, "Radix must be an integer no less than 2, and no greater than 36") \ M(IsNotA, "{} is not a {}") \ M(IsNotAEvaluatedFrom, "{} is not a {} (evaluated from '{}')") \ diff --git a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.js b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.js index cc76212e22..5a1c30178f 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.js @@ -24,6 +24,13 @@ test("timestamp constructor", () => { expect(date.getSeconds()).toBe(1); expect(date.getFullYear()).toBe(1970); expect(date.getMonth()).toBe(1); // Feb + + date = new Date(NaN); + expect(date.getTime()).toBe(NaN); + date = new Date(undefined); + expect(date.getTime()).toBe(NaN); + date = new Date(""); + expect(date.getTime()).toBe(NaN); }); test("tuple constructor", () => { @@ -52,6 +59,11 @@ test("tuple constructor", () => { let timestamp_upper_bound = 1577750400000; // 2019-12-31T00:00:00Z expect(date.getTime()).toBeGreaterThan(timestamp_lower_bound); expect(date.getTime()).toBeLessThan(timestamp_upper_bound); + + date = new Date(NaN, 11, 15, 9, 16, 14, 123); + expect(date.getTime()).toBe(NaN); + date = new Date(2021, 11, 15, 9, 16, 14, undefined); + expect(date.getTime()).toBe(NaN); }); test("tuple constructor overflow", () => { @@ -65,7 +77,7 @@ test("tuple constructor overflow", () => { expect(date.getMilliseconds()).toBe(345); expect(date.getDay()).toBe(4); - let date = new Date(2019, -13, -33, -30, -70, -80, -2345); + date = new Date(2019, -13, -33, -30, -70, -80, -2345); expect(date.getFullYear()).toBe(2017); expect(date.getMonth()).toBe(9); expect(date.getDate()).toBe(26); diff --git a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getDate.js b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getDate.js index 647e43a997..d234126373 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getDate.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getDate.js @@ -4,4 +4,5 @@ test("basic functionality", () => { expect(d.getDate()).not.toBeNaN(); expect(d.getDate()).toBeGreaterThanOrEqual(1); expect(d.getDate()).toBeLessThanOrEqual(31); + expect(new Date(NaN).getDate()).toBe(NaN); }); diff --git a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getDay.js b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getDay.js index 534efeeee5..8f2a8cb223 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getDay.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getDay.js @@ -4,4 +4,5 @@ test("basic functionality", () => { expect(d.getDay()).not.toBeNaN(); expect(d.getDay()).toBeGreaterThanOrEqual(0); expect(d.getDay()).toBeLessThanOrEqual(6); + expect(new Date(NaN).getDay()).toBe(NaN); }); diff --git a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getFullYear.js b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getFullYear.js index 3748e835cf..b50ff71d8d 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getFullYear.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getFullYear.js @@ -4,4 +4,5 @@ test("basic functionality", () => { expect(d.getFullYear()).not.toBeNaN(); expect(d.getFullYear()).toBe(d.getFullYear()); expect(d.getFullYear()).toBeGreaterThanOrEqual(2020); + expect(new Date(NaN).getFullYear()).toBe(NaN); }); diff --git a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getHours.js b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getHours.js index 7e562288f2..10cbe8bea5 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getHours.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getHours.js @@ -4,4 +4,5 @@ test("basic functionality", () => { expect(d.getHours()).not.toBeNaN(); expect(d.getHours()).toBeGreaterThanOrEqual(0); expect(d.getHours()).toBeLessThanOrEqual(23); + expect(new Date(NaN).getHours()).toBe(NaN); }); diff --git a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getMilliseconds.js b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getMilliseconds.js index 90c686f729..90ea61b32b 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getMilliseconds.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getMilliseconds.js @@ -4,4 +4,5 @@ test("basic functionality", () => { expect(d.getMilliseconds()).not.toBeNaN(); expect(d.getMilliseconds()).toBeGreaterThanOrEqual(0); expect(d.getMilliseconds()).toBeLessThanOrEqual(999); + expect(new Date(NaN).getMilliseconds()).toBe(NaN); }); diff --git a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getMinutes.js b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getMinutes.js index 5b87b8251d..06bd7b5b43 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getMinutes.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getMinutes.js @@ -4,4 +4,5 @@ test("basic functionality", () => { expect(d.getMinutes()).not.toBeNaN(); expect(d.getMinutes()).toBeGreaterThanOrEqual(0); expect(d.getMinutes()).toBeLessThanOrEqual(59); + expect(new Date(NaN).getMinutes()).toBe(NaN); }); diff --git a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getMonth.js b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getMonth.js index 7d52866ce7..ad9722a538 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getMonth.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getMonth.js @@ -4,4 +4,5 @@ test("basic functionality", () => { expect(d.getMonth()).not.toBeNaN(); expect(d.getMonth()).toBeGreaterThanOrEqual(0); expect(d.getMonth()).toBeLessThanOrEqual(11); + expect(new Date(NaN).getMonth()).toBe(NaN); }); diff --git a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getSeconds.js b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getSeconds.js index df30881c9a..07f02a8850 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getSeconds.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getSeconds.js @@ -4,4 +4,5 @@ test("basic functionality", () => { expect(d.getSeconds()).not.toBeNaN(); expect(d.getSeconds()).toBeGreaterThanOrEqual(0); expect(d.getSeconds()).toBeLessThanOrEqual(59); + expect(new Date(NaN).getSeconds()).toBe(NaN); }); diff --git a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getTime.js b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getTime.js index b9ada6fcc9..c3397ff0ff 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getTime.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getTime.js @@ -3,4 +3,5 @@ test("basic functionality", () => { expect(d.getTime()).toBe(d.getTime()); expect(d.getTime()).not.toBeNaN(); expect(d.getTime()).toBeGreaterThanOrEqual(1580000000000); + expect(new Date(NaN).getTime()).toBe(NaN); }); diff --git a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getUTCDate.js b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getUTCDate.js index d207385bad..2d1820508c 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getUTCDate.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getUTCDate.js @@ -4,4 +4,5 @@ test("basic functionality", () => { expect(d.getUTCDate()).not.toBeNaN(); expect(d.getUTCDate()).toBeGreaterThanOrEqual(1); expect(d.getUTCDate()).toBeLessThanOrEqual(31); + expect(new Date(NaN).getUTCDate()).toBe(NaN); }); diff --git a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getUTCDay.js b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getUTCDay.js index aec696be4a..63ab17c558 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getUTCDay.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getUTCDay.js @@ -4,4 +4,5 @@ test("basic functionality", () => { expect(d.getUTCDay()).not.toBeNaN(); expect(d.getUTCDay()).toBeGreaterThanOrEqual(0); expect(d.getUTCDay()).toBeLessThanOrEqual(6); + expect(new Date(NaN).getUTCDay()).toBe(NaN); }); diff --git a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getUTCFullYear.js b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getUTCFullYear.js index 50336d8178..733408c22b 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getUTCFullYear.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getUTCFullYear.js @@ -4,4 +4,5 @@ test("basic functionality", () => { expect(d.getUTCFullYear()).not.toBeNaN(); expect(d.getUTCFullYear()).toBe(d.getUTCFullYear()); expect(d.getUTCFullYear()).toBeGreaterThanOrEqual(2020); + expect(new Date(NaN).getUTCFullYear()).toBe(NaN); }); diff --git a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getUTCHours.js b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getUTCHours.js index 298ed178e5..9d9aa39942 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getUTCHours.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getUTCHours.js @@ -4,4 +4,5 @@ test("basic functionality", () => { expect(d.getUTCHours()).not.toBeNaN(); expect(d.getUTCHours()).toBeGreaterThanOrEqual(0); expect(d.getUTCHours()).toBeLessThanOrEqual(23); + expect(new Date(NaN).getUTCHours()).toBe(NaN); }); diff --git a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getUTCMilliseconds.js b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getUTCMilliseconds.js index f53ea70428..9abb0cc13a 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getUTCMilliseconds.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getUTCMilliseconds.js @@ -4,4 +4,5 @@ test("basic functionality", () => { expect(d.getUTCMilliseconds()).not.toBeNaN(); expect(d.getUTCMilliseconds()).toBeGreaterThanOrEqual(0); expect(d.getUTCMilliseconds()).toBeLessThanOrEqual(999); + expect(new Date(NaN).getUTCMilliseconds()).toBe(NaN); }); diff --git a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getUTCMinutes.js b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getUTCMinutes.js index 6b1146331c..d8a5a9b865 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getUTCMinutes.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getUTCMinutes.js @@ -4,4 +4,5 @@ test("basic functionality", () => { expect(d.getUTCMinutes()).not.toBeNaN(); expect(d.getUTCMinutes()).toBeGreaterThanOrEqual(0); expect(d.getUTCMinutes()).toBeLessThanOrEqual(59); + expect(new Date(NaN).getUTCMinutes()).toBe(NaN); }); diff --git a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getUTCMonth.js b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getUTCMonth.js index ed6ed64d97..48296f7084 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getUTCMonth.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getUTCMonth.js @@ -6,6 +6,7 @@ test("basic functionality", () => { expect(d.getUTCMonth()).toBeLessThanOrEqual(11); expect(new Date(Date.UTC(2020, 11)).getUTCMonth()).toBe(11); + expect(new Date(NaN).getUTCMonth()).toBe(NaN); }); test("leap years", () => { diff --git a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getUTCSeconds.js b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getUTCSeconds.js index d087a3c4c8..9a9f5d3e19 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getUTCSeconds.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.getUTCSeconds.js @@ -4,4 +4,5 @@ test("basic functionality", () => { expect(d.getUTCSeconds()).not.toBeNaN(); expect(d.getUTCSeconds()).toBeGreaterThanOrEqual(0); expect(d.getUTCSeconds()).toBeLessThanOrEqual(59); + expect(new Date(NaN).getUTCSeconds()).toBe(NaN); }); diff --git a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.setFullYear.js b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.setFullYear.js new file mode 100644 index 0000000000..a9a957b0db --- /dev/null +++ b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.setFullYear.js @@ -0,0 +1,112 @@ +test("no arguments", () => { + let date = new Date(2021, 0, 1); + date.setFullYear(); + expect(date.getTime()).toBe(NaN); +}); + +test("NaN or undefined as only argument", () => { + let date = new Date(2021, 0, 1); + date.setFullYear(NaN); + expect(date.getTime()).toBe(NaN); + + date = new Date(2021, 0, 1); + date.setFullYear(undefined); + expect(date.getTime()).toBe(NaN); + + date = new Date(2021, 0, 1); + date.setFullYear(""); + expect(date.getFullYear()).toBe(0); + + date = new Date(2021, 0, 1); + date.setFullYear("a"); + expect(date.getTime()).toBe(NaN); +}); + +test("Only year as argument", () => { + let date = new Date(2021, 0, 1); + + date.setFullYear(1992); + expect(date.getFullYear()).toBe(1992); + expect(date.getMonth()).toBe(0); + expect(date.getDate()).toBe(1); + expect(date.getHours()).toBe(0); + expect(date.getMinutes()).toBe(0); + expect(date.getSeconds()).toBe(0); + expect(date.getMilliseconds()).toBe(0); +}); + +test("Year and month as arguments", () => { + let date = new Date(2021, 0, 1); + + date.setFullYear(2021, 3); + expect(date.getFullYear()).toBe(2021); + expect(date.getMonth()).toBe(2); + expect(date.getDate()).toBe(1); + expect(date.getHours()).toBe(0); + expect(date.getMinutes()).toBe(0); + expect(date.getSeconds()).toBe(0); + expect(date.getMilliseconds()).toBe(0); +}); + +test("Year, month, and day as arguments", () => { + let date = new Date(2021, 0, 1); + + date.setFullYear(2021, 3, 16); + expect(date.getFullYear()).toBe(2021); + expect(date.getMonth()).toBe(2); + expect(date.getDate()).toBe(16); + expect(date.getHours()).toBe(0); + expect(date.getMinutes()).toBe(0); + expect(date.getSeconds()).toBe(0); + expect(date.getMilliseconds()).toBe(0); +}); + +test("NaN or undefined in any arguments", () => { + let date = new Date(2021, 0, 1); + date.setFullYear(NaN, 3, 16); + expect(date.getTime()).toBe(NaN); + + date = new Date(2021, 0, 1); + date.setFullYear(2021, NaN, 16); + expect(date.getTime()).toBe(NaN); + + date = new Date(2021, 0, 1); + date.setFullYear(2021, 3, NaN); + expect(date.getTime()).toBe(NaN); + + date = new Date(2021, 0, 1); + date.setFullYear(undefined, 3, 16); + expect(date.getTime()).toBe(NaN); + + date = new Date(2021, 0, 1); + date.setFullYear(2021, undefined, 16); + expect(date.getTime()).toBe(NaN); + + date = new Date(2021, 0, 1); + date.setFullYear(2021, 3, undefined); + expect(date.getTime()).toBe(NaN); + + date.setFullYear(2021, 3, 16); + expect(date.getFullYear()).toBe(2021); + expect(date.getMonth()).toBe(2); + expect(date.getDate()).toBe(16); + expect(date.getHours()).toBe(0); + expect(date.getMinutes()).toBe(0); + expect(date.getSeconds()).toBe(0); + expect(date.getMilliseconds()).toBe(0); +}); + +test("Make Invalid Date valid again", () => { + let date = new Date(2021, 0, 1); + date.setFullYear(NaN, 3, 16); + expect(date.getTime()).toBe(NaN); + + date.setFullYear(2021, 3, 16); + expect(date.getFullYear()).toBe(2021); + expect(date.getMonth()).toBe(2); + expect(date.getDate()).toBe(16); + expect(date.getHours()).toBe(0); + expect(date.getMinutes()).toBe(0); + expect(date.getSeconds()).toBe(0); + expect(date.getMilliseconds()).toBe(0); +}); diff --git a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.setHours.js b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.setHours.js index f85477aa23..78cee7e1cf 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.setHours.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.setHours.js @@ -18,4 +18,10 @@ test("basic functionality", () => { expect(d.getMinutes()).toBe(30); expect(d.getSeconds()).toBe(50); expect(d.getMilliseconds()).toBe(600); + + d.setHours(""); + expect(d.getHours()).toBe(0); + + d.setHours("a"); + expect(d.getHours()).toBe(NaN); }); diff --git a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.setMilliseconds.js b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.setMilliseconds.js index a750a35012..67b71cfcc7 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.setMilliseconds.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.setMilliseconds.js @@ -3,4 +3,10 @@ test("basic functionality", () => { d.setMilliseconds(600); expect(d.getMilliseconds()).toBe(600); + + d.setMilliseconds(""); + expect(d.getMilliseconds()).toBe(0); + + d.setMilliseconds("a"); + expect(d.getMilliseconds()).toBe(NaN); }); diff --git a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.setMinutes.js b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.setMinutes.js index 2c7232cbf9..d5243ecd08 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.setMinutes.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.setMinutes.js @@ -12,4 +12,10 @@ test("basic functionality", () => { expect(d.getMinutes()).toBe(30); expect(d.getSeconds()).toBe(50); expect(d.getMilliseconds()).toBe(600); + + d.setMinutes(""); + expect(d.getMinutes()).toBe(0); + + d.setMinutes("a"); + expect(d.getMinutes()).toBe(NaN); }); diff --git a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.setSeconds.js b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.setSeconds.js index 4fa5d39c30..06f7521a1e 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.setSeconds.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.setSeconds.js @@ -7,4 +7,10 @@ test("basic functionality", () => { d.setSeconds(50, 600); expect(d.getSeconds()).toBe(50); expect(d.getMilliseconds()).toBe(600); + + d.setSeconds(""); + expect(d.getSeconds()).toBe(0); + + d.setSeconds("a"); + expect(d.getSeconds()).toBe(NaN); }); diff --git a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.toISOString.js b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.toISOString.js index 2b380fc24d..eae4622796 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.toISOString.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Date/Date.prototype.toISOString.js @@ -4,4 +4,8 @@ test("basic functionality", () => { expect(new Date(Date.UTC(1950)).toISOString()).toBe("1950-01-01T00:00:00.000Z"); expect(new Date(Date.UTC(1800)).toISOString()).toBe("1800-01-01T00:00:00.000Z"); expect(new Date(Date.UTC(-100)).toISOString()).toBe("-000100-01-01T00:00:00.000Z"); + + expect(() => { + new Date(NaN).toISOString(); + }).toThrowWithMessage(RangeError, "Invalid time value"); }); |