lemon 0.9.0 → 0.9.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 (118) hide show
  1. checksums.yaml +7 -0
  2. data/{HISTORY.rdoc → HISTORY.md} +42 -11
  3. data/LICENSE.txt +27 -0
  4. data/README.md +48 -34
  5. data/{spec/coverage/01_complete.rdoc → demo/coverage/01_complete.md} +3 -3
  6. data/{spec/coverage/02_incomplete.rdoc → demo/coverage/02_incomplete.md} +2 -2
  7. data/{spec/coverage/03_extensions.rdoc → demo/coverage/03_extensions.md} +2 -2
  8. data/lib/lemon/cli/base.rb +50 -20
  9. data/lib/lemon/cli/generate.rb +51 -16
  10. data/lib/lemon/cli/lemon.ascii +84 -0
  11. data/lib/lemon/cli/obrother.rb +35 -0
  12. data/lib/lemon/cli/scaffold.rb +116 -0
  13. data/lib/lemon/cli.rb +19 -8
  14. data/lib/lemon/core_ext/module.rb +9 -0
  15. data/lib/lemon/core_ext.rb +2 -2
  16. data/lib/lemon/coverage/analyzer.rb +76 -5
  17. data/lib/lemon/coverage/cover_unit.rb +38 -14
  18. data/lib/lemon/coverage/formats/verbose.rb +1 -1
  19. data/lib/lemon/coverage/generator.rb +196 -0
  20. data/lib/lemon/coverage/snapshot.rb +16 -16
  21. data/lib/lemon/coverage/source_parser.rb +103 -37
  22. data/lib/lemon/ignore_callers.rb +19 -0
  23. data/lib/lemon/test_case.rb +135 -26
  24. data/lib/lemon/test_class.rb +16 -3
  25. data/lib/lemon/test_class_method.rb +58 -0
  26. data/lib/lemon/test_method.rb +57 -68
  27. data/lib/lemon/test_module.rb +47 -44
  28. data/lib/lemon/test_proc.rb +28 -2
  29. data/lib/lemon/test_scope.rb +14 -0
  30. data/lib/lemon/test_setup.rb +1 -1
  31. data/lib/lemon/test_world.rb +7 -0
  32. data/lib/lemon.rb +1 -15
  33. metadata +71 -147
  34. data/.gemspec +0 -152
  35. data/.gitignore +0 -8
  36. data/.reap/digest +0 -678
  37. data/.reap/test.reap +0 -7
  38. data/.ruby +0 -49
  39. data/Assembly +0 -37
  40. data/COPYING.rdoc +0 -33
  41. data/MANIFEST +0 -55
  42. data/PROFILE +0 -30
  43. data/Rakefile +0 -23
  44. data/VERSION +0 -1
  45. data/lib/lemon/core_ext/omission.rb +0 -18
  46. data/lib/lemon/generator.rb +0 -149
  47. data/lib/lemon.yml +0 -49
  48. data/notes/2010-05-05-coverage.rdoc +0 -47
  49. data/notes/2010-05-06-files-not-classes.rdoc +0 -19
  50. data/notes/2010-07-11-acid-testing.rdoc +0 -52
  51. data/notes/2010-08-02-enforcing-the-unit.md +0 -68
  52. data/notes/2010-08-03-new-api.md +0 -37
  53. data/notes/2011-07-07-nailing-down-the-nomenclature.md +0 -6
  54. data/site/.rsync-filter +0 -8
  55. data/site/assets/images/cut-lemon.png +0 -0
  56. data/site/assets/images/forkme.png +0 -0
  57. data/site/assets/images/github-logo.png +0 -0
  58. data/site/assets/images/lemon.jpg +0 -0
  59. data/site/assets/images/lemon.svg +0 -39
  60. data/site/assets/images/lemons-are-good.png +0 -0
  61. data/site/assets/images/opensource.png +0 -0
  62. data/site/assets/images/ruby-logo.png +0 -0
  63. data/site/assets/images/skin.jpg +0 -0
  64. data/site/assets/images/skin1.jpg +0 -0
  65. data/site/assets/images/tap.png +0 -0
  66. data/site/assets/images/title.png +0 -0
  67. data/site/assets/styles/class.css +0 -6
  68. data/site/assets/styles/reset.css +0 -17
  69. data/site/assets/styles/site.css +0 -33
  70. data/site/index.html +0 -218
  71. data/try/.test +0 -8
  72. data/try/case_error.rb +0 -18
  73. data/try/case_fail.rb +0 -19
  74. data/try/case_pass.rb +0 -42
  75. data/try/case_pending.rb +0 -18
  76. data/try/case_singleton.rb +0 -18
  77. data/try/case_untested.rb +0 -14
  78. data/try/fixtures/calculator.rb +0 -15
  79. data/try/fixtures/example-use.rb +0 -5
  80. data/try/fixtures/example.rb +0 -20
  81. data/try/helpers/loadpath.rb +0 -1
  82. data/work/deprecated/command/abstract.rb +0 -29
  83. data/work/deprecated/command/coverage.rb +0 -115
  84. data/work/deprecated/command/generate.rb +0 -124
  85. data/work/deprecated/command/test.rb +0 -112
  86. data/work/deprecated/cucumber.yml +0 -3
  87. data/work/deprecated/features/coverage.feature +0 -65
  88. data/work/deprecated/features/generate.feature +0 -66
  89. data/work/deprecated/features/step_definitions/coverage_steps.rb +0 -1
  90. data/work/deprecated/features/support/aruba.rb +0 -1
  91. data/work/deprecated/features/test.feature +0 -67
  92. data/work/deprecated/model/dsl/advice.rb +0 -78
  93. data/work/deprecated/model/dsl/subject.rb +0 -40
  94. data/work/deprecated/model/main.rb +0 -87
  95. data/work/deprecated/model/test.rb +0 -54
  96. data/work/deprecated/model/test_base_dsl.rb +0 -88
  97. data/work/deprecated/model/test_clause.rb +0 -112
  98. data/work/deprecated/model/test_context.rb +0 -90
  99. data/work/deprecated/model/test_feature.rb +0 -128
  100. data/work/deprecated/model/test_scenario.rb +0 -137
  101. data/work/deprecated/model/test_suite.rb +0 -297
  102. data/work/deprecated/rake.rb +0 -103
  103. data/work/deprecated/test/case_coverage_analyzer.rb +0 -25
  104. data/work/deprecated/test/case_test_case_dsl.rb +0 -46
  105. data/work/deprecated/test/fixtures/case_complete.rb +0 -25
  106. data/work/deprecated/test/fixtures/case_inclusion.rb +0 -18
  107. data/work/deprecated/test/fixtures/case_incomplete.rb +0 -12
  108. data/work/deprecated/test/fixtures/example.rb +0 -13
  109. data/work/deprecated/test/fixtures/helper.rb +0 -13
  110. data/work/deprecated/test/runner +0 -2
  111. data/work/old-tests/case_example.rb +0 -15
  112. data/work/old-tests/feature_example.rb +0 -40
  113. data/work/reference/dsl2.rb +0 -140
  114. data/work/reference/dynamic_constant_lookup.rb +0 -76
  115. /data/bin/{lemonade → lemons} +0 -0
  116. /data/{work/deprecated/features/support → demo/applique}/ae.rb +0 -0
  117. /data/{spec → demo}/applique/fs.rb +0 -0
  118. /data/{spec → demo}/coverage/applique/lemon.rb +0 -0
