spec 5.0.19 → 5.3.3
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 +4 -4
- data/History.txt +106 -0
- data/Manifest.txt +1 -1
- data/README.txt +83 -37
- data/Rakefile +3 -56
- data/lib/minitest.rb +58 -156
- data/lib/minitest/assertions.rb +13 -1
- data/lib/minitest/benchmark.rb +3 -3
- data/lib/minitest/hell.rb +1 -1
- data/lib/minitest/mock.rb +2 -2
- data/lib/minitest/parallel.rb +40 -0
- data/lib/minitest/pride_plugin.rb +1 -2
- data/lib/minitest/spec.rb +23 -22
- data/lib/minitest/test.rb +19 -8
- data/lib/spec.rb +156 -2
- data/readme.md +1 -1
- data/spec.gemspec +2 -2
- data/test/manual/simple.rb +10 -15
- data/test/minitest/metametameta.rb +4 -2
- data/test/minitest/test_minitest_benchmark.rb +7 -1
- data/test/minitest/test_minitest_mock.rb +12 -2
- data/test/minitest/test_minitest_reporter.rb +0 -1
- data/test/minitest/test_minitest_spec.rb +41 -4
- data/test/minitest/test_minitest_unit.rb +38 -20
- metadata +15 -37
- data/lib/minitest/parallel_each.rb +0 -120
- data/release_notes.md +0 -80
- data/test/manual/after_run.rb +0 -17
- data/test/manual/appium.rb +0 -14
- data/test/manual/appium_after_last.rb +0 -24
- data/test/manual/appium_before_first.rb +0 -23
- data/test/manual/assert.rb +0 -61
- data/test/manual/before_first_0.rb +0 -27
- data/test/manual/before_first_1.rb +0 -29
- data/test/manual/ctrl_c.rb +0 -11
- data/test/manual/debug.rb +0 -37
- data/test/manual/do_end.rb +0 -31
- data/test/manual/raise.rb +0 -61
- data/test/manual/run2.rb +0 -74
- data/test/manual/run3.rb +0 -91
- data/test/manual/setup.rb +0 -13
- data/test/manual/simple2.rb +0 -20
- data/test/manual/skip.rb +0 -15
- data/test/manual/t.rb +0 -11
- data/test/manual/trace.rb +0 -19
- data/test/manual/trace2.rb +0 -15
- data/test/minitest/test_helper.rb +0 -20
data/lib/minitest/assertions.rb
CHANGED
@@ -6,7 +6,7 @@ module Minitest
|
|
6
6
|
# printed if the assertion fails.
|
7
7
|
#
|
8
8
|
# Protocol: Nearly everything here boils up to +assert+, which
|
9
|
-
# expects to be able to increment an instance
|
9
|
+
# expects to be able to increment an instance accessor named
|
10
10
|
# +assertions+. This is not provided by Assertions and must be
|
11
11
|
# provided by the thing including Assertions. See Minitest::Runnable
|
12
12
|
# for an example.
|
@@ -131,6 +131,10 @@ module Minitest
|
|
131
131
|
true
|
132
132
|
end
|
133
133
|
|
134
|
+
def _synchronize # :nodoc:
|
135
|
+
yield
|
136
|
+
end
|
137
|
+
|
134
138
|
##
|
135
139
|
# Fails unless +obj+ is empty.
|
136
140
|
|
@@ -393,6 +397,8 @@ module Minitest
|
|
393
397
|
# that.
|
394
398
|
|
395
399
|
def capture_io
|
400
|
+
_synchronize do
|
401
|
+
begin
|
396
402
|
require 'stringio'
|
397
403
|
|
398
404
|
captured_stdout, captured_stderr = StringIO.new, StringIO.new
|
@@ -406,6 +412,8 @@ module Minitest
|
|
406
412
|
ensure
|
407
413
|
$stdout = orig_stdout
|
408
414
|
$stderr = orig_stderr
|
415
|
+
end
|
416
|
+
end
|
409
417
|
end
|
410
418
|
|
411
419
|
##
|
@@ -424,6 +432,8 @@ module Minitest
|
|
424
432
|
# only use it when you need to test the output of a subprocess.
|
425
433
|
|
426
434
|
def capture_subprocess_io
|
435
|
+
_synchronize do
|
436
|
+
begin
|
427
437
|
require 'tempfile'
|
428
438
|
|
429
439
|
captured_stdout, captured_stderr = Tempfile.new("out"), Tempfile.new("err")
|
@@ -443,6 +453,8 @@ module Minitest
|
|
443
453
|
captured_stderr.unlink
|
444
454
|
$stdout.reopen orig_stdout
|
445
455
|
$stderr.reopen orig_stderr
|
456
|
+
end
|
457
|
+
end
|
446
458
|
end
|
447
459
|
|
448
460
|
##
|
data/lib/minitest/benchmark.rb
CHANGED
@@ -376,7 +376,7 @@ module Minitest
|
|
376
376
|
##
|
377
377
|
# Create a benchmark that verifies that the performance is linear.
|
378
378
|
#
|
379
|
-
# describe "my class" do
|
379
|
+
# describe "my class Bench" do
|
380
380
|
# bench_performance_linear "fast_algorithm", 0.9999 do |n|
|
381
381
|
# @obj.fast_algorithm(n)
|
382
382
|
# end
|
@@ -391,7 +391,7 @@ module Minitest
|
|
391
391
|
##
|
392
392
|
# Create a benchmark that verifies that the performance is constant.
|
393
393
|
#
|
394
|
-
# describe "my class" do
|
394
|
+
# describe "my class Bench" do
|
395
395
|
# bench_performance_constant "zoom_algorithm!" do |n|
|
396
396
|
# @obj.zoom_algorithm!(n)
|
397
397
|
# end
|
@@ -406,7 +406,7 @@ module Minitest
|
|
406
406
|
##
|
407
407
|
# Create a benchmark that verifies that the performance is exponential.
|
408
408
|
#
|
409
|
-
# describe "my class" do
|
409
|
+
# describe "my class Bench" do
|
410
410
|
# bench_performance_exponential "algorithm" do |n|
|
411
411
|
# @obj.algorithm(n)
|
412
412
|
# end
|
data/lib/minitest/hell.rb
CHANGED
data/lib/minitest/mock.rb
CHANGED
@@ -109,7 +109,7 @@ module Minitest # :nodoc:
|
|
109
109
|
true
|
110
110
|
end
|
111
111
|
|
112
|
-
def method_missing(sym, *args) # :nodoc:
|
112
|
+
def method_missing(sym, *args, &block) # :nodoc:
|
113
113
|
unless @expected_calls.has_key?(sym) then
|
114
114
|
raise NoMethodError, "unmocked method %p, expected one of %p" %
|
115
115
|
[sym, @expected_calls.keys.sort_by(&:to_s)]
|
@@ -128,7 +128,7 @@ module Minitest # :nodoc:
|
|
128
128
|
|
129
129
|
if val_block then
|
130
130
|
raise MockExpectationError, "mocked method %p failed block w/ %p" %
|
131
|
-
[sym, args] unless val_block.call(args)
|
131
|
+
[sym, args] unless val_block.call(*args, &block)
|
132
132
|
|
133
133
|
# keep "verify" happy
|
134
134
|
@actual_calls[sym] << expected_call
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Minitest
|
2
|
+
module Parallel
|
3
|
+
class Executor
|
4
|
+
attr_reader :size
|
5
|
+
|
6
|
+
def initialize size
|
7
|
+
@size = size
|
8
|
+
@queue = Queue.new
|
9
|
+
@pool = size.times.map {
|
10
|
+
Thread.new(@queue) do |queue|
|
11
|
+
Thread.current.abort_on_exception = true
|
12
|
+
while job = queue.pop
|
13
|
+
klass, method, reporter = job
|
14
|
+
result = Minitest.run_one_method klass, method
|
15
|
+
reporter.synchronize { reporter.record result }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
def << work; @queue << work; end
|
22
|
+
|
23
|
+
def shutdown
|
24
|
+
size.times { @queue << nil }
|
25
|
+
@pool.each(&:join)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
module Test
|
30
|
+
def _synchronize; Test.io_lock.synchronize { yield }; end
|
31
|
+
|
32
|
+
module ClassMethods
|
33
|
+
def run_one_method klass, method_name, reporter
|
34
|
+
Minitest.parallel_executor << [klass, method_name, reporter]
|
35
|
+
end
|
36
|
+
def test_order; :parallel; end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require "minitest
|
1
|
+
require "minitest"
|
2
2
|
|
3
3
|
module Minitest
|
4
4
|
def self.plugin_pride_options opts, options # :nodoc:
|
@@ -52,7 +52,6 @@ module Minitest
|
|
52
52
|
@colors ||= (31..36).to_a
|
53
53
|
@size = @colors.size
|
54
54
|
@index = 0
|
55
|
-
# io.sync = true
|
56
55
|
end
|
57
56
|
|
58
57
|
##
|
data/lib/minitest/spec.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
#!/usr/bin/ruby -w
|
2
|
-
|
3
1
|
require 'minitest/unit'
|
4
2
|
|
5
3
|
class Module # :nodoc:
|
@@ -8,10 +6,10 @@ class Module # :nodoc:
|
|
8
6
|
self.class_eval <<-EOM
|
9
7
|
def #{new_name} *args
|
10
8
|
case
|
11
|
-
when Proc === self then
|
12
|
-
Minitest::Spec.current.#{meth}(*args, &self)
|
13
9
|
when #{!!dont_flip} then
|
14
10
|
Minitest::Spec.current.#{meth}(self, *args)
|
11
|
+
when Proc === self then
|
12
|
+
Minitest::Spec.current.#{meth}(*args, &self)
|
15
13
|
else
|
16
14
|
Minitest::Spec.current.#{meth}(args.first, self, *args[1..-1])
|
17
15
|
end
|
@@ -161,13 +159,6 @@ class Minitest::Spec < Minitest::Test
|
|
161
159
|
end
|
162
160
|
end
|
163
161
|
|
164
|
-
def before_first type = nil, &block
|
165
|
-
define_method :before_first_method do
|
166
|
-
super()
|
167
|
-
self.instance_eval(&block)
|
168
|
-
end
|
169
|
-
end
|
170
|
-
|
171
162
|
##
|
172
163
|
# Define a 'before' action. Inherits the way normal methods should.
|
173
164
|
#
|
@@ -196,13 +187,6 @@ class Minitest::Spec < Minitest::Test
|
|
196
187
|
end
|
197
188
|
end
|
198
189
|
|
199
|
-
def after_last type = nil, &block
|
200
|
-
define_method :after_last_method do
|
201
|
-
self.instance_eval(&block)
|
202
|
-
super()
|
203
|
-
end
|
204
|
-
end
|
205
|
-
|
206
190
|
##
|
207
191
|
# Define an expectation with name +desc+. Name gets morphed to a
|
208
192
|
# proper test method name. For some freakish reason, people who
|
@@ -211,7 +195,7 @@ class Minitest::Spec < Minitest::Test
|
|
211
195
|
#
|
212
196
|
# This is also aliased to #specify and doesn't require a +desc+ arg.
|
213
197
|
#
|
214
|
-
# Hint: If you _do_ want
|
198
|
+
# Hint: If you _do_ want inheritance, use minitest/test. You can mix
|
215
199
|
# and match between assertions and expectations as much as you want.
|
216
200
|
|
217
201
|
def it desc = "anonymous", &block
|
@@ -231,15 +215,20 @@ class Minitest::Spec < Minitest::Test
|
|
231
215
|
name
|
232
216
|
end
|
233
217
|
|
234
|
-
alias_method :t, :it
|
235
|
-
|
236
218
|
##
|
237
219
|
# Essentially, define an accessor for +name+ with +block+.
|
238
220
|
#
|
239
221
|
# Why use let instead of def? I honestly don't know.
|
240
222
|
|
241
223
|
def let name, &block
|
242
|
-
|
224
|
+
name = name.to_s
|
225
|
+
pre, post = "let '#{name}' cannot ", ". Please use another name."
|
226
|
+
methods = Minitest::Spec.instance_methods.map(&:to_s) - %w[subject]
|
227
|
+
raise ArgumentError, "#{pre}begin with 'test'#{post}" if
|
228
|
+
name =~ /\Atest/
|
229
|
+
raise ArgumentError, "#{pre}override a method in Minitest::Spec#{post}" if
|
230
|
+
methods.include? name
|
231
|
+
|
243
232
|
define_method name do
|
244
233
|
@_memoized ||= {}
|
245
234
|
@_memoized.fetch(name) { |k| @_memoized[k] = instance_eval(&block) }
|
@@ -278,6 +267,18 @@ class Minitest::Spec < Minitest::Test
|
|
278
267
|
# :stopdoc:
|
279
268
|
attr_reader :desc
|
280
269
|
alias :specify :it
|
270
|
+
|
271
|
+
module InstanceMethods
|
272
|
+
def before_setup
|
273
|
+
super
|
274
|
+
Thread.current[:current_spec] = self
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
def self.extended obj
|
279
|
+
obj.send :include, InstanceMethods
|
280
|
+
end
|
281
|
+
|
281
282
|
# :startdoc:
|
282
283
|
end
|
283
284
|
|
data/lib/minitest/test.rb
CHANGED
@@ -14,6 +14,9 @@ module Minitest
|
|
14
14
|
PASSTHROUGH_EXCEPTIONS = [NoMemoryError, SignalException, # :nodoc:
|
15
15
|
Interrupt, SystemExit]
|
16
16
|
|
17
|
+
class << self; attr_accessor :io_lock; end
|
18
|
+
self.io_lock = Mutex.new
|
19
|
+
|
17
20
|
##
|
18
21
|
# Call this at the top of your tests when you absolutely
|
19
22
|
# positively need to have ordered tests. In doing so, you're
|
@@ -46,19 +49,27 @@ module Minitest
|
|
46
49
|
# and your tests are awesome.
|
47
50
|
|
48
51
|
def self.parallelize_me!
|
49
|
-
|
50
|
-
|
51
|
-
class << self
|
52
|
-
undef_method :test_order if method_defined? :test_order
|
53
|
-
define_method :test_order do :parallel end
|
54
|
-
end
|
52
|
+
include Minitest::Parallel::Test
|
53
|
+
extend Minitest::Parallel::Test::ClassMethods
|
55
54
|
end
|
56
55
|
|
57
56
|
##
|
58
|
-
# Returns all instance methods starting with "test_".
|
57
|
+
# Returns all instance methods starting with "test_". Based on
|
58
|
+
# #test_order, the methods are either sorted, randomized
|
59
|
+
# (default), or run in parallel.
|
59
60
|
|
60
61
|
def self.runnable_methods
|
61
|
-
methods_matching(/^test_/)
|
62
|
+
methods = methods_matching(/^test_/)
|
63
|
+
|
64
|
+
case self.test_order
|
65
|
+
when :random, :parallel then
|
66
|
+
max = methods.size
|
67
|
+
methods.sort.sort_by { rand max }
|
68
|
+
when :alpha, :sorted then
|
69
|
+
methods.sort
|
70
|
+
else
|
71
|
+
raise "Unknown test_order: #{self.test_order.inspect}"
|
72
|
+
end
|
62
73
|
end
|
63
74
|
|
64
75
|
##
|
data/lib/spec.rb
CHANGED
@@ -1,3 +1,157 @@
|
|
1
1
|
# enable require 'spec'
|
2
|
-
|
3
|
-
|
2
|
+
require_relative 'minitest'
|
3
|
+
require_relative 'minitest/spec'
|
4
|
+
|
5
|
+
# patches to enable Appium spec
|
6
|
+
|
7
|
+
require 'rubygems'
|
8
|
+
require 'chronic_duration'
|
9
|
+
|
10
|
+
|
11
|
+
module Minitest
|
12
|
+
# override minitest.rb __run so tests execute serially
|
13
|
+
def self.__run reporter, options
|
14
|
+
Runnable.runnables.each do |runnable|
|
15
|
+
runnable.run reporter, options
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
##
|
20
|
+
# Trace file source to :io (default $stdout)
|
21
|
+
#
|
22
|
+
# spec_opts = {}
|
23
|
+
#
|
24
|
+
# @param :trace [Array<String>] the files to trace
|
25
|
+
# @param :io [IO] io to print to
|
26
|
+
def self.trace_specs spec_opts
|
27
|
+
targets = []
|
28
|
+
files = {}
|
29
|
+
last_file = ''
|
30
|
+
last_line = -1
|
31
|
+
|
32
|
+
files_to_trace = spec_opts.fetch(:trace, []);
|
33
|
+
io = spec_opts.fetch(:io, $stdout)
|
34
|
+
color = spec_opts.fetch(:color, "\e[32m") # ANSI.green default
|
35
|
+
# target only existing readable files
|
36
|
+
files_to_trace.each do |f|
|
37
|
+
if File.exists?(f) && File.readable?(f)
|
38
|
+
targets.push File.expand_path f
|
39
|
+
targets.push File.basename f # sometimes the file is relative
|
40
|
+
end
|
41
|
+
end
|
42
|
+
return if targets.empty?
|
43
|
+
|
44
|
+
set_trace_func(lambda do |event, file, line, id, binding, classname|
|
45
|
+
return unless targets.include?(file)
|
46
|
+
|
47
|
+
# never repeat a line
|
48
|
+
return if file == last_file && line == last_line
|
49
|
+
|
50
|
+
file_sym = file.intern
|
51
|
+
files[file_sym] = IO.readlines(file) if files[file_sym].nil?
|
52
|
+
lines = files[file_sym]
|
53
|
+
|
54
|
+
# arrays are 0 indexed and line numbers start at one.
|
55
|
+
io.print color if color # ANSI code
|
56
|
+
io.puts lines[line - 1]
|
57
|
+
io.print "\e[0m" if color # ANSI.clear
|
58
|
+
|
59
|
+
last_file = file
|
60
|
+
last_line = line
|
61
|
+
|
62
|
+
end)
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.on_exit exit_code
|
66
|
+
@@after_run.reverse_each(&:call)
|
67
|
+
exit exit_code || false
|
68
|
+
end
|
69
|
+
|
70
|
+
##
|
71
|
+
# Run specs. Does not print dots (ProgressReporter)
|
72
|
+
#
|
73
|
+
# spec_opts
|
74
|
+
# @param :io [Array<String>] defaults to $stdout
|
75
|
+
# @param :trace [Array<String>] files to trace
|
76
|
+
def self.run_specs spec_opts={}
|
77
|
+
options = { :io => spec_opts.fetch(:io, $stdout),
|
78
|
+
:verbose => spec_opts.fetch(:verbose, false) }
|
79
|
+
reporter = Minitest::CompositeReporter.new
|
80
|
+
reporter << Minitest::SummaryReporter.new(options[:io], options)
|
81
|
+
reporter.start
|
82
|
+
|
83
|
+
at_exit { on_exit reporter.passed? }
|
84
|
+
# exit on ctrl+c to trigger at_exit
|
85
|
+
trap('SIGINT') { exit }
|
86
|
+
|
87
|
+
trace_specs spec_opts
|
88
|
+
|
89
|
+
Minitest.__run reporter, options
|
90
|
+
reporter.reporters.each { |r| r.report }
|
91
|
+
end
|
92
|
+
|
93
|
+
##
|
94
|
+
# Responsible for running all runnable methods in a given class,
|
95
|
+
# each in its own instance. Each instance is passed to the
|
96
|
+
# reporter to record.
|
97
|
+
|
98
|
+
def self.run reporter, options = {}
|
99
|
+
filter = options[:filter] || '/./'
|
100
|
+
filter = Regexp.new $1 if filter =~ /\/(.*)\//
|
101
|
+
|
102
|
+
filtered_methods = self.runnable_methods.find_all { |m|
|
103
|
+
filter === m || filter === "#{self}##{m}"
|
104
|
+
}
|
105
|
+
|
106
|
+
with_info_handler reporter do
|
107
|
+
filtered_methods.each do |method_name|
|
108
|
+
|
109
|
+
method = self.new(method_name)
|
110
|
+
matched_name = method_name.match /test_(\d+)_/
|
111
|
+
if matched_name
|
112
|
+
test_number = matched_name[1].to_i
|
113
|
+
test_name = method_name.split(/_\d+_/).last
|
114
|
+
file_path, line_number = method.method(method_name).source_location
|
115
|
+
# /5/4/3/2/1/test.rb => 2/1/test.rb
|
116
|
+
file_path = file_path.split(File::SEPARATOR).reject(&:empty?)
|
117
|
+
file_path = (file_path.length >= 3 ? file_path[-3..-1] :
|
118
|
+
file_path).join(File::SEPARATOR)
|
119
|
+
# 36 = cyan, 0 = clear
|
120
|
+
test_output_title = "\e[36m#{test_name} | #{test_number} |" +
|
121
|
+
"#{file_path}:#{line_number}\e[0m"
|
122
|
+
io.puts test_output_title
|
123
|
+
end
|
124
|
+
|
125
|
+
run_one_method self, method_name, reporter
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
class Test < Runnable
|
131
|
+
# override lib/minitest/test.rb so methods execute in the exact order they are defined
|
132
|
+
def self.runnable_methods
|
133
|
+
methods_matching(/^test_/)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
class SummaryReporter < StatisticsReporter
|
138
|
+
# remove dots
|
139
|
+
def start # :nodoc:
|
140
|
+
super
|
141
|
+
|
142
|
+
self.sync = io.respond_to? :"sync=" # stupid emacs
|
143
|
+
self.old_sync, io.sync = io.sync, true if self.sync
|
144
|
+
end
|
145
|
+
|
146
|
+
# customize stats
|
147
|
+
def statistics # :nodoc:
|
148
|
+
"Finished in #{ChronicDuration.output(total_time.round) || '0s'}"
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
class Minitest::Spec < Minitest::Test
|
153
|
+
module DSL
|
154
|
+
alias_method :t, :it
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|