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
19static coap_pdu_t *pdu;          /* Holds the request PDU for most tests */
20static 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
28static void
29t_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
56static void
57t_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
85static void
86t_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
118static void
119t_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
157static void
158t_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
198static void
199t_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
239static void
240t_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
281static void
282t_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
322static int
323t_error_response_tests_create(void) {
324  pdu = coap_pdu_init(0, 0, 0, COAP_DEFAULT_MTU);
325
326  return pdu == NULL;
327}
328
329static int
330t_error_response_tests_remove(void) {
331  coap_delete_pdu(pdu);
332  return 0;
333}
334
335CU_pSuite
336t_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