Change file structure of Acedia

Improves grouping of some files in project's directories.
This commit is contained in:
Anton Tarasenko 2020-04-09 14:43:45 +07:00
commit 97569f9568
21 changed files with 0 additions and 0 deletions

View file

@ -0,0 +1,351 @@
/**
* This class implements JSON array storage capabilities.
* Array stores ordered JSON values that can be referred by their index.
* It can contain any mix of JSON value types and cannot have any gaps,
* i.e. in array of length N, there must be a valid value for all indices
* from 0 to N-1.
* Copyright 2020 Anton Tarasenko
*------------------------------------------------------------------------------
* This file is part of Acedia.
*
* Acedia is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License, or
* (at your option) any later version.
*
* Acedia is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Acedia. If not, see <https://www.gnu.org/licenses/>.
*/
class JArray extends JSON;
// Data will simply be stored as an array of JSON values
var private array<JStorageAtom> data;
// Return type of value stored at a given index.
// Returns `JSON_Undefined` if and only if given index is out of bounds.
public final function JType GetTypeOf(int index)
{
if (index < 0) return JSON_Undefined;
if (index >= data.length) return JSON_Undefined;
return data[index].type;
}
// Returns current length of this array.
public final function int GetLength()
{
return data.length;
}
// Changes length of this array.
// In case of the increase - fills new indices with `null` values.
public final function SetLength(int newLength)
{
local int i;
local int oldLength;
oldLength = data.length;
data.length = newLength;
if (oldLength >= newLength)
{
return;
}
i = oldLength;
while (i < newLength)
{
SetNull(i);
i += 1;
}
}
// Following functions are getters for various types of variables.
// Getter for null value simply checks if it's null
// and returns true/false as a result.
// Getters for simple types (number, string, boolean) can have optional
// default value specified, that will be returned if requested variable
// doesn't exist or has a different type.
// Getters for object and array types don't take default values and
// will simply return `none`.
public final function float GetNumber(int index, optional float defaultValue)
{
if (index < 0) return defaultValue;
if (index >= data.length) return defaultValue;
if (data[index].type != JSON_Number) return defaultValue;
return data[index].numberValue;
}
public final function string GetString(int index, optional string defaultValue)
{
if (index < 0) return defaultValue;
if (index >= data.length) return defaultValue;
if (data[index].type != JSON_String) return defaultValue;
return data[index].stringValue;
}
public final function bool GetBoolean(int index, optional bool defaultValue)
{
if (index < 0) return defaultValue;
if (index >= data.length) return defaultValue;
if (data[index].type != JSON_Boolean) return defaultValue;
return data[index].booleanValue;
}
public final function bool IsNull(int index)
{
if (index < 0) return false;
if (index >= data.length) return false;
return (data[index].type == JSON_Null);
}
public final function JArray GetArray(int index)
{
if (index < 0) return none;
if (index >= data.length) return none;
if (data[index].type != JSON_Array) return none;
return JArray(data[index].complexValue);
}
public final function JObject GetObject(int index)
{
if (index < 0) return none;
if (index >= data.length) return none;
if (data[index].type != JSON_Object) return none;
return JObject(data[index].complexValue);
}
// Following functions provide simple setters for boolean, string, number
// and null values.
// If passed index is negative - does nothing.
// If index lies beyond array length (`>= GetLength()`), -
// these functions will expand array in the same way as `GetLength()` function.
// This can be prevented by setting optional parameter `preventExpansion` to
// `false` (nothing will be done in this case).
// They return object itself, allowing user to chain calls like this:
// `array.SetNumber("num1", 1).SetNumber("num2", 2);`.
public final function JArray SetNumber
(
int index,
float value,
optional bool preventExpansion
)
{
local JStorageAtom newStorageValue;
if (index < 0) return self;
if (index >= data.length)
{
if (preventExpansion)
{
return self;
}
else
{
SetLength(index + 1);
}
}
newStorageValue.type = JSON_Number;
newStorageValue.numberValue = value;
data[index] = newStorageValue;
return self;
}
public final function JArray SetString
(
int index,
string value,
optional bool preventExpansion
)
{
local JStorageAtom newStorageValue;
if (index < 0) return self;
if (index >= data.length)
{
if (preventExpansion)
{
return self;
}
else
{
SetLength(index + 1);
}
}
newStorageValue.type = JSON_String;
newStorageValue.stringValue = value;
data[index] = newStorageValue;
return self;
}
public final function JArray SetBoolean
(
int index,
bool value,
optional bool preventExpansion
)
{
local JStorageAtom newStorageValue;
if (index < 0) return self;
if (index >= data.length)
{
if (preventExpansion)
{
return self;
}
else
{
SetLength(index + 1);
}
}
newStorageValue.type = JSON_Boolean;
newStorageValue.booleanValue = value;
data[index] = newStorageValue;
return self;
}
public final function JArray SetNull
(
int index,
optional bool preventExpansion
)
{
local JStorageAtom newStorageValue;
if (index < 0) return self;
if (index >= data.length)
{
if (preventExpansion)
{
return self;
}
else
{
SetLength(index + 1);
}
}
newStorageValue.type = JSON_Null;
data[index] = newStorageValue;
return self;
}
// JSON array and object types don't have setters, but instead have
// functions to create a new, empty array/object under a certain name.
// If passed index is negative - does nothing.
// If index lies beyond array length (`>= GetLength()`), -
// these functions will expand array in the same way as `GetLength()` function.
// This can be prevented by setting optional parameter `preventExpansion` to
// `false` (nothing will be done in this case).
// They return object itself, allowing user to chain calls like this:
// `array.CreateObject("sub object").CreateArray("sub array");`.
public final function JArray CreateArray
(
int index,
optional bool preventExpansion
)
{
local JStorageAtom newStorageValue;
if (index < 0) return self;
if (index >= data.length)
{
if (preventExpansion)
{
return self;
}
else
{
SetLength(index + 1);
}
}
newStorageValue.type = JSON_Array;
newStorageValue.complexValue = _.json.newArray();
data[index] = newStorageValue;
return self;
}
public final function JArray CreateObject
(
int index,
optional bool preventExpansion
)
{
local JStorageAtom newStorageValue;
if (index < 0) return self;
if (index >= data.length)
{
if (preventExpansion)
{
return self;
}
else
{
SetLength(index + 1);
}
}
newStorageValue.type = JSON_Object;
newStorageValue.complexValue = _.json.newObject();
data[index] = newStorageValue;
return self;
}
// Wrappers for setter functions that don't take index or
// `preventExpansion` parameters and add/create value at the end of the array.
public final function JArray AddNumber(float value)
{
return SetNumber(data.length, value);
}
public final function JArray AddString(string value)
{
return SetString(data.length, value);
}
public final function JArray AddBoolean(bool value)
{
return SetBoolean(data.length, value);
}
public final function JArray AddNull()
{
return SetNull(data.length);
}
public final function JArray AddArray()
{
return CreateArray(data.length);
}
public final function JArray AddObject()
{
return CreateObject(data.length);
}
// Removes up to `amount` (minimum of `1`) of values, starting from
// a given index.
// If `index` falls outside array boundaries - nothing will be done.
// Returns `true` if value was actually removed and `false` if it didn't exist.
public final function bool RemoveValue(int index, optional int amount)
{
if (index < 0) return false;
if (index >= data.length) return false;
amount = Max(amount, 1);
amount = Min(amount, data.length - index);
data.Remove(index, amount);
return true;
}
defaultproperties
{
}

