Out with googletest, in with doctest #202 (#231)

* introduce doctest over googletest #202
* call dtester in in targets
* doctest conversion #202
* channel.cpp -> doctest #202
* egcpool tests -> doctest #202
* input tests to doctester
* zaxis -> doctest
* drone: always define LANG
* libav to doctest #202
* panelreel tests to doctest #202
* spec that a C++17 compiler is now required for doctest #202
* enmetric tests -> doctest #202
* fade tests -> doctest #202
* notcurses test case -> doctest #202
* last conversion to doctest #202
* finish move to doctest #202
* drone: set up make test
This commit is contained in:
Nick Black 2019-12-27 17:20:20 -05:00 committed by GitHub
parent d4caefc55d
commit ce2a390b52
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 7999 additions and 2187 deletions

View File

@ -37,3 +37,4 @@ steps:
- cd build - cd build
- cmake .. -DCMAKE_BUILD_TYPE=Release - cmake .. -DCMAKE_BUILD_TYPE=Release
- make - make
- env LANG="en_US.UTF-8" make test

View File

@ -6,7 +6,7 @@ project(notcurses VERSION 0.9.3
set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_C_STANDARD 11) set(CMAKE_C_STANDARD 11)
set(CMAKE_C_VISIBILITY_PRESET hidden) set(CMAKE_C_VISIBILITY_PRESET hidden)
set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_VISIBILITY_PRESET hidden) set(CMAKE_CXX_VISIBILITY_PRESET hidden)
include(GNUInstallDirs) include(GNUInstallDirs)
@ -212,7 +212,7 @@ endif()
# Testing # Testing
file(GLOB TESTSRCS CONFIGURE_DEPENDS tests/*.cpp) file(GLOB TESTSRCS CONFIGURE_DEPENDS tests/*.cpp)
add_executable(notcurses-tester ${TESTSRCS}) add_executable(notcurses-tester ${TESTSRCS})
find_package(GTest 1.9 REQUIRED) find_package(doctest REQUIRED doctest>=1.2.7)
target_include_directories(notcurses-tester target_include_directories(notcurses-tester
PRIVATE PRIVATE
include include
@ -220,10 +220,12 @@ target_include_directories(notcurses-tester
src/lib src/lib
) )
target_link_libraries(notcurses-tester target_link_libraries(notcurses-tester
GTest::GTest PRIVATE
doctest::doctest
notcurses notcurses
) )
target_compile_options(notcurses-tester PRIVATE target_compile_options(notcurses-tester
PRIVATE
-Wall -Wextra -W -Wshadow -Wall -Wextra -W -Wshadow
) )
target_compile_definitions(notcurses-tester target_compile_definitions(notcurses-tester
@ -231,8 +233,11 @@ target_compile_definitions(notcurses-tester
FORTIFY_SOURCE=2 FORTIFY_SOURCE=2
) )
gtest_discover_tests(notcurses-tester)
enable_testing() enable_testing()
add_test(
NAME notcurses-tester
COMMAND notcurses-tester
)
# pkg-config support # pkg-config support
configure_file(tools/notcurses.pc.in configure_file(tools/notcurses.pc.in

View File

@ -101,7 +101,7 @@ that fine library.
## Requirements ## Requirements
* A C11 and a C++14 compiler * A C11 and a C++17 compiler
* CMake 3.13.0+ * CMake 3.13.0+
* From NCURSES: terminfo 6.1+ * From NCURSES: terminfo 6.1+
* (OPTIONAL) From FFMpeg: libswscale 5.0+, libavformat 57.0+, libavutil 56.0+ * (OPTIONAL) From FFMpeg: libswscale 5.0+, libavformat 57.0+, libavutil 56.0+

2
debian/control vendored
View File

@ -3,7 +3,7 @@ Priority: optional
Maintainer: Nick Black <dankamongmen@gmail.com> Maintainer: Nick Black <dankamongmen@gmail.com>
Build-Depends: debhelper-compat (= 12), cmake (>= 3.13), pkg-config (>= 0.29), Build-Depends: debhelper-compat (= 12), cmake (>= 3.13), pkg-config (>= 0.29),
libgtest-dev (>= 1.8.0), libncurses-dev (>= 6.1), libavformat-dev (>= 57.0), libgtest-dev (>= 1.8.0), libncurses-dev (>= 6.1), libavformat-dev (>= 57.0),
libswscale-dev (>= 5.0), libavutil-dev (>= 56.0) libswscale-dev (>= 5.0), libavutil-dev (>= 56.0), doctest-dev (>= 1.2.7)
Standards-Version: 4.4.1.1 Standards-Version: 4.4.1.1
Section: libs Section: libs
Homepage: https://nick-black.com/dankwiki/index.php/notcurses Homepage: https://nick-black.com/dankwiki/index.php/notcurses

View File

@ -10,13 +10,6 @@
#define BLOCKSIZE 512 // show this many per page #define BLOCKSIZE 512 // show this many per page
#define CHUNKSIZE 32 // show this many per line #define CHUNKSIZE 32 // show this many per line
static int
fade_block(struct ncplane* nn, const struct timespec* subdelay){
int ret = ncplane_fadein(nn, subdelay, demo_fader);
ncplane_destroy(nn);
return ret;
}
static int static int
draw_block(struct ncplane* nn, uint32_t blockstart){ draw_block(struct ncplane* nn, uint32_t blockstart){
cell ul = CELL_TRIVIAL_INITIALIZER, ur = CELL_TRIVIAL_INITIALIZER; cell ul = CELL_TRIVIAL_INITIALIZER, ur = CELL_TRIVIAL_INITIALIZER;
@ -204,9 +197,9 @@ int unicodeblocks_demo(struct notcurses* nc){
if(ncplane_printf_aligned(n, 6 + BLOCKSIZE / CHUNKSIZE, NCALIGN_CENTER, "%s", description) <= 0){ if(ncplane_printf_aligned(n, 6 + BLOCKSIZE / CHUNKSIZE, NCALIGN_CENTER, "%s", description) <= 0){
return -1; return -1;
} }
if(fade_block(nn, &subdelay)){ // destroys nn notcurses_render(nc);
return -1; nanosleep(&subdelay, NULL);
} ncplane_destroy(nn);
// for a 32-bit wchar_t, we would want up through 24 bits of block ID. but // for a 32-bit wchar_t, we would want up through 24 bits of block ID. but
// really, the vast majority of space is unused. // really, the vast majority of space is unused.
blockstart += BLOCKSIZE; blockstart += BLOCKSIZE;

View File

@ -99,10 +99,6 @@ int ncplane_fadein(ncplane* n, const struct timespec* ts, fadecb fader){
int maxsteps = maxfsteps > maxbsteps ? maxfsteps : maxbsteps; int maxsteps = maxfsteps > maxbsteps ? maxfsteps : maxbsteps;
uint64_t nanosecs_total = ts->tv_sec * NANOSECS_IN_SEC + ts->tv_nsec; uint64_t nanosecs_total = ts->tv_sec * NANOSECS_IN_SEC + ts->tv_nsec;
uint64_t nanosecs_step = nanosecs_total / maxsteps; uint64_t nanosecs_step = nanosecs_total / maxsteps;
while(nanosecs_step < 10000000){ // 10msec
nanosecs_step *= 10;
maxsteps = nanosecs_total / nanosecs_step;
}
struct timespec times; struct timespec times;
clock_gettime(CLOCK_MONOTONIC, &times); clock_gettime(CLOCK_MONOTONIC, &times);
// Start time in absolute nanoseconds // Start time in absolute nanoseconds
@ -178,10 +174,6 @@ int ncplane_fadeout(struct ncplane* n, const struct timespec* ts, fadecb fader){
int maxsteps = maxfsteps > maxbsteps ? maxfsteps : maxbsteps; int maxsteps = maxfsteps > maxbsteps ? maxfsteps : maxbsteps;
uint64_t nanosecs_total = ts->tv_sec * NANOSECS_IN_SEC + ts->tv_nsec; uint64_t nanosecs_total = ts->tv_sec * NANOSECS_IN_SEC + ts->tv_nsec;
uint64_t nanosecs_step = nanosecs_total / maxsteps; uint64_t nanosecs_step = nanosecs_total / maxsteps;
while(nanosecs_step < 10000000){ // 10msec
nanosecs_step *= 10;
maxsteps = nanosecs_total / nanosecs_step;
}
struct timespec times; struct timespec times;
clock_gettime(CLOCK_MONOTONIC, &times); clock_gettime(CLOCK_MONOTONIC, &times);
// Start time in absolute nanoseconds // Start time in absolute nanoseconds

View File

@ -2,119 +2,109 @@
#include "egcpool.h" #include "egcpool.h"
#include "main.h" #include "main.h"
class CellTest : public :: testing::Test { TEST_CASE("Cell") {
protected: // common initialization
void SetUp() override {
setlocale(LC_ALL, "");
if(getenv("TERM") == nullptr){ if(getenv("TERM") == nullptr){
GTEST_SKIP(); return;
} }
FILE* outfp_{};
outfp_ = fopen("/dev/tty", "wb");
REQUIRE(nullptr != outfp_);
notcurses_options nopts{}; notcurses_options nopts{};
nopts.inhibit_alternate_screen = true; nopts.inhibit_alternate_screen = true;
nopts.suppress_bannner = true; nopts.suppress_bannner = true;
outfp_ = fopen("/dev/tty", "wb"); struct notcurses* nc_ = notcurses_init(&nopts, outfp_);
ASSERT_NE(nullptr, outfp_); REQUIRE(nullptr != nc_);
nc_ = notcurses_init(&nopts, outfp_); struct ncplane* n_ = notcurses_stdplane(nc_);
ASSERT_NE(nullptr, nc_); REQUIRE(nullptr != n_);
n_ = notcurses_stdplane(nc_);
ASSERT_NE(nullptr, n_);
}
void TearDown() override { SUBCASE("LoadSimple") {
if(nc_){
EXPECT_EQ(0, notcurses_stop(nc_));
}
if(outfp_){
fclose(outfp_);
}
}
struct notcurses* nc_{};
struct ncplane* n_{};
FILE* outfp_{};
};
TEST_F(CellTest, LoadSimple) {
cell c = CELL_TRIVIAL_INITIALIZER; cell c = CELL_TRIVIAL_INITIALIZER;
ASSERT_EQ(1, cell_load(n_, &c, " ")); REQUIRE(1 == cell_load(n_, &c, " "));
EXPECT_TRUE(cell_simple_p(&c)); CHECK(cell_simple_p(&c));
cell_release(n_, &c); cell_release(n_, &c);
} }
TEST_F(CellTest, SetItalic) { SUBCASE("SetItalic") {
cell c = CELL_TRIVIAL_INITIALIZER; cell c = CELL_TRIVIAL_INITIALIZER;
int dimy, dimx; int dimy, dimx;
notcurses_term_dim_yx(nc_, &dimy, &dimx); notcurses_term_dim_yx(nc_, &dimy, &dimx);
cell_styles_set(&c, CELL_STYLE_ITALIC); cell_styles_set(&c, CELL_STYLE_ITALIC);
ASSERT_EQ(1, cell_load(n_, &c, "i")); REQUIRE(1 == cell_load(n_, &c, "i"));
cell_set_fg_rgb(&c, 255, 255, 255); cell_set_fg_rgb(&c, 255, 255, 255);
ncplane_set_default(n_, &c); ncplane_set_default(n_, &c);
cell_release(n_, &c); cell_release(n_, &c);
EXPECT_EQ(0, notcurses_render(nc_)); CHECK(0 == notcurses_render(nc_));
cell_styles_off(&c, CELL_STYLE_ITALIC); cell_styles_off(&c, CELL_STYLE_ITALIC);
} }
TEST_F(CellTest, SetBold) { SUBCASE("SetBold") {
cell c = CELL_TRIVIAL_INITIALIZER; cell c = CELL_TRIVIAL_INITIALIZER;
int dimy, dimx; int dimy, dimx;
notcurses_term_dim_yx(nc_, &dimy, &dimx); notcurses_term_dim_yx(nc_, &dimy, &dimx);
cell_styles_set(&c, CELL_STYLE_BOLD); cell_styles_set(&c, CELL_STYLE_BOLD);
ASSERT_EQ(1, cell_load(n_, &c, "b")); REQUIRE(1 == cell_load(n_, &c, "b"));
cell_set_fg_rgb(&c, 255, 255, 255); cell_set_fg_rgb(&c, 255, 255, 255);
ncplane_set_default(n_, &c); ncplane_set_default(n_, &c);
cell_release(n_, &c); cell_release(n_, &c);
EXPECT_EQ(0, notcurses_render(nc_)); CHECK(0 == notcurses_render(nc_));
cell_styles_off(&c, CELL_STYLE_BOLD); cell_styles_off(&c, CELL_STYLE_BOLD);
} }
TEST_F(CellTest, SetUnderline) { SUBCASE("SetUnderline") {
cell c = CELL_TRIVIAL_INITIALIZER; cell c = CELL_TRIVIAL_INITIALIZER;
int dimy, dimx; int dimy, dimx;
notcurses_term_dim_yx(nc_, &dimy, &dimx); notcurses_term_dim_yx(nc_, &dimy, &dimx);
cell_styles_set(&c, CELL_STYLE_UNDERLINE); cell_styles_set(&c, CELL_STYLE_UNDERLINE);
ASSERT_EQ(1, cell_load(n_, &c, "u")); REQUIRE(1 == cell_load(n_, &c, "u"));
cell_set_fg_rgb(&c, 255, 255, 255); cell_set_fg_rgb(&c, 255, 255, 255);
ncplane_set_default(n_, &c); ncplane_set_default(n_, &c);
cell_release(n_, &c); cell_release(n_, &c);
EXPECT_EQ(0, notcurses_render(nc_)); CHECK(0 == notcurses_render(nc_));
cell_styles_off(&c, CELL_STYLE_UNDERLINE); cell_styles_off(&c, CELL_STYLE_UNDERLINE);
} }
/*TEST_F(CellTest, CellLoadTamil) { /* SUBCASE("CellLoadTamil") {
const char zerodeg[] = "\u0bb8\u0bc0\u0bb0\u0bc7\u0bb3\u0b95\u0bbf\u0b95\u0bbf\u0bb0\u0bbf"; const char zerodeg[] = "\u0bb8\u0bc0\u0bb0\u0bc7\u0bb3\u0b95\u0bbf\u0b95\u0bbf\u0bb0\u0bbf";
cell c = CELL_TRIVIAL_INITIALIZER; cell c = CELL_TRIVIAL_INITIALIZER;
size_t ulen = cell_load(n_, &c, zerodeg); size_t ulen = cell_load(n_, &c, zerodeg);
// First have U+0BB8 TAMIL LETTER SA U+0BC0 TAMIL VOWEL SIGN II // First have U+0BB8 TAMIL LETTER SA U+0BC0 TAMIL VOWEL SIGN II
// // e0 ae b8 e0 af 80 // // e0 ae b8 e0 af 80
ASSERT_EQ(6, ulen); REQUIRE(6 == ulen);
ulen = cell_load(n_, &c, zerodeg + ulen); ulen = cell_load(n_, &c, zerodeg + ulen);
// U+0BB0 TAMIL LETTER RA U+0BCB TAMIL VOWEL SIGN OO // U+0BB0 TAMIL LETTER RA U+0BCB TAMIL VOWEL SIGN OO
// e0 ae b0 e0 af 8b // e0 ae b0 e0 af 8b
ASSERT_EQ(6, ulen); REQUIRE(6 == ulen);
// FIXME // FIXME
}*/ }*/
TEST_F(CellTest, CellSetFGAlpha){ SUBCASE("CellSetFGAlpha"){
cell c = CELL_TRIVIAL_INITIALIZER; cell c = CELL_TRIVIAL_INITIALIZER;
EXPECT_GT(0, cell_set_fg_alpha(&c, -1)); CHECK(0 > cell_set_fg_alpha(&c, -1));
EXPECT_GT(0, cell_set_fg_alpha(&c, 4)); CHECK(0 > cell_set_fg_alpha(&c, 4));
EXPECT_EQ(0, cell_set_fg_alpha(&c, CELL_ALPHA_OPAQUE)); CHECK(0 == cell_set_fg_alpha(&c, CELL_ALPHA_OPAQUE));
EXPECT_EQ(CELL_ALPHA_OPAQUE, cell_get_fg_alpha(&c)); CHECK(CELL_ALPHA_OPAQUE == cell_get_fg_alpha(&c));
EXPECT_EQ(0, cell_set_fg_alpha(&c, CELL_ALPHA_HIGHCONTRAST)); CHECK(0 == cell_set_fg_alpha(&c, CELL_ALPHA_HIGHCONTRAST));
EXPECT_EQ(CELL_ALPHA_HIGHCONTRAST, cell_get_fg_alpha(&c)); CHECK(CELL_ALPHA_HIGHCONTRAST == cell_get_fg_alpha(&c));
EXPECT_TRUE(cell_fg_default_p(&c)); CHECK(cell_fg_default_p(&c));
EXPECT_TRUE(cell_bg_default_p(&c)); CHECK(cell_bg_default_p(&c));
} }
TEST_F(CellTest, CellSetBGAlpha){ SUBCASE("CellSetBGAlpha"){
cell c = CELL_TRIVIAL_INITIALIZER; cell c = CELL_TRIVIAL_INITIALIZER;
EXPECT_GT(0, cell_set_bg_alpha(&c, -1)); CHECK(0 > cell_set_bg_alpha(&c, -1));
EXPECT_GT(0, cell_set_bg_alpha(&c, 4)); CHECK(0 > cell_set_bg_alpha(&c, 4));
EXPECT_EQ(0, cell_set_bg_alpha(&c, CELL_ALPHA_OPAQUE)); CHECK(0 == cell_set_bg_alpha(&c, CELL_ALPHA_OPAQUE));
EXPECT_EQ(CELL_ALPHA_OPAQUE, cell_get_bg_alpha(&c)); CHECK(CELL_ALPHA_OPAQUE == cell_get_bg_alpha(&c));
EXPECT_NE(0, cell_set_bg_alpha(&c, CELL_ALPHA_HIGHCONTRAST)); CHECK(0 != cell_set_bg_alpha(&c, CELL_ALPHA_HIGHCONTRAST));
EXPECT_EQ(0, cell_set_bg_alpha(&c, CELL_ALPHA_TRANSPARENT)); CHECK(0 == cell_set_bg_alpha(&c, CELL_ALPHA_TRANSPARENT));
EXPECT_EQ(CELL_ALPHA_TRANSPARENT, cell_get_bg_alpha(&c)); CHECK(CELL_ALPHA_TRANSPARENT == cell_get_bg_alpha(&c));
EXPECT_TRUE(cell_fg_default_p(&c)); CHECK(cell_fg_default_p(&c));
EXPECT_TRUE(cell_bg_default_p(&c)); CHECK(cell_bg_default_p(&c));
} }
// common teardown
CHECK(0 == notcurses_stop(nc_));
CHECK(0 == fclose(outfp_));
}

