// 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 #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(::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