-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathsensor_test.c
More file actions
150 lines (126 loc) · 6.2 KB
/
Copy pathsensor_test.c
File metadata and controls
150 lines (126 loc) · 6.2 KB
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/* Unittest for suts/sensor.c
* Compile using `gcc example/sensor_test.c example/suts/sensor.c -o ./sensor_test`
*/
#include <stdbool.h>
#define YUKTI_TEST_IMPLEMENTATION
#include "../yukti.h"
#include "suts/sensor.h"
/*************************************************************************************
* Mocking of readADC function
************************************************************************************/
YT_DECLARE_FUNC (uint16_t, readADC);
YT_DECLARE_FUNC (int, start_printing, const char*);
YT_DECLARE_FUNC (bool, is_printing_complete, int);
YT_DECLARE_FUNC_VOID (printer_report_progress, int);
YT_DECLARE_FUNC_VOID (set_status, Status);
YT_DEFINE_FUNC (uint16_t, readADC);
YT_DEFINE_FUNC (int, start_printing, const char*);
YT_DEFINE_FUNC (bool, is_printing_complete, int);
YT_DEFINE_FUNC_VOID (printer_report_progress, int);
YT_DEFINE_FUNC_VOID (set_status, Status);
/*************************************************************************************
* Tests
************************************************************************************/
YT_TESTP (sensor, read_temperature_test, uint16_t, double)
{
uint16_t adc_value = YT_ARG_0();
double temperature_exp = YT_ARG_1();
// readADC() called by read_temperature() SUT function should return the adc value we expect.
readADC_fake.ret = adc_value;
// Absolute floating point comparisons. Passes if actual & expectation differs less or equal to
// 0.00999.
YT_EQ_DOUBLE_ABS (read_temperature(), temperature_exp, 0.00999);
// Relative floating point comparisons. Passes if the difference (of actual & expectation)
// differs less than or equal to 0.1% of the largest value.
YT_EQ_DOUBLE_REL (read_temperature(), temperature_exp, 0.001);
YT_END();
}
YT_TEST (printer, printer_fail)
{
#define DUMMY_FILE_NAME "./somefile"
// In order to simulate printer error, we want start_printing() function to return a negative
// number. start_printing() is called by the print_and_wait() SUT function.
start_printing_fake.ret = -1;
// Since printing has failed, we expect `set_status (STATUS_ERROR)` to be called. ANY_ORDER
// macro is used because we don't care in what order this is called.
YT_MUST_CALL_ANY_ORDER (set_status, YT_V (STATUS_ERROR));
// Call the actual SUT function.
print_and_wait (DUMMY_FILE_NAME);
YT_END();
}
// Handler function is called when `is_printing_complete` mocked function is called. It must have
// the same signature as its mocked function, i.e `is_printing_complete` function here. What the
// handler function does has no effect as long as it returns what `is_printing_complete` function
// expects.
bool is_printing_complete_handler (int id)
{
(void)id; // unused argument.
// * `is_printing_complete.resources` is used to pass values from the test function. Since the
// handler function is called from within the test function, we can pass stack variables through
// this `resources`.
int stop_after_iteration = *(int*)is_printing_complete_fake.resources;
// * `is_printing_complete.invokeCount` shows the number of times this mocked function was
// called. Starting from 1.
return (is_printing_complete_fake.invokeCount > (unsigned)stop_after_iteration);
}
YT_TEST (printer, printer_success)
{
#define DUMMY_FILE_NAME "./somefile"
// In order to simulate printer error, we want start_printing() function to return a
// non-negative number. This step is OPTIONAL, since all fakes by default returns 0.
start_printing_fake.ret = 0;
// is_printing_complete() function should return false for 2 iterations, then it should return
// true to break out of the `while` loop in the print_and_wait() SUT function. The handler
// function contains this logic. To make it more flexible, we can pass in the number of
// iterations in is_printing_complete.resources.
int stop_after_iteration = 2;
is_printing_complete_fake.resources = &stop_after_iteration;
is_printing_complete_fake.handler = is_printing_complete_handler;
// Since this is the success case we do not expect `set_status (STATUS_ERROR)` to ever be
// called.
YT_MUST_NEVER_CALL (set_status, YT_V (STATUS_ERROR));
// We expect these functions to be called in the following order - start_printing() first
// followed by is_printing_complete() and so on. Note that print_and_wait() function might be
// calling more functions, but we only validate expectations on functions which we care about in
// the test.
// We can put expectations on what arguments were passed. There are two macros of this:
// * 'YT_V(..)' macro is used to pass some value when its expected. Here we expect
// `start_printing` to be called with the file name we passed to the SUT function
YT_MUST_CALL_IN_ORDER (start_printing, YT_V (DUMMY_FILE_NAME));
// YT_IN_SEQUENCE repeats the expectations placed within it the given number of times. It is
// used to put expectations on a loop which iterates some number of times.
YT_IN_SEQUENCE (stop_after_iteration)
{
// * '_' means don't care argument. That is we just expect 'is_printing_complete' to be
// called, but do not care about what argument was passed to it.
YT_MUST_CALL_IN_ORDER (is_printing_complete, _);
YT_MUST_CALL_IN_ORDER (printer_report_progress, _);
}
YT_MUST_CALL_IN_ORDER (set_status, YT_V (STATUS_FINISHED));
// Call the actual SUT function.
print_and_wait (DUMMY_FILE_NAME);
YT_END();
}
/*************************************************************************************
* Reset Mock functions.
* This function is automatically called before each test function is run.
************************************************************************************/
void yt_reset()
{
YT_RESET_MOCK (readADC);
YT_RESET_MOCK (start_printing);
YT_RESET_MOCK (is_printing_complete);
YT_RESET_MOCK (printer_report_progress);
YT_RESET_MOCK (set_status);
}
int main()
{
YT_INIT();
// clang-format off
read_temperature_test (3, YT_ARG (uint16_t){ 0, 24, 1023 },
YT_ARG (double){ 0.0, 29.32, 1250.0 });
// clang_format on
printer_fail();
printer_success();
YT_RETURN_WITH_REPORT();
}