View File

@ -1,14 +1,7 @@
#include <notcurses.h> #include <notcurses.h>
#include "main.h" #include "main.h"
class ChannelTest : public :: testing::Test { TEST_CASE("ChannelGetRGB") {
protected:
void SetUp() override {
setlocale(LC_ALL, "");
}
};
TEST_F(ChannelTest, ChannelGetRGB){
const struct t { const struct t {
uint32_t channel; uint32_t channel;
int r, g, b; int r, g, b;
@ -20,14 +13,14 @@ TEST_F(ChannelTest, ChannelGetRGB){
}; };
for(auto i = 0u ; i < sizeof(test) / sizeof(*test) ; ++i){ for(auto i = 0u ; i < sizeof(test) / sizeof(*test) ; ++i){
unsigned r, g, b; unsigned r, g, b;
EXPECT_EQ(test[i].channel, channel_get_rgb(test[i].channel, &r, &g, &b)); CHECK(test[i].channel == channel_get_rgb(test[i].channel, &r, &g, &b));
EXPECT_EQ(test[i].r, r); CHECK(test[i].r == r);
EXPECT_EQ(test[i].g, g); CHECK(test[i].g == g);
EXPECT_EQ(test[i].b, b); CHECK(test[i].b == b);
} }
} }
TEST_F(ChannelTest, ChannelGetAlpha){ TEST_CASE("ChannelGetAlpha") {
const struct t { const struct t {
uint32_t channel; uint32_t channel;
int a; int a;
@ -40,11 +33,11 @@ TEST_F(ChannelTest, ChannelGetAlpha){
{ .channel = 0xffffffff, .a = 3, }, { .channel = 0xffffffff, .a = 3, },
}; };
for(auto i = 0u ; i < sizeof(test) / sizeof(*test) ; ++i){ for(auto i = 0u ; i < sizeof(test) / sizeof(*test) ; ++i){
EXPECT_EQ(test[i].a, channel_get_alpha(test[i].channel)); CHECK(test[i].a == channel_get_alpha(test[i].channel));
} }
} }
TEST_F(ChannelTest, ChannelGetDefault){ TEST_CASE("ChannelGetDefault") {
const struct t { const struct t {
uint32_t channel; uint32_t channel;
bool def; bool def;
@ -57,19 +50,19 @@ TEST_F(ChannelTest, ChannelGetDefault){
{ .channel = 0xffffffff, .def = false, }, { .channel = 0xffffffff, .def = false, },
}; };
for(auto i = 0u ; i < sizeof(test) / sizeof(*test) ; ++i){ for(auto i = 0u ; i < sizeof(test) / sizeof(*test) ; ++i){
EXPECT_EQ(test[i].def, channel_default_p(test[i].channel)); CHECK(test[i].def == channel_default_p(test[i].channel));
} }
} }
TEST_F(ChannelTest, ChannelSetDefault){ TEST_CASE("ChannelSetDefault") {
const uint32_t channels[] = { const uint32_t channels[] = {
0x40000000, 0x4fffffff, 0xcfffffff, 0x40000000, 0x4fffffff, 0xcfffffff,
0x40808080, 0x40080808, 0xffffffff, 0x40808080, 0x40080808, 0xffffffff,
}; };
for(auto i = 0u ; i < sizeof(channels) / sizeof(*channels) ; ++i){ for(auto i = 0u ; i < sizeof(channels) / sizeof(*channels) ; ++i){
uint32_t channel = channels[i]; uint32_t channel = channels[i];
EXPECT_FALSE(channel_default_p(channel)); CHECK(!channel_default_p(channel));
channel_set_default(&channel); channel_set_default(&channel);
EXPECT_TRUE(channel_default_p(channel)); CHECK(channel_default_p(channel));
} }
} }

5942
tests/doctest.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,42 +1,34 @@
#include <vector>
#include <notcurses.h> #include <notcurses.h>
#include "egcpool.h" #include "egcpool.h"
#include "main.h" #include "main.h"
class EGCPoolTest : public :: testing::Test { TEST_CASE("EGCpool") {
protected:
void SetUp() override {
setlocale(LC_ALL, "");
}
void TearDown() override {
egcpool_dump(&pool_);
}
egcpool pool_{}; egcpool pool_{};
};
TEST_F(EGCPoolTest, Initialized) { SUBCASE("Initialized") {
EXPECT_EQ(nullptr, pool_.pool); CHECK(!pool_.pool);
EXPECT_EQ(0, pool_.poolsize); CHECK(!pool_.poolsize);
EXPECT_EQ(0, pool_.poolwrite); CHECK(!pool_.poolwrite);
EXPECT_EQ(0, pool_.poolused); CHECK(!pool_.poolused);
} }
TEST_F(EGCPoolTest, UTF8EGC) { SUBCASE("UTF8EGC") {
const char* wstr = ""; const char* wstr = "";
int c; int c;
auto ulen = utf8_egc_len(wstr, &c); auto ulen = utf8_egc_len(wstr, &c);
ASSERT_LT(0, ulen); REQUIRE(0 < ulen);
EXPECT_LT(0, c); CHECK(0 < c);
wstr = ""; wstr = "";
ulen = utf8_egc_len(wstr, &c); ulen = utf8_egc_len(wstr, &c);
ASSERT_LT(0, ulen); REQUIRE(0 < ulen);
EXPECT_LT(0, c); CHECK(0 < c);
} }
// we're gonna run both a composed latin a with grave, and then a latin a with // we're gonna run both a composed latin a with grave, and then a latin a with
// a combining nonspacing grave // a combining nonspacing grave
TEST_F(EGCPoolTest, UTF8EGCCombining) { SUBCASE("UTF8EGCCombining") {
const char* w1 = "\u00e0"; // (utf8: c3 a0) const char* w1 = "\u00e0"; // (utf8: c3 a0)
const char* w2 = "\u0061\u0300"; // (utf8: 61 cc 80) const char* w2 = "\u0061\u0300"; // (utf8: 61 cc 80)
const char* w3 = "\u0061"; // (utf8: 61) const char* w3 = "\u0061"; // (utf8: 61)
@ -44,84 +36,84 @@ TEST_F(EGCPoolTest, UTF8EGCCombining) {
auto u1 = utf8_egc_len(w1, &c1); auto u1 = utf8_egc_len(w1, &c1);
auto u2 = utf8_egc_len(w2, &c2); auto u2 = utf8_egc_len(w2, &c2);
auto u3 = utf8_egc_len(w3, &c3); auto u3 = utf8_egc_len(w3, &c3);
ASSERT_EQ(2, u1); REQUIRE(2 == u1);
ASSERT_EQ(3, u2); REQUIRE(3 == u2);
ASSERT_EQ(1, u3); REQUIRE(1 == u3);
ASSERT_EQ(1, c1); REQUIRE(1 == c1);
ASSERT_EQ(1, c2); REQUIRE(1 == c2);
ASSERT_EQ(1, c3); REQUIRE(1 == c3);
} }
TEST_F(EGCPoolTest, AddAndRemove) { SUBCASE("AddAndRemove") {
const char* wstr = "\ufdfd"; // bismallih const char* wstr = "\ufdfd"; // bismallih
int c; int c;
auto ulen = utf8_egc_len(wstr, &c); auto ulen = utf8_egc_len(wstr, &c);
ASSERT_LE(0, egcpool_stash(&pool_, wstr, ulen)); REQUIRE(0 <= egcpool_stash(&pool_, wstr, ulen));
ASSERT_EQ(1, c); // not considered wide, believe it or not REQUIRE(1 == c); // not considered wide, believe it or not
EXPECT_NE(nullptr, pool_.pool); CHECK(pool_.pool);
EXPECT_STREQ(pool_.pool, wstr); CHECK(!strcmp(pool_.pool, wstr));
EXPECT_LT(0, pool_.poolsize); CHECK(0 < pool_.poolsize);
EXPECT_EQ(ulen + 1, pool_.poolused); CHECK(ulen + 1 == pool_.poolused);
EXPECT_LT(0, pool_.poolwrite); CHECK(0 < pool_.poolwrite);
EXPECT_LE(pool_.poolused, pool_.poolsize); CHECK(pool_.poolused <= pool_.poolsize);
egcpool_release(&pool_, 0); egcpool_release(&pool_, 0);
EXPECT_EQ('\0', *pool_.pool); CHECK_EQ('\0', *pool_.pool);
EXPECT_LT(0, pool_.poolsize); CHECK(0 < pool_.poolsize);
EXPECT_EQ(0, pool_.poolused); CHECK(0 == pool_.poolused);
EXPECT_LT(0, pool_.poolwrite); CHECK(0 < pool_.poolwrite);
} }
TEST_F(EGCPoolTest, AddTwiceRemoveFirst) { SUBCASE("AddTwiceRemoveFirst") {
const char* wstr = "\u8840"; // cjk unified ideograph, wide const char* wstr = "\u8840"; // cjk unified ideograph, wide
int c1, c2; // column counts int c1, c2; // column counts
auto u1 = utf8_egc_len(wstr, &c1); // bytes consumed auto u1 = utf8_egc_len(wstr, &c1); // bytes consumed
auto u2 = utf8_egc_len(wstr, &c2); auto u2 = utf8_egc_len(wstr, &c2);
int o1 = egcpool_stash(&pool_, wstr, u1); int o1 = egcpool_stash(&pool_, wstr, u1);
int o2 = egcpool_stash(&pool_, wstr, u2); int o2 = egcpool_stash(&pool_, wstr, u2);
ASSERT_LE(0, o1); REQUIRE(0 <= o1);
ASSERT_LT(o1, o2); REQUIRE(o1 < o2);
ASSERT_EQ(2, c1); REQUIRE(2 == c1);
ASSERT_EQ(c1, c2); REQUIRE(c1 == c2);
EXPECT_NE(nullptr, pool_.pool); CHECK(pool_.pool);
EXPECT_STREQ(pool_.pool + o1, wstr); CHECK(!strcmp(pool_.pool + o1, wstr));
EXPECT_STREQ(pool_.pool + o2, wstr); CHECK(!strcmp(pool_.pool + o2, wstr));
EXPECT_LT(0, pool_.poolsize); CHECK(0 < pool_.poolsize);
EXPECT_EQ(u1 + u2 + 2, pool_.poolused); CHECK(u1 + u2 + 2 == pool_.poolused);
EXPECT_EQ(u1 + u2 + 2, pool_.poolwrite); CHECK(u1 + u2 + 2 == pool_.poolwrite);
EXPECT_LE(pool_.poolused, pool_.poolsize); CHECK(pool_.poolused < pool_.poolsize);
egcpool_release(&pool_, o1); egcpool_release(&pool_, o1);
EXPECT_EQ('\0', pool_.pool[o1]); CHECK('\0' == pool_.pool[o1]);
EXPECT_EQ(u2 + 1, pool_.poolused); CHECK(u2 + 1 == pool_.poolused);
EXPECT_LT(0, pool_.poolwrite); CHECK(0 < pool_.poolwrite);
} }
TEST_F(EGCPoolTest, AddTwiceRemoveSecond) { SUBCASE("AddTwiceRemoveSecond") {
const char* wstr = "\u8840"; // cjk unified ideograph, wide const char* wstr = "\u8840"; // cjk unified ideograph, wide
int c1, c2; // column counts int c1, c2; // column counts
auto u1 = utf8_egc_len(wstr, &c1); // bytes consumed auto u1 = utf8_egc_len(wstr, &c1); // bytes consumed
auto u2 = utf8_egc_len(wstr, &c2); auto u2 = utf8_egc_len(wstr, &c2);
int o1 = egcpool_stash(&pool_, wstr, u1); int o1 = egcpool_stash(&pool_, wstr, u1);
int o2 = egcpool_stash(&pool_, wstr, u2); int o2 = egcpool_stash(&pool_, wstr, u2);
ASSERT_LT(o1, o2); REQUIRE(o1 < o2);
ASSERT_EQ(2, c1); REQUIRE(2 == c1);
ASSERT_EQ(c1, c2); REQUIRE(c1 == c2);
EXPECT_NE(nullptr, pool_.pool); CHECK(pool_.pool);
EXPECT_STREQ(pool_.pool + o1, wstr); CHECK(!strcmp(pool_.pool + o1, wstr));
EXPECT_STREQ(pool_.pool + o2, wstr); CHECK(!strcmp(pool_.pool + o2, wstr));
EXPECT_LT(0, pool_.poolsize); CHECK(0 < pool_.poolsize);
EXPECT_EQ(u1 + u2 + 2, pool_.poolused); CHECK(u1 + u2 + 2 == pool_.poolused);
EXPECT_EQ(u1 + u2 + 2, pool_.poolwrite); CHECK(u1 + u2 + 2 == pool_.poolwrite);
EXPECT_LE(pool_.poolused, pool_.poolsize); CHECK(pool_.poolused <= pool_.poolsize);
egcpool_release(&pool_, o2); egcpool_release(&pool_, o2);
EXPECT_EQ('\0', pool_.pool[o2]); CHECK('\0' == pool_.pool[o2]);
EXPECT_EQ(u2 + 1, pool_.poolused); CHECK(u2 + 1 == pool_.poolused);
EXPECT_LT(0, pool_.poolwrite); CHECK(0 < pool_.poolwrite);
} }
// POOL_MINIMUM_ALLOC is the minimum size of an egcpool once it goes active. // POOL_MINIMUM_ALLOC is the minimum size of an egcpool once it goes active.
// add EGCs to it past this boundary, and verify that they're all still // add EGCs to it past this boundary, and verify that they're all still
// accurate. // accurate.
TEST_F(EGCPoolTest, ForceReallocation) { SUBCASE("ForceReallocation") {
std::vector<int> candidates; std::vector<int> candidates;
char* firstalloc = nullptr; char* firstalloc = nullptr;
for(auto i = 0u ; i < 1u << 20u ; ++i){ for(auto i = 0u ; i < 1u << 20u ; ++i){
@ -132,35 +124,35 @@ TEST_F(EGCPoolTest, ForceReallocation) {
candidates.push_back(-1); candidates.push_back(-1);
continue; continue;
} }
ASSERT_GE(sizeof(mb), r); REQUIRE(sizeof(mb) >= r);
mb[r] = '\0'; mb[r] = '\0';
candidates.push_back(egcpool_stash(&pool_, mb, r)); candidates.push_back(egcpool_stash(&pool_, mb, r));
ASSERT_GT(1u << 24u, candidates[i]); REQUIRE((1u << 24u) > candidates[i]);
if(!firstalloc){ if(!firstalloc){
firstalloc = pool_.pool; firstalloc = pool_.pool;
} }
} }
// verify that we moved the pool at least once // verify that we moved the pool at least once
ASSERT_NE(pool_.pool, firstalloc); REQUIRE(pool_.pool != firstalloc);
for(auto i = 0u ; i < candidates.size() ; ++i){ for(auto i = 0u ; i < candidates.size() ; ++i){
auto stored = pool_.pool + candidates[i]; auto stored = pool_.pool + candidates[i];
char mb[MB_CUR_MAX + 1]; char mb[MB_CUR_MAX + 1];
wchar_t wcs = i + 0x80; wchar_t wcs = i + 0x80;
auto r = wctomb(mb, wcs); auto r = wctomb(mb, wcs);
if(r < 0){ if(r < 0){
ASSERT_EQ(-1, candidates[i]); REQUIRE(-1 == candidates[i]);
continue; continue;
} }
ASSERT_LT(0, r); REQUIRE(0 < r);
mb[r] = '\0'; mb[r] = '\0';
EXPECT_STREQ(mb, stored); CHECK(!strcmp(mb, stored));
} }
} }
// POOL_MINIMUM_ALLOC is the minimum size of an egcpool once it goes active. // POOL_MINIMUM_ALLOC is the minimum size of an egcpool once it goes active.
// add EGCs to it past this boundary, and verify that they're all still // add EGCs to it past this boundary, and verify that they're all still
// accurate. // accurate.
TEST_F(EGCPoolTest, ForceReallocationWithRemovals) { SUBCASE("ForceReallocationWithRemovals") {
std::vector<int> candidates; std::vector<int> candidates;
char* curpool = nullptr; char* curpool = nullptr;
for(auto i = 0u ; i < 1u << 20u ; ++i){ for(auto i = 0u ; i < 1u << 20u ; ++i){
@ -171,11 +163,11 @@ TEST_F(EGCPoolTest, ForceReallocationWithRemovals) {
candidates.push_back(-1); candidates.push_back(-1);
continue; continue;
} }
ASSERT_GE(sizeof(mb), r); REQUIRE(sizeof(mb) >= r);
mb[r] = '\0'; mb[r] = '\0';
candidates.push_back(egcpool_stash(&pool_, mb, r)); candidates.push_back(egcpool_stash(&pool_, mb, r));
ASSERT_GT(1u << 24u, candidates[i]); REQUIRE((1u << 24u) > candidates[i]);
if(pool_.pool != curpool){ if(pool_.pool != curpool){
// cut through and release a bunch of them // cut through and release a bunch of them
if(curpool){ if(curpool){
@ -200,12 +192,17 @@ TEST_F(EGCPoolTest, ForceReallocationWithRemovals) {
wchar_t wcs = (i % 0x1000) + 0x80; wchar_t wcs = (i % 0x1000) + 0x80;
auto r = wctomb(mb, wcs); auto r = wctomb(mb, wcs);
if(r < 0){ if(r < 0){
ASSERT_EQ(-1, candidates[i]); REQUIRE(-1 == candidates[i]);
continue; continue;
} }
ASSERT_LT(0, r); REQUIRE(0 < r);
mb[r] = '\0'; mb[r] = '\0';
EXPECT_STREQ(mb, stored); CHECK(!strcmp(mb, stored));
} }
ASSERT_GT(candidates.size() / 13, no); CHECK(candidates.size() / 13 > no);
}
// common cleanup
egcpool_dump(&pool_);
} }

View File

@ -2,120 +2,109 @@
#include <cfenv> #include <cfenv>
#include <iostream> #include <iostream>
class EnmetricTest : public :: testing::Test {
protected:
void SetUp() override {
setlocale(LC_ALL, "");
decisep_ = localeconv()->decimal_point;
ASSERT_NE(nullptr, decisep_);
ASSERT_EQ(1, strlen(decisep_));
}
void TearDown() override {
}
const char* decisep_{};
char* impericize_enmetric(uintmax_t val, unsigned decimal, char* buf,
int omitdec, unsigned mult, int uprefix);
};
// run enmetric, and then change any localized decimal separator into our // run enmetric, and then change any localized decimal separator into our
// proud imperial yankee capitalist democratic one dot under god period. // proud imperial yankee capitalist democratic one dot under god period.
// manifest destiny, bitchhhhhhhezzzz! // manifest destiny, bitchhhhhhhezzzz!
char* EnmetricTest::impericize_enmetric(uintmax_t val, unsigned decimal, char* impericize_enmetric(uintmax_t val, unsigned decimal, char* buf,
char* buf, int omitdec, unsigned mult, int omitdec, unsigned mult, int uprefix) {
int uprefix) { const char* decisep = localeconv()->decimal_point;
enmetric(val, decimal, buf, omitdec, mult, uprefix); REQUIRE(decisep);
REQUIRE(1 == strlen(decisep));
REQUIRE(enmetric(val, decimal, buf, omitdec, mult, uprefix));
char* commie = buf; char* commie = buf;
while( (commie = strstr(commie, decisep_)) ){ while( (commie = strstr(commie, decisep)) ){
*commie = '.'; // https://dank.qemfd.net/images/16whcc.jpg *commie = '.'; // https://dank.qemfd.net/images/16whcc.jpg
++commie; ++commie;
} }
return buf; return buf;
} }
TEST_F(EnmetricTest, CornerInts) { TEST_CASE("Enmetric") {
const char* decisep = localeconv()->decimal_point;
REQUIRE(decisep);
REQUIRE(1 == strlen(decisep));
SUBCASE("CornerInts") {
char buf[PREFIXSTRLEN + 1]; char buf[PREFIXSTRLEN + 1];
impericize_enmetric(0, 1, buf, 0, 1000, '\0'); impericize_enmetric(0, 1, buf, 0, 1000, '\0');
EXPECT_STREQ("0.00", buf); CHECK(!strcmp("0.00", buf));
impericize_enmetric(0, 1, buf, 0, 1024, 'i'); impericize_enmetric(0, 1, buf, 0, 1024, 'i');
EXPECT_STREQ("0.00", buf); // no suffix on < mult CHECK(!strcmp("0.00", buf)); // no suffix on < mult
impericize_enmetric(1, 1, buf, 0, 1000, '\0'); impericize_enmetric(1, 1, buf, 0, 1000, '\0');
EXPECT_STREQ("1.00", buf); CHECK(!strcmp("1.00", buf));
impericize_enmetric(1, 1, buf, 0, 1024, 'i'); impericize_enmetric(1, 1, buf, 0, 1024, 'i');
EXPECT_STREQ("1.00", buf); CHECK(!strcmp("1.00", buf));
impericize_enmetric(0, 1, buf, 1, 1000, '\0'); impericize_enmetric(0, 1, buf, 1, 1000, '\0');
EXPECT_STREQ("0", buf); CHECK(!strcmp("0", buf));
impericize_enmetric(0, 1, buf, 1, 1024, 'i'); impericize_enmetric(0, 1, buf, 1, 1024, 'i');
EXPECT_STREQ("0", buf); // no suffix on < mult CHECK(!strcmp("0", buf)); // no suffix on < mult
impericize_enmetric(1, 1, buf, 1, 1000, '\0'); impericize_enmetric(1, 1, buf, 1, 1000, '\0');
EXPECT_STREQ("1", buf); CHECK(!strcmp("1", buf));
impericize_enmetric(1, 1, buf, 1, 1024, 'i'); impericize_enmetric(1, 1, buf, 1, 1024, 'i');
EXPECT_STREQ("1", buf); CHECK(!strcmp("1", buf));
impericize_enmetric(999, 1, buf, 1, 1000, '\0'); impericize_enmetric(999, 1, buf, 1, 1000, '\0');
EXPECT_STREQ("999", buf); CHECK(!strcmp("999", buf));
impericize_enmetric(1000, 1, buf, 1, 1000, '\0'); impericize_enmetric(1000, 1, buf, 1, 1000, '\0');
EXPECT_STREQ("1K", buf); CHECK(!strcmp("1K", buf));
impericize_enmetric(1000, 1, buf, 1, 1000, 'i'); impericize_enmetric(1000, 1, buf, 1, 1000, 'i');
EXPECT_STREQ("1Ki", buf); CHECK(!strcmp("1Ki", buf));
impericize_enmetric(1000, 1, buf, 1, 1024, 'i'); impericize_enmetric(1000, 1, buf, 1, 1024, 'i');
EXPECT_STREQ("1000", buf); // FIXME should be 0.977Ki CHECK(!strcmp("1000", buf)); // FIXME should be 0.977Ki
impericize_enmetric(1023, 1, buf, 1, 1000, '\0'); impericize_enmetric(1023, 1, buf, 1, 1000, '\0');
EXPECT_STREQ("1.02K", buf); CHECK(!strcmp("1.02K", buf));
impericize_enmetric(1023, 1, buf, 1, 1024, 'i'); impericize_enmetric(1023, 1, buf, 1, 1024, 'i');
EXPECT_STREQ("1023", buf); CHECK(!strcmp("1023", buf));
impericize_enmetric(1024, 1, buf, 1, 1000, '\0'); impericize_enmetric(1024, 1, buf, 1, 1000, '\0');
EXPECT_STREQ("1.02K", buf); CHECK(!strcmp("1.02K", buf));
impericize_enmetric(1024, 1, buf, 1, 1024, 'i'); impericize_enmetric(1024, 1, buf, 1, 1024, 'i');
EXPECT_STREQ("1Ki", buf); CHECK(!strcmp("1Ki", buf));
impericize_enmetric(1025, 1, buf, 1, 1000, '\0'); impericize_enmetric(1025, 1, buf, 1, 1000, '\0');
EXPECT_STREQ("1.02K", buf); CHECK(!strcmp("1.02K", buf));
impericize_enmetric(1025, 1, buf, 0, 1024, 'i'); impericize_enmetric(1025, 1, buf, 0, 1024, 'i');
EXPECT_STREQ("1.00Ki", buf); CHECK(!strcmp("1.00Ki", buf));
impericize_enmetric(1025, 1, buf, 1, 1024, 'i'); impericize_enmetric(1025, 1, buf, 1, 1024, 'i');
EXPECT_STREQ("1.00Ki", buf); CHECK(!strcmp("1.00Ki", buf));
impericize_enmetric(4096, 1, buf, 1, 1000, '\0'); impericize_enmetric(4096, 1, buf, 1, 1000, '\0');
EXPECT_STREQ("4.09K", buf); CHECK(!strcmp("4.09K", buf));
impericize_enmetric(4096, 1, buf, 1, 1024, 'i'); impericize_enmetric(4096, 1, buf, 1, 1024, 'i');
EXPECT_STREQ("4Ki", buf); CHECK(!strcmp("4Ki", buf));
} }
TEST_F(EnmetricTest, Maxints) { SUBCASE("Maxints") {
char buf[PREFIXSTRLEN + 1]; char buf[PREFIXSTRLEN + 1];
// FIXME these will change based on the size of intmax_t and uintmax_t // FIXME these will change based on the size of intmax_t and uintmax_t
impericize_enmetric(INTMAX_MAX - 1, 1, buf, 0, 1000, '\0'); impericize_enmetric(INTMAX_MAX - 1, 1, buf, 0, 1000, '\0');
EXPECT_STREQ("9.22E", buf); CHECK(!strcmp("9.22E", buf));
impericize_enmetric(INTMAX_MAX, 1, buf, 0, 1000, '\0'); impericize_enmetric(INTMAX_MAX, 1, buf, 0, 1000, '\0');
EXPECT_STREQ("9.22E", buf); CHECK(!strcmp("9.22E", buf));
impericize_enmetric(UINTMAX_MAX - 1, 1, buf, 0, 1000, '\0'); impericize_enmetric(UINTMAX_MAX - 1, 1, buf, 0, 1000, '\0');
EXPECT_STREQ("18.44E", buf); CHECK(!strcmp("18.44E", buf));
impericize_enmetric(UINTMAX_MAX, 1, buf, 0, 1000, '\0'); impericize_enmetric(UINTMAX_MAX, 1, buf, 0, 1000, '\0');
EXPECT_STREQ("18.44E", buf); CHECK(!strcmp("18.44E", buf));
} }
TEST_F(EnmetricTest, Maxints1024) { SUBCASE("Maxints1024") {
ASSERT_EQ(0, fesetround(FE_TOWARDZERO)); REQUIRE(0 == fesetround(FE_TOWARDZERO));
char buf[PREFIXSTRLEN + 1], gold[PREFIXSTRLEN + 1]; char buf[PREFIXSTRLEN + 1], gold[PREFIXSTRLEN + 1];
// FIXME these will change based on the size of intmax_t and uintmax_t // FIXME these will change based on the size of intmax_t and uintmax_t
enmetric(INTMAX_MAX - 1, 1, buf, 0, 1024, 'i'); enmetric(INTMAX_MAX - 1, 1, buf, 0, 1024, 'i');
sprintf(gold, "%.2fEi", ((double)(INTMAX_MAX - (1ull << 53))) / (1ull << 60)); sprintf(gold, "%.2fEi", ((double)(INTMAX_MAX - (1ull << 53))) / (1ull << 60));
EXPECT_STREQ(gold, buf); CHECK(!strcmp(gold, buf));
enmetric(INTMAX_MAX + 1ull, 1, buf, 0, 1024, 'i'); enmetric(INTMAX_MAX + 1ull, 1, buf, 0, 1024, 'i');
sprintf(gold, "%.2fEi", ((double)(INTMAX_MAX + 1ull)) / (1ull << 60)); sprintf(gold, "%.2fEi", ((double)(INTMAX_MAX + 1ull)) / (1ull << 60));
EXPECT_STREQ(gold, buf); CHECK(!strcmp(gold, buf));
impericize_enmetric(UINTMAX_MAX - 1, 1, buf, 0, 1024, 'i'); impericize_enmetric(UINTMAX_MAX - 1, 1, buf, 0, 1024, 'i');
EXPECT_STREQ("15.99Ei", buf); CHECK(!strcmp("15.99Ei", buf));
impericize_enmetric(UINTMAX_MAX, 1, buf, 0, 1024, 'i'); impericize_enmetric(UINTMAX_MAX, 1, buf, 0, 1024, 'i');
EXPECT_STREQ("15.99Ei", buf); CHECK(!strcmp("15.99Ei", buf));
enmetric(UINTMAX_MAX - (1ull << 53), 1, buf, 0, 1024, 'i'); enmetric(UINTMAX_MAX - (1ull << 53), 1, buf, 0, 1024, 'i');
sprintf(gold, "%.2fEi", ((double)UINTMAX_MAX - (1ull << 53)) / (1ull << 60)); sprintf(gold, "%.2fEi", ((double)UINTMAX_MAX - (1ull << 53)) / (1ull << 60));
EXPECT_STREQ(gold, buf); CHECK(!strcmp(gold, buf));
} }
const char suffixes[] = "\0KMGTPE"; const char suffixes[] = "\0KMGTPE";
TEST_F(EnmetricTest, PowersOfTen) { SUBCASE("PowersOfTen") {
char gold[PREFIXSTRLEN + 1]; char gold[PREFIXSTRLEN + 1];
char buf[PREFIXSTRLEN + 1]; char buf[PREFIXSTRLEN + 1];
uintmax_t goldval = 1; uintmax_t goldval = 1;
@ -124,8 +113,8 @@ TEST_F(EnmetricTest, PowersOfTen) {
do{ do{
enmetric(val, 1, buf, 0, 1000, '\0'); enmetric(val, 1, buf, 0, 1000, '\0');
const int sidx = i / 3; const int sidx = i / 3;
snprintf(gold, sizeof(gold), "%ju%s00%c", goldval, decisep_, suffixes[sidx]); snprintf(gold, sizeof(gold), "%ju%s00%c", goldval, decisep, suffixes[sidx]);
EXPECT_STREQ(gold, buf); CHECK(!strcmp(gold, buf));
if(UINTMAX_MAX / val < 10){ if(UINTMAX_MAX / val < 10){
break; break;
} }
@ -135,10 +124,10 @@ TEST_F(EnmetricTest, PowersOfTen) {
} }
}while(++i < sizeof(suffixes) * 3); }while(++i < sizeof(suffixes) * 3);
// If we ran through all our suffixes, that's a problem // If we ran through all our suffixes, that's a problem
EXPECT_GT(sizeof(suffixes) * 3, i); CHECK(sizeof(suffixes) * 3 > i);
} }
TEST_F(EnmetricTest, PowersOfTenNoDec) { SUBCASE("PowersOfTenNoDec") {
char gold[PREFIXSTRLEN + 1]; char gold[PREFIXSTRLEN + 1];
char buf[PREFIXSTRLEN + 1]; char buf[PREFIXSTRLEN + 1];
uintmax_t goldval = 1; uintmax_t goldval = 1;
@ -148,7 +137,7 @@ TEST_F(EnmetricTest, PowersOfTenNoDec) {
enmetric(val, 1, buf, 1, 1000, '\0'); enmetric(val, 1, buf, 1, 1000, '\0');
const int sidx = i / 3; const int sidx = i / 3;
snprintf(gold, sizeof(gold), "%ju%c", goldval, suffixes[sidx]); snprintf(gold, sizeof(gold), "%ju%c", goldval, suffixes[sidx]);
EXPECT_STREQ(gold, buf); CHECK(!strcmp(gold, buf));
if(UINTMAX_MAX / val < 10){ if(UINTMAX_MAX / val < 10){
break; break;
} }
@ -158,10 +147,10 @@ TEST_F(EnmetricTest, PowersOfTenNoDec) {
} }
}while(++i < sizeof(suffixes) * 3); }while(++i < sizeof(suffixes) * 3);
// If we ran through all our suffixes, that's a problem // If we ran through all our suffixes, that's a problem
EXPECT_GT(sizeof(suffixes) * 3, i); CHECK(sizeof(suffixes) * 3 > i);
} }
TEST_F(EnmetricTest, PowersOfTwo) { SUBCASE("PowersOfTwo") {
char gold[BPREFIXSTRLEN + 1]; char gold[BPREFIXSTRLEN + 1];
char buf[BPREFIXSTRLEN + 1]; char buf[BPREFIXSTRLEN + 1];
uintmax_t goldval = 1; uintmax_t goldval = 1;
@ -170,8 +159,8 @@ TEST_F(EnmetricTest, PowersOfTwo) {
do{ do{
enmetric(val, 1, buf, 0, 1024, 'i'); enmetric(val, 1, buf, 0, 1024, 'i');
const int sidx = i / 10; const int sidx = i / 10;
snprintf(gold, sizeof(gold), "%ju%s00%ci", goldval, decisep_, suffixes[sidx]); snprintf(gold, sizeof(gold), "%ju%s00%ci", goldval, decisep, suffixes[sidx]);
EXPECT_STREQ(gold, buf); CHECK(!strcmp(gold, buf));
if(UINTMAX_MAX / val < 10){ if(UINTMAX_MAX / val < 10){
break; break;
} }
@ -181,10 +170,10 @@ TEST_F(EnmetricTest, PowersOfTwo) {
} }
}while(++i < sizeof(suffixes) * 10); }while(++i < sizeof(suffixes) * 10);
// If we ran through all our suffixes, that's a problem // If we ran through all our suffixes, that's a problem
EXPECT_GT(sizeof(suffixes) * 10, i); CHECK(sizeof(suffixes) * 10 > i);
} }
TEST_F(EnmetricTest, PowersOfTwoNoDec) { SUBCASE("PowersOfTwoNoDec") {
char gold[BPREFIXSTRLEN + 1]; char gold[BPREFIXSTRLEN + 1];
char buf[BPREFIXSTRLEN + 1]; char buf[BPREFIXSTRLEN + 1];
uintmax_t goldval = 1; uintmax_t goldval = 1;
@ -194,7 +183,7 @@ TEST_F(EnmetricTest, PowersOfTwoNoDec) {
enmetric(val, 1, buf, 1, 1024, 'i'); enmetric(val, 1, buf, 1, 1024, 'i');
const int sidx = i / 10; const int sidx = i / 10;
snprintf(gold, sizeof(gold), "%ju%ci", goldval, suffixes[sidx]); snprintf(gold, sizeof(gold), "%ju%ci", goldval, suffixes[sidx]);
EXPECT_STREQ(gold, buf); CHECK(!strcmp(gold, buf));
if(UINTMAX_MAX / val < 10){ if(UINTMAX_MAX / val < 10){
break; break;
} }
@ -204,22 +193,22 @@ TEST_F(EnmetricTest, PowersOfTwoNoDec) {
} }
}while(++i < sizeof(suffixes) * 10); }while(++i < sizeof(suffixes) * 10);
// If we ran through all our suffixes, that's a problem // If we ran through all our suffixes, that's a problem
EXPECT_GT(sizeof(suffixes) * 10, i); CHECK(sizeof(suffixes) * 10 > i);
} }
TEST_F(EnmetricTest, PowersOfTwoAsTens) { SUBCASE("PowersOfTwoAsTens") {
char gold[PREFIXSTRLEN + 1]; char gold[PREFIXSTRLEN + 1];
char buf[PREFIXSTRLEN + 1]; char buf[PREFIXSTRLEN + 1];
uintmax_t vfloor = 1; uintmax_t vfloor = 1;
uintmax_t val = 1; uintmax_t val = 1;
size_t i = 0; size_t i = 0;
ASSERT_EQ(0, fesetround(FE_TOWARDZERO)); REQUIRE(0 == fesetround(FE_TOWARDZERO));
do{ do{
enmetric(val, 1, buf, 0, 1000, '\0'); enmetric(val, 1, buf, 0, 1000, '\0');
const int sidx = i / 10; const int sidx = i / 10;
snprintf(gold, sizeof(gold), "%.2f%c", snprintf(gold, sizeof(gold), "%.2f%c",
((double)val) / vfloor, suffixes[sidx]); ((double)val) / vfloor, suffixes[sidx]);
EXPECT_STREQ(gold, buf); CHECK(!strcmp(gold, buf));
if(UINTMAX_MAX / val < 10){ if(UINTMAX_MAX / val < 10){
break; break;
} }
@ -229,22 +218,22 @@ TEST_F(EnmetricTest, PowersOfTwoAsTens) {
} }
}while(++i < sizeof(suffixes) * 10); }while(++i < sizeof(suffixes) * 10);
// If we ran through all our suffixes, that's a problem // If we ran through all our suffixes, that's a problem
EXPECT_GT(sizeof(suffixes) * 10, i); CHECK(sizeof(suffixes) * 10 > i);
} }
TEST_F(EnmetricTest, PowersOfTenAsTwos) { SUBCASE("PowersOfTenAsTwos") {
char gold[BPREFIXSTRLEN + 1]; char gold[BPREFIXSTRLEN + 1];
char buf[BPREFIXSTRLEN + 1]; char buf[BPREFIXSTRLEN + 1];
uintmax_t vfloor = 1; uintmax_t vfloor = 1;
uintmax_t val = 1; uintmax_t val = 1;
size_t i = 0; size_t i = 0;
ASSERT_EQ(0, fesetround(FE_TOWARDZERO)); REQUIRE(0 == fesetround(FE_TOWARDZERO));
do{ do{
enmetric(val, 1, buf, 0, 1024, 'i'); enmetric(val, 1, buf, 0, 1024, 'i');
const int sidx = i ? (i - 1) / 3 : 0; const int sidx = i ? (i - 1) / 3 : 0;
snprintf(gold, sizeof(gold), "%.2f%ci", snprintf(gold, sizeof(gold), "%.2f%ci",
((double)val) / vfloor, suffixes[sidx]); ((double)val) / vfloor, suffixes[sidx]);
EXPECT_STREQ(gold, buf); CHECK(!strcmp(gold, buf));
if(UINTMAX_MAX / val < 10){ if(UINTMAX_MAX / val < 10){
break; break;
} }
@ -254,22 +243,22 @@ TEST_F(EnmetricTest, PowersOfTenAsTwos) {
} }
}while(++i < sizeof(suffixes) * 10); }while(++i < sizeof(suffixes) * 10);
// If we ran through all our suffixes, that's a problem // If we ran through all our suffixes, that's a problem
EXPECT_GT(sizeof(suffixes) * 10, i); CHECK(sizeof(suffixes) * 10 > i);
} }
TEST_F(EnmetricTest, PowersOfTenMinusOne) { SUBCASE("PowersOfTenMinusOne") {
char gold[PREFIXSTRLEN + 1]; char gold[PREFIXSTRLEN + 1];
char buf[PREFIXSTRLEN + 1]; char buf[PREFIXSTRLEN + 1];
uintmax_t vfloor = 1; uintmax_t vfloor = 1;
uintmax_t val = 1; uintmax_t val = 1;
size_t i = 0; size_t i = 0;
ASSERT_EQ(0, fesetround(FE_TOWARDZERO)); REQUIRE(0 == fesetround(FE_TOWARDZERO));
do{ do{
enmetric(val - 1, 1, buf, 0, 1000, '\0'); enmetric(val - 1, 1, buf, 0, 1000, '\0');
const int sidx = i ? (i - 1) / 3 : 0; const int sidx = i ? (i - 1) / 3 : 0;
snprintf(gold, sizeof(gold), "%.2f%c", snprintf(gold, sizeof(gold), "%.2f%c",
((double)(val - 1)) / vfloor, suffixes[sidx]); ((double)(val - 1)) / vfloor, suffixes[sidx]);
EXPECT_STREQ(gold, buf); CHECK(!strcmp(gold, buf));
if(UINTMAX_MAX / val < 10){ if(UINTMAX_MAX / val < 10){
break; break;
} }
@ -279,22 +268,22 @@ TEST_F(EnmetricTest, PowersOfTenMinusOne) {
} }
}while(++i < sizeof(suffixes) * 3); }while(++i < sizeof(suffixes) * 3);
// If we ran through all our suffixes, that's a problem // If we ran through all our suffixes, that's a problem
EXPECT_GT(sizeof(suffixes) * 3, i); CHECK(sizeof(suffixes) * 3 > i);
} }
TEST_F(EnmetricTest, PowersOfTenPlusOne) { SUBCASE("PowersOfTenPlusOne") {
char gold[PREFIXSTRLEN + 1]; char gold[PREFIXSTRLEN + 1];
char buf[PREFIXSTRLEN + 1]; char buf[PREFIXSTRLEN + 1];
uintmax_t vfloor = 1; uintmax_t vfloor = 1;
uintmax_t val = 1; uintmax_t val = 1;
size_t i = 0; size_t i = 0;
ASSERT_EQ(0, fesetround(FE_TOWARDZERO)); REQUIRE(0 == fesetround(FE_TOWARDZERO));
do{ do{
enmetric(val + 1, 1, buf, 0, 1000, '\0'); enmetric(val + 1, 1, buf, 0, 1000, '\0');
const int sidx = i / 3; const int sidx = i / 3;
snprintf(gold, sizeof(gold), "%.2f%c", snprintf(gold, sizeof(gold), "%.2f%c",
((double)(val + 1)) / vfloor, suffixes[sidx]); ((double)(val + 1)) / vfloor, suffixes[sidx]);
EXPECT_STREQ(gold, buf); CHECK(!strcmp(gold, buf));
if(UINTMAX_MAX / val < 10){ if(UINTMAX_MAX / val < 10){
break; break;
} }
@ -304,22 +293,22 @@ TEST_F(EnmetricTest, PowersOfTenPlusOne) {
} }
}while(++i < sizeof(suffixes) * 3); }while(++i < sizeof(suffixes) * 3);
// If we ran through all our suffixes, that's a problem // If we ran through all our suffixes, that's a problem
EXPECT_GT(sizeof(suffixes) * 3, i); CHECK(sizeof(suffixes) * 3 > i);
} }
TEST_F(EnmetricTest, PowersOfTenMinusOneAsTwos) { SUBCASE("PowersOfTenMinusOneAsTwos") {
char gold[BPREFIXSTRLEN + 1]; char gold[BPREFIXSTRLEN + 1];
char buf[BPREFIXSTRLEN + 1]; char buf[BPREFIXSTRLEN + 1];
uintmax_t vfloor = 1; uintmax_t vfloor = 1;
uintmax_t val = 1; uintmax_t val = 1;
size_t i = 0; size_t i = 0;
ASSERT_EQ(0, fesetround(FE_TOWARDZERO)); REQUIRE(0 == fesetround(FE_TOWARDZERO));
do{ do{
enmetric(val - 1, 1, buf, 0, 1024, 'i'); enmetric(val - 1, 1, buf, 0, 1024, 'i');
const int sidx = i ? (i - 1) / 3 : 0; const int sidx = i ? (i - 1) / 3 : 0;
snprintf(gold, sizeof(gold), "%.2f%ci", snprintf(gold, sizeof(gold), "%.2f%ci",
((double)(val - 1)) / vfloor, suffixes[sidx]); ((double)(val - 1)) / vfloor, suffixes[sidx]);
EXPECT_STREQ(gold, buf); CHECK(!strcmp(gold, buf));
if(UINTMAX_MAX / val < 10){ if(UINTMAX_MAX / val < 10){
break; break;
} }
@ -329,5 +318,7 @@ TEST_F(EnmetricTest, PowersOfTenMinusOneAsTwos) {
} }
}while(++i < sizeof(suffixes) * 10); }while(++i < sizeof(suffixes) * 10);
// If we ran through all our suffixes, that's a problem // If we ran through all our suffixes, that's a problem
EXPECT_GT(sizeof(suffixes) * 10, i); CHECK(sizeof(suffixes) * 10 > i);
}
} }

