Skip to content

Commit 59ced87

Browse files
Mizuchimeta-codesync[bot]
authored andcommitted
Add more shared JSON5 test cases
Summary: More shared JSON5 test cases, run by every implementation that uses the shared test data: - Decoding: negative zero, comments after the value, null members, field id -32768, a union holding only an unknown field, duplicate set elements and map keys, `float` keys from strings, bare base64, and `float` and `double` literals near rounding midpoints. - Rejected input: malformed bare base64, a map that is not a container, misnamed map entries, struct and container keys in object form, a top-level list, an empty field name, truncated input, a missing skipped value, two union fields around a null unknown one, and reader inputs such as `1/2` and `-null`. - Round trips: signs of zero and NaN in a `double` list, negative NaN in a `float` field, `float` overflow to `Infinity`. - Writing: more `double` and `float` text, enum keys in value order, list keys element by element, string keys in byte order, binary with a C1 control or a no-break space, and a union member with an empty value. ___ landed-with-radar-review Differential Revision: D129503639 fbshipit-source-id: 3f1e0de1035c32936a884ff0818da70ad2131aa4
1 parent 35d725e commit 59ced87

4 files changed

Lines changed: 438 additions & 0 deletions

File tree

‎thrift/test/json5/json5_compatibility_test.thrift‎

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,147 @@ const list<CompatibilityTestCase> compatibilityTestCases = [
393393
inputs = ["{\"floatAsKey\": {\"16777216\": 1}}"],
394394
output = json5_test.Example{floatAsKey = {16777216.0: 1}},
395395
},
396+
CompatibilityTestCase{
397+
name = "IntegerNegativeZero",
398+
inputs = [
399+
"{\"i64Value\": -0}",
400+
"{\"i64Value\": \"-0\"}",
401+
"{\"i64Value\": -0x0}",
402+
],
403+
output = json5_test.Example{i64Value = 0},
404+
},
405+
CompatibilityTestCase{
406+
name = "CommentAfterValue",
407+
inputs = [
408+
"{\"i64Value\": 1} // note",
409+
"{\"i64Value\": 1} /* note */",
410+
],
411+
output = json5_test.Example{i64Value = 1},
412+
},
413+
// A null member is skipped before its name or id is checked.
414+
CompatibilityTestCase{
415+
name = "NullMembersAreNotResolved",
416+
inputs = ["{\"boolValue (31)\": null, \"NonExist (30)\": null}"],
417+
output = json5_test.Example{},
418+
},
419+
// Field id -32768 stands for "no id".
420+
CompatibilityTestCase{
421+
name = "FieldIdInt16MinMeansNoId",
422+
inputs = ["{\"boolValue (-32768)\": true}"],
423+
output = json5_test.Example{boolValue = true},
424+
},
425+
CompatibilityTestCase{
426+
name = "UnionWithOnlyUnknownField",
427+
inputs = ["{\"unionValue\": {\"unknown\": 1}}"],
428+
output = json5_test.Example{unionValue = json5_test.ExampleUnion{}},
429+
},
430+
CompatibilityTestCase{
431+
name = "SetDuplicateElements",
432+
inputs = [
433+
"{\"i32SetValue\": [2, 1, 2], \"setValue\": [{\"nested\": \"b\"}, {\"nested\": \"a\"}, {\"nested\": \"b\"}]}",
434+
],
435+
output = json5_test.Example{
436+
i32SetValue = [1, 2],
437+
setValue = [json5_test.Nested{nested = "a"}, json5_test.Nested{nested = "b"}],
438+
},
439+
},
440+
CompatibilityTestCase{
441+
name = "MapDuplicateKeyLastWins",
442+
inputs = [
443+
"{\"i32AsKey\": [{\"key\": 1, \"value\": 2}, {\"key\": 1, \"value\": 3}]}",
444+
"{\"i32AsKey\": {\"1\": 2, \"0x1\": 3}}",
445+
],
446+
output = json5_test.Example{i32AsKey = {1: 3}},
447+
},
448+
CompatibilityTestCase{
449+
name = "StructKeyDuplicateLastWins",
450+
inputs = [
451+
"{\"structAsKey\": [{\"key\": {\"nested\": \"k\"}, \"value\": {\"nested\": \"v\"}}, {\"key\": {\"nested\": \"k\"}, \"value\": {\"nested\": \"w\"}}]}",
452+
],
453+
output = json5_test.Example{
454+
structAsKey = {json5_test.Nested{nested = "k"}: json5_test.Nested{nested = "w"}},
455+
},
456+
},
457+
CompatibilityTestCase{
458+
name = "SetAsKeyDuplicateElements",
459+
inputs = ["{\"setAsKey\": [{\"key\": [2, 1, 2], \"value\": 3}]}"],
460+
output = json5_test.Example{setAsKey = {[1, 2]: 3}},
461+
},
462+
CompatibilityTestCase{
463+
name = "FloatAsKeyFromString",
464+
inputs = [
465+
"{\"floatAsKey\": [{\"key\": 0.5, \"value\": 1}, {\"key\": \"16777216\", \"value\": 2}]}",
466+
],
467+
output = json5_test.Example{floatAsKey = {0.5: 1, 16777216.0: 2}},
468+
},
469+
// Bare base64 strings: padding is optional, and nonzero trailing bits ("QR")
470+
// are ignored.
471+
CompatibilityTestCase{
472+
name = "BinaryBareBase64OneByte",
473+
inputs = [
474+
"{\"binaryValue\": \"QQ\"}",
475+
"{\"binaryValue\": \"QQ==\"}",
476+
"{\"binaryValue\": \"QR\"}",
477+
],
478+
output = json5_test.Example{binaryValue = "A"},
479+
},
480+
CompatibilityTestCase{
481+
name = "BinaryBareBase64TwoBytes",
482+
inputs = ["{\"binaryValue\": \"QUI\"}", "{\"binaryValue\": \"QUI=\"}"],
483+
output = json5_test.Example{binaryValue = "AB"},
484+
},
485+
CompatibilityTestCase{
486+
name = "BinaryBareBase64ThreeBytes",
487+
inputs = ["{\"binaryValue\": \"QUJD\"}"],
488+
output = json5_test.Example{binaryValue = "ABC"},
489+
},
490+
CompatibilityTestCase{
491+
name = "BinaryBareBase64Empty",
492+
inputs = ["{\"binaryValue\": \"\"}"],
493+
output = json5_test.Example{binaryValue = ""},
494+
},
495+
// 1 + 2^-24 is exactly halfway between two binary32 values.
496+
CompatibilityTestCase{
497+
name = "FloatBinary32MidpointTiesToEven",
498+
inputs = ["{\"floatValue\": 1.000000059604644775390625}"],
499+
output = json5_test.Example{floatValue = 1.0},
500+
},
501+
// Above a binary32 midpoint whose exact decimal has 83 significant digits,
502+
// but below it rounded to 41 digits.
503+
CompatibilityTestCase{
504+
name = "FloatJustAboveLongBinary32Midpoint",
505+
inputs = ["{\"floatValue\": 7.03853100000000022281692450609677778769437e-26}"],
506+
output = json5_test.Example{
507+
floatValue = 0.0000000000000000000000000703853130814879132477466099505324860128273323223169199991389177739620208740234375,
508+
},
509+
},
510+
CompatibilityTestCase{
511+
name = "FloatJustBelowMidpointAfterFltMax",
512+
inputs = ["{\"floatValue\": 340282356779733661637539395458142568447.999999}"],
513+
output = json5_test.Example{
514+
floatValue = 340282346638528859811704183484516925440.0,
515+
},
516+
},
517+
CompatibilityTestCase{
518+
name = "FloatJustAboveHalfSmallestSubnormal",
519+
inputs = ["{\"floatValue\": 7.00649232162408535461864791644958065640130970938257885878534141944895541342930300743319094181060791015625000001e-46}"],
520+
output = json5_test.Example{
521+
floatValue = 0.000000000000000000000000000000000000000000001401298464324817070923729583289916131280261941876515771757068283889791082685860601486638188362121582031250,
522+
},
523+
},
524+
// Exactly halfway between the largest subnormal and DBL_MIN.
525+
CompatibilityTestCase{
526+
name = "DoubleSubnormalMidpointTiesToEven",
527+
inputs = ["{\"doubleValue\": 2.22507385850720113605740979670913197593481954635164564802342610972482222202107694551652952390813508791414915891303962110687008643869459464552765720740782062174337998814106326732925355228688137214901298112245145188984905722230728525513315575501591439747639798341180199932396254828901710708185069063066665599493827577257201576306269066333264756530000924588831643303777979186961204949739037782970490505108060994073026293712895895000358379996720725430436028407889577179615094551674824347103070260914462157228988025818254518032570701886087211312807951223342628836862232150377566662250398253433597456888442390026549819838548794829220689472168983109969836584681402285424333066033985088644580400103493397042756718644338377048603786162277173854562306587467901408672332763671875e-308}"],
528+
output = json5_test.Example{doubleValue = 2.2250738585072014e-308},
529+
},
530+
CompatibilityTestCase{
531+
name = "DoubleJustBelowSubnormalMidpoint",
532+
inputs = [
533+
"{\"doubleValue\": 2.225073858507201136057409796709131975934819546351645648e-308}",
534+
],
535+
output = json5_test.Example{doubleValue = 2.225073858507201e-308},
536+
},
396537
];
397538
398539
// Values that thrift constants cannot express: NaN, the infinities and
@@ -553,6 +694,53 @@ const list<RoundTripTestCase> roundTripTestCases = [
553694
value: 2,
554695
},
555696
],
697+
}",
698+
},
699+
RoundTripTestCase{
700+
name = "SignsOfZeroAndNaNInDoubleList",
701+
inputs = [
702+
"{\"doubleListValue\": [-0.0, -NaN, 0.0, NaN]}",
703+
"{\"doubleListValue\": [-0, \"-NaN\", 0, \"NaN\"]}",
704+
"{doubleListValue: [\"-0x0\", -NaN, \"0.0\", +NaN]}",
705+
],
706+
json = "{
707+
\"doubleListValue\": [
708+
-0.0,
709+
\"-NaN\",
710+
0.0,
711+
\"NaN\"
712+
]
713+
}",
714+
json5 = "{
715+
doubleListValue: [
716+
-0.0,
717+
-NaN,
718+
0.0,
719+
NaN,
720+
],
721+
}",
722+
},
723+
RoundTripTestCase{
724+
name = "FloatNegativeNaN",
725+
inputs = ["{\"floatValue\": -NaN}", "{\"floatValue\": \"-NaN\"}"],
726+
json = "{
727+
\"floatValue\": \"-NaN\"
728+
}",
729+
json5 = "{
730+
floatValue: -NaN,
731+
}",
732+
},
733+
RoundTripTestCase{
734+
name = "FloatOverflowsToInfinity",
735+
inputs = [
736+
"{\"floatValue\": 1e39}",
737+
"{\"floatValue\": 340282356779733661637539395458142568448.000001}",
738+
],
739+
json = "{
740+
\"floatValue\": \"Infinity\"
741+
}",
742+
json5 = "{
743+
floatValue: Infinity,
556744
}",
557745
},
558746
];

