2#if __cplusplus < 201703L
5 std::cout <<
"path_resolution_test skipped for C++11" << std::endl;
31 #include <mach-o/dyld.h>
38namespace fs = std::filesystem;
40static std::string exe_dir() {
42 std::vector<wchar_t> buf(32768);
43 DWORD n = GetModuleFileNameW(
nullptr, buf.data(),
static_cast<DWORD
>(buf.size()));
44 if (n == 0 || n == buf.size())
throw std::runtime_error(
"GetModuleFileNameW failed");
45 fs::path p(buf.data(), buf.data() + n);
46 return p.parent_path().u8string();
47#elif defined(__APPLE__)
49 _NSGetExecutablePath(
nullptr, &size);
50 std::vector<char> path(size);
51 if (_NSGetExecutablePath(path.data(), &size) != 0)
throw std::runtime_error(
"_NSGetExecutablePath failed");
52 fs::path p = fs::weakly_canonical(fs::path(path.data()));
53 return p.parent_path().u8string();
56 ssize_t n = readlink(
"/proc/self/exe", path,
sizeof(path)-1);
57 if (n <= 0)
throw std::runtime_error(
"readlink /proc/self/exe failed");
59 fs::path p = fs::weakly_canonical(fs::path(path));
60 return p.parent_path().u8string();
64static std::string uniq_suffix() {
65 auto now = std::chrono::high_resolution_clock::now().time_since_epoch().count();
66 std::mt19937_64 rng(
static_cast<uint64_t
>(now));
67 std::uniform_int_distribution<uint64_t> dist;
68 uint64_t x = dist(rng);
70 std::snprintf(buf,
sizeof(buf),
"%016llx",
static_cast<unsigned long long>(x));
71 return std::string(buf);
74static bool dir_nonempty(
const fs::path& p) {
75 if (!fs::exists(p) || !fs::is_directory(p))
return false;
76 return fs::directory_iterator(p) != fs::directory_iterator{};
80static fs::path expected_path_from_policy(
const std::string& pathname,
82 const fs::path& exeDir,
83 const fs::path& cwd) {
84 auto explicitly_rel = [](
const std::string& s){
85 auto sw = [&](
const char* p){
return s.rfind(p, 0) == 0; };
86 return sw(
"./") || sw(
"../") || sw(
".\\") || sw(
"..\\");
88 fs::path p = fs::u8path(pathname);
89 if (p.is_absolute()) {
91 }
else if (explicitly_rel(pathname)) {
93 }
else if (relative_to_exe) {
98#if __cplusplus >= 202002L
99 p = fs::weakly_canonical(p);
101 p = p.lexically_normal();
106template <
typename DoWriteVerify>
107static void run_case(
const std::string& case_name,
108 const std::string& raw_pathname,
109 bool relative_to_exe,
111 const fs::path& exeDir,
113 DoWriteVerify&& doWriteVerify) {
115 fs::path expect = expected_path_from_policy(raw_pathname, relative_to_exe, exeDir, cwd);
130 std::string tbl =
"kv_i8_i8_" + case_name +
"_" + uniq_suffix();
138 assert(fs::exists(expect));
139 assert(fs::is_directory(expect));
140 assert(dir_nonempty(expect));
143 assert(fs::exists(expect));
144 assert(fs::is_regular_file(expect));
151 const fs::path exeDir = fs::path(exe_dir());
152 const fs::path baseTmp = fs::temp_directory_path() / (
"mdbxc_path_tests_" + uniq_suffix());
153 fs::create_directories(baseTmp);
156 const fs::path cwdA = baseTmp /
"cwdA";
157 const fs::path cwdB = baseTmp /
"cwdB";
158 fs::create_directories(cwdA);
159 fs::create_directories(cwdB);
162 fs::current_path(cwdA);
165 run_case(
"dir_rel_cwd",
166 "data/db_dir_cwd_" + uniq_suffix(),
169 exeDir, fs::current_path(),
171 kv.insert_or_assign(1, (int8_t)42);
172#if __cplusplus >= 201703L
174 assert(v && *v == (int8_t)42);
176 auto v = kv.find_compat(1);
177 assert(v.first && v.second == (int8_t)42);
182 run_case(
"dir_rel_exe",
183 "data/db_dir_exe_" + uniq_suffix(),
186 exeDir, fs::current_path(),
188 kv.insert_or_assign(1, (int8_t)7);
189#if __cplusplus >= 201703L
191 assert(v && *v == (int8_t)7);
193 auto v = kv.find_compat(1);
194 assert(v.first && v.second == (int8_t)7);
199 run_case(
"dir_explicit_cwd",
200 "./data/db_dir_explicit_" + uniq_suffix(),
203 exeDir, fs::current_path(),
205 kv.insert_or_assign(1, (int8_t)-5);
206#if __cplusplus >= 201703L
208 assert(v && *v == (int8_t)-5);
210 auto v = kv.find_compat(1);
211 assert(v.first && v.second == (int8_t)-5);
216 fs::current_path(cwdB);
219 run_case(
"file_rel_cwd",
220 "data/db_file_cwd_" + uniq_suffix(),
223 exeDir, fs::current_path(),
225 kv.insert_or_assign(1, (int8_t)11);
226#if __cplusplus >= 201703L
228 assert(v && *v == (int8_t)11);
230 auto v = kv.find_compat(1);
231 assert(v.first && v.second == (int8_t)11);
236 run_case(
"file_rel_exe",
237 "data/db_file_exe_" + uniq_suffix(),
240 exeDir, fs::current_path(),
242 kv.insert_or_assign(1, (int8_t)12);
243#if __cplusplus >= 201703L
245 assert(v && *v == (int8_t)12);
247 auto v = kv.find_compat(1);
248 assert(v.first && v.second == (int8_t)12);
253 run_case(
"file_explicit_cwd",
254 "./data/db_file_explicit_" + uniq_suffix(),
257 exeDir, fs::current_path(),
259 kv.insert_or_assign(1, (int8_t)13);
260#if __cplusplus >= 201703L
262 assert(v && *v == (int8_t)13);
264 auto v = kv.find_compat(1);
265 assert(v.first && v.second == (int8_t)13);
269 std::cout <<
"[result] path resolution tests passed\n";
272catch (
const std::exception& e) {
273 std::cerr <<
"[error] " << e.what() <<
"\n";
Declaration of the KeyValueTable class for managing key-value pairs in an MDBX database.
Parameters used by Connection to create the MDBX environment.
bool no_subdir
Whether to store the database in a single file instead of a directory.
std::string pathname
Path to the database file or directory containing the database.
bool relative_to_exe
Whether to resolve a relative path relative to the executable directory.
int64_t max_dbs
Maximum number of named databases (DBI) in the environment.
static std::shared_ptr< Connection > create(const Config &config)
Creates and connects a new shared Connection instance.
Template class for managing key-value pairs in an MDBX database.