Add bundle cpp APIs 30/202430/19
authorhyunho <hhstark.kang@samsung.com>
Thu, 28 Mar 2019 10:42:50 +0000 (19:42 +0900)
committerHwankyu Jhun <h.jhun@samsung.com>
Thu, 4 Apr 2019 02:34:15 +0000 (11:34 +0900)
Change-Id: If49381e60053911d3911ac2eac8062a50a967eee
Signed-off-by: hyunho <hhstark.kang@samsung.com>
Signed-off-by: Junghoon Park <jh9216.park@samsung.com>
14 files changed:
CMakeLists.txt
bundle.pc.in
include/bundle_cpp.h [new file with mode: 0644]
include/bundle_internal.h
packaging/bundle.spec
src/bundle.c
src/bundle_cpp.cc [new file with mode: 0644]
src/bundle_cpp_implementation.h [new file with mode: 0644]
src/keyval.h
src/keyval_array.h
src/keyval_type.h
unit_tests/CMakeLists.txt [new file with mode: 0644]
unit_tests/src/test_bundle.cc [new file with mode: 0644]
unit_tests/src/test_main.cc [new file with mode: 0644]

index 939e00c..631c50f 100644 (file)
@@ -1,34 +1,39 @@
-CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
-PROJECT(bundle C)
-
+CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
+PROJECT(bundle C CXX)
 IF("${VERSION}" STREQUAL "")
-       MESSAGE(FATAL_ERROR "VERSION is not defined")
+       MESSAGE(FATAL_ERROR "VERSION is not defined")
 ENDIF()
 STRING(REGEX MATCH "^[0-9]+" VERSION_MAJOR ${VERSION})
 IF("${VERSION_MAJOR}" STREQUAL "")
-       MESSAGE(FATAL_ERROR "can't get VERSION_MAJOR")
+       MESSAGE(FATAL_ERROR "can't get VERSION_MAJOR")
 ENDIF()
 
-### Required packages
 INCLUDE(FindPkgConfig)
-pkg_check_modules(pkgs REQUIRED glib-2.0 dlog capi-base-common json-glib-1.0)
+pkg_check_modules(pkgs REQUIRED
+       glib-2.0 dlog capi-base-common json-glib-1.0
+)
+
 FOREACH(flag ${pkgs_CFLAGS})
        SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
 ENDFOREACH(flag)
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden -flto -Wall -Werror -Winline")
+
+SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CFLAGS} -std=c++11")
+SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -g")
+SET(CMAKE_CXX_FLAGS_RELEASE "-O2")
 
-set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fvisibility=hidden -flto")
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/include)
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/src)
 
-### Local include directories
-include_directories(${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/src)
+AUX_SOURCE_DIRECTORY(src SOURCES)
 
-### Build
-aux_source_directory(src SRCS)
-add_library(bundle SHARED ${SRCS})
+ADD_LIBRARY (${PROJECT_NAME} SHARED ${SOURCES})
 set_target_properties(bundle PROPERTIES SOVERSION ${VERSION_MAJOR})
 set_target_properties(bundle PROPERTIES VERSION "${VERSION}")
-message(STATUS "Version from debian/changelog: ${VERSION},  Major version: ${VERSION_MAJOR}")
-target_link_libraries(bundle ${pkgs_LDFLAGS})
 
+SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "${EXTRA_CFLAGS} -fPIE")
+SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES LINK_FLAGS "-pie")
+TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_LDFLAGS})
 
 ### Make pkgconfig file
 SET(PREFIX ${CMAKE_INSTALL_PREFIX})
@@ -38,3 +43,13 @@ CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/bundle.pc.in ${CMAKE_BINARY_DIR}/bundle.pc @O
 install(TARGETS bundle DESTINATION ${LIB_INSTALL_DIR})
 install(DIRECTORY ${CMAKE_SOURCE_DIR}/include/ DESTINATION include/)
 install(FILES ${CMAKE_BINARY_DIR}/bundle.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig/)
+
+IF(NOT DEFINED MINIMUM_BUILD)
+ENABLE_TESTING()
+SET(BUNDLE_UNITTESTS bundle_unittests)
+ADD_TEST(NAME ${BUNDLE_UNITTESTS} COMMAND ${BUNDLE_UNITTESTS}
+        WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/unit_tests)
+
+ADD_SUBDIRECTORY(unit_tests)
+ADD_DEPENDENCIES(bundle_unittests bundle)
+ENDIF(NOT DEFINED MINIMUM_BUILD)
index 399ea0b..c05c076 100644 (file)
@@ -11,3 +11,4 @@ Version: @VERSION@
 Requires: capi-base-common
 Libs: -L${libdir} -lbundle
 Cflags: -I${includedir}
