├── README.md ├── gtd └── tests ├── config.test ├── functions.test ├── hms.test ├── options.test ├── run ├── tmp.test └── usage.test /README.md: -------------------------------------------------------------------------------- 1 | # gtd 2 | > A simple shell script for effective time management. 3 | 4 | ## Flags 5 | 6 | -b : start on a break 7 | -c : custom command (defaults to "clear") 8 | -m : toggle MPD on change 9 | -n : notify on change 10 | -s : speak command 11 | -t : show time in tmux status bar 12 | -T : update time in /tmp file 13 | -e : specify time to end at (e.g. 2:45pm today) 14 | -f : specify a configuration file 15 | 16 | ## Usage 17 | 18 | gtd [ -bcmnstTef ] [ work length ] [ break length ] 19 | 20 | Basically it loops infinitely between periods of work and breaks. For example... 21 | 22 | gtd -s 25 23 | 24 | Will start a loop with 25 minute periods of work separated by 5 minute breaks. If you give it the `-b` flag then it starts on a break instead of a working period. 25 | 26 | If you don't specify a break length, the script automatically determines how long breaks should be depending on how long you want your working periods to be. I usually use either 25 or 15 minute working periods depending on my mood. The basic formula it uses is just integer division divided by 5. So 25 minute periods have 5 minute breaks and 15 minute periods have 3 minute breaks. An 11 minute period will have a 2 minute break since 11/5 = 2.2 ≈ 2. 27 | 28 | ## Configuration 29 | 30 | The `-c`, `-m`, `-n`, `-s` and `-t` flags use commands. The `-m` flag uses `mpc toggle` to toggle your mpd client and the `-n` flag uses libnotify to notify when the period ends. The `-s` flag enables `espeak` to speak to you when the period changes. The `-c` flag uses a custom command, which is `clear` by default. The `-t` flag refreshes tmux and updates `/tmp/gtd-tmux` with the time status so that it can be read by tmux. Just read the file somewhere in your `tmux.conf` status bar configuration somewhere. For example: 31 | 32 | set-option -g status-right "#(cat /tmp/gtd-tmux) %a %m/%d %I:%M %P" 33 | 34 | If you'd rather control a temporary file without the use of tmux you can use the `-T` flag which simply updates the time in `/tmp/gtd`. 35 | 36 | If you have the `at` command you can use its syntax to specify an end time with the `-e` flag. For example: 37 | 38 | gtd -e "10:45pm today" 39 | 40 | This will stop the script at 10:45pm today. See `man at` for more syntax options. 41 | 42 | The script is easily modifiable to use custom programs or commands if you'd rather not use the defaults. The one exception to this is the `tmux` integration. For the others, simply set the appropriate variable when starting or in the file `~/.gtdrc`. You can use the `-f` flag if you'd like to use a different file. The configurable variables are provided below. If you use a flag after setting a boolean variable to true it will toggle it, turning it off. 43 | 44 | CUSTOM_CMD="clear" 45 | MPD_CMD="mpc -q toggle" 46 | NOTIFY_CMD="notify-send" 47 | SPEAK_CMD="&>/dev/null espeak" 48 | 49 | DEFAULT_WORK_LENGTH=${DEFAULT_WORK_LENGTH:-15} 50 | NOTIFY_WORK="\"Get things done.\"" 51 | NOTIFY_BREAK="\"Take a break.\"" 52 | SPEAK_WORK="$NOTIFY_WORK" 53 | SPEAK_BREAK="$NOTIFY_BREAK" 54 | 55 | # Set these to "true" to change the default 56 | DO_BREAK= 57 | DO_CUSTOM= 58 | DO_MPD= 59 | DO_NOTIFY= 60 | DO_SPEAK= 61 | DO_TMUX= 62 | DO_TMP_FILE= 63 | 64 | ## MIT License 65 | 66 | Copyright (C) 2013 copyright holder 67 | 68 | Permission is hereby granted, free of charge, to any person obtaining 69 | a copy of this software and associated documentation files (the "Software"), 70 | to deal in the Software without restriction, including without limitation 71 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 72 | and/or sell copies of the Software, and to permit persons to whom the 73 | Software is furnished to do so, subject to the following conditions: 74 | 75 | The above copyright notice and this permission notice shall be included 76 | in all copies or substantial portions of the Software. 77 | 78 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 79 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 80 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 81 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 82 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 83 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 84 | OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 85 | -------------------------------------------------------------------------------- /gtd: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | # Command configuration 6 | CUSTOM_CMD="${CUSTOM_CMD:-"clear"}" 7 | MPD_CMD="${MPD_CMD:-"mpc -q toggle"}" 8 | NOTIFY_CMD="${NOTIFY_CMD:-"notify-send"}" 9 | SPEAK_CMD="${SPEAK_CMD:-"&>/dev/null espeak"}" 10 | 11 | # Setting configuration 12 | DEFAULT_WORK_LENGTH="${DEFAULT_WORK_LENGTH:-15}" 13 | DEFAULT_BREAK_LENGTH="${DEFAULT_BREAK_LENGTH}" 14 | NOTIFY_WORK="${NOTIFY_WORK:-"\"Get things done.\""}" 15 | NOTIFY_BREAK="${NOTIFY_BREAK:-"\"Take a break.\""}" 16 | SPEAK_WORK="${SPEAK_WORK:-"$NOTIFY_WORK"}" 17 | SPEAK_BREAK="${SPEAK_BREAK:-"$NOTIFY_BREAK"}" 18 | 19 | # File configuration 20 | CFG_FILE="${CFG_FILE:-$HOME/.gtdrc}" 21 | 22 | # Check for configuration file and source it 23 | if [[ -e "$CFG_FILE" ]]; then 24 | source "$CFG_FILE" 25 | fi 26 | 27 | # Display help 28 | usage() { 29 | cat << EOF 30 | USAGE: 31 | 32 | gtd [ -bcmnst ] [ work length ] [ break length ] 33 | 34 | OPTIONS: 35 | 36 | -b : start on a break 37 | -c : custom command (defaults to "clear") 38 | -m : toggle MPD on change 39 | -n : notify on change 40 | -s : speak command 41 | -t : show time in tmux status bar 42 | -T : update time in /tmp file 43 | -e : specify time to end at (e.g. 2:45pm today) 44 | 45 | EOF 46 | } 47 | 48 | # Show an error message and print usage 49 | error() { 50 | echo -e "\033[0;31m$1\033[0m" 51 | usage && exit 1 52 | } 53 | 54 | # Set flag options 55 | while getopts "bcmnpstTe:h" opt; do 56 | case "$opt" in 57 | b) [[ -n "$DO_BREAK" ]] && unset DO_BREAK || DO_BREAK=true;; 58 | c) [[ -n "$DO_CUSTOM" ]] && unset DO_CUSTOM || DO_CUSTOM=true;; 59 | m) [[ -n "$DO_MPD" ]] && unset DO_MPD || DO_MPD=true;; 60 | n) [[ -n "$DO_NOTIFY" ]] && unset DO_NOTIFY || DO_NOTIFY=true;; 61 | s) [[ -n "$DO_SPEAK" ]] && unset DO_SPEAK || DO_SPEAK=true;; 62 | t) [[ -n "$DO_TMUX" ]] && unset DO_TMUX || DO_TMUX=true;; 63 | T) [[ -n "$DO_TMP_FILE" ]] && unset DO_TMP_FILE || DO_TMP_FILE=true;; 64 | e) END_TIME="$OPTARG";; 65 | h) usage && exit 0;; 66 | *) error "Invalid flag.";; 67 | esac 68 | done 2>/dev/null 69 | shift "$((OPTIND-1))" 70 | 71 | # Make sure tmux is installed if it is required 72 | if [[ -n "$DO_TMUX" ]]; then 73 | which tmux &>/dev/null || error "This feature requires \`tmux\` to be installed." 74 | fi 75 | 76 | if [[ -n "$END_TIME" ]]; then 77 | # Make sure at is installed if it is required 78 | which at &>/dev/null || error "This feature requires \`at\` to be installed." 79 | 80 | # Kill this process at $END_TIME 81 | at "$END_TIME" <<<"kill $$" 82 | fi 83 | 84 | # Set work length if specified and is a number 85 | if [[ -z "$1" ]]; then 86 | work_length="$DEFAULT_WORK_LENGTH" 87 | elif [[ "$1" =~ [^0-9] ]]; then 88 | error "Work length must be a number of minutes." 89 | else 90 | work_length="$1" 91 | fi 92 | 93 | # Set break length if specified and is a number 94 | if [[ -z "$2" ]]; then 95 | break_length="${DEFAULT_BREAK_LENGTH:-$(( $work_length / 5 ))}" 96 | elif [[ "$2" =~ [^0-9] ]]; then 97 | error "Break length must be a number of minutes." 98 | else 99 | break_length="$2" 100 | fi 101 | 102 | # Show error message for three arguments or more 103 | [[ -n "$3" ]] && error "Only two arguments are allowed." 104 | 105 | # Collect session statistics 106 | total_working_time=0 107 | count=1 108 | 109 | # Displays milliseconds as HH:MM:SS 110 | hms() { 111 | local S="$1" 112 | ((h=S/3600)) 113 | ((m=S%3600/60)) 114 | ((s=S%60)) 115 | printf "%02d:%02d:%02d\n" "$h" "$m" "$s" 116 | } 117 | 118 | # Displays a countdown using hms() while sleeping ("visual" sleep) 119 | vsleep() { 120 | left="$1" 121 | while [[ "$left" -gt 0 ]]; do 122 | hms="$(hms $left)" 123 | 124 | # Updates a temporary file for tmux to read from and refreshes the client 125 | if [[ -n "$DO_TMUX" ]]; then 126 | (echo -ne "$hms |" > /tmp/gtd-tmux) 127 | (tmux refresh-client -S) 128 | fi 129 | 130 | if [[ -n "$DO_TMP_FILE" ]]; then 131 | (echo -ne "$hms" > /tmp/gtd) 132 | fi 133 | 134 | # Prints time information to terminal title bar 135 | if [[ -n "$in_break" ]]; then 136 | printf "\e]1;(brk) $hms\a" 137 | else 138 | printf "\e]1;(gtd) $hms\a" 139 | fi 140 | 141 | # Print the countdown to the terminal and decrement one second 142 | echo -e "$hms $(tput el)\r\c" 143 | sleep 1 144 | left="$(( $left - 1 ))" 145 | done 146 | } 147 | 148 | # Do various tasks based on the user-specified flags 149 | do_options() { 150 | [[ -n "$DO_CUSTOM" ]] && eval "$CUSTOM_CMD" 151 | 152 | if [[ -n "$DO_NOTIFY" ]]; then 153 | if [[ -n "$in_break" ]]; then 154 | eval "$NOTIFY_CMD $NOTIFY_BREAK" 155 | else 156 | eval "$NOTIFY_CMD $NOTIFY_WORK" 157 | fi 158 | fi 159 | 160 | if [[ -n "$DO_SPEAK" ]]; then 161 | if [[ -n "$in_break" ]]; then 162 | eval "$SPEAK_CMD $SPEAK_BREAK" 163 | else 164 | eval "$SPEAK_CMD $SPEAK_WORK" 165 | fi 166 | fi 167 | 168 | [[ -n "$DO_MPD" ]] && (sleep 1 && eval "$MPD_CMD") 169 | 170 | return 0 171 | } 172 | 173 | # Handle CTRL-C interrupt 174 | ctrl_c() { 175 | if [[ -n "$in_break" ]]; then 176 | total="$(hms $(( $total_working_time * 60 )) )" 177 | else 178 | total="$(hms $(( ($total_working_time + $work_length) * 60 - $left )))" 179 | fi 180 | 181 | echo -e "\rTotal working time: $total" 182 | 183 | # Prints total time to terminal title bar 184 | printf "\e]1;(tot) $total\a" 185 | 186 | exit 0 187 | } 188 | 189 | cleanup() { 190 | # Clear the temporary file and refresh tmux when interrupted/terminated 191 | [[ -n "$DO_TMP_FILE" ]] && rm /tmp/gtd 192 | 193 | [[ -n "$DO_TMUX" ]] && (tmux refresh-client -S && rm /tmp/gtd-tmux) 194 | 195 | exit 0 196 | } 197 | 198 | main() { 199 | # Display the initial session settings 200 | clear && echo "$work_length minute sessions with $break_length minute breaks." 201 | 202 | # Loop through work and break cycles 203 | while true; do 204 | # Break period 205 | if [[ -n "$DO_BREAK" ]]; then 206 | echo -e "Break. Total working time: $(hms $(( $total_working_time * 60 )))" 207 | in_break=true && do_options 208 | vsleep "$(( $break_length * 60 ))" 209 | else DO_BREAK=true; fi 210 | 211 | # Work period 212 | echo -e "Period #$count. Total working time: $(hms $(( $total_working_time * 60 )))" 213 | unset in_break && do_options 214 | vsleep "$(( $work_length * 60 ))" 215 | 216 | # Calculate totals 217 | total_working_time="$(( ($total_working_time + $work_length) ))" 218 | count="$(( $count + 1 ))" 219 | done 220 | } 221 | 222 | if [[ -z "$DEBUG" ]]; then 223 | trap ctrl_c INT TERM 224 | trap cleanup EXIT 225 | main 226 | fi 227 | -------------------------------------------------------------------------------- /tests/config.test: -------------------------------------------------------------------------------- 1 | # Configuration should be set {{{1 2 | 3 | source "$MAIN" 4 | 5 | assert "$f CUSTOM_CMD:" "$CUSTOM_CMD" = "clear" 6 | assert "$f MPD_CMD:" "$MPD_CMD" = "mpc -q toggle" 7 | assert "$f NOTIFY_CMD:" "$NOTIFY_CMD" = "notify-send" 8 | assert "$f SPEAK_CMD:" "$SPEAK_CMD" = "&>/dev/null espeak" 9 | assert "$f DEFAULT_WORK_LENGTH:" "$DEFAULT_WORK_LENGTH" = "15" 10 | assert "$f DEFAULT_BREAK_LENGTH:" "$DEFAULT_BREAK_LENGTH" = "" 11 | assert "$f NOTIFY_WORK:" "$NOTIFY_WORK" = "\"Get things done.\"" 12 | assert "$f NOTIFY_BREAK:" "$NOTIFY_BREAK" = "\"Take a break.\"" 13 | assert "$f SPEAK_WORK:" "$SPEAK_WORK" = "\"Get things done.\"" 14 | assert "$f SPEAK_BREAK:" "$SPEAK_BREAK" = "\"Take a break.\"" 15 | assert "$f DO_BREAK:" "-z" "$DO_BREAK" 16 | assert "$f DO_CUSTOM:" "-z" "$DO_CUSTOM" 17 | assert "$f DO_MPD:" "-z" "$DO_MPD" 18 | assert "$f DO_NOTIFY:" "-z" "$DO_NOTIFY" 19 | assert "$f DO_SPEAK:" "-z" "$DO_SPEAK" 20 | assert "$f DO_TMUX:" "-z" "$DO_TMUX" 21 | 22 | # Configuration should allow overwrites {{{1 23 | 24 | CUSTOM_CMD=blah 25 | MPD_CMD=blah 26 | NOTIFY_CMD=blah 27 | SPEAK_CMD=blah 28 | DEFAULT_WORK_LENGTH=1 29 | DEFAULT_BREAK_LENGTH=1 30 | NOTIFY_WORK=blah 31 | NOTIFY_BREAK=blah 32 | SPEAK_WORK=blah 33 | SPEAK_BREAK=blah 34 | DO_BREAK=true 35 | DO_CUSTOM=true 36 | DO_MPD=true 37 | DO_NOTIFY=true 38 | DO_SPEAK=true 39 | DO_TMUX=true 40 | 41 | source "$MAIN" 42 | 43 | assert "$f Overwrite CUSTOM_CMD:" "$CUSTOM_CMD" = "blah" 44 | assert "$f Overwrite MPD_CMD:" "$MPD_CMD" = "blah" 45 | assert "$f Overwrite NOTIFY_CMD:" "$NOTIFY_CMD" = "blah" 46 | assert "$f Overwrite SPEAK_CMD:" "$SPEAK_CMD" = "blah" 47 | assert "$f Overwrite DEFAULT_WORK_LENGTH:" "$DEFAULT_WORK_LENGTH" = "1" 48 | assert "$f Overwrite DEFAULT_BREAK_LENGTH:" "$DEFAULT_BREAK_LENGTH" = "1" 49 | assert "$f Overwrite NOTIFY_WORK:" "$NOTIFY_WORK" = "blah" 50 | assert "$f Overwrite NOTIFY_BREAK:" "$NOTIFY_BREAK" = "blah" 51 | assert "$f Overwrite SPEAK_WORK:" "$SPEAK_WORK" = "blah" 52 | assert "$f Overwrite SPEAK_BREAK:" "$SPEAK_BREAK" = "blah" 53 | assert "$f Overwrite DO_BREAK:" "$DO_BREAK" = true 54 | assert "$f Overwrite DO_CUSTOM:" "$DO_CUSTOM" = true 55 | assert "$f Overwrite DO_MPD:" "$DO_MPD" = true 56 | assert "$f Overwrite DO_NOTIFY:" "$DO_NOTIFY" = true 57 | assert "$f Overwrite DO_SPEAK:" "$DO_SPEAK" = true 58 | assert "$f Overwrite DO_TMUX:" "$DO_TMUX" = true 59 | 60 | # Flags should toggle state {{{1 61 | 62 | source "$MAIN" -bcmnst 63 | 64 | assert "$f Toggle DO_BREAK:" "-z" "$DO_BREAK" 65 | assert "$f Toggle DO_CUSTOM:" "-z" "$DO_CUSTOM" 66 | assert "$f Toggle DO_MPD:" "-z" "$DO_MPD" 67 | assert "$f Toggle DO_NOTIFY:" "-z" "$DO_NOTIFY" 68 | assert "$f Toggle DO_SPEAK:" "-z" "$DO_SPEAK" 69 | assert "$f Toggle DO_TMUX:" "-z" "$DO_TMUX" 70 | 71 | # Configuration file {{{1 72 | echo "CUSTOM_CMD=\"cfg_file\"" > ~/.gtdrc 73 | # echo "CUSTOM_CMD=\"custom_cfg\"" > /tmp/custom_cfg 74 | 75 | # Should read from ~/.gtdrc if exists {{{2 76 | source "$MAIN" 77 | assert "$f Read from ~/.gtdrc:" "$CUSTOM_CMD" = "cfg_file" 78 | 79 | # Should read from other file if specified {{{2 80 | # source "$MAIN" -f /tmp/custom_cfg 81 | # assert "$f Read from specified file:" "$CUSTOM_CMD" = "custom_cfg" 82 | 83 | # cleanup 84 | unset CUSTOM_CMD 85 | rm ~/.gtdrc 86 | 87 | # vim: ft=sh 88 | -------------------------------------------------------------------------------- /tests/functions.test: -------------------------------------------------------------------------------- 1 | # Functions should exit cleanly {{{1 2 | 3 | source "$MAIN" 4 | left=0 5 | 6 | assert "$f usage" "0" "=" "$((usage &>/dev/null); echo $?)" 7 | assert "$f hms 0" "0" "=" "$((hms 0 &>/dev/null); echo $?)" 8 | assert "$f vsleep 0" "0" "=" "$((vsleep 0 &>/dev/null); echo $?)" 9 | assert "$f do_options" "0" "=" "$((do_options &>/dev/null); echo $?)" 10 | assert "$f ctrl_c" "0" "=" "$((ctrl_c &>/dev/null); echo $?)" 11 | assert "$f cleanup" "0" "=" "$((cleanup &>/dev/null); echo $?)" 12 | 13 | assert "$f error" "1" "=" "$((error &>/dev/null); echo $?)" 14 | 15 | # vim: ft=sh 16 | -------------------------------------------------------------------------------- /tests/hms.test: -------------------------------------------------------------------------------- 1 | # hms() should display ms in HH:MM:SS {{{1 2 | 3 | source "$MAIN" 4 | 5 | assert "$f hms 0:" $(hms 0) = "00:00:00" 6 | assert "$f hms 1:" $(hms 1) = "00:00:01" 7 | assert "$f hms 10:" $(hms 10) = "00:00:10" 8 | assert "$f hms 60:" $(hms 60) = "00:01:00" 9 | assert "$f hms 600:" $(hms 600) = "00:10:00" 10 | assert "$f hms 3600:" $(hms 3600) = "01:00:00" 11 | assert "$f hms 36000:" $(hms 36000) = "10:00:00" 12 | 13 | # vim: ft=sh 14 | -------------------------------------------------------------------------------- /tests/options.test: -------------------------------------------------------------------------------- 1 | # CUSTOM_CMD {{{1 2 | CUSTOM_CMD="echo custom_cmd" 3 | 4 | # CUSTOM_CMD should be evaluated if DO_CUSTOM is true {{{2 5 | DO_CUSTOM=true 6 | source "$MAIN" 7 | assert "$f CUSTOM_CMD if DO_CUSTOM true:" "custom_cmd" = "$(do_options)" 8 | 9 | # CUSTOM_CMD should not be evaluated if DO_CUSTOM is false {{{2 10 | unset DO_CUSTOM 11 | source "$MAIN" 12 | assert "$f CUSTOM_CMD if DO_CUSTOM false:" "-z" "$(do_options)" 13 | 14 | unset DO_CUSTOM # }}}1 15 | # NOTIFY_CMD {{{1 16 | NOTIFY_CMD="echo" 17 | NOTIFY_BREAK="notify_break" 18 | NOTIFY_WORK="notify_work" 19 | 20 | # NOTIFY_CMD should be evaluated with NOTIFY_BREAK if DO_NOTIFY and in_break are true {{{2 21 | DO_NOTIFY=true 22 | in_break=true 23 | source "$MAIN" 24 | assert "$f NOTIFY_CMD if DO_NOTIFY/in_break true:" "notify_break" = "$(do_options)" 25 | 26 | # NOTIFY_CMD should be evaluated with NOTIFY_WORK if DO_NOTIFY is true but in_break is false {{{2 27 | DO_NOTIFY=true 28 | unset in_break 29 | source "$MAIN" 30 | assert "$f NOTIFY_CMD if DO_NOTIFY true && in_break false:" "notify_work" = "$(do_options)" 31 | 32 | # NOTIFY_CMD should not be evaluated if DO_NOTIFY is false {{{2 33 | unset DO_NOTIFY 34 | 35 | source "$MAIN" 36 | assert "$f No NOTIFY_CMD if DO_NOTIFY false:" "-z" "$(do_options)" 37 | 38 | unset DO_NOTIFY # }}}1 39 | # SPEAK_CMD {{{1 40 | SPEAK_CMD="echo" 41 | SPEAK_BREAK="speak_break" 42 | SPEAK_WORK="speak_work" 43 | 44 | # SPEAK_CMD should be evaluated with SPEAK_BREAK if DO_SPEAK and in_break are true {{{2 45 | DO_SPEAK=true 46 | in_break=true 47 | source "$MAIN" 48 | assert "$f SPEAK_CMD if DO_SPEAK/in_break true:" "speak_break" = "$(do_options)" 49 | 50 | # SPEAK_CMD should be evaluated with SPEAK_WORK if DO_SPEAK is true but in_break is false {{{2 51 | DO_SPEAK=true 52 | unset in_break 53 | source "$MAIN" 54 | assert "$f SPEAK_CMD if DO_SPEAK true && in_break false:" "speak_work" = "$(do_options)" 55 | 56 | # SPEAK_CMD should not be evaluated if DO_SPEAK is false {{{2 57 | unset DO_SPEAK 58 | 59 | source "$MAIN" 60 | assert "$f No SPEAK_CMD if DO_SPEAK false:" "-z" "$(do_options)" 61 | 62 | unset DO_SPEAK # }}}1 63 | # MPD_CMD {{{1 64 | MPD_CMD="echo yes" 65 | 66 | # MPD_CMD should be evaluated if DO_MPD is true {{{2 67 | DO_MPD=true 68 | source "$MAIN" 69 | assert "$f MPD_CMD if DO_MPD true:" "yes" = "$(do_options)" 70 | 71 | # MPD_CMD should not be evaluated if DO_MPD is false {{{2 72 | unset DO_MPD 73 | source "$MAIN" 74 | assert "$f MPD_CMD if DO_MPD false:" "-z" "$(do_options)" 75 | 76 | unset DO_MPD 77 | 78 | # vim: ft=sh 79 | -------------------------------------------------------------------------------- /tests/run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | MAIN="$(realpath gtd)" 4 | 5 | GREEN='\033[0;32m' 6 | RED='\033[0;31m' 7 | RESET_COLOR='\033[0m' 8 | 9 | pass_cnt=0 10 | fail_cnt=0 11 | 12 | assert() { 13 | if [ "${@:2}" ]; then 14 | pass_cnt="$(( pass_cnt + 1 ))" 15 | echo -ne "${GREEN}.${RESET_COLOR}" 16 | else 17 | fail_cnt="$(( fail_cnt + 1 ))" 18 | echo -ne "${RED}✗${RESET_COLOR}" 19 | errors="$errors\n$*\n" 20 | fi 21 | } 22 | 23 | echo -e "Running tests...\n" 24 | 25 | if [[ -e ~/.gtdrc ]]; then 26 | mv ~/.gtdrc /tmp/old_gtdrc 27 | fi 28 | 29 | for file in "$(dirname $MAIN)/tests/"*.test; do 30 | DEBUG=true f="$(basename $file) =>" source "$file" 31 | done 32 | 33 | if [[ -e /tmp/old_gtdrc || -h /tmp/old_gtdrc ]]; then 34 | mv /tmp/old_gtdrc ~/.gtdrc 35 | fi 36 | 37 | echo -e "\n${RED}${errors}${RESET_COLOR}" 38 | echo -e "Done. $pass_cnt passed. $fail_cnt failed." 39 | -------------------------------------------------------------------------------- /tests/tmp.test: -------------------------------------------------------------------------------- 1 | # The /tmp/gtd file should be managed appropriately {{{1 2 | 3 | source "$MAIN" -T 4 | 5 | # The /tmp/gtd file should be created if it does not exist {{{2 6 | 7 | vsleep 1 >/dev/null 8 | assert "$f create /tmp/gtd" "-e" "/tmp/gtd" 9 | 10 | # The /tmp/gtd file should be deleted on exit {{{2 11 | 12 | (cleanup >/dev/null) 13 | assert "$f remove /tmp/gtd" "!" "-e" "/tmp/gtd" 14 | 15 | # vim: ft=sh 16 | -------------------------------------------------------------------------------- /tests/usage.test: -------------------------------------------------------------------------------- 1 | # Usage should be printed for inappropriate flags {{{1 2 | 3 | source "$MAIN" 4 | 5 | assert "$f -h:" "$(source "$MAIN" -h)" = "$(usage)" 6 | assert "$f -?:" "$(source "$MAIN" -?)" = "$(error "Invalid flag.")" 7 | assert "$f -y:" "$(source "$MAIN" -y)" = "$(error "Invalid flag.")" 8 | 9 | # Usage should be printed for inappropriate arguments {{{1 10 | 11 | assert "$f ?:" "$(source "$MAIN" ?)" = "$(error "Work length must be a number of minutes.")" 12 | assert "$f help:" "$(source "$MAIN" help)" = "$(error "Work length must be a number of minutes.")" 13 | assert "$f 5m:" "$(source "$MAIN" "5m")" = "$(error "Work length must be a number of minutes.")" 14 | assert "$f 5 m:" "$(source "$MAIN" 5 m)" = "$(error "Break length must be a number of minutes.")" 15 | 16 | # Usage should be printed for too many arguments {{{1 17 | 18 | assert "$f 1 2 3:" "$(source "$MAIN" 1 2 3)" = "$(error "Only two arguments are allowed.")" 19 | 20 | # vim: ft=sh 21 | --------------------------------------------------------------------------------