#include #include #include #include "str.h" #include "common.h" static bool str_test_cmp(void) { AL_TEST_START("str_cmp"); str string0 = al_str_c("The Snake"); str string1 = al_str_c("The Rat"); str string2 = al_str_c("The Cat"); str string3 = al_str_c("The Dog"); str string4 = al_str_c("The Snake"); AL_TEST_FALSE(al_str_eq(&string0, &string1)); AL_TEST_FALSE(al_str_eq(&string0, &string2)); AL_TEST_FALSE(al_str_eq(&string0, &string3)); AL_TEST_FALSE(al_str_eq(&string2, &string3)); AL_TEST_TRUE(al_str_eq(&string3, &string3)); AL_TEST_TRUE(al_str_eq(&string4, &string0)); AL_TEST_EQ(al_str_cmp(&string0, &al_str_c("The "), 0, 4), 0, s32); AL_TEST_EQ(al_str_cmp(&string0, &al_str_c(" S"), 3, 2), 0, s32); // Sn[a]ke AL_TEST_LT(al_str_cmp(&string0, &al_str_c("b"), 6, 1), 0, s32); AL_TEST_GT(al_str_cmp(&string0, &al_str_cs(((char[]){ 'a' - 1 })), 6, 1), 0, s32); AL_TEST_EQ(al_str_cmp(&string0, &al_str_c("XX"), 15, 2), -1, s32); AL_TEST_EQ(al_str_cmp(&al_str_c("YY"), &string2, string2.length, 1), -1, s32); AL_TEST_EQ(al_str_cmp(&string2, &al_str_c("ZZ"), 0, string2.length), 1, s32); str string5 = al_str_c("the_database"); str string6 = al_str_c("the_database.json"); AL_TEST_FALSE(al_str_eq(&string6, &string5)); AL_TEST_FALSE(al_str_eq(&string5, &string6)); AL_TEST_END(); } static bool str_test_cat(void) { AL_TEST_START("str_cat"); str result = al_str_c("hygshiylitf"); str string0; al_str_from(&string0, "hyg"); AL_TEST_EQ(string0.length, 3, u32); al_str_cat(&string0, &al_str_c("shiylitf")); AL_TEST_TRUE(al_str_eq(&result, &string0)); al_str_free(&string0); AL_TEST_END(); } static bool str_test_insert(void) { AL_TEST_START("str_insert"); str insert_result = al_str_c("^_-^-^--__-^[insert]_-^--^___"); str prepend_result = al_str_c("[prepend]-^_^_^---^^-__"); str insert_str; al_str_from(&insert_str, "^_-^-^--__-^_-^--^___"); al_str_insert(&insert_str, 12, &al_str_c("[insert]")); AL_TEST_TRUE(al_str_eq(&insert_result, &insert_str)); str prepend_str; al_str_from(&prepend_str, "-^_^_^---^^-__"); al_str_prepend(&prepend_str, &al_str_c("[prepend]")); AL_TEST_TRUE(al_str_eq(&prepend_result, &prepend_str)); al_str_free(&insert_str); al_str_free(&prepend_str); AL_TEST_END(); } static bool str_test_find_rfind(void) { AL_TEST_START("str_find_rfind"); str string0 = al_str_c("wowowow\\$$\\wow"); AL_TEST_EQ(al_str_find(&string0, '\\'), 7, u32); AL_TEST_EQ(al_str_rfind(&string0, '\\'), 10, u32); AL_TEST_EQ(al_str_find(&string0, 'P'), AL_STR_NO_POS, u32); AL_TEST_EQ(al_str_find_str(&string0, &al_str_c("wow\\")), 4, u32); AL_TEST_EQ(al_str_find_str(&string0, &al_str_c("John\\")), AL_STR_NO_POS, u32); AL_TEST_END(); } static bool str_test_substr(void) { AL_TEST_START("str_substr"); str result0 = al_str_c("[cutout0]"); str result1 = al_str_c("[cutout1]"); str s; al_str_from(&s, "88888888[cutout0]999[cutout1]10"); u32 start = al_str_find(&s, '['); u32 end = al_str_find(&s, ']') + 1; str cutout0 = al_str_substr(&s, start, end); str sub = al_str_substr(&s, end, s.length); start = al_str_find(&sub, '['); end = al_str_find(&sub, ']') + 1; str cutout1 = al_str_substr(&sub, start, end); AL_TEST_TRUE(al_str_eq(&result0, &cutout0)); AL_TEST_TRUE(al_str_eq(&result1, &cutout1)); al_str_free(&s); AL_TEST_END(); } static bool str_test_replace_and_remove(void) { AL_TEST_START("str_replace_and_remove"); str string0 = al_str_c("beanie weenies"); str s; al_str_clone(&s, &string0); str result0 = al_str_c("beeneeweee"); al_str_replace(&s, 'a', 'e'); al_str_replace(&s, 'i', 'e'); s.length -= 3; al_str_atr(&s, 1) = 'e'; al_str_remove_at(&s, 6); AL_TEST_TRUE(al_str_eq(&s, &result0)); AL_TEST_END(); } static bool str_test_get_line(void) { AL_TEST_START("str_get_line"); str string0 = al_str_c("Yellow\nmellow\nhello,\nhello\n,\n"); str array0[] = { al_str_c("Yellow"), al_str_c("mellow"), al_str_c("hello,"), al_str_c("hello"), al_str_c(",") }; str string1 = al_str_c("Yellow\nmellow\nhello,\nhello\n,\n "); str array1[] = { al_str_c("Yellow"), al_str_c("mellow"), al_str_c("hello,"), al_str_c("hello"), al_str_c(","), al_str_c(" ") }; str strings[] = { string0, string1 }; str *arrays[] = { array0, array1 }; u32 sizes[] = { ARRAY_SIZE(array0), ARRAY_SIZE(array1) }; for (u32 i = 0; i < ARRAY_SIZE(strings); i++) { u32 counter = 0; str line = al_str_null(); for (; al_str_get_line(&strings[i], '\n', &line); ) { AL_TEST_LT(counter, sizes[i], u32); AL_TEST_TRUE(al_str_eq(&line, &arrays[i][counter++])); } AL_TEST_EQ(counter, sizes[i], u32); counter = 0; line = al_str_null(); // One empty line. for (; al_str_get_line(&al_str_c("\n"), '\n', &line); ) { AL_TEST_LT(counter, 1, u32); AL_TEST_EQ(line.length, 0, u32); counter++; } // No lines. line = al_str_null(); AL_TEST_FALSE(al_str_get_line(&al_str_c(""), '\n', &line)); } AL_TEST_END(); } static bool str_test_to_long(void) { AL_TEST_START("str_to_long"); str string0 = al_str_c("1738"); str string1 = al_str_c("-3563"); str string2 = al_str_c("-2147483647"); // 1 away (32 bit) str string2_1 = al_str_c("-2147483648"); // min (32 bit) str string2_2 = al_str_c("-2147483649"); // underflow (32 bit) str string2_3 = al_str_c("9223372036854775807"); // int64_max str string2_4 = al_str_c("9223372036854775806"); str string2_5 = al_str_c("9223372036854775808"); // overflow str string2_6 = al_str_c("0x7fffffffffffffff"); // int64_max str string2_7 = al_str_c("0x8000000000000000"); // overflow str string2_8 = al_str_c("-0x8000000000000000"); // int64_min str string2_9 = al_str_c("0b111111111111111111111111111111111111111111111111111111111111111"); // int64_max str string2_10 = al_str_c("0b1000000000000000000000000000000000000000000000000000000000000000"); // overflow str string2_11 = al_str_c("-0b1000000000000000000000000000000000000000000000000000000000000000"); // int64_min str string3 = al_str_c("0xfff"); str string4 = al_str_c("0b01010"); str string5 = al_str_c("01010"); str string6 = al_str_c("9999999999999999999999999999999999"); str string7 = al_str_c(" -99999999999999999999"); str string8 = al_str_c("---99999999999999999999"); str string9 = al_str_c("'p[afd'dfdfs[f"); str string10 = al_str_c("\n\t 01010"); str string11 = al_str_c("-9223372036854775809"); str string12 = al_str_c("6519749124957310923"); str string13 = al_str_c("-3519311901742109472"); str string14 = al_str_c("18446744073709551614"); str string15 = al_str_c("-18446744073709551616"); bool error; AL_TEST_EQ(al_str_to_long(&string0, 10, &error), 1738LL, s64); AL_TEST_FALSE(error); AL_TEST_EQ(al_str_to_long(&string1, 10, &error), -3563LL, s64); AL_TEST_FALSE(error); AL_TEST_EQ(al_str_to_long(&string2, 10, &error), -2147483647LL, s64); AL_TEST_FALSE(error); AL_TEST_EQ(al_str_to_long(&string2_1, 10, &error), -2147483648LL, s64); AL_TEST_FALSE(error); AL_TEST_EQ(al_str_to_long(&string2_2, 10, &error), -2147483649LL, s64); AL_TEST_FALSE(error); AL_TEST_EQ(al_str_to_long(&string2_3, 10, &error), INT64_MAX, s64); AL_TEST_FALSE(error); AL_TEST_EQ(al_str_to_long(&string2_4, 10, &error), INT64_MAX - 1, s64); AL_TEST_FALSE(error); al_str_to_long(&string2_5, 10, &error); AL_TEST_TRUE(error); AL_TEST_EQ(al_str_to_long(&string2_6, 16, &error), INT64_MAX, s64); AL_TEST_FALSE(error); al_str_to_long(&string2_7, 16, &error); AL_TEST_TRUE(error); AL_TEST_EQ(al_str_to_long(&string2_8, 16, &error), INT64_MIN, s64); AL_TEST_FALSE(error); AL_TEST_EQ(al_str_to_long(&string2_9, 2, &error), INT64_MAX, s64); AL_TEST_FALSE(error); al_str_to_long(&string2_10, 2, &error); AL_TEST_TRUE(error); AL_TEST_EQ(al_str_to_long(&string2_11, 2, &error), INT64_MIN, s64); AL_TEST_FALSE(error); AL_TEST_EQ(al_str_to_long(&string3, 16, &error), 0xfff, s64); AL_TEST_FALSE(error); AL_TEST_EQ(al_str_to_long(&string4, 2, &error), 0b01010, s64); AL_TEST_FALSE(error); AL_TEST_EQ(al_str_to_long(&string5, 2, &error), 0b01010, s64); AL_TEST_FALSE(error); al_str_to_long(&string6, 10, &error); AL_TEST_TRUE(error); al_str_to_long(&string7, 10, &error); AL_TEST_TRUE(error); al_str_to_long(&string8, 10, &error); AL_TEST_TRUE(error); al_str_to_long(&string9, 10, &error); AL_TEST_TRUE(error); AL_TEST_EQ(al_str_to_long(&string10, 2, &error), 0b01010, s64); AL_TEST_FALSE(error); al_str_to_long(&string11, 10, &error); AL_TEST_TRUE(error); AL_TEST_EQ(al_str_to_long(&string12, 10, &error), 6519749124957310923LL, s64); AL_TEST_FALSE(error); AL_TEST_EQ(al_str_to_long(&string13, 10, &error), -3519311901742109472, s64); AL_TEST_FALSE(error); al_str_to_long(&string14, 10, &error); AL_TEST_TRUE(error); al_str_to_long(&string15, 10, &error); AL_TEST_TRUE(error); AL_TEST_END(); } static bool str_test_to_lower_upper(void) { AL_TEST_START("str_to_lower_upper"); str string0; al_str_from(&string0, "Woopty-dOo"); al_str_to_lower(&string0); AL_TEST_TRUE(al_str_eq(&string0, &al_str_c("woopty-doo"))); al_str_to_upper(&string0); AL_TEST_TRUE(al_str_eq(&string0, &al_str_c("WOOPTY-DOO"))); str string1; al_str_from(&string1, "么造就美好生活? 最长幸福研究的AAAaaaA经验告fff诉你娜塔莉·波特曼演讲"); al_str_to_lower(&string1); AL_TEST_TRUE(al_str_eq(&string1, &al_str_c("么造就美好生活? 最长幸福研究的aaaaaaa经验告fff诉你娜塔莉·波特曼演讲"))); al_str_to_upper(&string1); AL_TEST_TRUE(al_str_eq(&string1, &al_str_c("么造就美好生活? 最长幸福研究的AAAAAAA经验告FFF诉你娜塔莉·波特曼演讲"))); AL_TEST_END(); } // Very non-exhaustive. static bool str_test_limits(void) { AL_TEST_START("str_limits"); str s = al_str_null(); for (u32 i = 0; i < MAX_ALLOC_32 - 1; i++) { al_str_cat(&s, &al_str_c("y")); } al_str_cat(&s, &al_str_c("x")); AL_TEST_TRUE(al_str_atr(&s, 1) == 'x'); AL_TEST_TRUE(al_str_at(&s, MAX_ALLOC_32 - 1) == 'x'); AL_TEST_TRUE(al_str_atr(&s, 2) == 'y'); AL_TEST_END(); } #ifndef _MSC_VER static str global_string = al_str_c("yeeee"); #endif static bool str_test_error_prone_str_c(void) { AL_TEST_START("str_error_prone_str_c"); str n = al_str_c("yoyoyoyoyo"); AL_TEST_EQ(n.length, al_strlen("yoyoyoyoyo"), u32); AL_TEST_EQ(n.alloc, 0, u32); AL_TEST_EQ(al_memcmp(n.data, "yoyoyoyoyo", al_strlen("yoyoyoyoyo") + 1), 0, s32); #ifndef _MSC_VER AL_TEST_TRUE(al_str_eq(&global_string, &al_str_c("yeeee"))); #endif wstr w = al_wstr_c(L"Ayo"); wstr wr = al_wstr_cr(L"Ayo"); AL_TEST_EQ(w.length, al_wcsnlen(L"Ayo", sizeof(L"Ayo") / sizeof(wchar_t)), u32); AL_TEST_EQ(wr.length, 3, u32); AL_TEST_EQ(w.alloc, 0, u32); AL_TEST_EQ(al_memcmp(w.data, L"Ayo", sizeof(L"Ayo")), 0, s32); // This is expected to cause a compile error. #if 0 char *d = al_malloc(26); char *s = "yoyoyoyoyo"; al_memcpy(d, s, strlen(s) + 1); str ds = *al_str_c(d); str ss = *al_str_cr(d); AL_TEST_EQ(ds.length, (u32)(sizeof(char *) - 1), u32); AL_TEST_EQ(ss.length, (u32)al_strlen(s), u32); al_free(d); wchar_t *wd = al_malloc(sizeof(wchar_t) * 26); wchar_t *ws = L"yoyoyoyoyo"; al_memcpy(wd, ws, (wcslen(ws) * sizeof(wchar_t)) + sizeof(wchar_t)); wstr wds = *al_wstr_c(wd); wstr wss = *al_wstr_cr(wd); AL_TEST_EQ(wds.length, (u32)((sizeof(wchar_t *) / sizeof(wchar_t)) - 1), u32); AL_TEST_EQ(wss.length, (u32)wcslen(ws), u32); al_free(wd); str sss = al_str_c(true ? "true" : "never"); wstr www = al_wstr_c(true ? L"false" : L"always"); #endif AL_TEST_END(); } static bool str_test_snprintf_truncate(void) { AL_TEST_START("str_snprintf_truncate"); str s; al_str_sized(&s, 12); u32 num = 1232; const char *st = "wuddup"; s32 expected_length = 12; // If the string is truncated, the return value is how many bytes would have been written. // Meaning if ret = size, the output was truncated by 1 character but will still have a null terminator. // This test is to show we should always expect snprintf to add a null terminator. Meaning there's no // trick we can do for str's in terms of truncating, we just have to make space for an extra null byte. AL_IGNORE_WARNING("-Wformat-truncation") s32 ret = al_snprintf(s.data, expected_length, "%05u_%s", num, st); AL_IGNORE_WARNING_END AL_TEST_EQ(ret, expected_length, s32); s.length = expected_length - 1; AL_TEST_TRUE(al_str_eq(&s, &al_str_c("01232_wuddu"))); AL_TEST_FALSE(al_str_eq(&s, &al_str_c("01232_wuddup"))); al_str_free(&s); AL_TEST_END(); } bool str_tests_run(u32 skip_mask) { AL_TEST_START_GROUP("str"); AL_TEST_RUN(str_test_cmp); AL_TEST_RUN(str_test_cat); AL_TEST_RUN(str_test_insert); AL_TEST_RUN(str_test_find_rfind); AL_TEST_RUN(str_test_substr); AL_TEST_RUN(str_test_replace_and_remove); AL_TEST_RUN(str_test_get_line); AL_TEST_RUN(str_test_to_long); AL_TEST_RUN(str_test_to_lower_upper); if (skip_mask & AL_TESTS_RUN_LIMITS) { AL_TEST_RUN(str_test_limits); } AL_TEST_RUN(str_test_error_prone_str_c); AL_TEST_RUN(str_test_snprintf_truncate); AL_TEST_END_GROUP(); }