Variant type as container for complex properties

This commit is contained in:
Urs Fleisch 2023-10-01 19:56:33 +02:00
parent 304ab62957
commit 75d4252480
5 changed files with 800 additions and 0 deletions

View File

@ -40,6 +40,7 @@ set(tag_HDRS
toolkit/tstringlist.h
toolkit/tbytevector.h
toolkit/tbytevectorlist.h
toolkit/tvariant.h
toolkit/tbytevectorstream.h
toolkit/tiostream.h
toolkit/tfile.h
@ -300,6 +301,7 @@ set(toolkit_SRCS
toolkit/tstringlist.cpp
toolkit/tbytevector.cpp
toolkit/tbytevectorlist.cpp
toolkit/tvariant.cpp
toolkit/tbytevectorstream.cpp
toolkit/tiostream.cpp
toolkit/tfile.cpp

391
taglib/toolkit/tvariant.cpp Normal file
View File

@ -0,0 +1,391 @@
/***************************************************************************
copyright : (C) 2023 by Urs Fleisch
email : ufleisch@users.sourceforge.net
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include "tvariant.h"
#include <variant>
#include <iomanip>
#include "tstring.h"
#include "tstringlist.h"
#include "tbytevector.h"
#include "tbytevectorlist.h"
using namespace TagLib;
namespace {
// The number and order of the template parameters must correspond to the
// enum values in Variant::Type!
using StdVariantType = std::variant<
std::monostate,
bool,
int,
unsigned int,
long long,
unsigned long long,
double,
TagLib::String,
TagLib::StringList,
TagLib::ByteVector,
TagLib::ByteVectorList,
List<TagLib::Variant>,
Map<TagLib::String, TagLib::Variant>
>;
template<typename T>
T getVariantValue(StdVariantType *v, bool *ok)
{
if(const auto valPtr = std::get_if<T>(v)) {
if(ok) {
*ok = true;
}
return *valPtr;
}
if(ok) {
*ok = false;
}
return {};
}
// Visitor to print a possibly recursive Variant to an ostream.
// The representation is JSON with hex strings for ByteVector.
class OStreamVisitor {
public:
OStreamVisitor(std::ostream &os) : s(os)
{
}
void operator()(std::monostate v)
{
s << "null";
}
void operator()(bool v)
{
s << (v ? "true" : "false");
}
void operator()(int v)
{
s << v;
}
void operator()(unsigned int v)
{
s << v;
}
void operator()(long long v)
{
s << v;
}
void operator()(unsigned long long v)
{
s << v;
}
void operator()(double v)
{
s << v;
}
void operator()(const TagLib::String &v)
{
s << '"';
for (char c : v.to8Bit()) {
if(c == '"') {
s << "\\\"";
}
else {
s << c;
}
}
s << '"';
}
void operator()(const TagLib::StringList &v)
{
s << '[';
for(auto it = v.cbegin(); it != v.cend(); ++it) {
if(it != v.cbegin()) {
s << ", ";
}
operator()(*it);
}
s << ']';
}
void operator()(const TagLib::ByteVector &v)
{
s << '"';
for(char c : v) {
s << "\\x" << std::setfill('0') << std::setw(2) << std::right << std::hex
<< (static_cast<int>(c) & 0xff);
}
s << std::dec << '"';
}
void operator()(const TagLib::ByteVectorList &v)
{
s << '[';
for(auto it = v.cbegin(); it != v.cend(); ++it) {
if(it != v.cbegin()) {
s << ", ";
}
operator()(*it);
}
s << ']';
}
void operator()(const List<TagLib::Variant> &v) {
s << '[';
for(auto it = v.cbegin(); it != v.cend(); ++it) {
if(it != v.cbegin()) {
s << ", ";
}
s << *it;
}
s << ']';
}
void operator()(const Map<TagLib::String, TagLib::Variant> &v)
{
s << '{';
for(auto it = v.cbegin(); it != v.cend(); ++it) {
if(it != v.cbegin()) {
s << ", ";
}
operator()(it->first);
s << ": ";
s << it->second;
}
s << '}';
}
private:
std::ostream &s;
};
} // namespace
class Variant::VariantPrivate
{
public:
VariantPrivate() = default;
VariantPrivate(const StdVariantType &v) : data(v) {}
StdVariantType data;
};
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
Variant::Variant() :
d(std::make_shared<VariantPrivate>())
{
}
Variant::Variant(int val) :
d(std::make_shared<VariantPrivate>(val))
{
}
Variant::Variant(unsigned int val) :
d(std::make_shared<VariantPrivate>(val))
{
}
Variant::Variant(long long val) :
d(std::make_shared<VariantPrivate>(val))
{
}
Variant::Variant(unsigned long long val) :
d(std::make_shared<VariantPrivate>(val))
{
}
Variant::Variant(bool val) :
d(std::make_shared<VariantPrivate>(val))
{
}
Variant::Variant(double val) :
d(std::make_shared<VariantPrivate>(val))
{
}
Variant::Variant(const char *val) :
d(std::make_shared<VariantPrivate>(TagLib::String(val)))
{
}
Variant::Variant(const TagLib::String &val) :
d(std::make_shared<VariantPrivate>(val))
{
}
Variant::Variant(const TagLib::StringList &val) :
d(std::make_shared<VariantPrivate>(val))
{
}
Variant::Variant(const TagLib::ByteVector &val) :
d(std::make_shared<VariantPrivate>(val))
{
}
Variant::Variant(const TagLib::ByteVectorList &val) :
d(std::make_shared<VariantPrivate>(val))
{
}
Variant::Variant(const TagLib::List<TagLib::Variant> &val) :
d(std::make_shared<VariantPrivate>(val))
{
}
Variant::Variant(const TagLib::Map<TagLib::String, TagLib::Variant> &val) :
d(std::make_shared<VariantPrivate>(val))
{
}
Variant::Variant(const Variant &) = default;
////////////////////////////////////////////////////////////////////////////////
Variant::~Variant() = default;
Variant::Type Variant::type() const {
return static_cast<Type>(d->data.index());
}
bool Variant::isEmpty() const
{
return type() == Void;
}
template<typename T>
T Variant::value(bool *ok) const
{
return getVariantValue<T>(&d->data, ok);
}
template bool Variant::value(bool *ok) const;
template int Variant::value(bool *ok) const;
template unsigned int Variant::value(bool *ok) const;
template long long Variant::value(bool *ok) const;
template unsigned long long Variant::value(bool *ok) const;
template double Variant::value(bool *ok) const;
template String Variant::value(bool *ok) const;
template StringList Variant::value(bool *ok) const;
template ByteVector Variant::value(bool *ok) const;
template ByteVectorList Variant::value(bool *ok) const;
template VariantList Variant::value(bool *ok) const;
template VariantMap Variant::value(bool *ok) const;
bool Variant::toBool(bool *ok) const
{
return value<bool>(ok);
}
int Variant::toInt(bool *ok) const
{
return value<int>(ok);
}
unsigned int Variant::toUInt(bool *ok) const
{
return value<unsigned int>(ok);
}
long long Variant::toLongLong(bool *ok) const
{
return value<long long>(ok);
}
unsigned long long Variant::toULongLong(bool *ok) const
{
return value<unsigned long long>(ok);
}
double Variant::toDouble(bool *ok) const
{
return value<double>(ok);
}
TagLib::String Variant::toString(bool *ok) const
{
return value<TagLib::String>(ok);
}
TagLib::StringList Variant::toStringList(bool *ok) const
{
return value<TagLib::StringList>(ok);
}
TagLib::ByteVector Variant::toByteVector(bool *ok) const
{
return value<TagLib::ByteVector>(ok);
}
TagLib::ByteVectorList Variant::toByteVectorList(bool *ok) const
{
return value<TagLib::ByteVectorList>(ok);
}
TagLib::List<TagLib::Variant> Variant::toList(bool *ok) const
{
return value<TagLib::List<TagLib::Variant>>(ok);
}
TagLib::Map<TagLib::String, TagLib::Variant> Variant::toMap(bool *ok) const
{
return value<TagLib::Map<TagLib::String, TagLib::Variant>>(ok);
}
bool Variant::operator==(const Variant &v) const
{
return (d == v.d || d->data == v.d->data);
}
bool Variant::operator!=(const Variant &v) const
{
return !(*this == v);
}
Variant &Variant::operator=(const Variant &) = default;
////////////////////////////////////////////////////////////////////////////////
// related non-member functions
////////////////////////////////////////////////////////////////////////////////
std::ostream &operator<<(std::ostream &s, const TagLib::Variant &v)
{
std::visit(OStreamVisitor(s), v.d->data);
return s;
}

202
taglib/toolkit/tvariant.h Normal file
View File

@ -0,0 +1,202 @@
/***************************************************************************
copyright : (C) 2023 by Urs Fleisch
email : ufleisch@users.sourceforge.net
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifndef TAGLIB_VARIANT_H
#define TAGLIB_VARIANT_H
#include <memory.h>
#include <iostream>
#include "tlist.h"
#include "tmap.h"
#include "taglib_export.h"
// Forward declaration needed for friend function
namespace TagLib { class Variant; }
/*!
* \relates TagLib::Variant
*
* Send the variant to an output stream.
*/
TAGLIB_EXPORT std::ostream &operator<<(std::ostream &s, const TagLib::Variant &v);
namespace TagLib {
class String;
class StringList;
class ByteVector;
class ByteVectorList;
/*!
* This is an implicitly shared discriminated union.
*
* The use of implicit sharing means that copying a variant is cheap.
* These Variant objects are immutable (have only const methods).
*/
class TAGLIB_EXPORT Variant
{
public:
/*!
* Types which can be stored in a variant.
*/
// The number and order of these types must correspond to the template
// parameters for StdVariantType in tvariant.cpp!
enum Type {
Void,
Bool,
Int,
UInt,
LongLong,
ULongLong,
Double,
String,
StringList,
ByteVector,
ByteVectorList,
VariantList,
VariantMap
};
/*!
* Constructs an empty Variant.
*/
Variant();
/*!
* Constructs a Variant from an integer value.
*/
Variant(int val);
Variant(unsigned int val);
Variant(long long val);
Variant(unsigned long long val);
Variant(bool val);
Variant(double val);
Variant(const char *val);
Variant(const TagLib::String &val);
Variant(const TagLib::StringList &val);
Variant(const TagLib::ByteVector &val);
Variant(const TagLib::ByteVectorList &val);
Variant(const TagLib::List<TagLib::Variant> &val);
Variant(const TagLib::Map<TagLib::String, TagLib::Variant> &val);
/*!
* Make a shallow, implicitly shared, copy of \a v. Because this is
* implicitly shared, this method is lightweight and suitable for
* pass-by-value usage.
*/
Variant(const Variant &v);
/*!
* Destroys this Variant instance.
*/
~Variant();
/*!
* Get the type which is currently stored in this Variant.
*/
Type type() const;
/*!
* Returns true if the Variant is empty.
*/
bool isEmpty() const;
/*!
* Extracts an integer value from the Variant.
* If \a ok is passed, its boolean variable will be set to true if the
* Variant contains the correct type, and the returned value is the value
* of the Variant. Otherwise, the \a ok variable is set to false and
* a dummy default value is returned.
*/
int toInt(bool *ok = nullptr) const;
unsigned int toUInt(bool *ok = nullptr) const;
long long toLongLong(bool *ok = nullptr) const;
unsigned long long toULongLong(bool *ok = nullptr) const;
bool toBool(bool *ok = nullptr) const;
double toDouble(bool *ok = nullptr) const;
TagLib::String toString(bool *ok = nullptr) const;
TagLib::StringList toStringList(bool *ok = nullptr) const;
TagLib::ByteVector toByteVector(bool *ok = nullptr) const;
TagLib::ByteVectorList toByteVectorList(bool *ok = nullptr) const;
TagLib::List<TagLib::Variant> toList(bool *ok = nullptr) const;
TagLib::Map<TagLib::String, TagLib::Variant> toMap(bool *ok = nullptr) const;
/*!
* Extracts value of type \a T from the Variant.
* If \a ok is passed, its boolean variable will be set to true if the
* Variant contains the correct type, and the returned value is the value
* of the Variant. Otherwise, the \a ok variable is set to false and
* a dummy default value is returned.
*/
template<typename T>
T value(bool *ok = nullptr) const;
/*!
* Returns true it the Variant and \a v are of the same type and contain the
* same value.
*/
bool operator==(const Variant &v) const;
/*!
* Returns true it the Variant and \a v differ in type or value.
*/
bool operator!=(const Variant &v) const;
/*!
* Performs a shallow, implicitly shared, copy of \a v, overwriting the
* Variant's current data.
*/
Variant &operator=(const Variant &v);
private:
friend std::ostream& ::operator<<(std::ostream &s, const TagLib::Variant &v);
class VariantPrivate;
std::shared_ptr<VariantPrivate> d;
};
/*! A list of Variant elements. */
using VariantList = TagLib::List<TagLib::Variant>;
/*! A map with String keys and Variant values. */
using VariantMap = TagLib::Map<TagLib::String, TagLib::Variant>;
extern template TAGLIB_EXPORT bool Variant::value(bool *ok) const;
extern template TAGLIB_EXPORT int Variant::value(bool *ok) const;
extern template TAGLIB_EXPORT unsigned int Variant::value(bool *ok) const;
extern template TAGLIB_EXPORT long long Variant::value(bool *ok) const;
extern template TAGLIB_EXPORT unsigned long long Variant::value(bool *ok) const;
extern template TAGLIB_EXPORT double Variant::value(bool *ok) const;
extern template TAGLIB_EXPORT String Variant::value(bool *ok) const;
extern template TAGLIB_EXPORT StringList Variant::value(bool *ok) const;
extern template TAGLIB_EXPORT ByteVector Variant::value(bool *ok) const;
extern template TAGLIB_EXPORT ByteVectorList Variant::value(bool *ok) const;
extern template TAGLIB_EXPORT VariantList Variant::value(bool *ok) const;
extern template TAGLIB_EXPORT VariantMap Variant::value(bool *ok) const;
} // namespace TagLib
#endif

View File

@ -39,6 +39,7 @@ SET(test_runner_SRCS
test_bytevectorstream.cpp
test_string.cpp
test_propertymap.cpp
test_variant.cpp
test_file.cpp
test_fileref.cpp
test_id3v1.cpp

204
tests/test_variant.cpp Normal file
View File

@ -0,0 +1,204 @@
/***************************************************************************
copyright : (C) 2023 by Urs Fleisch
email : ufleisch@users.sourceforge.net
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <array>
#include "tbytevector.h"
#include "tvariant.h"
#include "tstringlist.h"
#include "tbytevectorlist.h"
#include <cppunit/extensions/HelperMacros.h>
#include <sstream>
#include "utils.h"
using namespace TagLib;
class TestVariant : public CppUnit::TestFixture
{
CPPUNIT_TEST_SUITE(TestVariant);
CPPUNIT_TEST(testVariantTypes);
CPPUNIT_TEST(testVariantToOStream);
CPPUNIT_TEST_SUITE_END();
public:
void testVariantTypes()
{
ByteVectorList bvl {"first", "second"};
StringList sl {"el0", "el"};
VariantList vl {"1st", "2nd"};
VariantMap vm {{"key1", "value1"}, {"key2", "value2"}};
Variant varVoid;
Variant varBool(true);
Variant varInt(-4);
Variant varUInt(5U);
Variant varLongLong(-6LL);
Variant varULongLong(7ULL);
Variant varDouble(1.23);
Variant varString(String("test"));
Variant varString2("charp");
Variant varStringList(sl);
Variant varByteVector(ByteVector("data"));
Variant varByteVectorList(bvl);
Variant varVariantList(vl);
Variant varVariantMap(vm);
static const std::array<std::tuple<Variant, Variant::Type>, 14> varTypes {
std::tuple{varVoid, Variant::Void},
std::tuple{varBool, Variant::Bool},
std::tuple{varInt, Variant::Int},
std::tuple{varUInt, Variant::UInt},
std::tuple{varLongLong, Variant::LongLong},
std::tuple{varULongLong, Variant::ULongLong},
std::tuple{varDouble, Variant::Double},
std::tuple{varString, Variant::String},
std::tuple{varString2, Variant::String},
std::tuple{varStringList, Variant::StringList},
std::tuple{varByteVector, Variant::ByteVector},
std::tuple{varByteVectorList, Variant::ByteVectorList},
std::tuple{varVariantList, Variant::VariantList},
std::tuple{varVariantMap, Variant::VariantMap}
};
for(const auto &t : varTypes) {
CPPUNIT_ASSERT_EQUAL(std::get<1>(t), std::get<0>(t).type());
if(std::get<0>(t).type() == Variant::Void) {
CPPUNIT_ASSERT(std::get<0>(t).isEmpty());
}
else {
CPPUNIT_ASSERT(!std::get<0>(t).isEmpty());
}
}
bool ok;
CPPUNIT_ASSERT_EQUAL(true, varBool.toBool(&ok));
CPPUNIT_ASSERT(ok);
CPPUNIT_ASSERT_EQUAL(true, varBool.value<bool>(&ok));
CPPUNIT_ASSERT(ok);
CPPUNIT_ASSERT_EQUAL(-4, varInt.toInt(&ok));
CPPUNIT_ASSERT(ok);
CPPUNIT_ASSERT_EQUAL(-4, varInt.value<int>(&ok));
CPPUNIT_ASSERT(ok);
CPPUNIT_ASSERT_EQUAL(5U, varUInt.toUInt(&ok));
CPPUNIT_ASSERT(ok);
CPPUNIT_ASSERT_EQUAL(5U, varUInt.value<unsigned int>(&ok));
CPPUNIT_ASSERT(ok);
CPPUNIT_ASSERT_EQUAL(-6LL, varLongLong.toLongLong(&ok));
CPPUNIT_ASSERT(ok);
CPPUNIT_ASSERT_EQUAL(-6LL, varLongLong.value<long long>(&ok));
CPPUNIT_ASSERT(ok);
CPPUNIT_ASSERT_EQUAL(7ULL, varULongLong.toULongLong(&ok));
CPPUNIT_ASSERT(ok);
CPPUNIT_ASSERT_EQUAL(7ULL, varULongLong.value<unsigned long long>(&ok));
CPPUNIT_ASSERT(ok);
CPPUNIT_ASSERT_EQUAL(1.23, varDouble.toDouble(&ok));
CPPUNIT_ASSERT(ok);
CPPUNIT_ASSERT_EQUAL(1.23, varDouble.value<double>(&ok));
CPPUNIT_ASSERT(ok);
CPPUNIT_ASSERT_EQUAL(String("test"), varString.toString(&ok));
CPPUNIT_ASSERT(ok);
CPPUNIT_ASSERT_EQUAL(String("test"), varString.value<String>(&ok));
CPPUNIT_ASSERT(ok);
CPPUNIT_ASSERT_EQUAL(String("charp"), varString2.toString(&ok));
CPPUNIT_ASSERT(ok);
CPPUNIT_ASSERT_EQUAL(String("charp"), varString2.value<String>(&ok));
CPPUNIT_ASSERT(ok);
CPPUNIT_ASSERT_EQUAL(sl, varStringList.toStringList(&ok));
CPPUNIT_ASSERT(ok);
CPPUNIT_ASSERT_EQUAL(sl, varStringList.value<StringList>(&ok));
CPPUNIT_ASSERT(ok);
CPPUNIT_ASSERT_EQUAL(ByteVector("data"), varByteVector.toByteVector(&ok));
CPPUNIT_ASSERT(ok);
CPPUNIT_ASSERT_EQUAL(ByteVector("data"), varByteVector.value<ByteVector>(&ok));
CPPUNIT_ASSERT(ok);
CPPUNIT_ASSERT_EQUAL(bvl, varByteVectorList.toByteVectorList(&ok));
CPPUNIT_ASSERT(ok);
CPPUNIT_ASSERT_EQUAL(bvl, varByteVectorList.value<ByteVectorList>(&ok));
CPPUNIT_ASSERT(ok);
CPPUNIT_ASSERT_EQUAL(vl, varVariantList.toList(&ok));
CPPUNIT_ASSERT(ok);
CPPUNIT_ASSERT_EQUAL(vl, varVariantList.value<VariantList>(&ok));
CPPUNIT_ASSERT(ok);
CPPUNIT_ASSERT_EQUAL(vm, varVariantMap.toMap(&ok));
CPPUNIT_ASSERT(ok);
CPPUNIT_ASSERT_EQUAL(vm, varVariantMap.value<VariantMap>(&ok));
CPPUNIT_ASSERT(ok);
CPPUNIT_ASSERT_EQUAL(0, varBool.toInt(&ok));
CPPUNIT_ASSERT(!ok);
CPPUNIT_ASSERT_EQUAL(0U, varInt.toUInt(&ok));
CPPUNIT_ASSERT(!ok);
CPPUNIT_ASSERT_EQUAL(0LL, varUInt.toLongLong(&ok));
CPPUNIT_ASSERT(!ok);
CPPUNIT_ASSERT_EQUAL(0ULL, varLongLong.toULongLong(&ok));
CPPUNIT_ASSERT(!ok);
CPPUNIT_ASSERT_EQUAL(0.0, varULongLong.toDouble(&ok));
CPPUNIT_ASSERT(!ok);
CPPUNIT_ASSERT_EQUAL(String(), varDouble.toString(&ok));
CPPUNIT_ASSERT(!ok);
CPPUNIT_ASSERT_EQUAL(StringList(), varString.toStringList(&ok));
CPPUNIT_ASSERT(!ok);
CPPUNIT_ASSERT_EQUAL(ByteVector(), varStringList.toByteVector(&ok));
CPPUNIT_ASSERT(!ok);
CPPUNIT_ASSERT(varByteVector.toByteVectorList(&ok).isEmpty());
CPPUNIT_ASSERT(!ok);
CPPUNIT_ASSERT_EQUAL(VariantList(), varByteVectorList.toList(&ok));
CPPUNIT_ASSERT(!ok);
CPPUNIT_ASSERT_EQUAL(VariantMap(), varVariantList.toMap(&ok));
CPPUNIT_ASSERT(!ok);
CPPUNIT_ASSERT_EQUAL(false, varVariantMap.toBool(&ok));
CPPUNIT_ASSERT(!ok);
CPPUNIT_ASSERT(varUInt == varUInt);
CPPUNIT_ASSERT(varUInt == Variant(5U));
CPPUNIT_ASSERT(varUInt != Variant(6U));
CPPUNIT_ASSERT(varUInt != Variant(5));
CPPUNIT_ASSERT(varUInt != varInt);
Variant varUInt2(varUInt);
CPPUNIT_ASSERT(varUInt == varUInt2);
varUInt2 = 6U;
CPPUNIT_ASSERT(varUInt != varUInt2);
CPPUNIT_ASSERT_EQUAL(5U, varUInt.toUInt());
CPPUNIT_ASSERT_EQUAL(6U, varUInt2.toUInt());
}
void testVariantToOStream()
{
std::stringstream ss;
VariantMap vm {
{"strlist", StringList {"first", "second"}},
{"varlist", VariantList {Variant(), 1U, -10LL, 4.32, false}},
{"data", ByteVector("\xa9\x01\x7f", 3)}
};
ss << vm;
CPPUNIT_ASSERT_EQUAL(
R"({"data": "\xa9\x01\x7f", "strlist": ["first", "second"],)"
R"( "varlist": [null, 1, -10, 4.32, false]})"s,
ss.str());
}
};
CPPUNIT_TEST_SUITE_REGISTRATION(TestVariant);