module RSpecTracer

Constants

VERSION

Attributes

pid[RW]
running[RW]

Public Class Methods

at_exit_behavior() click to toggle source

rubocop:enable Metrics/AbcSize

# File lib/rspec_tracer.rb, line 74
def at_exit_behavior
  return unless RSpecTracer.pid == Process.pid && RSpecTracer.running

  run_exit_tasks
end
coverage_reporter() click to toggle source
# File lib/rspec_tracer.rb, line 102
def coverage_reporter
  return @coverage_reporter if defined?(@coverage_reporter)
end
filter_examples() click to toggle source

rubocop:disable Metrics/AbcSize

# File lib/rspec_tracer.rb, line 45
def filter_examples
  groups = Set.new
  to_run = Hash.new { |hash, group| hash[group] = [] }

  RSpec.world.filtered_examples.each_pair do |example_group, examples|
    examples.each do |example|
      tracer_example = RSpecTracer::Example.from(example)
      example_id = tracer_example[:example_id]
      example.metadata[:rspec_tracer_example_id] = example_id

      if runner.run_example?(example_id)
        run_reason = runner.run_example_reason(example_id)
        tracer_example[:run_reason] = run_reason
        example.metadata[:description] = "#{example.description} (#{run_reason})"

        to_run[example_group] << example
        groups << example.example_group.parent_groups.last

        runner.register_example(tracer_example)
      else
        runner.on_example_skipped(example_id)
      end
    end
  end

  [to_run, groups.to_a]
end
runner() click to toggle source
# File lib/rspec_tracer.rb, line 98
def runner
  return @runner if defined?(@runner)
end
simplecov?() click to toggle source
# File lib/rspec_tracer.rb, line 118
def simplecov?
  return @simplecov if defined?(@simplecov)
end
start(&block) click to toggle source
# File lib/rspec_tracer.rb, line 33
def start(&block)
  RSpecTracer.running = false
  RSpecTracer.pid = Process.pid

  puts 'Started RSpec tracer'

  configure(&block) if block

  initial_setup
end
start_example_trace() click to toggle source
# File lib/rspec_tracer.rb, line 80
def start_example_trace
  trace_point.enable if trace_example?
end
stop_example_trace(success) click to toggle source
# File lib/rspec_tracer.rb, line 84
def stop_example_trace(success)
  return unless trace_example?

  trace_point.disable

  unless success
    @traced_files = Set.new

    return
  end

  @trace_example = false
end
trace_example?() click to toggle source
# File lib/rspec_tracer.rb, line 114
def trace_example?
  defined?(@trace_example) ? @trace_example : false
end
trace_point() click to toggle source
# File lib/rspec_tracer.rb, line 106
def trace_point
  return @trace_point if defined?(@trace_point)
end
traced_files() click to toggle source
# File lib/rspec_tracer.rb, line 110
def traced_files
  return @traced_files if defined?(@traced_files)
end

Private Class Methods

generate_reports() click to toggle source
# File lib/rspec_tracer.rb, line 185
def generate_reports
  puts 'RSpec tracer is generating reports'

  process_dependency
  process_coverage
  runner.generate_report
  RSpecTracer::HTMLReporter::Reporter.new.generate_report
end
initial_setup() click to toggle source
# File lib/rspec_tracer.rb, line 124
def initial_setup
  unless setup_rspec
    puts 'Could not find a running RSpec process'

    return
  end

  setup_coverage
  setup_trace_point

  @runner = RSpecTracer::Runner.new
  @coverage_reporter = RSpecTracer::CoverageReporter.new
end
print_coverage_stats(file_name, elpased) click to toggle source
process_coverage() click to toggle source
# File lib/rspec_tracer.rb, line 207
def process_coverage
  starting = Process.clock_gettime(Process::CLOCK_MONOTONIC)

  coverage_reporter.generate_final_examples_coverage
  coverage_reporter.merge_coverage(runner.generate_missed_coverage)
  runner.register_examples_coverage(coverage_reporter.examples_coverage)

  ending = Process.clock_gettime(Process::CLOCK_MONOTONIC)
  elpased = RSpecTracer::TimeFormatter.format_time(ending - starting)

  puts "RSpec tracer processed coverage (took #{elpased})" if RSpecTracer.verbose?
