lemon 0.8.1 → 0.8.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. data/HISTORY.rdoc +15 -0
  2. data/README.rdoc +32 -14
  3. data/bin/lemon +3 -2
  4. data/demo/case_example_fail.rb +15 -0
  5. data/demo/case_example_pass.rb +32 -0
  6. data/demo/case_example_pending.rb +14 -0
  7. data/demo/case_example_untested.rb +10 -0
  8. data/demo/fixture/example-use.rb +5 -0
  9. data/demo/fixture/example.rb +20 -0
  10. data/lib/lemon.rb +2 -2
  11. data/lib/lemon/cli.rb +281 -0
  12. data/lib/lemon/controller/coverage_analyzer.rb +343 -0
  13. data/lib/lemon/controller/scaffold_generator.rb +110 -0
  14. data/lib/lemon/controller/test_runner.rb +284 -0
  15. data/lib/lemon/meta/data.rb +29 -0
  16. data/lib/lemon/meta/gemfile +24 -0
  17. data/{PROFILE → lib/lemon/meta/profile} +6 -5
  18. data/lib/lemon/model/ae.rb +4 -0
  19. data/lib/lemon/model/cover_unit.rb +75 -0
  20. data/lib/lemon/{dsl.rb → model/main.rb} +22 -28
  21. data/lib/lemon/model/pending.rb +10 -0
  22. data/lib/lemon/model/snapshot.rb +203 -0
  23. data/lib/lemon/model/source_parser.rb +198 -0
  24. data/lib/lemon/model/test_case.rb +221 -0
  25. data/lib/lemon/model/test_context.rb +90 -0
  26. data/lib/lemon/model/test_suite.rb +216 -0
  27. data/lib/lemon/{test/unit.rb → model/test_unit.rb} +40 -28
  28. data/lib/lemon/{coversheet → view/cover_reports}/abstract.rb +19 -20
  29. data/lib/lemon/view/cover_reports/compact.rb +37 -0
  30. data/lib/lemon/view/cover_reports/outline.rb +45 -0
  31. data/lib/lemon/view/cover_reports/verbose.rb +51 -0
  32. data/lib/lemon/view/cover_reports/yaml.rb +15 -0
  33. data/lib/lemon/view/test_reports/abstract.rb +149 -0
  34. data/lib/lemon/view/test_reports/dotprogress.rb +73 -0
  35. data/lib/lemon/view/test_reports/html.rb +146 -0
  36. data/lib/lemon/view/test_reports/outline.rb +118 -0
  37. data/lib/lemon/view/test_reports/summary.rb +131 -0
  38. data/lib/lemon/view/test_reports/tap.rb +49 -0
  39. data/lib/lemon/view/test_reports/verbose.rb +197 -0
  40. data/meta/data.rb +29 -0
  41. data/meta/gemfile +24 -0
  42. data/meta/profile +17 -0
  43. data/test/api/applique/fs.rb +18 -0
  44. data/test/api/coverage/complete.rdoc +136 -0
  45. data/test/api/coverage/extensions.rdoc +61 -0
  46. data/test/api/coverage/incomplete.rdoc +97 -0
  47. data/{features → test/cli}/coverage.feature +4 -4
  48. data/{features → test/cli}/generate.feature +2 -2
  49. data/{features → test/cli}/step_definitions/coverage_steps.rb +0 -0
  50. data/{features → test/cli}/support/ae.rb +0 -0
  51. data/{features → test/cli}/support/aruba.rb +0 -0
  52. data/{features → test/cli}/test.feature +0 -0
  53. data/test/fixtures/case_complete.rb +17 -4
  54. data/test/fixtures/case_inclusion.rb +18 -0
  55. data/test/fixtures/case_incomplete.rb +4 -4
  56. data/test/fixtures/example.rb +5 -0
  57. data/test/fixtures/helper.rb +13 -0
  58. data/test/runner +3 -0
  59. data/test/unit/case_coverage_analyzer.rb +25 -0
  60. data/test/unit/case_test_case_dsl.rb +46 -0
  61. metadata +87 -42
  62. data/REQUIRE +0 -9
  63. data/VERSION +0 -6
  64. data/lib/lemon/command.rb +0 -184
  65. data/lib/lemon/coverage.rb +0 -260
  66. data/lib/lemon/coversheet/outline.rb +0 -47
  67. data/lib/lemon/kernel.rb +0 -24
  68. data/lib/lemon/reporter.rb +0 -22
  69. data/lib/lemon/reporter/abstract.rb +0 -97
  70. data/lib/lemon/reporter/dotprogress.rb +0 -68
  71. data/lib/lemon/reporter/outline.rb +0 -105
  72. data/lib/lemon/reporter/verbose.rb +0 -143
  73. data/lib/lemon/runner.rb +0 -308
  74. data/lib/lemon/snapshot.rb +0 -185
  75. data/lib/lemon/test/case.rb +0 -139
  76. data/lib/lemon/test/concern.rb +0 -52
  77. data/lib/lemon/test/suite.rb +0 -229
  78. data/test/case_coverage.rb +0 -26
  79. data/test/case_testcase.rb +0 -58