View File

@ -2,25 +2,22 @@
#include <cstdlib> #include <cstdlib>
#include <iostream> #include <iostream>
class FadeTest : public :: testing::Test { TEST_CASE("Fade") {
protected:
void SetUp() override {
setlocale(LC_ALL, "");
if(getenv("TERM") == nullptr){ if(getenv("TERM") == nullptr){
GTEST_SKIP(); return;
} }
FILE* outfp_ = fopen("/dev/tty", "wb");
REQUIRE(outfp_);
notcurses_options nopts{}; notcurses_options nopts{};
nopts.inhibit_alternate_screen = true; nopts.inhibit_alternate_screen = true;
outfp_ = fopen("/dev/tty", "wb"); struct notcurses* nc_ = notcurses_init(&nopts, outfp_);
ASSERT_NE(nullptr, outfp_); REQUIRE(nc_);
nc_ = notcurses_init(&nopts, outfp_); struct ncplane* n_ = notcurses_stdplane(nc_);
ASSERT_NE(nullptr, nc_); REQUIRE(n_);
if(!notcurses_canfade(nc_)){ if(!notcurses_canfade(nc_)){
GTEST_SKIP(); return;
} }
n_ = notcurses_stdplane(nc_); REQUIRE(0 == ncplane_cursor_move_yx(n_, 0, 0));
ASSERT_NE(nullptr, n_);
ASSERT_EQ(0, ncplane_cursor_move_yx(n_, 0, 0));
int dimy, dimx; int dimy, dimx;
ncplane_dim_yx(n_, &dimy, &dimx); ncplane_dim_yx(n_, &dimy, &dimx);
cell c = CELL_TRIVIAL_INITIALIZER; cell c = CELL_TRIVIAL_INITIALIZER;
@ -35,36 +32,26 @@ class FadeTest : public :: testing::Test {
} }
cell_set_fg_rgb(&c, (rgb >> 16u) & 0xff, (rgb >> 8u) & 0xff, rgb & 0xff); cell_set_fg_rgb(&c, (rgb >> 16u) & 0xff, (rgb >> 8u) & 0xff, rgb & 0xff);
cell_set_bg_rgb(&c, rgb & 0xff, (rgb >> 16u) & 0xff, (rgb >> 8u) & 0xff); cell_set_bg_rgb(&c, rgb & 0xff, (rgb >> 16u) & 0xff, (rgb >> 8u) & 0xff);
EXPECT_LT(0, ncplane_putc(n_, &c)); CHECK(0 < ncplane_putc(n_, &c));
}
}
}
void TearDown() override {
if(nc_){
EXPECT_EQ(0, notcurses_stop(nc_));
}
if(outfp_){
fclose(outfp_);
} }
} }
struct notcurses* nc_{}; SUBCASE("FadeOut") {
struct ncplane* n_{}; CHECK(0 == notcurses_render(nc_));
FILE* outfp_{};
};
TEST_F(FadeTest, FadeOut) {
EXPECT_EQ(0, notcurses_render(nc_));
struct timespec ts; struct timespec ts;
ts.tv_sec = 1; ts.tv_sec = 1;
ts.tv_nsec = 0; ts.tv_nsec = 0;
ASSERT_EQ(0, ncplane_fadeout(n_, &ts, nullptr)); REQUIRE(0 == ncplane_fadeout(n_, &ts, nullptr));
} }
TEST_F(FadeTest, FadeIn) { SUBCASE("FadeIn") {
struct timespec ts; struct timespec ts;
ts.tv_sec = 1; ts.tv_sec = 1;
ts.tv_nsec = 0; ts.tv_nsec = 0;
ASSERT_EQ(0, ncplane_fadein(n_, &ts, nullptr)); REQUIRE(0 == ncplane_fadein(n_, &ts, nullptr));
}
CHECK(0 == notcurses_stop(nc_));
CHECK(0 == fclose(outfp_));
} }

