Add new apis for app_control_uri 97/201697/19
authorInkyun Kil <inkyun.kil@samsung.com>
Tue, 19 Mar 2019 02:06:31 +0000 (11:06 +0900)
committerHwanKyu Jhun <h.jhun@samsung.com>
Mon, 8 Apr 2019 08:34:07 +0000 (08:34 +0000)
Change-Id: I14ebeb2d1630d9848ec5d65fbb7d8c4cd9b04d6a
Signed-off-by: Inkyun Kil <inkyun.kil@samsung.com>
16 files changed:
AUTHORS [new file with mode: 0644]
CMakeLists.txt
include/app_control.h
include/app_control_uri.h [new file with mode: 0644]
packaging/capi-appfw-app-control.spec
src/CMakeLists.txt
src/app_control.c
src/uri/CMakeLists.txt [new file with mode: 0644]
src/uri/app_control_uri.cc [new file with mode: 0644]
src/uri/uri_internal.cc [new file with mode: 0644]
src/uri/uri_internal.h [new file with mode: 0644]
tools/check-coding-style [new file with mode: 0755]
unit_tests/CMakeLists.txt [new file with mode: 0644]
unit_tests/src/app_control_unittest.cc [new file with mode: 0644]
unit_tests/src/main.cc [new file with mode: 0644]
unit_tests/src/uri_unittest.cc [new file with mode: 0644]

diff --git a/AUTHORS b/AUTHORS
new file mode 100644 (file)
index 0000000..12534b4
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+Junghoon Park <jh9216.park@samsung.com>
index dd27bc33939b2772f82b7f32d7d00654a60292fe..7cae5893f80bb21effdf4a6aa0e7565ba4b535e6 100644 (file)
@@ -10,3 +10,12 @@ INSTALL(
         PATTERN "*_private.h" EXCLUDE
         PATTERN "${INC_DIR}/*.h"
         )
+
+IF(NOT DEFINED MINIMUM_BUILD)
+ENABLE_TESTING()
+SET(UNITTESTS unittests)
+ADD_TEST(NAME ${UNITTESTS} COMMAND ${UNITTESTS}
+    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/unit_tests)
+
+ADD_SUBDIRECTORY(unit_tests)
+ENDIF(NOT DEFINED MINIMUM_BUILD)
index 4750a2b5d0ab9fc62128317b1ea55c53316b8661..cafe27bf60a0e7a75149a9d8c64dba45be59f0e1 100755 (executable)
@@ -20,6 +20,8 @@
 
 #include <tizen.h>
 
+#include <app_control_uri.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -374,6 +376,16 @@ typedef enum {
  */
 #define APP_CONTROL_OPERATION_PRIVACY_SETTING_GUIDE "http://tizen.org/appcontrol/operation/guide_privacy_setting"
 
+/**
+ * @brief Definition for the application control operation: Sends URI.
+ * @details Input: URI, this is a mandatory field.\n
+ *          Input: APP_CONTROL_DATA_URI_FRAGMENT in extra is the fragment of the URI. \n
+ *          Input: APP_CONTROL_DATA_URI_PATH in extra is the path of the URI. \n
+ *          Output: Nothing\n
+ * @since_tizen 5.5
+ */
+#define APP_CONTROL_OPERATION_INTENT "http://tizen.org/appcontrol/operation/intent"
+
 /**
  * @brief Definition for the app_control data: Feature of function name.
  * @since_tizen @if WEARABLE 5.0 @endif
@@ -642,6 +654,17 @@ typedef enum {
  */
 #define APP_CONTROL_DATA_WIDGET_APP_ID "http://tizen.org/appcontrol/data/widget_app_id"
 
