Add config wrapper (sf_service_config) (#43)

This commit is contained in:
Matt Durak 2022-06-21 15:16:20 -07:00 коммит произвёл GitHub
Родитель f06949fe9b
Коммит 9fb051a8bd
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
10 изменённых файлов: 2099 добавлений и 1 удалений

Просмотреть файл

@ -9,7 +9,7 @@ endif()
#if ((NOT TARGET sf_c_util) AND (EXISTS ${CMAKE_CURRENT_LIST_DIR}/deps/sf-c-util/CMakeLists.txt))
# add_subdirectory(deps/sf-c-util)
#endif()
#endif()
if (TARGET sf_c_util)
RETURN()
@ -95,6 +95,13 @@ set(run_reals_check ${original_run_reals_check})
add_subdirectory(deps/servicefabric)
if((CMAKE_GENERATOR MATCHES "Visual Studio") AND (${run_traceability}))
#add traceability custom target
add_custom_target(sf_c_util_traceability ALL
COMMAND traceabilitytool -buildcheck -e ${CMAKE_CURRENT_LIST_DIR}/deps -i ${CMAKE_CURRENT_LIST_DIR})
add_dependencies(sf_c_util_traceability traceabilitytool)
endif()
set(sf_c_util_h_files
inc/sf_c_util/configuration_reader.h
inc/sf_c_util/fabric_async_op_cb.h
@ -107,6 +114,7 @@ set(sf_c_util_h_files
inc/sf_c_util/fabric_string_result_com.h
inc/sf_c_util/hresult_to_string.h
inc/sf_c_util/servicefabric_enums_to_strings.h
inc/sf_c_util/sf_service_config.h
)
set(sf_c_util_c_files

Просмотреть файл

@ -16,6 +16,8 @@ MOCKABLE_FUNCTION_WITH_RETURNS(, int, configuration_reader_get_char_string, IFab
MOCKABLE_FUNCTION_WITH_RETURNS(, int, configuration_reader_get_thandle_rc_string, IFabricCodePackageActivationContext*, activation_context, const wchar_t*, config_package_name, const wchar_t*, section_name, const wchar_t*, parameter_name, THANDLE(RC_STRING)*, value)(0, MU_FAILURE);
MOCKABLE_FUNCTION_WITH_RETURNS(, int, configuration_reader_get_wchar_string, IFabricCodePackageActivationContext*, activation_context, const wchar_t*, config_package_name, const wchar_t*, section_name, const wchar_t*, parameter_name, wchar_t**, value)(0, MU_FAILURE);
MOCKABLE_FUNCTION_WITH_RETURNS(, int, configuration_reader_get_bool, IFabricCodePackageActivationContext*, activation_context, const wchar_t*, config_package_name, const wchar_t*, section_name, const wchar_t*, parameter_name, bool*, value)(0, MU_FAILURE);
```
### configuration_reader_get_uint64_t

Просмотреть файл

@ -0,0 +1,253 @@
# `sf_service_config` requirements
## Overview
`sf_service_config` is a series of macros which can be used to generate code to read configurations from Service Fabric and expose the values as getters.
The following types are supported:
- `bool` (must be the string "True" for `true` or "False" or empty for `false`, any other value will fail to parse)
- `uint32_t`
- `uint64_t`
- `char*` (`char_ptr`)
- `wchar_t*` (`wchar_ptr`)
- `THANDLE(RC_STRING)` (`thandle_rc_string`)
Any of the string types may be required (must be present in the config or create will fail) or optional (`NULL` or empty strings are allowed). Integer and bool types do not behave differently for optional and required.
## Example Usage
```c
// In header:
#define MY_CONFIGURATION_PARAMETER_NAME_parameter_1 L"ParameterName1"
#define MY_CONFIGURATION_PARAMETER_NAME_parameter_2 L"ParameterName2"
#define MY_CONFIGURATION_PARAMETER_NAME_other_option L"OtherOption"
#define MY_CONFIGURATION_PARAMETER_NAME_foo L"FooNameInXML"
#define MY_CONFIGURATION_VALUES \
CONFIG_REQUIRED(uint64_t, parameter_1), \
CONFIG_REQUIRED(bool, parameter_2), \
CONFIG_REQUIRED(thandle_rc_string, other_option), \
CONFIG_OPTIONAL(thandle_rc_string, foo) \
DECLARE_SF_SERVICE_CONFIG(MY, MY_CONFIGURATION_VALUES)
// In source file:
DEFINE_SF_SERVICE_CONFIG(MY, L"default_config", L"MyParameterSection", MY_CONFIGURATION_VALUES)
```
SF Application Manifest
```xml
<?xml version="1.0" encoding="utf-8"?>
<ApplicationManifest ApplicationTypeName="my_application_type_name" ApplicationTypeVersion="1.42" xmlns="http://schemas.microsoft.com/2011/01/fabric" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Parameters>
<Parameter Name="ParameterName1Value" DefaultValue="42" />
<Parameter Name="ParameterName2Value" DefaultValue="True" />
<Parameter Name="OtherOptionValue" DefaultValue="some string" />
<Parameter Name="FooNameInXMLValue" DefaultValue="" />
</Parameters>
<ServiceManifestImport>
<ServiceManifestRef ServiceManifestName="MyServiceManifestName" ServiceManifestVersion="1.42" />
<ConfigOverrides>
<ConfigOverride Name="default_config">
<Settings>
<Section Name="MyParameterSection">
<Parameter Name="ParameterName1" Value="[ParameterName1Value]" />
<Parameter Name="ParameterName2" Value="[ParameterName2Value]" />
<Parameter Name="OtherOption" Value="[OtherOptionValueValue]" />
<Parameter Name="FooNameInXML" Value="[FooNameInXMLValue]" />
</Section>
</Settings>
</ConfigOverride>
</ConfigOverrides>
</ServiceManifestImport>
</ApplicationManifest>
```
SF Config XML
```xml
<?xml version="1.0" encoding="utf-8"?>
<Settings xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/2011/01/fabric">
<Section Name="MyParameterSection">
<Parameter Name="ParameterName1" Value="42" />
<Parameter Name="ParameterName2" Value="True" />
<Parameter Name="OtherOption" Value="some string" />
<Parameter Name="FooNameInXML" Value="" />
</Section>
</Settings>
```
## Exposed API
```c
#define SF_SERVICE_CONFIG(name) MU_C2(name, _CONFIGURATION)
#define SF_SERVICE_CONFIG_CREATE(name) MU_C2(name, _configuration_create)
#define SF_SERVICE_CONFIG_GETTER(name, param) MU_C3(name, _configuration_get_, param)
#define DECLARE_SF_SERVICE_CONFIG(name, ...) \
//...
#define DEFINE_SF_SERVICE_CONFIG(name, sf_config_name, sf_parameters_section_name, ...) \
//...
```
### DECLARE_SF_SERVICE_CONFIG
```c
#define DECLARE_SF_SERVICE_CONFIG(name, ...)
```
Creates all declarations for the configuration type `SF_SERVICE_CONFIG(name)`. This includes the mockable create, which produces a `THANDLE`, and all of the mockable getters for the parameters specified.
Each parameter must be in the form `CONFIG_REQUIRED(type, config_name)` or `CONFIG_OPTIONAL(type, config_name)`, for configurations that are required or optional, respectively. Required configs must be found in the SF configuration or the configuration create will fail, optional configs may be absent and a default (e.g. empty string) will be used.
Each of these parameters with name `config_name` must also have a corresponding `SF_SERVICE_CONFIG_PARAMETER_NAME_config_name` defined with a wide string for the name of the config value as specified in the SF XML.
**SRS_SF_SERVICE_CONFIG_42_001: [** `DECLARE_SF_SERVICE_CONFIG` shall generate a `THANDLE` declaration of type `SF_SERVICE_CONFIG(name)`. **]**
**SRS_SF_SERVICE_CONFIG_42_002: [** `DECLARE_SF_SERVICE_CONFIG` shall generate a mockable create function `SF_SERVICE_CONFIG_CREATE(name)` which takes an `IFabricCodePackageActivationContext*` and produces the `THANDLE`. **]**
**SRS_SF_SERVICE_CONFIG_42_003: [** `DECLARE_SF_SERVICE_CONFIG` shall generate mockable getter functions `SF_SERVICE_CONFIG_GETTER(name, param)` for each of the configurations provided. **]**
### DEFINE_SF_SERVICE_CONFIG
```c
#define DEFINE_SF_SERVICE_CONFIG(name, sf_config_name, sf_parameters_section_name, ...)
```
Creates the implementation of the configuration for the type `SF_SERVICE_CONFIG(name)`. This includes the underlying struct which will hold all of the configuration values specified.
The `sf_config_name` argument must be a wide string for the configuration values to read from Service Fabric. This is passed to `configuration_reader` as `config_package_name`.
The `sf_parameters_section_name` argument must be a wide string for the section name holding the configuration to read from Service Fabric. This is passed to `configuration_reader` as `section_name`.
**SRS_SF_SERVICE_CONFIG_42_004: [** `DEFINE_SF_SERVICE_CONFIG` shall generate the `SF_SERVICE_CONFIG(name)` struct. **]**
**SRS_SF_SERVICE_CONFIG_42_005: [** `DEFINE_SF_SERVICE_CONFIG` shall generate the implementation of `SF_SERVICE_CONFIG_CREATE(name)`. **]**
**SRS_SF_SERVICE_CONFIG_42_006: [** `DECLARE_SF_SERVICE_CONFIG` shall generate the implementation of the getter functions `SF_SERVICE_CONFIG_GETTER(name, param)` for each of the configurations provided. **]**
### SF_SERVICE_CONFIG
```c
#define SF_SERVICE_CONFIG(name) MU_C2(name, _CONFIGURATION)
```
Get the name of the configuration type, e.g. `MY_CONFIGURATION`.
**SRS_SF_SERVICE_CONFIG_42_007: [** `SF_SERVICE_CONFIG` shall expand to the name of the configuration module by appending the suffix `_CONFIGURATION`. **]**
### SF_SERVICE_CONFIG_CREATE
```c
#define SF_SERVICE_CONFIG_CREATE(name) MU_C2(name, _configuration_create)
```
Get the name of the function to create the configuration object, e.g. `MY_configuration_create`.
**SRS_SF_SERVICE_CONFIG_42_008: [** `SF_SERVICE_CONFIG_CREATE` shall expand to the name of the create function for the configuration module by appending the suffix `_configuration_create`. **]**
```c
THANDLE(SF_SERVICE_CONFIG(name)) SF_SERVICE_CONFIG_CREATE(name)(IFabricCodePackageActivationContext* activation_context)
```
**SRS_SF_SERVICE_CONFIG_42_009: [** If `activation_context` is `NULL` then `SF_SERVICE_CONFIG_CREATE(name)` shall fail and return `NULL`. **]**
**SRS_SF_SERVICE_CONFIG_42_010: [** `SF_SERVICE_CONFIG_CREATE(name)` shall allocate the `THANDLE(SF_SERVICE_CONFIG(name))` with `MU_C2A(SF_SERVICE_CONFIG(name), _dispose)` as the dispose function. **]**
**SRS_SF_SERVICE_CONFIG_42_011: [** `SF_SERVICE_CONFIG_CREATE(name)` shall call `AddRef` and store the `activation_context`. **]**
**SRS_SF_SERVICE_CONFIG_42_012: [** `SF_SERVICE_CONFIG_CREATE(name)` shall store the `sf_config_name` and `sf_parameters_section_name`. **]**
**SRS_SF_SERVICE_CONFIG_42_013: [** For each configuration value with name `config_name`: **]**
- **SRS_SF_SERVICE_CONFIG_42_014: [** If the type is `bool` then: **]**
- **SRS_SF_SERVICE_CONFIG_42_015: [** `SF_SERVICE_CONFIG_CREATE(name)` shall call `configuration_reader_get_bool` with the `activation_context`, `sf_config_name`, `sf_parameters_section_name`, and `SF_SERVICE_CONFIG_PARAMETER_NAME_config_name`. **]**
- **SRS_SF_SERVICE_CONFIG_42_016: [** If the type is `uint32_t` then: **]**
- **SRS_SF_SERVICE_CONFIG_42_017: [** `SF_SERVICE_CONFIG_CREATE(name)` shall call `configuration_reader_get_uint32_t` with the `activation_context`, `sf_config_name`, `sf_parameters_section_name`, and `SF_SERVICE_CONFIG_PARAMETER_NAME_config_name`. **]**
- **SRS_SF_SERVICE_CONFIG_42_018: [** If the result is `UINT32_MAX` then `SF_SERVICE_CONFIG_CREATE(name)` shall fail and return `NULL`. **]**
- **SRS_SF_SERVICE_CONFIG_42_019: [** If the type is `uint64_t` then: **]**
- **SRS_SF_SERVICE_CONFIG_42_020: [** `SF_SERVICE_CONFIG_CREATE(name)` shall call `configuration_reader_get_uint64_t` with the `activation_context`, `sf_config_name`, `sf_parameters_section_name`, and `SF_SERVICE_CONFIG_PARAMETER_NAME_config_name`. **]**
- **SRS_SF_SERVICE_CONFIG_42_021: [** If the result is `UINT64_MAX` then `SF_SERVICE_CONFIG_CREATE(name)` shall fail and return `NULL`. **]**
- **SRS_SF_SERVICE_CONFIG_42_022: [** If the type is `char_ptr` then: **]**
- **SRS_SF_SERVICE_CONFIG_42_023: [** `SF_SERVICE_CONFIG_CREATE(name)` shall call `configuration_reader_get_char_string` with the `activation_context`, `sf_config_name`, `sf_parameters_section_name`, and `SF_SERVICE_CONFIG_PARAMETER_NAME_config_name`. **]**
- **SRS_SF_SERVICE_CONFIG_42_024: [** If the value is an empty string then `SF_SERVICE_CONFIG_CREATE(name)` shall free the string and set it to `NULL`. **]**
- **SRS_SF_SERVICE_CONFIG_42_025: [** If the configuration value is `CONFIG_REQUIRED` and the value is `NULL` then `SF_SERVICE_CONFIG_CREATE(name)` shall fail and return `NULL`. **]**
- **SRS_SF_SERVICE_CONFIG_42_026: [** If the type is `wchar_ptr` then: **]**
- **SRS_SF_SERVICE_CONFIG_42_027: [** `SF_SERVICE_CONFIG_CREATE(name)` shall call `configuration_reader_get_wchar_string` with the `activation_context`, `sf_config_name`, `sf_parameters_section_name`, and `SF_SERVICE_CONFIG_PARAMETER_NAME_config_name`. **]**
- **SRS_SF_SERVICE_CONFIG_42_028: [** If the value is an empty string then `SF_SERVICE_CONFIG_CREATE(name)` shall free the string and set it to `NULL`. **]**
- **SRS_SF_SERVICE_CONFIG_42_029: [** If the configuration value is `CONFIG_REQUIRED` and the value is `NULL` then `SF_SERVICE_CONFIG_CREATE(name)` shall fail and return `NULL`. **]**
- **SRS_SF_SERVICE_CONFIG_42_030: [** If the type is `thandle_rc_string` then: **]**
- **SRS_SF_SERVICE_CONFIG_42_031: [** `SF_SERVICE_CONFIG_CREATE(name)` shall call `configuration_reader_get_thandle_rc_string` with the `activation_context`, `sf_config_name`, `sf_parameters_section_name`, and `SF_SERVICE_CONFIG_PARAMETER_NAME_config_name`. **]**
- **SRS_SF_SERVICE_CONFIG_42_032: [** If the value is an empty string then `SF_SERVICE_CONFIG_CREATE(name)` shall free the string and set it to `NULL`. **]**
- **SRS_SF_SERVICE_CONFIG_42_033: [** If the configuration value is `CONFIG_REQUIRED` and the value is `NULL` then `SF_SERVICE_CONFIG_CREATE(name)` shall fail and return `NULL`. **]**
**SRS_SF_SERVICE_CONFIG_42_034: [** If there are any errors then `SF_SERVICE_CONFIG_CREATE(name)` shall fail and return `NULL`. **]**
### Dispose
```c
static void MU_C2A(SF_SERVICE_CONFIG(name), _dispose)(SF_SERVICE_CONFIG(name)* handle)
```
The dispose function is called when the last `THANDLE` reference is released.
**SRS_SF_SERVICE_CONFIG_42_035: [** For each config value: **]**
- **SRS_SF_SERVICE_CONFIG_42_036: [** If the type is `char_ptr` then `MU_C2A(SF_SERVICE_CONFIG(name), _dispose)` shall free the string. **]**
- **SRS_SF_SERVICE_CONFIG_42_038: [** If the type is `wchar_ptr` then `MU_C2A(SF_SERVICE_CONFIG(name), _dispose)` shall free the string. **]**
- **SRS_SF_SERVICE_CONFIG_42_040: [** If the type is `thandle_rc_string` then `MU_C2A(SF_SERVICE_CONFIG(name), _dispose)` shall assign the `THANDLE` to `NULL`. **]**
**SRS_SF_SERVICE_CONFIG_42_042: [** `MU_C2A(SF_SERVICE_CONFIG(name), _dispose)` shall `Release` the `activation_context`. **]**
### SF_SERVICE_CONFIG_GETTER
```c
#define SF_SERVICE_CONFIG_GETTER(name, param) MU_C3(name, _configuration_get_, param)
```
Get the name of the function to get a parameter, e.g. `MY_configuration_get_foo`.
**SRS_SF_SERVICE_CONFIG_42_043: [** `SF_SERVICE_CONFIG_GETTER` shall expand to the name of the getter function for the configuration module and the given `param` by concatenating the `name`, the string `_configuration_get`, and the `param`. **]**
```c
SF_SERVICE_CONFIG_RETURN_TYPE(field_type) SF_SERVICE_CONFIG_GETTER(name, field_name)(THANDLE(SF_SERVICE_CONFIG(name)) handle)
```
Each getter function returns the value read from the config. The integer values are copied, string values are pointers back into this structure (and thus their lifetime depends on this configuration handle), and `thandle_rc_string` results are reference counted.
**SRS_SF_SERVICE_CONFIG_42_044: [** If `handle` is `NULL` then `SF_SERVICE_CONFIG_GETTER(name, field_name)` shall fail and return... **]**
- **SRS_SF_SERVICE_CONFIG_42_045: [** ...`false` if the type is `bool` **]**
- **SRS_SF_SERVICE_CONFIG_42_046: [** ...`UINT32_MAX` if the type is `uint32_t` **]**
- **SRS_SF_SERVICE_CONFIG_42_047: [** ...`UINT64_MAX` if the type is `uint64_t` **]**
- **SRS_SF_SERVICE_CONFIG_42_048: [** ...`NULL` otherwise **]**
**SRS_SF_SERVICE_CONFIG_42_049: [** If the type is `thandle_rc_string` then the returned value will be set using `THANDLE_INITIALIZE` and the caller will have a reference they must free. **]**
**SRS_SF_SERVICE_CONFIG_42_050: [** `SF_SERVICE_CONFIG_GETTER(name, field_name)` shall return the configuration value for `field_name`. **]**

Просмотреть файл

@ -0,0 +1,487 @@
// Copyright (C) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#ifndef SF_SERVICE_CONFIG_H
#define SF_SERVICE_CONFIG_H
#ifdef __cplusplus
#include <cinttypes>
#else
#include <inttypes.h>
#include <stdbool.h>
#include <stdlib.h>
#include <wchar.h>
#endif
#include "windows.h"
#include "fabricruntime.h"
#include "c_logging/xlogging.h"
#include "c_util/rc_string.h"
#include "c_util/thandle.h"
#include "c_pal/string_utils.h"
#include "macro_utils/macro_utils.h"
#include "sf_c_util/configuration_reader.h"
#include "umock_c/umock_c_prod.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
Currently supports the following types:
bool
uint32_t
uint64_t
char* (char_ptr)
wchar_t* (wchar_ptr)
THANDLE(RC_STRING) (thandle_rc_string)
*/
typedef char* char_ptr;
typedef wchar_t* wchar_ptr;
typedef THANDLE(RC_STRING) thandle_rc_string;
// Names
/*Codes_SRS_SF_SERVICE_CONFIG_42_007: [ SF_SERVICE_CONFIG shall expand to the name of the configuration module by appending the suffix _CONFIGURATION. ]*/
#define SF_SERVICE_CONFIG(name) MU_C2(name, _CONFIGURATION)
/*Codes_SRS_SF_SERVICE_CONFIG_42_008: [ SF_SERVICE_CONFIG_CREATE shall expand to the name of the create function for the configuration module by appending the suffix _configuration_create. ]*/
#define SF_SERVICE_CONFIG_CREATE(name) MU_C2(name, _configuration_create)
/*Codes_SRS_SF_SERVICE_CONFIG_42_043: [ SF_SERVICE_CONFIG_GETTER shall expand to the name of the getter function for the configuration module and the given param by concatenating the name, the string _configuration_get, and the param. ]*/
#define SF_SERVICE_CONFIG_GETTER(name, param) MU_C3(name, _configuration_get_, param)
// Helpers to declare parameters
#define SF_SERVICE_CONFIG_PARAMETER_NAME(name) MU_C2(SF_SERVICE_CONFIG_PARAMETER_NAME_, name)
// Declare configuration (for header)
#define DECLARE_SF_SERVICE_CONFIG(name, ...) \
/*Codes_SRS_SF_SERVICE_CONFIG_42_001: [ DECLARE_SF_SERVICE_CONFIG shall generate a THANDLE declaration of type SF_SERVICE_CONFIG(name). ]*/ \
typedef struct MU_C2(name, _CONFIGURATION_TAG) SF_SERVICE_CONFIG(name); \
THANDLE_TYPE_DECLARE(SF_SERVICE_CONFIG(name)); \
/*Codes_SRS_SF_SERVICE_CONFIG_42_002: [ DECLARE_SF_SERVICE_CONFIG shall generate a mockable create function SF_SERVICE_CONFIG_CREATE(name) which takes an IFabricCodePackageActivationContext* and produces the THANDLE. ]*/ \
MOCKABLE_FUNCTION(, THANDLE(SF_SERVICE_CONFIG(name)), SF_SERVICE_CONFIG_CREATE(name), IFabricCodePackageActivationContext*, activation_context); \
/*Codes_SRS_SF_SERVICE_CONFIG_42_003: [ DECLARE_SF_SERVICE_CONFIG shall generate mockable getter functions SF_SERVICE_CONFIG_GETTER(name, param) for each of the configurations provided. ]*/ \
SF_SERVICE_CONFIG_EXPANDED_MU_FOR_EACH_2_KEEP_1(DECLARE_SF_SERVICE_CONFIG_GETTER, name, SF_SERVICE_CONFIG_EXPAND_PARAMS(__VA_ARGS__))
// Define configuration (for .c file)
#define DEFINE_SF_SERVICE_CONFIG(name, sf_config_name, sf_parameters_section_name, ...) \
/*Codes_SRS_SF_SERVICE_CONFIG_42_004: [ DEFINE_SF_SERVICE_CONFIG shall generate the SF_SERVICE_CONFIG(name) struct. ]*/ \
DEFINE_SF_SERVICE_CONFIG_STRUCT(SF_SERVICE_CONFIG(name), sf_config_name, sf_parameters_section_name, SF_SERVICE_CONFIG_EXPAND_PARAMS(__VA_ARGS__)); \
THANDLE_TYPE_DEFINE(SF_SERVICE_CONFIG(name)); \
DEFINE_SF_SERVICE_CONFIG_DISPOSE(name, __VA_ARGS__) \
/*Codes_SRS_SF_SERVICE_CONFIG_42_005: [ DEFINE_SF_SERVICE_CONFIG shall generate the implementation of SF_SERVICE_CONFIG_CREATE(name). ]*/ \
SF_SERVICE_CONFIG_DEFINE_CREATE(name, sf_config_name, sf_parameters_section_name, __VA_ARGS__) \
/*Codes_SRS_SF_SERVICE_CONFIG_42_006: [ DECLARE_SF_SERVICE_CONFIG shall generate the implementation of the getter functions SF_SERVICE_CONFIG_GETTER(name, param) for each of the configurations provided. ]*/ \
SF_SERVICE_CONFIG_EXPANDED_MU_FOR_EACH_2_KEEP_1(SF_SERVICE_CONFIG_DEFINE_GETTER, name, SF_SERVICE_CONFIG_EXPAND_PARAMS(__VA_ARGS__))
// Implementation details
#define SF_SERVICE_CONFIG_EXPAND_PARAM_CONFIG_OPTIONAL(field_type, field_name) field_type, field_name
#define SF_SERVICE_CONFIG_EXPAND_PARAM_CONFIG_REQUIRED(field_type, field_name) field_type, field_name
#define SF_SERVICE_CONFIG_EXPAND_PARAM(count, field) MU_C2(SF_SERVICE_CONFIG_EXPAND_PARAM_, field) MU_IFCOMMALOGIC(MU_DEC(count))
#define SF_SERVICE_CONFIG_EXPAND_PARAM_WITH_REQUIRED_FLAG_CONFIG_OPTIONAL(field_type, field_name) field_type, field_name, 0
#define SF_SERVICE_CONFIG_EXPAND_PARAM_WITH_REQUIRED_FLAG_CONFIG_REQUIRED(field_type, field_name) field_type, field_name, 1
#define SF_SERVICE_CONFIG_EXPAND_PARAM_WITH_REQUIRED_FLAG(field) MU_C2(SF_SERVICE_CONFIG_EXPAND_PARAM_WITH_REQUIRED_FLAG_, field)
// This will strip the REQUIRED and OPTIONAL parts of the fields
#define SF_SERVICE_CONFIG_EXPAND_PARAMS(...) MU_FOR_EACH_1_COUNTED(SF_SERVICE_CONFIG_EXPAND_PARAM, __VA_ARGS__)
// When using SF_SERVICE_CONFIG_EXPAND_PARAMS, we need these layers of indirection so it expands before calling the FOR_EACH
#define SF_SERVICE_CONFIG_EXPAND_MACRO_HELPER(OUTER, arg1, ...) OUTER(arg1, __VA_ARGS__)
#define SF_SERVICE_CONFIG_EXPANDED_MU_FOR_EACH_2(MACRO, ...) SF_SERVICE_CONFIG_EXPAND_MACRO_HELPER(MU_FOR_EACH_2, MACRO, __VA_ARGS__)
#define SF_SERVICE_CONFIG_EXPANDED_MU_FOR_EACH_2_COUNTED(MACRO, ...) SF_SERVICE_CONFIG_EXPAND_MACRO_HELPER(MU_FOR_EACH_2_COUNTED, MACRO, __VA_ARGS__)
#define SF_SERVICE_CONFIG_EXPANDED_MU_FOR_EACH_2_KEEP_1(MACRO, keep, ...) SF_SERVICE_CONFIG_EXPAND_MACRO_HELPER(MU_FOR_EACH_2_KEEP_1, MACRO, keep, __VA_ARGS__)
#define SF_SERVICE_CONFIG_EXPANDED_MU_FOR_EACH_2_KEEP_2(MACRO, keep1, keep2, ...) SF_SERVICE_CONFIG_EXPAND_MACRO_HELPER(MU_FOR_EACH_2_KEEP_2, MACRO, keep1, keep2, __VA_ARGS__)
// The following will filter the list out to just the optional values or just the required values, so they can be handled differently
// This is done because we can't expand things like "CONFIG_REQUIRED(char_ptr, foo)" to "DO_SOMETHING_CONFIG_REQUIRED(something_else, char_ptr, foo)"
#define SF_SERVICE_CONFIG_EXPAND_REQUIRED_CONFIG_OPTIONAL(field_type, field_name) SKIP , SKIP
#define SF_SERVICE_CONFIG_EXPAND_REQUIRED_CONFIG_REQUIRED(field_type, field_name) field_type, field_name
#define SF_SERVICE_CONFIG_EXPAND_REQUIRED(count, field) MU_C2(SF_SERVICE_CONFIG_EXPAND_REQUIRED_,field) MU_IFCOMMALOGIC(MU_DEC(count))
#define SF_SERVICE_CONFIG_EXPAND_REQUIRED_ONLY(...) MU_FOR_EACH_1_COUNTED(SF_SERVICE_CONFIG_EXPAND_REQUIRED, __VA_ARGS__)
#define SF_SERVICE_CONFIG_EXPAND_OPTIONAL_CONFIG_OPTIONAL(field_type, field_name) field_type, field_name
#define SF_SERVICE_CONFIG_EXPAND_OPTIONAL_CONFIG_REQUIRED(field_type, field_name) SKIP , SKIP
#define SF_SERVICE_CONFIG_EXPAND_OPTIONAL(count, field) MU_C2(SF_SERVICE_CONFIG_EXPAND_OPTIONAL_,field) MU_IFCOMMALOGIC(MU_DEC(count))
#define SF_SERVICE_CONFIG_EXPAND_OPTIONAL_ONLY(...) MU_FOR_EACH_1_COUNTED(SF_SERVICE_CONFIG_EXPAND_OPTIONAL, __VA_ARGS__)
// Helpers for Declare
#define DECLARE_SF_SERVICE_CONFIG_GETTER(name, type, param) \
MOCKABLE_FUNCTION(, SF_SERVICE_CONFIG_RETURN_TYPE(type), SF_SERVICE_CONFIG_GETTER(name, param), THANDLE(SF_SERVICE_CONFIG(name)), handle);
// Helpers for Define
// Internal struct
// Need extra layer of indirection so the SF_SERVICE_CONFIG_EXPAND_PARAMS() macro expands first
#define DEFINE_SF_SERVICE_CONFIG_STRUCT(name, sf_config_name, sf_parameters_section_name, ...) \
MU_DEFINE_STRUCT(name, \
IFabricCodePackageActivationContext*, activation_context,\
const wchar_t*, sf_config_name_string, \
const wchar_t*, sf_parameters_section_name_string, \
__VA_ARGS__)
// Type helpers
#define PRI_uint32_t PRIu32
#define PRI_uint64_t PRIu64
#define CONFIGURATION_READER_FUNCTION_char_ptr configuration_reader_get_char_string
#define CONFIGURATION_READER_FUNCTION_wchar_ptr configuration_reader_get_wchar_string
#define SF_SERVICE_CONFIG_STR_PREFIX_char_ptr
#define SF_SERVICE_CONFIG_STR_PREFIX_wchar_ptr L
#define SF_SERVICE_CONFIG_STR_PREFIX(type) MU_C2(SF_SERVICE_CONFIG_STR_PREFIX_, type)
#define PRI_char_ptr "s"
#define PRI_wchar_ptr "ls"
#define SF_SERVICE_CONFIG_P_OR_NULL_char_ptr(value) MU_P_OR_NULL(value)
#define SF_SERVICE_CONFIG_P_OR_NULL_wchar_ptr(value) MU_WP_OR_NULL(value)
#define SF_SERVICE_CONFIG_P_OR_NULL(type, value) MU_C2(SF_SERVICE_CONFIG_P_OR_NULL_, type)(value)
// By default, nothing needs to be free'd
#define SF_SERVICE_CONFIG_MUST_CLEANUP_TYPE_char_ptr 0
#define SF_SERVICE_CONFIG_MUST_CLEANUP_TYPE_wchar_ptr 0
#define SF_SERVICE_CONFIG_MUST_CLEANUP_TYPE_thandle_rc_string 0
#define SF_SERVICE_CONFIG_MUST_CLEANUP_TYPE(type) MU_IF(MU_C2(SF_SERVICE_CONFIG_MUST_CLEANUP_TYPE_,type), 0, 1)
/*Codes_SRS_SF_SERVICE_CONFIG_42_036: [ If the type is char_ptr then MU_C2A(SF_SERVICE_CONFIG(name), _dispose) shall free the string. ]*/
#define SF_SERVICE_CONFIG_CLEANUP_FUNCTION_char_ptr(handle, field_name) free(handle->field_name); handle->field_name = NULL
/*Codes_SRS_SF_SERVICE_CONFIG_42_038: [ If the type is wchar_ptr then MU_C2A(SF_SERVICE_CONFIG(name), _dispose) shall free the string. ]*/
#define SF_SERVICE_CONFIG_CLEANUP_FUNCTION_wchar_ptr(handle, field_name) free(handle->field_name); handle->field_name = NULL
/*Codes_SRS_SF_SERVICE_CONFIG_42_040: [ If the type is thandle_rc_string then MU_C2A(SF_SERVICE_CONFIG(name), _dispose) shall assign the THANDLE to NULL. ]*/
#define SF_SERVICE_CONFIG_CLEANUP_FUNCTION_thandle_rc_string(handle, field_name) THANDLE_ASSIGN(RC_STRING)(&handle->field_name, NULL)
#define SF_SERVICE_CONFIG_CLEANUP_FUNCTION(handle, field_type, field_name) MU_C2(SF_SERVICE_CONFIG_CLEANUP_FUNCTION_, field_type)(handle, field_name)
// Helpers to read config values
// Note that "error_occurred" is defined below "by convention"
/*Codes_SRS_SF_SERVICE_CONFIG_42_014: [ If the type is bool then: ]*/
#define SF_SERVICE_CONFIG_DO_READ__Bool(config, field_name, parameter_string, result_value, error_occurred_flag, fail_if_null) \
result_value = false; \
if (!error_occurred_flag) \
{ \
/*Codes_SRS_SF_SERVICE_CONFIG_42_015: [ SF_SERVICE_CONFIG_CREATE(name) shall call configuration_reader_get_bool with the activation_context, sf_config_name, sf_parameters_section_name, and SF_SERVICE_CONFIG_PARAMETER_NAME_config_name. ]*/ \
if (configuration_reader_get_bool(config->activation_context, config->sf_config_name_string, config->sf_parameters_section_name_string, parameter_string, &result_value) != 0) \
{ \
/*Codes_SRS_SF_SERVICE_CONFIG_42_034: [ If there are any errors then SF_SERVICE_CONFIG_CREATE(name) shall fail and return NULL. ]*/ \
LogError("configuration_reader_get_bool (\"%ls\", \"%ls\", \"%ls\") failed", \
config->sf_config_name_string, config->sf_parameters_section_name_string, parameter_string); \
error_occurred_flag = true; \
} \
else \
{ \
LogVerbose("Config loaded: %ls = %" PRI_BOOL, parameter_string, MU_BOOL_VALUE(result_value)); \
} \
}
#define SF_SERVICE_CONFIG_DO_READ_integer_type(type, max_value, config, parameter_string, result_value, error_occurred_flag) \
if (!error_occurred_flag) \
{ \
/*Codes_SRS_SF_SERVICE_CONFIG_42_017: [ SF_SERVICE_CONFIG_CREATE(name) shall call configuration_reader_get_uint32_t with the activation_context, sf_config_name, sf_parameters_section_name, and SF_SERVICE_CONFIG_PARAMETER_NAME_config_name. ]*/ \
/*Codes_SRS_SF_SERVICE_CONFIG_42_020: [ SF_SERVICE_CONFIG_CREATE(name) shall call configuration_reader_get_uint64_t with the activation_context, sf_config_name, sf_parameters_section_name, and SF_SERVICE_CONFIG_PARAMETER_NAME_config_name. ]*/ \
if (MU_C2(configuration_reader_get_, type)(config->activation_context, config->sf_config_name_string, config->sf_parameters_section_name_string, parameter_string, &result_value) != 0) \
{ \
/*Codes_SRS_SF_SERVICE_CONFIG_42_034: [ If there are any errors then SF_SERVICE_CONFIG_CREATE(name) shall fail and return NULL. ]*/ \
LogError(MU_TOSTRING(MU_C2(configuration_reader_get_, type)) "(\"%ls\", \"%ls\", \"%ls\") failed", \
config->sf_config_name_string, config->sf_parameters_section_name_string, parameter_string); \
error_occurred_flag = true; \
} \
else if (result_value == max_value) \
{ \
/*Codes_SRS_SF_SERVICE_CONFIG_42_018: [ If the result is UINT32_MAX then SF_SERVICE_CONFIG_CREATE(name) shall fail and return NULL. ]*/ \
/*Codes_SRS_SF_SERVICE_CONFIG_42_021: [ If the result is UINT64_MAX then SF_SERVICE_CONFIG_CREATE(name) shall fail and return NULL. ]*/ \
LogError("Invalid %ls=%" MU_C2(PRI_, type), parameter_string, result_value); \
error_occurred_flag = true; \
} \
else \
{ \
LogVerbose("Config loaded: %ls = %" MU_C2(PRI_, type), parameter_string, result_value); \
} \
}
/*Codes_SRS_SF_SERVICE_CONFIG_42_016: [ If the type is uint32_t then: ]*/
#define SF_SERVICE_CONFIG_DO_READ_uint32_t(config, field_name, parameter_string, result_value, error_occurred_flag, fail_if_null) \
SF_SERVICE_CONFIG_DO_READ_integer_type(uint32_t, UINT32_MAX, config, parameter_string, result_value, error_occurred_flag)
/*Codes_SRS_SF_SERVICE_CONFIG_42_019: [ If the type is uint64_t then: ]*/
#define SF_SERVICE_CONFIG_DO_READ_uint64_t(config, field_name, parameter_string, result_value, error_occurred_flag, fail_if_null) \
SF_SERVICE_CONFIG_DO_READ_integer_type(uint64_t, UINT64_MAX, config, parameter_string, result_value, error_occurred_flag)
#define SF_SERVICE_CONFIG_DO_READ_any_char_ptr(config, type, field_name, parameter_string, result_value, error_occurred_flag, fail_if_null) \
result_value = NULL; \
if (!error_occurred_flag) \
{ \
/*Codes_SRS_SF_SERVICE_CONFIG_42_023: [ SF_SERVICE_CONFIG_CREATE(name) shall call configuration_reader_get_char_string with the activation_context, sf_config_name, sf_parameters_section_name, and SF_SERVICE_CONFIG_PARAMETER_NAME_config_name. ]*/ \
/*Codes_SRS_SF_SERVICE_CONFIG_42_027: [ SF_SERVICE_CONFIG_CREATE(name) shall call configuration_reader_get_wchar_string with the activation_context, sf_config_name, sf_parameters_section_name, and SF_SERVICE_CONFIG_PARAMETER_NAME_config_name. ]*/ \
if (MU_C2(CONFIGURATION_READER_FUNCTION_, type)(config->activation_context, config->sf_config_name_string, config->sf_parameters_section_name_string, parameter_string, &result_value) != 0) \
{ \
/*Codes_SRS_SF_SERVICE_CONFIG_42_034: [ If there are any errors then SF_SERVICE_CONFIG_CREATE(name) shall fail and return NULL. ]*/ \
LogError(MU_TOSTRING(MU_C2(CONFIGURATION_READER_FUNCTION_, type))"(\"%ls\", \"%ls\", \"%ls\") failed", \
config->sf_config_name_string, config->sf_parameters_section_name_string, parameter_string); \
error_occurred_flag = true; \
} \
else \
{ \
if (result_value != NULL && result_value[0] == MU_C2(SF_SERVICE_CONFIG_STR_PREFIX(type),'\0')) \
{ \
/*Codes_SRS_SF_SERVICE_CONFIG_42_024: [ If the value is an empty string then SF_SERVICE_CONFIG_CREATE(name) shall free the string and set it to NULL. ]*/ \
/*Codes_SRS_SF_SERVICE_CONFIG_42_028: [ If the value is an empty string then SF_SERVICE_CONFIG_CREATE(name) shall free the string and set it to NULL. ]*/ \
free(result_value); \
result_value = NULL; \
} \
MU_IF(fail_if_null, \
if (result_value == NULL) \
{ \
/*Codes_SRS_SF_SERVICE_CONFIG_42_025: [ If the configuration value is CONFIG_REQUIRED and the value is NULL then SF_SERVICE_CONFIG_CREATE(name) shall fail and return NULL. ]*/ \
/*Codes_SRS_SF_SERVICE_CONFIG_42_029: [ If the configuration value is CONFIG_REQUIRED and the value is NULL then SF_SERVICE_CONFIG_CREATE(name) shall fail and return NULL. ]*/ \
LogError("Invalid %ls=%" MU_C2(PRI_, type), parameter_string, SF_SERVICE_CONFIG_P_OR_NULL(type, result_value)); \
error_occurred_flag = true; \
} \
else \
, \
) \
{ \
LogVerbose("Config loaded: %ls = %" MU_C2(PRI_, type), parameter_string, SF_SERVICE_CONFIG_P_OR_NULL(type, result_value)); \
} \
} \
}
/*Codes_SRS_SF_SERVICE_CONFIG_42_022: [ If the type is char_ptr then: ]*/
#define SF_SERVICE_CONFIG_DO_READ_char_ptr(config, field_name, parameter_string, result_value, error_occurred_flag, fail_if_null) \
SF_SERVICE_CONFIG_DO_READ_any_char_ptr(config, char_ptr, field_name, parameter_string, result_value, error_occurred_flag, fail_if_null)
/*Codes_SRS_SF_SERVICE_CONFIG_42_026: [ If the type is wchar_ptr then: ]*/
#define SF_SERVICE_CONFIG_DO_READ_wchar_ptr(config, field_name, parameter_string, result_value, error_occurred_flag, fail_if_null) \
SF_SERVICE_CONFIG_DO_READ_any_char_ptr(config, wchar_ptr, field_name, parameter_string, result_value, error_occurred_flag, fail_if_null)
/*Codes_SRS_SF_SERVICE_CONFIG_42_030: [ If the type is thandle_rc_string then: ]*/
#define SF_SERVICE_CONFIG_DO_READ_thandle_rc_string(config, field_name, parameter_string, result_value, error_occurred_flag, fail_if_null) \
THANDLE_INITIALIZE(RC_STRING)(&result_value, NULL); \
if (!error_occurred_flag) \
{ \
/*Codes_SRS_SF_SERVICE_CONFIG_42_031: [ SF_SERVICE_CONFIG_CREATE(name) shall call configuration_reader_get_thandle_rc_string with the activation_context, sf_config_name, sf_parameters_section_name, and SF_SERVICE_CONFIG_PARAMETER_NAME_config_name. ]*/ \
if (configuration_reader_get_thandle_rc_string(config->activation_context, config->sf_config_name_string, config->sf_parameters_section_name_string, parameter_string, &result_value) != 0) \
{ \
/*Codes_SRS_SF_SERVICE_CONFIG_42_034: [ If there are any errors then SF_SERVICE_CONFIG_CREATE(name) shall fail and return NULL. ]*/ \
LogError("configuration_reader_get_thandle_rc_string(\"%ls\", \"%ls\", \"%ls\") failed", \
config->sf_config_name_string, config->sf_parameters_section_name_string, parameter_string); \
error_occurred_flag = true; \
} \
else \
{ \
if (result_value != NULL && result_value->string[0] == '\0') \
{ \
/*Codes_SRS_SF_SERVICE_CONFIG_42_032: [ If the value is an empty string then SF_SERVICE_CONFIG_CREATE(name) shall free the string and set it to NULL. ]*/ \
THANDLE_ASSIGN(RC_STRING)(&result_value, NULL); \
} \
MU_IF(fail_if_null, \
if (result_value == NULL) \
{ \
/*Codes_SRS_SF_SERVICE_CONFIG_42_033: [ If the configuration value is CONFIG_REQUIRED and the value is NULL then SF_SERVICE_CONFIG_CREATE(name) shall fail and return NULL. ]*/ \
LogError("Invalid %ls=%" PRI_RC_STRING, parameter_string, RC_STRING_VALUE_OR_NULL(result_value)); \
error_occurred_flag = true; \
} \
else \
, \
) \
{ \
LogVerbose("Config loaded: %ls = %" PRI_RC_STRING, parameter_string, RC_STRING_VALUE_OR_NULL(result_value)); \
} \
} \
}
#define SF_SERVICE_CONFIG_IS_TYPE_SKIP_SKIP 0
#define SF_SERVICE_CONFIG_IS_TYPE_SKIP(type) MU_IF(MU_C2(SF_SERVICE_CONFIG_IS_TYPE_SKIP_, type), 0, 1)
#define SF_SERVICE_CONFIG_DO_READ_REQUIRED(handle, field_type, field_name) \
MU_IF(SF_SERVICE_CONFIG_IS_TYPE_SKIP(field_type),, \
MU_C2(SF_SERVICE_CONFIG_DO_READ_, field_type)(handle, field_name, SF_SERVICE_CONFIG_PARAMETER_NAME(field_name), handle->field_name, error_occurred, 1) \
)
#define SF_SERVICE_CONFIG_DO_READ_OPTIONAL(handle, field_type, field_name) \
MU_IF(SF_SERVICE_CONFIG_IS_TYPE_SKIP(field_type),, \
MU_C2(SF_SERVICE_CONFIG_DO_READ_, field_type)(handle, field_name, SF_SERVICE_CONFIG_PARAMETER_NAME(field_name), handle->field_name, error_occurred, 0) \
)
#define SF_SERVICE_CONFIG_DO_READ_EITHER(handle, field_type, field_name, is_required) \
MU_IF(SF_SERVICE_CONFIG_IS_TYPE_SKIP(field_type),, \
MU_C2(SF_SERVICE_CONFIG_DO_READ_, field_type)(handle, field_name, SF_SERVICE_CONFIG_PARAMETER_NAME(field_name), handle->field_name, error_occurred, is_required) \
)
#define SF_SERVICE_CONFIG_DO_READ(handle, config) SF_SERVICE_CONFIG_EXPAND_MACRO_HELPER(SF_SERVICE_CONFIG_DO_READ_EITHER, handle, SF_SERVICE_CONFIG_EXPAND_PARAM_WITH_REQUIRED_FLAG(config))
#define SF_SERVICE_CONFIG_DEFINE_CREATE(name, sf_config_name, sf_parameters_section_name, ...) \
static int MU_C2(name, _read_all_config_values)(SF_SERVICE_CONFIG(name)* handle) \
{ \
int result; \
bool error_occurred = false; \
/*Codes_SRS_SF_SERVICE_CONFIG_42_013: [ For each configuration value with name config_name: ]*/ \
MU_FOR_EACH_1_KEEP_1(SF_SERVICE_CONFIG_DO_READ, handle, __VA_ARGS__) \
if (error_occurred) \
{ \
/*Codes_SRS_SF_SERVICE_CONFIG_42_034: [ If there are any errors then SF_SERVICE_CONFIG_CREATE(name) shall fail and return NULL. ]*/ \
MU_C2A(SF_SERVICE_CONFIG(name), _cleanup_fields)(handle); \
result = MU_FAILURE; \
} \
else \
{ \
result = 0; \
} \
return result; \
} \
THANDLE(SF_SERVICE_CONFIG(name)) SF_SERVICE_CONFIG_CREATE(name)(IFabricCodePackageActivationContext* activation_context) \
{ \
THANDLE(SF_SERVICE_CONFIG(name)) result = NULL; \
if ( \
/*Codes_SRS_SF_SERVICE_CONFIG_42_009: [ If activation_context is NULL then SF_SERVICE_CONFIG_CREATE(name) shall fail and return NULL. ]*/ \
activation_context == NULL \
) \
{ \
LogError("Invalid args: IFabricCodePackageActivationContext* activation_context = %p", \
activation_context); \
} \
else \
{ \
/*Codes_SRS_SF_SERVICE_CONFIG_42_010: [ SF_SERVICE_CONFIG_CREATE(name) shall allocate the THANDLE(SF_SERVICE_CONFIG(name)) with MU_C2A(SF_SERVICE_CONFIG(name), _dispose) as the dispose function. ]*/ \
THANDLE(SF_SERVICE_CONFIG(name)) temp_config = THANDLE_MALLOC(SF_SERVICE_CONFIG(name))(MU_C2A(SF_SERVICE_CONFIG(name), _dispose)); \
if (temp_config == NULL) \
{ \
/*Codes_SRS_SF_SERVICE_CONFIG_42_034: [ If there are any errors then SF_SERVICE_CONFIG_CREATE(name) shall fail and return NULL. ]*/ \
LogError("THANDLE_MALLOC(" MU_TOSTRING(SF_SERVICE_CONFIG(name)) ") failed"); \
} \
else \
{ \
SF_SERVICE_CONFIG(name)* temp_config_obj = THANDLE_GET_T(SF_SERVICE_CONFIG(name))(temp_config); \
/*Codes_SRS_SF_SERVICE_CONFIG_42_011: [ SF_SERVICE_CONFIG_CREATE(name) shall call AddRef and store the activation_context. ]*/ \
temp_config_obj->activation_context = activation_context; \
(void)temp_config_obj->activation_context->lpVtbl->AddRef(temp_config_obj->activation_context); \
/*Codes_SRS_SF_SERVICE_CONFIG_42_012: [ SF_SERVICE_CONFIG_CREATE(name) shall store the sf_config_name and sf_parameters_section_name. ]*/ \
temp_config_obj->sf_config_name_string = sf_config_name; \
temp_config_obj->sf_parameters_section_name_string = sf_parameters_section_name; \
\
if (MU_C2(name, _read_all_config_values)(temp_config_obj) != 0) \
{ \
/*Codes_SRS_SF_SERVICE_CONFIG_42_034: [ If there are any errors then SF_SERVICE_CONFIG_CREATE(name) shall fail and return NULL. ]*/ \
} \
else \
{ \
THANDLE_INITIALIZE_MOVE(SF_SERVICE_CONFIG(name))(&result, &temp_config); \
goto all_ok; \
} \
(void)temp_config_obj->activation_context->lpVtbl->Release(temp_config_obj->activation_context); \
THANDLE_FREE(SF_SERVICE_CONFIG(name))(temp_config_obj); \
} \
} \
all_ok: \
return result; \
}
// Cleanup
#define SF_SERVICE_CONFIG_DO_CLEANUP_POINTER(handle, field_type, field_name) \
if (handle->field_name != NULL) \
{ \
SF_SERVICE_CONFIG_CLEANUP_FUNCTION(handle, field_type, field_name); \
}
#define DO_CLEANUP_IF_NEEDED(handle, field_type, field_name) \
MU_IF(SF_SERVICE_CONFIG_MUST_CLEANUP_TYPE(field_type), SF_SERVICE_CONFIG_DO_CLEANUP_POINTER(handle, field_type, field_name), )
#define DEFINE_SF_SERVICE_CONFIG_DISPOSE(name, ...) \
static void MU_C2A(SF_SERVICE_CONFIG(name), _cleanup_fields)(SF_SERVICE_CONFIG(name)* handle) \
{ \
/*Codes_SRS_SF_SERVICE_CONFIG_42_035: [ For each config value: ]*/ \
SF_SERVICE_CONFIG_EXPANDED_MU_FOR_EACH_2_KEEP_1(DO_CLEANUP_IF_NEEDED, handle, SF_SERVICE_CONFIG_EXPAND_PARAMS(__VA_ARGS__)) \
} \
static void MU_C2A(SF_SERVICE_CONFIG(name), _dispose)(SF_SERVICE_CONFIG(name)* handle) \
{ \
MU_C2A(SF_SERVICE_CONFIG(name), _cleanup_fields)(handle); \
/*Codes_SRS_SF_SERVICE_CONFIG_42_042: [ MU_C2A(SF_SERVICE_CONFIG(name), _dispose) shall Release the activation_context. ]*/ \
(void)handle->activation_context->lpVtbl->Release(handle->activation_context); \
}
// Getters
#define SF_SERVICE_CONFIG_RETURN_TYPE__Bool bool
#define SF_SERVICE_CONFIG_RETURN_TYPE_uint32_t uint32_t
#define SF_SERVICE_CONFIG_RETURN_TYPE_uint64_t uint64_t
#define SF_SERVICE_CONFIG_RETURN_TYPE_char_ptr const char*
#define SF_SERVICE_CONFIG_RETURN_TYPE_wchar_ptr const wchar_t*
#define SF_SERVICE_CONFIG_RETURN_TYPE_thandle_rc_string THANDLE(RC_STRING)
#define SF_SERVICE_CONFIG_RETURN_TYPE(type) MU_C2A(SF_SERVICE_CONFIG_RETURN_TYPE_, type)
#define SF_SERVICE_CONFIG_INIT_RETURN__Bool
#define SF_SERVICE_CONFIG_INIT_RETURN_uint32_t
#define SF_SERVICE_CONFIG_INIT_RETURN_uint64_t
#define SF_SERVICE_CONFIG_INIT_RETURN_char_ptr
#define SF_SERVICE_CONFIG_INIT_RETURN_wchar_ptr
#define SF_SERVICE_CONFIG_INIT_RETURN_thandle_rc_string = NULL
#define SF_SERVICE_CONFIG_INIT_RETURN(type) MU_C2A(SF_SERVICE_CONFIG_INIT_RETURN_, type)
/*Codes_SRS_SF_SERVICE_CONFIG_42_045: [ ...false if the type is bool ]*/
#define SF_SERVICE_CONFIG_GETTER_ERROR__Bool false
/*Codes_SRS_SF_SERVICE_CONFIG_42_046: [ ...UINT32_MAX if the type is uint32_t ]*/
#define SF_SERVICE_CONFIG_GETTER_ERROR_uint32_t UINT32_MAX
/*Codes_SRS_SF_SERVICE_CONFIG_42_047: [ ...UINT64_MAX if the type is uint64_t ]*/
#define SF_SERVICE_CONFIG_GETTER_ERROR_uint64_t UINT64_MAX
/*Codes_SRS_SF_SERVICE_CONFIG_42_048: [ ...NULL otherwise ]*/
#define SF_SERVICE_CONFIG_GETTER_ERROR_char_ptr NULL
#define SF_SERVICE_CONFIG_GETTER_ERROR_wchar_ptr NULL
#define SF_SERVICE_CONFIG_GETTER_ERROR_thandle_rc_string NULL
#define SF_SERVICE_CONFIG_GETTER_ERROR(type) MU_C2(SF_SERVICE_CONFIG_GETTER_ERROR_, type)
#define SF_SERVICE_CONFIG_GETTER_DO_ASSIGN__Bool(lval, rval) lval = rval
#define SF_SERVICE_CONFIG_GETTER_DO_ASSIGN_uint32_t(lval, rval) lval = rval
#define SF_SERVICE_CONFIG_GETTER_DO_ASSIGN_uint64_t(lval, rval) lval = rval
#define SF_SERVICE_CONFIG_GETTER_DO_ASSIGN_char_ptr(lval, rval) lval = rval
#define SF_SERVICE_CONFIG_GETTER_DO_ASSIGN_wchar_ptr(lval, rval) lval = rval
/*Codes_SRS_SF_SERVICE_CONFIG_42_049: [ If the type is thandle_rc_string then the returned value will be set using THANDLE_INITIALIZE and the caller will have a reference they must free. ]*/
#define SF_SERVICE_CONFIG_GETTER_DO_ASSIGN_thandle_rc_string(lval, rval) THANDLE_INITIALIZE(RC_STRING)(&lval, rval)
#define SF_SERVICE_CONFIG_GETTER_DO_ASSIGN(field_type, lval, rval) MU_C2(SF_SERVICE_CONFIG_GETTER_DO_ASSIGN_, field_type)(lval, rval)
#define SF_SERVICE_CONFIG_DEFINE_GETTER(name, field_type, field_name) \
SF_SERVICE_CONFIG_RETURN_TYPE(field_type) SF_SERVICE_CONFIG_GETTER(name, field_name)(THANDLE(SF_SERVICE_CONFIG(name)) handle) \
{ \
SF_SERVICE_CONFIG_RETURN_TYPE(field_type) result SF_SERVICE_CONFIG_INIT_RETURN(field_type); \
if (handle == NULL) \
{ \
/*Codes_SRS_SF_SERVICE_CONFIG_42_044: [ If handle is NULL then SF_SERVICE_CONFIG_GETTER(name, field_name) shall fail and return... ]*/ \
LogError("Invalid args: THANDLE(" MU_TOSTRING(SF_SERVICE_CONFIG(name)) ") handle = %p", handle); \
SF_SERVICE_CONFIG_GETTER_DO_ASSIGN(field_type, result, SF_SERVICE_CONFIG_GETTER_ERROR(field_type)); \
} \
else \
{ \
/*Codes_SRS_SF_SERVICE_CONFIG_42_050: [ SF_SERVICE_CONFIG_GETTER(name, field_name) shall return the configuration value for field_name. ]*/ \
SF_SERVICE_CONFIG_GETTER_DO_ASSIGN(field_type, result, handle->field_name); \
} \
return result; \
} \
#ifdef __cplusplus
}
#endif
#endif /* SF_SERVICE_CONFIG_H */

Просмотреть файл

@ -12,6 +12,7 @@ if(${run_unittests})
build_test_folder(fabric_async_op_wrapper_ut)
build_test_folder(fabric_async_op_sync_wrapper_ut)
build_test_folder(hresult_to_string_ut)
build_test_folder(sf_service_config_ut)
build_test_folder(sf_c_util_reals_ut)
endif()

Просмотреть файл

@ -0,0 +1,23 @@
#Copyright (c) Microsoft. All rights reserved.
#Licensed under the MIT license. See LICENSE file in the project root for full license information.
compileAsC11()
set(theseTestsName sf_service_config_ut)
set(${theseTestsName}_test_files
${theseTestsName}.c
)
set(${theseTestsName}_c_files
test_sf_service_config.c
)
set(${theseTestsName}_h_files
sf_service_config_ut_helpers.h
test_sf_service_config.h
../../inc/sf_c_util/sf_service_config.h
)
include_directories($<TARGET_PROPERTY:FabricClient,INTERFACE_INCLUDE_DIRECTORIES>)
build_test_artifacts(${theseTestsName} "tests/sf_c_util" ADDITIONAL_LIBS debug FabricUUIDD optimized FabricUUID c_pal_reals c_util_reals c_util_test_helpers)

Просмотреть файл

@ -0,0 +1,842 @@
// Copyright (c) Microsoft. All rights reserved.
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <wchar.h>
#include "fabricruntime.h"
#include "fabrictypes.h"
#include "macro_utils/macro_utils.h"
#include "real_gballoc_ll.h"
static void* my_gballoc_malloc(size_t size)
{
return real_gballoc_ll_malloc(size);
}
static void my_gballoc_free(void* ptr)
{
real_gballoc_ll_free(ptr);
}
#include "testrunnerswitcher.h"
#include "umock_c/umock_c.h"
#include "umock_c/umocktypes.h"
#include "umock_c/umocktypes_stdint.h"
#include "umock_c/umocktypes_charptr.h"
#include "umock_c/umocktypes_wcharptr.h"
#include "umock_c/umock_c_negative_tests.h"
#define ENABLE_MOCKS
#include "c_pal/gballoc_hl.h"
#include "c_pal/gballoc_hl_redirect.h"
#include "c_pal/string_utils.h"
#include "c_util/rc_string.h"
#include "c_util/thandle.h"
#include "sf_c_util/configuration_reader.h"
#undef ENABLE_MOCKS
// Must include umock_c_prod so mocks are not expanded in real_rc_string
#include "umock_c/umock_c_prod.h"
#include "real_gballoc_hl.h"
#include "real_rc_string.h"
#include "real_string_utils.h"
#include "c_util_test_helpers/rc_string_test_decl.h"
#include "c_util_test_helpers/rc_string_test_type.h"
#include "sf_service_config_ut_helpers.h"
#include "test_sf_service_config.h"
#include "sf_c_util/sf_service_config.h"
CTEST_DECLARE_EQUALITY_ASSERTION_FUNCTIONS_FOR_TYPE(TEST_THANDLE_RC_STRING);
CTEST_DEFINE_EQUALITY_ASSERTION_FUNCTIONS_FOR_TYPE(TEST_THANDLE_RC_STRING, );
static TEST_MUTEX_HANDLE test_serialize_mutex;
RC_STRING_TEST_DECL(
empty_string, ""
)
typedef THANDLE(RC_STRING) thandle_rc_string;
static const wchar_t* expected_config_package_name = L"default_config";
static const wchar_t* expected_section_name = L"MyConfigSectionName";
TEST_SF_SERVICE_CONFIG_DEFINE_CONFIGURATION_READER_HOOKS(my_config, MY_CONFIG_TEST_PARAMS)
TEST_SF_SERVICE_CONFIG_DEFINE_EXPECTED_CALL_HELPERS(my_config, expected_config_package_name, expected_section_name, MY_CONFIG_TEST_PARAMS)
MU_DEFINE_ENUM_STRINGS(UMOCK_C_ERROR_CODE, UMOCK_C_ERROR_CODE_VALUES)
static void on_umock_c_error(UMOCK_C_ERROR_CODE error_code)
{
ASSERT_FAIL("umock_c reported error :%" PRI_MU_ENUM "", MU_ENUM_VALUE(UMOCK_C_ERROR_CODE, error_code));
}
BEGIN_TEST_SUITE(TEST_SUITE_NAME_FROM_CMAKE)
TEST_SUITE_INITIALIZE(suite_init)
{
ASSERT_ARE_EQUAL(int, 0, real_gballoc_hl_init(NULL, NULL));
test_serialize_mutex = TEST_MUTEX_CREATE();
ASSERT_IS_NOT_NULL(test_serialize_mutex);
ASSERT_ARE_EQUAL(int, 0, umock_c_init(on_umock_c_error));
ASSERT_ARE_EQUAL(int, 0, umocktypes_stdint_register_types());
ASSERT_ARE_EQUAL(int, 0, umocktypes_charptr_register_types());
ASSERT_ARE_EQUAL(int, 0, umocktypes_wcharptr_register_types());
ASSERT_ARE_EQUAL(int, 0, umocktypes_THANDLE_RC_STRING_register_types(), "umocktypes_THANDLE_RC_STRING_register_types");
REGISTER_RC_STRING_GLOBAL_MOCK_HOOKS();
REGISTER_STRING_UTILS_GLOBAL_MOCK_HOOK();
REGISTER_GBALLOC_HL_GLOBAL_MOCK_HOOK();
REGISTER_GLOBAL_MOCK_HOOK(malloc, my_gballoc_malloc);
REGISTER_GLOBAL_MOCK_FAIL_RETURN(malloc_flex, NULL);
REGISTER_GLOBAL_MOCK_FAIL_RETURN(realloc, NULL);
REGISTER_GLOBAL_MOCK_FAIL_RETURN(realloc_2, NULL);
REGISTER_GLOBAL_MOCK_FAIL_RETURN(realloc_flex, NULL);
REGISTER_GLOBAL_MOCK_HOOK(free, my_gballoc_free);
TEST_SF_SERVICE_CONFIG_HOOK_CONFIGURATION_READER(my_config)
rc_string_test_init_statics();
}
TEST_SUITE_CLEANUP(suite_cleanup)
{
umock_c_deinit();
rc_string_test_cleanup_statics();
TEST_MUTEX_DESTROY(test_serialize_mutex);
real_gballoc_hl_deinit();
}
TEST_FUNCTION_INITIALIZE(method_init)
{
if (TEST_MUTEX_ACQUIRE(test_serialize_mutex))
{
ASSERT_FAIL("Could not acquire test serialization mutex.");
}
// Initialize so each default value is returned (individual tests can override what gets returned)
TEST_SF_SERVICE_CONFIG_RESET(MY_CONFIG_TEST_PARAMS);
umock_c_reset_all_calls();
umock_c_negative_tests_init();
}
TEST_FUNCTION_CLEANUP(method_cleanup)
{
umock_c_negative_tests_deinit();
TEST_SF_SERVICE_CONFIG_CLEANUP(MY_CONFIG_TEST_PARAMS);
TEST_MUTEX_RELEASE(test_serialize_mutex);
}
/*Tests_SRS_SF_SERVICE_CONFIG_42_001: [ DECLARE_SF_SERVICE_CONFIG shall generate a THANDLE declaration of type SF_SERVICE_CONFIG(name). ]*/
static THANDLE(my_config_CONFIGURATION) my_config_CONFIGURATION_has_THANDLE = NULL;
// Tested implicitly in the cases below
/*Tests_SRS_SF_SERVICE_CONFIG_42_004: [ DEFINE_SF_SERVICE_CONFIG shall generate the SF_SERVICE_CONFIG(name) struct. ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_005: [ DEFINE_SF_SERVICE_CONFIG shall generate the implementation of SF_SERVICE_CONFIG_CREATE(name). ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_006: [ DECLARE_SF_SERVICE_CONFIG shall generate the implementation of the getter functions SF_SERVICE_CONFIG_GETTER(name, param) for each of the configurations provided. ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_007: [ SF_SERVICE_CONFIG shall expand to the name of the configuration module by appending the suffix _CONFIGURATION. ]*/
TEST_FUNCTION(SF_SERVICE_CONFIG_macro_expands_to_name)
{
// arrange
// act
const char* name = MU_TOSTRING(SF_SERVICE_CONFIG(name));
// assert
ASSERT_ARE_EQUAL(char_ptr, "name_CONFIGURATION", name);
}
//
// SF_SERVICE_CONFIG_CREATE
//
/*Tests_SRS_SF_SERVICE_CONFIG_42_008: [ SF_SERVICE_CONFIG_CREATE shall expand to the name of the create function for the configuration module by appending the suffix _configuration_create. ]*/
TEST_FUNCTION(SF_SERVICE_CONFIG_CREATE_macro_expands_to_name)
{
// arrange
// act
const char* name = MU_TOSTRING(SF_SERVICE_CONFIG_CREATE(name));
// assert
ASSERT_ARE_EQUAL(char_ptr, "name_configuration_create", name);
}
/*Tests_SRS_SF_SERVICE_CONFIG_42_009: [ If activation_context is NULL then SF_SERVICE_CONFIG_CREATE(name) shall fail and return NULL. ]*/
TEST_FUNCTION(SF_SERVICE_CONFIG_CREATE_with_NULL_activation_context_fails)
{
// arrange
// act
THANDLE(SF_SERVICE_CONFIG(my_config)) result = SF_SERVICE_CONFIG_CREATE(my_config)(NULL);
// assert
ASSERT_IS_NULL(result);
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
}
/*Tests_SRS_SF_SERVICE_CONFIG_42_002: [ DECLARE_SF_SERVICE_CONFIG shall generate a mockable create function SF_SERVICE_CONFIG_CREATE(name) which takes an IFabricCodePackageActivationContext* and produces the THANDLE. ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_010: [ SF_SERVICE_CONFIG_CREATE(name) shall allocate the THANDLE(SF_SERVICE_CONFIG(name)) with MU_C2A(SF_SERVICE_CONFIG(name), _dispose) as the dispose function. ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_011: [ SF_SERVICE_CONFIG_CREATE(name) shall call AddRef and store the activation_context. ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_012: [ SF_SERVICE_CONFIG_CREATE(name) shall store the sf_config_name and sf_parameters_section_name. ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_013: [ For each configuration value with name config_name: ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_014: [ If the type is bool then: ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_015: [ SF_SERVICE_CONFIG_CREATE(name) shall call configuration_reader_get_bool with the activation_context, sf_config_name, sf_parameters_section_name, and SF_SERVICE_CONFIG_PARAMETER_NAME_config_name. ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_016: [ If the type is uint32_t then: ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_017: [ SF_SERVICE_CONFIG_CREATE(name) shall call configuration_reader_get_uint32_t with the activation_context, sf_config_name, sf_parameters_section_name, and SF_SERVICE_CONFIG_PARAMETER_NAME_config_name. ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_019: [ If the type is uint64_t then: ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_020: [ SF_SERVICE_CONFIG_CREATE(name) shall call configuration_reader_get_uint64_t with the activation_context, sf_config_name, sf_parameters_section_name, and SF_SERVICE_CONFIG_PARAMETER_NAME_config_name. ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_022: [ If the type is char_ptr then: ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_023: [ SF_SERVICE_CONFIG_CREATE(name) shall call configuration_reader_get_char_string with the activation_context, sf_config_name, sf_parameters_section_name, and SF_SERVICE_CONFIG_PARAMETER_NAME_config_name. ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_026: [ If the type is wchar_ptr then: ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_027: [ SF_SERVICE_CONFIG_CREATE(name) shall call configuration_reader_get_wchar_string with the activation_context, sf_config_name, sf_parameters_section_name, and SF_SERVICE_CONFIG_PARAMETER_NAME_config_name. ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_030: [ If the type is thandle_rc_string then: ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_031: [ SF_SERVICE_CONFIG_CREATE(name) shall call configuration_reader_get_thandle_rc_string with the activation_context, sf_config_name, sf_parameters_section_name, and SF_SERVICE_CONFIG_PARAMETER_NAME_config_name. ]*/
TEST_FUNCTION(SF_SERVICE_CONFIG_CREATE_with_normal_values_for_all_types_succeeds)
{
// arrange
TEST_SF_SERVICE_CONFIG_EXPECT_ALL_READ(my_config)();
// act
THANDLE(SF_SERVICE_CONFIG(my_config)) result = SF_SERVICE_CONFIG_CREATE(my_config)(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(my_config));
// assert
ASSERT_IS_NOT_NULL(result);
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
// cleanup
THANDLE_ASSIGN(SF_SERVICE_CONFIG(my_config))(&result, NULL);
}
/*Tests_SRS_SF_SERVICE_CONFIG_42_034: [ If there are any errors then SF_SERVICE_CONFIG_CREATE(name) shall fail and return NULL. ]*/
TEST_FUNCTION(SF_SERVICE_CONFIG_CREATE_fails_when_underlying_functions_fail)
{
// arrange
TEST_SF_SERVICE_CONFIG_EXPECT_ALL_READ(my_config)();
umock_c_negative_tests_snapshot();
for (size_t i = 0; i < umock_c_negative_tests_call_count(); i++)
{
if (umock_c_negative_tests_can_call_fail(i))
{
umock_c_negative_tests_reset();
umock_c_negative_tests_fail_call(i);
/// act
THANDLE(SF_SERVICE_CONFIG(my_config)) result = SF_SERVICE_CONFIG_CREATE(my_config)(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(my_config));
/// assert
ASSERT_IS_NULL(result, "On failed call %zu", i);
}
}
}
/*Tests_SRS_SF_SERVICE_CONFIG_42_016: [ If the type is uint32_t then: ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_017: [ SF_SERVICE_CONFIG_CREATE(name) shall call configuration_reader_get_uint32_t with the activation_context, sf_config_name, sf_parameters_section_name, and SF_SERVICE_CONFIG_PARAMETER_NAME_config_name. ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_018: [ If the result is UINT32_MAX then SF_SERVICE_CONFIG_CREATE(name) shall fail and return NULL. ]*/
TEST_FUNCTION(SF_SERVICE_CONFIG_CREATE_fails_when_uint32_t_value_is_UINT32_MAX)
{
// arrange
TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(parameter_3) = UINT32_MAX;
TEST_SF_SERVICE_CONFIG_EXPECT_READ_UP_TO(my_config)(TEST_SF_SERVICE_CONFIG_INDEX_OF_CONFIG(my_config, parameter_3));
// act
THANDLE(SF_SERVICE_CONFIG(my_config)) result = SF_SERVICE_CONFIG_CREATE(my_config)(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(my_config));
// assert
ASSERT_IS_NULL(result);
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
}
/*Tests_SRS_SF_SERVICE_CONFIG_42_019: [ If the type is uint64_t then: ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_020: [ SF_SERVICE_CONFIG_CREATE(name) shall call configuration_reader_get_uint64_t with the activation_context, sf_config_name, sf_parameters_section_name, and SF_SERVICE_CONFIG_PARAMETER_NAME_config_name. ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_021: [ If the result is UINT64_MAX then SF_SERVICE_CONFIG_CREATE(name) shall fail and return NULL. ]*/
TEST_FUNCTION(SF_SERVICE_CONFIG_CREATE_fails_when_uint64_t_value_is_UINT64_MAX)
{
// arrange
TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(parameter_1) = UINT64_MAX;
TEST_SF_SERVICE_CONFIG_EXPECT_READ_UP_TO(my_config)(TEST_SF_SERVICE_CONFIG_INDEX_OF_CONFIG(my_config, parameter_1));
// act
THANDLE(SF_SERVICE_CONFIG(my_config)) result = SF_SERVICE_CONFIG_CREATE(my_config)(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(my_config));
// assert
ASSERT_IS_NULL(result);
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
}
/*Tests_SRS_SF_SERVICE_CONFIG_42_022: [ If the type is char_ptr then: ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_023: [ SF_SERVICE_CONFIG_CREATE(name) shall call configuration_reader_get_char_string with the activation_context, sf_config_name, sf_parameters_section_name, and SF_SERVICE_CONFIG_PARAMETER_NAME_config_name. ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_024: [ If the value is an empty string then SF_SERVICE_CONFIG_CREATE(name) shall free the string and set it to NULL. ]*/
TEST_FUNCTION(SF_SERVICE_CONFIG_CREATE_with_empty_optional_string_succeeds)
{
// arrange
TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(string_option_optional) = "";
TEST_SF_SERVICE_CONFIG_EXPECT_ALL_READ(my_config)();
// act
THANDLE(SF_SERVICE_CONFIG(my_config)) result = SF_SERVICE_CONFIG_CREATE(my_config)(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(my_config));
// assert
ASSERT_IS_NOT_NULL(result);
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
// cleanup
THANDLE_ASSIGN(SF_SERVICE_CONFIG(my_config))(&result, NULL);
}
/*Tests_SRS_SF_SERVICE_CONFIG_42_026: [ If the type is wchar_ptr then: ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_027: [ SF_SERVICE_CONFIG_CREATE(name) shall call configuration_reader_get_wchar_string with the activation_context, sf_config_name, sf_parameters_section_name, and SF_SERVICE_CONFIG_PARAMETER_NAME_config_name. ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_028: [ If the value is an empty string then SF_SERVICE_CONFIG_CREATE(name) shall free the string and set it to NULL. ]*/
TEST_FUNCTION(SF_SERVICE_CONFIG_CREATE_with_empty_optional_wide_string_succeeds)
{
// arrange
TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(wide_string_option_optional) = L"";
TEST_SF_SERVICE_CONFIG_EXPECT_ALL_READ(my_config)();
// act
THANDLE(SF_SERVICE_CONFIG(my_config)) result = SF_SERVICE_CONFIG_CREATE(my_config)(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(my_config));
// assert
ASSERT_IS_NOT_NULL(result);
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
// cleanup
THANDLE_ASSIGN(SF_SERVICE_CONFIG(my_config))(&result, NULL);
}
/*Tests_SRS_SF_SERVICE_CONFIG_42_030: [ If the type is thandle_rc_string then: ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_031: [ SF_SERVICE_CONFIG_CREATE(name) shall call configuration_reader_get_thandle_rc_string with the activation_context, sf_config_name, sf_parameters_section_name, and SF_SERVICE_CONFIG_PARAMETER_NAME_config_name. ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_032: [ If the value is an empty string then SF_SERVICE_CONFIG_CREATE(name) shall free the string and set it to NULL. ]*/
TEST_FUNCTION(SF_SERVICE_CONFIG_CREATE_with_empty_optional_thandle_rc_string_succeeds)
{
// arrange
THANDLE_ASSIGN(real_RC_STRING)(&TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(string_option_in_thandle_optional).x, g.empty_string);
TEST_SF_SERVICE_CONFIG_EXPECT_ALL_READ(my_config)();
// act
THANDLE(SF_SERVICE_CONFIG(my_config)) result = SF_SERVICE_CONFIG_CREATE(my_config)(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(my_config));
// assert
ASSERT_IS_NOT_NULL(result);
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
// cleanup
THANDLE_ASSIGN(SF_SERVICE_CONFIG(my_config))(&result, NULL);
}
/*Tests_SRS_SF_SERVICE_CONFIG_42_022: [ If the type is char_ptr then: ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_023: [ SF_SERVICE_CONFIG_CREATE(name) shall call configuration_reader_get_char_string with the activation_context, sf_config_name, sf_parameters_section_name, and SF_SERVICE_CONFIG_PARAMETER_NAME_config_name. ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_024: [ If the value is an empty string then SF_SERVICE_CONFIG_CREATE(name) shall free the string and set it to NULL. ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_025: [ If the configuration value is CONFIG_REQUIRED and the value is NULL then SF_SERVICE_CONFIG_CREATE(name) shall fail and return NULL. ]*/
TEST_FUNCTION(SF_SERVICE_CONFIG_CREATE_with_empty_required_string_fails)
{
// arrange
TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(string_option) = "";
TEST_SF_SERVICE_CONFIG_EXPECT_READ_UP_TO(my_config)(TEST_SF_SERVICE_CONFIG_INDEX_OF_CONFIG(my_config, string_option));
// act
THANDLE(SF_SERVICE_CONFIG(my_config)) result = SF_SERVICE_CONFIG_CREATE(my_config)(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(my_config));
// assert
ASSERT_IS_NULL(result);
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
}
/*Tests_SRS_SF_SERVICE_CONFIG_42_022: [ If the type is char_ptr then: ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_023: [ SF_SERVICE_CONFIG_CREATE(name) shall call configuration_reader_get_char_string with the activation_context, sf_config_name, sf_parameters_section_name, and SF_SERVICE_CONFIG_PARAMETER_NAME_config_name. ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_025: [ If the configuration value is CONFIG_REQUIRED and the value is NULL then SF_SERVICE_CONFIG_CREATE(name) shall fail and return NULL. ]*/
TEST_FUNCTION(SF_SERVICE_CONFIG_CREATE_with_NULL_required_string_fails)
{
// arrange
TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(string_option) = NULL;
TEST_SF_SERVICE_CONFIG_EXPECT_READ_UP_TO(my_config)(TEST_SF_SERVICE_CONFIG_INDEX_OF_CONFIG(my_config, string_option));
// act
THANDLE(SF_SERVICE_CONFIG(my_config)) result = SF_SERVICE_CONFIG_CREATE(my_config)(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(my_config));
// assert
ASSERT_IS_NULL(result);
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
}
/*Tests_SRS_SF_SERVICE_CONFIG_42_026: [ If the type is wchar_ptr then: ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_027: [ SF_SERVICE_CONFIG_CREATE(name) shall call configuration_reader_get_wchar_string with the activation_context, sf_config_name, sf_parameters_section_name, and SF_SERVICE_CONFIG_PARAMETER_NAME_config_name. ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_028: [ If the value is an empty string then SF_SERVICE_CONFIG_CREATE(name) shall free the string and set it to NULL. ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_029: [ If the configuration value is CONFIG_REQUIRED and the value is NULL then SF_SERVICE_CONFIG_CREATE(name) shall fail and return NULL. ]*/
TEST_FUNCTION(SF_SERVICE_CONFIG_CREATE_with_empty_required_wide_string_fails)
{
// arrange
TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(wide_string_option) = L"";
TEST_SF_SERVICE_CONFIG_EXPECT_READ_UP_TO(my_config)(TEST_SF_SERVICE_CONFIG_INDEX_OF_CONFIG(my_config, wide_string_option));
// act
THANDLE(SF_SERVICE_CONFIG(my_config)) result = SF_SERVICE_CONFIG_CREATE(my_config)(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(my_config));
// assert
ASSERT_IS_NULL(result);
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
}
/*Tests_SRS_SF_SERVICE_CONFIG_42_026: [ If the type is wchar_ptr then: ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_027: [ SF_SERVICE_CONFIG_CREATE(name) shall call configuration_reader_get_wchar_string with the activation_context, sf_config_name, sf_parameters_section_name, and SF_SERVICE_CONFIG_PARAMETER_NAME_config_name. ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_029: [ If the configuration value is CONFIG_REQUIRED and the value is NULL then SF_SERVICE_CONFIG_CREATE(name) shall fail and return NULL. ]*/
TEST_FUNCTION(SF_SERVICE_CONFIG_CREATE_with_NULL_required_wide_string_fails)
{
// arrange
TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(wide_string_option) = NULL;
TEST_SF_SERVICE_CONFIG_EXPECT_READ_UP_TO(my_config)(TEST_SF_SERVICE_CONFIG_INDEX_OF_CONFIG(my_config, wide_string_option));
// act
THANDLE(SF_SERVICE_CONFIG(my_config)) result = SF_SERVICE_CONFIG_CREATE(my_config)(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(my_config));
// assert
ASSERT_IS_NULL(result);
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
}
/*Tests_SRS_SF_SERVICE_CONFIG_42_030: [ If the type is thandle_rc_string then: ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_031: [ SF_SERVICE_CONFIG_CREATE(name) shall call configuration_reader_get_thandle_rc_string with the activation_context, sf_config_name, sf_parameters_section_name, and SF_SERVICE_CONFIG_PARAMETER_NAME_config_name. ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_032: [ If the value is an empty string then SF_SERVICE_CONFIG_CREATE(name) shall free the string and set it to NULL. ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_033: [ If the configuration value is CONFIG_REQUIRED and the value is NULL then SF_SERVICE_CONFIG_CREATE(name) shall fail and return NULL. ]*/
TEST_FUNCTION(SF_SERVICE_CONFIG_CREATE_with_empty_required_thandle_rcstring_fails)
{
// arrange
THANDLE_ASSIGN(real_RC_STRING)(&TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(string_option_in_thandle).x, g.empty_string);
TEST_SF_SERVICE_CONFIG_EXPECT_READ_UP_TO(my_config)(TEST_SF_SERVICE_CONFIG_INDEX_OF_CONFIG(my_config, string_option_in_thandle));
// act
THANDLE(SF_SERVICE_CONFIG(my_config)) result = SF_SERVICE_CONFIG_CREATE(my_config)(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(my_config));
// assert
ASSERT_IS_NULL(result);
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
}
/*Tests_SRS_SF_SERVICE_CONFIG_42_030: [ If the type is thandle_rc_string then: ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_031: [ SF_SERVICE_CONFIG_CREATE(name) shall call configuration_reader_get_thandle_rc_string with the activation_context, sf_config_name, sf_parameters_section_name, and SF_SERVICE_CONFIG_PARAMETER_NAME_config_name. ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_033: [ If the configuration value is CONFIG_REQUIRED and the value is NULL then SF_SERVICE_CONFIG_CREATE(name) shall fail and return NULL. ]*/
TEST_FUNCTION(SF_SERVICE_CONFIG_CREATE_with_NULL_required_thandle_rcstring_fails)
{
// arrange
THANDLE_ASSIGN(real_RC_STRING)(&TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(string_option_in_thandle).x, NULL);
TEST_SF_SERVICE_CONFIG_EXPECT_READ_UP_TO(my_config)(TEST_SF_SERVICE_CONFIG_INDEX_OF_CONFIG(my_config, string_option_in_thandle));
// act
THANDLE(SF_SERVICE_CONFIG(my_config)) result = SF_SERVICE_CONFIG_CREATE(my_config)(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(my_config));
// assert
ASSERT_IS_NULL(result);
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
}
//
// Dispose
//
/*Tests_SRS_SF_SERVICE_CONFIG_42_035: [ For each config value: ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_036: [ If the type is char_ptr then MU_C2A(SF_SERVICE_CONFIG(name), _dispose) shall free the string. ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_038: [ If the type is wchar_ptr then MU_C2A(SF_SERVICE_CONFIG(name), _dispose) shall free the string. ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_040: [ If the type is thandle_rc_string then MU_C2A(SF_SERVICE_CONFIG(name), _dispose) shall assign the THANDLE to NULL. ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_042: [ MU_C2A(SF_SERVICE_CONFIG(name), _dispose) shall Release the activation_context. ]*/
TEST_FUNCTION(SF_SERVICE_CONFIG_Dispose_frees_all_strings)
{
// arrange
TEST_SF_SERVICE_CONFIG_EXPECT_ALL_READ(my_config)();
THANDLE(SF_SERVICE_CONFIG(my_config)) config = SF_SERVICE_CONFIG_CREATE(my_config)(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(my_config));
ASSERT_IS_NOT_NULL(config);
TEST_SF_SERVICE_CONFIG_EXPECT_DESTROY(my_config)();
// act
THANDLE_ASSIGN(SF_SERVICE_CONFIG(my_config))(&config, NULL);
// assert
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
}
/*Tests_SRS_SF_SERVICE_CONFIG_42_042: [ MU_C2A(SF_SERVICE_CONFIG(name), _dispose) shall Release the activation_context. ]*/
TEST_FUNCTION(SF_SERVICE_CONFIG_Dispose_works_when_optional_strings_are_null)
{
// arrange
TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(string_option_optional) = "";
TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(wide_string_option_optional) = L"";
THANDLE_ASSIGN(real_RC_STRING)(&TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(string_option_in_thandle_optional).x, g.empty_string);
TEST_SF_SERVICE_CONFIG_EXPECT_ALL_READ(my_config)();
THANDLE(SF_SERVICE_CONFIG(my_config)) config = SF_SERVICE_CONFIG_CREATE(my_config)(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(my_config));
ASSERT_IS_NOT_NULL(config);
TEST_SF_SERVICE_CONFIG_EXPECT_DESTROY(my_config)();
// act
THANDLE_ASSIGN(SF_SERVICE_CONFIG(my_config))(&config, NULL);
// assert
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
}
//
// SF_SERVICE_CONFIG_GETTER
//
/*Tests_SRS_SF_SERVICE_CONFIG_42_043: [ SF_SERVICE_CONFIG_GETTER shall expand to the name of the getter function for the configuration module and the given param by concatenating the name, the string _configuration_get, and the param. ]*/
TEST_FUNCTION(SF_SERVICE_CONFIG_GETTER_macro_expands_to_name_of_getter_function)
{
// arrange
// act
const char* name = MU_TOSTRING(SF_SERVICE_CONFIG_GETTER(name, parameter));
// assert
ASSERT_ARE_EQUAL(char_ptr, "name_configuration_get_parameter", name);
}
/*Tests_SRS_SF_SERVICE_CONFIG_42_044: [ If handle is NULL then SF_SERVICE_CONFIG_GETTER(name, field_name) shall fail and return... ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_045: [ ...false if the type is bool ]*/
TEST_FUNCTION(SF_SERVICE_CONFIG_GETTER_for_bool_with_NULL_handle_returns_false)
{
// arrange
TEST_SF_SERVICE_CONFIG_EXPECT_ALL_READ(my_config)();
THANDLE(SF_SERVICE_CONFIG(my_config)) config = SF_SERVICE_CONFIG_CREATE(my_config)(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(my_config));
ASSERT_IS_NOT_NULL(config);
// act
bool result = SF_SERVICE_CONFIG_GETTER(my_config, some_flag)(NULL);
// assert
ASSERT_IS_FALSE(result);
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
// cleanup
THANDLE_ASSIGN(SF_SERVICE_CONFIG(my_config))(&config, NULL);
}
/*Tests_SRS_SF_SERVICE_CONFIG_42_044: [ If handle is NULL then SF_SERVICE_CONFIG_GETTER(name, field_name) shall fail and return... ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_046: [ ...UINT32_MAX if the type is uint32_t ]*/
TEST_FUNCTION(SF_SERVICE_CONFIG_GETTER_for_uint32_t_with_NULL_handle_returns_UINT32_MAX)
{
// arrange
TEST_SF_SERVICE_CONFIG_EXPECT_ALL_READ(my_config)();
THANDLE(SF_SERVICE_CONFIG(my_config)) config = SF_SERVICE_CONFIG_CREATE(my_config)(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(my_config));
ASSERT_IS_NOT_NULL(config);
// act
uint32_t result = SF_SERVICE_CONFIG_GETTER(my_config, parameter_3)(NULL);
// assert
ASSERT_ARE_EQUAL(uint32_t, UINT32_MAX, result);
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
// cleanup
THANDLE_ASSIGN(SF_SERVICE_CONFIG(my_config))(&config, NULL);
}
/*Tests_SRS_SF_SERVICE_CONFIG_42_044: [ If handle is NULL then SF_SERVICE_CONFIG_GETTER(name, field_name) shall fail and return... ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_047: [ ...UINT64_MAX if the type is uint64_t ]*/
TEST_FUNCTION(SF_SERVICE_CONFIG_GETTER_for_uint64_t_with_NULL_handle_returns_UINT64_MAX)
{
// arrange
TEST_SF_SERVICE_CONFIG_EXPECT_ALL_READ(my_config)();
THANDLE(SF_SERVICE_CONFIG(my_config)) config = SF_SERVICE_CONFIG_CREATE(my_config)(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(my_config));
ASSERT_IS_NOT_NULL(config);
// act
uint64_t result = SF_SERVICE_CONFIG_GETTER(my_config, parameter_1)(NULL);
// assert
ASSERT_ARE_EQUAL(uint64_t, UINT64_MAX, result);
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
// cleanup
THANDLE_ASSIGN(SF_SERVICE_CONFIG(my_config))(&config, NULL);
}
/*Tests_SRS_SF_SERVICE_CONFIG_42_044: [ If handle is NULL then SF_SERVICE_CONFIG_GETTER(name, field_name) shall fail and return... ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_048: [ ...NULL otherwise ]*/
TEST_FUNCTION(SF_SERVICE_CONFIG_GETTER_for_char_ptr_with_NULL_handle_returns_NULL)
{
// arrange
TEST_SF_SERVICE_CONFIG_EXPECT_ALL_READ(my_config)();
THANDLE(SF_SERVICE_CONFIG(my_config)) config = SF_SERVICE_CONFIG_CREATE(my_config)(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(my_config));
ASSERT_IS_NOT_NULL(config);
// act
const char* result = SF_SERVICE_CONFIG_GETTER(my_config, string_option)(NULL);
// assert
ASSERT_IS_NULL(result);
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
// cleanup
THANDLE_ASSIGN(SF_SERVICE_CONFIG(my_config))(&config, NULL);
}
/*Tests_SRS_SF_SERVICE_CONFIG_42_044: [ If handle is NULL then SF_SERVICE_CONFIG_GETTER(name, field_name) shall fail and return... ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_048: [ ...NULL otherwise ]*/
TEST_FUNCTION(SF_SERVICE_CONFIG_GETTER_for_wchar_ptr_with_NULL_handle_returns_NULL)
{
// arrange
TEST_SF_SERVICE_CONFIG_EXPECT_ALL_READ(my_config)();
THANDLE(SF_SERVICE_CONFIG(my_config)) config = SF_SERVICE_CONFIG_CREATE(my_config)(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(my_config));
ASSERT_IS_NOT_NULL(config);
// act
const wchar_t* result = SF_SERVICE_CONFIG_GETTER(my_config, wide_string_option)(NULL);
// assert
ASSERT_IS_NULL(result);
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
// cleanup
THANDLE_ASSIGN(SF_SERVICE_CONFIG(my_config))(&config, NULL);
}
/*Tests_SRS_SF_SERVICE_CONFIG_42_044: [ If handle is NULL then SF_SERVICE_CONFIG_GETTER(name, field_name) shall fail and return... ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_048: [ ...NULL otherwise ]*/
TEST_FUNCTION(SF_SERVICE_CONFIG_GETTER_for_thandle_rc_string_with_NULL_handle_returns_NULL)
{
// arrange
TEST_SF_SERVICE_CONFIG_EXPECT_ALL_READ(my_config)();
THANDLE(SF_SERVICE_CONFIG(my_config)) config = SF_SERVICE_CONFIG_CREATE(my_config)(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(my_config));
ASSERT_IS_NOT_NULL(config);
STRICT_EXPECTED_CALL(THANDLE_INITIALIZE(RC_STRING)(IGNORED_ARG, NULL));
// act
THANDLE(RC_STRING) result = SF_SERVICE_CONFIG_GETTER(my_config, string_option_in_thandle)(NULL);
// assert
ASSERT_IS_NULL(result);
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
// cleanup
THANDLE_ASSIGN(SF_SERVICE_CONFIG(my_config))(&config, NULL);
}
/*Tests_SRS_SF_SERVICE_CONFIG_42_003: [ DECLARE_SF_SERVICE_CONFIG shall generate mockable getter functions SF_SERVICE_CONFIG_GETTER(name, param) for each of the configurations provided. ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_050: [ SF_SERVICE_CONFIG_GETTER(name, field_name) shall return the configuration value for field_name. ]*/
TEST_FUNCTION(SF_SERVICE_CONFIG_GETTER_for_bool_with_true_value_returns_true)
{
// arrange
TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(some_flag) = true;
TEST_SF_SERVICE_CONFIG_EXPECT_ALL_READ(my_config)();
THANDLE(SF_SERVICE_CONFIG(my_config)) config = SF_SERVICE_CONFIG_CREATE(my_config)(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(my_config));
ASSERT_IS_NOT_NULL(config);
// act
bool result = SF_SERVICE_CONFIG_GETTER(my_config, some_flag)(config);
// assert
ASSERT_IS_TRUE(result);
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
// cleanup
THANDLE_ASSIGN(SF_SERVICE_CONFIG(my_config))(&config, NULL);
}
/*Tests_SRS_SF_SERVICE_CONFIG_42_050: [ SF_SERVICE_CONFIG_GETTER(name, field_name) shall return the configuration value for field_name. ]*/
TEST_FUNCTION(SF_SERVICE_CONFIG_GETTER_for_bool_with_false_value_returns_false)
{
// arrange
TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(some_flag) = false;
TEST_SF_SERVICE_CONFIG_EXPECT_ALL_READ(my_config)();
THANDLE(SF_SERVICE_CONFIG(my_config)) config = SF_SERVICE_CONFIG_CREATE(my_config)(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(my_config));
ASSERT_IS_NOT_NULL(config);
// act
bool result = SF_SERVICE_CONFIG_GETTER(my_config, some_flag)(config);
// assert
ASSERT_IS_FALSE(result);
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
// cleanup
THANDLE_ASSIGN(SF_SERVICE_CONFIG(my_config))(&config, NULL);
}
/*Tests_SRS_SF_SERVICE_CONFIG_42_050: [ SF_SERVICE_CONFIG_GETTER(name, field_name) shall return the configuration value for field_name. ]*/
TEST_FUNCTION(SF_SERVICE_CONFIG_GETTER_for_uint32_t_returns_value)
{
// arrange
TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(parameter_3) = 12345;
TEST_SF_SERVICE_CONFIG_EXPECT_ALL_READ(my_config)();
THANDLE(SF_SERVICE_CONFIG(my_config)) config = SF_SERVICE_CONFIG_CREATE(my_config)(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(my_config));
ASSERT_IS_NOT_NULL(config);
// act
uint32_t result = SF_SERVICE_CONFIG_GETTER(my_config, parameter_3)(config);
// assert
ASSERT_ARE_EQUAL(uint32_t, 12345, result);
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
// cleanup
THANDLE_ASSIGN(SF_SERVICE_CONFIG(my_config))(&config, NULL);
}
/*Tests_SRS_SF_SERVICE_CONFIG_42_050: [ SF_SERVICE_CONFIG_GETTER(name, field_name) shall return the configuration value for field_name. ]*/
TEST_FUNCTION(SF_SERVICE_CONFIG_GETTER_for_uint64_t_returns_value)
{
// arrange
TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(parameter_2) = 0x12345678FFFFFFFF;
TEST_SF_SERVICE_CONFIG_EXPECT_ALL_READ(my_config)();
THANDLE(SF_SERVICE_CONFIG(my_config)) config = SF_SERVICE_CONFIG_CREATE(my_config)(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(my_config));
ASSERT_IS_NOT_NULL(config);
// act
uint64_t result = SF_SERVICE_CONFIG_GETTER(my_config, parameter_2)(config);
// assert
ASSERT_ARE_EQUAL(uint64_t, 0x12345678FFFFFFFF, result);
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
// cleanup
THANDLE_ASSIGN(SF_SERVICE_CONFIG(my_config))(&config, NULL);
}
/*Tests_SRS_SF_SERVICE_CONFIG_42_050: [ SF_SERVICE_CONFIG_GETTER(name, field_name) shall return the configuration value for field_name. ]*/
TEST_FUNCTION(SF_SERVICE_CONFIG_GETTER_for_const_char_returns_string)
{
// arrange
TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(string_option) = "parameter value";
TEST_SF_SERVICE_CONFIG_EXPECT_ALL_READ(my_config)();
THANDLE(SF_SERVICE_CONFIG(my_config)) config = SF_SERVICE_CONFIG_CREATE(my_config)(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(my_config));
ASSERT_IS_NOT_NULL(config);
// act
const char* result = SF_SERVICE_CONFIG_GETTER(my_config, string_option)(config);
// assert
ASSERT_ARE_EQUAL(char_ptr, "parameter value", result);
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
// cleanup
THANDLE_ASSIGN(SF_SERVICE_CONFIG(my_config))(&config, NULL);
}
/*Tests_SRS_SF_SERVICE_CONFIG_42_050: [ SF_SERVICE_CONFIG_GETTER(name, field_name) shall return the configuration value for field_name. ]*/
TEST_FUNCTION(SF_SERVICE_CONFIG_GETTER_for_optional_const_char_empty_returns_NULL)
{
// arrange
TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(string_option_optional) = "";
TEST_SF_SERVICE_CONFIG_EXPECT_ALL_READ(my_config)();
THANDLE(SF_SERVICE_CONFIG(my_config)) config = SF_SERVICE_CONFIG_CREATE(my_config)(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(my_config));
ASSERT_IS_NOT_NULL(config);
// act
const char* result = SF_SERVICE_CONFIG_GETTER(my_config, string_option_optional)(config);
// assert
ASSERT_IS_NULL(result);
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
// cleanup
THANDLE_ASSIGN(SF_SERVICE_CONFIG(my_config))(&config, NULL);
}
/*Tests_SRS_SF_SERVICE_CONFIG_42_050: [ SF_SERVICE_CONFIG_GETTER(name, field_name) shall return the configuration value for field_name. ]*/
TEST_FUNCTION(SF_SERVICE_CONFIG_GETTER_for_const_wchar_returns_string)
{
// arrange
TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(wide_string_option) = L"parameter value";
TEST_SF_SERVICE_CONFIG_EXPECT_ALL_READ(my_config)();
THANDLE(SF_SERVICE_CONFIG(my_config)) config = SF_SERVICE_CONFIG_CREATE(my_config)(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(my_config));
ASSERT_IS_NOT_NULL(config);
// act
const wchar_t* result = SF_SERVICE_CONFIG_GETTER(my_config, wide_string_option)(config);
// assert
ASSERT_ARE_EQUAL(wchar_ptr, L"parameter value", result);
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
// cleanup
THANDLE_ASSIGN(SF_SERVICE_CONFIG(my_config))(&config, NULL);
}
/*Tests_SRS_SF_SERVICE_CONFIG_42_050: [ SF_SERVICE_CONFIG_GETTER(name, field_name) shall return the configuration value for field_name. ]*/
TEST_FUNCTION(SF_SERVICE_CONFIG_GETTER_for_optional_const_wchar_empty_returns_NULL)
{
// arrange
TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(wide_string_option_optional) = L"";
TEST_SF_SERVICE_CONFIG_EXPECT_ALL_READ(my_config)();
THANDLE(SF_SERVICE_CONFIG(my_config)) config = SF_SERVICE_CONFIG_CREATE(my_config)(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(my_config));
ASSERT_IS_NOT_NULL(config);
// act
const wchar_t* result = SF_SERVICE_CONFIG_GETTER(my_config, wide_string_option_optional)(config);
// assert
ASSERT_IS_NULL(result);
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
// cleanup
THANDLE_ASSIGN(SF_SERVICE_CONFIG(my_config))(&config, NULL);
}
/*Tests_SRS_SF_SERVICE_CONFIG_42_049: [ If the type is thandle_rc_string then the returned value will be set using THANDLE_INITIALIZE and the caller will have a reference they must free. ]*/
/*Tests_SRS_SF_SERVICE_CONFIG_42_050: [ SF_SERVICE_CONFIG_GETTER(name, field_name) shall return the configuration value for field_name. ]*/
TEST_FUNCTION(SF_SERVICE_CONFIG_GETTER_for_rc_string_returns_string)
{
// arrange
TEST_SF_SERVICE_CONFIG_EXPECT_ALL_READ(my_config)();
THANDLE(SF_SERVICE_CONFIG(my_config)) config = SF_SERVICE_CONFIG_CREATE(my_config)(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(my_config));
ASSERT_IS_NOT_NULL(config);
STRICT_EXPECTED_CALL(THANDLE_INITIALIZE(RC_STRING)(IGNORED_ARG, TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(string_option_in_thandle).x));
// act
THANDLE(RC_STRING) result = SF_SERVICE_CONFIG_GETTER(my_config, string_option_in_thandle)(config);
// assert
ASSERT_ARE_EQUAL(TEST_THANDLE_RC_STRING, TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(string_option_in_thandle).x, result);
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
// cleanup
THANDLE_ASSIGN(RC_STRING)(&result, NULL);
THANDLE_ASSIGN(SF_SERVICE_CONFIG(my_config))(&config, NULL);
}
/*Tests_SRS_SF_SERVICE_CONFIG_42_050: [ SF_SERVICE_CONFIG_GETTER(name, field_name) shall return the configuration value for field_name. ]*/
TEST_FUNCTION(SF_SERVICE_CONFIG_GETTER_for_rc_string_with_NULL_returns_NULL)
{
// arrange
THANDLE_ASSIGN(real_RC_STRING)(&TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(string_option_in_thandle_optional).x, g.empty_string);
TEST_SF_SERVICE_CONFIG_EXPECT_ALL_READ(my_config)();
THANDLE(SF_SERVICE_CONFIG(my_config)) config = SF_SERVICE_CONFIG_CREATE(my_config)(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(my_config));
ASSERT_IS_NOT_NULL(config);
STRICT_EXPECTED_CALL(THANDLE_INITIALIZE(RC_STRING)(IGNORED_ARG, NULL));
// act
THANDLE(RC_STRING) result = SF_SERVICE_CONFIG_GETTER(my_config, string_option_in_thandle_optional)(config);
// assert
ASSERT_IS_NULL(result);
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
// cleanup
THANDLE_ASSIGN(SF_SERVICE_CONFIG(my_config))(&config, NULL);
}
END_TEST_SUITE(TEST_SUITE_NAME_FROM_CMAKE)

Просмотреть файл

@ -0,0 +1,425 @@
// Copyright (C) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#ifndef SF_SERVICE_CONFIG_UT_HELPERS_H
#define SF_SERVICE_CONFIG_UT_HELPERS_H
#include <inttypes.h>
#include <stdbool.h>
#include <wchar.h>
#include "windows.h"
#include "fabricruntime.h"
#include "macro_utils/macro_utils.h"
#include "c_util/rc_string.h"
#include "c_util/thandle.h"
#include "c_pal/string_utils.h"
#include "sf_c_util/configuration_reader.h"
#include "sf_c_util/sf_service_config.h"
#include "umock_c/umock_c_prod.h"
// Setup the test hooks for configuration_reader to return configured values
#define TEST_SF_SERVICE_CONFIG_DEFINE_CONFIGURATION_READER_HOOKS(config_name, ...) \
/* This expands to a bunch of global variables for the values to return in the configuration reader */ \
SF_SERVICE_CONFIG_EXPANDED_MU_FOR_EACH_2(TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_DEFINE, SF_SERVICE_CONFIG_EXPAND_PARAMS(__VA_ARGS__))\
/* This expands to a bunch of global variables for the default values to return in the configuration reader */ \
SF_SERVICE_CONFIG_EXPANDED_MU_FOR_EACH_2(TEST_SF_SERVICE_CONFIG_DEFAULT_DEFINE, SF_SERVICE_CONFIG_EXPAND_PARAMS(__VA_ARGS__))\
/* This expands to the configuration reader mock hooks */ \
TEST_SF_SERVICE_CONFIG_DEFINE_CONFIGURATION_READER_HOOK(uint64_t, config_name, __VA_ARGS__) \
TEST_SF_SERVICE_CONFIG_DEFINE_CONFIGURATION_READER_HOOK(uint32_t, config_name, __VA_ARGS__) \
TEST_SF_SERVICE_CONFIG_DEFINE_CONFIGURATION_READER_HOOK(wchar_ptr, config_name, __VA_ARGS__) \
TEST_SF_SERVICE_CONFIG_DEFINE_CONFIGURATION_READER_HOOK(char_ptr, config_name, __VA_ARGS__) \
TEST_SF_SERVICE_CONFIG_DEFINE_CONFIGURATION_READER_HOOK(thandle_rc_string, config_name, __VA_ARGS__) \
TEST_SF_SERVICE_CONFIG_DEFINE_CONFIGURATION_READER_HOOK(bool, config_name, __VA_ARGS__) \
/* Creates variables "test_sf_service_config_NAME_index" which map the config name to its order in the list of configs (0 based index) */ \
TEST_SF_SERVICE_CONFIG_DEFINE_INDEX_OF(config_name, __VA_ARGS__) \
// In the test, each value which is returned by the reader hook can be referenced as TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(NAME)
// Example: TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(foo) = 42;
#define TEST_SF_SERVICE_CONFIG_DEFAULT_VALUE(name) MU_C2(sf_service_config_default_, name)
#define TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(name) MU_C2(sf_service_config_value_to_return_, name)
// Helper to get the index of the config (map the name to the index)
#define TEST_SF_SERVICE_CONFIG_INDEX_OF_CONFIG(name, field) MU_C3(test_sf_service_config_, name, _index_of)(TEST_SF_SERVICE_CONFIG_INDEX_OF_CONFIG_MACRO_COUNTER_NAME(field))
// Should be called in test suite setup
#define TEST_SF_SERVICE_CONFIG_HOOK_CONFIGURATION_READER(config_name) \
REGISTER_GLOBAL_MOCK_HOOK(configuration_reader_get_uint64_t, MU_C3(hook_, config_name, _configuration_reader_get_uint64_t)); \
REGISTER_GLOBAL_MOCK_HOOK(configuration_reader_get_uint32_t, MU_C3(hook_, config_name, _configuration_reader_get_uint32_t)); \
REGISTER_GLOBAL_MOCK_HOOK(configuration_reader_get_char_string, MU_C3(hook_, config_name, _configuration_reader_get_char_ptr)); \
REGISTER_GLOBAL_MOCK_HOOK(configuration_reader_get_thandle_rc_string, MU_C3(hook_, config_name, _configuration_reader_get_thandle_rc_string)); \
REGISTER_GLOBAL_MOCK_HOOK(configuration_reader_get_wchar_string, MU_C3(hook_, config_name, _configuration_reader_get_wchar_ptr)); \
REGISTER_GLOBAL_MOCK_HOOK(configuration_reader_get_bool, MU_C3(hook_, config_name, _configuration_reader_get__Bool)); \
MU_C2A(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(config_name), _vtbl).Release = MU_C2A(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(config_name), _Release); \
MU_C2A(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(config_name), _vtbl).AddRef = MU_C2A(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(config_name), _AddRef); \
MU_C2A(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(config_name), _storage).lpVtbl = &MU_C2A(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(config_name), _vtbl); \
TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(config_name) = &MU_C2A(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(config_name), _storage);
// Should be called in test method setup
#define TEST_SF_SERVICE_CONFIG_RESET(...) \
SF_SERVICE_CONFIG_EXPANDED_MU_FOR_EACH_2(TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_INIT_DEFAULT, SF_SERVICE_CONFIG_EXPAND_PARAMS(__VA_ARGS__))
// Should be called in test method cleanup
#define TEST_SF_SERVICE_CONFIG_CLEANUP(...) \
SF_SERVICE_CONFIG_EXPANDED_MU_FOR_EACH_2(TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_CLEANUP, SF_SERVICE_CONFIG_EXPAND_PARAMS(__VA_ARGS__))
// Should be called in a test where testing max values is desired
#define TEST_SF_SERVICE_CONFIG_SET_VALUES_TO_MAX(...) \
SF_SERVICE_CONFIG_EXPANDED_MU_FOR_EACH_2(TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_INIT_MAX, SF_SERVICE_CONFIG_EXPAND_PARAMS(__VA_ARGS__))
#define TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(name) MU_C2(name, _test_fabric_code_package_activation_context)
// Helper to expect the setup of the config, which should read all params
#define TEST_SF_SERVICE_CONFIG_EXPECT_ALL_READ(name) MU_C3(expect_, name, _read)
// Helper to expect the setup of the config, which should read all params up to an index then fail
#define TEST_SF_SERVICE_CONFIG_EXPECT_READ_UP_TO(name) MU_C3(expect_, name, _read_up_to)
// Helper to expect the cleanup of the config, which should free all the strings
#define TEST_SF_SERVICE_CONFIG_EXPECT_FREE_STRINGS(name) MU_C3(expect_, name, _free_strings)
// Helper to expect the destroy of the config
#define TEST_SF_SERVICE_CONFIG_EXPECT_DESTROY(name) MU_C3(expect_, name, _destroy)
// define expectation helpers
#define TEST_SF_SERVICE_CONFIG_DEFINE_EXPECTED_CALL_HELPERS(name, sf_config_name, sf_parameters_section_name, ...) \
static IFabricCodePackageActivationContextVtbl MU_C2A(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(name), _vtbl); \
static IFabricCodePackageActivationContext MU_C2A(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(name), _storage); \
static IFabricCodePackageActivationContext* TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(name); \
MOCK_FUNCTION_WITH_CODE(, ULONG, MU_C2A(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(name), _AddRef), IFabricCodePackageActivationContext*, This) \
MOCK_FUNCTION_END(0); \
MOCK_FUNCTION_WITH_CODE(, ULONG, MU_C2A(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(name), _Release), IFabricCodePackageActivationContext*, This) \
MOCK_FUNCTION_END(0); \
TEST_SF_SERVICE_CONFIG_DEFINE_EXPECT_READ(name, sf_config_name, sf_parameters_section_name, uint64_t) \
TEST_SF_SERVICE_CONFIG_DEFINE_EXPECT_READ(name, sf_config_name, sf_parameters_section_name, uint32_t) \
TEST_SF_SERVICE_CONFIG_DEFINE_EXPECT_READ(name, sf_config_name, sf_parameters_section_name, wchar_ptr) \
TEST_SF_SERVICE_CONFIG_DEFINE_EXPECT_READ(name, sf_config_name, sf_parameters_section_name, char_ptr) \
TEST_SF_SERVICE_CONFIG_DEFINE_EXPECT_READ(name, sf_config_name, sf_parameters_section_name, bool) \
TEST_SF_SERVICE_CONFIG_DEFINE_EXPECT_READ_THANDLE_RC_STRING(name, sf_config_name, sf_parameters_section_name) \
static void TEST_SF_SERVICE_CONFIG_EXPECT_ALL_READ(name)(void) \
{ \
STRICT_EXPECTED_CALL(malloc(IGNORED_ARG)); \
STRICT_EXPECTED_CALL(MU_C2A(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(name), _AddRef)(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(name))) \
.CallCannotFail(); \
SF_SERVICE_CONFIG_EXPANDED_MU_FOR_EACH_2_KEEP_1(TEST_SF_SERVICE_CONFIG_SETUP_EXPECTATION, name, SF_SERVICE_CONFIG_EXPAND_PARAMS(__VA_ARGS__)); \
} \
static void TEST_SF_SERVICE_CONFIG_EXPECT_READ_UP_TO(name)(uint32_t up_to_index) \
{ \
STRICT_EXPECTED_CALL(malloc(IGNORED_ARG)); \
STRICT_EXPECTED_CALL(MU_C2A(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(name), _AddRef)(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(name))) \
.CallCannotFail(); \
/* Counter for the up_to_index check */ \
uint32_t expectation_counter = 0; \
SF_SERVICE_CONFIG_EXPANDED_MU_FOR_EACH_2_KEEP_1(TEST_SF_SERVICE_CONFIG_SETUP_EXPECTATION_IF_LESS, name, SF_SERVICE_CONFIG_EXPAND_PARAMS(__VA_ARGS__)); \
/* Every string that was successful will need to be freed */ \
expectation_counter = 0; \
SF_SERVICE_CONFIG_EXPANDED_MU_FOR_EACH_2(TEST_SF_SERVICE_CONFIG_SETUP_EXPECTATION_FREE_IF_LESS, SF_SERVICE_CONFIG_EXPAND_PARAMS(__VA_ARGS__)); \
STRICT_EXPECTED_CALL(MU_C2A(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(name), _Release)(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(name))) \
.CallCannotFail(); \
STRICT_EXPECTED_CALL(free(IGNORED_ARG)); \
} \
static void TEST_SF_SERVICE_CONFIG_EXPECT_FREE_STRINGS(name)(void) \
{ \
SF_SERVICE_CONFIG_EXPANDED_MU_FOR_EACH_2(TEST_SF_SERVICE_CONFIG_EXPECT_FREE, SF_SERVICE_CONFIG_EXPAND_PARAMS(__VA_ARGS__)); \
} \
static void TEST_SF_SERVICE_CONFIG_EXPECT_DESTROY(name)(void) \
{ \
TEST_SF_SERVICE_CONFIG_EXPECT_FREE_STRINGS(name)(); \
STRICT_EXPECTED_CALL(MU_C2A(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(name), _Release)(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(name))) \
.CallCannotFail(); \
STRICT_EXPECTED_CALL(free(IGNORED_ARG)); \
} \
// The following are internal helpers for the above defines
#define TEST_SF_SERVICE_CONFIG_DEFINE_CONFIGURATION_READER_HOOK(type, config_name, ...) \
static int MU_C4(hook_, config_name, _configuration_reader_get_, type)(IFabricCodePackageActivationContext* activation_context, const wchar_t* config_package_name, const wchar_t* section_name, const wchar_t* parameter_name, type * value) \
{ \
int result; \
(void)activation_context; \
(void)config_package_name; \
(void)section_name; \
if (parameter_name == NULL || parameter_name[0] == L'\0') \
{ \
result = MU_FAILURE; \
ASSERT_FAIL("Unexpected missing parameter_name"); \
} \
SF_SERVICE_CONFIG_EXPANDED_MU_FOR_EACH_2(MU_C2(TEST_SF_SERVICE_CONFIG_DO_ASSIGN_IF_MATCH_, type), SF_SERVICE_CONFIG_EXPAND_PARAMS(__VA_ARGS__)) \
else \
{ \
result = MU_FAILURE; \
ASSERT_FAIL("Unknown parameter name %ls (did you forget to update the test?)", parameter_name); \
} \
return result; \
}
#define TEST_SF_SERVICE_CONFIG_DO_ASSIGN_IF_MATCH(name) \
else if (wcscmp(parameter_name, SF_SERVICE_CONFIG_PARAMETER_NAME(name)) == 0) \
{ \
*value = TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(name); \
result = 0; \
}
#define TEST_SF_SERVICE_CONFIG_DO_COPY_STRING_IF_MATCH(name) \
else if (wcscmp(parameter_name, SF_SERVICE_CONFIG_PARAMETER_NAME(name)) == 0) \
{ \
if (TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(name) != NULL) \
{ \
size_t len = strlen(TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(name)); \
*value = (char*)my_gballoc_malloc(len + 1); \
ASSERT_IS_NOT_NULL(*value); \
(void)strcpy(*value, TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(name)); \
} \
result = 0; \
}
#define TEST_SF_SERVICE_CONFIG_DO_ASSIGN_THANDLE_IF_MATCH(name) \
else if (wcscmp(parameter_name, SF_SERVICE_CONFIG_PARAMETER_NAME(name)) == 0) \
{ \
THANDLE_ASSIGN(real_RC_STRING)(value, TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(name).x); \
result = 0; \
}
// Used by the mock to do a lookup to the default or overridden value of the parameter (wide string copies)
#define TEST_SF_SERVICE_CONFIG_DO_COPY_WSTRING_IF_MATCH(name) \
else if (wcscmp(parameter_name, SF_SERVICE_CONFIG_PARAMETER_NAME(name)) == 0) \
{ \
if (TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(name) != NULL) \
{ \
size_t len = wcslen(TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(name)); \
*value = (wchar_t*)my_gballoc_malloc((len + 1) * sizeof(wchar_t)); \
ASSERT_IS_NOT_NULL(*value); \
(void)wcscpy(*value, TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(name)); \
} \
result = 0; \
}
#define TEST_SF_SERVICE_CONFIG_TYPE_IS_bool_bool 0
#define TEST_SF_SERVICE_CONFIG_TYPE_IS_bool__Bool 0
#define TEST_SF_SERVICE_CONFIG_TYPE_IS_bool(type) MU_IF(MU_C2(TEST_SF_SERVICE_CONFIG_TYPE_IS_bool_,type), 0, 1)
#define TEST_SF_SERVICE_CONFIG_DO_ASSIGN_IF_MATCH__Bool(type, name) MU_IF(TEST_SF_SERVICE_CONFIG_TYPE_IS_bool(type), TEST_SF_SERVICE_CONFIG_DO_ASSIGN_IF_MATCH(name), )
#define TEST_SF_SERVICE_CONFIG_TYPE_IS_UINT32_uint32_t 0
#define TEST_SF_SERVICE_CONFIG_TYPE_IS_UINT32(type) MU_IF(MU_C2(TEST_SF_SERVICE_CONFIG_TYPE_IS_UINT32_,type), 0, 1)
#define TEST_SF_SERVICE_CONFIG_DO_ASSIGN_IF_MATCH_uint32_t(type, name) MU_IF(TEST_SF_SERVICE_CONFIG_TYPE_IS_UINT32(type), TEST_SF_SERVICE_CONFIG_DO_ASSIGN_IF_MATCH(name), )
#define TEST_SF_SERVICE_CONFIG_TYPE_IS_UINT64_uint64_t 0
#define TEST_SF_SERVICE_CONFIG_TYPE_IS_UINT64(type) MU_IF(MU_C2(TEST_SF_SERVICE_CONFIG_TYPE_IS_UINT64_,type), 0, 1)
#define TEST_SF_SERVICE_CONFIG_DO_ASSIGN_IF_MATCH_uint64_t(type, name) MU_IF(TEST_SF_SERVICE_CONFIG_TYPE_IS_UINT64(type), TEST_SF_SERVICE_CONFIG_DO_ASSIGN_IF_MATCH(name), )
#define TEST_SF_SERVICE_CONFIG_TYPE_IS_CHAR_PTR_char_ptr 0
#define TEST_SF_SERVICE_CONFIG_TYPE_IS_CHAR_PTR(type) MU_IF(MU_C2(TEST_SF_SERVICE_CONFIG_TYPE_IS_CHAR_PTR_,type), 0, 1)
#define TEST_SF_SERVICE_CONFIG_DO_ASSIGN_IF_MATCH_char_ptr(type, name) MU_IF(TEST_SF_SERVICE_CONFIG_TYPE_IS_CHAR_PTR(type), TEST_SF_SERVICE_CONFIG_DO_COPY_STRING_IF_MATCH(name), )
#define TEST_SF_SERVICE_CONFIG_TYPE_IS_WCHAR_PTR_wchar_ptr 0
#define TEST_SF_SERVICE_CONFIG_TYPE_IS_WCHAR_PTR(type) MU_IF(MU_C2(TEST_SF_SERVICE_CONFIG_TYPE_IS_WCHAR_PTR_,type), 0, 1)
#define TEST_SF_SERVICE_CONFIG_DO_ASSIGN_IF_MATCH_wchar_ptr(type, name) MU_IF(TEST_SF_SERVICE_CONFIG_TYPE_IS_WCHAR_PTR(type), TEST_SF_SERVICE_CONFIG_DO_COPY_WSTRING_IF_MATCH(name), )
#define TEST_SF_SERVICE_CONFIG_TYPE_IS_ANY_CHAR_PTR_char_ptr 0
#define TEST_SF_SERVICE_CONFIG_TYPE_IS_ANY_CHAR_PTR_wchar_ptr 0
#define TEST_SF_SERVICE_CONFIG_TYPE_IS_ANY_CHAR_PTR(type) MU_IF(MU_C2(TEST_SF_SERVICE_CONFIG_TYPE_IS_ANY_CHAR_PTR_,type), 0, 1)
#define TEST_SF_SERVICE_CONFIG_TYPE_IS_THANDLE_thandle_rc_string 0
#define TEST_SF_SERVICE_CONFIG_TYPE_IS_THANDLE(type) MU_IF(MU_C2A(TEST_SF_SERVICE_CONFIG_TYPE_IS_THANDLE_,type), 0, 1)
#define TEST_SF_SERVICE_CONFIG_DO_ASSIGN_IF_MATCH_thandle_rc_string(type, name) MU_IF(TEST_SF_SERVICE_CONFIG_TYPE_IS_THANDLE(type), TEST_SF_SERVICE_CONFIG_DO_ASSIGN_THANDLE_IF_MATCH(name), )
#define TEST_SF_SERVICE_CONFIG_THANDLE_MEMBER_DECL(type, name) type name
#define TEST_SF_SERVICE_CONFIG_THANDLE_STATIC(type, name, member) \
static struct MU_C2B(name, _TAG) { \
TEST_SF_SERVICE_CONFIG_THANDLE_MEMBER_DECL(type, member); \
} name;
#define TEST_SF_SERVICE_CONFIG_TYPE_FOR_ASSERT_uint32_t uint32_t
#define TEST_SF_SERVICE_CONFIG_TYPE_FOR_ASSERT_uint64_t uint64_t
#define TEST_SF_SERVICE_CONFIG_TYPE_FOR_ASSERT_char_ptr char_ptr
#define TEST_SF_SERVICE_CONFIG_TYPE_FOR_ASSERT_wchar_ptr wchar_ptr
#define TEST_SF_SERVICE_CONFIG_TYPE_FOR_ASSERT_thandle_rc_string TEST_THANDLE_RC_STRING
#define TEST_SF_SERVICE_CONFIG_TYPE_FOR_ASSERT(type) MU_C2(TEST_SF_SERVICE_CONFIG_TYPE_FOR_ASSERT_, type)
#define TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_DEFINE_DEFAULT(type, name) static type TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(name);
#define TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_DEFINE_THANDLE(type, name) TEST_SF_SERVICE_CONFIG_THANDLE_STATIC(type, TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(name), x)
#define TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_DEFINE__Bool TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_DEFINE_DEFAULT
#define TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_DEFINE_bool TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_DEFINE_DEFAULT
#define TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_DEFINE_uint32_t TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_DEFINE_DEFAULT
#define TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_DEFINE_uint64_t TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_DEFINE_DEFAULT
#define TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_DEFINE_char_ptr TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_DEFINE_DEFAULT
#define TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_DEFINE_wchar_ptr TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_DEFINE_DEFAULT
#define TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_DEFINE_thandle_rc_string TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_DEFINE_THANDLE
#define TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_DEFINE(type, name) MU_C2A(TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_DEFINE_, type)(type, name)
#define TEST_SF_SERVICE_CONFIG_DEFAULT_DEFINE__Bool(type, name) static const bool TEST_SF_SERVICE_CONFIG_DEFAULT_VALUE(name) = true;
#define TEST_SF_SERVICE_CONFIG_DEFAULT_DEFINE_bool(type, name) static const bool TEST_SF_SERVICE_CONFIG_DEFAULT_VALUE(name) = true;
#define TEST_SF_SERVICE_CONFIG_DEFAULT_DEFINE_uint32_t(type, name) static const uint32_t TEST_SF_SERVICE_CONFIG_DEFAULT_VALUE(name) = 42;
#define TEST_SF_SERVICE_CONFIG_DEFAULT_DEFINE_uint64_t(type, name) static const uint64_t TEST_SF_SERVICE_CONFIG_DEFAULT_VALUE(name) = 4242;
#define TEST_SF_SERVICE_CONFIG_DEFAULT_DEFINE_char_ptr(type, name) static const char* TEST_SF_SERVICE_CONFIG_DEFAULT_VALUE(name) = MU_TOSTRING(name);
#define TEST_SF_SERVICE_CONFIG_DEFAULT_DEFINE_wchar_ptr(type, name) static const wchar_t* TEST_SF_SERVICE_CONFIG_DEFAULT_VALUE(name) = MU_C2(L, MU_TOSTRING(name));
#define TEST_SF_SERVICE_CONFIG_DEFAULT_DEFINE_thandle_rc_string(type, name) static const char* TEST_SF_SERVICE_CONFIG_DEFAULT_VALUE(name) = MU_TOSTRING(name);
#define TEST_SF_SERVICE_CONFIG_DEFAULT_DEFINE(type, name) MU_C2A(TEST_SF_SERVICE_CONFIG_DEFAULT_DEFINE_, type)(type, name)
#define TEST_SF_SERVICE_CONFIG_DO_ASSIGNMENT_DEFAULT(lval, rval) lval = rval;
#define TEST_SF_SERVICE_CONFIG_DO_ASSIGNMENT_THANDLE(lval, rval) THANDLE_ASSIGN(real_RC_STRING)(&lval, rval);
#define TEST_SF_SERVICE_CONFIG_DO_ASSIGNMENT__Bool TEST_SF_SERVICE_CONFIG_DO_ASSIGNMENT_DEFAULT
#define TEST_SF_SERVICE_CONFIG_DO_ASSIGNMENT_uint32_t TEST_SF_SERVICE_CONFIG_DO_ASSIGNMENT_DEFAULT
#define TEST_SF_SERVICE_CONFIG_DO_ASSIGNMENT_uint64_t TEST_SF_SERVICE_CONFIG_DO_ASSIGNMENT_DEFAULT
#define TEST_SF_SERVICE_CONFIG_DO_ASSIGNMENT_char_ptr TEST_SF_SERVICE_CONFIG_DO_ASSIGNMENT_DEFAULT
#define TEST_SF_SERVICE_CONFIG_DO_ASSIGNMENT_wchar_ptr TEST_SF_SERVICE_CONFIG_DO_ASSIGNMENT_DEFAULT
#define TEST_SF_SERVICE_CONFIG_DO_ASSIGNMENT_thandle_rc_string TEST_SF_SERVICE_CONFIG_DO_ASSIGNMENT_THANDLE
#define TEST_SF_SERVICE_CONFIG_DO_ASSIGNMENT(type, lval, rval) MU_C2(TEST_SF_SERVICE_CONFIG_DO_ASSIGNMENT_, type)(lval, rval)
#define TEST_SF_SERVICE_CONFIG_INDEX_OF_CONFIG_MACRO_COUNTER_NAME(name) MU_C3(test_sf_service_config_, name, _index)
#define TEST_SF_SERVICE_CONFIG_DEFINE_CONFIG_INDEX_VALUE(counter, type, name) static uint32_t TEST_SF_SERVICE_CONFIG_INDEX_OF_CONFIG_MACRO_COUNTER_NAME(name) = counter;
#define TEST_SF_SERVICE_CONFIG_DEFINE_INDEX_OF(name, ...) \
SF_SERVICE_CONFIG_EXPANDED_MU_FOR_EACH_2_COUNTED(TEST_SF_SERVICE_CONFIG_DEFINE_CONFIG_INDEX_VALUE, SF_SERVICE_CONFIG_EXPAND_PARAMS(__VA_ARGS__)) \
static uint32_t MU_C3(test_sf_service_config_, name, _index_of)(uint32_t macro_counter_value) \
{ \
return (MU_COUNT_ARG(__VA_ARGS__)) - macro_counter_value / 2; \
}
// Causes all mock calls to return the defaults (defined above)
#define TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_INIT_DEFAULT_bool(name) TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(name) = TEST_SF_SERVICE_CONFIG_DEFAULT_VALUE(name);
#define TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_INIT_DEFAULT__Bool(name) TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(name) = TEST_SF_SERVICE_CONFIG_DEFAULT_VALUE(name);
#define TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_INIT_DEFAULT_uint32_t(name) TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(name) = TEST_SF_SERVICE_CONFIG_DEFAULT_VALUE(name);
#define TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_INIT_DEFAULT_uint64_t(name) TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(name) = TEST_SF_SERVICE_CONFIG_DEFAULT_VALUE(name);
#define TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_INIT_DEFAULT_char_ptr(name) TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(name) = (char*)TEST_SF_SERVICE_CONFIG_DEFAULT_VALUE(name);
#define TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_INIT_DEFAULT_wchar_ptr(name) TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(name) = (wchar_t*)TEST_SF_SERVICE_CONFIG_DEFAULT_VALUE(name);
#define TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_INIT_DEFAULT_thandle_rc_string(name) \
THANDLE(RC_STRING) MU_C2(name, _temp) = real_rc_string_create(TEST_SF_SERVICE_CONFIG_DEFAULT_VALUE(name)); \
ASSERT_IS_NOT_NULL(MU_C2(name, _temp)); \
THANDLE_MOVE(real_RC_STRING)(&TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(name).x, &MU_C2(name, _temp));
#define TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_INIT_DEFAULT(type, name) MU_C2(TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_INIT_DEFAULT_, type)(name)
#define TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_INIT_MAX_bool(name) TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(name) = false;
#define TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_INIT_MAX__Bool(name) TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(name) = false;
#define TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_INIT_MAX_uint32_t(name) TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(name) = UINT32_MAX - 1;
#define TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_INIT_MAX_uint64_t(name) TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(name) = UINT64_MAX - 1;
#define TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_INIT_MAX_char_ptr(name) TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_INIT_DEFAULT(char_ptr, name)
#define TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_INIT_MAX_wchar_ptr(name) TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_INIT_DEFAULT(wchar_ptr, name)
#define TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_INIT_MAX_thandle_rc_string(name) TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_INIT_DEFAULT(thandle_rc_string, name)
// Causes all numerical values to report the maximum (but leaves strings default)
#define TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_INIT_MAX(type, name) MU_C2(TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_INIT_MAX_, type)(name)
// Cleanup defaults
#define TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_CLEANUP_bool(type, name) TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_INIT_DEFAULT(type, name)
#define TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_CLEANUP__Bool(type, name) TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_INIT_DEFAULT(type, name)
#define TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_CLEANUP_uint32_t(type, name) TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_INIT_DEFAULT(type, name)
#define TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_CLEANUP_uint64_t(type, name) TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_INIT_DEFAULT(type, name)
#define TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_CLEANUP_char_ptr(type, name) TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_INIT_DEFAULT(type, name)
#define TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_CLEANUP_wchar_ptr(type, name) TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_INIT_DEFAULT(type, name)
#define TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_CLEANUP_thandle_rc_string(type, name) \
THANDLE_ASSIGN(real_RC_STRING)(&TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(name).x, NULL);
#define TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_CLEANUP(type, name) MU_C2(TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN_CLEANUP_, type)(type, name)
#define TEST_SF_SERVICE_CONFIG_EXPECT_FREE_IF_EMPTY_STRING(name) \
if (TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(name) != NULL && TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(name)[0] == '\0') \
{ \
STRICT_EXPECTED_CALL(free(IGNORED_ARG)); \
}
#define TEST_SF_SERVICE_CONFIG_EXPECT_FREE_IF_EMPTY_WSTRING(name) \
if (TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(name) != NULL && TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(name)[0] == L'\0') \
{ \
STRICT_EXPECTED_CALL(free(IGNORED_ARG)); \
}
#define TEST_SF_SERVICE_CONFIG_EXPECT_FREE_IF_EMPTY_THANDLE_RC_STRING(name) \
if (TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(name).x != NULL && TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(name).x->string[0] == '\0') \
{ \
STRICT_EXPECTED_CALL(THANDLE_ASSIGN(RC_STRING)(IGNORED_ARG, NULL)); \
}
#define TEST_SF_SERVICE_CONFIG_EXPECT_FREE_bool(name)
#define TEST_SF_SERVICE_CONFIG_EXPECT_FREE__Bool(name)
#define TEST_SF_SERVICE_CONFIG_EXPECT_FREE_uint32_t(name)
#define TEST_SF_SERVICE_CONFIG_EXPECT_FREE_uint64_t(name)
#define TEST_SF_SERVICE_CONFIG_EXPECT_FREE_char_ptr(name) \
if (TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(name) != NULL && TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(name)[0] != '\0') \
{ \
STRICT_EXPECTED_CALL(free(IGNORED_ARG)); \
}
#define TEST_SF_SERVICE_CONFIG_EXPECT_FREE_wchar_ptr(name) \
if (TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(name) != NULL && TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(name)[0] != L'\0') \
{ \
STRICT_EXPECTED_CALL(free(IGNORED_ARG)); \
}
#define TEST_SF_SERVICE_CONFIG_EXPECT_FREE_thandle_rc_string(name) \
if (TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(name).x != NULL && TEST_SF_SERVICE_CONFIG_VALUE_TO_RETURN(name).x->string[0] != '\0') \
{ \
STRICT_EXPECTED_CALL(THANDLE_ASSIGN(RC_STRING)(IGNORED_ARG, NULL)); \
}
#define TEST_SF_SERVICE_CONFIG_EXPECT_FREE(type, name) MU_C2(TEST_SF_SERVICE_CONFIG_EXPECT_FREE_, type)(name)
#define TEST_SF_SERVICE_CONFIG_EXPECT_INIT_THANDLE(name) STRICT_EXPECTED_CALL(THANDLE_INITIALIZE(RC_STRING)(IGNORED_ARG, NULL));
#define TEST_SF_SERVICE_CONFIG_EXPECT_INIT_ON_FAILURE(type, name) \
MU_IF(TEST_SF_SERVICE_CONFIG_TYPE_IS_THANDLE(type), TEST_SF_SERVICE_CONFIG_EXPECT_INIT_THANDLE(name), )
#define TEST_SF_SERVICE_CONFIG_SETUP_EXPECTATION(name, field_type, field_name) \
MU_C3(name, _expect_read_, field_type)(SF_SERVICE_CONFIG_PARAMETER_NAME(field_name)); \
MU_IF(TEST_SF_SERVICE_CONFIG_TYPE_IS_CHAR_PTR(field_type), TEST_SF_SERVICE_CONFIG_EXPECT_FREE_IF_EMPTY_STRING(field_name), ) \
MU_IF(TEST_SF_SERVICE_CONFIG_TYPE_IS_WCHAR_PTR(field_type), TEST_SF_SERVICE_CONFIG_EXPECT_FREE_IF_EMPTY_WSTRING(field_name), ) \
MU_IF(TEST_SF_SERVICE_CONFIG_TYPE_IS_THANDLE(field_type), TEST_SF_SERVICE_CONFIG_EXPECT_FREE_IF_EMPTY_THANDLE_RC_STRING(field_name), )
#define TEST_SF_SERVICE_CONFIG_CONFIGURATION_READER_GET_FUNCTION_uint32_t configuration_reader_get_uint32_t
#define TEST_SF_SERVICE_CONFIG_CONFIGURATION_READER_GET_FUNCTION_uint64_t configuration_reader_get_uint64_t
#define TEST_SF_SERVICE_CONFIG_CONFIGURATION_READER_GET_FUNCTION__Bool configuration_reader_get_bool
#define TEST_SF_SERVICE_CONFIG_CONFIGURATION_READER_GET_FUNCTION_char_ptr configuration_reader_get_char_string
#define TEST_SF_SERVICE_CONFIG_CONFIGURATION_READER_GET_FUNCTION_wchar_ptr configuration_reader_get_wchar_string
#define TEST_SF_SERVICE_CONFIG_CONFIGURATION_READER_GET_FUNCTION_thandle_rc_string configuration_reader_get_thandle_rc_string
#define TEST_SF_SERVICE_CONFIG_CONFIGURATION_READER_GET_FUNCTION(type) MU_C2(TEST_SF_SERVICE_CONFIG_CONFIGURATION_READER_GET_FUNCTION_, type)
#define TEST_SF_SERVICE_CONFIG_DEFINE_EXPECT_READ(name, sf_config_name, sf_parameters_section_name, type) \
static void MU_C3(name, _expect_read_, type)(const wchar_t* parameter) \
{ \
STRICT_EXPECTED_CALL(TEST_SF_SERVICE_CONFIG_CONFIGURATION_READER_GET_FUNCTION(type)(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(name), sf_config_name, sf_parameters_section_name, parameter, IGNORED_ARG)); \
}
#define TEST_SF_SERVICE_CONFIG_DEFINE_EXPECT_READ_THANDLE_RC_STRING(name, sf_config_name, sf_parameters_section_name) \
static void MU_C2(name, _expect_read_thandle_rc_string)(const wchar_t* parameter) \
{ \
STRICT_EXPECTED_CALL(THANDLE_INITIALIZE(RC_STRING)(IGNORED_ARG, NULL)); \
STRICT_EXPECTED_CALL(TEST_SF_SERVICE_CONFIG_CONFIGURATION_READER_GET_FUNCTION(thandle_rc_string)(TEST_SF_SERVICE_CONFIG_ACTIVATION_CONTEXT(name), sf_config_name, sf_parameters_section_name, parameter, IGNORED_ARG)); \
}
#define TEST_SF_SERVICE_CONFIG_SETUP_EXPECTATION_IF_LESS(name, field_type, field_name) \
if (expectation_counter <= up_to_index) \
{ \
TEST_SF_SERVICE_CONFIG_SETUP_EXPECTATION(name, field_type, field_name) \
} \
else \
{ \
TEST_SF_SERVICE_CONFIG_EXPECT_INIT_ON_FAILURE(field_type, field_name); \
} \
expectation_counter++;
#define TEST_SF_SERVICE_CONFIG_SETUP_EXPECTATION_FREE_IF_LESS(type, name) \
if (expectation_counter <= up_to_index) \
{ \
TEST_SF_SERVICE_CONFIG_EXPECT_FREE(type, name) \
} \
expectation_counter++;
#endif /* SF_SERVICE_CONFIG_UT_HELPERS_H */

Просмотреть файл

@ -0,0 +1,15 @@
// Copyright (C) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include "c_pal/gballoc_hl.h"
#include "c_pal/gballoc_hl_redirect.h"
#include "sf_c_util/sf_service_config.h"
#include "test_sf_service_config.h"
// Avoid mock calls from the THANDLE (no other way to do this right now)
#include "real_interlocked_renames.h"
#include "real_interlocked.h"
DEFINE_SF_SERVICE_CONFIG(my_config, L"default_config", L"MyConfigSectionName", MY_CONFIG_TEST_PARAMS);

Просмотреть файл

@ -0,0 +1,42 @@
// Copyright (C) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#ifndef TEST_CONFIGURATION_WRAPPER_H
#define TEST_CONFIGURATION_WRAPPER_H
#include <inttypes.h>
#include <stdbool.h>
#include <wchar.h>
#include "sf_c_util/sf_service_config.h"
#include "umock_c/umock_c_prod.h"
#define SF_SERVICE_CONFIG_PARAMETER_NAME_parameter_1 L"Parameter1"
#define SF_SERVICE_CONFIG_PARAMETER_NAME_parameter_2 L"Parameter2"
#define SF_SERVICE_CONFIG_PARAMETER_NAME_parameter_3 L"Parameter3WithLongerName"
#define SF_SERVICE_CONFIG_PARAMETER_NAME_some_flag L"SomeFlag"
#define SF_SERVICE_CONFIG_PARAMETER_NAME_string_option_in_thandle L"StringOptionThandle"
#define SF_SERVICE_CONFIG_PARAMETER_NAME_string_option L"MyString"
#define SF_SERVICE_CONFIG_PARAMETER_NAME_wide_string_option L"MyWideString"
#define SF_SERVICE_CONFIG_PARAMETER_NAME_string_option_in_thandle_optional L"OptionalStringOptionThandle"
#define SF_SERVICE_CONFIG_PARAMETER_NAME_string_option_optional L"OptionalStringOption"
#define SF_SERVICE_CONFIG_PARAMETER_NAME_wide_string_option_optional L"OptionalWideStringOption"
#define SF_SERVICE_CONFIG_PARAMETER_NAME_another_flag L"AnotherFlag"
#define MY_CONFIG_TEST_PARAMS \
CONFIG_REQUIRED(uint64_t, parameter_1), \
CONFIG_REQUIRED(uint64_t, parameter_2), \
CONFIG_REQUIRED(uint32_t, parameter_3), \
CONFIG_REQUIRED(bool, some_flag), \
CONFIG_REQUIRED(thandle_rc_string, string_option_in_thandle), \
CONFIG_REQUIRED(char_ptr, string_option), \
CONFIG_REQUIRED(wchar_ptr, wide_string_option), \
CONFIG_OPTIONAL(thandle_rc_string, string_option_in_thandle_optional), \
CONFIG_OPTIONAL(char_ptr, string_option_optional), \
CONFIG_OPTIONAL(wchar_ptr, wide_string_option_optional), \
CONFIG_REQUIRED(bool, another_flag) \
DECLARE_SF_SERVICE_CONFIG(my_config, MY_CONFIG_TEST_PARAMS)
#endif /* TEST_CONFIGURATION_WRAPPER_H */