minitest 5.11.3 → 5.22.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
- checksums.yaml.gz.sig +0 -0
- data/History.rdoc +280 -4
- data/Manifest.txt +4 -0
- data/README.rdoc +104 -17
- data/Rakefile +5 -16
- data/lib/hoe/minitest.rb +0 -4
- data/lib/minitest/assertions.rb +209 -42
- data/lib/minitest/benchmark.rb +7 -7
- data/lib/minitest/compress.rb +94 -0
- data/lib/minitest/expectations.rb +72 -35
- data/lib/minitest/mock.rb +123 -34
- data/lib/minitest/pride_plugin.rb +8 -11
- data/lib/minitest/spec.rb +27 -9
- data/lib/minitest/test.rb +48 -19
- data/lib/minitest/test_task.rb +301 -0
- data/lib/minitest/unit.rb +5 -8
- data/lib/minitest.rb +247 -69
- data/test/minitest/metametameta.rb +52 -12
- data/test/minitest/test_minitest_assertions.rb +1721 -0
- data/test/minitest/test_minitest_benchmark.rb +2 -2
- data/test/minitest/test_minitest_mock.rb +289 -17
- data/test/minitest/test_minitest_reporter.rb +160 -19
- data/test/minitest/test_minitest_spec.rb +314 -155
- data/test/minitest/test_minitest_test.rb +429 -1196
- data/test/minitest/test_minitest_test_task.rb +48 -0
- data.tar.gz.sig +0 -0
- metadata +38 -23
- metadata.gz.sig +0 -0
    
        data/lib/minitest/assertions.rb
    CHANGED
    
    | @@ -27,20 +27,18 @@ module Minitest | |
| 27 27 | 
             
                # figure out what diff to use.
         | 
| 28 28 |  | 
| 29 29 | 
             
                def self.diff
         | 
| 30 | 
            +
                  return @diff if defined? @diff
         | 
| 31 | 
            +
             | 
| 30 32 | 
             
                  @diff = if (RbConfig::CONFIG["host_os"] =~ /mswin|mingw/ &&
         | 
| 31 33 | 
             
                              system("diff.exe", __FILE__, __FILE__)) then
         | 
| 32 34 | 
             
                            "diff.exe -u"
         | 
| 33 | 
            -
                          elsif Minitest::Test.maglev? then
         | 
| 34 | 
            -
                            "diff -u"
         | 
| 35 35 | 
             
                          elsif system("gdiff", __FILE__, __FILE__)
         | 
| 36 36 | 
             
                            "gdiff -u" # solaris and kin suck
         | 
| 37 37 | 
             
                          elsif system("diff", __FILE__, __FILE__)
         | 
| 38 38 | 
             
                            "diff -u"
         | 
| 39 39 | 
             
                          else
         | 
| 40 40 | 
             
                            nil
         | 
| 41 | 
            -
                          end | 
| 42 | 
            -
             | 
| 43 | 
            -
                  @diff
         | 
| 41 | 
            +
                          end
         | 
| 44 42 | 
             
                end
         | 
| 45 43 |  | 
| 46 44 | 
             
                ##
         | 
| @@ -55,22 +53,16 @@ module Minitest | |
| 55 53 | 
             
                # diff command or if it doesn't make sense to diff the output
         | 
| 56 54 | 
             
                # (single line, short output), then it simply returns a basic
         | 
| 57 55 | 
             
                # comparison between the two.
         | 
| 56 | 
            +
                #
         | 
| 57 | 
            +
                # See +things_to_diff+ for more info.
         | 
| 58 58 |  | 
| 59 59 | 
             
                def diff exp, act
         | 
| 60 | 
            -
                  expect = mu_pp_for_diff exp
         | 
| 61 | 
            -
                  butwas = mu_pp_for_diff act
         | 
| 62 60 | 
             
                  result = nil
         | 
| 63 61 |  | 
| 64 | 
            -
                   | 
| 65 | 
            -
                    (expect.include?("\n")    ||
         | 
| 66 | 
            -
                     butwas.include?("\n")    ||
         | 
| 67 | 
            -
                     expect.size > 30         ||
         | 
| 68 | 
            -
                     butwas.size > 30         ||
         | 
| 69 | 
            -
                     expect == butwas)        &&
         | 
| 70 | 
            -
                    Minitest::Assertions.diff
         | 
| 62 | 
            +
                  expect, butwas = things_to_diff(exp, act)
         | 
| 71 63 |  | 
| 72 64 | 
             
                  return "Expected: #{mu_pp exp}\n  Actual: #{mu_pp act}" unless
         | 
| 73 | 
            -
                     | 
| 65 | 
            +
                    expect
         | 
| 74 66 |  | 
| 75 67 | 
             
                  Tempfile.open("expect") do |a|
         | 
| 76 68 | 
             
                    a.puts expect
         | 
| @@ -99,10 +91,40 @@ module Minitest | |
| 99 91 | 
             
                  result
         | 