data/HISTORY.rdoc CHANGED
@@ -1,5 +1,20 @@
1
1
  = RELEASE HISTORY
2
2
 
3
+ == 0.8.2 / 2010-09-05
4
+
5
+ This release overhauls how coverage is performed so it does not need to
6
+ take a system snapshot after requiring each covered file. This greatly
7
+ improves Lemon's speed. In addition #setup and #teardown have been introduced
8
+ for performing procedures before and after each unit test.
9
+
10
+ Changes:
11
+
12
+ * Overhaul coverage analysis.
13
+ * Add TestCase#setup and #teardown methods.
14
+ * TestCase#concern and #context are just aliases of #setup.
15
+ * Improved output formats.
16
+
17
+
3
18
  == 0.8.1 / 2010-07-11
4
19
 
5
20
  This release adds a timer to the verbose output, which help isolate unit tests
data/README.rdoc CHANGED
@@ -23,30 +23,40 @@ Say our library 'mylib.rb' consists of the class X:
23
23
 
24
24
  The simplest test case would be written as follows:
25
25
 
26
- Covers 'mylib'
26
+ covers 'mylib'
27
27
 
28
- TestCase X do
29
- Unit :a => "method #a does something expected" do
28
+ testcase X do
29
+ unit :a => "method #a does something expected" do
30
30
  x = X.new
31
31
  x.a.assert.is_a? String
32
32
  end
33
33
  end
34
34
 
35
- The +Covers+ method works just like +require+ with the exception that loading the file does not occur until just before the tests are run. This allows Lemon to calculate accurate coverage reports.
35
+ The +Covers+ method works just like +require+ with the exception that Lemon records the file for refernce --under certain scenarios it can be used to improve overall test covered.
36
36
 
37
- As tests grow, we might need to organize them into special concerns. For this Lemon provides the #Concern method.
37
+ 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.
38
38
 
39
- Covers 'mylib'
39
+ covers 'mylib'
40
40
 
41
- TestCase X do
42
- Concern "Description of a concern that the following unit tests address."
41
+ testcase X do
42
+ setup "Description of a concern that the following unit tests address." do
43
+ X.new
44
+ end
43
45
 
44
- Unit :a => "method #a does something expected" do
45
- x = X.new
46
+ unit :a => "method #a does something expected" do |x|
46
47
  x.a.assert.is_a? String
47
48
  end
48
49
  end
49
50
 
51
+ Notice that the parameter passed to the block of +unit+ methdod is the instance of +X+ created in the +setup+ block. This block is run for every subsequent +Unit+ untill a new concern is defined.
52
+
53
+ In conjunction with the #setup methods, there is a #teardown method which can be used "tidy-up" after each unit run if need be.
54
+
55
+ 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.
56
+
57
+ That is the bulk of the matter forf 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].
58
+
59
+
50
60
  === Running Tests