View File

@ -1,38 +1,20 @@
#include "main.h" #include "main.h"
class InputTest : public :: testing::Test { TEST_CASE("NotcursesInput") {
protected:
void SetUp() override {
setlocale(LC_ALL, "");
if(getenv("TERM") == nullptr){ if(getenv("TERM") == nullptr){
GTEST_SKIP(); return;
} }
notcurses_options nopts{}; notcurses_options nopts{};
nopts.inhibit_alternate_screen = true; nopts.inhibit_alternate_screen = true;
nopts.suppress_bannner = true; nopts.suppress_bannner = true;
outfp_ = fopen("/dev/tty", "wb"); FILE* outfp_ = fopen("/dev/tty", "wb");
ASSERT_NE(nullptr, outfp_); REQUIRE(outfp_);
nc_ = notcurses_init(&nopts, outfp_); struct notcurses* nc_ = notcurses_init(&nopts, outfp_);
ASSERT_NE(nullptr, nc_); REQUIRE(nc_);
}
void TearDown() override { REQUIRE(0 == notcurses_mouse_enable(nc_));
if(nc_){ CHECK(0 == notcurses_mouse_disable(nc_));
EXPECT_EQ(0, notcurses_stop(nc_));
}
if(outfp_){
fclose(outfp_);
}
}
struct notcurses* nc_{}; CHECK(0 == notcurses_stop(nc_));
FILE* outfp_{}; CHECK(0 == fclose(outfp_));
};
TEST_F(InputTest, TestMouseOn){
ASSERT_EQ(0, notcurses_mouse_enable(nc_));
}
TEST_F(InputTest, TestMouseOff){
ASSERT_EQ(0, notcurses_mouse_disable(nc_));
} }

