Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions internal/test/openapi31/openapi31.gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 28 additions & 0 deletions internal/test/openapi31/openapi31_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,34 @@ func TestUnionEnumDropsConstants(t *testing.T) {
assert.Equal(t, "two", v)
}

// Union in array-items position: the element carries the permissive mapping,
// so the component is an `[]any` alias and mixed member values round-trip.
func TestReadingListUnionItems(t *testing.T) {
var r ReadingList
require.NoError(t, json.Unmarshal([]byte(`["low",97.5]`), &r))
assert.Equal(t, ReadingList{"low", 97.5}, r)
}

// A union as a oneOf branch keeps the outer schema's standard union
// machinery, with the branch accessor typed `any`. As... to `any` never
// fails, so branch discrimination falls to the caller.
func TestFlexibleIdUnionBranch(t *testing.T) {
var f FlexibleId
require.NoError(t, json.Unmarshal([]byte(`"user-7"`), &f))
v, err := f.AsFlexibleId1()
require.NoError(t, err)
assert.Equal(t, "user-7", v)

require.NoError(t, f.FromFlexibleId0(FlexibleId0{Id: "abc"}))
obj, err := f.AsFlexibleId0()
require.NoError(t, err)
assert.Equal(t, "abc", obj.Id)

v, err = f.AsFlexibleId1()
require.NoError(t, err, "the any-typed accessor succeeds even on the object branch's data")
assert.Equal(t, map[string]any{"id": "abc"}, v)
}

// petFieldComments extracts the doc comment text for each field of the Pet
// struct from a parsed AST. Returns map[fieldName]commentText.
func petFieldComments(t *testing.T, f *ast.File) map[string]string {
Expand Down
19 changes: 19 additions & 0 deletions internal/test/openapi31/spec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -247,3 +247,22 @@ components:
enum:
- 1
- two

# Union in array-items position: the element type carries the permissive
# mapping, so the component lowers to `[]any`.
ReadingList:
type: array
items:
type: [string, number]

# A union as a oneOf branch. The outer schema keeps the standard oneOf
# union machinery. The union branch's accessor is typed `any`, so its
# As... conversion never fails, the same as a typeless branch.
FlexibleId:
oneOf:
- type: object
required: [id]
properties:
id:
type: string
- type: [string, integer]
2 changes: 1 addition & 1 deletion internal/test/openapi31params/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// lowering of unions to `any` is covered in the sibling openapi31 suite;
// this suite generates a std-http server and client so the emitted
// bind-option Types lists are exercised against the real runtime binder
// (runtime >= v1.7.0), in path, query, and header positions:
// (runtime >= v1.7.0), in path, query, header, and response header positions:
//
// - the value binds to the first union member that parses, trying
// boolean, integer, number, then string — so "42" arrives as int64(42)
Expand Down
20 changes: 20 additions & 0 deletions internal/test/openapi31params/openapi31params.gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 26 additions & 0 deletions internal/test/openapi31params/openapi31params_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"testing"
Expand All @@ -26,6 +27,7 @@ func (s *captureServer) UpdateThing(w http.ResponseWriter, r *http.Request, id a
s.body = nil
_ = json.NewDecoder(r.Body).Decode(&s.body)
w.Header().Set("Content-Type", "application/json")
w.Header().Set("X-Echo", fmt.Sprint(id))
_ = json.NewEncoder(w).Encode(map[string]any{"id": id})
}

Expand Down Expand Up @@ -102,3 +104,27 @@ func TestUnionParamClientRoundTrip(t *testing.T) {
require.NoError(t, json.NewDecoder(resp.Body).Decode(&echoed))
assert.Equal(t, float64(42), echoed["id"], "response body is plain JSON, so the id comes back as a JSON number")
}

// The generated ClientWithResponses binds declared response headers through
// the styled binder with Types, so a union-typed header comes back as the
// first member that parses.
func TestUnionResponseHeaderClientBinding(t *testing.T) {
capture := &captureServer{}
srv := httptest.NewServer(Handler(capture))
defer srv.Close()

client, err := NewClientWithResponses(srv.URL)
require.NoError(t, err)

resp, err := client.UpdateThingWithResponse(context.Background(), 42, nil,
UpdateThingJSONRequestBody("x"))
require.NoError(t, err)
require.NotNil(t, resp.Headers200)
assert.Equal(t, int64(42), resp.Headers200.XEcho, "header [integer, string]: integer member wins for a numeric token")

resp, err = client.UpdateThingWithResponse(context.Background(), "abc", nil,
UpdateThingJSONRequestBody("x"))
require.NoError(t, err)
require.NotNil(t, resp.Headers200)
assert.Equal(t, "abc", resp.Headers200.XEcho, "non-numeric token falls to the string member")
}
15 changes: 11 additions & 4 deletions internal/test/openapi31params/spec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ info:
version: "1.0.0"
description: |
Exercises multi-type unions in every parameter position the runtime
binds: path, query, and header, plus a union request/response body.
Each union parameter lowers to `any`, and the generated bind calls
carry Types so runtime >= v1.7.0 picks the first member that parses
(boolean, integer, number, string).
binds: path, query, header, and response header, plus a union
request/response body. Each union parameter lowers to `any`, and the
generated bind calls carry Types so runtime >= v1.7.0 picks the first
member that parses (boolean, integer, number, string).
paths:
/things/{id}:
post:
Expand Down Expand Up @@ -54,6 +54,13 @@ paths:
responses:
"200":
description: echo of what was bound
headers:
# Response-header position: the generated ClientWithResponses
# binds declared headers through the same styled binder, so a
# union-typed header needs its Types list too.
X-Echo:
schema:
type: [integer, string]
content:
application/json:
schema:
Expand Down