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.
- checksums.yaml +5 -5
- data/.gitignore +1 -0
- data/.ruby-version +1 -1
- data/.travis.yml +2 -5
- data/README.rdoc +75 -47
- data/Rakefile +25 -29
- data/bin/methadone +13 -5
- data/lib/methadone.rb +1 -1
- data/lib/methadone/cli_logger.rb +0 -1
- data/lib/methadone/cli_logging.rb +1 -1
- data/lib/methadone/cucumber.rb +4 -0
- data/lib/methadone/main.rb +4 -1
- data/lib/methadone/test/base_integration_test.rb +29 -0
- data/lib/methadone/test/integration_test_assertions.rb +63 -0
- data/lib/methadone/version.rb +1 -1
- data/methadone.gemspec +3 -5
- data/templates/full/Rakefile.erb +9 -12
- data/templates/full/bin/executable.erb +2 -0
- data/templates/rspec/spec/something_spec.rb.erb +1 -1
- data/templates/test_unit/test/integration/test_cli.rb.erb +11 -0
- data/templates/test_unit/test/{tc_something.rb.erb → unit/test_something.rb.erb} +0 -0
- data/test/integration/base_integration_test.rb +60 -0
- data/test/integration/test_bootstrap.rb +150 -0
- data/test/integration/test_cli.rb +21 -0
- data/test/integration/test_license.rb +56 -0
- data/test/integration/test_readme.rb +53 -0
- data/test/integration/test_rspec.rb +28 -0
- data/test/integration/test_version.rb +21 -0
- data/test/{base_test.rb → unit/base_test.rb} +0 -0
- data/test/{command_for_tests.sh → unit/command_for_tests.sh} +0 -0
- data/test/{execution_strategy → unit/execution_strategy}/test_base.rb +0 -0
- data/test/{execution_strategy → unit/execution_strategy}/test_jvm.rb +4 -4
- data/test/{execution_strategy → unit/execution_strategy}/test_mri.rb +0 -0
- data/test/{execution_strategy → unit/execution_strategy}/test_open_3.rb +5 -5
- data/test/{execution_strategy → unit/execution_strategy}/test_open_4.rb +5 -5
- data/test/{execution_strategy → unit/execution_strategy}/test_rbx_open_4.rb +0 -0
- data/test/unit/test/test_integration_test_assertions.rb +211 -0
- data/test/{test_cli_logger.rb → unit/test_cli_logger.rb} +17 -17
- data/test/{test_cli_logging.rb → unit/test_cli_logging.rb} +12 -12
- data/test/{test_exit_now.rb → unit/test_exit_now.rb} +4 -4
- data/test/{test_main.rb → unit/test_main.rb} +48 -48
- data/test/{test_sh.rb → unit/test_sh.rb} +37 -37
- metadata +61 -93
- data/features/bootstrap.feature +0 -153
- data/features/license.feature +0 -43
- data/features/readme.feature +0 -26
- data/features/rspec_support.feature +0 -27
- data/features/step_definitions/bootstrap_steps.rb +0 -47
- data/features/step_definitions/license_steps.rb +0 -30
- data/features/step_definitions/readme_steps.rb +0 -26
- data/features/step_definitions/version_steps.rb +0 -4
- data/features/support/env.rb +0 -26
- data/features/version.feature +0 -17
- data/templates/full/features/executable.feature.erb +0 -13
- data/templates/full/features/step_definitions/executable_steps.rb.erb +0 -1
- data/templates/full/features/support/env.rb.erb +0 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: b21a9100411d2fd3589c39cd7e9db9f90712eb37d40748556dcfe33d760bcdaa
|
4
|
+
data.tar.gz: db454cb7ccda0705702cc4cbd888dad9b920b50a15e8d3026450239227e303aa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f7add29c4a7a948f22e98d04f364591b602f96665f4451005dd2d0b6ef8dab0a8ebf01a54b177d04224b8e1e88e500f7e26b756e5451ea5491fd70ba20c54e8d
|
7
|
+
data.tar.gz: 31afecc9be7254afc979904629684ac3af7fa5b49d3189247e5f073964ce8c1a86cabfe1edd5b1aacb76fbcad3ca9a9e57d0f58498cf453d484cac22b15fdc38
|
data/.gitignore
CHANGED
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.
|
1
|
+
2.5.1
|
data/.travis.yml
CHANGED
data/README.rdoc
CHANGED
@@ -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
|
-
*
|
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
|
-
|
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
|
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
|
53
|
-
$ cd
|
54
|
-
$ bundle
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
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
|
-
*
|
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
|
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
|
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
|
-
==
|
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
|
-
|
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
|
-
|
17
|
-
|
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, :
|
94
|
+
task :default => [:test, "test:integration"]
|
data/bin/methadone
CHANGED
@@ -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",
|
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/
|
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
|
data/lib/methadone.rb
CHANGED
@@ -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
|
15
|
+
# Note: DO NOT require cli.rb, cucumber.rb, or anything in test/ here
|
data/lib/methadone/cli_logger.rb
CHANGED
@@ -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
|
data/lib/methadone/cucumber.rb
CHANGED
@@ -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
|
#
|
data/lib/methadone/main.rb
CHANGED
@@ -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.
|
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
|