minitest 5.14.3 → 5.17.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.
@@ -48,7 +48,7 @@ module Minitest
48
48
  def initialize io # :nodoc:
49
49
  @io = io
50
50
  # stolen from /System/Library/Perl/5.10.0/Term/ANSIColor.pm
51
- # also reference http://en.wikipedia.org/wiki/ANSI_escape_code
51
+ # also reference https://en.wikipedia.org/wiki/ANSI_escape_code
52
52
  @colors ||= (31..36).to_a
53
53
  @size = @colors.size
54
54
  @index = 0
data/lib/minitest/spec.rb CHANGED
@@ -4,15 +4,21 @@ class Module # :nodoc:
4
4
  def infect_an_assertion meth, new_name, dont_flip = false # :nodoc:
5
5
  block = dont_flip == :block
6
6
  dont_flip = false if block
7
+ target_obj = block ? '_{obj.method}' : '_(obj)'
8
+
9
+ # https://eregon.me/blog/2021/02/13/correct-delegation-in-ruby-2-27-3.html
10
+ # Drop this when we can drop ruby 2.6 (aka after rails 6.1 EOL, ~2024-06)
11
+ kw_extra = "ruby2_keywords %p" % [new_name] if respond_to?(:ruby2_keywords, true)
7
12
 
8
13
  # warn "%-22p -> %p %p" % [meth, new_name, dont_flip]
9
14
  self.class_eval <<-EOM, __FILE__, __LINE__ + 1
10
15
  def #{new_name} *args
11
16
  where = Minitest.filter_backtrace(caller).first
12
17
  where = where.split(/:in /, 2).first # clean up noise
13
- warn "DEPRECATED: global use of #{new_name} from #\{where}. Use _(obj).#{new_name} instead. This will fail in Minitest 6."
18
+ Kernel.warn "DEPRECATED: global use of #{new_name} from #\{where}. Use #{target_obj}.#{new_name} instead. This will fail in Minitest 6."
14
19
  Minitest::Expectation.new(self, Minitest::Spec.current).#{new_name}(*args)
15
20
  end
21
+ #{kw_extra}
16
22
  EOM
17
23
 
18
24
  Minitest::Expectation.class_eval <<-EOM, __FILE__, __LINE__ + 1
@@ -27,6 +33,7 @@ class Module # :nodoc:
27
33
  ctx.#{meth}(args.first, target, *args[1..-1])
28
34
  end
29
35
  end
36
+ #{kw_extra}
30
37
  EOM
31
38
  end
32
39
  end
@@ -65,7 +72,7 @@ module Kernel
65
72
  #
66
73
  # For some suggestions on how to improve your specs, try:
67
74
  #
68
- # http://betterspecs.org
75
+ # https://betterspecs.org
69
76
  #
70
77
  # but do note that several items there are debatable or specific to
71
78
  # rspec.
data/lib/minitest/test.rb CHANGED
@@ -18,6 +18,10 @@ module Minitest
18
18
 
19
19
  PASSTHROUGH_EXCEPTIONS = [NoMemoryError, SignalException, SystemExit] # :nodoc:
20
20
 
21
+ SETUP_METHODS = %w[ before_setup setup after_setup ] # :nodoc:
22
+
23
+ TEARDOWN_METHODS = %w[ before_teardown teardown after_teardown ] # :nodoc:
24
+
21
25
  # :stopdoc:
22
26
  class << self; attr_accessor :io_lock; end
23
27
  self.io_lock = Mutex.new
@@ -67,8 +71,8 @@ module Minitest
67
71
 
68
72
  case self.test_order
69
73
  when :random, :parallel then
70
- max = methods.size
71
- methods.sort.sort_by { rand max }
74
+ srand Minitest.seed
75
+ methods.sort.shuffle
72
76
  when :alpha, :sorted then
73
77
  methods.sort
74
78
  else
@@ -84,8 +88,6 @@ module Minitest
84
88
  :random
85
89
  end
86
90
 
87
- TEARDOWN_METHODS = %w[ before_teardown teardown after_teardown ] # :nodoc:
88
-
89
91
  ##
90
92
  # Runs a single test with setup/teardown hooks.
91
93
 
@@ -93,7 +95,9 @@ module Minitest
93
95
  with_info_handler do