@@ -2,6 +2,7 @@ require 'lemon/core_ext'
2
2
  require 'lemon/test_advice'
3
3
  require 'lemon/test_setup'
4
4
  require 'lemon/test_world'
5
+ require 'lemon/test_scope'
5
6
 
6
7
  module Lemon
7
8
 
@@ -32,6 +33,7 @@ module Lemon
32
33
  # Skip execution of test case?
33
34
  attr :skip
34
35
 
36
+ #
35
37
  # A test case +target+ is a class or module.
36
38
  #
37
39
  # @param [Hash] settings
@@ -59,58 +61,88 @@ module Lemon
59
61
  @label = settings[:label]
60
62
  @setup = settings[:setup]
61
63
  @skip = settings[:skip]
64
+ @tags = settings[:tags]
62
65
 
63
66
  @advice = @context ? @context.advice.dup : TestAdvice.new
64
67
 
65
68
  @tests = []
66
- @scope = scope_class.new(self)
69
+ @domain = domain_class.new(self)
67
70
 
68
71
  validate_settings
69
72
 
70
73
  evaluate(&block)
71
74
  end
72
75
 
76
+ #
73
77
  # Subclasses can override this methof to validate settings.
74
78
  # It is run just before evaluation of scope block.
79
+ #
75
80
  def validate_settings
