internal/fuzz: add fuzzers for prototext and protojson packages

Change-Id: Iee065070e6a983c303a3551a67fc32f0e94b649e
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/212219
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
diff --git a/internal/cmd/generate-corpus/main.go b/internal/cmd/generate-corpus/main.go
index f566166..8f77dea 100644
--- a/internal/cmd/generate-corpus/main.go
+++ b/internal/cmd/generate-corpus/main.go
@@ -15,6 +15,8 @@
 	"io/ioutil"
 	"log"
 
+	"google.golang.org/protobuf/encoding/protojson"
+	"google.golang.org/protobuf/encoding/prototext"
 	"google.golang.org/protobuf/proto"
 
 	fuzzpb "google.golang.org/protobuf/internal/testprotos/fuzz"
@@ -115,5 +117,21 @@
 		if err := ioutil.WriteFile(fmt.Sprintf("internal/fuzz/wirefuzz/corpus/%x", sha1.Sum(wire)), wire, 0777); err != nil {
 			log.Fatal(err)
 		}
+
+		text, err := prototext.Marshal(m)
+		if err != nil {
+			log.Fatal(err)
+		}
+		if err := ioutil.WriteFile(fmt.Sprintf("internal/fuzz/textfuzz/corpus/%x", sha1.Sum(text)), text, 0777); err != nil {
+			log.Fatal(err)
+		}
+
+		json, err := protojson.Marshal(m)
+		if err != nil {
+			log.Fatal(err)
+		}
+		if err := ioutil.WriteFile(fmt.Sprintf("internal/fuzz/jsonfuzz/corpus/%x", sha1.Sum(json)), json, 0777); err != nil {
+			log.Fatal(err)
+		}
 	}
 }
