Files
plezy/windows/runner/mpv/display_mode_manager_test.cpp
T

466 lines
19 KiB
C++

#include "display_mode_manager.h"
#include <cstdlib>
#include <iostream>
#include <map>
#include <string>
#include <vector>
namespace mpv {
namespace {
constexpr wchar_t kVersion[] = L"Version";
constexpr wchar_t kModeDeviceName[] = L"ModeDeviceName";
constexpr wchar_t kLegacyDeviceName[] = L"DeviceName";
constexpr wchar_t kHDRDeviceName[] = L"HDRDeviceName";
constexpr wchar_t kOriginalRefreshRate[] = L"OriginalRefreshRate";
constexpr wchar_t kOriginalWidth[] = L"OriginalWidth";
constexpr wchar_t kOriginalHeight[] = L"OriginalHeight";
constexpr wchar_t kOriginalHDR[] = L"OriginalHDREnabled";
constexpr wchar_t kModeChanged[] = L"ModeChanged";
constexpr wchar_t kHDRChanged[] = L"HDRChanged";
constexpr wchar_t kModeDevice[] = L"\\\\.\\DISPLAY1";
constexpr wchar_t kHDRDevice[] = L"\\\\.\\DISPLAY2";
void Check(bool condition, const char* message) {
if (!condition) {
std::cerr << "display_mode_manager_test: " << message << '\n';
std::exit(1);
}
}
class FakeRecoveryBackend final : public DisplayRecoveryBackend {
public:
std::map<std::wstring, DWORD> dwords;
std::map<std::wstring, std::wstring> strings;
std::map<std::wstring, bool> device_present = {{kModeDevice, true}, {kHDRDevice, true}};
std::vector<std::wstring> events;
std::wstring expected_mode_device = kModeDevice;
std::wstring expected_hdr_device = kHDRDevice;
bool mode_restore_succeeds = true;
bool hdr_restore_succeeds = true;
bool mode_marker_clear_succeeds = true;
bool hdr_marker_clear_succeeds = true;
bool delete_succeeds = true;
bool final_mode_marker_write_succeeds = true;
bool final_hdr_marker_write_succeeds = true;
int delete_attempts = 0;
void SeedBoth() {
dwords[kVersion] = 1;
dwords[kModeChanged] = 1;
dwords[kHDRChanged] = 1;
dwords[kOriginalWidth] = 3840;
dwords[kOriginalHeight] = 2160;
dwords[kOriginalRefreshRate] = 60;
dwords[kOriginalHDR] = 0;
strings[kModeDeviceName] = kModeDevice;
strings[kHDRDeviceName] = kHDRDevice;
}
bool RecordExists() const override { return !dwords.empty() || !strings.empty(); }
bool ReadDWORD(const wchar_t* value_name, DWORD& value) override {
const auto it = dwords.find(value_name);
if (it == dwords.end()) return false;
value = it->second;
return true;
}
bool ReadString(const wchar_t* value_name, std::wstring& value) override {
const auto it = strings.find(value_name);
if (it == strings.end()) return false;
value = it->second;
return true;
}
bool WriteDWORD(const wchar_t* value_name, DWORD value) override {
const std::wstring name(value_name);
events.push_back(L"write:" + name + L"=" + std::to_wstring(value));
if ((name == kModeChanged && value == 1 && !final_mode_marker_write_succeeds) ||
(name == kHDRChanged && value == 1 && !final_hdr_marker_write_succeeds)) {
return false;
}
dwords[name] = value;
return true;
}
bool WriteString(const wchar_t* value_name, const std::wstring& value) override {
const std::wstring name(value_name);
events.push_back(L"write:" + name);
strings[name] = value;
return true;
}
bool IsDevicePresent(const std::wstring& device_name) const override {
const auto it = device_present.find(device_name);
return it != device_present.end() && it->second;
}
bool RestoreMode(const std::wstring& device_name, DWORD width, DWORD height, DWORD refresh_rate) override {
Check(device_name == expected_mode_device, "mode restore must use its persisted display");
Check(width == 3840 && height == 2160 && refresh_rate == 60, "mode restore must use persisted originals");
events.push_back(L"restore:mode");
return mode_restore_succeeds;
}
bool RestoreHDR(const std::wstring& device_name, bool enabled) override {
Check(device_name == expected_hdr_device, "HDR restore must use its independently persisted display");
Check(!enabled, "HDR restore must use the persisted original state");
events.push_back(L"restore:hdr");
return hdr_restore_succeeds;
}
bool ClearMarker(const wchar_t* value_name) override {
const std::wstring name(value_name);
events.push_back(L"clear:" + name);
const bool succeeds = name == kModeChanged ? mode_marker_clear_succeeds : hdr_marker_clear_succeeds;
if (succeeds) dwords[name] = 0;
return succeeds;
}
bool DeleteRecord() override {
++delete_attempts;
events.push_back(L"delete");
if (!delete_succeeds) return false;
dwords.clear();
strings.clear();
return true;
}
};
size_t EventIndex(const std::vector<std::wstring>& events, const std::wstring& event) {
for (size_t index = 0; index < events.size(); ++index) {
if (events[index] == event) return index;
}
return events.size();
}
bool ApplyModeAfterPreparing(FakeRecoveryBackend& backend) {
if (!DisplayModeManager::PrepareModeRecovery(backend, kModeDevice, 3840, 2160, 60)) {
return false;
}
backend.events.push_back(L"os:mode");
return true;
}
bool ApplyHDRAfterPreparing(FakeRecoveryBackend& backend) {
if (!DisplayModeManager::PrepareHDRRecovery(backend, kHDRDevice, false)) return false;
backend.events.push_back(L"os:hdr");
return true;
}
void TestMarkersArePersistedBeforeMutation() {
FakeRecoveryBackend mode;
Check(ApplyModeAfterPreparing(mode), "a complete mode recovery record must admit the OS mutation");
const size_t mode_marker = EventIndex(mode.events, L"write:ModeChanged=1");
const size_t mode_os = EventIndex(mode.events, L"os:mode");
Check(mode_marker < mode_os, "the mode marker must be durable before the OS mutation");
Check(
EventIndex(mode.events, L"write:ModeDeviceName") < mode_marker &&
EventIndex(mode.events, L"write:OriginalWidth=3840") < mode_marker &&
EventIndex(mode.events, L"write:OriginalHeight=2160") < mode_marker &&
EventIndex(mode.events, L"write:OriginalRefreshRate=60") < mode_marker,
"all mode originals must precede the operation marker");
FakeRecoveryBackend hdr;
Check(ApplyHDRAfterPreparing(hdr), "a complete HDR recovery record must admit the OS mutation");
const size_t hdr_marker = EventIndex(hdr.events, L"write:HDRChanged=1");
Check(
EventIndex(hdr.events, L"write:HDRDeviceName") < hdr_marker &&
EventIndex(hdr.events, L"write:OriginalHDREnabled=0") < hdr_marker &&
hdr_marker < EventIndex(hdr.events, L"os:hdr"),
"the HDR original and marker must be durable before the OS mutation");
FakeRecoveryBackend failed_marker;
failed_marker.final_mode_marker_write_succeeds = false;
Check(
!ApplyModeAfterPreparing(failed_marker),
"an OS mutation must not run when its final recovery marker cannot be persisted");
Check(
EventIndex(failed_marker.events, L"os:mode") == failed_marker.events.size(),
"a failed marker write must leave the display untouched");
}
void TestMalformedRecordIsIgnored() {
FakeRecoveryBackend backend;
backend.SeedBoth();
backend.dwords[kVersion] = 2;
backend.strings[kLegacyDeviceName] = kModeDevice;
Check(!DisplayModeManager::RecoverIfNeeded(backend), "an unknown recovery version must be ignored");
Check(
EventIndex(backend.events, L"restore:mode") == backend.events.size() &&
EventIndex(backend.events, L"restore:hdr") == backend.events.size(),
"a malformed record must not reach display APIs");
Check(backend.delete_attempts == 1 && !backend.RecordExists(), "a malformed record must be discarded");
}
void TestValidModeSurvivesMalformedHDR() {
FakeRecoveryBackend backend;
backend.SeedBoth();
backend.dwords[kOriginalHDR] = 2;
Check(
DisplayModeManager::RecoverIfNeeded(backend),
"malformed HDR evidence must not discard an independently valid mode restore");
Check(
EventIndex(backend.events, L"restore:mode") < backend.events.size() &&
EventIndex(backend.events, L"restore:hdr") == backend.events.size(),
"only the valid mode operation may reach a display API");
Check(
EventIndex(backend.events, L"clear:HDRChanged") < backend.events.size(),
"the malformed HDR operation must be discarded independently");
}
void TestValidHDRSurvivesMalformedMode() {
FakeRecoveryBackend backend;
backend.SeedBoth();
backend.dwords.erase(kOriginalHeight);
Check(
DisplayModeManager::RecoverIfNeeded(backend),
"malformed mode evidence must not discard an independently valid HDR restore");
Check(
EventIndex(backend.events, L"restore:mode") == backend.events.size() &&
EventIndex(backend.events, L"restore:hdr") < backend.events.size(),
"only the valid HDR operation may reach a display API");
Check(
EventIndex(backend.events, L"clear:ModeChanged") < backend.events.size(),
"the malformed mode operation must be discarded independently");
}
void TestPreparationClearsMalformedSibling() {
FakeRecoveryBackend mode;
mode.SeedBoth();
mode.dwords[kModeChanged] = 0;
mode.dwords[kOriginalHDR] = 2;
Check(ApplyModeAfterPreparing(mode), "a malformed HDR sibling must not block a new valid mode operation");
Check(mode.dwords[kHDRChanged] == 0, "mode preparation must not preserve malformed HDR evidence");
FakeRecoveryBackend hdr;
hdr.SeedBoth();
hdr.dwords[kHDRChanged] = 0;
hdr.dwords.erase(kOriginalHeight);
Check(ApplyHDRAfterPreparing(hdr), "a malformed mode sibling must not block a new valid HDR operation");
Check(hdr.dwords[kModeChanged] == 0, "HDR preparation must not preserve malformed mode evidence");
}
void TestModeAndHDRRestoreIndependently() {
FakeRecoveryBackend backend;
backend.SeedBoth();
backend.mode_restore_succeeds = false;
Check(!DisplayModeManager::RecoverIfNeeded(backend), "one failed restore must retain the record");
Check(
EventIndex(backend.events, L"restore:mode") < backend.events.size() &&
EventIndex(backend.events, L"restore:hdr") < backend.events.size(),
"mode failure must not prevent the independent HDR restore");
Check(backend.dwords[kModeChanged] == 1, "the failed mode marker must remain set");
Check(backend.dwords[kHDRChanged] == 0, "the successful HDR marker must be cleared");
backend.events.clear();
backend.mode_restore_succeeds = true;
Check(DisplayModeManager::RecoverIfNeeded(backend), "a later pass must finish the retained mode restore");
Check(
EventIndex(backend.events, L"restore:mode") < backend.events.size() &&
EventIndex(backend.events, L"restore:hdr") == backend.events.size(),
"a later pass must not repeat the completed HDR restore");
}
void TestFailedRestoreRemainsForTopologyRetry() {
FakeRecoveryBackend backend;
backend.SeedBoth();
backend.dwords[kHDRChanged] = 0;
backend.device_present[kModeDevice] = false;
Check(!DisplayModeManager::RecoverIfNeeded(backend), "an absent display must retain its marked restore");
Check(backend.dwords[kModeChanged] == 1, "an absent display must keep its operation marker");
Check(
EventIndex(backend.events, L"restore:mode") == backend.events.size(),
"an absent display must not call its restore API");
backend.events.clear();
backend.device_present[kModeDevice] = true;
Check(
DisplayModeManager::RecoverIfNeeded(backend), "a synchronous topology retry must restore a reconnected display");
Check(
EventIndex(backend.events, L"restore:mode") < backend.events.size(),
"the topology retry must attempt the retained restore");
}
void TestMarkerClearFailureRemainsRetryable() {
FakeRecoveryBackend backend;
backend.SeedBoth();
backend.dwords[kHDRChanged] = 0;
backend.mode_marker_clear_succeeds = false;
Check(!DisplayModeManager::RecoverIfNeeded(backend), "marker persistence is part of recovery completion");
Check(backend.dwords[kModeChanged] == 1, "a failed marker clear must retain idempotent recovery evidence");
backend.events.clear();
backend.mode_marker_clear_succeeds = true;
Check(DisplayModeManager::RecoverIfNeeded(backend), "a later pass must retry after marker persistence failure");
Check(
EventIndex(backend.events, L"restore:mode") < backend.events.size(),
"the retained marker must cause the restore to be retried");
}
void TestLifecycleCleanupPreservesPersistedSibling() {
FakeRecoveryBackend mode_completed;
mode_completed.SeedBoth();
Check(
DisplayModeManager::CompleteRecoveryOperationForTesting(mode_completed, true),
"successful mode cleanup must durably clear its own marker");
Check(
mode_completed.dwords[kModeChanged] == 0 && mode_completed.dwords[kHDRChanged] == 1,
"mode cleanup must preserve a persisted HDR sibling even without local HDR ownership");
Check(
mode_completed.dwords[kOriginalHDR] == 0 && mode_completed.strings[kHDRDeviceName] == kHDRDevice &&
mode_completed.delete_attempts == 0,
"mode cleanup must retain the HDR original and avoid deleting its record");
FakeRecoveryBackend hdr_failed_apply;
hdr_failed_apply.SeedBoth();
Check(
DisplayModeManager::CompleteRecoveryOperationForTesting(hdr_failed_apply, false),
"failed HDR apply cleanup must durably clear its own marker");
Check(
hdr_failed_apply.dwords[kHDRChanged] == 0 && hdr_failed_apply.dwords[kModeChanged] == 1,
"HDR cleanup must preserve a persisted mode sibling even without local mode ownership");
Check(
hdr_failed_apply.dwords[kOriginalWidth] == 3840 && hdr_failed_apply.strings[kModeDeviceName] == kModeDevice &&
hdr_failed_apply.delete_attempts == 0,
"HDR cleanup must retain the mode original and avoid deleting its record");
}
void TestReleasedLiveOperationRecoversAfterReconnect() {
FakeRecoveryBackend backend;
backend.SeedBoth();
backend.device_present[kModeDevice] = false;
Check(
!DisplayModeManager::RecoverIfNeededForTesting(backend, true, true),
"topology recovery must not take either genuinely live operation");
Check(backend.events.empty(), "live operations must not reach restore or persistence APIs");
Check(
!DisplayModeManager::RecoverIfNeededForTesting(backend, false, true),
"a released operation must remain marked while its target is absent");
Check(
backend.dwords[kModeChanged] == 1 && backend.dwords[kHDRChanged] == 1,
"an absent released mode and its live HDR sibling must both retain their markers");
backend.events.clear();
backend.device_present[kModeDevice] = true;
Check(
DisplayModeManager::RecoverIfNeededForTesting(backend, false, true),
"a topology retry must restore the released mode after reconnect");
Check(
EventIndex(backend.events, L"restore:mode") < backend.events.size() &&
EventIndex(backend.events, L"restore:hdr") == backend.events.size(),
"reconnect recovery must restore the released mode without stealing live HDR");
Check(
backend.dwords[kModeChanged] == 0 && backend.dwords[kHDRChanged] == 1 && backend.delete_attempts == 0,
"reconnect recovery must preserve the genuinely live sibling record");
}
void TestVersionlessModeRecoveryAndCleanup() {
FakeRecoveryBackend backend;
backend.dwords[kModeChanged] = 1;
backend.dwords[kHDRChanged] = 0;
backend.dwords[kOriginalWidth] = 3840;
backend.dwords[kOriginalHeight] = 2160;
backend.dwords[kOriginalRefreshRate] = 60;
backend.strings[kLegacyDeviceName] = kModeDevice;
Check(DisplayModeManager::RecoverIfNeeded(backend), "the released versionless mode layout must be recovered");
Check(
EventIndex(backend.events, L"restore:mode") < backend.events.size(),
"versionless mode recovery must use the backend restore");
Check(
backend.delete_attempts == 1 && !backend.RecordExists(),
"completed versionless mode recovery must clean the legacy DeviceName and record");
}
void TestVersionlessHDRRecoveryAndCleanup() {
FakeRecoveryBackend backend;
backend.dwords[kModeChanged] = 0;
backend.dwords[kHDRChanged] = 1;
backend.dwords[kOriginalHDR] = 0;
backend.strings[kLegacyDeviceName] = kHDRDevice;
Check(DisplayModeManager::RecoverIfNeeded(backend), "the released versionless HDR layout must be recovered");
Check(
EventIndex(backend.events, L"restore:hdr") < backend.events.size(),
"versionless HDR recovery must use the backend restore");
Check(
backend.delete_attempts == 1 && !backend.RecordExists(),
"completed versionless HDR recovery must clean the legacy DeviceName and record");
}
void TestVersionlessModeAndHDRUseSharedDevice() {
FakeRecoveryBackend backend;
backend.dwords[kModeChanged] = 1;
backend.dwords[kHDRChanged] = 1;
backend.dwords[kOriginalWidth] = 3840;
backend.dwords[kOriginalHeight] = 2160;
backend.dwords[kOriginalRefreshRate] = 60;
backend.dwords[kOriginalHDR] = 0;
backend.strings[kLegacyDeviceName] = kModeDevice;
backend.expected_hdr_device = kModeDevice;
Check(
DisplayModeManager::RecoverIfNeeded(backend),
"both versionless operations must recover from their shared DeviceName");
Check(
EventIndex(backend.events, L"restore:mode") < backend.events.size() &&
EventIndex(backend.events, L"restore:hdr") < backend.events.size(),
"the released shared-device layout must restore mode and HDR independently");
Check(
backend.delete_attempts == 1 && !backend.RecordExists(),
"shared versionless recovery must remove the legacy record after both markers clear");
}
void TestCleanupFailureDoesNotBlockNewOverride() {
FakeRecoveryBackend backend;
backend.SeedBoth();
backend.dwords[kHDRChanged] = 0;
backend.delete_succeeds = false;
Check(
DisplayModeManager::RecoverIfNeeded(backend),
"successful restoration must complete even when stale-value deletion fails");
Check(backend.dwords[kModeChanged] == 0, "the successful restore marker must be clear");
Check(backend.delete_attempts == 1, "completed recovery must make one best-effort cleanup attempt");
backend.events.clear();
Check(ApplyModeAfterPreparing(backend), "failed cleanup must not block persistence or admission of a fresh override");
Check(
backend.dwords[kModeChanged] == 1 &&
EventIndex(backend.events, L"write:ModeChanged=1") < EventIndex(backend.events, L"os:mode"),
"the fresh override must replace stale values with a pre-mutation marker");
}
} // namespace
} // namespace mpv
int main() {
mpv::TestMarkersArePersistedBeforeMutation();
mpv::TestMalformedRecordIsIgnored();
mpv::TestValidModeSurvivesMalformedHDR();
mpv::TestValidHDRSurvivesMalformedMode();
mpv::TestPreparationClearsMalformedSibling();
mpv::TestModeAndHDRRestoreIndependently();
mpv::TestFailedRestoreRemainsForTopologyRetry();
mpv::TestMarkerClearFailureRemainsRetryable();
mpv::TestLifecycleCleanupPreservesPersistedSibling();
mpv::TestReleasedLiveOperationRecoversAfterReconnect();
mpv::TestVersionlessModeRecoveryAndCleanup();
mpv::TestVersionlessHDRRecoveryAndCleanup();
mpv::TestVersionlessModeAndHDRUseSharedDevice();
mpv::TestCleanupFailureDoesNotBlockNewOverride();
std::cout << "display_mode_manager_test: PASS\n";
return 0;
}