76
81
  end
77
82
 
83
+ #
84
+ def domain
85
+ @domain
86
+ end
87
+
88
+ #
89
+ #
78
90
  #
79
91
  def evaluate(&block)
80
- @scope.module_eval(&block)
92
+ @domain.module_eval(&block)
81
93
  end
82
94
 
95
+ #
83
96
  # Iterate over each test and subcase.
97
+ #
84
98
  def each(&block)
85
99
  tests.each(&block)
86
100
  end
87
101
 
102
+ #
88
103
  # Number of tests and subcases.
104
+ #
89
105
  def size
90
106
  tests.size
91
107
  end
92
108
 
109
+ #
93
110
  # Subclasses of TestCase can override this to describe
94
111
  # the type of test case they define.
112
+ #
95
113
  def type
96
- 'Case'
114
+ 'Test Case'
97
115
  end
98
116
 
117
+ #
118
+ #
99
119
  #
100
120
  def to_s
101
121
  @label.to_s
102
122
  end
103
123
 
124
+ #
125
+ #
104
126
  #
105
127
  def skip?
106
128
  @skip
107
129
  end
108
130
 
131
+ #
132
+ #
109
133
  #
110
134
  def skip!(reason=true)
111
135
  @skip = reason
112
136
  end
113
137
 
138
+ #
139
+ #
140
+ #
141
+ def tags
142
+ @tags
143
+ end
144
+
145
+ #
114
146
  # Run test in the context of this case.
115
147
  #
116
148
  # @param [TestProc] test
@@ -132,48 +164,47 @@ module Lemon
132
164
  end
133
165
  end
134
166
 
167
+ #
135
168
  # Module for evaluating test case script.
136
169
  #
137
170
  # @return [Scope] evaluation scope
171
+ #
138
172
  def scope
139
- @scope
173
+ @scope ||= TestScope.new(self)
140
174
  end
141
175
 
142
- # Get the scope class dynamically so that each subclass
176
+ #
177
+ # Get the domain class dynamically so that each subclass
143
178
  # of TestCase will retrieve it's own.
144
- def scope_class
145
- self.class.const_get(:Scope)
179
+ #
180
+ def domain_class
181
+ self.class.const_get(:DSL)
146
182
  end
147
183
 
148
184
  #
149
- class Scope < World
185
+ class DSL < World
186
+
187
+ #
188
+ # The class for which this is a DSL context.
189
+ #
190
+ def context_class
191
+ TestCase
192
+ end
150
193
 
194
+ #
195
+ #
151
196
  #
152
197
  def initialize(testcase) #, &code)
153
198
  @_testcase = testcase
154
199
  @_setup = testcase.setup
155
200
  @_skip = nil
156
201
 
157
- extend testcase.context.scope if testcase.context
202
+ include testcase.context.domain if testcase.context
158
203
 
159
204
  #module_eval(&code)
160
205
  end
161
206
 
162
- #--
163
- # THINK: Instead of resuing TestCase can we have a TestContext
164
- # or other way to more generically mimics the parent context?
165
- #++
166
-
167
- ##
168
- #def context(label, &block)
169
- # @_testcase.tests << TestCase.new(
170
- # :testcase => @testcase,
171
- # :label => label,
172
- # &block
173
- # )
174
- #end
175
- #alias :Context :context
176
-
207
+ #
177
208
  # Setup is used to set things up for each unit test.
