Class: Covered::Coverage

Inherits:
Object
  • Object
show all
Includes:
Ratio
Defined in:
lib/covered/coverage.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Ratio

#complete?, #percentage, #ratio

Constructor Details

#initialize(source, counts = [], annotations = {}) ⇒ Coverage

Returns a new instance of Coverage.



32
33
34
35
36
# File 'lib/covered/coverage.rb', line 32

def initialize(source, counts = [], annotations = {})
  @source = source
  @counts = counts
  @annotations = annotations
end

Instance Attribute Details

#annotationsObject (readonly)

Returns the value of attribute annotations.



40
41
42
# File 'lib/covered/coverage.rb', line 40

def annotations
  @annotations
end

#countsObject (readonly)

Returns the value of attribute counts.



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

def counts
  @counts
end

#sourceObject

Returns the value of attribute source.



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

def source
  @source
end

Class Method Details

.deserialize(unpacker) ⇒ Object



190
191
192
193
194
195
196
# File 'lib/covered/coverage.rb', line 190

def self.deserialize(unpacker)
  source = unpacker.read
  counts = unpacker.read
  annotations = unpacker.read
  
  self.new(source, counts, annotations)
end

.for(path, **options) ⇒ Object



28
29
30
# File 'lib/covered/coverage.rb', line 28

def self.for(path, **options)
  self.new(Source.for(path, **options))
end

Instance Method Details

#[](line_number) ⇒ Object



143
144
145
# File 'lib/covered/coverage.rb', line 143

def [] line_number
  @counts[line_number]
end

#annotate(line_number, annotation) ⇒ Object



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

def annotate(line_number, annotation)
  @annotations[line_number] ||= []
  @annotations[line_number] << annotation
end

#as_jsonObject



175
176
177
178
179
180
181
182
# File 'lib/covered/coverage.rb', line 175

def as_json
  {
    counts: counts,
    executable_count: executable_count,
    executed_count: executed_count,
    percentage: percentage.to_f.round(2),
  }
end

#emptyObject

Create an empty coverage with the same source.



47
48
49
# File 'lib/covered/coverage.rb', line 47

def empty
  self.class.new(@source, [nil] * @counts.size)
end

#executable_countObject



151
152
153
# File 'lib/covered/coverage.rb', line 151

def executable_count
  executable_lines.count
end

#executable_linesObject



147
148
149
# File 'lib/covered/coverage.rb', line 147

def executable_lines
  @counts.compact
end

#executed_countObject



159
160
161
# File 'lib/covered/coverage.rb', line 159

def executed_count
  executed_lines.count
end

#executed_linesObject



155
156
157
# File 'lib/covered/coverage.rb', line 155

def executed_lines
  executable_lines.reject(&:zero?)
end

#for_lines(line_numbers) ⇒ Object

Construct a new coverage object for the given line numbers. Only the given line numbers will be considered for the purposes of computing coverage.



86
87
88
89
90
91
92
93
# File 'lib/covered/coverage.rb', line 86

def for_lines(line_numbers)
  counts = [nil] * @counts.size
  line_numbers.each do |line_number|
    counts[line_number] = @counts[line_number]
  end
  
  self.class.new(@source, counts, @annotations)
end

#freezeObject



126
127
128
129
130
131
132
133
# File 'lib/covered/coverage.rb', line 126

def freeze
  return self if frozen?
  
  @counts.freeze
  @annotations.freeze
  
  super
end

#fresh?Boolean

Returns:

  • (Boolean)


103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/covered/coverage.rb', line 103

def fresh?
  if @source.modified_time.nil?
    # We don't know when the file was last modified, so we assume it is stale:
    return false
  end
  
  unless File.exist?(@source.path)
    # The file no longer exists, so we assume it is stale:
    return false
  end
  
  if @source.modified_time >= File.mtime(@source.path)
    # The file has not been modified since we last processed it, so we assume it is fresh:
    return true
  end
  
  return false
end

#mark(line_number, value = 1) ⇒ Object



56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/covered/coverage.rb', line 56

def mark(line_number, value = 1)
  # As currently implemented, @counts is base-zero rather than base-one.
  # Line numbers generally start at line 1, so the first line, line 1, is at index 1. This means that index[0] is usually nil.
  Array(value).each_with_index do |value, index|
    offset = line_number + index
    if @counts[offset]
      @counts[offset] += value
    else
      @counts[offset] = value
    end
  end
end

#merge!(other) ⇒ Object



69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/covered/coverage.rb', line 69

def merge!(other)
  # If the counts are non-zero and don't match, that can indicate a problem.
  
  other.counts.each_with_index do |count, index|
    if count
      @counts[index] ||= 0
      @counts[index] += count
    end
  end
  
  @annotations.merge!(other.annotations) do |line_number, a, b|
    Array(a) + Array(b)
  end
end

#missing_countObject



163
164
165
# File 'lib/covered/coverage.rb', line 163

def missing_count
  executable_count - executed_count
end

#pathObject



95
96
97
# File 'lib/covered/coverage.rb', line 95

def path
  @source.path
end

#path=(value) ⇒ Object



99
100
101
# File 'lib/covered/coverage.rb', line 99

def path= value
  @source.path = value
end


167
168
169
# File 'lib/covered/coverage.rb', line 167

def print(output)
  output.puts "** #{executed_count}/#{executable_count} lines executed; #{percentage.to_f.round(2)}% covered."
end

#read(&block) ⇒ Object



122
123
124
# File 'lib/covered/coverage.rb', line 122

def read(&block)
  @source.read(&block)
end

#serialize(packer) ⇒ Object



184
185
186
187
188
# File 'lib/covered/coverage.rb', line 184

def serialize(packer)
  packer.write(@source)
  packer.write(@counts)
  packer.write(@annotations)
end

#to_aObject



135
136
137
# File 'lib/covered/coverage.rb', line 135

def to_a
  @counts
end

#to_sObject



171
172
173
# File 'lib/covered/coverage.rb', line 171

def to_s
  "\#<#{self.class} path=#{self.path} #{self.percentage.to_f.round(2)}% covered>"
end

#totalObject



42
43
44
# File 'lib/covered/coverage.rb', line 42

def total
  counts.sum{|count| count || 0}
end

#zero?Boolean

Returns:

  • (Boolean)


139
140
141
# File 'lib/covered/coverage.rb', line 139

def zero?
  total.zero?
end