1 /*
2  * Copyright (c) 2022 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <zephyr/ztest.h>
9 
10 #include "lwm2m_engine.h"
11 #include "lwm2m_rw_link_format.h"
12 
13 #define TEST_SSID 101
14 #define TEST_PMIN 5
15 #define TEST_PMAX 200
16 
17 #define TEST_OBJ_ID 0xFFFF
18 #define TEST_OBJ_INST_ID 0
19 
20 #define TEST_RES_S8 0
21 
22 #define TEST_OBJ_RES_MAX_ID 2
23 
24 static struct lwm2m_engine_obj test_obj;
25 
26 static struct lwm2m_engine_obj_field test_fields[] = {
27 	OBJ_FIELD_DATA(TEST_RES_S8, RW, S8),
28 };
29 
30 static struct lwm2m_engine_obj_inst test_inst;
31 static struct lwm2m_engine_res test_res[TEST_OBJ_RES_MAX_ID];
32 static struct lwm2m_engine_res_inst test_res_inst[TEST_OBJ_RES_MAX_ID];
33 
34 static int8_t test_s8;
35 
test_obj_create(uint16_t obj_inst_id)36 static struct lwm2m_engine_obj_inst *test_obj_create(uint16_t obj_inst_id)
37 {
38 	int i = 0, j = 0;
39 
40 	init_res_instance(test_res_inst, ARRAY_SIZE(test_res_inst));
41 
42 	INIT_OBJ_RES_DATA(TEST_RES_S8, test_res, i, test_res_inst, j,
43 			  &test_s8, sizeof(test_s8));
44 
45 	test_inst.resources = test_res;
46 	test_inst.resource_count = i;
47 
48 	return &test_inst;
49 }
50 
test_obj_init(void)51 static void test_obj_init(void)
52 {
53 	struct lwm2m_engine_obj_inst *obj_inst = NULL;
54 
55 	test_obj.obj_id = TEST_OBJ_ID;
56 	test_obj.version_major = 1;
57 	test_obj.version_minor = 1;
58 	test_obj.is_core = false;
59 	test_obj.fields = test_fields;
60 	test_obj.field_count = ARRAY_SIZE(test_fields);
61 	test_obj.max_instance_count = 1U;
62 	test_obj.create_cb = test_obj_create;
63 
64 	(void)lwm2m_register_obj(&test_obj);
65 	(void)lwm2m_create_obj_inst(TEST_OBJ_ID, TEST_OBJ_INST_ID, &obj_inst);
66 }
67 
test_attr_init(void)68 static void test_attr_init(void)
69 {
70 	struct lwm2m_attr *attr;
71 
72 	attr = lwm2m_engine_get_next_attr(NULL, NULL);
73 	attr->type = LWM2M_ATTR_PMIN;
74 	attr->int_val = TEST_PMIN;
75 	attr->ref = &test_inst;
76 
77 	attr = lwm2m_engine_get_next_attr(NULL, NULL);
78 	attr->type = LWM2M_ATTR_PMAX;
79 	attr->int_val = TEST_PMAX;
80 	attr->ref = &test_res;
81 }
82 
83 static struct lwm2m_output_context test_out;
84 static struct lwm2m_obj_path test_path;
85 static struct coap_packet test_packet;
86 static uint8_t test_payload[128];
87 static struct link_format_out_formatter_data test_formatter_data;
88 
context_reset(void)89 static void context_reset(void)
90 {
91 	memset(&test_out, 0, sizeof(test_out));
92 	test_out.writer = &link_format_writer;
93 	test_out.out_cpkt = &test_packet;
94 	test_out.user_data = &test_formatter_data;
95 
96 	memset(&test_payload, 0, sizeof(test_payload));
97 	memset(&test_packet, 0, sizeof(test_packet));
98 	test_packet.data = test_payload;
99 	test_packet.max_len = sizeof(test_payload);
100 
101 	memset(&test_path, 0, sizeof(test_path));
102 	test_path.level = LWM2M_PATH_LEVEL_OBJECT;
103 	test_path.obj_id = TEST_OBJ_ID;
104 	test_path.obj_inst_id = TEST_OBJ_INST_ID;
105 	test_path.res_id = TEST_RES_S8;
106 
107 	memset(&test_formatter_data, 0, sizeof(test_formatter_data));
108 	test_formatter_data.is_first = true;
109 	test_formatter_data.request_level = LWM2M_PATH_LEVEL_OBJECT;
110 }
111 
test_prepare(void * dummy)112 static void test_prepare(void *dummy)
113 {
114 	context_reset();
115 }
116 
test_prepare_nomem(void * dummy)117 static void test_prepare_nomem(void *dummy)
118 {
119 	context_reset();
120 
121 	test_packet.offset = sizeof(test_payload);
122 }
123 
ZTEST(net_content_link_format,test_put_begin_discovery)124 ZTEST(net_content_link_format, test_put_begin_discovery)
125 {
126 	int ret;
127 	const char *expected_payload = "";
128 
129 	test_formatter_data.mode = LINK_FORMAT_MODE_DISCOVERY;
130 
131 	ret = link_format_writer.put_begin(&test_out, &test_path);
132 	zassert_equal(ret, strlen(expected_payload),
133 		      "Invalid length returned");
134 	zassert_mem_equal(test_out.out_cpkt->data, expected_payload,
135 			  strlen(expected_payload), "Invalid payload format");
136 	zassert_equal(test_out.out_cpkt->offset, strlen(expected_payload),
137 			"Invalid packet offset");
138 }
139 
ZTEST(net_content_link_format,test_put_begin_bs_discovery)140 ZTEST(net_content_link_format, test_put_begin_bs_discovery)
141 {
142 	int ret;
143 	const char *expected_payload = "</>;lwm2m=\"1.0\"";
144 
145 	test_formatter_data.mode = LINK_FORMAT_MODE_BOOTSTRAP_DISCOVERY;
146 
147 	ret = link_format_writer.put_begin(&test_out, &test_path);
148 	zassert_equal(ret, strlen(expected_payload),
149 		      "Invalid length returned");
150 	zassert_mem_equal(test_out.out_cpkt->data, expected_payload,
151 			  strlen(expected_payload), "Invalid payload format");
152 	zassert_equal(test_out.out_cpkt->offset, strlen(expected_payload),
153 			"Invalid packet offset");
154 }
155 
ZTEST(net_content_link_format,test_put_begin_register)156 ZTEST(net_content_link_format, test_put_begin_register)
157 {
158 	int ret;
159 	const char *expected_payload = "</>;ct=11543";
160 
161 	test_formatter_data.mode = LINK_FORMAT_MODE_REGISTER;
162 
163 	ret = link_format_writer.put_begin(&test_out, &test_path);
164 	zassert_equal(ret, strlen(expected_payload),
165 		      "Invalid length returned");
166 	zassert_mem_equal(test_out.out_cpkt->data, expected_payload,
167 			  strlen(expected_payload), "Invalid payload format");
168 	zassert_equal(test_out.out_cpkt->offset, strlen(expected_payload),
169 			"Invalid packet offset");
170 }
171 
ZTEST(net_content_link_format_nomem,test_put_begin_nomem)172 ZTEST(net_content_link_format_nomem, test_put_begin_nomem)
173 {
174 	int ret;
175 
176 	test_formatter_data.mode = LINK_FORMAT_MODE_REGISTER;
177 
178 	ret = link_format_writer.put_begin(&test_out, &test_path);
179 	zassert_equal(ret, -ENOMEM, "Invalid error code returned");
180 }
181 
182 struct test_case_corelink {
183 	uint8_t request_level;
184 	uint8_t path_level;
185 	const char *expected_payload;
186 };
187 
ZTEST(net_content_link_format,test_put_corelink_discovery)188 ZTEST(net_content_link_format, test_put_corelink_discovery)
189 {
190 	int ret;
191 	int i;
192 	struct test_case_corelink test_case[] = {
193 		{
194 			.request_level = LWM2M_PATH_LEVEL_OBJECT,
195 			.path_level = LWM2M_PATH_LEVEL_OBJECT,
196 			.expected_payload = "</65535>;ver=1.1"
197 		},
198 		{
199 			.request_level = LWM2M_PATH_LEVEL_OBJECT,
200 			.path_level = LWM2M_PATH_LEVEL_OBJECT_INST,
201 			.expected_payload = "</65535/0>"
202 		},
203 		{
204 			.request_level = LWM2M_PATH_LEVEL_OBJECT,
205 			.path_level = LWM2M_PATH_LEVEL_RESOURCE,
206 			.expected_payload = "</65535/0/0>"
207 		},
208 		{
209 			.request_level = LWM2M_PATH_LEVEL_OBJECT_INST,
210 			.path_level = LWM2M_PATH_LEVEL_OBJECT_INST,
211 			.expected_payload = "</65535/0>;pmin=" STRINGIFY(TEST_PMIN)
212 		},
213 		{
214 			.request_level = LWM2M_PATH_LEVEL_OBJECT_INST,
215 			.path_level = LWM2M_PATH_LEVEL_RESOURCE,
216 			.expected_payload = "</65535/0/0>;pmax=" STRINGIFY(TEST_PMAX)
217 		},
218 		{
219 			.request_level = LWM2M_PATH_LEVEL_RESOURCE,
220 			.path_level = LWM2M_PATH_LEVEL_RESOURCE,
221 			.expected_payload = "</65535/0/0>;pmin=" STRINGIFY(TEST_PMIN)
222 					    ";pmax=" STRINGIFY(TEST_PMAX)
223 		},
224 	};
225 
226 	for (i = 0; i < ARRAY_SIZE(test_case); i++) {
227 		context_reset();
228 
229 		test_formatter_data.mode = LINK_FORMAT_MODE_DISCOVERY;
230 		test_formatter_data.request_level = test_case[i].request_level;
231 		test_path.level = test_case[i].path_level;
232 
233 		ret = link_format_writer.put_corelink(&test_out, &test_path);
234 		zassert_equal(ret, strlen(test_case[i].expected_payload),
235 			      "Invalid length returned");
236 		zassert_mem_equal(test_out.out_cpkt->data,
237 				  test_case[i].expected_payload,
238 				  strlen(test_case[i].expected_payload),
239 				  "Invalid payload format");
240 		zassert_equal(test_out.out_cpkt->offset,
241 			      strlen(test_case[i].expected_payload),
242 			      "Invalid packet offset");
243 	}
244 }
245 
ZTEST(net_content_link_format,test_put_corelink_bs_discovery)246 ZTEST(net_content_link_format, test_put_corelink_bs_discovery)
247 {
248 	int ret;
249 	int i;
250 	struct test_case_corelink test_case[] = {
251 		{
252 			.request_level = LWM2M_PATH_LEVEL_NONE,
253 			.path_level = LWM2M_PATH_LEVEL_OBJECT,
254 			.expected_payload = "</65535>;ver=1.1"
255 		},
256 		{
257 			.request_level = LWM2M_PATH_LEVEL_NONE,
258 			.path_level = LWM2M_PATH_LEVEL_OBJECT_INST,
259 			.expected_payload = "</65535/0>"
260 		},
261 		{
262 			.request_level = LWM2M_PATH_LEVEL_OBJECT,
263 			.path_level = LWM2M_PATH_LEVEL_OBJECT,
264 			.expected_payload = "</65535>;ver=1.1"
265 		},
266 		{
267 			.request_level = LWM2M_PATH_LEVEL_OBJECT,
268 			.path_level = LWM2M_PATH_LEVEL_OBJECT_INST,
269 			.expected_payload = "</65535/0>"
270 		},
271 	};
272 
273 	for (i = 0; i < ARRAY_SIZE(test_case); i++) {
274 		context_reset();
275 
276 		test_formatter_data.mode = LINK_FORMAT_MODE_BOOTSTRAP_DISCOVERY;
277 		test_formatter_data.request_level = test_case[i].request_level;
278 		test_path.level = test_case[i].path_level;
279 
280 		ret = link_format_writer.put_corelink(&test_out, &test_path);
281 		zassert_equal(ret, strlen(test_case[i].expected_payload),
282 			      "Invalid length returned");
283 		zassert_mem_equal(test_out.out_cpkt->data,
284 				  test_case[i].expected_payload,
285 				  strlen(test_case[i].expected_payload),
286 				  "Invalid payload format");
287 		zassert_equal(test_out.out_cpkt->offset,
288 			      strlen(test_case[i].expected_payload),
289 			      "Invalid packet offset");
290 	}
291 }
292 
ZTEST(net_content_link_format,test_put_corelink_bs_discovery_ssid)293 ZTEST(net_content_link_format, test_put_corelink_bs_discovery_ssid)
294 {
295 	int ret;
296 	int i;
297 	char * const expected_payload[] = {
298 		"</0/0>;ssid=" STRINGIFY(TEST_SSID),
299 		"</1/0>;ssid=" STRINGIFY(TEST_SSID),
300 	};
301 	uint16_t test_obj_id[] = {
302 		LWM2M_OBJECT_SECURITY_ID,
303 		LWM2M_OBJECT_SERVER_ID,
304 	};
305 
306 	for (i = 0; i < ARRAY_SIZE(expected_payload); i++) {
307 		context_reset();
308 
309 		test_formatter_data.mode = LINK_FORMAT_MODE_BOOTSTRAP_DISCOVERY;
310 		test_formatter_data.request_level = LWM2M_PATH_LEVEL_NONE;
311 		test_path.level = LWM2M_PATH_LEVEL_OBJECT_INST;
312 		test_path.obj_id = test_obj_id[i];
313 		test_path.obj_inst_id = 0;
314 
315 		ret = link_format_writer.put_corelink(&test_out, &test_path);
316 		zassert_equal(ret, strlen(expected_payload[i]),
317 			      "Invalid length returned");
318 		zassert_mem_equal(test_out.out_cpkt->data,
319 				  expected_payload[i],
320 				  strlen(expected_payload[i]),
321 				  "Invalid payload format");
322 		zassert_equal(test_out.out_cpkt->offset,
323 			      strlen(expected_payload[i]),
324 			      "Invalid packet offset");
325 	}
326 }
327 
ZTEST(net_content_link_format,test_put_corelink_register)328 ZTEST(net_content_link_format, test_put_corelink_register)
329 {
330 	int ret;
331 	int i;
332 	struct test_case_corelink test_case[] = {
333 		{
334 			.request_level = LWM2M_PATH_LEVEL_NONE,
335 			.path_level = LWM2M_PATH_LEVEL_OBJECT,
336 			.expected_payload = "</65535>;ver=1.1"
337 		},
338 		{
339 			.request_level = LWM2M_PATH_LEVEL_NONE,
340 			.path_level = LWM2M_PATH_LEVEL_OBJECT_INST,
341 			.expected_payload = "</65535/0>"
342 		},
343 	};
344 
345 	for (i = 0; i < ARRAY_SIZE(test_case); i++) {
346 		context_reset();
347 
348 		test_formatter_data.mode = LINK_FORMAT_MODE_REGISTER;
349 		test_formatter_data.request_level = test_case[i].request_level;
350 		test_path.level = test_case[i].path_level;
351 
352 		ret = link_format_writer.put_corelink(&test_out, &test_path);
353 		zassert_equal(ret, strlen(test_case[i].expected_payload),
354 			      "Invalid length returned");
355 		zassert_mem_equal(test_out.out_cpkt->data,
356 				  test_case[i].expected_payload,
357 				  strlen(test_case[i].expected_payload),
358 				  "Invalid payload format");
359 		zassert_equal(test_out.out_cpkt->offset,
360 			      strlen(test_case[i].expected_payload),
361 			      "Invalid packet offset");
362 	}
363 }
364 
ZTEST(net_content_link_format_nomem,test_put_corelink_nomem)365 ZTEST(net_content_link_format_nomem, test_put_corelink_nomem)
366 {
367 	int ret;
368 
369 	test_formatter_data.mode = LINK_FORMAT_MODE_REGISTER;
370 	test_formatter_data.request_level = LWM2M_PATH_LEVEL_NONE;
371 
372 	ret = link_format_writer.put_corelink(&test_out, &test_path);
373 	zassert_equal(ret, -ENOMEM, "Invalid error code returned");
374 }
375 
obj_attr_init(void)376 static void *obj_attr_init(void)
377 {
378 	test_obj_init();
379 	test_attr_init();
380 	lwm2m_set_u16(&LWM2M_OBJ(0, 0, 10), TEST_SSID);
381 	lwm2m_set_u16(&LWM2M_OBJ(1, 0, 0), TEST_SSID);
382 	return NULL;
383 }
384 
385 ZTEST_SUITE(net_content_link_format, NULL, obj_attr_init, test_prepare, NULL, NULL);
386 ZTEST_SUITE(net_content_link_format_nomem, NULL, obj_attr_init, test_prepare_nomem, NULL, NULL);
387