178
209
  # The setup procedure is run before each unit.
179
210
  #
@@ -187,10 +218,13 @@ module Lemon
187
218
  end
188
219
  alias :Setup :setup
189
220
 
221
+ #
190
222
  # Original Lemon nomenclature for `#setup`.
223
+ #
191
224
  alias :concern :setup
192
225
  alias :Concern :setup
193
226
 
227
+ #
194
228
  # Teardown procedure is used to clean-up after each unit test.
195
229
  #
196
230
  def teardown(&procedure)
@@ -198,11 +232,10 @@ module Lemon
198
232
  end
199
233
  alias :Teardown :teardown
200
234
 
201
- #--
202
235
  # TODO: Allow Before and After to handle setup and teardown?
203
236
  # But that would only allow one setup per case.
204
- #++
205
237
 
238
+ #
206
239
  # Define a _complex_ before procedure. The #before method allows
207
240
  # before procedures to be defined that are triggered by a match
208
241
  # against the unit's target method name or _aspect_ description.
@@ -233,6 +266,7 @@ module Lemon
233
266
  end
234
267
  alias :Before :before
235
268
 
269
+ #
236
270
  # Define a _complex_ after procedure. The #before method allows
237
271
  # before procedures to be defined that are triggered by a match
238
272
  # against the unit's target method name or _aspect_ description.
@@ -263,6 +297,81 @@ module Lemon
263
297
  end
264
298
  alias :After :after
265
299
 
300
+ # THINK: Instead of resuing TestCase can we have a TestContext
301
+ # or other way to more generically mimics the parent context?
302
+
303
+ #
304
+ # Create a subcase of module testcase.
305
+ #
306
+ def context(label, *tags, &block)
307
+ return if @_omit
308
+
309
+ @_testcase.tests << context_class.new(
310
+ :context => @_testcase,
311
+ :target => @_testcase.target,
312
+ :setup => @_setup,
313
+ :skip => @_skip,
314
+ :label => label,
315
+ :tags => tags,
316
+ &block
317
+ )
318
+ end
319
+ alias :Context :context
320
+
321
+ #
322
+ # Skip tests. Unlike omit, skipped tests are passed to the test harness,
323
+ # so they still can be included in reports, though they are not executed.
324
+ #
325
+ # If a block is given then only tests defined with-in the block are skipped.
326
+ # If no block is given then all subsquent tests in the test case are skipped.
327
+ #
328
+ # @param [String,Boolean] reason
329
+ # A description of the reason to skip the test, or simply a boolean value.
330
+ #
331
+ # @example
332
+ # skip "reason" do
333
+ # test do
334
+ # ...
335
+ # end
336
+ # end
337
+ #
338
+ def skip(reason=true)
339
+ if block_given?
340
+ @_skip = reason
341
+ yield
342
+ @_skip = nil
343
+ else
344
+ @_skip = reason
345
+ end
346
+ end
347
+ alias :Skip :skip
348
+
349
+ #
350
+ # Omitted tests are simply ignored and never instantiated let alone passed
351
+ # on to the test harness.
352
+ #
353
+ # If a block is given then only tests defined with-in the block are skipped.
354
+ # If no block is given then all subsquent tests in the test case are skipped.
355
+ #
356
+ #
357
+ # @example
358
+ # omit do
359
+ # test do
360
+ # ...
361
+ # end
362
+ # end
363
+ #
364
+ def omit(reason=true)
365
+ if block_given?
366
+ @_omit = reason
367
+ yield
368
+ @_omit = nil
369
+ else
370
+ @_omit = reason
371
+ end
372
+ end
373
+ alias :Omit :omit
374
+
266
375
  end
267
376
 
268
377
  end
@@ -9,18 +9,31 @@ module Lemon
9
9
 
10
10
  private
11
11
 
12
+ #
12
13
  # Make sure the target is a class.
13
- def validate_target
14
- raise unless Class === @target
14
+ #
15
+ def validate_settings
16
+ raise "#{@target} is not a module" unless Class === @target
15
17
  end
