shell_test 0.1.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.
data/History.rdoc ADDED
@@ -0,0 +1,7 @@
1
+ == 0.1.0 2011/07/07
2
+
3
+ Initial release.
4
+
5
+ Much of this code started in the {Tap-Test}[http://rubygems.org/gems/tap-test]
6
+ gem and was later added-to by Linecook[http://rubygems.org/gems/linecook]. It
7
+ has long wished to be it's own gem, and now it is.
data/MIT-LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2011, Simon Chiang.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,146 @@
1
+ = ShellTest
2
+
3
+ Test modules for shell scripts.
4
+
5
+ == Description
6
+
7
+ Provides test modules to simplify testing of shell scripts.
8
+
9
+ ShellTest is not a testing framework. ShellTest integrates with Test::Unit and
10
+ MiniTest out of the box, but it should be possible to include the test modules
11
+ into other test frameworks.
12
+
13
+ == Usage
14
+
15
+ ShellTest builds on modules that provide specific functionality. The modules
16
+ may be used independently, but by including ShellTest you get them all:
17
+
18
+ require 'shell_test/unit'
19
+
20
+ class ShellTestExample < Test::Unit::TestCase
21
+ include ShellTest
22
+
23
+ def test_a_script
24
+ script = prepare('script.sh') do |io|
25
+ io.puts "echo goodnight $1"
26
+ end
27
+
28
+ assert_script %{
29
+ $ sh '#{script}' moon
30
+ goodnight moon
31
+ }
32
+ end
33
+ end
34
+
35
+ ==== {ShellMethods}[link:classes/ShellTest/ShellMethods.html]
36
+
37
+ Provides the shell testing methods. These methods are designed to input a
38
+ string that looks like terminal input/output. Commands are parsed out of the
39
+ string, run, and then anything printed to stdout is compared to the expected
40
+ output. In addition the exit status is checked for success (0).
41
+
42
+ Special comments following the first line of a command can turn off
43
+ output/status checking, or specify a different exit status to expect.
44
+
45
+ require 'shell_test/unit'
46
+
47
+ class ShellMethodsExample < Test::Unit::TestCase
48
+ include ShellTest::ShellMethods
49
+
50
+ def test_a_script_using_variables
51
+ with_env("THING" => "moon") do
52
+ assert_script %{
53
+ $ echo "goodnight $THING"
54
+ goodnight moon
55
+ }
56
+ end
57
+ end
58
+
59
+ def test_multiple_commands
60
+ assert_script %{
61
+ $ echo one
62
+ one
63
+ $ echo two
64
+ two
65
+ }
66
+ end
67
+
68
+ def test_multiline_commands
69
+ assert_script %{
70
+ $ for n in one two; do
71
+ > echo $n
72
+ > done
73
+ one
74
+ two
75
+ }
76
+ end
77
+
78
+ def test_exit_statuses
79
+ assert_script %{
80
+ $ true # [0]
81
+ $ false # [1]
82
+ }
83
+ end
84
+
85
+ def test_exit_status_and_not_ouptut
86
+ assert_script %{
87
+ $ date # [0] ...
88
+ }
89
+ end
90
+
91
+ def test_output_with_inline_regexps
92
+ assert_script_match %{
93
+ $ cal
94
+ :...:
95
+ Su Mo Tu We Th Fr Sa
96
+ :...:
97
+ }
98
+ end
99
+ end
100
+
101
+ ==== {FileMethods}[link:classes/ShellTest/FileMethods.html]
102
+
103
+ Sets up a temporary, test-specific directory for working with files. This
104
+ approach is better in most cases than using Tempfile because you can flag the
105
+ directory to be saved on a failure (using ENV['KEEP_OUTPUTS']='true').
106
+
107
+ By default the directory is guessed based off of the test file and test
108
+ method. If this example were located in the 'test/file_methods_example.rb'
109
+ file, then the directory for the test case would be
110
+ 'test/file_methods_example/test_preparation_of_a_test_specific_file'.
111
+
112
+ require 'shell_test/unit'
113
+
114
+ class FileMethodsExample < Test::Unit::TestCase
115
+ include ShellTest::FileMethods
116
+
117
+ def test_preparation_of_a_test_specific_file
118
+ path = prepare('dir/file.txt') {|io| io << 'content' }
119
+ assert_equal "content", File.read(path)
120
+ end
121
+ end
122
+
123
+ == Installation
124
+
125
+ ShellTest is available as a gem[http://rubygems.org/gems/shell_test].
126
+
127
+ $ gem install shell_test
128
+
129
+ == Development
130
+
131
+ To get started, checkout the code from GitHub[http://github.com/thinkerbot/shell_test] and run:
132
+
133
+ git clone https://thinkerbot@github.com/thinkerbot/shell_test.git
134
+ cd shell_test
135
+ rake test
136
+
137
+ To test against multiple platforms I suggest using rvm. In that case:
138
+
139
+ rvm rake test
140
+
141
+ Please report any issues {here}[http://github.com/thinkerbot/shell_test/issues].
142
+
143
+ == Info
144
+
145
+ Developer:: {Simon Chiang}[http://thinkerbot.posterous.com]
146
+ License:: {MIT-Style}[link:files/MIT-LICENSE.html]
@@ -0,0 +1,67 @@
1
+ module ShellTest
2
+ class CommandParser
3
+ attr_reader :ps1
4
+ attr_reader :ps2
5
+
6
+ def initialize(options={})
7
+ options = {
8
+ :ps1 => '$ ',
9
+ :ps2 => '> '
10
+ }.merge(options)
11
+
12
+ @ps1 = options[:ps1]
13
+ @ps2 = options[:ps2]
14
+ end
15
+
16
+ def parse_cmd(cmd)
17
+ cmd =~ /.*?#\s*(?:\[(\d+)\])?\s*(\.{3})?/
18
+ exit_status = $1 ? $1.to_i : 0
19
+ output = $2 ? nil : ""
20
+
21
+ [cmd, output, exit_status]
22
+ end
23
+
24
+ def parse(script)
25
+ commands = []
26
+
27
+ command, output, exit_status = nil, "", 0
28
+ script.each_line do |line|
29
+ case
30
+ when line.index(ps1) == 0
31
+ if command
32
+ commands << [command, output, exit_status]
33
+ end
34
+
35
+ command, output, exit_status = parse_cmd lchomp(ps1, line)
36
+
37
+ when command.nil?
38
+ unless line.strip.empty?
39
+ command, output, exit_status = parse_cmd(line)
40
+ end
41
+
42
+ when line.index(ps2) == 0
43
+ command << lchomp(ps2, line)
44
+
45
+ when output.nil?
46
+ output = line
47
+
48
+ else
49
+ output << line
50
+ end
51
+ end
52
+
53
+ if command
54
+ commands << [command, output, exit_status]
55
+ end
56
+
57
+ commands
58
+ end
59
+
60
+ private
61
+
62
+ def lchomp(prefix, line) # :nodoc:
63
+ length = prefix.length
64
+ line[length, line.length - length]
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,208 @@
1
+ require 'fileutils'
2
+
3
+ module ShellTest
4
+ module FileMethods
5
+ module ClassMethods
6
+ attr_accessor :class_dir
7
+
8
+ attr_reader :cleanup_method_registry
9
+
10
+ def cleanup_methods
11
+ @cleanup_methods ||= begin
12
+ cleanup_methods = {}
13
+
14
+ ancestors.reverse.each do |ancestor|
15
+ next unless ancestor.kind_of?(ClassMethods)
16
+ ancestor.cleanup_method_registry.each_pair do |key, value|
17
+ if value.nil?
18
+ cleanup_methods.delete(key)
19
+ else
20
+ cleanup_methods[key] = value
21
+ end
22
+ end
23
+ end
24
+
25
+ cleanup_methods
26
+ end
27
+ end
28
+
29
+ def reset_cleanup_methods
30
+ @cleanup_methods = nil
31
+ end
32
+
33
+ protected
34
+
35
+ def self.initialize(base)
36
+ # Infers the test directory from the calling file.
37
+ # 'some_class_test.rb' => 'some_class_test'
38
+ call_line = caller.find {|value| value !~ /`(includ|inherit|extend)ed'$/ }
39
+
40
+ if call_line
41
+ calling_file = call_line.gsub(/:\d+(:in .*)?$/, "")
42
+ base.class_dir = calling_file.chomp(File.extname(calling_file))
43
+ else
44
+ unless Dir.respond_to?(:tmpdir)
45
+ require 'tmpdir'
46
+ end
47
+ base.class_dir = Dir.tmpdir
48
+ end
49
+
50
+ base.reset_cleanup_methods
51
+ unless base.instance_variable_defined?(:@cleanup_method_registry)
52
+ base.instance_variable_set(:@cleanup_method_registry, {})
53
+ end
54
+
55
+ unless base.instance_variable_defined?(:@cleanup_paths)
56
+ base.instance_variable_set(:@cleanup_paths, ['.'])
57
+ end
58
+
59
+ unless base.instance_variable_defined?(:@cleanup)
60
+ base.instance_variable_set(:@cleanup, true)
61
+ end
62
+ end
63
+
64
+ def inherited(base) # :nodoc:
65
+ ClassMethods.initialize(base)
66
+ super
67
+ end
68
+
69
+ def define_method_cleanup(method_name, dirs)
70
+ reset_cleanup_methods
71
+ cleanup_method_registry[method_name.to_sym] = dirs
72
+ end
73
+
74
+ def remove_method_cleanup(method_name)
75
+ reset_cleanup_methods
76
+ cleanup_method_registry.delete(method_name.to_sym)
77
+ end
78
+
79
+ def undef_method_cleanup(method_name)
80
+ reset_cleanup_methods
81
+ cleanup_method_registry[method_name.to_sym] = nil
82
+ end
83
+
84
+ def cleanup_paths(*dirs)
85
+ @cleanup_paths = dirs
86
+ end
87
+
88
+ def cleanup(*method_names)
89
+ if method_names.empty?
90
+ @cleanup = true
91
+ else
92
+ method_names.each do |method_name|
93
+ define_method_cleanup method_name, @cleanup_paths
94
+ end
95
+ end
96
+ end
97
+
98
+ def no_cleanup(*method_names)
99
+ if method_names.empty?
100
+ @cleanup = false
101
+ else
102
+ method_names.each do |method_name|
103
+ undef_method_cleanup method_name
104
+ end
105
+ end
106
+ end
107
+
108
+ def method_added(sym)
109
+ if @cleanup && !cleanup_method_registry.has_key?(sym.to_sym) && sym.to_s[0, 5] == "test_"
110
+ cleanup sym
111
+ end
112
+ end
113
+ end
114
+
115
+ module ModuleMethods
116
+ module_function
117
+
118
+ def included(base)
119
+ base.extend ClassMethods
120
+ base.extend ModuleMethods unless base.kind_of?(Class)
121
+
122
+ ClassMethods.initialize(base)
123
+ super
124
+ end
125
+ end
126
+
127
+ extend ModuleMethods
128
+
129
+ def setup
130
+ super
131
+ cleanup
132
+ end
133
+
134
+ def teardown
135
+ Dir.chdir(user_dir)
136
+
137
+ unless ENV["KEEP_OUTPUTS"] == "true"
138
+ cleanup
139
+
140
+ dir = method_dir
141
+ while dir != class_dir
142
+ dir = File.dirname(dir)
143
+ Dir.rmdir(dir)
144
+ end rescue(SystemCallError)
145
+ end
146
+
147
+ super
148
+ end
149
+
150
+ def user_dir
151
+ @user_dir ||= File.expand_path('.')
152
+ end
153
+
154
+ def class_dir
155
+ @class_dir ||= File.expand_path(self.class.class_dir, user_dir)
156
+ end
157
+
158
+ def method_dir
159
+ @method_dir ||= File.expand_path(method_name.to_s, class_dir)
160
+ end
161
+
162
+ def method_name
163
+ __name__
164
+ end
165
+
166
+ def cleanup_methods
167
+ self.class.cleanup_methods
168
+ end
169
+
170
+ def cleanup
171
+ if cleanup_paths = cleanup_methods[method_name.to_sym]
172
+ cleanup_paths.each {|relative_path| remove(relative_path) }
173
+ end
174
+ end
175
+
176
+ def path(relative_path)
177
+ path = File.expand_path(relative_path, method_dir)
178
+
179
+ unless path.index(method_dir) == 0
180
+ raise "does not make a path relative to method_dir: #{relative_path.inspect}"
181
+ end
182
+
183
+ path
184
+ end
185
+
186
+ def prepare(relative_path, content=nil, &block)
187
+ target = path(relative_path)
188
+
189
+ if File.exists?(target)
190
+ FileUtils.rm(target)
191
+ else
192
+ target_dir = File.dirname(target)
193
+ FileUtils.mkdir_p(target_dir) unless File.exists?(target_dir)
194
+ end
195
+
196
+ FileUtils.touch(target)
197
+ File.open(target, 'w') {|io| io << content } if content
198
+ File.open(target, 'a', &block) if block
199
+
200
+ target
201
+ end
202
+
203
+ def remove(relative_path)
204
+ full_path = path(relative_path)
205
+ FileUtils.rm_r(full_path) if File.exists?(full_path)
206
+ end
207
+ end
208
+ end
@@ -0,0 +1,84 @@
1
+ module ShellTest
2
+ # RegexpEscape is a subclass of regexp that escapes all but the text in a
3
+ # special escape sequence. This allows the creation of complex regexps
4
+ # to match, for instance, console output.
5
+ #
6
+ # The RegexpEscape.escape (or equivalently the quote) method does the
7
+ # work; all regexp-active characters are escaped except for characters
8
+ # enclosed by ':.' and '.:' delimiters.
9
+ #
10
+ # RegexpEscape.escape('reg[exp]+ chars. are(quoted)') # => 'reg\[exp\]\+\ chars\.\ are\(quoted\)'
11
+ # RegexpEscape.escape('these are not: :.a(b*)c.:') # => 'these\ are\ not:\ a(b*)c'
12
+ #
13
+ # In addition, all-period regexps are automatically upgraded to '.*?';
14
+ # use the '.{n}' notation to specify n arbitrary characters.
15
+ #
16
+ # RegexpEscape.escape('_:..:_:...:_:....:') # => '_.*?_.*?_.*?'
17
+ # RegexpEscape.escape(':..{1}.:') # => '.{1}'
18
+ #
19
+ # RegexpEscape instances are initialized using the escaped input string
20
+ # and return the original string upon to_s.
21
+ #
22
+ # str = %q{
23
+ # a multiline
24
+ # :...:
25
+ # example}
26
+ # r = RegexpEscape.new(str)
27
+ #
28
+ # r =~ %q{
29
+ # a multiline
30
+ # matching
31
+ # example} # => true
32
+ #
33
+ # r !~ %q{
34
+ # a failing multiline
35
+ # example} # => true
36
+ #
37
+ # r.to_s # => str
38
+ #
39
+ class RegexpEscape < Regexp
40
+
41
+ # matches the escape sequence
42
+ ESCAPE_SEQUENCE = /:\..*?\.:/
43
+
44
+ class << self
45
+
46
+ # Escapes regexp-active characters in str, except for character
47
+ # delimited by ':.' and '.:'. See the class description for
48
+ # details.
49
+ def escape(str)
50
+ substituents = []
51
+ str.scan(ESCAPE_SEQUENCE) do
52
+ regexp_str = $&[2...-2]
53
+ regexp_str = ".*?" if regexp_str =~ /^\.*$/
54
+ substituents << regexp_str
55
+ end
56
+ substituents << ""
57
+
58
+ splits = str.split(ESCAPE_SEQUENCE).collect do |split|
59
+ super(split)
60
+ end
61
+ splits << "" if splits.empty?
62
+
63
+ splits.zip(substituents).to_a.flatten.join
64
+ end
65
+
66
+ # Same as escape.
67
+ def quote(str)
68
+ escape(str)
69
+ end
70
+ end
71
+
72
+ # Generates a new RegexpEscape by escaping the str, using the same
73
+ # options as Regexp.
74
+ def initialize(str, *options)
75
+ super(RegexpEscape.escape(str), *options)
76
+ @original_str = str
77
+ end
78
+
79
+ # Returns the original string for self
80
+ def to_s
81
+ @original_str
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,176 @@
1
+ require 'shell_test/regexp_escape'
2
+ require 'shell_test/command_parser'
3
+
4
+ module ShellTest
5
+ module ShellMethods
6
+ def setup
7
+ super
8
+ @notify_method_name = true
9
+ end
10
+
11
+ # Parse a script into an array of [cmd, output, status] triplets.
12
+ def parse_script(script, options={})
13
+ CommandParser.new(options).parse(script)
14
+ end
15
+
16
+ # Returns true if the ENV variable 'VERBOSE' is true. When verbose,
17
+ # ShellTest prints the expanded commands of sh_test to $stdout.
18
+ def verbose?
19
+ verbose = ENV['VERBOSE']
20
+ verbose && verbose =~ /^true$/i ? true : false
21
+ end
22
+
23
+ # Sets the specified ENV variables and returns the *current* env.
24
+ # If replace is true, current ENV variables are replaced; otherwise
25
+ # the new env variables are simply added to the existing set.
26
+ def set_env(env={}, replace=false)
27
+ current_env = {}
28
+ ENV.each_pair do |key, value|
29
+ current_env[key] = value
30
+ end
31
+
32
+ ENV.clear if replace
33
+
34
+ env.each_pair do |key, value|
35
+ if value.nil?
36
+ ENV.delete(key)
37
+ else
38
+ ENV[key] = value
39
+ end
40
+ end if env
41
+
42
+ current_env
43
+ end
44
+
45
+ # Sets the specified ENV variables for the duration of the block.
46
+ # If replace is true, current ENV variables are replaced; otherwise
47
+ # the new env variables are simply added to the existing set.
48
+ #
49
+ # Returns the block return.
50
+ def with_env(env={}, replace=false)
51
+ current_env = nil
52
+ begin
53
+ current_env = set_env(env, replace)
54
+ yield
55
+ ensure
56
+ if current_env
57
+ set_env(current_env, true)
58
+ end
59
+ end
60
+ end
61
+
62
+ def sh(cmd)
63
+ if @notify_method_name && verbose?
64
+ @notify_method_name = false
65
+ puts
66
+ puts method_name
67
+ end
68
+
69
+ start = Time.now
70
+ result = `#{cmd}`
71
+ finish = Time.now
72
+
73
+ if verbose?
74
+ elapsed = "%.3f" % [finish-start]
75
+ puts " (#{elapsed}s) #{cmd}"
76
+ end
77
+
78
+ result
79
+ end
80
+
81
+ def assert_script(script, options={})
82
+ _assert_script outdent(script), options
83
+ end
84
+
85
+ def _assert_script(script, options={})
86
+ parse_script(script, options).each do |cmd, output, status|
87
+ result = sh(cmd)
88
+
89
+ _assert_output_equal(output, result, cmd) if output
90
+ assert_equal(status, $?.exitstatus, cmd) if status
91
+ end
92
+ end
93
+
94
+ def assert_script_match(script, options={})
95
+ _assert_script_match outdent(script), options
96
+ end
97
+
98
+ def _assert_script_match(script, options={})
99
+ parse_script(script, options).each do |cmd, output, status|
100
+ result = sh(cmd)
101
+
102
+ _assert_alike(output, result, cmd) if output
103
+ assert_equal(status, $?.exitstatus, cmd) if status
104
+ end
105
+ end
106
+
107
+ # Asserts whether or not the a and b strings are equal, with a more
108
+ # readable output than assert_equal for large strings (especially large
109
+ # strings with significant whitespace).
110
+ def assert_output_equal(a, b, msg=nil)
111
+ _assert_output_equal outdent(a), b, msg
112
+ end
113
+
114
+ def _assert_output_equal(a, b, msg=nil)
115
+ if a == b
116
+ assert true
117
+ else
118
+ flunk %Q{
119
+ #{msg}
120
+ ==================== expected output ====================
121
+ #{whitespace_escape(a)}
122
+ ======================== but was ========================
123
+ #{whitespace_escape(b)}
124
+ =========================================================
125
+ }
126
+ end
127
+ end
128
+
129
+ # Asserts whether or not b is like a (which should be a Regexp), and
130
+ # provides a more readable output in the case of a failure as compared
131
+ # with assert_match.
132
+ #
133
+ # If a is a string it is turned into a RegexpEscape.
134
+ def assert_alike(a, b, msg=nil)
135
+ a = outdent(a) if a.kind_of?(String)
136
+ _assert_alike a, b, msg
137
+ end
138
+
139
+ def _assert_alike(a, b, msg=nil)
140
+ if a.kind_of?(String)
141
+ a = RegexpEscape.new(a)
142
+ end
143
+
144
+ if b =~ a
145
+ assert true
146
+ else
147
+ flunk %Q{
148
+ #{msg}
149
+ ================= expected output like ==================
150
+ #{whitespace_escape(a)}
151
+ ======================== but was ========================
152
+ #{whitespace_escape(b)}
153
+ =========================================================
154
+ }
155
+ end
156
+ end
157
+
158
+ # helper for stripping indentation off a string
159
+ def outdent(str)
160
+ str =~ /\A(?:\s*?\n)( *)(.*)\z/m ? $2.gsub!(/^ {0,#{$1.length}}/, '') : str
161
+ end
162
+
163
+ # helper for formatting escaping whitespace into readable text
164
+ def whitespace_escape(str)
165
+ str.to_s.gsub(/\s/) do |match|
166
+ case match
167
+ when "\n" then "\\n\n"
168
+ when "\t" then "\\t"
169
+ when "\r" then "\\r"
170
+ when "\f" then "\\f"
171
+ else match
172
+ end
173
+ end
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,72 @@
1
+ # :stopdoc:
2
+ module ShellTest
3
+ module Unit
4
+
5
+ # An exception class to flag skips.
6
+ class SkipException < StandardError
7
+ end
8
+
9
+ # Modifies how errors related to a SkipException are displayed.
10
+ module SkipDisplay
11
+ # Display S rather than E in the progress.
12
+ def single_character_display
13
+ "S"
14
+ end
15
+
16
+ # Removes the exception class from the message.
17
+ def message
18
+ @exception.message
19
+ end
20
+
21
+ # Updates the output to look like a MiniTest skip error.
22
+ def long_display
23
+ backtrace = filter_backtrace(@exception.backtrace)
24
+ "Skipped:\n#@test_name [#{backtrace[0].sub(/:in `.*$/, "")}]:\n#{message}\n"
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ require 'test/unit/testresult'
31
+ class Test::Unit::TestResult
32
+ # Returns an array of skips recorded for self.
33
+ def skips
34
+ @skips ||= []
35
+ end
36
+
37
+ # Partition errors from a SkipException from other errors and records as
38
+ # them as skips (the error is extended to display as a skip).
39
+ def add_error(error)
40
+ if error.exception.kind_of?(ShellTest::Unit::SkipException)
41
+ error.extend ShellTest::Unit::SkipDisplay
42
+ skips << error
43
+ else
44
+ @errors << error
45
+ end
46
+
47
+ notify_listeners(FAULT, error)
48
+ notify_listeners(CHANGED, self)
49
+ end
50
+
51
+ alias shell_test_original_to_s to_s
52
+
53
+ # Adds the skip count to the summary.
54
+ def to_s
55
+ "#{shell_test_original_to_s}, #{skips.length} skips"
56
+ end
57
+ end
58
+
59
+ require 'test/unit/testcase'
60
+ class Test::Unit::TestCase
61
+ # Alias method_name to __name__ such that FileMethods can redefine
62
+ # method_name to call __name__ (circular I know, but necessary for
63
+ # compatibility with MiniTest)
64
+ alias __name__ method_name
65
+
66
+ # Call to skip a test.
67
+ def skip(msg = nil, bt = caller)
68
+ msg ||= "Skipped, no message given"
69
+ raise ShellTest::Unit::SkipException, msg, bt
70
+ end
71
+ end
72
+ # :startdoc:
@@ -0,0 +1,40 @@
1
+ require 'test/unit'
2
+ require 'shell_test'
3
+
4
+ module ShellTest
5
+ # ShellTest is designed to work with MiniTest, which is the standard testing
6
+ # framework included in ruby 1.9. Minor changes in the API break backward
7
+ # compatibility with Test::Unit and/or add functionality expected by
8
+ # ShellTest.
9
+ #
10
+ # Test::Unit can be patched by requiring the shim file before defining
11
+ # specific TestCase subclasses.
12
+ #
13
+ # require 'test/unit'
14
+ # unless Object.const_defined?(:MiniTest)
15
+ # require 'shell_test/unit/shim'
16
+ # end
17
+ #
18
+ # To let ShellTest do this for you:
19
+ #
20
+ # require 'shell_test/unit'
21
+ #
22
+ # Note that the shim script has only been tested vs the Test::Unit that
23
+ # comes with ruby 1.8.x. A Test::Unit 2.0 gem exists; use with caution.
24
+ #
25
+ # ==== Patches
26
+ #
27
+ # The shim script adds two things to Test::Unit:
28
+ #
29
+ # 1) A __name__ method which returns the test method name (alias for
30
+ # method_name)
31
+ #
32
+ # 2) A skip method which can be used to skip a test (use it like flunk)
33
+ #
34
+ module Unit
35
+ end
36
+ end
37
+
38
+ unless Object.const_defined?(:MiniTest)
39
+ require 'shell_test/unit/shim'
40
+ end
@@ -0,0 +1,3 @@
1
+ module ShellTest
2
+ VERSION = "0.1.0"
3
+ end
data/lib/shell_test.rb ADDED
@@ -0,0 +1,8 @@
1
+ require 'shell_test/version'
2
+ require 'shell_test/file_methods'
3
+ require 'shell_test/shell_methods'
4
+
5
+ module ShellTest
6
+ include FileMethods
7
+ include ShellMethods
8
+ end
metadata ADDED
@@ -0,0 +1,85 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: shell_test
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - Simon Chiang
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-07-07 00:00:00 -06:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: Provides test modules to simplify testing of shell scripts. ShellTest is not a testing framework. ShellTest integrates with Test::Unit and MiniTest out of the box, but it should be possible to include the test modules into other test frameworks.
23
+ email:
24
+ - simon.a.chiang@gmail.com
25
+ executables: []
26
+
27
+ extensions: []
28
+
29
+ extra_rdoc_files:
30
+ - History.rdoc
31
+ - README.rdoc
32
+ - MIT-LICENSE
33
+ files:
34
+ - lib/shell_test.rb
35
+ - lib/shell_test/command_parser.rb
36
+ - lib/shell_test/file_methods.rb
37
+ - lib/shell_test/regexp_escape.rb
38
+ - lib/shell_test/shell_methods.rb
39
+ - lib/shell_test/unit.rb
40
+ - lib/shell_test/unit/shim.rb
41
+ - lib/shell_test/version.rb
42
+ - History.rdoc
43
+ - README.rdoc
44
+ - MIT-LICENSE
45
+ has_rdoc: true
46
+ homepage: ""
47
+ licenses: []
48
+
49
+ post_install_message:
50
+ rdoc_options:
51
+ - --main
52
+ - README.rdoc
53
+ - -S
54
+ - -N
55
+ - --title
56
+ - ShellTest
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ none: false
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ hash: 3
65
+ segments:
66
+ - 0
67
+ version: "0"
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ hash: 3
74
+ segments:
75
+ - 0
76
+ version: "0"
77
+ requirements: []
78
+
79
+ rubyforge_project: shell_test
80
+ rubygems_version: 1.6.2
81
+ signing_key:
82
+ specification_version: 3
83
+ summary: Test modules for shell scripts
84
+ test_files: []
85
+