* it all compuiles

* no leaks

* it all compiles so far no leaks, files moved around, started writing specs

* added specs

* added tests with incomplete/complete/and file hosted types

* added unittests
This commit is contained in:
anporumb 2024-05-09 21:38:09 -07:00 коммит произвёл GitHub
Родитель f3e991a7f7
Коммит 751e5bec5e
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
12 изменённых файлов: 658 добавлений и 2 удалений

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

@ -0,0 +1,91 @@
# thandle_ptr_requirements
## Overview
`thandle_ptr` is a module that builds on `THANDLE` and provides a "move existing pointer under THANDLE" functionality.
`THANDLE` has as requirement to "only call malloc once". `THANDLE_PTR` retains that requirement. Note: the existing pointer must have been allocated "somehow" before. Even pointers to stack variables can be moved under `THANDLE_PTR` with the regular gotchas that deallocation happens when leaving the scope of the variable.
`THANDLE_PTR` should be used when the pointer already exists. In all the other situations, where the pointer hasn't been created yet, regular `THANDLE` should be used.
`THANDLE_PTR` works by declaring under the hood a struct as below which captures the parameters passed to `THANDLE_PTR_CREATE_WITH_MOVE` and...
```c
typedef struct PTR_STRUCT_TAG_TYPE_NAME(T)
{
T pointer;
THANDLE_PTR_FREE_FUNC_TYPE_NAME(T) the_free;
} PTR(T);
```
... and then declaring a regular `THANDLE` over the above defined structure type.
In this document and code implementation "T" is a previously defined type that has pointer semantics and is a C identifier. For example "PS" introduced as: `typedef struct S_TAG* PS;`
## Usage
Usage of `THANDLE_PTR` is very similar to `THANDLE`.
In a C header, introduce the following declaration:
```c
THANDLE_PTR_DECLARE(A_S_PTR);
```
In a C source file, introduce the following declaration:
```c
THANDLE_PTR_DEFINE(A_S_PTR);
```
Then use it like:
```c
THANDLE(PTR(A_S_PTR)) one = THANDLE_PTR_CREATE_WITH_MOVE(A_S_PTR)(a_s, dispose);
```
`a_s` is a pointer of type `A_S_PTR`.
The above code "moves" ("captures") the pointer `a_s` and produces the `THANDLE` `one`. `dispose` is a user function that takes the original `a_s` pointer and frees all resource used by `a_s`.
`one->pointer` produces the original `a_s` pointer. Other fields of the `one` pointer should not be used (it also captures the `dispose` function for example).
## Exposed API
`THANDLE_PTR` introduces several new types and APIs.
Types are:
`PTR(T)` - is a structure that contains the field `pointer` which captures the original `pointer` passed to `THANDLE_PTR_CREATE_WITH_MOVE`.
`THANDLE(PTR(T))` is the `PTR(T)` above with `THANDLE` semantics.
`THANDLE_PTR_FREE_FUNC_TYPE(T)` is the function pointer type of the `dispose` function. It takes `T` and frees it. `T` is already a pointer.
In addition all `THANDLE` regular APIs apply to `PTR(T)` type. For example
```c
THANDLE_ASSING(PTR(T))(&some_ptr_t, NULL);
```
APIs are:
### THANDLE_PTR_CREATE_WITH_MOVE(T)
```c
THANDLE(PTR(T)) THANDLE_PTR_CREATE_WITH_MOVE(T)(T pointer, THANDLE_PTR_FREE_FUNC_TYPE_NAME(T) dispose );
```
`THANDLE_PTR_CREATE_WITH_MOVE(T)` will "move" `pointer` to a newly created `THANDLE(PTR(T))` which then can be accessed by using the field "pointer" of the structure.
**SRS_THANDLE_PTR_02_001: [** `THANDLE_PTR_CREATE_WITH_MOVE(T)` shall return what `THANDLE_CREATE_FROM_CONTENT(PTR(T))(THANDLE_PTR_DISPOSE(T))` returns. **]**
### THANDLE_PTR_DISPOSE(T)
```
static void THANDLE_PTR_DISPOSE(T)(PTR(T)* ptr)
```
`THANDLE_PTR_DISPOSE` is a static function that calls the original `dispose` passed to `THANDLE_PTR_CREATE_WITH_MOVE(T)`.
**SRS_THANDLE_PTR_02_002: [** If the original `dispose` is non-`NULL` then `THANDLE_PTR_DISPOSE(T)` shall call `dispose`. **]**
**SRS_THANDLE_PTR_02_003: [** `THANDLE_PTR_DISPOSE(T)` shall return. **]**

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

