#include "config.h"
#include "cunit/cyrunit.h"
#include "prot.h"
#include "xmalloc.h"
#include "util.h"
#include "retry.h"
#include "map.h"
#include "util.h"
#include <sys/mman.h>
static void test_simple(void)
{
#define WORD0 "lorem"
#define WORD1 "ipsum"
struct buf b = BUF_INITIALIZER;
const char *s;
CU_ASSERT_EQUAL(b.len, 0);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT_PTR_NULL(b.s);
buf_appendcstr(&b, WORD0);
buf_putc(&b, ' ');
buf_appendcstr(&b, WORD1);
CU_ASSERT_EQUAL(b.len, sizeof(WORD0)-1+sizeof(WORD1)-1+1);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_PTR_NOT_NULL(b.s);
s = buf_cstring(&b);
CU_ASSERT_EQUAL(b.len, sizeof(WORD0)-1+sizeof(WORD1)-1+1);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_PTR_NOT_NULL(b.s);
CU_ASSERT_PTR_NOT_NULL(s);
CU_ASSERT_STRING_EQUAL(s, WORD0" "WORD1);
buf_free(&b);
#undef WORD0
#undef WORD1
}
static void test_map(void)
{
#define WORD0 "lorem"
#define WORD1 "ipsum"
struct buf b = BUF_INITIALIZER;
const char *map;
size_t len;
CU_ASSERT_EQUAL(b.len, 0);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT_PTR_NULL(b.s);
buf_appendmap(&b, WORD0, sizeof(WORD0)-1);
buf_putc(&b, ' ');
buf_appendmap(&b, WORD1, 2);
CU_ASSERT_EQUAL(b.len, sizeof(WORD0)+2);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_PTR_NOT_NULL(b.s);
map = (void *)0xdeadbeef;
len = 42;
buf_getmap(&b, &map, &len);
CU_ASSERT_EQUAL(b.len, sizeof(WORD0)+2);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT_EQUAL(len, b.len);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_PTR_NOT_NULL(b.s);
CU_ASSERT_PTR_NOT_NULL(map);
CU_ASSERT(!memcmp(map, WORD0" ip", sizeof(WORD0)+2));
buf_free(&b);
#undef WORD0
#undef WORD1
}
static void test_initm(void)
{
struct buf b = BUF_INITIALIZER;
/* data thanks to hipsteripsum.me */
static const char WORD0[] = "terry richardson fanny pack";
char *s = xstrdup(WORD0);
buf_initm(&b, s, sizeof(WORD0)-1);
CU_ASSERT_EQUAL(b.len, sizeof(WORD0)-1);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_PTR_NOT_NULL(b.s);
CU_ASSERT(!memcmp(b.s, WORD0, sizeof(WORD0)-1));
/* we don't free(s) - the buf_free() should do that */
buf_free(&b);
}
static void test_long(void)
{
struct buf b = BUF_INITIALIZER;
int i;
char *exp;
#define SZ 6
#define N 10000
char tt[SZ+1];
CU_ASSERT_EQUAL(b.len, 0);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT_PTR_NULL(b.s);
for (i = 0 ; i < N ; i++) {
snprintf(tt, sizeof(tt), "%c%05d", 'A'+(i%26), i);
buf_appendcstr(&b, tt);
}
buf_cstring(&b);
CU_ASSERT_EQUAL(b.len, SZ*N);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_PTR_NOT_NULL(b.s);
exp = xmalloc(SZ*N+1);
for (i = 0 ; i < N ; i++)
snprintf(exp+SZ*i, SZ+1, "%c%05d", 'A'+(i%26), i);
CU_ASSERT(!strcmp(b.s, exp));
free(exp);
buf_free(&b);
#undef N
#undef SZ
}
static void test_setcstr(void)
{
#define WORD0 "lorem"
struct buf b = BUF_INITIALIZER;
CU_ASSERT_EQUAL(b.len, 0);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT_PTR_NULL(b.s);
buf_setcstr(&b, WORD0);
buf_cstring(&b);
CU_ASSERT_EQUAL(b.len, sizeof(WORD0)-1);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_PTR_NOT_NULL(b.s);
CU_ASSERT_STRING_EQUAL(b.s, WORD0);
buf_free(&b);
#undef WORD0
}
static void test_setmap(void)
{
#define WORD1 "ipsum"
struct buf b = BUF_INITIALIZER;
CU_ASSERT_EQUAL(b.len, 0);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT_PTR_NULL(b.s);
buf_setmap(&b, WORD1, sizeof(WORD1)-1);
buf_cstring(&b);
CU_ASSERT_EQUAL(b.len, sizeof(WORD1)-1);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_PTR_NOT_NULL(b.s);
CU_ASSERT_STRING_EQUAL(b.s, WORD1);
buf_free(&b);
#undef WORD1
}
static void test_append(void)
{
#define WORD0 "lorem"
#define WORD1 "ipsum"
struct buf b = BUF_INITIALIZER;
struct buf b2 = BUF_INITIALIZER;
const char *s;
CU_ASSERT_EQUAL(b.len, 0);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT_PTR_NULL(b.s);
CU_ASSERT_EQUAL(b2.len, 0);
CU_ASSERT(b2.alloc >= b2.len);
CU_ASSERT_EQUAL(buf_len(&b2), b2.len);
CU_ASSERT_PTR_NULL(b2.s);
buf_setmap(&b, WORD0, sizeof(WORD0)-1);
buf_setmap(&b2, WORD1, sizeof(WORD1)-1);
buf_append(&b, &b2);
CU_ASSERT_EQUAL(b.len, sizeof(WORD0)-1+sizeof(WORD1)-1);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_PTR_NOT_NULL(b.s);
s = buf_cstring(&b);
CU_ASSERT_STRING_EQUAL(s, WORD0""WORD1);
CU_ASSERT_EQUAL(b2.len, sizeof(WORD1)-1);
CU_ASSERT_EQUAL(buf_len(&b2), b2.len);
CU_ASSERT(b2.alloc >= b2.len);
CU_ASSERT_PTR_NOT_NULL(b2.s);
s = buf_cstring(&b2);
CU_ASSERT_STRING_EQUAL(s, WORD1);
buf_free(&b);
buf_free(&b2);
#undef WORD0
#undef WORD1
}
static void test_appendbit32(void)
{
#define HEX0 0xcafebabe
#define HEX1 0xdeadbeef
static const unsigned char HEX[8] = {
0xca, 0xfe, 0xba, 0xbe,
0xde, 0xad, 0xbe, 0xef
};
struct buf b = BUF_INITIALIZER;
CU_ASSERT_EQUAL(b.len, 0);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT_PTR_NULL(b.s);
buf_appendbit32(&b, HEX0);
buf_appendbit32(&b, HEX1);
CU_ASSERT_EQUAL(b.len, 8);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_PTR_NOT_NULL(b.s);
CU_ASSERT(!memcmp(b.s, HEX, sizeof(HEX)));
buf_free(&b);
#undef HEX0
#undef HEX1
}
static void test_reset(void)
{
#define WORD0 "lorem"
#define WORD1 "ipsum"
struct buf b = BUF_INITIALIZER;
const char *s;
CU_ASSERT_EQUAL(b.len, 0);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT_PTR_NULL(b.s);
buf_appendcstr(&b, WORD0);
buf_reset(&b);
buf_appendcstr(&b, WORD1);
CU_ASSERT_EQUAL(b.len, sizeof(WORD1)-1);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_PTR_NOT_NULL(b.s);
s = buf_cstring(&b);
CU_ASSERT_PTR_NOT_NULL(s);
CU_ASSERT_STRING_EQUAL(s, WORD1);
buf_free(&b);
#undef WORD0
#undef WORD1
}
static void test_copy(void)
{
#define WORD0 "lorem"
#define WORD1 "ipsum"
struct buf b = BUF_INITIALIZER;
struct buf b2 = BUF_INITIALIZER;
const char *s;
CU_ASSERT_EQUAL(b.len, 0);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT_PTR_NULL(b.s);
CU_ASSERT_EQUAL(b2.len, 0);
CU_ASSERT(b2.alloc >= b2.len);
CU_ASSERT_EQUAL(buf_len(&b2), b2.len);
CU_ASSERT_PTR_NULL(b2.s);
buf_setmap(&b, WORD0, sizeof(WORD0)-1);
buf_setmap(&b2, WORD1, sizeof(WORD1)-1);
buf_copy(&b, &b2);
CU_ASSERT_EQUAL(b.len, sizeof(WORD1)-1);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_PTR_NOT_NULL(b.s);
s = buf_cstring(&b);
CU_ASSERT_STRING_EQUAL(s, WORD1);
CU_ASSERT_EQUAL(b2.len, sizeof(WORD1)-1);
CU_ASSERT_EQUAL(buf_len(&b2), b2.len);
CU_ASSERT(b2.alloc >= b2.len);
CU_ASSERT_PTR_NOT_NULL(b2.s);
s = buf_cstring(&b2);
CU_ASSERT_STRING_EQUAL(s, WORD1);
buf_free(&b);
buf_free(&b2);
#undef WORD0
#undef WORD1
}
static void test_move(void)
{
#define WORD0 "lorem"
#define WORD1 "ipsummma"
struct buf b = BUF_INITIALIZER;
struct buf b2 = BUF_INITIALIZER;
const char *s;
CU_ASSERT_EQUAL(b.len, 0);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT_PTR_NULL(b.s);
CU_ASSERT_EQUAL(b2.len, 0);
CU_ASSERT(b2.alloc >= b2.len);
CU_ASSERT_EQUAL(buf_len(&b2), b2.len);
CU_ASSERT_PTR_NULL(b2.s);
buf_setmap(&b, WORD0, sizeof(WORD0)-1);
buf_setmap(&b2, WORD1, sizeof(WORD1)-1);
buf_move(&b, &b2);
CU_ASSERT_EQUAL(b.len, sizeof(WORD1)-1);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_PTR_NOT_NULL(b.s);
s = buf_cstring(&b);
CU_ASSERT_STRING_EQUAL(s, WORD1);
CU_ASSERT_EQUAL(b2.len, 0);
CU_ASSERT_EQUAL(buf_len(&b2), b2.len);
CU_ASSERT_EQUAL(b2.alloc, 0);
CU_ASSERT_PTR_NULL(b2.s);
buf_free(&b);
buf_free(&b2);
#undef WORD0
#undef WORD1
}
static void test_printf(void)
{
#define WORD0 "lorem"
#define WORD1 "ipsum"
#define DEC0 31337
#define HEX0 0xcafebabe
struct buf b = BUF_INITIALIZER;
const char *s;
CU_ASSERT_EQUAL(b.len, 0);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT_PTR_NULL(b.s);
buf_printf(&b, WORD0" %s 0x%x %d", WORD1, HEX0, DEC0);
CU_ASSERT_EQUAL(b.len, sizeof(WORD0)+sizeof(WORD1)+16);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_PTR_NOT_NULL(b.s);
s = buf_cstring(&b);
CU_ASSERT_PTR_NOT_NULL(s);
CU_ASSERT_STRING_EQUAL(s, WORD0" "WORD1" 0xcafebabe 31337");
buf_free(&b);
#undef WORD0
#undef WORD1
#undef DEC0
#undef HEX0
}
static void test_long_printf(void)
{
struct buf b = BUF_INITIALIZER;
int i;
const char *s;
char *exp;
#define SZ 6
#define N 10000
CU_ASSERT_EQUAL(b.len, 0);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT_PTR_NULL(b.s);
exp = xmalloc(SZ*N+1);
for (i = 0 ; i < N ; i++)
snprintf(exp+SZ*i, SZ+1, "%c%05d", 'A'+(i%26), i);
buf_printf(&b, "x%sy", exp);
s = buf_cstring(&b);
CU_ASSERT_EQUAL(b.len, SZ*N+2);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_PTR_NOT_NULL(b.s);
CU_ASSERT_PTR_NOT_NULL(s);
CU_ASSERT_EQUAL(s[0], 'x');
CU_ASSERT(!memcmp(s+1, exp, SZ*N));
CU_ASSERT_EQUAL(s[SZ*N+1], 'y');
buf_free(&b);
free(exp);
#undef N
#undef SZ
}
static void test_replace_all(void)
{
#define WORD0 "lorem"
#define WORD0REP "LAUREN BACALL"
#define WORD0REP2 "L0R3M"
#define WORD0REP3 "LRM"
#define WORD0REP4 "XloremY"
#define WORD1 "ipsum"
#define WORD1 "ipsum"
#define WORD2 "dolor"
#define WORD3 "sit"
#define WORD4 "amet"
struct buf b = BUF_INITIALIZER;
unsigned int n;
char *buf_s;
CU_ASSERT_EQUAL(b.len, 0);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT_PTR_NULL(b.s);
/* simple test: a single replacement */
buf_reset(&b);
buf_appendcstr(&b, WORD0" "WORD1);
buf_cstring(&b);
CU_ASSERT_EQUAL(b.len, sizeof(WORD0" "WORD1)-1);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_PTR_NOT_NULL(b.s);
CU_ASSERT_STRING_EQUAL(b.s, WORD0" "WORD1);
n = buf_replace_all(&b, WORD0, WORD0REP);
CU_ASSERT_EQUAL(n, 1);
CU_ASSERT_EQUAL(b.len, sizeof(WORD0REP" "WORD1)-1);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_PTR_NOT_NULL(b.s);
CU_ASSERT_STRING_EQUAL(b.s, WORD0REP" "WORD1);
/* simple test: failure to match */
buf_reset(&b);
buf_appendcstr(&b, WORD0" "WORD1);
buf_cstring(&b);
CU_ASSERT_EQUAL(b.len, sizeof(WORD0" "WORD1)-1);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_PTR_NOT_NULL(b.s);
CU_ASSERT_STRING_EQUAL(b.s, WORD0" "WORD1);
n = buf_replace_all(&b, WORD4, WORD0REP);
CU_ASSERT_EQUAL(n, 0);
CU_ASSERT_EQUAL(b.len, sizeof(WORD0" "WORD1)-1);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_PTR_NOT_NULL(b.s);
CU_ASSERT_STRING_EQUAL(b.s, WORD0" "WORD1);
/* a replacement which doesn't change the size */
buf_reset(&b);
buf_appendcstr(&b, WORD0" "WORD1);
buf_cstring(&b);
CU_ASSERT_EQUAL(b.len, sizeof(WORD0" "WORD1)-1);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_PTR_NOT_NULL(b.s);
CU_ASSERT_STRING_EQUAL(b.s, WORD0" "WORD1);
buf_s = b.s;
n = buf_replace_all(&b, WORD0, WORD0REP2);
CU_ASSERT_EQUAL(n, 1);
CU_ASSERT_EQUAL(b.len, sizeof(WORD0REP2" "WORD1)-1);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_PTR_NOT_NULL(b.s);
CU_ASSERT_PTR_EQUAL(b.s, buf_s); /* no size change => no realloc */
CU_ASSERT_STRING_EQUAL(b.s, WORD0REP2" "WORD1);
/* a replacement which shrinks the size */
buf_reset(&b);
buf_appendcstr(&b, WORD0" "WORD1);
buf_cstring(&b);
CU_ASSERT_EQUAL(b.len, sizeof(WORD0" "WORD1)-1);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_PTR_NOT_NULL(b.s);
CU_ASSERT_STRING_EQUAL(b.s, WORD0" "WORD1);
/* a replacement with an empty string */
buf_reset(&b);
buf_appendcstr(&b, WORD0" "WORD1);
buf_cstring(&b);
CU_ASSERT_EQUAL(b.len, sizeof(WORD0" "WORD1)-1);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_PTR_NOT_NULL(b.s);
CU_ASSERT_STRING_EQUAL(b.s, WORD0" "WORD1);
buf_s = b.s;
n = buf_replace_all(&b, WORD0, "");
CU_ASSERT_EQUAL(n, 1);
CU_ASSERT_EQUAL(b.len, sizeof(" "WORD1)-1);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_PTR_NOT_NULL(b.s);
CU_ASSERT_PTR_EQUAL(b.s, buf_s); /* no size change => no realloc */
CU_ASSERT_STRING_EQUAL(b.s, " "WORD1);
/* a replacement with a NULL string */
buf_reset(&b);
buf_appendcstr(&b, WORD0" "WORD1);
buf_cstring(&b);
CU_ASSERT_EQUAL(b.len, sizeof(WORD0" "WORD1)-1);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_PTR_NOT_NULL(b.s);
CU_ASSERT_STRING_EQUAL(b.s, WORD0" "WORD1);
buf_s = b.s;
n = buf_replace_all(&b, WORD0, NULL);
CU_ASSERT_EQUAL(n, 1);
CU_ASSERT_EQUAL(b.len, sizeof(" "WORD1)-1);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_PTR_NOT_NULL(b.s);
CU_ASSERT_PTR_EQUAL(b.s, buf_s); /* no size change => no realloc */
CU_ASSERT_STRING_EQUAL(b.s, " "WORD1);
/* multiple replacements, including abutted ones */
buf_reset(&b);
buf_appendcstr(&b, WORD0" "WORD1" "WORD2" "WORD0" "WORD3" "WORD0""WORD0" "WORD4);
buf_cstring(&b);
CU_ASSERT_EQUAL(b.len, sizeof(WORD0" "WORD1" "WORD2" "WORD0" "WORD3" "WORD0""WORD0" "WORD4)-1);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_PTR_NOT_NULL(b.s);
CU_ASSERT_STRING_EQUAL(b.s, WORD0" "WORD1" "WORD2" "WORD0" "WORD3" "WORD0""WORD0" "WORD4);
n = buf_replace_all(&b, WORD0, WORD0REP2);
CU_ASSERT_EQUAL(n, 4);
CU_ASSERT_EQUAL(b.len, sizeof(WORD0REP2" "WORD1" "WORD2" "WORD0REP2" "WORD3" "WORD0REP2""WORD0REP2" "WORD4)-1);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_PTR_NOT_NULL(b.s);
CU_ASSERT_STRING_EQUAL(b.s, WORD0REP2" "WORD1" "WORD2" "WORD0REP2" "WORD3" "WORD0REP2""WORD0REP2" "WORD4);
/* multiple replacements with a replacement which contains the match */
buf_reset(&b);
buf_appendcstr(&b, WORD0" "WORD1" "WORD2" "WORD0" "WORD3" "WORD0""WORD0" "WORD4);
buf_cstring(&b);
CU_ASSERT_EQUAL(b.len, sizeof(WORD0" "WORD1" "WORD2" "WORD0" "WORD3" "WORD0""WORD0" "WORD4)-1);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_PTR_NOT_NULL(b.s);
CU_ASSERT_STRING_EQUAL(b.s, WORD0" "WORD1" "WORD2" "WORD0" "WORD3" "WORD0""WORD0" "WORD4);
n = buf_replace_all(&b, WORD0, WORD0REP4);
CU_ASSERT_EQUAL(n, 4);
CU_ASSERT_EQUAL(b.len, sizeof(WORD0REP4" "WORD1" "WORD2" "WORD0REP4" "WORD3" "WORD0REP4""WORD0REP4" "WORD4)-1);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_PTR_NOT_NULL(b.s);
CU_ASSERT_STRING_EQUAL(b.s, WORD0REP4" "WORD1" "WORD2" "WORD0REP4" "WORD3" "WORD0REP4""WORD0REP4" "WORD4);
buf_free(&b);
#undef WORD0
#undef WORD0REP
#undef WORD0REP2
#undef WORD0REP3
#undef WORD0REP4
#undef WORD1
#undef WORD2
#undef WORD3
#undef WORD4
}
/* we use buf_init_ro() instead of buf_appendcstr() to test
* the case where the input buffer is not a C string before
* calling buf_replace_*() */
#define TESTCASE_START(in, reg, rep, expn, exp) \
{ \
static const char _in[] = in; \
static const char _reg[] = reg; \
static const char *_rep = rep; \
static const int _expn = expn; \
static const char _exp[] = exp; \
struct buf b = BUF_INITIALIZER; \
regex_t re; \
unsigned int n; \
int r; \
\
buf_init_ro(&b, _in, sizeof(_in)-1); \
CU_ASSERT_EQUAL(b.len, sizeof(_in)-1); \
CU_ASSERT_EQUAL(buf_len(&b), b.len); \
CU_ASSERT_PTR_NOT_NULL(b.s); \
CU_ASSERT_STRING_EQUAL(b.s, _in); \
\
r = regcomp(&re, _reg, REG_EXTENDED); \
CU_ASSERT_EQUAL(r, 0);
#define TESTCASE_MIDDLE \
n = buf_replace_one_re(&b, &re, _rep);
#define TESTCASE_END \
CU_ASSERT_EQUAL(n, _expn); \
CU_ASSERT_EQUAL(b.len, sizeof(_exp)-1); \
CU_ASSERT_EQUAL(buf_len(&b), b.len); \
CU_ASSERT(b.alloc >= b.len); \
CU_ASSERT_PTR_NOT_NULL(b.s); \
CU_ASSERT_STRING_EQUAL(b.s, _exp); \
regfree(&re); \
buf_free(&b); \
}
#define TESTCASE(in, reg, rep, expn, exp) \
TESTCASE_START(in, reg, rep, expn, exp) \
TESTCASE_MIDDLE \
TESTCASE_END
static void test_replace_one_re(void)
{
/* data thanks to hipsteripsum.me */
#define WORD0 "bespoke"
#define WORD0_RE "be[a-df-z]+e"
#define WORD0REP "butcher"
#define WORD0REP2 "BeSp0K3"
#define WORD0REP3 "BpK"
#define WORD0REP4 "XbespokeY"
#define WORD1 "tattooed"
#define WORD2 "fap"
#define WORD3 "keffiyeh"
#define WORD4 "biodiesel"
#define WORD4_RE "[a-z]iod[a-z]+"
const char *buf_s;
/* simple test: a single replacement */
TESTCASE(WORD0" "WORD1,
WORD0_RE, WORD0REP,
1, WORD0REP" "WORD1);
/* simple test: failure to match */
TESTCASE_START(WORD0" "WORD1,
WORD4_RE, WORD0REP,
0, WORD0" "WORD1);
TESTCASE_MIDDLE
buf_cstring(&b);
TESTCASE_END
/* a replacement which doesn't change the size */
TESTCASE_START(WORD0" "WORD1,
WORD0_RE, WORD0REP2,
1, WORD0REP2" "WORD1);
buf_s = buf_cstring(&b);
TESTCASE_MIDDLE
CU_ASSERT_PTR_EQUAL(buf_cstring(&b), buf_s); /* no size change => no realloc */
TESTCASE_END
/* a replacement which shrinks the size */
TESTCASE_START(WORD0" "WORD1,
WORD0_RE, WORD0REP3,
1, WORD0REP3" "WORD1);
buf_s = buf_cstring(&b);
TESTCASE_MIDDLE
CU_ASSERT_PTR_EQUAL(buf_cstring(&b), buf_s); /* no size change => no realloc */
TESTCASE_END
/* a replacement with an empty string */
TESTCASE(WORD0" "WORD1,
WORD0_RE, "",
1, " "WORD1);
/* a replacement with a NULL string */
TESTCASE(WORD0" "WORD1,
WORD0_RE, NULL,
1, " "WORD1);
/* multiple matches, including abutted ones */
TESTCASE(WORD0" "WORD1" "WORD2" "WORD0" "WORD3" "WORD0""WORD0" "WORD4,
WORD0_RE, WORD0REP2,
1, WORD0REP2" "WORD1" "WORD2" "WORD0" "WORD3" "WORD0""WORD0" "WORD4);
/* multiple matches with a replacement which contains the match */
TESTCASE(WORD0" "WORD1" "WORD2" "WORD0" "WORD3" "WORD0""WORD0" "WORD4,
WORD0_RE, WORD0REP4,
1, WORD0REP4" "WORD1" "WORD2" "WORD0" "WORD3" "WORD0""WORD0" "WORD4);
#undef WORD0
#undef WORD0REP
#undef WORD0REP2
#undef WORD0REP3
#undef WORD0REP4
#undef WORD1
#undef WORD2
#undef WORD3
#undef WORD4
}
#undef TESTCASE_MIDDLE
#define TESTCASE_MIDDLE \
n = buf_replace_all_re(&b, &re, _rep);
static void test_replace_all_re(void)
{
/* data thanks to hipsteripsum.me */
#define WORD0 "bespoke"
#define WORD0_RE "be[a-df-z]+e"
#define WORD0REP "butcher"
#define WORD0REP2 "BeSp0K3"
#define WORD0REP3 "BpK"
#define WORD0REP4 "XbespokeY"
#define WORD1 "tattooed"
#define WORD2 "fap"
#define WORD3 "keffiyeh"
#define WORD4 "biodiesel"
#define WORD4_RE "[a-z]iod[a-z]+"
const char *buf_s;
/* simple test: a single replacement */
TESTCASE(WORD0" "WORD1,
WORD0_RE, WORD0REP,
1, WORD0REP" "WORD1);
/* simple test: failure to match */
TESTCASE_START(WORD0" "WORD1,
WORD4_RE, WORD0REP,
0, WORD0" "WORD1);
TESTCASE_MIDDLE
buf_cstring(&b);
TESTCASE_END
/* a replacement which doesn't change the size */
TESTCASE_START(WORD0" "WORD1,
WORD0_RE, WORD0REP2,
1, WORD0REP2" "WORD1);
buf_s = buf_cstring(&b);
TESTCASE_MIDDLE
CU_ASSERT_PTR_EQUAL(buf_cstring(&b), buf_s); /* no size change => no realloc */
TESTCASE_END
/* a replacement which shrinks the size */
TESTCASE_START(WORD0" "WORD1,
WORD0_RE, WORD0REP3,
1, WORD0REP3" "WORD1);
buf_s = buf_cstring(&b);
TESTCASE_MIDDLE
CU_ASSERT_PTR_EQUAL(buf_cstring(&b), buf_s); /* no size change => no realloc */
TESTCASE_END
/* a replacement with an empty string */
TESTCASE(WORD0" "WORD1,
WORD0_RE, "",
1, " "WORD1);
/* a replacement with a NULL string */
TESTCASE(WORD0" "WORD1,
WORD0_RE, NULL,
1, " "WORD1);
/* multiple matches, including abutted ones */
TESTCASE(WORD0" "WORD1" "WORD2" "WORD0" "WORD3" "WORD0""WORD0" "WORD4,
WORD0_RE, WORD0REP2,
4, WORD0REP2" "WORD1" "WORD2" "WORD0REP2" "WORD3" "WORD0REP2""WORD0REP2" "WORD4);
/* multiple matches with a replacement which contains the match */
TESTCASE(WORD0" "WORD1" "WORD2" "WORD0" "WORD3" "WORD0""WORD0" "WORD4,
WORD0_RE, WORD0REP4,
4, WORD0REP4" "WORD1" "WORD2" "WORD0REP4" "WORD3" "WORD0REP4""WORD0REP4" "WORD4);
#undef WORD0
#undef WORD0REP
#undef WORD0REP2
#undef WORD0REP3
#undef WORD0REP4
#undef WORD1
#undef WORD2
#undef WORD3
#undef WORD4
}
#undef TESTCASE_START
#undef TESTCASE_MIDDLE
#undef TESTCASE_END
#undef TESTCASE
#define TESTCASE(in, off, rep, exp) \
{ \
static const char _in[] = in; \
int _off = off; \
static const char _rep[] = rep; \
static const char _exp[] = exp; \
struct buf b = BUF_INITIALIZER; \
\
buf_appendcstr(&b, _in); \
buf_cstring(&b); \
CU_ASSERT_EQUAL(b.len, sizeof(_in)-1); \
CU_ASSERT_PTR_NOT_NULL(b.s); \
CU_ASSERT_STRING_EQUAL(b.s, _in); \
\
buf_insertcstr(&b, _off, _rep); \
CU_ASSERT_EQUAL(b.len, sizeof(_exp)-1); \
CU_ASSERT(b.alloc >= b.len); \
buf_cstring(&b); \
CU_ASSERT_PTR_NOT_NULL(b.s); \
CU_ASSERT_STRING_EQUAL(b.s, _exp); \
buf_free(&b); \
}
static void test_insertcstr(void)
{
/* data thanks to hipsteripsum.me */
#define WORD0 "gastropub"
#define WORD1 "vegan brunch"
#define WORD2 "portland"
TESTCASE(WORD0" "WORD2,
0, WORD1"\t",
WORD1"\t"WORD0" "WORD2);
TESTCASE(WORD0" "WORD2,
sizeof(WORD0)-1, "\t"WORD1,
WORD0"\t"WORD1" "WORD2);
TESTCASE(WORD0" "WORD2,
sizeof(WORD0" "WORD2)-1, "\t"WORD1,
WORD0" "WORD2"\t"WORD1);
TESTCASE("",
0, WORD1,
WORD1);
TESTCASE("",
1, WORD1,
"");
#undef WORD0
#undef WORD1
#undef WORD2
}
#undef TESTCASE
#define TESTCASE(in, off, rep, exp) \
{ \
static const char _in[] = in; \
int _off = off; \
static const char _rep[] = rep; \
static const char _exp[] = exp; \
struct buf b = BUF_INITIALIZER; \
\
buf_appendcstr(&b, _in); \
buf_cstring(&b); \
CU_ASSERT_EQUAL(b.len, sizeof(_in)-1); \
CU_ASSERT_PTR_NOT_NULL(b.s); \
CU_ASSERT_STRING_EQUAL(b.s, _in); \
\
buf_insertmap(&b, _off, _rep, sizeof(_rep)-1); \
CU_ASSERT_EQUAL(b.len, sizeof(_exp)-1); \
CU_ASSERT(b.alloc >= b.len); \
buf_cstring(&b); \
CU_ASSERT_PTR_NOT_NULL(b.s); \
CU_ASSERT_STRING_EQUAL(b.s, _exp); \
buf_free(&b); \
}
static void test_insertmap(void)
{
/* data thanks to hipsteripsum.me */
#define WORD0 "gastropub"
#define WORD1 "vegan brunch"
#define WORD2 "portland"
TESTCASE(WORD0" "WORD2,
0, WORD1"\t",
WORD1"\t"WORD0" "WORD2);
TESTCASE(WORD0" "WORD2,
sizeof(WORD0)-1, "\t"WORD1,
WORD0"\t"WORD1" "WORD2);
TESTCASE(WORD0" "WORD2,
sizeof(WORD0" "WORD2)-1, "\t"WORD1,
WORD0" "WORD2"\t"WORD1);
TESTCASE("",
0, WORD1,
WORD1);
TESTCASE("",
1, WORD1,
"");
#undef WORD0
#undef WORD1
#undef WORD2
}
#undef TESTCASE
#define TESTCASE(in, off, rep, exp) \
{ \
static const char _in[] = in; \
int _off = off; \
static const char _rep[] = rep; \
struct buf _repb = BUF_INITIALIZER; \
static const char _exp[] = exp; \
struct buf b = BUF_INITIALIZER; \
\
buf_appendmap(&_repb, _rep, sizeof(_rep)-1); \
\
buf_appendcstr(&b, _in); \
buf_cstring(&b); \
CU_ASSERT_EQUAL(b.len, sizeof(_in)-1); \
CU_ASSERT_PTR_NOT_NULL(b.s); \
CU_ASSERT_STRING_EQUAL(b.s, _in); \
\
buf_insert(&b, _off, &_repb); \
CU_ASSERT_EQUAL(b.len, sizeof(_exp)-1); \
CU_ASSERT(b.alloc >= b.len); \
buf_cstring(&b); \
CU_ASSERT_PTR_NOT_NULL(b.s); \
CU_ASSERT_STRING_EQUAL(b.s, _exp); \
buf_free(&b); \
buf_free(&_repb); \
}
static void test_insert(void)
{
/* data thanks to hipsteripsum.me */
#define WORD0 "gastropub"
#define WORD1 "brunch"
#define WORD2 "portland"
TESTCASE(WORD0" "WORD2,
0, WORD1"\t",
WORD1"\t"WORD0" "WORD2);
TESTCASE(WORD0" "WORD2,
sizeof(WORD0)-1, "\t"WORD1,
WORD0"\t"WORD1" "WORD2);
TESTCASE(WORD0" "WORD2,
sizeof(WORD0" "WORD2)-1, "\t"WORD1,
WORD0" "WORD2"\t"WORD1);
TESTCASE("",
0, WORD1,
WORD1);
TESTCASE("",
1, WORD1,
"");
#undef WORD0
#undef WORD1
#undef WORD2
}
#undef TESTCASE
#define TESTCASE(in, off, xlen, exp) \
{ \
static const char _in[] = in; \
int _off = off; \
int _len = xlen; \
static const char _exp[] = exp; \
struct buf b = BUF_INITIALIZER; \
\
buf_appendcstr(&b, _in); \
buf_cstring(&b); \
CU_ASSERT_EQUAL(b.len, sizeof(_in)-1); \
CU_ASSERT_PTR_NOT_NULL(b.s); \
CU_ASSERT_STRING_EQUAL(b.s, _in); \
\
buf_remove(&b, _off, _len); \
CU_ASSERT_EQUAL(b.len, sizeof(_exp)-1); \
CU_ASSERT(b.alloc >= b.len); \
buf_cstring(&b); \
CU_ASSERT_PTR_NOT_NULL(b.s); \
CU_ASSERT_STRING_EQUAL(b.s, _exp); \
buf_free(&b); \
}
static void test_remove(void)
{
/* data thanks to hipsteripsum.me */
#define WORD0 "fingerstache"
#define WORD1 "scenester"
#define WORD2 "ennui"
TESTCASE(WORD0" "WORD1"\t"WORD2,
0, sizeof(WORD0),
WORD1"\t"WORD2);
TESTCASE(WORD0" "WORD1"\t"WORD2,
0, 0,
WORD0" "WORD1"\t"WORD2);
TESTCASE(WORD0" "WORD1"\t"WORD2,
sizeof(WORD0), sizeof(WORD1),
WORD0" "WORD2);
TESTCASE(WORD0" "WORD1"\t"WORD2,
sizeof(WORD0)+sizeof(WORD1), sizeof(WORD2)-1,
WORD0" "WORD1"\t");
TESTCASE(WORD0" "WORD1"\t"WORD2,
sizeof(WORD0)+sizeof(WORD1), sizeof(WORD2)-1+20,
WORD0" "WORD1"\t");
TESTCASE(WORD0" "WORD1"\t"WORD2,
0, sizeof(WORD0" "WORD1"\t"WORD2)-1,
"");
TESTCASE("",
0, 1,
"");
#undef WORD0
#undef WORD1
#undef WORD2
}
#undef TESTCASE
static void test_truncate(void)
{
#define WORD0 "lorem"
#define WORD1 "ipsum"
struct buf b = BUF_INITIALIZER;
unsigned int i;
CU_ASSERT_EQUAL(b.len, 0);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT_PTR_NULL(b.s);
/* buf_truncate() which shortens the buffer */
buf_reset(&b);
buf_appendcstr(&b, WORD0" "WORD1);
buf_cstring(&b);
CU_ASSERT_EQUAL(b.len, sizeof(WORD0" "WORD1)-1);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_PTR_NOT_NULL(b.s);
CU_ASSERT_STRING_EQUAL(b.s, WORD0" "WORD1);
buf_truncate(&b, sizeof(WORD0)-1);
buf_cstring(&b);
CU_ASSERT_EQUAL(b.len, sizeof(WORD0)-1);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_PTR_NOT_NULL(b.s);
CU_ASSERT_STRING_EQUAL(b.s, WORD0);
/* buf_truncate() which extends and zero-fills the buffer */
buf_reset(&b);
buf_appendcstr(&b, WORD0" "WORD1);
buf_cstring(&b);
CU_ASSERT_EQUAL(b.len, sizeof(WORD0" "WORD1)-1);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_PTR_NOT_NULL(b.s);
CU_ASSERT_STRING_EQUAL(b.s, WORD0" "WORD1);
buf_truncate(&b, sizeof(WORD0" "WORD1)-1+2048);
buf_cstring(&b);
CU_ASSERT_EQUAL(b.len, sizeof(WORD0" "WORD1)-1+2048);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_PTR_NOT_NULL(b.s);
CU_ASSERT_STRING_EQUAL(b.s, WORD0" "WORD1);
for (i=sizeof(WORD0" "WORD1)-1; i<sizeof(WORD0" "WORD1)-1+2048 ; i++)
if (b.s[i] != 0)
break;
CU_ASSERT_EQUAL(i, sizeof(WORD0" "WORD1)-1+2048);
buf_free(&b);
#undef WORD0
#undef WORD1
}
static void test_cmp(void)
{
/* words chosen to be in alphabetical order */
#define WORD0 "alpha"
#define WORD0SUB "alp"
#define WORD1 "omega"
struct buf a = BUF_INITIALIZER;
struct buf b = BUF_INITIALIZER;
int d;
/* compare two empty (null) bufs */
CU_ASSERT_PTR_NULL(a.s);
CU_ASSERT_EQUAL(a.len, 0);
CU_ASSERT_PTR_NULL(b.s);
CU_ASSERT_EQUAL(b.len, 0);
d = buf_cmp(&a, &b);
CU_ASSERT_EQUAL(d, 0);
d = buf_cmp(&b, &a);
CU_ASSERT_EQUAL(d, 0);
/* compare empty (null) vs empty (zero-length) */
buf_appendcstr(&b, "foo");
buf_truncate(&b, 0);
CU_ASSERT_PTR_NULL(a.s);
CU_ASSERT_EQUAL(a.len, 0);
CU_ASSERT_PTR_NOT_NULL(b.s);
CU_ASSERT_EQUAL(b.len, 0);
d = buf_cmp(&a, &b);
CU_ASSERT_EQUAL(d, 0);
d = buf_cmp(&b, &a);
CU_ASSERT_EQUAL(d, 0);
/* compare identical strings */
buf_reset(&a);
buf_appendcstr(&a, WORD0);
buf_reset(&b);
buf_appendcstr(&b, WORD0);
CU_ASSERT_PTR_NOT_NULL(a.s);
CU_ASSERT_EQUAL(a.len, sizeof(WORD0)-1);
CU_ASSERT_PTR_NOT_NULL(b.s);
CU_ASSERT_EQUAL(b.len, sizeof(WORD0)-1);
d = buf_cmp(&a, &b);
CU_ASSERT_EQUAL(d, 0);
d = buf_cmp(&b, &a);
CU_ASSERT_EQUAL(d, 0);
/* compare different strings */
buf_reset(&a);
buf_appendcstr(&a, WORD0);
buf_reset(&b);
buf_appendcstr(&b, WORD1);
CU_ASSERT_PTR_NOT_NULL(a.s);
CU_ASSERT_EQUAL(a.len, sizeof(WORD0)-1);
CU_ASSERT_PTR_NOT_NULL(b.s);
CU_ASSERT_EQUAL(b.len, sizeof(WORD1)-1);
d = buf_cmp(&a, &b);
CU_ASSERT(d < 0);
d = buf_cmp(&b, &a);
CU_ASSERT(d > 0);
/* compare different strings where one is
* an initial subset of the other */
buf_reset(&a);
buf_appendcstr(&a, WORD0SUB);
buf_reset(&b);
buf_appendcstr(&b, WORD0);
CU_ASSERT_PTR_NOT_NULL(a.s);
CU_ASSERT_EQUAL(a.len, sizeof(WORD0SUB)-1);
CU_ASSERT_PTR_NOT_NULL(b.s);
CU_ASSERT_EQUAL(b.len, sizeof(WORD0)-1);
d = buf_cmp(&a, &b);
CU_ASSERT(d < 0);
d = buf_cmp(&b, &a);
CU_ASSERT(d > 0);
buf_free(&a);
buf_free(&b);
#undef WORD0
#undef WORD0SUB
#undef WORD1
}
static void test_cow(void)
{
static const char DATA0[] = "LoRem";
struct buf b = BUF_INITIALIZER;
CU_ASSERT_EQUAL(b.len, 0);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT_PTR_NULL(b.s);
buf_init_ro(&b, DATA0, sizeof(DATA0)-1);
CU_ASSERT_EQUAL(b.len, sizeof(DATA0)-1);
CU_ASSERT_EQUAL(b.alloc, 0);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT_PTR_EQUAL(b.s, (char *)DATA0);
buf_putc(&b, 'X');
CU_ASSERT_EQUAL(b.len, sizeof(DATA0)-1+1);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT_PTR_NOT_EQUAL(b.s, (char *)DATA0);
buf_free(&b);
}
static void test_cow2(void)
{
static const char DATA0[] = "cardigan umami";
struct buf b = BUF_INITIALIZER;
CU_ASSERT_EQUAL(b.len, 0);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT_PTR_NULL(b.s);
buf_init_ro_cstr(&b, DATA0);
CU_ASSERT_EQUAL(b.len, sizeof(DATA0)-1);
CU_ASSERT_EQUAL(b.alloc, 0);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT_PTR_EQUAL(b.s, (char *)DATA0);
buf_putc(&b, 'X');
CU_ASSERT_EQUAL(b.len, sizeof(DATA0)-1+1);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_EQUAL(buf_len(&b), b.len);
CU_ASSERT_PTR_NOT_EQUAL(b.s, (char *)DATA0);
buf_free(&b);
}
static void test_findchar(void)
{
struct buf b = BUF_INITIALIZER;
int i;
buf_appendcstr(&b, "ABCDEF");
/* Note: buf is NOT a C-string so should get a Valgrind
* error if findchar() runs off the end */
i = buf_findchar(&b, 0, 'A');
CU_ASSERT_EQUAL(i, 0);
i = buf_findchar(&b, 0, 'C');
CU_ASSERT_EQUAL(i, 2);
i = buf_findchar(&b, 0, 'F');
CU_ASSERT_EQUAL(i, 5);
i = buf_findchar(&b, 0, 'X');
CU_ASSERT_EQUAL(i, -1);
i = buf_findchar(&b, 0, -1);
CU_ASSERT_EQUAL(i, -1);
i = buf_findchar(&b, 2, 'A');
CU_ASSERT_EQUAL(i, -1);
i = buf_findchar(&b, 2, 'C');
CU_ASSERT_EQUAL(i, 2);
i = buf_findchar(&b, 2, 'F');
CU_ASSERT_EQUAL(i, 5);
i = buf_findchar(&b, 2, 'X');
CU_ASSERT_EQUAL(i, -1);
i = buf_findchar(&b, 2, -1);
CU_ASSERT_EQUAL(i, -1);
i = buf_findchar(&b, 6, 'F');
CU_ASSERT_EQUAL(i, -1);
i = buf_findchar(&b, 6, 'X');
CU_ASSERT_EQUAL(i, -1);
buf_free(&b);
}
static void test_cowappendmap(void)
{
/* data thanks to hipsteripsum.me */
#define WORD0 "beard"
#define WORD1 "narwhal"
struct buf b = BUF_INITIALIZER;
buf_cowappendmap(&b, WORD0, sizeof(WORD0)-1);
CU_ASSERT_EQUAL(b.len, sizeof(WORD0)-1);
CU_ASSERT(b.alloc == 0);
CU_ASSERT_PTR_NOT_NULL(b.s);
CU_ASSERT(!memcmp(b.s, WORD0, sizeof(WORD0)-1));
buf_cowappendmap(&b, WORD1, sizeof(WORD1)-1);
CU_ASSERT_EQUAL(b.len, sizeof(WORD0)-1+sizeof(WORD1)-1);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_PTR_NOT_NULL(b.s);
CU_ASSERT(!memcmp(b.s, WORD0""WORD1, sizeof(WORD0)-1+sizeof(WORD1)-1));
buf_free(&b);
#undef WORD0
#undef WORD1
}
static void test_cowappendfree(void)
{
/* data thanks to hipsteripsum.me */
#define WORD0 "beard"
#define WORD1 "narwhal"
struct buf b = BUF_INITIALIZER;
char *s;
s = xstrdup(WORD0);
buf_cowappendfree(&b, s, strlen(s));
CU_ASSERT_EQUAL(b.len, sizeof(WORD0)-1);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_PTR_NOT_NULL(b.s);
CU_ASSERT(!memcmp(b.s, WORD0, sizeof(WORD0)-1));
s = xstrdup(WORD1);
buf_cowappendfree(&b, s, strlen(s));
CU_ASSERT_EQUAL(b.len, sizeof(WORD0)-1+sizeof(WORD1)-1);
CU_ASSERT(b.alloc >= b.len);
CU_ASSERT_PTR_NOT_NULL(b.s);
CU_ASSERT(!memcmp(b.s, WORD0""WORD1, sizeof(WORD0)-1+sizeof(WORD1)-1));
/* we don't free s, buf_free() should do that */
buf_free(&b);
#undef WORD0
#undef WORD1
}
static void test_bufprint(void)
{
struct buf b = BUF_INITIALIZER;
struct protstream *outstream;
int i;
outstream = prot_writebuf(&b);
for (i = 0; i < 5000; i++) {
prot_putc('.', outstream);
}
prot_flush(outstream);
prot_free(outstream);
CU_ASSERT_EQUAL(b.len, 5000);
buf_free(&b);
}
#ifdef HAVE_ZLIB
static void test_compress(void)
{
struct buf b = BUF_INITIALIZER;
static const char DATA0[] = "LoRem";
int r;
buf_printf(&b, "%s", DATA0);
CU_ASSERT_STRING_EQUAL(buf_cstring(&b), DATA0);
r = buf_deflate(&b, Z_DEFAULT_COMPRESSION, DEFLATE_RAW);
CU_ASSERT_EQUAL(r, 0);
CU_ASSERT_STRING_NOT_EQUAL(buf_cstring(&b), DATA0);
r = buf_inflate(&b, DEFLATE_RAW);
CU_ASSERT_EQUAL(r, 0);
CU_ASSERT_STRING_EQUAL(buf_cstring(&b), DATA0);
buf_free(&b);
}
#endif
static void test_replace_shorten(void)
{
struct buf b = BUF_INITIALIZER;
buf_appendcstr(&b, "dreamcatcher skateboard");
/* Test that buf_replace_all() does not wander off the end of the
* buffer if a replacement operation at the end of the string
* shortens the string - this would show up in Valgrind. */
buf_replace_all(&b, "skateboard", "truck");
CU_ASSERT_STRING_EQUAL(b.s, "dreamcatcher truck");
buf_free(&b);
}
static void test_replace_cow_cstr(void)
{
struct buf b = BUF_INITIALIZER;
static const char DATA0[] = "food truck vegan";
buf_init_ro_cstr(&b, DATA0);
CU_ASSERT_PTR_NOT_NULL(b.s);
CU_ASSERT_PTR_EQUAL(b.s, DATA0);
CU_ASSERT_STRING_EQUAL(b.s, "food truck vegan");
/* There was a bug where buf_replace_all() was enforcing that
* the buffer was a C string but not that it was writable, which
* is often the same but isn't after a buf_init_ro_cstr(). With
* the bug, buf_replace_all() would SEGV */
buf_replace_all(&b, "truck", "vinyl");
CU_ASSERT_PTR_NOT_NULL(b.s);
CU_ASSERT_PTR_NOT_EQUAL(b.s, DATA0);
CU_ASSERT_STRING_EQUAL(b.s, "food vinyl vegan");
buf_free(&b);
}
static void test_findline(void)
{
struct buf b = BUF_INITIALIZER;
int r;
#define WORD0 "etsy"
#define WORD1 "quinoa"
#define WORD2 "dreamcatcher"
#define WORD3 "shoreditch"
#define WORD4 "williamsburg"
#define WORD5 "brooklyn"
#define WORDU "banksy"
buf_appendcstr(&b, WORD0"\n"WORD1"\n"WORD2"\n"WORD3" "WORD4"\n"WORD5"\n");
CU_ASSERT_EQUAL(b.len, sizeof(WORD0)+sizeof(WORD1)+sizeof(WORD2)+
sizeof(WORD3)+sizeof(WORD4)+sizeof(WORD5));
/* a zero length line is always unfound */
r = buf_findline(&b, "");
CU_ASSERT_EQUAL(r, -1);
r = buf_findline(&b, "\n");
CU_ASSERT_EQUAL(r, -1);
/* a line which is not present is unfound */
r = buf_findline(&b, WORDU);
CU_ASSERT_EQUAL(r, -1);
r = buf_findline(&b, WORDU"\n");
CU_ASSERT_EQUAL(r, -1);
/* only the first line of the needle is searched for */
r = buf_findline(&b, WORD1"\n"WORD3"\n");
CU_ASSERT_EQUAL(r, sizeof(WORD0));
/* the very first line is found */
r = buf_findline(&b, WORD0);
CU_ASSERT_EQUAL(r, 0);
r = buf_findline(&b, WORD0"\n");
CU_ASSERT_EQUAL(r, 0);
/* a line which is neither first nor last is found */
r = buf_findline(&b, WORD1);
CU_ASSERT_EQUAL(r, sizeof(WORD0));
r = buf_findline(&b, WORD1"\n");
CU_ASSERT_EQUAL(r, sizeof(WORD0));
/* a word which is a subset of a present line, is unfound */
r = buf_findline(&b, WORD3);
CU_ASSERT_EQUAL(r, -1);
r = buf_findline(&b, WORD3"\n");
CU_ASSERT_EQUAL(r, -1);
r = buf_findline(&b, WORD4);
CU_ASSERT_EQUAL(r, -1);
r = buf_findline(&b, WORD4"\n");
CU_ASSERT_EQUAL(r, -1);
/* the very last line is found */
r = buf_findline(&b, WORD5);
CU_ASSERT_EQUAL(r, sizeof(WORD0)+sizeof(WORD1)+sizeof(WORD2)+
sizeof(WORD3)+sizeof(WORD4));
r = buf_findline(&b, WORD5"\n");
CU_ASSERT_EQUAL(r, sizeof(WORD0)+sizeof(WORD1)+sizeof(WORD2)+
sizeof(WORD3)+sizeof(WORD4));
/* a word which is a subset of an earlier line, but
* matches a later present line, is found */
buf_reset(&b);
buf_appendcstr(&b, WORD0"\n"WORD1" "WORD2"\n"WORD1"\n"WORD2"\n"WORD5"\n");
CU_ASSERT_EQUAL(b.len, sizeof(WORD0)+sizeof(WORD1)+sizeof(WORD2)+
sizeof(WORD1)+sizeof(WORD2)+sizeof(WORD5));
r = buf_findline(&b, WORD1);
CU_ASSERT_EQUAL(r, sizeof(WORD0)+sizeof(WORD1)+sizeof(WORD2));
r = buf_findline(&b, WORD1"\n");
CU_ASSERT_EQUAL(r, sizeof(WORD0)+sizeof(WORD1)+sizeof(WORD2));
r = buf_findline(&b, WORD2);
CU_ASSERT_EQUAL(r, sizeof(WORD0)+sizeof(WORD1)+sizeof(WORD2)+
sizeof(WORD1));
r = buf_findline(&b, WORD2"\n");
CU_ASSERT_EQUAL(r, sizeof(WORD0)+sizeof(WORD1)+sizeof(WORD2)+
sizeof(WORD1));
/* a word which is the first subset of the first line, is unfound */
buf_reset(&b);
buf_appendcstr(&b, WORD0" "WORD1"\n"WORD2" "WORD3"\n");
CU_ASSERT_EQUAL(b.len, sizeof(WORD0)+sizeof(WORD1)+sizeof(WORD2)+
sizeof(WORD3));
r = buf_findline(&b, WORD0);
CU_ASSERT_EQUAL(r, -1);
r = buf_findline(&b, WORD0"\n");
CU_ASSERT_EQUAL(r, -1);
/* a word which is the last subset of the last line, is unfound */
r = buf_findline(&b, WORD3);
CU_ASSERT_EQUAL(r, -1);
r = buf_findline(&b, WORD3"\n");
CU_ASSERT_EQUAL(r, -1);
buf_free(&b);
#undef WORD0
#undef WORD1
#undef WORD2
#undef WORD3
#undef WORD4
#undef WORD5
#undef WORDU
}
static void _trimsto(const char *src, const char *dest)
{
struct buf buf = BUF_INITIALIZER;
buf_setcstr(&buf, src);
buf_trim(&buf);
CU_ASSERT_STRING_EQUAL(buf_cstring(&buf), dest);
buf_free(&buf);
}
static void test_trim(void)
{
_trimsto("", "");
_trimsto("a", "a");
_trimsto("abcdefg", "abcdefg");
_trimsto("ab\tcde fg", "ab\tcde fg");
_trimsto(" ab\tcde fg", "ab\tcde fg");
_trimsto(" ab\tcde fg ", "ab\tcde fg");
_trimsto("ab\tcde fg ", "ab\tcde fg");
_trimsto("\tab\tcde fg ", "ab\tcde fg");
_trimsto("\t ", "");
}
static void test_appendoverlap(void)
{
struct testcase {
const char *buf;
const char *str;
const char *want;
};
struct testcase testcases[] = {{
"abcdef", "efg", "abcdefg"
}, {
"abcd", "efg", "abcdefg"
}, {
"ab", "cdefg", "abcdefg"
}, {
"ab", "abcdefg", "abcdefg"
}, {
"a", "abcdefg", "abcdefg"
}, {
"", "abcdefg", "abcdefg"
}, {
"abcdefg", "", "abcdefg"
}, {
"abcdefg", "efg", "abcdefg"
}};
struct buf buf = BUF_INITIALIZER;
size_t i;
for (i = 0; i < sizeof(testcases) / sizeof(testcases[0]); i++) {
struct testcase tc = testcases[i];
buf_setcstr(&buf, tc.buf);
buf_appendoverlap(&buf, tc.str);
CU_ASSERT_STRING_EQUAL(tc.want, buf_cstring(&buf));
buf_reset(&buf);
}
buf_free(&buf);
}
static void test_tocrlf(void)
{
struct testcase {
char *input;
char *expect;
};
struct testcase testcases[] = {
{ "\rleading bare cr", "\r\nleading bare cr" },
{ "\nleading bare lf", "\r\nleading bare lf" },
{ "\r\nleading crlf", "\r\nleading crlf" },
{ "bare\rcr", "bare\r\ncr" },
{ "bare\nlf", "bare\r\nlf" },
{ "correct\r\ncrlf", "correct\r\ncrlf" },
{ "trailing bare cr\r", "trailing bare cr\r\n" },
{ "trailing bare lf\n", "trailing bare lf\r\n" },
{ "trailing crlf\r\n", "trailing crlf\r\n" },
{ "multiple\rbare\rcr", "multiple\r\nbare\r\ncr" },
{ "multiple\nbare\nlf", "multiple\r\nbare\r\nlf" },
{ "multiple\r\ncrlf\r\n", "multiple\r\ncrlf\r\n" },
{ "mixed cr\rand\nlf", "mixed cr\r\nand\r\nlf" },
{ "mixed bare\rcr, bare\nlf and\r\ncrlf",
"mixed bare\r\ncr, bare\r\nlf and\r\ncrlf" },
{ "adjacent\r\rbare cr", "adjacent\r\n\r\nbare cr" },
{ "adjacent\n\nbare lf", "adjacent\r\n\r\nbare lf" },
{ "adjacent\r\n\r\ncrlf", "adjacent\r\n\r\ncrlf" },
{ "more adjacent\r\r\rbare cr", "more adjacent\r\n\r\n\r\nbare cr" },
{ "more adjacent\n\n\nbare lf", "more adjacent\r\n\r\n\r\nbare lf" },
{ "more adjacent\r\n\r\n\r\ncrlf", "more adjacent\r\n\r\n\r\ncrlf" },
{ "adjacent\n\nbare\r\rmixed", "adjacent\r\n\r\nbare\r\n\r\nmixed" },
{ "tricksy\r\r\n\nsplit", "tricksy\r\n\r\n\r\nsplit" },
};
struct buf buf = BUF_INITIALIZER;
size_t i;
for (i = 0; i < sizeof(testcases) / sizeof(testcases[0]); i++) {
struct testcase tc = testcases[i];
buf_setcstr(&buf, tc.input);
buf_tocrlf(&buf);
CU_ASSERT_STRING_EQUAL(tc.expect, buf_cstring(&buf));
buf_reset(&buf);
}
buf_free(&buf);
}
/* TODO: test the Copy-On-Write feature of buf_ensure()...if anyone
* actually uses it */
/* vim: set ft=c: */