diff --git a/CMakeLists.txt b/CMakeLists.txt index 8fb4015de..5bd78ef5d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) diff --git a/ChangeLog b/ChangeLog index c6a422317..5e2df7d6a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -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. diff --git a/DEVELOPER b/DEVELOPER index 2c3a97f0a..bff632902 100644 --- a/DEVELOPER +++ b/DEVELOPER @@ -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 diff --git a/NEWS b/NEWS index 16224a133..11c774722 100644 --- a/NEWS +++ b/NEWS @@ -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.' 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: diff --git a/doc/man/task-color.5.in b/doc/man/task-color.5.in index 46d612124..020bcc8d0 100644 --- a/doc/man/task-color.5.in +++ b/doc/man/task-color.5.in @@ -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. diff --git a/doc/man/task-sync.5.in b/doc/man/task-sync.5.in index fe8d5bbbb..a66e265eb 100644 --- a/doc/man/task-sync.5.in +++ b/doc/man/task-sync.5.in @@ -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 diff --git a/doc/man/task.1.in b/doc/man/task.1.in index 887dd7e16..bc1dc1a37 100644 --- a/doc/man/task.1.in +++ b/doc/man/task.1.in @@ -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 +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 - + .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 diff --git a/doc/man/taskrc.5.in b/doc/man/taskrc.5.in index b0fa4cf79..b9bf7329b 100644 --- a/doc/man/taskrc.5.in +++ b/doc/man/taskrc.5.in @@ -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. diff --git a/doc/misc/themes/README b/doc/misc/themes/README index bcc7b93e3..aaf1af97b 100644 --- a/doc/misc/themes/README +++ b/doc/misc/themes/README @@ -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. diff --git a/doc/misc/themes/run b/doc/misc/themes/run deleted file mode 100755 index 4a30d07e7..000000000 --- a/doc/misc/themes/run +++ /dev/null @@ -1,23 +0,0 @@ - - -for theme in $PWD/../../rc/*.theme -do - cat <>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 diff --git a/doc/misc/themes/run.dark b/doc/misc/themes/run.dark index b6fd2f2d1..99d6ed7fe 100755 --- a/doc/misc/themes/run.dark +++ b/doc/misc/themes/run.dark @@ -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' diff --git a/doc/misc/themes/run.default b/doc/misc/themes/run.default new file mode 100755 index 000000000..3a0364537 --- /dev/null +++ b/doc/misc/themes/run.default @@ -0,0 +1,24 @@ +#!/bin/bash + +cat <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 diff --git a/doc/misc/themes/run.light b/doc/misc/themes/run.light index be74f42b7..3cde4e58f 100755 --- a/doc/misc/themes/run.light +++ b/doc/misc/themes/run.light @@ -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' diff --git a/doc/misc/themes/run.solar.dark b/doc/misc/themes/run.solar.dark index de43551a2..95ecd62a6 100755 --- a/doc/misc/themes/run.solar.dark +++ b/doc/misc/themes/run.solar.dark @@ -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' diff --git a/doc/misc/themes/run.solar.light b/doc/misc/themes/run.solar.light index 780cc2ac0..712b280c2 100755 --- a/doc/misc/themes/run.solar.light +++ b/doc/misc/themes/run.solar.light @@ -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' diff --git a/doc/rc/dark-16.theme b/doc/rc/dark-16.theme index c974f29b4..b3cccf109 100644 --- a/doc/rc/dark-16.theme +++ b/doc/rc/dark-16.theme @@ -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 diff --git a/doc/rc/dark-256.theme b/doc/rc/dark-256.theme index 1a3925ae2..36ec00041 100644 --- a/doc/rc/dark-256.theme +++ b/doc/rc/dark-256.theme @@ -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 diff --git a/doc/rc/dark-blue-256.theme b/doc/rc/dark-blue-256.theme index 6659eb682..d038bf147 100644 --- a/doc/rc/dark-blue-256.theme +++ b/doc/rc/dark-blue-256.theme @@ -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 diff --git a/doc/rc/dark-gray-256.theme b/doc/rc/dark-gray-256.theme index 95d583549..1fccb2986 100644 --- a/doc/rc/dark-gray-256.theme +++ b/doc/rc/dark-gray-256.theme @@ -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 diff --git a/doc/rc/dark-gray-blue-256.theme b/doc/rc/dark-gray-blue-256.theme index 596529eeb..0c3958b45 100644 --- a/doc/rc/dark-gray-blue-256.theme +++ b/doc/rc/dark-gray-blue-256.theme @@ -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 diff --git a/doc/rc/dark-green-256.theme b/doc/rc/dark-green-256.theme index f2d741a71..becaeba5c 100644 --- a/doc/rc/dark-green-256.theme +++ b/doc/rc/dark-green-256.theme @@ -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 diff --git a/doc/rc/dark-red-256.theme b/doc/rc/dark-red-256.theme index 17c4b1b69..9e3a7f11b 100644 --- a/doc/rc/dark-red-256.theme +++ b/doc/rc/dark-red-256.theme @@ -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 diff --git a/doc/rc/dark-violets-256.theme b/doc/rc/dark-violets-256.theme index 42c5b51d1..75dbc3bea 100644 --- a/doc/rc/dark-violets-256.theme +++ b/doc/rc/dark-violets-256.theme @@ -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 diff --git a/doc/rc/dark-yellow-green.theme b/doc/rc/dark-yellow-green.theme index 62d14e56c..82829dc74 100644 --- a/doc/rc/dark-yellow-green.theme +++ b/doc/rc/dark-yellow-green.theme @@ -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 diff --git a/doc/rc/light-16.theme b/doc/rc/light-16.theme index 527a21f9d..37f2e2b73 100644 --- a/doc/rc/light-16.theme +++ b/doc/rc/light-16.theme @@ -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 diff --git a/doc/rc/light-256.theme b/doc/rc/light-256.theme index 359272fd1..57eb3463a 100644 --- a/doc/rc/light-256.theme +++ b/doc/rc/light-256.theme @@ -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 diff --git a/doc/rc/solarized-dark-256.theme b/doc/rc/solarized-dark-256.theme index 20316cb45..add6723a5 100644 --- a/doc/rc/solarized-dark-256.theme +++ b/doc/rc/solarized-dark-256.theme @@ -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 diff --git a/doc/rc/solarized-light-256.theme b/doc/rc/solarized-light-256.theme index 2a0cd2015..3bb034217 100644 --- a/doc/rc/solarized-light-256.theme +++ b/doc/rc/solarized-light-256.theme @@ -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 diff --git a/doc/ref/task-ref.pages b/doc/ref/task-ref.pages index a13213b5c..0f5535fa7 100644 Binary files a/doc/ref/task-ref.pages and b/doc/ref/task-ref.pages differ diff --git a/doc/ref/task-ref.pdf b/doc/ref/task-ref.pdf index 400654472..ed8f95bb2 100644 Binary files a/doc/ref/task-ref.pdf and b/doc/ref/task-ref.pdf differ diff --git a/scripts/bash/task.sh b/scripts/bash/task.sh index 7c37944cc..506de4a21 100644 --- a/scripts/bash/task.sh +++ b/scripts/bash/task.sh @@ -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 diff --git a/src/CLI.cpp b/src/CLI.cpp index 1a15e65eb..b188abe39 100644 --- a/src/CLI.cpp +++ b/src/CLI.cpp @@ -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 ()) diff --git a/src/CLI.h b/src/CLI.h index cf84947d2..573809a39 100644 --- a/src/CLI.h +++ b/src/CLI.h @@ -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 getWords (); bool canonicalize (std::string&, const std::string&, const std::string&) const; std::string getBinary () const; diff --git a/src/Config.cpp b/src/Config.cpp index 792d9429a..ce1d956ac 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -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" diff --git a/src/Filter.cpp b/src/Filter.cpp index 3a672599d..0f3cd265f 100644 --- a/src/Filter.cpp +++ b/src/Filter.cpp @@ -67,7 +67,7 @@ Filter::~Filter () //////////////////////////////////////////////////////////////////////////////// // Take an input set of tasks and filter into a subset. -void Filter::subset (const std::vector & input, std::vector & output) +void Filter::subset (const std::vector & input, std::vector & output, bool applyContext /* = true */) { context.timer_filter.start (); _startCount = (int) input.size (); @@ -75,7 +75,7 @@ void Filter::subset (const std::vector & input, std::vector & 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 & input, std::vector & output //////////////////////////////////////////////////////////////////////////////// // Take the set of all tasks and filter into a subset. -void Filter::subset (std::vector & output) +void Filter::subset (std::vector & output, bool applyContext /* = true */) { context.timer_filter.start (); @@ -119,7 +119,7 @@ void Filter::subset (std::vector & 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 (); diff --git a/src/Filter.h b/src/Filter.h index 0a40543ac..e2c4c3d44 100644 --- a/src/Filter.h +++ b/src/Filter.h @@ -40,8 +40,8 @@ public: Filter (); ~Filter (); - void subset (const std::vector &, std::vector &); - void subset (std::vector &); + void subset (const std::vector &, std::vector &, bool applyContext = true); + void subset (std::vector &, bool applyContext = true); bool pendingOnly (); void safety (); diff --git a/src/commands/CmdExport.cpp b/src/commands/CmdExport.cpp index 43cb30ecb..750fa556b 100644 --- a/src/commands/CmdExport.cpp +++ b/src/commands/CmdExport.cpp @@ -54,7 +54,7 @@ int CmdExport::execute (std::string& output) // Apply filter. Filter filter; std::vector filtered; - filter.subset (filtered); + filter.subset (filtered, false); // Obey 'limit:N'. int rows = 0; diff --git a/src/commands/CmdVersion.cpp b/src/commands/CmdVersion.cpp index d5f357b2d..c20fa4234 100644 --- a/src/commands/CmdVersion.cpp +++ b/src/commands/CmdVersion.cpp @@ -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 diff --git a/test/basic.t b/test/basic.t deleted file mode 100755 index e254e0384..000000000 --- a/test/basic.t +++ /dev/null @@ -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 $_; - } - } - } - ''; -} diff --git a/test/bug.1056.t b/test/bug.1056.t deleted file mode 100755 index df8d11c37..000000000 --- a/test/bug.1056.t +++ /dev/null @@ -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; - diff --git a/test/bug.1063.t b/test/bug.1063.t index bb2afc206..cca1192d5 100755 --- a/test/bug.1063.t +++ b/test/bug.1063.t @@ -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 diff --git a/test/bug.1065.t b/test/bug.1065.t deleted file mode 100755 index 4ae494d5c..000000000 --- a/test/bug.1065.t +++ /dev/null @@ -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; diff --git a/test/bug.1110.t b/test/bug.1110.t deleted file mode 100755 index 900b875b2..000000000 --- a/test/bug.1110.t +++ /dev/null @@ -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; diff --git a/test/custom.config.t b/test/custom.config.t new file mode 100755 index 000000000..05f056a99 --- /dev/null +++ b/test/custom.config.t @@ -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 - 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 - 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 - 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 diff --git a/test/filter-prefix.t b/test/filter-prefix.t index 00e9f62ae..c55061725 100755 --- a/test/filter-prefix.t +++ b/test/filter-prefix.t @@ -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) diff --git a/test/filter.t b/test/filter.t index eff20bcda..430456ae0 100755 --- a/test/filter.t +++ b/test/filter.t @@ -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 diff --git a/test/project.t b/test/project.t index d7f4b53fa..9d566d56d 100755 --- a/test/project.t +++ b/test/project.t @@ -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 diff --git a/test/simpletap/__init__.py b/test/simpletap/__init__.py index 6cfd16676..6e81d6529 100644 --- a/test/simpletap/__init__.py +++ b/test/simpletap/__init__.py @@ -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 diff --git a/test/version.t b/test/version.t index 5e0324091..4fe1ab873 100755 --- a/test/version.t +++ b/test/version.t @@ -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())