+/**
+ * @brief Definition for the fragment data of a URI.
+ * @since_tizen 5.5
+ */
+#define APP_CONTROL_DATA_URI_FRAGMENT "http://tizen.org/appcontrol/data/uri/fragment"
+
+/**
+ * @brief Definition for the path data of a URI.
+ * @since_tizen 5.5
+ */
+#define APP_CONTROL_DATA_URI_PATH "http://tizen.org/appcontrol/data/uri/path"
 
 /**
  * @brief Called when the reply of the launch request is delivered.
@@ -800,6 +823,25 @@ int app_control_create_with_parameters(app_control_h *app_control,
                app_control_launch_mode_e mode, int extra_data_count, ...);
 
 
+/**
+ * @brief Creates an app_control handle from an app_control_uri handle.
+ *
+ * @since_tizen 5.5
+ * @remarks The @a app_control must be released using app_control_destroy().
+ *
+ * @param[out]  app_control             The app_control handle to be newly created on success
+ * @param[in]   uri                     The URI handle
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #APP_CONTROL_ERROR_NONE Successful
+ * @retval #APP_CONTROL_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #APP_CONTROL_ERROR_OUT_OF_MEMORY Out of memory
+ * @see app_control_destroy()
+ */
+int app_control_create_from_uri_handle(app_control_h *app_control,
+               app_control_uri_h uri);
+
+
 /**
  * @brief Destroys the app_control handle and releases all its resources.
  *
@@ -898,6 +940,22 @@ int app_control_set_uri(app_control_h app_control, const char *uri);
 int app_control_get_uri(app_control_h app_control, char **uri);
 
 
+/**
+ * @brief Sets the URI by the app_control_uri handle.
+ *
+ * @since_tizen 5.5
+ * @param[in] app_control The app_control handle
+ * @param[in] uri The URI handle
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #APP_CONTROL_ERROR_NONE Successful
+ * @retval #APP_CONTROL_ERROR_INVALID_PARAMETER Invalid parameter
+ * @see app_control_set_uri()
+ */
+int app_control_set_uri_by_handle(app_control_h app_control,
+               app_control_uri_h uri);
+
+
 /**
  * @brief Sets the explicit MIME type of the data.
  *
diff --git a/include/app_control_uri.h b/include/app_control_uri.h
new file mode 100644 (file)
index 0000000..bb2490c
--- /dev/null
@@ -0,0 +1,430 @@
+/*
+ * 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.
+ */
+
+#ifndef __TIZEN_APPFW_APP_CONTROL_URI_INCLUDE_H__
+#define __TIZEN_APPFW_APP_CONTROL_URI_INCLUDE_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdbool.h>
+#include <tizen_error.h>
+
+/**
+ * @addtogroup CAPI_APP_CONTROL_URI_MODULE
+ * @{
+ */
+
+/**
+ * @brief Enumeration for error codes of the App Control URI submodule.
+ * @since_tizen 5.5
+ */
+typedef enum {
+       APP_CONTROL_URI_ERROR_NONE = TIZEN_ERROR_NONE, /**< Successful */
+       APP_CONTROL_URI_ERROR_IO_ERROR = TIZEN_ERROR_IO_ERROR, /**< Internal I/O error */
+       APP_CONTROL_URI_ERROR_OUT_OF_MEMORY = TIZEN_ERROR_OUT_OF_MEMORY, /**< Out of memory */
+       APP_CONTROL_URI_ERROR_INVALID_PARAMETER = TIZEN_ERROR_INVALID_PARAMETER, /**< Invalid parameter */
+} app_control_uri_error_e;
+
+/**
+ * @brief The URI builder handle.
+ * @since_tizen 5.5
+ */
+typedef void *app_control_uri_builder_h;
+
+/**
+ * @brief The URI handle.
+ * @since_tizen 5.5
+ */
+typedef void *app_control_uri_h;
+
+/**
+ * @brief The query component handle of the URI.
+ * @since_tizen 5.5
+ */
+typedef const void *app_control_uri_query_h;
+
+/**
+ * @brief Creates a URI builder handle.
+ * @since_tizen 5.5
+ *
+ * @remarks The @a handle should be released using app_control_uri_builder_destroy().
+ *
+ * @param[out]  handle                  The URI builder handle
+ *
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #APP_CONTROL_URI_ERROR_NONE Successful
+ * @retval #APP_CONTROL_URI_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #APP_CONTROL_URI_ERROR_OUT_OF_MEMORY Out of memory
+ * @see app_control_uri_builder_destroy()
+ */
+int app_control_uri_builder_create(app_control_uri_builder_h *handle);
+
+/**
+ * @brief Sets the scheme component.
+ * @since_tizen 5.5
+ *
+ * @param[in]   handle                  The URI builder handle
+ * @param[in]   scheme                  The scheme component
+ *
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #APP_CONTROL_URI_ERROR_NONE Successful
+ * @retval #APP_CONTROL_URI_ERROR_INVALID_PARAMETER Invalid parameter
+ */
+int app_control_uri_builder_set_scheme(app_control_uri_builder_h handle,
+               const char *scheme);
+
+/**
+ * @brief Sets the authority component.
+ * @since_tizen 5.5
+ *
+ * @param[in]   handle                  The URI builder handle
+ * @param[in]   auth                    The authority component
+ *
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #APP_CONTROL_URI_ERROR_NONE Successful
+ * @retval #APP_CONTROL_URI_ERROR_INVALID_PARAMETER Invalid parameter
+ */
+int app_control_uri_builder_set_authority(app_control_uri_builder_h handle,
+               const char *auth);
+
+/**
+ * @brief Sets the path component.
+ * @details If the path was already set, it will be replaced with @a path.
+ * @since_tizen 5.5
+ *
+ * @param[in]   handle                  The URI builder handle
+ * @param[in]   path                    The path component
+ *
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #APP_CONTROL_URI_ERROR_NONE Successful
+ * @retval #APP_CONTROL_URI_ERROR_INVALID_PARAMETER Invalid parameter
+ */
+int app_control_uri_builder_set_path(app_control_uri_builder_h handle,
+               const char *path);
+
+/**
+ * @brief Adds the path component.
+ * @details Builder appends @a path component to the path. If @a path doesn't
+ *          start with a '/', builder will prepend the given path with a '/'.
+ * @since_tizen 5.5
+ *
+ * @param[in]   handle                  The URI builder handle
+ * @param[in]   path                    The path component
+ *
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #APP_CONTROL_URI_ERROR_NONE Successful
+ * @retval #APP_CONTROL_URI_ERROR_INVALID_PARAMETER Invalid parameter
+ */
+int app_control_uri_builder_add_path(app_control_uri_builder_h handle,
+               const char *path);
+
+/**
+ * @brief Sets the fragment identifier component.
+ * @since_tizen 5.5
+ *
+ * @param[in]   handle                  The URI builder handle
+ * @param[in]   fragment                The fragment identifier component
+ *
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #APP_CONTROL_URI_ERROR_NONE Successful
+ * @retval #APP_CONTROL_URI_ERROR_INVALID_PARAMETER Invalid parameter
+ */
+int app_control_uri_builder_set_fragment(app_control_uri_builder_h handle,
+               const char *fragment);
+
+/**
+ * @brief Adds the key-value pair attribute of the query component.
+ * @since_tizen 5.5
+ *
+ * @param[in]   handle                  The URI builder handle
+ * @param[in]   key                     The name of the query component key-value pairs
+ * @param[in]   val                     The value associated with the given key
+ *
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #APP_CONTROL_URI_ERROR_NONE Successful
+ * @retval #APP_CONTROL_URI_ERROR_INVALID_PARAMETER Invalid parameter
+ */
+int app_control_uri_builder_add_query(app_control_uri_builder_h handle,
+               const char *key, const char *val);
+
+/**
+ * @brief Creates a URI handle with the attributes set by calling URI builder functions.
+ * @since_tizen 5.5
+ *
+ * @remarks The @a app_control_uri should be released using app_control_uri_destroy().
+ *
+ * @param[in]   builder                 The URI builder handle
+ * @param[out]  app_control_uri         The URI handle
+ *
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #APP_CONTROL_URI_ERROR_NONE Successful
+ * @retval #APP_CONTROL_URI_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #APP_CONTROL_URI_ERROR_OUT_OF_MEMORY Out of memory
+ */
+int app_control_uri_builder_build(app_control_uri_builder_h builder,
+               app_control_uri_h* app_control_uri);
+
+/**
+ * @brief Destroys the URI builder handle.
+ * @since_tizen 5.5
+ *
+ * @param[in]   handle                  The URI builder handle
+ *
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #APP_CONTROL_URI_ERROR_NONE Successful
+ * @retval #APP_CONTROL_URI_ERROR_INVALID_PARAMETER Invalid parameter
+ */
+int app_control_uri_builder_destroy(app_control_uri_builder_h handle);
+
+/**
+ * @brief Creates a URI handle from an encoded URI string.
+ * @since_tizen 5.5
+ *
+ * @remarks The @a handle should be released using app_control_uri_destroy().
+ *
+ * @param[in]   encoded_app_control_uri The encoded URI string
+ * @param[out]  handle                  The URI handle
+ *
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #APP_CONTROL_URI_ERROR_NONE Successful
+ * @retval #APP_CONTROL_URI_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #APP_CONTROL_URI_ERROR_OUT_OF_MEMORY Out of memory
+ * @see app_control_uri_encode()
+ */
+int app_control_uri_create(const char *encoded_app_control_uri,
+               app_control_uri_h *handle);
+
+/**
+ * @brief Destroys the URI handle.
+ * @since_tizen 5.5
+ *
+ * @param[in]   handle                  The URI handle
+ *
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #APP_CONTROL_URI_ERROR_NONE Successful
+ * @retval #APP_CONTROL_URI_ERROR_INVALID_PARAMETER Invalid parameter
+ */
+int app_control_uri_destroy(app_control_uri_h handle);
+
+/**
+ * @brief Encodes the URI handle to string. The string is RFC 3986-compliant.
+ * @since_tizen 5.5
+ *
+ * @remarks The @a encoded_app_control_uri URI string should be released using free().
+ *
+ * @param[in]   handle                  The URI handle
+ * @param[out]  encoded_app_control_uri The encoded URI string
+ *
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #APP_CONTROL_URI_ERROR_NONE Successfully
+ * @retval #APP_CONTROL_URI_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #APP_CONTROL_URI_ERROR_OUT_OF_MEMORY Out of memory
+ */
+int app_control_uri_encode(app_control_uri_h handle,
+               char **encoded_app_control_uri);
+
+/**
+ * @brief Gets the scheme component from a URI handle.
+ * @since_tizen 5.5
+ *
+ * @remarks The @a scheme must not be released. The platform will release it
+ *          when the App Control URI object containing it is released.
+ *
+ * @param[in]   handle                  The URI handle
+ * @param[out]  scheme                  The scheme component
+ *
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #APP_CONTROL_URI_ERROR_NONE Successfully
+ * @retval #APP_CONTROL_URI_ERROR_INVALID_PARAMETER Invalid parameter
+ */
+int app_control_uri_get_scheme(app_control_uri_h handle, const char **scheme);
+
+/**
+ * @brief Gets the authority component from a URI handle.
+ * @since_tizen 5.5
+ *
+ * @remarks The @a authority must not be released. The platform will release it
+ *          when the App Control URI object containing it is released.
+ *
+ * @param[in]   handle                  The URI handle
+ * @param[out]  auth                    The authority component
+ *
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #APP_CONTROL_URI_ERROR_NONE Successfully
+ * @retval #APP_CONTROL_URI_ERROR_INVALID_PARAMETER Invalid parameter
+ */
+int app_control_uri_get_authority(app_control_uri_h handle, const char **auth);
+
+/**
+ * @brief Gets the path component from a URI handle.
+ * @since_tizen 5.5
+ *
+ * @remarks The @a path must not be released. The platform will release it
+ *          when the App Control URI object containing it is released.
+ *
+ * @param[in]   handle                  The URI handle
+ * @param[out]  path                    The path component
+ *
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #APP_CONTROL_URI_ERROR_NONE Successfully
+ * @retval #APP_CONTROL_URI_ERROR_INVALID_PARAMETER Invalid parameter
+ */
+int app_control_uri_get_path(app_control_uri_h handle, const char **path);
+
+/**
+ * @brief Gets the fragment identifier component from a URI handle.
+ * @since_tizen 5.5
+ *
+ * @remarks The @a fragment must not be released. The platform will release it
+ *          when the App Control URI object containing it is released.
+ *
+ * @param[in]   handle                  The URI handle
+ * @param[out]  fragment                The fragment identifier component
+ *
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #APP_CONTROL_URI_ERROR_NONE Successfully
+ * @retval #APP_CONTROL_URI_ERROR_INVALID_PARAMETER Invalid parameter
+ */
+int app_control_uri_get_fragment(app_control_uri_h handle,
+               const char **fragment);
+
+/**
+ * @brief Gets the handle of the query component from a URI handle.
+ * @since_tizen 5.5
+ *
+ * @remarks The @a query_handle will be released by the platform when
+ *          the App Control URI object which contains the query is released.
+ *
+ * @param[in]    handle                 The URI handle
+ * @param[out]   query_handle           The query component handle of the URI
+ *
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #APP_CONTROL_URI_ERROR_NONE Successfully
+ * @retval #APP_CONTROL_URI_ERROR_INVALID_PARAMETER Invalid parameter
+ */
+int app_control_uri_get_query(app_control_uri_h handle,
+               app_control_uri_query_h *query_handle);
+
+/**
+ * @brief Gets the host subcomponent from a URI handle.
+ * @since_tizen 5.5
+ *
+ * @remarks The @a host must not be released. The platform will release it
+ *          when the App Control URI object containing it is released.
+ *
+ * @param[in]    handle                  The URI handle
+ * @param[out]   host                    The host subcomponent of authority
+ *
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #APP_CONTROL_URI_ERROR_NONE Successfully
+ * @retval #APP_CONTROL_URI_ERROR_INVALID_PARAMETER Invalid parameter
+ */
+int app_control_uri_get_host(app_control_uri_h handle, const char **host);
+
+/**
+ * @brief Gets the port subcomponent from a URI handle.
+ * @since_tizen 5.5
+ *
+ * @remarks The @a port must not be released. The platform will release it
+ *          when the App Control URI object containing it is released.
+ *
+ * @param[in]   handle                   The URI handle
+ * @param[out]  port                     The port subcomponent of authority
+ *
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #APP_CONTROL_URI_ERROR_NONE Successfully
+ * @retval #APP_CONTROL_URI_ERROR_INVALID_PARAMETER Invalid parameter
+ */
+int app_control_uri_get_port(app_control_uri_h handle, const char **port);
+
+/**
+ * @brief Gets the user subcomponent from a URI handle.
+ * @since_tizen 5.5
+ *
+ * @remarks The @a user must not be released. The platform will release it
+ *          when the App Control URI object containing it is released.
+ *
+ * @param[in]   handle                  The URI handle
+ * @param[out]  user                    The user subcomponent of authority
+ *
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #APP_CONTROL_URI_ERROR_NONE Successfully
+ * @retval #APP_CONTROL_URI_ERROR_INVALID_PARAMETER Invalid parameter
+ */
+int app_control_uri_get_user(app_control_uri_h handle, const char **user);
+
+/**
+ * @brief Called to retrieve key-value pair attributes contained in the query component.
+ * @since_tizen 5.5
+ *
+ * @param[in]   key                     The name of the query component key-value pairs
+ * @param[in]   val                     The value associated with the given key
+ * @param[in]   user_data               The user data passed from the foreach function
+ *
+ * @return @c true to continue with the next iteration of the loop,
+ *         otherwise @c false to break out of the loop
+ * @see app_control_uri_query_foreach()
+ */
+typedef bool (*app_control_uri_query_foreach_cb)(const char *key,
+               const char *val, void *user_data);
+
+/**
+ * @brief Retrieves key-value pair attributes in the query component.
+ * @since_tizen 5.5
+ *
+ * @param[in]   handle                  The query component handle of the URI
+ * @param[in]   callback                The iteration callback function
+ * @param[in]   user_data               The user data to be passed the callback function
+ *
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #APP_CONTROL_URI_ERROR_NONE Successful
+ * @retval #APP_CONTROL_URI_ERROR_INVALID_PARAMETER Invalid parameter
+ */
+int app_control_uri_query_foreach(app_control_uri_query_h handle,
+               app_control_uri_query_foreach_cb callback, void *user_data);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __TIZEN_APPFW_APP_CONTROL_URI_INCLUDE_H__ */
index a121a453fde2828593a77e5bfd5ad18afae7478b..e61b034e3c2121fc92b06214d9cca4151240820a 100644 (file)
@@ -1,6 +1,6 @@
 Name:       capi-appfw-app-control
 Summary:    App control API
-Version:    0.10.1
+Version:    0.11.0
 Release:    0
 Group:      System/API
 License:    Apache-2.0
@@ -13,6 +13,12 @@ BuildRequires:  pkgconfig(aul)
 BuildRequires:  pkgconfig(capi-base-common)
 BuildRequires:  pkgconfig(appcore-common)
 Recommends:   amd-mod-share
+BuildRequires:  pkgconfig(gmock)
+%if 0%{?gcov:1}
+BuildRequires:  lcov
+BuildRequires:  zip
+%endif
+
 
 %description
 An Application Control library in Tizen C API
@@ -25,31 +31,102 @@ Requires: %{name} = %{version}-%{release}
 %description devel
 An Application Control library in Tizen C API (Development) package.
 
+
+#################################################
+# unittests
+#################################################
+%package -n unittests
+Summary:    GTest for uri
+Group:      Development/Libraries
+Requires:   %{name}
+
+%description -n unittests
+GTest for app_control
+
+#################################################
+# gcov
+#################################################
+%if 0%{?gcov:1}
+%package gcov
+Summary:    app_control(gcov)
+Group:      Application Framework/Testing
+
+%description gcov
+app_control gcov objects
+%endif
+
 %prep
 %setup -q
 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
+
 MAJORVER=`echo %{version} | awk 'BEGIN {FS="."}{print $1}'`
 %cmake . -DFULLVER=%{version} -DMAJORVER=${MAJORVER}
-%__make %{?jobs:-j%jobs}
+%__make %{?_smp_mflags}
+
+%if 0%{?gcov:1}
+mkdir -p gcov-obj
+find . -name '*.gcno' -exec cp '{}' gcov-obj ';'
+%endif
 
 %install
 rm -rf %{buildroot}
 %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 app_control.info
+genhtml app_control.info -o app_control.out
+zip -r app_control.zip app_control.out
+install -m 0644 app_control.zip %{buildroot}%{_datadir}/gcov/app_control.zip
+%endif
+
 %post -p /sbin/ldconfig
 %postun -p /sbin/ldconfig
 
+%post -n unittests
+%if 0%{?gcov:1}
+%{_bindir}/unittests
+%endif
+
 %files
 %manifest %{name}.manifest
 %{_libdir}/libcapi-appfw-app-control.so.*
+%{_libdir}/libcapi-appfw-app-control-uri.so.*
 %license LICENSE
 
 %files devel
 %manifest %{name}.manifest
 %{_includedir}/appfw/app_control.h
 %{_includedir}/appfw/app_control_internal.h
+%{_includedir}/appfw/app_control_uri.h
 %{_libdir}/pkgconfig/capi-appfw-app-control.pc
 %{_libdir}/libcapi-appfw-app-control.so
