Compare commits

..

11 Commits

Author SHA1 Message Date
Ingo Karkat
3b960a2e3c Revert to safer POSIX AWK regexp.
AWK from Ubuntu 8.04 (mawk) doesn't support [[:space:]]; so for backwards compatibility use a plain ASCII space instead.
2012-02-21 09:18:39 +01:00
Gina Trapani
ad1ca6c2c9 Merge pull request #75 from inkarkat/rid-tmp-file
Split up _list() and get rid of $TMP_FILE and cleanup().
2012-02-14 21:59:10 -08:00
Gina Trapani
36e018fd86 Merge pull request #74 from inkarkat/listpri-pri-range
ENH: Allow listpri filtering with priority ranges.
2012-02-14 21:58:26 -08:00
Gina Trapani
74858365f6 Merge pull request #73 from inkarkat/testlib-enhancements
Testlib enhancements

As the vast majority of tests uses the todo.sh output to verify its correctness, output differences should always be shown, not just in verbose mode. 

This change removes the output redirection and check for exit code from the command-under-test, so as another benefit, these "housekeeping commands" are now kept off the test log.

Also, by using a separate function for exit code assertion, this can now report both differences in output and exit code (and not suppress the former any more.)

(Note: To see any of this, you need to temporarily introduce some test failures.)

Finally, I've added color highlighting for the aggregate test report (as in test-lib), because it didn't stood out against the colored test results, so that I often missed the crucial summary.
2012-02-14 20:55:28 -08:00
Ingo Karkat
be0a0265d1 Also get rid of TMP_FILE in todo.cfg.
There's a slight chance that some add-on has used this (undocumented, unofficial) configuration value for its own purposes (and maybe also relied on the unexposed cleanup() infrastructure), but detecting and fixing that problem (by moving the cleanup into the add-on itself) is pretty straightforward.
2012-01-26 16:21:46 +01:00
Ingo Karkat
cf7f7531be Break up _list(), get rid of TMP_FILE.
Extract a new function _format() (and getPadding(), both also exported for add-ons) from _list(), which includes the main formatting and filtering pipeline, without the file handling and verbose summary. This can receive the todo file via stdin, so the listall action is able to format the concatenated files without going through a temporary file.

Eventually, after further refactorings, _format() could be used for actual formatted verbose messages in all commands; currently, the raw, unformatted task is printed.
2012-01-26 16:18:30 +01:00
Ingo Karkat
28ec5a06f2 Get rid of cleanup, only use TMP_FILE in listall.
After the recent refactorings, the temporary file is only needed for the listall action. Therefore, the creation-checks and eventual cleanup can be restricted to the listall action, which should slightly speed up the overall script execution.
2012-01-26 14:48:29 +01:00
Ingo Karkat
c31716af47 test-report: Use color highlighting as in test-lib.
The test aggregate results are easy to miss when running the entire test suite via "make test", as the status of the last test case is highlighted, but the aggregate results appear in an unformatted, uncolored block of text.
Copy the say_color() function from test-lib.sh. (Sorry for the duplication, I found no simple way to import or share just this piece of functionality without adding much complexity.)
Successes, errors and broken summaries will now be highlighted in the appropriate colors (unless --no-color is given or output is not to a terminal), but only if the number is more than zero.
2012-01-26 12:15:26 +01:00
Ingo Karkat
ebe9fb868b test-lib: Show full todo.sh output in verbose mode.
Now that differences in the output (and exit code) are already printed by default, we can make the verbose mode actually "verbose" by including all todo.sh output generated during the test run. This may help in reviewing the tests and for troubleshooting.
By moving the redirection to the output file to test_run_(), all testing-related embellishments have been removed from the command under test itself, resulting in much cleaner test messages.
Additionally, also capture stderr in output. todo.sh itself currently prints everything to stdout (but the die() output probably belongs to stderr), so as of now, that has no consequences, but seems to be more consistent and future-proof.
2012-01-26 09:54:30 +01:00
Ingo Karkat
189779c6de test-lib: Separate function for exit code assertion.
Remove the check for the todo.sh exit code (scripted via "=== N") from the command under test into a separate assertion test_expect_code_and_output. This allows for reporting of expected vs. actual exit code (also in the default non-verbose mode), and unexpected output from the same test is now reported, too.
2012-01-26 09:54:25 +01:00
Ingo Karkat
516f806d58 test-lib: Always print output differences, not just in verbose mode.
Differences in the expected and actual todo.sh output are critical to analyzing the error, so they should always be printed, not just when the -verbose argument is given.

