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