package llm import ( "errors" "io" "strings" "testing" ) type responseBytesAndError struct { data []byte err error } func (r *responseBytesAndError) Read(p []byte) (int, error) { if len(r.data) == 0 { return 0, r.err } n := copy(p, r.data) r.data = r.data[n:] if len(r.data) == 0 { return n, r.err } return n, nil } func TestSuccessfulResponseReadFailuresRetainCause(t *testing.T) { cause := errors.New("private reader diagnostic") for _, test := range []struct { name, prefix string together bool }{ {"partial", `{"choices":[`, false}, {"complete then failure", successfulProviderResponse, false}, {"bytes and error together", successfulProviderResponse, true}, } { t.Run(test.name, func(t *testing.T) { var reader io.Reader = io.MultiReader(strings.NewReader(test.prefix), failingReader{err: cause}) if test.together { reader = &responseBytesAndError{data: []byte(test.prefix), err: cause} } _, err := decodeOpenAIChatResponse(reader) if !errors.Is(err, ErrTransport) || !errors.Is(err, cause) || errors.Is(err, ErrMalformedResponse) || strings.Contains(err.Error(), cause.Error()) { t.Fatalf("read failure = %v", err) } }) } }