package cmdext import ( "reflect" "testing" "time" ) func TestRunnerInit(t *testing.T) { r := Runner("myprog") if r == nil { t.Fatalf("Runner returned nil") } if r.program != "myprog" { t.Errorf("program == %v, want myprog", r.program) } if r.args == nil { t.Errorf("args is nil, want empty slice") } if len(r.args) != 0 { t.Errorf("len(args) == %v, want 0", len(r.args)) } if r.env == nil { t.Errorf("env is nil, want empty slice") } if len(r.env) != 0 { t.Errorf("len(env) == %v, want 0", len(r.env)) } if r.listener == nil { t.Errorf("listener is nil, want empty slice") } if len(r.listener) != 0 { t.Errorf("len(listener) == %v, want 0", len(r.listener)) } if r.timeout != nil { t.Errorf("timeout == %v, want nil", r.timeout) } if r.enforceExitCodes != nil { t.Errorf("enforceExitCodes == %v, want nil", r.enforceExitCodes) } if r.enforceNoTimeout { t.Errorf("enforceNoTimeout == true, want false") } if r.enforceNoStderr { t.Errorf("enforceNoStderr == true, want false") } } func TestArgSingle(t *testing.T) { r := Runner("p").Arg("a") if !reflect.DeepEqual(r.args, []string{"a"}) { t.Errorf("args == %v, want [a]", r.args) } } func TestArgMultiple(t *testing.T) { r := Runner("p").Arg("a").Arg("b").Arg("c") if !reflect.DeepEqual(r.args, []string{"a", "b", "c"}) { t.Errorf("args == %v, want [a b c]", r.args) } } func TestArgsAppendsAll(t *testing.T) { r := Runner("p").Args([]string{"x", "y"}).Args([]string{"z"}) if !reflect.DeepEqual(r.args, []string{"x", "y", "z"}) { t.Errorf("args == %v, want [x y z]", r.args) } } func TestArgAndArgsMixed(t *testing.T) { r := Runner("p").Arg("a").Args([]string{"b", "c"}).Arg("d") if !reflect.DeepEqual(r.args, []string{"a", "b", "c", "d"}) { t.Errorf("args == %v, want [a b c d]", r.args) } } func TestArgsEmptySlice(t *testing.T) { r := Runner("p").Args([]string{}) if len(r.args) != 0 { t.Errorf("len(args) == %v, want 0", len(r.args)) } } func TestTimeoutSet(t *testing.T) { d := 500 * time.Millisecond r := Runner("p").Timeout(d) if r.timeout == nil { t.Fatalf("timeout is nil") } if *r.timeout != d { t.Errorf("timeout == %v, want %v", *r.timeout, d) } } func TestTimeoutOverride(t *testing.T) { r := Runner("p").Timeout(1 * time.Second).Timeout(2 * time.Second) if *r.timeout != 2*time.Second { t.Errorf("timeout == %v, want 2s", *r.timeout) } } func TestEnv(t *testing.T) { r := Runner("p").Env("KEY", "VALUE") if !reflect.DeepEqual(r.env, []string{"KEY=VALUE"}) { t.Errorf("env == %v, want [KEY=VALUE]", r.env) } } func TestEnvMultiple(t *testing.T) { r := Runner("p").Env("A", "1").Env("B", "2") if !reflect.DeepEqual(r.env, []string{"A=1", "B=2"}) { t.Errorf("env == %v, want [A=1 B=2]", r.env) } } func TestEnvWithEmptyValue(t *testing.T) { r := Runner("p").Env("KEY", "") if !reflect.DeepEqual(r.env, []string{"KEY="}) { t.Errorf("env == %v, want [KEY=]", r.env) } } func TestRawEnv(t *testing.T) { r := Runner("p").RawEnv("FOO=BAR=BAZ") if !reflect.DeepEqual(r.env, []string{"FOO=BAR=BAZ"}) { t.Errorf("env == %v, want [FOO=BAR=BAZ]", r.env) } } func TestEnvs(t *testing.T) { r := Runner("p").Envs([]string{"A=1", "B=2"}) if !reflect.DeepEqual(r.env, []string{"A=1", "B=2"}) { t.Errorf("env == %v, want [A=1 B=2]", r.env) } } func TestEnvMixed(t *testing.T) { r := Runner("p").Env("A", "1").RawEnv("B=2").Envs([]string{"C=3", "D=4"}) if !reflect.DeepEqual(r.env, []string{"A=1", "B=2", "C=3", "D=4"}) { t.Errorf("env == %v, want [A=1 B=2 C=3 D=4]", r.env) } } func TestEnsureExitcodeSingle(t *testing.T) { r := Runner("p").EnsureExitcode(2) if r.enforceExitCodes == nil { t.Fatalf("enforceExitCodes is nil") } if !reflect.DeepEqual(*r.enforceExitCodes, []int{2}) { t.Errorf("enforceExitCodes == %v, want [2]", *r.enforceExitCodes) } } func TestEnsureExitcodeMultiple(t *testing.T) { r := Runner("p").EnsureExitcode(0, 1, 2) if r.enforceExitCodes == nil { t.Fatalf("enforceExitCodes is nil") } if !reflect.DeepEqual(*r.enforceExitCodes, []int{0, 1, 2}) { t.Errorf("enforceExitCodes == %v, want [0 1 2]", *r.enforceExitCodes) } } func TestFailOnExitCode(t *testing.T) { r := Runner("p").FailOnExitCode() if r.enforceExitCodes == nil { t.Fatalf("enforceExitCodes is nil") } if !reflect.DeepEqual(*r.enforceExitCodes, []int{0}) { t.Errorf("enforceExitCodes == %v, want [0]", *r.enforceExitCodes) } } func TestFailOnTimeoutFlag(t *testing.T) { r := Runner("p") if r.enforceNoTimeout { t.Errorf("enforceNoTimeout was true before set") } r = r.FailOnTimeout() if !r.enforceNoTimeout { t.Errorf("enforceNoTimeout == false after FailOnTimeout()") } } func TestFailOnStderrFlag(t *testing.T) { r := Runner("p") if r.enforceNoStderr { t.Errorf("enforceNoStderr was true before set") } r = r.FailOnStderr() if !r.enforceNoStderr { t.Errorf("enforceNoStderr == false after FailOnStderr()") } } func TestListen(t *testing.T) { r := Runner("p").Listen(genericCommandListener{}) if len(r.listener) != 1 { t.Errorf("len(listener) == %v, want 1", len(r.listener)) } } func TestListenMultiple(t *testing.T) { r := Runner("p"). Listen(genericCommandListener{}). Listen(genericCommandListener{}). Listen(genericCommandListener{}) if len(r.listener) != 3 { t.Errorf("len(listener) == %v, want 3", len(r.listener)) } } func TestListenStdoutAddsListener(t *testing.T) { r := Runner("p").ListenStdout(func(string) {}) if len(r.listener) != 1 { t.Errorf("len(listener) == %v, want 1", len(r.listener)) } } func TestListenStdoutForwardsCalls(t *testing.T) { got := "" r := Runner("p").ListenStdout(func(s string) { got = s }) if len(r.listener) != 1 { t.Fatalf("len(listener) == %v, want 1", len(r.listener)) } r.listener[0].ReadStdoutLine("hello") if got != "hello" { t.Errorf("listener got %q, want hello", got) } // non-stdout methods should not panic and should not affect state r.listener[0].ReadStderrLine("nope") r.listener[0].ReadRawStdout([]byte("raw")) r.listener[0].ReadRawStderr([]byte("raw")) r.listener[0].Finished(0) r.listener[0].Timeout() if got != "hello" { t.Errorf("listener got mutated to %q, want hello", got) } } func TestListenStderrAddsListener(t *testing.T) { r := Runner("p").ListenStderr(func(string) {}) if len(r.listener) != 1 { t.Errorf("len(listener) == %v, want 1", len(r.listener)) } } func TestListenStderrForwardsCalls(t *testing.T) { got := "" r := Runner("p").ListenStderr(func(s string) { got = s }) if len(r.listener) != 1 { t.Fatalf("len(listener) == %v, want 1", len(r.listener)) } r.listener[0].ReadStderrLine("oops") if got != "oops" { t.Errorf("listener got %q, want oops", got) } r.listener[0].ReadStdoutLine("nope") if got != "oops" { t.Errorf("listener got mutated to %q, want oops", got) } } func TestChainReturnsSameInstance(t *testing.T) { r := Runner("p") if r.Arg("a") != r { t.Errorf("Arg returned different instance") } if r.Args([]string{"b"}) != r { t.Errorf("Args returned different instance") } if r.Timeout(time.Second) != r { t.Errorf("Timeout returned different instance") } if r.Env("K", "V") != r { t.Errorf("Env returned different instance") } if r.RawEnv("K=V") != r { t.Errorf("RawEnv returned different instance") } if r.Envs([]string{"K=V"}) != r { t.Errorf("Envs returned different instance") } if r.EnsureExitcode(0) != r { t.Errorf("EnsureExitcode returned different instance") } if r.FailOnExitCode() != r { t.Errorf("FailOnExitCode returned different instance") } if r.FailOnTimeout() != r { t.Errorf("FailOnTimeout returned different instance") } if r.FailOnStderr() != r { t.Errorf("FailOnStderr returned different instance") } if r.Listen(genericCommandListener{}) != r { t.Errorf("Listen returned different instance") } if r.ListenStdout(func(string) {}) != r { t.Errorf("ListenStdout returned different instance") } if r.ListenStderr(func(string) {}) != r { t.Errorf("ListenStderr returned different instance") } } func TestSeparateInstancesIndependent(t *testing.T) { r1 := Runner("p1").Arg("a") r2 := Runner("p2").Arg("b") if r1.program != "p1" { t.Errorf("r1.program == %v, want p1", r1.program) } if r2.program != "p2" { t.Errorf("r2.program == %v, want p2", r2.program) } if !reflect.DeepEqual(r1.args, []string{"a"}) { t.Errorf("r1.args == %v, want [a]", r1.args) } if !reflect.DeepEqual(r2.args, []string{"b"}) { t.Errorf("r2.args == %v, want [b]", r2.args) } }