package main // The CLI-side gates for `carlos features` (issue #347): argument parsing // and the refusals that fail before any network call. import ( "os/exec" "reflect" "strings" "testing" ) func TestParseFeatureArgs(t *testing.T) { set, unset, err := parseFeatureArgs([]string{"sandbox=on", "beta=", "limit=10 per day"}) if err != nil { t.Fatal(err) } if want := map[string]string{"sandbox": "on", "limit": "10 per day"}; !reflect.DeepEqual(set, want) { t.Fatalf("set = %v, want %v", set, want) } if want := []string{"beta"}; !reflect.DeepEqual(unset, want) { t.Fatalf("unset = %v, want %v", unset, want) } } func TestParseFeatureArgsRefusals(t *testing.T) { for _, c := range []struct { args []string want string }{ {[]string{"sandbox"}, "key=value"}, {[]string{"=on"}, "key"}, {[]string{"Sandbox=on"}, "key"}, {[]string{"sandbox=on", "sandbox=off"}, "twice"}, {[]string{"sandbox=on", "sandbox="}, "twice"}, } { _, _, err := parseFeatureArgs(c.args) if err == nil || !strings.Contains(err.Error(), c.want) { t.Errorf("%v: err = %v, want one mentioning %q", c.args, err, c.want) } } } func runFeaturesCLI(t *testing.T, args ...string) (string, error) { t.Helper() bin := buildCarlos(t) cmd := exec.Command(bin, args...) cmd.Env = carlosTestEnv(t) cmd.Dir = t.TempDir() out, err := cmd.CombinedOutput() return string(out), err } func TestFeaturesNeedsASubVerb(t *testing.T) { out, err := runFeaturesCLI(t, "features") if err == nil { t.Fatalf("bare `features` exited 0: %s", out) } if !strings.Contains(out, "set") || !strings.Contains(out, "list") { t.Fatalf("usage should name the sub-verbs, got: %s", out) } } func TestFeaturesSetRefusesNoPairsBeforeTheNetwork(t *testing.T) { // No pairs is a usage error, refused before the session is resolved — // so it must NOT be the no-target refusal. out, err := runFeaturesCLI(t, "features", "set", "-app", "titogo") if err == nil { t.Fatalf("set with no pairs exited 0: %s", out) } if !strings.Contains(out, "key=value") || strings.Contains(out, "no deployment target") { t.Fatalf("want a key=value usage refusal, got: %s", out) } } func TestFeaturesListNeedsASession(t *testing.T) { out, err := runFeaturesCLI(t, "features", "list", "-app", "titogo") if err == nil { t.Fatalf("list with no target exited 0: %s", out) } if !strings.Contains(out, "no deployment target configured") { t.Fatalf("want the no-target refusal, got: %s", out) } }