1 /* libcoap unit tests
2 *
3 * Copyright (C) 2013--2015 Olaf Bergmann <bergmann@tzi.org>
4 *
5 * This file is part of the CoAP library libcoap. Please see
6 * README for terms of use.
7 */
8
9 #include "coap_config.h"
10 #include "test_wellknown.h"
11
12 #include <coap.h>
13
14 #include <assert.h>
15 #include <netinet/in.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19
20 #define TEST_PDU_SIZE 120
21 #define TEST_URI_LEN 4
22
23 coap_context_t *ctx; /* Holds the coap context for most tests */
24 coap_pdu_t *pdu; /* Holds the parsed PDU for most tests */
25
26 static void
t_wellknown1(void)27 t_wellknown1(void) {
28 coap_print_status_t result;
29 coap_resource_t *r;
30 unsigned char buf[40];
31 size_t buflen, offset, ofs;
32
33 char teststr[] = { /* </>;title="some attribute";ct=0 (31 chars) */
34 '<', '/', '>', ';', 't', 'i', 't', 'l',
35 'e', '=', '"', 's', 'o', 'm', 'e', ' ',
36 'a', 't', 't', 'r', 'i', 'b', 'u', 't',
37 'e', '"', ';', 'c', 't', '=', '0'
38 };
39
40 r = coap_resource_init(NULL, 0, 0);
41
42 coap_add_attr(r, (unsigned char *)"ct", 2, (unsigned char *)"0", 1, 0);
43 coap_add_attr(r, (unsigned char *)"title", 5, (unsigned char *)"\"some attribute\"", 16, 0);
44
45 coap_add_resource(ctx, r);
46
47 for (offset = 0; offset < sizeof(teststr); offset++) {
48 ofs = offset;
49 buflen = sizeof(buf);
50
51 result = coap_print_link(r, buf, &buflen, &ofs);
52
53 CU_ASSERT(result == sizeof(teststr) - offset);
54 CU_ASSERT(buflen == sizeof(teststr));
55 CU_ASSERT(memcmp(buf, teststr + offset, sizeof(teststr) - offset) == 0);
56 }
57
58 /* offset points behind teststr */
59 ofs = offset;
60 buflen = sizeof(buf);
61 result = coap_print_link(r, buf, &buflen, &ofs);
62
63 CU_ASSERT(result == 0);
64 CU_ASSERT(buflen == sizeof(teststr));
65
66 /* offset exceeds buffer */
67 buflen = sizeof(buf);
68 ofs = buflen;
69 result = coap_print_link(r, buf, &buflen, &ofs);
70
71 CU_ASSERT(result == 0);
72 CU_ASSERT(buflen == sizeof(teststr));
73 }
74
75 static void
t_wellknown2(void)76 t_wellknown2(void) {
77 coap_print_status_t result;
78 coap_resource_t *r;
79 unsigned char buf[10]; /* smaller than teststr */
80 size_t buflen, offset, ofs;
81
82 char teststr[] = { /* ,</abcd>;if="one";obs (21 chars) */
83 '<', '/', 'a', 'b', 'c', 'd', '>', ';',
84 'i', 'f', '=', '"', 'o', 'n', 'e', '"',
85 ';', 'o', 'b', 's'
86 };
87
88 r = coap_resource_init((unsigned char *)"abcd", 4, 0);
89 r->observable = 1;
90 coap_add_attr(r, (unsigned char *)"if", 2, (unsigned char *)"\"one\"", 5, 0);
91
92 coap_add_resource(ctx, r);
93
94 for (offset = 0; offset < sizeof(teststr) - sizeof(buf); offset++) {
95 ofs = offset;
96 buflen = sizeof(buf);
97
98 result = coap_print_link(r, buf, &buflen, &ofs);
99
100 CU_ASSERT(result == (COAP_PRINT_STATUS_TRUNC | sizeof(buf)));
101 CU_ASSERT(buflen == sizeof(teststr));
102 CU_ASSERT(ofs == 0);
103 CU_ASSERT(memcmp(buf, teststr + offset, sizeof(buf)) == 0);
104 }
105
106 /* from here on, the resource description fits into buf */
107 for (; offset < sizeof(teststr); offset++) {
108 ofs = offset;
109 buflen = sizeof(buf);
110 result = coap_print_link(r, buf, &buflen, &ofs);
111
112 CU_ASSERT(result == sizeof(teststr) - offset);
113 CU_ASSERT(buflen == sizeof(teststr));
114 CU_ASSERT(ofs == 0);
115 CU_ASSERT(memcmp(buf, teststr + offset,
116 COAP_PRINT_OUTPUT_LENGTH(result)) == 0);
117 }
118
119 /* offset exceeds buffer */
120 buflen = sizeof(buf);
121 ofs = offset;
122 result = coap_print_link(r, buf, &buflen, &ofs);
123 CU_ASSERT(result == 0);
124 CU_ASSERT(buflen == sizeof(teststr));
125 CU_ASSERT(ofs == offset - sizeof(teststr));
126 }
127
128 static void
t_wellknown3(void)129 t_wellknown3(void) {
130 coap_print_status_t result;
131 int j;
132 coap_resource_t *r;
133 static char uris[2 * COAP_MAX_PDU_SIZE];
134 unsigned char *uribuf = (unsigned char *)uris;
135 unsigned char buf[40];
136 size_t buflen = sizeof(buf);
137 size_t offset;
138 const unsigned short num_resources = (sizeof(uris) / TEST_URI_LEN) - 1;
139
140 /* ,</0000> (TEST_URI_LEN + 4 chars) */
141 for (j = 0; j < num_resources; j++) {
142 int len = snprintf((char *)uribuf, TEST_URI_LEN + 1,
143 "%0*d", TEST_URI_LEN, j);
144 r = coap_resource_init(uribuf, len, 0);
145 coap_add_resource(ctx, r);
146 uribuf += TEST_URI_LEN;
147 }
148
149 /* the following test assumes that the first two resources from
150 * t_wellknown1() and t_wellknown2() need more than buflen
151 * characters. Otherwise, CU_ASSERT(result > 0) will fail.
152 */
153 offset = num_resources * (TEST_URI_LEN + 4);
154 result = coap_print_wellknown(ctx, buf, &buflen, offset, NULL);
155 CU_ASSERT((result & COAP_PRINT_STATUS_ERROR) == 0 );
156 CU_ASSERT(COAP_PRINT_OUTPUT_LENGTH(result) > 0);
157 }
158
159 /* Create wellknown response for request without Block-option. */
160 static void
t_wellknown4(void)161 t_wellknown4(void) {
162 coap_pdu_t *response;
163 coap_block_t block;
164
165 response = coap_wellknown_response(ctx, pdu);
166
167 CU_ASSERT_PTR_NOT_NULL(response);
168
169 CU_ASSERT(coap_get_block(response, COAP_OPTION_BLOCK2, &block) != 0);
170
171 CU_ASSERT(block.num == 0);
172 CU_ASSERT(block.m == 1);
173 CU_ASSERT(1 << (block.szx + 4)
174 == (unsigned char *)response->hdr + response->length - response->data);
175
176 coap_delete_pdu(response);
177 }
178
179 /* Create wellknown response for request with Block2-option and an szx
180 * value smaller than COAP_MAX_BLOCK_SZX.
181 */
182 static void
t_wellknown5(void)183 t_wellknown5(void) {
184 coap_pdu_t *response;
185 coap_block_t inblock = { .num = 1, .m = 0, .szx = 1 };
186 coap_block_t block;
187 unsigned char buf[3];
188
189 if (!coap_add_option(pdu, COAP_OPTION_BLOCK2,
190 coap_encode_var_bytes(buf, ((inblock.num << 4) |
191 (inblock.m << 3) |
192 inblock.szx)), buf)) {
193 CU_FAIL("cannot add Block2 option");
194 return;
195 }
196
197 response = coap_wellknown_response(ctx, pdu);
198
199 CU_ASSERT_PTR_NOT_NULL(response);
200
201 CU_ASSERT(coap_get_block(response, COAP_OPTION_BLOCK2, &block) != 0);
202
203 CU_ASSERT(block.num == inblock.num);
204 CU_ASSERT(block.m == 1);
205 CU_ASSERT(1 << (block.szx + 4)
206 == (unsigned char *)response->hdr + response->length - response->data);
207
208 coap_delete_pdu(response);
209 }
210
211 static void
t_wellknown6(void)212 t_wellknown6(void) {
213 coap_pdu_t *response;
214 coap_block_t block = { .num = 0, .szx = 6 };
215 unsigned char buf[TEST_PDU_SIZE];
216
217
218 do {
219 coap_pdu_clear(pdu, pdu->max_size); /* clear PDU */
220
221 pdu->hdr->type = COAP_MESSAGE_NON;
222 pdu->hdr->code = COAP_REQUEST_GET;
223 pdu->hdr->id = htons(0x1234);
224
225 CU_ASSERT_PTR_NOT_NULL(pdu);
226
227 if (!pdu || !coap_add_option(pdu, COAP_OPTION_BLOCK2,
228 coap_encode_var_bytes(buf,
229 ((block.num << 4) | block.szx)), buf)) {
230 CU_FAIL("cannot create request");
231 return;
232 }
233
234 response = coap_wellknown_response(ctx, pdu);
235
236 CU_ASSERT_PTR_NOT_NULL(response);
237
238 /* coap_show_pdu(response); */
239
240 CU_ASSERT(coap_get_block(response, COAP_OPTION_BLOCK2, &block) != 0);
241
242 block.num++;
243 coap_delete_pdu(response);
244 } while (block.m == 1);
245 }
246
247 static int
t_wkc_tests_create(void)248 t_wkc_tests_create(void) {
249 coap_address_t addr;
250
251 coap_address_init(&addr);
252
253 addr.size = sizeof(struct sockaddr_in6);
254 addr.addr.sin6.sin6_family = AF_INET6;
255 addr.addr.sin6.sin6_addr = in6addr_any;
256 addr.addr.sin6.sin6_port = htons(COAP_DEFAULT_PORT);
257
258 ctx = coap_new_context(&addr);
259
260 pdu = coap_pdu_init(0, 0, 0, TEST_PDU_SIZE);
261 #if 0
262 /* add resources to coap context */
263 if (ctx && pdu) {
264 coap_resource_t *r;
265 static char _buf[2 * COAP_MAX_PDU_SIZE];
266 unsigned char *buf = (unsigned char *)_buf;
267 int i;
268
269 /* </>;title="some attribute";ct=0 (31 chars) */
270 r = coap_resource_init(NULL, 0, 0);
271
272 coap_add_attr(r, (unsigned char *)"ct", 2, (unsigned char *)"0", 1, 0);
273 coap_add_attr(r, (unsigned char *)"title", 5, (unsigned char *)"\"some attribute\"", 16, 0);
274 coap_add_resource(ctx, r);
275
276 /* ,</abcd>;if="one";obs (21 chars) */
277 r = coap_resource_init((unsigned char *)"abcd", 4, 0);
278 r->observable = 1;
279 coap_add_attr(r, (unsigned char *)"if", 2, (unsigned char *)"\"one\"", 5, 0);
280
281 coap_add_resource(ctx, r);
282
283 /* ,</0000> (TEST_URI_LEN + 4 chars) */
284 for (i = 0; i < sizeof(_buf) / (TEST_URI_LEN + 4); i++) {
285 int len = snprintf((char *)buf, TEST_URI_LEN + 1,
286 "%0*d", TEST_URI_LEN, i);
287 r = coap_resource_init(buf, len, 0);
288 coap_add_resource(ctx, r);
289 buf += TEST_URI_LEN + 1;
290 }
291
292 }
293 #endif
294 return ctx == NULL || pdu == NULL;
295 }
296
297 static int
t_wkc_tests_remove(void)298 t_wkc_tests_remove(void) {
299 coap_delete_pdu(pdu);
300 coap_free_context(ctx);
301 return 0;
302 }
303
304 CU_pSuite
t_init_wellknown_tests(void)305 t_init_wellknown_tests(void) {
306 CU_pSuite suite;
307
308 suite = CU_add_suite(".well-known/core", t_wkc_tests_create, t_wkc_tests_remove);
309 if (!suite) { /* signal error */
310 fprintf(stderr, "W: cannot add .well-known/core test suite (%s)\n",
311 CU_get_error_msg());
312
313 return NULL;
314 }
315
316 #define WKC_TEST(s,t) \
317 if (!CU_ADD_TEST(s,t)) { \
318 fprintf(stderr, "W: cannot add .well-known/core test (%s)\n", \
319 CU_get_error_msg()); \
320 }
321
322 WKC_TEST(suite, t_wellknown1);
323 WKC_TEST(suite, t_wellknown2);
324 WKC_TEST(suite, t_wellknown3);
325 WKC_TEST(suite, t_wellknown4);
326 WKC_TEST(suite, t_wellknown5);
327 WKC_TEST(suite, t_wellknown6);
328
329 return suite;
330 }
331
332