172 lines
5.6 KiB
Go
172 lines
5.6 KiB
Go
package mujica
|
||
|
||
import (
|
||
"fmt"
|
||
"testing"
|
||
"time"
|
||
|
||
"github.com/egoist/mygo/ui"
|
||
)
|
||
|
||
type monthProbe struct {
|
||
month YearMonth
|
||
events []CalendarEvent
|
||
opts CalendarMonthViewOptions
|
||
opened []string
|
||
changes []CalendarChange
|
||
days []Date
|
||
disabled bool
|
||
}
|
||
|
||
func (p *monthProbe) tester() *ui.Tester {
|
||
if p.month.IsZero() {
|
||
p.month = YearMonth{2026, time.October}
|
||
}
|
||
p.opts.Location, p.opts.Today = calTokyo, calendarToday
|
||
return ui.NewTester(func(c *ui.Context) {
|
||
Use(c, Settings{})
|
||
o := p.opts
|
||
o.Disabled = p.disabled
|
||
r := CalendarMonthView(c, &p.month, p.events, o)
|
||
if id, ok := r.Opened(); ok {
|
||
p.opened = append(p.opened, id)
|
||
}
|
||
if ch, ok := r.Changed(); ok {
|
||
p.changes = append(p.changes, ch)
|
||
}
|
||
if d, ok := r.DayChosen(); ok {
|
||
p.days = append(p.days, d)
|
||
}
|
||
}, 1000, 900)
|
||
}
|
||
|
||
func TestCalendarMonthViewOverflowAndPopover(t *testing.T) {
|
||
p := &monthProbe{}
|
||
for i := range 5 {
|
||
p.events = append(p.events, calEvent(fmt.Sprint(i), 14, 8+2*i, 0, 60))
|
||
}
|
||
tt := p.tester()
|
||
if !tt.HasText("+2") || tt.HasText("Event 3") {
|
||
t.Fatalf("3 rows then +2 expected: %v", tt.Texts())
|
||
}
|
||
_ = tt.Click("2 more events")
|
||
if !tt.HasText("Event 4") {
|
||
t.Fatal("+N should list the hidden events")
|
||
}
|
||
_ = tt.Click("Event 4, 16:00 – 17:00")
|
||
if len(p.opened) != 1 || p.opened[0] != "4" {
|
||
t.Fatalf("opened %v", p.opened)
|
||
}
|
||
}
|
||
|
||
func TestCalendarMonthViewOverlapSideBySide(t *testing.T) {
|
||
p := &monthProbe{events: []CalendarEvent{calEvent("a", 14, 9, 0, 120), calEvent("b", 14, 10, 0, 60), calEvent("c", 14, 15, 0, 60)}}
|
||
tt := p.tester()
|
||
a, _ := tt.Find("Event a, 09:00 – 11:00")
|
||
b, _ := tt.Find("Event b, 10:00 – 11:00")
|
||
cc, _ := tt.Find("Event c, 15:00 – 16:00")
|
||
if a.Y != b.Y || b.X <= a.X || cc.Y <= a.Y {
|
||
t.Fatalf("overlapping events should share a row: %v %v %v", a, b, cc)
|
||
}
|
||
}
|
||
|
||
func TestCalendarMonthViewDragAndKeys(t *testing.T) {
|
||
p := &monthProbe{events: []CalendarEvent{calEvent("a", 14, 9, 30, 60)}}
|
||
tt := p.tester()
|
||
chip, _ := tt.Find("Event a, 09:30 – 10:30")
|
||
target, _ := tt.Find(datetimeTestLabel(oct(16)))
|
||
tt.Press(chip.X+10, chip.Y+5)
|
||
for i := 1; i <= 4; i++ {
|
||
f := float32(i) / 4
|
||
tt.Move(chip.X+10+(target.X+20-chip.X-10)*f, chip.Y+5+(target.Y+40-chip.Y-5)*f)
|
||
}
|
||
tt.Release(target.X+20, target.Y+40)
|
||
want := time.Date(2026, time.October, 16, 9, 30, 0, 0, calTokyo)
|
||
if len(p.changes) != 1 || !p.changes[0].Start.Equal(want) || p.changes[0].End.Sub(p.changes[0].Start) != time.Hour {
|
||
t.Fatalf("drop gave %+v", p.changes)
|
||
}
|
||
_ = tt.Click("Event a, 09:30 – 10:30")
|
||
tt.Key(ui.Alt, ui.KeyDown)
|
||
if len(p.changes) != 2 || !p.changes[1].Start.Equal(time.Date(2026, time.October, 21, 9, 30, 0, 0, calTokyo)) {
|
||
t.Fatalf("Alt+Down gave %+v", p.changes)
|
||
}
|
||
}
|
||
|
||
func TestCalendarMonthViewDSTGapReported(t *testing.T) {
|
||
ny, err := time.LoadLocation("America/New_York")
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
ev := CalendarEvent{ID: "g", Title: "Early", Start: time.Date(2026, time.March, 7, 2, 30, 0, 0, ny)}
|
||
ev.End = ev.Start.Add(time.Hour)
|
||
p := &monthProbe{month: YearMonth{2026, time.March}, events: []CalendarEvent{ev}}
|
||
p.opts.Location = ny
|
||
tt := ui.NewTester(func(c *ui.Context) {
|
||
Use(c, Settings{})
|
||
if ch, ok := CalendarMonthView(c, &p.month, p.events, CalendarMonthViewOptions{Location: ny, Today: Date{2026, time.March, 1}}).Changed(); ok {
|
||
p.changes = append(p.changes, ch)
|
||
}
|
||
}, 1000, 900)
|
||
_ = tt.Click("Early, 02:30 – 03:30")
|
||
tt.Key(ui.Alt, ui.KeyRight)
|
||
if len(p.changes) != 0 || !tt.HasText("2026-03-08 02:30 does not exist in America/New_York") {
|
||
t.Fatalf("gap not reported: %v", tt.Texts())
|
||
}
|
||
}
|
||
|
||
func TestCalendarMonthViewNavigationDayAndDisabled(t *testing.T) {
|
||
p := &monthProbe{events: []CalendarEvent{calEvent("a", 14, 9, 0, 60)}}
|
||
tt := p.tester()
|
||
_ = tt.Click(datetimeTestLabel(oct(20)))
|
||
_ = tt.Click("Next month")
|
||
if len(p.days) != 1 || p.days[0] != oct(20) || p.month != (YearMonth{2026, time.November}) {
|
||
t.Fatalf("day %v month %v", p.days, p.month)
|
||
}
|
||
p.month, p.disabled = YearMonth{2026, time.October}, true
|
||
tt.Frame()
|
||
_ = tt.Click("Next month")
|
||
_ = tt.Click("Event a, 09:00 – 10:00")
|
||
tt.Key(ui.Alt, ui.KeyRight)
|
||
if p.month != (YearMonth{2026, time.October}) || len(p.opened) != 0 || len(p.changes) != 0 {
|
||
t.Fatal("disabled view reacted")
|
||
}
|
||
}
|
||
|
||
func TestCalendarMonthViewLargeDataAndInvalid(t *testing.T) {
|
||
p := &monthProbe{}
|
||
base := time.Date(2000, 1, 1, 9, 0, 0, 0, calTokyo)
|
||
for i := range 100000 {
|
||
s := base.Add(time.Duration(i) * 3 * time.Hour)
|
||
p.events = append(p.events, CalendarEvent{ID: fmt.Sprint(i), Title: "E", Start: s, End: s.Add(time.Hour)})
|
||
}
|
||
tt := p.tester()
|
||
if n := len(tt.Texts()); n > 800 {
|
||
t.Fatalf("built %d labels for one month", n)
|
||
}
|
||
for _, bad := range []func(){
|
||
func() { q := &monthProbe{events: []CalendarEvent{{ID: "x", Start: base, End: base}}}; q.tester() },
|
||
func() { q := &monthProbe{opts: CalendarMonthViewOptions{MaxPerDay: -1}}; q.tester() },
|
||
} {
|
||
func() {
|
||
defer func() {
|
||
if recover() == nil {
|
||
t.Error("expected panic")
|
||
}
|
||
}()
|
||
bad()
|
||
}()
|
||
}
|
||
}
|
||
|
||
func TestCalendarMonthViewSnapshot(t *testing.T) {
|
||
m := YearMonth{2026, time.October}
|
||
evs := []CalendarEvent{calEvent("1", 6, 9, 0, 60), calEvent("2", 14, 9, 0, 120), calEvent("3", 14, 10, 0, 30),
|
||
calEvent("4", 14, 13, 0, 30), calEvent("5", 14, 15, 0, 30), calEvent("6", 14, 17, 0, 30), calEvent("7", 22, 18, 0, 60)}
|
||
evs[1].Color, evs[2].Color, evs[6].Color = EventInfo, EventSuccess, EventWarning
|
||
snapshot(t, "calendar_month_view", 900, 860, func(c *ui.Context) {
|
||
ui.Column(c).Padding(16).Children(func() {
|
||
CalendarMonthView(c, &m, evs, CalendarMonthViewOptions{Location: calTokyo, Today: calendarToday})
|
||
})
|
||
})
|
||
}
|