gli 2.11.0 → 2.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +28 -0
  3. data/.gitignore +3 -3
  4. data/.tool-versions +1 -0
  5. data/Gemfile +0 -2
  6. data/README.rdoc +29 -19
  7. data/Rakefile +15 -37
  8. data/bin/ci +29 -0
  9. data/bin/gli +24 -54
  10. data/bin/rake +29 -0
  11. data/bin/setup +5 -0
  12. data/exe/gli +68 -0
  13. data/gli.gemspec +20 -24
  14. data/gli.rdoc +9 -9
  15. data/lib/gli/app.rb +31 -8
  16. data/lib/gli/app_support.rb +15 -3
  17. data/lib/gli/command.rb +24 -2
  18. data/lib/gli/command_finder.rb +42 -25
  19. data/lib/gli/command_support.rb +7 -6
  20. data/lib/gli/commands/doc.rb +9 -3
  21. data/lib/gli/commands/help.rb +2 -1
  22. data/lib/gli/commands/help_modules/arg_name_formatter.rb +2 -2
  23. data/lib/gli/commands/help_modules/command_help_format.rb +19 -1
  24. data/lib/gli/commands/help_modules/full_synopsis_formatter.rb +3 -2
  25. data/lib/gli/commands/help_modules/global_help_format.rb +1 -1
  26. data/lib/gli/commands/help_modules/options_formatter.rb +4 -6
  27. data/lib/gli/commands/initconfig.rb +3 -6
  28. data/lib/gli/commands/rdoc_document_listener.rb +2 -1
  29. data/lib/gli/commands/scaffold.rb +71 -142
  30. data/lib/gli/dsl.rb +2 -1
  31. data/lib/gli/flag.rb +23 -2
  32. data/lib/gli/gli_option_parser.rb +66 -15
  33. data/lib/gli/option_parser_factory.rb +9 -2
  34. data/lib/gli/options.rb +2 -2
  35. data/lib/gli/switch.rb +4 -0
  36. data/lib/gli/terminal.rb +6 -2
  37. data/lib/gli/version.rb +1 -1
  38. data/lib/gli.rb +1 -0
  39. data/object-model.dot +29 -0
  40. data/object-model.png +0 -0
  41. data/test/apps/todo/Gemfile +1 -1
  42. data/test/apps/todo/bin/todo +12 -6
  43. data/test/apps/todo/lib/todo/commands/create.rb +42 -41
  44. data/test/apps/todo/lib/todo/commands/list.rb +48 -36
  45. data/test/apps/todo/lib/todo/commands/ls.rb +25 -24
  46. data/test/apps/todo/lib/todo/commands/make.rb +42 -39
  47. data/test/apps/todo/todo.gemspec +1 -2
  48. data/test/apps/todo_legacy/todo.gemspec +1 -2
  49. data/test/apps/todo_plugins/commands/third.rb +2 -0
  50. data/test/integration/gli_cli_test.rb +69 -0
  51. data/test/integration/gli_powered_app_test.rb +52 -0
  52. data/test/integration/scaffold_test.rb +30 -0
  53. data/test/integration/test_helper.rb +52 -0
  54. data/test/unit/command_finder_test.rb +54 -0
  55. data/test/{tc_command.rb → unit/command_test.rb} +20 -7
  56. data/test/unit/compound_command_test.rb +17 -0
  57. data/test/{tc_doc.rb → unit/doc_test.rb} +38 -51
  58. data/test/{tc_flag.rb → unit/flag_test.rb} +19 -25
  59. data/test/{tc_gli.rb → unit/gli_test.rb} +78 -50
  60. data/test/{tc_help.rb → unit/help_test.rb} +54 -113
  61. data/test/{tc_options.rb → unit/options_test.rb} +4 -4
  62. data/test/unit/subcommand_parsing_test.rb +263 -0
  63. data/test/unit/subcommands_test.rb +245 -0
  64. data/test/{config.yaml → unit/support/gli_test_config.yml} +1 -0
  65. data/test/unit/switch_test.rb +49 -0
  66. data/test/{tc_terminal.rb → unit/terminal_test.rb} +28 -3
  67. data/test/unit/test_helper.rb +13 -0
  68. data/test/unit/verbatim_wrapper_test.rb +24 -0
  69. metadata +85 -141
  70. data/.ruby-gemset +0 -1
  71. data/.ruby-version +0 -1
  72. data/.travis.yml +0 -12
  73. data/ObjectModel.graffle +0 -1191
  74. data/bin/report_on_rake_results +0 -10
  75. data/bin/test_all_rubies.sh +0 -6
  76. data/features/gli_executable.feature +0 -90
  77. data/features/gli_init.feature +0 -232
  78. data/features/step_definitions/gli_executable_steps.rb +0 -18
  79. data/features/step_definitions/gli_init_steps.rb +0 -11
  80. data/features/step_definitions/todo_steps.rb +0 -100
  81. data/features/support/env.rb +0 -55
  82. data/features/todo.feature +0 -546
  83. data/features/todo_legacy.feature +0 -128
  84. data/test/option_test_helper.rb +0 -13
  85. data/test/tc_compound_command.rb +0 -22
  86. data/test/tc_subcommand_parsing.rb +0 -104
  87. data/test/tc_subcommands.rb +0 -259
  88. data/test/tc_switch.rb +0 -55
  89. data/test/tc_verbatim_wrapper.rb +0 -36
  90. data/test/test_helper.rb +0 -20
  91. /data/test/{init_simplecov.rb → unit/init_simplecov.rb} +0 -0
  92. /data/test/{fake_std_out.rb → unit/support/fake_std_out.rb} +0 -0
