blob: cb4e476cbd2f3793179253dd86697b5febc7161c [file] [log] [blame]
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +01001/* tests for utilities of libmsomcore */
2/*
3 * (C) 2014 Holger Hans Peter Freyther
4 *
5 * All Rights Reserved
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 */
22
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +020023#include <osmocom/gsm/ipa.h>
24
25#include <osmocom/core/logging.h>
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +010026#include <osmocom/core/utils.h>
27
28#include <stdio.h>
Harald Welte504caac2017-10-27 17:19:59 +020029#include <ctype.h>
Harald Welte15a5f8d2018-06-06 16:58:17 +020030#include <time.h>
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +010031
32static void hexdump_test(void)
33{
34 uint8_t data[4098];
35 int i;
36
37 for (i = 0; i < ARRAY_SIZE(data); ++i)
38 data[i] = i & 0xff;
39
40 printf("Plain dump\n");
41 printf("%s\n", osmo_hexdump(data, 4));
42
43 printf("Corner case\n");
44 printf("%s\n", osmo_hexdump(data, ARRAY_SIZE(data)));
45 printf("%s\n", osmo_hexdump_nospc(data, ARRAY_SIZE(data)));
46}
47
Neels Hofmeyr7adb5672017-02-14 15:48:19 +010048static void hexparse_test(void)
49{
50 int i;
51 int rc;
52 uint8_t data[256];
53
54 printf("\nHexparse 0..255 in lower case\n");
55 memset(data, 0, sizeof(data));
56 rc = osmo_hexparse(
57 "000102030405060708090a0b0c0d0e0f"
58 "101112131415161718191a1b1c1d1e1f"
59 "202122232425262728292a2b2c2d2e2f"
60 "303132333435363738393a3b3c3d3e3f"
61 "404142434445464748494a4b4c4d4e4f"
62 "505152535455565758595a5b5c5d5e5f"
63 "606162636465666768696a6b6c6d6e6f"
64 "707172737475767778797a7b7c7d7e7f"
65 "808182838485868788898a8b8c8d8e8f"
66 "909192939495969798999a9b9c9d9e9f"
67 "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
68 "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
69 "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
70 "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
71 "e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
72 "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"
73 , data, sizeof(data));
74 printf("rc = %d\n", rc);
75 printf("--> %s\n\n", osmo_hexdump(data, sizeof(data)));
76 for (i = 0; i < sizeof(data); i++)
77 OSMO_ASSERT(data[i] == i);
78
79 printf("Hexparse 0..255 in upper case\n");
80 memset(data, 0, sizeof(data));
81 rc = osmo_hexparse(
82 "000102030405060708090A0B0C0D0E0F"
83 "101112131415161718191A1B1C1D1E1F"
84 "202122232425262728292A2B2C2D2E2F"
85 "303132333435363738393A3B3C3D3E3F"
86 "404142434445464748494A4B4C4D4E4F"
87 "505152535455565758595A5B5C5D5E5F"
88 "606162636465666768696A6B6C6D6E6F"
89 "707172737475767778797A7B7C7D7E7F"
90 "808182838485868788898A8B8C8D8E8F"
91 "909192939495969798999A9B9C9D9E9F"
92 "A0A1A2A3A4A5A6A7A8A9AAABACADAEAF"
93 "B0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF"
94 "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF"
95 "D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF"
96 "E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF"
97 "F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF"
98 , data, sizeof(data));
99 printf("rc = %d\n", rc);
100 printf("--> %s\n\n", osmo_hexdump(data, sizeof(data)));
101 for (i = 0; i < sizeof(data); i++)
102 OSMO_ASSERT(data[i] == i);
103
104 printf("Hexparse 0..255 in mixed case\n");
105 memset(data, 0, sizeof(data));
106 rc = osmo_hexparse(
107 "000102030405060708090A0B0C0D0E0F"
108 "101112131415161718191A1B1C1D1E1F"
109 "202122232425262728292A2B2C2D2E2F"
110 "303132333435363738393a3b3c3d3e3f"
111 "404142434445464748494A4B4C4D4E4F"
112 "505152535455565758595a5b5c5d5e5f"
113 "606162636465666768696A6B6C6D6E6F"
114 "707172737475767778797A7B7C7D7E7F"
115 "808182838485868788898A8B8C8D8E8F"
116 "909192939495969798999A9B9C9D9E9F"
117 "A0A1A2A3a4a5a6a7a8a9AAABACADAEAF"
118 "B0B1B2B3b4b5b6b7b8b9BABBBCBDBEBF"
119 "C0C1C2C3c4c5c6c7c8c9CACBCCCDCECF"
120 "D0D1D2D3d4d5d6d7d8d9DADBDCDDDEDF"
121 "E0E1E2E3e4e5e6e7e8e9EAEBECEDEEEF"
122 "F0F1F2F3f4f5f6f7f8f9FAFBFCFDFEFF"
123 , data, sizeof(data));
124 printf("rc = %d\n", rc);
125 printf("--> %s\n\n", osmo_hexdump(data, sizeof(data)));
126 for (i = 0; i < sizeof(data); i++)
127 OSMO_ASSERT(data[i] == i);
128
Neels Hofmeyr437ed4a2017-02-14 15:54:31 +0100129 printf("Hexparse 0..255 with whitespace\n");
130 memset(data, 0, sizeof(data));
131 rc = osmo_hexparse(
132 "00 01\t02\r030405060708090A0B0C0D0 E 0 F\n"
133 "10 11\t12\r131415161718191A1B1C1D1 E 1 F\n"
134 "20 21\t22\r232425262728292A2B2C2D2 E 2 F\n"
135 "30 31\t32\r333435363738393a3b3c3d3 e 3 f\n"
136 "40 41\t42\r434445464748494A4B4C4D4 E 4 F\n"
137 "50 51\t52\r535455565758595a5b5c5d5 e 5 f\n"
138 "60 61\t62\r636465666768696A6B6C6D6 E 6 F\n"
139 "70 71\t72\r737475767778797A7B7C7D7 E 7 F\n"
140 "80 81\t82\r838485868788898A8B8C8D8 E 8 F\n"
141 "90 91\t92\r939495969798999A9B9C9D9 E 9 F\n"
142 "A0 A1\tA2\rA3a4a5a6a7a8a9AAABACADA E A F\n"
143 "B0 B1\tB2\rB3b4b5b6b7b8b9BABBBCBDB E B F\n"
144 "C0 C1\tC2\rC3c4c5c6c7c8c9CACBCCCDC E C F \n"
145 "D0 D1\tD2\rD3d4d5d6d7d8d9DADBDCDDD E D F\t\n"
146 "E0 E1\tE2\rE3e4e5e6e7e8e9EAEBECEDE E E F \t\n"
147 "F0 F1\tF2\rF3f4f5f6f7f8f9FAFBFCFDF E F F \t\r\n"
148 , data, sizeof(data));
149 printf("rc = %d\n", rc);
150 printf("--> %s\n\n", osmo_hexdump(data, sizeof(data)));
151 for (i = 0; i < sizeof(data); i++)
152 OSMO_ASSERT(data[i] == i);
153
Neels Hofmeyr7adb5672017-02-14 15:48:19 +0100154 printf("Hexparse with buffer too short\n");
155 memset(data, 0, sizeof(data));
156 rc = osmo_hexparse("000102030405060708090a0b0c0d0e0f", data, 15);
157 printf("rc = %d\n", rc);
158
159 printf("Hexparse with uneven amount of digits\n");
160 memset(data, 0, sizeof(data));
161 rc = osmo_hexparse("000102030405060708090a0b0c0d0e0", data, 16);
162 printf("rc = %d\n", rc);
163
164 printf("Hexparse with invalid char\n");
165 memset(data, 0, sizeof(data));
166 rc = osmo_hexparse("0001020304050X0708090a0b0c0d0e0f", data, 16);
167 printf("rc = %d\n", rc);
168}
169
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +0200170static void test_idtag_parsing(void)
171{
172 struct tlv_parsed tvp;
173 int rc;
174
175 static uint8_t data[] = {
176 0x01, 0x08,
177 0x01, 0x07,
178 0x01, 0x02,
179 0x01, 0x03,
180 0x01, 0x04,
181 0x01, 0x05,
182 0x01, 0x01,
183 0x01, 0x00,
184 0x11, 0x23, 0x4e, 0x6a, 0x28, 0xd2, 0xa2, 0x53, 0x3a, 0x2a, 0x82, 0xa7, 0x7a, 0xef, 0x29, 0xd4, 0x44, 0x30,
185 0x11, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
186 };
187
188 rc = ipa_ccm_idtag_parse_off(&tvp, data, sizeof(data), 1);
189 OSMO_ASSERT(rc == 0);
190
191 OSMO_ASSERT(TLVP_PRESENT(&tvp, 8));
192 OSMO_ASSERT(TLVP_LEN(&tvp, 8) == 0);
193
194 OSMO_ASSERT(TLVP_PRESENT(&tvp, 7));
195 OSMO_ASSERT(TLVP_LEN(&tvp, 7) == 0);
196
197 OSMO_ASSERT(TLVP_PRESENT(&tvp, 2));
198 OSMO_ASSERT(TLVP_LEN(&tvp, 2) == 0);
199
200 OSMO_ASSERT(TLVP_PRESENT(&tvp, 3));
201 OSMO_ASSERT(TLVP_LEN(&tvp, 3) == 0);
202
203 OSMO_ASSERT(TLVP_PRESENT(&tvp, 4));
204 OSMO_ASSERT(TLVP_LEN(&tvp, 4) == 0);
205
206 OSMO_ASSERT(TLVP_PRESENT(&tvp, 5));
207 OSMO_ASSERT(TLVP_LEN(&tvp, 5) == 0);
208
209 OSMO_ASSERT(TLVP_PRESENT(&tvp, 1));
210 OSMO_ASSERT(TLVP_LEN(&tvp, 1) == 0);
211
212 OSMO_ASSERT(TLVP_PRESENT(&tvp, 0));
213 OSMO_ASSERT(TLVP_LEN(&tvp, 0) == 0);
214
215 OSMO_ASSERT(TLVP_PRESENT(&tvp, 0x23));
216 OSMO_ASSERT(TLVP_LEN(&tvp, 0x23) == 16);
217
218 OSMO_ASSERT(TLVP_PRESENT(&tvp, 0x24));
219 OSMO_ASSERT(TLVP_LEN(&tvp, 0x24) == 16);
220
221 OSMO_ASSERT(!TLVP_PRESENT(&tvp, 0x25));
222}
223
Neels Hofmeyr4335bad2017-10-07 04:39:14 +0200224static struct {
225 const char *str;
226 int min_digits;
227 int max_digits;
228 bool require_even;
229 bool expect_ok;
230} test_hexstrs[] = {
231 { NULL, 0, 10, false, true },
232 { NULL, 1, 10, false, false },
233 { "", 0, 10, false, true },
234 { "", 1, 10, false, false },
235 { " ", 0, 10, false, false },
236 { "1", 0, 10, false, true },
237 { "1", 1, 10, false, true },
238 { "1", 1, 10, true, false },
239 { "1", 2, 10, false, false },
240 { "123", 1, 10, false, true },
241 { "123", 1, 10, true, false },
242 { "123", 4, 10, false, false },
243 { "1234", 4, 10, true, true },
244 { "12345", 4, 10, true, false },
245 { "123456", 4, 10, true, true },
246 { "1234567", 4, 10, true, false },
247 { "12345678", 4, 10, true, true },
248 { "123456789", 4, 10, true, false },
249 { "123456789a", 4, 10, true, true },
250 { "123456789ab", 4, 10, true, false },
251 { "123456789abc", 4, 10, true, false },
252 { "123456789ab", 4, 10, false, false },
253 { "123456789abc", 4, 10, false, false },
254 { "0123456789abcdefABCDEF", 0, 100, false, true },
255 { "0123456789 abcdef ABCDEF", 0, 100, false, false },
256 { "foobar", 0, 100, false, false },
257 { "BeadedBeeAced1EbbedDefacedFacade", 32, 32, true, true },
258 { "C01ffedC1cadaeAc1d1f1edAcac1aB0a", 32, 32, false, true },
259 { "DeafBeddedBabeAcceededFadedDecaff", 32, 32, false, false },
260};
261
262bool test_is_hexstr()
263{
264 int i;
265 bool pass = true;
266 bool ok = true;
267 printf("\n----- %s\n", __func__);
268
269 for (i = 0; i < ARRAY_SIZE(test_hexstrs); i++) {
270 ok = osmo_is_hexstr(test_hexstrs[i].str,
271 test_hexstrs[i].min_digits,
272 test_hexstrs[i].max_digits,
273 test_hexstrs[i].require_even);
274 pass = pass && (ok == test_hexstrs[i].expect_ok);
275 printf("%2d: %s str='%s' min=%d max=%d even=%d expect=%s\n",
276 i, test_hexstrs[i].expect_ok == ok ? "pass" : "FAIL",
277 test_hexstrs[i].str,
278 test_hexstrs[i].min_digits,
279 test_hexstrs[i].max_digits,
280 test_hexstrs[i].require_even,
281 test_hexstrs[i].expect_ok ? "valid" : "invalid");
282 }
283 return pass;
284}
285
Harald Welte504caac2017-10-27 17:19:59 +0200286struct bcdcheck {
287 uint8_t bcd;
288 char ch;
289};
290
291static const struct bcdcheck bcdchecks[] = {
292 { 0, '0' },
293 { 1, '1' },
294 { 2, '2' },
295 { 3, '3' },
296 { 4, '4' },
297 { 5, '5' },
298 { 6, '6' },
299 { 7, '7' },
300 { 8, '8' },
301 { 9, '9' },
302 { 0xA, 'A' },
303 { 0xB, 'B' },
304 { 0xC, 'C' },
305 { 0xD, 'D' },
306 { 0xE, 'E' },
307 { 0xF, 'F' },
308};
309
310static void bcd_test(void)
311{
312 int i;
313
314 printf("\nTesting BCD conversion\n");
315 for (i = 0; i < ARRAY_SIZE(bcdchecks); i++) {
316 const struct bcdcheck *check = &bcdchecks[i];
317 char ch = osmo_bcd2char(check->bcd);
318 printf("\tval=0x%x, expected=%c, found=%c\n", check->bcd, check->ch, ch);
319 OSMO_ASSERT(osmo_bcd2char(check->bcd) == check->ch);
320 /* test char -> bcd back-coversion */
321 OSMO_ASSERT(osmo_char2bcd(ch) == check->bcd);
322 /* test for lowercase hex char */
323 OSMO_ASSERT(osmo_char2bcd(tolower(ch)) == check->bcd);
324 }
325}
326
Neels Hofmeyr9910bbc2017-12-16 00:54:52 +0100327static void str_escape_test(void)
328{
329 int i;
330 int j;
331 uint8_t in_buf[32];
332 char out_buf[11];
333 const char *printable = "printable";
334 const char *res;
335
336 printf("\nTesting string escaping\n");
337 printf("- all chars from 0 to 255 in batches of 16:\n");
Pau Espin Pedrol6de34ee2018-02-01 12:49:39 +0100338 in_buf[16] = '\0';
Neels Hofmeyr9910bbc2017-12-16 00:54:52 +0100339 for (j = 0; j < 16; j++) {
340 for (i = 0; i < 16; i++)
341 in_buf[i] = (j << 4) | i;
342 printf("\"%s\"\n", osmo_escape_str((const char*)in_buf, 16));
343 }
344
345 printf("- nul terminated:\n");
346 printf("\"%s\"\n", osmo_escape_str("termi\nated", -1));
347
348 printf("- passthru:\n");
349 res = osmo_escape_str(printable, -1);
350 if (res != printable)
351 printf("NOT passed through! \"%s\"\n", res);
352 else
353 printf("passed through unchanged \"%s\"\n", res);
354
355 printf("- zero length:\n");
356 printf("\"%s\"\n", osmo_escape_str("omitted", 0));
357
358 printf("- truncation when too long:\n");
359 memset(in_buf, 'x', sizeof(in_buf));
360 in_buf[0] = '\a';
361 in_buf[7] = 'E';
362 memset(out_buf, 0x7f, sizeof(out_buf));
363 printf("\"%s\"\n", osmo_escape_str_buf((const char *)in_buf, sizeof(in_buf), out_buf, 10));
364 OSMO_ASSERT(out_buf[10] == 0x7f);
365
366 printf("- passthrough without truncation when no escaping needed:\n");
367 memset(in_buf, 'x', sizeof(in_buf));
368 in_buf[19] = 'E';
369 in_buf[20] = '\0';
370 memset(out_buf, 0x7f, sizeof(out_buf));
371 printf("\"%s\"\n", osmo_escape_str_buf((const char *)in_buf, -1, out_buf, 10));
372 OSMO_ASSERT(out_buf[0] == 0x7f);
373}
374
Neels Hofmeyr04eb56f2018-04-09 00:41:28 +0200375static void str_quote_test(void)
376{
377 int i;
378 int j;
379 uint8_t in_buf[32];
380 char out_buf[11];
381 const char *printable = "printable";
382 const char *res;
383
384 printf("\nTesting string quoting\n");
385 printf("- all chars from 0 to 255 in batches of 16:\n");
386 in_buf[16] = '\0';
387 for (j = 0; j < 16; j++) {
388 for (i = 0; i < 16; i++)
389 in_buf[i] = (j << 4) | i;
390 printf("'%s'\n", osmo_quote_str((const char*)in_buf, 16));
391 }
392
393 printf("- nul terminated:\n");
394 printf("'%s'\n", osmo_quote_str("termi\nated", -1));
395
396 printf("- never passthru:\n");
397 res = osmo_quote_str(printable, -1);
398 if (res != printable)
399 printf("NOT passed through. '%s'\n", res);
400 else
401 printf("passed through unchanged '%s'\n", res);
402
403 printf("- zero length:\n");
404 printf("'%s'\n", osmo_quote_str("omitted", 0));
405
406 printf("- truncation when too long:\n");
407 memset(in_buf, 'x', sizeof(in_buf));
408 in_buf[0] = '\a';
409 in_buf[5] = 'E';
410 memset(out_buf, 0x7f, sizeof(out_buf));
411 printf("'%s'\n", osmo_quote_str_buf((const char *)in_buf, sizeof(in_buf), out_buf, 10));
412 OSMO_ASSERT(out_buf[10] == 0x7f);
413
414 printf("- always truncation, even when no escaping needed:\n");
415 memset(in_buf, 'x', sizeof(in_buf));
416 in_buf[6] = 'E'; /* dst has 10, less 2 quotes and nul, leaves 7, i.e. in[6] is last */
417 in_buf[20] = '\0';
418 memset(out_buf, 0x7f, sizeof(out_buf));
419 printf("'%s'\n", osmo_quote_str_buf((const char *)in_buf, -1, out_buf, 10));
420 OSMO_ASSERT(out_buf[0] == '"');
421
422 printf("- try to feed too little buf for quoting:\n");
423 printf("'%s'\n", osmo_quote_str_buf("", -1, out_buf, 2));
424
425 printf("- NULL string becomes a \"NULL\" literal:\n");
426 printf("'%s'\n", osmo_quote_str_buf(NULL, -1, out_buf, 10));
427}
428
Harald Welte15a5f8d2018-06-06 16:58:17 +0200429static void isqrt_test(void)
430{
431 int i;
432
433 printf("\nTesting integer square-root\n");
434 srand(time(NULL));
435 for (i = 0; i < 1024; i++) {
436 uint16_t x;
437 uint32_t r = rand();
438 if (RAND_MAX < UINT16_MAX)
439 x = r * (UINT16_MAX/RAND_MAX);
440 else
441 x = r;
442 uint32_t sq = x*x;
443 uint32_t y = osmo_isqrt32(sq);
444 if (y != x)
445 printf("ERROR: x=%u, sq=%u, osmo_isqrt(%u) = %u\n", x, sq, sq, y);
446 }
447}
448
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +0100449int main(int argc, char **argv)
450{
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +0200451 static const struct log_info log_info = {};
452 log_init(&log_info, NULL);
453
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +0100454 hexdump_test();
Neels Hofmeyr7adb5672017-02-14 15:48:19 +0100455 hexparse_test();
Holger Hans Peter Freytherf558ed42015-06-02 15:52:06 +0200456 test_idtag_parsing();
Neels Hofmeyr4335bad2017-10-07 04:39:14 +0200457 test_is_hexstr();
Harald Welte504caac2017-10-27 17:19:59 +0200458 bcd_test();
Neels Hofmeyr9910bbc2017-12-16 00:54:52 +0100459 str_escape_test();
Neels Hofmeyr04eb56f2018-04-09 00:41:28 +0200460 str_quote_test();
Harald Welte15a5f8d2018-06-06 16:58:17 +0200461 isqrt_test();
Holger Hans Peter Freytherb79a1482014-01-02 13:55:00 +0100462 return 0;
463}