Class: ChefSpec::Coverage

Inherits:
Object
  • Object
show all
Includes:
Singleton
Defined in:
lib/chefspec/coverage.rb,
lib/chefspec/coverage/filters.rb

Defined Under Namespace

Classes: BerkshelfFilter, BlockFilter, Filter, RegexpFilter, ResourceWrapper, StringFilter

Constant Summary collapse

EXIT_FAILURE =
1
EXIT_SUCCESS =
0

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeCoverage

Create a new coverage object singleton.



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

def initialize
  @collection = {}
  @filters    = {}
  @template = ChefSpec.root.join('templates', 'coverage', 'human.erb')
end

Instance Attribute Details

#filtersObject (readonly)

Returns the value of attribute filters.



23
24
25
# File 'lib/chefspec/coverage.rb', line 23

def filters
  @filters
end

Class Method Details

.method_added(name) ⇒ Object



9
10
11
12
13
14
15
16
17
18
# File 'lib/chefspec/coverage.rb', line 9

def method_added(name)
  # Only delegate public methods
  if method_defined?(name)
    instance_eval <<-EOH, __FILE__, __LINE__ + 1
      def #{name}(*args, &block)
        instance.public_send(:#{name}, *args, &block)
      end
    EOH
  end
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:



98
99
100
101
102
# File 'lib/chefspec/coverage.rb', line 98

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

#add_filter(filter = nil, &block) ⇒ true

Add a filter to the converage analysis.

Parameters:

  • (defaults to: nil)

    the filter to add

  • the block to use as a filter

Returns:



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/chefspec/coverage.rb', line 53

def add_filter(filter = nil, &block)
  id = "#{filter.inspect}/#{block.inspect}".hash

  @filters[id] = if filter.kind_of?(Filter)
                   filter
                 elsif filter.kind_of?(String)
                   StringFilter.new(filter)
                 elsif filter.kind_of?(Regexp)
                   RegexpFilter.new(filter)
                 elsif block
                   BlockFilter.new(block)
                 else
                   raise ArgumentError, 'Please specify either a string, ' \
                     'filter, or block to filter source files with!'
                 end

  true
end

#cover!(resource) ⇒ Object

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

Parameters:



109
110
111
112
113
# File 'lib/chefspec/coverage.rb', line 109

def cover!(resource)
  if 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:



121
122
123
# File 'lib/chefspec/coverage.rb', line 121

def filtered?(resource)
  filters.any? { |_, filter| filter.matches?(resource) }
end

#report!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


ChefSpec::Coverage.report!


133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# File 'lib/chefspec/coverage.rb', line 133

def report!
  # Borrowed from simplecov#41
  #
  # If an exception is thrown that isn't a "SystemExit", we need to capture
  # that error and re-raise.
  if $!
    exit_status = $!.is_a?(SystemExit) ? $!.status : EXIT_FAILURE
  else
    exit_status = EXIT_SUCCESS
  end

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

  report[:untouched_resources] = @collection.collect do |_, resource|
    resource unless resource.touched?
  end.compact
  report[:all_resources] = @collection.values
  
  begin
    erb = Erubis::Eruby.new(File.read(@template))
    puts erb.evaluate(report)
  rescue NameError => e
    raise Error::ErbTemplateParseError.new(original_error: e.message)
  end

  # Ensure we exit correctly (#351)
  Kernel.exit(exit_status) if exit_status && exit_status > 0
end

#set_template(file = 'human.erb') ⇒ true

Change the template for reporting of converage analysis.

Raises:

Parameters:

  • The template file to use for the output of the report

Returns:



79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/chefspec/coverage.rb', line 79

def set_template(file = 'human.erb')
  [
    ChefSpec.root.join('templates', 'coverage', file),
    File.expand_path(file, Dir.pwd)
  ].each do |temp|
    if File.exist?(temp)
      @template = temp
      return
    end
  end
  raise Error::TemplateNotFound.new(path: file)
end

#start!(&block) ⇒ Object

Start the coverage reporting analysis. This method also adds the the at_exit handler for printing the coverage report.



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

def start!(&block)
  instance_eval(&block) if block
  at_exit { ChefSpec::Coverage.report! }
end