| 100 92 | 
             
                end
         | 
| 101 93 |  | 
| 94 | 
            +
                ##
         | 
| 95 | 
            +
                # Returns things to diff [expect, butwas], or [nil, nil] if nothing to diff.
         | 
| 96 | 
            +
                #
         | 
| 97 | 
            +
                # Criterion:
         | 
| 98 | 
            +
                #
         | 
| 99 | 
            +
                # 1. Strings include newlines or escaped newlines, but not both.
         | 
| 100 | 
            +
                # 2. or:  String lengths are > 30 characters.
         | 
| 101 | 
            +
                # 3. or:  Strings are equal to each other (but maybe different encodings?).
         | 
| 102 | 
            +
                # 4. and: we found a diff executable.
         | 
| 103 | 
            +
             | 
| 104 | 
            +
                def things_to_diff exp, act
         | 
| 105 | 
            +
                  expect = mu_pp_for_diff exp
         | 
| 106 | 
            +
                  butwas = mu_pp_for_diff act
         | 
| 107 | 
            +
             | 
| 108 | 
            +
                  e1, e2 = expect.include?("\n"), expect.include?("\\n")
         | 
| 109 | 
            +
                  b1, b2 = butwas.include?("\n"), butwas.include?("\\n")
         | 
| 110 | 
            +
             | 
| 111 | 
            +
                  need_to_diff =
         | 
| 112 | 
            +
                    (e1 ^ e2                  ||
         | 
| 113 | 
            +
                     b1 ^ b2                  ||
         | 
| 114 | 
            +
                     expect.size > 30         ||
         | 
| 115 | 
            +
                     butwas.size > 30         ||
         | 
| 116 | 
            +
                     expect == butwas)        &&
         | 
| 117 | 
            +
                    Minitest::Assertions.diff
         | 
| 118 | 
            +
             | 
| 119 | 
            +
                  need_to_diff && [expect, butwas]
         | 
| 120 | 
            +
                end
         | 
| 121 | 
            +
             | 
| 102 122 | 
             
                ##
         | 
| 103 123 | 
             
                # This returns a human-readable version of +obj+. By default
         | 
| 104 | 
            -
                # #inspect is called. You can override this to use # | 
| 124 | 
            +
                # #inspect is called. You can override this to use #pretty_inspect
         | 
| 105 125 | 
             
                # if you want.
         | 
| 126 | 
            +
                #
         | 
| 127 | 
            +
                # See Minitest::Test.make_my_diffs_pretty!
         | 
| 106 128 |  | 
| 107 129 | 
             
                def mu_pp obj
         | 
| 108 130 | 
             
                  s = obj.inspect
         | 
| @@ -110,8 +132,11 @@ module Minitest | |
| 110 132 | 
             
                  if defined? Encoding then
         | 
| 111 133 | 
             
                    s = s.encode Encoding.default_external
         | 
| 112 134 |  | 
| 113 | 
            -
                    if String === obj && obj.encoding != Encoding.default_external  | 
| 114 | 
            -
             | 
| 135 | 
            +
                    if String === obj && (obj.encoding != Encoding.default_external ||
         | 
| 136 | 
            +
                                          !obj.valid_encoding?) then
         | 
| 137 | 
            +
                      enc = "# encoding: #{obj.encoding}"
         | 
| 138 | 
            +
                      val = "#    valid: #{obj.valid_encoding?}"
         | 
| 139 | 
            +
                      s = "#{enc}\n#{val}\n#{s}"
         | 
| 115 140 | 
             
                    end
         | 
| 116 141 | 
             
                  end
         | 
| 117 142 |  | 
| @@ -119,13 +144,32 @@ module Minitest | |
| 119 144 | 
             
                end
         | 
| 120 145 |  | 
| 121 146 | 
             
                ##
         | 
| 122 | 
            -
                # This returns a diff-able human-readable version of +obj+. | 
| 123 | 
            -
                # differs from the regular mu_pp because it expands escaped
         | 
| 124 | 
            -
                # newlines and makes hex-values  | 
| 147 | 
            +
                # This returns a diff-able more human-readable version of +obj+.
         | 
| 148 | 
            +
                # This differs from the regular mu_pp because it expands escaped
         | 
| 149 | 
            +
                # newlines and makes hex-values (like object_ids) generic. This
         | 
| 125 150 | 
             
                # uses mu_pp to do the first pass and then cleans it up.
         | 
| 126 151 |  | 
| 127 152 | 
             
                def mu_pp_for_diff obj
         | 
| 128 | 
            -
                  mu_pp | 
| 153 | 
            +
                  str = mu_pp obj
         | 
| 154 | 
            +
             | 
| 155 | 
            +
                  # both '\n' & '\\n' (_after_ mu_pp (aka inspect))
         | 
| 156 | 
            +
                  single = !!str.match(/(?<!\\|^)\\n/)
         | 
