lemon 0.8.1 → 0.8.2
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.
- data/HISTORY.rdoc +15 -0
- data/README.rdoc +32 -14
- data/bin/lemon +3 -2
- data/demo/case_example_fail.rb +15 -0
- data/demo/case_example_pass.rb +32 -0
- data/demo/case_example_pending.rb +14 -0
- data/demo/case_example_untested.rb +10 -0
- data/demo/fixture/example-use.rb +5 -0
- data/demo/fixture/example.rb +20 -0
- data/lib/lemon.rb +2 -2
- data/lib/lemon/cli.rb +281 -0
- data/lib/lemon/controller/coverage_analyzer.rb +343 -0
- data/lib/lemon/controller/scaffold_generator.rb +110 -0
- data/lib/lemon/controller/test_runner.rb +284 -0
- data/lib/lemon/meta/data.rb +29 -0
- data/lib/lemon/meta/gemfile +24 -0
- data/{PROFILE → lib/lemon/meta/profile} +6 -5
- data/lib/lemon/model/ae.rb +4 -0
- data/lib/lemon/model/cover_unit.rb +75 -0
- data/lib/lemon/{dsl.rb → model/main.rb} +22 -28
- data/lib/lemon/model/pending.rb +10 -0
- data/lib/lemon/model/snapshot.rb +203 -0
- data/lib/lemon/model/source_parser.rb +198 -0
- data/lib/lemon/model/test_case.rb +221 -0
- data/lib/lemon/model/test_context.rb +90 -0
- data/lib/lemon/model/test_suite.rb +216 -0
- data/lib/lemon/{test/unit.rb → model/test_unit.rb} +40 -28
- data/lib/lemon/{coversheet → view/cover_reports}/abstract.rb +19 -20
- data/lib/lemon/view/cover_reports/compact.rb +37 -0
- data/lib/lemon/view/cover_reports/outline.rb +45 -0
- data/lib/lemon/view/cover_reports/verbose.rb +51 -0
- data/lib/lemon/view/cover_reports/yaml.rb +15 -0
- data/lib/lemon/view/test_reports/abstract.rb +149 -0
- data/lib/lemon/view/test_reports/dotprogress.rb +73 -0
- data/lib/lemon/view/test_reports/html.rb +146 -0
- data/lib/lemon/view/test_reports/outline.rb +118 -0
- data/lib/lemon/view/test_reports/summary.rb +131 -0
- data/lib/lemon/view/test_reports/tap.rb +49 -0
- data/lib/lemon/view/test_reports/verbose.rb +197 -0
- data/meta/data.rb +29 -0
- data/meta/gemfile +24 -0
- data/meta/profile +17 -0
- data/test/api/applique/fs.rb +18 -0
- data/test/api/coverage/complete.rdoc +136 -0
- data/test/api/coverage/extensions.rdoc +61 -0
- data/test/api/coverage/incomplete.rdoc +97 -0
- data/{features → test/cli}/coverage.feature +4 -4
- data/{features → test/cli}/generate.feature +2 -2
- data/{features → test/cli}/step_definitions/coverage_steps.rb +0 -0
- data/{features → test/cli}/support/ae.rb +0 -0
- data/{features → test/cli}/support/aruba.rb +0 -0
- data/{features → test/cli}/test.feature +0 -0
- data/test/fixtures/case_complete.rb +17 -4
- data/test/fixtures/case_inclusion.rb +18 -0
- data/test/fixtures/case_incomplete.rb +4 -4
- data/test/fixtures/example.rb +5 -0
- data/test/fixtures/helper.rb +13 -0
- data/test/runner +3 -0
- data/test/unit/case_coverage_analyzer.rb +25 -0
- data/test/unit/case_test_case_dsl.rb +46 -0
- metadata +87 -42
- data/REQUIRE +0 -9
- data/VERSION +0 -6
- data/lib/lemon/command.rb +0 -184
- data/lib/lemon/coverage.rb +0 -260
- data/lib/lemon/coversheet/outline.rb +0 -47
- data/lib/lemon/kernel.rb +0 -24
- data/lib/lemon/reporter.rb +0 -22
- data/lib/lemon/reporter/abstract.rb +0 -97
- data/lib/lemon/reporter/dotprogress.rb +0 -68
- data/lib/lemon/reporter/outline.rb +0 -105
- data/lib/lemon/reporter/verbose.rb +0 -143
- data/lib/lemon/runner.rb +0 -308
- data/lib/lemon/snapshot.rb +0 -185
- data/lib/lemon/test/case.rb +0 -139
- data/lib/lemon/test/concern.rb +0 -52
- data/lib/lemon/test/suite.rb +0 -229
- data/test/case_coverage.rb +0 -26
- 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
|
-
|
26
|
+
covers 'mylib'
|
27
27
|
|
28
|
-
|
29
|
-
|
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
|
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
|
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
|
-
|
39
|
+
covers 'mylib'
|
40
40
|
|
41
|
-
|
42
|
-
|
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
|
-
|
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
|
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
|
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
|
-
(
|
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
@@ -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
|
+
|
data/lib/lemon.rb
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
require 'lemon/
|
2
|
-
require 'lemon/
|
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
|
+
|