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).



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.



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.



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) }


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 "\n      WARNING: ChefSpec Coverage reporting is in beta. Please use with caution.\n\n      ChefSpec Coverage report generated at '\#{output}':\n\n        Total Resources:   \#{report[:total]}\n        Touched Resources: \#{report[:touched]}\n        Touch Coverage:    \#{report[:coverage]}%\n\n      Untouched Resources:\n\n      \#{\n        report[:detailed]\n          .select { |_, resource| !resource[:touched] }\n          .sort_by { |_, resource| [resource[:source][:file], resource[:source][:line]] }\n          .map do |name, resource|\n            \"  \#{name} \#{resource[:source][:file]}:\#{resource[:source][:line]}\"\n          end\n          .flatten\n          .join(\"\\n\")\n      }\n\n    EOH\n  end\nend\n".gsub(/^ {10}/, '')