spec 5.0.14

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +7 -0
  2. data/.autotest +34 -0
  3. data/.gitignore +3 -0
  4. data/History.txt +911 -0
  5. data/Manifest.txt +26 -0
  6. data/README.txt +497 -0
  7. data/Rakefile +214 -0
  8. data/design_rationale.rb +52 -0
  9. data/lib/hoe/minitest.rb +26 -0
  10. data/lib/minitest/assertions.rb +649 -0
  11. data/lib/minitest/autorun.rb +12 -0
  12. data/lib/minitest/benchmark.rb +423 -0
  13. data/lib/minitest/expectations.rb +268 -0
  14. data/lib/minitest/hell.rb +11 -0
  15. data/lib/minitest/mock.rb +220 -0
  16. data/lib/minitest/parallel_each.rb +120 -0
  17. data/lib/minitest/pride.rb +4 -0
  18. data/lib/minitest/pride_plugin.rb +143 -0
  19. data/lib/minitest/spec.rb +292 -0
  20. data/lib/minitest/test.rb +272 -0
  21. data/lib/minitest/unit.rb +45 -0
  22. data/lib/minitest.rb +839 -0
  23. data/lib/spec.rb +3 -0
  24. data/readme.md +7 -0
  25. data/release_notes.md +49 -0
  26. data/spec.gemspec +36 -0
  27. data/test/manual/appium.rb +14 -0
  28. data/test/manual/appium_after_last.rb +24 -0
  29. data/test/manual/appium_before_first.rb +23 -0
  30. data/test/manual/assert.rb +61 -0
  31. data/test/manual/before_first_0.rb +27 -0
  32. data/test/manual/before_first_1.rb +29 -0
  33. data/test/manual/debug.rb +37 -0
  34. data/test/manual/do_end.rb +31 -0
  35. data/test/manual/raise.rb +61 -0
  36. data/test/manual/run2.rb +74 -0
  37. data/test/manual/run3.rb +91 -0
  38. data/test/manual/setup.rb +13 -0
  39. data/test/manual/simple.rb +19 -0
  40. data/test/manual/simple2.rb +20 -0
  41. data/test/manual/t.rb +11 -0
  42. data/test/manual/trace.rb +19 -0
  43. data/test/manual/trace2.rb +15 -0
  44. data/test/minitest/metametameta.rb +78 -0
  45. data/test/minitest/test_helper.rb +20 -0
  46. data/test/minitest/test_minitest_benchmark.rb +131 -0
  47. data/test/minitest/test_minitest_mock.rb +490 -0
  48. data/test/minitest/test_minitest_reporter.rb +270 -0
  49. data/test/minitest/test_minitest_spec.rb +794 -0
  50. data/test/minitest/test_minitest_unit.rb +1846 -0
  51. metadata +147 -0
