Add unit tests 38/244238/6 submit/tizen/20200924.050213 submit/tizen/20201029.023401
authorDaehyeon Jung <darrenh.jung@samsung.com>
Wed, 16 Sep 2020 07:42:28 +0000 (16:42 +0900)
committerDaehyeon Jung <darrenh.jung@samsung.com>
Thu, 24 Sep 2020 04:37:41 +0000 (13:37 +0900)
Change-Id: I286ac76222b2d0532c57a4b17b641f8e10ccb161
Signed-off-by: Daehyeon Jung <darrenh.jung@samsung.com>
CMakeLists.txt
packaging/capi-appfw-preference.spec
unittests/CMakeLists.txt [new file with mode: 0644]
unittests/mock/common_mock.cc [new file with mode: 0644]
unittests/mock/common_mock.h [new file with mode: 0644]
unittests/mock/mock_hook.h [new file with mode: 0644]
unittests/mock/module_mock.h [new file with mode: 0644]
unittests/mock/test_fixture.cc [new file with mode: 0644]
unittests/mock/test_fixture.h [new file with mode: 0644]
unittests/preference_test.cc [new file with mode: 0644]

index dd27bc33939b2772f82b7f32d7d00654a60292fe..919c4a32bcc344af859a6398be629c769dc69965 100644 (file)
@@ -10,3 +10,5 @@ INSTALL(
         PATTERN "*_private.h" EXCLUDE
         PATTERN "${INC_DIR}/*.h"
         )
+
+ADD_SUBDIRECTORY(unittests)
\ No newline at end of file
index 4018c412b15173305657088182a4fe756a95d082..800a9adfb2d68cccff5d2efcfa5a3cb8d9ff339d 100644 (file)
@@ -10,9 +10,14 @@ BuildRequires:  cmake
 BuildRequires:  pkgconfig(dlog)
 BuildRequires:  pkgconfig(sqlite3)
 BuildRequires:  pkgconfig(glib-2.0)
+BuildRequires:  pkgconfig(gmock)
 BuildRequires:  pkgconfig(capi-appfw-app-common)
 BuildRequires:  pkgconfig(capi-base-common)
 BuildRequires:  pkgconfig(libtzplatform-config)
+%if 0%{?gcov:1}
+BuildRequires:  lcov
+BuildRequires:  zip
+%endif
 
 %description
 An Application preference library in Tizen C API
