Rework the whole library
This commit is contained in:
parent
11f1335a20
commit
7661923650
373
LICENSE
373
LICENSE
@ -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.
|
73
README.md
73
README.md
@ -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.
|
||||
|
@ -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
66
sort.go
@ -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
|
||||
}
|
||||
|
335
sort_test.go
335
sort_test.go
@ -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)
|
||||
}
|
||||
}
|
736
task_test.go
736
task_test.go
@ -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
21
testdata/example.go
vendored
@ -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)
|
||||
}
|
63
testdata/expected_todo.txt
vendored
63
testdata/expected_todo.txt
vendored
@ -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
|
63
testdata/ouput_todo.txt
vendored
63
testdata/ouput_todo.txt
vendored
@ -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
|
28
testdata/sort_todo.txt
vendored
28
testdata/sort_todo.txt
vendored
@ -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
|
78
testdata/task_todo.txt
vendored
78
testdata/task_todo.txt
vendored
@ -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
|
||||
|
6
testdata/tasklist_completedDate_error.txt
vendored
6
testdata/tasklist_completedDate_error.txt
vendored
@ -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
|
5
testdata/tasklist_createdDate_error.txt
vendored
5
testdata/tasklist_createdDate_error.txt
vendored
@ -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
|
5
testdata/tasklist_dueDate_error.txt
vendored
5
testdata/tasklist_dueDate_error.txt
vendored
@ -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
|
2
testdata/tasklist_scanner_error.txt
vendored
2
testdata/tasklist_scanner_error.txt
vendored
File diff suppressed because one or more lines are too long
63
testdata/tasklist_todo.txt
vendored
63
testdata/tasklist_todo.txt
vendored
@ -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
|
@ -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
|
||||
}
|
8
todo.txt
8
todo.txt
@ -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
300
todolist.go
Normal 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)
|
||||
}
|
237
todotxt.go
237
todotxt.go
@ -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)
|
||||
}
|
522
todotxt_test.go
522
todotxt_test.go
@ -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)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user