Commit dd4342db authored by jacobgladish's avatar jacobgladish
Browse files

Fixed some variant bugs. Added unit test.

parent 58b933f8
Loading
Loading
Loading
Loading
+56 −4
Original line number Diff line number Diff line
#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))
+12 −3
Original line number Diff line number Diff line
#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);
+45 −0
Original line number Diff line number Diff line
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)
+5 −0
Original line number Diff line number Diff line

Unit tests for common. Uses google gtest.

sudo apt-get install libgtest-dev
+100 −0
Original line number Diff line number Diff line

#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();
}