16
18
 
19
+ #
17
20
  # The type of testcase.
21
+ #
18
22
  def type
19
23
  'Class'
20
24
  end
21
25
 
22
26
  # Evaluation scope for {TestClass}.
23
- class Scope < TestModule::Scope
27
+ #
28
+ class DSL < TestModule::DSL
29
+
30
+ #
31
+ # The class for which this is a DSL context.
32
+ #
33
+ def context_class
34
+ TestClass
35
+ end
36
+
24
37
  end
25
38
 
26
39
  end
@@ -0,0 +1,58 @@
1
+ module Lemon
2
+
3
+ require 'lemon/test_method'
4
+
5
+ # Subclass of TestMethod used for class methods.
6
+ # It's basically the same class.
7
+ #
8
+ class TestClassMethod < TestMethod
9
+
10
+ # Description of the type of test case.
11
+ def type
12
+ 'Class Method'
13
+ end
14
+
15
+ # If class method, returns target method's name prefixed with double colons.
16
+ # If instance method, then returns target method's name prefixed with hash
17
+ # character.
18
+ def name
19
+ "::#{target}"
20
+ end
21
+
22
+ # Returns the prefixed method name.
23
+ def to_s
24
+ "::#{target}"
25
+ end
26
+
27
+ # Returns the fully qulaified name of the target method. This is
28
+ # the standard interface used by RubyTest.
29
+ def unit
30
+ "#{context}.#{target}"
31
+ end
32
+
33
+ # For a class method, the target class is the meta-class.
34
+ def target_class
35
+ @target_class ||= (class << context.target; self; end)
36
+ end
37
+
38
+ #
39
+ def class_method?
40
+ true
41
+ end
42
+
43
+ # Scope for evaluating class method test definitions.
44
+ #
45
+ class DSL < TestMethod::DSL
46
+
47
+ #
48
+ # The class for which this is a DSL context.
49
+ #
50
+ def context_class
51
+ TestClassMethod
52
+ end
53
+
54
+ end
55
+
56
+ end
57
+
58
+ end
@@ -8,64 +8,62 @@ module Lemon
8
8
  #
9
9
  class TestMethod < TestCase
10
10
 
11
- # New unit test.
12
11
  #
13
- # @option settings [Boolean] :function
14
- # Is the target method a class method, or not.
12
+ # New unit test.
15
13
  #
16
14
  def initialize(settings={}, &block)
17
15
  @tested = false
18
- @function = settings[:function]
19
16
  super(settings)
20
17
  end
21
18
 
19
+ #
22
20
  # Validate that a context and target method have been supplied.
21
+ #
23
22
  def validate_settings
24
23
  raise "method test has no module or class context" unless @context
25
24
  raise "#{@target} is not a method name" unless Symbol === @target
26
25
  end
27
26
 
28
- # Type is either `Method` or `Function` (a function is a class method).
27
+ #
28
+ # Description of the type of test case.
29
+ #
29
30
  def type
30
- if function?
31
- 'Function'
32
- else
33
- 'Method'
34
- end
31
+ 'Method'
35
32
  end
36
33
 
34
+ #
37
35
  # Used to make sure the the method has been tested, or not.
36
+ #
38
37
  attr_accessor :tested
39
38
 
40
- # Is this method a class method?
41
- def function?
42
- @function
43
- end
44
-
45
- # A function is also known as a "class method".
46
- alias :class_method? :function?
47
-
39
+ #
48
40
  # If class method, returns target method's name prefixed with double colons.
49
41
  # If instance method, then returns target method's name prefixed with hash
50
42
  # character.
43
+ #
51
44
  def name
52
- function? ? "::#{target}" : "##{target}"
45
+ "##{target}"
53
46
  end
54
47
 
55
48
  # TODO: If sub-cases are to be supported than we need to incorporate
56
49
  # the label into to_s.
57
50
 
51
+ #
58
52
  # Returns the prefixed method name.
53
+ #
59
54
  def to_s
