Files
zeta-reconstructor/internal/arch/src/srcinfo_test.go
T

294 lines
9.6 KiB
Go

package src
import (
"os"
"path/filepath"
"slices"
"strings"
"testing"
)
// srcinfoFixtures is the committed testdata tree, relative to this package
// directory (internal/arch/src).
const srcinfoFixtures = "../../../testdata/srcinfo"
func readFixture(t *testing.T, path string) string {
t.Helper()
b, err := os.ReadFile(path)
if err != nil {
t.Fatalf("read fixture %s: %v", path, err)
}
return string(b)
}
// TestSrcInfoParseMytoolSRCINFO parses the committed mytool .SRCINFO with
// arch x86_64 and checks every field the converter consumes.
func TestSrcInfoParseMytoolSRCINFO(t *testing.T) {
src := readFixture(t, filepath.Join(srcinfoFixtures, "mytool", ".SRCINFO"))
got, err := ParseSRCINFO(src, "x86_64")
if err != nil {
t.Fatalf("ParseSRCINFO: %v", err)
}
if got.PkgBase != "mytool" {
t.Errorf("PkgBase = %q, want %q", got.PkgBase, "mytool")
}
if !slices.Equal(got.PkgNames, []string{"mytool"}) {
t.Errorf("PkgNames = %v, want [mytool]", got.PkgNames)
}
if got.Version != "1.0" || got.Rel != "1" {
t.Errorf("Version/Rel = %q/%q, want %q/%q", got.Version, got.Rel, "1.0", "1")
}
if got.Desc != "Example custom-build package" {
t.Errorf("Desc = %q, want %q", got.Desc, "Example custom-build package")
}
if got.URL != "https://example.org" {
t.Errorf("URL = %q, want %q", got.URL, "https://example.org")
}
if !slices.Equal(got.Arch, []string{"x86_64"}) {
t.Errorf("Arch = %v, want [x86_64]", got.Arch)
}
if !slices.Equal(got.Depends, []string{"glibc"}) {
t.Errorf("Depends = %v, want [glibc]", got.Depends)
}
if !slices.Equal(got.Sources, []string{"mytool-1.0.tar.gz"}) {
t.Errorf("Sources = %v, want [mytool-1.0.tar.gz]", got.Sources)
}
if !slices.Equal(got.SHA256Sums, []string{"SKIP"}) {
t.Errorf("SHA256Sums = %v, want [SKIP]", got.SHA256Sums)
}
}
// TestSrcInfoParseMytoolPKGBUILD exercises the best-effort bash fallback on
// the same package and expects the essential fields to agree.
func TestSrcInfoParseMytoolPKGBUILD(t *testing.T) {
src := readFixture(t, filepath.Join(srcinfoFixtures, "mytool", "PKGBUILD"))
got, err := ParsePKGBUILD(src)
if err != nil {
t.Fatalf("ParsePKGBUILD: %v", err)
}
if !slices.Equal(got.PkgNames, []string{"mytool"}) {
t.Errorf("PkgNames = %v, want [mytool]", got.PkgNames)
}
if got.Version != "1.0" || got.Rel != "1" {
t.Errorf("Version/Rel = %q/%q, want %q/%q", got.Version, got.Rel, "1.0", "1")
}
if got.Desc != "Example custom-build package" {
t.Errorf("Desc = %q, want %q", got.Desc, "Example custom-build package")
}
if got.URL != "https://example.org" {
t.Errorf("URL = %q, want %q", got.URL, "https://example.org")
}
if !slices.Equal(got.Arch, []string{"x86_64"}) {
t.Errorf("Arch = %v, want [x86_64]", got.Arch)
}
if !slices.Equal(got.Depends, []string{"glibc"}) {
t.Errorf("Depends = %v, want [glibc]", got.Depends)
}
if !slices.Equal(got.Sources, []string{"mytool-1.0.tar.gz"}) {
t.Errorf("Sources = %v, want [mytool-1.0.tar.gz]", got.Sources)
}
if !slices.Equal(got.SHA256Sums, []string{"SKIP"}) {
t.Errorf("SHA256Sums = %v, want [SKIP]", got.SHA256Sums)
}
}
// TestSrcInfoParseSplitPKGBUILD: a split package must PARSE fine (rejection
// happens later in the converter), yielding both pkgnames.
func TestSrcInfoParseSplitPKGBUILD(t *testing.T) {
src := readFixture(t, filepath.Join(srcinfoFixtures, "split", "PKGBUILD"))
got, err := ParsePKGBUILD(src)
if err != nil {
t.Fatalf("ParsePKGBUILD: %v", err)
}
if !slices.Equal(got.PkgNames, []string{"foo", "bar"}) {
t.Errorf("PkgNames = %v, want [foo bar]", got.PkgNames)
}
if got.PkgBase != "foobar" {
t.Errorf("PkgBase = %q, want %q", got.PkgBase, "foobar")
}
if got.Version != "1.0" {
t.Errorf("Version = %q, want %q", got.Version, "1.0")
}
}
// TestSrcInfoParseVCSPKGBUILD: VCS sources must come through verbatim so the
// converter can detect and reject them with a clear message.
func TestSrcInfoParseVCSPKGBUILD(t *testing.T) {
src := readFixture(t, filepath.Join(srcinfoFixtures, "vcs", "PKGBUILD"))
got, err := ParsePKGBUILD(src)
if err != nil {
t.Fatalf("ParsePKGBUILD: %v", err)
}
if !slices.Equal(got.PkgNames, []string{"mygit"}) {
t.Errorf("PkgNames = %v, want [mygit]", got.PkgNames)
}
if !slices.Contains(got.Sources, "git+https://example.org/repo.git") {
t.Errorf("Sources = %v, want it to contain %q", got.Sources, "git+https://example.org/repo.git")
}
}
// TestSrcInfoArchFilter feeds a .SRCINFO with arch-specific keys and checks
// that only the requested arch's variants are folded in.
func TestSrcInfoArchFilter(t *testing.T) {
src := `pkgbase = demo
pkgver = 2.0
pkgrel = 3
epoch = 1
depends = bash
depends_x86_64 = zsh
depends_aarch64 = sh
source_x86_64 = demo-2.0.tar.gz
source_aarch64 = demo-2.0-aarch64.tar.gz
sha256sums_x86_64 = SKIP
sha256sums_aarch64 = DEADBEEF
pkgname = demo
`
got, err := ParseSRCINFO(src, "x86_64")
if err != nil {
t.Fatalf("ParseSRCINFO(x86_64): %v", err)
}
if !slices.Equal(got.Depends, []string{"bash", "zsh"}) {
t.Errorf("Depends(x86_64) = %v, want [bash zsh] (aarch64 variant must NOT leak in)", got.Depends)
}
if !slices.Equal(got.Sources, []string{"demo-2.0.tar.gz"}) {
t.Errorf("Sources(x86_64) = %v, want [demo-2.0.tar.gz]", got.Sources)
}
if !slices.Equal(got.SHA256Sums, []string{"SKIP"}) {
t.Errorf("SHA256Sums(x86_64) = %v, want [SKIP]", got.SHA256Sums)
}
if got.Version != "2.0" || got.Rel != "3" || got.Epoch != "1" {
t.Errorf("Version/Rel/Epoch = %q/%q/%q, want %q/%q/%q", got.Version, got.Rel, got.Epoch, "2.0", "3", "1")
}
got, err = ParseSRCINFO(src, "aarch64")
if err != nil {
t.Fatalf("ParseSRCINFO(aarch64): %v", err)
}
if !slices.Equal(got.Depends, []string{"bash", "sh"}) {
t.Errorf("Depends(aarch64) = %v, want [bash sh]", got.Depends)
}
if !slices.Equal(got.Sources, []string{"demo-2.0-aarch64.tar.gz"}) {
t.Errorf("Sources(aarch64) = %v, want [demo-2.0-aarch64.tar.gz]", got.Sources)
}
if !slices.Equal(got.SHA256Sums, []string{"DEADBEEF"}) {
t.Errorf("SHA256Sums(aarch64) = %v, want [DEADBEEF]", got.SHA256Sums)
}
}
// TestSrcInfoMultiPkgnameSRCINFO: multiple pkgname sections must not fail
// parsing; every name is collected, only the FIRST section's keys apply.
func TestSrcInfoMultiPkgnameSRCINFO(t *testing.T) {
src := `pkgbase = split
pkgver = 1.0
pkgrel = 1
pkgname = foo
depends = a
pkgname = bar
depends = b
`
got, err := ParseSRCINFO(src, "x86_64")
if err != nil {
t.Fatalf("ParseSRCINFO: %v", err)
}
if !slices.Equal(got.PkgNames, []string{"foo", "bar"}) {
t.Errorf("PkgNames = %v, want [foo bar]", got.PkgNames)
}
if !slices.Equal(got.Depends, []string{"a"}) {
t.Errorf("Depends = %v, want [a] (only the first pkgname section applies)", got.Depends)
}
}
// TestSrcInfoPKGBUILDMissingPkgver: a PKGBUILD without a usable pkgver
// declaration is malformed and must error.
func TestSrcInfoPKGBUILDMissingPkgver(t *testing.T) {
src := `pkgname=foo
pkgrel=1
pkgdesc="no version here"
arch=(x86_64)
depends=('glibc')
`
got, err := ParsePKGBUILD(src)
if err == nil {
t.Fatalf("ParsePKGBUILD = %+v, want error for missing pkgver", got)
}
if !strings.Contains(err.Error(), "pkgver") {
t.Errorf("error %q does not mention pkgver", err)
}
}
// TestSrcInfoLoadDirPrefersSRCINFO: loading a directory uses .SRCINFO first
// (PkgBase is only present in the .SRCINFO fixture, not the PKGBUILD).
func TestSrcInfoLoadDirPrefersSRCINFO(t *testing.T) {
got, err := Load(filepath.Join(srcinfoFixtures, "mytool"), "x86_64")
if err != nil {
t.Fatalf("Load: %v", err)
}
if got.PkgBase != "mytool" {
t.Errorf("PkgBase = %q, want %q (proves .SRCINFO was preferred over PKGBUILD)", got.PkgBase, "mytool")
}
if got.Version != "1.0" {
t.Errorf("Version = %q, want %q", got.Version, "1.0")
}
}
// TestSrcInfoLoadDirFallsBackToPKGBUILD: a directory with only a PKGBUILD
// falls back to the best-effort parser.
func TestSrcInfoLoadDirFallsBackToPKGBUILD(t *testing.T) {
got, err := Load(filepath.Join(srcinfoFixtures, "split"), "x86_64")
if err != nil {
t.Fatalf("Load: %v", err)
}
if !slices.Equal(got.PkgNames, []string{"foo", "bar"}) {
t.Errorf("PkgNames = %v, want [foo bar]", got.PkgNames)
}
}
// TestSrcInfoLoadFilePKGBUILD: loading a file named PKGBUILD parses it as
// such regardless of directory.
func TestSrcInfoLoadFilePKGBUILD(t *testing.T) {
got, err := Load(filepath.Join(srcinfoFixtures, "vcs", "PKGBUILD"), "x86_64")
if err != nil {
t.Fatalf("Load: %v", err)
}
if !slices.Equal(got.PkgNames, []string{"mygit"}) {
t.Errorf("PkgNames = %v, want [mygit]", got.PkgNames)
}
}
// TestSrcInfoLoadFileSRCINFO: loading a file named .SRCINFO parses it as
// such.
func TestSrcInfoLoadFileSRCINFO(t *testing.T) {
got, err := Load(filepath.Join(srcinfoFixtures, "mytool", ".SRCINFO"), "x86_64")
if err != nil {
t.Fatalf("Load: %v", err)
}
if got.PkgBase != "mytool" {
t.Errorf("PkgBase = %q, want %q", got.PkgBase, "mytool")
}
}
// TestSrcInfoLoadUnknownFile: a file that is neither .SRCINFO nor PKGBUILD
// is rejected with a clear error.
func TestSrcInfoLoadUnknownFile(t *testing.T) {
dir := t.TempDir()
other := filepath.Join(dir, "notes.txt")
if err := os.WriteFile(other, []byte("pkgname=foo\npkgver=1\n"), 0o644); err != nil {
t.Fatalf("WriteFile: %v", err)
}
_, err := Load(other, "x86_64")
if err == nil {
t.Fatalf("Load(%s) = nil error, want unknown-file error", other)
}
if !strings.Contains(err.Error(), "unknown") {
t.Errorf("error %q does not mention the unknown file type", err)
}
}
// TestSrcInfoLoadMissingDir: a nonexistent path errors clearly.
func TestSrcInfoLoadMissingDir(t *testing.T) {
_, err := Load(filepath.Join(t.TempDir(), "does-not-exist"), "x86_64")
if err == nil {
t.Fatalf("Load(nonexistent) = nil error, want error")
}
}