Also, run all tests in a path with cyrillic chars and spacesdefault_compile_flags
#include <dds/util/paths.hpp> | #include <dds/util/paths.hpp> | ||||
#include <dds/util/signal.hpp> | #include <dds/util/signal.hpp> | ||||
#include <neo/assert.hpp> | |||||
#include <range/v3/action/join.hpp> | #include <range/v3/action/join.hpp> | ||||
#include <range/v3/range/conversion.hpp> | #include <range/v3/range/conversion.hpp> | ||||
#include <range/v3/view/concat.hpp> | #include <range/v3/view/concat.hpp> | ||||
#include <filesystem> | #include <filesystem> | ||||
#include <iostream> | #include <iostream> | ||||
#include <locale.h> | |||||
#include <sstream> | #include <sstream> | ||||
namespace { | namespace { | ||||
## ## ## ## #### ## ## | ## ## ## ## #### ## ## | ||||
*/ | */ | ||||
int main(int argc, char** argv) { | |||||
int main_fn(const std::vector<std::string>& argv) { | |||||
spdlog::set_pattern("[%H:%M:%S] [%^%-5l%$] %v"); | spdlog::set_pattern("[%H:%M:%S] [%^%-5l%$] %v"); | ||||
args::ArgumentParser parser("DDS - The drop-dead-simple library manager"); | args::ArgumentParser parser("DDS - The drop-dead-simple library manager"); | ||||
cli_build_deps build_deps{cli}; | cli_build_deps build_deps{cli}; | ||||
try { | try { | ||||
parser.ParseCLI(argc, argv); | |||||
parser.ParseCLI(argv); | |||||
} catch (const args::Help&) { | } catch (const args::Help&) { | ||||
std::cout << parser; | std::cout << parser; | ||||
return 0; | return 0; | ||||
return 2; | return 2; | ||||
} | } | ||||
} | } | ||||
#if NEO_OS_IS_WINDOWS | |||||
std::string wstr_to_u8str(std::wstring_view in) { | |||||
if (in.empty()) { | |||||
return ""; | |||||
} | |||||
auto req_size = ::WideCharToMultiByte(CP_UTF8, | |||||
0, | |||||
in.data(), | |||||
static_cast<int>(in.size()), | |||||
nullptr, | |||||
0, | |||||
nullptr, | |||||
nullptr); | |||||
neo_assert(invariant, | |||||
req_size > 0, | |||||
"Failed to convert given unicode string for main() argv", | |||||
req_size, | |||||
std::system_category().message(::GetLastError()), | |||||
::GetLastError()); | |||||
std::string ret; | |||||
ret.resize(req_size); | |||||
::WideCharToMultiByte(CP_UTF8, | |||||
0, | |||||
in.data(), | |||||
static_cast<int>(in.size()), | |||||
ret.data(), | |||||
static_cast<int>(ret.size()), | |||||
nullptr, | |||||
nullptr); | |||||
return ret; | |||||
} | |||||
int wmain(int argc, wchar_t** argv) { | |||||
std::vector<std::string> u8_argv; | |||||
::setlocale(LC_ALL, ".utf8"); | |||||
for (int i = 1; i < argc; ++i) { | |||||
u8_argv.emplace_back(wstr_to_u8str(argv[i])); | |||||
} | |||||
return main_fn(u8_argv); | |||||
} | |||||
#else | |||||
int main(int argc, char** argv) { return main_fn({argv + 1, argv + argc}); } | |||||
#endif |
auto repo = dds::catalog::open(":memory:"s); | auto repo = dds::catalog::open(":memory:"s); | ||||
} | } | ||||
TEST_CASE("Open a catalog in a non-ascii path") { | |||||
::setlocale(LC_ALL, ".utf8"); | |||||
auto THIS_DIR = dds::fs::canonical(__FILE__).parent_path(); | |||||
auto BUILD_DIR | |||||
= (THIS_DIR.parent_path().parent_path().parent_path() / "_build").lexically_normal(); | |||||
auto subdir = BUILD_DIR / "Ю́рий Алексе́евич Гага́рин"; | |||||
dds::fs::remove_all(subdir); | |||||
dds::catalog::open(subdir / "test.db"); | |||||
dds::fs::remove_all(subdir); | |||||
} | |||||
class catalog_test_case { | class catalog_test_case { | ||||
public: | public: | ||||
dds::catalog db = dds::catalog::open(":memory:"s); | dds::catalog db = dds::catalog::open(":memory:"s); |
throw std::system_error(std::error_code(::GetLastError(), std::system_category()), what); | throw std::system_error(std::error_code(::GetLastError(), std::system_category()), what); | ||||
} | } | ||||
std::wstring widen(std::string_view s) { | |||||
if (s.empty()) { | |||||
return L""; | |||||
} | |||||
auto req_chars | |||||
= ::MultiByteToWideChar(CP_UTF8, 0, s.data(), static_cast<int>(s.size()), nullptr, 0); | |||||
std::wstring ret; | |||||
ret.resize(req_chars); | |||||
::MultiByteToWideChar(CP_UTF8, 0, s.data(), static_cast<int>(s.size()), ret.data(), req_chars); | |||||
return ret; | |||||
} | |||||
} // namespace | } // namespace | ||||
proc_result dds::run_proc(const proc_options& opts) { | proc_result dds::run_proc(const proc_options& opts) { | ||||
auto cmd_str = quote_command(opts.command); | |||||
auto cmd_str = quote_command(opts.command); | |||||
auto cmd_wide = widen(cmd_str); | |||||
dds_log(debug, "Spawning subprocess: {}", cmd_str); | dds_log(debug, "Spawning subprocess: {}", cmd_str); | ||||
::SECURITY_ATTRIBUTES security = {}; | ::SECURITY_ATTRIBUTES security = {}; | ||||
wil::unique_process_information proc_info; | wil::unique_process_information proc_info; | ||||
::STARTUPINFOA startup_info = {}; | |||||
::STARTUPINFOW startup_info = {}; | |||||
::RtlSecureZeroMemory(&startup_info, sizeof startup_info); | ::RtlSecureZeroMemory(&startup_info, sizeof startup_info); | ||||
startup_info.hStdOutput = startup_info.hStdError = writer.get(); | startup_info.hStdOutput = startup_info.hStdError = writer.get(); | ||||
startup_info.dwFlags = STARTF_USESTDHANDLES; | startup_info.dwFlags = STARTF_USESTDHANDLES; | ||||
startup_info.cb = sizeof startup_info; | startup_info.cb = sizeof startup_info; | ||||
// DO IT! | // DO IT! | ||||
okay = ::CreateProcessA(nullptr, // cmd[0].data(), | |||||
cmd_str.data(), | |||||
okay = ::CreateProcessW(nullptr, // cmd[0].data(), | |||||
cmd_wide.data(), | |||||
nullptr, | nullptr, | ||||
nullptr, | nullptr, | ||||
true, | true, |
shared_file_mutex::shared_file_mutex(path_ref filepath) | shared_file_mutex::shared_file_mutex(path_ref filepath) | ||||
: _path{filepath} { | : _path{filepath} { | ||||
auto h = ::CreateFileA(_path.string().c_str(), | |||||
auto h = ::CreateFileW(_path.native().c_str(), | |||||
GENERIC_READ | GENERIC_WRITE, | GENERIC_READ | GENERIC_WRITE, | ||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, | FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, | ||||
nullptr, | nullptr, |
TEST_CASE("Simple glob") { | TEST_CASE("Simple glob") { | ||||
auto this_dir = dds::fs::path(__FILE__).parent_path(); | auto this_dir = dds::fs::path(__FILE__).parent_path(); | ||||
auto glob = dds::glob::compile("*.test.cpp"); | auto glob = dds::glob::compile("*.test.cpp"); | ||||
::setlocale(LC_ALL, ".utf8"); | |||||
auto it = glob.scan_from(this_dir); | auto it = glob.scan_from(this_dir); | ||||
for (; it != glob.end(); ++it) { | for (; it != glob.end(); ++it) { |
self.dds_exe = dds_exe | self.dds_exe = dds_exe | ||||
self.test_dir = test_dir | self.test_dir = test_dir | ||||
self.source_root = project_dir | self.source_root = project_dir | ||||
self.scratch_dir = project_dir / '_test_scratch' | |||||
self.scratch_dir = project_dir / '_test_scratch/Ю́рий Алексе́евич Гага́рин' | |||||
self.scope = scope | self.scope = scope | ||||
self.scope.callback(self.cleanup) | self.scope.callback(self.cleanup) | ||||