diff options
| author | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-08-03 23:59:09 +0200 |
|---|---|---|
| committer | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-08-03 23:59:09 +0200 |
| commit | 27ceffcb90c0716179342109163c559d492a8abc (patch) | |
| tree | fe34486e7cf7bbb4f49d624512fb3782c29cc319 /mobile/mobile_test.go | |
| parent | 13d5e99ab90ab872c8cc072a0246348f0d24fa9a (diff) | |
| download | lectio-27ceffcb90c0716179342109163c559d492a8abc.tar.gz lectio-27ceffcb90c0716179342109163c559d492a8abc.zip | |
mobile: add Days, a text-free week projection for the calendar
A week through Days benchmarks at ~9-10ms/op, versus ~23ms for seven
full days through Day.
Diffstat (limited to 'mobile/mobile_test.go')
| -rw-r--r-- | mobile/mobile_test.go | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/mobile/mobile_test.go b/mobile/mobile_test.go index c7df63c..57e835a 100644 --- a/mobile/mobile_test.go +++ b/mobile/mobile_test.go @@ -2,6 +2,7 @@ package mobile import ( "encoding/json" + "strings" "testing" ) @@ -40,3 +41,85 @@ func TestDayHasColourKeyButNoColourLabel(t *testing.T) { t.Error("colour_label must not be returned: the app draws a swatch") } } + +func decodeDays(t *testing.T, s string) []map[string]any { + t.Helper() + var a []map[string]any + if err := json.Unmarshal([]byte(s), &a); err != nil { + t.Fatalf("Days returned invalid JSON: %v\n%s", err, s) + } + return a +} + +func TestDaysReturnsConsecutiveDates(t *testing.T) { + a := decodeDays(t, Days("2026-07-27", 7, "of", "pl")) + if len(a) != 7 { + t.Fatalf("got %d elements, want 7", len(a)) + } + want := []string{"2026-07-27", "2026-07-28", "2026-07-29", "2026-07-30", + "2026-07-31", "2026-08-01", "2026-08-02"} + for i, w := range want { + if a[i]["date"] != w { + t.Errorf("element %d date = %v, want %v", i, a[i]["date"], w) + } + } +} + +// Days must agree with Day about the same date -- it is a cheaper projection of +// the same computation, not a second implementation. +func TestDaysAgreesWithDay(t *testing.T) { + one := decodeDay(t, Day("2026-08-01", "of", "vul", "pl")) + week := decodeDays(t, Days("2026-08-01", 1, "of", "pl")) + if len(week) != 1 { + t.Fatalf("got %d elements, want 1", len(week)) + } + row := week[0] + for _, k := range []string{"name", "colour", "rank", "rank_label"} { + if row[k] != one[k] { + t.Errorf("%s: Days = %v, Day = %v", k, row[k], one[k]) + } + } + parts := row["parts"].([]any) + readings := one["readings"].([]any) + if len(parts) != len(readings) { + t.Fatalf("parts = %d, readings = %d", len(parts), len(readings)) + } + for i := range parts { + p := parts[i].(map[string]any) + r := readings[i].(map[string]any) + if p["part"] != r["part"] || p["citation"] != r["citation"] { + t.Errorf("element %d: Days %v/%v vs Day %v/%v", + i, p["part"], p["citation"], r["part"], r["citation"]) + } + } +} + +// No reading text may cross the boundary: that is the whole point of Days. +func TestDaysCarriesNoReadingText(t *testing.T) { + s := Days("2026-08-01", 7, "of", "pl") + if strings.Contains(s, `"text"`) { + t.Error("Days must not return reading text") + } + if strings.Contains(s, "colour_label") { + t.Error("Days must not return a colour label") + } +} + +func TestDaysRejectsBadInput(t *testing.T) { + for _, c := range []struct { + start string + count int + }{ + {"not-a-date", 7}, {"2026-08-01", 0}, {"2026-08-01", -1}, {"2026-08-01", 400}, + } { + if got := Days(c.start, c.count, "of", "pl"); got != "[]" { + t.Errorf("Days(%q, %d) = %s, want []", c.start, c.count, got) + } + } +} + +func BenchmarkDaysWeek(b *testing.B) { + for i := 0; i < b.N; i++ { + Days("2026-07-27", 7, "of", "pl") + } +} |
