qa_robusta 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. data/.autotest +23 -0
  2. data/.gemtest +0 -0
  3. data/History.txt +6 -0
  4. data/Manifest.txt +101 -0
  5. data/README.txt +48 -0
  6. data/Rakefile +18 -0
  7. data/bin/qa_robusta +14 -0
  8. data/common/Rakefile +95 -0
  9. data/common/conf/monkey_patch.yaml +8 -0
  10. data/common/conf/monkey_patch.yaml.ex +10 -0
  11. data/common/lib/array.rb +9 -0
  12. data/common/lib/cache.rb +12 -0
  13. data/common/lib/constants.rb +35 -0
  14. data/common/lib/error_defns.rb +13 -0
  15. data/common/lib/format_html_tmp.html +34 -0
  16. data/common/lib/formatters.rb +18 -0
  17. data/common/lib/gem_helpers.rb +29 -0
  18. data/common/lib/gems/.svn/entries +43 -0
  19. data/common/lib/gems/cache/.svn/entries +28 -0
  20. data/common/lib/gems/doc/.svn/entries +28 -0
  21. data/common/lib/gems/gems/.svn/entries +28 -0
  22. data/common/lib/gems/installed/.svn/entries +40 -0
  23. data/common/lib/gems/installed/cache/.svn/entries +28 -0
  24. data/common/lib/gems/installed/doc/.svn/entries +28 -0
  25. data/common/lib/gems/installed/gems/.svn/entries +28 -0
  26. data/common/lib/gems/installed/specifications/.svn/entries +28 -0
  27. data/common/lib/gems/specifications/.svn/entries +28 -0
  28. data/common/lib/gen_suite_doc.rb +52 -0
  29. data/common/lib/load_test_data.rb +18 -0
  30. data/common/lib/monkey_patch.rb +149 -0
  31. data/common/lib/navigate_mech.rb +79 -0
  32. data/common/lib/update_element.rb +12 -0
  33. data/common/monkey_patches/mechanize.rb +589 -0
  34. data/common/monkey_patches/table.rb +363 -0
  35. data/common/monkey_patches/telnet.rb +420 -0
  36. data/common/monkey_patches/unit.rb +538 -0
  37. data/demo/demo_site.rb +38 -0
  38. data/demo/public/javascripts/jquery-1.6.2.min.js +18 -0
  39. data/demo/views/index.erb +35 -0
  40. data/lib/monkey_patch.rb +26 -0
  41. data/lib/qa_robusta.rb +3 -0
  42. data/mechanize_interface/conf/app.yaml +10 -0
  43. data/mechanize_interface/lib/agent.rb +18 -0
  44. data/mechanize_interface/lib/app_require.rb +19 -0
  45. data/mechanize_interface/lib/get_page.rb +20 -0
  46. data/mechanize_interface/lib/login.rb +30 -0
  47. data/mechanize_interface/lib/navigation_paths.rb +12 -0
  48. data/mechanize_interface/test/lib/mech_unit_test.rb +19 -0
  49. data/qa_observer/conf/dev_users.yaml +9 -0
  50. data/qa_observer/conf/development.yaml +3 -0
  51. data/qa_observer/conf/qa_observer_links.yaml +10 -0
  52. data/qa_observer/generators/site/site_generator.rb +61 -0
  53. data/qa_observer/generators/site/templates/base_urls.yaml.erb +6 -0
  54. data/qa_observer/generators/site/templates/create_flow.rb.erb +54 -0
  55. data/qa_observer/generators/site/templates/elements.rb.erb +61 -0
  56. data/qa_observer/generators/site/templates/html_elements.yaml +22 -0
  57. data/qa_observer/generators/site/templates/navigate.rb +32 -0
  58. data/qa_observer/generators/site/templates/reports.rb +7 -0
  59. data/qa_observer/generators/site/templates/users_list.yaml +21 -0
  60. data/qa_observer/generators/test_case/templates/test_case.rb.erb +62 -0
  61. data/qa_observer/generators/test_case/test_case_generator.rb +29 -0
  62. data/qa_observer/lib/doc.rb +103 -0
  63. data/qa_observer/lib/env_details.rb +2 -0
  64. data/qa_observer/lib/error_defns.rb +3 -0
  65. data/qa_observer/lib/form_helpers.rb +52 -0
  66. data/qa_observer/lib/reports.rb +7 -0
  67. data/qa_observer/lib/requires.rb +23 -0
  68. data/qa_observer/lib/system_test.rb +146 -0
  69. data/qa_observer/lib/test_extention.rb +29 -0
  70. data/qa_observer/lib/update_element.rb +12 -0
  71. data/qa_observer/lib/watir.rb +42 -0
  72. data/qa_observer/script/destroy +14 -0
  73. data/qa_observer/script/generate +14 -0
  74. data/qa_observer/sites/demo/conf/base_urls.yaml +6 -0
  75. data/qa_observer/sites/demo/conf/html_elements.yaml +22 -0
  76. data/qa_observer/sites/demo/conf/remote_machine.yaml +12 -0
  77. data/qa_observer/sites/demo/conf/users_list.yaml +21 -0
  78. data/qa_observer/sites/demo/elements/demo_elements.rb +9 -0
  79. data/qa_observer/sites/demo/flows/demo_flows.rb +37 -0
  80. data/qa_observer/sites/demo/helpers/.placeholder +0 -0
  81. data/qa_observer/sites/demo/lib/navigate.rb +32 -0
  82. data/qa_observer/sites/demo/lib/reports.rb +7 -0
  83. data/qa_observer/sites/demo/results/.placeholder +0 -0
  84. data/qa_observer/sites/demo/results/images/.placeholder +0 -0
  85. data/qa_observer/sites/demo/test_cases/home_page.rb +106 -0
  86. data/qa_observer/suites/demo_lg_chrome/lg.yaml +11 -0
  87. data/qa_observer/suites/demo_md_chrome/md.yaml +11 -0
  88. data/qa_observer/suites/demo_sm_chrome/sm.yaml +11 -0
  89. data/qa_observer/suites/init.rb +41 -0
  90. data/qa_observer/test_runner.rb +125 -0
  91. data/remote_unix/helpers/constants.rb +8 -0
  92. data/remote_unix/helpers/out_xforms.rb +48 -0
  93. data/remote_unix/lib/common.rb +52 -0
  94. data/remote_unix/lib/error_defn.rb +4 -0
  95. data/remote_unix/lib/general_unix.rb +308 -0
  96. data/remote_unix/lib/network_commands.rb +41 -0
  97. data/remote_unix/lib/network_info.rb +98 -0
  98. data/remote_unix/lib/postfix_commands.rb +87 -0
  99. data/remote_unix/lib/postfix_info.rb +30 -0
  100. data/remote_unix/lib/requires.rb +25 -0
  101. data/remote_unix/lib/scp.rb +22 -0
  102. data/remote_unix/lib/ssh.rb +46 -0
  103. data/test/test_qa_robusta.rb +8 -0
  104. metadata +219 -0
@@ -0,0 +1,538 @@
1
+ ##
2
+ #
3
+ # Totally minimal drop-in replacement for test-unit
4
+ #
5
+ # TODO: refute -> debunk, prove/rebut, show/deny... lots of possibilities
6
+
7
+ module MiniTest
8
+ class Assertion < Exception; end
9
+ class Skip < Assertion; end
10
+
11
+ file = if RUBY_VERSION =~ /^1\.9/ then # bt's expanded, but __FILE__ isn't :(
12
+ File.expand_path __FILE__
13
+ elsif __FILE__ =~ /^[^\.]/ then # assume both relative
14
+ require 'pathname'
15
+ pwd = Pathname.new Dir.pwd
16
+ pn = Pathname.new File.expand_path(__FILE__)
17
+ pn = File.join(".", pn.relative_path_from(pwd)) unless pn.relative?
18
+ pn.to_s
19
+ else # assume both are expanded
20
+ __FILE__
21
+ end
22
+
23
+ # './lib' in project dir, or '/usr/local/blahblah' if installed
24
+ MINI_DIR = File.dirname(File.dirname(file))
25
+
26
+ def self.filter_backtrace bt
27
+ return ["No backtrace"] unless bt
28
+
29
+ new_bt = []
30
+ bt.each do |line|
31
+ break if line.rindex(MINI_DIR, 0)
32
+ new_bt << line
33
+ end
34
+
35
+ new_bt = bt.reject { |line| line.rindex(MINI_DIR, 0) } if new_bt.empty?
36
+ new_bt = bt.dup if new_bt.empty?
37
+ new_bt
38
+ end
39
+
40
+ module Assertions
41
+ def mu_pp(obj)
42
+ s = obj.inspect
43
+ s = s.force_encoding(Encoding.default_external) if defined? Encoding
44
+ s
45
+ end
46
+
47
+ def _assertions= n
48
+ @_assertions = n
49
+ end
50
+
51
+ def _assertions
52
+ @_assertions ||= 0
53
+ end
54
+
55
+ def assert test, msg = nil
56
+ msg ||= "Failed assertion, no message given."
57
+ self._assertions += 1
58
+ unless test then
59
+ msg = msg.call if Proc === msg
60
+ raise MiniTest::Assertion, msg
61
+ end
62
+ true
63
+ end
64
+
65
+ def assert_block msg = nil
66
+ msg = message(msg) { "Expected block to return true value" }
67
+ assert yield, msg
68
+ end
69
+
70
+ def assert_empty obj, msg = nil
71
+ msg = message(msg) { "Expected #{obj.inspect} to be empty" }
72
+ assert_respond_to obj, :empty?
73
+ assert obj.empty?, msg
74
+ end
75
+
76
+ def assert_equal exp, act, msg = nil
77
+ msg = message(msg) { "Expected #{mu_pp(exp)}, not #{mu_pp(act)}" }
78
+ assert(exp == act, msg)
79
+ end
80
+
81
+ def assert_in_delta exp, act, delta = 0.001, msg = nil
82
+ n = (exp - act).abs
83
+ msg = message(msg) { "Expected #{exp} - #{act} (#{n}) to be < #{delta}" }
84
+ assert delta >= n, msg
85
+ end
86
+
87
+ def assert_in_epsilon a, b, epsilon = 0.001, msg = nil
88
+ assert_in_delta a, b, [a, b].min * epsilon, msg
89
+ end
90
+
91
+ def assert_includes collection, obj, msg = nil
92
+ msg = message(msg) { "Expected #{mu_pp(collection)} to include #{mu_pp(obj)}" }
93
+ flip = (obj.respond_to? :include?) && ! (collection.respond_to? :include?) # HACK for specs
94
+ obj, collection = collection, obj if flip
95
+ assert_respond_to collection, :include?
96
+ assert collection.include?(obj), msg
97
+ end
98
+
99
+ def assert_instance_of cls, obj, msg = nil
100
+ msg = message(msg) { "Expected #{mu_pp(obj)} to be an instance of #{cls}, not #{obj.class}" }
101
+ flip = (Module === obj) && ! (Module === cls) # HACK for specs
102
+ obj, cls = cls, obj if flip
103
+ assert obj.instance_of?(cls), msg
104
+ end
105
+
106
+ def assert_kind_of cls, obj, msg = nil # TODO: merge with instance_of
107
+ msg = message(msg) {
108
+ "Expected #{mu_pp(obj)} to be a kind of #{cls}, not #{obj.class}" }
109
+ flip = (Module === obj) && ! (Module === cls) # HACK for specs
110
+ obj, cls = cls, obj if flip
111
+ assert obj.kind_of?(cls), msg
112
+ end
113
+
114
+ def assert_match exp, act, msg = nil
115
+ msg = message(msg) { "Expected #{mu_pp(exp)} to match #{mu_pp(act)}" }
116
+ assert_respond_to act, :"=~"
117
+ exp = /#{Regexp.escape(exp)}/ if String === exp && String === act
118
+ assert exp =~ act, msg
119
+ end
120
+
121
+ def assert_nil obj, msg = nil
122
+ msg = message(msg) { "Expected #{mu_pp(obj)} to be nil" }
123
+ assert obj.nil?, msg
124
+ end
125
+
126
+ def assert_operator o1, op, o2, msg = nil
127
+ msg = message(msg) { "Expected #{mu_pp(o1)} to be #{op} #{mu_pp(o2)}" }
128
+ assert o1.__send__(op, o2), msg
129
+ end
130
+
131
+ def assert_raises *exp
132
+ msg = String === exp.last ? exp.pop : nil
133
+ should_raise = false
134
+ begin
135
+ yield
136
+ should_raise = true
137
+ rescue Exception => e
138
+ assert(exp.any? { |ex|
139
+ ex.instance_of?(Module) ? e.kind_of?(ex) : ex == e.class
140
+ }, exception_details(e, "#{mu_pp(exp)} exception expected, not"))
141
+
142
+ return e
143
+ end
144
+
145
+ exp = exp.first if exp.size == 1
146
+ flunk "#{mu_pp(exp)} expected but nothing was raised." if should_raise
147
+ end
148
+
149
+ def assert_respond_to obj, meth, msg = nil
150
+ msg = message(msg) {
151
+ "Expected #{mu_pp(obj)} (#{obj.class}) to respond to ##{meth}"
152
+ }
153
+ flip = (Symbol === obj) && ! (Symbol === meth) # HACK for specs
154
+ obj, meth = meth, obj if flip
155
+ assert obj.respond_to?(meth), msg
156
+ end
157
+
158
+ def assert_same exp, act, msg = nil
159
+ msg = message(msg) {
160
+ data = [mu_pp(act), act.object_id, mu_pp(exp), exp.object_id]
161
+ "Expected %s (0x%x) to be the same as %s (0x%x)" % data
162
+ }
163
+ assert exp.equal?(act), msg
164
+ end
165
+
166
+ def assert_send send_ary, m = nil
167
+ recv, msg, *args = send_ary
168
+ m = message(m) {
169
+ "Expected #{mu_pp(recv)}.#{msg}(*#{mu_pp(args)}) to return true" }
170
+ assert recv.__send__(msg, *args), m
171
+ end
172
+
173
+ def assert_throws sym, msg = nil
174
+ default = "Expected #{mu_pp(sym)} to have been thrown"
175
+ caught = true
176
+ catch(sym) do
177
+ begin
178
+ yield
179
+ rescue ArgumentError => e # 1.9 exception
180
+ default += ", not #{e.message.split(/ /).last}"
181
+ rescue NameError => e # 1.8 exception
182
+ default += ", not #{e.name.inspect}"
183
+ end
184
+ caught = false
185
+ end
186
+
187
+ assert caught, message(msg) { default }
188
+ end
189
+
190
+ def capture_io
191
+ require 'stringio'
192
+
193
+ orig_stdout, orig_stderr = $stdout, $stderr
194
+ captured_stdout, captured_stderr = StringIO.new, StringIO.new
195
+ $stdout, $stderr = captured_stdout, captured_stderr
196
+
197
+ yield
198
+
199
+ return captured_stdout.string, captured_stderr.string
200
+ ensure
201
+ $stdout = orig_stdout
202
+ $stderr = orig_stderr
203
+ end
204
+
205
+ def exception_details e, msg
206
+ "#{msg}\nClass: <#{e.class}>\nMessage: <#{e.message.inspect}>\n---Backtrace---\n#{MiniTest::filter_backtrace(e.backtrace).join("\n")}\n---------------"
207
+ end
208
+
209
+ def flunk msg = nil
210
+ msg ||= "Epic Fail!"
211
+ assert false, msg
212
+ end
213
+
214
+ def message msg = nil, &default
215
+ proc {
216
+ if msg then
217
+ msg = msg.to_s unless String === msg
218
+ msg += '.' unless msg.empty?
219
+ msg += "\n#{default.call}."
220
+ msg.strip
221
+ else
222
+ "#{default.call}."
223
+ end
224
+ }
225
+ end
226
+
227
+ # used for counting assertions
228
+ def pass msg = nil
229
+ assert true
230
+ end
231
+
232
+ def refute test, msg = nil
233
+ msg ||= "Failed refutation, no message given"
234
+ not assert(! test, msg)
235
+ end
236
+
237
+ def refute_empty obj, msg = nil
238
+ msg = message(msg) { "Expected #{obj.inspect} to not be empty" }
239
+ assert_respond_to obj, :empty?
240
+ refute obj.empty?, msg
241
+ end
242
+
243
+ def refute_equal exp, act, msg = nil
244
+ msg = message(msg) { "Expected #{mu_pp(act)} to not be equal to #{mu_pp(exp)}" }
245
+ refute exp == act, msg
246
+ end
247
+
248
+ def refute_in_delta exp, act, delta = 0.001, msg = nil
249
+ n = (exp - act).abs
250
+ msg = message(msg) { "Expected #{exp} - #{act} (#{n}) to not be < #{delta}" }
251
+ refute delta > n, msg
252
+ end
253
+
254
+ def refute_in_epsilon a, b, epsilon = 0.001, msg = nil
255
+ refute_in_delta a, b, a * epsilon, msg
256
+ end
257
+
258
+ def refute_includes collection, obj, msg = nil
259
+ msg = message(msg) { "Expected #{mu_pp(collection)} to not include #{mu_pp(obj)}" }
260
+ flip = (obj.respond_to? :include?) && ! (collection.respond_to? :include?) # HACK for specs
261
+ obj, collection = collection, obj if flip
262
+ assert_respond_to collection, :include?
263
+ refute collection.include?(obj), msg
264
+ end
265
+
266
+ def refute_instance_of cls, obj, msg = nil
267
+ msg = message(msg) { "Expected #{mu_pp(obj)} to not be an instance of #{cls}" }
268
+ flip = (Module === obj) && ! (Module === cls) # HACK for specs
269
+ obj, cls = cls, obj if flip
270
+ refute obj.instance_of?(cls), msg
271
+ end
272
+
273
+ def refute_kind_of cls, obj, msg = nil # TODO: merge with instance_of
274
+ msg = message(msg) { "Expected #{mu_pp(obj)} to not be a kind of #{cls}" }
275
+ flip = (Module === obj) && ! (Module === cls) # HACK for specs
276
+ obj, cls = cls, obj if flip
277
+ refute obj.kind_of?(cls), msg
278
+ end
279
+
280
+ def refute_match exp, act, msg = nil
281
+ msg = message(msg) { "Expected #{mu_pp(exp)} to not match #{mu_pp(act)}" }
282
+ assert_respond_to act, :"=~"
283
+ exp = /#{Regexp.escape(exp)}/ if String === exp && String === act
284
+ refute exp =~ act, msg
285
+ end
286
+
287
+ def refute_nil obj, msg = nil
288
+ msg = message(msg) { "Expected #{mu_pp(obj)} to not be nil" }
289
+ refute obj.nil?, msg
290
+ end
291
+
292
+ def refute_operator o1, op, o2, msg = nil
293
+ msg = message(msg) { "Expected #{mu_pp(o1)} to not be #{op} #{mu_pp(o2)}" }
294
+ refute o1.__send__(op, o2), msg
295
+ end
296
+
297
+ def refute_respond_to obj, meth, msg = nil
298
+ msg = message(msg) { "Expected #{mu_pp(obj)} to not respond to #{meth}" }
299
+ flip = (Symbol === obj) && ! (Symbol === meth) # HACK for specs
300
+ obj, meth = meth, obj if flip
301
+ refute obj.respond_to?(meth), msg
302
+ end
303
+
304
+ def refute_same exp, act, msg = nil
305
+ msg = message(msg) { "Expected #{mu_pp(act)} to not be the same as #{mu_pp(exp)}" }
306
+ refute exp.equal?(act), msg
307
+ end
308
+
309
+ def skip msg = nil, bt = caller
310
+ msg ||= "Skipped, no message given"
311
+ raise MiniTest::Skip, msg, bt
312
+ end
313
+ end
314
+
315
+ class Unit
316
+ VERSION = "1.3.1"
317
+
318
+ JUNIT_TEMPLATE=<<-EOF
319
+ <testsuite errors='<errors>' failures='<failures>'
320
+ name='' skipped="<skipped>" tests='<num_test>' time='' timestamp=''>
321
+ <TEST_CASES>
322
+ </testsuite>
323
+ EOF
324
+
325
+ JUNIT_TEST_CASE_SECTION=<<-EOF
326
+ <testcase classname="<test_class_name>" time="" name="<test_method_name>" result="<result>">
327
+ <failures>
328
+ </testcase>
329
+ EOF
330
+
331
+ attr_accessor :report, :failures, :errors, :skips
332
+ attr_accessor :test_count, :assertion_count
333
+
334
+ @@installed_at_exit ||= false
335
+
336
+ def self.autorun(format=nil)
337
+ at_exit {
338
+ next if $! # don't run if there was an exception
339
+ exit_code = MiniTest::Unit.new.run(ARGV, format)
340
+ exit false if exit_code && exit_code != 0
341
+
342
+ } unless @@installed_at_exit
343
+
344
+ @@installed_at_exit = true
345
+ end
346
+
347
+ def location e
348
+ last_before_assertion = ""
349
+ e.backtrace.reverse_each do |s|
350
+ break if s =~ /in .(assert|refute|flunk|pass|fail|raise)/
351
+ last_before_assertion = s
352
+ end
353
+ last_before_assertion.sub(/:in .*$/, '')
354
+ end
355
+
356
+ def puke klass, meth, e
357
+ e = case e
358
+ when MiniTest::Skip then
359
+ @skips += 1
360
+ "Skipped:\n#{meth}(#{klass}) [#{location e}]:\n#{e.message}\n"
361
+ when MiniTest::Assertion then
362
+ @failures += 1
363
+ "Failure:\n#{meth}(#{klass}) [#{location e}]:\n#{e.message}\n"
364
+ else
365
+ @errors += 1
366
+ bt = MiniTest::filter_backtrace(e.backtrace).join("\n ")
367
+ "Error:\n#{meth}(#{klass}):\n#{e.class}: #{e.message}\n #{bt}\n"
368
+ end
369
+ @report << e
370
+ e[0, 1]
371
+ end
372
+
373
+ def initialize
374
+ @report = []
375
+ @junit_test_case_section = ''
376
+ @errors = @failures = @skips = 0
377
+ @verbose = false
378
+ end
379
+
380
+ ##
381
+ # Top level driver, controls all output and filtering.
382
+
383
+ def run args = [], junit_xml=false
384
+ @verbose = args.delete('-v')
385
+
386
+ filter = if args.first =~ /^(-n|--name)$/ then
387
+ args.shift
388
+ arg = args.shift
389
+ arg =~ /\/(.*)\// ? Regexp.new($1) : arg
390
+ else
391
+ /./ # anything - ^test_ already filtered by #tests
392
+ end
393
+
394
+ puts "Loaded suite #{$0.sub(/\.rb$/, '')}\nStarted"
395
+
396
+ start = Time.now
397
+ run_test_suites filter
398
+
399
+ puts "Finished in #{'%.6f' % (Time.now - start)} seconds."
400
+
401
+ test_cases_junit = []
402
+
403
+ @report.each_with_index do |msg, i|
404
+
405
+ if junit_xml
406
+
407
+ end
408
+ puts "\n%3d) %s" % [i + 1, msg]
409
+ end
410
+
411
+ puts
412
+
413
+ if junit_xml
414
+ junit_ = JUNIT_TEMPLATE.gsub("<errors>", "#{errors}")
415
+ junit_ = junit_.gsub("<failures>", "#{failures}")
416
+ junit_ = junit_.gsub("<skipped>", "#{skips}")
417
+ junit_ = junit_.gsub("<num_test>", "#{test_count}")
418
+
419
+ junit_ = junit_.gsub("<TEST_CASES>", @junit_test_case_section)
420
+
421
+ puts "<JUNIT>#{junit_}</JUNIT>"
422
+ end
423
+
424
+ format = "%d tests, %d assertions, %d failures, %d errors, %d skips"
425
+ puts format % [test_count, assertion_count, failures, errors, skips]
426
+
427
+ return failures + errors if @test_count > 0 # or return nil...
428
+ end
429
+
430
+ def run_test_suites filter = /./
431
+ @test_count, @assertion_count = 0, 0
432
+ TestCase.test_suites.each do |suite|
433
+ suite.test_methods.grep(filter).each do |test|
434
+
435
+ inst = suite.new test
436
+ inst._assertions = 0
437
+ print "#{suite}##{test}: " if @verbose
438
+
439
+ t = Time.now if @verbose
440
+ result = inst.run(self)
441
+
442
+ print "%.2f s: " % (Time.now - t) if @verbose
443
+ print result
444
+ puts if @verbose
445
+
446
+
447
+ @test_count += 1
448
+ @assertion_count += inst._assertions
449
+ section = JUNIT_TEST_CASE_SECTION.gsub("<test_class_name>", suite.to_s)
450
+ section.gsub!("<test_method_name>", test)
451
+
452
+
453
+ if result == 'F'
454
+ section.gsub!("<result>", 'fail')
455
+ section.gsub!("<failures>", "<failure type=\"AssertionFailedError\" message=\"#{test}\">#{@report.inspect}</failure>")
456
+ else
457
+ section.gsub!("<result>", 'pass')
458
+ section.gsub!("<failures>", "")
459
+ end
460
+
461
+ @junit_test_case_section += section
462
+
463
+ end
464
+ end
465
+ [@test_count, @assertion_count]
466
+ end
467
+
468
+ class TestCase
469
+ attr_reader :name
470
+
471
+ def run runner
472
+ result = '.'
473
+ begin
474
+ @passed = nil
475
+ self.setup
476
+ self.__send__ self.name
477
+ @passed = true
478
+ rescue Exception => e
479
+ @passed = false
480
+ result = runner.puke(self.class, self.name, e)
481
+ ensure
482
+ begin
483
+ self.teardown
484
+ rescue Exception => e
485
+ result = runner.puke(self.class, self.name, e)
486
+ end
487
+ end
488
+ result
489
+ end
490
+
491
+ def initialize name
492
+ @name = name
493
+ @passed = nil
494
+ end
495
+
496
+ def self.reset
497
+ @@test_suites = {}
498
+ end
499
+
500
+ reset
501
+
502
+ def self.inherited klass
503
+ @@test_suites[klass] = true
504
+ end
505
+
506
+ def self.test_order
507
+ :random
508
+ end
509
+
510
+ def self.test_suites
511
+ @@test_suites.keys.sort_by { |ts| ts.name }
512
+ end
513
+
514
+ def self.test_methods
515
+ methods = public_instance_methods(true).grep(/^test/).map { |m|
516
+ m.to_s
517
+ }.sort
518
+
519
+ if self.test_order == :random then
520
+ max = methods.size
521
+ methods = methods.sort_by { rand(max) }
522
+ end
523
+
524
+ methods
525
+ end
526
+
527
+ def setup; end
528
+ def teardown; end
529
+
530
+ def passed?
531
+ @passed
532
+ end
533
+
534
+ include MiniTest::Assertions
535
+ end # class TestCase
536
+ end # class Test
537
+ end # module Mini
538
+