Rework the whole library

This commit is contained in:
Brian Buller 2023-08-23 09:17:16 -05:00
parent 11f1335a20
commit 7661923650
21 changed files with 433 additions and 2793 deletions

373
LICENSE
View File

@ -1,373 +0,0 @@
Mozilla Public License Version 2.0
==================================
1. Definitions
--------------
1.1. "Contributor"
means each individual or legal entity that creates, contributes to
the creation of, or owns Covered Software.
1.2. "Contributor Version"
means the combination of the Contributions of others (if any) used
by a Contributor and that particular Contributor's Contribution.
1.3. "Contribution"
means Covered Software of a particular Contributor.
1.4. "Covered Software"
means Source Code Form to which the initial Contributor has attached
the notice in Exhibit A, the Executable Form of such Source Code
Form, and Modifications of such Source Code Form, in each case
including portions thereof.
1.5. "Incompatible With Secondary Licenses"
means
(a) that the initial Contributor has attached the notice described
in Exhibit B to the Covered Software; or
(b) that the Covered Software was made available under the terms of
version 1.1 or earlier of the License, but not also under the
terms of a Secondary License.
1.6. "Executable Form"
means any form of the work other than Source Code Form.
1.7. "Larger Work"
means a work that combines Covered Software with other material, in
a separate file or files, that is not Covered Software.
1.8. "License"
means this document.
1.9. "Licensable"
means having the right to grant, to the maximum extent possible,
whether at the time of the initial grant or subsequently, any and
all of the rights conveyed by this License.
1.10. "Modifications"
means any of the following:
(a) any file in Source Code Form that results from an addition to,
deletion from, or modification of the contents of Covered
Software; or
(b) any new file in Source Code Form that contains any Covered
Software.
1.11. "Patent Claims" of a Contributor
means any patent claim(s), including without limitation, method,
process, and apparatus claims, in any patent Licensable by such
Contributor that would be infringed, but for the grant of the
License, by the making, using, selling, offering for sale, having
made, import, or transfer of either its Contributions or its
Contributor Version.
1.12. "Secondary License"
means either the GNU General Public License, Version 2.0, the GNU
Lesser General Public License, Version 2.1, the GNU Affero General
Public License, Version 3.0, or any later versions of those
licenses.
1.13. "Source Code Form"
means the form of the work preferred for making modifications.
1.14. "You" (or "Your")
means an individual or a legal entity exercising rights under this
License. For legal entities, "You" includes any entity that
controls, is controlled by, or is under common control with You. For
purposes of this definition, "control" means (a) the power, direct
or indirect, to cause the direction or management of such entity,
whether by contract or otherwise, or (b) ownership of more than
fifty percent (50%) of the outstanding shares or beneficial
ownership of such entity.
2. License Grants and Conditions
--------------------------------
2.1. Grants
Each Contributor hereby grants You a world-wide, royalty-free,
non-exclusive license:
(a) under intellectual property rights (other than patent or trademark)
Licensable by such Contributor to use, reproduce, make available,
modify, display, perform, distribute, and otherwise exploit its
Contributions, either on an unmodified basis, with Modifications, or
as part of a Larger Work; and
(b) under Patent Claims of such Contributor to make, use, sell, offer
for sale, have made, import, and otherwise transfer either its
Contributions or its Contributor Version.
2.2. Effective Date
The licenses granted in Section 2.1 with respect to any Contribution
become effective for each Contribution on the date the Contributor first
distributes such Contribution.
2.3. Limitations on Grant Scope
The licenses granted in this Section 2 are the only rights granted under
this License. No additional rights or licenses will be implied from the
distribution or licensing of Covered Software under this License.
Notwithstanding Section 2.1(b) above, no patent license is granted by a
Contributor:
(a) for any code that a Contributor has removed from Covered Software;
or
(b) for infringements caused by: (i) Your and any other third party's
modifications of Covered Software, or (ii) the combination of its
Contributions with other software (except as part of its Contributor
Version); or
(c) under Patent Claims infringed by Covered Software in the absence of
its Contributions.
This License does not grant any rights in the trademarks, service marks,
or logos of any Contributor (except as may be necessary to comply with
the notice requirements in Section 3.4).
2.4. Subsequent Licenses
No Contributor makes additional grants as a result of Your choice to
distribute the Covered Software under a subsequent version of this
License (see Section 10.2) or under the terms of a Secondary License (if
permitted under the terms of Section 3.3).
2.5. Representation
Each Contributor represents that the Contributor believes its
Contributions are its original creation(s) or it has sufficient rights
to grant the rights to its Contributions conveyed by this License.
2.6. Fair Use
This License is not intended to limit any rights You have under
applicable copyright doctrines of fair use, fair dealing, or other
equivalents.
2.7. Conditions
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
in Section 2.1.
3. Responsibilities
-------------------
3.1. Distribution of Source Form
All distribution of Covered Software in Source Code Form, including any
Modifications that You create or to which You contribute, must be under
the terms of this License. You must inform recipients that the Source
Code Form of the Covered Software is governed by the terms of this
License, and how they can obtain a copy of this License. You may not
attempt to alter or restrict the recipients' rights in the Source Code
Form.
3.2. Distribution of Executable Form
If You distribute Covered Software in Executable Form then:
(a) such Covered Software must also be made available in Source Code
Form, as described in Section 3.1, and You must inform recipients of
the Executable Form how they can obtain a copy of such Source Code
Form by reasonable means in a timely manner, at a charge no more
than the cost of distribution to the recipient; and
(b) You may distribute such Executable Form under the terms of this
License, or sublicense it under different terms, provided that the
license for the Executable Form does not attempt to limit or alter
the recipients' rights in the Source Code Form under this License.
3.3. Distribution of a Larger Work
You may create and distribute a Larger Work under terms of Your choice,
provided that You also comply with the requirements of this License for
the Covered Software. If the Larger Work is a combination of Covered
Software with a work governed by one or more Secondary Licenses, and the
Covered Software is not Incompatible With Secondary Licenses, this
License permits You to additionally distribute such Covered Software
under the terms of such Secondary License(s), so that the recipient of
the Larger Work may, at their option, further distribute the Covered
Software under the terms of either this License or such Secondary
License(s).
3.4. Notices
You may not remove or alter the substance of any license notices
(including copyright notices, patent notices, disclaimers of warranty,
or limitations of liability) contained within the Source Code Form of
the Covered Software, except that You may alter any license notices to
the extent required to remedy known factual inaccuracies.
3.5. Application of Additional Terms
You may choose to offer, and to charge a fee for, warranty, support,
indemnity or liability obligations to one or more recipients of Covered
Software. However, You may do so only on Your own behalf, and not on
behalf of any Contributor. You must make it absolutely clear that any
such warranty, support, indemnity, or liability obligation is offered by
You alone, and You hereby agree to indemnify every Contributor for any
liability incurred by such Contributor as a result of warranty, support,
indemnity or liability terms You offer. You may include additional
disclaimers of warranty and limitations of liability specific to any
jurisdiction.
4. Inability to Comply Due to Statute or Regulation
---------------------------------------------------
If it is impossible for You to comply with any of the terms of this
License with respect to some or all of the Covered Software due to
statute, judicial order, or regulation then You must: (a) comply with
the terms of this License to the maximum extent possible; and (b)
describe the limitations and the code they affect. Such description must
be placed in a text file included with all distributions of the Covered
Software under this License. Except to the extent prohibited by statute
or regulation, such description must be sufficiently detailed for a
recipient of ordinary skill to be able to understand it.
5. Termination
--------------
5.1. The rights granted under this License will terminate automatically
if You fail to comply with any of its terms. However, if You become
compliant, then the rights granted under this License from a particular
Contributor are reinstated (a) provisionally, unless and until such
Contributor explicitly and finally terminates Your grants, and (b) on an
ongoing basis, if such Contributor fails to notify You of the
non-compliance by some reasonable means prior to 60 days after You have
come back into compliance. Moreover, Your grants from a particular
Contributor are reinstated on an ongoing basis if such Contributor
notifies You of the non-compliance by some reasonable means, this is the
first time You have received notice of non-compliance with this License
from such Contributor, and You become compliant prior to 30 days after
Your receipt of the notice.
5.2. If You initiate litigation against any entity by asserting a patent
infringement claim (excluding declaratory judgment actions,
counter-claims, and cross-claims) alleging that a Contributor Version
directly or indirectly infringes any patent, then the rights granted to
You by any and all Contributors for the Covered Software under Section
2.1 of this License shall terminate.
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
end user license agreements (excluding distributors and resellers) which
have been validly granted by You or Your distributors under this License
prior to termination shall survive termination.
************************************************************************
* *
* 6. Disclaimer of Warranty *
* ------------------------- *
* *
* Covered Software is provided under this License on an "as is" *
* basis, without warranty of any kind, either expressed, implied, or *
* statutory, including, without limitation, warranties that the *
* Covered Software is free of defects, merchantable, fit for a *
* particular purpose or non-infringing. The entire risk as to the *
* quality and performance of the Covered Software is with You. *
* Should any Covered Software prove defective in any respect, You *
* (not any Contributor) assume the cost of any necessary servicing, *
* repair, or correction. This disclaimer of warranty constitutes an *
* essential part of this License. No use of any Covered Software is *
* authorized under this License except under this disclaimer. *
* *
************************************************************************
************************************************************************
* *
* 7. Limitation of Liability *
* -------------------------- *
* *
* Under no circumstances and under no legal theory, whether tort *
* (including negligence), contract, or otherwise, shall any *
* Contributor, or anyone who distributes Covered Software as *
* permitted above, be liable to You for any direct, indirect, *
* special, incidental, or consequential damages of any character *
* including, without limitation, damages for lost profits, loss of *
* goodwill, work stoppage, computer failure or malfunction, or any *
* and all other commercial damages or losses, even if such party *
* shall have been informed of the possibility of such damages. This *
* limitation of liability shall not apply to liability for death or *
* personal injury resulting from such party's negligence to the *
* extent applicable law prohibits such limitation. Some *
* jurisdictions do not allow the exclusion or limitation of *
* incidental or consequential damages, so this exclusion and *
* limitation may not apply to You. *
* *
************************************************************************
8. Litigation
-------------
Any litigation relating to this License may be brought only in the
courts of a jurisdiction where the defendant maintains its principal
place of business and such litigation shall be governed by laws of that
jurisdiction, without reference to its conflict-of-law provisions.
Nothing in this Section shall prevent a party's ability to bring
cross-claims or counter-claims.
9. Miscellaneous
----------------
This License represents the complete agreement concerning the subject
matter hereof. If any provision of this License is held to be
unenforceable, such provision shall be reformed only to the extent
necessary to make it enforceable. Any law or regulation which provides
that the language of a contract shall be construed against the drafter
shall not be used to construe this License against a Contributor.
10. Versions of the License
---------------------------
10.1. New Versions
Mozilla Foundation is the license steward. Except as provided in Section
10.3, no one other than the license steward has the right to modify or
publish new versions of this License. Each version will be given a
distinguishing version number.
10.2. Effect of New Versions
You may distribute the Covered Software under the terms of the version
of the License under which You originally received the Covered Software,
or under the terms of any subsequent version published by the license
steward.
10.3. Modified Versions
If you create software not governed by this License, and you want to
create a new license for such software, you may create and use a
modified version of this License if you rename the license and remove
any references to the name of the license steward (except to note that
such modified license differs from this License).
10.4. Distributing Source Code Form that is Incompatible With Secondary
Licenses
If You choose to distribute Source Code Form that is Incompatible With
Secondary Licenses under the terms of this version of the License, the
notice described in Exhibit B of this License must be attached.
Exhibit A - Source Code Form License Notice
-------------------------------------------
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/.
If it is not possible or desirable to put the notice in a particular
file, then You may include the notice in a location (such as a LICENSE
file in a relevant directory) where a recipient would be likely to look
for such a notice.
You may add additional accurate notices of copyright ownership.
Exhibit B - "Incompatible With Secondary Licenses" Notice
---------------------------------------------------------
This Source Code Form is "Incompatible With Secondary Licenses", as
defined by the Mozilla Public License, v. 2.0.