94
96
  time_it do
95
97
  capture_exceptions do
96
- before_setup; setup; after_setup
98
+ SETUP_METHODS.each do |hook|
99
+ self.send hook
100
+ end
97
101
 
98
102
  self.send self.name
99
103
  end
@@ -198,7 +202,39 @@ module Minitest
198
202
  rescue Assertion => e
199
203
  self.failures << e
200
204
  rescue Exception => e
201
- self.failures << UnexpectedError.new(e)
205
+ self.failures << UnexpectedError.new(sanitize_exception e)
206
+ end
207
+
208
+ def sanitize_exception e # :nodoc:
209
+ Marshal.dump e
210
+ e # good: use as-is
211
+ rescue
212
+ neuter_exception e
213
+ end
214
+
215
+ def neuter_exception e # :nodoc:
216
+ bt = e.backtrace
217
+ msg = e.message.dup
218
+
219
+ new_exception e.class, msg, bt # e.class can be a problem...
220
+ rescue
221
+ msg.prepend "Neutered Exception #{e.class}: "
222
+
223
+ new_exception RuntimeError, msg, bt, true # but if this raises, we die
224
+ end
225
+
226
+ def new_exception klass, msg, bt, kill = false # :nodoc:
227
+ ne = klass.new msg
228
+ ne.set_backtrace bt
229
+
230
+ if kill then
231
+ ne.instance_variables.each do |v|
232
+ ne.remove_instance_variable v
233
+ end
234
+ end
235
+
236
+ Marshal.dump ne # can raise TypeError
237
+ ne
202
238
  end
203
239
 
204
240
  def with_info_handler &block # :nodoc:
