Merge branch '2.4.3' into lexer2

This commit is contained in:
Paul Beckingham 2015-03-20 17:16:48 -04:00
commit 24a1cbefe9
49 changed files with 876 additions and 850 deletions

View file

@ -10,7 +10,7 @@ include (CheckStructHasMember)
set (HAVE_CMAKE true)
project (task)
set (PROJECT_VERSION "2.4.2")
set (PROJECT_VERSION "2.4.3")
OPTION(USE_GNUTLS "Build gnutls support." ON)

View file

@ -1,4 +1,11 @@
2.4.2 () -
2.4.3 () -
- TW-1578 Bash tab completion problems on first run
(thanks to Renato Alves and Ptolemarch).
------ current release ---------------------------
2.4.2 (2015-03-15) b9dc0813d9a8922b4cef9595033f133f9fbabf44
- TW-41 Tasks in subprojects are not counted in project completion (thanks
to Renato Alves).
@ -24,8 +31,8 @@
- The 'info' command now shows virtual tags.
- Fixed major on-modify hooks regression where hooks could no longer modify
the tasks handed to them.
------ current release ---------------------------
- 'task _version' now outputs "2.4.2 (git-ref)" when built from git. "2.4.2"
when built from release tarballs (thanks to Renato Alves).
2.4.1 (2015-02-16) 82e019a4a8b20de63d53b51d59b8d1c89d3c05b2
@ -122,6 +129,7 @@
- TW-52 "task add ... recur:2 months" interpreted as "2s" (thanks to jwhisnant).
- TW-55 Bulk edit recurring tasks without answering yes/no for each? (thanks to
Max Muller).
- TW-63 indicators for UDAs (thanks to David Patrick).
- TW-71 task ls/list/long/etc. should match contents of projects too (thanks to
Cory Donnelly).
- TW-72 extend info report with urgency column.

View file

@ -10,7 +10,7 @@ How to Build Taskwarrior
Obtain and build code:
$ git clone https://git.tasktools.org/scm/tm/task.git task.git
$ cd task.git
$ git checkout 2.4.2 # Latest dev branch
$ git checkout 2.4.3 # Latest dev branch
$ cmake -DCMAKE_BUILD_TYPE=debug . # debug or release. Default: neither.
$ make VERBOSE=1 # Shows details
@ -189,11 +189,11 @@ Work in Progress
Current Codebase Condition
'master' branch:
- 2.4.1 Current release, locked.
- 2.4.2 Current release, locked.
'2.4.2' branch:
'2.4.3' branch:
- Current development branch no plans yet.
---
2015-02-14 Updated for 2.4.1
2015-03-15 Updated for 2.4.3

33
NEWS
View file

@ -1,39 +1,26 @@
New Features in taskwarrior 2.4.2
New Features in taskwarrior 2.4.3
- Ability to set context, which serves as a permanent user-defined filter.
- The 'info' command now shows virtual tags.
-
New commands in taskwarrior 2.4.2
New commands in taskwarrior 2.4.3
- The 'context' command has been added, along with it subcommands 'define',
'delete', 'show', 'list' and 'none'.
-
New configuration options in taskwarrior 2.4.2
New configuration options in taskwarrior 2.4.3
- 'context' to store the current context applied.
- 'context.<name>' to store the definition of context 'name'
-
Newly deprecated features in taskwarrior 2.4.2
Newly deprecated features in taskwarrior 2.4.3
- None
-
Removed features in 2.4.2
Removed features in 2.4.3
- None
-
Known Issues
- If you upgraded from Taskwarrior 2.3.0, you will need one of the following
settings to allow continued syncing to a Taskserver:
$ task config taskd.trust strict
$ task config taskd.trust 'ignore hostname'
$ task config taskd.trust 'allow all'
These are presented in order of preference from most to least secure, and
depend on how your certs were generated.
- https://bug.tasktools.org/
Taskwarrior has been built and tested on the following configurations:

View file

@ -1,4 +1,4 @@
.TH task-color 5 2015-02-16 "${PACKAGE_STRING}" "User Manuals"
.TH task-color 5 2015-03-15 "${PACKAGE_STRING}" "User Manuals"
.SH NAME
task-color \- A color tutorial for the taskwarrior command line todo manager.

View file

@ -1,4 +1,4 @@
.TH task-sync 5 2015-02-16 "${PACKAGE_STRING}" "User Manuals"
.TH task-sync 5 2015-03-15 "${PACKAGE_STRING}" "User Manuals"
.SH NAME
task-sync \- A discussion and tutorial for the various task(1) data

View file

@ -1,4 +1,4 @@
.TH task 1 2015-02-16 "${PACKAGE_STRING}" "User Manuals"
.TH task 1 2015-03-15 "${PACKAGE_STRING}" "User Manuals"
.SH NAME
task \- A command line todo manager.
@ -379,6 +379,22 @@ time from the specified task.
Miscellaneous subcommands either accept no command line arguments, or accept
non-standard arguments.
.TP
.B task calc <expression>
Evaluates an algebraic expression. Can be used to test how TaskWarrior
parses and evaluates the expression given on the command line.
Examples:
task calc 1 + 1
2
task calc now + 8d
2015-03-26T18:06:57
task calc eom
2015-03-31T23:59:59
.TP
.B task config [name [value | '']]
Add, modify and remove settings directly in the taskwarrior configuration.
@ -1161,11 +1177,11 @@ the 'data.location' configuration setting of the task data directory.
For examples please see the online documentation starting at
.RS
<http://taskwarrior.org/projects/taskwarrior/wiki>
<http://taskwarrior.org/docs>
.RE
Note that the online documentation is more detailed and more current than this
man page.
Note that the online documentation can be more detailed and more current than
this man page.
.SH FILES

View file

@ -1,4 +1,4 @@
.TH taskrc 5 2015-02-16 "${PACKAGE_STRING}" "User Manuals"
.TH taskrc 5 2015-03-15 "${PACKAGE_STRING}" "User Manuals"
.SH NAME
taskrc \- Configuration details for the task(1) command
@ -288,7 +288,7 @@ value is "yes". Consider leaving this setting as "yes", for safety.
.TP
.B allow.empty.filter=yes
An empty filter combined with a write command is potentially a way to modify
all tasks by mistkae, and when this is detected, confirmation is required.
all tasks by mistake, and when this is detected, confirmation is required.
Setting this to 'no' means that it is an error to use a write command with no
filter.

View file

@ -1,15 +1,24 @@
Themes
To generate samples of themes, first execute the 'run' script to generate the
To generate samples of themes, first execute the 'setup' script to generate the
sample data. Note that this data may need to be tweaked to include qualities
that need to be illustrated in theme sample.
Then edit the 'rc' file to include the desired theme file.
Using a dark-background terminal (black recommended), run the following:
Then run 'per' to run a few commands for each theme.
run.dark
Note that this will require that the terminal window be switched between a black
and white background to properly show the light and dark themes.
Using a light-background terminal, run the following:
run.light
Using a solarized dark terminal, run the following:
run.solar.dark
Using a solarized light terminal, run the following:
run.solar.light
Note that for the solarized themes, the terminal color palette needs to be set
to specific colors.

View file

