From 11c22d1b549ceb13bb40df760bd64872d4303c74 Mon Sep 17 00:00:00 2001 From: Chloe Kudryavtsev Date: Wed, 31 May 2023 00:26:46 +0200 Subject: get better more/thorough tests for the native wrapper --- src/tm.c | 1 + test/01-native.janet | 55 +++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 43 insertions(+), 13 deletions(-) diff --git a/src/tm.c b/src/tm.c index 9385190..a88ac36 100644 --- a/src/tm.c +++ b/src/tm.c @@ -11,6 +11,7 @@ static JanetMethod jd_tm_methods[] = { {NULL, NULL}, }; +// WARNING: this only works if they're BOTH localtime or gmtime static int jd_tm_compare(void *lhs, void *rhs) { struct tm lhp = (*(struct tm*)lhs); struct tm rhp = (*(struct tm*)rhs); diff --git a/test/01-native.janet b/test/01-native.janet index ac04364..972e55e 100644 --- a/test/01-native.janet +++ b/test/01-native.janet @@ -1,14 +1,15 @@ (use date/native) -(defn platform [& ps] (some (partial = (os/which)) ps)) - # you generally start with this # `time` returns the time in UTC +# note that it's an *opaque* type +# you should not try to interpret it except with comparisons (def now (time)) # you can convert a `time` object into a `tm` object which represents a date # using :localtime or :gmtime, where gmtime interprets the time as UTC (def loc (:localtime now)) +(def gmt (:gmtime now)) # you can modify `tm` objects like an associative array # this means that put, update, keys, values, etc all work @@ -18,22 +19,50 @@ # if the second count was at 0, it would now be at -1, which is out of range # that's not a problem though, you can actually already perform comparisons +# WARN: you can ONLY compare `tm` objects of the same type (localtime vs gmtime) (assert (< loc* loc)) -# :localtime, :localtime!, :gmtime, :gmtime!, :mktime, and :mktime! -# all "renormalize" the object +# :mktime, and :mktime! "renormalize" the object # :mktime returns a `time` object # :mktime! does that, and normalizes the `tm` object in place by mutating it -(assert (= (:mktime loc) now)) +(assert (= (:mktime loc) now)) (assert (< (:mktime loc*) now)) -# :gmtime(!) is equivalent to (:gmtime (:mktime(!) tm)), ditto for localtime -(def loc* (:localtime! loc*)) -(assert (< loc* loc)) +# you must not call :mktime or :mktime! on the output of a :gmtime +# the data *will* be wrong, as mktime (as per the spec) presumes :localtime +(assert (not= (:mktime gmt) now)) + +# as such, the correct approach is to keep things in `time` format as much as +# possible, only converting to :localtime or :gmtime for mutation and formatting +# this is roughly what the janet wrapper does +(defn- put-date + [ds key val] + (when val # allow null val for update-time + (if (function? val) + (update ds key val) + (put ds key val)))) +(defn update-time + [time &keys {:sec seconds + :min minutes + :hour hours + :mday month-day + :mon month + :year year}] + (assert (= (type time) :date/time)) + (let [l (:localtime time) + p (partial put-date l)] + (p :sec seconds) + (p :min minutes) + (p :hour hours) + (p :mday month-day) + (p :mon month) + (p :year year) + (:mktime! l))) # mktime! is slightly more efficient and we're going to GC l anyway -# macos has a bug in its libc that makes it misinterpret gmtime outputs -# as localtime under certain conditions, so the gmtime tests are skipped -# TODO: UTC tests -(unless (platform :macos)) +# all supported keys can be given a function +(assert (< now (update-time now :sec inc))) +(assert (> now (update-time now :sec dec))) -# TODO: building a UTC datetime +# or a value to set them to +(assert (< now (update-time now :sec 61))) +(assert (> now (update-time now :sec -1))) -- cgit v1.2.3