Files
InstanceBrick--nightcap/tests/window_state_store_test.cc

155 lines
4.5 KiB
C++

#include "window/window_state_store.h"
#include <gtest/gtest.h>
#include <sys/stat.h>
#include <unistd.h>
#include <filesystem>
#include <fstream>
namespace mocktail {
namespace window {
namespace {
class TemporaryDirectory final {
public:
TemporaryDirectory() {
char pattern[] = "/tmp/mocktail_window_state_XXXXXX";
char* created = mkdtemp(pattern);
if (created != nullptr) {
path_ = created;
}
}
~TemporaryDirectory() {
std::error_code error;
std::filesystem::remove_all(path_, error);
}
const std::filesystem::path& path() const { return path_; }
private:
std::filesystem::path path_;
};
mode_t FileMode(const std::filesystem::path& path) {
struct stat status{};
return stat(path.c_str(), &status) == 0 ? status.st_mode & 0777 : 0;
}
TEST(WindowStateStoreTest, MissingStateUsesCallerDefaults) {
TemporaryDirectory temporary;
ASSERT_FALSE(temporary.path().empty());
const WindowStateLoadResult loaded =
LoadWindowState(temporary.path() / "window-state.json");
EXPECT_TRUE(loaded);
EXPECT_FALSE(loaded.found);
}
TEST(WindowStateStoreTest, RoundTripsGeometryAndPresentationState) {
TemporaryDirectory temporary;
const std::filesystem::path path =
temporary.path() / "state/window-state.json";
PersistedWindowState expected;
expected.x = -1440;
expected.y = 120;
expected.width = 1440;
expected.height = 900;
expected.has_position = true;
expected.fullscreen = true;
expected.maximized = false;
const Status stored = StoreWindowState(path, expected);
ASSERT_TRUE(stored.ok()) << stored.message();
EXPECT_EQ(FileMode(path), 0600);
const WindowStateLoadResult loaded = LoadWindowState(path);
ASSERT_TRUE(loaded) << loaded.status.message();
ASSERT_TRUE(loaded.found);
EXPECT_EQ(loaded.state.x, expected.x);
EXPECT_EQ(loaded.state.y, expected.y);
EXPECT_EQ(loaded.state.width, expected.width);
EXPECT_EQ(loaded.state.height, expected.height);
EXPECT_TRUE(loaded.state.has_position);
EXPECT_TRUE(loaded.state.fullscreen);
EXPECT_FALSE(loaded.state.maximized);
}
TEST(WindowStateStoreTest,
DefersMaximizedRestoreUntilAfterStartupConstraints) {
PersistedWindowState windowed;
WindowStartupPresentationPlan plan =
PlanWindowStartupPresentation(windowed);
EXPECT_FALSE(plan.fullscreen_at_creation);
EXPECT_FALSE(plan.maximize_after_constraints);
PersistedWindowState maximized;
maximized.maximized = true;
plan = PlanWindowStartupPresentation(maximized);
EXPECT_FALSE(plan.fullscreen_at_creation);
EXPECT_TRUE(plan.maximize_after_constraints);
PersistedWindowState fullscreen_and_maximized;
fullscreen_and_maximized.fullscreen = true;
fullscreen_and_maximized.maximized = true;
plan = PlanWindowStartupPresentation(fullscreen_and_maximized);
EXPECT_TRUE(plan.fullscreen_at_creation);
EXPECT_FALSE(plan.maximize_after_constraints);
}
TEST(WindowStateStoreTest, RejectsMalformedAndOutOfRangeState) {
TemporaryDirectory temporary;
const std::filesystem::path path = temporary.path() / "window-state.json";
{
std::ofstream output(path);
output << "{not-json";
}
EXPECT_FALSE(LoadWindowState(path));
PersistedWindowState invalid;
invalid.width = 100000;
EXPECT_FALSE(StoreWindowState(path, invalid).ok());
// The same floor the live window is clamped to.
PersistedWindowState too_small;
too_small.width = kMinimumWindowWidth - 1;
EXPECT_FALSE(StoreWindowState(path, too_small).ok());
too_small.width = kMinimumWindowWidth;
too_small.height = kMinimumWindowHeight - 1;
EXPECT_FALSE(StoreWindowState(path, too_small).ok());
too_small.height = kMinimumWindowHeight;
EXPECT_TRUE(StoreWindowState(path, too_small).ok());
{
std::ofstream output(path);
output << R"({"schema_version":1,"fullscreen":false,)"
R"("maximized":false,"windowed":{"has_position":false,)"
R"("width":9223372036854775807,"height":720}})";
}
EXPECT_FALSE(LoadWindowState(path));
}
TEST(WindowStateStoreTest, RefusesSymlinkTargets) {
TemporaryDirectory temporary;
const std::filesystem::path outside = temporary.path() / "outside.json";
const std::filesystem::path path = temporary.path() / "window-state.json";
{
std::ofstream output(outside);
output << "preserve";
}
ASSERT_EQ(symlink(outside.c_str(), path.c_str()), 0);
PersistedWindowState state;
EXPECT_FALSE(StoreWindowState(path, state).ok());
EXPECT_FALSE(LoadWindowState(path));
std::ifstream input(outside);
std::string contents;
input >> contents;
EXPECT_EQ(contents, "preserve");
}
} // namespace
} // namespace window
} // namespace mocktail