Initial import

This commit is contained in:
Justine Tunney 2020-06-15 07:18:57 -07:00
commit c91b3c5006
14915 changed files with 590219 additions and 0 deletions

View file

@ -0,0 +1,29 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/testlib/testlib.h"
/* ┌sign
exponent
fraction
*/
#define SGN 0b1000000000000000000000000000000000000000000000000000000000000000lu
#define EXP 0b0111111111110000000000000000000000000000000000000000000000000000lu
#define FAC 0b0000000000001111111111111111111111111111111111111111111111111111lu

View file

@ -0,0 +1,29 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/testlib/testlib.h"
/* ┌sign
exponent
fraction
*/
#define BINARY32_SIGN 0b10000000000000000000000000000000u
#define BINARY32_EXPO 0b01111111100000000000000000000000u
#define BINARY32_FRAC 0b00000000011111111111111111111111u

View file

@ -0,0 +1,29 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/math.h"
#include "libc/testlib/testlib.h"
#define EPSILON 0.0000000000001L
testonly bool testlib_almostequallongdouble(long double x, long double y) {
/* TODO(jart): This algorithm has to be binary. */
if (isnan(x) || isnan(y)) return false;
return fabsl(x - y) <= EPSILON;
}

43
libc/testlib/bench.S Normal file
View file

@ -0,0 +1,43 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
yoink __FILE__
yoink testlib_runallbenchmarks
/ Decentralized section for benchmark registration.
/
/ @see ape/ape.lds
.section .piro.relo.sort.bench.1,"aw",@nobits
.type __bench_start,@object
.type __bench_end,@object
.globl __bench_start,__bench_end
.hidden __bench_start,__bench_end
.byte 0
.align __SIZEOF_POINTER__
__bench_start:
.previous/*
...
decentralized content
...
*/.section .piro.relo.sort.bench.3,"aw",@nobits
__bench_end:
.quad 0
.previous

29
libc/testlib/bench.h Normal file
View file

@ -0,0 +1,29 @@
#ifndef COSMOPOLITAN_LIBC_BENCH_H_
#define COSMOPOLITAN_LIBC_BENCH_H_
#include "libc/bits/safemacros.h"
#include "libc/nexgen32e/bench.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
/**
* @fileoverview Microbenchmarking tools.
*/
#define BENCHLOOP(START, STOP, N, INIT, EXPR) \
({ \
int Iter, Count; \
long double Average, Sample, Time1, Time2; \
for (Average = 1.0, Iter = 1, Count = (N); Iter < Count; ++Iter) { \
INIT; \
Time1 = START(); \
EXPR; \
Time2 = STOP(); \
Sample = Time2 - Time1; \
Average += (Sample - Average) / Iter; \
} \
Average; \
})
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_BENCH_H_ */

View file

@ -0,0 +1,60 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/calls.h"
#include "libc/calls/kntprioritycombos.h"
#include "libc/log/log.h"
#include "libc/nexgen32e/x86feature.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/mlock.h"
#include "libc/testlib/testlib.h"
double g_avx2_juiceup_doubles_[4] aligned(32);
unsigned long long g_avx2_juiceup_quadwords_[4] aligned(32);
void testlib_benchwarmup(void) {
/* get mathematical parts of cpu juiced up */
if (X86_HAVE(AVX2) && X86_HAVE(FMA)) {
asm("vmovdqa\t%1,%%ymm0\n\t"
"vpmaddwd\t(%2),%%ymm0,%%ymm0\n\t"
"vmovdqa\t%%ymm0,%0\n\t"
"vzeroall"
: "=m"(g_avx2_juiceup_quadwords_)
: "m"(g_avx2_juiceup_quadwords_), "r"(&_base[0]));
asm("vmovapd\t%1,%%ymm1\n\t"
"vfmadd132pd\t(%2),%%ymm1,%%ymm1\n\t"
"vmovapd\t%%ymm1,%0\n\t"
"vzeroall"
: "=m"(g_avx2_juiceup_doubles_)
: "m"(g_avx2_juiceup_doubles_), "r"(&_base[32]));
}
}
/**
* Runs all benchmark functions in sorted order.
*
* @see BENCH()
*/
void testlib_runallbenchmarks(void) {
peekall();
mlockall(MCL_CURRENT);
nice(-1);
g_loglevel = kLogWarn;
testlib_runtestcases(__bench_start, __bench_end, testlib_benchwarmup);
}

41
libc/testlib/binequals.c Normal file
View file

@ -0,0 +1,41 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/str/str.h"
#include "libc/testlib/testlib.h"
/**
* Tests that raw memory is equal to visual representation, e.g.
*
* testlib_binequals(u" ☺☻♥", "\0\1\2\3", -1ul);
*
* @see libc/nexgen32e/kCp437.S
*/
testonly bool testlib_binequals(const char16_t *want, const void *got,
size_t n) {
size_t i;
const unsigned char *p = (const unsigned char *)got;
if (!got) return false;
for (i = 0; i < n; ++i) {
if (!want[i]) break;
if (i == n) break;
if (want[i] != kCp437[p[i]]) return false;
}
return true;
}

41
libc/testlib/combo.S Normal file
View file

@ -0,0 +1,41 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
.yoink __FILE__
/ Decentralized section for test combo registration.
/
/ @see ape/ape.lds
.section .piro.relo.sort.combo.1,"aw",@nobits
.type __combo_start,@object
.type __combo_end,@object
.globl __combo_start,__combo_end
.hidden __combo_start,__combo_end
.byte 0
.align __SIZEOF_POINTER__
__combo_start:
.previous/*
...
decentralized content
...
*/.section .piro.relo.sort.combo.3,"aw",@nobits
__combo_end:
.quad 0
.previous

100
libc/testlib/comborunner.c Normal file
View file

@ -0,0 +1,100 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/safemacros.h"
#include "libc/fmt/fmt.h"
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#include "libc/testlib/testlib.h"
struct ComboGroup {
unsigned entry;
unsigned i;
unsigned n;
};
struct ComboProduct {
unsigned n;
struct ComboGroup groups[];
};
mallocesque testonly struct ComboProduct *testlib_setupcomboproduct(
const struct TestFixture *start, const struct TestFixture *end) {
unsigned i, j, entrycount;
struct ComboProduct *product;
entrycount = testlib_countfixtures(start, end);
product = calloc(
sizeof(struct ComboProduct) + entrycount * sizeof(struct ComboGroup), 1);
for (j = i = 0; i < entrycount; ++i) {
if (j && strcmp(start[product->groups[j - 1].entry].group,
start[i].group) == 0) {
product->groups[j - 1].n++;
} else {
++j;
product->groups[j - 1].entry = i;
product->groups[j - 1].n = 1;
}
}
product->n = j;
return product;
}
static testonly void testlib_describecombo(struct ComboProduct *product,
const struct TestFixture *combos) {
char *p = &g_fixturename[0];
char *pe = p + sizeof(g_fixturename);
for (unsigned i = 0; i < product->n && p < pe; ++i) {
const char *sep = i ? ", " : "";
const struct TestFixture *e =
&combos[product->groups[i].entry + product->groups[i].i];
p += max(0, snprintf(p, pe - p, "%s%s=%s", sep, e->group, e->name));
}
}
static testonly void testlib_callcombos(struct ComboProduct *product,
const struct TestFixture *combos,
testfn_t *test_start,
testfn_t *test_end) {
for (;;) {
testlib_describecombo(product, combos);
for (unsigned i = 0; i < product->n; ++i) {
combos[product->groups[i].entry + product->groups[i].i].fn();
}
for (unsigned i = product->n;; --i) {
if (!i) return;
if (++product->groups[i - 1].i < product->groups[i - 1].n) break;
product->groups[i - 1].i = 0;
}
testlib_runtestcases(test_start, test_end, NULL);
}
}
/**
* Runs Cartesian product of COMBO() fixtures registered with linker.
* @see ape/ape.lds
* @see libc/testlib/testlib.h
*/
testonly void testlib_runcombos(testfn_t *test_start, testfn_t *test_end,
const struct TestFixture *combo_start,
const struct TestFixture *combo_end) {
struct ComboProduct *product;
product = testlib_setupcomboproduct(combo_start, combo_end);
testlib_callcombos(product, combo_start, test_start, test_end);
free(product);
}

28
libc/testlib/contains.c Normal file
View file

@ -0,0 +1,28 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/str/str.h"
#include "libc/testlib/testlib.h"
testonly bool testlib_contains(size_t cw, const void *s, const void *needle) {
if (s == needle) return true;
if (!s || !needle) return false;
return sizeof(cw) == sizeof(char16_t) ? !!strstr16(s, needle)
: !!strstr(s, needle);
}

29
libc/testlib/endswith.c Normal file
View file

@ -0,0 +1,29 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/str/str.h"
#include "libc/testlib/testlib.h"
testonly bool testlib_endswith(size_t cw, const void *s, const void *suffix) {
if (s == suffix) return true;
if (!s || !suffix) return false;
return cw == sizeof(wchar_t) ? wcsendswith(s, suffix)
: cw == sizeof(char16_t) ? endswith16(s, suffix)
: endswith(s, suffix);
}

29
libc/testlib/ezbench.h Normal file
View file

@ -0,0 +1,29 @@
#ifndef COSMOPOLITAN_LIBC_TESTLIB_EZBENCH_H_
#define COSMOPOLITAN_LIBC_TESTLIB_EZBENCH_H_
#include "libc/macros.h"
#include "libc/testlib/bench.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
#define EZBENCH(INIT, EXPR) EZBENCH2(#EXPR, INIT, EXPR)
#define EZBENCH2(NAME, INIT, EXPR) \
do { \
uint64_t Control, Speculative, MemoryStrict; \
Control = __testlib_ezbenchcontrol(); \
INIT; \
EXPR; \
Speculative = BENCHLOOP(__startbench, __endbench, 128, INIT, (EXPR)); \
MemoryStrict = BENCHLOOP(__startbench_m, __endbench_m, 8, ({ \
INIT; \
thrashcodecache(); \
}), \
(EXPR)); \
Control = MIN(Control, MIN(Speculative, MemoryStrict)); \
__testlib_ezbenchreport(NAME, Speculative - Control, \
MemoryStrict - Control); \
} while (0)
void __testlib_ezbenchreport(const char *, uint64_t, uint64_t);
uint64_t __testlib_ezbenchcontrol(void);
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_TESTLIB_EZBENCH_H_ */

View file

@ -0,0 +1,25 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/testlib/bench.h"
#include "libc/testlib/testlib.h"
uint64_t __testlib_ezbenchcontrol(void) {
return BENCHLOOP(__startbench, __endbench, 128, donothing, (void)0);
}

View file

@ -0,0 +1,35 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/math.h"
#include "libc/stdio/stdio.h"
#include "libc/testlib/testlib.h"
#include "libc/time/time.h"
STATIC_YOINK("ntoa");
STATIC_YOINK("stoa");
void __testlib_ezbenchreport(const char *form, uint64_t c1, uint64_t c2) {
uint64_t ns1, ns2;
ns1 = lrintl(converttickstonanos(c1));
ns2 = lrintl(converttickstonanos(c2));
(fprintf)(stderr,
VEIL("r", "%-30s l: %,10lu𝑐 %,10lu𝑛𝑠 m: %,10lu𝑐 %,10lu𝑛𝑠\n"),
form, c1, ns1, c2, ns2);
}

41
libc/testlib/fixture.S Normal file
View file

@ -0,0 +1,41 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
.yoink __FILE__
/ Decentralized section for test fixture registration.
/
/ @see ape/ape.lds
.section .piro.relo.sort.fixture.1,"aw",@nobits
.type __fixture_start,@object
.type __fixture_end,@object
.globl __fixture_start,__fixture_end
.hidden __fixture_start,__fixture_end
.byte 0
.align __SIZEOF_POINTER__
__fixture_start:
.previous/*
...
decentralized content
...
*/.section .piro.relo.sort.fixture.3,"aw",@nobits
__fixture_end:
.quad 0
.previous

View file

@ -0,0 +1,48 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/fmt/fmt.h"
#include "libc/runtime/internal.h"
#include "libc/sysv/consts/prot.h"
#include "libc/testlib/testlib.h"
testonly int testlib_countfixtures(const struct TestFixture *start,
const struct TestFixture *end) {
return ((intptr_t)end - (intptr_t)start) / sizeof(struct TestFixture);
}
/**
* Runs test cases for each FIXTURE() registered with the linker.
* @see ape/ape.lds
* @see libc/testlib/testlib.h
*/
testonly void testlib_runfixtures(testfn_t *test_start, testfn_t *test_end,
const struct TestFixture *fixture_start,
const struct TestFixture *fixture_end) {
unsigned i, count;
count = testlib_countfixtures(fixture_start, fixture_end);
for (i = 0; i < count && !g_testlib_failed; ++i) {
snprintf(g_fixturename, sizeof(g_fixturename), "%s_%s",
fixture_start[i].group, fixture_start[i].name);
__piro(PROT_READ | PROT_WRITE);
fixture_start[i].fn();
__piro(PROT_READ);
testlib_runtestcases(test_start, test_end, NULL);
}
}

