lemon 0.8.5 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
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