1 /* libcoap unit tests
2 *
3 * Copyright (C) 2013--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_wellknown.h"
13
14 #if COAP_SERVER_SUPPORT
15 #if COAP_CLIENT_SUPPORT
16 #include <assert.h>
17 #ifdef HAVE_NETINET_IN_H
18 #include <netinet/in.h>
19 #endif
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23
24 #define TEST_PDU_SIZE 120
25 #define TEST_URI_LEN 4
26
27 static coap_context_t *ctx; /* Holds the coap context for most tests */
28 static coap_pdu_t *pdu; /* Holds the parsed PDU for most tests */
29 static coap_session_t *session; /* Holds a reference-counted session object
30 * that is passed to coap_wellknown_response(). */
31
32 static void
t_wellknown1(void)33 t_wellknown1(void) {
34 coap_print_status_t result;
35 coap_resource_t *r;
36 unsigned char buf[40];
37 size_t buflen, offset, ofs;
38
39 char teststr[] = { /* </>;title="some attribute";ct=0 (31 chars) */
40 '<', '/', '>', ';', 't', 'i', 't', 'l',
41 'e', '=', '"', 's', 'o', 'm', 'e', ' ',
42 'a', 't', 't', 'r', 'i', 'b', 'u', 't',
43 'e', '"', ';', 'c', 't', '=', '0'
44 };
45
46 r = coap_resource_init(NULL, 0);
47
48 coap_add_attr(r, coap_make_str_const("ct"), coap_make_str_const("0"), 0);
49 coap_add_attr(r, coap_make_str_const("title"), coap_make_str_const("\"some attribute\""), 0);
50
51 coap_add_resource(ctx, r);
52
53 for (offset = 0; offset < sizeof(teststr); offset++) {
54 ofs = offset;
55 buflen = sizeof(buf);
56
57 result = coap_print_link(r, buf, &buflen, &ofs);
58
59 CU_ASSERT(result == sizeof(teststr) - offset);
60 CU_ASSERT(buflen == sizeof(teststr));
61 CU_ASSERT(memcmp(buf, teststr + offset, sizeof(teststr) - offset) == 0);
62 }
63
64 /* offset points behind teststr */
65 ofs = offset;
66 buflen = sizeof(buf);
67 result = coap_print_link(r, buf, &buflen, &ofs);
68
69 CU_ASSERT(result == 0);
70 CU_ASSERT(buflen == sizeof(teststr));
71
72 /* offset exceeds buffer */
73 buflen = sizeof(buf);
74 ofs = buflen;
75 result = coap_print_link(r, buf, &buflen, &ofs);
76
77 CU_ASSERT(result == 0);
78 CU_ASSERT(buflen == sizeof(teststr));
79 }
80
81 static void
t_wellknown2(void)82 t_wellknown2(void) {
83 coap_print_status_t result;
84 coap_resource_t *r;
85 unsigned char buf[10]; /* smaller than teststr */
86 size_t buflen, offset, ofs;
87
88 char teststr[] = { /* ,</abcd>;if="one";obs (21 chars) */
89 '<', '/', 'a', 'b', 'c', 'd', '>', ';',
90 'i', 'f', '=', '"', 'o', 'n', 'e', '"',
91 ';', 'o', 'b', 's'
92 };
93
94 r = coap_resource_init(coap_make_str_const("abcd"), 0);
95 coap_resource_set_get_observable(r, 1);
96 coap_add_attr(r, coap_make_str_const("if"), coap_make_str_const("\"one\""), 0);
97
98 coap_add_resource(ctx, r);
99
100 for (offset = 0; offset < sizeof(teststr) - sizeof(buf); offset++) {
101 ofs = offset;
102 buflen = sizeof(buf);
103
104 result = coap_print_link(r, buf, &buflen, &ofs);
105
106 CU_ASSERT(result == (COAP_PRINT_STATUS_TRUNC | sizeof(buf)));
107 CU_ASSERT(buflen == sizeof(teststr));
108 CU_ASSERT(ofs == 0);
109 CU_ASSERT(memcmp(buf, teststr + offset, sizeof(buf)) == 0);
110 }
111
112 /* from here on, the resource description fits into buf */
113 for (; offset < sizeof(teststr); offset++) {
114 ofs = offset;
115 buflen = sizeof(buf);
116 result = coap_print_link(r, buf, &buflen, &ofs);
117
118 CU_ASSERT(result == sizeof(teststr) - offset);
119 CU_ASSERT(buflen == sizeof(teststr));
120 CU_ASSERT(ofs == 0);
121 CU_ASSERT(memcmp(buf, teststr + offset,
122 COAP_PRINT_OUTPUT_LENGTH(result)) == 0);
123 }
124
125 /* offset exceeds buffer */
126 buflen = sizeof(buf);
127 ofs = offset;
128 result = coap_print_link(r, buf, &buflen, &ofs);
129 CU_ASSERT(result == 0);
130 CU_ASSERT(buflen == sizeof(teststr));
131 CU_ASSERT(ofs == offset - sizeof(teststr));
132 }
133
134 static void
t_wellknown3(void)135 t_wellknown3(void) {
136 coap_print_status_t result;
137 int j;
138 coap_resource_t *r;
139 static char uris[2 * 1024];
140 unsigned char *uribuf = (unsigned char *)uris;
141 unsigned char buf[40];
142 size_t buflen = sizeof(buf);
143 size_t offset;
144 const uint16_t num_resources = (sizeof(uris) / TEST_URI_LEN) - 1;
145
146 /* ,</0000> (TEST_URI_LEN + 4 chars) */
147 for (j = 0; j < num_resources; j++) {
148 int len = snprintf((char *)uribuf, TEST_URI_LEN + 1,
149 "%0*d", TEST_URI_LEN, j);
150 coap_str_const_t uri_path = {.length = len, .s = uribuf};
151 r = coap_resource_init(&uri_path, 0);
152 coap_add_resource(ctx, r);
153 uribuf += TEST_URI_LEN;
154 }
155
156 /* the following test assumes that the first two resources from
157 * t_wellknown1() and t_wellknown2() need more than buflen
158 * characters. Otherwise, CU_ASSERT(result > 0) will fail.
159 */
160 offset = num_resources * (TEST_URI_LEN + 4);
161 result = coap_print_wellknown(ctx, buf, &buflen, offset, NULL);
162 CU_ASSERT((result & COAP_PRINT_STATUS_ERROR) == 0);
163 CU_ASSERT(COAP_PRINT_OUTPUT_LENGTH(result) > 0);
164 }
165
166 static void
t_wellknown4(void)167 t_wellknown4(void) {
168 coap_print_status_t result;
169 coap_string_t *query;
170 unsigned char buf[40];
171 size_t buflen = sizeof(buf);
172 char teststr[] = { /* ,</abcd>;if="one";obs (21 chars) */
173 '<', '/', 'a', 'b', 'c', 'd', '>', ';',
174 'i', 'f', '=', '"', 'o', 'n', 'e', '"',
175 ';', 'o', 'b', 's'
176 };
177
178 /* Check for the resource added in t_wellknown2 */
179 query = coap_new_string(sizeof("if=one")-1);
180 CU_ASSERT(query != NULL);
181 memcpy(query->s, "if=one", sizeof("if=one")-1);
182 result = coap_print_wellknown(ctx, buf, &buflen, 0, query);
183 CU_ASSERT((result & COAP_PRINT_STATUS_ERROR) == 0);
184 CU_ASSERT(COAP_PRINT_OUTPUT_LENGTH(result) == sizeof(teststr));
185 CU_ASSERT(buflen == sizeof(teststr));
186 CU_ASSERT(memcmp(buf, teststr, buflen) == 0);
187 coap_delete_string(query);
188 }
189
190
191 static int
t_wkc_tests_create(void)192 t_wkc_tests_create(void) {
193 coap_address_t addr;
194
195 coap_address_init(&addr);
196
197 addr.size = sizeof(struct sockaddr_in6);
198 addr.addr.sin6.sin6_family = AF_INET6;
199 addr.addr.sin6.sin6_addr = in6addr_any;
200 addr.addr.sin6.sin6_port = htons(COAP_DEFAULT_PORT);
201
202 ctx = coap_new_context(&addr);
203
204 addr.addr.sin6.sin6_addr = in6addr_loopback;
205 session = coap_new_client_session(ctx, NULL, &addr, COAP_PROTO_UDP);
206
207 pdu = coap_pdu_init(0, 0, 0, TEST_PDU_SIZE);
208 #if 0
209 /* add resources to coap context */
210 if (ctx && pdu) {
211 coap_resource_t *r;
212 static char _buf[2 * 1024];
213 unsigned char *buf = (unsigned char *)_buf;
214 int i;
215
216 /* </>;title="some attribute";ct=0 (31 chars) */
217 r = coap_resource_init(NULL, 0, 0);
218
219 coap_add_attr(r, coap_make_str_const("ct"), coap_make_str_const("0"), 0);
220 coap_add_attr(r, coap_make_str_const("title"), coap_make_str_const("\"some attribute\""), 0);
221 coap_add_resource(ctx, r);
222
223 /* ,</abcd>;if="one";obs (21 chars) */
224 r = coap_resource_init((const uint8_t *)"abcd", 4, 0);
225 r->observable = 1;
226 coap_add_attr(r, coap_make_str_const("if"), coap_make_str_const("\"one\""), 0);
227
228 coap_add_resource(ctx, r);
229
230 /* ,</0000> (TEST_URI_LEN + 4 chars) */
231 for (i = 0; i < sizeof(_buf) / (TEST_URI_LEN + 4); i++) {
232 int len = snprintf((char *)buf, TEST_URI_LEN + 1,
233 "%0*d", TEST_URI_LEN, i);
234 r = coap_resource_init(buf, len, 0);
235 coap_add_resource(ctx, r);
236 buf += TEST_URI_LEN + 1;
237 }
238
239 }
240 #endif
241 return ctx == NULL || pdu == NULL;
242 }
243
244 static int
t_wkc_tests_remove(void)245 t_wkc_tests_remove(void) {
246 coap_delete_pdu(pdu);
247 coap_free_context(ctx);
248 return 0;
249 }
250
251 CU_pSuite
t_init_wellknown_tests(void)252 t_init_wellknown_tests(void) {
253 CU_pSuite suite;
254
255 suite = CU_add_suite(".well-known/core", t_wkc_tests_create, t_wkc_tests_remove);
256 if (!suite) { /* signal error */
257 fprintf(stderr, "W: cannot add .well-known/core test suite (%s)\n",
258 CU_get_error_msg());
259
260 return NULL;
261 }
262
263 #define WKC_TEST(s,t) \
264 if (!CU_ADD_TEST(s,t)) { \
265 fprintf(stderr, "W: cannot add .well-known/core test (%s)\n", \
266 CU_get_error_msg()); \
267 }
268
269 WKC_TEST(suite, t_wellknown1);
270 WKC_TEST(suite, t_wellknown2);
271 WKC_TEST(suite, t_wellknown3);
272 WKC_TEST(suite, t_wellknown4);
273
274 return suite;
275 }
276 #endif /* COAP_CLIENT_SUPPORT */
277 #endif /* COAP_SERVER_SUPPORT */
278