lemon 0.6 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,52 +1,22 @@
1
- module Lemon
2
-
3
- # = Reporter Base Class
4
- class Reporter
5
-
6
- #
7
- def self.factory(format, runner)
8
- format = format.to_sym if format
9
- case format
10
- when :verbose
11
- Reporters::Verbose.new(runner)
12
- else
13
- Reporters::DotProgress.new(runner)
14
- end
15
- end
16
-
17
- def initialize(runner)
18
- @runner = runner
19
- end
20
-
21
- #
22
- attr :runner
23
-
24
- #
25
- def report_start(suite)
26
- end
27
-
28
- def report_concern(concern)
29
- end
1
+ require 'lemon/reporter/dotprogress'
2
+ require 'lemon/reporter/outline'
3
+ require 'lemon/reporter/verbose'
30
4
 
31
- def report_success(testunit)
32
- end
33
-
34
- def report_failure(testunit, exception)
35
- end
36
-
37
- def report_error(testunit, exception)
38
- end
39
-
40
- def report_finish
5
+ module Lemon
6
+ module Reporter
7
+
8
+ # TODO: make Reporter#factory more dynamic
9
+ def self.factory(format, runner)
10
+ format = format.to_s if format
11
+ case format
12
+ when 'v', 'verb', 'verbose'
13
+ Reporter::Verbose.new(runner)
14
+ when 'o', 'out', 'outline'
15
+ Reporter::Outline.new(runner)
16
+ else
17
+ Reporter::DotProgress.new(runner)
41
18
  end
42
-
43
- private
44
-
45
- def successes ; runner.successes ; end
46
- def failures ; runner.failures ; end
47
- def errors ; runner.errors ; end
48
- def pendings ; runner.pendings ; end
49
-
50
19
  end
51
20
 
52
21
  end
22
+ end
@@ -0,0 +1,92 @@
1
+ module Lemon
2
+ module Reporter
3
+
4
+ # = Reporter Base Class
5
+ class Abstract
6
+
7
+ # Supports ANSI Codes?
8
+ ANSI_SUPPORT = (
9
+ begin
10
+ require 'ansi/code'
11
+ true
12
+ rescue LoadError
13
+ false
14
+ end
15
+ )
16
+
17
+ def initialize(runner)
18
+ @runner = runner
19
+ @ansicolor = ANSI_SUPPORT
20
+ end
21
+
22
+ #
23
+ attr :runner
24
+
25
+ #
26
+ def report_start(suite)
27
+ end
28
+
29
+ def report_concern(concern)
30
+ end
31
+
32
+ def report_success(testunit)
33
+ end
34
+
35
+ def report_failure(testunit, exception)
36
+ end
37
+
38
+ def report_error(testunit, exception)
39
+ end
40
+
41
+ def report_finish
42
+ end
43
+
44
+ private
45
+
46
+ def successes ; runner.successes ; end
47
+ def failures ; runner.failures ; end
48
+ def errors ; runner.errors ; end
49
+ def pendings ; runner.pendings ; end
50
+
51
+ def uncovered_cases ; runner.uncovered_cases ; end
52
+ def uncovered_units ; runner.uncovered_units ; end
53
+ def undefined_units ; runner.undefined_units ; end
54
+
55
+ #def uncovered ; runner.uncovered ; end
56
+ #def undefined ; runner.undefined ; end
57
+
58
+ # Is coverage information requested?
59
+ def cover? ; runner.cover? ; end
60
+
61
+ #
62
+ def red(string)
63
+ @ansicolor ? ANSI::Code.red{ string } : string
64
+ end
65
+
66
+ #
67
+ def yellow(string)
68
+ @ansicolor ? ANSI::Code.yellow{ string } : string
69
+ end
70
+
71
+ #
72
+ def green(string)
73
+ @ansicolor ? ANSI::Code.green{ string } : string
74
+ end
75
+
76
+ #
77
+ def total
78
+ successes.size + failures.size + errors.size + pendings.size
79
+ end
80
+
81
+ #
82
+ def tally
83
+ s = "#{total} tests: #{successes.size} pass, #{failures.size} fail, #{errors.size} err, #{pendings.size} pending "
84
+ s += "(#{uncovered_units.size} uncovered, #{undefined_units.size} undefined)" if cover?
85
+ s
86
+ end
87
+
88
+ end
89
+
90
+ end
91
+ end
92
+
@@ -1,10 +1,9 @@
1
1
  module Lemon
