Files
IACore/Tests/Unit/JSON.cpp
dev0 cfa0759133
Some checks failed
CI / build-linux-and-wasm (x64-linux) (push) Has been cancelled
TestSuite
2026-01-23 05:52:26 +05:30

192 lines
5.6 KiB
C++

// IACore-OSS; The Core Library for All IA Open Source Projects
// Copyright (C) 2026 IAS (ias@iasoft.dev)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <IACore/IATest.hpp>
#include <IACore/JSON.hpp>
using namespace IACore;
// -----------------------------------------------------------------------------
// Test Structures for Serialization
// -----------------------------------------------------------------------------
struct UserProfile {
String username;
u32 id;
bool is_active;
Vec<String> roles;
// Equality operator for verification
bool operator==(const UserProfile &other) const {
return username == other.username && id == other.id &&
is_active == other.is_active && roles == other.roles;
}
};
// -----------------------------------------------------------------------------
// Test Block Definition
// -----------------------------------------------------------------------------
IAT_BEGIN_BLOCK(Core, JSON)
// -------------------------------------------------------------------------
// 1. Dynamic JSON (nlohmann::json)
// -------------------------------------------------------------------------
auto test_dynamic_parse() -> bool {
const String json_text = R"({
"string": "Hello World",
"int": 42,
"float": 3.14159,
"bool": true,
"array": [10, 20, 30],
"object": { "key": "value" }
})";
auto res = Json::parse(json_text);
IAT_CHECK(res.has_value());
const auto &j = *res;
// Type checks and value retrieval
IAT_CHECK(j["string"].is_string());
IAT_CHECK_EQ(j["string"].get<String>(), String("Hello World"));
IAT_CHECK(j["int"].is_number_integer());
IAT_CHECK_EQ(j["int"].get<i32>(), 42);
IAT_CHECK(j["float"].is_number_float());
IAT_CHECK_APPROX(j["float"].get<f32>(), 3.14159f);
IAT_CHECK(j["bool"].is_boolean());
IAT_CHECK_EQ(j["bool"].get<bool>(), true);
IAT_CHECK(j["array"].is_array());
IAT_CHECK_EQ(j["array"].size(), 3u);
IAT_CHECK_EQ(j["array"][0].get<i32>(), 10);
IAT_CHECK(j["object"].is_object());
IAT_CHECK_EQ(j["object"]["key"].get<String>(), String("value"));
return true;
}
auto test_dynamic_encode() -> bool {
nlohmann::json j;
j["name"] = "IACore";
j["version"] = 2;
const String encoded = Json::encode(j);
// Simple containment check as key order isn't guaranteed
IAT_CHECK(encoded.find("IACore") != String::npos);
IAT_CHECK(encoded.find("version") != String::npos);
IAT_CHECK(encoded.find("2") != String::npos);
return true;
}
auto test_parse_invalid() -> bool {
const String bad_json = "{ key: value }"; // Missing quotes
auto res = Json::parse(bad_json);
IAT_CHECK_NOT(res.has_value());
return true;
}
// -------------------------------------------------------------------------
// 2. Struct Serialization (Glaze)
// -------------------------------------------------------------------------
auto test_struct_round_trip() -> bool {
UserProfile original{.username = "test_user",
.id = 12345,
.is_active = true,
.roles = {"admin", "editor"}};
// Struct -> JSON
auto encode_res = Json::encode_struct(original);
IAT_CHECK(encode_res.has_value());
String json_str = *encode_res;
// Verify JSON structure roughly
IAT_CHECK(json_str.find("test_user") != String::npos);
IAT_CHECK(json_str.find("roles") != String::npos);
// JSON -> Struct
auto decode_res = Json::parse_to_struct<UserProfile>(json_str);
IAT_CHECK(decode_res.has_value());
UserProfile decoded = *decode_res;
IAT_CHECK(decoded == original);
return true;
}
auto test_struct_parse_error() -> bool {
const String malformed = "{ broken_json: ";
auto res = Json::parse_to_struct<UserProfile>(malformed);
IAT_CHECK_NOT(res.has_value());
return true;
}
// -------------------------------------------------------------------------
// 3. Read-Only Parsing (simdjson)
// -------------------------------------------------------------------------
auto test_read_only() -> bool {
const String json_text = R"({
"id": 999,
"name": "Simd",
"scores": [1.1, 2.2]
})";
auto res = Json::parse_read_only(json_text);
IAT_CHECK(res.has_value());
auto &doc = *res;
simdjson::dom::element root = doc.root();
// Check ID
u64 id = 0;
auto err_id = root["id"].get(id);
IAT_CHECK(!err_id);
IAT_CHECK_EQ(id, 999ULL);
// Check Name
std::string_view name;
auto err_name = root["name"].get(name);
IAT_CHECK(!err_name);
IAT_CHECK_EQ(String(name), String("Simd"));
// Check Array
simdjson::dom::array scores;
auto err_arr = root["scores"].get(scores);
IAT_CHECK(!err_arr);
IAT_CHECK_EQ(scores.size(), 2u);
return true;
}
// -------------------------------------------------------------------------
// Registration
// -------------------------------------------------------------------------
IAT_BEGIN_TEST_LIST()
IAT_ADD_TEST(test_dynamic_parse);
IAT_ADD_TEST(test_dynamic_encode);
IAT_ADD_TEST(test_parse_invalid);
IAT_ADD_TEST(test_struct_round_trip);
IAT_ADD_TEST(test_struct_parse_error);
IAT_ADD_TEST(test_read_only);
IAT_END_TEST_LIST()
IAT_END_BLOCK()
IAT_REGISTER_ENTRY(Core, JSON)