@@ -1,2 +1,2 @@
1
- source :rubygems
1
+ source 'https://rubygems.org'
2
2
  gemspec
@@ -1,17 +1,17 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  # These would not be in a real GLI app; we do this so we can easily run this on the command line
4
- $: << File.expand_path(File.join(File.dirname(__FILE__),'..','..','..','lib'))
4
+ $: << File.expand_path(File.join(File.dirname(__FILE__),'..','..','..','..','lib'))
5
5
  $: << File.expand_path(File.join(File.dirname(__FILE__),'..','lib'))
6
6
 
7
7
  require 'gli'
8
8
  require 'todo/version'
9
9
 
10
-
10
+ class App
11
11
  if ENV['GLI1_COMPATIBILITY']
12
- include GLI
12
+ extend GLI
13
13
  else
14
- include GLI::App
14
+ extend GLI::App
15
15
  end
16
16
 
17
17
  sort_help (ENV['TODO_SORT_HELP'] || 'alpha').to_sym
@@ -20,6 +20,7 @@ synopsis_format (ENV['SYNOPSES'] || 'full').to_sym
20
20
  hide_commands_without_desc ENV['HIDE_COMMANDS_WITHOUT_DESC'] === 'true'
21
21
 
22
22
  subcommand_option_handling :normal
23
+ arguments :strict
23
24
 
24
25
  program_desc 'Manages tasks'
25
26
  program_long_desc "A test program that has a sophisticated UI that can be used to exercise a lot of GLI's power"
@@ -41,7 +42,12 @@ command :first do |c| c.action { |g,o,a| puts "first: #{a.join(',')}" } end
41
42
  arg :argument, :optional
42
43
  command :second do |c| c.action { |g,o,a| puts "second: #{a.join(',')}" } end
43
44
 
45
+ arg :first
46
+ arg :second
44
47
  command :chained => [ :first, :second ]
48
+
49
+ arg :first
50
+ arg :second
45
51
  command [:chained2,:ch2] => [ :second, :first ]
46
52
 
47
53
  pre do |global,command,options,args|
@@ -64,5 +70,5 @@ on_error do |exception|
64
70
  # return false to skip default error handling
65
71
  true