This refactoring moves the test_cmp call from the command under test (as seen from test-lib's perspective) into a new assertion test_expect_output, derived from test_expect_success.
2012-01-26 09:35:38 +01:00
4 changed files with 160 additions and 43 deletions

View File

@@ -1,4 +1,57 @@
#!/bin/sh #!/bin/bash
[ "x$TERM" != "xdumb" ] && (
export TERM &&
[ -t 1 ] &&
tput bold >/dev/null 2>&1 &&
tput setaf 1 >/dev/null 2>&1 &&
tput sgr0 >/dev/null 2>&1
) &&
color=t
case "$1" in
--no-color)
color=; shift ;;
esac
if test -n "$color"; then
say_color () {
(
export TERM
case "$1" in
error) tput bold; tput setaf 1;; # bold red
skip) tput bold; tput setaf 2;; # bold green
pass) tput setaf 2;; # green
info) tput setaf 3;; # brown
*) test -n "$quiet" && return;;
esac
shift
printf "* %s" "$*"
tput sgr0
echo
)
}
else
say_color() {
test -z "$1" && test -n "$quiet" && return
shift
echo "* $*"
}
fi
get_color()
{
# Only use the supplied color if there are actually instances of that
# type, so that a clean test run does not distract the user by the
# appearance of the error highlighting.
if [ ${1:?} -eq 0 ]
then
echo 'info'
else
echo "${2:-info}"
fi
}
fixed=0 fixed=0
success=0 success=0
@@ -27,8 +80,8 @@ do
done <"$file" done <"$file"
done done
printf "%-8s%d\n" fixed $fixed say_color 'info' "$(printf "%-8s%d\n" fixed $fixed)"
printf "%-8s%d\n" success $success say_color "$(get_color "$success" 'pass')" "$(printf "%-8s%d\n" success $success)"
printf "%-8s%d\n" failed $failed say_color "$(get_color "$failed" 'error')" "$(printf "%-8s%d\n" failed $failed)"
printf "%-8s%d\n" broken $broken say_color "$(get_color "$broken" 'error')" "$(printf "%-8s%d\n" broken $broken)"
printf "%-8s%d\n" total $total say_color 'info' "$(printf "%-8s%d\n" total $total)"

View File

