From 4ba66213658c3644f4f5f7723df10b4509630e51 Mon Sep 17 00:00:00 2001 From: Erik Winter Date: Fri, 22 Nov 2024 08:23:13 +0100 Subject: [PATCH] wip --- plan/command/add.go | 16 ++-- plan/command/add_test.go | 2 +- plan/command/argset_test.go | 110 +++++++++++++++++++++++++ plan/command/command.go | 7 ++ plan/command/update.go | 25 +++++- plan/command/update_test.go | 159 ++++++++++++++++++++++++++++++++++++ plan/main.go | 2 +- 7 files changed, 307 insertions(+), 14 deletions(-) create mode 100644 plan/command/argset_test.go diff --git a/plan/command/add.go b/plan/command/add.go index eb203b3..5fafe61 100644 --- a/plan/command/add.go +++ b/plan/command/add.go @@ -10,21 +10,15 @@ import ( "go-mod.ewintr.nl/planner/plan/storage" ) -const ( - FlagOn = "on" - FlagAt = "at" - FlagFor = "for" -) - -type AddCmd struct { +type Add struct { localIDRepo storage.LocalID eventRepo storage.Event syncRepo storage.Sync argSet *ArgSet } -func NewAddCmd(localRepo storage.LocalID, eventRepo storage.Event, syncRepo storage.Sync) Command { - return &AddCmd{ +func NewAdd(localRepo storage.LocalID, eventRepo storage.Event, syncRepo storage.Sync) Command { + return &Add{ localIDRepo: localRepo, eventRepo: eventRepo, syncRepo: syncRepo, @@ -38,7 +32,7 @@ func NewAddCmd(localRepo storage.LocalID, eventRepo storage.Event, syncRepo stor } } -func (add *AddCmd) Parse(main []string, flags map[string]string) error { +func (add *Add) Parse(main []string, flags map[string]string) error { if len(main) == 0 || main[0] != "add" { return ErrWrongCommand } @@ -78,7 +72,7 @@ func (add *AddCmd) Parse(main []string, flags map[string]string) error { return nil } -func (add *AddCmd) Do() error { +func (add *Add) Do() error { as := add.argSet start := as.GetTime(FlagOn) if as.IsSet(FlagAt) { diff --git a/plan/command/add_test.go b/plan/command/add_test.go index 0107aad..b239a65 100644 --- a/plan/command/add_test.go +++ b/plan/command/add_test.go @@ -108,7 +108,7 @@ func TestAddParse(t *testing.T) { eventRepo := memory.NewEvent() localRepo := memory.NewLocalID() syncRepo := memory.NewSync() - cmd := command.NewAddCmd(localRepo, eventRepo, syncRepo) + cmd := command.NewAdd(localRepo, eventRepo, syncRepo) actParseErr := cmd.Parse(tc.main, tc.flags) != nil if tc.expParseErr != actParseErr { t.Errorf("exp %v, got %v", tc.expParseErr, actParseErr) diff --git a/plan/command/argset_test.go b/plan/command/argset_test.go new file mode 100644 index 0000000..e8711e8 --- /dev/null +++ b/plan/command/argset_test.go @@ -0,0 +1,110 @@ +package command_test + +import ( + "testing" + "time" + + "go-mod.ewintr.nl/planner/plan/command" +) + +func TestArgSet(t *testing.T) { + for _, tt := range []struct { + name string + flags map[string]command.Flag + flagName string + setValue string + exp interface{} + expErr bool + }{ + { + name: "string flag success", + flags: map[string]command.Flag{ + "title": &command.FlagString{Name: "title"}, + }, + flagName: "title", + setValue: "test title", + exp: "test title", + }, + { + name: "date flag success", + flags: map[string]command.Flag{ + "date": &command.FlagDate{Name: "date"}, + }, + flagName: "date", + setValue: "2024-01-02", + exp: time.Date(2024, 1, 2, 0, 0, 0, 0, time.UTC), + }, + { + name: "time flag success", + flags: map[string]command.Flag{ + "time": &command.FlagTime{Name: "time"}, + }, + flagName: "time", + setValue: "15:04", + exp: time.Date(0, 1, 1, 15, 4, 0, 0, time.UTC), + }, + { + name: "duration flag success", + flags: map[string]command.Flag{ + "duration": &command.FlagDuration{Name: "duration"}, + }, + flagName: "duration", + setValue: "2h30m", + exp: 2*time.Hour + 30*time.Minute, + }, + { + name: "unknown flag error", + flags: map[string]command.Flag{}, + flagName: "unknown", + setValue: "value", + expErr: true, + }, + { + name: "invalid date format error", + flags: map[string]command.Flag{ + "date": &command.FlagDate{Name: "date"}, + }, + flagName: "date", + setValue: "invalid", + expErr: true, + }, + } { + t.Run(tt.name, func(t *testing.T) { + as := &command.ArgSet{ + Main: "test", + Flags: tt.flags, + } + + err := as.Set(tt.flagName, tt.setValue) + if (err != nil) != tt.expErr { + t.Errorf("ArgSet.Set() error = %v, expErr %v", err, tt.expErr) + return + } + + if tt.expErr { + return + } + + // Verify IsSet() returns true after setting + if !as.IsSet(tt.flagName) { + t.Errorf("ArgSet.IsSet() = false, want true for flag %s", tt.flagName) + } + + // Verify the value was set correctly based on flag type + switch v := tt.exp.(type) { + case string: + if got := as.GetString(tt.flagName); got != v { + t.Errorf("ArgSet.GetString() = %v, want %v", got, v) + } + case time.Time: + if got := as.GetTime(tt.flagName); !got.Equal(v) { + t.Errorf("ArgSet.GetTime() = %v, want %v", got, v) + } + case time.Duration: + if got := as.GetDuration(tt.flagName); got != v { + t.Errorf("ArgSet.GetDuration() = %v, want %v", got, v) + } + } + }) + } +} diff --git a/plan/command/command.go b/plan/command/command.go index 4d47c69..0f5d511 100644 --- a/plan/command/command.go +++ b/plan/command/command.go @@ -6,6 +6,13 @@ import ( "strings" ) +const ( + FlagName = "name" + FlagOn = "on" + FlagAt = "at" + FlagFor = "for" +) + type Command interface { Parse([]string, map[string]string) error Do() error diff --git a/plan/command/update.go b/plan/command/update.go index 883875a..87a377e 100644 --- a/plan/command/update.go +++ b/plan/command/update.go @@ -8,6 +8,29 @@ import ( "go-mod.ewintr.nl/planner/plan/storage" ) +type Update struct { + localIDRepo storage.LocalID + eventRepo storage.Event + syncRepo storage.Sync + argSet *ArgSet +} + +func NewUpdate(localIDRepo storage.LocalID, eventRepo storage.Event, syncRepo storage.Sync) Command { + return &Update{ + localIDRepo: localRepo, + eventRepo: eventRepo, + syncRepo: syncRepo, + argSet: &ArgSet{ + Flags: map[string]Flag{ + FlagTitle: &FlagString{}, + FlagOn: &FlagDate{}, + FlagAt: &FlagTime{}, + FlagFor: &FlagDuration{}, + }, + }, + } +} + var UpdateCmd = &cli.Command{ Name: "update", Usage: "Update an event", @@ -48,7 +71,7 @@ func NewUpdateCmd(localRepo storage.LocalID, eventRepo storage.Event, syncRepo s return UpdateCmd } -func Update(localRepo storage.LocalID, eventRepo storage.Event, syncRepo storage.Sync, localID int, nameStr, onStr, atStr, frStr string) error { +func UpdateOld(localRepo storage.LocalID, eventRepo storage.Event, syncRepo storage.Sync, localID int, nameStr, onStr, atStr, frStr string) error { var id string idMap, err := localRepo.FindAll() if err != nil { diff --git a/plan/command/update_test.go b/plan/command/update_test.go index 090a297..3aed2b6 100644 --- a/plan/command/update_test.go +++ b/plan/command/update_test.go @@ -194,3 +194,162 @@ func TestUpdate(t *testing.T) { }) } } +package command_test + +import ( + "fmt" + "testing" + "time" + + "github.com/google/go-cmp/cmp" + "go-mod.ewintr.nl/planner/item" + "go-mod.ewintr.nl/planner/plan/command" + "go-mod.ewintr.nl/planner/plan/storage" +) + +// Mock implementations +type mockLocalID struct { + ids map[string]int +} + +func (m *mockLocalID) Store(id string, localID int) error { + m.ids[id] = localID + return nil +} + +func (m *mockLocalID) FindAll() (map[string]int, error) { + return m.ids, nil +} + +type mockEvent struct { + events map[string]item.Event +} + +func (m *mockEvent) Store(event item.Event) error { + m.events[event.ID] = event + return nil +} + +func (m *mockEvent) Find(id string) (item.Event, error) { + if event, ok := m.events[id]; ok { + return event, nil + } + return item.Event{}, fmt.Errorf("event not found") +} + +func (m *mockEvent) FindAll() ([]item.Event, error) { + var events []item.Event + for _, e := range m.events { + events = append(events, e) + } + return events, nil +} + +func (m *mockEvent) Delete(id string) error { + delete(m.events, id) + return nil +} + +type mockSync struct { + items map[string]item.Item +} + +func (m *mockSync) Store(it item.Item) error { + m.items[it.ID] = it + return nil +} + +func TestUpdate(t *testing.T) { + baseTime := time.Date(2024, 1, 1, 10, 0, 0, 0, time.UTC) + testEvent := item.Event{ + ID: "test-id", + Title: "Original Title", + Start: baseTime, + Duration: 1 * time.Hour, + } + + tests := []struct { + name string + localID int + nameStr string + onStr string + atStr string + frStr string + setup func(*mockLocalID, *mockEvent, *mockSync) + wantErr bool + validate func(*testing.T, *mockEvent, *mockSync) + }{ + { + name: "update title only", + localID: 1, + nameStr: "New Title", + setup: func(l *mockLocalID, e *mockEvent, s *mockSync) { + l.ids["test-id"] = 1 + e.events["test-id"] = testEvent + }, + validate: func(t *testing.T, e *mockEvent, s *mockSync) { + updated := e.events["test-id"] + if updated.Title != "New Title" { + t.Errorf("expected title 'New Title', got %s", updated.Title) + } + if !updated.Start.Equal(baseTime) { + t.Error("start time should not have changed") + } + }, + }, + { + name: "update date only", + localID: 1, + onStr: "2024-02-01", + setup: func(l *mockLocalID, e *mockEvent, s *mockSync) { + l.ids["test-id"] = 1 + e.events["test-id"] = testEvent + }, + validate: func(t *testing.T, e *mockEvent, s *mockSync) { + updated := e.events["test-id"] + expectedTime := time.Date(2024, 2, 1, 10, 0, 0, 0, time.UTC) + if !updated.Start.Equal(expectedTime) { + t.Errorf("expected start time %v, got %v", expectedTime, updated.Start) + } + }, + }, + { + name: "invalid local ID", + localID: 999, + setup: func(l *mockLocalID, e *mockEvent, s *mockSync) { + l.ids["test-id"] = 1 + }, + wantErr: true, + }, + { + name: "invalid duration format", + localID: 1, + frStr: "invalid", + setup: func(l *mockLocalID, e *mockEvent, s *mockSync) { + l.ids["test-id"] = 1 + e.events["test-id"] = testEvent + }, + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + localRepo := &mockLocalID{ids: make(map[string]int)} + eventRepo := &mockEvent{events: make(map[string]item.Event)} + syncRepo := &mockSync{items: make(map[string]item.Item)} + + tt.setup(localRepo, eventRepo, syncRepo) + + err := command.Update(localRepo, eventRepo, syncRepo, tt.localID, tt.nameStr, tt.onStr, tt.atStr, tt.frStr) + if (err != nil) != tt.wantErr { + t.Errorf("Update() error = %v, wantErr %v", err, tt.wantErr) + return + } + + if !tt.wantErr && tt.validate != nil { + tt.validate(t, eventRepo, syncRepo) + } + }) + } +} diff --git a/plan/main.go b/plan/main.go index da2cab9..b59adf4 100644 --- a/plan/main.go +++ b/plan/main.go @@ -33,7 +33,7 @@ func main() { cli := command.CLI{ Commands: []command.Command{ - command.NewAddCmd(localIDRepo, eventRepo, syncRepo), + command.NewAdd(localIDRepo, eventRepo, syncRepo), // command.NewListCmd(localIDRepo, eventRepo), // command.NewUpdateCmd(localIDRepo, eventRepo, syncRepo), // command.NewDeleteCmd(localIDRepo, eventRepo, syncRepo),