1 /*
2 * Copyright (c) 2023 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/ztest.h>
8 #include <zephyr/sys/util.h>
9 #include "lwm2m_engine.h"
10 #include "lwm2m_util.h"
11
12 #define TEST_OBJ_ID 32768
13
14 static uint32_t callback_checker;
15 static char pre_write_cb_buf[10];
16
pre_write_cb(uint16_t obj_inst_id,uint16_t res_id,uint16_t res_inst_id,size_t * data_len)17 static void *pre_write_cb(uint16_t obj_inst_id,
18 uint16_t res_id,
19 uint16_t res_inst_id,
20 size_t *data_len)
21 {
22 callback_checker |= 0x01;
23 return pre_write_cb_buf;
24 }
25
post_write_cb(uint16_t obj_inst_id,uint16_t res_id,uint16_t res_inst_id,uint8_t * data,uint16_t data_len,bool last_block,size_t total_size,size_t offset)26 static int post_write_cb(uint16_t obj_inst_id, uint16_t res_id,
27 uint16_t res_inst_id, uint8_t *data,
28 uint16_t data_len, bool last_block,
29 size_t total_size, size_t offset)
30 {
31 callback_checker |= 0x02;
32 return 0;
33 }
34
read_cb(uint16_t obj_inst_id,uint16_t res_id,uint16_t res_inst_id,size_t * data_len)35 static void *read_cb(uint16_t obj_inst_id,
36 uint16_t res_id,
37 uint16_t res_inst_id,
38 size_t *data_len)
39 {
40 callback_checker |= 0x04;
41 return 0;
42 }
43
validate_cb(uint16_t obj_inst_id,uint16_t res_id,uint16_t res_inst_id,uint8_t * data,uint16_t data_len,bool last_block,size_t total_size,size_t offset)44 static int validate_cb(uint16_t obj_inst_id, uint16_t res_id,
45 uint16_t res_inst_id, uint8_t *data, uint16_t data_len,
46 bool last_block, size_t total_size, size_t offset)
47 {
48 callback_checker |= 0x08;
49 return 0;
50 }
51
obj_create_cb(uint16_t obj_inst_id)52 static int obj_create_cb(uint16_t obj_inst_id)
53 {
54 callback_checker |= 0x10;
55 return 0;
56 }
57
obj_delete_cb(uint16_t obj_inst_id)58 static int obj_delete_cb(uint16_t obj_inst_id)
59 {
60 callback_checker |= 0x20;
61 return 0;
62 }
63
exec_cb(uint16_t obj_inst_id,uint8_t * args,uint16_t args_len)64 static int exec_cb(uint16_t obj_inst_id, uint8_t *args, uint16_t args_len)
65 {
66 callback_checker |= 0x40;
67 return 0;
68 }
69
70 ZTEST_SUITE(lwm2m_registry, NULL, NULL, NULL, NULL, NULL);
71
ZTEST(lwm2m_registry,test_object_creation_and_deletion)72 ZTEST(lwm2m_registry, test_object_creation_and_deletion)
73 {
74 int ret;
75
76 ret = lwm2m_create_object_inst(&LWM2M_OBJ(3303, 0));
77 zassert_equal(ret, 0);
78
79 ret = lwm2m_delete_object_inst(&LWM2M_OBJ(3303, 0));
80 zassert_equal(ret, 0);
81 }
82
ZTEST(lwm2m_registry,test_create_unknown_object)83 ZTEST(lwm2m_registry, test_create_unknown_object)
84 {
85 int ret;
86
87 ret = lwm2m_create_object_inst(&LWM2M_OBJ(49999, 0));
88 zassert_equal(ret, -ENOENT);
89 }
90
ZTEST(lwm2m_registry,test_resource_buf)91 ZTEST(lwm2m_registry, test_resource_buf)
92 {
93 int ret;
94 uint8_t resource_buf = 0;
95
96 ret = lwm2m_create_object_inst(&LWM2M_OBJ(3303, 0));
97 zassert_equal(ret, 0);
98
99 ret = lwm2m_set_res_buf(&LWM2M_OBJ(3303, 0, 6042), &resource_buf, sizeof(resource_buf),
100 sizeof(resource_buf), 0);
101 zassert_equal(ret, 0);
102
103 ret = lwm2m_set_u8(&LWM2M_OBJ(3303, 0, 6042), 0x5A);
104 zassert_equal(ret, 0);
105
106 zassert_equal(resource_buf, 0x5A);
107
108 ret = lwm2m_delete_object_inst(&LWM2M_OBJ(3303, 0));
109 zassert_equal(ret, 0);
110 }
111
ZTEST(lwm2m_registry,test_unknown_res)112 ZTEST(lwm2m_registry, test_unknown_res)
113 {
114 int ret;
115 uint8_t resource_buf = 0;
116
117 ret = lwm2m_create_object_inst(&LWM2M_OBJ(3303, 0));
118 zassert_equal(ret, 0);
119
120 ret = lwm2m_set_res_buf(&LWM2M_OBJ(3303, 0, 49999), &resource_buf, sizeof(resource_buf),
121 sizeof(resource_buf), 0);
122 zassert_equal(ret, -ENOENT);
123
124 ret = lwm2m_delete_object_inst(&LWM2M_OBJ(3303, 0));
125 zassert_equal(ret, 0);
126 }
127
ZTEST(lwm2m_registry,test_get_res_inst)128 ZTEST(lwm2m_registry, test_get_res_inst)
129 {
130 zassert_is_null(lwm2m_engine_get_res_inst(&LWM2M_OBJ(3)));
131 zassert_is_null(lwm2m_engine_get_res_inst(&LWM2M_OBJ(3, 0)));
132 zassert_is_null(lwm2m_engine_get_res_inst(&LWM2M_OBJ(3, 0, 11)));
133 zassert_not_null(lwm2m_engine_get_res_inst(&LWM2M_OBJ(3, 0, 11, 0)));
134 }
135
136 #define GET_SET_UNINIT_PATTERN 0xA5
137 #define GET_SET_INT(c_type, name, init) \
138 struct { \
139 IDENTITY c_type out; \
140 IDENTITY c_type in; \
141 } name = {.out = init}; \
142 memset(&name.in, GET_SET_UNINIT_PATTERN, sizeof(name.in)); \
143 zassert_not_ok(memcmp(&name.out, &name.in, sizeof(name.out)), "init value must be " \
144 "non-zero")
145
146 #define GET_SET_ARRAY(c_type, name, init) \
147 struct { \
148 IDENTITY c_type out[sizeof((IDENTITY c_type[])__DEBRACKET init)]; \
149 IDENTITY c_type in[sizeof((IDENTITY c_type[])__DEBRACKET init)]; \
150 } name = {.out = __DEBRACKET init}; \
151 memset(&name.in, GET_SET_UNINIT_PATTERN, sizeof(name.in)); \
152 zassert_not_ok(memcmp(&name.out, &name.in, sizeof(name.out)), "init value must be " \
153 "non-zero")
154
155 #define GET_SET_STRING(c_type, name, init) \
156 struct { \
157 IDENTITY c_type out[sizeof(init)]; \
158 IDENTITY c_type in[sizeof(init)]; \
159 } name = {.out = init}; \
160 memset(&name.in, GET_SET_UNINIT_PATTERN, sizeof(name.in)); \
161 zassert_not_ok(memcmp(&name.out, &name.in, sizeof(name.out)), "init value must be " \
162 "non-zero")
163
164 #define GET_SET_STRUCT(c_type, name, init) \
165 struct { \
166 IDENTITY c_type out; \
167 IDENTITY c_type in; \
168 } name = {.out = __DEBRACKET init}; \
169 memset(&name.in, GET_SET_UNINIT_PATTERN, sizeof(name.in)); \
170 zassert_not_ok(memcmp(&name.out, &name.in, sizeof(name.out)), "init value must be " \
171 "non-zero")
172
ZTEST(lwm2m_registry,test_get_set)173 ZTEST(lwm2m_registry, test_get_set)
174 {
175 GET_SET_INT((bool), b, true);
176 GET_SET_ARRAY((uint8_t), opaque, ({0xde, 0xad, 0xbe, 0xff, 0, 0}));
177 GET_SET_STRING((char), string, "Hello");
178 GET_SET_INT((uint8_t), u8, 8);
179 GET_SET_INT((int8_t), s8, -8);
180 GET_SET_INT((uint16_t), u16, 16);
181 GET_SET_INT((int16_t), s16, -16);
182 GET_SET_INT((uint32_t), u32, 32);
183 GET_SET_INT((int32_t), s32, -32);
184 GET_SET_INT((int64_t), s64, -64);
185 GET_SET_INT((time_t), t, 1687949519);
186 GET_SET_INT((double), d, 3.1415);
187 GET_SET_STRUCT((struct lwm2m_objlnk), objl, ({.obj_id = 1, .obj_inst = 2}));
188
189 /* set all resources */
190 zassert_ok(lwm2m_set_bool(&LWM2M_OBJ(32768, 0, LWM2M_RES_TYPE_BOOL), b.out));
191 zassert_ok(lwm2m_set_opaque(&LWM2M_OBJ(32768, 0, LWM2M_RES_TYPE_OPAQUE), opaque.out,
192 sizeof(opaque.out)));
193 zassert_ok(lwm2m_set_string(&LWM2M_OBJ(32768, 0, LWM2M_RES_TYPE_STRING), string.out));
194 zassert_ok(lwm2m_set_u8(&LWM2M_OBJ(32768, 0, LWM2M_RES_TYPE_U8), u8.out));
195 zassert_ok(lwm2m_set_s8(&LWM2M_OBJ(32768, 0, LWM2M_RES_TYPE_S8), s8.out));
196 zassert_ok(lwm2m_set_u16(&LWM2M_OBJ(32768, 0, LWM2M_RES_TYPE_U16), u16.out));
197 zassert_ok(lwm2m_set_s16(&LWM2M_OBJ(32768, 0, LWM2M_RES_TYPE_S16), s16.out));
198 zassert_ok(lwm2m_set_u32(&LWM2M_OBJ(32768, 0, LWM2M_RES_TYPE_U32), u32.out));
199 zassert_ok(lwm2m_set_s32(&LWM2M_OBJ(32768, 0, LWM2M_RES_TYPE_S32), s32.out));
200 zassert_ok(lwm2m_set_s64(&LWM2M_OBJ(32768, 0, LWM2M_RES_TYPE_S64), s64.out));
201 zassert_ok(lwm2m_set_time(&LWM2M_OBJ(32768, 0, LWM2M_RES_TYPE_TIME), t.out));
202 zassert_ok(lwm2m_set_f64(&LWM2M_OBJ(32768, 0, LWM2M_RES_TYPE_FLOAT), d.out));
203 zassert_ok(lwm2m_set_objlnk(&LWM2M_OBJ(32768, 0, LWM2M_RES_TYPE_OBJLNK), &objl.out));
204
205 /* get all resources */
206 zassert_ok(lwm2m_get_bool(&LWM2M_OBJ(32768, 0, LWM2M_RES_TYPE_BOOL), &b.in));
207 zassert_ok(lwm2m_get_opaque(&LWM2M_OBJ(32768, 0, LWM2M_RES_TYPE_OPAQUE), opaque.in,
208 sizeof(opaque.in)));
209 zassert_ok(lwm2m_get_string(&LWM2M_OBJ(32768, 0, LWM2M_RES_TYPE_STRING), string.in,
210 sizeof(string.in)));
211 zassert_ok(lwm2m_get_u8(&LWM2M_OBJ(32768, 0, LWM2M_RES_TYPE_U8), &u8.in));
212 zassert_ok(lwm2m_get_s8(&LWM2M_OBJ(32768, 0, LWM2M_RES_TYPE_S8), &s8.in));
213 zassert_ok(lwm2m_get_u16(&LWM2M_OBJ(32768, 0, LWM2M_RES_TYPE_U16), &u16.in));
214 zassert_ok(lwm2m_get_s16(&LWM2M_OBJ(32768, 0, LWM2M_RES_TYPE_S16), &s16.in));
215 zassert_ok(lwm2m_get_u32(&LWM2M_OBJ(32768, 0, LWM2M_RES_TYPE_U32), &u32.in));
216 zassert_ok(lwm2m_get_s32(&LWM2M_OBJ(32768, 0, LWM2M_RES_TYPE_S32), &s32.in));
217 zassert_ok(lwm2m_get_s64(&LWM2M_OBJ(32768, 0, LWM2M_RES_TYPE_S64), &s64.in));
218 zassert_ok(lwm2m_get_time(&LWM2M_OBJ(32768, 0, LWM2M_RES_TYPE_TIME), &t.in));
219 zassert_ok(lwm2m_get_f64(&LWM2M_OBJ(32768, 0, LWM2M_RES_TYPE_FLOAT), &d.in));
220 zassert_ok(lwm2m_get_objlnk(&LWM2M_OBJ(32768, 0, LWM2M_RES_TYPE_OBJLNK), &objl.in));
221
222 /* check read value */
223 zassert_equal(b.in, b.out);
224 zassert_mem_equal(opaque.in, opaque.out, sizeof(opaque.out));
225 zassert_str_equal(string.in, string.out);
226 zassert_equal(u8.in, u8.out);
227 zassert_equal(s8.in, s8.out);
228 zassert_equal(u16.in, u16.out);
229 zassert_equal(s16.in, s16.out);
230 zassert_equal(u32.in, u32.out);
231 zassert_equal(s32.in, s32.out);
232 zassert_equal(s64.in, s64.out);
233 zassert_equal(t.in, t.out);
234 zassert_equal(d.in, d.out);
235 zassert_mem_equal(&objl.in, &objl.out, sizeof(objl.out));
236
237 /* set string resource to zero length */
238 zassert_ok(lwm2m_set_res_data_len(&LWM2M_OBJ(32768, 0, LWM2M_RES_TYPE_STRING), 0));
239 char buf[10];
240 zassert_ok(lwm2m_get_string(&LWM2M_OBJ(32768, 0, LWM2M_RES_TYPE_STRING), buf, sizeof(buf)));
241 zassert_equal(strlen(buf), 0);
242 }
243
ZTEST(lwm2m_registry,test_temp_sensor)244 ZTEST(lwm2m_registry, test_temp_sensor)
245 {
246 int ret;
247 uint8_t u8_buf = 0;
248 time_t time_buf = 0;
249 double dbl_buf = 0;
250 char char_buf[10];
251
252 uint8_t u8_getbuf = 0;
253 time_t time_getbuf = 0;
254 double dbl_getbuf = 0;
255 char char_getbuf[10];
256
257 ret = lwm2m_create_object_inst(&LWM2M_OBJ(3303, 0));
258 zassert_equal(ret, 0);
259
260 ret = lwm2m_set_res_buf(&LWM2M_OBJ(3303, 0, 6042), &u8_buf, sizeof(u8_buf),
261 sizeof(u8_buf), 0);
262 zassert_equal(ret, 0);
263 ret = lwm2m_set_res_buf(&LWM2M_OBJ(3303, 0, 5518), &time_buf, sizeof(time_buf),
264 sizeof(time_buf), 0);
265 zassert_equal(ret, 0);
266 ret = lwm2m_set_res_buf(&LWM2M_OBJ(3303, 0, 5601), &dbl_buf, sizeof(dbl_buf),
267 sizeof(dbl_buf), 0);
268 zassert_equal(ret, 0);
269 ret = lwm2m_set_res_buf(&LWM2M_OBJ(3303, 0, 5701), &char_buf, sizeof(char_buf),
270 sizeof(char_buf), 0);
271 zassert_equal(ret, 0);
272
273 ret = lwm2m_set_u8(&LWM2M_OBJ(3303, 0, 6042), 0x5A);
274 zassert_equal(ret, 0);
275 ret = lwm2m_set_time(&LWM2M_OBJ(3303, 0, 5518), 1674118825);
276 zassert_equal(ret, 0);
277 ret = lwm2m_set_f64(&LWM2M_OBJ(3303, 0, 5601), 5.89);
278 zassert_equal(ret, 0);
279 ret = lwm2m_set_string(&LWM2M_OBJ(3303, 0, 5701), "test");
280 zassert_equal(ret, 0);
281
282 zassert_equal(u8_buf, 0x5A);
283 zassert_equal(time_buf, 1674118825);
284 zassert_within(dbl_buf, 5.89, 0.01);
285 zassert_equal(strncmp(char_buf, "test", 10), 0);
286
287 ret = lwm2m_get_u8(&LWM2M_OBJ(3303, 0, 6042), &u8_getbuf);
288 zassert_equal(ret, 0);
289 ret = lwm2m_get_time(&LWM2M_OBJ(3303, 0, 5518), &time_getbuf);
290 zassert_equal(ret, 0);
291 ret = lwm2m_get_f64(&LWM2M_OBJ(3303, 0, 5601), &dbl_getbuf);
292 zassert_equal(ret, 0);
293 ret = lwm2m_get_string(&LWM2M_OBJ(3303, 0, 5701), &char_getbuf, 10);
294 zassert_equal(ret, 0);
295
296 zassert_equal(u8_buf, u8_getbuf);
297 zassert_equal(time_buf, time_getbuf);
298 zassert_within(dbl_buf, dbl_getbuf, 0.01);
299 zassert_equal(strncmp(char_buf, char_getbuf, 10), 0);
300
301 ret = lwm2m_delete_object_inst(&LWM2M_OBJ(3303, 0));
302 zassert_equal(ret, 0);
303 }
304
ZTEST(lwm2m_registry,test_resource_instance_creation_and_deletion)305 ZTEST(lwm2m_registry, test_resource_instance_creation_and_deletion)
306 {
307 int ret;
308
309 ret = lwm2m_create_res_inst(&LWM2M_OBJ(4, 0, 1, 0));
310 zassert_equal(ret, 0);
311
312 ret = lwm2m_delete_res_inst(&LWM2M_OBJ(4, 0, 1, 0));
313 zassert_equal(ret, 0);
314 }
315
ZTEST(lwm2m_registry,test_resource_instance_strings)316 ZTEST(lwm2m_registry, test_resource_instance_strings)
317 {
318 int ret;
319 char buf[40] = {0};
320 static const char string_a[] = "Hello";
321 static const char string_b[] = "World";
322 struct lwm2m_obj_path path_a = LWM2M_OBJ(16, 0, 0, 0);
323 struct lwm2m_obj_path path_b = LWM2M_OBJ(16, 0, 0, 1);
324
325 ret = lwm2m_create_object_inst(&LWM2M_OBJ(16, 0));
326 zassert_equal(ret, 0);
327
328 ret = lwm2m_create_res_inst(&path_a);
329 zassert_equal(ret, 0);
330
331 ret = lwm2m_create_res_inst(&path_b);
332 zassert_equal(ret, 0);
333
334 ret = lwm2m_set_string(&path_a, string_a);
335 zassert_equal(ret, 0);
336
337 ret = lwm2m_set_string(&path_b, string_b);
338 zassert_equal(ret, 0);
339
340 ret = lwm2m_get_string(&path_a, buf, sizeof(buf));
341 zassert_equal(ret, 0);
342 zassert_equal(0, memcmp(buf, string_a, sizeof(string_a)));
343
344 ret = lwm2m_get_string(&path_b, buf, sizeof(buf));
345 zassert_equal(ret, 0);
346 zassert_equal(0, memcmp(buf, string_b, sizeof(string_b)));
347
348 ret = lwm2m_delete_object_inst(&LWM2M_OBJ(16, 0));
349 zassert_equal(ret, 0);
350 }
351
ZTEST(lwm2m_registry,test_callbacks)352 ZTEST(lwm2m_registry, test_callbacks)
353 {
354 int ret;
355 double sensor_val;
356 struct lwm2m_engine_res *exec_res;
357
358 callback_checker = 0;
359 ret = lwm2m_register_create_callback(3303, obj_create_cb);
360 zassert_equal(ret, 0);
361 lwm2m_register_delete_callback(3303, obj_delete_cb);
362 zassert_equal(ret, 0);
363
364 ret = lwm2m_create_object_inst(&LWM2M_OBJ(3303, 0));
365 zassert_equal(ret, 0);
366 zassert_equal(callback_checker, 0x10);
367
368 ret = lwm2m_register_exec_callback(&LWM2M_OBJ(3303, 0, 5605), exec_cb);
369 zassert_equal(ret, 0);
370 ret = lwm2m_register_read_callback(&LWM2M_OBJ(3303, 0, 5700), read_cb);
371 zassert_equal(ret, 0);
372 ret = lwm2m_register_validate_callback(&LWM2M_OBJ(3303, 0, 5701), validate_cb);
373 zassert_equal(ret, 0);
374 ret = lwm2m_register_pre_write_callback(&LWM2M_OBJ(3303, 0, 5701), pre_write_cb);
375 zassert_equal(ret, 0);
376 ret = lwm2m_register_post_write_callback(&LWM2M_OBJ(3303, 0, 5701), post_write_cb);
377 zassert_equal(ret, 0);
378
379 exec_res = lwm2m_engine_get_res(&LWM2M_OBJ(3303, 0, 5605));
380 exec_res->execute_cb(0, 0, 0);
381
382 ret = lwm2m_set_string(&LWM2M_OBJ(3303, 0, 5701), "test");
383 zassert_equal(ret, 0);
384 zassert_equal(callback_checker, 0x5B);
385
386 ret = lwm2m_get_f64(&LWM2M_OBJ(3303, 0, 5700), &sensor_val);
387 zassert_equal(ret, 0);
388 zassert_equal(callback_checker, 0x5F);
389
390 ret = lwm2m_delete_object_inst(&LWM2M_OBJ(3303, 0));
391 zassert_equal(ret, 0);
392 zassert_equal(callback_checker, 0x7F);
393 }
394
ZTEST(lwm2m_registry,test_strings)395 ZTEST(lwm2m_registry, test_strings)
396 {
397 int ret;
398 char buf[40] = {0};
399 struct lwm2m_obj_path path = LWM2M_OBJ(TEST_OBJ_ID, 0, LWM2M_RES_TYPE_STRING);
400 static const char uri[] = "coap://127.0.0.1";
401 uint16_t len;
402 uint8_t *p;
403
404 ret = lwm2m_get_res_buf(&path, (void **)&p, &len, NULL, NULL);
405 zassert_equal(ret, 0);
406 memset(p, 0xff, len); /* Pre-fill buffer to check */
407
408 /* Handle strings in string resources */
409 ret = lwm2m_set_string(&path, uri);
410 zassert_equal(ret, 0);
411 ret = lwm2m_get_res_buf(&path, (void **)&p, NULL, &len, NULL);
412 zassert_equal(ret, 0);
413 zassert_equal(len, sizeof(uri));
414 zassert_equal(p[len - 1], '\0'); /* string terminator in buffer */
415 zassert_equal(p[len], 0xff);
416
417 ret = lwm2m_get_string(&path, buf, sizeof(buf));
418 zassert_equal(ret, 0);
419 zassert_equal(memcmp(uri, buf, sizeof(uri)), 0);
420 ret = lwm2m_get_string(&path, buf, sizeof(uri));
421 zassert_equal(ret, 0);
422 ret = lwm2m_get_string(&path, buf, strlen(uri));
423 zassert_equal(ret, -ENOMEM);
424
425 /* Handle strings in opaque resources (no terminator) */
426 path = LWM2M_OBJ(TEST_OBJ_ID, 0, LWM2M_RES_TYPE_OPAQUE);
427 ret = lwm2m_get_res_buf(&path, (void **)&p, &len, NULL, NULL);
428 zassert_equal(ret, 0);
429 memset(p, 0xff, len); /* Pre-fill buffer to check */
430
431 ret = lwm2m_set_string(&path, uri);
432 zassert_equal(ret, 0);
433 ret = lwm2m_get_res_buf(&path, (void **)&p, NULL, &len, NULL);
434 zassert_equal(ret, 0);
435 zassert_equal(len, strlen(uri)); /* No terminator counted in data length */
436 zassert_equal(p[len - 1], '1'); /* Last character in buffer is not terminator */
437 zassert_equal(p[len], 0xff);
438 memset(buf, 0xff, sizeof(buf));
439 ret = lwm2m_get_string(&path, buf, sizeof(buf)); /* get_string ensures termination */
440 zassert_equal(ret, 0);
441 zassert_equal(memcmp(uri, buf, sizeof(uri)), 0);
442 ret = lwm2m_get_string(&path, buf, sizeof(uri));
443 zassert_equal(ret, 0);
444 ret = lwm2m_get_string(&path, buf, strlen(uri));
445 zassert_equal(ret, -ENOMEM);
446 /* Corner case: we request exactly as much is stored in opaque resource, */
447 /* but because we request as a string, it must have room for terminator. */
448 ret = lwm2m_get_string(&path, buf, len);
449 zassert_equal(ret, -ENOMEM);
450 }
451
is_string(const struct lwm2m_obj_path * path)452 static bool is_string(const struct lwm2m_obj_path *path)
453 {
454 struct lwm2m_engine_obj_field *obj_field;
455 int ret;
456
457 ret = path_to_objs(path, NULL, &obj_field, NULL, NULL);
458 if (ret < 0 || !obj_field) {
459 return false;
460 }
461 if (obj_field->data_type == LWM2M_RES_TYPE_STRING) {
462 return true;
463 }
464 return false;
465 }
466
test_string_fit(struct lwm2m_obj_path * path,const char * str)467 void test_string_fit(struct lwm2m_obj_path *path, const char *str)
468 {
469 char buf[40] = {0};
470 uint8_t *p;
471 uint16_t len;
472
473 zassert_ok(lwm2m_get_res_buf(path, (void **)&p, &len, NULL, NULL));
474 zassert_equal(len, 32); /* Just check that our test object have 32 byte buffers */
475 memset(p, 0xff, len);
476 memset(buf, 0xff, sizeof(buf));
477
478 len = strlen(str);
479 zassert_true((len + 1) >= 31); /* Ensure our test strings fill entire buffer */
480
481 /* Test setting and getting a string that fits exactly */
482 zassert_ok(lwm2m_set_string(path, str));
483 zassert_ok(lwm2m_get_string(path, buf, sizeof(buf)));
484 zassert_equal(strlen(buf), len);
485 zassert_equal(memcmp(buf, str, len + 1), 0); /* check whole buffer, including terminator */
486 if (is_string(path)) {
487 zassert_equal(p[len], 0);
488 } else if (len < 32) {
489 zassert_equal(p[len], 0xff); /* did not fill entire opaque buffer */
490 } else {
491 /* Last byte on resource buffer is last byte from string, no terminator */
492 zassert_equal((uint8_t) p[31], (uint8_t) str[31]);
493 }
494 zassert_equal(buf[len], 0); /* must have terminator */
495 }
496
ZTEST(lwm2m_registry,test_strings_sizes)497 ZTEST(lwm2m_registry, test_strings_sizes)
498 {
499 static const char string32[] = "0123456789012345678901234567890";
500 static const char string33[] = "01234567890123456789012345678901";
501 static const char string34[] = "012345678901234567890123456789012";
502 static const char utf8_32[] = "©⏰⏳✅";
503 static const char utf8_33[] = "";
504 static const char utf8_34[] = "Ω✊";
505
506 struct lwm2m_obj_path path_string = LWM2M_OBJ(TEST_OBJ_ID, 0, LWM2M_RES_TYPE_STRING);
507 struct lwm2m_obj_path path_opaque = LWM2M_OBJ(TEST_OBJ_ID, 0, LWM2M_RES_TYPE_OPAQUE);
508
509 /* All OK without truncation, opaque resource does not store null terminator
510 * so it can store one byte more than string resource.
511 */
512 test_string_fit(&path_string, string32);
513 test_string_fit(&path_opaque, string32);
514 test_string_fit(&path_opaque, string33);
515 test_string_fit(&path_string, utf8_32);
516 test_string_fit(&path_opaque, utf8_32);
517 test_string_fit(&path_opaque, utf8_33);
518
519 /* These would truncate */
520 zassert_equal(lwm2m_set_string(&path_string, string33), -ENOMEM);
521 zassert_equal(lwm2m_set_string(&path_opaque, string34), -ENOMEM);
522 zassert_equal(lwm2m_set_string(&path_string, utf8_33), -ENOMEM);
523 zassert_equal(lwm2m_set_string(&path_opaque, utf8_34), -ENOMEM);
524 }
525
ZTEST(lwm2m_registry,test_lock_unlock)526 ZTEST(lwm2m_registry, test_lock_unlock)
527 {
528 /* Should be recursive mutex and should not block */
529 lwm2m_registry_lock();
530 lwm2m_registry_lock();
531 lwm2m_registry_unlock();
532 lwm2m_registry_unlock();
533 }
534
ZTEST(lwm2m_registry,test_resource_wrappers)535 ZTEST(lwm2m_registry, test_resource_wrappers)
536 {
537 zassert_not_null(lwm2m_engine_obj_list());
538 zassert_not_null(lwm2m_engine_obj_inst_list());
539 }
540
ZTEST(lwm2m_registry,test_unregister_obj)541 ZTEST(lwm2m_registry, test_unregister_obj)
542 {
543
544 struct lwm2m_obj_path none = {0};
545 struct lwm2m_engine_obj *obj;
546
547 zassert_is_null(lwm2m_engine_get_obj(&none));
548
549 obj = lwm2m_engine_get_obj(&LWM2M_OBJ(1));
550
551 zassert_not_null(obj);
552 lwm2m_unregister_obj(obj);
553 zassert_is_null(lwm2m_engine_get_obj(&LWM2M_OBJ(1)));
554 }
555
ZTEST(lwm2m_registry,test_next_engine_obj_inst)556 ZTEST(lwm2m_registry, test_next_engine_obj_inst)
557 {
558 zassert_equal(lwm2m_create_object_inst(&LWM2M_OBJ(3303, 0)), 0);
559 zassert_equal(lwm2m_create_object_inst(&LWM2M_OBJ(3303, 1)), 0);
560
561 struct lwm2m_engine_obj_inst *oi = lwm2m_engine_get_obj_inst(&LWM2M_OBJ(3303, 1));
562
563 zassert_not_null(oi);
564
565 zassert_not_null(next_engine_obj_inst(3303, 0));
566 zassert_equal(oi, next_engine_obj_inst(3303, 0));
567 zassert_is_null(next_engine_obj_inst(3303, 1));
568
569 zassert_equal(lwm2m_delete_object_inst(&LWM2M_OBJ(3303, 0)), 0);
570 zassert_equal(lwm2m_delete_object_inst(&LWM2M_OBJ(3303, 1)), 0);
571 zassert_is_null(lwm2m_engine_get_obj_inst(&LWM2M_OBJ(3303, 1)));
572 }
573
ZTEST(lwm2m_registry,test_null_strings)574 ZTEST(lwm2m_registry, test_null_strings)
575 {
576 int ret;
577 char buf[40] = {0};
578 struct lwm2m_obj_path path = LWM2M_OBJ(0, 0, 0);
579
580 ret = lwm2m_register_post_write_callback(&path, post_write_cb);
581 zassert_equal(ret, 0);
582
583 callback_checker = 0;
584 ret = lwm2m_set_string(&path, "string");
585 zassert_equal(ret, 0);
586 zassert_equal(callback_checker, 0x02);
587 ret = lwm2m_get_string(&path, buf, sizeof(buf));
588 zassert_equal(ret, 0);
589 zassert_equal(strlen(buf), strlen("string"));
590
591 callback_checker = 0;
592 ret = lwm2m_set_string(&path, "");
593 zassert_equal(ret, 0);
594 zassert_equal(callback_checker, 0x02);
595 ret = lwm2m_get_string(&path, buf, sizeof(buf));
596 zassert_equal(ret, 0);
597 zassert_equal(strlen(buf), 0);
598
599 callback_checker = 0;
600 ret = lwm2m_set_opaque(&path, NULL, 0);
601 zassert_equal(ret, 0);
602 zassert_equal(callback_checker, 0x02);
603 ret = lwm2m_get_string(&path, buf, sizeof(buf));
604 zassert_equal(ret, 0);
605 zassert_equal(strlen(buf), 0);
606 }
607
ZTEST(lwm2m_registry,test_obj_version)608 ZTEST(lwm2m_registry, test_obj_version)
609 {
610 #if defined(CONFIG_LWM2M_ENGINE_ALWAYS_REPORT_OBJ_VERSION)
611 zassert_true(lwm2m_engine_shall_report_obj_version(lwm2m_engine_get_obj(&LWM2M_OBJ(0))));
612 zassert_true(
613 lwm2m_engine_shall_report_obj_version(lwm2m_engine_get_obj(&LWM2M_OBJ(32768))));
614 zassert_true(lwm2m_engine_shall_report_obj_version(lwm2m_engine_get_obj(&LWM2M_OBJ(3303))));
615 #else
616 zassert_false(lwm2m_engine_shall_report_obj_version(lwm2m_engine_get_obj(&LWM2M_OBJ(0))));
617 zassert_false(
618 lwm2m_engine_shall_report_obj_version(lwm2m_engine_get_obj(&LWM2M_OBJ(32768))));
619 zassert_true(lwm2m_engine_shall_report_obj_version(lwm2m_engine_get_obj(&LWM2M_OBJ(3303))));
620 #endif
621 }
622
ZTEST(lwm2m_registry,test_resource_cache)623 ZTEST(lwm2m_registry, test_resource_cache)
624 {
625 struct lwm2m_obj_path path = LWM2M_OBJ(32768, 0, LWM2M_RES_TYPE_BOOL);
626 struct lwm2m_time_series_elem e;
627
628 /* Resource cache is turned off */
629 zassert_is_null(lwm2m_cache_entry_get_by_object(&path));
630 zassert_equal(lwm2m_enable_cache(&path, &e, 1), -ENOTSUP);
631 zassert_false(lwm2m_cache_write(NULL, NULL));
632 zassert_false(lwm2m_cache_read(NULL, NULL));
633 zassert_equal(lwm2m_cache_size(NULL), 0);
634 }
635
ZTEST(lwm2m_registry,test_set_bulk)636 ZTEST(lwm2m_registry, test_set_bulk)
637 {
638 GET_SET_INT((bool), b, true);
639 GET_SET_ARRAY((uint8_t), opaque, ({0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}));
640 GET_SET_STRING((char), string, "Hello world");
641 GET_SET_INT((uint8_t), u8, 80);
642 GET_SET_INT((int8_t), s8, -80);
643 GET_SET_INT((uint16_t), u16, 160);
644 GET_SET_INT((int16_t), s16, -160);
645 GET_SET_INT((uint32_t), u32, 320);
646 GET_SET_INT((int32_t), s32, -320);
647 GET_SET_INT((int64_t), s64, -640);
648 GET_SET_INT((time_t), t, 1687949518);
649 GET_SET_INT((double), d, 3.14151);
650 GET_SET_STRUCT((struct lwm2m_objlnk), objl, ({.obj_id = 10, .obj_inst = 20}));
651
652 struct lwm2m_res_item res_items[] = {
653 {&LWM2M_OBJ(TEST_OBJ_ID, 0, LWM2M_RES_TYPE_BOOL), &b.out, sizeof(b.out)},
654 {&LWM2M_OBJ(TEST_OBJ_ID, 0, LWM2M_RES_TYPE_OPAQUE), opaque.out, sizeof(opaque.out)},
655 {&LWM2M_OBJ(TEST_OBJ_ID, 0, LWM2M_RES_TYPE_STRING), string.out, sizeof(string.out)},
656 {&LWM2M_OBJ(TEST_OBJ_ID, 0, LWM2M_RES_TYPE_U8), &u8.out, sizeof(u8.out)},
657 {&LWM2M_OBJ(TEST_OBJ_ID, 0, LWM2M_RES_TYPE_S8), &s8.out, sizeof(s8.out)},
658 {&LWM2M_OBJ(TEST_OBJ_ID, 0, LWM2M_RES_TYPE_U16), &u16.out, sizeof(u16.out)},
659 {&LWM2M_OBJ(TEST_OBJ_ID, 0, LWM2M_RES_TYPE_S16), &s16.out, sizeof(s16.out)},
660 {&LWM2M_OBJ(TEST_OBJ_ID, 0, LWM2M_RES_TYPE_U32), &u32.out, sizeof(u32.out)},
661 {&LWM2M_OBJ(TEST_OBJ_ID, 0, LWM2M_RES_TYPE_S32), &s32.out, sizeof(s32.out)},
662 {&LWM2M_OBJ(TEST_OBJ_ID, 0, LWM2M_RES_TYPE_S64), &s64.out, sizeof(s64.out)},
663 {&LWM2M_OBJ(TEST_OBJ_ID, 0, LWM2M_RES_TYPE_TIME), &t.out, sizeof(t.out)},
664 {&LWM2M_OBJ(TEST_OBJ_ID, 0, LWM2M_RES_TYPE_FLOAT), &d.out, sizeof(d.out)},
665 {&LWM2M_OBJ(TEST_OBJ_ID, 0, LWM2M_RES_TYPE_OBJLNK), &objl.out, sizeof(objl.out)}};
666
667 zassert_equal(lwm2m_set_bulk(res_items, ARRAY_SIZE(res_items)), 0);
668
669 /* get all resources */
670 zassert_ok(lwm2m_get_bool(&LWM2M_OBJ(32768, 0, LWM2M_RES_TYPE_BOOL), &b.in));
671 zassert_ok(lwm2m_get_opaque(&LWM2M_OBJ(32768, 0, LWM2M_RES_TYPE_OPAQUE), opaque.in,
672 sizeof(opaque.in)));
673 zassert_ok(lwm2m_get_string(&LWM2M_OBJ(32768, 0, LWM2M_RES_TYPE_STRING), string.in,
674 sizeof(string.in)));
675 zassert_ok(lwm2m_get_u8(&LWM2M_OBJ(32768, 0, LWM2M_RES_TYPE_U8), &u8.in));
676 zassert_ok(lwm2m_get_s8(&LWM2M_OBJ(32768, 0, LWM2M_RES_TYPE_S8), &s8.in));
677 zassert_ok(lwm2m_get_u16(&LWM2M_OBJ(32768, 0, LWM2M_RES_TYPE_U16), &u16.in));
678 zassert_ok(lwm2m_get_s16(&LWM2M_OBJ(32768, 0, LWM2M_RES_TYPE_S16), &s16.in));
679 zassert_ok(lwm2m_get_u32(&LWM2M_OBJ(32768, 0, LWM2M_RES_TYPE_U32), &u32.in));
680 zassert_ok(lwm2m_get_s32(&LWM2M_OBJ(32768, 0, LWM2M_RES_TYPE_S32), &s32.in));
681 zassert_ok(lwm2m_get_s64(&LWM2M_OBJ(32768, 0, LWM2M_RES_TYPE_S64), &s64.in));
682 zassert_ok(lwm2m_get_time(&LWM2M_OBJ(32768, 0, LWM2M_RES_TYPE_TIME), &t.in));
683 zassert_ok(lwm2m_get_f64(&LWM2M_OBJ(32768, 0, LWM2M_RES_TYPE_FLOAT), &d.in));
684 zassert_ok(lwm2m_get_objlnk(&LWM2M_OBJ(32768, 0, LWM2M_RES_TYPE_OBJLNK), &objl.in));
685
686 /* check for equality */
687 zassert_equal(b.in, b.out);
688 zassert_mem_equal(opaque.in, opaque.out, sizeof(opaque.out));
689 zassert_str_equal(string.in, string.out);
690 zassert_equal(u8.in, u8.out);
691 zassert_equal(s8.in, s8.out);
692 zassert_equal(u16.in, u16.out);
693 zassert_equal(s16.in, s16.out);
694 zassert_equal(u32.in, u32.out);
695 zassert_equal(s32.in, s32.out);
696 zassert_equal(s64.in, s64.out);
697 zassert_equal(t.in, t.out);
698 zassert_equal(d.in, d.out);
699 zassert_mem_equal(&objl.in, &objl.out, sizeof(objl.out));
700 }
701