methadone 1.9.5 → 2.0.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 (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