rakelib/test.rake
# frozen_string_literal: true
require "rake/testtask"
begin
require "ruby_memcheck"
rescue LoadError => e
warn("WARNING: ruby_memcheck is not available in this environment: #{e}")
end
#
# much of this was ripped out of hoe-debugging
#
class ValgrindTestTask < Rake::TestTask
DEFAULT_DIRECTORY_NAME = "suppressions"
ERROR_EXITCODE = 42 # the answer to life, the universe, and segfaulting.
VALGRIND_OPTIONS = [
"--num-callers=50",
"--error-limit=no",
"--partial-loads-ok=yes",
"--undef-value-errors=no",
"--error-exitcode=#{ERROR_EXITCODE}",
"--gen-suppressions=all",
]
if defined?(RubyMemcheck)
RubyMemcheck.config(binary_name: "nokogiri", valgrind_generate_suppressions: true)
end
def ruby(*args, **options, &block)
valgrind_options = check_for_suppression_file(VALGRIND_OPTIONS)
command = "ulimit -s unlimited && valgrind #{valgrind_options.join(" ")} #{RUBY} #{args.join(" ")}"
ENV["NCPU"] = nil # don't run valgrind in parallel (minitest-parallel_fork)
sh(command, **options, &block)
end
def formatted_ruby_version
engine = if defined?(RUBY_DESCRIPTION) && RUBY_DESCRIPTION.include?("Ruby Enterprise Edition")
"ree"
else
defined?(RUBY_ENGINE) ? RUBY_ENGINE : "ruby"
end
%{#{engine}-#{RUBY_VERSION}.#{RUBY_PATCHLEVEL}}
end
def check_for_suppression_file(options)
options = options.dup
suppression_files = matching_suppression_files
suppression_files.each do |suppression_file|
puts "NOTICE: using valgrind suppressions in #{suppression_file.inspect}"
options << "--suppressions=#{suppression_file}"
end
options
end
def matching_suppression_files
matching_files = []
version_matches.each do |version_string|
matching_files += Dir[File.join(DEFAULT_DIRECTORY_NAME, "#{version_string}.supp")]
matching_files += Dir[File.join(DEFAULT_DIRECTORY_NAME, "#{version_string}_*.supp")]
end
matching_files
end
def version_matches
matches = [formatted_ruby_version] # e.g. "ruby-2.5.1.57"
matches << formatted_ruby_version.split(".")[0, 3].join(".") # e.g. "ruby-2.5.1"
matches << formatted_ruby_version.split(".")[0, 2].join(".") # e.g. "ruby-2.5"
matches << formatted_ruby_version.split(".")[0, 1].join(".") # e.g. "ruby-2"
matches << formatted_ruby_version.split("-").first # e.g. "ruby"
matches
end
end
class GdbTestTask < Rake::TestTask
def ruby(*args, **options, &block)
command = "gdb --args #{RUBY} #{args.join(" ")}"
sh(command, **options, &block)
end
end
class LldbTestTask < Rake::TestTask
def ruby(*args, **options, &block)
command = "lldb #{RUBY} -- #{args.join(" ")}"
sh(command, **options, &block)
end
end
class MemorySuiteTestTask < Rake::TestTask
def ruby(*args, **options, &block)
ENV["NCPU"] = nil
ENV["NOKOGIRI_MEMORY_SUITE"] = "t"
ENV["NOKOGIRI_TEST_GC_LEVEL"] = "major"
super
end
end
if defined?(RubyMemcheck)
class MemcheckTestTask < RubyMemcheck::TestTask
def ruby(*args, **options, &block)
ENV["NCPU"] = nil
ENV["NOKOGIRI_MEMORY_SUITE"] = "t"
super
end
end
end
def nokogiri_test_task_configuration(t)
t.libs << "test"
t.verbose = true if ENV["TESTGLOB"]
end
def nokogiri_test_case_configuration(t)
nokogiri_test_task_configuration(t)
t.test_files = FileList[ENV["TESTGLOB"] || "test/**/test_*.rb"]
end
def nokogiri_test_bench_configuration(t)
nokogiri_test_task_configuration(t)
t.test_files = FileList["test/**/bench_*.rb"]
end
def nokogiri_test_memory_suite_configuration(t)
nokogiri_test_task_configuration(t)
t.test_files = FileList["test/test_memory_usage.rb"]
end
Rake::TestTask.new do |t|
nokogiri_test_case_configuration(t)
end
namespace "test" do
Rake::TestTask.new("bench") do |t|
nokogiri_test_bench_configuration(t)
end
ValgrindTestTask.new("valgrind") do |t|
nokogiri_test_case_configuration(t)
end
GdbTestTask.new("gdb") do |t|
nokogiri_test_case_configuration(t)
end
LldbTestTask.new("lldb") do |t|
nokogiri_test_case_configuration(t)
end
MemorySuiteTestTask.new("memory_suite") do |t|
nokogiri_test_memory_suite_configuration(t)
end
if defined?(RubyMemcheck)
MemcheckTestTask.new("memcheck") do |t|
nokogiri_test_case_configuration(t)
end
end
end