diff options
Diffstat (limited to 'todolist')
| -rw-r--r-- | todolist/app.go | 101 | ||||
| -rw-r--r-- | todolist/app_test.go | 94 | ||||
| -rw-r--r-- | todolist/todo_list.go | 110 | ||||
| -rw-r--r-- | todolist/util.go | 7 | ||||
| -rw-r--r-- | todolist/util_test.go | 13 |
5 files changed, 253 insertions, 72 deletions
diff --git a/todolist/app.go b/todolist/app.go index 4d526c9..96da67f 100644 --- a/todolist/app.go +++ b/todolist/app.go @@ -38,65 +38,70 @@ func (a *App) AddTodo(input string) { func (a *App) DeleteTodo(input string) { a.Load() - id, _ := a.getId(input) - if id == -1 { + ids := a.getIds(input) + if len(ids) == 0 { return } - a.TodoList.Delete(id) + a.TodoList.Delete(ids...) a.Save() - fmt.Println("Todo deleted.") + fmt.Printf("%s deleted.\n", pluralize(len(ids), "Todo", "Todos")) } func (a *App) CompleteTodo(input string) { a.Load() - id, _ := a.getId(input) - if id == -1 { + ids := a.getIds(input) + if len(ids) == 0 { return } - a.TodoList.Complete(id) + a.TodoList.Complete(ids...) a.Save() fmt.Println("Todo completed.") } func (a *App) UncompleteTodo(input string) { a.Load() - id, _ := a.getId(input) - if id == -1 { + ids := a.getIds(input) + if len(ids) == 0 { return } - a.TodoList.Uncomplete(id) + a.TodoList.Uncomplete(ids...) a.Save() fmt.Println("Todo uncompleted.") } func (a *App) ArchiveTodo(input string) { a.Load() - id, _ := a.getId(input) - if id == -1 { + ids := a.getIds(input) + if len(ids) == 0 { return } - a.TodoList.Archive(id) + a.TodoList.Archive(ids...) a.Save() fmt.Println("Todo archived.") } func (a *App) UnarchiveTodo(input string) { a.Load() - id, _ := a.getId(input) - if id == -1 { + ids := a.getIds(input) + if len(ids) == 0 { return } - a.TodoList.Unarchive(id) + a.TodoList.Unarchive(ids...) a.Save() fmt.Println("Todo unarchived.") } func (a *App) EditTodo(input string) { a.Load() - id, todo := a.getId(input) + id := a.getId(input) if id == -1 { return } + todo := a.TodoList.FindById(id) + if todo == nil { + fmt.Println("No such id.") + return + } parser := &Parser{} if parser.ParseEditTodo(todo, input) { @@ -107,7 +112,7 @@ func (a *App) EditTodo(input string) { func (a *App) ExpandTodo(input string) { a.Load() - id, _ := a.getId(input) + id := a.getId(input) parser := &Parser{} if id == -1 { return @@ -153,7 +158,7 @@ func (a *App) ArchiveCompleted() { a.Load() for _, todo := range a.TodoList.Todos() { if todo.Completed { - todo.Archived = true + todo.Archive() } } a.Save() @@ -171,43 +176,69 @@ func (a *App) ListTodos(input string) { func (a *App) PrioritizeTodo(input string) { a.Load() - id, _ := a.getId(input) - if id == -1 { + ids := a.getIds(input) + if len(ids) == 0 { return } - a.TodoList.Prioritize(id) + a.TodoList.Prioritize(ids...) a.Save() fmt.Println("Todo prioritized.") } func (a *App) UnprioritizeTodo(input string) { a.Load() - id, _ := a.getId(input) - if id == -1 { + ids := a.getIds(input) + if len(ids) == 0 { return } - a.TodoList.Unprioritize(id) + a.TodoList.Unprioritize(ids...) a.Save() fmt.Println("Todo un-prioritized.") } -func (a *App) getId(input string) (int, *Todo) { +func (a *App) getId(input string) int { re, _ := regexp.Compile("\\d+") if re.MatchString(input) { id, _ := strconv.Atoi(re.FindString(input)) - todo := a.TodoList.FindById(id) - if todo == nil { - fmt.Println("No such id.") - return -1, nil + return id + } - } - return id, todo + fmt.Println("Invalid id.") + return -1 +} - } else { - fmt.Println("Invalid id.") - return -1, nil +func (a *App) getIds(input string) (ids []int) { + idGroups := strings.Split(input, ",") + for _, idGroup := range idGroups { + if rangedIds, err := a.parseRangedIds(idGroup); len(rangedIds) > 0 || err != nil { + if err != nil { + fmt.Printf("Invalid id group: %s.\n", input) + continue + } + ids = append(ids, rangedIds...) + } else if id := a.getId(idGroup); id != -1 { + ids = append(ids, id) + } else { + fmt.Printf("Invalid id: %s.\n", idGroup) + } + } + return ids +} + +func (a *App) parseRangedIds(input string) (ids []int, err error) { + rangeNumberRE, _ := regexp.Compile("(\\d+)-(\\d+)") + if matches := rangeNumberRE.FindStringSubmatch(input); len(matches) > 0 { + lowerID, _ := strconv.Atoi(matches[1]) + upperID, _ := strconv.Atoi(matches[2]) + if lowerID >= upperID { + return ids, fmt.Errorf("Invalid id group: %s.\n", input) + } + for id := lowerID; id <= upperID; id++ { + ids = append(ids, id) + } } + return ids, err } func (a *App) getGroups(input string, todos []*Todo) *GroupedTodos { diff --git a/todolist/app_test.go b/todolist/app_test.go index f35a7bc..2fb7717 100644 --- a/todolist/app_test.go +++ b/todolist/app_test.go @@ -43,3 +43,97 @@ func TestAddTodoWithEuropeanDates(t *testing.T) { assert.Equal([]string{}, todo.Projects) assert.Equal([]string{}, todo.Contexts) } + +func TestListbyProject(t *testing.T) { + assert := assert.New(t) + app := &App{TodoList: &TodoList{}, TodoStore: &MemoryStore{}} + app.Load() + + // create three todos w/wo a project + app.AddTodo("this is a test +testme") + app.AddTodo("this is a test +testmetoo @work") + app.AddTodo("this is a test with no projects") + app.CompleteTodo("c 1") + + // simulate listTodos + input := "l by p" + filtered := NewFilter(app.TodoList.Todos()).Filter(input) + grouped := app.getGroups(input, filtered) + + assert.Equal(3, len(grouped.Groups)) + + // testme project has 1 todo and its completed + assert.Equal(1, len(grouped.Groups["testme"])) + assert.Equal(true, grouped.Groups["testme"][0].Completed) + + // testmetoo project has 1 todo and it has a context + assert.Equal(1, len(grouped.Groups["testmetoo"])) + assert.Equal(1, len(grouped.Groups["testmetoo"][0].Contexts)) + assert.Equal("work", grouped.Groups["testmetoo"][0].Contexts[0]) +} + +func TestListbyContext(t *testing.T) { + assert := assert.New(t) + app := &App{TodoList: &TodoList{}, TodoStore: &MemoryStore{}} + app.Load() + + // create three todos w/wo a context + app.AddTodo("this is a test +testme") + app.AddTodo("this is a test +testmetoo @work") + app.AddTodo("this is a test with no projects") + app.CompleteTodo("c 1") + + // simulate listTodos + input := "l by c" + filtered := NewFilter(app.TodoList.Todos()).Filter(input) + grouped := app.getGroups(input, filtered) + + assert.Equal(2, len(grouped.Groups)) + + // work context has 1 todo and it has a project of testmetoo + assert.Equal(1, len(grouped.Groups["work"])) + assert.Equal(1, len(grouped.Groups["work"][0].Projects)) + assert.Equal("testmetoo", grouped.Groups["work"][0].Projects[0]) + + // There are two todos with no context + assert.Equal(2, len(grouped.Groups["No contexts"])) + + // check to see if the a todos with no context contain a + // completed todo + var hasACompletedTodo bool + for _, todo := range grouped.Groups["No contexts"] { + if todo.Completed { + hasACompletedTodo = true + } + } + assert.Equal(true, hasACompletedTodo) +} + +func TestGetId(t *testing.T) { + assert := assert.New(t) + app := &App{TodoList: &TodoList{}, TodoStore: &MemoryStore{}} + // not a valid id + assert.Equal(-1, app.getId("p")) + // a single digit id + assert.Equal(6, app.getId("6")) + // a double digit id + assert.Equal(66, app.getId("66")) +} + +func TestGetIds(t *testing.T) { + assert := assert.New(t) + app := &App{TodoList: &TodoList{}, TodoStore: &MemoryStore{}} + // no valid id here + assert.Equal(0, len(app.getIds("p"))) + // one valid value here + assert.Equal([]int{6}, app.getIds("6")) + // lots of single post numbers + assert.Equal([]int{6, 10, 8, 4}, app.getIds("6,10,8,4")) + // a correct range + assert.Equal([]int{6, 7, 8}, app.getIds("6-8")) + // some incorrect ranges + assert.Equal(0, len(app.getIds("6-6"))) + assert.Equal(0, len(app.getIds("8-6"))) + // some compsite ranges + assert.Equal([]int{5, 6, 7, 8, 10, 11, 9}, app.getIds("5,6-8,10-11,9")) +} diff --git a/todolist/todo_list.go b/todolist/todo_list.go index 4623a22..55c250d 100644 --- a/todolist/todo_list.go +++ b/todolist/todo_list.go @@ -15,57 +15,93 @@ func (t *TodoList) Add(todo *Todo) { t.Data = append(t.Data, todo) } -func (t *TodoList) Delete(id int) { - i := -1 - for index, todo := range t.Data { - if todo.Id == id { - i = index +func (t *TodoList) Delete(ids ...int) { + for _, id := range ids { + todo := t.FindById(id) + if todo == nil { + continue + } + i := -1 + for index, todo := range t.Data { + if todo.Id == id { + i = index + } } - } - t.Data = append(t.Data[:i], t.Data[i+1:]...) + t.Data = append(t.Data[:i], t.Data[i+1:]...) + } } -func (t *TodoList) Complete(id int) { - todo := t.FindById(id) - todo.Complete() - t.Delete(id) - t.Data = append(t.Data, todo) +func (t *TodoList) Complete(ids ...int) { + for _, id := range ids { + todo := t.FindById(id) + if todo == nil { + continue + } + todo.Complete() + t.Delete(id) + t.Data = append(t.Data, todo) + } } -func (t *TodoList) Uncomplete(id int) { - todo := t.FindById(id) - todo.Uncomplete() - t.Delete(id) - t.Data = append(t.Data, todo) +func (t *TodoList) Uncomplete(ids ...int) { + for _, id := range ids { + todo := t.FindById(id) + if todo == nil { + continue + } + todo.Uncomplete() + t.Delete(id) + t.Data = append(t.Data, todo) + } } -func (t *TodoList) Archive(id int) { - todo := t.FindById(id) - todo.Archive() - t.Delete(id) - t.Data = append(t.Data, todo) +func (t *TodoList) Archive(ids ...int) { + for _, id := range ids { + todo := t.FindById(id) + if todo == nil { + continue + } + todo.Archive() + t.Delete(id) + t.Data = append(t.Data, todo) + } } -func (t *TodoList) Unarchive(id int) { - todo := t.FindById(id) - todo.Unarchive() - t.Delete(id) - t.Data = append(t.Data, todo) +func (t *TodoList) Unarchive(ids ...int) { + for _, id := range ids { + todo := t.FindById(id) + if todo == nil { + continue + } + todo.Unarchive() + t.Delete(id) + t.Data = append(t.Data, todo) + } } -func (t *TodoList) Prioritize(id int) { - todo := t.FindById(id) - todo.Prioritize() - t.Delete(id) - t.Data = append(t.Data, todo) +func (t *TodoList) Prioritize(ids ...int) { + for _, id := range ids { + todo := t.FindById(id) + if todo == nil { + continue + } + todo.Prioritize() + t.Delete(id) + t.Data = append(t.Data, todo) + } } -func (t *TodoList) Unprioritize(id int) { - todo := t.FindById(id) - todo.Unprioritize() - t.Delete(id) - t.Data = append(t.Data, todo) +func (t *TodoList) Unprioritize(ids ...int) { + for _, id := range ids { + todo := t.FindById(id) + if todo == nil { + continue + } + todo.Unprioritize() + t.Delete(id) + t.Data = append(t.Data, todo) + } } func (t *TodoList) IndexOf(todoToFind *Todo) int { diff --git a/todolist/util.go b/todolist/util.go index 34f9dd1..ff3dbba 100644 --- a/todolist/util.go +++ b/todolist/util.go @@ -52,3 +52,10 @@ func getNearestMonday(t time.Time) time.Time { } } } + +func pluralize(count int, singular, plural string) string { + if count > 1 { + return plural + } + return singular +} diff --git a/todolist/util_test.go b/todolist/util_test.go new file mode 100644 index 0000000..40ecb54 --- /dev/null +++ b/todolist/util_test.go @@ -0,0 +1,13 @@ +package todolist + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestPluralize(t *testing.T) { + assert := assert.New(t) + assert.Equal("todo", pluralize(1, "todo", "todos")) + assert.Equal("todos", pluralize(2, "todo", "todos")) +} |
