Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions config/covered.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# frozen_string_literal: true

def ignore_paths
super + ["bake.rb"]
end
40 changes: 40 additions & 0 deletions test/covered/autostart.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# frozen_string_literal: true

# Released under the MIT License.
# Copyright, 2026, by Samuel Williams.

require "covered/config"

describe "Coverage::Autostart" do
it "reports at exit when reports are enabled" do
events = []
exit_hook = nil

config = Object.new
config.define_singleton_method(:start){events << :start}
config.define_singleton_method(:finish){events << :finish}
config.define_singleton_method(:report?){true}
config.define_singleton_method(:call){|stream| events << [:call, stream]}

Object.const_set(:Coverage, Module.new) unless Object.const_defined?(:Coverage)
::Coverage.const_set(:Autostart, Module.new) unless ::Coverage.const_defined?(:Autostart)

::Coverage::Autostart.define_singleton_method(:at_exit) do |&block|
exit_hook = block
end

mock(Covered::Config) do |mock|
mock.replace(:load){config}
end

load File.expand_path("../../lib/covered/autostart.rb", __dir__)

exit_hook.call

expect(events).to be == [
:start,
:finish,
[:call, $stderr],
]
end
end
64 changes: 64 additions & 0 deletions test/covered/minitest.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

require "covered"
require "minitest_tests"
require "covered/minitest"

describe "Covered::Minitest" do
include MinitestTests
Expand All @@ -18,4 +19,67 @@
buffer = input.read
expect(buffer).to be =~ /(.*?) files checked; (.*?) lines executed; (.*?)% covered/
end

it "starts coverage before running minitest" do
events = []
coverage = Object.new
coverage.define_singleton_method(:start){events << :start}

runner = Class.new do
prepend Covered::Minitest

def run
:ran
end
end.new

original_coverage = $covered
$covered = coverage

expect(runner.run).to be == :ran
expect(events).to be == [:start]
ensure
$covered = original_coverage
end

it "registers the Minitest hooks when coverage is enabled" do
events = []

coverage = Object.new
coverage.define_singleton_method(:record?){true}
coverage.define_singleton_method(:finish){events << :finish}
coverage.define_singleton_method(:call){|stream| events << [:call, stream]}

original_coverage = $covered
original_after_run = Minitest.method(:after_run)

mock(Covered::Config) do |mock|
mock.replace(:load){coverage}
end

mock(Minitest.singleton_class) do |mock|
mock.replace(:prepend) do |mod|
events << [:prepend, mod]
end
end

Minitest.define_singleton_method(:after_run) do |&block|
events << :after_run
block.call
end

events.clear

load File.expand_path("../../lib/covered/minitest.rb", __dir__)

expect(events).to be == [
[:prepend, Covered::Minitest],
:after_run,
:finish,
[:call, $stderr],
]
ensure
$covered = original_coverage
Minitest.define_singleton_method(:after_run, original_after_run) if original_after_run
end
end
27 changes: 27 additions & 0 deletions test/covered/partial_summary.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,33 @@
expect(io.string).to be(:include?, "summary.rb")
end

it "shows multiple 100% coverage files when there are partial files" do
partial_file = __FILE__
complete_file1 = File.join(__dir__, "../covered/summary.rb")
complete_file2 = File.join(__dir__, "../covered/brief_summary.rb")

files.mark(partial_file, 1, 1)
files.mark(partial_file, 2, 0)

files.mark(complete_file1, 1, 1)
files.mark(complete_file2, 1, 1)

summary.call(files, io)

expect(io.string).to be(:include?, "2 files have 100% coverage and are not shown above:")
expect(io.string).to be(:include?, "summary.rb")
expect(io.string).to be(:include?, "brief_summary.rb")
end

it "prints rendering errors" do
coverage = Covered::Coverage.new(Covered::Source.new("missing.rb"), [nil, 1, 0])
files.add(coverage)

summary.call(files, io)

expect(io.string).to be(:include?, "Error: No such file or directory")
end

it "does not show 100% coverage files when all files are 100%" do
# Create a scenario where all files have 100% coverage
file1 = __FILE__
Expand Down
86 changes: 86 additions & 0 deletions test/covered/rspec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

