openai/openai-go

Public

mirrored from https://github.com/openai/openai-goAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v1.9.0

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

packages/param/encoder_test.go

365lines · modecode

1package param_test
2
3import (
4 "encoding/json"
5 "testing"
6 "time"
7
8 "github.com/openai/openai-go/packages/param"
9)
10
11type Struct struct {
12 A string `json:"a"`
13 B int64 `json:"b"`
14 param.APIObject
15}
16
17func (r Struct) MarshalJSON() (data []byte, err error) {
18 type shadow Struct
19 return param.MarshalObject(r, (*shadow)(&r))
20}
21
22// Note that the order of fields affects the JSON
23// key order. Changing the order of the fields in this struct
24// will fail tests unnecessarily.
25type FieldStruct struct {
26 A param.Opt[string] `json:"a,omitzero"`
27 B param.Opt[int64] `json:"b,omitzero"`
28 C Struct `json:"c,omitzero"`
29 D time.Time `json:"d,omitzero" format:"date"`
30 E time.Time `json:"e,omitzero"`
31 F param.Opt[time.Time] `json:"f,omitzero" format:"date"`
32 G param.Opt[time.Time] `json:"g,omitzero"`
33 H param.Opt[time.Time] `json:"h,omitzero" format:"date-time"`
34 param.APIObject
35}
36
37func (r FieldStruct) MarshalJSON() (data []byte, err error) {
38 type shadow FieldStruct
39 return param.MarshalObject(r, (*shadow)(&r))
40}
41
42type StructWithAdditionalProperties struct {
43 First string `json:"first"`
44 Second int `json:"second"`
45 ExtraFields map[string]any `json:"-"`
46 param.APIObject
47}
48
49func (s StructWithAdditionalProperties) MarshalJSON() ([]byte, error) {
50 type shadow StructWithAdditionalProperties
51 return param.MarshalWithExtras(s, (*shadow)(&s), s.ExtraFields)
52}
53
54func TestIsNullish(t *testing.T) {
55 nullTests := map[string]param.ParamNullable{
56 "null_string": param.Null[string](),
57 "null_int64": param.Null[int64](),
58 "null_time": param.Null[time.Time](),
59 "null_struct": param.NullStruct[Struct](),
60 }
61
62 for name, test := range nullTests {
63 t.Run(name, func(t *testing.T) {
64 if !param.IsNull(test) {
65 t.Fatalf("expected %s to be null", name)
66 }
67 if param.IsOmitted(test) {
68 t.Fatalf("expected %s to not be omitted", name)
69 }
70 })
71 }
72
73 omitTests := map[string]param.ParamNullable{
74 "omit_string": param.Opt[string]{},
75 "omit_int64": param.Opt[int64]{},
76 "omit_time": param.Opt[time.Time]{},
77 "omit_struct": Struct{},
78 }
79
80 for name, test := range omitTests {
81 t.Run(name, func(t *testing.T) {
82 if param.IsNull(test) {
83 t.Fatalf("expected %s to be null", name)
84 }
85 if !param.IsOmitted(test) {
86 t.Fatalf("expected %s to not be omitted", name)
87 }
88 })
89 }
90}
91
92func TestFieldMarshal(t *testing.T) {
93 tests := map[string]struct {
94 value any
95 expected string
96 }{
97 "null_string": {param.Null[string](), "null"},
98 "null_int64": {param.Null[int64](), "null"},
99 "null_time": {param.Null[time.Time](), "null"},
100 "null_struct": {param.NullStruct[Struct](), "null"},
101
102 "float_zero": {param.NewOpt(float64(0.0)), "0"},
103 "string_zero": {param.NewOpt(""), `""`},
104 "time_zero": {param.NewOpt(time.Time{}), `"0001-01-01T00:00:00Z"`},
105
106 "string": {param.Opt[string]{Value: "string"}, `"string"`},
107 "int": {param.Opt[int64]{Value: 123}, "123"},
108 "int64": {param.Opt[int64]{Value: int64(123456789123456789)}, "123456789123456789"},
109 "struct": {Struct{A: "yo", B: 123}, `{"a":"yo","b":123}`},
110 "datetime": {
111 param.Opt[time.Time]{Value: time.Date(2023, time.March, 18, 14, 47, 38, 0, time.UTC)},
112 `"2023-03-18T14:47:38Z"`,
113 },
114 "optional_date": {
115 FieldStruct{
116 F: param.Opt[time.Time]{Value: time.Date(2023, time.March, 18, 14, 47, 38, 0, time.UTC)},
117 },
118 `{"f":"2023-03-18"}`,
119 },
120 "optional_time": {
121 FieldStruct{
122 G: param.Opt[time.Time]{Value: time.Date(2023, time.March, 18, 14, 47, 38, 0, time.UTC)},
123 },
124 `{"g":"2023-03-18T14:47:38Z"}`,
125 },
126 "optional_datetime_explicit_format": {
127 FieldStruct{
128 H: param.Opt[time.Time]{Value: time.Date(2023, time.March, 18, 14, 47, 38, 0, time.UTC)},
129 },
130 `{"h":"2023-03-18T14:47:38Z"}`,
131 },
132 "param_struct": {
133 FieldStruct{
134 A: param.Opt[string]{Value: "hello"},
135 B: param.Opt[int64]{Value: int64(12)},
136 D: time.Date(2023, time.March, 18, 14, 47, 38, 0, time.UTC),
137 E: time.Date(2023, time.March, 18, 14, 47, 38, 0, time.UTC),
138 F: param.Opt[time.Time]{Value: time.Date(2023, time.March, 18, 14, 47, 38, 0, time.UTC)},
139 G: param.Opt[time.Time]{Value: time.Date(2023, time.March, 18, 14, 47, 38, 0, time.UTC)},
140 H: param.Opt[time.Time]{Value: time.Date(2023, time.March, 18, 14, 47, 38, 0, time.UTC)},
141 },
142 `{"a":"hello","b":12,"d":"2023-03-18","e":"2023-03-18T14:47:38Z","f":"2023-03-18","g":"2023-03-18T14:47:38Z","h":"2023-03-18T14:47:38Z"}`,
143 },
144 }
145
146 for name, test := range tests {
147 t.Run(name, func(t *testing.T) {
148 b, err := json.Marshal(test.value)
149 if err != nil {
150 t.Fatalf("didn't expect error %v, expected %s", err, test.expected)
151 }
152 if string(b) != test.expected {
153 t.Fatalf("expected %s, received %s", test.expected, string(b))
154 }
155 })
156 }
157}
158
159func TestAdditionalProperties(t *testing.T) {
160 s := StructWithAdditionalProperties{
161 First: "hello",
162 Second: 14,
163 ExtraFields: map[string]any{
164 "hi": "there",
165 },
166 }
167 exp := `{"first":"hello","second":14,"hi":"there"}`
168
169 bytes, err := json.Marshal(s)
170 if err != nil {
171 t.Fatalf("failed to marshal: %v", err)
172 }
173
174 if string(bytes) != exp {
175 t.Fatalf("expected %s, got %s", exp, string(bytes))
176 }
177}
178
179func TestExtraFields(t *testing.T) {
180 v := Struct{
181 A: "hello",
182 B: 123,
183 }
184 v.SetExtraFields(map[string]any{
185 "extra": Struct{A: "recursive"},
186 "b": nil,
187 })
188 bytes, err := json.Marshal(v)
189 if err != nil {
190 t.Fatalf("failed to marshal: %v", err)
191 }
192 if string(bytes) != `{"a":"hello","b":null,"extra":{"a":"recursive","b":0}}` {
193 t.Fatalf("failed to marshal: got %v", string(bytes))
194 }
195 if v.B != 123 {
196 t.Fatalf("marshal modified field B: got %v", v.B)
197 }
198}
199
200func TestExtraFieldsForceOmitted(t *testing.T) {
201 v := Struct{
202 // Testing with the zero value.
203 // A: "",
204 // B: 0,
205 }
206 v.SetExtraFields(map[string]any{
207 "b": param.Omit,
208 })
209 bytes, err := json.Marshal(v)
210 if err != nil {
211 t.Fatalf("failed to marshal: %v", err)
212 }
213 if string(bytes) != `{"a":""}` {
214 t.Fatalf("failed to marshal: got %v", string(bytes))
215 }
216}
217
218type UnionWithDates struct {
219 OfDate param.Opt[time.Time]
220 OfTime param.Opt[time.Time]
221 param.APIUnion
222}
223
224func (r UnionWithDates) MarshalJSON() (data []byte, err error) {
225 return param.MarshalUnion(r, param.EncodedAsDate(r.OfDate), r.OfTime)
226}
227
228func TestUnionDateMarshal(t *testing.T) {
229 tests := map[string]struct {
230 value UnionWithDates
231 expected string
232 }{
233 "date_only": {
234 UnionWithDates{
235 OfDate: param.Opt[time.Time]{Value: time.Date(2023, time.March, 18, 0, 0, 0, 0, time.UTC)},
236 },
237 `"2023-03-18"`,
238 },
239 "datetime_only": {
240 UnionWithDates{
241 OfTime: param.Opt[time.Time]{Value: time.Date(2023, time.March, 18, 14, 47, 38, 0, time.UTC)},
242 },
243 `"2023-03-18T14:47:38Z"`,
244 },
245 }
246
247 for name, test := range tests {
248 t.Run(name, func(t *testing.T) {
249 b, err := json.Marshal(test.value)
250 if err != nil {
251 t.Fatalf("didn't expect error %v, expected %s", err, test.expected)
252 }
253 if string(b) != test.expected {
254 t.Fatalf("expected %s, received %s", test.expected, string(b))
255 }
256 })
257 }
258}
259
260func TestOverride(t *testing.T) {
261 tests := map[string]struct {
262 value param.ParamStruct
263 expected string
264 }{
265 "param_struct": {
266 param.Override[FieldStruct](map[string]any{
267 "a": "hello",
268 "b": 12,
269 "c": nil,
270 }),
271 `{"a":"hello","b":12,"c":null}`,
272 },
273 "param_struct_primitive": {
274 param.Override[FieldStruct](12),
275 `12`,
276 },
277 "param_struct_null": {
278 param.Override[FieldStruct](nil),
279 `null`,
280 },
281 }
282
283 f := FieldStruct{}
284
285 f.SetExtraFields(map[string]any{
286 "z": "ok",
287 })
288
289 for name, test := range tests {
290 t.Run(name, func(t *testing.T) {
291 b, err := json.Marshal(test.value)
292 if err != nil {
293 t.Fatalf("didn't expect error %v, expected %s", err, test.expected)
294 }
295 if string(b) != test.expected {
296 t.Fatalf("expected %s, received %s", test.expected, string(b))
297 }
298 if _, ok := test.value.Overrides(); !ok {
299 t.Fatalf("expected to be overridden")
300 }
301 })
302 }
303}
304
305// Despite implementing the interface, this struct is not an param.Optional
306// since it was defined in a different package.
307type almostOpt struct{}
308
309func (almostOpt) Valid() bool { return true }
310func (almostOpt) Null() bool { return false }
311func (almostOpt) isZero() bool { return false }
312
313func (almostOpt) implOpt() {}
314
315func TestOptionalInterfaceAssignability(t *testing.T) {
316 optInt := param.Opt[int]{}
317 if _, ok := any(optInt).(param.Optional); !ok {
318 t.Fatalf("failed to assign")
319 }
320
321 notOpt := almostOpt{}
322 if _, ok := any(notOpt).(param.Optional); ok {
323 t.Fatalf("unexpected successful assignment")
324 }
325
326 notOpt.implOpt() // silence the warning
327}
328
329type PrimitiveUnion struct {
330 OfString param.Opt[string]
331 OfInt param.Opt[int]
332 param.APIUnion
333}
334
335func (p PrimitiveUnion) MarshalJSON() (data []byte, err error) {
336 return param.MarshalUnion(p, p.OfString, p.OfInt)
337}
338
339func TestOverriddenUnion(t *testing.T) {
340 tests := map[string]struct {
341 value PrimitiveUnion
342 expected string
343 }{
344 "string": {
345 param.Override[PrimitiveUnion](json.RawMessage(`"hello"`)),
346 `"hello"`,
347 },
348 "int": {
349 param.Override[PrimitiveUnion](json.RawMessage(`42`)),
350 `42`,
351 },
352 }
353
354 for name, test := range tests {
355 t.Run(name, func(t *testing.T) {
356 b, err := json.Marshal(test.value)
357 if err != nil {
358 t.Fatalf("didn't expect error %v, expected %s", err, test.expected)
359 }
360 if string(b) != test.expected {
361 t.Fatalf("expected %s, received %s", test.expected, string(b))
362 }
363 })
364 }
365}
366