sourcemod/plugins/testsuite/test_json.sp
ProjectSky e1c5578324 feat: enhance JSON management with new rotation and value counting features
- Added ObjectRotate and ArrayRotate methods for rotating key-value pairs in JSON objects and arrays, respectively
- Introduced GetValCount method to retrieve the total number of values in immutable JSON documents
- Renamed all Float-related methods to Double in C++ interface (IJsonManager) for better precision clarity
- Fixed TypeAccess configuration in handle type registration to allow external extensions to create JSON handles by properly setting HTypeAccess_Create flag
- Renamed GetHandleType to GetJsonHandleType for better clarity and consistency
- Updated documentation to clarify usage and performance considerations for new methods
- Enhanced tests to cover rotation functionality and value counting in various JSON structures
2025-11-21 00:07:25 +08:00

3380 lines
71 KiB
SourcePawn
Executable File

#include <sourcemod>
#include <json>
#pragma newdecls required
#pragma semicolon 1
public Plugin myinfo =
{
name = "JSON Test Suite",
author = "ProjectSky",
description = "test suite for JSON functions",
version = "1.0.0",
url = "https://github.com/ProjectSky/sm-ext-yyjson"
};
// Test statistics
int g_iTotalTests = 0;
int g_iPassedTests = 0;
int g_iFailedTests = 0;
char g_sCurrentTest[128];
bool g_bCurrentTestFailed = false;
public void OnPluginStart()
{
RegServerCmd("test_json", Command_RunTests, "Run JSON test suite");
}
// ============================================================================
// Test Framework - Assertion Functions
// ============================================================================
/**
* Start a new test case
*/
void TestStart(const char[] name)
{
g_iTotalTests++;
strcopy(g_sCurrentTest, sizeof(g_sCurrentTest), name);
g_bCurrentTestFailed = false;
}
/**
* End current test case
*/
void TestEnd()
{
if (!g_bCurrentTestFailed)
{
g_iPassedTests++;
PrintToServer("[PASS] %s", g_sCurrentTest);
}
else
{
g_iFailedTests++;
}
}
/**
* Assert a condition is true
*/
void Assert(bool condition, const char[] message = "")
{
if (!condition)
{
g_bCurrentTestFailed = true;
PrintToServer("[FAIL] %s - %s", g_sCurrentTest, message);
}
}
/**
* Assert two integers are equal
*/
void AssertEq(int a, int b, const char[] message = "")
{
if (a != b)
{
g_bCurrentTestFailed = true;
char buffer[256];
if (message[0] != '\0')
{
FormatEx(buffer, sizeof(buffer), "%s (expected %d, got %d)", message, b, a);
}
else
{
FormatEx(buffer, sizeof(buffer), "Expected %d, got %d", b, a);
}
PrintToServer("[FAIL] %s - %s", g_sCurrentTest, buffer);
}
}
/**
* Assert two integers are not equal
*/
stock void AssertNeq(int a, int b, const char[] message = "")
{
if (a == b)
{
g_bCurrentTestFailed = true;
char buffer[256];
if (message[0] != '\0')
{
FormatEx(buffer, sizeof(buffer), "%s (values should not be equal: %d)", message, a);
}
else
{
FormatEx(buffer, sizeof(buffer), "Values should not be equal: %d", a);
}
PrintToServer("[FAIL] %s - %s", g_sCurrentTest, buffer);
}
}
/**
* Assert condition is true
*/
void AssertTrue(bool condition, const char[] message = "")
{
Assert(condition, message[0] != '\0' ? message : "Expected true, got false");
}
/**
* Assert condition is false
*/
void AssertFalse(bool condition, const char[] message = "")
{
Assert(!condition, message[0] != '\0' ? message : "Expected false, got true");
}
/**
* Assert two strings are equal
*/
void AssertStrEq(const char[] a, const char[] b, const char[] message = "")
{
if (strcmp(a, b) != 0)
{
g_bCurrentTestFailed = true;
char buffer[512];
if (message[0] != '\0')
{
FormatEx(buffer, sizeof(buffer), "%s (expected \"%s\", got \"%s\")", message, b, a);
}
else
{
FormatEx(buffer, sizeof(buffer), "Expected \"%s\", got \"%s\"", b, a);
}
PrintToServer("[FAIL] %s - %s", g_sCurrentTest, buffer);
}
}
/**
* Assert two floats are equal within epsilon
*/
void AssertFloatEq(float a, float b, const char[] message = "", float epsilon = 0.0001)
{
if (FloatAbs(a - b) > epsilon)
{
g_bCurrentTestFailed = true;
char buffer[256];
if (message[0] != '\0')
{
FormatEx(buffer, sizeof(buffer), "%s (expected %.4f, got %.4f)", message, b, a);
}
else
{
FormatEx(buffer, sizeof(buffer), "Expected %.4f, got %.4f", b, a);
}
PrintToServer("[FAIL] %s - %s", g_sCurrentTest, buffer);
}
}
/**
* Assert handle is valid
*/
void AssertValidHandle(Handle handle, const char[] message = "")
{
Assert(handle != null, message[0] != '\0' ? message : "Handle should not be null");
}
/**
* Assert handle is null
*/
void AssertNullHandle(Handle handle, const char[] message = "")
{
Assert(handle == null, message[0] != '\0' ? message : "Handle should be null");
}
// ============================================================================
// Test Command
// ============================================================================
public Action Command_RunTests(int args)
{
PrintToServer("========================================");
PrintToServer("JSON Test Suite");
PrintToServer("========================================");
// Reset statistics
g_iTotalTests = 0;
g_iPassedTests = 0;
g_iFailedTests = 0;
// Run all test categories
Test_BasicValues();
Test_ObjectOperations();
Test_ArrayOperations();
Test_ParseAndSerialize();
Test_Iterators();
Test_JSONPointer();
Test_AdvancedFeatures();
Test_Int64Operations();
Test_EdgeCases();
// Print results
PrintToServer("========================================");
PrintToServer("JSON Test Suite Results");
PrintToServer("========================================");
PrintToServer("Total Tests: %d", g_iTotalTests);
PrintToServer("Passed: %d", g_iPassedTests);
PrintToServer("Failed: %d", g_iFailedTests);
if (g_iTotalTests > 0)
{
float successRate = (float(g_iPassedTests) / float(g_iTotalTests)) * 100.0;
PrintToServer("Success Rate: %.2f%%", successRate);
}
PrintToServer("========================================");
return Plugin_Handled;
}
// ============================================================================
// 2.1 Basic Value Tests
// ============================================================================
void Test_BasicValues()
{
PrintToServer("\n[Category] Basic Value Tests");
// Test CreateBool & GetBool
TestStart("BasicValues_CreateBool_True");
{
JSON val = JSON.CreateBool(true);
AssertValidHandle(val);
AssertTrue(val.GetBool());
AssertEq(val.Type, JSON_TYPE_BOOL);
AssertTrue(val.IsBool);
AssertTrue(val.IsTrue);
AssertFalse(val.IsFalse);
delete val;
}
TestEnd();
TestStart("BasicValues_CreateBool_False");
{
JSON val = JSON.CreateBool(false);
AssertValidHandle(val);
AssertFalse(val.GetBool());
AssertTrue(val.IsBool);
AssertFalse(val.IsTrue);
AssertTrue(val.IsFalse);
delete val;
}
TestEnd();
// Test CreateInt & GetInt
TestStart("BasicValues_CreateInt_Positive");
{
JSON val = JSON.CreateInt(42);
AssertValidHandle(val);
AssertEq(val.GetInt(), 42);
AssertEq(val.Type, JSON_TYPE_NUM);
AssertTrue(val.IsInt);
AssertTrue(val.IsNum);
delete val;
}
TestEnd();
TestStart("BasicValues_CreateInt_Negative");
{
JSON val = JSON.CreateInt(-123);
AssertValidHandle(val);
AssertEq(val.GetInt(), -123);
AssertTrue(val.IsSint);
delete val;
}
TestEnd();
TestStart("BasicValues_CreateInt_Zero");
{
JSON val = JSON.CreateInt(0);
AssertValidHandle(val);
AssertEq(val.GetInt(), 0);
delete val;
}
TestEnd();
// Test CreateFloat & GetFloat
TestStart("BasicValues_CreateFloat_Positive");
{
JSON val = JSON.CreateFloat(3.14159);
AssertValidHandle(val);
AssertFloatEq(val.GetFloat(), 3.14159);
AssertTrue(val.IsFloat);
AssertTrue(val.IsNum);
delete val;
}
TestEnd();
TestStart("BasicValues_CreateFloat_Negative");
{
JSON val = JSON.CreateFloat(-2.71828);
AssertValidHandle(val);
AssertFloatEq(val.GetFloat(), -2.71828);
delete val;
}
TestEnd();
TestStart("BasicValues_CreateFloat_Zero");
{
JSON val = JSON.CreateFloat(0.0);
AssertValidHandle(val);
AssertFloatEq(val.GetFloat(), 0.0);
delete val;
}
TestEnd();
// Test CreateString & GetString
TestStart("BasicValues_CreateString_Regular");
{
JSON val = JSON.CreateString("Hello, World!");
AssertValidHandle(val);
char buffer[64];
AssertTrue(val.GetString(buffer, sizeof(buffer)));
AssertStrEq(buffer, "Hello, World!");
AssertEq(val.Type, JSON_TYPE_STR);
AssertTrue(val.IsStr);
delete val;
}
TestEnd();
TestStart("BasicValues_CreateString_Empty");
{
JSON val = JSON.CreateString("");
AssertValidHandle(val);
char buffer[64];
AssertTrue(val.GetString(buffer, sizeof(buffer)));
AssertStrEq(buffer, "");
delete val;
}
TestEnd();
TestStart("BasicValues_CreateString_Unicode");
{
JSON val = JSON.CreateString("测试字符串");
AssertValidHandle(val);
char buffer[64];
AssertTrue(val.GetString(buffer, sizeof(buffer)));
AssertStrEq(buffer, "测试字符串");
delete val;
}
TestEnd();
// Test CreateInt64 & GetInt64
TestStart("BasicValues_CreateInt64_Large");
{
JSON val = JSON.CreateInt64("9223372036854775807");
AssertValidHandle(val);
char buffer[32];
AssertTrue(val.GetInt64(buffer, sizeof(buffer)));
AssertStrEq(buffer, "9223372036854775807");
delete val;
}
TestEnd();
TestStart("BasicValues_CreateInt64_Negative");
{
JSON val = JSON.CreateInt64("-9223372036854775808");
AssertValidHandle(val);
char buffer[32];
AssertTrue(val.GetInt64(buffer, sizeof(buffer)));
AssertStrEq(buffer, "-9223372036854775808");
delete val;
}
TestEnd();
// Test CreateNull
TestStart("BasicValues_CreateNull");
{
JSON val = JSON.CreateNull();
AssertValidHandle(val);
AssertEq(val.Type, JSON_TYPE_NULL);
AssertTrue(val.IsNull);
delete val;
}
TestEnd();
// Test GetTypeDesc
TestStart("BasicValues_GetTypeDesc");
{
JSON boolVal = JSON.CreateBool(true);
JSON intVal = JSON.CreateInt(42);
JSON floatVal = JSON.CreateFloat(3.14);
JSON strVal = JSON.CreateString("test");
JSON nullVal = JSON.CreateNull();
char buffer[32];
boolVal.GetTypeDesc(buffer, sizeof(buffer));
AssertStrEq(buffer, "true");
intVal.GetTypeDesc(buffer, sizeof(buffer));
AssertTrue(strcmp(buffer, "uint") == 0 || strcmp(buffer, "sint") == 0);
floatVal.GetTypeDesc(buffer, sizeof(buffer));
AssertStrEq(buffer, "real");
strVal.GetTypeDesc(buffer, sizeof(buffer));
AssertStrEq(buffer, "string");
nullVal.GetTypeDesc(buffer, sizeof(buffer));
AssertStrEq(buffer, "null");
delete boolVal;
delete intVal;
delete floatVal;
delete strVal;
delete nullVal;
}
TestEnd();
}
// ============================================================================
// 2.2 Object Operations Tests
// ============================================================================
void Test_ObjectOperations()
{
PrintToServer("\n[Category] Object Operations Tests");
// Test object creation
TestStart("Object_Constructor");
{
JSONObject obj = new JSONObject();
AssertValidHandle(obj);
AssertTrue(obj.IsObject);
AssertEq(obj.Size, 0);
delete obj;
}
TestEnd();
// Test Set/Get methods
TestStart("Object_SetGetInt");
{
JSONObject obj = new JSONObject();
AssertTrue(obj.SetInt("number", 42));
AssertEq(obj.GetInt("number"), 42);
AssertEq(obj.Size, 1);
delete obj;
}
TestEnd();
TestStart("Object_SetGetFloat");
{
JSONObject obj = new JSONObject();
AssertTrue(obj.SetFloat("pi", 3.14159));
AssertFloatEq(obj.GetFloat("pi"), 3.14159);
delete obj;
}
TestEnd();
TestStart("Object_SetGetBool");
{
JSONObject obj = new JSONObject();
AssertTrue(obj.SetBool("flag", true));
AssertTrue(obj.GetBool("flag"));
delete obj;
}
TestEnd();
TestStart("Object_SetGetString");
{
JSONObject obj = new JSONObject();
AssertTrue(obj.SetString("name", "test"));
char buffer[64];
AssertTrue(obj.GetString("name", buffer, sizeof(buffer)));
AssertStrEq(buffer, "test");
delete obj;
}
TestEnd();
TestStart("Object_SetGetInt64");
{
JSONObject obj = new JSONObject();
AssertTrue(obj.SetInt64("bignum", "9223372036854775807"));
char buffer[32];
AssertTrue(obj.GetInt64("bignum", buffer, sizeof(buffer)));
AssertStrEq(buffer, "9223372036854775807");
delete obj;
}
TestEnd();
TestStart("Object_SetGetNull");
{
JSONObject obj = new JSONObject();
AssertTrue(obj.SetNull("nullable"));
AssertTrue(obj.IsNull("nullable"));
delete obj;
}
TestEnd();
// Test HasKey
TestStart("Object_HasKey");
{
JSONObject obj = new JSONObject();
obj.SetInt("exists", 1);
AssertTrue(obj.HasKey("exists"));
AssertFalse(obj.HasKey("notexists"));
delete obj;
}
TestEnd();
// Test GetKey and GetValueAt
TestStart("Object_GetKeyAndValueAt");
{
JSONObject obj = new JSONObject();
obj.SetInt("first", 1);
obj.SetInt("second", 2);
char key[32];
AssertTrue(obj.GetKey(0, key, sizeof(key)));
AssertStrEq(key, "first");
JSON val = obj.GetValueAt(0);
AssertValidHandle(val);
AssertEq(val.GetInt(), 1);
delete val;
delete obj;
}
TestEnd();
// Test Remove
TestStart("Object_Remove");
{
JSONObject obj = new JSONObject();
obj.SetInt("remove_me", 1);
obj.SetInt("keep_me", 2);
AssertEq(obj.Size, 2);
AssertTrue(obj.Remove("remove_me"));
AssertEq(obj.Size, 1);
AssertFalse(obj.HasKey("remove_me"));
AssertTrue(obj.HasKey("keep_me"));
delete obj;
}
TestEnd();
// Test Clear
TestStart("Object_Clear");
{
JSONObject obj = new JSONObject();
obj.SetInt("a", 1);
obj.SetInt("b", 2);
obj.SetInt("c", 3);
AssertEq(obj.Size, 3);
AssertTrue(obj.Clear());
AssertEq(obj.Size, 0);
delete obj;
}
TestEnd();
// Test RenameKey
TestStart("Object_RenameKey");
{
JSONObject obj = new JSONObject();
obj.SetInt("oldname", 42);
AssertTrue(obj.RenameKey("oldname", "newname"));
AssertFalse(obj.HasKey("oldname"));
AssertTrue(obj.HasKey("newname"));
AssertEq(obj.GetInt("newname"), 42);
delete obj;
}
TestEnd();
// Test FromString
TestStart("Object_FromString");
{
JSONObject obj = JSONObject.FromString("{\"key\":\"value\",\"num\":123}");
AssertValidHandle(obj);
char buffer[64];
AssertTrue(obj.GetString("key", buffer, sizeof(buffer)));
AssertStrEq(buffer, "value");
AssertEq(obj.GetInt("num"), 123);
delete obj;
}
TestEnd();
// Test FromStrings
TestStart("Object_FromStrings");
{
char pairs[][] = {"name", "test", "type", "demo", "version", "1.0"};
JSONObject obj = JSONObject.FromStrings(pairs, sizeof(pairs));
AssertValidHandle(obj);
AssertEq(obj.Size, 3);
char buffer[64];
AssertTrue(obj.GetString("name", buffer, sizeof(buffer)));
AssertStrEq(buffer, "test");
delete obj;
}
TestEnd();
// Test Sort
TestStart("Object_Sort_Ascending");
{
JSONObject obj = new JSONObject();
obj.SetInt("zebra", 1);
obj.SetInt("alpha", 2);
obj.SetInt("beta", 3);
AssertTrue(obj.Sort(JSON_SORT_ASC));
char key[32];
obj.GetKey(0, key, sizeof(key));
AssertStrEq(key, "alpha");
delete obj;
}
TestEnd();
TestStart("Object_Sort_Descending");
{
JSONObject obj = new JSONObject();
obj.SetInt("alpha", 1);
obj.SetInt("beta", 2);
obj.SetInt("gamma", 3);
AssertTrue(obj.Sort(JSON_SORT_DESC));
char key[32];
obj.GetKey(0, key, sizeof(key));
AssertStrEq(key, "gamma");
delete obj;
}
TestEnd();
// Test Rotate
TestStart("Object_Rotate_Forward");
{
JSONObject obj = new JSONObject();
obj.SetInt("a", 1);
obj.SetInt("b", 2);
obj.SetInt("c", 3);
obj.SetInt("d", 4);
AssertTrue(obj.Rotate(1));
char key[32];
obj.GetKey(0, key, sizeof(key));
AssertStrEq(key, "b", "First key should be 'b' after rotate 1");
obj.GetKey(3, key, sizeof(key));
AssertStrEq(key, "a", "Last key should be 'a' after rotate 1");
delete obj;
}
TestEnd();
TestStart("Object_Rotate_Multiple");
{
JSONObject obj = new JSONObject();
obj.SetInt("first", 1);
obj.SetInt("second", 2);
obj.SetInt("third", 3);
obj.SetInt("fourth", 4);
obj.SetInt("fifth", 5);
AssertTrue(obj.Rotate(2));
char key[32];
obj.GetKey(0, key, sizeof(key));
AssertStrEq(key, "third", "First key should be 'third' after rotate 2");
obj.GetKey(4, key, sizeof(key));
AssertStrEq(key, "second", "Last key should be 'second' after rotate 2");
delete obj;
}
TestEnd();
TestStart("Object_Rotate_Zero");
{
JSONObject obj = new JSONObject();
obj.SetInt("x", 1);
obj.SetInt("y", 2);
AssertTrue(obj.Rotate(0));
char key[32];
obj.GetKey(0, key, sizeof(key));
AssertStrEq(key, "x", "Order should not change after rotate 0");
delete obj;
}
TestEnd();
// Test Set with handle
TestStart("Object_SetWithHandle");
{
JSONObject obj = new JSONObject();
JSON val = JSON.CreateInt(999);
AssertTrue(obj.Set("nested", val));
AssertEq(obj.GetInt("nested"), 999);
delete val;
delete obj;
}
TestEnd();
// Test Get with handle
TestStart("Object_GetHandle");
{
JSONObject obj = new JSONObject();
obj.SetInt("value", 42);
JSON val = obj.Get("value");
AssertValidHandle(val);
AssertEq(val.GetInt(), 42);
delete val;
delete obj;
}
TestEnd();
}
// ============================================================================
// 2.3 Array Operations Tests
// ============================================================================
void Test_ArrayOperations()
{
PrintToServer("\n[Category] Array Operations Tests");
// Test array creation
TestStart("Array_Constructor");
{
JSONArray arr = new JSONArray();
AssertValidHandle(arr);
AssertTrue(arr.IsArray);
AssertEq(arr.Length, 0);
delete arr;
}
TestEnd();
// Test Push methods
TestStart("Array_PushInt");
{
JSONArray arr = new JSONArray();
AssertTrue(arr.PushInt(42));
AssertEq(arr.Length, 1);
AssertEq(arr.GetInt(0), 42);
delete arr;
}
TestEnd();
TestStart("Array_PushFloat");
{
JSONArray arr = new JSONArray();
AssertTrue(arr.PushFloat(3.14));
AssertFloatEq(arr.GetFloat(0), 3.14);
delete arr;
}
TestEnd();
TestStart("Array_PushBool");
{
JSONArray arr = new JSONArray();
AssertTrue(arr.PushBool(true));
AssertTrue(arr.GetBool(0));
delete arr;
}
TestEnd();
TestStart("Array_PushString");
{
JSONArray arr = new JSONArray();
AssertTrue(arr.PushString("test"));
char buffer[64];
AssertTrue(arr.GetString(0, buffer, sizeof(buffer)));
AssertStrEq(buffer, "test");
delete arr;
}
TestEnd();
TestStart("Array_PushInt64");
{
JSONArray arr = new JSONArray();
AssertTrue(arr.PushInt64("9223372036854775807"));
char buffer[32];
arr.GetInt64(0, buffer, sizeof(buffer));
AssertStrEq(buffer, "9223372036854775807");
delete arr;
}
TestEnd();
TestStart("Array_PushNull");
{
JSONArray arr = new JSONArray();
AssertTrue(arr.PushNull());
AssertTrue(arr.IsNull(0));
delete arr;
}
TestEnd();
// Test Set/Get methods
TestStart("Array_SetGetInt");
{
JSONArray arr = new JSONArray();
arr.PushInt(0);
AssertTrue(arr.SetInt(0, 100));
AssertEq(arr.GetInt(0), 100);
delete arr;
}
TestEnd();
TestStart("Array_SetGetFloat");
{
JSONArray arr = new JSONArray();
arr.PushFloat(0.0);
AssertTrue(arr.SetFloat(0, 2.718));
AssertFloatEq(arr.GetFloat(0), 2.718);
delete arr;
}
TestEnd();
// Test Remove methods
TestStart("Array_Remove");
{
JSONArray arr = new JSONArray();
arr.PushInt(1);
arr.PushInt(2);
arr.PushInt(3);
AssertEq(arr.Length, 3);
AssertTrue(arr.Remove(1));
AssertEq(arr.Length, 2);
AssertEq(arr.GetInt(0), 1);
AssertEq(arr.GetInt(1), 3);
delete arr;
}
TestEnd();
TestStart("Array_RemoveFirst");
{
JSONArray arr = new JSONArray();
arr.PushInt(1);
arr.PushInt(2);
arr.PushInt(3);
AssertTrue(arr.RemoveFirst());
AssertEq(arr.Length, 2);
AssertEq(arr.GetInt(0), 2);
delete arr;
}
TestEnd();
TestStart("Array_RemoveLast");
{
JSONArray arr = new JSONArray();
arr.PushInt(1);
arr.PushInt(2);
arr.PushInt(3);
AssertTrue(arr.RemoveLast());
AssertEq(arr.Length, 2);
AssertEq(arr.GetInt(1), 2);
delete arr;
}
TestEnd();
TestStart("Array_RemoveRange");
{
JSONArray arr = new JSONArray();
for (int i = 0; i < 10; i++)
{
arr.PushInt(i);
}
AssertTrue(arr.RemoveRange(2, 5));
AssertEq(arr.Length, 5);
delete arr;
}
TestEnd();
TestStart("Array_Clear");
{
JSONArray arr = new JSONArray();
arr.PushInt(1);
arr.PushInt(2);
arr.PushInt(3);
AssertTrue(arr.Clear());
AssertEq(arr.Length, 0);
delete arr;
}
TestEnd();
// Test First/Last properties
TestStart("Array_FirstLast");
{
JSONArray arr = new JSONArray();
arr.PushInt(10);
arr.PushInt(20);
arr.PushInt(30);
JSON first = arr.First;
JSON last = arr.Last;
AssertValidHandle(first);
AssertValidHandle(last);
AssertEq(first.GetInt(), 10);
AssertEq(last.GetInt(), 30);
delete first;
delete last;
delete arr;
}
TestEnd();
// Test IndexOf methods
TestStart("Array_IndexOfInt");
{
JSONArray arr = new JSONArray();
arr.PushInt(10);
arr.PushInt(20);
arr.PushInt(30);
AssertEq(arr.IndexOfInt(20), 1);
AssertEq(arr.IndexOfInt(999), -1);
delete arr;
}
TestEnd();
TestStart("Array_IndexOfBool");
{
JSONArray arr = new JSONArray();
arr.PushBool(false);
arr.PushBool(true);
arr.PushBool(false);
AssertEq(arr.IndexOfBool(true), 1);
delete arr;
}
TestEnd();
TestStart("Array_IndexOfString");
{
JSONArray arr = new JSONArray();
arr.PushString("apple");
arr.PushString("banana");
arr.PushString("cherry");
AssertEq(arr.IndexOfString("banana"), 1);
AssertEq(arr.IndexOfString("orange"), -1);
delete arr;
}
TestEnd();
TestStart("Array_IndexOfFloat");
{
JSONArray arr = new JSONArray();
arr.PushFloat(1.1);
arr.PushFloat(2.2);
arr.PushFloat(3.3);
AssertEq(arr.IndexOfFloat(2.2), 1);
delete arr;
}
TestEnd();
TestStart("Array_IndexOfInt64");
{
JSONArray arr = new JSONArray();
arr.PushInt64("1000000000000");
arr.PushInt64("2000000000000");
AssertEq(arr.IndexOfInt64("2000000000000"), 1);
AssertEq(arr.IndexOfInt64("3000000000000"), -1);
delete arr;
}
TestEnd();
// Test FromString
TestStart("Array_FromString");
{
JSONArray arr = JSONArray.FromString("[1,2,3,4,5]");
AssertValidHandle(arr);
AssertEq(arr.Length, 5);
AssertEq(arr.GetInt(0), 1);
AssertEq(arr.GetInt(4), 5);
delete arr;
}
TestEnd();
// Test FromStrings
TestStart("Array_FromStrings");
{
char strings[][] = {"apple", "banana", "cherry"};
JSONArray arr = JSONArray.FromStrings(strings, sizeof(strings));
AssertValidHandle(arr);
AssertEq(arr.Length, 3);
char buffer[64];
arr.GetString(1, buffer, sizeof(buffer));
AssertStrEq(buffer, "banana");
delete arr;
}
TestEnd();
// Test Sort
TestStart("Array_Sort_Ascending");
{
JSONArray arr = new JSONArray();
arr.PushInt(3);
arr.PushInt(1);
arr.PushInt(4);
arr.PushInt(1);
arr.PushInt(5);
AssertTrue(arr.Sort(JSON_SORT_ASC));
AssertEq(arr.GetInt(0), 1);
AssertEq(arr.GetInt(4), 5);
delete arr;
}
TestEnd();
TestStart("Array_Sort_Descending");
{
JSONArray arr = new JSONArray();
arr.PushInt(1);
arr.PushInt(2);
arr.PushInt(3);
arr.PushInt(4);
arr.PushInt(5);
AssertTrue(arr.Sort(JSON_SORT_DESC));
AssertEq(arr.GetInt(0), 5);
AssertEq(arr.GetInt(4), 1);
delete arr;
}
TestEnd();
// Test Rotate
TestStart("Array_Rotate_Forward");
{
JSONArray arr = new JSONArray();
arr.PushInt(1);
arr.PushInt(2);
arr.PushInt(3);
arr.PushInt(4);
arr.PushInt(5);
AssertTrue(arr.Rotate(2));
AssertEq(arr.GetInt(0), 3, "First element should be 3 after rotate 2");
AssertEq(arr.GetInt(1), 4, "Second element should be 4");
AssertEq(arr.GetInt(2), 5, "Third element should be 5");
AssertEq(arr.GetInt(3), 1, "Fourth element should be 1");
AssertEq(arr.GetInt(4), 2, "Fifth element should be 2");
delete arr;
}
TestEnd();
TestStart("Array_Rotate_Single");
{
JSONArray arr = new JSONArray();
arr.PushString("a");
arr.PushString("b");
arr.PushString("c");
arr.PushString("d");
AssertTrue(arr.Rotate(1));
char buffer[32];
arr.GetString(0, buffer, sizeof(buffer));
AssertStrEq(buffer, "b", "First element should be 'b' after rotate 1");
arr.GetString(3, buffer, sizeof(buffer));
AssertStrEq(buffer, "a", "Last element should be 'a' after rotate 1");
delete arr;
}
TestEnd();
TestStart("Array_Rotate_Zero");
{
JSONArray arr = new JSONArray();
arr.PushInt(10);
arr.PushInt(20);
arr.PushInt(30);
AssertTrue(arr.Rotate(0));
AssertEq(arr.GetInt(0), 10, "Order should not change after rotate 0");
AssertEq(arr.GetInt(1), 20);
AssertEq(arr.GetInt(2), 30);
delete arr;
}
TestEnd();
TestStart("Array_Rotate_LargeIndex");
{
JSONArray arr = new JSONArray();
arr.PushInt(1);
arr.PushInt(2);
arr.PushInt(3);
// Rotate by array length or greater should fail (idx must be < length)
AssertFalse(arr.Rotate(3), "Rotate by array length should fail");
AssertFalse(arr.Rotate(10), "Rotate by value > length should fail");
// Values should remain unchanged
AssertEq(arr.GetInt(0), 1);
AssertEq(arr.GetInt(1), 2);
AssertEq(arr.GetInt(2), 3);
delete arr;
}
TestEnd();
// Test Push with handle
TestStart("Array_PushHandle");
{
JSONArray arr = new JSONArray();
JSON val = JSON.CreateInt(999);
AssertTrue(arr.Push(val));
AssertEq(arr.GetInt(0), 999);
delete val;
delete arr;
}
TestEnd();
// Test Get with handle
TestStart("Array_GetHandle");
{
JSONArray arr = new JSONArray();
arr.PushInt(42);
JSON val = arr.Get(0);
AssertValidHandle(val);
AssertEq(val.GetInt(), 42);
delete val;
delete arr;
}
TestEnd();
// Test FromInt
TestStart("Array_FromInt");
{
int values[] = {10, 20, 30, 40, 50};
JSONArray arr = JSONArray.FromInt(values, sizeof(values));
AssertValidHandle(arr);
AssertEq(arr.Length, 5);
AssertEq(arr.GetInt(0), 10);
AssertEq(arr.GetInt(2), 30);
AssertEq(arr.GetInt(4), 50);
delete arr;
}
TestEnd();
TestStart("Array_FromInt_Negative");
{
int values[] = {-100, -50, 0, 50, 100};
JSONArray arr = JSONArray.FromInt(values, sizeof(values));
AssertValidHandle(arr);
AssertEq(arr.Length, 5);
AssertEq(arr.GetInt(0), -100);
AssertEq(arr.GetInt(2), 0);
AssertEq(arr.GetInt(4), 100);
delete arr;
}
TestEnd();
// Test FromInt64
TestStart("Array_FromInt64_Mixed");
{
char values[][] = {"9223372036854775807", "-9223372036854775808", "0", "18446744073709551615"};
JSONArray arr = JSONArray.FromInt64(values, sizeof(values));
AssertValidHandle(arr);
AssertEq(arr.Length, 4);
char buffer[32];
arr.GetInt64(0, buffer, sizeof(buffer));
AssertStrEq(buffer, "9223372036854775807");
arr.GetInt64(1, buffer, sizeof(buffer));
AssertStrEq(buffer, "-9223372036854775808");
arr.GetInt64(2, buffer, sizeof(buffer));
AssertStrEq(buffer, "0");
arr.GetInt64(3, buffer, sizeof(buffer));
AssertStrEq(buffer, "18446744073709551615");
delete arr;
}
TestEnd();
TestStart("Array_FromInt64_LargeValues");
{
char values[][] = {"1234567890123456", "9876543210987654", "5555555555555555"};
JSONArray arr = JSONArray.FromInt64(values, sizeof(values));
AssertValidHandle(arr);
AssertEq(arr.Length, 3);
char buffer[32];
arr.GetInt64(1, buffer, sizeof(buffer));
AssertStrEq(buffer, "9876543210987654");
delete arr;
}
TestEnd();
// Test FromBool
TestStart("Array_FromBool");
{
bool values[] = {true, false, true, true, false};
JSONArray arr = JSONArray.FromBool(values, sizeof(values));
AssertValidHandle(arr);
AssertEq(arr.Length, 5);
AssertTrue(arr.GetBool(0));
AssertFalse(arr.GetBool(1));
AssertTrue(arr.GetBool(2));
AssertTrue(arr.GetBool(3));
AssertFalse(arr.GetBool(4));
delete arr;
}
TestEnd();
TestStart("Array_FromBool_AllTrue");
{
bool values[] = {true, true, true};
JSONArray arr = JSONArray.FromBool(values, sizeof(values));
AssertValidHandle(arr);
AssertEq(arr.Length, 3);
AssertTrue(arr.GetBool(0));
AssertTrue(arr.GetBool(1));
AssertTrue(arr.GetBool(2));
delete arr;
}
TestEnd();
// Test FromFloat
TestStart("Array_FromFloat");
{
float values[] = {1.1, 2.2, 3.3, 4.4, 5.5};
JSONArray arr = JSONArray.FromFloat(values, sizeof(values));
AssertValidHandle(arr);
AssertEq(arr.Length, 5);
AssertFloatEq(arr.GetFloat(0), 1.1);
AssertFloatEq(arr.GetFloat(2), 3.3, "", 0.01);
AssertFloatEq(arr.GetFloat(4), 5.5);
delete arr;
}
TestEnd();
TestStart("Array_FromFloat_Negative");
{
float values[] = {-3.14, 0.0, 2.718, -1.414};
JSONArray arr = JSONArray.FromFloat(values, sizeof(values));
AssertValidHandle(arr);
AssertEq(arr.Length, 4);
AssertFloatEq(arr.GetFloat(0), -3.14);
AssertFloatEq(arr.GetFloat(1), 0.0);
AssertFloatEq(arr.GetFloat(2), 2.718);
delete arr;
}
TestEnd();
// Test Insert methods
TestStart("Array_InsertInt");
{
JSONArray arr = new JSONArray();
arr.PushInt(1);
arr.PushInt(3);
arr.PushInt(4);
AssertTrue(arr.InsertInt(1, 2));
AssertEq(arr.Length, 4);
AssertEq(arr.GetInt(0), 1);
AssertEq(arr.GetInt(1), 2);
AssertEq(arr.GetInt(2), 3);
AssertEq(arr.GetInt(3), 4);
delete arr;
}
TestEnd();
TestStart("Array_InsertBool");
{
JSONArray arr = new JSONArray();
arr.PushBool(true);
arr.PushBool(true);
AssertTrue(arr.InsertBool(1, false));
AssertEq(arr.Length, 3);
AssertTrue(arr.GetBool(0));
AssertFalse(arr.GetBool(1));
AssertTrue(arr.GetBool(2));
delete arr;
}
TestEnd();
TestStart("Array_InsertFloat");
{
JSONArray arr = new JSONArray();
arr.PushFloat(1.1);
arr.PushFloat(3.3);
AssertTrue(arr.InsertFloat(1, 2.2));
AssertEq(arr.Length, 3);
AssertFloatEq(arr.GetFloat(0), 1.1);
AssertFloatEq(arr.GetFloat(1), 2.2);
AssertFloatEq(arr.GetFloat(2), 3.3, "", 0.01);
delete arr;
}
TestEnd();
TestStart("Array_InsertString");
{
JSONArray arr = new JSONArray();
arr.PushString("first");
arr.PushString("third");
AssertTrue(arr.InsertString(1, "second"));
AssertEq(arr.Length, 3);
char buffer[64];
arr.GetString(0, buffer, sizeof(buffer));
AssertStrEq(buffer, "first");
arr.GetString(1, buffer, sizeof(buffer));
AssertStrEq(buffer, "second");
arr.GetString(2, buffer, sizeof(buffer));
AssertStrEq(buffer, "third");
delete arr;
}
TestEnd();
TestStart("Array_InsertInt64");
{
JSONArray arr = new JSONArray();
arr.PushInt64("1111111111111111");
arr.PushInt64("3333333333333333");
AssertTrue(arr.InsertInt64(1, "2222222222222222"));
AssertEq(arr.Length, 3);
char buffer[32];
arr.GetInt64(0, buffer, sizeof(buffer));
AssertStrEq(buffer, "1111111111111111");
arr.GetInt64(1, buffer, sizeof(buffer));
AssertStrEq(buffer, "2222222222222222");
arr.GetInt64(2, buffer, sizeof(buffer));
AssertStrEq(buffer, "3333333333333333");
delete arr;
}
TestEnd();
TestStart("Array_InsertNull");
{
JSONArray arr = new JSONArray();
arr.PushInt(1);
arr.PushInt(2);
AssertTrue(arr.InsertNull(1));
AssertEq(arr.Length, 3);
AssertEq(arr.GetInt(0), 1);
AssertTrue(arr.IsNull(1));
AssertEq(arr.GetInt(2), 2);
delete arr;
}
TestEnd();
TestStart("Array_InsertAtBeginning");
{
JSONArray arr = new JSONArray();
arr.PushInt(2);
arr.PushInt(3);
AssertTrue(arr.InsertInt(0, 1));
AssertEq(arr.Length, 3);
AssertEq(arr.GetInt(0), 1);
AssertEq(arr.GetInt(1), 2);
AssertEq(arr.GetInt(2), 3);
delete arr;
}
TestEnd();
TestStart("Array_InsertAtEnd");
{
JSONArray arr = new JSONArray();
arr.PushInt(1);
arr.PushInt(2);
AssertTrue(arr.InsertInt(2, 3));
AssertEq(arr.Length, 3);
AssertEq(arr.GetInt(0), 1);
AssertEq(arr.GetInt(1), 2);
AssertEq(arr.GetInt(2), 3);
delete arr;
}
TestEnd();
TestStart("Array_InsertHandle");
{
JSONArray arr = new JSONArray();
arr.PushInt(1);
arr.PushInt(3);
JSON val = JSON.CreateInt(2);
AssertTrue(arr.Insert(1, val));
AssertEq(arr.Length, 3);
AssertEq(arr.GetInt(0), 1);
AssertEq(arr.GetInt(1), 2);
AssertEq(arr.GetInt(2), 3);
delete val;
delete arr;
}
TestEnd();
// Test Prepend methods
TestStart("Array_PrependInt");
{
JSONArray arr = new JSONArray();
arr.PushInt(2);
arr.PushInt(3);
AssertTrue(arr.PrependInt(1));
AssertEq(arr.Length, 3);
AssertEq(arr.GetInt(0), 1);
AssertEq(arr.GetInt(1), 2);
AssertEq(arr.GetInt(2), 3);
delete arr;
}
TestEnd();
TestStart("Array_PrependBool");
{
JSONArray arr = new JSONArray();
arr.PushBool(false);
arr.PushBool(false);
AssertTrue(arr.PrependBool(true));
AssertEq(arr.Length, 3);
AssertTrue(arr.GetBool(0));
AssertFalse(arr.GetBool(1));
AssertFalse(arr.GetBool(2));
delete arr;
}
TestEnd();
TestStart("Array_PrependFloat");
{
JSONArray arr = new JSONArray();
arr.PushFloat(2.2);
arr.PushFloat(3.3);
AssertTrue(arr.PrependFloat(1.1));
AssertEq(arr.Length, 3);
AssertFloatEq(arr.GetFloat(0), 1.1);
AssertFloatEq(arr.GetFloat(1), 2.2);
delete arr;
}
TestEnd();
TestStart("Array_PrependString");
{
JSONArray arr = new JSONArray();
arr.PushString("second");
arr.PushString("third");
AssertTrue(arr.PrependString("first"));
AssertEq(arr.Length, 3);
char buffer[64];
arr.GetString(0, buffer, sizeof(buffer));
AssertStrEq(buffer, "first");
arr.GetString(1, buffer, sizeof(buffer));
AssertStrEq(buffer, "second");
delete arr;
}
TestEnd();
TestStart("Array_PrependInt64");
{
JSONArray arr = new JSONArray();
arr.PushInt64("2222222222222222");
arr.PushInt64("3333333333333333");
AssertTrue(arr.PrependInt64("1111111111111111"));
AssertEq(arr.Length, 3);
char buffer[32];
arr.GetInt64(0, buffer, sizeof(buffer));
AssertStrEq(buffer, "1111111111111111");
arr.GetInt64(1, buffer, sizeof(buffer));
AssertStrEq(buffer, "2222222222222222");
delete arr;
}
TestEnd();
TestStart("Array_PrependNull");
{
JSONArray arr = new JSONArray();
arr.PushInt(1);
arr.PushInt(2);
AssertTrue(arr.PrependNull());
AssertEq(arr.Length, 3);
AssertTrue(arr.IsNull(0));
AssertEq(arr.GetInt(1), 1);
AssertEq(arr.GetInt(2), 2);
delete arr;
}
TestEnd();
TestStart("Array_PrependHandle");
{
JSONArray arr = new JSONArray();
arr.PushInt(2);
arr.PushInt(3);
JSON val = JSON.CreateInt(1);
AssertTrue(arr.Prepend(val));
AssertEq(arr.Length, 3);
AssertEq(arr.GetInt(0), 1);
AssertEq(arr.GetInt(1), 2);
delete val;
delete arr;
}
TestEnd();
TestStart("Array_PrependToEmpty");
{
JSONArray arr = new JSONArray();
AssertTrue(arr.PrependInt(1));
AssertEq(arr.Length, 1);
AssertEq(arr.GetInt(0), 1);
delete arr;
}
TestEnd();
// Test combined Insert and Prepend
TestStart("Array_CombinedInsertPrepend");
{
JSONArray arr = new JSONArray();
arr.PushInt(5);
arr.PrependInt(1);
arr.InsertInt(1, 3);
arr.InsertInt(1, 2);
arr.InsertInt(3, 4);
AssertEq(arr.Length, 5);
AssertEq(arr.GetInt(0), 1);
AssertEq(arr.GetInt(1), 2);
AssertEq(arr.GetInt(2), 3);
AssertEq(arr.GetInt(3), 4);
AssertEq(arr.GetInt(4), 5);
delete arr;
}
TestEnd();
}
// ============================================================================
// 2.4 Parse & Serialize Tests
// ============================================================================
void Test_ParseAndSerialize()
{
PrintToServer("\n[Category] Parse & Serialize Tests");
// Test Parse string
TestStart("Parse_SimpleObject");
{
JSON json = JSON.Parse("{\"key\":\"value\",\"num\":42}");
AssertValidHandle(json);
AssertTrue(json.IsObject);
delete json;
}
TestEnd();
TestStart("Parse_SimpleArray");
{
JSON json = JSON.Parse("[1,2,3,4,5]");
AssertValidHandle(json);
AssertTrue(json.IsArray);
delete json;
}
TestEnd();
TestStart("Parse_NestedStructure");
{
JSON json = JSON.Parse("{\"user\":{\"name\":\"test\",\"age\":25},\"items\":[1,2,3]}");
AssertValidHandle(json);
delete json;
}
TestEnd();
// Test mutable/immutable
TestStart("Parse_ImmutableDocument");
{
JSON json = JSON.Parse("{\"key\":\"value\"}");
AssertValidHandle(json);
AssertTrue(json.IsImmutable);
AssertFalse(json.IsMutable);
delete json;
}
TestEnd();
TestStart("Parse_MutableDocument");
{
JSON json = JSON.Parse("{\"key\":\"value\"}", .is_mutable_doc = true);
AssertValidHandle(json);
AssertTrue(json.IsMutable);
AssertFalse(json.IsImmutable);
delete json;
}
TestEnd();
// Test ValCount (only works on immutable documents)
TestStart("Parse_ValCount_SimpleObject");
{
JSON json = JSON.Parse("{\"a\":1,\"b\":2,\"c\":3}");
AssertValidHandle(json);
int valCount = json.ValCount;
// Object has 7 values: 1 object + 3 keys ("a","b","c") + 3 integer values (1,2,3)
AssertEq(valCount, 7, "Simple object should have 7 values (object + keys + values)");
delete json;
}
TestEnd();
TestStart("Parse_ValCount_NestedStructure");
{
// {"user":{"name":"John","age":30},"items":[1,2,3]}
// Root object: 1
// "user" key + nested object: 2
// "name" key + "John" value: 2
// "age" key + 30 value: 2
// "items" key + array: 2
// Three integers in array: 3
// Total: 1 + 2 + 2 + 2 + 2 + 3 = 12
JSON json = JSON.Parse("{\"user\":{\"name\":\"John\",\"age\":30},\"items\":[1,2,3]}");
AssertValidHandle(json);
int valCount = json.ValCount;
AssertTrue(valCount > 0, "Nested structure should have multiple values");
delete json;
}
TestEnd();
TestStart("Parse_ValCount_Array");
{
JSON json = JSON.Parse("[1,2,3,4,5]");
AssertValidHandle(json);
int valCount = json.ValCount;
// Array itself + 5 integers = 6
AssertEq(valCount, 6, "Array with 5 elements should have 6 values");
delete json;
}
TestEnd();
TestStart("Parse_ValCount_MutableReturnsZero");
{
JSON json = JSON.Parse("{\"key\":\"value\"}", .is_mutable_doc = true);
AssertValidHandle(json);
int valCount = json.ValCount;
AssertEq(valCount, 0, "ValCount should return 0 for mutable documents");
delete json;
}
TestEnd();
TestStart("Parse_ValCount_CreatedObjectReturnsZero");
{
JSONObject obj = new JSONObject();
obj.SetInt("a", 1);
obj.SetInt("b", 2);
int valCount = obj.ValCount;
AssertEq(valCount, 0, "ValCount should return 0 for created (mutable) objects");
delete obj;
}
TestEnd();
// Test ToString
TestStart("Serialize_ToString");
{
JSONObject obj = new JSONObject();
obj.SetInt("num", 42);
obj.SetString("str", "test");
char buffer[256];
int len = obj.ToString(buffer, sizeof(buffer));
AssertTrue(len > 0);
Assert(StrContains(buffer, "num") != -1);
Assert(StrContains(buffer, "test") != -1);
delete obj;
}
TestEnd();
TestStart("Serialize_ToString_Pretty");
{
JSONObject obj = new JSONObject();
obj.SetInt("a", 1);
obj.SetInt("b", 2);
char buffer[256];
int len = obj.ToString(buffer, sizeof(buffer), JSON_WRITE_PRETTY);
AssertTrue(len > 0);
Assert(StrContains(buffer, "\n") != -1, "Pretty output should contain newlines");
delete obj;
}
TestEnd();
// Test GetSerializedSize
TestStart("Serialize_GetSerializedSize");
{
JSONObject obj = new JSONObject();
obj.SetInt("test", 123);
int size = obj.GetSerializedSize();
AssertTrue(size > 0);
char[] buffer = new char[size];
int written = obj.ToString(buffer, size);
AssertEq(written, size);
delete obj;
}
TestEnd();
// Test read flags
TestStart("Parse_WithTrailingCommas");
{
JSON json = JSON.Parse("[1,2,3,]", .flag = JSON_READ_ALLOW_TRAILING_COMMAS);
AssertValidHandle(json);
delete json;
}
TestEnd();
TestStart("Parse_WithComments");
{
JSON json = JSON.Parse("/* comment */ {\"key\":\"value\"}", .flag = JSON_READ_ALLOW_COMMENTS);
AssertValidHandle(json);
delete json;
}
TestEnd();
// Test file operations (create temporary test file)
TestStart("Parse_ToFile_FromFile");
{
JSONObject obj = new JSONObject();
obj.SetInt("filetest", 999);
obj.SetString("name", "testfile");
// Write to file
AssertTrue(obj.ToFile("json_test_temp.json"));
// Read from file
JSONObject loaded = JSON.Parse("json_test_temp.json", true);
AssertValidHandle(loaded);
// Verify content
JSONObject loadedObj = loaded;
AssertEq(loadedObj.GetInt("filetest"), 999);
char buffer[64];
loadedObj.GetString("name", buffer, sizeof(buffer));
AssertStrEq(buffer, "testfile");
delete obj;
delete loaded;
// Cleanup
DeleteFile("json_test_temp.json");
}
TestEnd();
// Test round-trip serialization
TestStart("Parse_RoundTrip");
{
char original[] = "{\"int\":42,\"float\":3.14,\"bool\":true,\"str\":\"test\",\"null\":null}";
JSON json1 = JSON.Parse(original);
char buffer[256];
json1.ToString(buffer, sizeof(buffer));
JSON json2 = JSON.Parse(buffer);
AssertTrue(JSON.Equals(json1, json2));
delete json1;
delete json2;
}
TestEnd();
}
// ============================================================================
// 2.5 Iterator Tests
// ============================================================================
void Test_Iterators()
{
PrintToServer("\n[Category] Iterator Tests");
// Test ForeachObject
TestStart("Iterator_ForeachObject");
{
JSONObject obj = new JSONObject();
obj.SetInt("a", 1);
obj.SetInt("b", 2);
obj.SetInt("c", 3);
int count = 0;
char key[32];
JSONObjIter iter = new JSONObjIter(obj);
while (iter.Next(key, sizeof(key)))
{
count++;
JSON value = iter.Value;
AssertValidHandle(value);
delete value;
}
AssertFalse(iter.HasNext);
AssertEq(count, 3);
AssertTrue(iter.Reset());
count = 0;
while (iter.Next(key, sizeof(key)))
{
count++;
JSON value = iter.Value;
AssertValidHandle(value);
delete value;
}
AssertEq(count, 3);
delete iter;
delete obj;
}
TestEnd();
// Test ForeachArray
TestStart("Iterator_ForeachArray");
{
JSONArray arr = new JSONArray();
arr.PushInt(10);
arr.PushInt(20);
arr.PushInt(30);
int count = 0;
JSONArrIter iter = new JSONArrIter(arr);
while (iter.HasNext)
{
JSON value = iter.Next;
AssertValidHandle(value);
AssertEq(iter.Index, count);
delete value;
count++;
}
AssertFalse(iter.HasNext);
AssertEq(count, 3);
AssertTrue(iter.Reset());
count = 0;
while (iter.HasNext)
{
JSON value = iter.Next;
AssertValidHandle(value);
AssertEq(iter.Index, count);
delete value;
count++;
}
AssertEq(count, 3);
delete iter;
delete arr;
}
TestEnd();
// Test ForeachKey
TestStart("Iterator_ForeachKey");
{
JSONObject obj = new JSONObject();
obj.SetInt("key1", 1);
obj.SetInt("key2", 2);
obj.SetInt("key3", 3);
int count = 0;
char key[32];
JSONObjIter iter = new JSONObjIter(obj);
while (iter.Next(key, sizeof(key)))
{
AssertTrue(strlen(key) > 0);
count++;
}
AssertFalse(iter.HasNext);
AssertEq(count, 3);
AssertTrue(iter.Reset());
count = 0;
while (iter.Next(key, sizeof(key)))
{
AssertTrue(strlen(key) > 0);
count++;
}
AssertEq(count, 3);
delete iter;
delete obj;
}
TestEnd();
// Test ForeachIndex
TestStart("Iterator_ForeachIndex");
{
JSONArray arr = new JSONArray();
arr.PushInt(1);
arr.PushInt(2);
arr.PushInt(3);
int count = 0;
JSONArrIter iter = new JSONArrIter(arr);
while (iter.HasNext)
{
JSON value = iter.Next;
AssertEq(iter.Index, count);
delete value;
count++;
}
AssertFalse(iter.HasNext);
AssertEq(count, 3);
AssertTrue(iter.Reset());
count = 0;
while (iter.HasNext)
{
JSON value = iter.Next;
AssertEq(iter.Index, count);
delete value;
count++;
}
AssertEq(count, 3);
delete iter;
delete arr;
}
TestEnd();
// Test empty iterations
TestStart("Iterator_EmptyObject");
{
JSONObject obj = new JSONObject();
char key[32];
JSONObjIter iter = new JSONObjIter(obj);
AssertFalse(iter.Next(key, sizeof(key)));
AssertTrue(iter.Reset());
AssertFalse(iter.Next(key, sizeof(key)));
delete iter;
delete obj;
}
TestEnd();
TestStart("Iterator_EmptyArray");
{
JSONArray arr = new JSONArray();
JSONArrIter iter = new JSONArrIter(arr);
AssertFalse(iter.HasNext);
AssertTrue(iter.Reset());
AssertFalse(iter.HasNext);
delete iter;
delete arr;
}
TestEnd();
}
// ============================================================================
// 2.6 JSON Pointer Tests
// ============================================================================
void Test_JSONPointer()
{
PrintToServer("\n[Category] JSON Pointer Tests");
// Test PtrSet methods
TestStart("Pointer_PtrSetInt");
{
JSONObject obj = new JSONObject();
AssertTrue(obj.PtrSetInt("/number", 42));
AssertEq(obj.PtrGetInt("/number"), 42);
delete obj;
}
TestEnd();
TestStart("Pointer_PtrSetFloat");
{
JSONObject obj = new JSONObject();
AssertTrue(obj.PtrSetFloat("/pi", 3.14159));
AssertFloatEq(obj.PtrGetFloat("/pi"), 3.14159);
delete obj;
}
TestEnd();
TestStart("Pointer_PtrSetBool");
{
JSONObject obj = new JSONObject();
AssertTrue(obj.PtrSetBool("/flag", true));
AssertTrue(obj.PtrGetBool("/flag"));
delete obj;
}
TestEnd();
TestStart("Pointer_PtrSetString");
{
JSONObject obj = new JSONObject();
AssertTrue(obj.PtrSetString("/name", "test"));
char buffer[64];
AssertTrue(obj.PtrGetString("/name", buffer, sizeof(buffer)));
AssertStrEq(buffer, "test");
delete obj;
}
TestEnd();
TestStart("Pointer_PtrSetInt64");
{
JSONObject obj = new JSONObject();
AssertTrue(obj.PtrSetInt64("/bignum", "9223372036854775807"));
char buffer[32];
AssertTrue(obj.PtrGetInt64("/bignum", buffer, sizeof(buffer)));
AssertStrEq(buffer, "9223372036854775807");
delete obj;
}
TestEnd();
TestStart("Pointer_PtrSetNull");
{
JSONObject obj = new JSONObject();
AssertTrue(obj.PtrSetNull("/nullable"));
AssertTrue(obj.PtrGetIsNull("/nullable"));
delete obj;
}
TestEnd();
// Test nested path creation
TestStart("Pointer_NestedPathCreation");
{
JSONObject obj = new JSONObject();
AssertTrue(obj.PtrSetInt("/a/b/c/d", 123));
AssertEq(obj.PtrGetInt("/a/b/c/d"), 123);
delete obj;
}
TestEnd();
// Test PtrGet with handle
TestStart("Pointer_PtrGet");
{
JSONObject obj = new JSONObject();
obj.PtrSetInt("/test", 999);
JSON val = obj.PtrGet("/test");
AssertValidHandle(val);
AssertEq(val.GetInt(), 999);
delete val;
delete obj;
}
TestEnd();
// Test PtrAdd methods
TestStart("Pointer_PtrAddInt");
{
JSONObject obj = new JSONObject();
obj.PtrSetInt("/arr/0", 1);
AssertTrue(obj.PtrAddInt("/arr/1", 2));
AssertEq(obj.PtrGetInt("/arr/1"), 2);
delete obj;
}
TestEnd();
TestStart("Pointer_PtrAddString");
{
JSONObject obj = new JSONObject();
obj.PtrSetString("/items/0", "first");
AssertTrue(obj.PtrAddString("/items/1", "second"));
char buffer[64];
obj.PtrGetString("/items/1", buffer, sizeof(buffer));
AssertStrEq(buffer, "second");
delete obj;
}
TestEnd();
// Test PtrRemove
TestStart("Pointer_PtrRemove");
{
JSONObject obj = new JSONObject();
obj.PtrSetInt("/remove_me", 1);
obj.PtrSetInt("/keep_me", 2);
AssertTrue(obj.PtrRemove("/remove_me"));
JSON val;
obj.PtrTryGetVal("/remove_me", val);
AssertNullHandle(val);
delete obj;
}
TestEnd();
// Test PtrGetLength
TestStart("Pointer_PtrGetLength");
{
JSONObject obj = new JSONObject();
obj.PtrSetString("/text", "hello");
int len = obj.PtrGetLength("/text");
AssertEq(len, 6); // Including null terminator
delete obj;
}
TestEnd();
// Test PtrTryGet methods
TestStart("Pointer_PtrTryGetInt");
{
JSONObject obj = new JSONObject();
obj.PtrSetInt("/value", 42);
int value;
AssertTrue(obj.PtrTryGetInt("/value", value));
AssertEq(value, 42);
AssertFalse(obj.PtrTryGetInt("/nonexistent", value));
delete obj;
}
TestEnd();
TestStart("Pointer_PtrTryGetBool");
{
JSONObject obj = new JSONObject();
obj.PtrSetBool("/flag", true);
bool value;
AssertTrue(obj.PtrTryGetBool("/flag", value));
AssertTrue(value);
delete obj;
}
TestEnd();
TestStart("Pointer_PtrTryGetFloat");
{
JSONObject obj = new JSONObject();
obj.PtrSetFloat("/pi", 3.14);
float value;
AssertTrue(obj.PtrTryGetFloat("/pi", value));
AssertFloatEq(value, 3.14);
delete obj;
}
TestEnd();
TestStart("Pointer_PtrTryGetString");
{
JSONObject obj = new JSONObject();
obj.PtrSetString("/name", "test");
char buffer[64];
AssertTrue(obj.PtrTryGetString("/name", buffer, sizeof(buffer)));
AssertStrEq(buffer, "test");
delete obj;
}
TestEnd();
TestStart("Pointer_PtrTryGetInt64");
{
JSONObject obj = new JSONObject();
obj.PtrSetInt64("/bignum", "123456789012345");
char buffer[32];
AssertTrue(obj.PtrTryGetInt64("/bignum", buffer, sizeof(buffer)));
AssertStrEq(buffer, "123456789012345");
delete obj;
}
TestEnd();
TestStart("Pointer_PtrTryGetVal");
{
JSONObject obj = new JSONObject();
obj.PtrSetInt("/test", 42);
JSON value;
AssertTrue(obj.PtrTryGetVal("/test", value));
AssertValidHandle(value);
AssertEq(value.GetInt(), 42);
delete value;
delete obj;
}
TestEnd();
}
// ============================================================================
// 2.7 Advanced Features Tests
// ============================================================================
void Test_AdvancedFeatures()
{
PrintToServer("\n[Category] Advanced Features Tests");
// Test DeepCopy
TestStart("Advanced_DeepCopy_Object");
{
JSONObject original = new JSONObject();
original.SetInt("num", 42);
original.SetString("str", "test");
JSONObject target = new JSONObject();
JSONObject copy = JSON.DeepCopy(target, original);
AssertValidHandle(copy);
AssertEq(copy.GetInt("num"), 42);
char buffer[64];
copy.GetString("str", buffer, sizeof(buffer));
AssertStrEq(buffer, "test");
delete original;
delete target;
delete copy;
}
TestEnd();
TestStart("Advanced_DeepCopy_Array");
{
JSONArray original = new JSONArray();
original.PushInt(1);
original.PushInt(2);
original.PushInt(3);
JSONArray target = new JSONArray();
JSONArray copy = JSON.DeepCopy(target, original);
AssertValidHandle(copy);
AssertEq(copy.Length, 3);
AssertEq(copy.GetInt(0), 1);
AssertEq(copy.GetInt(2), 3);
delete original;
delete target;
delete copy;
}
TestEnd();
// Test Equals
TestStart("Advanced_Equals_True");
{
JSONObject obj1 = new JSONObject();
obj1.SetInt("a", 1);
obj1.SetString("b", "test");
JSONObject obj2 = new JSONObject();
obj2.SetInt("a", 1);
obj2.SetString("b", "test");
AssertTrue(JSON.Equals(obj1, obj2));
delete obj1;
delete obj2;
}
TestEnd();
TestStart("Advanced_Equals_False");
{
JSONObject obj1 = new JSONObject();
obj1.SetInt("a", 1);
JSONObject obj2 = new JSONObject();
obj2.SetInt("a", 2);
AssertFalse(JSON.Equals(obj1, obj2));
delete obj1;
delete obj2;
}
TestEnd();
// Test ToMutable/ToImmutable
TestStart("Advanced_ToMutable");
{
JSON immutable = JSON.Parse("{\"key\":\"value\"}");
AssertTrue(immutable.IsImmutable);
JSON mutable = immutable.ToMutable();
AssertValidHandle(mutable);
AssertTrue(mutable.IsMutable);
delete immutable;
delete mutable;
}
TestEnd();
TestStart("Advanced_ToImmutable");
{
JSONObject mutable = new JSONObject();
mutable.SetInt("key", 42);
AssertTrue(mutable.IsMutable);
JSON immutable = mutable.ToImmutable();
AssertValidHandle(immutable);
AssertTrue(immutable.IsImmutable);
delete mutable;
delete immutable;
}
TestEnd();
// Test ApplyJsonPatch (new value, immutable result)
TestStart("Advanced_ApplyJsonPatch");
{
JSONObject original = new JSONObject();
original.SetInt("score", 10);
original.SetString("name", "bot");
JSON patch = JSON.Parse("[{\"op\":\"replace\",\"path\":\"/score\",\"value\":42}]");
AssertValidHandle(patch);
JSON result = original.ApplyJsonPatch(patch);
AssertValidHandle(result);
AssertTrue(result.IsImmutable);
AssertEq(result.PtrGetInt("/score"), 42);
char buffer[32];
result.PtrGetString("/name", buffer, sizeof(buffer));
AssertStrEq(buffer, "bot");
// ensure original unchanged
AssertEq(original.GetInt("score"), 10);
delete result;
delete patch;
delete original;
}
TestEnd();
// Test ApplyJsonPatch resultMutable = true
TestStart("Advanced_ApplyJsonPatch_MutableResult");
{
JSONObject original = new JSONObject();
original.SetInt("count", 1);
JSON patch = JSON.Parse("[{\"op\":\"add\",\"path\":\"/newField\",\"value\":\"hello\"}]");
AssertValidHandle(patch);
JSON result = original.ApplyJsonPatch(patch, true);
AssertValidHandle(result);
AssertTrue(result.IsMutable);
char buffer[16];
result.PtrGetString("/newField", buffer, sizeof(buffer));
AssertStrEq(buffer, "hello");
delete result;
delete patch;
delete original;
}
TestEnd();
// Test JsonPatchInPlace
TestStart("Advanced_JsonPatchInPlace");
{
JSONObject target = new JSONObject();
target.SetInt("score", 5);
target.SetInt("lives", 3);
JSON patch = JSON.Parse("[{\"op\":\"remove\",\"path\":\"/lives\"},{\"op\":\"replace\",\"path\":\"/score\",\"value\":9}]");
AssertValidHandle(patch);
AssertTrue(target.JsonPatchInPlace(patch));
AssertEq(target.GetInt("score"), 9);
AssertFalse(target.HasKey("lives"));
delete patch;
delete target;
}
TestEnd();
// Test ApplyMergePatch (immutable result)
TestStart("Advanced_ApplyMergePatch");
{
JSONObject original = new JSONObject();
original.PtrSetString("/settings/mode", "coop");
original.PtrSetInt("/settings/difficulty", 1);
JSON mergePatch = JSON.Parse("{\"settings\":{\"difficulty\":3,\"friendlyFire\":true}}");
AssertValidHandle(mergePatch);
JSON result = original.ApplyMergePatch(mergePatch);
AssertValidHandle(result);
AssertTrue(result.IsImmutable);
AssertEq(result.PtrGetInt("/settings/difficulty"), 3);
AssertTrue(result.PtrGetBool("/settings/friendlyFire"));
delete result;
delete mergePatch;
delete original;
}
TestEnd();
// Test ApplyMergePatch resultMutable = true
TestStart("Advanced_ApplyMergePatch_MutableResult");
{
JSONObject original = new JSONObject();
original.PtrSetString("/profile/name", "player");
JSON mergePatch = JSON.Parse("{\"profile\":{\"rank\":10}}");
AssertValidHandle(mergePatch);
JSON result = original.ApplyMergePatch(mergePatch, true);
AssertValidHandle(result);
AssertTrue(result.IsMutable);
AssertEq(result.PtrGetInt("/profile/rank"), 10);
char buffer[16];
result.PtrGetString("/profile/name", buffer, sizeof(buffer));
AssertStrEq(buffer, "player");
delete result;
delete mergePatch;
delete original;
}
TestEnd();
// Test MergePatchInPlace
TestStart("Advanced_MergePatchInPlace");
{
JSONObject target = new JSONObject();
target.PtrSetString("/config/mode", "coop");
target.PtrSetInt("/config/players", 4);
JSON mergePatch = JSON.Parse("{\"config\":{\"players\":6,\"region\":\"EU\"}}");
AssertValidHandle(mergePatch);
AssertTrue(target.MergePatchInPlace(mergePatch));
AssertEq(target.PtrGetInt("/config/players"), 6);
char buffer[16];
target.PtrGetString("/config/region", buffer, sizeof(buffer));
AssertStrEq(buffer, "EU");
delete mergePatch;
delete target;
}
TestEnd();
// Test Pack
TestStart("Advanced_Pack_SimpleObject");
{
JSONObject json = JSON.Pack("{s:i,s:s,s:b}",
"num", 42,
"str", "test",
"bool", true
);
AssertValidHandle(json);
AssertTrue(json.IsObject);
JSONObject obj = json;
AssertEq(obj.GetInt("num"), 42);
char buffer[64];
obj.GetString("str", buffer, sizeof(buffer));
AssertStrEq(buffer, "test");
AssertTrue(obj.GetBool("bool"));
delete json;
}
TestEnd();
TestStart("Advanced_Pack_Array");
{
JSONArray json = JSON.Pack("[i,i,i]", 1, 2, 3);
AssertValidHandle(json);
AssertTrue(json.IsArray);
JSONArray arr = json;
AssertEq(arr.Length, 3);
AssertEq(arr.GetInt(0), 1);
AssertEq(arr.GetInt(2), 3);
delete json;
}
TestEnd();
TestStart("Advanced_Pack_Nested");
{
JSONObject json = JSON.Pack("{s:{s:s,s:i}}",
"user",
"name", "test",
"age", 25
);
AssertValidHandle(json);
char buffer[64];
JSONObject obj = json;
obj.PtrGetString("/user/name", buffer, sizeof(buffer));
AssertStrEq(buffer, "test");
AssertEq(obj.PtrGetInt("/user/age"), 25);
delete json;
}
TestEnd();
// Test mixed type array sorting
TestStart("Advanced_MixedTypeSort");
{
JSONArray json = JSON.Parse("[true, 42, \"hello\", 1.5, false]", .is_mutable_doc = true);
JSONArray arr = json;
AssertTrue(arr.Sort(JSON_SORT_ASC));
AssertEq(arr.Length, 5);
delete json;
}
TestEnd();
}
// ============================================================================
// 2.8 Int64 Operations Tests
// ============================================================================
void Test_Int64Operations()
{
PrintToServer("\n[Category] Int64 Operations Tests");
// Test JSON.SetInt64 - Modify value in-place
TestStart("Int64_SetInt64_Positive");
{
JSON val = JSON.CreateInt(100);
AssertTrue(val.SetInt64("123456789012345"));
char buffer[32];
AssertTrue(val.GetInt64(buffer, sizeof(buffer)));
AssertStrEq(buffer, "123456789012345");
delete val;
}
TestEnd();
TestStart("Int64_SetInt64_Negative");
{
JSON val = JSON.CreateInt(100);
AssertTrue(val.SetInt64("-987654321098765"));
char buffer[32];
AssertTrue(val.GetInt64(buffer, sizeof(buffer)));
AssertStrEq(buffer, "-987654321098765");
delete val;
}
TestEnd();
TestStart("Int64_SetInt64_Zero");
{
JSON val = JSON.CreateInt(999);
AssertTrue(val.SetInt64("0"));
char buffer[32];
AssertTrue(val.GetInt64(buffer, sizeof(buffer)));
AssertStrEq(buffer, "0");
delete val;
}
TestEnd();
// Test JSONArray.SetInt64 - Replace value in array
TestStart("Int64_Array_SetInt64");
{
JSONArray arr = new JSONArray();
arr.PushInt(100);
arr.PushInt(200);
arr.PushInt(300);
AssertTrue(arr.SetInt64(1, "5555555555555555"));
char buffer[32];
arr.GetInt64(1, buffer, sizeof(buffer));
AssertStrEq(buffer, "5555555555555555");
delete arr;
}
TestEnd();
TestStart("Int64_Array_SetInt64_Negative");
{
JSONArray arr = new JSONArray();
arr.PushInt64("1111111111111111");
AssertTrue(arr.SetInt64(0, "-2222222222222222"));
char buffer[32];
arr.GetInt64(0, buffer, sizeof(buffer));
AssertStrEq(buffer, "-2222222222222222");
delete arr;
}
TestEnd();
// Test large unsigned int64 values
TestStart("Int64_Array_PushLargeUnsigned");
{
JSONArray arr = new JSONArray();
AssertTrue(arr.PushInt64("18446744073709551615"));
char buffer[32];
arr.GetInt64(0, buffer, sizeof(buffer));
AssertStrEq(buffer, "18446744073709551615");
delete arr;
}
TestEnd();
TestStart("Int64_Array_IndexOfLargeValues");
{
JSONArray arr = new JSONArray();
arr.PushInt64("11111111111111111");
arr.PushInt64("22222222222222222");
arr.PushInt64("33333333333333333");
AssertEq(arr.IndexOfInt64("22222222222222222"), 1);
AssertEq(arr.IndexOfInt64("99999999999999999"), -1);
delete arr;
}
TestEnd();
// Test PtrAddInt64
TestStart("Int64_Pointer_PtrAddInt64");
{
JSONObject obj = new JSONObject();
obj.PtrSetInt("/numbers/0", 1);
AssertTrue(obj.PtrAddInt64("/numbers/1", "7777777777777777"));
char buffer[32];
AssertTrue(obj.PtrGetInt64("/numbers/1", buffer, sizeof(buffer)));
AssertStrEq(buffer, "7777777777777777");
delete obj;
}
TestEnd();
TestStart("Int64_Pointer_PtrAddInt64_Negative");
{
JSONObject obj = new JSONObject();
obj.PtrSetInt("/data/0", 1);
AssertTrue(obj.PtrAddInt64("/data/1", "-8888888888888888"));
char buffer[32];
AssertTrue(obj.PtrGetInt64("/data/1", buffer, sizeof(buffer)));
AssertStrEq(buffer, "-8888888888888888");
delete obj;
}
TestEnd();
// Test PtrAddInt64 with large unsigned value
TestStart("Int64_Pointer_PtrAddInt64_LargeUnsigned");
{
JSONObject obj = new JSONObject();
obj.PtrSetInt("/bigvals/0", 1);
AssertTrue(obj.PtrAddInt64("/bigvals/1", "18446744073709551615"));
char buffer[32];
AssertTrue(obj.PtrGetInt64("/bigvals/1", buffer, sizeof(buffer)));
AssertStrEq(buffer, "18446744073709551615");
delete obj;
}
TestEnd();
// Test mixed signed/unsigned values
TestStart("Int64_Mixed_SignedUnsigned_Array");
{
JSONArray arr = new JSONArray();
arr.PushInt64("-9223372036854775808");
arr.PushInt64("18446744073709551615");
arr.PushInt64("0");
arr.PushInt64("9223372036854775807");
AssertEq(arr.Length, 4);
char buffer[32];
arr.GetInt64(0, buffer, sizeof(buffer));
AssertStrEq(buffer, "-9223372036854775808");
arr.GetInt64(1, buffer, sizeof(buffer));
AssertStrEq(buffer, "18446744073709551615");
arr.GetInt64(2, buffer, sizeof(buffer));
AssertStrEq(buffer, "0");
arr.GetInt64(3, buffer, sizeof(buffer));
AssertStrEq(buffer, "9223372036854775807");
delete arr;
}
TestEnd();
TestStart("Int64_Mixed_SignedUnsigned_Object");
{
JSONObject obj = new JSONObject();
obj.SetInt64("min_int64", "-9223372036854775808");
obj.SetInt64("max_int64", "9223372036854775807");
obj.SetInt64("max_uint64", "18446744073709551615");
char buffer[32];
AssertTrue(obj.GetInt64("min_int64", buffer, sizeof(buffer)));
AssertStrEq(buffer, "-9223372036854775808");
AssertTrue(obj.GetInt64("max_int64", buffer, sizeof(buffer)));
AssertStrEq(buffer, "9223372036854775807");
AssertTrue(obj.GetInt64("max_uint64", buffer, sizeof(buffer)));
AssertStrEq(buffer, "18446744073709551615");
delete obj;
}
TestEnd();
// Test serialization with int64
TestStart("Int64_Serialization_ToString");
{
JSONObject obj = new JSONObject();
obj.SetInt64("large_num", "9007199254740992");
obj.SetInt64("negative_num", "-9007199254740992");
char json[256];
int len = obj.ToString(json, sizeof(json));
AssertTrue(len > 0);
// Parse it back
JSONObject parsed = JSONObject.FromString(json);
AssertValidHandle(parsed);
char buffer[32];
AssertTrue(parsed.GetInt64("large_num", buffer, sizeof(buffer)));
AssertStrEq(buffer, "9007199254740992");
AssertTrue(parsed.GetInt64("negative_num", buffer, sizeof(buffer)));
AssertStrEq(buffer, "-9007199254740992");
delete obj;
delete parsed;
}
TestEnd();
TestStart("Int64_Serialization_Array");
{
JSONArray arr = new JSONArray();
arr.PushInt64("1234567890123456");
arr.PushInt64("-9876543210987654");
arr.PushInt64("18000000000000000000");
char json[256];
int len = arr.ToString(json, sizeof(json));
AssertTrue(len > 0);
// Parse it back
JSONArray parsed = JSONArray.FromString(json);
AssertValidHandle(parsed);
AssertEq(parsed.Length, 3);
char buffer[32];
parsed.GetInt64(0, buffer, sizeof(buffer));
AssertStrEq(buffer, "1234567890123456");
parsed.GetInt64(1, buffer, sizeof(buffer));
AssertStrEq(buffer, "-9876543210987654");
parsed.GetInt64(2, buffer, sizeof(buffer));
AssertStrEq(buffer, "18000000000000000000");
delete arr;
delete parsed;
}
TestEnd();
// Test boundary values
TestStart("Int64_Boundary_JustAboveInt32Max");
{
JSON val = JSON.CreateInt64("2147483648");
AssertValidHandle(val);
char buffer[32];
AssertTrue(val.GetInt64(buffer, sizeof(buffer)));
AssertStrEq(buffer, "2147483648");
delete val;
}
TestEnd();
TestStart("Int64_Boundary_JustBelowInt32Min");
{
JSON val = JSON.CreateInt64("-2147483649");
AssertValidHandle(val);
char buffer[32];
AssertTrue(val.GetInt64(buffer, sizeof(buffer)));
AssertStrEq(buffer, "-2147483649");
delete val;
}
TestEnd();
TestStart("Int64_Boundary_UInt32Max");
{
JSON val = JSON.CreateInt64("4294967295");
AssertValidHandle(val);
char buffer[32];
AssertTrue(val.GetInt64(buffer, sizeof(buffer)));
AssertStrEq(buffer, "4294967295");
delete val;
}
TestEnd();
TestStart("Int64_Boundary_JustAboveUInt32Max");
{
JSON val = JSON.CreateInt64("4294967296");
AssertValidHandle(val);
char buffer[32];
AssertTrue(val.GetInt64(buffer, sizeof(buffer)));
AssertStrEq(buffer, "4294967296");
delete val;
}
TestEnd();
// Test Int64 in nested structures
TestStart("Int64_Nested_ObjectInObject");
{
JSONObject obj = new JSONObject();
obj.PtrSetInt64("/outer/inner/deep", "5432109876543210");
char buffer[32];
AssertTrue(obj.PtrGetInt64("/outer/inner/deep", buffer, sizeof(buffer)));
AssertStrEq(buffer, "5432109876543210");
delete obj;
}
TestEnd();
TestStart("Int64_Nested_ArrayInObject");
{
JSONObject obj = new JSONObject();
obj.PtrSetInt64("/data/values/0", "1111111111111111");
obj.PtrAddInt64("/data/values/1", "2222222222222222");
obj.PtrAddInt64("/data/values/2", "3333333333333333");
char buffer[32];
AssertTrue(obj.PtrGetInt64("/data/values/0", buffer, sizeof(buffer)));
AssertStrEq(buffer, "1111111111111111");
AssertTrue(obj.PtrGetInt64("/data/values/1", buffer, sizeof(buffer)));
AssertStrEq(buffer, "2222222222222222");
AssertTrue(obj.PtrGetInt64("/data/values/2", buffer, sizeof(buffer)));
AssertStrEq(buffer, "3333333333333333");
delete obj;
}
TestEnd();
// Test DeepCopy with int64
TestStart("Int64_DeepCopy_Object");
{
JSONObject original = new JSONObject();
original.SetInt64("bignum", "9999999999999999");
original.SetInt64("negative", "-8888888888888888");
JSONObject target = new JSONObject();
JSONObject copy = JSON.DeepCopy(target, original);
AssertValidHandle(copy);
char buffer[32];
AssertTrue(copy.GetInt64("bignum", buffer, sizeof(buffer)));
AssertStrEq(buffer, "9999999999999999");
AssertTrue(copy.GetInt64("negative", buffer, sizeof(buffer)));
AssertStrEq(buffer, "-8888888888888888");
delete original;
delete target;
delete copy;
}
TestEnd();
TestStart("Int64_DeepCopy_Array");
{
JSONArray original = new JSONArray();
original.PushInt64("1111111111111111");
original.PushInt64("-2222222222222222");
original.PushInt64("18446744073709551615");
JSONArray target = new JSONArray();
JSONArray copy = JSON.DeepCopy(target, original);
AssertValidHandle(copy);
AssertEq(copy.Length, 3);
char buffer[32];
copy.GetInt64(0, buffer, sizeof(buffer));
AssertStrEq(buffer, "1111111111111111");
copy.GetInt64(1, buffer, sizeof(buffer));
AssertStrEq(buffer, "-2222222222222222");
copy.GetInt64(2, buffer, sizeof(buffer));
AssertStrEq(buffer, "18446744073709551615");
delete original;
delete target;
delete copy;
}
TestEnd();
// Test array sorting with int64 values
TestStart("Int64_Array_Sort_Ascending");
{
JSONArray arr = new JSONArray();
arr.PushInt64("9999999999999999");
arr.PushInt64("1111111111111111");
arr.PushInt64("5555555555555555");
arr.PushInt64("3333333333333333");
AssertTrue(arr.Sort(JSON_SORT_ASC));
char buffer[32];
arr.GetInt64(0, buffer, sizeof(buffer));
AssertStrEq(buffer, "1111111111111111");
arr.GetInt64(3, buffer, sizeof(buffer));
AssertStrEq(buffer, "9999999999999999");
delete arr;
}
TestEnd();
TestStart("Int64_Array_Sort_Descending");
{
JSONArray arr = new JSONArray();
arr.PushInt64("1111111111111111");
arr.PushInt64("5555555555555555");
arr.PushInt64("3333333333333333");
arr.PushInt64("9999999999999999");
AssertTrue(arr.Sort(JSON_SORT_DESC));
char buffer[32];
arr.GetInt64(0, buffer, sizeof(buffer));
AssertStrEq(buffer, "9999999999999999");
arr.GetInt64(3, buffer, sizeof(buffer));
AssertStrEq(buffer, "1111111111111111");
delete arr;
}
TestEnd();
// Test int64 with type checks
TestStart("Int64_TypeChecks");
{
JSON val = JSON.CreateInt64("9223372036854775807");
AssertTrue(val.IsNum);
AssertTrue(val.IsInt);
AssertFalse(val.IsFloat);
AssertFalse(val.IsStr);
AssertFalse(val.IsBool);
delete val;
}
TestEnd();
TestStart("Int64_TypeChecks_Signed");
{
JSON val = JSON.CreateInt64("-9223372036854775808");
AssertTrue(val.IsNum);
AssertTrue(val.IsInt);
AssertTrue(val.IsSint);
AssertFalse(val.IsUint);
delete val;
}
TestEnd();
TestStart("Int64_TypeChecks_LargeUnsigned");
{
JSON val = JSON.CreateInt64("18446744073709551615");
AssertTrue(val.IsNum);
AssertTrue(val.IsInt);
// Large unsigned value should be detected as unsigned integer
AssertTrue(val.IsUint);
AssertFalse(val.IsSint);
delete val;
}
TestEnd();
}
// ============================================================================
// 2.9 Edge Cases & Error Handling Tests
// ============================================================================
void Test_EdgeCases()
{
PrintToServer("\n[Category] Edge Cases & Error Handling Tests");
// Test empty containers
TestStart("EdgeCase_EmptyObject");
{
JSONObject obj = new JSONObject();
AssertEq(obj.Size, 0);
AssertFalse(obj.HasKey("anything"));
char buffer[64];
int len = obj.ToString(buffer, sizeof(buffer));
AssertTrue(len > 0);
delete obj;
}
TestEnd();
TestStart("EdgeCase_EmptyArray");
{
JSONArray arr = new JSONArray();
AssertEq(arr.Length, 0);
delete arr;
}
TestEnd();
// Test nonexistent keys/indices
TestStart("EdgeCase_NonexistentKey");
{
JSONObject obj = new JSONObject();
obj.SetInt("exists", 1);
AssertTrue(obj.HasKey("exists"));
AssertFalse(obj.HasKey("notexists"));
delete obj;
}
TestEnd();
TestStart("EdgeCase_ArrayOutOfBounds");
{
JSONArray arr = new JSONArray();
arr.PushInt(1);
// Verify array bounds
AssertEq(arr.Length, 1);
AssertEq(arr.GetInt(0), 1);
delete arr;
}
TestEnd();
// Test very long strings
TestStart("EdgeCase_LongString");
{
char longStr[1024];
for (int i = 0; i < sizeof(longStr) - 1; i++)
{
longStr[i] = 'A' + (i % 26);
}
longStr[sizeof(longStr) - 1] = '\0';
JSON val = JSON.CreateString(longStr);
AssertValidHandle(val);
char retrieved[1024];
AssertTrue(val.GetString(retrieved, sizeof(retrieved)));
AssertStrEq(retrieved, longStr);
delete val;
}
TestEnd();
// Test deep nesting
TestStart("EdgeCase_DeepNesting");
{
JSONObject obj = new JSONObject();
// Create deeply nested structure
obj.PtrSetInt("/a/b/c/d/e/f/g/h/i/j", 42);
AssertEq(obj.PtrGetInt("/a/b/c/d/e/f/g/h/i/j"), 42);
delete obj;
}
TestEnd();
// Test large arrays
TestStart("EdgeCase_LargeArray");
{
JSONArray arr = new JSONArray();
for (int i = 0; i < 1000; i++)
{
arr.PushInt(i);
}
AssertEq(arr.Length, 1000);
AssertEq(arr.GetInt(0), 0);
AssertEq(arr.GetInt(999), 999);
delete arr;
}
TestEnd();
// Test large objects
TestStart("EdgeCase_LargeObject");
{
JSONObject obj = new JSONObject();
char key[32];
for (int i = 0; i < 100; i++)
{
FormatEx(key, sizeof(key), "key_%d", i);
obj.SetInt(key, i);
}
AssertEq(obj.Size, 100);
AssertEq(obj.GetInt("key_0"), 0);
AssertEq(obj.GetInt("key_99"), 99);
delete obj;
}
TestEnd();
// Test int64 boundaries
TestStart("EdgeCase_Int64_MaxValue");
{
JSON val = JSON.CreateInt64("9223372036854775807");
AssertValidHandle(val);
char buffer[32];
val.GetInt64(buffer, sizeof(buffer));
AssertStrEq(buffer, "9223372036854775807");
delete val;
}
TestEnd();
TestStart("EdgeCase_Int64_MinValue");
{
JSON val = JSON.CreateInt64("-9223372036854775808");
AssertValidHandle(val);
char buffer[32];
val.GetInt64(buffer, sizeof(buffer));
AssertStrEq(buffer, "-9223372036854775808");
delete val;
}
TestEnd();
// Test special float values
TestStart("EdgeCase_Float_VerySmall");
{
JSON val = JSON.CreateFloat(0.000001);
AssertValidHandle(val);
AssertFloatEq(val.GetFloat(), 0.000001);
delete val;
}
TestEnd();
TestStart("EdgeCase_Float_VeryLarge");
{
JSON val = JSON.CreateFloat(999999.999999);
AssertValidHandle(val);
AssertFloatEq(val.GetFloat(), 999999.999999, "", 0.001);
delete val;
}
TestEnd();
// Test special characters in strings
TestStart("EdgeCase_SpecialCharacters");
{
JSON val = JSON.CreateString("Line1\nLine2\tTabbed\"Quoted\"");
AssertValidHandle(val);
char buffer[128];
val.GetString(buffer, sizeof(buffer));
Assert(StrContains(buffer, "Line1") != -1);
delete val;
}
TestEnd();
// Test removing from empty array
TestStart("EdgeCase_RemoveFromEmptyArray");
{
JSONArray arr = new JSONArray();
AssertFalse(arr.RemoveFirst());
AssertFalse(arr.RemoveLast());
delete arr;
}
TestEnd();
// Test clearing already empty containers
TestStart("EdgeCase_ClearEmpty");
{
JSONObject obj = new JSONObject();
AssertTrue(obj.Clear());
AssertEq(obj.Size, 0);
JSONArray arr = new JSONArray();
AssertTrue(arr.Clear());
AssertEq(arr.Length, 0);
delete obj;
delete arr;
}
TestEnd();
// Test IndexOf on empty array
TestStart("EdgeCase_IndexOfEmpty");
{
JSONArray arr = new JSONArray();
AssertEq(arr.IndexOfInt(42), -1);
AssertEq(arr.IndexOfString("test"), -1);
AssertEq(arr.IndexOfBool(true), -1);
delete arr;
}
TestEnd();
// Test pointer to nonexistent path
TestStart("EdgeCase_PointerNonexistentPath");
{
JSONObject obj = new JSONObject();
// Note: PtrGet throws exception for nonexistent paths (expected behavior)
// Use PtrTryGet methods for safe access
int intVal;
AssertFalse(obj.PtrTryGetInt("/does/not/exist", intVal));
delete obj;
}
TestEnd();
// Test sorting empty containers
TestStart("EdgeCase_SortEmpty");
{
JSONObject obj = new JSONObject();
AssertTrue(obj.Sort());
JSONArray arr = new JSONArray();
AssertTrue(arr.Sort());
delete obj;
delete arr;
}
TestEnd();
// Test single element operations
TestStart("EdgeCase_SingleElement");
{
JSONArray arr = new JSONArray();
arr.PushInt(42);
AssertTrue(arr.Sort());
AssertEq(arr.GetInt(0), 42);
AssertEq(arr.IndexOfInt(42), 0);
JSON first = arr.First;
JSON last = arr.Last;
AssertEq(first.GetInt(), last.GetInt());
delete first;
delete last;
delete arr;
}
TestEnd();
}