66
72
  end
67
-
68
- exit run(ARGV)
73
+ end
74
+ exit App.run(ARGV)
@@ -1,53 +1,54 @@
1
- desc "Create a new task or context"
2
- command [:create,:new] do |c|
3
- c.desc "Make a new task"
4
- c.arg_name 'task_name', :multiple
5
- c.arg :should_ignore_this
6
- c.command :tasks do |tasks|
7
- tasks.action do |global,options,args|
8
- puts "#{args}"
1
+ class App
2
+ desc "Create a new task or context"
3
+ command [:create,:new] do |c|
4
+ c.desc "Make a new task"
5
+ c.arg_name 'task_name', :multiple
6
+ c.arg :should_ignore_this
7
+ c.command :tasks do |tasks|
8
+ tasks.action do |global,options,args|
9
+ puts "#{args}"
10
+ end
9
11
  end
10
- end
11
12
 
12
- c.desc "Make a new context"
13
- c.arg :should_ignore_this
14
- c.arg_name 'context_name', :optional
15
- c.command :contexts do |contexts|
16
- contexts.action do |global,options,args|
17
- puts "#{args}"
13
+ c.desc "Make a new context"
14
+ c.arg :should_ignore_this
15
+ c.arg_name 'context_name', :optional
16
+ c.command :contexts do |contexts|
17
+ contexts.action do |global,options,args|
18
+ puts "#{args}"
19
+ end
18
20
  end
19
- end
20
21
 
21
- c.default_desc "Makes a new task"
22
- c.action do
23
- puts "default action"
24
- end
22
+ c.default_desc "Makes a new task"
23
+ c.action do
24
+ puts "default action"
25
+ end
25
26
 
26
- c.arg "first"
27
- c.arg "second"
28
- c.arg "name", :optional
29
- c.command :"relation_1-1" do |remote|
30
- remote.action do |global,options,args|
31
- puts "relation: #{args}"
27
+ c.arg "first"
28
+ c.arg "second"
29
+ c.arg "name", :optional
30
+ c.command :"relation_1-1" do |remote|
31
+ remote.action do |global,options,args|
32
+ puts "relation: #{args}"
33
+ end
32
34
  end
33
- end
34
35
 
35
- c.arg "first", :multiple
36
- c.arg "second"
37
- c.arg "name", :optional
38
- c.command :"relation_n-1" do |remote|
39
- remote.action do |global,options,args|
40
- puts "relation: #{args}"
36
+ c.arg "first", :multiple
37
+ c.arg "second"
38
+ c.arg "name", :optional
39
+ c.command :"relation_n-1" do |remote|
40
+ remote.action do |global,options,args|
41
+ puts "relation: #{args}"
42
+ end
41
43
  end
42
- end
43
44
 
44
- c.arg "first"
45
- c.arg "second", :multiple
46
- c.arg "name", :optional
47
- c.command :"relation_1-n" do |remote|
48
- remote.action do |global,options,args|
49
- puts "relation: #{args}"
45
+ c.arg "first"
46
+ c.arg "second", :multiple
47
+ c.arg "name", :optional
48
+ c.command :"relation_1-n" do |remote|
49
+ remote.action do |global,options,args|
50
+ puts "relation: #{args}"
51
+ end
50
52
  end
51
53
  end
52
54
  end
