lemon 0.8.5 → 0.9.0

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 (113) hide show
  1. data/{lemon.gemspec → .gemspec} +0 -0
  2. data/.ruby +4 -11
  3. data/Assembly +5 -11
  4. data/HISTORY.rdoc +31 -0
  5. data/MANIFEST +45 -55
  6. data/PROFILE +6 -6
  7. data/README.md +113 -0
  8. data/Rakefile +12 -3
  9. data/VERSION +1 -1
  10. data/bin/lemonade +8 -0
  11. data/lib/lemon.rb +52 -2
  12. data/lib/lemon.yml +4 -11
  13. data/lib/lemon/{model/ae.rb → ae.rb} +0 -0
  14. data/lib/lemon/cli.rb +28 -279
  15. data/lib/lemon/cli/base.rb +139 -0
  16. data/lib/lemon/cli/coverage.rb +52 -0
  17. data/lib/lemon/cli/generate.rb +51 -0
  18. data/lib/lemon/cli/test.rb +50 -0
  19. data/lib/lemon/core_ext.rb +7 -0
  20. data/lib/lemon/core_ext/kernel.rb +20 -0
  21. data/lib/lemon/core_ext/omission.rb +18 -0
  22. data/lib/lemon/{controller/coverage_analyzer.rb → coverage/analyzer.rb} +41 -19
  23. data/lib/lemon/{model → coverage}/cover_unit.rb +0 -0
  24. data/lib/lemon/{view/cover_reports → coverage/formats}/abstract.rb +0 -0
  25. data/lib/lemon/{view/cover_reports → coverage/formats}/compact.rb +1 -1
  26. data/lib/lemon/{view/cover_reports → coverage/formats}/outline.rb +1 -1
  27. data/lib/lemon/{view/cover_reports → coverage/formats}/verbose.rb +1 -1
  28. data/lib/lemon/{view/cover_reports → coverage/formats}/yaml.rb +1 -1
  29. data/lib/lemon/{model → coverage}/snapshot.rb +0 -0
  30. data/lib/lemon/{model → coverage}/source_parser.rb +0 -0
  31. data/lib/lemon/{controller/scaffold_generator.rb → generator.rb} +53 -14
  32. data/lib/lemon/test_advice.rb +63 -0
  33. data/lib/lemon/test_case.rb +270 -0
  34. data/lib/lemon/test_class.rb +28 -0
  35. data/lib/lemon/test_method.rb +207 -0
  36. data/lib/lemon/test_module.rb +114 -0
  37. data/lib/lemon/test_proc.rb +140 -0
  38. data/lib/lemon/test_setup.rb +54 -0
  39. data/lib/lemon/test_world.rb +9 -0
  40. data/notes/{2010-05-06-files_not_classes.rdoc → 2010-05-06-files-not-classes.rdoc} +0 -0
  41. data/notes/{2010-07-11-acid_testing.rdoc → 2010-07-11-acid-testing.rdoc} +0 -0
  42. data/notes/2011-07-07-nailing-down-the-nomenclature.md +6 -0
  43. data/site/index.html +7 -6
  44. data/{qed → spec}/applique/fs.rb +0 -0
  45. data/{qed → spec}/coverage/01_complete.rdoc +26 -16
  46. data/{qed → spec}/coverage/02_incomplete.rdoc +10 -7
  47. data/{qed → spec}/coverage/03_extensions.rdoc +10 -6
  48. data/spec/coverage/applique/lemon.rb +1 -0
  49. data/try/.test +8 -0
  50. data/try/case_error.rb +18 -0
  51. data/try/case_fail.rb +19 -0
  52. data/try/case_pass.rb +42 -0
  53. data/try/case_pending.rb +18 -0
  54. data/try/case_singleton.rb +18 -0
  55. data/try/case_untested.rb +14 -0
  56. data/try/fixtures/calculator.rb +15 -0
  57. data/{demo/fixture → try/fixtures}/example-use.rb +0 -0
  58. data/{demo/fixture → try/fixtures}/example.rb +0 -0
  59. data/try/helpers/loadpath.rb +1 -0
  60. data/{.config → work/deprecated}/cucumber.yml +0 -0
  61. data/{features → work/deprecated/features}/coverage.feature +0 -0
  62. data/{features → work/deprecated/features}/generate.feature +0 -0
  63. data/{features → work/deprecated/features}/step_definitions/coverage_steps.rb +0 -0
  64. data/{features → work/deprecated/features}/support/ae.rb +0 -0
  65. data/{features → work/deprecated/features}/support/aruba.rb +0 -0
  66. data/{features → work/deprecated/features}/test.feature +0 -0
  67. data/work/deprecated/model/dsl/advice.rb +78 -0
  68. data/work/deprecated/model/dsl/subject.rb +40 -0
  69. data/{lib/lemon → work/deprecated}/model/main.rb +40 -29
  70. data/work/deprecated/model/test.rb +54 -0
  71. data/work/deprecated/model/test_base_dsl.rb +88 -0
  72. data/work/deprecated/model/test_clause.rb +112 -0
  73. data/{lib/lemon → work/deprecated}/model/test_context.rb +24 -24
  74. data/work/deprecated/model/test_feature.rb +128 -0
  75. data/work/deprecated/model/test_scenario.rb +137 -0
  76. data/{lib/lemon → work/deprecated}/model/test_suite.rb +113 -32
  77. data/work/deprecated/rake.rb +103 -0
  78. data/{test → work/deprecated/test}/case_coverage_analyzer.rb +0 -0
  79. data/{test → work/deprecated/test}/case_test_case_dsl.rb +2 -2
  80. data/{test → work/deprecated/test}/fixtures/case_complete.rb +0 -0
  81. data/{test → work/deprecated/test}/fixtures/case_inclusion.rb +0 -0
  82. data/{test → work/deprecated/test}/fixtures/case_incomplete.rb +0 -0
  83. data/{test → work/deprecated/test}/fixtures/example.rb +0 -0
  84. data/{test → work/deprecated/test}/fixtures/helper.rb +0 -0
  85. data/{test → work/deprecated/test}/runner +0 -0
  86. data/work/old-tests/case_example.rb +15 -0
  87. data/work/old-tests/feature_example.rb +40 -0
  88. data/work/reference/dsl2.rb +4 -0
  89. metadata +101 -98
  90. data/README.rdoc +0 -103
  91. data/bin/lemon +0 -4
  92. data/demo/case_example_error.rb +0 -10
  93. data/demo/case_example_fail.rb +0 -15
  94. data/demo/case_example_pass.rb +0 -32
  95. data/demo/case_example_pending.rb +0 -14
  96. data/demo/case_example_untested.rb +0 -10
  97. data/lib/lemon/controller/test_runner.rb +0 -299
  98. data/lib/lemon/model/pending.rb +0 -10
  99. data/lib/lemon/model/test_case.rb +0 -305
  100. data/lib/lemon/model/test_unit.rb +0 -147
  101. data/lib/lemon/view/test_reports/abstract.rb +0 -256
  102. data/lib/lemon/view/test_reports/dotprogress.rb +0 -73
  103. data/lib/lemon/view/test_reports/html.rb +0 -146
  104. data/lib/lemon/view/test_reports/outline.rb +0 -118
  105. data/lib/lemon/view/test_reports/summary.rb +0 -131
  106. data/lib/lemon/view/test_reports/tap.rb +0 -49
  107. data/lib/lemon/view/test_reports/tapj.rb +0 -130
  108. data/lib/lemon/view/test_reports/tapy.rb +0 -141
  109. data/lib/lemon/view/test_reports/verbose.rb +0 -197
  110. data/work/sandbox/lib/sample.rb +0 -13
  111. data/work/sandbox/test/sample_case.rb +0 -12
  112. data/work/trash/example-cover.rb +0 -5
  113. data/work/trash/example.rb +0 -16
