lemon 0.6 → 0.7.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.
- 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
|