Skip to content

Commit 730beeb

Browse files
Update aggregate schema tests to use V3 union API (From/As methods)
Rewrite 9 test files that referenced the old V2 struct-field pattern (e.g., union.Cat, union.String0) to use V3 deferred-parsing union API (FromCat/AsCat via json.RawMessage). Updated: any_of_inline, nested_aggregate, parameters/any_of, issue_502, issue_936, issue_1029, issue_1189, issue_1429, issue_1710. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 1d1e5be commit 730beeb

File tree

9 files changed

+1392
-924
lines changed

9 files changed

+1392
-924
lines changed

codegen/internal/test/components/any_of_inline/output/types_test.go

Lines changed: 165 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import (
66
)
77

88
// TestAnyOfInlineCatType verifies the Cat type fields are accessible.
9-
// V2 test suite: internal/test/components/anyof/inline
109
func TestAnyOfInlineCatType(t *testing.T) {
1110
id := "cat-1"
1211
name := "Whiskers"
@@ -28,6 +27,12 @@ func TestAnyOfInlineCatType(t *testing.T) {
2827
if *cat.Name != "Whiskers" {
2928
t.Errorf("Name = %q, want %q", *cat.Name, "Whiskers")
3029
}
30+
if *cat.Breed != "Siamese" {
31+
t.Errorf("Breed = %q, want %q", *cat.Breed, "Siamese")
32+
}
33+
if *cat.Color != "cream" {
34+
t.Errorf("Color = %q, want %q", *cat.Color, "cream")
35+
}
3136
if *cat.Purrs != true {
3237
t.Errorf("Purrs = %v, want true", *cat.Purrs)
3338
}
@@ -37,17 +42,24 @@ func TestAnyOfInlineCatType(t *testing.T) {
3742
func TestAnyOfInlineDogType(t *testing.T) {
3843
id := "dog-1"
3944
name := "Rex"
45+
breed := "Labrador"
46+
color := "golden"
4047
barks := true
4148

4249
dog := Dog{
4350
ID: &id,
4451
Name: &name,
52+
Breed: &breed,
53+
Color: &color,
4554
Barks: &barks,
4655
}
4756

4857
if *dog.ID != "dog-1" {
4958
t.Errorf("ID = %q, want %q", *dog.ID, "dog-1")
5059
}
60+
if *dog.Name != "Rex" {
61+
t.Errorf("Name = %q, want %q", *dog.Name, "Rex")
62+
}
5163
if *dog.Barks != true {
5264
t.Errorf("Barks = %v, want true", *dog.Barks)
5365
}
@@ -57,155 +69,221 @@ func TestAnyOfInlineDogType(t *testing.T) {
5769
func TestAnyOfInlineRatType(t *testing.T) {
5870
id := "rat-1"
5971
name := "Remy"
72+
color := "grey"
6073
squeaks := true
6174

6275
rat := Rat{
6376
ID: &id,
6477
Name: &name,
78+
Color: &color,
6579
Squeaks: &squeaks,
6680
}
6781

6882
if *rat.ID != "rat-1" {
6983
t.Errorf("ID = %q, want %q", *rat.ID, "rat-1")
7084
}
85+
if *rat.Name != "Remy" {
86+
t.Errorf("Name = %q, want %q", *rat.Name, "Remy")
87+
}
7188
if *rat.Squeaks != true {
7289
t.Errorf("Squeaks = %v, want true", *rat.Squeaks)
7390
}
7491
}
7592

76-
// TestAnyOfInlineUnionType verifies the anyOf union type
77-
// GetPets200ResponseJSON2 holds Cat, Dog, and Rat members.
78-
func TestAnyOfInlineUnionType(t *testing.T) {
93+
// TestAnyOfInlineFromCatRoundTrip verifies FromCat -> MarshalJSON ->
94+
// UnmarshalJSON -> AsCat round-trip.
95+
func TestAnyOfInlineFromCatRoundTrip(t *testing.T) {
7996
id := "cat-1"
8097
name := "Whiskers"
81-
cat := Cat{
82-
ID: &id,
83-
Name: &name,
98+
breed := "Siamese"
99+
color := "cream"
100+
purrs := true
101+
102+
var union GetPets200ResponseJSON2
103+
if err := union.FromCat(Cat{
104+
ID: &id,
105+
Name: &name,
106+
Breed: &breed,
107+
Color: &color,
108+
Purrs: &purrs,
109+
}); err != nil {
110+
t.Fatalf("FromCat failed: %v", err)
84111
}
85112

86-
union := GetPets200ResponseJSON2{
87-
Cat: &cat,
113+
data, err := union.MarshalJSON()
114+
if err != nil {
115+
t.Fatalf("MarshalJSON failed: %v", err)
116+
}
117+
118+
var decoded GetPets200ResponseJSON2
119+
if err := decoded.UnmarshalJSON(data); err != nil {
120+
t.Fatalf("UnmarshalJSON failed: %v", err)
88121
}
89122

90-
if union.Cat == nil {
91-
t.Fatal("Cat should not be nil")
123+
got, err := decoded.AsCat()
124+
if err != nil {
125+
t.Fatalf("AsCat failed: %v", err)
126+
}
127+
if *got.ID != "cat-1" {
128+
t.Errorf("ID = %q, want %q", *got.ID, "cat-1")
92129
}
93-
if *union.Cat.ID != "cat-1" {
94-
t.Errorf("Cat.ID = %q, want %q", *union.Cat.ID, "cat-1")
130+
if *got.Name != "Whiskers" {
131+
t.Errorf("Name = %q, want %q", *got.Name, "Whiskers")
95132
}
96-
if union.Dog != nil {
97-
t.Error("Dog should be nil")
133+
if *got.Breed != "Siamese" {
134+
t.Errorf("Breed = %q, want %q", *got.Breed, "Siamese")
98135
}
99-
if union.Rat != nil {
100-
t.Error("Rat should be nil")
136+
if *got.Purrs != true {
137+
t.Errorf("Purrs = %v, want true", *got.Purrs)
101138
}
102139
}
103140

104-
// TestAnyOfInlineUnionMarshalJSON verifies that MarshalJSON merges the fields
105-
// from the set anyOf member into a single JSON object.
106-
func TestAnyOfInlineUnionMarshalJSON(t *testing.T) {
141+
// TestAnyOfInlineFromDogRoundTrip verifies FromDog -> MarshalJSON ->
142+
// UnmarshalJSON -> AsDog round-trip.
143+
func TestAnyOfInlineFromDogRoundTrip(t *testing.T) {
107144
id := "dog-1"
108145
name := "Buddy"
109146
barks := true
110-
dog := Dog{
147+
148+
var union GetPets200ResponseJSON2
149+
if err := union.FromDog(Dog{
111150
ID: &id,
112151
Name: &name,
113152
Barks: &barks,
153+
}); err != nil {
154+
t.Fatalf("FromDog failed: %v", err)
114155
}
115156

116-
union := GetPets200ResponseJSON2{
117-
Dog: &dog,
118-
}
119-
120-
data, err := json.Marshal(union)
157+
data, err := union.MarshalJSON()
121158
if err != nil {
122-
t.Fatalf("Marshal failed: %v", err)
159+
t.Fatalf("MarshalJSON failed: %v", err)
123160
}
124161

125-
var m map[string]any
126-
if err := json.Unmarshal(data, &m); err != nil {
127-
t.Fatalf("Unmarshal into map failed: %v", err)
162+
var decoded GetPets200ResponseJSON2
163+
if err := decoded.UnmarshalJSON(data); err != nil {
164+
t.Fatalf("UnmarshalJSON failed: %v", err)
128165
}
129166

130-
if m["id"] != "dog-1" {
131-
t.Errorf("id = %v, want %q", m["id"], "dog-1")
167+
got, err := decoded.AsDog()
168+
if err != nil {
169+
t.Fatalf("AsDog failed: %v", err)
170+
}
171+
if *got.ID != "dog-1" {
172+
t.Errorf("ID = %q, want %q", *got.ID, "dog-1")
132173
}
133-
if m["name"] != "Buddy" {
134-
t.Errorf("name = %v, want %q", m["name"], "Buddy")
174+
if *got.Name != "Buddy" {
175+
t.Errorf("Name = %q, want %q", *got.Name, "Buddy")
135176
}
136-
if m["barks"] != true {
137-
t.Errorf("barks = %v, want true", m["barks"])
177+
if *got.Barks != true {
178+
t.Errorf("Barks = %v, want true", *got.Barks)
138179
}
139180
}
140181

141-
// TestAnyOfInlineUnionUnmarshalJSON verifies that UnmarshalJSON populates all
142-
// matching anyOf members from the input JSON.
143-
func TestAnyOfInlineUnionUnmarshalJSON(t *testing.T) {
144-
input := `{"id":"pet-1","name":"Furball","color":"brown","purrs":true}`
182+
// TestAnyOfInlineFromRatRoundTrip verifies FromRat -> MarshalJSON ->
183+
// UnmarshalJSON -> AsRat round-trip.
184+
func TestAnyOfInlineFromRatRoundTrip(t *testing.T) {
185+
id := "rat-1"
186+
name := "Remy"
187+
squeaks := true
145188

146189
var union GetPets200ResponseJSON2
147-
if err := json.Unmarshal([]byte(input), &union); err != nil {
148-
t.Fatalf("Unmarshal failed: %v", err)
190+
if err := union.FromRat(Rat{
191+
ID: &id,
192+
Name: &name,
193+
Squeaks: &squeaks,
194+
}); err != nil {
195+
t.Fatalf("FromRat failed: %v", err)
149196
}
150197

151-
// Cat should match because purrs is a Cat field
152-
if union.Cat == nil {
153-
t.Fatal("Cat should not be nil after unmarshal")
154-
}
155-
if *union.Cat.Name != "Furball" {
156-
t.Errorf("Cat.Name = %q, want %q", *union.Cat.Name, "Furball")
198+
data, err := union.MarshalJSON()
199+
if err != nil {
200+
t.Fatalf("MarshalJSON failed: %v", err)
157201
}
158-
if *union.Cat.Purrs != true {
159-
t.Errorf("Cat.Purrs = %v, want true", *union.Cat.Purrs)
202+
203+
var decoded GetPets200ResponseJSON2
204+
if err := decoded.UnmarshalJSON(data); err != nil {
205+
t.Fatalf("UnmarshalJSON failed: %v", err)
160206
}
161207

162-
// Dog and Rat should also match (anyOf allows multiple matches)
163-
if union.Dog == nil {
164-
t.Fatal("Dog should not be nil (anyOf allows multiple matches)")
208+
got, err := decoded.AsRat()
209+
if err != nil {
210+
t.Fatalf("AsRat failed: %v", err)
211+
}
212+
if *got.ID != "rat-1" {
213+
t.Errorf("ID = %q, want %q", *got.ID, "rat-1")
165214
}
166-
if union.Rat == nil {
167-
t.Fatal("Rat should not be nil (anyOf allows multiple matches)")
215+
if *got.Name != "Remy" {
216+
t.Errorf("Name = %q, want %q", *got.Name, "Remy")
217+
}
218+
if *got.Squeaks != true {
219+
t.Errorf("Squeaks = %v, want true", *got.Squeaks)
168220
}
169221
}
170222

171-
// TestAnyOfInlineResponseType verifies the GetPetsJSONResponse wrapper type.
172-
func TestAnyOfInlineResponseType(t *testing.T) {
173-
id := "rat-1"
174-
name := "Scabbers"
175-
rat := Rat{
176-
ID: &id,
177-
Name: &name,
223+
// TestAnyOfInlineUnmarshalJSONObject verifies that raw JSON can be unmarshaled
224+
// into the union and then extracted as the correct variant.
225+
func TestAnyOfInlineUnmarshalJSONObject(t *testing.T) {
226+
input := `{"id":"pet-1","name":"Furball","color":"brown","purrs":true}`
227+
228+
var union GetPets200ResponseJSON2
229+
if err := union.UnmarshalJSON([]byte(input)); err != nil {
230+
t.Fatalf("UnmarshalJSON failed: %v", err)
231+
}
232+
233+
// The JSON has "purrs", so it should decode as a Cat.
234+
cat, err := union.AsCat()
235+
if err != nil {
236+
t.Fatalf("AsCat failed: %v", err)
237+
}
238+
if *cat.Name != "Furball" {
239+
t.Errorf("Cat.Name = %q, want %q", *cat.Name, "Furball")
240+
}
241+
if *cat.Color != "brown" {
242+
t.Errorf("Cat.Color = %q, want %q", *cat.Color, "brown")
243+
}
244+
if *cat.Purrs != true {
245+
t.Errorf("Cat.Purrs = %v, want true", *cat.Purrs)
178246
}
179247

180-
resp := GetPetsJSONResponse{
181-
Data: []GetPets200ResponseJSON2{
182-
{Rat: &rat},
183-
},
248+
// anyOf allows the same data to also be read as Dog or Rat (shared fields
249+
// decode, variant-specific fields are zero/nil).
250+
dog, err := union.AsDog()
251+
if err != nil {
252+
t.Fatalf("AsDog failed: %v", err)
253+
}
254+
if *dog.Name != "Furball" {
255+
t.Errorf("Dog.Name = %q, want %q", *dog.Name, "Furball")
256+
}
257+
if dog.Barks != nil {
258+
t.Errorf("Dog.Barks = %v, want nil (not in input)", *dog.Barks)
184259
}
185260

186-
if len(resp.Data) != 1 {
187-
t.Fatalf("Data length = %d, want 1", len(resp.Data))
261+
rat, err := union.AsRat()
262+
if err != nil {
263+
t.Fatalf("AsRat failed: %v", err)
188264
}
189-
if resp.Data[0].Rat == nil {
190-
t.Fatal("Data[0].Rat should not be nil")
265+
if *rat.Name != "Furball" {
266+
t.Errorf("Rat.Name = %q, want %q", *rat.Name, "Furball")
191267
}
192-
if *resp.Data[0].Rat.Name != "Scabbers" {
193-
t.Errorf("Data[0].Rat.Name = %q, want %q", *resp.Data[0].Rat.Name, "Scabbers")
268+
if rat.Squeaks != nil {
269+
t.Errorf("Rat.Squeaks = %v, want nil (not in input)", *rat.Squeaks)
194270
}
195271
}
196272

197273
// TestAnyOfInlineResponseJSONRoundTrip verifies JSON round-trip for the
198-
// response wrapper containing anyOf union items.
274+
// GetPetsJSONResponse wrapper containing anyOf union items.
199275
func TestAnyOfInlineResponseJSONRoundTrip(t *testing.T) {
200276
id := "cat-2"
201277
name := "Luna"
202278
purrs := true
203-
cat := Cat{ID: &id, Name: &name, Purrs: &purrs}
279+
280+
var union GetPets200ResponseJSON2
281+
if err := union.FromCat(Cat{ID: &id, Name: &name, Purrs: &purrs}); err != nil {
282+
t.Fatalf("FromCat failed: %v", err)
283+
}
204284

205285
original := GetPetsJSONResponse{
206-
Data: []GetPets200ResponseJSON2{
207-
{Cat: &cat},
208-
},
286+
Data: []GetPets200ResponseJSON2{union},
209287
}
210288

211289
data, err := json.Marshal(original)
@@ -221,11 +299,16 @@ func TestAnyOfInlineResponseJSONRoundTrip(t *testing.T) {
221299
if len(decoded.Data) != 1 {
222300
t.Fatalf("Data length = %d, want 1", len(decoded.Data))
223301
}
224-
if decoded.Data[0].Cat == nil {
225-
t.Fatal("decoded Cat should not be nil")
302+
303+
cat, err := decoded.Data[0].AsCat()
304+
if err != nil {
305+
t.Fatalf("AsCat failed: %v", err)
306+
}
307+
if *cat.Name != "Luna" {
308+
t.Errorf("Cat.Name = %q, want %q", *cat.Name, "Luna")
226309
}
227-
if *decoded.Data[0].Cat.Name != "Luna" {
228-
t.Errorf("Cat.Name = %q, want %q", *decoded.Data[0].Cat.Name, "Luna")
310+
if *cat.Purrs != true {
311+
t.Errorf("Cat.Purrs = %v, want true", *cat.Purrs)
229312
}
230313
}
231314

@@ -253,9 +336,6 @@ func TestAnyOfInlineApplyDefaults(t *testing.T) {
253336
resp := &GetPetsJSONResponse{}
254337
resp.ApplyDefaults()
255338

256-
id := "test"
257-
union := &GetPets200ResponseJSON2{
258-
Cat: &Cat{ID: &id},
259-
}
339+
union := &GetPets200ResponseJSON2{}
260340
union.ApplyDefaults()
261341
}

0 commit comments

Comments
 (0)