methadone 1.9.5 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -0
  3. data/.ruby-version +1 -1
  4. data/.travis.yml +2 -5
  5. data/README.rdoc +75 -47
  6. data/Rakefile +25 -29
  7. data/bin/methadone +13 -5
  8. data/lib/methadone.rb +1 -1
  9. data/lib/methadone/cli_logger.rb +0 -1
  10. data/lib/methadone/cli_logging.rb +1 -1
  11. data/lib/methadone/cucumber.rb +4 -0
  12. data/lib/methadone/main.rb +4 -1
  13. data/lib/methadone/test/base_integration_test.rb +29 -0
  14. data/lib/methadone/test/integration_test_assertions.rb +63 -0
  15. data/lib/methadone/version.rb +1 -1
  16. data/methadone.gemspec +3 -5
  17. data/templates/full/Rakefile.erb +9 -12
  18. data/templates/full/bin/executable.erb +2 -0
  19. data/templates/rspec/spec/something_spec.rb.erb +1 -1
  20. data/templates/test_unit/test/integration/test_cli.rb.erb +11 -0
  21. data/templates/test_unit/test/{tc_something.rb.erb → unit/test_something.rb.erb} +0 -0
  22. data/test/integration/base_integration_test.rb +60 -0
  23. data/test/integration/test_bootstrap.rb +150 -0
  24. data/test/integration/test_cli.rb +21 -0
  25. data/test/integration/test_license.rb +56 -0
  26. data/test/integration/test_readme.rb +53 -0
  27. data/test/integration/test_rspec.rb +28 -0
  28. data/test/integration/test_version.rb +21 -0
  29. data/test/{base_test.rb → unit/base_test.rb} +0 -0
  30. data/test/{command_for_tests.sh → unit/command_for_tests.sh} +0 -0
  31. data/test/{execution_strategy → unit/execution_strategy}/test_base.rb +0 -0
  32. data/test/{execution_strategy → unit/execution_strategy}/test_jvm.rb +4 -4
  33. data/test/{execution_strategy → unit/execution_strategy}/test_mri.rb +0 -0
  34. data/test/{execution_strategy → unit/execution_strategy}/test_open_3.rb +5 -5
  35. data/test/{execution_strategy → unit/execution_strategy}/test_open_4.rb +5 -5
  36. data/test/{execution_strategy → unit/execution_strategy}/test_rbx_open_4.rb +0 -0
  37. data/test/unit/test/test_integration_test_assertions.rb +211 -0
  38. data/test/{test_cli_logger.rb → unit/test_cli_logger.rb} +17 -17
  39. data/test/{test_cli_logging.rb → unit/test_cli_logging.rb} +12 -12
  40. data/test/{test_exit_now.rb → unit/test_exit_now.rb} +4 -4
  41. data/test/{test_main.rb → unit/test_main.rb} +48 -48
  42. data/test/{test_sh.rb → unit/test_sh.rb} +37 -37
  43. metadata +61 -93
  44. data/features/bootstrap.feature +0 -153
  45. data/features/license.feature +0 -43
  46. data/features/readme.feature +0 -26
  47. data/features/rspec_support.feature +0 -27
  48. data/features/step_definitions/bootstrap_steps.rb +0 -47
  49. data/features/step_definitions/license_steps.rb +0 -30
  50. data/features/step_definitions/readme_steps.rb +0 -26
  51. data/features/step_definitions/version_steps.rb +0 -4
  52. data/features/support/env.rb +0 -26
  53. data/features/version.feature +0 -17
  54. data/templates/full/features/executable.feature.erb +0 -13
  55. data/templates/full/features/step_definitions/executable_steps.rb.erb +0 -1
  56. data/templates/full/features/support/env.rb.erb +0 -16
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 16b7b785cbc498169dcd41650a52eba9aba67e33
4
- data.tar.gz: 3d1177ef34caba30beb4808ba3615d82cb0cadf4
2
+ SHA256:
3
+ metadata.gz: b21a9100411d2fd3589c39cd7e9db9f90712eb37d40748556dcfe33d760bcdaa
4
+ data.tar.gz: db454cb7ccda0705702cc4cbd888dad9b920b50a15e8d3026450239227e303aa
5
5
  SHA512:
