class Covet::LogFile

Represents log file of JSON coverage information for each test method. For each write of a memory buffer to disk, a separate index file keeps track of the file offset and bytes written for the buffer. This is so that when there lots of tests in a test suite, we don't have to keep all coverage information in memory. Instead, we flush the information and write it to disk at certain intervals. This way, we can also load the information in chunks as well, using the same index file.

Constants

LoadError

Attributes

name[R]
writes[R]

Public Class Methods

new(options = {}) click to toggle source
# File lib/covet/log_file.rb, line 19
def initialize(options = {})
  @mode = options[:mode] || 'w'
  @name = options[:filename] || File.join(Dir.pwd, 'run_log.json')
  if @mode != 'r'
    # We only want to create the real file during the `write_end` method, so write to
    # a tempfile until then. This is in case the user stops their test suite with an
    # interrupt.
    @tmpfile = Tempfile.new(File.basename(@name))
    @tmpname = @tmpfile.path
  else
    @tmpfile = nil
    @tmpname = nil
  end
  @index_file = LogFileIndex.new(:filename => options[:index_filename])
  @writes = 0
end

Public Instance Methods

file_exists?() click to toggle source
# File lib/covet/log_file.rb, line 93
def file_exists?
  File.exist?(@name)
end
load!() click to toggle source
# File lib/covet/log_file.rb, line 61
def load!
  JSON.load(File.read(@name))
end
load_buf!(buf_idx) click to toggle source

@raises LogFile::LoadError @return Array

# File lib/covet/log_file.rb, line 79
def load_buf!(buf_idx)
  @index_file.reload!('r')
  reload!('r')
  index = JSON.load(File.read(@index_file.name))
  pos, bytes_to_read = index[buf_idx]
  load_buf_from_file!(pos, bytes_to_read)
end
load_each_buf!() { |res| ... } click to toggle source

Yields each coverage buffer (Array) one a time from the run log. @raises LogFile::LoadError

# File lib/covet/log_file.rb, line 67
def load_each_buf! # yields
  @index_file.reload!('r')
  reload!('r')
  index = JSON.load(File.read(@index_file.name))
  index.each do |(pos, bytes_to_read)|
    res = load_buf_from_file!(pos, bytes_to_read)
    yield res # @var Array
  end
end
load_run_stats!() click to toggle source

@raises LogFile::LoadError @return Hash

# File lib/covet/log_file.rb, line 89
def load_run_stats!
  load_buf!(-1).last[-1]
end
reload!(mode) click to toggle source

re-opens file, can raise Errno::ENOENT

# File lib/covet/log_file.rb, line 98
def reload!(mode)
  if @file && !@file.closed?
    @file.close
  end
  @file = File.open(@name, mode)
end
write_buf(buf) click to toggle source
# File lib/covet/log_file.rb, line 42
def write_buf(buf)
  check_can_write!
  pos_start = @tmpfile.pos
  @tmpfile.write(JSON.dump(buf) + ',')
  @writes += 1
  pos_after = @tmpfile.pos
  @index_file.add_index(pos_start, pos_after - pos_start)
end
write_end() click to toggle source
# File lib/covet/log_file.rb, line 51
def write_end
  check_can_write!
  @tmpfile.pos -= 1 # remove final comma at end of array
  @tmpfile.write(']')
  @writes += 1
  @tmpfile.close
  FileUtils.cp(@tmpfile, @name)
  @index_file.finish!
end
write_start() click to toggle source
# File lib/covet/log_file.rb, line 36
def write_start
  check_can_write!
  @tmpfile.write('[')
  @writes += 1
end

Private Instance Methods

check_can_write!() click to toggle source
# File lib/covet/log_file.rb, line 111
def check_can_write!
  if @mode == 'r'
    raise "For writing to the log file, you must construct it with a different :mode"
  end
end
file() click to toggle source
# File lib/covet/log_file.rb, line 107
def file
  @file ||= File.open(@name, @mode)
end
load_buf_from_file!(pos, bytes_to_read) click to toggle source

@raises LogFile::LoadError @return Array

# File lib/covet/log_file.rb, line 119
def load_buf_from_file!(pos, bytes_to_read)
  file.pos = pos
  buf = file.read(bytes_to_read)
  if buf.end_with?(',', ']]')
    buf = buf[0..-2]
  end
  JSON.load(buf)
rescue JSON::ParserError => e
  raise LogFile::LoadError, e.message
end