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
27static coap_context_t *ctx;       /* Holds the coap context for most tests */
28static coap_pdu_t *pdu;           /* Holds the parsed PDU for most tests */
29static coap_session_t *session;   /* Holds a reference-counted session object
30                                   * that is passed to coap_wellknown_response(). */
31
32static void
33t_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
81static void
82t_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
134static void
135t_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
166static void
167t_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
191static int
192t_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
244static int
245t_wkc_tests_remove(void) {
246  coap_delete_pdu(pdu);
247  coap_free_context(ctx);
248  return 0;
249}
250
251CU_pSuite
252t_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