View File

@ -3,70 +3,17 @@ go-todotxt
A Go todo.txt library.
[![GoDoc](https://godoc.org/github.com/JamesClonk/go-todotxt?status.png)](https://godoc.org/github.com/JamesClonk/go-todotxt) [![Build Status](https://travis-ci.org/JamesClonk/go-todotxt.png?branch=master)](https://travis-ci.org/JamesClonk/go-todotxt)
The *todotxt* package is a Go client library for Gina Trapani's [todo.txt](https://github.com/ginatrapani/todo.txt-cli/) files.
It allows for parsing and manipulating of task lists and tasks in the todo.txt format.
## Installation
$ go get github.com/JamesClonk/go-todotxt
## Requirements
go-todotxt requires Go1.1 or higher.
## Usage
```go
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)
}
// tasklist now contains a slice of Tasks
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)
// Filter list to get only completed tasks
completedList := tasklist.Filter(func(t Task) bool {
return t.Completed
})
fmt.Print(completedList)
// Add a new empty Task to tasklist
task := NewTask()
tasklist.AddTask(&task)
// Or a parsed Task from a string
parsedTask, _ := ParseTask("x (C) 2014-01-01 Create golang library documentation @Go +go-todotxt due:2014-01-12")
tasklist.AddTask(parsed)
// Update an existing task
task, _ := tasklist.GetTask(2) // Task pointer
task.Todo = "Do something different.."
tasklist.WriteToFilename("todo.txt")
}
## Example todo.txt
```
(A) Call Mom @Phone +Family
(A) Schedule annual checkup +Health
(B) Outline chapter 5 +Novel @Computer
(C) Add cover sheets @Office +TPSReports
Plan backyard herb garden @Home
Pick up milk @GroceryStore
Research self-publishing services +Novel @Computer
x Download Todo.txt mobile app @Phone
```
## Documentation
See [GoDoc - Documentation](https://godoc.org/github.com/JamesClonk/go-todotxt) for further documentation.
## License
The source files are distributed under the [Mozilla Public License, version 2.0](http://mozilla.org/MPL/2.0/), unless otherwise noted.
Please read the [FAQ](http://www.mozilla.org/MPL/2.0/FAQ.html) if you have further questions regarding the license.

View File

@ -1,48 +0,0 @@
/* 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
}

66
sort.go
View File

@ -1,7 +1,3 @@
/* 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 (
@ -22,52 +18,52 @@ const (
SORT_DUE_DATE_DESC
)
// Sort allows a TaskList to be sorted by certain predefined fields.
// Sort allows a TodoList to be sorted by certain predefined fields.
// See constants SORT_* for fields and sort order.
func (tasklist *TaskList) Sort(sortFlag int) error {
func (todolist *TodoList) Sort(sortFlag int) error {
switch sortFlag {
case SORT_PRIORITY_ASC, SORT_PRIORITY_DESC:
tasklist.sortByPriority(sortFlag)
todolist.sortByPriority(sortFlag)
case SORT_CREATED_DATE_ASC, SORT_CREATED_DATE_DESC:
tasklist.sortByCreatedDate(sortFlag)
todolist.sortByCreatedDate(sortFlag)
case SORT_COMPLETED_DATE_ASC, SORT_COMPLETED_DATE_DESC:
tasklist.sortByCompletedDate(sortFlag)
todolist.sortByCompletedDate(sortFlag)
case SORT_DUE_DATE_ASC, SORT_DUE_DATE_DESC:
tasklist.sortByDueDate(sortFlag)
todolist.sortByDueDate(sortFlag)
default:
return errors.New("unrecognized sort option")
}
return nil
}
type tasklistSort struct {
tasklists TaskList
by func(t1, t2 *Task) bool
type todolistSort struct {
todolists TodoList
by func(t1, t2 *Todo) bool
}
func (ts *tasklistSort) Len() int {
return len(ts.tasklists)
func (ts *todolistSort) Len() int {
return len(ts.todolists)
}
func (ts *tasklistSort) Swap(l, r int) {
ts.tasklists[l], ts.tasklists[r] = ts.tasklists[r], ts.tasklists[l]
func (ts *todolistSort) Swap(l, r int) {
ts.todolists[l], ts.todolists[r] = ts.todolists[r], ts.todolists[l]
}
func (ts *tasklistSort) Less(l, r int) bool {
return ts.by(&ts.tasklists[l], &ts.tasklists[r])
func (ts *todolistSort) Less(l, r int) bool {
return ts.by(&ts.todolists[l], &ts.todolists[r])
}
func (tasklist *TaskList) sortBy(by func(t1, t2 *Task) bool) *TaskList {
ts := &tasklistSort{
tasklists: *tasklist,
func (todolist *TodoList) sortBy(by func(t1, t2 *Todo) bool) *TodoList {
ts := &todolistSort{
todolists: *todolist,
by: by,
}
sort.Sort(ts)
return tasklist
return todolist
}
func (tasklist *TaskList) sortByPriority(order int) *TaskList {
tasklist.sortBy(func(t1, t2 *Task) bool {
func (todolist *TodoList) sortByPriority(order int) *TodoList {
todolist.sortBy(func(t1, t2 *Todo) bool {
if order == SORT_PRIORITY_ASC { // ASC
if t1.HasPriority() && t2.HasPriority() {
return t1.Priority < t2.Priority
@ -80,7 +76,7 @@ func (tasklist *TaskList) sortByPriority(order int) *TaskList {
}
return !t1.HasPriority()
})
return tasklist
return todolist
}
func sortByDate(asc bool, hasDate1, hasDate2 bool, date1, date2 time.Time) bool {
@ -97,23 +93,23 @@ func sortByDate(asc bool, hasDate1, hasDate2 bool, date1, date2 time.Time) bool
return !hasDate2
}
func (tasklist *TaskList) sortByCreatedDate(order int) *TaskList {
tasklist.sortBy(func(t1, t2 *Task) bool {
func (todolist *TodoList) sortByCreatedDate(order int) *TodoList {
todolist.sortBy(func(t1, t2 *Todo) bool {
return sortByDate(order == SORT_CREATED_DATE_ASC, t1.HasCreatedDate(), t2.HasCreatedDate(), t1.CreatedDate, t2.CreatedDate)
})
return tasklist
return todolist
}
func (tasklist *TaskList) sortByCompletedDate(order int) *TaskList {
tasklist.sortBy(func(t1, t2 *Task) bool {
func (todolist *TodoList) sortByCompletedDate(order int) *TodoList {
todolist.sortBy(func(t1, t2 *Todo) bool {
return sortByDate(order == SORT_COMPLETED_DATE_ASC, t1.HasCompletedDate(), t2.HasCompletedDate(), t1.CompletedDate, t2.CompletedDate)
})
return tasklist
return todolist
}
func (tasklist *TaskList) sortByDueDate(order int) *TaskList {
tasklist.sortBy(func(t1, t2 *Task) bool {
func (todolist *TodoList) sortByDueDate(order int) *TodoList {
todolist.sortBy(func(t1, t2 *Todo) bool {
return sortByDate(order == SORT_DUE_DATE_ASC, t1.HasDueDate(), t2.HasDueDate(), t1.DueDate, t2.DueDate)
})
return tasklist
return todolist
}

View File

@ -1,335 +0,0 @@
/* 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 (
"testing"
)
var (
testInputSort = "testdata/sort_todo.txt"
)
func TestTaskSortByPriority(t *testing.T) {
testTasklist.LoadFromFilename(testInputSort)
taskId := 0
testTasklist = testTasklist[taskId : taskId+6]
if err := testTasklist.Sort(SORT_PRIORITY_ASC); err != nil {
t.Fatal(err)
}
testExpected = "(A) 2012-01-30 Call Mom @Call @Phone +Family"
testGot = testTasklist[0].Task()
if testGot != testExpected {
t.Errorf("Expected Task[1] after Sort() to be [%s], but got [%s]", testExpected, testGot)
}
testExpected = "x 2014-01-02 (B) 2013-12-30 Create golang library test cases @Go +go-todotxt"
testGot = testTasklist[1].Task()
if testGot != testExpected {
t.Errorf("Expected Task[2] after Sort() to be [%s], but got [%s]", testExpected, testGot)
}
testExpected = "x (C) 2014-01-01 Create golang library documentation @Go +go-todotxt due:2014-01-12"
testGot = testTasklist[2].Task()
if testGot != testExpected {
t.Errorf("Expected Task[3] after Sort() to be [%s], but got [%s]", testExpected, testGot)
}
testExpected = "(D) 2013-12-01 Outline chapter 5 @Computer +Novel Level:5 private:false due:2014-02-17"
testGot = testTasklist[3].Task()
if testGot != testExpected {
t.Errorf("Expected Task[4] after Sort() to be [%s], but got [%s]", testExpected, testGot)
}
testExpected = "2013-02-22 Pick up milk @GroceryStore"
testGot = testTasklist[4].Task()
if testGot != testExpected {
t.Errorf("Expected Task[5] after Sort() to be [%s], but got [%s]", testExpected, testGot)
}
testExpected = "x 2014-01-03 Create golang library @Go +go-todotxt due:2014-01-05"
testGot = testTasklist[5].Task()
if testGot != testExpected {
t.Errorf("Expected Task[6] after Sort() to be [%s], but got [%s]", testExpected, testGot)
}
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"
testGot = testTasklist[0].Task()
if testGot != testExpected {
t.Errorf("Expected Task[1] after Sort() to be [%s], but got [%s]", testExpected, testGot)
}
testExpected = "2013-02-22 Pick up milk @GroceryStore"
testGot = testTasklist[1].Task()
if testGot != testExpected {
t.Errorf("Expected Task[2] after Sort() to be [%s], but got [%s]", testExpected, testGot)
}
testExpected = "(D) 2013-12-01 Outline chapter 5 @Computer +Novel Level:5 private:false due:2014-02-17"
testGot = testTasklist[2].Task()
if testGot != testExpected {
t.Errorf("Expected Task[3] after Sort() to be [%s], but got [%s]", testExpected, testGot)
}
testExpected = "x (C) 2014-01-01 Create golang library documentation @Go +go-todotxt due:2014-01-12"
testGot = testTasklist[3].Task()
if testGot != testExpected {
t.Errorf("Expected Task[4] after Sort() to be [%s], but got [%s]", testExpected, testGot)
}
testExpected = "x 2014-01-02 (B) 2013-12-30 Create golang library test cases @Go +go-todotxt"
testGot = testTasklist[4].Task()
if testGot != testExpected {
t.Errorf("Expected Task[5] after Sort() to be [%s], but got [%s]", testExpected, testGot)
}
testExpected = "(A) 2012-01-30 Call Mom @Call @Phone +Family"
testGot = testTasklist[5].Task()
if testGot != testExpected {
t.Errorf("Expected Task[6] after Sort() to be [%s], but got [%s]", testExpected, testGot)
}
}
func TestTaskSortByCreatedDate(t *testing.T) {
testTasklist.LoadFromFilename(testInputSort)
taskId := 6
testTasklist = testTasklist[taskId : taskId+5]
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"
testGot = testTasklist[0].Task()
if testGot != testExpected {
t.Errorf("Expected Task[1] after Sort() to be [%s], but got [%s]", testExpected, testGot)
}
testExpected = "(A) Call Mom @Call @Phone +Family"
testGot = testTasklist[1].Task()
if testGot != testExpected {
t.Errorf("Expected Task[2] after Sort() to be [%s], but got [%s]", testExpected, testGot)
}
testExpected = "2013-02-22 Pick up milk @GroceryStore"
testGot = testTasklist[2].Task()
if testGot != testExpected {
t.Errorf("Expected Task[3] after Sort() to be [%s], but got [%s]", testExpected, testGot)
}
testExpected = "x 2014-01-02 (B) 2013-12-30 Create golang library test cases @Go +go-todotxt"
testGot = testTasklist[3].Task()
if testGot != testExpected {
t.Errorf("Expected Task[4] after Sort() to be [%s], but got [%s]", testExpected, testGot)
}
testExpected = "x (C) 2014-01-01 Create golang library documentation @Go +go-todotxt due:2014-01-12"
testGot = testTasklist[4].Task()
if testGot != testExpected {
t.Errorf("Expected Task[5] after Sort() to be [%s], but got [%s]", testExpected, testGot)
}
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"
testGot = testTasklist[0].Task()
if testGot != testExpected {
t.Errorf("Expected Task[1] after Sort() to be [%s], but got [%s]", testExpected, testGot)
}
testExpected = "x 2014-01-02 (B) 2013-12-30 Create golang library test cases @Go +go-todotxt"
testGot = testTasklist[1].Task()
if testGot != testExpected {
t.Errorf("Expected Task[2] after Sort() to be [%s], but got [%s]", testExpected, testGot)
}
testExpected = "2013-02-22 Pick up milk @GroceryStore"
testGot = testTasklist[2].Task()
if testGot != testExpected {
t.Errorf("Expected Task[3] after Sort() to be [%s], but got [%s]", testExpected, testGot)
}
testExpected = "(A) Call Mom @Call @Phone +Family"
testGot = testTasklist[3].Task()
if testGot != testExpected {
t.Errorf("Expected Task[4] after Sort() to be [%s], but got [%s]", testExpected, testGot)
}
testExpected = "x 2014-01-03 Create golang library @Go +go-todotxt due:2014-01-05"
testGot = testTasklist[4].Task()
if testGot != testExpected {
t.Errorf("Expected Task[5] after Sort() to be [%s], but got [%s]", testExpected, testGot)
}
}
func TestTaskSortByCompletedDate(t *testing.T) {
testTasklist.LoadFromFilename(testInputSort)
taskId := 11
testTasklist = testTasklist[taskId : taskId+6]
if err := testTasklist.Sort(SORT_COMPLETED_DATE_ASC); err != nil {
t.Fatal(err)
}
testExpected = "x Download Todo.txt mobile app @Phone"
testGot = testTasklist[0].Task()
if testGot != testExpected {
t.Errorf("Expected Task[1] after Sort() to be [%s], but got [%s]", testExpected, testGot)
}
testExpected = "x (C) 2014-01-01 Create golang library documentation @Go +go-todotxt due:2014-01-12"
testGot = testTasklist[1].Task()
if testGot != testExpected {
t.Errorf("Expected Task[2] after Sort() to be [%s], but got [%s]", testExpected, testGot)
}
testExpected = "2013-02-22 Pick up milk @GroceryStore"
testGot = testTasklist[2].Task()
if testGot != testExpected {
t.Errorf("Expected Task[3] after Sort() to be [%s], but got [%s]", testExpected, testGot)
}
testExpected = "x 2014-01-02 (B) 2013-12-30 Create golang library test cases @Go +go-todotxt"
testGot = testTasklist[3].Task()
if testGot != testExpected {
t.Errorf("Expected Task[4] after Sort() to be [%s], but got [%s]", testExpected, testGot)
}
testExpected = "x 2014-01-03 Create golang library @Go +go-todotxt due:2014-01-05"
testGot = testTasklist[4].Task()
if testGot != testExpected {
t.Errorf("Expected Task[5] after Sort() to be [%s], but got [%s]", testExpected, testGot)
}
testExpected = "x 2014-01-04 2014-01-01 Create some more golang library test cases @Go +go-todotxt"
testGot = testTasklist[5].Task()
if testGot != testExpected {
t.Errorf("Expected Task[6] after Sort() to be [%s], but got [%s]", testExpected, testGot)
}
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"
testGot = testTasklist[0].Task()
if testGot != testExpected {
t.Errorf("Expected Task[1] after Sort() to be [%s], but got [%s]", testExpected, testGot)
}
testExpected = "x 2014-01-03 Create golang library @Go +go-todotxt due:2014-01-05"
testGot = testTasklist[1].Task()
if testGot != testExpected {
t.Errorf("Expected Task[2] after Sort() to be [%s], but got [%s]", testExpected, testGot)
}
testExpected = "x 2014-01-02 (B) 2013-12-30 Create golang library test cases @Go +go-todotxt"
testGot = testTasklist[2].Task()
if testGot != testExpected {
t.Errorf("Expected Task[3] after Sort() to be [%s], but got [%s]", testExpected, testGot)
}
testExpected = "2013-02-22 Pick up milk @GroceryStore"
testGot = testTasklist[3].Task()
if testGot != testExpected {
t.Errorf("Expected Task[4] after Sort() to be [%s], but got [%s]", testExpected, testGot)
}
testExpected = "x (C) 2014-01-01 Create golang library documentation @Go +go-todotxt due:2014-01-12"
testGot = testTasklist[4].Task()
if testGot != testExpected {
t.Errorf("Expected Task[5] after Sort() to be [%s], but got [%s]", testExpected, testGot)
}
testExpected = "x Download Todo.txt mobile app @Phone"
testGot = testTasklist[5].Task()
if testGot != testExpected {
t.Errorf("Expected Task[6] after Sort() to be [%s], but got [%s]", testExpected, testGot)
}
}
func TestTaskSortByDueDate(t *testing.T) {
testTasklist.LoadFromFilename(testInputSort)
taskId := 17
testTasklist = testTasklist[taskId : taskId+4]
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"
testGot = testTasklist[0].Task()
if testGot != testExpected {
t.Errorf("Expected Task[1] after Sort() to be [%s], but got [%s]", testExpected, testGot)
}
testExpected = "x 2014-01-03 Create golang library @Go +go-todotxt due:2014-01-05"
testGot = testTasklist[1].Task()
if testGot != testExpected {
t.Errorf("Expected Task[2] after Sort() to be [%s], but got [%s]", testExpected, testGot)
}
testExpected = "x (C) 2014-01-01 Create golang library documentation @Go +go-todotxt due:2014-01-12"
testGot = testTasklist[2].Task()
if testGot != testExpected {
t.Errorf("Expected Task[3] after Sort() to be [%s], but got [%s]", testExpected, testGot)
}
testExpected = "(B) 2013-12-01 Outline chapter 5 @Computer +Novel Level:5 private:false due:2014-02-17"
testGot = testTasklist[3].Task()
if testGot != testExpected {
t.Errorf("Expected Task[4] after Sort() to be [%s], but got [%s]", testExpected, testGot)
}
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"
testGot = testTasklist[0].Task()
if testGot != testExpected {
t.Errorf("Expected Task[1] after Sort() to be [%s], but got [%s]", testExpected, testGot)
}
testExpected = "x (C) 2014-01-01 Create golang library documentation @Go +go-todotxt due:2014-01-12"
testGot = testTasklist[1].Task()
if testGot != testExpected {
t.Errorf("Expected Task[2] after Sort() to be [%s], but got [%s]", testExpected, testGot)
}
testExpected = "x 2014-01-03 Create golang library @Go +go-todotxt due:2014-01-05"
testGot = testTasklist[2].Task()
if testGot != testExpected {
t.Errorf("Expected Task[3] after Sort() to be [%s], but got [%s]", testExpected, testGot)
}
testExpected = "x 2014-01-02 (B) 2013-12-30 Create golang library test cases @Go +go-todotxt"
testGot = testTasklist[3].Task()
if testGot != testExpected {
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)
}
}

View File

@ -1,736 +0,0 @@
/* 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 (
"testing"
"time"
)
var (
testInputTask = "testdata/task_todo.txt"
)
func TestNewTask(t *testing.T) {
task := NewTask()
testExpected = 0
testGot = task.Id
if testGot != testExpected {
t.Errorf("Expected new Task to have default Id [%d], but got [%d]", testExpected, testGot)
}
testExpected = ""
testGot = task.Original
if testGot != testExpected {
t.Errorf("Expected new Task to be empty, but got [%s]", testGot)
}
testExpected = ""
testGot = task.Todo
if testGot != testExpected {
t.Errorf("Expected new Task to be empty, but got [%s]", testGot)
}
testExpected = false
testGot = task.HasPriority()
if testGot != testExpected {
t.Errorf("Expected new Task to have no priority, but got [%v]", testGot)
}
testExpected = 0
testGot = len(task.Projects)
if testGot != testExpected {
t.Errorf("Expected new Task to have %d projects, but got [%d]", testExpected, testGot)
}
testExpected = 0
testGot = len(task.Contexts)
if testGot != testExpected {
t.Errorf("Expected new Task to have %d contexts, but got [%d]", testExpected, testGot)
}
testExpected = 0
testGot = len(task.AdditionalTags)
if testGot != testExpected {
t.Errorf("Expected new Task to have %d additional tags, but got [%d]", testExpected, testGot)
}
testExpected = true
testGot = task.HasCreatedDate()
if testGot != testExpected {
t.Errorf("Expected new Task to have a created date, but got [%v]", testGot)
}
testExpected = false
testGot = task.HasCompletedDate()
if testGot != testExpected {
t.Errorf("Expected new Task to not have a completed date, but got [%v]", testGot)
}
testExpected = false
testGot = task.HasDueDate()
if testGot != testExpected {
t.Errorf("Expected new Task to not have a due date, but got [%v]", testGot)
}
testExpected = false
testGot = task.Completed
if testGot != testExpected {
t.Errorf("Expected new Task to not be completed, but got [%v]", testGot)
}
}
func TestParseTask(t *testing.T) {
task, err := ParseTask("x (C) 2014-01-01 @Go due:2014-01-12 Create golang library documentation +go-todotxt ")
if err != nil {
t.Error(err)
}
testExpected = "x (C) 2014-01-01 Create golang library documentation @Go +go-todotxt due:2014-01-12"
testGot = task.Task()
if testGot != testExpected {
t.Errorf("Expected Task to be [%s], but got [%s]", testExpected, testGot)
}
testExpected = 0
testGot = task.Id
if testGot != testExpected {
t.Errorf("Expected Task to have default Id [%d], but got [%d]", testExpected, testGot)
}
testExpected = "x (C) 2014-01-01 @Go due:2014-01-12 Create golang library documentation +go-todotxt"
testGot = task.Original
if testGot != testExpected {
t.Errorf("Expected Task to be [%s], but got [%s]", testExpected, testGot)
}
testExpected = "Create golang library documentation"
testGot = task.Todo
if testGot != testExpected {
t.Errorf("Expected Task to be [%s], but got [%s]", testExpected, testGot)
}
testExpected = true
testGot = task.HasPriority()
if testGot != testExpected {
t.Errorf("Expected Task to have no priority, but got [%v]", testGot)
}
testExpected = "C"
testGot = task.Priority
if testGot != testExpected {
t.Errorf("Expected Task to have priority [%v], but got [%v]", testExpected, testGot)
}
testExpected = 1
testGot = len(task.Projects)
if testGot != testExpected {
t.Errorf("Expected Task to have %d projects, but got [%d]", testExpected, testGot)
}
testExpected = 1
testGot = len(task.Contexts)
if testGot != testExpected {
t.Errorf("Expected Task to have %d contexts, but got [%d]", testExpected, testGot)
}
testExpected = 0
testGot = len(task.AdditionalTags)
if testGot != testExpected {
t.Errorf("Expected Task to have %d additional tags, but got [%d]", testExpected, testGot)
}
testExpected = true
testGot = task.HasCreatedDate()
if testGot != testExpected {
t.Errorf("Expected Task to have a created date, but got [%v]", testGot)
}
testExpected = false
testGot = task.HasCompletedDate()
if testGot != testExpected {
t.Errorf("Expected Task to not have a completed date, but got [%v]", testGot)
}
testExpected = true
testGot = task.HasDueDate()
if testGot != testExpected {
t.Errorf("Expected Task to have a due date, but got [%v]", testGot)
}
testExpected = true
testGot = task.Completed
if testGot != testExpected {
t.Errorf("Expected Task to be completed, but got [%v]", testGot)
}
}
func TestTaskId(t *testing.T) {
testTasklist.LoadFromFilename(testInputTask)
taskId := 1
testGot = testTasklist[taskId-1].Id
if testGot != taskId {
t.Errorf("Expected Task[%d] to have Id [%d], but got [%d]", taskId, taskId, testGot)
}
taskId = 5
testGot = testTasklist[taskId-1].Id
if testGot != taskId {
t.Errorf("Expected Task[%d] to have Id [%d], but got [%d]", taskId, taskId, testGot)
}
taskId = 27
testGot = testTasklist[taskId-1].Id
if testGot != taskId {
t.Errorf("Expected Task[%d] to have Id [%d], but got [%d]", taskId, taskId, testGot)
}
taskId++
}
func TestTaskString(t *testing.T) {
testTasklist.LoadFromFilename(testInputTask)
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++
testExpected = "x Download Todo.txt mobile app @Phone"
testGot = testTasklist[taskId-1].String()
if testGot != testExpected {
t.Errorf("Expected Task[%d] to be [%s], but got [%s]", taskId, testExpected, testGot)
}
taskId++
testExpected = "(B) 2013-12-01 Outline chapter 5 @Computer +Novel Level:5 private:false due:2014-02-17"
testGot = testTasklist[taskId-1].Task()
if testGot != testExpected {
t.Errorf("Expected Task[%d] to be [%s], but got [%s]", taskId, testExpected, testGot)
}
taskId++
testExpected = "x 2014-01-02 (B) 2013-12-30 Create golang library test cases @Go +go-todotxt"
testGot = testTasklist[taskId-1].Task()
if testGot != testExpected {
t.Errorf("Expected Task[%d] to be [%s], but got [%s]", taskId, testExpected, testGot)
}
taskId++
testExpected = "x 2014-01-03 2014-01-01 Create some more golang library test cases @Go +go-todotxt"
testGot = testTasklist[taskId-1].Task()
if testGot != testExpected {
t.Errorf("Expected Task[%d] to be [%s], but got [%s]", taskId, testExpected, testGot)
}
taskId++
}
func TestTaskPriority(t *testing.T) {
testTasklist.LoadFromFilename(testInputTask)
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++
testExpected = "C"
testGot = testTasklist[taskId-1].Priority
if testGot != testExpected {
t.Errorf("Expected Task[%d] to have priority '%s', but got '%s'", taskId, testExpected, testGot)
}
taskId++
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++
if testTasklist[taskId-1].HasPriority() {
t.Errorf("Expected Task[%d] to have no priority, but got '%s'", taskId, testTasklist[4].Priority)
}
taskId++
}
func TestTaskCreatedDate(t *testing.T) {
testTasklist.LoadFromFilename(testInputTask)
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++
testExpected, err = time.Parse(DateLayout, "2013-02-22")
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++
testExpected, err = time.Parse(DateLayout, "2014-01-01")
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++
testExpected, err = time.Parse(DateLayout, "2013-12-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++
testExpected, err = time.Parse(DateLayout, "2014-01-01")
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++
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(testInputTask)
taskId := 16
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(testInputTask)
taskId := 20
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(testInputTask)
taskId := 23
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(testInputTask)
taskId := 25
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(testInputTask)
taskId := 29
testExpected = true
testGot = testTasklist[taskId-1].Completed
if testGot != testExpected {
t.Errorf("Expected Task[%d] to be completed, but got '%v'", taskId, 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)
}
taskId++
testExpected = true
testGot = testTasklist[taskId-1].Completed
if testGot != testExpected {
t.Errorf("Expected Task[%d] 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++
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(testInputTask)
taskId := 34
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++
}
func TestTaskIsOverdue(t *testing.T) {
testTasklist.LoadFromFilename(testInputTask)
taskId := 40
testGot = testTasklist[taskId-1].IsOverdue()
if !testGot.(bool) {
t.Errorf("Expected Task[%d] to be overdue, but got '%v'", taskId, testGot)
}
taskId++
testGot = testTasklist[taskId-1].IsOverdue()
if testGot.(bool) {
t.Errorf("Expected Task[%d] not to be overdue, but got '%v'", taskId, testGot)
}
testTasklist[taskId-1].DueDate = time.Now().AddDate(0, 0, 1)
testGot = testTasklist[taskId-1].Due()
if testGot.(time.Duration).Hours() < 23 ||
testGot.(time.Duration).Hours() > 25 {
t.Errorf("Expected Task[%d] to be due in 24 hours, but got '%v'", taskId, testGot)
}
taskId++
testGot = testTasklist[taskId-1].IsOverdue()
if !testGot.(bool) {
t.Errorf("Expected Task[%d] to be overdue, but got '%v'", taskId, testGot)
}
testTasklist[taskId-1].DueDate = time.Now().AddDate(0, 0, -3)
testGot = testTasklist[taskId-1].Due()
if testGot.(time.Duration).Hours() < 71 ||
testGot.(time.Duration).Hours() > 73 {
t.Errorf("Expected Task[%d] to be due since 72 hours, but got '%v'", taskId, testGot)
}
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 {
if len(list1) != len(list2) {
return false
}
for i := range list1 {
if list1[i] != list2[i] {
return false
}
}
return true
}
func compareMaps(map1 map[string]string, map2 map[string]string) bool {
if len(map1) != len(map2) {
return false
}
compare := func(map1 map[string]string, map2 map[string]string) bool {
for key, value := range map1 {
if value2, found := map2[key]; !found {
return false
} else if value != value2 {
return false
}
}
return true
}
return compare(map1, map2) && compare(map2, map1)
}

21
testdata/example.go vendored
View File

@ -1,21 +0,0 @@
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,63 +0,0 @@
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 (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
(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
x 2014-01-04 (B) 2013-12-30 Create golang library @Go +go-todotxt due:2014-01-02
(B) 2013-12-01 Outline chapter 5 @Computer +Novel Level:5 private:false due:2014-02-17
Research self-publishing services +Novel due:2014-01-01
2013-02-22 Pick up milk @GroceryStore
x 2014-01-02 (B) 2013-12-30 Create golang library test cases @Go +go-todotxt
x (C) 2014-01-01 Create golang library documentation @Go +go-todotxt due:2014-01-12
(D) 2013-12-01 Outline chapter 5 @Computer +Novel Level:5 private:false due:2014-02-17
x 2014-01-03 Create golang library @Go +go-todotxt due:2014-01-05
(A) 2012-01-30 Call Mom @Call @Phone +Family
x 2014-01-02 (B) 2013-12-30 Create golang library test cases @Go +go-todotxt
x 2014-01-03 Create golang library @Go +go-todotxt due:2014-01-05
2013-02-22 Pick up milk @GroceryStore
(A) Call Mom @Call @Phone +Family
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-01-04 2014-01-01 Create some more golang library test cases @Go +go-todotxt
2013-02-22 Pick up milk @GroceryStore
(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 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

View File

@ -1,63 +0,0 @@
2013-02-22 Pick up milk @GroceryStore
x Download Todo.txt mobile app @Phone
(C) 2013-12-01 Go home! @Computer +Novel Level:5 private:false due:2011-11-11
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 (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
(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
x 2014-01-04 (B) 2013-12-30 Create golang library @Go +go-todotxt due:2014-01-02
(B) 2013-12-01 Outline chapter 5 @Computer +Novel Level:5 private:false due:2014-02-17
Research self-publishing services +Novel due:2014-01-01
2013-02-22 Pick up milk @GroceryStore
x 2014-01-02 (B) 2013-12-30 Create golang library test cases @Go +go-todotxt
x (C) 2014-01-01 Create golang library documentation @Go +go-todotxt due:2014-01-12
(D) 2013-12-01 Outline chapter 5 @Computer +Novel Level:5 private:false due:2014-02-17
x 2014-01-03 Create golang library @Go +go-todotxt due:2014-01-05
(A) 2012-01-30 Call Mom @Call @Phone +Family
x 2014-01-02 (B) 2013-12-30 Create golang library test cases @Go +go-todotxt
x 2014-01-03 Create golang library @Go +go-todotxt due:2014-01-05
2013-02-22 Pick up milk @GroceryStore
(A) Call Mom @Call @Phone +Family
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-01-04 2014-01-01 Create some more golang library test cases @Go +go-todotxt
2013-02-22 Pick up milk @GroceryStore
(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 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

View File

@ -1,28 +0,0 @@
# Sort Priority test case
2013-02-22 Pick up milk @GroceryStore
x 2014-01-02 (B) 2013-12-30 Create golang library test cases @Go +go-todotxt
x (C) 2014-01-01 Create golang library documentation @Go +go-todotxt due:2014-01-12
(D) 2013-12-01 private:false Outline chapter 5 +Novel @Computer Level:5 due:2014-02-17
x 2014-01-03 Create golang library @Go +go-todotxt due:2014-01-05
(A) 2012-01-30 @Phone Call Mom @Call +Family
# Sort CreatedDate test case
x 2014-01-02 (B) 2013-12-30 Create golang library test cases @Go +go-todotxt
x 2014-01-03 Create golang library @Go +go-todotxt due:2014-01-05
2013-02-22 Pick up milk @GroceryStore
(A) @Phone Call Mom @Call +Family
x (C) 2014-01-01 Create golang library documentation @Go +go-todotxt due:2014-01-12
# Sort CompletedDate test case
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-04 2014-01-01 Create some more golang library test cases @Go +go-todotxt
2013-02-22 Pick up milk @GroceryStore
# Sort DueDate test case
(B) 2013-12-01 private:false Outline chapter 5 +Novel @Computer due:2014-02-17 Level:5
x 2014-01-02 (B) 2013-12-30 Create golang library test cases @Go +go-todotxt
x 2014-01-03 due:2014-01-05 Create golang library @Go +go-todotxt
x (C) 2014-01-01 Create golang library documentation @Go due:2014-01-12 +go-todotxt

View File

@ -1,78 +0,0 @@
# String test cases
2013-02-22 Pick up milk @GroceryStore
x Download Todo.txt mobile app @Phone
(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
# Priority test cases
(B) 2013-12-01 private:false Outline chapter 5 +Novel @Computer Level:5 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
+Gardening Plan backyard herb garden +Planning @Home +Improving
# CreatedDate test cases
(A) 2012-01-30 @Phone Call Mom @Call +Family
2013-02-22 Pick up milk @GroceryStore
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
(C) Add cover sheets @Office +TPSReports
# Contexts test cases
(A) 2012-01-30 @Phone Call Mom @Call +Family
(C) Add cover sheets @Office +TPSReports
@Home Turn off TV @Electricity @Television @Electricity @Of_Super-Importance Importance:Very!
Research self-publishing services +Novel +Novel +Novel due:2014-01-01
# Projects test cases
+Gardening Plan backyard herb garden +Planning @Home +Improving +Relaxing-Work
Research self-publishing services +Novel +Novel +Novel due:2014-01-01
@Home Turn off TV @Electricity @Television @Electricity Importance:Very!
# DueDate test cases
(B) 2013-12-01 private:false Outline chapter 5 +Novel @Computer due:2014-02-17 Level:5
x 2014-01-02 (B) 2013-12-30 Create golang library test cases @Go +go-todotxt
# AdditionalTags test cases
(B) 2013-12-01 private:false Outline chapter 5 +Novel @Computer Level:5 due:2014-02-17
@Home Turn off TV @Electricity @Television @Electricity Importance:Very!
x (C) 2014-01-01 Create golang library documentation @Go +go-todotxt due:2014-01-12
(A) 2012-01-30 @Phone Call Mom @Call +Family
# Completed test cases
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
# CompletedDate test cases
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
# Overdue test cases
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:2027-07-17 Level:5
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

View File

@ -1,6 +0,0 @@
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

View File

@ -1,5 +0,0 @@
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

View File

@ -1,5 +0,0 @@
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

File diff suppressed because one or more lines are too long

View File

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

View File

@ -1,7 +1,3 @@
/* 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 (
@ -26,11 +22,11 @@ var (
projectRx = regexp.MustCompile(`(^|\s+)\+(\S+)`) // Match projects: '+Project...' or '... +Project ...')
)
// Task represents a todo.txt task entry.
type Task struct {
Id int // Internal task id.
Original string // Original raw task text.
Todo string // Todo part of task text.
// Todo represents a todo.txt task entry.
type Todo struct {
Id int // Internal todo id.
Original string // Original raw todo text.
Todo string // Todo part of todo text.
Priority string
Projects []string
Contexts []string
@ -41,7 +37,7 @@ type Task struct {
Completed bool
}
// String returns a complete task string in todo.txt format.
// String returns a complete todo string in todo.txt format.
//
// Contexts, Projects and additional tags are alphabetically sorted,
// and appendend at the end in the following order:
@ -50,102 +46,102 @@ type Task struct {
// For example:
//
// "(A) 2013-07-23 Call Dad @Home @Phone +Family due:2013-07-31 customTag1:Important!"
func (task Task) String() string {
func (todo Todo) String() string {
var text string
if task.Completed {
if todo.Completed {
text += "x "
if task.HasCompletedDate() {
text += fmt.Sprintf("%s ", task.CompletedDate.Format(DateLayout))
if todo.HasCompletedDate() {
text += fmt.Sprintf("%s ", todo.CompletedDate.Format(DateLayout))
}
}
if task.HasPriority() {
text += fmt.Sprintf("(%s) ", task.Priority)
if todo.HasPriority() {
text += fmt.Sprintf("(%s) ", todo.Priority)
}
if task.HasCreatedDate() {
text += fmt.Sprintf("%s ", task.CreatedDate.Format(DateLayout))
if todo.HasCreatedDate() {
text += fmt.Sprintf("%s ", todo.CreatedDate.Format(DateLayout))
}
text += task.Todo
text += todo.Todo
if len(task.Contexts) > 0 {
sort.Strings(task.Contexts)
for _, context := range task.Contexts {
if len(todo.Contexts) > 0 {
sort.Strings(todo.Contexts)
for _, context := range todo.Contexts {
text += fmt.Sprintf(" @%s", context)
}
}
if len(task.Projects) > 0 {
sort.Strings(task.Projects)
for _, project := range task.Projects {
if len(todo.Projects) > 0 {
sort.Strings(todo.Projects)
for _, project := range todo.Projects {
text += fmt.Sprintf(" +%s", project)
}
}
if len(task.AdditionalTags) > 0 {
if len(todo.AdditionalTags) > 0 {
// Sort map alphabetically by keys
keys := make([]string, 0, len(task.AdditionalTags))
for key := range task.AdditionalTags {
keys := make([]string, 0, len(todo.AdditionalTags))
for key := range todo.AdditionalTags {
keys = append(keys, key)
}
sort.Strings(keys)
for _, key := range keys {
text += fmt.Sprintf(" %s:%s", key, task.AdditionalTags[key])
text += fmt.Sprintf(" %s:%s", key, todo.AdditionalTags[key])
}
}
if task.HasDueDate() {
text += fmt.Sprintf(" due:%s", task.DueDate.Format(DateLayout))
if todo.HasDueDate() {
text += fmt.Sprintf(" due:%s", todo.DueDate.Format(DateLayout))
}
return text
}
// NewTask creates a new empty Task with default values. (CreatedDate is set to Now())
func NewTask() Task {
task := Task{}
task.CreatedDate = time.Now()
return task
// NewTodo creates a new empty Todo with default values. (CreatedDate is set to Now())
func NewTodo() Todo {
todo := Todo{}
todo.CreatedDate = time.Now()
return todo
}
// ParseTask parses the input text string into a Task struct.
func ParseTask(text string) (*Task, error) {
// ParseTodo parses the input text string into a Todo struct.
func ParseTodo(text string) (*Todo, error) {
var err error
task := Task{}
task.Original = strings.Trim(text, "\t\n\r ")
task.Todo = task.Original
todo := Todo{}
todo.Original = strings.Trim(text, "\t\n\r ")
todo.Todo = todo.Original
// Check for completed
if completedRx.MatchString(task.Original) {
task.Completed = true
if completedRx.MatchString(todo.Original) {
todo.Completed = true
// Check for completed date
if completedDateRx.MatchString(task.Original) {
if date, err := time.Parse(DateLayout, completedDateRx.FindStringSubmatch(task.Original)[1]); err == nil {
task.CompletedDate = date
if completedDateRx.MatchString(todo.Original) {
if date, err := time.Parse(DateLayout, completedDateRx.FindStringSubmatch(todo.Original)[1]); err == nil {
todo.CompletedDate = date
} else {
return nil, err
}
}
// 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 '
todo.Todo = completedDateRx.ReplaceAllString(todo.Todo, "") // Strip CompletedDate first, otherwise it wouldn't match anymore (^x date...)
todo.Todo = completedRx.ReplaceAllString(todo.Todo, "") // Strip 'x '
}
// Check for priority
if priorityRx.MatchString(task.Original) {
task.Priority = priorityRx.FindStringSubmatch(task.Original)[2]
task.Todo = priorityRx.ReplaceAllString(task.Todo, "") // Remove from Todo text
if priorityRx.MatchString(todo.Original) {
todo.Priority = priorityRx.FindStringSubmatch(todo.Original)[2]
todo.Todo = priorityRx.ReplaceAllString(todo.Todo, "") // Remove from Todo text
}
// Check for created date
if createdDateRx.MatchString(task.Original) {
if date, err := time.Parse(DateLayout, createdDateRx.FindStringSubmatch(task.Original)[2]); err == nil {
task.CreatedDate = date
task.Todo = createdDateRx.ReplaceAllString(task.Todo, "") // Remove from Todo text
if createdDateRx.MatchString(todo.Original) {
if date, err := time.Parse(DateLayout, createdDateRx.FindStringSubmatch(todo.Original)[2]); err == nil {
todo.CreatedDate = date
todo.Todo = createdDateRx.ReplaceAllString(todo.Todo, "") // Remove from Todo text
} else {
return nil, err
}
@ -153,7 +149,7 @@ func ParseTask(text string) (*Task, error) {
// function for collecting projects/contexts as slices from text
getSlice := func(rx *regexp.Regexp) []string {
matches := rx.FindAllStringSubmatch(task.Original, -1)
matches := rx.FindAllStringSubmatch(todo.Original, -1)
slice := make([]string, 0, len(matches))
seen := make(map[string]bool, len(matches))
for _, match := range matches {
@ -168,26 +164,26 @@ func ParseTask(text string) (*Task, error) {
}
// Check for contexts
if contextRx.MatchString(task.Original) {
task.Contexts = getSlice(contextRx)
task.Todo = contextRx.ReplaceAllString(task.Todo, "") // Remove from Todo text
if contextRx.MatchString(todo.Original) {
todo.Contexts = getSlice(contextRx)
todo.Todo = contextRx.ReplaceAllString(todo.Todo, "") // Remove from Todo text
}
// Check for projects
if projectRx.MatchString(task.Original) {
task.Projects = getSlice(projectRx)
task.Todo = projectRx.ReplaceAllString(task.Todo, "") // Remove from Todo text
if projectRx.MatchString(todo.Original) {
todo.Projects = getSlice(projectRx)
todo.Todo = projectRx.ReplaceAllString(todo.Todo, "") // Remove from Todo text
}
// Check for additional tags
if addonTagRx.MatchString(task.Original) {
matches := addonTagRx.FindAllStringSubmatch(task.Original, -1)
if addonTagRx.MatchString(todo.Original) {
matches := addonTagRx.FindAllStringSubmatch(todo.Original, -1)
tags := make(map[string]string, len(matches))
for _, match := range matches {
key, value := match[2], match[3]
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 {
task.DueDate = date
todo.DueDate = date
} else {
return nil, err
}
@ -195,57 +191,51 @@ func ParseTask(text string) (*Task, error) {
tags[key] = value
}
}
task.AdditionalTags = tags
task.Todo = addonTagRx.ReplaceAllString(task.Todo, "") // Remove from Todo text
todo.AdditionalTags = tags
todo.Todo = addonTagRx.ReplaceAllString(todo.Todo, "") // Remove from Todo text
}
// Trim any remaining whitespaces from Todo text
task.Todo = strings.Trim(task.Todo, "\t\n\r\f ")
todo.Todo = strings.Trim(todo.Todo, "\t\n\r\f ")
return &task, err
}
// Task returns a complete task string in todo.txt format.
// See *Task.String() for further information.
func (task *Task) Task() string {
return task.String()
return &todo, err
}
// HasPriority returns true if the task has a priority.
func (task *Task) HasPriority() bool {
return task.Priority != ""
func (todo *Todo) HasPriority() bool {
return todo.Priority != ""
}
// HasCreatedDate returns true if the task has a created date.
func (task *Task) HasCreatedDate() bool {
return !task.CreatedDate.IsZero()
func (todo *Todo) HasCreatedDate() bool {
return !todo.CreatedDate.IsZero()
}
// HasDueDate returns true if the task has a due date.
func (task *Task) HasDueDate() bool {
return !task.DueDate.IsZero()
func (todo *Todo) HasDueDate() bool {
return !todo.DueDate.IsZero()
}
// HasCompletedDate returns true if the task has a completed date.
func (task *Task) HasCompletedDate() bool {
return !task.CompletedDate.IsZero() && task.Completed
func (todo *Todo) HasCompletedDate() bool {
return !todo.CompletedDate.IsZero() && todo.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()
func (todo *Todo) Complete() {
if !todo.Completed {
todo.Completed = true
todo.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
func (todo *Todo) Reopen() {
if todo.Completed {
todo.Completed = false
todo.CompletedDate = time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC) // time.IsZero() value
}
}
@ -253,9 +243,9 @@ func (task *Task) Reopen() {
//
// This function does not take the Completed flag into consideration.
// You should check Task.Completed first if needed.
func (task *Task) IsOverdue() bool {
if task.HasDueDate() {
return task.DueDate.Before(time.Now())
func (todo *Todo) IsOverdue() bool {
if todo.HasDueDate() {
return todo.DueDate.Before(time.Now())
}
return false
}
@ -265,15 +255,15 @@ func (task *Task) IsOverdue() bool {
//
// Just as with IsOverdue(), this function does also not take the Completed flag into consideration.
// You should check Task.Completed first if needed.
func (task *Task) Due() time.Duration {
if task.IsOverdue() {
return time.Now().Sub(task.DueDate)
func (todo *Todo) Due() time.Duration {
if todo.IsOverdue() {
return time.Now().Sub(todo.DueDate)
}
return task.DueDate.Sub(time.Now())
return todo.DueDate.Sub(time.Now())
}
func (task *Task) HasContext(ctx string) bool {
for _, c := range task.Contexts {
func (todo *Todo) HasContext(ctx string) bool {
for _, c := range todo.Contexts {
if c == ctx {
return true
}
@ -281,8 +271,8 @@ func (task *Task) HasContext(ctx string) bool {
return false
}
func (task *Task) HasProject(proj string) bool {
for _, p := range task.Projects {
func (todo *Todo) HasProject(proj string) bool {
for _, p := range todo.Projects {
if p == proj {
return true
}

View File

@ -1,8 +0,0 @@
(A) Call Mom @Phone +Family
(A) Schedule annual checkup +Health
(B) Outline chapter 5 +Novel @Computer
(C) Add cover sheets @Office +TPSReports
Plan backyard herb garden @Home
Pick up milk @GroceryStore
Research self-publishing services +Novel @Computer
x Download Todo.txt mobile app @Phone

300
todolist.go Normal file
View File

@ -0,0 +1,300 @@
package todotxt
import (
"bufio"
"errors"
"fmt"
"io/ioutil"
"os"
"strings"
)
type TodoList struct {
todos []*Todo
sortFlag int
}
// Newtodolist creates a new empty todolist.
func NewTodoList() *TodoList { return &TodoList{} }
func (todolist *TodoList) Size() int { return len(todolist.todos) }
func (todolist *TodoList) GetTaskSlice() []*Todo { return todolist.todos }
func (todolist *TodoList) Contains(t *Todo) bool {
for _, tsk := range todolist.todos {
if tsk == t {
return true
}
}
return false
}
func (todolist *TodoList) GetTasksWithContext(context string) *TodoList {
return todolist.Filter(func(t *Todo) bool {
return t.HasContext(context)
})
}
func (todolist *TodoList) GetTasksWithProject(project string) *TodoList {
return todolist.Filter(func(t *Todo) bool {
return t.HasProject(project)
})
}
func (todolist *TodoList) GetContexts() []string {
var ret []string
added := make(map[string]bool)
for _, tsk := range todolist.todos {
for _, c := range tsk.Contexts {
if !added[c] {
ret = append(ret, c)
added[c] = true
}
}
}
sort.String(ret)
return ret
}
func (todolist *TodoList) GetProjects() []string {
var ret []string
added := make(map[string]bool)
for _, tsk := range todolist.todos {
for _, p := range tsk.Projects {
if !added[p] {
ret = append(ret, p)
added[p] = true
}
}
}
sort.Strings(ret)
return ret
}
func (todolist *TodoList) GetTagKVList() []string {
var ret []string
added := make(map[string]bool)
for _, tsk := range todolist.todos {
for k, v := range tsk.AdditionalTags {
tag := fmt.Sprintf("%s:%s", k, v)
if !added[tag] {
ret = append(ret, tag)
added[tag] = true
}
}
}
sort.Strings(ret)
return ret
}
func (todolist *TodoList) GetTagKeys() []string {
var ret []string
added := make(map[string]bool)
for _, tsk := range todolist.todos {
for k := range tsk.AdditionalTags {
if !added[k] {
ret = append(ret, k)
added[k] = true
}
}
}
sort.Strings(ret)
return ret
}
func (todolist *TodoList) GetTagValuesForKey(key string) []string {
var ret []string
added := make(map[string]bool)
for _, tsk := range todolist.todos {
if v, ok := tsk.AdditionalTags[key]; ok && !added[v] {
ret = append(ret, v)
added[v] = true
}
}
sort.Strings(ret)
return ret
}
func (todolist *TodoList) GetIncompleteTasks() *TodoList {
t := *NewTodoList()
for _, v := range todolist.todos {
if !v.Complete {
t.todos = append(t.todos, v)
}
}
return &t
}
// String returns a complete list of tasks in todo.txt format.
func (todolist *TodoList) String() string {
var ret string
for _, todo := range todolist.todos {
ret += fmt.Sprintf("%s\n", todo.String())
}
return ret
}
// AddTodo prepends a Todo to the current TodoList and takes care to set the Todo.Id correctly
func (todolist *TodoList) AddTodo(todo *Todo) {
todolist.todos = append(todolist.todos, todo)
todolist.refresh()
}
// AddTimers adds all passed in timers to the list, sorts the list, then updates the Timer.Id values.
func (todolist *TodoList) AddTodos(todos []*Todo) {
todolist.todos = append(todolist.todos, todos...)
todolist.Sort(SORT_START_DATE_ASC)
}
func (todolist *TodoList) Combine(other *TodoList) { todolist.AddTodo(other.todos) }
// GetTodo returns the Todo with the given todo 'id' from the TodoList.
// Returns an error if Todo could not be found.
func (todolist *TodoList) GetTodo(id int) (*Todo, error) {
for i := range todolist.todos {
if todolist.todos[i].Id == id {
return todolist.todos[i], nil
}
}
return nil, errors.New("todo not found")
}
// RemoveTodoById removes any Todo with the given Todo 'id' from the TodoList.
// Returns an error if no Todo was removed
func (todolist *TodoList) RemoveTodoById(id int) error {
found := false
var remIdx int
var t *Todo
for remIdx, t = range todolist.todos {
if t.Id == id {
found = true
break
}
}
if !found {
return errors.New("todo not found")
}
todolist.todos = append(todolist.todos[:remIdx], todolist.todos[remIdx+1:]...)
todolist.refresh()
return nil
}
// RemoveTodo removes any Todo from the TodoList with the same String representation as the given Todo.
// Returns an error if no Todo was removed.
func (todolist *TodoList) RemoveTodo(todo Todo) error {
found := false
var remIdx int
var t *Todo
for remIdx, t = range todolist.todos {
if t.String() == todo.String() {
found = true
break
}
}
if !found {
return errors.New("todo not found")
}
todolist.todos = append(todolist.todos[:remIdx], todolist.todos[remIdx+1:]...)
todolist.refresh()
return nil
}
// ArchiveTodoToFile removes the todo from the active list and concatenates it to
// the passed in filename
// Return an err if any part of that fails
func (todolist *TodoList) ArchiveTodoToFile(todo Todo, filename string) error {
if err := todolist.RemoveTodo(todo); err != nil {
return err
}
f, err := os.OpenFile(filename, os.O_APPEND|os.O_WRONLY, 0600)
if err != nil {
return err
}
defer f.Close()
_, err = f.WriteString(todo.String() + "\n")
return err
}
// Filter filters the current TodoList for the given predicate (a function that takes a todo as input and returns a
// bool), and returns a new TodoList. The original TodoList is not modified.
func (todolist *TodoList) Filter(predicate func(*Todo) bool) *TodoList {
var newList TodoList
for _, t := range todolist.todos {
if predicate(t) {
newList.todos = append(newList.todos, t)
}
}
return &newList
}
// LoadFromFile loads a TodoList from *os.File.
// Note: This will clear the current TodoList and overwrite it's contents with whatever is in *os.File.
func (todolist *TodoList) LoadFromFile(file *os.File) error {
todolist.todos = []*Todo{} // Empty todolist
todoId := 1
scanner := bufio.NewScanner(file)
for scanner.Scan() {
text := strings.Trim(scanner.Text(), "\t\n\r") // Read Line
// Ignore blank lines
if text == "" {
continue
}
todo, err := ParseTodo(text)
if err != nil {
return err
}
todo.Id = todoId
todoId++
todolist.todos = append(todolist.todos, todo)
}
if err := scanner.Err(); err != nil {
return err
}
todolist.refresh()
return nil
}
// WriteToFile writes a TodoList to *os.File
func (todolist *TodoList) WriteToFile(file *os.File) error {
writer := bufio.NewWriter(file)
_, err := writer.WriteString(todolist.String())
writer.Flush()
return err
}
// LoadFromFilename loads a TodoList from the filename.
func (todolist *TodoList) LoadFromFilename(filename string) error {
file, err := os.Open(filename)
if err != nil {
return err
}
defer file.Close()
return todolist.LoadFromFile(file)
}
// WriteToFilename writes a TodoList to the specified file (most likely called "todo.txt").
func (todolist *TodoList) WriteToFilename(filename string) error {
return ioutil.WriteFile(filename, []byte(todolist.String()), 0640)
}
// LoadFromFile loads and returns a TodoList from *os.File.
func LoadFromFile(file *os.File) (*TodoList, error) {
todolist := TodoList{}
if err := todolist.LoadFromFile(file); err != nil {
return nil, err
}
return &todolist, nil
}
// WriteToFile writes a TodoList to *os.File.
func WriteToFile(todolist *TodoList, file *os.File) error {
return todolist.WriteToFile(file)
}
// LoadFromFilename loads and returns a TodoList from a file (most likely called "todo.txt")
func LoadFromFilename(filename string) (*TodoList, error) {
todolist := TodoList{}
if err := todolist.LoadFromFilename(filename); err != nil {
return nil, err
}
return &todolist, nil
}
// WriteToFilename write a TodoList to the specified file (most likely called "todo.txt")
func WriteToFilename(todolist *TodoList, filename string) error {
return todolist.WriteToFilename(filename)
}

View File

@ -1,237 +0,0 @@
/* 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 is a Go client library for Gina Trapani's todo.txt files.
// It allows for parsing and manipulating of task lists and tasks in the todo.txt format.
//
// Source code and project home: https://github.com/JamesClonk/go-todotxt
package todotxt
import (
"bufio"
"errors"
"fmt"
"io/ioutil"
"os"
"strings"
)
// TaskList represents a list of todo.txt task entries.
// It is usually loaded from a whole todo.txt file.
type TaskList []Task
// IgnoreComments can be set to 'true', to ignore lines that start with #
// The todo.txt format does not define comments.
var (
// 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 = false
)
// 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())
}
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) {
task.Id = 0
for _, t := range *tasklist {
if t.Id > task.Id {
task.Id = t.Id
}
}
task.Id += 1
*tasklist = append(*tasklist, *task)
}
// GetTask returns a Task by given task 'id' from the TaskList. The returned Task pointer can be used to update the Task inside the TaskList.
// Returns an error if Task could not be found.
func (tasklist *TaskList) GetTask(id int) (*Task, error) {
for i := range *tasklist {
if ([]Task(*tasklist))[i].Id == id {
return &([]Task(*tasklist))[i], 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.
//
// Using *os.File instead of a filename allows to also use os.Stdin.
//
// Note: This will clear the current TaskList and overwrite it's contents with whatever is in *os.File.
func (tasklist *TaskList) LoadFromFile(file *os.File) error {
*tasklist = []Task{} // Empty tasklist
taskId := 1
scanner := bufio.NewScanner(file)
for scanner.Scan() {
text := strings.Trim(scanner.Text(), "\t\n\r ") // Read line
// Ignore blank or comment lines
if text == "" || (IgnoreComments && strings.HasPrefix(text, "#")) {
continue
}
task, err := ParseTask(text)
if err != nil {
return err
}
task.Id = taskId
*tasklist = append(*tasklist, *task)
taskId++
}
if err := scanner.Err(); err != nil {
return err
}
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").
//
// Note: This will clear the current TaskList and overwrite it's contents with whatever is in the file.
func (tasklist *TaskList) LoadFromFilename(filename string) error {
file, err := os.Open(filename)
if err != nil {
return err
}
defer file.Close()
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()), 0640)
}
func (tasklist *TaskList) ArchiveTaskToFile(task Task, filename string) error {
if err := tasklist.RemoveTask(task); err != nil {
return err
}
f, err := os.OpenFile(filename, os.O_APPEND|os.O_WRONLY, 0600)
if err != nil {
return err
}
defer f.Close()
_, err = f.WriteString(task.String() + "\n")
return err
}
func (tasklist *TaskList) GetTaskSlice() []*Task {
var res []*Task
for _, t := range *tasklist {
res = append(res, &t)
}
return res
}
// LoadFromFile loads and returns a TaskList from *os.File.
//
// Using *os.File instead of a filename allows to also use os.Stdin.
func LoadFromFile(file *os.File) (TaskList, error) {
tasklist := TaskList{}
if err := tasklist.LoadFromFile(file); err != nil {
return nil, err
}
return tasklist, nil
}
// 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").
func LoadFromFilename(filename string) (TaskList, error) {
tasklist := TaskList{}
if err := tasklist.LoadFromFilename(filename); err != nil {
return nil, err
}
return tasklist, nil
}
// 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

@ -1,522 +0,0 @@
/* 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 (
"io/ioutil"
"os"
"testing"
"time"
)
var (
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"
testExpectedOutput = "testdata/expected_todo.txt"
testTasklist TaskList
testExpected interface{}
testGot interface{}
)
func TestLoadFromFile(t *testing.T) {
file, err := os.Open(testInputTasklist)
if err != nil {
t.Fatal(err)
}
defer file.Close()
if testTasklist, err := LoadFromFile(file); err != nil {
t.Fatal(err)
} else {
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)
}
}
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) {
if testTasklist, err := LoadFromFilename(testInputTasklist); err != nil {
t.Fatal(err)
} else {
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)
}
}
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) {
os.Remove(testOutput)
os.Create(testOutput)
var err error
fileInput, err := os.Open(testInputTasklist)
if err != nil {
t.Fatal(err)
}
defer fileInput.Close()
fileOutput, err := os.OpenFile(testOutput, os.O_RDWR, 0644)
if err != nil {
t.Fatal(err)
}
defer fileInput.Close()
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 {
t.Fatal(err)
}
if testTasklist, err = 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 TestTaskListWriteFile(t *testing.T) {
os.Remove(testOutput)
os.Create(testOutput)
testTasklist := TaskList{}
fileInput, err := os.Open(testInputTasklist)
if err != nil {
t.Fatal(err)
}
defer fileInput.Close()
fileOutput, err := os.OpenFile(testOutput, os.O_RDWR, 0644)
if err != nil {
t.Fatal(err)
}
defer fileInput.Close()
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(testInputTasklist); 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(testInputTasklist); 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 TestNewTaskList(t *testing.T) {
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) {
if err := testTasklist.LoadFromFilename(testInputTasklist); err != nil {
t.Fatal(err)
}
testExpected = 63
testGot = len(testTasklist)
if testGot != testExpected {
t.Errorf("Expected TaskList to contain %d tasks, but got %d", testExpected, testGot)
}
}
func TestTaskListAddTask(t *testing.T) {
if err := testTasklist.LoadFromFilename(testInputTasklist); err != nil {
t.Fatal(err)
}
// add new empty task
task := NewTask()
testTasklist.AddTask(&task)
testExpected = 64
testGot = len(testTasklist)
if testGot != testExpected {
t.Errorf("Expected TaskList to contain %d tasks, but got %d", testExpected, testGot)
}
taskId := 64
testExpected = time.Now().Format(DateLayout) + " " // tasks created by NewTask() have their created date set
testGot = testTasklist[taskId-1].String()
if testGot != testExpected {
t.Errorf("Expected Task[%d] to be [%s], but got [%s]", taskId, testExpected, testGot)
}
testExpected = 64
testGot = testTasklist[taskId-1].Id
if testGot != testExpected {
t.Errorf("Expected Task[%d] to be [%d], but got [%d]", taskId, testExpected, testGot)
}
taskId++
// add parsed task
parsed, err := ParseTask("x (C) 2014-01-01 Create golang library documentation @Go +go-todotxt due:2014-01-12")
if err != nil {
t.Error(err)
}
testTasklist.AddTask(parsed)
testExpected = "x (C) 2014-01-01 Create golang library documentation @Go +go-todotxt due:2014-01-12"
testGot = testTasklist[taskId-1].String()
if testGot != testExpected {
t.Errorf("Expected Task[%d] to be [%s], but got [%s]", taskId, testExpected, testGot)
}
testExpected = 65
testGot = testTasklist[taskId-1].Id
if testGot != testExpected {
t.Errorf("Expected Task[%d] to be [%d], but got [%d]", taskId, testExpected, testGot)
}
taskId++
// add selfmade task
createdDate := time.Now()
testTasklist.AddTask(&Task{
CreatedDate: createdDate,
Todo: "Go shopping..",
Contexts: []string{"GroceryStore"},
})
testExpected = createdDate.Format(DateLayout) + " Go shopping.. @GroceryStore"
testGot = testTasklist[taskId-1].String()
if testGot != testExpected {
t.Errorf("Expected Task[%d] to be [%s], but got [%s]", taskId, testExpected, testGot)
}
testExpected = 66
testGot = testTasklist[taskId-1].Id
if testGot != testExpected {
t.Errorf("Expected Task[%d] to be [%d], but got [%d]", taskId, testExpected, testGot)
}
taskId++
// add task with explicit Id, AddTask() should ignore this!
testTasklist.AddTask(&Task{
Id: 101,
})
testExpected = 67
testGot = testTasklist[taskId-1].Id
if testGot != testExpected {
t.Errorf("Expected Task[%d] to be [%d], but got [%d]", taskId, testExpected, testGot)
}
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 TestTaskListUpdateTask(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)
}
task.Priority = "C"
task.Todo = "Go home!"
date, err := time.Parse(DateLayout, "2011-11-11")
if err != nil {
t.Error(err)
}
task.DueDate = date
testGot := task
os.Remove(testOutput)
if err := testTasklist.WriteToFilename(testOutput); err != nil {
t.Fatal(err)
}
if err := testTasklist.LoadFromFilename(testOutput); err != nil {
t.Fatal(err)
}
testExpected, err := testTasklist.GetTask(taskId)
if err != nil {
t.Error(err)
}
if testGot.Task() != testExpected.Task() {
t.Errorf("Expected Task to be [%v]\n, but got [%v]", testExpected, testGot)
}
}
func TestTaskListRemoveTaskById(t *testing.T) {
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) {
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) {
if err := testTasklist.LoadFromFilename(testInputTasklist); err != nil {
t.Fatal(err)
}
// Filter list to get only completed tasks
completedList := testTasklist.Filter(func(t Task) bool { return t.Completed })
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 { return t.HasDueDate() })
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 {
return t.HasPriority() && t.Priority == "B"
})
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) {
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)
}
}