@ -0,0 +1,74 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#ifndef THANDLE_PTR_H
#define THANDLE_PTR_H
#include "c_pal/thandle.h"
#include "c_pal/thandle_ll.h" // for THANDLE
#include "macro_utils/macro_utils.h" // for MU_COUNT_ARG_0, MU_DISPATCH_EMP...
/*all the macros in this file depend on "T". T is "a pointer to a type", so it looks like "COORD_STRUCT*". */
/*this introduces a new *name* for a type that is a typedef of struct THANDLE_PTR_STRUCT_TAG_NAME {...}*/
#define PTR(T) MU_C2(PTR_STRUCT_, T)
/*this introduces a new *name* for a structure type that contains "T pointer"*/
#define PTR_STRUCT_TAG_TYPE_NAME(T) MU_C2(PTR(T), _TAG)
/*this introduces a new *name* for a function pointer type that takes a T and frees it*/
#define THANDLE_PTR_FREE_FUNC_TYPE_NAME(T) MU_C2(THANDLE_PTR_FREE_FUNC_, T)
/*this introduces a new *type* which is a pointer to the free type for T*/
#define THANDLE_PTR_FREE_FUNC_TYPE(T) typedef void (*THANDLE_PTR_FREE_FUNC_TYPE_NAME(T))(T arg);
/*this introduces a new *type* which is a structure with a field of type T"*/
#define PTR_STRUCT_TYPE_TYPEDEF(T) \
typedef struct PTR_STRUCT_TAG_TYPE_NAME(T) \
{ \
T pointer; /*original pointer passed to THANDLE_PTR_CREATE_WITH_MOVE*/ \
THANDLE_PTR_FREE_FUNC_TYPE_NAME(T) dispose; /*original dispose passed to THANDLE_PTR_CREATE_WITH_MOVE*/ \
} PTR(T);
/*this introduces one new *name* for a function which is used to capture a T ptr and move it under the THANDLE(PTR(T))*/
#define THANDLE_PTR_CREATE_WITH_MOVE(T) MU_C2(THANDLE_PTR_CREATE_WITH_MOVE_, T)
/*this introduces a new *name* for a function that calls the dispose as passed to THANDLE_PTR_CREATE_WITH_MOVE*/
#define THANDLE_PTR_DISPOSE(T) MU_C2(THANDLE_PTR_DISPOSE_, T)
/*this introduces the declaration of a function that returns a THANDLE(PTR(T))*/
#define THANDLE_PTR_DECLARE(T) \
THANDLE_PTR_FREE_FUNC_TYPE(T); \
PTR_STRUCT_TYPE_TYPEDEF(T); \
THANDLE_TYPE_DECLARE(PTR(T)); \
THANDLE(PTR(T)) THANDLE_PTR_CREATE_WITH_MOVE(T)(T pointer, THANDLE_PTR_FREE_FUNC_TYPE_NAME(T) dispose ); \
/*this introduces the definition of the function declared above*/
#define THANDLE_PTR_DEFINE(T) \
THANDLE_TYPE_DEFINE(PTR(T)); \
static void THANDLE_PTR_DISPOSE(T)(PTR(T)* ptr) \
{ \
/*Codes_SRS_THANDLE_PTR_02_002: [ If the original dispose is non-NULL then THANDLE_PTR_DISPOSE(T) shall call dispose. ]*/ \
if(ptr->dispose!=NULL) \
{ \
ptr->dispose(ptr->pointer); \
} \
else \
{ \
/*Codes_SRS_THANDLE_PTR_02_003: [ THANDLE_PTR_DISPOSE(T) shall return. ]*/ \
/*do nothing*/ \
} \
} \
THANDLE(PTR(T)) THANDLE_PTR_CREATE_WITH_MOVE(T)(T pointer, THANDLE_PTR_FREE_FUNC_TYPE_NAME(T) dispose ) \
{ \
PTR(T) temp = \
{ \
.pointer = pointer, /* this is "move" */ \
.dispose = dispose \
}; \
/*Codes_SRS_THANDLE_PTR_02_001: [ THANDLE_PTR_CREATE_WITH_MOVE(T) shall return what THANDLE_CREATE_FROM_CONTENT(PTR(T))(THANDLE_PTR_DISPOSE(T)) returns. ]*/ \
return THANDLE_CREATE_FROM_CONTENT(PTR(T))(&temp, THANDLE_PTR_DISPOSE(T), NULL); \
}
#endif /*THANDLE_PTR_H*/

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

