lemon 0.8.1 → 0.8.2
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.
- data/HISTORY.rdoc +15 -0
- data/README.rdoc +32 -14
- data/bin/lemon +3 -2
- data/demo/case_example_fail.rb +15 -0
- data/demo/case_example_pass.rb +32 -0
- data/demo/case_example_pending.rb +14 -0
- data/demo/case_example_untested.rb +10 -0
- data/demo/fixture/example-use.rb +5 -0
- data/demo/fixture/example.rb +20 -0
- data/lib/lemon.rb +2 -2
- data/lib/lemon/cli.rb +281 -0
- data/lib/lemon/controller/coverage_analyzer.rb +343 -0
- data/lib/lemon/controller/scaffold_generator.rb +110 -0
- data/lib/lemon/controller/test_runner.rb +284 -0
- data/lib/lemon/meta/data.rb +29 -0
- data/lib/lemon/meta/gemfile +24 -0
- data/{PROFILE → lib/lemon/meta/profile} +6 -5
- data/lib/lemon/model/ae.rb +4 -0
- data/lib/lemon/model/cover_unit.rb +75 -0
- data/lib/lemon/{dsl.rb → model/main.rb} +22 -28
- data/lib/lemon/model/pending.rb +10 -0
- data/lib/lemon/model/snapshot.rb +203 -0
- data/lib/lemon/model/source_parser.rb +198 -0
- data/lib/lemon/model/test_case.rb +221 -0
- data/lib/lemon/model/test_context.rb +90 -0
- data/lib/lemon/model/test_suite.rb +216 -0
- data/lib/lemon/{test/unit.rb → model/test_unit.rb} +40 -28
- data/lib/lemon/{coversheet → view/cover_reports}/abstract.rb +19 -20
- data/lib/lemon/view/cover_reports/compact.rb +37 -0
- data/lib/lemon/view/cover_reports/outline.rb +45 -0
- data/lib/lemon/view/cover_reports/verbose.rb +51 -0
- data/lib/lemon/view/cover_reports/yaml.rb +15 -0
- data/lib/lemon/view/test_reports/abstract.rb +149 -0
- data/lib/lemon/view/test_reports/dotprogress.rb +73 -0
- data/lib/lemon/view/test_reports/html.rb +146 -0
- data/lib/lemon/view/test_reports/outline.rb +118 -0
- data/lib/lemon/view/test_reports/summary.rb +131 -0
- data/lib/lemon/view/test_reports/tap.rb +49 -0
- data/lib/lemon/view/test_reports/verbose.rb +197 -0
- data/meta/data.rb +29 -0
- data/meta/gemfile +24 -0
- data/meta/profile +17 -0
- data/test/api/applique/fs.rb +18 -0
- data/test/api/coverage/complete.rdoc +136 -0
- data/test/api/coverage/extensions.rdoc +61 -0
- data/test/api/coverage/incomplete.rdoc +97 -0
- data/{features → test/cli}/coverage.feature +4 -4
- data/{features → test/cli}/generate.feature +2 -2
- data/{features → test/cli}/step_definitions/coverage_steps.rb +0 -0
- data/{features → test/cli}/support/ae.rb +0 -0
- data/{features → test/cli}/support/aruba.rb +0 -0
- data/{features → test/cli}/test.feature +0 -0
- data/test/fixtures/case_complete.rb +17 -4
- data/test/fixtures/case_inclusion.rb +18 -0
- data/test/fixtures/case_incomplete.rb +4 -4
- data/test/fixtures/example.rb +5 -0
- data/test/fixtures/helper.rb +13 -0
- data/test/runner +3 -0
- data/test/unit/case_coverage_analyzer.rb +25 -0
- data/test/unit/case_test_case_dsl.rb +46 -0
- metadata +87 -42
- data/REQUIRE +0 -9
- data/VERSION +0 -6
- data/lib/lemon/command.rb +0 -184
- data/lib/lemon/coverage.rb +0 -260
- data/lib/lemon/coversheet/outline.rb +0 -47
- data/lib/lemon/kernel.rb +0 -24
- data/lib/lemon/reporter.rb +0 -22
- data/lib/lemon/reporter/abstract.rb +0 -97
- data/lib/lemon/reporter/dotprogress.rb +0 -68
- data/lib/lemon/reporter/outline.rb +0 -105
- data/lib/lemon/reporter/verbose.rb +0 -143
- data/lib/lemon/runner.rb +0 -308
- data/lib/lemon/snapshot.rb +0 -185
- data/lib/lemon/test/case.rb +0 -139
- data/lib/lemon/test/concern.rb +0 -52
- data/lib/lemon/test/suite.rb +0 -229
- data/test/case_coverage.rb +0 -26
- data/test/case_testcase.rb +0 -58
@@ -0,0 +1,343 @@
|
|
1
|
+
require 'lemon/model/snapshot'
|
2
|
+
require 'lemon/model/main'
|
3
|
+
|
4
|
+
module Lemon
|
5
|
+
|
6
|
+
#
|
7
|
+
class CoverageAnalyzer
|
8
|
+
|
9
|
+
## New Coverage object.
|
10
|
+
##
|
11
|
+
## Coverage.new('lib/', :MyApp, :public => true)
|
12
|
+
##
|
13
|
+
#def initialize(suite_or_files, namespaces=nil, options={})
|
14
|
+
# @namespaces = namespaces || []
|
15
|
+
# case suite_or_files
|
16
|
+
# when Test::Suite
|
17
|
+
# @suite = suite_or_files
|
18
|
+
# @files = suite_or_files.files
|
19
|
+
# else
|
20
|
+
# @suite = Test::Suite.new(suite_or_files)
|
21
|
+
# @files = suite_or_files
|
22
|
+
# end
|
23
|
+
# #@canonical = @suite.canonical
|
24
|
+
# @public = options[:public]
|
25
|
+
#end
|
26
|
+
|
27
|
+
# New Coverage object.
|
28
|
+
#
|
29
|
+
# CoverageAnalyzer.new(suite, :MyApp, :public => true)
|
30
|
+
#
|
31
|
+
def initialize(files, options={})
|
32
|
+
@files = files
|
33
|
+
|
34
|
+
@namespaces = [options[:namespaces]].flatten.compact
|
35
|
+
@private = options[:private]
|
36
|
+
@format = options[:format]
|
37
|
+
@zealous = options[:zealous]
|
38
|
+
|
39
|
+
@reporter = reporter_find(@format)
|
40
|
+
|
41
|
+
initialize_prerequisites(options)
|
42
|
+
|
43
|
+
@canonical = Snapshot.capture #system #@suite.canonical
|
44
|
+
|
45
|
+
#@suite = Lemon.suite
|
46
|
+
@suite = Lemon::TestSuite.new(files, :cover=>true) #@suite = suite
|
47
|
+
Lemon.suite = @suite
|
48
|
+
|
49
|
+
files = files.map{ |f| Dir[f] }.flatten
|
50
|
+
files = files.map{ |f|
|
51
|
+
if File.directory?(f)
|
52
|
+
Dir[File.join(f, '**/*.rb')]
|
53
|
+
else
|
54
|
+
f
|
55
|
+
end
|
56
|
+
}.flatten.uniq
|
57
|
+
files = files.map{ |f| File.expand_path(f) }
|
58
|
+
|
59
|
+
files.each{ |s| load s } #require s }
|
60
|
+
end
|
61
|
+
|
62
|
+
# Load in prerequisites
|
63
|
+
def initialize_prerequisites(options)
|
64
|
+
loadpath = options[:loadpath] || []
|
65
|
+
requires = options[:requires] || []
|
66
|
+
|
67
|
+
loadpath.each{ |path| $LOAD_PATH.unshift(path) }
|
68
|
+
requires.each{ |path| require(path) }
|
69
|
+
end
|
70
|
+
|
71
|
+
#
|
72
|
+
attr :suite
|
73
|
+
|
74
|
+
# Paths of lemon tests and/or ruby scripts to be compared and covered.
|
75
|
+
# This can include directories too, in which case all .rb scripts below
|
76
|
+
# then directory will be included.
|
77
|
+
attr :files
|
78
|
+
|
79
|
+
## Conical snapshot of system (before loading libraries to be covered).
|
80
|
+
#attr :canonical
|
81
|
+
|
82
|
+
# Report format.
|
83
|
+
attr :format
|
84
|
+
|
85
|
+
#
|
86
|
+
attr :namespaces
|
87
|
+
|
88
|
+
#
|
89
|
+
def canonical
|
90
|
+
@canonical #= Snapshot.capture
|
91
|
+
end
|
92
|
+
|
93
|
+
#
|
94
|
+
def suite=(suite)
|
95
|
+
raise ArgumentError unless TestSuite === suite
|
96
|
+
@suite = suite
|
97
|
+
end
|
98
|
+
|
99
|
+
# Only use public methods for coverage.
|
100
|
+
def public_only?
|
101
|
+
!@private
|
102
|
+
end
|
103
|
+
|
104
|
+
#
|
105
|
+
def private?
|
106
|
+
@private
|
107
|
+
end
|
108
|
+
|
109
|
+
# Include methods of uncovered cases in uncovered units.
|
110
|
+
def zealous?
|
111
|
+
@zealous
|
112
|
+
end
|
113
|
+
|
114
|
+
#
|
115
|
+
def namespaces
|
116
|
+
@namespaces
|
117
|
+
end
|
118
|
+
|
119
|
+
#
|
120
|
+
#def target_units
|
121
|
+
# @target_units ||= target_system.units
|
122
|
+
#end
|
123
|
+
|
124
|
+
|
125
|
+
# Trigger a full set of calculations.
|
126
|
+
def calculate
|
127
|
+
uncovered_cases # that should be all it takes
|
128
|
+
end
|
129
|
+
|
130
|
+
#
|
131
|
+
def covered_units
|
132
|
+
@covered_units ||= (
|
133
|
+
list = []
|
134
|
+
suite.each do |testcase|
|
135
|
+
testcase.testunits.each do |unit|
|
136
|
+
list << Snapshot::Unit.new(
|
137
|
+
unit.testcase.target,
|
138
|
+
unit.target,
|
139
|
+
:function=>unit.function?
|
140
|
+
)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
list.uniq
|
144
|
+
)
|
145
|
+
end
|
146
|
+
|
147
|
+
#
|
148
|
+
def covered_namespaces
|
149
|
+
@covered_namespaces ||= covered_units.map{ |u| u.namespace }.uniq
|
150
|
+
end
|
151
|
+
|
152
|
+
#
|
153
|
+
def target_namespaces
|
154
|
+
@target_namespaces ||= filter(covered_namespaces)
|
155
|
+
end
|
156
|
+
|
157
|
+
# Target system snapshot.
|
158
|
+
def target
|
159
|
+
@target ||= Snapshot.capture(target_namespaces)
|
160
|
+
end
|
161
|
+
|
162
|
+
# Current system snapshot.
|
163
|
+
def current
|
164
|
+
@current ||= Snapshot.capture
|
165
|
+
end
|
166
|
+
|
167
|
+
#
|
168
|
+
def uncovered_units
|
169
|
+
@uncovered_units ||= (
|
170
|
+
units = target.units
|
171
|
+
if public_only?
|
172
|
+
units = units.select{ |u| u.public? }
|
173
|
+
end
|
174
|
+
units -= (covered_units + canonical.units)
|
175
|
+
units += uncovered_system.units if zealous?
|
176
|
+
units
|
177
|
+
)
|
178
|
+
end
|
179
|
+
|
180
|
+
#
|
181
|
+
def undefined_units
|
182
|
+
@undefined_units ||= covered_units - target.units
|
183
|
+
end
|
184
|
+
|
185
|
+
# List of modules/classes not covered.
|
186
|
+
def uncovered_cases
|
187
|
+
@uncovered_cases ||= (
|
188
|
+
list = current.units - (target.units + canonical.units)
|
189
|
+
list = list.map{ |u| u.namespace }.uniq
|
190
|
+
list - canonical_cases
|
191
|
+
)
|
192
|
+
end
|
193
|
+
|
194
|
+
#
|
195
|
+
def uncovered_system
|
196
|
+
@uncovered_system ||= Snapshot.capture(uncovered_cases)
|
197
|
+
end
|
198
|
+
|
199
|
+
#
|
200
|
+
def canonical_cases
|
201
|
+
@canonical_cases ||= canonical.units.map{ |u| u.namespace }.uniq
|
202
|
+
end
|
203
|
+
|
204
|
+
#
|
205
|
+
alias_method :covered, :covered_units
|
206
|
+
alias_method :uncovered, :uncovered_units
|
207
|
+
alias_method :undefined, :undefined_units
|
208
|
+
|
209
|
+
# Reset coverage data for recalcuation.
|
210
|
+
def reset!
|
211
|
+
@covered_units = nil
|
212
|
+
@covered_namespaces = nil
|
213
|
+
@target_namespaces = nil
|
214
|
+
@uncovered_units = nil
|
215
|
+
@undefined_units = nil
|
216
|
+
@target = nil
|
217
|
+
@current = nil
|
218
|
+
end
|
219
|
+
|
220
|
+
# Iterate over covered units.
|
221
|
+
def each(&block)
|
222
|
+
covered_units.each(&block)
|
223
|
+
end
|
224
|
+
|
225
|
+
# Number of covered units.
|
226
|
+
def size
|
227
|
+
covered_units.size
|
228
|
+
end
|
229
|
+
|
230
|
+
# Iterate over +paths+ and use #load to bring in all +.rb+ scripts.
|
231
|
+
#def load_system
|
232
|
+
# files = []
|
233
|
+
# paths.map do |path|
|
234
|
+
# if File.directory?(path)
|
235
|
+
# files.concat(Dir[File.join(path, '**', '*.rb')])
|
236
|
+
# else
|
237
|
+
# files.concat(Dir[path])
|
238
|
+
# end
|
239
|
+
# end
|
240
|
+
# files.each{ |file| load(file) }
|
241
|
+
#end
|
242
|
+
|
243
|
+
# # Snapshot of System to be covered. This takes a current snapshot
|
244
|
+
# # of the system and removes the canonical snapshot or filters out
|
245
|
+
# # everything but the selected namespace.
|
246
|
+
# def system
|
247
|
+
# if namespaces.empty?
|
248
|
+
# snapshot - canonical
|
249
|
+
# else
|
250
|
+
# (snapshot - canonical).filter do |ofmod|
|
251
|
+
# namespaces.any?{ |n| ofmod.name.start_with?(n.to_s) }
|
252
|
+
# end
|
253
|
+
# end
|
254
|
+
# end
|
255
|
+
|
256
|
+
#
|
257
|
+
#def system
|
258
|
+
# if namespaces.empty?
|
259
|
+
# suite.coverage
|
260
|
+
# else
|
261
|
+
# suite.coverage.filter do |ofmod|
|
262
|
+
# namespaces.any?{ |n| ofmod.name.start_with?(n.to_s) }
|
263
|
+
# end
|
264
|
+
# end
|
265
|
+
#end
|
266
|
+
|
267
|
+
private
|
268
|
+
|
269
|
+
#
|
270
|
+
def system(*namespaces)
|
271
|
+
namespaces = nil if namespaces.empty?
|
272
|
+
Snapshot.capture(namespaces)
|
273
|
+
end
|
274
|
+
|
275
|
+
# Get a snapshot of the system.
|
276
|
+
#def snapshot
|
277
|
+
# Snapshot.capture
|
278
|
+
#end
|
279
|
+
|
280
|
+
# Filter namespaces.
|
281
|
+
def filter(ns)
|
282
|
+
return ns if namespaces.nil? or namespaces.empty?
|
283
|
+
#units = units.reject do |u|
|
284
|
+
# /^Lemon::/ =~ u.namespace.to_s
|
285
|
+
#end
|
286
|
+
ns.select do |u|
|
287
|
+
namespaces.any?{ |ns| /^#{ns}(::|$)/ =~ u.namespace.to_s }
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
#
|
292
|
+
def filter_units(units)
|
293
|
+
return units if namespaces.nil? or namespaces.empty?
|
294
|
+
#units = units.reject do |u|
|
295
|
+
# /^Lemon::/ =~ u.namespace.to_s
|
296
|
+
#end
|
297
|
+
units = units.select do |u|
|
298
|
+
namespaces.any? do |ns|
|
299
|
+
/^#{ns}/ =~ u.namespace.to_s
|
300
|
+
end
|
301
|
+
end
|
302
|
+
units
|
303
|
+
end
|
304
|
+
|
305
|
+
public
|
306
|
+
|
307
|
+
#
|
308
|
+
def render
|
309
|
+
reporter.render
|
310
|
+
end
|
311
|
+
|
312
|
+
# All output is handled by a reporter.
|
313
|
+
def reporter
|
314
|
+
@reporter ||= reporter_find(format)
|
315
|
+
end
|
316
|
+
|
317
|
+
private
|
318
|
+
|
319
|
+
DEFAULT_REPORTER = 'compact'
|
320
|
+
|
321
|
+
#
|
322
|
+
def reporter_find(format)
|
323
|
+
format = format ? format.to_s.downcase : DEFAULT_REPORTER
|
324
|
+
format = reporter_list.find do |name|
|
325
|
+
/^#{format}/ =~ name
|
326
|
+
end
|
327
|
+
raise "unsupported format" unless format
|
328
|
+
require "lemon/view/cover_reports/#{format}"
|
329
|
+
reporter = Lemon::CoverReports.const_get(format.capitalize)
|
330
|
+
reporter.new(self)
|
331
|
+
end
|
332
|
+
|
333
|
+
#
|
334
|
+
def reporter_list
|
335
|
+
Dir[File.dirname(__FILE__) + '/../view/cover_reports/*.rb'].map do |rb|
|
336
|
+
File.basename(rb).chomp('.rb')
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
end#class Coverage
|
341
|
+
|
342
|
+
end#module Lemon
|
343
|
+
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'lemon/controller/coverage_analyzer'
|
2
|
+
|
3
|
+
module Lemon
|
4
|
+
|
5
|
+
#
|
6
|
+
class ScaffoldGenerator
|
7
|
+
|
8
|
+
# New Scaffold Generator.
|
9
|
+
#
|
10
|
+
def initialize(files, options={})
|
11
|
+
@files = files
|
12
|
+
|
13
|
+
@coverage = CoverageAnalyzer.new(files, options)
|
14
|
+
@suite = @coverage.suite
|
15
|
+
|
16
|
+
@namespaces = options[:namespaces]
|
17
|
+
@private = options[:private]
|
18
|
+
@uncovered = options[:uncovered]
|
19
|
+
@all = options[:all]
|
20
|
+
end
|
21
|
+
|
22
|
+
# Returns CoverageAnalyzer instance.
|
23
|
+
def coverage
|
24
|
+
@coverage
|
25
|
+
end
|
26
|
+
|
27
|
+
#
|
28
|
+
def namespaces
|
29
|
+
@namespaces
|
30
|
+
end
|
31
|
+
|
32
|
+
#
|
33
|
+
def all?
|
34
|
+
@all
|
35
|
+
end
|
36
|
+
|
37
|
+
#
|
38
|
+
def covered?
|
39
|
+
@covered
|
40
|
+
end
|
41
|
+
|
42
|
+
# Include only uncovered methods.
|
43
|
+
def uncovered?
|
44
|
+
@uncovered
|
45
|
+
end
|
46
|
+
|
47
|
+
# Include private and protected methods.
|
48
|
+
def private?
|
49
|
+
@private
|
50
|
+
end
|
51
|
+
|
52
|
+
# Generate test template(s).
|
53
|
+
def generate
|
54
|
+
if all?
|
55
|
+
generate_all
|
56
|
+
elsif uncovered?
|
57
|
+
generate_uncovered
|
58
|
+
else
|
59
|
+
generate_target
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
#
|
64
|
+
def generate_target
|
65
|
+
render(filter(coverage.target.units))
|
66
|
+
end
|
67
|
+
|
68
|
+
#
|
69
|
+
def generate_uncovered
|
70
|
+
render(filter(coverage.uncovered))
|
71
|
+
end
|
72
|
+
|
73
|
+
# Generate code template.
|
74
|
+
def generate_all
|
75
|
+
render(Snapshot.capture(namespaces).units)
|
76
|
+
end
|
77
|
+
|
78
|
+
#
|
79
|
+
def filter(units)
|
80
|
+
return units if namespaces.nil? or namespaces.empty?
|
81
|
+
units.select do |u|
|
82
|
+
namespaces.any? do |ns|
|
83
|
+
/^#{ns}/ =~ u.namespace.to_s
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Generate code template.
|
89
|
+
def render(units)
|
90
|
+
code = []
|
91
|
+
mods = units.group_by{ |u| u.namespace }
|
92
|
+
mods.each do |mod, units|
|
93
|
+
code << "TestCase #{mod} do"
|
94
|
+
units.each do |unit|
|
95
|
+
next unless private? or unit.public?
|
96
|
+
if unit.function?
|
97
|
+
code << "\n MetaUnit :#{unit.method} => '' do\n\n end"
|
98
|
+
else
|
99
|
+
code << "\n Unit :#{unit.method} => '' do\n\n end"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
code << "\nend\n"
|
103
|
+
end
|
104
|
+
|
105
|
+
code.join("\n")
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|