lib/lemon/coverage.rb in lemon-0.6 vs lib/lemon/coverage.rb in lemon-0.7.0
- old
+ new
@@ -1,73 +1,103 @@
+require 'lemon/snapshot'
+
module Lemon
#
class Coverage
+ #
+ attr :suite
+
# Paths of lemon tests and/or ruby scripts to be compared and covered.
# This can include directories too, in which case all .rb scripts below
# then directory will be included.
attr :files
- # Conical snapshot of system (before loading libraries to be covered).
- attr :conical
+ ## Conical snapshot of system (before loading libraries to be covered).
+ #attr :canonical
#
attr :namespaces
+ ## New Coverage object.
+ ##
+ ## Coverage.new('lib/', :MyApp, :public => true)
+ ##
+ #def initialize(suite_or_files, namespaces=nil, options={})
+ # @namespaces = namespaces || []
+ # case suite_or_files
+ # when Test::Suite
+ # @suite = suite_or_files
+ # @files = suite_or_files.files
+ # else
+ # @suite = Test::Suite.new(suite_or_files)
+ # @files = suite_or_files
+ # end
+ # #@canonical = @suite.canonical
+ # @public = options[:public]
+ #end
+
# New Coverage object.
#
# Coverage.new('lib/', :MyApp, :public => true)
#
- def initialize(files, namespaces=nil, options={})
- @namespaces = namespaces || []
+ def initialize(suite, namespaces=nil, options={})
+ @namespaces = [namespaces].flatten.compact
+ @suite = suite
+ @files = suite.files
+ #@canonical = @suite.canonical
+ @public = options[:public]
+ end
- @files = files
- @conical = snapshot
+ ##
+ #def canonical!
+ # @canonical = Snapshot.capture
+ #end
- @public = options[:public]
-
- # this must come after concial snapshot
- @suite = Test::Suite.new(files)
+ #
+ def suite=(suite)
+ raise ArgumentError unless Test::Suite === suite
+ @suite = suite
end
# Over use public methods for coverage.
def public_only?
@public
end
+ #
+ def each(&block)
+ checklist.each(&block)
+ end
+
# Produce a coverage map.
- def coverage(suite)
- checklist = cover()
+ #def checklist
+ # list = system.checklist
+ # suite.each do |testcase|
+ # testcase.testunits.each do |testunit|
+ # list[testcase.target.name][testunit.key] = true
+ # end
+ # end
+ # list
+ #end
+
+ # Produce a coverage checklist.
+ def checklist
+ list = system.checklist
suite.each do |testcase|
testcase.testunits.each do |testunit|
- checklist[testcase.target.name][testunit.target.to_s] = true
+ list[testcase.target.name][testunit.key] = true
end
end
- checklist
+ list
end
- # Coverage template.
- def cover
- cover = Hash.new{|h,k|h[k]={}}
- system.each do |base|
- next if base.is_a?(Lemon::Test::Suite)
- cover[base.name] = {}
- base.public_instance_methods(false).each do |meth|
- cover[base.name][meth.to_s] = false
- end
- unless public_only?
- base.private_instance_methods(false).each do |meth|
- cover[base.name][meth.to_s] = false
- end
- base.protected_instance_methods(false).each do |meth|
- cover[base.name][meth.to_s] = false
- end
- end
- end
- cover
- end
+# #
+# def load_covered_files
+# suite.load_covered_files
+# end
# Iterate over +paths+ and use #load to bring in all +.rb+ scripts.
#def load_system
# files = []
# paths.map do |path|
@@ -78,58 +108,138 @@
# end
# end
# files.each{ |file| load(file) }
#end
- # System to be covered. This takes a sanpshot of the system
- # and then removes the conical snapshot, and then filters out
- # the namespace.
+# # Snapshot of System to be covered. This takes a current snapshot
+# # of the system and removes the canonical snapshot or filters out
+# # everything but the selected namespace.
+# def system
+# if namespaces.empty?
+# snapshot - canonical
+# else
+# (snapshot - canonical).filter do |ofmod|
+# namespaces.any?{ |n| ofmod.name.start_with?(n.to_s) }
+# end
+# end
+# end
+
+ # List of modules/classes not covered.
+ def uncovered_cases
+ c = suite.coverage.map{ |ofmod| ofmod.base }
+ a = suite.testcases.map{ |tc| tc.target }
+ c - a
+ end
+
+ # List of methods not covered by covered cases.
+ def uncovered_units
+ @calculated ||= calculate_coverage
+ @uncovered_units
+ end
+
#
- # TODO: Perhaps get rid of the conical subtraction and require a namespace?
+ def undefined_units
+ @calculated ||= calculate_coverage
+ @undefined_units
+ end
+
+ #
+ def calculate_coverage
+ clist = []
+ tlist = []
+ suite.testcases.each do |tc|
+ mod = tc.target
+
+ metaunits, units = *tc.testunits.partition{ |u| u.meta? }
+
+ units.map!{ |u| u.fullname }
+ metaunits.map!{ |u| u.fullname }
+
+ tlist = tlist | units
+ tlist = tlist | metaunits
+
+ if system[mod]
+ meths = system[mod].instance_methods.map{ |m| "#{mod}##{m}" }
+ metameths = system[mod].class_methods.map{ |m| "#{mod}.#{m}" }
+
+ clist = clist | meths
+ clist = clist | metameths
+ end
+ end
+ @uncovered_units = clist - tlist
+ @undefined_units = tlist - clist
+ end
+
+ #
def system
if namespaces.empty?
- snapshot - conical
+ suite.coverage
else
- snapshot.select do |m|
- namespaces.any?{ |n| m.name.start_with?(n) }
+ suite.coverage.filter do |ofmod|
+ namespaces.any?{ |n| ofmod.name.start_with?(n.to_s) }
end
end
end
- # Produces a list of all existent Modules and Classes.
- def snapshot
- sys = []
- #ObjectSpace.each_object(Class) do |c|
- # sys << c
- #end
- ObjectSpace.each_object(Module) do |m|
- sys << m
+ # Generate code template.
+ #
+ # TODO: support output
+ def generate(output=nil)
+ code = []
+
+ system.each do |ofmod|
+ next if ofmod.base.is_a?(Lemon::Test::Suite)
+
+ code << "TestCase #{ofmod.base} do"
+
+ ofmod.class_methods(public_only?).each do |meth|
+ code << "\n MetaUnit :#{meth} => '' do\n raise Pending\n end"
+ end
+
+ ofmod.instance_methods(public_only?).each do |meth|
+ code << "\n Unit :#{meth} => '' do\n raise Pending\n end"
+ end
+
+ code << "\nend\n"
end
- sys
+
+ code.join("\n")
end
- # TODO: combine with coverage to provided option to do only do what hasn't been covered thus far.
- # TODO: support output directory
-
- def generate(output=nil)
+ #
+ def generate_uncovered(output=nil)
code = []
- system.each do |base|
- next if base.is_a?(Lemon::Test::Suite)
+ checklist.each do |base, methods|
+ next if /Lemon::Test::Suite/ =~ base.to_s
code << "TestCase #{base} do"
- base.public_instance_methods(false).each do |meth|
- code << "\n Unit :#{meth} => '' do\n pending\n end"
- end
- unless public_only?
- base.private_instance_methods(false).each do |meth|
- code << "\n Unit :#{meth} => '' do\n pending\n end"
+ methods.each do |meth, covered|
+ next if covered
+ if meth.to_s =~ /^\:\:/
+ meth = meth.sub('::','')
+ code << "\n MetaUnit :#{meth} => '' do\n raise Pending\n end"
+ else
+ code << "\n Unit :#{meth} => '' do\n raise Pending\n end"
end
- base.protected_instance_methods(false).each do |meth|
- code << "\n Unit :#{meth} => '' do\n pending\n end"
- end
end
+ #base.public_instance_methods(false).each do |meth|
+ # code << "\n Unit :#{meth} => '' do\n Pending\n end"
+ #end
+ #unless public_only?
+ # base.private_instance_methods(false).each do |meth|
+ # code << "\n Unit :#{meth} => '' do\n Pending\n end"
+ # end
+ # base.protected_instance_methods(false).each do |meth|
+ # code << "\n Unit :#{meth} => '' do\n Pending\n end"
+ # end
+ #end
code << "\nend\n"
end
code.join("\n")
+ end
+
+ # Get a snapshot of the system.
+ def snapshot
+ Snapshot.capture
end
end#class Coverage
end#module Lemon