View File

@ -4,79 +4,72 @@
#include "internal.h" #include "internal.h"
#include "main.h" #include "main.h"
class InternalsTest : public :: testing::Test { TEST_CASE("RGBtoANSIWhite") {
protected:
void SetUp() override {
setlocale(LC_ALL, "");
}
};
TEST_F(InternalsTest, RGBtoANSIWhite) {
unsigned r, g, b; unsigned r, g, b;
for(r = 250 ; r < 256 ; ++r){ for(r = 250 ; r < 256 ; ++r){
g = b = r; g = b = r;
EXPECT_EQ(15, rgb_quantize_256(r, g, b)); CHECK(15 == rgb_quantize_256(r, g, b));
} }
} }
TEST_F(InternalsTest, RGBtoANSIBlack) { TEST_CASE("RGBtoANSIBlack") {
unsigned r, g, b; unsigned r, g, b;
for(r = 0 ; r < 10 ; ++r){ for(r = 0 ; r < 10 ; ++r){
g = b = r; g = b = r;
EXPECT_EQ(0, rgb_quantize_256(r, g, b)); CHECK(0 == rgb_quantize_256(r, g, b));
} }
} }
TEST_F(InternalsTest, RGBtoANSIGrey) { TEST_CASE("RGBtoANSIGrey") {
unsigned r, g, b; unsigned r, g, b;
for(r = 10 ; r < 244 ; ++r){ for(r = 10 ; r < 244 ; ++r){
g = b = r; g = b = r;
EXPECT_EQ(231 + (r * 5) / 49, rgb_quantize_256(r, g, b)); CHECK(231 + (r * 5) / 49 == rgb_quantize_256(r, g, b));
} }
} }
// Pure reds are either 0 (black), or 16 plus 36 * [0..5]. // Pure reds are either 0 (black), or 16 plus 36 * [0..5].
TEST_F(InternalsTest, RGBtoANSIRed) { TEST_CASE("RGBtoANSIRed") {
unsigned r, g, b; unsigned r, g, b;
g = b = 0x0; g = b = 0x0;
for(r = 0 ; r < 256 ; ++r){ for(r = 0 ; r < 256 ; ++r){
int c256 = rgb_quantize_256(r, g, b); int c256 = rgb_quantize_256(r, g, b);
if(r < 8){ if(r < 8){
EXPECT_EQ(0, c256); CHECK(0 == c256);
}else{ }else{
EXPECT_LT(15, c256); CHECK(15 < c256);
EXPECT_EQ(16, c256 % 36); CHECK(16 == c256 % 36);
} }
} }
} }
// Pure greens are either 0 (black), or 16 plus 6 * [0..5]. // Pure greens are either 0 (black), or 16 plus 6 * [0..5].
TEST_F(InternalsTest, RGBtoANSIGreen) { TEST_CASE("RGBtoANSIGreen") {
unsigned r, g, b; unsigned r, g, b;
r = b = 0x0; r = b = 0x0;
for(g = 0 ; g < 256 ; ++g){ for(g = 0 ; g < 256 ; ++g){
int c256 = rgb_quantize_256(r, g, b); int c256 = rgb_quantize_256(r, g, b);
EXPECT_GT(48, c256); CHECK(48 > c256);
if(g < 8){ if(g < 8){
EXPECT_EQ(0, c256); CHECK(0 == c256);
}else{ }else{
EXPECT_LT(15, c256); CHECK(15 < c256);
EXPECT_EQ(4, c256 % 6); CHECK(4 == c256 % 6);
} }
} }
} }
// Pure blues are either 0 (black), or one of the first 6 colors [16..22]. // Pure blues are either 0 (black), or one of the first 6 colors [16..22].
TEST_F(InternalsTest, RGBtoANSIBlue) { TEST_CASE("RGBtoANSIBlue") {
unsigned r, g, b; unsigned r, g, b;
r = g = 0x0; r = g = 0x0;
for(b = 0 ; b < 256 ; ++b){ for(b = 0 ; b < 256 ; ++b){
int c256 = rgb_quantize_256(r, g, b); int c256 = rgb_quantize_256(r, g, b);
EXPECT_GT(22, c256); CHECK(22 > c256);
if(b < 8){ if(b < 8){
EXPECT_EQ(0, c256); CHECK(0 == c256);
}else{ }else{
EXPECT_LT(15, c256); CHECK(15 < c256);
} }
} }
} }

View File

@ -1,104 +1,92 @@
#include <notcurses.h> #include <notcurses.h>
#include "version.h" #include "version.h"
#include "main.h" #include "main.h"
#ifndef DISABLE_FFMPEG
#include <libavutil/pixdesc.h>
#include <libavutil/avconfig.h>
#include <libavcodec/avcodec.h> // ffmpeg doesn't reliably "C"-guard itself
#endif
class LibavTest : public :: testing::Test { TEST_CASE("Multimedia") {
protected:
void SetUp() override {
setlocale(LC_ALL, "");
if(getenv("TERM") == nullptr){ if(getenv("TERM") == nullptr){
GTEST_SKIP(); return;
} }
notcurses_options nopts{}; notcurses_options nopts{};
nopts.inhibit_alternate_screen = true; nopts.inhibit_alternate_screen = true;
nopts.suppress_bannner = true; nopts.suppress_bannner = true;
outfp_ = fopen("/dev/tty", "wb"); FILE* outfp_ = fopen("/dev/tty", "wb");
ASSERT_NE(nullptr, outfp_); REQUIRE(outfp_);
nc_ = notcurses_init(&nopts, outfp_); notcurses* nc_ = notcurses_init(&nopts, outfp_);
ASSERT_NE(nullptr, nc_); REQUIRE(nc_);
ncp_ = notcurses_stdplane(nc_); ncplane* ncp_ = notcurses_stdplane(nc_);
ASSERT_NE(nullptr, ncp_); REQUIRE(ncp_);
}
void TearDown() override {
if(nc_){
EXPECT_EQ(0, notcurses_stop(nc_));
}
if(outfp_){
fclose(outfp_);
}
}
notcurses* nc_{};
ncplane* ncp_{};
FILE* outfp_{};
};
#ifdef DISABLE_FFMPEG #ifdef DISABLE_FFMPEG
TEST_F(LibavTest, LibavDisabled){ SUBCASE("LibavDisabled"){
ASSERT_FALSE(notcurses_canopen(nc_)); REQUIRE(!notcurses_canopen(nc_));
} }
#else #else
#include <libavutil/pixdesc.h> SUBCASE("LibavEnabled"){
#include <libavutil/avconfig.h> REQUIRE(notcurses_canopen(nc_));
#include <libavcodec/avcodec.h> // ffmpeg doesn't reliably "C"-guard itself
TEST_F(LibavTest, LibavEnabled){
ASSERT_TRUE(notcurses_canopen(nc_));
} }
TEST_F(LibavTest, LoadImage) { SUBCASE("LoadImage") {
int averr; int averr;
int dimy, dimx; int dimy, dimx;
ncplane_dim_yx(ncp_, &dimy, &dimx); ncplane_dim_yx(ncp_, &dimy, &dimx);
auto ncv = ncplane_visual_open(ncp_, "../data/dsscaw-purp.png", &averr); auto ncv = ncplane_visual_open(ncp_, "../data/dsscaw-purp.png", &averr);
ASSERT_NE(nullptr, ncv); REQUIRE(ncv);
ASSERT_EQ(0, averr); REQUIRE(0 == averr);
auto frame = ncvisual_decode(ncv, &averr); auto frame = ncvisual_decode(ncv, &averr);
ASSERT_NE(nullptr, frame); REQUIRE(frame);
ASSERT_EQ(0, averr); REQUIRE(0 == averr);
EXPECT_EQ(dimy * 2, frame->height); CHECK(dimy * 2 == frame->height);
EXPECT_EQ(dimx, frame->width); CHECK(dimx == frame->width);
EXPECT_EQ(0, ncvisual_render(ncv, 0, 0, 0, 0)); CHECK(0 == ncvisual_render(ncv, 0, 0, 0, 0));
EXPECT_EQ(0, notcurses_render(nc_)); CHECK(0 == notcurses_render(nc_));
frame = ncvisual_decode(ncv, &averr); frame = ncvisual_decode(ncv, &averr);
ASSERT_EQ(nullptr, frame); REQUIRE_EQ(nullptr, frame);
EXPECT_EQ(AVERROR_EOF, averr); CHECK(AVERROR_EOF == averr);
ncvisual_destroy(ncv); ncvisual_destroy(ncv);
} }
// FIXME ought run through full video, not just first frame // FIXME ought run through full video, not just first frame
TEST_F(LibavTest, LoadVideo) { SUBCASE("LoadVideo") {
int averr; int averr;
int dimy, dimx; int dimy, dimx;
ncplane_dim_yx(ncp_, &dimy, &dimx); ncplane_dim_yx(ncp_, &dimy, &dimx);
auto ncv = ncplane_visual_open(ncp_, "../data/fm6.mkv", &averr); auto ncv = ncplane_visual_open(ncp_, "../data/fm6.mkv", &averr);
ASSERT_NE(nullptr, ncv); REQUIRE(ncv);
EXPECT_EQ(0, averr); CHECK(0 == averr);
auto frame = ncvisual_decode(ncv, &averr); auto frame = ncvisual_decode(ncv, &averr);
ASSERT_NE(nullptr, frame); REQUIRE(frame);
EXPECT_EQ(0, averr); CHECK(0 == averr);
EXPECT_EQ(dimy * 2, frame->height); CHECK(dimy * 2 == frame->height);
EXPECT_EQ(dimx, frame->width); CHECK(dimx == frame->width);
EXPECT_EQ(0, ncvisual_render(ncv, 0, 0, 0, 0)); CHECK(0 == ncvisual_render(ncv, 0, 0, 0, 0));
EXPECT_EQ(0, notcurses_render(nc_)); CHECK(0 == notcurses_render(nc_));
ncvisual_destroy(ncv); ncvisual_destroy(ncv);
} }
TEST_F(LibavTest, LoadVideoCreatePlane) { SUBCASE("LoadVideoCreatePlane") {
int averr; int averr;
int dimy, dimx; int dimy, dimx;
ncplane_dim_yx(ncp_, &dimy, &dimx); ncplane_dim_yx(ncp_, &dimy, &dimx);
auto ncv = ncvisual_open_plane(nc_, "../data/fm6.mkv", &averr, 0, 0, NCSCALE_STRETCH); auto ncv = ncvisual_open_plane(nc_, "../data/fm6.mkv", &averr, 0, 0, NCSCALE_STRETCH);
ASSERT_NE(nullptr, ncv); REQUIRE(ncv);
EXPECT_EQ(0, averr); CHECK(0 == averr);
auto frame = ncvisual_decode(ncv, &averr); auto frame = ncvisual_decode(ncv, &averr);
ASSERT_NE(nullptr, frame); REQUIRE_NE(nullptr, frame);
EXPECT_EQ(0, averr); CHECK(0 == averr);
EXPECT_EQ(dimy * 2, frame->height); CHECK(dimy * 2 == frame->height);
EXPECT_EQ(dimx, frame->width); CHECK(dimx == frame->width);
EXPECT_EQ(0, ncvisual_render(ncv, 0, 0, 0, 0)); CHECK(0 == ncvisual_render(ncv, 0, 0, 0, 0));
EXPECT_EQ(0, notcurses_render(nc_)); CHECK(0 == notcurses_render(nc_));
ncvisual_destroy(ncv); ncvisual_destroy(ncv);
} }
#endif #endif
CHECK(!notcurses_stop(nc_));
CHECK(!fclose(outfp_));
}

