diff --git a/dist/plan b/dist/plan index 11aa328..fe46657 100755 Binary files a/dist/plan and b/dist/plan differ diff --git a/plan/command/add.go b/plan/command/add.go index 53c39b0..7aaaab4 100644 --- a/plan/command/add.go +++ b/plan/command/add.go @@ -3,109 +3,107 @@ package command import ( "fmt" "strings" + "time" "github.com/google/uuid" "go-mod.ewintr.nl/planner/item" - "go-mod.ewintr.nl/planner/plan/storage" ) -type Add struct { - localIDRepo storage.LocalID - taskRepo storage.Task - syncRepo storage.Sync - argSet *ArgSet +type AddArgs struct { + fieldTPL map[string][]string + task item.Task } -func NewAdd(localRepo storage.LocalID, taskRepo storage.Task, syncRepo storage.Sync) Command { - return &Add{ - localIDRepo: localRepo, - taskRepo: taskRepo, - syncRepo: syncRepo, - argSet: &ArgSet{ - Flags: map[string]Flag{ - FlagOn: &FlagDate{}, - FlagAt: &FlagTime{}, - FlagFor: &FlagDuration{}, - FlagRec: &FlagRecurrer{}, - }, +func NewAddArgs() AddArgs { + return AddArgs{ + fieldTPL: map[string][]string{ + "date": []string{"d", "date", "on"}, + "time": []string{"t", "time", "at"}, + "duration": []string{"dur", "duration", "for"}, + "recurrer": []string{"rec", "recurrer"}, }, } } -func (add *Add) Execute(main []string, flags map[string]string) error { +func (aa AddArgs) Parse(main []string, fields map[string]string) (Command, error) { if len(main) == 0 || main[0] != "add" { - return ErrWrongCommand + return nil, ErrWrongCommand } - as := add.argSet - if len(main) > 1 { - as.Main = strings.Join(main[1:], " ") + main = main[1:] + if len(main) == 0 { + return nil, fmt.Errorf("%w: title is required for add", ErrInvalidArg) } - for k := range as.Flags { - v, ok := flags[k] - if !ok { - continue - } - if err := as.Set(k, v); err != nil { - return fmt.Errorf("could not set %s: %v", k, err) - } - } - if as.Main == "" { - return fmt.Errorf("%w: title is required", ErrInvalidArg) - } - if !as.IsSet(FlagOn) { - return fmt.Errorf("%w: date is required", ErrInvalidArg) - } - if !as.IsSet(FlagAt) && as.IsSet(FlagFor) { - return fmt.Errorf("%w: can not have duration without start time", ErrInvalidArg) - } - if as.IsSet(FlagAt) && !as.IsSet(FlagFor) { - if err := as.Flags[FlagFor].Set("1h"); err != nil { - return fmt.Errorf("could not set duration to one hour") - } - } - if !as.IsSet(FlagAt) && !as.IsSet(FlagFor) { - if err := as.Flags[FlagFor].Set("24h"); err != nil { - return fmt.Errorf("could not set duration to 24 hours") - } + fields, err := ResolveFields(fields, aa.fieldTPL) + if err != nil { + return nil, err } - return add.do() -} - -func (add *Add) do() error { - as := add.argSet - rec := as.GetRecurrer(FlagRec) tsk := item.Task{ - ID: uuid.New().String(), - Date: as.GetDate(FlagOn), - Recurrer: rec, + ID: uuid.New().String(), TaskBody: item.TaskBody{ - Title: as.Main, - Time: as.GetTime(FlagAt), - Duration: as.GetDuration(FlagFor), + Title: strings.Join(main, ","), }, } - if rec != nil { - tsk.RecurNext = rec.First() + + if val, ok := fields["date"]; ok { + d := item.NewDateFromString(val) + if d.IsZero() { + return nil, fmt.Errorf("%w: could not parse date", ErrInvalidArg) + } + tsk.Date = d + } + if val, ok := fields["time"]; ok { + t := item.NewTimeFromString(val) + if t.IsZero() { + return nil, fmt.Errorf("%w: could not parse time", ErrInvalidArg) + } + tsk.Time = t + } + if val, ok := fields["duration"]; ok { + d, err := time.ParseDuration(val) + if err != nil { + return nil, fmt.Errorf("%w: could not parse duration", ErrInvalidArg) + } + tsk.Duration = d + } + if val, ok := fields["recurrer"]; ok { + rec := item.NewRecurrer(val) + if rec == nil { + return nil, fmt.Errorf("%w: could not parse recurrer", ErrInvalidArg) + } + tsk.Recurrer = rec + tsk.RecurNext = tsk.Recurrer.First() } - if err := add.taskRepo.Store(tsk); err != nil { + return &Add{ + args: AddArgs{ + task: tsk, + }, + }, nil +} + +type Add struct { + args AddArgs +} + +func (a *Add) Do(deps Dependencies) error { + if err := deps.TaskRepo.Store(a.args.task); err != nil { return fmt.Errorf("could not store event: %v", err) } - localID, err := add.localIDRepo.Next() + localID, err := deps.LocalIDRepo.Next() if err != nil { return fmt.Errorf("could not create next local id: %v", err) } - if err := add.localIDRepo.Store(tsk.ID, localID); err != nil { + if err := deps.LocalIDRepo.Store(a.args.task.ID, localID); err != nil { return fmt.Errorf("could not store local id: %v", err) } - it, err := tsk.Item() + it, err := a.args.task.Item() if err != nil { return fmt.Errorf("could not convert event to sync item: %v", err) } - if err := add.syncRepo.Store(it); err != nil { + if err := deps.SyncRepo.Store(it); err != nil { return fmt.Errorf("could not store sync item: %v", err) } diff --git a/plan/command/add_test.go b/plan/command/add_test.go index 6af038d..ad14feb 100644 --- a/plan/command/add_test.go +++ b/plan/command/add_test.go @@ -14,14 +14,13 @@ func TestAdd(t *testing.T) { aDate := item.NewDate(2024, 11, 2) aTime := item.NewTime(12, 0) - aDay := time.Duration(24) * time.Hour anHourStr := "1h" anHour := time.Hour for _, tc := range []struct { name string main []string - flags map[string]string + fields map[string]string expErr bool expTask item.Task }{ @@ -32,38 +31,18 @@ func TestAdd(t *testing.T) { { name: "title missing", main: []string{"add"}, - flags: map[string]string{ - command.FlagOn: aDate.String(), + fields: map[string]string{ + "date": aDate.String(), }, expErr: true, }, { - name: "date missing", - main: []string{"add", "some", "title"}, - expErr: true, - }, - { - name: "only date", + name: "date time duration", main: []string{"add", "title"}, - flags: map[string]string{ - command.FlagOn: aDate.String(), - }, - expTask: item.Task{ - ID: "title", - Date: aDate, - TaskBody: item.TaskBody{ - Title: "title", - Duration: aDay, - }, - }, - }, - { - name: "date, time and duration", - main: []string{"add", "title"}, - flags: map[string]string{ - command.FlagOn: aDate.String(), - command.FlagAt: aTime.String(), - command.FlagFor: anHourStr, + fields: map[string]string{ + "date": aDate.String(), + "time": aTime.String(), + "duration": anHourStr, }, expTask: item.Task{ ID: "title", @@ -75,28 +54,25 @@ func TestAdd(t *testing.T) { }, }, }, - { - name: "date and duration", - main: []string{"add", "title"}, - flags: map[string]string{ - command.FlagOn: aDate.String(), - command.FlagFor: anHourStr, - }, - expErr: true, - }, } { t.Run(tc.name, func(t *testing.T) { taskRepo := memory.NewTask() - localRepo := memory.NewLocalID() + localIDRepo := memory.NewLocalID() syncRepo := memory.NewSync() - cmd := command.NewAdd(localRepo, taskRepo, syncRepo) - actParseErr := cmd.Execute(tc.main, tc.flags) != nil - if tc.expErr != actParseErr { + cmd, actParseErr := command.NewAddArgs().Parse(tc.main, tc.fields) + if tc.expErr != (actParseErr != nil) { t.Errorf("exp %v, got %v", tc.expErr, actParseErr) } if tc.expErr { return } + if err := cmd.Do(command.Dependencies{ + TaskRepo: taskRepo, + LocalIDRepo: localIDRepo, + SyncRepo: syncRepo, + }); err != nil { + t.Errorf("exp nil, got %v", err) + } actTasks, err := taskRepo.FindAll() if err != nil { @@ -106,7 +82,7 @@ func TestAdd(t *testing.T) { t.Errorf("exp 1, got %d", len(actTasks)) } - actLocalIDs, err := localRepo.FindAll() + actLocalIDs, err := localIDRepo.FindAll() if err != nil { t.Errorf("exp nil, got %v", err) } diff --git a/plan/command/argset.go b/plan/command/argset.go deleted file mode 100644 index 7464d1f..0000000 --- a/plan/command/argset.go +++ /dev/null @@ -1,101 +0,0 @@ -package command - -import ( - "fmt" - "time" - - "go-mod.ewintr.nl/planner/item" -) - -type ArgSet struct { - Main string - Flags map[string]Flag -} - -func (as *ArgSet) Set(name, val string) error { - f, ok := as.Flags[name] - if !ok { - return fmt.Errorf("unknown flag %s", name) - } - return f.Set(val) -} - -func (as *ArgSet) IsSet(name string) bool { - f, ok := as.Flags[name] - if !ok { - return false - } - return f.IsSet() -} - -func (as *ArgSet) GetString(name string) string { - flag, ok := as.Flags[name] - if !ok { - return "" - } - val, ok := flag.Get().(string) - if !ok { - return "" - } - return val -} - -func (as *ArgSet) GetDate(name string) item.Date { - flag, ok := as.Flags[name] - if !ok { - return item.Date{} - } - val, ok := flag.Get().(item.Date) - if !ok { - return item.Date{} - } - return val -} - -func (as *ArgSet) GetTime(name string) item.Time { - flag, ok := as.Flags[name] - if !ok { - return item.Time{} - } - val, ok := flag.Get().(item.Time) - if !ok { - return item.Time{} - } - return val -} - -func (as *ArgSet) GetDuration(name string) time.Duration { - flag, ok := as.Flags[name] - if !ok { - return time.Duration(0) - } - val, ok := flag.Get().(time.Duration) - if !ok { - return time.Duration(0) - } - return val -} - -func (as *ArgSet) GetRecurrer(name string) item.Recurrer { - flag, ok := as.Flags[name] - if !ok { - return nil - } - val, ok := flag.Get().(item.Recurrer) - if !ok { - return nil - } - return val -} - -func (as *ArgSet) GetInt(name string) int { - flag, ok := as.Flags[name] - if !ok { - return 0 - } - val, ok := flag.Get().(int) - if !ok { - return 0 - } - return val -} diff --git a/plan/command/argset_test.go b/plan/command/argset_test.go deleted file mode 100644 index 0e03ede..0000000 --- a/plan/command/argset_test.go +++ /dev/null @@ -1,103 +0,0 @@ -package command_test - -import ( - "testing" - "time" - - "go-mod.ewintr.nl/planner/item" - "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: "recur period flag success", - flags: map[string]command.Flag{ - "recur": &command.FlagRecurrer{Name: "recur"}, - }, - flagName: "recur", - setValue: "2024-12-23, daily", - exp: item.NewRecurrer("2024-12-23, daily"), - }, - { - 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 - } - - if !as.IsSet(tt.flagName) { - t.Errorf("ArgSet.IsSet() = false, want true for flag %s", tt.flagName) - } - }) - } -} diff --git a/plan/command/command.go b/plan/command/command.go index 6c1daa8..2a8467d 100644 --- a/plan/command/command.go +++ b/plan/command/command.go @@ -3,66 +3,104 @@ package command import ( "errors" "fmt" + "slices" "strings" + + "go-mod.ewintr.nl/planner/plan/storage" + "go-mod.ewintr.nl/planner/sync/client" ) const ( - FlagTitle = "title" - FlagOn = "on" - FlagAt = "at" - FlagFor = "for" - FlagRec = "rec" + DateFormat = "2006-01-02" + TimeFormat = "15:04" ) +var ( + ErrWrongCommand = errors.New("wrong command") + ErrInvalidArg = errors.New("invalid argument") +) + +type Dependencies struct { + LocalIDRepo storage.LocalID + TaskRepo storage.Task + SyncRepo storage.Sync + SyncClient client.Client +} + +type CommandArgs interface { + Parse(main []string, fields map[string]string) (Command, error) +} + type Command interface { - Execute([]string, map[string]string) error + Do(deps Dependencies) error } type CLI struct { - Commands []Command + deps Dependencies + cmdArgs []CommandArgs +} + +func NewCLI(deps Dependencies) *CLI { + return &CLI{ + deps: deps, + cmdArgs: []CommandArgs{ + NewAddArgs(), NewDeleteArgs(), NewListArgs(), + NewSyncArgs(), NewUpdateArgs(), + }, + } } func (cli *CLI) Run(args []string) error { - main, flags, err := ParseFlags(args) - if err != nil { - return err - } - for _, c := range cli.Commands { - err := c.Execute(main, flags) + main, flags := FindFields(args) + for _, ca := range cli.cmdArgs { + cmd, err := ca.Parse(main, flags) switch { case errors.Is(err, ErrWrongCommand): continue case err != nil: return err default: - return nil + return cmd.Do(cli.deps) } } return fmt.Errorf("could not find matching command") } -func ParseFlags(args []string) ([]string, map[string]string, error) { - flags := make(map[string]string) +func FindFields(args []string) ([]string, map[string]string) { + fields := make(map[string]string) main := make([]string, 0) - var inMain bool for i := 0; i < len(args); i++ { - if strings.HasPrefix(args[i], "-") { - inMain = false - if i+1 >= len(args) { - return nil, nil, fmt.Errorf("flag wihout value") - } - flags[strings.TrimPrefix(args[i], "-")] = args[i+1] - i++ + if k, v, ok := strings.Cut(args[i], ":"); ok && !strings.Contains(k, " ") { + fields[k] = v continue } - - if !inMain && len(main) > 0 { - return nil, nil, fmt.Errorf("two mains") - } - inMain = true main = append(main, args[i]) } - return main, flags, nil + return main, fields +} + +func ResolveFields(fields map[string]string, tmpl map[string][]string) (map[string]string, error) { + res := make(map[string]string) + for k, v := range fields { + for tk, tv := range tmpl { + if slices.Contains(tv, k) { + if _, ok := res[tk]; ok { + return nil, fmt.Errorf("%w: duplicate field: %v", ErrInvalidArg, tk) + } + res[tk] = v + delete(fields, k) + } + } + } + if len(fields) > 0 { + ks := make([]string, 0, len(fields)) + for k := range fields { + ks = append(ks, k) + } + return nil, fmt.Errorf("%w: unknown field(s): %v", ErrInvalidArg, strings.Join(ks, ",")) + } + + return res, nil } diff --git a/plan/command/command_test.go b/plan/command/command_test.go index 54af244..54dc5a3 100644 --- a/plan/command/command_test.go +++ b/plan/command/command_test.go @@ -7,62 +7,120 @@ import ( "go-mod.ewintr.nl/planner/plan/command" ) -func TestParseArgs(t *testing.T) { +func TestFindFields(t *testing.T) { t.Parallel() for _, tc := range []struct { - name string - args []string - expMain []string - expFlags map[string]string - expErr bool + name string + args []string + expMain []string + expFields map[string]string }{ { - name: "empty", - expMain: []string{}, - expFlags: map[string]string{}, + name: "empty", + expMain: []string{}, + expFields: map[string]string{}, }, { - name: "just main", - args: []string{"one", "two three", "four"}, - expMain: []string{"one", "two three", "four"}, - expFlags: map[string]string{}, + name: "just main", + args: []string{"one", "two three", "four"}, + expMain: []string{"one", "two three", "four"}, + expFields: map[string]string{}, }, { name: "with flags", - args: []string{"-flag1", "value1", "one", "two", "-flag2", "value2", "-flag3", "value3"}, + args: []string{"flag1:value1", "one", "two", "flag2:value2", "flag3:value3"}, expMain: []string{"one", "two"}, - expFlags: map[string]string{ + expFields: map[string]string{ "flag1": "value1", "flag2": "value2", "flag3": "value3", }, }, { - name: "flag without value", - args: []string{"one", "two", "-flag1"}, - expErr: true, + name: "flag without value", + args: []string{"one", "two", "flag1:"}, + expMain: []string{"one", "two"}, + expFields: map[string]string{ + "flag1": "", + }, }, { - name: "split main", - args: []string{"one", "-flag1", "value1", "two"}, - expErr: true, + name: "split main", + args: []string{"one", "flag1:value1", "two"}, + expMain: []string{"one", "two"}, + expFields: map[string]string{ + "flag1": "value1", + }, }, } { t.Run(tc.name, func(t *testing.T) { - actMain, actFlags, actErr := command.ParseFlags(tc.args) - if tc.expErr != (actErr != nil) { - t.Errorf("exp %v, got %v", tc.expErr, actErr) - } - if tc.expErr { - return - } + actMain, actFields := command.FindFields(tc.args) if diff := cmp.Diff(tc.expMain, actMain); diff != "" { t.Errorf("(exp +, got -)\n%s", diff) } - if diff := cmp.Diff(tc.expFlags, actFlags); diff != "" { + if diff := cmp.Diff(tc.expFields, actFields); diff != "" { t.Errorf("(exp +, got -)\n%s", diff) } }) } } + +func TestResolveFields(t *testing.T) { + t.Parallel() + + tmpl := map[string][]string{ + "one": []string{"a", "b"}, + "two": []string{"c", "d"}, + } + for _, tc := range []struct { + name string + fields map[string]string + expRes map[string]string + expErr bool + }{ + { + name: "empty", + expRes: map[string]string{}, + }, + { + name: "unknown", + fields: map[string]string{ + "unknown": "value", + }, + expErr: true, + }, + { + name: "duplicate", + fields: map[string]string{ + "a": "val1", + "b": "val2", + }, + expErr: true, + }, + { + name: "valid", + fields: map[string]string{ + "a": "val1", + "d": "val2", + }, + expRes: map[string]string{ + "one": "val1", + "two": "val2", + }, + }, + } { + t.Run(tc.name, func(t *testing.T) { + actRes, actErr := command.ResolveFields(tc.fields, tmpl) + if tc.expErr != (actErr != nil) { + t.Errorf("exp %v, got %v", tc.expErr, actErr != nil) + } + if tc.expErr { + return + } + if diff := cmp.Diff(tc.expRes, actRes); diff != "" { + t.Errorf("(+exp, -got)%s\n", diff) + } + }) + } +} diff --git a/plan/command/delete.go b/plan/command/delete.go index e6325fd..cc2c777 100644 --- a/plan/command/delete.go +++ b/plan/command/delete.go @@ -3,46 +3,45 @@ package command import ( "fmt" "strconv" - - "go-mod.ewintr.nl/planner/plan/storage" ) -type Delete struct { - localIDRepo storage.LocalID - taskRepo storage.Task - syncRepo storage.Sync - localID int +type DeleteArgs struct { + LocalID int } -func NewDelete(localIDRepo storage.LocalID, taskRepo storage.Task, syncRepo storage.Sync) Command { - return &Delete{ - localIDRepo: localIDRepo, - taskRepo: taskRepo, - syncRepo: syncRepo, - } +func NewDeleteArgs() DeleteArgs { + return DeleteArgs{} } -func (del *Delete) Execute(main []string, flags map[string]string) error { +func (da DeleteArgs) Parse(main []string, flags map[string]string) (Command, error) { if len(main) < 2 || main[0] != "delete" { - return ErrWrongCommand + return nil, ErrWrongCommand } + localID, err := strconv.Atoi(main[1]) if err != nil { - return fmt.Errorf("not a local id: %v", main[1]) + return nil, fmt.Errorf("not a local id: %v", main[1]) } - del.localID = localID - return del.do() + return &Delete{ + args: DeleteArgs{ + LocalID: localID, + }, + }, nil } -func (del *Delete) do() error { +type Delete struct { + args DeleteArgs +} + +func (del *Delete) Do(deps Dependencies) error { var id string - idMap, err := del.localIDRepo.FindAll() + idMap, err := deps.LocalIDRepo.FindAll() if err != nil { return fmt.Errorf("could not get local ids: %v", err) } for tskID, lid := range idMap { - if del.localID == lid { + if del.args.LocalID == lid { id = tskID } } @@ -50,7 +49,7 @@ func (del *Delete) do() error { return fmt.Errorf("could not find local id") } - tsk, err := del.taskRepo.Find(id) + tsk, err := deps.TaskRepo.Find(id) if err != nil { return fmt.Errorf("could not get task: %v", err) } @@ -60,15 +59,15 @@ func (del *Delete) do() error { return fmt.Errorf("could not convert task to sync item: %v", err) } it.Deleted = true - if err := del.syncRepo.Store(it); err != nil { + if err := deps.SyncRepo.Store(it); err != nil { return fmt.Errorf("could not store sync item: %v", err) } - if err := del.localIDRepo.Delete(id); err != nil { + if err := deps.LocalIDRepo.Delete(id); err != nil { return fmt.Errorf("could not delete local id: %v", err) } - if err := del.taskRepo.Delete(id); err != nil { + if err := deps.TaskRepo.Delete(id); err != nil { return fmt.Errorf("could not delete task: %v", err) } diff --git a/plan/command/delete_test.go b/plan/command/delete_test.go index aac3dc0..bfd39e3 100644 --- a/plan/command/delete_test.go +++ b/plan/command/delete_test.go @@ -22,20 +22,21 @@ func TestDelete(t *testing.T) { } for _, tc := range []struct { - name string - main []string - flags map[string]string - expErr bool + name string + main []string + flags map[string]string + expParseErr bool + expDoErr bool }{ { - name: "invalid", - main: []string{"update"}, - expErr: true, + name: "invalid", + main: []string{"update"}, + expParseErr: true, }, { - name: "not found", - main: []string{"delete", "5"}, - expErr: true, + name: "not found", + main: []string{"delete", "5"}, + expDoErr: true, }, { name: "valid", @@ -48,26 +49,35 @@ func TestDelete(t *testing.T) { if err := taskRepo.Store(e); err != nil { t.Errorf("exp nil, got %v", err) } - localRepo := memory.NewLocalID() - if err := localRepo.Store(e.ID, 1); err != nil { + localIDRepo := memory.NewLocalID() + if err := localIDRepo.Store(e.ID, 1); err != nil { t.Errorf("exp nil, got %v", err) } - cmd := command.NewDelete(localRepo, taskRepo, syncRepo) - - actErr := cmd.Execute(tc.main, tc.flags) != nil - if tc.expErr != actErr { - t.Errorf("exp %v, got %v", tc.expErr, actErr) + cmd, actParseErr := command.NewDeleteArgs().Parse(tc.main, tc.flags) + if tc.expParseErr != (actParseErr != nil) { + t.Errorf("exp %v, got %v", tc.expParseErr, actParseErr) } - if tc.expErr { + if tc.expParseErr { + return + } + actDoErr := cmd.Do(command.Dependencies{ + TaskRepo: taskRepo, + LocalIDRepo: localIDRepo, + SyncRepo: syncRepo, + }) != nil + if tc.expDoErr != actDoErr { + t.Errorf("exp false, got %v", actDoErr) + } + if tc.expDoErr { return } _, repoErr := taskRepo.Find(e.ID) if !errors.Is(repoErr, storage.ErrNotFound) { - t.Errorf("exp %v, got %v", storage.ErrNotFound, actErr) + t.Errorf("exp %v, got %v", storage.ErrNotFound, repoErr) } - idMap, idErr := localRepo.FindAll() + idMap, idErr := localIDRepo.FindAll() if idErr != nil { t.Errorf("exp nil, got %v", idErr) } diff --git a/plan/command/flag.go b/plan/command/flag.go deleted file mode 100644 index c771e60..0000000 --- a/plan/command/flag.go +++ /dev/null @@ -1,156 +0,0 @@ -package command - -import ( - "errors" - "fmt" - "strconv" - "time" - - "go-mod.ewintr.nl/planner/item" -) - -const ( - DateFormat = "2006-01-02" - TimeFormat = "15:04" -) - -var ( - ErrWrongCommand = errors.New("wrong command") - ErrInvalidArg = errors.New("invalid argument") -) - -type Flag interface { - Set(val string) error - IsSet() bool - Get() any -} - -type FlagString struct { - Name string - Value string -} - -func (fs *FlagString) Set(val string) error { - fs.Value = val - return nil -} - -func (fs *FlagString) IsSet() bool { - return fs.Value != "" -} - -func (fs *FlagString) Get() any { - return fs.Value -} - -type FlagDate struct { - Name string - Value item.Date -} - -func (fd *FlagDate) Set(val string) error { - d := item.NewDateFromString(val) - if d.IsZero() { - return fmt.Errorf("could not parse date: %v", d) - } - fd.Value = d - - return nil -} - -func (fd *FlagDate) IsSet() bool { - return !fd.Value.IsZero() -} - -func (fd *FlagDate) Get() any { - return fd.Value -} - -type FlagTime struct { - Name string - Value item.Time -} - -func (ft *FlagTime) Set(val string) error { - d := item.NewTimeFromString(val) - if d.IsZero() { - return fmt.Errorf("could not parse date: %v", d) - } - ft.Value = d - - return nil -} - -func (fd *FlagTime) IsSet() bool { - return !fd.Value.IsZero() -} - -func (fs *FlagTime) Get() any { - return fs.Value -} - -type FlagDuration struct { - Name string - Value time.Duration -} - -func (fd *FlagDuration) Set(val string) error { - dur, err := time.ParseDuration(val) - if err != nil { - return fmt.Errorf("could not parse duration: %v", err) - } - fd.Value = dur - return nil -} - -func (fd *FlagDuration) IsSet() bool { - return fd.Value.String() != "0s" -} - -func (fs *FlagDuration) Get() any { - return fs.Value -} - -type FlagRecurrer struct { - Name string - Value item.Recurrer -} - -func (fr *FlagRecurrer) Set(val string) error { - fr.Value = item.NewRecurrer(val) - if fr.Value == nil { - return fmt.Errorf("not a valid recurrer: %v", val) - } - return nil -} - -func (fr *FlagRecurrer) IsSet() bool { - return fr.Value != nil -} - -func (fr *FlagRecurrer) Get() any { - return fr.Value -} - -type FlagInt struct { - Name string - Value int -} - -func (fi *FlagInt) Set(val string) error { - i, err := strconv.Atoi(val) - if err != nil { - return fmt.Errorf("not a valid integer: %v", val) - } - - fi.Value = i - return nil -} - -func (fi *FlagInt) IsSet() bool { - return fi.Value != 0 -} - -func (fi *FlagInt) Get() any { - return fi.Value -} diff --git a/plan/command/flag_test.go b/plan/command/flag_test.go deleted file mode 100644 index 1a18e90..0000000 --- a/plan/command/flag_test.go +++ /dev/null @@ -1,141 +0,0 @@ -package command_test - -import ( - "testing" - "time" - - "go-mod.ewintr.nl/planner/item" - "go-mod.ewintr.nl/planner/plan/command" -) - -func TestFlagString(t *testing.T) { - t.Parallel() - - valid := "test" - f := command.FlagString{} - if f.IsSet() { - t.Errorf("exp false, got true") - } - - if err := f.Set(valid); err != nil { - t.Errorf("exp nil, got %v", err) - } - - if !f.IsSet() { - t.Errorf("exp true, got false") - } - - act, ok := f.Get().(string) - if !ok { - t.Errorf("exp true, got false") - } - if act != valid { - t.Errorf("exp %v, got %v", valid, act) - } -} - -func TestFlagDate(t *testing.T) { - t.Parallel() - - valid := item.NewDate(2024, 11, 20) - f := command.FlagDate{} - if f.IsSet() { - t.Errorf("exp false, got true") - } - - if err := f.Set(valid.String()); err != nil { - t.Errorf("exp nil, got %v", err) - } - - if !f.IsSet() { - t.Errorf("exp true, got false") - } - - act, ok := f.Get().(item.Date) - if !ok { - t.Errorf("exp true, got false") - } - if act.String() != valid.String() { - t.Errorf("exp %v, got %v", valid.String(), act.String()) - } -} - -func TestFlagTime(t *testing.T) { - t.Parallel() - - valid := item.NewTime(12, 30) - f := command.FlagTime{} - if f.IsSet() { - t.Errorf("exp false, got true") - } - - if err := f.Set(valid.String()); err != nil { - t.Errorf("exp nil, got %v", err) - } - - if !f.IsSet() { - t.Errorf("exp true, got false") - } - - act, ok := f.Get().(item.Time) - if !ok { - t.Errorf("exp true, got false") - } - if act.String() != valid.String() { - t.Errorf("exp %v, got %v", valid.String(), act.String()) - } -} - -func TestFlagDurationTime(t *testing.T) { - t.Parallel() - - valid := time.Hour - validStr := "1h" - f := command.FlagDuration{} - if f.IsSet() { - t.Errorf("exp false, got true") - } - - if err := f.Set(validStr); err != nil { - t.Errorf("exp nil, got %v", err) - } - - if !f.IsSet() { - t.Errorf("exp true, got false") - } - - act, ok := f.Get().(time.Duration) - if !ok { - t.Errorf("exp true, got false") - } - if act != valid { - t.Errorf("exp %v, got %v", valid, act) - } -} - -func TestFlagRecurrer(t *testing.T) { - t.Parallel() - - validStr := "2024-12-23, daily" - valid := item.NewRecurrer(validStr) - f := command.FlagRecurrer{} - if f.IsSet() { - t.Errorf("exp false, got true") - } - - if err := f.Set(validStr); err != nil { - t.Errorf("exp nil, got %v", err) - } - - if !f.IsSet() { - t.Errorf("exp true, got false") - } - - act, ok := f.Get().(item.Recurrer) - if !ok { - t.Errorf("exp true, got false") - } - if act != valid { - t.Errorf("exp %v, got %v", valid, act) - } -} diff --git a/plan/command/list.go b/plan/command/list.go index e5cf8d5..b31bca8 100644 --- a/plan/command/list.go +++ b/plan/command/list.go @@ -2,36 +2,32 @@ package command import ( "fmt" - - "go-mod.ewintr.nl/planner/plan/storage" ) -type List struct { - localIDRepo storage.LocalID - taskRepo storage.Task +type ListArgs struct { } -func NewList(localIDRepo storage.LocalID, taskRepo storage.Task) Command { - return &List{ - localIDRepo: localIDRepo, - taskRepo: taskRepo, - } +func NewListArgs() ListArgs { + return ListArgs{} } -func (list *List) Execute(main []string, flags map[string]string) error { +func (la ListArgs) Parse(main []string, flags map[string]string) (Command, error) { if len(main) > 0 && main[0] != "list" { - return ErrWrongCommand + return nil, ErrWrongCommand } - return list.do() + return &List{}, nil } -func (list *List) do() error { - localIDs, err := list.localIDRepo.FindAll() +type List struct { +} + +func (list *List) Do(deps Dependencies) error { + localIDs, err := deps.LocalIDRepo.FindAll() if err != nil { return fmt.Errorf("could not get local ids: %v", err) } - all, err := list.taskRepo.FindAll() + all, err := deps.TaskRepo.FindAll() if err != nil { return err } diff --git a/plan/command/list_test.go b/plan/command/list_test.go index 652432b..953ba39 100644 --- a/plan/command/list_test.go +++ b/plan/command/list_test.go @@ -47,11 +47,19 @@ func TestList(t *testing.T) { }, } { t.Run(tc.name, func(t *testing.T) { - cmd := command.NewList(localRepo, taskRepo) - actErr := cmd.Execute(tc.main, nil) != nil - if tc.expErr != actErr { + cmd, actErr := command.NewListArgs().Parse(tc.main, nil) + if tc.expErr != (actErr != nil) { t.Errorf("exp %v, got %v", tc.expErr, actErr) } + if tc.expErr { + return + } + if err := cmd.Do(command.Dependencies{ + TaskRepo: taskRepo, + LocalIDRepo: localRepo, + }); err != nil { + t.Errorf("exp nil, got %v", err) + } }) } } diff --git a/plan/command/sync.go b/plan/command/sync.go index 8ffcb44..7da90df 100644 --- a/plan/command/sync.go +++ b/plan/command/sync.go @@ -7,52 +7,43 @@ import ( "go-mod.ewintr.nl/planner/item" "go-mod.ewintr.nl/planner/plan/storage" - "go-mod.ewintr.nl/planner/sync/client" ) -type Sync struct { - client client.Client - syncRepo storage.Sync - localIDRepo storage.LocalID - taskRepo storage.Task +type SyncArgs struct{} + +func NewSyncArgs() SyncArgs { + return SyncArgs{} } -func NewSync(client client.Client, syncRepo storage.Sync, localIDRepo storage.LocalID, taskRepo storage.Task) Command { - return &Sync{ - client: client, - syncRepo: syncRepo, - localIDRepo: localIDRepo, - taskRepo: taskRepo, - } -} - -func (sync *Sync) Execute(main []string, flags map[string]string) error { +func (sa SyncArgs) Parse(main []string, flags map[string]string) (Command, error) { if len(main) == 0 || main[0] != "sync" { - return ErrWrongCommand + return nil, ErrWrongCommand } - return sync.do() + return &Sync{}, nil } -func (sync *Sync) do() error { +type Sync struct{} + +func (s *Sync) Do(deps Dependencies) error { // local new and updated - sendItems, err := sync.syncRepo.FindAll() + sendItems, err := deps.SyncRepo.FindAll() if err != nil { return fmt.Errorf("could not get updated items: %v", err) } - if err := sync.client.Update(sendItems); err != nil { + if err := deps.SyncClient.Update(sendItems); err != nil { return fmt.Errorf("could not send updated items: %v", err) } - if err := sync.syncRepo.DeleteAll(); err != nil { + if err := deps.SyncRepo.DeleteAll(); err != nil { return fmt.Errorf("could not clear updated items: %v", err) } // get new/updated items - ts, err := sync.syncRepo.LastUpdate() + ts, err := deps.SyncRepo.LastUpdate() if err != nil { return fmt.Errorf("could not find timestamp of last update: %v", err) } - recItems, err := sync.client.Updated([]item.Kind{item.KindTask}, ts) + recItems, err := deps.SyncClient.Updated([]item.Kind{item.KindTask}, ts) if err != nil { return fmt.Errorf("could not receive updates: %v", err) } @@ -60,10 +51,10 @@ func (sync *Sync) do() error { updated := make([]item.Item, 0) for _, ri := range recItems { if ri.Deleted { - if err := sync.localIDRepo.Delete(ri.ID); err != nil && !errors.Is(err, storage.ErrNotFound) { + if err := deps.LocalIDRepo.Delete(ri.ID); err != nil && !errors.Is(err, storage.ErrNotFound) { return fmt.Errorf("could not delete local id: %v", err) } - if err := sync.taskRepo.Delete(ri.ID); err != nil && !errors.Is(err, storage.ErrNotFound) { + if err := deps.TaskRepo.Delete(ri.ID); err != nil && !errors.Is(err, storage.ErrNotFound) { return fmt.Errorf("could not delete task: %v", err) } continue @@ -71,7 +62,7 @@ func (sync *Sync) do() error { updated = append(updated, ri) } - lidMap, err := sync.localIDRepo.FindAll() + lidMap, err := deps.LocalIDRepo.FindAll() if err != nil { return fmt.Errorf("could not get local ids: %v", err) } @@ -87,17 +78,17 @@ func (sync *Sync) do() error { RecurNext: u.RecurNext, TaskBody: tskBody, } - if err := sync.taskRepo.Store(tsk); err != nil { + if err := deps.TaskRepo.Store(tsk); err != nil { return fmt.Errorf("could not store task: %v", err) } lid, ok := lidMap[u.ID] if !ok { - lid, err = sync.localIDRepo.Next() + lid, err = deps.LocalIDRepo.Next() if err != nil { return fmt.Errorf("could not get next local id: %v", err) } - if err := sync.localIDRepo.Store(u.ID, lid); err != nil { + if err := deps.LocalIDRepo.Store(u.ID, lid); err != nil { return fmt.Errorf("could not store local id: %v", err) } } diff --git a/plan/command/sync_test.go b/plan/command/sync_test.go index 7463ea1..151e174 100644 --- a/plan/command/sync_test.go +++ b/plan/command/sync_test.go @@ -14,11 +14,6 @@ import ( func TestSyncParse(t *testing.T) { t.Parallel() - syncClient := client.NewMemory() - syncRepo := memory.NewSync() - localIDRepo := memory.NewLocalID() - taskRepo := memory.NewTask() - for _, tc := range []struct { name string main []string @@ -39,9 +34,8 @@ func TestSyncParse(t *testing.T) { }, } { t.Run(tc.name, func(t *testing.T) { - cmd := command.NewSync(syncClient, syncRepo, localIDRepo, taskRepo) - actErr := cmd.Execute(tc.main, nil) != nil - if tc.expErr != actErr { + _, actErr := command.SyncArgs{}.Parse(tc.main, nil) + if tc.expErr != (actErr != nil) { t.Errorf("exp %v, got %v", tc.expErr, actErr) } }) @@ -82,8 +76,16 @@ func TestSyncSend(t *testing.T) { }, } { t.Run(tc.name, func(t *testing.T) { - cmd := command.NewSync(syncClient, syncRepo, localIDRepo, taskRepo) - if err := cmd.Execute([]string{"sync"}, nil); err != nil { + cmd, err := command.SyncArgs{}.Parse([]string{"sync"}, nil) + if err != nil { + t.Errorf("exp nil, got %v", err) + } + if err := cmd.Do(command.Dependencies{ + TaskRepo: taskRepo, + LocalIDRepo: localIDRepo, + SyncRepo: syncRepo, + SyncClient: syncClient, + }); err != nil { t.Errorf("exp nil, got %v", err) } actItems, actErr := syncClient.Updated(tc.ks, tc.ts) @@ -181,12 +183,12 @@ func TestSyncReceive(t *testing.T) { }, } { t.Run(tc.name, func(t *testing.T) { - // setup syncClient := client.NewMemory() syncRepo := memory.NewSync() localIDRepo := memory.NewLocalID() taskRepo := memory.NewTask() + // setup for i, p := range tc.present { if err := taskRepo.Store(p); err != nil { t.Errorf("exp nil, got %v", err) @@ -200,8 +202,16 @@ func TestSyncReceive(t *testing.T) { } // sync - cmd := command.NewSync(syncClient, syncRepo, localIDRepo, taskRepo) - if err := cmd.Execute([]string{"sync"}, nil); err != nil { + cmd, err := command.NewSyncArgs().Parse([]string{"sync"}, nil) + if err != nil { + t.Errorf("exp nil, got %v", err) + } + if err := cmd.Do(command.Dependencies{ + TaskRepo: taskRepo, + LocalIDRepo: localIDRepo, + SyncRepo: syncRepo, + SyncClient: syncClient, + }); err != nil { t.Errorf("exp nil, got %v", err) } diff --git a/plan/command/update.go b/plan/command/update.go index 60a50a3..1dd70c1 100644 --- a/plan/command/update.go +++ b/plan/command/update.go @@ -4,71 +4,93 @@ import ( "fmt" "strconv" "strings" + "time" - "go-mod.ewintr.nl/planner/plan/storage" + "go-mod.ewintr.nl/planner/item" ) -type Update struct { - localIDRepo storage.LocalID - taskRepo storage.Task - syncRepo storage.Sync - argSet *ArgSet - localID int +type UpdateArgs struct { + fieldTPL map[string][]string + LocalID int + Title string + Date item.Date + Time item.Time + Duration time.Duration + Recurrer item.Recurrer } -func NewUpdate(localIDRepo storage.LocalID, taskRepo storage.Task, syncRepo storage.Sync) Command { - return &Update{ - localIDRepo: localIDRepo, - taskRepo: taskRepo, - syncRepo: syncRepo, - argSet: &ArgSet{ - Flags: map[string]Flag{ - FlagTitle: &FlagString{}, - FlagOn: &FlagDate{}, - FlagAt: &FlagTime{}, - FlagFor: &FlagDuration{}, - FlagRec: &FlagRecurrer{}, - }, +func NewUpdateArgs() UpdateArgs { + return UpdateArgs{ + fieldTPL: map[string][]string{ + "date": []string{"d", "date", "on"}, + "time": []string{"t", "time", "at"}, + "duration": []string{"dur", "duration", "for"}, + "recurrer": []string{"rec", "recurrer"}, }, } } -func (update *Update) Execute(main []string, flags map[string]string) error { +func (ua UpdateArgs) Parse(main []string, fields map[string]string) (Command, error) { if len(main) < 2 || main[0] != "update" { - return ErrWrongCommand + return nil, ErrWrongCommand } localID, err := strconv.Atoi(main[1]) if err != nil { - return fmt.Errorf("not a local id: %v", main[1]) + return nil, fmt.Errorf("not a local id: %v", main[1]) } - update.localID = localID - main = main[2:] - - as := update.argSet - as.Main = strings.Join(main, " ") - for k := range as.Flags { - v, ok := flags[k] - if !ok { - continue - } - if err := as.Set(k, v); err != nil { - return fmt.Errorf("could not set %s: %v", k, err) - } + fields, err = ResolveFields(fields, ua.fieldTPL) + if err != nil { + return nil, err + } + args := UpdateArgs{ + LocalID: localID, + Title: strings.Join(main[2:], " "), } - update.argSet = as - return update.do() + if val, ok := fields["date"]; ok { + d := item.NewDateFromString(val) + if d.IsZero() { + return nil, fmt.Errorf("%w: could not parse date", ErrInvalidArg) + } + args.Date = d + } + if val, ok := fields["time"]; ok { + t := item.NewTimeFromString(val) + if t.IsZero() { + return nil, fmt.Errorf("%w: could not parse time", ErrInvalidArg) + } + args.Time = t + } + if val, ok := fields["duration"]; ok { + d, err := time.ParseDuration(val) + if err != nil { + return nil, fmt.Errorf("%w: could not parse duration", ErrInvalidArg) + } + args.Duration = d + } + if val, ok := fields["recurrer"]; ok { + rec := item.NewRecurrer(val) + if rec == nil { + return nil, fmt.Errorf("%w: could not parse recurrer", ErrInvalidArg) + } + args.Recurrer = rec + } + + return &Update{args}, nil } -func (update *Update) do() error { - as := update.argSet +type Update struct { + args UpdateArgs +} + +func (u *Update) Do(deps Dependencies) error { var id string - idMap, err := update.localIDRepo.FindAll() + idMap, err := deps.LocalIDRepo.FindAll() if err != nil { return fmt.Errorf("could not get local ids: %v", err) } for tid, lid := range idMap { - if update.localID == lid { + if u.args.LocalID == lid { id = tid } } @@ -76,32 +98,33 @@ func (update *Update) do() error { return fmt.Errorf("could not find local id") } - tsk, err := update.taskRepo.Find(id) + tsk, err := deps.TaskRepo.Find(id) if err != nil { return fmt.Errorf("could not find task") } - if as.Main != "" { - tsk.Title = as.Main + if u.args.Title != "" { + tsk.Title = u.args.Title } - if as.IsSet(FlagOn) { - tsk.Date = as.GetDate(FlagOn) + if !u.args.Date.IsZero() { + tsk.Date = u.args.Date } - if as.IsSet(FlagAt) { - tsk.Time = as.GetTime(FlagAt) + if !u.args.Time.IsZero() { + tsk.Time = u.args.Time } - if as.IsSet(FlagFor) { - tsk.Duration = as.GetDuration(FlagFor) + if u.args.Duration != 0 { + tsk.Duration = u.args.Duration } - if as.IsSet(FlagRec) { - tsk.Recurrer = as.GetRecurrer(FlagRec) + if u.args.Recurrer != nil { + tsk.Recurrer = u.args.Recurrer + tsk.RecurNext = tsk.Recurrer.First() } if !tsk.Valid() { return fmt.Errorf("task is unvalid") } - if err := update.taskRepo.Store(tsk); err != nil { + if err := deps.TaskRepo.Store(tsk); err != nil { return fmt.Errorf("could not store task: %v", err) } @@ -109,7 +132,7 @@ func (update *Update) do() error { if err != nil { return fmt.Errorf("could not convert task to sync item: %v", err) } - if err := update.syncRepo.Store(it); err != nil { + if err := deps.SyncRepo.Store(it); err != nil { return fmt.Errorf("could not store sync item: %v", err) } diff --git a/plan/command/update_test.go b/plan/command/update_test.go index 7b7fc88..fa1ab82 100644 --- a/plan/command/update_test.go +++ b/plan/command/update_test.go @@ -28,21 +28,22 @@ func TestUpdateExecute(t *testing.T) { } for _, tc := range []struct { - name string - localID int - main []string - flags map[string]string - expTask item.Task - expErr bool + name string + localID int + main []string + fields map[string]string + expTask item.Task + expParseErr bool + expDoErr bool }{ { - name: "no args", - expErr: true, + name: "no args", + expParseErr: true, }, { - name: "not found", - localID: 1, - expErr: true, + name: "not found", + main: []string{"update", "1"}, + expDoErr: true, }, { name: "name", @@ -59,19 +60,19 @@ func TestUpdateExecute(t *testing.T) { }, }, { - name: "invalid on", + name: "invalid date", localID: lid, main: []string{"update", fmt.Sprintf("%d", lid)}, - flags: map[string]string{ + fields: map[string]string{ "on": "invalid", }, - expErr: true, + expParseErr: true, }, { - name: "on", + name: "date", localID: lid, main: []string{"update", fmt.Sprintf("%d", lid)}, - flags: map[string]string{ + fields: map[string]string{ "on": "2024-10-02", }, expTask: item.Task{ @@ -85,20 +86,20 @@ func TestUpdateExecute(t *testing.T) { }, }, { - name: "invalid at", + name: "invalid time", localID: lid, main: []string{"update", fmt.Sprintf("%d", lid)}, - flags: map[string]string{ + fields: map[string]string{ "at": "invalid", }, - expErr: true, + expParseErr: true, }, { - name: "at", + name: "time", localID: lid, main: []string{"update", fmt.Sprintf("%d", lid)}, - flags: map[string]string{ - "at": "11:00", + fields: map[string]string{ + "time": "11:00", }, expTask: item.Task{ ID: tskID, @@ -111,37 +112,19 @@ func TestUpdateExecute(t *testing.T) { }, }, { - name: "on and at", + name: "invalid duration", localID: lid, main: []string{"update", fmt.Sprintf("%d", lid)}, - flags: map[string]string{ - "on": "2024-10-02", - "at": "11:00", - }, - expTask: item.Task{ - ID: tskID, - Date: item.NewDate(2024, 10, 2), - TaskBody: item.TaskBody{ - Title: title, - Time: item.NewTime(11, 0), - Duration: oneHour, - }, - }, - }, - { - name: "invalid for", - localID: lid, - main: []string{"update", fmt.Sprintf("%d", lid)}, - flags: map[string]string{ + fields: map[string]string{ "for": "invalid", }, - expErr: true, + expParseErr: true, }, { - name: "for", + name: "duration", localID: lid, main: []string{"update", fmt.Sprintf("%d", lid)}, - flags: map[string]string{ + fields: map[string]string{ "for": "2h", }, expTask: item.Task{ @@ -155,17 +138,17 @@ func TestUpdateExecute(t *testing.T) { }, }, { - name: "invalid rec", + name: "invalid recurrer", main: []string{"update", fmt.Sprintf("%d", lid)}, - flags: map[string]string{ + fields: map[string]string{ "rec": "invalud", }, - expErr: true, + expParseErr: true, }, { - name: "valid rec", + name: "valid recurrer", main: []string{"update", fmt.Sprintf("%d", lid)}, - flags: map[string]string{ + fields: map[string]string{ "rec": "2024-12-08, daily", }, expTask: item.Task{ @@ -199,12 +182,22 @@ func TestUpdateExecute(t *testing.T) { t.Errorf("exp nil, ,got %v", err) } - cmd := command.NewUpdate(localIDRepo, taskRepo, syncRepo) - actParseErr := cmd.Execute(tc.main, tc.flags) != nil - if tc.expErr != actParseErr { - t.Errorf("exp %v, got %v", tc.expErr, actParseErr) + cmd, actErr := command.NewUpdateArgs().Parse(tc.main, tc.fields) + if tc.expParseErr != (actErr != nil) { + t.Errorf("exp %v, got %v", tc.expParseErr, actErr) } - if tc.expErr { + if tc.expParseErr { + return + } + actDoErr := cmd.Do(command.Dependencies{ + TaskRepo: taskRepo, + LocalIDRepo: localIDRepo, + SyncRepo: syncRepo, + }) != nil + if tc.expDoErr != actDoErr { + t.Errorf("exp %v, got %v", tc.expDoErr, actDoErr) + } + if tc.expDoErr { return } diff --git a/plan/main.go b/plan/main.go index f87ca57..14850c1 100644 --- a/plan/main.go +++ b/plan/main.go @@ -35,16 +35,12 @@ func main() { syncClient := client.New(conf.SyncURL, conf.ApiKey) - cli := command.CLI{ - Commands: []command.Command{ - command.NewAdd(localIDRepo, taskRepo, syncRepo), - command.NewList(localIDRepo, taskRepo), - command.NewUpdate(localIDRepo, taskRepo, syncRepo), - command.NewDelete(localIDRepo, taskRepo, syncRepo), - command.NewSync(syncClient, syncRepo, localIDRepo, taskRepo), - }, - } - + cli := command.NewCLI(command.Dependencies{ + LocalIDRepo: localIDRepo, + TaskRepo: taskRepo, + SyncRepo: syncRepo, + SyncClient: syncClient, + }) if err := cli.Run(os.Args[1:]); err != nil { fmt.Println(err) os.Exit(1)