micron 0.5.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.
Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +19 -0
  3. data/Gemfile.lock +88 -0
  4. data/Rakefile +40 -0
  5. data/VERSION +1 -0
  6. data/bin/micron +4 -0
  7. data/lib/micron.rb +29 -0
  8. data/lib/micron/app.rb +127 -0
  9. data/lib/micron/app/options.rb +73 -0
  10. data/lib/micron/assertion.rb +10 -0
  11. data/lib/micron/fork_runner.rb +55 -0
  12. data/lib/micron/minitest.rb +45 -0
  13. data/lib/micron/proc_runner.rb +114 -0
  14. data/lib/micron/rake.rb +29 -0
  15. data/lib/micron/reporter.rb +30 -0
  16. data/lib/micron/reporter/console.rb +146 -0
  17. data/lib/micron/reporter/coverage.rb +37 -0
  18. data/lib/micron/runner.rb +95 -0
  19. data/lib/micron/runner/backtrace_filter.rb +39 -0
  20. data/lib/micron/runner/clazz.rb +45 -0
  21. data/lib/micron/runner/clazz19.rb +24 -0
  22. data/lib/micron/runner/debug.rb +22 -0
  23. data/lib/micron/runner/exception_info.rb +16 -0
  24. data/lib/micron/runner/fork_worker.rb +185 -0
  25. data/lib/micron/runner/forking_clazz.rb +40 -0
  26. data/lib/micron/runner/liveness_checker.rb +40 -0
  27. data/lib/micron/runner/liveness_checker/ping.rb +65 -0
  28. data/lib/micron/runner/liveness_checker/pong.rb +36 -0
  29. data/lib/micron/runner/method.rb +124 -0
  30. data/lib/micron/runner/parallel_clazz.rb +135 -0
  31. data/lib/micron/runner/proc_clazz.rb +48 -0
  32. data/lib/micron/runner/process_reaper.rb +98 -0
  33. data/lib/micron/runner/shim.rb +68 -0
  34. data/lib/micron/runner/test_file.rb +79 -0
  35. data/lib/micron/test_case.rb +36 -0
  36. data/lib/micron/test_case/assertions.rb +701 -0
  37. data/lib/micron/test_case/lifecycle_hooks.rb +74 -0
  38. data/lib/micron/test_case/redir_logging.rb +85 -0
  39. data/lib/micron/test_case/teardown_coverage.rb +13 -0
  40. data/lib/micron/util/ex.rb +23 -0
  41. data/lib/micron/util/io.rb +54 -0
  42. data/lib/micron/util/thread_dump.rb +29 -0
  43. data/micron.gemspec +97 -0
  44. metadata +184 -0