@@ -0,0 +1,305 @@
1
+ require "shellwords"
2
+ require "rbconfig"
3
+ require "rake/tasklib"
4
+
5
+ module Minitest # :nodoc:
6
+
7
+ ##
8
+ # Minitest::TestTask is a rake helper that generates several rake
9
+ # tasks under the main test task's name-space.
10
+ #
11
+ # task <name> :: the main test task
12
+ # task <name>:cmd :: prints the command to use
13
+ # task <name>:deps :: runs each test file by itself to find dependency errors
14
+ # task <name>:slow :: runs the tests and reports the slowest 25 tests.
15
+ #
16
+ # Examples:
17
+ #
18
+ # Minitest::TestTask.create
19
+ #
20
+ # The most basic and default setup.
21
+ #
22
+ # Minitest::TestTask.create :my_tests
23
+ #
24
+ # The most basic/default setup, but with a custom name
25
+ #
26
+ # Minitest::TestTask.create :unit do |t|
27
+ # t.test_globs = ["test/unit/**/*_test.rb"]
28
+ # t.warning = false
29
+ # end
30
+ #
31
+ # Customize the name and only run unit tests.
32
+
33
+ class TestTask < Rake::TaskLib
34
+ WINDOWS = RbConfig::CONFIG["host_os"] =~ /mswin|mingw/ # :nodoc:
35
+
36
+ ##
37
+ # Create several test-oriented tasks under +name+. Takes an
38
+ # optional block to customize variables.
39
+
40
+ def self.create name = :test, &block
41
+ task = new name
42
+ task.instance_eval(&block) if block
43
+ task.process_env
44
+ task.define
45
+ task
46
+ end
47
+
48
+ ##
49
+ # Extra arguments to pass to the tests. Defaults empty but gets
50
+ # populated by a number of enviroment variables:
51
+ #
52
+ # N (-n flag) :: a string or regexp of tests to run.
53
+ # X (-e flag) :: a string or regexp of tests to exclude.
54
+ # A (arg) :: quick way to inject an arbitrary argument (eg A=--help).
55
+ #
56
+ # See #process_env
57
+
58
+ attr_accessor :extra_args
59
+
60
+ ##
61
+ # The code to load the framework. Defaults to requiring
62
+ # minitest/autorun...
63
+ #
64
+ # Why do I have this as an option?
65
+
66
+ attr_accessor :framework
67
+
68
+ ##
69
+ # Extra library directories to include. Defaults to %w[lib test
70
+ # .]. Also uses $MT_LIB_EXTRAS allowing you to dynamically
71
+ # override/inject directories for custom runs.
72
+
73
+ attr_accessor :libs
74
+
75
+ ##
76
+ # The name of the task and base name for the other tasks generated.
77
+
78
+ attr_accessor :name
79
+
80
+ ##
81
+ # File globs to find test files. Defaults to something sensible to
82
+ # find test files under the test directory.
83
+
84
+ attr_accessor :test_globs
85
+
86
+ ##
87
+ # Turn on ruby warnings (-w flag). Defaults to true.
88
+
89
+ attr_accessor :warning
90
+
91
+ ##
92
+ # Optional: Additional ruby to run before the test framework is loaded.
93
+
94
+ attr_accessor :test_prelude
95
+
96
+ ##
97
+ # Print out commands as they run. Defaults to Rake's +trace+ (-t
98
+ # flag) option.
99
+
100
+ attr_accessor :verbose
101
+
102
+ ##
103
+ # Use TestTask.create instead.
104
+
105
+ def initialize name = :test # :nodoc:
106
+ self.extra_args = []
107
+ self.framework = %(require "minitest/autorun")
108
+ self.libs = %w[lib test .]
109
+ self.name = name
110
+ self.test_globs = ["test/**/test_*.rb",
111
+ "test/**/*_test.rb"]
112
+ self.test_prelude = nil
113
+ self.verbose = Rake.application.options.trace
114
+ self.warning = true
115
+ end
116
+
117
+ ##
118
+ # Extract variables from the environment and convert them to
119
+ # command line arguments. See #extra_args.
120
+ #
121
+ # Environment Variables:
122
+ #
123
+ # MT_LIB_EXTRAS :: Extra libs to dynamically override/inject for custom runs.
124
+ # N :: Tests to run (string or /regexp/).
125
+ # X :: Tests to exclude (string or /regexp/).
126
+ # A :: Any extra arguments. Honors shell quoting.
127
+ #
128
+ # Deprecated:
129
+ #
130
+ # TESTOPTS :: For argument passing, use +A+.
131
+ # N :: For parallel testing, use +MT_CPU+.
132
+ # FILTER :: Same as +TESTOPTS+.
133
+
134
+ def process_env
135
+ warn "TESTOPTS is deprecated in Minitest::TestTask. Use A instead" if
136
+ ENV["TESTOPTS"]
137
+ warn "FILTER is deprecated in Minitest::TestTask. Use A instead" if
138
+ ENV["FILTER"]
139
+ warn "N is deprecated in Minitest::TestTask. Use MT_CPU instead" if
140
+ ENV["N"] && ENV["N"].to_i > 0
141
+
142
+ lib_extras = (ENV["MT_LIB_EXTRAS"] || "").split File::PATH_SEPARATOR
143
+ self.libs[0,0] = lib_extras
144
+
145
+ extra_args << "-n" << ENV["N"] if ENV["N"]
146
+ extra_args << "-e" << ENV["X"] if ENV["X"]
147
+ extra_args.concat Shellwords.split(ENV["TESTOPTS"]) if ENV["TESTOPTS"]
148
+ extra_args.concat Shellwords.split(ENV["FILTER"]) if ENV["FILTER"]
149
+ extra_args.concat Shellwords.split(ENV["A"]) if ENV["A"]
150
+
151
+ ENV.delete "N" if ENV["N"]
152
+
153
+ # TODO? RUBY_DEBUG = ENV["RUBY_DEBUG"]
154
+ # TODO? ENV["RUBY_FLAGS"]
155
+
156
+ extra_args.compact!
157
+ end
158
+
159
+ def define # :nodoc:
160
+ default_tasks = []
161
+
162
+ desc "Run the test suite. Use N, X, A, and TESTOPTS to add flags/args."
163
+ task name do
164
+ ruby make_test_cmd, verbose:verbose
165
+ end
166
+
167
+ desc "Print out the test command. Good for profiling and other tools."
168
+ task "#{name}:cmd" do
169
+ puts "ruby #{make_test_cmd}"
170
+ end
171
+
172
+ desc "Show which test files fail when run in isolation."
173
+ task "#{name}:isolated" do
174
+ tests = Dir[*self.test_globs].uniq
175
+
176
+ # 3 seems to be the magic number... (tho not by that much)
177
+ bad, good, n = {}, [], (ENV.delete("K") || 3).to_i
178
+ file = ENV.delete("F")
179
+ times = {}
180
+
181
+ tt0 = Time.now
182
+
183
+ n.threads_do tests.sort do |path|
184
+ t0 = Time.now
185
+ output = `#{Gem.ruby} #{make_test_cmd path} 2>&1`
186
+ t1 = Time.now - t0
187
+
188
+ times[path] = t1
189
+
190
+ if $?.success?
191
+ $stderr.print "."
192
+ good << path
193
+ else
194
+ $stderr.print "x"
195
+ bad[path] = output
196
+ end
197
+ end
198
+
199
+ puts "done"
200
+ puts "Ran in %.2f seconds" % [ Time.now - tt0 ]
201
+
202
+ if file then
203
+ require "json"
204
+ File.open file, "w" do |io|
205
+ io.puts JSON.pretty_generate times
206
+ end
207
+ end
208
+
209
+ unless good.empty?
210
+ puts
211
+ puts "# Good tests:"
212
+ puts
213
+ good.sort.each do |path|
214
+ puts "%.2fs: %s" % [times[path], path]
215
+ end
216
+ end
217
+
218
+ unless bad.empty?
219
+ puts
220
+ puts "# Bad tests:"
221
+ puts
222
+ bad.keys.sort.each do |path|
223
+ puts "%.2fs: %s" % [times[path], path]
224
+ end
225
+ puts
226
+ puts "# Bad Test Output:"
227
+ puts
228
+ bad.sort.each do |path, output|
229
+ puts
230
+ puts "# #{path}:"
231
+ puts output
232
+ end
233
+ exit 1
234
+ end
235
+ end
236
+
237
+ task "#{name}:deps" => "#{name}:isolated" # now just an alias
238
+
239
+ desc "Show bottom 25 tests wrt time."
240
+ task "#{name}:slow" do
241
+ sh ["rake #{name} A=-v",
242
+ "egrep '#test_.* s = .'",
243
+ "sort -n -k2 -t=",
244
+ "tail -25"].join " | "
245
+ end
246
+
247
+ default_tasks << name
248
+
249
+ desc "Run the default task(s)."
250
+ task :default => default_tasks
251
+ end
252
+
253
+ ##
254
+ # Generate the test command-line.
255
+
256
+ def make_test_cmd globs = test_globs
257
+ tests = []
258
+ tests.concat Dir[*globs].sort.shuffle # TODO: SEED -> srand first?
259
+ tests.map! { |f| %(require "#{f}") }
260
+
261
+ runner = []
262
+ runner << test_prelude if test_prelude
263
+ runner << framework
264
+ runner.concat tests
265
+ runner = runner.join "; "
266
+
267
+ args = []
268
+ args << "-I#{libs.join(File::PATH_SEPARATOR)}" unless libs.empty?
269
+ args << "-w" if warning
270
+ args << '-e'
271
+ args << "'#{runner}'"
272
+ args << '--'
273
+ args << extra_args.map(&:shellescape)
274
+
275
+ args.join " "
276
+ end
277
+ end
278
+ end
279
+
280
+ class Work < Queue # :nodoc:
281
+ def initialize jobs = [] # :nodoc:
282
+ super()
283
+
284
+ jobs.each do |job|
285
+ self << job
286
+ end
287
+
288
+ close
289
+ end
290
+ end
291
+
292
+ class Integer # :nodoc:
293
+ def threads_do(jobs) # :nodoc:
294
+ require "thread"
295
+ q = Work.new jobs
296
+
297
+ self.times.map {
298
+ Thread.new do
299
+ while job = q.pop # go until quit value
300
+ yield job
301
+ end
302
+ end
303
+ }.each(&:join)
304
+ end
305
+ end
data/lib/minitest/unit.rb CHANGED
@@ -1,5 +1,3 @@
1
- # :stopdoc:
2
-
3
1
  unless defined?(Minitest) then
