lemon 0.8.1 → 0.8.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. data/HISTORY.rdoc +15 -0
  2. data/README.rdoc +32 -14
  3. data/bin/lemon +3 -2
  4. data/demo/case_example_fail.rb +15 -0
  5. data/demo/case_example_pass.rb +32 -0
  6. data/demo/case_example_pending.rb +14 -0
  7. data/demo/case_example_untested.rb +10 -0
  8. data/demo/fixture/example-use.rb +5 -0
  9. data/demo/fixture/example.rb +20 -0
  10. data/lib/lemon.rb +2 -2
  11. data/lib/lemon/cli.rb +281 -0
  12. data/lib/lemon/controller/coverage_analyzer.rb +343 -0
  13. data/lib/lemon/controller/scaffold_generator.rb +110 -0
  14. data/lib/lemon/controller/test_runner.rb +284 -0
  15. data/lib/lemon/meta/data.rb +29 -0
  16. data/lib/lemon/meta/gemfile +24 -0
  17. data/{PROFILE → lib/lemon/meta/profile} +6 -5
  18. data/lib/lemon/model/ae.rb +4 -0
  19. data/lib/lemon/model/cover_unit.rb +75 -0
  20. data/lib/lemon/{dsl.rb → model/main.rb} +22 -28
  21. data/lib/lemon/model/pending.rb +10 -0
  22. data/lib/lemon/model/snapshot.rb +203 -0
  23. data/lib/lemon/model/source_parser.rb +198 -0
  24. data/lib/lemon/model/test_case.rb +221 -0
  25. data/lib/lemon/model/test_context.rb +90 -0
  26. data/lib/lemon/model/test_suite.rb +216 -0
  27. data/lib/lemon/{test/unit.rb → model/test_unit.rb} +40 -28
  28. data/lib/lemon/{coversheet → view/cover_reports}/abstract.rb +19 -20
  29. data/lib/lemon/view/cover_reports/compact.rb +37 -0
  30. data/lib/lemon/view/cover_reports/outline.rb +45 -0
  31. data/lib/lemon/view/cover_reports/verbose.rb +51 -0
  32. data/lib/lemon/view/cover_reports/yaml.rb +15 -0
  33. data/lib/lemon/view/test_reports/abstract.rb +149 -0
  34. data/lib/lemon/view/test_reports/dotprogress.rb +73 -0
  35. data/lib/lemon/view/test_reports/html.rb +146 -0
  36. data/lib/lemon/view/test_reports/outline.rb +118 -0
  37. data/lib/lemon/view/test_reports/summary.rb +131 -0
  38. data/lib/lemon/view/test_reports/tap.rb +49 -0
  39. data/lib/lemon/view/test_reports/verbose.rb +197 -0
  40. data/meta/data.rb +29 -0
  41. data/meta/gemfile +24 -0
  42. data/meta/profile +17 -0
  43. data/test/api/applique/fs.rb +18 -0
  44. data/test/api/coverage/complete.rdoc +136 -0
  45. data/test/api/coverage/extensions.rdoc +61 -0
  46. data/test/api/coverage/incomplete.rdoc +97 -0
  47. data/{features → test/cli}/coverage.feature +4 -4
  48. data/{features → test/cli}/generate.feature +2 -2
  49. data/{features → test/cli}/step_definitions/coverage_steps.rb +0 -0
  50. data/{features → test/cli}/support/ae.rb +0 -0
  51. data/{features → test/cli}/support/aruba.rb +0 -0
  52. data/{features → test/cli}/test.feature +0 -0
  53. data/test/fixtures/case_complete.rb +17 -4
  54. data/test/fixtures/case_inclusion.rb +18 -0
  55. data/test/fixtures/case_incomplete.rb +4 -4
  56. data/test/fixtures/example.rb +5 -0
  57. data/test/fixtures/helper.rb +13 -0
  58. data/test/runner +3 -0
  59. data/test/unit/case_coverage_analyzer.rb +25 -0
  60. data/test/unit/case_test_case_dsl.rb +46 -0
  61. metadata +87 -42
  62. data/REQUIRE +0 -9
  63. data/VERSION +0 -6
  64. data/lib/lemon/command.rb +0 -184
  65. data/lib/lemon/coverage.rb +0 -260
  66. data/lib/lemon/coversheet/outline.rb +0 -47
  67. data/lib/lemon/kernel.rb +0 -24
  68. data/lib/lemon/reporter.rb +0 -22
  69. data/lib/lemon/reporter/abstract.rb +0 -97
  70. data/lib/lemon/reporter/dotprogress.rb +0 -68
  71. data/lib/lemon/reporter/outline.rb +0 -105
  72. data/lib/lemon/reporter/verbose.rb +0 -143
  73. data/lib/lemon/runner.rb +0 -308
  74. data/lib/lemon/snapshot.rb +0 -185
  75. data/lib/lemon/test/case.rb +0 -139
  76. data/lib/lemon/test/concern.rb +0 -52
  77. data/lib/lemon/test/suite.rb +0 -229
  78. data/test/case_coverage.rb +0 -26
  79. data/test/case_testcase.rb +0 -58
