mirror of
https://github.com/89luca89/distrobox.git
synced 2026-11-02 20:30:16 -06:00
223 lines
6.0 KiB
Go
223 lines
6.0 KiB
Go
package commands_test
|
|
|
|
import (
|
|
"bufio"
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"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"
|
|
"github.com/89luca89/distrobox/pkg/internal/testutil"
|
|
"github.com/89luca89/distrobox/pkg/manifest"
|
|
"github.com/89luca89/distrobox/pkg/ui"
|
|
)
|
|
|
|
func newTestAssembleCommand(mock *testutil.MockContainerManager) *commands.AssembleCommand {
|
|
progress := ui.NewDevNullProgress()
|
|
prompter := ui.NewPrompter(*bufio.NewReader(strings.NewReader("")), io.Discard)
|
|
printer := ui.NewPrinter(io.Discard, false)
|
|
return commands.NewAssembleCommand(&config.Values{}, mock, prompter, progress, printer)
|
|
}
|
|
|
|
func getEnterOptions(spy testutil.ContainerManagerSpy, index int) containermanager.EnterOptions {
|
|
return spy.Enter[index][0].(containermanager.EnterOptions)
|
|
}
|
|
|
|
func TestAssembleCommand_SetupBox_StartNowTrue(t *testing.T) {
|
|
mock := &testutil.MockContainerManager{}
|
|
cmd := newTestAssembleCommand(mock)
|
|
|
|
err := cmd.Execute(context.Background(), commands.AssembleOptions{
|
|
Items: []manifest.Item{
|
|
{
|
|
Name: "test-box",
|
|
Image: "ubuntu:latest",
|
|
StartNow: true,
|
|
},
|
|
},
|
|
})
|
|
require.NoError(t, err)
|
|
require.NotEmpty(t, mock.Spy.Enter, "expected Enter to be called when StartNow is true")
|
|
|
|
opts := getEnterOptions(mock.Spy, 0)
|
|
assert.Equal(t, "test-box", opts.ContainerName)
|
|
assert.Equal(t, "true", opts.CustomCommand)
|
|
}
|
|
|
|
func TestAssembleCommand_SetupBox_ExportedApps_Valid(t *testing.T) {
|
|
validNames := []string{
|
|
"firefox",
|
|
"org.mozilla.firefox",
|
|
"gnome-terminal",
|
|
"lib2to3",
|
|
"g++",
|
|
"my_app.v2",
|
|
"A",
|
|
}
|
|
|
|
for _, app := range validNames {
|
|
t.Run(app, func(t *testing.T) {
|
|
mock := &testutil.MockContainerManager{}
|
|
cmd := newTestAssembleCommand(mock)
|
|
|
|
apps := []string{app, "another-app"}
|
|
err := cmd.Execute(context.Background(), commands.AssembleOptions{
|
|
Items: []manifest.Item{
|
|
{
|
|
Name: "test-box",
|
|
Image: "ubuntu:latest",
|
|
ExportedApps: apps,
|
|
},
|
|
},
|
|
})
|
|
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)
|
|
assert.Equal(t, "test-box", opts.ContainerName, "call %d", i)
|
|
assert.Equal(t, expectedCmd, opts.CustomCommand, "call %d", i)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAssembleCommand_SetupBox_ExportedApps_Invalid(t *testing.T) {
|
|
invalidNames := []string{
|
|
"--delete",
|
|
"-rf",
|
|
"",
|
|
"app name with spaces",
|
|
".hidden",
|
|
"_leading",
|
|
"app;rm -rf /",
|
|
"app$(cmd)",
|
|
}
|
|
|
|
for _, app := range invalidNames {
|
|
t.Run(app, func(t *testing.T) {
|
|
mock := &testutil.MockContainerManager{}
|
|
cmd := newTestAssembleCommand(mock)
|
|
|
|
err := cmd.Execute(context.Background(), commands.AssembleOptions{
|
|
Items: []manifest.Item{
|
|
{
|
|
Name: "test-box",
|
|
Image: "ubuntu:latest",
|
|
ExportedApps: []string{app},
|
|
},
|
|
},
|
|
})
|
|
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)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAssembleCommand_SetupBox_ExportedBins_Valid(t *testing.T) {
|
|
validBins := []string{
|
|
"/usr/bin/vim",
|
|
"/usr/local/bin/node",
|
|
"/opt/app/bin/tool",
|
|
"/usr/bin/g++",
|
|
"/usr/bin/python3.11",
|
|
"/usr/bin/my_tool",
|
|
}
|
|
|
|
for _, bin := range validBins {
|
|
t.Run(bin, func(t *testing.T) {
|
|
mock := &testutil.MockContainerManager{}
|
|
cmd := newTestAssembleCommand(mock)
|
|
|
|
bins := []string{bin, "/usr/bin/another"}
|
|
err := cmd.Execute(context.Background(), commands.AssembleOptions{
|
|
Items: []manifest.Item{
|
|
{
|
|
Name: "test-box",
|
|
Image: "ubuntu:latest",
|
|
ExportedBins: bins,
|
|
ExportedBinsPath: "/home/user/.local/bin",
|
|
},
|
|
},
|
|
})
|
|
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)
|
|
assert.Equal(t, "test-box", opts.ContainerName, "call %d", i)
|
|
assert.Equal(t, expectedCmd, opts.CustomCommand, "call %d", i)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAssembleCommand_SetupBox_ExportedBins_Invalid(t *testing.T) {
|
|
invalidBins := []string{
|
|
"--delete",
|
|
"-rf",
|
|
"",
|
|
"relative/path/bin",
|
|
"/path with spaces/bin",
|
|
"/usr/bin/app;rm -rf /",
|
|
"/usr/bin/app$(cmd)",
|
|
}
|
|
|
|
for _, bin := range invalidBins {
|
|
t.Run(bin, func(t *testing.T) {
|
|
mock := &testutil.MockContainerManager{}
|
|
cmd := newTestAssembleCommand(mock)
|
|
|
|
err := cmd.Execute(context.Background(), commands.AssembleOptions{
|
|
Items: []manifest.Item{
|
|
{
|
|
Name: "test-box",
|
|
Image: "ubuntu:latest",
|
|
ExportedBins: []string{bin},
|
|
ExportedBinsPath: "/home/user/.local/bin",
|
|
},
|
|
},
|
|
})
|
|
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)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAssembleCommand_SetupBox_ExportedBins_InvalidExportPath(t *testing.T) {
|
|
invalidPaths := []string{
|
|
"",
|
|
"relative/path",
|
|
"--some-flag",
|
|
"/path with spaces",
|
|
"/path;injection",
|
|
}
|
|
|
|
for _, path := range invalidPaths {
|
|
t.Run(path, func(t *testing.T) {
|
|
mock := &testutil.MockContainerManager{}
|
|
cmd := newTestAssembleCommand(mock)
|
|
|
|
err := cmd.Execute(context.Background(), commands.AssembleOptions{
|
|
Items: []manifest.Item{
|
|
{
|
|
Name: "test-box",
|
|
Image: "ubuntu:latest",
|
|
ExportedBins: []string{"/usr/bin/vim"},
|
|
ExportedBinsPath: path,
|
|
},
|
|
},
|
|
})
|
|
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)
|
|
})
|
|
}
|
|
}
|