diff --git a/sources/Data/JSON/JArray.uc b/sources/Data/JSON/JArray.uc index 7278ea8..70d8476 100644 --- a/sources/Data/JSON/JArray.uc +++ b/sources/Data/JSON/JArray.uc @@ -533,6 +533,53 @@ public function JSON Clone() return clonedArray; } +public function bool ParseIntoSelfWith(Parser parser) +{ + local int i; + local bool parsingSucceeded; + local Parser.ParserState initState; + local JStorageAtom nextAtom; + local array parsedAtoms; + if (parser == none) return false; + initState = parser.GetCurrentState(); + parser.Skip().Match("[").Confirm(); + if (!parser.Ok()) + { + parser.RestoreState(initState); + return false; + } + while (parser.Ok() && !parser.HasFinished()) + { + parser.Skip().Confirm(); + if (parser.Match("]").Ok()) { + parsingSucceeded = true; + break; + } + if (parsedAtoms.length > 0 && !parser.R().Match(",").Skip().Ok()) { + break; + } + else { + parser.Confirm(); + } + nextAtom = ParseAtom(parser.R()); + if (nextAtom.type == JSON_Undefined) { + break; + } + parsedAtoms[parsedAtoms.length] = nextAtom; + parser.Confirm(); + } + if (parsingSucceeded) + { + for (i = 0; i < parsedAtoms.length; i += 1) { + data[data.length] = parsedAtoms[i]; + } + } + else { + parser.RestoreState(initState); + } + return parsingSucceeded; +} + public function string DisplayWith(JSONDisplaySettings displaySettings) { local int i; diff --git a/sources/Data/JSON/JObject.uc b/sources/Data/JSON/JObject.uc index 57e28b4..1713a9d 100644 --- a/sources/Data/JSON/JObject.uc +++ b/sources/Data/JSON/JObject.uc @@ -529,6 +529,54 @@ public function JSON Clone() return clonedObject; } +public function bool ParseIntoSelfWith(Parser parser) +{ + local int i; + local bool parsingSucceeded; + local Parser.ParserState initState; + local JProperty nextProperty; + local array parsedProperties; + if (parser == none) return false; + initState = parser.GetCurrentState(); + parser.Skip().Match("{").Confirm(); + if (!parser.Ok()) + { + parser.RestoreState(initState); + return false; + } + while (parser.Ok() && !parser.HasFinished()) + { + parser.Skip().Confirm(); + if (parser.Match("}").Ok()) { + parsingSucceeded = true; + break; + } + if (parsedProperties.length > 0 && !parser.R().Match(",").Skip().Ok()) { + break; + } + else { + parser.Confirm(); + } + parser.R().Skip().MStringLiteral(nextProperty.name).Skip().Match(":"); + nextProperty.value = ParseAtom(parser.Skip()); + if (!parser.Ok() || nextProperty.value.type == JSON_Undefined) { + break; + } + parsedProperties[parsedProperties.length] = nextProperty; + parser.Confirm(); + } + if (parsingSucceeded) + { + for (i = 0; i < parsedProperties.length; i += 1) { + UpdateProperty(parsedProperties[i]); + } + } + else { + parser.RestoreState(initState); + } + return parsingSucceeded; +} + public function string DisplayWith(JSONDisplaySettings displaySettings) { local int i, j; diff --git a/sources/Data/JSON/JSON.uc b/sources/Data/JSON/JSON.uc index 28e9440..80424c9 100644 --- a/sources/Data/JSON/JSON.uc +++ b/sources/Data/JSON/JSON.uc @@ -58,23 +58,23 @@ struct JStorageAtom { // What type is stored exactly? // Depending on that, uses one of the other fields as a storage. - var protected JType type; - var protected float numberValue; - var protected string stringValue; - var protected bool booleanValue; + var JType type; + var float numberValue; + var string stringValue; + var bool booleanValue; // Used for storing both JSON objects and arrays. - var protected JSON complexValue; + var JSON complexValue; // Numeric value might not fit into a `float` very well, so we will store // them as both `float` and `integer` and allow user to request any version // of them - var protected int numberValueAsInt; - var protected bool preferIntegerValue; + var int numberValueAsInt; + var bool preferIntegerValue; // Some `string` values might be actually used to represent classes, // so we will give users an ability to request `string` value as a class. - var protected class stringValueAsClass; + var class stringValueAsClass; // To avoid several unsuccessful attempts to load `class` object from // a `string`, we will record whether we've already tied that. - var protected bool classLoadingWasAttempted; + var bool classLoadingWasAttempted; }; enum JComparisonResult @@ -101,6 +101,8 @@ struct JSONDisplaySettings var string afterArrayComma; }; +var private const int MAX_FLOAT_PRECISION; + public function JSON Clone() { return none; @@ -350,6 +352,135 @@ protected final function JSONDisplaySettings IndentSettings( return indentedSettings; } +public function bool ParseIntoSelfWith(Parser parser) +{ + return false; +} + +public final function bool ParseIntoSelf(Text source) +{ + local bool successfullyParsed; + local Parser jsonParser; + jsonParser = _.text.Parse(source); + successfullyParsed = ParseIntoSelfWith(jsonParser); + _.memory.Free(jsonParser); + return successfullyParsed; +} + +public final function bool ParseIntoSelfString(string source) +{ + local bool successfullyParsed; + local Parser jsonParser; + jsonParser = _.text.ParseString(source); + successfullyParsed = ParseIntoSelfWith(jsonParser); + _.memory.Free(jsonParser); + return successfullyParsed; +} + +public final function bool ParseIntoSelfRaw(array rawSource) +{ + local bool successfullyParsed; + local Parser jsonParser; + jsonParser = _.text.ParseRaw(rawSource); + successfullyParsed = ParseIntoSelfWith(jsonParser); + _.memory.Free(jsonParser); + return successfullyParsed; +} + +protected final function JStorageAtom ParseAtom(Parser parser) +{ + local Parser.ParserState initState; + local JStorageAtom newAtom; + if (parser == none) return newAtom; + if (!parser.Ok()) return newAtom; + initState = parser.GetCurrentState(); + parser.Skip().Confirm(); + if (parser.MStringLiteral(newAtom.stringValue).Ok()) + { + newAtom.type = JSON_String; + return newAtom; + } + newAtom = ParseLiteral(parser.R()); + if (newAtom.type != JSON_Undefined) { + return newAtom; + } + newAtom = ParseComplex(parser.R()); + if (newAtom.type != JSON_Undefined) { + return newAtom; + } + newAtom = ParseNumber(parser.R()); + if (newAtom.type == JSON_Undefined) { + parser.RestoreState(initState); + } + return newAtom; +} + +protected final function JStorageAtom ParseLiteral(Parser parser) +{ + local JStorageAtom newAtom; + if (parser.Match("null", true).Ok()) + { + newAtom.type = JSON_Null; + return newAtom; + } + if (parser.R().Match("false", true).Ok()) + { + newAtom.type = JSON_Boolean; + return newAtom; + } + if (parser.R().Match("true", true).Ok()) + { + newAtom.type = JSON_Boolean; + newAtom.booleanValue = true; + return newAtom; + } +} + +protected final function JStorageAtom ParseComplex(Parser parser) +{ + local JStorageAtom newAtom; + if (parser.Match("{").Ok()) + { + newAtom.complexValue = _.json.NewObject(); + newAtom.type = JSON_Object; + } + else if (parser.R().Match("[").Ok()) + { + newAtom.complexValue = _.json.NewArray(); + newAtom.type = JSON_Array; + } + if ( newAtom.complexValue != none + && newAtom.complexValue.ParseIntoSelfWith(parser.R())) { + return newAtom; + } + newAtom.type = JSON_Undefined; + newAtom.complexValue = none; + return newAtom; +} + +protected final function JStorageAtom ParseNumber(Parser parser) +{ + local JStorageAtom newAtom; + local Parser.ParserState integerParsedState; + if (!parser.MInteger(newAtom.numberValueAsInt).Ok()) { + return newAtom; + } + newAtom.type = JSON_Number; + integerParsedState = parser.GetCurrentState(); + // For a number check if it is recorded as a float specifically. + // If not - prefer integer for storage. + if ( parser.Match(".").Ok() + || parser.RestoreState(integerParsedState).Match("e", true).Ok()) + { + parser.R().MNumber(newAtom.numberValue); + return newAtom; + } + parser.RestoreState(integerParsedState); + newAtom.numberValue = newAtom.numberValueAsInt; + newAtom.preferIntegerValue = true; + return newAtom; +} + defaultproperties { MAX_FLOAT_PRECISION = 4 diff --git a/sources/Data/JSON/JSONAPI.uc b/sources/Data/JSON/JSONAPI.uc index 8e88fa6..e737f3b 100644 --- a/sources/Data/JSON/JSONAPI.uc +++ b/sources/Data/JSON/JSONAPI.uc @@ -33,6 +33,126 @@ public function JArray newArray() return newArray; } +public function JObject ParseObjectWith(Parser jsonParser) +{ + local JObject result; + result = NewObject(); + if (result == none) { + return none; + } + if (!result.ParseIntoSelfWith(jsonParser)) + { + result.Destroy(); + return none; + } + return result; +} + +public function JObject ParseObject(Text source) +{ + local JObject result; + result = NewObject(); + if (result == none) { + return none; + } + if (!result.ParseIntoSelf(source)) + { + result.Destroy(); + return none; + } + return result; +} + +public function JObject ParseObjectString(string source) +{ + local JObject result; + result = NewObject(); + if (result == none) { + return none; + } + if (!result.ParseIntoSelfString(source)) + { + result.Destroy(); + return none; + } + return result; +} + +public function JObject ParseObjectRaw(array source) +{ + local JObject result; + result = NewObject(); + if (result == none) { + return none; + } + if (!result.ParseIntoSelfRaw(source)) + { + result.Destroy(); + return none; + } + return result; +} + +public function JArray ParseArrayWith(Parser jsonParser) +{ + local JArray result; + result = NewArray(); + if (result == none) { + return none; + } + if (!result.ParseIntoSelfWith(jsonParser)) + { + result.Destroy(); + return none; + } + return result; +} + +public function JArray ParseArray(Text source) +{ + local JArray result; + result = NewArray(); + if (result == none) { + return none; + } + if (!result.ParseIntoSelf(source)) + { + result.Destroy(); + return none; + } + return result; +} + +public function JArray ParseArrayString(string source) +{ + local JArray result; + result = NewArray(); + if (result == none) { + return none; + } + if (!result.ParseIntoSelfString(source)) + { + result.Destroy(); + return none; + } + return result; +} + +public function JArray ParseArrayRaw(array source) +{ + local JArray result; + result = NewArray(); + if (result == none) { + return none; + } + if (!result.ParseIntoSelfRaw(source)) + { + result.Destroy(); + return none; + } + return result; +} + defaultproperties { } \ No newline at end of file diff --git a/sources/Data/JSON/Tests/TEST_JSON.uc b/sources/Data/JSON/Tests/TEST_JSON.uc index 95e1d38..ec581f4 100644 --- a/sources/Data/JSON/Tests/TEST_JSON.uc +++ b/sources/Data/JSON/Tests/TEST_JSON.uc @@ -21,6 +21,8 @@ class TEST_JSON extends TestCase abstract; +var string preparedJObjectString; + protected static function TESTS() { local JObject jsonData; @@ -31,6 +33,7 @@ protected static function TESTS() Test_JSONComparison(); Test_JSONCloning(); Test_JSONSetComplexValues(); + Test_JSONParsing(); } protected static function Test_ObjectGetSetRemove() @@ -1003,11 +1006,11 @@ protected static function JObject Prepare_FoldedObject() { local JObject testObject; testObject = _().json.NewObject(); - testObject.SetNumber("some_var", 7.32); + testObject.SetNumber("some_var", -7.32); testObject.SetString("another_var", "aye!"); testObject.CreateObject("innerObject"); testObject.GetObject("innerObject").SetBoolean("my_bool", true) - .SetInteger("my_int", 9823452).CreateArray("array"); + .SetInteger("my_int", -9823452).CreateArray("array"); testObject.GetObject("innerObject").GetArray("array").AddClass(class'Actor') .AddBoolean(false).AddNull().AddObject().AddNumber(56.6); testObject.GetObject("innerObject").GetArray("array").GetObject(3) @@ -1161,7 +1164,279 @@ protected static function Test_JSONSetComplexValues() != original.GetObject("innerObject").GetArray("array")); } +protected static function Test_JSONParsing() +{ + Context("Testing parsing JSON data."); + SubTest_JSONObjectParsingWithParser(); + SubTest_JSONArrayParsingWithParser(); + SubTest_JSONObjectParsingText(); + SubTest_JSONArrayParsingText(); + SubTest_JSONObjectParsingRaw(); + SubTest_JSONArrayParsingRaw(); + SubTest_JSONObjectParsingString(); + SubTest_JSONArrayParsingString(); + + Issue("Complex JSON object is incorrectly parsed."); + Test_ExpectTrue(Prepare_FoldedObject().IsEqual(_().json.ParseObjectWith( + _().text.ParseString(default.preparedJObjectString)))); + Test_ExpectTrue(Prepare_FoldedObject().IsEqual(_().json.ParseObject( + _().text.FromString(default.preparedJObjectString)))); + Test_ExpectTrue(Prepare_FoldedObject().IsEqual(_().json.ParseObjectRaw( + _().text.StringToRaw(default.preparedJObjectString)))); + Test_ExpectTrue(Prepare_FoldedObject().IsEqual( + _().json.ParseObjectString(default.preparedJObjectString))); +} + +protected static function SubTest_JSONObjectParsingWithParser() +{ + local JObject parsedObject; + Issue("`ParseObjectWith()` cannot parse empty JSON object."); + parsedObject = _().json.ParseObjectWith(_().text.ParseString("{}")); + TEST_ExpectNotNone(parsedObject); + TEST_ExpectTrue(parsedObject.GetKeys().length == 0); + + Issue("`ParseObjectWith()` doesn't report error when parsing an incorrect" + @ "object."); + parsedObject = _().json.ParseObjectWith(_().text.ParseString("{}")); + TEST_ExpectNone(_().json.ParseObjectWith(_().text.ParseString(""))); + TEST_ExpectNone(_().json.ParseObjectWith( + _().text.ParseString("{\"var\": 89"))); + TEST_ExpectNone(_().json.ParseObjectWith( + _().text.ParseString("\"var\": 89}"))); + TEST_ExpectNone(_().json.ParseObjectWith( + _().text.ParseString("{var:false}"))); + + Issue("`ParseObjectWith()` cannot parse simple JSON object."); + parsedObject = _().json.ParseObjectWith( + _().text.ParseString("{\"var\":7 ,\"str\":\"aye!~\"}")); + TEST_ExpectNotNone(parsedObject); + TEST_ExpectTrue(parsedObject.GetNumber("var") == 7); + TEST_ExpectTrue(parsedObject.GetString("str") == "aye!~"); + + Issue("`JObject.ParseIntoSelfWith()` cannot add new properties."); + TEST_ExpectTrue(parsedObject.ParseIntoSelfWith( + _().text.ParseString("{\"newVar\": true}"))); + TEST_ExpectTrue(parsedObject.GetBoolean("newVar")); +} + +protected static function SubTest_JSONArrayParsingWithParser() +{ + local JArray parsedArray; + Issue("`ParseArrayWith()` cannot parse empty JSON array."); + parsedArray = _().json.ParseArrayWith(_().text.ParseString("[]")); + TEST_ExpectNotNone(parsedArray); + TEST_ExpectTrue(parsedArray.GetLength() == 0); + + Issue("`ParseArrayWith()` doesn't report error when parsing an incorrect" + @ "object."); + parsedArray = _().json.ParseArrayWith(_().text.ParseString("[]")); + TEST_ExpectNone(_().json.ParseArrayWith(_().text.ParseString(""))); + TEST_ExpectNone(_().json.ParseArrayWith(_().text.ParseString("[89"))); + TEST_ExpectNone(_().json.ParseArrayWith(_().text.ParseString("89]"))); + TEST_ExpectNone(_().json.ParseArrayWith( + _().text.ParseString("[false null]"))); + + Issue("`ParseArrayWith()` cannot parse simple JSON array."); + parsedArray = _().json.ParseArrayWith( + _().text.ParseString("[null, 67.349e2, \"what\" , {}]")); + TEST_ExpectNotNone(parsedArray); + TEST_ExpectTrue(parsedArray.IsNull(0)); + TEST_ExpectTrue(parsedArray.GetNumber(1) == 6734.9); + TEST_ExpectTrue(parsedArray.GetString(2) == "what"); + TEST_ExpectTrue(parsedArray.GetObject(3).GetKeys().length == 0); + + Issue("`JArray.ParseIntoSelfWith()` cannot add new elements."); + TEST_ExpectTrue(parsedArray.ParseIntoSelfWith( + _().text.ParseString("[\"huh\", Null]"))); + TEST_ExpectTrue(parsedArray.GetString(4) == "huh"); + TEST_ExpectTrue(parsedArray.IsNull(5)); +} + +protected static function SubTest_JSONObjectParsingText() +{ + local JObject parsedObject; + Issue("`ParseObject()` cannot parse empty JSON object."); + parsedObject = _().json.ParseObject(_().text.FromString("{}")); + TEST_ExpectNotNone(parsedObject); + TEST_ExpectTrue(parsedObject.GetKeys().length == 0); + + Issue("`ParseObject()` doesn't report error when parsing an incorrect" + @ "object."); + parsedObject = _().json.ParseObject(_().text.FromString("{}")); + TEST_ExpectNone(_().json.ParseObject(_().text.FromString(""))); + TEST_ExpectNone(_().json.ParseObject(_().text.FromString("{\"var\": 89"))); + TEST_ExpectNone(_().json.ParseObject(_().text.FromString("\"var\": 89}"))); + TEST_ExpectNone(_().json.ParseObject(_().text.FromString("{var:false}"))); + + Issue("`ParseObject()` cannot parse simple JSON object."); + parsedObject = _().json.ParseObject( + _().text.FromString("{\"var\":7 ,\"str\":\"aye!~\"}")); + TEST_ExpectNotNone(parsedObject); + TEST_ExpectTrue(parsedObject.GetNumber("var") == 7); + TEST_ExpectTrue(parsedObject.GetString("str") == "aye!~"); + + Issue("`JObject.ParseIntoSelf()` cannot add new properties."); + TEST_ExpectTrue(parsedObject.ParseIntoSelf( + _().text.FromString("{\"newVar\": true}"))); + TEST_ExpectTrue(parsedObject.GetBoolean("newVar")); +} + +protected static function SubTest_JSONArrayParsingText() +{ + local JArray parsedArray; + Issue("`ParseArray()` cannot parse empty JSON array."); + parsedArray = _().json.ParseArray(_().text.FromString("[]")); + TEST_ExpectNotNone(parsedArray); + TEST_ExpectTrue(parsedArray.GetLength() == 0); + + Issue("`ParseArray()` doesn't report error when parsing an incorrect" + @ "object."); + parsedArray = _().json.ParseArray(_().text.FromString("[]")); + TEST_ExpectNone(_().json.ParseArray(_().text.FromString(""))); + TEST_ExpectNone(_().json.ParseArray(_().text.FromString("[89"))); + TEST_ExpectNone(_().json.ParseArray(_().text.FromString("89]"))); + TEST_ExpectNone(_().json.ParseArray(_().text.FromString("[false null]"))); + + Issue("`ParseArray()` cannot parse simple JSON array."); + parsedArray = _().json.ParseArray( + _().text.FromString("[null, 67.349e2, \"what\" , {}]")); + TEST_ExpectNotNone(parsedArray); + TEST_ExpectTrue(parsedArray.IsNull(0)); + TEST_ExpectTrue(parsedArray.GetNumber(1) == 6734.9); + TEST_ExpectTrue(parsedArray.GetString(2) == "what"); + TEST_ExpectTrue(parsedArray.GetObject(3).GetKeys().length == 0); + + Issue("`JArray.ParseIntoSelf()` cannot add new elements."); + TEST_ExpectTrue(parsedArray.ParseIntoSelf( + _().text.FromString("[\"huh\", Null]"))); + TEST_ExpectTrue(parsedArray.GetString(4) == "huh"); + TEST_ExpectTrue(parsedArray.IsNull(5)); +} + +protected static function SubTest_JSONObjectParsingRaw() +{ + local JObject parsedObject; + Issue("`ParseObjectRaw()` cannot parse empty JSON object."); + parsedObject = _().json.ParseObjectRaw(_().text.StringToRaw("{}")); + TEST_ExpectNotNone(parsedObject); + TEST_ExpectTrue(parsedObject.GetKeys().length == 0); + + Issue("`ParseObjectRaw()` doesn't report error when parsing an incorrect" + @ "object."); + parsedObject = _().json.ParseObjectRaw(_().text.StringToRaw("{}")); + TEST_ExpectNone(_().json.ParseObjectRaw(_().text.StringToRaw(""))); + TEST_ExpectNone(_().json.ParseObjectRaw( + _().text.StringToRaw("{\"var\": 89"))); + TEST_ExpectNone(_().json.ParseObjectRaw( + _().text.StringToRaw("\"var\": 89}"))); + TEST_ExpectNone(_().json.ParseObjectRaw( + _().text.StringToRaw("{var:false}"))); + + Issue("`ParseObjectRaw()` cannot parse simple JSON object."); + parsedObject = _().json.ParseObjectRaw( + _().text.StringToRaw("{\"var\":7 ,\"str\":\"aye!~\"}")); + TEST_ExpectNotNone(parsedObject); + TEST_ExpectTrue(parsedObject.GetNumber("var") == 7); + TEST_ExpectTrue(parsedObject.GetString("str") == "aye!~"); + + Issue("`JObject.ParseIntoSelfRaw()` cannot add new properties."); + TEST_ExpectTrue(parsedObject.ParseIntoSelfRaw( + _().text.StringToRaw("{\"newVar\": true}"))); + TEST_ExpectTrue(parsedObject.GetBoolean("newVar")); +} + +protected static function SubTest_JSONArrayParsingRaw() +{ + local JArray parsedArray; + Issue("`ParseArrayRaw()` cannot parse empty JSON array."); + parsedArray = _().json.ParseArrayRaw(_().text.StringToRaw("[]")); + TEST_ExpectNotNone(parsedArray); + TEST_ExpectTrue(parsedArray.GetLength() == 0); + + Issue("`ParseArrayRaw()` doesn't report error when parsing an incorrect" + @ "object."); + parsedArray = _().json.ParseArrayRaw(_().text.StringToRaw("[]")); + TEST_ExpectNone(_().json.ParseArrayRaw(_().text.StringToRaw(""))); + TEST_ExpectNone(_().json.ParseArrayRaw(_().text.StringToRaw("[89"))); + TEST_ExpectNone(_().json.ParseArrayRaw(_().text.StringToRaw("89]"))); + TEST_ExpectNone(_().json.ParseArrayRaw( + _().text.StringToRaw("[false null]"))); + + Issue("`ParseArrayRaw()` cannot parse simple JSON array."); + parsedArray = _().json.ParseArrayRaw( + _().text.StringToRaw("[null, 67.349e2, \"what\" , {}]")); + TEST_ExpectNotNone(parsedArray); + TEST_ExpectTrue(parsedArray.IsNull(0)); + TEST_ExpectTrue(parsedArray.GetNumber(1) == 6734.9); + TEST_ExpectTrue(parsedArray.GetString(2) == "what"); + TEST_ExpectTrue(parsedArray.GetObject(3).GetKeys().length == 0); + + Issue("`JArray.ParseIntoSelfRaw()` cannot add new elements."); + TEST_ExpectTrue(parsedArray.ParseIntoSelfRaw( + _().text.StringToRaw("[\"huh\", Null]"))); + TEST_ExpectTrue(parsedArray.GetString(4) == "huh"); + TEST_ExpectTrue(parsedArray.IsNull(5)); +} + +protected static function SubTest_JSONObjectParsingString() +{ + local JObject parsedObject; + Issue("`ParseObjectString()` cannot parse empty JSON object."); + parsedObject = _().json.ParseObjectString("{}"); + TEST_ExpectNotNone(parsedObject); + TEST_ExpectTrue(parsedObject.GetKeys().length == 0); + + Issue("`ParseObjectString()` doesn't report error when parsing an incorrect" + @ "object."); + parsedObject = _().json.ParseObjectString("{}"); + TEST_ExpectNone(_().json.ParseObjectString("")); + TEST_ExpectNone(_().json.ParseObjectString("{\"var\": 89")); + TEST_ExpectNone(_().json.ParseObjectString("\"var\": 89}")); + TEST_ExpectNone(_().json.ParseObjectString("{var:false}")); + + Issue("`ParseObjectString()` cannot parse simple JSON object."); + parsedObject = _().json.ParseObjectString("{\"var\":7 ,\"str\":\"aye!~\"}"); + TEST_ExpectNotNone(parsedObject); + TEST_ExpectTrue(parsedObject.GetNumber("var") == 7); + TEST_ExpectTrue(parsedObject.GetString("str") == "aye!~"); + + Issue("`JObject.ParseIntoSelfString()` cannot add new properties."); + TEST_ExpectTrue(parsedObject.ParseIntoSelfString("{\"newVar\": true}")); + TEST_ExpectTrue(parsedObject.GetBoolean("newVar")); +} + +protected static function SubTest_JSONArrayParsingString() +{ + local JArray parsedArray; + Issue("`ParseArrayString()` cannot parse empty JSON array."); + parsedArray = _().json.ParseArrayString("[]"); + TEST_ExpectNotNone(parsedArray); + TEST_ExpectTrue(parsedArray.GetLength() == 0); + + Issue("`ParseArrayString()` doesn't report error when parsing an incorrect" + @ "object."); + parsedArray = _().json.ParseArrayString("[]"); + TEST_ExpectNone(_().json.ParseArrayString("")); + TEST_ExpectNone(_().json.ParseArrayString("[89")); + TEST_ExpectNone(_().json.ParseArrayString("89]")); + TEST_ExpectNone(_().json.ParseArrayString("[false null]")); + + Issue("`ParseArrayString()` cannot parse simple JSON array."); + parsedArray = _().json.ParseArrayString("[null, 67.349e2, \"what\" , {}]"); + TEST_ExpectNotNone(parsedArray); + TEST_ExpectTrue(parsedArray.IsNull(0)); + TEST_ExpectTrue(parsedArray.GetNumber(1) == 6734.9); + TEST_ExpectTrue(parsedArray.GetString(2) == "what"); + TEST_ExpectTrue(parsedArray.GetObject(3).GetKeys().length == 0); + + Issue("`JArray.ParseIntoSelfString()` cannot add new elements."); + TEST_ExpectTrue(parsedArray.ParseIntoSelfString("[\"huh\", Null]")); + TEST_ExpectTrue(parsedArray.GetString(4) == "huh"); + TEST_ExpectTrue(parsedArray.IsNull(5)); +} + defaultproperties { caseName = "JSON" + preparedJObjectString = "{\"innerObject\":{\"my_bool\":true,\"array\":[\"Engine.Actor\",false,null,{\"something here\":\"yes\",\"maybe\":0.003},56.6],\"one more\":{\"nope\":324532,\"whatever\":false,\"o rly?\":\"ya rly\"},\"my_int\":-9823452},\"some_var\":-7.32,\"another_var\":\"aye!\"}" } \ No newline at end of file