/**
 * @file event_params_test.cpp
 * @brief Standalone C++ test for the EventParams tagged union type.
 *
 * Tests the EventValue and EventParams classes directly (C++ API),
 * covering all supported types: entity ID, int, float, double, string,
 * and arrays of each type.
 *
 * Build with:
 *   g++ -std=c++17 -I. -I../.. -I../../lua/lua-5.4.8/src \
 *       event_params_test.cpp \
 *       -o event_params_test -lm
 *
 * Or via CMake (see CMakeLists.txt in this directory).
 */

#include <cstdio>
#include <cstring>
#include <cassert>
#include <string>
#include <vector>
#include <cmath>

// Ogre stub (provides Ogre::String, Ogre::Vector3, Ogre::LogManager)
#include "ogre_stub.h"

// Include the component under test
#include "../components/EventParams.hpp"

using namespace editScene;

// ---------------------------------------------------------------------------
// Test helpers
// ---------------------------------------------------------------------------

static int testCount = 0;
static int passCount = 0;

#define TEST(name)                                             \
	do {                                                   \
		testCount++;                                   \
		printf("  TEST %d: %s ... ", testCount, name); \
	} while (0)

#define PASS()                    \
	do {                      \
		passCount++;      \
		printf("PASS\n"); \
	} while (0)

#define FAIL(msg)                          \
	do {                               \
		printf("FAIL: %s\n", msg); \
		return 1;                  \
	} while (0)

// ---------------------------------------------------------------------------
// Test 1: EventValue default construction (nil)
// ---------------------------------------------------------------------------