View File

@ -1,3 +1,4 @@
#define DOCTEST_CONFIG_IMPLEMENT
#include <clocale> #include <clocale>
#include <iostream> #include <iostream>
#include "main.h" #include "main.h"
@ -7,6 +8,26 @@ int main(int argc, char **argv){
std::cerr << "Coudln't set locale based on user preferences!" << std::endl; std::cerr << "Coudln't set locale based on user preferences!" << std::endl;
return EXIT_FAILURE; return EXIT_FAILURE;
} }
::testing::InitGoogleTest(&argc, argv); doctest::Context context;
return RUN_ALL_TESTS();
// defaults
context.addFilter("test-case-exclude", "*math*"); // exclude test cases with "math" in their name
context.setOption("abort-after", 5); // stop test execution after 5 failed assertions
context.setOption("order-by", "name"); // sort the test cases by their name
context.applyCommandLine(argc, argv);
// overrides
context.setOption("no-breaks", true); // don't break in the debugger when assertions fail
int res = context.run(); // run
if(context.shouldExit()){ // important - query flags (and --exit) rely on the user doing this
return res; // propagate the result of the tests
}
int client_stuff_return_code = 0;
// your program - if the testing framework is integrated in your production code
return res + client_stuff_return_code; // the result from doctest is propagated here as well
} }

View File

@ -1,14 +1,8 @@
#ifndef NOTCURSES_TEST_MAIN #ifndef NOTCURSES_TEST_MAIN
#define NOTCURSES_TEST_MAIN #define NOTCURSES_TEST_MAIN
#include <gtest/gtest.h> #include "doctest.h"
#include <notcurses.h> #include <notcurses.h>
#include <curses.h> #include <curses.h>
// GTEST_SKIP only came along in GoogleTest 1.9
#ifndef GTEST_SKIP
#define GTEST_SKIP() return;
#endif
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -1,94 +1,76 @@
#include <string> #include <string>
#include <cstdlib> #include <cstdlib>
#include <iostream>
#include <notcurses.h> #include <notcurses.h>
#include "internal.h" #include "internal.h"
#include "main.h" #include "main.h"
class NotcursesTest : public :: testing::Test { TEST_CASE("NotcursesBase") {
protected:
void SetUp() override {
setlocale(LC_ALL, "");
if(getenv("TERM") == nullptr){ if(getenv("TERM") == nullptr){
GTEST_SKIP(); return;
} }
notcurses_options nopts{}; notcurses_options nopts{};
nopts.inhibit_alternate_screen = true; nopts.inhibit_alternate_screen = true;
nopts.suppress_bannner = true; nopts.suppress_bannner = true;
outfp_ = fopen("/dev/tty", "wb"); FILE* outfp_ = fopen("/dev/tty", "wb");
ASSERT_NE(nullptr, outfp_); REQUIRE(outfp_);
nc_ = notcurses_init(&nopts, outfp_); struct notcurses* nc_ = notcurses_init(&nopts, outfp_);
ASSERT_NE(nullptr, nc_); REQUIRE(nc_);
}
void TearDown() override { SUBCASE("NotcursesVersionString") {
if(nc_){
EXPECT_EQ(0, notcurses_stop(nc_));
}
if(outfp_){
fclose(outfp_);
}
}
struct notcurses* nc_{};
FILE* outfp_{};
};
TEST_F(NotcursesTest, NotcursesVersionString) {
const char* ver = notcurses_version(); const char* ver = notcurses_version();
ASSERT_NE(nullptr, ver); REQUIRE(ver);
ASSERT_LT(0, strlen(ver)); REQUIRE(0 < strlen(ver));
std::cout << "notcurses version " << ver << std::endl; std::cout << "notcurses version " << ver << std::endl;
} }
TEST_F(NotcursesTest, BasicLifetime) { SUBCASE("TermDimensions") {
}
TEST_F(NotcursesTest, TermDimensions) {
int x, y; int x, y;
notcurses_term_dim_yx(nc_, &y, &x); notcurses_term_dim_yx(nc_, &y, &x);
auto stry = getenv("LINES"); auto stry = getenv("LINES");
if(stry){ if(stry){
auto envy = std::stoi(stry, nullptr); auto envy = std::stoi(stry, nullptr);
EXPECT_EQ(envy, y); CHECK(envy == y);
} }
auto strx = getenv("COLUMNS"); auto strx = getenv("COLUMNS");
if(stry){ if(stry){
auto envx = std::stoi(strx, nullptr); auto envx = std::stoi(strx, nullptr);
EXPECT_EQ(envx, x); CHECK(envx == x);
} }
} }
TEST_F(NotcursesTest, ResizeSameSize) { SUBCASE("ResizeSameSize") {
int x, y; int x, y;
notcurses_term_dim_yx(nc_, &y, &x); notcurses_term_dim_yx(nc_, &y, &x);
int newx, newy; int newx, newy;
EXPECT_EQ(0, notcurses_resize(nc_, &newy, &newx)); CHECK(0 == notcurses_resize(nc_, &newy, &newx));
EXPECT_EQ(newx, x); CHECK(newx == x);
EXPECT_EQ(newy, y); CHECK(newy == y);
} }
// we should at least have CELL_STYLE_BOLD everywhere, i should think? // we should at least have CELL_STYLE_BOLD everywhere, i should think?
TEST_F(NotcursesTest, CursesStyles) { SUBCASE("CursesStyles") {
unsigned attrs = notcurses_supported_styles(nc_); unsigned attrs = notcurses_supported_styles(nc_);
EXPECT_EQ(1, !!(CELL_STYLE_BOLD & attrs)); CHECK(1 == !!(CELL_STYLE_BOLD & attrs));
} }
// it is an error to attempt to destroy the standard plane // it is an error to attempt to destroy the standard plane
TEST_F(NotcursesTest, RejectDestroyStdPlane) { SUBCASE("RejectDestroyStdPlane") {
ncplane* ncp = notcurses_stdplane(nc_); ncplane* ncp = notcurses_stdplane(nc_);
ASSERT_NE(nullptr, ncp); REQUIRE(ncp);
ASSERT_NE(0, ncplane_destroy(ncp)); REQUIRE(0 > ncplane_destroy(ncp));
} }
// it is an error to attempt to move the standard plane // it is an error to attempt to move the standard plane
TEST_F(NotcursesTest, RejectMoveStdPlane) { SUBCASE("RejectMoveStdPlane") {
ncplane* ncp = notcurses_stdplane(nc_); ncplane* ncp = notcurses_stdplane(nc_);
ASSERT_NE(nullptr, ncp); REQUIRE(ncp);
ASSERT_NE(0, ncplane_move_yx(ncp, 1, 1)); REQUIRE(0 > ncplane_move_yx(ncp, 1, 1));
} }
// create planes partitioning the entirety of the screen, one at each coordinate // create planes partitioning the entirety of the screen, one at each coordinate
TEST_F(NotcursesTest, TileScreenWithPlanes) { SUBCASE("TileScreenWithPlanes") {
int maxx, maxy; int maxx, maxy;
notcurses_term_dim_yx(nc_, &maxy, &maxx); notcurses_term_dim_yx(nc_, &maxy, &maxx);
auto total = maxx * maxy; auto total = maxx * maxy;
@ -98,57 +80,62 @@ TEST_F(NotcursesTest, TileScreenWithPlanes) {
for(int x = 0 ; x < maxx ; ++x){ for(int x = 0 ; x < maxx ; ++x){
const auto idx = y * maxx + x; const auto idx = y * maxx + x;
planes[idx] = notcurses_newplane(nc_, 1, 1, y, x, &planesecrets[idx]); planes[idx] = notcurses_newplane(nc_, 1, 1, y, x, &planesecrets[idx]);
ASSERT_NE(nullptr, planes[idx]); REQUIRE(planes[idx]);
} }
} }
ASSERT_EQ(0, notcurses_render(nc_)); REQUIRE(0 == notcurses_render(nc_));
for(int y = 0 ; y < maxy ; ++y){ for(int y = 0 ; y < maxy ; ++y){
for(int x = 0 ; x < maxx ; ++x){ for(int x = 0 ; x < maxx ; ++x){
const auto idx = y * maxx + x; const auto idx = y * maxx + x;
auto userptr = ncplane_userptr(planes[idx]); auto userptr = ncplane_userptr(planes[idx]);
ASSERT_NE(nullptr, userptr); REQUIRE(userptr);
EXPECT_EQ(userptr, &planesecrets[idx]); CHECK(userptr == &planesecrets[idx]);
ASSERT_EQ(0, ncplane_destroy(planes[idx])); REQUIRE(0 == ncplane_destroy(planes[idx]));
} }
} }
delete[] planesecrets; delete[] planesecrets;
delete[] planes; delete[] planes;
ASSERT_EQ(0, notcurses_render(nc_)); REQUIRE(0 == notcurses_render(nc_));
} }
TEST_F(NotcursesTest, ChannelSetFGAlpha){ SUBCASE("ChannelSetFGAlpha"){
uint64_t channel = 0; uint64_t channel = 0;
EXPECT_GT(0, channels_set_fg_alpha(&channel, -1)); CHECK(0 > channels_set_fg_alpha(&channel, -1));
EXPECT_GT(0, channels_set_fg_alpha(&channel, 4)); CHECK(0 > channels_set_fg_alpha(&channel, 4));
EXPECT_EQ(0, channels_set_fg_alpha(&channel, CELL_ALPHA_OPAQUE)); CHECK(0 == channels_set_fg_alpha(&channel, CELL_ALPHA_OPAQUE));
EXPECT_EQ(CELL_ALPHA_OPAQUE, channels_get_fg_alpha(channel)); CHECK(CELL_ALPHA_OPAQUE == channels_get_fg_alpha(channel));
EXPECT_EQ(0, channels_set_fg_alpha(&channel, CELL_ALPHA_HIGHCONTRAST)); CHECK(0 == channels_set_fg_alpha(&channel, CELL_ALPHA_HIGHCONTRAST));
EXPECT_EQ(CELL_ALPHA_HIGHCONTRAST, channels_get_fg_alpha(channel)); CHECK(CELL_ALPHA_HIGHCONTRAST == channels_get_fg_alpha(channel));
EXPECT_TRUE(channels_fg_default_p(channel)); CHECK(channels_fg_default_p(channel));
EXPECT_TRUE(channels_bg_default_p(channel)); CHECK(channels_bg_default_p(channel));
} }
TEST_F(NotcursesTest, ChannelSetBGAlpha){ SUBCASE("ChannelSetBGAlpha"){
uint64_t channel = 0; uint64_t channel = 0;
EXPECT_GT(0, channels_set_bg_alpha(&channel, -1)); CHECK(0 > channels_set_bg_alpha(&channel, -1));
EXPECT_GT(0, channels_set_bg_alpha(&channel, 4)); CHECK(0 > channels_set_bg_alpha(&channel, 4));
EXPECT_EQ(0, channels_set_bg_alpha(&channel, CELL_ALPHA_OPAQUE)); CHECK(0 == channels_set_bg_alpha(&channel, CELL_ALPHA_OPAQUE));
EXPECT_EQ(0, channels_get_bg_alpha(channel)); CHECK(CELL_ALPHA_OPAQUE == channels_get_bg_alpha(channel));
EXPECT_EQ(0, channels_set_bg_alpha(&channel, CELL_ALPHA_TRANSPARENT)); CHECK(0 == channels_set_bg_alpha(&channel, CELL_ALPHA_TRANSPARENT));
EXPECT_NE(0, channels_set_bg_alpha(&channel, CELL_ALPHA_HIGHCONTRAST)); CHECK(0 > channels_set_bg_alpha(&channel, CELL_ALPHA_HIGHCONTRAST));
EXPECT_EQ(CELL_ALPHA_TRANSPARENT, channels_get_bg_alpha(channel)); CHECK(CELL_ALPHA_TRANSPARENT == channels_get_bg_alpha(channel));
EXPECT_TRUE(channels_fg_default_p(channel)); CHECK(channels_fg_default_p(channel));
EXPECT_TRUE(channels_bg_default_p(channel)); CHECK(channels_bg_default_p(channel));
} }
TEST_F(NotcursesTest, Stats){ SUBCASE("Stats"){
struct ncstats stats; struct ncstats stats;
notcurses_stats(nc_, &stats); notcurses_stats(nc_, &stats);
EXPECT_EQ(0, stats.renders); CHECK(0 == stats.renders);
EXPECT_EQ(0, notcurses_render(nc_)); CHECK(0 == notcurses_render(nc_));
notcurses_stats(nc_, &stats); notcurses_stats(nc_, &stats);
EXPECT_EQ(1, stats.renders); CHECK(1 == stats.renders);
notcurses_reset_stats(nc_); notcurses_reset_stats(nc_);
notcurses_stats(nc_, &stats); notcurses_stats(nc_, &stats);
EXPECT_EQ(0, stats.renders); CHECK(0 == stats.renders);
}
CHECK(0 == notcurses_stop(nc_));
CHECK(0 == fclose(outfp_));
} }

