1// Copyright (C) MongoDB, Inc. 2014-present.
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may
4// not use this file except in compliance with the License. You may obtain
5// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
6//
7// Based on github.com/golang/go by The Go Authors
8// See THIRD-PARTY-NOTICES for original license terms.
9
10package json
11
12import (
13	"bytes"
14	"math"
15	"reflect"
16	"testing"
17	"unicode"
18
19	"github.com/mongodb/mongo-tools/legacy/testtype"
20)
21
22type Optionals struct {
23	Sr string `json:"sr"`
24	So string `json:"so,omitempty"`
25	Sw string `json:"-"`
26
27	Ir int `json:"omitempty"` // actually named omitempty, not an option
28	Io int `json:"io,omitempty"`
29
30	Slr []string `json:"slr,random"`
31	Slo []string `json:"slo,omitempty"`
32
33	Mr map[string]interface{} `json:"mr"`
34	Mo map[string]interface{} `json:",omitempty"`
35
36	Fr float64 `json:"fr"`
37	Fo float64 `json:"fo,omitempty"`
38
39	Br bool `json:"br"`
40	Bo bool `json:"bo,omitempty"`
41
42	Ur uint `json:"ur"`
43	Uo uint `json:"uo,omitempty"`
44
45	Str struct{} `json:"str"`
46	Sto struct{} `json:"sto,omitempty"`
47}
48
49var optionalsExpected = `{
50 "sr": "",
51 "omitempty": 0,
52 "slr": null,
53 "mr": {},
54 "fr": 0,
55 "br": false,
56 "ur": 0,
57 "str": {},
58 "sto": {}
59}`
60
61func TestOmitEmpty(t *testing.T) {
62	testtype.SkipUnlessTestType(t, testtype.UnitTestType)
63	var o Optionals
64	o.Sw = "something"
65	o.Mr = map[string]interface{}{}
66	o.Mo = map[string]interface{}{}
67
68	got, err := MarshalIndent(&o, "", " ")
69	if err != nil {
70		t.Fatal(err)
71	}
72	if got := string(got); got != optionalsExpected {
73		t.Errorf(" got: %s\nwant: %s\n", got, optionalsExpected)
74	}
75}
76
77type StringTag struct {
78	BoolStr bool   `json:",string"`
79	IntStr  int64  `json:",string"`
80	StrStr  string `json:",string"`
81}
82
83var stringTagExpected = `{
84 "BoolStr": "true",
85 "IntStr": "42",
86 "StrStr": "\"xzbit\""
87}`
88
89func TestStringTag(t *testing.T) {
90	testtype.SkipUnlessTestType(t, testtype.UnitTestType)
91	var s StringTag
92	s.BoolStr = true
93	s.IntStr = 42
94	s.StrStr = "xzbit"
95	got, err := MarshalIndent(&s, "", " ")
96	if err != nil {
97		t.Fatal(err)
98	}
99	if got := string(got); got != stringTagExpected {
100		t.Fatalf(" got: %s\nwant: %s\n", got, stringTagExpected)
101	}
102
103	// Verify that it round-trips.
104	var s2 StringTag
105	err = NewDecoder(bytes.NewReader(got)).Decode(&s2)
106	if err != nil {
107		t.Fatalf("Decode: %v", err)
108	}
109	if !reflect.DeepEqual(s, s2) {
110		t.Fatalf("decode didn't match.\nsource: %#v\nEncoded as:\n%s\ndecode: %#v", s, string(got), s2)
111	}
112}
113
114// byte slices are special even if they're renamed types.
115type renamedByte byte
116type renamedByteSlice []byte
117type renamedRenamedByteSlice []renamedByte
118
119func TestEncodeRenamedByteSlice(t *testing.T) {
120	testtype.SkipUnlessTestType(t, testtype.UnitTestType)
121	s := renamedByteSlice("abc")
122	result, err := Marshal(s)
123	if err != nil {
124		t.Fatal(err)
125	}
126	expect := `"YWJj"`
127	if string(result) != expect {
128		t.Errorf(" got %s want %s", result, expect)
129	}
130	r := renamedRenamedByteSlice("abc")
131	result, err = Marshal(r)
132	if err != nil {
133		t.Fatal(err)
134	}
135	if string(result) != expect {
136		t.Errorf(" got %s want %s", result, expect)
137	}
138}
139
140func TestFloatSpecialValues(t *testing.T) {
141	testtype.SkipUnlessTestType(t, testtype.UnitTestType)
142	_, err := Marshal(math.NaN())
143	if err != nil {
144		t.Errorf("Got error for NaN: %v", err)
145	}
146
147	_, err = Marshal(math.Inf(-1))
148	if err != nil {
149		t.Errorf("Got error for -Inf: %v", err)
150	}
151
152	_, err = Marshal(math.Inf(1))
153	if err != nil {
154		t.Errorf("Got error for +Inf: %v", err)
155	}
156}
157
158// Ref has Marshaler and Unmarshaler methods with pointer receiver.
159type Ref int
160
161func (*Ref) MarshalJSON() ([]byte, error) {
162	return []byte(`"ref"`), nil
163}
164
165func (r *Ref) UnmarshalJSON([]byte) error {
166	*r = 12
167	return nil
168}
169
170// Val has Marshaler methods with value receiver.
171type Val int
172
173func (Val) MarshalJSON() ([]byte, error) {
174	return []byte(`"val"`), nil
175}
176
177// RefText has Marshaler and Unmarshaler methods with pointer receiver.
178type RefText int
179
180func (*RefText) MarshalText() ([]byte, error) {
181	return []byte(`"ref"`), nil
182}
183
184func (r *RefText) UnmarshalText([]byte) error {
185	*r = 13
186	return nil
187}
188
189// ValText has Marshaler methods with value receiver.
190type ValText int
191
192func (ValText) MarshalText() ([]byte, error) {
193	return []byte(`"val"`), nil
194}
195
196func TestRefValMarshal(t *testing.T) {
197	testtype.SkipUnlessTestType(t, testtype.UnitTestType)
198	var s = struct {
199		R0 Ref
200		R1 *Ref
201		R2 RefText
202		R3 *RefText
203		V0 Val
204		V1 *Val
205		V2 ValText
206		V3 *ValText
207	}{
208		R0: 12,
209		R1: new(Ref),
210		R2: 14,
211		R3: new(RefText),
212		V0: 13,
213		V1: new(Val),
214		V2: 15,
215		V3: new(ValText),
216	}
217	const want = `{"R0":"ref","R1":"ref","R2":"\"ref\"","R3":"\"ref\"","V0":"val","V1":"val","V2":"\"val\"","V3":"\"val\""}`
218	b, err := Marshal(&s)
219	if err != nil {
220		t.Fatalf("Marshal: %v", err)
221	}
222	if got := string(b); got != want {
223		t.Errorf("got %q, want %q", got, want)
224	}
225}
226
227// C1 implements Marshaler and returns unescaped JSON.
228type C1 int
229
230func (C1) MarshalJSON() ([]byte, error) {
231	return []byte(`"<&>"`), nil
232}
233
234// CText implements Marshaler and returns unescaped text.
235type CText int
236
237func (CText) MarshalText() ([]byte, error) {
238	return []byte(`"<&>"`), nil
239}
240
241func TestMarshalerEscaping(t *testing.T) {
242	testtype.SkipUnlessTestType(t, testtype.UnitTestType)
243	var c C1
244	want := `"\u003c\u0026\u003e"`
245	b, err := Marshal(c)
246	if err != nil {
247		t.Fatalf("Marshal(c1): %v", err)
248	}
249	if got := string(b); got != want {
250		t.Errorf("Marshal(c1) = %#q, want %#q", got, want)
251	}
252
253	var ct CText
254	want = `"\"\u003c\u0026\u003e\""`
255	b, err = Marshal(ct)
256	if err != nil {
257		t.Fatalf("Marshal(ct): %v", err)
258	}
259	if got := string(b); got != want {
260		t.Errorf("Marshal(ct) = %#q, want %#q", got, want)
261	}
262}
263
264type IntType int
265
266type MyStruct struct {
267	IntType
268}
269
270func TestAnonymousNonstruct(t *testing.T) {
271	testtype.SkipUnlessTestType(t, testtype.UnitTestType)
272	var i IntType = 11
273	a := MyStruct{i}
274	const want = `{"IntType":11}`
275
276	b, err := Marshal(a)
277	if err != nil {
278		t.Fatalf("Marshal: %v", err)
279	}
280	if got := string(b); got != want {
281		t.Errorf("got %q, want %q", got, want)
282	}
283}
284
285type BugA struct {
286	S string
287}
288
289type BugB struct {
290	BugA
291	S string
292}
293
294type BugC struct {
295	S string
296}
297
298// Legal Go: We never use the repeated embedded field (S).
299type BugX struct {
300	A int
301	BugA
302	BugB
303}
304
305// Issue 5245.
306func TestEmbeddedBug(t *testing.T) {
307	testtype.SkipUnlessTestType(t, testtype.UnitTestType)
308	v := BugB{
309		BugA{"A"},
310		"B",
311	}
312	b, err := Marshal(v)
313	if err != nil {
314		t.Fatal("Marshal:", err)
315	}
316	want := `{"S":"B"}`
317	got := string(b)
318	if got != want {
319		t.Fatalf("Marshal: got %s want %s", got, want)
320	}
321	// Now check that the duplicate field, S, does not appear.
322	x := BugX{
323		A: 23,
324	}
325	b, err = Marshal(x)
326	if err != nil {
327		t.Fatal("Marshal:", err)
328	}
329	want = `{"A":23}`
330	got = string(b)
331	if got != want {
332		t.Fatalf("Marshal: got %s want %s", got, want)
333	}
334}
335
336type BugD struct { // Same as BugA after tagging.
337	XXX string `json:"S"`
338}
339
340// BugD's tagged S field should dominate BugA's.
341type BugY struct {
342	BugA
343	BugD
344}
345
346// Test that a field with a tag dominates untagged fields.
347func TestTaggedFieldDominates(t *testing.T) {
348	testtype.SkipUnlessTestType(t, testtype.UnitTestType)
349	v := BugY{
350		BugA{"BugA"},
351		BugD{"BugD"},
352	}
353	b, err := Marshal(v)
354	if err != nil {
355		t.Fatal("Marshal:", err)
356	}
357	want := `{"S":"BugD"}`
358	got := string(b)
359	if got != want {
360		t.Fatalf("Marshal: got %s want %s", got, want)
361	}
362}
363
364// There are no tags here, so S should not appear.
365type BugZ struct {
366	BugA
367	BugC
368	BugY // Contains a tagged S field through BugD; should not dominate.
369}
370
371func TestDuplicatedFieldDisappears(t *testing.T) {
372	testtype.SkipUnlessTestType(t, testtype.UnitTestType)
373	v := BugZ{
374		BugA{"BugA"},
375		BugC{"BugC"},
376		BugY{
377			BugA{"nested BugA"},
378			BugD{"nested BugD"},
379		},
380	}
381	b, err := Marshal(v)
382	if err != nil {
383		t.Fatal("Marshal:", err)
384	}
385	want := `{}`
386	got := string(b)
387	if got != want {
388		t.Fatalf("Marshal: got %s want %s", got, want)
389	}
390}
391
392func TestStringBytes(t *testing.T) {
393	testtype.SkipUnlessTestType(t, testtype.UnitTestType)
394	// Test that encodeState.stringBytes and encodeState.string use the same encoding.
395	es := &encodeState{}
396	var r []rune
397	for i := '\u0000'; i <= unicode.MaxRune; i++ {
398		r = append(r, i)
399	}
400	s := string(r) + "\xff\xff\xffhello" // some invalid UTF-8 too
401	_, err := es.string(s)
402	if err != nil {
403		t.Fatal(err)
404	}
405
406	esBytes := &encodeState{}
407	_, err = esBytes.stringBytes([]byte(s))
408	if err != nil {
409		t.Fatal(err)
410	}
411
412	enc := es.Buffer.String()
413	encBytes := esBytes.Buffer.String()
414	if enc != encBytes {
415		i := 0
416		for i < len(enc) && i < len(encBytes) && enc[i] == encBytes[i] {
417			i++
418		}
419		enc = enc[i:]
420		encBytes = encBytes[i:]
421		i = 0
422		for i < len(enc) && i < len(encBytes) && enc[len(enc)-i-1] == encBytes[len(encBytes)-i-1] {
423			i++
424		}
425		enc = enc[:len(enc)-i]
426		encBytes = encBytes[:len(encBytes)-i]
427
428		if len(enc) > 20 {
429			enc = enc[:20] + "..."
430		}
431		if len(encBytes) > 20 {
432			encBytes = encBytes[:20] + "..."
433		}
434
435		t.Errorf("encodings differ at %#q vs %#q", enc, encBytes)
436	}
437}
438
439func TestIssue6458(t *testing.T) {
440	testtype.SkipUnlessTestType(t, testtype.UnitTestType)
441	type Foo struct {
442		M RawMessage
443	}
444	x := Foo{RawMessage(`"foo"`)}
445
446	b, err := Marshal(&x)
447	if err != nil {
448		t.Fatal(err)
449	}
450	if want := `{"M":"foo"}`; string(b) != want {
451		t.Errorf("Marshal(&x) = %#q; want %#q", b, want)
452	}
453
454	b, err = Marshal(x)
455	if err != nil {
456		t.Fatal(err)
457	}
458
459	if want := `{"M":"ImZvbyI="}`; string(b) != want {
460		t.Errorf("Marshal(x) = %#q; want %#q", b, want)
461	}
462}
463
464func TestHTMLEscape(t *testing.T) {
465	testtype.SkipUnlessTestType(t, testtype.UnitTestType)
466	var b, want bytes.Buffer
467	m := `{"M":"<html>foo &` + "\xe2\x80\xa8 \xe2\x80\xa9" + `</html>"}`
468	want.Write([]byte(`{"M":"\u003chtml\u003efoo \u0026\u2028 \u2029\u003c/html\u003e"}`))
469	HTMLEscape(&b, []byte(m))
470	if !bytes.Equal(b.Bytes(), want.Bytes()) {
471		t.Errorf("HTMLEscape(&b, []byte(m)) = %s; want %s", b.Bytes(), want.Bytes())
472	}
473}
474