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