diff options
Diffstat (limited to 'tests')
83 files changed, 3311 insertions, 1321 deletions
diff --git a/tests/b-info/driver.cxx b/tests/b-info/driver.cxx index 6a3e0a4..5691221 100644 --- a/tests/b-info/driver.cxx +++ b/tests/b-info/driver.cxx @@ -1,28 +1,15 @@ // file : tests/b-info/driver.cxx -*- C++ -*- // license : MIT; see accompanying LICENSE file -#include <cassert> - -#ifndef __cpp_lib_modules_ts #include <string> #include <iostream> -#endif - -// Other includes. - -#ifdef __cpp_modules_ts -#ifdef __cpp_lib_modules_ts -import std.core; -import std.io; -#endif -import butl.b; -import butl.path; -import butl.utility; // operator<<(ostream,exception) -#else -#include <libbutl/b.mxx> -#include <libbutl/path.mxx> -#include <libbutl/utility.mxx> -#endif + +#include <libbutl/b.hxx> +#include <libbutl/path.hxx> +#include <libbutl/utility.hxx> // operator<<(ostream,exception) + +#undef NDEBUG +#include <cassert> using namespace std; using namespace butl; @@ -62,12 +49,14 @@ try cout.exceptions (ios::failbit | ios::badbit); - b_project_info pi (b_info (project, - 1 /* verb */, - {} /* cmd_callback */, - b, - {} /* search_fallback */, - {"--no-default-options"})); + b_project_info pi ( + b_info (project, + b_info_flags::ext_mods | b_info_flags::subprojects, + 1 /* verb */, + {} /* cmd_callback */, + b, + {} /* search_fallback */, + {"--no-default-options"})); cout << "project: " << pi.project << endl << "version: " << pi.version << endl @@ -109,6 +98,18 @@ try cout << *i; } + cout << endl + << "modules: "; + + for (auto b (pi.modules.begin ()), i (b); + i != pi.modules.end (); + ++i) + { + if (i != b) + cout << ' '; + + cout << *i; + } cout << endl; return 0; diff --git a/tests/b-info/testscript b/tests/b-info/testscript index c5c3910..1ebf060 100644 --- a/tests/b-info/testscript +++ b/tests/b-info/testscript @@ -57,10 +57,11 @@ test.options += -b $recall($build.path) url:$sp %src_root: .+/prj/% %out_root: .+/prj/% - amalgamation: ../../../../ + %amalgamation: .*% subprojects: @subprj/ operations: update clean meta-operations: perform configure disfigure dist info + modules: version config dist EOO $* prj/subprj >>/~"%EOO%" @@ -74,6 +75,7 @@ test.options += -b $recall($build.path) subprojects:$sp operations: update clean meta-operations: perform configure disfigure dist info + modules: config dist EOO } diff --git a/tests/backtrace/driver.cxx b/tests/backtrace/driver.cxx index d998942..ecfa58e 100644 --- a/tests/backtrace/driver.cxx +++ b/tests/backtrace/driver.cxx @@ -5,31 +5,17 @@ # include <sys/resource.h> // setrlimit() #endif -#include <cassert> - -#ifndef __cpp_lib_modules_ts #include <string> #include <iostream> #include <exception> // set_terminate(), terminate_handler #include <system_error> -#else -import std.io; -#endif -// Other includes. +#include <libbutl/process.hxx> +#include <libbutl/fdstream.hxx> +#include <libbutl/backtrace.hxx> -#ifdef __cpp_modules_ts -#ifdef __cpp_lib_modules_ts -import std.core; -#endif -import butl.process; -import butl.fdstream; -import butl.backtrace; -#else -#include <libbutl/process.mxx> -#include <libbutl/fdstream.mxx> -#include <libbutl/backtrace.mxx> -#endif +#undef NDEBUG +#include <cassert> using namespace std; using namespace butl; diff --git a/tests/base64/driver.cxx b/tests/base64/driver.cxx index c7906f5..32d5236 100644 --- a/tests/base64/driver.cxx +++ b/tests/base64/driver.cxx @@ -1,29 +1,20 @@ // file : tests/base64/driver.cxx -*- C++ -*- // license : MIT; see accompanying LICENSE file -#include <cassert> - -#ifndef __cpp_lib_modules_ts #include <string> #include <vector> #include <sstream> -#endif -// Other includes. +#include <libbutl/base64.hxx> -#ifdef __cpp_modules_ts -#ifdef __cpp_lib_modules_ts -import std.core; -import std.io; -#endif -import butl.base64; -#else -#include <libbutl/base64.mxx> -#endif +#undef NDEBUG +#include <cassert> using namespace std; using namespace butl; +// Test base64 encoding and decoding. +// static bool encode (const string& i, const string& o) { @@ -79,9 +70,44 @@ encode (const string& i, const string& o) return r; } +// Test base64url encoding only (decoding not yet implemented). +// +static bool +encode_url (const string& i, const string& o) +{ + istringstream is (i); + string s (base64url_encode (is)); + bool r (s == o && is.eof ()); + + if (r) + { + is.seekg (0); + + // VC15 seekg() doesn't clear eofbit. + // +#if defined(_MSC_VER) && _MSC_VER < 1920 + is.clear (); +#endif + + assert (!is.eof ()); + + ostringstream os; + base64url_encode (os, is); + r = os.str () == o && is.eof (); + } + + if (r) + r = base64url_encode (vector<char> (i.begin (), i.end ())) == o; + + return r; +} + + int main () { + // base64 + // assert (encode ("", "")); assert (encode ("B", "Qg==")); assert (encode ("BX", "Qlg=")); @@ -91,6 +117,19 @@ main () assert (encode ("BXzS@#", "Qlh6U0Aj")); assert (encode ("BXzS@#/", "Qlh6U0AjLw==")); + // base64url: no padding in output. + // + assert (encode_url ("", "")); + assert (encode_url ("B", "Qg")); + assert (encode_url ("BX", "Qlg")); + assert (encode_url ("BXz", "Qlh6")); + assert (encode_url ("BXzS", "Qlh6Uw")); + assert (encode_url ("BXzS@", "Qlh6U0A")); + assert (encode_url ("BXzS@#", "Qlh6U0Aj")); + assert (encode_url ("BXzS@#/", "Qlh6U0AjLw")); + + // Multi-line input. + // const char* s ( "class fdstream_base\n" "{\n" @@ -102,10 +141,29 @@ main () " fdbuf buf_;\n" "};\n"); + // base64 + // const char* r ( "Y2xhc3MgZmRzdHJlYW1fYmFzZQp7CnByb3RlY3RlZDoKICBmZHN0cmVhbV9iYXNlICgpID0gZGVm\n" "YXVsdDsKICBmZHN0cmVhbV9iYXNlIChpbnQgZmQpOiBidWZfIChmZCkge30KCnByb3RlY3RlZDoK\n" "ICBmZGJ1ZiBidWZfOwp9Owo="); assert (encode (s, r)); + + // base64url: no newlines or padding in output. + // + r = +"Y2xhc3MgZmRzdHJlYW1fYmFzZQp7CnByb3RlY3RlZDoKICBmZHN0cmVhbV9iYXNlICgpID0gZGVm" +"YXVsdDsKICBmZHN0cmVhbV9iYXNlIChpbnQgZmQpOiBidWZfIChmZCkge30KCnByb3RlY3RlZDoK" +"ICBmZGJ1ZiBidWZfOwp9Owo"; + + assert (encode_url (s, r)); + + // Test 63rd and 64th characters: `>` maps to `+` or `-`; `?` maps to `/` or + // `_`. + // + assert (encode (">>>>>>", "Pj4+Pj4+")); + assert (encode_url (">>>>>>", "Pj4-Pj4-")); + assert (encode ("??????", "Pz8/Pz8/")); + assert (encode_url ("??????", "Pz8_Pz8_")); } diff --git a/tests/build/root.build b/tests/build/root.build index bb274d3..5ce7156 100644 --- a/tests/build/root.build +++ b/tests/build/root.build @@ -4,15 +4,26 @@ cxx.std = latest using cxx +using c hxx{*}: extension = hxx cxx{*}: extension = cxx if ($cxx.target.system == 'win32-msvc') - cxx.poptions += -D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS + cc.poptions += -D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS if ($cxx.class == 'msvc') - cxx.coptions += /wd4251 /wd4275 /wd4800 + cc.coptions += /wd4251 /wd4275 /wd4800 +elif ($cxx.id == 'gcc') +{ + cxx.coptions += -Wno-maybe-uninitialized -Wno-free-nonheap-object \ +-Wno-stringop-overread + + if ($cxx.version.major >= 13) + cxx.coptions += -Wno-dangling-reference +} +elif ($cxx.id.type == 'clang' && $cxx.version.major >= 15) + cxx.coptions += -Wno-unqualified-std-cast-call # Every exe{} in this subproject is by default a test. # diff --git a/tests/builtin/buildfile b/tests/builtin/buildfile index 8341847..8d22fe4 100644 --- a/tests/builtin/buildfile +++ b/tests/builtin/buildfile @@ -6,3 +6,6 @@ import libs = libbutl%lib{butl} ./: exe{driver} file{cp-dir/cp-file} exe{driver}: {hxx cxx}{*} $libs testscript{*} + +if ($cxx.target.class != 'windows') + cxx.libs += -lpthread 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); + } } diff --git a/tests/builtin/find.testscript b/tests/builtin/find.testscript new file mode 100644 index 0000000..b09822c --- /dev/null +++ b/tests/builtin/find.testscript @@ -0,0 +1,276 @@ +# file : tests/builtin/find.testscript +# license : MIT; see accompanying LICENSE file + +posix = ($cxx.target.class != 'windows') + +test.arguments = "find" + +: no-paths +: +$* 2>"find: missing start path" == 1 + +: no-paths-primary +: +$* -name foo 2>"find: unknown option '-name'" == 1 + +: unknown-primary +: +$* . -foo 2>"find: unknown primary '-foo'" == 1 + + +: no-primary-value +: +$* . -name 2>"find: missing value for primary '-name'" == 1 + +: empty-primary-value +: +$* . -type '' 2>"find: empty value for primary '-type'" == 1 + +: invalid-type-primary +: +$* . -type foo 2>"find: invalid value 'foo' for primary '-type'" == 1 + +: invalid-mindepth-primary +: +$* . -mindepth 12a 2>"find: invalid value '12a' for primary '-mindepth'" == 1 + +: path-not-exists +: +{ + mkdir d; + $* x d >'d' 2>"find: 'x' doesn't exists" != 0 +} + +: path +: +{ + : relative + : + { + : no-cwd + : + { + mkdir a; + touch a/b; + + $* a >>/EOO + a + a/b + EOO + } + + : absolute-cwd + : + : When cross-testing we cannot guarantee that host absolute paths are + : recognized by the target process. + : + if ($test.target == $build.host) + { + test.options += -d $~/a; + mkdir a; + touch a/b; + + $* b >'b' + } + + : relative-cwd + : + if ($test.target == $build.host) + { + test.options += -d a; + mkdir a; + touch a/b; + + $* b >'b' + } + } + + : non-normalized + : + { + mkdir a; + touch a/b; + + # Note that the path specified on the command line is used unaltered. + # + s = ($posix ? '/' : '\'); + + $* ./a >>"EOO" + ./a + ./a$(s)b + EOO + } + + : absolute + : + { + mkdir a; + touch a/b; + + $* $~/a >>/"EOO" + $~/a + $~/a/b + EOO + } + + : non-existent + : + { + touch a b; + + $* a x b >>EOO 2>"find: 'x' doesn't exists" != 0 + a + b + EOO + } + + : non-directory + : + { + touch a b c; + + $* a b/ c >>EOO 2>"find: 'b' is not a directory" != 0 + a + c + EOO + } + + : trailing-slash + : + { + mkdir -p a/b; + + $* a >>/"EOO"; + a + a/b + EOO + + $* a/ >>"EOO" + a/ + a/b + EOO + } +} + +: name-primary +: +{ + : basic + : + { + mkdir a; + touch a/ab a/ba; + + $* . -name 'a*' >>/EOO; + ./a + ./a/ab + EOO + + $* . -name 'b*' >>/EOO; + ./a/ba + EOO + + $* a -name 'a*' >>/EOO + a + a/ab + EOO + } + + : empty + : + { + touch a; + + $* . -name '' + } +} + +: type-primary +: +{ + : regular + : + { + mkdir -p a/b; + touch a/b/c; + + $* a -type f >>/EOO + a/b/c + EOO + } + + : directory + : + { + mkdir -p a/b; + touch a/b/c; + + $* a -type d >>/EOO + a + a/b + EOO + } + + : symlink + : + if $posix + { + mkdir -p a/b; + touch a/b/c; + ln -s c a/b/d; + + $* a -type l >>/EOO + a/b/d + EOO + } +} + +: mindepth-primary +: +{ + mkdir -p a/b/c; + + $* a -mindepth 0 >>/EOO; + a + a/b + a/b/c + EOO + + $* a -mindepth 1 >>/EOO; + a/b + a/b/c + EOO + + $* a -mindepth 2 >>/EOO; + a/b/c + EOO + + $* a -mindepth 3 +} + +: maxdepth-primary +: +{ + mkdir -p a/b/c; + + $* a -maxdepth 0 >>/EOO; + a + EOO + + $* a -maxdepth 1 >>/EOO; + a + a/b + EOO + + $* a -maxdepth 2 >>/EOO; + a + a/b + a/b/c + EOO + + $* a -maxdepth 3 >>/EOO + a + a/b + a/b/c + EOO +} diff --git a/tests/builtin/sed.testscript b/tests/builtin/sed.testscript index ad26483..2ed3088 100644 --- a/tests/builtin/sed.testscript +++ b/tests/builtin/sed.testscript @@ -89,16 +89,10 @@ test.options += -c sed: empty script EOE - : multiple - : - $* -e 's/a//' -e 's/a//' 2>>EOE != 0 - sed: multiple scripts - EOE - : invalid : $* -e 'z' 2>>EOE != 0 - sed: only 's' command supported + sed: unknown command in 'z': only 's' command supported EOE } @@ -156,13 +150,13 @@ test.options += -c : none : $* -e 's' 2>>EOE != 0 - sed: no delimiter for 's' command + sed: no delimiter for 's' command in 's' EOE : invalid : $* -e 's\\' 2>>EOE != 0 - sed: invalid delimiter for 's' command + sed: invalid delimiter for 's' command in 's\\' EOE } @@ -171,14 +165,14 @@ test.options += -c { : unterminated : - $* -e 's/foo' 2>>/EOE != 0 - sed: unterminated 's' command regex + $* -e 's/foo' 2>>EOE != 0 + sed: invalid 's' command 's/foo': no delimiter after regex EOE : empty : $* -e 's///' 2>>EOE != 0 - sed: empty regex in 's' command + sed: invalid 's' command 's///': empty regex EOE : invalid @@ -187,20 +181,20 @@ test.options += -c : regex errors. For example '*' is parsed successfully. : $* -e 's/foo[/bar/' 2>>~%EOE% != 0 - %sed: invalid regex.*% + %sed: invalid regex 'foo\[' in 's/foo\[/bar/'.*% EOE } : unterminated-replacement : - $* -e 's/foo/bar' 2>>/EOE != 0 - sed: unterminated 's' command replacement + $* -e 's/foo/bar' 2>>EOE != 0 + sed: invalid 's' command 's/foo/bar': no delimiter after replacement EOE : invalid-flags : $* -e 's/foo/bar/a' 2>>EOE != 0 - sed: invalid 's' command flag 'a' + sed: invalid 's' command flag 'a' in 's/foo/bar/a' EOE } @@ -314,6 +308,35 @@ test.options += -c } } } + + : multiple + : + { + $* -e 's/b/x/' -e 's/x/y/' -e 's/c/z/' <'abc' >'ayz' : replace-replacement + + : new-cycle + : + $* -e 's/b/x/p' -e 's/x/y/p' <<EOI >>EOO + abc + klm + dxe + EOI + axc + klm + dye + EOO + + : quiet + : + $* -n -e 's/b/x/p' -e 's/x/y/p' <<EOI >>EOO + abc + klm + dxe + EOI + axc + dye + EOO + } } : in-place diff --git a/tests/builtin/timeout.testscript b/tests/builtin/timeout.testscript new file mode 100644 index 0000000..b8eddc3 --- /dev/null +++ b/tests/builtin/timeout.testscript @@ -0,0 +1,30 @@ +# file : tests/builtin/timeout.testscript +# license : MIT; see accompanying LICENSE file + +: async-builtin +: +{ + : expired + : + $* -s 5 'cat' <'test' | $* -t 1 'cat' >=f 2>'timeout expired' != 0 + + : not-expired + : + echo 'test' | $* -t 10000 'cat' >! +} + +: pseudo-builtin +: +{ + : expired + : + $* -s 5 'cat' <'test' | $* -t 1 'roundtrip' >=f 2>'timeout expired' != 0 + + : not-expired + : + echo 'test' | $* -t 10000 'roundtrip' >! +} + +: sync-builtin +: +$* -t 1 'mkdir' d &d/ diff --git a/tests/command/driver.cxx b/tests/command/driver.cxx index 0c070ab..9194c13 100644 --- a/tests/command/driver.cxx +++ b/tests/command/driver.cxx @@ -1,38 +1,22 @@ // file : tests/command/driver.cxx -*- C++ -*- // license : MIT; see accompanying LICENSE file -#include <cassert> - -#ifndef __cpp_lib_modules_ts #include <ios> #include <string> #include <vector> #include <iostream> #include <stdexcept> // invalid_argument #include <system_error> -#endif -// Other includes. +#include <libbutl/path.hxx> +#include <libbutl/path-io.hxx> +#include <libbutl/process.hxx> +#include <libbutl/command.hxx> +#include <libbutl/utility.hxx> +#include <libbutl/optional.hxx> -#ifdef __cpp_modules_ts -#ifdef __cpp_lib_modules_ts -import std.core; -import std.io; -#endif -import butl.path; -import butl.path_io; -import butl.process; // process::print() -import butl.command; -import butl.utility; -import butl.optional; -#else -#include <libbutl/path.mxx> -#include <libbutl/path-io.mxx> -#include <libbutl/process.mxx> -#include <libbutl/command.mxx> -#include <libbutl/utility.mxx> -#include <libbutl/optional.mxx> -#endif +#undef NDEBUG +#include <cassert> using namespace std; using namespace butl; diff --git a/tests/cpfile/driver.cxx b/tests/cpfile/driver.cxx index c613b49..fe01bdd 100644 --- a/tests/cpfile/driver.cxx +++ b/tests/cpfile/driver.cxx @@ -1,29 +1,16 @@ // file : tests/cpfile/driver.cxx -*- C++ -*- // license : MIT; see accompanying LICENSE file -#include <cassert> - -#ifndef __cpp_lib_modules_ts #include <ios> #include <string> #include <system_error> -#endif -// Other includes. +#include <libbutl/path.hxx> +#include <libbutl/fdstream.hxx> +#include <libbutl/filesystem.hxx> -#ifdef __cpp_modules_ts -#ifdef __cpp_lib_modules_ts -import std.core; -import std.io; -#endif -import butl.path; -import butl.fdstream; -import butl.filesystem; -#else -#include <libbutl/path.mxx> -#include <libbutl/fdstream.mxx> -#include <libbutl/filesystem.mxx> -#endif +#undef NDEBUG +#include <cassert> using namespace std; using namespace butl; diff --git a/tests/curl/driver.cxx b/tests/curl/driver.cxx index 18ed1e6..856fde3 100644 --- a/tests/curl/driver.cxx +++ b/tests/curl/driver.cxx @@ -1,35 +1,17 @@ // file : tests/curl/driver.cxx -*- C++ -*- // license : MIT; see accompanying LICENSE file -#include <cassert> - -#ifndef __cpp_lib_modules_ts #include <iostream> #include <system_error> -#endif - -// Other includes. - -#ifdef __cpp_modules_ts -#ifdef __cpp_lib_modules_ts -import std.core; -import std.io; -#endif -import butl.curl; -import butl.path; -import butl.process; -import butl.utility; // operator<<(ostream, exception) -import butl.fdstream; - -import butl.optional; // @@ MOD Clang should not be necessary. -import butl.small_vector; // @@ MOD Clang should not be necessary. -#else -#include <libbutl/curl.mxx> -#include <libbutl/path.mxx> -#include <libbutl/process.mxx> -#include <libbutl/utility.mxx> -#include <libbutl/fdstream.mxx> -#endif + +#include <libbutl/curl.hxx> +#include <libbutl/path.hxx> +#include <libbutl/process.hxx> +#include <libbutl/utility.hxx> // operator<<(ostream, exception) +#include <libbutl/fdstream.hxx> + +#undef NDEBUG +#include <cassert> using namespace std; using namespace butl; @@ -122,6 +104,26 @@ http () c.out.close (); assert (!c.wait ()); } + + // POST from stream without --fail. + // + { + curl c (p, path ("-"), nullfd, 2, + curl::post, + curl::flags::no_fail, + u + "/bogus"); + + c.out << "bogus" << endl; + c.out.close (); + assert (c.wait ()); + } + + // POST empty data. + // + { + curl c (p, nullfd, 1, 2, curl::post, u + "/bogus", "--verbose"); + assert (!c.wait ()); + } } int diff --git a/tests/curl/testscript b/tests/curl/testscript index 3da2306..d2056cd 100644 --- a/tests/curl/testscript +++ b/tests/curl/testscript @@ -43,14 +43,22 @@ sudo /usr/sbin/in.tftpd \ : http : { - $* 'http' 2>>EOE + $* 'http' 2>>~%EOE% - curl -s -S --fail --location https://build2.org/bogus - curl: (22) The requested URL returned error: 404 Not Found + curl -sS --fail --location https://build2.org/bogus + %curl: \(22\) The requested URL returned error: 404( Not Found)?% - curl -s -S --fail --location https://build2.org + curl -sS --fail --location https://build2.org - curl -s -S --fail --location --data-binary @- https://build2.org/bogus - curl: (22) The requested URL returned error: 404 Not Found + curl -sS --fail --location --data-binary @- https://build2.org/bogus + %curl: \(22\) The requested URL returned error: 404( Not Found)?% + + curl -sS --location --data-binary @- https://build2.org/bogus + + curl -sS --fail --location --data-raw "" --verbose https://build2.org/bogus + %.* + %> POST /bogus HTTP.+% + %.* + %curl: \(22\) The requested URL returned error: 404( Not Found)?% EOE } diff --git a/tests/default-options/driver.cxx b/tests/default-options/driver.cxx index c6ac671..766dca8 100644 --- a/tests/default-options/driver.cxx +++ b/tests/default-options/driver.cxx @@ -1,62 +1,53 @@ // file : tests/default-options/driver.cxx -*- C++ -*- // license : MIT; see accompanying LICENSE file -#include <cassert> - -#ifndef __cpp_lib_modules_ts +#include <limits> #include <string> #include <vector> #include <iostream> -#endif - -// Other includes. - -#ifdef __cpp_modules_ts -#ifdef __cpp_lib_modules_ts -import std.core; -import std.io; -#endif -import butl.path; -import butl.path_io; -import butl.optional; -import butl.fdstream; -import butl.default_options; -#else -#include <libbutl/path.mxx> -#include <libbutl/path-io.mxx> -#include <libbutl/utility.mxx> // eof() -#include <libbutl/optional.mxx> -#include <libbutl/fdstream.mxx> -#include <libbutl/default-options.mxx> -#endif +#include <exception> +#include <stdexcept> // invalid_argument + +#include <libbutl/path.hxx> +#include <libbutl/path-io.hxx> +#include <libbutl/utility.hxx> // eof() +#include <libbutl/optional.hxx> +#include <libbutl/fdstream.hxx> +#include <libbutl/default-options.hxx> + +#undef NDEBUG +#include <cassert> using namespace std; using namespace butl; // Usage: argv[0] [-f <file>] [-d <start-dir>] [-s <sys-dir>] [-h <home-dir>] -// [-x <extra-dir>] [-e] [-t] <cmd-options> +// [-x <extra-dir>] [-a] [-e] [-t] <cmd-options> // // Parse default options files, merge them with the command line options, and // print the resulting options to STDOUT one per line. Note that the options // instance is a vector of arbitrary strings. // -// -f +// -f <file> // Default options file name. Can be specified multiple times. // -// -d +// -d <start-dir> // Directory to start the default options files search from. Can be // specified multiple times, in which case a common start (parent) // directory is deduced. // -// -s +// -s <sys-dir> // System directory. // -// -h +// -h <home-dir> // Home directory. // -// -x +// -x <extra-dir> // Extra directory. // +// -a +// Default arguments are allowed in the options files. +// // -e // Print the default options entries (rather than the merged options) to // STDOUT one per line in the following format: @@ -66,6 +57,12 @@ using namespace butl; // -t // Trace the default options files search to STDERR. // +// -m <num> +// Maximum number of arguments globally (SIZE_MAX/2 by default). +// +// -l <num> +// Maximum number of arguments in the options file (1024 by default). +// int main (int argc, const char* argv[]) { @@ -74,37 +71,111 @@ main (int argc, const char* argv[]) class scanner { public: - scanner (const string& f): ifs_ (f, fdopen_mode::in, ifdstream::badbit) {} + scanner (const string& f, const string& option, size_t pos) + : option_ (option), start_pos_ (pos) {load (path (f));} + + bool + more () + { + return i_ < args_.size (); + } - optional<string> + string + peek () + { + assert (more ()); + return args_[i_]; + } + + string next () { - string s; - return !eof (getline (ifs_, s)) ? optional<string> (move (s)) : nullopt; + assert (more ()); + return args_[i_++]; + } + + size_t + position () + { + return start_pos_ + i_; } private: - ifdstream ifs_; + void + load (const path& f) + { + ifdstream is (f, fdopen_mode::in, ifdstream::badbit); + + for (string l; !eof (getline (is, l)); ) + { + if (option_ && *option_ == l) + { + assert (!eof (getline (is, l))); + + // If the path of the file being parsed is not simple and the path + // of the file that needs to be loaded is relative, then complete + // the latter using the former as a base. + // + path p (l); + + if (!f.simple () && p.relative ()) + p = f.directory () / p; + + load (p); + } + else + args_.push_back (move (l)); + } + } + + private: + optional<string> option_; + vector<string> args_; + size_t i_ = 0; + size_t start_pos_; }; enum class unknow_mode { + stop, fail }; + class unknown_argument: public std::exception + { + public: + string argument; + + explicit + unknown_argument (string a): argument (move (a)) {} + }; + class options: public vector<string> { public: bool - parse (scanner& s, unknow_mode, unknow_mode) + parse (scanner& s, unknow_mode, unknow_mode m) { bool r (false); - while (optional<string> o = s.next ()) + while (s.more ()) { - if (*o == "--no-default-options") + string a (s.peek ()); + + if (a.compare (0, 2, "--") != 0) + { + switch (m) + { + case unknow_mode::stop: return r; + case unknow_mode::fail: throw unknown_argument (move (a)); + } + } + + s.next (); + + if (a == "--no-default-options") no_default_options_ = true; - push_back (move (*o)); + push_back (move (a)); r = true; } return r; @@ -132,60 +203,98 @@ main (int argc, const char* argv[]) optional<dir_path> sys_dir; optional<dir_path> home_dir; optional<dir_path> extra_dir; + bool args (false); vector<dir_path> dirs; options cmd_ops; + vector<string> cmd_args; bool print_entries (false); bool trace (false); + size_t arg_max (numeric_limits<size_t>::max () / 2); + size_t arg_max_file (1024); + + auto num = [] (const string& s) -> size_t + { + 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 () && + r <= numeric_limits<size_t>::max ()); + + return static_cast<size_t> (r); + }; for (int i (1); i != argc; ++i) { - string op (argv[i]); + string a (argv[i]); - if (op == "-f") + if (a == "-f") { assert (++i != argc); fs.files.push_back (path (argv[i])); } - else if (op == "-d") + else if (a == "-d") { assert (++i != argc); dirs.emplace_back (argv[i]); } - else if (op == "-s") + else if (a == "-s") { assert (++i != argc); sys_dir = dir_path (argv[i]); } - else if (op == "-h") + else if (a == "-h") { assert (++i != argc); home_dir = dir_path (argv[i]); } - else if (op == "-x") + else if (a == "-x") { assert (++i != argc); extra_dir = dir_path (argv[i]); } - else if (op == "-e") + else if (a == "-a") + { + args = true; + } + else if (a == "-e") { print_entries = true; } - else if (op == "-t") + else if (a == "-t") { trace = true; } + else if (a == "-m") + { + assert (++i != argc); + arg_max = num (argv[i]); + } + else if (a == "-l") + { + assert (++i != argc); + arg_max_file = num (argv[i]); + } + else if (a.compare (0, 2, "--") == 0) + cmd_ops.push_back (move (a)); else - cmd_ops.push_back (argv[i]); + cmd_args.push_back (move (a)); } // Deduce a common start directory. // - fs.start = default_options_start (home_dir, dirs); + fs.start = default_options_start (home_dir, dirs.begin (), dirs.end ()); // Load and print the default options. // - default_options<options> def_ops ( - load_default_options<options, scanner, unknow_mode> ( + default_options<options> def_ops; + + try + { + def_ops = load_default_options<options, scanner, unknow_mode> ( sys_dir, home_dir, extra_dir, @@ -195,7 +304,23 @@ main (int argc, const char* argv[]) if (trace) cerr << (overwrite ? "overwriting " : "loading ") << (remote ? "remote " : "local ") << f << endl; - })); + }, + "--options-file", + arg_max, + arg_max_file, + args); + } + catch (const unknown_argument& e) + { + cerr << "error: unexpected argument '" << e.argument << "'" << endl; + return 1; + } + catch (const invalid_argument& e) + { + cerr << "error: unable to load default options files: " << e.what () + << endl; + return 1; + } if (print_entries) { @@ -211,18 +336,40 @@ main (int argc, const char* argv[]) cout << o; } + if (args) + { + cout << "|"; + + for (const string& a: e.arguments) + { + if (&a != &e.arguments[0]) + cout << ' '; + + cout << a; + } + + } + cout << (e.remote ? ",true" : ",false") << endl; } } // Merge the options and print the result. // - options ops (merge_default_options (def_ops, cmd_ops)); - if (!print_entries) { + options ops (merge_default_options (def_ops, cmd_ops)); + for (const string& o: ops) cout << o << endl; + + if (args) + { + vector<string> as (merge_default_arguments (def_ops, cmd_args)); + + for (const string& a: as) + cout << a << endl; + } } return 0; diff --git a/tests/default-options/testscript b/tests/default-options/testscript index fa65e62..f071701 100644 --- a/tests/default-options/testscript +++ b/tests/default-options/testscript @@ -4,9 +4,9 @@ # Note that when cross-testing the driver may not be able to run the command # due to the meaningless program path. # -+if ($test.target != $build.host) - exit -end +#+if ($test.target != $build.host) +# exit +#end : basic : @@ -14,46 +14,47 @@ end sys_dir = $canonicalize([dir_path] $~/build2) +mkdir -p $sys_dir/local - +echo 'sys-foo' >=$sys_dir/foo - +echo 'sys-bar' >=$sys_dir/bar - +echo 'sys-local-foo' >=$sys_dir/local/foo - +echo 'sys-local-bar' >=$sys_dir/local/bar + +echo '--sys-foo' >=$sys_dir/foo + +echo '--sys-bar' >=$sys_dir/bar + +echo '--sys-local-foo' >=$sys_dir/local/foo + +echo '--sys-local-bar' >=$sys_dir/local/bar home_dir = $canonicalize([dir_path] $~/home) +mkdir -p $home_dir/.build2/local/ - +echo 'home-foo' >=$home_dir/.build2/foo - +echo 'home-bar' >=$home_dir/.build2/bar - +echo 'home-local-foo' >=$home_dir/.build2/local/foo - +echo 'home-local-bar' >=$home_dir/.build2/local/bar + +echo '--home-foo' >=$home_dir/.build2/foo + +echo '--home-bar' >=$home_dir/.build2/bar + +echo '--home-local-foo' >=$home_dir/.build2/local/foo + +echo '--home-local-bar' >=$home_dir/.build2/local/bar work_dir = $home_dir/work +mkdir -p $work_dir/.build2/local/ d = $work_dir/.build2 - +echo 'work-foo' >=$d/foo - +echo 'work-bar' >=$d/bar - +echo 'work-local-foo' >=$d/local/foo - +echo 'work-local-bar' >=$d/local/bar + +echo '--work-foo' >=$d/foo + +echo '--work-bar' >=$d/bar + +echo '--work-local-foo' >=$d/local/foo + +echo '--work-local-bar' >=$d/local/bar d = $work_dir/project/.build2 +mkdir -p $d/local/ +touch $work_dir/project/.git - +echo 'project-foo' >=$d/foo - +echo 'project-bar' >=$d/bar - +echo 'project-local-foo' >=$d/local/foo - +echo 'project-local-bar' >=$d/local/bar + +echo '--project-foo' >=$d/foo + +echo '--project-bar' >=$d/bar + +echo '--project-local-foo' >=$d/local/foo + +echo '--project-local-bar' >=$d/local/bar d = $work_dir/project/package/.build2 +mkdir -p $d/local/ - +echo 'package-foo' >=$d/foo - +echo 'package-bar' >=$d/bar - +echo 'package-local-foo' >=$d/local/foo - +echo 'package-local-bar' >=$d/local/bar + +echo '--package-foo' >=$d/foo + +echo '--package-fox' >+$d/foo + +echo '--package-bar' >=$d/bar + +echo '--package-local-foo' >=$d/local/foo + +echo '--package-local-bar' >=$d/local/bar +echo '--no-default-options' >=$d/local/baz @@ -62,26 +63,26 @@ end : entries : $* -e -t -f foo -f bar -d $start_dir -s $sys_dir -h $home_dir >>/~%EOO%d 2>>/~%EOE%d - %\.+/build2/foo,sys-foo,false% - %\.+/build2/bar,sys-bar,false% - %\.+/build2/local/foo,sys-local-foo,false% - %\.+/build2/local/bar,sys-local-bar,false% - %\.+/home/.build2/foo,home-foo,false% - %\.+/home/.build2/bar,home-bar,false% - %\.+/home/.build2/local/foo,home-local-foo,false% - %\.+/home/.build2/local/bar,home-local-bar,false% - %\.+/home/work/.build2/foo,work-foo,false% - %\.+/home/work/.build2/bar,work-bar,false% - %\.+/home/work/.build2/local/foo,work-local-foo,false% - %\.+/home/work/.build2/local/bar,work-local-bar,false% - %\.+/home/work/project/.build2/foo,project-foo,true% - %\.+/home/work/project/.build2/bar,project-bar,true% - %\.+/home/work/project/.build2/local/foo,project-local-foo,true% - %\.+/home/work/project/.build2/local/bar,project-local-bar,true% - %\.+/home/work/project/package/.build2/foo,package-foo,true% - %\.+/home/work/project/package/.build2/bar,package-bar,true% - %\.+/home/work/project/package/.build2/local/foo,package-local-foo,true% - %\.+/home/work/project/package/.build2/local/bar,package-local-bar,true% + %\.+/build2/foo,--sys-foo,false% + %\.+/build2/bar,--sys-bar,false% + %\.+/build2/local/foo,--sys-local-foo,false% + %\.+/build2/local/bar,--sys-local-bar,false% + %\.+/home/.build2/foo,--home-foo,false% + %\.+/home/.build2/bar,--home-bar,false% + %\.+/home/.build2/local/foo,--home-local-foo,false% + %\.+/home/.build2/local/bar,--home-local-bar,false% + %\.+/home/work/.build2/foo,--work-foo,false% + %\.+/home/work/.build2/bar,--work-bar,false% + %\.+/home/work/.build2/local/foo,--work-local-foo,false% + %\.+/home/work/.build2/local/bar,--work-local-bar,false% + %\.+/home/work/project/.build2/foo,--project-foo,true% + %\.+/home/work/project/.build2/bar,--project-bar,true% + %\.+/home/work/project/.build2/local/foo,--project-local-foo,true% + %\.+/home/work/project/.build2/local/bar,--project-local-bar,true% + %\.+/home/work/project/package/.build2/foo,--package-foo --package-fox,true% + %\.+/home/work/project/package/.build2/bar,--package-bar,true% + %\.+/home/work/project/package/.build2/local/foo,--package-local-foo,true% + %\.+/home/work/project/package/.build2/local/bar,--package-local-bar,true% EOO %loading local \.+/home/work/project/package/.build2/local/bar% %loading local \.+/home/work/project/package/.build2/local/foo% @@ -111,37 +112,38 @@ end : merged : - $* -f foo -f bar -d $start_dir -s $sys_dir -h $home_dir cmd-foo cmd-bar >>EOO - sys-foo - sys-bar - sys-local-foo - sys-local-bar - home-foo - home-bar - home-local-foo - home-local-bar - work-foo - work-bar - work-local-foo - work-local-bar - project-foo - project-bar - project-local-foo - project-local-bar - package-foo - package-bar - package-local-foo - package-local-bar - cmd-foo - cmd-bar + $* -f foo -f bar -d $start_dir -s $sys_dir -h $home_dir --cmd-foo --cmd-bar >>EOO + --sys-foo + --sys-bar + --sys-local-foo + --sys-local-bar + --home-foo + --home-bar + --home-local-foo + --home-local-bar + --work-foo + --work-bar + --work-local-foo + --work-local-bar + --project-foo + --project-bar + --project-local-foo + --project-local-bar + --package-foo + --package-fox + --package-bar + --package-local-foo + --package-local-bar + --cmd-foo + --cmd-bar EOO : no-default-options : $* -e -t -f foo -f baz -f bar -d $start_dir -s $sys_dir -h $home_dir >>/~%EOO%d 2>>/~%EOE%d - %\.+/home/work/project/package/.build2/local/foo,package-local-foo,true% + %\.+/home/work/project/package/.build2/local/foo,--package-local-foo,true% %\.+/home/work/project/package/.build2/local/baz,--no-default-options,true% - %\.+/home/work/project/package/.build2/local/bar,package-local-bar,true% + %\.+/home/work/project/package/.build2/local/bar,--package-local-bar,true% EOO %loading local \.+/home/work/project/package/.build2/local/bar% %loading local \.+/home/work/project/package/.build2/local/baz% @@ -150,6 +152,67 @@ end %overwriting remote \.+/home/work/project/package/.build2/local/baz% %overwriting remote \.+/home/work/project/package/.build2/local/foo% EOE + + : positions + : + { + : success + : + $* -f foo -f bar -d $start_dir -m 36 -l 2 >! + + : fail-file + : + $* -f foo -f bar -d $start_dir -m 36 -l 1 2>>/~%EOE% != 0 + %error: unable to load default options files: too many options in file .+/package/\.build2/foo% + EOE + + : fail-globally + : + $* -f foo -f bar -d $start_dir -m 100 -l 10 2>>EOE != 0 + error: unable to load default options files: too many options files + EOE + } +} + +: args +: +{ + home_dir = $canonicalize([dir_path] $~/home) + +mkdir -p $home_dir/.build2 + +echo '--home' >=$home_dir/.build2/ops + +echo 'home' >+$home_dir/.build2/ops + + start_dir = $canonicalize([dir_path] $home_dir/start) + +mkdir -p $start_dir/.build2 + +echo '--start1' >=$start_dir/.build2/ops + +echo 'start2' >+$start_dir/.build2/ops + +echo '--start3' >+$start_dir/.build2/ops + +echo 'start4' >+$start_dir/.build2/ops + + : allowed + : + $* -a -e -f ops -d $start_dir -h $home_dir >>/~%EOO%d + %\.+/home/.build2/ops,--home\|home,false% + %\.+/home/start/.build2/ops,--start1 --start3\|start2 start4,false% + EOO + + : disallowed + : + $* -e -f ops -d $start_dir -h $home_dir 2>>EOE != 0 + error: unexpected argument 'start2' + EOE + + : merged + : + $* -a -f ops -d $start_dir -h $home_dir cmd >>EOO + --home + --start1 + --start3 + home + start2 + start4 + cmd + EOO } : common-start @@ -166,10 +229,10 @@ end +mkdir -p $work_dir/.build2 $cfg1/.build2 $cfg2/.build2 $cfg3/.build2 - +echo 'work' >=$work_dir/.build2/ops - +echo 'cfg1' >=$cfg1/.build2/ops - +echo 'cfg2' >=$cfg2/.build2/ops - +echo 'cfg3' >=$cfg3/.build2/ops + +echo '--work' >=$work_dir/.build2/ops + +echo '--cfg1' >=$cfg1/.build2/ops + +echo '--cfg2' >=$cfg2/.build2/ops + +echo '--cfg3' >=$cfg3/.build2/ops : exists : @@ -177,29 +240,29 @@ end : single : $* -f ops -d $cfg3 -h $home_dir >>EOO - work - cfg2 - cfg3 + --work + --cfg2 + --cfg3 EOO : same : $* -f ops -d $cfg1 -d $cfg1 -h $home_dir >>EOO - work - cfg1 + --work + --cfg1 EOO : adjacent : $* -f ops -d $cfg1 -d $cfg2 -h $home_dir >>EOO - work + --work EOO : nested : $* -f ops -d $cfg2 -d $cfg3 -h $home_dir >>EOO - work - cfg2 + --work + --cfg2 EOO } @@ -209,7 +272,7 @@ end : home-reached : $* -f ops -d $cfg1 -d $cfg2 -h $work_dir >>EOO - work + --work EOO : root-reached @@ -229,20 +292,20 @@ end { home_dir = $canonicalize([dir_path] $~/home); mkdir -p $home_dir/.build2; - echo 'home' >=$home_dir/.build2/ops; + echo '--home' >=$home_dir/.build2/ops; extra_dir = $canonicalize([dir_path] $home_dir/extra); mkdir -p $extra_dir; - echo 'extra' >=$extra_dir/ops; + echo '--extra' >=$extra_dir/ops; start_dir = $canonicalize([dir_path] $home_dir/start); mkdir -p $start_dir/.build2; - echo 'start' >=$start_dir/.build2/ops; + echo '--start' >=$start_dir/.build2/ops; $* -e -f ops -d $start_dir -h $home_dir -x $extra_dir >>/~%EOO%d - %\.+/home/.build2/ops,home,false% - %\.+/home/extra/ops,extra,false% - %\.+/home/start/.build2/ops,start,false% + %\.+/home/.build2/ops,--home,false% + %\.+/home/extra/ops,--extra,false% + %\.+/home/start/.build2/ops,--start,false% EOO } @@ -251,56 +314,89 @@ end { home_dir = $canonicalize([dir_path] $~/home); mkdir -p $home_dir/.build2; - echo 'home' >=$home_dir/.build2/ops; + echo '--home' >=$home_dir/.build2/ops; d = $home_dir/project/.build2; mkdir -p $d; - echo 'project' >=$d/ops; + echo '--project' >=$d/ops; touch $home_dir/project/.git; d = $home_dir/project/package/.build2; mkdir -p $d; - echo 'package' >=$d/ops; + echo '--package' >=$d/ops; extra_dir = $canonicalize([dir_path] $home_dir/project/package/extra1); mkdir -p $extra_dir; - echo 'extra1' >=$extra_dir/ops; + echo '--extra1' >=$extra_dir/ops; start_dir = $canonicalize([dir_path] $home_dir/project/package); $* -e -f ops -d $start_dir -h $home_dir -x $extra_dir >>/~%EOO%d; - %\.+/home/.build2/ops,home,false% - %\.+/home/project/.build2/ops,project,true% - %\.+/home/project/package/.build2/ops,package,true% - %\.+/home/project/package/extra1/ops,extra1,false% + %\.+/home/.build2/ops,--home,false% + %\.+/home/project/.build2/ops,--project,true% + %\.+/home/project/package/.build2/ops,--package,true% + %\.+/home/project/package/extra1/ops,--extra1,false% EOO extra_dir = $canonicalize([dir_path] $home_dir/project/package/.build2); $* -e -f ops -d $start_dir -h $home_dir -x $extra_dir/ >>/~%EOO%d; - %\.+/home/.build2/ops,home,false% - %\.+/home/project/.build2/ops,project,true% - %\.+/home/project/package/.build2/ops,package,false% + %\.+/home/.build2/ops,--home,false% + %\.+/home/project/.build2/ops,--project,true% + %\.+/home/project/package/.build2/ops,--package,false% EOO extra_dir = $canonicalize([dir_path] $home_dir/project/extra2); mkdir -p $extra_dir; - echo 'extra2' >=$extra_dir/ops; + echo '--extra2' >=$extra_dir/ops; $* -e -f ops -d $start_dir -h $home_dir -x $extra_dir >>/~%EOO%d; - %\.+/home/.build2/ops,home,false% - %\.+/home/project/.build2/ops,project,true% - %\.+/home/project/extra2/ops,extra2,false% - %\.+/home/project/package/.build2/ops,package,true% + %\.+/home/.build2/ops,--home,false% + %\.+/home/project/.build2/ops,--project,true% + %\.+/home/project/extra2/ops,--extra2,false% + %\.+/home/project/package/.build2/ops,--package,true% EOO extra_dir = $canonicalize([dir_path] $home_dir/project/.build2); $* -e -f ops -d $start_dir -h $home_dir -x $extra_dir/ >>/~%EOO%d - %\.+/home/.build2/ops,home,false% - %\.+/home/project/.build2/ops,project,false% - %\.+/home/project/package/.build2/ops,package,true% + %\.+/home/.build2/ops,--home,false% + %\.+/home/project/.build2/ops,--project,false% + %\.+/home/project/package/.build2/ops,--package,true% EOO } } + +: options-file +: +{ + d = work/.build2; + mkdir -p work/.build2; + + cat <<EOI >=$d/foo; + --foo + --options-file + bar + --fox + EOI + + cat <<EOI >=$d/bar; + --bar + --options-file + baz + --box + EOI + + cat <<EOI >=$d/baz; + --baz + EOI + + $* -d $~/work -f foo >>EOO + --foo + --bar + --baz + --box + --fox + EOO +} diff --git a/tests/dir-iterator/driver.cxx b/tests/dir-iterator/driver.cxx index b73e2e2..c9f7218 100644 --- a/tests/dir-iterator/driver.cxx +++ b/tests/dir-iterator/driver.cxx @@ -1,30 +1,17 @@ // file : tests/dir-iterator/driver.cxx -*- C++ -*- // license : MIT; see accompanying LICENSE file -#include <cassert> - -#ifndef __cpp_lib_modules_ts #include <cstddef> // size_t #include <iostream> -#endif - -// Other includes. - -#ifdef __cpp_modules_ts -#ifdef __cpp_lib_modules_ts -import std.core; -import std.io; -#endif -import butl.path; -import butl.path_io; -import butl.utility; -import butl.filesystem; -#else -#include <libbutl/path.mxx> -#include <libbutl/path-io.mxx> -#include <libbutl/utility.mxx> // operator<<(ostream, exception) -#include <libbutl/filesystem.mxx> -#endif + +#include <libbutl/path.hxx> +#include <libbutl/path-io.hxx> +#include <libbutl/utility.hxx> // operator<<(ostream, exception) +#include <libbutl/timestamp.hxx> +#include <libbutl/filesystem.hxx> + +#undef NDEBUG +#include <cassert> using namespace std; using namespace butl; @@ -40,7 +27,7 @@ operator<< (ostream& os, entry_type e) return os << entry_type_string[static_cast<size_t> (e)]; } -// Usage: argv[0] [-v] [-i] <dir> +// Usage: argv[0] [-v] [-i|-d] <dir> // // Iterates over a directory filesystem sub-entries, obtains their types and // target types for symlinks. @@ -52,6 +39,10 @@ operator<< (ostream& os, entry_type e) // Ignore dangling symlinks, rather than fail trying to obtain the target // type. // +// -d +// Detect dangling symlinks, rather than fail trying to obtain the target +// type. +// int main (int argc, const char* argv[]) { @@ -59,6 +50,7 @@ main (int argc, const char* argv[]) bool verbose (false); bool ignore_dangling (false); + bool detect_dangling (false); int i (1); for (; i != argc; ++i) @@ -69,6 +61,8 @@ main (int argc, const char* argv[]) verbose = true; else if (v == "-i") ignore_dangling = true; + else if (v == "-d") + detect_dangling = true; else break; } @@ -79,15 +73,42 @@ main (int argc, const char* argv[]) return 1; } + assert (!ignore_dangling || !detect_dangling); + const char* d (argv[i]); try { - for (const dir_entry& de: dir_iterator (dir_path (d), ignore_dangling)) + for (const dir_entry& de: + dir_iterator (dir_path (d), + (ignore_dangling ? dir_iterator::ignore_dangling : + detect_dangling ? dir_iterator::detect_dangling : + dir_iterator::no_follow))) { + timestamp mt (de.mtime ()); + timestamp at (de.atime ()); + entry_type lt (de.ltype ()); entry_type t (lt == entry_type::symlink ? de.type () : lt); + const path& p (de.path ()); + path fp (de.base () / p); + + entry_time et (t == entry_type::directory + ? dir_time (path_cast<dir_path> (fp)) + : file_time (fp)); + + if (mt != timestamp_unknown) + assert (mt == et.modification); + + if (at != timestamp_unknown) + assert (mt == et.access); + + if (de.mtime () != timestamp_unknown) + assert (de.mtime () == et.modification); + + if (de.atime () != timestamp_unknown) + assert (de.atime () == et.access); if (verbose) { diff --git a/tests/dir-iterator/testscript b/tests/dir-iterator/testscript index 03ed164..9bc5513 100644 --- a/tests/dir-iterator/testscript +++ b/tests/dir-iterator/testscript @@ -7,6 +7,8 @@ test.options = -v : mkdir a; touch a/b; +sleep 1; +echo "a" >=a/b; # Change modification time. $* a >"reg b" : dir @@ -24,16 +26,16 @@ $* a >"dir b" if ($test.target == $build.host) { +if ($cxx.target.class != 'windows') - lnf = ^ln -s t wd/l &wd/l - lnd = $lnf + lnf = [cmdline] ^ln -s t wd/l &wd/l + lnd = [cmdline] $lnf else echo 'yes' >=t if cmd /C 'mklink l t' >- 2>- &?l && cat l >'yes' - lnf = cmd /C 'mklink wd\l t' &wd/l >- - lnd = cmd /C 'mklink /D wd\l t' &wd/l >- + lnf = [cmdline] cmd /C 'mklink wd\l t' &wd/l >- + lnd = [cmdline] cmd /C 'mklink /D wd\l t' &wd/l >- end - jnc = cmd /C 'mklink /J wd\l wd\t' &wd/l >- + jnc = [cmdline] cmd /C 'mklink /J wd\l wd\t' &wd/l >- end : symlink @@ -54,6 +56,12 @@ if ($test.target == $build.host) $* ../wd >- 2>! != 0 : keep $* -i ../wd >'reg f': skip + + : detect + : + $* -d ../wd >>~%EOO% + %(reg f|sym unk l)%{2} + EOO } : dir @@ -71,6 +79,12 @@ if ($test.target == $build.host) $* ../wd >- 2>! != 0 : keep $* -i ../wd >'dir d': skip + + : detect + : + $* -d ../wd >>~%EOO% + %(dir d|sym unk l)%{2} + EOO } } @@ -89,5 +103,11 @@ if ($test.target == $build.host) $* ../wd >- 2>! != 0 : keep $* -i ../wd >'dir d': skip + + : detect + : + $* -d ../wd >>~%EOO% + %(dir d|sym unk l)%{2} + EOO } } diff --git a/tests/entry-time/driver.cxx b/tests/entry-time/driver.cxx index 1e64b0d..c29837d 100644 --- a/tests/entry-time/driver.cxx +++ b/tests/entry-time/driver.cxx @@ -1,31 +1,17 @@ // file : tests/entry-time/driver.cxx -*- C++ -*- // license : MIT; see accompanying LICENSE file -#include <cassert> - -#ifndef __cpp_lib_modules_ts #include <string> #include <chrono> #include <iostream> -#endif -// Other includes. +#include <libbutl/path.hxx> +#include <libbutl/optional.hxx> +#include <libbutl/timestamp.hxx> +#include <libbutl/filesystem.hxx> -#ifdef __cpp_modules_ts -#ifdef __cpp_lib_modules_ts -import std.core; -import std.io; -#endif -import butl.path; -import butl.filesystem; - -import butl.optional; // @@ MOD Clang should not be necessary. -#else -#include <libbutl/path.mxx> -#include <libbutl/optional.mxx> -#include <libbutl/timestamp.mxx> -#include <libbutl/filesystem.mxx> -#endif +#undef NDEBUG +#include <cassert> using namespace std; using namespace butl; diff --git a/tests/fdstream/driver.cxx b/tests/fdstream/driver.cxx index 3215e02..d039b00 100644 --- a/tests/fdstream/driver.cxx +++ b/tests/fdstream/driver.cxx @@ -5,9 +5,6 @@ # include <libbutl/win32-utility.hxx> #endif -#include <cassert> - -#ifndef __cpp_lib_modules_ts #ifndef _WIN32 # include <chrono> #endif @@ -15,38 +12,28 @@ #include <ios> #include <string> #include <vector> -#include <thread> #include <iomanip> #include <sstream> #include <fstream> #include <utility> // move() #include <iostream> #include <exception> -#endif -// Other includes. - -#ifdef __cpp_modules_ts -#ifdef __cpp_lib_modules_ts -import std.core; -import std.io; -#ifndef _WIN32 -import std.threading; -#endif -#endif -import butl.path; -import butl.process; -import butl.fdstream; -import butl.timestamp; -import butl.filesystem; +#ifndef LIBBUTL_MINGW_STDTHREAD +# include <thread> #else -#include <libbutl/path.mxx> -#include <libbutl/process.mxx> -#include <libbutl/fdstream.mxx> -#include <libbutl/timestamp.mxx> -#include <libbutl/filesystem.mxx> +# include <libbutl/mingw-thread.hxx> #endif +#include <libbutl/path.hxx> +#include <libbutl/process.hxx> +#include <libbutl/fdstream.hxx> +#include <libbutl/timestamp.hxx> +#include <libbutl/filesystem.hxx> + +#undef NDEBUG +#include <cassert> + using namespace std; using namespace butl; @@ -55,7 +42,9 @@ static const string text2 ("12"); // Keep shorter than text1. // Windows text mode write-translated form of text1. // +#ifdef _WIN32 static const string text3 ("ABCDEF\r\nXYZ"); +#endif static string from_stream (ifdstream& is) @@ -133,6 +122,12 @@ read_time (const path& p, const T& s, size_t n) int main (int argc, const char* argv[]) { +#ifndef LIBBUTL_MINGW_STDTHREAD + using std::thread; +#else + using mingw_stdthread::thread; +#endif + bool v (false); bool child (false); @@ -470,12 +465,12 @@ main (int argc, const char* argv[]) // { string s; - for (size_t i (0); i < 100; ++i) + for (size_t i (0); i < 300; ++i) s += "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\n"; const char* args[] = {argv[0], "-c", nullptr}; - auto test_read = [&args, &s] () + auto test_read = [&args, &s] (bool timeout) { try { @@ -491,11 +486,29 @@ main (int argc, const char* argv[]) string r; char buf[300]; + bool timedout (false); while (!is.eof ()) { - pair<size_t, size_t> nd (fdselect (rds, wds)); - - assert (nd.first == 1 && nd.second == 0 && rds[0].ready); + if (timeout) + { + pair<size_t, size_t> nd ( + fdselect (rds, wds, chrono::milliseconds (3))); + + assert (((nd.first == 0 && !rds[0].ready) || + (nd.first == 1 && rds[0].ready)) && + nd.second == 0); + + if (nd.first == 0) + { + timedout = true; + continue; + } + } + else + { + pair<size_t, size_t> nd (fdselect (rds, wds)); + assert (nd.first == 1 && nd.second == 0 && rds[0].ready); + } for (streamsize n; (n = is.readsome (buf, sizeof (buf))) != 0; ) r.append (buf, static_cast<size_t> (n)); @@ -504,6 +517,10 @@ main (int argc, const char* argv[]) is.close (); assert (r == s); + + // If timeout is used, then it most likely timedout, at least once. + // + assert (timedout == timeout); } catch (const ios::failure&) { @@ -517,7 +534,10 @@ main (int argc, const char* argv[]) vector<thread> threads; for (size_t i (0); i < 10; ++i) - threads.emplace_back (test_read); + { + threads.emplace_back ([&test_read] {test_read (true /* timeout */);}); + threads.emplace_back ([&test_read] {test_read (false /* timeout */);}); + } // While the threads are busy, let's test the skip/non_blocking modes // combination. @@ -550,7 +570,85 @@ main (int argc, const char* argv[]) t.join (); } - // Test setting and getting position via the non-standard fdbuf interface. + // Test (non-blocking) reading with getline_non_blocking(). + // + { + const string ln ( + "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"); + + string s; + for (size_t i (0); i < 300; ++i) + { + s += ln; + s += '\n'; + } + + const char* args[] = {argv[0], "-c", nullptr}; + + auto test_read = [&args, &s, &ln] () + { + try + { + process pr (args, -1, -1); + ofdstream os (move (pr.out_fd)); + + ifdstream is (move (pr.in_ofd), + fdstream_mode::non_blocking, + ios_base::badbit); + + os << s; + os.close (); + + fdselect_set fds {is.fd ()}; + fdselect_state& ist (fds[0]); + + string r; + for (string l; ist.fd != nullfd; ) + { + if (ist.fd != nullfd && getline_non_blocking (is, l)) + { + if (eof (is)) + ist.fd = nullfd; + else + { + assert (l == ln); + + r += l; + r += '\n'; + + l.clear (); + } + + continue; + } + + ifdselect (fds); + } + + is.close (); + + assert (r == s); + } + catch (const ios::failure&) + { + assert (false); + } + catch (const process_error&) + { + assert (false); + } + }; + + vector<thread> threads; + for (size_t i (0); i < 20; ++i) + threads.emplace_back (test_read); + + for (thread& t: threads) + t.join (); + } + + // Test setting and getting position via the non-standard fdstreambuf + // interface. // // Seek for read. // @@ -559,7 +657,7 @@ main (int argc, const char* argv[]) ifdstream is (f); - fdbuf* buf (dynamic_cast<fdbuf*> (is.rdbuf ())); + fdstreambuf* buf (dynamic_cast<fdstreambuf*> (is.rdbuf ())); assert (buf != nullptr); char c; @@ -602,7 +700,7 @@ main (int argc, const char* argv[]) { ifdstream is (f, fdopen_mode::in | fdopen_mode::out); - fdbuf* buf (dynamic_cast<fdbuf*> (is.rdbuf ())); + fdstreambuf* buf (dynamic_cast<fdstreambuf*> (is.rdbuf ())); assert (buf != nullptr); // Read till the end of the fragment. @@ -660,7 +758,7 @@ main (int argc, const char* argv[]) assert (static_cast<streamoff> (is.tellg ()) == 8); - const fdbuf* buf (dynamic_cast<const fdbuf*> (is.rdbuf ())); + const fdstreambuf* buf (dynamic_cast<const fdstreambuf*> (is.rdbuf ())); assert (buf != nullptr && buf->tellg () == 8); assert (from_stream (is) == "89"); @@ -679,7 +777,7 @@ main (int argc, const char* argv[]) assert (static_cast<streamoff> (os.tellp ()) == 2); - const fdbuf* buf (dynamic_cast<const fdbuf*> (os.rdbuf ())); + const fdstreambuf* buf (dynamic_cast<const fdstreambuf*> (os.rdbuf ())); assert (buf != nullptr && buf->tellp () == 2); os.close (); @@ -732,7 +830,7 @@ main (int argc, const char* argv[]) assert (static_cast<streamoff> (is.tellg ()) == 8); - const fdbuf* buf (dynamic_cast<const fdbuf*> (is.rdbuf ())); + const fdstreambuf* buf (dynamic_cast<const fdstreambuf*> (is.rdbuf ())); assert (buf != nullptr && buf->tellp () == 8); assert (from_stream (is) == "6789"); @@ -867,6 +965,11 @@ main (int argc, const char* argv[]) } #endif + + // Test fdterm(). + // + assert (!fdterm (fdopen_null ().get ())); // /dev/null is not a terminal. + // Compare fdstream and fstream operations performance. // duration fwd (0); diff --git a/tests/host-os-release/buildfile b/tests/host-os-release/buildfile new file mode 100644 index 0000000..cd277ff --- /dev/null +++ b/tests/host-os-release/buildfile @@ -0,0 +1,6 @@ +# file : tests/host-os-release/buildfile +# license : MIT; see accompanying LICENSE file + +import libs = libbutl%lib{butl} + +exe{driver}: {hxx cxx}{*} $libs testscript diff --git a/tests/host-os-release/driver.cxx b/tests/host-os-release/driver.cxx new file mode 100644 index 0000000..249cbff --- /dev/null +++ b/tests/host-os-release/driver.cxx @@ -0,0 +1,58 @@ +// file : tests/host-os-release/driver.cxx -*- C++ -*- +// license : MIT; see accompanying LICENSE file + +#include <libbutl/host-os-release.hxx> + +#include <libbutl/path.hxx> + +namespace butl +{ + LIBBUTL_SYMEXPORT os_release + host_os_release_linux (path f = {}); +} + +#include <iostream> + +#undef NDEBUG +#include <cassert> + +using namespace std; +using namespace butl; + +int +main (int argc, char* argv[]) +{ + assert (argc >= 2); // <host-target-triplet> + + target_triplet host (argv[1]); + + os_release r; + if (host.class_ == "linux") + { + assert (argc == 3); // <host-target-triplet> <file-path> + r = host_os_release_linux (path (argv[2])); + } + else + { + assert (argc == 2); + if (optional<os_release> o = host_os_release (host)) + r = move (*o); + else + { + cerr << "unrecognized host os " << host.string () << endl; + return 1; + } + } + + cout << r.name_id << '\n'; + for (auto b (r.like_ids.begin ()), i (b); i != r.like_ids.end (); ++i) + cout << (i != b ? "|" : "") << *i; + cout << '\n' + << r.version_id << '\n' + << r.variant_id << '\n' + << r.name << '\n' + << r.version_codename << '\n' + << r.variant << '\n'; + + return 0; +} diff --git a/tests/host-os-release/testscript b/tests/host-os-release/testscript new file mode 100644 index 0000000..a18aa74 --- /dev/null +++ b/tests/host-os-release/testscript @@ -0,0 +1,223 @@ +# file : tests/host-os-release/testscript +# license : MIT; see accompanying LICENSE file + +: linux +: +$* x86_64-linux-gnu os-release >>EOO + linux + + + + Linux + + + EOO + +: debian-10 +: +cat <<EOI >=os-release; + PRETTY_NAME="Debian GNU/Linux 10 (buster)" + NAME="Debian GNU/Linux" + VERSION_ID="10" + VERSION="10 (buster)" + VERSION_CODENAME=buster + ID=debian + HOME_URL="https://www.debian.org/" + SUPPORT_URL="https://www.debian.org/support" + BUG_REPORT_URL="https://bugs.debian.org/" + EOI +$* x86_64-linux-gnu os-release >>EOO + debian + + 10 + + Debian GNU/Linux + buster + + EOO + +: debian-testing +: +cat <<EOI >=os-release; + PRETTY_NAME="Debian GNU/Linux bookworm/sid" + NAME="Debian GNU/Linux" + ID=debian + HOME_URL="https://www.debian.org/" + SUPPORT_URL="https://www.debian.org/support" + BUG_REPORT_URL="https://bugs.debian.org/" + EOI +$* x86_64-linux-gnu os-release >>EOO + debian + + + + Debian GNU/Linux + + + EOO + +: ubuntu-20.04 +: +cat <<EOI >=os-release; + NAME="Ubuntu" + VERSION="20.04.1 LTS (Focal Fossa)" + ID=ubuntu + ID_LIKE=debian + PRETTY_NAME="Ubuntu 20.04.1 LTS" + VERSION_ID="20.04" + HOME_URL="https://www.ubuntu.com/" + SUPPORT_URL="https://help.ubuntu.com/" + BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/" + PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy" + VERSION_CODENAME=focal + UBUNTU_CODENAME=focal + EOI +$* x86_64-linux-gnu os-release >>EOO + ubuntu + debian + 20.04 + + Ubuntu + focal + + EOO + +: fedora-35 +: +cat <<EOI >=os-release; + NAME="Fedora Linux" + VERSION="35 (Workstation Edition)" + ID=fedora + VERSION_ID=35 + VERSION_CODENAME="" + PLATFORM_ID="platform:f35" + PRETTY_NAME="Fedora Linux 35 (Workstation Edition)" + ANSI_COLOR="0;38;2;60;110;180" + LOGO=fedora-logo-icon + CPE_NAME="cpe:/o:fedoraproject:fedora:35" + HOME_URL="https://fedoraproject.org/" + DOCUMENTATION_URL="https://docs.fedoraproject.org/en-US/fedora/f35/system-administrators-guide/" + SUPPORT_URL="https://ask.fedoraproject.org/" + BUG_REPORT_URL="https://bugzilla.redhat.com/" + REDHAT_BUGZILLA_PRODUCT="Fedora" + REDHAT_BUGZILLA_PRODUCT_VERSION=35 + REDHAT_SUPPORT_PRODUCT="Fedora" + REDHAT_SUPPORT_PRODUCT_VERSION=35 + PRIVACY_POLICY_URL="https://fedoraproject.org/wiki/Legal:PrivacyPolicy" + VARIANT="Workstation Edition" + VARIANT_ID=workstation + EOI +$* x86_64-linux-gnu os-release >>EOO + fedora + + 35 + workstation + Fedora Linux + + Workstation Edition + EOO + +: rhel-8.2 +: +cat <<EOI >=os-release; + NAME="Red Hat Enterprise Linux" + VERSION="8.2 (Ootpa)" + ID="rhel" + ID_LIKE="fedora" + VERSION_ID="8.2" + PLATFORM_ID="platform:el8" + PRETTY_NAME="Red Hat Enterprise Linux 8.2 (Ootpa)" + ANSI_COLOR="0;31" + CPE_NAME="cpe:/o:redhat:enterprise_linux:8.2:GA" + HOME_URL="https://www.redhat.com/" + BUG_REPORT_URL="https://bugzilla.redhat.com/" + + REDHAT_BUGZILLA_PRODUCT="Red Hat Enterprise Linux 8" + REDHAT_BUGZILLA_PRODUCT_VERSION=8.2 + REDHAT_SUPPORT_PRODUCT="Red Hat Enterprise Linux" + REDHAT_SUPPORT_PRODUCT_VERSION="8.2" + EOI +$* x86_64-linux-gnu os-release >>EOO + rhel + fedora + 8.2 + + Red Hat Enterprise Linux + + + EOO + +: centos-8 +: +cat <<EOI >=os-release; + NAME="CentOS Linux" + VERSION="8 (Core)" + ID="centos" + ID_LIKE="rhel fedora" + VERSION_ID="8" + PLATFORM_ID="platform:el8" + PRETTY_NAME="CentOS Linux 8 (Core)" + ANSI_COLOR="0;31" + CPE_NAME="cpe:/o:centos:centos:8" + HOME_URL="https://www.centos.org/" + BUG_REPORT_URL="https://bugs.centos.org/" + + CENTOS_MANTISBT_PROJECT="CentOS-8" + CENTOS_MANTISBT_PROJECT_VERSION="8" + REDHAT_SUPPORT_PRODUCT="centos" + REDHAT_SUPPORT_PRODUCT_VERSION="8" + EOI +$* x86_64-linux-gnu os-release >>EOO + centos + rhel|fedora + 8 + + CentOS Linux + + + EOO + +: macos +: +if ($build.host.class == 'macos') +{ + $* $build.host >>~/EOO/ + macos + + /[0-9]+(\.[0-9]+(\.[0-9]+)?)?/ + + Mac OS + + + EOO +} + +: freebsd +: +if ($build.host.system == 'freebsd') +{ + $* $build.host >>~/EOO/ + freebsd + + /[0-9]+\.[0-9]+/ + + FreeBSD + + + EOO +} + +: windows +: +if ($build.host.system == 'windows') +{ + $* $build.host >>~/EOO/ + windows + + /[0-9]+(\.[0-9]+)?/ + + Windows + + + EOO +} diff --git a/tests/link/driver.cxx b/tests/link/driver.cxx index 231da4b..b659838 100644 --- a/tests/link/driver.cxx +++ b/tests/link/driver.cxx @@ -1,34 +1,19 @@ // file : tests/link/driver.cxx -*- C++ -*- // license : MIT; see accompanying LICENSE file -#include <cassert> - -#ifndef __cpp_lib_modules_ts #include <set> #include <utility> // pair #include <iostream> // cerr #include <system_error> -#endif -// Other includes. +#include <libbutl/path.hxx> +#include <libbutl/path-io.hxx> +#include <libbutl/utility.hxx> +#include <libbutl/fdstream.hxx> +#include <libbutl/filesystem.hxx> -#ifdef __cpp_modules_ts -#ifdef __cpp_lib_modules_ts -import std.core; -import std.io; -#endif -import butl.path; -import butl.path_io; -import butl.utility; -import butl.fdstream; -import butl.filesystem; -#else -#include <libbutl/path.mxx> -#include <libbutl/path-io.mxx> -#include <libbutl/utility.mxx> -#include <libbutl/fdstream.mxx> -#include <libbutl/filesystem.mxx> -#endif +#undef NDEBUG +#include <cassert> using namespace std; using namespace butl; @@ -122,11 +107,11 @@ link_dir (const dir_path& target, dir_path tp (target.absolute () ? target : link.directory () / target); set<pair<entry_type, path>> te; - for (const dir_entry& de: dir_iterator (tp, false /* ignore_dangling */)) + for (const dir_entry& de: dir_iterator (tp, dir_iterator::no_follow)) te.emplace (de.ltype (), de.path ()); set<pair<entry_type, path>> le; - for (const dir_entry& de: dir_iterator (link, false /* ignore_dangling */)) + for (const dir_entry& de: dir_iterator (link, dir_iterator::no_follow)) le.emplace (de.ltype (), de.path ()); return te == le; @@ -321,7 +306,7 @@ main (int argc, const char* argv[]) assert (pe.first && pe.second.type == entry_type::directory); } - for (const dir_entry& de: dir_iterator (td, false /* ignore_dangling */)) + for (const dir_entry& de: dir_iterator (td, dir_iterator::no_follow)) { assert (de.path () != path ("dslink") || (de.type () == entry_type::directory && @@ -383,7 +368,9 @@ main (int argc, const char* argv[]) { mksymlink (dp / "non-existing", dp / "lnk"); assert (!dir_empty (dp)); - assert (dir_iterator (dp, true /* ignore_dangling */) == dir_iterator ()); + + assert (dir_iterator (dp, dir_iterator::ignore_dangling) == + dir_iterator ()); } catch (const system_error& e) { @@ -408,10 +395,10 @@ main (int argc, const char* argv[]) mksymlink (dp / "non-existing", dp / "lnk1", true /* dir */); assert (!dir_empty (dp)); - assert (dir_iterator (dp, true /* ignore_dangling */) == dir_iterator ()); + assert (dir_iterator (dp, dir_iterator::ignore_dangling) == dir_iterator ()); mksymlink (tgd, dp / "lnk2", true /* dir */); - assert (dir_iterator (dp, true /* ignore_dangling */) != dir_iterator ()); + assert (dir_iterator (dp, dir_iterator::ignore_dangling) != dir_iterator ()); rmdir_r (dp); assert (dir_exists (tgd)); diff --git a/tests/lz4/buildfile b/tests/lz4/buildfile new file mode 100644 index 0000000..1f9a244 --- /dev/null +++ b/tests/lz4/buildfile @@ -0,0 +1,6 @@ +# file : tests/lz4/buildfile +# license : MIT; see accompanying LICENSE file + +import libs = libbutl%lib{butl} + +exe{driver}: {hxx cxx}{*} $libs testscript file{*.lz4} diff --git a/tests/lz4/driver.cxx b/tests/lz4/driver.cxx new file mode 100644 index 0000000..8139c34 --- /dev/null +++ b/tests/lz4/driver.cxx @@ -0,0 +1,46 @@ +// file : tests/lz4/driver.cxx -*- C++ -*- +// license : MIT; see accompanying LICENSE file + +#include <iostream> +#include <exception> + +#include <libbutl/lz4.hxx> +#include <libbutl/fdstream.hxx> +#include <libbutl/filesystem.hxx> // entry_stat, path_entry() + +#undef NDEBUG +#include <cassert> + +using namespace std; +using namespace butl; + +// Usage: argv[0] [-c|-d] <input-file> <output-file> +// +int +main (int argc, const char* argv[]) +try +{ + assert (argc == 4); + + ifdstream ifs (argv[2], fdopen_mode::binary, ifdstream::badbit); + ofdstream ofs (argv[3], fdopen_mode::binary); + + if (argv[1][1] == 'c') + { + lz4::compress (ofs, ifs, + 1 /* compression_level */, + 4 /* block_size_id (64KB) */, + fdstat (ifs.fd ()).size); + } + else + { + lz4::decompress (ofs, ifs); + } + + ofs.close (); +} +catch (const std::exception& e) +{ + cerr << e.what () << endl; + return 1; +} diff --git a/tests/lz4/testscript b/tests/lz4/testscript new file mode 100644 index 0000000..b064cff --- /dev/null +++ b/tests/lz4/testscript @@ -0,0 +1,85 @@ +# file : tests/lz4/testscript +# license : MIT; see accompanying LICENSE file + ++touch zero ++cat <:'1' >=one ++cat <'The quick brown fox jumps over the lazy dog.' >=small ++cat <<EOI >=1kb +The quick brown fox jumps over the lazy dog. The quick brown fox jumps over +the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox +jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The +quick brown fox jumps over the lazy dog. The quick brown fox jumps over the +lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox +jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The +quick brown fox jumps over the lazy dog. The quick brown fox jumps over the +lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox +jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The +quick brown fox jumps over the lazy dog. The quick brown fox jumps over the +lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox +jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The +quick brown fox jumps over the lazy dog. The quick brown fox jumps over the +lazy dog. The quick brown fox jumps over th +EOI ++cat 1kb 1kb 1kb 1kb 1kb 1kb 1kb 1kb >=8kb ++cat 8kb 8kb 8kb 8kb 8kb 8kb 8kb 8kb >=64kb ++cat 64kb 64kb 64kb 64kb 64kb 64kb 64kb 64kb >=512kb + +: rt-zero +: +$* -c ../zero zero.lz4 &zero.lz4; +$* -d zero.lz4 zero &zero; +diff ../zero zero + +: rt-one +: +$* -c ../one one.lz4 &one.lz4; +$* -d one.lz4 one &one; +diff ../one one + +: rt-small +: +$* -c ../small small.lz4 &small.lz4; +$* -d small.lz4 small &small; +diff ../small small + +: rt-1kb +: +$* -c ../1kb 1kb.lz4 &1kb.lz4; +$* -d 1kb.lz4 1kb &1kb; +diff ../1kb 1kb + +: rt-8kb +: +$* -c ../8kb 8kb.lz4 &8kb.lz4; +$* -d 8kb.lz4 8kb &8kb; +diff ../8kb 8kb + +: rt-64kb +: +$* -c ../64kb 64kb.lz4 &64kb.lz4; +$* -d 64kb.lz4 64kb &64kb; +diff ../64kb 64kb + +: rt-512kb +: +$* -c ../512kb 512kb.lz4 &512kb.lz4; +$* -d 512kb.lz4 512kb &512kb; +diff ../512kb 512kb + +: truncated-header6 +: +$* -d $src_base/truncated-header6.lz4 out &out 2>>EOE !=0 +incomplete LZ4 frame header +EOE + +: truncated-header12 +: +$* -d $src_base/truncated-header12.lz4 out &out 2>>EOE !=0 +incomplete LZ4 frame header +EOE + +: truncated-content +: +$* -d $src_base/truncated-content.lz4 out &out 2>>EOE !=0 +incomplete LZ4 compressed content +EOE diff --git a/tests/lz4/truncated-content.lz4 b/tests/lz4/truncated-content.lz4 Binary files differnew file mode 100644 index 0000000..2a9a39d --- /dev/null +++ b/tests/lz4/truncated-content.lz4 diff --git a/tests/lz4/truncated-header12.lz4 b/tests/lz4/truncated-header12.lz4 Binary files differnew file mode 100644 index 0000000..101088e --- /dev/null +++ b/tests/lz4/truncated-header12.lz4 diff --git a/tests/lz4/truncated-header6.lz4 b/tests/lz4/truncated-header6.lz4 new file mode 100644 index 0000000..a00e998 --- /dev/null +++ b/tests/lz4/truncated-header6.lz4 @@ -0,0 +1 @@ +"Ml@
\ No newline at end of file diff --git a/tests/manifest-parser/driver.cxx b/tests/manifest-parser/driver.cxx index a34f2b7..56c614a 100644 --- a/tests/manifest-parser/driver.cxx +++ b/tests/manifest-parser/driver.cxx @@ -1,29 +1,17 @@ // file : tests/manifest-parser/driver.cxx -*- C++ -*- // license : MIT; see accompanying LICENSE file -#include <cassert> - -#ifndef __cpp_lib_modules_ts #include <vector> #include <string> #include <utility> // pair, move() #include <sstream> #include <iostream> -#endif - -// Other includes. - -#ifdef __cpp_modules_ts -#ifdef __cpp_lib_modules_ts -import std.core; -import std.io; -#endif -import butl.optional; -import butl.manifest_parser; -#else -#include <libbutl/optional.mxx> -#include <libbutl/manifest-parser.mxx> -#endif + +#include <libbutl/optional.hxx> +#include <libbutl/manifest-parser.hxx> + +#undef NDEBUG +#include <cassert> using namespace std; @@ -176,14 +164,18 @@ namespace butl // Manifest value splitting (into the value/comment pair). // + // Single-line. + // { - auto p (manifest_parser::split_comment ("value\\; text ; comment text")); - assert (p.first == "value; text" && p.second == "comment text"); + auto p (manifest_parser::split_comment ( + "\\value\\\\\\; text ; comment text")); + + assert (p.first == "\\value\\; text" && p.second == "comment text"); } { - auto p (manifest_parser::split_comment ("value")); - assert (p.first == "value" && p.second == ""); + auto p (manifest_parser::split_comment ("value\\")); + assert (p.first == "value\\" && p.second == ""); } { @@ -191,6 +183,59 @@ namespace butl assert (p.first == "" && p.second == "comment"); } + // Multi-line. + // + { + auto p (manifest_parser::split_comment ("value\n;")); + assert (p.first == "value" && p.second == ""); + } + + { + auto p (manifest_parser::split_comment ("value\ntext\n")); + assert (p.first == "value\ntext\n" && p.second == ""); + } + + { + auto p (manifest_parser::split_comment ("value\ntext\n;")); + assert (p.first == "value\ntext" && p.second == ""); + } + + { + auto p (manifest_parser::split_comment ("value\ntext\n;\n")); + assert (p.first == "value\ntext" && p.second == ""); + } + + { + auto p (manifest_parser::split_comment ("\n\\\nvalue\ntext\n" + ";\n" + "\n\n comment\ntext")); + + assert (p.first == "\n\\\nvalue\ntext" && p.second == + "\n\n comment\ntext"); + } + + { + auto p (manifest_parser::split_comment ("\n;\ncomment")); + assert (p.first == "" && p.second == "comment"); + } + + { + auto p (manifest_parser::split_comment (";\ncomment")); + assert (p.first == "" && p.second == "comment"); + } + + { + auto p (manifest_parser::split_comment (";\n")); + assert (p.first == "" && p.second == ""); + } + + { + auto p (manifest_parser::split_comment ( + "\\;\n\\\\;\n\\\\\\;\n\\\\\\\\;\n\\\\\\\\\\;")); + + assert (p.first == ";\n\\;\n\\;\n\\\\;\n\\\\;" && p.second == ""); + } + // UTF-8. // assert (test (":1\n#\xD0\xB0\n\xD0\xB0y\xD0\xB0:\xD0\xB0z\xD0\xB0", diff --git a/tests/manifest-rewriter/driver.cxx b/tests/manifest-rewriter/driver.cxx index ec73d81..3b1dfe9 100644 --- a/tests/manifest-rewriter/driver.cxx +++ b/tests/manifest-rewriter/driver.cxx @@ -1,36 +1,21 @@ // file : tests/manifest-rewriter/driver.cxx -*- C++ -*- // license : MIT; see accompanying LICENSE file -#include <cassert> - -#ifndef __cpp_lib_modules_ts #include <vector> #include <string> #include <cstdint> // uint64_t #include <utility> // move() #include <iostream> #include <exception> -#endif - -// Other includes. - -#ifdef __cpp_modules_ts -#ifdef __cpp_lib_modules_ts -import std.core; -import std.io; -#endif -import butl.path; -import butl.optional; -import butl.fdstream; -import butl.manifest_parser; -import butl.manifest_rewriter; -#else -#include <libbutl/path.mxx> -#include <libbutl/optional.mxx> -#include <libbutl/fdstream.mxx> -#include <libbutl/manifest-parser.mxx> -#include <libbutl/manifest-rewriter.mxx> -#endif + +#include <libbutl/path.hxx> +#include <libbutl/optional.hxx> +#include <libbutl/fdstream.hxx> +#include <libbutl/manifest-parser.hxx> +#include <libbutl/manifest-rewriter.hxx> + +#undef NDEBUG +#include <cassert> using namespace std; @@ -82,17 +67,26 @@ namespace butl {{"a", "xyz"}, edit_cmd {"x", "y", "c"}, {"e", "123"}}) == ":1\na: xyz\nc:d\nx: y\ne: 123"); - assert (edit (":1\na: b", {{"a", "xy\nz"}}) == ":1\na: \\\nxy\nz\n\\"); + assert (edit (":1\na: b", {{"a", "xy\nz"}}) == ":1\na:\\\nxy\nz\n\\"); + + assert (edit (":1\na:\\\nxy\nz\n\\\nb: c", {{"a", "ab\ncd\ne"}}) == + ":1\na:\\\nab\ncd\ne\n\\\nb: c"); + + assert (edit (":1\na: \\\nxy\nz\n\\\nb: c", {{"a", "ab\ncd\ne"}}) == + ":1\na:\\\nab\ncd\ne\n\\\nb: c"); + + assert (edit (":1\na:\n\\\nxy\nz\n\\\nb: c", {{"a", "ab\ncd\ne"}}) == + ":1\na:\\\nab\ncd\ne\n\\\nb: c"); assert (edit (":1\n", {{"a", "b", ""}}) == ":1\na: b\n"); assert (edit (":1\n abc: b", {{"abc", "xyz"}}) == - ":1\n abc: \\\nxyz\n\\"); + ":1\n abc:\\\nxyz\n\\"); assert (edit (":1\n a\xD0\xB0g : b", {{"a\xD0\xB0g", "xyz"}}) == - ":1\n a\xD0\xB0g : \\\nxyz\n\\"); + ":1\n a\xD0\xB0g :\\\nxyz\n\\"); // Test editing of manifests that contains CR characters. // diff --git a/tests/manifest-roundtrip/buildfile b/tests/manifest-roundtrip/buildfile index 8056f64..7ddcc1f 100644 --- a/tests/manifest-roundtrip/buildfile +++ b/tests/manifest-roundtrip/buildfile @@ -3,5 +3,4 @@ import libs = libbutl%lib{butl} -exe{driver}: {hxx cxx}{*} $libs -exe{driver}: manifest: test.roundtrip = true +exe{driver}: {hxx cxx}{*} $libs testscript diff --git a/tests/manifest-roundtrip/driver.cxx b/tests/manifest-roundtrip/driver.cxx index 53b688e..c63a729 100644 --- a/tests/manifest-roundtrip/driver.cxx +++ b/tests/manifest-roundtrip/driver.cxx @@ -1,45 +1,60 @@ // file : tests/manifest-roundtrip/driver.cxx -*- C++ -*- // license : MIT; see accompanying LICENSE file -#include <cassert> - -#ifndef __cpp_lib_modules_ts #include <string> #include <iostream> -#endif - -// Other includes. - -#ifdef __cpp_modules_ts -#ifdef __cpp_lib_modules_ts -import std.core; -import std.io; -#endif -import butl.utility; // operator<<(ostream, exception) -import butl.fdstream; -import butl.manifest_parser; -import butl.manifest_serializer; -#else -#include <libbutl/utility.mxx> -#include <libbutl/fdstream.mxx> -#include <libbutl/manifest-parser.mxx> -#include <libbutl/manifest-serializer.mxx> -#endif + +#include <libbutl/utility.hxx> // operator<<(ostream, exception) +#include <libbutl/fdstream.hxx> +#include <libbutl/manifest-parser.hxx> +#include <libbutl/manifest-serializer.hxx> + +#undef NDEBUG +#include <cassert> using namespace std; using namespace butl; +// Usage: argv[0] [-m] +// +// Round-trip a manifest reading it from stdin and printing to stdout. +// +// -m +// Serialize multi-line manifest values using the v2 form. +// +// -s +// Split values into the value/comment pairs and merge them back before +// printing. +// int -main () +main (int argc, const char* argv[]) try { + bool multiline_v2 (false); + bool split (false); + + for (int i (1); i != argc; ++i) + { + string v (argv[i]); + + if (v == "-m") + multiline_v2 = true; + else if (v == "-s") + split = true; + } + // Read/write in binary mode. // stdin_fdmode (fdstream_mode::binary); stdout_fdmode (fdstream_mode::binary); manifest_parser p (cin, "stdin"); - manifest_serializer s (cout, "stdout"); + + manifest_serializer s (cout, + "stdout", + false /* long_lines */, + {} /* filter */, + multiline_v2); for (bool eom (true), eos (false); !eos; ) { @@ -53,6 +68,12 @@ try else eom = false; + if (split) + { + const auto& vc (manifest_parser::split_comment (nv.value)); + nv.value = manifest_serializer::merge_comment (vc.first, vc.second); + } + s.next (nv.name, nv.value); } } diff --git a/tests/manifest-roundtrip/manifest b/tests/manifest-roundtrip/manifest deleted file mode 100644 index 23c2730..0000000 --- a/tests/manifest-roundtrip/manifest +++ /dev/null @@ -1,32 +0,0 @@ -: 1 -name: libbpkg -version: 1.0.1 -summary: build2 package manager library -license: MIT -tags: c++, package, manager, bpkg -description: A very very very very very very very very very very very very\ - very very very very very very very very very very very very very very very\ - very very long description. -changes: \ -1.0.1 - - Fixed a very very very very very very very very very very very very very\ - very annoying bug. -1.0.0 - - Firts public release - - Lots of really cool features -\ -url: http://www.codesynthesis.com/projects/libstudxml/ -email: build-users@codesynthesis.com; Public mailing list, posts by\ - non-members are allowed but moderated. -package-email: boris@codesynthesis.com; Direct email to the author. -depends: libbutl -depends: * build2 -depends: ?* bpkg -requires: ?* linux | windows -requires: c++11 -: -path: c:\windows\\ -path: \ - -c:\windows\\ -\ diff --git a/tests/manifest-roundtrip/testscript b/tests/manifest-roundtrip/testscript new file mode 100644 index 0000000..a228b0f --- /dev/null +++ b/tests/manifest-roundtrip/testscript @@ -0,0 +1,118 @@ +# file : tests/manifest-roundtrip/testscript +# license : MIT; see accompanying LICENSE file + +: basics +: +$* <<EOF >>EOF + : 1 + name: libbpkg + version: 1.0.1 + summary: build2 package manager library + license: MIT + tags: c++, package, manager, bpkg + description: A very very very very very very very very very very very very\ + very very very very very very very very very very very very very very very\ + very very long description. + changes:\ + 1.0.1 + - Fixed a very very very very very very very very very very very very very\ + very annoying bug. + 1.0.0 + - Firts public release + - Lots of really cool features + \ + url: http://www.codesynthesis.com/projects/libstudxml/ + email: build-users@codesynthesis.com; Public mailing list, posts by\ + non-members are allowed but moderated. + package-email: boris@codesynthesis.com; Direct email to the author. + depends: libbutl + depends: * build2 + depends: * bpkg + requires: * linux ? ($linux) | windows ? ($windows) + requires: c++11 + : + path: c:\windows\\ + path:\ + + c:\windows\\ + \ + EOF + +: multiline-v2 +: +$* -m <<EOF >>EOF + : 1 + name: libbpkg + version: 1.0.1 + summary: build2 package manager library + license: MIT + tags: c++, package, manager, bpkg + description: A very very very very very very very very very very very very\ + very very very very very very very very very very very very very very very\ + very very long description. + changes: + \ + 1.0.1 + - Fixed a very very very very very very very very very very very very very\ + very annoying bug. + 1.0.0 + - Firts public release + - Lots of really cool features + \ + url: http://www.codesynthesis.com/projects/libstudxml/ + email: build-users@codesynthesis.com; Public mailing list, posts by\ + non-members are allowed but moderated. + package-email: boris@codesynthesis.com; Direct email to the author. + depends: libbutl + depends: * build2 + depends: * bpkg + requires: * linux ? ($linux) | windows ? ($windows) + requires: c++11 + : + path: c:\windows\\ + path: + \ + + c:\windows\\ + \ + EOF + +: split-merge-comment +: +$* -s <<EOF >>EOF + : 1 + info:\ + value + text + \ + info:\ + value + text + ; + comment + \ + info:\ + ; + comment + text + \ + info:\ + value + \; + \\ + ; + comment + \ + info:\ + value + \\; + ; + comment + \ + info:\ + value + \\\\; + ; + comment + \ + EOF diff --git a/tests/manifest-serializer/driver.cxx b/tests/manifest-serializer/driver.cxx index c818b4a..a003fa4 100644 --- a/tests/manifest-serializer/driver.cxx +++ b/tests/manifest-serializer/driver.cxx @@ -1,27 +1,16 @@ // file : tests/manifest-serializer/driver.cxx -*- C++ -*- // license : MIT; see accompanying LICENSE file -#include <cassert> - -#ifndef __cpp_lib_modules_ts #include <vector> #include <string> #include <utility> // pair #include <sstream> #include <iostream> -#endif -// Other includes. +#include <libbutl/manifest-serializer.hxx> -#ifdef __cpp_modules_ts -#ifdef __cpp_lib_modules_ts -import std.core; -import std.io; -#endif -import butl.manifest_serializer; -#else -#include <libbutl/manifest-serializer.mxx> -#endif +#undef NDEBUG +#include <cassert> using namespace std; using namespace butl; @@ -200,21 +189,21 @@ main () // string n ("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); assert (test ({{"","1"},{n,"x"},{"",""},{"",""}}, - ": 1\n" + n + ": \\\nx\n\\\n")); + ": 1\n" + n + ":\\\nx\n\\\n")); assert (test ({{"","1"},{"a","\n"},{"",""},{"",""}}, - ": 1\na: \\\n\n\n\\\n")); + ": 1\na:\\\n\n\n\\\n")); assert (test ({{"","1"},{"a","\n\n"},{"",""},{"",""}}, - ": 1\na: \\\n\n\n\n\\\n")); + ": 1\na:\\\n\n\n\n\\\n")); assert (test ({{"","1"},{"a","\nx\n"},{"",""},{"",""}}, - ": 1\na: \\\n\nx\n\n\\\n")); + ": 1\na:\\\n\nx\n\n\\\n")); assert (test ({{"","1"},{"a","x\ny\nz"},{"",""},{"",""}}, - ": 1\na: \\\nx\ny\nz\n\\\n")); + ": 1\na:\\\nx\ny\nz\n\\\n")); assert (test ({{"","1"},{"a"," x"},{"",""},{"",""}}, - ": 1\na: \\\n x\n\\\n")); + ": 1\na:\\\n x\n\\\n")); assert (test ({{"","1"},{"a","x "},{"",""},{"",""}}, - ": 1\na: \\\nx \n\\\n")); + ": 1\na:\\\nx \n\\\n")); assert (test ({{"","1"},{"a"," x "},{"",""},{"",""}}, - ": 1\na: \\\n x \n\\\n")); + ": 1\na:\\\n x \n\\\n")); // The long lines mode. // @@ -223,51 +212,76 @@ main () true /* long_lines */)); assert (test ({{"","1"},{"a", " abc\n" + l1 + "\ndef"},{"",""},{"",""}}, - ": 1\na: \\\n abc\n" + l1 + "\ndef\n\\\n", + ": 1\na:\\\n abc\n" + l1 + "\ndef\n\\\n", true /* long_lines */)); assert (test ({{"","1"},{n,l1},{"",""},{"",""}}, - ": 1\n" + n + ": \\\n" + l1 + "\n\\\n", + ": 1\n" + n + ":\\\n" + l1 + "\n\\\n", true /* long_lines */)); // Carriage return character. // assert (test ({{"","1"},{"a","x\ry"},{"",""},{"",""}}, - ": 1\na: \\\nx\ny\n\\\n")); + ": 1\na:\\\nx\ny\n\\\n")); assert (test ({{"","1"},{"a","x\r"},{"",""},{"",""}}, - ": 1\na: \\\nx\n\n\\\n")); + ": 1\na:\\\nx\n\n\\\n")); assert (test ({{"","1"},{"a","x\r\ny"},{"",""},{"",""}}, - ": 1\na: \\\nx\ny\n\\\n")); + ": 1\na:\\\nx\ny\n\\\n")); assert (test ({{"","1"},{"a","x\r\n"},{"",""},{"",""}}, - ": 1\na: \\\nx\n\n\\\n")); + ": 1\na:\\\nx\n\n\\\n")); // Extra three x's are for the leading name part ("a: ") that we // don't have. // assert (test ({{"","1"},{"a","\nxxx" + l1},{"",""},{"",""}}, - ": 1\na: \\\n\nxxx" + e1 + "\n\\\n")); + ": 1\na:\\\n\nxxx" + e1 + "\n\\\n")); assert (test ({{"","1"},{"a","\nxxx" + l2},{"",""},{"",""}}, - ": 1\na: \\\n\nxxx" + e2 + "\n\\\n")); + ": 1\na:\\\n\nxxx" + e2 + "\n\\\n")); assert (test ({{"","1"},{"a","\nxxx" + l3},{"",""},{"",""}}, - ": 1\na: \\\n\nxxx" + e3 + "\n\\\n")); + ": 1\na:\\\n\nxxx" + e3 + "\n\\\n")); assert (test ({{"","1"},{"a","\nxxx" + l4},{"",""},{"",""}}, - ": 1\na: \\\n\nxxx" + e4 + "\n\\\n")); + ": 1\na:\\\n\nxxx" + e4 + "\n\\\n")); // Backslash escaping (simple and multi-line). // assert (test ({{"","1"},{"a","c:\\"},{"",""},{"",""}}, ": 1\na: c:\\\\\n")); assert (test ({{"","1"},{"a","c:\\\nd:\\"},{"",""},{"",""}}, - ": 1\na: \\\nc:\\\\\nd:\\\\\n\\\n")); + ": 1\na:\\\nc:\\\\\nd:\\\\\n\\\n")); // Manifest value/comment merging. // - assert (manifest_serializer::merge_comment ("value; text", "comment") == - "value\\; text; comment"); + // Single-line. + // + assert (manifest_serializer::merge_comment ("value\\; text", "comment") == + "value\\\\\\; text; comment"); assert (manifest_serializer::merge_comment ("value text", "") == "value text"); + // Multi-line. + // + assert (manifest_serializer::merge_comment ("value\n;\ntext", "comment") == + "value\n\\;\ntext\n;\ncomment"); + + assert (manifest_serializer::merge_comment ("value\n\\;\ntext\n", + "comment") == + "value\n\\\\;\ntext\n\n;\ncomment"); + + assert (manifest_serializer::merge_comment ("value\n\\\\;\ntext\n", + "comment") == + "value\n\\\\\\\\;\ntext\n\n;\ncomment"); + + + assert (manifest_serializer::merge_comment ("value\n\\\ntext", "comment") == + "value\n\\\ntext\n;\ncomment"); + + assert (manifest_serializer::merge_comment ("\\", "comment\n") == + "\\\n;\ncomment\n"); + + assert (manifest_serializer::merge_comment ("", "comment\ntext") == + ";\ncomment\ntext"); + // Filtering. // assert (test ({{"","1"},{"a","abc"},{"b","bca"},{"c","cab"},{"",""},{"",""}}, diff --git a/tests/move-only-function/buildfile b/tests/move-only-function/buildfile new file mode 100644 index 0000000..9012fd6 --- /dev/null +++ b/tests/move-only-function/buildfile @@ -0,0 +1,6 @@ +# file : tests/move-only-function/buildfile +# license : MIT; see accompanying LICENSE file + +import libs = libbutl%lib{butl} + +exe{driver}: {hxx cxx}{*} $libs diff --git a/tests/move-only-function/driver.cxx b/tests/move-only-function/driver.cxx new file mode 100644 index 0000000..b94d674 --- /dev/null +++ b/tests/move-only-function/driver.cxx @@ -0,0 +1,149 @@ +// file : tests/move-only-function/driver.cxx -*- C++ -*- +// license : MIT; see accompanying LICENSE file + +#include <memory> // unique_ptr +#include <utility> // move() + +#include <libbutl/move-only-function.hxx> + +#undef NDEBUG +#include <cassert> + +using namespace std; + +static int +func (int v) +{ + return v + 1; +} + +struct functor +{ + int i; + + int + operator() (int v) + { + return v + i; + } +}; + +int +main () +{ + using butl::move_only_function_ex; + + // Attempt to copy-construct or copy-assign should not compile. + // Also check non-collable. + // +#if 0 + { + using ft = move_only_function_ex<int (int)>; + ft f; + ft f2 (f); + ft f3; f3 = f; + ft f4 (123); + } +#endif + + // NULL. + // + { + using ft = move_only_function_ex<int (int)>; + + ft f1; + assert (!f1); + + ft f2 (nullptr); + assert (f2 == nullptr); + + f1 = func; + assert (f1 != nullptr); + f1 = nullptr; + assert (!f1); + + int (*f) (int) = nullptr; + f2 = f; + assert (!f2); + } + + // Function. + // + { + using ft = move_only_function_ex<int (int)>; + + ft f (func); + + assert (f (1) == 2); + + ft f1 (move (f)); + assert (!f); + assert (f1 (1) == 2); + + f = &func; + + assert (f (1) == 2); + + assert (f.target<int (*) (int)> () != nullptr); + assert (f1.target<int (*) (int)> () != nullptr); + } + + // Functor. + // + { + using ft = move_only_function_ex<int (int)>; + + ft f (functor {1}); + + assert (f (1) == 2); + + ft f1 (move (f)); + assert (!f); + assert (f1 (1) == 2); + + f = functor {2}; + + assert (f (1) == 3); + + assert (ft (functor {1}).target<functor> () != nullptr); + } + + // Lambda. + // + { + using ft = move_only_function_ex<int (int)>; + + ft f ([p = unique_ptr<int> (new int (1))] (int v) + { + return *p + v; + }); + + assert (f (1) == 2); + + ft f1 (move (f)); + assert (!f); + assert (f1 (1) == 2); + + f = ([p = unique_ptr<int> (new int (2))] (int v) + { + return *p + v; + }); + + assert (f (1) == 3); + } + + // Void result. + // + { + using ft = move_only_function_ex<void (int)>; + + ft f ([] (int v) + { + assert (v == 1); + }); + + f (1); + ft f1 (move (f)); + f1 (1); + } +} diff --git a/tests/mventry/driver.cxx b/tests/mventry/driver.cxx index cb1c348..e895ad6 100644 --- a/tests/mventry/driver.cxx +++ b/tests/mventry/driver.cxx @@ -1,28 +1,15 @@ // file : tests/mventry/driver.cxx -*- C++ -*- // license : MIT; see accompanying LICENSE file -#include <cassert> - -#ifndef __cpp_lib_modules_ts #include <iostream> #include <system_error> -#endif -// Other includes. +#include <libbutl/path.hxx> +#include <libbutl/utility.hxx> // operator<<(ostream, exception) +#include <libbutl/filesystem.hxx> -#ifdef __cpp_modules_ts -#ifdef __cpp_lib_modules_ts -import std.core; -import std.io; -#endif -import butl.path; -import butl.utility; // operator<<(ostream, exception) -import butl.filesystem; -#else -#include <libbutl/path.mxx> -#include <libbutl/utility.mxx> -#include <libbutl/filesystem.mxx> -#endif +#undef NDEBUG +#include <cassert> using namespace std; using namespace butl; diff --git a/tests/mventry/testscript b/tests/mventry/testscript index 61ef871..f52be79 100644 --- a/tests/mventry/testscript +++ b/tests/mventry/testscript @@ -98,16 +98,16 @@ if ($test.target == $build.host) { +if ($cxx.target.class != 'windows') - lnf = ^ln -s t l &l - lnd = $lnf + lnf = [cmdline] ^ln -s t l &l + lnd = [cmdline] $lnf else echo 'yes' >=t if cmd /C 'mklink l t' >- 2>- &?l && cat l >'yes' - lnf = cmd /C 'mklink l t' &l >- - lnd = cmd /C 'mklink /D l t' &l >- + lnf = [cmdline] cmd /C 'mklink l t' &l >- + lnd = [cmdline] cmd /C 'mklink /D l t' &l >- end - jnc = cmd /C 'mklink /J l t' &l >- + jnc = [cmdline] cmd /C 'mklink /J l t' &l >- end : symlink diff --git a/tests/next-word/buildfile b/tests/next-word/buildfile new file mode 100644 index 0000000..e06cd88 --- /dev/null +++ b/tests/next-word/buildfile @@ -0,0 +1,6 @@ +# file : tests/next-word/buildfile +# license : MIT; see accompanying LICENSE file + +import libs = libbutl%lib{butl} + +exe{driver}: {hxx cxx}{*} $libs diff --git a/tests/next-word/driver.cxx b/tests/next-word/driver.cxx new file mode 100644 index 0000000..4ebe1a5 --- /dev/null +++ b/tests/next-word/driver.cxx @@ -0,0 +1,46 @@ +// file : tests/next-word/driver.cxx -*- C++ -*- +// license : MIT; see accompanying LICENSE file + +#include <vector> +#include <string> +//#include <iostream> + +#include <libbutl/utility.hxx> + +#undef NDEBUG +#include <cassert> + +using namespace std; +using namespace butl; + +using strings = vector<string>; + +static strings +parse_lines (const string& s) +{ + strings r; + for (size_t b (0), e (0), m (0), n (s.size ()); + next_word (s, n, b, e, m, '\n', '\r'), b != n; ) + { + //cerr << "'" << string (s, b, e - b) << "'" << endl; + r.push_back (string (s, b, e - b)); + } + return r; +} + +int +main () +{ + assert ((parse_lines("") == strings {})); + assert ((parse_lines("a") == strings {"a"})); + assert ((parse_lines("\n") == strings {"", ""})); + assert ((parse_lines("\n\n") == strings {"", "", ""})); + assert ((parse_lines("\n\n\n") == strings {"", "", "", ""})); + assert ((parse_lines("\na") == strings {"", "a"})); + assert ((parse_lines("\n\na") == strings {"", "", "a"})); + assert ((parse_lines("a\n") == strings {"a", ""})); + assert ((parse_lines("a\n\n") == strings {"a", "", ""})); + assert ((parse_lines("a\nb") == strings {"a", "b"})); + assert ((parse_lines("a\n\nb") == strings {"a", "", "b"})); + assert ((parse_lines("\na\nb\n") == strings {"", "a", "b", ""})); +} diff --git a/tests/odb/buildfile b/tests/odb/buildfile new file mode 100644 index 0000000..c59ab0f --- /dev/null +++ b/tests/odb/buildfile @@ -0,0 +1,6 @@ +# file : tests/odb/buildfile +# license : MIT; see accompanying LICENSE file + +import libs = libbutl%lib{butl-odb} + +exe{driver}: {hxx cxx}{*} $libs diff --git a/tests/odb/driver.cxx b/tests/odb/driver.cxx new file mode 120000 index 0000000..d880fda --- /dev/null +++ b/tests/odb/driver.cxx @@ -0,0 +1 @@ +../../upstream/odb/libodb-sqlite/tests/basics/driver.cxx
\ No newline at end of file diff --git a/tests/openssl/driver.cxx b/tests/openssl/driver.cxx index d245a3a..55f91dd 100644 --- a/tests/openssl/driver.cxx +++ b/tests/openssl/driver.cxx @@ -1,36 +1,18 @@ // file : tests/openssl/driver.cxx -*- C++ -*- // license : MIT; see accompanying LICENSE file -#include <cassert> - -#ifndef __cpp_lib_modules_ts #include <vector> #include <iostream> #include <iterator> #include <system_error> -#endif - -// Other includes. - -#ifdef __cpp_modules_ts -#ifdef __cpp_lib_modules_ts -import std.core; -import std.io; -#endif -import butl.path; -import butl.utility; // operator<<(ostream, exception) -import butl.openssl; -import butl.process; -import butl.fdstream; // nullfd - -import butl.optional; // @@ MOD Clang should not be necessary. -import butl.small_vector; // @@ MOD Clang should not be necessary. -#else -#include <libbutl/path.mxx> -#include <libbutl/utility.mxx> -#include <libbutl/openssl.mxx> -#include <libbutl/fdstream.mxx> -#endif + +#include <libbutl/path.hxx> +#include <libbutl/utility.hxx> // operator<<(ostream, exception) +#include <libbutl/openssl.hxx> +#include <libbutl/fdstream.hxx> // nullfd + +#undef NDEBUG +#include <cassert> using namespace std; using namespace butl; @@ -41,12 +23,28 @@ int main (int, const char* argv[]) try { - openssl os (nullfd, path ("-"), 2, path ("openssl"), "rand", 128); + using butl::optional; + + // Test openssl rand command. + // + { + openssl os (nullfd, path ("-"), 2, path ("openssl"), "rand", 128); + + vector<char> r (os.in.read_binary ()); + os.in.close (); + + assert (os.wait () && r.size () == 128); + } + + // Test openssl info retrieval. + // + { + optional<openssl_info> v (openssl::info (2, path ("openssl"))); - vector<char> r (os.in.read_binary ()); - os.in.close (); + assert (v); + } - return os.wait () && r.size () == 128 ? 0 : 1; + return 0; } catch (const system_error& e) { diff --git a/tests/optional/driver.cxx b/tests/optional/driver.cxx index 5d72f08..da09cf5 100644 --- a/tests/optional/driver.cxx +++ b/tests/optional/driver.cxx @@ -1,23 +1,13 @@ // file : tests/optional/driver.cxx -*- C++ -*- // license : MIT; see accompanying LICENSE file -#include <cassert> - -#ifndef __cpp_lib_modules_ts #include <vector> #include <utility> // move() -#endif - -// Other includes. - -#ifdef __cpp_modules_ts -#ifdef __cpp_lib_modules_ts -import std.core; -#endif -import butl.optional; -#else -#include <libbutl/optional.mxx> -#endif + +#include <libbutl/optional.hxx> + +#undef NDEBUG +#include <cassert> using namespace std; diff --git a/tests/pager/driver.cxx b/tests/pager/driver.cxx index ca3c3b9..c807ed0 100644 --- a/tests/pager/driver.cxx +++ b/tests/pager/driver.cxx @@ -1,28 +1,17 @@ // file : tests/pager/driver.cxx -*- C++ -*- // license : MIT; see accompanying LICENSE file -#include <cassert> - -#ifndef __cpp_lib_modules_ts #include <ios> // ios_base::failure #include <vector> #include <string> #include <utility> // move() #include <sstream> #include <iostream> -#endif - -// Other includes. - -#ifdef __cpp_modules_ts -#ifdef __cpp_lib_modules_ts -import std.core; -import std.io; -#endif -import butl.pager; -#else -#include <libbutl/pager.mxx> -#endif + +#include <libbutl/pager.hxx> + +#undef NDEBUG +#include <cassert> using namespace std; using namespace butl; diff --git a/tests/path-entry/driver.cxx b/tests/path-entry/driver.cxx index 30aae92..d9ea2be 100644 --- a/tests/path-entry/driver.cxx +++ b/tests/path-entry/driver.cxx @@ -1,36 +1,20 @@ // file : tests/path-entry/driver.cxx -*- C++ -*- // license : MIT; see accompanying LICENSE file -#include <cassert> - -#ifndef __cpp_lib_modules_ts #include <string> #include <iostream> #include <stdexcept> // invalid_argument #include <system_error> -#endif - -// Other includes. - -#ifdef __cpp_modules_ts -#ifdef __cpp_lib_modules_ts -import std.core; -import std.io; -#endif -import butl.path; -import butl.path-io; -import butl.utility; // operator<<(ostream, exception) -import butl.optional; -import butl.timestamp; -import butl.filesystem; -#else -#include <libbutl/path.mxx> -#include <libbutl/path-io.mxx> -#include <libbutl/utility.mxx> -#include <libbutl/optional.mxx> -#include <libbutl/timestamp.mxx> -#include <libbutl/filesystem.mxx> -#endif + +#include <libbutl/path.hxx> +#include <libbutl/path-io.hxx> +#include <libbutl/utility.hxx> // operator<<(ostream, exception) +#include <libbutl/optional.hxx> +#include <libbutl/timestamp.hxx> +#include <libbutl/filesystem.hxx> + +#undef NDEBUG +#include <cassert> using namespace std; using namespace butl; diff --git a/tests/path-entry/testscript b/tests/path-entry/testscript index 16039fa..3ac363b 100644 --- a/tests/path-entry/testscript +++ b/tests/path-entry/testscript @@ -57,16 +57,16 @@ if ($test.target == $build.host) { +if ($cxx.target.class != 'windows') - lnf = ^ln -s t l &l - lnd = $lnf + lnf = [cmdline] ^ln -s t l &l + lnd = [cmdline] $lnf else echo 'yes' >=t if cmd /C 'mklink l t' >- 2>- &?l && cat l >'yes' - lnf = cmd /C 'mklink l t' &l >- - lnd = cmd /C 'mklink /D l t' &l >- + lnf = [cmdline] cmd /C 'mklink l t' &l >- + lnd = [cmdline] cmd /C 'mklink /D l t' &l >- end - jnc = cmd /C 'mklink /J l t' &l >- + jnc = [cmdline] cmd /C 'mklink /J l t' &l >- end : symlink diff --git a/tests/path/driver.cxx b/tests/path/driver.cxx index b855e34..3124c13 100644 --- a/tests/path/driver.cxx +++ b/tests/path/driver.cxx @@ -1,27 +1,15 @@ // file : tests/path/driver.cxx -*- C++ -*- // license : MIT; see accompanying LICENSE file -#include <cassert> - -#ifndef __cpp_lib_modules_ts #include <sstream> #include <iostream> #include <type_traits> -#endif -// Other includes. +#include <libbutl/path.hxx> +//#include <libbutl/path-io.hxx> -#ifdef __cpp_modules_ts -#ifdef __cpp_lib_modules_ts -import std.core; -import std.io; -#endif -import butl.path; -//import butl.path_io; -#else -#include <libbutl/path.mxx> -//#include <libbutl/path-io.mxx> -#endif +#undef NDEBUG +#include <cassert> using namespace std; using namespace butl; diff --git a/tests/pkg-config/buildfile b/tests/pkg-config/buildfile new file mode 100644 index 0000000..896b916 --- /dev/null +++ b/tests/pkg-config/buildfile @@ -0,0 +1,6 @@ +# file : tests/pkg-config/buildfile +# license : MIT; see accompanying LICENSE file + +import libs = libbutl%lib{butl-pkg-config} + +exe{driver}: {h c}{*} $libs testscript diff --git a/tests/pkg-config/driver.c b/tests/pkg-config/driver.c new file mode 120000 index 0000000..2e6f14a --- /dev/null +++ b/tests/pkg-config/driver.c @@ -0,0 +1 @@ +../../upstream/libpkg-config/libpkg-config/tests/basic/driver.c
\ No newline at end of file diff --git a/tests/pkg-config/testscript b/tests/pkg-config/testscript new file mode 120000 index 0000000..628bd41 --- /dev/null +++ b/tests/pkg-config/testscript @@ -0,0 +1 @@ +../../upstream/libpkg-config/libpkg-config/tests/basic/testscript
\ No newline at end of file diff --git a/tests/prefix-map/driver.cxx b/tests/prefix-map/driver.cxx index e0da9ea..8ed35ea 100644 --- a/tests/prefix-map/driver.cxx +++ b/tests/prefix-map/driver.cxx @@ -1,24 +1,13 @@ // file : tests/prefix-map/driver.cxx -*- C++ -*- // license : MIT; see accompanying LICENSE file -#include <cassert> - -#ifndef __cpp_lib_modules_ts #include <string> #include <iostream> -#endif - -// Other includes. - -#ifdef __cpp_modules_ts -#ifdef __cpp_lib_modules_ts -import std.core; -import std.io; -#endif -import butl.prefix_map; -#else -#include <libbutl/prefix-map.mxx> -#endif + +#include <libbutl/prefix-map.hxx> + +#undef NDEBUG +#include <cassert> using namespace std; using namespace butl; diff --git a/tests/process-run/driver.cxx b/tests/process-run/driver.cxx index 94b6e00..032f890 100644 --- a/tests/process-run/driver.cxx +++ b/tests/process-run/driver.cxx @@ -1,31 +1,16 @@ // file : tests/process-run/driver.cxx -*- C++ -*- // license : MIT; see accompanying LICENSE file -#include <cassert> - -#ifndef __cpp_lib_modules_ts #include <string> #include <iostream> -#endif - -// Other includes. - -#ifdef __cpp_modules_ts -#ifdef __cpp_lib_modules_ts -import std.core; -import std.io; -#endif -import butl.path; -import butl.process; -import butl.optional; // @@ MOD Clang shouldn't be needed. -import butl.fdstream; -import butl.small_vector; -#else -#include <libbutl/path.mxx> -#include <libbutl/process.mxx> -#include <libbutl/fdstream.mxx> -#include <libbutl/small-vector.mxx> -#endif + +#include <libbutl/path.hxx> +#include <libbutl/process.hxx> +#include <libbutl/fdstream.hxx> +#include <libbutl/small-vector.hxx> + +#undef NDEBUG +#include <cassert> using namespace std; using namespace butl; diff --git a/tests/process-term/buildfile b/tests/process-term/buildfile new file mode 100644 index 0000000..e710179 --- /dev/null +++ b/tests/process-term/buildfile @@ -0,0 +1,6 @@ +# file : tests/process-term/buildfile +# license : MIT; see accompanying LICENSE file + +import libs = libbutl%lib{butl} + +exe{driver}: {hxx cxx}{*} $libs testscript diff --git a/tests/process-term/driver.cxx b/tests/process-term/driver.cxx new file mode 100644 index 0000000..799757c --- /dev/null +++ b/tests/process-term/driver.cxx @@ -0,0 +1,403 @@ +// file : tests/process-term/driver.cxx -*- C++ -*- +// license : MIT; see accompanying LICENSE file + +#ifndef _WIN32 +# include <time.h> +# include <signal.h> +# include <unistd.h> +# include <sys/types.h> +#else +# include <libbutl/win32-utility.hxx> +#endif + +#include <string> +#include <cerrno> // ERANGE +#include <utility> // move() +#include <cstdlib> // atexit(), exit(), strtoull() +#include <cstring> // memset() +#include <cstdint> // uint64_t +#include <iostream> +#ifndef _WIN32 +# include <chrono> +#endif + +#include <libbutl/process.hxx> +#include <libbutl/optional.hxx> +#include <libbutl/fdstream.hxx> + +#undef NDEBUG +#include <cassert> + +using namespace std; +using namespace butl; + +void +atexit_func () +{ + cout << "exiting"; +} + +#ifndef _WIN32 + +volatile sig_atomic_t term_sig = 0; + +static void +term (int sig) +{ + term_sig = sig; +} +#endif + +// Usages: +// +// argv[0] +// argv[0] -s <sec> [-t (ignore|exit|default)] [-e] [-c <num>] +// +// In the first form run some basic process termination tests, running its +// child in the second form. +// +// In the second form optionally register the SIGTERM signal handler +// (POSIX-only) and the atexit function, then sleep for the requested number +// of seconds and exit with the specified status. +// +// -s <sec> +// Sleep for the specified timeout. +// +// -t (ignore|exit|default) +// Register the SIGTERM signal handler. If the signal is received than +// either ignore it, interrupt the sleep and exit, or call the default +// handler. +// +// -e +// Register the function with atexit() that prints the 'exiting' string to +// stdout. +// +// -c <num> +// Exit with the specified status (zero by default). +// +int +main (int argc, const char* argv[]) +{ + using butl::optional; + + 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; + }; + + int ec (0); + optional<uint64_t> sec; + +#ifndef _WIN32 + enum class sig_action + { + ignore, + exit, + default_ + }; + + optional<sig_action> term_action; + + struct sigaction def_handler; +#endif + + for (int i (1); i != argc; ++i) + { + string o (argv[i]); + + if (o == "-s") + { + assert (++i != argc); + sec = num (argv[i]); + } + else if (o == "-c") + { + assert (++i != argc); + ec = static_cast<int> (num (argv[i])); + } + else if (o == "-e") + { + assert (atexit (atexit_func) == 0); + } + else if (o == "-t") + { + assert (++i != argc); + +#ifndef _WIN32 + string v (argv[i]); + + if (v == "ignore") + term_action = sig_action::ignore; + else if (v == "exit") + term_action = sig_action::exit; + else if (v == "default") + term_action = sig_action::default_; + else + assert (false); + + struct sigaction action; + memset (&action, 0, sizeof (action)); + action.sa_handler = term; + assert (sigaction (SIGTERM, &action, &def_handler) == 0); +#endif + } + else + assert (false); + } + +#ifndef _WIN32 + auto sleep = [&term_action, &def_handler] (uint64_t sec) + { + // Wait until timeout expires or SIGTERM is received and is not ignored. + // + for (timespec tm {static_cast<time_t> (sec), 0}; + nanosleep (&tm, &tm) == -1; ) + { + assert (term_action && errno == EINTR && term_sig == SIGTERM); + + if (*term_action == sig_action::ignore) + continue; + + if (*term_action == sig_action::default_) + { + assert (sigaction (term_sig, &def_handler, nullptr) == 0); + kill (getpid (), term_sig); + } + + break; + } + }; +#else + auto sleep = [] (uint64_t sec) + { + Sleep (static_cast<DWORD> (sec) * 1000); + }; +#endif + + // Child process. + // + if (sec) + { + if (*sec != 0) + sleep (*sec); + + return ec; + } + + // Main process. + // + + // Return true if the child process has written the specified string to + // stdout, represented by the reading end of the specified pipe. + // + auto test_out = [] (fdpipe&& pipe, const char* out) + { + pipe.out.close (); + + ifdstream is (move (pipe.in)); + bool r (is.read_text () == out); + is.close (); + return r; + }; + +#ifndef _WIN32 + // Terminate a process with the default SIGTERM handler. + // + { + fdpipe pipe (fdopen_pipe ()); + process p (process_start (0, pipe, 2, argv[0], "-s", 60, "-e")); + + sleep (3); // Give the child some time to initialize. + p.term (); + + assert (test_out (move (pipe), "")); + + assert (!p.wait ()); + assert (p.exit); + assert (!p.exit->normal ()); + assert (p.exit->signal () == SIGTERM); + } + + // Terminate a process that exits on SIGTERM. Make sure it exits normally + // and atexit function is called. + // + { + fdpipe pipe (fdopen_pipe ()); + process p (process_start (0, pipe, 2, + argv[0], "-s", 60, "-t", "exit", "-e", "-c", 5)); + + sleep (3); // Give the child some time to initialize. + p.term (); + + assert (test_out (move (pipe), "exiting")); + + assert (!p.wait ()); + assert (p.exit); + assert (p.exit->normal ()); + assert (p.exit->code () == 5); + } + + // Terminate a process that calls the default handler on SIGTERM. + // + { + fdpipe pipe (fdopen_pipe ()); + process p ( + process_start (0, pipe, 2, + argv[0], "-s", 60, "-t", "default", "-e", "-c", 5)); + + sleep (3); // Give the child some time to initialize. + p.term (); + + assert (test_out (move (pipe), "")); + + assert (!p.wait ()); + assert (p.exit); + assert (!p.exit->normal ()); + assert (p.exit->signal () == SIGTERM); + } + + // Terminate and then kill still running process. + // + { + fdpipe pipe (fdopen_pipe ()); + process p (process_start (0, pipe, 2, + argv[0], "-s", 60, "-t", "ignore", "-e")); + + sleep (3); // Give the child some time to initialize. + p.term (); + + assert (!p.timed_wait (chrono::seconds (1))); + + p.kill (); + + assert (test_out (move (pipe), "")); + + assert (!p.wait ()); + assert (p.exit); + assert (!p.exit->normal ()); + assert (p.exit->signal () == SIGKILL); + } + + // Terminate an already terminated process. + // + { + fdpipe pipe (fdopen_pipe ()); + process p (process_start (0, pipe, 2, argv[0], "-s", 0, "-c", 5)); + + sleep (4); // Give the child some time to terminate. + p.term (); + + assert (test_out (move (pipe), "")); + + assert (!p.wait ()); + assert (p.exit); + assert (p.exit->normal ()); + assert (p.exit->code () == 5); + } + + // Terminate a process being terminated. + // + { + fdpipe pipe (fdopen_pipe ()); + process p (process_start (0, pipe, 2, argv[0], "-s", 60)); + + p.term (); + p.term (); + + assert (test_out (move (pipe), "")); + + assert (!p.wait ()); + assert (p.exit); + assert (!p.exit->normal ()); + } + + // Kill a process being terminated. + // + { + fdpipe pipe (fdopen_pipe ()); + process p (process_start (0, pipe, 2, argv[0], "-s", 60)); + + p.term (); + p.kill (); + + assert (test_out (move (pipe), "")); + + assert (!p.wait ()); + assert (p.exit); + assert (!p.exit->normal ()); + assert (p.exit->signal () == SIGTERM || p.exit->signal () == SIGKILL); + } + + // Kill a process being killed. + // + { + fdpipe pipe (fdopen_pipe ()); + process p (process_start (0, pipe, 2, argv[0], "-s", 60)); + + p.kill (); + p.kill (); + + assert (test_out (move (pipe), "")); + + assert (!p.wait ()); + assert (p.exit); + assert (!p.exit->normal ()); + } +#endif + + // Terminate and wait a process. + // + { + fdpipe pipe (fdopen_pipe ()); + process p (process_start (0, pipe, 2, argv[0], "-s", 60, "-e")); + + sleep (3); // Give the child some time to initialize. + p.term (); + + assert (test_out (move (pipe), "")); + + assert (!p.wait ()); + assert (p.exit); + assert (!p.exit->normal ()); + } + + // Kill and wait a process. + // + { + fdpipe pipe (fdopen_pipe ()); + process p (process_start (0, pipe, 2, argv[0], "-s", 60, "-e")); + + sleep (3); // Give the child some time to initialize. + p.kill (); + + assert (test_out (move (pipe), "")); + + assert (!p.wait ()); + assert (p.exit); + assert (!p.exit->normal ()); + } + + // Kill a terminated process. + // + { + fdpipe pipe (fdopen_pipe ()); + process p (process_start (0, pipe, 2, argv[0], "-s", 0, "-c", 5)); + + sleep (4); // Give the child some time to terminate. + p.kill (); + + assert (test_out (move (pipe), "")); + + assert (!p.wait ()); + assert (p.exit); + assert (p.exit->normal ()); + assert (p.exit->code () == 5); + } +} diff --git a/tests/process-term/testscript b/tests/process-term/testscript new file mode 100644 index 0000000..f61899c --- /dev/null +++ b/tests/process-term/testscript @@ -0,0 +1,4 @@ +# file : tests/process-term/testscript +# license : MIT; see accompanying LICENSE file + +$* diff --git a/tests/process/driver.cxx b/tests/process/driver.cxx index 3be4154..1ee5710 100644 --- a/tests/process/driver.cxx +++ b/tests/process/driver.cxx @@ -1,44 +1,29 @@ // file : tests/process/driver.cxx -*- C++ -*- // license : MIT; see accompanying LICENSE file -#include <cassert> - -#ifndef __cpp_lib_modules_ts #include <ios> #include <string> #include <vector> +#include <chrono> #include <sstream> #include <iterator> // istreambuf_iterator, ostream_iterator #include <algorithm> // copy() #include <iostream> -#endif -// Other includes. +#include <libbutl/path.hxx> +#include <libbutl/utility.hxx> // setenv(), getenv() +#include <libbutl/process.hxx> +#include <libbutl/process-io.hxx> +#include <libbutl/optional.hxx> +#include <libbutl/fdstream.hxx> +#include <libbutl/timestamp.hxx> -#ifdef __cpp_modules_ts -#ifdef __cpp_lib_modules_ts -import std.core; -import std.io; -#endif -import butl.path; -import butl.utility; // setenv(), getenv() -import butl.process; -import butl.optional; -import butl.fdstream; -#else -#include <libbutl/path.mxx> -#include <libbutl/utility.mxx> -#include <libbutl/process.mxx> -#include <libbutl/process-io.mxx> -#include <libbutl/optional.mxx> -#include <libbutl/fdstream.mxx> -#endif +#undef NDEBUG +#include <cassert> using namespace std; using namespace butl; -static const char* envvars[] = {"ABC=1", "DEF", nullptr}; - using cstrings = vector<const char*>; bool @@ -91,18 +76,16 @@ exec (const path& p, if (bin) args.push_back ("-b"); + const char* evars[] = { + "PAR1", "PAR2=2P", "PAR6=66", "PAR7", // Override the process variables. + "THR1", "THR2=2T", // Override the thread variables. + "CHD1", // Unset a non-existing variable. + "CHD2=C2", // Add the new variable. + nullptr}; + if (env) - { args.push_back ("-e"); - // Here we set the environment variables for the current process to make - // sure that the child process will not see the variable that is requested - // to be unset, and will see the other one unaffected. - // - setenv ("DEF", "2"); - setenv ("XYZ", "3"); - } - if (cwd != nullptr) args.push_back (cwd); @@ -120,7 +103,7 @@ exec (const path& p, out ? -1 : -2, err ? (out ? 1 : -1) : -2, cwd, - env ? envvars : nullptr); + env ? evars : nullptr); try { @@ -154,18 +137,21 @@ exec (const path& p, process pr3 (args.data (), -1, -1, -2, cwd, - env ? envvars : nullptr); + env ? evars : nullptr); process pr2 (args.data (), pr, bin_mode (move (pr3.out_fd)).get (), -2, cwd, - env ? envvars : nullptr); + env ? evars : nullptr); ifdstream is (bin_mode (move (pr3.in_ofd))); o = is.read_binary (); - r = pr2.wait () && r; - r = pr3.wait () && r; + // While at it, make sure that the process::timed_wait() template + // function overloads can be properly instantiated/linked. + // + r = pr2.timed_wait (duration::max ()) && r; + r = pr3.timed_wait (chrono::milliseconds::max ()) && r; } else { @@ -323,12 +309,23 @@ main (int argc, const char* argv[]) if (env) { - // Check that the ABC variable is set, the DEF is unset and the XYZ is - // left unchanged. + // Check that the variables are (un)set as expected. // - if (getenv ("ABC") != optional<string> ("1") || - getenv ("DEF") || - getenv ("XYZ") != optional<string> ("3")) + if (getenv ("PAR1") || + getenv ("PAR2") != optional<string> ("2P") || + getenv ("PAR3") != optional<string> ("P3") || + getenv ("PAR4") || + getenv ("PAR5") != optional<string> ("5P") || + getenv ("PAR6") != optional<string> ("66") || + getenv ("PAR7") || + + getenv ("THR1") || + getenv ("THR2") != optional<string> ("2T") || + getenv ("THR3") != optional<string> ("T3") || + getenv ("THR4") || + + getenv ("CHD1") || + getenv ("CHD2") != optional<string> ("C2")) return 1; } @@ -358,6 +355,26 @@ main (int argc, const char* argv[]) return 0; } + // Here we set the process and thread environment variables to make sure + // that the child process will not see the variables that are requested to + // be unset, will see change for the variables that are requested to be set, + // and will see the other ones unaffected. + // + setenv ("PAR1", "P1"); + setenv ("PAR2", "P2"); + setenv ("PAR3", "P3"); + setenv ("PAR4", "P4"); + setenv ("PAR5", "P5"); + setenv ("PAR6", "P6"); + setenv ("PAR7", "P7"); + + const char* tevars[] = { + "THR1=T1", "THR2=T2", "THR3=T3", "THR4", + "PAR4", "PAR5=5P", "PAR6", "PAR7=7P", // Override the process variables. + nullptr}; + + auto_thread_env ate (tevars); + dir_path owd (dir_path::current_directory ()); // Test processes created as "already terminated". diff --git a/tests/progress/driver.cxx b/tests/progress/driver.cxx index 2a0b647..f1a257c 100644 --- a/tests/progress/driver.cxx +++ b/tests/progress/driver.cxx @@ -8,38 +8,19 @@ # include <io.h> //_write() #endif -#include <cassert> - -#ifndef __cpp_lib_modules_ts #include <string> #include <cstddef> // size_t #include <iostream> #ifndef _WIN32 # include <thread> // this_thread::sleep_for() #endif -#endif -// Other includes. - -#ifdef __cpp_modules_ts -#ifdef __cpp_lib_modules_ts -import std.core; -import std.io; -#ifndef _WIN32 -import std.threading; -#endif -#endif -import butl.process; -import butl.fdstream; -import butl.diagnostics; +#include <libbutl/process.hxx> +#include <libbutl/fdstream.hxx> // fdopen_null(), stderr_fd() +#include <libbutl/diagnostics.hxx> -import butl.optional; // @@ MOD Clang should not be necessary. -import butl.small_vector; // @@ MOD Clang should not be necessary. -#else -#include <libbutl/process.mxx> -#include <libbutl/fdstream.mxx> // fdopen_null(), stderr_fd() -#include <libbutl/diagnostics.mxx> -#endif +#undef NDEBUG +#include <cassert> using namespace std; using namespace butl; diff --git a/tests/project-name/driver.cxx b/tests/project-name/driver.cxx index 02b3ae3..ac1c898 100644 --- a/tests/project-name/driver.cxx +++ b/tests/project-name/driver.cxx @@ -1,28 +1,17 @@ // file : tests/project-name/driver.cxx -*- C++ -*- // license : MIT; see accompanying LICENSE file -#include <cassert> - -#ifndef __cpp_lib_modules_ts #include <ios> // ios::*bit #include <string> #include <iostream> #include <stdexcept> // invalid_argument -#endif - -// Other includes. - -#ifdef __cpp_modules_ts -#ifdef __cpp_lib_modules_ts -import std.core; -import std.io; -#endif -import butl.utility; // operator<<(ostream,exception), eof(), *case() -import butl.project_name; -#else -#include <libbutl/utility.mxx> -#include <libbutl/project-name.mxx> -#endif + +#include <libbutl/utility.hxx> // operator<<(ostream,exception), eof(), + // *case() +#include <libbutl/project-name.hxx> + +#undef NDEBUG +#include <cassert> using namespace std; using namespace butl; diff --git a/tests/regex/driver.cxx b/tests/regex/driver.cxx index f78a100..f8363e1 100644 --- a/tests/regex/driver.cxx +++ b/tests/regex/driver.cxx @@ -1,33 +1,23 @@ // file : tests/regex/driver.cxx -*- C++ -*- // license : MIT; see accompanying LICENSE file -#include <cassert> - -#ifndef __cpp_lib_modules_ts +#include <regex> #include <string> +#include <utility> // pair #include <iostream> +#include <stdexcept> // invalid_argument #include <exception> -#endif -// Other includes. +#include <libbutl/regex.hxx> +#include <libbutl/utility.hxx> // operator<<(ostream, exception) -#ifdef __cpp_modules_ts -#ifdef __cpp_lib_modules_ts -import std.core; -import std.io; -import std.regex; // @@ MOD TODO: shouldn't be necessary (re-export). -#endif -import butl.regex; -import butl.utility; // operator<<(ostream, exception) -#else -#include <libbutl/regex.mxx> -#include <libbutl/utility.mxx> -#endif +#undef NDEBUG +#include <cassert> using namespace std; using namespace butl; -// Usage: argv[0] [-ffo] [-fnc] [-m] <string> <regex> <format> +// Usage: argv[0] [-ffo] [-fnc] [-m] <string> "/<regex>/<format>/" // // Perform substitution of matched substrings with formatted replacement // strings using regex_replace_*() functions. If the string matches the regex @@ -66,11 +56,13 @@ try break; } - assert (i + 3 == argc); + assert (i + 2 == argc); + + string s (argv[i++]); + pair<regex, string> rf (regex_replace_parse (argv[i])); - string s (argv[i++]); - regex re (argv[i++]); - string fmt (argv[i]); + const regex& re (rf.first); + const string& fmt (rf.second); auto r (match ? regex_replace_match (s, re, fmt) @@ -86,8 +78,13 @@ catch (const regex_error& e) cerr << "invalid regex" << e << endl; // Print sanitized. return 2; } -catch (const exception& e) +catch (const invalid_argument& e) { cerr << e << endl; return 2; } +catch (const exception&) +{ + assert (false); + return 2; +} diff --git a/tests/regex/testscript b/tests/regex/testscript index fbee1d6..93ad4b6 100644 --- a/tests/regex/testscript +++ b/tests/regex/testscript @@ -4,38 +4,38 @@ : replace-search : { - $* abcbd b x >axcxd : all - $* -ffo abcbd b x >axcbd : first-only - $* -fnc abcbd b x >xx : no-copy + $* abcbd /b/x/ >axcxd : all + $* -ffo abcbd /b/x/ >axcbd : first-only + $* -fnc abcbd /b/x/ >xx : no-copy : ecma-escape : { - $* xay a '$b' >'x$by' : none - $* xay a '$' >'x$y' : none-term - $* xay a '$$' >'x$y' : self - $* xay a 'b$&c' >'xbacy' : match - $* xay a 'b$`c' >'xbxcy' : match-precede - $* xay a "b\\\$'c" >'xbycy' : match-follow + $* xay '/a/$b/' >'x$by' : none + $* xay '/a/$/' >'x$y' : none-term + $* xay '/a/$$/' >'x$y' : self + $* xay '/a/b$&c/' >'xbacy' : match + $* xay '/a/b$`c/' >'xbxcy' : match-precede + $* xay "/a/b\\\$'c/" >'xbycy' : match-follow : capture : { - $* abcdefghij '(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)' '$1$10' >aj : matched - $* a '(a)|(b)' '$1$2$3' >a : unmatched + $* abcdefghij '/(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)/$1$10/' >aj : matched + $* a '/(a)|(b)/$1$2$3/' >a : unmatched } } : perl-escape : { - $* xay a '\b' >'xby' : none - $* xay a '\' >'xy' : none-term - $* xay a '\\' >'x\y' : self + $* xay '/a/\b/' >'xby' : none + $* xay '/a/\/' >'xy' : none-term + $* xay '/a/\\/' >'x\y' : self : newline : - $* xay a '\n' >>EOO + $* xay '/a/\n/' >>EOO x y EOO @@ -43,25 +43,25 @@ : capture : { - $* abcdefghij '(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)' '\1\10' >aa0 : matched - $* a '(a)|(b)' '\1\2\3' >a : unmatched + $* abcdefghij '/(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)/\1\10/' >aa0 : matched + $* a '/(a)|(b)/\1\2\3/' >a : unmatched } : upper : { - $* xay a '\U' >xy : none - $* xay a '\Uvz' >xVZy : repl - $* xay a '\Uv\Ez' >xVzy : end - $* aa a 'v\Uz' >vZvZ : locality - $* xay '(a)' '\U\1' >xAy : capt - $* x-y '(a?)-' '\U\1z' >xZy : capt-empty - $* xay a '\uvz' >xVzy : once + $* xay '/a/\U/' >xy : none + $* xay '/a/\Uvz/' >xVZy : repl + $* xay '/a/\Uv\Ez/' >xVzy : end + $* aa '/a/v\Uz/' >vZvZ : locality + $* xay '/(a)/\U\1/' >xAy : capt + $* x-y '/(a?)-/\U\1z/' >xZy : capt-empty + $* xay '/a/\uvz/' >xVzy : once } : lower : - $* xay a '\lVZ' >xvZy + $* xay '/a/\lVZ/' >xvZy } } @@ -70,6 +70,19 @@ { test.options += -m - $* abc 'a(b)c' 'x\1y' >xby : match - $* abcd 'a(b)c' 'x\1yd' == 1 : no-match + $* abc '/a(b)c/x\1y/' >xby : match + $* abcd '/a(b)c/x\1yd/' == 1 : no-match +} + +: invalid-regex-fmt +: +{ + test.arguments += '' # Note: we will fail before the matching. + + $* '' 2> 'no leading delimiter' != 0 : no-leading-delim + $* '/a' 2> 'no delimiter after regex' != 0 : no-mid-delim + $* '//' 2> 'empty regex' != 0 : no-regex + $* '/a[b/c/' 2>~'/invalid regex.*/' != 0 : regex + $* '/a/b' 2> 'no delimiter after replacement' != 0 : no-trailing-delim + $* '/a/b/s' 2> 'junk after trailing delimiter' != 0 : junk } diff --git a/tests/semantic-version/driver.cxx b/tests/semantic-version/driver.cxx index 032cb14..3c20a6c 100644 --- a/tests/semantic-version/driver.cxx +++ b/tests/semantic-version/driver.cxx @@ -1,23 +1,12 @@ // file : tests/semantic-version/driver.cxx -*- C++ -*- // license : MIT; see accompanying LICENSE file -#include <cassert> - -#ifndef __cpp_lib_modules_ts #include <iostream> -#endif -// Other includes. +#include <libbutl/semantic-version.hxx> -#ifdef __cpp_modules_ts -#ifdef __cpp_lib_modules_ts -import std.core; -import std.io; -#endif -import butl.semantic_version; -#else -#include <libbutl/semantic-version.mxx> -#endif +#undef NDEBUG +#include <cassert> using namespace std; using namespace butl; @@ -34,7 +23,6 @@ main () semver v; assert (v.major == 0 && v.minor == 0 && v.patch == 0 && v.build.empty ()); } - { semver v (1, 2, 3); assert (v.major == 1 && v.minor == 2 && v.patch == 3 && v.build.empty ()); @@ -57,17 +45,27 @@ main () // String representation. // - assert (semver ("1.2") == semver (1, 2, 0)); - assert (semver ("1.2-3") == semver (1, 2, 0, "-3")); - assert (semver ("1.2.a1", "+-.") == semver (1, 2, 0, ".a1")); - assert (semver ("1.2.3") == semver (1, 2, 3)); - assert (semver ("1.2.3-4") == semver (1, 2, 3, "-4")); - assert (semver ("1.2.3+4") == semver (1, 2, 3, "+4")); - assert (semver ("1.2.3.4", "+-.") == semver (1, 2, 3, ".4")); - assert (semver ("1.2.3a", "") == semver (1, 2, 3, "a")); - try {semver v ("1.2.3-4", false); assert (false);} catch (failed) {} - try {semver v ("1.2.3.4"); assert (false);} catch (failed) {} - try {semver v ("1.2.3a"); assert (false);} catch (failed) {} + assert (semver ("1", semver::allow_omit_minor) == semver (1, 0, 0)); + assert (semver ("1-2", semver::allow_omit_minor | semver::allow_build) == semver (1, 0, 0, "-2")); + assert (semver ("1.2", semver::allow_omit_minor) == semver (1, 2, 0)); + assert (semver ("1.2+a", semver::allow_omit_minor | semver::allow_build) == semver (1, 2, 0, "+a")); + assert (semver ("1.2", semver::allow_omit_patch) == semver (1, 2, 0)); + assert (semver ("1.2-3", semver::allow_omit_patch | semver::allow_build) == semver (1, 2, 0, "-3")); + assert (semver ("1.2.a1", semver::allow_omit_patch | semver::allow_build, ".+-") == semver (1, 2, 0, ".a1")); + assert (semver ("1.2.3") == semver (1, 2, 3)); + assert (semver ("1.2.3-4", semver::allow_build) == semver (1, 2, 3, "-4")); + assert (semver ("1.2.3+4", semver::allow_build) == semver (1, 2, 3, "+4")); + assert (semver ("1.2.3.4", semver::allow_build, "+-.") == semver (1, 2, 3, ".4")); + assert (semver ("1.2.3a", semver::allow_build, "") == semver (1, 2, 3, "a")); + + try {semver v ("1"); assert (false);} catch (failed) {} + try {semver v ("1.x.2"); assert (false);} catch (failed) {} + try {semver v ("1.2"); assert (false);} catch (failed) {} + try {semver v ("1.2.x"); assert (false);} catch (failed) {} + try {semver v ("1.2.3-4"); assert (false);} catch (failed) {} + try {semver v ("1.2.3.4"); assert (false);} catch (failed) {} + try {semver v ("1.2.3a"); assert (false);} catch (failed) {} + assert (!parse_semantic_version ("1.2.3.4")); // Numeric representation. diff --git a/tests/sendmail/driver.cxx b/tests/sendmail/driver.cxx index e73940b..3b97202 100644 --- a/tests/sendmail/driver.cxx +++ b/tests/sendmail/driver.cxx @@ -1,34 +1,16 @@ // file : tests/sendmail/driver.cxx -*- C++ -*- // license : MIT; see accompanying LICENSE file -#include <cassert> - -#ifndef __cpp_lib_modules_ts #include <iostream> #include <system_error> -#endif - -// Other includes. - -#ifdef __cpp_modules_ts -#ifdef __cpp_lib_modules_ts -import std.core; -import std.io; -#endif -import butl.path; -import butl.process; -import butl.utility; // operator<<(ostream, exception) -import butl.sendmail; -import butl.fdstream; - -import butl.optional; // @@ MOD Clang should not be necessary. -import butl.small_vector; // @@ MOD Clang should not be necessary. -#else -#include <libbutl/path.mxx> -#include <libbutl/process.mxx> -#include <libbutl/utility.mxx> -#include <libbutl/sendmail.mxx> -#endif + +#include <libbutl/path.hxx> +#include <libbutl/process.hxx> +#include <libbutl/utility.hxx> // operator<<(ostream, exception) +#include <libbutl/sendmail.hxx> + +#undef NDEBUG +#include <cassert> using namespace std; using namespace butl; diff --git a/tests/sha1/driver.cxx b/tests/sha1/driver.cxx index 2b58113..1e8e254 100644 --- a/tests/sha1/driver.cxx +++ b/tests/sha1/driver.cxx @@ -1,29 +1,16 @@ // file : tests/sha1/driver.cxx -*- C++ -*- // license : MIT; see accompanying LICENSE file -#include <cassert> - -#ifndef __cpp_lib_modules_ts #include <string> #include <cstddef> // size_t -#endif - -// Other includes. - -#ifdef __cpp_modules_ts -#ifdef __cpp_lib_modules_ts -import std.core; -#endif -import butl.sha1; -import butl.path; -import butl.fdstream; -import butl.filesystem; -#else -#include <libbutl/sha1.mxx> -#include <libbutl/path.mxx> -#include <libbutl/fdstream.mxx> -#include <libbutl/filesystem.mxx> // auto_rmfile -#endif + +#include <libbutl/sha1.hxx> +#include <libbutl/path.hxx> +#include <libbutl/fdstream.hxx> +#include <libbutl/filesystem.hxx> // auto_rmfile + +#undef NDEBUG +#include <cassert> using namespace std; using namespace butl; diff --git a/tests/sha256/driver.cxx b/tests/sha256/driver.cxx index 2946755..30dfa49 100644 --- a/tests/sha256/driver.cxx +++ b/tests/sha256/driver.cxx @@ -1,29 +1,16 @@ // file : tests/sha256/driver.cxx -*- C++ -*- // license : MIT; see accompanying LICENSE file -#include <cassert> - -#ifndef __cpp_lib_modules_ts #include <string> #include <cstddef> // size_t -#endif - -// Other includes. - -#ifdef __cpp_modules_ts -#ifdef __cpp_lib_modules_ts -import std.core; -#endif -import butl.path; -import butl.sha256; -import butl.fdstream; -import butl.filesystem; -#else -#include <libbutl/path.mxx> -#include <libbutl/sha256.mxx> -#include <libbutl/fdstream.mxx> -#include <libbutl/filesystem.mxx> // auto_rmfile -#endif + +#include <libbutl/path.hxx> +#include <libbutl/sha256.hxx> +#include <libbutl/fdstream.hxx> +#include <libbutl/filesystem.hxx> // auto_rmfile + +#undef NDEBUG +#include <cassert> using namespace std; using namespace butl; diff --git a/tests/small-forward-list/driver.cxx b/tests/small-forward-list/driver.cxx index 670fff1..1cfea77 100644 --- a/tests/small-forward-list/driver.cxx +++ b/tests/small-forward-list/driver.cxx @@ -1,24 +1,13 @@ // file : tests/small-forward-list/driver.cxx -*- C++ -*- // license : MIT; see accompanying LICENSE file -#include <cassert> - -#ifndef __cpp_lib_modules_ts #include <string> #include <iostream> -#endif - -// Other includes. - -#ifdef __cpp_modules_ts -#ifdef __cpp_lib_modules_ts -import std.core; -import std.io; -#endif -import butl.small_forward_list; -#else -#include <libbutl/small-forward-list.mxx> -#endif + +#include <libbutl/small-forward-list.hxx> + +#undef NDEBUG +#include <cassert> using namespace std; using namespace butl; diff --git a/tests/small-list/driver.cxx b/tests/small-list/driver.cxx index 9674402..8e2fb6e 100644 --- a/tests/small-list/driver.cxx +++ b/tests/small-list/driver.cxx @@ -1,24 +1,13 @@ // file : tests/small-list/driver.cxx -*- C++ -*- // license : MIT; see accompanying LICENSE file -#include <cassert> - -#ifndef __cpp_lib_modules_ts #include <string> #include <iostream> -#endif -// Other includes. +#include <libbutl/small-list.hxx> -#ifdef __cpp_modules_ts -#ifdef __cpp_lib_modules_ts -import std.core; -import std.io; -#endif -import butl.small_list; -#else -#include <libbutl/small-list.mxx> -#endif +#undef NDEBUG +#include <cassert> using namespace std; using namespace butl; diff --git a/tests/small-vector/driver.cxx b/tests/small-vector/driver.cxx index d79a03b..cc012fc 100644 --- a/tests/small-vector/driver.cxx +++ b/tests/small-vector/driver.cxx @@ -1,24 +1,13 @@ // file : tests/small-vector/driver.cxx -*- C++ -*- // license : MIT; see accompanying LICENSE file -#include <cassert> - -#ifndef __cpp_lib_modules_ts #include <string> #include <iostream> -#endif -// Other includes. +#include <libbutl/small-vector.hxx> -#ifdef __cpp_modules_ts -#ifdef __cpp_lib_modules_ts -import std.core; -import std.io; -#endif -import butl.small_vector; -#else -#include <libbutl/small-vector.mxx> -#endif +#undef NDEBUG +#include <cassert> using namespace std; using namespace butl; @@ -111,6 +100,7 @@ main () s1.emplace_back ("abc"); vector s2 (move (s1)); assert (s2[0] == "abc" && s2.capacity () == 2 && small (s2)); + assert (s1.empty ()); // The source vector must be empty now. } { diff --git a/tests/standard-version/driver.cxx b/tests/standard-version/driver.cxx index 4b985e1..4bddf08 100644 --- a/tests/standard-version/driver.cxx +++ b/tests/standard-version/driver.cxx @@ -1,31 +1,18 @@ // file : tests/standard-version/driver.cxx -*- C++ -*- // license : MIT; see accompanying LICENSE file -#include <cassert> - -#ifndef __cpp_lib_modules_ts #include <ios> // ios::failbit, ios::badbit #include <string> #include <cstdint> // uint*_t #include <iostream> #include <stdexcept> // invalid_argument -#endif - -// Other includes. - -#ifdef __cpp_modules_ts -#ifdef __cpp_lib_modules_ts -import std.core; -import std.io; -#endif -import butl.utility; // operator<<(ostream,exception), eof() -import butl.optional; -import butl.standard_version; -#else -#include <libbutl/utility.mxx> -#include <libbutl/optional.mxx> -#include <libbutl/standard-version.mxx> -#endif + +#include <libbutl/utility.hxx> // operator<<(ostream,exception), eof() +#include <libbutl/optional.hxx> +#include <libbutl/standard-version.hxx> + +#undef NDEBUG +#include <cassert> using namespace std; using namespace butl; @@ -96,7 +83,7 @@ version (const string& s, if (v.minor () != 99999) { - standard_version_constraint c1 ("~" + s); + standard_version_constraint c1 ('~' + s); standard_version_constraint c2 ('[' + s + ' ' + max_ver ('~') + ')'); assert (c1 == c2); } @@ -104,7 +91,7 @@ version (const string& s, if ((v.major () == 0 && v.minor () != 99999) || (v.major () != 0 && v.major () != 99999)) { - standard_version_constraint c1 ("^" + s); + standard_version_constraint c1 ('^' + s); standard_version_constraint c2 ('[' + s + ' ' + max_ver ('^') + ')'); assert (c1 == c2); } diff --git a/tests/strcase/driver.cxx b/tests/strcase/driver.cxx index f9ea3b6..8e964a6 100644 --- a/tests/strcase/driver.cxx +++ b/tests/strcase/driver.cxx @@ -1,22 +1,12 @@ // file : tests/strcase/driver.cxx -*- C++ -*- // license : MIT; see accompanying LICENSE file -#include <cassert> - -#ifndef __cpp_lib_modules_ts #include <string> -#endif -// Other includes. +#include <libbutl/utility.hxx> -#ifdef __cpp_modules_ts -#ifdef __cpp_lib_modules_ts -import std.core; -#endif -import butl.utility; -#else -#include <libbutl/utility.mxx> -#endif +#undef NDEBUG +#include <cassert> using namespace std; using namespace butl; diff --git a/tests/string-parser/driver.cxx b/tests/string-parser/driver.cxx index 4e4984e..8cba912 100644 --- a/tests/string-parser/driver.cxx +++ b/tests/string-parser/driver.cxx @@ -1,27 +1,15 @@ // file : tests/string-parser/driver.cxx -*- C++ -*- // license : MIT; see accompanying LICENSE file -#include <cassert> - -#ifndef __cpp_lib_modules_ts #include <string> #include <vector> #include <iostream> -#endif - -// Other includes. - -#ifdef __cpp_modules_ts -#ifdef __cpp_lib_modules_ts -import std.core; -import std.io; -#endif -import butl.utility; // operator<<(ostream,exception) -import butl.string_parser; -#else -#include <libbutl/utility.mxx> -#include <libbutl/string-parser.mxx> -#endif + +#include <libbutl/utility.hxx> // operator<<(ostream,exception) +#include <libbutl/string-parser.hxx> + +#undef NDEBUG +#include <cassert> using namespace std; using namespace butl::string_parser; diff --git a/tests/tab-parser/driver.cxx b/tests/tab-parser/driver.cxx index 5a527cf..99c19d9 100644 --- a/tests/tab-parser/driver.cxx +++ b/tests/tab-parser/driver.cxx @@ -1,26 +1,14 @@ // file : tests/tab-parser/driver.cxx -*- C++ -*- // license : MIT; see accompanying LICENSE file -#include <cassert> - -#ifndef __cpp_lib_modules_ts #include <string> #include <iostream> -#endif -// Other includes. +#include <libbutl/utility.hxx> // operator<<(ostream,exception) +#include <libbutl/tab-parser.hxx> -#ifdef __cpp_modules_ts -#ifdef __cpp_lib_modules_ts -import std.core; -import std.io; -#endif -import butl.utility; // operator<<(ostream,exception) -import butl.tab_parser; -#else -#include <libbutl/utility.mxx> -#include <libbutl/tab-parser.mxx> -#endif +#undef NDEBUG +#include <cassert> using namespace std; using namespace butl; diff --git a/tests/target-triplet/driver.cxx b/tests/target-triplet/driver.cxx index 0bb305e..8c08a90 100644 --- a/tests/target-triplet/driver.cxx +++ b/tests/target-triplet/driver.cxx @@ -1,25 +1,14 @@ // file : tests/target-triplet/driver.cxx -*- C++ -*- // license : MIT; see accompanying LICENSE file -#include <cassert> - -#ifndef __cpp_lib_modules_ts #include <string> #include <iostream> #include <stdexcept> // invalid_argument -#endif -// Other includes. +#include <libbutl/target-triplet.hxx> -#ifdef __cpp_modules_ts -#ifdef __cpp_lib_modules_ts -import std.core; -import std.io; -#endif -import butl.target_triplet; -#else -#include <libbutl/target-triplet.mxx> -#endif +#undef NDEBUG +#include <cassert> using namespace std; using namespace butl; @@ -61,6 +50,14 @@ main () "arm-eabi", "arm", "", "eabi", "")); + assert (test ("arm-unknown-none-eabi", + "arm-none-eabi", + "arm", "", "none-eabi", "")); + + assert (test ("arm-none", + "arm-none", + "arm", "", "none", "")); + assert (test ("arm-none-linux-gnueabi", "arm-linux-gnueabi", "arm", "", "linux-gnueabi", "", "linux")); @@ -77,6 +74,10 @@ main () "i686-w64-mingw32", "i686", "w64", "mingw32", "", "windows")); + assert (test ("x86_64-w64-windows-gnu", + "x86_64-w64-mingw32", + "x86_64", "w64", "mingw32", "", "windows")); + assert (test ("i686-lfs-linux-gnu", "i686-lfs-linux-gnu", "i686", "lfs", "linux-gnu", "", "linux")); @@ -85,6 +86,10 @@ main () "x86_64-linux-gnu", "x86_64", "", "linux-gnu", "", "linux")); + assert (test ("x86_64-redhat-linux", + "x86_64-redhat-linux-gnu", + "x86_64", "redhat", "linux-gnu", "", "linux")); + assert (test ("x86_64-linux-gnux32", "x86_64-linux-gnux32", "x86_64", "", "linux-gnux32", "", "linux")); @@ -93,15 +98,41 @@ main () "x86_64-netbsd", "x86_64", "", "netbsd", "", "bsd")); - // Removal of none-. - // - assert (test ("arm-none", - "arm-none", - "arm", "", "none", "")); + assert (test ("aarch64-unknown-nto-qnx7.0.0", + "aarch64-nto-qnx7.0.0", + "aarch64", "", "nto-qnx", "7.0.0", "other")); - assert (test ("arm-unknown-none-eabi", - "arm-eabi", - "arm", "", "eabi", "")); + assert (test ("aarch64-nto-qnx7.0.0", + "aarch64-nto-qnx7.0.0", + "aarch64", "", "nto-qnx", "7.0.0", "other")); + + assert (test ("wasm32-emscripten", + "wasm32-emscripten", + "wasm32", "", "emscripten", "", "other")); + + assert (test ("arm64-apple-darwin20.1.0", + "aarch64-apple-darwin20.1.0", + "aarch64", "apple", "darwin", "20.1.0", "macos")); + + assert (test ("arm64-apple-ios14.4", + "aarch64-apple-ios14.4", + "aarch64", "apple", "ios", "14.4", "ios")); + + assert (test ("arm64-apple-ios", + "aarch64-apple-ios", + "aarch64", "apple", "ios", "", "ios")); + + assert (test ("arm64-apple-ios14.4-simulator", + "aarch64-apple-ios14.4-simulator", + "aarch64", "apple", "ios-simulator", "14.4", "ios")); + + assert (test ("arm64-apple-ios-simulator", + "aarch64-apple-ios-simulator", + "aarch64", "apple", "ios-simulator", "", "ios")); + + assert (test ("x86_64-apple-ios14.4-macabi", + "x86_64-apple-ios14.4-macabi", + "x86_64", "apple", "ios-macabi", "14.4", "ios")); // Version extraction. // diff --git a/tests/timestamp/driver.cxx b/tests/timestamp/driver.cxx index 6283798..956b295 100644 --- a/tests/timestamp/driver.cxx +++ b/tests/timestamp/driver.cxx @@ -3,28 +3,17 @@ #include <time.h> // tzset() (POSIX), _tzset() (Windows) -#include <cassert> - -#ifndef __cpp_lib_modules_ts #include <chrono> #include <locale> #include <clocale> #include <sstream> #include <iomanip> #include <system_error> -#endif -// Other includes. +#include <libbutl/timestamp.hxx> -#ifdef __cpp_modules_ts -#ifdef __cpp_lib_modules_ts -import std.core; -import std.io; -#endif -import butl.timestamp; -#else -#include <libbutl/timestamp.mxx> -#endif +#undef NDEBUG +#include <cassert> using namespace std; using namespace butl; @@ -189,15 +178,15 @@ main () assert (parse (".384902285 Feb 21 19:31:10 2016", "%[.N] %b %d %H:%M:%S %Y", - "." + ns (384902285) + " Feb 21 19:31:10 2016")); + '.' + ns (384902285) + " Feb 21 19:31:10 2016")); assert (parse (".384902285 2016-02-21 19:31:10", "%[.N] %Y-%m-%d %H:%M:%S", - "." + ns (384902285) + " 2016-02-21 19:31:10")); + '.' + ns (384902285) + " 2016-02-21 19:31:10")); assert (parse (".3849022852016-02-21 19:31:10", "%[.N]%Y-%m-%d %H:%M:%S", - "." + ns (384902285) + "2016-02-21 19:31:10")); + '.' + ns (384902285) + "2016-02-21 19:31:10")); assert (parse ("Feb 1 2016", "%b %e %Y", "Feb 1 2016")); assert (parse ("Feb 11 2016", "%b %e %Y", "Feb 11 2016")); diff --git a/tests/url/driver.cxx b/tests/url/driver.cxx index 5f787bd..869eed5 100644 --- a/tests/url/driver.cxx +++ b/tests/url/driver.cxx @@ -1,29 +1,17 @@ // file : tests/url/driver.cxx -*- C++ -*- // license : MIT; see accompanying LICENSE file -#include <cassert> - -#ifndef __cpp_lib_modules_ts #include <string> #include <utility> // move() #include <iostream> #include <iterator> // back_inserter #include <stdexcept> // invalid_argument -#endif - -// Other includes. - -#ifdef __cpp_modules_ts -#ifdef __cpp_lib_modules_ts -import std.core; -import std.io; -#endif -import butl.url; -import butl.utility; // operator<<(ostream, exception) -#else -#include <libbutl/url.mxx> -#include <libbutl/utility.mxx> -#endif + +#include <libbutl/url.hxx> +#include <libbutl/utility.hxx> // operator<<(ostream, exception) + +#undef NDEBUG +#include <cassert> using namespace std; using namespace butl; @@ -151,7 +139,7 @@ namespace butl // Usages: // // argv[0] -// argv[0] [-c|-s|-w] <url> +// argv[0] [-c|-s|-w] [-n] <url> // // Perform some basic tests if no URL is provided. Otherwise round-trip the URL // to STDOUT. URL must contain only ASCII characters. Exit with zero code on @@ -159,7 +147,7 @@ namespace butl // to STDERR. // // -c -// Print the URL components one per line. Print the special '[null]' string +// Print the URL components one per line. Print the special '<null>' string // for an absent components. This is the default option if URL is provided. // // -s @@ -169,6 +157,9 @@ namespace butl // Same as above, but use the custom wstring-based url_traits // implementation for the basic_url template. // +// -n +// Normalize the URL. +// int main (int argc, const char* argv[]) try @@ -186,6 +177,8 @@ try comp } mode (print_mode::comp); + bool norm (false); + int i (1); for (; i != argc; ++i) { @@ -196,6 +189,8 @@ try mode = print_mode::wstr; else if (o == "-c") mode = print_mode::comp; + else if (o == "-n") + norm = true; else break; // End of options. } @@ -209,16 +204,18 @@ try assert (u0.empty ()); wurl u1 (scheme::http, - wurl_authority {wstring (), wurl_host (L"[123]"), 0}, + wurl_authority {wstring (), wurl_host (L"[::123]"), 0}, wstring (L"login"), wstring (L"q="), wstring (L"f")); + u1.normalize (); + assert (!u1.empty ()); assert (u1 != u0); wurl u2 (scheme::http, - wurl_host (L"123", url_host_kind::ipv6), + wurl_host (L"::123", url_host_kind::ipv6), wstring (L"login"), wstring (L"q="), wstring (L"f")); @@ -226,16 +223,18 @@ try assert (u2 == u1); wurl u3 (scheme::http, - wurl_host (L"123", url_host_kind::ipv6), + wurl_host (L"::123", url_host_kind::ipv6), 0, wstring (L"login"), wstring (L"q="), wstring (L"f")); + u3.normalize (); + assert (u3 == u2); wurl u4 (scheme::http, - L"[123]", + L"[::123]", wstring (L"login"), wstring (L"q="), wstring (L"f")); @@ -243,7 +242,7 @@ try assert (u4 == u3); wurl u5 (scheme::http, - L"[123]", + L"[::123]", 0, wstring (L"login"), wstring (L"q="), @@ -323,16 +322,31 @@ try { case print_mode::str: { - cout << (*ua != '\0' ? url (ua) : url ()) << endl; + url u; + if (*ua != '\0') + u = url (ua); + + if (norm) + u.normalize (); + + cout << u << endl; break; } case print_mode::wstr: { + wurl u; + // Convert ASCII string to wstring. // wstring s (ua, ua + strlen (ua)); - wcout << (!s.empty () ? wurl (s) : wurl ()) << endl; + if (!s.empty ()) + u = wurl (s); + + if (norm) + u.normalize (); + + wcout << u << endl; break; } case print_mode::comp: @@ -345,6 +359,9 @@ try if (!s.empty ()) u = wurl (s); + if (norm) + u.normalize (); + if (!u.empty ()) { wstring s; @@ -357,7 +374,7 @@ try false) << endl; } else - wcout << L"[null]" << endl; + wcout << L"<null>" << endl; if (u.authority) { @@ -368,11 +385,11 @@ try << " " << kinds[static_cast<size_t> (a.host.kind)] << endl; } else - wcout << L"[null]" << endl; + wcout << L"<null>" << endl; - wcout << (u.path ? *u.path : L"[null]") << endl - << (u.query ? *u.query : L"[null]") << endl - << (u.fragment ? *u.fragment : L"[null]") << endl; + wcout << (u.path ? *u.path : L"<null>") << endl + << (u.query ? *u.query : L"<null>") << endl + << (u.fragment ? *u.fragment : L"<null>") << endl; break; } } diff --git a/tests/url/testscript b/tests/url/testscript index 94f63ff..52c5005 100644 --- a/tests/url/testscript +++ b/tests/url/testscript @@ -21,11 +21,11 @@ $* : empty-url : $* '' >>EOO - [null] - [null] - [null] - [null] - [null] + <null> + <null> + <null> + <null> + <null> EOO : no-id @@ -43,19 +43,19 @@ $* $* 'http://build2.org' >>EOO http @build2.org:0 name - [null] - [null] - [null] + <null> + <null> + <null> EOO : deduced : $* 'c:/a' >>EOO file - [null] + <null> c:/a - [null] - [null] + <null> + <null> EOO $* ':/a' 2>'no scheme' != 0 : none @@ -70,10 +70,10 @@ $* : $* 'file:/tmp/a' >>EOO file - [null] + <null> tmp/a - [null] - [null] + <null> + <null> EOO : empty @@ -82,8 +82,8 @@ $* file @:0 name tmp/a - [null] - [null] + <null> + <null> EOO : query @@ -91,9 +91,9 @@ $* $* 'http://localhost?q' >>EOO http @localhost:0 name - [null] + <null> q - [null] + <null> EOO : fragment @@ -101,8 +101,8 @@ $* $* 'http://localhost#master' >>EOO http @localhost:0 name - [null] - [null] + <null> + <null> master EOO @@ -111,9 +111,9 @@ $* $* 'http://localhost' >>EOO http @localhost:0 name - [null] - [null] - [null] + <null> + <null> + <null> EOO : user @@ -124,9 +124,9 @@ $* $* 'http://admin@localhost' >>EOO http admin@localhost:0 name - [null] - [null] - [null] + <null> + <null> + <null> EOO : empty @@ -134,9 +134,9 @@ $* $* 'http://@localhost' >>EOO http @localhost:0 name - [null] - [null] - [null] + <null> + <null> + <null> EOO } @@ -148,26 +148,97 @@ $* { : port : - $* 'http://[1:23]:443' >>EOO + $* 'http://[1:2:3:4:5:6:7:8]:443' >>EOO http - @1:23:443 ipv6 - [null] - [null] - [null] + @1:2:3:4:5:6:7:8:443 ipv6 + <null> + <null> + <null> EOO : no-port : - $* 'http://[1:23]' >>EOO + $* 'http://[1:2:3:4:5:6:7:abcd]' >>EOO http - @1:23:0 ipv6 - [null] - [null] - [null] + @1:2:3:4:5:6:7:abcd:0 ipv6 + <null> + <null> + <null> + EOO + + : squashed2-begin + : + $* 'http://[::3:4:5:6:7:8]' >>EOO + http + @::3:4:5:6:7:8:0 ipv6 + <null> + <null> + <null> + EOO + + : squashed3-end + : + $* 'http://[1:2:3:4:5::]' >>EOO + http + @1:2:3:4:5:::0 ipv6 + <null> + <null> + <null> + EOO + + : squashed4-middle + : + $* 'http://[1:2::7:8]' >>EOO + http + @1:2::7:8:0 ipv6 + <null> + <null> + <null> + EOO + + : squashed-all + : + $* 'http://[::]' >>EOO + http + @:::0 ipv6 + <null> + <null> + <null> EOO $* 'http://[123' 2>'invalid IPv6 address' != 0 : missed-bracket $* 'http://[123] :80' 2>'invalid IPv6 address' != 0 : extra-char + + $* 'http://[]' 2>'invalid IPv6 address' != 0 : empty + $* 'http://[1:2]' 2>'invalid IPv6 address' != 0 : too-short + $* 'http://[1:2:3:4:5:6:7:8:9]' 2>'invalid IPv6 address' != 0 : too-long1 + $* 'http://[::2:3:4:5:6:7:8:9]' 2>'invalid IPv6 address' != 0 : too-long2 + $* 'http://[::3:4::7:8:9]' 2>'invalid IPv6 address' != 0 : several-squashes + $* 'http://[1:2:3:4::6:7:8:9]' 2>'invalid IPv6 address' != 0 : squash-one-hextet + $* 'http://[12345:2:3:4:5:6:7:8:9]' 2>'invalid IPv6 address' != 0 : long-hextet + $* 'http://[123z:2:3:4:5:6:7:8:9]' 2>'invalid IPv6 address' != 0 : not-hex + + : normalize + : + { + test.options += -n -s + + $* 'http://[::01:0:002:00:0003]' >'http://[::1:0:2:0:3]' : strip-zeros + $* 'http://[::ABC]' >'http://[::abc]' : lower-case + + $* 'http://[::]' >'http://[::]' : squash-all + $* 'http://[::1]' >'http://[::1]' : squash-left + $* 'http://[1::]' >'http://[1::]' : squash-right + $* 'http://[1::2]' >'http://[1::2]' : squash-middle + + $* 'http://[1::0:2:0:0:3]' >'http://[1::2:0:0:3]' : squash-longest1 + $* 'http://[::0:2:0:0:3]' >'http://[::2:0:0:3]' : squash-longest2 + $* 'http://[::0:2:0:0:0:0]' >'http://[0:0:0:2::]' : squash-longest3 + $* 'http://[0:0:1::2:3:4]' >'http://[::1:0:0:2:3:4]' : squash-first + $* 'http://[0:0:2:0:0:0::]' >'http://[0:0:2::]' : squash-trailing + + $* 'http://[::1:2:3:4:5:6:7]' >'http://[0:1:2:3:4:5:6:7]' : expand-zero + } } : ipv4 @@ -178,9 +249,9 @@ $* $* 'http://0.10.200.255' >>EOO http @0.10.200.255:0 ipv4 - [null] - [null] - [null] + <null> + <null> + <null> EOO : long @@ -188,9 +259,9 @@ $* $* 'http://0.10.200.255.30' >>EOO http @0.10.200.255.30:0 name - [null] - [null] - [null] + <null> + <null> + <null> EOO : short @@ -198,9 +269,9 @@ $* $* 'http://0.10.200' >>EOO http @0.10.200:0 name - [null] - [null] - [null] + <null> + <null> + <null> EOO : missed @@ -208,9 +279,9 @@ $* $* 'http://0.10..200' >>EOO http @0.10..200:0 name - [null] - [null] - [null] + <null> + <null> + <null> EOO : out-of-range @@ -218,10 +289,18 @@ $* $* 'http://0.10.200.256' >>EOO http @0.10.200.256:0 name - [null] - [null] - [null] + <null> + <null> + <null> EOO + + : normalize + : + { + test.options += -n -s + + $* 'http://0.010.000.00' >'http://0.10.0.0' : strip-zeros + } } : name @@ -232,9 +311,9 @@ $* $* 'https://www.b2.org' >>EOO https @www.b2.org:0 name - [null] - [null] - [null] + <null> + <null> + <null> EOO : encoded @@ -245,9 +324,9 @@ $* $* 'https://www.%62%32.org' >>EOO https @www.b2.org:0 name - [null] - [null] - [null] + <null> + <null> + <null> EOO $* 'https://www.%62%3.org' 2>'invalid URL-encoding' != 0 : short @@ -256,6 +335,15 @@ $* } $* 'https://www.b|2.org' 2>'invalid host name' != 0 : invalid-char + + : normalize + : + { + test.options += -n + + $* -s 'http://Build2.org' >'http://build2.org' : lower-case-char + $* -w 'http://Build2.org' >'http://build2.org' : lower-case-wchar + } } $* 'http://admin@:80?q=' 2>'no host' != 0: no-host @@ -269,9 +357,9 @@ $* $* 'http://build2.org:443' >>EOO http @build2.org:443 name - [null] - [null] - [null] + <null> + <null> + <null> EOO $* 'http://build2.org:-433' 2>'invalid port' != 0 : invalid-char @@ -288,9 +376,9 @@ $* $* 'http://b2.org' >>EOO http @b2.org:0 name - [null] - [null] - [null] + <null> + <null> + <null> EOO : empty @@ -299,8 +387,8 @@ $* http @b2.org:0 name - [null] - [null] + <null> + <null> EOO : non-empty @@ -309,8 +397,8 @@ $* http @b2.org:0 name s/q - [null] - [null] + <null> + <null> EOO : encoded @@ -319,8 +407,8 @@ $* http @b2.org:0 name o/s - [null] - [null] + <null> + <null> EOO $* 'http:a/b/c' 2>'rootless path' != 0 : rootless-path @@ -335,10 +423,10 @@ $* : $* 'pkcs11:token=sign;object=SIGN%20key' >>EOO pkcs11 - [null] + <null> token=sign;object=SIGN key - [null] - [null] + <null> + <null> EOO } @@ -352,7 +440,7 @@ $* @b2.org:0 name a x=foo&y=bar - [null] + <null> EOO : fragment @@ -372,8 +460,8 @@ $* $* 'http://b2.org#foo' >>EOO http @b2.org:0 name - [null] - [null] + <null> + <null> foo EOO } @@ -389,10 +477,10 @@ $* : host : { - $* 'file:///a' >'file:///a' : empty - $* 'http://1.1.1.1' >'http://1.1.1.1' : ipv4 - $* 'https://[1:2:3]' >'https://[1:2:3]' : ipv6 - $* 'file://a%d1%84' >'file://a%D1%84' : name + $* 'file:///a' >'file:///a' : empty + $* 'https://[1:2:3:4:5:6:7:8]' >'https://[1:2:3:4:5:6:7:8]' : ipv6 + $* 'http://1.1.1.1' >'http://1.1.1.1' : ipv4 + $* 'file://a%d1%84' >'file://a%D1%84' : name } $* 'http://admin@localhost' >'http://admin@localhost' : user diff --git a/tests/utf8/driver.cxx b/tests/utf8/driver.cxx index f35e65e..ccc2870 100644 --- a/tests/utf8/driver.cxx +++ b/tests/utf8/driver.cxx @@ -1,24 +1,13 @@ // file : tests/utf8/driver.cxx -*- C++ -*- // license : MIT; see accompanying LICENSE file -#include <cassert> - -#ifndef __cpp_lib_modules_ts #include <string> -#endif - -// Other includes. - -#ifdef __cpp_modules_ts -#ifdef __cpp_lib_modules_ts -import std.core; -#endif -import butl.utf8; -import butl.utility; -#else -#include <libbutl/utf8.mxx> -#include <libbutl/utility.mxx> -#endif + +#include <libbutl/utf8.hxx> +#include <libbutl/utility.hxx> + +#undef NDEBUG +#include <cassert> using namespace std; using namespace butl; diff --git a/tests/uuid/driver.cxx b/tests/uuid/driver.cxx index d8dae23..63e5bc7 100644 --- a/tests/uuid/driver.cxx +++ b/tests/uuid/driver.cxx @@ -5,13 +5,15 @@ # include <rpc.h> // GUID #endif -#include <cassert> #include <sstream> #include <iostream> #include <libbutl/uuid.hxx> #include <libbutl/uuid-io.hxx> +#undef NDEBUG +#include <cassert> + using namespace std; using namespace butl; diff --git a/tests/wildcard/driver.cxx b/tests/wildcard/driver.cxx index 00a317a..fee2748 100644 --- a/tests/wildcard/driver.cxx +++ b/tests/wildcard/driver.cxx @@ -1,36 +1,24 @@ // file : tests/wildcard/driver.cxx -*- C++ -*- // license : MIT; see accompanying LICENSE file -#include <cassert> - -#ifndef __cpp_lib_modules_ts #include <map> #include <string> #include <vector> -#include <algorithm> // sort() -#include <exception> #include <iostream> -#endif +#include <algorithm> // sort() +#include <exception> +#include <functional> +#include <system_error> -// Other includes. +#include <libbutl/path.hxx> +#include <libbutl/path-io.hxx> +#include <libbutl/utility.hxx> // operator<<(ostream, exception) +#include <libbutl/optional.hxx> +#include <libbutl/filesystem.hxx> +#include <libbutl/path-pattern.hxx> -#ifdef __cpp_modules_ts -#ifdef __cpp_lib_modules_ts -import std.core; -import std.io; -#endif -import butl.path; -import butl.utility; // operator<<(ostream, exception) -import butl.optional; -import butl.filesystem; -import butl.path_pattern; -#else -#include <libbutl/path.mxx> -#include <libbutl/utility.mxx> -#include <libbutl/optional.mxx> -#include <libbutl/filesystem.mxx> -#include <libbutl/path-pattern.mxx> -#endif +#undef NDEBUG +#include <cassert> using namespace std; using namespace butl; @@ -74,8 +62,13 @@ int _CRT_glob = 0; // through contains only the specified entry. The start directory is used if // the first pattern component is a self-matching wildcard. // +// -d (print|stop) +// If a inaccessible/dangling link is encountered, then print its path to +// stderr and, optionally, stop the search. Meaningful in combination with +// -sd and must follow it, if specified in the command line. +// // -i -// Pass psflags::ignorable_components to the match/search functions. +// Pass path_match_flags::match_absent to the match/search functions. // Meaningful in combination with -sd or -sp options and must follow it, if // specified in the command line. // @@ -108,6 +101,9 @@ try bool sort (true); path_match_flags flags (path_match_flags::follow_symlinks); + bool dangle_stop (false); + function<bool (const dir_entry&)> dangle_func; + int i (2); for (; i != argc; ++i) { @@ -116,6 +112,34 @@ try sort = false; else if (o == "-i") flags |= path_match_flags::match_absent; + else if (o == "-d") + { + ++i; + + assert (op == "-sd" && i != argc); + + string v (argv[i]); + + if (v == "print") + { + dangle_func = [] (const dir_entry& de) + { + cerr << de.base () / de.path () << endl; + return true; + }; + } + else if (v == "stop") + { + dangle_func = [&dangle_stop] (const dir_entry& de) + { + cerr << de.base () / de.path () << endl; + dangle_stop = true; + return false; + }; + } + else + assert (false); + } else break; // End of options. } @@ -181,10 +205,13 @@ try }; if (!entry) - path_search (pattern, add, start, flags); + path_search (pattern, add, start, flags, dangle_func); else path_search (pattern, *entry, add, start, flags); + if (dangle_stop) + return 1; + // It the search succeeds, then test search in the directory tree // represented by each matched path. Otherwise, if the directory tree is // specified, then make sure that it doesn't match the pattern. @@ -245,8 +272,13 @@ catch (const invalid_path& e) cerr << e << ": " << e.path << endl; return 2; } +catch (const system_error& e) +{ + cerr << e << endl; + return 3; +} catch (const exception& e) { cerr << e << endl; - return 2; + return 4; } diff --git a/tests/wildcard/testscript b/tests/wildcard/testscript index 5f6a767..baa51aa 100644 --- a/tests/wildcard/testscript +++ b/tests/wildcard/testscript @@ -650,12 +650,14 @@ { mkdir a; touch --no-cleanup a/b; - ^ln -s b a/l &a/l; + ln -s b a/l &a/l; rm a/b; touch a/c; - $* a/* >/'a/c' + $* a/* 2>! == 3; + $* -d 'print' a/* >/'a/c' 2>/'a/l'; + $* -d 'stop' a/* >! 2>/'a/l' == 1 } } |