defmodule GitGud.Packages.Formats.Rpm.HeaderTest do
@moduledoc """
The RPM header parser, against a real package.
The fixture is the first 9141 bytes of
`aspell-sl-0.50-4.6.x86_64.rpm` from openSUSE Tumbleweed — the lead,
the signature header and the main header, with the 5.9 MB compressed
payload cut off. Truncating it is not a shortcut around a hard case:
the parser never reads past the main header, and a fixture that
stops exactly where the parser should proves that.
Every expected value below was taken from `rpm -qp --qf` on the
untruncated file, not from this parser, so the assertions are a
comparison against rpm rather than a recording of our own output.
"""
use ExUnit.Case, async: true
alias GitGud.Packages.Formats.Rpm.Header
@fixture File.read!("test/support/fixtures/rpm/aspell-sl-headers.rpm")
setup do
{:ok, header} = Header.parse(@fixture)
%{header: header}
end
describe "scalar tags" do
test "the identity rpm prints", %{header: header} do
assert Header.get(header, :name) == "aspell-sl"
assert Header.get(header, :version) == "0.50"
assert Header.get(header, :release) == "4.6"
assert Header.get(header, :arch) == "x86_64"
end
test "no epoch is nil, not zero", %{header: header} do
# rpm prints "(none)" here. Storing a 0 would be a claim the
# package doesn't make, and epoch 0 and no epoch compare the same
# way only because the *renderer* defaults it.
assert Header.get(header, :epoch) == nil
end
test "integers are integers", %{header: header} do
assert Header.get(header, :buildtime) == 1_709_119_039
assert Header.get(header, :size) == 22_694_857
end
test "the free text", %{header: header} do
assert Header.get(header, :summary) == "Slovenian (slovenski) Dictionary for Aspell"
assert Header.get(header, :license) == "GPL-2.0-or-later"
assert Header.get(header, :vendor) == "openSUSE"
assert Header.get(header, :url) == "http://aspell.net/"
assert Header.get(header, :sourcerpm) == "aspell-dictionaries-0.50.6-4.6.src.rpm"
end
test "the payload size comes out of the signature header", %{header: header} do
# The one tag that isn't in the main header at all. It is tag
# 1007 there, which the main header calls BUILDHOST — reading
# both with one table gives you a hostname where a size belongs,
# and this is the assertion that catches that.
assert Header.get(header, :archivesize) == 22_696_668
assert Header.get(header, :buildhost) == "reproducible"
end
end
describe "array tags" do
test "provides line up name, flags and version by index", %{header: header} do
assert Enum.take(Header.list(header, :providename), 3) ==
["aspell-sl", "aspell-sl(x86-64)", "locale(aspell:sl)"]
assert Enum.take(Header.list(header, :provideversion), 3) == ["0.50-4.6", "0.50-4.6", ""]
assert Enum.take(Header.list(header, :provideflags), 3) == [8, 8, 0]
end
test "this package requires nothing but rpmlib", %{header: header} do
assert Header.list(header, :requirename) == [
"rpmlib(CompressedFileNames)",
"rpmlib(FileDigests)",
"rpmlib(PayloadFilesHavePrefix)",
"rpmlib(PayloadIsZstd)"
]
end
test "list/2 wraps a scalar so callers never branch", %{header: header} do
assert Header.list(header, :name) == ["aspell-sl"]
assert Header.list(header, :nonexistent) == []
end
end
describe "files" do
test "are reassembled from dirnames, dirindexes and basenames", %{header: header} do
files = Header.files(header)
assert length(files) == 11
assert "/usr/lib64/aspell-0.60/sl.dat" in files
assert "/usr/lib64/aspell-0.60/sl.rws" in files
end
end
describe "the header range" do
test "brackets the main header in the file", %{header: header} do
# These go into primary.xml as <rpm:header-range/>, and dnf uses
# them to range-request a package's metadata instead of the
# package. Wrong values mean a client fetches garbage and can't
# say why.
assert header.header_start == 4504
assert header.header_end == 9141
# …which is the whole truncated fixture, by construction: the
# payload starts exactly where the header ends.
assert header.header_end == byte_size(@fixture)
end
test "the start is 8-byte aligned", %{header: header} do
assert rem(header.header_start, 8) == 0
end
end
describe "the filename" do
test "is the one rpmbuild writes", %{header: header} do
assert Header.filename(header) == "aspell-sl-0.50-4.6.x86_64.rpm"
end
end
describe "refusing input" do
test "something that isn't an RPM at all" do
assert {:error, {422, message}} = Header.parse("PK\x03\x04 this is a zip")
assert message =~ "lead magic"
end
test "a truncated header rather than a truncated payload" do
# Cutting inside the main header has to be an error; cutting
# after it is the fixture above and must not be.
assert {:error, {422, _}} = Header.parse(binary_part(@fixture, 0, 6000))
end
test "an empty body" do
assert {:error, {422, _}} = Header.parse("")
end
end
end
neiam
/gitgud
Git Gud
public · Issues · Pulls · Labels · Forks · Compare · Actions success · Badges · Packages
⭐
1
Log in to mark this repository.
5.2 KiB · text
History
ff5c190