Class: Arrow::TestCase

Inherits:
Test::Unit::TestCase
  • Object
show all
Defined in:
lib/arrow/testcase.rb

Overview

Test case class

Constant Summary

AnsiAttributes =

Set some ANSI escape code constants (Shamelessly stolen from Perl’s Term::ANSIColor by Russ Allbery and Zenin

{
  'clear'      => 0,
  'reset'      => 0,
  'bold'       => 1,
  'dark'       => 2,
  'underline'  => 4,
  'underscore' => 4,
  'blink'      => 5,
  'reverse'    => 7,
  'concealed'  => 8,

  'black'      => 30,   'on_black'   => 40, 
  'red'        => 31,   'on_red'     => 41, 
  'green'      => 32,   'on_green'   => 42, 
  'yellow'     => 33,   'on_yellow'  => 43, 
  'blue'       => 34,   'on_blue'    => 44, 
  'magenta'    => 35,   'on_magenta' => 45, 
  'cyan'       => 36,   'on_cyan'    => 46, 
  'white'      => 37,   'on_white'   => 47
}
ConfigSaveFile =

The name of the file containing marshalled configuration values

"test.cfg"
@@methodCounter =
0

Class Method Summary

Instance Method Summary

Class Method Details

+ (Object) addSetupBlock(&block)

Append a setup block for the current testcase



153
154
155
156
157
158
# File 'lib/arrow/testcase.rb', line 153

def self::addSetupBlock( &block )
  @@methodCounter += 1
  newMethodName = "setup_#{@@methodCounter}".to_sym
  define_method( newMethodName, &block )
  self.setupMethods.push newMethodName
end

+ (Object) addTeardownBlock(&block)

Prepend a teardown block for the current testcase



162
163
164
165
166
167
# File 'lib/arrow/testcase.rb', line 162

def self::addTeardownBlock( &block )
  @@methodCounter += 1
  newMethodName = "teardown_#{@@methodCounter}".to_sym
  define_method( newMethodName, &block )
  self.teardownMethods.unshift newMethodName
end

+ (Object) ansiCode(*attributes)

Returns a String containing the specified ANSI escapes suitable for inclusion in another string. The attributes should be one or more of the keys of AnsiAttributes.



122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/arrow/testcase.rb', line 122

def self::ansiCode( *attributes )
  return '' unless /(?:xterm(?:-color)?|eterm|linux)/i =~ ENV['TERM']

  attr = attributes.collect {|a|
    AnsiAttributes[a] ? AnsiAttributes[a] : nil
  }.compact.join(';')
  if attr.empty? 
    return ''
  else
    return "\e[%sm" % attr
  end
end

+ (Object) debugMsg(*msgs)

Output the specified msgs joined together to STDERR if $DEBUG is set.



138
139
140
141
142
# File 'lib/arrow/testcase.rb', line 138

def self::debugMsg( *msgs )
  return unless $DEBUG
  self.message "%sDEBUG>>> %s %s" %
    [ ansiCode('dark', 'white'), msgs.join(''), ansiCode('reset') ]
end

+ (Object) inherited(klass)

Inheritance callback — adds @setupMethods and @teardownMethods ivars and accessors to the inheriting class.



106
107
108
109
110
111
112
113
114
115
116
# File 'lib/arrow/testcase.rb', line 106

def self::inherited( klass )
  klass.module_eval {
    @setupMethods = []
    @teardownMethods = []

    class << self
      attr_accessor :setupMethods
      attr_accessor :teardownMethods
    end
  }
end

+ (Object) message(*msgs)

Output the specified msgs joined together to STDOUT.



147
148
149
150
# File 'lib/arrow/testcase.rb', line 147

def self::message( *msgs )
  $stderr.puts msgs.join('')
  $stderr.flush
end

Instance Method Details

- (Object) addSetupBlock(&block)

Add the specified block to the code that gets executed by #setup.



219
# File 'lib/arrow/testcase.rb', line 219

def addSetupBlock( &block ) self.class.addSetupBlock( &block ) end

- (Object) addTeardownBlock(&block)

Add the specified block to the code that gets executed by #teardown.



223
# File 'lib/arrow/testcase.rb', line 223

def addTeardownBlock( &block ) self.class.addTeardownBlock( &block ) end

- (Object) ansiCode(*attributes)

Instance-alias for the like-named class method



461
462
463
# File 'lib/arrow/testcase.rb', line 461

def ansiCode( *attributes )
  self.class.ansiCode( *attributes )
end

- (Object) assert_has_instance_method(klass, meth)

Assert that the specified klass defines the specified instance method meth.



434
435
436
437
438
439
440
441
442
443
444
445
446
# File 'lib/arrow/testcase.rb', line 434

def assert_has_instance_method( klass, meth )
  msg = "<%s> expected to define instance method #%s" %
    [ klass, meth ]
  assert_block( msg ) {
    klass.instance_methods.include?( meth.to_s )
  }
rescue Test::Unit::AssertionFailedError => err
  cutframe = err.backtrace.reverse.find {|frame|
    /assert_has_instance_method/ =~ frame
  }
  firstIdx = (err.backtrace.rindex( cutframe )||0) + 1
  Kernel.raise( err, err.message, err.backtrace[firstIdx..-1] )
end

- (Object) assert_has_ivar(sym, object)

Assert that the specified object has an instance variable which matches the specified sym. The ’@’ at the beginning of the sym will be prepended if not present.



399
400
401
402
403
404
405
406
407
408
409
410
411
412
# File 'lib/arrow/testcase.rb', line 399

def assert_has_ivar( sym, object )
  sym = "@#{sym}" unless /^@/ =~ sym.to_s
  msg = "Object <%s> expected to have an instance variable <%s>" %
    [ object.inspect, sym ]
  assert_block( msg ) {
    object.instance_variables.include?( sym.to_s )
  }
rescue Test::Unit::AssertionFailedError => err
  cutframe = err.backtrace.reverse.find {|frame|
    /assert_has_ivar/ =~ frame
  }
  firstIdx = (err.backtrace.rindex( cutframe )||0) + 1
  Kernel.raise( err, err.message, err.backtrace[firstIdx..-1] )
end

- (Object) assert_hash_equal(expected, actual, msg = "")

Test Hashes for equivalent content



234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
# File 'lib/arrow/testcase.rb', line 234

def assert_hash_equal( expected, actual, msg="" )
  errmsg = "Expected hash <%p> to be equal to <%p>" % [expected, actual]
  errmsg += ": #{msg}" unless msg.empty?

  assert_block( errmsg ) {
    diffs = compare_hashes( expected, actual )
    unless diffs.empty?
      errmsg += ": " + diffs.join("; ")
      return false
    else
      return true
    end
  }
rescue Test::Unit::AssertionFailedError => err
  cutframe = err.backtrace.reverse.find {|frame|
    /assert_hash_equal/ =~ frame
  }
  firstIdx = (err.backtrace.rindex( cutframe )||0) + 1
  Kernel.raise( err, err.message, err.backtrace[firstIdx..-1] )
end

- (Object) assert_include(item, obj, msg = nil)

Succeeds if obj include? item.



333
334
335
336
337
338
339
340
341
342
# File 'lib/arrow/testcase.rb', line 333

def assert_include( item, obj, msg=nil )
  msg ||= "<%p> expected to include <%p>." % [ obj, item ]
  assert_block( msg ) { obj.respond_to?(:include?) && obj.include?(item) }
rescue Test::Unit::AssertionFailedError => err
  cutframe = err.backtrace.reverse.find {|frame|
    /assert_include/ =~ frame
  }
  firstIdx = (err.backtrace.rindex( cutframe )||0) + 1
  Kernel.raise( err, err.message, err.backtrace[firstIdx..-1] )
end

- (Object) assert_ivar_equal(value, object, sym)

Assert that the instance variable specified by sym of an object is equal to the specified value. The ’@’ at the beginning of the sym will be prepended if not present.



379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
# File 'lib/arrow/testcase.rb', line 379

def assert_ivar_equal( value, object, sym )
  sym = "@#{sym}".to_sym unless /^@/ =~ sym.to_s
  msg = "Instance variable '%s'\n\tof <%s>\n\texpected to be <%s>\n" %
    [ sym, object.inspect, value.inspect ]
  msg += "\tbut was: <%p>" % [ object.instance_variable_get(sym) ]
  assert_block( msg ) {
    value == object.instance_variable_get(sym)
  }
rescue Test::Unit::AssertionFailedError => err
  cutframe = err.backtrace.reverse.find {|frame|
    /assert_ivar_equal/ =~ frame
  }
  firstIdx = (err.backtrace.rindex( cutframe )||0) + 1
  Kernel.raise( err, err.message, err.backtrace[firstIdx..-1] )
end

- (Object) assert_not_match(re, str)

Assert that the specified str does not match the given regular expression re.



417
418
419
420
421
422
423
424
425
426
427
428
429
# File 'lib/arrow/testcase.rb', line 417

def assert_not_match( re, str )
  msg = "<%s> expected not to match %p" %
    [ str, re ]
  assert_block( msg ) {
    !re.match( str )
  }
rescue Test::Unit::AssertionFailedError => err
  cutframe = err.backtrace.reverse.find {|frame|
    /assert_not_match/ =~ frame
  }
  firstIdx = (err.backtrace.rindex( cutframe )||0) + 1
  Kernel.raise( err, err.message, err.backtrace[firstIdx..-1] )
end

- (Object) assert_not_nil(obj, msg = nil)

Override the stupid deprecated #assert_not_nil so when it disappears, code doesn’t break.



320
321
322
323
324
325
326
327
328
329
# File 'lib/arrow/testcase.rb', line 320

def assert_not_nil( obj, msg=nil )
  msg ||= "<%p> expected to not be nil." % obj
  assert_block( msg ) { !obj.nil? }
rescue Test::Unit::AssertionFailedError => err
  cutframe = err.backtrace.reverse.find {|frame|
    /assert_not_nil/ =~ frame
  }
  firstIdx = (err.backtrace.rindex( cutframe )||0) + 1
  Kernel.raise( err, err.message, err.backtrace[firstIdx..-1] )
end

- (Object) assert_not_respond_to(obj, meth)

Negative of assert_respond_to



361
362
363
364
365
366
367
368
369
370
371
372
373
# File 'lib/arrow/testcase.rb', line 361

def assert_not_respond_to( obj, meth )
  msg = "%s expected NOT to respond to '%s'" %
    [ obj.inspect, meth ]
  assert_block( msg ) {
    !obj.respond_to?( meth )
  }
rescue Test::Unit::AssertionFailedError => err
  cutframe = err.backtrace.reverse.find {|frame|
    /assert_not_respond_to/ =~ frame
  }
  firstIdx = (err.backtrace.rindex( cutframe )||0) + 1
  Kernel.raise( err, err.message, err.backtrace[firstIdx..-1] )
end

- (Object) assert_not_tainted(obj, msg = nil)

Negative of assert_respond_to



346
347
348
349
350
351
352
353
354
355
356
357
# File 'lib/arrow/testcase.rb', line 346

def assert_not_tainted( obj, msg=nil )
  msg ||= "<%p> expected to NOT be tainted" % [ obj ]
  assert_block( msg ) {
    !obj.tainted?
  }
rescue Test::Unit::AssertionFailedError => err
  cutframe = err.backtrace.reverse.find {|frame|
    /assert_not_tainted/ =~ frame
  }
  firstIdx = (err.backtrace.rindex( cutframe )||0) + 1
  Kernel.raise( err, err.message, err.backtrace[firstIdx..-1] )
end

- (Object) assert_same_keys(expected, actual, msg = "")

Test Hashes (or any other objects with a #keys method) for key set equality



284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
# File 'lib/arrow/testcase.rb', line 284

def assert_same_keys( expected, actual, msg="" )
  errmsg = "Expected keys of <%p> to be equal to those of <%p>" %
    [ actual, expected ]
  errmsg += ": #{msg}" unless msg.empty?

  ekeys = expected.keys; akeys = actual.keys
  assert_block( errmsg ) {
    diffs = []

    # XOR the arrays and make a diff for each one
    ((ekeys + akeys) - (ekeys & akeys)).each do |key|
      if ekeys.include?( key )
        diffs << "missing key %p" % [key]
      else
        diffs << "extra key %p" % [key]
      end
    end

    unless diffs.empty?
      errmsg += "\n" + diffs.join("; ")
      return false
    else
      return true
    end
  }
rescue Test::Unit::AssertionFailedError => err
  cutframe = err.backtrace.reverse.find {|frame|
    /assert_hash_equal/ =~ frame
  }
  firstIdx = (err.backtrace.rindex( cutframe )||0) + 1
  Kernel.raise( err, err.message, err.backtrace[firstIdx..-1] )
end

- (Object) collectGarbage

Try to force garbage collection to start.



502
503
504
505
506
507
# File 'lib/arrow/testcase.rb', line 502

def collectGarbage
  a = []
  1000.times { a << {} }
  a = nil
  GC.start
end

- (Object) compare_hashes(hash1, hash2, subkeys = nil)

Compare two hashes for content, returning a list of their differences as descriptions. An empty Array return-value means they were the same.



258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
# File 'lib/arrow/testcase.rb', line 258

def compare_hashes( hash1, hash2, subkeys=nil )
  diffs = []
  seenKeys = []

  hash1.each {|k,v|
    if !hash2.key?( k )
      diffs << "missing %p pair" % k
    elsif hash1[k].is_a?( Hash ) && hash2[k].is_a?( Hash )
      diffs.push( compare_hashes(hash1[k], hash2[k]) )
    elsif hash2[k] != hash1[k]
      diffs << "value for %p expected to be %p, but was %p" %
        [ k, hash1[k], hash2[k] ]
    else
      seenKeys << k
    end
  }

  extraKeys = (hash2.keys - hash1.keys)
  diffs << "extra key/s: #{extraKeys.join(', ')}" unless extraKeys.empty?

  return diffs.flatten
end

- (Object) debugMsg(*msgs)

Instance alias for the like-named class method



467
468
469
# File 'lib/arrow/testcase.rb', line 467

def debugMsg( *msgs )
  self.class.debugMsg( *msgs )
end

- (Object) default_test

Turn off the stupid ‘No tests were specified’



227
# File 'lib/arrow/testcase.rb', line 227

def default_test; end

- (Object) hrule(length = 75, char = "-")

Return a separator line made up of length of the specified char.



474
475
476
# File 'lib/arrow/testcase.rb', line 474

def hrule( length=75, char="-" )
  return (char * length ) + "\n"
end

- (Object) hruleSection(content, caption = '')

Return a section delimited by hrules with the specified caption and content.



480
481
482
483
484
485
486
# File 'lib/arrow/testcase.rb', line 480

def hruleSection( content, caption='' )
  caption << ' ' unless caption.empty?
  return caption +
    hrule( 75 - caption.length ) +
    content.chomp + "\n" +
    hrule()
end

- (Object) message(*msgs)

Instance alias for the like-named class method.



455
456
457
# File 'lib/arrow/testcase.rb', line 455

def message( *msgs )
  self.class.message( *msgs )
end

- (Object) printTestHeader(desc)

Output a header for delimiting tests



490
491
492
493
494
# File 'lib/arrow/testcase.rb', line 490

def printTestHeader( desc )
  return unless $VERBOSE || $DEBUG
  message "%s>>> %s <<<%s" % 
    [ ansiCode('bold','yellow','on_blue'), desc, ansiCode('reset') ]
end

- (Object) prompt(promptString)

Output the specified promptString as a prompt (in green) and return the user’s input with leading and trailing spaces removed.



547
548
549
550
551
# File 'lib/arrow/testcase.rb', line 547

def prompt( promptString )
  promptString.chomp!
  return readline( ansiCode('bold', 'green') + "#{promptString}: " +
           ansiCode('reset') ).strip
end

- (Object) promptWithDefault(promptString, default)

Prompt the user with the given promptString via #prompt, substituting the given default if the user doesn’t input anything.



557
558
559
560
561
562
563
564
# File 'lib/arrow/testcase.rb', line 557

def promptWithDefault( promptString, default )
  response = prompt( "%s [%s]" % [ promptString, default ] )
  if response.empty?
    return default
  else
    return response
  end
end

- (Object) run(result)

Output the name of the test as it’s running if in verbose mode.



518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
# File 'lib/arrow/testcase.rb', line 518

def run( result )
  $stderr.puts self.name if $VERBOSE || $DEBUG

  # Support debugging for individual tests
  olddb = nil
  if $DebugPattern && $DebugPattern =~ @method_name
    Arrow::Logger.global.outputters <<
      Arrow::Logger::Outputter.create( 'file:stderr' )
    Arrow::Logger.global.level = :debug

    olddb = $DEBUG
    $DEBUG = true
  end
  
  super

  unless olddb.nil?
    $DEBUG = olddb 
    Arrow::Logger.global.outputters.clear
  end
end

- (Object) setup(*args) Also known as: set_up

Run dynamically-added setup methods



180
181
182
183
184
185
186
# File 'lib/arrow/testcase.rb', line 180

def setup( *args )
  if self.class < Arrow::TestCase
    self.class.setupMethods.each {|sblock|
      self.send( sblock )
    }
  end
end

- (Object) skip(reason = nil)

Skip the current step (called from #setup) with the reason given.



202
203
204
205
206
207
208
209
210
211
# File 'lib/arrow/testcase.rb', line 202

def skip( reason=nil )
  if reason
    msg = "Skipping %s: %s" % [ @method_name, reason ]
  else
    msg = "Skipping %s: No reason given." % @method_name
  end

  $stderr.puts( msg ) if $VERBOSE
  @method_name = :skipped_test
end

- (Object) skipped_test

:nodoc:



214
215
# File 'lib/arrow/testcase.rb', line 214

def skipped_test 
end

- (Object) teardown(*args) Also known as: tear_down

Run dynamically-added teardown methods



191
192
193
194
195
196
197
# File 'lib/arrow/testcase.rb', line 191

def teardown( *args )
  if self.class < Arrow::TestCase
    self.class.teardownMethods.each {|tblock|
      self.send( tblock )
    }
  end
end

- (Object) zerofile(filename)

Touch a file and truncate it to 0 bytes



511
512
513
514
# File 'lib/arrow/testcase.rb', line 511

def zerofile( filename )
  File.open( filename, File::WRONLY|File::CREAT ) {}
  File.truncate( filename, 0 )
end