@@ -0,0 +1,79 @@
1
+
2
+ module Micron
3
+ class Runner
4
+ class TestFile
5
+
6
+ def initialize(filename)
7
+ @filename = filename
8
+ end
9
+
10
+ # Load the test file
11
+ #
12
+ # @throws [Exception] exception, if one was raised during loading
13
+ def load(coverage=false)
14
+ if coverage then
15
+ file = @filename
16
+ EasyCov.filters << lambda { |f| f == file }
17
+ EasyCov.start
18
+ end
19
+ require @filename
20
+ return nil
21
+ end
22
+
23
+ # Simply load the file and collect coverage
24
+ def collect_coverage
25
+ worker = ForkWorker.new do
26
+ load(true)
27
+ EasyCov.dump
28
+ end
29
+ worker.run
30
+ worker.wait
31
+ end
32
+
33
+ # Execute the tests in the file, using the given Clazz
34
+ #
35
+ # @param [Clazz] run_clazz
36
+ #
37
+ # @return [Array<Object>] array of Clazz and Exception objects
38
+ def run(run_clazz)
39
+
40
+ results = []
41
+ test_clazz = TestCase.subclasses.last
42
+
43
+ begin
44
+ clazz = run_clazz.new(test_clazz, @filename)
45
+
46
+ Micron.runner.report(:start_class, clazz)
47
+ if !clazz.methods.empty? then
48
+ clazz.run
49
+ results << clazz
50
+ end
51
+ Micron.runner.report(:end_class, clazz)
52
+
53
+ rescue Exception => ex
54
+ # Error with loading the test class itself
55
+ results << ex
56
+ return results
57
+ end
58
+
59
+ return results
60
+ end
61
+
62
+ # Run the given test method
63
+ #
64
+ # @param [String] test_clazz Name of the TestCase Class
65
+ # @param [String] test_method Method name
66
+ # @param [Clazz] run_clazz Clazz to run with
67
+ #
68
+ # @return [Method]
69
+ def run_method(test_clazz, test_method, run_clazz)
70
+ clazz = run_clazz.new(test_clazz, @filename)
71
+ method = clazz.methods.find{ |m| m.name.to_s == test_method }
72
+ method.run
73
+
74
+ return method
75
+ end
76
+
77
+ end # TestFile
78
+ end # Runner
79
+ end # Micron
@@ -0,0 +1,36 @@
1
+
2
+ require "micron/test_case/assertions"
3
+ require "micron/test_case/lifecycle_hooks"
4
+
5
+ module Micron
6
+
7
+ class TestCase
8
+
9
+ include LifecycleHooks
10
+ include Assertions
11
+
12
+ def setup
13
+ end
14
+
15
+ def teardown
16
+ end
17
+
18
+
19
+ # retrieve all loaded subclasses of this class
20
+ #
21
+ # @return [Array<Class>] List of subclasses
22
+ def self.subclasses
23
+ @subclasses
24
+ end
25
+
26
+ def self.inherited(subclass)
27
+ if superclass.respond_to? :inherited
28
+ superclass.inherited(subclass)
29
+ end
30
+ @subclasses ||= []
31
+ @subclasses << subclass
32
+ end
33
+
34
+ end
35
+
36
+ end
@@ -0,0 +1,701 @@
1
+
2
+ module Micron
3
+
4
+ class TestCase
5
+
6
+ # Micron Assertions. All assertion methods accept a +msg+ which is
7
+ # printed if the assertion fails.
8
+ #
9
+ # Copied from MiniTest
10
+ module Assertions
11
+
12
+ UNDEFINED = Object.new # :nodoc:
13
+
14
+ def UNDEFINED.inspect # :nodoc:
15
+ "UNDEFINED" # again with the rdoc bugs... :(
16
+ end
17
+
18
+ ##
19
+ # Returns the diff command to use in #diff. Tries to intelligently
20
+ # figure out what diff to use.
21
+
22
+ def self.diff
23
+ @diff = if (RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ &&
24
+ system("diff.exe", __FILE__, __FILE__)) then
25
+ "diff.exe -u"
26
+ # elsif Minitest::Unit::Guard.maglev? then # HACK
27
+ # "diff -u"
28
+ elsif system("gdiff", __FILE__, __FILE__)
29
+ "gdiff -u" # solaris and kin suck
30
+ elsif system("diff", __FILE__, __FILE__)
31
+ "diff -u"
32
+ else
33
+ nil
34
+ end unless defined? @diff
35
+
36
+ @diff
37
+ end
38
+
39
+ ##
40
+ # Set the diff command to use in #diff.
41
+
42
+ def self.diff= o
43
+ @diff = o
44
+ end
45
+
46
+ ##
47
+ # Returns a diff between +exp+ and +act+. If there is no known
48
+ # diff command or if it doesn't make sense to diff the output
49
+ # (single line, short output), then it simply returns a basic
50
+ # comparison between the two.
51
+
52
+ def diff exp, act
53
+ require "tempfile"
54
+
55
+ expect = mu_pp_for_diff exp
56
+ butwas = mu_pp_for_diff act
57
+ result = nil
58
+
59
+ need_to_diff =
60
+ Micron::TestCase::Assertions.diff &&
61
+ (expect.include?("\n") ||
62
+ butwas.include?("\n") ||
63
+ expect.size > 30 ||
64
+ butwas.size > 30 ||
65
+ expect == butwas)
66
+
67
+ return "Expected: #{mu_pp exp}\n Actual: #{mu_pp act}" unless
68
+ need_to_diff
69
+
70
+ Tempfile.open("expect") do |a|
71
+ a.puts expect
72
+ a.flush
73
+
74
+ Tempfile.open("butwas") do |b|
75
+ b.puts butwas
76
+ b.flush
77
+
78
+ result = `#{Micron::TestCase::Assertions.diff} #{a.path} #{b.path}`
79
+ result.sub!(/^\-\-\- .+/, "--- expected")
80
+ result.sub!(/^\+\+\+ .+/, "+++ actual")
81
+
82
+ if result.empty? then
83
+ klass = exp.class
84
+ result = [
85
+ "No visible difference in the #{klass}#inspect output.\n",
86
+ "You should look at the implementation of #== on ",
87
+ "#{klass} or its members.\n",
88
+ expect,
89
+ ].join
90
+ end
91
+ end
92
+ end
93
+
94
+ result
95
+ end
96
+
97
+ ##
98
+ # This returns a human-readable version of +obj+. By default
99
+ # #inspect is called. You can override this to use #pretty_print
100
+ # if you want.
101
+
102
+ def mu_pp obj
103
+ s = obj.inspect
104
+ s = s.encode Encoding.default_external if defined? Encoding
105
+ s
106
+ end
107
+
108
+ ##
109
+ # This returns a diff-able human-readable version of +obj+. This
110
+ # differs from the regular mu_pp because it expands escaped
111
+ # newlines and makes hex-values generic (like object_ids). This
112
+ # uses mu_pp to do the first pass and then cleans it up.
113
+
114
+ def mu_pp_for_diff obj
115
+ mu_pp(obj).gsub(/\\n/, "\n").gsub(/:0x[a-fA-F0-9]{4,}/m, ':0xXXXXXX')
116
+ end
117
+
118
+ def _assertions= n # :nodoc:
119
+ @_assertions = n
120
+ end
121
+
122
+ def _assertions # :nodoc:
123
+ @_assertions ||= 0
124
+ end
125
+
126
+ ##
127
+ # Fails unless +test+ is a true value.
128
+
129
+ def assert test, msg = nil
130
+ msg ||= "Failed assertion, no message given."
131
+ self._assertions += 1
132
+ unless test then
133
+ msg = msg.call if Proc === msg
134
+ raise Micron::Assertion, msg
135
+ end
136
+ true
137
+ end
138
+
139
+ ##
140
+ # Fails unless +obj+ is empty.
141
+
142
+ def assert_empty obj, msg = nil
143
+ msg = message(msg) { "Expected #{mu_pp(obj)} to be empty" }
144
+ assert_respond_to obj, :empty?
145
+ assert obj.empty?, msg
146
+ end
147
+
148
+ ##
149
+ # Fails unless <tt>exp == act</tt> printing the difference between
150
+ # the two, if possible.
151
+ #
152
+ # If there is no visible difference but the assertion fails, you
153
+ # should suspect that your #== is buggy, or your inspect output is
154
+ # missing crucial details.
155
+ #
156
+ # For floats use assert_in_delta.
157
+ #
158
+ # See also: Micron::TestCase::Assertions.diff
159
+
160
+ def assert_equal exp, act, msg = nil
161
+ msg = message(msg, "") { diff exp, act }
162
+ assert exp == act, msg
163
+ end
164
+
165
+ ##
166
+ # For comparing Floats. Fails unless +exp+ and +act+ are within +delta+
167
+ # of each other.
168
+ #
169
+ # assert_in_delta Math::PI, (22.0 / 7.0), 0.01
170
+
171
+ def assert_in_delta exp, act, delta = 0.001, msg = nil
172
+ n = (exp - act).abs
173
+ msg = message(msg) {
174
+ "Expected |#{exp} - #{act}| (#{n}) to be <= #{delta}"
175
+ }
176
+ assert delta >= n, msg
177
+ end
178
+
179
+ ##
180
+ # For comparing Floats. Fails unless +exp+ and +act+ have a relative
181
+ # error less than +epsilon+.
182
+
183
+ def assert_in_epsilon a, b, epsilon = 0.001, msg = nil
184
+ assert_in_delta a, b, [a.abs, b.abs].min * epsilon, msg
185
+ end
186
+
187
+ ##
188
+ # Fails unless +collection+ includes +obj+.
189
+
190
+ def assert_includes collection, obj, msg = nil
191
+ msg = message(msg) {
192
+ "Expected #{mu_pp(collection)} to include #{mu_pp(obj)}"
193
+ }
194
+ assert_respond_to collection, :include?
195
+ assert collection.include?(obj), msg
196
+ end
197
+
198
+ ##
199
+ # Fails unless +obj+ is an instance of +cls+.
200
+
201
+ def assert_instance_of cls, obj, msg = nil
202
+ msg = message(msg) {
203
+ "Expected #{mu_pp(obj)} to be an instance of #{cls}, not #{obj.class}"
204
+ }
205
+
206
+ assert obj.instance_of?(cls), msg
207
+ end
208
+
209
+ ##
210
+ # Fails unless +obj+ is a kind of +cls+.
211
+
212
+ def assert_kind_of cls, obj, msg = nil # TODO: merge with instance_of
213
+ msg = message(msg) {
214
+ "Expected #{mu_pp(obj)} to be a kind of #{cls}, not #{obj.class}" }
215
+
216
+ assert obj.kind_of?(cls), msg
217
+ end
218
+
219
+ ##
220
+ # Fails unless +matcher+ <tt>=~</tt> +obj+.
221
+
222
+ def assert_match matcher, obj, msg = nil
223
+ msg = message(msg) { "Expected #{mu_pp matcher} to match #{mu_pp obj}" }
224
+ assert_respond_to matcher, :"=~"
225
+ matcher = Regexp.new Regexp.escape matcher if String === matcher
226
+ assert matcher =~ obj, msg
227
+ end
228
+
229
+ ##
230
+ # Fails unless +obj+ is nil
231
+
232
+ def assert_nil obj, msg = nil
233
+ msg = message(msg) { "Expected #{mu_pp(obj)} to be nil" }
234
+ assert obj.nil?, msg
235
+ end
236
+
237
+ ##
238
+ # For testing with binary operators.
239
+ #
240
+ # assert_operator 5, :<=, 4
241
+
242
+ def assert_operator o1, op, o2 = UNDEFINED, msg = nil
243
+ return assert_predicate o1, op, msg if UNDEFINED == o2
244
+ msg = message(msg) { "Expected #{mu_pp(o1)} to be #{op} #{mu_pp(o2)}" }
245
+ assert o1.__send__(op, o2), msg
246
+ end
247
+
248
+ ##
249
+ # Fails if stdout or stderr do not output the expected results.
250
+ # Pass in nil if you don't care about that streams output. Pass in
251
+ # "" if you require it to be silent. Pass in a regexp if you want
252
+ # to pattern match.
253
+ #
254
+ # NOTE: this uses #capture_io, not #capture_subprocess_io.
255
+ #
256
+ # See also: #assert_silent
257
+
258
+ def assert_output stdout = nil, stderr = nil
259
+ out, err = capture_io do
260
+ yield
261
+ end
262
+
263
+ err_msg = Regexp === stderr ? :assert_match : :assert_equal if stderr
264
+ out_msg = Regexp === stdout ? :assert_match : :assert_equal if stdout
265
+
266
+ y = send err_msg, stderr, err, "In stderr" if err_msg
267
+ x = send out_msg, stdout, out, "In stdout" if out_msg
268
+
269
+ (!stdout || x) && (!stderr || y)
270
+ end
271
+
272
+ ##
273
+ # For testing with predicates.
274
+ #
275
+ # assert_predicate str, :empty?
276
+ #
277
+ # This is really meant for specs and is front-ended by assert_operator:
278
+ #
279
+ # str.must_be :empty?
280
+
281
+ def assert_predicate o1, op, msg = nil
282
+ msg = message(msg) { "Expected #{mu_pp(o1)} to be #{op}" }
283
+ assert o1.__send__(op), msg
284
+ end
285
+
286
+ ##
287
+ # Fails unless the block raises one of +exp+. Returns the
288
+ # exception matched so you can check the message, attributes, etc.
289
+
290
+ def assert_raises *exp
291
+ msg = "#{exp.pop}.\n" if String === exp.last
292
+
293
+ begin
294
+ yield
295
+ rescue Micron::Skip => e
296
+ return e if exp.include? Micron::Skip
297
+ raise e
298
+ rescue Exception => e
299
+ expected = exp.any? { |ex|
300
+ if ex.instance_of? Module then
301
+ e.kind_of? ex
302
+ else
303
+ e.instance_of? ex
304
+ end
305
+ }
306
+
307
+ assert expected, proc {
308
+ exception_details(e, "#{msg}#{mu_pp(exp)} exception expected, not")
309
+ }
310
+
311
+ return e
312
+ end
313
+
314
+ exp = exp.first if exp.size == 1
315
+
316
+ flunk "#{msg}#{mu_pp(exp)} expected but nothing was raised."
317
+ end
318
+ alias_method :assert_throws, :assert_raises
319
+
320
+ ##
321
+ # Fails unless +obj+ responds to +meth+.
322
+
323
+ def assert_respond_to obj, meth, msg = nil
324
+ msg = message(msg) {
325
+ "Expected #{mu_pp(obj)} (#{obj.class}) to respond to ##{meth}"
326
+ }
327
+ assert obj.respond_to?(meth), msg
328
+ end
329
+
330
+ ##
331
+ # Fails unless +exp+ and +act+ are #equal?
332
+
333
+ def assert_same exp, act, msg = nil
334
+ msg = message(msg) {
335
+ data = [mu_pp(act), act.object_id, mu_pp(exp), exp.object_id]
336
+ "Expected %s (oid=%d) to be the same as %s (oid=%d)" % data
337
+ }
338
+ assert exp.equal?(act), msg
339
+ end
340
+
341
+ ##
342
+ # +send_ary+ is a receiver, message and arguments.
343
+ #
344
+ # Fails unless the call returns a true value
345
+ # TODO: I should prolly remove this from specs
346
+
347
+ def assert_send send_ary, m = nil
348
+ recv, msg, *args = send_ary
349
+ m = message(m) {
350
+ "Expected #{mu_pp(recv)}.#{msg}(*#{mu_pp(args)}) to return true" }
351
+ assert recv.__send__(msg, *args), m
352
+ end
353
+
354
+ ##
355
+ # Fails if the block outputs anything to stderr or stdout.
356
+ #
357
+ # See also: #assert_output
358
+
359
+ def assert_silent
360
+ assert_output "", "" do
361
+ yield
362
+ end
363
+ end
364
+
365
+ ##
366
+ # Fails unless the block throws +sym+
367
+
368
+ # def assert_throws sym, msg = nil
369
+ # default = "Expected #{mu_pp(sym)} to have been thrown"
370
+ # caught = true
371
+ # catch(sym) do
372
+ # begin
373
+ # yield
374
+ # rescue ThreadError => e # wtf?!? 1.8 + threads == suck
375
+ # default += ", not \:#{e.message[/uncaught throw \`(\w+?)\'/, 1]}"
376
+ # rescue ArgumentError => e # 1.9 exception
377
+ # default += ", not #{e.message.split(/ /).last}"
378
+ # rescue NameError => e # 1.8 exception
379
+ # default += ", not #{e.name.inspect}"
380
+ # end
381
+ # caught = false
382
+ # end
383
+
384
+ # assert caught, message(msg) { default }
385
+ # end
386
+
387
+ # Fails unless the block throws +clazz+ and +msg+ matches the exception message
388
+ #
389
+ # minitest assert_throws doesn't seem to work properly
390
+ # This version will catch *ALL* exceptions, including SystemExit
391
+ # def assert_throws(clazz, msg = nil, &block)
392
+ # begin
393
+ # yield
394
+
395
+ # rescue Exception => ex
396
+ # if ex.kind_of? clazz then
397
+ # if msg.nil?
398
+ # return
399
+ # elsif msg.kind_of?(Regexp) && msg.match(ex.message) then
400
+ # return
401
+ # elsif msg.kind_of?(String) && msg == ex.message then
402
+ # return
403
+ # end
404
+ # end
405
+
406
+ # puts "Caught an unexpected exception:"
407
+ # puts "Expected: <#{clazz}> #{msg.inspect}"
408
+ # puts " Caught: <#{ex.class}> #{ex.message.inspect}"
409
+ # puts " " + ex.backtrace.join("\n ")
410
+ # puts
411
+ # end
412
+
413
+ # flunk("Expected #{mu_pp(clazz)} to have been thrown")
414
+ # end
415
+
416
+ ##
417
+ # Captures $stdout and $stderr into strings:
418
+ #
419
+ # out, err = capture_io do
420
+ # puts "Some info"
421
+ # warn "You did a bad thing"
422
+ # end
423
+ #
424
+ # assert_match %r%info%, out
425
+ # assert_match %r%bad%, err
426
+ #
427
+ # NOTE: For efficiency, this method uses StringIO and does not
428
+ # capture IO for subprocesses. Use #capture_subprocess_io for
429
+ # that.
430
+
431
+ def capture_io
432
+ require 'stringio'
433
+
434
+ captured_stdout, captured_stderr = StringIO.new, StringIO.new
435
+
436
+ synchronize do
437
+ orig_stdout, orig_stderr = $stdout, $stderr
438
+ $stdout, $stderr = captured_stdout, captured_stderr
439
+
440
+ begin
441
+ yield
442
+ ensure
443
+ $stdout = orig_stdout
444
+ $stderr = orig_stderr
445
+ end
446
+ end
447
+
448
+ return captured_stdout.string, captured_stderr.string
449
+ end
450
+
451
+ ##
452
+ # Captures $stdout and $stderr into strings, using Tempfile to
453
+ # ensure that subprocess IO is captured as well.
454
+ #
455
+ # out, err = capture_subprocess_io do
456
+ # system "echo Some info"
457
+ # system "echo You did a bad thing 1>&2"
458
+ # end
459
+ #
460
+ # assert_match %r%info%, out
461
+ # assert_match %r%bad%, err
462
+ #
463
+ # NOTE: This method is approximately 10x slower than #capture_io so
464
+ # only use it when you need to test the output of a subprocess.
465
+
466
+ def capture_subprocess_io
467
+ require 'tempfile'
468
+
469
+ captured_stdout, captured_stderr = Tempfile.new("out"), Tempfile.new("err")
470
+
471
+ synchronize do
472
+ orig_stdout, orig_stderr = $stdout.dup, $stderr.dup
473
+ $stdout.reopen captured_stdout
474
+ $stderr.reopen captured_stderr
475
+
476
+ begin
477
+ yield
478
+
479
+ $stdout.rewind
480
+ $stderr.rewind
481
+
482
+ [captured_stdout.read, captured_stderr.read]
483
+ ensure
484
+ captured_stdout.unlink
485
+ captured_stderr.unlink
486
+ $stdout.reopen orig_stdout
487
+ $stderr.reopen orig_stderr
488
+ end
489
+ end
490
+ end
491
+
492
+ ##
493
+ # Returns details for exception +e+
494
+
495
+ def exception_details e, msg
496
+ [
497
+ "#{msg}",
498
+ "<#{e.class}> #{e.message.inspect}",
499
+ "#{Micron.filter_backtrace(e.backtrace).join("\n")}",
500
+ ].join "\n "
501
+ end
502
+
503
+ ##
504
+ # Fails with +msg+
505
+
506
+ def flunk msg = nil
507
+ msg ||= "Epic Fail!"
508
+ assert false, msg
509
+ end
510
+
511
+ ##
512
+ # Returns a proc that will output +msg+ along with the default message.
513
+
514
+ def message msg = nil, ending = ".", &default
515
+ proc {
516
+ msg = msg.call.chomp(".") if Proc === msg
517
+ custom_message = "#{msg}.\n" unless msg.nil? or msg.to_s.empty?
518
+ "#{custom_message}#{default.call}#{ending}"
519
+ }
520
+ end
521
+
522
+ ##
523
+ # used for counting assertions
524
+
525
+ def pass msg = nil
526
+ assert true
527
+ end
528
+
529
+ ##
530
+ # Fails if +test+ is a true value
531
+
532
+ def refute test, msg = nil
533
+ msg ||= "Failed refutation, no message given"
534
+ not assert(! test, msg)
535
+ end
536
+
537
+ ##
538
+ # Fails if +obj+ is empty.
539
+
540
+ def refute_empty obj, msg = nil
541
+ msg = message(msg) { "Expected #{mu_pp(obj)} to not be empty" }
542
+ assert_respond_to obj, :empty?
543
+ refute obj.empty?, msg
544
+ end
545
+
546
+ ##
547
+ # Fails if <tt>exp == act</tt>.
548
+ #
549
+ # For floats use refute_in_delta.
550
+
551
+ def refute_equal exp, act, msg = nil
552
+ msg = message(msg) {
553
+ "Expected #{mu_pp(act)} to not be equal to #{mu_pp(exp)}"
554
+ }
555
+ refute exp == act, msg
556
+ end
557
+
558
+ ##
559
+ # For comparing Floats. Fails if +exp+ is within +delta+ of +act+.
560
+ #
561
+ # refute_in_delta Math::PI, (22.0 / 7.0)
562
+
563
+ def refute_in_delta exp, act, delta = 0.001, msg = nil
564
+ n = (exp - act).abs
565
+ msg = message(msg) {
566
+ "Expected |#{exp} - #{act}| (#{n}) to not be <= #{delta}"
567
+ }
568
+ refute delta >= n, msg
569
+ end
570
+
571
+ ##
572
+ # For comparing Floats. Fails if +exp+ and +act+ have a relative error
573
+ # less than +epsilon+.
574
+
575
+ def refute_in_epsilon a, b, epsilon = 0.001, msg = nil
576
+ refute_in_delta a, b, a * epsilon, msg
577
+ end
578
+
579
+ ##
580
+ # Fails if +collection+ includes +obj+.
581
+
582
+ def refute_includes collection, obj, msg = nil
583
+ msg = message(msg) {
584
+ "Expected #{mu_pp(collection)} to not include #{mu_pp(obj)}"
585
+ }
586
+ assert_respond_to collection, :include?
587
+ refute collection.include?(obj), msg
588
+ end
589
+
590
+ ##
591
+ # Fails if +obj+ is an instance of +cls+.
592
+
593
+ def refute_instance_of cls, obj, msg = nil
594
+ msg = message(msg) {
595
+ "Expected #{mu_pp(obj)} to not be an instance of #{cls}"
596
+ }
597
+ refute obj.instance_of?(cls), msg
598
+ end
599
+
600
+ ##
601
+ # Fails if +obj+ is a kind of +cls+.
602
+
603
+ def refute_kind_of cls, obj, msg = nil # TODO: merge with instance_of
604
+ msg = message(msg) { "Expected #{mu_pp(obj)} to not be a kind of #{cls}" }
605
+ refute obj.kind_of?(cls), msg
606
+ end
607
+
608
+ ##
609
+ # Fails if +matcher+ <tt>=~</tt> +obj+.
610
+
611
+ def refute_match matcher, obj, msg = nil
612
+ msg = message(msg) {"Expected #{mu_pp matcher} to not match #{mu_pp obj}"}
613
+ assert_respond_to matcher, :"=~"
614
+ matcher = Regexp.new Regexp.escape matcher if String === matcher
615
+ refute matcher =~ obj, msg
616
+ end
617
+
618
+ ##
619
+ # Fails if +obj+ is nil.
620
+
621
+ def refute_nil obj, msg = nil
622
+ msg = message(msg) { "Expected #{mu_pp(obj)} to not be nil" }
623
+ refute obj.nil?, msg
624
+ end
625
+
626
+ ##
627
+ # Fails if +o1+ is not +op+ +o2+. Eg:
628
+ #
629
+ # refute_operator 1, :>, 2 #=> pass
630
+ # refute_operator 1, :<, 2 #=> fail
631
+
632
+ def refute_operator o1, op, o2 = UNDEFINED, msg = nil
633
+ return refute_predicate o1, op, msg if UNDEFINED == o2
634
+ msg = message(msg) { "Expected #{mu_pp(o1)} to not be #{op} #{mu_pp(o2)}"}
635
+ refute o1.__send__(op, o2), msg
636
+ end
637
+
638
+ ##
639
+ # For testing with predicates.
640
+ #
641
+ # refute_predicate str, :empty?
642
+ #
643
+ # This is really meant for specs and is front-ended by refute_operator:
644
+ #
645
+ # str.wont_be :empty?
646
+
647
+ def refute_predicate o1, op, msg = nil
648
+ msg = message(msg) { "Expected #{mu_pp(o1)} to not be #{op}" }
649
+ refute o1.__send__(op), msg
650
+ end
651
+
652
+ ##
653
+ # Fails if +obj+ responds to the message +meth+.
654
+
655
+ def refute_respond_to obj, meth, msg = nil
656
+ msg = message(msg) { "Expected #{mu_pp(obj)} to not respond to #{meth}" }
657
+
658
+ refute obj.respond_to?(meth), msg
659
+ end
660
+
661
+ ##
662
+ # Fails if +exp+ is the same (by object identity) as +act+.
663
+
664
+ def refute_same exp, act, msg = nil
665
+ msg = message(msg) {
666
+ data = [mu_pp(act), act.object_id, mu_pp(exp), exp.object_id]
667
+ "Expected %s (oid=%d) to not be the same as %s (oid=%d)" % data
668
+ }
669
+ refute exp.equal?(act), msg
670
+ end
671
+
672
+ ##
673
+ # Skips the current test. Gets listed at the end of the run but
674
+ # doesn't cause a failure exit code.
675
+
676
+ def skip msg = nil, bt = caller
677
+ msg ||= "Skipped, no message given"
678
+ @skip = true
679
+ raise Micron::Skip, msg, bt
680
+ end
681
+
682
+ ##
683
+ # Was this testcase skipped? Meant for #teardown.
684
+
685
+ def skipped?
686
+ defined?(@skip) and @skip
687
+ end
688
+
689
+ ##
690
+ # Takes a block and wraps it with the runner's shared mutex.
691
+
692
+ def synchronize
693
+ Micron.runner.synchronize do
694
+ yield
695
+ end
696
+ end
697
+
698
+ end # Assertions
699
+
700
+ end # TestCase
701
+ end # Micron