6
- metadata.gz: cb015a80a55b3a454b59872ab84890de5ce89000009bf81137a0ca97724ad73601080bd7e431376797347f5ecd53e82749b9a4e051bd742f30e76dd649aea2f6
7
- data.tar.gz: 2198036125cd7af64763e7d59a77fe561cd7e8dd4e7be45dc171c7a2bae4f0970ee6ee346a85b1a7aa03651013776827e6b57c5e4c5e96b62be98f2dc4b1fe11
6
+ metadata.gz: f7add29c4a7a948f22e98d04f364591b602f96665f4451005dd2d0b6ef8dab0a8ebf01a54b177d04224b8e1e88e500f7e26b756e5451ea5491fd70ba20c54e8d
7
+ data.tar.gz: 31afecc9be7254afc979904629684ac3af7fa5b49d3189247e5f073964ce8c1a86cabfe1edd5b1aacb76fbcad3ca9a9e57d0f58498cf453d484cac22b15fdc38
data/.gitignore CHANGED
@@ -13,3 +13,4 @@ T_KICK_THE_BASH_HABIT_WITH_RUBY_AND_METHADONE.itmsp
13
13
  bin/cukedoc
14
14
  methadone.wiki
15
15
  tut
16
+ .idea
@@ -1 +1 @@
1
- 2.3.1
1
+ 2.5.1
@@ -3,8 +3,5 @@ notifications:
3
3
  on_success: always
4
4
  script: 'bundle exec rake'
5
5
  rvm:
6
- - 2.1.10
7
- - 2.2.6
8
- - 2.3.3
9
- - 2.4.0
10
- - jruby-19mode
6
+ - 2.4.3
7
+ - 2.5.1
@@ -16,10 +16,12 @@ Toward that end, this gem provides:
16
16
  * A lightweight DSL to create your command-line interface, that loses none of <tt>OptionParser</tt>'s power.
17
17
  * A simplified means of running external commands that has better error handling and diagnostics.
18
18
  * Simplified zero-config logging that is a better-than-<tt>puts</tt> <tt>puts</tt>.
19
- * Cucumber Steps, built on Aruba, to allow you to test-drive your command-line app development.
19
+ * Support for integration-testing your CLI using Test::Unit
20
20
 
21
21
  == Tutorial
22
22
 
23
+ **This tutorial is somewhat outdated, but generally still applies**
24
+
23
25
  http://a1.mzstatic.com/us/r30/Publication/v4/2c/f7/90/2cf7902f-f709-9125-c73d-87311216527d/MethadoneTutorial.225x225-75.jpg
24
26
 