‎thrift/test/json5/json5_negative_test.thrift‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,20 @@ const list<NegativeTestCase> typeValidationNegativeCases = [
250250
name = "FloatKeyPrecisionLoss",
251251
json = "{\"floatAsKey\": {\"16777217\": 1}}",
252252
},
253+
NegativeTestCase{name = "BinaryBareBase64OneCharacter", json = "{\"binaryValue\": \"Q\"}"},
254+
NegativeTestCase{name = "BinaryBareBase64FiveCharacters", json = "{\"binaryValue\": \"QUJDR\"}"},
255+
NegativeTestCase{name = "BinaryBareBase64PartialPadding", json = "{\"binaryValue\": \"QQ=\"}"},
256+
NegativeTestCase{name = "BinaryBareBase64PaddingAfterCompleteQuantum", json = "{\"binaryValue\": \"QUJD====\"}"},
257+
NegativeTestCase{name = "BinaryBareBase64ThreePaddingCharacters", json = "{\"binaryValue\": \"Q===\"}"},
258+
NegativeTestCase{name = "BinaryBareBase64OnlyPadding", json = "{\"binaryValue\": \"====\"}"},
259+
NegativeTestCase{name = "BinaryBareBase64PaddingInside", json = "{\"binaryValue\": \"QQ==QQ==\"}"},
260+
NegativeTestCase{name = "BinaryBareBase64Space", json = "{\"binaryValue\": \"QQ Q\"}"},
261+
NegativeTestCase{name = "BinaryBareBase64OtherCharacter", json = "{\"binaryValue\": \"QQ!Q\"}"},
262+
NegativeTestCase{name = "MapGotString", json = "{\"i32AsKey\": \"x\"}"},
263+
NegativeTestCase{name = "MapEntryMisnamedValue", json = "{\"i32AsKey\": [{\"key\": 1, \"val\": 2}]}"},
264+
NegativeTestCase{name = "StructKeyInObjectForm", json = "{\"structAsKey\": {\"k\": {}}}"},
265+
NegativeTestCase{name = "ListKeyInObjectForm", json = "{\"listAsKey\": {k: 1}}"},
266+
NegativeTestCase{name = "MapKeyInObjectForm", json = "{\"mapAsKey\": {\"k\": 1}}"},
253267
];
254268

