blob: b5bdcd04ec767d954a256cffda1865ea62b29cdd [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/win/dark_mode_support.h"
#include <windows.h>
#include "base/native_library.h"
#include "base/scoped_native_library.h"
#include "base/test/gtest_util.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base::win {
namespace {
constexpr wchar_t kWndClassName[] = L"DarkModeWClass";
class DarkModeSupportTest : public testing::Test {
protected:
DarkModeSupportTest() {
ux_theme_lib_ = base::ScopedNativeLibrary(
base::LoadSystemLibrary(L"uxtheme.dll", &error_));
}
~DarkModeSupportTest() override = default;
void SetUp() override {
testing::Test::SetUp();
// Do this here since the assert cannot live in the constructor.
ASSERT_FALSE(error_.code)
<< "Failed to load uxtheme.dll with error " << error_.ToString();
}
void TearDown() override {
// Return the process to the pre-allowed dark mode state.
AllowDarkModeForApp(false);
testing::Test::TearDown();
}
private:
base::NativeLibraryLoadError error_;
base::ScopedNativeLibrary ux_theme_lib_;
};
class ScopedWindowClass {
public:
explicit ScopedWindowClass(const WNDCLASSEX& wnd_class)
: instance_(wnd_class.hInstance),
wnd_class_name_(wnd_class.lpszClassName) {
DoRegisterClass(wnd_class);
}
~ScopedWindowClass() { ::UnregisterClass(wnd_class_name_, instance_); }
private:
void DoRegisterClass(const WNDCLASSEX& wnd_class) {
ASSERT_TRUE(::RegisterClassEx(&wnd_class));
}
const HMODULE instance_;
const wchar_t* wnd_class_name_;
};
} // namespace
TEST_F(DarkModeSupportTest, TestIsDarkModeAvailable) {
// The return value is irrelevant here. This only tests that this call can be
// make without crashing or otherwise behaving badly.
IsDarkModeAvailable();
}
TEST_F(DarkModeSupportTest, TestAllowDarkModeForApp) {
// This call should always succeed and not crash or behave badly.
AllowDarkModeForApp(true);
}
TEST_F(DarkModeSupportTest, TestAllowDarkModeForWindowNoCrash) {
HINSTANCE instance = ::GetModuleHandle(nullptr);
WNDCLASSEX wnd_class = {
.cbSize = sizeof(wnd_class),
.style = CS_HREDRAW | CS_VREDRAW,
.lpfnWndProc = ::DefWindowProc,
.hInstance = instance,
.hIcon = ::LoadIcon(NULL, IDI_APPLICATION),
.hCursor = ::LoadCursor(NULL, IDC_ARROW),
.hbrBackground = static_cast<HBRUSH>(::GetStockObject(WHITE_BRUSH)),
.lpszClassName = kWndClassName,
};
ScopedWindowClass scoped_window_class = ScopedWindowClass(wnd_class);
HWND hwnd =
::CreateWindow(kWndClassName, L"DarkModeTest", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
nullptr, nullptr, instance, nullptr);
ASSERT_TRUE(hwnd) << "::CreateWindow failed with error " << ::GetLastError();
// The "dark mode" calls below shouldn't crash. This doesn't test whether or
// not they actually work, rather only that they don't crash or otherwise
// behave badly.
AllowDarkModeForApp(true);
AllowDarkModeForWindow(hwnd, true);
::DestroyWindow(hwnd);
}
} // namespace base::win