| 1 | package calc |
| 2 | |
| 3 | import ( |
| 4 | "testing" |
| 5 | "time" |
| 6 | ) |
| 7 | |
| 8 | // pinnedEnv answers every cell as blank and Now() as a fixed instant — |
| 9 | // the minimal Env a NOW()/TODAY() unit test needs, independent of |
| 10 | // corpus_test.go's clockEnv (which additionally models advancing a wall |
| 11 | // clock that Now() ignores). |
| 12 | type pinnedEnv time.Time |
| 13 | |
| 14 | func (p pinnedEnv) CellValue(CellKey) Value { return Value{} } |
| 15 | func (p pinnedEnv) Now() time.Time { return time.Time(p) } |
| 16 | |
| 17 | func TestNowUsesEnvClock(t *testing.T) { |
| 18 | env := pinnedEnv(time.Date(2026, 8, 30, 12, 0, 0, 0, time.UTC)) |
| 19 | v := Eval(mustParse(t, "NOW()"), env) |
| 20 | if v.Kind != KindNum { |
| 21 | t.Fatalf("NOW() Kind = %v, want KindNum", v.Kind) |
| 22 | } |
| 23 | want := dateSerial(time.Time(env)) |
| 24 | if v.Num != want { |
| 25 | t.Fatalf("NOW() = %v, want %v", v.Num, want) |
| 26 | } |
| 27 | } |
| 28 | |
| 29 | // TODAY truncates the time of day to midnight, so it differs from NOW by |
| 30 | // less than one full day and is itself a whole number of days. |
| 31 | func TestTodayTruncatesToMidnight(t *testing.T) { |
| 32 | env := pinnedEnv(time.Date(2026, 8, 30, 15, 30, 0, 0, time.UTC)) |
| 33 | v := Eval(mustParse(t, "TODAY()"), env) |
| 34 | if v.Kind != KindNum { |
| 35 | t.Fatalf("TODAY() Kind = %v, want KindNum", v.Kind) |
| 36 | } |
| 37 | if v.Num != float64(int64(v.Num)) { |
| 38 | t.Fatalf("TODAY() = %v, want a whole number of days", v.Num) |
| 39 | } |
| 40 | now := Eval(mustParse(t, "NOW()"), env) |
| 41 | if now.Num-v.Num >= 1 || now.Num-v.Num < 0 { |
| 42 | t.Fatalf("NOW()-TODAY() = %v, want in [0,1)", now.Num-v.Num) |
| 43 | } |
| 44 | } |
| 45 | |
| 46 | func TestNowTodayRejectArguments(t *testing.T) { |
| 47 | env := pinnedEnv(time.Now()) |
| 48 | for _, formula := range []string{"NOW(1)", "TODAY(1)"} { |
| 49 | v := Eval(mustParse(t, formula), env) |
| 50 | if v.Kind != KindErr || v.Err != ErrValue { |
| 51 | t.Errorf("with an argument = %v, want #VALUE!", v) |
| 52 | } |
| 53 | } |
| 54 | } |
| 55 | |