View file

@ -0,0 +1,265 @@
/**
* This class implements JSON object storage capabilities.
* Whenever one wants to store JSON data, they need to define such object.
* It stores name-value pairs, where names are strings and values can be:
* ~ Boolean, string, null or number (float in this implementation) data;
* ~ Other JSON objects;
* ~ JSON Arrays (see `JArray` class).
*
* This implementation provides getters and setters for boolean, string,
* null or number types that allow to freely set and fetch their values
* by name.
* JSON objects and arrays can be fetched by getters, but you cannot
* add existing object or array to another object. Instead one has to create
* a new, empty object with a certain name and then fill it with data.
* This allows to avoid loop situations, where object is contained in itself.
* Functions to remove existing values are also provided and are applicable
* to all variable types.
* Setters can also be used to overwrite any value by a different value,
* even of a different type.
* Copyright 2020 Anton Tarasenko
*------------------------------------------------------------------------------
* This file is part of Acedia.
*
* Acedia is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License, or
* (at your option) any later version.
*
* Acedia is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Acedia. If not, see <https://www.gnu.org/licenses/>.
*/
class JObject extends JSON;
// We will store all our properties as a simple array of name-value pairs.
struct JProperty
{
var string name;
var JStorageAtom value;
};
var private array<JProperty> properties;
// Returns index of name-value pair in `properties` for a given name.
// Returns `-1` if such a pair does not exist.
private final function int GetPropertyIndex(string name)
{
local int i;
for (i = 0; i < properties.length; i += 1)
{
if (name == properties[i].name)
{
return i;
}
}
return -1;
}
// Returns `JType` of a variable with a given name in our properties.
// This function can be used to check if certain variable exists
// in this object, since if such variable does not exist -
// function will return `JSON_Undefined`.
public final function JType GetTypeOf(string name)
{
local int index;
index = GetPropertyIndex(name);
if (index < 0) return JSON_Undefined;
return properties[index].value.type;
}
// Following functions are getters for various types of variables.
// Getter for null value simply checks if it's null
// and returns true/false as a result.
// Getters for simple types (number, string, boolean) can have optional
// default value specified, that will be returned if requested variable
// doesn't exist or has a different type.
// Getters for object and array types don't take default values and
// will simply return `none`.
public final function float GetNumber(string name, optional float defaultValue)
{
local int index;
index = GetPropertyIndex(name);
if (index < 0) return defaultValue;
if (properties[index].value.type != JSON_Number) return defaultValue;
return properties[index].value.numberValue;
}
public final function string GetString
(
string name,
optional string defaultValue
)
{
local int index;
index = GetPropertyIndex(name);
if (index < 0) return defaultValue;
if (properties[index].value.type != JSON_String) return defaultValue;
return properties[index].value.stringValue;
}
public final function bool GetBoolean(string name, optional bool defaultValue)
{
local int index;
index = GetPropertyIndex(name);
if (index < 0) return defaultValue;
if (properties[index].value.type != JSON_Boolean) return defaultValue;
return properties[index].value.booleanValue;
}
public final function bool IsNull(string name)
{
local int index;
index = GetPropertyIndex(name);
if (index < 0) return false;
if (properties[index].value.type != JSON_Null) return false;
return (properties[index].value.type == JSON_Null);
}
public final function JArray GetArray(string name)
{
local int index;
index = GetPropertyIndex(name);
if (index < 0) return none;
if (properties[index].value.type != JSON_Array) return none;
return JArray(properties[index].value.complexValue);
}
public final function JObject GetObject(string name)
{
local int index;
index = GetPropertyIndex(name);
if (index < 0) return none;
if (properties[index].value.type != JSON_Object) return none;
return JObject(properties[index].value.complexValue);
}
// Following functions provide simple setters for boolean, string, number
// and null values.
// They return object itself, allowing user to chain calls like this:
// `object.SetNumber("num1", 1).SetNumber("num2", 2);`.
public final function JObject SetNumber(string name, float value)
{
local int index;
local JProperty newProperty;
index = GetPropertyIndex(name);
if (index < 0)
{
index = properties.length;
}
newProperty.name = name;
newProperty.value.type = JSON_Number;
newProperty.value.numberValue = value;
properties[index] = newProperty;
return self;
}
public final function JObject SetString(string name, string value)
{
local int index;
local JProperty newProperty;
index = GetPropertyIndex(name);
if (index < 0)
{
index = properties.length;
}
newProperty.name = name;
newProperty.value.type = JSON_String;
newProperty.value.stringValue = value;
properties[index] = newProperty;
return self;
}
public final function JObject SetBoolean(string name, bool value)
{
local int index;
local JProperty newProperty;
index = GetPropertyIndex(name);
if (index < 0)
{
index = properties.length;
}
newProperty.name = name;
newProperty.value.type = JSON_Boolean;
newProperty.value.booleanValue = value;
properties[index] = newProperty;
return self;
}
public final function JObject SetNull(string name)
{
local int index;
local JProperty newProperty;
index = GetPropertyIndex(name);
if (index < 0)
{
index = properties.length;
}
newProperty.name = name;
newProperty.value.type = JSON_Null;
properties[index] = newProperty;
return self;
}
// JSON array and object types don't have setters, but instead have
// functions to create a new, empty array/object under a certain name.
// They return object itself, allowing user to chain calls like this:
// `object.CreateObject("folded object").CreateArray("names list");`.
public final function JObject CreateArray(string name)
{
local int index;
local JProperty newProperty;
index = GetPropertyIndex(name);
if (index < 0)
{
index = properties.length;
}
newProperty.name = name;
newProperty.value.type = JSON_Array;
newProperty.value.complexValue = _.json.newArray();
properties[index] = newProperty;
return self;
}
public final function JObject CreateObject(string name)
{
local int index;
local JProperty newProperty;
index = GetPropertyIndex(name);
if (index < 0)
{
index = properties.length;
}
newProperty.name = name;
newProperty.value.type = JSON_Object;
newProperty.value.complexValue = _.json.newObject();
properties[index] = newProperty;
return self;
}
// Removes values with a given name.
// Returns `true` if value was actually removed and `false` if it didn't exist.
public final function bool RemoveValue(string name)
{
local int index;
index = GetPropertyIndex(name);
if (index < 0) return false;
properties.Remove(index, 1);
return true;
}
defaultproperties
{
}