@@ -0,0 +1,220 @@
1
+ class MockExpectationError < StandardError; end # :nodoc:
2
+
3
+ module Minitest # :nodoc:
4
+
5
+ ##
6
+ # A simple and clean mock object framework.
7
+ #
8
+ # All mock objects are an instance of Mock
9
+
10
+ class Mock
11
+ alias :__respond_to? :respond_to?
12
+
13
+ overridden_methods = %w(
14
+ ===
15
+ inspect
16
+ object_id
17
+ public_send
18
+ respond_to_missing?
19
+ send
20
+ to_s
21
+ )
22
+
23
+ instance_methods.each do |m|
24
+ undef_method m unless overridden_methods.include?(m.to_s) || m =~ /^__/
25
+ end
26
+
27
+ overridden_methods.map(&:to_sym).each do |method_id|
28
+ define_method method_id do |*args, &b|
29
+ if @expected_calls.has_key? method_id then
30
+ method_missing(method_id, *args, &b)
31
+ else
32
+ super(*args, &b)
33
+ end
34
+ end
35
+ end
36
+
37
+ def initialize # :nodoc:
38
+ @expected_calls = Hash.new { |calls, name| calls[name] = [] }
39
+ @actual_calls = Hash.new { |calls, name| calls[name] = [] }
40
+ end
41
+
42
+ ##
43
+ # Expect that method +name+ is called, optionally with +args+ or a
44
+ # +blk+, and returns +retval+.
45
+ #
46
+ # @mock.expect(:meaning_of_life, 42)
47
+ # @mock.meaning_of_life # => 42
48
+ #
49
+ # @mock.expect(:do_something_with, true, [some_obj, true])
50
+ # @mock.do_something_with(some_obj, true) # => true
51
+ #
52
+ # @mock.expect(:do_something_else, true) do |a1, a2|
53
+ # a1 == "buggs" && a2 == :bunny
54
+ # end
55
+ #
56
+ # +args+ is compared to the expected args using case equality (ie, the
57
+ # '===' operator), allowing for less specific expectations.
58
+ #
59
+ # @mock.expect(:uses_any_string, true, [String])
60
+ # @mock.uses_any_string("foo") # => true
61
+ # @mock.verify # => true
62
+ #
63
+ # @mock.expect(:uses_one_string, true, ["foo"])
64
+ # @mock.uses_one_string("bar") # => true
65
+ # @mock.verify # => raises MockExpectationError
66
+
67
+ def expect(name, retval, args=[], &blk)
68
+ name = name.to_sym
69
+
70
+ if block_given?
71
+ raise ArgumentError, "args ignored when block given" unless args.empty?
72
+ @expected_calls[name] << { :retval => retval, :block => blk }
73
+ else
74
+ raise ArgumentError, "args must be an array" unless Array === args
75
+ @expected_calls[name] << { :retval => retval, :args => args }
76
+ end
77
+ self
78
+ end
79
+
80
+ def __call name, data # :nodoc:
81
+ case data
82
+ when Hash then
83
+ "#{name}(#{data[:args].inspect[1..-2]}) => #{data[:retval].inspect}"
84
+ else
85
+ data.map { |d| __call name, d }.join ", "
86
+ end
87
+ end
88
+
89
+ ##
90
+ # Verify that all methods were called as expected. Raises
91
+ # +MockExpectationError+ if the mock object was not called as
92
+ # expected.
93
+
94
+ def verify
95
+ @expected_calls.each do |name, calls|
96
+ calls.each do |expected|
97
+ msg1 = "expected #{__call name, expected}"
98
+ msg2 = "#{msg1}, got [#{__call name, @actual_calls[name]}]"
99
+
100
+ raise MockExpectationError, msg2 if
101
+ @actual_calls.has_key?(name) and
102
+ not @actual_calls[name].include?(expected)
103
+
104
+ raise MockExpectationError, msg1 unless
105
+ @actual_calls.has_key?(name) and
106
+ @actual_calls[name].include?(expected)
107
+ end
108
+ end
109
+ true
110
+ end
111
+
112
+ def method_missing(sym, *args) # :nodoc:
113
+ unless @expected_calls.has_key?(sym) then
114
+ raise NoMethodError, "unmocked method %p, expected one of %p" %
115
+ [sym, @expected_calls.keys.sort_by(&:to_s)]
116
+ end
117
+
118
+ index = @actual_calls[sym].length
119
+ expected_call = @expected_calls[sym][index]
120
+
121
+ unless expected_call then
122
+ raise MockExpectationError, "No more expects available for %p: %p" %
123
+ [sym, args]
124
+ end
125
+
126
+ expected_args, retval, val_block =
127
+ expected_call.values_at(:args, :retval, :block)
128
+
129
+ if val_block then
130
+ raise MockExpectationError, "mocked method %p failed block w/ %p" %
131
+ [sym, args] unless val_block.call(args)
132
+
133
+ # keep "verify" happy
134
+ @actual_calls[sym] << expected_call
135
+ return retval
136
+ end
137
+
138
+ if expected_args.size != args.size then
139
+ raise ArgumentError, "mocked method %p expects %d arguments, got %d" %
140
+ [sym, expected_args.size, args.size]
141
+ end
142
+
143
+ fully_matched = expected_args.zip(args).all? { |mod, a|
144
+ mod === a or mod == a
145
+ }
146
+
147
+ unless fully_matched then
148
+ raise MockExpectationError, "mocked method %p called with unexpected arguments %p" %
149
+ [sym, args]
150
+ end
151
+
152
+ @actual_calls[sym] << {
153
+ :retval => retval,
154
+ :args => expected_args.zip(args).map { |mod, a| mod === a ? mod : a }
155
+ }
156
+
157
+ retval
158
+ end
159
+
160
+ def respond_to?(sym, include_private = false) # :nodoc:
161
+ return true if @expected_calls.has_key? sym.to_sym
162
+ return __respond_to?(sym, include_private)
163
+ end
164
+ end
165
+ end
166
+
167
+ class Object # :nodoc:
168
+
169
+ ##
170
+ # Add a temporary stubbed method replacing +name+ for the duration
171
+ # of the +block+. If +val_or_callable+ responds to #call, then it
172
+ # returns the result of calling it, otherwise returns the value
173
+ # as-is. If stubbed method yields a block, +block_args+ will be
174
+ # passed along. Cleans up the stub at the end of the +block+. The
175
+ # method +name+ must exist before stubbing.
176
+ #
177
+ # def test_stale_eh
178
+ # obj_under_test = Something.new
179
+ # refute obj_under_test.stale?
180
+ #
181
+ # Time.stub :now, Time.at(0) do
182
+ # assert obj_under_test.stale?
183
+ # end
184
+ # end
185
+ #
186
+
187
+ def stub name, val_or_callable, *block_args, &block
188
+ new_name = "__minitest_stub__#{name}"
189
+
190
+ metaclass = class << self; self; end
191
+
192
+ if respond_to? name and not methods.map(&:to_s).include? name.to_s then
193
+ metaclass.send :define_method, name do |*args|
194
+ super(*args)
195
+ end
196
+ end
197
+
198
+ metaclass.send :alias_method, new_name, name
199
+
200
+ metaclass.send :define_method, name do |*args, &blk|
201
+
202
+ ret = if val_or_callable.respond_to? :call then
203
+ val_or_callable.call(*args)
204
+ else
205
+ val_or_callable
206
+ end
207
+
208
+ blk.call(*block_args) if blk
209
+
210
+ ret
211
+ end
212
+
213
+ yield self
214
+ ensure
215
+ metaclass.send :undef_method, name
216
+ metaclass.send :alias_method, name, new_name
217
+ metaclass.send :undef_method, new_name
218
+ end
219
+
220
+ end
@@ -0,0 +1,120 @@
1
+ ##
2
+ # Provides a parallel #each that lets you enumerate using N threads.
3
+ # Use environment variable N to customize. Defaults to 2. Enumerable,
4
+ # so all the goodies come along (tho not all are wrapped yet to
5
+ # return another ParallelEach instance).
6
+
7
+ class Minitest::ParallelEach
8
+ require 'thread'
9
+ include Enumerable
10
+
11
+ ##
12
+ # How many Threads to use for this parallel #each.
13
+
14
+ N = (ENV['N'] || 2).to_i
15
+
16
+ ##
17
+ # Create a new ParallelEach instance over +list+.
18
+
19
+ def initialize list
20
+ @queue = Queue.new # *sigh*... the Queue api sucks sooo much...
21
+
22
+ list.each { |i| @queue << i }
23
+ N.times { @queue << nil }
24
+ end
25
+
26
+ def select(&block) # :nodoc:
27
+ self.class.new super
28
+ end
29
+
30
+ alias find_all select # :nodoc:
31
+
32
+ ##
33
+ # Starts N threads that yield each element to your block. Joins the
34
+ # threads at the end.
35
+
36
+ def each
37
+ threads = N.times.map {
38
+ Thread.new do
39
+ Thread.current.abort_on_exception = true
40
+ while job = @queue.pop
41
+ yield job
42
+ end
43
+ end
44
+ }
45
+ threads.map(&:join)
46
+ end
47
+
48
+ def count # :nodoc:
49
+ [@queue.size - N, 0].max
50
+ end
51
+
52
+ alias_method :size, :count # :nodoc:
53
+ end
54
+
55
+ module Minitest
56
+ class << self
57
+ remove_method :__run
58
+ end
59
+
60
+ class Test
61
+ @mutex = Mutex.new
62
+
63
+ def self.synchronize # :nodoc:
64
+ if @mutex then # see parallel_each.rb
65
+ @mutex.synchronize { yield }
66
+ else
67
+ yield
68
+ end
69
+ end
70
+
71
+ alias :simple_capture_io :capture_io
72
+
73
+ def capture_io(&b)
74
+ Test.synchronize do
75
+ simple_capture_io(&b)
76
+ end
77
+ end
78
+
79
+ alias :simple_capture_subprocess_io :capture_subprocess_io
80
+
81
+ def capture_subprocess_io(&b)
82
+ Test.synchronize do
83
+ simple_capture_subprocess_io(&b)
84
+ end
85
+ end
86
+ end
87
+
88
+ class Reporter
89
+ @mutex = Mutex.new
90
+
91
+ def self.synchronize # :nodoc:
92
+ if @mutex then # see parallel_each.rb
93
+ @mutex.synchronize { yield }
94
+ else
95
+ yield
96
+ end
97
+ end
98
+
99
+ alias :simple_record :record
100
+
101
+ def record result
102
+ Reporter.synchronize do
103
+ simple_record result
104
+ end
105
+ end
106
+ end
107
+
108
+ ##
109
+ # Runs all the +suites+ for a given +type+. Runs suites declaring
110
+ # a test_order of +:parallel+ in parallel, and everything else
111
+ # serial.
112
+
113
+ def self.__run reporter, options
114
+ suites = Runnable.runnables
115
+ parallel, serial = suites.partition { |s| s.test_order == :parallel }
116
+
117
+ ParallelEach.new(parallel).map { |suite| suite.run reporter, options } +
118
+ serial.map { |suite| suite.run reporter, options }
119
+ end
120
+ end
@@ -0,0 +1,4 @@
1
+ require "minitest"
2
+
3
+ Minitest.load_plugins
4
+ Minitest::PrideIO.pride!
@@ -0,0 +1,143 @@
1
+ require "minitest/autorun"
2
+
3
+ module Minitest
4
+ def self.plugin_pride_options opts, options # :nodoc:
5
+ opts.on "-p", "--pride", "Pride. Show your testing pride!" do
6
+ PrideIO.pride!
7
+ end
8
+ end
9
+
10
+ def self.plugin_pride_init options # :nodoc:
11
+ if PrideIO.pride? then
12
+ klass = ENV["TERM"] =~ /^xterm|-256color$/ ? PrideLOL : PrideIO
13
+ io = klass.new options[:io]
14
+
15
+ self.reporter.reporters.grep(Minitest::Reporter).each do |rep|
16
+ rep.io = io
17
+ end
18
+ end
19
+ end
20
+
21
+ ##
22
+ # Show your testing pride!
23
+
24
+ class PrideIO
25
+ ##
26
+ # Activate the pride plugin. Called from both -p option and minitest/pride
27
+
28
+ def self.pride!
29
+ @pride = true
30
+ end
31
+
32
+ ##
33
+ # Are we showing our testing pride?
34
+
35
+ def self.pride?
36
+ @pride ||= false
37
+ end
38
+
39
+ # Start an escape sequence
40
+ ESC = "\e["
41
+
42
+ # End the escape sequence
43
+ NND = "#{ESC}0m"
44
+
45
+ # The IO we're going to pipe through.
46
+ attr_reader :io
47
+
48
+ def initialize io # :nodoc:
49
+ @io = io
50
+ # stolen from /System/Library/Perl/5.10.0/Term/ANSIColor.pm
51
+ # also reference http://en.wikipedia.org/wiki/ANSI_escape_code
52
+ @colors ||= (31..36).to_a
53
+ @size = @colors.size
54
+ @index = 0
55
+ # io.sync = true
56
+ end
57
+
58
+ ##
59
+ # Wrap print to colorize the output.
60
+
61
+ def print o
62
+ case o
63
+ when "." then
64
+ io.print pride o
65
+ when "E", "F" then
66
+ io.print "#{ESC}41m#{ESC}37m#{o}#{NND}"
67
+ when "S" then
68
+ io.print pride o
69
+ else
70
+ io.print o
71
+ end
72
+ end
73
+
74
+ def puts(*o) # :nodoc:
75
+ o.map! { |s|
76
+ s.to_s.sub(/Finished/) {
77
+ @index = 0
78
+ 'Fabulous run'.split(//).map { |c|
79
+ pride(c)
80
+ }.join
81
+ }
82
+ }
83
+
84
+ io.puts(*o)
85
+ end
86
+
87
+ ##
88
+ # Color a string.
89
+
90
+ def pride string
91
+ string = "*" if string == "."
92
+ c = @colors[@index % @size]
93
+ @index += 1
94
+ "#{ESC}#{c}m#{string}#{NND}"
95
+ end
96
+
97
+ def method_missing msg, *args # :nodoc:
98
+ io.send(msg, *args)
99
+ end
100
+ end
101
+
102
+ ##
103
+ # If you thought the PrideIO was colorful...
104
+ #
105
+ # (Inspired by lolcat, but with clean math)
106
+
107
+ class PrideLOL < PrideIO
108
+ PI_3 = Math::PI / 3 # :nodoc:
109
+
110
+ def initialize io # :nodoc:
111
+ # walk red, green, and blue around a circle separated by equal thirds.
112
+ #
113
+ # To visualize, type this into wolfram-alpha:
114
+ #
115
+ # plot (3*sin(x)+3), (3*sin(x+2*pi/3)+3), (3*sin(x+4*pi/3)+3)
116
+
117
+ # 6 has wide pretty gradients. 3 == lolcat, about half the width
118
+ @colors = (0...(6 * 7)).map { |n|
119
+ n *= 1.0 / 6
120
+ r = (3 * Math.sin(n ) + 3).to_i
121
+ g = (3 * Math.sin(n + 2 * PI_3) + 3).to_i
122
+ b = (3 * Math.sin(n + 4 * PI_3) + 3).to_i
123
+
124
+ # Then we take rgb and encode them in a single number using base 6.
125
+ # For some mysterious reason, we add 16... to clear the bottom 4 bits?
126
+ # Yes... they're ugly.
127
+
128
+ 36 * r + 6 * g + b + 16
129
+ }
130
+
131
+ super
132
+ end
133
+
134
+ ##
135
+ # Make the string even more colorful. Damnit.
136
+
137
+ def pride string
138
+ c = @colors[@index % @size]
139
+ @index += 1
140
+ "#{ESC}38;5;#{c}m#{string}#{NND}"
141
+ end
142
+ end
143
+ end