qa_robusta 0.1.3

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 (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
+