subcommand 1.0.2 → 1.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/Makefile +29 -0
- data/VERSION +1 -1
- data/lib/subcommand.rb +39 -15
- data/tests/Makefile +2 -0
- data/tests/README +313 -0
- data/tests/aggregate-results.sh +34 -0
- data/tests/recreate.sh +33 -0
- data/tests/rtest2.sh +127 -0
- data/tests/t0001-main.sh +51 -0
- data/tests/t0002-subcomm.sh +21 -0
- data/tests/t0003-inv_comm.sh +53 -0
- data/tests/t0004-subcomm.sh +25 -0
- data/tests/t0005-alias_goo.sh +28 -0
- data/tests/t0006-goo_opt.sh +25 -0
- data/tests/t0007-bar_baz.sh +44 -0
- data/tests/t0008-boo_zoo.sh +44 -0
- data/tests/test-lib.sh +618 -0
- metadata +17 -2
data/Makefile
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#DISTFILES := README.markdown get_serial_number colors.sh todoapp.sh
|
2
|
+
#VERSION := `cat VERSION_FILE`
|
3
|
+
|
4
|
+
all: install
|
5
|
+
|
6
|
+
install:
|
7
|
+
|
8
|
+
rake build && sudo rake install
|
9
|
+
|
10
|
+
#
|
11
|
+
# Testing
|
12
|
+
#
|
13
|
+
TESTS = $(wildcard tests/t[0-9][0-9][0-9][0-9]-*.sh)
|
14
|
+
#TEST_OPTIONS=--verbose
|
15
|
+
|
16
|
+
test-pre-clean:
|
17
|
+
rm -rf tests/test-results "tests/trash directory"*
|
18
|
+
|
19
|
+
aggregate-results: $(TESTS)
|
20
|
+
|
21
|
+
$(TESTS): test-pre-clean
|
22
|
+
-cd tests && sh $(notdir $@) $(TEST_OPTIONS)
|
23
|
+
|
24
|
+
test: aggregate-results
|
25
|
+
tests/aggregate-results.sh tests/test-results/t*-*
|
26
|
+
rm -rf tests/test-results
|
27
|
+
|
28
|
+
# Force tests to get run every time
|
29
|
+
.PHONY: test test-pre-clean aggregate-results $(TESTS)
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.0.
|
1
|
+
1.0.3
|
data/lib/subcommand.rb
CHANGED
@@ -12,12 +12,12 @@
|
|
12
12
|
# @examples
|
13
13
|
# if a program has subcommands foo and baz
|
14
14
|
#
|
15
|
-
# ruby
|
16
|
-
# ruby
|
17
|
-
# ruby
|
18
|
-
# ruby
|
19
|
-
# ruby
|
20
|
-
# ruby
|
15
|
+
# ruby subcommand.rb help
|
16
|
+
# ruby subcommand.rb --help
|
17
|
+
# ruby subcommand.rb help foo
|
18
|
+
# ruby subcommand.rb foo --help
|
19
|
+
# ruby subcommand.rb baz --quiet "some text"
|
20
|
+
# ruby subcommand.rb --verbose foo --force file.zzz
|
21
21
|
#
|
22
22
|
# == STEPS
|
23
23
|
# 1. define global_options (optional)
|
@@ -121,7 +121,7 @@ module Subcommands
|
|
121
121
|
# print aliases
|
122
122
|
unless @aliases.empty?
|
123
123
|
cmdtext << "\n\nAliases: \n"
|
124
|
-
@aliases.each_pair { |name, val| cmdtext << " #{name} - #{val}" }
|
124
|
+
@aliases.each_pair { |name, val| cmdtext << " #{name} - #{val}\n" }
|
125
125
|
end
|
126
126
|
|
127
127
|
cmdtext << "\n\nSee '#{$0} help COMMAND' for more information on a specific command."
|
@@ -136,15 +136,12 @@ module Subcommands
|
|
136
136
|
@global.order!
|
137
137
|
cmd = ARGV.shift
|
138
138
|
if cmd
|
139
|
-
|
139
|
+
$stderr.puts "Command: #{cmd}, args:#{ARGV}, #{@commands.keys} "
|
140
140
|
sc = @commands[cmd]
|
141
141
|
#puts "sc: #{sc}: #{@commands}"
|
142
|
-
#puts "sc: ="+@commands.include?(cmd)
|
143
142
|
unless sc
|
144
143
|
# see if an alias exists
|
145
|
-
|
146
|
-
sc = @commands[alas] if alas
|
147
|
-
cmd = alas if alas
|
144
|
+
sc, cmd = _check_alias cmd
|
148
145
|
end
|
149
146
|
# if valid command parse the args
|
150
147
|
if sc
|
@@ -154,19 +151,23 @@ module Subcommands
|
|
154
151
|
# else if help <command> then print its help GIT style (3)
|
155
152
|
if !ARGV.empty? && cmd == "help"
|
156
153
|
cmd = ARGV.shift
|
157
|
-
|
154
|
+
$stderr.puts " 110 help #{cmd}"
|
158
155
|
sc = @commands[cmd]
|
159
156
|
# if valid command print help, else print global help
|
157
|
+
unless sc
|
158
|
+
sc, cmd = _check_alias cmd
|
159
|
+
end
|
160
160
|
if sc
|
161
161
|
#puts " 111 help #{cmd}"
|
162
162
|
puts sc.call
|
163
163
|
else
|
164
|
-
|
164
|
+
# no help for this command XXX check for alias
|
165
|
+
puts "Invalid command: #{cmd}."
|
165
166
|
puts @global
|
166
167
|
end
|
167
168
|
else
|
168
169
|
# invalid command
|
169
|
-
|
170
|
+
puts "Invalid command: #{cmd}" unless cmd == "help"
|
170
171
|
puts @global
|
171
172
|
end
|
172
173
|
exit 0
|
@@ -174,6 +175,26 @@ module Subcommands
|
|
174
175
|
end
|
175
176
|
return @command_name
|
176
177
|
end
|
178
|
+
def alias_command name, *args
|
179
|
+
@aliases[name.to_s] = args
|
180
|
+
end
|
181
|
+
def _check_alias cmd
|
182
|
+
alas = @aliases[cmd]
|
183
|
+
$stderr.puts "195 alas: #{alas} "
|
184
|
+
if alas
|
185
|
+
case alas
|
186
|
+
when Array
|
187
|
+
cmd = alas.shift
|
188
|
+
$stderr.puts "Array cmd: #{cmd} "
|
189
|
+
ARGV.unshift alas.shift unless alas.empty?
|
190
|
+
$stderr.puts "ARGV #{ARGV} "
|
191
|
+
else
|
192
|
+
cmd = alas
|
193
|
+
end
|
194
|
+
end
|
195
|
+
sc = @commands[cmd] if cmd
|
196
|
+
return sc, cmd
|
197
|
+
end
|
177
198
|
end
|
178
199
|
|
179
200
|
if __FILE__ == $PROGRAM_NAME
|
@@ -205,6 +226,9 @@ if __FILE__ == $PROGRAM_NAME
|
|
205
226
|
options[:quiet] = v
|
206
227
|
end
|
207
228
|
end
|
229
|
+
alias_command :bar, 'baz'
|
230
|
+
alias_command :boo, 'foo', '--force'
|
231
|
+
alias_command :zoo, 'foo', 'ruby'
|
208
232
|
|
209
233
|
# do the parsing.
|
210
234
|
cmd = opt_parse()
|
data/tests/Makefile
ADDED
data/tests/README
ADDED
@@ -0,0 +1,313 @@
|
|
1
|
+
todorb.rb tests
|
2
|
+
===============
|
3
|
+
|
4
|
+
This directory holds test scripts for todorb.rb . The
|
5
|
+
first part of this short document describes how to run the tests
|
6
|
+
and read their output.
|
7
|
+
|
8
|
+
When fixing the tools or adding enhancements, you are strongly
|
9
|
+
encouraged to add tests in this directory to cover what you are
|
10
|
+
trying to fix or enhance. The later part of this short document
|
11
|
+
describes how your test scripts should be organized.
|
12
|
+
|
13
|
+
|
14
|
+
Running Tests
|
15
|
+
-------------
|
16
|
+
|
17
|
+
The easiest way to run tests is to say "make test" from the top-level.
|
18
|
+
This runs all the tests.
|
19
|
+
|
20
|
+
rm -rf tests/test-results "tests/trash directory"*
|
21
|
+
cd tests && sh t0000-config.sh
|
22
|
+
* ok 1: no config file
|
23
|
+
* ok 2: config file (default location 1)
|
24
|
+
* ok 3: config file (default location 2)
|
25
|
+
* ok 4: config file (command line)
|
26
|
+
* ok 5: config file (env variable)
|
27
|
+
* passed all 5 test(s)
|
28
|
+
cd tests && sh t0001-null.sh
|
29
|
+
* ok 1: null ls
|
30
|
+
* passed all 1 test(s)
|
31
|
+
rm -rf tests/test-results
|
32
|
+
|
33
|
+
Or you can run each test individually from command line, like
|
34
|
+
this:
|
35
|
+
|
36
|
+
$ ./t0001-null.sh
|
37
|
+
* ok 1: null ls
|
38
|
+
* passed all 1 test(s)
|
39
|
+
|
40
|
+
You can pass --verbose (or -v), --debug (or -d), and --immediate
|
41
|
+
(or -i) command line argument to the test, or by setting GIT_TEST_OPTS
|
42
|
+
appropriately before running "make".
|
43
|
+
|
44
|
+
--verbose::
|
45
|
+
This makes the test more verbose. Specifically, the
|
46
|
+
command being run and their output if any are also
|
47
|
+
output.
|
48
|
+
|
49
|
+
--debug::
|
50
|
+
This may help the person who is developing a new test.
|
51
|
+
It causes the command defined with test_debug to run.
|
52
|
+
|
53
|
+
--immediate::
|
54
|
+
This causes the test to immediately exit upon the first
|
55
|
+
failed test.
|
56
|
+
|
57
|
+
--long-tests::
|
58
|
+
This causes additional long-running tests to be run (where
|
59
|
+
available), for more exhaustive testing.
|
60
|
+
|
61
|
+
--tee::
|
62
|
+
In addition to printing the test output to the terminal,
|
63
|
+
write it to files named 't/test-results/$TEST_NAME.out'.
|
64
|
+
As the names depend on the tests' file names, it is safe to
|
65
|
+
run the tests with this option in parallel.
|
66
|
+
|
67
|
+
Skipping Tests
|
68
|
+
--------------
|
69
|
+
|
70
|
+
In some environments, certain tests have no way of succeeding
|
71
|
+
due to platform limitation, such as lack of 'unzip' program, or
|
72
|
+
filesystem that do not allow arbitrary sequence of non-NUL bytes
|
73
|
+
as pathnames.
|
74
|
+
|
75
|
+
You should be able to say something like
|
76
|
+
|
77
|
+
$ SKIP_TESTS=t0000.2 sh ./t0000-config.sh
|
78
|
+
|
79
|
+
and even:
|
80
|
+
|
81
|
+
$ SKIP_TESTS='t[0-4]??? t91?? t9200.8' make
|
82
|
+
|
83
|
+
to omit such tests. The value of the environment variable is a
|
84
|
+
SP separated list of patterns that tells which tests to skip,
|
85
|
+
and either can match the "t[0-9]{4}" part to skip the whole
|
86
|
+
test, or t[0-9]{4} followed by ".$number" to say which
|
87
|
+
particular test to skip.
|
88
|
+
|
89
|
+
Note that some tests in the existing test suite rely on previous
|
90
|
+
test item, so you cannot arbitrarily disable one and expect the
|
91
|
+
remainder of test to check what the test originally was intended
|
92
|
+
to check.
|
93
|
+
|
94
|
+
|
95
|
+
Naming Tests
|
96
|
+
------------
|
97
|
+
|
98
|
+
The test files are named as:
|
99
|
+
|
100
|
+
tNNNN-commandname-details.sh
|
101
|
+
|
102
|
+
where N is a decimal digit.
|
103
|
+
|
104
|
+
First digit tells the family:
|
105
|
+
|
106
|
+
0 - the absolute basics and global stuff
|
107
|
+
1 - basic every-day usage
|
108
|
+
2 - add ins
|
109
|
+
|
110
|
+
Second digit tells the particular command we are testing.
|
111
|
+
|
112
|
+
Third digit (optionally) tells the particular switch or group of switches
|
113
|
+
we are testing.
|
114
|
+
|
115
|
+
If you create files under tests/ directory (i.e. here) that is not
|
116
|
+
the top-level test script, never name the file to match the above
|
117
|
+
pattern. The Makefile here considers all such files as the
|
118
|
+
top-level test script and tries to run all of them. A care is
|
119
|
+
especially needed if you are creating a common test library
|
120
|
+
file, similar to test-lib.sh, because such a library file may
|
121
|
+
not be suitable for standalone execution.
|
122
|
+
|
123
|
+
|
124
|
+
Writing Tests
|
125
|
+
-------------
|
126
|
+
|
127
|
+
The test script is written as a shell script. It should start
|
128
|
+
with the standard "#!/bin/sh" with copyright notices, and an
|
129
|
+
assignment to variable 'test_description', like this:
|
130
|
+
|
131
|
+
#!/bin/sh
|
132
|
+
#
|
133
|
+
# Copyright (c) 2005 Junio C Hamano
|
134
|
+
#
|
135
|
+
|
136
|
+
test_description='xxx test (option --frotz)
|
137
|
+
|
138
|
+
This test registers the following structure in the cache
|
139
|
+
and tries to run git-ls-files with option --frotz.'
|
140
|
+
|
141
|
+
|
142
|
+
Source 'test-lib.sh'
|
143
|
+
--------------------
|
144
|
+
|
145
|
+
After assigning test_description, the test script should source
|
146
|
+
test-lib.sh like this:
|
147
|
+
|
148
|
+
. ./test-lib.sh
|
149
|
+
|
150
|
+
This test harness library does the following things:
|
151
|
+
|
152
|
+
- If the script is invoked with command line argument --help
|
153
|
+
(or -h), it shows the test_description and exits.
|
154
|
+
|
155
|
+
- Creates an empty test directory with an empty todo file
|
156
|
+
database and chdir(2) into it. This directory is 't/trash directory'
|
157
|
+
if you must know, but I do not think you care.
|
158
|
+
|
159
|
+
- Defines standard test helper functions for your scripts to
|
160
|
+
use. These functions are designed to make all scripts behave
|
161
|
+
consistently when command line arguments --verbose (or -v),
|
162
|
+
--debug (or -d), and --immediate (or -i) is given.
|
163
|
+
|
164
|
+
|
165
|
+
End with test_done
|
166
|
+
------------------
|
167
|
+
|
168
|
+
Your script will be a sequence of tests, using helper functions
|
169
|
+
from the test harness library. At the end of the script, call
|
170
|
+
'test_done'.
|
171
|
+
|
172
|
+
|
173
|
+
Test harness library
|
174
|
+
--------------------
|
175
|
+
|
176
|
+
There are a handful helper functions defined in the test harness
|
177
|
+
library for your script to use.
|
178
|
+
|
179
|
+
- test_todo_session <message> < transcript
|
180
|
+
|
181
|
+
This takes a single string as a parameter, which is treated
|
182
|
+
as a base description of what is being tested, and then
|
183
|
+
reads from standard input a transcript of todorb.rb commands
|
184
|
+
and expected output. Each command is run in the current
|
185
|
+
test environment and the output is compared with the
|
186
|
+
expected output. (See below for how to generate transcripts
|
187
|
+
easily.)
|
188
|
+
|
189
|
+
- test_tick [interval]
|
190
|
+
|
191
|
+
The test harness has an internal view of time which is
|
192
|
+
implemented by wrapping the date command. This takes a single
|
193
|
+
optional positive integer parameter which indicates how much
|
194
|
+
to advance the internal time. The default value is one day.
|
195
|
+
|
196
|
+
- test_expect_success <message> <script>
|
197
|
+
|
198
|
+
This takes two strings as parameter, and evaluates the
|
199
|
+
<script>. If it yields success, test is considered
|
200
|
+
successful. <message> should state what it is testing.
|
201
|
+
|
202
|
+
Example:
|
203
|
+
|
204
|
+
test_expect_success \
|
205
|
+
'git-write-tree should be able to write an empty tree.' \
|
206
|
+
'tree=$(git-write-tree)'
|
207
|
+
|
208
|
+
- test_expect_failure <message> <script>
|
209
|
+
|
210
|
+
This is NOT the opposite of test_expect_success, but is used
|
211
|
+
to mark a test that demonstrates a known breakage. Unlike
|
212
|
+
the usual test_expect_success tests, which say "ok" on
|
213
|
+
success and "FAIL" on failure, this will say "FIXED" on
|
214
|
+
success and "still broken" on failure. Failures from these
|
215
|
+
tests won't cause -i (immediate) to stop.
|
216
|
+
|
217
|
+
- test_debug <script>
|
218
|
+
|
219
|
+
This takes a single argument, <script>, and evaluates it only
|
220
|
+
when the test script is started with --debug command line
|
221
|
+
argument. This is primarily meant for use during the
|
222
|
+
development of a new test script.
|
223
|
+
|
224
|
+
- test_done
|
225
|
+
|
226
|
+
Your test script must have test_done at the end. Its purpose
|
227
|
+
is to summarize successes and failures in the test script and
|
228
|
+
exit with an appropriate error code.
|
229
|
+
|
230
|
+
|
231
|
+
Generating test transcripts
|
232
|
+
---------------------------
|
233
|
+
|
234
|
+
You can generate test scripts from screenshots as following:
|
235
|
+
|
236
|
+
$ ./testshell.sh
|
237
|
+
|
238
|
+
You'll be in a special test environment with an empty TODO2.txt
|
239
|
+
and the dates and timestamps will be artificially fixed.
|
240
|
+
|
241
|
+
Then the session can be used to make a unit test thanks to
|
242
|
+
test_todo_session, see the existing tests as examples.
|
243
|
+
|
244
|
+
Be careful to replace all occurences of the full path to the test
|
245
|
+
directory by $HOME as testshell.sh will explain you when you execute it
|
246
|
+
otherwise the tests will work properly only on your own computer.
|
247
|
+
|
248
|
+
Don't use "script" as this would log every keystroke, not only what's
|
249
|
+
visible!!
|
250
|
+
|
251
|
+
***NOTE***
|
252
|
+
|
253
|
+
I am not clear how to generate transcripts using the above.
|
254
|
+
The script rtest2.sh actually generates a fully working test case/suite.
|
255
|
+
You may interactively enter actions and the action and result will get
|
256
|
+
written into a test script.
|
257
|
+
-- rkumar 2009-12-21 23:43
|
258
|
+
|
259
|
+
Credits
|
260
|
+
-------
|
261
|
+
|
262
|
+
This test framework was derived from the framework used by
|
263
|
+
git itself, written originally by Junio Hamano and licensed
|
264
|
+
for use under the GPL. It was specialized for todo.txt-cli
|
265
|
+
by Emil Sit and Philippe Teuwen.
|
266
|
+
Further modified for todorb.rb by Rahul Kumar.
|
267
|
+
|
268
|
+
./rtest2.sh --load dataset1.txt "listing"
|
269
|
+
then type commands in there.
|
270
|
+
NOTE that a blank line in output terminates what "expect" file gets so test will fail.
|
271
|
+
|
272
|
+
|
273
|
+
Issues and Drawbacks with this framework
|
274
|
+
----------------------------------------
|
275
|
+
|
276
|
+
This framework uses the standard output of a command as the expected
|
277
|
+
result. This usually means the message reported to the user on success or
|
278
|
+
failure. If we change the message, the test breaks. Similarly, any
|
279
|
+
change to the formatting of a listing breaks *many* tests.
|
280
|
+
|
281
|
+
The actual result in the file is not being checked, only the informational
|
282
|
+
message. To circumvent the problem of recreating test cases whenever output
|
283
|
+
changes, one may pipe the commands from a broken test file to rtest2.sh and create
|
284
|
+
a fresh file.
|
285
|
+
grep '^>>> ' t0001-broken.sh \
|
286
|
+
| sed 's/^>>> *//' \
|
287
|
+
| ./rtest2.sh --load data1.txt "listing"
|
288
|
+
|
289
|
+
Note that any data created on top of the broken test file, is to be saved and passed
|
290
|
+
in the --load parameter to rtest2.sh.
|
291
|
+
|
292
|
+
Date related:
|
293
|
+
-------------
|
294
|
+
This script works fine with shell scripts that use "date" to derive
|
295
|
+
date. There's a nice hack in the bin directorythat is created at runtime
|
296
|
+
in the trash folder. However, my ruby prog does not use "date". It uses
|
297
|
+
Time.now(). So the add method which appends a date appends actual date
|
298
|
+
not the fake date 12345000.
|
299
|
+
|
300
|
+
Fix for ruby programs:
|
301
|
+
t = Time.now
|
302
|
+
ut = ENV["TODO_TEST_TIME"]
|
303
|
+
t = Time.at(ut.to_i) if ut
|
304
|
+
|
305
|
+
Add the line of picking up unix time stamp from env and using that, if it's there.
|
306
|
+
|
307
|
+
Testing for failure returned by method
|
308
|
+
=== 1
|
309
|
+
=== -1
|
310
|
+
prior to output
|
311
|
+
PLEASE be sure to unset any TODO_ env variables prior to test, such as
|
312
|
+
TODO_SHOW_ALL or else tests will fail when its not set!
|
313
|
+
## vim:tw=72:ai:formatoptions=tcqln:nocindent
|