2020-04-21 03:26:41 +00:00
|
|
|
#include "main.h"
|
|
|
|
#include <cerrno>
|
|
|
|
#include <mutex>
|
|
|
|
#include <cstring>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <unistd.h>
|
2020-04-28 04:27:07 +00:00
|
|
|
#include "internal.h"
|
2020-04-21 03:26:41 +00:00
|
|
|
#include <condition_variable>
|
|
|
|
|
|
|
|
std::mutex lock;
|
|
|
|
std::condition_variable cond;
|
|
|
|
bool inline_cancelled = false;
|
|
|
|
|
2020-05-09 01:39:15 +00:00
|
|
|
auto testfdcb(struct ncfdplane* ncfd, const void* buf, size_t s, void* curry) -> int {
|
2020-04-21 03:26:41 +00:00
|
|
|
struct ncplane* n = ncfdplane_plane(ncfd);
|
|
|
|
lock.lock();
|
|
|
|
if(ncplane_putstr(n, static_cast<const char*>(buf)) <= 0){
|
|
|
|
lock.unlock();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
lock.unlock();
|
|
|
|
(void)curry;
|
|
|
|
(void)s;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-05-09 01:39:15 +00:00
|
|
|
auto testfdeof(struct ncfdplane* n, int fderrno, void* curry) -> int {
|
2020-04-28 04:27:07 +00:00
|
|
|
bool* outofline_cancelled = static_cast<bool*>(curry);
|
2020-04-21 03:26:41 +00:00
|
|
|
lock.lock();
|
2020-04-28 04:27:07 +00:00
|
|
|
*outofline_cancelled = true;
|
2020-04-21 03:26:41 +00:00
|
|
|
lock.unlock();
|
|
|
|
cond.notify_one();
|
|
|
|
(void)n;
|
|
|
|
(void)fderrno;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-05-09 01:39:15 +00:00
|
|
|
auto testfdeofdestroys(struct ncfdplane* n, int fderrno, void* curry) -> int {
|
2020-04-21 03:26:41 +00:00
|
|
|
lock.lock();
|
|
|
|
inline_cancelled = true;
|
|
|
|
int ret = ncfdplane_destroy(n);
|
|
|
|
lock.unlock();
|
|
|
|
cond.notify_one();
|
|
|
|
(void)curry;
|
|
|
|
(void)fderrno;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// test ncfdplanes and ncsubprocs
|
|
|
|
TEST_CASE("FdsAndSubprocs") {
|
|
|
|
if(getenv("TERM") == nullptr){
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
notcurses_options nopts{};
|
|
|
|
nopts.inhibit_alternate_screen = true;
|
|
|
|
nopts.suppress_banner = 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));
|
|
|
|
|
|
|
|
// destroy the ncfdplane outside of its own context
|
|
|
|
SUBCASE("FdPlaneDestroyOffline") {
|
2020-04-28 04:27:07 +00:00
|
|
|
bool outofline_cancelled = false;
|
2020-04-21 03:26:41 +00:00
|
|
|
ncfdplane_options opts{};
|
2020-04-28 04:27:07 +00:00
|
|
|
opts.curry = &outofline_cancelled;
|
2020-04-22 19:55:35 +00:00
|
|
|
int fd = open("/dev/null", O_RDONLY|O_CLOEXEC);
|
2020-04-21 03:26:41 +00:00
|
|
|
REQUIRE(0 <= fd);
|
|
|
|
auto ncfdp = ncfdplane_create(n_, &opts, fd, testfdcb, testfdeof);
|
|
|
|
REQUIRE(ncfdp);
|
|
|
|
std::unique_lock<std::mutex> lck(lock);
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
while(!outofline_cancelled){
|
|
|
|
cond.wait(lck);
|
|
|
|
}
|
|
|
|
CHECK(0 == ncfdplane_destroy(ncfdp));
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
lock.unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
// destroy the ncfdplane within its own context, i.e. from the eof callback
|
|
|
|
SUBCASE("FdPlaneDestroyInline") {
|
2020-04-21 05:50:53 +00:00
|
|
|
inline_cancelled = false;
|
2020-04-21 03:26:41 +00:00
|
|
|
ncfdplane_options opts{};
|
|
|
|
opts.curry = n_;
|
2020-04-22 19:55:35 +00:00
|
|
|
int fd = open("/dev/null", O_RDONLY|O_CLOEXEC);
|
2020-04-21 03:26:41 +00:00
|
|
|
REQUIRE(0 <= fd);
|
|
|
|
auto ncfdp = ncfdplane_create(n_, &opts, fd, testfdcb, testfdeofdestroys);
|
|
|
|
REQUIRE(ncfdp);
|
|
|
|
std::unique_lock<std::mutex> lck(lock);
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
while(!inline_cancelled){
|
|
|
|
cond.wait(lck);
|
|
|
|
}
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
lock.unlock();
|
|
|
|
}
|
|
|
|
|
2020-05-02 07:49:16 +00:00
|
|
|
SUBCASE("SubprocDestroyCmdExecFails") {
|
2020-05-09 01:30:45 +00:00
|
|
|
char * const argv[] = { strdup("/dev/nope"), nullptr, };
|
2020-04-28 04:27:07 +00:00
|
|
|
bool outofline_cancelled = false;
|
2020-04-22 19:55:35 +00:00
|
|
|
ncsubproc_options opts{};
|
2020-05-02 15:57:38 +00:00
|
|
|
opts.curry = &outofline_cancelled;
|
2020-04-22 19:55:35 +00:00
|
|
|
auto ncsubp = ncsubproc_createvp(n_, &opts, argv[0], argv, testfdcb, testfdeof);
|
|
|
|
REQUIRE(ncsubp);
|
|
|
|
std::unique_lock<std::mutex> lck(lock);
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
while(!outofline_cancelled){
|
|
|
|
cond.wait(lck);
|
|
|
|
}
|
2020-05-06 23:53:59 +00:00
|
|
|
CHECK(0 != ncsubproc_destroy(ncsubp));
|
2020-05-02 08:34:37 +00:00
|
|
|
// FIXME we ought get indication of an error here! or via callback...
|
|
|
|
// FIXME should be 0 !=, methinks!
|
2020-04-22 19:55:35 +00:00
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
lock.unlock();
|
|
|
|
}
|
|
|
|
|
2020-05-02 07:49:16 +00:00
|
|
|
// FIXME SIGCHLD seems to blow up doctest...
|
|
|
|
SUBCASE("SubprocDestroyCmdSucceeds") {
|
2020-05-09 01:30:45 +00:00
|
|
|
char * const argv[] = { strdup("/bin/cat"), strdup("/dev/null"), nullptr, };
|
2020-04-28 04:27:07 +00:00
|
|
|
bool outofline_cancelled = false;
|
2020-04-22 19:55:35 +00:00
|
|
|
ncsubproc_options opts{};
|
2020-05-02 15:57:38 +00:00
|
|
|
opts.curry = &outofline_cancelled;
|
2020-04-22 19:55:35 +00:00
|
|
|
auto ncsubp = ncsubproc_createvp(n_, &opts, argv[0], argv, testfdcb, testfdeof);
|
|
|
|
REQUIRE(ncsubp);
|
|
|
|
std::unique_lock<std::mutex> lck(lock);
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
while(!outofline_cancelled){
|
|
|
|
cond.wait(lck);
|
|
|
|
}
|
|
|
|
CHECK(0 == ncsubproc_destroy(ncsubp));
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
lock.unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
SUBCASE("SubprocDestroyCmdFailed") {
|
2020-05-09 01:30:45 +00:00
|
|
|
char * const argv[] = { strdup("/bin/cat"), strdup("/dev/nope"), nullptr, };
|
2020-04-28 04:27:07 +00:00
|
|
|
bool outofline_cancelled = false;
|
2020-04-21 05:07:45 +00:00
|
|
|
ncsubproc_options opts{};
|
2020-05-02 15:57:38 +00:00
|
|
|
opts.curry = &outofline_cancelled;
|
2020-04-21 05:07:45 +00:00
|
|
|
auto ncsubp = ncsubproc_createvp(n_, &opts, argv[0], argv, testfdcb, testfdeof);
|
|
|
|
REQUIRE(ncsubp);
|
|
|
|
std::unique_lock<std::mutex> lck(lock);
|
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
while(!outofline_cancelled){
|
|
|
|
cond.wait(lck);
|
|
|
|
}
|
2020-05-06 23:53:59 +00:00
|
|
|
CHECK(0 != ncsubproc_destroy(ncsubp));
|
2020-04-21 05:07:45 +00:00
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
lock.unlock();
|
2020-04-22 16:53:56 +00:00
|
|
|
}
|
2020-04-21 05:07:45 +00:00
|
|
|
|
2020-05-02 08:34:37 +00:00
|
|
|
SUBCASE("SubprocDestroyCmdHung") {
|
2020-05-09 01:30:45 +00:00
|
|
|
char * const argv[] = { strdup("/bin/cat"), nullptr, };
|
2020-05-02 08:34:37 +00:00
|
|
|
bool outofline_cancelled = false;
|
|
|
|
ncsubproc_options opts{};
|
2020-05-02 15:57:38 +00:00
|
|
|
opts.curry = &outofline_cancelled;
|
2020-05-02 08:34:37 +00:00
|
|
|
auto ncsubp = ncsubproc_createvp(n_, &opts, argv[0], argv, testfdcb, testfdeof);
|
|
|
|
REQUIRE(ncsubp);
|
2020-05-06 23:53:59 +00:00
|
|
|
CHECK(0 != ncsubproc_destroy(ncsubp));
|
2020-05-02 08:34:37 +00:00
|
|
|
CHECK(0 == notcurses_render(nc_));
|
|
|
|
}
|
|
|
|
|
2020-04-21 03:26:41 +00:00
|
|
|
CHECK(0 == notcurses_stop(nc_));
|
|
|
|
CHECK(0 == fclose(outfp_));
|
|
|
|
}
|