scripts/test-gem-file-contents
#! /usr/bin/env ruby
# frozen_string_literal: true
#
# this script is intended to run as part of the CI test suite.
#
# it inspects the contents of a nokogiri gem file -- both the files and the gemspec -- to ensure
# we're packaging what we expect, and that we're not packaging anything we don't expect.
#
# this file isn't in the `test/` subdirectory because it's intended to be run standalone against a
# built gem file (and not against the source code or behavior of the gem itself).
#
require "bundler/inline"
gemfile do
source "https://rubygems.org"
gem "minitest"
end
require "yaml"
def usage_and_exit(message = nil)
puts "ERROR: #{message}" if message
puts "USAGE: #{File.basename(__FILE__)} <gemfile> [options]"
exit(1)
end
usage_and_exit if ARGV.include?("-h")
usage_and_exit unless (gemfile = ARGV[0])
usage_and_exit("#{gemfile} does not exist") unless File.file?(gemfile)
usage_and_exit("#{gemfile} is not a gem") unless /\.gem$/.match?(gemfile)
gemfile = File.expand_path(gemfile)
gemfile_contents = Dir.mktmpdir do |dir|
Dir.chdir(dir) do
unless system("tar -xf #{gemfile} data.tar.gz")
raise "could not unpack gem #{gemfile}"
end
%x(tar -ztf data.tar.gz).split("\n")
end
end
gemspec = Dir.mktmpdir do |dir|
Dir.chdir(dir) do
unless system("tar -xf #{gemfile} metadata.gz")
raise "could not unpack gem #{gemfile}"
end
YAML.safe_load(
%x(gunzip -c metadata.gz),
permitted_classes: [Gem::Specification, Gem::Version, Gem::Dependency, Gem::Requirement, Time, Symbol],
)
end
end
if ARGV.include?("-v")
puts "---------- gemfile contents ----------"
puts gemfile_contents
puts
puts "---------- gemspec ----------"
puts gemspec.to_ruby
puts
end
require "minitest/autorun"
puts "Testing '#{gemfile}' (#{gemspec.platform})"
describe File.basename(gemfile) do
let(:cross_rubies_path) { File.join(File.dirname(__FILE__), "..", ".cross_rubies") }
let(:platform_supported_ruby_versions) do
File.read(cross_rubies_path).split("\n").filter_map do |line|
ver, plat = line.split(":")
next if plat != gemspec.platform.to_s
ver.split(".").take(2).join(".") # ugh
end.uniq.sort
end
let(:all_supported_ruby_versions) do
File.read(cross_rubies_path).split("\n").map do |line|
ver, _ = line.split(":")
ver.split(".").take(2).join(".") # ugh
end.uniq.sort
end
describe "setup" do
it "gemfile contains some files" do
actual = gemfile_contents.length
assert_operator(actual, :>, 60, "expected gemfile to contain more than #{actual} files")
end
it "gemspec is a Gem::Specification" do
assert_equal(Gem::Specification, gemspec.class)
end
end
describe "all platforms" do
it "contains every ruby file in lib/" do
expected = %x(git ls-files lib).split("\n").grep(/\.rb$/).sort
skip "looks like this isn't a git repository" if expected.empty?
actual = gemfile_contents.grep(%r{^lib/}).grep(/\.rb$/).sort
assert_equal(expected, actual)
end
end
describe "ruby platform" do
it "depends on mini_portile2" do
assert(gemspec.dependencies.find { |d| d.name == "mini_portile2" })
end
it "contains ext/nokogiri C and header files" do
assert_operator(gemfile_contents.grep(%r{^ext/nokogiri/.*\.c}).length, :>, 20)
assert_operator(gemfile_contents.grep(%r{^ext/nokogiri/.*\.h}).length, :>, 0)
end
it "includes C files in extra_rdoc_files" do
assert_operator(gemspec.extra_rdoc_files.grep(%r{ext/nokogiri/.*\.c$}).length, :>, 10)
end
it "contains the port files" do
actual_ports = gemfile_contents.grep(%r{^ports/})
assert_equal(
1,
actual_ports.grep(/libxml2-\d+\.\d+\.\d+\.tar\.[gx]z/).length,
"expected #{actual_ports} to include libxml2",
)
assert_equal(
1,
actual_ports.grep(/libxslt-\d+\.\d+\.\d+\.tar\.[gx]z/).length,
"expected #{actual_ports} to include libxslt",
)
assert_equal(2, actual_ports.length)
end
it "contains the patch files" do
assert_operator(gemfile_contents.grep(%r{^patches/}).length, :>, 0)
end
it "does not contain packaged libraries' header files" do
# these files are present after installation if the packaged libraries are used
assert_empty(gemfile_contents.grep(%r{^ext/nokogiri/include/}))
end
it "contains the gumbo parser source code" do
assert_includes(gemfile_contents, "gumbo-parser/src/Makefile")
assert_operator(gemfile_contents.grep(%r{^gumbo-parser/src/.*\.c}).length, :>, 10)
assert_operator(gemfile_contents.grep(%r{^gumbo-parser/src/.*\.h}).length, :>, 10)
end
it "does not contain java files" do
assert_empty(gemfile_contents.grep(%r{^ext/java/}))
assert_empty(gemfile_contents.grep(/.*\.jar$/))
end
end if gemspec.platform == Gem::Platform::RUBY
describe "native platform" do
it "does not depend on mini_portile2" do
refute(gemspec.dependencies.find { |d| d.name == "mini_portile2" })
end
it "contains ext/nokogiri C and header files" do
assert_operator(gemfile_contents.grep(%r{^ext/nokogiri/.*\.c}).length, :>, 20)
assert_operator(gemfile_contents.grep(%r{^ext/nokogiri/.*\.h}).length, :>, 20)
end
it "includes C files in extra_rdoc_files" do
assert_operator(gemspec.extra_rdoc_files.grep(%r{ext/nokogiri/.*\.c$}).length, :>, 10)
end
it "does not contain the port files" do
assert_empty(gemfile_contents.grep(%r{^ports/}))
end
it "does not contain the patch files" do
assert_empty(gemfile_contents.grep(%r{^patches/}))
end
it "contains packaged libraries' header files" do
assert_includes(gemfile_contents, "ext/nokogiri/include/libxml2/libxml/tree.h")
assert_includes(gemfile_contents, "ext/nokogiri/include/libxslt/xslt.h")
assert_includes(gemfile_contents, "ext/nokogiri/include/libexslt/exslt.h")
end
it "does not contain the gumbo parser source code" do
assert_empty(gemfile_contents.grep(%r{^gumbo-parser/src/}))
end
it "does not contain java files" do
assert_empty(gemfile_contents.grep(%r{^ext/java/}))
assert_empty(gemfile_contents.grep(/.*\.jar$/))
end
it "contains expected shared library files " do
platform_supported_ruby_versions.each do |version|
actual = gemfile_contents.find do |p|
File.fnmatch?("lib/nokogiri/#{version}/nokogiri.{so,bundle}", p, File::FNM_EXTGLOB)
end
assert(actual, "expected to find shared library file for ruby #{version}")
end
actual = gemfile_contents.find do |p|
File.fnmatch?("lib/nokogiri/nokogiri.{so,bundle}", p, File::FNM_EXTGLOB)
end
refute(actual, "did not expect to find shared library file in lib/nokogiri")
actual = gemfile_contents.find_all do |p|
File.fnmatch?("lib/nokogiri/**/*.{so,bundle}", p, File::FNM_EXTGLOB)
end
assert_equal(
platform_supported_ruby_versions.length,
actual.length,
"did not expect extra shared library files",
)
end
it "sets required_ruby_version appropriately" do
unsupported_versions = all_supported_ruby_versions - platform_supported_ruby_versions
platform_supported_ruby_versions.each do |v|
assert(
gemspec.required_ruby_version.satisfied_by?(Gem::Version.new(v)),
"required_ruby_version='#{gemspec.required_ruby_version}' should support ruby #{v}",
)
end
unsupported_versions.each do |v|
refute(
gemspec.required_ruby_version.satisfied_by?(Gem::Version.new(v)),
"required_ruby_version='#{gemspec.required_ruby_version}' should not support ruby #{v}",
)
end
end
end if gemspec.platform.is_a?(Gem::Platform) && gemspec.platform.cpu
describe "java platform" do
it "does not depend on mini_portile2" do
refute(gemspec.dependencies.find { |d| d.name == "mini_portile2" })
end
it "contains ext/nokogiri C files" do
# NOTE: we keep the C files because they have docstrings and Java files don't
assert_operator(gemfile_contents.grep(%r{^ext/nokogiri/.*\.c}).length, :>, 20)
end
it "does not contain ext/nokogiri header files" do
assert_empty(gemfile_contents.grep(%r{^ext/nokogiri/.*\.h}))
end
it "includes C files in extra_rdoc_files" do
assert_operator(gemspec.extra_rdoc_files.grep(%r{ext/nokogiri/.*\.c$}).length, :>, 10)
end
it "does not contain the port files" do
assert_empty(gemfile_contents.grep(%r{^ports/}))
end
it "does not contain the patch files" do
assert_empty(gemfile_contents.grep(%r{^patches/}))
end
it "does not contain packaged libraries' header files" do
assert_empty(gemfile_contents.grep(%r{^ext/nokogiri/include/}))
end
it "does not contain the gumbo parser source code" do
assert_empty(gemfile_contents.grep(%r{^gumbo-parser/src/}))
end
it "contains java source files" do
assert_operator(gemfile_contents.grep(%r{^ext/java/.*\.java}).length, :>, 20)
end
it "contains the java jar files" do
assert_includes(gemfile_contents, "lib/nokogiri/nokogiri.jar")
actual_jars = gemfile_contents.grep(/.*\.jar$/)
expected_jars = [
"isorelax",
"jing",
"neko-htmlunit",
"nekodtd",
"serializer",
"xalan",
"xercesImpl",
"xml-apis",
]
expected_jars.each do |name|
assert_equal(
1,
actual_jars.count { |j| File.fnmatch?("lib/nokogiri/jruby/**/#{name}-*.jar", j) },
"expected to contain '#{name}-*.jar'",
)
end
end
end if gemspec.platform == Gem::Platform.new("java")
end