1// +build ignore
2
3// Copyright 2015 go-fuzz project authors. All rights reserved.
4// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
5
6package fuzz
7
8import (
9	"bytes"
10	encodingJSON "encoding/json"
11	"fmt"
12	"reflect"
13
14	"github.com/dvyukov/go-fuzz-corpus/fuzz"
15	"github.com/segmentio/encoding/json"
16)
17
18func fixS(v interface{}) {
19	if s, ok := v.(*S); ok {
20		if len(s.P) == 0 {
21			s.P = []byte(`""`)
22		}
23	}
24}
25
26func Fuzz(data []byte) int {
27	score := 0
28	for _, ctor := range []func() interface{}{
29		func() interface{} { return nil },
30		func() interface{} { return new([]interface{}) },
31		func() interface{} { m := map[string]string{}; return &m },
32		func() interface{} { m := map[string]interface{}{}; return &m },
33		func() interface{} { return new(S) },
34	} {
35		// Note: we modified the test to verify that we behavior like the
36		// standard encoding/json package, whether it's right or wrong.
37		v1 := ctor()
38		v2 := ctor()
39
40		err1 := encodingJSON.Unmarshal(data, v1)
41		err2 := json.Unmarshal(data, v2)
42
43		if err1 != nil {
44			if err2 != nil {
45				// both implementations report an error
46				if reflect.TypeOf(err1) != reflect.TypeOf(err2) {
47					fmt.Printf("input: %s\n", string(data))
48					fmt.Printf("encoding/json.Unmarshal(%T): %T: %s\n", v1, err1, err1)
49					fmt.Printf("segmentio/encoding/json.Unmarshal(%T): %T: %s\n", v2, err2, err2)
50					panic("error types mismatch")
51				}
52				continue
53			} else {
54				fmt.Printf("input: %s\n", string(data))
55				fmt.Printf("encoding/json.Unmarshal(%T): %T: %s\n", v1, err1, err1)
56				fmt.Printf("segmentio/encoding/json.Unmarshal(%T): <nil>\n")
57				panic("error values mismatch")
58			}
59		} else {
60			if err2 != nil {
61				fmt.Printf("input: %s\n", string(data))
62				fmt.Printf("encoding/json.Unmarshal(%T): <nil>\n")
63				fmt.Printf("segmentio/encoding/json.Unmarshal(%T): %T: %s\n", v2, err2, err2)
64				panic("error values mismatch")
65			} else {
66				// both implementations pass
67			}
68		}
69
70		score = 1
71		fixS(v1)
72		fixS(v2)
73		if !fuzz.DeepEqual(v1, v2) {
74			fmt.Printf("input: %s\n", string(data))
75			fmt.Printf("encoding/json:      %#v\n", v1)
76			fmt.Printf("segmentio/encoding: %#v\n", v2)
77			panic("not equal")
78		}
79
80		data1, err := encodingJSON.Marshal(v1)
81		if err != nil {
82			panic(err)
83		}
84		data2, err := json.Marshal(v2)
85		if err != nil {
86			panic(err)
87		}
88		if !bytes.Equal(data1, data2) {
89			fmt.Printf("input: %s\n", string(data))
90			fmt.Printf("encoding/json:      %s\n", string(data1))
91			fmt.Printf("segmentio/encoding: %s\n", string(data2))
92			panic("not equal")
93		}
94	}
95	return score
96}
97
98type S struct {
99	A int    `json:",omitempty"`
100	B string `json:"B1,omitempty"`
101	C float64
102	D bool
103	E uint8
104	F []byte
105	G interface{}
106	H map[string]interface{}
107	I map[string]string
108	J []interface{}
109	K []string
110	L S1
111	M *S1
112	N *int
113	O **int
114	P json.RawMessage
115	Q Marshaller
116	R int `json:"-"`
117	S int `json:",string"`
118}
119
120type S1 struct {
121	A int
122	B string
123}
124
125type Marshaller struct {
126	v string
127}
128
129func (m *Marshaller) MarshalJSON() ([]byte, error) {
130	return json.Marshal(m.v)
131}
132
133func (m *Marshaller) UnmarshalJSON(data []byte) error {
134	return json.Unmarshal(data, &m.v)
135}
136