@ -19,6 +19,7 @@ if(${run_unittests})
build_test_folder(s_list_ut)
build_test_folder(thandle_2_ut)
build_test_folder(thandle_ut)
build_test_folder(thandle_ptr_ut)
endif()
if(${run_int_tests})
@ -27,6 +28,7 @@ if(${run_int_tests})
build_test_folder(interlocked_hl_int)
build_test_folder(lazy_init_int)
build_test_folder(sm_int)
build_test_folder(thandle_ptr_int)
endif()

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

@ -11,7 +11,7 @@
#include "umock_c/umock_c.h"
#define ENABLE_MOCKS
#include "c_pal/gballoc_hl.h"
#include "c_pal/gballoc_hl.h"
#include "c_pal/gballoc_hl_redirect.h" /*THANDLE needs malloc/malloc_flex/free to exist*/
#include "malloc_mocks.h"
#undef ENABLE_MOCKS
@ -236,7 +236,7 @@ TEST_FUNCTION(T_ON_create_from_content_flex_with_malloc_functions_calls_var_mall
TEST_FUNCTION(T_OFF_uses_malloc_when_no_function_is_specified_1)
{
///arrange
STRICT_EXPECTED_CALL(malloc(IGNORED_ARG));
//act

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

@ -0,0 +1,22 @@
#Copyright (c) Microsoft. All rights reserved.
#Licensed under the MIT license. See LICENSE file in the project root for full license information.
set(theseTestsName thandle_ptr_int)
set(${theseTestsName}_test_files
${theseTestsName}.c
)
set(${theseTestsName}_c_files
example.c
example_incomplete_type.c
)
set(${theseTestsName}_h_files
example.h
example_incomplete_type.h
../../inc/c_pal/thandle_ptr.h
)
build_test_artifacts(${theseTestsName} "tests/c_pal" ADDITIONAL_LIBS c_pal c_pal_reals)

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

@ -0,0 +1,18 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include <stdlib.h>
#include "c_pal/gballoc_hl.h" // IWYU pragma: keep
#include "c_pal/gballoc_hl_redirect.h" // IWYU pragma: keep
#include "c_pal/thandle_ptr.h"
#include "example.h"
THANDLE_PTR_DEFINE(EXAMPLE_COMPLETE_PTR);
void dispose_example_complete(EXAMPLE_COMPLETE_PTR example_complete)
{
free(example_complete); /*nothing else*/
}

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

@ -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.
#ifndef EXAMPLE_H
#define EXAMPLE_H
#include "macro_utils/macro_utils.h"
#include "c_pal/thandle_ptr.h"
/*this is a complete type*/
typedef struct EXAMPLE_COMPLETE_TAG
{
int example_complete;
}EXAMPLE_COMPLETE;
typedef EXAMPLE_COMPLETE* EXAMPLE_COMPLETE_PTR;
THANDLE_PTR_DECLARE(EXAMPLE_COMPLETE_PTR);
void dispose_example_complete(EXAMPLE_COMPLETE_PTR example_complete);
#endif /*EXAMPLE_H*/

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

@ -0,0 +1,30 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include <stdlib.h>
#include "macro_utils/macro_utils.h"
#include "c_pal/gballoc_hl.h" // IWYU pragma: keep
#include "c_pal/gballoc_hl_redirect.h" // IWYU pragma: keep
#include "c_pal/thandle_ptr.h"
#include "example_incomplete_type.h"
struct EXAMPLE_INCOMPLETE
{
int example_incomplete;
};
THANDLE_PTR_DEFINE(EXAMPLE_INCOMPLETE_PTR);
EXAMPLE_INCOMPLETE_PTR create_example_incomplete(void)
{
return malloc(sizeof(struct EXAMPLE_INCOMPLETE));
}
void dispose_example_incomplete(EXAMPLE_INCOMPLETE_PTR example_incomplete)
{
free(example_incomplete); /*nothing else*/
}

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

@ -0,0 +1,20 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#ifndef EXAMPLE_INCOMPLETE_TYPE_H
#define EXAMPLE_INCOMPLETE_TYPE_H
#include "macro_utils/macro_utils.h"
#include "c_pal/thandle_ptr.h"
/*EXAMPLE_INCOMPLETE is an incomplete type (opaque)*/
typedef struct EXAMPLE_INCOMPLETE* EXAMPLE_INCOMPLETE_PTR;
THANDLE_PTR_DECLARE(EXAMPLE_INCOMPLETE_PTR);
EXAMPLE_INCOMPLETE_PTR create_example_incomplete(void);
void dispose_example_incomplete(EXAMPLE_INCOMPLETE_PTR example_incomplete);
#endif /*EXAMPLE_INCOMPLETE_TYPE_H*/

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

@ -0,0 +1,195 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include <stdlib.h>
#include "macro_utils/macro_utils.h" // IWYU pragma: keep
#include "c_logging/logger.h"
#include "testrunnerswitcher.h"
#include "c_pal/gballoc_hl.h" // IWYU pragma: keep
#include "c_pal/gballoc_hl_redirect.h" // IWYU pragma: keep
#include "c_pal/thandle.h"
#include "c_pal/string_utils.h"
#include "c_pal/thandle_ll.h"
#include "c_pal/thandle.h" // IWYU pragma: keep
#include "c_pal/thandle_ptr.h"
#include "example.h"
#include "example_incomplete_type.h"
typedef struct A_S_TAG
{
int a;
char* s;
}A_S;
typedef A_S* A_S_PTR;
static void dispose(A_S_PTR a_s)
{
free(a_s->s);
free(a_s);
}
THANDLE_PTR_DECLARE(A_S_PTR);
THANDLE_PTR_DEFINE(A_S_PTR);
typedef struct A_S_CONST_TAG
{
const int a;
const char* s;
}A_S_CONST;
typedef A_S_CONST* A_S_CONST_PTR;
static void dispose_const(A_S_CONST_PTR a_s)
{
free((void*)a_s->s);
free(a_s);
}
THANDLE_PTR_DECLARE(A_S_CONST_PTR);
THANDLE_PTR_DEFINE(A_S_CONST_PTR);
BEGIN_TEST_SUITE(TEST_SUITE_NAME_FROM_CMAKE)
TEST_SUITE_INITIALIZE(it_does_something)
{
ASSERT_ARE_EQUAL(int, 0, gballoc_hl_init(NULL, NULL));
}
TEST_SUITE_CLEANUP(TestClassCleanup)
{
gballoc_hl_deinit();
}
TEST_FUNCTION_INITIALIZE(f)
{
}
TEST_FUNCTION_CLEANUP(cleans)
{
}
/*the test will
1. allocate on the heap some structure that needs a special "destroy" function
2. move the pointer to the structure into a THANDLE(PTR())
3. verify that the pointer in the THANDLE is the same as the original pointer
3.1 verify that the pointer has the same qualifiers as the original pointer (in this case fields are not const)
4. THANDLE_ASSIGN(PTR, NULL) so that memory is freed (the THANDLE memory and the original "destroy"
*/
TEST_FUNCTION(thandle_int_works_with_both_declare_and_define_in_this_file)
{
///arrange
LogInfo("1. allocate on the heap some structure that needs a special \"destroy\" function.");
A_S_PTR a_s = malloc(sizeof(A_S));
ASSERT_IS_NOT_NULL(a_s);
a_s->a = 42;
a_s->s = sprintf_char("%s", "3333333333333333333333_here_some_string_3333333333333333333333");
ASSERT_IS_NOT_NULL(a_s->s);
///act
LogInfo("2. move the pointer to the structure into a THANDLE(PTR())");
THANDLE(PTR(A_S_PTR)) one = THANDLE_PTR_CREATE_WITH_MOVE(A_S_PTR)(a_s, dispose);
///assert
LogInfo("3. verify that the pointer in the THANDLE is the same as the original pointer");
ASSERT_IS_NOT_NULL(one);
ASSERT_ARE_EQUAL(void_ptr, a_s, one->pointer);
///assert
LogInfo("3.1 verify that the pointer has the same qualifiers as the original pointer (in this case fields are not const)");
one->pointer->a = 3;
one->pointer->s[0] = 'a';
///cleanup
LogInfo("4. THANDLE_ASSIGN(PTR, NULL) so that memory is freed (the THANDLE memory and the original \"destroy\"");
THANDLE_ASSIGN(PTR(A_S_PTR))(&one, NULL);
}
/*the test will
1. allocate on the heap some structure that needs a special "destroy" function
2. move the pointer to the structure into a THANDLE(PTR())
3. verify that the pointer in the THANDLE is the same as the original pointer
3.1 verify that the pointer has the same qualifiers as the original pointer (in this case fields are const)
4. THANDLE_ASSIGN(PTR, NULL) so that memory is freed (the THANDLE memory and the original "destroy"
*/
TEST_FUNCTION(thandle_int_works_with_both_declare_and_define_in_this_file_for_const)
{
///arrange
LogInfo("1. allocate on the heap some structure that needs a special \"destroy\" function.");
A_S_CONST_PTR a_s = malloc(sizeof(A_S_CONST));
ASSERT_IS_NOT_NULL(a_s);
/*cast the const away... just for a tiny momnet*/
*(int*)& a_s->a = 42;
*(char**)&a_s->s = sprintf_char("%s", "3333333333333333333333_here_some_string_3333333333333333333333");
ASSERT_IS_NOT_NULL(a_s->s);
///act
LogInfo("2. move the pointer to the structure into a THANDLE(PTR())");
THANDLE(PTR(A_S_CONST_PTR)) one = THANDLE_PTR_CREATE_WITH_MOVE(A_S_CONST_PTR)(a_s, dispose_const);
///assert
LogInfo("3. verify that the pointer in the THANDLE is the same as the original pointer");
ASSERT_IS_NOT_NULL(one);
ASSERT_ARE_EQUAL(void_ptr, a_s, one->pointer);
///assert
LogInfo("3.1 verify that the pointer has the same qualifiers as the original pointer (in this case fields are const)");
/*one->pointer->a = 3;*/ /*error C2166: l-value specifies const object*/
/*one->pointer->s[0] = 'a';*/ /*error C2166: l-value specifies const object*/
/*ENTER C GENERICS - with a shout out to "compatible types..." Note: it seems that "const int" and "int" are "compatible", however, int* and const int* are not.*/
ASSERT_ARE_EQUAL(int, 1, _Generic(&one->pointer->a, const int *: 1, int*: 2, default : 0));
ASSERT_ARE_EQUAL(int, 1, _Generic(&(one->pointer->s), const char** : 1, default: 0));
///cleanup
LogInfo("4. THANDLE_ASSIGN(PTR, NULL) so that memory is freed (the THANDLE memory and the original \"destroy\"");
THANDLE_ASSIGN(PTR(A_S_CONST_PTR))(&one, NULL);
}
TEST_FUNCTION(thandle_int_works_with_both_declare_and_define_in_different_files)
{
///arrange
EXAMPLE_COMPLETE_PTR p = malloc(sizeof(EXAMPLE_COMPLETE));
ASSERT_IS_NOT_NULL(p);
p->example_complete= 2;
///act
THANDLE(PTR(EXAMPLE_COMPLETE_PTR)) example_complete = THANDLE_PTR_CREATE_WITH_MOVE(EXAMPLE_COMPLETE_PTR)(p, dispose_example_complete);
///assert
ASSERT_IS_NOT_NULL(example_complete);
ASSERT_ARE_EQUAL(void_ptr, p, example_complete->pointer);
ASSERT_ARE_EQUAL(int, 2, example_complete->pointer->example_complete);
///cleanup
THANDLE_ASSIGN(PTR(EXAMPLE_COMPLETE_PTR))(&example_complete, NULL);
}
TEST_FUNCTION(thandle_int_works_with_incomplete_types)
{
///arrange
EXAMPLE_INCOMPLETE_PTR p = create_example_incomplete();
ASSERT_IS_NOT_NULL(p);
///act
THANDLE(PTR(EXAMPLE_INCOMPLETE_PTR)) example_incomplete = THANDLE_PTR_CREATE_WITH_MOVE(EXAMPLE_INCOMPLETE_PTR)(p, dispose_example_incomplete);
///assert
ASSERT_IS_NOT_NULL(example_incomplete);
ASSERT_ARE_EQUAL(void_ptr, p, example_incomplete->pointer);
///cleanup
THANDLE_ASSIGN(PTR(EXAMPLE_INCOMPLETE_PTR))(&example_incomplete, NULL);
}
END_TEST_SUITE(TEST_SUITE_NAME_FROM_CMAKE)

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

@ -0,0 +1,18 @@
#Copyright (c) Microsoft. All rights reserved.
#Licensed under the MIT license. See LICENSE file in the project root for full license information.
set(theseTestsName thandle_ptr_ut)
set(${theseTestsName}_test_files
${theseTestsName}.c
)
set(${theseTestsName}_c_files
)
set(${theseTestsName}_h_files
../../inc/c_pal/thandle_ptr.h
)
build_test_artifacts(${theseTestsName} "tests/c_pal" ADDITIONAL_LIBS c_pal c_pal_reals)

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

@ -0,0 +1,163 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include <stdlib.h>
#include "macro_utils/macro_utils.h" // IWYU pragma: keep
#include "testrunnerswitcher.h"
#include "c_pal/thandle_ll.h" // for THANDLE, THANDLE_ASSIGN
#define ENABLE_MOCKS
#include "umock_c/umock_c.h"
#include "c_pal/gballoc_hl.h"
#include "c_pal/gballoc_hl_redirect.h"
#undef ENABLE_MOCKS
#include "real_gballoc_hl.h"
#include "c_pal/thandle_ptr.h"
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));
}
typedef struct UNDER_TEST_TAG
{
int a;
}UNDER_TEST;
typedef UNDER_TEST* UNDER_TEST_PTR;
THANDLE_PTR_DECLARE(UNDER_TEST_PTR);
THANDLE_PTR_DEFINE(UNDER_TEST_PTR);
BEGIN_TEST_SUITE(TEST_SUITE_NAME_FROM_CMAKE)
TEST_SUITE_INITIALIZE(it_does_something)
{
ASSERT_ARE_EQUAL(int, 0, real_gballoc_hl_init(NULL, NULL));
umock_c_init(on_umock_c_error);
REGISTER_GBALLOC_HL_GLOBAL_MOCK_HOOK();
}
TEST_SUITE_CLEANUP(TestClassCleanup)
{
umock_c_deinit();
real_gballoc_hl_deinit();
}
TEST_FUNCTION_INITIALIZE(f)
{
umock_c_reset_all_calls();
}
TEST_FUNCTION_CLEANUP(cleans)
{
}
static void just_call_free(UNDER_TEST_PTR p)
{
free(p);
}
/*Tests_SRS_THANDLE_PTR_02_001: [ THANDLE_PTR_CREATE_WITH_MOVE(T) shall return what THANDLE_CREATE_FROM_CONTENT(PTR(T))(THANDLE_PTR_DISPOSE(T)) returns. ]*/
TEST_FUNCTION(THANDLE_PTR_CREATE_WITH_MOVE_happy_path)
{
///arrange
UNDER_TEST_PTR p = real_gballoc_hl_malloc(sizeof(UNDER_TEST));
ASSERT_IS_NOT_NULL(p);
umock_c_reset_all_calls();
STRICT_EXPECTED_CALL(malloc_flex(IGNORED_ARG, IGNORED_ARG, IGNORED_ARG)); /*this is THANDLE_CREATE_FROM_CONTENT...*/
///act
THANDLE(PTR(UNDER_TEST_PTR)) t = THANDLE_PTR_CREATE_WITH_MOVE(UNDER_TEST_PTR)(p, just_call_free);
///assert
ASSERT_IS_NOT_NULL(t);
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
///clean
THANDLE_ASSIGN(PTR(UNDER_TEST_PTR))(&t, NULL);
}
/*Tests_SRS_THANDLE_PTR_02_001: [ THANDLE_PTR_CREATE_WITH_MOVE(T) shall return what THANDLE_CREATE_FROM_CONTENT(PTR(T))(THANDLE_PTR_DISPOSE(T)) returns. ]*/
TEST_FUNCTION(THANDLE_PTR_CREATE_WITH_MOVE_unhappy_path)
{
///arrange
UNDER_TEST_PTR p = real_gballoc_hl_malloc(sizeof(UNDER_TEST));
ASSERT_IS_NOT_NULL(p);
umock_c_reset_all_calls();
STRICT_EXPECTED_CALL(malloc_flex(IGNORED_ARG, IGNORED_ARG, IGNORED_ARG)) /*this is THANDLE_CREATE_FROM_CONTENT...*/
.SetReturn(NULL);
///act
THANDLE(PTR(UNDER_TEST_PTR)) t = THANDLE_PTR_CREATE_WITH_MOVE(UNDER_TEST_PTR)(p, just_call_free);
///assert
ASSERT_IS_NULL(t);
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls());
///clean
just_call_free(p);
}
/*Tests_SRS_THANDLE_PTR_02_002: [ If the original dispose is non-NULL then THANDLE_PTR_DISPOSE(T) shall call dispose. ]*/
TEST_FUNCTION(THANDLE_PTR_DISPOSE_call_dispose)
{
///arrange
UNDER_TEST_PTR p = real_gballoc_hl_malloc(sizeof(UNDER_TEST));
ASSERT_IS_NOT_NULL(p);
THANDLE(PTR(UNDER_TEST_PTR)) t = THANDLE_PTR_CREATE_WITH_MOVE(UNDER_TEST_PTR)(p, just_call_free);
ASSERT_IS_NOT_NULL(t);
umock_c_reset_all_calls();
STRICT_EXPECTED_CALL(free(p)); /*this is freeing "p"*/
STRICT_EXPECTED_CALL(free(IGNORED_ARG)); /*this is freeing the THANDLE storage space*/
///act
THANDLE_ASSIGN(PTR(UNDER_TEST_PTR))(&t, NULL);
///assert
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); /*this is "shall return"... */
}
/*Tests_SRS_THANDLE_PTR_02_003: [ THANDLE_PTR_DISPOSE(T) shall return. ]*/
TEST_FUNCTION(THANDLE_PTR_DISPOSE_NULL_does_not_call_anything)
{
///arrange
UNDER_TEST local = { .a = 42 };
UNDER_TEST_PTR p = &local; /*note: no function needed to be called to dispose of local*/
ASSERT_IS_NOT_NULL(p);
THANDLE(PTR(UNDER_TEST_PTR)) t = THANDLE_PTR_CREATE_WITH_MOVE(UNDER_TEST_PTR)(p, NULL);
ASSERT_IS_NOT_NULL(t);
umock_c_reset_all_calls();
STRICT_EXPECTED_CALL(free(IGNORED_ARG)); /*this is freeing the THANDLE storage space*/
///act
THANDLE_ASSIGN(PTR(UNDER_TEST_PTR))(&t, NULL);
///assert
ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); /*this is "shall return"... */
}
END_TEST_SUITE(TEST_SUITE_NAME_FROM_CMAKE)