From: Inkyun Kil Date: Tue, 19 Mar 2019 02:06:31 +0000 (+0900) Subject: Add new apis for app_control_uri X-Git-Tag: submit/tizen/20190408.232926~1 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F97%2F201697%2F19;p=platform%2Fcore%2Fapi%2Fapp-control.git Add new apis for app_control_uri Change-Id: I14ebeb2d1630d9848ec5d65fbb7d8c4cd9b04d6a Signed-off-by: Inkyun Kil --- diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..12534b4 --- /dev/null +++ b/AUTHORS @@ -0,0 +1 @@ +Junghoon Park diff --git a/CMakeLists.txt b/CMakeLists.txt index dd27bc3..7cae589 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) diff --git a/include/app_control.h b/include/app_control.h index 4750a2b..cafe27b 100755 --- a/include/app_control.h +++ b/include/app_control.h @@ -20,6 +20,8 @@ #include +#include + #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 index 0000000..bb2490c --- /dev/null +++ b/include/app_control_uri.h @@ -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 +#include + +/** + * @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__ */ diff --git a/packaging/capi-appfw-app-control.spec b/packaging/capi-appfw-app-control.spec index a121a45..e61b034 100644 --- a/packaging/capi-appfw-app-control.spec +++ b/packaging/capi-appfw-app-control.spec @@ -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 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5b96b47..7abbae7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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) diff --git a/src/app_control.c b/src/app_control.c index 62b23e0..707d108 100644 --- a/src/app_control.c +++ b/src/app_control.c @@ -15,6 +15,7 @@ */ +#include #include #include #include @@ -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 index 0000000..5fff10a --- /dev/null +++ b/src/uri/CMakeLists.txt @@ -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 index 0000000..95eb4de --- /dev/null +++ b/src/uri/app_control_uri.cc @@ -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 + +#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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(handle); + const auto& ql = app_control_uri->GetQuery(); + *query_handle = static_cast(&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(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(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(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>*>(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 index 0000000..5efa30f --- /dev/null +++ b/src/uri/uri_internal.cc @@ -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 +#include + +#include + +#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 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> 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>& 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 e_scheme( + g_uri_escape_string(scheme_.c_str(), NULL, TRUE), std::free); + std::unique_ptr e_auth( + g_uri_escape_string(auth_.c_str(), NULL, TRUE), std::free); + std::unique_ptr e_path( + g_uri_escape_string(path_.c_str(), NULL, TRUE), std::free); + std::unique_ptr 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 key( + g_uri_escape_string(i.first.c_str(), NULL, TRUE), std::free); + std::unique_ptr 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 index 0000000..c896ff4 --- /dev/null +++ b/src/uri/uri_internal.h @@ -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 +#include +#include +#include + +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> 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>& 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> 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> 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 index 0000000..fd60481 --- /dev/null +++ b/tools/check-coding-style @@ -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 index 0000000..1941c22 --- /dev/null +++ b/unit_tests/CMakeLists.txt @@ -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 index 0000000..059cfef --- /dev/null +++ b/unit_tests/src/app_control_unittest.cc @@ -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 +#include +#include +#include + +#include +#include + +#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( + builder_, app_control_uri_builder_destroy); + builder_ = nullptr; + } + if (uri_ != nullptr) { + auto uri = std::unique_ptr(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 index 0000000..52fce8d --- /dev/null +++ b/unit_tests/src/main.cc @@ -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 + +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 index 0000000..f1272dd --- /dev/null +++ b/unit_tests/src/uri_unittest.cc @@ -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 +#include +#include + +#include +#include + +#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(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( + builder_, app_control_uri_builder_destroy); + builder_ = nullptr; + } + if (uri_ != nullptr) { + auto uri = std::unique_ptr(uri_, + app_control_uri_destroy); + uri_ = nullptr; + } + } + + std::unique_ptr 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 uri = std::unique_ptr( + 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 uri = std::unique_ptr( + 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 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( + 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(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(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); +}