test_str.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. #include "common.h"
  2. #include <assert.h>
  3. #include <limits.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include "util/str.h"
  8. static void test_strncpy_simple(void) {
  9. char s[] = "xxxxxxxxxx";
  10. size_t w = sc_strncpy(s, "abcdef", sizeof(s));
  11. // returns strlen of copied string
  12. assert(w == 6);
  13. // is nul-terminated
  14. assert(s[6] == '\0');
  15. // does not write useless bytes
  16. assert(s[7] == 'x');
  17. // copies the content as expected
  18. assert(!strcmp("abcdef", s));
  19. }
  20. static void test_strncpy_just_fit(void) {
  21. char s[] = "xxxxxx";
  22. size_t w = sc_strncpy(s, "abcdef", sizeof(s));
  23. // returns strlen of copied string
  24. assert(w == 6);
  25. // is nul-terminated
  26. assert(s[6] == '\0');
  27. // copies the content as expected
  28. assert(!strcmp("abcdef", s));
  29. }
  30. static void test_strncpy_truncated(void) {
  31. char s[] = "xxx";
  32. size_t w = sc_strncpy(s, "abcdef", sizeof(s));
  33. // returns 'n' (sizeof(s))
  34. assert(w == 4);
  35. // is nul-terminated
  36. assert(s[3] == '\0');
  37. // copies the content as expected
  38. assert(!strncmp("abcdef", s, 3));
  39. }
  40. static void test_join_simple(void) {
  41. const char *const tokens[] = { "abc", "de", "fghi", NULL };
  42. char s[] = "xxxxxxxxxxxxxx";
  43. size_t w = sc_str_join(s, tokens, ' ', sizeof(s));
  44. // returns strlen of concatenation
  45. assert(w == 11);
  46. // is nul-terminated
  47. assert(s[11] == '\0');
  48. // does not write useless bytes
  49. assert(s[12] == 'x');
  50. // copies the content as expected
  51. assert(!strcmp("abc de fghi", s));
  52. }
  53. static void test_join_just_fit(void) {
  54. const char *const tokens[] = { "abc", "de", "fghi", NULL };
  55. char s[] = "xxxxxxxxxxx";
  56. size_t w = sc_str_join(s, tokens, ' ', sizeof(s));
  57. // returns strlen of concatenation
  58. assert(w == 11);
  59. // is nul-terminated
  60. assert(s[11] == '\0');
  61. // copies the content as expected
  62. assert(!strcmp("abc de fghi", s));
  63. }
  64. static void test_join_truncated_in_token(void) {
  65. const char *const tokens[] = { "abc", "de", "fghi", NULL };
  66. char s[] = "xxxxx";
  67. size_t w = sc_str_join(s, tokens, ' ', sizeof(s));
  68. // returns 'n' (sizeof(s))
  69. assert(w == 6);
  70. // is nul-terminated
  71. assert(s[5] == '\0');
  72. // copies the content as expected
  73. assert(!strcmp("abc d", s));
  74. }
  75. static void test_join_truncated_before_sep(void) {
  76. const char *const tokens[] = { "abc", "de", "fghi", NULL };
  77. char s[] = "xxxxxx";
  78. size_t w = sc_str_join(s, tokens, ' ', sizeof(s));
  79. // returns 'n' (sizeof(s))
  80. assert(w == 7);
  81. // is nul-terminated
  82. assert(s[6] == '\0');
  83. // copies the content as expected
  84. assert(!strcmp("abc de", s));
  85. }
  86. static void test_join_truncated_after_sep(void) {
  87. const char *const tokens[] = { "abc", "de", "fghi", NULL };
  88. char s[] = "xxxxxxx";
  89. size_t w = sc_str_join(s, tokens, ' ', sizeof(s));
  90. // returns 'n' (sizeof(s))
  91. assert(w == 8);
  92. // is nul-terminated
  93. assert(s[7] == '\0');
  94. // copies the content as expected
  95. assert(!strcmp("abc de ", s));
  96. }
  97. static void test_quote(void) {
  98. const char *s = "abcde";
  99. char *out = sc_str_quote(s);
  100. // add '"' at the beginning and the end
  101. assert(!strcmp("\"abcde\"", out));
  102. free(out);
  103. }
  104. static void test_utf8_truncate(void) {
  105. const char *s = "aÉbÔc";
  106. assert(strlen(s) == 7); // É and Ô are 2 bytes-wide
  107. size_t count;
  108. count = sc_str_utf8_truncation_index(s, 1);
  109. assert(count == 1);
  110. count = sc_str_utf8_truncation_index(s, 2);
  111. assert(count == 1); // É is 2 bytes-wide
  112. count = sc_str_utf8_truncation_index(s, 3);
  113. assert(count == 3);
  114. count = sc_str_utf8_truncation_index(s, 4);
  115. assert(count == 4);
  116. count = sc_str_utf8_truncation_index(s, 5);
  117. assert(count == 4); // Ô is 2 bytes-wide
  118. count = sc_str_utf8_truncation_index(s, 6);
  119. assert(count == 6);
  120. count = sc_str_utf8_truncation_index(s, 7);
  121. assert(count == 7);
  122. count = sc_str_utf8_truncation_index(s, 8);
  123. assert(count == 7); // no more chars
  124. }
  125. static void test_parse_integer(void) {
  126. long value;
  127. bool ok = sc_str_parse_integer("1234", &value);
  128. assert(ok);
  129. assert(value == 1234);
  130. ok = sc_str_parse_integer("-1234", &value);
  131. assert(ok);
  132. assert(value == -1234);
  133. ok = sc_str_parse_integer("1234k", &value);
  134. assert(!ok);
  135. ok = sc_str_parse_integer("123456789876543212345678987654321", &value);
  136. assert(!ok); // out-of-range
  137. }
  138. static void test_parse_integers(void) {
  139. long values[5];
  140. size_t count = sc_str_parse_integers("1234", ':', 5, values);
  141. assert(count == 1);
  142. assert(values[0] == 1234);
  143. count = sc_str_parse_integers("1234:5678", ':', 5, values);
  144. assert(count == 2);
  145. assert(values[0] == 1234);
  146. assert(values[1] == 5678);
  147. count = sc_str_parse_integers("1234:5678", ':', 2, values);
  148. assert(count == 2);
  149. assert(values[0] == 1234);
  150. assert(values[1] == 5678);
  151. count = sc_str_parse_integers("1234:-5678", ':', 2, values);
  152. assert(count == 2);
  153. assert(values[0] == 1234);
  154. assert(values[1] == -5678);
  155. count = sc_str_parse_integers("1:2:3:4:5", ':', 5, values);
  156. assert(count == 5);
  157. assert(values[0] == 1);
  158. assert(values[1] == 2);
  159. assert(values[2] == 3);
  160. assert(values[3] == 4);
  161. assert(values[4] == 5);
  162. count = sc_str_parse_integers("1234:5678", ':', 1, values);
  163. assert(count == 0); // max_items == 1
  164. count = sc_str_parse_integers("1:2:3:4:5", ':', 3, values);
  165. assert(count == 0); // max_items == 3
  166. count = sc_str_parse_integers(":1234", ':', 5, values);
  167. assert(count == 0); // invalid
  168. count = sc_str_parse_integers("1234:", ':', 5, values);
  169. assert(count == 0); // invalid
  170. count = sc_str_parse_integers("1234:", ':', 1, values);
  171. assert(count == 0); // invalid, even when max_items == 1
  172. count = sc_str_parse_integers("1234::5678", ':', 5, values);
  173. assert(count == 0); // invalid
  174. }
  175. static void test_parse_integer_with_suffix(void) {
  176. long value;
  177. bool ok = sc_str_parse_integer_with_suffix("1234", &value);
  178. assert(ok);
  179. assert(value == 1234);
  180. ok = sc_str_parse_integer_with_suffix("-1234", &value);
  181. assert(ok);
  182. assert(value == -1234);
  183. ok = sc_str_parse_integer_with_suffix("1234k", &value);
  184. assert(ok);
  185. assert(value == 1234000);
  186. ok = sc_str_parse_integer_with_suffix("1234m", &value);
  187. assert(ok);
  188. assert(value == 1234000000);
  189. ok = sc_str_parse_integer_with_suffix("-1234k", &value);
  190. assert(ok);
  191. assert(value == -1234000);
  192. ok = sc_str_parse_integer_with_suffix("-1234m", &value);
  193. assert(ok);
  194. assert(value == -1234000000);
  195. ok = sc_str_parse_integer_with_suffix("123456789876543212345678987654321", &value);
  196. assert(!ok); // out-of-range
  197. char buf[32];
  198. int r = snprintf(buf, sizeof(buf), "%ldk", LONG_MAX / 2000);
  199. assert(r >= 0 && (size_t) r < sizeof(buf));
  200. ok = sc_str_parse_integer_with_suffix(buf, &value);
  201. assert(ok);
  202. assert(value == LONG_MAX / 2000 * 1000);
  203. r = snprintf(buf, sizeof(buf), "%ldm", LONG_MAX / 2000);
  204. assert(r >= 0 && (size_t) r < sizeof(buf));
  205. ok = sc_str_parse_integer_with_suffix(buf, &value);
  206. assert(!ok);
  207. r = snprintf(buf, sizeof(buf), "%ldk", LONG_MIN / 2000);
  208. assert(r >= 0 && (size_t) r < sizeof(buf));
  209. ok = sc_str_parse_integer_with_suffix(buf, &value);
  210. assert(ok);
  211. assert(value == LONG_MIN / 2000 * 1000);
  212. r = snprintf(buf, sizeof(buf), "%ldm", LONG_MIN / 2000);
  213. assert(r >= 0 && (size_t) r < sizeof(buf));
  214. ok = sc_str_parse_integer_with_suffix(buf, &value);
  215. assert(!ok);
  216. }
  217. static void test_strlist_contains(void) {
  218. assert(sc_str_list_contains("a,bc,def", ',', "bc"));
  219. assert(!sc_str_list_contains("a,bc,def", ',', "b"));
  220. assert(sc_str_list_contains("", ',', ""));
  221. assert(sc_str_list_contains("abc,", ',', ""));
  222. assert(sc_str_list_contains(",abc", ',', ""));
  223. assert(sc_str_list_contains("abc,,def", ',', ""));
  224. assert(!sc_str_list_contains("abc", ',', ""));
  225. assert(sc_str_list_contains(",,|x", '|', ",,"));
  226. assert(sc_str_list_contains("xyz", '\0', "xyz"));
  227. }
  228. static void test_wrap_lines(void) {
  229. const char *s = "This is a text to test line wrapping. The lines must be "
  230. "wrapped at a space or a line break.\n"
  231. "\n"
  232. "This rectangle must remains a rectangle because it is "
  233. "drawn in lines having lengths lower than the specified "
  234. "number of columns:\n"
  235. " +----+\n"
  236. " | |\n"
  237. " +----+\n";
  238. // |---- 1 1 2 2|
  239. // |0 5 0 5 0 3| <-- 24 columns
  240. const char *expected = " This is a text to\n"
  241. " test line wrapping.\n"
  242. " The lines must be\n"
  243. " wrapped at a space\n"
  244. " or a line break.\n"
  245. " \n"
  246. " This rectangle must\n"
  247. " remains a rectangle\n"
  248. " because it is drawn\n"
  249. " in lines having\n"
  250. " lengths lower than\n"
  251. " the specified number\n"
  252. " of columns:\n"
  253. " +----+\n"
  254. " | |\n"
  255. " +----+\n";
  256. char *formatted = sc_str_wrap_lines(s, 24, 4);
  257. assert(formatted);
  258. assert(!strcmp(formatted, expected));
  259. free(formatted);
  260. }
  261. static void test_index_of_column(void) {
  262. assert(sc_str_index_of_column("a bc d", 0, " ") == 0);
  263. assert(sc_str_index_of_column("a bc d", 1, " ") == 2);
  264. assert(sc_str_index_of_column("a bc d", 2, " ") == 6);
  265. assert(sc_str_index_of_column("a bc d", 3, " ") == -1);
  266. assert(sc_str_index_of_column("a ", 0, " ") == 0);
  267. assert(sc_str_index_of_column("a ", 1, " ") == -1);
  268. assert(sc_str_index_of_column("", 0, " ") == 0);
  269. assert(sc_str_index_of_column("", 1, " ") == -1);
  270. assert(sc_str_index_of_column("a \t \t bc \t d\t", 0, " \t") == 0);
  271. assert(sc_str_index_of_column("a \t \t bc \t d\t", 1, " \t") == 8);
  272. assert(sc_str_index_of_column("a \t \t bc \t d\t", 2, " \t") == 15);
  273. assert(sc_str_index_of_column("a \t \t bc \t d\t", 3, " \t") == -1);
  274. assert(sc_str_index_of_column(" a bc d", 1, " ") == 2);
  275. }
  276. static void test_remove_trailing_cr(void) {
  277. char s[] = "abc\r";
  278. sc_str_remove_trailing_cr(s, sizeof(s) - 1);
  279. assert(!strcmp(s, "abc"));
  280. char s2[] = "def\r\r\r\r";
  281. sc_str_remove_trailing_cr(s2, sizeof(s2) - 1);
  282. assert(!strcmp(s2, "def"));
  283. char s3[] = "adb\rdef\r";
  284. sc_str_remove_trailing_cr(s3, sizeof(s3) - 1);
  285. assert(!strcmp(s3, "adb\rdef"));
  286. }
  287. int main(int argc, char *argv[]) {
  288. (void) argc;
  289. (void) argv;
  290. test_strncpy_simple();
  291. test_strncpy_just_fit();
  292. test_strncpy_truncated();
  293. test_join_simple();
  294. test_join_just_fit();
  295. test_join_truncated_in_token();
  296. test_join_truncated_before_sep();
  297. test_join_truncated_after_sep();
  298. test_quote();
  299. test_utf8_truncate();
  300. test_parse_integer();
  301. test_parse_integers();
  302. test_parse_integer_with_suffix();
  303. test_strlist_contains();
  304. test_wrap_lines();
  305. test_index_of_column();
  306. test_remove_trailing_cr();
  307. return 0;
  308. }