oficina / calendar Public

Clone
git clone https://amadan.net/oficina/calendar

Plain git — no account needed to clone.

Download

Download this file

1package calendar
2
3import (
4 "context"
5 "os"
6 "os/exec"
7 "testing"
8 "time"
9)
10
11func TestWeeklyLargeIntervalFinishesPromptly(t *testing.T) {
12 if os.Getenv("CALENDAR_WEEKLY_BOUND_PROBE") == "1" {
13 proto := time.Date(2026, 9, 7, 9, 0, 0, 0, time.UTC)
14 r, err := ParseRule("FREQ=WEEKLY;INTERVAL=100000000;BYDAY=MO")
15 if err != nil {
16 t.Fatal(err)
17 }
18 got, state := advance(proto, proto, r, time.UTC)
19 if state != stepIncomplete {
20 t.Fatalf("next=%v state=%v want incomplete horizon", got, state)
21 }
22 return
23 }
24 ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
25 defer cancel()
26 cmd := exec.CommandContext(ctx, os.Args[0], "-test.run=^TestWeeklyLargeIntervalFinishesPromptly$", "-test.count=1")
27 cmd.Env = append(os.Environ(), "CALENDAR_WEEKLY_BOUND_PROBE=1")
28 out, err := cmd.CombinedOutput()
29 if ctx.Err() != nil {
30 t.Fatal("weekly BYDAY expansion exceeded the bounded subprocess deadline")
31 }
32 if err != nil {
33 t.Fatalf("probe: %v\n%s", err, out)
34 }
35}
36
37func TestCivilDateDifferencesDoNotSaturateAt292Years(t *testing.T) {
38 start := time.Date(1600, 1, 1, 9, 0, 0, 0, time.UTC)
39 end := time.Date(2000, 1, 1, 9, 0, 0, 0, time.UTC)
40 if got := daysBetween(start, end); got != 146097 {
41 t.Errorf("civil days=%d want146097", got)
42 }
43 if got := daysBetween(end, start); got != -146097 {
44 t.Errorf("reverse civil days=%d want-146097", got)
45 }
46}
47
48func TestYearlyAdvanceNeverWrapsBackwards(t *testing.T) {
49 proto := time.Date(2026, 9, 7, 9, 0, 0, 0, time.UTC)
50 for _, interval := range []int{int(^uint(0) >> 1), int(^uint(0)>>1) / 2, int(^uint(0)>>1) / 3} {
51 next, state := advance(proto, proto, Rule{Freq: FreqYearly, Interval: interval}, time.UTC)
52 if state == stepCandidate && !next.After(proto) {
53 t.Errorf("interval=%d next=%v is not later than %v", interval, next, proto)
54 }
55 }
56}
57
58func TestStrictExpansionDoesNotCallInvalidInputComplete(t *testing.T) {
59 r, _ := ParseRule("FREQ=DAILY")
60 from := time.Date(2026, 9, 7, 0, 0, 0, 0, time.UTC).Unix()
61 to := from + 86400
62 for _, c := range []struct{ start, end, zone string }{
63 {"2026-09-07T09:00", "2026-09-07T10:00", "Not/AZone"},
64 {"invalid", "2026-09-07T10:00", "UTC"},
65 {"2026-09-07T09:00", "invalid", "UTC"},
66 } {
67 if _, complete := ExpandComplete(c.start, c.end, c.zone, false, r, "", from, to); complete {
68 t.Errorf("invalid input marked complete: %+v", c)
69 }
70 }
71}
72
73func TestFourCenturyWeeklyOccurrenceIsNotSilentlyLost(t *testing.T) {
74 r, err := ParseRule("FREQ=WEEKLY;INTERVAL=20871;BYDAY=SA;COUNT=2")
75 if err != nil {
76 t.Fatal(err)
77 }
78 from := time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC).Unix()
79 to := time.Date(2000, 1, 2, 0, 0, 0, 0, time.UTC).Unix()
80 got, complete := ExpandComplete("1600-01-01T09:00", "1600-01-01T10:00", "UTC", false, r, "", from, to)
81 if !complete || len(got) != 1 || got[0].Local != "2000-01-01T09:00" {
82 t.Fatalf("occurrences=%+v complete=%v; want the second occurrence on 2000-01-01", got, complete)
83 }
84}
85