2021-01-09 02:24:51 +08:00
|
|
|
#include "common.h"
|
|
|
|
|
2018-01-19 00:08:24 +08:00
|
|
|
#include <assert.h>
|
2019-12-07 18:01:55 +08:00
|
|
|
#include <limits.h>
|
|
|
|
#include <stdio.h>
|
2021-11-25 04:44:29 +08:00
|
|
|
#include <stdlib.h>
|
2018-01-19 00:08:24 +08:00
|
|
|
#include <string.h>
|
|
|
|
|
2021-11-13 06:12:51 +08:00
|
|
|
#include "util/str.h"
|
2018-01-19 00:08:24 +08:00
|
|
|
|
2021-11-13 06:08:19 +08:00
|
|
|
static void test_strncpy_simple(void) {
|
2018-01-19 00:08:24 +08:00
|
|
|
char s[] = "xxxxxxxxxx";
|
2021-11-13 06:08:19 +08:00
|
|
|
size_t w = sc_strncpy(s, "abcdef", sizeof(s));
|
2018-01-19 00:08:24 +08:00
|
|
|
|
|
|
|
// returns strlen of copied string
|
|
|
|
assert(w == 6);
|
|
|
|
|
|
|
|
// is nul-terminated
|
|
|
|
assert(s[6] == '\0');
|
|
|
|
|
|
|
|
// does not write useless bytes
|
|
|
|
assert(s[7] == 'x');
|
|
|
|
|
|
|
|
// copies the content as expected
|
|
|
|
assert(!strcmp("abcdef", s));
|
|
|
|
}
|
|
|
|
|
2021-11-13 06:08:19 +08:00
|
|
|
static void test_strncpy_just_fit(void) {
|
2018-01-19 00:08:24 +08:00
|
|
|
char s[] = "xxxxxx";
|
2021-11-13 06:08:19 +08:00
|
|
|
size_t w = sc_strncpy(s, "abcdef", sizeof(s));
|
2018-01-19 00:08:24 +08:00
|
|
|
|
|
|
|
// returns strlen of copied string
|
|
|
|
assert(w == 6);
|
|
|
|
|
|
|
|
// is nul-terminated
|
|
|
|
assert(s[6] == '\0');
|
|
|
|
|
|
|
|
// copies the content as expected
|
|
|
|
assert(!strcmp("abcdef", s));
|
|
|
|
}
|
|
|
|
|
2021-11-13 06:08:19 +08:00
|
|
|
static void test_strncpy_truncated(void) {
|
2018-01-19 00:08:24 +08:00
|
|
|
char s[] = "xxx";
|
2021-11-13 06:08:19 +08:00
|
|
|
size_t w = sc_strncpy(s, "abcdef", sizeof(s));
|
2018-01-19 00:08:24 +08:00
|
|
|
|
|
|
|
// returns 'n' (sizeof(s))
|
|
|
|
assert(w == 4);
|
|
|
|
|
|
|
|
// is nul-terminated
|
|
|
|
assert(s[3] == '\0');
|
|
|
|
|
|
|
|
// copies the content as expected
|
|
|
|
assert(!strncmp("abcdef", s, 3));
|
|
|
|
}
|
|
|
|
|
2021-11-13 06:08:19 +08:00
|
|
|
static void test_join_simple(void) {
|
2018-01-19 00:08:24 +08:00
|
|
|
const char *const tokens[] = { "abc", "de", "fghi", NULL };
|
|
|
|
char s[] = "xxxxxxxxxxxxxx";
|
2021-11-13 06:08:19 +08:00
|
|
|
size_t w = sc_str_join(s, tokens, ' ', sizeof(s));
|
2018-01-19 00:08:24 +08:00
|
|
|
|
|
|
|
// returns strlen of concatenation
|
|
|
|
assert(w == 11);
|
|
|
|
|
|
|
|
// is nul-terminated
|
|
|
|
assert(s[11] == '\0');
|
|
|
|
|
|
|
|
// does not write useless bytes
|
|
|
|
assert(s[12] == 'x');
|
|
|
|
|
|
|
|
// copies the content as expected
|
|
|
|
assert(!strcmp("abc de fghi", s));
|
|
|
|
}
|
|
|
|
|
2021-11-13 06:08:19 +08:00
|
|
|
static void test_join_just_fit(void) {
|
2018-01-19 00:08:24 +08:00
|
|
|
const char *const tokens[] = { "abc", "de", "fghi", NULL };
|
|
|
|
char s[] = "xxxxxxxxxxx";
|
2021-11-13 06:08:19 +08:00
|
|
|
size_t w = sc_str_join(s, tokens, ' ', sizeof(s));
|
2018-01-19 00:08:24 +08:00
|
|
|
|
|
|
|
// returns strlen of concatenation
|
|
|
|
assert(w == 11);
|
|
|
|
|
|
|
|
// is nul-terminated
|
|
|
|
assert(s[11] == '\0');
|
|
|
|
|
|
|
|
// copies the content as expected
|
|
|
|
assert(!strcmp("abc de fghi", s));
|
|
|
|
}
|
|
|
|
|
2021-11-13 06:08:19 +08:00
|
|
|
static void test_join_truncated_in_token(void) {
|
2018-01-19 00:08:24 +08:00
|
|
|
const char *const tokens[] = { "abc", "de", "fghi", NULL };
|
|
|
|
char s[] = "xxxxx";
|
2021-11-13 06:08:19 +08:00
|
|
|
size_t w = sc_str_join(s, tokens, ' ', sizeof(s));
|
2018-01-19 00:08:24 +08:00
|
|
|
|
|
|
|
// returns 'n' (sizeof(s))
|
|
|
|
assert(w == 6);
|
|
|
|
|
|
|
|
// is nul-terminated
|
|
|
|
assert(s[5] == '\0');
|
|
|
|
|
|
|
|
// copies the content as expected
|
|
|
|
assert(!strcmp("abc d", s));
|
|
|
|
}
|
|
|
|
|
2021-11-13 06:08:19 +08:00
|
|
|
static void test_join_truncated_before_sep(void) {
|
2018-01-19 00:08:24 +08:00
|
|
|
const char *const tokens[] = { "abc", "de", "fghi", NULL };
|
|
|
|
char s[] = "xxxxxx";
|
2021-11-13 06:08:19 +08:00
|
|
|
size_t w = sc_str_join(s, tokens, ' ', sizeof(s));
|
2018-01-19 00:08:24 +08:00
|
|
|
|
|
|
|
// returns 'n' (sizeof(s))
|
|
|
|
assert(w == 7);
|
|
|
|
|
|
|
|
// is nul-terminated
|
|
|
|
assert(s[6] == '\0');
|
|
|
|
|
|
|
|
// copies the content as expected
|
|
|
|
assert(!strcmp("abc de", s));
|
|
|
|
}
|
|
|
|
|
2021-11-13 06:08:19 +08:00
|
|
|
static void test_join_truncated_after_sep(void) {
|
2018-01-19 00:08:24 +08:00
|
|
|
const char *const tokens[] = { "abc", "de", "fghi", NULL };
|
|
|
|
char s[] = "xxxxxxx";
|
2021-11-13 06:08:19 +08:00
|
|
|
size_t w = sc_str_join(s, tokens, ' ', sizeof(s));
|
2018-01-19 00:08:24 +08:00
|
|
|
|
|
|
|
// returns 'n' (sizeof(s))
|
|
|
|
assert(w == 8);
|
|
|
|
|
|
|
|
// is nul-terminated
|
|
|
|
assert(s[7] == '\0');
|
|
|
|
|
|
|
|
// copies the content as expected
|
|
|
|
assert(!strcmp("abc de ", s));
|
|
|
|
}
|
|
|
|
|
2021-11-13 06:08:19 +08:00
|
|
|
static void test_quote(void) {
|
2019-11-30 12:15:58 +08:00
|
|
|
const char *s = "abcde";
|
2021-11-13 06:08:19 +08:00
|
|
|
char *out = sc_str_quote(s);
|
2019-11-30 12:15:58 +08:00
|
|
|
|
|
|
|
// add '"' at the beginning and the end
|
|
|
|
assert(!strcmp("\"abcde\"", out));
|
|
|
|
|
2021-01-24 22:14:53 +08:00
|
|
|
free(out);
|
2019-11-30 12:15:58 +08:00
|
|
|
}
|
|
|
|
|
2019-05-31 01:01:08 +08:00
|
|
|
static void test_utf8_truncate(void) {
|
|
|
|
const char *s = "aÉbÔc";
|
|
|
|
assert(strlen(s) == 7); // É and Ô are 2 bytes-wide
|
|
|
|
|
|
|
|
size_t count;
|
|
|
|
|
2021-11-13 06:08:19 +08:00
|
|
|
count = sc_str_utf8_truncation_index(s, 1);
|
2019-05-31 01:01:08 +08:00
|
|
|
assert(count == 1);
|
|
|
|
|
2021-11-13 06:08:19 +08:00
|
|
|
count = sc_str_utf8_truncation_index(s, 2);
|
2019-05-31 01:01:08 +08:00
|
|
|
assert(count == 1); // É is 2 bytes-wide
|
|
|
|
|
2021-11-13 06:08:19 +08:00
|
|
|
count = sc_str_utf8_truncation_index(s, 3);
|
2019-05-31 01:01:08 +08:00
|
|
|
assert(count == 3);
|
|
|
|
|
2021-11-13 06:08:19 +08:00
|
|
|
count = sc_str_utf8_truncation_index(s, 4);
|
2019-05-31 01:01:08 +08:00
|
|
|
assert(count == 4);
|
|
|
|
|
2021-11-13 06:08:19 +08:00
|
|
|
count = sc_str_utf8_truncation_index(s, 5);
|
2019-05-31 01:01:08 +08:00
|
|
|
assert(count == 4); // Ô is 2 bytes-wide
|
|
|
|
|
2021-11-13 06:08:19 +08:00
|
|
|
count = sc_str_utf8_truncation_index(s, 6);
|
2019-05-31 01:01:08 +08:00
|
|
|
assert(count == 6);
|
|
|
|
|
2021-11-13 06:08:19 +08:00
|
|
|
count = sc_str_utf8_truncation_index(s, 7);
|
2019-05-31 01:01:08 +08:00
|
|
|
assert(count == 7);
|
|
|
|
|
2021-11-13 06:08:19 +08:00
|
|
|
count = sc_str_utf8_truncation_index(s, 8);
|
2019-05-31 01:01:08 +08:00
|
|
|
assert(count == 7); // no more chars
|
|
|
|
}
|
|
|
|
|
2019-12-07 18:01:55 +08:00
|
|
|
static void test_parse_integer(void) {
|
|
|
|
long value;
|
2021-11-13 06:08:19 +08:00
|
|
|
bool ok = sc_str_parse_integer("1234", &value);
|
2019-12-07 18:01:55 +08:00
|
|
|
assert(ok);
|
|
|
|
assert(value == 1234);
|
|
|
|
|
2021-11-13 06:08:19 +08:00
|
|
|
ok = sc_str_parse_integer("-1234", &value);
|
2019-12-07 18:01:55 +08:00
|
|
|
assert(ok);
|
|
|
|
assert(value == -1234);
|
|
|
|
|
2021-11-13 06:08:19 +08:00
|
|
|
ok = sc_str_parse_integer("1234k", &value);
|
2019-12-07 18:01:55 +08:00
|
|
|
assert(!ok);
|
|
|
|
|
2021-11-13 06:08:19 +08:00
|
|
|
ok = sc_str_parse_integer("123456789876543212345678987654321", &value);
|
2019-12-07 18:01:55 +08:00
|
|
|
assert(!ok); // out-of-range
|
|
|
|
}
|
|
|
|
|
2019-12-09 21:32:59 +08:00
|
|
|
static void test_parse_integers(void) {
|
|
|
|
long values[5];
|
|
|
|
|
2021-11-13 06:08:19 +08:00
|
|
|
size_t count = sc_str_parse_integers("1234", ':', 5, values);
|
2019-12-09 21:32:59 +08:00
|
|
|
assert(count == 1);
|
|
|
|
assert(values[0] == 1234);
|
|
|
|
|
2021-11-13 06:08:19 +08:00
|
|
|
count = sc_str_parse_integers("1234:5678", ':', 5, values);
|
2019-12-09 21:32:59 +08:00
|
|
|
assert(count == 2);
|
|
|
|
assert(values[0] == 1234);
|
|
|
|
assert(values[1] == 5678);
|
|
|
|
|
2021-11-13 06:08:19 +08:00
|
|
|
count = sc_str_parse_integers("1234:5678", ':', 2, values);
|
2019-12-09 21:32:59 +08:00
|
|
|
assert(count == 2);
|
|
|
|
assert(values[0] == 1234);
|
|
|
|
assert(values[1] == 5678);
|
|
|
|
|
2021-11-13 06:08:19 +08:00
|
|
|
count = sc_str_parse_integers("1234:-5678", ':', 2, values);
|
2019-12-09 21:32:59 +08:00
|
|
|
assert(count == 2);
|
|
|
|
assert(values[0] == 1234);
|
|
|
|
assert(values[1] == -5678);
|
|
|
|
|
2021-11-13 06:08:19 +08:00
|
|
|
count = sc_str_parse_integers("1:2:3:4:5", ':', 5, values);
|
2019-12-09 21:32:59 +08:00
|
|
|
assert(count == 5);
|
|
|
|
assert(values[0] == 1);
|
|
|
|
assert(values[1] == 2);
|
|
|
|
assert(values[2] == 3);
|
|
|
|
assert(values[3] == 4);
|
|
|
|
assert(values[4] == 5);
|
|
|
|
|
2021-11-13 06:08:19 +08:00
|
|
|
count = sc_str_parse_integers("1234:5678", ':', 1, values);
|
2019-12-09 21:32:59 +08:00
|
|
|
assert(count == 0); // max_items == 1
|
|
|
|
|
2021-11-13 06:08:19 +08:00
|
|
|
count = sc_str_parse_integers("1:2:3:4:5", ':', 3, values);
|
2019-12-09 21:32:59 +08:00
|
|
|
assert(count == 0); // max_items == 3
|
|
|
|
|
2021-11-13 06:08:19 +08:00
|
|
|
count = sc_str_parse_integers(":1234", ':', 5, values);
|
2019-12-09 21:32:59 +08:00
|
|
|
assert(count == 0); // invalid
|
|
|
|
|
2021-11-13 06:08:19 +08:00
|
|
|
count = sc_str_parse_integers("1234:", ':', 5, values);
|
2019-12-09 21:32:59 +08:00
|
|
|
assert(count == 0); // invalid
|
|
|
|
|
2021-11-13 06:08:19 +08:00
|
|
|
count = sc_str_parse_integers("1234:", ':', 1, values);
|
2019-12-09 21:32:59 +08:00
|
|
|
assert(count == 0); // invalid, even when max_items == 1
|
|
|
|
|
2021-11-13 06:08:19 +08:00
|
|
|
count = sc_str_parse_integers("1234::5678", ':', 5, values);
|
2019-12-09 21:32:59 +08:00
|
|
|
assert(count == 0); // invalid
|
|
|
|
}
|
|
|
|
|
2019-12-07 18:01:55 +08:00
|
|
|
static void test_parse_integer_with_suffix(void) {
|
|
|
|
long value;
|
2021-11-13 06:08:19 +08:00
|
|
|
bool ok = sc_str_parse_integer_with_suffix("1234", &value);
|
2019-12-07 18:01:55 +08:00
|
|
|
assert(ok);
|
|
|
|
assert(value == 1234);
|
|
|
|
|
2021-11-13 06:08:19 +08:00
|
|
|
ok = sc_str_parse_integer_with_suffix("-1234", &value);
|
2019-12-07 18:01:55 +08:00
|
|
|
assert(ok);
|
|
|
|
assert(value == -1234);
|
|
|
|
|
2021-11-13 06:08:19 +08:00
|
|
|
ok = sc_str_parse_integer_with_suffix("1234k", &value);
|
2019-12-07 18:01:55 +08:00
|
|
|
assert(ok);
|
|
|
|
assert(value == 1234000);
|
|
|
|
|
2021-11-13 06:08:19 +08:00
|
|
|
ok = sc_str_parse_integer_with_suffix("1234m", &value);
|
2019-12-07 18:01:55 +08:00
|
|
|
assert(ok);
|
|
|
|
assert(value == 1234000000);
|
|
|
|
|
2021-11-13 06:08:19 +08:00
|
|
|
ok = sc_str_parse_integer_with_suffix("-1234k", &value);
|
2019-12-07 18:01:55 +08:00
|
|
|
assert(ok);
|
|
|
|
assert(value == -1234000);
|
|
|
|
|
2021-11-13 06:08:19 +08:00
|
|
|
ok = sc_str_parse_integer_with_suffix("-1234m", &value);
|
2019-12-07 18:01:55 +08:00
|
|
|
assert(ok);
|
|
|
|
assert(value == -1234000000);
|
|
|
|
|
2021-11-13 06:08:19 +08:00
|
|
|
ok = sc_str_parse_integer_with_suffix("123456789876543212345678987654321", &value);
|
2019-12-07 18:01:55 +08:00
|
|
|
assert(!ok); // out-of-range
|
|
|
|
|
|
|
|
char buf[32];
|
|
|
|
|
|
|
|
sprintf(buf, "%ldk", LONG_MAX / 2000);
|
2021-11-13 06:08:19 +08:00
|
|
|
ok = sc_str_parse_integer_with_suffix(buf, &value);
|
2019-12-07 18:01:55 +08:00
|
|
|
assert(ok);
|
|
|
|
assert(value == LONG_MAX / 2000 * 1000);
|
|
|
|
|
|
|
|
sprintf(buf, "%ldm", LONG_MAX / 2000);
|
2021-11-13 06:08:19 +08:00
|
|
|
ok = sc_str_parse_integer_with_suffix(buf, &value);
|
2019-12-07 18:01:55 +08:00
|
|
|
assert(!ok);
|
|
|
|
|
|
|
|
sprintf(buf, "%ldk", LONG_MIN / 2000);
|
2021-11-13 06:08:19 +08:00
|
|
|
ok = sc_str_parse_integer_with_suffix(buf, &value);
|
2019-12-07 18:01:55 +08:00
|
|
|
assert(ok);
|
|
|
|
assert(value == LONG_MIN / 2000 * 1000);
|
|
|
|
|
|
|
|
sprintf(buf, "%ldm", LONG_MIN / 2000);
|
2021-11-13 06:08:19 +08:00
|
|
|
ok = sc_str_parse_integer_with_suffix(buf, &value);
|
2019-12-07 18:01:55 +08:00
|
|
|
assert(!ok);
|
|
|
|
}
|
|
|
|
|
2021-04-19 15:22:53 +08:00
|
|
|
static void test_strlist_contains(void) {
|
2021-11-13 06:08:19 +08:00
|
|
|
assert(sc_str_list_contains("a,bc,def", ',', "bc"));
|
|
|
|
assert(!sc_str_list_contains("a,bc,def", ',', "b"));
|
|
|
|
assert(sc_str_list_contains("", ',', ""));
|
|
|
|
assert(sc_str_list_contains("abc,", ',', ""));
|
|
|
|
assert(sc_str_list_contains(",abc", ',', ""));
|
|
|
|
assert(sc_str_list_contains("abc,,def", ',', ""));
|
|
|
|
assert(!sc_str_list_contains("abc", ',', ""));
|
|
|
|
assert(sc_str_list_contains(",,|x", '|', ",,"));
|
|
|
|
assert(sc_str_list_contains("xyz", '\0', "xyz"));
|
2021-04-19 15:22:53 +08:00
|
|
|
}
|
|
|
|
|
2021-11-07 03:26:35 +08:00
|
|
|
static void test_wrap_lines(void) {
|
|
|
|
const char *s = "This is a text to test line wrapping. The lines must be "
|
|
|
|
"wrapped at a space or a line break.\n"
|
|
|
|
"\n"
|
|
|
|
"This rectangle must remains a rectangle because it is "
|
|
|
|
"drawn in lines having lengths lower than the specified "
|
|
|
|
"number of columns:\n"
|
|
|
|
" +----+\n"
|
|
|
|
" | |\n"
|
|
|
|
" +----+\n";
|
|
|
|
|
|
|
|
// |---- 1 1 2 2|
|
|
|
|
// |0 5 0 5 0 3| <-- 24 columns
|
|
|
|
const char *expected = " This is a text to\n"
|
|
|
|
" test line wrapping.\n"
|
|
|
|
" The lines must be\n"
|
|
|
|
" wrapped at a space\n"
|
|
|
|
" or a line break.\n"
|
|
|
|
" \n"
|
|
|
|
" This rectangle must\n"
|
|
|
|
" remains a rectangle\n"
|
|
|
|
" because it is drawn\n"
|
|
|
|
" in lines having\n"
|
|
|
|
" lengths lower than\n"
|
|
|
|
" the specified number\n"
|
|
|
|
" of columns:\n"
|
|
|
|
" +----+\n"
|
|
|
|
" | |\n"
|
|
|
|
" +----+\n";
|
|
|
|
|
|
|
|
char *formatted = sc_str_wrap_lines(s, 24, 4);
|
|
|
|
assert(formatted);
|
|
|
|
|
|
|
|
assert(!strcmp(formatted, expected));
|
|
|
|
|
|
|
|
free(formatted);
|
|
|
|
}
|
|
|
|
|
2021-11-18 04:38:59 +08:00
|
|
|
static void test_truncate(void) {
|
2021-11-18 01:25:56 +08:00
|
|
|
char s[] = "hello\nworld\n!";
|
2021-11-18 04:38:59 +08:00
|
|
|
size_t len = sc_str_truncate(s, sizeof(s), "\n");
|
2021-11-18 01:25:56 +08:00
|
|
|
|
|
|
|
assert(len == 5);
|
|
|
|
assert(!strcmp("hello", s));
|
2021-11-18 04:38:59 +08:00
|
|
|
|
|
|
|
char s2[] = "hello\r\nworkd\r\n!";
|
|
|
|
len = sc_str_truncate(s2, sizeof(s2), "\n\r");
|
|
|
|
|
|
|
|
assert(len == 5);
|
|
|
|
assert(!strcmp("hello", s));
|
|
|
|
|
|
|
|
char s3[] = "hello world\n!";
|
|
|
|
len = sc_str_truncate(s3, sizeof(s3), " \n\r");
|
|
|
|
|
|
|
|
assert(len == 5);
|
|
|
|
assert(!strcmp("hello", s3));
|
|
|
|
|
|
|
|
char s4[] = "hello ";
|
|
|
|
len = sc_str_truncate(s4, sizeof(s4), " \n\r");
|
|
|
|
|
|
|
|
assert(len == 5);
|
|
|
|
assert(!strcmp("hello", s4));
|
2021-11-18 01:25:56 +08:00
|
|
|
}
|
|
|
|
|
2020-07-15 18:17:04 +08:00
|
|
|
int main(int argc, char *argv[]) {
|
|
|
|
(void) argc;
|
|
|
|
(void) argv;
|
|
|
|
|
2021-11-13 06:08:19 +08:00
|
|
|
test_strncpy_simple();
|
|
|
|
test_strncpy_just_fit();
|
|
|
|
test_strncpy_truncated();
|
|
|
|
test_join_simple();
|
|
|
|
test_join_just_fit();
|
|
|
|
test_join_truncated_in_token();
|
|
|
|
test_join_truncated_before_sep();
|
|
|
|
test_join_truncated_after_sep();
|
|
|
|
test_quote();
|
2019-05-31 01:01:08 +08:00
|
|
|
test_utf8_truncate();
|
2019-12-07 18:01:55 +08:00
|
|
|
test_parse_integer();
|
2019-12-09 21:32:59 +08:00
|
|
|
test_parse_integers();
|
2019-12-07 18:01:55 +08:00
|
|
|
test_parse_integer_with_suffix();
|
2021-04-19 15:22:53 +08:00
|
|
|
test_strlist_contains();
|
2021-11-07 03:26:35 +08:00
|
|
|
test_wrap_lines();
|
2021-11-18 04:38:59 +08:00
|
|
|
test_truncate();
|
2018-01-19 00:08:24 +08:00
|
|
|
return 0;
|
|
|
|
}
|