View file

@ -0,0 +1,84 @@
/**
* JSON is an open standard file format, and data interchange format,
* that uses human-readable text to store and transmit data objects
* consisting of namevalue pairs and array data types.
* For more information refer to https://en.wikipedia.org/wiki/JSON
* This is a base class for implementation of JSON data storage for Acedia.
* It does not implement parsing and printing from/into human-readable
* text representation, just provides means to store such information.
*
* JSON data is stored as an object (represented via `JSONObject`) that
* contains a set of name-value pairs, where value can be
* a number, string, boolean value, another object or
* an array (represented by `JSONArray`).
* Copyright 2020 Anton Tarasenko
*------------------------------------------------------------------------------
* This file is part of Acedia.
*
* Acedia is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License, or
* (at your option) any later version.
*
* Acedia is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Acedia. If not, see <https://www.gnu.org/licenses/>.
*/
class JSON extends AcediaActor
abstract;
// Enumeration for possible types of JSON values.
enum JType
{
// Technical type, used to indicate that requested value is missing.
// Undefined values are not part of JSON format.
JSON_Undefined,
// An empty value, in teste representation defined by a single word "null".
JSON_Null,
// A number, recorded as a float.
// JSON itself doesn't specify whether number is an integer or float.
JSON_Number,
// A string.
JSON_String,
// A bool value.
JSON_Boolean,
// Array of other JSON values, stored without names;
// Single array can contain any mix of value types.
JSON_Array,
// Another JSON object, i.e. associative array of name-value pairs
JSON_Object
};
// Stores a single JSON value
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;
// Used for storing both JSON objects and arrays.
var protected JSON complexValue;
};
// TODO: Rewrite JSON object to use more efficient storage data structures
// that will support subtypes:
// ~ Number: byte, int, float
// ~ String: string, class
// (maybe move to auto generated code?).
// TODO: Add cleanup queue to efficiently and without crashes clean up
// removed objects.
// TODO: Add `JValue` - a reference type for number / string / boolean / null
// TODO: Add accessors for last values.
// TODO: Add path-getters.
// TODO: Add iterators.
// TODO: Add parsing/printing.
// TODO: Add functions for deep copy.
defaultproperties
{
}

View file

@ -0,0 +1,41 @@
/**
* Singleton is an auxiliary class, meant to be used as a base for others,
* that allows for only one instance of it to exist.
* To make sure your child class properly works, either don't overload
* 'PreBeginPlay' or make sure to call it's parent's version.
* Copyright 2019 Anton Tarasenko
*------------------------------------------------------------------------------
* This file is part of Acedia.
*
* Acedia is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License, or
* (at your option) any later version.
*
* Acedia is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Acedia. If not, see <https://www.gnu.org/licenses/>.
*/
class JSONAPI extends Singleton;
public function JObject newObject()
{
local JObject newObject;
newObject = Spawn(class'JObject');
return newObject;
}
public function JArray newArray()
{
local JArray newArray;
newArray = Spawn(class'JArray');
return newArray;
}
defaultproperties
{
}

View file

