refactor: tests with testify (#2057)

Signed-off-by: Fabrizio Sestito <fabrizio.sestito@suse.com>
This commit is contained in:
Fabrizio Sestito authored and Alessio Biancalana committed 2026-06-14 13:04:28 +02:00
1 parent ffeba2b78b
commit 637725affe
7 files changed
+154 -429

No files matched your search

+9 -20
View File
@@ -5,6 +5,9 @@ import (
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
insidedistrobox "github.com/89luca89/distrobox/internal/inside-distrobox"
)
@@ -13,14 +16,10 @@ func TestProvisionScripts_CustomDir(t *testing.T) {
t.Setenv("DBX_SCRIPTS_DIR", tmpDir)
scriptsDir, err := insidedistrobox.ProvisionScripts()
if err != nil {
t.Fatalf("ProvisionScripts failed: %v", err)
}
require.NoError(t, err, "ProvisionScripts failed")
defer os.RemoveAll(scriptsDir)
if scriptsDir != tmpDir {
t.Fatalf("Expected scripts directory to be %s, but got %s", tmpDir, scriptsDir)
}
require.Equal(t, tmpDir, scriptsDir)
expectedScripts := []string{
"distrobox-host-exec",
@@ -30,10 +29,7 @@ func TestProvisionScripts_CustomDir(t *testing.T) {
for _, scriptName := range expectedScripts {
scriptPath := filepath.Join(scriptsDir, scriptName)
_, err := os.Stat(scriptPath)
if err != nil {
t.Errorf("Expected script %s to exist, but got error: %v", scriptName, err)
}
assert.FileExists(t, scriptPath, "Expected script %s to exist", scriptName)
}
}
@@ -42,15 +38,11 @@ func TestProvisionScripts_HomeDir(t *testing.T) {
t.Setenv("HOME", tmpDir)
scriptsDir, err := insidedistrobox.ProvisionScripts()
if err != nil {
t.Fatalf("ProvisionScripts failed: %v", err)
}
require.NoError(t, err, "ProvisionScripts failed")
defer os.RemoveAll(scriptsDir)
expected := filepath.Join(tmpDir, ".local", "share", "distrobox", "v2")
if scriptsDir != expected {
t.Fatalf("Expected scripts directory to be %s, but got %s", expected, scriptsDir)
}
require.Equal(t, expected, scriptsDir)
expectedScripts := []string{
"distrobox-host-exec",
@@ -60,9 +52,6 @@ func TestProvisionScripts_HomeDir(t *testing.T) {
for _, scriptName := range expectedScripts {
scriptPath := filepath.Join(scriptsDir, scriptName)
_, err := os.Stat(scriptPath)
if err != nil {
t.Errorf("Expected script %s to exist, but got error: %v", scriptName, err)
}
assert.FileExists(t, scriptPath, "Expected script %s to exist", scriptName)
}
}
+33 -87
View File
@@ -9,6 +9,9 @@ import (
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/89luca89/distrobox/internal/userenv"
)
@@ -34,31 +37,19 @@ func TestLoadUserEnvironment_EnvironmentVariables(t *testing.T) {
env := userenv.LoadUserEnvironment(ctx)
// Verify env vars took precedence
if env.User != "testuser" {
t.Errorf("Expected User='testuser', got '%s'", env.User)
}
if env.Home != "/test/home" {
t.Errorf("Expected Home='/test/home', got '%s'", env.Home)
}
if env.Shell != "/test/shell" {
t.Errorf("Expected Shell='/test/shell', got '%s'", env.Shell)
}
assert.Equal(t, "testuser", env.User)
assert.Equal(t, "/test/home", env.Home)
assert.Equal(t, "/test/shell", env.Shell)
// UserID and GroupID should still be populated from system
if env.UserID == "" {
t.Error("UserID should not be empty")
}
if env.GroupID == "" {
t.Error("GroupID should not be empty")
}
assert.NotEmpty(t, env.UserID, "UserID should not be empty")
assert.NotEmpty(t, env.GroupID, "GroupID should not be empty")
// Verify they're numeric strings
if _, err := strconv.Atoi(env.UserID); err != nil {
t.Errorf("UserID should be numeric, got '%s': %v", env.UserID, err)
}
if _, err := strconv.Atoi(env.GroupID); err != nil {
t.Errorf("GroupID should be numeric, got '%s': %v", env.GroupID, err)
}
_, err := strconv.Atoi(env.UserID)
require.NoError(t, err, "UserID should be numeric, got '%s'", env.UserID)
_, err = strconv.Atoi(env.GroupID)
assert.NoError(t, err, "GroupID should be numeric, got '%s'", env.GroupID)
}
func TestLoadUserEnvironment_NoEnvironmentVariables(t *testing.T) {
@@ -87,30 +78,18 @@ func TestLoadUserEnvironment_NoEnvironmentVariables(t *testing.T) {
env := userenv.LoadUserEnvironment(ctx)
// Should have found values from system
if env.User == "" {
t.Error("User should not be empty")
}
assert.NotEmpty(t, env.User, "User should not be empty")
if env.User == "nobody" {
t.Log("Warning: User defaulted to 'nobody', system lookups might have failed")
}
if env.Home == "" {
t.Error("Home should not be empty")
}
assert.NotEmpty(t, env.Home, "Home should not be empty")
// Shell should at least have the default
if env.Shell == "" {
t.Error("Shell should not be empty")
}
if env.UserID == "" {
t.Error("UserID should not be empty")
}
if env.GroupID == "" {
t.Error("GroupID should not be empty")
}
assert.NotEmpty(t, env.Shell, "Shell should not be empty")
assert.NotEmpty(t, env.UserID, "UserID should not be empty")
assert.NotEmpty(t, env.GroupID, "GroupID should not be empty")
}
func TestLoadUserEnvironment_ContextCancellation(t *testing.T) {
@@ -131,17 +110,11 @@ func TestLoadUserEnvironment_ContextCancellation(t *testing.T) {
// Should still work but getent might fail due to cancelled context
// The function should handle this gracefully
if env.User == "" {
t.Error("User should not be empty even with cancelled context")
}
assert.NotEmpty(t, env.User, "User should not be empty even with cancelled context")
// Should have defaults or fallbacks
if env.Home == "" {
t.Error("Home should not be empty")
}
if env.Shell == "" {
t.Error("Shell should not be empty")
}
assert.NotEmpty(t, env.Home, "Home should not be empty")
assert.NotEmpty(t, env.Shell, "Shell should not be empty")
}
func TestLoadUserEnvironment_ContextTimeout(t *testing.T) {
@@ -155,17 +128,11 @@ func TestLoadUserEnvironment_ContextTimeout(t *testing.T) {
env := userenv.LoadUserEnvironment(ctx)
// Function should still return valid data through fallbacks
if env == nil {
t.Fatal("LoadUserEnvironment should never return nil")
}
require.NotNil(t, env, "LoadUserEnvironment should never return nil")
// Basic fields should still be populated
if env.UserID == "" {
t.Error("UserID should be populated even with timeout")
}
if env.GroupID == "" {
t.Error("GroupID should be populated even with timeout")
}
assert.NotEmpty(t, env.UserID, "UserID should be populated even with timeout")
assert.NotEmpty(t, env.GroupID, "GroupID should be populated even with timeout")
}
func TestLoadUserEnvironment_PartialEnvironment(t *testing.T) {
@@ -199,14 +166,10 @@ func TestLoadUserEnvironment_PartialEnvironment(t *testing.T) {
ctx := context.Background()
env := userenv.LoadUserEnvironment(ctx)
if env.User != "testuser" {
t.Errorf("Expected User='testuser', got '%s'", env.User)
}
assert.Equal(t, "testuser", env.User)
// HOME should be populated (either from passwd or default)
if env.Home == "" {
t.Error("Home should not be empty")
}
assert.NotEmpty(t, env.Home, "Home should not be empty")
// If getent fails for testuser, should have default home
if env.Home == "/home/testuser" {
@@ -214,9 +177,7 @@ func TestLoadUserEnvironment_PartialEnvironment(t *testing.T) {
}
// Shell should have a value (from passwd or default)
if env.Shell == "" {
t.Error("Shell should not be empty")
}
assert.NotEmpty(t, env.Shell, "Shell should not be empty")
// Default shell should be /bin/sh if user doesn't exist
if env.Shell == "/bin/sh" {
@@ -229,32 +190,19 @@ func TestLoadUserEnvironment_IDs(t *testing.T) {
env := userenv.LoadUserEnvironment(ctx)
// These should always be populated on a Unix system
if env.UserID == "" {
t.Error("UserID should not be empty")
}
if env.GroupID == "" {
t.Error("GroupID should not be empty")
}
assert.NotEmpty(t, env.UserID, "UserID should not be empty")
assert.NotEmpty(t, env.GroupID, "GroupID should not be empty")
// Verify they're valid integers
uid, err := strconv.Atoi(env.UserID)
if err != nil {
t.Errorf("UserID should be a valid integer, got '%s': %v", env.UserID, err)
}
require.NoError(t, err, "UserID should be a valid integer, got '%s'", env.UserID)
gid, err := strconv.Atoi(env.GroupID)
if err != nil {
t.Errorf("GroupID should be a valid integer, got '%s': %v", env.GroupID, err)
}
require.NoError(t, err, "GroupID should be a valid integer, got '%s'", env.GroupID)
// Verify they match os.Getuid() and os.Getgid()
if uid != os.Getuid() {
t.Errorf("UserID mismatch: got %d, expected %d", uid, os.Getuid())
}
if gid != os.Getgid() {
t.Errorf("GroupID mismatch: got %d, expected %d", gid, os.Getgid())
}
assert.Equal(t, os.Getuid(), uid, "UserID mismatch")
assert.Equal(t, os.Getgid(), gid, "GroupID mismatch")
}
func TestLoadUserEnvironment_SystemCommands(t *testing.T) {
@@ -285,9 +233,7 @@ func TestLoadUserEnvironment_SystemCommands(t *testing.T) {
}
result := strings.TrimSpace(string(output))
if result == "" {
t.Errorf("%s returned empty output", tc.name)
}
assert.NotEmpty(t, result, "%s returned empty output", tc.name)
t.Logf("%s output: %s", tc.name, result)
})
+21 -55
View File
@@ -8,6 +8,9 @@ import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/89luca89/distrobox/pkg/commands"
"github.com/89luca89/distrobox/pkg/config"
"github.com/89luca89/distrobox/pkg/containermanager"
@@ -40,21 +43,12 @@ func TestAssembleCommand_SetupBox_StartNowTrue(t *testing.T) {
},
},
})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if len(mock.Spy.Enter) == 0 {
t.Fatal("expected Enter to be called when StartNow is true, but it was not")
}
require.NoError(t, err)
require.NotEmpty(t, mock.Spy.Enter, "expected Enter to be called when StartNow is true")
opts := getEnterOptions(mock.Spy, 0)
if opts.ContainerName != "test-box" {
t.Errorf("expected ContainerName %q, got %q", "test-box", opts.ContainerName)
}
if opts.CustomCommand != "true" {
t.Errorf("expected CustomCommand %q, got %q", "true", opts.CustomCommand)
}
assert.Equal(t, "test-box", opts.ContainerName)
assert.Equal(t, "true", opts.CustomCommand)
}
func TestAssembleCommand_SetupBox_ExportedApps_Valid(t *testing.T) {
@@ -83,21 +77,13 @@ func TestAssembleCommand_SetupBox_ExportedApps_Valid(t *testing.T) {
},
},
})
if err != nil {
t.Fatalf("expected valid app name %q to succeed, got error: %v", app, err)
}
if len(mock.Spy.Enter) != len(apps) {
t.Fatalf("expected Enter to be called %d times, got %d", len(apps), len(mock.Spy.Enter))
}
require.NoError(t, err, "expected valid app name %q to succeed", app)
require.Len(t, mock.Spy.Enter, len(apps))
for i, a := range apps {
opts := getEnterOptions(mock.Spy, i)
expectedCmd := fmt.Sprintf("distrobox-export --app %s", a)
if opts.ContainerName != "test-box" {
t.Errorf("call %d: expected ContainerName %q, got %q", i, "test-box", opts.ContainerName)
}
if opts.CustomCommand != expectedCmd {
t.Errorf("call %d: expected CustomCommand %q, got %q", i, expectedCmd, opts.CustomCommand)
}
assert.Equal(t, "test-box", opts.ContainerName, "call %d", i)
assert.Equal(t, expectedCmd, opts.CustomCommand, "call %d", i)
}
})
}
@@ -129,12 +115,8 @@ func TestAssembleCommand_SetupBox_ExportedApps_Invalid(t *testing.T) {
},
},
})
if err == nil {
t.Fatalf("expected invalid app name %q to be rejected, but got no error", app)
}
if len(mock.Spy.Enter) != 0 {
t.Errorf("expected Enter to not be called for invalid app name %q, but it was called %d times", app, len(mock.Spy.Enter))
}
require.Error(t, err, "expected invalid app name %q to be rejected", app)
assert.Empty(t, mock.Spy.Enter, "expected Enter to not be called for invalid app name %q", app)
})
}
}
@@ -165,21 +147,13 @@ func TestAssembleCommand_SetupBox_ExportedBins_Valid(t *testing.T) {
},
},
})
if err != nil {
t.Fatalf("expected valid bin path %q to succeed, got error: %v", bin, err)
}
if len(mock.Spy.Enter) != len(bins) {
t.Fatalf("expected Enter to be called %d times, got %d", len(bins), len(mock.Spy.Enter))
}
require.NoError(t, err, "expected valid bin path %q to succeed", bin)
require.Len(t, mock.Spy.Enter, len(bins))
for i, b := range bins {
opts := getEnterOptions(mock.Spy, i)
expectedCmd := fmt.Sprintf("distrobox-export --bin %s --export-path /home/user/.local/bin", b)
if opts.ContainerName != "test-box" {
t.Errorf("call %d: expected ContainerName %q, got %q", i, "test-box", opts.ContainerName)
}
if opts.CustomCommand != expectedCmd {
t.Errorf("call %d: expected CustomCommand %q, got %q", i, expectedCmd, opts.CustomCommand)
}
assert.Equal(t, "test-box", opts.ContainerName, "call %d", i)
assert.Equal(t, expectedCmd, opts.CustomCommand, "call %d", i)
}
})
}
@@ -211,12 +185,8 @@ func TestAssembleCommand_SetupBox_ExportedBins_Invalid(t *testing.T) {
},
},
})
if err == nil {
t.Fatalf("expected invalid bin path %q to be rejected, but got no error", bin)
}
if len(mock.Spy.Enter) != 0 {
t.Errorf("expected Enter to not be called for invalid bin path %q, but it was called %d times", bin, len(mock.Spy.Enter))
}
require.Error(t, err, "expected invalid bin path %q to be rejected", bin)
assert.Empty(t, mock.Spy.Enter, "expected Enter to not be called for invalid bin path %q", bin)
})
}
}
@@ -245,12 +215,8 @@ func TestAssembleCommand_SetupBox_ExportedBins_InvalidExportPath(t *testing.T) {
},
},
})
if err == nil {
t.Fatalf("expected invalid export path %q to be rejected, but got no error", path)
}
if len(mock.Spy.Enter) != 0 {
t.Errorf("expected Enter to not be called for invalid export path %q, but it was called %d times", path, len(mock.Spy.Enter))
}
require.Error(t, err, "expected invalid export path %q to be rejected", path)
assert.Empty(t, mock.Spy.Enter, "expected Enter to not be called for invalid export path %q", path)
})
}
}
+19 -60
View File
@@ -6,6 +6,9 @@ import (
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/89luca89/distrobox/pkg/commands"
"github.com/89luca89/distrobox/pkg/config"
"github.com/89luca89/distrobox/pkg/containermanager/providers"
@@ -38,14 +41,10 @@ func TestGenerateEntryCommand_Execute(t *testing.T) {
}
err := generateEntryCmd.Execute(ctx, opts)
if err != nil {
t.Errorf("GenerateEntryCommand.Execute() error = %v", err)
}
require.NoError(t, err, "GenerateEntryCommand.Execute()")
expectedEntryPath := fmt.Sprintf("%s/.local/share/applications/test-container.desktop", tempDir)
if _, err := os.Stat(expectedEntryPath); os.IsNotExist(err) {
t.Errorf("Expected desktop entry file %s does not exist, %s", expectedEntryPath, tempDir)
}
assert.FileExists(t, expectedEntryPath)
expectedContent := `[Desktop Entry]
Name=Test-container
@@ -67,34 +66,19 @@ Exec=/usr/bin/distrobox rm test-container
`
content, err := os.ReadFile(expectedEntryPath)
if err != nil {
t.Errorf("Failed to read desktop entry file: %v", err)
}
if string(content) != expectedContent {
t.Errorf(
"Desktop entry content does not match expected.\nGot:\n'%s'\nExpected:\n'%s'",
string(content),
expectedContent,
)
}
require.NoError(t, err, "Failed to read desktop entry file")
assert.Equal(t, expectedContent, string(content), "Desktop entry content mismatch")
// Delete the entry
opts.Delete = true
err = generateEntryCmd.Execute(ctx, opts)
if err != nil {
t.Errorf("GenerateEntryCommand.Execute() error on delete = %v", err)
}
require.NoError(t, err, "GenerateEntryCommand.Execute() on delete")
if _, err := os.Stat(expectedEntryPath); !os.IsNotExist(err) {
t.Errorf("Expected desktop entry file %s to be deleted, %s", expectedEntryPath, tempDir)
}
assert.NoFileExists(t, expectedEntryPath)
// Try deleting a non-existing entry
err = generateEntryCmd.Execute(ctx, opts)
if err != nil {
t.Errorf("GenerateEntryCommand.Execute() error on delete non-existing = %v", err)
}
assert.NoError(t, err, "GenerateEntryCommand.Execute() on delete non-existing")
}
func TestGenerateEntryCommand_Execute_Root(t *testing.T) {
@@ -119,14 +103,10 @@ func TestGenerateEntryCommand_Execute_Root(t *testing.T) {
}
err := generateEntryCmd.Execute(ctx, opts)
if err != nil {
t.Errorf("GenerateEntryCommand.Execute() error = %v", err)
}
require.NoError(t, err, "GenerateEntryCommand.Execute()")
expectedEntryPath := fmt.Sprintf("%s/.local/share/applications/test-container.desktop", tempDir)
if _, err := os.Stat(expectedEntryPath); os.IsNotExist(err) {
t.Errorf("Expected desktop entry file %s does not exist, %s", expectedEntryPath, tempDir)
}
assert.FileExists(t, expectedEntryPath)
expectedContent := `[Desktop Entry]
Name=Test-container
@@ -148,17 +128,8 @@ Exec=/usr/bin/distrobox rm --root test-container
`
content, err := os.ReadFile(expectedEntryPath)
if err != nil {
t.Errorf("Failed to read desktop entry file: %v", err)
}
if string(content) != expectedContent {
t.Errorf(
"Desktop entry content does not match expected.\nGot:\n'%s'\nExpected:\n'%s'",
string(content),
expectedContent,
)
}
require.NoError(t, err, "Failed to read desktop entry file")
assert.Equal(t, expectedContent, string(content), "Desktop entry content mismatch")
}
func TestGenerateAllEntriesCommand_Execute(t *testing.T) {
@@ -187,23 +158,16 @@ func TestGenerateAllEntriesCommand_Execute(t *testing.T) {
DistroboxPath: "/usr/bin/distrobox",
}
err := genAllEntriesCmd.Execute(ctx, opts)
if err != nil {
t.Errorf("GenerateAllEntriesCommand.Execute() error = %v", err)
}
require.NoError(t, err, "GenerateAllEntriesCommand.Execute()")
// retrieve the list of containers to verify entries were created
listResult, err := listCmd.Execute(ctx)
if err != nil {
t.Errorf("ListCommand.Execute() error = %v", err)
}
require.NoError(t, err, "ListCommand.Execute()")
// verify that each container has a corresponding desktop entry
for _, container := range listResult.Containers {
expectedEntryPath := fmt.Sprintf("%s/.local/share/applications/%s.desktop", tempDir, container.Name)
if _, err := os.Stat(expectedEntryPath); os.IsNotExist(err) {
t.Errorf("Expected desktop entry file %s does not exist", expectedEntryPath)
}
assert.FileExists(t, expectedEntryPath)
}
//
@@ -212,16 +176,11 @@ func TestGenerateAllEntriesCommand_Execute(t *testing.T) {
opts.Delete = true
err = genAllEntriesCmd.Execute(ctx, opts)
if err != nil {
t.Errorf("GenerateAllEntriesCommand.Execute() error = %v", err)
}
require.NoError(t, err, "GenerateAllEntriesCommand.Execute() on delete")
// verify that each container's desktop entry has been deleted
for _, container := range listResult.Containers {
expectedEntryPath := fmt.Sprintf("%s/.local/share/applications/%s.desktop", tempDir, container.Name)
if _, err := os.Stat(expectedEntryPath); !os.IsNotExist(err) {
t.Errorf("Expected desktop entry file %s to be deleted", expectedEntryPath)
}
assert.NoFileExists(t, expectedEntryPath)
}
}
@@ -4,6 +4,8 @@ import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/89luca89/distrobox/internal/userenv"
)
@@ -110,9 +112,7 @@ func TestDocker_makeCreateCommand(t *testing.T) {
got := oneline(strings.Join(cmd, " "))
if got != expected {
t.Errorf("Expected command:\n'%s'\nGot:\n'%s'", expected, got)
}
assert.Equal(t, expected, got)
}
func TestBuildContainerPath(t *testing.T) {
@@ -210,9 +210,7 @@ func TestBuildContainerPath(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := buildContainerPath(tt.cleanPath, tt.hostPath, tt.containerPath)
if got != tt.want {
t.Errorf("buildContainerPath() = %v, want %v", got, tt.want)
}
assert.Equal(t, tt.want, got)
})
}
}
@@ -222,24 +220,18 @@ func TestBuildContainerPathEdgeCases(t *testing.T) {
t.Run("hostPath with colon at start", func(t *testing.T) {
got := buildContainerPath(false, ":/usr/bin", "")
// Should treat this as hostPath not containing standard paths initially
if !contains(got, "/usr/local/sbin") {
t.Errorf("Expected standard paths to be added")
}
assert.True(t, contains(got, "/usr/local/sbin"), "Expected standard paths to be added")
})
t.Run("hostPath with colon at end", func(t *testing.T) {
got := buildContainerPath(false, "/usr/bin:", "")
if !contains(got, "/usr/local/sbin") {
t.Errorf("Expected standard paths to be added")
}
assert.True(t, contains(got, "/usr/local/sbin"), "Expected standard paths to be added")
})
t.Run("hostPath with multiple colons", func(t *testing.T) {
got := buildContainerPath(false, "/usr/bin::/sbin", "")
// Should still add missing standard paths
if !contains(got, "/usr/local/sbin") {
t.Errorf("Expected standard paths to be added")
}
assert.True(t, contains(got, "/usr/local/sbin"), "Expected standard paths to be added")
})
}
@@ -379,9 +371,7 @@ func TestBuildCommandArgs(t *testing.T) {
got := buildCommandArgs(tt.customCommand, tt.user, tt.noTTY, tt.unshareGroups)
gotStr := strings.Join(got, "|")
if gotStr != tt.want {
t.Errorf("buildCommandArgs() = %q, want %q", gotStr, tt.want)
}
assert.Equal(t, tt.want, gotStr)
})
}
}
@@ -460,15 +450,11 @@ func TestBuildCommandArgsMatrix(t *testing.T) {
resultStr := strings.Join(result, "|")
for _, want := range tt.wantContains {
if !strings.Contains(resultStr, want) {
t.Errorf("Expected result to contain %q, got: %q", want, resultStr)
}
assert.Contains(t, resultStr, want)
}
for _, notWant := range tt.wantNotContains {
if strings.Contains(resultStr, notWant) {
t.Errorf("Expected result NOT to contain %q, got: %q", notWant, resultStr)
}
assert.NotContains(t, resultStr, notWant)
}
})
}
@@ -6,6 +6,9 @@ import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/89luca89/distrobox/internal/userenv"
)
@@ -63,9 +66,7 @@ func TestPodman_makeCreateCommand(t *testing.T) {
}
for _, flag := range requiredFlags {
if !strings.Contains(cmdStr, flag) {
t.Errorf("Expected command to contain '%s', but it was missing.\nCommand: %s", flag, cmdStr)
}
assert.Contains(t, cmdStr, flag)
}
// Check Docker-specific flags are NOT present
@@ -78,13 +79,7 @@ func TestPodman_makeCreateCommand(t *testing.T) {
}
for _, flag := range dockerOnlyFlags {
if strings.Contains(cmdStr, flag) {
t.Errorf(
"Expected command NOT to contain Docker-specific flag '%s', but it was present.\nCommand: %s",
flag,
cmdStr,
)
}
assert.NotContains(t, cmdStr, flag)
}
// Check common flags are present
@@ -96,9 +91,7 @@ func TestPodman_makeCreateCommand(t *testing.T) {
}
for _, flag := range commonFlags {
if !strings.Contains(cmdStr, flag) {
t.Errorf("Expected command to contain common flag '%s', but it was missing.\nCommand: %s", flag, cmdStr)
}
assert.Contains(t, cmdStr, flag)
}
}
@@ -143,17 +136,11 @@ func TestPodman_makeCreateCommandRootful(t *testing.T) {
cmdStr := strings.Join(cmd, " ")
// Rootful mode should NOT have --userns keep-id
if strings.Contains(cmdStr, "--userns keep-id") {
t.Errorf("Expected rootful command NOT to contain '--userns keep-id', but it was present.\nCommand: %s", cmdStr)
}
assert.NotContains(t, cmdStr, "--userns keep-id")
// Should still have other Podman-specific flags
if !strings.Contains(cmdStr, "--annotation run.oci.keep_original_groups=1") {
t.Errorf("Expected command to contain '--annotation run.oci.keep_original_groups=1'")
}
if !strings.Contains(cmdStr, "--ulimit host") {
t.Errorf("Expected command to contain '--ulimit host'")
}
assert.Contains(t, cmdStr, "--annotation run.oci.keep_original_groups=1")
assert.Contains(t, cmdStr, "--ulimit host")
}
func TestPodman_makeCreateCommandNoInit(t *testing.T) {
@@ -197,17 +184,10 @@ func TestPodman_makeCreateCommandNoInit(t *testing.T) {
cmdStr := strings.Join(cmd, " ")
// Without init, should NOT have --systemd=always
if strings.Contains(cmdStr, "--systemd=always") {
t.Errorf(
"Expected non-init command NOT to contain '--systemd=always', but it was present.\nCommand: %s",
cmdStr,
)
}
assert.NotContains(t, cmdStr, "--systemd=always")
// Should still have other Podman-specific flags
if !strings.Contains(cmdStr, "--annotation run.oci.keep_original_groups=1") {
t.Errorf("Expected command to contain '--annotation run.oci.keep_original_groups=1'")
}
assert.Contains(t, cmdStr, "--annotation run.oci.keep_original_groups=1")
}
func TestPodman_makeCreateCommandWithCrun(t *testing.T) {
@@ -254,19 +234,9 @@ func TestPodman_makeCreateCommandWithCrun(t *testing.T) {
// If crun exists, it should be in the command
if commandExists("crun") {
if !strings.Contains(cmdStr, "--runtime=crun") {
t.Errorf(
"Expected command to contain '--runtime=crun' when crun is available, but it was missing.\nCommand: %s",
cmdStr,
)
}
assert.Contains(t, cmdStr, "--runtime=crun")
} else {
if strings.Contains(cmdStr, "--runtime=crun") {
t.Errorf(
"Expected command NOT to contain '--runtime=crun' when crun is not available, but it was present.\nCommand: %s",
cmdStr,
)
}
assert.NotContains(t, cmdStr, "--runtime=crun")
}
}
@@ -309,9 +279,7 @@ func TestPodman_makeCreateCommandWithPlatform(t *testing.T) {
cmdStr := strings.Join(cmd, " ")
if !strings.Contains(cmdStr, "--platform=linux/arm64") {
t.Errorf("Expected command to contain '--platform=linux/arm64', but it was missing.\nCommand: %s", cmdStr)
}
assert.Contains(t, cmdStr, "--platform=linux/arm64")
}
func TestPodman_makeCreateCommandWithCustomHome(t *testing.T) {
@@ -354,24 +322,16 @@ func TestPodman_makeCreateCommandWithCustomHome(t *testing.T) {
cmdStr := strings.Join(cmd, " ")
// Check custom home is set
if !strings.Contains(cmdStr, "--env HOME=/custom/home") {
t.Errorf("Expected command to contain '--env HOME=/custom/home', but it was missing")
}
assert.Contains(t, cmdStr, "--env HOME=/custom/home")
// Check DISTROBOX_HOST_HOME is set to original home
if !strings.Contains(cmdStr, "--env DISTROBOX_HOST_HOME=/home/user") {
t.Errorf("Expected command to contain '--env DISTROBOX_HOST_HOME=/home/user', but it was missing")
}
assert.Contains(t, cmdStr, "--env DISTROBOX_HOST_HOME=/home/user")
// Check custom home is mounted
if !strings.Contains(cmdStr, "--volume /custom/home:/custom/home:rslave") {
t.Errorf("Expected command to contain custom home volume mount, but it was missing")
}
assert.Contains(t, cmdStr, "--volume /custom/home:/custom/home:rslave")
// Check entrypoint args use custom home
if !strings.Contains(cmdStr, "--home /custom/home") {
t.Errorf("Expected entrypoint args to use custom home, but it was missing")
}
assert.Contains(t, cmdStr, "--home /custom/home")
}
func TestPodman_makeCreateCommandWithAdditionalFlags(t *testing.T) {
@@ -418,12 +378,8 @@ func TestPodman_makeCreateCommandWithAdditionalFlags(t *testing.T) {
cmdStr := strings.Join(cmd, " ")
if !strings.Contains(cmdStr, "--cap-add=SYS_ADMIN") {
t.Errorf("Expected command to contain additional flag '--cap-add=SYS_ADMIN', but it was missing")
}
if !strings.Contains(cmdStr, "--device=/dev/fuse") {
t.Errorf("Expected command to contain additional flag '--device=/dev/fuse', but it was missing")
}
assert.Contains(t, cmdStr, "--cap-add=SYS_ADMIN")
assert.Contains(t, cmdStr, "--device=/dev/fuse")
}
func TestPodman_makeCreateCommandWithAdditionalPackages(t *testing.T) {
@@ -471,12 +427,9 @@ func TestPodman_makeCreateCommandWithAdditionalPackages(t *testing.T) {
cmdStr := strings.Join(cmd, " ")
if !strings.Contains(cmdStr, "--additional-packages vim git htop") {
t.Errorf("Expected command to contain additional packages, but it was missing")
}
assert.Contains(t, cmdStr, "--additional-packages vim git htop")
}
//nolint:gocognit
func TestPodman_makeCreateCommandUnshareOptions(t *testing.T) {
tests := []struct {
name string
@@ -575,33 +528,21 @@ func TestPodman_makeCreateCommandUnshareOptions(t *testing.T) {
cmdStr := strings.Join(cmd, " ")
if tt.wantIPC {
if !strings.Contains(cmdStr, "--ipc host") {
t.Errorf("Expected '--ipc host' in command")
}
assert.Contains(t, cmdStr, "--ipc host")
} else {
if strings.Contains(cmdStr, "--ipc host") {
t.Errorf("Did not expect '--ipc host' in command")
}
assert.NotContains(t, cmdStr, "--ipc host")
}
if tt.wantNetwork {
if !strings.Contains(cmdStr, "--network host") {
t.Errorf("Expected '--network host' in command")
}
assert.Contains(t, cmdStr, "--network host")
} else {
if strings.Contains(cmdStr, "--network host") {
t.Errorf("Did not expect '--network host' in command")
}
assert.NotContains(t, cmdStr, "--network host")
}
if tt.wantPID {
if !strings.Contains(cmdStr, "--pid host") {
t.Errorf("Expected '--pid host' in command")
}
assert.Contains(t, cmdStr, "--pid host")
} else {
if strings.Contains(cmdStr, "--pid host") {
t.Errorf("Did not expect '--pid host' in command")
}
assert.NotContains(t, cmdStr, "--pid host")
}
})
}
@@ -609,14 +550,10 @@ func TestPodman_makeCreateCommandUnshareOptions(t *testing.T) {
func TestPodman_Name(t *testing.T) {
podman := NewPodman(false, "sudo", false)
if podman.Name() != "podman" {
t.Errorf("Expected Name() to return 'podman', got '%s'", podman.Name())
}
assert.Equal(t, "podman", podman.Name())
launcher := NewPodmanLauncher(false, "sudo", false)
if launcher.Name() != "podman-launcher" {
t.Errorf("Expected Name() to return 'podman-launcher', got '%s'", launcher.Name())
}
assert.Equal(t, "podman-launcher", launcher.Name())
}
func TestParsePodmanContainerList(t *testing.T) {
@@ -624,50 +561,26 @@ func TestParsePodmanContainerList(t *testing.T) {
output := `[{"Command":"sleep infinity","CreatedAt":"2024-01-31 10:00:00 +0000 UTC","ID":"abc123def456789012345678901234567890","Image":"fedora:39","Labels":{"manager":"distrobox","distrobox.unshare_groups":"0"},"Mounts":"","Names":["my-container"],"Networks":"","Ports":"","State":"running","Status":"Up 2 hours"},{"Command":"/bin/bash","CreatedAt":"2024-01-31 09:00:00 +0000 UTC","ID":"xyz789abc123456789012345678901234567890","Image":"ubuntu:22.04","Labels":{"manager":"distrobox"},"Mounts":"","Names":["test-box"],"Networks":"","Ports":"","State":"exited","Status":"Exited (0) 1 hour ago"}]`
containers, err := parsePodmanContainerList(output)
if err != nil {
t.Fatalf("parsePodmanContainerList returned error: %v", err)
}
if len(containers) != 2 {
t.Fatalf("Expected 2 containers, got %d", len(containers))
}
require.NoError(t, err)
require.Len(t, containers, 2)
// Check first container
if containers[0].ID != "abc123def456" {
t.Errorf("Expected container ID 'abc123def456', got '%s'", containers[0].ID)
}
if containers[0].Name != "my-container" {
t.Errorf("Expected container name 'my-container', got '%s'", containers[0].Name)
}
if containers[0].Image != "fedora:39" {
t.Errorf("Expected container image 'fedora:39', got '%s'", containers[0].Image)
}
if containers[0].Labels["manager"] != "distrobox" {
t.Errorf("Expected label manager=distrobox")
}
if containers[0].Labels["distrobox.unshare_groups"] != "0" {
t.Errorf("Expected label distrobox.unshare_groups=0")
}
assert.Equal(t, "abc123def456", containers[0].ID)
assert.Equal(t, "my-container", containers[0].Name)
assert.Equal(t, "fedora:39", containers[0].Image)
assert.Equal(t, "distrobox", containers[0].Labels["manager"])
assert.Equal(t, "0", containers[0].Labels["distrobox.unshare_groups"])
// Check second container
if containers[1].ID != "xyz789abc123" {
t.Errorf("Expected container ID 'xyz789abc123', got '%s'", containers[1].ID)
}
if containers[1].Name != "test-box" {
t.Errorf("Expected container name 'test-box', got '%s'", containers[1].Name)
}
assert.Equal(t, "xyz789abc123", containers[1].ID)
assert.Equal(t, "test-box", containers[1].Name)
}
func TestParsePodmanContainerListEmpty(t *testing.T) {
output := ""
containers, err := parsePodmanContainerList(output)
if err != nil {
t.Fatalf("parsePodmanContainerList returned error: %v", err)
}
if len(containers) != 0 {
t.Errorf("Expected 0 containers for empty output, got %d", len(containers))
}
require.NoError(t, err)
assert.Empty(t, containers)
}
func TestParsePodmanContainerListEmptyNames(t *testing.T) {
@@ -700,18 +613,10 @@ func TestParsePodmanContainerListEmptyNames(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
containers, err := parsePodmanContainerList(tt.json)
if err != nil {
t.Fatalf("parsePodmanContainerList returned error: %v", err)
}
if len(containers) != 1 {
t.Fatalf("Expected 1 container, got %d", len(containers))
}
if containers[0].Name != tt.wantName {
t.Errorf("Expected Name %q, got %q", tt.wantName, containers[0].Name)
}
if containers[0].ID != tt.wantID {
t.Errorf("Expected ID %q, got %q", tt.wantID, containers[0].ID)
}
require.NoError(t, err)
require.Len(t, containers, 1)
assert.Equal(t, tt.wantName, containers[0].Name)
assert.Equal(t, tt.wantID, containers[0].ID)
})
}
}
@@ -741,9 +646,7 @@ func TestPodman_runUsesCorrectBinary(t *testing.T) {
// Capture stdout during DryRun
origStdout := os.Stdout
r, w, err := os.Pipe()
if err != nil {
t.Fatalf("failed to create pipe: %v", err)
}
require.NoError(t, err)
os.Stdout = w //nolint:reassign // redirect stdout to capture dry-run output in test
_, _ = p.run(t.Context(), []string{"info"}, runOptions{DryRun: true})
@@ -752,26 +655,20 @@ func TestPodman_runUsesCorrectBinary(t *testing.T) {
os.Stdout = origStdout //nolint:reassign // restore original stdout
var buf bytes.Buffer
if _, err := buf.ReadFrom(r); err != nil {
t.Fatalf("failed to read captured output: %v", err)
}
_, err = buf.ReadFrom(r)
require.NoError(t, err)
got := buf.String()
if !strings.HasPrefix(got, tt.expectedPrefix) {
t.Errorf("expected output to start with %q, got %q", tt.expectedPrefix, got)
}
assert.True(t, strings.HasPrefix(got, tt.expectedPrefix),
"expected output to start with %q, got %q", tt.expectedPrefix, got)
})
}
}
func TestCommandExists(t *testing.T) {
// Test with a command that should exist on all systems
if !commandExists("sh") {
t.Error("Expected 'sh' command to exist")
}
assert.True(t, commandExists("sh"), "Expected 'sh' command to exist")
// Test with a command that should not exist
if commandExists("this-command-definitely-does-not-exist-12345") {
t.Error("Did not expect non-existent command to be found")
}
assert.False(t, commandExists("this-command-definitely-does-not-exist-12345"), "Did not expect non-existent command to be found")
}
+11 -29
View File
@@ -6,6 +6,8 @@ import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/89luca89/distrobox/pkg/ui"
)
@@ -16,9 +18,7 @@ func TestPrompt_YesReturnsTrue(t *testing.T) {
result := p.Prompt("Continue?", false)
if result != true {
t.Errorf("expected true, got %v", result)
}
assert.True(t, result)
}
func TestPrompt_YReturnsTrue(t *testing.T) {
@@ -28,9 +28,7 @@ func TestPrompt_YReturnsTrue(t *testing.T) {
result := p.Prompt("Continue?", false)
if result != true {
t.Errorf("expected true, got %v", result)
}
assert.True(t, result)
}
func TestPrompt_NoReturnsFalse(t *testing.T) {
@@ -40,9 +38,7 @@ func TestPrompt_NoReturnsFalse(t *testing.T) {
result := p.Prompt("Continue?", true)
if result != false {
t.Errorf("expected false, got %v", result)
}
assert.False(t, result)
}
func TestPrompt_NReturnsFalse(t *testing.T) {
@@ -52,9 +48,7 @@ func TestPrompt_NReturnsFalse(t *testing.T) {
result := p.Prompt("Continue?", true)
if result != false {
t.Errorf("expected false, got %v", result)
}
assert.False(t, result)
}
func TestPrompt_InvalidInputReturnsDefaultTrue(t *testing.T) {
@@ -64,9 +58,7 @@ func TestPrompt_InvalidInputReturnsDefaultTrue(t *testing.T) {
result := p.Prompt("Continue?", true)
if result != true {
t.Errorf("expected true (default), got %v", result)
}
assert.True(t, result)
}
func TestPrompt_InvalidInputReturnsDefaultFalse(t *testing.T) {
@@ -76,9 +68,7 @@ func TestPrompt_InvalidInputReturnsDefaultFalse(t *testing.T) {
result := p.Prompt("Continue?", false)
if result != false {
t.Errorf("expected false (default), got %v", result)
}
assert.False(t, result)
}
func TestPrompt_EmptyInputReturnsDefault(t *testing.T) {
@@ -88,9 +78,7 @@ func TestPrompt_EmptyInputReturnsDefault(t *testing.T) {
result := p.Prompt("Continue?", true)
if result != true {
t.Errorf("expected true (default), got %v", result)
}
assert.True(t, result)
}
func TestPrompt_WritesPromptToWriter(t *testing.T) {
@@ -100,10 +88,7 @@ func TestPrompt_WritesPromptToWriter(t *testing.T) {
p.Prompt("Continue?", true)
expected := "Continue? [Y/n] "
if writer.String() != expected {
t.Errorf("expected %q, got %q", expected, writer.String())
}
assert.Equal(t, "Continue? [Y/n] ", writer.String())
}
func TestPrompt_WritesPromptWithDefaultNo(t *testing.T) {
@@ -113,8 +98,5 @@ func TestPrompt_WritesPromptWithDefaultNo(t *testing.T) {
p.Prompt("Delete file?", false)
expected := "Delete file? [y/N] "
if writer.String() != expected {
t.Errorf("expected %q, got %q", expected, writer.String())
}
assert.Equal(t, "Delete file? [y/N] ", writer.String())
}