1 /* libcoap unit tests
2 *
3 * Copyright (C) 2013,2015,2022-2023 Olaf Bergmann <bergmann@tzi.org>
4 *
5 * SPDX-License-Identifier: BSD-2-Clause
6 *
7 * This file is part of the CoAP library libcoap. Please see
8 * README for terms of use.
9 */
10
11 #include "test_common.h"
12 #include "test_error_response.h"
13
14 #include <assert.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18
19 static coap_pdu_t *pdu; /* Holds the request PDU for most tests */
20 static coap_opt_filter_t opts; /* option filter used for generating responses */
21
22 /************************************************************************
23 ** PDU decoder
24 ************************************************************************/
25
26 /* FIXME: handle COAP_ERROR_PHRASE_LENGTH == 0 */
27
28 static void
t_error_response1(void)29 t_error_response1(void) {
30 uint8_t teststr[] = {
31 0x60, 0x80, 0x12, 0x34, 0xff, 'B', 'a', 'd',
32 ' ', 'R', 'e', 'q', 'u', 'e', 's', 't'
33 };
34 coap_pdu_t *response;
35
36 coap_pdu_clear(pdu, pdu->max_size);
37 pdu->type = COAP_MESSAGE_CON;
38 pdu->mid = 0x1234;
39
40 /* result = coap_add_token(pdu, 5, (unsigned char *)"token"); */
41 coap_option_filter_clear(&opts);
42 response = coap_new_error_response(pdu, COAP_RESPONSE_CODE(400), &opts);
43
44 CU_ASSERT_PTR_NOT_NULL(response);
45
46 CU_ASSERT(response->used_size == sizeof(teststr) - 4);
47 CU_ASSERT(response->type == COAP_MESSAGE_ACK);
48 CU_ASSERT(response->e_token_length == 0);
49 CU_ASSERT(response->code == 0x80);
50 CU_ASSERT(response->mid == 0x1234);
51 CU_ASSERT(coap_pdu_encode_header(response, COAP_PROTO_UDP) == 4);
52 CU_ASSERT(memcmp(response->token - 4, teststr, sizeof(teststr)) == 0);
53 coap_delete_pdu(response);
54 }
55
56 static void
t_error_response2(void)57 t_error_response2(void) {
58 uint8_t teststr[] = {
59 0x55, 0x84, 0x12, 0x34, 't', 'o', 'k', 'e',
60 'n', 0xff, 'N', 'o', 't', ' ', 'F', 'o',
61 'u', 'n', 'd'
62 };
63 coap_pdu_t *response;
64
65 coap_pdu_clear(pdu, pdu->max_size);
66 pdu->type = COAP_MESSAGE_NON;
67 pdu->mid = 0x1234;
68 coap_add_token(pdu, 5, (const uint8_t *)"token");
69 coap_add_option(pdu, COAP_OPTION_URI_HOST, 4, (const uint8_t *)"time");
70
71 coap_option_filter_clear(&opts);
72 response = coap_new_error_response(pdu, COAP_RESPONSE_CODE(404), &opts);
73
74 CU_ASSERT_PTR_NOT_NULL(response);
75
76 CU_ASSERT(response->used_size == sizeof(teststr) - 4);
77 CU_ASSERT(response->type == COAP_MESSAGE_NON);
78 CU_ASSERT(response->e_token_length == 5);
79 CU_ASSERT(response->code == 0x84);
80 CU_ASSERT(coap_pdu_encode_header(response, COAP_PROTO_UDP) == 4);
81 CU_ASSERT(memcmp(response->token - 4, teststr, sizeof(teststr)) == 0);
82 coap_delete_pdu(response);
83 }
84
85 static void
t_error_response3(void)86 t_error_response3(void) {
87 const uint8_t code = COAP_RESPONSE_CODE(402);
88 uint8_t teststr[] = {
89 0x65, code, 0x00, 0x00, 't', 'o', 'k', 'e',
90 'n', 0xd0, 0x0c, 0xff, 'B', 'a', 'd', ' ', 'O',
91 'p', 't', 'i', 'o', 'n'
92 };
93 coap_pdu_t *response;
94
95 coap_pdu_clear(pdu, pdu->max_size);
96 pdu->type = COAP_MESSAGE_CON;
97 coap_add_token(pdu, 5, (const uint8_t *)"token");
98 /* coap_add_option(pdu, COAP_OPTION_URI_HOST, 4, (const uint8_t *)"time"); */
99
100 /* unknown critical option 25 */
101 coap_add_option(pdu, 25, 0, NULL);
102
103 coap_option_filter_clear(&opts);
104 coap_option_filter_set(&opts, 25);
105 response = coap_new_error_response(pdu, code, &opts);
106
107 CU_ASSERT_PTR_NOT_NULL(response);
108
109 CU_ASSERT(response->used_size == sizeof(teststr) - 4);
110 CU_ASSERT(response->type == COAP_MESSAGE_ACK);
111 CU_ASSERT(response->e_token_length == 5);
112 CU_ASSERT(response->code == code);
113 CU_ASSERT(coap_pdu_encode_header(response, COAP_PROTO_UDP) == 4);
114 CU_ASSERT(memcmp(response->token - 4, teststr, sizeof(teststr)) == 0);
115 coap_delete_pdu(response);
116 }
117
118 static void
t_error_response4(void)119 t_error_response4(void) {
120 const uint8_t code = COAP_RESPONSE_CODE(402);
121 unsigned char optval[] = {
122 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
123 0x08, 0x09, 0x0a, 0x0b
124 };
125 uint8_t teststr[] = {
126 0x65, code, 0x00, 0x00, 't', 'o', 'k', 'e',
127 'n', 0xdc, 0x0c, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
128 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0xff, 'B',
129 'a', 'd', ' ', 'O', 'p', 't', 'i', 'o',
130 'n'
131 };
132 coap_pdu_t *response;
133
134 coap_pdu_clear(pdu, pdu->max_size);
135 pdu->type = COAP_MESSAGE_CON;
136 coap_add_token(pdu, 5, (const uint8_t *)"token");
137 /* coap_add_option(pdu, COAP_OPTION_URI_HOST, 4, (const uint8_t *)"time"); */
138
139 /* unknown critical option 25 */
140 coap_add_option(pdu, 25, sizeof(optval), optval);
141
142 coap_option_filter_clear(&opts);
143 coap_option_filter_set(&opts, 25);
144 response = coap_new_error_response(pdu, code, &opts);
145
146 CU_ASSERT_PTR_NOT_NULL(response);
147
148 CU_ASSERT(response->used_size == sizeof(teststr) - 4);
149 CU_ASSERT(response->type == COAP_MESSAGE_ACK);
150 CU_ASSERT(response->e_token_length == 5);
151 CU_ASSERT(response->code == code);
152 CU_ASSERT(coap_pdu_encode_header(response, COAP_PROTO_UDP) == 4);
153 CU_ASSERT(memcmp(response->token - 4, teststr, sizeof(teststr)) == 0);
154 coap_delete_pdu(response);
155 }
156
157 static void
t_error_response5(void)158 t_error_response5(void) {
159 const uint8_t code = COAP_RESPONSE_CODE(402);
160 unsigned char optval[] = {
161 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
162 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
163 0x10, 0x11, 0x12
164 };
165 uint8_t teststr[] = {
166 0x65, code, 0x00, 0x00, 't', 'o', 'k', 'e',
167 'n', 0xdd, 0x0c, 0x06, 0x00, 0x01, 0x02, 0x03, 0x04,
168 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
169 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0xff, 'B',
170 'a', 'd', ' ', 'O', 'p', 't', 'i', 'o',
171 'n'
172 };
173 coap_pdu_t *response;
174
175 coap_pdu_clear(pdu, pdu->max_size);
176 pdu->type = COAP_MESSAGE_CON;
177 coap_add_token(pdu, 5, (const uint8_t *)"token");
178 /* coap_add_option(pdu, COAP_OPTION_URI_HOST, 4, (const uint8_t *)"time"); */
179
180 /* unknown critical option 25 */
181 coap_add_option(pdu, 25, sizeof(optval), optval);
182
183 coap_option_filter_clear(&opts);
184 coap_option_filter_set(&opts, 25);
185 response = coap_new_error_response(pdu, code, &opts);
186
187 CU_ASSERT_PTR_NOT_NULL(response);
188
189 CU_ASSERT(response->used_size == sizeof(teststr) - 4);
190 CU_ASSERT(response->type == COAP_MESSAGE_ACK);
191 CU_ASSERT(response->e_token_length == 5);
192 CU_ASSERT(response->code == code);
193 CU_ASSERT(coap_pdu_encode_header(response, COAP_PROTO_UDP) == 4);
194 CU_ASSERT(memcmp(response->token - 4, teststr, sizeof(teststr)) == 0);
195 coap_delete_pdu(response);
196 }
197
198 static void
t_error_response6(void)199 t_error_response6(void) {
200 const uint8_t code = COAP_RESPONSE_CODE(402);
201 unsigned char optval[] = {
202 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
203 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
204 0x10, 0x11, 0x12
205 };
206 uint8_t teststr[] = {
207 0x65, code, 0x00, 0x00, 't', 'o', 'k', 'e',
208 'n', 0xdd, 0x0a, 0x06, 0x00, 0x01, 0x02, 0x03,
209 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
210 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0xff,
211 'B', 'a', 'd', ' ', 'O', 'p', 't', 'i',
212 'o', 'n'
213 };
214 coap_pdu_t *response;
215
216 coap_pdu_clear(pdu, pdu->max_size);
217 pdu->type = COAP_MESSAGE_CON;
218 coap_add_token(pdu, 5, (const uint8_t *)"token");
219 /* coap_add_option(pdu, COAP_OPTION_URI_HOST, 4, (const uint8_t *)"time"); */
220
221 /* unknown critical option 23 */
222 coap_add_option(pdu, 23, sizeof(optval), optval);
223
224 coap_option_filter_clear(&opts);
225 coap_option_filter_set(&opts, 23);
226 response = coap_new_error_response(pdu, code, &opts);
227
228 CU_ASSERT_PTR_NOT_NULL(response);
229
230 CU_ASSERT(response->used_size == sizeof(teststr) - 4);
231 CU_ASSERT(response->type == COAP_MESSAGE_ACK);
232 CU_ASSERT(response->e_token_length == 5);
233 CU_ASSERT(response->code == code);
234 CU_ASSERT(coap_pdu_encode_header(response, COAP_PROTO_UDP) == 4);
235 CU_ASSERT(memcmp(response->token - 4, teststr, sizeof(teststr)) == 0);
236 coap_delete_pdu(response);
237 }
238
239 static void
t_error_response7(void)240 t_error_response7(void) {
241 const uint8_t code = COAP_RESPONSE_CODE(402);
242 unsigned char optval[] = {
243 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
244 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
245 0x10, 0x11, 0x12
246 };
247 uint8_t teststr[] = {
248 0x65, code, 0x00, 0x00, 't', 'o', 'k', 'e',
249 'n', 0xdd, 0x0a, 0x06, 0x00, 0x01, 0x02, 0x03,
250 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
251 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0xff,
252 'B', 'a', 'd', ' ', 'O', 'p', 't', 'i',
253 'o', 'n'
254 };
255 coap_pdu_t *response;
256
257 coap_pdu_clear(pdu, pdu->max_size);
258 pdu->type = COAP_MESSAGE_CON;
259 coap_add_token(pdu, 5, (const uint8_t *)"token");
260 /* known option 11 */
261 coap_add_option(pdu, 11, 4, (const uint8_t *)"time");
262
263 /* unknown critical option 23 */
264 coap_add_option(pdu, 23, sizeof(optval), optval);
265
266 coap_option_filter_clear(&opts);
267 coap_option_filter_set(&opts, 23);
268 response = coap_new_error_response(pdu, code, &opts);
269
270 CU_ASSERT_PTR_NOT_NULL(response);
271
272 CU_ASSERT(response->used_size == sizeof(teststr) - 4);
273 CU_ASSERT(response->type == COAP_MESSAGE_ACK);
274 CU_ASSERT(response->e_token_length == 5);
275 CU_ASSERT(response->code == code);
276 CU_ASSERT(coap_pdu_encode_header(response, COAP_PROTO_UDP) == 4);
277 CU_ASSERT(memcmp(response->token - 4, teststr, sizeof(teststr)) == 0);
278 coap_delete_pdu(response);
279 }
280
281 static void
t_error_response8(void)282 t_error_response8(void) {
283 const uint8_t code = COAP_RESPONSE_CODE(503);
284 uint8_t teststr[] = {
285 0x65, code, 0x00, 0x00, 't', 'o', 'k', 'e',
286 'n', 0xe0, 0x02, 0xdc, 0xd0, 0x00, 0xff, 'S',
287 'e', 'r', 'v', 'i', 'c', 'e', ' ', 'U',
288 'n', 'a', 'v', 'a', 'i', 'l', 'a', 'b',
289 'l', 'e'
290 };
291 coap_pdu_t *response;
292
293 coap_pdu_clear(pdu, pdu->max_size);
294 pdu->type = COAP_MESSAGE_CON;
295 coap_add_token(pdu, 5, (const uint8_t *)"token");
296 /* known option 1000 */
297 coap_add_option(pdu, 1000, 0, NULL);
298
299 /* unknown options 1001 and 1014 */
300 coap_add_option(pdu, 1001, 0, NULL);
301 coap_add_option(pdu, 1014, 0, NULL);
302
303 /* known option 2000 */
304 coap_add_option(pdu, 2000, 0, NULL);
305
306 coap_option_filter_clear(&opts);
307 coap_option_filter_set(&opts, 1001);
308 coap_option_filter_set(&opts, 1014);
309 response = coap_new_error_response(pdu, code, &opts);
310
311 CU_ASSERT_PTR_NOT_NULL(response);
312
313 CU_ASSERT(response->used_size == sizeof(teststr) - 4);
314 CU_ASSERT(response->type == COAP_MESSAGE_ACK);
315 CU_ASSERT(response->e_token_length == 5);
316 CU_ASSERT(response->code == code);
317 CU_ASSERT(coap_pdu_encode_header(response, COAP_PROTO_UDP) == 4);
318 CU_ASSERT(memcmp(response->token - 4, teststr, sizeof(teststr)) == 0);
319 coap_delete_pdu(response);
320 }
321
322 static int
t_error_response_tests_create(void)323 t_error_response_tests_create(void) {
324 pdu = coap_pdu_init(0, 0, 0, COAP_DEFAULT_MTU);
325
326 return pdu == NULL;
327 }
328
329 static int
t_error_response_tests_remove(void)330 t_error_response_tests_remove(void) {
331 coap_delete_pdu(pdu);
332 return 0;
333 }
334
335 CU_pSuite
t_init_error_response_tests(void)336 t_init_error_response_tests(void) {
337 CU_pSuite suite[1];
338
339 suite[0] = CU_add_suite("error response generator",
340 t_error_response_tests_create,
341 t_error_response_tests_remove);
342 if (!suite[0]) { /* signal error */
343 fprintf(stderr, "W: cannot add error response generator test suite (%s)\n",
344 CU_get_error_msg());
345
346 return NULL;
347 }
348
349 #define ERROR_RESPONSE_TEST(s,t) \
350 if (!CU_ADD_TEST(s,t)) { \
351 fprintf(stderr, "W: cannot add error response generator test (%s)\n", \
352 CU_get_error_msg()); \
353 }
354
355 ERROR_RESPONSE_TEST(suite[0], t_error_response1);
356 ERROR_RESPONSE_TEST(suite[0], t_error_response2);
357 ERROR_RESPONSE_TEST(suite[0], t_error_response3);
358 ERROR_RESPONSE_TEST(suite[0], t_error_response4);
359 ERROR_RESPONSE_TEST(suite[0], t_error_response5);
360 ERROR_RESPONSE_TEST(suite[0], t_error_response6);
361 ERROR_RESPONSE_TEST(suite[0], t_error_response7);
362 ERROR_RESPONSE_TEST(suite[0], t_error_response8);
363
364 return suite[0];
365 }
366