@@ -2,12 +2,16 @@ package openai //nolint:testpackage // testing private field
2
2
3
3
import (
4
4
"bytes"
5
+ "context"
6
+ "errors"
5
7
"fmt"
6
8
"io"
9
+ "net/http"
7
10
"os"
8
11
"path/filepath"
9
12
"testing"
10
13
14
+ utils "github.com/sashabaranov/go-openai/internal"
11
15
"github.com/sashabaranov/go-openai/internal/test"
12
16
"github.com/sashabaranov/go-openai/internal/test/checks"
13
17
)
@@ -107,3 +111,131 @@ func TestCreateFileField(t *testing.T) {
107
111
checks .HasError (t , err , "createFileField using file should return error when open file fails" )
108
112
})
109
113
}
114
+
115
+ // failingFormBuilder always returns an error when creating form files.
116
+ type failingFormBuilder struct { err error }
117
+
118
+ func (f * failingFormBuilder ) CreateFormFile (_ string , _ * os.File ) error {
119
+ return f .err
120
+ }
121
+
122
+ func (f * failingFormBuilder ) CreateFormFileReader (_ string , _ io.Reader , _ string ) error {
123
+ return f .err
124
+ }
125
+
126
+ func (f * failingFormBuilder ) WriteField (_ , _ string ) error {
127
+ return nil
128
+ }
129
+
130
+ func (f * failingFormBuilder ) Close () error {
131
+ return nil
132
+ }
133
+
134
+ func (f * failingFormBuilder ) FormDataContentType () string {
135
+ return "multipart/form-data"
136
+ }
137
+
138
+ // failingAudioRequestBuilder simulates an error during HTTP request construction.
139
+ type failingAudioRequestBuilder struct { err error }
140
+
141
+ func (f * failingAudioRequestBuilder ) Build (
142
+ _ context.Context ,
143
+ _ , _ string ,
144
+ _ any ,
145
+ _ http.Header ,
146
+ ) (* http.Request , error ) {
147
+ return nil , f .err
148
+ }
149
+
150
+ // errorHTTPClient always returns an error when making HTTP calls.
151
+ type errorHTTPClient struct { err error }
152
+
153
+ func (e * errorHTTPClient ) Do (_ * http.Request ) (* http.Response , error ) {
154
+ return nil , e .err
155
+ }
156
+
157
+ func TestCallAudioAPIMultipartFormError (t * testing.T ) {
158
+ client := NewClient ("test-token" )
159
+ errForm := errors .New ("mock create form file failure" )
160
+ // Override form builder to force an error during multipart form creation.
161
+ client .createFormBuilder = func (_ io.Writer ) utils.FormBuilder {
162
+ return & failingFormBuilder {err : errForm }
163
+ }
164
+
165
+ // Provide a reader so createFileField uses the reader path (no file open).
166
+ req := AudioRequest {FilePath : "fake.mp3" , Reader : bytes .NewBuffer ([]byte ("dummy" )), Model : Whisper1 }
167
+ _ , err := client .callAudioAPI (context .Background (), req , "transcriptions" )
168
+ if err == nil {
169
+ t .Fatal ("expected error but got none" )
170
+ }
171
+ if ! errors .Is (err , errForm ) {
172
+ t .Errorf ("expected error %v, got %v" , errForm , err )
173
+ }
174
+ }
175
+
176
+ func TestCallAudioAPINewRequestError (t * testing.T ) {
177
+ client := NewClient ("test-token" )
178
+ // Create a real temp file so multipart form succeeds.
179
+ tmp := t .TempDir ()
180
+ path := filepath .Join (tmp , "file.mp3" )
181
+ if err := os .WriteFile (path , []byte ("content" ), 0644 ); err != nil {
182
+ t .Fatalf ("failed to write temp file: %v" , err )
183
+ }
184
+
185
+ errBuild := errors .New ("mock build failure" )
186
+ client .requestBuilder = & failingAudioRequestBuilder {err : errBuild }
187
+
188
+ req := AudioRequest {FilePath : path , Model : Whisper1 }
189
+ _ , err := client .callAudioAPI (context .Background (), req , "translations" )
190
+ if err == nil {
191
+ t .Fatal ("expected error but got none" )
192
+ }
193
+ if ! errors .Is (err , errBuild ) {
194
+ t .Errorf ("expected error %v, got %v" , errBuild , err )
195
+ }
196
+ }
197
+
198
+ func TestCallAudioAPISendRequestErrorJSON (t * testing.T ) {
199
+ client := NewClient ("test-token" )
200
+ // Create a real temp file so multipart form succeeds.
201
+ tmp := t .TempDir ()
202
+ path := filepath .Join (tmp , "file.mp3" )
203
+ if err := os .WriteFile (path , []byte ("content" ), 0644 ); err != nil {
204
+ t .Fatalf ("failed to write temp file: %v" , err )
205
+ }
206
+
207
+ errHTTP := errors .New ("mock HTTPClient failure" )
208
+ // Override HTTP client to simulate a network error.
209
+ client .config .HTTPClient = & errorHTTPClient {err : errHTTP }
210
+
211
+ req := AudioRequest {FilePath : path , Model : Whisper1 }
212
+ _ , err := client .callAudioAPI (context .Background (), req , "transcriptions" )
213
+ if err == nil {
214
+ t .Fatal ("expected error but got none" )
215
+ }
216
+ if ! errors .Is (err , errHTTP ) {
217
+ t .Errorf ("expected error %v, got %v" , errHTTP , err )
218
+ }
219
+ }
220
+
221
+ func TestCallAudioAPISendRequestErrorText (t * testing.T ) {
222
+ client := NewClient ("test-token" )
223
+ tmp := t .TempDir ()
224
+ path := filepath .Join (tmp , "file.mp3" )
225
+ if err := os .WriteFile (path , []byte ("content" ), 0644 ); err != nil {
226
+ t .Fatalf ("failed to write temp file: %v" , err )
227
+ }
228
+
229
+ errHTTP := errors .New ("mock HTTPClient failure" )
230
+ client .config .HTTPClient = & errorHTTPClient {err : errHTTP }
231
+
232
+ // Use a non-JSON response format to exercise the text path.
233
+ req := AudioRequest {FilePath : path , Model : Whisper1 , Format : AudioResponseFormatText }
234
+ _ , err := client .callAudioAPI (context .Background (), req , "translations" )
235
+ if err == nil {
236
+ t .Fatal ("expected error but got none" )
237
+ }
238
+ if ! errors .Is (err , errHTTP ) {
239
+ t .Errorf ("expected error %v, got %v" , errHTTP , err )
240
+ }
241
+ }
0 commit comments