summaryrefslogtreecommitdiffstats
path: root/src/VBox/Runtime/testcase/tstRTCRest-1.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Runtime/testcase/tstRTCRest-1.cpp')
-rw-r--r--src/VBox/Runtime/testcase/tstRTCRest-1.cpp2295
1 files changed, 2295 insertions, 0 deletions
diff --git a/src/VBox/Runtime/testcase/tstRTCRest-1.cpp b/src/VBox/Runtime/testcase/tstRTCRest-1.cpp
new file mode 100644
index 00000000..e96c1e10
--- /dev/null
+++ b/src/VBox/Runtime/testcase/tstRTCRest-1.cpp
@@ -0,0 +1,2295 @@
+/* $Id: tstRTCRest-1.cpp $ */
+/** @file
+ * IPRT Testcase - REST C++ classes.
+ */
+
+/*
+ * Copyright (C) 2018-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/cpp/restbase.h>
+#include <iprt/cpp/restarray.h>
+#include <iprt/cpp/reststringmap.h>
+#include <iprt/cpp/restclient.h>
+#include <iprt/cpp/restoutput.h>
+
+#include <iprt/ctype.h>
+#include <iprt/err.h>
+#include <iprt/message.h>
+#include <iprt/string.h>
+#include <iprt/test.h>
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+static RTTEST g_hTest;
+
+
+static char *toJson(RTCRestObjectBase const *pObj)
+{
+ RTCString str;
+ RTCRestOutputToString Dst(&str, false);
+ pObj->serializeAsJson(Dst);
+
+ static char s_szReturnBuffer[4096];
+ RTStrCopy(s_szReturnBuffer, sizeof(s_szReturnBuffer), str.c_str());
+ return s_szReturnBuffer;
+}
+
+
+static int deserializeFromJson(RTCRestObjectBase *pObj, const char *pszJson, PRTERRINFOSTATIC pErrInfo, const char *pszName)
+{
+ RTJSONVAL hValue;
+ RTTESTI_CHECK_RC_OK_RET(RTJsonParseFromString(&hValue, pszJson, pErrInfo ? RTErrInfoInitStatic(pErrInfo) : NULL), rcCheck);
+ RTCRestJsonPrimaryCursor Cursor(hValue, pszName, pErrInfo ? RTErrInfoInitStatic(pErrInfo) : NULL);
+ return pObj->deserializeFromJson(Cursor.m_Cursor);
+}
+
+
+static int fromString(RTCRestObjectBase *pObj, const char *pszString, PRTERRINFOSTATIC pErrInfo, const char *pszName)
+{
+ RTCString strValue(pszString);
+ return pObj->fromString(strValue, pszName, pErrInfo ? RTErrInfoInitStatic(pErrInfo) : NULL);
+}
+
+
+static void testBool(void)
+{
+ RTTestSub(g_hTest, "RTCRestBool");
+
+ {
+ RTCRestBool obj1;
+ RTTESTI_CHECK(obj1.m_fValue == false);
+ RTTESTI_CHECK(obj1.isNull() == false);
+ RTTESTI_CHECK(strcmp(obj1.typeName(), "bool") == 0);
+ RTTESTI_CHECK(obj1.typeClass() == RTCRestObjectBase::kTypeClass_Bool);
+ }
+
+ {
+ RTCRestBool obj2(true);
+ RTTESTI_CHECK(obj2.m_fValue == true);
+ RTTESTI_CHECK(obj2.isNull() == false);
+ }
+
+ {
+ RTCRestBool obj2(false);
+ RTTESTI_CHECK(obj2.m_fValue == false);
+ RTTESTI_CHECK(obj2.isNull() == false);
+ }
+
+ {
+ /* Value assignments: */
+ RTCRestBool obj3;
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.isNull() == true);
+ obj3.assignValue(true);
+ RTTESTI_CHECK(obj3.m_fValue == true);
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.isNull() == true);
+ obj3.assignValue(false);
+ RTTESTI_CHECK(obj3.m_fValue == false);
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ obj3.assignValue(true);
+ RTTESTI_CHECK(obj3.m_fValue == true);
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ RTTESTI_CHECK_RC(obj3.resetToDefault(), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.m_fValue == false);
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ obj3.assignValue(true);
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK_RC(obj3.resetToDefault(), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.m_fValue == false);
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ /* Copy assignments: */
+ RTCRestBool obj3True(true);
+ RTTESTI_CHECK(obj3True.m_fValue == true);
+ RTTESTI_CHECK(obj3True.isNull() == false);
+ RTCRestBool obj3False(false);
+ RTTESTI_CHECK(obj3False.m_fValue == false);
+ RTTESTI_CHECK(obj3False.isNull() == false);
+ RTCRestBool obj3Null;
+ obj3Null.setNull();
+ RTTESTI_CHECK(obj3Null.m_fValue == false);
+ RTTESTI_CHECK(obj3Null.isNull() == true);
+
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK_RC(obj3.assignCopy(obj3True), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.m_fValue == true);
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ RTTESTI_CHECK_RC(obj3.assignCopy(obj3Null), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.m_fValue == false);
+ RTTESTI_CHECK(obj3.isNull() == true);
+
+ RTTESTI_CHECK_RC(obj3.assignCopy(obj3False), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.m_fValue == false);
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ obj3 = obj3Null;
+ RTTESTI_CHECK(obj3.m_fValue == false);
+ RTTESTI_CHECK(obj3.isNull() == true);
+
+ obj3 = obj3True;
+ RTTESTI_CHECK(obj3.m_fValue == true);
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ obj3 = obj3Null;
+ RTTESTI_CHECK(obj3.m_fValue == false);
+ RTTESTI_CHECK(obj3.isNull() == true);
+
+ obj3 = obj3False;
+ RTTESTI_CHECK(obj3.m_fValue == false);
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ /* setNull implies resetToDefault: */
+ obj3 = obj3True;
+ RTTESTI_CHECK(obj3.m_fValue == true);
+ RTTESTI_CHECK(obj3.isNull() == false);
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.isNull() == true);
+ RTTESTI_CHECK(obj3.m_fValue == false);
+
+ /* Copy constructors: */
+ {
+ RTCRestBool obj3a(obj3True);
+ RTTESTI_CHECK(obj3a.m_fValue == true);
+ RTTESTI_CHECK(obj3a.isNull() == false);
+ }
+ {
+ RTCRestBool obj3b(obj3False);
+ RTTESTI_CHECK(obj3b.m_fValue == false);
+ RTTESTI_CHECK(obj3b.isNull() == false);
+ }
+ {
+ RTCRestBool obj3c(obj3Null);
+ RTTESTI_CHECK(obj3c.m_fValue == false);
+ RTTESTI_CHECK(obj3c.isNull() == true);
+ }
+
+ /* Serialization to json: */
+ const char *pszJson = toJson(&obj3True);
+ RTTESTI_CHECK_MSG(strcmp(pszJson, "true") == 0, ("pszJson=%s\n", pszJson));
+ pszJson = toJson(&obj3False);
+ RTTESTI_CHECK_MSG(strcmp(pszJson, "false") == 0, ("pszJson=%s\n", pszJson));
+ pszJson = toJson(&obj3Null);
+ RTTESTI_CHECK_MSG(strcmp(pszJson, "null") == 0, ("pszJson=%s\n", pszJson));
+
+ /* Serialization to string. */
+ RTCString str;
+ str = "lead-in:";
+ RTTESTI_CHECK_RC(obj3True.toString(&str, RTCRestObjectBase::kToString_Append), VINF_SUCCESS);
+ RTTESTI_CHECK_MSG(str.equals("lead-in:true"), ("str=%s\n", str.c_str()));
+ RTTESTI_CHECK_RC(obj3True.toString(&str), VINF_SUCCESS);
+ RTTESTI_CHECK_MSG(str.equals("true"), ("str=%s\n", str.c_str()));
+
+ str = "lead-in:";
+ RTTESTI_CHECK_RC(obj3False.toString(&str, RTCRestObjectBase::kToString_Append), VINF_SUCCESS);
+ RTTESTI_CHECK_MSG(str.equals("lead-in:false"), ("str=%s\n", str.c_str()));
+ RTTESTI_CHECK_RC(obj3False.toString(&str), VINF_SUCCESS);
+ RTTESTI_CHECK_MSG(str.equals("false"), ("str=%s\n", str.c_str()));
+
+ str = "lead-in:";
+ RTTESTI_CHECK_RC(obj3Null.toString(&str, RTCRestObjectBase::kToString_Append), VINF_SUCCESS);
+ RTTESTI_CHECK_MSG(str.equals("lead-in:null"), ("str=%s\n", str.c_str()));
+ RTTESTI_CHECK_RC(obj3Null.toString(&str), VINF_SUCCESS);
+ RTTESTI_CHECK_MSG(str.equals("null"), ("str=%s\n", str.c_str()));
+ }
+
+ /* deserialize: */
+ RTERRINFOSTATIC ErrInfo;
+ {
+ RTCRestBool obj4;
+ obj4.setNull();
+ RTTESTI_CHECK_RC(deserializeFromJson(&obj4, "false", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4.m_fValue == false);
+ RTTESTI_CHECK(obj4.isNull() == false);
+
+ obj4.setNull();
+ RTTESTI_CHECK_RC(deserializeFromJson(&obj4, "true", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4.m_fValue == true);
+ RTTESTI_CHECK(obj4.isNull() == false);
+
+ RTTESTI_CHECK_RC(deserializeFromJson(&obj4, "null", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4.m_fValue == false);
+ RTTESTI_CHECK(obj4.isNull() == true);
+
+ /* object goes to default state on failure: */
+ RTTESTI_CHECK_RC(deserializeFromJson(&obj4, "0", &ErrInfo, RT_XSTR(__LINE__)), VERR_REST_WRONG_JSON_TYPE_FOR_BOOL);
+ RTTESTI_CHECK(obj4.m_fValue == false);
+ RTTESTI_CHECK(obj4.isNull() == false);
+ RTTESTI_CHECK(RTErrInfoIsSet(&ErrInfo.Core));
+
+ obj4.assignValue(true);
+ RTTESTI_CHECK_RC(deserializeFromJson(&obj4, "\"false\"", &ErrInfo, RT_XSTR(__LINE__)), VERR_REST_WRONG_JSON_TYPE_FOR_BOOL);
+ RTTESTI_CHECK(obj4.m_fValue == false);
+ RTTESTI_CHECK(obj4.isNull() == false);
+ RTTESTI_CHECK(RTErrInfoIsSet(&ErrInfo.Core));
+
+ obj4.setNull();
+ RTTESTI_CHECK_RC(deserializeFromJson(&obj4, "[ null ]", NULL, RT_XSTR(__LINE__)), VERR_REST_WRONG_JSON_TYPE_FOR_BOOL);
+ RTTESTI_CHECK(obj4.m_fValue == false);
+ RTTESTI_CHECK(obj4.isNull() == false);
+
+ obj4.setNull();
+ RTTESTI_CHECK_RC(fromString(&obj4, "true", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4.m_fValue == true);
+ RTTESTI_CHECK(obj4.isNull() == false);
+
+ RTTESTI_CHECK_RC(fromString(&obj4, "false", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4.m_fValue == false);
+ RTTESTI_CHECK(obj4.isNull() == false);
+
+ obj4.m_fValue = true;
+ RTTESTI_CHECK_RC(fromString(&obj4, "null", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4.m_fValue == false);
+ RTTESTI_CHECK(obj4.isNull() == true);
+
+ obj4.setNull();
+ RTTESTI_CHECK_RC(fromString(&obj4, " TrUe ", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4.m_fValue == true);
+ RTTESTI_CHECK(obj4.isNull() == false);
+
+ RTTESTI_CHECK_RC(fromString(&obj4, "\tfAlSe;", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4.m_fValue == false);
+ RTTESTI_CHECK(obj4.isNull() == false);
+
+ RTTESTI_CHECK_RC(fromString(&obj4, "\r\nfAlSe\n;", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4.m_fValue == false);
+ RTTESTI_CHECK(obj4.isNull() == false);
+
+ RTTESTI_CHECK_RC(fromString(&obj4, "\r\tNuLl\n;", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4.m_fValue == false);
+ RTTESTI_CHECK(obj4.isNull() == true);
+
+ RTTESTI_CHECK_RC(fromString(&obj4, "1", &ErrInfo, RT_XSTR(__LINE__)), VERR_REST_UNABLE_TO_PARSE_STRING_AS_BOOL);
+ RTTESTI_CHECK(RTErrInfoIsSet(&ErrInfo.Core));
+
+ RTTESTI_CHECK_RC(fromString(&obj4, "0", NULL, RT_XSTR(__LINE__)), VERR_REST_UNABLE_TO_PARSE_STRING_AS_BOOL);
+ }
+}
+
+class Int64Constants
+{
+public:
+ Int64Constants() {}
+ const char *getSubName() const { return "RTCRestInt64"; }
+ int64_t getMin() const { return INT64_MIN; }
+ const char *getMinStr() const { return "-9223372036854775808"; }
+ int64_t getMax() const { return INT64_MAX; }
+ const char *getMaxStr() const { return "9223372036854775807"; }
+ const char *getTypeName() const { return "int64_t"; }
+ RTCRestObjectBase::kTypeClass getTypeClass() const { return RTCRestObjectBase::kTypeClass_Int64; }
+};
+
+class Int32Constants
+{
+public:
+ Int32Constants() { }
+ const char *getSubName() const { return "RTCRestInt32"; }
+ int32_t getMin() const { return INT32_MIN; }
+ const char *getMinStr() const { return "-2147483648"; }
+ int32_t getMax() const { return INT32_MAX; }
+ const char *getMaxStr() const { return "2147483647"; }
+ const char *getTypeName() const { return "int32_t"; }
+ RTCRestObjectBase::kTypeClass getTypeClass() const { return RTCRestObjectBase::kTypeClass_Int32; }
+};
+
+class Int16Constants
+{
+public:
+ Int16Constants() { }
+ const char *getSubName() const { return "RTCRestInt16"; }
+ int16_t getMin() const { return INT16_MIN; }
+ const char *getMinStr() const { return "-32768"; }
+ int16_t getMax() const { return INT16_MAX; }
+ const char *getMaxStr() const { return "32767"; }
+ const char *getTypeName() const { return "int16_t"; }
+ RTCRestObjectBase::kTypeClass getTypeClass() const { return RTCRestObjectBase::kTypeClass_Int16; }
+};
+
+template<typename RestType, typename IntType, typename ConstantClass>
+void testInteger(void)
+{
+ ConstantClass const Consts;
+ RTTestSub(g_hTest, Consts.getSubName());
+
+ {
+ RestType obj1;
+ RTTESTI_CHECK(obj1.m_iValue == 0);
+ RTTESTI_CHECK(obj1.isNull() == false);
+ RTTESTI_CHECK(strcmp(obj1.typeName(), Consts.getTypeName()) == 0);
+ RTTESTI_CHECK(obj1.typeClass() == Consts.getTypeClass());
+ }
+
+ {
+ RestType obj2(2398);
+ RTTESTI_CHECK(obj2.m_iValue == 2398);
+ RTTESTI_CHECK(obj2.isNull() == false);
+ }
+
+ {
+ RestType obj2(-7345);
+ RTTESTI_CHECK(obj2.m_iValue == -7345);
+ RTTESTI_CHECK(obj2.isNull() == false);
+ }
+
+ {
+ /* Value assignments: */
+ RestType obj3;
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.isNull() == true);
+ RTTESTI_CHECK(obj3.m_iValue == 0);
+ obj3.assignValue(-1);
+ RTTESTI_CHECK(obj3.m_iValue == -1);
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.isNull() == true);
+ obj3.assignValue(42);
+ RTTESTI_CHECK(obj3.m_iValue == 42);
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ obj3.assignValue(Consts.getMax());
+ RTTESTI_CHECK(obj3.m_iValue == Consts.getMax());
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ obj3.assignValue(Consts.getMin());
+ RTTESTI_CHECK(obj3.m_iValue == Consts.getMin());
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ /* Reset to default: */
+ RTTESTI_CHECK_RC(obj3.resetToDefault(), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.m_iValue == 0);
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ obj3.assignValue(42);
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK_RC(obj3.resetToDefault(), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.m_iValue == 0);
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ /* Copy assignments: */
+ RestType obj3Max(Consts.getMax());
+ RTTESTI_CHECK(obj3Max.m_iValue == Consts.getMax());
+ RTTESTI_CHECK(obj3Max.isNull() == false);
+ RestType obj3Min(Consts.getMin());
+ RTTESTI_CHECK(obj3Min.m_iValue == Consts.getMin());
+ RTTESTI_CHECK(obj3Min.isNull() == false);
+ RestType obj3Null;
+ obj3Null.setNull();
+ RTTESTI_CHECK(obj3Null.m_iValue == 0);
+ RTTESTI_CHECK(obj3Null.isNull() == true);
+
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK_RC(obj3.assignCopy(obj3Max), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.m_iValue == Consts.getMax());
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ RTTESTI_CHECK_RC(obj3.assignCopy(obj3Null), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.m_iValue == 0);
+ RTTESTI_CHECK(obj3.isNull() == true);
+
+ RTTESTI_CHECK_RC(obj3.assignCopy(obj3Min), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.m_iValue == Consts.getMin());
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ obj3 = obj3Null;
+ RTTESTI_CHECK(obj3.m_iValue == 0);
+ RTTESTI_CHECK(obj3.isNull() == true);
+
+ obj3 = obj3Max;
+ RTTESTI_CHECK(obj3.m_iValue == Consts.getMax());
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ obj3 = obj3Null;
+ RTTESTI_CHECK(obj3.m_iValue == 0);
+ RTTESTI_CHECK(obj3.isNull() == true);
+
+ obj3 = obj3Min;
+ RTTESTI_CHECK(obj3.m_iValue == Consts.getMin());
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ /* setNull implies resetToDefault: */
+ obj3 = obj3Max;
+ RTTESTI_CHECK(obj3.m_iValue == Consts.getMax());
+ RTTESTI_CHECK(obj3.isNull() == false);
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.isNull() == true);
+ RTTESTI_CHECK(obj3.m_iValue == 0);
+
+ /* Copy constructors: */
+ {
+ RestType obj3a(obj3Max);
+ RTTESTI_CHECK(obj3a.m_iValue == Consts.getMax());
+ RTTESTI_CHECK(obj3a.isNull() == false);
+ }
+ {
+ RestType obj3b(obj3Min);
+ RTTESTI_CHECK(obj3b.m_iValue == Consts.getMin());
+ RTTESTI_CHECK(obj3b.isNull() == false);
+ }
+ {
+ RestType obj3c(obj3Null);
+ RTTESTI_CHECK(obj3c.m_iValue == 0);
+ RTTESTI_CHECK(obj3c.isNull() == true);
+ }
+
+ /* Serialization to json: */
+ const char *pszJson = toJson(&obj3Max);
+ RTTESTI_CHECK_MSG(strcmp(pszJson, Consts.getMaxStr()) == 0, ("pszJson=%s\n", pszJson));
+ pszJson = toJson(&obj3Min);
+ RTTESTI_CHECK_MSG(strcmp(pszJson, Consts.getMinStr()) == 0, ("pszJson=%s\n", pszJson));
+ pszJson = toJson(&obj3Null);
+ RTTESTI_CHECK_MSG(strcmp(pszJson, "null") == 0, ("pszJson=%s\n", pszJson));
+
+ /* Serialization to string. */
+ RTCString str;
+ RTCString strExpect;
+ str = "lead-in:";
+ RTTESTI_CHECK_RC(obj3Max.toString(&str, RTCRestObjectBase::kToString_Append), VINF_SUCCESS);
+ strExpect.printf("lead-in:%s", Consts.getMaxStr());
+ RTTESTI_CHECK_MSG(str.equals(strExpect), ("str=%s strExpect=%s\n", str.c_str(), strExpect.c_str()));
+ RTTESTI_CHECK_RC(obj3Max.toString(&str), VINF_SUCCESS);
+ RTTESTI_CHECK_MSG(str.equals(Consts.getMaxStr()), ("str=%s\n", str.c_str()));
+
+ str = "lead-in:";
+ RTTESTI_CHECK_RC(obj3Min.toString(&str, RTCRestObjectBase::kToString_Append), VINF_SUCCESS);
+ strExpect.printf("lead-in:%s", Consts.getMinStr());
+ RTTESTI_CHECK_MSG(str.equals(strExpect), ("str=%s strExpect=%s\n", str.c_str(), strExpect.c_str()));
+ RTTESTI_CHECK_RC(obj3Min.toString(&str), VINF_SUCCESS);
+ RTTESTI_CHECK_MSG(str.equals(Consts.getMinStr()), ("str=%s\n", str.c_str()));
+
+ str = "lead-in:";
+ RTTESTI_CHECK_RC(obj3Null.toString(&str, RTCRestObjectBase::kToString_Append), VINF_SUCCESS);
+ RTTESTI_CHECK_MSG(str.equals("lead-in:null"), ("str=%s\n", str.c_str()));
+ RTTESTI_CHECK_RC(obj3Null.toString(&str), VINF_SUCCESS);
+ RTTESTI_CHECK_MSG(str.equals("null"), ("str=%s\n", str.c_str()));
+ }
+
+ /* deserialize: */
+ RTERRINFOSTATIC ErrInfo;
+ {
+ /* from json: */
+ RestType obj4;
+ obj4.setNull();
+ RTTESTI_CHECK_RC(deserializeFromJson(&obj4, "42", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4.m_iValue == 42);
+ RTTESTI_CHECK(obj4.isNull() == false);
+
+ obj4.setNull();
+ RTTESTI_CHECK_RC(deserializeFromJson(&obj4, "-22", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4.m_iValue == -22);
+ RTTESTI_CHECK(obj4.isNull() == false);
+
+ obj4.setNull();
+ RTTESTI_CHECK_RC(deserializeFromJson(&obj4, Consts.getMaxStr(), &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4.m_iValue == Consts.getMax());
+ RTTESTI_CHECK(obj4.isNull() == false);
+
+ obj4.setNull();
+ RTTESTI_CHECK_RC(deserializeFromJson(&obj4, Consts.getMinStr(), &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4.m_iValue == Consts.getMin());
+ RTTESTI_CHECK(obj4.isNull() == false);
+
+ RTTESTI_CHECK_RC(deserializeFromJson(&obj4, "null", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4.m_iValue == 0);
+ RTTESTI_CHECK(obj4.isNull() == true);
+
+ /* object goes to default state on failure: */
+ obj4.assignValue(Consts.getMin());
+ RTTESTI_CHECK_RC(deserializeFromJson(&obj4, "0.0", &ErrInfo, RT_XSTR(__LINE__)), VERR_REST_WRONG_JSON_TYPE_FOR_INTEGER);
+ RTTESTI_CHECK(obj4.m_iValue == 0);
+ RTTESTI_CHECK(obj4.isNull() == false);
+ RTTESTI_CHECK(RTErrInfoIsSet(&ErrInfo.Core));
+
+ obj4.assignValue(Consts.getMax());
+ RTTESTI_CHECK_RC(deserializeFromJson(&obj4, "\"false\"", &ErrInfo, RT_XSTR(__LINE__)), VERR_REST_WRONG_JSON_TYPE_FOR_INTEGER);
+ RTTESTI_CHECK(obj4.m_iValue == 0);
+ RTTESTI_CHECK(obj4.isNull() == false);
+ RTTESTI_CHECK(RTErrInfoIsSet(&ErrInfo.Core));
+
+ obj4.setNull();
+ RTTESTI_CHECK_RC(deserializeFromJson(&obj4, "[ null ]", NULL, RT_XSTR(__LINE__)), VERR_REST_WRONG_JSON_TYPE_FOR_INTEGER);
+ RTTESTI_CHECK(obj4.m_iValue == 0);
+ RTTESTI_CHECK(obj4.isNull() == false);
+
+ /* from string: */
+ obj4.setNull();
+ RTTESTI_CHECK_RC(fromString(&obj4, "22", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4.m_iValue == 22);
+ RTTESTI_CHECK(obj4.isNull() == false);
+
+ RTTESTI_CHECK_RC(fromString(&obj4, "-42", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4.m_iValue == -42);
+ RTTESTI_CHECK(obj4.isNull() == false);
+
+ RTTESTI_CHECK_RC(fromString(&obj4, Consts.getMaxStr(), &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4.m_iValue == Consts.getMax());
+ RTTESTI_CHECK(obj4.isNull() == false);
+
+ RTTESTI_CHECK_RC(fromString(&obj4, Consts.getMinStr(), &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4.m_iValue == Consts.getMin());
+ RTTESTI_CHECK(obj4.isNull() == false);
+
+ obj4.m_iValue = 33;
+ RTTESTI_CHECK_RC(fromString(&obj4, "null", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4.m_iValue == 0);
+ RTTESTI_CHECK(obj4.isNull() == true);
+
+ obj4.m_iValue = 33;
+ RTTESTI_CHECK_RC(fromString(&obj4, " nULl;", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4.m_iValue == 0);
+ RTTESTI_CHECK(obj4.isNull() == true);
+
+ obj4.setNull();
+ RTTESTI_CHECK_RC(fromString(&obj4, " 0x42 ", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4.m_iValue == 0x42);
+ RTTESTI_CHECK(obj4.isNull() == false);
+
+ RTTESTI_CHECK_RC(fromString(&obj4, "\t010\t", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4.m_iValue == 8);
+ RTTESTI_CHECK(obj4.isNull() == false);
+
+ RTTESTI_CHECK_RC(fromString(&obj4, "\r\t0X4FDB\t", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4.m_iValue == 0x4fdb);
+ RTTESTI_CHECK(obj4.isNull() == false);
+
+ RTTESTI_CHECK_RC(fromString(&obj4, "1.1", &ErrInfo, RT_XSTR(__LINE__)), VERR_TRAILING_CHARS);
+ RTTESTI_CHECK(RTErrInfoIsSet(&ErrInfo.Core));
+
+ RTTESTI_CHECK_RC(fromString(&obj4, "false", NULL, RT_XSTR(__LINE__)), VERR_NO_DIGITS);
+ }
+}
+
+
+void testDouble(void)
+{
+ RTTestSub(g_hTest, "RTCRestDouble");
+#define TST_DBL_MAX (1.79769313486231571e+308)
+#define TST_DBL_MIN (2.22507385850720138e-308)
+#define TST_DBL_MAX_STRING1 "1.79769313486231571e+308"
+#define TST_DBL_MAX_STRING2 "1.7976931348623157e+308"
+#define TST_DBL_MAX_EQUAL(a_psz) ( strcmp(a_psz, TST_DBL_MAX_STRING1) == 0 || strcmp(a_psz, TST_DBL_MAX_STRING2) == 0 )
+#define TST_DBL_MIN_STRING1 "2.22507385850720138e-308"
+#define TST_DBL_MIN_STRING2 "2.2250738585072014e-308"
+#define TST_DBL_MIN_EQUAL(a_psz) ( strcmp(a_psz, TST_DBL_MIN_STRING1) == 0 || strcmp(a_psz, TST_DBL_MIN_STRING2) == 0 )
+
+ {
+ RTCRestDouble obj1;
+ RTTESTI_CHECK(obj1.m_rdValue == 0.0);
+ RTTESTI_CHECK(obj1.isNull() == false);
+ RTTESTI_CHECK(strcmp(obj1.typeName(), "double") == 0);
+ RTTESTI_CHECK(obj1.typeClass() == RTCRestObjectBase::kTypeClass_Double);
+ }
+
+ {
+ RTCRestDouble obj2(2398.1);
+ RTTESTI_CHECK(obj2.m_rdValue == 2398.1);
+ RTTESTI_CHECK(obj2.isNull() == false);
+ }
+
+ {
+ RTCRestDouble obj2(-7345.2);
+ RTTESTI_CHECK(obj2.m_rdValue == -7345.2);
+ RTTESTI_CHECK(obj2.isNull() == false);
+ }
+
+ {
+ /* Value assignments: */
+ RTCRestDouble obj3;
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.isNull() == true);
+ RTTESTI_CHECK(obj3.m_rdValue == 0.0);
+ obj3.assignValue(-1.0);
+ RTTESTI_CHECK(obj3.m_rdValue == -1.0);
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.isNull() == true);
+ obj3.assignValue(42.42);
+ RTTESTI_CHECK(obj3.m_rdValue == 42.42);
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ obj3.assignValue(TST_DBL_MAX);
+ RTTESTI_CHECK(obj3.m_rdValue == TST_DBL_MAX);
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ obj3.assignValue(TST_DBL_MIN);
+ RTTESTI_CHECK(obj3.m_rdValue == TST_DBL_MIN);
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ /* Reset to default: */
+ RTTESTI_CHECK_RC(obj3.resetToDefault(), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.m_rdValue == 0.0);
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ obj3.assignValue(42);
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK_RC(obj3.resetToDefault(), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.m_rdValue == 0.0);
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ /* Copy assignments: */
+ RTCRestDouble obj3Max(TST_DBL_MAX);
+ RTTESTI_CHECK(obj3Max.m_rdValue == TST_DBL_MAX);
+ RTTESTI_CHECK(obj3Max.isNull() == false);
+ RTCRestDouble obj3Min(TST_DBL_MIN);
+ RTTESTI_CHECK(obj3Min.m_rdValue == TST_DBL_MIN);
+ RTTESTI_CHECK(obj3Min.isNull() == false);
+ RTCRestDouble obj3Null;
+ obj3Null.setNull();
+ RTTESTI_CHECK(obj3Null.m_rdValue == 0.0);
+ RTTESTI_CHECK(obj3Null.isNull() == true);
+
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK_RC(obj3.assignCopy(obj3Max), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.m_rdValue == TST_DBL_MAX);
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ RTTESTI_CHECK_RC(obj3.assignCopy(obj3Null), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.m_rdValue == 0.0);
+ RTTESTI_CHECK(obj3.isNull() == true);
+
+ RTTESTI_CHECK_RC(obj3.assignCopy(obj3Min), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.m_rdValue == TST_DBL_MIN);
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ obj3 = obj3Null;
+ RTTESTI_CHECK(obj3.m_rdValue == 0.0);
+ RTTESTI_CHECK(obj3.isNull() == true);
+
+ obj3 = obj3Max;
+ RTTESTI_CHECK(obj3.m_rdValue == TST_DBL_MAX);
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ obj3 = obj3Null;
+ RTTESTI_CHECK(obj3.m_rdValue == 0.0);
+ RTTESTI_CHECK(obj3.isNull() == true);
+
+ obj3 = obj3Min;
+ RTTESTI_CHECK(obj3.m_rdValue == TST_DBL_MIN);
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ /* setNull implies resetToDefault: */
+ obj3 = obj3Max;
+ RTTESTI_CHECK(obj3.m_rdValue == TST_DBL_MAX);
+ RTTESTI_CHECK(obj3.isNull() == false);
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.isNull() == true);
+ RTTESTI_CHECK(obj3.m_rdValue == 0.0);
+
+ /* Copy constructors: */
+ {
+ RTCRestDouble obj3a(obj3Max);
+ RTTESTI_CHECK(obj3a.m_rdValue == TST_DBL_MAX);
+ RTTESTI_CHECK(obj3a.isNull() == false);
+ }
+ {
+ RTCRestDouble obj3b(obj3Min);
+ RTTESTI_CHECK(obj3b.m_rdValue == TST_DBL_MIN);
+ RTTESTI_CHECK(obj3b.isNull() == false);
+ }
+ {
+ RTCRestDouble obj3c(obj3Null);
+ RTTESTI_CHECK(obj3c.m_rdValue == 0.0);
+ RTTESTI_CHECK(obj3c.isNull() == true);
+ }
+
+ /* Serialization to json: */
+ const char *pszJson = toJson(&obj3Max);
+ RTTESTI_CHECK_MSG(TST_DBL_MAX_EQUAL(pszJson), ("pszJson=%s\n", pszJson));
+ pszJson = toJson(&obj3Min);
+ RTTESTI_CHECK_MSG(TST_DBL_MIN_EQUAL(pszJson), ("pszJson=%s\n", pszJson));
+ pszJson = toJson(&obj3Null);
+ RTTESTI_CHECK_MSG(strcmp(pszJson, "null") == 0, ("pszJson=%s\n", pszJson));
+
+ /* Serialization to string. */
+ RTCString str;
+ RTCString strExpect1;
+ RTCString strExpect2;
+ str = "lead-in:";
+ RTTESTI_CHECK_RC(obj3Max.toString(&str, RTCRestObjectBase::kToString_Append), VINF_SUCCESS);
+ strExpect1.printf("lead-in:%s", TST_DBL_MAX_STRING1);
+ strExpect2.printf("lead-in:%s", TST_DBL_MAX_STRING2);
+ RTTESTI_CHECK_MSG(str.equals(strExpect1) || str.equals(strExpect2),
+ ("str=%s strExpect1=%s strExpect2=%s\n", str.c_str(), strExpect1.c_str(), strExpect2.c_str()));
+ RTTESTI_CHECK_RC(obj3Max.toString(&str), VINF_SUCCESS);
+ RTTESTI_CHECK_MSG(TST_DBL_MAX_EQUAL(str.c_str()), ("str=%s\n", str.c_str()));
+
+ str = "lead-in:";
+ RTTESTI_CHECK_RC(obj3Min.toString(&str, RTCRestObjectBase::kToString_Append), VINF_SUCCESS);
+ strExpect1.printf("lead-in:%s", TST_DBL_MIN_STRING1);
+ strExpect2.printf("lead-in:%s", TST_DBL_MIN_STRING2);
+ RTTESTI_CHECK_MSG(str.equals(strExpect1) || str.equals(strExpect2),
+ ("str=%s strExpect1=%s strExpect2=%s\n", str.c_str(), strExpect1.c_str(), strExpect2.c_str()));
+ RTTESTI_CHECK_RC(obj3Min.toString(&str), VINF_SUCCESS);
+ RTTESTI_CHECK_MSG(TST_DBL_MIN_EQUAL(str.c_str()), ("str=%s\n", str.c_str()));
+
+ str = "lead-in:";
+ RTTESTI_CHECK_RC(obj3Null.toString(&str, RTCRestObjectBase::kToString_Append), VINF_SUCCESS);
+ RTTESTI_CHECK_MSG(str.equals("lead-in:null"), ("str=%s\n", str.c_str()));
+ RTTESTI_CHECK_RC(obj3Null.toString(&str), VINF_SUCCESS);
+ RTTESTI_CHECK_MSG(str.equals("null"), ("str=%s\n", str.c_str()));
+ }
+
+ /* deserialize: */
+ RTERRINFOSTATIC ErrInfo;
+ {
+ /* Some linux systems and probably all solaris fail to parse the longer MIN string, so just detect and skip. */
+ bool fGroksMinString = true;
+#if defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS)
+ RTJSONVAL hTmpValue = NIL_RTJSONVAL;
+ int rcTmp = RTJsonParseFromString(&hTmpValue, TST_DBL_MIN_STRING1, NULL);
+ RTJsonValueRelease(hTmpValue);
+ if (rcTmp == VERR_INVALID_PARAMETER)
+ fGroksMinString = false;
+#endif
+
+ /* from json: */
+ RTCRestDouble obj4;
+ obj4.setNull();
+ RTTESTI_CHECK_RC(deserializeFromJson(&obj4, "42.42", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4.m_rdValue == 42.42);
+ RTTESTI_CHECK(obj4.isNull() == false);
+
+ obj4.setNull();
+ RTTESTI_CHECK_RC(deserializeFromJson(&obj4, "-22.22", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4.m_rdValue == -22.22);
+ RTTESTI_CHECK(obj4.isNull() == false);
+
+ obj4.setNull();
+ RTTESTI_CHECK_RC(deserializeFromJson(&obj4, TST_DBL_MAX_STRING1, &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4.m_rdValue == TST_DBL_MAX);
+ RTTESTI_CHECK(obj4.isNull() == false);
+
+ if (fGroksMinString)
+ {
+ obj4.setNull();
+ RTTESTI_CHECK_RC(deserializeFromJson(&obj4, TST_DBL_MIN_STRING1, &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4.m_rdValue == TST_DBL_MIN);
+ RTTESTI_CHECK(obj4.isNull() == false);
+ }
+
+ RTTESTI_CHECK_RC(deserializeFromJson(&obj4, "null", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4.m_rdValue == 0.0);
+ RTTESTI_CHECK(obj4.isNull() == true);
+
+ obj4.setNull();
+ RTTESTI_CHECK_RC(deserializeFromJson(&obj4, "14323", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4.m_rdValue == 14323.0);
+ RTTESTI_CHECK(obj4.isNull() == false);
+
+ obj4.setNull();
+ RTTESTI_CHECK_RC(deserializeFromJson(&obj4, "-234875", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4.m_rdValue == -234875.0);
+ RTTESTI_CHECK(obj4.isNull() == false);
+
+ /* object goes to default state on failure: */
+ obj4.assignValue(TST_DBL_MIN);
+ RTTESTI_CHECK_RC(deserializeFromJson(&obj4, "false", &ErrInfo, RT_XSTR(__LINE__)), VERR_REST_WRONG_JSON_TYPE_FOR_DOUBLE);
+ RTTESTI_CHECK(obj4.m_rdValue == 0.0);
+ RTTESTI_CHECK(obj4.isNull() == false);
+ RTTESTI_CHECK(RTErrInfoIsSet(&ErrInfo.Core));
+
+ obj4.assignValue(TST_DBL_MAX);
+ RTTESTI_CHECK_RC(deserializeFromJson(&obj4, "\"false\"", &ErrInfo, RT_XSTR(__LINE__)), VERR_REST_WRONG_JSON_TYPE_FOR_DOUBLE);
+ RTTESTI_CHECK(obj4.m_rdValue == 0.0);
+ RTTESTI_CHECK(obj4.isNull() == false);
+ RTTESTI_CHECK(RTErrInfoIsSet(&ErrInfo.Core));
+
+ obj4.setNull();
+ RTTESTI_CHECK_RC(deserializeFromJson(&obj4, "[ null ]", NULL, RT_XSTR(__LINE__)), VERR_REST_WRONG_JSON_TYPE_FOR_DOUBLE);
+ RTTESTI_CHECK(obj4.m_rdValue == 0.0);
+ RTTESTI_CHECK(obj4.isNull() == false);
+
+ /* from string: */
+ obj4.setNull();
+ RTTESTI_CHECK_RC(fromString(&obj4, "22.42", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4.m_rdValue == 22.42);
+ RTTESTI_CHECK(obj4.isNull() == false);
+
+ RTTESTI_CHECK_RC(fromString(&obj4, "-42.22", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4.m_rdValue == -42.22);
+ RTTESTI_CHECK(obj4.isNull() == false);
+
+ RTTESTI_CHECK_RC(fromString(&obj4, TST_DBL_MAX_STRING1, &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4.m_rdValue == TST_DBL_MAX);
+ RTTESTI_CHECK(obj4.isNull() == false);
+
+ if (fGroksMinString)
+ {
+ RTTESTI_CHECK_RC(fromString(&obj4, TST_DBL_MIN_STRING1, &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4.m_rdValue == TST_DBL_MIN);
+ RTTESTI_CHECK(obj4.isNull() == false);
+ }
+
+ obj4.m_rdValue = 33.33;
+ RTTESTI_CHECK_RC(fromString(&obj4, "null", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4.m_rdValue == 0.0);
+ RTTESTI_CHECK(obj4.isNull() == true);
+
+ obj4.m_rdValue = 33.33;
+ RTTESTI_CHECK_RC(fromString(&obj4, " nULl;", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4.m_rdValue == 0.0);
+ RTTESTI_CHECK(obj4.isNull() == true);
+
+ obj4.setNull();
+ RTTESTI_CHECK_RC(fromString(&obj4, " 42.22 ", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4.m_rdValue == 42.22);
+ RTTESTI_CHECK(obj4.isNull() == false);
+
+ RTTESTI_CHECK_RC(fromString(&obj4, "\t010\t", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4.m_rdValue ==10.0);
+ RTTESTI_CHECK(obj4.isNull() == false);
+
+ RTTESTI_CHECK_RC(fromString(&obj4, "\r\t03495.344\t\r\n", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4.m_rdValue == 3495.344);
+ RTTESTI_CHECK(obj4.isNull() == false);
+
+ RTTESTI_CHECK_RC(fromString(&obj4, "1.1;", &ErrInfo, RT_XSTR(__LINE__)), VERR_TRAILING_CHARS);
+ RTTESTI_CHECK(RTErrInfoIsSet(&ErrInfo.Core));
+
+ RTTESTI_CHECK_RC(fromString(&obj4, "false", NULL, RT_XSTR(__LINE__)), VERR_NO_DIGITS);
+
+#if defined(RT_OS_WINDOWS) || defined(RT_OS_SOLARIS)
+ RTTESTI_CHECK_RC(fromString(&obj4, " 0x42 ", &ErrInfo, RT_XSTR(__LINE__)), VERR_TRAILING_CHARS);
+ RTTESTI_CHECK(obj4.m_rdValue == 0.0);
+#else
+ RTTESTI_CHECK_RC(fromString(&obj4, " 0x42 ", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4.m_rdValue == 66.0);
+#endif
+ RTTESTI_CHECK(obj4.isNull() == false);
+ }
+}
+
+
+void testString(const char *pszDummy, ...)
+{
+ RTTestSub(g_hTest, "RTCRestString");
+
+ {
+ RTCRestString obj1;
+ RTTESTI_CHECK(obj1.isEmpty());
+ RTTESTI_CHECK(obj1.isNull() == false);
+ RTTESTI_CHECK(strcmp(obj1.typeName(), "RTCString") == 0);
+ RTTESTI_CHECK(obj1.typeClass() == RTCRestObjectBase::kTypeClass_String);
+ }
+
+ {
+ RTCRestString obj2(RTCString("2398.1"));
+ RTTESTI_CHECK(obj2 == "2398.1");
+ RTTESTI_CHECK(obj2.isNull() == false);
+ }
+
+ {
+ RTCRestString obj2("-7345.2");
+ RTTESTI_CHECK(obj2 == "-7345.2");
+ RTTESTI_CHECK(obj2.isNull() == false);
+ }
+
+ {
+ /* Value assignments: */
+ RTCRestString obj3;
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.isNull() == true);
+ RTTESTI_CHECK(obj3.isEmpty());
+ obj3 = "-1.0";
+ RTTESTI_CHECK(obj3 == "-1.0");
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.isNull() == true && obj3.isEmpty());
+ obj3 = RTCString("-2.0");
+ RTTESTI_CHECK(obj3 == "-2.0");
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.isNull() == true && obj3.isEmpty());
+ obj3 = RTCRestString("-3.0");
+ RTTESTI_CHECK(obj3 == "-3.0");
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.isNull() == true && obj3.isEmpty());
+ RTTESTI_CHECK_RC(obj3.assignNoThrow(RTCRestString("4.0")), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3 == "4.0");
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.isNull() == true && obj3.isEmpty());
+ RTTESTI_CHECK_RC(obj3.assignNoThrow("-4.0"), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3 == "-4.0");
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.isNull() == true && obj3.isEmpty());
+ RTTESTI_CHECK_RC(obj3.assignNoThrow(RTCRestString("0123456789"), 3, 5), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3 == "34567");
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.isNull() == true && obj3.isEmpty());
+ RTTESTI_CHECK_RC(obj3.assignNoThrow("0123456789", 4), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3 == "0123");
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.isNull() == true && obj3.isEmpty());
+ RTTESTI_CHECK_RC(obj3.assignNoThrow(8, 'x'), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3 == "xxxxxxxx");
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.isNull() == true && obj3.isEmpty());
+ RTTESTI_CHECK_RC(obj3.printfNoThrow("%d%s%d", 42, "asdf", 22), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3 == "42asdf22");
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.isNull() == true && obj3.isEmpty());
+ va_list va;
+ va_start(va, pszDummy);
+ RTTESTI_CHECK_RC(obj3.printfVNoThrow("asdf", va), VINF_SUCCESS);
+ va_end(va);
+ RTTESTI_CHECK(obj3 == "asdf");
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.isNull() == true && obj3.isEmpty());
+ obj3.assign(RTCRestString("4.0"));
+ RTTESTI_CHECK(obj3 == "4.0");
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.isNull() == true && obj3.isEmpty());
+ obj3.assign("-4.0");
+ RTTESTI_CHECK(obj3 == "-4.0");
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.isNull() == true && obj3.isEmpty());
+ obj3.assign(RTCRestString("0123456789"), 3, 5);
+ RTTESTI_CHECK(obj3 == "34567");
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.isNull() == true && obj3.isEmpty());
+ obj3.assign("0123456789", 4);
+ RTTESTI_CHECK(obj3 == "0123");
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.isNull() == true && obj3.isEmpty());
+ obj3.assign(8, 'x');
+ RTTESTI_CHECK(obj3 == "xxxxxxxx");
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.isNull() == true && obj3.isEmpty());
+ obj3.printf("%d%s%d", 42, "asdf", 22);
+ RTTESTI_CHECK(obj3 == "42asdf22");
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.isNull() == true && obj3.isEmpty());
+ va_start(va, pszDummy);
+ obj3.printfV("asdf", va);
+ va_end(va);
+ RTTESTI_CHECK(obj3 == "asdf");
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ /* Reset to default: */
+ RTTESTI_CHECK_RC(obj3.resetToDefault(), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.isEmpty());
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ obj3 = "1";
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK_RC(obj3.resetToDefault(), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.isEmpty());
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ /* Copy assignments: */
+ RTCRestString const obj3Max("max");
+ RTTESTI_CHECK(obj3Max == "max");
+ RTTESTI_CHECK(obj3Max.isNull() == false);
+ RTCRestString obj3Null;
+ obj3Null.setNull();
+ RTTESTI_CHECK(obj3Null.isEmpty());
+ RTTESTI_CHECK(obj3Null.isNull() == true);
+ RTCRestString obj3Empty;
+ RTTESTI_CHECK(obj3Empty.isEmpty());
+ RTTESTI_CHECK(obj3Empty.isNull() == false);
+
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.isNull() == true && obj3.isEmpty());
+ RTTESTI_CHECK_RC(obj3.assignCopy(obj3Max), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3 == "max");
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.isNull() == true && obj3.isEmpty());
+ RTTESTI_CHECK_RC(obj3.assignCopy(obj3Null), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.isEmpty());
+ RTTESTI_CHECK(obj3.isNull() == true);
+
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.isNull() == true && obj3.isEmpty());
+ RTTESTI_CHECK_RC(obj3.assignCopy(obj3Empty), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3 == "");
+ RTTESTI_CHECK(obj3.isEmpty());
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.isNull() == true && obj3.isEmpty());
+ RTTESTI_CHECK_RC(obj3.assignCopy(RTCString("11.0")), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3 == "11.0");
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.isNull() == true && obj3.isEmpty());
+ RTTESTI_CHECK_RC(obj3.assignCopy("12.0"), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3 == "12.0");
+ RTTESTI_CHECK(obj3.isNull() == false);
+
+ /* setNull implies resetToDefault: */
+ obj3 = obj3Max;
+ RTTESTI_CHECK(obj3 == "max");
+ RTTESTI_CHECK(obj3.isNull() == false);
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK(obj3.isNull() == true);
+ RTTESTI_CHECK(obj3.isEmpty());
+
+ /* Copy constructors: */
+ {
+ RTCRestString obj3a(obj3Max);
+ RTTESTI_CHECK(obj3a == "max");
+ RTTESTI_CHECK(obj3a.isNull() == false);
+ }
+ {
+ RTCRestString const obj3c(obj3Null);
+ RTTESTI_CHECK(obj3c.isEmpty());
+ RTTESTI_CHECK(obj3c.isNull() == true);
+ }
+
+ /* Serialization to json: */
+ const char *pszJson = toJson(&obj3Max);
+ RTTESTI_CHECK_MSG(strcmp(pszJson, "\"max\"") == 0, ("pszJson=%s\n", pszJson));
+ pszJson = toJson(&obj3Null);
+ RTTESTI_CHECK_MSG(strcmp(pszJson, "null") == 0, ("pszJson=%s\n", pszJson));
+ pszJson = toJson(&obj3Empty);
+ RTTESTI_CHECK_MSG(strcmp(pszJson, "\"\"") == 0, ("pszJson=%s\n", pszJson));
+
+ /* Serialization to string. */
+ RTCString str;
+ RTCString strExpect;
+ str = "lead-in:";
+ RTTESTI_CHECK_RC(obj3Max.toString(&str, RTCRestObjectBase::kToString_Append), VINF_SUCCESS);
+ RTTESTI_CHECK_MSG(str.equals("lead-in:max"), ("str=%s\n", str.c_str()));
+ RTTESTI_CHECK_RC(obj3Max.toString(&str), VINF_SUCCESS);
+ RTTESTI_CHECK_MSG(str.equals("max"), ("str=%s\n", str.c_str()));
+
+ str = "lead-in:";
+ RTTESTI_CHECK_RC(obj3Empty.toString(&str, RTCRestObjectBase::kToString_Append), VINF_SUCCESS);
+ RTTESTI_CHECK_MSG(str.equals("lead-in:"), ("str=%s\n", str.c_str()));
+ RTTESTI_CHECK_RC(obj3Empty.toString(&str), VINF_SUCCESS);
+ RTTESTI_CHECK_MSG(str.equals(""), ("str=%s\n", str.c_str()));
+
+ str = "lead-in:";
+ RTTESTI_CHECK_RC(obj3Null.toString(&str, RTCRestObjectBase::kToString_Append), VINF_SUCCESS);
+ RTTESTI_CHECK_MSG(str.equals("lead-in:"), ("str=%s\n", str.c_str()));
+ RTTESTI_CHECK_RC(obj3Null.toString(&str), VINF_SUCCESS);
+ RTTESTI_CHECK_MSG(str.equals(""), ("str=%s\n", str.c_str()));
+ }
+
+ /* deserialize: */
+ RTERRINFOSTATIC ErrInfo;
+ {
+ /* from json: */
+ RTCRestString obj4;
+ obj4.setNull();
+ RTTESTI_CHECK_RC(deserializeFromJson(&obj4, "\"42.42\"", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4 == "42.42");
+ RTTESTI_CHECK(obj4.isNull() == false);
+
+ obj4.setNull();
+ RTTESTI_CHECK_RC(deserializeFromJson(&obj4, "\"-22.22\"", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4 == "-22.22");
+ RTTESTI_CHECK(obj4.isNull() == false);
+
+ obj4.setNull();
+ RTTESTI_CHECK_RC(deserializeFromJson(&obj4, "\"maximum\"", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4 == "maximum");
+ RTTESTI_CHECK(obj4.isNull() == false);
+
+ RTTESTI_CHECK_RC(deserializeFromJson(&obj4, "null", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4.isEmpty());
+ RTTESTI_CHECK(obj4.isNull() == true);
+
+ obj4.setNull();
+ RTTESTI_CHECK_RC(deserializeFromJson(&obj4, "\"\\u0020\"", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4 == " ");
+ RTTESTI_CHECK(obj4.isNull() == false);
+
+ obj4.setNull();
+ RTTESTI_CHECK_RC(deserializeFromJson(&obj4, "\"\\u004f\\u004D\\u0047\\u0021 :-)\"",
+ &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4 == "OMG! :-)");
+ RTTESTI_CHECK(obj4.isNull() == false);
+
+ obj4.setNull();
+ RTTESTI_CHECK_RC(deserializeFromJson(&obj4, "\"42:\\uD801\\udC37\\ud852\\uDf62:42\"", /* U+10437 U+24B62 */
+ &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4 == "42:" "\xf0\x90\x90\xb7" "\xf0\xa4\xad\xa2" ":42");
+ RTTESTI_CHECK(obj4.isNull() == false);
+
+ /* object goes to default state on failure: */
+ obj4 = "asdf";
+ RTTESTI_CHECK_RC(deserializeFromJson(&obj4, "false", &ErrInfo, RT_XSTR(__LINE__)), VERR_REST_WRONG_JSON_TYPE_FOR_STRING);
+ RTTESTI_CHECK(obj4.isEmpty());
+ RTTESTI_CHECK(obj4.isNull() == false);
+ RTTESTI_CHECK(RTErrInfoIsSet(&ErrInfo.Core));
+
+ obj4 = "asdf";
+ RTTESTI_CHECK_RC(deserializeFromJson(&obj4, "1", &ErrInfo, RT_XSTR(__LINE__)), VERR_REST_WRONG_JSON_TYPE_FOR_STRING);
+ RTTESTI_CHECK(obj4.isEmpty());
+ RTTESTI_CHECK(obj4.isNull() == false);
+ RTTESTI_CHECK(RTErrInfoIsSet(&ErrInfo.Core));
+
+ obj4.setNull();
+ RTTESTI_CHECK_RC(deserializeFromJson(&obj4, "[ null ]", NULL, RT_XSTR(__LINE__)), VERR_REST_WRONG_JSON_TYPE_FOR_STRING);
+ RTTESTI_CHECK(obj4.isEmpty());
+ RTTESTI_CHECK(obj4.isNull() == false);
+
+ /* from string: */
+ obj4.setNull();
+ RTTESTI_CHECK_RC(fromString(&obj4, "22.42", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4 == "22.42");
+ RTTESTI_CHECK(obj4.isNull() == false);
+
+ RTTESTI_CHECK_RC(fromString(&obj4, "-42.22", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4 == "-42.22");
+ RTTESTI_CHECK(obj4.isNull() == false);
+
+ obj4.setNull();
+ RTTESTI_CHECK_RC(fromString(&obj4, "null", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ RTTESTI_CHECK(obj4 == "null");
+ RTTESTI_CHECK(obj4.isNull() == false);
+ }
+}
+
+
+void testDate()
+{
+ RTTestSub(g_hTest, "RTCRestDate");
+ int64_t const iRecent = INT64_C(1536580687739632500);
+ int64_t const iRecentSec = INT64_C(1536580687000000000);
+ RTTIMESPEC TimeSpec;
+
+#define CHECK_DATE(a_obj, a_fNull, a_fOkay, a_i64Nano, a_sz, a_fUtc) \
+ do { \
+ RTTESTI_CHECK((a_obj).isOkay() == (a_fOkay)); \
+ if ((a_obj).getEpochNano() != (a_i64Nano)) \
+ RTTestIFailed("line " RT_XSTR(__LINE__) ": getEpochNano=%RI64, expected %RI64", (a_obj).getEpochNano(), (int64_t)(a_i64Nano)); \
+ if (!(a_obj).getString().equals(a_sz)) \
+ RTTestIFailed("line " RT_XSTR(__LINE__) ": getString=%s, expected %s", (a_obj).getString().c_str(), a_sz); \
+ RTTESTI_CHECK((a_obj).isUtc() == (a_fUtc)); \
+ RTTESTI_CHECK((a_obj).isNull() == (a_fNull)); \
+ } while (0)
+#define CHECK_DATE_FMT(a_obj, a_fNull, a_fOkay, a_i64Nano, a_sz, a_fUtc, a_enmFormat) \
+ do { \
+ CHECK_DATE(a_obj, a_fNull, a_fOkay, a_i64Nano, a_sz, a_fUtc); \
+ if ((a_obj).getFormat() != (a_enmFormat)) \
+ RTTestIFailed("line " RT_XSTR(__LINE__) ": getFormat=%d, expected %d (%s)", (a_obj).getFormat(), (a_enmFormat), #a_enmFormat); \
+ } while (0)
+
+ {
+ RTCRestDate obj1;
+ CHECK_DATE(obj1, true, false, 0, "", true);
+ RTTESTI_CHECK(strcmp(obj1.typeName(), "RTCRestDate") == 0);
+ RTTESTI_CHECK(obj1.typeClass() == RTCRestObjectBase::kTypeClass_Date);
+ }
+
+ {
+ /* Value assignments: */
+ RTCRestDate obj3;
+ RTTESTI_CHECK_RC(obj3.assignValue(RTTimeSpecSetNano(&TimeSpec, 0), RTCRestDate::kFormat_Rfc3339), VINF_SUCCESS);
+ CHECK_DATE(obj3, false, true, 0, "1970-01-01T00:00:00Z", true);
+
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ CHECK_DATE(obj3, true, false, 0, "", true);
+ RTTESTI_CHECK_RC(obj3.assignValueRfc3339(RTTimeSpecSetNano(&TimeSpec, 0)), VINF_SUCCESS);
+ CHECK_DATE(obj3, false, true, 0, "1970-01-01T00:00:00Z", true);
+
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ CHECK_DATE(obj3, true, false, 0, "", true);
+ RTTESTI_CHECK_RC(obj3.assignValueRfc2822(RTTimeSpecSetNano(&TimeSpec, 0)), VINF_SUCCESS);
+ CHECK_DATE(obj3, false, true, 0, "Thu, 1 Jan 1970 00:00:00 -0000", true);
+
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK_RC(obj3.assignValueRfc7131(RTTimeSpecSetNano(&TimeSpec, 0)), VINF_SUCCESS);
+ CHECK_DATE(obj3, false, true, 0, "Thu, 1 Jan 1970 00:00:00 GMT", true);
+
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK_RC(obj3.assignValue(RTTimeSpecSetNano(&TimeSpec, 0), RTCRestDate::kFormat_Rfc2822), VINF_SUCCESS);
+ CHECK_DATE(obj3, false, true, 0, "Thu, 1 Jan 1970 00:00:00 -0000", true);
+
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK_RC(obj3.assignValue(RTTimeSpecSetNano(&TimeSpec, 0), RTCRestDate::kFormat_Rfc7131), VINF_SUCCESS);
+ CHECK_DATE(obj3, false, true, 0, "Thu, 1 Jan 1970 00:00:00 GMT", true);
+
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK_RC(obj3.assignValue(RTTimeSpecSetNano(&TimeSpec, 0), RTCRestDate::kFormat_Rfc3339_Fraction_9), VINF_SUCCESS);
+ CHECK_DATE(obj3, false, true, 0, "1970-01-01T00:00:00.000000000Z", true);
+
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK_RC(obj3.assignValue(RTTimeSpecSetNano(&TimeSpec, 0), RTCRestDate::kFormat_Rfc3339_Fraction_6), VINF_SUCCESS);
+ CHECK_DATE(obj3, false, true, 0, "1970-01-01T00:00:00.000000Z", true);
+
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK_RC(obj3.assignValue(RTTimeSpecSetNano(&TimeSpec, 0), RTCRestDate::kFormat_Rfc3339_Fraction_3), VINF_SUCCESS);
+ CHECK_DATE(obj3, false, true, 0, "1970-01-01T00:00:00.000Z", true);
+
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK_RC(obj3.assignValue(RTTimeSpecSetNano(&TimeSpec, 0), RTCRestDate::kFormat_Rfc3339_Fraction_2), VINF_SUCCESS);
+ CHECK_DATE(obj3, false, true, 0, "1970-01-01T00:00:00.00Z", true);
+
+ /* Format changes: */
+ RTTESTI_CHECK_RC(obj3.assignValue(RTTimeSpecSetNano(&TimeSpec, 59123456789), RTCRestDate::kFormat_Rfc3339_Fraction_9), VINF_SUCCESS);
+ CHECK_DATE(obj3, false, true, 59123456789, "1970-01-01T00:00:59.123456789Z", true);
+ RTTESTI_CHECK_RC(obj3.setFormat(RTCRestDate::kFormat_Rfc2822), VINF_SUCCESS);
+ CHECK_DATE(obj3, false, true, 59123456789, "Thu, 1 Jan 1970 00:00:59 -0000", true);
+ RTTESTI_CHECK_RC(obj3.setFormat(RTCRestDate::kFormat_Rfc7131), VINF_SUCCESS);
+ CHECK_DATE(obj3, false, true, 59123456789, "Thu, 1 Jan 1970 00:00:59 GMT", true);
+ RTTESTI_CHECK_RC(obj3.setFormat(RTCRestDate::kFormat_Rfc3339), VINF_SUCCESS);
+ CHECK_DATE(obj3, false, true, 59123456789, "1970-01-01T00:00:59Z", true);
+ RTTESTI_CHECK_RC(obj3.setFormat(RTCRestDate::kFormat_Rfc3339_Fraction_2), VINF_SUCCESS);
+ CHECK_DATE(obj3, false, true, 59123456789, "1970-01-01T00:00:59.12Z", true);
+ RTTESTI_CHECK_RC(obj3.setFormat(RTCRestDate::kFormat_Rfc3339_Fraction_3), VINF_SUCCESS);
+ CHECK_DATE(obj3, false, true, 59123456789, "1970-01-01T00:00:59.123Z", true);
+ RTTESTI_CHECK_RC(obj3.setFormat(RTCRestDate::kFormat_Rfc3339_Fraction_6), VINF_SUCCESS);
+ CHECK_DATE(obj3, false, true, 59123456789, "1970-01-01T00:00:59.123456Z", true);
+ RTTESTI_CHECK_RC(obj3.setFormat(RTCRestDate::kFormat_Rfc3339_Fraction_9), VINF_SUCCESS);
+ CHECK_DATE(obj3, false, true, 59123456789, "1970-01-01T00:00:59.123456789Z", true);
+
+ /* Reset to default and setNull works identically: */
+ RTTESTI_CHECK_RC(obj3.resetToDefault(), VINF_SUCCESS);
+ CHECK_DATE(obj3, true, false, 0, "", true);
+
+ RTTESTI_CHECK_RC(obj3.assignValue(RTTimeSpecSetNano(&TimeSpec, 0), RTCRestDate::kFormat_Rfc3339_Fraction_2), VINF_SUCCESS);
+ CHECK_DATE(obj3, false, true, 0, "1970-01-01T00:00:00.00Z", true);
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ CHECK_DATE(obj3, true, false, 0, "", true);
+
+ /* Copy assignments: */
+ RTCRestDate obj3Epoch_3339_9;
+ RTTESTI_CHECK_RC(obj3Epoch_3339_9.assignValue(RTTimeSpecSetNano(&TimeSpec, 0), RTCRestDate::kFormat_Rfc3339_Fraction_9), VINF_SUCCESS);
+ CHECK_DATE(obj3Epoch_3339_9, false, true, 0, "1970-01-01T00:00:00.000000000Z", true);
+
+ RTCRestDate obj3Epoch_7131;
+ RTTESTI_CHECK_RC(obj3Epoch_7131.assignValue(RTTimeSpecSetNano(&TimeSpec, 0), RTCRestDate::kFormat_Rfc7131), VINF_SUCCESS);
+ CHECK_DATE(obj3Epoch_7131, false, true, 0, "Thu, 1 Jan 1970 00:00:00 GMT", true);
+
+ RTCRestDate obj3Recent_3339;
+ RTTESTI_CHECK_RC(obj3Recent_3339.assignValue(RTTimeSpecSetNano(&TimeSpec, iRecent), RTCRestDate::kFormat_Rfc3339), VINF_SUCCESS);
+ CHECK_DATE(obj3Recent_3339, false, true, iRecent, "2018-09-10T11:58:07Z", true);
+
+ RTCRestDate obj3Recent_2822;
+ RTTESTI_CHECK_RC(obj3Recent_2822.assignValue(RTTimeSpecSetNano(&TimeSpec, iRecent), RTCRestDate::kFormat_Rfc2822), VINF_SUCCESS);
+ CHECK_DATE(obj3Recent_2822, false, true, iRecent, "Mon, 10 Sep 2018 11:58:07 -0000", true);
+
+ RTCRestDate const obj3Null;
+ CHECK_DATE(obj3Null, true, false, 0, "", true);
+
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK_RC(obj3.assignCopy(obj3Epoch_3339_9), VINF_SUCCESS);
+ CHECK_DATE(obj3, false, true, 0, "1970-01-01T00:00:00.000000000Z", true);
+
+ RTTESTI_CHECK_RC(obj3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK_RC(obj3.assignCopy(obj3Epoch_7131), VINF_SUCCESS);
+ CHECK_DATE(obj3, false, true, 0, "Thu, 1 Jan 1970 00:00:00 GMT", true);
+
+ RTTESTI_CHECK_RC(obj3.assignCopy(obj3Recent_3339), VINF_SUCCESS);
+ CHECK_DATE(obj3Recent_2822, false, true, iRecent, "Mon, 10 Sep 2018 11:58:07 -0000", true);
+
+ RTTESTI_CHECK_RC(obj3.assignCopy(obj3Null), VINF_SUCCESS);
+ CHECK_DATE(obj3, true, false, 0, "", true);
+
+ obj3 = obj3Recent_2822;
+ CHECK_DATE(obj3Recent_2822, false, true, iRecent, "Mon, 10 Sep 2018 11:58:07 -0000", true);
+
+ obj3 = obj3Epoch_3339_9;
+ CHECK_DATE(obj3, false, true, 0, "1970-01-01T00:00:00.000000000Z", true);
+
+ obj3 = obj3Null;
+ CHECK_DATE(obj3, true, false, 0, "", true);
+
+ /* Copy constructors: */
+ {
+ RTCRestDate obj3a(obj3Epoch_3339_9);
+ CHECK_DATE(obj3a, false, true, 0, "1970-01-01T00:00:00.000000000Z", true);
+ }
+ {
+ RTCRestDate obj3b(obj3Epoch_7131);
+ CHECK_DATE(obj3b, false, true, 0, "Thu, 1 Jan 1970 00:00:00 GMT", true);
+ }
+ {
+ RTCRestDate obj3c(obj3Recent_3339);
+ CHECK_DATE(obj3Recent_3339, false, true, iRecent, "2018-09-10T11:58:07Z", true);
+ }
+ {
+ RTCRestDate obj3d(obj3Recent_2822);
+ CHECK_DATE(obj3d, false, true, iRecent, "Mon, 10 Sep 2018 11:58:07 -0000", true);
+ }
+ {
+ RTCRestDate obj3e(obj3Null);
+ CHECK_DATE(obj3e, true, false, 0, "", true);
+ }
+
+ /* Serialization to json: */
+ const char *pszJson = toJson(&obj3Epoch_3339_9);
+ RTTESTI_CHECK_MSG(strcmp(pszJson, "\"1970-01-01T00:00:00.000000000Z\"") == 0, ("pszJson=%s\n", pszJson));
+ pszJson = toJson(&obj3Epoch_7131);
+ RTTESTI_CHECK_MSG(strcmp(pszJson, "\"Thu, 1 Jan 1970 00:00:00 GMT\"") == 0, ("pszJson=%s\n", pszJson));
+ pszJson = toJson(&obj3Recent_3339);
+ RTTESTI_CHECK_MSG(strcmp(pszJson, "\"2018-09-10T11:58:07Z\"") == 0, ("pszJson=%s\n", pszJson));
+ pszJson = toJson(&obj3Recent_2822);
+ RTTESTI_CHECK_MSG(strcmp(pszJson, "\"Mon, 10 Sep 2018 11:58:07 -0000\"") == 0, ("pszJson=%s\n", pszJson));
+ pszJson = toJson(&obj3Null);
+ RTTESTI_CHECK_MSG(strcmp(pszJson, "null") == 0, ("pszJson=%s\n", pszJson));
+
+ /* Serialization to string. */
+ RTCString str;
+ str = "lead-in:";
+ RTTESTI_CHECK_RC(obj3Epoch_7131.toString(&str, RTCRestObjectBase::kToString_Append), VINF_SUCCESS);
+ RTTESTI_CHECK_MSG(str.equals("lead-in:Thu, 1 Jan 1970 00:00:00 GMT"), ("str=%s\n", str.c_str()));
+ RTTESTI_CHECK_RC(obj3Epoch_7131.toString(&str), VINF_SUCCESS);
+ RTTESTI_CHECK_MSG(str.equals("Thu, 1 Jan 1970 00:00:00 GMT"), ("str=%s\n", str.c_str()));
+
+ str = "lead-in:";
+ RTTESTI_CHECK_RC(obj3Recent_3339.toString(&str, RTCRestObjectBase::kToString_Append), VINF_SUCCESS);
+ RTTESTI_CHECK_MSG(str.equals("lead-in:2018-09-10T11:58:07Z"), ("str=%s\n", str.c_str()));
+ RTTESTI_CHECK_RC(obj3Recent_3339.toString(&str), VINF_SUCCESS);
+ RTTESTI_CHECK_MSG(str.equals("2018-09-10T11:58:07Z"), ("str=%s\n", str.c_str()));
+
+ str = "lead-in:";
+ RTTESTI_CHECK_RC(obj3Null.toString(&str, RTCRestObjectBase::kToString_Append), VINF_SUCCESS);
+ RTTESTI_CHECK_MSG(str.equals("lead-in:null"), ("str=%s\n", str.c_str()));
+ RTTESTI_CHECK_RC(obj3Null.toString(&str), VINF_SUCCESS);
+ RTTESTI_CHECK_MSG(str.equals("null"), ("str=%s\n", str.c_str()));
+ }
+
+ /* deserialize: */
+ RTERRINFOSTATIC ErrInfo;
+ {
+ RTCRestDate obj4;
+ RTTESTI_CHECK_RC(deserializeFromJson(&obj4, "\"Thu, 1 Jan 1970 00:00:00 GMT\"", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ CHECK_DATE_FMT(obj4, false, true, 0, "Thu, 1 Jan 1970 00:00:00 GMT", true, RTCRestDate::kFormat_Rfc7131);
+
+ obj4.setNull();
+ RTTESTI_CHECK_RC(deserializeFromJson(&obj4, "\"Thu, 1 Jan 1970 00:00:00.0000 GMT\"", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ CHECK_DATE_FMT(obj4, false, true, 0, "Thu, 1 Jan 1970 00:00:00.0000 GMT", true, RTCRestDate::kFormat_Rfc7131);
+
+ RTTESTI_CHECK_RC(deserializeFromJson(&obj4, "\"1 Jan 1970 00:00:00 GMT\"", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ CHECK_DATE_FMT(obj4, false, true, 0, "1 Jan 1970 00:00:00 GMT", true, RTCRestDate::kFormat_Rfc7131);
+
+ RTTESTI_CHECK_RC(deserializeFromJson(&obj4, "\"1 Jan 1970 00:00:00\"", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ CHECK_DATE_FMT(obj4, false, true, 0, "1 Jan 1970 00:00:00", false, RTCRestDate::kFormat_Rfc2822);
+
+ RTTESTI_CHECK_RC(deserializeFromJson(&obj4, "\"1 Jan 070 00:00:00\"", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ CHECK_DATE_FMT(obj4, false, true, 0, "1 Jan 070 00:00:00", false, RTCRestDate::kFormat_Rfc2822);
+
+ RTTESTI_CHECK_RC(deserializeFromJson(&obj4, "\"2018-09-10T11:58:07Z\"", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ CHECK_DATE_FMT(obj4, false, true, iRecentSec , "2018-09-10T11:58:07Z", true, RTCRestDate::kFormat_Rfc3339);
+
+ RTTESTI_CHECK_RC(deserializeFromJson(&obj4, "\"1 Jan 70 00:00:00\"", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ CHECK_DATE_FMT(obj4, false, true, 0, "1 Jan 70 00:00:00", false, RTCRestDate::kFormat_Rfc2822);
+
+ RTTESTI_CHECK_RC(deserializeFromJson(&obj4, "\"2018-09-10T11:58:07.739632500Z\"", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ CHECK_DATE_FMT(obj4, false, true, iRecent, "2018-09-10T11:58:07.739632500Z", true, RTCRestDate::kFormat_Rfc3339_Fraction_9);
+
+ RTTESTI_CHECK_RC(deserializeFromJson(&obj4, "null", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ CHECK_DATE_FMT(obj4, true, false, 0, "", true, RTCRestDate::kFormat_Rfc3339_Fraction_9);
+
+ /* object goes to default state if not string and to non-okay if string: */
+ RTTESTI_CHECK_RC(obj4.assignValue(RTTimeSpecSetNano(&TimeSpec, iRecent), RTCRestDate::kFormat_Rfc2822), VINF_SUCCESS);
+ RTTESTI_CHECK_RC(deserializeFromJson(&obj4, "true", &ErrInfo, RT_XSTR(__LINE__)), VERR_REST_WRONG_JSON_TYPE_FOR_DATE);
+ CHECK_DATE_FMT(obj4, true, false, 0, "", true, RTCRestDate::kFormat_Rfc2822);
+
+ RTTESTI_CHECK_RC(obj4.assignValue(RTTimeSpecSetNano(&TimeSpec, iRecent), RTCRestDate::kFormat_Rfc2822), VINF_SUCCESS);
+ RTTESTI_CHECK_RC(deserializeFromJson(&obj4, "\"string\"", &ErrInfo, RT_XSTR(__LINE__)), VWRN_REST_UNABLE_TO_DECODE_DATE);
+ CHECK_DATE_FMT(obj4, false, false, 0, "string", false, RTCRestDate::kFormat_Rfc2822);
+
+ RTTESTI_CHECK_RC(obj4.assignValue(RTTimeSpecSetNano(&TimeSpec, iRecent), RTCRestDate::kFormat_Rfc2822), VINF_SUCCESS);
+ RTTESTI_CHECK_RC(deserializeFromJson(&obj4, "\"0x199 string\"", &ErrInfo, RT_XSTR(__LINE__)), VWRN_REST_UNABLE_TO_DECODE_DATE);
+ CHECK_DATE_FMT(obj4, false, false, 0, "0x199 string", false, RTCRestDate::kFormat_Rfc2822);
+
+ RTTESTI_CHECK_RC(obj4.assignValue(RTTimeSpecSetNano(&TimeSpec, iRecent), RTCRestDate::kFormat_Rfc2822), VINF_SUCCESS);
+ RTTESTI_CHECK_RC(deserializeFromJson(&obj4, "[ null ]", &ErrInfo, RT_XSTR(__LINE__)), VERR_REST_WRONG_JSON_TYPE_FOR_DATE);
+ CHECK_DATE_FMT(obj4, true, false, 0, "", true, RTCRestDate::kFormat_Rfc2822);
+
+ RTTESTI_CHECK_RC(obj4.assignValue(RTTimeSpecSetNano(&TimeSpec, iRecent), RTCRestDate::kFormat_Rfc2822), VINF_SUCCESS);
+ RTTESTI_CHECK_RC(deserializeFromJson(&obj4, "{ \"foo\": 1 }", &ErrInfo, RT_XSTR(__LINE__)), VERR_REST_WRONG_JSON_TYPE_FOR_DATE);
+ CHECK_DATE_FMT(obj4, true, false, 0, "", true, RTCRestDate::kFormat_Rfc2822);
+
+ /* From string: */
+ obj4.setNull();
+ RTTESTI_CHECK_RC(fromString(&obj4, "Thu, 1 Jan 1970 00:00:00 GMT", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ CHECK_DATE_FMT(obj4, false, true, 0, "Thu, 1 Jan 1970 00:00:00 GMT", true, RTCRestDate::kFormat_Rfc7131);
+
+ RTTESTI_CHECK_RC(fromString(&obj4, "Mon, 10 Sep 2018 11:58:07 -0000", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ CHECK_DATE_FMT(obj4, false, true, iRecentSec, "Mon, 10 Sep 2018 11:58:07 -0000", true, RTCRestDate::kFormat_Rfc2822);
+
+ RTTESTI_CHECK_RC(fromString(&obj4, "\t\n\rnull;\r\n\t", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ CHECK_DATE_FMT(obj4, true, false, 0, "", true, RTCRestDate::kFormat_Rfc2822);
+
+ RTTESTI_CHECK_RC(fromString(&obj4, "Mon, 10 Sep 2018 11:58:07 +0000", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ CHECK_DATE_FMT(obj4, false, true, iRecentSec, "Mon, 10 Sep 2018 11:58:07 +0000", false, RTCRestDate::kFormat_Rfc2822);
+
+ RTTESTI_CHECK_RC(fromString(&obj4, "1970-01-01T00:00:00.000000000Z", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ CHECK_DATE_FMT(obj4, false, true, 0, "1970-01-01T00:00:00.000000000Z", true, RTCRestDate::kFormat_Rfc3339_Fraction_9);
+
+ RTTESTI_CHECK_RC(fromString(&obj4, "10 Sep 2018 11:58:07 -0000", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ CHECK_DATE_FMT(obj4, false, true, iRecentSec, "10 Sep 2018 11:58:07 -0000", true, RTCRestDate::kFormat_Rfc2822);
+
+ RTTESTI_CHECK_RC(fromString(&obj4, "null", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ CHECK_DATE_FMT(obj4, true, false, 0, "", true, RTCRestDate::kFormat_Rfc2822);
+
+ RTTESTI_CHECK_RC(fromString(&obj4, "Mon, 10 Sep 18 11:58:07 -0000", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ CHECK_DATE_FMT(obj4, false, true, iRecentSec, "Mon, 10 Sep 18 11:58:07 -0000", true, RTCRestDate::kFormat_Rfc2822);
+
+ RTTESTI_CHECK_RC(fromString(&obj4, "fa;se", &ErrInfo, RT_XSTR(__LINE__)), VERR_REST_UNABLE_TO_DECODE_DATE);
+ CHECK_DATE_FMT(obj4, false, false, 0, "fa;se", false, RTCRestDate::kFormat_Rfc2822);
+
+ RTTESTI_CHECK_RC(fromString(&obj4, "10 Sep 18 11:58:07", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ CHECK_DATE_FMT(obj4, false, true, iRecentSec, "10 Sep 18 11:58:07", false, RTCRestDate::kFormat_Rfc2822);
+
+ obj4.setNull();
+ RTTESTI_CHECK_RC(fromString(&obj4, "10 Sep 118 11:58:07", &ErrInfo, RT_XSTR(__LINE__)), VINF_SUCCESS);
+ CHECK_DATE_FMT(obj4, false, true, iRecentSec, "10 Sep 118 11:58:07", false, RTCRestDate::kFormat_Rfc2822);
+ }
+}
+
+
+/** Wraps RTCRestInt16 to check for leaks. */
+class MyRestInt16 : public RTCRestInt16
+{
+public:
+ static size_t s_cInstances;
+ MyRestInt16() : RTCRestInt16() { s_cInstances++; /*printf("%p: default %02u; cInstances %zu\n", this, m_iValue, s_cInstances);*/ }
+ MyRestInt16(MyRestInt16 const &a_rThat) : RTCRestInt16(a_rThat) { s_cInstances++; /*printf("%p: copy %02u; cInstances %zu\n", this, m_iValue, s_cInstances);*/ }
+ MyRestInt16(int16_t a_iValue) : RTCRestInt16(a_iValue) { s_cInstances++; /*printf("%p: value %02u; cInstances %zu\n", this, m_iValue, s_cInstances);*/ }
+ ~MyRestInt16() { s_cInstances--; /*printf("%p: delete %02u; cInstances %zu\n", this, m_iValue, s_cInstances);*/ }
+ virtual RTCRestObjectBase *baseClone() const RT_NOEXCEPT RT_OVERRIDE { /*printf("clone\n");*/ return new MyRestInt16(*this); }
+};
+
+size_t MyRestInt16::s_cInstances = 0;
+
+
+static void verifyArray(RTCRestArray<MyRestInt16> const &rArray, int iLine, unsigned cElements, ...)
+{
+ if (rArray.size() != cElements)
+ RTTestIFailed("line %u: size() -> %zu, expected %u", iLine, rArray.size(), cElements);
+ va_list va;
+ va_start(va, cElements);
+ for (unsigned i = 0; i < cElements; i++)
+ {
+ int iExpected = va_arg(va, int);
+ if (rArray.at(i)->m_iValue != iExpected)
+ RTTestIFailed("line %u: element #%u: %d, expected %d", iLine, i, rArray.at(i)->m_iValue, iExpected);
+ }
+ va_end(va);
+}
+
+
+static void testArray()
+{
+ RTTestSub(g_hTest, "RTCRestArray");
+
+ {
+ RTCRestArray<RTCRestBool> obj1;
+ RTTESTI_CHECK(obj1.size() == 0);
+ RTTESTI_CHECK(obj1.isEmpty() == true);
+ RTTESTI_CHECK(obj1.isNull() == false);
+ RTTESTI_CHECK(strcmp(obj1.typeName(), "RTCRestArray<ElementType>") == 0);
+ RTTESTI_CHECK(obj1.typeClass() == RTCRestObjectBase::kTypeClass_Array);
+ }
+
+ /* Some random order insertion and manipulations: */
+ {
+ RTCRestArray<MyRestInt16> Arr2;
+ RTCRestArray<MyRestInt16> const *pConstArr2 = &Arr2;
+
+ RTTESTI_CHECK_RC(Arr2.insert(0, new MyRestInt16(3)), VINF_SUCCESS);
+ verifyArray(Arr2, __LINE__, 1, 3);
+ RTTESTI_CHECK_RC(Arr2.append( new MyRestInt16(7)), VINF_SUCCESS);
+ verifyArray(Arr2, __LINE__, 2, 3, 7);
+ RTTESTI_CHECK_RC(Arr2.insert(1, new MyRestInt16(5)), VINF_SUCCESS);
+ verifyArray(Arr2, __LINE__, 3, 3, 5, 7);
+ RTTESTI_CHECK_RC(Arr2.insert(2, new MyRestInt16(6)), VINF_SUCCESS);
+ verifyArray(Arr2, __LINE__, 4, 3, 5, 6, 7);
+ RTTESTI_CHECK_RC(Arr2.prepend( new MyRestInt16(0)), VINF_SUCCESS);
+ verifyArray(Arr2, __LINE__, 5, 0, 3, 5, 6, 7);
+ RTTESTI_CHECK_RC(Arr2.append( new MyRestInt16(9)), VINF_SUCCESS);
+ verifyArray(Arr2, __LINE__, 6, 0, 3, 5, 6, 7, 9);
+ RTTESTI_CHECK_RC(Arr2.insert(5, new MyRestInt16(8)), VINF_SUCCESS);
+ verifyArray(Arr2, __LINE__, 7, 0, 3, 5, 6, 7, 8, 9);
+ RTTESTI_CHECK_RC(Arr2.insert(1, new MyRestInt16(1)), VINF_SUCCESS);
+ verifyArray(Arr2, __LINE__, 8, 0, 1, 3, 5, 6, 7, 8, 9);
+ RTTESTI_CHECK_RC(Arr2.insert(3, new MyRestInt16(4)), VINF_SUCCESS);
+ verifyArray(Arr2, __LINE__, 9, 0, 1, 3, 4, 5, 6, 7, 8, 9);
+ RTTESTI_CHECK_RC(Arr2.insert(2, new MyRestInt16(2)), VINF_SUCCESS);
+ verifyArray(Arr2, __LINE__, 10, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+ RTTESTI_CHECK_MSG(MyRestInt16::s_cInstances == Arr2.size(), ("%zu vs %zu\n", MyRestInt16::s_cInstances, Arr2.size()));
+
+ RTTESTI_CHECK(Arr2.size() == 10);
+
+ for (size_t i = 0; i < Arr2.size(); i++)
+ {
+ MyRestInt16 *pCur = Arr2.at(i);
+ RTTESTI_CHECK(pCur->m_iValue == (int16_t)i);
+
+ MyRestInt16 const *pCur2 = pConstArr2->at(i);
+ RTTESTI_CHECK(pCur2->m_iValue == (int16_t)i);
+ }
+
+ RTTESTI_CHECK_RC(Arr2.replace(2, new MyRestInt16(22)), VWRN_ALREADY_EXISTS);
+ verifyArray(Arr2, __LINE__, 10, 0, 1, 22, 3, 4, 5, 6, 7, 8, 9);
+
+ RTTESTI_CHECK_RC(Arr2.replace(7, new MyRestInt16(77)), VWRN_ALREADY_EXISTS);
+ verifyArray(Arr2, __LINE__, 10, 0, 1, 22, 3, 4, 5, 6, 77, 8, 9);
+
+ RTTESTI_CHECK_RC(Arr2.replace(10, new MyRestInt16(10)), VINF_SUCCESS);
+ verifyArray(Arr2, __LINE__, 11, 0, 1, 22, 3, 4, 5, 6, 77, 8, 9, 10);
+
+ RTTESTI_CHECK_RC(Arr2.replaceCopy(2, MyRestInt16(2)), VWRN_ALREADY_EXISTS);
+ verifyArray(Arr2, __LINE__, 11, 0, 1, 2, 3, 4, 5, 6, 77, 8, 9, 10);
+ RTTESTI_CHECK_MSG(MyRestInt16::s_cInstances == Arr2.size(), ("%zu vs %zu\n", MyRestInt16::s_cInstances, Arr2.size()));
+
+ /* copy constructor: */
+ {
+ RTCRestArray<MyRestInt16> const Arr2Copy(Arr2);
+ verifyArray(Arr2Copy, __LINE__, 11, 0, 1, 2, 3, 4, 5, 6, 77, 8, 9, 10);
+ }
+ verifyArray(Arr2, __LINE__, 11, 0, 1, 2, 3, 4, 5, 6, 77, 8, 9, 10);
+ RTTESTI_CHECK_MSG(MyRestInt16::s_cInstances == Arr2.size(), ("%zu vs %zu\n", MyRestInt16::s_cInstances, Arr2.size()));
+
+ {
+ RTCRestArray<MyRestInt16> Arr2Copy2(Arr2);
+ verifyArray(Arr2Copy2, __LINE__, 11, 0, 1, 2, 3, 4, 5, 6, 77, 8, 9, 10);
+ RTTESTI_CHECK_RC(Arr2Copy2.removeAt(7), VINF_SUCCESS);
+ verifyArray(Arr2Copy2, __LINE__, 10, 0, 1, 2, 3, 4, 5, 6, 8, 9, 10);
+ }
+ verifyArray(Arr2, __LINE__, 11, 0, 1, 2, 3, 4, 5, 6, 77, 8, 9, 10);
+ RTTESTI_CHECK_MSG(MyRestInt16::s_cInstances == Arr2.size(), ("%zu vs %zu\n", MyRestInt16::s_cInstances, Arr2.size()));
+
+ /* copy method + clear: */
+ {
+ RTCRestArray<MyRestInt16> Arr2Copy3;
+ RTTESTI_CHECK_RC(Arr2Copy3.assignCopy(Arr2), VINF_SUCCESS);
+ verifyArray(Arr2Copy3, __LINE__, 11, 0, 1, 2, 3, 4, 5, 6, 77, 8, 9, 10);
+ Arr2Copy3.at(3)->m_iValue = 33;
+ verifyArray(Arr2Copy3, __LINE__, 11, 0, 1, 2, 33, 4, 5, 6, 77, 8, 9, 10);
+ Arr2Copy3.clear();
+ verifyArray(Arr2Copy3, __LINE__, 0);
+ RTTESTI_CHECK_MSG(MyRestInt16::s_cInstances == Arr2.size(), ("%zu vs %zu\n", MyRestInt16::s_cInstances, Arr2.size()));
+ }
+ verifyArray(Arr2, __LINE__, 11, 0, 1, 2, 3, 4, 5, 6, 77, 8, 9, 10);
+ RTTESTI_CHECK_MSG(MyRestInt16::s_cInstances == Arr2.size(), ("%zu vs %zu\n", MyRestInt16::s_cInstances, Arr2.size()));
+
+ /* Check setNull and resetToDefaults with copies: */
+ {
+ RTCRestArray<MyRestInt16> Arr2Copy4(Arr2);
+ verifyArray(Arr2Copy4, __LINE__, 11, 0, 1, 2, 3, 4, 5, 6, 77, 8, 9, 10);
+
+ RTTESTI_CHECK_RC(Arr2Copy4.setNull(), VINF_SUCCESS);
+ verifyArray(Arr2Copy4, __LINE__, 0);
+ RTTESTI_CHECK_MSG(MyRestInt16::s_cInstances == Arr2.size(), ("%zu vs %zu\n", MyRestInt16::s_cInstances, Arr2.size()));
+ RTTESTI_CHECK(Arr2Copy4.isNull() == true);
+
+ RTTESTI_CHECK_RC(Arr2Copy4.resetToDefault(), VINF_SUCCESS);
+ RTTESTI_CHECK(Arr2Copy4.isNull() == false);
+ verifyArray(Arr2Copy4, __LINE__, 0);
+ }
+ verifyArray(Arr2, __LINE__, 11, 0, 1, 2, 3, 4, 5, 6, 77, 8, 9, 10);
+ {
+ RTCRestArray<MyRestInt16> Arr2Copy5(Arr2);
+ verifyArray(Arr2Copy5, __LINE__, 11, 0, 1, 2, 3, 4, 5, 6, 77, 8, 9, 10);
+
+ RTTESTI_CHECK_RC(Arr2Copy5.resetToDefault(), VINF_SUCCESS);
+ verifyArray(Arr2Copy5, __LINE__, 0);
+ RTTESTI_CHECK_MSG(MyRestInt16::s_cInstances == Arr2.size(), ("%zu vs %zu\n", MyRestInt16::s_cInstances, Arr2.size()));
+ RTTESTI_CHECK(Arr2Copy5.isNull() == false);
+
+ RTTESTI_CHECK_RC(Arr2Copy5.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK(Arr2Copy5.isNull() == true);
+
+ RTTESTI_CHECK_RC(Arr2Copy5.append(new MyRestInt16(100)), VINF_SUCCESS);
+ RTTESTI_CHECK(Arr2Copy5.isNull() == false);
+ verifyArray(Arr2Copy5, __LINE__, 1, 100);
+ RTTESTI_CHECK_MSG(MyRestInt16::s_cInstances == Arr2.size() + 1, ("%zu vs %zu\n", MyRestInt16::s_cInstances, Arr2.size() + 1));
+ }
+ verifyArray(Arr2, __LINE__, 11, 0, 1, 2, 3, 4, 5, 6, 77, 8, 9, 10);
+
+ RTTESTI_CHECK_MSG(MyRestInt16::s_cInstances == Arr2.size(), ("%zu vs %zu\n", MyRestInt16::s_cInstances, Arr2.size()));
+ }
+ RTTESTI_CHECK_MSG(MyRestInt16::s_cInstances == 0, ("%zu\n", MyRestInt16::s_cInstances));
+
+ {
+ RTCRestArray<RTCRestInt64> Arr3;
+ RTCRestArray<RTCRestInt64> const *pConstArr3 = &Arr3;
+
+ /* Insert a range of numbers into a int64 array. */
+ for (int64_t i = 0; i < _64K; i++)
+ {
+ if (i & 1)
+ {
+ RTCRestInt64 toCopy(i);
+ if (i & 2)
+ RTTESTI_CHECK_RC(Arr3.insertCopy(i, toCopy), VINF_SUCCESS);
+ else
+ RTTESTI_CHECK_RC(Arr3.appendCopy(toCopy), VINF_SUCCESS);
+ }
+ else
+ {
+ RTCRestInt64 *pDirect = new RTCRestInt64(i);
+ if (i & 2)
+ RTTESTI_CHECK_RC(Arr3.insert(i, pDirect), VINF_SUCCESS);
+ else
+ RTTESTI_CHECK_RC(Arr3.append(pDirect), VINF_SUCCESS);
+ }
+ RTTESTI_CHECK(Arr3.size() == (size_t)i + 1);
+ RTTESTI_CHECK(Arr3.isEmpty() == false);
+ }
+
+ /* Verify insertions: */
+ size_t cElements = _64K;
+ RTTESTI_CHECK(Arr3.size() == cElements);
+
+ for (int64_t i = 0; i < _64K; i++)
+ {
+ RTCRestInt64 *pCur = Arr3.at(i);
+ RTTESTI_CHECK(pCur->m_iValue == i);
+
+ RTCRestInt64 const *pCur2 = pConstArr3->at(i);
+ RTTESTI_CHECK(pCur2->m_iValue == i);
+ }
+ RTTESTI_CHECK(Arr3.first()->m_iValue == 0);
+ RTTESTI_CHECK(Arr3.last()->m_iValue == _64K - 1);
+ RTTESTI_CHECK(pConstArr3->first()->m_iValue == 0);
+ RTTESTI_CHECK(pConstArr3->last()->m_iValue == _64K - 1);
+
+ /* Remove every 3rd element: */
+ RTTESTI_CHECK(Arr3.size() == cElements);
+ for (int64_t i = _64K - 1; i >= 0; i -= 3)
+ {
+ RTTESTI_CHECK_RC(Arr3.removeAt(i), VINF_SUCCESS);
+ cElements--;
+ RTTESTI_CHECK(Arr3.size() == cElements);
+ }
+
+ /* Verify after removal: */
+ for (int64_t i = 0, iValue = 0; i < (ssize_t)Arr3.size(); i++, iValue++)
+ {
+ if ((iValue % 3) == 0)
+ iValue++;
+ RTTESTI_CHECK_MSG(Arr3.at(i)->m_iValue == iValue, ("%RI64: %RI64 vs %RI64\n", i, Arr3.at(i)->m_iValue, iValue));
+ }
+
+ /* Clear it and we're done: */
+ Arr3.clear();
+ RTTESTI_CHECK(Arr3.size() == 0);
+ RTTESTI_CHECK(Arr3.isEmpty() == true);
+ }
+
+ {
+ RTCRestArray<RTCRestInt32> Arr4;
+
+ /* Insert a range of numbers into a int32 array, in reverse order. */
+ for (int32_t i = 0; i < 2048; i++)
+ {
+ if (i & 1)
+ {
+ RTCRestInt32 toCopy(i);
+ if (i & 2)
+ RTTESTI_CHECK_RC(Arr4.insertCopy(0, toCopy), VINF_SUCCESS);
+ else
+ RTTESTI_CHECK_RC(Arr4.prependCopy(toCopy), VINF_SUCCESS);
+ }
+ else
+ {
+ RTCRestInt32 *pDirect = new RTCRestInt32(i);
+ if (i & 2)
+ RTTESTI_CHECK_RC(Arr4.insert(0, pDirect), VINF_SUCCESS);
+ else
+ RTTESTI_CHECK_RC(Arr4.prepend(pDirect), VINF_SUCCESS);
+ }
+ RTTESTI_CHECK((ssize_t)Arr4.size() == i + 1);
+ RTTESTI_CHECK(Arr4.isEmpty() == false);
+ }
+
+ for (int32_t i = 0, iValue = (int32_t)Arr4.size() - 1; i < (ssize_t)Arr4.size(); i++, iValue--)
+ RTTESTI_CHECK_MSG(Arr4.at(i)->m_iValue == iValue, ("%RI32: %RI32 vs %RI32\n", i, Arr4.at(i)->m_iValue, iValue));
+
+ for (int32_t i = 0; i < 512; i++)
+ RTTESTI_CHECK_RC(Arr4.removeAt(0), VINF_SUCCESS);
+ RTTESTI_CHECK(Arr4.size() == 1536);
+
+ for (int32_t i = 0; i < 512; i++)
+ RTTESTI_CHECK_RC(Arr4.removeAt(~(size_t)0), VINF_SUCCESS);
+ RTTESTI_CHECK(Arr4.size() == 1024);
+
+ for (int32_t i = 0, iValue = 1535; i < (ssize_t)Arr4.size(); i++, iValue--)
+ RTTESTI_CHECK_MSG(Arr4.at(i)->m_iValue == iValue, ("%RI32: %RI32 vs %RI32\n", i, Arr4.at(i)->m_iValue, iValue));
+ }
+}
+
+
+static void verifyMap(RTCRestStringMap<MyRestInt16> const &rMap, int iLine, unsigned cEntries, ...)
+{
+ if (rMap.size() != cEntries)
+ RTTestIFailed("line %u: size() -> %zu, expected %u", iLine, rMap.size(), cEntries);
+ if (rMap.isEmpty() != (cEntries ? false : true))
+ RTTestIFailed("line %u: isEmpty() -> %RTbool, with %u entries", iLine, rMap.isEmpty(), cEntries);
+
+ va_list va;
+ va_start(va, cEntries);
+ for (unsigned i = 0; i < cEntries; i++)
+ {
+ const char *pszKey = va_arg(va, const char *);
+ int iValue = va_arg(va, int);
+ if ( rMap.containsKey(pszKey) != true
+ || rMap.containsKey(RTCString(pszKey)) != true
+ || rMap.get(pszKey) == NULL
+ || rMap.get(RTCString(pszKey)) == NULL)
+ RTTestIFailed("line %u: entry '%s' not found!", iLine, pszKey);
+ else if (rMap.get(pszKey)->m_iValue != iValue)
+ RTTestIFailed("line %u: entry '%s' value mismatch: %d, expected %d",
+ iLine, pszKey, rMap.get(pszKey)->m_iValue, iValue);
+ RTTESTI_CHECK(rMap.get(pszKey) == rMap.get(RTCString(pszKey)));
+ }
+ va_end(va);
+ RTTESTI_CHECK(rMap.isNull() == false);
+
+ uint64_t fFound = 0;
+ for (RTCRestStringMapBase::ConstIterator it = rMap.begin(); it != rMap.end(); ++it)
+ {
+ MyRestInt16 const *pObj = (MyRestInt16 const *)it.getValue();
+ RTTESTI_CHECK(RT_VALID_PTR(pObj));
+
+ bool fFoundIt = false;
+ va_start(va, cEntries);
+ for (unsigned i = 0; i < cEntries; i++)
+ {
+ const char *pszKey = va_arg(va, const char *);
+ int iValue = va_arg(va, int);
+ if (it.getKey().equals(pszKey))
+ {
+ if (fFound & RT_BIT_64(i))
+ RTTestIFailed("line %u: base enum: entry '%s' returned more than once!", iLine, pszKey);
+ if (pObj->m_iValue != iValue)
+ RTTestIFailed("line %u: base enum: entry '%s' value mismatch: %d, expected %d",
+ iLine, pszKey, pObj->m_iValue, iValue);
+ fFound |= RT_BIT_64(i);
+ fFoundIt = true;
+ va_end(va);
+ return;
+ }
+ }
+ va_end(va);
+ if (!fFoundIt)
+ RTTestIFailed("line %u: base enum: entry '%s' not expected!", iLine, it.getKey().c_str());
+ }
+}
+
+
+void testStringMap(void)
+{
+ RTTestSub(g_hTest, "RTCRestMap");
+
+ {
+ RTCRestStringMap<RTCRestString> obj1;
+ RTTESTI_CHECK(obj1.size() == 0);
+ RTTESTI_CHECK(obj1.isEmpty() == true);
+ RTTESTI_CHECK(obj1.isNull() == false);
+ RTTESTI_CHECK(strcmp(obj1.typeName(), "RTCRestStringMap<ValueType>") == 0);
+ RTTESTI_CHECK(obj1.typeClass() == RTCRestObjectBase::kTypeClass_StringMap);
+ }
+
+ /* Basic operations: */
+ {
+ MyRestInt16::s_cInstances = 0;
+ RTCRestStringMap<MyRestInt16> Map2;
+ verifyMap(Map2, __LINE__, 0);
+
+ RTTESTI_CHECK_RC(Map2.putCopy("0x0004", MyRestInt16(4)), VINF_SUCCESS);
+ verifyMap(Map2, __LINE__, 1, "0x0004", 4);
+ RTTESTI_CHECK(MyRestInt16::s_cInstances == 1);
+ RTTESTI_CHECK_RC(Map2.put("0x0001", new MyRestInt16(1)), VINF_SUCCESS);
+ verifyMap(Map2, __LINE__, 2, "0x0004",4, "0x0001",1);
+ RTTESTI_CHECK_RC(Map2.put("0x0003", new MyRestInt16(3)), VINF_SUCCESS);
+ verifyMap(Map2, __LINE__, 3, "0x0004",4, "0x0001",1, "0x0003",3);
+ RTTESTI_CHECK_RC(Map2.put("0x0002", new MyRestInt16(2)), VINF_SUCCESS);
+ verifyMap(Map2, __LINE__, 4, "0x0004",4, "0x0001",1, "0x0003",3, "0x0002",2);
+ RTTESTI_CHECK(MyRestInt16::s_cInstances == 4);
+ RTTESTI_CHECK_RC(Map2.put("0x0000", new MyRestInt16(0)), VINF_SUCCESS);
+ verifyMap(Map2, __LINE__, 5, "0x0004",4, "0x0001",1, "0x0003",3, "0x0002",2, "0x0000",0);
+ RTTESTI_CHECK(MyRestInt16::s_cInstances == 5);
+ RTTESTI_CHECK_RC(Map2.putCopy("towel", MyRestInt16(42)), VINF_SUCCESS);
+ verifyMap(Map2, __LINE__, 6, "0x0004",4, "0x0001",1, "0x0003",3, "0x0002",2, "0x0000",0, "towel",42);
+ RTTESTI_CHECK(MyRestInt16::s_cInstances == 6);
+
+ RTTESTI_CHECK(Map2.containsKey("0x0005") == false);
+ RTTESTI_CHECK(Map2.get("0x0005") == NULL);
+
+ RTTESTI_CHECK(Map2.remove("0x0003") == true);
+ verifyMap(Map2, __LINE__, 5, "0x0004",4, "0x0001",1, "0x0002",2, "0x0000",0, "towel",42);
+ RTTESTI_CHECK(MyRestInt16::s_cInstances == 5);
+
+ RTTESTI_CHECK(Map2.remove("0x0003") == false);
+ verifyMap(Map2, __LINE__, 5, "0x0004",4, "0x0001",1, "0x0002",2, "0x0000",0, "towel",42);
+ RTTESTI_CHECK(MyRestInt16::s_cInstances == 5);
+
+ RTCRestObjectBase *pNewBase = NULL;
+ RTTESTI_CHECK_RC(Map2.putNewValue(&pNewBase, "putNewValue"), VINF_SUCCESS);
+ ((MyRestInt16 *)pNewBase)->m_iValue = 88;
+ RTTESTI_CHECK(MyRestInt16::s_cInstances == 6);
+ verifyMap(Map2, __LINE__, 6, "0x0004",4, "0x0001",1, "0x0002",2, "0x0000",0, "towel",42, "putNewValue",88);
+
+ pNewBase = NULL;
+ RTTESTI_CHECK_RC(Map2.putNewValue(&pNewBase, RTCString("putNewValue")), VERR_ALREADY_EXISTS);
+ verifyMap(Map2, __LINE__, 6, "0x0004",4, "0x0001",1, "0x0002",2, "0x0000",0, "towel",42, "putNewValue",88);
+ pNewBase = NULL;
+ RTTESTI_CHECK_RC(Map2.putNewValue(&pNewBase, RTCString("putNewValue"), true /*a_fReplace*/), VWRN_ALREADY_EXISTS);
+ verifyMap(Map2, __LINE__, 6, "0x0004",4, "0x0001",1, "0x0002",2, "0x0000",0, "towel",42, "putNewValue",0);
+ RTTESTI_CHECK(MyRestInt16::s_cInstances == 6);
+
+ /* Make copy and remove all: */
+ {
+ RTCRestStringMap<MyRestInt16> Map2Copy1;
+
+ RTTESTI_CHECK_RC(Map2Copy1.assignCopy(Map2), VINF_SUCCESS);
+ verifyMap(Map2Copy1, __LINE__, 6, "0x0004",4, "0x0001",1, "0x0002",2, "0x0000",0, "towel",42, "putNewValue",0);
+ RTTESTI_CHECK(MyRestInt16::s_cInstances == 12);
+
+ RTTESTI_CHECK(Map2Copy1.remove("0x0004") == true);
+ verifyMap(Map2Copy1, __LINE__, 5, "0x0001",1, "0x0002",2, "0x0000",0, "towel",42, "putNewValue",0);
+ RTTESTI_CHECK(MyRestInt16::s_cInstances == 11);
+
+ RTTESTI_CHECK(Map2Copy1.remove("putNewValue") == true);
+ verifyMap(Map2Copy1, __LINE__, 4, "0x0001",1, "0x0002",2, "0x0000",0, "towel",42);
+ RTTESTI_CHECK(MyRestInt16::s_cInstances == 10);
+
+ RTTESTI_CHECK(Map2Copy1.remove("towel") == true);
+ verifyMap(Map2Copy1, __LINE__, 3, "0x0001",1, "0x0002",2, "0x0000",0);
+ RTTESTI_CHECK(MyRestInt16::s_cInstances == 9);
+
+ RTTESTI_CHECK(Map2Copy1.remove("0x0002") == true);
+ verifyMap(Map2Copy1, __LINE__, 2, "0x0001",1, "0x0000",0);
+ RTTESTI_CHECK(MyRestInt16::s_cInstances == 8);
+
+ RTTESTI_CHECK(Map2Copy1.remove("0x0000") == true);
+ verifyMap(Map2Copy1, __LINE__, 1, "0x0001",1);
+ RTTESTI_CHECK(MyRestInt16::s_cInstances == 7);
+
+ RTTESTI_CHECK(Map2Copy1.remove("0x0001") == true);
+ verifyMap(Map2Copy1, __LINE__, 0);
+ RTTESTI_CHECK(Map2Copy1.isEmpty() == true);
+ RTTESTI_CHECK(MyRestInt16::s_cInstances == 6);
+ }
+ verifyMap(Map2, __LINE__, 6, "0x0004",4, "0x0001",1, "0x0002",2, "0x0000",0, "towel",42, "putNewValue",0);
+
+ /* Make copy and use clear: */
+ {
+ RTCRestStringMap<MyRestInt16> Map2Copy2(Map2);
+ verifyMap(Map2Copy2, __LINE__, 6, "0x0004",4, "0x0001",1, "0x0002",2, "0x0000",0, "towel",42, "putNewValue",0);
+ RTTESTI_CHECK(MyRestInt16::s_cInstances == 12);
+ Map2Copy2.clear();
+ verifyMap(Map2Copy2, __LINE__, 0);
+ RTTESTI_CHECK(Map2Copy2.isEmpty() == true);
+ RTTESTI_CHECK(MyRestInt16::s_cInstances == 6);
+ }
+ verifyMap(Map2, __LINE__, 6, "0x0004",4, "0x0001",1, "0x0002",2, "0x0000",0, "towel",42, "putNewValue",0);
+
+ /* Make copy and reset to default: */
+ {
+ RTCRestStringMap<MyRestInt16> Map2Copy3(Map2);
+ verifyMap(Map2Copy3, __LINE__, 6, "0x0004",4, "0x0001",1, "0x0002",2, "0x0000",0, "towel",42, "putNewValue",0);
+ RTTESTI_CHECK(MyRestInt16::s_cInstances == 12);
+ RTTESTI_CHECK_RC(Map2Copy3.resetToDefault(), VINF_SUCCESS);
+ verifyMap(Map2Copy3, __LINE__, 0);
+ RTTESTI_CHECK(Map2Copy3.isEmpty() == true);
+ RTTESTI_CHECK(MyRestInt16::s_cInstances == 6);
+ }
+ verifyMap(Map2, __LINE__, 6, "0x0004",4, "0x0001",1, "0x0002",2, "0x0000",0, "towel",42, "putNewValue",0);
+
+ /* Make copy and set to null: */
+ {
+ RTCRestStringMap<MyRestInt16> Map2Copy4;
+ Map2Copy4 = Map2;
+ verifyMap(Map2Copy4, __LINE__, 6, "0x0004",4, "0x0001",1, "0x0002",2, "0x0000",0, "towel",42, "putNewValue",0);
+ RTTESTI_CHECK(MyRestInt16::s_cInstances == 12);
+ RTTESTI_CHECK_RC(Map2Copy4.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK(Map2Copy4.size() == 0);
+ RTTESTI_CHECK(Map2Copy4.isEmpty() == true);
+ RTTESTI_CHECK(Map2Copy4.isNull() == true);
+ RTTESTI_CHECK(MyRestInt16::s_cInstances == 6);
+ }
+ verifyMap(Map2, __LINE__, 6, "0x0004",4, "0x0001",1, "0x0002",2, "0x0000",0, "towel",42, "putNewValue",0);
+ }
+ RTTESTI_CHECK(MyRestInt16::s_cInstances == 0);
+
+ /* Check that null indicator is reset when it should: */
+ {
+ RTCRestStringMap<MyRestInt16> Map3;
+ Map3.setNull();
+ RTTESTI_CHECK_RC(Map3.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK(Map3.size() == 0);
+ RTTESTI_CHECK(Map3.isEmpty() == true);
+ RTTESTI_CHECK(Map3.isNull() == true);
+ RTTESTI_CHECK_RC(Map3.putCopy("not-null-anymore", MyRestInt16(1)), VINF_SUCCESS);
+ verifyMap(Map3, __LINE__, 1, "not-null-anymore",1);
+ }
+ RTTESTI_CHECK(MyRestInt16::s_cInstances == 0);
+
+ {
+ RTCRestStringMap<MyRestInt16> Map4;
+ Map4.setNull();
+ RTTESTI_CHECK_RC(Map4.setNull(), VINF_SUCCESS);
+ RTTESTI_CHECK(Map4.size() == 0);
+ RTTESTI_CHECK(Map4.isEmpty() == true);
+ RTTESTI_CHECK(Map4.isNull() == true);
+ RTCRestObjectBase *pNewBase = NULL;
+ RTTESTI_CHECK_RC(Map4.putNewValue(&pNewBase, "putNewValue"), VINF_SUCCESS);
+ verifyMap(Map4, __LINE__, 1, "putNewValue",0);
+ }
+ RTTESTI_CHECK(MyRestInt16::s_cInstances == 0);
+}
+
+
+class TestRequest : public RTCRestClientRequestBase
+{
+public:
+ RTCRestString m_strValue;
+ RTCRestInt64 m_iValue;
+ RTCRestArray<RTCRestString> m_Array;
+ RTCRestStringMap<RTCRestString> m_Map;
+ /** @todo add more attributes. */
+
+ TestRequest(const char *a_pszValue, int64_t a_iValue, unsigned a_cElements, ...)
+ : RTCRestClientRequestBase()
+ , m_strValue(a_pszValue)
+ , m_iValue(a_iValue)
+ {
+ m_fIsSet = UINT64_MAX;
+ va_list va;
+ va_start(va, a_cElements);
+ for (unsigned i = 0; i < a_cElements; i++)
+ m_Array.append(new RTCRestString(va_arg(va, const char *)));
+ va_end(va);
+ }
+
+ int resetToDefault() RT_NOEXCEPT RT_OVERRIDE
+ {
+ m_strValue = "";
+ m_iValue = 0;
+ return m_Array.resetToDefault();
+ }
+
+ int xmitPrepare(RTCString *a_pStrPath, RTCString *a_pStrQuery, RTHTTP a_hHttp, RTCString *a_pStrBody) const RT_NOEXCEPT RT_OVERRIDE
+ {
+ RT_NOREF(a_pStrPath, a_pStrQuery, a_hHttp, a_pStrBody);
+ return VINF_SUCCESS;
+ }
+
+ void xmitComplete(int a_rcStatus, RTHTTP a_hHttp) const RT_NOEXCEPT RT_OVERRIDE
+ {
+ RT_NOREF(a_rcStatus, a_hHttp);
+ }
+
+ void testPath(const char *a_pszExpected)
+ {
+ static PATHPARAMDESC const s_aParams[] =
+ {
+ { RT_STR_TUPLE("{string}"), 0, 0 },
+ { RT_STR_TUPLE("{integer}"), 0, 0 },
+ { RT_STR_TUPLE("{array}"), 0, 0 },
+ };
+ PATHPARAMSTATE aState[] = { { &m_strValue, 0 }, { &m_iValue, 0 }, { &m_Array, 0 } };
+ RTCString strPath;
+ RTTESTI_CHECK_RC(doPathParameters(&strPath, RT_STR_TUPLE("my/{integer}/{string}/array:{array}/path"),
+ s_aParams, aState, RT_ELEMENTS(aState)), VINF_SUCCESS);
+ RTTESTI_CHECK_MSG(strPath.equals(a_pszExpected), ("actual: '%s'\nexpect: '%s'\n", strPath.c_str(), a_pszExpected));
+ }
+
+ void testQuery(const char *a_pszCsv,
+ const char *a_pszSsv,
+ const char *a_pszTsv,
+ const char *a_pszPipes,
+ const char *a_pszMulti)
+ {
+ QUERYPARAMDESC aParams[] =
+ {
+ { "string", 0, true, 0 },
+ { "integer", 0, true, 0 },
+ { "array", 0, true, 0 },
+ };
+
+ RTCRestObjectBase const *apObjects[] = { &m_strValue, &m_iValue, &m_Array };
+ RTCString strQuery;
+ RTTESTI_CHECK_RC(doQueryParameters(&strQuery, aParams, apObjects, RT_ELEMENTS(apObjects)), VINF_SUCCESS);
+ RTTESTI_CHECK_MSG(strQuery.equals(a_pszCsv), ("actual: '%s'\nexpect: %s\n", strQuery.c_str(), a_pszCsv));
+
+ strQuery.setNull();
+ aParams[2].fFlags = RTCRestObjectBase::kCollectionFormat_csv;
+ RTTESTI_CHECK_RC(doQueryParameters(&strQuery, aParams, apObjects, RT_ELEMENTS(apObjects)), VINF_SUCCESS);
+ RTTESTI_CHECK_MSG(strQuery.equals(a_pszCsv), ("actual: '%s'\nexpect: %s\n", strQuery.c_str(), a_pszCsv));
+
+ strQuery.setNull();
+ aParams[2].fFlags = RTCRestObjectBase::kCollectionFormat_ssv;
+ RTTESTI_CHECK_RC(doQueryParameters(&strQuery, aParams, apObjects, RT_ELEMENTS(apObjects)), VINF_SUCCESS);
+ RTTESTI_CHECK_MSG(strQuery.equals(a_pszSsv), ("actual: '%s'\nexpect: %s\n", strQuery.c_str(), a_pszSsv));
+
+ strQuery.setNull();
+ aParams[2].fFlags = RTCRestObjectBase::kCollectionFormat_tsv;
+ RTTESTI_CHECK_RC(doQueryParameters(&strQuery, aParams, apObjects, RT_ELEMENTS(apObjects)), VINF_SUCCESS);
+ RTTESTI_CHECK_MSG(strQuery.equals(a_pszTsv), ("actual: '%s'\nexpect: %s\n", strQuery.c_str(), a_pszTsv));
+
+ strQuery.setNull();
+ aParams[2].fFlags = RTCRestObjectBase::kCollectionFormat_pipes;
+ RTTESTI_CHECK_RC(doQueryParameters(&strQuery, aParams, apObjects, RT_ELEMENTS(apObjects)), VINF_SUCCESS);
+ RTTESTI_CHECK_MSG(strQuery.equals(a_pszPipes), ("actual: '%s'\nexpect: %s\n", strQuery.c_str(), a_pszPipes));
+
+ strQuery.setNull();
+ aParams[2].fFlags = RTCRestObjectBase::kCollectionFormat_multi;
+ RTTESTI_CHECK_RC(doQueryParameters(&strQuery, aParams, apObjects, RT_ELEMENTS(apObjects)), VINF_SUCCESS);
+ RTTESTI_CHECK_MSG(strQuery.equals(a_pszMulti), ("actual: '%s'\nexpect: %s\n", strQuery.c_str(), a_pszMulti));
+ }
+
+ void testHeader(unsigned a_cHeaders, ...)
+ {
+ HEADERPARAMDESC aParams[] =
+ {
+ { "x-string", 0, true, 0, false },
+ { "x-integer", 0, true, 0, false },
+ { "x-array", 0, true, 0, false },
+ { "x-map-", 0, true, 0, true },
+ };
+ RTCRestObjectBase const *apObjects[] = { &m_strValue, &m_iValue, &m_Array, &m_Map };
+ RTHTTP hHttp = NIL_RTHTTP;
+ RTTESTI_CHECK_RC(RTHttpCreate(&hHttp), VINF_SUCCESS);
+ RTTESTI_CHECK_RC(doHeaderParameters(hHttp, aParams, apObjects, RT_ELEMENTS(apObjects)), VINF_SUCCESS);
+ RTTESTI_CHECK(RTHttpGetHeaderCount(hHttp) == a_cHeaders);
+ va_list va;
+ va_start(va, a_cHeaders);
+ for (size_t i = 0; i < a_cHeaders; i++)
+ {
+ const char *pszField = va_arg(va, const char *);
+ const char *pszValue = va_arg(va, const char *);
+ const char *pszActual = RTHttpGetHeader(hHttp, pszField, RTSTR_MAX);
+ RTTESTI_CHECK_MSG(RTStrCmp(pszActual, pszValue) == 0,
+ ("Header '%s' value is '%s' rather than '%s'", pszField, pszActual, pszValue));
+ }
+ va_end(va);
+ RTTESTI_CHECK_RC(RTHttpDestroy(hHttp), VINF_SUCCESS);
+ }
+};
+
+
+void testClientRequestBase()
+{
+ RTTestSub(g_hTest, "RTCRestClientRequestBase");
+ {
+ TestRequest Req1("this-is-a-string", 123456789, 5, "1", "22", "333", "444", "555");
+ Req1.testPath("my/123456789/this-is-a-string/array:1%2C22%2C333%2C444%2C555/path");
+ Req1.testQuery("?string=this-is-a-string&integer=123456789&array=1%2C22%2C333%2C444%2C555",
+ "?string=this-is-a-string&integer=123456789&array=1%2022%20333%20444%20555",
+ "?string=this-is-a-string&integer=123456789&array=1%0922%09333%09444%09555",
+ "?string=this-is-a-string&integer=123456789&array=1%7C22%7C333%7C444%7C555",
+ "?string=this-is-a-string&integer=123456789&array=1&array=22&array=333&array=444&array=555");
+ Req1.testHeader(3, "x-string","this-is-a-string", "x-integer","123456789", "x-array","1,22,333,444,555");
+ }
+ {
+ TestRequest Req2(";'[]", 42, 3, "null", "foo", "bar");
+ RTTESTI_CHECK_RC(Req2.m_Map.put("stuff-1", new RTCRestString("stuffy-value-1")), VINF_SUCCESS);
+ RTTESTI_CHECK_RC(Req2.m_Map.put("stuff-2", new RTCRestString("stuffy-value-2")), VINF_SUCCESS);
+ RTTESTI_CHECK_RC(Req2.m_Map.put("2222", new RTCRestString("33")), VINF_SUCCESS);
+ Req2.testPath("my/42/%3B%27%5B%5D/array:null%2Cfoo%2Cbar/path");
+ Req2.testQuery("?string=%3B%27%5B%5D&integer=42&array=null%2Cfoo%2Cbar",
+ "?string=%3B%27%5B%5D&integer=42&array=null%20foo%20bar",
+ "?string=%3B%27%5B%5D&integer=42&array=null%09foo%09bar",
+ "?string=%3B%27%5B%5D&integer=42&array=null%7Cfoo%7Cbar",
+ "?string=%3B%27%5B%5D&integer=42&array=null&array=foo&array=bar");
+ Req2.testHeader(6, "x-string",";'[]", "x-integer","42", "x-array","null,foo,bar",
+ "x-map-stuff-1","stuffy-value-1",
+ "x-map-stuff-2","stuffy-value-2",
+ "x-map-2222","33");
+ }
+}
+
+
+class TestResponse : public RTCRestClientResponseBase
+{
+public:
+ RTCRestArray<RTCRestString> *m_pArray;
+ RTCRestStringMap<RTCRestString> *m_pMap;
+ RTCRestInt64 *m_pInteger;
+ RTCRestString *m_pStrContentType;
+
+ TestResponse() : m_pArray(NULL), m_pMap(NULL), m_pInteger(NULL), m_pStrContentType(NULL)
+ { }
+
+protected:
+ virtual int consumeHeader(uint32_t a_uMatchWord, const char *a_pchField, size_t a_cchField,
+ const char *a_pchValue, size_t a_cchValue) RT_NOEXCEPT RT_OVERRIDE
+ {
+ int rc = RTCRestClientResponseBase::consumeHeader(a_uMatchWord, a_pchField, a_cchField, a_pchValue, a_cchValue);
+ AssertRCReturn(rc, rc);
+
+#define MATCH_FIELD(a_sz) (sizeof(a_sz) - 1 == a_cchField && RTStrNICmpAscii(a_pchField, RT_STR_TUPLE(a_sz)) == 0)
+ if (MATCH_FIELD("x-array"))
+ {
+ if (!m_pArray)
+ {
+ m_pArray = new (std::nothrow) RTCRestArray<RTCRestString>();
+ AssertReturn(m_pArray, VERR_NO_MEMORY);
+ return deserializeHeader(m_pArray, a_pchValue, a_cchValue, RTCRestObjectBase::kCollectionFormat_csv, "x-array");
+ }
+ }
+ else if (a_cchField >= sizeof("x-map-") - 1 && RTStrNICmpAscii(a_pchField, RT_STR_TUPLE("x-map-")) == 0)
+ {
+ if (!m_pMap)
+ {
+ m_pMap = new (std::nothrow) RTCRestStringMap<RTCRestString>();
+ AssertReturn(m_pMap, VERR_NO_MEMORY);
+ }
+ return deserializeHeaderIntoMap(m_pMap, a_pchField + 6, a_cchField - 6, a_pchValue, a_cchValue, 0, "x-map-");
+ }
+ else if (MATCH_FIELD("x-integer"))
+ {
+ if (!m_pInteger)
+ {
+ m_pInteger = new (std::nothrow) RTCRestInt64();
+ AssertReturn(m_pInteger, VERR_NO_MEMORY);
+ return deserializeHeader(m_pInteger, a_pchValue, a_cchValue, 0, "x-integer");
+ }
+ }
+ else if (MATCH_FIELD("content-type"))
+ {
+ if (!m_pStrContentType)
+ {
+ m_pStrContentType = new (std::nothrow) RTCRestString();
+ AssertReturn(m_pStrContentType, VERR_NO_MEMORY);
+ return deserializeHeader(m_pStrContentType, a_pchValue, a_cchValue, 0, "content-type");
+ }
+ }
+ else
+ return VWRN_NOT_FOUND;
+ RT_NOREF(a_uMatchWord);
+ return addError(VERR_ALREADY_EXISTS, "Already have field '%.*s'!", a_cchField, a_pchField);
+ }
+
+public:
+ int pushHeader(const char *pszField, const char *pszValue)
+ {
+ size_t const cchField = strlen(pszField);
+ void *pvFieldCopy = RTTestGuardedAllocTail(g_hTest, cchField);
+ RTTESTI_CHECK_RET(pvFieldCopy, VERR_NO_MEMORY);
+ memcpy(pvFieldCopy, pszField, cchField);
+
+ size_t const cchValue = strlen(pszValue);
+ void *pvValueCopy = RTTestGuardedAllocTail(g_hTest, cchValue);
+ RTTESTI_CHECK_RET(pvValueCopy, VERR_NO_MEMORY);
+ memcpy(pvValueCopy, pszValue, cchValue);
+
+ uint32_t uWord = RTHTTP_MAKE_HDR_MATCH_WORD(cchField,
+ cchField >= 1 ? RT_C_TO_LOWER(pszField[0]) : 0,
+ cchField >= 2 ? RT_C_TO_LOWER(pszField[1]) : 0,
+ cchField >= 3 ? RT_C_TO_LOWER(pszField[2]) : 0);
+ int rc = consumeHeader(uWord, (const char *)pvFieldCopy, cchField, (const char *)pvValueCopy, cchValue);
+ RTTestGuardedFree(g_hTest, pvValueCopy);
+ RTTestGuardedFree(g_hTest, pvFieldCopy);
+ return rc;
+ }
+};
+
+
+void testClientResponseBase()
+{
+ RTTestSub(g_hTest, "RTCRestClientResponseBase");
+ {
+ TestResponse Resp1;
+ RTTESTI_CHECK_RC(Resp1.pushHeader("content-type", "application/json; charset=utf-8"), VINF_SUCCESS);
+ RTTESTI_CHECK(Resp1.getContentType().equals("application/json; charset=utf-8"));
+ RTTESTI_CHECK(Resp1.m_pStrContentType && Resp1.m_pStrContentType->equals("application/json; charset=utf-8"));
+
+ RTTESTI_CHECK_RC(Resp1.pushHeader("content-typ2", "oopsy daisy"), VWRN_NOT_FOUND);
+ RTTESTI_CHECK_RC(Resp1.pushHeader("content-type2", "oopsy daisy"), VWRN_NOT_FOUND);
+ RTTESTI_CHECK(Resp1.getContentType().equals("application/json; charset=utf-8"));
+ RTTESTI_CHECK(Resp1.m_pStrContentType && Resp1.m_pStrContentType->equals("application/json; charset=utf-8"));
+
+ RTTESTI_CHECK_RC(Resp1.pushHeader("x-integer", "398679406"), VINF_SUCCESS);
+ RTTESTI_CHECK(Resp1.m_pInteger && Resp1.m_pInteger->m_iValue == 398679406);
+
+ RTTESTI_CHECK_RC(Resp1.pushHeader("x-array", "zero,one,two,three"), VINF_SUCCESS);
+ RTTESTI_CHECK(Resp1.m_pArray && Resp1.m_pArray->size() == 4);
+
+ RTTESTI_CHECK_RC(Resp1.pushHeader("x-map-", "empty-key"), VINF_SUCCESS);
+ RTTESTI_CHECK(Resp1.m_pMap && Resp1.m_pMap->size() == 1 && Resp1.m_pMap->get("") != NULL && Resp1.m_pMap->get("")->equals("empty-key"));
+
+ RTTESTI_CHECK_RC(Resp1.pushHeader("x-map-42", "key-is-42"), VINF_SUCCESS);
+ RTTESTI_CHECK(Resp1.m_pMap && Resp1.m_pMap->size() == 2 && Resp1.m_pMap->get("42") != NULL && Resp1.m_pMap->get("42")->equals("key-is-42"));
+ }
+}
+
+
+int main()
+{
+ RTEXITCODE rcExit = RTTestInitAndCreate("tstRTCRest-1", &g_hTest);
+ if (rcExit == RTEXITCODE_SUCCESS )
+ {
+ testBool();
+ testInteger<RTCRestInt64, int64_t, Int64Constants>();
+ testInteger<RTCRestInt32, int32_t, Int32Constants>();
+ testInteger<RTCRestInt16, int16_t, Int16Constants>();
+ testDouble();
+ testString("dummy", 1, 2);
+ testDate();
+ testArray();
+ testStringMap();
+ testClientRequestBase();
+ testClientResponseBase();
+
+ rcExit = RTTestSummaryAndDestroy(g_hTest);
+ }
+ return rcExit;
+}
+