@@ -180,7 +180,7 @@ test_failure_ () {
test_failure=$(($test_failure + 1)) test_failure=$(($test_failure + 1))
say_color error "FAIL $test_count: $1" say_color error "FAIL $test_count: $1"
shift shift
echo "$@" | sed -e 's/^/ /' echo "$@"
test "$immediate" = "" || { trap - EXIT; exit 1; } test "$immediate" = "" || { trap - EXIT; exit 1; }
} }
@@ -199,8 +199,9 @@ test_debug () {
} }
test_run_ () { test_run_ () {
eval >&3 2>&4 "$1" eval > output 2>&1 "$1"
eval_ret="$?" eval_ret="$?"
cat >&3 output
return 0 return 0
} }
@@ -260,6 +261,57 @@ test_expect_success () {
echo >&3 "" echo >&3 ""
} }
test_expect_output () {
test "$#" = 2 ||
error "bug in the test script: not 2 parameters to test-expect-output"
if ! test_skip "$@"
then
say >&3 "expecting success and output: $2"
test_run_ "$2"
if [ "$?" = 0 -a "$eval_ret" = 0 ]
then
cmp_output=$(test_cmp expect output)
if [ "$?" = 0 ]
then
test_ok_ "$1"
else
test_failure_ "$@" "
$cmp_output"
fi
else
test_failure_ "$@"
fi
fi
echo >&3 ""
}
test_expect_code_and_output () {
test "$#" = 3 ||
error "bug in the test script: not 3 parameters to test-expect-code-and-output"
if ! test_skip "$@"
then
say >&3 "expecting exit code $1 and output: $3"
test_run_ "$3"
if [ "$?" = 0 -a "$eval_ret" = "$1" ]
then
cmp_output=$(test_cmp expect output)
if [ "$?" = 0 ]
then
test_ok_ "$2"
else
test_failure_ "$2" "$3" "
$cmp_output"
fi
else
cmp_output=$(test_cmp expect output)
test_failure_ "$2" "$3" "
* expected exit code $1, actual ${eval_ret}${cmp_output:+
}${cmp_output}"
fi
fi
echo >&3 ""
}
test_expect_code () { test_expect_code () {
test "$#" = 3 || test "$#" = 3 ||
error "bug in the test script: not 3 parameters to test-expect-code" error "bug in the test script: not 3 parameters to test-expect-code"
@@ -271,7 +323,8 @@ test_expect_code () {
then then
test_ok_ "$2" test_ok_ "$2"
else else
test_failure_ "$@" test_failure_ "$2" "$3" "
* expected exit code $1, actual ${eval_ret}"
fi fi
fi fi
echo >&3 "" echo >&3 ""
@@ -542,9 +595,9 @@ test_todo_session () {
"") "")
if [ ! -z "$cmd" ]; then if [ ! -z "$cmd" ]; then
if [ $status = 0 ]; then if [ $status = 0 ]; then
test_expect_success "$1 $subnum" "$cmd > output && test_cmp expect output" test_expect_output "$1 $subnum" "$cmd"
else else
test_expect_success "$1 $subnum" "$cmd > output ; test \$? = $status && test_cmp expect output" test_expect_code_and_output "$status" "$1 $subnum" "$cmd"
fi fi
subnum=$(($subnum + 1)) subnum=$(($subnum + 1))
@@ -560,9 +613,9 @@ test_todo_session () {
done done
if [ ! -z "$cmd" ]; then if [ ! -z "$cmd" ]; then
if [ $status = 0 ]; then if [ $status = 0 ]; then
test_expect_success "$1 $subnum" "$cmd > output && test_cmp expect output" test_expect_output "$1 $subnum" "$cmd"
else else
test_expect_success "$1 $subnum" "$cmd > output ; test \$? = $status && test_cmp expect output" test_expect_code_and_output "$status" "$1 $subnum" "$cmd"
fi fi
fi fi
} }

View File

@@ -8,7 +8,6 @@ export TODO_DIR=`dirname "$0"`
export TODO_FILE="$TODO_DIR/todo.txt" export TODO_FILE="$TODO_DIR/todo.txt"
export DONE_FILE="$TODO_DIR/done.txt" export DONE_FILE="$TODO_DIR/done.txt"
export REPORT_FILE="$TODO_DIR/report.txt" export REPORT_FILE="$TODO_DIR/report.txt"
export TMP_FILE="$TODO_DIR/todo.tmp"
# You can customize your actions directory location # You can customize your actions directory location
#export TODO_ACTIONS_DIR="$HOME/.todo.actions.d" #export TODO_ACTIONS_DIR="$HOME/.todo.actions.d"

70
todo.sh
View File

@@ -303,12 +303,6 @@ die()
exit 1 exit 1
} }
cleanup()
{
[ -f "$TMP_FILE" ] && rm "$TMP_FILE"
return 0
}
cleaninput() cleaninput()
{ {
# Parameters: When $1 = "for sed", performs additional escaping for use # Parameters: When $1 = "for sed", performs additional escaping for use
@@ -671,7 +665,6 @@ ACTION=${1:-$TODOTXT_DEFAULT_ACTION}
[ -d "$TODO_DIR" ] || die "Fatal Error: $TODO_DIR is not a directory" [ -d "$TODO_DIR" ] || die "Fatal Error: $TODO_DIR is not a directory"
( cd "$TODO_DIR" ) || die "Fatal Error: Unable to cd to $TODO_DIR" ( cd "$TODO_DIR" ) || die "Fatal Error: Unable to cd to $TODO_DIR"
[ -w "$TMP_FILE" ] || echo -n > "$TMP_FILE" || die "Fatal Error: Unable to write to $TMP_FILE"
[ -f "$TODO_FILE" ] || cp /dev/null "$TODO_FILE" [ -f "$TODO_FILE" ] || cp /dev/null "$TODO_FILE"
[ -f "$DONE_FILE" ] || cp /dev/null "$DONE_FILE" [ -f "$DONE_FILE" ] || cp /dev/null "$DONE_FILE"
[ -f "$REPORT_FILE" ] || cp /dev/null "$REPORT_FILE" [ -f "$REPORT_FILE" ] || cp /dev/null "$REPORT_FILE"
@@ -761,13 +754,32 @@ _list() {
## Get our search arguments, if any ## Get our search arguments, if any
shift ## was file name, new $1 is first search term shift ## was file name, new $1 is first search term
## Build the filter. _format "$src" '' "$@"
filter_command=$(filtercommand "${pre_filter_command:-}" "${post_filter_command:-}" "$@")
## Figure out how much padding we need to use if [ $TODOTXT_VERBOSE -gt 0 ]; then
## We need one level of padding for each power of 10 $LINES uses echo "--"
LINES=$( sed -n '$ =' "$src" ) echo "$(getPrefix "$src"): ${NUMTASKS:-0} of ${TOTALTASKS:-0} tasks shown"
PADDING=${#LINES} fi
}
getPadding()
{
## We need one level of padding for each power of 10 $LINES uses.
LINES=$(sed -n '$ =' "${1:-$TODO_FILE}")
printf %s ${#LINES}
}
_format()
{
# Parameters: $1: todo input file; when empty formats stdin
# $2: ITEM# number width; if empty auto-detects from $1 / $TODO_FILE.
# Precondition: None
# Postcondition: $NUMTASKS and $TOTALTASKS contain statistics (unless $TODOTXT_VERBOSE=0).
FILE=$1
shift
## Figure out how much padding we need to use, unless this was passed to us.
PADDING=${1:-$(getPadding "$FILE")}
shift
## Number the file, then run the filter command, ## Number the file, then run the filter command,
## then sort and mangle output some more ## then sort and mangle output some more
@@ -775,7 +787,11 @@ _list() {
TODOTXT_FINAL_FILTER="cat" TODOTXT_FINAL_FILTER="cat"
fi fi
items=$( items=$(
sed = "$src" \ if [ "$FILE" ]; then
sed = "$FILE"
else
sed =
fi \
| sed -e ''' | sed -e '''
N N
s/^/ / s/^/ /
@@ -783,6 +799,9 @@ _list() {
/^[ 0-9]\{1,\} *$/d /^[ 0-9]\{1,\} *$/d
''' '''
) )
## Build and apply the filter.
filter_command=$(filtercommand "${pre_filter_command:-}" "${post_filter_command:-}" "$@")
if [ "${filter_command}" ]; then if [ "${filter_command}" ]; then
filtered_items=$(echo -n "$items" | eval "${filter_command}") filtered_items=$(echo -n "$items" | eval "${filter_command}")
else else
@@ -807,7 +826,7 @@ _list() {
{ {
if (match($0, /^[0-9]+ x /)) { if (match($0, /^[0-9]+ x /)) {
print highlight("COLOR_DONE") $0 highlight("DEFAULT") print highlight("COLOR_DONE") $0 highlight("DEFAULT")
} else if (match($0, /^[0-9]+ \([A-Z]\)[[:space:]]/)) { } else if (match($0, /^[0-9]+ \([A-Z]\) /)) {
clr = highlight("PRI_" substr($0, RSTART + RLENGTH - 3, 1)) clr = highlight("PRI_" substr($0, RSTART + RLENGTH - 3, 1))
print \ print \
(clr ? clr : highlight("PRI_X")) \ (clr ? clr : highlight("PRI_X")) \
@@ -828,16 +847,13 @@ _list() {
if [ $TODOTXT_VERBOSE -gt 0 ]; then if [ $TODOTXT_VERBOSE -gt 0 ]; then
NUMTASKS=$( echo -n "$filtered_items" | sed -n '$ =' ) NUMTASKS=$( echo -n "$filtered_items" | sed -n '$ =' )
TOTALTASKS=$( echo -n "$items" | sed -n '$ =' ) TOTALTASKS=$( echo -n "$items" | sed -n '$ =' )
echo "--"
echo "$(getPrefix "$FILE"): ${NUMTASKS:-0} of ${TOTALTASKS:-0} tasks shown"
fi fi
if [ $TODOTXT_VERBOSE -gt 1 ]; then if [ $TODOTXT_VERBOSE -gt 1 ]; then
echo "TODO DEBUG: Filter Command was: ${filter_command:-cat}" echo "TODO DEBUG: Filter Command was: ${filter_command:-cat}"
fi fi
} }
export -f cleaninput getPrefix getTodo getNewtodo shellquote filtercommand _list die export -f cleaninput getPrefix getTodo getNewtodo shellquote filtercommand _list getPadding _format die
# == HANDLE ACTION == # == HANDLE ACTION ==
action=$( printf "%s\n" "$ACTION" | tr 'A-Z' 'a-z' ) action=$( printf "%s\n" "$ACTION" | tr 'A-Z' 'a-z' )
@@ -855,9 +871,7 @@ then
elif [ -d "$TODO_ACTIONS_DIR" -a -x "$TODO_ACTIONS_DIR/$action" ] elif [ -d "$TODO_ACTIONS_DIR" -a -x "$TODO_ACTIONS_DIR/$action" ]
then then
"$TODO_ACTIONS_DIR/$action" "$@" "$TODO_ACTIONS_DIR/$action" "$@"
status=$? exit $?
cleanup
exit $status
fi fi
## Only run if $action isn't found in .todo.actions.d ## Only run if $action isn't found in .todo.actions.d
@@ -1083,16 +1097,16 @@ case $action in
"listall" | "lsa" ) "listall" | "lsa" )
shift ## Was lsa; new $1 is first search term shift ## Was lsa; new $1 is first search term
cat "$TODO_FILE" "$DONE_FILE" > "$TMP_FILE"
TOTAL=$( sed -n '$ =' "$TODO_FILE" ) TOTAL=$( sed -n '$ =' "$TODO_FILE" )
PADDING=${#TOTAL}
post_filter_command="awk -v TOTAL=$TOTAL -v PADDING=${#TOTAL} '{ \$1 = sprintf(\"%\" PADDING \"d\", (\$1 > TOTAL ? 0 : \$1)); print }' " post_filter_command="awk -v TOTAL=$TOTAL -v PADDING=$PADDING '{ \$1 = sprintf(\"%\" PADDING \"d\", (\$1 > TOTAL ? 0 : \$1)); print }' "
TODOTXT_VERBOSE=0 _list "$TMP_FILE" "$@" cat "$TODO_FILE" "$DONE_FILE" | TODOTXT_VERBOSE=0 _format '' "$PADDING" "$@"
if [ $TODOTXT_VERBOSE -gt 0 ]; then if [ $TODOTXT_VERBOSE -gt 0 ]; then
TDONE=$( sed -n '$ =' "$DONE_FILE" ) TDONE=$( sed -n '$ =' "$DONE_FILE" )
TASKNUM=$(TODOTXT_PLAIN=1 TODOTXT_VERBOSE=0 _list "$TODO_FILE" "$@" | sed -n '$ =') TASKNUM=$(TODOTXT_PLAIN=1 TODOTXT_VERBOSE=0 _format "$TODO_FILE" 1 "$@" | sed -n '$ =')
DONENUM=$(TODOTXT_PLAIN=1 TODOTXT_VERBOSE=0 _list "$DONE_FILE" "$@" | sed -n '$ =') DONENUM=$(TODOTXT_PLAIN=1 TODOTXT_VERBOSE=0 _format "$DONE_FILE" 1 "$@" | sed -n '$ =')
echo "--" echo "--"
echo "$(getPrefix "$TODO_FILE"): ${TASKNUM:-0} of ${TOTAL:-0} tasks shown" echo "$(getPrefix "$TODO_FILE"): ${TASKNUM:-0} of ${TOTAL:-0} tasks shown"
echo "$(getPrefix "$DONE_FILE"): ${DONENUM:-0} of ${TDONE:-0} tasks shown" echo "$(getPrefix "$DONE_FILE"): ${DONENUM:-0} of ${TDONE:-0} tasks shown"
@@ -1284,5 +1298,3 @@ note: PRIORITY must be anywhere from A to Z."
* ) * )
usage;; usage;;
esac esac
cleanup