@@ -75,6 +75,160 @@ func TestLoadFromJsonBytesArray(t *testing.T) {
7575 assert .EqualValues (t , []string {"foo" , "bar" }, expect )
7676}
7777
78+ func TestConfigJson5 (t * testing.T ) {
79+ // JSON5 with comments, trailing commas, and unquoted keys
80+ text := `{
81+ // This is a comment
82+ a: 'foo', // single quotes
83+ b: 1,
84+ c: "${FOO}",
85+ d: "abcd!@#$112", // trailing comma
86+ }`
87+ t .Setenv ("FOO" , "2" )
88+
89+ tmpfile , err := createTempFile (t , ".json5" , text )
90+ assert .Nil (t , err )
91+
92+ var val struct {
93+ A string `json:"a"`
94+ B int `json:"b"`
95+ C string `json:"c"`
96+ D string `json:"d"`
97+ }
98+ MustLoad (tmpfile , & val )
99+ assert .Equal (t , "foo" , val .A )
100+ assert .Equal (t , 1 , val .B )
101+ assert .Equal (t , "${FOO}" , val .C )
102+ assert .Equal (t , "abcd!@#$112" , val .D )
103+ }
104+
105+ func TestConfigJsonStandardParser (t * testing.T ) {
106+ // Standard JSON uses standard JSON parser (not JSON5) for backward compatibility
107+ text := `{
108+ "a": "foo",
109+ "b": 1,
110+ "c": "${FOO}",
111+ "d": "abcd!@#$112"
112+ }`
113+ t .Setenv ("FOO" , "2" )
114+
115+ tmpfile , err := createTempFile (t , ".json" , text )
116+ assert .Nil (t , err )
117+
118+ var val struct {
119+ A string `json:"a"`
120+ B int `json:"b"`
121+ C string `json:"c"`
122+ D string `json:"d"`
123+ }
124+ MustLoad (tmpfile , & val )
125+ assert .Equal (t , "foo" , val .A )
126+ assert .Equal (t , 1 , val .B )
127+ assert .Equal (t , "${FOO}" , val .C )
128+ assert .Equal (t , "abcd!@#$112" , val .D )
129+ }
130+
131+ func TestConfigJsonLargeIntegers (t * testing.T ) {
132+ // Test that .json files preserve large integer precision (backward compatibility)
133+ text := `{
134+ "id": 1234567890123456789,
135+ "timestamp": 9223372036854775807
136+ }`
137+
138+ tmpfile , err := createTempFile (t , ".json" , text )
139+ assert .Nil (t , err )
140+
141+ var val struct {
142+ ID int64 `json:"id"`
143+ Timestamp int64 `json:"timestamp"`
144+ }
145+ MustLoad (tmpfile , & val )
146+ assert .Equal (t , int64 (1234567890123456789 ), val .ID )
147+ assert .Equal (t , int64 (9223372036854775807 ), val .Timestamp )
148+ }
149+
150+ func TestConfigJson5Env (t * testing.T ) {
151+ text := `{
152+ // Comment with env variable
153+ a: "foo",
154+ b: 1,
155+ c: "${FOO}",
156+ d: "abcd!@#$a12 3",
157+ }`
158+ t .Setenv ("FOO" , "2" )
159+
160+ tmpfile , err := createTempFile (t , ".json5" , text )
161+ assert .Nil (t , err )
162+
163+ var val struct {
164+ A string `json:"a"`
165+ B int `json:"b"`
166+ C string `json:"c"`
167+ D string `json:"d"`
168+ }
169+ MustLoad (tmpfile , & val , UseEnv ())
170+ assert .Equal (t , "foo" , val .A )
171+ assert .Equal (t , 1 , val .B )
172+ assert .Equal (t , "2" , val .C )
173+ assert .Equal (t , "abcd!@# 3" , val .D )
174+ }
175+
176+ func TestLoadFromJson5Bytes (t * testing.T ) {
177+ // Test JSON5 features: comments, trailing commas, single quotes, unquoted keys
178+ input := []byte (`{
179+ // This is a comment
180+ users: [
181+ {name: 'foo'}, // trailing comma
182+ {Name: "bar"},
183+ ],
184+ }` )
185+ var val struct {
186+ Users []struct {
187+ Name string
188+ }
189+ }
190+
191+ assert .NoError (t , LoadFromJson5Bytes (input , & val ))
192+ var expect []string
193+ for _ , user := range val .Users {
194+ expect = append (expect , user .Name )
195+ }
196+ assert .EqualValues (t , []string {"foo" , "bar" }, expect )
197+ }
198+
199+ func TestLoadFromJson5BytesError (t * testing.T ) {
200+ // Invalid JSON5 syntax
201+ input := []byte (`{a: foo}` ) // unquoted string value (invalid)
202+ var val struct {
203+ A string
204+ }
205+
206+ assert .Error (t , LoadFromJson5Bytes (input , & val ))
207+ }
208+
209+ func TestConfigJson5LargeIntegersLimitation (t * testing.T ) {
210+ // Document that JSON5 has precision limitations for large integers (>2^53)
211+ // due to JavaScript number semantics. Users should use .json for configs with large IDs.
212+ text := `{
213+ // JSON5 converts numbers to float64, which loses precision for large integers
214+ id: 1234567890123456789
215+ }`
216+
217+ tmpfile , err := createTempFile (t , ".json5" , text )
218+ assert .Nil (t , err )
219+
220+ var val struct {
221+ ID int64 `json:"id"`
222+ }
223+
224+ // This will load; depending on the JSON5 implementation, large integers may lose precision.
225+ // This test documents that behavior without requiring loss of precision as an invariant.
226+ err = Load (tmpfile , & val )
227+ assert .NoError (t , err )
228+
229+ t .Logf ("loaded JSON5 large integer id=%d (original 1234567890123456789)" , val .ID )
230+ }
231+
78232func TestConfigToml (t * testing.T ) {
79233 text := `a = "foo"
80234b = 1
0 commit comments