summaryrefslogtreecommitdiff
path: root/tests/lowmem-mock.hpp
blob: 0977ce9333b2c5a8e7306cf3d1f78341e1ffc4ad (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
/*
 * resourced
 *
 * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/

#pragma once

#include <iostream>
#include "cmocka-wrap.hpp"

/* Macro WRAP is used for wrapping and mocking functions from libraries, e.g. from glibc or glib.
 *
 * Its params are:
 * - global_object - an object that actually handles the wrapped function;
 * - rettype - return type of the wrapped function;
 * - name - the name of the wrapped function;
 * - def_args - function arguments as defined in function declaration, e.g. (pid_t pid, int sig)
 * - call_args - function arguments as used in calling, e.g. (pid, sig)
 *
 * For example, writing WRAP(global_object, int, kill, (pid_t pid, int sig), (pid, sig)) does two things:
 * - declares a function:
 *     extern "C" int __real_kill(pid_t pid, int sig);
 * - defines a function:
 *     extern "C" int __wrap_kill(pid_t pid, int sig) {
 *         // ...
 *         auto ret = global_object->kill(pid, sig);
 *         if (ret.first)
 *             return ret.second;
 *         return __real_kill(pid, sig);
 *     }
 *
 * global_object can handle the wrapped function or pass it to the real version, by manipulating
 * its return value.
 */
#define WRAP(global_object, rettype, name, def_args, call_args) \
	extern "C" rettype __real_##name def_args; \
	extern "C" rettype __wrap_##name def_args { \
		std::cerr << #name"\n"; \
		assert_non_null(global_object); \
		auto ret = global_object->name call_args; \
		if (ret.first) \
			return ret.second; \
		return __real_##name call_args; \
	}

/* Macro WRAP64 is used for wrapping the large-file versions of the base call.
 *
 * Its params are similar to WRAP (except global_object), but they call the base version of
 * the call (so as to keep the queue of mocks intact, i.e. allow "__will_return(foo, x)"
 * to return the value even inside foo64.
 *
 * Keep in mind this only really works when the base call is mocked as well. */
#define WRAP64(rettype, name, def_args, call_args) \
	extern "C" rettype __wrap_##name##64 def_args { \
		return __wrap_##name call_args; \
	}

/*
 * Macro MOCK is used for redirecting function handlers for mocked functions from resourced
 * to global_test_lowmem_limit_env static object.
 * Its params are:
 * - global_object - an object that actually handles the mocked function;
 * - rettype - return type of the wrapped function;
 * - name - the name of the wrapped function;
 * - def_args - function arguments as defined in function declaration, e.g. (pid_t pid)
 * - call_args - function arguments as used in calling, e.g. (pid)
 *
 */
#define MOCK(global_object, rettype, name, def_args, call_args) \
	extern "C" rettype name def_args { \
		std::cerr << #name"\n"; \
		if (!global_object) std::cerr << "no global_object!\n"; \
		assert_non_null(global_object); \
		return global_object->name call_args; \
	}