2
- module Reporters
3
-
4
- require 'lemon/reporter'
2
+ module Reporter
3
+ require 'lemon/reporter/abstract'
5
4
 
6
5
  # Generic Reporter
7
- class DotProgress < Reporter
6
+ class DotProgress < Abstract
8
7
 
9
8
  def report_start(suite)
10
9
  end
@@ -13,7 +12,7 @@ module Reporters
13
12
  end
14
13
 
15
14
  def report_success(testunit)
16
- print "."
15
+ print "."; $stdout.flush
17
16
  end
18
17
 
19
18
  def report_failure(testunit, exception)
@@ -59,8 +58,7 @@ module Reporters
59
58
  puts
60
59
  end
61
60
 
62
- total = successes.size + failures.size + errors.size + pendings.size
63
- puts "#{total} tests, #{successes.size} pass, #{failures.size} failures, #{errors.size} errors, #{pendings.size} pending"
61
+ puts tally
64
62
  end
65
63
 
66
64
  end
@@ -0,0 +1,105 @@
1
+ module Lemon
2
+ module Reporter
3
+ require 'lemon/reporter/abstract'
4
+
5
+ # Outline Reporter
6
+ class Outline < Abstract
7
+
8
+ #
9
+ def report_start(suite)
10
+ end
11
+
12
+ #
13
+ def report_concern(concern)
14
+ puts
15
+ puts "#{concern.description}\n\n" unless concern.description.empty?
16
+ end
17
+
18
+ #
19
+ def report_success(testunit)
20
+ puts green("* #{testunit}")
21
+ end
22
+
23
+ #
24
+ def report_failure(testunit, exception)
25
+ puts red("* #{testunit} (FAILURE)")
26
+ #puts
27
+ #puts " FAIL #{exception.backtrace[0]}"
28
+ #puts " #{exception}"
29
+ #puts
30
+ end
31
+
32
+ #
33
+ def report_error(testunit, exception)
34
+ puts red("* #{testunit} (ERROR)")
35
+ #puts
36
+ #puts " ERROR #{exception.backtrace[0]}"
37
+ #puts " #{exception}"
38
+ #puts
39
+ end
40
+
41
+ #
42
+ def report_pending(testunit, exception)
43
+ puts yellow("* #{testunit} (PENDING)")
44
+ #puts
45
+ #puts " PENDING #{exception.backtrace[0]}"
46
+ #puts
47
+ end
48
+
49
+ #
50
+ def report_finish
51
+ puts
52
+
53
+ unless failures.empty?
54
+ puts "FAILURES:\n\n"
55
+ failures.each do |testunit, exception|
56
+ puts " #{testunit}"
57
+ puts " #{exception}"
58
+ puts " #{exception.backtrace[0]}"
59
+ puts
60
+ end
61
+ end
62
+
63
+ unless errors.empty?
64
+ puts "ERRORS:\n\n"
65
+ errors.each do |testunit, exception|
66
+ puts " #{testunit}"
67
+ puts " #{exception}"
68
+ puts " #{exception.backtrace[0]}"
69
+ puts
70
+ end
71
+ end
72
+
73
+ #unless pendings.empty?
74
+ # puts "PENDING:\n\n"
75
+ # pendings.each do |testunit, exception|
76
+ # puts " #{testunit}"
77
+ # end
78
+ #end
79
+
80
+ unless uncovered.empty?
81
+ puts "UNCOVERED:\n\n"
82
+ unc = uncovered.map do |testunit|
83
+ yellow("* " +testunit.join('#'))
84
+ end.join("\n")
85
+ puts unc
86
+ puts
87
+ end
88
+
89
+ unless undefined.empty?
90
+ puts "UNDEFINED:\n\n"
91
+ unc = undefined.map do |testunit|
92
+ yellow("* " + testunit.join('#'))
93
+ end.join("\n")
94
+ puts unc
95
+ puts
96
+ end
97
+
98
+ puts tally
99
+ end
100
+
101
+ end
102
+
103
+ end
104
+ end
105
+
@@ -0,0 +1,127 @@
1
+ module Lemon
2
+ module Reporter
3
+ require 'lemon/reporter/abstract'
4
+
5
+ # Verbose Reporter
6
+ class Verbose < Abstract
7
+
8
+ #
9
+ def report_start(suite)
10
+ end
11
+
12
+ #
13
+ def report_concern(concern)
14
+ puts
15
+ puts "#{concern.description}\n\n" unless concern.description.empty?
16
+ end
17
+
18
+ #
19
+ def report_success(testunit)
20
+ puts green("* #{testunit}")
21
+ end
22
+
23
+ #
24
+ def report_failure(testunit, exception)
25
+ puts red("* #{testunit} (FAILURE)")
26
+ puts
27
+ puts " FAIL #{exception.backtrace[0]}"
28
+ puts " #{exception}"
29
+ puts
30
+ end
31
+
32
+ #
33
+ def report_error(testunit, exception)
34
+ puts red("* #{testunit} (ERROR)")
35
+ puts
36
+ puts " ERROR #{exception.backtrace[0]}"
37
+ puts " #{exception}"
38
+ puts
39
+ end
40
+
41
+ #
42
+ def report_pending(testunit, exception)
43
+ puts yellow("* #{testunit} (PENDING)")
44
+ #puts
45
+ #puts " PENDING #{exception.backtrace[1]}"
46
+ #puts
47
+ end
48
+
49
+ #
50
+ def report_finish
51
+ #puts
52
+
53
+ #unless failures.empty?
54
+ # puts "FAILURES:\n\n"
55
+ # failures.each do |testunit, exception|
56
+ # puts " #{testunit}"
57
+ # puts " #{exception}"
58
+ # puts " #{exception.backtrace[0]}"
59
+ # puts
60
+ # end
61
+ #end
62
+
63
+ #unless errors.empty?
64
+ # puts "ERRORS:\n\n"
65
+ # errors.each do |testunit, exception|
66
+ # puts " #{testunit}"
67
+ # puts " #{exception}"
68
+ # puts " #{exception.backtrace[0]}"
69
+ # puts
70
+ # end
71
+ #end
72
+
73
+ #unless pendings.empty?
74
+ # puts "PENDING:\n\n"
75
+ # pendings.each do |testunit, exception|
76
+ # puts " #{testunit}"
77
+ # end
78
+ # puts
79
+ #end
80
+
81
+ if cover?
82
+
83
+ unless uncovered_cases.empty?
84
+ unc = uncovered_cases.map do |mod|
85
+ yellow(mod.name)
86
+ end.join(", ")
87
+ puts "\nUncovered Cases: " + unc
88
+ end
89
+
90
+ unless uncovered_units.empty?
91
+ unc = uncovered_units.map do |unit|
92
+ yellow(unit)
93
+ end.join(", ")
94
+ puts "\nUncovered Units: " + unc
95
+ end
96
+
97
+ #unless uncovered.empty?
98
+ # unc = uncovered.map do |unit|
99
+ # yellow(unit)
100
+ # end.join(", ")
101
+ # puts "\nUncovered: " + unc
102
+ #end
103
+
104
+ unless undefined_units.empty?
105
+ unc = undefined_units.map do |unit|
106
+ yellow(unit)
107
+ end.join(", ")
108
+ puts "\nUndefined Units: " + unc
109
+ end
110
+
111
+ end
112
+
113
+ #total = successes.size + failures.size + errors.size + pendings.size
114
+ #tally = "\n#{total} tests: #{successes.size} pass, #{failures.size} fail, #{errors.size} err, #{pendings.size} pending"
115
+ #if cover?
116
+ # tally += " (#{uncovered.size} uncovered, #{undefined.size} undefined)"
117
+ #end
118
+
119
+ puts
120
+ puts tally
121
+ end
122
+
123
+ end
124
+
125
+ end
126
+ end
127
+
data/lib/lemon/runner.rb CHANGED
@@ -6,7 +6,7 @@ module Lemon
6
6
 
