@@ -2,12 +2,16 @@ package openai //nolint:testpackage // testing private field
22
33import (
44 "bytes"
5+ "context"
6+ "errors"
57 "fmt"
68 "io"
9+ "net/http"
710 "os"
811 "path/filepath"
912 "testing"
1013
14+ utils "github.com/sashabaranov/go-openai/internal"
1115 "github.com/sashabaranov/go-openai/internal/test"
1216 "github.com/sashabaranov/go-openai/internal/test/checks"
1317)
@@ -107,3 +111,131 @@ func TestCreateFileField(t *testing.T) {
107111 checks .HasError (t , err , "createFileField using file should return error when open file fails" )
108112 })
109113}
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