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
@@ -1,103 +0,0 @@
1
- = Lemon
2
-
3
- * Homepage[http://rubyworks.github.com/lemon]
4
- * Development[http://github.com/rubyworks/lemon]
5
- * Issues[http://github.com/rubyworks/lemon/issues]
6
-
7
-
8
- == DESCRIPTION
9
-
10
- Lemon is a Unit Testing Framework that enforces a test case construction mirroring the class/module and method design of the target system. Arguably this promotes the proper technique for unit testing and helps ensure good test coverage.
11
-
12
- The difference between unit testing and functional testing, and all other forms of testing for that matter, is simply a matter of where the *concern* lies. The concerns of unit testing are the concerns of unit tests -- the individual methods.
13
-
14
-
15
- == HOW TO USE
16
-
17
- === Writing Tests
18
-
19
- Say our library 'mylib.rb' consists of the class X:
20
-
21
- class X
22
- def a; "a"; end
23
- end
24
-
25
- The simplest test case would be written as follows:
26
-
27
- covers 'mylib'
28
-
29
- testcase X do
30
- unit :a => "method #a does something expected" do
31
- x = X.new
32
- x.a.assert.is_a? String
33
- end
34
- end
35
-
36
- The +Covers+ method works just like +require+ with the exception that Lemon records the file for reference --under certain scenarios it can be used to improve overall test covered.
37
-
38
- As tests grow, we might need to organize them into special concerns. For this Lemon provides a #concern method and a #setup method. Technically the two methods are the same, but #concern is used more for descriptive purposes whereas #setup is used to create an instance of the testcase's target class.
39
-
40
- covers 'mylib'
41
-
42
- testcase X do
43
- setup "Description of a concern that the following unit tests address." do
44
- X.new
45
- end
46
-
47
- unit :a => "method #a does something expected" do |x|
48
- x.a.assert.is_a? String
49
- end
50
- end
51
-
52
- Notice that the parameter passed to the block of +unit+ method is the instance of +X+ created in the +setup+ block. This block is run for every subsequent +Unit+ until a new concern is defined.
53
-
54
- In conjunction with the #setup methods, there is a #teardown method which can be used "tidy-up" after each unit run if need be.
55
-
56
- Lastly, there are the +before+ and +after+ methods which can be used only once for each testcase. The +before+ method defines a procedure to run before any of the testcase's units are run, and the +after+ method defines a procedure to run after that are all finished.
57
-
58
- That is the bulk of the matter for writing Lemon tests. There are few other features not mentions here. You can learn more about hose by reading the wiki[http://wiki.github.com/proutils/lemon].
59
-
60
-
61
- === Running Tests
62
-
63
- To run tests use the +lemon+ command-line utility.
64
-
65
- $ lemon test/cases/name_case.rb
66
-
67
- Normal output is typical <i>dot-progress</i>. For verbose output, use the <code>--verbose</code> or <code>-v</code> option.
68
-
69
- $ lemon -v test/cases/name_case.rb
70
-
71
- Other output types can be specified by the `--format` or `-f` option.
72
-
73
- $ lemon -f tap test/cases/name_case.rb
74
-
75
-
76
- === Checking Test Coverage
77
-
78
- Lemon can check test coverage by loading your target system and comparing it to your tests. To do this supply the <code>lemon</code> command the <code>--coverage</code> or <code>-c</code> option.
79
-
80
- $ lemon -c -Ilib test/cases/*.rb
81
-
82
- === Generating Test Skeletons
83
-
84
- Because of the one to one correspondence of case-unit to class-method, Lemon can also generate test scaffolding for previously written code. To do this, use the <code>--generate</code> or <code>-g</code> option and provide the lib location, or files, of the scripts for which to generate test scaffolding, and the output location for the test scripts.
85
-
86
- $ lemon -g -Ilib test/cases/*.rb
87
-
88
- Generating test case scaffolding from code will undoubtedly strike test-driven developers as a case of putting the cart before the horse. However, it is not unreasonable to argue that high-level, behavior-driven, functional testing frameworks, such as Q.E.D. and Cucumber are better suited to test-first methodologies. While test-driven development can obviously be done with Lemon, unit-testing is more appropriate for testing specific, critical portions of code, or for achieving full test coverage for mission critical applications.
89
-
90
- === Test Directory
91
-
92
- There is no special directory for Lemon tests. Since they are unit tests, `test/` or `test/unit/` are good choices. Other options are `cases/` and `test/cases` since each file generally defines a single testcase. However, I recommend using interface-based names, regardless of the framework you actually use. In which case, `test/unit` is still a good choice, but also `test/api` if Lemon will be the only framework you use to test the API directly.
93
-
94
-
95
- == COPYRIGHT
96
-
97
- Lemon Unit Testing Framework
98
-
99
- Copyright (c) 2009 Thomas Sawyer
100
-
101
- BSD 2 Clause License
102
-
103
- See COPYING.rdoc for details.
data/bin/lemon DELETED
@@ -1,4 +0,0 @@
1
- #!/usr/bin/env ruby
2
- require 'lemon'
3
- Lemon::CLI.run(ARGV)
4
-
@@ -1,10 +0,0 @@
1
- covers File.dirname(__FILE__) + '/fixture/example.rb'
2
-
3
- testcase Example do
4
-
5
- unit :f => "one and one is two"do
6
- ExampleUnknown.new.f(1,1).assert == 2
7
- end
8
-
9
- end
10
-
@@ -1,15 +0,0 @@
1
- covers File.dirname(__FILE__) + '/fixture/example.rb'
2
-
3
- testcase Example do
4
-
5
- unit :f => "one and one is two"do
6
- Example.new.f(1,1).assert == 2
7
- end
8
-
9
- unit :f do
10
- ex = Example.new
11
- ex.f(1,2).assert == 4
12
- end
13
-
14
- end
15
-
@@ -1,32 +0,0 @@
1
- covers File.dirname(__FILE__) + '/fixture/example.rb'
2
-
3
- testcase Example do
4
-
5
- setup "without multipler" do
6
- Example.new
7
- end
8
-
9
- unit :f do |ex|
10
- ex.f(1,2).assert == 3
11
- ex.f(2,2).assert == 4
12
- end
13
-
14
- setup "with multipler" do
15
- Example.new(2)
16
- end
17
-
18
- unit :f => "incorporate the multiplier" do |ex|
19
- ex.f(1,2).assert == 4
20
- ex.f(2,2).assert == 6
21
- end
22
-
23
- teardown do
24
- # ...
25
- end
26
-
27
- meta :m do
28
- Example.m(1,1).assert == 1
29
- end
30
-
31
- end
32
-
@@ -1,14 +0,0 @@
1
- covers File.dirname(__FILE__) + '/fixture/example.rb'
2
-
3
- testcase Example do
4
-
5
- unit :f => "one and one is two"do
6
- Example.new.f(1,1).assert == 2
7
- end
8
-
9
- unit :f do
10
- raise Pending
11
- end
12
-
13
- end
14
-
@@ -1,10 +0,0 @@
1
- covers File.dirname(__FILE__) + '/fixture/example.rb'
2
-
3
- testcase Example do
4
-
5
- unit :f do
6
- # notice Example#f has not been called
7
- end
8
-
9
- end
10
-
@@ -1,299 +0,0 @@
1
- module Lemon
2
-
3
- require 'lemon/model/main'
4
- require 'lemon/model/test_suite'
5
-
6
- # The TestRunner class handles the execution of Lemon tests.
7
- class TestRunner
8
-
9
- # Test suite to run.
10
- attr :suite
11
-
12
- #
13
- attr :files
14
-
15
- # Report format.
16
- attr :format
17
-
18
- # Record pass, fail, error, pending and omitted units.
19
- attr :record
20
-
21
- # New Runner.
22
- def initialize(files, options={})
23
- @files = files
24
- @options = options
25
-
26
- @record = {:pass=>[], :fail=>[], :error=>[], :pending=>[], :omit=>[]}
27
-
28
- ## TODO: can we create and assign the suite here?
29
- @suite = Lemon::TestSuite.new(files) #([])
30
- #@suite = Lemon.suite
31
-
32
- initialize_rc # TODO: before or after @suite =
33
-
34
- #files = files.map{ |f| Dir[f] }.flatten
35
- #files = files.map{ |f|
36
- # if File.directory?(f)
37
- # Dir[File.join(f, '**/*.rb')]
38
- # else
39
- # f
40
- # end
41
- #}.flatten.uniq
42
- #files = files.map{ |f| File.expand_path(f) }
43
- #files.each{ |s| require s }
44
- end
45
-
46
- # Samples
47
- #
48
- # * .lemon/rc
49
- # * .lemon/rc.rb
50
- # * .config/lemon/rc
51
- # * .config/lemon/rc.rb
52
- #
53
- RC_GLOB = '{.,.config/,config/}lemon/rc{,.rb}'
54
-
55
- #
56
- def initialize_rc
57
- if file = Dir[RC_GLOB].first
58
- require file
59
- end
60
- end
61
-
62
- #
63
- def format
64
- @options[:format]
65
- end
66
-
67
- #
68
- #def cover?
69
- # @options[:cover]
70
- #end
71
-
72
- # Namespaces option specifies the selection of test cases
73
- # to run. Is is an array of strings which are matched
74
- # against the module/class names using #start_wtih?
75
- def namespaces
76
- @options[:namespaces] || []
77
- end
78
-
79
- # Run tests.
80
- #
81
- # @return [Boolean]
82
- # Whether tests ran without error or failure.
83
- def run
84
- #prepare
85
- report.start_suite(suite)
86
- each do |testcase|
87
- scope = Object.new
88
- scope.extend(testcase.dsl)
89
- report.start_case(testcase)
90
- if testcase.prepare #before[[]]
91
- scope.instance_eval(&testcase.prepare)
92
- end
93
- testcase.each do |unit|
94
- #case step
95
- #when TestInstance
96
- # reporter.report_instance(step)
97
- #when TestUnit
98
- # unit = step
99
- if unit.omit?
100
- report.omit(unit)
101
- record[:omit] << unit
102
- next
103
- end
104
- report.start_unit(unit)
105
- run_pretest_procedures(unit, scope) #, suite, testcase)
106
- begin
107
- run_unit(unit, scope)
108
- #unit.call(scope)
109
- report.pass(unit)
110
- record[:pass] << unit
111
- rescue Pending => exception
112
- exception = clean_backtrace(exception)
113
- report.pending(unit, exception)
114
- record[:pending] << [unit, exception]
115
- rescue Assertion => exception
116
- exception = clean_backtrace(exception)
117
- report.fail(unit, exception)
118
- record[:fail] << [unit, exception]
119
- rescue Exception => exception
120
- exception = clean_backtrace(exception)
121
- report.error(unit, exception)
122
- record[:error] << [unit, exception]
123
- end
124
- report.finish_unit(unit)
125
- run_postest_procedures(unit, scope) #, suite, testcase)
126
- #end
127
- end
128
- if testcase.cleanup #after[[]]
129
- scope.instance_eval(&testcase.cleanup)
130
- end
131
- report.finish_case(testcase)
132
- end
133
- report.finish_suite(suite) #(successes, failures, errors, pendings)
134
- return record[:error].size + record[:fail].size > 0 ? false : true
135
- end
136
-
137
- # Iterate over suite testcases, filtering out unselected testcases
138
- # if any namespaces are provided.
139
- def each(&block)
140
- if namespaces.empty?
141
- suite.each do |testcase|
142
- block.call(testcase)
143
- end
144
- else
145
- suite.each do |testcase|
146
- next unless namespaces.any?{ |n| testcase.target.name.start_with?(n) }
147
- block.call(testcase)
148
- end
149
- end
150
- end
151
-
152
- # All output is handled by a reporter.
153
- def report
154
- @report ||= report_find(format)
155
- end
156
-
157
- # Find a report type be name fragment.
158
- def report_find(format)
159
- format = format ? format.to_s.downcase : 'dotprogress'
160
- format = report_list.find do |r|
161
- /^#{format}/ =~ r
162
- end
163
- raise "unsupported format" unless format
164
- require "lemon/view/test_reports/#{format}"
165
- reporter = Lemon::TestReports.const_get(format.capitalize)
166
- reporter.new(self)
167
- end
168
-
169
- # Returns a list of report types.
170
- def report_list
171
- Dir[File.dirname(__FILE__) + '/../view/test_reports/*.rb'].map do |rb|
172
- File.basename(rb).chomp('.rb')
173
- end
174
- end
175
-
176
- private
177
-
178
- #
179
- def run_unit(unit, scope)
180
- if unit.function?
181
- base = (class << unit.testcase.target; self; end)
182
- else
183
- base = unit.testcase.target
184
- end
185
-
186
- raise Pending unless unit.procedure
187
-
188
- begin
189
- base.class_eval do
190
- alias_method "_lemon_#{unit.target}", unit.target
191
- define_method(unit.target) do |*a,&b|
192
- unit.tested = true
193
- __send__("_lemon_#{unit.target}",*a,&b)
194
- end
195
- end
196
- rescue => error
197
- Kernel.eval <<-END, unit.procedure.binding
198
- raise #{error.class}, "#{unit.target} not tested"
199
- END
200
- end
201
- #Lemon.test_stack << self # hack
202
-
203
- begin
204
- if unit.context && unit.procedure.arity != 0
205
- cntx = unit.context.setup(scope)
206
- scope.instance_exec(cntx, &unit.procedure) #procedure.call
207
- else
208
- scope.instance_exec(&unit.procedure) #procedure.call
209
- end
210
- unit.context.teardown(scope) if unit.context
211
- ensure
212
- #Lemon.test_stack.pop
213
- base.class_eval %{
214
- alias_method "#{unit.target}", "_lemon_#{unit.target}"
215
- }
216
- end
217
- if !unit.tested
218
- #exception = Untested.new("#{unit.target} not tested")
219
- if RUBY_VERSION < '1.9'
220
- Kernel.eval %[raise Pending, "#{unit.target} not tested"], unit.procedure
221
- else
222
- Kernel.eval %[raise Pending, "#{unit.target} not tested"], unit.procedure.binding
223
- end
224
- end
225
- end
226
-
227
- =begin
228
- #
229
- def run_concern_procedures(concern, scope) #suite, testcase)
230
- tc = concern.testcase
231
- suite = tc.suite
232
- suite.when_clauses.each do |match, block|
233
- if match.nil? or match === concern.to_s
234
- #block.call #(test_case)
235
- scope.instance_exec(tc, &block)
236
- end
237
- end
238
- tc.when_clauses.each do |match, block|
239
- if match.nil? or match === concern.to_s
240
- if match === concern.to_s
241
- #block.call #(test_case)
242
- scope.instance_exec(tc, &block)
243
- end
244
- end
245
- end
246
- concern.call(scope)
247
- end
248
- =end
249
-
250
- # Run pre-test advice.
251
- def run_pretest_procedures(unit, scope) #, suite, testcase)
252
- suite = unit.testcase.suite
253
- suite.before.each do |matches, block|
254
- if matches.all?{ |match| unit.match?(match) }
255
- scope.instance_exec(unit, &block) #block.call(unit)
256
- end
257
- end
258
- unit.testcase.before.each do |matches, block|
259
- if matches.all?{ |match| unit.match?(match) }
260
- scope.instance_exec(unit, &block) #block.call(unit)
261
- end
262
- end
263
- end
264
-
265
- # Run post-test advice.
266
- def run_postest_procedures(unit, scope) #, suite, testcase)
267
- suite = unit.testcase.suite
268
- unit.testcase.after.each do |matches, block|
269
- if matches.all?{ |match| unit.match?(match) }
270
- scope.instance_exec(unit, &block) #block.call(unit)
271
- end
272
- end
273
- suite.after.each do |matches, block|
274
- if matches.all?{ |match| unit.match?(match) }
275
- scope.instance_exec(unit, &block) #block.call(unit)
276
- end
277
- end
278
- end
279
-
280
- EXCLUDE = Regexp.new(Regexp.escape(File.dirname(File.dirname(__FILE__))))
281
-
282
- # Remove reference to lemon library from backtrace.
283
- # TODO: Matching `bin/lemon` is not robust.
284
- def clean_backtrace(exception)
285
- trace = (Exception === exception ? exception.backtrace : exception)
286
- trace = trace.reject{ |t| t =~ /bin\/lemon/ }
287
- trace = trace.reject{ |t| t =~ EXCLUDE }
288
- if trace.empty?
289
- exception
290
- else
291
- exception.set_backtrace(trace) if Exception === exception
292
- exception
293
- end
294
- end
295
-
296
- end
297
-
298
- end
299
-