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.
|
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.
|
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.
|
It allows for parsing and manipulating of task lists and tasks in the todo.txt format.
|
||||||
|
|
||||||
## Installation
|
## Example todo.txt
|
||||||
|
```
|
||||||
$ go get github.com/JamesClonk/go-todotxt
|
(A) Call Mom @Phone +Family
|
||||||
|
(A) Schedule annual checkup +Health
|
||||||
## Requirements
|
(B) Outline chapter 5 +Novel @Computer
|
||||||
|
(C) Add cover sheets @Office +TPSReports
|
||||||
go-todotxt requires Go1.1 or higher.
|
Plan backyard herb garden @Home
|
||||||
|
Pick up milk @GroceryStore
|
||||||
## Usage
|
Research self-publishing services +Novel @Computer
|
||||||
|
x Download Todo.txt mobile app @Phone
|
||||||
```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")
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## 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
|
package todotxt
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -22,52 +18,52 @@ const (
|
|||||||
SORT_DUE_DATE_DESC
|
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.
|
// See constants SORT_* for fields and sort order.
|
||||||
func (tasklist *TaskList) Sort(sortFlag int) error {
|
func (todolist *TodoList) Sort(sortFlag int) error {
|
||||||
switch sortFlag {
|
switch sortFlag {
|
||||||
case SORT_PRIORITY_ASC, SORT_PRIORITY_DESC:
|
case SORT_PRIORITY_ASC, SORT_PRIORITY_DESC:
|
||||||
tasklist.sortByPriority(sortFlag)
|
todolist.sortByPriority(sortFlag)
|
||||||
case SORT_CREATED_DATE_ASC, SORT_CREATED_DATE_DESC:
|
case SORT_CREATED_DATE_ASC, SORT_CREATED_DATE_DESC:
|
||||||
tasklist.sortByCreatedDate(sortFlag)
|
todolist.sortByCreatedDate(sortFlag)
|
||||||
case SORT_COMPLETED_DATE_ASC, SORT_COMPLETED_DATE_DESC:
|
case SORT_COMPLETED_DATE_ASC, SORT_COMPLETED_DATE_DESC:
|
||||||
tasklist.sortByCompletedDate(sortFlag)
|
todolist.sortByCompletedDate(sortFlag)
|
||||||
case SORT_DUE_DATE_ASC, SORT_DUE_DATE_DESC:
|
case SORT_DUE_DATE_ASC, SORT_DUE_DATE_DESC:
|
||||||
tasklist.sortByDueDate(sortFlag)
|
todolist.sortByDueDate(sortFlag)
|
||||||
default:
|
default:
|
||||||
return errors.New("unrecognized sort option")
|
return errors.New("unrecognized sort option")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type tasklistSort struct {
|
type todolistSort struct {
|
||||||
tasklists TaskList
|
todolists TodoList
|
||||||
by func(t1, t2 *Task) bool
|
by func(t1, t2 *Todo) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ts *tasklistSort) Len() int {
|
func (ts *todolistSort) Len() int {
|
||||||
return len(ts.tasklists)
|
return len(ts.todolists)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ts *tasklistSort) Swap(l, r int) {
|
func (ts *todolistSort) Swap(l, r int) {
|
||||||
ts.tasklists[l], ts.tasklists[r] = ts.tasklists[r], ts.tasklists[l]
|
ts.todolists[l], ts.todolists[r] = ts.todolists[r], ts.todolists[l]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ts *tasklistSort) Less(l, r int) bool {
|
func (ts *todolistSort) Less(l, r int) bool {
|
||||||
return ts.by(&ts.tasklists[l], &ts.tasklists[r])
|
return ts.by(&ts.todolists[l], &ts.todolists[r])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tasklist *TaskList) sortBy(by func(t1, t2 *Task) bool) *TaskList {
|
func (todolist *TodoList) sortBy(by func(t1, t2 *Todo) bool) *TodoList {
|
||||||
ts := &tasklistSort{
|
ts := &todolistSort{
|
||||||
tasklists: *tasklist,
|
todolists: *todolist,
|
||||||
by: by,
|
by: by,
|
||||||
}
|
}
|
||||||
sort.Sort(ts)
|
sort.Sort(ts)
|
||||||
return tasklist
|
return todolist
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tasklist *TaskList) sortByPriority(order int) *TaskList {
|
func (todolist *TodoList) sortByPriority(order int) *TodoList {
|
||||||
tasklist.sortBy(func(t1, t2 *Task) bool {
|
todolist.sortBy(func(t1, t2 *Todo) bool {
|
||||||
if order == SORT_PRIORITY_ASC { // ASC
|
if order == SORT_PRIORITY_ASC { // ASC
|
||||||
if t1.HasPriority() && t2.HasPriority() {
|
if t1.HasPriority() && t2.HasPriority() {
|
||||||
return t1.Priority < t2.Priority
|
return t1.Priority < t2.Priority
|
||||||
@ -80,7 +76,7 @@ func (tasklist *TaskList) sortByPriority(order int) *TaskList {
|
|||||||
}
|
}
|
||||||
return !t1.HasPriority()
|
return !t1.HasPriority()
|
||||||
})
|
})
|
||||||
return tasklist
|
return todolist
|
||||||
}
|
}
|
||||||
|
|
||||||
func sortByDate(asc bool, hasDate1, hasDate2 bool, date1, date2 time.Time) bool {
|
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
|
return !hasDate2
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tasklist *TaskList) sortByCreatedDate(order int) *TaskList {
|
func (todolist *TodoList) sortByCreatedDate(order int) *TodoList {
|
||||||
tasklist.sortBy(func(t1, t2 *Task) bool {
|
todolist.sortBy(func(t1, t2 *Todo) bool {
|
||||||
return sortByDate(order == SORT_CREATED_DATE_ASC, t1.HasCreatedDate(), t2.HasCreatedDate(), t1.CreatedDate, t2.CreatedDate)
|
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 {
|
func (todolist *TodoList) sortByCompletedDate(order int) *TodoList {
|
||||||
tasklist.sortBy(func(t1, t2 *Task) bool {
|
todolist.sortBy(func(t1, t2 *Todo) bool {
|
||||||
return sortByDate(order == SORT_COMPLETED_DATE_ASC, t1.HasCompletedDate(), t2.HasCompletedDate(), t1.CompletedDate, t2.CompletedDate)
|
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 {
|
func (todolist *TodoList) sortByDueDate(order int) *TodoList {
|
||||||
tasklist.sortBy(func(t1, t2 *Task) bool {
|
todolist.sortBy(func(t1, t2 *Todo) bool {
|
||||||
return sortByDate(order == SORT_DUE_DATE_ASC, t1.HasDueDate(), t2.HasDueDate(), t1.DueDate, t2.DueDate)
|
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
|
package todotxt
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -26,11 +22,11 @@ var (
|
|||||||
projectRx = regexp.MustCompile(`(^|\s+)\+(\S+)`) // Match projects: '+Project...' or '... +Project ...')
|
projectRx = regexp.MustCompile(`(^|\s+)\+(\S+)`) // Match projects: '+Project...' or '... +Project ...')
|
||||||
)
|
)
|
||||||
|
|
||||||
// Task represents a todo.txt task entry.
|
// Todo represents a todo.txt task entry.
|
||||||
type Task struct {
|
type Todo struct {
|
||||||
Id int // Internal task id.
|
Id int // Internal todo id.
|
||||||
Original string // Original raw task text.
|
Original string // Original raw todo text.
|
||||||
Todo string // Todo part of task text.
|
Todo string // Todo part of todo text.
|
||||||
Priority string
|
Priority string
|
||||||
Projects []string
|
Projects []string
|
||||||
Contexts []string
|
Contexts []string
|
||||||
@ -41,7 +37,7 @@ type Task struct {
|
|||||||
Completed bool
|
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,
|
// Contexts, Projects and additional tags are alphabetically sorted,
|
||||||
// and appendend at the end in the following order:
|
// and appendend at the end in the following order:
|
||||||
@ -50,102 +46,102 @@ type Task struct {
|
|||||||
// For example:
|
// For example:
|
||||||
//
|
//
|
||||||
// "(A) 2013-07-23 Call Dad @Home @Phone +Family due:2013-07-31 customTag1:Important!"
|
// "(A) 2013-07-23 Call Dad @Home @Phone +Family due:2013-07-31 customTag1:Important!"
|
||||||
func (task Task) String() string {
|
func (todo Todo) String() string {
|
||||||
var text string
|
var text string
|
||||||
|
|
||||||
if task.Completed {
|
if todo.Completed {
|
||||||
text += "x "
|
text += "x "
|
||||||
if task.HasCompletedDate() {
|
if todo.HasCompletedDate() {
|
||||||
text += fmt.Sprintf("%s ", task.CompletedDate.Format(DateLayout))
|
text += fmt.Sprintf("%s ", todo.CompletedDate.Format(DateLayout))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if task.HasPriority() {
|
if todo.HasPriority() {
|
||||||
text += fmt.Sprintf("(%s) ", task.Priority)
|
text += fmt.Sprintf("(%s) ", todo.Priority)
|
||||||
}
|
}
|
||||||
|
|
||||||
if task.HasCreatedDate() {
|
if todo.HasCreatedDate() {
|
||||||
text += fmt.Sprintf("%s ", task.CreatedDate.Format(DateLayout))
|
text += fmt.Sprintf("%s ", todo.CreatedDate.Format(DateLayout))
|
||||||
}
|
}
|
||||||
|
|
||||||
text += task.Todo
|
text += todo.Todo
|
||||||
|
|
||||||
if len(task.Contexts) > 0 {
|
if len(todo.Contexts) > 0 {
|
||||||
sort.Strings(task.Contexts)
|
sort.Strings(todo.Contexts)
|
||||||
for _, context := range task.Contexts {
|
for _, context := range todo.Contexts {
|
||||||
text += fmt.Sprintf(" @%s", context)
|
text += fmt.Sprintf(" @%s", context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(task.Projects) > 0 {
|
if len(todo.Projects) > 0 {
|
||||||
sort.Strings(task.Projects)
|
sort.Strings(todo.Projects)
|
||||||
for _, project := range task.Projects {
|
for _, project := range todo.Projects {
|
||||||
text += fmt.Sprintf(" +%s", project)
|
text += fmt.Sprintf(" +%s", project)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(task.AdditionalTags) > 0 {
|
if len(todo.AdditionalTags) > 0 {
|
||||||
// Sort map alphabetically by keys
|
// Sort map alphabetically by keys
|
||||||
keys := make([]string, 0, len(task.AdditionalTags))
|
keys := make([]string, 0, len(todo.AdditionalTags))
|
||||||
for key := range task.AdditionalTags {
|
for key := range todo.AdditionalTags {
|
||||||
keys = append(keys, key)
|
keys = append(keys, key)
|
||||||
}
|
}
|
||||||
sort.Strings(keys)
|
sort.Strings(keys)
|
||||||
for _, key := range 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() {
|
if todo.HasDueDate() {
|
||||||
text += fmt.Sprintf(" due:%s", task.DueDate.Format(DateLayout))
|
text += fmt.Sprintf(" due:%s", todo.DueDate.Format(DateLayout))
|
||||||
}
|
}
|
||||||
|
|
||||||
return text
|
return text
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTask creates a new empty Task with default values. (CreatedDate is set to Now())
|
// NewTodo creates a new empty Todo with default values. (CreatedDate is set to Now())
|
||||||
func NewTask() Task {
|
func NewTodo() Todo {
|
||||||
task := Task{}
|
todo := Todo{}
|
||||||
task.CreatedDate = time.Now()
|
todo.CreatedDate = time.Now()
|
||||||
return task
|
return todo
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseTask parses the input text string into a Task struct.
|
// ParseTodo parses the input text string into a Todo struct.
|
||||||
func ParseTask(text string) (*Task, error) {
|
func ParseTodo(text string) (*Todo, error) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
task := Task{}
|
todo := Todo{}
|
||||||
task.Original = strings.Trim(text, "\t\n\r ")
|
todo.Original = strings.Trim(text, "\t\n\r ")
|
||||||
task.Todo = task.Original
|
todo.Todo = todo.Original
|
||||||
|
|
||||||
// Check for completed
|
// Check for completed
|
||||||
if completedRx.MatchString(task.Original) {
|
if completedRx.MatchString(todo.Original) {
|
||||||
task.Completed = true
|
todo.Completed = true
|
||||||
// Check for completed date
|
// Check for completed date
|
||||||
if completedDateRx.MatchString(task.Original) {
|
if completedDateRx.MatchString(todo.Original) {
|
||||||
if date, err := time.Parse(DateLayout, completedDateRx.FindStringSubmatch(task.Original)[1]); err == nil {
|
if date, err := time.Parse(DateLayout, completedDateRx.FindStringSubmatch(todo.Original)[1]); err == nil {
|
||||||
task.CompletedDate = date
|
todo.CompletedDate = date
|
||||||
} else {
|
} else {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove from Todo text
|
// Remove from Todo text
|
||||||
task.Todo = completedDateRx.ReplaceAllString(task.Todo, "") // Strip CompletedDate first, otherwise it wouldn't match anymore (^x date...)
|
todo.Todo = completedDateRx.ReplaceAllString(todo.Todo, "") // Strip CompletedDate first, otherwise it wouldn't match anymore (^x date...)
|
||||||
task.Todo = completedRx.ReplaceAllString(task.Todo, "") // Strip 'x '
|
todo.Todo = completedRx.ReplaceAllString(todo.Todo, "") // Strip 'x '
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for priority
|
// Check for priority
|
||||||
if priorityRx.MatchString(task.Original) {
|
if priorityRx.MatchString(todo.Original) {
|
||||||
task.Priority = priorityRx.FindStringSubmatch(task.Original)[2]
|
todo.Priority = priorityRx.FindStringSubmatch(todo.Original)[2]
|
||||||
task.Todo = priorityRx.ReplaceAllString(task.Todo, "") // Remove from Todo text
|
todo.Todo = priorityRx.ReplaceAllString(todo.Todo, "") // Remove from Todo text
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for created date
|
// Check for created date
|
||||||
if createdDateRx.MatchString(task.Original) {
|
if createdDateRx.MatchString(todo.Original) {
|
||||||
if date, err := time.Parse(DateLayout, createdDateRx.FindStringSubmatch(task.Original)[2]); err == nil {
|
if date, err := time.Parse(DateLayout, createdDateRx.FindStringSubmatch(todo.Original)[2]); err == nil {
|
||||||
task.CreatedDate = date
|
todo.CreatedDate = date
|
||||||
task.Todo = createdDateRx.ReplaceAllString(task.Todo, "") // Remove from Todo text
|
todo.Todo = createdDateRx.ReplaceAllString(todo.Todo, "") // Remove from Todo text
|
||||||
} else {
|
} else {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -153,7 +149,7 @@ func ParseTask(text string) (*Task, error) {
|
|||||||
|
|
||||||
// function for collecting projects/contexts as slices from text
|
// function for collecting projects/contexts as slices from text
|
||||||
getSlice := func(rx *regexp.Regexp) []string {
|
getSlice := func(rx *regexp.Regexp) []string {
|
||||||
matches := rx.FindAllStringSubmatch(task.Original, -1)
|
matches := rx.FindAllStringSubmatch(todo.Original, -1)
|
||||||
slice := make([]string, 0, len(matches))
|
slice := make([]string, 0, len(matches))
|
||||||
seen := make(map[string]bool, len(matches))
|
seen := make(map[string]bool, len(matches))
|
||||||
for _, match := range matches {
|
for _, match := range matches {
|
||||||
@ -168,26 +164,26 @@ func ParseTask(text string) (*Task, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check for contexts
|
// Check for contexts
|
||||||
if contextRx.MatchString(task.Original) {
|
if contextRx.MatchString(todo.Original) {
|
||||||
task.Contexts = getSlice(contextRx)
|
todo.Contexts = getSlice(contextRx)
|
||||||
task.Todo = contextRx.ReplaceAllString(task.Todo, "") // Remove from Todo text
|
todo.Todo = contextRx.ReplaceAllString(todo.Todo, "") // Remove from Todo text
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for projects
|
// Check for projects
|
||||||
if projectRx.MatchString(task.Original) {
|
if projectRx.MatchString(todo.Original) {
|
||||||
task.Projects = getSlice(projectRx)
|
todo.Projects = getSlice(projectRx)
|
||||||
task.Todo = projectRx.ReplaceAllString(task.Todo, "") // Remove from Todo text
|
todo.Todo = projectRx.ReplaceAllString(todo.Todo, "") // Remove from Todo text
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for additional tags
|
// Check for additional tags
|
||||||
if addonTagRx.MatchString(task.Original) {
|
if addonTagRx.MatchString(todo.Original) {
|
||||||
matches := addonTagRx.FindAllStringSubmatch(task.Original, -1)
|
matches := addonTagRx.FindAllStringSubmatch(todo.Original, -1)
|
||||||
tags := make(map[string]string, len(matches))
|
tags := make(map[string]string, len(matches))
|
||||||
for _, match := range matches {
|
for _, match := range matches {
|
||||||
key, value := match[2], match[3]
|
key, value := match[2], match[3]
|
||||||
if key == "due" { // due date is a known addon tag, it has its own struct field
|
if key == "due" { // due date is a known addon tag, it has its own struct field
|
||||||
if date, err := time.Parse(DateLayout, value); err == nil {
|
if date, err := time.Parse(DateLayout, value); err == nil {
|
||||||
task.DueDate = date
|
todo.DueDate = date
|
||||||
} else {
|
} else {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -195,57 +191,51 @@ func ParseTask(text string) (*Task, error) {
|
|||||||
tags[key] = value
|
tags[key] = value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
task.AdditionalTags = tags
|
todo.AdditionalTags = tags
|
||||||
task.Todo = addonTagRx.ReplaceAllString(task.Todo, "") // Remove from Todo text
|
todo.Todo = addonTagRx.ReplaceAllString(todo.Todo, "") // Remove from Todo text
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trim any remaining whitespaces 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
|
return &todo, 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()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasPriority returns true if the task has a priority.
|
// HasPriority returns true if the task has a priority.
|
||||||
func (task *Task) HasPriority() bool {
|
func (todo *Todo) HasPriority() bool {
|
||||||
return task.Priority != ""
|
return todo.Priority != ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasCreatedDate returns true if the task has a created date.
|
// HasCreatedDate returns true if the task has a created date.
|
||||||
func (task *Task) HasCreatedDate() bool {
|
func (todo *Todo) HasCreatedDate() bool {
|
||||||
return !task.CreatedDate.IsZero()
|
return !todo.CreatedDate.IsZero()
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasDueDate returns true if the task has a due date.
|
// HasDueDate returns true if the task has a due date.
|
||||||
func (task *Task) HasDueDate() bool {
|
func (todo *Todo) HasDueDate() bool {
|
||||||
return !task.DueDate.IsZero()
|
return !todo.DueDate.IsZero()
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasCompletedDate returns true if the task has a completed date.
|
// HasCompletedDate returns true if the task has a completed date.
|
||||||
func (task *Task) HasCompletedDate() bool {
|
func (todo *Todo) HasCompletedDate() bool {
|
||||||
return !task.CompletedDate.IsZero() && task.Completed
|
return !todo.CompletedDate.IsZero() && todo.Completed
|
||||||
}
|
}
|
||||||
|
|
||||||
// Complete sets Task.Completed to 'true' if the task was not already completed.
|
// Complete sets Task.Completed to 'true' if the task was not already completed.
|
||||||
// Also sets Task.CompletedDate to time.Now()
|
// Also sets Task.CompletedDate to time.Now()
|
||||||
func (task *Task) Complete() {
|
func (todo *Todo) Complete() {
|
||||||
if !task.Completed {
|
if !todo.Completed {
|
||||||
task.Completed = true
|
todo.Completed = true
|
||||||
task.CompletedDate = time.Now()
|
todo.CompletedDate = time.Now()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reopen sets Task.Completed to 'false' if the task was completed.
|
// Reopen sets Task.Completed to 'false' if the task was completed.
|
||||||
// Also resets Task.CompletedDate.
|
// Also resets Task.CompletedDate.
|
||||||
func (task *Task) Reopen() {
|
func (todo *Todo) Reopen() {
|
||||||
if task.Completed {
|
if todo.Completed {
|
||||||
task.Completed = false
|
todo.Completed = false
|
||||||
task.CompletedDate = time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC) // time.IsZero() value
|
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.
|
// This function does not take the Completed flag into consideration.
|
||||||
// You should check Task.Completed first if needed.
|
// You should check Task.Completed first if needed.
|
||||||
func (task *Task) IsOverdue() bool {
|
func (todo *Todo) IsOverdue() bool {
|
||||||
if task.HasDueDate() {
|
if todo.HasDueDate() {
|
||||||
return task.DueDate.Before(time.Now())
|
return todo.DueDate.Before(time.Now())
|
||||||
}
|
}
|
||||||
return false
|
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.
|
// Just as with IsOverdue(), this function does also not take the Completed flag into consideration.
|
||||||
// You should check Task.Completed first if needed.
|
// You should check Task.Completed first if needed.
|
||||||
func (task *Task) Due() time.Duration {
|
func (todo *Todo) Due() time.Duration {
|
||||||
if task.IsOverdue() {
|
if todo.IsOverdue() {
|
||||||
return time.Now().Sub(task.DueDate)
|
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 {
|
func (todo *Todo) HasContext(ctx string) bool {
|
||||||
for _, c := range task.Contexts {
|
for _, c := range todo.Contexts {
|
||||||
if c == ctx {
|
if c == ctx {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -281,8 +271,8 @@ func (task *Task) HasContext(ctx string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (task *Task) HasProject(proj string) bool {
|
func (todo *Todo) HasProject(proj string) bool {
|
||||||
for _, p := range task.Projects {
|
for _, p := range todo.Projects {
|
||||||
if p == proj {
|
if p == proj {
|
||||||
return true
|
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