Skip to content

Commit 5ea214a

Browse files
authored
Improve unit test coverage (#984)
* add tests for config * add audio tests * lint * lint * lint
1 parent d65f0cb commit 5ea214a

File tree

2 files changed

+153
-0
lines changed

2 files changed

+153
-0
lines changed

audio_test.go

+132
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,16 @@ package openai //nolint:testpackage // testing private field
22

33
import (
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+
}

config_test.go

+21
Original file line numberDiff line numberDiff line change
@@ -100,3 +100,24 @@ func TestDefaultAnthropicConfigWithEmptyValues(t *testing.T) {
100100
t.Errorf("Expected BaseURL to be %v, got %v", expectedBaseURL, config.BaseURL)
101101
}
102102
}
103+
104+
func TestClientConfigString(t *testing.T) {
105+
// String() should always return the constant value
106+
conf := openai.DefaultConfig("dummy-token")
107+
expected := "<OpenAI API ClientConfig>"
108+
got := conf.String()
109+
if got != expected {
110+
t.Errorf("ClientConfig.String() = %q; want %q", got, expected)
111+
}
112+
}
113+
114+
func TestGetAzureDeploymentByModel_NoMapper(t *testing.T) {
115+
// On a zero-value or DefaultConfig, AzureModelMapperFunc is nil,
116+
// so GetAzureDeploymentByModel should just return the input model.
117+
conf := openai.DefaultConfig("dummy-token")
118+
model := "some-model"
119+
got := conf.GetAzureDeploymentByModel(model)
120+
if got != model {
121+
t.Errorf("GetAzureDeploymentByModel(%q) = %q; want %q", model, got, model)
122+
}
123+
}

0 commit comments

Comments
 (0)