require "covered"
require "rspec_tests"
require "rspec/core"
require "covered/rspec"

describe "Covered::RSpec" do
include RSpecTests
Expand All @@ -18,4 +20,88 @@
buffer = input.read
expect(buffer).to be =~ /(.*?) files checked; (.*?) lines executed; (.*?)% covered/
end

it "starts coverage before loading spec files" do
events = []
coverage = Object.new
coverage.define_singleton_method(:start){events << :start}

configuration = Class.new do
prepend Covered::RSpec::Policy

def load_spec_files
:loaded
end
end.new

original_coverage = $covered
$covered = coverage

expect(configuration.load_spec_files).to be == :loaded
expect(events).to be == [:start]
ensure
$covered = original_coverage
end

it "gets and sets the active coverage" do
configuration = Object.new
configuration.singleton_class.prepend(Covered::RSpec::Policy)

original_coverage = $covered
coverage = Object.new

configuration.covered = coverage

expect(configuration.covered).to be == coverage
ensure
$covered = original_coverage
end

it "registers the RSpec hooks when coverage is enabled" do
events = []
output = StringIO.new

coverage = Object.new
coverage.define_singleton_method(:record?){true}
coverage.define_singleton_method(:finish){events << :finish}
coverage.define_singleton_method(:call){|stream| events << [:call, stream]}

config = Object.new
config.define_singleton_method(:after) do |name, &block|
events << [:after, name]
block.call
end
config.define_singleton_method(:output_stream){output}

original_coverage = $covered

mock(Covered::Config) do |mock|
mock.replace(:load){coverage}
end

mock(RSpec::Core::Configuration) do |mock|
mock.replace(:prepend) do |mod|
events << [:prepend, mod]
end
end

mock(RSpec) do |mock|
mock.replace(:configure) do |&block|
events << :configure
block.call(config)
end
end

load File.expand_path("../../lib/covered/rspec.rb", __dir__)

expect(events).to be == [
[:prepend, Covered::RSpec::Policy],
:configure,
[:after, :suite],
:finish,
[:call, output],
]
ensure
$covered = original_coverage
end
end
129 changes: 129 additions & 0 deletions test/covered/sus.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
# frozen_string_literal: true

# Released under the MIT License.
# Copyright, 2026, by Samuel Williams.

require "covered/sus"

describe Covered::Sus do
let(:coverage) do
Class.new do
attr :events

def initialize(record: true)
@record = record
@events = []
end

def record?
@record
end

def start
@events << :start
end

def finish
@events << :finish
end

def call(output)
output << "covered"
@events << :call
end
end
end

let(:runner_class) do
base = Class.new do
def initialize
end

def after_tests(assertions)
end
end

Class.new(base) do
include Covered::Sus

attr :events

def initialize
@events = []
super
end

def root
__dir__
end

def output
Struct.new(:io).new(StringIO.new)
end

def after_tests(assertions)
@events << [:after_tests, assertions]
super
end
end
end

it "starts and finishes configured coverage" do
config = coverage.new

mock(Covered::Config) do |mock|
mock.replace(:load) do |root:|
expect(root).to be == __dir__
config
end
end

mock(ENV) do |mock|
mock.replace(:[]) do |key|
"PartialSummary" if key == "COVERAGE"
end
end

runner = runner_class.new
runner.after_tests(:assertions)

expect(runner.covered).to be == config
expect(config.events).to be == [:start, :finish, :call]
expect(runner.events).to be == [[:after_tests, :assertions]]
end

it "skips coverage when it is not configured to record" do
config = coverage.new(record: false)

mock(Covered::Config) do |mock|
mock.replace(:load) do |root:|
config
end
end

mock(ENV) do |mock|
mock.replace(:[]) do |key|
"Quiet" if key == "COVERAGE"
end
end

runner = runner_class.new
runner.after_tests(:assertions)

expect(runner.covered).to be == config
expect(config.events).to be(:empty?)
end

it "does nothing when coverage is not requested" do
mock(ENV) do |mock|
mock.replace(:[]) do |key|
nil
end
end

runner = runner_class.new
runner.after_tests(:assertions)

expect(runner.covered).to be_nil
end
end
Loading