| 157 | 
            +
                  double = !!str.match(/(?<=\\|^)\\n/)
         | 
| 158 | 
            +
             | 
| 159 | 
            +
                  process =
         | 
| 160 | 
            +
                    if single ^ double then
         | 
| 161 | 
            +
                      if single then
         | 
| 162 | 
            +
                        lambda { |s| s == "\\n"   ? "\n"    : s } # unescape
         | 
| 163 | 
            +
                      else
         | 
| 164 | 
            +
                        lambda { |s| s == "\\\\n" ? "\\n\n" : s } # unescape a bit, add nls
         | 
| 165 | 
            +
                      end
         | 
| 166 | 
            +
                    else
         | 
| 167 | 
            +
                      :itself                                     # leave it alone
         | 
| 168 | 
            +
                    end
         | 
| 169 | 
            +
             | 
| 170 | 
            +
                  str.
         | 
| 171 | 
            +
                    gsub(/\\?\\n/, &process).
         | 
| 172 | 
            +
                    gsub(/:0x[a-fA-F0-9]{4,}/m, ":0xXXXXXX") # anonymize hex values
         | 
| 129 173 | 
             
                end
         | 
| 130 174 |  | 
| 131 175 | 
             
                ##
         | 
| @@ -154,6 +198,11 @@ module Minitest | |
| 154 198 | 
             
                  assert obj.empty?, msg
         | 
| 155 199 | 
             
                end
         | 
| 156 200 |  | 
| 201 | 
            +
                def _where # :nodoc:
         | 
| 202 | 
            +
                  where = Minitest.filter_backtrace(caller).first
         | 
| 203 | 
            +
                  where = where.split(/:in /, 2).first # clean up noise
         | 
| 204 | 
            +
                end
         | 
| 205 | 
            +
             | 
| 157 206 | 
             
                E = "" # :nodoc:
         | 
| 158 207 |  | 
| 159 208 | 
             
                ##
         | 
| @@ -177,10 +226,7 @@ module Minitest | |
| 177 226 | 
             
                    if Minitest::VERSION =~ /^6/ then
         | 
| 178 227 | 
             
                      refute_nil exp, "Use assert_nil if expecting nil."
         | 
| 179 228 | 
             
                    else
         | 
| 180 | 
            -
                       | 
| 181 | 
            -
                      where = where.split(/:in /, 2).first # clean up noise
         | 
| 182 | 
            -
             | 
| 183 | 
            -
                      warn "DEPRECATED: Use assert_nil if expecting nil from #{where}. This will fail in Minitest 6."
         | 
| 229 | 
            +
                      warn "DEPRECATED: Use assert_nil if expecting nil from #{_where}. This will fail in Minitest 6."
         | 
| 184 230 | 
             
                    end
         | 
| 185 231 | 
             
                  end
         | 
| 186 232 |  | 
| @@ -249,6 +295,8 @@ module Minitest | |
| 249 295 | 
             
                  assert_respond_to matcher, :"=~"
         | 
| 250 296 | 
             
                  matcher = Regexp.new Regexp.escape matcher if String === matcher
         | 
| 251 297 | 
             
                  assert matcher =~ obj, msg
         | 
| 298 | 
            +
             | 
| 299 | 
            +
                  Regexp.last_match
         | 
| 252 300 | 
             
                end
         | 
| 253 301 |  | 
| 254 302 | 
             
                ##
         | 
| @@ -283,6 +331,9 @@ module Minitest | |
| 283 331 | 
             
                # See also: #assert_silent
         | 
| 284 332 |  | 
| 285 333 | 
             
                def assert_output stdout = nil, stderr = nil
         | 
| 334 | 
            +
                  flunk "assert_output requires a block to capture output." unless
         | 
| 335 | 
            +
                    block_given?
         | 
| 336 | 
            +
             | 
| 286 337 | 
             
                  out, err = capture_io do
         | 
| 287 338 | 
             
                    yield
         | 
| 288 339 | 
             
                  end
         | 
| @@ -294,6 +345,44 @@ module Minitest | |
| 294 345 | 
             
                  x = send out_msg, stdout, out, "In stdout" if out_msg
         | 
| 295 346 |  | 
| 296 347 | 
             
                  (!stdout || x) && (!stderr || y)
         | 
| 348 | 
            +
                rescue Assertion
         | 
| 349 | 
            +
                  raise
         | 
| 350 | 
            +
                rescue => e
         | 
| 351 | 
            +
                  raise UnexpectedError, e
         | 
| 352 | 
            +
                end
         | 
| 353 | 
            +
             | 
| 354 | 
            +
                ##
         | 
| 355 | 
            +
                # Fails unless +path+ exists.
         | 
| 356 | 
            +
             | 
| 357 | 
            +
                def assert_path_exists path, msg = nil
         | 
| 358 | 
            +
                  msg = message(msg) { "Expected path '#{path}' to exist" }
         | 
| 359 | 
            +
                  assert File.exist?(path), msg
         | 
