Converted testing.c to buffer test output. Also reordered test logs to be after the status line, like in Go. Now we can add verbosity control, and then maybe later even subtests!
This commit is contained in:
parent
8b70e6d247
commit
b7f06074fb
|
@ -36,39 +36,142 @@ static void *mustmalloc(size_t n, const char *what)
|
||||||
#define new(T) ((T *) mustmalloc(sizeof (T), #T))
|
#define new(T) ((T *) mustmalloc(sizeof (T), #T))
|
||||||
#define newArray(T, n) ((T *) mustmalloc(n * sizeof (T), #T "[" #n "]"))
|
#define newArray(T, n) ((T *) mustmalloc(n * sizeof (T), #T "[" #n "]"))
|
||||||
|
|
||||||
static void *mustrealloc(void *x, size_t n, const char *what)
|
static void *mustrealloc(void *x, size_t prevN, size_t n, const char *what)
|
||||||
{
|
{
|
||||||
void *y;
|
void *y;
|
||||||
|
|
||||||
y = realloc(x, n);
|
// don't use realloc() because we want to clear the new memory
|
||||||
|
y = malloc(n);
|
||||||
if (y == NULL)
|
if (y == NULL)
|
||||||
internalError("memory exhausted reallocating %s", what);
|
internalError("memory exhausted reallocating %s", what);
|
||||||
|
memset(y, 0, n);
|
||||||
|
memmove(y, x, prevN);
|
||||||
|
free(x);
|
||||||
return y;
|
return y;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define resizeArray(x, T, n) ((T *) mustrealloc(x, n * sizeof (T), #T "[" #n "]"))
|
#define resizeArray(x, T, prevN, n) ((T *) mustrealloc(x, prevN * sizeof (T), n * sizeof (T), #T "[" #n "]"))
|
||||||
|
|
||||||
static int mustvsnprintf(char *s, size_t n, const char *fmt, va_list ap)
|
static int mustvsnprintf(char *s, size_t n, const char *format, va_list ap)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = vsnprintf(s, n, fmt, ap);
|
ret = vsnprintf(s, n, format, ap);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
internalError("encoding error in vsnprintf(); this likely means your call to testingTLogf() and the like is invalid");
|
internalError("encoding error in vsnprintf(); this likely means your call to testingTLogf() and the like is invalid");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mustsnprintf(char *s, size_t n, const char *fmt, ...)
|
static int mustsnprintf(char *s, size_t n, const char *format, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
va_start(ap, fmt);
|
va_start(ap, format);
|
||||||
ret = mustvsnprintf(s, n, fmt, ap);
|
ret = mustvsnprintf(s, n, format, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// a struct outbuf of NULL writes directly to stdout
|
||||||
|
struct outbuf {
|
||||||
|
char *buf;
|
||||||
|
size_t len;
|
||||||
|
size_t cap;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define nOutbufGrow 32
|
||||||
|
|
||||||
|
static void outbufCopyStr(struct outbuf *o, const char *str, size_t len)
|
||||||
|
{
|
||||||
|
size_t grow;
|
||||||
|
|
||||||
|
if (len == 0)
|
||||||
|
return;
|
||||||
|
if (o == NULL) {
|
||||||
|
printf("%s", str);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
grow = len + 1;
|
||||||
|
if (grow < nOutbufGrow)
|
||||||
|
grow = nOutbufGrow;
|
||||||
|
if ((o->len + grow) >= o->cap) {
|
||||||
|
size_t prevcap;
|
||||||
|
|
||||||
|
prevcap = o->cap;
|
||||||
|
o->cap += grow;
|
||||||
|
o->buf = resizeArray(o->buf, char, prevcap, o->cap);
|
||||||
|
}
|
||||||
|
memmove(o->buf + o->len, str, len * sizeof (char));
|
||||||
|
o->len += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define outbufAddNewline(o) outbufCopyStr(o, "\n", 1)
|
||||||
|
|
||||||
|
static void outbufAddIndent(struct outbuf *o, int n)
|
||||||
|
{
|
||||||
|
for (; n != 0; n--)
|
||||||
|
outbufCopyStr(o, " ", 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void outbufVprintf(struct outbuf *o, int indent, const char *format, va_list ap)
|
||||||
|
{
|
||||||
|
va_list ap2;
|
||||||
|
char *buf;
|
||||||
|
int n;
|
||||||
|
char *lineStart, *lineEnd;
|
||||||
|
int firstLine = 1;
|
||||||
|
|
||||||
|
va_copy(ap2, ap);
|
||||||
|
n = mustvsnprintf(NULL, 0, format, ap2);
|
||||||
|
// TODO handle n < 0 case
|
||||||
|
va_end(ap2);
|
||||||
|
buf = newArray(char, n + 1);
|
||||||
|
mustvsnprintf(buf, n + 1, format, ap);
|
||||||
|
|
||||||
|
// strip trailing blank lines
|
||||||
|
while (buf[n - 1] == '\n')
|
||||||
|
n--;
|
||||||
|
buf[n] = '\0';
|
||||||
|
|
||||||
|
lineStart = buf;
|
||||||
|
for (;;) {
|
||||||
|
lineEnd = strchr(lineStart, '\n');
|
||||||
|
if (lineEnd == NULL) // last line
|
||||||
|
break;
|
||||||
|
*lineEnd = '\0';
|
||||||
|
outbufAddIndent(o, indent);
|
||||||
|
outbufCopyStr(o, lineStart, lineEnd - lineStart);
|
||||||
|
outbufAddNewline(o);
|
||||||
|
lineStart = lineEnd + 1;
|
||||||
|
if (firstLine) {
|
||||||
|
// subsequent lines are indented twice
|
||||||
|
indent++;
|
||||||
|
firstLine = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// print the last line
|
||||||
|
outbufAddIndent(o, indent);
|
||||||
|
outbufCopyStr(o, lineStart, strlen(lineStart));
|
||||||
|
outbufAddNewline(o);
|
||||||
|
|
||||||
|
free(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void outbufPrintf(struct outbuf *o, int indent, const char *format, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, format);
|
||||||
|
outbufVprintf(o, indent, format, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void outbufCopy(struct outbuf *o, const struct outbuf *from)
|
||||||
|
{
|
||||||
|
outbufCopyStr(o, from->buf, from->len);
|
||||||
|
}
|
||||||
|
|
||||||
struct defer {
|
struct defer {
|
||||||
void (*f)(testingT *, void *);
|
void (*f)(testingT *, void *);
|
||||||
void *data;
|
void *data;
|
||||||
|
@ -102,9 +205,7 @@ struct testingT {
|
||||||
// output
|
// output
|
||||||
int indent;
|
int indent;
|
||||||
int verbose;
|
int verbose;
|
||||||
char *output;
|
struct outbuf output;
|
||||||
size_t outputLen;
|
|
||||||
size_t outputCap;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
|
@ -135,8 +236,11 @@ static struct testset testsAfter = { NULL, 0, 0 };
|
||||||
static void testsetAdd(struct testset *set, const char *name, void (*f)(testingT *), const char *file, long line)
|
static void testsetAdd(struct testset *set, const char *name, void (*f)(testingT *), const char *file, long line)
|
||||||
{
|
{
|
||||||
if (set->len == set->cap) {
|
if (set->len == set->cap) {
|
||||||
|
size_t prevcap;
|
||||||
|
|
||||||
|
prevcap = set->cap;
|
||||||
set->cap += nGrow;
|
set->cap += nGrow;
|
||||||
set->tests = resizeArray(set->tests, testingT, set->cap);
|
set->tests = resizeArray(set->tests, testingT, prevcap, set->cap);
|
||||||
}
|
}
|
||||||
initTest(set->tests + set->len, name, f, file, line);
|
initTest(set->tests + set->len, name, f, file, line);
|
||||||
set->len++;
|
set->len++;
|
||||||
|
@ -178,63 +282,6 @@ static void testsetSort(struct testset *set)
|
||||||
qsort(set->tests, set->len, sizeof (testingT), testcmp);
|
qsort(set->tests, set->len, sizeof (testingT), testcmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void printIndent(int n)
|
|
||||||
{
|
|
||||||
for (; n != 0; n--)
|
|
||||||
printf(" ");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void vprintfIndented(int indent, const char *format, va_list ap)
|
|
||||||
{
|
|
||||||
va_list ap2;
|
|
||||||
char *buf;
|
|
||||||
int n;
|
|
||||||
char *lineStart, *lineEnd;
|
|
||||||
int firstLine = 1;
|
|
||||||
|
|
||||||
va_copy(ap2, ap);
|
|
||||||
n = mustvsnprintf(NULL, 0, format, ap2);
|
|
||||||
// TODO handle n < 0 case
|
|
||||||
va_end(ap2);
|
|
||||||
buf = newArray(char, n + 1);
|
|
||||||
mustvsnprintf(buf, n + 1, format, ap);
|
|
||||||
|
|
||||||
// strip trailing blank lines
|
|
||||||
while (buf[n - 1] == '\n')
|
|
||||||
n--;
|
|
||||||
buf[n] = '\0';
|
|
||||||
|
|
||||||
lineStart = buf;
|
|
||||||
for (;;) {
|
|
||||||
lineEnd = strchr(lineStart, '\n');
|
|
||||||
if (lineEnd == NULL) // last line
|
|
||||||
break;
|
|
||||||
*lineEnd = '\0';
|
|
||||||
printIndent(indent);
|
|
||||||
printf("%s\n", lineStart);
|
|
||||||
lineStart = lineEnd + 1;
|
|
||||||
if (firstLine) {
|
|
||||||
// subsequent lines are indented twice
|
|
||||||
indent++;
|
|
||||||
firstLine = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// print the last line
|
|
||||||
printIndent(indent);
|
|
||||||
printf("%s\n", lineStart);
|
|
||||||
|
|
||||||
free(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void printfIndented(int indent, const char *format, ...)
|
|
||||||
{
|
|
||||||
va_list ap;
|
|
||||||
|
|
||||||
va_start(ap, format);
|
|
||||||
vprintfIndented(indent, format, ap);
|
|
||||||
va_end(ap);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void runDefers(testingT *t)
|
static void runDefers(testingT *t)
|
||||||
{
|
{
|
||||||
struct defer *d;
|
struct defer *d;
|
||||||
|
@ -256,7 +303,7 @@ static void testsetRun(struct testset *set, int indent, int *anyFailed)
|
||||||
|
|
||||||
t = set->tests;
|
t = set->tests;
|
||||||
for (i = 0; i < set->len; i++) {
|
for (i = 0; i < set->len; i++) {
|
||||||
printfIndented(indent, "=== RUN %s\n", t->name);
|
outbufPrintf(NULL, indent, "=== RUN %s", t->name);
|
||||||
t->indent = indent + 1;
|
t->indent = indent + 1;
|
||||||
start = timerMonotonicNow();
|
start = timerMonotonicNow();
|
||||||
if (setjmp(t->returnNowBuf) == 0)
|
if (setjmp(t->returnNowBuf) == 0)
|
||||||
|
@ -272,7 +319,8 @@ static void testsetRun(struct testset *set, int indent, int *anyFailed)
|
||||||
// note that failed overrides skipped
|
// note that failed overrides skipped
|
||||||
status = "SKIP";
|
status = "SKIP";
|
||||||
timerDurationString(timerTimeSub(end, start), timerstr);
|
timerDurationString(timerTimeSub(end, start), timerstr);
|
||||||
printfIndented(indent, "--- %s: %s (%s)\n", status, t->name, timerstr);
|
outbufPrintf(NULL, indent, "--- %s: %s (%s)", status, t->name, timerstr);
|
||||||
|
outbufCopy(NULL, &(t->output));
|
||||||
t++;
|
t++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -333,7 +381,7 @@ void testingprivTLogvfFull(testingT *t, const char *file, long line, const char
|
||||||
buf = newArray(char, n + n2 + 1);
|
buf = newArray(char, n + n2 + 1);
|
||||||
mustsnprintf(buf, n + 1, "%s:%ld: ", file, line);
|
mustsnprintf(buf, n + 1, "%s:%ld: ", file, line);
|
||||||
mustvsnprintf(buf + n, n2 + 1, format, ap);
|
mustvsnprintf(buf + n, n2 + 1, format, ap);
|
||||||
printfIndented(t->indent, "%s", buf);
|
outbufPrintf(&(t->output), t->indent, "%s", buf);
|
||||||
free(buf);
|
free(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue