Module: Minitest::Assertions

Included in:
Test
Defined in:
opal/stdlib/minitest/assertions.rb

Overview

Minitest Assertions. All assertion methods accept a +msg+ which is printed if the assertion fails.

Protocol: Nearly everything here boils up to +assert+, which expects to be able to increment an instance accessor named +assertions+. This is not provided by Assertions and must be provided by the thing including Assertions. See Minitest::Runnable for an example.

Constant Summary

UNDEFINED =

:nodoc:

Object.new
E =

:nodoc:

""

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.diffObject

Returns the diff command to use in #diff. Tries to intelligently figure out what diff to use.



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'opal/stdlib/minitest/assertions.rb', line 27

def self.diff
  @diff = if (RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ &&
              system("diff.exe", __FILE__, __FILE__)) then
            "diff.exe -u"
          elsif Minitest::Test.maglev? then
            "diff -u"
          elsif system("gdiff", __FILE__, __FILE__)
            "gdiff -u" # solaris and kin suck
          elsif system("diff", __FILE__, __FILE__)
            "diff -u"
          else
            nil
          end unless defined? @diff

  @diff
end

.diff=(o) ⇒ Object

Set the diff command to use in #diff.



47
48
49
# File 'opal/stdlib/minitest/assertions.rb', line 47

def self.diff= o
  @diff = o
end

Instance Method Details

#_synchronizeObject

:nodoc:



135
136
137
# File 'opal/stdlib/minitest/assertions.rb', line 135

def _synchronize # :nodoc:
  yield
end

#assert(test, msg = nil) ⇒ Object

Fails unless +test+ is truthy.



125
126
127
128
129
130
131
132
133
# File 'opal/stdlib/minitest/assertions.rb', line 125

def assert test, msg = nil
  self.assertions += 1
  unless test then
    msg ||= "Failed assertion, no message given."
    msg = msg.call if Proc === msg
    raise Minitest::Assertion, msg
  end
  true
end

#assert_empty(obj, msg = nil) ⇒ Object

Fails unless +obj+ is empty.



142
143
144
145
146
# File 'opal/stdlib/minitest/assertions.rb', line 142

def assert_empty obj, msg = nil
  msg = message(msg) { "Expected #{mu_pp(obj)} to be empty" }
  assert_respond_to obj, :empty?
  assert obj.empty?, msg
end

#assert_equal(exp, act, msg = nil) ⇒ Object

Fails unless exp == act printing the difference between the two, if possible.

If there is no visible difference but the assertion fails, you should suspect that your #== is buggy, or your inspect output is missing crucial details.

For floats use assert_in_delta.

See also: Minitest::Assertions.diff



162
163
164
165
# File 'opal/stdlib/minitest/assertions.rb', line 162

def assert_equal exp, act, msg = nil
  msg = message(msg, E) { diff exp, act }
  assert exp == act, msg
end

#assert_in_delta(exp, act, delta = 0.001, msg = nil) ⇒ Object

For comparing Floats. Fails unless +exp+ and +act+ are within +delta+ of each other.

assert_in_delta Math::PI, (22.0 / 7.0), 0.01



173
174
175
176
177
178
179
# File 'opal/stdlib/minitest/assertions.rb', line 173

def assert_in_delta exp, act, delta = 0.001, msg = nil
  n = (exp - act).abs
  msg = message(msg) {
    "Expected |#{exp} - #{act}| (#{n}) to be <= #{delta}"
  }
  assert delta >= n, msg
end

#assert_in_epsilon(a, b, epsilon = 0.001, msg = nil) ⇒ Object

For comparing Floats. Fails unless +exp+ and +act+ have a relative error less than +epsilon+.



185
186
187
# File 'opal/stdlib/minitest/assertions.rb', line 185

def assert_in_epsilon a, b, epsilon = 0.001, msg = nil
  assert_in_delta a, b, [a.abs, b.abs].min * epsilon, msg
end

#assert_includes(collection, obj, msg = nil) ⇒ Object

Fails unless +collection+ includes +obj+.



192
193
194
195
196
197
198
# File 'opal/stdlib/minitest/assertions.rb', line 192

def assert_includes collection, obj, msg = nil
  msg = message(msg) {
    "Expected #{mu_pp(collection)} to include #{mu_pp(obj)}"
  }
  assert_respond_to collection, :include?
  assert collection.include?(obj), msg
end

#assert_instance_of(cls, obj, msg = nil) ⇒ Object

Fails unless +obj+ is an instance of +cls+.



203
204
205
206
207
208
209
# File 'opal/stdlib/minitest/assertions.rb', line 203

def assert_instance_of cls, obj, msg = nil
  msg = message(msg) {
    "Expected #{mu_pp(obj)} to be an instance of #{cls}, not #{obj.class}"
  }

  assert obj.instance_of?(cls), msg
end

#assert_kind_of(cls, obj, msg = nil) ⇒ Object

Fails unless +obj+ is a kind of +cls+.



214
215
216
217
218
219
# File 'opal/stdlib/minitest/assertions.rb', line 214

def assert_kind_of cls, obj, msg = nil
  msg = message(msg) {
    "Expected #{mu_pp(obj)} to be a kind of #{cls}, not #{obj.class}" }

  assert obj.kind_of?(cls), msg
end

#assert_match(matcher, obj, msg = nil) ⇒ Object

Fails unless +matcher+ =~ +obj+.



224
225
226
227
228
229
# File 'opal/stdlib/minitest/assertions.rb', line 224

def assert_match matcher, obj, msg = nil
  msg = message(msg) { "Expected #{mu_pp matcher} to match #{mu_pp obj}" }
  assert_respond_to matcher, :=~"
  matcher = Regexp.new Regexp.escape matcher if String === matcher
  assert matcher =~ obj, msg
end

#assert_nil(obj, msg = nil) ⇒ Object

Fails unless +obj+ is nil



234
235
236
237
# File 'opal/stdlib/minitest/assertions.rb', line 234

def assert_nil obj, msg = nil
  msg = message(msg) { "Expected #{mu_pp(obj)} to be nil" }
  assert obj.nil?, msg
end

#assert_operator(o1, op, o2 = UNDEFINED, msg = nil) ⇒ Object

For testing with binary operators. Eg:

assert_operator 5, :<=, 4



244
245
246
247
248
# File 'opal/stdlib/minitest/assertions.rb', line 244

def assert_operator o1, op, o2 = UNDEFINED, msg = nil
  return assert_predicate o1, op, msg if UNDEFINED == o2
  msg = message(msg) { "Expected #{mu_pp(o1)} to be #{op} #{mu_pp(o2)}" }
  assert o1.__send__(op, o2), msg
end

#assert_output(stdout = nil, stderr = nil) ⇒ Object

Fails if stdout or stderr do not output the expected results. Pass in nil if you don't care about that streams output. Pass in "" if you require it to be silent. Pass in a regexp if you want to pattern match.

NOTE: this uses #capture_io, not #capture_subprocess_io.

See also: #assert_silent



260
261
262
263
264
265
266
267
268
269
270
271
272
# File 'opal/stdlib/minitest/assertions.rb', line 260

def assert_output stdout = nil, stderr = nil
  out, err = capture_io do
    yield
  end

  err_msg = Regexp === stderr ? :assert_match : :assert_equal if stderr
  out_msg = Regexp === stdout ? :assert_match : :assert_equal if stdout

  y = send err_msg, stderr, err, "In stderr" if err_msg
  x = send out_msg, stdout, out, "In stdout" if out_msg

  (!stdout || x) && (!stderr || y)
end

#assert_predicate(o1, op, msg = nil) ⇒ Object

For testing with predicates. Eg:

assert_predicate str, :empty?

This is really meant for specs and is front-ended by assert_operator:

str.must_be :empty?



283
284
285
286
# File 'opal/stdlib/minitest/assertions.rb', line 283

def assert_predicate o1, op, msg = nil
  msg = message(msg) { "Expected #{mu_pp(o1)} to be #{op}" }
  assert o1.__send__(op), msg
end

#assert_raises(*exp) ⇒ Object

Fails unless the block raises one of +exp+. Returns the exception matched so you can check the message, attributes, etc.



292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
# File 'opal/stdlib/minitest/assertions.rb', line 292

def assert_raises *exp
  msg = "#{exp.pop}.\n" if String === exp.last

  begin
    yield
  rescue Minitest::Skip => e
    return e if exp.include? Minitest::Skip
    raise e
  rescue Exception => e
    expected = exp.any? { |ex|
      if ex.instance_of? Module then
        e.kind_of? ex
      else
        e.instance_of? ex
      end
    }

    assert expected, proc {
      exception_details(e, "#{msg}#{mu_pp(exp)} exception expected, not")
    }

    return e
  end

  exp = exp.first if exp.size == 1

  flunk "#{msg}#{mu_pp(exp)} expected but nothing was raised."
end

#assert_respond_to(obj, meth, msg = nil) ⇒ Object

Fails unless +obj+ responds to +meth+.



324
325
326
327
328
329
# File 'opal/stdlib/minitest/assertions.rb', line 324

def assert_respond_to obj, meth, msg = nil
  msg = message(msg) {
    "Expected #{mu_pp(obj)} (#{obj.class}) to respond to ##{meth}"
  }
  assert obj.respond_to?(meth), msg
end

#assert_same(exp, act, msg = nil) ⇒ Object

Fails unless +exp+ and +act+ are #equal?



334
335
336
337
338
339
340
# File 'opal/stdlib/minitest/assertions.rb', line 334

def assert_same exp, act, msg = nil
  msg = message(msg) {
    data = [mu_pp(act), act.object_id, mu_pp(exp), exp.object_id]
    "Expected %s (oid=%d) to be the same as %s (oid=%d)" % data
  }
  assert exp.equal?(act), msg
end

#assert_send(send_ary, m = nil) ⇒ Object

+send_ary+ is a receiver, message and arguments.

Fails unless the call returns a true value



347
348
349
350
351
352
# File 'opal/stdlib/minitest/assertions.rb', line 347

def assert_send send_ary, m = nil
  recv, msg, *args = send_ary
  m = message(m) {
    "Expected #{mu_pp(recv)}.#{msg}(*#{mu_pp(args)}) to return true" }
  assert recv.__send__(msg, *args), m
end

#assert_silentObject

Fails if the block outputs anything to stderr or stdout.

See also: #assert_output



359
360
361
362
363
# File 'opal/stdlib/minitest/assertions.rb', line 359

def assert_silent
  assert_output "", "" do
    yield
  end
end

#assert_throws(sym, msg = nil) ⇒ Object

Fails unless the block throws +sym+



368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
# File 'opal/stdlib/minitest/assertions.rb', line 368

def assert_throws sym, msg = nil
  default = "Expected #{mu_pp(sym)} to have been thrown"
  caught = true
  catch(sym) do
    begin
      yield
    rescue ThreadError => e       # wtf?!? 1.8 + threads == suck
      default += ", not \:#{e.message[/uncaught throw \`(\w+?)\'/, 1]}"
    rescue ArgumentError => e     # 1.9 exception
      default += ", not #{e.message.split(/ /).last}"
    rescue NameError => e         # 1.8 exception
      default += ", not #{e.name.inspect}"
    end
    caught = false
  end

  assert caught, message(msg) { default }
end

#capture_ioObject

Captures $stdout and $stderr into strings:

out, err = capture_io do puts "Some info" warn "You did a bad thing" end

assert_match %r%info%, out assert_match %r%bad%, err

NOTE: For efficiency, this method uses StringIO and does not capture IO for subprocesses. Use #capture_subprocess_io for that.



402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
# File 'opal/stdlib/minitest/assertions.rb', line 402

def capture_io
  _synchronize do
    begin
      captured_stdout, captured_stderr = StringIO.new, StringIO.new

      orig_stdout, orig_stderr = $stdout, $stderr
      $stdout, $stderr         = captured_stdout, captured_stderr

      yield

      return captured_stdout.string, captured_stderr.string
    ensure
      $stdout = orig_stdout
      $stderr = orig_stderr
    end
  end
end

#capture_subprocess_ioObject

Captures $stdout and $stderr into strings, using Tempfile to ensure that subprocess IO is captured as well.

out, err = capture_subprocess_io do system "echo Some info" system "echo You did a bad thing 1>&2" end

assert_match %r%info%, out assert_match %r%bad%, err

NOTE: This method is approximately 10x slower than #capture_io so only use it when you need to test the output of a subprocess.



435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
# File 'opal/stdlib/minitest/assertions.rb', line 435

def capture_subprocess_io
  _synchronize do
    begin
  require 'tempfile'

  captured_stdout, captured_stderr = Tempfile.new("out"), Tempfile.new("err")

  orig_stdout, orig_stderr = $stdout.dup, $stderr.dup
  $stdout.reopen captured_stdout
  $stderr.reopen captured_stderr

  yield

  $stdout.rewind
  $stderr.rewind

  return captured_stdout.read, captured_stderr.read
ensure
  captured_stdout.unlink
  captured_stderr.unlink
  $stdout.reopen orig_stdout
  $stderr.reopen orig_stderr
    end
  end
end

#diff(exp, act) ⇒ Object

Returns a diff between +exp+ and +act+. If there is no known diff command or if it doesn't make sense to diff the output (single line, short output), then it simply returns a basic comparison between the two.



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'opal/stdlib/minitest/assertions.rb', line 57

def diff exp, act
  expect = mu_pp_for_diff exp
  butwas = mu_pp_for_diff act
  result = nil

  need_to_diff = false
    # (expect.include?("\n")    ||
    #  butwas.include?("\n")    ||
    #  expect.size > 30         ||
    #  butwas.size > 30         ||
    #  expect == butwas)        &&
    # Minitest::Assertions.diff


  return "Expected: #{mu_pp exp}\n  Actual: #{mu_pp act}" unless
    need_to_diff

  # Tempfile.open("expect") do |a|
  #   a.puts expect
  #   a.flush
  #
  #   Tempfile.open("butwas") do |b|
  #     b.puts butwas
  #     b.flush
  #
  #     result = `#{Minitest::Assertions.diff} #{a.path} #{b.path}`
  #     result.sub!(/^\-\-\- .+/, "--- expected")
  #     result.sub!(/^\+\+\+ .+/, "+++ actual")
  #
  #     if result.empty? then
  #       klass = exp.class
  #       result = [
  #                 "No visible difference in the #{klass}#inspect output.\n",
  #                 "You should look at the implementation of #== on ",
  #                 "#{klass} or its members.\n",
  #                 expect,
  #                ].join
  #     end
  #   end
  # end

  result
end

#exception_details(e, msg) ⇒ Object

Returns details for exception +e+



464
465
466
467
468
469
470
471
472
473
# File 'opal/stdlib/minitest/assertions.rb', line 464

def exception_details e, msg
  [
   "#{msg}",
   "Class: <#{e.class}>",
   "Message: <#{e.message.inspect}>",
   "---Backtrace---",
   "#{Minitest::filter_backtrace(e.backtrace).join("\n")}",
   "---------------",
  ].join "\n"
end

#flunk(msg = nil) ⇒ Object

Fails with +msg+



478
479
480
481
# File 'opal/stdlib/minitest/assertions.rb', line 478

def flunk msg = nil
  msg ||= "Epic Fail!"
  assert false, msg
end

#message(msg = nil, ending = nil, &default) ⇒ Object

Returns a proc that will output +msg+ along with the default message.



486
487
488
489
490
491
492
# File 'opal/stdlib/minitest/assertions.rb', line 486

def message msg = nil, ending = nil, &default
  proc {
    msg = msg.call.chomp(".") if Proc === msg
    custom_message = "#{msg}.\n" unless msg.nil? or msg.to_s.empty?
    "#{custom_message}#{default.call}#{ending || "."}"
  }
end