255269
const list<NegativeTestCase> typeMismatchNegativeCases = [
@@ -356,6 +370,11 @@ const list<NegativeTestCase> formatValidationNegativeCases = [
356370
name = "UnionUnknownThenKnownField",
357371
json = "{\"unionValue\": {\"unknown\": 1, \"intValue\": 2}}",
358372
},
373+
NegativeTestCase{name = "TopLevelList", json = "[]"},
374+
NegativeTestCase{name = "EmptyFieldName", json = "{\"\": 1}"},
375+
NegativeTestCase{name = "EndOfInputAfterFieldName", json = "{\"i64Value\":"},
376+
NegativeTestCase{name = "SkippedValueMissing", json = "{\"unknown\": }"},
377+
NegativeTestCase{name = "UnionNullUnknownFieldBetweenFields", json = "{\"unionValue\": {\"intValue\": 1, \"unknown\": null, \"stringValue\": \"a\"}}"},
359378
];
360379

361380
const list<NegativeTestCase> overflowValidationNegativeCases = [

‎thrift/test/json5/json5_reader_test.thrift‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,4 +176,8 @@ const list<ReaderTestCase> readerTestCases = [
176176
ReaderTestCase{name = "ValueAfterComma", input = "{\"a\": 1}, {}"},
177177
ReaderTestCase{name = "ValueAfterCommaInList", input = "[1], 2"},
178178
ReaderTestCase{name = "ValueAfterCommaAndComment", input = "42 /* comment */ , 43"},
179+
ReaderTestCase{name = "LoneSlash", input = "1/2"},
180+
ReaderTestCase{name = "SignThenIdentifier", input = "-null"},
181+
ReaderTestCase{name = "SignThenInfinityMisspelled", input = "-Inf"},
182+
ReaderTestCase{name = "SignedDecimalPointThenExponent", input = "-.e5"},
179183
];

0 commit comments

Comments
 (0)