25
27
  {Tutorial for your iPad}[http://itunes.apple.com/us/book/kick-bash-habit-ruby-methadone/id515825242?ls=1] - This is a *free* iBooks interactive ebook that contains a step-by-step tutorial on making an awesome app with Methadone, including screencasts.
@@ -31,11 +33,13 @@ http://a1.mzstatic.com/us/r30/Publication/v4/2c/f7/90/2cf7902f-f709-9125-c73d-87
31
33
 
32
34
  == Platforms
33
35
 
34
- In general, we try to support {supported MRI Rubies}[https://www.ruby-lang.org/en/downloads/] as well as JRuby, however see the {Travis config file}[./.travis.yml] for specifics.
36
+ This library only supports the latest versions of Ruby. JRuby support has been too difficult to keep up with, though the library should work for JRuby.
37
+
38
+ See the {Travis config file}[./.travis.yml] for specifics.
35
39
 
36
40
  == Bootstrapping a new CLI App
37
41
 
38
- The +methadone+ command-line app will bootstrap a new command-line app, setting up a proper gem structure, unit tests, and cucumber-based tests with aruba.
42
+ The +methadone+ command-line app will bootstrap a new command-line app, setting up a proper gem structure, unit tests, and integration tests.
39
43
 
40
44
  It assumes you are using a standard Ruby development environment, which includes:
41
45
 
@@ -47,41 +51,83 @@ _(Note that apps *powered* by this gem have no particular runtime dependencies a
47
51
 
48
52
 
49
53
  $ methadone --help
54
+ Usage: methadone [options] app_name
55
+
56
+ Kick the bash habit by bootstrapping your Ruby command-line apps
57
+
58
+ v2.0.0
59
+
60
+ Options:
61
+ -h, --help Show command line help
62
+ --force Overwrite files if they exist
63
+ --[no-]readme [Do not ]produce a README file
64
+ --rspec Generate RSpec unit tests instead of Test::Unit
65
+ -l, --license LICENSE Specify the license for your project
66
+ (mit|apache|gplv2|gplv3|custom|NONE)
67
+ --log-level LEVEL Set the logging level
68
+ (debug|info|warn|error|fatal)
69
+ (Default: info)
70
+ --version Show help/version info
71
+
72
+ Arguments:
73
+
74
+ app_name
75
+ Name of your app, which is used for the gem name and executable name
76
+
77
+
78
+
79
+
80
+
50
81
  Usage: methadone [options] app_name
51
82
  --force Overwrite files if they exist
52
- $ methadone newgem
53
- $ cd newgem
54
- $ bundle
55
- $ rake
56
- 1 tests, 1 assertions, 0 failures, 0 errors, 0 skips
57
- 1 scenario (1 passed)
58
- 3 steps (3 passed)
59
- $ cat features/newgem.feature
60
- Feature: My bootstrapped app kinda works
61
- In order to get going on coding my awesome app
62
- I want to have aruba and cucumber setup
63
- So I don't have to do it myself
64
-
65
- Scenario: App just runs
66
- When I run `newgem --help`
67
- Then the exit status should be 0
68
- And the output should contain:
69
- """
70
- Usage: newgem [options]
71
- """
83
+ $ methadone myapp -l mit
84
+ $ cd myapp
85
+ $ bundle install
86
+ ...
87
+ $ bundle exec rake
88
+ Started
89
+ .
90
+ Finished in 0.000499 seconds.
91
+ -----------------------------------------------------------------------------------------
92
+ 1 tests, 1 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications
93
+ 100% passed
94
+ -----------------------------------------------------------------------------------------
95
+ 2004.01 tests/s, 2004.01 assertions/s
96
+ Started
97
+ .
98
+ Finished in 0.298281 seconds.
99
+ -----------------------------------------------------------------------------------------
100
+ 1 tests, 8 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications
101
+ 100% passed
102
+ -----------------------------------------------------------------------------------------
103
+ 3.35 tests/s, 26.82 assertions/s
104
+
105
+ $ cat test/integration/test_cli.rb
106
+ require "methadone/test/base_integration_test"
107
+
108
+ class TestSomething < Methadone::BaseIntegrationTest
109
+ def test_truth
110
+ stdout,stderr,results = run_app("myapp","--help")
111
+ assert_banner(stdout, "myapp", takes_options: true, takes_arguments: false)
112
+ assert_option(stdout,"-h", "--help")
113
+ assert_option(stdout,"--version")
114
+ assert_oneline_summary(stdout)
115
+ end
116
+ end
117
+
72
118
 
73
119
  Basically, this sets you up with all the boilerplate that you *should* be using to write a command-line app. Specifically, you get:
74
120
 
75
121
  * Gemified project (based on <tt>bundle gem</tt>)
76
122
  * An executable using Methadone::Main to outline your new app
77
123
  * <tt>Test::Unit</tt> test task set up and an empty unit test.
78
- * Aruba/Cucumber set up with a basic feature that exercise your executable
124
+ * <tt>Test::Unit</tt> integration tests with some of methadone's assertions to let you drive your CLI's development
79
125
  * The outline of a README
80
126
  * An optional license included
81
127
 
82
128
  == DSL for your <tt>bin</tt> file
83
129
 
84
- A canonical <tt>OptionParser</tt> driven app has a few problems with it structurally that Methadone can solve:
130
+ A canonical <tt>OptionParser</tt>-driven app has a few problems with it structurally that Methadone can solve:
85
131
 
86
132
  * Backwards organization - main logic is at the bottom of the file, not the top
87
133
  * Verbose to use +opts.on+ just to set a value in a +Hash+
@@ -117,7 +163,7 @@ This isn't a replacement for Open3 or ChildProcess, but a way to easily "do the
117
163
 
118
164
  == Zero-Config Logging
119
165
 
120
- Chances are, your code is littered with <tt>STDERR.puts</tt> on a good day, and nothing on a bad day. You probably also have a bunch of debug <tt>puts</tt> calls that you have commented out. Logging is extremely helpful in understand how your app is behaving (or how it behaved in the past). Logging can be a pain to set up, and can also make it hard to give the user at the command-prompt a good experience.
166
+ Chances are, your code is littered with <tt>STDERR.puts</tt> on a good day, and nothing on a bad day. You probably also have a bunch of debug <tt>puts</tt> calls that you have commented out. Logging is extremely helpful in understanding how your app is behaving (or how it behaved in the past). Logging can be a pain to set up, and can also make it hard to give the user at the command-prompt a good experience.
121
167
 
122
168
  Methadone::CLILogger is designed to handle this. It's a proper subclass of Ruby's built-in <tt>Logger</tt> with a few enhancements:
123
169
 
@@ -129,32 +175,14 @@ Methadone::CLILogger is designed to handle this. It's a proper subclass of Ruby
129
175
 
130
176
  See {CLILogger's rdoc}[http://davetron5000.github.com/methadone/rdoc/classes/Methadone/CLILogger.html] and then {CLILogging's}[http://davetron5000.github.com/methadone/rdoc/classes/Methadone/CLILogging.html] for more.
131
177
 
132
-
133
178
  Currently, there are classes that assist in directing output logger-style to the right place; basically ensuring that errors go to +STDERR+ and everything else goes to +STDOUT+. All of this is, of course, configurable
134
179
 
135
- == Cucumber Steps
136
-
137
- Methadone uses aruba[http://www.github.com/cucumber/aruba] for BDD-style testing with cucumber. This library has some awesome steps, and Methadone provides additional, more opinionated, steps.
138
-
139
- === Example
140
-
141
- Here's an example from methadone's own tests:
142
-
143
- Scenario: Help is properly documented
144
- When I get help for "methadone"
145
- Then the exit status should be 0
146
- And the following options should be documented:
147
- |--force|
148
- And the banner should be present
149
- And the banner should include the version
150
- And the banner should document that this app takes options
151
- And the banner should document that this app's arguments are:
152
- |app_name|which is required|
153
- |dir_name|which is optional|
180
+ == Integration Tests
154
181
 
155
- See Methadone::Cucumber or its {rdoc}[http://davetron5000.github.com/methadone/rdoc/classes/Methadone/Cucumber.html] for a list of all the steps provided.
182
+ Methadone provides some basic features for executing your CLI and asserting things about it. Methadone::Test::IntegrationTestAssertions documents these.
156
183
 
157
184
  == Contributing
158
185
 
159
186
  * Feel free to file an issue, even if you don't have time to submit a patch
160
187
  * Please try to include a test for any patch you submit. If you don't include a test, I'll have to write one, and it'll take longer to get your code in.
188
+ * This is not intended to support “command-suite” style CLIs. See {GLI}[http://naildrivin5.com/gli] if that's what you want.
data/Rakefile CHANGED
@@ -2,19 +2,37 @@ require 'sdoc'
2
2
  require 'bundler'
3
3
  require 'rake/clean'
4
4
  require 'rake/testtask'
5
- require 'cucumber'
6
- require 'cucumber/rake/task'
7
5
 
8
6
  include Rake::DSL
9
7
 
10
8
  Bundler::GemHelper.install_tasks
11
9
 
12
- desc 'run tests'
10
+ desc 'run unit tests'
13
11
  Rake::TestTask.new do |t|
14
12
  t.libs << "lib"
15
- t.libs << "test"
16
- t.ruby_opts << "-rrubygems"
17
- t.test_files = FileList['test/test_*.rb'] + FileList['test/execution_strategy/test_*.rb']
13
+ t.libs << "test/unit"
14
+ test_file = ENV["TEST"]
15
+ ENV.delete("TEST")
16
+ t.test_files = if test_file
17
+ [test_file]
18
+ else
19
+ FileList['test/unit/test_*.rb'] +
20
+ FileList['test/unit/execution_strategy/test_*.rb'] +
21
+ FileList['test/unit/test/test_*.rb']
22
+ end
23
+ end
24
+
25
+ desc 'run integration tests'
26
+ Rake::TestTask.new("test:integration") do |t|
27
+ t.libs << "lib"
28
+ t.libs << "test/integration"
29
+ test_file = ENV["TEST"]
30
+ ENV.delete("TEST")
31
+ t.test_files = if test_file
32
+ [test_file]
33
+ else
34
+ FileList['test/integration/test_*.rb']
35
+ end
18
36
  end
19
37
 
20
38
  desc 'build rdoc'
@@ -70,29 +88,7 @@ task :hack_css do
70
88
  end
71
89
  end
72
90
  end
73
- if RUBY_PLATFORM == 'java'
74
- task :features do
75
- puts "Aruba doesn't work on JRuby; cannot run features"
76
- end
77
- task 'features:wip' => :features
78
- else
79
- CUKE_RESULTS = 'results.html'
80
- CLEAN << CUKE_RESULTS
81
- Cucumber::Rake::Task.new(:features) do |t|
82
- tag_opts = ' --tags ~@pending'
83
- tag_opts = " --tags #{ENV['TAGS']}" if ENV['TAGS']
84
- t.cucumber_opts = "features --format html -o #{CUKE_RESULTS} --format pretty -x -s#{tag_opts}"
85
- t.fork = false
86
- end
87
-
88
- Cucumber::Rake::Task.new('features:wip') do |t|
89
- tag_opts = ' --tags ~@pending'
90
- tag_opts = ' --tags @wip'
91
- t.cucumber_opts = "features --format html -o #{CUKE_RESULTS} --format pretty -x -s#{tag_opts}"
92
- t.fork = false
93
- end
94
- end
95
91
 
96
92
  CLEAN << "coverage"
97
93
  CLOBBER << FileList['**/*.rbc']
98
- task :default => [:test, :features]
94
+ task :default => [:test, "test:integration"]
@@ -28,6 +28,9 @@ main do |app_name|
28
28
  file =~ /\.rb$/ && file !~ /version.rb$/
29
29
  }.first
30
30
  end
31
+ rm_rf "#{gemname}/spec" # Don't want the default RSpec droppings
32
+ rm_rf "#{gemname}/.rspec"
33
+
31
34
  require_file = gemname if require_file.nil?
32
35
  require_file.gsub!(/^.*lib\//,'')
33
36
 
@@ -37,7 +40,7 @@ main do |app_name|
37
40
 
38
41
  rspec = options[:rspec]
39
42
 
40
- ["Rakefile", ".gitignore", "features/support/env.rb"].each do |file|
43
+ ["Rakefile", ".gitignore", ].each do |file|
41
44
  copy_file file, :binding => binding
42
45
  end
43
46
 
@@ -46,7 +49,8 @@ main do |app_name|
46
49
  copy_file "spec/something_spec.rb", :from => :rspec, :binding => binding
47
50
  else
48
51
  template_dirs_in(:test_unit).each { |dir| mkdir_p dir }
49
- copy_file "test/tc_something.rb", :from => :test_unit, :binding => binding
52
+ copy_file "test/unit/test_something.rb", :from => :test_unit, :binding => binding
53
+ copy_file "test/integration/test_cli.rb", :from => :test_unit, :binding => binding
50
54
  end
51
55
 
52
56
 
@@ -71,18 +75,21 @@ main do |app_name|
71
75
  else
72
76
  gemspec_content.gsub!(/(^\s*#{gem_variable}\.name\s*=\s*.*)/,"\\1\n#{" #{gem_variable}.license".ljust(20)} = #{license.to_s.inspect.upcase}")
73
77
  end
78
+ # RubyGems won't deal with a gemspec in this state and so Bundler won't even
79
+ # work at all. This is not helpful, so replace the magic keys its looking for
80
+ # with something else
81
+ gemspec_content.gsub!(/TODO/,"to-do")
82
+ gemspec_content.gsub!(/FIXME/,"fix me")
83
+ gemspec_content.gsub!(/^.*\.homepage.*$/,"")
74
84
  File.open(gemspec,'w') {|f| f.write gemspec_content }
75
85
 
76
86
 
77
87
  copy_file "README.rdoc", :binding => binding if using_readme
78
88
 
79
- copy_file "features/executable.feature", :as => "#{gemname}.feature", :binding => binding
80
- copy_file "features/step_definitions/executable_steps.rb", :as => "#{gemname}_steps.rb"
81
89
  copy_file "bin/executable", :as => gemname, :executable => true, :binding => binding
82
90
 
83
91
  add_to_file gemspec, [
84
92
  " #{gem_variable}.add_development_dependency('rdoc')",
85
- " #{gem_variable}.add_development_dependency('aruba')",
86
93
  " #{gem_variable}.add_dependency('methadone', '~> #{Methadone::VERSION}')",
87
94
  ], :before => /^end\s*$/
88
95
  ruby_major,ruby_minor,ruby_patch = RUBY_VERSION.split(/\./).map(&:to_i)
@@ -98,6 +105,7 @@ main do |app_name|
98
105
  " #{gem_variable}.add_development_dependency('rspec', '~> 3')",
99
106
  ], :before => /^end\s*$/
100
107
  end
108
+ FileUtils.rm_f "README.md", verbose: true
101
109
 
102
110
  sh! %q(git add --all .)
103
111
  end
@@ -12,4 +12,4 @@ require 'methadone/execution_strategy/open_4'
12
12
  require 'methadone/execution_strategy/rbx_open_4'
13
13
  require 'methadone/execution_strategy/jvm'
14
14
  require 'methadone/sh'
15
- # Note: DO NOT require cli.rb OR cucumber.rb here
15
+ # Note: DO NOT require cli.rb, cucumber.rb, or anything in test/ here
@@ -100,7 +100,6 @@ module Methadone
100
100
 
101
101
  def level=(level)
102
102
  super(level)
103
- current_error_level = @stderr_logger.level
104
103
  if (level > DEFAULT_ERROR_LEVEL) && @split_logs
105
104
  @stderr_logger.level = level
106
105
  end
@@ -48,7 +48,7 @@ module Methadone
48
48
  def change_logger(new_logger)
49
49
  raise ArgumentError,"Logger may not be nil" if new_logger.nil?
50
50
  @@logger = new_logger
51
- @@logger.level = @log_level if @log_level
51
+ @@logger.level = @log_level if defined?(@log_level) && @log_level
52
52
  end
53
53
 
54
54
  alias logger= change_logger
@@ -1,4 +1,8 @@
1
1
  module Methadone
2
+ #
3
+ # **NOTE!** Cucumber is not recommened or supported by methadone, as Aruba has diverged too much. This
4
+ # file is left here to allow you to update methadone but still use Cucumber & Aruba on older versions.
5
+ #
2
6
  # By <tt>require</tt>'ing <tt>methadone/cucumber</tt> in your Cucumber setup (e.g. in <tt>env.rb</tt>), you
3
7
  # gain access to the steps defined in this file. They provide you with the following:
4
8
  #
@@ -325,6 +325,8 @@ module Methadone
325
325
  end
326
326
 
327
327
  def add_defaults_to_docs
328
+ @env_var = nil unless defined? @env_var
329
+ @rc_file = nil unless defined? @rc_file
328
330
  if @env_var && @rc_file
329
331
  opts.separator ''
330
332
  opts.separator 'Default values can be placed in:'
@@ -351,7 +353,7 @@ module Methadone
351
353
  end
352
354
 
353
355
  def set_defaults_from_rc_file
354
- if @rc_file && File.exists?(@rc_file)
356
+ if @rc_file && File.exist?(@rc_file)
355
357
  File.open(@rc_file) do |file|
356
358
  parsed = begin
357
359
  YAML::load(file)
@@ -392,6 +394,7 @@ module Methadone
392
394
 
393
395
  # Handle calling main and trapping any exceptions thrown
394
396
  def call_main
397
+ @leak_exceptions = nil unless defined? @leak_exceptions
395
398
  @main_block.call(*ARGV)
396
399
  rescue Methadone::Error => ex
397
400
  raise ex if ENV['DEBUG']
@@ -0,0 +1,29 @@
1
+ require "test/unit"
2
+ require "fileutils"
3
+ require "pathname"
4
+ require "tmpdir"
5
+ require "open3"
6
+
7
+ require_relative "integration_test_assertions"
8
+
9
+ # Clean test should be setting this
10
+ $FOR_TESTING_ONLY_SKIP_STDERR = false
11
+
12
+ class Methadone::BaseIntegrationTest < Test::Unit::TestCase
13
+ include FileUtils
14
+ include Methadone::IntegrationTestAssertions
15
+
16
+ # Run your app, capturing stdout, stderr, and process status.
17
+ # app_name:: Your bin name, without `bin/`
18
+ # args:: CLI args as a string
19
+ # allow_failure:: if true, this will return even if the app invocation fails. If false (the default), blows up if things go
20
+ # wrong.
21
+ def run_app(app_name, args, allow_failure: false)
22
+ command = "bin/#{app_name} #{args}"
23
+ stdout,stderr,results = Open3.capture3(command)
24
+ if @allow_failure && !results.success?
25
+ raise "'#{command}' failed!: #{results.inspect}\n\nSTDOUT {\n#{stdout}\n} STDERR {\n#{stderr}\n} END"
26
+ end
27
+ [stdout,stderr,results]
28
+ end
29
+ end
@@ -0,0 +1,63 @@
1
+ module Methadone::IntegrationTestAssertions
2
+ # Assert that a file's contents contains one or more regexps
3
+ #
4
+ # filename:: The file whose contents to check
5
+ # contains:: either a regexp or array of regexpts that the file's contents must match
6
+ def assert_file(filename, contains:)
7
+ contents = File.read(filename)
8
+ Array(contains).each do |regexp|
9
+ assert_match(regexp,contents,"Expected #{filename} to contain #{regexp}")
10
+ end
11
+ end
12
+
13
+ # Assert that the stdout contains an appropriate banner for your app
14
+ #
15
+ # stdout:: The standard out, presumably of running `«your-app» --help`
16
+ # bin_name:: The binary name of your app
17
+ # takes_options:: set this to true if your app should take options
18
+ # takes_arguments:: set this to a hash of the arguments your app should take, with the key being the arg name and the value
19
+ # being either `:required` or `:optional`
20
+ def assert_banner(stdout, bin_name, takes_options: , takes_arguments: {})
21
+ if takes_options
22
+ assert_match(/Options/, stdout)
23
+ if takes_arguments == false || takes_arguments.empty?
24
+ assert_match(/Usage: #{Regexp.escape(bin_name)}.*\[options\]\s*$/,stdout)
25
+ else
26
+ expected_args = takes_arguments.map { |arg, required|
27
+ if required == :required
28
+ arg.to_s
29
+ else
30
+ "[#{arg}]"
31
+ end
32
+ }.join(" ")
33
+
34
+ assert_match(/Usage: #{Regexp.escape(bin_name)}.*\[options\]\s*#{Regexp.escape(expected_args)}$/,stdout)
35
+ end
36
+ else
37
+ assert_match(/Usage: #{Regexp.escape(bin_name)}\s*$/,stdout)
38
+ end
39
+ end
40
+
41
+ # Assert that your app takes the given option(s)
42
+ #
43
+ # stdout:: The standard out, presumably of running `«your-app» --help`
44
+ # options:: options your app should take. Put the literal value in here e.g. `--foo` or `--[no-]bar`. The array form is to
45
+ # allow you to assert long and short options for readable tests:
46
+ #
47
+ # assert_option(stdout, "--version")
48
+ # assert_option(stdout, "-h", "--help")
49
+ def assert_option(stdout, *options)
50
+ options.each do |option|
51
+ assert_match(/#{Regexp.escape(option)}/,stdout)
52
+ end
53
+ end
54
+
55
+ # Assert that your app has a one-line summary
56
+ # stdout:: The standard out, presumably of running `«your-app» --help`
57
+ def assert_oneline_summary(stdout)
58
+ output = stdout.split(/\n/)
59
+ assert output.size >= 3, "Expected 3 or more lines:\n#{stdout}"
60
+ assert_match(/^\s*$/,output[1],"Should be a blank line after the banner")
61
+ assert_match(/^\w+\s+\w+/,output[2],"Should be at least two words describing your app")
62
+ end
63
+ end