parsing todo.txt done

This commit is contained in:
jamesclonk@jamesclonk.ch 2014-01-03 20:00:40 +01:00
parent 510c61ffb3
commit 6d32f8e493
7 changed files with 601 additions and 264 deletions

View File

@ -16,6 +16,10 @@ It allows for parsing and manipulating of task lists and tasks in the todo.txt f
go-todotxt requires Go1.1 or higher. go-todotxt requires Go1.1 or higher.
## Usage
...
## Documentation ## Documentation
See [GoDoc - Documentation](https://godoc.org/github.com/JamesClonk/go-todotxt) for further documentation. See [GoDoc - Documentation](https://godoc.org/github.com/JamesClonk/go-todotxt) for further documentation.

21
testdata/example.go vendored Normal file
View File

@ -0,0 +1,21 @@
package main
import (
"fmt"
"github.com/JamesClonk/go-todotxt"
"log"
)
func main() {
todotxt.IgnoreComments = false
tasklist, err := todotxt.LoadFromFilename("../todo.txt")
if err != nil {
log.Fatal(err)
}
fmt.Printf("Task 2, todo: %v\n", tasklist[1].Todo)
fmt.Printf("Task 3: %v\n", tasklist[2])
fmt.Printf("Task 4, has priority: %v\n\n", tasklist[3].HasPriority())
fmt.Print(tasklist)
}

View File

@ -1,10 +1,38 @@
(A) 2012-01-30 Call Mom @Call @Phone +Family
(A) Schedule annual checkup +Health
(B) 2013-12-01 Outline chapter 5 @Computer +Novel Level:5 private:false due:2014-02-17
(C) Add cover sheets @Office +TPSReports
Plan backyard herb garden @Home +Gardening +Improving +Planning
2013-02-22 Pick up milk @GroceryStore 2013-02-22 Pick up milk @GroceryStore
Research self-publishing services +Novel due:2014-01-01
x Download Todo.txt mobile app @Phone x Download Todo.txt mobile app @Phone
(B) 2013-12-01 Outline chapter 5 @Computer +Novel Level:5 private:false 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 Outline chapter 5 @Computer +Novel Level:5 private:false due:2014-02-17
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
Plan backyard herb garden @Home +Gardening +Improving +Planning
(A) 2012-01-30 Call Mom @Call @Phone +Family
2013-02-22 Pick up milk @GroceryStore
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
(C) Add cover sheets @Office +TPSReports
(A) 2012-01-30 Call Mom @Call @Phone +Family
(C) Add cover sheets @Office +TPSReports
Turn off TV @Electricity @Home @Of_Super-Importance @Television Importance:Very!
Research self-publishing services +Novel due:2014-01-01
Plan backyard herb garden @Home +Gardening +Improving +Planning +Relaxing-Work
Research self-publishing services +Novel due:2014-01-01
Turn off TV @Electricity @Home @Television Importance:Very! Turn off TV @Electricity @Home @Television Importance:Very!
(B) 2013-12-01 Outline chapter 5 @Computer +Novel Level:5 private:false due:2014-02-17
x 2014-01-02 (B) 2013-12-30 Create golang library test cases @Go +go-todotxt
(B) 2013-12-01 Outline chapter 5 @Computer +Novel Level:5 private:false due:2014-02-17
Turn off TV @Electricity @Home @Television Importance:Very!
x (C) 2014-01-01 Create golang library documentation @Go +go-todotxt due:2014-01-12
(A) 2012-01-30 Call Mom @Call @Phone +Family
x Create golang library @Go +go-todotxt due:2014-01-05
x 2014-01-03 Create golang library @Go +go-todotxt due:2014-01-05 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
xylophone lesson
X 2012-01-01 Make resolutions
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-01-03 2014-01-01 Create some more golang library test cases @Go +go-todotxt
2013-02-22 Pick up milk @GroceryStore

View File

@ -21,11 +21,11 @@ x 2014-01-03 2014-01-01 Create some more golang library test cases @Go +go-todot
# Contexts test cases # Contexts test cases
(A) 2012-01-30 @Phone Call Mom @Call +Family (A) 2012-01-30 @Phone Call Mom @Call +Family
(C) Add cover sheets @Office +TPSReports (C) Add cover sheets @Office +TPSReports
@Home Turn off TV @Electricity @Television @Electricity Importance:Very! @Home Turn off TV @Electricity @Television @Electricity @Of_Super-Importance Importance:Very!
Research self-publishing services +Novel +Novel +Novel due:2014-01-01 Research self-publishing services +Novel +Novel +Novel due:2014-01-01
# Projects test cases # Projects test cases
+Gardening Plan backyard herb garden +Planning @Home +Improving +Gardening Plan backyard herb garden +Planning @Home +Improving +Relaxing-Work
Research self-publishing services +Novel +Novel +Novel due:2014-01-01 Research self-publishing services +Novel +Novel +Novel due:2014-01-01
@Home Turn off TV @Electricity @Television @Electricity Importance:Very! @Home Turn off TV @Electricity @Television @Electricity Importance:Very!
@ -52,3 +52,4 @@ 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 (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-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 x 2014-01-03 2014-01-01 Create some more golang library test cases @Go +go-todotxt
2013-02-22 Pick up milk @GroceryStore

38
testdata/ouput_todo.txt vendored Normal file
View File

@ -0,0 +1,38 @@
2013-02-22 Pick up milk @GroceryStore
x Download Todo.txt mobile app @Phone
(B) 2013-12-01 Outline chapter 5 @Computer +Novel Level:5 private:false 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 Outline chapter 5 @Computer +Novel Level:5 private:false due:2014-02-17
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
Plan backyard herb garden @Home +Gardening +Improving +Planning
(A) 2012-01-30 Call Mom @Call @Phone +Family
2013-02-22 Pick up milk @GroceryStore
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
(C) Add cover sheets @Office +TPSReports
(A) 2012-01-30 Call Mom @Call @Phone +Family
(C) Add cover sheets @Office +TPSReports
Turn off TV @Electricity @Home @Of_Super-Importance @Television Importance:Very!
Research self-publishing services +Novel due:2014-01-01
Plan backyard herb garden @Home +Gardening +Improving +Planning +Relaxing-Work
Research self-publishing services +Novel due:2014-01-01
Turn off TV @Electricity @Home @Television Importance:Very!
(B) 2013-12-01 Outline chapter 5 @Computer +Novel Level:5 private:false due:2014-02-17
x 2014-01-02 (B) 2013-12-30 Create golang library test cases @Go +go-todotxt
(B) 2013-12-01 Outline chapter 5 @Computer +Novel Level:5 private:false due:2014-02-17
Turn off TV @Electricity @Home @Television Importance:Very!
x (C) 2014-01-01 Create golang library documentation @Go +go-todotxt due:2014-01-12
(A) 2012-01-30 Call Mom @Call @Phone +Family
x Create golang library @Go +go-todotxt due:2014-01-05
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
xylophone lesson
X 2012-01-01 Make resolutions
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-01-03 2014-01-01 Create some more golang library test cases @Go +go-todotxt
2013-02-22 Pick up milk @GroceryStore

View File

@ -11,6 +11,7 @@ package todotxt
import ( import (
"bufio" "bufio"
"fmt" "fmt"
"io/ioutil"
"os" "os"
"regexp" "regexp"
"sort" "sort"
@ -20,12 +21,12 @@ import (
// Task represents a todo.txt task entry. // Task represents a todo.txt task entry.
type Task struct { type Task struct {
Original string // Original raw task text Original string // Original raw task text.
Todo string // Todo part of task text Todo string // Todo part of task text.
Priority string Priority string
Projects []string Projects []string
Contexts []string Contexts []string
AdditionalTags map[string]string // Addon tags will be available here AdditionalTags map[string]string // Addon tags will be available here.
CreatedDate time.Time CreatedDate time.Time
DueDate time.Time DueDate time.Time
CompletedDate time.Time CompletedDate time.Time
@ -36,14 +37,19 @@ type Task struct {
// 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.
// The todo.txt format does not define comments.
var ( var (
// Used for formatting time.Time into todo.txt date format. // 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 = true
// unexported vars // unexported vars
priorityRx = regexp.MustCompile(`^(x|x \d{4}-\d{2}-\d{2}|)\s*\(([A-Z])\)\s+`) // Match priority: '(A) ...' or 'x (A) ...' or 'x 2012-12-12 (A) ...' priorityRx = regexp.MustCompile(`^(x|x \d{4}-\d{2}-\d{2}|)\s*\(([A-Z])\)\s+`) // Match priority: '(A) ...' or 'x (A) ...' or 'x 2012-12-12 (A) ...'
// Match created date: '(A) 2012-12-12 ...' or 'x 2012-12-12 (A) 2012-12-12 ...' or 'x 2012-12-12 2012-12-12 ...' or '2012-12-12 ...' // Match created date: '(A) 2012-12-12 ...' or 'x 2012-12-12 (A) 2012-12-12 ...' or 'x 2012-12-12 2012-12-12 ...' or '2012-12-12 ...'
createdDateRx = regexp.MustCompile(`^(\([A-Z]\)|x \d{4}-\d{2}-\d{2} \([A-Z]\)|x \d{4}-\d{2}-\d{2}|)\s*(\d{4}-\d{2}-\d{2})\s+`) createdDateRx = regexp.MustCompile(`^(\([A-Z]\)|x \d{4}-\d{2}-\d{2} \([A-Z]\)|x \d{4}-\d{2}-\d{2}|)\s*(\d{4}-\d{2}-\d{2})\s+`)
completedRx = regexp.MustCompile(`^x\s+`) // Match completed: 'x ...'
completedDateRx = regexp.MustCompile(`^x\s*(\d{4}-\d{2}-\d{2})\s+`) // Match completed date: 'x 2012-12-12 ...' completedDateRx = regexp.MustCompile(`^x\s*(\d{4}-\d{2}-\d{2})\s+`) // Match completed date: 'x 2012-12-12 ...'
addonTagRx = regexp.MustCompile(`(^|\s+)([\w-]+):(\S+)`) // Match additional tags date: '... due:2012-12-12 ...' addonTagRx = regexp.MustCompile(`(^|\s+)([\w-]+):(\S+)`) // Match additional tags date: '... due:2012-12-12 ...'
contextRx = regexp.MustCompile(`(^|\s+)@(\S+)`) // Match contexts: '@Context ...' or '... @Context ...' contextRx = regexp.MustCompile(`(^|\s+)@(\S+)`) // Match contexts: '@Context ...' or '... @Context ...'
@ -51,8 +57,8 @@ var (
) )
// String returns a complete tasklist string in todo.txt format. // String returns a complete tasklist string in todo.txt format.
func (tasklist *TaskList) String() (text string) { func (tasklist TaskList) String() (text string) {
for _, task := range *tasklist { for _, task := range tasklist {
text += fmt.Sprintf("%s\n", task.String()) text += fmt.Sprintf("%s\n", task.String())
} }
return text return text
@ -66,7 +72,7 @@ func (tasklist *TaskList) String() (text string) {
// //
// For example: // For example:
// "(A) 2013-07-23 Call Dad @Home @Phone +Family due:2013-07-31 customTag1:Important!" // "(A) 2013-07-23 Call Dad @Home @Phone +Family due:2013-07-31 customTag1:Important!"
func (task *Task) String() string { func (task Task) String() string {
var text string var text string
if task.Completed { if task.Completed {
@ -154,15 +160,16 @@ func (tasklist *TaskList) LoadFromFile(file *os.File) error {
scanner := bufio.NewScanner(file) scanner := bufio.NewScanner(file)
for scanner.Scan() { for scanner.Scan() {
task := Task{} task := Task{}
task.Original = scanner.Text() task.Original = strings.Trim(scanner.Text(), "\t\n\r ") // Read line
task.Todo = task.Original
// Ignore blank or comment lines // Ignore blank or comment lines
if strings.Trim(task.Original, "\t\n\r ") == "" || strings.HasPrefix(task.Original, "#") { if task.Todo == "" || (IgnoreComments && strings.HasPrefix(task.Todo, "#")) {
continue continue
} }
// Check for completed // Check for completed
if strings.HasPrefix(task.Original, "x ") { if completedRx.MatchString(task.Original) {
task.Completed = true task.Completed = true
// Check for completed date // Check for completed date
if completedDateRx.MatchString(task.Original) { if completedDateRx.MatchString(task.Original) {
@ -172,11 +179,16 @@ func (tasklist *TaskList) LoadFromFile(file *os.File) error {
task.CompletedDate = date task.CompletedDate = date
} }
} }
// Remove from Todo text
task.Todo = completedDateRx.ReplaceAllString(task.Todo, "") // Strip CompletedDate first, otherwise it wouldn't match anymore (^x date...)
task.Todo = completedRx.ReplaceAllString(task.Todo, "") // Strip 'x '
} }
// Check for priority // Check for priority
if priorityRx.MatchString(task.Original) { if priorityRx.MatchString(task.Original) {
task.Priority = priorityRx.FindStringSubmatch(task.Original)[2] task.Priority = priorityRx.FindStringSubmatch(task.Original)[2]
task.Todo = priorityRx.ReplaceAllString(task.Todo, "") // Remove from Todo text
} }
// Check for created date // Check for created date
@ -185,6 +197,7 @@ func (tasklist *TaskList) LoadFromFile(file *os.File) error {
return err return err
} else { } else {
task.CreatedDate = date task.CreatedDate = date
task.Todo = createdDateRx.ReplaceAllString(task.Todo, "") // Remove from Todo text
} }
} }
@ -207,11 +220,13 @@ func (tasklist *TaskList) LoadFromFile(file *os.File) error {
// Check for contexts // Check for contexts
if contextRx.MatchString(task.Original) { if contextRx.MatchString(task.Original) {
task.Contexts = getSlice(contextRx) task.Contexts = getSlice(contextRx)
task.Todo = contextRx.ReplaceAllString(task.Todo, "") // Remove from Todo text
} }
// Check for projects // Check for projects
if projectRx.MatchString(task.Original) { if projectRx.MatchString(task.Original) {
task.Projects = getSlice(projectRx) task.Projects = getSlice(projectRx)
task.Todo = projectRx.ReplaceAllString(task.Todo, "") // Remove from Todo text
} }
// Check for additional tags // Check for additional tags
@ -231,20 +246,11 @@ func (tasklist *TaskList) LoadFromFile(file *os.File) error {
} }
} }
task.AdditionalTags = tags task.AdditionalTags = tags
task.Todo = addonTagRx.ReplaceAllString(task.Todo, "") // Remove from Todo text
} }
text := task.Original // Trim any remaining whitespaces from Todo text
if task.Completed { task.Todo = strings.Trim(task.Todo, "\t\n\r\f ")
text = text[2:] // Strip 'x '
text = completedDateRx.ReplaceAllString(text, "")
}
// Remove all matching regular expressions from text, so only the actual todo text is left
text = priorityRx.ReplaceAllString(text, "")
text = createdDateRx.ReplaceAllString(text, "")
text = contextRx.ReplaceAllString(text, "")
text = projectRx.ReplaceAllString(text, "")
text = addonTagRx.ReplaceAllString(text, "")
task.Todo = strings.Trim(text, "\t\n\r\f ")
*tasklist = append(*tasklist, task) *tasklist = append(*tasklist, task)
} }
@ -255,6 +261,16 @@ func (tasklist *TaskList) LoadFromFile(file *os.File) error {
return nil return nil
} }
// WriteToFile writes a TaskList to *os.File.
//
// Using *os.File instead of a filename allows to also use os.Stdout.
func (tasklist *TaskList) WriteToFile(file *os.File) error {
writer := bufio.NewWriter(file)
_, err := writer.WriteString(tasklist.String())
writer.Flush()
return err
}
// LoadFromFilename loads a TaskList from a file (most likely called "todo.txt"). // LoadFromFilename loads a TaskList from a file (most likely called "todo.txt").
// //
// Note: This will clear the current TaskList and overwrite it's contents with whatever is in the file. // Note: This will clear the current TaskList and overwrite it's contents with whatever is in the file.
@ -268,18 +284,35 @@ func (tasklist *TaskList) LoadFromFilename(filename string) error {
return tasklist.LoadFromFile(file) return tasklist.LoadFromFile(file)
} }
// WriteToFilename writes a TaskList to the specified file (most likely called "todo.txt").
func (tasklist *TaskList) WriteToFilename(filename string) error {
return ioutil.WriteFile(filename, []byte(tasklist.String()), 0644)
}
// LoadFromFile loads and returns a TaskList from *os.File. // LoadFromFile loads and returns a TaskList from *os.File.
// //
// 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) err := tasklist.LoadFromFile(file)
return tasklist, err return tasklist, err
} }
// WriteToFile writes a TaskList to *os.File.
//
// Using *os.File instead of a filename allows to also use os.Stdout.
func WriteToFile(tasklist *TaskList, file *os.File) error {
return tasklist.WriteToFile(file)
}
// 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) err := tasklist.LoadFromFilename(filename)
return tasklist, err return tasklist, err
} }
// WriteToFilename writes a TaskList to the specified file (most likely called "todo.txt").
func WriteToFilename(tasklist *TaskList, filename string) error {
return tasklist.WriteToFilename(filename)
}

View File

@ -11,308 +11,520 @@ import (
"time" "time"
) )
var (
testInput = "testdata/input_todo.txt"
testOutput = "testdata/ouput_todo.txt"
testExpectedOutput = "testdata/expected_todo.txt"
testTasklist TaskList
testExpected interface{}
testGot interface{}
)
func TestLoadFromFile(t *testing.T) { func TestLoadFromFile(t *testing.T) {
file, err := os.Open("testdata/input_todo.txt") file, err := os.Open(testInput)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer file.Close() defer file.Close()
if tasklist, err := LoadFromFile(file); err != nil { if testTasklist, err := LoadFromFile(file); err != nil {
t.Fatal(err) t.Fatal(err)
} else { } else {
loadTest(t, *tasklist) data, err := ioutil.ReadFile(testExpectedOutput)
if err != nil {
t.Fatal(err)
}
testExpected := string(data)
testGot := testTasklist.String()
if testGot != testExpected {
t.Errorf("Expected TaskList to be [%s], but got [%s]", testExpected, testGot)
}
} }
} }
func TestLoadFromFilename(t *testing.T) { func TestLoadFromFilename(t *testing.T) {
if tasklist, err := LoadFromFilename("testdata/input_todo.txt"); err != nil { if testTasklist, err := LoadFromFilename(testInput); err != nil {
t.Fatal(err) t.Fatal(err)
} else { } else {
loadTest(t, *tasklist) data, err := ioutil.ReadFile(testExpectedOutput)
if err != nil {
t.Fatal(err)
}
testExpected := string(data)
testGot := testTasklist.String()
if testGot != testExpected {
t.Errorf("Expected TaskList to be [%s], but got [%s]", testExpected, testGot)
}
} }
} }
func loadTest(t *testing.T, tasklist TaskList) { func TestWriteFile(t *testing.T) {
taskId := 1 os.Remove(testOutput)
var expected, got interface{} os.Create(testOutput)
var err error var err error
// ------------------------------------------------------------------------------------- fileInput, err := os.Open(testInput)
// complete tasklist string
data, err := ioutil.ReadFile("testdata/expected_todo.txt")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
expected = string(data) defer fileInput.Close()
got = tasklist.String() fileOutput, err := os.OpenFile(testOutput, os.O_RDWR, 0644)
if got != expected {
//t.Errorf("Expected TaskList to be [%s], but got [%s]", expected, got)--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
}
// -------------------------------------------------------------------------------------
// count tasks
expected = 10
got = len(tasklist)
if got != expected {
t.Errorf("Expected TaskList to contain %d tasks, but got %d", expected, got)
}
// -------------------------------------------------------------------------------------
// complete task strings
expected = "2013-02-22 Pick up milk @GroceryStore"
got = tasklist[taskId-1].String()
if got != expected {
t.Errorf("Expected Task[%d] to be [%s], but got [%s]", taskId, expected, got)
}
taskId++
expected = "x Download Todo.txt mobile app @Phone"
got = tasklist[taskId-1].String()
if got != expected {
t.Errorf("Expected Task[%d] to be [%s], but got [%s]", taskId, expected, got)
}
taskId++
expected = "(B) 2013-12-01 Outline chapter 5 @Computer +Novel Level:5 private:false due:2014-02-17"
got = tasklist[taskId-1].Task()
if got != expected {
t.Errorf("Expected Task[%d] to be [%s], but got [%s]", taskId, expected, got)
}
taskId++
expected = "x 2014-01-02 (B) 2013-12-30 Create golang library test cases @Go +go-todotxt"
got = tasklist[taskId-1].Task()
if got != expected {
t.Errorf("Expected Task[%d] to be [%s], but got [%s]", taskId, expected, got)
}
expected = "1"
got = tasklist[taskId-1].Todo
if got != expected {
t.Errorf("Expected Task[%d] to be [%s], but got [%s]", taskId, expected, got)
}
taskId++
expected = "x 2014-01-03 2014-01-01 Create some more golang library test cases @Go +go-todotxt"
got = tasklist[taskId-1].Task()
if got != expected {
t.Errorf("Expected Task[%d] to be [%s], but got [%s]", taskId, expected, got)
}
taskId++
// -------------------------------------------------------------------------------------
// task priority
expected = "B"
got = tasklist[taskId-1].Priority
if got != expected {
t.Errorf("Expected Task[%d] to have priority '%s', but got '%s'", taskId, expected, got)
}
taskId++
expected = "C"
got = tasklist[taskId-1].Priority
if got != expected {
t.Errorf("Expected Task[%d] to have priority '%s', but got '%s'", taskId, expected, got)
}
taskId++
expected = "B"
got = tasklist[taskId-1].Priority
if got != expected {
t.Errorf("Expected Task[%d] to have priority '%s', but got '%s'", taskId, expected, got)
}
taskId++
if tasklist[taskId-1].HasPriority() {
t.Errorf("Expected Task[%d] to have no priority, but got '%s'", taskId, tasklist[4].Priority)
}
taskId++
// -------------------------------------------------------------------------------------
// task created date
expected, err = time.Parse(DateLayout, "2012-01-30")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
got = tasklist[taskId-1].CreatedDate defer fileInput.Close()
if got != expected {
t.Errorf("Expected Task[%d] to have created date '%s', but got '%v'", taskId, expected, got)
}
taskId++
expected, err = time.Parse(DateLayout, "2013-02-22") if testTasklist, err = LoadFromFile(fileInput); err != nil {
t.Fatal(err)
}
if err = WriteToFile(&testTasklist, fileOutput); err != nil {
t.Fatal(err)
}
fileInput.Close()
fileOutput, err = os.Open(testOutput)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
got = tasklist[taskId-1].CreatedDate if testTasklist, err = LoadFromFile(fileOutput); err != nil {
if got != expected { t.Fatal(err)
t.Errorf("Expected Task[%d] to have created date '%s', but got '%v'", taskId, expected, got)
} }
taskId++
expected, err = time.Parse(DateLayout, "2013-12-30") data, err := ioutil.ReadFile(testExpectedOutput)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
got = tasklist[taskId-1].CreatedDate testExpected := string(data)
if got != expected { testGot := testTasklist.String()
t.Errorf("Expected Task[%d] to have created date '%s', but got '%v'", taskId, expected, got) if testGot != testExpected {
t.Errorf("Expected TaskList to be [%s], but got [%s]", testExpected, testGot)
}
} }
taskId++
expected, err = time.Parse(DateLayout, "2014-01-01") func TestTaskListWriteFile(t *testing.T) {
os.Remove(testOutput)
os.Create(testOutput)
testTasklist := TaskList{}
fileInput, err := os.Open(testInput)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
got = tasklist[taskId-1].CreatedDate defer fileInput.Close()
if got != expected { fileOutput, err := os.OpenFile(testOutput, os.O_RDWR, 0644)
t.Errorf("Expected Task[%d] to have created date '%s', but got '%v'", taskId, expected, got)
}
taskId++
if tasklist[taskId-1].HasCreatedDate() {
t.Errorf("Expected Task[%d] to have no created date, but got '%v'", taskId, tasklist[4].CreatedDate)
}
taskId++
// -------------------------------------------------------------------------------------
// task contexts
expected = []string{"Call", "Phone"}
got = tasklist[taskId-1].Contexts
if !compareSlices(got.([]string), expected.([]string)) {
t.Errorf("Expected Task[%d] to have contexts '%v', but got '%v'", taskId, expected, got)
}
taskId++
expected = []string{"Office"}
got = tasklist[taskId-1].Contexts
if !compareSlices(got.([]string), expected.([]string)) {
t.Errorf("Expected Task[%d] to have contexts '%v', but got '%v'", taskId, expected, got)
}
taskId++
expected = []string{"Electricity", "Home", "Television"}
got = tasklist[taskId-1].Contexts
if !compareSlices(got.([]string), expected.([]string)) {
t.Errorf("Expected Task[%d] to have contexts '%v', but got '%v'", taskId, expected, got)
}
taskId++
expected = []string{}
got = tasklist[taskId-1].Contexts
if !compareSlices(got.([]string), expected.([]string)) {
t.Errorf("Expected Task[%d] to have no contexts, but got '%v'", taskId, got)
}
taskId++
// -------------------------------------------------------------------------------------
// task projects
expected = []string{"Gardening", "Improving", "Planning"}
got = tasklist[taskId-1].Projects
if !compareSlices(got.([]string), expected.([]string)) {
t.Errorf("Expected Task[%d] to have projects '%v', but got '%v'", taskId, expected, got)
}
taskId++
expected = []string{"Novel"}
got = tasklist[taskId-1].Projects
if !compareSlices(got.([]string), expected.([]string)) {
t.Errorf("Expected Task[%d] to have projects '%v', but got '%v'", taskId, expected, got)
}
taskId++
expected = []string{}
got = tasklist[taskId-1].Projects
if !compareSlices(got.([]string), expected.([]string)) {
t.Errorf("Expected Task[%d] to have no projects, but got '%v'", taskId, got)
}
taskId++
// -------------------------------------------------------------------------------------
// task due date
expected, err = time.Parse(DateLayout, "2014-02-17")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
got = tasklist[taskId-1].DueDate defer fileInput.Close()
if got != expected {
t.Errorf("Expected Task[%d] to have due date '%s', but got '%v'", taskId, expected, got) if err := testTasklist.LoadFromFile(fileInput); err != nil {
t.Fatal(err)
}
if err := testTasklist.WriteToFile(fileOutput); err != nil {
t.Fatal(err)
}
fileInput.Close()
fileOutput, err = os.Open(testOutput)
if err != nil {
t.Fatal(err)
}
if err := testTasklist.LoadFromFile(fileOutput); err != nil {
t.Fatal(err)
}
data, err := ioutil.ReadFile(testExpectedOutput)
if err != nil {
t.Fatal(err)
}
testExpected := string(data)
testGot := testTasklist.String()
if testGot != testExpected {
t.Errorf("Expected TaskList to be [%s], but got [%s]", testExpected, testGot)
}
}
func TestWriteFilename(t *testing.T) {
os.Remove(testOutput)
var err error
if testTasklist, err = LoadFromFilename(testInput); err != nil {
t.Fatal(err)
}
if err = WriteToFilename(&testTasklist, testOutput); err != nil {
t.Fatal(err)
}
if testTasklist, err = LoadFromFilename(testOutput); err != nil {
t.Fatal(err)
}
data, err := ioutil.ReadFile(testExpectedOutput)
if err != nil {
t.Fatal(err)
}
testExpected := string(data)
testGot := testTasklist.String()
if testGot != testExpected {
t.Errorf("Expected TaskList to be [%s], but got [%s]", testExpected, testGot)
}
}
func TestTaskListWriteFilename(t *testing.T) {
os.Remove(testOutput)
testTasklist := TaskList{}
if err := testTasklist.LoadFromFilename(testInput); err != nil {
t.Fatal(err)
}
if err := testTasklist.WriteToFilename(testOutput); err != nil {
t.Fatal(err)
}
if err := testTasklist.LoadFromFilename(testOutput); err != nil {
t.Fatal(err)
}
data, err := ioutil.ReadFile(testExpectedOutput)
if err != nil {
t.Fatal(err)
}
testExpected := string(data)
testGot := testTasklist.String()
if testGot != testExpected {
t.Errorf("Expected TaskList to be [%s], but got [%s]", testExpected, testGot)
}
}
func TestTaskListCount(t *testing.T) {
testTasklist.LoadFromFilename(testInput)
testExpected := 38
testGot := len(testTasklist)
if testGot != testExpected {
t.Errorf("Expected TaskList to contain %d tasks, but got %d", testExpected, testGot)
}
}
func TestTaskString(t *testing.T) {
testTasklist.LoadFromFilename(testInput)
taskId := 1
testExpected = "2013-02-22 Pick up milk @GroceryStore"
testGot = testTasklist[taskId-1].String()
if testGot != testExpected {
t.Errorf("Expected Task[%d] to be [%s], but got [%s]", taskId, testExpected, testGot)
} }
taskId++ taskId++
if tasklist[taskId-1].HasDueDate() { testExpected = "x Download Todo.txt mobile app @Phone"
t.Errorf("Expected Task[%d] to have no due date, but got '%v'", taskId, tasklist[taskId-1].DueDate) testGot = testTasklist[taskId-1].String()
if testGot != testExpected {
t.Errorf("Expected Task[%d] to be [%s], but got [%s]", taskId, testExpected, testGot)
} }
taskId++ taskId++
// ------------------------------------------------------------------------------------- testExpected = "(B) 2013-12-01 Outline chapter 5 @Computer +Novel Level:5 private:false due:2014-02-17"
// task addon tags testGot = testTasklist[taskId-1].Task()
expected = map[string]string{"Level": "5", "private": "false"} if testGot != testExpected {
got = tasklist[taskId-1].AdditionalTags t.Errorf("Expected Task[%d] to be [%s], but got [%s]", taskId, testExpected, testGot)
if len(got.(map[string]string)) != 2 ||
!compareMaps(got.(map[string]string), expected.(map[string]string)) {
t.Errorf("Expected Task[%d] to have addon tags '%v', but got '%v'", taskId, expected, got)
} }
taskId++ taskId++
expected = map[string]string{"Importance": "Very!"} testExpected = "x 2014-01-02 (B) 2013-12-30 Create golang library test cases @Go +go-todotxt"
got = tasklist[taskId-1].AdditionalTags testGot = testTasklist[taskId-1].Task()
if len(got.(map[string]string)) != 1 || if testGot != testExpected {
!compareMaps(got.(map[string]string), expected.(map[string]string)) { t.Errorf("Expected Task[%d] to be [%s], but got [%s]", taskId, testExpected, testGot)
t.Errorf("Expected Task[%d] to have projects '%v', but got '%v'", taskId, expected, got)
} }
taskId++ taskId++
expected = map[string]string{} testExpected = "x 2014-01-03 2014-01-01 Create some more golang library test cases @Go +go-todotxt"
got = tasklist[taskId-1].AdditionalTags testGot = testTasklist[taskId-1].Task()
if len(got.(map[string]string)) != 0 || if testGot != testExpected {
!compareMaps(got.(map[string]string), expected.(map[string]string)) { t.Errorf("Expected Task[%d] to be [%s], but got [%s]", taskId, testExpected, testGot)
t.Errorf("Expected Task[%d] to have no additional tags, but got '%v'", taskId, got) }
taskId++
}
func TestTaskPriority(t *testing.T) {
testTasklist.LoadFromFilename(testInput)
taskId := 6
testExpected = "B"
testGot = testTasklist[taskId-1].Priority
if testGot != testExpected {
t.Errorf("Expected Task[%d] to have priority '%s', but got '%s'", taskId, testExpected, testGot)
} }
taskId++ taskId++
expected = map[string]string{} testExpected = "C"
got = tasklist[taskId-1].AdditionalTags testGot = testTasklist[taskId-1].Priority
if len(got.(map[string]string)) != 0 || if testGot != testExpected {
!compareMaps(got.(map[string]string), expected.(map[string]string)) { t.Errorf("Expected Task[%d] to have priority '%s', but got '%s'", taskId, testExpected, testGot)
t.Errorf("Expected Task[%d] to have no additional tags, but got '%v'", taskId, got)
} }
taskId++ taskId++
// ------------------------------------------------------------------------------------- testExpected = "B"
// task completed testGot = testTasklist[taskId-1].Priority
expected = true if testGot != testExpected {
got = tasklist[taskId-1].Completed t.Errorf("Expected Task[%d] to have priority '%s', but got '%s'", taskId, testExpected, testGot)
if got != expected {
t.Errorf("Expected Task[%d] to be completed, but got '%v'", taskId, got)
} }
taskId++ taskId++
expected = true if testTasklist[taskId-1].HasPriority() {
got = tasklist[taskId-1].Completed t.Errorf("Expected Task[%d] to have no priority, but got '%s'", taskId, testTasklist[4].Priority)
if got != expected { }
t.Errorf("Expected Task[%d] to be completed, but got '%v'", taskId, got) taskId++
}
func TestTaskCreatedDate(t *testing.T) {
testTasklist.LoadFromFilename(testInput)
taskId := 10
testExpected, err := time.Parse(DateLayout, "2012-01-30")
if err != nil {
t.Fatal(err)
}
testGot = testTasklist[taskId-1].CreatedDate
if testGot != testExpected {
t.Errorf("Expected Task[%d] to have created date '%s', but got '%v'", taskId, testExpected, testGot)
} }
taskId++ taskId++
expected = true testExpected, err = time.Parse(DateLayout, "2013-02-22")
got = tasklist[taskId-1].Completed if err != nil {
if got != expected { t.Fatal(err)
t.Errorf("Expected Task[%d] to be completed, but got '%v'", taskId, got) }
testGot = testTasklist[taskId-1].CreatedDate
if testGot != testExpected {
t.Errorf("Expected Task[%d] to have created date '%s', but got '%v'", taskId, testExpected, testGot)
} }
taskId++ taskId++
expected = false testExpected, err = time.Parse(DateLayout, "2013-12-30")
got = tasklist[taskId-1].Completed if err != nil {
if got != expected { t.Fatal(err)
t.Errorf("Expected Task[%d] to not be completed, but got '%v'", taskId, got) }
testGot = testTasklist[taskId-1].CreatedDate
if testGot != testExpected {
t.Errorf("Expected Task[%d] to have created date '%s', but got '%v'", taskId, testExpected, testGot)
} }
taskId++ taskId++
expected = false testExpected, err = time.Parse(DateLayout, "2014-01-01")
got = tasklist[taskId-1].Completed if err != nil {
if got != expected { t.Fatal(err)
t.Errorf("Expected Task[%d] to not be completed, but got '%v'", taskId, got) }
testGot = testTasklist[taskId-1].CreatedDate
if testGot != testExpected {
t.Errorf("Expected Task[%d] to have created date '%s', but got '%v'", taskId, testExpected, testGot)
}
taskId++
if testTasklist[taskId-1].HasCreatedDate() {
t.Errorf("Expected Task[%d] to have no created date, but got '%v'", taskId, testTasklist[4].CreatedDate)
}
taskId++
}
func TestTaskContexts(t *testing.T) {
testTasklist.LoadFromFilename(testInput)
taskId := 15
testExpected = []string{"Call", "Phone"}
testGot = testTasklist[taskId-1].Contexts
if !compareSlices(testGot.([]string), testExpected.([]string)) {
t.Errorf("Expected Task[%d] to have contexts '%v', but got '%v'", taskId, testExpected, testGot)
}
taskId++
testExpected = []string{"Office"}
testGot = testTasklist[taskId-1].Contexts
if !compareSlices(testGot.([]string), testExpected.([]string)) {
t.Errorf("Expected Task[%d] to have contexts '%v', but got '%v'", taskId, testExpected, testGot)
}
taskId++
testExpected = []string{"Electricity", "Home", "Of_Super-Importance", "Television"}
testGot = testTasklist[taskId-1].Contexts
if !compareSlices(testGot.([]string), testExpected.([]string)) {
t.Errorf("Expected Task[%d] to have contexts '%v', but got '%v'", taskId, testExpected, testGot)
}
taskId++
testExpected = []string{}
testGot = testTasklist[taskId-1].Contexts
if !compareSlices(testGot.([]string), testExpected.([]string)) {
t.Errorf("Expected Task[%d] to have no contexts, but got '%v'", taskId, testGot)
}
taskId++
}
func TestTasksProjects(t *testing.T) {
testTasklist.LoadFromFilename(testInput)
taskId := 19
testExpected = []string{"Gardening", "Improving", "Planning", "Relaxing-Work"}
testGot = testTasklist[taskId-1].Projects
if !compareSlices(testGot.([]string), testExpected.([]string)) {
t.Errorf("Expected Task[%d] to have projects '%v', but got '%v'", taskId, testExpected, testGot)
}
taskId++
testExpected = []string{"Novel"}
testGot = testTasklist[taskId-1].Projects
if !compareSlices(testGot.([]string), testExpected.([]string)) {
t.Errorf("Expected Task[%d] to have projects '%v', but got '%v'", taskId, testExpected, testGot)
}
taskId++
testExpected = []string{}
testGot = testTasklist[taskId-1].Projects
if !compareSlices(testGot.([]string), testExpected.([]string)) {
t.Errorf("Expected Task[%d] to have no projects, but got '%v'", taskId, testGot)
}
taskId++
}
func TestTaskDueDate(t *testing.T) {
testTasklist.LoadFromFilename(testInput)
taskId := 22
testExpected, err := time.Parse(DateLayout, "2014-02-17")
if err != nil {
t.Fatal(err)
}
testGot = testTasklist[taskId-1].DueDate
if testGot != testExpected {
t.Errorf("Expected Task[%d] to have due date '%s', but got '%v'", taskId, testExpected, testGot)
}
taskId++
if testTasklist[taskId-1].HasDueDate() {
t.Errorf("Expected Task[%d] to have no due date, but got '%v'", taskId, testTasklist[taskId-1].DueDate)
}
taskId++
}
func TestTaskAddonTags(t *testing.T) {
testTasklist.LoadFromFilename(testInput)
taskId := 24
testExpected = map[string]string{"Level": "5", "private": "false"}
testGot = testTasklist[taskId-1].AdditionalTags
if len(testGot.(map[string]string)) != 2 ||
!compareMaps(testGot.(map[string]string), testExpected.(map[string]string)) {
t.Errorf("Expected Task[%d] to have addon tags '%v', but got '%v'", taskId, testExpected, testGot)
}
taskId++
testExpected = map[string]string{"Importance": "Very!"}
testGot = testTasklist[taskId-1].AdditionalTags
if len(testGot.(map[string]string)) != 1 ||
!compareMaps(testGot.(map[string]string), testExpected.(map[string]string)) {
t.Errorf("Expected Task[%d] to have projects '%v', but got '%v'", taskId, testExpected, testGot)
}
taskId++
testExpected = map[string]string{}
testGot = testTasklist[taskId-1].AdditionalTags
if len(testGot.(map[string]string)) != 0 ||
!compareMaps(testGot.(map[string]string), testExpected.(map[string]string)) {
t.Errorf("Expected Task[%d] to have no additional tags, but got '%v'", taskId, testGot)
}
taskId++
testExpected = map[string]string{}
testGot = testTasklist[taskId-1].AdditionalTags
if len(testGot.(map[string]string)) != 0 ||
!compareMaps(testGot.(map[string]string), testExpected.(map[string]string)) {
t.Errorf("Expected Task[%d] to have no additional tags, but got '%v'", taskId, testGot)
}
taskId++
}
func TestTaskCompleted(t *testing.T) {
testTasklist.LoadFromFilename(testInput)
taskId := 28
testExpected = true
testGot = testTasklist[taskId-1].Completed
if testGot != testExpected {
t.Errorf("Expected Task[%d] not to completed, but got '%v'", taskId, testGot)
}
taskId++
testExpected = true
testGot = testTasklist[taskId-1].Completed
if testGot != testExpected {
t.Errorf("Expected Task[%d] not to completed, but got '%v'", taskId, testGot)
}
taskId++
testExpected = true
testGot = testTasklist[taskId-1].Completed
if testGot != testExpected {
t.Errorf("Expected Task[%d] not to completed, but got '%v'", taskId, testGot)
}
taskId++
testExpected = false
testGot = testTasklist[taskId-1].Completed
if testGot != testExpected {
t.Errorf("Expected Task[%d] not to be completed, but got '%v'", taskId, testGot)
}
taskId++
testExpected = false
testGot = testTasklist[taskId-1].Completed
if testGot != testExpected {
t.Errorf("Expected Task[%d] not to be completed, but got '%v'", taskId, testGot)
}
taskId++
}
func TestTaskCompletedDate(t *testing.T) {
testTasklist.LoadFromFilename(testInput)
taskId := 33
if testTasklist[taskId-1].HasCompletedDate() {
t.Errorf("Expected Task[%d] to not have a completed date, but got '%v'", taskId, testTasklist[taskId-1].CompletedDate)
}
taskId++
testExpected, err := time.Parse(DateLayout, "2014-01-03")
if err != nil {
t.Fatal(err)
}
testGot = testTasklist[taskId-1].CompletedDate
if testGot != testExpected {
t.Errorf("Expected Task[%d] to have completed date '%s', but got '%v'", taskId, testExpected, testGot)
}
taskId++
if testTasklist[taskId-1].HasCompletedDate() {
t.Errorf("Expected Task[%d] to not have a completed date, but got '%v'", taskId, testTasklist[taskId-1].CompletedDate)
}
taskId++
testExpected, err = time.Parse(DateLayout, "2014-01-02")
if err != nil {
t.Fatal(err)
}
testGot = testTasklist[taskId-1].CompletedDate
if testGot != testExpected {
t.Errorf("Expected Task[%d] to have completed date '%s', but got '%v'", taskId, testExpected, testGot)
}
taskId++
testExpected, err = time.Parse(DateLayout, "2014-01-03")
if err != nil {
t.Fatal(err)
}
testGot = testTasklist[taskId-1].CompletedDate
if testGot != testExpected {
t.Errorf("Expected Task[%d] to have completed date '%s', but got '%v'", taskId, testExpected, testGot)
}
taskId++
if testTasklist[taskId-1].HasCompletedDate() {
t.Errorf("Expected Task[%d] to not have a completed date, but got '%v'", taskId, testTasklist[taskId-1].CompletedDate)
} }
taskId++ taskId++
} }