mirror of
https://github.com/InstanceBrick/nightcap.git
synced 2026-10-17 16:01:38 +02:00
Add Sober-compatible asset overlay system
This commit is contained in:
5 files changed
+233
-19
No files matched your search
@@ -67,6 +67,9 @@ class RuntimePaths {
|
||||
return active_payload_manifest_;
|
||||
}
|
||||
const std::filesystem::path& cookie_file() const { return cookie_file_; }
|
||||
const std::filesystem::path& asset_overlay_dir() const {
|
||||
return asset_overlay_dir_;
|
||||
}
|
||||
bool use_real_sober_paths() const { return use_real_sober_paths_; }
|
||||
|
||||
std::filesystem::path DefaultAssetPath() const;
|
||||
@@ -99,6 +102,7 @@ class RuntimePaths {
|
||||
std::filesystem::path config_file_;
|
||||
std::filesystem::path active_payload_manifest_;
|
||||
std::filesystem::path cookie_file_;
|
||||
std::filesystem::path asset_overlay_dir_;
|
||||
bool use_real_sober_paths_ = false;
|
||||
};
|
||||
|
||||
|
||||
@@ -349,6 +349,14 @@ RuntimePaths RuntimePaths::FromEnvironment(
|
||||
paths.cookie_file_ = paths.auth_root_ / "roblox.cookie";
|
||||
paths.use_real_sober_paths_ =
|
||||
LegacyEnabled(environment, "MOCKTAIL_USE_REAL_SOBER_PATHS");
|
||||
if (environment.HasNonEmpty("MOCKTAIL_ASSET_OVERLAY_DIR")) {
|
||||
paths.asset_overlay_dir_ =
|
||||
environment.GetOr("MOCKTAIL_ASSET_OVERLAY_DIR", "");
|
||||
} else {
|
||||
paths.asset_overlay_dir_ = paths.DefaultSoberAwarePath(
|
||||
paths.sober_data_root_ / "asset_overlay",
|
||||
paths.data_root_ / "asset_overlay");
|
||||
}
|
||||
return paths;
|
||||
}
|
||||
|
||||
@@ -593,7 +601,8 @@ bool ExportRuntimePathEnvironment(const RuntimePaths& paths,
|
||||
std::error_code filesystem_error;
|
||||
for (const std::filesystem::path& directory :
|
||||
{paths.android_runtime_root(), paths.android_cache_root(),
|
||||
paths.vulkan_shader_cache_file().parent_path()}) {
|
||||
paths.vulkan_shader_cache_file().parent_path(),
|
||||
paths.asset_overlay_dir()}) {
|
||||
if (!RuntimePaths::EnsureDirectory(directory, &filesystem_error)) {
|
||||
if (error != nullptr) {
|
||||
*error = "cannot create resolved runtime path: " + directory.string();
|
||||
@@ -609,7 +618,9 @@ bool ExportRuntimePathEnvironment(const RuntimePaths& paths,
|
||||
SetEnvironmentDefault("MOCKTAIL_VULKAN_SHADER_CACHE_HOST_PATH",
|
||||
paths.vulkan_shader_cache_file(), error) &&
|
||||
SetEnvironmentDefault("MOCKTAIL_TEXTURE_OVERRIDE_DIR",
|
||||
paths.config_root() / "textures", error);
|
||||
paths.config_root() / "textures", error) &&
|
||||
SetEnvironmentDefault("MOCKTAIL_ASSET_OVERLAY_DIR",
|
||||
paths.asset_overlay_dir(), error);
|
||||
}
|
||||
|
||||
bool PrepareManagedPayloadWorkingDirectory(const RuntimePaths& paths,
|
||||
|
||||
+63
-17
@@ -43,6 +43,7 @@ struct AAsset {
|
||||
std::string apk_entry;
|
||||
std::vector<unsigned char> data;
|
||||
bool transcoded = false;
|
||||
bool is_overlay = false;
|
||||
size_t offset = 0;
|
||||
};
|
||||
struct AAssetDir {};
|
||||
@@ -115,25 +116,33 @@ bool FileExists(const std::string& path) {
|
||||
return !path.empty() && ::stat(path.c_str(), &st) == 0 && S_ISREG(st.st_mode);
|
||||
}
|
||||
|
||||
struct ResolvedAsset {
|
||||
std::string path;
|
||||
bool is_overlay = false;
|
||||
};
|
||||
|
||||
struct AssetLookupCache {
|
||||
std::mutex mutex;
|
||||
std::unordered_map<std::string, std::string> resolved_paths;
|
||||
std::unordered_map<std::string, ResolvedAsset> resolved_paths;
|
||||
};
|
||||
|
||||
AssetLookupCache g_asset_lookup_cache;
|
||||
constexpr std::size_t kMaxCachedAssetPaths = 1024 * 5;
|
||||
|
||||
std::string AssetCacheKey(const std::string& root,
|
||||
const std::string& overlay,
|
||||
const std::string& requested) {
|
||||
std::string key;
|
||||
key.reserve(root.size() + 1 + requested.size());
|
||||
key.reserve(root.size() + 1 + overlay.size() + 1 + requested.size());
|
||||
key.append(root);
|
||||
key.push_back('\0');
|
||||
key.append(overlay);
|
||||
key.push_back('\0');
|
||||
key.append(requested);
|
||||
return key;
|
||||
}
|
||||
|
||||
std::string ResolveAssetPath(const char* filename) {
|
||||
ResolvedAsset ResolveAssetPath(const char* filename) {
|
||||
if (filename == nullptr) {
|
||||
return {};
|
||||
}
|
||||
@@ -145,13 +154,16 @@ std::string ResolveAssetPath(const char* filename) {
|
||||
const std::string requested(requested_view);
|
||||
const char* root_env = GetEnvNonEmpty("MOCKTAIL_ASSET_ROOT");
|
||||
const std::string root = root_env != nullptr ? root_env : "rbx_bin/assets";
|
||||
const std::string cache_key = AssetCacheKey(root, requested);
|
||||
const char* overlay_env = GetEnvNonEmpty("MOCKTAIL_ASSET_OVERLAY_DIR");
|
||||
const std::string overlay =
|
||||
overlay_env != nullptr ? overlay_env : "rbx_bin/asset_overlay";
|
||||
const std::string cache_key = AssetCacheKey(root, overlay, requested);
|
||||
|
||||
{
|
||||
std::scoped_lock lock(g_asset_lookup_cache.mutex);
|
||||
auto it = g_asset_lookup_cache.resolved_paths.find(cache_key);
|
||||
if (it != g_asset_lookup_cache.resolved_paths.end()) {
|
||||
if (FileExists(it->second)) {
|
||||
if (FileExists(it->second.path)) {
|
||||
return it->second;
|
||||
}
|
||||
g_asset_lookup_cache.resolved_paths.erase(it);
|
||||
@@ -160,14 +172,44 @@ std::string ResolveAssetPath(const char* filename) {
|
||||
|
||||
const std::string stripped(StripAndroidAssetPrefix(requested_view));
|
||||
|
||||
const std::vector<std::string> candidates = {
|
||||
if (!overlay.empty()) {
|
||||
const std::vector<std::string> overlay_candidates = {
|
||||
overlay + "/" + requested,
|
||||
overlay + "/" + stripped,
|
||||
overlay + "/content/" + requested,
|
||||
overlay + "/content/" + stripped,
|
||||
overlay + "/ExtraContent/" + requested,
|
||||
overlay + "/ExtraContent/" + stripped,
|
||||
};
|
||||
for (const std::string& candidate : overlay_candidates) {
|
||||
if (FileExists(candidate)) {
|
||||
ResolvedAsset resolved{candidate, true};
|
||||
std::scoped_lock lock(g_asset_lookup_cache.mutex);
|
||||
if (g_asset_lookup_cache.resolved_paths.size() >=
|
||||
kMaxCachedAssetPaths &&
|
||||
g_asset_lookup_cache.resolved_paths.find(cache_key) ==
|
||||
g_asset_lookup_cache.resolved_paths.end()) {
|
||||
g_asset_lookup_cache.resolved_paths.erase(
|
||||
g_asset_lookup_cache.resolved_paths.begin());
|
||||
}
|
||||
g_asset_lookup_cache.resolved_paths.insert_or_assign(cache_key,
|
||||
resolved);
|
||||
return resolved;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<std::string> root_candidates = {
|
||||
root + "/" + requested,
|
||||
root + "/" + stripped,
|
||||
root + "/content/" + requested,
|
||||
root + "/content/" + stripped,
|
||||
root + "/ExtraContent/" + requested,
|
||||
root + "/ExtraContent/" + stripped,
|
||||
};
|
||||
for (const std::string& candidate : candidates) {
|
||||
for (const std::string& candidate : root_candidates) {
|
||||
if (FileExists(candidate)) {
|
||||
ResolvedAsset resolved{candidate, false};
|
||||
std::scoped_lock lock(g_asset_lookup_cache.mutex);
|
||||
if (g_asset_lookup_cache.resolved_paths.size() >=
|
||||
kMaxCachedAssetPaths &&
|
||||
@@ -177,8 +219,8 @@ std::string ResolveAssetPath(const char* filename) {
|
||||
g_asset_lookup_cache.resolved_paths.begin());
|
||||
}
|
||||
g_asset_lookup_cache.resolved_paths.insert_or_assign(cache_key,
|
||||
candidate);
|
||||
return candidate;
|
||||
resolved);
|
||||
return resolved;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -330,24 +372,27 @@ AAsset* AAssetManager_open(AAssetManager* mgr, const char* filename,
|
||||
if (mgr == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
std::string path = ResolveAssetPath(filename);
|
||||
if (path.empty()) {
|
||||
ResolvedAsset resolved = ResolveAssetPath(filename);
|
||||
if (resolved.path.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
auto* asset = new AAsset;
|
||||
asset->path = path;
|
||||
asset->path = resolved.path;
|
||||
asset->apk_entry = ApkEntryName(filename);
|
||||
if (!LoadFile(path, &asset->data)) {
|
||||
asset->is_overlay = resolved.is_overlay;
|
||||
if (!LoadFile(resolved.path, &asset->data)) {
|
||||
delete asset;
|
||||
return nullptr;
|
||||
}
|
||||
if (MocktailUsesDirectVulkan()) {
|
||||
asset->transcoded =
|
||||
libc_shim::TranscodeEtc1SkyTextureForVulkan(path.c_str(), &asset->data);
|
||||
libc_shim::TranscodeEtc1SkyTextureForVulkan(resolved.path.c_str(),
|
||||
&asset->data);
|
||||
}
|
||||
if (AssetTraceEnabled()) {
|
||||
std::fprintf(stderr, "[asset] open %s -> %s (%zu bytes)\n", filename,
|
||||
path.c_str(), asset->data.size());
|
||||
std::fprintf(stderr, "[asset] open %s -> %s (%zu bytes%s)\n", filename,
|
||||
resolved.path.c_str(), asset->data.size(),
|
||||
resolved.is_overlay ? " [overlay]" : "");
|
||||
}
|
||||
return asset;
|
||||
}
|
||||
@@ -464,7 +509,8 @@ int AAsset_openFileDescriptor(AAsset* asset, off_t* outStart,
|
||||
int fd = -1;
|
||||
off_t start = 0;
|
||||
off_t descriptor_length = static_cast<off_t>(asset->data.size());
|
||||
if (!OpenStoredApkEntryDescriptor(asset->apk_entry, &fd, &start,
|
||||
if (asset->is_overlay ||
|
||||
!OpenStoredApkEntryDescriptor(asset->apk_entry, &fd, &start,
|
||||
&descriptor_length)) {
|
||||
fd = ::open(asset->path.c_str(), O_RDONLY | O_CLOEXEC);
|
||||
}
|
||||
|
||||
@@ -55,6 +55,7 @@ class AssetManagerTest : public ::testing::Test {
|
||||
root_ = MakeTempRoot();
|
||||
ASSERT_FALSE(root_.empty());
|
||||
setenv("MOCKTAIL_ASSET_ROOT", root_.c_str(), 1);
|
||||
unsetenv("MOCKTAIL_ASSET_OVERLAY_DIR");
|
||||
const char* backend = std::getenv("MOCKTAIL_GRAPHICS_BACKEND");
|
||||
had_backend_ = backend != nullptr;
|
||||
previous_backend_ = backend != nullptr ? backend : "";
|
||||
@@ -63,6 +64,7 @@ class AssetManagerTest : public ::testing::Test {
|
||||
|
||||
void TearDown() override {
|
||||
unsetenv("MOCKTAIL_ASSET_ROOT");
|
||||
unsetenv("MOCKTAIL_ASSET_OVERLAY_DIR");
|
||||
if (had_backend_) {
|
||||
setenv("MOCKTAIL_GRAPHICS_BACKEND", previous_backend_.c_str(), 1);
|
||||
} else {
|
||||
@@ -298,4 +300,115 @@ TEST_F(AssetManagerTest, CacheSeparatesRuntimeAssetRootChanges) {
|
||||
AAsset_close(second);
|
||||
}
|
||||
|
||||
TEST_F(AssetManagerTest, OverlayAssetTakesPrecedenceOverRootAsset) {
|
||||
WriteAsset("content/textures/Cursors/KeyboardMouse/ArrowCursor.png",
|
||||
"stock-arrow");
|
||||
const std::string overlay_root = MakeTempRoot();
|
||||
ASSERT_FALSE(overlay_root.empty());
|
||||
WriteAssetAt(overlay_root,
|
||||
"content/textures/Cursors/KeyboardMouse/ArrowCursor.png",
|
||||
"custom-overlay-arrow");
|
||||
ASSERT_EQ(setenv("MOCKTAIL_ASSET_OVERLAY_DIR", overlay_root.c_str(), 1), 0);
|
||||
|
||||
AAssetManager* manager = AAssetManager_fromJava(nullptr, nullptr);
|
||||
|
||||
// 1. Direct content/ path
|
||||
AAsset* direct = AAssetManager_open(
|
||||
manager, "content/textures/Cursors/KeyboardMouse/ArrowCursor.png", 0);
|
||||
ASSERT_NE(direct, nullptr);
|
||||
EXPECT_EQ(std::string(static_cast<const char*>(AAsset_getBuffer(direct)),
|
||||
static_cast<std::size_t>(AAsset_getLength(direct))),
|
||||
"custom-overlay-arrow");
|
||||
AAsset_close(direct);
|
||||
|
||||
// 2. rbxasset:// URI prefix without content/
|
||||
AAsset* rbxasset = AAssetManager_open(
|
||||
manager, "rbxasset://textures/Cursors/KeyboardMouse/ArrowCursor.png", 0);
|
||||
ASSERT_NE(rbxasset, nullptr);
|
||||
EXPECT_EQ(std::string(static_cast<const char*>(AAsset_getBuffer(rbxasset)),
|
||||
static_cast<std::size_t>(AAsset_getLength(rbxasset))),
|
||||
"custom-overlay-arrow");
|
||||
AAsset_close(rbxasset);
|
||||
|
||||
// 3. Bare textures/ prefix
|
||||
AAsset* bare = AAssetManager_open(
|
||||
manager, "textures/Cursors/KeyboardMouse/ArrowCursor.png", 0);
|
||||
ASSERT_NE(bare, nullptr);
|
||||
EXPECT_EQ(std::string(static_cast<const char*>(AAsset_getBuffer(bare)),
|
||||
static_cast<std::size_t>(AAsset_getLength(bare))),
|
||||
"custom-overlay-arrow");
|
||||
AAsset_close(bare);
|
||||
}
|
||||
|
||||
TEST_F(AssetManagerTest, OverlayOpenFileDescriptorReadsDirectlyFromFile) {
|
||||
const std::string overlay_root = MakeTempRoot();
|
||||
ASSERT_FALSE(overlay_root.empty());
|
||||
WriteAssetAt(overlay_root, "content/custom_shader.bin", "custom-overlay-shader");
|
||||
ASSERT_EQ(setenv("MOCKTAIL_ASSET_OVERLAY_DIR", overlay_root.c_str(), 1), 0);
|
||||
// Point APK path to non-existent or dummy file to ensure descriptor reads overlay
|
||||
ASSERT_EQ(setenv("MOCKTAIL_ASSET_APK_PATH", "/nonexistent/apk/path.apk", 1), 0);
|
||||
|
||||
AAssetManager* manager = AAssetManager_fromJava(nullptr, nullptr);
|
||||
AAsset* asset = AAssetManager_open(manager, "content/custom_shader.bin", 0);
|
||||
ASSERT_NE(asset, nullptr);
|
||||
|
||||
off_t start = -1;
|
||||
off_t length = -1;
|
||||
int fd = AAsset_openFileDescriptor(asset, &start, &length);
|
||||
ASSERT_GE(fd, 0);
|
||||
EXPECT_EQ(start, 0);
|
||||
EXPECT_EQ(length, 21);
|
||||
|
||||
char buf[32] = {};
|
||||
EXPECT_EQ(pread(fd, buf, 21, start), 21);
|
||||
EXPECT_STREQ(buf, "custom-overlay-shader");
|
||||
close(fd);
|
||||
AAsset_close(asset);
|
||||
unsetenv("MOCKTAIL_ASSET_APK_PATH");
|
||||
}
|
||||
|
||||
TEST_F(AssetManagerTest, NonOverlaidAssetFallsBackToRootAsset) {
|
||||
WriteAsset("content/sounds/oof.mp3", "stock-sound");
|
||||
const std::string overlay_root = MakeTempRoot();
|
||||
ASSERT_FALSE(overlay_root.empty());
|
||||
WriteAssetAt(overlay_root, "content/textures/unrelated.png", "other-texture");
|
||||
ASSERT_EQ(setenv("MOCKTAIL_ASSET_OVERLAY_DIR", overlay_root.c_str(), 1), 0);
|
||||
|
||||
AAssetManager* manager = AAssetManager_fromJava(nullptr, nullptr);
|
||||
AAsset* asset = AAssetManager_open(manager, "sounds/oof.mp3", 0);
|
||||
ASSERT_NE(asset, nullptr);
|
||||
EXPECT_EQ(std::string(static_cast<const char*>(AAsset_getBuffer(asset)),
|
||||
static_cast<std::size_t>(AAsset_getLength(asset))),
|
||||
"stock-sound");
|
||||
AAsset_close(asset);
|
||||
}
|
||||
|
||||
TEST_F(AssetManagerTest, CacheSeparatesOverlayDirectoryChanges) {
|
||||
WriteAsset("content/test.txt", "stock");
|
||||
const std::string first_overlay = MakeTempRoot();
|
||||
ASSERT_FALSE(first_overlay.empty());
|
||||
WriteAssetAt(first_overlay, "content/test.txt", "overlay-1");
|
||||
ASSERT_EQ(setenv("MOCKTAIL_ASSET_OVERLAY_DIR", first_overlay.c_str(), 1), 0);
|
||||
|
||||
AAssetManager* manager = AAssetManager_fromJava(nullptr, nullptr);
|
||||
AAsset* first = AAssetManager_open(manager, "content/test.txt", 0);
|
||||
ASSERT_NE(first, nullptr);
|
||||
EXPECT_EQ(std::string(static_cast<const char*>(AAsset_getBuffer(first)),
|
||||
static_cast<std::size_t>(AAsset_getLength(first))),
|
||||
"overlay-1");
|
||||
AAsset_close(first);
|
||||
|
||||
const std::string second_overlay = MakeTempRoot();
|
||||
ASSERT_FALSE(second_overlay.empty());
|
||||
WriteAssetAt(second_overlay, "content/test.txt", "overlay-2");
|
||||
ASSERT_EQ(setenv("MOCKTAIL_ASSET_OVERLAY_DIR", second_overlay.c_str(), 1), 0);
|
||||
|
||||
AAsset* second = AAssetManager_open(manager, "content/test.txt", 0);
|
||||
ASSERT_NE(second, nullptr);
|
||||
EXPECT_EQ(std::string(static_cast<const char*>(AAsset_getBuffer(second)),
|
||||
static_cast<std::size_t>(AAsset_getLength(second))),
|
||||
"overlay-2");
|
||||
AAsset_close(second);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -439,6 +439,36 @@ TEST(RuntimePathsTest, SelectsExistingRealSoberAssetPath) {
|
||||
EXPECT_EQ(paths.DefaultAssetPath(), sober_assets);
|
||||
}
|
||||
|
||||
TEST(RuntimePathsTest, SelectsExistingRealSoberAssetOverlayPath) {
|
||||
TemporaryDirectory temporary;
|
||||
ASSERT_FALSE(temporary.path().empty());
|
||||
const std::filesystem::path home = temporary.path() / "home";
|
||||
const std::filesystem::path sober_overlay =
|
||||
home / ".var/app/org.vinegarhq.Sober/data/sober/asset_overlay";
|
||||
ASSERT_TRUE(RuntimePaths::EnsureDirectory(sober_overlay));
|
||||
|
||||
const MapEnvironment environment({
|
||||
{"HOME", home.string()},
|
||||
{"MOCKTAIL_USE_REAL_SOBER_PATHS", "1"},
|
||||
});
|
||||
const RuntimePaths paths = RuntimePaths::FromEnvironment(
|
||||
environment, temporary.path() / "empty-workspace");
|
||||
|
||||
EXPECT_EQ(paths.asset_overlay_dir(), sober_overlay);
|
||||
}
|
||||
|
||||
TEST(RuntimePathsTest, RespectsExplicitAssetOverlayOverride) {
|
||||
TemporaryDirectory temporary;
|
||||
ASSERT_FALSE(temporary.path().empty());
|
||||
const MapEnvironment environment({
|
||||
{"HOME", temporary.path().string()},
|
||||
{"MOCKTAIL_ASSET_OVERLAY_DIR", "/custom/asset_overlay"},
|
||||
});
|
||||
const RuntimePaths paths = RuntimePaths::FromEnvironment(
|
||||
environment, temporary.path());
|
||||
EXPECT_EQ(paths.asset_overlay_dir(), "/custom/asset_overlay");
|
||||
}
|
||||
|
||||
TEST(RuntimePathsTest, PrefersWorkspaceAssets) {
|
||||
TemporaryDirectory temporary;
|
||||
ASSERT_FALSE(temporary.path().empty());
|
||||
@@ -591,10 +621,13 @@ TEST(RuntimePathsTest, ExportsXdgBackedAndroidPathsAndCreatesParents) {
|
||||
"MOCKTAIL_VULKAN_SHADER_CACHE_HOST_PATH");
|
||||
const ScopedProcessEnvironment texture_overrides(
|
||||
"MOCKTAIL_TEXTURE_OVERRIDE_DIR");
|
||||
const ScopedProcessEnvironment overlay_dir(
|
||||
"MOCKTAIL_ASSET_OVERLAY_DIR");
|
||||
ASSERT_EQ(unsetenv("MOCKTAIL_RUNTIME_ROOT"), 0);
|
||||
ASSERT_EQ(unsetenv("MOCKTAIL_ANDROID_CACHE_HOST_ROOT"), 0);
|
||||
ASSERT_EQ(unsetenv("MOCKTAIL_VULKAN_SHADER_CACHE_HOST_PATH"), 0);
|
||||
ASSERT_EQ(unsetenv("MOCKTAIL_TEXTURE_OVERRIDE_DIR"), 0);
|
||||
ASSERT_EQ(unsetenv("MOCKTAIL_ASSET_OVERLAY_DIR"), 0);
|
||||
|
||||
const MapEnvironment environment({
|
||||
{"HOME", temporary.path().string()},
|
||||
@@ -614,10 +647,13 @@ TEST(RuntimePathsTest, ExportsXdgBackedAndroidPathsAndCreatesParents) {
|
||||
paths.vulkan_shader_cache_file().c_str());
|
||||
EXPECT_STREQ(std::getenv("MOCKTAIL_TEXTURE_OVERRIDE_DIR"),
|
||||
(paths.config_root() / "textures").c_str());
|
||||
EXPECT_STREQ(std::getenv("MOCKTAIL_ASSET_OVERLAY_DIR"),
|
||||
paths.asset_overlay_dir().c_str());
|
||||
EXPECT_TRUE(std::filesystem::is_directory(paths.android_runtime_root()));
|
||||
EXPECT_TRUE(std::filesystem::is_directory(paths.android_cache_root()));
|
||||
EXPECT_TRUE(std::filesystem::is_directory(
|
||||
paths.vulkan_shader_cache_file().parent_path()));
|
||||
EXPECT_TRUE(std::filesystem::is_directory(paths.asset_overlay_dir()));
|
||||
}
|
||||
|
||||
TEST(RuntimePathsTest, PreservesExplicitAndroidPathOverrides) {
|
||||
@@ -628,12 +664,15 @@ TEST(RuntimePathsTest, PreservesExplicitAndroidPathOverrides) {
|
||||
"MOCKTAIL_ANDROID_CACHE_HOST_ROOT");
|
||||
const ScopedProcessEnvironment shader_cache(
|
||||
"MOCKTAIL_VULKAN_SHADER_CACHE_HOST_PATH");
|
||||
const ScopedProcessEnvironment overlay_dir(
|
||||
"MOCKTAIL_ASSET_OVERLAY_DIR");
|
||||
ASSERT_EQ(setenv("MOCKTAIL_RUNTIME_ROOT", "/explicit/runtime", 1), 0);
|
||||
ASSERT_EQ(setenv("MOCKTAIL_ANDROID_CACHE_HOST_ROOT", "/explicit/cache", 1),
|
||||
0);
|
||||
ASSERT_EQ(setenv("MOCKTAIL_VULKAN_SHADER_CACHE_HOST_PATH",
|
||||
"/explicit/shader-cache", 1),
|
||||
0);
|
||||
ASSERT_EQ(setenv("MOCKTAIL_ASSET_OVERLAY_DIR", "/explicit/overlay", 1), 0);
|
||||
|
||||
const MapEnvironment environment({{"HOME", temporary.path().string()}});
|
||||
const RuntimePaths paths =
|
||||
@@ -646,6 +685,7 @@ TEST(RuntimePathsTest, PreservesExplicitAndroidPathOverrides) {
|
||||
"/explicit/cache");
|
||||
EXPECT_STREQ(std::getenv("MOCKTAIL_VULKAN_SHADER_CACHE_HOST_PATH"),
|
||||
"/explicit/shader-cache");
|
||||
EXPECT_STREQ(std::getenv("MOCKTAIL_ASSET_OVERLAY_DIR"), "/explicit/overlay");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Reference in new issue
Block a user