View File

@ -1,174 +1,155 @@
#include "main.h" #include "main.h"
#include <iostream> #include <iostream>
class PanelReelTest : public :: testing::Test {
protected:
void SetUp() override {
setlocale(LC_ALL, "");
if(getenv("TERM") == nullptr){
GTEST_SKIP();
}
notcurses_options nopts{};
nopts.inhibit_alternate_screen = true;
nopts.suppress_bannner = true;
outfp_ = fopen("/dev/tty", "wb");
ASSERT_NE(nullptr, outfp_);
nc_ = notcurses_init(&nopts, outfp_);
ASSERT_NE(nullptr, nc_);
n_ = notcurses_stdplane(nc_);
ASSERT_NE(nullptr, n_);
ASSERT_EQ(0, ncplane_cursor_move_yx(n_, 0, 0));
}
void TearDown() override {
if(nc_){
EXPECT_EQ(0, notcurses_stop(nc_));
}
if(outfp_){
fclose(outfp_);
}
}
struct notcurses* nc_{};
struct ncplane* n_{};
FILE* outfp_{};
};
TEST_F(PanelReelTest, InitLinear) {
panelreel_options p = { };
struct panelreel* pr = panelreel_create(n_, &p, -1);
ASSERT_NE(nullptr, pr);
}
TEST_F(PanelReelTest, InitLinearInfinite) {
panelreel_options p{};
p.infinitescroll = true;
struct panelreel* pr = panelreel_create(n_, &p, -1);
ASSERT_NE(nullptr, pr);
}
TEST_F(PanelReelTest, InitCircular) {
panelreel_options p{};
p.infinitescroll = true;
p.circular = true;
struct panelreel* pr = panelreel_create(n_, &p, -1);
ASSERT_NE(nullptr, pr);
ASSERT_EQ(0, panelreel_destroy(pr));
}
// circular is not allowed to be true when infinitescroll is false
TEST_F(PanelReelTest, FiniteCircleRejected) {
panelreel_options p{};
p.infinitescroll = false;
p.circular = true;
struct panelreel* pr = panelreel_create(n_, &p, -1);
ASSERT_EQ(nullptr, pr);
}
// We ought be able to invoke panelreel_next() and panelreel_prev() safely,
// even if there are no tablets. They both ought return nullptr.
TEST_F(PanelReelTest, MovementWithoutTablets) {
panelreel_options p{};
p.infinitescroll = false;
struct panelreel* pr = panelreel_create(n_, &p, -1);
ASSERT_NE(nullptr, pr);
EXPECT_EQ(nullptr, panelreel_next(pr));
// EXPECT_EQ(0, panelreel_validate(n_, pr));
EXPECT_EQ(nullptr, panelreel_prev(pr));
// EXPECT_EQ(0, panelreel_validate(n_, pr));
}
int panelcb(struct tablet* t, int begx, int begy, int maxx, int maxy, bool cliptop){ int panelcb(struct tablet* t, int begx, int begy, int maxx, int maxy, bool cliptop){
EXPECT_NE(nullptr, tablet_ncplane(t)); CHECK(tablet_ncplane(t));
EXPECT_LT(begx, maxx); CHECK(begx < maxx);
EXPECT_LT(begy, maxy); CHECK(begy < maxy);
EXPECT_EQ(nullptr, tablet_userptr(t)); CHECK(!tablet_userptr(t));
EXPECT_FALSE(cliptop); CHECK(!cliptop);
// FIXME verify geometry is as expected // FIXME verify geometry is as expected
return 0; return 0;
} }
TEST_F(PanelReelTest, OneTablet) { TEST_CASE("PanelReelTest") {
if(getenv("TERM") == nullptr){
return;
}
notcurses_options nopts{};
nopts.inhibit_alternate_screen = true;
nopts.suppress_bannner = true;
FILE* outfp_ = fopen("/dev/tty", "wb");
REQUIRE(outfp_);
struct notcurses* nc_ = notcurses_init(&nopts, outfp_);
REQUIRE(nc_);
struct ncplane* n_ = notcurses_stdplane(nc_);
REQUIRE(n_);
REQUIRE(0 == ncplane_cursor_move_yx(n_, 0, 0));
SUBCASE("InitLinear") {
panelreel_options p = { };
struct panelreel* pr = panelreel_create(n_, &p, -1);
REQUIRE(pr);
}
SUBCASE("InitLinearInfinite") {
panelreel_options p{};
p.infinitescroll = true;
struct panelreel* pr = panelreel_create(n_, &p, -1);
REQUIRE(pr);
}
SUBCASE("InitCircular") {
panelreel_options p{};
p.infinitescroll = true;
p.circular = true;
struct panelreel* pr = panelreel_create(n_, &p, -1);
REQUIRE(pr);
REQUIRE(0 == panelreel_destroy(pr));
}
// circular is not allowed to be true when infinitescroll is false
SUBCASE("FiniteCircleRejected") {
panelreel_options p{};
p.infinitescroll = false;
p.circular = true;
struct panelreel* pr = panelreel_create(n_, &p, -1);
REQUIRE(!pr);
}
// We ought be able to invoke panelreel_next() and panelreel_prev() safely,
// even if there are no tablets. They both ought return nullptr.
SUBCASE("MovementWithoutTablets") {
panelreel_options p{}; panelreel_options p{};
p.infinitescroll = false; p.infinitescroll = false;
struct panelreel* pr = panelreel_create(n_, &p, -1); struct panelreel* pr = panelreel_create(n_, &p, -1);
ASSERT_NE(nullptr, pr); REQUIRE(pr);
struct tablet* t = panelreel_add(pr, nullptr, nullptr, panelcb, nullptr); CHECK(!panelreel_next(pr));
ASSERT_NE(nullptr, t); // CHECK_EQ(0, panelreel_validate(n_, pr));
// EXPECT_EQ(0, panelreel_validate(n_, pr)); CHECK(!panelreel_prev(pr));
EXPECT_EQ(0, panelreel_del(pr, t)); // CHECK_EQ(0, panelreel_validate(n_, pr));
// EXPECT_EQ(0, panelreel_validate(n_, pr));
} }
TEST_F(PanelReelTest, MovementWithOneTablet) { SUBCASE("OneTablet") {
panelreel_options p{}; panelreel_options p{};
p.infinitescroll = false; p.infinitescroll = false;
struct panelreel* pr = panelreel_create(n_, &p, -1); struct panelreel* pr = panelreel_create(n_, &p, -1);
ASSERT_NE(nullptr, pr); REQUIRE(pr);
struct tablet* t = panelreel_add(pr, nullptr, nullptr, panelcb, nullptr); struct tablet* t = panelreel_add(pr, nullptr, nullptr, panelcb, nullptr);
ASSERT_NE(nullptr, t); REQUIRE(t);
// EXPECT_EQ(0, panelreel_validate(n_, pr)); // CHECK_EQ(0, panelreel_validate(n_, pr));
EXPECT_NE(nullptr, panelreel_next(pr)); CHECK(0 == panelreel_del(pr, t));
// EXPECT_EQ(0, panelreel_validate(n_, pr)); // CHECK_EQ(0, panelreel_validate(n_, pr));
EXPECT_NE(nullptr, panelreel_prev(pr));
// EXPECT_EQ(0, panelreel_validate(n_, pr));
EXPECT_EQ(0, panelreel_del(pr, t));
// EXPECT_EQ(0, panelreel_validate(n_, pr));
} }
TEST_F(PanelReelTest, DeleteActiveTablet) { SUBCASE("MovementWithOneTablet") {
panelreel_options p{}; panelreel_options p{};
p.infinitescroll = false; p.infinitescroll = false;
struct panelreel* pr = panelreel_create(n_, &p, -1); struct panelreel* pr = panelreel_create(n_, &p, -1);
ASSERT_NE(nullptr, pr); REQUIRE(pr);
struct tablet* t = panelreel_add(pr, nullptr, nullptr, panelcb, nullptr); struct tablet* t = panelreel_add(pr, nullptr, nullptr, panelcb, nullptr);
ASSERT_NE(nullptr, t); REQUIRE(t);
EXPECT_EQ(0, panelreel_del_focused(pr)); // CHECK_EQ(0, panelreel_validate(n_, pr));
CHECK(panelreel_next(pr));
// CHECK_EQ(0, panelreel_validate(n_, pr));
CHECK(panelreel_prev(pr));
// CHECK_EQ(0, panelreel_validate(n_, pr));
CHECK(0 == panelreel_del(pr, t));
// CHECK_EQ(0, panelreel_validate(n_, pr));
} }
TEST_F(PanelReelTest, NoBorder) { SUBCASE("DeleteActiveTablet") {
panelreel_options p{};
p.infinitescroll = false;
struct panelreel* pr = panelreel_create(n_, &p, -1);
REQUIRE(pr);
struct tablet* t = panelreel_add(pr, nullptr, nullptr, panelcb, nullptr);
REQUIRE(t);
CHECK(0 == panelreel_del_focused(pr));
}
SUBCASE("NoBorder") {
panelreel_options p{}; panelreel_options p{};
p.bordermask = NCBOXMASK_LEFT | NCBOXMASK_RIGHT | p.bordermask = NCBOXMASK_LEFT | NCBOXMASK_RIGHT |
NCBOXMASK_TOP | NCBOXMASK_BOTTOM; NCBOXMASK_TOP | NCBOXMASK_BOTTOM;
struct panelreel* pr = panelreel_create(n_, &p, -1); struct panelreel* pr = panelreel_create(n_, &p, -1);
ASSERT_NE(nullptr, pr); REQUIRE(pr);
} }
TEST_F(PanelReelTest, BadBorderBitsRejected) { SUBCASE("BadBorderBitsRejected") {
panelreel_options p{}; panelreel_options p{};
p.bordermask = NCBOXMASK_LEFT * 2; p.bordermask = NCBOXMASK_LEFT * 2;
struct panelreel* pr = panelreel_create(n_, &p, -1); struct panelreel* pr = panelreel_create(n_, &p, -1);
ASSERT_EQ(nullptr, pr); REQUIRE(!pr);
} }
TEST_F(PanelReelTest, NoTabletBorder) { SUBCASE("NoTabletBorder") {
panelreel_options p{}; panelreel_options p{};
p.tabletmask = NCBOXMASK_LEFT | NCBOXMASK_RIGHT | p.tabletmask = NCBOXMASK_LEFT | NCBOXMASK_RIGHT |
NCBOXMASK_TOP | NCBOXMASK_BOTTOM; NCBOXMASK_TOP | NCBOXMASK_BOTTOM;
struct panelreel* pr = panelreel_create(n_, &p, -1); struct panelreel* pr = panelreel_create(n_, &p, -1);
ASSERT_NE(nullptr, pr); REQUIRE(pr);
} }
TEST_F(PanelReelTest, NoTopBottomBorder) { SUBCASE("NoTopBottomBorder") {
panelreel_options p{}; panelreel_options p{};
p.bordermask = NCBOXMASK_TOP | NCBOXMASK_BOTTOM; p.bordermask = NCBOXMASK_TOP | NCBOXMASK_BOTTOM;
struct panelreel* pr = panelreel_create(n_, &p, -1); struct panelreel* pr = panelreel_create(n_, &p, -1);
ASSERT_NE(nullptr, pr); REQUIRE(pr);
} }
TEST_F(PanelReelTest, NoSideBorders) { SUBCASE("NoSideBorders") {
panelreel_options p{}; panelreel_options p{};
p.bordermask = NCBOXMASK_LEFT | NCBOXMASK_RIGHT; p.bordermask = NCBOXMASK_LEFT | NCBOXMASK_RIGHT;
struct panelreel* pr = panelreel_create(n_, &p, -1); struct panelreel* pr = panelreel_create(n_, &p, -1);
ASSERT_NE(nullptr, pr); REQUIRE(pr);
} }
TEST_F(PanelReelTest, BadTabletBorderBitsRejected) { SUBCASE("BadTabletBorderBitsRejected") {
panelreel_options p{}; panelreel_options p{};
p.tabletmask = NCBOXMASK_LEFT * 2; p.tabletmask = NCBOXMASK_LEFT * 2;
struct panelreel* pr = panelreel_create(n_, &p, -1); struct panelreel* pr = panelreel_create(n_, &p, -1);
ASSERT_EQ(nullptr, pr); REQUIRE(!pr);
} }
/* /*
@ -177,7 +158,7 @@ TEST_F(PanelReelTest, BadTabletBorderBitsRejected) {
struct ncpanel* make_targwin(struct ncpanel* w) { struct ncpanel* make_targwin(struct ncpanel* w) {
cchar_t cc; cchar_t cc;
int cpair = COLOR_GREEN; int cpair = COLOR_GREEN;
EXPECT_EQ(OK, setcchar(&cc, L"W", 0, 0, &cpair)); CHECK_EQ(OK, setcchar(&cc, L"W", 0, 0, &cpair));
int x, y, xx, yy; int x, y, xx, yy;
getbegyx(w, y, x); getbegyx(w, y, x);
getmaxyx(w, yy, xx); getmaxyx(w, yy, xx);
@ -186,33 +167,33 @@ struct ncpanel* make_targwin(struct ncpanel* w) {
++x; ++x;
++y; ++y;
WINDOW* ww = subwin(w, yy, xx, y, x); WINDOW* ww = subwin(w, yy, xx, y, x);
EXPECT_NE(nullptr, ww); CHECK_NE(nullptr, ww);
PANEL* p = new_panel(ww); PANEL* p = new_panel(ww);
EXPECT_NE(nullptr, p); CHECK_NE(nullptr, p);
EXPECT_EQ(OK, wbkgrnd(ww, &cc)); CHECK_EQ(OK, wbkgrnd(ww, &cc));
return p; return p;
} }
TEST_F(PanelReelTest, InitWithinSubwin) { SUBCASE("InitWithinSubwin") {
panelreel_options p{}; panelreel_options p{};
p.loff = 1; p.loff = 1;
p.roff = 1; p.roff = 1;
p.toff = 1; p.toff = 1;
p.boff = 1; p.boff = 1;
EXPECT_EQ(0, clear()); CHECK_EQ(0, clear());
PANEL* base = make_targwin(n_); PANEL* base = make_targwin(n_);
ASSERT_NE(nullptr, base); REQUIRE_NE(nullptr, base);
WINDOW* basew = panel_window(base); WINDOW* basew = panel_window(base);
ASSERT_NE(nullptr, basew); REQUIRE_NE(nullptr, basew);
struct panelreel* pr = panelreel_create(basew, &p, -1); struct panelreel* pr = panelreel_create(basew, &p, -1);
ASSERT_NE(nullptr, pr); REQUIRE_NE(nullptr, pr);
EXPECT_EQ(0, panelreel_validate(basew, pr)); CHECK_EQ(0, panelreel_validate(basew, pr));
ASSERT_EQ(0, panelreel_destroy(pr)); REQUIRE_EQ(0, panelreel_destroy(pr));
EXPECT_EQ(OK, del_panel(base)); CHECK_EQ(OK, del_panel(base));
EXPECT_EQ(OK, delwin(basew)); CHECK_EQ(OK, delwin(basew));
} }
TEST_F(PanelReelTest, SubwinNoPanelreelBorders) { SUBCASE("SubwinNoPanelreelBorders") {
panelreel_options p{}; panelreel_options p{};
p.loff = 1; p.loff = 1;
p.roff = 1; p.roff = 1;
@ -220,39 +201,43 @@ TEST_F(PanelReelTest, SubwinNoPanelreelBorders) {
p.boff = 1; p.boff = 1;
p.bordermask = NCBOXMASK_LEFT | NCBOXMASK_RIGHT | p.bordermask = NCBOXMASK_LEFT | NCBOXMASK_RIGHT |
NCBOXMASK_TOP | NCBOXMASK_BOTTOM; NCBOXMASK_TOP | NCBOXMASK_BOTTOM;
EXPECT_EQ(0, clear()); CHECK_EQ(0, clear());
PANEL* base = make_targwin(n_); PANEL* base = make_targwin(n_);
ASSERT_NE(nullptr, base); REQUIRE_NE(nullptr, base);
WINDOW* basew = panel_window(base); WINDOW* basew = panel_window(base);
ASSERT_NE(nullptr, basew); REQUIRE_NE(nullptr, basew);
struct panelreel* pr = panelreel_create(basew, &p, -1); struct panelreel* pr = panelreel_create(basew, &p, -1);
ASSERT_NE(nullptr, pr); REQUIRE_NE(nullptr, pr);
EXPECT_EQ(0, panelreel_validate(basew, pr)); CHECK_EQ(0, panelreel_validate(basew, pr));
ASSERT_EQ(0, panelreel_destroy(pr)); REQUIRE_EQ(0, panelreel_destroy(pr));
EXPECT_EQ(OK, del_panel(base)); CHECK_EQ(OK, del_panel(base));
EXPECT_EQ(OK, delwin(basew)); CHECK_EQ(OK, delwin(basew));
} }
TEST_F(PanelReelTest, SubwinNoOffsetGeom) { SUBCASE("SubwinNoOffsetGeom") {
panelreel_options p{}; panelreel_options p{};
EXPECT_EQ(0, clear()); CHECK_EQ(0, clear());
PANEL* base = make_targwin(n_); PANEL* base = make_targwin(n_);
ASSERT_NE(nullptr, base); REQUIRE_NE(nullptr, base);
WINDOW* basew = panel_window(base); WINDOW* basew = panel_window(base);
ASSERT_NE(nullptr, basew); REQUIRE_NE(nullptr, basew);
struct panelreel* pr = panelreel_create(basew, &p, -1); struct panelreel* pr = panelreel_create(basew, &p, -1);
ASSERT_NE(nullptr, pr); REQUIRE_NE(nullptr, pr);
EXPECT_EQ(0, panelreel_validate(basew, pr)); CHECK_EQ(0, panelreel_validate(basew, pr));
ASSERT_EQ(0, panelreel_destroy(pr)); REQUIRE_EQ(0, panelreel_destroy(pr));
EXPECT_EQ(OK, del_panel(base)); CHECK_EQ(OK, del_panel(base));
EXPECT_EQ(OK, delwin(basew)); CHECK_EQ(OK, delwin(basew));
} }
*/ */
TEST_F(PanelReelTest, TransparentBackground) { SUBCASE("TransparentBackground") {
panelreel_options p{}; panelreel_options p{};
channels_set_bg_alpha(&p.bgchannel, 3); channels_set_bg_alpha(&p.bgchannel, 3);
struct panelreel* pr = panelreel_create(n_, &p, -1); struct panelreel* pr = panelreel_create(n_, &p, -1);
ASSERT_NE(nullptr, pr); REQUIRE(pr);
// FIXME // FIXME
} }
CHECK(0 == notcurses_stop(nc_));
CHECK(0 == fclose(outfp_));
}