View file

@ -0,0 +1,30 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/str/str.h"
#include "libc/testlib/testlib.h"
#include "libc/x/x.h"
testonly void testlib_formatbinaryasglyphs(const char16_t *want,
const void *got, size_t n,
char **out_v1, char **out_v2) {
if (n == -1ul) n = strlen(want);
*out_v1 = xasprintf("%`#.*hs", n, want);
*out_v2 = xasprintf(" %`'#.*s", n, got);
}

View file

@ -0,0 +1,41 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#include "libc/testlib/testlib.h"
#include "libc/x/x.h"
testonly void testlib_formatbinaryashex(const char *want, const void *got,
size_t n, char **out_v1,
char **out_v2) {
size_t i;
uint8_t b;
char *gothex;
if (n == -1ul) n = strlen(want) / 2;
gothex = xmalloc(n * 2 + 1);
gothex[n * 2] = '\0';
for (i = 0; i < n; ++i) {
b = ((uint8_t *)got)[i];
gothex[i * 2 + 0] = "0123456789abcdef"[(b >> 4) & 0xf];
gothex[i * 2 + 1] = "0123456789abcdef"[(b >> 0) & 0xf];
}
*out_v1 = strdup(want);
*out_v2 = gothex;
}

27
libc/testlib/formatbool.c Normal file
View file

@ -0,0 +1,27 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/testlib/testlib.h"
static const char kTrueStr[] = "true";
static const char kFalseStr[] = "false";
char *testlib_formatbool(bool v) {
return (/*unconst*/ char *)(v ? kTrueStr : kFalseStr);
}

View file

@ -0,0 +1,30 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/fmt/fmt.h"
#include "libc/mem/mem.h"
#include "libc/testlib/testlib.h"
#include "third_party/dtoa/dtoa.h"
testonly char *testlib_formatfloat(long double x) {
char dtoabuf[32];
char *str = malloc(256);
sprintf(str, "%Lf (%s)", x, g_fmt(dtoabuf, x));
return str;
}

39
libc/testlib/formatint.c Normal file
View file

@ -0,0 +1,39 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/bits.h"
#include "libc/fmt/fmt.h"
#include "libc/macros.h"
#include "libc/mem/mem.h"
#include "libc/testlib/testlib.h"
static size_t sbufi_;
static char sbufs_[2][256];
nodiscard testonly char *testlib_formatint(intmax_t x) {
char *str = sbufi_ < ARRAYLEN(sbufs_) ? sbufs_[sbufi_++] : malloc(256);
char *p = str;
p += sprintf(p, "%jd\t(or %#jx", x, x);
if (0 <= x && x < 256) {
p += sprintf(p, " or %#`c", (unsigned char)x);
}
*p++ = ')';
*p++ = '\0';
return str;
}

View file

@ -0,0 +1,25 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/testlib/testlib.h"
#include "libc/x/x.h"
nodiscard testonly char *testlib_formatrange(intmax_t beg, intmax_t end) {
return xasprintf("[%#jx,%#jx]", beg, end);
}

43
libc/testlib/formatstr.c Normal file
View file

@ -0,0 +1,43 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/progn.h"
#include "libc/bits/safemacros.h"
#include "libc/str/str.h"
#include "libc/testlib/testlib.h"
#include "libc/x/x.h"
/**
* Turns string into code.
*/
nodiscard testonly char *testlib_formatstr(size_t cw, const void *s, int n) {
switch (cw) {
case 1:
if (n == -1) n = s ? strlen(s) : 0;
return xasprintf("%`'.*s", n, s);
case 2:
if (n == -1) n = s ? strlen16(s) : 0;
return xasprintf("%`'.*hs", n, s);
case 4:
if (n == -1) n = s ? wcslen(s) : 0;
return xasprintf("%`'.*ls", n, s);
default:
abort();
}
}

24
libc/testlib/globals.c Normal file
View file

@ -0,0 +1,24 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/testlib/testlib.h"
char g_fixturename[256];
unsigned g_testlib_ran;
unsigned g_testlib_failed;

43
libc/testlib/hexequals.c Normal file
View file

@ -0,0 +1,43 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/str/str.h"
#include "libc/testlib/testlib.h"
/**
* Tests that raw memory is equal to numeric representation, e.g.
*
* testlib_hexequals("00010203", "\0\1\2\3", -1ul);
*
* @see unhexstr()
*/
testonly bool testlib_hexequals(const char *want, const void *got, size_t n) {
size_t i;
const unsigned char *p = (const unsigned char *)got;
if (!got) return false;
for (i = 0; i < n; ++i) {
if (!want[i * 2]) break;
if (i == n) break;
if (p[i] != (unsigned char)(hextoint(want[i * 2 + 0]) * 16 +
hextoint(want[i * 2 + 1]))) {
return false;
}
}
return true;
}

34
libc/testlib/hyperion.S Normal file
View file

@ -0,0 +1,34 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
.rodata
.yoink __FILE__
/ Nontrivial NUL-terminated string test vector.
.align 1
kHyperion:
0: .incbin "libc/testlib/hyperion.txt"
1: .byte 0
.endobj kHyperion,globl
.align 8
kHyperionSize:
.quad 1b-0b
.endobj kHyperionSize,globl

12
libc/testlib/hyperion.h Normal file
View file

@ -0,0 +1,12 @@
#ifndef COSMOPOLITAN_LIBC_TESTLIB_HYPERION_H_
#define COSMOPOLITAN_LIBC_TESTLIB_HYPERION_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
extern size_t kHyperionSize;
extern char kHyperion[];
extern uint8_t kHyperionZip[];
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_TESTLIB_HYPERION_H_ */

547
libc/testlib/hyperion.txt Normal file
View file