7
7
  require 'lemon/kernel'
8
8
  require 'lemon/test/suite'
9
- require 'lemon/reporters'
9
+ require 'lemon/reporter'
10
10
 
11
11
  #
12
12
  class Runner
@@ -30,29 +30,51 @@ module Lemon
30
30
  attr :pendings
31
31
 
32
32
  # New Runner.
33
- def initialize(suite, format)
33
+ def initialize(suite, options={})
34
34
  @suite = suite
35
- @format = format
35
+ @options = options
36
+
36
37
  @successes = []
37
38
  @failures = []
38
39
  @errors = []
39
40
  @pendings = []
40
41
  end
41
42
 
43
+ #
44
+ def format
45
+ @options[:format]
46
+ end
47
+
48
+ #
49
+ def cover?
50
+ @options[:cover]
51
+ end
52
+
53
+ # Namespaces option specifies the selection of test cases
54
+ # to run. Is is an array of strings which are matched
55
+ # against the module/class names using #start_wtih?
56
+ def namespaces
57
+ @options[:namespaces] || []
58
+ end
59
+
42
60
  # Run tests.
43
61
  def run
62
+ #prepare
63
+
44
64
  reporter.report_start(suite)
45
- suite.each do |testcase|
65
+
66
+ each do |testcase|
46
67
  testcase.each do |concern|
