syncfiles/macos/pstrbuilder_test.c
Dietrich Epp def1c2c253 Add Pascal string builder module
This will be used for formatting messages for the user. The idea is to
have something more usable than the Mac OS toolbox ParamText function.
2023-04-19 22:14:34 -04:00

164 lines
4.0 KiB
C

// Copyright 2023 Dietrich Epp.
// This file is part of SyncFiles. SyncFiles is licensed under the terms of the
// Mozilla Public License, version 2.0. See LICENSE.txt for details.
#include "macos/pstrbuilder.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// =============================================================================
// Temporary buffer for Pascal strings
static size_t PStrBufPos;
static unsigned char PStrBuf[1024];
static const unsigned char *P2CStr(const char *str)
{
size_t len;
unsigned char *ptr;
len = strlen(str);
if (len > 255) {
fputs("Error: PStr too long\n", stderr);
exit(1);
}
if (len + 1 > sizeof(PStrBuf) - PStrBufPos) {
fputs("Error: PStr overflow\n", stderr);
exit(1);
}
ptr = PStrBuf + PStrBufPos;
*ptr = len;
memcpy(ptr + 1, str, len);
PStrBufPos += len + 1;
return ptr;
}
static void PStrReset(void)
{
PStrBufPos = 0;
}
#define PSTR(x) P2CStr(x)
#define PSTR_RESET() PStrReset()
// =============================================================================
static Boolean TestFailed;
static void PrintQuoted(const unsigned char *str)
{
const unsigned char *ptr = str + 1;
const unsigned char *end = ptr + str[0];
int ch;
for (; ptr < end; ptr++) {
ch = *ptr;
if (32 <= ch && ch <= 126) {
if (ch == '\\' || ch == '"') {
fputc('\\', stderr);
}
fputc(ch, stderr);
} else {
fprintf(stderr, "\\x%02x", ch);
}
}
}
static void TestString(int lineno, const struct PStrBuilder *buf,
const unsigned char *expect, Boolean expect_truncated)
{
if (memcmp(buf->data, expect, expect[0] + 1) != 0 ||
buf->truncated != expect_truncated) {
fprintf(stderr, "%s:%d: Incorrect result\n", __FILE__, lineno);
fputs(" expect: \"", stderr);
PrintQuoted(expect);
fprintf(stderr, "\" (truncated=%d)\n", expect_truncated);
fputs(" got: \"", stderr);
PrintQuoted(buf->data);
fprintf(stderr, "\" (truncated=%d)\n", buf->truncated);
TestFailed = true;
}
}
#define TEST_STRING(buf, expect, expect_truncated) \
TestString(__LINE__, buf, expect, expect_truncated)
#define STR50 "0123456789abcdef0123456789abcdef0123456789abcdef0."
#define STR250 STR50 STR50 STR50 STR50 STR50
static void Clear(struct PStrBuilder *buf, const unsigned char **params)
{
int i;
buf->data[0] = 0;
buf->truncated = false;
for (i = 0; i < 9; i++) {
params[i] = NULL;
}
}
int main(int argc, char **argv)
{
struct PStrBuilder buf;
const unsigned char *params[9];
(void)argc;
(void)argv;
Clear(&buf, params);
TEST_STRING(&buf, PSTR(""), false);
PSTR_RESET();
// Append string to empty buffer.
PStrAppend(&buf, PSTR("String1"));
TEST_STRING(&buf, PSTR("String1"), false);
PSTR_RESET();
// Append string to non-empty buffer.
PStrAppend(&buf, PSTR("String2"));
TEST_STRING(&buf, PSTR("String1String2"), false);
PSTR_RESET();
// Append string with parameters.
Clear(&buf, params);
PStrAppend(&buf, PSTR("initial: "));
params[0] = PSTR("(param1)");
params[1] = PSTR("(param2)");
params[8] = PSTR("(param9)");
PStrAppendSubstitute(&buf, PSTR("^1 ^9 -> ^2"), 9, params);
TEST_STRING(&buf, PSTR("initial: (param1) (param9) -> (param2)"), false);
PSTR_RESET();
// Missing parameters are left alone, including NULL parameters.
Clear(&buf, params);
params[0] = PSTR("param1");
PStrAppendSubstitute(&buf, PSTR("^0 ^1 ^2 ^3 ^9"), 2, params);
TEST_STRING(&buf, PSTR("^0 param1 ^2 ^3 ^9"), false);
// String length 255 works.
Clear(&buf, params);
PStrAppend(&buf, PSTR(STR250));
PStrAppend(&buf, PSTR("VWXYZ"));
TEST_STRING(&buf, PSTR(STR250 "VWXYZ"), false);
PSTR_RESET();
// String length 256 is truncated.
PStrAppend(&buf, PSTR("."));
TEST_STRING(&buf, PSTR(STR250 "VWXY\xc9"), true);
PSTR_RESET();
// Truncate with parameters.
Clear(&buf, params);
params[0] = PSTR(STR50);
PStrAppendSubstitute(&buf, PSTR("^1^1^1^1^1^1"), 1, params);
TEST_STRING(&buf, PSTR(STR250 "0123\xc9"), true);
PSTR_RESET();
fputs("OK?\n", stderr);
if (TestFailed) {
fputs("Test failed\n", stderr);
exit(1);
}
return 0;
}