@ -0,0 +1,547 @@
The fall of Hyperion - a Dream
John Keats
CANTO I
Fanatics have their dreams, wherewith they weave
A paradise for a sect; the savage too
From forth the loftiest fashion of his sleep
Guesses at Heaven; pity these have not
Trac'd upon vellum or wild Indian leaf
The shadows of melodious utterance.
But bare of laurel they live, dream, and die;
For Poesy alone can tell her dreams,
With the fine spell of words alone can save
Imagination from the sable charm
And dumb enchantment. Who alive can say,
'Thou art no Poet may'st not tell thy dreams?'
Since every man whose soul is not a clod
Hath visions, and would speak, if he had loved
And been well nurtured in his mother tongue.
Whether the dream now purpos'd to rehearse
Be poet's or fanatic's will be known
When this warm scribe my hand is in the grave.
Methought I stood where trees of every clime,
Palm, myrtle, oak, and sycamore, and beech,
With plantain, and spice blossoms, made a screen;
In neighbourhood of fountains, by the noise
Soft showering in my ears, and, by the touch
Of scent, not far from roses. Turning round
I saw an arbour with a drooping roof
Of trellis vines, and bells, and larger blooms,
Like floral censers swinging light in air;
Before its wreathed doorway, on a mound
Of moss, was spread a feast of summer fruits,
Which, nearer seen, seem'd refuse of a meal
By angel tasted or our Mother Eve;
For empty shells were scattered on the grass,
And grape stalks but half bare, and remnants more,
Sweet smelling, whose pure kinds I could not know.
Still was more plenty than the fabled horn
Thrice emptied could pour forth, at banqueting
For Proserpine return'd to her own fields,
Where the white heifers low. And appetite
More yearning than on earth I ever felt
Growing within, I ate deliciously;
And, after not long, thirsted, for thereby
Stood a cool vessel of transparent juice
Sipp'd by the wander'd bee, the which I took,
And, pledging all the mortals of the world,
And all the dead whose names are in our lips,
Drank. That full draught is parent of my theme.
No Asian poppy nor elixir fine
Of the soon fading jealous Caliphat,
No poison gender'd in close monkish cell
To thin the scarlet conclave of old men,
Could so have rapt unwilling life away.
Among the fragrant husks and berries crush'd,
Upon the grass I struggled hard against
The domineering potion; but in vain:
The cloudy swoon came on, and down I sunk
Like a Silenus on an antique vase.
How long I slumber'd 'tis a chance to guess.
When sense of life return'd, I started up
As if with wings; but the fair trees were gone,
The mossy mound and arbour were no more:
I look'd around upon the carved sides
Of an old sanctuary with roof august,
Builded so high, it seem'd that filmed clouds
Might spread beneath, as o'er the stars of heaven;
So old the place was, I remember'd none
The like upon the earth: what I had seen
Of grey cathedrals, buttress'd walls, rent towers,
The superannuations of sunk realms,
Or Nature's rocks toil'd hard in waves and winds,
Seem'd but the faulture of decrepit things
To that eternal domed monument.
Upon the marble at my feet there lay
Store of strange vessels and large draperies,
Which needs had been of dyed asbestos wove,
Or in that place the moth could not corrupt,
So white the linen, so, in some, distinct
Ran imageries from a sombre loom.
All in a mingled heap confus'd there lay
Robes, golden tongs, censer and chafing dish,
Girdles, and chains, and holy jewelries.
Turning from these with awe, once more I rais'd
My eyes to fathom the space every way;
The embossed roof, the silent massy range
Of columns north and south, ending in mist
Of nothing, then to eastward, where black gates
Were shut against the sunrise evermore.
Then to the west I look'd, and saw far off
An image, huge of feature as a cloud,
At level of whose feet an altar slept,
To be approach'd on either side by steps,
And marble balustrade, and patient travail
To count with toil the innumerable degrees.
Towards the altar sober paced I went,
Repressing haste, as too unholy there;
And, coming nearer, saw beside the shrine
One minist'ring; and there arose a flame.
When in mid May the sickening East wind
Shifts sudden to the south, the small warm rain
Melts out the frozen incense from all flowers,
And fills the air with so much pleasant health
That even the dying man forgets his shroud;
Even so that lofty sacrificial fire,
Sending forth Maian incense, spread around
Forgetfulness of everything but bliss,
And clouded all the altar with soft smoke,
From whose white fragrant curtains thus I heard
Language pronounc'd: 'If thou canst not ascend
'These steps, die on that marble where thou art.
'Thy flesh, near cousin to the common dust,
'Will parch for lack of nutriment thy bones
'Will wither in few years, and vanish so
'That not the quickest eye could find a grain
'Of what thou now art on that pavement cold.
'The sands of thy short life are spent this hour,
'And no hand in the universe can turn
'Thy hourglass, if these gummed leaves be burnt
'Ere thou canst mount up these immortal steps.'
I heard, I look'd: two senses both at once,
So fine, so subtle, felt the tyranny
Of that fierce threat and the hard task proposed.
Prodigious seem'd the toil, the leaves were yet
Burning when suddenly a palsied chill
Struck from the paved level up my limbs,
And was ascending quick to put cold grasp
Upon those streams that pulse beside the throat:
I shriek'd; and the sharp anguish of my shriek
Stung my own ears I strove hard to escape
The numbness; strove to gain the lowest step.
Slow, heavy, deadly was my pace: the cold
Grew stifling, suffocating, at the heart;
And when I clasp'd my hands I felt them not.
One minute before death, my iced foot touch'd
The lowest stair; and as it touch'd, life seem'd
To pour in at the toes: I mounted up,
As once fair angels on a ladder flew
From the green turf to Heaven. 'Holy Power,'
Cried I, approaching near the horned shrine,
'What am I that should so be saved from death?
'What am I that another death come not
'To choke my utterance sacrilegious here?'
Then said the veiled shadow 'Thou hast felt
'What 'tis to die and live again before
'Thy fated hour. That thou hadst power to do so
'Is thy own safety; thou hast dated on
'Thy doom.' 'High Prophetess,' said I, 'purge off,
'Benign, if so it please thee, my mind's film.'
'None can usurp this height,' return'd that shade,
'But those to whom the miseries of the world
'Are misery, and will not let them rest.
'All else who find a haven in the world,
'Where they may thoughtless sleep away their days,
'If by a chance into this fane they come,
'Rot on the pavement where thou rottedst half.'
'Are there not thousands in the world,' said I,
Encourag'd by the sooth voice of the shade,
'Who love their fellows even to the death;
'Who feel the giant agony of the world;
'And more, like slaves to poor humanity,
'Labour for mortal good? I sure should see
'Other men here; but I am here alone.'
'Those whom thou spak'st of are no vision'ries,'
Rejoin'd that voice; 'they are no dreamers weak;
'They seek no wonder but the human face,
'No music but a happy noted voice;
'They come not here, they have no thought to come;
'And thou art here, for thou art less than they:
'What benefit canst thou do, or all thy tribe,
'To the great world? Thou art a dreaming thing,
'A fever of thyself think of the Earth;
'What bliss even in hope is there for thee?
'What haven? every creature hath its home;
'Every sole man hath days of joy and pain,
'Whether his labours be sublime or low
'The pain alone; the joy alone; distinct:
'Only the dreamer venoms all his days,
'Bearing more woe than all his sins deserve.
'Therefore, that happiness be somewhat shar'd,
'Such things as thou art are admitted oft
'Into like gardens thou didst pass erewhile,
'And suffer'd in these temples: for that cause
'Thou standest safe beneath this statue's knees.'
'That I am favour'd for unworthiness,
'By such propitious parley medicin'd
'In sickness not ignoble, I rejoice,
'Aye, and could weep for love of such award.'
So answer'd I, continuing, 'If it please,
'Majestic shadow, tell me: sure not all
'Those melodies sung into the world's ear
'Are useless: sure a poet is a sage;
'A humanist, physician to all men.
'That I am none I feel, as vultures feel
'They are no birds when eagles are abroad.
'What am I then? Thou spakest of my tribe:
'What tribe?' The tall shade veil'd in drooping white
Then spake, so much more earnest, that the breath
Moved the thin linen folds that drooping hung
About a golden censer from the hand
Pendent. 'Art thou not of the dreamer tribe?
'The poet and the dreamer are distinct,
'Diverse, sheer opposite, antipodes.
'The one pours out a balm upon the world,
'The other vexes it.' Then shouted I
Spite of myself, and with a Pythia's spleen,
'Apollo! faded! O far flown Apollo!
'Where is thy misty pestilence to creep
'Into the dwellings, through the door crannies
'Of all mock lyrists, large self worshipers,
'And careless Hectorers in proud bad verse.
'Though I breathe death with them it will be life
'To see them sprawl before me into graves.
'Majestic shadow, tell me where I am,
'Whose altar this; for whom this incense curls;
'What image this whose face I cannot see,
'For the broad marble knees; and who thou art,
'Of accent feminine so courteous?'
Then the tall shade, in drooping linens veil'd,
Spoke out, so much more earnest, that her breath
Stirr'd the thin folds of gauze that drooping hung
About a golden censer from her hand
Pendent; and by her voice I knew she shed
Long treasured tears. 'This temple, sad and lone,
'Is all spar'd from the thunder of a war
'Foughten long since by giant hierarchy
'Against rebellion: this old image here,
'Whose carved features wrinkled as he fell,
'Is Saturn's; I Moneta, left supreme
'Sole priestess of this desolation.'
I had no words to answer, for my tongue,
Useless, could find about its roofed home
No syllable of a fit majesty
To make rejoinder to Moneta's mourn.
There was a silence, while the altar's blaze
Was fainting for sweet food: I look'd thereon,
And on the paved floor, where nigh were piled
Faggots of cinnamon, and many heaps
Of other crisped spice wood then again
I look'd upon the altar, and its horns
Whiten'd with ashes, and its lang'rous flame,
And then upon the offerings again;
And so by turns till sad Moneta cried,
'The sacrifice is done, but not the less
'Will I be kind to thee for thy good will.
'My power, which to me is still a curse,
'Shall be to thee a wonder; for the scenes
'Still swooning vivid through my globed brain
'With an electral changing misery
'Thou shalt with those dull mortal eyes behold,
'Free from all pain, if wonder pain thee not.'
As near as an immortal's sphered words
Could to a mother's soften, were these last:
And yet I had a terror of her robes,
And chiefly of the veils, that from her brow
Hung pale, and curtain'd her in mysteries
That made my heart too small to hold its blood.
This saw that G-ddess, and with sacred hand
Parted the veils. Then saw I a wan face,
Not pin'd by human sorrows, but bright blanch'd
By an immortal sickness which kills not;
It works a constant change, which happy death
Can put no end to; deathwards progressing
To no death was that visage; it had pass'd
The lily and the snow; and beyond these
I must not think now, though I saw that face
But for her eyes I should have fled away.
They held me back, with a benignant light
Soft mitigated by divinest lids
Half closed, and visionless entire they seem'd
Of all external things; they saw me not,
But in blank splendour beam'd like the mild moon,
Who comforts those she sees not, who knows not
What eyes are upward cast. As I had found
A grain of gold upon a mountain side,
And twing'd with avarice strain'd out my eyes
To search its sullen entrails rich with ore,
So at the view of sad Moneta's brow
I ach'd to see what things the hollow brain
Behind enwombed: what high tragedy
In the dark secret chambers of her skull
Was acting, that could give so dread a stress
To her cold lips, and fill with such a light
Her planetary eyes, and touch her voice
With such a sorrow 'Shade of Memory!'
Cried I, with act adorant at her feet,
'By all the gloom hung round thy fallen house,
'By this last temple, by the golden age,
'By great Apollo, thy dear Foster Child,
'And by thyself, forlorn divinity,
'The pale Omega of a withered race,
'Let me behold, according as thou saidst,
'What in thy brain so ferments to and fro!'
No sooner had this conjuration pass'd
My devout lips, than side by side we stood
(Like a stunt bramble by a solemn pine)
Deep in the shady sadness of a vale,
Far sunken from the healthy breath of morn,
Far from the fiery noon and eve's one star.
Onward I look'd beneath the gloomy boughs,
And saw, what first I thought an image huge,
Like to the image pedestal'd so high
In Saturn's temple. Then Moneta's voice
Came brief upon mine ear 'So Saturn sat
When he had lost his realms ' whereon there grew
A power within me of enormous ken
To see as a g-d sees, and take the depth
Of things as nimbly as the outward eye
Can size and shape pervade. The lofty theme
At those few words hung vast before my mind,
With half unravel'd web. I set myself
Upon an eagle's watch, that I might see,
And seeing ne'er forget. No stir of life
Was in this shrouded vale, not so much air
As in the zoning of a summer's day
Robs not one light seed from the feather'd grass,
But where the dead leaf fell there did it rest.
A stream went voiceless by, still deaden'd more
By reason of the fallen divinity
Spreading more shade; the Naiad 'mid her reeds
Press'd her cold finger closer to her lips.
Along the margin sand large footmarks went
No farther than to where old Saturn's feet
Had rested, and there slept, how long a sleep!
Degraded, cold, upon the sodden ground
His old right hand lay nerveless, listless, dead,
Unsceptred; and his realmless eyes were clos'd,
While his bow'd head seem'd listening to the Earth,
His ancient mother, for some comfort yet.
It seem'd no force could wake him from his place;
But there came one who with a kindred hand
Touch'd his wide shoulders after bending low
With reverence, though to one who knew it not.
Then came the griev'd voice of Mnemosyne,
And griev'd I hearken'd. 'That divinity
'Whom thou saw'st step from yon forlornest wood,
'And with slow pace approach our fallen King,
'Is Thea, softest natur'd of our brood.'
I mark'd the G-ddess in fair statuary
Surpassing wan Moneta by the head,
And in her sorrow nearer woman's tears.
There was a listening fear in her regard,
As if calamity had but begun;
As if the vanward clouds of evil days
Had spent their malice, and the sullen rear
Was with its stored thunder labouring up.
One hand she press'd upon that aching spot
Where beats the human heart, as if just there,
Though an immortal, she felt cruel pain;
The other upon Saturn's bended neck
She laid, and to the level of his hollow ear
Leaning with parted lips, some words she spake
In solemn tenor and deep organ tune;
Some mourning words, which in our feeble tongue
Would come in this like accenting; how frail
To that large utterance of the early G-ds!
'Saturn! look up and for what, poor lost King?
'I have no comfort for thee; no not one;
'I cannot cry, Wherefore thus sleepest thou?
'For Heaven is parted from thee, and the Earth
'Knows thee not, so afflicted, for a G-d;
'And Ocean too, with all its solemn noise,
'Has from thy sceptre pass'd, and all the air
'Is emptied of thine hoary majesty:
'Thy thunder, captious at the new command,
'Rumbles reluctant o'er our fallen house;
'And thy sharp lightning, in unpracticed hands,
'Scorches and burns our once serene domain.
'With such remorseless speed still come new woes,
'That unbelief has not a space to breathe.
'Saturn! sleep on: Me thoughtless, why should I
'Thus violate thy slumbrous solitude?
'Why should I ope thy melancholy eyes?
'Saturn, sleep on, while at thy feet I weep.'
As when upon a tranced summer night
Forests, branch charmed by the earnest stars,
Dream, and so dream all night without a noise,
Save from one gradual solitary gust,
Swelling upon the silence; dying off;
As if the ebbing air had but one wave;
So came these words, and went; the while in tears
She press'd her fair large forehead to the earth,
Just where her fallen hair might spread in curls
A soft and silken mat for Saturn's feet.
Long, long those two were postured motionless,
Like sculpture builded up upon the grave
Of their own power. A long awful time
I look'd upon them: still they were the same;
The frozen G-d still bending to the earth,
And the sad G-ddess weeping at his feet,
Moneta silent. Without stay or prop
But my own weak mortality, I bore
The load of this eternal quietude,
The unchanging gloom, and the three fixed shapes
Ponderous upon my senses, a whole moon.
For by my burning brain I measured sure
Her silver seasons shedded on the night,
And ever day by day methought I grew
More gaunt and ghostly. Oftentimes I pray'd
Intense, that Death would take me from the vale
And all its burthens gasping with despair
Of change, hour after hour I curs'd myself;
Until old Saturn rais'd his faded eyes,
And look'd around and saw his kingdom gone,
And all the gloom and sorrow of the place,
And that fair kneeling G-ddess at his feet.
As the moist scent of flowers, and grass, and leaves
Fills forest dells with a pervading air,
Known to the woodland nostril, so the words
Of Saturn fill'd the mossy glooms around,
Even to the hollows of time eaten oaks
And to the windings of the foxes' hole,
With sad low tones, while thus he spake, and sent
Strange musings to the solitary Pan.
'Moan, brethren, moan; for we are swallow'd up
'And buried from all G-dlike exercise
'Of influence benign on planets pale,
'And peaceful sway above man's harvesting,
'And all those acts which Deity supreme
'Doth ease its heart of love in. Moan and wail,
'Moan, brethren, moan; for lo, the rebel spheres
'Spin round, the stars their ancient courses keep,
'Clouds still with shadowy moisture haunt the earth,
'Still suck their fill of light from sun and moon,
'Still buds the tree, and still the sea shores murmur;
'There is no death in all the Universe,
'No smell of death there shall be death Moan, moan,
'Moan, Cybele, moan; for thy pernicious babes
'Have changed a G-d into a shaking Palsy.
'Moan, brethren, moan, for I have no strength left,
'Weak as the reed weak feeble as my voice
'O, O, the pain, the pain of feebleness.
'Moan, moan, for still I thaw or give me help;
'Throw down those imps, and give me victory.
'Let me hear other groans, and trumpets blown
'Of triumph calm, and hymns of festival
'From the gold peaks of Heaven's high piled clouds;
'Voices of soft proclaim, and silver stir
'Of strings in hollow shells; and let there be
'Beautiful things made new, for the surprise
'Of the sky children.' So he feebly ceas'd,
With such a poor and sickly sounding pause,
Methought I heard some old man of the earth
Bewailing earthly loss; nor could my eyes
And ears act with that pleasant unison of sense
Which marries sweet sound with the grace of form,
And dolorous accent from a tragic harp
With large limb'd visions. More I scrutinized:
Still fix'd he sat beneath the sable trees,
Whose arms spread straggling in wild serpent forms,
With leaves all hush'd; his awful presence there
(Now all was silent) gave a deadly lie
To what I erewhile heard only his lips
Trembled amid the white curls of his beard.
They told the truth, though, round, the snowy locks
Hung nobly, as upon the face of heaven
A mid day fleece of clouds. Thea arose,
And stretched her white arm through the hollow dark,
Pointing some whither: whereat he too rose
Like a vast giant, seen by men at sea
To grow pale from the waves at dull midnight.
They melted from my sight into the woods;
Ere I could turn, Moneta cried, 'These twain
'Are speeding to the families of grief,
'Where roof'd in by black rocks they waste, in pain
'And darkness, for no hope.' And she spake on,
As ye may read who can unwearied pass
Onward from the antechamber of this dream,
Where even at the open doors awhile
I must delay, and glean my memory
Of her high phrase: perhaps no further dare.
CANTO II
'Mortal, that thou may'st understand aright,
'I humanize my sayings to thine ear,
'Making comparisons of earthly things;
'Or thou might'st better listen to the wind,
'Whose language is to thee a barren noise,
'Though it blows legend laden through the trees.
'In melancholy realms big tears are shed,
'More sorrow like to this, and such like woe,
'Too huge for mortal tongue, or pen of scribe.
'The Titans fierce, self hid or prison bound,
'Groan for the old allegiance once more,
'Listening in their doom for Saturn's voice.
'But one of our whole eagle brood still keeps
'His sov'reignty, and rule, and majesty;
'Blazing Hyperion on his orbed fire
'Still sits, still snuffs the incense teeming up
'From man to the sun's G-d: yet unsecure,
'For as upon the earth dire prodigies
'Fright and perplex, so also shudders he:
'Nor at dog's howl or gloom bird's Even screech,
'Or the familiar visitings of one
'Upon the first toll of his passing bell:
'But horrors, portioned to a giant nerve,
'Make great Hyperion ache. His palace bright,
'Bastion'd with pyramids of glowing gold,
'And touch'd with shade of bronzed obelisks,
'Glares a blood red through all the thousand courts,
'Arches, and domes, and fiery galleries:
'And all its curtains of Aurorian clouds
'Flush angerly; when he would taste the wreaths
'Of incense breath'd aloft from sacred hills,
'Instead of sweets his ample palate takes
'Savour of poisonous brass and metals sick.
'Wherefore when harbour'd in the sleepy West,
'After the full completion of fair day,
'For rest divine upon exalted couch
'And slumber in the arms of melody,
'He paces through the pleasant hours of ease
'With strides colossal, on from hall to hall;
'While far within each aisle and deep recess
'His winged minions in close clusters stand
'Amaz'd, and full of fear; like anxious men,
'Who on a wide plain gather in sad troops,
'When earthquakes jar their battlements and towers.
'Even now, while Saturn, roused from icy trance,
'Goes step for step with Thea from yon woods,
'Hyperion, leaving twilight in the rear,
'Is sloping to the threshold of the West.
'Thither we tend.' Now in clear light I stood,
Reliev'd from the dusk vale. Mnemosyne
Was sitting on a square edg'd polish'd stone,
That in its lucid depth reflected pure
Her priestess garments. My quick eyes ran on
From stately nave to nave, from vault to vault,
Through bow'rs of fragrant and enwreathed light
And diamond paved lustrous long arcades.
Anon rush'd by the bright Hyperion;
His flaming robes stream'd out beyond his heels,
And gave a roar, as if of earthly fire,
That scared away the meek ethereal hours
And made their dove wings tremble. On he flared.
THE END

View file

@ -0,0 +1,28 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/stdio/stdio.h"
#include "libc/testlib/testlib.h"
void testlib_incrementfailed(void) {
if (++g_testlib_failed > 23) {
fprintf(stderr, "too many failures, aborting\n");
testlib_abort();
}
}

45
libc/testlib/runner.c Normal file
View file

@ -0,0 +1,45 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/calls.h"
#include "libc/log/log.h"
#include "libc/nexgen32e/nexgen32e.h"
#include "libc/runtime/missioncritical.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/testlib/testlib.h"
/**
* Runs all TEST(), FIXTURE(), etc. recorded by ld.
* @see libc/testlib/testlib.h
* @see ape/ape.lds
*/
testonly void testlib_runalltests(void) {
if ((intptr_t)__testcase_end > (intptr_t)__testcase_start) {
if (testlib_countfixtures(__combo_start, __combo_end)) {
testlib_runcombos(__testcase_start, __testcase_end, __combo_start,
__combo_end);
} else {
testlib_runtestcases(__testcase_start, __testcase_end, NULL);
testlib_runfixtures(__testcase_start, __testcase_end, __fixture_start,
__fixture_end);
testlib_finish();
}
}
}

View file

@ -0,0 +1,22 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/testlib/testlib.h"
bool g_testlib_shoulddebugbreak;

49
libc/testlib/showerror.c Normal file
View file

@ -0,0 +1,49 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/calls/internal.h"
#include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/log/internal.h"
#include "libc/log/log.h"
#include "libc/math.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/testlib/testlib.h"
testonly void testlib_showerror(const char *file, int line, const char *func,
const char *method, const char *symbol,
const char *code, char *v1, char *v2) {
/* TODO(jart): Pay off tech debt re duplication */
getpid$sysv(); /* make strace easier to read */
getpid$sysv();
fprintf(stderr,
"%s%s%s%s:%s:%d%s: %s() %s %s(%s)\n"
"\t%s\n"
"\t\t%s %s %s\n"
"\t\t%s %s\n"
"\t%s%s\n"
"\t%s%s\n",
RED2, "error", UNBOLD, BLUE1, file, line, RESET, method, "in", func,
g_fixturename, code, "want", v1, symbol, " got", v2, SUBTLE,
strerror(errno), program_invocation_name, RESET);
free_s(&v1);
free_s(&v2);
}

90
libc/testlib/showerror_.c Normal file
View file

@ -0,0 +1,90 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/safemacros.h"
#include "libc/calls/internal.h"
#include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/log/internal.h"
#include "libc/log/log.h"
#include "libc/math.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/testlib/testlib.h"
STATIC_YOINK("isfdkind");
const char *testlib_showerror_errno;
const char *testlib_showerror_file;
const char *testlib_showerror_func;
const char *testlib_showerror_isfatal;
const char *testlib_showerror_macro;
const char *testlib_showerror_symbol;
testonly void testlib_showerror_(int line, const char *wantcode,
const char *gotcode, char *FREED_want,
char *FREED_got, const char *fmt, ...) {
va_list va;
getpid$sysv(); /* make strace easier to read */
getpid$sysv();
fflush(stdout);
fflush(stderr);
/* TODO(jart): Pay off tech debt re duplication */
fprintf(stderr, "%s%s%s%s:%s:%d%s: %s(%s)\n\t%s(%s", RED2, "error", UNBOLD,
BLUE1, testlib_showerror_file, line, RESET, testlib_showerror_func,
g_fixturename, testlib_showerror_macro, wantcode);
if (wantcode) {
fprintf(stderr,
", %s)\n"
"\t\t%s %s %s\n"
"\t\t%s %s\n",
gotcode, "want", FREED_want, testlib_showerror_symbol, " got",
FREED_got);
} else {
fprintf(stderr,
", %s)\n"
"\t\t→ %s%s\n",
gotcode, testlib_showerror_symbol, FREED_want);
}
if (!isempty(fmt)) {
fputc('\t', stderr);
va_start(va, fmt);
vfprintf(stderr, fmt, va);
va_end(va);
fputc('\n', stderr);
}
fprintf(stderr,
"\t%s%s\n"
"\t%s%s\n",
SUBTLE, strerror(errno), program_invocation_name, RESET);
free_s(&FREED_want);
free_s(&FREED_got);
++g_testlib_failed;
if (testlib_showerror_isfatal) testlib_abort();
}

30
libc/testlib/startswith.c Normal file
View file

@ -0,0 +1,30 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/str/str.h"
#include "libc/testlib/testlib.h"
testonly bool testlib_startswith(size_t cw, const void *s, const void *prefix) {
if (s == prefix) return true;
if (!s || !prefix) return false;
return cw == sizeof(wchar_t)
? wcsstartswith(s, prefix)
: cw == sizeof(char16_t) ? startswith16(s, prefix)
: startswith(s, prefix);
}

View file

@ -0,0 +1,36 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/limits.h"
#include "libc/str/str.h"
#include "libc/testlib/testlib.h"
testonly bool testlib_strcaseequals(size_t cw, const void *s1, const void *s2) {
return testlib_strncaseequals(cw, s1, s2, SIZE_MAX);
}
testonly bool testlib_strncaseequals(size_t cw, const void *s1, const void *s2,
size_t n) {
if (s1 == s2) return true;
if (!s1 || !s2) return false;
return (cw == sizeof(wchar_t)
? wcsncasecmp(s1, s2, n)
: cw == sizeof(char16_t) ? strncasecmp16(s1, s2, n)
: strncasecmp(s1, s2, n)) == 0;
}

36
libc/testlib/strequals.c Normal file
View file

@ -0,0 +1,36 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/limits.h"
#include "libc/str/str.h"
#include "libc/testlib/testlib.h"
testonly bool testlib_strequals(size_t cw, const void *s1, const void *s2) {
return testlib_strnequals(cw, s1, s2, SIZE_MAX);
}
testonly bool testlib_strnequals(size_t cw, const void *s1, const void *s2,
size_t n) {
if (s1 == s2) return true;
if (!s1 || !s2) return false;
return (cw == sizeof(wchar_t)
? wcsncmp(s1, s2, n)
: cw == sizeof(char16_t) ? strncmp16(s1, s2, n)
: strncmp(s1, s2, n)) == 0;
}

41
libc/testlib/testcase.S Normal file
View file

@ -0,0 +1,41 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
.yoink __FILE__
/ Decentralized section for test testcase registration.
/
/ @see ape/ape.lds
.section .piro.relo.sort.testcase.1,"aw",@nobits
.type __testcase_start,@object
.type __testcase_end,@object
.globl __testcase_start,__testcase_end
.hidden __testcase_start,__testcase_end
.byte 0
.align __SIZEOF_POINTER__
__testcase_start:
.previous/*
...
decentralized content
...
*/.section .piro.relo.sort.testcase.3,"aw",@nobits
__testcase_end:
.quad 0
.previous

631
libc/testlib/testlib.h Normal file
View file

