From a0e8e1801dcbfcbf18d6f840beb594cf8410e684 Mon Sep 17 00:00:00 2001 From: JamesClonk Date: Mon, 13 Jan 2014 20:27:58 +0100 Subject: [PATCH] Added new methods on TaskList. --- README.md | 9 +++ task.go | 4 +- todotxt.go | 78 +++++++++++++++++++++-- todotxt_test.go | 163 +++++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 239 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 5f08996..d38f1d6 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,15 @@ go-todotxt requires Go1.1 or higher. fmt.Printf("Task 3: %v\n", tasklist[2]) fmt.Printf("Task 4, has priority: %v\n\n", tasklist[3].HasPriority()) fmt.Print(tasklist) + + // Filter list to get only completed tasks + completedList := testTasklist.Filter(func(t Task) bool { + if t.Completed { + return true + } + return false + }) + fmt.Print(completedList) } ``` diff --git a/task.go b/task.go index 6d25723..07c5159 100644 --- a/task.go +++ b/task.go @@ -103,10 +103,10 @@ func (task Task) String() string { } // NewTask creates a new empty Task with default values. (CreatedDate is set to Now()) -func NewTask() *Task { +func NewTask() Task { task := Task{} task.CreatedDate = time.Now() - return &task + return task } // ParseTask parses the input text string into a Task struct. diff --git a/todotxt.go b/todotxt.go index c774526..7f8bc68 100644 --- a/todotxt.go +++ b/todotxt.go @@ -10,6 +10,7 @@ package todotxt import ( "bufio" + "errors" "fmt" "io/ioutil" "os" @@ -28,7 +29,13 @@ var ( IgnoreComments = true ) -// String returns a complete tasklist string in todo.txt format. +// NewTaskList creates a new empty TaskList. +func NewTaskList() TaskList { + tasklist := TaskList{} + return tasklist +} + +// String returns a complete list of tasks in todo.txt format. func (tasklist TaskList) String() (text string) { for _, task := range tasklist { text += fmt.Sprintf("%s\n", task.String()) @@ -36,8 +43,8 @@ func (tasklist TaskList) String() (text string) { return text } -// AddTask appends a task to the current TaskList, and takes care to set the Task.Id correctly, modifying the Task by the given pointer! -func (tasklist *TaskList) AddTask(task *Task) (err error) { +// AddTask appends a task to the current TaskList and takes care to set the Task.Id correctly, modifying the Task by the given pointer! +func (tasklist *TaskList) AddTask(task *Task) { task.Id = 0 for _, t := range *tasklist { if t.Id > task.Id { @@ -47,7 +54,70 @@ func (tasklist *TaskList) AddTask(task *Task) (err error) { task.Id += 1 *tasklist = append(*tasklist, *task) - return +} + +// GetTask returns task by given task 'id' from the TaskList. Returns an error if task could not be found. +func (tasklist *TaskList) GetTask(id int) (*Task, error) { + for _, t := range *tasklist { + if t.Id == id { + return &t, nil + } + } + return nil, errors.New("task not found") +} + +// RemoveTaskById removes any task with given task 'id' from the TaskList. +// Returns an error if no task was removed. +func (tasklist *TaskList) RemoveTaskById(id int) error { + var newList TaskList + + found := false + for _, t := range *tasklist { + if t.Id != id { + newList = append(newList, t) + } else { + found = true + } + } + if !found { + return errors.New("task not found") + } + + *tasklist = newList + return nil +} + +// RemoveTask removes any task from the TaskList with the same String representation as the given task. +// Returns an error if no task was removed. +func (tasklist *TaskList) RemoveTask(task Task) error { + var newList TaskList + + found := false + for _, t := range *tasklist { + if t.String() != task.String() { + newList = append(newList, t) + } else { + found = true + } + } + if !found { + return errors.New("task not found") + } + + *tasklist = newList + return nil +} + +// Filter filters the current TaskList for the given predicate (a function that takes a task as input and returns a bool), +// and returns a new TaskList. The original TaskList is not modified. +func (tasklist *TaskList) Filter(predicate func(Task) bool) *TaskList { + var newList TaskList + for _, t := range *tasklist { + if predicate(t) { + newList = append(newList, t) + } + } + return &newList } // LoadFromFile loads a TaskList from *os.File. diff --git a/todotxt_test.go b/todotxt_test.go index ea545eb..2021d73 100644 --- a/todotxt_test.go +++ b/todotxt_test.go @@ -205,7 +205,13 @@ func TestTaskListWriteFilename(t *testing.T) { } func TestNewTaskList(t *testing.T) { - t.Fail() + testTasklist := NewTaskList() + + testExpected = 0 + testGot = len(testTasklist) + if testGot != testExpected { + t.Errorf("Expected TaskList to contain %d tasks, but got %d", testExpected, testGot) + } } func TestTaskListCount(t *testing.T) { @@ -226,7 +232,8 @@ func TestTaskListAddTask(t *testing.T) { } // add new empty task - testTasklist.AddTask(NewTask()) + task := NewTask() + testTasklist.AddTask(&task) testExpected = 64 testGot = len(testTasklist) @@ -299,21 +306,159 @@ func TestTaskListAddTask(t *testing.T) { taskId++ } +func TestTaskListGetTask(t *testing.T) { + if err := testTasklist.LoadFromFilename(testInputTasklist); err != nil { + t.Fatal(err) + } + + taskId := 3 + task, err := testTasklist.GetTask(taskId) + if err != nil { + t.Error(err) + } + testExpected = "(B) 2013-12-01 Outline chapter 5 @Computer +Novel Level:5 private:false due:2014-02-17" + testGot = task.String() + if testGot != testExpected { + t.Errorf("Expected Task[%d] to be [%s], but got [%s]", taskId, testExpected, testGot) + } + testExpected = 3 + testGot = testTasklist[taskId-1].Id + if testGot != testExpected { + t.Errorf("Expected Task[%d] to be [%d], but got [%d]", taskId, testExpected, testGot) + } + taskId++ +} + func TestTaskListRemoveTaskById(t *testing.T) { - t.Fail() + if err := testTasklist.LoadFromFilename(testInputTasklist); err != nil { + t.Fatal(err) + } + + taskId := 10 + if err := testTasklist.RemoveTaskById(taskId); err != nil { + t.Error(err) + } + testExpected = 62 + testGot = len(testTasklist) + if testGot != testExpected { + t.Errorf("Expected TaskList to contain %d tasks, but got %d", testExpected, testGot) + } + task, err := testTasklist.GetTask(taskId) + if err == nil || task != nil { + t.Errorf("Expected no Task to be found anymore, but got %v", task) + } + + taskId = 27 + if err := testTasklist.RemoveTaskById(taskId); err != nil { + t.Error(err) + } + testExpected = 61 + testGot = len(testTasklist) + if testGot != testExpected { + t.Errorf("Expected TaskList to contain %d tasks, but got %d", testExpected, testGot) + } + task, err = testTasklist.GetTask(taskId) + if err == nil || task != nil { + t.Errorf("Expected no Task to be found anymore, but got %v", task) + } + + taskId = 99 + if err := testTasklist.RemoveTaskById(taskId); err == nil { + t.Errorf("Expected no Task to be found for removal") + } } func TestTaskListRemoveTask(t *testing.T) { - // removes by comparing Task.String() with each other - t.Fail() + if err := testTasklist.LoadFromFilename(testInputTasklist); err != nil { + t.Fatal(err) + } + + taskId := 52 // Is "unique" in tasklist + task, err := testTasklist.GetTask(taskId) + if err != nil { + t.Error(err) + } + + if err := testTasklist.RemoveTask(*task); err != nil { + t.Error(err) + } + testExpected = 62 + testGot = len(testTasklist) + if testGot != testExpected { + t.Errorf("Expected TaskList to contain %d tasks, but got %d", testExpected, testGot) + } + task, err = testTasklist.GetTask(taskId) + if err == nil || task != nil { + t.Errorf("Expected no Task to be found anymore, but got %v", task) + } + + taskId = 2 // Exists 3 times in tasklist + task, err = testTasklist.GetTask(taskId) + if err != nil { + t.Error(err) + } + + if err := testTasklist.RemoveTask(*task); err != nil { + t.Error(err) + } + testExpected = 59 + testGot = len(testTasklist) + if testGot != testExpected { + t.Errorf("Expected TaskList to contain %d tasks, but got %d", testExpected, testGot) + } + task, err = testTasklist.GetTask(taskId) + if err == nil || task != nil { + t.Errorf("Expected no Task to be found anymore, but got %v", task) + } + + if err := testTasklist.RemoveTask(NewTask()); err == nil { + t.Errorf("Expected no Task to be found for removal") + } } func TestTaskListFilter(t *testing.T) { - t.Fail() -} + if err := testTasklist.LoadFromFilename(testInputTasklist); err != nil { + t.Fatal(err) + } -func TestTaskListFilterNot(t *testing.T) { - t.Fail() + // Filter list to get only completed tasks + completedList := testTasklist.Filter(func(t Task) bool { + if t.Completed { + return true + } + return false + }) + testExpected = 33 + testGot = len(*completedList) + if testGot != testExpected { + t.Errorf("Expected TaskList to contain %d tasks, but got %d", testExpected, testGot) + } + + // Filter list to get only tasks with a due date + dueDateList := testTasklist.Filter(func(t Task) bool { + if t.HasDueDate() { + return true + } + return false + }) + testExpected = 26 + testGot = len(*dueDateList) + if testGot != testExpected { + t.Errorf("Expected TaskList to contain %d tasks, but got %d", testExpected, testGot) + } + + // Filter list to get only tasks with "B" priority + prioBList := testTasklist.Filter(func(t Task) bool { + if t.HasPriority() && t.Priority == "B" { + return true + } + return false + }) + testExpected = 17 + testGot = len(*prioBList) + if testGot != testExpected { + t.Errorf("Expected TaskList to contain %d tasks, but got %d", testExpected, testGot) + } } func TestTaskListReadErrors(t *testing.T) {