@@ -1,185 +0,0 @@
1
- module Lemon
2
-
3
- #
4
- class Snapshot
5
- include Enumerable
6
-
7
- #
8
- def self.capture
9
- o = new
10
- o.capture
11
- o
12
- end
13
-
14
- #
15
- attr :modules
16
-
17
- #
18
- def initialize
19
- @modules = {}
20
- end
21
-
22
- #
23
- def each(&block)
24
- modules.values.each(&block)
25
- end
26
-
27
- #
28
- def size
29
- modules.size
30
- end
31
-
32
- #
33
- def [](mod)
34
- @modules[mod]
35
- end
36
-
37
- #
38
- def []=(mod, ofmod)
39
- @modules[mod] = ofmod
40
- end
41
-
42
- #
43
- def capture
44
- @modules = {}
45
- ObjectSpace.each_object(Module) do |mod|
46
- next if mod.name.empty?
47
- @modules[mod] = OfModule.new(mod)
48
- end
49
- end
50
-
51
- #
52
- def to_a(public_only=true)
53
- modules.values.map{ |m| m.to_a(public_only) }.flatten
54
- end
55
-
56
- # Produce a hash based checklist thap mod #.namet Coverage uses
57
- # to compare against tests and create a coverage report.
58
- def checklist(public_only=true)
59
- h = Hash.new{|h,k|h[k]={}}
60
- modules.values.each do |mod|
61
- mod.class_methods(public_only).each do |meth|
62
- h[mod.name]["::#{meth}"] = false
63
- end
64
- mod.instance_methods(public_only).each do |meth|
65
- h[mod.name]["#{meth}"] = false
66
- end
67
- end
68
- h
69
- end
70
-
71
- #
72
- def -(other)
73
- c = Snapshot.new
74
- modules.each do |mod, ofmod|
75
- c[mod] = ofmod.dup
76
- end
77
- other.modules.each do |mod, ofmod|
78
- if c[mod]
79
- c[mod].public_instance_methods -= ofmod.public_instance_methods
80
- c[mod].private_instance_methods -= ofmod.private_instance_methods
81
- c[mod].protected_instance_methods -= ofmod.protected_instance_methods
82
-
83
- c[mod].public_class_methods -= ofmod.public_class_methods
84
- c[mod].private_class_methods -= ofmod.private_class_methods
85
- c[mod].protected_class_methods -= ofmod.protected_class_methods
86
- end
87
- end
88
- c.clean!
89
- return c
90
- end
91
-
92
- #
93
- def <<(other)
94
- other.modules.each do |mod, ofmod|
95
- if self[mod]
96
- self[mod].public_instance_methods += ofmod.public_instance_methods
97
- self[mod].private_instance_methods += ofmod.private_instance_methods
98
- self[mod].protected_instance_methods += ofmod.protected_instance_methods
99
-
100
- self[mod].public_class_methods += ofmod.public_class_methods
101
- self[mod].private_class_methods += ofmod.private_class_methods
102
- self[mod].protected_class_methods += ofmod.protected_class_methods
103
- else
104
- self[mod] = ofmod.dup
105
- end
106
- end
107
- end
108
-
109
- #
110
- def clean!
111
- modules.each do |mod, ofmod|
112
- if ofmod.class_methods(false).empty? && ofmod.instance_methods(false).empty?
113
- modules.delete(mod)
114
- end
115
- end
116
- end
117
-
118
- #
119
- def filter(&block)
120
- c = Snapshot.new
121
- modules.each do |mod, ofmod|
122
- if block.call(ofmod)
123
- c[mod] = ofmod
124
- end
125
- end
126
- c
127
- end
128
-
129
- #
130
- class OfModule
131
- attr :base
132
-
133
- attr_accessor :public_instance_methods
134
- attr_accessor :protected_instance_methods
135
- attr_accessor :private_instance_methods
136
-
137
- attr_accessor :public_class_methods
138
- attr_accessor :protected_class_methods
139
- attr_accessor :private_class_methods
140
-
141
- #
142
- def initialize(base)
143
- @base = base
144
-
145
- @public_instance_methods = base.public_instance_methods(false)
146
- @protected_instance_methods = base.protected_instance_methods(false)
147
- @private_instance_methods = base.private_instance_methods(false)
148
-
149
- @public_class_methods = base.methods(false)
150
- @protected_class_methods = base.protected_methods(false)
151
- @private_class_methods = base.private_methods(false)
152
- end
153
-
154
- #
155
- def name
156
- @base.name
157
- end
158
-
159
- #
160
- def instance_methods(public_only=true)
161
- if public_only
162
- public_instance_methods
163
- else
164
- public_instance_methods + private_instance_methods + protected_instance_methods
165
- end
166
- end
167
-
168
- #
169
- def class_methods(public_only=true)
170
- if public_only
171
- public_class_methods
172
- else
173
- public_class_methods + private_class_methods + protected_class_methods
174
- end
175
- end
176
-
177
- #
178
- def to_a(public_only=true)
179
- class_methods(public_only).map{ |m| "#{name}.#{m}" } + instance_methods(public_only).map{ |m| "#{name}##{m}" }
180
- end
181
- end
182
-
183
- end
184
-
185
- end
@@ -1,139 +0,0 @@
1
- module Lemon::Test
2
-
3
- require 'lemon/test/concern'
4
- require 'lemon/test/unit'
5
-
6
- # Test Case encapsulates a collection of
7
- # unit tests organized into groups of concern.
8
- class Case
9
-
10
- # The test suite to which this testcase belongs.
11
- attr :suite
12
-
13
- # A testcase +target+ is a class or module.
14
- attr :target
15
-
16
- #
17
- attr :testunits
18
-
19
- # List of before procedures that apply case-wide.
20
- attr :before_clauses
21
-
22
- # List of after procedures that apply case-wide.
23
- attr :after_clauses
24
-
25
- # List of concern procedures that apply case-wide.
26
- attr :when_clauses
27
-
28
- # A test case +target+ is a class or module.
29
- def initialize(suite, target, &block)
30
- @suite = suite
31
- @target = target
32
- @testunits = []
33
- @concerns = []
34
- @before_clauses = {}
35
- @after_clauses = {}
36
- @when_clauses = {}
37
- instance_eval(&block)
38
- end
39
-
40
- # Load a helper script applicable to this test case.
41
- def helper(file)
42
- instance_eval(File.read(file), file)
43
- end
44
-
45
- # NOTE: Due to a limitation in Ruby this does not
46
- # provived access to submodules. A hack has been used
47
- # to circumvent. See Suite.const_missing.
48
- def include(*mods)
49
- extend *mods
50
- end
51
-
52
- # Define a new test concern for this case.
53
- # TODO: Probably will deprecate the &setup procedure (YAGNI).
54
- def Concern(*description, &setup)
55
- concern = Concern.new(self, description, &setup)
56
- @concerns << concern
57
- end
58
-
59
- alias_method :concern, :Concern
60
-
61
- # The last defined concern. Used to assign new unit tests.
62
- def current_concern
63
- if @concerns.empty?
64
- @concerns << Concern.new(self)
65
- end
66
- @concerns.last
67
- end
68
-
69
- # Iterate over each test concern.
70
- def each(&block)
71
- @concerns.each(&block)
72
- end
73
-
74
- # Define a unit test for this case.
75
- def Unit(*targets, &block)
76
- targets_hash = Hash===targets.last ? targets.pop : {}
77
- targets_hash.each do |target_method, target_concern|
78
- @testunits << Unit.new(current_concern, target_method, :aspect=>target_concern, &block)
79
- end
80
- targets.each do |target_method|
81
- @testunits << Unit.new(current_concern, target_method, &block)
82
- end
83
- end
84
- alias_method :unit, :Unit
85
-
86
- # Define a meta-method unit test for this case.
87
- def MetaUnit(*targets, &block)
88
- targets_hash = Hash===targets.last ? targets.pop : {}
89
- targets_hash.each do |target_method, target_concern|
90
- @testunits << Unit.new(current_concern, target_method, :aspect=>target_concern, :metaclass=>true, &block)
91
- end
92
- targets.each do |target_method|
93
- @testunits << Unit.new(current_concern, target_method, :metaclass=>true, &block)
94
- end
95
- end
96
- alias_method :metaunit, :MetaUnit
97
-
98
- # Define a before procedure for this case.
99
- def Before(*matches, &block)
100
- matches = [nil] if matches.empty?
101
- matches.each do |match|
102
- @before_clauses[match] = block #<< Advice.new(match, &block)
103
- end
104
- end
105
-
106
- alias_method :before, :Before
107
-
108
- # Define an after procedure for this case.
109
- def After(*matches, &block)
110
- matches = [nil] if matches.empty?
111
- matches.each do |match|
112
- @after_clauses[match] = block #<< Advice.new(match, &block)
113
- end
114
- end
115
-
116
- alias_method :after, :After
117
-
118
- # Define a concern procedure to apply case-wide.
119
- def When(match=nil, &block)
120
- @when_clauses[match] = block #<< Advice.new(match, &block)
121
- end
122
-
123
- #
124
- #def pending
125
- # raise Pending
126
- #end
127
-
128
- #
129
- def to_s
130
- target.to_s.sub(/^\#\<.*?\>::/, '')
131
- end
132
- end
133
-
134
- end
135
-
136
- class Pending < Assertion
137
- def self.to_proc; lambda{ raise self }; end
138
- end
139
-
@@ -1,52 +0,0 @@
1
- module Lemon::Test
2
-
3
- # Test Concerns are used to organize unit tests
4
- # in groups, so as to address specific quality
5
- # assurance objectives.
6
- class Concern
7
-
8
- # The test case to which this concern belongs.
9
- attr :testcase
10
-
11
- # The description of this concern. Make this
12
- # as detailed as you wish.
13
- attr :description
14
-
15
- # Unit tests that belong to this concern.
16
- attr :testunits
17
-
18
- # Setup procedure for concern.
19
- attr :setup
20
-
21
- # New concern.
22
- def initialize(testcase, *description, &setup)
23
- @testcase = testcase
24
- @description = description.join("\n")
25
- @setup = setup
26
- @testunits = []
27
- end
28
-
29
- # Assign a unit test to this concern.
30
- def assign(testunit)
31
- raise ArgumentError unless Unit === testunit
32
- @testunits << testunit
33
- end
34
-
35
- # Iterate through each test unit.
36
- def each(&block)
37
- @testunits.each(&block)
38
- end
39
-
40
- # Returns the description with newlines removed.
41
- def to_s
42
- description.gsub(/\n/, ' ')
43
- end
44
-
45
- #
46
- def call
47
- setup.call if setup
48
- end
49
-
50
- end
51
-
52
- end
@@ -1,229 +0,0 @@
1
- module Lemon
2
- module Test
3
-
4
- require 'lemon/test/case'
5
- require 'lemon/dsl'
6
-
7
- # Test Suites encapsulate a set of test cases.
8
- #
9
- class Suite
10
-
11
- # Files from which the suite is loaded.
12
- attr :files
13
-
14
- # Test cases in this suite.
15
- attr :testcases
16
-
17
- # List of concern procedures that apply suite-wide.
18
- attr :when_clauses
19
-
20
- # List of pre-test procedures that apply suite-wide.
21
- attr :before_clauses
22
-
23
- # List of post-test procedures that apply suite-wide.
24
- attr :after_clauses
25
-
26
- ## A snapshot of the system before the suite is loaded.
27
- #attr :canonical
28
-
29
- # List of files to be covered. This primarily serves
30
- # as a means for allowing one test to load another
31
- # and ensuring converage remains accurate.
32
- #attr :subtest
33
-
34
- def coverage
35
- @final_coveage ||= @coverage - @canonical
36
- end
37
-
38
- #
39
- #attr :options
40
-
41
- #
42
- def initialize(files, options={})
43
- @files = files.flatten
44
- @options = options
45
-
46
- #@subtest = []
47
- @testcases = []
48
- @before_clauses = {}
49
- @after_clauses = {}
50
- @when_clauses = {}
51
-
52
- #load_helpers
53
-
54
- @coverage = Snapshot.new
55
- @canonical = Snapshot.capture
56
-
57
- load_files
58
- #load_subtest_helpers
59
- end
60
-
61
- #
62
- def cover?
63
- @options[:cover]
64
- end
65
-
66
- #
67
- def cover_all?
68
- @options[:cover_all]
69
- end
70
-
71
- #
72
- #def load_helpers(*files)
73
- # helpers = []
74
- # filelist.each do |file|
75
- # dir = File.dirname(file)
76
- # hlp = Dir[File.join(dir, '{test_,}helper.rb')]
77
- # helpers.concat(hlp)
78
- # end
79
- #
80
- # helpers.each do |hlp|
81
- # require hlp
82
- # end
83
- #end
84
-
85
- #def load_subtest_helpers
86
- # helpers = []
87
- # @subtest.each do |file|
88
- # dir = File.dirname(file)
89
- # hlp = Dir[File.join(dir, '{test_,}helper.rb')]
90
- # helpers.concat(hlp)
91
- # end
92
- #
93
- # #s = Snapshot.capture
94
- # helpers.each do |hlp|
95
- # require hlp
96
- # end
97
- # #z = Snapshot.capture
98
- # #d = z - s
99
- # #@canonical << d
100
- #end
101
-
102
- #
103
- def load_files #(*files)
104
- #if cover?
105
- # $stdout << "Load: "
106
- #end
107
-
108
- Lemon.suite = self
109
- filelist.each do |file|
110
- #@current_file = file
111
- #file = File.expand_path(file)
112
- #instance_eval(File.read(file), file)
113
- if cover_all?
114
- Covers(file)
115
- else
116
- require(file) #load(file)
117
- end
118
- end
119
-
120
- #if cover?
121
- # $stdout << "\n"
122
- # $stdout.flush
123
- #end
124
-
125
- return Lemon.suite
126
- end
127
-
128
- # Directories glob *.rb files.
129
- def filelist
130
- @filelist ||= (
131
- @files.flatten.map do |file|
132
- if File.directory?(file)
133
- Dir[File.join(file, '**', '*.rb')]
134
- else
135
- file
136
- end
137
- end.flatten.uniq
138
- )
139
- end
140
-
141
- ## Load a helper. This method must be used when loading local
142
- ## suite support. The usual #require or #load can only be used
143
- ## for extenal support libraries (such as a test mock framework).
144
- ## This is so because suite code is not evaluated at the toplevel.
145
- #def helper(file)
146
- # instance_eval(File.read(file), file)
147
- #end
148
-
149
- #
150
- #def load(file)
151
- # instance_eval(File.read(file), file)
152
- #end
153
-
154
- # Includes at the suite level are routed to the toplevel.
155
- def include(*mods)
156
- TOPLEVEL_BINDING.eval('self').instance_eval do
157
- include(*mods)
158
- end
159
- end
160
-
161
- # Define a test case belonging to this suite.
162
- def Case(target_class, &block)
163
- raise "lemon: case target must be a class or module" unless Module === target_class
164
- testcases << Case.new(self, target_class, &block)
165
- end
166
-
167
- #
168
- alias_method :TestCase, :Case
169
- #alias_method :testcase, :Case
170
-
171
- # Define a pre-test procedure to apply suite-wide.
172
- def Before(match=nil, &block)
173
- @before_clauses[match] = block #<< Advice.new(match, &block)
174
- end
175
-
176
- #alias_method :before, :Before
177
-
178
- # Define a post-test procedure to apply suite-wide.
179
- def After(match=nil, &block)
180
- @after_clauses[match] = block #<< Advice.new(match, &block)
181
- end
182
-
183
- #alias_method :after, :After
184
-
185
- # Define a concern procedure to apply suite-wide.
186
- def When(match=nil, &block)
187
- @when_clauses[match] = block #<< Advice.new(match, &block)
188
- end
189
-
190
- # TODO: need require_find() to avoid first snapshot
191
- def Covers(file)
192
- if cover?
193
- #return if $".include?(file)
194
- s = Snapshot.capture
195
- if require(file)
196
- z = Snapshot.capture
197
- @coverage << (z - s)
198
- end
199
- else
200
- require file
201
- end
202
- end
203
-
204
- #
205
- def Helper(file)
206
- local = File.join(File.dirname(caller[1]), file.to_str + '.rb')
207
- if File.exist?(local)
208
- require local
209
- else
210
- require file
211
- end
212
- end
213
-
214
- #
215
- #def Subtest(file)
216
- # @subtest << file
217
- # require file
218
- #end
219
-
220
- # Iterate through this suite's test cases.
221
- def each(&block)
222
- @testcases.each(&block)
223
- end
224
-
225
- end
226
-
227
- end
228
- end
229
-