lemon 0.6 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY +32 -1
- data/LICENSE +22 -0
- data/README.rdoc +30 -34
- data/lib/lemon/command.rb +16 -39
- data/lib/lemon/command/abstract.rb +29 -0
- data/lib/lemon/{commands → command}/coverage.rb +13 -14
- data/lib/lemon/{commands → command}/generate.rb +35 -19
- data/lib/lemon/{commands → command}/test.rb +34 -13
- data/lib/lemon/coverage.rb +175 -65
- data/lib/lemon/dsl.rb +15 -2
- data/lib/lemon/kernel.rb +16 -12
- data/lib/lemon/reporter.rb +17 -47
- data/lib/lemon/reporter/abstract.rb +92 -0
- data/lib/lemon/{reporters → reporter}/dotprogress.rb +5 -7
- data/lib/lemon/reporter/outline.rb +105 -0
- data/lib/lemon/reporter/verbose.rb +127 -0
- data/lib/lemon/runner.rb +195 -12
- data/lib/lemon/snapshot.rb +185 -0
- data/lib/lemon/test/case.rb +33 -11
- data/lib/lemon/test/concern.rb +10 -1
- data/lib/lemon/test/suite.rb +128 -22
- data/lib/lemon/test/unit.rb +43 -7
- data/meta/{author → authors} +0 -0
- data/meta/version +1 -1
- data/test/{cases/coverage_case.rb → coverage_case.rb} +4 -6
- data/test/{cases/testcase_case.rb → testcase_case.rb} +1 -1
- metadata +33 -31
- data/COPYING +0 -621
- data/COPYING.LESSER +0 -166
- data/MANIFEST +0 -43
- data/Syckfile +0 -68
- data/lib/lemon/reporters.rb +0 -3
- data/lib/lemon/reporters/verbose.rb +0 -92
data/HISTORY
CHANGED
@@ -1,6 +1,37 @@
|
|
1
1
|
= RELEASE HISTORY
|
2
2
|
|
3
|
-
== 0.
|
3
|
+
== 0.7.0 / 2010-05-04
|
4
|
+
|
5
|
+
This release fixes issue with coverage reports. To do this
|
6
|
+
we have interoduced the +Covers+ method. This allows Lemon
|
7
|
+
to distingush between code that is inteded to be covered
|
8
|
+
by the tests and mere support code.
|
9
|
+
|
10
|
+
Keep in mind that there is no perfect way to handle coverage.
|
11
|
+
Even with the distiction the +Covers+ method provides, coverage
|
12
|
+
might not be reported exactly as desired. Other techinques can
|
13
|
+
be used to refine coverage however, such a preloading embedded
|
14
|
+
support libraries.
|
15
|
+
|
16
|
+
Changes:
|
17
|
+
|
18
|
+
* Add +Covers+ method to solidify coverage reporting.
|
19
|
+
* New Snapshot class improves encapsulation to coverage state.
|
20
|
+
|
21
|
+
|
22
|
+
== 0.6.0 / 2010-03-06
|
23
|
+
|
24
|
+
This release adds coverage reporting to testing and improves
|
25
|
+
the generator.
|
26
|
+
|
27
|
+
Changes:
|
28
|
+
|
29
|
+
* Runner can provide uncovered and undefined testunit list.
|
30
|
+
* Generator can exclude already covered testunits with -u option.
|
31
|
+
* Suite class has Coverage instance.
|
32
|
+
|
33
|
+
|
34
|
+
== 0.5.0 / 2009-12-31
|
4
35
|
|
5
36
|
This is the initial public release of Lemon. Lemon is
|
6
37
|
still under development and should be considered betaware,
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
The MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2009 Thomas Sawyer
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
CHANGED
@@ -1,26 +1,28 @@
|
|
1
1
|
= Lemon
|
2
2
|
|
3
|
-
* http://proutils.github.com/lemon
|
4
|
-
* http://github.com/proutils/lemon
|
3
|
+
* home: http://proutils.github.com/lemon
|
4
|
+
* work: http://github.com/proutils/lemon
|
5
5
|
|
6
6
|
|
7
7
|
== DESCRIPTION
|
8
8
|
|
9
|
-
Lemon is a Unit Testing Framework that enforces a
|
10
|
-
construction mirroring the class
|
9
|
+
Lemon is a Unit Testing Framework that enforces a test case
|
10
|
+
construction mirroring the class/module and method design
|
11
11
|
of the target system. Arguably this promotes the proper
|
12
|
-
technique for unit testing
|
12
|
+
technique for unit testing and helps ensure good test
|
13
13
|
coverage.
|
14
14
|
|
15
15
|
The difference between unit testing and functional testing, and
|
16
16
|
all other forms of testing for that matter, lies in where the
|
17
17
|
*concern* lies. The concern of unit testing are the concerns
|
18
|
-
of unit tests.
|
18
|
+
of unit tests -- the individual methods.
|
19
19
|
|
20
20
|
|
21
21
|
== HOW TO USE
|
22
22
|
|
23
|
-
|
23
|
+
=== Writing Tests
|
24
|
+
|
25
|
+
Say our library 'mylib.rb' consists of the class X:
|
24
26
|
|
25
27
|
class X
|
26
28
|
def a; "a"; end
|
@@ -28,6 +30,8 @@ Say our library consists of the class X:
|
|
28
30
|
|
29
31
|
The simplist test case would be written as follows:
|
30
32
|
|
33
|
+
Covers 'mylib'
|
34
|
+
|
31
35
|
TestCase X do
|
32
36
|
Unit :a => "method #a does something expected" do
|
33
37
|
x = X.new
|
@@ -35,12 +39,17 @@ The simplist test case would be written as follows:
|
|
35
39
|
end
|
36
40
|
end
|
37
41
|
|
38
|
-
|
39
|
-
|
42
|
+
The +Covers+ method works just like +require+ with the exception
|
43
|
+
that loading the file does not occur until just before the tests
|
44
|
+
are run. This allows Lemon to cacluate accurate coverage reports.
|
45
|
+
|
46
|
+
As tests grow, we might need to organize them into special concerns.
|
47
|
+
For this Lemon provides the #Concern method.
|
48
|
+
|
49
|
+
Covers 'mylib'
|
40
50
|
|
41
51
|
TestCase X do
|
42
|
-
Concern "Description of a concern that the following unit"
|
43
|
-
"tests address."
|
52
|
+
Concern "Description of a concern that the following unit tests address."
|
44
53
|
|
45
54
|
Unit :a => "method #a does something expected" do
|
46
55
|
x = X.new
|
@@ -48,27 +57,25 @@ Lemon provides the #Concern method.
|
|
48
57
|
end
|
49
58
|
end
|
50
59
|
|
60
|
+
=== Running Tests
|
61
|
+
|
51
62
|
To run tests use the +lemon+ command-line utility.
|
52
63
|
|
53
64
|
$ lemon test/cases/name_case.rb
|
54
65
|
|
55
|
-
Normal output is typical <i>dot-progress</i>. For verbose output, use
|
56
|
-
or <tt>-v</tt> option.
|
66
|
+
Normal output is typical <i>dot-progress</i>. For verbose output, use
|
67
|
+
the <tt>--verbose</tt> or <tt>-v</tt> option.
|
57
68
|
|
58
69
|
$ lemon -v test/cases/name_case.rb
|
59
70
|
|
60
|
-
|
61
|
-
== Checking Test Coverage
|
71
|
+
=== Checking Test Coverage
|
62
72
|
|
63
73
|
Lemon can check test coverage by loading your target system and
|
64
74
|
comparing it to your tests.
|
65
75
|
|
66
|
-
$ lemon --coverage -Ilib
|
67
|
-
|
68
|
-
|
69
|
-
== Generating Test Skeletons
|
76
|
+
$ lemon --coverage -Ilib test/cases/
|
70
77
|
|
71
|
-
|
78
|
+
=== Generating Test Skeletons
|
72
79
|
|
73
80
|
Because of the one to one correspondance of case-unit to class-method, Lemon can
|
74
81
|
also generate test scaffolding for previously written code. To do this, use the
|
@@ -76,7 +83,7 @@ also generate test scaffolding for previously written code. To do this, use the
|
|
76
83
|
scripts for which to generate test scaffolding, and the output location for
|
77
84
|
the test scripts.
|
78
85
|
|
79
|
-
$ lemon --generate -
|
86
|
+
$ lemon --generate -Ilib test/cases/
|
80
87
|
|
81
88
|
Generating test case scaffodling from code will undoubtedly strike test-driven developers
|
82
89
|
as a case of putting the cart before the horse. However, it is not unreasonable to argue
|
@@ -89,20 +96,9 @@ applications.
|
|
89
96
|
|
90
97
|
== COPYRIGHT
|
91
98
|
|
92
|
-
(
|
99
|
+
(MIT License)
|
93
100
|
|
94
101
|
Copyright (c) 2009 Thomas Sawyer
|
95
102
|
|
96
|
-
|
97
|
-
it under the terms of the Lesser General Public License as published by
|
98
|
-
the Free Software Foundation, either version 3 of the License, or
|
99
|
-
(at your option) any later version.
|
100
|
-
|
101
|
-
This program is distributed in the hope that it will be useful,
|
102
|
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
103
|
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
104
|
-
Lesser General Public License for more details.
|
105
|
-
|
106
|
-
You should have received a copy of the Lesser General Public License
|
107
|
-
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
103
|
+
See LICENSE file for details.
|
108
104
|
|
data/lib/lemon/command.rb
CHANGED
@@ -1,45 +1,22 @@
|
|
1
|
-
require '
|
2
|
-
|
3
|
-
|
4
|
-
#require 'yaml'
|
1
|
+
require 'lemon/command/test'
|
2
|
+
require 'lemon/command/coverage'
|
3
|
+
require 'lemon/command/generate'
|
5
4
|
|
6
5
|
module Lemon
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
# Stores a list of command classes.
|
19
|
-
def self.commands
|
20
|
-
@commands ||= []
|
21
|
-
end
|
22
|
-
|
23
|
-
# When this class is inherited, it is registered to the commands list.
|
24
|
-
def self.inherited(command_class)
|
25
|
-
commands << command_class
|
6
|
+
module Command
|
7
|
+
|
8
|
+
# Factory method to initialize and run choosen sub-command.
|
9
|
+
def self.run
|
10
|
+
cmd = Abstract.commands.find do |command_class|
|
11
|
+
/^#{ARGV.first}/ =~ command_class.subcommand
|
12
|
+
#[command_class.options].flatten.find do |subcmd|
|
13
|
+
# #ARGV.delete(opt)
|
14
|
+
# /^#{ARGV.first}/ =~ subcmd
|
15
|
+
#end
|
26
16
|
end
|
27
|
-
|
28
|
-
|
29
|
-
def self.run
|
30
|
-
cmd = commands.find do |command_class|
|
31
|
-
[command_class.options].flatten.find do |opt|
|
32
|
-
ARGV.delete(opt)
|
33
|
-
end
|
34
|
-
end
|
35
|
-
cmd ? cmd.run : Commands::Test.run
|
36
|
-
end
|
37
|
-
|
17
|
+
ARGV.shift if cmd
|
18
|
+
cmd ? cmd.run : Command::Test.run
|
38
19
|
end
|
39
20
|
|
40
21
|
end
|
41
|
-
|
42
|
-
require 'lemon/commands/test'
|
43
|
-
require 'lemon/commands/coverage'
|
44
|
-
require 'lemon/commands/generate'
|
45
|
-
|
22
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Lemon
|
2
|
+
module Command
|
3
|
+
require 'optparse'
|
4
|
+
|
5
|
+
# Lemon Command-line tool base class.
|
6
|
+
class Abstract
|
7
|
+
|
8
|
+
# Used to map command-line options to command classes.
|
9
|
+
# This must be overridden in subclasses, and return an
|
10
|
+
# array of of options, e.g. [ '-g', '--generate'].
|
11
|
+
def self.options
|
12
|
+
raise "not implemented"
|
13
|
+
end
|
14
|
+
|
15
|
+
# Stores a list of command classes.
|
16
|
+
def self.commands
|
17
|
+
@commands ||= []
|
18
|
+
end
|
19
|
+
|
20
|
+
# When this class is inherited, it is registered to the commands list.
|
21
|
+
def self.inherited(command_class)
|
22
|
+
commands << command_class
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
@@ -1,13 +1,14 @@
|
|
1
1
|
module Lemon
|
2
|
-
module
|
2
|
+
module Command
|
3
|
+
require 'lemon/command/abstract'
|
3
4
|
|
4
5
|
# Lemon Coverage Command-line tool.
|
5
|
-
class Coverage <
|
6
|
+
class Coverage < Abstract
|
6
7
|
require 'yaml'
|
7
8
|
require 'lemon/coverage'
|
8
9
|
|
9
|
-
def self.
|
10
|
-
['-c', '--coverage']
|
10
|
+
def self.subcommand
|
11
|
+
'coverage' #['-c', '--coverage']
|
11
12
|
end
|
12
13
|
|
13
14
|
# Initialize and run.
|
@@ -52,9 +53,9 @@ module Commands
|
|
52
53
|
# Instance of OptionParser.
|
53
54
|
def parser
|
54
55
|
@parser ||= OptionParser.new do |opt|
|
55
|
-
opt.banner = "lemon
|
56
|
-
opt.separator("Produce test coverage
|
57
|
-
opt.on('--namespace', '-n [NAME]', "
|
56
|
+
opt.banner = "lemon coverage [OPTIONS]"
|
57
|
+
opt.separator("Produce test coverage report.")
|
58
|
+
opt.on('--namespace', '-n [NAME]', "limit coverage to this namespace") do |name|
|
58
59
|
namespaces(name)
|
59
60
|
end
|
60
61
|
opt.on('--public', '-p', "only include public methods") do
|
@@ -85,15 +86,13 @@ module Commands
|
|
85
86
|
test_files = ARGV.dup
|
86
87
|
load_files = []
|
87
88
|
|
88
|
-
includes.each
|
89
|
-
$LOAD_PATHS.unshift(path)
|
90
|
-
end
|
91
|
-
|
89
|
+
includes.each{ |path| $LOAD_PATH.unshift(path) }
|
92
90
|
requires.each{ |path| require(path) }
|
93
91
|
|
94
|
-
|
95
|
-
|
96
|
-
|
92
|
+
suite = Lemon::Test::Suite.new(test_files, :cover=>true)
|
93
|
+
coverage = Lemon::Coverage.new(suite, namespaces, :public => public_only?)
|
94
|
+
|
95
|
+
puts coverage.checklist.to_yaml
|
97
96
|
end
|
98
97
|
|
99
98
|
end
|
@@ -1,13 +1,14 @@
|
|
1
1
|
module Lemon
|
2
|
-
module
|
2
|
+
module Command
|
3
|
+
require 'lemon/command/abstract'
|
3
4
|
|
4
5
|
# Lemon Generate Command-line tool.
|
5
|
-
class Generate <
|
6
|
+
class Generate < Abstract
|
6
7
|
require 'lemon/coverage'
|
7
8
|
|
8
9
|
#
|
9
|
-
def self.
|
10
|
-
['-g', '--generate']
|
10
|
+
def self.subcommand
|
11
|
+
'generate' #['-g', '--generate']
|
11
12
|
end
|
12
13
|
|
13
14
|
# Initialize and run.
|
@@ -21,19 +22,28 @@ module Commands
|
|
21
22
|
@includes = []
|
22
23
|
@namespaces = []
|
23
24
|
@public_only = false
|
25
|
+
@uncovered = false
|
24
26
|
end
|
25
27
|
|
26
|
-
#
|
27
|
-
attr_accessor :output
|
28
|
+
# TODO: Support output ? perhaps complex scaffolding
|
29
|
+
#attr_accessor :output
|
28
30
|
|
29
31
|
#
|
30
32
|
attr_accessor :public_only
|
31
33
|
|
34
|
+
#
|
35
|
+
attr_accessor :uncovered
|
36
|
+
|
32
37
|
#
|
33
38
|
def public_only?
|
34
39
|
@public_only
|
35
40
|
end
|
36
41
|
|
42
|
+
#
|
43
|
+
def uncovered_only?
|
44
|
+
@uncovered
|
45
|
+
end
|
46
|
+
|
37
47
|
# Get or set librarires to pre-require.
|
38
48
|
def requires(*paths)
|
39
49
|
@requires.concat(paths) unless paths.empty?
|
@@ -46,7 +56,7 @@ module Commands
|
|
46
56
|
@includes
|
47
57
|
end
|
48
58
|
|
49
|
-
#
|
59
|
+
#
|
50
60
|
def namespaces(*names)
|
51
61
|
@namespaces.concat(names) unless names.empty?
|
52
62
|
@namespaces
|
@@ -55,17 +65,20 @@ module Commands
|
|
55
65
|
# Instance of OptionParser.
|
56
66
|
def parser
|
57
67
|
@parser ||= OptionParser.new do |opt|
|
58
|
-
opt.banner = "lemon
|
59
|
-
opt.separator("Generate test scaffolding.")
|
60
|
-
opt.on("--namespace", "-n [NAME]", "
|
68
|
+
opt.banner = "lemon generate [OPTIONS]"
|
69
|
+
opt.separator("Generate unit test scaffolding.")
|
70
|
+
opt.on("--namespace", "-n [NAME]", "limit tests to this namespace") do |name|
|
61
71
|
namespaces(name)
|
62
72
|
end
|
63
73
|
opt.on("--public", "-p", "only include public methods") do
|
64
74
|
self.public_only = true
|
65
75
|
end
|
66
|
-
opt.on("--
|
67
|
-
self.
|
76
|
+
opt.on("--uncovered", "-u", "only include uncovered methods") do
|
77
|
+
self.uncovered = true
|
68
78
|
end
|
79
|
+
#opt.on("--output", "-o [PATH]", "output directory") do |path|
|
80
|
+
# self.output = path
|
81
|
+
#end
|
69
82
|
opt.on("-r [FILES]" , "library files to require") do |files|
|
70
83
|
files = files.split(/[:;]/)
|
71
84
|
requires(*files)
|
@@ -90,15 +103,18 @@ module Commands
|
|
90
103
|
|
91
104
|
test_files = ARGV.dup
|
92
105
|
|
93
|
-
includes.each
|
94
|
-
$LOAD_PATHS.unshift(path)
|
95
|
-
end
|
96
|
-
|
106
|
+
includes.each{ |path| $LOAD_PATH.unshift(path) }
|
97
107
|
requires.each{ |path| require(path) }
|
98
108
|
|
99
|
-
|
100
|
-
|
101
|
-
|
109
|
+
suite = Lemon::Test::Suite.new(test_files, :cover=>true)
|
110
|
+
cover = Lemon::Coverage.new(suite, namespaces, :public=>public_only?)
|
111
|
+
#cover = Lemon::Coverage.new([], namespaces, :public=>public_only?, :uncovered=>uncovered_only?)
|
112
|
+
|
113
|
+
if uncovered_only?
|
114
|
+
puts cover.generate_uncovered #(output)
|
115
|
+
else
|
116
|
+
puts cover.generate #(output)
|
117
|
+
end
|
102
118
|
end
|
103
119
|
|
104
120
|
end
|