+%{_libdir}/libcapi-appfw-app-control-uri.so
+
+#################################################
+# unittests
+#################################################
+%files -n unittests
+%{_bindir}/unittests
 
+#################################################
+# uri-gcov
+#################################################
+%if 0%{?gcov:1}
+%files gcov
+%{_datadir}/gcov/*
+%endif
index 5b96b4782c8b5204e6e5cb004eda8e4c443b2993..7abbae7706d981ecd2ab6c5626d542c6ede4587a 100644 (file)
@@ -1,5 +1,6 @@
 CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
 SET(fw_name "capi-appfw-app-control")
+SET(uri_fw_name "capi-appfw-app-control-uri")
 
 PROJECT(${fw_name})
 
@@ -34,7 +35,7 @@ add_library(${fw_name} SHARED
                app_control.c
                )
 
-TARGET_LINK_LIBRARIES(${fw_name} ${${fw_name}_LDFLAGS})
+TARGET_LINK_LIBRARIES(${fw_name} ${${fw_name}_LDFLAGS} ${uri_fw_name})
 
 SET_TARGET_PROPERTIES(${fw_name}
      PROPERTIES
@@ -51,9 +52,10 @@ INSTALL(
         PATTERN "${INC_DIR}/*.h"
         )
 
+
 SET(PC_NAME ${fw_name})
 SET(PC_REQUIRED ${pc_requires})
-SET(PC_LDFLAGS -l${fw_name})
+SET(PC_LDFLAGS -l${fw_name} -l${uri_fw_name})
 
 CONFIGURE_FILE(
     ${CMAKE_SOURCE_DIR}/${fw_name}.pc.in
@@ -61,3 +63,5 @@ CONFIGURE_FILE(
     @ONLY
 )
 INSTALL(FILES ${CMAKE_SOURCE_DIR}/${fw_name}.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig)
+
+ADD_SUBDIRECTORY(uri)
index 62b23e097aaa00dd347d1068c34f133fab66452d..707d1086694e53267f718e2824c7d002d91d9ba4 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 
+#include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
@@ -371,6 +372,121 @@ int app_control_create_with_parameters(app_control_h *app_control,
        return ret;
 }
 
+static bool uri_query_cb(const char *key, const char *val, void *user_data)
+{
+       int ret;
+
+       app_control_h *app_control = (app_control_h *)user_data;
+
+       ret = app_control_add_extra_data(*app_control, key, val);
+       if (ret != APP_CONTROL_ERROR_NONE) {
+               LOGE("app_control_add_extra_data failed: %d[%s,%s]", ret, key, val);
+               return false;
+       }
+
+       return true;
+}
+
+int app_control_create_from_uri_handle(app_control_h *app_control,
+               app_control_uri_h uri)
+{
+       app_control_h tmp_control;
+       const char *scheme;
+       const char *auth;
+       const char *path;
+       const char *fragment;
+       app_control_uri_query_h query;
+       char *uri_str;
+       int uri_str_len = 0;
+       int ret;
+
+       if (app_control == NULL)
+               return app_control_error(APP_CONTROL_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
+
+       ret = app_control_create_request(NULL, &tmp_control);
+       if (ret != APP_CONTROL_ERROR_NONE)
+               return ret;
+
+       ret = app_control_set_operation(tmp_control,
+                       APP_CONTROL_OPERATION_INTENT);
+       if (ret != APP_CONTROL_ERROR_NONE) {
+               app_control_destroy(tmp_control);
+               return ret;
+       }
+
+       ret = app_control_uri_get_scheme(uri, &scheme);
+       if (ret != APP_CONTROL_ERROR_NONE) {
+               app_control_destroy(tmp_control);
+               return ret;
+       }
+
+       ret = app_control_uri_get_authority(uri, &auth);
+       if (ret != APP_CONTROL_ERROR_NONE) {
+               app_control_destroy(tmp_control);
+               return ret;
+       }
+
+       ret = app_control_uri_get_path(uri, &path);
+       if (ret != APP_CONTROL_ERROR_NONE) {
+               app_control_destroy(tmp_control);
+               return ret;
+       }
+
+       ret = app_control_uri_get_fragment(uri, &fragment);
+       if (ret != APP_CONTROL_ERROR_NONE) {
+               app_control_destroy(tmp_control);
+               return ret;
+       }
+
+       ret = app_control_add_extra_data(tmp_control,
+                       APP_CONTROL_DATA_URI_PATH, path);
+       if (ret != APP_CONTROL_ERROR_NONE) {
+               app_control_destroy(tmp_control);
+               return ret;
+       }
+
+       ret = app_control_add_extra_data(tmp_control,
+                       APP_CONTROL_DATA_URI_FRAGMENT, fragment);
+       if (ret != APP_CONTROL_ERROR_NONE) {
+               app_control_destroy(tmp_control);
+               return ret;
+       }
+
+       ret = app_control_uri_get_query(uri, &query);
+       if (ret != APP_CONTROL_ERROR_NONE) {
+               app_control_destroy(tmp_control);
+               return ret;
+       }
+
+       ret = app_control_uri_query_foreach(query, uri_query_cb,
+                       &tmp_control);
+       if (ret != APP_CONTROL_ERROR_NONE) {
+               app_control_destroy(tmp_control);
+               return ret;
+       }
+
+       uri_str_len = strlen(scheme) + strlen(auth) + 2;
+       uri_str = malloc(sizeof(char) * uri_str_len);
+       if (uri_str == NULL) {
+               app_control_destroy(tmp_control);
+               free(uri_str);
+               return app_control_error(APP_CONTROL_ERROR_OUT_OF_MEMORY, __FUNCTION__, NULL);
+       }
+
+       snprintf(uri_str, uri_str_len, "%s:%s", scheme, auth);
+       if (aul_svc_set_uri(tmp_control->data, uri_str) != 0) {
+               app_control_destroy(tmp_control);
+               free(uri_str);
+               return app_control_error(APP_CONTROL_ERROR_IO_ERROR, __FUNCTION__, "invalid URI");
+       }
+
+       free(uri_str);
+
+       *app_control = tmp_control;
+
+       return APP_CONTROL_ERROR_NONE;
+}
+
 int app_control_create_event(bundle *data, struct app_control_s **app_control)
 {
        struct app_control_s *app_control_event;
@@ -513,6 +629,37 @@ int app_control_get_uri(app_control_h app_control, char **uri)
        return APP_CONTROL_ERROR_NONE;
 }
 
+int app_control_set_uri_by_handle(app_control_h app_control, app_control_uri_h uri)
+{
+       const char *scheme;
+       const char *auth;
+       char *uri_str;
+       int uri_str_len = 0;
+
+       if (app_control_validate(app_control))
+               return app_control_error(APP_CONTROL_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
+
+       if (app_control_uri_get_scheme(uri, &scheme))
+               return app_control_error(APP_CONTROL_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
+
+       if (app_control_uri_get_authority(uri, &auth))
+               return app_control_error(APP_CONTROL_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
+
+       uri_str_len = strlen(scheme) + strlen(auth) + 2;
+       uri_str = malloc(sizeof(char) * uri_str_len);
+       if (uri_str == NULL)
+               return app_control_error(APP_CONTROL_ERROR_OUT_OF_MEMORY, __FUNCTION__, NULL);
+
+       snprintf(uri_str, uri_str_len, "%s:%s", scheme, auth);
+       if (aul_svc_set_uri(app_control->data, uri_str) != 0) {
+               free(uri_str);
+               return app_control_error(APP_CONTROL_ERROR_IO_ERROR, __FUNCTION__, "invalid URI");
+       }
+
+       free(uri_str);
+       return APP_CONTROL_ERROR_NONE;
+}
+
 int app_control_set_mime(app_control_h app_control, const char *mime)
 {
        if (app_control_validate(app_control))
diff --git a/src/uri/CMakeLists.txt b/src/uri/CMakeLists.txt
new file mode 100644 (file)
index 0000000..5fff10a
--- /dev/null
@@ -0,0 +1,33 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
+PROJECT(capi-appfw-app-control-uri C CXX)
+
+IF("${FULLVER}" STREQUAL "")
+       MESSAGE(FATAL_ERROR "VERSION is not defined")
+ENDIF()
+STRING(REGEX MATCH "^[0-9]+" VERSION_MAJOR ${FULLVER})
+IF("${VERSION_MAJOR}" STREQUAL "")
+       MESSAGE(FATAL_ERROR "can't get VERSION_MAJOR")
+ENDIF()
+
+### Required packages
+INCLUDE(FindPkgConfig)
+pkg_check_modules(pkgs REQUIRED glib-2.0 dlog)
+FOREACH(flag ${pkgs_CFLAGS})
+       SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fvisibility=hidden -flto")
+SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CFLAGS} -fvisibility=hidden -flto")
+
+### Local include directories
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/src/uri)
+
+### Build
+AUX_SOURCE_DIRECTORY(${CMAKE_SOURCE_DIR}/src/uri SRCS)
+ADD_LIBRARY(capi-appfw-app-control-uri SHARED ${SRCS})
+SET_TARGET_PROPERTIES(capi-appfw-app-control-uri PROPERTIES SOVERSION ${MAJORVER})
+SET_TARGET_PROPERTIES(capi-appfw-app-control-uri PROPERTIES VERSION "${FULLVER}")
+MESSAGE(STATUS "Version from debian/changelog: ${FULLVER},  Major version: ${MAJORVER}")
+TARGET_LINK_LIBRARIES(capi-appfw-app-control-uri ${pkgs_LDFLAGS})
+
+INSTALL(TARGETS capi-appfw-app-control-uri DESTINATION ${LIB_INSTALL_DIR})
diff --git a/src/uri/app_control_uri.cc b/src/uri/app_control_uri.cc
new file mode 100644 (file)
index 0000000..95eb4de
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ * 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 <cstring>
+
+#include "app_control_uri.h"
+#include "uri_internal.h"
+
+#undef URI_API
+#define URI_API extern "C" __attribute__((visibility("default")))
+
+using namespace appcontrol;
+
+URI_API int app_control_uri_builder_create(app_control_uri_builder_h* handle) {
+  if (handle == nullptr)
+    return APP_CONTROL_URI_ERROR_INVALID_PARAMETER;
+  Uri::Builder* builder = new (std::nothrow) Uri::Builder();
+  if (builder == nullptr)
+    return APP_CONTROL_URI_ERROR_OUT_OF_MEMORY;
+  *handle = static_cast<app_control_uri_builder_h>(builder);
+  return APP_CONTROL_URI_ERROR_NONE;
+}
+
+URI_API int app_control_uri_builder_set_scheme(app_control_uri_builder_h handle,
+    const char* scheme) {
+  if (handle == nullptr || scheme == nullptr)
+    return APP_CONTROL_URI_ERROR_INVALID_PARAMETER;
+  auto* builder = static_cast<Uri::Builder*>(handle);
+  builder->SetScheme(scheme);
+  return APP_CONTROL_URI_ERROR_NONE;
+}
+
+URI_API int app_control_uri_builder_set_authority(
+    app_control_uri_builder_h handle, const char* auth) {
+  if (handle == nullptr || auth == nullptr)
+    return APP_CONTROL_URI_ERROR_INVALID_PARAMETER;
+  auto* builder = static_cast<Uri::Builder*>(handle);
+  builder->SetAuthority(auth);
+  return APP_CONTROL_URI_ERROR_NONE;
+}
+
+URI_API int app_control_uri_builder_set_path(app_control_uri_builder_h handle,
+    const char* path) {
+  if (handle == nullptr || path == nullptr)
+    return APP_CONTROL_URI_ERROR_INVALID_PARAMETER;
+  auto* builder = static_cast<Uri::Builder*>(handle);
+  builder->SetPath(path);
+  return APP_CONTROL_URI_ERROR_NONE;
+}
+
+URI_API int app_control_uri_builder_add_path(app_control_uri_builder_h handle,
+    const char* path) {
+  if (handle == nullptr || path == nullptr)
+    return APP_CONTROL_URI_ERROR_INVALID_PARAMETER;
+  auto* builder = static_cast<Uri::Builder*>(handle);
+  builder->AddPath(path);
+  return APP_CONTROL_URI_ERROR_NONE;
+}
+
+URI_API int app_control_uri_builder_set_fragment(
+    app_control_uri_builder_h handle, const char* fragment) {
+  if (handle == nullptr || fragment == nullptr)
+    return APP_CONTROL_URI_ERROR_INVALID_PARAMETER;
+  auto* builder = static_cast<Uri::Builder*>(handle);
+  builder->SetFragment(fragment);
+  return APP_CONTROL_URI_ERROR_NONE;
+}
+
+URI_API int app_control_uri_builder_add_query(app_control_uri_builder_h handle,
+    const char* key, const char* val) {
+  if (handle == nullptr || key == nullptr || val == nullptr)
+    return APP_CONTROL_URI_ERROR_INVALID_PARAMETER;
+  auto* builder = static_cast<Uri::Builder*>(handle);
+  builder->AddQuery(key, val);
+  return APP_CONTROL_URI_ERROR_NONE;
+}
+
+URI_API int app_control_uri_builder_build(app_control_uri_builder_h builder,
+    app_control_uri_h* app_control_uri) {
+  if (builder == nullptr || app_control_uri == nullptr)
+    return APP_CONTROL_URI_ERROR_INVALID_PARAMETER;
+  auto* b = static_cast<Uri::Builder*>(builder);
+  auto* u = new (std::nothrow) Uri(b->Build());
+  if (u == nullptr)
+    return APP_CONTROL_URI_ERROR_OUT_OF_MEMORY;
+  *app_control_uri = static_cast<app_control_uri_h>(u);
+  return APP_CONTROL_URI_ERROR_NONE;
+}
+
+URI_API int app_control_uri_builder_destroy(app_control_uri_builder_h handle) {
+  if (handle == nullptr)
+    return APP_CONTROL_URI_ERROR_INVALID_PARAMETER;
+  auto* builder = static_cast<Uri::Builder*>(handle);
+  delete builder;
+  return APP_CONTROL_URI_ERROR_NONE;
+}
+
+URI_API int app_control_uri_create(const char* encoded_app_control_uri,
+    app_control_uri_h* handle) {
+  if (encoded_app_control_uri == nullptr || handle == nullptr)
+    return APP_CONTROL_URI_ERROR_INVALID_PARAMETER;
+  auto* u = new (std::nothrow) Uri(encoded_app_control_uri);
+  if (u == nullptr)
+    return APP_CONTROL_URI_ERROR_OUT_OF_MEMORY;
+  *handle = static_cast<app_control_uri_h>(u);
+  return APP_CONTROL_URI_ERROR_NONE;
+}
+
+URI_API int app_control_uri_destroy(app_control_uri_h handle) {
+  if (handle == nullptr)
+    return APP_CONTROL_URI_ERROR_INVALID_PARAMETER;
+  auto* app_control_uri = static_cast<Uri*>(handle);
+  delete app_control_uri;
+  return APP_CONTROL_URI_ERROR_NONE;
+}
+
+URI_API int app_control_uri_encode(app_control_uri_h handle,
+    char **encoded_app_control_uri) {
+  if (handle == nullptr)
+    return APP_CONTROL_URI_ERROR_INVALID_PARAMETER;
+  auto* app_control_uri = static_cast<Uri*>(handle);
+  *encoded_app_control_uri = strdup(app_control_uri->Encode().c_str());
+  if (*encoded_app_control_uri == nullptr)
+    return APP_CONTROL_URI_ERROR_OUT_OF_MEMORY;
+
+  return APP_CONTROL_URI_ERROR_NONE;
+}
+
+URI_API int app_control_uri_get_scheme(app_control_uri_h handle,
+    const char **scheme) {
+  if (handle == nullptr)
+    return APP_CONTROL_URI_ERROR_INVALID_PARAMETER;
+  auto* app_control_uri = static_cast<Uri*>(handle);
+  *scheme = app_control_uri->GetScheme().c_str();
+  return APP_CONTROL_URI_ERROR_NONE;
+}
+
+URI_API int app_control_uri_get_authority(app_control_uri_h handle,
+    const char **authority) {
+  if (handle == nullptr)
+    return APP_CONTROL_URI_ERROR_INVALID_PARAMETER;
+  auto* app_control_uri = static_cast<Uri*>(handle);
+  *authority = app_control_uri->GetAuthority().c_str();
+  return APP_CONTROL_URI_ERROR_NONE;
+}
+
+URI_API int app_control_uri_get_path(app_control_uri_h handle,
+    const char **path) {
+  if (handle == nullptr)
+    return APP_CONTROL_URI_ERROR_INVALID_PARAMETER;
+  auto* app_control_uri = static_cast<Uri*>(handle);
+  *path = app_control_uri->GetPath().c_str();
+  return APP_CONTROL_URI_ERROR_NONE;
+}
+
+URI_API int app_control_uri_get_fragment(app_control_uri_h handle,
+    const char **fragment) {
+  if (handle == nullptr)
+    return APP_CONTROL_URI_ERROR_INVALID_PARAMETER;
+  auto* app_control_uri = static_cast<Uri*>(handle);
+  *fragment = app_control_uri->GetFragment().c_str();
+  return APP_CONTROL_URI_ERROR_NONE;
+}
+
+URI_API int app_control_uri_get_query(app_control_uri_h handle,
+    app_control_uri_query_h* query_handle) {
+  if (handle == nullptr || query_handle == nullptr)
+    return APP_CONTROL_URI_ERROR_INVALID_PARAMETER;
+  auto* app_control_uri = static_cast<Uri*>(handle);
+  const auto& ql = app_control_uri->GetQuery();
+  *query_handle = static_cast<app_control_uri_query_h>(&ql);
+  return APP_CONTROL_URI_ERROR_NONE;
+}
+
+URI_API int app_control_uri_get_host(app_control_uri_h handle,
+    const char **host) {
+  if (handle == nullptr)
+    return APP_CONTROL_URI_ERROR_INVALID_PARAMETER;
+  auto* app_control_uri = static_cast<Uri*>(handle);
+  *host = app_control_uri->GetHost().c_str();
+  return APP_CONTROL_URI_ERROR_NONE;
+}
+
+URI_API int app_control_uri_get_port(app_control_uri_h handle,
+    const char **port) {
+  if (handle == nullptr)
+    return APP_CONTROL_URI_ERROR_INVALID_PARAMETER;
+  auto* app_control_uri = static_cast<Uri*>(handle);
+  *port = app_control_uri->GetPort().c_str();
+  return APP_CONTROL_URI_ERROR_NONE;
+}
+
+URI_API int app_control_uri_get_user(app_control_uri_h handle,
+    const char **user) {
+  if (handle == nullptr)
+    return APP_CONTROL_URI_ERROR_INVALID_PARAMETER;
+  auto* app_control_uri = static_cast<Uri*>(handle);
+  *user = app_control_uri->GetUser().c_str();
+  return APP_CONTROL_URI_ERROR_NONE;
+}
+
+URI_API int app_control_uri_query_foreach(app_control_uri_query_h handle,
+    app_control_uri_query_foreach_cb callback,
+    void* data) {
+  if (handle == nullptr || callback == nullptr)
+    return APP_CONTROL_URI_ERROR_INVALID_PARAMETER;
+
+  const auto* ql = static_cast<const std::list<std::pair<std::string,
+      std::string>>*>(handle);
+  for (auto& i : *ql) {
+    if (!callback(i.first.c_str(), i.second.c_str(), data))
+      break;
+  }
+  return APP_CONTROL_URI_ERROR_NONE;
+}
diff --git a/src/uri/uri_internal.cc b/src/uri/uri_internal.cc
new file mode 100644 (file)
index 0000000..5efa30f
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ * 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 <glib.h>
+#include <glib/gi18n.h>
+
+#include <memory>
+
+#include "uri_internal.h"
+
+namespace appcontrol {
+
+Uri::Builder& Uri::Builder::SetScheme(std::string scheme) {
+  scheme_ = std::move(scheme);
+  return *this;
+}
+
+Uri::Builder& Uri::Builder::SetAuthority(std::string auth) {
+  auth_ = std::move(auth);
+  return *this;
+}
+
+Uri::Builder& Uri::Builder::SetPath(std::string path) {
+  path_ = std::move(path);
+  return *this;
+}
+
+Uri::Builder& Uri::Builder::AddPath(std::string path) {
+  if (path[0] != '/')
+    path_ += "/";
+  path_ += path;
+  return *this;
+}
+
+Uri::Builder& Uri::Builder::SetFragment(std::string fragment) {
+  fragment_ = std::move(fragment);
+  return *this;
+}
+
+Uri::Builder& Uri::Builder::AddQuery(std::string key, std::string val) {
+  query_list_.emplace_back(std::move(key), std::move(val));
+  return *this;
+}
+
+Uri Uri::Builder::Build() {
+  return Uri(std::move(scheme_), std::move(auth_), std::move(path_),
+      std::move(query_list_), std::move(fragment_));
+}
+
+Uri::Uri(std::string encoded_uri) {
+  std::unique_ptr<char, decltype(std::free)*> d_uri(
+      g_uri_unescape_string(encoded_uri.c_str(), NULL), std::free);
+  std::string uri(d_uri.get());
+  Parse(uri);
+}
+
+Uri::Uri(std::string scheme, std::string auth, std::string path,
+         std::list<std::pair<std::string, std::string>> query,
+         std::string fragment) :
+    scheme_(std::move(scheme)), auth_(std::move(auth)), path_(std::move(path)),
+    fragment_(std::move(fragment)), query_list_(std::move(query)) {
+  ParseAuthoritySubcomponent(auth_);
+}
+
+const std::string& Uri::GetScheme() const {
+  return scheme_;
+}
+
+const std::string& Uri::GetAuthority() const {
+  return auth_;
+}
+
+const std::string& Uri::GetPath() const {
+  return path_;
+}
+
+const std::string& Uri::GetFragment() const {
+  return fragment_;
+}
+
+const std::list<std::pair<std::string, std::string>>& Uri::GetQuery() const {
+  return query_list_;
+}
+
+const std::string& Uri::GetHost() const {
+  return host_;
+}
+
+const std::string& Uri::GetPort() const {
+  return port_;
+}
+
+const std::string& Uri::GetUser() const {
+  return user_;
+}
+
+std::string Uri::Encode() const {
+  std::unique_ptr<char, decltype(std::free)*> e_scheme(
+      g_uri_escape_string(scheme_.c_str(), NULL, TRUE), std::free);
+  std::unique_ptr<char, decltype(std::free)*> e_auth(
+      g_uri_escape_string(auth_.c_str(), NULL, TRUE), std::free);
+  std::unique_ptr<char, decltype(std::free)*> e_path(
+      g_uri_escape_string(path_.c_str(), NULL, TRUE), std::free);
+  std::unique_ptr<char, decltype(std::free)*> e_fragment(
+      g_uri_escape_string(fragment_.c_str(), NULL, TRUE), std::free);
+
+  std::string ret = e_scheme.get();
+  ret += ":";
+  ret += e_auth.get();
+  ret += e_path.get();
+  bool first = true;
+
+  for (auto& i : query_list_) {
+    std::unique_ptr<char, decltype(std::free)*> key(
+      g_uri_escape_string(i.first.c_str(), NULL, TRUE), std::free);
+    std::unique_ptr<char, decltype(std::free)*> val(
+      g_uri_escape_string(i.second.c_str(), NULL, TRUE), std::free);
+    if (first) {
+      first = false;
+      ret += "?";
+    } else {
+      ret += "&";
+    }
+
+    ret += key.get();
+    ret += "=";
+    ret += val.get();
+  }
+
+  ret += "#";
+  ret += e_fragment.get();
+
+  return ret;
+}
+
+void Uri::Parse(const std::string& uri) {
+  std::size_t idx = 0;
+
+  ParseScheme(uri, idx);
+  ParseAuthority(uri, idx);
+  ParsePath(uri, idx);
+  ParseQuery(uri, idx);
+  ParseFragment(uri, idx);
+}
+
+void Uri::ParseScheme(const std::string& uri, std::size_t& idx) {
+  std::size_t found = uri.find(":");
+  if (found == std::string::npos)
+    return;
+
+  scheme_ = uri.substr(idx, found - idx);
+  idx = found + 1;
+}
+
+void Uri::ParseAuthority(const std::string& uri, std::size_t& idx) {
+  const std::string delim("//");
+  std::size_t found = uri.find(delim, idx);
+  if (found == std::string::npos)
+    return;
+
+  idx = found;
+  found = uri.find("/", idx + delim.length());
+  auth_ = uri.substr(idx, found - idx);
+  idx = found;
+
+  ParseAuthoritySubcomponent(auth_);
+}
+
+void Uri::ParsePath(const std::string& uri, std::size_t& idx) {
+  std::size_t found = uri.find("?", idx);
+  if (found == std::string::npos) {
+    found = uri.find("#", idx);
+    if (found == std::string::npos)
+      found = uri.length();
+  }
+
+  path_ = uri.substr(idx, found - idx);
+  idx = found;
+}
+
+void Uri::ParseQuery(const std::string& uri, std::size_t& idx) {
+  if (idx == uri.length())
+    return;
+
+  std::size_t found = uri.find("?", idx);
+  if (found == std::string::npos)
+    return;
+
+  idx = found;
+  found = uri.find("#", idx);
+  if (found == std::string::npos)
+    found = uri.length();
+
+  std::string query = uri.substr(idx, found - idx);
+  idx = found;
+
+  std::size_t i = query.find("?") + 1;
+  found = query.find("&");
+  while (found != std::string::npos) {
+    AddQuery(query.substr(i, found - i));
+    i = found + 1;
+    found = query.find("&", i);
+  }
+  AddQuery(query.substr(i, found - i));
+}
+
+void Uri::ParseFragment(const std::string& uri, std::size_t& idx) {
+  if (idx == uri.length())
+    return;
+
+  std::size_t found = uri.find("#", idx);
+  if (found == std::string::npos)
+    return;
+
+  idx = found + 1;
+  fragment_ = uri.substr(idx);
+}
+
+void Uri::ParseAuthoritySubcomponent(const std::string& auth) {
+  if (auth.empty())
+    return;
+
+  std::size_t idx = std::string("//").length();
+  std::size_t found = auth.find("@");
+  if (found != std::string::npos) {
+    user_ = auth.substr(idx, found - idx);
+    idx = found + 1;
+  }
+
+  found = auth.find_last_of(":");
+  if (found != std::string::npos && IsNumber(auth.substr(found + 1))) {
+    host_ = auth.substr(idx, found - idx);
+    port_ = auth.substr(found + 1);
+  } else {
+    host_ = auth.substr(idx);
+  }
+}
+
+void Uri::AddQuery(const std::string& query) {
+  std::size_t found = query.find("=");
+  if (found == std::string::npos)
+    return;
+
+  query_list_.emplace_back(query.substr(0, found), query.substr(found + 1));
+}
+
+bool Uri::IsNumber(const std::string& s) {
+  std::string::const_iterator iter = s.begin();
+  while (iter != s.end() && std::isdigit(*iter))
+    iter++;
+
+  return (!s.empty() && iter == s.end());
+}
+
+}  // namespace appcontrol
diff --git a/src/uri/uri_internal.h b/src/uri/uri_internal.h
new file mode 100644 (file)
index 0000000..c896ff4
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * 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.
+ */
+
+#ifndef URI_INTERNAL_H_
+#define URI_INTERNAL_H_
+
+#include <algorithm>
+#include <string>
+#include <list>
+#include <utility>
+
+namespace appcontrol {
+
+class Uri {
+ public:
+  class Builder {
+   public:
+    Builder& SetScheme(std::string scheme);
+    Builder& SetAuthority(std::string auth);
+    Builder& SetPath(std::string path);
+    Builder& AddPath(std::string path);
+    Builder& SetFragment(std::string fragment);
+    Builder& AddQuery(std::string key, std::string val);
+    Uri Build();
+
+   private:
+    std::string scheme_;
+    std::string auth_;
+    std::string path_;
+    std::string fragment_;
+    std::list<std::pair<std::string, std::string>> query_list_;
+  };
+
+  explicit Uri(std::string encoded_uri);
+  virtual ~Uri() {}
+
+  const std::string& GetScheme() const;
+  const std::string& GetAuthority() const;
+  const std::string& GetPath() const;
+  const std::string& GetFragment() const;
+  const std::list<std::pair<std::string, std::string>>& GetQuery() const;
+  const std::string& GetHost() const;
+  const std::string& GetPort() const;
+  const std::string& GetUser() const;
+  std::string Encode() const;
+
+ private:
+  Uri(std::string scheme, std::string auth, std::string path,
+      std::list<std::pair<std::string, std::string>> query,
+      std::string fragment);
+
+  bool IsNumber(const std::string& s);
+  void Parse(const std::string& uri);
+  void ParseScheme(const std::string& uri, std::size_t& idx);
+  void ParseAuthority(const std::string& uri, std::size_t& idx);
+  void ParsePath(const std::string& uri, std::size_t& idx);
+  void ParseQuery(const std::string& uri, std::size_t& idx);
+  void ParseFragment(const std::string& uri, std::size_t& idx);
+  void ParseAuthoritySubcomponent(const std::string& auth);
+  void AddQuery(const std::string& query);
+
+ private:
+  std::string scheme_;
+  std::string auth_;
+  std::string path_;
+  std::string fragment_;
+  std::list<std::pair<std::string, std::string>> query_list_;
+  std::string host_;
+  std::string port_;
+  std::string user_;
+};
+
+}  // namespace appcontrol
+
+#endif  // URI_INTERNAL_H_
diff --git a/tools/check-coding-style b/tools/check-coding-style
new file mode 100755 (executable)
index 0000000..fd60481
--- /dev/null
@@ -0,0 +1,28 @@
+#!/bin/bash
+# Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+if [ ! `which cpplint.py` ]; then
+   echo -e "\nPlease make sure cpplint.py is in your PATH. It is part of depot_tools inside Chromium repository."
+   exit 1
+fi
+
+OLDPWD=$PWD
+BASE=`dirname $0`
+cd $BASE/..
+
+# filters
+FILTERS="-readability/streams,-build/c++11"
+
+cpplint.py --root=src --filter="$FILTERS" $(find . \( -name '*.h' -o -name '*.cc' \) )
+RET=$?
+
+JS_RET_VAL=$?
+cd $OLDPWD
+
+if [ "x$RET" == "x0" ]; then
+  exit 0
+else
+  exit 1
+fi
diff --git a/unit_tests/CMakeLists.txt b/unit_tests/CMakeLists.txt
new file mode 100644 (file)
index 0000000..1941c22
--- /dev/null
@@ -0,0 +1,39 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
+PROJECT(unittests CXX)
+
+INCLUDE(FindPkgConfig)
+pkg_check_modules(unittests REQUIRED
+    glib-2.0
+    gmock
+    aul
+    appcore-common
+)
+
+FOREACH(flag ${unittests_CFLAGS})
+       SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden -Wall -Werror -Winline")
+SET(CMAKE_C_FLAGS "${EXTRA_CFLAGS}")
+
+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(SOURCES
+       ${CMAKE_SOURCE_DIR}/src/app_control.c
+       ${CMAKE_SOURCE_DIR}/src/uri/uri_internal.cc
+       ${CMAKE_SOURCE_DIR}/src/uri/app_control_uri.cc)
+
+INCLUDE_DIRECTORIES(
+       ${CMAKE_CURRENT_SOURCE_DIR}/../include
+       ${CMAKE_CURRENT_SOURCE_DIR}/../src/uri
+       )
+
+AUX_SOURCE_DIRECTORY(src TEST_SOURCES)
+ADD_EXECUTABLE(${PROJECT_NAME}
+       ${SOURCES}
+       ${TEST_SOURCES}
+)
+
+TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${unittests_LDFLAGS})
+
+INSTALL(TARGETS ${PROJECT_NAME} DESTINATION /usr/bin)
diff --git a/unit_tests/src/app_control_unittest.cc b/unit_tests/src/app_control_unittest.cc
new file mode 100644 (file)
index 0000000..059cfef
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * 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 <stdlib.h>
+#include <gtest/gtest.h>
+#include <app_control.h>
+#include <app_control_uri.h>
+
+#include <iostream>
+#include <memory>
+
+#include "uri_internal.h"
+
+// The source of the following example is "https://en.wikipedia.org/wiki/Uniform_Resource_Identifier"
+static const char EXAM_URI1[] = "https://john.doe@www.example.com:123";
+extern int gargc;
+extern char** gargv;
+
+class AppControlTest : public testing::Test {
+ public:
+  virtual ~AppControlTest() {
+    if (builder_ != nullptr)
+      app_control_uri_builder_destroy(builder_);
+    if (uri_ != nullptr)
+      app_control_uri_destroy(uri_);
+  }
+
+  virtual void SetUp() {
+    app_control_uri_builder_create(&builder_);
+    EXPECT_NE(builder_, nullptr);
+
+    app_control_uri_builder_set_scheme(builder_, "https");
+    app_control_uri_builder_set_authority(builder_,
+        "//john.doe@www.example.com:123");
+    app_control_uri_builder_set_path(builder_, "/forum/questions/");
+    app_control_uri_builder_set_fragment(builder_, "top");
+    app_control_uri_builder_add_query(builder_, "tag", "networking");
+    app_control_uri_builder_add_query(builder_, "order", "newest");
+
+    app_control_uri_builder_build(builder_, &uri_);
+    EXPECT_NE(uri_, nullptr);
+  }
+
+  virtual void TearDown() {
+    count_ = 0;
+
+    if (builder_ != nullptr) {
+      auto builder =
+        std::unique_ptr<void, decltype(app_control_uri_builder_destroy)*>(
+          builder_, app_control_uri_builder_destroy);
+      builder_ = nullptr;
+    }
+    if (uri_ != nullptr) {
+      auto uri = std::unique_ptr<void, decltype(app_control_uri_destroy)*>(uri_,
+          app_control_uri_destroy);
+      uri_ = nullptr;
+    }
+  }
+
+  app_control_uri_builder_h builder_;
+  app_control_uri_h uri_;
+  int count_ = 0;
+};
+
+/*
+ * @testcase app_control_create_from_uri_handle_p
+ * @description Creates a app_control handle from uri handle.
+ * @apicovered app_control_create_from_uri_handle
+ */
+TEST_F(AppControlTest, app_control_create_from_uri_handle_p) {
+  app_control_h app_control;
+  char *uri;
+  char *query_tag;
+  int r = app_control_create_from_uri_handle(&app_control, uri_);
+  EXPECT_EQ(r, APP_CONTROL_ERROR_NONE);
+
+  r = app_control_get_uri(app_control, &uri);
+  EXPECT_EQ(r, APP_CONTROL_ERROR_NONE);
+  EXPECT_STREQ(uri, EXAM_URI1);
+
+  r = app_control_get_extra_data(app_control, "tag", &query_tag);
+  EXPECT_EQ(r, APP_CONTROL_ERROR_NONE);
+  EXPECT_STREQ(query_tag, "networking");
+}
+
+/*
+ * @testcase app_control_set_uri_by_handle_p
+ * @description Sets uri data by uri handle.
+ * @apicovered app_control_set_uri_by_handle
+ */
+TEST_F(AppControlTest, app_control_set_uri_by_handle_p) {
+  app_control_h app_control;
+  char *uri;
+  int r = app_control_create(&app_control);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_NONE);
+
+  r = app_control_set_uri_by_handle(app_control, uri_);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_NONE);
+
+  r = app_control_get_uri(app_control, &uri);
+  EXPECT_EQ(r, APP_CONTROL_ERROR_NONE);
+  EXPECT_STREQ(uri, EXAM_URI1);
+}
diff --git a/unit_tests/src/main.cc b/unit_tests/src/main.cc
new file mode 100644 (file)
index 0000000..52fce8d
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * 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 <gtest/gtest.h>
+
+int gargc;
+char** gargv;
+
+int main(int argc, char** argv) {
+  gargc = argc;
+  gargv = argv;
+
+  testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/unit_tests/src/uri_unittest.cc b/unit_tests/src/uri_unittest.cc
new file mode 100644 (file)
index 0000000..f1272dd
--- /dev/null
@@ -0,0 +1,920 @@
+/*
+ * 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 <stdlib.h>
+#include <gtest/gtest.h>
+#include <app_control_uri.h>
+
+#include <iostream>
+#include <memory>
+
+#include "uri_internal.h"
+
+// The source of the following example is "https://en.wikipedia.org/wiki/Uniform_Resource_Identifier"
+static const char EXAM_URI1[] = "https://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top";
+static const char EXAM_URI2[] = "ldap://[2001:db8::7]/c=GB?objectClass?one";
+static const char EXAM_URI3[] = "mailto:John.Doe@example.com";
+static const char EXAM_URI4[] = "news:comp.infosystems.www.servers.unix";
+static const char EXAM_URI5[] = "tel:+1-816-555-1212";
+static const char EXAM_URI6[] = "telnet://192.0.2.16:80/";
+static const char EXAM_URI7[] = "urn:oasis:names:specification:docbook:dtd:xml:4.1.2";
+
+static const char ENCODED_URI1[] = "https:%2F%2Fjohn.doe%40www.example.com%3A123%2Fforum%2Fquestions%2F?tag=networking&order=newest#top";
+static const char ENCODED_URI2[] = "ldap:%2F%2F%5B2001%3Adb8%3A%3A7%5D%2Fc%3DGB?objectClass?one";
+static const char ENCODED_URI3[] = "mailto:John.Doe%40example.com";
+static const char ENCODED_URI4[] = "news:comp.infosystems.www.servers.unix";
+static const char ENCODED_URI5[] = "tel:%2B1-816-555-1212";
+static const char ENCODED_URI6[] = "telnet:%2F%2F192.0.2.16%3A80%2F";
+static const char ENCODED_URI7[] = "urn:oasis%3Anames%3Aspecification%3Adocbook%3Adtd%3Axml%3A4.1.2";
+
+extern int gargc;
+extern char** gargv;
+
+class UriTest : public testing::Test {
+ public:
+  virtual ~UriTest() {
+    if (builder_ != nullptr)
+      app_control_uri_builder_destroy(builder_);
+    if (uri_ != nullptr)
+      app_control_uri_destroy(uri_);
+  }
+
+  virtual void SetUp() {
+    std::string exam_uri[] = {
+      ENCODED_URI1,
+      ENCODED_URI2,
+      ENCODED_URI3,
+      ENCODED_URI4,
+      ENCODED_URI5,
+      ENCODED_URI6,
+      ENCODED_URI7,
+    };
+
+    for (int i = 0; i < 7; i++) {
+      uri_list_[i] =
+        std::unique_ptr<appcontrol::Uri>(new appcontrol::Uri(exam_uri[i]));
+    }
+
+    app_control_uri_builder_create(&builder_);
+    EXPECT_NE(builder_, nullptr);
+
+    app_control_uri_builder_set_scheme(builder_, "https");
+    app_control_uri_builder_set_authority(builder_,
+        "//john.doe@www.example.com:123");
+    app_control_uri_builder_set_path(builder_, "/forum/questions/");
+    app_control_uri_builder_set_fragment(builder_, "top");
+    app_control_uri_builder_add_query(builder_, "tag", "networking");
+    app_control_uri_builder_add_query(builder_, "order", "newest");
+
+    app_control_uri_builder_build(builder_, &uri_);
+    EXPECT_NE(uri_, nullptr);
+  }
+
+  virtual void TearDown() {
+    count_ = 0;
+
+    if (builder_ != nullptr) {
+      auto builder =
+        std::unique_ptr<void, decltype(app_control_uri_builder_destroy)*>(
+          builder_, app_control_uri_builder_destroy);
+      builder_ = nullptr;
+    }
+    if (uri_ != nullptr) {
+      auto uri = std::unique_ptr<void, decltype(app_control_uri_destroy)*>(uri_,
+          app_control_uri_destroy);
+      uri_ = nullptr;
+    }
+  }
+
+  std::unique_ptr<appcontrol::Uri> uri_list_[7];
+  app_control_uri_builder_h builder_;
+  app_control_uri_h uri_;
+  int count_ = 0;
+};
+
+/*
+ * @testcase Uri_Constructor
+ * @description Creates a Uri object.
+ * @apicovered appcontrol::Uri
+ */
+TEST_F(UriTest, Uri_Constructor) {
+  std::unique_ptr<appcontrol::Uri> uri = std::unique_ptr<appcontrol::Uri>(
+      new appcontrol::Uri(ENCODED_URI1));
+  EXPECT_NE(uri, nullptr);
+}
+
+/*
+ * @testcase Uri_GetScheme
+ * @description Gets a scheme component from a URI object.
+ * @apicovered appcontrol::Uri::GetScheme
+ */
+TEST_F(UriTest, Uri_GetScheme) {
+  std::string exam_scheme[] = {
+    "https",
+    "ldap",
+    "mailto",
+    "news",
+    "tel",
+    "telnet",
+    "urn",
+  };
+
+  for (int i = 0; i < 7; i++) {
+    EXPECT_EQ(uri_list_[i]->GetScheme(), exam_scheme[i]);
+  }
+}
+
+/*
+ * @testcase Uri_GetAuthority
+ * @description Gets an authority component from a URI object.
+ * @apicovered appcontrol::Uri::GetAuthority
+ */
+TEST_F(UriTest, Uri_GetAuthority) {
+  std::string exam_auth[] = {
+    "//john.doe@www.example.com:123",
+    "//[2001:db8::7]",
+    "",
+    "",
+    "",
+    "//192.0.2.16:80",
+    "",
+  };
+
+  for (int i = 0; i < 7; i++) {
+    EXPECT_EQ(uri_list_[i]->GetAuthority(), exam_auth[i]);
+  }
+}
+
+/*
+ * @testcase Uri_GetPath
+ * @description Gets a path component from a URI object.
+ * @apicovered appcontrol::Uri::GetPath
+ */
+TEST_F(UriTest, Uri_GetPath) {
+  std::string exam_path[] = {
+    "/forum/questions/",
+    "/c=GB",
+    "John.Doe@example.com",
+    "comp.infosystems.www.servers.unix",
+    "+1-816-555-1212",
+    "/",
+    "oasis:names:specification:docbook:dtd:xml:4.1.2",
+  };
+
+  for (int i = 0; i < 7; i++) {
+    EXPECT_EQ(uri_list_[i]->GetPath(), exam_path[i]);
+  }
+}
+
+/*
+ * @testcase Uri_GetFragment
+ * @description Gets a fragment component from a URI object.
+ * @apicovered appcontrol::Uri::GetFragment
+ */
+TEST_F(UriTest, Uri_GetFragment) {
+  std::string exam_fragment[] = {
+    "top",
+    "",
+    "",
+    "",
+    "",
+    "",
+    "",
+  };
+
+  for (int i = 0; i < 7; i++) {
+    EXPECT_EQ(uri_list_[i]->GetFragment(), exam_fragment[i]);
+  }
+}
+
+/*
+ * @testcase Uri_GetHost
+ * @description Gets a host subcomponent from a URI object.
+ * @apicovered appcontrol::Uri::GetHost
+ */
+TEST_F(UriTest, Uri_GetHost) {
+  std::string exam_host[] = {
+    "www.example.com",
+    "[2001:db8::7]",
+    "",
+    "",
+    "",
+    "192.0.2.16",
+    "",
+  };
+
+  for (int i = 0; i < 7; i++) {
+    EXPECT_EQ(uri_list_[i]->GetHost(), exam_host[i]);
+  }
+}
+
+/*
+ * @testcase Uri_GetPort
+ * @description Gets a port subcomponent from a URI object.
+ * @apicovered appcontrol::Uri::GetPort
+ */
+TEST_F(UriTest, Uri_GetPort) {
+  std::string exam_port[] = {
+    "123",
+    "",
+    "",
+    "",
+    "",
+    "80",
+    "",
+  };
+
+  for (int i = 0; i < 7; i++) {
+    EXPECT_EQ(uri_list_[i]->GetPort(), exam_port[i]);
+  }
+}
+
+/*
+ * @testcase Uri_GetUser
+ * @description Gets a user subcomponent from a URI object.
+ * @apicovered appcontrol::Uri::GetUser
+ */
+TEST_F(UriTest, Uri_GetUser) {
+  std::string exam_user[] = {
+    "john.doe",
+    "",
+    "",
+    "",
+    "",
+    "",
+    "",
+  };
+
+  for (int i = 0; i < 7; i++) {
+    EXPECT_EQ(uri_list_[i]->GetUser(), exam_user[i]);
+  }
+}
+
+/*
+ * @testcase Uri_GetQuery
+ * @description Gets a query component from a URI object.
+ * @apicovered appcontrol::Uri::GetQuery
+ */
+TEST_F(UriTest, Uri_GetQuery) {
+  int match_count = 0;
+  auto& query = uri_list_[0]->GetQuery();
+  for (auto& i : query) {
+    if (i.first == "tag" &&
+        i.second == "networking") {
+      match_count++;
+    } else if (i.first == "order" &&
+               i.second == "newest") {
+      match_count++;
+    }
+  }
+
+  EXPECT_EQ(match_count, 2);
+}
+
+/*
+ * @testcase Uri_Encode
+ * @description Encodes a URI object to string.
+ * @apicovered appcontrol::Uri::Encode
+ */
+TEST_F(UriTest, Uri_Encode) {
+  std::unique_ptr<appcontrol::Uri> uri = std::unique_ptr<appcontrol::Uri>(
+      new appcontrol::Uri(EXAM_URI1));
+  EXPECT_NE(uri, nullptr);
+  EXPECT_EQ(uri->Encode(), ENCODED_URI1);
+}
+
+/*
+ * @testcase Uri_Builder
+ * @description Builds a URI builder object to create a URI object.
+ * @apicovered appcontrol::Uri::Builder, appcontrol::Uri::Builder::SetScheme,
+ *             appcontrol::Uri::Builder::SetAuthority, appcontrol::Uri::Builder::SetPath,
+ *             appcontrol::Uri::Builder::AddQuery, appcontrol::Uri::Builder::SetFragment,
+ *             appcontrol::Uri::Builder::Build
+ */
+TEST_F(UriTest, Uri_Builder) {
+  std::unique_ptr<appcontrol::Uri::Builder> builder(new appcontrol::Uri::Builder());
+  EXPECT_NE(builder, nullptr);
+  builder->SetScheme("https");
+  builder->SetAuthority("//john.doe@www.example.com:123");
+  builder->SetPath("/forum/questions/");
+  builder->AddQuery("tag", "networking");
+  builder->AddQuery("order", "newest");
+  builder->SetFragment("top");
+
+  appcontrol::Uri uri = builder->Build();
+  EXPECT_EQ(uri.Encode(), ENCODED_URI1);
+}
+
+/*
+ * @testcase app_control_uri_builder_create_p
+ * @description Creates a URI builder handle.
+ * @apicovered app_control_uri_builder_create
+ */
+TEST_F(UriTest, app_control_uri_builder_create_p) {
+  app_control_uri_builder_h builder = nullptr;
+  int r = app_control_uri_builder_create(&builder);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_NONE);
+  EXPECT_NE(builder, nullptr);
+  app_control_uri_builder_destroy(builder);
+}
+
+/*
+ * @testcase app_control_uri_builder_create_n
+ * @description Creates a URI builder handle.
+ *              The function returns a negative error value.
+ * @apicovered app_control_uri_builder_create
+ */
+TEST_F(UriTest, app_control_uri_builder_create_n) {
+  int r = app_control_uri_builder_create(nullptr);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_INVALID_PARAMETER);
+}
+
+/*
+ * @testcase app_control_uri_builder_set_scheme_p
+ * @description Sets a scheme component to a URI builder handle.
+ * @apicovered app_control_uri_builder_set_scheme
+ */
+TEST_F(UriTest, app_control_uri_builder_set_scheme_p) {
+  int r = app_control_uri_builder_set_scheme(builder_, "https");
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_NONE);
+}
+
+/*
+ * @testcase app_control_uri_builder_set_scheme_n
+ * @description Sets a scheme component to a URI builder handle.
+ *              The function returns a negative error value.
+ * @apicovered app_control_uri_builder_set_scheme
+ */
+TEST_F(UriTest, app_control_uri_builder_set_scheme_n) {
+  int r = app_control_uri_builder_set_scheme(builder_, nullptr);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_INVALID_PARAMETER);
+
+  r = app_control_uri_builder_set_scheme(nullptr, "https");
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_INVALID_PARAMETER);
+}
+
+/*
+ * @testcase app_control_uri_builder_set_authority_p
+ * @description Sets an authority component to a URI builder handle.
+ * @apicovered app_control_uri_builder_set_authority
+ */
+TEST_F(UriTest, app_control_uri_builder_set_authority_p) {
+  int r = app_control_uri_builder_set_authority(builder_,
+      "//john.doe@www.example.com:123");
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_NONE);
+}
+
+/*
+ * @testcase app_control_uri_builder_set_authority_n
+ * @description Sets an authority component to a URI builder handle.
+ *              The function returns a negative error value.
+ * @apicovered app_control_uri_builder_set_authority
+ */
+TEST_F(UriTest, app_control_uri_builder_set_authority_n) {
+  int r = app_control_uri_builder_set_authority(builder_, nullptr);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_INVALID_PARAMETER);
+
+  r = app_control_uri_builder_set_authority(nullptr,
+      "//john.doe@www.example.com:123");
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_INVALID_PARAMETER);
+}
+
+/*
+ * @testcase app_control_uri_builder_set_path_p
+ * @description Sets a path component to a URI builder handle.
+ * @apicovered app_control_uri_builder_set_path
+ */
+TEST_F(UriTest, app_control_uri_builder_set_path_p) {
+  int r = app_control_uri_builder_set_path(builder_, "/forum/questions/");
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_NONE);
+}
+
+/*
+ * @testcase app_control_uri_builder_set_path_n
+ * @description Sets a path component to a URI builder handle.
+ *              The function returns a negative error value.
+ * @apicovered app_control_uri_builder_set_path
+ */
+TEST_F(UriTest, app_control_uri_builder_set_path_n) {
+  int r = app_control_uri_builder_set_path(builder_, nullptr);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_INVALID_PARAMETER);
+
+  r = app_control_uri_builder_set_path(nullptr, "/forum/questions/");
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_INVALID_PARAMETER);
+}
+
+/*
+ * @testcase app_control_uri_builder_add_path_p
+ * @description Adds a path component on a URI builder handle.
+ * @apicovered app_control_uri_builder_add_path
+ */
+TEST_F(UriTest, app_control_uri_builder_add_path_p) {
+  int r = app_control_uri_builder_add_path(builder_, "/forum");
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_NONE);
+
+  r = app_control_uri_builder_add_path(builder_, "/questions/");
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_NONE);
+}
+
+/*
+ * @testcase app_control_uri_builder_add_path_n
+ * @description Adds a path component on a URI builder handle.
+ *              The function returns a negative error value.
+ * @apicovered app_control_uri_builder_add_path
+ */
+TEST_F(UriTest, app_control_uri_builder_add_path_n) {
+  int r = app_control_uri_builder_add_path(builder_, nullptr);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_INVALID_PARAMETER);
+
+  r = app_control_uri_builder_add_path(nullptr, "/questions/");
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_INVALID_PARAMETER);
+}
+
+/*
+ * @testcase app_control_uri_builder_set_fragment_p
+ * @description Sets a fragment component to a URI builder handle.
+ * @apicovered app_control_uri_builder_set_fragment
+ */
+TEST_F(UriTest, app_control_uri_builder_set_fragment_p) {
+  int r = app_control_uri_builder_set_fragment(builder_, "top");
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_NONE);
+}
+
+/*
+ * @testcase app_control_uri_builder_set_fragment_n
+ * @description Sets a fragment component to a URI builder handle.
+ *              The function returns a negative error value.
+ * @apicovered app_control_uri_builder_set_fragment
+ */
+TEST_F(UriTest, app_control_uri_builder_set_fragment_n) {
+  int r = app_control_uri_builder_set_fragment(builder_, nullptr);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_INVALID_PARAMETER);
+
+  r = app_control_uri_builder_set_fragment(nullptr, "top");
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_INVALID_PARAMETER);
+}
+
+/*
+ * @testcase app_control_uri_builder_add_query_p
+ * @description Adds a query component on a URI builder handle.
+ * @apicovered app_control_uri_builder_add_query
+ */
+TEST_F(UriTest, app_control_uri_builder_add_query_p) {
+  int r = app_control_uri_builder_add_query(builder_, "tag", "networking");
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_NONE);
+
+  r = app_control_uri_builder_add_query(builder_, "order", "newest");
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_NONE);
+}
+
+/*
+ * @testcase app_control_uri_builder_add_query_n
+ * @description Adds a query component on a URI builder handle.
+ *              The function returns a negative error value.
+ * @apicovered app_control_uri_builder_add_query
+ */
+TEST_F(UriTest, app_control_uri_builder_add_query_n) {
+  int r = app_control_uri_builder_add_query(builder_, "tag", nullptr);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_INVALID_PARAMETER);
+
+  r = app_control_uri_builder_add_query(builder_, nullptr, "newest");
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_INVALID_PARAMETER);
+
+  r = app_control_uri_builder_add_query(nullptr, "tag", "newest");
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_INVALID_PARAMETER);
+}
+
+/*
+ * @testcase app_control_uri_builder_build_p
+ * @description Builds a URI builder handle to create a URI handle.
+ * @apicovered app_control_uri_builder_build
+ */
+TEST_F(UriTest, app_control_uri_builder_build_p) {
+  app_control_uri_h app_control_uri = nullptr;
+  int r = app_control_uri_builder_build(builder_, &app_control_uri);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_NONE);
+  EXPECT_NE(app_control_uri, nullptr);
+  app_control_uri_destroy(app_control_uri);
+}
+
+/*
+ * @testcase app_control_uri_builder_build_n
+ * @description Builds a URI builder handle to create a URI handle.
+ *              The function returns a negative error value.
+ * @apicovered app_control_uri_builder_build
+ */
+TEST_F(UriTest, app_control_uri_builder_build_n) {
+  int r = app_control_uri_builder_build(builder_, nullptr);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_INVALID_PARAMETER);
+
+  app_control_uri_h app_control_uri = nullptr;
+  r = app_control_uri_builder_build(nullptr, &app_control_uri);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_INVALID_PARAMETER);
+}
+
+/*
+ * @testcase app_control_uri_builder_destroy_p
+ * @description Destroys a URI builder handle.
+ * @apicovered app_control_uri_builder_destroy
+ */
+TEST_F(UriTest, app_control_uri_builder_destroy_p) {
+  int r = app_control_uri_builder_destroy(builder_);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_NONE);
+  builder_ = nullptr;
+}
+
+/*
+ * @testcase app_control_uri_builder_destroy_n
+ * @description Destroys a URI builder handle.
+ *              The function returns a negative error value.
+ * @apicovered app_control_uri_builder_destroy
+ */
+TEST_F(UriTest, app_control_uri_builder_destroy_n) {
+  int r = app_control_uri_builder_destroy(nullptr);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_INVALID_PARAMETER);
+}
+
+/*
+ * @testcase app_control_uri_create_p
+ * @description Creates a URI builder handle from an encoded URI string.
+ * @apicovered app_control_uri_create
+ */
+TEST_F(UriTest, app_control_uri_create_p) {
+  app_control_uri_h app_control_uri = nullptr;
+  const char *scheme;
+  const char *authority;
+  const char *path;
+  const char *fragment;
+  const char *host;
+  const char *port;
+  const char *user;
+  int r = app_control_uri_create(ENCODED_URI1, &app_control_uri);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_NONE);
+
+  auto handle = std::unique_ptr<void, decltype(app_control_uri_destroy)*>(
+      app_control_uri, app_control_uri_destroy);
+
+  r = app_control_uri_get_scheme(handle.get(), &scheme);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_NONE);
+  r = app_control_uri_get_authority(handle.get(), &authority);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_NONE);
+  r = app_control_uri_get_path(handle.get(), &path);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_NONE);
+  r = app_control_uri_get_fragment(handle.get(), &fragment);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_NONE);
+
+  EXPECT_EQ(std::string(scheme), "https");
+  EXPECT_EQ(std::string(authority), "//john.doe@www.example.com:123");
+  EXPECT_EQ(std::string(path), "/forum/questions/");
+  EXPECT_EQ(std::string(fragment), "top");
+
+  app_control_uri_query_h query = nullptr;
+  r = app_control_uri_get_query(handle.get(), &query);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_NONE);
+  EXPECT_NE(query, nullptr);
+
+  r = app_control_uri_get_host(handle.get(), &host);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_NONE);
+
+  r = app_control_uri_get_port(handle.get(), &port);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_NONE);
+
+  r = app_control_uri_get_user(handle.get(), &user);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_NONE);
+
+  EXPECT_EQ(std::string(host), "www.example.com");
+  EXPECT_EQ(std::string(port), "123");
+  EXPECT_EQ(std::string(user), "john.doe");
+}
+
+/*
+ * @testcase app_control_uri_create_n
+ * @description Creates a URI builder handle from an encoded URI string.
+ *              The function returns a negative error value.
+ * @apicovered app_control_uri_create
+ */
+TEST_F(UriTest, app_control_uri_create_n) {
+  int r = app_control_uri_create(ENCODED_URI1, nullptr);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_INVALID_PARAMETER);
+
+  app_control_uri_h app_control_uri = nullptr;
+  r = app_control_uri_create(nullptr, &app_control_uri);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_INVALID_PARAMETER);
+}
+
+/*
+ * @testcase app_control_uri_destroy_p
+ * @description Destroys a URI handle.
+ * @apicovered app_control_uri_destroy
+ */
+TEST_F(UriTest, app_control_uri_destroy_p) {
+  int r = app_control_uri_destroy(uri_);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_NONE);
+  uri_ = nullptr;
+}
+
+/*
+ * @testcase app_control_uri_destroy_n
+ * @description Destroys a URI handle.
+ *              The function returns a negative error value.
+ * @apicovered app_control_uri_destroy
+ */
+TEST_F(UriTest, app_control_uri_destroy_n) {
+  int r = app_control_uri_destroy(nullptr);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_INVALID_PARAMETER);
+}
+
+/*
+ * @testcase app_control_uri_encode_p
+ * @description Encodes a URI handle to string.
+ * @apicovered app_control_uri_encode
+ */
+TEST_F(UriTest, app_control_uri_encode_p) {
+  char *encoded_app_control_uri = nullptr;
+  int r = app_control_uri_encode(uri_, &encoded_app_control_uri);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_NONE);
+  EXPECT_EQ(std::string(encoded_app_control_uri), ENCODED_URI1);
+  if (encoded_app_control_uri)
+    free(encoded_app_control_uri);
+}
+
+/*
+ * @testcase app_control_uri_encode_n
+ * @description Encodes a URI handle to string.
+ *              The function returns a nullptr.
+ * @apicovered app_control_uri_encode
+ */
+TEST_F(UriTest, app_control_uri_encode_n) {
+  char *encoded_app_control_uri;
+  int r = app_control_uri_encode(nullptr, &encoded_app_control_uri);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_INVALID_PARAMETER);
+}
+
+/*
+ * @testcase app_control_uri_get_scheme_p
+ * @description Gets a scheme component from a URI handle.
+ * @apicovered app_control_uri_get_scheme
+ */
+TEST_F(UriTest, app_control_uri_get_scheme_p) {
+  const char* scheme;
+  int r = app_control_uri_get_scheme(uri_, &scheme);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_NONE);
+  EXPECT_NE(scheme, nullptr);
+  EXPECT_EQ(std::string(scheme), "https");
+}
+
+/*
+ * @testcase app_control_uri_get_scheme_n
+ * @description Gets a scheme component from a URI handle.
+ *              The function returns a nullptr.
+ * @apicovered app_control_uri_get_scheme
+ */
+TEST_F(UriTest, app_control_uri_get_scheme_n) {
+  const char* scheme;
+  int r = app_control_uri_get_scheme(nullptr, &scheme);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_INVALID_PARAMETER);
+}
+
+/*
+ * @testcase app_control_uri_get_authority_p
+ * @description Gets an authority component from a URI handle.
+ * @apicovered app_control_uri_get_authority
+ */
+TEST_F(UriTest, app_control_uri_get_authority_p) {
+  const char* auth;
+  int r = app_control_uri_get_authority(uri_, &auth);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_NONE);
+  EXPECT_NE(auth, nullptr);
+  EXPECT_EQ(std::string(auth), "//john.doe@www.example.com:123");
+}
+
+/*
+ * @testcase app_control_uri_get_authority_n
+ * @description Gets an authority component from a URI handle.
+ *              The function returns a nullptr.
+ * @apicovered app_control_uri_get_authority
+ */
+TEST_F(UriTest, app_control_uri_get_authority_n) {
+  const char* auth;
+  int r = app_control_uri_get_authority(nullptr, &auth);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_INVALID_PARAMETER);
+}
+
+/*
+ * @testcase app_control_uri_get_path_p
+ * @description Gets a path component from a URI handle.
+ * @apicovered app_control_uri_get_path
+ */
+TEST_F(UriTest, app_control_uri_get_path_p) {
+  const char* path;
+  int r = app_control_uri_get_path(uri_, &path);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_NONE);
+  EXPECT_NE(path, nullptr);
+  EXPECT_EQ(std::string(path), "/forum/questions/");
+}
+
+/*
+ * @testcase app_control_uri_get_path_n
+ * @description Gets a path component from a URI handle.
+ *              The function returns a nullptr.
+ * @apicovered app_control_uri_get_path
+ */
+TEST_F(UriTest, app_control_uri_get_path_n) {
+  const char* path;
+  int r = app_control_uri_get_path(nullptr, &path);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_INVALID_PARAMETER);
+}
+
+/*
+ * @testcase app_control_uri_get_fragment_p
+ * @description Gets a fragment component from a URI handle.
+ * @apicovered app_control_uri_get_fragment
+ */
+TEST_F(UriTest, app_control_uri_get_fragment_p) {
+  const char* fragment;
+  int r = app_control_uri_get_fragment(uri_, &fragment);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_NONE);
+  EXPECT_NE(fragment, nullptr);
+  EXPECT_EQ(std::string(fragment), "top");
+}
+
+/*
+ * @testcase app_control_uri_get_fragment_n
+ * @description Gets a fragment component from a URI handle.
+ *              The function returns a nullptr.
+ * @apicovered app_control_uri_get_fragment
+ */
+TEST_F(UriTest, app_control_uri_get_fragment_n) {
+  const char* fragment;
+  int r = app_control_uri_get_fragment(nullptr, &fragment);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_INVALID_PARAMETER);
+}
+
+/*
+ * @testcase app_control_uri_get_query_p
+ * @description Gets a handle of the query component from a URI handle.
+ * @apicovered app_control_uri_get_query
+ */
+TEST_F(UriTest, app_control_uri_get_query_p) {
+  app_control_uri_query_h query = nullptr;
+  int r = app_control_uri_get_query(uri_, &query);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_NONE);
+  EXPECT_NE(query, nullptr);
+}
+
+/*
+ * @testcase app_control_uri_get_query_n
+ * @description Gets a handle of the query component from a URI handle.
+ *              The function returns a negative error value.
+ * @apicovered app_control_uri_get_query
+ */
+TEST_F(UriTest, app_control_uri_get_query_n) {
+  int r = app_control_uri_get_query(uri_, nullptr);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_INVALID_PARAMETER);
+
+  app_control_uri_query_h query = nullptr;
+  r = app_control_uri_get_query(nullptr, &query);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_INVALID_PARAMETER);
+}
+
+/*
+ * @testcase app_control_uri_get_host_p
+ * @description Gets a host subcomponent from a URI handle.
+ * @apicovered app_control_uri_get_host
+ */
+TEST_F(UriTest, app_control_uri_get_host_p) {
+  const char* host;
+  int r = app_control_uri_get_host(uri_, &host);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_NONE);
+  EXPECT_NE(host, nullptr);
+  EXPECT_EQ(std::string(host), "www.example.com");
+}
+
+/*
+ * @testcase app_control_uri_get_host_n
+ * @description Gets a host subcomponent from a URI handle.
+ *              The function returns a nullptr.
+ * @apicovered app_control_uri_get_host
+ */
+TEST_F(UriTest, app_control_uri_get_host_n) {
+  const char* host;
+  int r = app_control_uri_get_host(nullptr, &host);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_INVALID_PARAMETER);
+}
+
+/*
+ * @testcase app_control_uri_get_port_p
+ * @description Gets a port subcomponent from a URI handle.
+ * @apicovered app_control_uri_get_port
+ */
+TEST_F(UriTest, app_control_uri_get_port_p) {
+  const char* port;
+  int r = app_control_uri_get_port(uri_, &port);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_NONE);
+  EXPECT_NE(port, nullptr);
+  EXPECT_EQ(std::string(port), "123");
+}
+
+/*
+ * @testcase app_control_uri_get_port_n
+ * @description Gets a port subcomponent from a URI handle.
+ *              The function returns a nullptr.
+ * @apicovered app_control_uri_get_port
+ */
+TEST_F(UriTest, app_control_uri_get_port_n) {
+  const char* port;
+  int r = app_control_uri_get_port(nullptr, &port);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_INVALID_PARAMETER);
+}
+
+/*
+ * @testcase app_control_uri_get_user_p
+ * @description Gets a user subcomponent from a URI handle.
+ * @apicovered app_control_uri_get_user
+ */
+TEST_F(UriTest, app_control_uri_get_user_p) {
+  const char* user;
+  int r = app_control_uri_get_user(uri_, &user);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_NONE);
+  EXPECT_NE(user, nullptr);
+  EXPECT_EQ(std::string(user), "john.doe");
+}
+
+/*
+ * @testcase app_control_uri_get_user_n
+ * @description Gets a user subcomponent from a URI handle.
+ *              The function returns a nullptr.
+ * @apicovered app_control_uri_get_user
+ */
+TEST_F(UriTest, app_control_uri_get_user_n) {
+  const char* user;
+  int r = app_control_uri_get_user(nullptr, &user);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_INVALID_PARAMETER);
+}
+
+/*
+ * @testcase app_control_uri_query_foreach_p
+ * @description Retrieves the key-value pairs attributes in the query component.
+ * @apicovered app_control_uri_query_foreach
+ */
+TEST_F(UriTest, app_control_uri_query_foreach_p) {
+  // Pre-condition: Gets the query handle
+  app_control_uri_query_h query = nullptr;
+  int r = app_control_uri_get_query(uri_, &query);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_NONE);
+  EXPECT_NE(query, nullptr);
+
+  r = app_control_uri_query_foreach(query,
+      [](const char* key, const char* val, void* user_data) -> bool {
+        UriTest* p = static_cast<UriTest*>(user_data);
+        if (!strcmp(key, "tag") && !strcmp(val, "networking"))
+          p->count_++;
+        else if (!strcmp(key, "order") && !strcmp(val, "newest"))
+          p->count_++;
+        return true;
+      }, this);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_NONE);
+  EXPECT_EQ(count_, 2);
+}
+
+/*
+ * @testcase app_control_uri_query_foreach_n
+ * @description Retrieves the key-value pairs attributes in the query component.
+ *              The function returns a negative error value.
+ * @apicovered app_control_uri_query_foreach
+ */
+TEST_F(UriTest, app_control_uri_query_foreach_n) {
+  // Pre-condition: Gets the query handle
+  app_control_uri_query_h query = nullptr;
+  int r = app_control_uri_get_query(uri_, &query);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_NONE);
+  EXPECT_NE(query, nullptr);
+
+  r = app_control_uri_query_foreach(query, nullptr, this);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_INVALID_PARAMETER);
+
+  r = app_control_uri_query_foreach(nullptr,
+      [](const char* key, const char* val, void* user_data) -> bool {
+        UriTest* p = static_cast<UriTest*>(user_data);
+        if (!strcmp(key, "tag") && !strcmp(val, "networking"))
+          p->count_++;
+        else if (!strcmp(key, "order") && !strcmp(val, "newest"))
+          p->count_++;
+        return true;
+      }, this);
+  EXPECT_EQ(r, APP_CONTROL_URI_ERROR_INVALID_PARAMETER);
+  EXPECT_EQ(count_, 0);
+}