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 CHANGED
@@ -1,6 +1,37 @@
1
1
  = RELEASE HISTORY
2
2
 
3
- == 0.5 / 2009-12-31
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 testcase
10
- construction mirroring the class or module and method design
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, since it helps ensure good test
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
- Say our library consists of the class X:
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
- As tests grow, we need to organize them into concerns. For this
39
- Lemon provides the #Concern method.
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 the <tt>--verbose</tt>
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 -rmyapp test/cases/
67
-
68
-
69
- == Generating Test Skeletons
76
+ $ lemon --coverage -Ilib test/cases/
70
77
 
71
- NOTE: This feature is not yet fully implemented!
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 -rlib/ test/cases/
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
- (LGPL License)
99
+ (MIT License)
93
100
 
94
101
  Copyright (c) 2009 Thomas Sawyer
95
102
 
96
- This program is free software: you can redistribute it and/or modify
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 'optparse'
2
-
3
- #require 'lemon'
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
- # Lemon Command-line tool base class.
9
- class Command
10
-
11
- # Used to map command-line options to command classes.
12
- # This must be overridden in subclasses, and return an
13
- # array of of options, e.g. [ '-g', '--generate'].
14
- def self.options
15
- raise "not implemented"
16
- end
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
- # Factory method to initialize and run choosen sub-command.
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 Commands
2
+ module Command
3
+ require 'lemon/command/abstract'
3
4
 
4
5
  # Lemon Coverage Command-line tool.
5
- class Coverage < Command
6
+ class Coverage < Abstract
6
7
  require 'yaml'
7
8
  require 'lemon/coverage'
8
9
 
9
- def self.options
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 -c [OPTIONS]"
56
- opt.separator("Produce test coverage reports.")
57
- opt.on('--namespace', '-n [NAME]', "include namespace") do |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 do |path|
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
- cover = Lemon::Coverage.new(load_files, namespaces, :public => public_only?)
95
- suite = Lemon::Test::Suite.new(test_files)
96
- puts cover.coverage(suite).to_yaml
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 Commands
2
+ module Command
3
+ require 'lemon/command/abstract'
3
4
 
4
5
  # Lemon Generate Command-line tool.
5
- class Generate < Command
6
+ class Generate < Abstract
6
7
  require 'lemon/coverage'
7
8
 
8
9
  #
9
- def self.options
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
- # Get or set paths to include in $LOAD_PATH.
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 -g [OPTIONS]"
59
- opt.separator("Generate test scaffolding.")
60
- opt.on("--namespace", "-n [NAME]", "include namespace") do |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("--output", "-o [PATH]", "output directory") do |path|
67
- self.output = path
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 do |path|
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
- cover = Lemon::Coverage.new([], namespaces, :public=>public_only?)
100
- suite = Lemon::Test::Suite.new(*test_files)
101
- puts cover.generate(output) #(suite).to_yaml
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