@ -0,0 +1,631 @@
#ifndef COSMOPOLITAN_LIBC_TESTLIB_H_
#define COSMOPOLITAN_LIBC_TESTLIB_H_
#include "libc/bits/bits.h"
#include "libc/runtime/gc.h"
#include "libc/testlib/ugly.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § testing library
*/
/**
* Declares test case function.
*
* Test cases are guaranteed by the linker to be run in order, sorted by
* the (SUITE, NAME) tuple passed here.
*/
#define TEST(SUITE, NAME) __TEST_PROTOTYPE(SUITE, NAME, __TEST_ARRAY)
/**
* Declares function that globally modifies program state.
*
* All tests will be run an additional time, for each fixture. Fixtures
* are useful, for example, when multiple implementations of a function
* exist. Memory protections, on sections such as .initbss, are removed
* temorarilly by the runtime while calling fixture functions. Fixtures
* are also guaranteed by the linker to be run in sorted order.
*/
#define FIXTURE(SUITE, NAME) __FIXTURE("fixture", SUITE, NAME)
/**
* Registers explosive fixture with linker.
*
* All tests will run an additional time for each set of entries in the
* Cartesian product of groups. That makes this similar to fixture, but
* more appropriate for testing pure code (i.e. no syscalls) like math.
*/
#define COMBO(GROUP, ENTRY) __FIXTURE("combo", GROUP, ENTRY)
/**
* Declares benchmark function.
*
* These only run if (1) the -b flag is passed to the FOO_test.com; and
* (2) the unit tests passed. It's just an ordinary function, that gets
* registered with the linker. It should print things to stdout.
*
* @see EZBENCH()
*/
#define BENCH(SUITE, NAME) \
STATIC_YOINK("__bench_start"); \
__TEST_PROTOTYPE(SUITE, NAME, __BENCH_ARRAY)
#define ASSERT_GE(C, X) _TEST2("ASSERT_GE", C, >=, (X), #C, " ≥ ", #X, 1)
#define ASSERT_GT(C, X) _TEST2("ASSERT_GT", C, >, (X), #C, " > ", #X, 1)
#define ASSERT_LE(C, X) _TEST2("ASSERT_LE", C, <=, (X), #C, " ≤ ", #X, 1)
#define ASSERT_LT(C, X) _TEST2("ASSERT_LT", C, <, (X), #C, " < ", #X, 1)
#define EXPECT_GE(C, X) _TEST2("EXPECT_GE", C, >=, (X), #C, " ≥ ", #X, 0)
#define EXPECT_GT(C, X) _TEST2("EXPECT_GT", C, >, (X), #C, " > ", #X, 0)
#define EXPECT_LE(C, X) _TEST2("EXPECT_LE", C, <=, (X), #C, " ≤ ", #X, 0)
#define EXPECT_LT(C, X) _TEST2("EXPECT_LT", C, <, (X), #C, " < ", #X, 0)
#define _TEST2(NAME, WANT, OP, GOT, WANTCODE, OPSTR, GOTCODE, ISFATAL) \
do { \
autotype(WANT) Want = (WANT); \
autotype(GOT) Got = (GOT); \
if (!(Want OP Got)) { \
testlib_showerror(FILIFU NAME, OPSTR, WANTCODE OPSTR GOTCODE, \
testlib_formatint(Want), testlib_formatint(Got)); \
testlib_onfail2(ISFATAL); \
} \
} while (0)
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § testing library » assert or die
*/
#define EXPECT_TRUE(X) _TEST2("EXPECT_TRUE", true, ==, (X), #X, "", "", 0)
#define EXPECT_FALSE(X) _TEST2("EXPECT_FALSE", false, ==, (X), #X, "", "", 0)
#define ASSERT_TRUE(X) _TEST2("ASSERT_TRUE", true, ==, (X), #X, "", "", 1)
#define ASSERT_FALSE(X) _TEST2("ASSERT_FALSE", false, ==, (X), #X, "", "", 1)
#define ASSERT_EQ(WANT, GOT, ...) \
__TEST_EQ(assert, __FILE__, __LINE__, __FUNCTION__, #WANT, #GOT, WANT, GOT, \
__VA_ARGS__)
#define EXPECT_EQ(WANT, GOT, ...) \
__TEST_EQ(expect, __FILE__, __LINE__, __FUNCTION__, #WANT, #GOT, WANT, GOT, \
__VA_ARGS__)
#define __TEST_EQ(KIND, FILE, LINE, FUNC, WANTCODE, GOTCODE, WANT, GOT, ...) \
({ \
autotype(GOT) Got = _I(GOT); \
typeof(Got) Want = _I(WANT); \
testlib_ontest(); \
if (Want != Got) { \
TESTLIB_ONFAIL(FILE, FUNC); \
TESTLIB_SHOWERROR(testlib_showerror_##KIND##_eq, LINE, WANTCODE, \
GOTCODE, testlib_formatint(_I(Want)), \
testlib_formatint(_I(Got)), "" __VA_ARGS__); \
} \
(void)0; \
})
#define ASSERT_NE(WANT, GOT, ...) \
__TEST_NE(assert, __FILE__, __LINE__, __FUNCTION__, #WANT, #GOT, WANT, GOT, \
__VA_ARGS__)
#define EXPECT_NE(WANT, GOT, ...) \
__TEST_NE(expect, __FILE__, __LINE__, __FUNCTION__, #WANT, #GOT, WANT, GOT, \
__VA_ARGS__)
#define __TEST_NE(KIND, FILE, LINE, FUNC, WANTCODE, GOTCODE, WANT, GOT, ...) \
({ \
autotype(GOT) Got = (GOT); \
typeof(Got) Want = (WANT); \
testlib_ontest(); \
if (Want == Got) { \
TESTLIB_ONFAIL(FILE, FUNC); \
TESTLIB_SHOWERROR(testlib_showerror_##KIND##_ne, LINE, WANTCODE, \
GOTCODE, testlib_formatint(_I(Want)), \
testlib_formatint(_I(Got)), "" __VA_ARGS__); \
} \
(void)0; \
})
#define ASSERT_BETWEEN(BEG, END, GOT) \
assertBetween(FILIFU _I(BEG), _I(END), _I(GOT), \
#BEG " <= " #GOT " <= " #END, true)
#define ASSERT_STREQ(WANT, GOT) \
assertStringEquals(FILIFU sizeof(*(WANT)), WANT, GOT, #GOT, true)
#define ASSERT_STRNE(NOPE, GOT) \
assertStringNotEquals(FILIFU sizeof(*(NOPE)), NOPE, GOT, #GOT, true)
#define ASSERT_STREQN(WANT, GOT, N) \
assertStrnEquals(FILIFU sizeof(*(WANT)), WANT, GOT, N, #GOT, true)
#define ASSERT_STRNEN(NOPE, GOT, N) \
assertStrnNotEquals(FILIFU sizeof(*(NOPE)), NOPE, GOT, N, #GOT, true)
#define ASSERT_STRCASEEQ(WANT, GOT) \
assertStringCaseEquals(FILIFU sizeof(*(WANT)), WANT, GOT, #GOT, true)
#define ASSERT_STRCASENE(NOPE, GOT) \
assertStringCaseNotEquals(FILIFU sizeof(*(NOPE)), NOPE, GOT, #GOT, true)
#define ASSERT_STRNCASEEQ(WANT, GOT, N) \
assertStrnCaseEquals(FILIFU sizeof(*(WANT)), WANT, GOT, N, #GOT, true)
#define ASSERT_STRNCASENE(NOPE, GOT, N) \
assertStrnCaseNotEquals(FILIFU sizeof(*(NOPE)), NOPE, GOT, N, #GOT, true)
#define ASSERT_STARTSWITH(PREFIX, GOT) \
assertStartsWith(FILIFU sizeof(*(PREFIX)), PREFIX, GOT, #GOT, true)
#define ASSERT_ENDSWITH(SUFFIX, GOT) \
assertEndsWith(FILIFU sizeof(*(SUFFIX)), SUFFIX, GOT, #GOT, true)
#define ASSERT_IN(NEEDLE, GOT) \
assertContains(FILIFU sizeof(*(NEEDLE)), NEEDLE, GOT, #GOT, true)
#define ASSERT_BINEQ(WANT, GOT) \
_Generic((WANT)[0], char \
: assertBinaryEquals$hex, default \
: assertBinaryEquals$cp437)(FILIFU WANT, GOT, -1, #GOT, true)
#define ASSERT_BINNE(NOPE, GOT) \
_Generic((NOPE)[0], char \
: assertBinaryNotEquals$hex, default \
: assertBinaryNotEquals$cp437)(FILIFU NOPE, GOT, -1, #GOT, true)
#define ASSERT_BINEQN(WANT, GOT, N) \
_Generic((WANT)[0], char \
: assertBinaryEquals$hex, default \
: assertBinaryEquals$cp437)(FILIFU WANT, GOT, N, #GOT, true)
#define ASSERT_BINNEN(NOPE, GOT, N) \
_Generic((NOPE)[0], char \
: assertBinaryNotEquals$hex, default \
: assertBinaryNotEquals$cp437)(FILIFU NOPE, GOT, -1, #GOT, true)
#define ASSERT_FLOAT_EQ(WANT, GOT) \
assertLongDoubleEquals(FILIFU WANT, GOT, #GOT, true)
#define ASSERT_DOUBLE_EQ(WANT, GOT) \
assertLongDoubleEquals(FILIFU WANT, GOT, #GOT, true)
#define ASSERT_LDBL_EQ(WANT, GOT) \
assertLongDoubleEquals(FILIFU WANT, GOT, #GOT, true)
#define ASSERT_LDBL_GT(VAL, GOT) \
assertLongDoubleGreaterThan(VAL, GOT, #VAL " > " #GOT, true)
#define ASSERT_LDBL_LT(VAL, GOT) \
assertLongDoubleLessThan(VAL, GOT, #VAL " < " #GOT, true)
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § testing library » assert or log
*/
#define EXPECT_BETWEEN(BEG, END, GOT) \
assertBetween(FILIFU _I(BEG), _I(END), _I(GOT), \
#BEG " <= " #GOT " <= " #END, false)
#define EXPECT_STREQ(WANT, GOT) \
assertStringEquals(FILIFU sizeof(*(WANT)), WANT, GOT, #GOT, false)
#define EXPECT_STRNE(NOPE, GOT) \
assertStringNotEquals(FILIFU sizeof(*(NOPE)), NOPE, GOT, #GOT, false)
#define EXPECT_STREQN(WANT, GOT, N) \
assertStrnEquals(FILIFU sizeof(*(WANT)), WANT, GOT, N, #GOT, false)
#define EXPECT_STRNEN(NOPE, GOT, N) \
assertStrnNotEquals(FILIFU sizeof(*(NOPE)), NOPE, GOT, N, #GOT, false)
#define EXPECT_STRCASEEQ(WANT, GOT) \
assertStringCaseEquals(FILIFU sizeof(*(WANT)), WANT, GOT, #GOT, false)
#define EXPECT_STRCASENE(NOPE, GOT) \
assertStringCaseNotEquals(FILIFU sizeof(*(NOPE)), NOPE, GOT, #GOT, false)
#define EXPECT_STRNCASEEQ(WANT, GOT, N) \
assertStrnCaseEquals(FILIFU sizeof(*(WANT)), WANT, GOT, N, #GOT, false)
#define EXPECT_STRNCASENE(NOPE, GOT, N) \
assertStrnCaseNotEquals(FILIFU sizeof(*(NOPE)), NOPE, GOT, N, #GOT, false)
#define EXPECT_STARTSWITH(PREFIX, GOT) \
assertStartsWith(FILIFU sizeof(*(PREFIX)), PREFIX, GOT, #GOT, false)
#define EXPECT_ENDSWITH(SUFFIX, GOT) \
assertEndsWith(FILIFU sizeof(*(SUFFIX)), SUFFIX, GOT, #GOT, false)
#define EXPECT_IN(NEEDLE, GOT) \
assertContains(FILIFU sizeof(*(NEEDLE)), NEEDLE, GOT, #GOT, false)
#define EXPECT_BINEQ(WANT, GOT) \
_Generic((WANT)[0], char \
: assertBinaryEquals$hex, default \
: assertBinaryEquals$cp437)(FILIFU WANT, GOT, -1, #GOT, false)
#define EXPECT_BINNE(NOPE, GOT) \
_Generic((NOPE)[0], char \
: assertBinaryNotEquals$hex, default \
: assertBinaryNotEquals$cp437)(FILIFU NOPE, GOT, -1, #GOT, false)
#define EXPECT_BINEQN(WANT, GOT, N) \
_Generic((WANT)[0], char \
: assertBinaryEquals$hex, default \
: assertBinaryEquals$cp437)(FILIFU WANT, GOT, N, #GOT, false)
#define EXPECT_BINNEN(NOPE, GOT, N) \
_Generic((NOPE)[0], char \
: assertBinaryNotEquals$hex, default \
: assertBinaryNotEquals$cp437)(FILIFU NOPE, GOT, -1, #GOT, false)
#define EXPECT_FLOAT_EQ(WANT, GOT) \
assertLongDoubleEquals(FILIFU WANT, GOT, #GOT, false)
#define EXPECT_DOUBLE_EQ(WANT, GOT) \
assertLongDoubleEquals(FILIFU WANT, GOT, #GOT, false)
#define EXPECT_LDBL_EQ(WANT, GOT) \
assertLongDoubleEquals(FILIFU WANT, GOT, #GOT, false)
#define EXPECT_LGBL_GT(VAL, GOT) \
expectLongDoubleGreaterThan(VAL, GOT, #VAL " > " #GOT, false)
#define EXPECT_LGBL_LT(VAL, GOT) \
expectLongDoubleLessThan(VAL, GOT, #VAL " < " #GOT, false)
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § testing library » hardware-accelerated memory safety
*/
typedef void (*testfn_t)(void);
struct TestFixture {
const char *group;
const char *name;
testfn_t fn;
};
struct TestAllocation {
void *mapaddr;
size_t mapsize;
void *useraddr;
size_t usersize;
};
struct TestMemoryStack {
size_t i;
size_t n;
struct TestAllocation *p;
};
extern struct TestMemoryStack g_testmem;
void tfree(void *) paramsnonnull();
void *tmalloc(size_t) returnsnonnull returnspointerwithnoaliases nodiscard
attributeallocsize((1)) returnsaligned((1));
void *tmemalign(size_t,
size_t) returnsnonnull returnspointerwithnoaliases nodiscard
attributeallocsize((2)) libcesque attributeallocalign((1));
char *tstrdup(const char *) returnsnonnull returnspointerwithnoaliases nodiscard
returnsaligned((1));
void *tunbing(const char16_t *)
paramsnonnull() returnsnonnull returnspointerwithnoaliases nodiscard
returnsaligned((1));
void *tunbinga(size_t, const char16_t *)
paramsnonnull() returnsnonnull returnspointerwithnoaliases nodiscard
attributeallocalign((1));
#define tgc(TMEM) \
({ \
void *Res; \
/* volatile b/c testmem only lifo atm */ \
asm volatile("" ::: "memory"); \
Res = defer((tfree), (TMEM)); \
asm volatile("" ::: "memory"); \
Res; \
})
#define tfree(P) \
do { \
__tfree_check(P); \
(tfree)(P); \
} while (0)
#define __tfree_check(P) \
ASSERT_BETWEEN(g_testmem.p[g_testmem.i - 1].useraddr, \
((char *)g_testmem.p[g_testmem.i - 1].useraddr + \
g_testmem.p[g_testmem.i - 1].usersize), \
P)
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § testing library » implementation details
*/
#define FILIFU __FILE__, __LINE__, __FUNCTION__,
#define FILIFU_OBJ(...) __FILE__, __LINE__, ##__VA_ARGS__
#define FILIFU_ARGS const char *file, int line, const char *func,
#define FILIFU_FROM(OBJ) (OBJ)->file, (OBJ)->line, __FUNCTION__,
#define FILIFU_FIELDS \
const char *file; \
int line
extern char g_fixturename[256];
extern bool g_testlib_shoulddebugbreak; /* set by testmain */
extern unsigned g_testlib_ran; /* set by wrappers */
extern unsigned g_testlib_failed; /* set by wrappers */
extern const char *testlib_showerror_errno; /* set by macros */
extern const char *testlib_showerror_file; /* set by macros */
extern const char *testlib_showerror_func; /* set by macros */
extern const testfn_t __bench_start[], __bench_end[];
extern const testfn_t __testcase_start[], __testcase_end[];
extern const struct TestFixture __fixture_start[], __fixture_end[];
extern const struct TestFixture __combo_start[], __combo_end[];
#define TESTLIB_ONFAIL(FILE, FUNC) \
if (g_testlib_shoulddebugbreak) DebugBreak(); \
testlib_showerror_file = FILE; \
testlib_showerror_func = FUNC
#define TESTLIB_SHOWERROR(THUNK, ...) \
(((typeof(&testlib_showerror_))strongaddr(#THUNK)))(__VA_ARGS__)
void testlib_showerror_(int line, const char *wantcode, const char *gotcode,
char *FREED_want, char *FREED_got, const char *fmt,
...) relegated;
void testlib_showerror(const char *file, int line, const char *func,
const char *method, const char *symbol, const char *code,
char *v1, char *v2);
void thrashcodecache(void);
void testlib_finish(void);
void testlib_runalltests(void);
void testlib_runallbenchmarks(void);
void testlib_runtestcases(testfn_t *, testfn_t *, testfn_t);
void testlib_runcombos(testfn_t *, testfn_t *, const struct TestFixture *,
const struct TestFixture *);
void testlib_runfixtures(testfn_t *, testfn_t *, const struct TestFixture *,
const struct TestFixture *);
int testlib_countfixtures(const struct TestFixture *,
const struct TestFixture *);
void testlib_abort(void) noreturn relegated;
bool testlib_strequals(size_t, const void *, const void *) nosideeffect;
bool testlib_strnequals(size_t, const void *, const void *,
size_t) nosideeffect;
bool testlib_strcaseequals(size_t, const void *, const void *) nosideeffect;
bool testlib_strncaseequals(size_t, const void *, const void *,
size_t) nosideeffect;
void testlib_free(void *);
bool testlib_binequals(const char16_t *, const void *, size_t) nosideeffect;
bool testlib_hexequals(const char *, const void *, size_t) nosideeffect;
bool testlib_startswith(size_t, const void *, const void *) nosideeffect;
bool testlib_endswith(size_t, const void *, const void *) nosideeffect;
bool testlib_contains(size_t, const void *, const void *) nosideeffect;
char *testlib_formatrange(intmax_t, intmax_t) mallocesque;
char *testlib_formatstr(size_t, const void *, int) mallocesque;
char *testlib_formatint(intmax_t) mallocesque;
char *testlib_formatbool(bool);
char *testlib_formatfloat(long double) mallocesque;
void testlib_formatbinaryashex(const char *, const void *, size_t, char **,
char **);
void testlib_formatbinaryasglyphs(const char16_t *, const void *, size_t,
char **, char **);
bool testlib_almostequallongdouble(long double, long double);
void testlib_incrementfailed(void);
forceinline void testlib_ontest() {
YOINK(__testcase_start);
YOINK(__fixture_start);
YOINK(__combo_start);
++g_testlib_ran;
}
forceinline void testlib_onfail2(bool isfatal) {
testlib_incrementfailed();
if (isfatal) testlib_abort();
}
forceinline void assertNotEquals(FILIFU_ARGS intmax_t donotwant, intmax_t got,
const char *gotcode, bool isfatal) {
++g_testlib_ran;
if (got != donotwant) return;
if (g_testlib_shoulddebugbreak) DebugBreak();
testlib_showerror(file, line, func, "assertNotEquals", "=", gotcode,
testlib_formatint(got), testlib_formatint(donotwant));
testlib_onfail2(isfatal);
}
#define assertLongDoubleGreaterThan(a, b, code, isfatal) \
({ \
autotype(a) a_ = (a); \
autotype(b) b_ = (b); \
if (a_ <= b_) { \
testlib_showerror(FILIFU "assertLongDoubleGreaterThan", ">", code, \
testlib_formatfloat(a_), testlib_formatfloat(b_)); \
testlib_onfail2(isfatal); \
} \
(void)0; \
})
#define assertLongDoubleLessThan(a, b, code, isfatal) \
({ \
autotype(a) a_ = (a); \
autotype(b) b_ = (b); \
if (a_ >= b_) { \
testlib_showerror(FILIFU "assertLongDoubleLessThan", "<", code, \
testlib_formatfloat(a_), testlib_formatfloat(b_)); \
testlib_onfail2(isfatal); \
} \
(void)0; \
})
forceinline void assertBetween(FILIFU_ARGS intmax_t beg, intmax_t end,
intmax_t got, const char *gotcode,
bool isfatal) {
++g_testlib_ran;
if (beg <= got && got <= end) return;
if (g_testlib_shoulddebugbreak) DebugBreak();
testlib_showerror(file, line, func, "assertBetween", "", gotcode,
testlib_formatint(got), testlib_formatrange(beg, end));
testlib_onfail2(isfatal);
}
forceinline void assertStringEquals(FILIFU_ARGS size_t cw, const void *want,
const void *got, const char *gotcode,
bool isfatal) {
++g_testlib_ran;
if (testlib_strequals(cw, want, got)) return;
if (g_testlib_shoulddebugbreak) DebugBreak();
testlib_showerror(file, line, func, "assertStringEquals", "", gotcode,
testlib_formatstr(cw, want, -1),
testlib_formatstr(cw, got, -1));
testlib_onfail2(isfatal);
}
forceinline void assertStringNotEquals(FILIFU_ARGS size_t cw, const void *want,
const void *got, const char *gotcode,
bool isfatal) {
++g_testlib_ran;
if (!testlib_strequals(cw, want, got)) return;
if (g_testlib_shoulddebugbreak) DebugBreak();
testlib_showerror(file, line, func, "assertStringNotEquals", "=", gotcode,
testlib_formatstr(cw, want, -1),
testlib_formatstr(cw, got, -1));
testlib_onfail2(isfatal);
}
forceinline void assertStrnEquals(FILIFU_ARGS size_t cw, const void *want,
const void *got, size_t n,
const char *gotcode, bool isfatal) {
++g_testlib_ran;
if (testlib_strnequals(cw, want, got, n)) return;
if (g_testlib_shoulddebugbreak) DebugBreak();
testlib_showerror(file, line, func, "assertStrnEquals", "", gotcode,
testlib_formatstr(cw, got, n),
testlib_formatstr(cw, want, n));
testlib_onfail2(isfatal);
}
forceinline void assertStrnNotEquals(FILIFU_ARGS size_t cw, const void *want,
const void *got, size_t n,
const char *gotcode, bool isfatal) {
++g_testlib_ran;
if (!testlib_strnequals(cw, want, got, n)) return;
if (g_testlib_shoulddebugbreak) DebugBreak();
testlib_showerror(file, line, func, "assertStrnNotEquals", "=", gotcode,
testlib_formatstr(cw, got, n),
testlib_formatstr(cw, want, n));
testlib_onfail2(isfatal);
}
forceinline void assertStringCaseEquals(FILIFU_ARGS size_t cw, const void *want,
const void *got, const char *gotcode,
bool isfatal) {
++g_testlib_ran;
if (testlib_strcaseequals(cw, want, got)) return;
if (g_testlib_shoulddebugbreak) DebugBreak();
testlib_showerror(file, line, func, "assertStringCaseEquals", "", gotcode,
testlib_formatstr(cw, got, -1),
testlib_formatstr(cw, want, -1));
testlib_onfail2(isfatal);
}
forceinline void assertStringCaseNotEquals(FILIFU_ARGS size_t cw,
const void *want, const void *got,
const char *gotcode, bool isfatal) {
++g_testlib_ran;
if (!testlib_strcaseequals(cw, want, got)) return;
if (g_testlib_shoulddebugbreak) DebugBreak();
testlib_showerror(file, line, func, "assertStringCaseNotEquals", "=", gotcode,
testlib_formatstr(cw, got, -1),
testlib_formatstr(cw, want, -1));
testlib_onfail2(isfatal);
}
forceinline void assertStrnCaseEquals(FILIFU_ARGS size_t cw, const void *want,
const void *got, size_t n,
const char *gotcode, bool isfatal) {
++g_testlib_ran;
if (testlib_strncaseequals(cw, want, got, n)) return;
if (g_testlib_shoulddebugbreak) DebugBreak();
testlib_showerror(file, line, func, "assertStrnCaseEquals", "", gotcode,
testlib_formatstr(cw, got, n),
testlib_formatstr(cw, want, n));
testlib_onfail2(isfatal);
}
forceinline void assertStrnCaseNotEquals(FILIFU_ARGS size_t cw,
const void *want, const void *got,
size_t n, const char *gotcode,
bool isfatal) {
++g_testlib_ran;
if (!testlib_strncaseequals(cw, want, got, n)) return;
if (g_testlib_shoulddebugbreak) DebugBreak();
testlib_showerror(file, line, func, "assertStrnCaseNotEquals", "=", gotcode,
testlib_formatstr(cw, got, n),
testlib_formatstr(cw, want, n));
testlib_onfail2(isfatal);
}
forceinline void assertStartsWith(FILIFU_ARGS size_t cw, const char *prefix,
const char *s, const char *gotcode,
bool isfatal) {
++g_testlib_ran;
if (testlib_startswith(cw, s, prefix)) return;
if (g_testlib_shoulddebugbreak) DebugBreak();
testlib_showerror(file, line, func, "assertStartsWith", "", gotcode,
testlib_formatstr(1, s, -1),
testlib_formatstr(1, prefix, -1));
testlib_onfail2(isfatal);
}
forceinline void assertEndsWith(FILIFU_ARGS size_t cw, const char *suffix,
const char *s, const char *gotcode,
bool isfatal) {
++g_testlib_ran;
if (testlib_endswith(cw, s, suffix)) return;
if (g_testlib_shoulddebugbreak) DebugBreak();
testlib_showerror(file, line, func, "assertEndsWith", "", gotcode,
testlib_formatstr(1, s, -1),
testlib_formatstr(1, suffix, -1));
testlib_onfail2(isfatal);
}
forceinline void assertContains(FILIFU_ARGS size_t cw, const char *needle,
const char *s, const char *gotcode,
bool isfatal) {
++g_testlib_ran;
if (testlib_contains(cw, s, needle)) return;
if (g_testlib_shoulddebugbreak) DebugBreak();
testlib_showerror(file, line, func, "assertContains", "", gotcode,
testlib_formatstr(1, s, -1),
testlib_formatstr(1, needle, -1));
testlib_onfail2(isfatal);
}
forceinline void assertBinaryEquals$cp437(FILIFU_ARGS const char16_t *want,
const void *got, size_t n,
const char *gotcode, bool isfatal) {
++g_testlib_ran;
char *v1, *v2;
if (testlib_binequals(want, got, n)) return;
if (g_testlib_shoulddebugbreak) DebugBreak();
testlib_formatbinaryasglyphs(want, got, n, &v1, &v2);
testlib_showerror(file, line, func, "assertBinaryEquals", "", gotcode, v1,
v2);
testlib_onfail2(isfatal);
}
forceinline void assertBinaryEquals$hex(FILIFU_ARGS const char *want,
const void *got, size_t n,
const char *gotcode, bool isfatal) {
++g_testlib_ran;
char *v1, *v2;
if (testlib_hexequals(want, got, n)) return;
if (g_testlib_shoulddebugbreak) DebugBreak();
testlib_formatbinaryashex(want, got, n, &v1, &v2);
testlib_showerror(file, line, func, "assertBinaryEquals", "", gotcode, v1,
v2);
testlib_onfail2(isfatal);
}
forceinline void assertBinaryNotEquals$cp437(FILIFU_ARGS const char16_t *want,
const void *got, size_t n,
const char *gotcode,
bool isfatal) {
++g_testlib_ran;
char *v1, *v2;
if (!testlib_binequals(want, got, n)) return;
if (g_testlib_shoulddebugbreak) DebugBreak();
testlib_formatbinaryasglyphs(want, got, n, &v1, &v2);
testlib_showerror(file, line, func, "assertBinaryNotEquals", "=", gotcode, v1,
v2);
testlib_onfail2(isfatal);
}
forceinline void assertBinaryNotEquals$hex(FILIFU_ARGS const char *want,
const void *got, size_t n,
const char *gotcode, bool isfatal) {
++g_testlib_ran;
char *v1, *v2;
if (!testlib_hexequals(want, got, n)) return;
if (g_testlib_shoulddebugbreak) DebugBreak();
testlib_formatbinaryashex(want, got, n, &v1, &v2);
testlib_showerror(file, line, func, "assertBinaryNotEquals", "=", gotcode, v1,
v2);
testlib_onfail2(isfatal);
}
forceinline void assertLongDoubleEquals(FILIFU_ARGS long double want,
long double got, const char *gotcode,
bool isfatal) {
++g_testlib_ran;
if (testlib_almostequallongdouble(want, got)) return;
if (g_testlib_shoulddebugbreak) DebugBreak();
testlib_showerror(file, line, func, "assertLongDoubleEquals", "", gotcode,
testlib_formatfloat(want), testlib_formatfloat(got));
testlib_onfail2(isfatal);
}
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_TESTLIB_H_ */

197
libc/testlib/testlib.mk Normal file
View file

@ -0,0 +1,197 @@
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
# Description:
# Cosmopolitan Testing Library.
PKGS += LIBC_TESTLIB
#───────────────────────────────────────────────────────────────────────────────
LIBC_TESTLIB_ARTIFACTS += LIBC_TESTLIB_A
LIBC_TESTLIB = $(LIBC_TESTLIB_A_DEPS) $(LIBC_TESTLIB_A)
LIBC_TESTLIB_A = o/$(MODE)/libc/testlib/testlib.a
LIBC_TESTLIB_A_CHECKS = $(LIBC_TESTLIB_A).pkg
LIBC_TESTLIB_A_ASSETS = \
libc/testlib/hyperion.txt
LIBC_TESTLIB_A_HDRS = \
libc/testlib/bench.h \
libc/testlib/ezbench.h \
libc/testlib/hyperion.h \
libc/testlib/testlib.h
LIBC_TESTLIB_A_SRCS_S = \
libc/testlib/bench.S \
libc/testlib/combo.S \
libc/testlib/fixture.S \
libc/testlib/hyperion.S \
libc/testlib/testcase.S \
libc/testlib/thrashcodecache.S \
libc/testlib/thunks/assert_eq.S \
libc/testlib/thunks/assert_false.S \
libc/testlib/thunks/assert_ne.S \
libc/testlib/thunks/assert_true.S \
libc/testlib/thunks/expect_eq.S \
libc/testlib/thunks/expect_false.S \
libc/testlib/thunks/expect_ne.S \
libc/testlib/thunks/expect_true.S \
libc/testlib/thunks/free.S \
libc/testlib/thunks/jump.S
LIBC_TESTLIB_A_SRCS_C = \
libc/testlib/almostequallongdouble.c \
libc/testlib/hexequals.c \
libc/testlib/binequals.c \
libc/testlib/formatbool.c \
libc/testlib/formatrange.c \
libc/testlib/globals.c \
libc/testlib/incrementfailed.c \
libc/testlib/formatfloat.c \
libc/testlib/formatbinaryasglyphs.c \
libc/testlib/formatbinaryashex.c \
libc/testlib/formatint.c \
libc/testlib/formatstr.c \
libc/testlib/shoulddebugbreak.c \
libc/testlib/showerror.c \
libc/testlib/showerror_.c \
libc/testlib/testmem.c \
libc/testlib/strequals.c \
libc/testlib/startswith.c \
libc/testlib/endswith.c \
libc/testlib/contains.c \
libc/testlib/strcaseequals.c \
libc/testlib/benchrunner.c \
libc/testlib/testrunner.c \
libc/testlib/comborunner.c \
libc/testlib/fixturerunner.c \
libc/testlib/ezbenchreport.c \
libc/testlib/ezbenchcontrol.c
LIBC_TESTLIB_A_SRCS = \
$(LIBC_TESTLIB_A_SRCS_S) \
$(LIBC_TESTLIB_A_SRCS_C)
LIBC_TESTLIB_A_OBJS = \
$(LIBC_TESTLIB_A_SRCS:%=o/$(MODE)/%.zip.o) \
$(LIBC_TESTLIB_A_SRCS_C:%.c=o/$(MODE)/%.o) \
$(LIBC_TESTLIB_A_SRCS_S:%.S=o/$(MODE)/%.o) \
$(LIBC_TESTLIB_A_ASSETS:%=o/$(MODE)/%.zip.o)
LIBC_TESTLIB_A_DIRECTDEPS = \
APE_LIB \
LIBC_ALG \
LIBC_CALLS \
LIBC_FMT \
LIBC_LOG \
LIBC_MEM \
LIBC_NEXGEN32E \
LIBC_NT_KERNEL32 \
LIBC_RAND \
LIBC_RUNTIME \
LIBC_STDIO \
LIBC_STR \
LIBC_TIME \
LIBC_TINYMATH \
LIBC_STUBS \
LIBC_SYSV_CALLS \
LIBC_UNICODE \
LIBC_X \
LIBC_ZIPOS \
THIRD_PARTY_DTOA
LIBC_TESTLIB_A_DEPS := \
$(call uniq,$(foreach x,$(LIBC_TESTLIB_A_DIRECTDEPS),$($(x))))
$(LIBC_TESTLIB_A): \
libc/testlib/ \
$(LIBC_TESTLIB_A).pkg \
$(LIBC_TESTLIB_A_OBJS)
$(LIBC_TESTLIB_A).pkg: \
$(LIBC_TESTLIB_A_OBJS) \
$(foreach x,$(LIBC_TESTLIB_A_DIRECTDEPS),$($(x)_A).pkg)
#───────────────────────────────────────────────────────────────────────────────
LIBC_TESTLIB_ARTIFACTS += LIBC_TESTLIB_RUNNER_A
LIBC_TESTLIB_RUNNER = $(LIBC_TESTLIB_RUNNER_A_DEPS) $(LIBC_TESTLIB_RUNNER_A)
LIBC_TESTLIB_RUNNER_A = o/$(MODE)/libc/testlib/runner.a
LIBC_TESTLIB_RUNNER_A_SRCS = libc/testlib/runner.c
LIBC_TESTLIB_RUNNER_A_CHECKS = $(LIBC_TESTLIB_RUNNER_A).pkg
LIBC_TESTLIB_RUNNER_A_OBJS = \
$(LIBC_TESTLIB_RUNNER_A_SRCS:%=o/$(MODE)/%.zip.o) \
$(LIBC_TESTLIB_RUNNER_A_SRCS:%.c=o/$(MODE)/%.o)
LIBC_TESTLIB_RUNNER_A_DIRECTDEPS = \
LIBC_FMT \
LIBC_RUNTIME \
LIBC_NEXGEN32E \
LIBC_STDIO \
LIBC_STR \
LIBC_STUBS \
LIBC_TESTLIB
LIBC_TESTLIB_RUNNER_A_DEPS := \
$(call uniq,$(foreach x,$(LIBC_TESTLIB_RUNNER_A_DIRECTDEPS),$($(x))))
$(LIBC_TESTLIB_RUNNER_A): \
libc/testlib/ \
$(LIBC_TESTLIB_RUNNER_A).pkg \
$(LIBC_TESTLIB_RUNNER_A_OBJS)
$(LIBC_TESTLIB_RUNNER_A).pkg: \
$(LIBC_TESTLIB_RUNNER_A_OBJS) \
$(foreach x,$(LIBC_TESTLIB_RUNNER_A_DIRECTDEPS),$($(x)_A).pkg)
#───────────────────────────────────────────────────────────────────────────────
LIBC_TESTLIB_ARTIFACTS += LIBC_TESTMAIN
LIBC_TESTMAIN = \
$(LIBC_TESTMAIN_DEPS) \
$(LIBC_TESTMAIN_OBJS)
LIBC_TESTMAIN_CHECKS = \
o/$(MODE)/libc/testlib/testmain.pkg
LIBC_TESTMAIN_SRCS = \
libc/testlib/testmain.c
LIBC_TESTMAIN_OBJS = \
$(LIBC_TESTMAIN_SRCS:%=o/$(MODE)/%.zip.o) \
o/$(MODE)/libc/testlib/testmain.o
LIBC_TESTMAIN_DIRECTDEPS = \
LIBC_CALLS \
LIBC_LOG \
LIBC_NEXGEN32E \
LIBC_RUNTIME \
LIBC_STDIO \
LIBC_STUBS \
LIBC_SYSV \
LIBC_SYSV_CALLS \
LIBC_TESTLIB \
LIBC_TESTLIB_RUNNER \
THIRD_PARTY_GETOPT
LIBC_TESTMAIN_DEPS := \
$(call uniq,$(foreach x,$(LIBC_TESTMAIN_DIRECTDEPS),$($(x))))
o/$(MODE)/libc/testlib/testmain.pkg: \
$(LIBC_TESTMAIN_OBJS) \
$(foreach x,$(LIBC_TESTMAIN_DIRECTDEPS),$($(x)_A).pkg)
#───────────────────────────────────────────────────────────────────────────────
LIBC_TESTLIB_LIBS = $(foreach x,$(LIBC_TESTLIB_ARTIFACTS),$($(x)_A))
LIBC_TESTLIB_ARCHIVES = $(foreach x,$(LIBC_TESTLIB_ARTIFACTS),$($(x)_A))
LIBC_TESTLIB_SRCS = $(foreach x,$(LIBC_TESTLIB_ARTIFACTS),$($(x)_SRCS))
LIBC_TESTLIB_HDRS = $(foreach x,$(LIBC_TESTLIB_ARTIFACTS),$($(x)_HDRS))
LIBC_TESTLIB_CHECKS = $(foreach x,$(LIBC_TESTLIB_ARTIFACTS),$($(x)_CHECKS))
LIBC_TESTLIB_OBJS = $(foreach x,$(LIBC_TESTLIB_ARTIFACTS),$($(x)_OBJS))
$(LIBC_TESTLIB_OBJS): $(BUILD_FILES) libc/libc.mk
.PHONY: o/$(MODE)/libc/testlib
o/$(MODE)/libc/testlib: $(LIBC_TESTLIB_LIBS) $(LIBC_TESTLIB_CHECKS)

82
libc/testlib/testmain.c Normal file
View file

@ -0,0 +1,82 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/bits.h"
#include "libc/bits/safemacros.h"
#include "libc/calls/internal.h"
#include "libc/log/log.h"
#include "libc/nexgen32e/x86feature.h"
#include "libc/runtime/rbx.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/ex.h"
#include "libc/sysv/consts/exit.h"
#include "libc/testlib/testlib.h"
#include "third_party/getopt/getopt.h"
#define USAGE \
" [FLAGS]\n\
\n\
Flags:\n\
\n\
-b run benchmarks if tests pass\n\
-h show this information\n\
\n"
STATIC_YOINK("die");
static bool runbenchmarks_;
static testonly void PrintUsage(int rc, FILE *f) {
fputs("Usage: ", f);
fputs(program_invocation_name, f);
fputs(USAGE, f);
exit(rc);
}
static testonly void GetOpts(int argc, char *argv[]) {
int opt;
while ((opt = getopt(argc, argv, "?hb")) != -1) {
switch (opt) {
case 'b':
runbenchmarks_ = true;
break;
case '?':
case 'h':
PrintUsage(EXIT_SUCCESS, stdout);
default:
PrintUsage(EX_USAGE, stderr);
}
}
}
/**
* Generic test program main function.
*/
testonly int main(int argc, char *argv[]) {
g_loglevel = kLogInfo;
GetOpts(argc, argv);
showcrashreports();
g_testlib_shoulddebugbreak = IsDebuggerPresent(false);
getpid$sysv(); /* make strace easier to read */
testlib_runalltests();
if (!g_testlib_failed && runbenchmarks_ && weaken(testlib_runallbenchmarks)) {
weaken(testlib_runallbenchmarks)();
}
return min(255, g_testlib_failed);
}

185
libc/testlib/testmem.c Normal file
View file

@ -0,0 +1,185 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/assert.h"
#include "libc/bits/safemacros.h"
#include "libc/calls/calls.h"
#include "libc/dce.h"
#include "libc/fmt/bing.h"
#include "libc/limits.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/macros.h"
#include "libc/mem/mem.h"
#include "libc/runtime/sysconf.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/prot.h"
#include "libc/testlib/testlib.h"
struct TestMemoryStack g_testmem;
struct TestMemoryStack g_testmem_trash;
static struct TestAllocation g_testmem_scratch[2][8];
static const char kMemZero[1];
static bool g_atstartofpage;
static struct TestAllocation testmem_push(struct TestMemoryStack *stack,
struct TestAllocation entry) {
if (stack->i == stack->n) {
if (!grow(&stack->p, &stack->n, sizeof(struct TestAllocation), 0)) abort();
}
return (stack->p[stack->i++] = entry);
}
static struct TestAllocation testmem_pop(struct TestMemoryStack *stack) {
assert(stack->i > 0);
struct TestAllocation res = stack->p[--stack->i];
return res;
}
static void testmem_destroy(struct TestAllocation alloc) {
if (munmap(alloc.mapaddr, alloc.mapsize) == -1) perror("munmap"), die();
}
static struct TestAllocation talloc(size_t n) {
struct TestAllocation alloc;
if (n) {
while (g_testmem_trash.i) {
struct TestAllocation trash = testmem_pop(&g_testmem_trash);
if (n <= trash.usersize) {
return trash;
} else {
testmem_destroy(trash);
}
}
alloc.mapsize = ROUNDUP(n + PAGESIZE * 2, FRAMESIZE);
CHECK_NE(MAP_FAILED, (alloc.mapaddr = mapanon(alloc.mapsize)));
CHECK_NE(-1, mprotect(alloc.mapaddr, PAGESIZE, PROT_NONE));
CHECK_NE(-1, mprotect((char *)alloc.mapaddr + alloc.mapsize - PAGESIZE,
PAGESIZE, PROT_NONE));
alloc.useraddr = (char *)alloc.mapaddr + PAGESIZE;
alloc.usersize = alloc.mapsize - PAGESIZE * 2;
CHECK_GE(alloc.usersize, n);
return alloc;
} else {
alloc.mapaddr = (/*unconst*/ void *)kMemZero;
alloc.mapsize = 0;
alloc.useraddr = (/*unconst*/ void *)kMemZero;
alloc.usersize = 0;
return alloc;
}
}
static void testmem_fini(void) {
CHECK_EQ(0, g_testmem.i);
free_s(&g_testmem.p);
while (g_testmem_trash.i) {
testmem_destroy(testmem_pop(&g_testmem_trash));
}
}
static void testmem_init(void) {
atexit(testmem_fini);
g_testmem.p = g_testmem_scratch[0];
g_testmem.n = ARRAYLEN(g_testmem_scratch[0]);
g_testmem_trash.p = g_testmem_scratch[1];
g_testmem_trash.n = ARRAYLEN(g_testmem_scratch[1]);
}
const void *const testmem_ctor[] initarray = {testmem_init};
FIXTURE(testmemory, triggerOffByOneArrayErrors) {
/* automate testing buffer overflows *and* underflows */
g_atstartofpage = true;
}
/**
* Allocates memory with properties useful for testing.
*
* This returns a pointer 𝑝 where reading or writing to either 𝑝[-1] or
* 𝑝[𝑛+𝟷] will immediately trigger a segmentation fault; and bytes are
* initialized to 10100101 (A5).
*
* Implementation Details: Accomplishing this entails two things. First,
* we grant each allocation a page granular memory mapping, with access
* to the two adjacent pages disabled. Second, since hardware memory
* protection isn't 1-byte granular, we add a fixture so each test runs
* a second time; the first call we return a pointer where the data is
* placed on the righthand side, and the second call we return the data
* on the lefthand side, thereby allowing both underflow/overflow
* off-by-one out-of-bounds accesses to be detected.
*/
void *tmalloc(size_t n) {
struct TestAllocation alloc = talloc(n);
memset(alloc.useraddr, 0xa5, alloc.usersize);
testmem_push(&g_testmem, alloc);
return (char *)alloc.useraddr + (g_atstartofpage ? 0 : alloc.usersize - n);
}
/**
* Same as tmalloc() but guarantees a specific alignment.
*
* Reading or writing to either 𝑝[-1] or 𝑝[roundup(𝑛+𝟷,𝑎)] will
* immediately trigger a segmentation fault.
*
* @param 𝑎 is alignment in bytes, e.g. 16
* @param 𝑛 is number of bytes
*/
void *tmemalign(size_t a, size_t n) {
/* TODO(jart): ASAN detect 𝑝[𝑛+𝟷] */
return tmalloc(ROUNDUP(n, a));
}
/**
* Same as tunbing() w/ alignment guarantee.
*/
void *tunbinga(size_t a, const char16_t *binglyphs) {
size_t size;
EXPECT_NE(0, (size = strlen16(binglyphs)));
return unbingbuf(tmemalign(a, size), size, binglyphs, -1);
}
/**
* Decodes CP437 glyphs to bounds-checked binary buffer, e.g.
*
* char *mem = tunbing(u" ☺☻♥♦");
* EXPECT_EQ(0, memcmp("\0\1\2\3\4", mem, 5));
* tfree(mem);
*
* @see tunbing(), unbingstr(), unbing()
*/
void *tunbing(const char16_t *binglyphs) {
return tunbinga(1, binglyphs);
}
/**
* Frees memory allocated with tmalloc().
* This needs to be called in LIFO order.
* @param
*/
void(tfree)(void *p) {
struct TestAllocation alloc;
__tfree_check(p);
alloc = testmem_pop(&g_testmem);
if (alloc.mapsize) testmem_push(&g_testmem_trash, alloc);
}
char *tstrdup(const char *s) {
return strcpy(tmalloc(strlen(s) + 1), s);
}

77
libc/testlib/testrunner.c Normal file
View file

@ -0,0 +1,77 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/bits.h"
#include "libc/bits/safemacros.h"
#include "libc/calls/internal.h"
#include "libc/errno.h"
#include "libc/nt/process.h"
#include "libc/stdio/stdio.h"
#include "libc/testlib/testlib.h"
void SetUp(void);
void TearDown(void);
void testlib_finish(void) {
if (g_testlib_failed) {
fprintf(stderr, "%u / %u %s\n", g_testlib_failed, g_testlib_ran,
"tests failed");
}
}
noreturn void testlib_abort(void) {
int rc;
testlib_finish();
rc = min(255, g_testlib_failed);
quick_exit(rc); /* so we don't run __testmemory_fini() */
unreachable;
}
/**
* Runs all test case functions in sorted order.
*/
testonly void testlib_runtestcases(testfn_t *start, testfn_t *end,
testfn_t warmup) {
/**
* getpid() calls are inserted to help visually see tests in traces
* which can be performed on Linux, FreeBSD, OpenBSD, and XNU:
*
* strace -f o/default/test.com |& less
* truss o/default/test.com |& less
* ktrace -f trace o/default/test.com </dev/null; kdump -f trace | less
* dtruss o/default/test.com |& less
*
* Test cases are iterable via a decentralized section. Your TEST()
* macro inserts .testcase.SUITENAME sections into the binary which
* the linker sorts into an array.
*
* @see ape/ape.lds
*/
const testfn_t *fn;
for (fn = start; fn != end; ++fn) {
if (weaken(SetUp)) weaken(SetUp)();
errno = 0;
SetLastError(0);
getpid$sysv();
if (warmup) warmup();
(*fn)();
getpid$sysv();
if (weaken(TearDown)) weaken(TearDown)();
}
}

View file

@ -0,0 +1,42 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
.testonly
.yoink __FILE__
/ Empties L1 instruction cache.
thrashcodecache:
.leafprologue
push %rbx
xor %eax,%eax
xor %ecx,%ecx
cpuid
/ pushpop 4,%rcx
0: .rept 32768/(8+9)
.byte 0x0f,0x1f,0x84,0,0,0,0,0 # fat nop x8
.byte 0x66,0x0f,0x1f,0x84,0,0,0,0,0 # fat nop x9
.endr
/ loop 0b
xor %eax,%eax
xor %ecx,%ecx
cpuid
pop %rbx
.leafepilogue
.endfn thrashcodecache,globl

View file

@ -0,0 +1,30 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
.yoink __FILE__
.text.unlikely
testlib_showerror_assert_eq:
push $TRUE
pushstr "ASSERT_EQ"
pushstr "="
jmp testlib_showerror_jump
.endfn testlib_showerror_assert_eq,globl,hidden
.previous

View file

@ -0,0 +1,30 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
.yoink __FILE__
.text.unlikely
testlib_showerror_assert_false:
push $TRUE
pushstr "ASSERT_FALSE"
pushstr "!"
jmp testlib_showerror_jump
.endfn testlib_showerror_assert_false,globl,hidden
.previous

View file

@ -0,0 +1,30 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
.yoink __FILE__
.text.unlikely
testlib_showerror_assert_ne:
push $TRUE
pushstr "ASSERT_NE"
pushstr ""
jmp testlib_showerror_jump
.endfn testlib_showerror_assert_ne,globl,hidden
.previous

View file

@ -0,0 +1,30 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
.yoink __FILE__
.text.unlikely
testlib_showerror_assert_true:
push $TRUE
pushstr "ASSERT_TRUE"
pushstr ""
jmp testlib_showerror_jump
.endfn testlib_showerror_assert_true,globl,hidden
.previous

View file

@ -0,0 +1,30 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
.yoink __FILE__
.text.unlikely
testlib_showerror_expect_eq:
push $FALSE
pushstr "EXPECT_EQ"
pushstr "="
jmp testlib_showerror_jump
.endfn testlib_showerror_expect_eq,globl,hidden
.previous

View file

@ -0,0 +1,30 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
.yoink __FILE__
.text.unlikely
testlib_showerror_expect_false:
push $FALSE
pushstr "EXPECT_FALSE"
pushstr "!"
jmp testlib_showerror_jump
.endfn testlib_showerror_expect_false,globl,hidden
.previous

View file

@ -0,0 +1,30 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
.yoink __FILE__
.text.unlikely
testlib_showerror_expect_ne:
push $FALSE
pushstr "EXPECT_NE"
pushstr ""
jmp testlib_showerror_jump
.endfn testlib_showerror_expect_ne,globl,hidden
.previous

View file

@ -0,0 +1,30 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
.yoink __FILE__
.text.unlikely
testlib_showerror_expect_true:
push $FALSE
pushstr "EXPECT_TRUE"
pushstr ""
jmp testlib_showerror_jump
.endfn testlib_showerror_expect_true,globl,hidden
.previous

View file

@ -0,0 +1,28 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
.yoink __FILE__
/ Delegates to free().
/
/ @note reduces make dependency toil caused by macros
testlib_free:
jmp free
.endfn testlib_free,globl

View file

@ -0,0 +1,30 @@
/*-*- mode:asm; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify │
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. │
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of │
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software │
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/macros.h"
.yoink __FILE__
.text.unlikely
testlib_showerror_jump:
popstr testlib_showerror_symbol(%rip)
popstr testlib_showerror_macro(%rip)
pop testlib_showerror_isfatal(%rip)
jmp testlib_showerror_
.endfn testlib_showerror_jump,globl,hidden
.previous

40
libc/testlib/ugly.h Normal file
View file

@ -0,0 +1,40 @@
#ifndef COSMOPOLITAN_LIBC_TESTLIB_UGLY_H_
#define COSMOPOLITAN_LIBC_TESTLIB_UGLY_H_
#include "libc/macros.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
#if defined(__GNUC__) || defined(__llvm__)
#pragma GCC diagnostic ignored "-Wpointer-to-int-cast" /* j.f.c. */
#endif
#define _I(x) (TYPE_SIGNED(typeof(x)) ? (intmax_t)(x) : (uintmax_t)(x))
#define __TEST_ARRAY(S) \
_Section(".piro.relo.sort.testcase.2." #S ",\"aw\",@init_array #")
#define __BENCH_ARRAY(S) \
_Section(".piro.relo.sort.bench.2." #S ",\"aw\",@init_array #")
#define __TEST_PROTOTYPE(S, N, A) \
testonly void S##_##N(void); \
alignas(8) const void *const S##_##N##_ptr[] A(S) = {S##_##N}; \
testonly void S##_##N(void)
#define __TEST_SECTION(NAME, CONTENT) \
".section " NAME "\n" CONTENT "\n\t.previous\n"
#define __RELOSECTION(NAME, CONTENT) \
__TEST_SECTION(".piro.relo.sort" NAME ",\"aw\",@progbits", CONTENT)
#define __ROSTR(STR) __TEST_SECTION(".rodata.str1.1,\"aSM\",@progbits,1", STR)
#define __FIXTURE(KIND, GROUP, ENTRY) \
asm(__RELOSECTION("." KIND ".2." #GROUP #ENTRY, \
"\t.quad\t1f\n" \
"\t.quad\t2f\n" \
"\t.quad\t" STRINGIFY(GROUP##_##ENTRY)) \
__ROSTR("1:\t.asciz\t" STRINGIFY(#GROUP)) \
__ROSTR("2:\t.asciz\t" STRINGIFY(#ENTRY))); \
testonly void GROUP##_##ENTRY(void)
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_TESTLIB_UGLY_H_ */