View File

@ -2,136 +2,122 @@
#include <cstdlib> #include <cstdlib>
#include <iostream> #include <iostream>
class ZAxisTest : public :: testing::Test { TEST_CASE("ZAxisTest") {
protected:
void SetUp() override {
setlocale(LC_ALL, "");
if(getenv("TERM") == nullptr){ if(getenv("TERM") == nullptr){
GTEST_SKIP(); return;
} }
notcurses_options nopts{}; notcurses_options nopts{};
nopts.inhibit_alternate_screen = true; nopts.inhibit_alternate_screen = true;
nopts.suppress_bannner = true; nopts.suppress_bannner = true;
outfp_ = fopen("/dev/tty", "wb"); FILE* outfp_ = fopen("/dev/tty", "wb");
ASSERT_NE(nullptr, outfp_); REQUIRE(outfp_);
nc_ = notcurses_init(&nopts, outfp_); struct notcurses* nc_ = notcurses_init(&nopts, outfp_);
ASSERT_NE(nullptr, nc_); REQUIRE(nc_);
n_ = notcurses_stdplane(nc_); struct ncplane* n_ = notcurses_stdplane(nc_);
ASSERT_NE(nullptr, n_); REQUIRE(n_);
}
void TearDown() override { SUBCASE("StdPlaneOnly") {
if(nc_){
EXPECT_EQ(0, notcurses_stop(nc_));
}
if(outfp_){
fclose(outfp_);
}
}
struct notcurses* nc_{};
struct ncplane* n_{};
FILE* outfp_{};
};
TEST_F(ZAxisTest, StdPlaneOnly) {
struct ncplane* top = notcurses_top(nc_); struct ncplane* top = notcurses_top(nc_);
EXPECT_EQ(n_, top); CHECK(n_ == top);
EXPECT_EQ(nullptr, ncplane_below(top)); CHECK(!ncplane_below(top));
} }
// if you want to move the plane which is already top+bottom to either, go ahead // if you want to move the plane which is already top+bottom to either, go ahead
TEST_F(ZAxisTest, StdPlaneOnanism) { SUBCASE("StdPlaneOnanism") {
EXPECT_EQ(0, ncplane_move_top(n_)); CHECK(0 == ncplane_move_top(n_));
struct ncplane* top = notcurses_top(nc_); struct ncplane* top = notcurses_top(nc_);
EXPECT_EQ(n_, top); CHECK(n_ == top);
EXPECT_EQ(nullptr, ncplane_below(top)); CHECK(!ncplane_below(top));
EXPECT_EQ(0, ncplane_move_bottom(n_)); CHECK(0 == ncplane_move_bottom(n_));
EXPECT_EQ(nullptr, ncplane_below(n_)); CHECK(!ncplane_below(n_));
} }
// you can't place a plane above or below itself, stdplane or otherwise // you can't place a plane above or below itself, stdplane or otherwise
TEST_F(ZAxisTest, NoMoveSelf) { SUBCASE("NoMoveSelf") {
struct ncplane* np = notcurses_newplane(nc_, 2, 2, 0, 0, nullptr); struct ncplane* np = notcurses_newplane(nc_, 2, 2, 0, 0, nullptr);
ASSERT_NE(nullptr, np); REQUIRE(np);
EXPECT_NE(0, ncplane_move_below(n_, n_)); CHECK(ncplane_move_below(n_, n_));
EXPECT_NE(0, ncplane_move_above(n_, n_)); CHECK(ncplane_move_above(n_, n_));
EXPECT_NE(0, ncplane_move_below(np, np)); CHECK(ncplane_move_below(np, np));
EXPECT_NE(0, ncplane_move_above(np, np)); CHECK(ncplane_move_above(np, np));
} }
// new planes ought be on the top // new planes ought be on the top
TEST_F(ZAxisTest, NewPlaneOnTop) { SUBCASE("NewPlaneOnTop") {
struct ncplane* np = notcurses_newplane(nc_, 2, 2, 0, 0, nullptr); struct ncplane* np = notcurses_newplane(nc_, 2, 2, 0, 0, nullptr);
ASSERT_NE(nullptr, np); REQUIRE(np);
struct ncplane* top = notcurses_top(nc_); struct ncplane* top = notcurses_top(nc_);
EXPECT_EQ(np, top); CHECK(np == top);
EXPECT_EQ(n_, ncplane_below(top)); CHECK(n_ == ncplane_below(top));
EXPECT_EQ(nullptr, ncplane_below(n_)); CHECK(!ncplane_below(n_));
} }
// "move" top plane to top. everything ought remain the same. // "move" top plane to top. everything ought remain the same.
TEST_F(ZAxisTest, TopToTop) { SUBCASE("TopToTop") {
struct ncplane* np = notcurses_newplane(nc_, 2, 2, 0, 0, nullptr); struct ncplane* np = notcurses_newplane(nc_, 2, 2, 0, 0, nullptr);
ASSERT_NE(nullptr, np); REQUIRE(np);
struct ncplane* top = notcurses_top(nc_); struct ncplane* top = notcurses_top(nc_);
EXPECT_EQ(np, top); CHECK(np == top);
EXPECT_EQ(n_, ncplane_below(top)); CHECK(n_ == ncplane_below(top));
EXPECT_EQ(nullptr, ncplane_below(n_)); CHECK(!ncplane_below(n_));
EXPECT_EQ(0, ncplane_move_top(np)); CHECK(!ncplane_move_top(np));
// verify it // verify it
top = notcurses_top(nc_); top = notcurses_top(nc_);
EXPECT_EQ(np, top); CHECK(np == top);
EXPECT_EQ(n_, ncplane_below(top)); CHECK(n_ == ncplane_below(top));
EXPECT_EQ(nullptr, ncplane_below(n_)); CHECK(!ncplane_below(n_));
} }
// move top plane to bottom, and verify enumeration // move top plane to bottom, and verify enumeration
TEST_F(ZAxisTest, TopToBottom) { SUBCASE("TopToBottom") {
struct ncplane* np = notcurses_newplane(nc_, 2, 2, 0, 0, nullptr); struct ncplane* np = notcurses_newplane(nc_, 2, 2, 0, 0, nullptr);
ASSERT_NE(nullptr, np); REQUIRE(np);
struct ncplane* top = notcurses_top(nc_); struct ncplane* top = notcurses_top(nc_);
EXPECT_EQ(np, top); CHECK(np == top);
EXPECT_EQ(n_, ncplane_below(top)); CHECK(n_ == ncplane_below(top));
EXPECT_EQ(nullptr, ncplane_below(n_)); CHECK(!ncplane_below(n_));
EXPECT_EQ(0, ncplane_move_bottom(np)); CHECK(!ncplane_move_bottom(np));
top = notcurses_top(nc_); top = notcurses_top(nc_);
EXPECT_EQ(n_, top); CHECK(n_ == top);
EXPECT_EQ(np, ncplane_below(top)); CHECK(np == ncplane_below(top));
EXPECT_EQ(nullptr, ncplane_below(np)); CHECK(!ncplane_below(np));
} }
// verify that moving one above another, with no other changes, is reflected at // verify that moving one above another, with no other changes, is reflected at
// render time (requires explicit damage maintenance from move functionality). // render time (requires explicit damage maintenance from move functionality).
TEST_F(ZAxisTest, ZAxisDamage) { SUBCASE("ZAxisDamage") {
cell cat = CELL_TRIVIAL_INITIALIZER; cell cat = CELL_TRIVIAL_INITIALIZER;
cell c = CELL_SIMPLE_INITIALIZER('x'); cell c = CELL_SIMPLE_INITIALIZER('x');
ASSERT_EQ(0, cell_set_fg_rgb(&c, 0xff, 0, 0)); REQUIRE(!cell_set_fg_rgb(&c, 0xff, 0, 0));
ASSERT_EQ(1, ncplane_putc(n_, &c)); REQUIRE(1 == ncplane_putc(n_, &c));
EXPECT_EQ(0, notcurses_render(nc_)); CHECK(!notcurses_render(nc_));
ASSERT_EQ(0, ncplane_cursor_move_yx(n_, 0, 0)); REQUIRE(!ncplane_cursor_move_yx(n_, 0, 0));
ASSERT_EQ(1, ncplane_at_cursor(n_, &cat)); REQUIRE(1 == ncplane_at_cursor(n_, &cat));
ASSERT_TRUE(cell_simple_p(&cat)); REQUIRE(cell_simple_p(&cat));
ASSERT_EQ('x', cat.gcluster); REQUIRE('x' == cat.gcluster);
struct ncplane* n2 = notcurses_newplane(nc_, 2, 2, 0, 0, nullptr); struct ncplane* n2 = notcurses_newplane(nc_, 2, 2, 0, 0, nullptr);
ASSERT_EQ(1, cell_load(n2, &c, "y")); REQUIRE(1 == cell_load(n2, &c, "y"));
ASSERT_EQ(0, cell_set_fg_rgb(&c, 0, 0xff, 0)); REQUIRE(!cell_set_fg_rgb(&c, 0, 0xff, 0));
ASSERT_EQ(1, ncplane_putc(n2, &c)); REQUIRE(1 == ncplane_putc(n2, &c));
EXPECT_EQ(0, notcurses_render(nc_)); CHECK_EQ(0, notcurses_render(nc_));
ASSERT_EQ(0, ncplane_cursor_move_yx(n2, 0, 0)); REQUIRE(!ncplane_cursor_move_yx(n2, 0, 0));
ASSERT_EQ(1, ncplane_at_cursor(n2, &cat)); REQUIRE(1 == ncplane_at_cursor(n2, &cat));
ASSERT_EQ('y', cat.gcluster); REQUIRE('y' == cat.gcluster);
struct ncplane* n3 = notcurses_newplane(nc_, 2, 2, 0, 0, nullptr); struct ncplane* n3 = notcurses_newplane(nc_, 2, 2, 0, 0, nullptr);
ASSERT_EQ(1, cell_load(n3, &c, "z")); REQUIRE(1 == cell_load(n3, &c, "z"));
ASSERT_EQ(0, cell_set_fg_rgb(&c, 0, 0, 0xff)); REQUIRE(!cell_set_fg_rgb(&c, 0, 0, 0xff));
ASSERT_EQ(1, ncplane_putc(n3, &c)); REQUIRE(1 == ncplane_putc(n3, &c));
EXPECT_EQ(0, notcurses_render(nc_)); CHECK(!notcurses_render(nc_));
ASSERT_EQ(0, ncplane_cursor_move_yx(n3, 0, 0)); REQUIRE(!ncplane_cursor_move_yx(n3, 0, 0));
ASSERT_EQ(1, ncplane_at_cursor(n3, &cat)); REQUIRE(1 == ncplane_at_cursor(n3, &cat));
ASSERT_EQ('z', cat.gcluster); REQUIRE('z' == cat.gcluster);
// FIXME testing damage requires notcurses keeping a copy of the screen.... // FIXME testing damage requires notcurses keeping a copy of the screen....
// FIXME move y atop z // FIXME move y atop z
// FIXME inspect // FIXME inspect
// FIXME move z atop y // FIXME move z atop y
// FIXME inspect // FIXME inspect
} }
CHECK(0 == notcurses_stop(nc_));
CHECK(0 == fclose(outfp_));
}