@ -1,23 +0,0 @@
for theme in $PWD/../../rc/*.theme
do
cat <<EOF >>x
data.location=.
confirmation=off
_forcecolor=on
include $theme
EOF
echo "--- $theme -----------------------------------------------------"
echo '$ task list'
task rc:x list
echo '$ task summary'
task rc:x summary
echo '$ task ghistory'
task rc:x ghistory
echo '$ task calendar'
task rc:x calendar
echo '$ task burndown.daily'
task rc:x burndown.daily
done

View file

@ -21,6 +21,8 @@ include $theme
EOF
echo "--- $theme -----------------------------------------------------"
echo '$ task color legend'
task rc:x color legend
echo '$ task list'
task rc:x list
echo '$ task summary'

24
doc/misc/themes/run.default Executable file
View file

@ -0,0 +1,24 @@
#!/bin/bash
cat <<EOF >x
data.location=.
confirmation=off
detection=off
_forcecolor=on
default.height=24
verbose=off
EOF
echo "--- DEFAULT -----------------------------------------------------"
echo '$ task color legend'
task rc:x color legend
echo '$ task list'
task rc:x list
echo '$ task summary'
task rc:x summary
echo '$ task ghistory'
task rc:x ghistory
echo '$ task calendar'
task rc:x calendar
echo '$ task burndown.daily'
task rc:x burndown.daily

View file

@ -14,6 +14,8 @@ include $theme
EOF
echo "--- $theme -----------------------------------------------------"
echo '$ task color legend'
task rc:x color legend
echo '$ task list'
task rc:x list
echo '$ task summary'

View file

@ -13,6 +13,8 @@ include $theme
EOF
echo "--- $theme -----------------------------------------------------"
echo '$ task color legend'
task rc:x color legend
echo '$ task list'
task rc:x list
echo '$ task summary'

View file

@ -13,6 +13,8 @@ include $theme
EOF
echo "--- $theme -----------------------------------------------------"
echo '$ task color legend'
task rc:x color legend
echo '$ task list'
task rc:x list
echo '$ task summary'

View file

@ -33,15 +33,15 @@ color.alternate=
color.header=yellow
color.footnote=yellow
color.warning=bold red
color.error=yellow
color.debug=yellow
color.error=white on red
color.debug=blue
# Task state
color.completed=green on white
color.deleted=red on white
color.completed=
color.deleted=
color.active=black on bright green
color.recurring=magenta
color.scheduled=on green
color.scheduled=white on green
color.until=
color.blocked=black on white
color.blocking=black on bright white

View file

@ -29,16 +29,16 @@ rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overd
# General decoration
color.label=
color.label.sort=
color.alternate=on gray1
color.alternate=on gray2
color.header=color3
color.footnote=color3
color.warning=bold red
color.error=color3
color.debug=color3
color.error=white on red
color.debug=color4
# Task state
color.completed=rgb010 on white
color.deleted=rgb100 on white
color.completed=
color.deleted=
color.active=rgb555 on rgb410
color.recurring=rgb013
color.scheduled=on rgb001

View file

@ -29,19 +29,19 @@ rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overd
# General decoration
color.label=
color.label.sort=
color.alternate=on gray1
color.alternate=on gray2
color.header=rgb013
color.footnote=rgb013
color.warning=bold red
color.error=rgb013
color.error=white on red
color.debug=rgb013
# Task state
color.completed=rgb001 on white
color.deleted=rgb100 on white
color.completed=
color.deleted=
color.active=rgb045 on rgb015
color.recurring=rgb115
color.scheduled=on rgb011
color.scheduled=on rgb012
color.until=
color.blocked=white on rgb001
color.blocking=white on rgb002
@ -76,8 +76,8 @@ color.history.delete=color0 on rgb035
color.history.done=color0 on rgb025
# Report: summary
color.summary.background=white on color0
color.summary.bar=white on rgb003
color.summary.background=on rgb001
color.summary.bar=on rgb114
# Command: calendar
color.calendar.due.today=color0 on color252

View file

@ -29,16 +29,16 @@ rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overd
# General decoration
color.label=
color.label.sort=
color.alternate=on gray1
color.alternate=on gray2
color.header=color0 on gray11
color.footnote=on gray5
color.warning=bold red
color.error=red on white
color.debug=black on white
color.error=white on red
color.debug=blue
# Task state
color.completed=black on white
color.deleted=black on white
color.completed=
color.deleted=
color.active=black on gray18
color.recurring=
color.scheduled=on gray8
@ -61,7 +61,7 @@ color.tag.none=
color.tagged=
# Due
color.due=on gray2
color.due=on gray3
color.due.today=on gray4
color.overdue=on gray6
@ -76,12 +76,12 @@ color.history.delete=black on gray10
color.history.done=gray5 on gray23
# Report: summary
color.summary.bar=on gray15
color.summary.background=on black
color.summary.bar=on gray12
color.summary.background=on gray5
# Command: calendar
color.calendar.due=on gray8
color.calendar.due.today=on gray15
color.calendar.due.today=black on gray15
color.calendar.holiday=black on gray20
color.calendar.overdue=gray2 on gray10
color.calendar.today=bold white
@ -89,7 +89,7 @@ color.calendar.weekend=on gray2
color.calendar.weeknumber=gray6
# Command: sync
color.sync.add=gray15 on gray5
color.sync.added=gray15 on gray5
color.sync.changed=black on gray10
color.sync.rejected=gray5 on gray23

View file

@ -29,12 +29,12 @@ rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overd
# General decoration
color.label=
color.label.sort=
color.alternate=on gray0
color.alternate=on gray2
color.header=gray10
color.footnote=gray10
color.warning=
color.error=rgb500
color.debug=rgb500
color.error=white on red
color.debug=blue
# Task state
color.completed=
@ -66,18 +66,18 @@ color.due.today=color0 on rgb024
color.overdue=color0 on rgb035
# Report: burndown
color.burndown.pending=on gray9
color.burndown.started=on gray16
color.burndown.done=on rgb013
color.burndown.pending=white on gray9
color.burndown.started=black on gray16
color.burndown.done=white on rgb013
# Report: history
color.history.add=on gray9
color.history.delete=black on gray23
color.history.done=black on rgb013
color.history.add=white on gray6
color.history.delete=black on gray18
color.history.done=black on rgb024
# Report: summary
color.summary.bar=on rgb012
color.summary.background=on color0
color.summary.background=on gray2
# Command: calendar
color.calendar.due=color0 on gray10
@ -94,6 +94,6 @@ color.sync.changed=gray15
color.sync.rejected=gray23
# Command: undo
color.undo.before=green
color.undo.after=red
color.undo.before=rgb013
color.undo.after=rgb035

View file

@ -29,19 +29,19 @@ rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overd
# General decoration
color.label=
color.label.sort=
color.alternate=on gray1
color.alternate=on gray2
color.header=rgb031
color.footnote=rgb031
color.warning=bold red
color.error=rgb031
color.debug=rgb031
color.warning=rgb020
color.error=white on red
color.debug=blue
# Task state
color.completed=rgb020 on white
color.deleted=rgb200 on white
color.completed=
color.deleted=
color.active=rgb050 on rgb010
color.recurring=rgb151
color.scheduled=on rgb011
color.scheduled=black on rgb031
color.until=
color.blocked=white on rgb010
color.blocking=white on rgb020
@ -76,7 +76,7 @@ color.history.delete=color0 on rgb050
color.history.done=color0 on rgb030
# Report: summary
color.summary.background=white on color0
color.summary.background=white on gray3
color.summary.bar=white on rgb030
# Command: calendar
@ -95,4 +95,4 @@ color.sync.rejected=rgb010
# Command: undo
color.undo.after=rgb053
color.undo.before=rgb031
color.undo.before=rgb021

View file

@ -29,19 +29,19 @@ rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overd
# General decoration
color.label=
color.label.sort=
color.alternate=on gray1
color.alternate=on gray2
color.header=rgb100
color.footnote=rgb100
color.warning=bold red
color.error=rgb100
color.debug=rgb100
color.warning=red
color.error=white on red
color.debug=blue
# Task state
color.completed=rgb020 on white
color.deleted=rgb200 on white
color.completed=
color.deleted=
color.active=rgb500 on rgb100
color.recurring=rgb511
color.scheduled=on rgb201
color.scheduled=white on rgb311
color.until=
color.blocked=white on rgb100
color.blocking=white on rgb200
@ -56,7 +56,7 @@ color.pri.M=rgb400
color.pri.none=
# Tags
color.tag.next=rgb440
color.tag.next=rgb511
color.tag.none=
color.tagged=color246
@ -94,6 +94,6 @@ color.sync.changed=rgb411
color.sync.rejected=rgb200
# Command: undo
color.undo.after=rgb503
color.undo.before=rgb301
color.undo.after=rgb511
color.undo.before=rgb200

View file

@ -33,15 +33,15 @@ color.alternate=on gray2
color.header=rgb013
color.footnote=rgb013
color.warning=
color.error=rgb013
color.debug=rgb013
color.error=white on red
color.debug=blue
# Task state
color.completed=
color.deleted=
color.active=rgb445 on rgb213
color.recurring=rgb115
color.scheduled=
color.scheduled=white on rgb113
color.until=
color.blocked=white on rgb101
color.blocking=white on rgb202
@ -61,9 +61,9 @@ color.tag.none=
color.tagged=rgb334
# Due
color.due=rgb055
color.due.today=rgb533
color.overdue=color9
color.due=rgb015
color.due.today=rgb125
color.overdue=color5
# Report: burndown
color.burndown.pending=on rgb103
@ -76,14 +76,14 @@ color.history.done=color0 on rgb205
color.history.delete=color0 on rgb305
# Report: summary
color.summary.bar=white on rgb103
color.summary.background=white on color0
color.summary.bar=white on rgb104
color.summary.background=white on rgb001
# Command: calendar
color.calendar.due=color0 on rgb325
color.calendar.due.today=color0 on rgb404
color.calendar.holiday=color15 on rgb022
color.calendar.overdue=color0 on color9
color.calendar.holiday=color15 on rgb102
color.calendar.overdue=color0 on color5
color.calendar.today=color15 on rgb103
color.calendar.weekend=gray12 on gray3
color.calendar.weeknumber=rgb104

View file

@ -33,15 +33,15 @@ color.alternate=on gray2
color.header=rgb031
color.footnote=rgb031
color.warning=
color.error=rgb031
color.debug=rgb031
color.error=white on red
color.debug=blue
# Task state
color.completed=
color.deleted=
color.active=rgb451 on rgb310
color.active=rgb451 on rgb320
color.recurring=rgb343
color.scheduled=
color.scheduled=black on rgb441
color.until=
color.blocked=white on rgb110
color.blocking=white on rgb220
@ -61,9 +61,9 @@ color.tag.none=
color.tagged=rgb342
# Due
color.due=rgb420
color.due.today=rgb410
color.overdue=rgb400
color.due=rgb440
color.due.today=rgb430
color.overdue=rgb420
# Report: burndown
color.burndown.pending=on rgb110
@ -71,19 +71,19 @@ color.burndown.started=on rgb430
color.burndown.done=on gray4
# Report: history
color.history.add=color0 on rgb010
color.history.done=color0 on rgb030
color.history.delete=color0 on rgb050
color.history.add=color0 on rgb110
color.history.done=color0 on rgb430
color.history.delete=white on gray4
# Report: summary
color.summary.bar=white on rgb030
color.summary.background=white on color0
color.summary.bar=white on rgb330
color.summary.background=white on rgb110
# Command: calendar
color.calendar.due=color0 on rgb430
color.calendar.due.today=color0 on rgb410
color.calendar.due=color0 on rgb440
color.calendar.due.today=color0 on rgb430
color.calendar.holiday=rgb151 on rgb020
color.calendar.overdue=color0 on rgb400
color.calendar.overdue=color0 on rgb420
color.calendar.today=color15 on rgb110
color.calendar.weekend=on color235
color.calendar.weeknumber=rgb110
@ -94,6 +94,6 @@ color.sync.changed=rgb430
color.sync.rejected=rgb110
# Command: undo
color.undo.before=rgb031
color.undo.after=rgb053
color.undo.before=rgb021
color.undo.after=rgb042

View file

@ -33,12 +33,12 @@ color.alternate=
color.header=bold white on bright black
color.footnote=bold cyan on bright black
color.warning=bold red
color.error=red on white
color.debug=white on black
color.error=white on red
color.debug=blue
# Task state
color.completed=green on black
color.deleted=red on black
color.completed=
color.deleted=
color.active=bold yellow on bright black
color.recurring=
color.scheduled=on bright cyan
@ -63,17 +63,17 @@ color.tagged=
# Due
color.due=on bright green
color.due.today=on bright yellow
color.overdue=on bright magenta
color.overdue=on bright red
# Report: burndown
color.burndown.pending=on bright green
color.burndown.pending=on bright red
color.burndown.started=on bright yellow
color.burndown.done=on green
# Report: history
color.history.add=blue on bright yellow
color.history.done=green on bright green
color.history.delete=black on red
color.history.add=black on bright red
color.history.done=black on bright green
color.history.delete=black on yellow
# Report: summary
color.summary.bar=on bright green
@ -82,11 +82,11 @@ color.summary.background=on white
# Command: calendar
color.calendar.due=on bright green
color.calendar.due.today=blue on bright yellow
color.calendar.holiday=yellow
color.calendar.overdue=on bright magenta
color.calendar.holiday=on yellow
color.calendar.overdue=on bright red
color.calendar.today=blue
color.calendar.weekend=on white
color.calendar.weeknumber=white on bright black
color.calendar.weeknumber=blue
# Command: sync
color.sync.added=green

View file

@ -33,13 +33,13 @@ color.alternate=on gray22
color.header=color15 on gray8
color.footnote=on gray18
color.warning=color9
color.error=red on white
color.debug=color7 on color0
color.error=white on red
color.debug=rgb025
# Task state
color.completed=rgb353 on rgb000
color.deleted=rgb533 on rgb000
color.active=rgb420
color.completed=
color.deleted=
color.active=rgb510
color.recurring=
color.scheduled=on rgb345
color.until=
@ -53,7 +53,7 @@ color.project.none=
color.pri.H=gray0
color.pri.M=gray5
color.pri.L=gray10
color.pri.none=gray5
color.pri.none=
# Tags
color.tag.next=rgb420
@ -66,14 +66,14 @@ color.due.today=on rgb353
color.overdue=on rgb544
# Report: burndown
color.burndown.pending=on rgb141
color.burndown.started=on rgb440
color.burndown.pending=on rgb411
color.burndown.started=on rgb550
color.burndown.done=on rgb151
# Report: history
color.history.add=rgb005 on rgb440
color.history.done=rgb020 on rgb343
color.history.delete=rgb300 on rgb533
color.history.add=color0 on rgb411
color.history.done=color0 on rgb151
color.history.delete=color0 on rgb550
# Report: summary
color.summary.bar=on rgb141
@ -82,7 +82,7 @@ color.summary.background=on gray20
# Command: calendar
color.calendar.due=on rgb343
color.calendar.due.today=on rgb353
color.calendar.holiday=rgb420
color.calendar.holiday=color0 on rgb530
color.calendar.overdue=on rgb533
color.calendar.today=rgb005
color.calendar.weekend=on gray21

View file

@ -83,14 +83,14 @@ color.due.today=color1
color.overdue=color5
# Report: burndown
color.burndown.done=color0 on color4
color.burndown.done=color0 on color6
color.burndown.pending=color0 on color1
color.burndown.started=color0 on color9
color.burndown.started=color0 on color3
# Report: history
color.history.add=color0 on color1
color.history.delete=color0 on color3
color.history.done=color0 on color10
color.history.done=color0 on color6
# Report: summary
color.summary.background=on color0

View file

@ -46,7 +46,7 @@ rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overd
# General decoration
color.label=
color.label.sort=
color.alternate=on white #color7 (allows bold for alternate rows)
color.alternate=on color7
color.header=color2
color.footnote=color2
color.warning=
@ -56,20 +56,20 @@ color.debug=color3
# Task state
color.completed=
color.deleted=
color.active=bold red #color9
color.active=color9
color.recurring=color4
color.scheduled=
color.until=
color.blocked=on color14
color.blocking=on color14
color.blocked=color0 on color14
color.blocking=color15 on color0
# Project
color.project.none=
# Priority
color.pri.H=bold black #color0
color.pri.M=bold yellow #color11
color.pri.L=bold cyan #color14
color.pri.H=bold color0
color.pri.M=bold color11
color.pri.L=bold color14
color.pri.none=
# Tags
@ -83,14 +83,14 @@ color.due.today=color1
color.overdue=color5
# Report: burndown
color.burndown.done=color0 on color4
color.burndown.done=color0 on color6
color.burndown.pending=color0 on color1
color.burndown.started=color0 on color9
color.burndown.started=color0 on color3
# Report: history
color.history.add=color0 on color1
color.history.delete=color0 on color3
color.history.done=color14 on color0
color.history.done=color0 on color6
# Report: summary
color.summary.background=on color7

Binary file not shown.

Binary file not shown.

View file

@ -50,7 +50,7 @@
#
################################################################################
#the following variable is substituted for by ../../test/bash_completion.t
taskcommand='task rc.verbose:nothing'
taskcommand='task rc.verbose:nothing rc.confirmation:no'
_task_get_tags() {
$taskcommand _tags

View file

@ -529,10 +529,13 @@ void CLI::applyOverrides ()
////////////////////////////////////////////////////////////////////////////////
// Extract all the FILTER-tagged items.
const std::string CLI::getFilter ()
const std::string CLI::getFilter (bool applyContext /* = true */)
{
// Handle context setting
addContextFilter ();
// Commands that don't want to respect current context should leverage
// the applyContext argument
if (applyContext)
addContextFilter ();
std::string filter = "";
if (_args.size ())

View file

@ -81,7 +81,7 @@ public:
void addRawFilter (const std::string& arg);
void analyze (bool parse = true, bool strict = false);
void applyOverrides ();
const std::string getFilter ();
const std::string getFilter (bool applyContext = true);
const std::vector <std::string> getWords ();
bool canonicalize (std::string&, const std::string&, const std::string&) const;
std::string getBinary () const;

View file

@ -165,29 +165,29 @@ std::string Config::_defaults =
"\n"
"# Color controls.\n"
"color=on # Enable color\n"
#ifdef LINUX
#if defined(LINUX) || defined(DARWIN)
"\n"
"rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,pri.\n"
"\n"
"# General decoration\n"
"color.label=\n"
"color.label.sort=\n"
"color.alternate=on gray1\n"
"color.alternate=on gray2\n"
"color.header=color3\n"
"color.footnote=color3\n"
"color.warning=bold red\n"
"color.error=color3\n"
"color.debug=color3\n"
"color.error=white on red\n"
"color.debug=color4\n"
"\n"
"# Task state\n"
"color.completed=rgb010 on white\n"
"color.deleted=rgb100 on white\n"
"color.completed=\n"
"color.deleted=\n"
"color.active=rgb555 on rgb410\n"
"color.recurring=rgb013\n"
"color.scheduled=on rgb001\n"
"color.until=\n"
"color.blocked=white on color8\n"
"color.blocking=white on color15\n"
"color.blocking=black on color15\n"
"\n"
"# Project\n"
"color.project.none=\n"
@ -251,15 +251,15 @@ std::string Config::_defaults =
"color.header=yellow\n"
"color.footnote=yellow\n"
"color.warning=bold red\n"
"color.error=yellow\n"
"color.debug=yellow\n"
"color.error=white on red\n"
"color.debug=blue\n"
"\n"
"# Task state\n"
"color.completed=green on white\n"
"color.deleted=red on white\n"
"color.completed=\n"
"color.deleted=\n"
"color.active=black on bright green\n"
"color.recurring=magenta\n"
"color.scheduled=on green\n"
"color.scheduled=white on green\n"
"color.until=\n"
"color.blocked=black on white\n"
"color.blocking=black on bright white\n"

View file

@ -67,7 +67,7 @@ Filter::~Filter ()
////////////////////////////////////////////////////////////////////////////////
// Take an input set of tasks and filter into a subset.
void Filter::subset (const std::vector <Task>& input, std::vector <Task>& output)
void Filter::subset (const std::vector <Task>& input, std::vector <Task>& output, bool applyContext /* = true */)
{
context.timer_filter.start ();
_startCount = (int) input.size ();
@ -75,7 +75,7 @@ void Filter::subset (const std::vector <Task>& input, std::vector <Task>& output
if (context.config.getInteger ("debug.parser") >= 1)
context.debug (context.cli.dump ("Filter::subset"));
std::string filterExpr = context.cli.getFilter ();
std::string filterExpr = context.cli.getFilter (applyContext);
if (filterExpr.length ())
{
Eval eval;
@ -111,7 +111,7 @@ void Filter::subset (const std::vector <Task>& input, std::vector <Task>& output
////////////////////////////////////////////////////////////////////////////////
// Take the set of all tasks and filter into a subset.
void Filter::subset (std::vector <Task>& output)
void Filter::subset (std::vector <Task>& output, bool applyContext /* = true */)
{
context.timer_filter.start ();
@ -119,7 +119,7 @@ void Filter::subset (std::vector <Task>& output)
context.debug (context.cli.dump ("Filter::subset"));
bool shortcut = false;
std::string filterExpr = context.cli.getFilter ();
std::string filterExpr = context.cli.getFilter (applyContext);
if (filterExpr.length ())
{
context.timer_filter.stop ();

View file

@ -40,8 +40,8 @@ public:
Filter ();
~Filter ();
void subset (const std::vector <Task>&, std::vector <Task>&);
void subset (std::vector <Task>&);
void subset (const std::vector <Task>&, std::vector <Task>&, bool applyContext = true);
void subset (std::vector <Task>&, bool applyContext = true);
bool pendingOnly ();
void safety ();

View file

@ -54,7 +54,7 @@ int CmdExport::execute (std::string& output)
// Apply filter.
Filter filter;
std::vector <Task> filtered;
filter.subset (filtered);
filter.subset (filtered, false);
// Obey 'limit:N'.
int rows = 0;

View file

@ -135,7 +135,10 @@ CmdCompletionVersion::CmdCompletionVersion ()
int CmdCompletionVersion::execute (std::string& output)
{
#ifdef HAVE_COMMIT
output = COMMIT;
output = std::string (VERSION)
+ std::string (" (")
+ std::string (COMMIT)
+ std::string (")");
#else
output = VERSION;
#endif

View file

@ -1,86 +0,0 @@
#! /usr/bin/env perl
################################################################################
##
## Copyright 2006 - 2015, Paul Beckingham, Federico Hernandez.
##
## Permission is hereby granted, free of charge, to any person obtaining a copy
## of this software and associated documentation files (the "Software"), to deal
## in the Software without restriction, including without limitation the rights
## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
## copies of the Software, and to permit persons to whom the Software is
## furnished to do so, subject to the following conditions:
##
## The above copyright notice and this permission notice shall be included
## in all copies or substantial portions of the Software.
##
## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
## OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
## THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
## SOFTWARE.
##
## http://www.opensource.org/licenses/mit-license.php
##
################################################################################
use strict;
use warnings;
use Test::More tests => 5;
# Ensure environment has no influence.
delete $ENV{'TASKDATA'};
delete $ENV{'TASKRC'};
use File::Basename;
my $ut = basename ($0);
my $rc = $ut . '.rc';
# Create the rc file.
if (open my $fh, '>', $rc)
{
print $fh "data.location=.\n",
"default.command=\n";
close $fh;
}
# Get the version number from configure.ac
my $version = slurp ('../CMakeLists.txt');
# Test the usage command.
my $output = qx{../src/task rc:$rc 2>&1 >/dev/null};
like ($output, qr/You must specify a command or a task to modify./m, "$ut: missing command and ID");
# Test the version command.
$output = qx{../src/task rc:$rc version 2>&1};
like ($output, qr/task $version/, "$ut: version - task version number");
like ($output, qr/MIT\slicense/, "$ut: version - license");
like ($output, qr/http:\/\/taskwarrior\.org/, "$ut: version - url");
# Test the _version command.
$output = qx{../src/task rc:$rc _version 2>&1};
like ($output, qr/[a-f0-9]{7}/, "$ut: _version - task version number");
# Cleanup.
unlink $rc;
exit 0;
################################################################################
sub slurp
{
my ($file) = @_;
if (open my $fh, '<', $file)
{
while (<$fh>) {
if (/PROJECT_VERSION/) {
chomp;
s/^set \(PROJECT_VERSION "//;
s/"\).*$//;
close $fh;
return $_;
}
}
}
'';
}

View file

@ -1,72 +0,0 @@
#! /usr/bin/env perl
################################################################################
##
## Copyright 2006 - 2015, Paul Beckingham, Federico Hernandez.
##
## Permission is hereby granted, free of charge, to any person obtaining a copy
## of this software and associated documentation files (the "Software"), to deal
## in the Software without restriction, including without limitation the rights
## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
## copies of the Software, and to permit persons to whom the Software is
## furnished to do so, subject to the following conditions:
##
## The above copyright notice and this permission notice shall be included
## in all copies or substantial portions of the Software.
##
## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
## OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
## THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
## SOFTWARE.
##
## http://www.opensource.org/licenses/mit-license.php
##
################################################################################
use strict;
use warnings;
use Test::More tests => 7;
# Ensure environment has no influence.
delete $ENV{'TASKDATA'};
delete $ENV{'TASKRC'};
use File::Basename;
my $ut = basename ($0);
my $rc = $ut . '.rc';
# Create the rc file.
if (open my $fh, '>', $rc)
{
print $fh "data.location=.\n",
"confirmation=off\n",
"color=off\n",
"verbose=nothing\n";
close $fh;
}
# Bug 1056: Project indentation in CmdSummary.
qx{../src/task rc:$rc add testing project:existingParent 2>&1 >/dev/null};
qx{../src/task rc:$rc add testing project:existingParent.child 2>&1 >/dev/null};
qx{../src/task rc:$rc add testing project:abstractParent.kid 2>&1 >/dev/null};
qx{../src/task rc:$rc add testing project:.myProject 2>&1 >/dev/null};
qx{../src/task rc:$rc add testing project:myProject. 2>&1 >/dev/null};
qx{../src/task rc:$rc add testing project:.myProject. 2>&1 >/dev/null};
my $output = qx{../src/task rc:$rc summary 2>&1};
my @lines = split ('\n',$output);
like ($lines[0], qr/^\.myProject\s/, "$ut: '.myProject' not indented");
like ($lines[1], qr/^\.myProject\.\s/, "$ut: '.myProject.' not indented");
like ($lines[2], qr/^abstractParent\s*$/, "$ut: 'abstractParent' not indented, no data");
like ($lines[3], qr/^\s\skid\s+\d/, "$ut: ' kid' indented, without parent, with data");
like ($lines[4], qr/^existingParent\s+\d/, "$ut: 'existingParent' not indented, with data");
like ($lines[5], qr/^\s\schild\s+\d/, "$ut: ' child' indented, without parent, with data");
like ($lines[6], qr/^myProject\.\s+\d/, "$ut: 'myProject.' not indented, with data");
# Cleanup.
unlink qw(pending.data completed.data undo.data backlog.data), $rc;
exit 0;

View file

@ -1,72 +1,74 @@
#! /usr/bin/env perl
################################################################################
##
## Copyright 2006 - 2015, Paul Beckingham, Federico Hernandez.
##
## Permission is hereby granted, free of charge, to any person obtaining a copy
## of this software and associated documentation files (the "Software"), to deal
## in the Software without restriction, including without limitation the rights
## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
## copies of the Software, and to permit persons to whom the Software is
## furnished to do so, subject to the following conditions:
##
## The above copyright notice and this permission notice shall be included
## in all copies or substantial portions of the Software.
##
## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
## OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
## THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
## SOFTWARE.
##
## http://www.opensource.org/licenses/mit-license.php
##
################################################################################
#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
###############################################################################
#
# Copyright 2006 - 2015, Paul Beckingham, Federico Hernandez.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
# http://www.opensource.org/licenses/mit-license.php
#
###############################################################################
use strict;
use warnings;
use Test::More tests => 6;
import sys
import os
import re
import unittest
# Ensure python finds the local simpletap module
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
# Ensure environment has no influence.
delete $ENV{'TASKDATA'};
delete $ENV{'TASKRC'};
from basetest import Task, TestCase
use File::Basename;
my $ut = basename ($0);
my $rc = $ut . '.rc';
# Create the rc file.
if (open my $fh, '>', $rc)
{
print $fh "data.location=.\n",
"confirmation=off\n",
"uda.foo.type=numeric\n",
"uda.foo.label=Foo\n",
"report.bar.columns=foo,description\n",
"report.bar.description=Bar\n",
"report.bar.labels=Foo,Desc\n",
"report.bar.sort=foo-\n";
close $fh;
}
class TestBug1063(TestCase):
def setUp(self):
self.t = Task()
# Bug 1063 - Numeric UDA fields are not sortable.
qx{../src/task rc:$rc add four foo:4 2>&1};
ok ($? == 0, "$ut: add four");
qx{../src/task rc:$rc add one foo:1 2>&1};
ok ($? == 0, "$ut: add one");
qx{../src/task rc:$rc add three foo:3 2>&1};
ok ($? == 0, "$ut: add three");
qx{../src/task rc:$rc add two foo:2 2>&1};
ok ($? == 0, "$ut: add two");
self.t.config("uda.foo.type", "numeric")
self.t.config("uda.foo.label", "Foo")
self.t.config("report.bar.columns", "foo,description")
self.t.config("report.bar.description", "Bar")
self.t.config("report.bar.labels", "Foo,Desc")
self.t.config("report.bar.sort", "foo-")
my $output = qx{../src/task rc:$rc bar 2>&1};
like ($output, qr/4.+3.+2.+1/ms, "$ut: Default descending sort correct");
def test_sortable_uda(self):
"""numeric UDA fields are sortable
$output = qx{../src/task rc:$rc bar rc.report.bar.sort=foo+ 2>&1};
like ($output, qr/1.+2.+3.+4/ms, "$ut: Default ascending sort correct");
Reported as bug 1063
"""
## Cleanup.
unlink qw(pending.data completed.data undo.data backlog.data), $rc;
exit 0;
self.t(("add", "four", "foo:4"))
self.t(("add", "one", "foo:1"))
self.t(("add", "three", "foo:3"))
self.t(("add", "two", "foo:2"))
code, out, err = self.t(("bar",))
expected = re.compile("4.+3.+2.+1", re.DOTALL) # dot matches \n too
self.assertRegexpMatches(out, expected)
code, out, err = self.t(("bar", "rc.report.bar.sort=foo+"))
expected = re.compile("1.+2.+3.+4", re.DOTALL) # dot matches \n too
self.assertRegexpMatches(out, expected)
if __name__ == "__main__":
from simpletap import TAPTestRunner
unittest.main(testRunner=TAPTestRunner())
# vim: ai sts=4 et sw=4

View file

@ -1,78 +0,0 @@
#! /usr/bin/env perl
################################################################################
##
## Copyright 2006 - 2015, Paul Beckingham, Federico Hernandez.
##
## Permission is hereby granted, free of charge, to any person obtaining a copy
## of this software and associated documentation files (the "Software"), to deal
## in the Software without restriction, including without limitation the rights
## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
## copies of the Software, and to permit persons to whom the Software is
## furnished to do so, subject to the following conditions:
##
## The above copyright notice and this permission notice shall be included
## in all copies or substantial portions of the Software.
##
## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
## OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
## THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
## SOFTWARE.
##
## http://www.opensource.org/licenses/mit-license.php
##
################################################################################
use strict;
use warnings;
use Test::More tests => 12;
# Ensure environment has no influence.
delete $ENV{'TASKDATA'};
delete $ENV{'TASKRC'};
use File::Basename;
my $ut = basename ($0);
my $rc = $ut . '.rc';
# Create the rc file.
if (open my $fh, '>', $rc)
{
print $fh "data.location=.\n";
print $fh "alias.xyzzyx=status:waiting\n";
print $fh "imnotrecognized=kai\n";
close $fh;
}
# Bug 1065 - CmdShow should not display the differ message if no non-default in matched elements.
my $output = qx{../src/task rc:$rc show alias 2>&1};
ok ($? == 0, "$ut: Exit status check");
like ($output, qr/Some of your .taskrc variables differ from the default values./, "$ut: Message is shown when non-default matches in pattern");
$output = qx{../src/task rc:$rc show 2>&1};
ok ($? == 0, "$ut: Exit status check");
like ($output, qr/Some of your .taskrc variables differ from the default values./, "$ut: Message is shown when non-default matches in all");
$output = qx{../src/task rc:$rc show report.overdue 2>&1};
ok ($? == 0, "$ut: Exit status check");
unlike ($output, qr/Some of your .taskrc variables differ/, "$ut: Message is not shown when no non-default matches in pattern");
# Bug 1065 - CmdShow should not display the unrecognized message if no non-default in matched elements.
$output = qx{../src/task rc:$rc show notrecog 2>&1};
ok ($? == 0, "$ut: Exit status check");
like ($output, qr/Your .taskrc file contains these unrecognized variables:/, "$ut: Message is shown when unrecognized matches in pattern");
$output = qx{../src/task rc:$rc show 2>&1};
ok ($? == 0, "$ut: Exit status check");
like ($output, qr/Your .taskrc file contains these unrecognized variables:/, "$ut: Message is shown when unrecognized matches in all");
$output = qx{../src/task rc:$rc show report.overdue 2>&1};
ok ($? == 0, "$ut: Exit status check");
unlike ($output, qr/unrecognized variables/, "$ut: Message is not shown when no non-default matches in pattern");
# Cleanup.
unlink qw(pending.data completed.data undo.data backlog.data), $rc;
exit 0;

View file

@ -1,60 +0,0 @@
#! /usr/bin/env perl
################################################################################
##
## Copyright 2006 - 2015, Paul Beckingham, Federico Hernandez.
##
## Permission is hereby granted, free of charge, to any person obtaining a copy
## of this software and associated documentation files (the "Software"), to deal
## in the Software without restriction, including without limitation the rights
## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
## copies of the Software, and to permit persons to whom the Software is
## furnished to do so, subject to the following conditions:
##
## The above copyright notice and this permission notice shall be included
## in all copies or substantial portions of the Software.
##
## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
## OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
## THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
## SOFTWARE.
##
## http://www.opensource.org/licenses/mit-license.php
##
################################################################################
use strict;
use warnings;
use Test::More tests => 2;
# Ensure environment has no influence.
delete $ENV{'TASKDATA'};
delete $ENV{'TASKRC'};
use File::Basename;
my $ut = basename ($0);
my $rc = $ut . '.rc';
# Create the rc file.
if (open my $fh, '>', $rc)
{
print $fh "data.location=.\n",
"confirmation=off\n";
close $fh;
}
# Bug 1110: reports print "Completed" but "Completed" != "completed"
qx{../src/task rc:$rc add ToBeCompleted 2>&1};
qx{../src/task rc:$rc 1 done 2>&1};
my $output = qx{../src/task all status:Completed rc:$rc 2>&1};
like ($output, qr/ToBeCompleted/, "$ut: status:Completed returns Completed tasks");
$output = qx{../src/task all status:completed rc:$rc 2>&1};
like ($output, qr/ToBeCompleted/, "$ut: status:completed returns completed tasks");
# Cleanup.
unlink qw(pending.data completed.data undo.data backlog.data), $rc;
exit 0;

95
test/custom.config.t Executable file
View file

@ -0,0 +1,95 @@
#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
###############################################################################
#
# Copyright 2006 - 2015, Paul Beckingham, Federico Hernandez.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
# http://www.opensource.org/licenses/mit-license.php
#
###############################################################################
import sys
import os
import unittest
# Ensure python finds the local simpletap module
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
from basetest import Task, TestCase, Taskd, ServerTestCase
class TestCustomConfig(TestCase):
def setUp(self):
self.t = Task()
self.t.config("alias.xyzzyx", "status:waiting")
self.t.config("imnotrecognized", "kai")
self.DIFFER_MSG = ("Some of your .taskrc variables differ from the "
"default values.")
self.NOT_RECOG_MSG = ("Your .taskrc file contains these unrecognized "
"variables:")
def test_show_alias(self):
"""task show <filter> - warns when non-default values are matched
Reported in bug 1065
"""
code, out, err = self.t(("show", "alias"))
self.assertIn(self.DIFFER_MSG, out)
self.assertNotIn(self.NOT_RECOG_MSG, out)
def test_show(self):
"""task show - warns when non-default values are matched
Reported in bug 1065
"""
code, out, err = self.t(("show",))
self.assertIn(self.DIFFER_MSG, out)
self.assertIn(self.NOT_RECOG_MSG, out)
def test_show_report_overdue(self):
"""task show <filter> - no warn when no non-default values are matched
Reported in bug 1065
"""
code, out, err = self.t(("show", "report.overdue"))
self.assertNotIn(self.DIFFER_MSG, out)
self.assertNotIn(self.NOT_RECOG_MSG, out)
def test_show_notrecog(self):
"""task show <filter> - warns when unrecognized values are matched
Reported in bug 1065
"""
code, out, err = self.t(("show", "notrecog"))
self.assertNotIn(self.DIFFER_MSG, out)
self.assertIn(self.NOT_RECOG_MSG, out)
if __name__ == "__main__":
from simpletap import TAPTestRunner
unittest.main(testRunner=TAPTestRunner())
# vim: ai sts=4 et sw=4

View file

@ -88,7 +88,7 @@ class TestFilterPrefix(TestCase):
self.assertIn('seven', out)
self.assertIn('eight', out)
def test_list_project_startwsith_bar(self):
def test_list_project_startswith_bar(self):
"""Filter on project name start."""
code, out, err = self.t(('list', 'project.startswith:bar'))
self.assertNotIn('one', out)
@ -124,7 +124,7 @@ class TestFilterPrefix(TestCase):
self.assertNotIn('seven', out)
self.assertNotIn('eight', out)
def test_list_descrtiption_has_foo(self):
def test_list_description_has_foo(self):
"""Filter on description pattern."""
code, out, err = self.t(('list', 'description.has:foo'))
self.assertIn('one', out)

View file

@ -1,281 +1,375 @@
#! /usr/bin/env perl
################################################################################
##
## Copyright 2006 - 2015, Paul Beckingham, Federico Hernandez.
##
## Permission is hereby granted, free of charge, to any person obtaining a copy
## of this software and associated documentation files (the "Software"), to deal
## in the Software without restriction, including without limitation the rights
## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
## copies of the Software, and to permit persons to whom the Software is
## furnished to do so, subject to the following conditions:
##
## The above copyright notice and this permission notice shall be included
## in all copies or substantial portions of the Software.
##
## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
## OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
## THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
## SOFTWARE.
##
## http://www.opensource.org/licenses/mit-license.php
##
################################################################################
#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
###############################################################################
#
# Copyright 2006 - 2015, Paul Beckingham, Federico Hernandez.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
# http://www.opensource.org/licenses/mit-license.php
#
###############################################################################
use strict;
use warnings;
use Test::More tests => 161;
import sys
import os
import unittest
# Ensure python finds the local simpletap module
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
# Ensure environment has no influence.
delete $ENV{'TASKDATA'};
delete $ENV{'TASKRC'};
from basetest import Task, TestCase
# Create the rc file.
if (open my $fh, '>', 'filter.rc')
{
print $fh "data.location=.\n";
close $fh;
}
# Test the filters.
qx{../src/task rc:filter.rc add project:A priority:H +tag one foo 2>&1};
qx{../src/task rc:filter.rc add project:A priority:H two 2>&1};
qx{../src/task rc:filter.rc add project:A three 2>&1};
qx{../src/task rc:filter.rc add priority:H four 2>&1};
qx{../src/task rc:filter.rc add +tag five 2>&1};
qx{../src/task rc:filter.rc add six foo 2>&1};
qx{../src/task rc:filter.rc add priority:L seven bar foo 2>&1};
class TestFilter(TestCase):
def setUp(self):
self.t = Task()
my $output = qx{../src/task rc:filter.rc list 2>&1};
like ($output, qr/one/, 'a1');
like ($output, qr/two/, 'a2');
like ($output, qr/three/, 'a3');
like ($output, qr/four/, 'a4');
like ($output, qr/five/, 'a5');
like ($output, qr/six/, 'a6');
like ($output, qr/seven/, 'a7');
self.t(("add", "project:A", "prio:H", "+tag", "one", "foo"))
self.t(("add", "project:A", "prio:H", "two"))
self.t(("add", "project:A", "three"))
self.t(("add", "prio:H", "four"))
self.t(("add", "+tag", "five"))
self.t(("add", "six", "foo"))
self.t(("add", "prio:L", "seven", "bar", "foo"))
$output = qx{../src/task rc:filter.rc list project:A 2>&1};
like ($output, qr/one/, 'b1');
like ($output, qr/two/, 'b2');
like ($output, qr/three/, 'b3');
unlike ($output, qr/four/, 'b4');
unlike ($output, qr/five/, 'b5');
unlike ($output, qr/six/, 'b6');
unlike ($output, qr/seven/, 'b7');
def test_list(self):
"""filter - list"""
code, out, err = self.t(("list",))
$output = qx{../src/task rc:filter.rc list priority:H 2>&1};
like ($output, qr/one/, 'c1');
like ($output, qr/two/, 'c2');
unlike ($output, qr/three/, 'c3');
like ($output, qr/four/, 'c4');
unlike ($output, qr/five/, 'c5');
unlike ($output, qr/six/, 'c6');
unlike ($output, qr/seven/, 'c7');
self.assertIn("one", out)
self.assertIn("two", out)
self.assertIn("three", out)
self.assertIn("four", out)
self.assertIn("five", out)
self.assertIn("six", out)
self.assertIn("seven", out)
$output = qx{../src/task rc:filter.rc list priority: 2>&1};
unlike ($output, qr/one/, 'd1');
unlike ($output, qr/two/, 'd2');
like ($output, qr/three/, 'd3');
unlike ($output, qr/four/, 'd4');
like ($output, qr/five/, 'd5');
like ($output, qr/six/, 'd6');
unlike ($output, qr/seven/, 'd7');
def test_list_projectA(self):
"""filter - list project:A"""
code, out, err = self.t(("list", "project:A"))
$output = qx{../src/task rc:filter.rc list /foo/ 2>&1};
like ($output, qr/one/, 'e1');
unlike ($output, qr/two/, 'e2');
unlike ($output, qr/three/, 'e3');
unlike ($output, qr/four/, 'e4');
unlike ($output, qr/five/, 'e5');
like ($output, qr/six/, 'e6');
like ($output, qr/seven/, 'e7');
self.assertIn("one", out)
self.assertIn("two", out)
self.assertIn("three", out)
self.assertNotIn("four", out)
self.assertNotIn("five", out)
self.assertNotIn("six", out)
self.assertNotIn("seven", out)
$output = qx{../src/task rc:filter.rc list /foo/ /bar/ 2>&1};
unlike ($output, qr/one/, 'f1');
unlike ($output, qr/two/, 'f2');
unlike ($output, qr/three/, 'f3');
unlike ($output, qr/four/, 'f4');
unlike ($output, qr/five/, 'f5');
unlike ($output, qr/six/, 'f6');
like ($output, qr/seven/, 'f7');
def test_list_priorityH(self):
"""filter - list priority:H"""
code, out, err = self.t(("list", "priority:H"))
$output = qx{../src/task rc:filter.rc list +tag 2>&1};
like ($output, qr/one/, 'g1');
unlike ($output, qr/two/, 'g2');
unlike ($output, qr/three/, 'g3');
unlike ($output, qr/four/, 'g4');
like ($output, qr/five/, 'g5');
unlike ($output, qr/six/, 'g6');
unlike ($output, qr/seven/, 'g7');
self.assertIn("one", out)
self.assertIn("two", out)
self.assertNotIn("three", out)
self.assertIn("four", out)
self.assertNotIn("five", out)
self.assertNotIn("six", out)
self.assertNotIn("seven", out)
$output = qx{../src/task rc:filter.rc list -tag 2>&1};
unlike ($output, qr/one/, 'h1');
like ($output, qr/two/, 'h2');
like ($output, qr/three/, 'h3');
like ($output, qr/four/, 'h4');
unlike ($output, qr/five/, 'h5');
like ($output, qr/six/, 'h6');
like ($output, qr/seven/, 'h7');
def test_list_priority(self):
"""filter - list priority:"""
code, out, err = self.t(("list", "priority:"))
$output = qx{../src/task rc:filter.rc list -missing 2>&1};
like ($output, qr/one/, 'i1');
like ($output, qr/two/, 'i2');
like ($output, qr/three/, 'i3');
like ($output, qr/four/, 'i4');
like ($output, qr/five/, 'i5');
like ($output, qr/six/, 'i6');
like ($output, qr/seven/, 'i7');
self.assertNotIn("one", out)
self.assertNotIn("two", out)
self.assertIn("three", out)
self.assertNotIn("four", out)
self.assertIn("five", out)
self.assertIn("six", out)
self.assertNotIn("seven", out)
$output = qx{../src/task rc:filter.rc list +tag -tag 2>&1};
unlike ($output, qr/one/, 'j1');
unlike ($output, qr/two/, 'j2');
unlike ($output, qr/three/, 'j3');
unlike ($output, qr/four/, 'j4');
unlike ($output, qr/five/, 'j5');
unlike ($output, qr/six/, 'j6');
unlike ($output, qr/seven/, 'j7');
def test_list_substring(self):
"""filter - list /foo/"""
code, out, err = self.t(("list", "/foo/"))
$output = qx{../src/task rc:filter.rc list project:A priority:H 2>&1};
like ($output, qr/one/, 'k1');
like ($output, qr/two/, 'k2');
unlike ($output, qr/three/, 'k3');
unlike ($output, qr/four/, 'k4');
unlike ($output, qr/five/, 'k5');
unlike ($output, qr/six/, 'k6');
unlike ($output, qr/seven/, 'k7');
self.assertIn("one", out)
self.assertNotIn("two", out)
self.assertNotIn("three", out)
self.assertNotIn("four", out)
self.assertNotIn("five", out)
self.assertIn("six", out)
self.assertIn("seven", out)
$output = qx{../src/task rc:filter.rc list project:A priority: 2>&1};
unlike ($output, qr/one/, 'l1');
unlike ($output, qr/two/, 'l2');
like ($output, qr/three/, 'l3');
unlike ($output, qr/four/, 'l4');
unlike ($output, qr/five/, 'l5');
unlike ($output, qr/six/, 'l6');
unlike ($output, qr/seven/, 'l7');
def test_list_double_substring(self):
"""filter - list /foo/ /bar/"""
code, out, err = self.t(("list", "/foo/", "/bar/"))
$output = qx{../src/task rc:filter.rc list project:A /foo/ 2>&1};
like ($output, qr/one/, 'm1');
unlike ($output, qr/two/, 'm2');
unlike ($output, qr/three/, 'm3');
unlike ($output, qr/four/, 'm4');
unlike ($output, qr/five/, 'm5');
unlike ($output, qr/six/, 'm6');
unlike ($output, qr/seven/, 'm7');
self.assertNotIn("one", out)
self.assertNotIn("two", out)
self.assertNotIn("three", out)
self.assertNotIn("four", out)
self.assertNotIn("five", out)
self.assertNotIn("six", out)
self.assertIn("seven", out)
$output = qx{../src/task rc:filter.rc list project:A +tag 2>&1};
like ($output, qr/one/, 'n1');
unlike ($output, qr/two/, 'n2');
unlike ($output, qr/three/, 'n3');
unlike ($output, qr/four/, 'n4');
unlike ($output, qr/five/, 'n5');
unlike ($output, qr/six/, 'n6');
unlike ($output, qr/seven/, 'n7');
def test_list_include_tag(self):
"""filter - list +tag"""
code, out, err = self.t(("list", "+tag"))
$output = qx{../src/task rc:filter.rc list project:A priority:H /foo/ 2>&1};
like ($output, qr/one/, 'o1');
unlike ($output, qr/two/, 'o2');
unlike ($output, qr/three/, 'o3');
unlike ($output, qr/four/, 'o4');
unlike ($output, qr/five/, 'o5');
unlike ($output, qr/six/, 'o6');
unlike ($output, qr/seven/, 'o7');
self.assertIn("one", out)
self.assertNotIn("two", out)
self.assertNotIn("three", out)
self.assertNotIn("four", out)
self.assertIn("five", out)
self.assertNotIn("six", out)
self.assertNotIn("seven", out)
$output = qx{../src/task rc:filter.rc list project:A priority:H +tag 2>&1};
like ($output, qr/one/, 'p1');
unlike ($output, qr/two/, 'p2');
unlike ($output, qr/three/, 'p3');
unlike ($output, qr/four/, 'p4');
unlike ($output, qr/five/, 'p5');
unlike ($output, qr/six/, 'p6');
unlike ($output, qr/seven/, 'p7');
def test_list_exclude_tag(self):
"""filter - list -tag"""
code, out, err = self.t(("list", "-tag"))
$output = qx{../src/task rc:filter.rc list project:A priority:H /foo/ +tag 2>&1};
like ($output, qr/one/, 'q1');
unlike ($output, qr/two/, 'q2');
unlike ($output, qr/three/, 'q3');
unlike ($output, qr/four/, 'q4');
unlike ($output, qr/five/, 'q5');
unlike ($output, qr/six/, 'q6');
unlike ($output, qr/seven/, 'q7');
self.assertNotIn("one", out)
self.assertIn("two", out)
self.assertIn("three", out)
self.assertIn("four", out)
self.assertNotIn("five", out)
self.assertIn("six", out)
self.assertIn("seven", out)
$output = qx{../src/task rc:filter.rc list project:A priority:H /foo/ +tag /baz/ 2>&1};
unlike ($output, qr/one/, 'r1');
unlike ($output, qr/two/, 'r2');
unlike ($output, qr/three/, 'r3');
unlike ($output, qr/four/, 'r4');
unlike ($output, qr/five/, 'r5');
unlike ($output, qr/six/, 'r6');
unlike ($output, qr/seven/, 'r7');
def test_list_non_existing_tag(self):
"""filter - list -missing"""
code, out, err = self.t(("list", "-missing"))
# Regex filters.
#$output = qx{../src/task rc:filter.rc list rc.regex:on project:/[A-Z]/ 2>&1};
#like ($output, qr/one/, 's1');
#like ($output, qr/two/, 's2');
#like ($output, qr/three/, 's3');
#unlike ($output, qr/four/, 's4');
#unlike ($output, qr/five/, 's5');
#unlike ($output, qr/six/, 's6');
#unlike ($output, qr/seven/, 's7');
self.assertIn("one", out)
self.assertIn("two", out)
self.assertIn("three", out)
self.assertIn("four", out)
self.assertIn("five", out)
self.assertIn("six", out)
self.assertIn("seven", out)
#$output = qx{../src/task rc:filter.rc list rc.regex:on project:. 2>&1};
#like ($output, qr/one/, 't1');
#like ($output, qr/two/, 't2');
#like ($output, qr/three/, 't3');
#unlike ($output, qr/four/, 't4');
#unlike ($output, qr/five/, 't5');
#unlike ($output, qr/six/, 't6');
#unlike ($output, qr/seven/, 't7');
def test_list_mutually_exclusive_tag(self):
"""filter - list +tag -tag"""
code, out, err = self.t.runError(("list", "+tag", "-tag"))
$output = qx{../src/task rc:filter.rc rc.regex:on list /fo\{2\}/ 2>&1};
like ($output, qr/one/, 'u1');
unlike ($output, qr/two/, 'u2');
unlike ($output, qr/three/, 'u3');
unlike ($output, qr/four/, 'u4');
unlike ($output, qr/five/, 'u5');
like ($output, qr/six/, 'u6');
like ($output, qr/seven/, 'u7');
self.assertNotIn("one", out)
self.assertNotIn("two", out)
self.assertNotIn("three", out)
self.assertNotIn("four", out)
self.assertNotIn("five", out)
self.assertNotIn("six", out)
self.assertNotIn("seven", out)
$output = qx{../src/task rc:filter.rc rc.regex:on list /f../ /b../ 2>&1};
unlike ($output, qr/one/, 'v1');
unlike ($output, qr/two/, 'v2');
unlike ($output, qr/three/, 'v3');
unlike ($output, qr/four/, 'v4');
unlike ($output, qr/five/, 'v5');
unlike ($output, qr/six/, 'v6');
like ($output, qr/seven/, 'v7');
def test_list_projectA_priorityH(self):
"""filter - list project:A priority:H"""
code, out, err = self.t(("list", "project:A", "priority:H"))
$output = qx{../src/task rc:filter.rc rc.regex:on list /\\^s/ 2>&1};
unlike ($output, qr/one/, 'w1');
unlike ($output, qr/two/, 'w2');
unlike ($output, qr/three/, 'w3');
unlike ($output, qr/four/, 'w4');
unlike ($output, qr/five/, 'w5');
like ($output, qr/six/, 'w6');
like ($output, qr/seven/, 'w7');
self.assertIn("one", out)
self.assertIn("two", out)
self.assertNotIn("three", out)
self.assertNotIn("four", out)
self.assertNotIn("five", out)
self.assertNotIn("six", out)
self.assertNotIn("seven", out)
$output = qx{../src/task rc:filter.rc rc.regex:on list /\\^.i/ 2>&1};
unlike ($output, qr/one/, 'x1');
unlike ($output, qr/two/, 'x2');
unlike ($output, qr/three/, 'x3');
unlike ($output, qr/four/, 'x4');
like ($output, qr/five/, 'x5');
like ($output, qr/six/, 'x6');
unlike ($output, qr/seven/, 'x7');
def test_list_projectA_priority(self):
"""filter - list project:A priority:"""
code, out, err = self.t(("list", "project:A", "priority:"))
$output = qx{../src/task rc:filter.rc rc.regex:on list "/two|five/" 2>&1};
unlike ($output, qr/one/, 'y1');
like ($output, qr/two/, 'y2');
unlike ($output, qr/three/, 'y3');
unlike ($output, qr/four/, 'y4');
like ($output, qr/five/, 'y5');
unlike ($output, qr/six/, 'y6');
unlike ($output, qr/seven/, 'y7');
self.assertNotIn("one", out)
self.assertNotIn("two", out)
self.assertIn("three", out)
self.assertNotIn("four", out)
self.assertNotIn("five", out)
self.assertNotIn("six", out)
self.assertNotIn("seven", out)
# Cleanup.
unlink qw(pending.data completed.data undo.data backlog.data filter.rc);
exit 0;
def test_list_projectA_substring(self):
"""filter - list project:A /foo/"""
code, out, err = self.t(("list", "project:A", "/foo/"))
self.assertIn("one", out)
self.assertNotIn("two", out)
self.assertNotIn("three", out)
self.assertNotIn("four", out)
self.assertNotIn("five", out)
self.assertNotIn("six", out)
self.assertNotIn("seven", out)
def test_list_projectA_tag(self):
"""filter - list project:A +tag"""
code, out, err = self.t(("list", "project:A", "+tag"))
self.assertIn("one", out)
self.assertNotIn("two", out)
self.assertNotIn("three", out)
self.assertNotIn("four", out)
self.assertNotIn("five", out)
self.assertNotIn("six", out)
self.assertNotIn("seven", out)
def test_list_projectA_priorityH_substring(self):
"""filter - list project:A priority:H /foo/"""
code, out, err = self.t(("list", "project:A", "priority:H", "/foo/"))
self.assertIn("one", out)
self.assertNotIn("two", out)
self.assertNotIn("three", out)
self.assertNotIn("four", out)
self.assertNotIn("five", out)
self.assertNotIn("six", out)
self.assertNotIn("seven", out)
def test_list_projectA_priorityH_tag(self):
"""filter - list project:A priority:H +tag"""
code, out, err = self.t(("list", "project:A", "priority:H", "+tag"))
self.assertIn("one", out)
self.assertNotIn("two", out)
self.assertNotIn("three", out)
self.assertNotIn("four", out)
self.assertNotIn("five", out)
self.assertNotIn("six", out)
self.assertNotIn("seven", out)
def test_list_projectA_priorityH_substring_tag(self):
"""filter - list project:A priority:H /foo/ +tag"""
code, out, err = self.t(("list", "project:A", "priority:H", "/foo/",
"+tag"))
self.assertIn("one", out)
self.assertNotIn("two", out)
self.assertNotIn("three", out)
self.assertNotIn("four", out)
self.assertNotIn("five", out)
self.assertNotIn("six", out)
self.assertNotIn("seven", out)
def test_list_projectA_priorityH_substring_tag_substring(self):
"""filter - list project:A priority:H /foo/ +tag /baz/"""
code, out, err = self.t.runError(("list", "project:A", "priority:H",
"/foo/", "+tag", "/baz/"))
self.assertNotIn("one", out)
self.assertNotIn("two", out)
self.assertNotIn("three", out)
self.assertNotIn("four", out)
self.assertNotIn("five", out)
self.assertNotIn("six", out)
self.assertNotIn("seven", out)
@unittest.expectedFailure
def test_regex_list_project(self):
"""filter - rc.regex:on list project:/[A-Z]/"""
code, out, err = self.t(("rc.regex:on", "list", "project:/[A-Z]/"))
self.assertIn("one", out)
self.assertIn("two", out)
self.assertIn("three", out)
self.assertNotIn("four", out)
self.assertNotIn("five", out)
self.assertNotIn("six", out)
self.assertNotIn("seven", out)
@unittest.expectedFailure
def test_regex_list_project_any(self):
"""filter - rc.regex:on list project:."""
code, out, err = self.t(("rc.regex:on", "list", "project:."))
self.assertIn("one", out)
self.assertIn("two", out)
self.assertIn("three", out)
self.assertNotIn("four", out)
self.assertNotIn("five", out)
self.assertNotIn("six", out)
self.assertNotIn("seven", out)
def test_regex_list_substring(self):
"""filter - rc.regex:on list /fo{2}/"""
code, out, err = self.t(("rc.regex:on", "list", "/fo{2}/"))
self.assertIn("one", out)
self.assertNotIn("two", out)
self.assertNotIn("three", out)
self.assertNotIn("four", out)
self.assertNotIn("five", out)
self.assertIn("six", out)
self.assertIn("seven", out)
def test_regex_list_double_substring_wildcard(self):
"""filter - rc.regex:on list /f../ /b../"""
code, out, err = self.t(("rc.regex:on", "list", "/f../", "/b../"))
self.assertNotIn("one", out)
self.assertNotIn("two", out)
self.assertNotIn("three", out)
self.assertNotIn("four", out)
self.assertNotIn("five", out)
self.assertNotIn("six", out)
self.assertIn("seven", out)
def test_regex_list_substring_startswith(self):
"""filter - rc.regex:on list /^s/"""
code, out, err = self.t(("rc.regex:on", "list", "/^s/"))
self.assertNotIn("one", out)
self.assertNotIn("two", out)
self.assertNotIn("three", out)
self.assertNotIn("four", out)
self.assertNotIn("five", out)
self.assertIn("six", out)
self.assertIn("seven", out)
def test_regex_list_substring_wildcard_startswith(self):
"""filter - rc.regex:on list /^.i/"""
code, out, err = self.t(("rc.regex:on", "list", "/^.i/"))
self.assertNotIn("one", out)
self.assertNotIn("two", out)
self.assertNotIn("three", out)
self.assertNotIn("four", out)
self.assertIn("five", out)
self.assertIn("six", out)
self.assertNotIn("seven", out)
def test_regex_list_substring_or(self):
"""filter - rc.regex:on list /two|five/"""
code, out, err = self.t(("rc.regex:on", "list", "/two|five/"))
self.assertNotIn("one", out)
self.assertIn("two", out)
self.assertNotIn("three", out)
self.assertNotIn("four", out)
self.assertIn("five", out)
self.assertNotIn("six", out)
self.assertNotIn("seven", out)
class TestBug1110(TestCase):
def setUp(self):
self.t = Task()
def test_status_is_case_insensitive(self):
"""filter - status:Completed / status:completed - behave the same"""
self.t(("add", "ToBeCompleted"))
self.t(("1", "done"))
code, out, err = self.t(("all", "status:Completed"))
self.assertIn("ToBeCompleted", out)
code, out, err = self.t(("all", "status:completed"))
self.assertIn("ToBeCompleted", out)
if __name__ == "__main__":
from simpletap import TAPTestRunner
unittest.main(testRunner=TAPTestRunner())
# vim: ai sts=4 et sw=4

View file

@ -96,13 +96,7 @@ class TestProjects(TestCase):
self.assertRegexpMatches(err, self.STATUS.format("foo bar", "0%",
"1 task"))
def test_project_indentation(self):
"""check project/subproject indentation
Reported in bug 1056
See also the tests of helper functions for CmdProjects in util.t.cpp
"""
def add_tasks(self):
self.t(("add", "testing", "project:existingParent"))
self.t(("add", "testing", "project:existingParent.child"))
self.t(("add", "testing", "project:abstractParent.kid"))
@ -110,8 +104,7 @@ class TestProjects(TestCase):
self.t(("add", "testing", "project:myProject"))
self.t(("add", "testing", "project:.myProject."))
code, out, err = self.t(("projects",))
def validate_indentation(self, out):
order = (
".myProject ",
".myProject. ",
@ -135,6 +128,30 @@ class TestProjects(TestCase):
"indentation.{2}".format(proj, pos, out))
)
def test_project_indentation(self):
"""check project/subproject indentation in 'task projects'
Reported in bug 1056
See also the tests of helper functions for CmdProjects in util.t.cpp
"""
self.add_tasks()
code, out, err = self.t(("projects",))
self.validate_indentation(out)
def test_project_indentation_in_summary(self):
"""check project/subproject indentation in 'task summary'
Reported in bug 1056
"""
self.add_tasks()
code, out, err = self.t(("summary",))
self.validate_indentation(out)
if __name__ == "__main__":
from simpletap import TAPTestRunner

View file

@ -33,6 +33,23 @@ import warnings
import traceback
def color(text, c):
"""
Add color on the keyword that identifies the state of the test
"""
if sys.stdout.isatty():
clear = "\033[0m"
colors = {
"red": "\033[1m\033[91m",
"yellow": "\033[1m\033[93m",
"green": "\033[1m\033[92m",
}
return colors[c] + text + clear
else:
return text
class TAPTestResult(unittest.result.TestResult):
def __init__(self, stream, descriptions, verbosity):
super(TAPTestResult, self).__init__(stream, descriptions, verbosity)
@ -126,13 +143,20 @@ class TAPTestResult(unittest.result.TestResult):
if status:
if status == "SKIP":
self.stream.writeln("skip {0} - {1}".format(
self.testsRun, desc))
self.stream.writeln("{0} {1} - {2}".format(
color("skip", "yellow"), self.testsRun, desc)
)
elif status == "EXPECTED_FAILURE":
self.stream.writeln("{0} {1} - {2}".format(
color("ok", "green"), self.testsRun, desc)
)
else:
self.stream.writeln("not ok {0} - {1}".format(
self.testsRun, desc))
self.stream.writeln("{0} {1} - {2}".format(
color("not ok", "red"), self.testsRun, desc)
)
self.stream.writeln("# {0}: {1} {2}:".format(
status, exception_name, trace_msg))
status, exception_name, trace_msg)
)
# Magic 3 is just for pretty indentation
padding = " " * (len(status) + 3)
@ -142,7 +166,9 @@ class TAPTestResult(unittest.result.TestResult):
line = line.replace("\\n", "\n# ")
self.stream.writeln("#{0}{1}".format(padding, line))
else:
self.stream.writeln("ok {0} - {1}".format(self.testsRun, desc))
self.stream.writeln("{0} {1} - {2}".format(
color("ok", "green"), self.testsRun, desc)
)
# Flush all buffers to stdout
self._mergeStdout()
@ -163,6 +189,10 @@ class TAPTestResult(unittest.result.TestResult):
super(TAPTestResult, self).addSkip(test, reason)
self.report(test, "SKIP", reason)
def addExpectedFailure(self, test, err):
super(TAPTestResult, self).addExpectedFailure(test, err)
self.report(test, "EXPECTED_FAILURE", err)
class TAPTestRunner(unittest.runner.TextTestRunner):
"""A test runner that displays results using the Test Anything Protocol

View file

@ -29,6 +29,7 @@
import sys
import os
import unittest
import re
from datetime import datetime
# Ensure python finds the local simpletap module
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
@ -41,28 +42,76 @@ class TestVersion(TestCase):
def setUp(self):
self.t = Task()
def test_version(self):
"""Copyright is current"""
args = ("version",)
self.t.config("default.command", "")
code, out, err = self.t(args)
def test_usage_command(self):
"""no_command = usage - reports failure"""
code, out, err = self.t.runError()
self.assertIn("You must specify a command or a task to modify", err)
def test_copyright_up_to_date(self):
"""Copyright is current"""
code, out, err = self.t(("version",))
expected = "Copyright \(C\) \d{4} - %d" % (datetime.now().year,)
self.assertRegexpMatches(out.decode("utf8"), expected)
self.assertRegexpMatches(out, expected)
def slurp(self, file="../CMakeLists.txt"):
number = "\.".join(["[0-9]+"] * 3)
ver = re.compile("^set \(PROJECT_VERSION \"({0})\"\)$".format(number))
with open(file) as fh:
for line in fh:
if "PROJECT_VERSION" in line:
match = ver.match(line)
if match:
return match.group(1)
raise ValueError("Couldn't find matching version in {0}".format(file))
def test_version(self):
"""version command outputs expected version and license"""
code, out, err = self.t(("version",))
expected = "task {0}".format(self.slurp())
self.assertIn(expected, out)
self.assertIn("MIT license", out)
self.assertIn("http://taskwarrior.org", out)
def slurp_git(self):
git_cmd = ("git", "rev-parse", "--short", "--verify", "HEAD")
_, hash, _ = run_cmd_wait(git_cmd)
return hash.rstrip("\n")
def test_under_version(self):
"""_version outputs expected version and syntax"""
code, out, err = self.t(("_version",))
# version = "x.x.x (git-hash)" or simply "x.x.x"
# corresponding to "compiled from git" or "compiled from tarball"
version = out.split()
if 2 >= len(version) > 0:
git = version[1]
git_expected = "({0})".format(self.slurp_git())
self.assertEqual(git_expected, git)
else:
raise ValueError("Unexpected output from _version '{0}'".format(
out))
ver = version[0]
ver_expected = self.slurp()
self.assertEqual(ver_expected, ver)
def test_task_git_version(self):
"""Task binary matches the current git commit"""
git_cmd = ("git", "rev-parse", "--short", "--verify", "HEAD")
_, hash, _ = run_cmd_wait(git_cmd)
expected = "Commit: {0}".format(hash)
expected = "Commit: {0}".format(self.slurp_git())
args = ("diag",)
code, out, err = self.t(args)
self.assertIn(expected, out)
if __name__ == "__main__":
from simpletap import TAPTestRunner
unittest.main(testRunner=TAPTestRunner())