#mu_pp(obj) ⇒ Object

This returns a human-readable version of +obj+. By default

inspect is called. You can override this to use #pretty_print

if you want.



106
107
108
109
110
# File 'opal/stdlib/minitest/assertions.rb', line 106

def mu_pp obj
  s = obj.inspect
  s = s.encode Encoding.default_external if defined? Encoding
  s
end

#mu_pp_for_diff(obj) ⇒ Object

This returns a diff-able human-readable version of +obj+. This differs from the regular mu_pp because it expands escaped newlines and makes hex-values generic (like object_ids). This uses mu_pp to do the first pass and then cleans it up.



118
119
120
# File 'opal/stdlib/minitest/assertions.rb', line 118

def mu_pp_for_diff obj
  mu_pp(obj).gsub(/\\n/, "\n").gsub(/:0x[a-fA-F0-9]{4,}/m, ':0xXXXXXX')
end

#pass(msg = nil) ⇒ Object

used for counting assertions



497
498
499
# File 'opal/stdlib/minitest/assertions.rb', line 497

def pass msg = nil
  assert true
end

#refute(test, msg = nil) ⇒ Object

Fails if +test+ is truthy.



504
505
506
507
# File 'opal/stdlib/minitest/assertions.rb', line 504

def refute test, msg = nil
  msg ||= "Failed refutation, no message given"
  not assert(! test, msg)
end

#refute_empty(obj, msg = nil) ⇒ Object

Fails if +obj+ is empty.



512
513
514
515
516
# File 'opal/stdlib/minitest/assertions.rb', line 512

def refute_empty obj, msg = nil
  msg = message(msg) { "Expected #{mu_pp(obj)} to not be empty" }
  assert_respond_to obj, :empty?
  refute obj.empty?, msg
end

#refute_equal(exp, act, msg = nil) ⇒ Object

Fails if exp == act.

For floats use refute_in_delta.



523
524
525
526
527
528
# File 'opal/stdlib/minitest/assertions.rb', line 523

def refute_equal exp, act, msg = nil
  msg = message(msg) {
    "Expected #{mu_pp(act)} to not be equal to #{mu_pp(exp)}"
  }
  refute exp == act, msg
end

#refute_in_delta(exp, act, delta = 0.001, msg = nil) ⇒ Object

For comparing Floats. Fails if +exp+ is within +delta+ of +act+.

refute_in_delta Math::PI, (22.0 / 7.0)



535
536
537
538
539
540
541
# File 'opal/stdlib/minitest/assertions.rb', line 535

def refute_in_delta exp, act, delta = 0.001, msg = nil
  n = (exp - act).abs
  msg = message(msg) {
    "Expected |#{exp} - #{act}| (#{n}) to not be <= #{delta}"
  }
  refute delta >= n, msg
end

#refute_in_epsilon(a, b, epsilon = 0.001, msg = nil) ⇒ Object

For comparing Floats. Fails if +exp+ and +act+ have a relative error less than +epsilon+.



547
548
549
# File 'opal/stdlib/minitest/assertions.rb', line 547

def refute_in_epsilon a, b, epsilon = 0.001, msg = nil
  refute_in_delta a, b, a * epsilon, msg
end

#refute_includes(collection, obj, msg = nil) ⇒ Object

Fails if +collection+ includes +obj+.



554
555
556
557
558
559
560
# File 'opal/stdlib/minitest/assertions.rb', line 554

def refute_includes collection, obj, msg = nil
  msg = message(msg) {
    "Expected #{mu_pp(collection)} to not include #{mu_pp(obj)}"
  }
  assert_respond_to collection, :include?
  refute collection.include?(obj), msg
end

#refute_instance_of(cls, obj, msg = nil) ⇒ Object

Fails if +obj+ is an instance of +cls+.



565
566
567
568
569
570
# File 'opal/stdlib/minitest/assertions.rb', line 565

def refute_instance_of cls, obj, msg = nil
  msg = message(msg) {
    "Expected #{mu_pp(obj)} to not be an instance of #{cls}"
  }
  refute obj.instance_of?(cls), msg