53
-
@@ -1,5 +1,6 @@
1
- desc "List things, such as tasks or contexts"
2
- long_desc %(
1
+ class App
2
+ desc "List things, such as tasks or contexts"
3
+ long_desc %(
3
4
  List a whole lot of things that you might be keeping track of
4
5
  in your overall todo list.
5
6
 
@@ -8,59 +9,70 @@ long_desc %(
8
9
  stored in
9
10
  your todo databases.
10
11
  )
11
- command [:list] do |c|
12
- c.default_command :tasks
13
12
 
14
- c.desc "Show long form"
15
- c.switch [:l,:long]
13
+ command [:list] do |c|
14
+ c.default_command :tasks
16
15
 
17
- c.flag :required_flag, :required => true
18
- c.flag :required_flag2, :required => true
16
+ c.desc "Show long form"
17
+ c.switch [:l,:long]
19
18
 
20
- c.desc "List tasks"
21
- c.long_desc %(
19
+ c.flag :required_flag, :required => true
20
+ c.flag :required_flag2, :required => true
21
+
22
+ c.desc "List tasks"
23
+ c.long_desc %(
22
24
  Lists all of your tasks that you have, in varying orders, and
23
25
  all that stuff. Yes, this is long, but I need a long description.
24
26
  )
25
- c.command :tasks do |tasks|
26
- tasks.desc "blah blah crud x whatever"
27
- tasks.flag [:x], :must_match => Array
28
27
 
29
- tasks.flag :flag
28
+ c.arg :task, [:optional, :multiple]
29
+ c.command :tasks do |tasks|
30
+ tasks.desc "blah blah crud x whatever"
31
+ tasks.flag [:x], :must_match => Array
30
32
 
31
- tasks.action do |global,options,args|
32
- puts options[:x].inspect
33
- puts "list tasks: #{args.join(',')}"
34
- end
33
+ tasks.flag :flag
35
34
 
36
- tasks.desc 'list open tasks'
37
- tasks.command :open do |open|
38
- open.action do |global,options,args|
39
- puts "tasks open"
35
+ tasks.action do |global,options,args|
36
+ puts options[:x].inspect
37
+ puts "list tasks: #{args.join(',')}"
40
38
  end
41
- end
42
39
 
43
- tasks.default_desc 'list all tasks'
44
- end
40
+ tasks.desc 'list open tasks'
41
+ tasks.command :open do |open|
42
+ open.desc "blah blah crud x whatever"
43
+ open.flag [:x], :must_match => Array
44
+
45
+ open.flag :flag
46
+
47
+ open.example "todo list tasks open --flag=blah", desc: "example number 1"
48
+ open.example "todo list tasks open -x foo"
45
49
 
46
- c.desc "List contexts"
47
- c.long_desc %(
50
+ open.action do |global,options,args|
51
+ puts "tasks open"
52
+ end
53
+ end
54
+
55
+ tasks.default_desc 'list all tasks'
56
+ end
57
+
58
+ c.desc "List contexts"
59
+ c.long_desc %(
48
60
  Lists all of your contexts, which are places you might be
49
61
  where you can do stuff and all that.
50
62
  )
51
- c.command :contexts do |contexts|
63
+ c.command :contexts do |contexts|
52
64
 
53
- contexts.desc "Foobar"
54
- contexts.switch [:f,'foobar']
65
+ contexts.desc "Foobar"
66
+ contexts.switch [:f,'foobar']
55
67
 
56
- contexts.desc "Blah"
57
- contexts.switch [:b]
68
+ contexts.desc "Blah"
69
+ contexts.switch [:b]
58
70
 
59
- contexts.flag :otherflag
71
+ contexts.flag :otherflag
60
72
 
61
- contexts.action do |global,options,args|
62
- puts "list contexts: #{args.join(',')}"
73
+ contexts.action do |global,options,args|
74
+ puts "list contexts: #{args.join(',')}"
75
+ end
63
76
  end
64
77
  end
65
78
  end
66
-
@@ -1,6 +1,7 @@
1
- # This is copied so I can have two slightly different versions of the same thing
2
- desc "LS things, such as tasks or contexts"
3
- long_desc %(
1
+ class App
2
+ # This is copied so I can have two slightly different versions of the same thing
3
+ desc "LS things, such as tasks or contexts"
4
+ long_desc %(
4
5
  List a whole lot of things that you might be keeping track of
5
6
  in your overall todo list.
6
7
 
@@ -9,39 +10,39 @@ long_desc %(
9
10
  stored in
10
11
  your todo databases.
11
12
  )
12
- command [:ls] do |c|
13
- c.desc "Show long form"
14
- c.switch [:l,:long]
13
+ command [:ls] do |c|
14
+ c.desc "Show long form"
15
+ c.switch [:l,:long]
15
16
 
16
- c.desc "List tasks"
17
- c.long_desc %(
17
+ c.desc "List tasks"
18
+ c.long_desc %(
18
19
  Lists all of your tasks that you have, in varying orders, and
19
20
  all that stuff. Yes, this is long, but I need a long description.
20
21
  )
21
- c.command :tasks do |tasks|
22
- tasks.desc "blah blah crud x whatever"
23
- tasks.flag [:x]
24
- tasks.action do |global,options,args|
25
- puts "ls tasks: #{args.join(',')}"
22
+ c.command :tasks do |tasks|
23
+ tasks.desc "blah blah crud x whatever"
24
+ tasks.flag [:x]
25
+ tasks.action do |global,options,args|
26
+ puts "ls tasks: #{args.join(',')}"
27
+ end
26
28
  end
27
- end
28
29
 
29
- c.desc "List contexts"
30
- c.long_desc %(
30
+ c.desc "List contexts"
31
+ c.long_desc %(
31
32
  Lists all of your contexts, which are places you might be
32
33
  where you can do stuff and all that.
33
34
  )
34
- c.command :contexts do |contexts|
35
+ c.command :contexts do |contexts|
35
36
 
36
- contexts.desc "Foobar"
37
- contexts.switch [:f,'foobar']
37
+ contexts.desc "Foobar"
38
+ contexts.switch [:f,'foobar']
38
39
 
39
- contexts.desc "Blah"
40
- contexts.switch [:b]
40
+ contexts.desc "Blah"
41
+ contexts.switch [:b]
41
42
 
42
- contexts.action do |global,options,args|
43
- puts "ls contexts: #{args.join(',')}"
43
+ contexts.action do |global,options,args|
44
+ puts "ls contexts: #{args.join(',')}"
45
+ end
44
46
  end
45
47
  end
46
48
  end
47
-
@@ -1,52 +1,55 @@
1
- command [:make] do |c|
2
- c.desc "Show long form"
3
- c.flag [:l,:long]
1
+ class App
2
+ command [:make] do |c|
3
+ c.desc "Show long form"
4
+ c.flag [:l,:long]
4
5
 
5
- c.desc 'make a new task'
6
- c.command :task do |task|
7
- task.desc 'make the task a long task'
8
- task.flag [:l,:long]
6
+ c.desc 'make a new task'
7
+ c.command :task do |task|
8
+ task.desc 'make the task a long task'
9
+ task.flag [:l,:long]
9
10
 
10
- task.action do |g,o,a|
11
- puts 'new task'
12
- puts a.join(',')
13
- puts o[:long]
11
+ task.action do |g,o,a|
12
+ puts 'new task'
13
+ puts a.join(',')
14
+ puts o[:long]
15
+ end
16
+
17
+ task.desc 'make a bug'
18
+ task.arg :argument, [:multiple, :optional]
19
+ task.command :bug do |bug|
20
+ bug.desc 'make this bug in the legacy system'
21
+ bug.flag [:l,:legacy]
22
+
23
+ bug.action do |g,o,a|
24
+ puts 'new task bug'
25
+ puts a.join(',')
26
+ # All this .to_s is to make sure 1.8.7/REE don't convert nil to the string "nil"
27
+ puts o[:legacy].to_s
28
+ puts o[:long].to_s
29
+ puts o[:l].to_s
30
+ puts o[GLI::Command::PARENT][:l].to_s
31
+ puts o[GLI::Command::PARENT][:long].to_s
32
+ puts o[GLI::Command::PARENT][:legacy].to_s
33
+ puts o[GLI::Command::PARENT][GLI::Command::PARENT][:l].to_s
34
+ puts o[GLI::Command::PARENT][GLI::Command::PARENT][:long].to_s
35
+ puts o[GLI::Command::PARENT][GLI::Command::PARENT][:legacy].to_s
36
+ end
37
+ end
14
38
  end
15
39
 
16
- desc 'make a bug'
17
- task.command :bug do |bug|
18
- bug.desc 'make this bug in the legacy system'
19
- bug.flag [:l,:legacy]
40
+ c.desc 'make a new context'
41
+ c.command :context do |context|
42
+ context.desc 'make the context a local context'
43
+ context.flag [:l,:local]
20
44
 
21
- bug.action do |g,o,a|
22
- puts 'new task bug'
45
+ context.action do |g,o,a|
46
+ puts 'new context'
23
47
  puts a.join(',')
24
- # All this .to_s is to make sure 1.8.7/REE don't convert nil to the string "nil"
25
- puts o[:legacy].to_s
48
+ puts o[:local].to_s
26
49
  puts o[:long].to_s
27
50
  puts o[:l].to_s
28
- puts o[GLI::Command::PARENT][:l].to_s
29
- puts o[GLI::Command::PARENT][:long].to_s
30
- puts o[GLI::Command::PARENT][:legacy].to_s
31
- puts o[GLI::Command::PARENT][GLI::Command::PARENT][:l].to_s
32
- puts o[GLI::Command::PARENT][GLI::Command::PARENT][:long].to_s
33
- puts o[GLI::Command::PARENT][GLI::Command::PARENT][:legacy].to_s
34
51
  end
35
52
  end
36
- end
37
-
38
- c.desc 'make a new context'
39
- c.command :context do |context|
40
- context.desc 'make the context a local context'
41
- context.flag [:l,:local]
42
53
 
43
- context.action do |g,o,a|
44
- puts 'new context'
45
- puts a.join(',')
46
- puts o[:local].to_s
47
- puts o[:long].to_s
48
- puts o[:l].to_s
49
- end
50
54
  end
51
-
52
55
  end
@@ -1,6 +1,6 @@
1
1
  # Ensure we require the local version and not one we might have installed already
2
2
  require File.join([File.dirname(__FILE__),'lib','todo','version.rb'])
3
- spec = Gem::Specification.new do |s|
3
+ spec = Gem::Specification.new do |s|
4
4
  s.name = 'todo'
5
5
  s.version = Todo::VERSION
6
6
  s.author = 'Your Name Here'
@@ -13,7 +13,6 @@ spec = Gem::Specification.new do |s|
13
13
  bin/todo
14
14
  )
15
15
  s.require_paths << 'lib'
16
- s.has_rdoc = true
17
16
  s.extra_rdoc_files = ['README.rdoc','todo.rdoc']
18
17
  s.rdoc_options << '--title' << 'todo' << '--main' << 'README.rdoc' << '-ri'
19
18
  s.bindir = 'bin'
@@ -1,6 +1,6 @@
1
1
  # Ensure we require the local version and not one we might have installed already
2
2
  require File.join([File.dirname(__FILE__),'lib','todo','version.rb'])
3
- spec = Gem::Specification.new do |s|
3
+ spec = Gem::Specification.new do |s|
4
4
  s.name = 'todo'
5
5
  s.version = Todo::VERSION
6
6
  s.author = 'Your Name Here'
@@ -13,7 +13,6 @@ spec = Gem::Specification.new do |s|
13
13
  bin/todo
14
14
  )
15
15
  s.require_paths << 'lib'
16
- s.has_rdoc = true
17
16
  s.extra_rdoc_files = ['README.rdoc','todo.rdoc']
18
17
  s.rdoc_options << '--title' << 'todo' << '--main' << 'README.rdoc' << '-ri'
19
18
  s.bindir = 'bin'
@@ -1 +1,3 @@
1
+ class App
1
2
  command :third do |c| c.action { |g,o,a| puts "third: #{a.join(',')}" } end
3
+ end
@@ -0,0 +1,69 @@
1
+ require_relative "test_helper"
2
+ require "open3"
3
+
4
+ class GLICLITest < MiniTest::Test
5
+ include TestHelper
6
+
7
+ class AppHelp < GLICLITest
8
+ def test_running_with_no_options_produces_help
9
+ out = run_gli
10
+ assert_output_looks_like_help out
11
+ end
12
+
13
+ def test_running_with_help_command_produces_help
14
+ out = run_gli("help")
15
+ assert_output_looks_like_help out
16
+ end
17
+
18
+ def test_running_with_help_switch_produces_help
19
+ out = run_gli("--help")
20
+ assert_output_looks_like_help out
21
+ end
22
+
23
+ private
24
+
25
+ def assert_output_looks_like_help(out)
26
+ assert_match /gli - create scaffolding for a GLI-powered application/,out
27
+ assert_match /SYNOPSIS/,out
28
+ assert_match /GLOBAL OPTIONS/,out
29
+ assert_match /COMMANDS/,out
30
+ end
31
+
32
+ end
33
+
34
+ class Scaffolding < GLICLITest
35
+ def test_help_on_scaffold_command
36
+ out = run_gli("help scaffold")
37
+ assert_output_looks_like_help(out)
38
+ end
39
+ def test_help_on_scaffold_command_as_init
40
+ out = run_gli("help init")
41
+ assert_output_looks_like_help(out)
42
+ end
43
+
44
+ private
45
+
46
+ def assert_output_looks_like_help(out)
47
+ assert_match /init - Create a new GLI-based project/,out
48
+ assert_match /SYNOPSIS/,out
49
+ assert_match /COMMAND OPTIONS/,out
50
+ end
51
+ end
52
+
53
+ private
54
+
55
+ def run_gli(args="", return_err_and_status: false, expect_failure: false)
56
+ command_line_invocation = "bin/gli #{args}"
57
+ stdout_string, stderr_string, status = Open3.capture3(command_line_invocation)
58
+ if expect_failure
59
+ refute_equal 0,status.exitstatus,"Expected failure for '#{command_line_invocation}' but it succeeded"
60
+ else
61
+ assert_equal 0,status.exitstatus,"Expected success for '#{command_line_invocation}' but it failed"
62
+ end
63
+ if return_err_and_status
64
+ [ stdout_string, stderr_string, status ]
65
+ else
66
+ stdout_string
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,52 @@
1
+ require_relative "test_helper"
2
+ require "open3"
3
+
4
+ class GLIPoweredAppTest < MiniTest::Test
5
+ include TestHelper
6
+
7
+ def teardown
8
+ FileUtils.rm_f("todo.rdoc")
9
+ end
10
+
11
+ def test_help_works
12
+ out = run_app("help")
13
+ assert_top_level_help(out)
14
+ end
15
+
16
+ def test_unknown_command_exits_nonzero
17
+ out, err, status = run_app("asdfasdfasdf", expect_failure: true, return_err_and_status: true)
18
+ assert_match /Unknown command 'asdfasdfasdf'/,err
19
+ assert_equal 64, status.exitstatus
20
+ assert_top_level_help(out)
21
+ end
22
+
23
+ def test_unknown_switch_exits_nonzero
24
+ out, err, status = run_app("list --foo", expect_failure: true, return_err_and_status: true)
25
+ assert_match /Unknown option \-\-foo/,err
26
+ assert_equal 64, status.exitstatus
27
+ assert_match /COMMAND OPTIONS/, out
28
+ end
29
+
30
+ def test_missing_args_exits_nonzero
31
+ out, err, status = run_app("list", expect_failure: true, return_err_and_status: true)
32
+ assert_match /required_flag is required, required_flag2 is required/,err
33
+ assert_equal 64, status.exitstatus
34
+ assert_match /COMMAND OPTIONS/, out
35
+ end
36
+
37
+ def test_doc_generation
38
+ out, err, status = run_app("_doc", return_err_and_status: true)
39
+ assert File.exists?("todo.rdoc")
40
+ end
41
+
42
+ private
43
+ def assert_top_level_help(out)
44
+ assert_match /SYNOPSIS/, out
45
+ assert_match /GLOBAL OPTIONS/, out
46
+ assert_match /COMMANDS/, out
47
+ end
48
+
49
+ def run_app(args="", return_err_and_status: false, expect_failure: false)
50
+ run_command("test/apps/todo/bin/todo",args,return_err_and_status:return_err_and_status,expect_failure:expect_failure)
51
+ end
52
+ end
@@ -0,0 +1,30 @@
1
+ require_relative "test_helper"
2
+ require "open3"
3
+
4
+ class ScaffoldCommandTest < MiniTest::Test
5
+ include TestHelper
6
+
7
+ def test_scaffolded_app_has_reasonable_setup
8
+ FileUtils.rm_rf "scaffold_test"
9
+ run_gli("init scaffold_test")
10
+ assert Dir.exist? "scaffold_test"
11
+ FileUtils.chdir "scaffold_test" do
12
+ run_command("bundle install", "", return_err_and_status: false, expect_failure: false)
13
+
14
+ scaffold_lib = "lib:../lib"
15
+
16
+ # help works
17
+ out = run_command("bin/scaffold_test","--help", return_err_and_status: false, expect_failure: false, rubylib: scaffold_lib)
18
+ assert_match /SYNOPSIS/,out
19
+ assert_match /GLOBAL OPTIONS/,out
20
+ assert_match /COMMANDS/,out
21
+
22
+ # can run unit tests
23
+ out = run_command("bundle exec ","rake test", return_err_and_status: false, expect_failure: false, rubylib: scaffold_lib)
24
+ assert_match /0 failures/,out
25
+ assert_match /0 errors/,out
26
+ assert_match /0 skips/,out
27
+ end
28
+ end
29
+
30
+ end
@@ -0,0 +1,52 @@
1
+ require "minitest/autorun"
2
+ require "pathname"
3
+ require "fileutils"
4
+
5
+ # Copied from https://github.com/splattael/minitest-around
6
+ # so as to avoid an explicit dependency
7
+ Minitest::Test.class_eval do
8
+ alias_method :run_without_around, :run
9
+ def run(*args)
10
+ if defined?(around)
11
+ result = nil
12
+ around { result = run_without_around(*args) }
13
+ result
14
+ else
15
+ run_without_around(*args)
16
+ end
17
+ end
18
+ end
19
+
20
+ module TestHelper
21
+ def around(&block)
22
+ Bundler.with_original_env do
23
+ root = Pathname(__FILE__).dirname / ".." / ".."
24
+ FileUtils.chdir root do
25
+ block.()
26
+ end
27
+ end
28
+ end
29
+
30
+ def run_gli(args="", return_err_and_status: false, expect_failure: false)
31
+ run_command("bin/gli",args,return_err_and_status:return_err_and_status,expect_failure:expect_failure)
32
+ end
33
+
34
+ def run_command(command,args,return_err_and_status:,expect_failure:,rubylib:nil)
35
+ command_line_invocation = "#{command} #{args}"
36
+ env = {}
37
+ if !rubylib.nil?
38
+ env["RUBYLIB"] = rubylib
39
+ end
40
+ stdout_string, stderr_string, status = Open3.capture3(env,command_line_invocation)
41
+ if expect_failure
42
+ refute_equal 0,status.exitstatus,"Expected failure for '#{command_line_invocation}' but it succeeded"
43
+ else
44
+ assert_equal 0,status.exitstatus,"Expected success for '#{command_line_invocation}' but it failed:\n#{stdout_string}\n\n#{stderr_string}\n\n"
45
+ end
46
+ if return_err_and_status
47
+ [ stdout_string, stderr_string, status ]
48
+ else
49
+ stdout_string
50
+ end
51
+ end
52
+ end