first commit

This commit is contained in:
robojerk 2025-09-05 07:10:12 -07:00
commit 7584207f76
72 changed files with 12801 additions and 0 deletions

View file

@ -0,0 +1,279 @@
package apt
import (
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// createTestSolver creates a test solver with default configuration
func createTestSolver(t *testing.T) *Solver {
tmpDir := t.TempDir()
repos := []RepoConfig{
{
BaseURL: "http://deb.debian.org/debian",
Components: []string{"main"},
Priority: 500,
},
}
solver, err := NewSolver(tmpDir, "amd64", repos)
require.NoError(t, err)
return solver
}
func TestSolverCreation(t *testing.T) {
// Test creating a new solver
solver := createTestSolver(t)
assert.NotNil(t, solver)
assert.NotNil(t, solver.repos)
}
func TestMockDepsolve(t *testing.T) {
solver := createTestSolver(t)
// Test mock depsolve with empty package list
result, err := solver.mockDepsolve([]string{})
assert.NoError(t, err)
assert.NotNil(t, result)
assert.Empty(t, result.Packages)
// Test mock depsolve with some packages
packages := []string{"base-files", "systemd", "linux-image-amd64"}
result, err = solver.mockDepsolve(packages)
assert.NoError(t, err)
assert.NotNil(t, result)
// Check that we got PackageSpec structs with correct names
expectedNames := []string{"base-files", "systemd", "linux-image-amd64"}
actualNames := make([]string, len(result.Packages))
for i, pkg := range result.Packages {
actualNames[i] = pkg.Name
}
assert.Equal(t, expectedNames, actualNames)
}
func TestDepsolve(t *testing.T) {
solver := createTestSolver(t)
// Test depsolve with empty package list
result, err := solver.Depsolve([]string{}, 0)
assert.NoError(t, err)
assert.NotNil(t, result)
assert.Empty(t, result.Packages)
// Test depsolve with some packages (should fall back to mock)
packages := []string{"base-files", "systemd", "linux-image-amd64"}
result, err = solver.Depsolve(packages, 0)
assert.NoError(t, err)
assert.NotNil(t, result)
// Check that we got PackageSpec structs with correct names
expectedNames := []string{"base-files", "systemd", "linux-image-amd64"}
actualNames := make([]string, len(result.Packages))
for i, pkg := range result.Packages {
actualNames[i] = pkg.Name
}
assert.Equal(t, expectedNames, actualNames)
}
func TestParseAptOutput(t *testing.T) {
solver := createTestSolver(t)
// Test with empty output
result := solver.parseAptOutput("")
assert.Empty(t, result)
// Test with valid package names
output := `base-files
systemd
linux-image-amd64
grub-common`
result = solver.parseAptOutput(output)
expected := []string{"base-files", "systemd", "linux-image-amd64", "grub-common"}
assert.ElementsMatch(t, expected, result)
// Test with dependency keywords (should be filtered out)
output = `Depends: base-files
PreDepends: systemd
Breaks: old-package
Replaces: old-package
Conflicts: conflicting-package
Recommends: recommended-package
Suggests: suggested-package
Enhances: enhanced-package
|Depends: alternative-package
|PreDepends: alternative-pre-depends
Enhances: enhanced-package
base-files
systemd`
result = solver.parseAptOutput(output)
expected = []string{"base-files", "systemd"}
assert.ElementsMatch(t, expected, result)
// Test with package names containing special characters (should be filtered out)
output = `base-files
<virtual-package>
>version-constraint
|alternative-package
base-files:amd64
systemd`
result = solver.parseAptOutput(output)
expected = []string{"base-files", "systemd"}
assert.ElementsMatch(t, expected, result)
// Test with mixed content
output = `Depends: base-files
systemd
Breaks: old-package
linux-image-amd64
|Depends: alternative
grub-common
Enhances: enhanced
bootc`
result = solver.parseAptOutput(output)
expected = []string{"systemd", "linux-image-amd64", "grub-common", "bootc"}
assert.ElementsMatch(t, expected, result)
}
func TestCreateAptConf(t *testing.T) {
solver := createTestSolver(t)
// Test creating apt configuration
aptConfPath, err := solver.createAptConf()
assert.NoError(t, err)
assert.NotEmpty(t, aptConfPath)
// Check that apt.conf was created
assert.FileExists(t, aptConfPath)
// Check that sources.list was created in the same directory as apt.conf
sourcesListPath := filepath.Join(filepath.Dir(aptConfPath), "sources.list")
assert.FileExists(t, sourcesListPath)
// Read and verify apt.conf content
aptConfContent, err := os.ReadFile(aptConfPath)
assert.NoError(t, err)
aptConfStr := string(aptConfContent)
assert.Contains(t, aptConfStr, "Dir::Etc::SourceList")
assert.Contains(t, aptConfStr, "sources.list")
// Read and verify sources.list content
sourcesListContent, err := os.ReadFile(sourcesListPath)
assert.NoError(t, err)
sourcesListStr := string(sourcesListContent)
assert.Contains(t, sourcesListStr, "deb.debian.org")
assert.Contains(t, sourcesListStr, "main")
}
func TestGetPackageVersion(t *testing.T) {
solver := createTestSolver(t)
// Test getting version for a package (may get real version or fall back to mock)
version, err := solver.getPackageVersion("base-files", "")
// Don't assert specific version since it depends on system state
assert.NoError(t, err)
assert.NotEmpty(t, version)
// Test getting version for non-existent package (should fall back to mock)
version, err = solver.getPackageVersion("non-existent-package", "")
// This might fail with real apt-cache, so we just check it doesn't panic
_ = version
_ = err
}
func TestRealDepsolve(t *testing.T) {
solver := createTestSolver(t)
// Test real depsolve (may fail if apt-cache is not available)
result, err := solver.realDepsolve([]string{"base-files"})
// We don't assert success here because apt-cache may not be available in test environment
// The important thing is that it doesn't panic
// Result might be nil if apt-cache fails, which is acceptable
_ = result
_ = err // Suppress unused variable warning
}
func TestSolverWithCustomRepos(t *testing.T) {
// Test creating solver with custom repositories
repos := []RepoConfig{
{
BaseURL: "http://deb.debian.org/debian",
Components: []string{"main"},
Priority: 500,
},
{
BaseURL: "https://git.raines.xyz/api/packages/particle-os/debian",
Components: []string{"trixie", "main"},
Priority: 400,
},
}
solver := &Solver{repos: repos}
assert.NotNil(t, solver)
assert.Equal(t, repos, solver.repos)
}
func TestDepsolveWithLargePackageList(t *testing.T) {
solver := createTestSolver(t)
// Test with a large package list
packages := make([]string, 100)
for i := 0; i < 100; i++ {
packages[i] = "package-" + string(rune('a'+i%26))
}
result, err := solver.Depsolve(packages, 0)
assert.NoError(t, err)
assert.NotNil(t, result)
// Check that we got PackageSpec structs with correct names
actualNames := make([]string, len(result.Packages))
for i, pkg := range result.Packages {
actualNames[i] = pkg.Name
}
assert.Equal(t, packages, actualNames)
}
func TestParseAptOutputEdgeCases(t *testing.T) {
solver := createTestSolver(t)
// Test with only whitespace
result := solver.parseAptOutput(" \n\t \n ")
assert.Empty(t, result)
// Test with only dependency keywords
output := `Depends: package1
PreDepends: package2
Breaks: package3
Replaces: package4
Conflicts: package5
Recommends: package6
Suggests: package7
Enhances: package8
|Depends: package9
|PreDepends: package10`
result = solver.parseAptOutput(output)
assert.Empty(t, result)
// Test with only special characters
output = `<virtual>
>constraint
|alternative
package:arch`
result = solver.parseAptOutput(output)
assert.Empty(t, result)
// Test with mixed valid and invalid
output = `valid-package
Depends: invalid
another-valid
<virtual>
yet-another-valid`
result = solver.parseAptOutput(output)
expected := []string{"valid-package", "another-valid", "yet-another-valid"}
assert.ElementsMatch(t, expected, result)
}