blob: 8fe4b5c63b27da6fe9633b83c43f5a28cd804be2 [file] [log] [blame]
Earl Lee2e463fb2025-04-17 11:22:22 -07001package claudetool
2
3import (
4 "context"
5 "encoding/json"
6 "strings"
7 "testing"
8 "time"
9)
10
11func TestBashRun(t *testing.T) {
12 // Test basic functionality
13 t.Run("Basic Command", func(t *testing.T) {
14 input := json.RawMessage(`{"command":"echo 'Hello, world!'"}`)
15
16 result, err := BashRun(context.Background(), input)
17 if err != nil {
18 t.Fatalf("Unexpected error: %v", err)
19 }
20
21 expected := "Hello, world!\n"
22 if result != expected {
23 t.Errorf("Expected %q, got %q", expected, result)
24 }
25 })
26
27 // Test with arguments
28 t.Run("Command With Arguments", func(t *testing.T) {
29 input := json.RawMessage(`{"command":"echo -n foo && echo -n bar"}`)
30
31 result, err := BashRun(context.Background(), input)
32 if err != nil {
33 t.Fatalf("Unexpected error: %v", err)
34 }
35
36 expected := "foobar"
37 if result != expected {
38 t.Errorf("Expected %q, got %q", expected, result)
39 }
40 })
41
42 // Test with timeout parameter
43 t.Run("With Timeout", func(t *testing.T) {
44 inputObj := struct {
45 Command string `json:"command"`
46 Timeout string `json:"timeout"`
47 }{
48 Command: "sleep 0.1 && echo 'Completed'",
49 Timeout: "5s",
50 }
51 inputJSON, err := json.Marshal(inputObj)
52 if err != nil {
53 t.Fatalf("Failed to marshal input: %v", err)
54 }
55
56 result, err := BashRun(context.Background(), inputJSON)
57 if err != nil {
58 t.Fatalf("Unexpected error: %v", err)
59 }
60
61 expected := "Completed\n"
62 if result != expected {
63 t.Errorf("Expected %q, got %q", expected, result)
64 }
65 })
66
67 // Test command timeout
68 t.Run("Command Timeout", func(t *testing.T) {
69 inputObj := struct {
70 Command string `json:"command"`
71 Timeout string `json:"timeout"`
72 }{
73 Command: "sleep 0.5 && echo 'Should not see this'",
74 Timeout: "100ms",
75 }
76 inputJSON, err := json.Marshal(inputObj)
77 if err != nil {
78 t.Fatalf("Failed to marshal input: %v", err)
79 }
80
81 _, err = BashRun(context.Background(), inputJSON)
82 if err == nil {
83 t.Errorf("Expected timeout error, got none")
84 } else if !strings.Contains(err.Error(), "timed out") {
85 t.Errorf("Expected timeout error, got: %v", err)
86 }
87 })
88
89 // Test command that fails
90 t.Run("Failed Command", func(t *testing.T) {
91 input := json.RawMessage(`{"command":"exit 1"}`)
92
93 _, err := BashRun(context.Background(), input)
94 if err == nil {
95 t.Errorf("Expected error for failed command, got none")
96 }
97 })
98
99 // Test invalid input
100 t.Run("Invalid JSON Input", func(t *testing.T) {
101 input := json.RawMessage(`{"command":123}`) // Invalid JSON (command must be string)
102
103 _, err := BashRun(context.Background(), input)
104 if err == nil {
105 t.Errorf("Expected error for invalid input, got none")
106 }
107 })
108}
109
110func TestExecuteBash(t *testing.T) {
111 ctx := context.Background()
112
113 // Test successful command
114 t.Run("Successful Command", func(t *testing.T) {
115 req := bashInput{
116 Command: "echo 'Success'",
117 Timeout: "5s",
118 }
119
120 output, err := executeBash(ctx, req)
121 if err != nil {
122 t.Fatalf("Unexpected error: %v", err)
123 }
124
125 want := "Success\n"
126 if output != want {
127 t.Errorf("Expected %q, got %q", want, output)
128 }
129 })
130
131 // Test command with output to stderr
132 t.Run("Command with stderr", func(t *testing.T) {
133 req := bashInput{
134 Command: "echo 'Error message' >&2 && echo 'Success'",
135 Timeout: "5s",
136 }
137
138 output, err := executeBash(ctx, req)
139 if err != nil {
140 t.Fatalf("Unexpected error: %v", err)
141 }
142
143 want := "Error message\nSuccess\n"
144 if output != want {
145 t.Errorf("Expected %q, got %q", want, output)
146 }
147 })
148
149 // Test command that fails with stderr
150 t.Run("Failed Command with stderr", func(t *testing.T) {
151 req := bashInput{
152 Command: "echo 'Error message' >&2 && exit 1",
153 Timeout: "5s",
154 }
155
156 _, err := executeBash(ctx, req)
157 if err == nil {
158 t.Errorf("Expected error for failed command, got none")
159 } else if !strings.Contains(err.Error(), "Error message") {
160 t.Errorf("Expected stderr in error message, got: %v", err)
161 }
162 })
163
164 // Test timeout
165 t.Run("Command Timeout", func(t *testing.T) {
166 req := bashInput{
167 Command: "sleep 1 && echo 'Should not see this'",
168 Timeout: "100ms",
169 }
170
171 start := time.Now()
172 _, err := executeBash(ctx, req)
173 elapsed := time.Since(start)
174
175 // Command should time out after ~100ms, not wait for full 1 second
176 if elapsed >= 1*time.Second {
177 t.Errorf("Command did not respect timeout, took %v", elapsed)
178 }
179
180 if err == nil {
181 t.Errorf("Expected timeout error, got none")
182 } else if !strings.Contains(err.Error(), "timed out") {
183 t.Errorf("Expected timeout error, got: %v", err)
184 }
185 })
186}