finish cleanup
This commit is contained in:
907
3rd/str/str_test.c
Normal file
907
3rd/str/str_test.c
Normal file
@@ -0,0 +1,907 @@
|
||||
/*
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2020,2021,2022,2023,2024 Maxim Konakov and contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
|
||||
#include "str.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <locale.h>
|
||||
|
||||
// make sure assert is always enabled
|
||||
#ifdef NDEBUG
|
||||
#undef NDEBUG
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#define passed printf("passed: %s\n", __func__)
|
||||
|
||||
static
|
||||
void test_str_lit(void)
|
||||
{
|
||||
const str s = str_lit("ZZZ");
|
||||
|
||||
assert(str_len(s) == 3);
|
||||
assert(str_is_ref(s));
|
||||
assert(!str_is_owner(s));
|
||||
assert(str_eq(s, str_lit("ZZZ")));
|
||||
|
||||
passed;
|
||||
}
|
||||
|
||||
static
|
||||
void test_str_cpy(void)
|
||||
{
|
||||
str_auto s = str_null;
|
||||
|
||||
assert(str_cpy(&s, str_lit("ZZZ")) == 0);
|
||||
|
||||
assert(str_len(s) == 3);
|
||||
assert(!str_is_ref(s));
|
||||
assert(str_is_owner(s));
|
||||
assert(str_eq(s, str_lit("ZZZ")));
|
||||
assert(*str_end(s) == 0);
|
||||
|
||||
passed;
|
||||
}
|
||||
|
||||
static
|
||||
void test_str_clear(void)
|
||||
{
|
||||
str s = str_null;
|
||||
|
||||
assert(str_cpy(&s, str_lit("ZZZ")) == 0);
|
||||
|
||||
assert(str_len(s) == 3);
|
||||
assert(str_is_owner(s));
|
||||
assert(*str_end(s) == 0);
|
||||
|
||||
str_clear(&s);
|
||||
|
||||
assert(str_is_empty(s));
|
||||
assert(str_is_ref(s));
|
||||
|
||||
passed;
|
||||
}
|
||||
|
||||
static
|
||||
void test_str_move(void)
|
||||
{
|
||||
str s1 = str_null;
|
||||
|
||||
assert(str_cpy(&s1, str_lit("ZZZ")) == 0);
|
||||
|
||||
str s2 = str_move(&s1);
|
||||
|
||||
assert(str_is_empty(s1));
|
||||
assert(str_is_ref(s1));
|
||||
|
||||
assert(str_is_owner(s2));
|
||||
assert(str_eq(s2, str_lit("ZZZ")));
|
||||
|
||||
str_free(s2);
|
||||
passed;
|
||||
}
|
||||
|
||||
static
|
||||
void test_str_pass(void)
|
||||
{
|
||||
str s1 = str_null;
|
||||
|
||||
assert(str_cpy(&s1, str_lit("ZZZ")) == 0);
|
||||
|
||||
str s2 = str_pass(&s1);
|
||||
|
||||
assert(str_is_ref(s1));
|
||||
assert(str_eq(s1, str_lit("ZZZ")));
|
||||
|
||||
assert(str_is_owner(s2));
|
||||
assert(str_eq(s2, str_lit("ZZZ")));
|
||||
|
||||
str_free(s2);
|
||||
passed;
|
||||
}
|
||||
|
||||
static
|
||||
void test_str_ref(void)
|
||||
{
|
||||
str s = str_ref("ZZZ");
|
||||
|
||||
assert(str_len(s) == 3);
|
||||
assert(str_is_ref(s));
|
||||
|
||||
s = str_ref(s);
|
||||
|
||||
assert(str_is_ref(s));
|
||||
assert(str_eq(s, str_lit("ZZZ")));
|
||||
|
||||
const char* const p = "ZZZ";
|
||||
|
||||
s = str_ref(p);
|
||||
|
||||
assert(str_is_ref(s));
|
||||
assert(str_eq(s, str_lit("ZZZ")));
|
||||
|
||||
passed;
|
||||
}
|
||||
|
||||
static
|
||||
void test_str_cmp(void)
|
||||
{
|
||||
const str_auto s = str_lit("zzz");
|
||||
|
||||
assert(str_cmp(s, s) == 0);
|
||||
assert(str_cmp(s, str_lit("zzz")) == 0);
|
||||
assert(str_cmp(s, str_lit("zz")) > 0);
|
||||
assert(str_cmp(s, str_lit("zzzz")) < 0);
|
||||
assert(str_cmp(s, str_null) > 0);
|
||||
assert(str_cmp(str_null, s) < 0);
|
||||
assert(str_cmp(str_null, str_null) == 0);
|
||||
assert(str_eq(s, str_lit("zzz")));
|
||||
|
||||
passed;
|
||||
}
|
||||
|
||||
static
|
||||
void test_str_cmp_ci(void)
|
||||
{
|
||||
const str s = str_lit("zzz");
|
||||
|
||||
assert(str_cmp_ci(s, s) == 0);
|
||||
assert(str_cmp_ci(s, str_lit("zzz")) == 0);
|
||||
assert(str_cmp_ci(s, str_lit("zz")) > 0);
|
||||
assert(str_cmp_ci(s, str_lit("zzzz")) < 0);
|
||||
assert(str_cmp_ci(s, str_null) > 0);
|
||||
assert(str_cmp_ci(str_null, s) < 0);
|
||||
assert(str_cmp_ci(str_null, str_null) == 0);
|
||||
assert(str_cmp_ci(s, str_lit("ZZZ")) == 0);
|
||||
assert(str_cmp_ci(s, str_lit("ZZ")) > 0);
|
||||
assert(str_cmp_ci(s, str_lit("ZZZZ")) < 0);
|
||||
assert(str_eq_ci(s, str_lit("ZZZ")));
|
||||
|
||||
passed;
|
||||
}
|
||||
|
||||
static
|
||||
void test_str_acquire(void)
|
||||
{
|
||||
str_auto s = str_acquire(strdup("ZZZ"));
|
||||
|
||||
assert(str_is_owner(s));
|
||||
assert(str_eq(s, str_lit("ZZZ")));
|
||||
assert(*str_end(s) == 0);
|
||||
|
||||
passed;
|
||||
}
|
||||
|
||||
static
|
||||
void test_str_cat(void)
|
||||
{
|
||||
str s = str_null;
|
||||
|
||||
assert(str_cat(&s, str_lit("AAA"), str_lit("BBB"), str_lit("CCC")) == 0);
|
||||
|
||||
assert(str_eq(s, str_lit("AAABBBCCC")));
|
||||
assert(str_is_owner(s));
|
||||
assert(*str_end(s) == 0);
|
||||
|
||||
assert(str_cat(&s, str_null, str_null, str_null) == 0); // this simply clears the target string
|
||||
|
||||
assert(str_is_empty(s));
|
||||
assert(str_is_ref(s));
|
||||
|
||||
passed;
|
||||
}
|
||||
|
||||
static
|
||||
void test_str_join(void)
|
||||
{
|
||||
str s = str_null;
|
||||
|
||||
assert(str_join(&s, str_lit("_"), str_lit("AAA"), str_lit("BBB"), str_lit("CCC")) == 0);
|
||||
|
||||
assert(str_eq(s, str_lit("AAA_BBB_CCC")));
|
||||
assert(str_is_owner(s));
|
||||
assert(*str_end(s) == 0);
|
||||
|
||||
assert(str_join(&s, str_lit("_"), str_null, str_lit("BBB"), str_lit("CCC")) == 0);
|
||||
|
||||
assert(str_eq(s, str_lit("_BBB_CCC")));
|
||||
assert(str_is_owner(s));
|
||||
assert(*str_end(s) == 0);
|
||||
|
||||
assert(str_join(&s, str_lit("_"), str_lit("AAA"), str_null, str_lit("CCC")) == 0);
|
||||
|
||||
assert(str_eq(s, str_lit("AAA__CCC")));
|
||||
assert(str_is_owner(s));
|
||||
assert(*str_end(s) == 0);
|
||||
|
||||
assert(str_join(&s, str_lit("_"), str_lit("AAA"), str_lit("BBB"), str_null) == 0);
|
||||
|
||||
assert(str_eq(s, str_lit("AAA_BBB_")));
|
||||
assert(str_is_owner(s));
|
||||
assert(*str_end(s) == 0);
|
||||
|
||||
assert(str_join(&s, str_lit("_"), str_null, str_null, str_null) == 0);
|
||||
|
||||
assert(str_eq(s, str_lit("__")));
|
||||
assert(str_is_owner(s));
|
||||
assert(*str_end(s) == 0);
|
||||
|
||||
assert(str_join(&s, str_null) == 0); // this simply clears the target string
|
||||
|
||||
assert(str_is_empty(s));
|
||||
assert(str_is_ref(s));
|
||||
|
||||
passed;
|
||||
}
|
||||
|
||||
static
|
||||
void test_composition(void)
|
||||
{
|
||||
str_auto s = str_lit(", ");
|
||||
|
||||
assert(str_join(&s, s, str_lit("Here"), str_lit("there"), str_lit("and everywhere")) == 0);
|
||||
assert(str_cat(&s, s, str_lit("...")) == 0);
|
||||
|
||||
assert(str_eq(s, str_lit("Here, there, and everywhere...")));
|
||||
assert(str_is_owner(s));
|
||||
assert(*str_end(s) == 0);
|
||||
|
||||
passed;
|
||||
}
|
||||
|
||||
static
|
||||
void test_sort(void)
|
||||
{
|
||||
str src[] = { str_lit("z"), str_lit("zzz"), str_lit("aaa"), str_lit("bbb") };
|
||||
|
||||
str_sort_range(str_order_asc, src, sizeof(src)/sizeof(src[0]));
|
||||
|
||||
assert(str_eq(src[0], str_lit("aaa")));
|
||||
assert(str_eq(src[1], str_lit("bbb")));
|
||||
assert(str_eq(src[2], str_lit("z")));
|
||||
assert(str_eq(src[3], str_lit("zzz")));
|
||||
|
||||
str_sort_range(str_order_desc, src, sizeof(src)/sizeof(src[0]));
|
||||
|
||||
assert(str_eq(src[0], str_lit("zzz")));
|
||||
assert(str_eq(src[1], str_lit("z")));
|
||||
assert(str_eq(src[2], str_lit("bbb")));
|
||||
assert(str_eq(src[3], str_lit("aaa")));
|
||||
|
||||
passed;
|
||||
}
|
||||
|
||||
static
|
||||
void test_sort_ci(void)
|
||||
{
|
||||
str src[] = { str_lit("ZZZ"), str_lit("zzz"), str_lit("aaa"), str_lit("AAA") };
|
||||
|
||||
str_sort_range(str_order_asc_ci, src, sizeof(src)/sizeof(src[0]));
|
||||
|
||||
assert(str_eq_ci(src[0], str_lit("aaa")));
|
||||
assert(str_eq_ci(src[1], str_lit("aaa")));
|
||||
assert(str_eq_ci(src[2], str_lit("zzz")));
|
||||
assert(str_eq_ci(src[3], str_lit("zzz")));
|
||||
|
||||
str_sort_range(str_order_desc_ci, src, sizeof(src)/sizeof(src[0]));
|
||||
|
||||
assert(str_eq_ci(src[0], str_lit("zzz")));
|
||||
assert(str_eq_ci(src[1], str_lit("zzz")));
|
||||
assert(str_eq_ci(src[2], str_lit("aaa")));
|
||||
assert(str_eq_ci(src[3], str_lit("aaa")));
|
||||
|
||||
passed;
|
||||
}
|
||||
|
||||
static
|
||||
void test_search(void)
|
||||
{
|
||||
str src[] = { str_lit("z"), str_lit("zzz"), str_lit("aaa"), str_lit("bbb") };
|
||||
const size_t count = sizeof(src)/sizeof(src[0]);
|
||||
|
||||
str_sort_range(str_order_asc, src, count);
|
||||
|
||||
assert(str_search_range(src[0], src, count) == &src[0]);
|
||||
assert(str_search_range(src[1], src, count) == &src[1]);
|
||||
assert(str_search_range(src[2], src, count) == &src[2]);
|
||||
assert(str_search_range(src[3], src, count) == &src[3]);
|
||||
assert(str_search_range(str_lit("xxx"), src, count) == NULL);
|
||||
|
||||
passed;
|
||||
}
|
||||
|
||||
static
|
||||
void test_prefix(void)
|
||||
{
|
||||
const str s = str_lit("abcd");
|
||||
|
||||
assert(str_has_prefix(s, str_null));
|
||||
assert(str_has_prefix(s, str_lit("a")));
|
||||
assert(str_has_prefix(s, str_lit("ab")));
|
||||
assert(str_has_prefix(s, str_lit("abc")));
|
||||
assert(str_has_prefix(s, str_lit("abcd")));
|
||||
|
||||
assert(!str_has_prefix(s, str_lit("zzz")));
|
||||
assert(!str_has_prefix(s, str_lit("abcde")));
|
||||
|
||||
passed;
|
||||
}
|
||||
|
||||
static
|
||||
void test_suffix(void)
|
||||
{
|
||||
const str s = str_lit("abcd");
|
||||
|
||||
assert(str_has_suffix(s, str_null));
|
||||
assert(str_has_suffix(s, str_lit("d")));
|
||||
assert(str_has_suffix(s, str_lit("cd")));
|
||||
assert(str_has_suffix(s, str_lit("bcd")));
|
||||
assert(str_has_suffix(s, str_lit("abcd")));
|
||||
|
||||
assert(!str_has_suffix(s, str_lit("zzz")));
|
||||
assert(!str_has_suffix(s, str_lit("_abcd")));
|
||||
|
||||
passed;
|
||||
}
|
||||
|
||||
static
|
||||
void test_cpy_to_fd(void)
|
||||
{
|
||||
FILE* const tmp = tmpfile();
|
||||
|
||||
assert(tmp != NULL);
|
||||
assert(str_cpy(fileno(tmp), str_lit("ZZZ")) == 0);
|
||||
|
||||
rewind(tmp);
|
||||
|
||||
char buff[32];
|
||||
|
||||
assert(fread(buff, 1, sizeof(buff), tmp) == 3);
|
||||
assert(memcmp(buff, "ZZZ", 3) == 0);
|
||||
|
||||
fclose(tmp);
|
||||
passed;
|
||||
}
|
||||
|
||||
static
|
||||
void test_cpy_to_stream(void)
|
||||
{
|
||||
FILE* const tmp = tmpfile();
|
||||
|
||||
assert(tmp != NULL);
|
||||
assert(str_cpy(tmp, str_lit("ZZZ")) == 0);
|
||||
|
||||
assert(fflush(tmp) == 0);
|
||||
rewind(tmp);
|
||||
|
||||
char buff[32];
|
||||
|
||||
assert(fread(buff, 1, sizeof(buff), tmp) == 3);
|
||||
assert(memcmp(buff, "ZZZ", 3) == 0);
|
||||
|
||||
fclose(tmp);
|
||||
passed;
|
||||
}
|
||||
|
||||
static
|
||||
void test_cat_range_to_fd(void)
|
||||
{
|
||||
const str src[] = {
|
||||
str_lit("aaa"),
|
||||
str_lit("bbb"),
|
||||
str_null,
|
||||
str_lit("ccc"),
|
||||
str_lit("ddd"),
|
||||
str_null,
|
||||
str_null
|
||||
};
|
||||
|
||||
const size_t num_items = sizeof(src)/sizeof(src[0]);
|
||||
|
||||
FILE* const tmp = tmpfile();
|
||||
|
||||
assert(tmp != NULL);
|
||||
assert(str_cat_range(fileno(tmp), src, num_items) == 0);
|
||||
|
||||
rewind(tmp);
|
||||
|
||||
const char res[] = "aaabbbcccddd";
|
||||
const size_t len = sizeof(res) - 1;
|
||||
char buff[32];
|
||||
|
||||
assert(fread(buff, 1, sizeof(buff), tmp) == len);
|
||||
assert(memcmp(buff, res, len) == 0);
|
||||
|
||||
fclose(tmp);
|
||||
passed;
|
||||
}
|
||||
|
||||
static
|
||||
void test_cat_large_range_to_fd(void)
|
||||
{
|
||||
// prepare data
|
||||
const size_t n = 100000;
|
||||
str* const src = calloc(n, sizeof(str));
|
||||
|
||||
assert(src != NULL);
|
||||
|
||||
char buff[100];
|
||||
|
||||
for(unsigned i = 0; i < n; i++)
|
||||
assert(str_cpy(&src[i], str_ref_chars(buff, sprintf(buff, "%u\n", i))) == 0);
|
||||
|
||||
// write to file
|
||||
FILE* const tmp = tmpfile();
|
||||
|
||||
assert(tmp != NULL);
|
||||
assert(str_cat_range(fileno(tmp), src, n) == 0);
|
||||
|
||||
// clear input data
|
||||
for(unsigned i = 0; i < n; ++i)
|
||||
str_free(src[i]);
|
||||
|
||||
free(src);
|
||||
|
||||
// validate
|
||||
rewind(tmp);
|
||||
|
||||
char* line = NULL;
|
||||
size_t cap = 0;
|
||||
ssize_t len;
|
||||
int i = 0;
|
||||
|
||||
while((len = getline(&line, &cap, tmp)) >= 0)
|
||||
assert(atoi(line) == i++);
|
||||
|
||||
assert(i == (int)n);
|
||||
|
||||
// all done
|
||||
fclose(tmp);
|
||||
free(line);
|
||||
passed;
|
||||
}
|
||||
|
||||
static
|
||||
void test_cat_range_to_stream(void)
|
||||
{
|
||||
const str src[] = {
|
||||
str_lit("aaa"),
|
||||
str_lit("bbb"),
|
||||
str_null,
|
||||
str_lit("ccc"),
|
||||
str_lit("ddd"),
|
||||
str_null,
|
||||
str_null
|
||||
};
|
||||
|
||||
const size_t num_items = sizeof(src)/sizeof(src[0]);
|
||||
|
||||
FILE* const tmp = tmpfile();
|
||||
|
||||
assert(tmp != NULL);
|
||||
assert(str_cat_range(tmp, src, num_items) == 0);
|
||||
|
||||
assert(fflush(tmp) == 0);
|
||||
rewind(tmp);
|
||||
|
||||
const char res[] = "aaabbbcccddd";
|
||||
const size_t len = sizeof(res) - 1;
|
||||
char buff[32];
|
||||
|
||||
assert(fread(buff, 1, sizeof(buff), tmp) == len);
|
||||
assert(memcmp(buff, res, len) == 0);
|
||||
|
||||
fclose(tmp);
|
||||
passed;
|
||||
}
|
||||
|
||||
static
|
||||
void test_join_to_fd(void)
|
||||
{
|
||||
FILE* const tmp = tmpfile();
|
||||
|
||||
assert(tmp != NULL);
|
||||
assert(str_join(fileno(tmp), str_lit("_"), str_lit("aaa"), str_lit("bbb"), str_lit("ccc")) == 0);
|
||||
|
||||
rewind(tmp);
|
||||
|
||||
const char res[] = "aaa_bbb_ccc";
|
||||
const size_t len = sizeof(res) - 1;
|
||||
char buff[32];
|
||||
|
||||
assert(fread(buff, 1, sizeof(buff), tmp) == len);
|
||||
assert(memcmp(buff, res, len) == 0);
|
||||
|
||||
fclose(tmp);
|
||||
passed;
|
||||
}
|
||||
|
||||
static
|
||||
void test_join_large_range_to_fd(void)
|
||||
{
|
||||
// prepare data
|
||||
const size_t n = 100000;
|
||||
str* const src = calloc(n, sizeof(str));
|
||||
|
||||
assert(src != NULL);
|
||||
|
||||
char buff[100];
|
||||
|
||||
for(unsigned i = 0; i < n; i++)
|
||||
assert(str_cpy(&src[i], str_ref_chars(buff, sprintf(buff, "%u", i))) == 0);
|
||||
|
||||
// write to file
|
||||
FILE* const tmp = tmpfile();
|
||||
|
||||
assert(tmp != NULL);
|
||||
assert(str_join_range(fileno(tmp), str_lit("\n"), src, n) == 0);
|
||||
|
||||
// clear input data
|
||||
for(unsigned i = 0; i < n; ++i)
|
||||
str_free(src[i]);
|
||||
|
||||
free(src);
|
||||
|
||||
// validate
|
||||
rewind(tmp);
|
||||
|
||||
char* line = NULL;
|
||||
size_t cap = 0;
|
||||
ssize_t len;
|
||||
int i = 0;
|
||||
|
||||
while((len = getline(&line, &cap, tmp)) >= 0)
|
||||
assert(atoi(line) == i++);
|
||||
|
||||
assert(i == (int)n);
|
||||
|
||||
// all done
|
||||
fclose(tmp);
|
||||
free(line);
|
||||
passed;
|
||||
}
|
||||
|
||||
static
|
||||
void test_join_to_stream(void)
|
||||
{
|
||||
FILE* const tmp = tmpfile();
|
||||
|
||||
assert(tmp != NULL);
|
||||
assert(str_join(tmp, str_lit("_"), str_lit("aaa"), str_lit("bbb"), str_lit("ccc")) == 0);
|
||||
|
||||
assert(fflush(tmp) == 0);
|
||||
rewind(tmp);
|
||||
|
||||
const char res[] = "aaa_bbb_ccc";
|
||||
const size_t len = sizeof(res) - 1;
|
||||
char buff[32];
|
||||
|
||||
assert(fread(buff, 1, sizeof(buff), tmp) == len);
|
||||
assert(memcmp(buff, res, len) == 0);
|
||||
|
||||
fclose(tmp);
|
||||
passed;
|
||||
}
|
||||
|
||||
static
|
||||
bool part_pred(const str s) { return str_len(s) < 2; }
|
||||
|
||||
static
|
||||
void test_partition_range(void)
|
||||
{
|
||||
str src[] = { str_lit("aaa"), str_lit("a"), str_lit("aaaa"), str_lit("z") };
|
||||
|
||||
assert(str_partition_range(part_pred, src, 1) == 0);
|
||||
|
||||
assert(str_partition_range(part_pred, src, sizeof(src)/sizeof(src[0])) == 2);
|
||||
assert(str_eq(src[0], str_lit("a")));
|
||||
assert(str_eq(src[1], str_lit("z")));
|
||||
assert(str_partition_range(part_pred, src, 1) == 1);
|
||||
|
||||
src[0] = str_lit("?");
|
||||
src[2] = str_lit("*");
|
||||
|
||||
assert(str_partition_range(part_pred, src, sizeof(src)/sizeof(src[0])) == 3);
|
||||
assert(str_eq(src[0], str_lit("?")));
|
||||
assert(str_eq(src[1], str_lit("z")));
|
||||
assert(str_eq(src[2], str_lit("*")));
|
||||
assert(str_eq(src[3], str_lit("aaa")));
|
||||
|
||||
assert(str_partition_range(part_pred, NULL, 42) == 0);
|
||||
assert(str_partition_range(part_pred, src, 0) == 0);
|
||||
|
||||
passed;
|
||||
}
|
||||
|
||||
static
|
||||
void test_unique_range(void)
|
||||
{
|
||||
str src[] = {
|
||||
str_lit("zzz"),
|
||||
str_lit("aaa"),
|
||||
str_lit("zzz"),
|
||||
str_lit("bbb"),
|
||||
str_lit("aaa"),
|
||||
str_lit("ccc"),
|
||||
str_lit("ccc"),
|
||||
str_lit("aaa"),
|
||||
str_lit("ccc"),
|
||||
str_lit("zzz")
|
||||
};
|
||||
|
||||
assert(str_unique_range(src, sizeof(src)/sizeof(src[0])) == 4);
|
||||
assert(str_eq(src[0], str_lit("aaa")));
|
||||
assert(str_eq(src[1], str_lit("bbb")));
|
||||
assert(str_eq(src[2], str_lit("ccc")));
|
||||
assert(str_eq(src[3], str_lit("zzz")));
|
||||
|
||||
passed;
|
||||
}
|
||||
|
||||
static
|
||||
void test_from_file(void)
|
||||
{
|
||||
str_auto fname = str_null;
|
||||
|
||||
assert(str_cat(&fname, str_lit("tmp_"), str_ref_chars(__func__, sizeof(__func__) - 1)) == 0);
|
||||
|
||||
FILE* const stream = fopen(str_ptr(fname), "w");
|
||||
|
||||
assert(stream);
|
||||
assert(str_join(stream, str_lit(" "), str_lit("aaa"), str_lit("bbb"), str_lit("ccc")) == 0);
|
||||
assert(fclose(stream) == 0);
|
||||
|
||||
str_auto res = str_null;
|
||||
|
||||
assert(str_from_file(&res, str_ptr(fname)) == 0);
|
||||
unlink(str_ptr(fname));
|
||||
assert(str_eq(res, str_lit("aaa bbb ccc")));
|
||||
assert(str_is_owner(res));
|
||||
|
||||
// test errors
|
||||
assert(str_from_file(&res, ".") == EISDIR);
|
||||
assert(str_from_file(&res, "/dev/null") == EOPNOTSUPP);
|
||||
assert(str_from_file(&res, "does-not-exist") == ENOENT);
|
||||
|
||||
passed;
|
||||
}
|
||||
|
||||
#ifdef __STDC_UTF_32__
|
||||
|
||||
static
|
||||
void test_codepoint_iterator(void)
|
||||
{
|
||||
const str src = str_lit(u8"жёлтый"); // means "yellow" in Russian
|
||||
static const char32_t src32[] = { U'ж', U'ё', U'л', U'т', U'ы', U'й' };
|
||||
size_t i = 0;
|
||||
char32_t c;
|
||||
|
||||
for_each_codepoint(c, src)
|
||||
{
|
||||
assert(i < sizeof(src32)/sizeof(src32[0]));
|
||||
assert(c == src32[i++]);
|
||||
}
|
||||
|
||||
assert(c == CPI_END_OF_STRING);
|
||||
assert(i == sizeof(src32)/sizeof(src32[0]));
|
||||
|
||||
// empty string iteration
|
||||
c = 0;
|
||||
|
||||
for_each_codepoint(c, str_null)
|
||||
assert(0);
|
||||
|
||||
assert(c == CPI_END_OF_STRING);
|
||||
passed;
|
||||
}
|
||||
|
||||
#endif // ifdef __STDC_UTF_32__
|
||||
|
||||
static
|
||||
void test_tok(void)
|
||||
{
|
||||
typedef struct
|
||||
{
|
||||
const str src, delim;
|
||||
const unsigned n_tok;
|
||||
const str tok[3];
|
||||
} test_data;
|
||||
|
||||
static const test_data t[] =
|
||||
{
|
||||
{
|
||||
str_lit("a,b,c"),
|
||||
str_lit(","),
|
||||
3,
|
||||
{ str_lit("a"), str_lit("b"), str_lit("c") }
|
||||
},
|
||||
{
|
||||
str_lit(",,a,b,,c,"),
|
||||
str_lit(","),
|
||||
3,
|
||||
{ str_lit("a"), str_lit("b"), str_lit("c") }
|
||||
},
|
||||
{
|
||||
str_lit("aaa;=~bbb~,=ccc="),
|
||||
str_lit(",;=~"),
|
||||
3,
|
||||
{ str_lit("aaa"), str_lit("bbb"), str_lit("ccc") }
|
||||
},
|
||||
{
|
||||
str_lit(""),
|
||||
str_lit(","),
|
||||
0,
|
||||
{ }
|
||||
},
|
||||
{
|
||||
str_lit(""),
|
||||
str_lit(""),
|
||||
0,
|
||||
{ }
|
||||
},
|
||||
{
|
||||
str_lit(",.;,.;;.,;.,"),
|
||||
str_lit(",.;"),
|
||||
0,
|
||||
{ }
|
||||
},
|
||||
{
|
||||
str_lit("aaa,bbb,ccc"),
|
||||
str_lit(""),
|
||||
1,
|
||||
{ str_lit("aaa,bbb,ccc") }
|
||||
},
|
||||
{
|
||||
str_lit("aaa,bbb,ccc"),
|
||||
str_lit(";-="),
|
||||
1,
|
||||
{ str_lit("aaa,bbb,ccc") }
|
||||
}
|
||||
};
|
||||
|
||||
for(unsigned i = 0; i < sizeof(t)/sizeof(t[0]); ++i)
|
||||
{
|
||||
unsigned tok_count = 0;
|
||||
|
||||
str tok = str_null;
|
||||
str_tok_state state;
|
||||
|
||||
str_tok_init(&state, t[i].src, t[i].delim);
|
||||
|
||||
while(str_tok(&tok, &state))
|
||||
{
|
||||
// printf("%u-%u: \"%.*s\" %zu\n",
|
||||
// i, tok_count, (int)str_len(tok), str_ptr(tok), str_len(tok));
|
||||
// fflush(stdout);
|
||||
|
||||
assert(tok_count < t[i].n_tok);
|
||||
assert(str_eq(tok, t[i].tok[tok_count]));
|
||||
|
||||
++tok_count;
|
||||
}
|
||||
|
||||
assert(tok_count == t[i].n_tok);
|
||||
}
|
||||
|
||||
passed;
|
||||
}
|
||||
|
||||
static
|
||||
void test_partition(void)
|
||||
{
|
||||
typedef struct
|
||||
{
|
||||
const bool res;
|
||||
const str src, patt, pref, suff;
|
||||
} test_data;
|
||||
|
||||
static const test_data t[] =
|
||||
{
|
||||
{ true, str_lit("...abc..."), str_lit("abc"), str_lit("..."), str_lit("...") },
|
||||
{ true, str_lit("......abc"), str_lit("abc"), str_lit("......"), str_null },
|
||||
{ true, str_lit("abc......"), str_lit("abc"), str_null, str_lit("......") },
|
||||
|
||||
{ true, str_lit("...a..."), str_lit("a"), str_lit("..."), str_lit("...") },
|
||||
{ true, str_lit("......a"), str_lit("a"), str_lit("......"), str_null },
|
||||
{ true, str_lit("a......"), str_lit("a"), str_null, str_lit("......") },
|
||||
|
||||
{ false, str_lit("zzz"), str_null, str_lit("zzz"), str_null },
|
||||
{ false, str_null, str_lit("zzz"), str_null, str_null },
|
||||
{ false, str_null, str_null, str_null, str_null },
|
||||
|
||||
{ false, str_lit("...zzz..."), str_lit("xxx"), str_lit("...zzz..."), str_null },
|
||||
{ false, str_lit("...xxz..."), str_lit("xxx"), str_lit("...xxz..."), str_null },
|
||||
{ true, str_lit("...xxz...xxx."), str_lit("xxx"), str_lit("...xxz..."), str_lit(".") },
|
||||
{ true, str_lit(u8"...цифры___"), str_lit(u8"цифры"), str_lit("..."), str_lit("___") }
|
||||
};
|
||||
|
||||
for(unsigned i = 0; i < sizeof(t)/sizeof(t[0]); ++i)
|
||||
{
|
||||
str pref = str_lit("???"), suff = str_lit("???");
|
||||
|
||||
assert(str_partition(t[i].src, t[i].patt, &pref, &suff) == t[i].res);
|
||||
assert(str_eq(pref, t[i].pref));
|
||||
assert(str_eq(suff, t[i].suff));
|
||||
}
|
||||
|
||||
passed;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// tests
|
||||
test_str_lit();
|
||||
test_str_cpy();
|
||||
test_str_clear();
|
||||
test_str_move();
|
||||
test_str_pass();
|
||||
test_str_ref();
|
||||
test_str_cmp();
|
||||
test_str_cmp_ci();
|
||||
test_str_acquire();
|
||||
test_str_cat();
|
||||
test_str_join();
|
||||
test_composition();
|
||||
test_sort();
|
||||
test_sort_ci();
|
||||
test_search();
|
||||
test_prefix();
|
||||
test_suffix();
|
||||
test_cpy_to_fd();
|
||||
test_cpy_to_stream();
|
||||
test_cat_range_to_fd();
|
||||
test_cat_large_range_to_fd();
|
||||
test_cat_range_to_stream();
|
||||
test_join_to_fd();
|
||||
test_join_large_range_to_fd();
|
||||
test_join_to_stream();
|
||||
test_partition_range();
|
||||
test_unique_range();
|
||||
test_from_file();
|
||||
test_tok();
|
||||
test_partition();
|
||||
|
||||
#ifdef __STDC_UTF_32__
|
||||
assert(setlocale(LC_ALL, "C.UTF-8"));
|
||||
|
||||
test_codepoint_iterator();
|
||||
#endif
|
||||
|
||||
return puts("OK.") < 0;
|
||||
}
|
||||
Reference in New Issue
Block a user