source: extensions/gsdl-video/trunk/installed/cmdline/lib/ruby/1.8/test/unit/assertions.rb@ 18425

Last change on this file since 18425 was 18425, checked in by davidb, 15 years ago

Video extension to Greenstone

File size: 17.8 KB
Line 
1# Author:: Nathaniel Talbott.
2# Copyright:: Copyright (c) 2000-2003 Nathaniel Talbott. All rights reserved.
3# License:: Ruby license.
4
5require 'test/unit/assertionfailederror'
6require 'test/unit/util/backtracefilter'
7
8module Test
9 module Unit
10
11 ##
12 # Test::Unit::Assertions contains the standard Test::Unit assertions.
13 # Assertions is included in Test::Unit::TestCase.
14 #
15 # To include it in your own code and use its functionality, you simply
16 # need to rescue Test::Unit::AssertionFailedError. Additionally you may
17 # override add_assertion to get notified whenever an assertion is made.
18 #
19 # Notes:
20 # * The message to each assertion, if given, will be propagated with the
21 # failure.
22 # * It is easy to add your own assertions based on assert_block().
23 #
24 # = Example Custom Assertion
25 #
26 # def deny(boolean, message = nil)
27 # message = build_message message, '<?> is not false or nil.', boolean
28 # assert_block message do
29 # not boolean
30 # end
31 # end
32
33 module Assertions
34
35 ##
36 # The assertion upon which all other assertions are based. Passes if the
37 # block yields true.
38 #
39 # Example:
40 # assert_block "Couldn't do the thing" do
41 # do_the_thing
42 # end
43
44 public
45 def assert_block(message="assert_block failed.") # :yields:
46 _wrap_assertion do
47 if (! yield)
48 raise AssertionFailedError.new(message.to_s)
49 end
50 end
51 end
52
53 ##
54 # Asserts that +boolean+ is not false or nil.
55 #
56 # Example:
57 # assert [1, 2].include?(5)
58
59 public
60 def assert(boolean, message=nil)
61 _wrap_assertion do
62 assert_block("assert should not be called with a block.") { !block_given? }
63 assert_block(build_message(message, "<?> is not true.", boolean)) { boolean }
64 end
65 end
66
67 ##
68 # Passes if +expected+ == +actual.
69 #
70 # Note that the ordering of arguments is important, since a helpful
71 # error message is generated when this one fails that tells you the
72 # values of expected and actual.
73 #
74 # Example:
75 # assert_equal 'MY STRING', 'my string'.upcase
76
77 public
78 def assert_equal(expected, actual, message=nil)
79 full_message = build_message(message, <<EOT, expected, actual)
80<?> expected but was
81<?>.
82EOT
83 assert_block(full_message) { expected == actual }
84 end
85
86 private
87 def _check_exception_class(args) # :nodoc:
88 args.partition do |klass|
89 next if klass.instance_of?(Module)
90 assert(Exception >= klass, "Should expect a class of exception, #{klass}")
91 true
92 end
93 end
94
95 private
96 def _expected_exception?(actual_exception, exceptions, modules) # :nodoc:
97 exceptions.include?(actual_exception.class) or
98 modules.any? {|mod| actual_exception.is_a?(mod)}
99 end
100
101 ##
102 # Passes if the block raises one of the given exceptions.
103 #
104 # Example:
105 # assert_raise RuntimeError, LoadError do
106 # raise 'Boom!!!'
107 # end
108
109 public
110 def assert_raise(*args)
111 _wrap_assertion do
112 if Module === args.last
113 message = ""
114 else
115 message = args.pop
116 end
117 exceptions, modules = _check_exception_class(args)
118 expected = args.size == 1 ? args.first : args
119 actual_exception = nil
120 full_message = build_message(message, "<?> exception expected but none was thrown.", expected)
121 assert_block(full_message) do
122 begin
123 yield
124 rescue Exception => actual_exception
125 break
126 end
127 false
128 end
129 full_message = build_message(message, "<?> exception expected but was\n?", expected, actual_exception)
130 assert_block(full_message) {_expected_exception?(actual_exception, exceptions, modules)}
131 actual_exception
132 end
133 end
134
135 ##
136 # Alias of assert_raise.
137 #
138 # Will be deprecated in 1.9, and removed in 2.0.
139
140 public
141 def assert_raises(*args, &block)
142 assert_raise(*args, &block)
143 end
144
145 ##
146 # Passes if +object+ .instance_of? +klass+
147 #
148 # Example:
149 # assert_instance_of String, 'foo'
150
151 public
152 def assert_instance_of(klass, object, message="")
153 _wrap_assertion do
154 assert_equal(Class, klass.class, "assert_instance_of takes a Class as its first argument")
155 full_message = build_message(message, <<EOT, object, klass, object.class)
156<?> expected to be an instance of
157<?> but was
158<?>.
159EOT
160 assert_block(full_message){object.instance_of?(klass)}
161 end
162 end
163
164 ##
165 # Passes if +object+ is nil.
166 #
167 # Example:
168 # assert_nil [1, 2].uniq!
169
170 public
171 def assert_nil(object, message="")
172 assert_equal(nil, object, message)
173 end
174
175 ##
176 # Passes if +object+ .kind_of? +klass+
177 #
178 # Example:
179 # assert_kind_of Object, 'foo'
180
181 public
182 def assert_kind_of(klass, object, message="")
183 _wrap_assertion do
184 assert(klass.kind_of?(Module), "The first parameter to assert_kind_of should be a kind_of Module.")
185 full_message = build_message(message, "<?>\nexpected to be kind_of\\?\n<?> but was\n<?>.", object, klass, object.class)
186 assert_block(full_message){object.kind_of?(klass)}
187 end
188 end
189
190 ##
191 # Passes if +object+ .respond_to? +method+
192 #
193 # Example:
194 # assert_respond_to 'bugbear', :slice
195
196 public
197 def assert_respond_to(object, method, message="")
198 _wrap_assertion do
199 full_message = build_message(nil, "<?>\ngiven as the method name argument to #assert_respond_to must be a Symbol or #respond_to\\?(:to_str).", method)
200
201 assert_block(full_message) do
202 method.kind_of?(Symbol) || method.respond_to?(:to_str)
203 end
204 full_message = build_message(message, <<EOT, object, object.class, method)
205<?>
206of type <?>
207expected to respond_to\\?<?>.
208EOT
209 assert_block(full_message) { object.respond_to?(method) }
210 end
211 end
212
213 ##
214 # Passes if +string+ =~ +pattern+.
215 #
216 # Example:
217 # assert_match(/\d+/, 'five, 6, seven')
218
219 public
220 def assert_match(pattern, string, message="")
221 _wrap_assertion do
222 pattern = case(pattern)
223 when String
224 Regexp.new(Regexp.escape(pattern))
225 else
226 pattern
227 end
228 full_message = build_message(message, "<?> expected to be =~\n<?>.", string, pattern)
229 assert_block(full_message) { string =~ pattern }
230 end
231 end
232
233 ##
234 # Passes if +actual+ .equal? +expected+ (i.e. they are the same
235 # instance).
236 #
237 # Example:
238 # o = Object.new
239 # assert_same o, o
240
241 public
242 def assert_same(expected, actual, message="")
243 full_message = build_message(message, <<EOT, expected, expected.__id__, actual, actual.__id__)
244<?>
245with id <?> expected to be equal\\? to
246<?>
247with id <?>.
248EOT
249 assert_block(full_message) { actual.equal?(expected) }
250 end
251
252 ##
253 # Compares the +object1+ with +object2+ using +operator+.
254 #
255 # Passes if object1.__send__(operator, object2) is true.
256 #
257 # Example:
258 # assert_operator 5, :>=, 4
259
260 public
261 def assert_operator(object1, operator, object2, message="")
262 _wrap_assertion do
263 full_message = build_message(nil, "<?>\ngiven as the operator for #assert_operator must be a Symbol or #respond_to\\?(:to_str).", operator)
264 assert_block(full_message){operator.kind_of?(Symbol) || operator.respond_to?(:to_str)}
265 full_message = build_message(message, <<EOT, object1, AssertionMessage.literal(operator), object2)
266<?> expected to be
267?
268<?>.
269EOT
270 assert_block(full_message) { object1.__send__(operator, object2) }
271 end
272 end
273
274 ##
275 # Passes if block does not raise an exception.
276 #
277 # Example:
278 # assert_nothing_raised do
279 # [1, 2].uniq
280 # end
281
282 public
283 def assert_nothing_raised(*args)
284 _wrap_assertion do
285 if Module === args.last
286 message = ""
287 else
288 message = args.pop
289 end
290 exceptions, modules = _check_exception_class(args)
291 begin
292 yield
293 rescue Exception => e
294 if ((args.empty? && !e.instance_of?(AssertionFailedError)) ||
295 _expected_exception?(e, exceptions, modules))
296 assert_block(build_message(message, "Exception raised:\n?", e)){false}
297 else
298 raise
299 end
300 end
301 nil
302 end
303 end
304
305 ##
306 # Flunk always fails.
307 #
308 # Example:
309 # flunk 'Not done testing yet.'
310
311 public
312 def flunk(message="Flunked")
313 assert_block(build_message(message)){false}
314 end
315
316 ##
317 # Passes if ! +actual+ .equal? +expected+
318 #
319 # Example:
320 # assert_not_same Object.new, Object.new
321
322 public
323 def assert_not_same(expected, actual, message="")
324 full_message = build_message(message, <<EOT, expected, expected.__id__, actual, actual.__id__)
325<?>
326with id <?> expected to not be equal\\? to
327<?>
328with id <?>.
329EOT
330 assert_block(full_message) { !actual.equal?(expected) }
331 end
332
333 ##
334 # Passes if +expected+ != +actual+
335 #
336 # Example:
337 # assert_not_equal 'some string', 5
338
339 public
340 def assert_not_equal(expected, actual, message="")
341 full_message = build_message(message, "<?> expected to be != to\n<?>.", expected, actual)
342 assert_block(full_message) { expected != actual }
343 end
344
345 ##
346 # Passes if ! +object+ .nil?
347 #
348 # Example:
349 # assert_not_nil '1 two 3'.sub!(/two/, '2')
350
351 public
352 def assert_not_nil(object, message="")
353 full_message = build_message(message, "<?> expected to not be nil.", object)
354 assert_block(full_message){!object.nil?}
355 end
356
357 ##
358 # Passes if +regexp+ !~ +string+
359 #
360 # Example:
361 # assert_no_match(/two/, 'one 2 three')
362
363 public
364 def assert_no_match(regexp, string, message="")
365 _wrap_assertion do
366 assert_instance_of(Regexp, regexp, "The first argument to assert_no_match should be a Regexp.")
367 full_message = build_message(message, "<?> expected to not match\n<?>.", regexp, string)
368 assert_block(full_message) { regexp !~ string }
369 end
370 end
371
372 UncaughtThrow = {NameError => /^uncaught throw \`(.+)\'$/,
373 ThreadError => /^uncaught throw \`(.+)\' in thread /} #`
374
375 ##
376 # Passes if the block throws +expected_symbol+
377 #
378 # Example:
379 # assert_throws :done do
380 # throw :done
381 # end
382
383 public
384 def assert_throws(expected_symbol, message="", &proc)
385 _wrap_assertion do
386 assert_instance_of(Symbol, expected_symbol, "assert_throws expects the symbol that should be thrown for its first argument")
387 assert_block("Should have passed a block to assert_throws."){block_given?}
388 caught = true
389 begin
390 catch(expected_symbol) do
391 proc.call
392 caught = false
393 end
394 full_message = build_message(message, "<?> should have been thrown.", expected_symbol)
395 assert_block(full_message){caught}
396 rescue NameError, ThreadError => error
397 if UncaughtThrow[error.class] !~ error.message
398 raise error
399 end
400 full_message = build_message(message, "<?> expected to be thrown but\n<?> was thrown.", expected_symbol, $1.intern)
401 flunk(full_message)
402 end
403 end
404 end
405
406 ##
407 # Passes if block does not throw anything.
408 #
409 # Example:
410 # assert_nothing_thrown do
411 # [1, 2].uniq
412 # end
413
414 public
415 def assert_nothing_thrown(message="", &proc)
416 _wrap_assertion do
417 assert(block_given?, "Should have passed a block to assert_nothing_thrown")
418 begin
419 proc.call
420 rescue NameError, ThreadError => error
421 if UncaughtThrow[error.class] !~ error.message
422 raise error
423 end
424 full_message = build_message(message, "<?> was thrown when nothing was expected", $1.intern)
425 flunk(full_message)
426 end
427 assert(true, "Expected nothing to be thrown")
428 end
429 end
430
431 ##
432 # Passes if +expected_float+ and +actual_float+ are equal
433 # within +delta+ tolerance.
434 #
435 # Example:
436 # assert_in_delta 0.05, (50000.0 / 10**6), 0.00001
437
438 public
439 def assert_in_delta(expected_float, actual_float, delta, message="")
440 _wrap_assertion do
441 {expected_float => "first float", actual_float => "second float", delta => "delta"}.each do |float, name|
442 assert_respond_to(float, :to_f, "The arguments must respond to to_f; the #{name} did not")
443 end
444 assert_operator(delta, :>=, 0.0, "The delta should not be negative")
445 full_message = build_message(message, <<EOT, expected_float, actual_float, delta)
446<?> and
447<?> expected to be within
448<?> of each other.
449EOT
450 assert_block(full_message) { (expected_float.to_f - actual_float.to_f).abs <= delta.to_f }
451 end
452 end
453
454 ##
455 # Passes if the method send returns a true value.
456 #
457 # +send_array+ is composed of:
458 # * A receiver
459 # * A method
460 # * Arguments to the method
461 #
462 # Example:
463 # assert_send [[1, 2], :include?, 4]
464
465 public
466 def assert_send(send_array, message="")
467 _wrap_assertion do
468 assert_instance_of(Array, send_array, "assert_send requires an array of send information")
469 assert(send_array.size >= 2, "assert_send requires at least a receiver and a message name")
470 full_message = build_message(message, <<EOT, send_array[0], AssertionMessage.literal(send_array[1].to_s), send_array[2..-1])
471<?> expected to respond to
472<?(?)> with a true value.
473EOT
474 assert_block(full_message) { send_array[0].__send__(send_array[1], *send_array[2..-1]) }
475 end
476 end
477
478 ##
479 # Builds a failure message. +head+ is added before the +template+ and
480 # +arguments+ replaces the '?'s positionally in the template.
481
482 public
483 def build_message(head, template=nil, *arguments)
484 template &&= template.chomp
485 return AssertionMessage.new(head, template, arguments)
486 end
487
488 private
489 def _wrap_assertion
490 @_assertion_wrapped ||= false
491 unless (@_assertion_wrapped)
492 @_assertion_wrapped = true
493 begin
494 add_assertion
495 return yield
496 ensure
497 @_assertion_wrapped = false
498 end
499 else
500 return yield
501 end
502 end
503
504 ##
505 # Called whenever an assertion is made. Define this in classes that
506 # include Test::Unit::Assertions to record assertion counts.
507
508 private
509 def add_assertion
510 end
511
512 ##
513 # Select whether or not to use the pretty-printer. If this option is set
514 # to false before any assertions are made, pp.rb will not be required.
515
516 public
517 def self.use_pp=(value)
518 AssertionMessage.use_pp = value
519 end
520
521 # :stopdoc:
522
523 class AssertionMessage
524 @use_pp = true
525 class << self
526 attr_accessor :use_pp
527 end
528
529 class Literal
530 def initialize(value)
531 @value = value
532 end
533
534 def inspect
535 @value.to_s
536 end
537 end
538
539 class Template
540 def self.create(string)
541 parts = (string ? string.scan(/(?=[^\\])\?|(?:\\\?|[^\?])+/m) : [])
542 self.new(parts)
543 end
544
545 attr_reader :count
546
547 def initialize(parts)
548 @parts = parts
549 @count = parts.find_all{|e| e == '?'}.size
550 end
551
552 def result(parameters)
553 raise "The number of parameters does not match the number of substitutions." if(parameters.size != count)
554 params = parameters.dup
555 @parts.collect{|e| e == '?' ? params.shift : e.gsub(/\\\?/m, '?')}.join('')
556 end
557 end
558
559 def self.literal(value)
560 Literal.new(value)
561 end
562
563 include Util::BacktraceFilter
564
565 def initialize(head, template_string, parameters)
566 @head = head
567 @template_string = template_string
568 @parameters = parameters
569 end
570
571 def convert(object)
572 case object
573 when Exception
574 <<EOM.chop
575Class: <#{convert(object.class)}>
576Message: <#{convert(object.message)}>
577---Backtrace---
578#{filter_backtrace(object.backtrace).join("\n")}
579---------------
580EOM
581 else
582 if(self.class.use_pp)
583 begin
584 require 'pp'
585 rescue LoadError
586 self.class.use_pp = false
587 return object.inspect
588 end unless(defined?(PP))
589 PP.pp(object, '').chomp
590 else
591 object.inspect
592 end
593 end
594 end
595
596 def template
597 @template ||= Template.create(@template_string)
598 end
599
600 def add_period(string)
601 (string =~ /\.\Z/ ? string : string + '.')
602 end
603
604 def to_s
605 message_parts = []
606 if (@head)
607 head = @head.to_s
608 unless(head.empty?)
609 message_parts << add_period(head)
610 end
611 end
612 tail = template.result(@parameters.collect{|e| convert(e)})
613 message_parts << tail unless(tail.empty?)
614 message_parts.join("\n")
615 end
616 end
617
618 # :startdoc:
619
620 end
621 end
622end
Note: See TracBrowser for help on using the repository browser.