end
process_dependency() click to toggle source
# File lib/rspec_tracer.rb, line 194
def process_dependency
  starting = Process.clock_gettime(Process::CLOCK_MONOTONIC)

  runner.register_deleted_examples
  runner.register_dependency(coverage_reporter.examples_coverage)
  runner.register_untraced_dependency(@traced_files)

  ending = Process.clock_gettime(Process::CLOCK_MONOTONIC)
  elpased = RSpecTracer::TimeFormatter.format_time(ending - starting)

  puts "RSpec tracer processed dependency (took #{elpased})" if RSpecTracer.verbose?
end
run_coverage_exit_task() click to toggle source
# File lib/rspec_tracer.rb, line 230
def run_coverage_exit_task
  starting = Process.clock_gettime(Process::CLOCK_MONOTONIC)

  coverage_reporter.generate_final_coverage

  file_name = File.join(RSpecTracer.coverage_path, 'coverage.json')

  write_coverage_report(file_name)

  ending = Process.clock_gettime(Process::CLOCK_MONOTONIC)
  elpased = RSpecTracer::TimeFormatter.format_time(ending - starting)

  print_coverage_stats(file_name, elpased)
end
run_exit_tasks() click to toggle source
# File lib/rspec_tracer.rb, line 177
def run_exit_tasks
  generate_reports

  simplecov? ? run_simplecov_exit_task : run_coverage_exit_task
ensure
  RSpecTracer.running = false
end
run_simplecov_exit_task() click to toggle source
# File lib/rspec_tracer.rb, line 220
def run_simplecov_exit_task
  coverage_clazz = ::Coverage.singleton_class
  clazz = RSpecTracer::RubyCoverage
  coverage_clazz.prepend(clazz) unless coverage_clazz.ancestors.include?(clazz)

  puts 'SimpleCov will now generate coverage report (<3 RSpec tracer)'

  SimpleCov.result.format!
end
setup_coverage() click to toggle source
# File lib/rspec_tracer.rb, line 154
def setup_coverage
  @simplecov = defined?(SimpleCov) && SimpleCov.running

  if simplecov?
    # rubocop:disable Lint/EmptyBlock
    SimpleCov.at_exit {}
    # rubocop:enable Lint/EmptyBlock
  else
    require 'coverage'

    ::Coverage.start
  end
end
setup_rspec() click to toggle source
# File lib/rspec_tracer.rb, line 138
def setup_rspec
  runners = ObjectSpace.each_object(::RSpec::Core::Runner) do |runner|
    runner_clazz = runner.singleton_class
    clazz = RSpecTracer::RSpecRunner

    runner_clazz.prepend(clazz) unless runner_clazz.ancestors.include?(clazz)

    reporter_clazz = runner.configuration.reporter.singleton_class
    clazz = RSpecTracer::RSpecReporter

    reporter_clazz.prepend(clazz) unless reporter_clazz.ancestors.include?(clazz)
  end

  runners.positive?
end
setup_trace_point() click to toggle source
# File lib/rspec_tracer.rb, line 168
def setup_trace_point
  @trace_example = true
  @traced_files = Set.new

  @trace_point = TracePoint.new(:call) do |tp|
    RSpecTracer.traced_files << tp.path if tp.path.start_with?(RSpecTracer.root)
  end
end
write_coverage_report(file_name) click to toggle source
# File lib/rspec_tracer.rb, line 245
def write_coverage_report(file_name)
  report = {
    RSpecTracer: {
      coverage: coverage_reporter.coverage,
      timestamp: Time.now.utc.to_i
    }
  }

  File.write(file_name, JSON.pretty_generate(report))
end