4
2
  # all of this crap is just to avoid circular requires and is only
5
3
  # needed if a user requires "minitest/unit" directly instead of
@@ -10,17 +8,18 @@ unless defined?(Minitest) then
10
8
  warn %(Warning: or add 'gem "minitest"' before 'require "minitest/autorun"')
11
9
  warn "From:\n #{from}"
12
10
 
13
- module Minitest; end
14
- MiniTest = Minitest # prevents minitest.rb from requiring back to us
11
+ module Minitest # :nodoc:
12
+ end
13
+ MiniTest = Minitest # :nodoc: # prevents minitest.rb from requiring back to us
15
14
  require "minitest"
16
15
  end
17
16
 
18
17
  MiniTest = Minitest unless defined?(MiniTest)
19
18
 
20
19
  module Minitest
21
- class Unit
20
+ class Unit # :nodoc:
22
21
  VERSION = Minitest::VERSION
23
- class TestCase < Minitest::Test
22
+ class TestCase < Minitest::Test # :nodoc:
24
23
  def self.inherited klass # :nodoc:
25
24
  from = caller.first
26
25
  warn "MiniTest::Unit::TestCase is now Minitest::Test. From #{from}"
@@ -41,5 +40,3 @@ module Minitest
41
40
  end
42
41
  end
