diff options
Diffstat (limited to 'tests/builtin/driver.cxx')
-rw-r--r-- | tests/builtin/driver.cxx | 184 |
1 files changed, 146 insertions, 38 deletions
diff --git a/tests/builtin/driver.cxx b/tests/builtin/driver.cxx index 9fb6d6f..bdf3fa9 100644 --- a/tests/builtin/driver.cxx +++ b/tests/builtin/driver.cxx @@ -1,53 +1,60 @@ // file : tests/builtin/driver.cxx -*- C++ -*- // license : MIT; see accompanying LICENSE file -#include <cassert> +#ifdef _WIN32 +# include <libbutl/win32-utility.hxx> +#endif -#ifndef __cpp_lib_modules_ts #include <string> #include <vector> +#include <chrono> #include <utility> // move() +#include <cstdint> // uint8_t #include <ostream> #include <iostream> +#ifndef _WIN32 +# include <thread> // this_thread::sleep_for() #endif -// Other includes. +#include <libbutl/path.hxx> +#include <libbutl/utility.hxx> // eof() +#include <libbutl/builtin.hxx> +#include <libbutl/optional.hxx> +#include <libbutl/timestamp.hxx> // to_stream(duration) -#ifdef __cpp_modules_ts -#ifdef __cpp_lib_modules_ts -import std.core; -import std.io; -#endif -import butl.path; -import butl.utility; // eof() -import butl.builtin; -import butl.optional; -import butl.timestamp; // to_stream(duration) -#else -#include <libbutl/path.mxx> -#include <libbutl/utility.mxx> -#include <libbutl/builtin.mxx> -#include <libbutl/optional.mxx> -#include <libbutl/timestamp.mxx> -#endif +#undef NDEBUG +#include <cassert> using namespace std; using namespace butl; +// Disable arguments globbing that may be enabled by default for MinGW runtime +// (see tests/wildcard/driver.cxx for details). +// +#ifdef __MINGW32__ +int _CRT_glob = 0; +#endif + inline ostream& operator<< (ostream& os, const path& p) { return os << p.representation (); } -// Usage: argv[0] [-d <dir>] [-o <opt>] [-c] [-i] <builtin> <builtin-args> +// Usage: argv[0] [-d <dir>] [-o <opt>] [-c] [-i] [-t <msec>] [-s <sec>] +// <builtin> <builtin-args> // // Execute the builtin and exit with its exit status. // -// -d <dir> use as a current working directory -// -c use callbacks that, in particular, trace calls to stdout -// -o <opt> additional builtin option recognized by the callback -// -i read lines from stdin and append them to the builtin arguments +// -d <dir> use as a current working directory +// -c use callbacks that, in particular, trace calls to stdout +// -o <opt> additional builtin option recognized by the callback +// -i read lines from stdin and append them to the builtin arguments +// -t <msec> print diag if the builtin didn't complete in <msec> milliseconds +// -s <sec> sleep <sec> seconds prior to running the builtin +// +// Note that the 'roundtrip' builtin name is also recognized and results in +// running the pseudo-builtin that just roundtrips stdin to stdout. // int main (int argc, char* argv[]) @@ -62,12 +69,25 @@ main (int argc, char* argv[]) dir_path cwd; string option; builtin_callbacks callbacks; + optional<duration> timeout; + optional<chrono::seconds> sec; string name; vector<string> args; auto flag = [] (bool v) {return v ? "true" : "false";}; + auto num = [] (const string& s) + { + assert (!s.empty ()); + + char* e (nullptr); + errno = 0; // We must clear it according to POSIX. + uint64_t r (strtoull (s.c_str (), &e, 10)); // Can't throw. + assert (errno != ERANGE && e == s.c_str () + s.size ()); + return r; + }; + // Parse the driver options and arguments. // int i (1); @@ -120,7 +140,23 @@ main (int argc, char* argv[]) ); } else if (a == "-i") + { in = true; + } + else if (a == "-t") + { + ++i; + + assert (i != argc); + timeout = chrono::milliseconds (num (argv[i])); + } + else if (a == "-s") + { + ++i; + + assert (i != argc); + sec = chrono::seconds (num (argv[i])); + } else break; } @@ -142,23 +178,95 @@ main (int argc, char* argv[]) args.push_back (move (s)); } - // Execute the builtin. - // - const builtin_info* bi (builtins.find (name)); + auto sleep = [&sec] () + { + if (sec) + { + // MINGW GCC 4.9 doesn't implement this_thread so use Win32 Sleep(). + // +#ifndef _WIN32 + this_thread::sleep_for (*sec); +#else + Sleep (static_cast<DWORD> (sec->count () * 1000)); +#endif + } + }; - if (bi == nullptr) + auto wait = [&timeout] (builtin& b) { - cerr << "unknown builtin '" << name << "'" << endl; - return 1; - } + optional<uint8_t> r; + + if (timeout) + { + r = b.timed_wait (*timeout); + + if (!r) + { + cerr << "timeout expired" << endl; - if (bi->function == nullptr) + b.wait (); + r = 1; + } + } + else + r = b.wait (); + + assert (b.try_wait ()); // While at it, test try_wait(). + + return *r; + }; + + // Execute the builtin. + // + if (name != "roundtrip") { - cerr << "external builtin '" << name << "'" << endl; - return 1; + const builtin_info* bi (builtins.find (name)); + + if (bi == nullptr) + { + cerr << "unknown builtin '" << name << "'" << endl; + return 1; + } + + if (bi->function == nullptr) + { + cerr << "external builtin '" << name << "'" << endl; + return 1; + } + + sleep (); + + uint8_t r; // Storage. + builtin b (bi->function (r, args, nullfd, nullfd, nullfd, cwd, callbacks)); + return wait (b); } + else + { + uint8_t r; // Storage. - uint8_t r; // Storage. - builtin b (bi->function (r, args, nullfd, nullfd, nullfd, cwd, callbacks)); - return b.wait (); + auto run = [&r, &sleep] () + { + // While at it, test that a non-copyable lambda can be used as a + // builtin. + // + auto_fd fd; + + return pseudo_builtin ( + r, + [&sleep, fd = move (fd)] () mutable noexcept + { + fd.reset (); + + sleep (); + + if (cin.peek () != istream::traits_type::eof ()) + cout << cin.rdbuf (); + + return 0; + }); + }; + + builtin b (run ()); + return wait (b); + } } |