| 360 | 
            +
                end
         | 
| 361 | 
            +
             | 
| 362 | 
            +
                ##
         | 
| 363 | 
            +
                # For testing with pattern matching (only supported with Ruby 3.0 and later)
         | 
| 364 | 
            +
                #
         | 
| 365 | 
            +
                #   # pass
         | 
| 366 | 
            +
                #   assert_pattern { [1,2,3] => [Integer, Integer, Integer] }
         | 
| 367 | 
            +
                #
         | 
| 368 | 
            +
                #   # fail "length mismatch (given 3, expected 1)"
         | 
| 369 | 
            +
                #   assert_pattern { [1,2,3] => [Integer] }
         | 
| 370 | 
            +
                #
         | 
| 371 | 
            +
                # The bare <tt>=></tt> pattern will raise a NoMatchingPatternError on failure, which would
         | 
| 372 | 
            +
                # normally be counted as a test error. This assertion rescues NoMatchingPatternError and
         | 
| 373 | 
            +
                # generates a test failure. Any other exception will be raised as normal and generate a test
         | 
| 374 | 
            +
                # error.
         | 
| 375 | 
            +
             | 
| 376 | 
            +
                def assert_pattern
         | 
| 377 | 
            +
                  raise NotImplementedError, "only available in Ruby 3.0+" unless RUBY_VERSION >= "3.0"
         | 
| 378 | 
            +
                  flunk "assert_pattern requires a block to capture errors." unless block_given?
         | 
| 379 | 
            +
             | 
| 380 | 
            +
                  begin # TODO: remove after ruby 2.6 dropped
         | 
| 381 | 
            +
                    yield
         | 
| 382 | 
            +
                    pass
         | 
| 383 | 
            +
                  rescue NoMatchingPatternError => e
         | 
| 384 | 
            +
                    flunk e.message
         | 
| 385 | 
            +
                  end
         | 
| 297 386 | 
             
                end
         | 
| 298 387 |  | 
| 299 388 | 
             
                ##
         | 
| @@ -316,9 +405,26 @@ module Minitest | |
| 316 405 | 
             
                #
         | 
| 317 406 | 
             
                # +exp+ takes an optional message on the end to help explain
         | 
| 318 407 | 
             
                # failures and defaults to StandardError if no exception class is
         | 
| 319 | 
            -
                # passed.
         | 
| 408 | 
            +
                # passed. Eg:
         | 
| 409 | 
            +
                #
         | 
| 410 | 
            +
                #   assert_raises(CustomError) { method_with_custom_error }
         | 
| 411 | 
            +
                #
         | 
| 412 | 
            +
                # With custom error message:
         | 
| 413 | 
            +
                #
         | 
| 414 | 
            +
                #   assert_raises(CustomError, 'This should have raised CustomError') { method_with_custom_error }
         | 
| 415 | 
            +
                #
         | 
| 416 | 
            +
                # Using the returned object:
         | 
| 417 | 
            +
                #
         | 
| 418 | 
            +
                #   error = assert_raises(CustomError) do
         | 
| 419 | 
            +
                #     raise CustomError, 'This is really bad'
         | 
| 420 | 
            +
                #   end
         | 
| 421 | 
            +
                #
         | 
| 422 | 
            +
                #   assert_equal 'This is really bad', error.message
         | 
| 320 423 |  | 
| 321 424 | 
             
                def assert_raises *exp
         | 
| 425 | 
            +
                  flunk "assert_raises requires a block to capture errors." unless
         | 
| 426 | 
            +
                    block_given?
         | 
| 427 | 
            +
             | 
| 322 428 | 
             
                  msg = "#{exp.pop}.\n" if String === exp.last
         | 
| 323 429 | 
             
                  exp << StandardError if exp.empty?
         | 
| 324 430 |  | 
| @@ -327,7 +433,7 @@ module Minitest | |
| 327 433 | 
             
                  rescue *exp => e
         | 
| 328 434 | 
             
                    pass # count assertion
         | 
| 329 435 | 
             
                    return e
         | 
| 330 | 
            -
                  rescue Minitest::Skip | 
| 436 | 
            +
                  rescue Minitest::Assertion # incl Skip & UnexpectedError
         | 
| 331 437 | 
             
                    # don't count assertion
         | 
| 332 438 | 
             
                    raise
         | 
| 333 439 | 
             
                  rescue SignalException, SystemExit
         | 
| @@ -345,12 +451,13 @@ module Minitest | |
| 345 451 |  | 
| 346 452 | 
             
                ##
         | 
| 347 453 | 
             
                # Fails unless +obj+ responds to +meth+.
         | 
| 454 | 
            +
                # include_all defaults to false to match Object#respond_to?
         | 
| 348 455 |  | 
| 349 | 
            -
                def assert_respond_to obj, meth, msg = nil
         | 
| 456 | 
            +
                def assert_respond_to obj, meth, msg = nil, include_all: false
         | 