43
42
  end
44
-
45
- # :startdoc:
data/lib/minitest.rb CHANGED
@@ -3,56 +3,71 @@ require "thread"
3
3
  require "mutex_m"
4
4
  require "minitest/parallel"
5
5
  require "stringio"
6
+ require "etc"
6
7
 
7
8
  ##
8
9
  # :include: README.rdoc
9
10
 
10
11
  module Minitest
11
- VERSION = "5.14.3" # :nodoc:
12
- ENCS = "".respond_to? :encoding # :nodoc:
12
+ VERSION = "5.17.0" # :nodoc:
13
13
 
14
14
  @@installed_at_exit ||= false
15
15
  @@after_run = []
16
16
  @extensions = []
17
17
 
18
- mc = (class << self; self; end)
18
+ def self.cattr_accessor name # :nodoc:
19
+ (class << self; self; end).attr_accessor name
20
+ end
21
+
22
+ ##
23
+ # The random seed used for this run. This is used to srand at the
24
+ # start of the run and between each +Runnable.run+.
25
+ #
26
+ # Set via Minitest.run after processing args.
27
+
28
+ cattr_accessor :seed
19
29
 
20
30
  ##
21
31
  # Parallel test executor
22
32
 
23
- mc.send :attr_accessor, :parallel_executor
33
+ cattr_accessor :parallel_executor
24
34
 
25
35
  warn "DEPRECATED: use MT_CPU instead of N for parallel test runs" if ENV["N"]
26
- n_threads = (ENV["MT_CPU"] || ENV["N"] || 2).to_i
36
+ n_threads = (ENV["MT_CPU"] || ENV["N"] || Etc.nprocessors).to_i
37
+
27
38
  self.parallel_executor = Parallel::Executor.new n_threads
28
39
 
29
40
  ##
30
41
  # Filter object for backtraces.
31
42
 
32
- mc.send :attr_accessor, :backtrace_filter
43
+ cattr_accessor :backtrace_filter
33
44
 
34
45
  ##
35
46
  # Reporter object to be used for all runs.
36
47
  #
37
48
  # NOTE: This accessor is only available during setup, not during runs.
38
49
 
39
- mc.send :attr_accessor, :reporter
50
+ cattr_accessor :reporter
40
51
 
41
52
  ##
42
53
  # Names of known extension plugins.
43
54
 
44
- mc.send :attr_accessor, :extensions
55
+ cattr_accessor :extensions
45
56
 
46
57
  ##
47
58
  # The signal to use for dumping information to STDERR. Defaults to "INFO".
48
59
 
49
- mc.send :attr_accessor, :info_signal
60
+ cattr_accessor :info_signal
50
61
  self.info_signal = "INFO"
51
62
 
52
63
  ##
53
64
  # Registers Minitest to run at process exit
54
65
 
55
66
  def self.autorun
