package editflags
import (
"strings"
"testing"
"github.com/spf13/cobra"
"gotest.tools/v3/assert"
"github.com/lima-vm/lima/v2/pkg/localpathutil"
)
func TestCompleteCPUs(t *testing.T) {
assert.DeepEqual(t, []int{1}, completeCPUs(1))
assert.DeepEqual(t, []int{1, 2}, completeCPUs(2))
assert.DeepEqual(t, []int{1, 2, 4, 8}, completeCPUs(8))
assert.DeepEqual(t, []int{1, 2, 4, 8, 16, 20}, completeCPUs(20))
}
func TestCompleteMemoryGiB(t *testing.T) {
assert.DeepEqual(t, []float32{0.5}, completeMemoryGiB(1<<30))
assert.DeepEqual(t, []float32{1}, completeMemoryGiB(2<<30))
assert.DeepEqual(t, []float32{1, 2}, completeMemoryGiB(4<<30))
assert.DeepEqual(t, []float32{1, 2, 4}, completeMemoryGiB(8<<30))
assert.DeepEqual(t, []float32{1, 2, 4, 8, 10}, completeMemoryGiB(20<<30))
}
func TestBuildPortForwardExpression(t *testing.T) {
tests := []struct {
name string
portForwards []string
expected string
expectError bool
}{
{
name: "empty port forwards",
portForwards: []string{},
expected: "",
},
{
name: "single dynamic port forward",
portForwards: []string{"8080:80"},
expected: `.portForwards += [{"guestPort": "80", "hostPort": "8080", "static": false}]`,
},
{
name: "single static port forward",
portForwards: []string{"8080:80,static=true"},
expected: `.portForwards += [{"guestPort": "80", "hostPort": "8080", "static": true}]`,
},
{
name: "multiple mixed port forwards",
portForwards: []string{"8080:80", "2222:22,static=true", "3000:3000"},
expected: `.portForwards += [{"guestPort": "80", "hostPort": "8080", "static": false},{"guestPort": "22", "hostPort": "2222", "static": true},{"guestPort": "3000", "hostPort": "3000", "static": false}]`,
},
{
name: "invalid format - missing colon",
portForwards: []string{"8080"},
expectError: true,
},
{
name: "invalid format - too many colons",
portForwards: []string{"8080:80:extra"},
expectError: true,
},
{
name: "invalid static parameter",
portForwards: []string{"8080:80,invalid=true"},
expectError: true,
},
{
name: "too many parameters",
portForwards: []string{"8080:80,static=true,extra=value"},
expectError: true,
},
{
name: "whitespace handling",
portForwards: []string{" 8080 : 80 , static=true "},
expected: `.portForwards += [{"guestPort": "80", "hostPort": "8080", "static": true}]`,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := BuildPortForwardExpression(tt.portForwards)
if tt.expectError {
assert.Check(t, err != nil)
} else {
assert.NilError(t, err)
assert.Equal(t, tt.expected, result)
}
})
}
}
func TestParsePortForward(t *testing.T) {
tests := []struct {
name string
spec string
hostPort string
guestPort string
isStatic bool
expectError bool
}{
{
name: "dynamic port forward",
spec: "8080:80",
hostPort: "8080",
guestPort: "80",
isStatic: false,
},
{
name: "static port forward",
spec: "8080:80,static=true",
hostPort: "8080",
guestPort: "80",
isStatic: true,
},
{
name: "whitespace handling",
spec: " 8080 : 80 , static=true ",
hostPort: "8080",
guestPort: "80",
isStatic: true,
},
{
name: "invalid format - missing colon",
spec: "8080",
expectError: true,
},
{
name: "invalid format - too many colons",
spec: "8080:80:extra",
expectError: true,
},
{
name: "invalid parameter",
spec: "8080:80,invalid=true",
expectError: true,
},
{
name: "too many parameters",
spec: "8080:80,static=true,extra=value",
expectError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
hostPort, guestPort, isStatic, err := ParsePortForward(tt.spec)
if tt.expectError {
assert.Check(t, err != nil)
} else {
assert.NilError(t, err)
assert.Equal(t, tt.hostPort, hostPort)
assert.Equal(t, tt.guestPort, guestPort)
assert.Equal(t, tt.isStatic, isStatic)
}
})
}
}
func TestYQExpressions(t *testing.T) {
expand := func(s string) string {
s, err := localpathutil.Expand(s)
assert.NilError(t, err)
s = strings.ReplaceAll(s, "\\", "\\\\")
return s
}
tests := []struct {
name string
args []string
newInstance bool
expected []string
expectError string
}{
{
name: "mount",
args: []string{"--mount", "/foo", "--mount", "./bar:w"},
newInstance: false,
expected: []string{`.mounts = [{"location": "` + expand("./bar") + `", "mountPoint": "` + expand("./bar") + `", "writable": true},{"location": "` + expand("/foo") + `", "mountPoint": "` + expand("/foo") + `", "writable": false}] + .mounts`},
},
{
name: "mount-only",
args: []string{"--mount-only", "/foo", "--mount-only", "/bar:w"},
newInstance: false,
expected: []string{`.mounts = [{"location": "` + expand("/foo") + `", "mountPoint": "` + expand("/foo") + `", "writable": false},{"location": "` + expand("/bar") + `", "mountPoint": "` + expand("/bar") + `", "writable": true}]`},
},
{
name: "mixture of mount and mount-only",
args: []string{"--mount", "/foo", "--mount-only", "/bar:w"},
newInstance: false,
expectError: "flag `--mount` conflicts with `--mount-only`",
},
{
name: "dns",
args: []string{"--dns", "8.8.8.8", "--dns", "8.8.4.4", "--dns", "1.1.1.1"},
newInstance: false,
expected: []string{`.dns += ["8.8.8.8","8.8.4.4","1.1.1.1"] | .dns |= unique | .hostResolver.enabled=false`},
},
{
name: "network vzNAT",
args: []string{"--network", "vzNAT"},
newInstance: true,
expected: []string{`.networks += [{"vzNAT": true}] | .networks |= unique_by(.lima)`},
},
{
name: "network lima:shared",
args: []string{"--network", "lima:shared"},
newInstance: true,
expected: []string{`.networks += [{"lima": "shared"}] | .networks |= unique_by(.lima)`},
},
{
name: "multiple networks",
args: []string{"--network", "vzNAT", "--network", "lima:shared", "--network", "lima:bridged"},
newInstance: true,
expected: []string{`.networks += [{"vzNAT": true},{"lima": "shared"},{"lima": "bridged"}] | .networks |= unique_by(.lima)`},
},
{
name: "invalid network",
args: []string{"--network", "invalid"},
newInstance: true,
expectError: `network name must be "vzNAT" or "lima:*", got "invalid"`,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
cmd := &cobra.Command{}
RegisterEdit(cmd, "")
assert.NilError(t, cmd.ParseFlags(tt.args))
expr, err := YQExpressions(cmd.Flags(), tt.newInstance)
if tt.expectError != "" {
assert.ErrorContains(t, err, tt.expectError)
} else {
assert.NilError(t, err)
assert.DeepEqual(t, tt.expected, expr)
}
})
}
}