141 lines
3.4 KiB
Ruby
141 lines
3.4 KiB
Ruby
# typed: strict
|
|
# frozen_string_literal: true
|
|
|
|
require "simplecov"
|
|
require "simplecov-lcov"
|
|
|
|
SimpleCov::Formatter::LcovFormatter.config do |c|
|
|
c.report_with_single_file = true
|
|
c.lcov_file_name = "lcov.info"
|
|
end
|
|
|
|
SimpleCov.start do
|
|
enable_coverage :branch
|
|
add_filter "spec"
|
|
formatter(
|
|
SimpleCov::Formatter::MultiFormatter.new(
|
|
[
|
|
SimpleCov::Formatter::LcovFormatter, # Add Lcov as an output when generating code coverage report
|
|
SimpleCov::Formatter::HTMLFormatter # Add other outputs for the code coverage report
|
|
]
|
|
)
|
|
)
|
|
end
|
|
|
|
require "pry"
|
|
require "active_record"
|
|
require "active_record/errors"
|
|
require "has_aux_table"
|
|
|
|
# Configure ActiveRecord to use in-memory SQLite database
|
|
ActiveRecord::Base.establish_connection(
|
|
adapter: "sqlite3",
|
|
database: ":memory:"
|
|
)
|
|
|
|
require_relative "spec_models"
|
|
|
|
RSpec.configure do |config|
|
|
# Enable flags like --only-failures and --next-failure
|
|
config.example_status_persistence_file_path = ".rspec_status"
|
|
|
|
# Disable RSpec exposing methods globally on `Module` and `main`
|
|
config.disable_monkey_patching!
|
|
|
|
config.backtrace_inclusion_patterns = [/\bactiverecord\b/]
|
|
|
|
config.expect_with :rspec do |c|
|
|
c.syntax = :expect
|
|
end
|
|
|
|
config.around(:each) do |example|
|
|
ActiveRecord::Base.transaction do
|
|
example.run
|
|
raise ActiveRecord::Rollback
|
|
end
|
|
end
|
|
|
|
config.include(
|
|
Module.new do
|
|
extend T::Sig
|
|
sig do
|
|
type_parameters(:T)
|
|
.params(block: T.proc.returns(T.type_parameter(:T)))
|
|
.returns(SpecHelper::CaptureQueries[T.type_parameter(:T)])
|
|
end
|
|
def capture_queries(&block)
|
|
SpecHelper.capture_queries(&block)
|
|
end
|
|
end
|
|
)
|
|
|
|
config.extend(
|
|
Module.new do
|
|
extend T::Sig
|
|
|
|
sig do
|
|
type_parameters(:T)
|
|
.params(binding: Symbol, block: T.proc.returns(T.type_parameter(:T)))
|
|
.returns(T.type_parameter(:T))
|
|
end
|
|
def let_and_capture(binding, &block)
|
|
T.bind(self, RSpec::Core::MemoizedHelpers::ClassMethods)
|
|
let(binding) { SpecHelper.capture_queries(&block) }
|
|
end
|
|
end
|
|
)
|
|
end
|
|
|
|
module SpecHelper
|
|
extend T::Sig
|
|
extend T::Helpers
|
|
LOG_QUERIES = T.let(false, T::Boolean)
|
|
|
|
class CaptureQueries < Array
|
|
extend T::Sig
|
|
extend T::Generic
|
|
Elem = type_member { { fixed: String } }
|
|
Result = type_member
|
|
|
|
sig { params(queries: T::Array[String], result: Result).void }
|
|
def initialize(queries, result)
|
|
super(queries)
|
|
@result = result
|
|
end
|
|
|
|
sig { returns(Result) }
|
|
attr_reader :result
|
|
end
|
|
|
|
# Helper method to count queries
|
|
sig do
|
|
type_parameters(:T)
|
|
.params(block: T.proc.returns(T.type_parameter(:T)))
|
|
.returns(CaptureQueries[T.type_parameter(:T)])
|
|
end
|
|
def self.capture_queries(&block)
|
|
queries = T.let([], T::Array[String])
|
|
query_callback =
|
|
lambda do |name, start, finish, message_id, values|
|
|
queries << values[:sql]
|
|
end
|
|
|
|
result = T.let(nil, T.untyped)
|
|
ActiveSupport::Notifications.subscribed(
|
|
query_callback,
|
|
"sql.active_record"
|
|
) do
|
|
if LOG_QUERIES
|
|
old_logger = ActiveRecord::Base.logger
|
|
ActiveRecord::Base.logger = Logger.new(STDOUT)
|
|
ActiveRecord::Base.logger.level = Logger::DEBUG
|
|
end
|
|
result = block.call
|
|
ensure
|
|
ActiveRecord::Base.logger = old_logger if LOG_QUERIES
|
|
end
|
|
|
|
CaptureQueries.new(queries, result)
|
|
end
|
|
end
|