diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/buildfile | 4 | ||||
-rw-r--r-- | tests/dir-iterator/driver.cxx | 3 | ||||
-rw-r--r-- | tests/pager/buildfile | 7 | ||||
-rw-r--r-- | tests/pager/driver.cxx | 111 | ||||
-rw-r--r-- | tests/path/driver.cxx | 17 | ||||
-rw-r--r-- | tests/process/buildfile | 7 | ||||
-rw-r--r-- | tests/process/driver.cxx | 357 | ||||
-rw-r--r-- | tests/timestamp/driver.cxx | 13 |
8 files changed, 511 insertions, 8 deletions
diff --git a/tests/buildfile b/tests/buildfile index 59caba8..e6670ca 100644 --- a/tests/buildfile +++ b/tests/buildfile @@ -2,6 +2,8 @@ # copyright : Copyright (c) 2014-2016 Code Synthesis Ltd # license : MIT; see accompanying LICENSE file -d = base64/ dir-iterator/ path/ prefix-map/ sha256/ timestamp/ triplet/ +d = base64/ dir-iterator/ pager/ path/ prefix-map/ process/ sha256/ \ + timestamp/ triplet/ + .: $d include $d diff --git a/tests/dir-iterator/driver.cxx b/tests/dir-iterator/driver.cxx index 4e81298..9eebb9f 100644 --- a/tests/dir-iterator/driver.cxx +++ b/tests/dir-iterator/driver.cxx @@ -24,6 +24,9 @@ operator<< (ostream& os, entry_type e) return os << entry_type_string[static_cast<size_t> (e)]; } +// @@ Should we make the test silent unless -v arg passed. In silen mode could +// compare the output with a set of predefined dir entries. +// int main (int argc, const char* argv[]) { diff --git a/tests/pager/buildfile b/tests/pager/buildfile new file mode 100644 index 0000000..e42f3b0 --- /dev/null +++ b/tests/pager/buildfile @@ -0,0 +1,7 @@ +# file : tests/pager/buildfile +# copyright : Copyright (c) 2014-2016 Code Synthesis Ltd +# license : MIT; see accompanying LICENSE file + +exe{driver}: cxx{driver} ../../butl/lib{butl} + +include ../../butl/ diff --git a/tests/pager/driver.cxx b/tests/pager/driver.cxx new file mode 100644 index 0000000..cab3078 --- /dev/null +++ b/tests/pager/driver.cxx @@ -0,0 +1,111 @@ +// file : tests/pager/driver.cxx -*- C++ -*- +// copyright : Copyright (c) 2014-2016 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#include <vector> +#include <string> +#include <utility> // move() +#include <cassert> +#include <sstream> +#include <iostream> + +#include <butl/pager> + +using namespace std; +using namespace butl; + +int +main (int argc, const char* argv[]) +{ + bool child (false); + bool interactive (false); + string pgprog; + vector<string> pgopts; + + assert (argc > 0); + + int i (1); + for (; i != argc; ++i) + { + string v (argv[i]); + if (pgprog.empty ()) + { + if (v == "-c") + child = true; + else if (v == "-i") + interactive = true; + else + { + pgprog = move (v); + interactive = true; + } + } + else + pgopts.emplace_back (move (v)); + } + + if (i != argc) + { + if (!child) + cerr << "usage: " << argv[0] << " [-c] [-i] [<pager> [<options>]]" + << endl; + + return 1; + } + + const char* s (R"delim( +class fdstream_base +{ +protected: + fdstream_base () = default; + fdstream_base (int fd): buf_ (fd) {} + +protected: + fdbuf buf_; +}; + +class ifdstream: fdstream_base, public std::istream +{ +public: + ifdstream (): std::istream (&buf_) {} + ifdstream (int fd): fdstream_base (fd), std::istream (&buf_) {} + + void close () {buf_.close ();} + void open (int fd) {buf_.open (fd);} + bool is_open () const {return buf_.is_open ();} +}; +)delim"); + + if (child) + { + string il; + string ol; + istringstream is (s); + do + { + getline (cin, il); + getline (is, ol); + } + while (cin.good () && is.good () && il == ol); + return cin.eof () && !cin.bad () && is.eof () ? 0 : 1; + } + + try + { + string prog (argv[0]); + vector<string> opts ({"-c"}); + + pager p ("pager test", + false, + interactive ? (pgprog.empty () ? nullptr : &pgprog) : &prog, + interactive ? (pgopts.empty () ? nullptr : &pgopts) : &opts); + + p.stream () << s; + + assert (p.wait ()); + } + catch (const system_error&) + { + assert (false); + } +} diff --git a/tests/path/driver.cxx b/tests/path/driver.cxx index 4df2a05..de8e8b1 100644 --- a/tests/path/driver.cxx +++ b/tests/path/driver.cxx @@ -15,11 +15,20 @@ using namespace butl; int main () { + // Make sure we have nothrow destructor and move constructor so that + // storage in containers is not pessimized. + // static_assert (is_nothrow_destructible<path>::value, ""); - static_assert (is_nothrow_move_constructible<path>::value, ""); - static_assert (is_nothrow_destructible<dir_path>::value, ""); + + // MINGW GCC 4.9 std::string is not nothrow-move-constructible, so path and + // dir_path (which have a member of std::string type) are not as such as + // well. + // +#if !defined(_WIN32) || !defined(__GNUC__) || __GNUC__ > 4 + static_assert (is_nothrow_move_constructible<path>::value, ""); static_assert (is_nothrow_move_constructible<dir_path>::value, ""); +#endif assert (path ("/").string () == "/"); assert (path ("//").string () == "/"); @@ -174,7 +183,11 @@ main () assert (path (p.begin (), p.end ()) == p); assert (path (++p.begin (), p.end ()) == path ("foo/bar")); assert (path (++(++p.begin ()), p.end ()) == path ("bar")); + +#ifndef _WIN32 assert (path (p.begin (), ++p.begin ()) == path ("/")); +#endif + assert (path (++p.begin (), ++(++p.begin ())) == path ("foo")); assert (path (++(++p.begin ()), ++(++(++p.begin ()))) == path ("bar")); } diff --git a/tests/process/buildfile b/tests/process/buildfile new file mode 100644 index 0000000..f3d2cd4 --- /dev/null +++ b/tests/process/buildfile @@ -0,0 +1,7 @@ +# file : tests/process/buildfile +# copyright : Copyright (c) 2014-2016 Code Synthesis Ltd +# license : MIT; see accompanying LICENSE file + +exe{driver}: cxx{driver} ../../butl/lib{butl} + +include ../../butl/ diff --git a/tests/process/driver.cxx b/tests/process/driver.cxx new file mode 100644 index 0000000..ba61ea8 --- /dev/null +++ b/tests/process/driver.cxx @@ -0,0 +1,357 @@ +// file : tests/process/driver.cxx -*- C++ -*- +// copyright : Copyright (c) 2014-2016 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#include <stdlib.h> // getenv(), setenv(), _putenv_s() + +#include <ios> +#include <string> +#include <vector> +#include <cassert> +#include <iostream> +#include <iterator> // istreambuf_iterator, ostream_iterator +#include <algorithm> // copy() + +#include <butl/path> +#include <butl/process> +#include <butl/fdstream> + +using namespace std; +using namespace butl; + +static bool +exec (const path& p, + vector<char> in = vector<char> (), + bool out = false, + bool err = false, + bool pipeline = false, + bool bin = true, // Set binary mode for file descriptors. + dir_path wd = dir_path ()) // Set the working dir for the child process. +{ + using cstrings = vector<const char*>; + + assert (!in.empty () || (!out && !err)); // Nothing to output if no input. + assert (!pipeline || out); // To pipeline need to output something. + + const char* cwd (!wd.empty () ? wd.string ().c_str () : nullptr); + + auto args = [&p, bin, &cwd](bool i, bool o, bool e) -> cstrings + { + cstrings a {p.string ().c_str (), "-c"}; + + if (i) + a.push_back ("-i"); + + if (o) + a.push_back ("-o"); + + if (e) + a.push_back ("-e"); + + if (bin) + a.push_back ("-b"); + + if (cwd != nullptr) + a.push_back (cwd); + + a.push_back (nullptr); + return a; + }; + + try + { + bool r (true); + cstrings a (args (!in.empty (), out, err)); + + // If both o and e are true, then redirect STDERR to STDOUT, so both can be + // read from the same stream. + // + process pr (cwd, + a.data (), + !in.empty () ? -1 : 0, + out ? -1 : 1, + err ? (out ? 1 : -1) : 2); + + try + { + if (!in.empty ()) + { + bool s; + r = !pr.try_wait (s); // Couldn't exit as waiting for the input. + + auto bin_mode = [bin](int fd) -> int + { + if (bin) + fdmode (fd, fdtranslate::binary); + + return fd; + }; + + ofdstream os (bin_mode (pr.out_fd)); + os.exceptions (ofdstream::badbit); + copy (in.begin (), in.end (), ostream_iterator<char> (os)); + os.close (); + + if (out) + { + vector<char> o; + + if (pipeline) + { + // Here we test both passing process output fd as an input for + // another process (pr2.in = pr.out), as well as passing process + // input fd as an output for another one (pr2.out = pr3.in). The + // overall pipeline looks like 'os -> pr -> pr2 -> pr3 -> is'. + // + cstrings a (args (true, true, false)); + process pr3 (cwd, a.data (), -1, -1); + process pr2 (cwd, a.data (), pr, bin_mode (pr3.out_fd)); + + bool cr (fdclose (pr3.out_fd)); + assert (cr); + + ifdstream is (bin_mode (pr3.in_ofd)); + + o = vector<char> ( + (istreambuf_iterator<char> (is)), istreambuf_iterator<char> ()); + + r = pr2.wait () && r; + r = pr3.wait () && r; + } + else + { + ifdstream is (bin_mode (pr.in_ofd)); + + o = vector<char> ( + (istreambuf_iterator<char> (is)), istreambuf_iterator<char> ()); + } + + if (err) + { + // If STDERR is redirected to STDOUT then output will be + // duplicated. + // + vector<char> v (in); + in.reserve (in.size () * 2); + in.insert (in.end (), v.begin (), v.end ()); + } + + r = in == o && r; + } + + if (err && !out) + { + ifdstream is (bin_mode (pr.in_efd)); + + vector<char> e + ((istreambuf_iterator<char> (is)), istreambuf_iterator<char> ()); + + r = in == e && r; + } + } + } + catch (const ios_base::failure&) + { + r = false; + } + + bool s; + return pr.wait () && pr.try_wait (s) && s && r; + } + catch (const process_error& e) + { + if (e.child ()) + exit (1); + + return false; + } +} + +static bool +exec (const path& p, + const string& i, + bool o = false, + bool e = false, + bool pipeline = false, + dir_path wd = dir_path ()) +{ + return exec ( + p, vector<char> (i.begin (), i.end ()), o, e, pipeline, false, wd); +} + +int +main (int argc, const char* argv[]) +try +{ + bool child (false); + bool in (false); + bool out (false); + bool err (false); + bool bin (false); + dir_path wd; // Working directory. + + assert (argc > 0); + + int i (1); + for (; i != argc; ++i) + { + string v (argv[i]); + if (v == "-c") + child = true; + else if (v == "-i") + in = true; + else if (v == "-o") + out = true; + else if (v == "-e") + err = true; + else if (v == "-b") + bin = true; + else + { + if (!wd.empty ()) + break; + + try + { + wd = dir_path (v); + } + catch (const invalid_path&) + { + break; + } + } + } + + if (i != argc) + { + if (!child) + cerr << "usage: " << argv[0] << " [-c] [-i] [-o] [-e] [-b] [<dir>]" + << endl; + + return 1; + } + + path p; + + try + { + p = path (argv[0]); + } + catch (const invalid_path&) + { + if (child) + return 1; + + assert (false); + } + + if (child) + { + // Child process. Check if the working directory argument matches the + // current directory if specified. Read input data if requested, optionally + // write it to cout and/or cerr. + // + + if (!wd.empty () && wd.realize () != dir_path::current ()) + return 1; + + if (!in) + return 0; // Nothing to read, so nothing to write. + + try + { + if (bin) + { + stdin_fdmode (fdtranslate::binary); + stdout_fdmode (fdtranslate::binary); + stderr_fdmode (fdtranslate::binary); + } + + vector<char> data + ((istreambuf_iterator<char> (cin)), istreambuf_iterator<char> ()); + + if (out) + { + cout.exceptions (istream::badbit); + copy (data.begin (), data.end (), ostream_iterator<char> (cout)); + } + + if (err) + { + cerr.exceptions (istream::badbit); + copy (data.begin (), data.end (), ostream_iterator<char> (cerr)); + } + } + catch (const ios_base::failure&) + { + return 1; + } + + return 0; + } + + const char* s ("ABC\nXYZ"); + + assert (exec (p)); + assert (exec (p, s)); + assert (exec (p, s, true)); + assert (exec (p, s, true, false, true)); // Same but with piping. + assert (exec (p, s, false, true)); + assert (exec (p, s, true, true)); + assert (exec (p, s, true, true, true)); // Same but with piping. + + // Transmit large binary data through the child. + // + vector<char> v; + v.reserve (5000 * 256); + for (size_t i (0); i < 5000; ++i) + { + for (size_t c (0); c < 256; ++c) + v.push_back (c); + } + + assert (exec (p, v, true, true)); + assert (exec (p, v, true, true, true)); // Same as above but with piping. + + // Execute the child using the full path. + // + path fp (p); + fp.complete (); + assert (exec (fp)); + + // Execute the child using the relative path. + // + dir_path::current (fp.directory ()); + + assert (exec (path (".") / fp.leaf ())); + + // Fail for unexistent file path. + // + assert (!exec (path ("./dr"))); + + // Execute the child using file name having PATH variable being properly set. + // + string paths (fp.directory ().string ()); + + if (char const* s = getenv ("PATH")) + paths += string (1, path::traits::path_separator) + s; + +#ifndef _WIN32 + assert (setenv ("PATH", paths.c_str (), 1) == 0); +#else + assert (_putenv_s ("PATH", paths.c_str ()) == 0); +#endif + + dir_path::current (fp.directory () / dir_path ("..")); + + assert (exec (fp.leaf ())); + + // Same as above but also with changing the child current directory. + // + assert (exec ( + fp.leaf (), vector<char> (), false, false, false, true, fp.directory ())); +} +catch (const system_error&) +{ + assert (false); +} diff --git a/tests/timestamp/driver.cxx b/tests/timestamp/driver.cxx index 4c366fc..f5f30b9 100644 --- a/tests/timestamp/driver.cxx +++ b/tests/timestamp/driver.cxx @@ -10,7 +10,6 @@ #include <cassert> #include <sstream> #include <iomanip> -#include <iostream> #include <system_error> #include <butl/timestamp> @@ -172,12 +171,16 @@ main () "%[.N]%Y-%m-%d %H:%M:%S", "." + ns (384902285) + "2016-02-21 19:31:10")); - /* - setlocale (LC_ALL, "de_DE.utf-8"); - locale::global (locale ("de_DE.utf-8")); +// setlocale (LC_ALL, ""); +// setlocale (LC_ALL, "de_DE.utf-8"); +// setlocale (LC_ALL, "de-de"); +// setlocale (LC_ALL, "German_Germany.1252"); +// locale::global (locale ("")); +// locale::global (locale ("de_DE.utf-8")); +/* assert (parse ("Mai 11 19:31:10 2016 GMT", "%b %d %H:%M:%S%[.N] %Y")); locale::global (locale ("C")); - */ +*/ // @@ When debuging strptime() fallback implementation compiled with GCC // 5.3.1, the following asserts will fail due to bugs in implementation |