diff --git a/internal/fuzz/jsonfuzz/corpus/e619335648415cae976b3200d5a291e8da4b4866 b/internal/fuzz/jsonfuzz/corpus/e619335648415cae976b3200d5a291e8da4b4866
new file mode 100755
index 0000000..f8b6e00
--- /dev/null
+++ b/internal/fuzz/jsonfuzz/corpus/e619335648415cae976b3200d5a291e8da4b4866
@@ -0,0 +1 @@
+{"testAllTypes":{"optionalInt32":1001, "optionalInt64":"1002", "optionalUint32":1003, "optionalUint64":"1004", "optionalSint32":1005, "optionalSint64":"1006", "optionalFixed32":1007, "optionalFixed64":"1008", "optionalSfixed32":1009, "optionalSfixed64":"1010", "optionalFloat":1011.5, "optionalDouble":1012.5, "optionalBool":true, "optionalString":"string", "optionalBytes":"Ynl0ZXM=", "optionalgroup":{"a":1017}, "optionalNestedMessage":{"a":42, "corecursive":{"optionalInt32":43}}, "optionalNestedEnum":"BAR", "repeatedInt32":[1001, 2001], "repeatedInt64":["1002", "2002"], "repeatedUint32":[1003, 2003], "repeatedUint64":["1004", "2004"], "repeatedSint32":[1005, 2005], "repeatedSint64":["1006", "2006"], "repeatedFixed32":[1007, 2007], "repeatedFixed64":["1008", "2008"], "repeatedSfixed32":[1009, 2009], "repeatedSfixed64":["1010", "2010"], "repeatedFloat":[1011.5, 2011.5], "repeatedDouble":[1012.5, 2012.5], "repeatedBool":[true, false], "repeatedString":["foo", "bar"], "repeatedBytes":["Rk9P", "QkFS"], "repeatedgroup":[{"a":1017}, {}, {"a":2017}], "repeatedNestedMessage":[{"a":1}, {}, {"a":2}], "repeatedNestedEnum":["FOO", "BAR"], "mapInt32Int32":{"1056":1156, "2056":2156}, "mapInt64Int64":{"1057":"1157", "2057":"2157"}, "mapUint32Uint32":{"1058":1158, "2058":2158}, "mapUint64Uint64":{"1059":"1159", "2059":"2159"}, "mapSint32Sint32":{"1060":1160, "2060":2160}, "mapSint64Sint64":{"1061":"1161", "2061":"2161"}, "mapFixed32Fixed32":{"1062":1162, "2062":2162}, "mapFixed64Fixed64":{"1063":"1163", "2063":"2163"}, "mapSfixed32Sfixed32":{"1064":1164, "2064":2164}, "mapSfixed64Sfixed64":{"1065":"1165", "2065":"2165"}, "mapInt32Float":{"1066":1166.5, "2066":2166.5}, "mapInt32Double":{"1067":1167.5, "2067":2167.5}, "mapBoolBool":{"false":true, "true":false}, "mapStringString":{"69.1.key":"69.1.val", "69.2.key":"69.2.val"}, "mapStringBytes":{"70.1.key":"NzAuMS52YWw=", "70.2.key":"NzAuMi52YWw="}, "mapStringNestedMessage":{"71.1.key":{"a":1171}, "71.2.key":{"a":2171}}, "mapStringNestedEnum":{"73.1.key":"FOO", "73.2.key":"BAR"}, "oneofUint32":1111}}
\ No newline at end of file
diff --git a/internal/fuzz/jsonfuzz/fuzz.go b/internal/fuzz/jsonfuzz/fuzz.go
new file mode 100644
index 0000000..969ad6d
--- /dev/null
+++ b/internal/fuzz/jsonfuzz/fuzz.go
@@ -0,0 +1,39 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package textfuzz includes a fuzzer for the text marshaler and unmarshaler.
+package textfuzz
+
+import (
+	"google.golang.org/protobuf/encoding/protojson"
+	"google.golang.org/protobuf/proto"
+
+	fuzzpb "google.golang.org/protobuf/internal/testprotos/fuzz"
+)
+
+// Fuzz is a fuzzer for proto.Marshal and proto.Unmarshal.
+func Fuzz(data []byte) (score int) {
+	m1 := &fuzzpb.Fuzz{}
+	if err := (protojson.UnmarshalOptions{
+		AllowPartial: true,
+	}).Unmarshal(data, m1); err != nil {
+		return 0
+	}
+	data1, err := protojson.MarshalOptions{
+		AllowPartial: true,
+	}.Marshal(m1)
+	if err != nil {
+		panic(err)
+	}
+	m2 := &fuzzpb.Fuzz{}
+	if err := (protojson.UnmarshalOptions{
+		AllowPartial: true,
+	}).Unmarshal(data1, m2); err != nil {
+		return 0
+	}
+	if !proto.Equal(m1, m2) {
+		panic("not equal")
+	}
+	return 1
+}
diff --git a/internal/fuzz/jsonfuzz/fuzz_test.go b/internal/fuzz/jsonfuzz/fuzz_test.go
new file mode 100644
index 0000000..a0e9d0c
--- /dev/null
+++ b/internal/fuzz/jsonfuzz/fuzz_test.go
@@ -0,0 +1,34 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package textfuzz
+
+import (
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"testing"
+)
+
+func Test(t *testing.T) {
+	dir, err := os.Open("corpus")
+	if err != nil {
+		t.Fatal(err)
+	}
+	infos, err := dir.Readdir(0)
+	if err != nil {
+		t.Fatal(err)
+
+	}
+	for _, info := range infos {
+		name := info.Name()
+		t.Run(name, func(t *testing.T) {
+			b, err := ioutil.ReadFile(filepath.Join("corpus", name))
+			if err != nil {
+				t.Fatal(err)
+			}
+			Fuzz(b)
+		})
+	}
+}
diff --git a/internal/fuzz/textfuzz/corpus/a950e4f0890f34717c5c9beffe1bd0cee33e5a2b b/internal/fuzz/textfuzz/corpus/a950e4f0890f34717c5c9beffe1bd0cee33e5a2b
new file mode 100755
index 0000000..84107dd
--- /dev/null
+++ b/internal/fuzz/textfuzz/corpus/a950e4f0890f34717c5c9beffe1bd0cee33e5a2b
@@ -0,0 +1 @@
+test_all_types:{optional_int32:1001  optional_int64:1002  optional_uint32:1003  optional_uint64:1004  optional_sint32:1005  optional_sint64:1006  optional_fixed32:1007  optional_fixed64:1008  optional_sfixed32:1009  optional_sfixed64:1010  optional_float:1011.5  optional_double:1012.5  optional_bool:true  optional_string:"string"  optional_bytes:"bytes"  OptionalGroup:{a:1017}  optional_nested_message:{a:42  corecursive:{optional_int32:43}}  optional_nested_enum:BAR  repeated_int32:1001  repeated_int32:2001  repeated_int64:1002  repeated_int64:2002  repeated_uint32:1003  repeated_uint32:2003  repeated_uint64:1004  repeated_uint64:2004  repeated_sint32:1005  repeated_sint32:2005  repeated_sint64:1006  repeated_sint64:2006  repeated_fixed32:1007  repeated_fixed32:2007  repeated_fixed64:1008  repeated_fixed64:2008  repeated_sfixed32:1009  repeated_sfixed32:2009  repeated_sfixed64:1010  repeated_sfixed64:2010  repeated_float:1011.5  repeated_float:2011.5  repeated_double:1012.5  repeated_double:2012.5  repeated_bool:true  repeated_bool:false  repeated_string:"foo"  repeated_string:"bar"  repeated_bytes:"FOO"  repeated_bytes:"BAR"  RepeatedGroup:{a:1017}  RepeatedGroup:{}  RepeatedGroup:{a:2017}  repeated_nested_message:{a:1}  repeated_nested_message:{}  repeated_nested_message:{a:2}  repeated_nested_enum:FOO  repeated_nested_enum:BAR  map_int32_int32:{key:1056  value:1156}  map_int32_int32:{key:2056  value:2156}  map_int64_int64:{key:1057  value:1157}  map_int64_int64:{key:2057  value:2157}  map_uint32_uint32:{key:1058  value:1158}  map_uint32_uint32:{key:2058  value:2158}  map_uint64_uint64:{key:1059  value:1159}  map_uint64_uint64:{key:2059  value:2159}  map_sint32_sint32:{key:1060  value:1160}  map_sint32_sint32:{key:2060  value:2160}  map_sint64_sint64:{key:1061  value:1161}  map_sint64_sint64:{key:2061  value:2161}  map_fixed32_fixed32:{key:1062  value:1162}  map_fixed32_fixed32:{key:2062  value:2162}  map_fixed64_fixed64:{key:1063  value:1163}  map_fixed64_fixed64:{key:2063  value:2163}  map_sfixed32_sfixed32:{key:1064  value:1164}  map_sfixed32_sfixed32:{key:2064  value:2164}  map_sfixed64_sfixed64:{key:1065  value:1165}  map_sfixed64_sfixed64:{key:2065  value:2165}  map_int32_float:{key:1066  value:1166.5}  map_int32_float:{key:2066  value:2166.5}  map_int32_double:{key:1067  value:1167.5}  map_int32_double:{key:2067  value:2167.5}  map_bool_bool:{key:false  value:true}  map_bool_bool:{key:true  value:false}  map_string_string:{key:"69.1.key"  value:"69.1.val"}  map_string_string:{key:"69.2.key"  value:"69.2.val"}  map_string_bytes:{key:"70.1.key"  value:"70.1.val"}  map_string_bytes:{key:"70.2.key"  value:"70.2.val"}  map_string_nested_message:{key:"71.1.key"  value:{a:1171}}  map_string_nested_message:{key:"71.2.key"  value:{a:2171}}  map_string_nested_enum:{key:"73.1.key"  value:FOO}  map_string_nested_enum:{key:"73.2.key"  value:BAR}  oneof_uint32:1111}
\ No newline at end of file
diff --git a/internal/fuzz/textfuzz/fuzz.go b/internal/fuzz/textfuzz/fuzz.go
new file mode 100644
index 0000000..bd89da0
--- /dev/null
+++ b/internal/fuzz/textfuzz/fuzz.go
@@ -0,0 +1,39 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package textfuzz includes a fuzzer for the text marshaler and unmarshaler.
+package textfuzz
+
+import (
+	"google.golang.org/protobuf/encoding/prototext"
+	"google.golang.org/protobuf/proto"
+
+	fuzzpb "google.golang.org/protobuf/internal/testprotos/fuzz"
+)
+
+// Fuzz is a fuzzer for proto.Marshal and proto.Unmarshal.
+func Fuzz(data []byte) (score int) {
+	m1 := &fuzzpb.Fuzz{}
+	if err := (prototext.UnmarshalOptions{
+		AllowPartial: true,
+	}).Unmarshal(data, m1); err != nil {
+		return 0
+	}
+	data1, err := prototext.MarshalOptions{
+		AllowPartial: true,
+	}.Marshal(m1)
+	if err != nil {
+		panic(err)
+	}
+	m2 := &fuzzpb.Fuzz{}
+	if err := (prototext.UnmarshalOptions{
+		AllowPartial: true,
+	}).Unmarshal(data1, m2); err != nil {
+		return 0
+	}
+	if !proto.Equal(m1, m2) {
+		panic("not equal")
+	}
+	return 1
+}
diff --git a/internal/fuzz/textfuzz/fuzz_test.go b/internal/fuzz/textfuzz/fuzz_test.go
new file mode 100644
index 0000000..a0e9d0c
--- /dev/null
+++ b/internal/fuzz/textfuzz/fuzz_test.go
@@ -0,0 +1,34 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package textfuzz
+
+import (
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"testing"
+)
+
+func Test(t *testing.T) {
+	dir, err := os.Open("corpus")
+	if err != nil {
+		t.Fatal(err)
+	}
+	infos, err := dir.Readdir(0)
+	if err != nil {
+		t.Fatal(err)
+
+	}
+	for _, info := range infos {
+		name := info.Name()
+		t.Run(name, func(t *testing.T) {
+			b, err := ioutil.ReadFile(filepath.Join("corpus", name))
+			if err != nil {
+				t.Fatal(err)
+			}
+			Fuzz(b)
+		})
+	}
+}