lemon 0.9.0 → 0.9.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.ruby +23 -14
- data/.yardopts +6 -0
- data/Config.rb +14 -0
- data/{HISTORY.rdoc → HISTORY.md} +26 -11
- data/LICENSE.txt +27 -0
- data/README.md +42 -28
- data/SPECSHEET.md +314 -0
- data/bin/{lemonade → lemons} +0 -0
- data/lib/lemon.yml +23 -14
- data/lib/lemon/cli.rb +19 -8
- data/lib/lemon/cli/base.rb +50 -20
- data/lib/lemon/cli/generate.rb +51 -16
- data/lib/lemon/cli/lemon.ascii +84 -0
- data/lib/lemon/cli/obrother.rb +35 -0
- data/lib/lemon/cli/scaffold.rb +116 -0
- data/lib/lemon/core_ext.rb +2 -2
- data/lib/lemon/core_ext/module.rb +9 -0
- data/lib/lemon/coverage/analyzer.rb +76 -5
- data/lib/lemon/coverage/cover_unit.rb +38 -14
- data/lib/lemon/coverage/formats/verbose.rb +1 -1
- data/lib/lemon/coverage/generator.rb +196 -0
- data/lib/lemon/coverage/snapshot.rb +16 -16
- data/lib/lemon/coverage/source_parser.rb +103 -37
- data/lib/lemon/ignore_callers.rb +19 -0
- data/lib/lemon/test_case.rb +135 -26
- data/lib/lemon/test_class.rb +16 -3
- data/lib/lemon/test_class_method.rb +58 -0
- data/lib/lemon/test_method.rb +57 -68
- data/lib/lemon/test_module.rb +47 -44
- data/lib/lemon/test_proc.rb +28 -2
- data/lib/lemon/test_scope.rb +14 -0
- data/lib/lemon/test_setup.rb +1 -1
- data/lib/lemon/test_world.rb +7 -0
- data/{work/deprecated/features/support → spec/applique}/ae.rb +0 -0
- data/spec/coverage/{01_complete.rdoc → 01_complete.md} +3 -3
- data/spec/coverage/{02_incomplete.rdoc → 02_incomplete.md} +2 -2
- data/spec/coverage/{03_extensions.rdoc → 03_extensions.md} +2 -2
- data/try/case_scope.rb +19 -0
- metadata +50 -102
- data/.gemspec +0 -152
- data/.gitignore +0 -8
- data/.reap/digest +0 -678
- data/.reap/test.reap +0 -7
- data/Assembly +0 -37
- data/COPYING.rdoc +0 -33
- data/MANIFEST +0 -55
- data/PROFILE +0 -30
- data/Rakefile +0 -23
- data/VERSION +0 -1
- data/lib/lemon/core_ext/omission.rb +0 -18
- data/lib/lemon/generator.rb +0 -149
- data/notes/2010-05-05-coverage.rdoc +0 -47
- data/notes/2010-05-06-files-not-classes.rdoc +0 -19
- data/notes/2010-07-11-acid-testing.rdoc +0 -52
- data/notes/2010-08-02-enforcing-the-unit.md +0 -68
- data/notes/2010-08-03-new-api.md +0 -37
- data/notes/2011-07-07-nailing-down-the-nomenclature.md +0 -6
- data/site/.rsync-filter +0 -8
- data/site/assets/images/cut-lemon.png +0 -0
- data/site/assets/images/forkme.png +0 -0
- data/site/assets/images/github-logo.png +0 -0
- data/site/assets/images/lemon.jpg +0 -0
- data/site/assets/images/lemon.svg +0 -39
- data/site/assets/images/lemons-are-good.png +0 -0
- data/site/assets/images/opensource.png +0 -0
- data/site/assets/images/ruby-logo.png +0 -0
- data/site/assets/images/skin.jpg +0 -0
- data/site/assets/images/skin1.jpg +0 -0
- data/site/assets/images/tap.png +0 -0
- data/site/assets/images/title.png +0 -0
- data/site/assets/styles/class.css +0 -6
- data/site/assets/styles/reset.css +0 -17
- data/site/assets/styles/site.css +0 -33
- data/site/index.html +0 -218
- data/work/deprecated/command/abstract.rb +0 -29
- data/work/deprecated/command/coverage.rb +0 -115
- data/work/deprecated/command/generate.rb +0 -124
- data/work/deprecated/command/test.rb +0 -112
- data/work/deprecated/cucumber.yml +0 -3
- data/work/deprecated/features/coverage.feature +0 -65
- data/work/deprecated/features/generate.feature +0 -66
- data/work/deprecated/features/step_definitions/coverage_steps.rb +0 -1
- data/work/deprecated/features/support/aruba.rb +0 -1
- data/work/deprecated/features/test.feature +0 -67
- data/work/deprecated/model/dsl/advice.rb +0 -78
- data/work/deprecated/model/dsl/subject.rb +0 -40
- data/work/deprecated/model/main.rb +0 -87
- data/work/deprecated/model/test.rb +0 -54
- data/work/deprecated/model/test_base_dsl.rb +0 -88
- data/work/deprecated/model/test_clause.rb +0 -112
- data/work/deprecated/model/test_context.rb +0 -90
- data/work/deprecated/model/test_feature.rb +0 -128
- data/work/deprecated/model/test_scenario.rb +0 -137
- data/work/deprecated/model/test_suite.rb +0 -297
- data/work/deprecated/rake.rb +0 -103
- data/work/deprecated/test/case_coverage_analyzer.rb +0 -25
- data/work/deprecated/test/case_test_case_dsl.rb +0 -46
- data/work/deprecated/test/fixtures/case_complete.rb +0 -25
- data/work/deprecated/test/fixtures/case_inclusion.rb +0 -18
- data/work/deprecated/test/fixtures/case_incomplete.rb +0 -12
- data/work/deprecated/test/fixtures/example.rb +0 -13
- data/work/deprecated/test/fixtures/helper.rb +0 -13
- data/work/deprecated/test/runner +0 -2
- data/work/old-tests/case_example.rb +0 -15
- data/work/old-tests/feature_example.rb +0 -40
- data/work/reference/dsl2.rb +0 -140
- data/work/reference/dynamic_constant_lookup.rb +0 -76
@@ -0,0 +1,116 @@
|
|
1
|
+
module Lemon
|
2
|
+
|
3
|
+
module CLI
|
4
|
+
|
5
|
+
require 'lemon/cli/generate'
|
6
|
+
require 'fileutils'
|
7
|
+
|
8
|
+
# Scaffold Command
|
9
|
+
class Scaffold < Generate
|
10
|
+
|
11
|
+
# TODO: To be on the safe side, maybe require a --force option in order
|
12
|
+
# to write into a test directory that already has content.
|
13
|
+
|
14
|
+
#
|
15
|
+
# Unlike the Generate command, the Scaffold commnad writes output
|
16
|
+
# to test files.
|
17
|
+
#
|
18
|
+
def generate_output(render_map)
|
19
|
+
render_map.each do |group, test|
|
20
|
+
file = test_file(group)
|
21
|
+
|
22
|
+
if File.exist?(file)
|
23
|
+
append_test(file, test)
|
24
|
+
else
|
25
|
+
write_test(file, test)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
#
|
31
|
+
#
|
32
|
+
#
|
33
|
+
def command_parse(argv)
|
34
|
+
option_parser.banner = "Usage: lemons scaffold [options] [files ...]"
|
35
|
+
setup_options
|
36
|
+
option_parser.parse!(argv)
|
37
|
+
end
|
38
|
+
|
39
|
+
#
|
40
|
+
#
|
41
|
+
#
|
42
|
+
def setup_options
|
43
|
+
option_output
|
44
|
+
option_dryrun
|
45
|
+
super
|
46
|
+
end
|
47
|
+
|
48
|
+
#
|
49
|
+
# Output directory, default is `test`.
|
50
|
+
#
|
51
|
+
def output
|
52
|
+
options[:output] || 'test'
|
53
|
+
end
|
54
|
+
|
55
|
+
#
|
56
|
+
#
|
57
|
+
#
|
58
|
+
def dryrun?
|
59
|
+
options[:dryrun]
|
60
|
+
end
|
61
|
+
|
62
|
+
#
|
63
|
+
# Given the group name, convert it to a suitable test file name.
|
64
|
+
#
|
65
|
+
def test_file(group)
|
66
|
+
if options[:group] == :file
|
67
|
+
file = group
|
68
|
+
else
|
69
|
+
file = group.gsub('::', '/').downcase
|
70
|
+
end
|
71
|
+
|
72
|
+
dirname, basename = File.split(file)
|
73
|
+
|
74
|
+
if i = dirname.index('/')
|
75
|
+
dirname = dirname[i+1..-1]
|
76
|
+
file = File.join(dirname, output, "case_#{basename}")
|
77
|
+
else
|
78
|
+
file = File.join(output, "case_#{basename}")
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
#
|
83
|
+
# Write test file.
|
84
|
+
#
|
85
|
+
def write_test(file, test)
|
86
|
+
return if test.strip.empty?
|
87
|
+
if dryrun?
|
88
|
+
puts "[DRYRUN] write #{file}"
|
89
|
+
else
|
90
|
+
dir = File.dirname(file)
|
91
|
+
FileUtils.mkdir_p(dir) unless File.directory?(dir)
|
92
|
+
File.open(file, 'w'){ |f| f << test.to_s }
|
93
|
+
puts "write #{file}"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
#
|
98
|
+
# Append tests to file.
|
99
|
+
#
|
100
|
+
def append_test(file, test)
|
101
|
+
return if test.strip.empty?
|
102
|
+
if dryrun?
|
103
|
+
puts "[DRYRUN] append #{file}"
|
104
|
+
else
|
105
|
+
dir = File.dirname(file)
|
106
|
+
FileUtils.mkdir_p(dir) unless File.directory?(dir)
|
107
|
+
File.open(file, 'a'){ |f| f << "\n" + test.to_s }
|
108
|
+
puts "append #{file}"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
data/lib/lemon/core_ext.rb
CHANGED
@@ -24,6 +24,7 @@ module Lemon
|
|
24
24
|
# @public = options[:public]
|
25
25
|
#end
|
26
26
|
|
27
|
+
#
|
27
28
|
# New Coverage object.
|
28
29
|
#
|
29
30
|
# CoverageAnalyzer.new(suite, :MyApp, :public => true)
|
@@ -63,7 +64,9 @@ module Lemon
|
|
63
64
|
@suite = $TEST_SUITE.dup
|
64
65
|
end
|
65
66
|
|
67
|
+
#
|
66
68
|
# Load in prerequisites
|
69
|
+
#
|
67
70
|
def initialize_prerequisites(options)
|
68
71
|
loadpath = [options[:loadpath] || []].compact.flatten
|
69
72
|
requires = [options[:requires] || []].compact.flatten
|
@@ -72,56 +75,80 @@ module Lemon
|
|
72
75
|
requires.each{ |path| require(path) }
|
73
76
|
end
|
74
77
|
|
78
|
+
#
|
79
|
+
#
|
75
80
|
#
|
76
81
|
def reset_suite
|
77
82
|
$TEST_SUITE = []
|
78
83
|
end
|
79
84
|
|
85
|
+
#
|
86
|
+
#
|
80
87
|
#
|
81
88
|
def suite
|
82
89
|
@suite
|
83
90
|
end
|
84
91
|
|
92
|
+
#
|
85
93
|
# Paths of lemon tests and/or ruby scripts to be compared and covered.
|
86
94
|
# This can include directories too, in which case all .rb scripts below
|
87
95
|
# then directory will be included.
|
96
|
+
#
|
88
97
|
attr :files
|
89
98
|
|
90
|
-
|
91
|
-
#attr :canonical
|
92
|
-
|
99
|
+
#
|
93
100
|
# Report format.
|
101
|
+
#
|
94
102
|
attr :format
|
95
103
|
|
104
|
+
#
|
105
|
+
#
|
96
106
|
#
|
97
107
|
attr :namespaces
|
98
108
|
|
109
|
+
#
|
110
|
+
## Conical snapshot of system (before loading libraries to be covered).
|
111
|
+
#
|
112
|
+
#attr :canonical
|
113
|
+
|
114
|
+
#
|
115
|
+
#
|
99
116
|
#
|
100
117
|
def canonical
|
101
118
|
@canonical #= Snapshot.capture
|
102
119
|
end
|
103
120
|
|
121
|
+
#
|
122
|
+
#
|
104
123
|
#
|
105
124
|
def suite=(suite)
|
106
125
|
raise ArgumentError unless TestSuite === suite
|
107
126
|
@suite = suite
|
108
127
|
end
|
109
128
|
|
129
|
+
#
|
110
130
|
# Only use public methods for coverage.
|
131
|
+
#
|
111
132
|
def public_only?
|
112
133
|
!@private
|
113
134
|
end
|
114
135
|
|
136
|
+
#
|
137
|
+
#
|
115
138
|
#
|
116
139
|
def private?
|
117
140
|
@private
|
118
141
|
end
|
119
142
|
|
143
|
+
#
|
120
144
|
# Include methods of uncovered cases in uncovered units.
|
145
|
+
#
|
121
146
|
def zealous?
|
122
147
|
@zealous
|
123
148
|
end
|
124
149
|
|
150
|
+
#
|
151
|
+
#
|
125
152
|
#
|
126
153
|
def namespaces
|
127
154
|
@namespaces
|
@@ -138,6 +165,8 @@ module Lemon
|
|
138
165
|
uncovered_cases # that should be all it takes
|
139
166
|
end
|
140
167
|
|
168
|
+
#
|
169
|
+
#
|
141
170
|
#
|
142
171
|
def covered_units
|
143
172
|
@covered_units ||= (
|
@@ -149,6 +178,8 @@ module Lemon
|
|
149
178
|
)
|
150
179
|
end
|
151
180
|
|
181
|
+
#
|
182
|
+
#
|
152
183
|
#
|
153
184
|
def covered_unit(test, list)
|
154
185
|
case test
|
@@ -160,33 +191,43 @@ module Lemon
|
|
160
191
|
list << Snapshot::Unit.new(
|
161
192
|
test.context.target,
|
162
193
|
test.target,
|
163
|
-
:
|
164
|
-
)
|
194
|
+
:singleton=>test.class_method?
|
195
|
+
)
|
165
196
|
else
|
166
197
|
# ignore
|
167
198
|
end
|
168
199
|
end
|
169
200
|
|
201
|
+
#
|
202
|
+
#
|
170
203
|
#
|
171
204
|
def covered_namespaces
|
172
205
|
@covered_namespaces ||= covered_units.map{ |u| u.namespace }.uniq
|
173
206
|
end
|
174
207
|
|
208
|
+
#
|
209
|
+
#
|
175
210
|
#
|
176
211
|
def target_namespaces
|
177
212
|
@target_namespaces ||= filter(covered_namespaces)
|
178
213
|
end
|
179
214
|
|
215
|
+
#
|
180
216
|
# Target system snapshot.
|
217
|
+
#
|
181
218
|
def target
|
182
219
|
@target ||= Snapshot.capture(target_namespaces)
|
183
220
|
end
|
184
221
|
|
222
|
+
#
|
185
223
|
# Current system snapshot.
|
224
|
+
#
|
186
225
|
def current
|
187
226
|
@current ||= Snapshot.capture
|
188
227
|
end
|
189
228
|
|
229
|
+
#
|
230
|
+
#
|
190
231
|
#
|
191
232
|
def uncovered_units
|
192
233
|
@uncovered_units ||= (
|
@@ -200,12 +241,16 @@ module Lemon
|
|
200
241
|
)
|
201
242
|
end
|
202
243
|
|
244
|
+
#
|
245
|
+
#
|
203
246
|
#
|
204
247
|
def undefined_units
|
205
248
|
@undefined_units ||= covered_units - target.units
|
206
249
|
end
|
207
250
|
|
251
|
+
#
|
208
252
|
# List of modules/classes not covered.
|
253
|
+
#
|
209
254
|
def uncovered_cases
|
210
255
|
@uncovered_cases ||= (
|
211
256
|
list = current.units - (target.units + canonical.units)
|
@@ -214,22 +259,30 @@ module Lemon
|
|
214
259
|
)
|
215
260
|
end
|
216
261
|
|
262
|
+
#
|
263
|
+
#
|
217
264
|
#
|
218
265
|
def uncovered_system
|
219
266
|
@uncovered_system ||= Snapshot.capture(uncovered_cases)
|
220
267
|
end
|
221
268
|
|
269
|
+
#
|
270
|
+
#
|
222
271
|
#
|
223
272
|
def canonical_cases
|
224
273
|
@canonical_cases ||= canonical.units.map{ |u| u.namespace }.uniq
|
225
274
|
end
|
226
275
|
|
276
|
+
#
|
277
|
+
#
|
227
278
|
#
|
228
279
|
alias_method :covered, :covered_units
|
229
280
|
alias_method :uncovered, :uncovered_units
|
230
281
|
alias_method :undefined, :undefined_units
|
231
282
|
|
283
|
+
#
|
232
284
|
# Reset coverage data for recalcuation.
|
285
|
+
#
|
233
286
|
def reset!
|
234
287
|
@covered_units = nil
|
235
288
|
@covered_namespaces = nil
|
@@ -240,12 +293,16 @@ module Lemon
|
|
240
293
|
@current = nil
|
241
294
|
end
|
242
295
|
|
296
|
+
#
|
243
297
|
# Iterate over covered units.
|
298
|
+
#
|
244
299
|
def each(&block)
|
245
300
|
covered_units.each(&block)
|
246
301
|
end
|
247
302
|
|
303
|
+
#
|
248
304
|
# Number of covered units.
|
305
|
+
#
|
249
306
|
def size
|
250
307
|
covered_units.size
|
251
308
|
end
|
@@ -289,6 +346,8 @@ module Lemon
|
|
289
346
|
|
290
347
|
private
|
291
348
|
|
349
|
+
#
|
350
|
+
#
|
292
351
|
#
|
293
352
|
def system(*namespaces)
|
294
353
|
namespaces = nil if namespaces.empty?
|
@@ -300,7 +359,9 @@ module Lemon
|
|
300
359
|
# Snapshot.capture
|
301
360
|
#end
|
302
361
|
|
362
|
+
#
|
303
363
|
# Filter namespaces.
|
364
|
+
#
|
304
365
|
def filter(ns)
|
305
366
|
return ns if namespaces.nil? or namespaces.empty?
|
306
367
|
#units = units.reject do |u|
|
@@ -311,6 +372,8 @@ module Lemon
|
|
311
372
|
end
|
312
373
|
end
|
313
374
|
|
375
|
+
#
|
376
|
+
#
|
314
377
|
#
|
315
378
|
def filter_units(units)
|
316
379
|
return units if namespaces.nil? or namespaces.empty?
|
@@ -327,12 +390,16 @@ module Lemon
|
|
327
390
|
|
328
391
|
public
|
329
392
|
|
393
|
+
#
|
394
|
+
#
|
330
395
|
#
|
331
396
|
def render
|
332
397
|
reporter.render
|
333
398
|
end
|
334
399
|
|
400
|
+
#
|
335
401
|
# All output is handled by a reporter.
|
402
|
+
#
|
336
403
|
def reporter
|
337
404
|
@reporter ||= reporter_find(format)
|
338
405
|
end
|
@@ -341,6 +408,8 @@ module Lemon
|
|
341
408
|
|
342
409
|
DEFAULT_REPORTER = 'compact'
|
343
410
|
|
411
|
+
#
|
412
|
+
#
|
344
413
|
#
|
345
414
|
def reporter_find(format)
|
346
415
|
format = format ? format.to_s.downcase : DEFAULT_REPORTER
|
@@ -353,6 +422,8 @@ module Lemon
|
|
353
422
|
reporter.new(self)
|
354
423
|
end
|
355
424
|
|
425
|
+
#
|
426
|
+
#
|
356
427
|
#
|
357
428
|
def reporter_list
|
358
429
|
Dir[File.dirname(__FILE__) + '/formats/*.rb'].map do |rb|
|
@@ -5,45 +5,60 @@ module Lemon
|
|
5
5
|
class CoverUnit
|
6
6
|
|
7
7
|
attr :target
|
8
|
+
|
8
9
|
attr :method
|
9
|
-
attr :function
|
10
10
|
|
11
|
+
attr :singleton
|
12
|
+
|
13
|
+
#
|
11
14
|
def initialize(target, method, props={})
|
12
|
-
@target
|
13
|
-
@method
|
14
|
-
@
|
15
|
-
@
|
15
|
+
@target = target
|
16
|
+
@method = method.to_sym
|
17
|
+
@covered = props[:covered]
|
18
|
+
@singleton = props[:singleton] ? true : false
|
16
19
|
|
17
|
-
if @
|
20
|
+
if @singleton
|
18
21
|
@private = !@target.public_methods.find{ |m| m.to_sym == @method }
|
19
22
|
else
|
20
23
|
@private = !@target.public_instance_methods.find{ |m| m.to_sym == @method }
|
21
24
|
end
|
22
25
|
end
|
23
26
|
|
27
|
+
#
|
24
28
|
# Method access is private or protected?
|
29
|
+
#
|
25
30
|
def private?
|
26
31
|
@private
|
27
32
|
end
|
28
33
|
|
34
|
+
#
|
29
35
|
# Marked as covered?
|
36
|
+
#
|
30
37
|
def covered?
|
31
38
|
@covered
|
32
39
|
end
|
33
40
|
|
34
41
|
#
|
35
|
-
|
36
|
-
|
42
|
+
#
|
43
|
+
#
|
44
|
+
def singleton?
|
45
|
+
@singleton
|
37
46
|
end
|
38
47
|
|
48
|
+
alias class_method? singleton?
|
49
|
+
|
50
|
+
#
|
51
|
+
#
|
39
52
|
#
|
40
53
|
def hash
|
41
|
-
@target.hash ^ @method.hash ^
|
54
|
+
@target.hash ^ @method.hash ^ singleton.hash
|
42
55
|
end
|
43
56
|
|
57
|
+
#
|
58
|
+
#
|
44
59
|
#
|
45
60
|
def to_s
|
46
|
-
if
|
61
|
+
if singleton?
|
47
62
|
"#{@target}.#{@method}"
|
48
63
|
else
|
49
64
|
"#{@target}##{@method}"
|
@@ -51,23 +66,32 @@ module Lemon
|
|
51
66
|
end
|
52
67
|
alias to_str to_s
|
53
68
|
|
69
|
+
#
|
70
|
+
#
|
71
|
+
#
|
54
72
|
def eql?(other)
|
55
73
|
return false unless Unit === other
|
56
74
|
return false unless target == other.target
|
57
75
|
return false unless method == other.method
|
58
|
-
return false unless
|
76
|
+
return false unless singleton == other.singleton
|
59
77
|
return true
|
60
78
|
end
|
61
79
|
|
80
|
+
#
|
81
|
+
#
|
82
|
+
#
|
62
83
|
def inspect
|
63
|
-
"#{target}#{
|
84
|
+
"#{target}#{singleton? ? '.' : '#'}#{method}"
|
64
85
|
end
|
65
86
|
|
87
|
+
#
|
88
|
+
#
|
89
|
+
#
|
66
90
|
def <=>(other)
|
67
91
|
c = (target.name <=> other.target.name)
|
68
92
|
return c unless c == 0
|
69
|
-
return -1 if
|
70
|
-
return 1 if !
|
93
|
+
return -1 if singleton && !other.singleton
|
94
|
+
return 1 if !singleton && other.singleton
|
71
95
|
method.to_s <=> other.method.to_s
|
72
96
|
end
|
73
97
|
end
|