@@ -17,7 +17,7 @@ func TestDefinition_MarshalJSON(t *testing.T) {
17
17
{
18
18
name : "Test with empty Definition" ,
19
19
def : jsonschema.Definition {},
20
- want : `{"properties":{} }` ,
20
+ want : `{}` ,
21
21
},
22
22
{
23
23
name : "Test with Definition properties set" ,
@@ -31,15 +31,14 @@ func TestDefinition_MarshalJSON(t *testing.T) {
31
31
},
32
32
},
33
33
want : `{
34
- "type":"string",
35
- "description":"A string type",
36
- "properties":{
37
- "name":{
38
- "type":"string",
39
- "properties":{}
40
- }
41
- }
42
- }` ,
34
+ "type":"string",
35
+ "description":"A string type",
36
+ "properties":{
37
+ "name":{
38
+ "type":"string"
39
+ }
40
+ }
41
+ }` ,
43
42
},
44
43
{
45
44
name : "Test with nested Definition properties" ,
@@ -60,23 +59,21 @@ func TestDefinition_MarshalJSON(t *testing.T) {
60
59
},
61
60
},
62
61
want : `{
63
- "type":"object",
64
- "properties":{
65
- "user":{
66
- "type":"object",
67
- "properties":{
68
- "name":{
69
- "type":"string",
70
- "properties":{}
71
- },
72
- "age":{
73
- "type":"integer",
74
- "properties":{}
75
- }
76
- }
77
- }
78
- }
79
- }` ,
62
+ "type":"object",
63
+ "properties":{
64
+ "user":{
65
+ "type":"object",
66
+ "properties":{
67
+ "name":{
68
+ "type":"string"
69
+ },
70
+ "age":{
71
+ "type":"integer"
72
+ }
73
+ }
74
+ }
75
+ }
76
+ }` ,
80
77
},
81
78
{
82
79
name : "Test with complex nested Definition" ,
@@ -108,36 +105,32 @@ func TestDefinition_MarshalJSON(t *testing.T) {
108
105
},
109
106
},
110
107
want : `{
111
- "type":"object",
112
- "properties":{
113
- "user":{
114
- "type":"object",
115
- "properties":{
116
- "name":{
117
- "type":"string",
118
- "properties":{}
119
- },
120
- "age":{
121
- "type":"integer",
122
- "properties":{}
123
- },
124
- "address":{
125
- "type":"object",
126
- "properties":{
127
- "city":{
128
- "type":"string",
129
- "properties":{}
130
- },
131
- "country":{
132
- "type":"string",
133
- "properties":{}
134
- }
135
- }
136
- }
137
- }
138
- }
139
- }
140
- }` ,
108
+ "type":"object",
109
+ "properties":{
110
+ "user":{
111
+ "type":"object",
112
+ "properties":{
113
+ "name":{
114
+ "type":"string"
115
+ },
116
+ "age":{
117
+ "type":"integer"
118
+ },
119
+ "address":{
120
+ "type":"object",
121
+ "properties":{
122
+ "city":{
123
+ "type":"string"
124
+ },
125
+ "country":{
126
+ "type":"string"
127
+ }
128
+ }
129
+ }
130
+ }
131
+ }
132
+ }
133
+ }` ,
141
134
},
142
135
{
143
136
name : "Test with Array type Definition" ,
@@ -153,20 +146,16 @@ func TestDefinition_MarshalJSON(t *testing.T) {
153
146
},
154
147
},
155
148
want : `{
156
- "type":"array",
157
- "items":{
158
- "type":"string",
159
- "properties":{
160
-
161
- }
162
- },
163
- "properties":{
164
- "name":{
165
- "type":"string",
166
- "properties":{}
167
- }
168
- }
169
- }` ,
149
+ "type":"array",
150
+ "items":{
151
+ "type":"string"
152
+ },
153
+ "properties":{
154
+ "name":{
155
+ "type":"string"
156
+ }
157
+ }
158
+ }` ,
170
159
},
171
160
}
172
161
@@ -193,6 +182,185 @@ func TestDefinition_MarshalJSON(t *testing.T) {
193
182
}
194
183
}
195
184
185
+ func TestStructToSchema (t * testing.T ) {
186
+ tests := []struct {
187
+ name string
188
+ in any
189
+ want string
190
+ }{
191
+ {
192
+ name : "Test with empty struct" ,
193
+ in : struct {}{},
194
+ want : `{
195
+ "type":"object",
196
+ "additionalProperties":false
197
+ }` ,
198
+ },
199
+ {
200
+ name : "Test with struct containing many fields" ,
201
+ in : struct {
202
+ Name string `json:"name"`
203
+ Age int `json:"age"`
204
+ Active bool `json:"active"`
205
+ Height float64 `json:"height"`
206
+ Cities []struct {
207
+ Name string `json:"name"`
208
+ State string `json:"state"`
209
+ } `json:"cities"`
210
+ }{
211
+ Name : "John Doe" ,
212
+ Age : 30 ,
213
+ Cities : []struct {
214
+ Name string `json:"name"`
215
+ State string `json:"state"`
216
+ }{
217
+ {Name : "New York" , State : "NY" },
218
+ {Name : "Los Angeles" , State : "CA" },
219
+ },
220
+ },
221
+ want : `{
222
+ "type":"object",
223
+ "properties":{
224
+ "name":{
225
+ "type":"string"
226
+ },
227
+ "age":{
228
+ "type":"integer"
229
+ },
230
+ "active":{
231
+ "type":"boolean"
232
+ },
233
+ "height":{
234
+ "type":"number"
235
+ },
236
+ "cities":{
237
+ "type":"array",
238
+ "items":{
239
+ "additionalProperties":false,
240
+ "type":"object",
241
+ "properties":{
242
+ "name":{
243
+ "type":"string"
244
+ },
245
+ "state":{
246
+ "type":"string"
247
+ }
248
+ },
249
+ "required":["name","state"]
250
+ }
251
+ }
252
+ },
253
+ "required":["name","age","active","height","cities"],
254
+ "additionalProperties":false
255
+ }` ,
256
+ },
257
+ {
258
+ name : "Test with description tag" ,
259
+ in : struct {
260
+ Name string `json:"name" description:"The name of the person"`
261
+ }{
262
+ Name : "John Doe" ,
263
+ },
264
+ want : `{
265
+ "type":"object",
266
+ "properties":{
267
+ "name":{
268
+ "type":"string",
269
+ "description":"The name of the person"
270
+ }
271
+ },
272
+ "required":["name"],
273
+ "additionalProperties":false
274
+ }` ,
275
+ },
276
+ {
277
+ name : "Test with required tag" ,
278
+ in : struct {
279
+ Name string `json:"name" required:"false"`
280
+ }{
281
+ Name : "John Doe" ,
282
+ },
283
+ want : `{
284
+ "type":"object",
285
+ "properties":{
286
+ "name":{
287
+ "type":"string"
288
+ }
289
+ },
290
+ "additionalProperties":false
291
+ }` ,
292
+ },
293
+ {
294
+ name : "Test with enum tag" ,
295
+ in : struct {
296
+ Color string `json:"color" enum:"red,green,blue"`
297
+ }{
298
+ Color : "red" ,
299
+ },
300
+ want : `{
301
+ "type":"object",
302
+ "properties":{
303
+ "color":{
304
+ "type":"string",
305
+ "enum":["red","green","blue"]
306
+ }
307
+ },
308
+ "required":["color"],
309
+ "additionalProperties":false
310
+ }` ,
311
+ },
312
+ {
313
+ name : "Test with nullable tag" ,
314
+ in : struct {
315
+ Name * string `json:"name" nullable:"true"`
316
+ }{
317
+ Name : nil ,
318
+ },
319
+ want : `{
320
+
321
+ "type":"object",
322
+ "properties":{
323
+ "name":{
324
+ "type":"string",
325
+ "nullable":true
326
+ }
327
+ },
328
+ "required":["name"],
329
+ "additionalProperties":false
330
+ }` ,
331
+ },
332
+ }
333
+
334
+ for _ , tt := range tests {
335
+ t .Run (tt .name , func (t * testing.T ) {
336
+ wantBytes := []byte (tt .want )
337
+
338
+ schema , err := jsonschema .GenerateSchemaForType (tt .in )
339
+ if err != nil {
340
+ t .Errorf ("Failed to generate schema: error = %v" , err )
341
+ return
342
+ }
343
+
344
+ var want map [string ]interface {}
345
+ err = json .Unmarshal (wantBytes , & want )
346
+ if err != nil {
347
+ t .Errorf ("Failed to Unmarshal JSON: error = %v" , err )
348
+ return
349
+ }
350
+
351
+ got := structToMap (t , schema )
352
+ gotPtr := structToMap (t , & schema )
353
+
354
+ if ! reflect .DeepEqual (got , want ) {
355
+ t .Errorf ("MarshalJSON() got = %v, want %v" , got , want )
356
+ }
357
+ if ! reflect .DeepEqual (gotPtr , want ) {
358
+ t .Errorf ("MarshalJSON() gotPtr = %v, want %v" , gotPtr , want )
359
+ }
360
+ })
361
+ }
362
+ }
363
+
196
364
func structToMap (t * testing.T , v any ) map [string ]any {
197
365
t .Helper ()
198
366
gotBytes , err := json .Marshal (v )
0 commit comments