mirror of
https://github.com/gogrlx/snack.git
synced 2026-04-02 05:08:42 -07:00
Implements the dnf sub-package with Manager, VersionQuerier, Holder, Cleaner, FileOwner, RepoManager, KeyManager, Grouper, and NameNormalizer interfaces. Implements the rpm sub-package with Manager, FileOwner, and NameNormalizer interfaces. Both follow the existing pattern: exported methods on struct delegate to unexported functions, _linux.go for real implementations, _other.go with build-tag stubs, embedded snack.Locker for mutating operations, and compile-time interface checks. Includes parser tests for all output formats.
235 lines
6.5 KiB
Go
235 lines
6.5 KiB
Go
package dnf
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/gogrlx/snack"
|
|
)
|
|
|
|
func TestParseList(t *testing.T) {
|
|
input := `Last metadata expiration check: 0:42:03 ago on Wed 26 Feb 2025 10:00:00 AM UTC.
|
|
Installed Packages
|
|
acl.x86_64 2.3.1-4.el9 @anaconda
|
|
bash.x86_64 5.1.8-6.el9 @anaconda
|
|
curl.x86_64 7.76.1-23.el9 @baseos
|
|
`
|
|
pkgs := parseList(input)
|
|
if len(pkgs) != 3 {
|
|
t.Fatalf("expected 3 packages, got %d", len(pkgs))
|
|
}
|
|
tests := []struct {
|
|
name, ver, arch, repo string
|
|
}{
|
|
{"acl", "2.3.1-4.el9", "x86_64", "@anaconda"},
|
|
{"bash", "5.1.8-6.el9", "x86_64", "@anaconda"},
|
|
{"curl", "7.76.1-23.el9", "x86_64", "@baseos"},
|
|
}
|
|
for i, tt := range tests {
|
|
if pkgs[i].Name != tt.name {
|
|
t.Errorf("pkg[%d].Name = %q, want %q", i, pkgs[i].Name, tt.name)
|
|
}
|
|
if pkgs[i].Version != tt.ver {
|
|
t.Errorf("pkg[%d].Version = %q, want %q", i, pkgs[i].Version, tt.ver)
|
|
}
|
|
if pkgs[i].Arch != tt.arch {
|
|
t.Errorf("pkg[%d].Arch = %q, want %q", i, pkgs[i].Arch, tt.arch)
|
|
}
|
|
if pkgs[i].Repository != tt.repo {
|
|
t.Errorf("pkg[%d].Repository = %q, want %q", i, pkgs[i].Repository, tt.repo)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestParseListUpgrades(t *testing.T) {
|
|
input := `Available Upgrades
|
|
curl.x86_64 7.76.1-26.el9 baseos
|
|
vim-minimal.x86_64 2:9.0.1572-1.el9 appstream
|
|
`
|
|
pkgs := parseList(input)
|
|
if len(pkgs) != 2 {
|
|
t.Fatalf("expected 2 packages, got %d", len(pkgs))
|
|
}
|
|
if pkgs[0].Name != "curl" || pkgs[0].Version != "7.76.1-26.el9" {
|
|
t.Errorf("unexpected first package: %+v", pkgs[0])
|
|
}
|
|
}
|
|
|
|
func TestParseSearch(t *testing.T) {
|
|
input := `Last metadata expiration check: 0:10:00 ago.
|
|
=== Name Exactly Matched: nginx ===
|
|
nginx.x86_64 : A high performance web server and reverse proxy server
|
|
=== Name & Summary Matched: nginx ===
|
|
nginx-mod-http-perl.x86_64 : Nginx HTTP perl module
|
|
`
|
|
pkgs := parseSearch(input)
|
|
if len(pkgs) != 2 {
|
|
t.Fatalf("expected 2 packages, got %d", len(pkgs))
|
|
}
|
|
if pkgs[0].Name != "nginx" || pkgs[0].Arch != "x86_64" {
|
|
t.Errorf("unexpected first package: %+v", pkgs[0])
|
|
}
|
|
if pkgs[0].Description != "A high performance web server and reverse proxy server" {
|
|
t.Errorf("unexpected description: %q", pkgs[0].Description)
|
|
}
|
|
}
|
|
|
|
func TestParseInfo(t *testing.T) {
|
|
input := `Last metadata expiration check: 0:10:00 ago.
|
|
Available Packages
|
|
Name : nginx
|
|
Version : 1.20.1
|
|
Release : 14.el9_2.1
|
|
Architecture : x86_64
|
|
Size : 45 k
|
|
Source : nginx-1.20.1-14.el9_2.1.src.rpm
|
|
Repository : appstream
|
|
Summary : A high performance web server
|
|
License : BSD
|
|
Description : Nginx is a web server.
|
|
`
|
|
p := parseInfo(input)
|
|
if p == nil {
|
|
t.Fatal("expected package, got nil")
|
|
}
|
|
if p.Name != "nginx" {
|
|
t.Errorf("Name = %q, want nginx", p.Name)
|
|
}
|
|
if p.Version != "1.20.1-14.el9_2.1" {
|
|
t.Errorf("Version = %q, want 1.20.1-14.el9_2.1", p.Version)
|
|
}
|
|
if p.Arch != "x86_64" {
|
|
t.Errorf("Arch = %q, want x86_64", p.Arch)
|
|
}
|
|
if p.Repository != "appstream" {
|
|
t.Errorf("Repository = %q, want appstream", p.Repository)
|
|
}
|
|
}
|
|
|
|
func TestParseVersionLock(t *testing.T) {
|
|
input := `Last metadata expiration check: 0:05:00 ago.
|
|
nginx-0:1.20.1-14.el9_2.1.*
|
|
curl-0:7.76.1-23.el9.*
|
|
`
|
|
pkgs := parseVersionLock(input)
|
|
if len(pkgs) != 2 {
|
|
t.Fatalf("expected 2 packages, got %d", len(pkgs))
|
|
}
|
|
if pkgs[0].Name != "nginx" {
|
|
t.Errorf("pkg[0].Name = %q, want nginx", pkgs[0].Name)
|
|
}
|
|
if pkgs[1].Name != "curl" {
|
|
t.Errorf("pkg[1].Name = %q, want curl", pkgs[1].Name)
|
|
}
|
|
}
|
|
|
|
func TestParseRepoList(t *testing.T) {
|
|
input := `repo id repo name status
|
|
appstream CentOS Stream 9 - AppStream enabled
|
|
baseos CentOS Stream 9 - BaseOS enabled
|
|
crb CentOS Stream 9 - CRB disabled
|
|
`
|
|
repos := parseRepoList(input)
|
|
if len(repos) != 3 {
|
|
t.Fatalf("expected 3 repos, got %d", len(repos))
|
|
}
|
|
if repos[0].ID != "appstream" || !repos[0].Enabled {
|
|
t.Errorf("unexpected repo[0]: %+v", repos[0])
|
|
}
|
|
if repos[2].ID != "crb" || repos[2].Enabled {
|
|
t.Errorf("unexpected repo[2]: %+v", repos[2])
|
|
}
|
|
}
|
|
|
|
func TestParseGroupList(t *testing.T) {
|
|
input := `Available Groups:
|
|
Container Management
|
|
Development Tools
|
|
Headless Management
|
|
Installed Groups:
|
|
Minimal Install
|
|
`
|
|
groups := parseGroupList(input)
|
|
if len(groups) != 4 {
|
|
t.Fatalf("expected 4 groups, got %d", len(groups))
|
|
}
|
|
if groups[0] != "Container Management" {
|
|
t.Errorf("groups[0] = %q, want Container Management", groups[0])
|
|
}
|
|
}
|
|
|
|
func TestParseGroupInfo(t *testing.T) {
|
|
input := `Group: Development Tools
|
|
Description: A basic development environment.
|
|
Mandatory Packages:
|
|
autoconf
|
|
automake
|
|
gcc
|
|
Default Packages:
|
|
byacc
|
|
flex
|
|
Optional Packages:
|
|
ElectricFence
|
|
`
|
|
pkgs := parseGroupInfo(input)
|
|
if len(pkgs) != 6 {
|
|
t.Fatalf("expected 6 packages, got %d", len(pkgs))
|
|
}
|
|
names := make(map[string]bool)
|
|
for _, p := range pkgs {
|
|
names[p.Name] = true
|
|
}
|
|
for _, want := range []string{"autoconf", "automake", "gcc", "byacc", "flex", "ElectricFence"} {
|
|
if !names[want] {
|
|
t.Errorf("missing package %q", want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestNormalizeName(t *testing.T) {
|
|
tests := []struct {
|
|
input, want string
|
|
}{
|
|
{"nginx.x86_64", "nginx"},
|
|
{"curl.aarch64", "curl"},
|
|
{"bash.noarch", "bash"},
|
|
{"python3", "python3"},
|
|
{"glibc.i686", "glibc"},
|
|
}
|
|
for _, tt := range tests {
|
|
got := normalizeName(tt.input)
|
|
if got != tt.want {
|
|
t.Errorf("normalizeName(%q) = %q, want %q", tt.input, got, tt.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestParseArch(t *testing.T) {
|
|
tests := []struct {
|
|
input, wantName, wantArch string
|
|
}{
|
|
{"nginx.x86_64", "nginx", "x86_64"},
|
|
{"curl.aarch64", "curl", "aarch64"},
|
|
{"bash", "bash", ""},
|
|
{"python3.11.noarch", "python3.11", "noarch"},
|
|
}
|
|
for _, tt := range tests {
|
|
name, arch := parseArch(tt.input)
|
|
if name != tt.wantName || arch != tt.wantArch {
|
|
t.Errorf("parseArch(%q) = (%q, %q), want (%q, %q)", tt.input, name, arch, tt.wantName, tt.wantArch)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Ensure interface checks from capabilities.go are satisfied.
|
|
var (
|
|
_ snack.Manager = (*DNF)(nil)
|
|
_ snack.VersionQuerier = (*DNF)(nil)
|
|
_ snack.Holder = (*DNF)(nil)
|
|
_ snack.Cleaner = (*DNF)(nil)
|
|
_ snack.FileOwner = (*DNF)(nil)
|
|
_ snack.RepoManager = (*DNF)(nil)
|
|
_ snack.KeyManager = (*DNF)(nil)
|
|
_ snack.Grouper = (*DNF)(nil)
|
|
_ snack.NameNormalizer = (*DNF)(nil)
|
|
)
|