123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421 |
- // 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 protojson_test
- import (
- "math"
- "testing"
- "google.golang.org/protobuf/encoding/protojson"
- "google.golang.org/protobuf/internal/flags"
- "google.golang.org/protobuf/proto"
- preg "google.golang.org/protobuf/reflect/protoregistry"
- "google.golang.org/protobuf/encoding/testprotos/pb2"
- "google.golang.org/protobuf/encoding/testprotos/pb3"
- testpb "google.golang.org/protobuf/internal/testprotos/test"
- weakpb "google.golang.org/protobuf/internal/testprotos/test/weak1"
- "google.golang.org/protobuf/types/known/anypb"
- "google.golang.org/protobuf/types/known/durationpb"
- "google.golang.org/protobuf/types/known/emptypb"
- "google.golang.org/protobuf/types/known/fieldmaskpb"
- "google.golang.org/protobuf/types/known/structpb"
- "google.golang.org/protobuf/types/known/timestamppb"
- "google.golang.org/protobuf/types/known/wrapperspb"
- )
- func TestUnmarshal(t *testing.T) {
- tests := []struct {
- desc string
- umo protojson.UnmarshalOptions
- inputMessage proto.Message
- inputText string
- wantMessage proto.Message
- // TODO: verify expected error message substring.
- wantErr bool
- skip bool
- }{{
- desc: "proto2 empty message",
- inputMessage: &pb2.Scalars{},
- inputText: "{}",
- wantMessage: &pb2.Scalars{},
- }, {
- desc: "unexpected value instead of EOF",
- inputMessage: &pb2.Scalars{},
- inputText: "{} {}",
- wantErr: true,
- }, {
- desc: "proto2 optional scalars set to zero values",
- inputMessage: &pb2.Scalars{},
- inputText: `{
- "optBool": false,
- "optInt32": 0,
- "optInt64": 0,
- "optUint32": 0,
- "optUint64": 0,
- "optSint32": 0,
- "optSint64": 0,
- "optFixed32": 0,
- "optFixed64": 0,
- "optSfixed32": 0,
- "optSfixed64": 0,
- "optFloat": 0,
- "optDouble": 0,
- "optBytes": "",
- "optString": ""
- }`,
- wantMessage: &pb2.Scalars{
- OptBool: proto.Bool(false),
- OptInt32: proto.Int32(0),
- OptInt64: proto.Int64(0),
- OptUint32: proto.Uint32(0),
- OptUint64: proto.Uint64(0),
- OptSint32: proto.Int32(0),
- OptSint64: proto.Int64(0),
- OptFixed32: proto.Uint32(0),
- OptFixed64: proto.Uint64(0),
- OptSfixed32: proto.Int32(0),
- OptSfixed64: proto.Int64(0),
- OptFloat: proto.Float32(0),
- OptDouble: proto.Float64(0),
- OptBytes: []byte{},
- OptString: proto.String(""),
- },
- }, {
- desc: "proto3 scalars set to zero values",
- inputMessage: &pb3.Scalars{},
- inputText: `{
- "sBool": false,
- "sInt32": 0,
- "sInt64": 0,
- "sUint32": 0,
- "sUint64": 0,
- "sSint32": 0,
- "sSint64": 0,
- "sFixed32": 0,
- "sFixed64": 0,
- "sSfixed32": 0,
- "sSfixed64": 0,
- "sFloat": 0,
- "sDouble": 0,
- "sBytes": "",
- "sString": ""
- }`,
- wantMessage: &pb3.Scalars{},
- }, {
- desc: "proto2 optional scalars set to null",
- inputMessage: &pb2.Scalars{},
- inputText: `{
- "optBool": null,
- "optInt32": null,
- "optInt64": null,
- "optUint32": null,
- "optUint64": null,
- "optSint32": null,
- "optSint64": null,
- "optFixed32": null,
- "optFixed64": null,
- "optSfixed32": null,
- "optSfixed64": null,
- "optFloat": null,
- "optDouble": null,
- "optBytes": null,
- "optString": null
- }`,
- wantMessage: &pb2.Scalars{},
- }, {
- desc: "proto3 scalars set to null",
- inputMessage: &pb3.Scalars{},
- inputText: `{
- "sBool": null,
- "sInt32": null,
- "sInt64": null,
- "sUint32": null,
- "sUint64": null,
- "sSint32": null,
- "sSint64": null,
- "sFixed32": null,
- "sFixed64": null,
- "sSfixed32": null,
- "sSfixed64": null,
- "sFloat": null,
- "sDouble": null,
- "sBytes": null,
- "sString": null
- }`,
- wantMessage: &pb3.Scalars{},
- }, {
- desc: "boolean",
- inputMessage: &pb3.Scalars{},
- inputText: `{"sBool": true}`,
- wantMessage: &pb3.Scalars{
- SBool: true,
- },
- }, {
- desc: "not boolean",
- inputMessage: &pb3.Scalars{},
- inputText: `{"sBool": "true"}`,
- wantErr: true,
- }, {
- desc: "float and double",
- inputMessage: &pb3.Scalars{},
- inputText: `{
- "sFloat": 1.234,
- "sDouble": 5.678
- }`,
- wantMessage: &pb3.Scalars{
- SFloat: 1.234,
- SDouble: 5.678,
- },
- }, {
- desc: "float and double in string",
- inputMessage: &pb3.Scalars{},
- inputText: `{
- "sFloat": "1.234",
- "sDouble": "5.678"
- }`,
- wantMessage: &pb3.Scalars{
- SFloat: 1.234,
- SDouble: 5.678,
- },
- }, {
- desc: "float and double in E notation",
- inputMessage: &pb3.Scalars{},
- inputText: `{
- "sFloat": 12.34E-1,
- "sDouble": 5.678e4
- }`,
- wantMessage: &pb3.Scalars{
- SFloat: 1.234,
- SDouble: 56780,
- },
- }, {
- desc: "float and double in string E notation",
- inputMessage: &pb3.Scalars{},
- inputText: `{
- "sFloat": "12.34E-1",
- "sDouble": "5.678e4"
- }`,
- wantMessage: &pb3.Scalars{
- SFloat: 1.234,
- SDouble: 56780,
- },
- }, {
- desc: "float exceeds limit",
- inputMessage: &pb3.Scalars{},
- inputText: `{"sFloat": 3.4e39}`,
- wantErr: true,
- }, {
- desc: "float in string exceeds limit",
- inputMessage: &pb3.Scalars{},
- inputText: `{"sFloat": "-3.4e39"}`,
- wantErr: true,
- }, {
- desc: "double exceeds limit",
- inputMessage: &pb3.Scalars{},
- inputText: `{"sFloat": -1.79e+309}`,
- wantErr: true,
- }, {
- desc: "double in string exceeds limit",
- inputMessage: &pb3.Scalars{},
- inputText: `{"sFloat": "1.79e+309"}`,
- wantErr: true,
- }, {
- desc: "infinites",
- inputMessage: &pb3.Scalars{},
- inputText: `{"sFloat": "Infinity", "sDouble": "-Infinity"}`,
- wantMessage: &pb3.Scalars{
- SFloat: float32(math.Inf(+1)),
- SDouble: math.Inf(-1),
- },
- }, {
- desc: "float string with leading space",
- inputMessage: &pb3.Scalars{},
- inputText: `{"sFloat": " 1.234"}`,
- wantErr: true,
- }, {
- desc: "double string with trailing space",
- inputMessage: &pb3.Scalars{},
- inputText: `{"sDouble": "5.678 "}`,
- wantErr: true,
- }, {
- desc: "not float",
- inputMessage: &pb3.Scalars{},
- inputText: `{"sFloat": true}`,
- wantErr: true,
- }, {
- desc: "not double",
- inputMessage: &pb3.Scalars{},
- inputText: `{"sDouble": "not a number"}`,
- wantErr: true,
- }, {
- desc: "integers",
- inputMessage: &pb3.Scalars{},
- inputText: `{
- "sInt32": 1234,
- "sInt64": -1234,
- "sUint32": 1e2,
- "sUint64": 100E-2,
- "sSint32": 1.0,
- "sSint64": -1.0,
- "sFixed32": 1.234e+5,
- "sFixed64": 1200E-2,
- "sSfixed32": -1.234e05,
- "sSfixed64": -1200e-02
- }`,
- wantMessage: &pb3.Scalars{
- SInt32: 1234,
- SInt64: -1234,
- SUint32: 100,
- SUint64: 1,
- SSint32: 1,
- SSint64: -1,
- SFixed32: 123400,
- SFixed64: 12,
- SSfixed32: -123400,
- SSfixed64: -12,
- },
- }, {
- desc: "integers in string",
- inputMessage: &pb3.Scalars{},
- inputText: `{
- "sInt32": "1234",
- "sInt64": "-1234",
- "sUint32": "1e2",
- "sUint64": "100E-2",
- "sSint32": "1.0",
- "sSint64": "-1.0",
- "sFixed32": "1.234e+5",
- "sFixed64": "1200E-2",
- "sSfixed32": "-1.234e05",
- "sSfixed64": "-1200e-02"
- }`,
- wantMessage: &pb3.Scalars{
- SInt32: 1234,
- SInt64: -1234,
- SUint32: 100,
- SUint64: 1,
- SSint32: 1,
- SSint64: -1,
- SFixed32: 123400,
- SFixed64: 12,
- SSfixed32: -123400,
- SSfixed64: -12,
- },
- }, {
- desc: "integers in escaped string",
- inputMessage: &pb3.Scalars{},
- inputText: `{"sInt32": "\u0031\u0032"}`,
- wantMessage: &pb3.Scalars{
- SInt32: 12,
- },
- }, {
- desc: "integer string with leading space",
- inputMessage: &pb3.Scalars{},
- inputText: `{"sInt32": " 1234"}`,
- wantErr: true,
- }, {
- desc: "integer string with trailing space",
- inputMessage: &pb3.Scalars{},
- inputText: `{"sUint32": "1e2 "}`,
- wantErr: true,
- }, {
- desc: "number is not an integer",
- inputMessage: &pb3.Scalars{},
- inputText: `{"sInt32": 1.001}`,
- wantErr: true,
- }, {
- desc: "32-bit int exceeds limit",
- inputMessage: &pb3.Scalars{},
- inputText: `{"sInt32": 2e10}`,
- wantErr: true,
- }, {
- desc: "64-bit int exceeds limit",
- inputMessage: &pb3.Scalars{},
- inputText: `{"sSfixed64": -9e19}`,
- wantErr: true,
- }, {
- desc: "not integer",
- inputMessage: &pb3.Scalars{},
- inputText: `{"sInt32": "not a number"}`,
- wantErr: true,
- }, {
- desc: "not unsigned integer",
- inputMessage: &pb3.Scalars{},
- inputText: `{"sUint32": "not a number"}`,
- wantErr: true,
- }, {
- desc: "number is not an unsigned integer",
- inputMessage: &pb3.Scalars{},
- inputText: `{"sUint32": -1}`,
- wantErr: true,
- }, {
- desc: "string",
- inputMessage: &pb2.Scalars{},
- inputText: `{"optString": "谷歌"}`,
- wantMessage: &pb2.Scalars{
- OptString: proto.String("谷歌"),
- },
- }, {
- desc: "string with invalid UTF-8",
- inputMessage: &pb3.Scalars{},
- inputText: "{\"sString\": \"\xff\"}",
- wantErr: true,
- }, {
- desc: "not string",
- inputMessage: &pb2.Scalars{},
- inputText: `{"optString": 42}`,
- wantErr: true,
- }, {
- desc: "bytes",
- inputMessage: &pb3.Scalars{},
- inputText: `{"sBytes": "aGVsbG8gd29ybGQ"}`,
- wantMessage: &pb3.Scalars{
- SBytes: []byte("hello world"),
- },
- }, {
- desc: "bytes padded",
- inputMessage: &pb3.Scalars{},
- inputText: `{"sBytes": "aGVsbG8gd29ybGQ="}`,
- wantMessage: &pb3.Scalars{
- SBytes: []byte("hello world"),
- },
- }, {
- desc: "not bytes",
- inputMessage: &pb3.Scalars{},
- inputText: `{"sBytes": true}`,
- wantErr: true,
- }, {
- desc: "proto2 enum",
- inputMessage: &pb2.Enums{},
- inputText: `{
- "optEnum": "ONE",
- "optNestedEnum": "UNO"
- }`,
- wantMessage: &pb2.Enums{
- OptEnum: pb2.Enum_ONE.Enum(),
- OptNestedEnum: pb2.Enums_UNO.Enum(),
- },
- }, {
- desc: "proto3 enum",
- inputMessage: &pb3.Enums{},
- inputText: `{
- "sEnum": "ONE",
- "sNestedEnum": "DIEZ"
- }`,
- wantMessage: &pb3.Enums{
- SEnum: pb3.Enum_ONE,
- SNestedEnum: pb3.Enums_DIEZ,
- },
- }, {
- desc: "enum numeric value",
- inputMessage: &pb3.Enums{},
- inputText: `{
- "sEnum": 2,
- "sNestedEnum": 2
- }`,
- wantMessage: &pb3.Enums{
- SEnum: pb3.Enum_TWO,
- SNestedEnum: pb3.Enums_DOS,
- },
- }, {
- desc: "enum unnamed numeric value",
- inputMessage: &pb3.Enums{},
- inputText: `{
- "sEnum": 101,
- "sNestedEnum": -101
- }`,
- wantMessage: &pb3.Enums{
- SEnum: 101,
- SNestedEnum: -101,
- },
- }, {
- desc: "enum set to number string",
- inputMessage: &pb3.Enums{},
- inputText: `{
- "sEnum": "1"
- }`,
- wantErr: true,
- }, {
- desc: "enum set to invalid named",
- inputMessage: &pb3.Enums{},
- inputText: `{
- "sEnum": "UNNAMED"
- }`,
- wantErr: true,
- }, {
- desc: "enum set to not enum",
- inputMessage: &pb3.Enums{},
- inputText: `{
- "sEnum": true
- }`,
- wantErr: true,
- }, {
- desc: "enum set to JSON null",
- inputMessage: &pb3.Enums{},
- inputText: `{
- "sEnum": null
- }`,
- wantMessage: &pb3.Enums{},
- }, {
- desc: "proto name",
- inputMessage: &pb3.JSONNames{},
- inputText: `{
- "s_string": "proto name used"
- }`,
- wantMessage: &pb3.JSONNames{
- SString: "proto name used",
- },
- }, {
- desc: "proto group name",
- inputMessage: &pb2.Nests{},
- inputText: `{
- "OptGroup": {"optString": "hello"},
- "RptGroup": [{"rptString": ["goodbye"]}]
- }`,
- wantMessage: &pb2.Nests{
- Optgroup: &pb2.Nests_OptGroup{OptString: proto.String("hello")},
- Rptgroup: []*pb2.Nests_RptGroup{{RptString: []string{"goodbye"}}},
- },
- }, {
- desc: "json_name",
- inputMessage: &pb3.JSONNames{},
- inputText: `{
- "foo_bar": "json_name used"
- }`,
- wantMessage: &pb3.JSONNames{
- SString: "json_name used",
- },
- }, {
- desc: "camelCase name",
- inputMessage: &pb3.JSONNames{},
- inputText: `{
- "sString": "camelcase used"
- }`,
- wantErr: true,
- }, {
- desc: "proto name and json_name",
- inputMessage: &pb3.JSONNames{},
- inputText: `{
- "foo_bar": "json_name used",
- "s_string": "proto name used"
- }`,
- wantErr: true,
- }, {
- desc: "duplicate field names",
- inputMessage: &pb3.JSONNames{},
- inputText: `{
- "foo_bar": "one",
- "foo_bar": "two",
- }`,
- wantErr: true,
- }, {
- desc: "null message",
- inputMessage: &pb2.Nests{},
- inputText: "null",
- wantErr: true,
- }, {
- desc: "proto2 nested message not set",
- inputMessage: &pb2.Nests{},
- inputText: "{}",
- wantMessage: &pb2.Nests{},
- }, {
- desc: "proto2 nested message set to null",
- inputMessage: &pb2.Nests{},
- inputText: `{
- "optNested": null,
- "optgroup": null
- }`,
- wantMessage: &pb2.Nests{},
- }, {
- desc: "proto2 nested message set to empty",
- inputMessage: &pb2.Nests{},
- inputText: `{
- "optNested": {},
- "optgroup": {}
- }`,
- wantMessage: &pb2.Nests{
- OptNested: &pb2.Nested{},
- Optgroup: &pb2.Nests_OptGroup{},
- },
- }, {
- desc: "proto2 nested messages",
- inputMessage: &pb2.Nests{},
- inputText: `{
- "optNested": {
- "optString": "nested message",
- "optNested": {
- "optString": "another nested message"
- }
- }
- }`,
- wantMessage: &pb2.Nests{
- OptNested: &pb2.Nested{
- OptString: proto.String("nested message"),
- OptNested: &pb2.Nested{
- OptString: proto.String("another nested message"),
- },
- },
- },
- }, {
- desc: "proto2 groups",
- inputMessage: &pb2.Nests{},
- inputText: `{
- "optgroup": {
- "optString": "inside a group",
- "optNested": {
- "optString": "nested message inside a group"
- },
- "optnestedgroup": {
- "optFixed32": 47
- }
- }
- }`,
- wantMessage: &pb2.Nests{
- Optgroup: &pb2.Nests_OptGroup{
- OptString: proto.String("inside a group"),
- OptNested: &pb2.Nested{
- OptString: proto.String("nested message inside a group"),
- },
- Optnestedgroup: &pb2.Nests_OptGroup_OptNestedGroup{
- OptFixed32: proto.Uint32(47),
- },
- },
- },
- }, {
- desc: "proto3 nested message not set",
- inputMessage: &pb3.Nests{},
- inputText: "{}",
- wantMessage: &pb3.Nests{},
- }, {
- desc: "proto3 nested message set to null",
- inputMessage: &pb3.Nests{},
- inputText: `{"sNested": null}`,
- wantMessage: &pb3.Nests{},
- }, {
- desc: "proto3 nested message set to empty",
- inputMessage: &pb3.Nests{},
- inputText: `{"sNested": {}}`,
- wantMessage: &pb3.Nests{
- SNested: &pb3.Nested{},
- },
- }, {
- desc: "proto3 nested message",
- inputMessage: &pb3.Nests{},
- inputText: `{
- "sNested": {
- "sString": "nested message",
- "sNested": {
- "sString": "another nested message"
- }
- }
- }`,
- wantMessage: &pb3.Nests{
- SNested: &pb3.Nested{
- SString: "nested message",
- SNested: &pb3.Nested{
- SString: "another nested message",
- },
- },
- },
- }, {
- desc: "message set to non-message",
- inputMessage: &pb3.Nests{},
- inputText: `"not valid"`,
- wantErr: true,
- }, {
- desc: "nested message set to non-message",
- inputMessage: &pb3.Nests{},
- inputText: `{"sNested": true}`,
- wantErr: true,
- }, {
- desc: "oneof not set",
- inputMessage: &pb3.Oneofs{},
- inputText: "{}",
- wantMessage: &pb3.Oneofs{},
- }, {
- desc: "oneof set to empty string",
- inputMessage: &pb3.Oneofs{},
- inputText: `{"oneofString": ""}`,
- wantMessage: &pb3.Oneofs{
- Union: &pb3.Oneofs_OneofString{},
- },
- }, {
- desc: "oneof set to string",
- inputMessage: &pb3.Oneofs{},
- inputText: `{"oneofString": "hello"}`,
- wantMessage: &pb3.Oneofs{
- Union: &pb3.Oneofs_OneofString{
- OneofString: "hello",
- },
- },
- }, {
- desc: "oneof set to enum",
- inputMessage: &pb3.Oneofs{},
- inputText: `{"oneofEnum": "ZERO"}`,
- wantMessage: &pb3.Oneofs{
- Union: &pb3.Oneofs_OneofEnum{
- OneofEnum: pb3.Enum_ZERO,
- },
- },
- }, {
- desc: "oneof set to empty message",
- inputMessage: &pb3.Oneofs{},
- inputText: `{"oneofNested": {}}`,
- wantMessage: &pb3.Oneofs{
- Union: &pb3.Oneofs_OneofNested{
- OneofNested: &pb3.Nested{},
- },
- },
- }, {
- desc: "oneof set to message",
- inputMessage: &pb3.Oneofs{},
- inputText: `{
- "oneofNested": {
- "sString": "nested message"
- }
- }`,
- wantMessage: &pb3.Oneofs{
- Union: &pb3.Oneofs_OneofNested{
- OneofNested: &pb3.Nested{
- SString: "nested message",
- },
- },
- },
- }, {
- desc: "oneof set to more than one field",
- inputMessage: &pb3.Oneofs{},
- inputText: `{
- "oneofEnum": "ZERO",
- "oneofString": "hello"
- }`,
- wantErr: true,
- }, {
- desc: "oneof set to null and value",
- inputMessage: &pb3.Oneofs{},
- inputText: `{
- "oneofEnum": "ZERO",
- "oneofString": null
- }`,
- wantMessage: &pb3.Oneofs{
- Union: &pb3.Oneofs_OneofEnum{
- OneofEnum: pb3.Enum_ZERO,
- },
- },
- }, {
- desc: "repeated null fields",
- inputMessage: &pb2.Repeats{},
- inputText: `{
- "rptString": null,
- "rptInt32" : null,
- "rptFloat" : null,
- "rptBytes" : null
- }`,
- wantMessage: &pb2.Repeats{},
- }, {
- desc: "repeated scalars",
- inputMessage: &pb2.Repeats{},
- inputText: `{
- "rptString": ["hello", "world"],
- "rptInt32" : [-1, 0, 1],
- "rptBool" : [false, true]
- }`,
- wantMessage: &pb2.Repeats{
- RptString: []string{"hello", "world"},
- RptInt32: []int32{-1, 0, 1},
- RptBool: []bool{false, true},
- },
- }, {
- desc: "repeated enums",
- inputMessage: &pb2.Enums{},
- inputText: `{
- "rptEnum" : ["TEN", 1, 42],
- "rptNestedEnum": ["DOS", 2, -47]
- }`,
- wantMessage: &pb2.Enums{
- RptEnum: []pb2.Enum{pb2.Enum_TEN, pb2.Enum_ONE, 42},
- RptNestedEnum: []pb2.Enums_NestedEnum{pb2.Enums_DOS, pb2.Enums_DOS, -47},
- },
- }, {
- desc: "repeated messages",
- inputMessage: &pb2.Nests{},
- inputText: `{
- "rptNested": [
- {
- "optString": "repeat nested one"
- },
- {
- "optString": "repeat nested two",
- "optNested": {
- "optString": "inside repeat nested two"
- }
- },
- {}
- ]
- }`,
- wantMessage: &pb2.Nests{
- RptNested: []*pb2.Nested{
- {
- OptString: proto.String("repeat nested one"),
- },
- {
- OptString: proto.String("repeat nested two"),
- OptNested: &pb2.Nested{
- OptString: proto.String("inside repeat nested two"),
- },
- },
- {},
- },
- },
- }, {
- desc: "repeated groups",
- inputMessage: &pb2.Nests{},
- inputText: `{
- "rptgroup": [
- {
- "rptString": ["hello", "world"]
- },
- {}
- ]
- }
- `,
- wantMessage: &pb2.Nests{
- Rptgroup: []*pb2.Nests_RptGroup{
- {
- RptString: []string{"hello", "world"},
- },
- {},
- },
- },
- }, {
- desc: "repeated string contains invalid UTF8",
- inputMessage: &pb2.Repeats{},
- inputText: `{"rptString": ["` + "abc\xff" + `"]}`,
- wantErr: true,
- }, {
- desc: "repeated messages contain invalid UTF8",
- inputMessage: &pb2.Nests{},
- inputText: `{"rptNested": [{"optString": "` + "abc\xff" + `"}]}`,
- wantErr: true,
- }, {
- desc: "repeated scalars contain invalid type",
- inputMessage: &pb2.Repeats{},
- inputText: `{"rptString": ["hello", null, "world"]}`,
- wantErr: true,
- }, {
- desc: "repeated messages contain invalid type",
- inputMessage: &pb2.Nests{},
- inputText: `{"rptNested": [{}, null]}`,
- wantErr: true,
- }, {
- desc: "map fields 1",
- inputMessage: &pb3.Maps{},
- inputText: `{
- "int32ToStr": {
- "-101": "-101",
- "0" : "zero",
- "255" : "0xff"
- },
- "boolToUint32": {
- "false": 101,
- "true" : "42"
- }
- }`,
- wantMessage: &pb3.Maps{
- Int32ToStr: map[int32]string{
- -101: "-101",
- 0xff: "0xff",
- 0: "zero",
- },
- BoolToUint32: map[bool]uint32{
- true: 42,
- false: 101,
- },
- },
- }, {
- desc: "map fields 2",
- inputMessage: &pb3.Maps{},
- inputText: `{
- "uint64ToEnum": {
- "1" : "ONE",
- "2" : 2,
- "10": 101
- }
- }`,
- wantMessage: &pb3.Maps{
- Uint64ToEnum: map[uint64]pb3.Enum{
- 1: pb3.Enum_ONE,
- 2: pb3.Enum_TWO,
- 10: 101,
- },
- },
- }, {
- desc: "map fields 3",
- inputMessage: &pb3.Maps{},
- inputText: `{
- "strToNested": {
- "nested_one": {
- "sString": "nested in a map"
- },
- "nested_two": {}
- }
- }`,
- wantMessage: &pb3.Maps{
- StrToNested: map[string]*pb3.Nested{
- "nested_one": {
- SString: "nested in a map",
- },
- "nested_two": {},
- },
- },
- }, {
- desc: "map fields 4",
- inputMessage: &pb3.Maps{},
- inputText: `{
- "strToOneofs": {
- "nested": {
- "oneofNested": {
- "sString": "nested oneof in map field value"
- }
- },
- "string": {
- "oneofString": "hello"
- }
- }
- }`,
- wantMessage: &pb3.Maps{
- StrToOneofs: map[string]*pb3.Oneofs{
- "string": {
- Union: &pb3.Oneofs_OneofString{
- OneofString: "hello",
- },
- },
- "nested": {
- Union: &pb3.Oneofs_OneofNested{
- OneofNested: &pb3.Nested{
- SString: "nested oneof in map field value",
- },
- },
- },
- },
- },
- }, {
- desc: "map contains duplicate keys",
- inputMessage: &pb3.Maps{},
- inputText: `{
- "int32ToStr": {
- "0": "cero",
- "0": "zero"
- }
- }
- `,
- wantErr: true,
- }, {
- desc: "map key empty string",
- inputMessage: &pb3.Maps{},
- inputText: `{
- "strToNested": {
- "": {}
- }
- }`,
- wantMessage: &pb3.Maps{
- StrToNested: map[string]*pb3.Nested{
- "": {},
- },
- },
- }, {
- desc: "map contains invalid key 1",
- inputMessage: &pb3.Maps{},
- inputText: `{
- "int32ToStr": {
- "invalid": "cero"
- }`,
- wantErr: true,
- }, {
- desc: "map contains invalid key 2",
- inputMessage: &pb3.Maps{},
- inputText: `{
- "int32ToStr": {
- "1.02": "float"
- }`,
- wantErr: true,
- }, {
- desc: "map contains invalid key 3",
- inputMessage: &pb3.Maps{},
- inputText: `{
- "int32ToStr": {
- "2147483648": "exceeds 32-bit integer max limit"
- }`,
- wantErr: true,
- }, {
- desc: "map contains invalid key 4",
- inputMessage: &pb3.Maps{},
- inputText: `{
- "uint64ToEnum": {
- "-1": 0
- }
- }`,
- wantErr: true,
- }, {
- desc: "map contains invalid value",
- inputMessage: &pb3.Maps{},
- inputText: `{
- "int32ToStr": {
- "101": true
- }`,
- wantErr: true,
- }, {
- desc: "map contains null for scalar value",
- inputMessage: &pb3.Maps{},
- inputText: `{
- "int32ToStr": {
- "101": null
- }`,
- wantErr: true,
- }, {
- desc: "map contains null for message value",
- inputMessage: &pb3.Maps{},
- inputText: `{
- "strToNested": {
- "hello": null
- }
- }`,
- wantErr: true,
- }, {
- desc: "map contains contains message value with invalid UTF8",
- inputMessage: &pb3.Maps{},
- inputText: `{
- "strToNested": {
- "hello": {
- "sString": "` + "abc\xff" + `"
- }
- }
- }`,
- wantErr: true,
- }, {
- desc: "map key contains invalid UTF8",
- inputMessage: &pb3.Maps{},
- inputText: `{
- "strToNested": {
- "` + "abc\xff" + `": {}
- }
- }`,
- wantErr: true,
- }, {
- desc: "required fields not set",
- inputMessage: &pb2.Requireds{},
- wantErr: true,
- }, {
- desc: "required field set",
- inputMessage: &pb2.PartialRequired{},
- inputText: `{
- "reqString": "this is required"
- }`,
- wantMessage: &pb2.PartialRequired{
- ReqString: proto.String("this is required"),
- },
- }, {
- desc: "required fields partially set",
- inputMessage: &pb2.Requireds{},
- inputText: `{
- "reqBool": false,
- "reqSfixed64": 42,
- "reqString": "hello",
- "reqEnum": "ONE"
- }`,
- wantMessage: &pb2.Requireds{
- ReqBool: proto.Bool(false),
- ReqSfixed64: proto.Int64(42),
- ReqString: proto.String("hello"),
- ReqEnum: pb2.Enum_ONE.Enum(),
- },
- wantErr: true,
- }, {
- desc: "required fields partially set with AllowPartial",
- umo: protojson.UnmarshalOptions{AllowPartial: true},
- inputMessage: &pb2.Requireds{},
- inputText: `{
- "reqBool": false,
- "reqSfixed64": 42,
- "reqString": "hello",
- "reqEnum": "ONE"
- }`,
- wantMessage: &pb2.Requireds{
- ReqBool: proto.Bool(false),
- ReqSfixed64: proto.Int64(42),
- ReqString: proto.String("hello"),
- ReqEnum: pb2.Enum_ONE.Enum(),
- },
- }, {
- desc: "required fields all set",
- inputMessage: &pb2.Requireds{},
- inputText: `{
- "reqBool": false,
- "reqSfixed64": 42,
- "reqDouble": 1.23,
- "reqString": "hello",
- "reqEnum": "ONE",
- "reqNested": {}
- }`,
- wantMessage: &pb2.Requireds{
- ReqBool: proto.Bool(false),
- ReqSfixed64: proto.Int64(42),
- ReqDouble: proto.Float64(1.23),
- ReqString: proto.String("hello"),
- ReqEnum: pb2.Enum_ONE.Enum(),
- ReqNested: &pb2.Nested{},
- },
- }, {
- desc: "indirect required field",
- inputMessage: &pb2.IndirectRequired{},
- inputText: `{
- "optNested": {}
- }`,
- wantMessage: &pb2.IndirectRequired{
- OptNested: &pb2.NestedWithRequired{},
- },
- wantErr: true,
- }, {
- desc: "indirect required field with AllowPartial",
- umo: protojson.UnmarshalOptions{AllowPartial: true},
- inputMessage: &pb2.IndirectRequired{},
- inputText: `{
- "optNested": {}
- }`,
- wantMessage: &pb2.IndirectRequired{
- OptNested: &pb2.NestedWithRequired{},
- },
- }, {
- desc: "indirect required field in repeated",
- inputMessage: &pb2.IndirectRequired{},
- inputText: `{
- "rptNested": [
- {"reqString": "one"},
- {}
- ]
- }`,
- wantMessage: &pb2.IndirectRequired{
- RptNested: []*pb2.NestedWithRequired{
- {
- ReqString: proto.String("one"),
- },
- {},
- },
- },
- wantErr: true,
- }, {
- desc: "indirect required field in repeated with AllowPartial",
- umo: protojson.UnmarshalOptions{AllowPartial: true},
- inputMessage: &pb2.IndirectRequired{},
- inputText: `{
- "rptNested": [
- {"reqString": "one"},
- {}
- ]
- }`,
- wantMessage: &pb2.IndirectRequired{
- RptNested: []*pb2.NestedWithRequired{
- {
- ReqString: proto.String("one"),
- },
- {},
- },
- },
- }, {
- desc: "indirect required field in map",
- inputMessage: &pb2.IndirectRequired{},
- inputText: `{
- "strToNested": {
- "missing": {},
- "contains": {
- "reqString": "here"
- }
- }
- }`,
- wantMessage: &pb2.IndirectRequired{
- StrToNested: map[string]*pb2.NestedWithRequired{
- "missing": &pb2.NestedWithRequired{},
- "contains": &pb2.NestedWithRequired{
- ReqString: proto.String("here"),
- },
- },
- },
- wantErr: true,
- }, {
- desc: "indirect required field in map with AllowPartial",
- umo: protojson.UnmarshalOptions{AllowPartial: true},
- inputMessage: &pb2.IndirectRequired{},
- inputText: `{
- "strToNested": {
- "missing": {},
- "contains": {
- "reqString": "here"
- }
- }
- }`,
- wantMessage: &pb2.IndirectRequired{
- StrToNested: map[string]*pb2.NestedWithRequired{
- "missing": &pb2.NestedWithRequired{},
- "contains": &pb2.NestedWithRequired{
- ReqString: proto.String("here"),
- },
- },
- },
- }, {
- desc: "indirect required field in oneof",
- inputMessage: &pb2.IndirectRequired{},
- inputText: `{
- "oneofNested": {}
- }`,
- wantMessage: &pb2.IndirectRequired{
- Union: &pb2.IndirectRequired_OneofNested{
- OneofNested: &pb2.NestedWithRequired{},
- },
- },
- wantErr: true,
- }, {
- desc: "indirect required field in oneof with AllowPartial",
- umo: protojson.UnmarshalOptions{AllowPartial: true},
- inputMessage: &pb2.IndirectRequired{},
- inputText: `{
- "oneofNested": {}
- }`,
- wantMessage: &pb2.IndirectRequired{
- Union: &pb2.IndirectRequired_OneofNested{
- OneofNested: &pb2.NestedWithRequired{},
- },
- },
- }, {
- desc: "extensions of non-repeated fields",
- inputMessage: &pb2.Extensions{},
- inputText: `{
- "optString": "non-extension field",
- "optBool": true,
- "optInt32": 42,
- "[pb2.opt_ext_bool]": true,
- "[pb2.opt_ext_nested]": {
- "optString": "nested in an extension",
- "optNested": {
- "optString": "another nested in an extension"
- }
- },
- "[pb2.opt_ext_string]": "extension field",
- "[pb2.opt_ext_enum]": "TEN"
- }`,
- wantMessage: func() proto.Message {
- m := &pb2.Extensions{
- OptString: proto.String("non-extension field"),
- OptBool: proto.Bool(true),
- OptInt32: proto.Int32(42),
- }
- proto.SetExtension(m, pb2.E_OptExtBool, true)
- proto.SetExtension(m, pb2.E_OptExtString, "extension field")
- proto.SetExtension(m, pb2.E_OptExtEnum, pb2.Enum_TEN)
- proto.SetExtension(m, pb2.E_OptExtNested, &pb2.Nested{
- OptString: proto.String("nested in an extension"),
- OptNested: &pb2.Nested{
- OptString: proto.String("another nested in an extension"),
- },
- })
- return m
- }(),
- }, {
- desc: "extensions of repeated fields",
- inputMessage: &pb2.Extensions{},
- inputText: `{
- "[pb2.rpt_ext_enum]": ["TEN", 101, "ONE"],
- "[pb2.rpt_ext_fixed32]": [42, 47],
- "[pb2.rpt_ext_nested]": [
- {"optString": "one"},
- {"optString": "two"},
- {"optString": "three"}
- ]
- }`,
- wantMessage: func() proto.Message {
- m := &pb2.Extensions{}
- proto.SetExtension(m, pb2.E_RptExtEnum, []pb2.Enum{pb2.Enum_TEN, 101, pb2.Enum_ONE})
- proto.SetExtension(m, pb2.E_RptExtFixed32, []uint32{42, 47})
- proto.SetExtension(m, pb2.E_RptExtNested, []*pb2.Nested{
- &pb2.Nested{OptString: proto.String("one")},
- &pb2.Nested{OptString: proto.String("two")},
- &pb2.Nested{OptString: proto.String("three")},
- })
- return m
- }(),
- }, {
- desc: "extensions of non-repeated fields in another message",
- inputMessage: &pb2.Extensions{},
- inputText: `{
- "[pb2.ExtensionsContainer.opt_ext_bool]": true,
- "[pb2.ExtensionsContainer.opt_ext_enum]": "TEN",
- "[pb2.ExtensionsContainer.opt_ext_nested]": {
- "optString": "nested in an extension",
- "optNested": {
- "optString": "another nested in an extension"
- }
- },
- "[pb2.ExtensionsContainer.opt_ext_string]": "extension field"
- }`,
- wantMessage: func() proto.Message {
- m := &pb2.Extensions{}
- proto.SetExtension(m, pb2.E_ExtensionsContainer_OptExtBool, true)
- proto.SetExtension(m, pb2.E_ExtensionsContainer_OptExtString, "extension field")
- proto.SetExtension(m, pb2.E_ExtensionsContainer_OptExtEnum, pb2.Enum_TEN)
- proto.SetExtension(m, pb2.E_ExtensionsContainer_OptExtNested, &pb2.Nested{
- OptString: proto.String("nested in an extension"),
- OptNested: &pb2.Nested{
- OptString: proto.String("another nested in an extension"),
- },
- })
- return m
- }(),
- }, {
- desc: "extensions of repeated fields in another message",
- inputMessage: &pb2.Extensions{},
- inputText: `{
- "optString": "non-extension field",
- "optBool": true,
- "optInt32": 42,
- "[pb2.ExtensionsContainer.rpt_ext_nested]": [
- {"optString": "one"},
- {"optString": "two"},
- {"optString": "three"}
- ],
- "[pb2.ExtensionsContainer.rpt_ext_enum]": ["TEN", 101, "ONE"],
- "[pb2.ExtensionsContainer.rpt_ext_string]": ["hello", "world"]
- }`,
- wantMessage: func() proto.Message {
- m := &pb2.Extensions{
- OptString: proto.String("non-extension field"),
- OptBool: proto.Bool(true),
- OptInt32: proto.Int32(42),
- }
- proto.SetExtension(m, pb2.E_ExtensionsContainer_RptExtEnum, []pb2.Enum{pb2.Enum_TEN, 101, pb2.Enum_ONE})
- proto.SetExtension(m, pb2.E_ExtensionsContainer_RptExtString, []string{"hello", "world"})
- proto.SetExtension(m, pb2.E_ExtensionsContainer_RptExtNested, []*pb2.Nested{
- &pb2.Nested{OptString: proto.String("one")},
- &pb2.Nested{OptString: proto.String("two")},
- &pb2.Nested{OptString: proto.String("three")},
- })
- return m
- }(),
- }, {
- desc: "invalid extension field name",
- inputMessage: &pb2.Extensions{},
- inputText: `{ "[pb2.invalid_message_field]": true }`,
- wantErr: true,
- }, {
- desc: "extensions of repeated field contains null",
- inputMessage: &pb2.Extensions{},
- inputText: `{
- "[pb2.ExtensionsContainer.rpt_ext_nested]": [
- {"optString": "one"},
- null,
- {"optString": "three"}
- ],
- }`,
- wantErr: true,
- }, {
- desc: "MessageSet",
- inputMessage: &pb2.MessageSet{},
- inputText: `{
- "[pb2.MessageSetExtension]": {
- "optString": "a messageset extension"
- },
- "[pb2.MessageSetExtension.ext_nested]": {
- "optString": "just a regular extension"
- },
- "[pb2.MessageSetExtension.not_message_set_extension]": {
- "optString": "not a messageset extension"
- }
- }`,
- wantMessage: func() proto.Message {
- m := &pb2.MessageSet{}
- proto.SetExtension(m, pb2.E_MessageSetExtension_MessageSetExtension, &pb2.MessageSetExtension{
- OptString: proto.String("a messageset extension"),
- })
- proto.SetExtension(m, pb2.E_MessageSetExtension_NotMessageSetExtension, &pb2.MessageSetExtension{
- OptString: proto.String("not a messageset extension"),
- })
- proto.SetExtension(m, pb2.E_MessageSetExtension_ExtNested, &pb2.Nested{
- OptString: proto.String("just a regular extension"),
- })
- return m
- }(),
- skip: !flags.ProtoLegacy,
- }, {
- desc: "not real MessageSet 1",
- inputMessage: &pb2.FakeMessageSet{},
- inputText: `{
- "[pb2.FakeMessageSetExtension.message_set_extension]": {
- "optString": "not a messageset extension"
- }
- }`,
- wantMessage: func() proto.Message {
- m := &pb2.FakeMessageSet{}
- proto.SetExtension(m, pb2.E_FakeMessageSetExtension_MessageSetExtension, &pb2.FakeMessageSetExtension{
- OptString: proto.String("not a messageset extension"),
- })
- return m
- }(),
- skip: !flags.ProtoLegacy,
- }, {
- desc: "not real MessageSet 2",
- inputMessage: &pb2.FakeMessageSet{},
- inputText: `{
- "[pb2.FakeMessageSetExtension]": {
- "optString": "not a messageset extension"
- }
- }`,
- wantErr: true,
- skip: !flags.ProtoLegacy,
- }, {
- desc: "not real MessageSet 3",
- inputMessage: &pb2.MessageSet{},
- inputText: `{
- "[pb2.message_set_extension]": {
- "optString": "another not a messageset extension"
- }
- }`,
- wantMessage: func() proto.Message {
- m := &pb2.MessageSet{}
- proto.SetExtension(m, pb2.E_MessageSetExtension, &pb2.FakeMessageSetExtension{
- OptString: proto.String("another not a messageset extension"),
- })
- return m
- }(),
- skip: !flags.ProtoLegacy,
- }, {
- desc: "Empty",
- inputMessage: &emptypb.Empty{},
- inputText: `{}`,
- wantMessage: &emptypb.Empty{},
- }, {
- desc: "Empty contains unknown",
- inputMessage: &emptypb.Empty{},
- inputText: `{"unknown": null}`,
- wantErr: true,
- }, {
- desc: "BoolValue false",
- inputMessage: &wrapperspb.BoolValue{},
- inputText: `false`,
- wantMessage: &wrapperspb.BoolValue{},
- }, {
- desc: "BoolValue true",
- inputMessage: &wrapperspb.BoolValue{},
- inputText: `true`,
- wantMessage: &wrapperspb.BoolValue{Value: true},
- }, {
- desc: "BoolValue invalid value",
- inputMessage: &wrapperspb.BoolValue{},
- inputText: `{}`,
- wantErr: true,
- }, {
- desc: "Int32Value",
- inputMessage: &wrapperspb.Int32Value{},
- inputText: `42`,
- wantMessage: &wrapperspb.Int32Value{Value: 42},
- }, {
- desc: "Int32Value in JSON string",
- inputMessage: &wrapperspb.Int32Value{},
- inputText: `"1.23e3"`,
- wantMessage: &wrapperspb.Int32Value{Value: 1230},
- }, {
- desc: "Int64Value",
- inputMessage: &wrapperspb.Int64Value{},
- inputText: `"42"`,
- wantMessage: &wrapperspb.Int64Value{Value: 42},
- }, {
- desc: "UInt32Value",
- inputMessage: &wrapperspb.UInt32Value{},
- inputText: `42`,
- wantMessage: &wrapperspb.UInt32Value{Value: 42},
- }, {
- desc: "UInt64Value",
- inputMessage: &wrapperspb.UInt64Value{},
- inputText: `"42"`,
- wantMessage: &wrapperspb.UInt64Value{Value: 42},
- }, {
- desc: "FloatValue",
- inputMessage: &wrapperspb.FloatValue{},
- inputText: `1.02`,
- wantMessage: &wrapperspb.FloatValue{Value: 1.02},
- }, {
- desc: "FloatValue exceeds max limit",
- inputMessage: &wrapperspb.FloatValue{},
- inputText: `1.23+40`,
- wantErr: true,
- }, {
- desc: "FloatValue Infinity",
- inputMessage: &wrapperspb.FloatValue{},
- inputText: `"-Infinity"`,
- wantMessage: &wrapperspb.FloatValue{Value: float32(math.Inf(-1))},
- }, {
- desc: "DoubleValue",
- inputMessage: &wrapperspb.DoubleValue{},
- inputText: `1.02`,
- wantMessage: &wrapperspb.DoubleValue{Value: 1.02},
- }, {
- desc: "DoubleValue Infinity",
- inputMessage: &wrapperspb.DoubleValue{},
- inputText: `"Infinity"`,
- wantMessage: &wrapperspb.DoubleValue{Value: math.Inf(+1)},
- }, {
- desc: "StringValue empty",
- inputMessage: &wrapperspb.StringValue{},
- inputText: `""`,
- wantMessage: &wrapperspb.StringValue{},
- }, {
- desc: "StringValue",
- inputMessage: &wrapperspb.StringValue{},
- inputText: `"谷歌"`,
- wantMessage: &wrapperspb.StringValue{Value: "谷歌"},
- }, {
- desc: "StringValue with invalid UTF8 error",
- inputMessage: &wrapperspb.StringValue{},
- inputText: "\"abc\xff\"",
- wantErr: true,
- }, {
- desc: "StringValue field with invalid UTF8 error",
- inputMessage: &pb2.KnownTypes{},
- inputText: "{\n \"optString\": \"abc\xff\"\n}",
- wantErr: true,
- }, {
- desc: "NullValue field with JSON null",
- inputMessage: &pb2.KnownTypes{},
- inputText: `{
- "optNull": null
- }`,
- wantMessage: &pb2.KnownTypes{OptNull: new(structpb.NullValue)},
- }, {
- desc: "NullValue field with string",
- inputMessage: &pb2.KnownTypes{},
- inputText: `{
- "optNull": "NULL_VALUE"
- }`,
- wantMessage: &pb2.KnownTypes{OptNull: new(structpb.NullValue)},
- }, {
- desc: "BytesValue",
- inputMessage: &wrapperspb.BytesValue{},
- inputText: `"aGVsbG8="`,
- wantMessage: &wrapperspb.BytesValue{Value: []byte("hello")},
- }, {
- desc: "Value null",
- inputMessage: &structpb.Value{},
- inputText: `null`,
- wantMessage: &structpb.Value{Kind: &structpb.Value_NullValue{}},
- }, {
- desc: "Value field null",
- inputMessage: &pb2.KnownTypes{},
- inputText: `{
- "optValue": null
- }`,
- wantMessage: &pb2.KnownTypes{
- OptValue: &structpb.Value{Kind: &structpb.Value_NullValue{}},
- },
- }, {
- desc: "Value bool",
- inputMessage: &structpb.Value{},
- inputText: `false`,
- wantMessage: &structpb.Value{Kind: &structpb.Value_BoolValue{}},
- }, {
- desc: "Value field bool",
- inputMessage: &pb2.KnownTypes{},
- inputText: `{
- "optValue": true
- }`,
- wantMessage: &pb2.KnownTypes{
- OptValue: &structpb.Value{Kind: &structpb.Value_BoolValue{true}},
- },
- }, {
- desc: "Value number",
- inputMessage: &structpb.Value{},
- inputText: `1.02`,
- wantMessage: &structpb.Value{Kind: &structpb.Value_NumberValue{1.02}},
- }, {
- desc: "Value field number",
- inputMessage: &pb2.KnownTypes{},
- inputText: `{
- "optValue": 1.02
- }`,
- wantMessage: &pb2.KnownTypes{
- OptValue: &structpb.Value{Kind: &structpb.Value_NumberValue{1.02}},
- },
- }, {
- desc: "Value string",
- inputMessage: &structpb.Value{},
- inputText: `"hello"`,
- wantMessage: &structpb.Value{Kind: &structpb.Value_StringValue{"hello"}},
- }, {
- desc: "Value string with invalid UTF8",
- inputMessage: &structpb.Value{},
- inputText: "\"\xff\"",
- wantErr: true,
- }, {
- desc: "Value field string",
- inputMessage: &pb2.KnownTypes{},
- inputText: `{
- "optValue": "NaN"
- }`,
- wantMessage: &pb2.KnownTypes{
- OptValue: &structpb.Value{Kind: &structpb.Value_StringValue{"NaN"}},
- },
- }, {
- desc: "Value field string with invalid UTF8",
- inputMessage: &pb2.KnownTypes{},
- inputText: `{
- "optValue": "` + "\xff" + `"
- }`,
- wantErr: true,
- }, {
- desc: "Value empty struct",
- inputMessage: &structpb.Value{},
- inputText: `{}`,
- wantMessage: &structpb.Value{
- Kind: &structpb.Value_StructValue{
- &structpb.Struct{Fields: map[string]*structpb.Value{}},
- },
- },
- }, {
- desc: "Value struct",
- inputMessage: &structpb.Value{},
- inputText: `{
- "string": "hello",
- "number": 123,
- "null": null,
- "bool": false,
- "struct": {
- "string": "world"
- },
- "list": []
- }`,
- wantMessage: &structpb.Value{
- Kind: &structpb.Value_StructValue{
- &structpb.Struct{
- Fields: map[string]*structpb.Value{
- "string": {Kind: &structpb.Value_StringValue{"hello"}},
- "number": {Kind: &structpb.Value_NumberValue{123}},
- "null": {Kind: &structpb.Value_NullValue{}},
- "bool": {Kind: &structpb.Value_BoolValue{false}},
- "struct": {
- Kind: &structpb.Value_StructValue{
- &structpb.Struct{
- Fields: map[string]*structpb.Value{
- "string": {Kind: &structpb.Value_StringValue{"world"}},
- },
- },
- },
- },
- "list": {
- Kind: &structpb.Value_ListValue{&structpb.ListValue{}},
- },
- },
- },
- },
- },
- }, {
- desc: "Value struct with invalid UTF8 string",
- inputMessage: &structpb.Value{},
- inputText: "{\"string\": \"abc\xff\"}",
- wantErr: true,
- }, {
- desc: "Value field struct",
- inputMessage: &pb2.KnownTypes{},
- inputText: `{
- "optValue": {
- "string": "hello"
- }
- }`,
- wantMessage: &pb2.KnownTypes{
- OptValue: &structpb.Value{
- Kind: &structpb.Value_StructValue{
- &structpb.Struct{
- Fields: map[string]*structpb.Value{
- "string": {Kind: &structpb.Value_StringValue{"hello"}},
- },
- },
- },
- },
- },
- }, {
- desc: "Value empty list",
- inputMessage: &structpb.Value{},
- inputText: `[]`,
- wantMessage: &structpb.Value{
- Kind: &structpb.Value_ListValue{
- &structpb.ListValue{Values: []*structpb.Value{}},
- },
- },
- }, {
- desc: "Value list",
- inputMessage: &structpb.Value{},
- inputText: `[
- "string",
- 123,
- null,
- true,
- {},
- [
- "string",
- 1.23,
- null,
- false
- ]
- ]`,
- wantMessage: &structpb.Value{
- Kind: &structpb.Value_ListValue{
- &structpb.ListValue{
- Values: []*structpb.Value{
- {Kind: &structpb.Value_StringValue{"string"}},
- {Kind: &structpb.Value_NumberValue{123}},
- {Kind: &structpb.Value_NullValue{}},
- {Kind: &structpb.Value_BoolValue{true}},
- {Kind: &structpb.Value_StructValue{&structpb.Struct{}}},
- {
- Kind: &structpb.Value_ListValue{
- &structpb.ListValue{
- Values: []*structpb.Value{
- {Kind: &structpb.Value_StringValue{"string"}},
- {Kind: &structpb.Value_NumberValue{1.23}},
- {Kind: &structpb.Value_NullValue{}},
- {Kind: &structpb.Value_BoolValue{false}},
- },
- },
- },
- },
- },
- },
- },
- },
- }, {
- desc: "Value list with invalid UTF8 string",
- inputMessage: &structpb.Value{},
- inputText: "[\"abc\xff\"]",
- wantErr: true,
- }, {
- desc: "Value field list with invalid UTF8 string",
- inputMessage: &pb2.KnownTypes{},
- inputText: `{
- "optValue": [ "` + "abc\xff" + `"]
- }`,
- wantErr: true,
- }, {
- desc: "Duration empty string",
- inputMessage: &durationpb.Duration{},
- inputText: `""`,
- wantErr: true,
- }, {
- desc: "Duration with secs",
- inputMessage: &durationpb.Duration{},
- inputText: `"3s"`,
- wantMessage: &durationpb.Duration{Seconds: 3},
- }, {
- desc: "Duration with escaped unicode",
- inputMessage: &durationpb.Duration{},
- inputText: `"\u0033s"`,
- wantMessage: &durationpb.Duration{Seconds: 3},
- }, {
- desc: "Duration with -secs",
- inputMessage: &durationpb.Duration{},
- inputText: `"-3s"`,
- wantMessage: &durationpb.Duration{Seconds: -3},
- }, {
- desc: "Duration with plus sign",
- inputMessage: &durationpb.Duration{},
- inputText: `"+3s"`,
- wantMessage: &durationpb.Duration{Seconds: 3},
- }, {
- desc: "Duration with nanos",
- inputMessage: &durationpb.Duration{},
- inputText: `"0.001s"`,
- wantMessage: &durationpb.Duration{Nanos: 1e6},
- }, {
- desc: "Duration with -nanos",
- inputMessage: &durationpb.Duration{},
- inputText: `"-0.001s"`,
- wantMessage: &durationpb.Duration{Nanos: -1e6},
- }, {
- desc: "Duration with -nanos",
- inputMessage: &durationpb.Duration{},
- inputText: `"-.001s"`,
- wantMessage: &durationpb.Duration{Nanos: -1e6},
- }, {
- desc: "Duration with +nanos",
- inputMessage: &durationpb.Duration{},
- inputText: `"+.001s"`,
- wantMessage: &durationpb.Duration{Nanos: 1e6},
- }, {
- desc: "Duration with -secs -nanos",
- inputMessage: &durationpb.Duration{},
- inputText: `"-123.000000450s"`,
- wantMessage: &durationpb.Duration{Seconds: -123, Nanos: -450},
- }, {
- desc: "Duration with large secs",
- inputMessage: &durationpb.Duration{},
- inputText: `"10000000000.000000001s"`,
- wantMessage: &durationpb.Duration{Seconds: 1e10, Nanos: 1},
- }, {
- desc: "Duration with decimal without fractional",
- inputMessage: &durationpb.Duration{},
- inputText: `"3.s"`,
- wantMessage: &durationpb.Duration{Seconds: 3},
- }, {
- desc: "Duration with decimal without integer",
- inputMessage: &durationpb.Duration{},
- inputText: `"0.5s"`,
- wantMessage: &durationpb.Duration{Nanos: 5e8},
- }, {
- desc: "Duration max value",
- inputMessage: &durationpb.Duration{},
- inputText: `"315576000000.999999999s"`,
- wantMessage: &durationpb.Duration{Seconds: 315576000000, Nanos: 999999999},
- }, {
- desc: "Duration min value",
- inputMessage: &durationpb.Duration{},
- inputText: `"-315576000000.999999999s"`,
- wantMessage: &durationpb.Duration{Seconds: -315576000000, Nanos: -999999999},
- }, {
- desc: "Duration with +secs out of range",
- inputMessage: &durationpb.Duration{},
- inputText: `"315576000001s"`,
- wantErr: true,
- }, {
- desc: "Duration with -secs out of range",
- inputMessage: &durationpb.Duration{},
- inputText: `"-315576000001s"`,
- wantErr: true,
- }, {
- desc: "Duration with nanos beyond 9 digits",
- inputMessage: &durationpb.Duration{},
- inputText: `"0.1000000000s"`,
- wantErr: true,
- }, {
- desc: "Duration without suffix s",
- inputMessage: &durationpb.Duration{},
- inputText: `"123"`,
- wantErr: true,
- }, {
- desc: "Duration invalid signed fraction",
- inputMessage: &durationpb.Duration{},
- inputText: `"123.+123s"`,
- wantErr: true,
- }, {
- desc: "Duration invalid multiple .",
- inputMessage: &durationpb.Duration{},
- inputText: `"123.123.s"`,
- wantErr: true,
- }, {
- desc: "Duration invalid integer",
- inputMessage: &durationpb.Duration{},
- inputText: `"01s"`,
- wantErr: true,
- }, {
- desc: "Timestamp zero",
- inputMessage: ×tamppb.Timestamp{},
- inputText: `"1970-01-01T00:00:00Z"`,
- wantMessage: ×tamppb.Timestamp{},
- }, {
- desc: "Timestamp with tz adjustment",
- inputMessage: ×tamppb.Timestamp{},
- inputText: `"1970-01-01T00:00:00+01:00"`,
- wantMessage: ×tamppb.Timestamp{Seconds: -3600},
- }, {
- desc: "Timestamp UTC",
- inputMessage: ×tamppb.Timestamp{},
- inputText: `"2019-03-19T23:03:21Z"`,
- wantMessage: ×tamppb.Timestamp{Seconds: 1553036601},
- }, {
- desc: "Timestamp with escaped unicode",
- inputMessage: ×tamppb.Timestamp{},
- inputText: `"2019-0\u0033-19T23:03:21Z"`,
- wantMessage: ×tamppb.Timestamp{Seconds: 1553036601},
- }, {
- desc: "Timestamp with nanos",
- inputMessage: ×tamppb.Timestamp{},
- inputText: `"2019-03-19T23:03:21.000000001Z"`,
- wantMessage: ×tamppb.Timestamp{Seconds: 1553036601, Nanos: 1},
- }, {
- desc: "Timestamp max value",
- inputMessage: ×tamppb.Timestamp{},
- inputText: `"9999-12-31T23:59:59.999999999Z"`,
- wantMessage: ×tamppb.Timestamp{Seconds: 253402300799, Nanos: 999999999},
- }, {
- desc: "Timestamp above max value",
- inputMessage: ×tamppb.Timestamp{},
- inputText: `"9999-12-31T23:59:59-01:00"`,
- wantErr: true,
- }, {
- desc: "Timestamp min value",
- inputMessage: ×tamppb.Timestamp{},
- inputText: `"0001-01-01T00:00:00Z"`,
- wantMessage: ×tamppb.Timestamp{Seconds: -62135596800},
- }, {
- desc: "Timestamp below min value",
- inputMessage: ×tamppb.Timestamp{},
- inputText: `"0001-01-01T00:00:00+01:00"`,
- wantErr: true,
- }, {
- desc: "Timestamp with nanos beyond 9 digits",
- inputMessage: ×tamppb.Timestamp{},
- inputText: `"1970-01-01T00:00:00.0000000001Z"`,
- wantErr: true,
- }, {
- desc: "FieldMask empty",
- inputMessage: &fieldmaskpb.FieldMask{},
- inputText: `""`,
- wantMessage: &fieldmaskpb.FieldMask{Paths: []string{}},
- }, {
- desc: "FieldMask",
- inputMessage: &fieldmaskpb.FieldMask{},
- inputText: `"foo,fooBar , foo.barQux ,Foo"`,
- wantMessage: &fieldmaskpb.FieldMask{
- Paths: []string{
- "foo",
- "foo_bar",
- "foo.bar_qux",
- "_foo",
- },
- },
- }, {
- desc: "FieldMask field",
- inputMessage: &pb2.KnownTypes{},
- inputText: `{
- "optFieldmask": "foo, qux.fooBar"
- }`,
- wantMessage: &pb2.KnownTypes{
- OptFieldmask: &fieldmaskpb.FieldMask{
- Paths: []string{
- "foo",
- "qux.foo_bar",
- },
- },
- },
- }, {
- desc: "Any empty",
- inputMessage: &anypb.Any{},
- inputText: `{}`,
- wantMessage: &anypb.Any{},
- }, {
- desc: "Any with non-custom message",
- inputMessage: &anypb.Any{},
- inputText: `{
- "@type": "foo/pb2.Nested",
- "optString": "embedded inside Any",
- "optNested": {
- "optString": "inception"
- }
- }`,
- wantMessage: func() proto.Message {
- m := &pb2.Nested{
- OptString: proto.String("embedded inside Any"),
- OptNested: &pb2.Nested{
- OptString: proto.String("inception"),
- },
- }
- b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
- if err != nil {
- t.Fatalf("error in binary marshaling message for Any.value: %v", err)
- }
- return &anypb.Any{
- TypeUrl: "foo/pb2.Nested",
- Value: b,
- }
- }(),
- }, {
- desc: "Any with empty embedded message",
- inputMessage: &anypb.Any{},
- inputText: `{"@type": "foo/pb2.Nested"}`,
- wantMessage: &anypb.Any{TypeUrl: "foo/pb2.Nested"},
- }, {
- desc: "Any without registered type",
- umo: protojson.UnmarshalOptions{Resolver: new(preg.Types)},
- inputMessage: &anypb.Any{},
- inputText: `{"@type": "foo/pb2.Nested"}`,
- wantErr: true,
- }, {
- desc: "Any with missing required",
- inputMessage: &anypb.Any{},
- inputText: `{
- "@type": "pb2.PartialRequired",
- "optString": "embedded inside Any"
- }`,
- wantMessage: func() proto.Message {
- m := &pb2.PartialRequired{
- OptString: proto.String("embedded inside Any"),
- }
- b, err := proto.MarshalOptions{
- Deterministic: true,
- AllowPartial: true,
- }.Marshal(m)
- if err != nil {
- t.Fatalf("error in binary marshaling message for Any.value: %v", err)
- }
- return &anypb.Any{
- TypeUrl: string(m.ProtoReflect().Descriptor().FullName()),
- Value: b,
- }
- }(),
- }, {
- desc: "Any with partial required and AllowPartial",
- umo: protojson.UnmarshalOptions{
- AllowPartial: true,
- },
- inputMessage: &anypb.Any{},
- inputText: `{
- "@type": "pb2.PartialRequired",
- "optString": "embedded inside Any"
- }`,
- wantMessage: func() proto.Message {
- m := &pb2.PartialRequired{
- OptString: proto.String("embedded inside Any"),
- }
- b, err := proto.MarshalOptions{
- Deterministic: true,
- AllowPartial: true,
- }.Marshal(m)
- if err != nil {
- t.Fatalf("error in binary marshaling message for Any.value: %v", err)
- }
- return &anypb.Any{
- TypeUrl: string(m.ProtoReflect().Descriptor().FullName()),
- Value: b,
- }
- }(),
- }, {
- desc: "Any with invalid UTF8",
- inputMessage: &anypb.Any{},
- inputText: `{
- "optString": "` + "abc\xff" + `",
- "@type": "foo/pb2.Nested"
- }`,
- wantErr: true,
- }, {
- desc: "Any with BoolValue",
- inputMessage: &anypb.Any{},
- inputText: `{
- "@type": "type.googleapis.com/google.protobuf.BoolValue",
- "value": true
- }`,
- wantMessage: func() proto.Message {
- m := &wrapperspb.BoolValue{Value: true}
- b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
- if err != nil {
- t.Fatalf("error in binary marshaling message for Any.value: %v", err)
- }
- return &anypb.Any{
- TypeUrl: "type.googleapis.com/google.protobuf.BoolValue",
- Value: b,
- }
- }(),
- }, {
- desc: "Any with Empty",
- inputMessage: &anypb.Any{},
- inputText: `{
- "value": {},
- "@type": "type.googleapis.com/google.protobuf.Empty"
- }`,
- wantMessage: &anypb.Any{
- TypeUrl: "type.googleapis.com/google.protobuf.Empty",
- },
- }, {
- desc: "Any with missing Empty",
- inputMessage: &anypb.Any{},
- inputText: `{
- "@type": "type.googleapis.com/google.protobuf.Empty"
- }`,
- wantErr: true,
- }, {
- desc: "Any with StringValue containing invalid UTF8",
- inputMessage: &anypb.Any{},
- inputText: `{
- "@type": "google.protobuf.StringValue",
- "value": "` + "abc\xff" + `"
- }`,
- wantErr: true,
- }, {
- desc: "Any with Int64Value",
- inputMessage: &anypb.Any{},
- inputText: `{
- "@type": "google.protobuf.Int64Value",
- "value": "42"
- }`,
- wantMessage: func() proto.Message {
- m := &wrapperspb.Int64Value{Value: 42}
- b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
- if err != nil {
- t.Fatalf("error in binary marshaling message for Any.value: %v", err)
- }
- return &anypb.Any{
- TypeUrl: "google.protobuf.Int64Value",
- Value: b,
- }
- }(),
- }, {
- desc: "Any with invalid Int64Value",
- inputMessage: &anypb.Any{},
- inputText: `{
- "@type": "google.protobuf.Int64Value",
- "value": "forty-two"
- }`,
- wantErr: true,
- }, {
- desc: "Any with invalid UInt64Value",
- inputMessage: &anypb.Any{},
- inputText: `{
- "@type": "google.protobuf.UInt64Value",
- "value": -42
- }`,
- wantErr: true,
- }, {
- desc: "Any with Duration",
- inputMessage: &anypb.Any{},
- inputText: `{
- "@type": "type.googleapis.com/google.protobuf.Duration",
- "value": "0s"
- }`,
- wantMessage: func() proto.Message {
- m := &durationpb.Duration{}
- b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
- if err != nil {
- t.Fatalf("error in binary marshaling message for Any.value: %v", err)
- }
- return &anypb.Any{
- TypeUrl: "type.googleapis.com/google.protobuf.Duration",
- Value: b,
- }
- }(),
- }, {
- desc: "Any with Value of StringValue",
- inputMessage: &anypb.Any{},
- inputText: `{
- "@type": "google.protobuf.Value",
- "value": "` + "abc\xff" + `"
- }`,
- wantErr: true,
- }, {
- desc: "Any with Value of NullValue",
- inputMessage: &anypb.Any{},
- inputText: `{
- "@type": "google.protobuf.Value",
- "value": null
- }`,
- wantMessage: func() proto.Message {
- m := &structpb.Value{Kind: &structpb.Value_NullValue{}}
- b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
- if err != nil {
- t.Fatalf("error in binary marshaling message for Any.value: %v", err)
- }
- return &anypb.Any{
- TypeUrl: "google.protobuf.Value",
- Value: b,
- }
- }(),
- }, {
- desc: "Any with Struct",
- inputMessage: &anypb.Any{},
- inputText: `{
- "@type": "google.protobuf.Struct",
- "value": {
- "bool": true,
- "null": null,
- "string": "hello",
- "struct": {
- "string": "world"
- }
- }
- }`,
- wantMessage: func() proto.Message {
- m := &structpb.Struct{
- Fields: map[string]*structpb.Value{
- "bool": {Kind: &structpb.Value_BoolValue{true}},
- "null": {Kind: &structpb.Value_NullValue{}},
- "string": {Kind: &structpb.Value_StringValue{"hello"}},
- "struct": {
- Kind: &structpb.Value_StructValue{
- &structpb.Struct{
- Fields: map[string]*structpb.Value{
- "string": {Kind: &structpb.Value_StringValue{"world"}},
- },
- },
- },
- },
- },
- }
- b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
- if err != nil {
- t.Fatalf("error in binary marshaling message for Any.value: %v", err)
- }
- return &anypb.Any{
- TypeUrl: "google.protobuf.Struct",
- Value: b,
- }
- }(),
- }, {
- desc: "Any with missing @type",
- umo: protojson.UnmarshalOptions{},
- inputMessage: &anypb.Any{},
- inputText: `{
- "value": {}
- }`,
- wantErr: true,
- }, {
- desc: "Any with empty @type",
- inputMessage: &anypb.Any{},
- inputText: `{
- "@type": ""
- }`,
- wantErr: true,
- }, {
- desc: "Any with duplicate @type",
- inputMessage: &anypb.Any{},
- inputText: `{
- "@type": "google.protobuf.StringValue",
- "value": "hello",
- "@type": "pb2.Nested"
- }`,
- wantErr: true,
- }, {
- desc: "Any with duplicate value",
- inputMessage: &anypb.Any{},
- inputText: `{
- "@type": "google.protobuf.StringValue",
- "value": "hello",
- "value": "world"
- }`,
- wantErr: true,
- }, {
- desc: "Any with unknown field",
- inputMessage: &anypb.Any{},
- inputText: `{
- "@type": "pb2.Nested",
- "optString": "hello",
- "unknown": "world"
- }`,
- wantErr: true,
- }, {
- desc: "Any with embedded type containing Any",
- inputMessage: &anypb.Any{},
- inputText: `{
- "@type": "pb2.KnownTypes",
- "optAny": {
- "@type": "google.protobuf.StringValue",
- "value": "` + "abc\xff" + `"
- }
- }`,
- wantErr: true,
- }, {
- desc: "well known types as field values",
- inputMessage: &pb2.KnownTypes{},
- inputText: `{
- "optBool": false,
- "optInt32": 42,
- "optInt64": "42",
- "optUint32": 42,
- "optUint64": "42",
- "optFloat": 1.23,
- "optDouble": 3.1415,
- "optString": "hello",
- "optBytes": "aGVsbG8=",
- "optDuration": "123s",
- "optTimestamp": "2019-03-19T23:03:21Z",
- "optStruct": {
- "string": "hello"
- },
- "optList": [
- null,
- "",
- {},
- []
- ],
- "optValue": "world",
- "optEmpty": {},
- "optAny": {
- "@type": "google.protobuf.Empty",
- "value": {}
- },
- "optFieldmask": "fooBar,barFoo"
- }`,
- wantMessage: &pb2.KnownTypes{
- OptBool: &wrapperspb.BoolValue{Value: false},
- OptInt32: &wrapperspb.Int32Value{Value: 42},
- OptInt64: &wrapperspb.Int64Value{Value: 42},
- OptUint32: &wrapperspb.UInt32Value{Value: 42},
- OptUint64: &wrapperspb.UInt64Value{Value: 42},
- OptFloat: &wrapperspb.FloatValue{Value: 1.23},
- OptDouble: &wrapperspb.DoubleValue{Value: 3.1415},
- OptString: &wrapperspb.StringValue{Value: "hello"},
- OptBytes: &wrapperspb.BytesValue{Value: []byte("hello")},
- OptDuration: &durationpb.Duration{Seconds: 123},
- OptTimestamp: ×tamppb.Timestamp{Seconds: 1553036601},
- OptStruct: &structpb.Struct{
- Fields: map[string]*structpb.Value{
- "string": {Kind: &structpb.Value_StringValue{"hello"}},
- },
- },
- OptList: &structpb.ListValue{
- Values: []*structpb.Value{
- {Kind: &structpb.Value_NullValue{}},
- {Kind: &structpb.Value_StringValue{}},
- {
- Kind: &structpb.Value_StructValue{
- &structpb.Struct{Fields: map[string]*structpb.Value{}},
- },
- },
- {
- Kind: &structpb.Value_ListValue{
- &structpb.ListValue{Values: []*structpb.Value{}},
- },
- },
- },
- },
- OptValue: &structpb.Value{
- Kind: &structpb.Value_StringValue{"world"},
- },
- OptEmpty: &emptypb.Empty{},
- OptAny: &anypb.Any{
- TypeUrl: "google.protobuf.Empty",
- },
- OptFieldmask: &fieldmaskpb.FieldMask{
- Paths: []string{"foo_bar", "bar_foo"},
- },
- },
- }, {
- desc: "DiscardUnknown: regular messages",
- umo: protojson.UnmarshalOptions{DiscardUnknown: true},
- inputMessage: &pb3.Nests{},
- inputText: `{
- "sNested": {
- "unknown": {
- "foo": 1,
- "bar": [1, 2, 3]
- }
- },
- "unknown": "not known"
- }`,
- wantMessage: &pb3.Nests{SNested: &pb3.Nested{}},
- }, {
- desc: "DiscardUnknown: repeated",
- umo: protojson.UnmarshalOptions{DiscardUnknown: true},
- inputMessage: &pb2.Nests{},
- inputText: `{
- "rptNested": [
- {"unknown": "blah"},
- {"optString": "hello"}
- ]
- }`,
- wantMessage: &pb2.Nests{
- RptNested: []*pb2.Nested{
- {},
- {OptString: proto.String("hello")},
- },
- },
- }, {
- desc: "DiscardUnknown: map",
- umo: protojson.UnmarshalOptions{DiscardUnknown: true},
- inputMessage: &pb3.Maps{},
- inputText: `{
- "strToNested": {
- "nested_one": {
- "unknown": "what you see is not"
- }
- }
- }`,
- wantMessage: &pb3.Maps{
- StrToNested: map[string]*pb3.Nested{
- "nested_one": {},
- },
- },
- }, {
- desc: "DiscardUnknown: extension",
- umo: protojson.UnmarshalOptions{DiscardUnknown: true},
- inputMessage: &pb2.Extensions{},
- inputText: `{
- "[pb2.opt_ext_nested]": {
- "unknown": []
- }
- }`,
- wantMessage: func() proto.Message {
- m := &pb2.Extensions{}
- proto.SetExtension(m, pb2.E_OptExtNested, &pb2.Nested{})
- return m
- }(),
- }, {
- desc: "DiscardUnknown: Empty",
- umo: protojson.UnmarshalOptions{DiscardUnknown: true},
- inputMessage: &emptypb.Empty{},
- inputText: `{"unknown": "something"}`,
- wantMessage: &emptypb.Empty{},
- }, {
- desc: "DiscardUnknown: Any without type",
- umo: protojson.UnmarshalOptions{DiscardUnknown: true},
- inputMessage: &anypb.Any{},
- inputText: `{
- "value": {"foo": "bar"},
- "unknown": true
- }`,
- wantMessage: &anypb.Any{},
- }, {
- desc: "DiscardUnknown: Any",
- umo: protojson.UnmarshalOptions{
- DiscardUnknown: true,
- },
- inputMessage: &anypb.Any{},
- inputText: `{
- "@type": "foo/pb2.Nested",
- "unknown": "none"
- }`,
- wantMessage: &anypb.Any{
- TypeUrl: "foo/pb2.Nested",
- },
- }, {
- desc: "DiscardUnknown: Any with Empty",
- umo: protojson.UnmarshalOptions{
- DiscardUnknown: true,
- },
- inputMessage: &anypb.Any{},
- inputText: `{
- "@type": "type.googleapis.com/google.protobuf.Empty",
- "value": {"unknown": 47}
- }`,
- wantMessage: &anypb.Any{
- TypeUrl: "type.googleapis.com/google.protobuf.Empty",
- },
- }, {
- desc: "weak fields",
- inputMessage: &testpb.TestWeak{},
- inputText: `{"weak_message1":{"a":1}}`,
- wantMessage: func() *testpb.TestWeak {
- m := new(testpb.TestWeak)
- m.SetWeakMessage1(&weakpb.WeakImportMessage1{A: proto.Int32(1)})
- return m
- }(),
- skip: !flags.ProtoLegacy,
- }, {
- desc: "weak fields; unknown field",
- inputMessage: &testpb.TestWeak{},
- inputText: `{"weak_message1":{"a":1}, "weak_message2":{"a":1}}`,
- wantErr: true, // weak_message2 is unknown since the package containing it is not imported
- skip: !flags.ProtoLegacy,
- }}
- for _, tt := range tests {
- tt := tt
- if tt.skip {
- continue
- }
- t.Run(tt.desc, func(t *testing.T) {
- err := tt.umo.Unmarshal([]byte(tt.inputText), tt.inputMessage)
- if err != nil && !tt.wantErr {
- t.Errorf("Unmarshal() returned error: %v\n\n", err)
- }
- if err == nil && tt.wantErr {
- t.Error("Unmarshal() got nil error, want error\n\n")
- }
- if tt.wantMessage != nil && !proto.Equal(tt.inputMessage, tt.wantMessage) {
- t.Errorf("Unmarshal()\n<got>\n%v\n<want>\n%v\n", tt.inputMessage, tt.wantMessage)
- }
- })
- }
- }
|