Class: ChefSpec::Coverage

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Includes:
Singleton
Defined in:
lib/chefspec/coverage.rb

Defined Under Namespace

Classes: ResourceWrapper

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeCoverage

Create a new coverage object singleton.



16
17
18
19
# File 'lib/chefspec/coverage.rb', line 16

def initialize
  @collection = {}
  @filters = []
end

Instance Attribute Details

#filtersObject

Returns the value of attribute filters.



4
5
6
# File 'lib/chefspec/coverage.rb', line 4

def filters
  @filters
end

Instance Method Details

#add(resource) ⇒ Object

Add a resource to the resource collection. Only new resources are added and only resources that match the given filter are covered (which is * by default).

Parameters:



28
29
30
31
32
# File 'lib/chefspec/coverage.rb', line 28

def add(resource)
  if !exists?(resource) && filtered?(resource)
    @collection[resource.to_s] = ResourceWrapper.new(resource)
  end
end

#cover!(resource) ⇒ Object

Called when a resource is matched to indicate it has been tested.

Parameters:



39
40
41
42
43
# File 'lib/chefspec/coverage.rb', line 39

def cover!(resource)
  if filtered?(resource) && (wrapper = find(resource))
    wrapper.touch!
  end
end

#filtered?(resource) ⇒ Boolean

Called to check if a resource belongs to a cookbook from the specified directories.

Parameters:

Returns:

  • (Boolean)


51
52
53
# File 'lib/chefspec/coverage.rb', line 51

def filtered?(resource)
  filters.empty? || filters.any? { |f| resource.source_line =~/^#{f}/ }
end

#report!(output = '.coverage/results.json', announce = true) ⇒ Object

Generate a coverage report. This report must be generated at_exit or else the entire resource collection may not be complete!

Examples:

Generating a report


at_exit { ChefSpec::Coverage.report! }

Generating a custom report without announcing


at_exit { ChefSpec::Coverage.report!('/custom/path', false) }

Parameters:

  • output (String) (defaults to: '.coverage/results.json')

    the path to output the report on disk (default: ‘.coverage/results.json’)

  • announce (Boolean) (defaults to: true)

    print the results to standard out



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/chefspec/coverage.rb', line 73

def report!(output = '.coverage/results.json', announce = true)
  report = {}

  report[:total] = @collection.size
  report[:touched] = @collection.count { |_, resource| resource.touched? }
  report[:untouched] = report[:total] - report[:touched]
  report[:coverage] = ((report[:touched].to_f/report[:total].to_f)*100).round(2)

  report[:detailed] = Hash[*@collection.map do |name, wrapper|
    [name, wrapper.to_hash]
  end.flatten]

  output = File.expand_path(output)
  FileUtils.mkdir_p(File.dirname(output))
  File.open(File.join(output), 'w') do |f|
    f.write(JSON.pretty_generate(report) + "\n")
  end

  if announce
    puts <<-EOH.gsub(/^ {10}/, '')

      WARNING: ChefSpec Coverage reporting is in beta. Please use with caution.

      ChefSpec Coverage report generated at '#{output}':

        Total Resources:   #{report[:total]}
        Touched Resources: #{report[:touched]}
        Touch Coverage:    #{report[:coverage]}%

      Untouched Resources:

      #{
        report[:detailed]
          .select { |_, resource| !resource[:touched] }
          .sort_by { |_, resource| [resource[:source][:file], resource[:source][:line]] }
          .map do |name, resource|
            "  #{name} #{resource[:source][:file]}:#{resource[:source][:line]}"
          end
          .flatten
          .join("\n")
      }

    EOH
  end
end