mirror of
https://github.com/sbrow/thor.git
synced 2026-08-26 11:23:32 -04:00
75a7d7a14b
The configured timezone (or local) is now set on Site directly.
295 lines
9.5 KiB
Odin
295 lines
9.5 KiB
Odin
#+test
|
|
package mustache
|
|
|
|
import "core:testing"
|
|
import "core:time/timezone"
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// parse_iso_date
|
|
// ---------------------------------------------------------------------------
|
|
|
|
@(test)
|
|
test_parse_iso_date_extracts_time :: proc(t: ^testing.T) {
|
|
c, ok := parse_iso_date("2026-03-15T08:49:54-04:00")
|
|
testing.expect(t, ok, "should parse")
|
|
testing.expect_value(t, c.year, 2026)
|
|
testing.expect_value(t, c.month, 3)
|
|
testing.expect_value(t, c.day, 15)
|
|
testing.expect_value(t, c.hour, 8)
|
|
testing.expect_value(t, c.minute, 49)
|
|
testing.expect_value(t, c.second, 54)
|
|
testing.expect_value(t, c.has_offset, true)
|
|
testing.expect_value(t, c.offset_seconds, -14400)
|
|
testing.expect_value(t, c.tz_abbr, "UTC")
|
|
}
|
|
|
|
@(test)
|
|
test_parse_iso_date_lowercase_t :: proc(t: ^testing.T) {
|
|
c, ok := parse_iso_date("2026-03-15t08:49:54Z")
|
|
testing.expect(t, ok, "should parse lowercase t separator")
|
|
testing.expect_value(t, c.hour, 8)
|
|
testing.expect_value(t, c.minute, 49)
|
|
testing.expect_value(t, c.second, 54)
|
|
testing.expect_value(t, c.has_offset, true)
|
|
testing.expect_value(t, c.offset_seconds, 0)
|
|
}
|
|
|
|
@(test)
|
|
test_parse_iso_date_date_only_zero_time :: proc(t: ^testing.T) {
|
|
c, ok := parse_iso_date("2026-03-15")
|
|
testing.expect(t, ok, "should parse date-only")
|
|
testing.expect_value(t, c.hour, 0)
|
|
testing.expect_value(t, c.minute, 0)
|
|
testing.expect_value(t, c.second, 0)
|
|
testing.expect_value(t, c.has_offset, false)
|
|
}
|
|
|
|
@(test)
|
|
test_parse_iso_date_invalid_day_errors :: proc(t: ^testing.T) {
|
|
_, ok := parse_iso_date("2026-03-32")
|
|
testing.expect(t, !ok, "day > 31 should fail")
|
|
}
|
|
|
|
@(test)
|
|
test_parse_iso_date_too_short_errors :: proc(t: ^testing.T) {
|
|
_, ok := parse_iso_date("2026-03")
|
|
testing.expect(t, !ok, "input shorter than 10 chars should fail")
|
|
}
|
|
|
|
@(test)
|
|
test_parse_offset_positive_colon :: proc(t: ^testing.T) {
|
|
c, ok := parse_iso_date("2026-03-15T08:49:54+07:00")
|
|
testing.expect(t, ok, "should parse")
|
|
testing.expect_value(t, c.has_offset, true)
|
|
testing.expect_value(t, c.offset_seconds, 25200)
|
|
}
|
|
|
|
@(test)
|
|
test_parse_offset_positive_no_colon :: proc(t: ^testing.T) {
|
|
c, ok := parse_iso_date("2026-03-15T08:49:54+0530")
|
|
testing.expect(t, ok, "should parse")
|
|
testing.expect_value(t, c.has_offset, true)
|
|
testing.expect_value(t, c.offset_seconds, 19800)
|
|
}
|
|
|
|
@(test)
|
|
test_parse_offset_hours_only :: proc(t: ^testing.T) {
|
|
c, ok := parse_iso_date("2026-03-15T08:49:54+05")
|
|
testing.expect(t, ok, "should parse")
|
|
testing.expect_value(t, c.has_offset, true)
|
|
testing.expect_value(t, c.offset_seconds, 18000)
|
|
}
|
|
|
|
@(test)
|
|
test_parse_offset_none_with_time :: proc(t: ^testing.T) {
|
|
c, ok := parse_iso_date("2026-03-15T08:49:54")
|
|
testing.expect(t, ok, "should parse")
|
|
testing.expect_value(t, c.has_offset, false)
|
|
testing.expect_value(t, c.offset_seconds, 0)
|
|
}
|
|
|
|
@(test)
|
|
test_parse_offset_skips_fractional_seconds :: proc(t: ^testing.T) {
|
|
c, ok := parse_iso_date("2026-03-15T08:49:54.123Z")
|
|
testing.expect(t, ok, "should parse")
|
|
testing.expect_value(t, c.has_offset, true)
|
|
testing.expect_value(t, c.offset_seconds, 0)
|
|
testing.expect_value(t, c.second, 54)
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// format_date / match_token
|
|
// ---------------------------------------------------------------------------
|
|
|
|
@(test)
|
|
test_format_date_weekday_full :: proc(t: ^testing.T) {
|
|
// 2026-01-01 is a Thursday.
|
|
dt := Date_Components{year = 2026, month = 1, day = 1}
|
|
result := format_date(dt, "Monday")
|
|
testing.expect_value(t, result, "Thursday")
|
|
}
|
|
|
|
@(test)
|
|
test_format_date_weekday_abbr :: proc(t: ^testing.T) {
|
|
dt := Date_Components{year = 2026, month = 1, day = 1}
|
|
result := format_date(dt, "Mon")
|
|
testing.expect_value(t, result, "Thu")
|
|
}
|
|
|
|
@(test)
|
|
test_format_date_month_full_name :: proc(t: ^testing.T) {
|
|
dt := Date_Components{year = 2026, month = 3, day = 15}
|
|
result := format_date(dt, "January")
|
|
testing.expect_value(t, result, "March")
|
|
}
|
|
|
|
@(test)
|
|
test_format_date_two_digit_year :: proc(t: ^testing.T) {
|
|
dt := Date_Components{year = 2026, month = 3, day = 15}
|
|
result := format_date(dt, "06")
|
|
testing.expect_value(t, result, "26")
|
|
}
|
|
|
|
@(test)
|
|
test_format_date_hour24_padded :: proc(t: ^testing.T) {
|
|
midnight := Date_Components{year = 2026, month = 1, day = 1, hour = 0}
|
|
testing.expect_value(t, format_date(midnight, "15"), "00")
|
|
|
|
afternoon := Date_Components{year = 2026, month = 1, day = 1, hour = 13}
|
|
testing.expect_value(t, format_date(afternoon, "15"), "13")
|
|
}
|
|
|
|
@(test)
|
|
test_format_date_hour12_padded_am_pm_boundaries :: proc(t: ^testing.T) {
|
|
cases := [4]struct {
|
|
hour: int,
|
|
expected: string,
|
|
}{{0, "12 AM"}, {12, "12 PM"}, {13, "01 PM"}, {23, "11 PM"}}
|
|
|
|
for &c in cases {
|
|
dt := Date_Components{year = 2026, month = 1, day = 1, hour = c.hour}
|
|
result := format_date(dt, "03 PM")
|
|
testing.expect_value(t, result, c.expected)
|
|
}
|
|
}
|
|
|
|
@(test)
|
|
test_format_date_hour12_unpadded :: proc(t: ^testing.T) {
|
|
one_am := Date_Components{year = 2026, month = 1, day = 1, hour = 1}
|
|
testing.expect_value(t, format_date(one_am, "3"), "1")
|
|
|
|
one_pm := Date_Components{year = 2026, month = 1, day = 1, hour = 13}
|
|
testing.expect_value(t, format_date(one_pm, "3"), "1")
|
|
}
|
|
|
|
@(test)
|
|
test_format_date_am_pm_lowercase :: proc(t: ^testing.T) {
|
|
afternoon := Date_Components{year = 2026, month = 1, day = 1, hour = 13}
|
|
testing.expect_value(t, format_date(afternoon, "pm"), "pm")
|
|
|
|
morning := Date_Components{year = 2026, month = 1, day = 1, hour = 9}
|
|
testing.expect_value(t, format_date(morning, "pm"), "am")
|
|
}
|
|
|
|
@(test)
|
|
test_format_date_minute_second_padding :: proc(t: ^testing.T) {
|
|
dt := Date_Components{year = 2026, month = 1, day = 1, minute = 4, second = 5}
|
|
testing.expect_value(t, format_date(dt, "04:05"), "04:05")
|
|
testing.expect_value(t, format_date(dt, "4:5"), "4:5")
|
|
}
|
|
|
|
@(test)
|
|
test_format_date_month_day_numeric_padding :: proc(t: ^testing.T) {
|
|
dt := Date_Components{year = 2026, month = 3, day = 5}
|
|
testing.expect_value(t, format_date(dt, "01"), "03")
|
|
testing.expect_value(t, format_date(dt, "1"), "3")
|
|
testing.expect_value(t, format_date(dt, "02"), "05")
|
|
testing.expect_value(t, format_date(dt, "2"), "5")
|
|
}
|
|
|
|
@(test)
|
|
test_format_date_mst_defaults_utc :: proc(t: ^testing.T) {
|
|
// Date_Components constructed directly (not via parse_iso_date)
|
|
// defaults to UTC for the MST token.
|
|
dt := Date_Components{year = 2026, month = 1, day = 1, hour = 12}
|
|
result := format_date(dt, "MST")
|
|
testing.expect_value(t, result, "UTC")
|
|
}
|
|
|
|
@(test)
|
|
test_format_date_literal_passthrough :: proc(t: ^testing.T) {
|
|
dt := Date_Components{year = 2026, month = 1, day = 1}
|
|
result := format_date(dt, "Year: 2006!")
|
|
testing.expect_value(t, result, "Year: 2026!")
|
|
}
|
|
|
|
@(test)
|
|
test_format_date_combined_go_reference_layout :: proc(t: ^testing.T) {
|
|
// 2023-10-15 is a Sunday.
|
|
dt := Date_Components{year = 2023, month = 10, day = 15, hour = 13, minute = 18, second = 50}
|
|
result := format_date(dt, "Mon Jan 2 15:04:05 MST 2006")
|
|
testing.expect_value(t, result, "Sun Oct 15 13:18:50 UTC 2023")
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// format_offset
|
|
// ---------------------------------------------------------------------------
|
|
|
|
@(test)
|
|
test_format_offset_zero :: proc(t: ^testing.T) {
|
|
testing.expect_value(t, format_offset(0), "UTC")
|
|
}
|
|
|
|
@(test)
|
|
test_format_offset_negative :: proc(t: ^testing.T) {
|
|
testing.expect_value(t, format_offset(-14400), "UTC-04:00")
|
|
}
|
|
|
|
@(test)
|
|
test_format_offset_positive :: proc(t: ^testing.T) {
|
|
testing.expect_value(t, format_offset(19800), "UTC+05:30")
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// convert_to_tz (require system zoneinfo)
|
|
// ---------------------------------------------------------------------------
|
|
|
|
@(test)
|
|
test_convert_to_tz_no_offset_assumes_target :: proc(t: ^testing.T) {
|
|
tz, tz_ok := timezone.region_load("America/New_York", context.temp_allocator)
|
|
testing.expect(t, tz_ok, "should load timezone")
|
|
if !tz_ok do return
|
|
defer timezone.region_destroy(tz, context.temp_allocator)
|
|
|
|
c := Date_Components{
|
|
year = 2026, month = 3, day = 15,
|
|
hour = 8, minute = 49, second = 54,
|
|
}
|
|
result, ok := convert_to_tz(c, tz)
|
|
testing.expect_value(t, ok, true)
|
|
testing.expect_value(t, result.hour, 8)
|
|
testing.expect_value(t, result.minute, 49)
|
|
testing.expect(t, len(result.tz_abbr) > 0, "should resolve abbreviation")
|
|
}
|
|
|
|
@(test)
|
|
test_convert_to_tz_with_offset_converts :: proc(t: ^testing.T) {
|
|
tz, tz_ok := timezone.region_load("America/New_York", context.temp_allocator)
|
|
testing.expect(t, tz_ok, "should load timezone")
|
|
if !tz_ok do return
|
|
defer timezone.region_destroy(tz, context.temp_allocator)
|
|
|
|
// 2026-03-15T12:49:54Z (UTC) → 08:49:54 EDT (UTC-4)
|
|
c := Date_Components{
|
|
year = 2026, month = 3, day = 15,
|
|
hour = 12, minute = 49, second = 54,
|
|
offset_seconds = 0,
|
|
has_offset = true,
|
|
}
|
|
result, ok := convert_to_tz(c, tz)
|
|
testing.expect_value(t, ok, true)
|
|
testing.expect_value(t, result.hour, 8)
|
|
testing.expect_value(t, result.minute, 49)
|
|
testing.expect_value(t, result.tz_abbr, "EDT")
|
|
}
|
|
|
|
@(test)
|
|
test_convert_to_tz_with_negative_offset_converts :: proc(t: ^testing.T) {
|
|
tz, tz_ok := timezone.region_load("America/New_York", context.temp_allocator)
|
|
testing.expect(t, tz_ok, "should load timezone")
|
|
if !tz_ok do return
|
|
defer timezone.region_destroy(tz, context.temp_allocator)
|
|
|
|
// 2026-03-15T08:49:54-04:00 → UTC 12:49:54 → EDT 08:49:54
|
|
c := Date_Components{
|
|
year = 2026, month = 3, day = 15,
|
|
hour = 8, minute = 49, second = 54,
|
|
offset_seconds = -14400,
|
|
has_offset = true,
|
|
}
|
|
result, ok := convert_to_tz(c, tz)
|
|
testing.expect_value(t, ok, true)
|
|
testing.expect_value(t, result.hour, 8)
|
|
testing.expect_value(t, result.tz_abbr, "EDT")
|
|
}
|