lemon 0.6 → 0.7.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.
@@ -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