+cppflags: -I${includedir}
diff --git a/include/bundle_cpp.h b/include/bundle_cpp.h
new file mode 100644 (file)
index 0000000..2abc522
--- /dev/null
@@ -0,0 +1,335 @@
+/*
+ * Copyright (c) 2019 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 BUNDLE_CPP_H_
+#define BUNDLE_CPP_H_
+
+/**
+ * @file bundle_cpp.h
+ * @brief This file declares API of the bundle C++ library.
+ */
+
+/**
+ * @addtogroup CORE_LIB_BUNDLE_CPP_MODULE
+ * @{
+ */
+
+#include <bundle.h>
+#include <dlog.h>
+
+#include <cstdio>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "BUNDLE"
+
+#ifndef EXPORT_API
+#define EXPORT_API __attribute__((visibility("default")))
+#endif
+
+namespace tizen_base {
+
+/**
+ * @brief The class for bundle APIs.
+ * @since_tizen 5.5
+ */
+class EXPORT_API Bundle final {
+ public:
+  /**
+   * @brief The type for raw bundle.
+   * @since_tizen 5.5
+   */
+  using BundleRaw =
+      std::pair<std::unique_ptr<bundle_raw, decltype(std::free)*>, int>;
+
+  /**
+   * @brief The class for information of keys.
+   * @since_tizen 5.5
+   */
+  class KeyInfo final {
+   public:
+    /**
+     * @brief Constructor.
+     * @since_tizen 5.5
+     * @param[in] handle The handle for type bundle_keyval_t
+     * @param[in] name The key string
+     */
+    KeyInfo(const bundle_keyval_t* handle,  std::string name);
+
+    /**
+     * @brief Constructor.
+     * @since_tizen 5.5
+     */
+    KeyInfo();
+
+    /**
+     * @brief Destructor.
+     * @since_tizen 5.5
+     */
+    ~KeyInfo();
+
+    /**
+     * @brief Copy-constructor.
+     * @since_tizen 5.5
+     * @param[in] b The object to copy
+    */
+    KeyInfo(const KeyInfo& b);
+
+    /**
+     * @brief Assignment.
+     * @since_tizen 5.5
+     * @param[in] b The object to copy
+     */
+    KeyInfo& operator = (const KeyInfo& b);
+
+    /**
+     * @brief Move-constructor.
+     * @since_tizen 5.5
+     * @param[in] b The object to move
+    */
+    KeyInfo(KeyInfo&& b) noexcept;
+
+    /**
+     * @brief Assignment.
+     * @since_tizen 5.5
+     * @param[in] b The object to move
+     */
+    KeyInfo& operator = (KeyInfo&& b) noexcept;
+
+    /**
+     * @brief Gets the type of a key-value pair.
+     * @since_tizen 5.5
+     * @return The type
+     */
+    bundle_type GetType() const;
+
+    /**
+     * @brief Determines whether the type of a key-value pair is an array.
+     * @since_tizen 5.5
+     * @return True when it is an array
+     */
+    bool IsArray() const;
+
+    /**
+     * @brief Gets the key string.
+     * @since_tizen 5.5
+     * @return The key string
+     */
+    const std::string& GetName() const;
+
+   private:
+    class Impl;
+    std::unique_ptr<Impl> impl_;
+  };
+
+  /**
+   * @brief Constructor.
+   * @since_tizen 5.5
+   */
+  Bundle();
+
+  /**
+   * @brief Constructor.
+   * @since_tizen 5.5
+   * @param[in] raw The object for BundleRaw
+   */
+  explicit Bundle(BundleRaw raw);
+
+  /**
+   * @brief Constructor.
+   * @since_tizen 5.5
+   * @param[in] raw The string object for raw bundle
+   */
+  explicit Bundle(const std::string& raw);
+
+  /**
+   * @brief Constructor.
+   * @since_tizen 5.5
+   * @param[in] b The handle for bundle
+   * @param[in] copy True if this object wants to copy it from the handle
+   * @param[in] own True if this object owns the handle
+   */
+  explicit Bundle(bundle* b, bool copy = true, bool own = true);
+
+  /**
+   * @brief Destructor.
+   * @since_tizen 5.5
+   */
+  ~Bundle();
+
+  /**
+   * @brief Copy-constructor.
+   * @since_tizen 5.5
+   * @param[in] b The object to copy
+   */
+  Bundle(const Bundle& b);
+
+  /**
+   * @brief Assignment.
+   * @since_tizen 5.5
+   * @param[in] b The object to copy
+   */
+  Bundle& operator = (const Bundle& b);
+
+  /**
+   * @brief Move-constructor.
+   * @since_tizen 5.5
+   * @param[in] b The object to move
+   */
+  Bundle(Bundle&& b) noexcept;
+
+  /**
+   * @brief Assignment.
+   * @since_tizen 5.5
+   * @param[in] b The object to move
+   */
+  Bundle& operator = (Bundle&& b) noexcept;
+
+  /**
+   * @brief Gets keys in bundle object.
+   * @since_tizen 5.5
+   * @return A string array of object KeyInfo
+  */
+  std::vector<KeyInfo> GetKeys();
+
+  /**
+   * @brief Adds a string type key-value pair into a bundle.
+   * @since_tizen 5.5
+   * @param[in] key The string key
+   * @param[in] val The string value
+   * @return The operation result
+   * @retval BUNDLE_ERROR_NONE Success
+   * @retval BUNDLE_ERROR_INVALID_PARAMETER Invalid parameter
+   * @retval BUNDLE_ERROR_KEY_EXISTS Key already exists
+   * @retval BUNDLE_ERROR_OUT_OF_MEMORY Out of memory
+  */
+  int Add(const std::string& key, const std::string& val);
+
+  /**
+   * @brief Adds a string type key-value pair into a bundle.
+   * @since_tizen 5.5
+   * @param[in] key The string key
+   * @param[in] val The array of strings
+   * @return The operation result
+   * @retval BUNDLE_ERROR_NONE Success
+   * @retval BUNDLE_ERROR_INVALID_PARAMETER Invalid parameter
+   * @retval BUNDLE_ERROR_KEY_EXISTS Key already exists
+   * @retval BUNDLE_ERROR_OUT_OF_MEMORY Out of memory
+  */
+  int Add(const std::string& key, const std::vector<std::string>& val);
+
+  /**
+   * @brief Adds a string type key-value pair into a bundle.
+   * @since_tizen 5.5
+   * @param[in] key The string key
+   * @param[in] val The array of bytes
+   * @return The operation result
+   * @retval BUNDLE_ERROR_NONE Success
+   * @retval BUNDLE_ERROR_INVALID_PARAMETER Invalid parameter
+   * @retval BUNDLE_ERROR_KEY_EXISTS Key already exists
+   * @retval BUNDLE_ERROR_OUT_OF_MEMORY Out of memory
+  */
+  int Add(const std::string& key, const std::vector<unsigned char>& val);
+
+  /**
+   * @brief Deletes a key-value object with the given key.
+   * @since_tizen 5.5
+   * @param[in] key The string key
+   * @return The operation result
+   * @retval BUNDLE_ERROR_NONE Success
+   * @retval BUNDLE_ERROR_INVALID_PARAMETER Invalid parameter
+   * @retval BUNDLE_ERROR_KEY_NOT_AVAILABLE Key not available
+  */
+  int Delete(const std::string& key);
+
+  /**
+   * @brief Gets a string from the key.
+   * @since_tizen 5.5
+   * @param[in] key The string key
+   * @return The string
+  */
+  std::string GetString(const std::string& key) const;
+
+  /**
+   * @brief Gets strings from the key.
+   * @since_tizen 5.5
+   * @param[in] key The string key
+   * @return The array of strings
+  */
+  std::vector<std::string> GetStringArray(const std::string& key) const;
+
+  /**
+   * @brief Gets bytes from the key.
+   * @since_tizen 5.5
+   * @param[in] key The string key
+   * @return Bytes
+  */
+  std::vector<unsigned char> GetByte(const std::string& key) const;
+
+  /**
+   * @brief Converts this object to BundleRaw type.
+   * @since_tizen 5.5
+   * @return The object of BundleRaw
+  */
+  BundleRaw ToRaw();
+
+  /**
+   * @brief Gets the count of keys.
+   * @since_tizen 5.5
+   * @return The count
+  */
+  int GetCount() const;
+
+  /**
+   * @brief Gets the data type from the key.
+   * @since_tizen 5.5
+   * @param[in] key The string key
+   * @return The data type
+  */
+  bundle_type GetType(const std::string& key) const;
+
+  /**
+   * @brief Gets the handle for bundle APIs.
+   * @since_tizen 5.5
+   * @return The handle for bundle
+  */
+  bundle* GetHandle() const;
+
+  /**
+   * @brief Moves this object into the bundle handle.
+   * @since_tizen 5.5
+   * @return The handle for bundle
+  */
+  bundle* Detach();
+
+ private:
+  class Impl;
+  std::unique_ptr<Impl> impl_;
+};
+
+}  // namespace tizen_base
+
+/**
+ * @}
+ */
+
+#endif  // BUNDLE_CPP_H_
index e94db58..8817b13 100755 (executable)
@@ -137,6 +137,16 @@ API void bundle_iterate(bundle *b, bundle_iterate_cb_t callback, void *cb_data);
 API int bundle_keyval_type_is_measurable(bundle_keyval_t *kv);
 
 /**
+ * @brief Duplicate key-value pair.
+ * @since_tizen 5.5
+ * @param[in]  kv      A bundle_keyval_t object
+ * @return     The bundle object
+ * @retval     @c NULL - Failure
+ * @pre                @a kv must be a valid bundle_keyval_t object.
+ */
+API bundle_keyval_t *bundle_keyval_dup(const bundle_keyval_t *kv);
+
+/**
  * @brief Frees the encoded rawdata.
  * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif
  * @param[in]  r       The rawdata
index b84bab0..9b000e9 100644 (file)
@@ -11,6 +11,13 @@ BuildRequires:  pkgconfig(glib-2.0)
 BuildRequires:  pkgconfig(dlog)
 BuildRequires:  pkgconfig(capi-base-common)
 BuildRequires:  pkgconfig(json-glib-1.0)
+BuildRequires:  pkgconfig(gmock)
+
+%if 0%{?gcov:1}
+BuildRequires:  lcov
+BuildRequires:  zip
+%endif
+
 %description
 Simple string key-val dictionary ADT
 
@@ -22,22 +29,73 @@ Requires:   %{name} = %{version}-%{release}
 %description devel
 Simple string key-val dictionary ADT (devel)
 
+#################################################
+# unittests
+#################################################
+%package unittests
+Summary:    GTest for bundle
+Group:      Development/Libraries
+
+%description unittests
+GTest for bundle
+
+#################################################
+# gcov
+#################################################
+%if 0%{?gcov:1}
+%package gcov
+Summary:    Simple string key-val dictionary ADT (gcov)
+Group:      Application Framework/Testing
+
+%description gcov
+Simple string key-val dictionary ADT gcov objects
+%endif
 
 %prep
 %setup -q -n %{name}-%{version}
 cp %{SOURCE1001} .
 
 %build
+%if 0%{?gcov:1}
+export CFLAGS+=" -fprofile-arcs -ftest-coverage"
+export CXXFLAGS+=" -fprofile-arcs -ftest-coverage"
+export FFLAGS+=" -fprofile-arcs -ftest-coverage"
+export LDFLAGS+=" -lgcov"
+%endif
+
 %cmake -DVERSION=%{version} .
 %__make %{?_smp_mflags}
 
+%if 0%{?gcov:1}
+mkdir -p gcov-obj
+find . -name '*.gcno' -exec cp '{}' gcov-obj ';'
+%endif
+
 %install
 %make_install
 
+%if 0%{?gcov:1}
+mkdir -p %{buildroot}%{_datadir}/gcov/obj
+install -m 0644 gcov-obj/* %{buildroot}%{_datadir}/gcov/obj
+%endif
+
+%check
+ctest --output-on-failure %{?_smp_mflags}
+%if 0%{?gcov:1}
+lcov -c --ignore-errors graph --no-external -q -d . -o bundle.info
+genhtml bundle.info -o bundle.out
+zip -r bundle.zip bundle.out
+install -m 0644 bundle.zip %{buildroot}%{_datadir}/gcov/
+%endif
+
 %post -p /sbin/ldconfig
 
 %postun -p /sbin/ldconfig
 
+%post unittests
+%if 0%{?gcov:1}
+%{_bindir}/bundle_unittests
+%endif
 
 %files
 %manifest %{name}.manifest
@@ -51,3 +109,17 @@ cp %{SOURCE1001} .
 %{_includedir}/*.h
 %{_libdir}/pkgconfig/bundle.pc
 %{_libdir}/libbundle.so
+
+#################################################
+# unittests
+#################################################
+%files unittests
+%{_bindir}/bundle_unittests
+
+#################################################
+# bundle-gcov
+#################################################
+%if 0%{?gcov:1}
+%files gcov
+%{_datadir}/gcov/*
+%endif
index f5e6864..2afa47f 100644 (file)
@@ -374,6 +374,40 @@ int bundle_keyval_get_array_val(bundle_keyval_t *kv, void ***array_val,
                        array_val, array_len, array_item_size);
 }
 
+bundle_keyval_t *bundle_keyval_dup(const bundle_keyval_t *kv)
+{
+       bundle_keyval_t *ret_kv = NULL;
+       void *byte = NULL;
+       size_t byte_len;
+       size_t len;
+
+       if (!kv)
+               return NULL;
+
+       if (keyval_type_is_array(kv->type)) {
+               len = keyval_array_encode(
+                       (keyval_array_t *)kv, &byte, &byte_len);
+               if (len == 0)
+                       return NULL;
+               len = keyval_array_decode(byte,
+                       (keyval_array_t **)&ret_kv, byte_len);
+               free(byte);
+               if (len == 0)
+                       return NULL;
+       } else {
+               len = keyval_encode((keyval_t *)kv,
+                       (unsigned char **)&byte, &byte_len);
+               if (len == 0)
+                       return NULL;
+               len = keyval_decode(
+                       (unsigned char *)byte, (keyval_t **)&ret_kv, byte_len);
+               free(byte);
+               if (len == 0)
+                       return NULL;
+       }
+       return ret_kv;
+}
+
 bundle *bundle_dup(bundle *b_from)
 {
        bundle *b_to;
diff --git a/src/bundle_cpp.cc b/src/bundle_cpp.cc
new file mode 100644 (file)
index 0000000..5a5001d
--- /dev/null
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 2019 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 <dlog.h>
+
+#include <memory>
+
+#include "bundle_cpp_implementation.h"
+#include "bundle_cpp.h"
+#include "bundle_internal.h"
+
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "BUNDLE"
+
+namespace tizen_base {
+Bundle::Impl::Impl(Bundle* parent, bool copy, bool own)
+  : copy_(copy), own_(own), parent_(parent) {
+}
+
+Bundle::Impl::Impl(Bundle* parent) : parent_(parent) {
+}
+
+Bundle::Impl::~Impl() = default;
+
+Bundle::Bundle()
+  : impl_(new Impl(this)) {
+  impl_->handle_ = bundle_create();
+}
+
+Bundle::Bundle(BundleRaw raw)
+  : impl_(new Impl(this)) {
+  impl_->handle_ = bundle_decode(raw.first.get(), raw.second);
+}
+
+Bundle::Bundle(const std::string& raw)
+  : impl_(new Impl(this)) {
+  impl_->handle_ = bundle_decode(reinterpret_cast<const bundle_raw*>(
+      raw.c_str()), raw.length());
+}
+
+Bundle::Bundle(bundle* b, bool copy, bool own)
+  : impl_(new Impl(this, copy, own)) {
+  if (!impl_->copy_)
+    impl_->handle_ = b;
+  else
+    impl_->handle_ = bundle_dup(b);
+}
+
+Bundle::~Bundle() {
+  if (impl_->handle_ && (impl_->own_ || impl_->copy_))
+    bundle_free(impl_->handle_);
+}
+
+Bundle::Bundle(const Bundle& b)
+  : impl_(new Impl(this)) {
+  impl_->handle_ = bundle_dup(b.impl_->handle_);
+}
+
+Bundle::KeyInfo::KeyInfo(const bundle_keyval_t* handle, std::string name)
+  : impl_(new Impl(this, handle, std::move(name))) {
+}
+
+Bundle::KeyInfo::KeyInfo()
+  : impl_(new Impl(this)) {
+}
+
+Bundle::KeyInfo::~KeyInfo() {
+}
+
+Bundle::KeyInfo::Impl::~Impl() = default;
+Bundle::KeyInfo::Impl::Impl(Bundle::KeyInfo* parent,
+                            const bundle_keyval_t* handle,
+                            std::string name)
+  : handle_(handle), name_(name), parent_(parent) {
+}
+
+Bundle::KeyInfo::Impl::Impl(Bundle::KeyInfo* parent) : parent_(parent) {
+}
+
+Bundle::KeyInfo::KeyInfo(const KeyInfo& k)
+    : impl_(new Impl(this)) {
+  impl_->handle_ = bundle_keyval_dup(k.impl_->handle_);
+  impl_->name_ = k.impl_->name_;
+}
+
+Bundle::KeyInfo& Bundle::KeyInfo::operator = (const Bundle::KeyInfo& k) {
+  if (this != &k) {
+    impl_->handle_ = bundle_keyval_dup(k.impl_->handle_);
+    impl_->name_ = k.impl_->name_;
+  }
+  return *this;
+}
+
+Bundle::KeyInfo::KeyInfo(Bundle::KeyInfo&& k) noexcept {
+  impl_ = std::unique_ptr<Impl>(new Impl(this));
+  impl_->handle_ = k.impl_->handle_;
+  impl_->name_ = k.impl_->name_;
+  k.impl_->handle_ = nullptr;
+  k.impl_->name_ = "";
+}
+
+Bundle::KeyInfo& Bundle::KeyInfo::operator = (Bundle::KeyInfo&& k) noexcept {
+  if (this != &k) {
+    impl_->handle_ = k.impl_->handle_;
+    impl_->name_ = k.impl_->name_;
+    k.impl_->handle_ = nullptr;
+    k.impl_->name_ = "";
+  }
+  return *this;
+}
+
+bundle_type Bundle::KeyInfo::GetType() const {
+  return static_cast<bundle_type>(
+      bundle_keyval_get_type(const_cast<bundle_keyval_t*>(impl_->handle_)));
+}
+
+bool Bundle::KeyInfo::IsArray() const {
+  return bundle_keyval_type_is_array(const_cast<bundle_keyval_t*>(
+      impl_->handle_));
+}
+
+const std::string& Bundle::KeyInfo::GetName() const {
+  return impl_->name_;
+}
+
+Bundle& Bundle::operator = (const Bundle& b) {
+  if (this != &b) {
+    impl_->handle_ = bundle_dup(b.impl_->handle_);
+  }
+  return *this;
+}
+
+Bundle::Bundle(Bundle&& b) noexcept {
+  impl_ = std::unique_ptr<Impl>(new Impl(this));
+  impl_->handle_ = b.impl_->handle_;
+  b.impl_->handle_ = nullptr;
+}
+
+Bundle& Bundle::operator = (Bundle&& b) noexcept {
+  if (this != &b) {
+    impl_->handle_ = b.impl_->handle_;
+    b.impl_->handle_ = nullptr;
+  }
+  return *this;
+}
+
+std::vector<Bundle::KeyInfo> Bundle::GetKeys() {
+  std::vector<Bundle::KeyInfo> v;
+
+  bundle_foreach(impl_->handle_, [](const char *key, const int type,
+      const bundle_keyval_t *kv, void *user_data) {
+        auto* v = static_cast<std::vector<KeyInfo>*>(user_data);
+        v->emplace_back(kv, key);
+      }, &v);
+
+  return v;
+}
+
+int Bundle::Add(const std::string& key, const std::string& val) {
+  return bundle_add_str(impl_->handle_, key.c_str(), val.c_str());
+}
+
+int Bundle::Add(const std::string& key, const std::vector<std::string>& val) {
+  std::vector<const char*> v;
+  for (auto& i : val) {
+    v.push_back(i.c_str());
+  }
+
+  return bundle_add_str_array(impl_->handle_, key.c_str(), v.data(), v.size());
+}
+
+int Bundle::Add(const std::string& key, const std::vector<unsigned char>& val) {
+  return bundle_add_byte(impl_->handle_, key.c_str(), val.data(), val.size());
+}
+
+int Bundle::Delete(const std::string& key) {
+  return bundle_del(impl_->handle_, key.c_str());
+}
+
+std::string Bundle::GetString(const std::string& key) const {
+  char* str = nullptr;
+  bundle_get_str(impl_->handle_, key.c_str(), &str);
+
+  if (!str)
+    return "";
+
+  return std::string(str);
+}
+
+std::vector<std::string> Bundle::GetStringArray(const std::string& key) const {
+  std::vector<std::string> v;
+
+  const char** str_array = nullptr;
+  int len = 0;
+
+  str_array = bundle_get_str_array(impl_->handle_, key.c_str(), &len);
+
+  for (int i = 0; i < len; i++) {
+    v.emplace_back(str_array[i]);
+  }
+
+  return v;
+}
+
+std::vector<unsigned char> Bundle::GetByte(const std::string& key) const {
+  size_t size;
+  unsigned char* bytes = nullptr;
+  bundle_get_byte(impl_->handle_, key.c_str(),
+      reinterpret_cast<void**>(&bytes), &size);
+  return std::vector<unsigned char>(bytes, bytes + size);
+}
+
+Bundle::BundleRaw Bundle::ToRaw() {
+  bundle_raw* raw = nullptr;
+  int len = 0;
+  bundle_encode(impl_->handle_, &raw, &len);
+
+  return BundleRaw(
+      std::unique_ptr<bundle_raw, decltype(std::free)*>(raw, std::free), len);
+}
+
+int Bundle::GetCount() const {
+  return bundle_get_count(impl_->handle_);
+}
+
+bundle_type Bundle::GetType(const std::string& key) const {
+  return static_cast<bundle_type>(bundle_get_type(impl_->handle_, key.c_str()));
+}
+
+bundle* Bundle::GetHandle() const {
+  return impl_->handle_;
+}
+
+bundle* Bundle::Detach() {
+  auto* h = impl_->handle_;
+  impl_->handle_ = nullptr;
+  return h;
+}
+
+}  // namespace tizen_base
diff --git a/src/bundle_cpp_implementation.h b/src/bundle_cpp_implementation.h
new file mode 100644 (file)
index 0000000..5810f09
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2019 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 BUNDLE_CPP_IMPLEMENTATION_H_
+#define BUNDLE_CPP_IMPLEMENTATION_H_
+
+#include <string>
+#include <memory>
+#include <list>
+
+#include "bundle_cpp.h"
+
+namespace tizen_base {
+
+class Bundle::KeyInfo::Impl {
+ public:
+  virtual ~Impl();
+
+ private:
+  Impl(Bundle::KeyInfo* parent, const bundle_keyval_t* handle,
+       std::string name);
+  explicit Impl(Bundle::KeyInfo* parent);
+
+ private:
+  friend class Bundle::KeyInfo;
+
+ private:
+  const bundle_keyval_t* handle_;
+  std::string name_;
+  Bundle::KeyInfo* parent_;
+};
+
+class Bundle::Impl {
+ public:
+  virtual ~Impl();
+
+ private:
+  explicit Impl(Bundle* parent);
+  Impl(Bundle* parent, bool copy, bool own);
+
+ private:
+  friend class Bundle;
+
+  bundle* handle_;
+  bool copy_ = true;
+  bool own_ = true;
+  Bundle* parent_;
+};
+
+}  // namespace tizen_base
+
+#endif  // BUNDLE_CPP_IMPLEMENTATION_H_
index 1116b6b..bd8441b 100755 (executable)
 
 #include <stddef.h>
 
+#ifdef __cplusplus
+extern "C" {
+# endif
+
 /* ADT: object */
 typedef struct keyval_t keyval_t;
 