60
- function? ? "::#{target}" : "##{target}"
55
+ "##{target}"
61
56
  end
62
57
 
58
+ #
63
59
  # Returns the fully qulaified name of the target method. This is
64
60
  # the standard interface used by Ruby Test.
61
+ #
65
62
  def unit
66
- function? ? "#{context}.#{target}" : "#{context}##{target}"
63
+ "#{context}##{target}"
67
64
  end
68
65
 
66
+ #
69
67
  # Run test in the context of this case. Notice that #run for
70
68
  # TestMethod is more complex than a general TestCase. This is
71
69
  # to ensure that the target method is invoked during the course
@@ -109,6 +107,8 @@ module Lemon
109
107
  raise_pending(test.procedure) unless test.tested
110
108
  end
111
109
 
110
+ #
111
+ #
112
112
  #
113
113
  def raise_pending(procedure)
114
114
  if RUBY_VERSION < '1.9'
@@ -118,22 +118,32 @@ module Lemon
118
118
  end
119
119
  end
120
120
 
121
- # If the target method is a class method, then the target class is the
122
- # meta-class, otherwise just the class itself.
121
+ #
122
+ # The target class.
123
+ #
123
124
  def target_class
124
- @target_class ||= (
125
- if function?
126
- (class << context.target; self; end)
127
- else
128
- context.target
129
- end
130
- )
125
+ @target_class ||= context.target
126
+ end
127
+
128
+ #
129
+ #
130
+ #
131
+ def class_method?
132
+ false
131
133
  end
132
134
 
133
135
  # Scope for evaluating method test definitions.
134
136
  #
135
- class Scope < TestCase::Scope
137
+ class DSL < TestCase::DSL
136
138
 
139
+ #
140
+ # The class for which this is a DSL context.
141
+ #
142
+ def context_class
143
+ TestMethod
144
+ end
145
+
146
+ #
137
147
  # Define a unit test for this case.
138
148
  #
139
149
  # @example
@@ -141,64 +151,43 @@ module Lemon
141
151
  # puts "Hello"
142
152
  # end
143
153
  #
144
- def test(label=nil, &block)
145
- block = Omission.new(@_omit).to_proc if @_omit
154
+ def test(label=nil, *tags, &block)
155
+ return if @_omit
156
+
146
157
  test = TestProc.new(
147
158
  :context => @_testcase,
148
159
  :setup => @_setup,
149
160
  :skip => @_skip,
150
161
  :label => label,
162
+ :tags => tags,
151
163
  &block
152
164
  )
165
+
153
166
  @_testcase.tests << test
167
+
154
168
  test
155
169
  end
156
- alias :Test :test
157
170
 
158
- # Create a sub-case ofr the method case.
159
- def context(label, &block)
171
+ #
172
+ # Create a sub-case of the method case.
173
+ #
174
+ def context(label, *tags, &block)
175
+ return if @_omit
176
+
160
177
  @_testcase.tests << TestMethod.new(
161
178
  :context => @_testcase,
162
179
  :target => @_testcase.target,
163
180
  :setup => @_setup,
164
181
  :skip => @_skip,
165
182
  :label => label,
183
+ :tags => tags,
166
184
  &block
167
185
  )
168
186
  end
169
- alias :Context :context
170
-
171
- # Omit tests.
172
- #
173
- # @example
174
- # omit "reason" do
175
- # test do
176
- # ...
177
- # end
178
- # end
179
- #
180
- def omit(label=true, &block)
181
- @_omit = label
182
- block.call
183
- @_omit = nil
184
- end
185
- alias :Omit :omit
186
187
 
187
- # Skip tests. Unlike omit, skipped tests are not executed at all.
188
- #
189
- # @example
190
- # skip "reason" do
191
- # test do
192
- # ...
193
- # end
194
- # end
195
- #
196
- def skip(label=true, &block)
197
- @_skip = label
198
- block.call
199
- @_skip = nil
200
- end
201
- alias :Skip :skip
188
+ # Capitialized term.
189
+ alias :Test :test
190
+ alias :Context :context
202
191
 
203
192
  end
204
193