end

#refute_kind_of(cls, obj, msg = nil) ⇒ Object

Fails if +obj+ is a kind of +cls+.



575
576
577
578
# File 'opal/stdlib/minitest/assertions.rb', line 575

def refute_kind_of cls, obj, msg = nil
  msg = message(msg) { "Expected #{mu_pp(obj)} to not be a kind of #{cls}" }
  refute obj.kind_of?(cls), msg
end

#refute_match(matcher, obj, msg = nil) ⇒ Object

Fails if +matcher+ =~ +obj+.



583
584
585
586
587
588
# File 'opal/stdlib/minitest/assertions.rb', line 583

def refute_match matcher, obj, msg = nil
  msg = message(msg) {"Expected #{mu_pp matcher} to not match #{mu_pp obj}"}
  assert_respond_to matcher, :=~"
  matcher = Regexp.new Regexp.escape matcher if String === matcher
  refute matcher =~ obj, msg
end

#refute_nil(obj, msg = nil) ⇒ Object

Fails if +obj+ is nil.



593
594
595
596
# File 'opal/stdlib/minitest/assertions.rb', line 593

def refute_nil obj, msg = nil
  msg = message(msg) { "Expected #{mu_pp(obj)} to not be nil" }
  refute obj.nil?, msg
end

#refute_operator(o1, op, o2 = UNDEFINED, msg = nil) ⇒ Object

Fails if +o1+ is not +op+ +o2+. Eg:

refute_operator 1, :>, 2 #=> pass refute_operator 1, :<, 2 #=> fail



604
605
606
607
608
# File 'opal/stdlib/minitest/assertions.rb', line 604

def refute_operator o1, op, o2 = UNDEFINED, msg = nil
  return refute_predicate o1, op, msg if UNDEFINED == o2
  msg = message(msg) { "Expected #{mu_pp(o1)} to not be #{op} #{mu_pp(o2)}"}
  refute o1.__send__(op, o2), msg
end

#refute_predicate(o1, op, msg = nil) ⇒ Object

For testing with predicates.

refute_predicate str, :empty?

This is really meant for specs and is front-ended by refute_operator:

str.wont_be :empty?



619
620
621
622
# File 'opal/stdlib/minitest/assertions.rb', line 619

def refute_predicate o1, op, msg = nil
  msg = message(msg) { "Expected #{mu_pp(o1)} to not be #{op}" }
  refute o1.__send__(op), msg
end

#refute_respond_to(obj, meth, msg = nil) ⇒ Object

Fails if +obj+ responds to the message +meth+.



627
628
629
630
631
# File 'opal/stdlib/minitest/assertions.rb', line 627

def refute_respond_to obj, meth, msg = nil
  msg = message(msg) { "Expected #{mu_pp(obj)} to not respond to #{meth}" }

  refute obj.respond_to?(meth), msg
end

#refute_same(exp, act, msg = nil) ⇒ Object

Fails if +exp+ is the same (by object identity) as +act+.



636
637
638
639
640
641
642
# File 'opal/stdlib/minitest/assertions.rb', line 636

def refute_same exp, act, msg = nil
  msg = message(msg) {
    data = [mu_pp(act), act.object_id, mu_pp(exp), exp.object_id]
    "Expected %s (oid=%d) to not be the same as %s (oid=%d)" % data
  }
  refute exp.equal?(act), msg
end

#skip(msg = nil, bt = caller) ⇒ Object

Skips the current run. If run in verbose-mode, the skipped run gets listed at the end of the run but doesn't cause a failure exit code.

Raises:



649
650
651
652
653
# File 'opal/stdlib/minitest/assertions.rb', line 649

def skip msg = nil, bt = caller
  msg ||= "Skipped, no message given"
  @skip = true
  raise Minitest::Skip, msg, bt
end

#skipped?Boolean

Was this testcase skipped? Meant for #teardown.

Returns:



658
659
660
# File 'opal/stdlib/minitest/assertions.rb', line 658

def skipped?
  defined?(@skip) and @skip
end