@@ -68,4 +72,8 @@ size_t keyval_decode(unsigned char *byte, keyval_t **kv, size_t byte_size);
 int keyval_get_data(keyval_t *kv, int *type, void **val, size_t *size);
 int keyval_get_type_from_encoded_byte(unsigned char *byte);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* __KEYVAL_H__ */
index 510a1c8..dd23946 100755 (executable)
 
 #include "keyval.h"
 
+#ifdef __cplusplus
+extern "C" {
+# endif
+
 typedef struct keyval_array_t {
        struct keyval_t kv; /* Inherits keyval_t */
        unsigned int len; /* length of array_val */
@@ -47,4 +51,8 @@ int keyval_array_set_element(keyval_array_t *kva,
                int idx, void *val, size_t size);
 int keyval_array_is_idx_valid(keyval_array_t *kva, int idx);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* __KEYVAL_ARRAY_H__ */
index 3d9ff15..786cf1c 100755 (executable)
 
 #include "bundle.h"
 
+#ifdef __cplusplus
+extern "C" {
+# endif
+
 /* measure_size function type */
 typedef size_t (*keyval_type_measure_size_func_t) (void *val);
 
@@ -40,4 +44,8 @@ keyval_type_measure_size_func_t keyval_type_get_measure_size_func(int type);
 size_t keyval_type_measure_size_str(void *val);
 void keyval_type_init(void);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* __KEYVAL_TYPE_H__ */
diff --git a/unit_tests/CMakeLists.txt b/unit_tests/CMakeLists.txt
new file mode 100644 (file)
index 0000000..f96ee7e
--- /dev/null
@@ -0,0 +1,37 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
+PROJECT(bundle_unittests C CXX)
+
+INCLUDE(FindPkgConfig)
+pkg_check_modules(bundle_unittests REQUIRED
+    dlog
+    gmock
+    glib-2.0
+    json-glib-1.0
+    capi-base-common
+)
+
+FOREACH(flag ${bundle_unittests_CFLAGS})
+    SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden -Wall -Werror -Winline")
+
+SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CFLAGS} -std=c++11")
+SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -g")
+SET(CMAKE_CXX_FLAGS_RELEASE "-O2")
+
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../)
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../src)
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../include)
+
+AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/src UNITTESTS_SOURCES)
+AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/../src BUNDLE_SOURCES)
+
+ADD_EXECUTABLE(${PROJECT_NAME}
+    ${BUNDLE_SOURCES}
+    ${UNITTESTS_SOURCES}
+)
+
+SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "${EXTRA_CFLAGS}")
+TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${bundle_unittests_LDFLAGS})
+
+INSTALL(TARGETS ${PROJECT_NAME} DESTINATION /usr/bin/)
diff --git a/unit_tests/src/test_bundle.cc b/unit_tests/src/test_bundle.cc
new file mode 100644 (file)
index 0000000..0ac8827
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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 <gtest/gtest.h>
+#include <gmock/gmock.h>
+#include <iostream>
+#include <stdexcept>
+
+#include "bundle_cpp.h"
+
+using ::testing::AtLeast;
+using namespace tizen_base;
+using namespace std;
+
+TEST(Bundle, CtorDtor) {
+  Bundle bundle;
+}
+
+TEST(Bundle, CopyCtor) {
+  Bundle bundle;
+  bundle.Add("TestKey", "TestVal");
+
+  Bundle b2(bundle);
+  EXPECT_EQ(b2.GetString("TestKey"), "TestVal");
+}
+
+TEST(Bundle, MoveCtor) {
+  Bundle bundle;
+  bundle.Add("TestKey", "TestVal");
+
+  Bundle b2(std::move(bundle));
+  EXPECT_EQ(b2.GetString("TestKey"), "TestVal");
+}
+
+TEST(Bundle, AddStringGetString) {
+  Bundle bundle;
+  bundle.Add("TestKey", "TestVal");
+
+  EXPECT_EQ(bundle.GetString("TestKey"), "TestVal");
+}
+
+TEST(Bundle, AddByteGetByte) {
+  Bundle bundle;
+  std::vector<unsigned char> v = { 0, 1, 2, 3};
+  bundle.Add("TestKey", v);
+  auto v2 = bundle.GetByte("TestKey");
+
+  EXPECT_EQ(v2.size(), 4);
+  EXPECT_EQ(v2[0], 0);
+  EXPECT_EQ(v2[1], 1);
+  EXPECT_EQ(v2[2], 2);
+  EXPECT_EQ(v2[3], 3);
+}
+
+TEST(Bundle, AddStringArrayGetStringArray) {
+  Bundle bundle;
+  bundle.Add("TestKey", { "TestVal1", "TestVal2", "TestVal3" });
+
+  auto v = bundle.GetStringArray("TestKey");
+
+  EXPECT_EQ(v.size(), 3);
+  EXPECT_EQ(v[0], "TestVal1");
+  EXPECT_EQ(v[1], "TestVal2");
+  EXPECT_EQ(v[2], "TestVal3");
+}
+
+TEST(Bundle, ToRaw) {
+  Bundle bundle;
+  bundle.Add("TestKey", "TestVal");
+
+  auto r = bundle.ToRaw();
+  Bundle b2(std::move(r));
+  EXPECT_EQ(bundle.GetString("TestKey"), "TestVal");
+}
+
+TEST(Bundle, GetCount) {
+  Bundle bundle;
+  bundle.Add("TestKey1", "TestVal1");
+  bundle.Add("TestKey2", "TestVal2");
+
+  EXPECT_EQ(bundle.GetCount(), 2);
+}
+
+TEST(Bundle, Delete) {
+  Bundle bundle;
+  int r = bundle.Add("TestKey1", "TestVal1");
+  EXPECT_EQ(r, 0);
+
+  r = bundle.Delete("TestKey1");
+  EXPECT_EQ(r, 0);
+
+  EXPECT_EQ(bundle.GetString("TestKey1"), "");
+}
+
+TEST(Bundle, GetKeys) {
+  Bundle bundle;
+  bundle.Add("TestKey1", "TestVal1");
+  bundle.Add("TestKey2", "TestVal2");
+  bundle.Add("TestKey3", "TestVal3");
+
+  auto v = bundle.GetKeys();
+
+  EXPECT_EQ(bundle.GetCount(), 3);
+
+  for (auto& i : v) {
+    EXPECT_EQ(i.GetType(), BUNDLE_TYPE_STR);
+  }
+}
+
+TEST(Bundle, GetKeysCopy) {
+  Bundle bundle;
+  bundle.Add("TestKey1", "TestVal1");
+  bundle.Add("TestKey2", "TestVal2");
+  bundle.Add("TestKey3", "TestVal3");
+
+  auto v = bundle.GetKeys();
+
+  EXPECT_EQ(bundle.GetCount(), 3);
+
+  for (auto& i : v) {
+    Bundle::KeyInfo copied = i;
+    EXPECT_EQ(copied.GetType(), BUNDLE_TYPE_STR);
+    EXPECT_EQ(copied.GetName(), i.GetName());
+  }
+}
+
+TEST(Bundle, GetKeysMove) {
+  Bundle bundle;
+  bundle.Add("TestKey1", "TestVal1");
+  bundle.Add("TestKey2", "TestVal2");
+  bundle.Add("TestKey3", "TestVal3");
+
+  auto v = bundle.GetKeys();
+
+  EXPECT_EQ(bundle.GetCount(), 3);
+
+  for (auto& i : v) {
+    string name = i.GetName();
+    Bundle::KeyInfo copied = move(i);
+    EXPECT_EQ(copied.GetType(), BUNDLE_TYPE_STR);
+    EXPECT_EQ(copied.GetName(), name);
+  }
+}
diff --git a/unit_tests/src/test_main.cc b/unit_tests/src/test_main.cc
new file mode 100644 (file)
index 0000000..df16333
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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 <gtest/gtest.h>
+#include <gmock/gmock.h>
+
+int main(int argc, char** argv) {
+  testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}