67
+ if Object.const_defined?(:Warning) && Warning.respond_to?(:[]=)
68
+ Warning[:deprecated] = true
69
+ end
70
+
56
71
  at_exit {
57
72
  next if $! and not ($!.kind_of? SystemExit and $!.success?)
58
73
 
@@ -127,6 +142,9 @@ module Minitest
127
142
 
128
143
  options = process_args args
129
144
 
145
+ Minitest.seed = options[:seed]
146
+ srand Minitest.seed
147
+
130
148
  reporter = CompositeReporter.new
131
149
  reporter << SummaryReporter.new(options[:io], options)
132
150
  reporter << ProgressReporter.new(options[:io], options)
@@ -153,7 +171,7 @@ module Minitest
153
171
  # sub-classes to run.
154
172
 
155
173
  def self.__run reporter, options
156
- suites = Runnable.runnables.reject { |s| s.runnable_methods.empty? }.shuffle
174
+ suites = Runnable.runnables.shuffle
157
175
  parallel, serial = suites.partition { |s| s.test_order == :parallel }
158
176
 
159
177
  # If we run the parallel tests before the serial tests, the parallel tests
@@ -191,6 +209,10 @@ module Minitest
191
209
  options[:verbose] = true
192
210
  end
193
211
 
212
+ opts.on "--show-skips", "Show skipped at the end of run." do
213
+ options[:show_skips] = true
214
+ end
215
+
194
216
  opts.on "-n", "--name PATTERN", "Filter run on /regexp/ or string." do |a|
195
217
  options[:filter] = a
196
218
  end
@@ -199,6 +221,10 @@ module Minitest
199
221
  options[:exclude] = a
200
222
  end
201
223
 
224
+ opts.on "-S", "--skip CODES", String, "Skip reporting of certain types of results (eg E)." do |s|
225
+ options[:skip] = s.chars.to_a
226
+ end
227
+
202
228
  unless extensions.empty?
203
229
  opts.separator ""
204
230
  opts.separator "Known extensions: #{extensions.join(", ")}"
@@ -228,8 +254,6 @@ module Minitest
228
254
  orig_args << "--seed" << options[:seed].to_s
229
255
  end
230
256
 
231
- srand options[:seed]
232
-
233
257
  options[:args] = orig_args.map { |s|
234
258
  s =~ /[\s|&<>$()]/ ? s.inspect : s
235
259
  }.join " "
@@ -784,9 +808,14 @@ module Minitest
784
808
 
785
809
  def aggregated_results io # :nodoc:
786
810
  filtered_results = results.dup
787
- filtered_results.reject!(&:skipped?) unless options[:verbose]
811
+ filtered_results.reject!(&:skipped?) unless
812
+ options[:verbose] or options[:show_skips]
813
+
814
+ skip = options[:skip] || []
788
815
 
789
816
  filtered_results.each_with_index { |result, i|
817
+ next if skip.include? result.result_code
818
+
790
819
  io.puts "\n%3d) %s" % [i+1, result]
791
820
  }
792
821
  io.puts
@@ -794,26 +823,19 @@ module Minitest
794
823
  end
795
824
 
796
825
  def to_s # :nodoc:
797
- aggregated_results(StringIO.new(binary_string)).string
826
+ aggregated_results(StringIO.new(''.b)).string
798
827
  end
799
828
 
800
829
  def summary # :nodoc:
801
830
  extra = ""
802
831
 
803
832
  extra = "\n\nYou have skipped tests. Run with --verbose for details." if
804
- results.any?(&:skipped?) unless options[:verbose] or ENV["MT_NO_SKIP_MSG"]
833
+ results.any?(&:skipped?) unless
834
+ options[:verbose] or options[:show_skips] or ENV["MT_NO_SKIP_MSG"]
805
835
 
806
836
  "%d runs, %d assertions, %d failures, %d errors, %d skips%s" %
807
837
  [count, assertions, failures, errors, skips, extra]
808
838
  end
809
-
810
- private
811
-
812
- if '<3'.respond_to? :b
813
- def binary_string; ''.b; end
814
- else
815
- def binary_string; ''.force_encoding(Encoding::ASCII_8BIT); end
816
- end
817
839
  end
818
840
 
819
841
  ##
@@ -129,7 +129,7 @@ class MetaMetaMetaTestCase < Minitest::Test
129
129
 
130
130
  def setup
131
131
  super
132
- srand 42
132
+ Minitest.seed = 42
133
133
  Minitest::Test.reset
134
134
  @tu = nil
135
135
  end