118 lines
4.8 KiB
C++
118 lines
4.8 KiB
C++
#pragma once
|
|
// test/PathBesideSource.h
|
|
//
|
|
// Shared helper for resolving test asset paths relative to the test source file.
|
|
// On desktop the path is dirname(__FILE__); on Android/iOS test apps the
|
|
// build-host path baked into __FILE__ is replaced with the on-device unpacked
|
|
// tree root so that `pathBesideThisSource("assets/...")` resolves to
|
|
// <internal>/evengine_test/assets/... on the device.
|
|
//
|
|
// Deliberately uses its own `eve_test_path` namespace (NOT `eve`): this header is
|
|
// included *inside* the anonymous namespaces of several test files, so introducing
|
|
// `namespace eve` there would shadow the global ::eve and break every
|
|
// `eve::window::...` / `eve::image::...` reference in those files.
|
|
|
|
#include <cstdlib>
|
|
#include <string>
|
|
|
|
#if defined(EVENGINE_ANDROID)
|
|
#include <SDL2/SDL.h>
|
|
#endif
|
|
|
|
namespace eve_test_path {
|
|
|
|
#if defined(EVENGINE_ANDROID)
|
|
inline std::string androidTestRoot() {
|
|
static const std::string root = [] {
|
|
const char *internal = SDL_AndroidGetInternalStoragePath();
|
|
return internal ? std::string(internal) + "/evengine_test" : std::string();
|
|
}();
|
|
return root;
|
|
}
|
|
|
|
// Map a build-host source path (__FILE__) onto the on-device test layout.
|
|
// All test sources are flat in test/, and the APK unpacks assets/test/* directly
|
|
// into the device root (<internal>/evengine_test/*), so the basename is the only
|
|
// meaningful part of __FILE__ here.
|
|
inline std::string androidSourcePath(const char *file) {
|
|
std::string s = file ? file : "";
|
|
const std::string root = androidTestRoot();
|
|
if (root.empty())
|
|
return s;
|
|
size_t slash = s.find_last_of("/\\");
|
|
std::string rel = (slash == std::string::npos) ? s : s.substr(slash + 1);
|
|
return root + "/" + rel;
|
|
}
|
|
#elif defined(EVENGINE_IOS_TEST_APP)
|
|
// Same layout as Android: the runner chdirs to the staged root and all test
|
|
// sources are flat in test/, so the basename of __FILE__ is the only
|
|
// meaningful part. This header is included *inside* anonymous namespaces in
|
|
// several test files, so it cannot include ios_test.h (which declares
|
|
// `namespace eve`); instead the root is recomputed from the same HOME-based
|
|
// path ios_test.mm stages into (iOS sets HOME to the app sandbox root).
|
|
inline std::string iosTestRoot() {
|
|
static const std::string root = [] {
|
|
const char *home = std::getenv("HOME");
|
|
return home ? std::string(home) + "/Library/Caches/evengine_test" : std::string();
|
|
}();
|
|
return root;
|
|
}
|
|
|
|
inline std::string iosSourcePath(const char *file) {
|
|
std::string s = file ? file : "";
|
|
const std::string root = iosTestRoot();
|
|
if (root.empty()) return s;
|
|
size_t slash = s.find_last_of("/\\");
|
|
std::string rel = (slash == std::string::npos) ? s : s.substr(slash + 1);
|
|
return root + "/" + rel;
|
|
}
|
|
#endif // EVENGINE_ANDROID / EVENGINE_IOS_TEST_APP
|
|
|
|
inline std::string pathBesideSourceImpl(const char *file, const char *relative) {
|
|
#if defined(EVENGINE_ANDROID)
|
|
std::string source = androidSourcePath(file);
|
|
size_t slash = source.find_last_of('/');
|
|
std::string dir = (slash == std::string::npos) ? std::string(".") : source.substr(0, slash);
|
|
return dir + "/" + relative;
|
|
#elif defined(EVENGINE_IOS_TEST_APP)
|
|
std::string source = iosSourcePath(file);
|
|
size_t slash = source.find_last_of('/');
|
|
std::string dir = (slash == std::string::npos) ? std::string(".") : source.substr(0, slash);
|
|
return dir + "/" + relative;
|
|
#else
|
|
std::string here = file ? file : "";
|
|
auto slash = here.find_last_of("/\\");
|
|
std::string dir = (slash == std::string::npos) ? std::string(".") : here.substr(0, slash);
|
|
return dir + "/" + relative;
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* @brief Resolve an asset path relative to the repo's test/ directory.
|
|
*
|
|
* Several test files build paths as `dirname(__FILE__) + "/" + relative`.
|
|
* On the iOS test app the compiled __FILE__ points at the build host, so the
|
|
* host test/ dir must be replaced with the on-device staged root (where the
|
|
* bundled test/ contents live flat and examples/ sits alongside); leading
|
|
* "../" segments that would leave test/ are collapsed accordingly.
|
|
*/
|
|
inline std::string pathBesideTestDir(const char *file, const std::string &relative) {
|
|
#if defined(EVENGINE_IOS_TEST_APP)
|
|
std::string rel = relative;
|
|
while (rel.rfind("../", 0) == 0) rel = rel.substr(3);
|
|
return iosTestRoot() + "/" + rel;
|
|
#else
|
|
std::string here = file ? file : "";
|
|
auto slash = here.find_last_of("/\\");
|
|
std::string dir = (slash == std::string::npos) ? std::string(".") : here.substr(0, slash);
|
|
return dir + "/" + relative;
|
|
#endif
|
|
}
|
|
|
|
} // namespace eve_test_path
|
|
|
|
#define EVE_DEFINE_PATH_BESIDE_SOURCE() \
|
|
static std::string pathBesideThisSource(const char *filename) { \
|
|
return eve_test_path::pathBesideSourceImpl(__FILE__, filename); \
|
|
}
|