You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
notcurses/src/tests/fds.cpp

171 lines
5.3 KiB
C++

#include "main.h"
#include <cerrno>
#include <mutex>
#include <cstring>
#include <fcntl.h>
#include <unistd.h>
#include <condition_variable>
static pthread_cond_t cond;
static pthread_mutex_t lock;
auto testfdcb(struct ncfdplane* ncfd, const void* buf, size_t s, void* curry) -> int {
struct ncplane* n = ncfdplane_plane(ncfd);
pthread_mutex_lock(&lock);
if(ncplane_putnstr(n, s, static_cast<const char*>(buf)) <= 0){
pthread_mutex_unlock(&lock);
return -1;
}
notcurses_render(ncplane_notcurses(ncfdplane_plane(ncfd)));
pthread_mutex_unlock(&lock);
(void)curry;
(void)s;
return 0;
}
auto testfdeof(struct ncfdplane* n, int fderrno, void* curry) -> int {
bool* outofline_cancelled = static_cast<bool*>(curry);
pthread_mutex_lock(&lock);
*outofline_cancelled = true;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
(void)n;
(void)fderrno;
return 0;
}
auto testfdeofdestroys(struct ncfdplane* n, int fderrno, void* curry) -> int {
bool* inline_cancelled = static_cast<bool*>(curry);
pthread_mutex_lock(&lock);
int ret = ncfdplane_destroy(n);
*inline_cancelled = true;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
(void)fderrno;
return ret;
}
// test ncfdplanes and ncsubprocs
TEST_CASE("FdsAndSubprocs"
Fully general ncvisual layer (#647) This represents an essentially complete rewrite of ncvisual and associated code. It had two major goals: Improve the ncvisual API based off lessons learned, pursuant to the upcoming API freeze. In particular, I wanted to: decouple ncvisuals from ncplanes. It should be possible to render a ncvisual to multiple planes, with different scaling each time. It should be possible to create an ncvisual without a plane, etc. normalize the various ways of constructing an ncvisual -- file, memory, plane, etc. Support multiple blitters, from 7-bit ASCII to Sixel. This required writing the blitters in several cases, and they're not yet in their final implementations (but the API is fine) I have not yet unified Plots and Visuals, and might not, given that the Plot code works fine. We could at this point implement Plots in terms of Visuals, though -- the blitter backend range has been unified. Sixel is not yet implemented, though it is listed. There is a new POC tool, blitter. It renders its arguments using all possible blitter+scaling combinations. Another new POC, resize, displays its argument, then resizes it to the screen size and displays that, explicitly making use of ncvisual_resize() rather than a scaling parameter to ncvisual_render(). This also eliminates some memory leaks and bugs we were seeing in trunk, and brings in Sixel scaffolding. The C++ wrapper will also need patching back up; I cut most of it down while wrestling with this crap, urk. Closes #638, #562, and #622.
4 years ago
* doctest::description("Fdplanes and subprocedures")) {
REQUIRE(0 == pthread_cond_init(&cond, NULL));
REQUIRE(0 == pthread_mutex_init(&lock, NULL));
auto nc_ = testing_notcurses();
if(!nc_){
return;
}
struct ncplane* n_ = notcurses_stdplane(nc_);
REQUIRE(n_);
REQUIRE(0 == ncplane_cursor_move_yx(n_, 0, 0));
// destroy the ncfdplane outside of its own context
SUBCASE("FdPlaneDestroyOffline") {
bool outofline_cancelled = false;
ncfdplane_options opts{};
opts.curry = &outofline_cancelled;
int fd = open("/dev/null", O_RDONLY|O_CLOEXEC);
REQUIRE(0 <= fd);
auto ncfdp = ncfdplane_create(n_, &opts, fd, testfdcb, testfdeof);
REQUIRE(ncfdp);
pthread_mutex_lock(&lock);
CHECK(0 == notcurses_render(nc_));
while(!outofline_cancelled){
pthread_cond_wait(&cond, &lock);
}
pthread_mutex_unlock(&lock);
CHECK(0 == ncfdplane_destroy(ncfdp));
CHECK(0 == notcurses_render(nc_));
}
// destroy the ncfdplane within its own context, i.e. from the eof callback
SUBCASE("FdPlaneDestroyInline") {
bool inline_cancelled = false;
ncfdplane_options opts{};
opts.curry = &inline_cancelled;
int fd = open("/dev/null", O_RDONLY|O_CLOEXEC);
REQUIRE(0 <= fd);
auto ncfdp = ncfdplane_create(n_, &opts, fd, testfdcb, testfdeofdestroys);
REQUIRE(ncfdp);
pthread_mutex_lock(&lock);
CHECK(0 == notcurses_render(nc_));
while(!inline_cancelled){
pthread_cond_wait(&cond, &lock);
}
pthread_mutex_unlock(&lock);
CHECK(0 == notcurses_render(nc_));
}
/*
SUBCASE("SubprocDestroyCmdExecFails") {
char * const argv[] = { "/should-not-exist", nullptr, };
bool outofline_cancelled = false;
ncsubproc_options opts{};
opts.curry = &outofline_cancelled;
auto ncsubp = ncsubproc_createvp(n_, &opts, argv[0], argv, testfdcb, testfdeof);
REQUIRE(ncsubp);
pthread_mutex_lock(&lock);
CHECK(0 == notcurses_render(nc_));
while(!outofline_cancelled){
pthread_cond_wait(&cond, &lock);
}
lck.unlock();
CHECK(0 != ncsubproc_destroy(ncsubp));
// FIXME we ought get indication of an error here! or via callback...
CHECK(0 == notcurses_render(nc_));
}
*/
SUBCASE("SubprocDestroyCmdSucceeds") {
char const * const argv[] = { "/bin/cat", "/dev/null", nullptr, };
bool outofline_cancelled = false;
ncsubproc_options opts{};
opts.curry = &outofline_cancelled;
auto ncsubp = ncsubproc_createvp(n_, &opts, argv[0], argv, testfdcb, testfdeof);
REQUIRE(ncsubp);
pthread_mutex_lock(&lock);
CHECK(0 == notcurses_render(nc_));
while(!outofline_cancelled){
pthread_cond_wait(&cond, &lock);
}
pthread_mutex_unlock(&lock);
CHECK(0 == ncsubproc_destroy(ncsubp));
CHECK(0 == notcurses_render(nc_));
}
// assuming the path /dev/nope doesn't exist, cat ought be successfully
// launched (fork() and exec() both succeed), but then immediately fail.
SUBCASE("SubprocDestroyCmdFailed") {
char const * const argv[] = { "/bin/cat", "/dev/nope", nullptr, };
bool outofline_cancelled = false;
ncsubproc_options opts{};
opts.curry = &outofline_cancelled;
auto ncsubp = ncsubproc_createvp(n_, &opts, argv[0], argv, testfdcb, testfdeof);
REQUIRE(ncsubp);
pthread_mutex_lock(&lock);
CHECK(0 == notcurses_render(nc_));
while(!outofline_cancelled){
pthread_cond_wait(&cond, &lock);
}
pthread_mutex_unlock(&lock);
CHECK(0 != ncsubproc_destroy(ncsubp));
CHECK(0 == notcurses_render(nc_));
}
SUBCASE("SubprocDestroyCmdHung") {
char const * const argv[] = { "/bin/cat", nullptr, };
bool outofline_cancelled = false;
ncsubproc_options opts{};
opts.curry = &outofline_cancelled;
auto ncsubp = ncsubproc_createvp(n_, &opts, argv[0], argv, testfdcb, testfdeof);
REQUIRE(ncsubp);
WARN(0 != ncsubproc_destroy(ncsubp)); // FIXME
CHECK(0 == notcurses_render(nc_));
}
CHECK(0 == pthread_cond_destroy(&cond));
// FIXME why does this (very rarely) fail? ugh
WARN(0 == pthread_mutex_destroy(&lock));
CHECK(0 == notcurses_stop(nc_));
}