diff --git a/Makefile.am b/Makefile.am index 8f692d116..f607814a9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -63,3 +63,12 @@ dist-hook: icinga-version.stamp $(SED) -e 's|^#undef GIT_IS_DIST.*|#define GIT_IS_DIST 1|' \ "icinga-version.h" > "$(distdir)/icinga-version.h"; \ fi + +check-coverage: + lcov -d . -z + make check + lcov -d . -c -o icinga2.info + lcov -e icinga2.info -o icinga2-filtered.info `pwd`\* + mkdir -p docs/lcov + genhtml -o docs/lcov icinga2-filtered.info + diff --git a/configure.ac b/configure.ac index 723c2a02d..5c8d4203a 100644 --- a/configure.ac +++ b/configure.ac @@ -90,8 +90,8 @@ AC_MSG_RESULT($enable_debug) AC_MSG_CHECKING(whether to enable coverage) AC_ARG_ENABLE(coverage, [ --enable-coverage=[no/yes] turn on profiling (default=no)],, enable_coverage=no) if test "x$enable_coverage" = "xyes"; then - CFLAGS="$CFLAGS -g -O0 -fprofile-arcs -ftest-coverage -lgcov" - CXXFLAGS="$CXXFLAGS -g -O0 -fprofile-arcs -ftest-coverage -lgcov" + CFLAGS="$CFLAGS -g -O0 -DNDEBUG -fprofile-arcs -ftest-coverage -lgcov" + CXXFLAGS="$CXXFLAGS -g -O0 -DNDEBUG -fprofile-arcs -ftest-coverage -lgcov" fi AC_MSG_RESULT($enable_coverage) diff --git a/lib/base/array.cpp b/lib/base/array.cpp index fdb175698..cfcd7c826 100644 --- a/lib/base/array.cpp +++ b/lib/base/array.cpp @@ -58,7 +58,9 @@ void Array::Set(unsigned int index, const Value& value) ASSERT(!OwnsLock()); ObjectLock olock(this); - ASSERT(!m_Sealed); + if (m_Sealed) + BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be sealed.")); + m_Data.at(index) = value; } @@ -72,7 +74,9 @@ void Array::Add(const Value& value) ASSERT(!OwnsLock()); ObjectLock olock(this); - ASSERT(!m_Sealed); + if (m_Sealed) + BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be sealed.")); + m_Data.push_back(value); } @@ -127,7 +131,9 @@ void Array::Remove(unsigned int index) ASSERT(!OwnsLock()); ObjectLock olock(this); - ASSERT(!m_Sealed); + if (m_Sealed) + BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be sealed.")); + m_Data.erase(m_Data.begin() + index); } @@ -138,10 +144,11 @@ void Array::Remove(unsigned int index) */ void Array::Remove(Array::Iterator it) { - ASSERT(!OwnsLock()); - ObjectLock olock(this); + ASSERT(OwnsLock()); + + if (m_Sealed) + BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be sealed.")); - ASSERT(!m_Sealed); m_Data.erase(it); } @@ -197,8 +204,7 @@ Array::Ptr Array::FromJson(cJSON *json) { Array::Ptr array = boost::make_shared(); - if (json->type != cJSON_Array) - BOOST_THROW_EXCEPTION(std::invalid_argument("JSON type must be cJSON_Array.")); + ASSERT(json->type == cJSON_Array); for (cJSON *i = json->child; i != NULL; i = i->next) { array->Add(Value::FromJson(i)); diff --git a/lib/base/convert.cpp b/lib/base/convert.cpp index afe6ba7ac..a4edd5ba4 100644 --- a/lib/base/convert.cpp +++ b/lib/base/convert.cpp @@ -38,13 +38,6 @@ bool Convert::ToBool(const String& val) return (ToLong(val) != 0); } -String Convert::ToString(long val) -{ - std::ostringstream cs; - cs << val; - return cs.str(); -} - String Convert::ToString(const Value& val) { return static_cast(val); diff --git a/lib/base/convert.h b/lib/base/convert.h index 45da18f1b..fa40e73e3 100644 --- a/lib/base/convert.h +++ b/lib/base/convert.h @@ -37,7 +37,6 @@ public: static long ToLong(const String& val); static double ToDouble(const String& val); static bool ToBool(const String& val); - static String ToString(long val); static String ToString(const Value& val); private: diff --git a/lib/base/dictionary.cpp b/lib/base/dictionary.cpp index c5cae0a5f..eb72fd6c8 100644 --- a/lib/base/dictionary.cpp +++ b/lib/base/dictionary.cpp @@ -114,7 +114,8 @@ void Dictionary::Set(const String& key, const Value& value) ASSERT(!OwnsLock()); ObjectLock olock(this); - ASSERT(!m_Sealed); + if (m_Sealed) + BOOST_THROW_EXCEPTION(std::invalid_argument("Dictionary must not be sealed.")); std::pair::iterator, bool> ret; ret = m_Data.insert(std::make_pair(key, value)); @@ -193,7 +194,9 @@ void Dictionary::Remove(const String& key) if (it == m_Data.end()) return; - ASSERT(!m_Sealed); + if (m_Sealed) + BOOST_THROW_EXCEPTION(std::invalid_argument("Dictionary must not be sealed.")); + m_Data.erase(it); } @@ -204,10 +207,11 @@ void Dictionary::Remove(const String& key) */ void Dictionary::Remove(Dictionary::Iterator it) { - ASSERT(!OwnsLock()); - ObjectLock olock(this); + ASSERT(OwnsLock()); + + if (m_Sealed) + BOOST_THROW_EXCEPTION(std::invalid_argument("Dictionary must not be sealed.")); - ASSERT(!m_Sealed); m_Data.erase(it); } diff --git a/lib/base/value.cpp b/lib/base/value.cpp index 8e3abe90d..2617fa4a6 100644 --- a/lib/base/value.cpp +++ b/lib/base/value.cpp @@ -33,13 +33,21 @@ Value::Value(void) { } Value::Value(int value) - : m_Value(value) + : m_Value(double(value)) +{ } + +Value::Value(unsigned int value) + : m_Value(double(value)) { } Value::Value(long value) : m_Value(double(value)) { } +Value::Value(unsigned long value) + : m_Value(double(value)) +{ } + Value::Value(double value) : m_Value(value) { } diff --git a/lib/base/value.h b/lib/base/value.h index e786f2719..e5335eeee 100644 --- a/lib/base/value.h +++ b/lib/base/value.h @@ -53,7 +53,9 @@ class I2_BASE_API Value public: Value(void); Value(int value); + Value(unsigned int value); Value(long value); + Value(unsigned long value); Value(double value); Value(const String& value); Value(const char *value); diff --git a/test/base-array.cpp b/test/base-array.cpp index 2d3515dd4..2b46ad877 100644 --- a/test/base-array.cpp +++ b/test/base-array.cpp @@ -53,6 +53,23 @@ BOOST_AUTO_TEST_CASE(getset) BOOST_CHECK(array->Get(1) == 5); } +BOOST_AUTO_TEST_CASE(remove) +{ + Array::Ptr array = boost::make_shared(); + array->Add(7); + array->Add(2); + array->Add(5); + + { + ObjectLock olock(array); + Array::Iterator it = array->Begin(); + array->Remove(it); + } + + BOOST_CHECK(array->GetLength() == 2); + BOOST_CHECK(array->Get(0) == 2); +} + BOOST_AUTO_TEST_CASE(foreach) { Array::Ptr array = boost::make_shared(); @@ -88,4 +105,51 @@ BOOST_AUTO_TEST_CASE(clone) BOOST_CHECK(clone->Get(2) == 5); } +BOOST_AUTO_TEST_CASE(seal) +{ + Array::Ptr array = boost::make_shared(); + array->Add(7); + + BOOST_CHECK(!array->IsSealed()); + array->Seal(); + BOOST_CHECK(array->IsSealed()); + + BOOST_CHECK_THROW(array->Add(2), boost::exception); + BOOST_CHECK(array->GetLength() == 1); + + BOOST_CHECK_THROW(array->Set(0, 8), boost::exception); + BOOST_CHECK(array->Get(0) == 7); + + BOOST_CHECK_THROW(array->Remove(0), boost::exception); + BOOST_CHECK(array->GetLength() == 1); + BOOST_CHECK(array->Get(0) == 7); + + { + ObjectLock olock(array); + Array::Iterator it = array->Begin(); + BOOST_CHECK_THROW(array->Remove(it), boost::exception); + } + + BOOST_CHECK(array->GetLength() == 1); + BOOST_CHECK(array->Get(0) == 7); +} + +BOOST_AUTO_TEST_CASE(serialize) +{ + Array::Ptr array = boost::make_shared(); + array->Add(7); + array->Add(2); + array->Add(5); + + String json = Value(array).Serialize(); + BOOST_CHECK(json.GetLength() > 0); + + Array::Ptr deserialized = Value::Deserialize(json); + BOOST_CHECK(deserialized); + BOOST_CHECK(deserialized->GetLength() == 3); + BOOST_CHECK(deserialized->Get(0) == 7); + BOOST_CHECK(deserialized->Get(1) == 2); + BOOST_CHECK(deserialized->Get(2) == 5); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/test/base-convert.cpp b/test/base-convert.cpp index 3bb283a27..f9438d24e 100644 --- a/test/base-convert.cpp +++ b/test/base-convert.cpp @@ -18,8 +18,10 @@ ******************************************************************************/ #include "base/convert.h" +#include "base/object.h" #include #include +#include using namespace icinga; @@ -28,8 +30,33 @@ BOOST_AUTO_TEST_SUITE(base_convert) BOOST_AUTO_TEST_CASE(tolong) { BOOST_CHECK_THROW(Convert::ToLong(" 7"), boost::exception); - BOOST_CHECK(Convert::ToLong("7") == 7); + BOOST_CHECK(Convert::ToLong("-7") == -7); BOOST_CHECK_THROW(Convert::ToLong("7a"), boost::exception); } +BOOST_AUTO_TEST_CASE(todouble) +{ + BOOST_CHECK_THROW(Convert::ToDouble(" 7.3"), boost::exception); + BOOST_CHECK(Convert::ToDouble("-7.3") == -7.3); + BOOST_CHECK_THROW(Convert::ToDouble("7.3a"), boost::exception); +} + +BOOST_AUTO_TEST_CASE(tostring) +{ + BOOST_CHECK(Convert::ToString(7) == "7"); + BOOST_CHECK(Convert::ToString(7.3) == "7.3"); + BOOST_CHECK(Convert::ToString("hello") == "hello"); + + Object::Ptr object = boost::make_shared(); + BOOST_CHECK(Convert::ToString(object) == "Object of type 'icinga::Object'"); +} + +BOOST_AUTO_TEST_CASE(tobool) +{ + BOOST_CHECK_THROW(Convert::ToBool("a"), boost::exception); + BOOST_CHECK(Convert::ToBool("0") == false); + BOOST_CHECK(Convert::ToBool("1") == true); + BOOST_CHECK(Convert::ToBool("2") == true); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/test/base-dictionary.cpp b/test/base-dictionary.cpp index a05142060..540e4d567 100644 --- a/test/base-dictionary.cpp +++ b/test/base-dictionary.cpp @@ -18,8 +18,11 @@ ******************************************************************************/ #include "base/dictionary.h" +#include "base/objectlock.h" #include #include +#include +#include using namespace icinga; @@ -31,7 +34,7 @@ BOOST_AUTO_TEST_CASE(construct) BOOST_CHECK(dictionary); } -BOOST_AUTO_TEST_CASE(getproperty) +BOOST_AUTO_TEST_CASE(get1) { Dictionary::Ptr dictionary = boost::make_shared(); dictionary->Set("test1", 7); @@ -53,7 +56,7 @@ BOOST_AUTO_TEST_CASE(getproperty) BOOST_CHECK(test3.IsEmpty()); } -BOOST_AUTO_TEST_CASE(getproperty_dict) +BOOST_AUTO_TEST_CASE(get2) { Dictionary::Ptr dictionary = boost::make_shared(); Dictionary::Ptr other = boost::make_shared(); @@ -69,7 +72,41 @@ BOOST_AUTO_TEST_CASE(getproperty_dict) BOOST_CHECK(!test2); } -BOOST_AUTO_TEST_CASE(remove_dict) +BOOST_AUTO_TEST_CASE(foreach) +{ + Dictionary::Ptr dictionary = boost::make_shared(); + dictionary->Set("test1", 7); + dictionary->Set("test2", "hello world"); + + ObjectLock olock(dictionary); + + bool seen_test1 = false, seen_test2 = false; + + String key; + Value value; + BOOST_FOREACH(boost::tie(key, value), dictionary) { + BOOST_CHECK(key == "test1" || key == "test2"); + + if (key == "test1") { + BOOST_CHECK(!seen_test1); + seen_test1 = true; + + BOOST_CHECK(value == 7); + + continue; + } else if (key == "test2") { + BOOST_CHECK(!seen_test2); + seen_test2 = true; + + BOOST_CHECK(value == "hello world"); + } + } + + BOOST_CHECK(seen_test1); + BOOST_CHECK(seen_test2); +} + +BOOST_AUTO_TEST_CASE(remove) { Dictionary::Ptr dictionary = boost::make_shared(); @@ -88,6 +125,85 @@ BOOST_AUTO_TEST_CASE(remove_dict) BOOST_CHECK(!dictionary->Contains("test2")); BOOST_CHECK(dictionary->GetLength() == 0); + + dictionary->Set("test1", 7); + dictionary->Set("test2", "hello world"); + + { + ObjectLock olock(dictionary); + + Dictionary::Iterator it = dictionary->Begin(); + dictionary->Remove(it); + } + + BOOST_CHECK(dictionary->GetLength() == 1); +} + +BOOST_AUTO_TEST_CASE(clone) +{ + Dictionary::Ptr dictionary = boost::make_shared(); + + dictionary->Set("test1", 7); + dictionary->Set("test2", "hello world"); + + Dictionary::Ptr clone = dictionary->ShallowClone(); + + BOOST_CHECK(dictionary != clone); + + BOOST_CHECK(clone->GetLength() == 2); + BOOST_CHECK(clone->Get("test1") == 7); + BOOST_CHECK(clone->Get("test2") == "hello world"); + + clone->Set("test3", 5); + BOOST_CHECK(!dictionary->Contains("test3")); + BOOST_CHECK(dictionary->GetLength() == 2); + + clone->Set("test2", "test"); + BOOST_CHECK(dictionary->Get("test2") == "hello world"); +} + +BOOST_AUTO_TEST_CASE(seal) +{ + Dictionary::Ptr dictionary = boost::make_shared(); + dictionary->Set("test1", 7); + + BOOST_CHECK(!dictionary->IsSealed()); + dictionary->Seal(); + BOOST_CHECK(dictionary->IsSealed()); + + BOOST_CHECK_THROW(dictionary->Set("test2", "hello world"), boost::exception); + BOOST_CHECK(dictionary->GetLength() == 1); + + BOOST_CHECK_THROW(dictionary->Set("test1", 8), boost::exception); + BOOST_CHECK(dictionary->Get("test1") == 7); + + BOOST_CHECK_THROW(dictionary->Remove("test1"), boost::exception); + BOOST_CHECK(dictionary->GetLength() == 1); + BOOST_CHECK(dictionary->Get("test1") == 7); + + { + ObjectLock olock(dictionary); + Dictionary::Iterator it = dictionary->Begin(); + BOOST_CHECK_THROW(dictionary->Remove(it), boost::exception); + } + + BOOST_CHECK(dictionary->GetLength() == 1); + BOOST_CHECK(dictionary->Get("test1") == 7); +} + +BOOST_AUTO_TEST_CASE(serialize) +{ + Dictionary::Ptr dictionary = boost::make_shared(); + + dictionary->Set("test1", 7); + dictionary->Set("test2", "hello world"); + + String json = Value(dictionary).Serialize(); + BOOST_CHECK(json.GetLength() > 0); + Dictionary::Ptr deserialized = Value::Deserialize(json); + BOOST_CHECK(deserialized->GetLength() == 2); + BOOST_CHECK(deserialized->Get("test1") == 7); + BOOST_CHECK(deserialized->Get("test2") == "hello world"); } BOOST_AUTO_TEST_SUITE_END()