rubytest 0.3.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.
@@ -0,0 +1,145 @@
1
+ # encoding: UTF-8
2
+
3
+ module Test::Reporters
4
+
5
+ # Summary Reporter
6
+ class Summary < Abstract
7
+
8
+ #
9
+ SEP = ' '
10
+
11
+ #
12
+ def begin_suite(suite)
13
+ timer_reset
14
+ @tc = []
15
+ end
16
+
17
+ #
18
+ def begin_case(tc)
19
+ @tc << tc.to_s.split("\n").first
20
+ end
21
+
22
+ #
23
+ #def report_instance(instance)
24
+ # puts
25
+ # puts instance #"== #{concern.description}\n\n" unless concern.description.empty?
26
+ # #timer_reset
27
+ #end
28
+
29
+ #
30
+ #def begin_test(test)
31
+ # context = test.context
32
+ # if @instance != context
33
+ # @context = context
34
+ # puts
35
+ # puts " #{context}"
36
+ # puts
37
+ # end
38
+ #end
39
+
40
+ #
41
+ def pass(test)
42
+ print "PASS ".ansi(:green, :bold)
43
+ e = @tc + [test.to_s]
44
+ puts e.join(SEP).ansi(:green)
45
+ end
46
+
47
+ #
48
+ def fail(test, exception)
49
+ print "FAIL ".ansi(:red, :bold)
50
+ e = @tc + [test.to_s]
51
+ puts e.join(SEP).ansi(:red)
52
+ end
53
+
54
+ #
55
+ def error(test, exception)
56
+ print "ERROR ".ansi(:red, :bold)
57
+ e = @tc + [test.to_s]
58
+ puts e.join(SEP).ansi(:red)
59
+ end
60
+
61
+ #
62
+ def todo(test, exception)
63
+ print "TODO ".ansi(:yellow, :bold)
64
+ e = @tc + [test.to_s]
65
+ puts e.join(SEP).ansi(:yellow)
66
+ end
67
+
68
+ #
69
+ def omit(test)
70
+ print "OMIT ".ansi(:cyan, :bold)
71
+ e = @tc + [test.to_s]
72
+ puts e.join(SEP).ansi(:cyan)
73
+ end
74
+
75
+ #
76
+ def skip_test(test)
77
+ print "SKIP ".ansi(:blue, :bold)
78
+ e = @tc + [test.to_s]
79
+ puts e.join(SEP).ansi(:blue)
80
+ end
81
+
82
+ #
83
+ def end_case(test_case)
84
+ @tc.pop
85
+ end
86
+
87
+ #
88
+ def end_suite(suite)
89
+ puts
90
+
91
+ unless record[:pending].empty?
92
+ puts "PENDING:\n\n"
93
+ record[:pending].each do |test, exception|
94
+ puts " #{test}"
95
+ puts " #{file_and_line(exception)}"
96
+ puts
97
+ end
98
+ end
99
+
100
+ unless record[:fail].empty?
101
+ puts "FAILURES:\n\n"
102
+ record[:fail].each do |test, exception|
103
+ puts " #{test}"
104
+ puts " #{file_and_line(exception)}"
105
+ puts " #{exception}"
106
+ puts code(exception).to_s
107
+ #puts " #{exception.backtrace[0]}"
108
+ puts
109
+ end
110
+ end
111
+
112
+ unless record[:error].empty?
113
+ puts "ERRORS:\n\n"
114
+ record[:error].each do |test, exception|
115
+ puts " #{test}"
116
+ puts " #{file_and_line(exception)}"
117
+ puts " #{exception}"
118
+ puts code(exception).to_s
119
+ #puts " #{exception.backtrace[0]}"
120
+ puts
121
+ end
122
+ end
123
+
124
+ puts timestamp
125
+ puts
126
+ puts tally
127
+ end
128
+
129
+ private
130
+
131
+ #
132
+ def timer
133
+ secs = Time.now - @time
134
+ @time = Time.now
135
+ return "%0.5fs" % [secs.to_s]
136
+ end
137
+
138
+ #
139
+ def timer_reset
140
+ @time = Time.now
141
+ end
142
+
143
+ end
144
+
145
+ end
@@ -0,0 +1,61 @@
1
+ # encoding: UTF-8
2
+
3
+ module Test::Reporters
4
+
5
+ # Classic TAP Reporter
6
+ #
7
+ # This reporter conforms to v12 of TAP. It could do with some
8
+ # imporvements yet, and eventually upgraded to v13 of standard.
9
+ class Tap < Abstract
10
+
11
+ #
12
+ def begin_suite(suite)
13
+ @start_time = Time.now
14
+ @i = 0
15
+ @n = total_count(suite)
16
+ puts "1..#{@n}"
17
+ end
18
+
19
+ def begin_test(test)
20
+ @i += 1
21
+ end
22
+
23
+ #
24
+ def pass(test)
25
+ puts "ok #{@i} - #{test}"
26
+ end
27
+
28
+ #
29
+ def fail(test, exception)
30
+ puts "not ok #{@i} - #{test}"
31
+ puts " FAIL #{exception.class}"
32
+ puts " #{exception}"
33
+ puts " #{clean_backtrace(exception)[0]}"
34
+ end
35
+
36
+ #
37
+ def error(test, exception)
38
+ puts "not ok #{@i} - #{test}"
39
+ puts " ERROR #{exception.class}"
40
+ puts " #{exception}"
41
+ puts " " + clean_backtrace(exception).join("\n ")
42
+ end
43
+
44
+ #
45
+ def todo(test, exception)
46
+ puts "not ok #{@i} - #{test}"
47
+ puts " PENDING"
48
+ puts " #{clean_backtrace(exception)[1]}"
49
+ end
50
+
51
+ #
52
+ def omit(test, exception)
53
+ puts "ok #{@i} - #{test}"
54
+ puts " OMIT"
55
+ puts " #{clean_backtrace(exception)[1]}"
56
+ end
57
+
58
+ end
59
+
60
+ end
61
+
@@ -0,0 +1,53 @@
1
+ # encoding: UTF-8
2
+
3
+ module Test::Reporters
4
+
5
+ # TAP-J Reporter
6
+ #
7
+ class Tapj < AbstractHash
8
+
9
+ #
10
+ def initialize(runner)
11
+ require 'json'
12
+ super(runner)
13
+ end
14
+
15
+ #
16
+ def begin_suite(suite)
17
+ puts super(suite).to_json
18
+ end
19
+
20
+ #
21
+ def begin_case(test_case)
22
+ puts super(test_case).to_json
23
+ end
24
+
25
+ #
26
+ def pass(test) #, backtrace=nil)
27
+ puts super(test).to_json
28
+ end
29
+
30
+ #
31
+ def fail(test, exception)
32
+ puts super(test, exception).to_json
33
+ end
34
+
35
+ #
36
+ def error(test, exception)
37
+ puts super(test, exception).to_json
38
+ end
39
+
40
+ #
41
+ def todo(test, exception)
42
+ puts super(test, exception).to_json
43
+ end
44
+
45
+ #
46
+ def end_suite(suite)
47
+ puts super(suite).to_json
48
+ puts "..."
49
+ end
50
+
51
+ end
52
+
53
+ end
@@ -0,0 +1,58 @@
1
+ # encoding: UTF-8
2
+
3
+ module Test::Reporters
4
+
5
+ # TAP-Y Reporter
6
+ #
7
+ class Tapy < AbstractHash
8
+
9
+ #
10
+ def initialize(runner)
11
+ require 'json'
12
+ super(runner)
13
+ end
14
+
15
+ #
16
+ def begin_suite(suite)
17
+ puts super(suite).to_yaml
18
+ end
19
+
20
+ #
21
+ def begin_case(test_case)
22
+ puts super(test_case).to_yaml
23
+ end
24
+
25
+ #
26
+ def pass(test) #, backtrace=nil)
27
+ puts super(test).to_yaml
28
+ end
29
+
30
+ #
31
+ def fail(test, exception)
32
+ puts super(test, exception).to_yaml
33
+ end
34
+
35
+ #
36
+ def error(test, exception)
37
+ puts super(test, exception).to_yaml
38
+ end
39
+
40
+ #
41
+ def todo(test, exception)
42
+ puts super(test, exception).to_yaml
43
+ end
44
+
45
+ #
46
+ def omit(test, exception)
47
+ puts super(test, exception).to_yaml
48
+ end
49
+
50
+ #
51
+ def end_suite(suite)
52
+ puts super(suite).to_yaml
53
+ puts "..."
54
+ end
55
+
56
+ end
57
+
58
+ end
@@ -0,0 +1,51 @@
1
+ # encoding: UTF-8
2
+
3
+ module Test::Reporters
4
+
5
+ # Test Reporter is used to test Ruby Test itself.
6
+ #
7
+ class Test < AbstractHash
8
+
9
+ #
10
+ def initialize(runner)
11
+ super(runner)
12
+ end
13
+
14
+ #
15
+ def begin_suite(suite)
16
+ super(suite)
17
+ end
18
+
19
+ #
20
+ def begin_case(test_case)
21
+ super(test_case)
22
+ end
23
+
24
+ #
25
+ def pass(test) #, backtrace=nil)
26
+ super(test)
27
+ end
28
+
29
+ #
30
+ def fail(test, exception)
31
+ super(test, exception)
32
+ end
33
+
34
+ #
35
+ def error(test, exception)
36
+ super(test, exception)
37
+ end
38
+
39
+ #
40
+ def todo(test, exception)
41
+ super(test, exception)
42
+ end
43
+
44
+ #
45
+ def end_suite(suite)
46
+ super(suite)
47
+ end
48
+
49
+ end
50
+
51
+ end
@@ -0,0 +1,349 @@
1
+ module Test
2
+
3
+ # The Test::Runner class handles the execution of tests.
4
+ #
5
+ class Runner
6
+
7
+ # Default report is in the old "dot-progress" format.
8
+ DEFAULT_FORMAT = 'dotprogress'
9
+
10
+ # Exceptions that are not caught by test runner.
11
+ OPEN_ERRORS = [NoMemoryError, SignalException, Interrupt, SystemExit]
12
+
13
+ # / / / D E F A U L T S / / /
14
+
15
+ # Default test suite ($TEST_SUITE).
16
+ def self.suite
17
+ $TEST_SUITE
18
+ end
19
+
20
+ # Default list of test files to load.
21
+ def self.files
22
+ @files ||= []
23
+ end
24
+
25
+ #
26
+ def self.format
27
+ @format || DEFAULT_FORMAT
28
+ end
29
+
30
+ #
31
+ def self.format=(format)
32
+ @format = format
33
+ end
34
+
35
+ #
36
+ def self.verbose
37
+ @verbose
38
+ end
39
+
40
+ #
41
+ def self.verbose=(boolean)
42
+ @verbose = !!boolean
43
+ end
44
+
45
+ # Default description match for filtering tests.
46
+ def self.match
47
+ @match ||= []
48
+ end
49
+
50
+ # Default selection of tags for filtering tests.
51
+ def self.tags
52
+ @tags ||= []
53
+ end
54
+
55
+ # Default selection of units for filtering tests.
56
+ def self.units
57
+ @unit ||= []
58
+ end
59
+
60
+ #
61
+ def self.hard
62
+ @hard
63
+ end
64
+
65
+ #
66
+ def self.hard=(boolean)
67
+ @hard = !!boolean
68
+ end
69
+
70
+ # / / / A T T R I B U T E S / / /
71
+
72
+ # Test suite to run. This is a list of compliant test units and test cases.
73
+ attr :suite
74
+
75
+ # Test files to load.
76
+ attr :files
77
+
78
+ # Reporter format name, or name fragment, used to look up reporter class.
79
+ attr :format
80
+
81
+ #
82
+ def format=(name)
83
+ @format = name.to_s
84
+ end
85
+
86
+ # Matching text used to filter which tests are run.
87
+ attr :match
88
+
89
+ # Selected tags used to filter which tests are run.
90
+ attr :tags
91
+
92
+ # List of units with which to filter tests. It is an array of strings
93
+ # which are matched against module, class and method names.
94
+ attr :units
95
+
96
+ # Show extra details in reports.
97
+ def verbose?
98
+ @verbose
99
+ end
100
+
101
+ #
102
+ def verbose=(boolean)
103
+ @verbose = !!boolean
104
+ end
105
+
106
+ # Use "hard" test mode?
107
+ def hard?
108
+ @hard
109
+ end
110
+
111
+ #
112
+ def hard=(boolean)
113
+ @hard = !!boolean
114
+ end
115
+
116
+ # New Runner.
117
+ #
118
+ # @param [Array] suite
119
+ # A list of compliant tests/testcases.
120
+ #
121
+ def initialize(options={}, &block)
122
+ @suite = options[:suite] || self.class.suite
123
+ @files = options[:files] || self.class.files
124
+ @format = options[:format] || self.class.format
125
+ @tags = options[:tags] || self.class.tags
126
+ @units = options[:units] || self.class.units
127
+ @match = options[:match] || self.class.match
128
+ @verbose = options[:verbose] || self.class.verbose
129
+ @hard = options[:hard] || self.class.hard
130
+
131
+ block.call(self) if block
132
+ end
133
+
134
+ # The reporter to use for ouput.
135
+ attr :reporter
136
+
137
+ # Record pass, fail, error, pending and omitted tests.
138
+ attr :recorder
139
+
140
+ # Array of observers, typically this just contains the recorder and
141
+ # reporter instances.
142
+ attr :observers
143
+
144
+ # Run test suite.
145
+ #
146
+ # @return [Boolean]
147
+ # That the tests ran without error or failure.
148
+ #
149
+ def run
150
+ ignore_callers
151
+
152
+ files_resolved.each do |file|
153
+ require file
154
+ end
155
+
156
+ @reporter = reporter_load(format)
157
+ @recorder = Recorder.new
158
+ @observers = [@reporter, @recorder]
159
+
160
+ #cd_tmp do
161
+ observers.each{ |o| o.begin_suite(suite) }
162
+ run_thru(suite)
163
+ observers.each{ |o| o.end_suite(suite) }
164
+ #end
165
+
166
+ recorder.success?
167
+ end
168
+
169
+ private
170
+
171
+ # Add to RUBY_IGNORE_CALLERS.
172
+ #
173
+ # @todo Improve on this!
174
+ def ignore_callers
175
+ ignore_path = File.expand_path(File.join(__FILE__, '../../..'))
176
+ ignore_regexp = Regexp.new(Regexp.escape(ignore_path))
177
+
178
+ ::RUBY_IGNORE_CALLERS << ignore_regexp
179
+ ::RUBY_IGNORE_CALLERS << /bin\/rubytest/
180
+ end
181
+
182
+ #
183
+ def run_thru(list)
184
+ list.each do |t|
185
+ if t.respond_to?(:each)
186
+ run_case(t)
187
+ elsif t.respond_to?(:call)
188
+ run_test(t)
189
+ else
190
+ #run_note(t) ?
191
+ end
192
+ end
193
+ end
194
+
195
+ # Run a test case.
196
+ #
197
+ def run_case(tcase)
198
+ if tcase.respond_to?(:skip?) && tcase.skip?
199
+ return observers.each{ |o| o.skip_case(tcase) }
200
+ end
201
+
202
+ observers.each{ |o| o.begin_case(tcase) }
203
+
204
+ if tcase.respond_to?(:call)
205
+ tcase.call do
206
+ run_thru( select(tcase) )
207
+ end
208
+ else
209
+ run_thru( select(tcase) )
210
+ end
211
+
212
+ observers.each{ |o| o.end_case(tcase) }
213
+ end
214
+
215
+ # Run a test.
216
+ #
217
+ # @param [Object] test
218
+ # The test to run, must repsond to #call.
219
+ #
220
+ def run_test(test)
221
+ if test.respond_to?(:skip?) && test.skip?
222
+ return observers.each{ |o| o.skip_test(test) }
223
+ end
224
+
225
+ observers.each{ |o| o.begin_test(test) }
226
+ begin
227
+ success = test.call
228
+ if hard? && !success # TODO: separate run_test method to speed things up?
229
+ raise Assertion, "failure of #{test}"
230
+ else
231
+ observers.each{ |o| o.pass(test) }
232
+ end
233
+ rescue *OPEN_ERRORS => exception
234
+ raise exception
235
+ rescue NotImplementedError => exception
236
+ if exception.assertion?
237
+ observers.each{ |o| o.omit(test, exception) }
238
+ else
239
+ observers.each{ |o| o.todo(test, exception) }
240
+ end
241
+ rescue Exception => exception
242
+ if exception.assertion?
243
+ observers.each{ |o| o.fail(test, exception) }
244
+ else
245
+ observers.each{ |o| o.error(test, exception) }
246
+ end
247
+ end
248
+ observers.each{ |o| o.end_test(test) }
249
+ end
250
+
251
+ # TODO: Make sure this filtering code is correct for the complex
252
+ # condition that that ordered testcases can't have their tests
253
+ # filtered individually (since they may depend on one another).
254
+
255
+ # Filter cases based on selection criteria.
256
+ #
257
+ # @return [Array] selected test cases
258
+ def select(cases)
259
+ selected = []
260
+ if cases.respond_to?(:ordered?) && cases.ordered?
261
+ cases.each do |tc|
262
+ selected << tc
263
+ end
264
+ else
265
+ cases.each do |tc|
266
+ next if tc.respond_to?(:skip?) && tc.skip?
267
+ next if !match.empty? && !match.any?{ |m| m =~ tc.to_s }
268
+
269
+ if !units.empty?
270
+ next unless tc.respond_to?(:unit)
271
+ next unless units.find{ |u| tc.unit.start_with?(u) }
272
+ end
273
+
274
+ if !tags.empty?
275
+ next unless tc.respond_to?(:tags)
276
+ tc_tags = [tc.tags].flatten.map{ |t| t.to_s }
277
+ next if (tags & tc_tags).empty?
278
+ end
279
+
280
+ selected << tc
281
+ end
282
+ end
283
+ selected
284
+ end
285
+
286
+ # Get a reporter instance be name fragment.
287
+ #
288
+ # @return [Reporter::Abstract]
289
+ # The test reporter instance.
290
+ #
291
+ def reporter_load(format)
292
+ format = DEFAULT_REPORT_FORMAT unless format
293
+ format = format.to_s.downcase
294
+ name = reporter_list.find{ |r| /^#{format}/ =~ r }
295
+
296
+ raise "unsupported report format" unless format
297
+
298
+ if RUBY_VERSION < '1.9'
299
+ require "rubytest/reporters/#{name}"
300
+ else
301
+ require_relative "reporters/#{name}"
302
+ end
303
+
304
+ reporter = Test::Reporters.const_get(name.capitalize)
305
+ reporter.new(self)
306
+ end
307
+
308
+ # Returns a list of available report types.
309
+ #
310
+ # @return [Array<String>]
311
+ # The names of available reporters.
312
+ #
313
+ def reporter_list
314
+ list = Dir[File.dirname(__FILE__) + '/reporters/*.rb']
315
+ list = list.map{ |r| File.basename(r).chomp('.rb') }
316
+ list = list.reject{ |r| /^abstract/ =~ r }
317
+ list.sort
318
+ end
319
+
320
+ # Files can be globs and directories which need to be
321
+ # resolved to a list of files.
322
+ #
323
+ def files_resolved
324
+ list = files.flatten
325
+ list = list.map{ |f| Dir[f] }.flatten
326
+ list = list.map{ |f| File.directory?(f) ? Dir[File.join(f, '**/*.rb')] : f }
327
+ list = list.flatten.uniq
328
+ list = list.map{ |f| File.expand_path(f) }
329
+ list
330
+ end
331
+
332
+ =begin
333
+ # TODO ?
334
+ def cd_tmp(&block)
335
+ dir = Test::Config.root + '/tmp'
336
+ if Directory.exist?(dir)
337
+ dir = File.join(dir, 'test')
338
+ FileUtils.mkdir(dir) unless File.exist?(dir)
339
+ else
340
+ dir = File.join(Dir.tmpdir)
341
+ end
342
+
343
+ Dir.chdir(dir, &block)
344
+ end
345
+ =end
346
+
347
+ end
348
+
349
+ end