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.
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
-