mirror of
https://github.com/taglib/taglib.git
synced 2025-05-25 12:10:26 -04:00
Variant type as container for complex properties
This commit is contained in:
parent
304ab62957
commit
75d4252480
@ -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
391
taglib/toolkit/tvariant.cpp
Normal 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
202
taglib/toolkit/tvariant.h
Normal 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
|
@ -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
204
tests/test_variant.cpp
Normal 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);
|
Loading…
Reference in New Issue
Block a user