static int testDefaultValue()
{
	TEST("EventValue default construction (nil)");

	EventValue v;
	if (v.getType() != EventValue::NIL)
		FAIL("expected NIL type");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Test 2: EventValue entity ID construction
// ---------------------------------------------------------------------------

static int testEntityIdValue()
{
	TEST("EventValue entity ID construction");

	uint64_t id = 12345;
	EventValue v(id);
	if (v.getType() != EventValue::ENTITY_ID)
		FAIL("expected ENTITY_ID type");
	if (v.getEntityId() != id)
		FAIL("entity ID mismatch");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Test 3: EventValue int construction
// ---------------------------------------------------------------------------

static int testIntValue()
{
	TEST("EventValue int construction");

	int64_t val = -42;
	EventValue v(val);
	if (v.getType() != EventValue::INT)
		FAIL("expected INT type");
	if (v.getInt() != val)
		FAIL("int value mismatch");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Test 4: EventValue float construction
// ---------------------------------------------------------------------------

static int testFloatValue()
{
	TEST("EventValue float construction");

	float val = 3.14f;
	EventValue v(val);
	if (v.getType() != EventValue::FLOAT)
		FAIL("expected FLOAT type");
	if (std::abs(v.getFloat() - val) > 0.0001f)
		FAIL("float value mismatch");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Test 5: EventValue double construction
// ---------------------------------------------------------------------------

static int testDoubleValue()
{
	TEST("EventValue double construction");

	double val = 3.141592653589793;
	EventValue v(val);
	if (v.getType() != EventValue::DOUBLE)
		FAIL("expected DOUBLE type");
	if (std::abs(v.getDouble() - val) > 1e-12)
		FAIL("double value mismatch");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Test 6: EventValue string construction
// ---------------------------------------------------------------------------

static int testStringValue()
{
	TEST("EventValue string construction");

	std::string val = "hello world";
	EventValue v(val);
	if (v.getType() != EventValue::STRING)
		FAIL("expected STRING type");
	if (v.getString() != val)
		FAIL("string value mismatch");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Test 7: EventValue entity ID array construction
// ---------------------------------------------------------------------------

static int testEntityIdArrayValue()
{
	TEST("EventValue entity ID array construction");

	std::vector<uint64_t> arr = { 100, 200, 300 };
	EventValue v(arr);
	if (v.getType() != EventValue::ENTITY_ID_ARRAY)
		FAIL("expected ENTITY_ID_ARRAY type");
	const auto &result = v.getEntityIdArray();
	if (result.size() != 3)
		FAIL("array size mismatch");
	if (result[0] != 100 || result[1] != 200 || result[2] != 300)
		FAIL("array element mismatch");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Test 8: EventValue int array construction
// ---------------------------------------------------------------------------

static int testIntArrayValue()
{
	TEST("EventValue int array construction");

	std::vector<int64_t> arr = { -1, 0, 42, 999 };
	EventValue v(arr);
	if (v.getType() != EventValue::INT_ARRAY)
		FAIL("expected INT_ARRAY type");
	const auto &result = v.getIntArray();
	if (result.size() != 4)
		FAIL("array size mismatch");
	if (result[0] != -1 || result[1] != 0 || result[2] != 42 ||
	    result[3] != 999)
		FAIL("array element mismatch");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Test 9: EventValue float array construction
// ---------------------------------------------------------------------------

static int testFloatArrayValue()
{
	TEST("EventValue float array construction");

	std::vector<float> arr = { 1.5f, 2.5f, 3.5f };
	EventValue v(arr);
	if (v.getType() != EventValue::FLOAT_ARRAY)
		FAIL("expected FLOAT_ARRAY type");
	const auto &result = v.getFloatArray();
	if (result.size() != 3)
		FAIL("array size mismatch");
	if (std::abs(result[0] - 1.5f) > 0.0001f ||
	    std::abs(result[1] - 2.5f) > 0.0001f ||
	    std::abs(result[2] - 3.5f) > 0.0001f)
		FAIL("array element mismatch");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Test 10: EventValue double array construction
// ---------------------------------------------------------------------------

static int testDoubleArrayValue()
{
	TEST("EventValue double array construction");

	std::vector<double> arr = { 1.1, 2.2, 3.3, 4.4 };
	EventValue v(arr);
	if (v.getType() != EventValue::DOUBLE_ARRAY)
		FAIL("expected DOUBLE_ARRAY type");
	const auto &result = v.getDoubleArray();
	if (result.size() != 4)
		FAIL("array size mismatch");
	if (std::abs(result[0] - 1.1) > 1e-12 ||
	    std::abs(result[1] - 2.2) > 1e-12 ||
	    std::abs(result[2] - 3.3) > 1e-12 ||
	    std::abs(result[3] - 4.4) > 1e-12)
		FAIL("array element mismatch");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Test 11: EventValue string array construction
// ---------------------------------------------------------------------------

static int testStringArrayValue()
{
	TEST("EventValue string array construction");

	std::vector<std::string> arr = { "foo", "bar", "baz" };
	EventValue v(arr);
	if (v.getType() != EventValue::STRING_ARRAY)
		FAIL("expected STRING_ARRAY type");
	const auto &result = v.getStringArray();
	if (result.size() != 3)
		FAIL("array size mismatch");
	if (result[0] != "foo" || result[1] != "bar" || result[2] != "baz")
		FAIL("array element mismatch");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Test 12: EventValue copy construction
// ---------------------------------------------------------------------------

static int testCopyConstruction()
{
	TEST("EventValue copy construction");

	EventValue original((int64_t)42);
	EventValue copy(original);
	if (copy.getType() != EventValue::INT)
		FAIL("expected INT type after copy");
	if (copy.getInt() != 42)
		FAIL("int value mismatch after copy");

	// Modify original should not affect copy
	original = EventValue((int64_t)99);
	if (copy.getInt() != 42)
		FAIL("copy should be independent");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Test 13: EventValue assignment
// ---------------------------------------------------------------------------

static int testAssignment()
{
	TEST("EventValue assignment");

	EventValue v;
	v = EventValue(std::string("test"));
	if (v.getType() != EventValue::STRING)
		FAIL("expected STRING type after assignment");
	if (v.getString() != "test")
		FAIL("string value mismatch after assignment");

	// Re-assign to different type
	v = EventValue((double)2.71828);
	if (v.getType() != EventValue::DOUBLE)
		FAIL("expected DOUBLE type after re-assignment");
	if (std::abs(v.getDouble() - 2.71828) > 1e-12)
		FAIL("double value mismatch after re-assignment");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Test 14: EventParams default construction
// ---------------------------------------------------------------------------

static int testParamsDefault()
{
	TEST("EventParams default construction");

	EventParams p;
	if (p.begin() != p.end())
		FAIL("expected empty params");
	if (p.size() != 0)
		FAIL("expected size 0");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Test 15: EventParams set/get int
// ---------------------------------------------------------------------------

static int testParamsSetGetInt()
{
	TEST("EventParams set/get int");

	EventParams p;
	p.setInt("score", 100);
	if (p.size() != 1)
		FAIL("expected size 1");
	if (p.getInt("score") != 100)
		FAIL("expected score 100");
	if (p.has("score") != true)
		FAIL("expected has('score') == true");
	if (p.has("missing") != false)
		FAIL("expected has('missing') == false");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Test 16: EventParams set/get float
// ---------------------------------------------------------------------------

static int testParamsSetGetFloat()
{
	TEST("EventParams set/get float");

	EventParams p;
	p.setFloat("speed", 1.5f);
	if (p.getFloat("speed") != 1.5f)
		FAIL("expected speed 1.5");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Test 17: EventParams set/get double
// ---------------------------------------------------------------------------

static int testParamsSetGetDouble()
{
	TEST("EventParams set/get double");

	EventParams p;
	p.setDouble("pi", 3.141592653589793);
	if (std::abs(p.getDouble("pi") - 3.141592653589793) > 1e-12)
		FAIL("expected pi value");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Test 18: EventParams set/get string
// ---------------------------------------------------------------------------

static int testParamsSetGetString()
{
	TEST("EventParams set/get string");

	EventParams p;
	p.setString("name", "hero");
	if (p.getString("name") != "hero")
		FAIL("expected name 'hero'");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Test 19: EventParams set/get entity ID
// ---------------------------------------------------------------------------

static int testParamsSetGetEntityId()
{
	TEST("EventParams set/get entity ID");

	EventParams p;
	p.setEntityId("target", 12345);
	if (p.getEntityId("target") != 12345)
		FAIL("expected target 12345");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Test 20: EventParams set/get int array via EventValue
// ---------------------------------------------------------------------------

static int testParamsSetGetIntArray()
{
	TEST("EventParams set/get int array");

	EventParams p;
	std::vector<int64_t> arr = { 1, 2, 3, 4, 5 };
	p.setIntArray("values", arr);
	const EventValue *v = p.get("values");
	if (!v)
		FAIL("expected value for 'values'");
	if (v->getType() != EventValue::INT_ARRAY)
		FAIL("expected INT_ARRAY type");
	const auto &result = v->getIntArray();
	if (result.size() != 5)
		FAIL("expected array size 5");
	if (result[0] != 1 || result[4] != 5)
		FAIL("array element mismatch");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Test 21: EventParams set/get float array via EventValue
// ---------------------------------------------------------------------------

static int testParamsSetGetFloatArray()
{
	TEST("EventParams set/get float array");

	EventParams p;
	std::vector<float> arr = { 0.5f, 1.0f, 1.5f };
	p.setFloatArray("positions", arr);
	const EventValue *v = p.get("positions");
	if (!v)
		FAIL("expected value for 'positions'");
	if (v->getType() != EventValue::FLOAT_ARRAY)
		FAIL("expected FLOAT_ARRAY type");
	const auto &result = v->getFloatArray();
	if (result.size() != 3)
		FAIL("expected array size 3");
	if (std::abs(result[0] - 0.5f) > 0.0001f)
		FAIL("array element mismatch");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Test 22: EventParams set/get double array via EventValue
// ---------------------------------------------------------------------------

static int testParamsSetGetDoubleArray()
{
	TEST("EventParams set/get double array");

	EventParams p;
	std::vector<double> arr = { 1.1, 2.2, 3.3 };
	p.setDoubleArray("coords", arr);
	const EventValue *v = p.get("coords");
	if (!v)
		FAIL("expected value for 'coords'");
	if (v->getType() != EventValue::DOUBLE_ARRAY)
		FAIL("expected DOUBLE_ARRAY type");
	const auto &result = v->getDoubleArray();
	if (result.size() != 3)
		FAIL("expected array size 3");
	if (std::abs(result[2] - 3.3) > 1e-12)
		FAIL("array element mismatch");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Test 23: EventParams set/get string array via EventValue
// ---------------------------------------------------------------------------

static int testParamsSetGetStringArray()
{
	TEST("EventParams set/get string array");

	EventParams p;
	std::vector<std::string> arr = { "a", "b", "c" };
	p.setStringArray("tags", arr);
	const EventValue *v = p.get("tags");
	if (!v)
		FAIL("expected value for 'tags'");
	if (v->getType() != EventValue::STRING_ARRAY)
		FAIL("expected STRING_ARRAY type");
	const auto &result = v->getStringArray();
	if (result.size() != 3)
		FAIL("expected array size 3");
	if (result[0] != "a" || result[2] != "c")
		FAIL("array element mismatch");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Test 24: EventParams set/get entity ID array via EventValue
// ---------------------------------------------------------------------------

static int testParamsSetGetEntityIdArray()
{
	TEST("EventParams set/get entity ID array");

	EventParams p;
	std::vector<uint64_t> arr = { 100, 200, 300 };
	p.setEntityIdArray("entities", arr);
	const EventValue *v = p.get("entities");
	if (!v)
		FAIL("expected value for 'entities'");
	if (v->getType() != EventValue::ENTITY_ID_ARRAY)
		FAIL("expected ENTITY_ID_ARRAY type");
	const auto &result = v->getEntityIdArray();
	if (result.size() != 3)
		FAIL("expected array size 3");
	if (result[0] != 100 || result[2] != 300)
		FAIL("array element mismatch");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Test 25: EventParams multiple types
// ---------------------------------------------------------------------------

static int testParamsMultipleTypes()
{
	TEST("EventParams multiple types");

	EventParams p;
	p.setInt("score", 42);
	p.setFloat("speed", 1.5f);
	p.setDouble("pi", 3.14);
	p.setString("name", "test");
	p.setEntityId("target", 999);

	if (p.size() != 5)
		FAIL("expected size 5");
	if (p.getInt("score") != 42)
		FAIL("expected score 42");
	if (std::abs(p.getFloat("speed") - 1.5f) > 0.0001f)
		FAIL("expected speed 1.5");
	if (std::abs(p.getDouble("pi") - 3.14) > 0.001)
		FAIL("expected pi 3.14");
	if (p.getString("name") != "test")
		FAIL("expected name 'test'");
	if (p.getEntityId("target") != 999)
		FAIL("expected target 999");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Test 26: EventParams iteration
// ---------------------------------------------------------------------------

static int testParamsIteration()
{
	TEST("EventParams iteration");

	EventParams p;
	p.setInt("a", 1);
	p.setInt("b", 2);
	p.setInt("c", 3);

	int count = 0;
	bool foundA = false, foundB = false, foundC = false;
	for (EventParams::ConstIterator it = p.begin(); it != p.end(); ++it) {
		count++;
		if (it->first == "a")
			foundA = true;
		if (it->first == "b")
			foundB = true;
		if (it->first == "c")
			foundC = true;
	}
	if (count != 3)
		FAIL("expected 3 entries");
	if (!foundA || !foundB || !foundC)
		FAIL("missing expected keys");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Test 27: EventParams merge
// ---------------------------------------------------------------------------

static int testParamsMerge()
{
	TEST("EventParams merge");

	EventParams p1;
	p1.setInt("a", 1);
	p1.setString("b", "hello");

	EventParams p2;
	p2.setInt("c", 3);
	p2.setFloat("d", 4.5f);

	p1.merge(p2);
	if (p1.size() != 4)
		FAIL("expected size 4 after merge");
	if (p1.getInt("a") != 1)
		FAIL("expected a=1");
	if (p1.getString("b") != "hello")
		FAIL("expected b='hello'");
	if (p1.getInt("c") != 3)
		FAIL("expected c=3");
	if (std::abs(p1.getFloat("d") - 4.5f) > 0.0001f)
		FAIL("expected d=4.5");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Test 28: EventParams merge with override
// ---------------------------------------------------------------------------

static int testParamsMergeOverride()
{
	TEST("EventParams merge with override");

	EventParams p1;
	p1.setInt("a", 1);
	p1.setString("b", "original");

	EventParams p2;
	p2.setInt("a", 99);
	p2.setString("b", "overridden");

	p1.merge(p2);
	if (p1.getInt("a") != 99)
		FAIL("expected a=99 after override");
	if (p1.getString("b") != "overridden")
		FAIL("expected b='overridden' after override");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Test 29: EventParams dump
// ---------------------------------------------------------------------------

static int testParamsDump()
{
	TEST("EventParams dump");

	EventParams p;
	p.setInt("score", 42);
	p.setString("name", "test");

	std::string dump = p.dump();
	if (dump.empty())
		FAIL("dump should not be empty");
	if (dump.find("score") == std::string::npos)
		FAIL("dump should contain 'score'");
	if (dump.find("name") == std::string::npos)
		FAIL("dump should contain 'name'");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Test 30: EventParams equality
// ---------------------------------------------------------------------------

static int testParamsEquality()
{
	TEST("EventParams equality");

	EventParams p1;
	p1.setInt("a", 1);
	p1.setString("b", "test");

	EventParams p2;
	p2.setInt("a", 1);
	p2.setString("b", "test");

	if (!(p1 == p2))
		FAIL("expected equal params");

	EventParams p3;
	p3.setInt("a", 99);
	p3.setString("b", "test");

	if (p1 == p3)
		FAIL("expected different params to be unequal");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Test 31: EventParams clear
// ---------------------------------------------------------------------------

static int testParamsClear()
{
	TEST("EventParams clear");

	EventParams p;
	p.setInt("a", 1);
	p.setString("b", "test");
	if (p.size() != 2)
		FAIL("expected size 2 before clear");

	p.clear();
	if (p.size() != 0)
		FAIL("expected size 0 after clear");
	if (p.begin() != p.end())
		FAIL("expected empty after clear");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Test 32: EventValue equality
// ---------------------------------------------------------------------------

static int testValueEquality()
{
	TEST("EventValue equality");

	EventValue v1((int64_t)42);
	EventValue v2((int64_t)42);
	EventValue v3((int64_t)99);

	if (!(v1 == v2))
		FAIL("expected equal values");
	if (v1 == v3)
		FAIL("expected different values to be unequal");

	// Different types should be unequal
	EventValue v4(3.14f);
	if (v1 == v4)
		FAIL("expected different types to be unequal");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Test 33: EventValue asNumeric
// ---------------------------------------------------------------------------

static int testValueAsNumeric()
{
	TEST("EventValue asNumeric");

	EventValue vi((int64_t)42);
	if (std::abs(vi.asNumeric() - 42.0) > 0.0001)
		FAIL("expected int asNumeric 42");

	EventValue vf(3.14f);
	if (std::abs(vf.asNumeric() - 3.14) > 0.001)
		FAIL("expected float asNumeric 3.14");

	EventValue vd(2.71828);
	if (std::abs(vd.asNumeric() - 2.71828) > 1e-12)
		FAIL("expected double asNumeric 2.71828");

	EventValue ve((uint64_t)100);
	if (std::abs(ve.asNumeric() - 100.0) > 0.0001)
		FAIL("expected entity_id asNumeric 100");

	// Nil should return 0
	EventValue vn;
	if (vn.asNumeric() != 0.0)
		FAIL("expected nil asNumeric 0");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Test 34: EventParams remove
// ---------------------------------------------------------------------------

static int testParamsRemove()
{
	TEST("EventParams remove key");

	EventParams p;
	p.setInt("a", 1);
	p.setInt("b", 2);
	if (p.size() != 2)
		FAIL("expected size 2");

	p.remove("a");
	if (p.size() != 1)
		FAIL("expected size 1 after remove");
	if (p.has("a"))
		FAIL("expected 'a' to be removed");
	if (!p.has("b"))
		FAIL("expected 'b' to still exist");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Test 35: EventValue move semantics
// ---------------------------------------------------------------------------

static int testValueMove()
{
	TEST("EventValue move semantics");

	EventValue original(std::string("moved"));
	EventValue moved(std::move(original));
	if (moved.getType() != EventValue::STRING)
		FAIL("expected STRING type after move");
	if (moved.getString() != "moved")
		FAIL("string value mismatch after move");
	// Original should be nil after move
	if (original.getType() != EventValue::NIL)
		FAIL("original should be NIL after move");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Test 36: EventValue char* constructor
// ---------------------------------------------------------------------------

static int testCharPtrValue()
{
	TEST("EventValue char* construction");

	EventValue v("hello from c-string");
	if (v.getType() != EventValue::STRING)
		FAIL("expected STRING type");
	if (v.getString() != "hello from c-string")
		FAIL("string value mismatch");

	// Null pointer should give empty string
	EventValue vnull((const char *)nullptr);
	if (vnull.getType() != EventValue::STRING)
		FAIL("expected STRING type for null");
	if (vnull.getString() != "")
		FAIL("expected empty string for null");

	PASS();
	return 0;
}

// ---------------------------------------------------------------------------
// Main
// ---------------------------------------------------------------------------

int main()
{
	printf("EventParams C++ API Tests\n");
	printf("=========================\n\n");

	int failures = 0;
	failures += testDefaultValue();
	failures += testEntityIdValue();
	failures += testIntValue();
	failures += testFloatValue();
	failures += testDoubleValue();
	failures += testStringValue();
	failures += testEntityIdArrayValue();
	failures += testIntArrayValue();
	failures += testFloatArrayValue();
	failures += testDoubleArrayValue();
	failures += testStringArrayValue();
	failures += testCopyConstruction();
	failures += testAssignment();
	failures += testParamsDefault();
	failures += testParamsSetGetInt();
	failures += testParamsSetGetFloat();
	failures += testParamsSetGetDouble();
	failures += testParamsSetGetString();
	failures += testParamsSetGetEntityId();
	failures += testParamsSetGetIntArray();
	failures += testParamsSetGetFloatArray();
	failures += testParamsSetGetDoubleArray();
	failures += testParamsSetGetStringArray();
	failures += testParamsSetGetEntityIdArray();
	failures += testParamsMultipleTypes();
	failures += testParamsIteration();
	failures += testParamsMerge();
	failures += testParamsMergeOverride();
	failures += testParamsDump();
	failures += testParamsEquality();
	failures += testParamsClear();
	failures += testValueEquality();
	failures += testValueAsNumeric();
	failures += testParamsRemove();
	failures += testValueMove();
	failures += testCharPtrValue();

	printf("\nResults: %d/%d passed, %d failed\n", passCount, testCount,
	       failures);

	return failures > 0 ? 1 : 0;
}
