Commit dd4342db authored by jacobgladish's avatar jacobgladish

Fixed some variant bugs. Added unit test.

parent 58b933f8
#include "Variant.h"
#include <string.h>
#include <sstream>
namespace
{
template<class TFrom, class TOut>
void printArray(std::stringstream& buff, void* arr, int n)
{
TFrom* typed_array = reinterpret_cast<TFrom *>(arr);
for (int i = 0; i < n; ++i)
{
if (i > 0) buff << ',';
buff << static_cast<TOut>(typed_array[i]);
}
}
}
common::Variant::Data::Data()
{
......@@ -181,10 +196,10 @@ common::Variant::Variant(Variant const& other)
common::Variant::~Variant()
{
if (m_data.Item.v_string)
if (m_data.Type == DataType::String && m_data.Item.v_string)
delete m_data.Item.v_string;
if (m_data.Item.v_arr)
if (IsArray() && m_data.Item.v_arr)
free(m_data.Item.v_arr);
}
......@@ -192,12 +207,24 @@ common::Variant&
common::Variant::operator=(Variant const& other)
{
if (&other != this)
{
AssignFrom(other);
}
return *this;
}
bool
common::Variant::IsArray() const
{
// relies on knowing order of enum
return GetType() > DataType::String;
}
int
common::Variant::Length() const
{
if (!IsArray()) return -1;
return m_data.Size;
}
std::vector<bool>
common::Variant::ToBooleanArray(bool* ok) const
{
......@@ -338,6 +365,31 @@ common::Variant::CanConvert(DataType t) const
std::string
common::Variant::ToString(bool* ok) const
{
if (IsArray())
{
std::stringstream buff;
buff << '[';
switch (m_data.Type)
{
case DataType::Invalid: break;
case DataType::BooleanArray: printArray<bool, bool>(buff, m_data.Item.v_arr, m_data.Size); break;
case DataType::UInt8Array: printArray<uint8_t, int>(buff, m_data.Item.v_arr, m_data.Size); break;
case DataType::Int16Array: printArray<int16_t, int>(buff, m_data.Item.v_arr, m_data.Size); break;
case DataType::UInt16Array: printArray<uint16_t, int>(buff, m_data.Item.v_arr, m_data.Size); break;
case DataType::Int32Array: printArray<int32_t, int>(buff, m_data.Item.v_arr, m_data.Size); break;
case DataType::UInt32Array: printArray<uint32_t, uint32_t>(buff, m_data.Item.v_arr, m_data.Size); break;
case DataType::Int64Array: printArray<int64_t, int64_t>(buff, m_data.Item.v_arr, m_data.Size); break;
case DataType::UInt64Array: printArray<uint64_t, uint64_t>(buff, m_data.Item.v_arr, m_data.Size); break;
case DataType::DoubleArray: printArray<double, double>(buff, m_data.Item.v_arr, m_data.Size); break;
case DataType::StringArray: printArray<std::string, std::string>(buff, m_data.Item.v_arr, m_data.Size); break;
default:
assert(false);
break;
}
buff << ']';
return buff.str();
}
// string handled special to allow for other data types
// to be converted later.
if (CanConvert(DataType::String))
......
#pragma once
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <string>
#include <vector>
......@@ -68,6 +69,10 @@ namespace common
~Variant();
bool IsArray() const;
int Length() const;
inline DataType GetType() const
{ return m_data.Type; }
......@@ -140,7 +145,7 @@ namespace common
{
if (CanConvert(t))
{
if (*ok)
if (ok)
*ok = true;
return Convert<T>(t);
}
......@@ -198,10 +203,13 @@ namespace common
template<class T>
void AssignFromArray(Data& to, Data const& from)
{
if (to.Item.v_arr)
if (IsArray() && to.Item.v_arr)
free(to.Item.v_arr);
memset(&to.Item, 0, sizeof(to.Item));
to.Item.v_arr = malloc(sizeof(T) * from.Size);
to.Size = from.Size;
to.Type = from.Type;
T* toVect = reinterpret_cast<T *>(to.Item.v_arr);
T* fromVect = reinterpret_cast<T *>(from.Item.v_arr);
......@@ -216,9 +224,10 @@ namespace common
d.Size = static_cast<int>(v.size());
if (d.Size > 0)
{
if (d.Item.v_arr)
if (IsArray() && d.Item.v_arr)
free(d.Item.v_arr);
memset(&d.Item, 0, sizeof(d.Item));
d.Item.v_arr = malloc(sizeof(T) * d.Size);
T* arr = reinterpret_cast<T *>(d.Item.v_arr);
......
SRCS=VariantTest.cpp
ALLJOYN_INSTALL_DIR?=/
GTEST_DIR?=/usr/src/gtest
LIBXML_INC?=/usr/include/libxml2
CXX_WARNINGS=-Wall -Wextra -Wno-missing-field-initializers -Wno-deprecated-declarations -Wno-ignored-qualifiers
CXX_DEFINES=-D QCC_OS_GROUP_POSIX
CXX_SEARCH=-I.. -I$(ALLJOYN_INSTALL_DIR)/inc -I$(LIBXML_INC) -I$(GTEST_DIR)/include
CXXFLAGS=-isystem -std=c++0x -g $(CXX_WARNINGS) $(CXX_DEFINES) $(CXX_SEARCH)
LDFLAGS=-L$(ALLJOYN_INSTALL_DIR)/lib -lalljoyn -lcrypto -lxml2 -L$(GTEST_DIR)/libgtest.a
TEST_OBJS=$(patsubst %.cpp, %.o, $(SRCS))
OBJS=$(TEST_OBJS)
DEPS = $(OBJS:%.o=%.d)
UNAME_S = $(shell uname -s)
ifeq ($(UNAME_S),Linux)
LDFLAGS += -pthread -luuid
endif
ifeq ($V, 1)
CXX_PRETTY = $(CXX)
LD_PRETTY = $(CXX)
else
CXX_PRETTY = @echo " [CXX] $<" ; $(CXX)
LD_PRETTY = @echo "[LINK] $@" ; $(CXX)
endif
ALL_TESTS=VariantTest
all: $(ALL_TESTS)
clean:
$(RM) $(ALL_TESTS) $(OBJS) $(DEPS)
VariantTest: VariantTest.cpp ../Variant.cpp
$(CXX) -isystem $(CXXFLAGS) $(LDFLAGS) $^ $(GTEST_DIR)/libgtest.a -o $@
%.o: %.cpp
$(CXX_PRETTY) $(CXXFLAGS) -MMD -c -o $@ $<
%.o: $(GTEST_DIR)/src/%.cc
$(CXX_PRETTY) $(CXXFLAGS) -MMD -c -o $@ $<
#-include $(DEPS)
Unit tests for common. Uses google gtest.
sudo apt-get install libgtest-dev
#include <gtest/gtest.h>
#include <Variant.h>
bool TestVariant_Boolean1()
{
common::Variant v(true);
return v.ToBoolean();
}
bool TestVariant_Boolean2()
{
common::Variant v(false);
return v.ToBoolean();
}
uint8_t TestVariant_UInt8(uint8_t n)
{
common::Variant v(n);
return v.ToUInt8();
}
std::string TestVariant_StdString(std::string const& s)
{
common::Variant v(s);
return v.ToString();
}
TEST(VariantTest, Boolean) {
EXPECT_TRUE(TestVariant_Boolean1());
EXPECT_FALSE(TestVariant_Boolean2());
}
TEST(VariantTest, UInt8) {
EXPECT_EQ(0, TestVariant_UInt8(0));
EXPECT_EQ(10, TestVariant_UInt8(10));
EXPECT_EQ(100, TestVariant_UInt8(100));
EXPECT_EQ(200, TestVariant_UInt8(200));
EXPECT_EQ(std::numeric_limits<uint8_t>::max(), TestVariant_UInt8(std::numeric_limits<uint8_t>::max()));
for (uint8_t n = 0; n < std::numeric_limits<uint8_t>::max(); ++n)
{
EXPECT_EQ(n, TestVariant_UInt8(n));
}
}
TEST(Variant, UInt8Array) {
std::vector<uint8_t> arr;
for (int i = 0; i < 10; ++i)
arr.push_back(i);
common::Variant v1(arr);
EXPECT_EQ(v1.ToUInt8Array(), arr);
EXPECT_EQ(v1.Length(), 10);
EXPECT_TRUE(v1.IsArray());
arr.clear();
arr.push_back(10);
arr.push_back(20);
v1 = arr;
EXPECT_TRUE(v1.IsArray());
EXPECT_EQ(v1.Length(), 2);
std::vector<uint8_t> arr2 = v1.ToUInt8Array();
EXPECT_EQ(arr.size(), arr2.size());
EXPECT_EQ(arr[0], arr2[0]);
EXPECT_EQ(arr[1], arr2[1]);
EXPECT_EQ(std::string("[10,20]"), v1.ToString());
}
TEST(VariantTest, String) {
EXPECT_EQ(std::string("hello world"), TestVariant_StdString("hello world"));
EXPECT_EQ(std::string(""), TestVariant_StdString(""));
EXPECT_EQ(std::string(), TestVariant_StdString(""));
}
#if 0
TEST(VariantTest, StringCopyAssign) {
common::Variant v1;
common::Variant v2;
v1 = "asdf123";
v2 = "asdf123";
EXPECT_EQ(v1.ToString(), v2.ToString());
v2 = "";
EXPECT_NE(v1.ToString(), v2.ToString());
v1 = v2;
EXPECT_EQ(v1.ToString(), v2.ToString());
}
#endif
int main(int argc, char* argv[])
{
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment