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