minor README.txt tweaks
[trollop:mainline.git] / test / test_trollop.rb
1 ## test/test_trollop.rb -- unit tests for trollop
2 ## Author::    William Morgan (mailto: wmorgan-trollop@masanjin.net)
3 ## Copyright:: Copyright 2007 William Morgan
4 ## License::   GNU GPL version 2
5
6 require 'test/unit'
7 require 'stringio'
8 require 'trollop'
9
10 module Trollop
11 module Test
12
13 class Trollop < ::Test::Unit::TestCase
14   def setup
15     @p = Parser.new
16   end
17
18   def test_unknown_arguments
19     assert_raise(CommandlineError) { @p.parse(%w(--arg)) }
20     @p.opt "arg"
21     assert_nothing_raised { @p.parse(%w(--arg)) }
22     assert_raise(CommandlineError) { @p.parse(%w(--arg2)) }
23   end
24
25   def test_syntax_check
26     @p.opt "arg"
27
28     assert_nothing_raised { @p.parse(%w(--arg)) }
29     assert_nothing_raised { @p.parse(%w(arg)) }
30     assert_raise(CommandlineError) { @p.parse(%w(---arg)) }
31     assert_raise(CommandlineError) { @p.parse(%w(-arg)) }
32   end
33
34   def test_required_flags_are_required
35     @p.opt "arg", "desc", :required => true
36     @p.opt "arg2", "desc", :required => false
37     @p.opt "arg3", "desc", :required => false
38
39     assert_nothing_raised { @p.parse(%w(--arg)) }
40     assert_nothing_raised { @p.parse(%w(--arg --arg2)) }
41     assert_raise(CommandlineError) { @p.parse(%w(--arg2)) }
42     assert_raise(CommandlineError) { @p.parse(%w(--arg2 --arg3)) }
43   end
44   
45   ## flags that take an argument error unless given one
46   def test_argflags_demand_args
47     @p.opt "goodarg", "desc", :type => String
48     @p.opt "goodarg2", "desc", :type => String
49
50     assert_nothing_raised { @p.parse(%w(--goodarg goat)) }
51     assert_raise(CommandlineError) { @p.parse(%w(--goodarg --goodarg2 goat)) }
52     assert_raise(CommandlineError) { @p.parse(%w(--goodarg)) }
53   end
54
55   ## flags that don't take arguments ignore them
56   def test_arglessflags_refuse_args
57     @p.opt "goodarg"
58     @p.opt "goodarg2"
59     assert_nothing_raised { @p.parse(%w(--goodarg)) }
60     assert_nothing_raised { @p.parse(%w(--goodarg --goodarg2)) }
61     opts = @p.parse %w(--goodarg a)
62     assert_equal true, opts["goodarg"]
63     assert_equal ["a"], @p.leftovers
64   end
65
66   ## flags that require args of a specific type refuse args of other
67   ## types
68   def test_typed_args_refuse_args_of_other_types
69     assert_nothing_raised { @p.opt "goodarg", "desc", :type => :int }
70     assert_raise(ArgumentError) { @p.opt "badarg", "desc", :type => :asdf }
71
72     assert_nothing_raised { @p.parse(%w(--goodarg 3)) }
73     assert_raise(CommandlineError) { @p.parse(%w(--goodarg 4.2)) }
74     assert_raise(CommandlineError) { @p.parse(%w(--goodarg hello)) }
75   end
76
77   ## type is correctly derived from :default
78   def test_type_correctly_derived_from_default
79     assert_raise(ArgumentError) { @p.opt "badarg", "desc", :default => [] }
80
81     opts = nil
82
83     # single arg: int
84     assert_nothing_raised { @p.opt "argsi", "desc", :default => 0 }
85     assert_nothing_raised { opts = @p.parse("--") }
86     assert_equal 0, opts["argsi"]
87     assert_nothing_raised { opts = @p.parse(%w(--argsi 4)) }
88     assert_equal 4, opts["argsi"]
89     assert_raise(CommandlineError) { @p.parse(%w(--argsi 4.2)) }
90     assert_raise(CommandlineError) { @p.parse(%w(--argsi hello)) }
91
92     # single arg: float
93     assert_nothing_raised { @p.opt "argsf", "desc", :default => 3.14 }
94     assert_nothing_raised { opts = @p.parse("--") }
95     assert_equal 3.14, opts["argsf"]
96     assert_nothing_raised { opts = @p.parse(%w(--argsf 2.41)) }
97     assert_equal 2.41, opts["argsf"]
98     assert_nothing_raised { opts = @p.parse(%w(--argsf 2)) }
99     assert_equal 2, opts["argsf"]
100     assert_raise(CommandlineError) { @p.parse(%w(--argsf hello)) }
101
102     # single arg: date
103     date = Date.today
104     assert_nothing_raised { @p.opt "argsd", "desc", :default => date }
105     assert_nothing_raised { opts = @p.parse("--") }
106     assert_equal Date.today, opts["argsd"]
107     assert_nothing_raised { opts = @p.parse(['--argsd', 'Jan 4, 2007']) }
108     assert_equal Date.civil(2007, 1, 4), opts["argsd"]
109     assert_raise(CommandlineError) { @p.parse(%w(--argsd hello)) }
110
111     # single arg: string
112     assert_nothing_raised { @p.opt "argss", "desc", :default => "foobar" }
113     assert_nothing_raised { opts = @p.parse("--") }
114     assert_equal "foobar", opts["argss"]
115     assert_nothing_raised { opts = @p.parse(%w(--argss 2.41)) }
116     assert_equal "2.41", opts["argss"]
117     assert_nothing_raised { opts = @p.parse(%w(--argss hello)) }
118     assert_equal "hello", opts["argss"]
119
120     # multi args: ints
121     assert_nothing_raised { @p.opt "argmi", "desc", :default => [3, 5] }
122     assert_nothing_raised { opts = @p.parse("--") }
123     assert_equal [3, 5], opts["argmi"]
124     assert_nothing_raised { opts = @p.parse(%w(--argmi 4)) }
125     assert_equal [4], opts["argmi"]
126     assert_raise(CommandlineError) { @p.parse(%w(--argmi 4.2)) }
127     assert_raise(CommandlineError) { @p.parse(%w(--argmi hello)) }
128
129     # multi args: floats
130     assert_nothing_raised { @p.opt "argmf", "desc", :default => [3.34, 5.21] }
131     assert_nothing_raised { opts = @p.parse("--") }
132     assert_equal [3.34, 5.21], opts["argmf"]
133     assert_nothing_raised { opts = @p.parse(%w(--argmf 2)) }
134     assert_equal [2], opts["argmf"]
135     assert_nothing_raised { opts = @p.parse(%w(--argmf 4.0)) }
136     assert_equal [4.0], opts["argmf"]
137     assert_raise(CommandlineError) { @p.parse(%w(--argmf hello)) }
138
139     # multi args: dates
140     dates = [Date.today, Date.civil(2007, 1, 4)]
141     assert_nothing_raised { @p.opt "argmd", "desc", :default => dates }
142     assert_nothing_raised { opts = @p.parse("--") }
143     assert_equal dates, opts["argmd"]
144     assert_nothing_raised { opts = @p.parse(['--argmd', 'Jan 4, 2007']) }
145     assert_equal [Date.civil(2007, 1, 4)], opts["argmd"]
146     assert_raise(CommandlineError) { @p.parse(%w(--argmd hello)) }
147
148     # multi args: strings
149     assert_nothing_raised { @p.opt "argmst", "desc", :default => %w(hello world) }
150     assert_nothing_raised { opts = @p.parse("--") }
151     assert_equal %w(hello world), opts["argmst"]
152     assert_nothing_raised { opts = @p.parse(%w(--argmst 3.4)) }
153     assert_equal ["3.4"], opts["argmst"]
154     assert_nothing_raised { opts = @p.parse(%w(--argmst goodbye)) }
155     assert_equal ["goodbye"], opts["argmst"]
156   end    
157
158   ## :type and :default must match if both are specified
159   def test_type_and_default_must_match
160     assert_raise(ArgumentError) { @p.opt "badarg", "desc", :type => :int, :default => "hello" }
161     assert_raise(ArgumentError) { @p.opt "badarg2", "desc", :type => :String, :default => 4 }
162     assert_raise(ArgumentError) { @p.opt "badarg2", "desc", :type => :String, :default => ["hi"] }
163     assert_raise(ArgumentError) { @p.opt "badarg2", "desc", :type => :ints, :default => [3.14] }
164
165     assert_nothing_raised { @p.opt "argsi", "desc", :type => :int, :default => 4 }
166     assert_nothing_raised { @p.opt "argsf", "desc", :type => :float, :default => 3.14 }
167     assert_nothing_raised { @p.opt "argsd", "desc", :type => :date, :default => Date.today }
168     assert_nothing_raised { @p.opt "argss", "desc", :type => :string, :default => "yo" }
169     assert_nothing_raised { @p.opt "argmi", "desc", :type => :ints, :default => [4] }
170     assert_nothing_raised { @p.opt "argmf", "desc", :type => :floats, :default => [3.14] }
171     assert_nothing_raised { @p.opt "argmd", "desc", :type => :dates, :default => [Date.today] }
172     assert_nothing_raised { @p.opt "argmst", "desc", :type => :strings, :default => ["yo"] }
173   end
174
175   def test_long_detects_bad_names
176     assert_nothing_raised { @p.opt "goodarg", "desc", :long => "none" }
177     assert_nothing_raised { @p.opt "goodarg2", "desc", :long => "--two" }
178     assert_raise(ArgumentError) { @p.opt "badarg", "desc", :long => "" }
179     assert_raise(ArgumentError) { @p.opt "badarg2", "desc", :long => "--" }
180     assert_raise(ArgumentError) { @p.opt "badarg3", "desc", :long => "-one" }
181     assert_raise(ArgumentError) { @p.opt "badarg4", "desc", :long => "---toomany" }
182   end
183
184   def test_short_detects_bad_names
185     assert_nothing_raised { @p.opt "goodarg", "desc", :short => "a" }
186     assert_nothing_raised { @p.opt "goodarg2", "desc", :short => "-b" }
187     assert_raise(ArgumentError) { @p.opt "badarg", "desc", :short => "" }
188     assert_raise(ArgumentError) { @p.opt "badarg2", "desc", :short => "-ab" }
189     assert_raise(ArgumentError) { @p.opt "badarg3", "desc", :short => "--t" }
190   end
191
192   def test_short_names_created_automatically
193     @p.opt "arg"
194     @p.opt "arg2"
195     @p.opt "arg3"
196     opts = @p.parse %w(-a -g)
197     assert_equal true, opts["arg"]
198     assert_equal false, opts["arg2"]
199     assert_equal true, opts["arg3"]
200   end
201
202   def test_short_autocreation_skips_dashes_and_numbers
203     @p.opt :arg # auto: a
204     @p.opt :arg_potato # auto: r
205     @p.opt :arg_muffin # auto: g
206     assert_nothing_raised { @p.opt :arg_daisy } # auto: d (not _)!
207     assert_nothing_raised { @p.opt :arg_r2d2f } # auto: f (not 2)!
208
209     opts = @p.parse %w(-f -d)
210     assert_equal true, opts[:arg_daisy]
211     assert_equal true, opts[:arg_r2d2f]
212     assert_equal false, opts[:arg]
213     assert_equal false, opts[:arg_potato]
214     assert_equal false, opts[:arg_muffin]
215   end
216
217   def test_short_autocreation_is_ok_with_running_out_of_chars
218     @p.opt :arg1 # auto: a
219     @p.opt :arg2 # auto: r
220     @p.opt :arg3 # auto: g
221     @p.opt :arg4 # auto: uh oh!
222     assert_nothing_raised { @p.parse [] }
223   end
224
225   def test_short_can_be_nothing
226     assert_nothing_raised do
227       @p.opt "arg", "desc", :short => :none
228       @p.parse []
229     end
230
231     sio = StringIO.new "w"
232     @p.educate sio
233     assert sio.string =~ /--arg:\s+desc/
234
235     assert_raise(CommandlineError) { @p.parse %w(-a) }
236   end
237
238   ## two args can't have the same name
239   def test_conflicting_names_are_detected
240     assert_nothing_raised { @p.opt "goodarg" }
241     assert_raise(ArgumentError) { @p.opt "goodarg" }
242   end
243
244   ## two args can't have the same :long
245   def test_conflicting_longs_detected
246     assert_nothing_raised { @p.opt "goodarg", "desc", :long => "--goodarg" }
247     assert_raise(ArgumentError) { @p.opt "badarg", "desc", :long => "--goodarg" }
248   end  
249
250   ## two args can't have the same :short
251   def test_conflicting_shorts_detected
252     assert_nothing_raised { @p.opt "goodarg", "desc", :short => "-g" }
253     assert_raise(ArgumentError) { @p.opt "badarg", "desc", :short => "-g" }
254   end  
255
256   def test_flag_defaults
257     @p.opt "defaultfalse", "desc"
258     @p.opt "defaulttrue", "desc", :default => true
259     opts = @p.parse []
260     assert_equal false, opts["defaultfalse"]
261     assert_equal true, opts["defaulttrue"]
262
263     opts = @p.parse %w(--defaultfalse --defaulttrue)
264     assert_equal true, opts["defaultfalse"]
265     assert_equal false, opts["defaulttrue"]
266   end
267
268   def test_special_flags_work
269     @p.version "asdf fdas"
270     assert_raise(VersionNeeded) { @p.parse(%w(-v)) }
271     assert_raise(HelpNeeded) { @p.parse(%w(-h)) }
272   end
273
274   def test_short_options_combine
275     @p.opt :arg1, "desc", :short => "a"
276     @p.opt :arg2, "desc", :short => "b"
277     @p.opt :arg3, "desc", :short => "c", :type => :int
278
279     opts = nil
280     assert_nothing_raised { opts = @p.parse %w(-a -b) }
281     assert_equal true, opts[:arg1]
282     assert_equal true, opts[:arg2]
283     assert_equal nil, opts[:arg3]
284
285     assert_nothing_raised { opts = @p.parse %w(-ab) }
286     assert_equal true, opts[:arg1]
287     assert_equal true, opts[:arg2]
288     assert_equal nil, opts[:arg3]
289
290     assert_nothing_raised { opts = @p.parse %w(-ac 4 -b) }
291     assert_equal true, opts[:arg1]
292     assert_equal true, opts[:arg2]
293     assert_equal 4, opts[:arg3]
294
295     assert_raises(CommandlineError) { @p.parse %w(-cab 4) }
296     assert_raises(CommandlineError) { @p.parse %w(-cba 4) }
297   end
298
299   def test_version_only_appears_if_set
300     @p.opt "arg"
301     assert_raise(CommandlineError) { @p.parse %w(-v) }
302     @p.version "trollop 1.2.3.4"
303     assert_raise(VersionNeeded) { @p.parse %w(-v) }
304   end
305
306   def test_doubledash_ends_option_processing
307     @p.opt :arg1, "desc", :short => "a", :default => 0
308     @p.opt :arg2, "desc", :short => "b", :default => 0
309     opts = nil
310     assert_nothing_raised { opts = @p.parse %w(-- -a 3 -b 2) }
311     assert_equal opts[:arg1], 0
312     assert_equal opts[:arg2], 0
313     assert_equal %w(-a 3 -b 2), @p.leftovers
314     assert_nothing_raised { opts = @p.parse %w(-a 3 -- -b 2) }
315     assert_equal opts[:arg1], 3
316     assert_equal opts[:arg2], 0
317     assert_equal %w(-b 2), @p.leftovers
318     assert_nothing_raised { opts = @p.parse %w(-a 3 -b 2 --) }
319     assert_equal opts[:arg1], 3
320     assert_equal opts[:arg2], 2
321     assert_equal %w(), @p.leftovers
322   end
323
324   def test_wrap
325     assert_equal [""], @p.wrap("")
326     assert_equal ["a"], @p.wrap("a")
327     assert_equal ["one two", "three"], @p.wrap("one two three", :width => 8)
328     assert_equal ["one two three"], @p.wrap("one two three", :width => 80)
329     assert_equal ["one", "two", "three"], @p.wrap("one two three", :width => 3)
330     assert_equal ["onetwothree"], @p.wrap("onetwothree", :width => 3)
331     assert_equal [
332       "Test is an awesome program that does something very, very important.",
333       "",
334       "Usage:",
335       "  test [options] <filenames>+",
336       "where [options] are:"], @p.wrap(<<EOM, :width => 100)
337 Test is an awesome program that does something very, very important.
338
339 Usage:
340   test [options] <filenames>+
341 where [options] are:
342 EOM
343   end
344
345   def test_floating_point_formatting
346     @p.opt :arg, "desc", :type => :float, :short => "f"
347     opts = nil
348     assert_nothing_raised { opts = @p.parse %w(-f 1) }
349     assert_equal 1.0, opts[:arg]
350     assert_nothing_raised { opts = @p.parse %w(-f 1.0) }
351     assert_equal 1.0, opts[:arg]
352     assert_nothing_raised { opts = @p.parse %w(-f 0.1) }
353     assert_equal 0.1, opts[:arg]
354     assert_nothing_raised { opts = @p.parse %w(-f .1) }
355     assert_equal 0.1, opts[:arg]
356     assert_nothing_raised { opts = @p.parse %w(-f .99999999999999999999) }
357     assert_equal 1.0, opts[:arg]
358     assert_nothing_raised { opts = @p.parse %w(-f -1) }
359     assert_equal(-1.0, opts[:arg])
360     assert_nothing_raised { opts = @p.parse %w(-f -1.0) }
361     assert_equal(-1.0, opts[:arg])
362     assert_nothing_raised { opts = @p.parse %w(-f -0.1) }
363     assert_equal(-0.1, opts[:arg])
364     assert_nothing_raised { opts = @p.parse %w(-f -.1) }
365     assert_equal(-0.1, opts[:arg])
366     assert_raises(CommandlineError) { @p.parse %w(-f a) }
367     assert_raises(CommandlineError) { @p.parse %w(-f 1a) }
368     assert_raises(CommandlineError) { @p.parse %w(-f 1.a) }
369     assert_raises(CommandlineError) { @p.parse %w(-f a.1) }
370     assert_raises(CommandlineError) { @p.parse %w(-f 1.0.0) }
371     assert_raises(CommandlineError) { @p.parse %w(-f .) }
372     assert_raises(CommandlineError) { @p.parse %w(-f -.) }
373   end
374
375   def test_date_formatting
376     @p.opt :arg, "desc", :type => :date, :short => 'd'
377     opts = nil
378     assert_nothing_raised { opts = @p.parse(['-d', 'Jan 4, 2007']) }
379     assert_equal Date.civil(2007, 1, 4), opts[:arg]
380     begin
381       require 'chronic'
382       assert_nothing_raised { opts = @p.parse(['-d', 'today']) }
383       assert_equal Date.today, opts[:arg]
384     rescue LoadError
385       # chronic is not available
386     end
387   end
388
389   def test_short_options_cant_be_numeric
390     assert_raises(ArgumentError) { @p.opt :arg, "desc", :short => "-1" }
391     @p.opt :a1b, "desc"
392     @p.opt :a2b, "desc"
393     assert_not_equal "2", @p.specs[:a2b][:short]
394   end
395
396   def test_short_options_can_be_weird
397     assert_nothing_raised { @p.opt :arg1, "desc", :short => "#" }
398     assert_nothing_raised { @p.opt :arg2, "desc", :short => "." }
399     assert_raises(ArgumentError) { @p.opt :arg3, "desc", :short => "-" }
400   end
401
402   def test_options_cant_be_set_multiple_times_if_not_specified
403     @p.opt :arg, "desc", :short => "-x"
404     assert_nothing_raised { @p.parse %w(-x) }
405     assert_raises(CommandlineError) { @p.parse %w(-x -x) }
406     assert_raises(CommandlineError) { @p.parse %w(-xx) }
407   end
408
409   def test_options_can_be_set_multiple_times_if_specified
410     assert_nothing_raised do
411       @p.opt :arg, "desc", :short => "-x", :multi => true
412     end
413     assert_nothing_raised { @p.parse %w(-x) }
414     assert_nothing_raised { @p.parse %w(-x -x) }
415     assert_nothing_raised { @p.parse %w(-xx) }
416   end
417
418   def test_short_options_with_multiple_options
419     opts = nil
420
421     assert_nothing_raised do
422        @p.opt :xarg, "desc", :short => "-x", :type => String, :multi => true
423     end
424     assert_nothing_raised { opts = @p.parse %w(-x a -x b) }
425     assert_equal %w(a b), opts[:xarg]
426     assert_equal [], @p.leftovers
427   end
428
429   def short_options_with_multiple_options_does_not_affect_flags_type
430     opts = nil
431
432     assert_nothing_raised do
433       @p.opt :xarg, "desc", :short => "-x", :type => :flag, :multi => true
434     end
435
436     assert_nothing_raised { opts = @p.parse %w(-x a) }
437     assert_equal true, opts[:xarg]
438     assert_equal %w(a), @p.leftovers
439
440     assert_nothing_raised { opts = @p.parse %w(-x a -x b) }
441     assert_equal true, opts[:xarg]
442     assert_equal %w(a b), @p.leftovers
443
444     assert_nothing_raised { opts = @p.parse %w(-xx a -x b) }
445     assert_equal true, opts[:xarg]
446     assert_equal %w(a b), @p.leftovers
447   end
448
449   def test_short_options_with_multiple_arguments
450     opts = nil
451
452     @p.opt :xarg, "desc", :type => :ints
453     assert_nothing_raised { opts = @p.parse %w(-x 3 4 0) }
454     assert_equal [3, 4, 0], opts[:xarg]
455     assert_equal [], @p.leftovers
456
457     @p.opt :yarg, "desc", :type => :floats
458     assert_nothing_raised { opts = @p.parse %w(-y 3.14 4.21 0.66) }
459     assert_equal [3.14, 4.21, 0.66], opts[:yarg]
460     assert_equal [], @p.leftovers
461
462     @p.opt :zarg, "desc", :type => :strings
463     assert_nothing_raised { opts = @p.parse %w(-z a b c) }
464     assert_equal %w(a b c), opts[:zarg]
465     assert_equal [], @p.leftovers
466   end
467
468   def test_short_options_with_multiple_options_and_arguments
469     opts = nil
470
471     @p.opt :xarg, "desc", :type => :ints, :multi => true
472     assert_nothing_raised { opts = @p.parse %w(-x 3 4 5 -x 6 7) }
473     assert_equal [[3, 4, 5], [6, 7]], opts[:xarg]
474     assert_equal [], @p.leftovers
475
476     @p.opt :yarg, "desc", :type => :floats, :multi => true
477     assert_nothing_raised { opts = @p.parse %w(-y 3.14 4.21 5.66 -y 6.99 7.01) }
478     assert_equal [[3.14, 4.21, 5.66], [6.99, 7.01]], opts[:yarg]
479     assert_equal [], @p.leftovers
480
481     @p.opt :zarg, "desc", :type => :strings, :multi => true
482     assert_nothing_raised { opts = @p.parse %w(-z a b c -z d e) }
483     assert_equal [%w(a b c), %w(d e)], opts[:zarg]
484     assert_equal [], @p.leftovers
485   end
486
487   def test_combined_short_options_with_multiple_arguments
488     @p.opt :arg1, "desc", :short => "a"
489     @p.opt :arg2, "desc", :short => "b"
490     @p.opt :arg3, "desc", :short => "c", :type => :ints
491     @p.opt :arg4, "desc", :short => "d", :type => :floats
492
493     opts = nil
494
495     assert_nothing_raised { opts = @p.parse %w(-abc 4 6 9) }
496     assert_equal true, opts[:arg1]
497     assert_equal true, opts[:arg2]
498     assert_equal [4, 6, 9], opts[:arg3]
499
500     assert_nothing_raised { opts = @p.parse %w(-ac 4 6 9 -bd 3.14 2.41) }
501     assert_equal true, opts[:arg1]
502     assert_equal true, opts[:arg2]
503     assert_equal [4, 6, 9], opts[:arg3]
504     assert_equal [3.14, 2.41], opts[:arg4]
505
506     assert_raises(CommandlineError) { opts = @p.parse %w(-abcd 3.14 2.41) }
507   end
508
509   def test_long_options_with_multiple_options
510     @p.opt :xarg, "desc", :type => String, :multi => true
511     opts = nil
512     assert_nothing_raised { opts = @p.parse %w(--xarg=a --xarg=b) }
513     assert_equal %w(a b), opts[:xarg]
514     assert_equal [], @p.leftovers
515     assert_nothing_raised { opts = @p.parse %w(--xarg a --xarg b) }
516     assert_equal %w(a b), opts[:xarg]
517     assert_equal [], @p.leftovers
518   end
519
520   def test_long_options_with_multiple_arguments
521     opts = nil
522
523     @p.opt :xarg, "desc", :type => :ints
524     assert_nothing_raised { opts = @p.parse %w(--xarg 3 2 5) }
525     assert_equal [3, 2, 5], opts[:xarg]
526     assert_equal [], @p.leftovers
527     assert_nothing_raised { opts = @p.parse %w(--xarg=3) }
528     assert_equal [3], opts[:xarg]
529     assert_equal [], @p.leftovers
530
531     @p.opt :yarg, "desc", :type => :floats
532     assert_nothing_raised { opts = @p.parse %w(--yarg 3.14 2.41 5.66) }
533     assert_equal [3.14, 2.41, 5.66], opts[:yarg]
534     assert_equal [], @p.leftovers
535     assert_nothing_raised { opts = @p.parse %w(--yarg=3.14) }
536     assert_equal [3.14], opts[:yarg]
537     assert_equal [], @p.leftovers
538
539     @p.opt :zarg, "desc", :type => :strings
540     assert_nothing_raised { opts = @p.parse %w(--zarg a b c) }
541     assert_equal %w(a b c), opts[:zarg]
542     assert_equal [], @p.leftovers
543     assert_nothing_raised { opts = @p.parse %w(--zarg=a) }
544     assert_equal %w(a), opts[:zarg]
545     assert_equal [], @p.leftovers
546   end
547
548   def test_long_options_with_multiple_options_and_arguments
549     opts = nil
550
551     @p.opt :xarg, "desc", :type => :ints, :multi => true
552     assert_nothing_raised { opts = @p.parse %w(--xarg 3 2 5 --xarg 2 1) }
553     assert_equal [[3, 2, 5], [2, 1]], opts[:xarg]
554     assert_equal [], @p.leftovers
555     assert_nothing_raised { opts = @p.parse %w(--xarg=3 --xarg=2) }
556     assert_equal [[3], [2]], opts[:xarg]
557     assert_equal [], @p.leftovers
558
559     @p.opt :yarg, "desc", :type => :floats, :multi => true
560     assert_nothing_raised { opts = @p.parse %w(--yarg 3.14 2.72 5 --yarg 2.41 1.41) }
561     assert_equal [[3.14, 2.72, 5], [2.41, 1.41]], opts[:yarg]
562     assert_equal [], @p.leftovers
563     assert_nothing_raised { opts = @p.parse %w(--yarg=3.14 --yarg=2.41) }
564     assert_equal [[3.14], [2.41]], opts[:yarg]
565     assert_equal [], @p.leftovers
566
567     @p.opt :zarg, "desc", :type => :strings, :multi => true
568     assert_nothing_raised { opts = @p.parse %w(--zarg a b c --zarg d e) }
569     assert_equal [%w(a b c), %w(d e)], opts[:zarg]
570     assert_equal [], @p.leftovers
571     assert_nothing_raised { opts = @p.parse %w(--zarg=a --zarg=d) }
572     assert_equal [%w(a), %w(d)], opts[:zarg]
573     assert_equal [], @p.leftovers
574   end
575
576   def test_long_options_also_take_equals
577     @p.opt :arg, "desc", :long => "arg", :type => String, :default => "hello"
578     opts = nil
579     assert_nothing_raised { opts = @p.parse %w() }
580     assert_equal "hello", opts[:arg]
581     assert_nothing_raised { opts = @p.parse %w(--arg goat) }
582     assert_equal "goat", opts[:arg]
583     assert_nothing_raised { opts = @p.parse %w(--arg=goat) }
584     assert_equal "goat", opts[:arg]
585     ## actually, this next one is valid. empty string for --arg, and goat as a
586     ## leftover.
587     ## assert_raises(CommandlineError) { opts = @p.parse %w(--arg= goat) }
588   end
589
590   def test_auto_generated_long_names_convert_underscores_to_hyphens
591     @p.opt :hello_there
592     assert_equal "hello-there", @p.specs[:hello_there][:long]
593   end
594
595   def test_arguments_passed_through_block
596     @goat = 3
597     boat = 4
598     Parser.new(@goat) do |goat|
599       boat = goat
600     end
601     assert_equal @goat, boat
602   end
603
604   def test_help_has_default_banner
605     @p = Parser.new
606     sio = StringIO.new "w"
607     @p.parse []
608     @p.educate sio
609     help = sio.string.split "\n"
610     assert help[0] =~ /options/i
611     assert_equal 2, help.length # options, then -h
612
613     @p = Parser.new
614     @p.version "my version"
615     sio = StringIO.new "w"
616     @p.parse []
617     @p.educate sio
618     help = sio.string.split "\n"
619     assert help[0] =~ /my version/i
620     assert_equal 4, help.length # version, options, -h, -v
621
622     @p = Parser.new
623     @p.banner "my own banner"
624     sio = StringIO.new "w"
625     @p.parse []
626     @p.educate sio
627     help = sio.string.split "\n"
628     assert help[0] =~ /my own banner/i
629     assert_equal 2, help.length # banner, -h
630   end
631
632   def test_help_preserves_positions
633     @p.opt :zzz, "zzz"
634     @p.opt :aaa, "aaa"
635     sio = StringIO.new "w"
636     @p.educate sio
637
638     help = sio.string.split "\n"
639     assert help[1] =~ /zzz/
640     assert help[2] =~ /aaa/
641   end
642
643   def test_version_and_help_short_args_can_be_overridden
644     @p.opt :verbose, "desc", :short => "-v"
645     @p.opt :hello, "desc", :short => "-h"
646     @p.version "version"
647
648     assert_nothing_raised { @p.parse(%w(-v)) }
649     assert_raises(VersionNeeded) { @p.parse(%w(--version)) }
650     assert_nothing_raised { @p.parse(%w(-h)) }
651     assert_raises(HelpNeeded) { @p.parse(%w(--help)) }
652   end
653
654   def test_version_and_help_long_args_can_be_overridden
655     @p.opt :asdf, "desc", :long => "help"
656     @p.opt :asdf2, "desc2", :long => "version"
657     assert_nothing_raised { @p.parse %w() }
658     assert_nothing_raised { @p.parse %w(--help) }
659     assert_nothing_raised { @p.parse %w(--version) }
660     assert_nothing_raised { @p.parse %w(-h) }
661     assert_nothing_raised { @p.parse %w(-v) }
662   end
663
664   def test_version_and_help_override_errors
665     @p.opt :asdf, "desc", :type => String
666     @p.version "version"
667     assert_nothing_raised { @p.parse %w(--asdf goat) }
668     assert_raises(CommandlineError) { @p.parse %w(--asdf) }
669     assert_raises(HelpNeeded) { @p.parse %w(--asdf --help) }
670     assert_raises(VersionNeeded) { @p.parse %w(--asdf --version) }
671   end
672
673   def test_conflicts
674     @p.opt :one
675     assert_raises(ArgumentError) { @p.conflicts :one, :two }
676     @p.opt :two
677     assert_nothing_raised { @p.conflicts :one, :two }
678     assert_nothing_raised { @p.parse %w(--one) }
679     assert_nothing_raised { @p.parse %w(--two) }
680     assert_raises(CommandlineError) { opts = @p.parse %w(--one --two) }
681
682     @p.opt :hello
683     @p.opt :yellow
684     @p.opt :mellow
685     @p.opt :jello
686     @p.conflicts :hello, :yellow, :mellow, :jello
687     assert_raises(CommandlineError) { opts = @p.parse %w(--hello --yellow --mellow --jello) }
688     assert_raises(CommandlineError) { opts = @p.parse %w(--hello --mellow --jello) }
689     assert_raises(CommandlineError) { opts = @p.parse %w(--hello --jello) }
690
691     assert_nothing_raised { opts = @p.parse %w(--hello) }
692     assert_nothing_raised { opts = @p.parse %w(--jello) }
693     assert_nothing_raised { opts = @p.parse %w(--yellow) }
694     assert_nothing_raised { opts = @p.parse %w(--mellow) }
695
696     assert_nothing_raised { opts = @p.parse %w(--mellow --one) }
697     assert_nothing_raised { opts = @p.parse %w(--mellow --two) }
698
699     assert_raises(CommandlineError) { opts = @p.parse %w(--mellow --two --jello) }
700     assert_raises(CommandlineError) { opts = @p.parse %w(--one --mellow --two --jello) }
701   end
702
703   def test_conflict_error_messages
704     @p.opt :one
705     @p.opt "two"
706     @p.conflicts :one, "two"
707
708     begin
709       @p.parse %w(--one --two)
710       flunk "no error thrown"
711     rescue CommandlineError => e
712       assert_match(/--one/, e.message)
713       assert_match(/--two/, e.message)
714     end
715   end
716
717   def test_depends
718     @p.opt :one
719     assert_raises(ArgumentError) { @p.depends :one, :two }
720     @p.opt :two
721     assert_nothing_raised { @p.depends :one, :two }
722     assert_nothing_raised { opts = @p.parse %w(--one --two) }
723     assert_raises(CommandlineError) { @p.parse %w(--one) }
724     assert_raises(CommandlineError) { @p.parse %w(--two) }
725
726     @p.opt :hello
727     @p.opt :yellow
728     @p.opt :mellow
729     @p.opt :jello
730     @p.depends :hello, :yellow, :mellow, :jello
731     assert_nothing_raised { opts = @p.parse %w(--hello --yellow --mellow --jello) }
732     assert_raises(CommandlineError) { opts = @p.parse %w(--hello --mellow --jello) }
733     assert_raises(CommandlineError) { opts = @p.parse %w(--hello --jello) }
734
735     assert_raises(CommandlineError) { opts = @p.parse %w(--hello) }
736     assert_raises(CommandlineError) { opts = @p.parse %w(--mellow) }
737
738     assert_nothing_raised { opts = @p.parse %w(--hello --yellow --mellow --jello --one --two) }
739     assert_nothing_raised { opts = @p.parse %w(--hello --yellow --mellow --jello --one --two a b c) }
740
741     assert_raises(CommandlineError) { opts = @p.parse %w(--mellow --two --jello --one) }
742   end
743
744   def test_depend_error_messages
745     @p.opt :one
746     @p.opt "two"
747     @p.depends :one, "two"
748
749     assert_nothing_raised { @p.parse %w(--one --two) }
750
751     begin
752       @p.parse %w(--one)
753       flunk "no error thrown"
754     rescue CommandlineError => e
755       assert_match(/--one/, e.message)
756       assert_match(/--two/, e.message)
757     end
758
759     begin
760       @p.parse %w(--two)
761       flunk "no error thrown"
762     rescue CommandlineError => e
763       assert_match(/--one/, e.message)
764       assert_match(/--two/, e.message)
765     end
766   end
767
768   ## courtesy neill zero
769   def test_two_required_one_missing_accuses_correctly
770     @p.opt "arg1", "desc1", :required => true
771     @p.opt "arg2", "desc2", :required => true
772
773     begin
774       @p.parse(%w(--arg1))
775       flunk "should have failed on a missing req"
776     rescue CommandlineError => e
777       assert e.message =~ /arg2/, "didn't mention arg2 in the error msg: #{e.message}"
778     end
779
780     begin
781       @p.parse(%w(--arg2))
782       flunk "should have failed on a missing req"
783     rescue CommandlineError => e
784       assert e.message =~ /arg1/, "didn't mention arg1 in the error msg: #{e.message}"
785     end
786
787     assert_nothing_raised { @p.parse(%w(--arg1 --arg2)) }
788   end
789
790   def test_stopwords_mixed
791     @p.opt "arg1", :default => false
792     @p.opt "arg2", :default => false
793     @p.stop_on %w(happy sad)
794
795     opts = @p.parse %w(--arg1 happy --arg2)
796     assert_equal true, opts["arg1"]
797     assert_equal false, opts["arg2"]
798
799     ## restart parsing
800     @p.leftovers.shift
801     opts = @p.parse @p.leftovers
802     assert_equal false, opts["arg1"]
803     assert_equal true, opts["arg2"]
804   end
805
806   def test_stopwords_no_stopwords
807     @p.opt "arg1", :default => false
808     @p.opt "arg2", :default => false
809     @p.stop_on %w(happy sad)
810
811     opts = @p.parse %w(--arg1 --arg2)
812     assert_equal true, opts["arg1"]
813     assert_equal true, opts["arg2"]
814
815     ## restart parsing
816     @p.leftovers.shift
817     opts = @p.parse @p.leftovers
818     assert_equal false, opts["arg1"]
819     assert_equal false, opts["arg2"]
820   end
821
822   def test_stopwords_multiple_stopwords
823     @p.opt "arg1", :default => false
824     @p.opt "arg2", :default => false
825     @p.stop_on %w(happy sad)
826
827     opts = @p.parse %w(happy sad --arg1 --arg2)
828     assert_equal false, opts["arg1"]
829     assert_equal false, opts["arg2"]
830
831     ## restart parsing
832     @p.leftovers.shift
833     opts = @p.parse @p.leftovers
834     assert_equal false, opts["arg1"]
835     assert_equal false, opts["arg2"]
836
837     ## restart parsing again
838     @p.leftovers.shift
839     opts = @p.parse @p.leftovers
840     assert_equal true, opts["arg1"]
841     assert_equal true, opts["arg2"]
842   end
843
844   def test_stopwords_with_short_args
845     @p.opt :global_option, "This is a global option", :short => "-g"
846     @p.stop_on %w(sub-command-1 sub-command-2)
847
848     global_opts = @p.parse %w(-g sub-command-1 -c)
849     cmd = @p.leftovers.shift
850
851     @q = Parser.new
852     @q.opt :cmd_option, "This is an option only for the subcommand", :short => "-c"
853     cmd_opts = @q.parse @p.leftovers
854
855     assert_equal true, global_opts[:global_option]
856     assert_nil global_opts[:cmd_option]
857
858     assert_equal true, cmd_opts[:cmd_option]
859     assert_nil cmd_opts[:global_option]
860
861     assert_equal cmd, "sub-command-1"
862     assert_equal @q.leftovers, []
863   end
864
865   def assert_parses_correctly(parser, commandline, expected_opts,
866                               expected_leftovers)
867     opts = parser.parse commandline
868     assert_equal expected_opts, opts
869     assert_equal expected_leftovers, parser.leftovers
870   end
871
872   def test_unknown_subcommand
873     @p.opt :global_flag, "Global flag", :short => "-g", :type => :flag
874     @p.opt :global_param, "Global parameter", :short => "-p", :default => 5
875     @p.stop_on_unknown
876
877     expected_opts = { :global_flag => true, :help => false, :global_param => 5, :global_flag_given => true }
878     expected_leftovers = [ "my_subcommand", "-c" ]
879
880     assert_parses_correctly @p, %w(--global-flag my_subcommand -c), \
881       expected_opts, expected_leftovers
882     assert_parses_correctly @p, %w(-g my_subcommand -c), \
883       expected_opts, expected_leftovers
884
885     expected_opts = { :global_flag => false, :help => false, :global_param => 5, :global_param_given => true }
886     expected_leftovers = [ "my_subcommand", "-c" ]
887
888     assert_parses_correctly @p, %w(-p 5 my_subcommand -c), \
889       expected_opts, expected_leftovers
890     assert_parses_correctly @p, %w(--global-param 5 my_subcommand -c), \
891       expected_opts, expected_leftovers
892   end
893
894   def test_alternate_args
895     args = %w(-a -b -c)
896
897     opts = ::Trollop.options(args) do
898       opt :alpher, "Ralph Alpher", :short => "-a"
899       opt :bethe, "Hans Bethe", :short => "-b"
900       opt :gamow, "George Gamow", :short => "-c"
901     end
902
903     physicists_with_humor = [:alpher, :bethe, :gamow]
904     physicists_with_humor.each do |physicist|
905       assert_equal true, opts[physicist]
906     end
907   end
908
909   def test_io_arg_type
910     @p.opt :arg, "desc", :type => :io
911     @p.opt :arg2, "desc", :type => IO
912     @p.opt :arg3, "desc", :default => $stdout
913
914     opts = nil
915     assert_nothing_raised { opts = @p.parse() }
916     assert_equal $stdout, opts[:arg3]
917
918     assert_nothing_raised { opts = @p.parse %w(--arg /dev/null) }
919     assert_kind_of File, opts[:arg]
920     assert_equal "/dev/null", opts[:arg].path
921
922     #TODO: move to mocks
923     #assert_nothing_raised { opts = @p.parse %w(--arg2 http://google.com/) }
924     #assert_kind_of StringIO, opts[:arg2]
925
926     assert_nothing_raised { opts = @p.parse %w(--arg3 stdin) }
927     assert_equal $stdin, opts[:arg3]
928
929     assert_raises(CommandlineError) { opts = @p.parse %w(--arg /fdasfasef/fessafef/asdfasdfa/fesasf) }
930   end
931
932   def test_openstruct_style_access
933     @p.opt "arg1", "desc", :type => :int
934     @p.opt :arg2, "desc", :type => :int
935
936     opts = @p.parse(%w(--arg1 3 --arg2 4))
937
938     assert_nothing_raised { opts.arg1 }
939     assert_nothing_raised { opts.arg2 }
940     assert_equal 3, opts.arg1
941     assert_equal 4, opts.arg2
942   end
943
944   def test_multi_args_autobox_defaults
945     @p.opt :arg1, "desc", :default => "hello", :multi => true
946     @p.opt :arg2, "desc", :default => ["hello"], :multi => true
947
948     opts = @p.parse
949     assert_equal ["hello"], opts[:arg1]
950     assert_equal ["hello"], opts[:arg2]
951
952     opts = @p.parse %w(--arg1 hello)
953     assert_equal ["hello"], opts[:arg1]
954     assert_equal ["hello"], opts[:arg2]
955
956     opts = @p.parse %w(--arg1 hello --arg1 there)
957     assert_equal ["hello", "there"], opts[:arg1]
958   end
959
960   def test_ambigious_multi_plus_array_default_resolved_as_specified_by_documentation
961     @p.opt :arg1, "desc", :default => ["potato"], :multi => true
962     @p.opt :arg2, "desc", :default => ["potato"], :multi => true, :type => :strings
963     @p.opt :arg3, "desc", :default => ["potato"]
964     @p.opt :arg4, "desc", :default => ["potato", "rhubarb"], :short => :none, :multi => true
965
966     ## arg1 should be multi-occurring but not multi-valued
967     opts = @p.parse %w(--arg1 one two)
968     assert_equal ["one"], opts[:arg1]
969     assert_equal ["two"], @p.leftovers
970
971     opts = @p.parse %w(--arg1 one --arg1 two)
972     assert_equal ["one", "two"], opts[:arg1]
973     assert_equal [], @p.leftovers
974
975     ## arg2 should be multi-valued and multi-occurring
976     opts = @p.parse %w(--arg2 one two)
977     assert_equal [["one", "two"]], opts[:arg2]
978     assert_equal [], @p.leftovers
979
980     ## arg3 should be multi-valued but not multi-occurring
981     opts = @p.parse %w(--arg3 one two)
982     assert_equal ["one", "two"], opts[:arg3]
983     assert_equal [], @p.leftovers
984
985     ## arg4 should be multi-valued but not multi-occurring
986     opts = @p.parse %w()
987     assert_equal ["potato", "rhubarb"], opts[:arg4]
988   end
989
990   def test_given_keys
991     @p.opt :arg1
992     @p.opt :arg2
993
994     opts = @p.parse %w(--arg1)
995     assert opts[:arg1_given]
996     assert !opts[:arg2_given]
997
998     opts = @p.parse %w(--arg2)
999     assert !opts[:arg1_given]
1000     assert opts[:arg2_given]
1001
1002     opts = @p.parse []
1003     assert !opts[:arg1_given]
1004     assert !opts[:arg2_given]
1005
1006     opts = @p.parse %w(--arg1 --arg2)
1007     assert opts[:arg1_given]
1008     assert opts[:arg2_given]
1009   end
1010
1011   def test_default_shorts_assigned_only_after_user_shorts
1012     @p.opt :aab, "aaa" # should be assigned to -b
1013     @p.opt :ccd, "bbb" # should be assigned to -d
1014     @p.opt :user1, "user1", :short => 'a'
1015     @p.opt :user2, "user2", :short => 'c'
1016
1017     opts = @p.parse %w(-a -b)
1018     assert opts[:user1]
1019     assert !opts[:user2]
1020     assert opts[:aab]
1021     assert !opts[:ccd]
1022
1023     opts = @p.parse %w(-c -d)
1024     assert !opts[:user1]
1025     assert opts[:user2]
1026     assert !opts[:aab]
1027     assert opts[:ccd]
1028   end
1029
1030   def test_accepts_arguments_with_spaces
1031     @p.opt :arg1, "arg", :type => String
1032     @p.opt :arg2, "arg2", :type => String
1033
1034     opts = @p.parse ["--arg1", "hello there", "--arg2=hello there"]
1035     assert_equal "hello there", opts[:arg1]
1036     assert_equal "hello there", opts[:arg2]
1037     assert_equal 0, @p.leftovers.size
1038   end
1039
1040   def test_multi_args_default_to_empty_array
1041     @p.opt :arg1, "arg", :multi => true
1042     opts = @p.parse ""
1043     assert_equal [], opts[:arg1]
1044   end
1045 end
1046
1047 end
1048 end