| 350 457 | 
             
                  msg = message(msg) {
         | 
| 351 458 | 
             
                    "Expected #{mu_pp(obj)} (#{obj.class}) to respond to ##{meth}"
         | 
| 352 459 | 
             
                  }
         | 
| 353 | 
            -
                  assert obj.respond_to?(meth), msg
         | 
| 460 | 
            +
                  assert obj.respond_to?(meth, include_all), msg
         | 
| 354 461 | 
             
                end
         | 
| 355 462 |  | 
| 356 463 | 
             
                ##
         | 
| @@ -370,9 +477,7 @@ module Minitest | |
| 370 477 | 
             
                # Fails unless the call returns a true value
         | 
| 371 478 |  | 
| 372 479 | 
             
                def assert_send send_ary, m = nil
         | 
| 373 | 
            -
                   | 
| 374 | 
            -
                  where = where.split(/:in /, 2).first # clean up noise
         | 
| 375 | 
            -
                  warn "DEPRECATED: assert_send. From #{where}"
         | 
| 480 | 
            +
                  warn "DEPRECATED: assert_send. From #{_where}"
         | 
| 376 481 |  | 
| 377 482 | 
             
                  recv, msg, *args = send_ary
         | 
| 378 483 | 
             
                  m = message(m) {
         | 
| @@ -397,7 +502,7 @@ module Minitest | |
| 397 502 | 
             
                def assert_throws sym, msg = nil
         | 
| 398 503 | 
             
                  default = "Expected #{mu_pp(sym)} to have been thrown"
         | 
| 399 504 | 
             
                  caught = true
         | 
| 400 | 
            -
                  catch(sym) do
         | 
| 505 | 
            +
                  value = catch(sym) do
         | 
| 401 506 | 
             
                    begin
         | 
| 402 507 | 
             
                      yield
         | 
| 403 508 | 
             
                    rescue ThreadError => e       # wtf?!? 1.8 + threads == suck
         | 
| @@ -413,6 +518,11 @@ module Minitest | |
| 413 518 | 
             
                  end
         | 
| 414 519 |  | 
| 415 520 | 
             
                  assert caught, message(msg) { default }
         | 
| 521 | 
            +
                  value
         | 
| 522 | 
            +
                rescue Assertion
         | 
| 523 | 
            +
                  raise
         | 
| 524 | 
            +
                rescue => e
         | 
| 525 | 
            +
                  raise UnexpectedError, e
         | 
| 416 526 | 
             
                end
         | 
| 417 527 |  | 
| 418 528 | 
             
                ##
         | 
| @@ -481,10 +591,13 @@ module Minitest | |
| 481 591 |  | 
| 482 592 | 
             
                      return captured_stdout.read, captured_stderr.read
         | 
| 483 593 | 
             
                    ensure
         | 
| 484 | 
            -
                      captured_stdout.unlink
         | 
| 485 | 
            -
                      captured_stderr.unlink
         | 
| 486 594 | 
             
                      $stdout.reopen orig_stdout
         | 
| 487 595 | 
             
                      $stderr.reopen orig_stderr
         | 
| 596 | 
            +
             | 
| 597 | 
            +
                      orig_stdout.close
         | 
| 598 | 
            +
                      orig_stderr.close
         | 
| 599 | 
            +
                      captured_stdout.close!
         | 
| 600 | 
            +
                      captured_stderr.close!
         | 
| 488 601 | 
             
                    end
         | 
| 489 602 | 
             
                  end
         | 
| 490 603 | 
             
                end
         | 
| @@ -504,7 +617,16 @@ module Minitest | |
| 504 617 | 
             
                end
         | 
| 505 618 |  | 
| 506 619 | 
             
                ##
         | 
| 507 | 
            -
                # Fails  | 
| 620 | 
            +
                # Fails after a given date (in the local time zone). This allows
         | 
| 621 | 
            +
                # you to put time-bombs in your tests if you need to keep
         | 
| 622 | 
            +
                # something around until a later date lest you forget about it.
         | 
| 623 | 
            +
             | 
| 624 | 
            +
                def fail_after y,m,d,msg
         | 
| 625 | 
            +
                  flunk msg if Time.now > Time.local(y, m, d)
         | 
| 626 | 
            +
                end
         | 
| 627 | 
            +
             | 
| 628 | 
            +
                ##
         | 
| 629 | 
            +
                # Fails with +msg+.
         | 
| 508 630 |  | 
| 509 631 | 
             
                def flunk msg = nil
         | 
| 510 632 | 
             
                  msg ||= "Epic Fail!"
         | 
| @@ -534,7 +656,7 @@ module Minitest | |
| 534 656 |  | 
| 535 657 | 
             
                def refute test, msg = nil
         | 
| 536 658 | 
             
                  msg ||= message { "Expected #{mu_pp(test)} to not be truthy" }
         | 
| 537 | 
            -
                   | 
| 659 | 
            +
                  assert !test, msg
         | 
| 538 660 | 
             
                end
         | 
| 539 661 |  | 
| 540 662 | 
             
                ##
         | 
| @@ -626,6 +748,30 @@ module Minitest | |
| 626 748 | 
             
                  refute obj.nil?, msg
         | 
| 627 749 | 
             
                end
         | 
| 628 750 |  | 
| 751 | 
            +
                ##
         | 
| 752 | 
            +
                # For testing with pattern matching (only supported with Ruby 3.0 and later)
         | 
| 753 | 
            +
                #
         | 
| 754 | 
            +
                #   # pass
         | 
| 755 | 
            +
                #   refute_pattern { [1,2,3] => [String] }
         | 
| 756 | 
            +
                #
         | 
| 757 | 
            +
                #   # fail "NoMatchingPatternError expected, but nothing was raised."
         | 
| 758 | 
            +
                #   refute_pattern { [1,2,3] => [Integer, Integer, Integer] }
         | 
| 759 | 
            +
                #
         | 
| 760 | 
            +
                # This assertion expects a NoMatchingPatternError exception, and will fail if none is raised. Any
         | 
| 761 | 
            +
                # other exceptions will be raised as normal and generate a test error.
         | 
| 762 | 
            +
             | 
| 763 | 
            +
                def refute_pattern
         | 
| 764 | 
            +
                  raise NotImplementedError, "only available in Ruby 3.0+" unless RUBY_VERSION >= "3.0"
         | 
| 765 | 
            +
                  flunk "refute_pattern requires a block to capture errors." unless block_given?
         | 
| 766 | 
            +
             | 
| 767 | 
            +
                  begin
         | 
| 768 | 
            +
                    yield
         | 
| 769 | 
            +
                    flunk("NoMatchingPatternError expected, but nothing was raised.")
         | 
| 770 | 
            +
                  rescue NoMatchingPatternError
         | 
| 771 | 
            +
                    pass
         | 
| 772 | 
            +
                  end
         | 
| 773 | 
            +
                end
         | 
| 774 | 
            +
             | 
| 629 775 | 
             
                ##
         | 
| 630 776 | 
             
                # Fails if +o1+ is not +op+ +o2+. Eg:
         | 
| 631 777 | 
             
                #
         | 
| @@ -638,6 +784,14 @@ module Minitest | |
| 638 784 | 
             
                  refute o1.__send__(op, o2), msg
         | 
| 639 785 | 
             
                end
         | 
| 640 786 |  | 
| 787 | 
            +
                ##
         | 
| 788 | 
            +
                # Fails if +path+ exists.
         | 
| 789 | 
            +
             | 
| 790 | 
            +
                def refute_path_exists path, msg = nil
         | 
| 791 | 
            +
                  msg = message(msg) { "Expected path '#{path}' to not exist" }
         | 
| 792 | 
            +
                  refute File.exist?(path), msg
         | 
| 793 | 
            +
                end
         | 
| 794 | 
            +
             | 
| 641 795 | 
             
                ##
         | 
| 642 796 | 
             
                # For testing with predicates.
         | 
| 643 797 | 
             
                #
         | 
| @@ -654,11 +808,12 @@ module Minitest | |
| 654 808 |  | 
| 655 809 | 
             
                ##
         | 
| 656 810 | 
             
                # Fails if +obj+ responds to the message +meth+.
         | 
| 811 | 
            +
                # include_all defaults to false to match Object#respond_to?
         | 
| 657 812 |  | 
| 658 | 
            -
                def refute_respond_to obj, meth, msg = nil
         | 
| 813 | 
            +
                def refute_respond_to obj, meth, msg = nil, include_all: false
         | 
| 659 814 | 
             
                  msg = message(msg) { "Expected #{mu_pp(obj)} to not respond to #{meth}" }
         | 
| 660 815 |  | 
| 661 | 
            -
                  refute obj.respond_to?(meth), msg
         | 
| 816 | 
            +
                  refute obj.respond_to?(meth, include_all), msg
         | 
| 662 817 | 
             
                end
         | 
| 663 818 |  | 
| 664 819 | 
             
                ##
         | 
| @@ -677,10 +832,22 @@ module Minitest | |
| 677 832 | 
             
                # gets listed at the end of the run but doesn't cause a failure
         | 
| 678 833 | 
             
                # exit code.
         | 
| 679 834 |  | 
| 680 | 
            -
                def skip msg = nil,  | 
| 835 | 
            +
                def skip msg = nil, _ignored = nil
         | 
| 681 836 | 
             
                  msg ||= "Skipped, no message given"
         | 
| 682 837 | 
             
                  @skip = true
         | 
| 683 | 
            -
                  raise Minitest::Skip, msg | 
| 838 | 
            +
                  raise Minitest::Skip, msg
         | 
| 839 | 
            +
                end
         | 
| 840 | 
            +
             | 
| 841 | 
            +
                ##
         | 
| 842 | 
            +
                # Skips the current run until a given date (in the local time
         | 
| 843 | 
            +
                # zone). This allows you to put some fixes on hold until a later
         | 
| 844 | 
            +
                # date, but still holds you accountable and prevents you from
         | 
| 845 | 
            +
                # forgetting it.
         | 
| 846 | 
            +
             | 
| 847 | 
            +
                def skip_until y,m,d,msg
         | 
| 848 | 
            +
                  skip msg if Time.now < Time.local(y, m, d)
         | 
| 849 | 
            +
                  where = caller.first.rpartition(':in').reject(&:empty?).first
         | 
| 850 | 
            +
                  warn "Stale skip_until %p at %s" % [msg, where]
         | 
| 684 851 | 
             
                end
         | 
| 685 852 |  | 
| 686 853 | 
             
                ##
         | 
    
        data/lib/minitest/benchmark.rb
    CHANGED
    
    | @@ -109,8 +109,8 @@ module Minitest | |
| 109 109 | 
             
                # is applied against the slope itself. As such, you probably want
         | 
| 110 110 | 
             
                # to tighten it from the default.
         | 
| 111 111 | 
             
                #
         | 
| 112 | 
            -
                # See  | 
| 113 | 
            -
                # more details.
         | 
| 112 | 
            +
                # See https://www.graphpad.com/guides/prism/8/curve-fitting/reg_intepretingnonlinr2.htm
         | 
| 113 | 
            +
                # for more details.
         | 
| 114 114 | 
             
                #
         | 
| 115 115 | 
             
                # Fit is calculated by #fit_linear.
         | 
| 116 116 | 
             
                #
         | 
| @@ -217,7 +217,7 @@ module Minitest | |
| 217 217 | 
             
                ##
         | 
| 218 218 | 
             
                # Takes an array of x/y pairs and calculates the general R^2 value.
         | 
| 219 219 | 
             
                #
         | 
| 220 | 
            -
                # See:  | 
| 220 | 
            +
                # See: https://en.wikipedia.org/wiki/Coefficient_of_determination
         | 
| 221 221 |  | 
| 222 222 | 
             
                def fit_error xys
         | 
| 223 223 | 
             
                  y_bar  = sigma(xys) { |_, y| y } / xys.size.to_f
         | 
| @@ -232,7 +232,7 @@ module Minitest | |
| 232 232 | 
             
                #
         | 
| 233 233 | 
             
                # Takes x and y values and returns [a, b, r^2].
         | 
| 234 234 | 
             
                #
         | 
| 235 | 
            -
                # See:  | 
| 235 | 
            +
                # See: https://mathworld.wolfram.com/LeastSquaresFittingExponential.html
         | 
| 236 236 |  | 
| 237 237 | 
             
                def fit_exponential xs, ys
         | 
| 238 238 | 
             
                  n     = xs.size
         | 
| @@ -254,7 +254,7 @@ module Minitest | |
| 254 254 | 
             
                #
         | 
| 255 255 | 
             
                # Takes x and y values and returns [a, b, r^2].
         | 
| 256 256 | 
             
                #
         | 
| 257 | 
            -
                # See:  | 
| 257 | 
            +
                # See: https://mathworld.wolfram.com/LeastSquaresFittingLogarithmic.html
         | 
| 258 258 |  | 
| 259 259 | 
             
                def fit_logarithmic xs, ys
         | 
| 260 260 | 
             
                  n     = xs.size
         | 
| @@ -276,7 +276,7 @@ module Minitest | |
| 276 276 | 
             
                #
         | 
| 277 277 | 
             
                # Takes x and y values and returns [a, b, r^2].
         | 
| 278 278 | 
             
                #
         | 
| 279 | 
            -
                # See:  | 
| 279 | 
            +
                # See: https://mathworld.wolfram.com/LeastSquaresFitting.html
         | 
| 280 280 |  | 
| 281 281 | 
             
                def fit_linear xs, ys
         | 
| 282 282 | 
             
                  n   = xs.size
         | 
| @@ -298,7 +298,7 @@ module Minitest | |
| 298 298 | 
             
                #
         | 
| 299 299 | 
             
                # Takes x and y values and returns [a, b, r^2].
         | 
| 300 300 | 
             
                #
         | 
| 301 | 
            -
                # See:  | 
| 301 | 
            +
                # See: https://mathworld.wolfram.com/LeastSquaresFittingPowerLaw.html
         | 
| 302 302 |  | 
| 303 303 | 
             
                def fit_power xs, ys
         | 
| 304 304 | 
             
                  n       = xs.size
         | 
| @@ -0,0 +1,94 @@ | |
| 1 | 
            +
            module Minitest
         | 
| 2 | 
            +
              ##
         | 
| 3 | 
            +
              # Compresses backtraces.
         | 
| 4 | 
            +
             | 
| 5 | 
            +
              module Compress
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                ##
         | 
| 8 | 
            +
                # Takes a backtrace (array of strings) and compresses repeating
         | 
| 9 | 
            +
                # cycles in it to make it more readable.
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                def compress orig
         | 
| 12 | 
            +
                  ary = orig
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  eswo = ->(ary, n, off) { # each_slice_with_offset
         | 
| 15 | 
            +
                    if off.zero? then
         | 
| 16 | 
            +
                      ary.each_slice n
         | 
| 17 | 
            +
                    else
         | 
| 18 | 
            +
                      # [ ...off... [...n...] [...n...] ... ]
         | 
| 19 | 
            +
                      front, back = ary.take(off), ary.drop(off)
         | 
| 20 | 
            +
                      [front].chain back.each_slice n
         | 
| 21 | 
            +
                    end
         | 
| 22 | 
            +
                  }
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  3.times do # maybe don't use loop do here?
         | 
| 25 | 
            +
                    index = ary                               # [ a b c b c b c d ]
         | 
| 26 | 
            +
                      .size
         | 
| 27 | 
            +
                      .times                                  # 0...size
         | 
| 28 | 
            +
                      .group_by { |i| ary[i] }                # { a: [0] b: [1 3 5], c: [2 4 6], d: [7] }
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                    order = index
         | 
| 31 | 
            +
                      .reject { |k, v| v.size == 1 }          # { b: [1 3 5], c: [2 4 6] }
         | 
| 32 | 
            +
                      .sort_by { |k, ary|                     ### sort by max dist + min offset
         | 
| 33 | 
            +
                        d = ary.each_cons(2).sum { |a, b| b-a }
         | 
| 34 | 
            +
                        [-d, ary.first]
         | 
| 35 | 
            +
                      }                                       # b: [1 3 5] c: [2 4 6]
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                    ranges = order
         | 
| 38 | 
            +
                      .map { |k, ary|                         # [[1..2 3..4] [2..3 4..5]]
         | 
| 39 | 
            +
                        ary
         | 
| 40 | 
            +
                          .each_cons(2)
         | 
| 41 | 
            +
                          .map { |a, b| a..b-1 }
         | 
| 42 | 
            +
                      }
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                    big_ranges = ranges
         | 
| 45 | 
            +
                      .flat_map { |a|                         # [1..2 3..4 2..3 4..5]
         | 
| 46 | 
            +
                        a.sort_by { |r| [-r.size, r.first] }.first 5
         | 
| 47 | 
            +
                      }
         | 
| 48 | 
            +
                      .first(100)
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                    culprits = big_ranges
         | 
| 51 | 
            +
                      .map { |r|
         | 
| 52 | 
            +
                        eswo[ary, r.size, r.begin]            # [o1 s1 s1 s2 s2]
         | 
| 53 | 
            +
                          .chunk_while { |a,b| a == b }       # [[o1] [s1 s1] [s2 s2]]
         | 
| 54 | 
            +
                          .map { |a| [a.size, a.first] }      # [[1 o1] [2 s1] [2 s2]]
         | 
| 55 | 
            +
                      }
         | 
| 56 | 
            +
                      .select { |chunks|
         | 
| 57 | 
            +
                        chunks.any? { |a| a.first > 1 }       # compressed anything?
         | 
| 58 | 
            +
                      }
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                    min = culprits
         | 
| 61 | 
            +
                      .min_by { |a| a.flatten.size }          # most compressed
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                    break unless min
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                    ary = min.flat_map { |(n, lines)|
         | 
| 66 | 
            +
                      if n > 1 then
         | 
| 67 | 
            +
                        [[n, compress(lines)]]                # [o1 [2 s1] [2 s2]]
         | 
| 68 | 
            +
                      else
         | 
| 69 | 
            +
                        lines
         | 
| 70 | 
            +
                      end
         | 
| 71 | 
            +
                    }
         | 
| 72 | 
            +
                  end
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                  format = ->(lines) {
         | 
| 75 | 
            +
                    lines.flat_map { |line|
         | 
| 76 | 
            +
                      case line
         | 
| 77 | 
            +
                      when Array then
         | 
| 78 | 
            +
                        n, lines = line
         | 
| 79 | 
            +
                        lines = format[lines]
         | 
| 80 | 
            +
                        [
         | 
| 81 | 
            +
                          " +->> #{n} cycles of #{lines.size} lines:",
         | 
| 82 | 
            +
                          *lines.map { |s| " | #{s}" },
         | 
| 83 | 
            +
                          " +-<<",
         | 
| 84 | 
            +
                        ]
         | 
| 85 | 
            +
                      else
         | 
| 86 | 
            +
                        line
         | 
| 87 | 
            +
                      end
         | 
| 88 | 
            +
                    }
         | 
| 89 | 
            +
                  }
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                  format[ary]
         | 
| 92 | 
            +
                end
         | 
| 93 | 
            +
              end
         | 
| 94 | 
            +
            end
         |