github.com/segmentio/encoding@v0.4.0/json/fuzz/fuzz.go (about)

     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  
     6  package fuzz
     7  
     8  import (
     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  
    18  func fixS(v interface{}) {
    19  	if s, ok := v.(*S); ok {
    20  		if len(s.P) == 0 {
    21  			s.P = []byte(`""`)
    22  		}
    23  	}
    24  }
    25  
    26  func 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  
    98  type 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  
   120  type S1 struct {
   121  	A int
   122  	B string
   123  }
   124  
   125  type Marshaller struct {
   126  	v string
   127  }
   128  
   129  func (m *Marshaller) MarshalJSON() ([]byte, error) {
   130  	return json.Marshal(m.v)
   131  }
   132  
   133  func (m *Marshaller) UnmarshalJSON(data []byte) error {
   134  	return json.Unmarshal(data, &m.v)
   135  }