@@ -64,6 +69,17 @@ mkdir -p %{buildroot}%{_datadir}/gcov/obj
 install -m 0644 gcov-obj/* %{buildroot}%{_datadir}/gcov/obj
 %endif
 
+%check
+cd unittests
+LD_LIBRARY_PATH=../src ctest -V
+%if 0%{?gcov:1}
+cd ../src
+lcov -c --ignore-errors graph --no-external -d . -o preference.info
+genhtml preference.info -o preference.out
+zip -r preference.zip preference.out
+install -m 0644 preference.zip %{buildroot}%{_datadir}/gcov/
+%endif
+
 %post -p /sbin/ldconfig
 %postun -p /sbin/ldconfig
 
@@ -85,4 +101,5 @@ install -m 0644 gcov-obj/* %{buildroot}%{_datadir}/gcov/obj
 %if 0%{?gcov:1}
 %files gcov
 %{_datadir}/gcov/obj/*
+%{_datadir}/gcov/preference.zip
 %endif
diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt
new file mode 100644 (file)
index 0000000..93444f8
--- /dev/null
@@ -0,0 +1,20 @@
+AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} TEST_SRCS)
+AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/mock MOCK_SRCS)
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../include/)
+
+ENABLE_TESTING()
+
+SET(TARGET_TEST "preference-test")
+ADD_EXECUTABLE(${TARGET_TEST} ${TEST_SRCS} ${MOCK_SRCS})
+ADD_TEST(${TARGET_TEST} ${TARGET_TEST})
+
+INCLUDE(FindPkgConfig)
+pkg_check_modules(test REQUIRED dlog glib-2.0 capi-appfw-app-common)
+FOREACH(flag ${test_CFLAGS})
+    SET(EXTRA_CXXFLAGS_test "${EXTRA_CXXFLAGS_test} ${flag}")
+ENDFOREACH(flag)
+
+SET(${EXTRA_CXXFLAGS_test} "${EXTRA_CXXFLAGS_test} --std=c++14")
+SET_TARGET_PROPERTIES(${TARGET_TEST} PROPERTIES COMPILE_FLAGS ${EXTRA_CXXFLAGS_test})
+
+TARGET_LINK_LIBRARIES(${TARGET_TEST} gmock capi-appfw-preference pthread)
\ No newline at end of file
diff --git a/unittests/mock/common_mock.cc b/unittests/mock/common_mock.cc
new file mode 100644 (file)
index 0000000..7f4a2c5
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common_mock.h"
+#include "mock_hook.h"
+#include "test_fixture.h"
+
+extern "C" char* app_get_data_path() {
+  return MOCK_HOOK_P0(CommonMock, app_get_data_path);
+}
diff --git a/unittests/mock/common_mock.h b/unittests/mock/common_mock.h
new file mode 100644 (file)
index 0000000..408a7da
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MOCK_COMMON_MOCK_H_
+#define MOCK_COMMON_MOCK_H_
+#include <gmock/gmock.h>
+
+#include "module_mock.h"
+
+class CommonMock : public virtual ModuleMock {
+ public:
+  virtual ~CommonMock() {}
+
+  MOCK_METHOD0(app_get_data_path, char*());
+};
+
+#endif  // MOCK_COMMON_HOOK_H_
diff --git a/unittests/mock/mock_hook.h b/unittests/mock/mock_hook.h
new file mode 100644 (file)
index 0000000..79831d7
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MOCK_MOCK_HOOK_H_
+#define MOCK_MOCK_HOOK_H_
+
+#define MOCK_HOOK_P0(MOCK_CLASS, f)                                            \
+    TestFixture::GetMock<MOCK_CLASS>().f()
+#define MOCK_HOOK_P1(MOCK_CLASS, f, p1)                                        \
+    TestFixture::GetMock<MOCK_CLASS>().f(p1)
+#define MOCK_HOOK_P2(MOCK_CLASS, f, p1, p2)                                    \
+    TestFixture::GetMock<MOCK_CLASS>().f(p1, p2)
+#define MOCK_HOOK_P3(MOCK_CLASS, f, p1, p2, p3)                                \
+    TestFixture::GetMock<MOCK_CLASS>().f(p1, p2, p3)
+#define MOCK_HOOK_P4(MOCK_CLASS, f, p1, p2, p3, p4)                            \
+    TestFixture::GetMock<MOCK_CLASS>().f(p1, p2, p3, p4)
+#define MOCK_HOOK_P5(MOCK_CLASS, f, p1, p2, p3, p4, p5)                        \
+    TestFixture::GetMock<MOCK_CLASS>().f(p1, p2, p3, p4, p5)
+#define MOCK_HOOK_P6(MOCK_CLASS, f, p1, p2, p3, p4, p5, p6)                    \
+    TestFixture::GetMock<MOCK_CLASS>().f(p1, p2, p3, p4, p5, p6)
+#define MOCK_HOOK_P7(MOCK_CLASS, f, p1, p2, p3, p4, p5, p6, p7)                \
+    TestFixture::GetMock<MOCK_CLASS>().f(p1, p2, p3, p4, p5, p6, p7)
+#define MOCK_HOOK_P8(MOCK_CLASS, f, p1, p2, p3, p4, p5, p6, p7, p8)            \
+    TestFixture::GetMock<MOCK_CLASS>().f(p1, p2, p3, p4, p5, p6, p7, p8)
+#define MOCK_HOOK_P10(MOCK_CLASS, f, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10)  \
+    TestFixture::GetMock<MOCK_CLASS>().f(                                      \
+        p1, p2, p3, p4, p5, p6, p7, p8, p9, p10)
+
+#endif  // MOCK_MOCK_HOOK_H_
diff --git a/unittests/mock/module_mock.h b/unittests/mock/module_mock.h
new file mode 100644 (file)
index 0000000..0934014
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MOCK_MODULE_MOCK_H_
+#define MOCK_MODULE_MOCK_H_
+
+class ModuleMock {
+ public:
+  virtual ~ModuleMock() {}
+};
+
+#endif  // MOCK_MODULE_MOCK_H_
diff --git a/unittests/mock/test_fixture.cc b/unittests/mock/test_fixture.cc
new file mode 100644 (file)
index 0000000..4a77054
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <memory>
+
+#include "test_fixture.h"
+
+std::unique_ptr<ModuleMock> TestFixture::mock_;
diff --git a/unittests/mock/test_fixture.h b/unittests/mock/test_fixture.h
new file mode 100644 (file)
index 0000000..db223f1
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MOCK_TEST_FIXTURE_H_
+#define MOCK_TEST_FIXTURE_H_
+
+#include <gtest/gtest.h>
+
+#include <memory>
+#include <stdexcept>
+#include <string>
+#include <utility>
+
+#include "module_mock.h"
+
+class TestFixture : public ::testing::Test {
+ public:
+  explicit TestFixture(std::unique_ptr<ModuleMock>&& mock) {
+    mock_ = std::move(mock);
+  }
+  virtual ~TestFixture() {
+    mock_.reset();
+  }
+
+  virtual void SetUp() {}
+  virtual void TearDown() {}
+
+  template <typename T>
+  static T& GetMock() {
+    auto ptr = dynamic_cast<T*>(mock_.get());
+    if (!ptr)
+      throw std::invalid_argument("The test does not provide mock of \"" +
+          std::string(typeid(T).name()) + "\"");
+    return *ptr;
+  }
+
+  static std::unique_ptr<ModuleMock> mock_;
+};
+
+#endif  // MOCK_TEST_FIXTURE_H_
diff --git a/unittests/preference_test.cc b/unittests/preference_test.cc
new file mode 100644 (file)
index 0000000..5b40e19
--- /dev/null
@@ -0,0 +1,296 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string.h>
+
+#include <functional>
+
+#include <app_preference.h>
+#include <dlog.h>
+#include <glib.h>
+#include <gmock/gmock.h>
+
+#include "mock/common_mock.h"
+#include "mock/test_fixture.h"
+
+extern "C" int __dlog_print(log_id_t log_id, int prio, const char *tag, const char *fmt, ...) {
+  printf("%s:", tag);
+  va_list ap;
+  va_start(ap, fmt);
+  vprintf(fmt, ap);
+  va_end(ap);
+  printf("\n");
+
+  return 0;
+}
+
+namespace preference {
+
+class Mocks : public ::testing::NiceMock<CommonMock> {};
+
+class PreferenceTest : public TestFixture {
+ public:
+  PreferenceTest() : TestFixture(std::make_unique<Mocks>()) {}
+  virtual ~PreferenceTest() {}
+
+  virtual void SetUp() {}
+  virtual void TearDown() {}
+};
+
+TEST_F(PreferenceTest, Basic) {
+  int ret;
+  int intval;
+  double doubleval;
+  char* strval;
+  bool boolval;
+
+  ret = preference_set_int(nullptr, 0);
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_INVALID_PARAMETER));
+  ret = preference_set_double(nullptr, 0.1f);
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_INVALID_PARAMETER));
+  ret = preference_set_string(nullptr, nullptr);
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_INVALID_PARAMETER));
+  ret = preference_set_boolean(nullptr, false);
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_INVALID_PARAMETER));
+  ret = preference_get_int(nullptr, nullptr);
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_INVALID_PARAMETER));
+  ret = preference_get_double(nullptr, nullptr);
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_INVALID_PARAMETER));
+  ret = preference_get_string(nullptr, nullptr);
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_INVALID_PARAMETER));
+  ret = preference_get_boolean(nullptr, nullptr);
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_INVALID_PARAMETER));
+
+  EXPECT_CALL(GetMock<CommonMock>(), app_get_data_path())
+      .WillRepeatedly(testing::Invoke([&]() {
+    return nullptr;
+  }));
+
+  ret = preference_set_int("testint", 0);
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_IO_ERROR));
+  ret = preference_get_int("testint", &intval);
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_IO_ERROR));
+  ret = preference_set_double("testdouble", 0.0f);
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_IO_ERROR));
+  ret = preference_get_double("testdouble", &doubleval);
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_IO_ERROR));
+  ret = preference_set_string("teststring", "test");
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_IO_ERROR));
+  ret = preference_get_string("teststring", &strval);
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_IO_ERROR));
+  ret = preference_set_boolean("testboolean", false);
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_IO_ERROR));
+  ret = preference_get_boolean("testboolean", &boolval);
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_IO_ERROR));
+
+  EXPECT_CALL(GetMock<CommonMock>(), app_get_data_path())
+      .WillRepeatedly(testing::Invoke([&]() {
+    return strdup("../data");
+  }));
+
+  ret = preference_set_int("testint", 1);
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE));
+  ret = preference_get_int("testint", &intval);
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE));
+  EXPECT_THAT(intval, testing::Eq(1));
+  ret = preference_set_double("testdouble", 0.1f);
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE));
+  ret = preference_get_double("testdouble", &doubleval);
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE));
+  EXPECT_THAT(doubleval, testing::Eq(0.1f));
+  ret = preference_set_string("teststring", "test");
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE));
+  ret = preference_get_string("teststring", &strval);
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE));
+  EXPECT_THAT(strval, testing::StrEq("test"));
+  free(strval);
+  ret = preference_set_boolean("testboolean", true);
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE));
+  ret = preference_get_boolean("testboolean", &boolval);
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE));
+  EXPECT_THAT(boolval, testing::Eq(true));
+
+  // cleanup
+  ret = preference_remove_all();
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE));
+}
+
+TEST_F(PreferenceTest, Remove) {
+  EXPECT_CALL(GetMock<CommonMock>(), app_get_data_path())
+      .WillRepeatedly(testing::Invoke([&]() {
+    return strdup("../data");
+  }));
+
+  int ret;
+  bool val;
+  int intval;
+
+  ret = preference_set_int("testint", 1);
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE));
+  ret = preference_get_int("testint", &intval);
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE));
+
+  ret = preference_is_existing("testint", &val);
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE));
+  EXPECT_THAT(val, testing::Eq(true));
+  ret = preference_is_existing("testint2", &val);
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE));
+  EXPECT_THAT(val, testing::Eq(false));
+
+  ret = preference_remove("testint");
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE));
+  ret = preference_is_existing("testint", &val);
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE));
+  EXPECT_THAT(val, testing::Eq(false));
+
+  ret = preference_set_int("testint", 1);
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE));
+  ret = preference_get_int("testint", &intval);
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE));
+  ret = preference_set_int("testint2", 1);
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE));
+  ret = preference_get_int("testint2", &intval);
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE));
+  ret = preference_remove_all();
+  ret = preference_is_existing("testint", &val);
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE));
+  EXPECT_THAT(val, testing::Eq(false));
+  ret = preference_is_existing("testint2", &val);
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE));
+  EXPECT_THAT(val, testing::Eq(false));
+}
+
+TEST_F(PreferenceTest, Foreach) {
+  int ret;
+  ret = preference_set_int("1", 1);
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE));
+  ret = preference_set_int("2", 2);
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE));
+  ret = preference_set_int("3", 3);
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE));
+  ret = preference_set_int("4", 4);
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE));
+
+  int test = 0;
+  ret = preference_foreach_item([](const char* key, void* user_data) -> bool {
+    int* test = reinterpret_cast<int*>(user_data);
+    int val;
+    int ret = preference_get_int(key, &val);
+
+    if (ret != PREFERENCE_ERROR_NONE)
+      return false;
+
+    if (val == (key[0] - '0'))
+      *test = *test + 1;
+
+    return true;
+  }, reinterpret_cast<void*>(&test));
+
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE));
+  EXPECT_THAT(test, testing::Eq(4));
+
+  ret = preference_remove_all();
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE));
+}
+
+TEST_F(PreferenceTest, Type) {
+  int ret;
+
+  ret = preference_set_int("int", 0);
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE));
+  ret = preference_set_string("string", "string");
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE));
+  ret = preference_set_double("double", 0.0f);
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE));
+  ret = preference_set_boolean("boolean", true);
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE));
+
+  preference_type_e type;
+  ret = preference_get_type("int", &type);
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE));
+  EXPECT_THAT(type, testing::Eq(PREFERENCE_TYPE_INT));
+  ret = preference_get_type("double", &type);
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE));
+  EXPECT_THAT(type, testing::Eq(PREFERENCE_TYPE_DOUBLE));
+  ret = preference_get_type("string", &type);
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE));
+  EXPECT_THAT(type, testing::Eq(PREFERENCE_TYPE_STRING));
+  ret = preference_get_type("boolean", &type);
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE));
+  EXPECT_THAT(type, testing::Eq(PREFERENCE_TYPE_BOOLEAN));
+
+  ret = preference_remove_all();
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE));
+}
+
+TEST_F(PreferenceTest, Callback) {
+  int ret;
+
+  ret = preference_set_int("test1", 0);
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE));
+  bool called = false;
+  ret = preference_set_changed_cb("test1", [](const char* key, void* user_data) {
+    bool* called = reinterpret_cast<bool*>(user_data);
+    *called = true;
+  }, reinterpret_cast<bool*>(&called));
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE));
+  EXPECT_THAT(called, testing::Eq(false));
+
+  ret = preference_set_int("test1", 1);
+  g_main_context_iteration(g_main_context_default(), false);
+
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE));
+  EXPECT_THAT(called, testing::Eq(true));
+
+  called = false;
+  ret = preference_unset_changed_cb("test1");
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE));
+
+  ret = preference_set_int("test1", 1);
+  g_main_context_iteration(g_main_context_default(), false);
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE));
+  EXPECT_THAT(called, testing::Eq(false));
+
+  ret = preference_set_changed_cb(nullptr, nullptr, nullptr);
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_INVALID_PARAMETER));
+
+  ret = preference_unset_changed_cb(nullptr);
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_INVALID_PARAMETER));
+
+  ret = preference_remove_all();
+  EXPECT_THAT(ret, testing::Eq(PREFERENCE_ERROR_NONE));
+}
+
+} //  namespace
+
+int main(int argc, char* argv[]) {
+  int ret = 0;
+  try {
+    ::testing::InitGoogleTest(&argc, argv);
+  } catch(...) {
+    std::cout << "Exception occured" << std::endl;
+    return 1;
+  }
+
+  try {
+    return RUN_ALL_TESTS();
+  } catch(const ::testing::internal::GoogleTestFailureException& e) {
+    std::cout << "GoogleTestFailureException occured:" << e.what() << std::endl;
+    ret = 1;
+  }
+
+  return ret;
+}