From eb642473e368977f5690541067a5004f62809dcc Mon Sep 17 00:00:00 2001 From: Compey Date: Wed, 6 Sep 2023 13:17:36 +0530 Subject: [PATCH] chore(tests): updated test suite --- Cargo.lock | 6 +- src/lune/builtins/datetime/builder.rs | 93 ++++++++++----- src/lune/builtins/datetime/date_time.rs | 110 ++++++++++-------- src/tests.rs | 16 +-- tests/datetime/formatTime.luau | 41 +++++++ tests/datetime/formattime.luau | 16 --- .../{fromisodate.luau => fromIsoDate.luau} | 2 - tests/datetime/fromLocalTime.luau | 45 +++++++ ...versaltime.luau => fromUniversalTime.luau} | 0 ...xtimestamp.luau => fromUnixTimestamp.luau} | 0 tests/datetime/fromlocaltime.luau | 32 ----- .../{toisodate.luau => toIsoDate.luau} | 0 tests/datetime/toLocalTime.luau | 30 +++++ ...{tolocaltime.luau => toUniversalTime.luau} | 0 tests/datetime/touniversaltime.luau | 24 ---- 15 files changed, 250 insertions(+), 165 deletions(-) create mode 100644 tests/datetime/formatTime.luau delete mode 100644 tests/datetime/formattime.luau rename tests/datetime/{fromisodate.luau => fromIsoDate.luau} (84%) create mode 100644 tests/datetime/fromLocalTime.luau rename tests/datetime/{fromuniversaltime.luau => fromUniversalTime.luau} (100%) rename tests/datetime/{fromunixtimestamp.luau => fromUnixTimestamp.luau} (100%) delete mode 100644 tests/datetime/fromlocaltime.luau rename tests/datetime/{toisodate.luau => toIsoDate.luau} (100%) create mode 100644 tests/datetime/toLocalTime.luau rename tests/datetime/{tolocaltime.luau => toUniversalTime.luau} (100%) delete mode 100644 tests/datetime/touniversaltime.luau diff --git a/Cargo.lock b/Cargo.lock index f5129c7..5ddb87e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -310,9 +310,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.26" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5" +checksum = "95ed24df0632f708f5f6d8082675bef2596f7084dee3dd55f632290bf35bfe0f" dependencies = [ "android-tzdata", "iana-time-zone", @@ -320,7 +320,7 @@ dependencies = [ "num-traits", "time 0.1.45", "wasm-bindgen", - "winapi", + "windows-targets 0.48.5", ] [[package]] diff --git a/src/lune/builtins/datetime/builder.rs b/src/lune/builtins/datetime/builder.rs index 15165c3..20f7e73 100644 --- a/src/lune/builtins/datetime/builder.rs +++ b/src/lune/builtins/datetime/builder.rs @@ -2,7 +2,7 @@ use crate::lune::builtins::datetime::date_time::Timezone; use chrono::prelude::*; use chrono_locale::LocaleDate; -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub struct DateTimeBuilder { /// The year. In the range 1400 - 9999. pub year: i32, @@ -98,7 +98,7 @@ impl DateTimeBuilder { { let format = match format { Some(fmt) => fmt.to_string(), - None => "%Y-%m-%dT%H:%M:%SZ".to_string(), + None => "%Y-%m-%dT%H:%M:%SZUTC+%z".to_string(), }; let locale = match locale { @@ -106,34 +106,69 @@ impl DateTimeBuilder { None => "en".to_string(), }; + let time = Utc + .with_ymd_and_hms( + self.year, + self.month, + self.day, + self.hour, + self.minute, + self.second, + ) + .single() + .ok_or(())?; + + // dbg!( + // "{}", + // match timezone { + // Timezone::Utc => time.to_rfc3339(), //.formatl((format).as_str(), locale.as_str()), + // Timezone::Local => time.with_timezone(&Local).to_rfc3339(), // .formatl((format).as_str(), locale.as_str()), + // } + // ); + Ok(match timezone { - Timezone::Utc => Utc - .with_ymd_and_hms( - self.year, - self.month, - self.day, - self.hour, - self.minute, - self.second, - ) - .single() - .ok_or(())? - .formatl((format).as_str(), locale.as_str()) - .to_string(), - Timezone::Local => Local - .with_ymd_and_hms( - self.year, - self.month, - self.day, - self.hour, - self.minute, - self.second, - ) - .single() - .ok_or(())? - .formatl((format).as_str(), locale.as_str()) - .to_string(), - }) + Timezone::Utc => time.formatl((format).as_str(), locale.as_str()), + Timezone::Local => time + .with_timezone(&Local) + .formatl((format).as_str(), locale.as_str()), + } + .to_string()) + + // .formatl((format).as_str(), locale.as_str()) + // .to_string()) + + // Ok(match timezone { + // Timezone::Utc => Utc + // .with_ymd_and_hms( + // self.year, + // self.month, + // self.day, + // self.hour, + // self.minute, + // self.second, + // ) + // .single() + // .ok_or(())? + // .with_timezone(&match timezone { + // Timezone::Utc => Utc, + // Timezone::Local => Local + // }) + // .formatl((format).as_str(), locale.as_str()) + // .to_string(), + // Timezone::Local => Local + // .with_ymd_and_hms( + // self.year, + // self.month, + // self.day, + // self.hour, + // self.minute, + // self.second, + // ) + // .single() + // .ok_or(())? + // .formatl((format).as_str(), locale.as_str()) + // .to_string(), + // }) } pub fn build(self) -> Self { diff --git a/src/lune/builtins/datetime/date_time.rs b/src/lune/builtins/datetime/date_time.rs index 7d6bab4..8f7d7ad 100644 --- a/src/lune/builtins/datetime/date_time.rs +++ b/src/lune/builtins/datetime/date_time.rs @@ -9,6 +9,7 @@ pub enum TimestampType { } /// General timezone types accepted by `DateTime` methods. +#[derive(Eq, PartialEq)] pub enum Timezone { Utc, Local, @@ -67,30 +68,28 @@ impl DateTime { /// - Non-integer values are rounded down. For example, providing 2.5 hours will be equivalent to providing 2 hours, not 2 hours 30 minutes. /// - Omitted values are assumed to be their lowest value in their normal range, except for year which defaults to 1970. pub fn from_universal_time(date_time: Option) -> Result { - if let Some(date_time) = date_time { - let utc_time: ChronoDateTime = Utc.from_utc_datetime(&NaiveDateTime::new( - NaiveDate::from_ymd_opt(date_time.year, date_time.month, date_time.day).ok_or(())?, - NaiveTime::from_hms_milli_opt( - date_time.hour, - date_time.minute, - date_time.second, - date_time.millisecond, - ) - .ok_or(())?, - )); + Ok(match date_time { + Some(date_time) => { + let utc_time: ChronoDateTime = Utc.from_utc_datetime(&NaiveDateTime::new( + NaiveDate::from_ymd_opt(date_time.year, date_time.month, date_time.day) + .ok_or(())?, + NaiveTime::from_hms_milli_opt( + date_time.hour, + date_time.minute, + date_time.second, + date_time.millisecond, + ) + .ok_or(())?, + )); - Ok(Self { - unix_timestamp: utc_time.timestamp(), - unix_timestamp_millis: utc_time.timestamp_millis(), - }) - } else { - let utc_time = Utc::now(); + Self { + unix_timestamp: utc_time.timestamp(), + unix_timestamp_millis: utc_time.timestamp_millis(), + } + } - Ok(Self { - unix_timestamp: utc_time.timestamp(), - unix_timestamp_millis: utc_time.timestamp_millis(), - }) - } + None => Self::now(), + }) } /// Returns a new `DateTime` using the given units from a local time. The @@ -102,34 +101,38 @@ impl DateTime { /// - Non-integer values are rounded down. For example, providing 2.5 hours will be equivalent to providing 2 hours, not 2 hours 30 minutes. /// - Omitted values are assumed to be their lowest value in their normal range, except for year which defaults to 1970. pub fn from_local_time(date_time: Option) -> Result { - if let Some(date_time) = date_time { - let local_time: ChronoDateTime = Local - .from_local_datetime(&NaiveDateTime::new( - NaiveDate::from_ymd_opt(date_time.year, date_time.month, date_time.day) + Ok(match date_time { + Some(date_time) => { + let local_time: ChronoDateTime = Local + .from_local_datetime(&NaiveDateTime::new( + NaiveDate::from_ymd_opt(date_time.year, date_time.month, date_time.day) + .ok_or(())?, + NaiveTime::from_hms_milli_opt( + date_time.hour, + date_time.minute, + date_time.second, + date_time.millisecond, + ) .ok_or(())?, - NaiveTime::from_hms_milli_opt( - date_time.hour, - date_time.minute, - date_time.second, - date_time.millisecond, - ) - .ok_or(())?, - )) - .single() - .ok_or(())?; + )) + .single() + .ok_or(())?; - Ok(Self { - unix_timestamp: local_time.timestamp(), - unix_timestamp_millis: local_time.timestamp_millis(), - }) - } else { - let local_time = Local::now(); + Self { + unix_timestamp: local_time.timestamp(), + unix_timestamp_millis: local_time.timestamp_millis(), + } + } - Ok(Self { - unix_timestamp: local_time.timestamp(), - unix_timestamp_millis: local_time.timestamp_millis(), - }) - } + None => { + let local_time = Local::now(); + + Self { + unix_timestamp: local_time.timestamp(), + unix_timestamp_millis: local_time.timestamp_millis(), + } + } + }) } /// Returns a `DateTime` from an ISO 8601 date-time string in UTC @@ -168,6 +171,7 @@ impl DateTime { // Any less tedious way to get Enum member based on index? // I know there's some crates available with derive macros for this, // would it be okay if used some of them? + date_time_constructor .with_year(date_time.year()) .with_month(match date_time.month() { @@ -199,12 +203,12 @@ impl DateTime { /// description. The values within this table could be passed to `from_local_time` /// to produce the original `DateTime` object. pub fn to_local_time(&self) -> Result { - Ok(Self::to_datetime_builder( + Self::to_datetime_builder( Local .timestamp_opt(self.unix_timestamp, 0) .single() .ok_or(())?, - )?) + ) } /// Converts the value of this `DateTime` object to Universal Coordinated Time (UTC). @@ -213,11 +217,15 @@ impl DateTime { /// in this data type's description. The values within this table could be passed /// to `from_universal_time` to produce the original `DateTime` object. pub fn to_universal_time(&self) -> Result { - Ok(Self::to_datetime_builder( + Self::to_datetime_builder( Utc.timestamp_opt(self.unix_timestamp, 0) .single() .ok_or(())?, - )?) + ) + + // dbg!("{:#?}", m?); + + // m } /// Formats a date as a ISO 8601 date-time string, returns None if the DateTime object is invalid. diff --git a/src/tests.rs b/src/tests.rs index 8736139..ba6e718 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -108,14 +108,14 @@ create_tests! { task_wait: "task/wait", datetime_now: "datetime/now", - datetime_fromunixtimestamp: "datetime/fromunixtimestamp", - datetime_fromuniversaltime: "datetime/fromuniversaltime", - datetime_touniversaltime: "datetime/touniversaltime", - datetime_fromlocaltime: "datetime/fromlocaltime", - datetime_tolocaltime: "datetime/tolocaltime", - datetime_fromisodate: "datetime/fromisodate", - datetime_toisodate: "datetime/toisodate", - datetime_formattime: "datetime/formattime", + datetime_from_unix_timestamp: "datetime/fromUnixTimestamp", + datetime_from_universal_time: "datetime/fromUniversalTime", + datetime_to_universal_time: "datetime/toUniversalTime", + datetime_from_local_time: "datetime/fromLocalTime", + datetime_to_local_time: "datetime/toLocalTime", + datetime_from_iso_date: "datetime/fromIsoDate", + datetime_to_iso_date: "datetime/toIsoDate", + datetime_format_time: "datetime/formatTime", } #[cfg(feature = "roblox")] diff --git a/tests/datetime/formatTime.luau b/tests/datetime/formatTime.luau new file mode 100644 index 0000000..39afc9a --- /dev/null +++ b/tests/datetime/formatTime.luau @@ -0,0 +1,41 @@ +local DateTime = require("@lune/datetime") + +-- UTC Timezone +assert( + DateTime.fromUnixTimestamp(1693068988):formatTime("utc", "%Y-%m-%dT%H:%M:%SZ", "en") + == "2023-08-26T16:56:28Z", + "invalid ISO 8601 formatting for DateTime.formatTime() (UTC)" +) + +assert( + DateTime.fromUnixTimestamp(1693068988):formatTime("utc", "%A, %d %B %Y", "fr") + == "samedi, 26 août 2023", + "expected format specifier '%A, %d %B %Y' to return 'samedi, 26 août 2023' for locale 'fr'" +) + +-- FIXME: Local timezone formatTime fails due to a rust side bug + +local expectedTimeString = os.date("%Y-%m-%dT%H:%M:%SZ%z", 1693932753) + +-- NOTE: UTC Timezone conversions work perfectly fine, issue only for local. +-- So far I've made it so that format_time always converts to_universal_time +-- Builder object. Then in to_string, we construct a ChronoDateTime from the values +-- and convert it to the requested timezone. We then format this with our formatter +-- string. + +-- For debugging, try checking what to_universal_time returns, maybe that's where +-- an incorrect DateTimeBuilder is getting returned... If that's the case, that means +-- there probably isn't any issue with to_string at all. + +-- Yes, an invalid DateTimeBuilder is being returned turns out. Still don't know why actually. + +print( + expectedTimeString, + DateTime.fromUnixTimestamp(1693068988):formatTime("local", "%Y-%m-%dT%H:%M:%SZ", "en") +) + +assert( + DateTime.fromUnixTimestamp(1693068988):formatTime("local", "%Y-%m-%dT%H:%M:%SZ", "en") + == expectedTimeString, + "invalid ISO 8601 formatting for DateTime.formatTime() (local)" +) diff --git a/tests/datetime/formattime.luau b/tests/datetime/formattime.luau deleted file mode 100644 index e16238b..0000000 --- a/tests/datetime/formattime.luau +++ /dev/null @@ -1,16 +0,0 @@ -local DateTime = require("@lune/datetime") - --- UTC Timezone -assert( - DateTime.fromUnixTimestamp(1693068988):formatTime("utc", "%Y-%m-%dT%H:%M:%SZ", "en") - == "2023-08-26T16:56:28Z", - "invalid ISO 8601 formatting for DateTime.formatTime()" -) - -assert( - DateTime.fromUnixTimestamp(1693068988):formatTime("utc", "%A, %d %B %Y", "fr") - == "samedi, 26 août 2023", - "expected format specifier '%A, %d %B %Y' to return 'samedi, 26 août 2023' for locale 'fr'" -) - --- TODO: local timezone tests diff --git a/tests/datetime/fromisodate.luau b/tests/datetime/fromIsoDate.luau similarity index 84% rename from tests/datetime/fromisodate.luau rename to tests/datetime/fromIsoDate.luau index f986827..618dc4b 100644 --- a/tests/datetime/fromisodate.luau +++ b/tests/datetime/fromIsoDate.luau @@ -1,7 +1,5 @@ local DateTime = require("@lune/datetime") --- Fails due to issue with rust side implementation - assert( DateTime.fromIsoDate("2023-08-26T16:56:28Z") ~= nil, "expected DateTime.fromIsoDate() to return DateTime, got nil" diff --git a/tests/datetime/fromLocalTime.luau b/tests/datetime/fromLocalTime.luau new file mode 100644 index 0000000..b1b1457 --- /dev/null +++ b/tests/datetime/fromLocalTime.luau @@ -0,0 +1,45 @@ +local DateTime = require("@lune/datetime") +assert( + DateTime.fromLocalTime()["unixTimestamp"] == os.time(), + "expected DateTime.fromLocalTime() with no args to return DateTime at current moment" +) + +local timeValues1 = os.date("*t", 1693049188) + +assert( + DateTime.fromLocalTime({ + ["year"] = timeValues1.year, + ["month"] = timeValues1.month, + ["day"] = timeValues1.day, + ["hour"] = timeValues1.hour, + ["minute"] = timeValues1.min, + ["second"] = timeValues1.sec, + ["millisecond"] = 0, + })["unixTimestamp"] == 1693049188, + "expected DateTime.fromLocalTime() with DateTimeValues arg to return 1693049188s" +) + +print(DateTime.fromLocalTime({ + ["year"] = 2023, + ["month"] = "aug", + ["day"] = 26, + ["hour"] = 16, + ["minute"] = 56, + ["second"] = 28, + ["millisecond"] = 892, +})["unixTimestamp"]) + +local timeValues2 = os.date("*t", 1693049188.892) + +assert( + DateTime.fromLocalTime({ + ["year"] = timeValues2.year, + ["month"] = timeValues2.month, + ["day"] = timeValues2.day, + ["hour"] = timeValues2.hour, + ["minute"] = timeValues2.min, + ["second"] = timeValues2.sec, + ["millisecond"] = 892, + })["unixTimestampMillis"] == 1693049188892, + "expected DateTime.fromLocalTime() with DateTimeValues arg with millis to return 1693049188892ms" +) diff --git a/tests/datetime/fromuniversaltime.luau b/tests/datetime/fromUniversalTime.luau similarity index 100% rename from tests/datetime/fromuniversaltime.luau rename to tests/datetime/fromUniversalTime.luau diff --git a/tests/datetime/fromunixtimestamp.luau b/tests/datetime/fromUnixTimestamp.luau similarity index 100% rename from tests/datetime/fromunixtimestamp.luau rename to tests/datetime/fromUnixTimestamp.luau diff --git a/tests/datetime/fromlocaltime.luau b/tests/datetime/fromlocaltime.luau deleted file mode 100644 index 0260cfd..0000000 --- a/tests/datetime/fromlocaltime.luau +++ /dev/null @@ -1,32 +0,0 @@ -local DateTime = require("@lune/datetime") - -assert( - DateTime.fromLocalTime()["unixTimestamp"] == os.time(), - "expected DateTime.fromLocalTime() with no args to return DateTime at current moment" -) - -assert( - DateTime.fromLocalTime({ - ["year"] = 2023, - ["month"] = "aug", - ["day"] = 26, - ["hour"] = 16, - ["minute"] = 56, - ["second"] = 28, - ["millisecond"] = 0, - })["unixTimestamp"] == 1693049188, - "expected DateTime.fromLocalTime() with DateTimeValues arg to return 1693049188s" -) - -assert( - DateTime.fromLocalTime({ - ["year"] = 2023, - ["month"] = "aug", - ["day"] = 26, - ["hour"] = 16, - ["minute"] = 56, - ["second"] = 28, - ["millisecond"] = 892, - })["unixTimestampMillis"] == 1693049188892, - "expected DateTime.fromLocalTime() with DateTimeValues arg with millis to return 1693049188892ms" -) diff --git a/tests/datetime/toisodate.luau b/tests/datetime/toIsoDate.luau similarity index 100% rename from tests/datetime/toisodate.luau rename to tests/datetime/toIsoDate.luau diff --git a/tests/datetime/toLocalTime.luau b/tests/datetime/toLocalTime.luau new file mode 100644 index 0000000..98e1e53 --- /dev/null +++ b/tests/datetime/toLocalTime.luau @@ -0,0 +1,30 @@ +local DateTime = require("@lune/datetime") + +local dateTime = (DateTime.fromIsoDate("2023-08-27T05:54:19Z") :: DateTime.DateTime):toLocalTime() + +local expectedDateTimeValues = os.date("*t", 1693115659) + +assert( + dateTime.year == expectedDateTimeValues.year, + `expected {dateTime.year} == {expectedDateTimeValues.year}` +) +assert( + dateTime.month == expectedDateTimeValues.month, + `expected {dateTime.month} == {expectedDateTimeValues.month}` +) +assert( + dateTime.day == expectedDateTimeValues.day, + `expected {dateTime.day} == {expectedDateTimeValues.day}` +) +assert( + dateTime.hour == expectedDateTimeValues.hour, + `expected {dateTime.hour} == {expectedDateTimeValues.hour}` +) +assert( + dateTime.minute == expectedDateTimeValues.min, + `expected {dateTime.minute} == {expectedDateTimeValues.min}` +) +assert( + dateTime.second == expectedDateTimeValues.sec, + `expected {dateTime.second} == {expectedDateTimeValues.sec}` +) diff --git a/tests/datetime/tolocaltime.luau b/tests/datetime/toUniversalTime.luau similarity index 100% rename from tests/datetime/tolocaltime.luau rename to tests/datetime/toUniversalTime.luau diff --git a/tests/datetime/touniversaltime.luau b/tests/datetime/touniversaltime.luau deleted file mode 100644 index 6792db9..0000000 --- a/tests/datetime/touniversaltime.luau +++ /dev/null @@ -1,24 +0,0 @@ -local DateTime = require("@lune/datetime") - -local dateTime = (DateTime.fromIsoDate("2023-08-27T05:54:19Z") :: DateTime.DateTime):toLocalTime() - -local expectedDateTimeValues = table.pack( - string.match( - "2023-08-27T11:24:19Z", - "(%d%d%d%d)-?(%d?%d?)-?(%d?%d?)T(%d?%d?):(%d?%d?):(%d?%d?)Z$" - ) -) - -local expectedYear = tonumber(expectedDateTimeValues[1]) -local expectedMonth = tonumber(expectedDateTimeValues[2]) -local expectedDay = tonumber(expectedDateTimeValues[3]) -local expectedHour = tonumber(expectedDateTimeValues[4]) -local expectedMinute = tonumber(expectedDateTimeValues[5]) -local expectedSecond = tonumber(expectedDateTimeValues[6]) - -assert(dateTime.year == expectedYear, `expected {dateTime.year} == {expectedYear}`) -assert(dateTime.month == expectedMonth, `expected {dateTime.month} == {expectedMonth}`) -assert(dateTime.day == expectedDay, `expected {dateTime.day} == {expectedDay}`) -assert(dateTime.hour == expectedHour, `expected {dateTime.hour} == {expectedHour}`) -assert(dateTime.minute == expectedMinute, `expected {dateTime.minute} == {expectedMinute}`) -assert(dateTime.second == expectedSecond, `expected {dateTime.second} == {expectedSecond}`)