added Complete() and Reopen() to Task.
This commit is contained in:
parent
caa944bb71
commit
48dacccdf1
48
example_test.go
Normal file
48
example_test.go
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
package todotxt
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ExampleLoadFromFilename() {
|
||||||
|
if tasklist, err := LoadFromFilename("todo.txt"); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
} else {
|
||||||
|
fmt.Print(tasklist) // String representation of TaskList works as expected.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// (A) Call Mom @Phone +Family
|
||||||
|
// (A) Schedule annual checkup +Health
|
||||||
|
// (B) Outline chapter 5 @Computer +Novel
|
||||||
|
// (C) Add cover sheets @Office +TPSReports
|
||||||
|
// Plan backyard herb garden @Home
|
||||||
|
// Pick up milk @GroceryStore
|
||||||
|
// Research self-publishing services @Computer +Novel
|
||||||
|
// x Download Todo.txt mobile app @Phone
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleTaskList_LoadFromFilename() {
|
||||||
|
var tasklist TaskList
|
||||||
|
|
||||||
|
// This will overwrite whatever was in the tasklist before.
|
||||||
|
// Irrelevant here since the list is still empty.
|
||||||
|
if err := tasklist.LoadFromFilename("todo.txt"); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(tasklist[0].Todo) // Text part of first task (Call Mom)
|
||||||
|
fmt.Println(tasklist[2].Contexts) // Slice of contexts from third task ([Computer])
|
||||||
|
fmt.Println(tasklist[3].Priority) // Priority of fourth task (C)
|
||||||
|
fmt.Println(tasklist[7].Completed) // Completed flag of eigth task (true)
|
||||||
|
// Output:
|
||||||
|
// Call Mom
|
||||||
|
// [Computer]
|
||||||
|
// C
|
||||||
|
// true
|
||||||
|
}
|
24
sort.go
24
sort.go
@ -35,7 +35,7 @@ func (tasklist *TaskList) Sort(sortFlag int) error {
|
|||||||
case SORT_DUE_DATE_ASC, SORT_DUE_DATE_DESC:
|
case SORT_DUE_DATE_ASC, SORT_DUE_DATE_DESC:
|
||||||
tasklist.sortByDueDate(sortFlag)
|
tasklist.sortByDueDate(sortFlag)
|
||||||
default:
|
default:
|
||||||
return errors.New("Unrecognized sort option")
|
return errors.New("unrecognized sort option")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -68,19 +68,17 @@ func (tasklist *TaskList) sortBy(by func(t1, t2 *Task) bool) *TaskList {
|
|||||||
|
|
||||||
func (tasklist *TaskList) sortByPriority(order int) *TaskList {
|
func (tasklist *TaskList) sortByPriority(order int) *TaskList {
|
||||||
tasklist.sortBy(func(t1, t2 *Task) bool {
|
tasklist.sortBy(func(t1, t2 *Task) bool {
|
||||||
if order == SORT_PRIORITY_DESC { // DESC
|
if order == SORT_PRIORITY_ASC { // ASC
|
||||||
if t1.HasPriority() && t2.HasPriority() {
|
|
||||||
return t1.Priority > t2.Priority
|
|
||||||
} else {
|
|
||||||
return !t1.HasPriority()
|
|
||||||
}
|
|
||||||
} else { // ASC
|
|
||||||
if t1.HasPriority() && t2.HasPriority() {
|
if t1.HasPriority() && t2.HasPriority() {
|
||||||
return t1.Priority < t2.Priority
|
return t1.Priority < t2.Priority
|
||||||
} else {
|
}
|
||||||
return t1.HasPriority()
|
return t1.HasPriority()
|
||||||
}
|
}
|
||||||
|
// DESC
|
||||||
|
if t1.HasPriority() && t2.HasPriority() {
|
||||||
|
return t1.Priority > t2.Priority
|
||||||
}
|
}
|
||||||
|
return !t1.HasPriority()
|
||||||
})
|
})
|
||||||
return tasklist
|
return tasklist
|
||||||
}
|
}
|
||||||
@ -89,16 +87,14 @@ func sortByDate(asc bool, hasDate1, hasDate2 bool, date1, date2 time.Time) bool
|
|||||||
if asc { // ASC
|
if asc { // ASC
|
||||||
if hasDate1 && hasDate2 {
|
if hasDate1 && hasDate2 {
|
||||||
return date1.Before(date2)
|
return date1.Before(date2)
|
||||||
} else {
|
}
|
||||||
return hasDate2
|
return hasDate2
|
||||||
}
|
}
|
||||||
} else { // DESC
|
// DESC
|
||||||
if hasDate1 && hasDate2 {
|
if hasDate1 && hasDate2 {
|
||||||
return date1.After(date2)
|
return date1.After(date2)
|
||||||
} else {
|
}
|
||||||
return !hasDate2
|
return !hasDate2
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tasklist *TaskList) sortByCreatedDate(order int) *TaskList {
|
func (tasklist *TaskList) sortByCreatedDate(order int) *TaskList {
|
||||||
|
42
sort_test.go
42
sort_test.go
@ -14,7 +14,9 @@ func TestTaskSortByPriority(t *testing.T) {
|
|||||||
|
|
||||||
testTasklist = testTasklist[taskId : taskId+6]
|
testTasklist = testTasklist[taskId : taskId+6]
|
||||||
|
|
||||||
testTasklist.Sort(SORT_PRIORITY_ASC)
|
if err := testTasklist.Sort(SORT_PRIORITY_ASC); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
testExpected = "(A) 2012-01-30 Call Mom @Call @Phone +Family"
|
testExpected = "(A) 2012-01-30 Call Mom @Call @Phone +Family"
|
||||||
testGot = testTasklist[0].Task()
|
testGot = testTasklist[0].Task()
|
||||||
@ -52,7 +54,9 @@ func TestTaskSortByPriority(t *testing.T) {
|
|||||||
t.Errorf("Expected Task[6] after Sort() to be [%s], but got [%s]", testExpected, testGot)
|
t.Errorf("Expected Task[6] after Sort() to be [%s], but got [%s]", testExpected, testGot)
|
||||||
}
|
}
|
||||||
|
|
||||||
testTasklist.Sort(SORT_PRIORITY_DESC)
|
if err := testTasklist.Sort(SORT_PRIORITY_DESC); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
testExpected = "x 2014-01-03 Create golang library @Go +go-todotxt due:2014-01-05"
|
testExpected = "x 2014-01-03 Create golang library @Go +go-todotxt due:2014-01-05"
|
||||||
testGot = testTasklist[0].Task()
|
testGot = testTasklist[0].Task()
|
||||||
@ -97,7 +101,9 @@ func TestTaskSortByCreatedDate(t *testing.T) {
|
|||||||
|
|
||||||
testTasklist = testTasklist[taskId : taskId+5]
|
testTasklist = testTasklist[taskId : taskId+5]
|
||||||
|
|
||||||
testTasklist.Sort(SORT_CREATED_DATE_ASC)
|
if err := testTasklist.Sort(SORT_CREATED_DATE_ASC); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
testExpected = "x 2014-01-03 Create golang library @Go +go-todotxt due:2014-01-05"
|
testExpected = "x 2014-01-03 Create golang library @Go +go-todotxt due:2014-01-05"
|
||||||
testGot = testTasklist[0].Task()
|
testGot = testTasklist[0].Task()
|
||||||
@ -129,7 +135,9 @@ func TestTaskSortByCreatedDate(t *testing.T) {
|
|||||||
t.Errorf("Expected Task[5] after Sort() to be [%s], but got [%s]", testExpected, testGot)
|
t.Errorf("Expected Task[5] after Sort() to be [%s], but got [%s]", testExpected, testGot)
|
||||||
}
|
}
|
||||||
|
|
||||||
testTasklist.Sort(SORT_CREATED_DATE_DESC)
|
if err := testTasklist.Sort(SORT_CREATED_DATE_DESC); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
testExpected = "x (C) 2014-01-01 Create golang library documentation @Go +go-todotxt due:2014-01-12"
|
testExpected = "x (C) 2014-01-01 Create golang library documentation @Go +go-todotxt due:2014-01-12"
|
||||||
testGot = testTasklist[0].Task()
|
testGot = testTasklist[0].Task()
|
||||||
@ -168,7 +176,9 @@ func TestTaskSortByCompletedDate(t *testing.T) {
|
|||||||
|
|
||||||
testTasklist = testTasklist[taskId : taskId+6]
|
testTasklist = testTasklist[taskId : taskId+6]
|
||||||
|
|
||||||
testTasklist.Sort(SORT_COMPLETED_DATE_ASC)
|
if err := testTasklist.Sort(SORT_COMPLETED_DATE_ASC); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
testExpected = "x Download Todo.txt mobile app @Phone"
|
testExpected = "x Download Todo.txt mobile app @Phone"
|
||||||
testGot = testTasklist[0].Task()
|
testGot = testTasklist[0].Task()
|
||||||
@ -206,7 +216,9 @@ func TestTaskSortByCompletedDate(t *testing.T) {
|
|||||||
t.Errorf("Expected Task[6] after Sort() to be [%s], but got [%s]", testExpected, testGot)
|
t.Errorf("Expected Task[6] after Sort() to be [%s], but got [%s]", testExpected, testGot)
|
||||||
}
|
}
|
||||||
|
|
||||||
testTasklist.Sort(SORT_COMPLETED_DATE_DESC)
|
if err := testTasklist.Sort(SORT_COMPLETED_DATE_DESC); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
testExpected = "x 2014-01-04 2014-01-01 Create some more golang library test cases @Go +go-todotxt"
|
testExpected = "x 2014-01-04 2014-01-01 Create some more golang library test cases @Go +go-todotxt"
|
||||||
testGot = testTasklist[0].Task()
|
testGot = testTasklist[0].Task()
|
||||||
@ -251,7 +263,9 @@ func TestTaskSortByDueDate(t *testing.T) {
|
|||||||
|
|
||||||
testTasklist = testTasklist[taskId : taskId+4]
|
testTasklist = testTasklist[taskId : taskId+4]
|
||||||
|
|
||||||
testTasklist.Sort(SORT_DUE_DATE_ASC)
|
if err := testTasklist.Sort(SORT_DUE_DATE_ASC); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
testExpected = "x 2014-01-02 (B) 2013-12-30 Create golang library test cases @Go +go-todotxt"
|
testExpected = "x 2014-01-02 (B) 2013-12-30 Create golang library test cases @Go +go-todotxt"
|
||||||
testGot = testTasklist[0].Task()
|
testGot = testTasklist[0].Task()
|
||||||
@ -277,7 +291,9 @@ func TestTaskSortByDueDate(t *testing.T) {
|
|||||||
t.Errorf("Expected Task[4] after Sort() to be [%s], but got [%s]", testExpected, testGot)
|
t.Errorf("Expected Task[4] after Sort() to be [%s], but got [%s]", testExpected, testGot)
|
||||||
}
|
}
|
||||||
|
|
||||||
testTasklist.Sort(SORT_DUE_DATE_DESC)
|
if err := testTasklist.Sort(SORT_DUE_DATE_DESC); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
testExpected = "(B) 2013-12-01 Outline chapter 5 @Computer +Novel Level:5 private:false due:2014-02-17"
|
testExpected = "(B) 2013-12-01 Outline chapter 5 @Computer +Novel Level:5 private:false due:2014-02-17"
|
||||||
testGot = testTasklist[0].Task()
|
testGot = testTasklist[0].Task()
|
||||||
@ -303,3 +319,13 @@ func TestTaskSortByDueDate(t *testing.T) {
|
|||||||
t.Errorf("Expected Task[4] after Sort() to be [%s], but got [%s]", testExpected, testGot)
|
t.Errorf("Expected Task[4] after Sort() to be [%s], but got [%s]", testExpected, testGot)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTaskSortError(t *testing.T) {
|
||||||
|
testTasklist.LoadFromFilename(testInputSort)
|
||||||
|
|
||||||
|
if err := testTasklist.Sort(123); err == nil {
|
||||||
|
t.Errorf("Expected Sort() to fail because of unrecognized sort option, but it didn't!")
|
||||||
|
} else if err.Error() != "unrecognized sort option" {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
28
task.go
28
task.go
@ -67,7 +67,7 @@ func (task Task) String() string {
|
|||||||
if len(task.AdditionalTags) > 0 {
|
if len(task.AdditionalTags) > 0 {
|
||||||
// Sort map alphabetically by keys
|
// Sort map alphabetically by keys
|
||||||
keys := make([]string, 0, len(task.AdditionalTags))
|
keys := make([]string, 0, len(task.AdditionalTags))
|
||||||
for key, _ := range task.AdditionalTags {
|
for key := range task.AdditionalTags {
|
||||||
keys = append(keys, key)
|
keys = append(keys, key)
|
||||||
}
|
}
|
||||||
sort.Strings(keys)
|
sort.Strings(keys)
|
||||||
@ -106,7 +106,25 @@ func (task *Task) HasDueDate() bool {
|
|||||||
|
|
||||||
// HasCompletedDate returns true if the task has a completed date.
|
// HasCompletedDate returns true if the task has a completed date.
|
||||||
func (task *Task) HasCompletedDate() bool {
|
func (task *Task) HasCompletedDate() bool {
|
||||||
return !task.CompletedDate.IsZero()
|
return !task.CompletedDate.IsZero() && task.Completed
|
||||||
|
}
|
||||||
|
|
||||||
|
// Complete sets Task.Completed to 'true' if the task was not already completed.
|
||||||
|
// Also sets Task.CompletedDate to time.Now()
|
||||||
|
func (task *Task) Complete() {
|
||||||
|
if !task.Completed {
|
||||||
|
task.Completed = true
|
||||||
|
task.CompletedDate = time.Now()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reopen sets Task.Completed to 'false' if the task was completed.
|
||||||
|
// Also resets Task.CompletedDate.
|
||||||
|
func (task *Task) Reopen() {
|
||||||
|
if task.Completed {
|
||||||
|
task.Completed = false
|
||||||
|
task.CompletedDate = time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC) // time.IsZero() value
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsOverdue returns true if due date is in the past.
|
// IsOverdue returns true if due date is in the past.
|
||||||
@ -116,9 +134,8 @@ func (task *Task) HasCompletedDate() bool {
|
|||||||
func (task *Task) IsOverdue() bool {
|
func (task *Task) IsOverdue() bool {
|
||||||
if task.HasDueDate() {
|
if task.HasDueDate() {
|
||||||
return task.DueDate.Before(time.Now())
|
return task.DueDate.Before(time.Now())
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Due returns the duration passed since due date, or until due date from now.
|
// Due returns the duration passed since due date, or until due date from now.
|
||||||
@ -129,7 +146,6 @@ func (task *Task) IsOverdue() bool {
|
|||||||
func (task *Task) Due() time.Duration {
|
func (task *Task) Due() time.Duration {
|
||||||
if task.IsOverdue() {
|
if task.IsOverdue() {
|
||||||
return time.Now().Sub(task.DueDate)
|
return time.Now().Sub(task.DueDate)
|
||||||
} else {
|
|
||||||
return task.DueDate.Sub(time.Now())
|
|
||||||
}
|
}
|
||||||
|
return task.DueDate.Sub(time.Now())
|
||||||
}
|
}
|
||||||
|
145
task_test.go
145
task_test.go
@ -263,21 +263,21 @@ func TestTaskCompleted(t *testing.T) {
|
|||||||
testExpected = true
|
testExpected = true
|
||||||
testGot = testTasklist[taskId-1].Completed
|
testGot = testTasklist[taskId-1].Completed
|
||||||
if testGot != testExpected {
|
if testGot != testExpected {
|
||||||
t.Errorf("Expected Task[%d] not to be completed, but got '%v'", taskId, testGot)
|
t.Errorf("Expected Task[%d] to be completed, but got '%v'", taskId, testGot)
|
||||||
}
|
}
|
||||||
taskId++
|
taskId++
|
||||||
|
|
||||||
testExpected = true
|
testExpected = true
|
||||||
testGot = testTasklist[taskId-1].Completed
|
testGot = testTasklist[taskId-1].Completed
|
||||||
if testGot != testExpected {
|
if testGot != testExpected {
|
||||||
t.Errorf("Expected Task[%d] not to be completed, but got '%v'", taskId, testGot)
|
t.Errorf("Expected Task[%d] to be completed, but got '%v'", taskId, testGot)
|
||||||
}
|
}
|
||||||
taskId++
|
taskId++
|
||||||
|
|
||||||
testExpected = true
|
testExpected = true
|
||||||
testGot = testTasklist[taskId-1].Completed
|
testGot = testTasklist[taskId-1].Completed
|
||||||
if testGot != testExpected {
|
if testGot != testExpected {
|
||||||
t.Errorf("Expected Task[%d] not to be completed, but got '%v'", taskId, testGot)
|
t.Errorf("Expected Task[%d] to be completed, but got '%v'", taskId, testGot)
|
||||||
}
|
}
|
||||||
taskId++
|
taskId++
|
||||||
|
|
||||||
@ -379,6 +379,145 @@ func TestTaskIsOverdue(t *testing.T) {
|
|||||||
t.Errorf("Expected Task[%d] to be due since 72 hours, but got '%v'", taskId, testGot)
|
t.Errorf("Expected Task[%d] to be due since 72 hours, but got '%v'", taskId, testGot)
|
||||||
}
|
}
|
||||||
taskId++
|
taskId++
|
||||||
|
|
||||||
|
testGot = testTasklist[taskId-1].IsOverdue()
|
||||||
|
if testGot.(bool) {
|
||||||
|
t.Errorf("Expected Task[%d] not to be overdue, but got '%v'", taskId, testGot)
|
||||||
|
}
|
||||||
|
taskId++
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTaskComplete(t *testing.T) {
|
||||||
|
testTasklist.LoadFromFilename(testInputTask)
|
||||||
|
taskId := 44
|
||||||
|
|
||||||
|
// first 4 tasks should all match the same tests
|
||||||
|
for i := 0; i < 4; i++ {
|
||||||
|
testExpected = false
|
||||||
|
testGot = testTasklist[taskId-1].Completed
|
||||||
|
if testGot != testExpected {
|
||||||
|
t.Errorf("Expected Task[%d] not to be completed, but got '%v'", taskId, testGot)
|
||||||
|
}
|
||||||
|
testGot = testTasklist[taskId-1].HasCompletedDate()
|
||||||
|
if testGot != testExpected {
|
||||||
|
t.Errorf("Expected Task[%d] not to have a completed date, but got '%v'", taskId, testGot)
|
||||||
|
}
|
||||||
|
testTasklist[taskId-1].Complete()
|
||||||
|
testExpected = true
|
||||||
|
testGot = testTasklist[taskId-1].Completed
|
||||||
|
if testGot != testExpected {
|
||||||
|
t.Errorf("Expected Task[%d] to be completed, but got '%v'", taskId, testGot)
|
||||||
|
}
|
||||||
|
testGot = testTasklist[taskId-1].HasCompletedDate()
|
||||||
|
if testGot != testExpected {
|
||||||
|
t.Errorf("Expected Task[%d] to have a completed date, but got '%v'", taskId, testGot)
|
||||||
|
}
|
||||||
|
testExpected = time.Now().Format(DateLayout)
|
||||||
|
testGot = testTasklist[taskId-1].CompletedDate.Format(DateLayout)
|
||||||
|
if testGot != testExpected {
|
||||||
|
t.Errorf("Expected Task[%d] to have a completed date of '%v', but got '%v'", taskId, testExpected, testGot)
|
||||||
|
}
|
||||||
|
taskId++
|
||||||
|
}
|
||||||
|
|
||||||
|
testExpected = true
|
||||||
|
testGot = testTasklist[taskId-1].Completed
|
||||||
|
if testGot != testExpected {
|
||||||
|
t.Errorf("Expected Task[%d] to be completed, but got '%v'", taskId, testGot)
|
||||||
|
}
|
||||||
|
testGot = testTasklist[taskId-1].HasCompletedDate()
|
||||||
|
if testGot != testExpected {
|
||||||
|
t.Errorf("Expected Task[%d] to have a completed date, but got '%v'", taskId, testGot)
|
||||||
|
}
|
||||||
|
testTasklist[taskId-1].Complete()
|
||||||
|
testGot = testTasklist[taskId-1].Completed // should be unchanged
|
||||||
|
if testGot != testExpected {
|
||||||
|
t.Errorf("Expected Task[%d] to be completed, but got '%v'", taskId, testGot)
|
||||||
|
}
|
||||||
|
testGot = testTasklist[taskId-1].HasCompletedDate() // should be unchanged
|
||||||
|
if testGot != testExpected {
|
||||||
|
t.Errorf("Expected Task[%d] to have a completed date, but got '%v'", taskId, testGot)
|
||||||
|
}
|
||||||
|
testExpected = "2012-01-01" // should be unchanged
|
||||||
|
testGot = testTasklist[taskId-1].CompletedDate.Format(DateLayout)
|
||||||
|
if testGot != testExpected {
|
||||||
|
t.Errorf("Expected Task[%d] to have a completed date of '%v', but got '%v'", taskId, testExpected, testGot)
|
||||||
|
}
|
||||||
|
taskId++
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTaskReopen(t *testing.T) {
|
||||||
|
testTasklist.LoadFromFilename(testInputTask)
|
||||||
|
taskId := 49
|
||||||
|
|
||||||
|
// the first 2 tasks should match the same tests
|
||||||
|
for i := 0; i < 2; i++ {
|
||||||
|
testExpected = true
|
||||||
|
testGot = testTasklist[taskId-1].Completed
|
||||||
|
if testGot != testExpected {
|
||||||
|
t.Errorf("Expected Task[%d] to be completed, but got '%v'", taskId, testGot)
|
||||||
|
}
|
||||||
|
testExpected = false
|
||||||
|
testGot = testTasklist[taskId-1].HasCompletedDate()
|
||||||
|
if testGot != testExpected {
|
||||||
|
t.Errorf("Expected Task[%d] to have a completed date, but got '%v'", taskId, testGot)
|
||||||
|
}
|
||||||
|
testTasklist[taskId-1].Reopen()
|
||||||
|
testExpected = false
|
||||||
|
testGot = testTasklist[taskId-1].Completed
|
||||||
|
if testGot != testExpected {
|
||||||
|
t.Errorf("Expected Task[%d] to not be completed, but got '%v'", taskId, testGot)
|
||||||
|
}
|
||||||
|
testGot = testTasklist[taskId-1].HasCompletedDate()
|
||||||
|
if testGot != testExpected {
|
||||||
|
t.Errorf("Expected Task[%d] to not have a completed date, but got '%v'", taskId, testGot)
|
||||||
|
}
|
||||||
|
taskId++
|
||||||
|
}
|
||||||
|
|
||||||
|
// the next 3 tasks should all match the same tests
|
||||||
|
for i := 0; i < 3; i++ {
|
||||||
|
testExpected = true
|
||||||
|
testGot = testTasklist[taskId-1].Completed
|
||||||
|
if testGot != testExpected {
|
||||||
|
t.Errorf("Expected Task[%d] to be completed, but got '%v'", taskId, testGot)
|
||||||
|
}
|
||||||
|
testGot = testTasklist[taskId-1].HasCompletedDate()
|
||||||
|
if testGot != testExpected {
|
||||||
|
t.Errorf("Expected Task[%d] to have a completed date, but got '%v'", taskId, testGot)
|
||||||
|
}
|
||||||
|
testTasklist[taskId-1].Reopen()
|
||||||
|
testExpected = false
|
||||||
|
testGot = testTasklist[taskId-1].Completed
|
||||||
|
if testGot != testExpected {
|
||||||
|
t.Errorf("Expected Task[%d] to not be completed, but got '%v'", taskId, testGot)
|
||||||
|
}
|
||||||
|
testGot = testTasklist[taskId-1].HasCompletedDate()
|
||||||
|
if testGot != testExpected {
|
||||||
|
t.Errorf("Expected Task[%d] to not have a completed date, but got '%v'", taskId, testGot)
|
||||||
|
}
|
||||||
|
taskId++
|
||||||
|
}
|
||||||
|
|
||||||
|
testExpected = false
|
||||||
|
testGot = testTasklist[taskId-1].Completed
|
||||||
|
if testGot != testExpected {
|
||||||
|
t.Errorf("Expected Task[%d] to be completed, but got '%v'", taskId, testGot)
|
||||||
|
}
|
||||||
|
testGot = testTasklist[taskId-1].HasCompletedDate()
|
||||||
|
if testGot != testExpected {
|
||||||
|
t.Errorf("Expected Task[%d] to have a completed date, but got '%v'", taskId, testGot)
|
||||||
|
}
|
||||||
|
testTasklist[taskId-1].Reopen()
|
||||||
|
testGot = testTasklist[taskId-1].Completed // should be unchanged
|
||||||
|
if testGot != testExpected {
|
||||||
|
t.Errorf("Expected Task[%d] to be completed, but got '%v'", taskId, testGot)
|
||||||
|
}
|
||||||
|
testGot = testTasklist[taskId-1].HasCompletedDate() // should be unchanged
|
||||||
|
if testGot != testExpected {
|
||||||
|
t.Errorf("Expected Task[%d] to have a completed date, but got '%v'", taskId, testGot)
|
||||||
|
}
|
||||||
|
taskId++
|
||||||
}
|
}
|
||||||
|
|
||||||
func compareSlices(list1 []string, list2 []string) bool {
|
func compareSlices(list1 []string, list2 []string) bool {
|
||||||
|
17
testdata/task_todo.txt
vendored
17
testdata/task_todo.txt
vendored
@ -59,3 +59,20 @@ x 2014-01-03 2014-01-01 Create some more golang library test cases @Go +go-todot
|
|||||||
x 2014-01-04 (B) 2013-12-30 Create golang library @Go +go-todotxt due:2014-01-02
|
x 2014-01-04 (B) 2013-12-30 Create golang library @Go +go-todotxt due:2014-01-02
|
||||||
(B) 2013-12-01 private:false Outline chapter 5 +Novel @Computer due:2017-07-17 Level:5
|
(B) 2013-12-01 private:false Outline chapter 5 +Novel @Computer due:2017-07-17 Level:5
|
||||||
Research self-publishing services +Novel +Novel +Novel due:2014-01-01
|
Research self-publishing services +Novel +Novel +Novel due:2014-01-01
|
||||||
|
x 2014-01-03 2014-01-01 Create some more golang library test cases @Go +go-todotxt
|
||||||
|
|
||||||
|
# Complete test cases
|
||||||
|
Create golang library @Go +go-todotxt due:2014-01-05
|
||||||
|
(A) @Phone Call Mom @Call +Family
|
||||||
|
2014-01-03 Create golang library @Go +go-todotxt due:2014-01-05
|
||||||
|
(B) 2013-12-30 Create golang library test cases @Go +go-todotxt
|
||||||
|
x 2012-01-01 More Go!
|
||||||
|
|
||||||
|
# Reopen test cases
|
||||||
|
x Download Todo.txt mobile app @Phone
|
||||||
|
x (C) 2014-01-01 Create golang library documentation @Go +go-todotxt due:2014-01-12
|
||||||
|
x 2014-01-03 Create golang library @Go +go-todotxt due:2014-01-05
|
||||||
|
x 2014-01-02 (B) 2013-12-30 Create golang library test cases @Go +go-todotxt
|
||||||
|
x 2014-01-03 2014-01-01 Create some more golang library test cases @Go +go-todotxt
|
||||||
|
(B) 2013-12-30 Create golang library test cases @Go +go-todotxt
|
||||||
|
|
||||||
|
6
testdata/tasklist_completedDate_error.txt
vendored
Normal file
6
testdata/tasklist_completedDate_error.txt
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
x (C) 2014-01-01 Create golang library documentation @Go +go-todotxt due:2014-01-12
|
||||||
|
x Download Todo.txt mobile app @Phone
|
||||||
|
x 2014-01-03 Create golang library @Go +go-todotxt due:2014-01-05
|
||||||
|
x (C) 2014-01-01 Create golang library documentation @Go +go-todotxt due:2014-01-12
|
||||||
|
x 2014-01-02 (B) 2013-12-30 Create golang library test cases @Go +go-todotxt
|
||||||
|
x 2014-25-04 2014-01-01 Create some more golang library test cases @Go +go-todotxt
|
5
testdata/tasklist_createdDate_error.txt
vendored
Normal file
5
testdata/tasklist_createdDate_error.txt
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
2013-02-22 Pick up milk @GroceryStore
|
||||||
|
x Download Todo.txt mobile app @Phone
|
||||||
|
(B) 2013-13-01 private:false Outline chapter 5 +Novel @Computer Level:5 due:2014-02-17
|
||||||
|
x 2014-01-02 (B) 2013-12-30 Create golang library test cases @Go +go-todotxt
|
||||||
|
x 2014-01-03 2014-01-01 Create some more golang library test cases @Go +go-todotxt
|
5
testdata/tasklist_dueDate_error.txt
vendored
Normal file
5
testdata/tasklist_dueDate_error.txt
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
B) 2013-12-01 private:false Outline chapter 5 +Novel @Computer Level:5 due:2014-02-17
|
||||||
|
x 2014-01-02 (B) 2013-12-30 Create golang library test cases @Go +go-todotxt
|
||||||
|
x 2014-01-03 2014-01-01 Create some more golang library test cases @Go +go-todotxt
|
||||||
|
(B) 2013-12-01 private:false Outline chapter 5 +Novel @Computer Level:5 due:2014-02-32
|
||||||
|
x (C) 2014-01-01 Create golang library documentation @Go +go-todotxt due:2014-01-12
|
2
testdata/tasklist_scanner_error.txt
vendored
Normal file
2
testdata/tasklist_scanner_error.txt
vendored
Normal file
File diff suppressed because one or more lines are too long
37
todotxt.go
37
todotxt.go
@ -23,12 +23,13 @@ import (
|
|||||||
// It is usually loaded from a whole todo.txt file.
|
// It is usually loaded from a whole todo.txt file.
|
||||||
type TaskList []Task
|
type TaskList []Task
|
||||||
|
|
||||||
// IgnoreComments can be set to 'false', in order to revert to more standard todo.txt behaviour.
|
// IgnoreComments can be set to 'false', in order to revert to a more standard todo.txt behaviour.
|
||||||
// The todo.txt format does not define comments.
|
// The todo.txt format does not define comments.
|
||||||
var (
|
var (
|
||||||
// Used for formatting time.Time into todo.txt date format and vice-versa.
|
// DateLayout is used for formatting time.Time into todo.txt date format and vice-versa.
|
||||||
DateLayout = "2006-01-02"
|
DateLayout = "2006-01-02"
|
||||||
// Ignores comments (Lines/Text starting with "#").
|
// IgnoreComments is used to switch ignoring of comments (lines starting with "#").
|
||||||
|
// If this is set to 'false', then lines starting with "#" will be parsed as tasks.
|
||||||
IgnoreComments = true
|
IgnoreComments = true
|
||||||
|
|
||||||
// unexported vars
|
// unexported vars
|
||||||
@ -74,10 +75,10 @@ func (tasklist *TaskList) LoadFromFile(file *os.File) error {
|
|||||||
task.Completed = true
|
task.Completed = true
|
||||||
// Check for completed date
|
// Check for completed date
|
||||||
if completedDateRx.MatchString(task.Original) {
|
if completedDateRx.MatchString(task.Original) {
|
||||||
if date, err := time.Parse(DateLayout, completedDateRx.FindStringSubmatch(task.Original)[1]); err != nil {
|
if date, err := time.Parse(DateLayout, completedDateRx.FindStringSubmatch(task.Original)[1]); err == nil {
|
||||||
return err
|
|
||||||
} else {
|
|
||||||
task.CompletedDate = date
|
task.CompletedDate = date
|
||||||
|
} else {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,11 +95,11 @@ func (tasklist *TaskList) LoadFromFile(file *os.File) error {
|
|||||||
|
|
||||||
// Check for created date
|
// Check for created date
|
||||||
if createdDateRx.MatchString(task.Original) {
|
if createdDateRx.MatchString(task.Original) {
|
||||||
if date, err := time.Parse(DateLayout, createdDateRx.FindStringSubmatch(task.Original)[2]); err != nil {
|
if date, err := time.Parse(DateLayout, createdDateRx.FindStringSubmatch(task.Original)[2]); err == nil {
|
||||||
return err
|
|
||||||
} else {
|
|
||||||
task.CreatedDate = date
|
task.CreatedDate = date
|
||||||
task.Todo = createdDateRx.ReplaceAllString(task.Todo, "") // Remove from Todo text
|
task.Todo = createdDateRx.ReplaceAllString(task.Todo, "") // Remove from Todo text
|
||||||
|
} else {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,10 +138,10 @@ func (tasklist *TaskList) LoadFromFile(file *os.File) error {
|
|||||||
for _, match := range matches {
|
for _, match := range matches {
|
||||||
key, value := match[2], match[3]
|
key, value := match[2], match[3]
|
||||||
if key == "due" { // due date is a known addon tag, it has its own struct field
|
if key == "due" { // due date is a known addon tag, it has its own struct field
|
||||||
if date, err := time.Parse(DateLayout, value); err != nil {
|
if date, err := time.Parse(DateLayout, value); err == nil {
|
||||||
return err
|
|
||||||
} else {
|
|
||||||
task.DueDate = date
|
task.DueDate = date
|
||||||
|
} else {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
} else if key != "" && value != "" {
|
} else if key != "" && value != "" {
|
||||||
tags[key] = value
|
tags[key] = value
|
||||||
@ -195,8 +196,10 @@ func (tasklist *TaskList) WriteToFilename(filename string) error {
|
|||||||
// Using *os.File instead of a filename allows to also use os.Stdin.
|
// Using *os.File instead of a filename allows to also use os.Stdin.
|
||||||
func LoadFromFile(file *os.File) (TaskList, error) {
|
func LoadFromFile(file *os.File) (TaskList, error) {
|
||||||
tasklist := TaskList{}
|
tasklist := TaskList{}
|
||||||
err := tasklist.LoadFromFile(file)
|
if err := tasklist.LoadFromFile(file); err != nil {
|
||||||
return tasklist, err
|
return nil, err
|
||||||
|
}
|
||||||
|
return tasklist, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteToFile writes a TaskList to *os.File.
|
// WriteToFile writes a TaskList to *os.File.
|
||||||
@ -209,8 +212,10 @@ func WriteToFile(tasklist *TaskList, file *os.File) error {
|
|||||||
// LoadFromFilename loads and returns a TaskList from a file (most likely called "todo.txt").
|
// LoadFromFilename loads and returns a TaskList from a file (most likely called "todo.txt").
|
||||||
func LoadFromFilename(filename string) (TaskList, error) {
|
func LoadFromFilename(filename string) (TaskList, error) {
|
||||||
tasklist := TaskList{}
|
tasklist := TaskList{}
|
||||||
err := tasklist.LoadFromFilename(filename)
|
if err := tasklist.LoadFromFilename(filename); err != nil {
|
||||||
return tasklist, err
|
return nil, err
|
||||||
|
}
|
||||||
|
return tasklist, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteToFilename writes a TaskList to the specified file (most likely called "todo.txt").
|
// WriteToFilename writes a TaskList to the specified file (most likely called "todo.txt").
|
||||||
|
@ -12,6 +12,10 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
testInputTasklist = "testdata/tasklist_todo.txt"
|
testInputTasklist = "testdata/tasklist_todo.txt"
|
||||||
|
testInputTasklistCreatedDateError = "testdata/tasklist_createdDate_error.txt"
|
||||||
|
testInputTasklistDueDateError = "testdata/tasklist_dueDate_error.txt"
|
||||||
|
testInputTasklistCompletedDateError = "testdata/tasklist_completedDate_error.txt"
|
||||||
|
testInputTasklistScannerError = "testdata/tasklist_scanner_error.txt"
|
||||||
testOutput = "testdata/ouput_todo.txt"
|
testOutput = "testdata/ouput_todo.txt"
|
||||||
testExpectedOutput = "testdata/expected_todo.txt"
|
testExpectedOutput = "testdata/expected_todo.txt"
|
||||||
testTasklist TaskList
|
testTasklist TaskList
|
||||||
@ -39,6 +43,10 @@ func TestLoadFromFile(t *testing.T) {
|
|||||||
t.Errorf("Expected TaskList to be [%s], but got [%s]", testExpected, testGot)
|
t.Errorf("Expected TaskList to be [%s], but got [%s]", testExpected, testGot)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if testTasklist, err := LoadFromFile(nil); testTasklist != nil || err == nil {
|
||||||
|
t.Errorf("Expected LoadFromFile to fail, but got TaskList back: [%s]", testTasklist)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLoadFromFilename(t *testing.T) {
|
func TestLoadFromFilename(t *testing.T) {
|
||||||
@ -55,6 +63,10 @@ func TestLoadFromFilename(t *testing.T) {
|
|||||||
t.Errorf("Expected TaskList to be [%s], but got [%s]", testExpected, testGot)
|
t.Errorf("Expected TaskList to be [%s], but got [%s]", testExpected, testGot)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if testTasklist, err := LoadFromFilename("some_file_that_does_not_exists.txt"); testTasklist != nil || err == nil {
|
||||||
|
t.Errorf("Expected LoadFromFilename to fail, but got TaskList back: [%s]", testTasklist)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWriteFile(t *testing.T) {
|
func TestWriteFile(t *testing.T) {
|
||||||
@ -192,7 +204,9 @@ func TestTaskListWriteFilename(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestTaskListCount(t *testing.T) {
|
func TestTaskListCount(t *testing.T) {
|
||||||
testTasklist.LoadFromFilename(testInputTasklist)
|
if err := testTasklist.LoadFromFilename(testInputTasklist); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
testExpected := 63
|
testExpected := 63
|
||||||
testGot := len(testTasklist)
|
testGot := len(testTasklist)
|
||||||
@ -200,3 +214,30 @@ func TestTaskListCount(t *testing.T) {
|
|||||||
t.Errorf("Expected TaskList to contain %d tasks, but got %d", testExpected, testGot)
|
t.Errorf("Expected TaskList to contain %d tasks, but got %d", testExpected, testGot)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTaskListReadErrors(t *testing.T) {
|
||||||
|
if testTasklist, err := LoadFromFilename(testInputTasklistCreatedDateError); testTasklist != nil || err == nil {
|
||||||
|
t.Errorf("Expected LoadFromFilename to fail because of invalid created date, but got TaskList back: [%s]", testTasklist)
|
||||||
|
} else if err.Error() != `parsing time "2013-13-01": month out of range` {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if testTasklist, err := LoadFromFilename(testInputTasklistDueDateError); testTasklist != nil || err == nil {
|
||||||
|
t.Errorf("Expected LoadFromFilename to fail because of invalid due date, but got TaskList back: [%s]", testTasklist)
|
||||||
|
} else if err.Error() != `parsing time "2014-02-32": day out of range` {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if testTasklist, err := LoadFromFilename(testInputTasklistCompletedDateError); testTasklist != nil || err == nil {
|
||||||
|
t.Errorf("Expected LoadFromFilename to fail because of invalid completed date, but got TaskList back: [%s]", testTasklist)
|
||||||
|
} else if err.Error() != `parsing time "2014-25-04": month out of range` {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// really silly test
|
||||||
|
if testTasklist, err := LoadFromFilename(testInputTasklistScannerError); testTasklist != nil || err == nil {
|
||||||
|
t.Errorf("Expected LoadFromFilename to fail because of invalid file, but got TaskList back: [%s]", testTasklist)
|
||||||
|
} else if err.Error() != `bufio.Scanner: token too long` {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user