1package shell
  2
  3import (
  4	"context"
  5	"path/filepath"
  6	"runtime"
  7	"strings"
  8	"testing"
  9	"time"
 10)
 11
 12// Benchmark to measure CPU efficiency
 13func BenchmarkShellQuickCommands(b *testing.B) {
 14	shell := NewShell(&Options{WorkingDir: b.TempDir()})
 15
 16	b.ReportAllocs()
 17
 18	for b.Loop() {
 19		_, _, err := shell.Exec(b.Context(), "echo test")
 20		exitCode := ExitCode(err)
 21		if err != nil || exitCode != 0 {
 22			b.Fatalf("Command failed: %v, exit code: %d", err, exitCode)
 23		}
 24	}
 25}
 26
 27func TestTestTimeout(t *testing.T) {
 28	// XXX(@andreynering): This fails on Windows. Address once possible.
 29	if runtime.GOOS == "windows" {
 30		t.Skip("Skipping test on Windows")
 31	}
 32
 33	ctx, cancel := context.WithTimeout(t.Context(), time.Millisecond)
 34	t.Cleanup(cancel)
 35
 36	shell := NewShell(&Options{WorkingDir: t.TempDir()})
 37	_, _, err := shell.Exec(ctx, "sleep 10")
 38	if status := ExitCode(err); status == 0 {
 39		t.Fatalf("Expected non-zero exit status, got %d", status)
 40	}
 41	if !IsInterrupt(err) {
 42		t.Fatalf("Expected command to be interrupted, but it was not")
 43	}
 44	if err == nil {
 45		t.Fatalf("Expected an error due to timeout, but got none")
 46	}
 47}
 48
 49func TestTestCancel(t *testing.T) {
 50	ctx, cancel := context.WithCancel(t.Context())
 51	cancel() // immediately cancel the context
 52
 53	shell := NewShell(&Options{WorkingDir: t.TempDir()})
 54	_, _, err := shell.Exec(ctx, "sleep 10")
 55	if status := ExitCode(err); status == 0 {
 56		t.Fatalf("Expected non-zero exit status, got %d", status)
 57	}
 58	if !IsInterrupt(err) {
 59		t.Fatalf("Expected command to be interrupted, but it was not")
 60	}
 61	if err == nil {
 62		t.Fatalf("Expected an error due to cancel, but got none")
 63	}
 64}
 65
 66func TestRunCommandError(t *testing.T) {
 67	shell := NewShell(&Options{WorkingDir: t.TempDir()})
 68	_, _, err := shell.Exec(t.Context(), "nopenopenope")
 69	if status := ExitCode(err); status == 0 {
 70		t.Fatalf("Expected non-zero exit status, got %d", status)
 71	}
 72	if IsInterrupt(err) {
 73		t.Fatalf("Expected command to not be interrupted, but it was")
 74	}
 75	if err == nil {
 76		t.Fatalf("Expected an error, got nil")
 77	}
 78}
 79
 80func TestRunContinuity(t *testing.T) {
 81	tempDir1 := t.TempDir()
 82	tempDir2 := t.TempDir()
 83
 84	shell := NewShell(&Options{WorkingDir: tempDir1})
 85	if _, _, err := shell.Exec(t.Context(), "export FOO=bar"); err != nil {
 86		t.Fatalf("failed to set env: %v", err)
 87	}
 88	if _, _, err := shell.Exec(t.Context(), "cd "+filepath.ToSlash(tempDir2)); err != nil {
 89		t.Fatalf("failed to change directory: %v", err)
 90	}
 91	out, _, err := shell.Exec(t.Context(), "echo $FOO ; pwd")
 92	if err != nil {
 93		t.Fatalf("failed to echo: %v", err)
 94	}
 95	expect := "bar\n" + tempDir2 + "\n"
 96	if out != expect {
 97		t.Fatalf("expected output %q, got %q", expect, out)
 98	}
 99}
100
101func TestCrossPlatformExecution(t *testing.T) {
102	shell := NewShell(&Options{WorkingDir: "."})
103	ctx, cancel := context.WithTimeout(t.Context(), 5*time.Second)
104	defer cancel()
105
106	// Test a simple command that should work on all platforms
107	stdout, stderr, err := shell.Exec(ctx, "echo hello")
108	if err != nil {
109		t.Fatalf("Echo command failed: %v, stderr: %s", err, stderr)
110	}
111
112	if stdout == "" {
113		t.Error("Echo command produced no output")
114	}
115
116	// The output should contain "hello" regardless of platform
117	if !strings.Contains(strings.ToLower(stdout), "hello") {
118		t.Errorf("Echo output should contain 'hello', got: %q", stdout)
119	}
120}