1 /*
2  * Copyright (c) 2023 Codecoup
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/fff.h>
8 #include <zephyr/kernel.h>
9 #include <zephyr/bluetooth/bluetooth.h>
10 
11 DEFINE_FFF_GLOBALS;
12 
13 FAKE_VALUE_FUNC(bool, bt_data_parse_func, struct bt_data *, void *);
14 
fff_reset_rule_before(const struct ztest_unit_test * test,void * fixture)15 static void fff_reset_rule_before(const struct ztest_unit_test *test, void *fixture)
16 {
17 	RESET_FAKE(bt_data_parse_func);
18 }
19 
20 ZTEST_RULE(fff_reset_rule, fff_reset_rule_before, NULL);
21 
22 ZTEST_SUITE(bt_data_parse, NULL, NULL, NULL, NULL, NULL);
23 
24 /*
25  *  Test empty data buffer
26  *
27  *  Constraints:
28  *   - data.len set to 0
29  *
30  *  Expected behaviour:
31  *   - Callback function is not called
32  */
ZTEST(bt_data_parse,test_parsing_empty_buf)33 ZTEST(bt_data_parse, test_parsing_empty_buf)
34 {
35 	struct net_buf_simple *buf = NET_BUF_SIMPLE(0);
36 
37 	bt_data_parse(buf, bt_data_parse_func, NULL);
38 
39 	zassert_equal(bt_data_parse_func_fake.call_count, 0);
40 }
41 
42 /*
43  *  Test AD Structure invalid length
44  *
45  *  Constraints:
46  *   - AD Structure N length > number of bytes after
47  *
48  *  Expected behaviour:
49  *   - Callback function is called N - 1 times
50  */
ZTEST(bt_data_parse,test_parsing_invalid_length)51 ZTEST(bt_data_parse, test_parsing_invalid_length)
52 {
53 	struct net_buf_simple buf;
54 	uint8_t data[] = {
55 		/* Significant part */
56 		0x02, 0x01, 0x00,                       /* AD Structure 1 */
57 		0x03, 0x02, 0x01, 0x00,                 /* AD Structure 2 */
58 		/* Invalid length 0xff */
59 		0xff, 0x03, 0x02, 0x01,                 /* AD Structure N */
60 		0x05, 0x04, 0x03, 0x02, 0x01, 0x00,     /* AD Structure N + 1 */
61 	};
62 
63 	bt_data_parse_func_fake.return_val = true;
64 
65 	net_buf_simple_init_with_data(&buf, data, ARRAY_SIZE(data));
66 
67 	bt_data_parse(&buf, bt_data_parse_func, NULL);
68 
69 	zassert_equal(2, bt_data_parse_func_fake.call_count,
70 		      "called %d", bt_data_parse_func_fake.call_count);
71 }
72 
73 /*
74  *  Test early termination of the significant part
75  *
76  *  Constraints:
77  *   - The significant part contains a sequence of N AD structures
78  *   - The non-significant part extends the data with all-zero octets
79  *
80  *  Expected behaviour:
81  *   - Callback function is called N times
82  */
ZTEST(bt_data_parse,test_parsing_early_termination)83 ZTEST(bt_data_parse, test_parsing_early_termination)
84 {
85 	struct net_buf_simple buf;
86 	uint8_t data[] = {
87 		/* Significant part */
88 		0x02, 0x01, 0x00,                       /* AD Structure 1 */
89 		0x03, 0x02, 0x01, 0x00,                 /* AD Structure 2 */
90 		0x04, 0x03, 0x02, 0x01, 0x00,           /* AD Structure 3 */
91 		/* Non-significant part */
92 		0x00, 0x00, 0x00, 0x00, 0x00
93 	};
94 
95 	bt_data_parse_func_fake.return_val = true;
96 
97 	net_buf_simple_init_with_data(&buf, data, ARRAY_SIZE(data));
98 
99 	bt_data_parse(&buf, bt_data_parse_func, NULL);
100 
101 	zassert_equal(3, bt_data_parse_func_fake.call_count,
102 		      "called %d", bt_data_parse_func_fake.call_count);
103 }
104 
105 /*
106  *  Test parsing stopped
107  *
108  *  Constraints:
109  *   - Data contains valid AD Structures
110  *   - Callback function returns false to stop parsing
111  *
112  *  Expected behaviour:
113  *   - Once parsing is stopped, the callback is not called anymore
114  */
ZTEST(bt_data_parse,test_parsing_stopped)115 ZTEST(bt_data_parse, test_parsing_stopped)
116 {
117 	struct net_buf_simple buf;
118 	uint8_t data[] = {
119 		/* Significant part */
120 		0x02, 0x01, 0x00,                       /* AD Structure 1 */
121 		0x03, 0x02, 0x01, 0x00,                 /* AD Structure 2 */
122 	};
123 
124 	bt_data_parse_func_fake.return_val = false;
125 
126 	net_buf_simple_init_with_data(&buf, data, ARRAY_SIZE(data));
127 
128 	bt_data_parse(&buf, bt_data_parse_func, NULL);
129 
130 	zassert_equal(1, bt_data_parse_func_fake.call_count,
131 		      "called %d", bt_data_parse_func_fake.call_count);
132 }
133 
134 struct custom_fake_user_data {
135 	const uint8_t *data;
136 	size_t len;
137 };
138 
bt_data_parse_func_custom_fake(struct bt_data * data,void * user_data)139 static bool bt_data_parse_func_custom_fake(struct bt_data *data,
140 					   void *user_data)
141 {
142 	struct custom_fake_user_data *ud = user_data;
143 
144 	/* length check */
145 	zassert_true(ud->len-- > 0);
146 	zassert_equal(data->data_len, *ud->data - 1);
147 	ud->data++;
148 
149 	/* type check */
150 	zassert_true(ud->len-- > 0);
151 	zassert_equal(data->type, *ud->data);
152 	ud->data++;
153 
154 	/* value check */
155 	zassert_true(ud->len >= data->data_len);
156 	zassert_mem_equal(data->data, ud->data, data->data_len);
157 	ud->data += data->data_len;
158 	ud->len -= data->data_len;
159 
160 	return true;
161 }
162 
163 /*
164  *  Test parsing AD Data
165  *
166  *  Constraints:
167  *   - Data contains valid AD Structures
168  *   - Callback function returns false to stop parsing
169  *
170  *  Expected behaviour:
171  *   - Data passed to the callback match the expected data
172  */
ZTEST(bt_data_parse,test_parsing_success)173 ZTEST(bt_data_parse, test_parsing_success)
174 {
175 	struct net_buf_simple buf;
176 	uint8_t data[] = {
177 		/* Significant part */
178 		0x02, 0x01, 0x00,                       /* AD Structure 1 */
179 		0x03, 0x02, 0x01, 0x00,                 /* AD Structure 2 */
180 	};
181 	struct custom_fake_user_data user_data = {
182 		.data = data,
183 		.len = ARRAY_SIZE(data),
184 	};
185 
186 	bt_data_parse_func_fake.custom_fake = bt_data_parse_func_custom_fake;
187 
188 	net_buf_simple_init_with_data(&buf, data, ARRAY_SIZE(data));
189 
190 	bt_data_parse(&buf, bt_data_parse_func, &user_data);
191 
192 	zassert_equal(2, bt_data_parse_func_fake.call_count,
193 		      "called %d", bt_data_parse_func_fake.call_count);
194 }
195