@@ -0,0 +1,63 @@
1
+ module Lemon
2
+
3
+ #--
4
+ # TODO: Probably can replace advice with simple hash.
5
+ #++
6
+
7
+ # Test Advice
8
+ class TestAdvice
9
+
10
+ # The test case to which this advice belongs.
11
+ #attr :context
12
+
13
+ #
14
+ attr :table
15
+
16
+ # New case instance.
17
+ def initialize
18
+ @table = Hash.new{ |h,k| h[k] = {} }
19
+ end
20
+
21
+ #
22
+ def initialize_copy(original)
23
+ @table = original.table.clone
24
+ end
25
+
26
+ #
27
+ def [](type)
28
+ @table[type.to_sym]
29
+ end
30
+
31
+ =begin
32
+ #
33
+ #def teardown=(procedure)
34
+ # @teardown = procedure
35
+ #end
36
+
37
+ # Setup.
38
+ def setup(scope=nil)
39
+ if scope
40
+ scope.instance_eval(&@setup)
41
+ else
42
+ @setup
43
+ end
44
+ end
45
+
46
+ # Teardown.
47
+ def teardown(scope=nil)
48
+ if scope
49
+ scope.instance_eval(&@teardown) if @teardown
50
+ else
51
+ @teardown
52
+ end
53
+ end
54
+
55
+ # Returns the description with newlines removed.
56
+ def to_s
57
+ description.gsub(/\n/, ' ')
58
+ end
59
+ =end
60
+
61
+ end
62
+
63
+ end
@@ -0,0 +1,270 @@
1
+ require 'lemon/core_ext'
2
+ require 'lemon/test_advice'
3
+ require 'lemon/test_setup'
4
+ require 'lemon/test_world'
5
+
6
+ module Lemon
7
+
8
+ # Test Case serves as the base class for Lemon's
9
+ # specialized test case classes.
10
+ #
11
+ class TestCase
12
+
13
+ # The parent context in which this case resides.
14
+ attr :context
15
+
16
+ # Brief description of the test case.
17
+ attr :label
18
+
19
+ # Target component.
20
+ attr :target
21
+
22
+ # The setup and teardown advice.
23
+ attr :setup
24
+
25
+ # Advice are labeled procedures, such as before
26
+ # and after advice.
27
+ attr :advice
28
+
29
+ # List of tests and sub-contexts.
30
+ attr :tests
31
+
32
+ # Skip execution of test case?
33
+ attr :skip
34
+
35
+ # A test case +target+ is a class or module.
36
+ #
37
+ # @param [Hash] settings
38
+ # The settings used to define the test case.
39
+ #
40
+ # @option settings [TestCase] :context
41
+ # Parent test case.
42
+ #
43
+ # @option settings [Module,Class,Symbol] :target
44
+ # The testcase's target.
45
+ #
46
+ # @option settings [String] :label
47
+ # Breif description of testcase.
48
+ # (NOTE: this might not be used)
49
+ #
50
+ # @option settings [TestSetup] :setup
51
+ # Test setup.
52
+ #
53
+ # @option settings [Boolean] :skip
54
+ # If runner should skip test.
55
+ #
56
+ def initialize(settings={}, &block)
57
+ @context = settings[:context]
58
+ @target = settings[:target]
59
+ @label = settings[:label]
60
+ @setup = settings[:setup]
61
+ @skip = settings[:skip]
62
+
63
+ @advice = @context ? @context.advice.dup : TestAdvice.new
64
+
65
+ @tests = []
66
+ @scope = scope_class.new(self)
67
+
68
+ validate_settings
69
+
70
+ evaluate(&block)
71
+ end
72
+
73
+ # Subclasses can override this methof to validate settings.
74
+ # It is run just before evaluation of scope block.
75
+ def validate_settings
76
+ end
77
+
78
+ #
79
+ def evaluate(&block)
80
+ @scope.module_eval(&block)
81
+ end
82
+
83
+ # Iterate over each test and subcase.
84
+ def each(&block)
85
+ tests.each(&block)
86
+ end
87
+
88
+ # Number of tests and subcases.
89
+ def size
90
+ tests.size
91
+ end
92
+
93
+ # Subclasses of TestCase can override this to describe
94
+ # the type of test case they define.
95
+ def type
96
+ 'Case'
97
+ end
98
+
99
+ #
100
+ def to_s
101
+ @label.to_s
102
+ end
103
+
104
+ #
105
+ def skip?
106
+ @skip
107
+ end
108
+
109
+ #
110
+ def skip!(reason=true)
111
+ @skip = reason
112
+ end
113
+
114
+ # Run test in the context of this case.
115
+ #
116
+ # @param [TestProc] test
117
+ # The test unit to run.
118
+ #
119
+ def run(test, &block)
120
+ advice[:before].each do |matches, block|
121
+ if matches.all?{ |match| test.match?(match) }
122
+ scope.instance_exec(test, &block) #block.call(unit)
123
+ end
124
+ end
125
+
126
+ block.call
127
+
128
+ advice[:after].each do |matches, block|
129
+ if matches.all?{ |match| test.match?(match) }
130
+ scope.instance_exec(test, &block) #block.call(unit)
131
+ end
132
+ end
133
+ end
134
+
135
+ # Module for evaluating test case script.
136
+ #
137
+ # @return [Scope] evaluation scope
138
+ def scope
139
+ @scope
140
+ end
141
+
142
+ # Get the scope class dynamically so that each subclass
143
+ # of TestCase will retrieve it's own.
144
+ def scope_class
145
+ self.class.const_get(:Scope)
146
+ end
147
+
148
+ #
149
+ class Scope < World
150
+
151
+ #
152
+ def initialize(testcase) #, &code)
153
+ @_testcase = testcase
154
+ @_setup = testcase.setup
155
+ @_skip = nil
156
+
157
+ extend testcase.context.scope if testcase.context
158
+
159
+ #module_eval(&code)
160
+ end
161
+
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
+
177
+ # Setup is used to set things up for each unit test.
178
+ # The setup procedure is run before each unit.
179
+ #
180
+ # @param [String] description
181
+ # A brief description of what the setup procedure sets-up.
182
+ #
183
+ def setup(description=nil, &procedure)
184
+ if procedure
185
+ @_setup = TestSetup.new(@test_case, description, &procedure)
186
+ end
187
+ end
188
+ alias :Setup :setup
189
+
190
+ # Original Lemon nomenclature for `#setup`.
191
+ alias :concern :setup
192
+ alias :Concern :setup
193
+
194
+ # Teardown procedure is used to clean-up after each unit test.
195
+ #
196
+ def teardown(&procedure)
197
+ @_setup.teardown = procedure
198
+ end
199
+ alias :Teardown :teardown
200
+
201
+ #--
202
+ # TODO: Allow Before and After to handle setup and teardown?
203
+ # But that would only allow one setup per case.
204
+ #++
205
+
206
+ # Define a _complex_ before procedure. The #before method allows
207
+ # before procedures to be defined that are triggered by a match
208
+ # against the unit's target method name or _aspect_ description.
209
+ # This allows groups of tests to be defined that share special
210
+ # setup code.
211
+ #
212
+ # @example
213
+ # Method :puts do
214
+ # Test "standard output (@stdout)" do
215
+ # puts "Hello"
216
+ # end
217
+ #
218
+ # Before /@stdout/ do
219
+ # $stdout = StringIO.new
220
+ # end
221
+ #
222
+ # After /@stdout/ do
223
+ # $stdout = STDOUT
224
+ # end
225
+ # end
226
+ #
227
+ # @param [Array<Symbol,Regexp>] matches
228
+ # List of match critera that must _all_ be matched
229
+ # to trigger the before procedure.
230
+ #
231
+ def before(*matches, &procedure)
232
+ @_testcase.advice[:before][matches] = procedure
233
+ end
234
+ alias :Before :before
235
+
236
+ # Define a _complex_ after procedure. The #before method allows
237
+ # before procedures to be defined that are triggered by a match
238
+ # against the unit's target method name or _aspect_ description.
239
+ # This allows groups of tests to be defined that share special
240
+ # teardown code.
241
+ #
242
+ # @example
243
+ # Method :puts do
244
+ # Test "standard output (@stdout)" do
245
+ # puts "Hello"
246
+ # end
247
+ #
248
+ # Before /@stdout/ do
249
+ # $stdout = StringIO.new
250
+ # end
251
+ #
252
+ # After /@stdout/ do
253
+ # $stdout = STDOUT
254
+ # end
255
+ # end
256
+ #
257
+ # @param [Array<Symbol,Regexp>] matches
258
+ # List of match critera that must _all_ be matched
259
+ # to trigger the after procedure.
260
+ #
261
+ def after(*matches, &procedure)
262
+ @_testcase.advice[:after][matches] = procedure
263
+ end
264
+ alias :After :after
265
+
266
+ end
267
+
268
+ end
269
+
270
+ end
@@ -0,0 +1,28 @@
1
+ module Lemon
2
+
3
+ require 'lemon/test_module'
4
+
5
+ # Subclass of TestModule used for classes.
6
+ # It's basically the same class.
7
+ #
8
+ class TestClass < TestModule
9
+
10
+ private
11
+
12
+ # Make sure the target is a class.
13
+ def validate_target
14
+ raise unless Class === @target
15
+ end
16
+
17
+ # The type of testcase.
18
+ def type
19
+ 'Class'
20
+ end
21
+
22
+ # Evaluation scope for {TestClass}.
23
+ class Scope < TestModule::Scope
24
+ end
25
+
26
+ end
27
+
28
+ end
@@ -0,0 +1,207 @@
1
+ module Lemon
2
+
3
+ require 'lemon/test_case'
4
+ require 'lemon/test_proc'
5
+
6
+ # The TestMethod class is a special TestCase that requires
7
+ # a particular target method be tested.
8
+ #
9
+ class TestMethod < TestCase
10
+
11
+ # New unit test.
12
+ #
13
+ # @option settings [Boolean] :function
14
+ # Is the target method a class method, or not.
15
+ #
16
+ def initialize(settings={}, &block)
17
+ @tested = false
18
+ @function = settings[:function]
19
+ super(settings)
20
+ end
21
+
22
+ # Validate that a context and target method have been supplied.
23
+ def validate_settings
24
+ raise "method test has no module or class context" unless @context
25
+ raise "#{@target} is not a method name" unless Symbol === @target
26
+ end
27
+
28
+ # Type is either `Method` or `Function` (a function is a class method).
29
+ def type
30
+ if function?
31
+ 'Function'
32
+ else
33
+ 'Method'
34
+ end
35
+ end
36
+
37
+ # Used to make sure the the method has been tested, or not.
38
+ attr_accessor :tested
39
+
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
+
48
+ # If class method, returns target method's name prefixed with double colons.
49
+ # If instance method, then returns target method's name prefixed with hash
50
+ # character.
51
+ def name
52
+ function? ? "::#{target}" : "##{target}"
53
+ end
54
+
55
+ # TODO: If sub-cases are to be supported than we need to incorporate
56
+ # the label into to_s.
57
+
58
+ # Returns the prefixed method name.
59
+ def to_s
60
+ function? ? "::#{target}" : "##{target}"
61
+ end
62
+
63
+ # Returns the fully qulaified name of the target method. This is
64
+ # the standard interface used by Ruby Test.
65
+ def unit
66
+ function? ? "#{context}.#{target}" : "#{context}##{target}"
67
+ end
68
+
69
+ # Run test in the context of this case. Notice that #run for
70
+ # TestMethod is more complex than a general TestCase. This is
71
+ # to ensure that the target method is invoked during the course
72
+ # of the test.
73
+ #
74
+ # @param [TestProc] test
75
+ # The test procedure instance to run.
76
+ #
77
+ # @yield
78
+ # The procedure for running the test.
79
+ #
80
+ def run(test, &block)
81
+ target = self.target
82
+
83
+ raise_pending(test.procedure) unless test.procedure
84
+
85
+ begin
86
+ target_class.class_eval do
87
+ alias_method "_lemon_#{target}", target
88
+ define_method(target) do |*a,&b|
89
+ test.tested = true
90
+ __send__("_lemon_#{target}",*a,&b)
91
+ end
92
+ end
93
+ rescue => error
94
+ Kernel.eval <<-END, test.to_proc.binding
95
+ raise #{error.class}, "#{target} not tested"
96
+ END
97
+ end
98
+
99
+ begin
100
+ super(test, &block)
101
+ #block.call
102
+
103
+ ensure
104
+ target_class.class_eval %{
105
+ alias_method "#{target}", "_lemon_#{target}"
106
+ }
107
+ end
108
+
109
+ raise_pending(test.procedure) unless test.tested
110
+ end
111
+
112
+ #
113
+ def raise_pending(procedure)
114
+ if RUBY_VERSION < '1.9'
115
+ Kernel.eval %[raise NotImplementedError, "#{target} not tested"], procedure
116
+ else
117
+ Kernel.eval %[raise NotImplementedError, "#{target} not tested"], procedure.binding
118
+ end
119
+ end
120
+
121
+ # If the target method is a class method, then the target class is the
122
+ # meta-class, otherwise just the class itself.
123
+ def target_class
124
+ @target_class ||= (
125
+ if function?
126
+ (class << context.target; self; end)
127
+ else
128
+ context.target
129
+ end
130
+ )
131
+ end
132
+
133
+ # Scope for evaluating method test definitions.
134
+ #
135
+ class Scope < TestCase::Scope
136
+
137
+ # Define a unit test for this case.
138
+ #
139
+ # @example
140
+ # test "print message with new line to stdout" do
141
+ # puts "Hello"
142
+ # end
143
+ #
144
+ def test(label=nil, &block)
145
+ block = Omission.new(@_omit).to_proc if @_omit
146
+ test = TestProc.new(
147
+ :context => @_testcase,
148
+ :setup => @_setup,
149
+ :skip => @_skip,
150
+ :label => label,
151
+ &block
152
+ )
153
+ @_testcase.tests << test
154
+ test
155
+ end
156
+ alias :Test :test
157
+
158
+ # Create a sub-case ofr the method case.
159
+ def context(label, &block)
160
+ @_testcase.tests << TestMethod.new(
161
+ :context => @_testcase,
162
+ :target => @_testcase.target,
163
+ :setup => @_setup,
164
+ :skip => @_skip,
165
+ :label => label,
166
+ &block
167
+ )
168
+ 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
+ # 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
202
+
203
+ end
204
+
205
+ end
206
+
207
+ end