Skip to content

Commit f028c28

Browse files
authored
fix: function call error due to nil properties (429) (#431)
* fix: fix function call error due to nil properties (429) * refactor: refactoring initializeProperties func in jsonschema pkg (429)
1 parent 181fc2a commit f028c28

File tree

2 files changed

+225
-1
lines changed

2 files changed

+225
-1
lines changed

jsonschema/json.go

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
// and/or pass in the schema in []byte format.
55
package jsonschema
66

7+
import "encoding/json"
8+
79
type DataType string
810

911
const (
@@ -17,7 +19,7 @@ const (
1719
)
1820

1921
// Definition is a struct for describing a JSON Schema.
20-
// It is fairly limited and you may have better luck using a third-party library.
22+
// It is fairly limited, and you may have better luck using a third-party library.
2123
type Definition struct {
2224
// Type specifies the data type of the schema.
2325
Type DataType `json:"type,omitempty"`
@@ -33,3 +35,24 @@ type Definition struct {
3335
// Items specifies which data type an array contains, if the schema type is Array.
3436
Items *Definition `json:"items,omitempty"`
3537
}
38+
39+
func (d *Definition) MarshalJSON() ([]byte, error) {
40+
d.initializeProperties()
41+
return json.Marshal(*d)
42+
}
43+
44+
func (d *Definition) initializeProperties() {
45+
if d.Properties == nil {
46+
d.Properties = make(map[string]Definition)
47+
return
48+
}
49+
50+
for k, v := range d.Properties {
51+
if v.Properties == nil {
52+
v.Properties = make(map[string]Definition)
53+
} else {
54+
v.initializeProperties()
55+
}
56+
d.Properties[k] = v
57+
}
58+
}

jsonschema/json_test.go

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
package jsonschema_test
2+
3+
import (
4+
"encoding/json"
5+
"reflect"
6+
"testing"
7+
8+
. "github.com/sashabaranov/go-openai/jsonschema"
9+
)
10+
11+
func TestDefinition_MarshalJSON(t *testing.T) {
12+
tests := []struct {
13+
name string
14+
def Definition
15+
want string
16+
}{
17+
{
18+
name: "Test with empty Definition",
19+
def: Definition{},
20+
want: `{"properties":{}}`,
21+
},
22+
{
23+
name: "Test with Definition properties set",
24+
def: Definition{
25+
Type: String,
26+
Description: "A string type",
27+
Properties: map[string]Definition{
28+
"name": {
29+
Type: String,
30+
},
31+
},
32+
},
33+
want: `{
34+
"type":"string",
35+
"description":"A string type",
36+
"properties":{
37+
"name":{
38+
"type":"string",
39+
"properties":{}
40+
}
41+
}
42+
}`,
43+
},
44+
{
45+
name: "Test with nested Definition properties",
46+
def: Definition{
47+
Type: Object,
48+
Properties: map[string]Definition{
49+
"user": {
50+
Type: Object,
51+
Properties: map[string]Definition{
52+
"name": {
53+
Type: String,
54+
},
55+
"age": {
56+
Type: Integer,
57+
},
58+
},
59+
},
60+
},
61+
},
62+
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+
}`,
80+
},
81+
{
82+
name: "Test with complex nested Definition",
83+
def: Definition{
84+
Type: Object,
85+
Properties: map[string]Definition{
86+
"user": {
87+
Type: Object,
88+
Properties: map[string]Definition{
89+
"name": {
90+
Type: String,
91+
},
92+
"age": {
93+
Type: Integer,
94+
},
95+
"address": {
96+
Type: Object,
97+
Properties: map[string]Definition{
98+
"city": {
99+
Type: String,
100+
},
101+
"country": {
102+
Type: String,
103+
},
104+
},
105+
},
106+
},
107+
},
108+
},
109+
},
110+
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+
}`,
141+
},
142+
{
143+
name: "Test with Array type Definition",
144+
def: Definition{
145+
Type: Array,
146+
Items: &Definition{
147+
Type: String,
148+
},
149+
Properties: map[string]Definition{
150+
"name": {
151+
Type: String,
152+
},
153+
},
154+
},
155+
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+
}`,
170+
},
171+
}
172+
173+
for _, tt := range tests {
174+
t.Run(tt.name, func(t *testing.T) {
175+
gotBytes, err := json.Marshal(&tt.def)
176+
if err != nil {
177+
t.Errorf("Failed to Marshal JSON: error = %v", err)
178+
return
179+
}
180+
181+
var got map[string]interface{}
182+
err = json.Unmarshal(gotBytes, &got)
183+
if err != nil {
184+
t.Errorf("Failed to Unmarshal JSON: error = %v", err)
185+
return
186+
}
187+
188+
wantBytes := []byte(tt.want)
189+
var want map[string]interface{}
190+
err = json.Unmarshal(wantBytes, &want)
191+
if err != nil {
192+
t.Errorf("Failed to Unmarshal JSON: error = %v", err)
193+
return
194+
}
195+
196+
if !reflect.DeepEqual(got, want) {
197+
t.Errorf("MarshalJSON() got = %v, want %v", got, want)
198+
}
199+
})
200+
}
201+
}

0 commit comments

Comments
 (0)