47
68
  reporter.report_concern(concern)
48
69
  run_concern_procedures(concern, suite, testcase)
49
70
  concern.each do |testunit|
71
+ #mark_coverage(testcase, testunit)
50
72
  run_pretest_procedures(testunit, suite, testcase)
51
73
  begin
52
74
  testunit.call
53
75
  reporter.report_success(testunit)
54
76
  successes << testunit
55
- rescue PendingAssertion => exception
77
+ rescue Pending => exception
56
78
  reporter.report_pending(testunit, exception)
57
79
  pendings << [testunit, exception]
58
80
  rescue Assertion => exception
@@ -66,15 +88,121 @@ module Lemon
66
88
  end
67
89
  end
68
90
  end
91
+
69
92
  reporter.report_finish #(successes, failures, errors, pendings)
70
93
  end
71
94
 
95
+ # Iterate overs suite testcases, filtering out unselected testcases
96
+ # if any namespaces are provided.
97
+ def each(&block)
98
+ if namespaces.empty?
99
+ suite.each do |testcase|
100
+ block.call(testcase)
101
+ end
102
+ else
103
+ suite.each do |testcase|
104
+ next unless namespaces.any?{ |n| testcase.target.name.start_with?(n) }
105
+ block.call(testcase)
106
+ end
107
+ end
108
+ end
109
+
72
110
  # All output is handled by a reporter.
73
111
  def reporter
74
112
  @reporter ||= Reporter.factory(format, self)
75
113
  end
76
114
 
77
- private
115
+ #
116
+ #def uncovered
117
+ # c = []
118
+ # @testcase_coverage.each do |testcase, testunits|
119
+ # testunits.each do |testunit, coverage|
120
+ # c << [testcase, testunit] if coverage == false
121
+ # end
122
+ # end
123
+ # c
124
+ #end
125
+
126
+ =begin
127
+ #
128
+ def prepare
129
+ if cover?
130
+ coverage.canonical!
131
+ end
132
+
133
+ suite.load_covered_files
134
+
135
+ if cover?
136
+ @uncovered = calculate_uncovered
137
+ @undefined = calculate_undefined
138
+ end
139
+ end
140
+ =end
141
+
142
+ #
143
+ def uncovered_cases
144
+ @uncovered_cases ||= coverage.uncovered_cases
145
+ end
146
+
147
+ #
148
+ def uncovered_units
149
+ @uncovered_units ||= coverage.uncovered_units
150
+ end
151
+
152
+ #
153
+ def undefined_units
154
+ @undefined_units ||= coverage.undefined_units
155
+ end
156
+
157
+ =begin
158
+ #
159
+ def uncovered
160
+ @uncovered ||= calculate_uncovered
161
+ end
162
+
163
+ #
164
+ def undefined
165
+ @undefined ||= calculate_undefined
166
+ end
167
+
168
+ #
169
+ def calculate_uncovered
170
+ uncovered_targets = []
171
+ coverage.checklist.each do |mod, meths|
172
+ meths.each do |meth, covered|
173
+ if !covered
174
+ if /^::/ =~ meth.to_s
175
+ uncovered_targets << "#{mod}#{meth}"
176
+ else
177
+ uncovered_targets << "#{mod}##{meth}"
178
+ end
179
+ end
180
+ end
181
+ end
182
+ uncovered_targets
183
+ end
184
+
185
+ #
186
+ def calculate_undefined
187
+ covered_testunits = successes + (failures + errors + pendings).map{ |tu, e| tu }
188
+ covered_targets = covered_testunits.map{ |tu| tu.fullname }
189
+
190
+ targets = []
191
+ coverage.each do |mod, meths|
192
+ meths.each do |meth, cov|
193
+ if /^::/ =~ meth.to_s
194
+ targets << "#{mod}#{meth}"
195
+ else
196
+ targets << "#{mod}##{meth}"
197
+ end
198
+ end
199
+ end
200
+
201
+ covered_targets - targets
202
+ end
203
+ =end
204
+
205
+ private
78
206
 