@ -0,0 +1,711 @@
/**
* Set of tests for JSON data storage, implemented via
* `JObject` and `JArray`.
* Copyright 2020 Anton Tarasenko
*------------------------------------------------------------------------------
* This file is part of Acedia.
*
* Acedia is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License, or
* (at your option) any later version.
*
* Acedia is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Acedia. If not, see <https://www.gnu.org/licenses/>.
*/
class TEST_JSON extends TestCase
abstract;
protected static function TESTS()
{
local JObject jsonData;
jsonData = _().json.newObject();
Test_ObjectGetSetRemove();
Test_ArrayGetSetRemove();
}
protected static function Test_ObjectGetSetRemove()
{
SubTest_Undefined();
SubTest_StringGetSetRemove();
SubTest_BooleanGetSetRemove();
SubTest_NumberGetSetRemove();
SubTest_NullGetSetRemove();
SubTest_MultipleVariablesGetSet();
SubTest_Object();
}
protected static function Test_ArrayGetSetRemove()
{
Context("Testing get/set/remove functions for JSON arrays");
SubTest_ArrayUndefined();
SubTest_ArrayStringGetSetRemove();
SubTest_ArrayBooleanGetSetRemove();
SubTest_ArrayNumberGetSetRemove();
SubTest_ArrayNullGetSetRemove();
SubTest_ArrayMultipleVariablesStorage();
SubTest_ArrayMultipleVariablesRemoval();
SubTest_ArrayRemovingMultipleVariablesAtOnce();
SubTest_ArrayExpansions();
}
protected static function SubTest_Undefined()
{
local JObject testJSON;
testJSON = _().json.newObject();
Context("Testing how `JObject` handles undefined values");
Issue("Undefined variable doesn't have proper type.");
TEST_ExpectTrue(testJSON.GetTypeOf("some_var") == JSON_Undefined);
Issue("There is a variable in an empty object after `GetTypeOf` call.");
TEST_ExpectTrue(testJSON.GetTypeOf("some_var") == JSON_Undefined);
Issue("Getters don't return default values for undefined variables.");
TEST_ExpectTrue(testJSON.GetNumber("some_var", 0) == 0);
TEST_ExpectTrue(testJSON.GetString("some_var", "") == "");
TEST_ExpectTrue(testJSON.GetBoolean("some_var", false) == false);
TEST_ExpectNone(testJSON.GetObject("some_var"));
TEST_ExpectNone(testJSON.GetArray("some_var"));
}
protected static function SubTest_BooleanGetSetRemove()
{
local JObject testJSON;
testJSON = _().json.newObject();
testJSON.SetBoolean("some_boolean", true);
Context("Testing `JObject`'s get/set/remove functions for" @
"boolean variables");
Issue("Boolean type isn't properly set by `SetBoolean`");
TEST_ExpectTrue(testJSON.GetTypeOf("some_boolean") == JSON_Boolean);
Issue("Variable value is incorrectly assigned by `SetBoolean`");
TEST_ExpectTrue(testJSON.GetBoolean("some_boolean") == true);
Issue("Variable value isn't correctly reassigned by `SetBoolean`");
testJSON.SetBoolean("some_boolean", false);
TEST_ExpectTrue(testJSON.GetBoolean("some_boolean") == false);
Issue( "Getting boolean variable as a wrong type" @
"doesn't yield default value");
TEST_ExpectTrue(testJSON.GetNumber("some_boolean", 7) == 7);
Issue("Boolean variable isn't being properly removed");
testJSON.RemoveValue("some_boolean");
TEST_ExpectTrue(testJSON.GetTypeOf("some_boolean") == JSON_Undefined);
Issue( "Getters don't return default value for missing key that" @
"previously stored boolean value, that got removed");
TEST_ExpectTrue(testJSON.GetBoolean("some_boolean", true) == true);
}
protected static function SubTest_StringGetSetRemove()
{
local JObject testJSON;
testJSON = _().json.newObject();
testJSON.SetString("some_string", "first string");
Context("Testing `JObject`'s get/set/remove functions for" @
"string variables");
Issue("String type isn't properly set by `SetString`");
TEST_ExpectTrue(testJSON.GetTypeOf("some_string") == JSON_String);
Issue("Value is incorrectly assigned by `SetString`");
TEST_ExpectTrue(testJSON.GetString("some_string") == "first string");
Issue( "Providing default variable value makes 'GetString'" @
"return wrong value");
TEST_ExpectTrue( testJSON.GetString("some_string", "alternative")
== "first string");
Issue("Variable value isn't correctly reassigned by `SetString`");
testJSON.SetString("some_string", "new string!~");
TEST_ExpectTrue(testJSON.GetString("some_string") == "new string!~");
Issue( "Getting string variable as a wrong type" @
"doesn't yield default value");
TEST_ExpectTrue(testJSON.GetBoolean("some_string", true) == true);
Issue("String variable isn't being properly removed");
testJSON.RemoveValue("some_string");
TEST_ExpectTrue(testJSON.GetTypeOf("some_string") == JSON_Undefined);
Issue( "Getters don't return default value for missing key that" @
"previously stored string value, but got removed");
TEST_ExpectTrue(testJSON.GetString("some_string", "other") == "other");
}
protected static function SubTest_NumberGetSetRemove()
{
local JObject testJSON;
testJSON = _().json.newObject();
testJSON.SetNumber("some_number", 3.5);
Context("Testing `JObject`'s get/set/remove functions for" @
"number variables");
Issue("Number type isn't properly set by `SetNumber`");
TEST_ExpectTrue(testJSON.GetTypeOf("some_number") == JSON_Number);
Issue("Value is incorrectly assigned by `SetNumber`");
TEST_ExpectTrue(testJSON.GetNumber("some_number") == 3.5);
Issue( "Providing default variable value makes 'GetNumber'" @
"return wrong value");
TEST_ExpectTrue(testJSON.GetNumber("some_number", 5) == 3.5);
Issue("Variable value isn't correctly reassigned by `SetNumber`");
testJSON.SetNumber("some_number", 7);
TEST_ExpectTrue(testJSON.GetNumber("some_number") == 7);
Issue( "Getting number variable as a wrong type" @
"doesn't yield default value.");
TEST_ExpectTrue(testJSON.GetString("some_number", "default") == "default");
Issue("Number type isn't being properly removed");
testJSON.RemoveValue("some_number");
TEST_ExpectTrue(testJSON.GetTypeOf("some_number") == JSON_Undefined);
Issue( "Getters don't return default value for missing key that" @
"previously stored number value, that got removed");
TEST_ExpectTrue(testJSON.GetNumber("some_number", 13) == 13);
}
protected static function SubTest_NullGetSetRemove()
{
local JObject testJSON;
testJSON = _().json.newObject();
Context("Testing `JObject`'s get/set/remove functions for" @
"null values");
Issue("Undefined variable is incorrectly considered `null`");
TEST_ExpectFalse(testJSON.IsNull("some_var"));
Issue("Number variable is incorrectly considered `null`");
testJSON.SetNumber("some_var", 4);
TEST_ExpectFalse(testJSON.IsNull("some_var"));
Issue("Boolean variable is incorrectly considered `null`");
testJSON.SetBoolean("some_var", true);
TEST_ExpectFalse(testJSON.IsNull("some_var"));
Issue("String variable is incorrectly considered `null`");
testJSON.SetString("some_var", "string");
TEST_ExpectFalse(testJSON.IsNull("some_var"));
Issue("Null value is incorrectly assigned");
testJSON.SetNull("some_var");
TEST_ExpectTrue(testJSON.IsNull("some_var"));
Issue("Null type isn't properly set by `SetNumber`");
TEST_ExpectTrue(testJSON.GetTypeOf("some_var") == JSON_Null);
Issue("Null value isn't being properly removed.");
testJSON.RemoveValue("some_var");
TEST_ExpectTrue(testJSON.GetTypeOf("some_var") == JSON_Undefined);
}
protected static function SubTest_MultipleVariablesGetSet()
{
local int i;
local bool correctValue, allValuesCorrect;
local JObject testJSON;
testJSON = _().json.newObject();
Context("Testing how `JObject` handles addition, change and removal" @
"of relatively large (hundreds) number of variables");
for (i = 0; i < 2000; i += 1)
{
testJSON.SetNumber("num" $ string(i), 4 * i*i - 2.6 * i + 0.75);
}
for (i = 0; i < 500; i += 1)
{
testJSON.SetString("num" $ string(i), "str" $ string(Sin(i)));
}
for (i = 1500; i < 2000; i += 1)
{
testJSON.RemoveValue("num" $ string(i));
}
allValuesCorrect = true;
for (i = 0; i < 200; i += 1)
{
if (i < 500)
{
correctValue = ( testJSON.GetString("num" $ string(i))
== ("str" $ string(Sin(i))) );
Issue("Variables are incorrectly overwritten");
}
else if(i < 1500)
{
correctValue = ( testJSON.GetNumber("num" $ string(i))
== 4 * i*i - 2.6 * i + 0.75);
Issue("Variables are lost");
}
else
{
correctValue = ( testJSON.GetTypeOf("num" $ string(i))
== JSON_Undefined);
Issue("Variables aren't removed");
}
if (!correctValue)
{
allValuesCorrect = false;
break;
}
}
TEST_ExpectTrue(allValuesCorrect);
}
protected static function SubTest_Object()
{
local JObject testObject;
Context("Testing setters and getters for folded objects");
testObject = _().json.newObject();
testObject.CreateObject("folded");
testObject.GetObject("folded").CreateObject("folded");
testObject.SetString("out", "string outside");
testObject.GetObject("folded").SetNumber("mid", 8);
testObject.GetObject("folded")
.GetObject("folded")
.SetString("in", "string inside");
Issue("Addressing variables in root object doesn't work");
TEST_ExpectTrue(testObject.GetString("out", "default") == "string outside");
Issue("Addressing variables in folded object doesn't work");
TEST_ExpectTrue(testObject.GetObject("folded").GetNumber("mid", 1) == 8);
Issue("Addressing plain variables in folded (twice) object doesn't work");
TEST_ExpectTrue(testObject.GetObject("folded").GetObject("folded")
.GetString("in", "default") == "string inside");
}
protected static function SubTest_ArrayUndefined()
{
local JArray testJSON;
testJSON = _().json.newArray();
Context("Testing how `JArray` handles undefined values");
Issue("Undefined variable doesn't have `JSON_Undefined` type");
TEST_ExpectTrue(testJSON.GetTypeOf(0) == JSON_Undefined);
Issue("There is a variable in an empty object after `GetTypeOf` call");
TEST_ExpectTrue(testJSON.GetTypeOf(0) == JSON_Undefined);
Issue("Negative index refers to a defined value");
TEST_ExpectTrue(testJSON.GetTypeOf(-1) == JSON_Undefined);
Issue("Getters don't return default values for undefined variables");
TEST_ExpectTrue(testJSON.GetNumber(0, 0) == 0);
TEST_ExpectTrue(testJSON.GetString(0, "") == "");
TEST_ExpectTrue(testJSON.GetBoolean(0, false) == false);
TEST_ExpectNone(testJSON.GetObject(0));
TEST_ExpectNone(testJSON.GetArray(0));
Issue( "Getters don't return user-defined default values for" @
"undefined variables");
TEST_ExpectTrue(testJSON.GetNumber(0, 10) == 10);
TEST_ExpectTrue(testJSON.GetString(0, "test") == "test");
TEST_ExpectTrue(testJSON.GetBoolean(0, true) == true);
}
protected static function SubTest_ArrayBooleanGetSetRemove()
{
local JArray testJSON;
testJSON = _().json.newArray();
testJSON.SetBoolean(0, true);
Context("Testing `JArray`'s get/set/remove functions for" @
"boolean variables");
Issue("Boolean type isn't properly set by `SetBoolean`");
TEST_ExpectTrue(testJSON.GetTypeOf(0) == JSON_Boolean);
Issue("Value is incorrectly assigned by `SetBoolean`");
TEST_ExpectTrue(testJSON.GetBoolean(0) == true);
testJSON.SetBoolean(0, false);
Issue("Variable value isn't correctly reassigned by `SetBoolean`");
TEST_ExpectTrue(testJSON.GetBoolean(0) == false);
Issue( "Getting boolean variable as a wrong type" @
"doesn't yield default value");
TEST_ExpectTrue(testJSON.GetNumber(0, 7) == 7);
Issue("Boolean variable isn't being properly removed");
testJSON.RemoveValue(0);
TEST_ExpectTrue( testJSON.GetTypeOf(0) == JSON_Undefined);
Issue( "Getters don't return default value for missing key that" @
"previously stored boolean value, but got removed");
TEST_ExpectTrue(testJSON.GetBoolean(0, true) == true);
}
protected static function SubTest_ArrayStringGetSetRemove()
{
local JArray testJSON;
testJSON = _().json.newArray();
testJSON.SetString(0, "first string");
Context("Testing `JArray`'s get/set/remove functions for" @
"string variables");
Issue("String type isn't properly set by `SetString`");
TEST_ExpectTrue(testJSON.GetTypeOf(0) == JSON_String);
Issue("Value is incorrectly assigned by `SetString`");
TEST_ExpectTrue(testJSON.GetString(0) == "first string");
Issue( "Providing default variable value makes 'GetString'" @
"return incorrect value");
TEST_ExpectTrue(testJSON.GetString(0, "alternative") == "first string");
Issue("Variable value isn't correctly reassigned by `SetString`");
testJSON.SetString(0, "new string!~");
TEST_ExpectTrue(testJSON.GetString(0) == "new string!~");
Issue( "Getting string variable as a wrong type" @
"doesn't yield default value");
TEST_ExpectTrue(testJSON.GetBoolean(0, true) == true);
Issue("Boolean variable isn't being properly removed");
testJSON.RemoveValue(0);
TEST_ExpectTrue(testJSON.GetTypeOf(0) == JSON_Undefined);
Issue( "Getters don't return default value for missing key that" @
"previously stored string value, but got removed");
TEST_ExpectTrue(testJSON.GetString(0, "other") == "other");
}
protected static function SubTest_ArrayNumberGetSetRemove()
{
local JArray testJSON;
testJSON = _().json.newArray();
testJSON.SetNumber(0, 3.5);
Context("Testing `JArray`'s get/set/remove functions for" @
"number variables");
Issue("Number type isn't properly set by `SetNumber`");
TEST_ExpectTrue(testJSON.GetTypeOf(0) == JSON_Number);
Issue("Value is incorrectly assigned by `SetNumber`");
TEST_ExpectTrue(testJSON.GetNumber(0) == 3.5);
Issue( "Providing default variable value makes 'GetNumber'" @
"return incorrect value");
TEST_ExpectTrue(testJSON.GetNumber(0, 5) == 3.5);
Issue("Variable value isn't correctly reassigned by `SetNumber`");
testJSON.SetNumber(0, 7);
TEST_ExpectTrue(testJSON.GetNumber(0) == 7);
Issue( "Getting number variable as a wrong type" @
"doesn't yield default value");
TEST_ExpectTrue(testJSON.GetString(0, "default") == "default");
Issue("Number type isn't being properly removed");
testJSON.RemoveValue(0);
TEST_ExpectTrue(testJSON.GetTypeOf(0) == JSON_Undefined);
Issue( "Getters don't return default value for missing key that" @
"previously stored number value, but got removed");
TEST_ExpectTrue(testJSON.GetNumber(0, 13) == 13);
}
protected static function SubTest_ArrayNullGetSetRemove()
{
local JArray testJSON;
testJSON = _().json.newArray();
Context("Testing `JArray`'s get/set/remove functions for" @
"null values");
Issue("Undefined variable is incorrectly considered `null`");
TEST_ExpectFalse(testJSON.IsNull(0));
TEST_ExpectFalse(testJSON.IsNull(2));
TEST_ExpectFalse(testJSON.IsNull(-1));
Issue("Number variable is incorrectly considered `null`");
testJSON.SetNumber(0, 4);
TEST_ExpectFalse(testJSON.IsNull(0));
Issue("Boolean variable is incorrectly considered `null`");
testJSON.SetBoolean(0, true);
TEST_ExpectFalse(testJSON.IsNull(0));
Issue("String variable is incorrectly considered `null`");
testJSON.SetString(0, "string");
TEST_ExpectFalse(testJSON.IsNull(0));
Issue("Null value is incorrectly assigned");
testJSON.SetNull(0);
TEST_ExpectTrue(testJSON.IsNull(0));
Issue("Null type isn't properly set by `SetNumber`");
TEST_ExpectTrue(testJSON.GetTypeOf(0) == JSON_Null);
Issue("Null value isn't being properly removed");
testJSON.RemoveValue(0);
TEST_ExpectTrue(testJSON.GetTypeOf(0) == JSON_Undefined);
}
// Returns following array:
// [10.0, "test string", "another string", true, 0.0, {"var": 7.0}]
protected static function JArray Prepare_Array()
{
local JArray testArray;
testArray = _().json.newArray();
testArray.AddNumber(10.0f)
.AddString("test string")
.AddString("another string")
.AddBoolean(true)
.AddNumber(0.0f)
.AddObject();
testArray.GetObject(5).SetNumber("var", 7);
return testArray;
}
protected static function SubTest_ArrayMultipleVariablesStorage()
{
local JArray testArray;
testArray = Prepare_Array();
Context("Testing how `JArray` handles adding and" @
"changing several variables");
Issue("Stored values are compromised.");
TEST_ExpectTrue(testArray.GetNumber(0) == 10.0f);
TEST_ExpectTrue(testArray.GetString(1) == "test string");
TEST_ExpectTrue(testArray.GetString(2) == "another string");
TEST_ExpectTrue(testArray.GetBoolean(3) == true);
TEST_ExpectTrue(testArray.GetNumber(4) == 0.0f);
TEST_ExpectTrue(testArray.GetObject(5).GetNumber("var") == 7);
Issue("Values incorrectly change their values.");
testArray.SetString(3, "new string");
TEST_ExpectTrue(testArray.GetString(3) == "new string");
Issue( "After overwriting boolean value with a different type," @
"attempting go get it as a boolean gives old value," @
"instead of default");
TEST_ExpectTrue(testArray.GetBoolean(3, false) == false);
Issue("Type of the variable is incorrectly changed.");
TEST_ExpectTrue(testArray.GetTypeOf(3) == JSON_String);
}
protected static function SubTest_ArrayMultipleVariablesRemoval()
{
local JArray testArray;
testArray = Prepare_Array();
// Test removing variables
// After `Prepare_Array`, our array should be:
// [10.0, "test string", "another string", true, 0.0, {"var": 7.0}]
Context("Testing how `JArray` handles adding and" @
"removing several variables");
Issue("Values are incorrectly removed");
testArray.RemoveValue(2);
// [10.0, "test string", true, 0.0, {"var": 7.0}]
Issue("Values are incorrectly removed");
TEST_ExpectTrue(testArray.GetNumber(0) == 10.0);
TEST_ExpectTrue(testArray.GetString(1) == "test string");
TEST_ExpectTrue(testArray.GetBoolean(2) == true);
TEST_ExpectTrue(testArray.GetNumber(3) == 0.0f);
TEST_ExpectTrue(testArray.GetTypeOf(4) == JSON_Object);
Issue("First element incorrectly removed");
testArray.RemoveValue(0);
// ["test string", true, 0.0, {"var": 7.0}]
TEST_ExpectTrue(testArray.GetString(0) == "test string");
TEST_ExpectTrue(testArray.GetBoolean(1) == true);
TEST_ExpectTrue(testArray.GetNumber(2) == 0.0f);
TEST_ExpectTrue(testArray.GetTypeOf(3) == JSON_Object);
TEST_ExpectTrue(testArray.GetObject(3).GetNumber("var") == 7.0);
Issue("Last element incorrectly removed");
testArray.RemoveValue(3);
// ["test string", true, 0.0]
TEST_ExpectTrue(testArray.GetLength() == 3);
TEST_ExpectTrue(testArray.GetString(0) == "test string");
TEST_ExpectTrue(testArray.GetBoolean(1) == true);
TEST_ExpectTrue(testArray.GetNumber(2) == 0.0f);
Issue("Removing all elements is handled incorrectly");
testArray.RemoveValue(0);
testArray.RemoveValue(0);
testArray.RemoveValue(0);
TEST_ExpectTrue(testArray.Getlength() == 0);
TEST_ExpectTrue(testArray.GetTypeOf(0) == JSON_Undefined);
}
protected static function SubTest_ArrayRemovingMultipleVariablesAtOnce()
{
local JArray testArray;
testArray = _().json.newArray();
testArray.AddNumber(10.0f)
.AddString("test string")
.AddString("another string")
.AddNumber(7.0);
Context("Testing how `JArray`' handles removing" @
"multiple elements at once");
Issue("Multiple values are incorrectly removed");
testArray.RemoveValue(1, 2);
TEST_ExpectTrue(testArray.GetLength() == 2);
TEST_ExpectTrue(testArray.GetNumber(1) == 7.0);
testArray.AddNumber(4.0f)
.AddString("test string")
.AddString("another string")
.AddNumber(8.0);
// Current array:
// [10.0, 7.0, 4.0, "test string", "another string", 8.0]
Issue("Last value is incorrectly removed");
testArray.RemoveValue(5, 1);
TEST_ExpectTrue(testArray.GetLength() == 5);
TEST_ExpectTrue(testArray.GetString(4) == "another string");
// Current array:
// [10.0, 7.0, 4.0, "test string", "another string"]
Issue("Tail elements are incorrectly removed");
testArray.RemoveValue(3, 4);
TEST_ExpectTrue(testArray.GetLength() == 3);
TEST_ExpectTrue(testArray.GetNumber(0) == 10.0);
TEST_ExpectTrue(testArray.GetNumber(2) == 4.0);
Issue("Array empties incorrectly");
testArray.RemoveValue(0, testArray.GetLength());
TEST_ExpectTrue(testArray.GetLength() == 0);
TEST_ExpectTrue(testArray.GetTypeOf(0) == JSON_Undefined);
TEST_ExpectTrue(testArray.GetTypeOf(1) == JSON_Undefined);
}
protected static function SubTest_ArrayExpansions()
{
local JArray testArray;
testArray = _().json.newArray();
Context("Testing how `JArray`' handles expansions/shrinking " @
"via `SetLength()`");
Issue("`SetLength()` doesn't properly expand empty array");
testArray.SetLength(2);
TEST_ExpectTrue(testArray.GetLength() == 2);
TEST_ExpectTrue(testArray.GetTypeOf(0) == JSON_Null);
TEST_ExpectTrue(testArray.GetTypeOf(1) == JSON_Null);
Issue("`SetLength()` doesn't properly expand non-empty array");
testArray.AddNumber(1);
testArray.SetLength(4);
TEST_ExpectTrue(testArray.GetLength() == 4);
TEST_ExpectTrue(testArray.GetTypeOf(0) == JSON_Null);
TEST_ExpectTrue(testArray.GetTypeOf(1) == JSON_Null);
TEST_ExpectTrue(testArray.GetTypeOf(2) == JSON_Number);
TEST_ExpectTrue(testArray.GetTypeOf(3) == JSON_Null);
TEST_ExpectTrue(testArray.GetNumber(2) == 1);
SubSubTest_ArraySetNumberExpansions();
SubSubTest_ArraySetStringExpansions();
SubSubTest_ArraySetBooleanExpansions();
}
protected static function SubSubTest_ArraySetNumberExpansions()
{
local JArray testArray;
testArray = _().json.newArray();
Context("Testing how `JArray`' handles expansions via" @
"`SetNumber()` function");
Issue("Setters don't create correct first element");
testArray.SetNumber(0, 1);
TEST_ExpectTrue(testArray.GetLength() == 1);
TEST_ExpectTrue(testArray.GetNumber(0) == 1);
Issue( "`SetNumber()` doesn't properly define array when setting" @
"value out-of-bounds");
testArray = _().json.newArray();
testArray.AddNumber(1);
testArray.SetNumber(4, 2);
TEST_ExpectTrue(testArray.GetLength() == 5);
TEST_ExpectTrue(testArray.GetNumber(0) == 1);
TEST_ExpectTrue(testArray.GetTypeOf(1) == JSON_Null);
TEST_ExpectTrue(testArray.GetTypeOf(2) == JSON_Null);
TEST_ExpectTrue(testArray.GetTypeOf(3) == JSON_Null);
TEST_ExpectTrue(testArray.GetNumber(4) == 2);
Issue("`SetNumber()` expands array even when it told not to");
testArray.SetNumber(6, 7, true);
TEST_ExpectTrue(testArray.GetLength() == 5);
TEST_ExpectTrue(testArray.GetNumber(6) == 0);
TEST_ExpectTrue(testArray.GetTypeOf(5) == JSON_Undefined);
TEST_ExpectTrue(testArray.GetTypeOf(6) == JSON_Undefined);
}
protected static function SubSubTest_ArraySetStringExpansions()
{
local JArray testArray;
testArray = _().json.newArray();
Context("Testing how `JArray`' handles expansions via" @
"`SetString()` function");
Issue("Setters don't create correct first element");
testArray.SetString(0, "str");
TEST_ExpectTrue(testArray.GetLength() == 1);
TEST_ExpectTrue(testArray.GetString(0) == "str");
Issue( "`SetString()` doesn't properly define array when setting" @
"value out-of-bounds");
testArray = _().json.newArray();
testArray.AddString("str");
testArray.SetString(4, "str2");
TEST_ExpectTrue(testArray.GetLength() == 5);
TEST_ExpectTrue(testArray.GetString(0) == "str");
TEST_ExpectTrue(testArray.GetTypeOf(1) == JSON_Null);
TEST_ExpectTrue(testArray.GetTypeOf(2) == JSON_Null);
TEST_ExpectTrue(testArray.GetTypeOf(3) == JSON_Null);
TEST_ExpectTrue(testArray.GetString(4) == "str2");
Issue("`SetString()` expands array even when it told not to");
testArray.SetString(6, "new string", true);
TEST_ExpectTrue(testArray.GetLength() == 5);
TEST_ExpectTrue(testArray.GetString(6) == "");
TEST_ExpectTrue(testArray.GetTypeOf(5) == JSON_Undefined);
TEST_ExpectTrue(testArray.GetTypeOf(6) == JSON_Undefined);
}
protected static function SubSubTest_ArraySetBooleanExpansions()
{
local JArray testArray;
testArray = _().json.newArray();
Context("Testing how `JArray`' handles expansions via" @
"`SetBoolean()` function");
Issue("Setters don't create correct first element");
testArray.SetBoolean(0, false);
TEST_ExpectTrue(testArray.GetLength() == 1);
TEST_ExpectTrue(testArray.GetBoolean(0) == false);
Issue( "`SetBoolean()` doesn't properly define array when setting" @
"value out-of-bounds");
testArray = _().json.newArray();
testArray.AddBoolean(true);
testArray.SetBoolean(4, true);
TEST_ExpectTrue(testArray.GetLength() == 5);
TEST_ExpectTrue(testArray.GetBoolean(0) == true);
TEST_ExpectTrue(testArray.GetTypeOf(1) == JSON_Null);
TEST_ExpectTrue(testArray.GetTypeOf(2) == JSON_Null);
TEST_ExpectTrue(testArray.GetTypeOf(3) == JSON_Null);
TEST_ExpectTrue(testArray.GetBoolean(4) == true);
Issue("`SetBoolean()` expands array even when it told not to");
testArray.SetBoolean(6, true, true);
TEST_ExpectTrue(testArray.GetLength() == 5);
TEST_ExpectTrue(testArray.GetBoolean(6) == false);
TEST_ExpectTrue(testArray.GetTypeOf(5) == JSON_Undefined);
TEST_ExpectTrue(testArray.GetTypeOf(6) == JSON_Undefined);
}
defaultproperties
{
caseName = "JSON"
}