51
61
 
52
62
  To run tests use the +lemon+ command-line utility.
@@ -57,26 +67,34 @@ Normal output is typical <i>dot-progress</i>. For verbose output, use the <code>
57
67
 
58
68
  $ lemon -v test/cases/name_case.rb
59
69
 
70
+ Other output types can be specified by the `--format` or `-f` option.
71
+
72
+ $ lemon -f tap test/cases/name_case.rb
73
+
74
+
60
75
  === Checking Test Coverage
61
76
 
62
77
  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.
63
78
 
64
- $ lemon --coverage -Ilib test/cases/
79
+ $ lemon -c -Ilib test/cases/*.rb
65
80
 
66
81
  === Generating Test Skeletons
67
82
 
68
83
  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.
69
84
 
70
- $ lemon --generate -Ilib test/cases/
85
+ $ lemon -g -Ilib test/cases/*.rb
71
86
 
72
87
  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.
73
88
 
89
+ === Test Directory
90
+
91
+ 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.
92
+
74
93
 
75
94
  == COPYRIGHT
76
95
 
77
- (MIT License)
96
+ (Apache 2.0 License)
78
97
 
79
98
  Copyright (c) 2009 Thomas Sawyer
80
99
 
81
100
  See LICENSE file for details.
82
-
data/bin/lemon CHANGED
@@ -1,3 +1,4 @@
1
1
  #!/usr/bin/env ruby
2
- require 'lemon/command'
3
- Lemon::Command.run
2
+ require 'lemon/cli'
3
+ Lemon::CLI.run(ARGV)
4
+
@@ -0,0 +1,15 @@
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
+
@@ -0,0 +1,32 @@
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
+
@@ -0,0 +1,14 @@
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
+
@@ -0,0 +1,10 @@
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
+
@@ -0,0 +1,5 @@
1
+ require File.dirname(__FILE__) + '/example.rb'
2
+
3
+ ex = Example.new
4
+ ex.f(1,2)
5
+
@@ -0,0 +1,20 @@
1
+ class Example
2
+
3
+ def initialize(a=1)
4
+ @a = a
5
+ end
6
+
7
+ def f(x,y)
8
+ @a * x + y
9
+ end
10
+
11
+ def q(x,y)
12
+ x % y
13
+ end
14
+
15
+ def self.m(a,b)
16
+ a * b
17
+ end
18
+
19
+ end
20
+
data/lib/lemon.rb CHANGED
@@ -1,2 +1,2 @@
1
- require 'lemon/runner'
2
- require 'lemon/coverage'
1
+ require 'lemon/meta/data'
2
+ require 'lemon/controller/coverage_analyzer'
data/lib/lemon/cli.rb ADDED
@@ -0,0 +1,281 @@
1
+ module Lemon
2
+
3
+ require 'lemon/meta/data'
4
+ require 'optparse'
5
+
6
+ # TODO: What about a config file?
7
+
8
+ # CLI Interface handle all lemon sub-commands.
9
+ class CLI
10
+
11
+ COMMANDS = {
12
+ '-t' => 'test' , '--test' => 'test',
13
+ '-c' => 'coverage', '--cov' => 'coverage', '--coverage' => 'coverage',
14
+ '-g' => 'generate', '--gen' => 'generate', '--generate' => 'generate'
15
+ }
16
+
17
+ #
18
+ def self.run(argv=ARGV)
19
+ new.run(argv)
20
+ end
21
+
22
+ #
23
+ def initialize(argv=ARGV)
24
+ @options = {}
25
+ end
26
+
27
+ #
28
+ def options
29
+ @options
30
+ end
31
+
32
+ #
33
+ def run(argv)
34
+ cmdopt = COMMANDS.keys.find{ |k| argv.delete(k) }
35
+ command = COMMANDS[cmdopt]
36
+
37
+ if command.nil? && argv.include?('--help')
38
+ option_commands
39
+ option_parser.parse!(argv)
40
+ end
41
+
42
+ command ||= 'test'
43
+
44
+ #option_commands
45
+
46
+ #cmd = argv.shift
47
+ #cmd = COMMANDS.find{ |c| /^#{cmd}/ =~ c }
48
+ #option_parser.order!(argv)
49
+
50
+ begin
51
+ __send__("#{command}_parse", argv)
52
+ __send__("#{command}", argv)
53
+ rescue => err
54
+ raise err if $DEBUG
55
+ $stderr.puts('ERROR: ' + err.to_s)
56
+ end
57
+ end
58
+
59
+ # T E S T
60
+
61
+ # Run unit tests.
62
+ def test(scripts)
63
+ require 'lemon/controller/test_runner'
64
+
65
+ loadpath = options[:loadpath] || []
66
+ requires = options[:requires] || []
67
+
68
+ loadpath.each{ |path| $LOAD_PATH.unshift(path) }
69
+ requires.each{ |path| require(path) }
70
+
71
+ #suite = Lemon::Test::Suite.new(files, :cover=>cover)
72
+ #runner = Lemon::Runner.new(suite, :format=>format, :cover=>cover, :namespaces=>namespaces)
73
+
74
+ runner = Lemon::TestRunner.new(
75
+ scripts, :format=>options[:format], :namespaces=>options[:namespaces]
76
+ )
77
+
78
+ runner.run
79
+ end
80
+
81
+ #
82
+ def test_parse(argv)
83
+ option_parser.banner = "Usage: lemon [-t] [options] [files ...]"
84
+ #option_parser.separator("Run unit tests.")
85
+
86
+ option_format
87
+ option_verbose
88
+ option_namespaces
89
+ option_loadpath
90
+ option_requires
91
+
92
+ option_parser.parse!(argv)
93
+ end
94
+
95
+ # C O V E R A G E
96
+
97
+ # Ouput coverage report.
98
+ def coverage(test_files)
99
+ require 'lemon/controller/coverage_analyzer'
100
+
101
+ #loadpath = options[:loadpath] || []
102
+ #requires = options[:requires] || []
103
+
104
+ #loadpath.each{ |path| $LOAD_PATH.unshift(path) }
105
+ #requires.each{ |path| require(path) }
106
+
107
+ $stderr.print "Calculating... "
108
+ $stderr.flush
109
+
110
+ cover = Lemon::CoverageAnalyzer.new(test_files, options)
111
+
112
+ cover.calculate # this just helps calcs get done up front
113
+
114
+ $stderr.puts
115
+
116
+ cover.render
117
+ end
118
+
119
+ #
120
+ def coverage_parse(argv)
121
+ option_parser.banner = "Usage: lemon -c [options] [files ...]"
122
+ #option_parser.separator("Check test coverage.")
123
+
124
+ option_namespaces
125
+ option_private
126
+ option_zealous
127
+ option_output
128
+ option_format
129
+ option_loadpath
130
+ option_requires
131
+
132
+ option_parser.parse!(argv)
133
+ end
134
+
135
+ # G E N E R A T E
136
+
137
+ # Generate test templates.
138
+ def generate(test_files)
139
+ require 'lemon/controller/scaffold_generator'
140
+
141
+ loadpath = options[:loadpath] || []
142
+ requires = options[:requires] || []
143
+
144
+ loadpath.each{ |path| $LOAD_PATH.unshift(path) }
145
+ requires.each{ |path| require(path) }
146
+
147
+ #cover = options[:uncovered]
148
+ #suite = Lemon::TestSuite.new(test_files, :cover=>cover) #, :cover_all=>true)
149
+ generator = Lemon::ScaffoldGenerator.new(test_files, options)
150
+
151
+ #if uncovered
152
+ # puts cover.generate_uncovered #(output)
153
+ #else
154
+ puts generator.generate #(output)
155
+ #end
156
+ end
157
+
158
+ #
159
+ def generate_parse(argv)
160
+ option_parser.banner = "Usage: lemon -g [options] [files ...]"
161
+ #option_parser.separator("Generate test scaffolding.")
162
+
163
+ option_namespaces
164
+ option_uncovered
165
+ option_all
166
+ option_private
167
+ option_loadpath
168
+ option_requires
169
+
170
+ option_parser.parse!(argv)
171
+ end
172
+
173
+ # P A R S E R O P T I O N S
174
+
175
+ def option_commands
176
+ option_parser.banner = "Usage: lemon [command] [options] [files ...]"
177
+ option_parser.on('-t', '--test', 'run unit tests [default]') do
178
+ @command = :test
179
+ end
180
+ option_parser.on('-c', '--cov', '--coverage', 'provide test coverage analysis') do
181
+ @command = :coverage
182
+ end
183
+ option_parser.on('-g', '--gen', '--generate', 'generate unit test scaffolding') do
184
+ @command = :generate
185
+ end
186
+ end
187
+
188
+ def option_namespaces
189
+ option_parser.on('-n', '--namespace NAME', 'add a namespace to output') do |name|
190
+ options[:namespaces] ||= []
191
+ options[:namespaces] << name
192
+ end
193
+ end
194
+
195
+ #def option_framework
196
+ # option_parser.on('-f', '--framework NAME', 'framework syntax to output') do |name|
197
+ # options[:framework] = name.to_sym
198
+ # end
199
+ #end
200
+
201
+ def option_format
202
+ option_parser.on('-f', '--format NAME', 'output format') do |name|
203
+ options[:format] = name
204
+ end
205
+ end
206
+
207
+ def option_verbose
208
+ option_parser.on('-v', '--verbose', 'shortcut for `-f verbose`') do |name|
209
+ options[:format] = 'verbose'
210
+ end
211
+ end
212
+
213
+ def option_uncovered
214
+ option_parser.on('-u', '--uncovered', 'include only uncovered units') do
215
+ options[:uncovered] = true
216
+ end
217
+ end
218
+
219
+ def option_all
220
+ option_parser.on('-a', '--all', 'include all namespaces and units') do
221
+ options[:all] = true
222
+ end
223
+ end
224
+
225
+ def option_private
226
+ option_parser.on('-p', '--private', 'include private and protected methods') do
227
+ options[:private] = true
228
+ end
229
+ end
230
+
231
+ def option_zealous
232
+ option_parser.on('-z', '--zealous', 'include undefined case methods') do
233
+ options[:zealous] = true
234
+ end
235
+ end
236
+
237
+ def option_output
238
+ option_parser.on('-o', '--output DIRECTORY', 'log directory') do |dir|
239
+ options[:output] = dir
240
+ end
241
+ end
242
+
243
+ def option_loadpath
244
+ option_parser.on("-I PATH" , 'add directory to $LOAD_PATH') do |path|
245
+ paths = path.split(/[:;]/)
246
+ options[:loadpath] ||= []
247
+ options[:loadpath].concat(paths)
248
+ end
249
+ end
250
+
251
+ def option_requires
252
+ option_parser.on("-r FILE" , 'require file(s) (before doing anything else)') do |files|
253
+ files = files.split(/[:;]/)
254
+ options[:requires] ||= []
255
+ options[:requires].concat(files)
256
+ end
257
+ end
258
+
259
+ def option_parser
260
+ @option_parser ||= (
261
+ OptionParser.new do |opt|
262
+ opt.on_tail("--debug" , 'turn on debugging mode') do
263
+ $DEBUG = true
264
+ end
265
+ opt.on_tail("--about" , 'display information about lemon') do
266
+ puts "Lemon v#{Lemon::VERSION}"
267
+ puts "#{Lemon::COPYRIGHT}"
268
+ exit
269
+ end
270
+ opt.on_tail('-h', '--help', 'display help (also try `<command> --help`)') do
271
+ puts opt
272
+ exit
273
+ end
274
+ end
275
+ )
276
+ end
277
+
278
+ end
279
+
280
+ end
281
+