79
207
  #
80
208
  def run_concern_procedures(concern, suite, testcase)
@@ -88,36 +216,91 @@ module Lemon
88
216
  block.call(testcase) if match === concern.to_s
89
217
  end
90
218
  end
219
+ concern.call
91
220
  end
92
221
 
93
- #
222
+ # Run pre-test advice.
94
223
  def run_pretest_procedures(testunit, suite, testcase)
95
224
  suite.before_clauses.each do |match, block|
96
- if match.nil? or match === testunit.aspect
225
+ if match.nil? or testunit.match?(match)
97
226
  block.call(testunit)
98
227
  end
99
228
  end
100
229
  testcase.before_clauses.each do |match, block|
101
- if match.nil? or match === testunit.aspect
230
+ if match.nil? or testunit.match?(match)
102
231
  block.call(testunit)
103
232
  end
104
233
  end
105
234
  end
106
235
 
107
- #
236
+ # Run post-test advice.
108
237
  def run_postest_procedures(testunit, suite, testcase)
109
238
  testcase.after_clauses.each do |match, block|
110
- if match.nil? or match === testunit.aspect
239
+ if match.nil? or testunit.match?(match)
111
240
  block.call(testunit)
112
241
  end
113
242
  end
114
243
  suite.after_clauses.each do |match, block|
115
- if match.nil? or match === testunit.aspect
244
+ if match.nil? or testunit.match?(match)
116
245
  block.call(testunit)
117
246
  end
118
247
  end
119
248
  end
120
249
 
250
+ #
251
+ def coverage
252
+ @coverage ||= Lemon::Coverage.new(suite, namespaces) #, :public => public_only?)
253
+ end
254
+
255
+ =begin
256
+ # TODO: I would think all this should be gained form the Coverage class.
257
+
258
+ # TODO: options to include non-public and superclasses less Object and Kernel.
259
+ def mark_coverage(testcase, testunit)
260
+ testunit = testunit.target.to_sym
261
+ profile = testcase_profile(testcase)
262
+ coverage = testcase_coverage(testcase)
263
+
264
+ if profile[:public].include?(testunit) || profile[:meta_public].include?(testunit)
265
+ coverage[testunit] = :public
266
+ elsif profile[:private].include?(testunit) || profile[:meta_private].include?(testunit)
267
+ coverage[testunit] = :private
268
+ elsif profile[:protected].include?(testunit) || profile[:meta_protected].include?(testunit)
269
+ coverage[testunit] = :protected
270
+ else
271
+ coverage[testunit] = nil # nil means does not exist, while false means not covered.
272
+ end
273
+ end
274
+
275
+ #
276
+ def testcase_coverage(testcase)
277
+ target = testcase.target
278
+ @testcase_coverage ||= {}
279
+ @testcase_coverage[target] ||= (
280
+ h = {}
281
+ target.public_instance_methods(false).each{|unit| h[unit] = false }
282
+ (target.public_methods(false) - Object.public_methods(false)).each{|unit| h[unit] = false }
283
+ #target.private_instance_method(false)
284
+ #target.protected_instance_method(false)
285
+ h
286
+ )
287
+ end
288
+
289
+ #
290
+ def testcase_profile(testcase)
291
+ target = testcase.target
292
+ @testcase_profile ||= {}
293
+ @testcase_profile[target] ||= {
294
+ :public => target.public_instance_methods(false).map{|s|s.to_sym},
295
+ :private => target.private_instance_methods(false).map{|s|s.to_sym},
296
+ :protected => target.protected_instance_methods(false).map{|s|s.to_sym},
297
+ :meta_public => (target.public_methods(false) - Object.public_methods(false)).map{|s|s.to_sym},
298
+ :meta_private => (target.private_methods(false) - Object.private_methods(false)).map{|s|s.to_sym},
299
+ :meta_protected => (target.protected_methods(false)- Object.protected_methods(false)).map{|s|s.to_sym}
300
+ }
301
+ end
302
+ =end
303
+
121
304
  end
122
305
 
123
306
  end