2019-12-27 22:20:20 +00:00
|
|
|
#define DOCTEST_CONFIG_IMPLEMENT
|
2020-05-20 22:36:25 +00:00
|
|
|
#include "main.h"
|
2020-04-21 05:07:45 +00:00
|
|
|
#include <term.h>
|
|
|
|
#include <fcntl.h>
|
2019-11-17 10:04:41 +00:00
|
|
|
#include <clocale>
|
2019-12-27 22:43:24 +00:00
|
|
|
#include <cstring>
|
|
|
|
#include <cstdlib>
|
2019-11-17 10:04:41 +00:00
|
|
|
#include <iostream>
|
2020-05-07 04:53:01 +00:00
|
|
|
#include <climits>
|
2020-04-21 05:07:45 +00:00
|
|
|
#include <termios.h>
|
2020-12-02 19:00:30 +00:00
|
|
|
#include <sys/stat.h>
|
2020-05-07 04:53:01 +00:00
|
|
|
#include <filesystem>
|
2020-02-07 02:52:41 +00:00
|
|
|
#include <langinfo.h>
|
2019-11-17 10:04:41 +00:00
|
|
|
|
2021-04-24 09:18:04 +00:00
|
|
|
const char* datadir = NOTCURSES_SHARE;
|
|
|
|
ncloglevel_e loglevel = NCLOGLEVEL_SILENT;
|
2019-12-27 22:43:24 +00:00
|
|
|
|
2020-06-16 03:52:11 +00:00
|
|
|
auto testing_notcurses() -> struct notcurses* {
|
|
|
|
notcurses_options nopts{};
|
2021-04-24 09:18:04 +00:00
|
|
|
// get loglevel from command line. enabling it by default leads to
|
2021-03-15 04:52:32 +00:00
|
|
|
// more confusion than useful information, so leave it off by default.
|
2021-04-24 09:18:04 +00:00
|
|
|
nopts.loglevel = loglevel;
|
2020-12-31 05:32:47 +00:00
|
|
|
nopts.flags = NCOPTION_SUPPRESS_BANNERS | NCOPTION_NO_ALTERNATE_SCREEN;
|
2020-06-16 03:52:11 +00:00
|
|
|
auto nc = notcurses_init(&nopts, nullptr);
|
|
|
|
return nc;
|
|
|
|
}
|
|
|
|
|
2020-05-07 04:53:01 +00:00
|
|
|
auto find_data(const char* datum) -> char* {
|
|
|
|
std::filesystem::path p = datadir;
|
|
|
|
p /= datum;
|
|
|
|
return strdup(p.c_str());
|
2020-05-02 19:52:11 +00:00
|
|
|
}
|
|
|
|
|
2019-12-27 22:43:24 +00:00
|
|
|
static void
|
|
|
|
handle_opts(const char** argv){
|
|
|
|
bool inarg = false;
|
|
|
|
while(*argv){
|
|
|
|
if(inarg){
|
2020-04-20 00:03:33 +00:00
|
|
|
datadir = strdup(*argv);
|
2019-12-27 22:43:24 +00:00
|
|
|
inarg = false;
|
|
|
|
}else if(strcmp(*argv, "-p") == 0){
|
|
|
|
inarg = true;
|
2021-04-24 09:18:04 +00:00
|
|
|
}else if(strcmp(*argv, "-l") == 0){
|
|
|
|
loglevel = NCLOGLEVEL_TRACE;
|
2019-12-27 22:43:24 +00:00
|
|
|
}
|
|
|
|
++argv;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-02 19:00:30 +00:00
|
|
|
// check that the (provided or default) data directory exists, and has at
|
|
|
|
// least one of our necessary files. otherwise, print a warning + return error.
|
|
|
|
static int
|
|
|
|
check_data_dir(){
|
|
|
|
auto p = find_data("changes.jpg");
|
|
|
|
if(!p){
|
|
|
|
std::cerr << "Coudln't find testing data! Supply directory with -p." << std::endl;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
struct stat s;
|
|
|
|
if(stat(p, &s)){
|
|
|
|
std::cerr << "Couldn't open " << p << ". Supply directory with -p." << std::endl;
|
|
|
|
free(p);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
free(p);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-04-20 01:10:15 +00:00
|
|
|
// reset the terminal in the event of early exit (notcurses_init() presumably
|
2020-12-02 18:40:37 +00:00
|
|
|
// ran, but we don't have the notcurses struct to destroy, so just do it raw).
|
2020-04-20 01:10:15 +00:00
|
|
|
static void
|
|
|
|
reset_terminal(){
|
2020-04-21 05:07:45 +00:00
|
|
|
int fd = open("/dev/tty", O_RDWR|O_CLOEXEC);
|
|
|
|
if(fd >= 0){
|
|
|
|
struct termios tios;
|
|
|
|
if(tcgetattr(fd, &tios) == 0){
|
|
|
|
tios.c_iflag |= INLCR;
|
|
|
|
tios.c_lflag |= ISIG | ICANON | ECHO;
|
|
|
|
tcsetattr(fd, TCSADRAIN, &tios);
|
|
|
|
}
|
|
|
|
char* str = tigetstr("sgr0");
|
2020-05-17 07:09:50 +00:00
|
|
|
if(str != (char*)-1){
|
2020-04-21 05:07:45 +00:00
|
|
|
printf("%s", str);
|
|
|
|
}
|
|
|
|
fflush(stdout);
|
2020-05-13 14:50:42 +00:00
|
|
|
str = tigetstr("oc");
|
2020-05-17 07:09:50 +00:00
|
|
|
if(str != (char*)-1){
|
2020-05-13 14:50:42 +00:00
|
|
|
printf("%s", str);
|
|
|
|
}
|
|
|
|
fflush(stdout);
|
2021-04-24 05:51:26 +00:00
|
|
|
str = tigetstr("cnorm");
|
|
|
|
if(str != (char*)-1){
|
|
|
|
printf("%s", str);
|
|
|
|
}
|
|
|
|
fflush(stdout);
|
2020-04-21 05:07:45 +00:00
|
|
|
close(fd);
|
2020-04-20 01:10:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-27 22:43:24 +00:00
|
|
|
// from https://github.com/onqtam/doctest/blob/master/doc/markdown/commandline.md
|
|
|
|
class dt_removed {
|
|
|
|
std::vector<const char*> vec;
|
|
|
|
public:
|
|
|
|
dt_removed(const char** argv_in) {
|
|
|
|
for(; *argv_in; ++argv_in)
|
|
|
|
if(strncmp(*argv_in, "--dt-", strlen("--dt-")) != 0)
|
|
|
|
vec.push_back(*argv_in);
|
2020-05-07 04:53:01 +00:00
|
|
|
vec.push_back(nullptr);
|
2019-12-27 22:43:24 +00:00
|
|
|
}
|
|
|
|
|
2020-05-07 04:53:01 +00:00
|
|
|
auto argc() -> int { return static_cast<int>(vec.size()) - 1; }
|
|
|
|
auto argv() -> const char** { return &vec[0]; }
|
2019-12-27 22:43:24 +00:00
|
|
|
};
|
|
|
|
|
2021-03-14 07:32:17 +00:00
|
|
|
auto lang_and_term() -> void {
|
2020-07-27 02:57:36 +00:00
|
|
|
const char* lang = getenv("LANG");
|
|
|
|
if(lang == nullptr){
|
|
|
|
std::cerr << "Warning: LANG wasn't defined" << std::endl;
|
|
|
|
}else{
|
|
|
|
std::cout << "Running with LANG=" << lang << std::endl;
|
|
|
|
}
|
2020-06-16 04:30:02 +00:00
|
|
|
const char* term = getenv("TERM");
|
2020-08-08 11:54:09 +00:00
|
|
|
// ubuntu's buildd sets TERM=unknown, fuck it, handle this atrocity
|
|
|
|
if(term == nullptr || strcmp(term, "unknown") == 0){
|
2020-05-22 07:31:03 +00:00
|
|
|
std::cerr << "TERM wasn't defined, exiting with success" << std::endl;
|
2021-03-14 07:32:17 +00:00
|
|
|
exit(EXIT_SUCCESS);
|
|
|
|
}
|
|
|
|
auto nc = testing_notcurses();
|
|
|
|
if(!nc){
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
int dimy, dimx;
|
|
|
|
notcurses_stddim_yx(nc, &dimy, &dimx);
|
|
|
|
std::cout << "Running with TERM=" << term << " (" << dimx << 'x'
|
|
|
|
<< dimy << ")" << std::endl;
|
|
|
|
notcurses_stop(nc);
|
|
|
|
if(dimx < 80 || dimy < 24){ // minimum assumed geometry
|
|
|
|
std::cerr << "Terminal was too small for tests (minimum 80x24)" << std::endl;
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
auto main(int argc, const char **argv) -> int {
|
|
|
|
if(!setlocale(LC_ALL, "")){
|
|
|
|
std::cerr << "Couldn't set locale based on user preferences!" << std::endl;
|
|
|
|
return EXIT_FAILURE;
|
2020-05-22 07:31:03 +00:00
|
|
|
}
|
2021-03-14 07:32:17 +00:00
|
|
|
lang_and_term(); // might exit
|
2019-12-27 22:20:20 +00:00
|
|
|
doctest::Context context;
|
|
|
|
|
2020-12-02 18:40:37 +00:00
|
|
|
context.setOption("order-by", "name"); // sort the test cases by their name
|
2019-12-27 22:20:20 +00:00
|
|
|
context.applyCommandLine(argc, argv);
|
2020-12-02 18:40:37 +00:00
|
|
|
context.setOption("no-breaks", true); // don't break in the debugger when assertions fail
|
2019-12-27 22:43:24 +00:00
|
|
|
dt_removed args(argv);
|
|
|
|
handle_opts(argv);
|
2019-12-27 22:20:20 +00:00
|
|
|
int res = context.run(); // run
|
2021-02-11 20:46:28 +00:00
|
|
|
reset_terminal();
|
|
|
|
check_data_dir();
|
2019-12-27 22:20:20 +00:00
|
|
|
if(context.shouldExit()){ // important - query flags (and --exit) rely on the user doing this
|
|
|
|
return res; // propagate the result of the tests
|
|
|
|
}
|
2020-04-20 01:10:15 +00:00
|
|
|
return res; // the result from doctest is propagated here as well
|
2019-11-17 10:04:41 +00:00
|
|
|
}
|