[Test] Add tests for widgets code
This creates a vbam-wx-widgets target for the custom widgets code and adds tests for them.
This commit is contained in:
parent
5766b9b9c7
commit
4f1a5dd726
|
@ -1,4 +1,4 @@
|
|||
name: macOS Latest Build
|
||||
name: macOS Latest
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
|
@ -60,4 +60,4 @@ jobs:
|
|||
- if: matrix.build_options == 'default'
|
||||
name: Run tests
|
||||
run: >-
|
||||
nix-shell --command 'cd build && ctest -j'
|
||||
nix-shell --command 'cd build && ctest -j --output-on-failure'
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
name: MSYS2 Build
|
||||
name: MSYS2
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
name: Ubuntu Latest Build
|
||||
name: Ubuntu Latest
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
|
@ -45,6 +45,9 @@ jobs:
|
|||
run: >-
|
||||
bash installdeps; if [ "${{ matrix.build_compiler }}" = clang ]; then sudo apt -y install clang; fi
|
||||
|
||||
- name: Install xvfb
|
||||
run: sudo apt -y install xvfb
|
||||
|
||||
# CMake build
|
||||
- if: matrix.build_options != 'libretro'
|
||||
name: Configure CMake
|
||||
|
@ -65,4 +68,4 @@ jobs:
|
|||
# Run tests
|
||||
- if: matrix.build_options == 'default'
|
||||
name: Run tests
|
||||
run: cd build && ctest -j
|
||||
run: cd build && xvfb-run ctest -j --output-on-failure
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
name: Visual Studio Build
|
||||
name: Visual Studio
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
|
@ -57,4 +57,4 @@ jobs:
|
|||
# Run tests
|
||||
- if: matrix.build_options == 'default' && matrix.msvc_arch != 'amd64_arm64'
|
||||
name: Run tests
|
||||
run: cd build && ctest -j
|
||||
run: cd build && ctest -j --output-on-failure
|
||||
|
|
|
@ -51,6 +51,28 @@ if(NOT DEFINED VCPKG_TARGET_TRIPLET)
|
|||
message(STATUS "Inferred VCPKG_TARGET_TRIPLET=${VCPKG_TARGET_TRIPLET}")
|
||||
endif()
|
||||
|
||||
function(vcpkg_seconds)
|
||||
if(CMAKE_HOST_SYSTEM MATCHES Windows OR ((NOT DEFINED CMAKE_HOST_SYSTEM) AND WIN32))
|
||||
execute_process(
|
||||
COMMAND cmd /c echo %TIME:~0,8%
|
||||
OUTPUT_VARIABLE time
|
||||
)
|
||||
else()
|
||||
execute_process(
|
||||
COMMAND date +%H:%M:%S
|
||||
OUTPUT_VARIABLE time
|
||||
)
|
||||
endif()
|
||||
|
||||
string(SUBSTRING "${time}" 0 2 hours)
|
||||
string(SUBSTRING "${time}" 3 2 minutes)
|
||||
string(SUBSTRING "${time}" 6 2 secs)
|
||||
|
||||
math(EXPR seconds "(${hours} * 60 * 60) + (${minutes} * 60) + ${secs}")
|
||||
|
||||
set(seconds ${seconds} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(vcpkg_check_git_status git_status)
|
||||
# The VS vcpkg component cannot be written to without elevation.
|
||||
if(NOT git_status EQUAL 0 AND NOT VCPKG_ROOT MATCHES "Visual Studio")
|
||||
|
|
|
@ -60,3 +60,5 @@ target_link_libraries(vbam-core-base
|
|||
PRIVATE vbam-fex stb-image
|
||||
PUBLIC ${ZLIB_LIBRARY}
|
||||
)
|
||||
|
||||
add_subdirectory(test)
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
#define VBAM_IMMEDIATE_CRASH_DETAIL() __builtin_trap()
|
||||
#define VBAM_INTRINSIC_UNREACHABLE_DETAIL() __builtin_unreachable()
|
||||
|
||||
#elif defined(_MSC_VER) // defined(__GNUC__) || defined(__clang__)
|
||||
#elif defined(_MSC_VER) // defined(__GNUC__) || defined(__clang__)
|
||||
|
||||
// MSVC.
|
||||
#define VBAM_IMMEDIATE_CRASH_DETAIL() __debugbreak()
|
||||
|
@ -33,29 +33,25 @@
|
|||
#define VBAM_STRINGIFY(x) VBAM_STRINGIFY_DETAIL(x)
|
||||
|
||||
#define VBAM_REQUIRE_SEMICOLON_DETAIL() \
|
||||
static_assert(true, "Require a semicolon after macros invocation.")
|
||||
static_assert(true, "Require a semicolon after macros invocation.")
|
||||
|
||||
#define VBAM_CHECK(condition) \
|
||||
if (!(condition)) { \
|
||||
fputs("CHECK failed at " __FILE__ ":" VBAM_STRINGIFY(__LINE__) ": " #condition "\n", stderr); \
|
||||
VBAM_IMMEDIATE_CRASH_DETAIL(); \
|
||||
} \
|
||||
VBAM_REQUIRE_SEMICOLON_DETAIL()
|
||||
|
||||
#define VBAM_NOTREACHED_MESSAGE_DETAIL() \
|
||||
fputs("NOTREACHED code reached at " __FILE__ ":" VBAM_STRINGIFY(__LINE__) "\n", stderr)
|
||||
#define VBAM_CHECK(condition) \
|
||||
if (!(condition)) { \
|
||||
fputs("CHECK failed at " __FILE__ ":" VBAM_STRINGIFY(__LINE__) ": " #condition "\n", \
|
||||
stderr); \
|
||||
VBAM_IMMEDIATE_CRASH_DETAIL(); \
|
||||
} \
|
||||
VBAM_REQUIRE_SEMICOLON_DETAIL()
|
||||
|
||||
#if defined(DEBUG)
|
||||
|
||||
#define VBAM_NOTREACHED() \
|
||||
VBAM_NOTREACHED_MESSAGE_DETAIL(); \
|
||||
VBAM_IMMEDIATE_CRASH_DETAIL()
|
||||
#define VBAM_NOTREACHED() \
|
||||
fputs("NOTREACHED code reached at " __FILE__ ":" VBAM_STRINGIFY(__LINE__) "\n", stderr); \
|
||||
VBAM_IMMEDIATE_CRASH_DETAIL()
|
||||
|
||||
#else // defined(DEBUG)
|
||||
|
||||
#define VBAM_NOTREACHED() \
|
||||
VBAM_NOTREACHED_MESSAGE_DETAIL(); \
|
||||
VBAM_INTRINSIC_UNREACHABLE_DETAIL()
|
||||
#define VBAM_NOTREACHED() VBAM_INTRINSIC_UNREACHABLE_DETAIL()
|
||||
|
||||
#endif // defined(DEBUG)
|
||||
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
# This defines the `vbam-core-base-test` library.
|
||||
|
||||
if(NOT BUILD_TESTING)
|
||||
return()
|
||||
endif()
|
||||
|
||||
add_library(vbam-core-base-test
|
||||
INTERFACE
|
||||
notreached.h)
|
||||
|
||||
target_link_libraries(vbam-core-base-test
|
||||
INTERFACE GTest::gtest)
|
|
@ -0,0 +1,22 @@
|
|||
#ifndef VBAM_CORE_BASE_TEST_NOTREACHED_H_
|
||||
#define VBAM_CORE_BASE_TEST_NOTREACHED_H_
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#if defined(DEBUG)
|
||||
|
||||
#define VBAM_EXPECT_NOTREACHED(statement) EXPECT_DEATH(statement, "NOTREACHED")
|
||||
|
||||
#else // defined(DEBUG)
|
||||
|
||||
// There is no way to test this in release builds as the compiler might optimize
|
||||
// this code path away. Eat the statement to avoid unused variable warnings.
|
||||
#define VBAM_EXPECT_NOTREACHED(statement) \
|
||||
if constexpr (false) { \
|
||||
statement; \
|
||||
} \
|
||||
static_assert(true, "")
|
||||
|
||||
#endif // defined(DEBUG)
|
||||
|
||||
#endif // VBAM_CORE_BASE_TEST_NOTREACHED_H_
|
|
@ -46,33 +46,6 @@ set(VBAM_WX_COMMON
|
|||
viewsupt.h
|
||||
wayland.cpp
|
||||
wayland.h
|
||||
# from external source with minor modifications
|
||||
widgets/checkedlistctrl.cpp
|
||||
widgets/checkedlistctrl.h
|
||||
widgets/client-data.h
|
||||
widgets/dpi-support.h
|
||||
widgets/event-handler-provider.h
|
||||
widgets/group-check-box.cpp
|
||||
widgets/group-check-box.h
|
||||
widgets/keep-on-top-styler.cpp
|
||||
widgets/keep-on-top-styler.h
|
||||
widgets/option-validator.cpp
|
||||
widgets/option-validator.h
|
||||
widgets/render-plugin.cpp
|
||||
widgets/render-plugin.h
|
||||
widgets/user-input-ctrl.cpp
|
||||
widgets/user-input-ctrl.h
|
||||
widgets/user-input-event.cpp
|
||||
widgets/user-input-event.h
|
||||
widgets/sdl-poller.cpp
|
||||
widgets/sdl-poller.h
|
||||
widgets/shortcut-menu-bar.cpp
|
||||
widgets/shortcut-menu-bar.h
|
||||
widgets/utils.cpp
|
||||
widgets/utils.h
|
||||
widgets/webupdatedef.h
|
||||
widgets/wxmisc.h
|
||||
widgets/wxmisc.cpp
|
||||
wxhead.h
|
||||
wxlogdebug.h
|
||||
wxvbam.cpp
|
||||
|
@ -253,6 +226,9 @@ function(configure_wx_target target)
|
|||
endif()
|
||||
endfunction()
|
||||
|
||||
# Core emulator.
|
||||
_add_link_libraries(vbam-core)
|
||||
|
||||
# Nonstd.
|
||||
_add_link_libraries(nonstd-lib)
|
||||
_add_include_directories(${NONSTD_INCLUDE_DIR})
|
||||
|
@ -311,6 +287,7 @@ endfunction()
|
|||
# Sub-projects.
|
||||
add_subdirectory(test)
|
||||
add_subdirectory(config)
|
||||
add_subdirectory(widgets)
|
||||
|
||||
set(VBAM_ICON visualboyadvance-m.icns)
|
||||
set(VBAM_ICON_PATH ${CMAKE_CURRENT_SOURCE_DIR}/icons/${VBAM_ICON})
|
||||
|
@ -326,13 +303,13 @@ target_include_directories(visualboyadvance-m PRIVATE ${SDL2_INCLUDE_DIRS})
|
|||
|
||||
target_link_libraries(
|
||||
visualboyadvance-m
|
||||
vbam-core
|
||||
vbam-components-draw-text
|
||||
vbam-components-filters
|
||||
vbam-components-filters-agb
|
||||
vbam-components-filters-interframe
|
||||
vbam-components-user-config
|
||||
vbam-wx-config
|
||||
vbam-wx-widgets
|
||||
)
|
||||
|
||||
# adjust link command when making a static binary for gcc
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# This defines the vbam-wx-config target and the
|
||||
# `VBAM_LOCALIZABLE_WX_CONFIG_FILES` variable, containing the list of
|
||||
# `VBAM_LOCALIZABLE_WX_CONFIG_FILES` variable, containing the list of
|
||||
# localizable files in the vbam-wx-config target.
|
||||
|
||||
# I don't like duplicating/triplicating code, so I only declare
|
||||
|
@ -61,15 +61,9 @@ target_sources(vbam-wx-config
|
|||
user-input.h
|
||||
)
|
||||
|
||||
target_link_libraries(vbam-wx-config
|
||||
PUBLIC
|
||||
nonstd-lib
|
||||
vbam-core
|
||||
)
|
||||
|
||||
configure_wx_target(vbam-wx-config)
|
||||
|
||||
if (BUILD_TESTING)
|
||||
if(BUILD_TESTING)
|
||||
add_executable(vbam-wx-config-tests
|
||||
bindings-test.cpp
|
||||
command-test.cpp
|
||||
|
@ -79,10 +73,12 @@ if (BUILD_TESTING)
|
|||
user-input-test.cpp
|
||||
)
|
||||
target_link_libraries(vbam-wx-config-tests
|
||||
vbam-core
|
||||
# Test deps.
|
||||
vbam-core-fake
|
||||
vbam-wx-config
|
||||
vbam-wx-fake-opts
|
||||
|
||||
# Target deps.
|
||||
vbam-wx-config
|
||||
GTest::gtest_main
|
||||
)
|
||||
|
||||
|
|
|
@ -135,7 +135,8 @@ TEST_F(GamepadTest, NonDefaultInput) {
|
|||
const config::KeyboardInput f1(WXK_F1);
|
||||
|
||||
// Assign F1 to "Up".
|
||||
bindings()->AssignInputToCommand(f1, config::GameCommand(config::GameJoy(0), config::GameKey::Up));
|
||||
bindings()->AssignInputToCommand(f1,
|
||||
config::GameCommand(config::GameJoy(0), config::GameKey::Up));
|
||||
|
||||
// Press F1, the up key should be pressed.
|
||||
EXPECT_TRUE(gamepad()->OnInputPressed(f1));
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
#include "core/base/check.h"
|
||||
#include "wx/config/option.h"
|
||||
|
||||
#include "core/base/check.h"
|
||||
|
||||
namespace config {
|
||||
|
||||
// An Option::Observer that calls a callback when an option has changed.
|
||||
|
|
|
@ -6,10 +6,8 @@ if(NOT BUILD_TESTING)
|
|||
endif()
|
||||
|
||||
add_library(vbam-wx-fake-opts OBJECT)
|
||||
|
||||
target_sources(vbam-wx-fake-opts
|
||||
PRIVATE
|
||||
fake_opts.cpp
|
||||
fake-opts.cpp
|
||||
)
|
||||
|
||||
configure_wx_target(vbam-wx-fake-opts)
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
# This defines the vbam-wx-widgets target.
|
||||
# This does not export any localizable file as there is no localized string
|
||||
# in this target.
|
||||
|
||||
add_library(vbam-wx-widgets OBJECT)
|
||||
|
||||
target_sources(vbam-wx-widgets
|
||||
PRIVATE
|
||||
# from external source with minor modifications
|
||||
checkedlistctrl.cpp
|
||||
group-check-box.cpp
|
||||
keep-on-top-styler.cpp
|
||||
option-validator.cpp
|
||||
render-plugin.cpp
|
||||
user-input-ctrl.cpp
|
||||
user-input-event.cpp
|
||||
sdl-poller.cpp
|
||||
shortcut-menu-bar.cpp
|
||||
utils.cpp
|
||||
wxmisc.cpp
|
||||
|
||||
PUBLIC
|
||||
# from external source with minor modifications
|
||||
checkedlistctrl.h
|
||||
client-data.h
|
||||
dpi-support.h
|
||||
event-handler-provider.h
|
||||
group-check-box.h
|
||||
keep-on-top-styler.h
|
||||
option-validator.h
|
||||
render-plugin.h
|
||||
user-input-ctrl.h
|
||||
user-input-event.h
|
||||
sdl-poller.h
|
||||
shortcut-menu-bar.h
|
||||
utils.h
|
||||
wxmisc.h
|
||||
)
|
||||
|
||||
target_link_libraries(vbam-wx-widgets PUBLIC vbam-wx-config)
|
||||
configure_wx_target(vbam-wx-widgets)
|
||||
|
||||
if(BUILD_TESTING)
|
||||
add_executable(vbam-wx-widgets-tests
|
||||
client-data-test.cpp
|
||||
group-check-box-test.cpp
|
||||
keep-on-top-styler-test.cpp
|
||||
option-validator-test.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(vbam-wx-widgets-tests
|
||||
# Test deps.
|
||||
vbam-core-base-test
|
||||
vbam-core-fake
|
||||
vbam-wx-fake-opts
|
||||
vbam-wx-widgets-test-fixture
|
||||
|
||||
# Target deps.
|
||||
vbam-wx-config
|
||||
vbam-wx-widgets
|
||||
GTest::gtest_main
|
||||
)
|
||||
|
||||
configure_wx_target(vbam-wx-widgets-tests)
|
||||
if (NOT CMAKE_CROSSCOMPILING)
|
||||
gtest_discover_tests(vbam-wx-widgets-tests)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_subdirectory(test)
|
|
@ -13,10 +13,21 @@
|
|||
#define VBAM_WX_WIDGETS_CHECKEDLISTCTRL_H_
|
||||
|
||||
// wxWidgets headers
|
||||
#include "wx/widgets/webupdatedef.h" // for the WXDLLIMPEXP_WEBUPDATE macro
|
||||
#include <wx/imaglist.h>
|
||||
#include <wx/listctrl.h>
|
||||
|
||||
// this will never be part of a DLL
|
||||
#define WXDLLIMPEXP_WEBUPDATE
|
||||
// why would I include it and not enable it?
|
||||
#define wxUSE_CHECKEDLISTCTRL 1
|
||||
// enable customizations:
|
||||
// - include wx/settings.h (bugfix; always enabled)
|
||||
// - make a dynamic class so it can be subclass in xrc
|
||||
// - only make col0 checkable
|
||||
// - use "native" checkbox (also requires CLC_USE_SYSICONS)
|
||||
#define CLC_VBAM_USAGE 1
|
||||
#define CLC_USE_SYSICONS 1
|
||||
|
||||
#if wxUSE_CHECKEDLISTCTRL
|
||||
|
||||
// image indexes (used internally by wxCheckedListCtrl)
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
#include "wx/widgets/client-data.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <wx/window.h>
|
||||
|
||||
#include "wx/config/user-input.h"
|
||||
|
||||
namespace widgets {
|
||||
|
||||
// Test the ClientData class with a simple type.
|
||||
TEST(ClientDataTest, Int) {
|
||||
std::unique_ptr<wxWindow> window(std::make_unique<wxWindow>());
|
||||
window->SetClientObject(new ClientData<int>(42));
|
||||
|
||||
EXPECT_EQ(ClientData<int>::From(window.get()), 42);
|
||||
}
|
||||
|
||||
// Test the ClientData class with a complex type.
|
||||
TEST(ClientDataTest, Object) {
|
||||
std::unique_ptr<wxWindow> window(std::make_unique<wxWindow>());
|
||||
window->SetClientObject(new ClientData<config::UserInput>(config::KeyboardInput('4')));
|
||||
|
||||
EXPECT_EQ(ClientData<config::UserInput>::From(window.get()).device(),
|
||||
config::UserInput::Device::Keyboard);
|
||||
}
|
||||
|
||||
} // namespace widgets
|
|
@ -0,0 +1,27 @@
|
|||
#include "wx/widgets/group-check-box.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <wx/frame.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/xrc/xmlres.h>
|
||||
|
||||
#include "wx/widgets/test/widgets-test.h"
|
||||
|
||||
namespace widgets {
|
||||
|
||||
TEST_F(WidgetsTest, GroupCheckBoxTest) {
|
||||
// Add 2 GroupCheckBoxes to the frame, `frame()` takes ownership here.
|
||||
GroupCheckBox* check_box_1 = new GroupCheckBox(frame(), XRCID("One"), "One");
|
||||
GroupCheckBox* check_box_2 = new GroupCheckBox(frame(), XRCID("Two"), "Two");
|
||||
|
||||
// Tick one checkbox and check the other is unticked.
|
||||
check_box_1->SetValue(true);
|
||||
EXPECT_FALSE(check_box_2->GetValue());
|
||||
|
||||
// And vice-versa.
|
||||
check_box_2->SetValue(true);
|
||||
EXPECT_FALSE(check_box_1->GetValue());
|
||||
}
|
||||
|
||||
} // namespace widgets
|
|
@ -0,0 +1,37 @@
|
|||
#include "wx/widgets/keep-on-top-styler.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <wx/frame.h>
|
||||
#include <wx/xrc/xmlres.h>
|
||||
|
||||
#include "wx/config/option-proxy.h"
|
||||
#include "wx/widgets/test/widgets-test.h"
|
||||
|
||||
namespace widgets {
|
||||
|
||||
TEST_F(WidgetsTest, KeepOnTopStyler) {
|
||||
// Enable the keep on top option.
|
||||
OPTION(kDispKeepOnTop) = true;
|
||||
|
||||
// Create a Frame, it should not have the wxSTAY_ON_TOP style.
|
||||
EXPECT_EQ(frame()->GetWindowStyle() & wxSTAY_ON_TOP, 0);
|
||||
|
||||
// Add a KeepOnTopStyler to the frame.
|
||||
KeepOnTopStyler styler(frame());
|
||||
|
||||
// Send the Show event to the frame.
|
||||
wxShowEvent show_event(wxEVT_SHOW, true);
|
||||
frame()->GetEventHandler()->ProcessEvent(show_event);
|
||||
|
||||
// The frame should have the wxSTAY_ON_TOP style.
|
||||
EXPECT_EQ(frame()->GetWindowStyle() & wxSTAY_ON_TOP, wxSTAY_ON_TOP);
|
||||
|
||||
// Disable the keep on top option.
|
||||
OPTION(kDispKeepOnTop) = false;
|
||||
|
||||
// The frame should no longer have the wxSTAY_ON_TOP style.
|
||||
EXPECT_EQ(frame()->GetWindowStyle() & wxSTAY_ON_TOP, 0);
|
||||
}
|
||||
|
||||
} // namespace widgets
|
|
@ -0,0 +1,156 @@
|
|||
#include "wx/widgets/option-validator.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <wx/checkbox.h>
|
||||
#include <wx/choice.h>
|
||||
#include <wx/frame.h>
|
||||
#include <wx/spinctrl.h>
|
||||
#include <wx/window.h>
|
||||
#include <wx/xrc/xmlres.h>
|
||||
|
||||
#include "core/base/test/notreached.h"
|
||||
#include "wx/config/option.h"
|
||||
#include "wx/widgets/test/widgets-test.h"
|
||||
|
||||
namespace widgets {
|
||||
|
||||
TEST_F(WidgetsTest, OptionSelectedValidator) {
|
||||
wxCheckBox* check_box_0 = new wxCheckBox(frame(), XRCID("Zero"), "Zero");
|
||||
wxCheckBox* check_box_1 = new wxCheckBox(frame(), XRCID("One"), "One");
|
||||
config::Option* option = config::Option::ByID(config::OptionID::kPrefCaptureFormat);
|
||||
|
||||
check_box_0->SetValidator(OptionSelectedValidator(config::OptionID::kPrefCaptureFormat, 0));
|
||||
check_box_1->SetValidator(OptionSelectedValidator(config::OptionID::kPrefCaptureFormat, 1));
|
||||
|
||||
// Tick the first checkbox, the second should be unticked.
|
||||
check_box_0->SetValue(true);
|
||||
frame()->TransferDataFromWindow();
|
||||
EXPECT_EQ(option->GetUnsigned(), 0);
|
||||
EXPECT_FALSE(check_box_1->GetValue());
|
||||
|
||||
// And vice-versa.
|
||||
check_box_1->SetValue(true);
|
||||
frame()->TransferDataFromWindow();
|
||||
EXPECT_EQ(option->GetUnsigned(), 1);
|
||||
EXPECT_FALSE(check_box_0->GetValue());
|
||||
|
||||
// Set the kPrefCaptureFormat option to 0, the first checkbox should be ticked.
|
||||
option->SetUnsigned(0);
|
||||
frame()->TransferDataToWindow();
|
||||
EXPECT_TRUE(check_box_0->GetValue());
|
||||
EXPECT_FALSE(check_box_1->GetValue());
|
||||
|
||||
// Set the kPrefCaptureFormat option to 1, the second checkbox should be ticked.
|
||||
option->SetUnsigned(1);
|
||||
frame()->TransferDataToWindow();
|
||||
EXPECT_FALSE(check_box_0->GetValue());
|
||||
EXPECT_TRUE(check_box_1->GetValue());
|
||||
}
|
||||
|
||||
TEST_F(WidgetsTest, OptionSelectedValidator_InvalidData) {
|
||||
wxCheckBox* check_box = new wxCheckBox(frame(), XRCID("Checbox"), "Checkbox");
|
||||
|
||||
// The value is higher than the max for this option.
|
||||
EXPECT_DEATH(
|
||||
check_box->SetValidator(OptionSelectedValidator(config::OptionID::kPrefCaptureFormat, 2)),
|
||||
"value_ <= option\\(\\)->GetUnsignedMax\\(\\)");
|
||||
|
||||
// The option is not an unsigned option.
|
||||
EXPECT_DEATH(check_box->SetValidator(OptionSelectedValidator(config::OptionID::kDispFilter, 0)),
|
||||
"option\\(\\)->is_unsigned\\(\\)");
|
||||
|
||||
// Unsupported wxWindow type.
|
||||
wxWindow* window = new wxWindow(frame(), XRCID("Window"));
|
||||
#if WX_HAS_VALIDATOR_SET_WINDOW_OVERRIDE
|
||||
VBAM_EXPECT_NOTREACHED(
|
||||
window->SetValidator(OptionSelectedValidator(config::OptionID::kPrefCaptureFormat, 0)));
|
||||
#else // WX_HAS_VALIDATOR_SET_WINDOW_OVERRIDE
|
||||
window->SetValidator(OptionSelectedValidator(config::OptionID::kPrefCaptureFormat, 0));
|
||||
VBAM_EXPECT_NOTREACHED(frame()->TransferDataToWindow());
|
||||
#endif // WX_HAS_VALIDATOR_SET_WINDOW_OVERRIDE
|
||||
}
|
||||
|
||||
TEST_F(WidgetsTest, OptionIntValidator) {
|
||||
wxSpinCtrl* spin_ctrl = new wxSpinCtrl(frame(), XRCID("SpinCtrl"));
|
||||
config::Option* option = config::Option::ByID(config::OptionID::kDispMaxThreads);
|
||||
|
||||
spin_ctrl->SetValidator(OptionIntValidator(config::OptionID::kDispMaxThreads));
|
||||
|
||||
// Set the kPrefCaptureFormat option to 0, the spin control should be set to 0.
|
||||
option->SetInt(0);
|
||||
frame()->TransferDataToWindow();
|
||||
EXPECT_EQ(spin_ctrl->GetValue(), 0);
|
||||
|
||||
// Set the spin control to 100, the kPrefCaptureFormat option should be set to 100.
|
||||
spin_ctrl->SetValue(100);
|
||||
frame()->TransferDataFromWindow();
|
||||
EXPECT_EQ(option->GetInt(), 100);
|
||||
}
|
||||
|
||||
TEST_F(WidgetsTest, OptionIntValidator_InvalidData) {
|
||||
wxSpinCtrl* spin_ctrl = new wxSpinCtrl(frame(), XRCID("SpinCtrl"));
|
||||
|
||||
// The option is not an int option.
|
||||
EXPECT_DEATH(spin_ctrl->SetValidator(OptionIntValidator(config::OptionID::kDispFilter)),
|
||||
"option\\(\\)->is_int\\(\\)");
|
||||
|
||||
// Unsupported wxWindow type.
|
||||
wxWindow* window = new wxWindow(frame(), XRCID("Window"));
|
||||
#if WX_HAS_VALIDATOR_SET_WINDOW_OVERRIDE
|
||||
VBAM_EXPECT_NOTREACHED(
|
||||
window->SetValidator(OptionIntValidator(config::OptionID::kDispMaxThreads)));
|
||||
#else // WX_HAS_VALIDATOR_SET_WINDOW_OVERRIDE
|
||||
window->SetValidator(OptionIntValidator(config::OptionID::kDispMaxThreads));
|
||||
VBAM_EXPECT_NOTREACHED(frame()->TransferDataToWindow());
|
||||
#endif // WX_HAS_VALIDATOR_SET_WINDOW_OVERRIDE
|
||||
}
|
||||
|
||||
TEST_F(WidgetsTest, OptionChoiceValidator) {
|
||||
wxChoice* choice = new wxChoice(frame(), XRCID("Choice"));
|
||||
choice->Append("Zero");
|
||||
choice->Append("One");
|
||||
config::Option* option = config::Option::ByID(config::OptionID::kPrefCaptureFormat);
|
||||
|
||||
choice->SetValidator(OptionChoiceValidator(config::OptionID::kPrefCaptureFormat));
|
||||
|
||||
// Set the kPrefCaptureFormat option to 0, the first item should be selected.
|
||||
option->SetUnsigned(0);
|
||||
frame()->TransferDataToWindow();
|
||||
EXPECT_EQ(choice->GetSelection(), 0);
|
||||
|
||||
// Set the kPrefCaptureFormat option to 1, the second item should be selected.
|
||||
option->SetUnsigned(1);
|
||||
frame()->TransferDataToWindow();
|
||||
EXPECT_EQ(choice->GetSelection(), 1);
|
||||
|
||||
// Select the first item, the kPrefCaptureFormat option should be 0.
|
||||
choice->SetSelection(0);
|
||||
frame()->TransferDataFromWindow();
|
||||
EXPECT_EQ(option->GetUnsigned(), 0);
|
||||
|
||||
// Select the second item, the kPrefCaptureFormat option should be 1.
|
||||
choice->SetSelection(1);
|
||||
frame()->TransferDataFromWindow();
|
||||
EXPECT_EQ(option->GetUnsigned(), 1);
|
||||
}
|
||||
|
||||
TEST_F(WidgetsTest, OptionChoiceValidator_InvalidData) {
|
||||
wxChoice* choice = new wxChoice(frame(), XRCID("Choice"));
|
||||
|
||||
// The option is not an unsigned option.
|
||||
EXPECT_DEATH(choice->SetValidator(OptionChoiceValidator(config::OptionID::kDispFilter)),
|
||||
"option\\(\\)->is_unsigned\\(\\)");
|
||||
|
||||
// Unsupported wxWindow type.
|
||||
wxWindow* window = new wxWindow(frame(), XRCID("Window"));
|
||||
#if WX_HAS_VALIDATOR_SET_WINDOW_OVERRIDE
|
||||
VBAM_EXPECT_NOTREACHED(
|
||||
window->SetValidator(OptionChoiceValidator(config::OptionID::kPrefCaptureFormat)));
|
||||
#else // WX_HAS_VALIDATOR_SET_WINDOW_OVERRIDE
|
||||
window->SetValidator(OptionChoiceValidator(config::OptionID::kPrefCaptureFormat));
|
||||
VBAM_EXPECT_NOTREACHED(frame()->TransferDataToWindow());
|
||||
#endif // WX_HAS_VALIDATOR_SET_WINDOW_OVERRIDE
|
||||
}
|
||||
|
||||
} // namespace widgets
|
|
@ -28,18 +28,15 @@ bool OptionValidator::TransferToWindow() {
|
|||
#if WX_HAS_VALIDATOR_SET_WINDOW_OVERRIDE
|
||||
void OptionValidator::SetWindow(wxWindow* window) {
|
||||
wxValidator::SetWindow(window);
|
||||
[[maybe_unused]] const bool write_success = WriteToWindow();
|
||||
VBAM_CHECK(write_success);
|
||||
OnValueChanged();
|
||||
}
|
||||
#endif
|
||||
|
||||
void OptionValidator::OnValueChanged() {
|
||||
[[maybe_unused]] const bool write_success = WriteToWindow();
|
||||
VBAM_CHECK(write_success);
|
||||
VBAM_CHECK(WriteToWindow());
|
||||
}
|
||||
|
||||
OptionSelectedValidator::OptionSelectedValidator(config::OptionID option_id,
|
||||
uint32_t value)
|
||||
OptionSelectedValidator::OptionSelectedValidator(config::OptionID option_id, uint32_t value)
|
||||
: OptionValidator(option_id), value_(value) {
|
||||
VBAM_CHECK(option()->is_unsigned());
|
||||
VBAM_CHECK(value_ >= option()->GetUnsignedMin());
|
||||
|
@ -80,8 +77,7 @@ bool OptionSelectedValidator::WriteToOption() {
|
|||
return true;
|
||||
}
|
||||
|
||||
const wxRadioButton* radio_button =
|
||||
wxDynamicCast(GetWindow(), wxRadioButton);
|
||||
const wxRadioButton* radio_button = wxDynamicCast(GetWindow(), wxRadioButton);
|
||||
if (radio_button) {
|
||||
if (radio_button->GetValue()) {
|
||||
option()->SetUnsigned(value_);
|
||||
|
@ -93,8 +89,7 @@ bool OptionSelectedValidator::WriteToOption() {
|
|||
return false;
|
||||
}
|
||||
|
||||
OptionIntValidator::OptionIntValidator(config::OptionID option_id)
|
||||
: OptionValidator(option_id) {
|
||||
OptionIntValidator::OptionIntValidator(config::OptionID option_id) : OptionValidator(option_id) {
|
||||
VBAM_CHECK(option()->is_int());
|
||||
}
|
||||
|
||||
|
@ -153,19 +148,26 @@ bool OptionChoiceValidator::IsWindowValueValid() {
|
|||
|
||||
bool OptionChoiceValidator::WriteToWindow() {
|
||||
wxChoice* choice = wxDynamicCast(GetWindow(), wxChoice);
|
||||
VBAM_CHECK(choice);
|
||||
choice->SetSelection(option()->GetUnsigned());
|
||||
return true;
|
||||
if (choice) {
|
||||
choice->SetSelection(option()->GetUnsigned());
|
||||
return true;
|
||||
}
|
||||
|
||||
VBAM_NOTREACHED();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OptionChoiceValidator::WriteToOption() {
|
||||
const wxChoice* choice = wxDynamicCast(GetWindow(), wxChoice);
|
||||
VBAM_CHECK(choice);
|
||||
return option()->SetUnsigned(choice->GetSelection());
|
||||
if (choice) {
|
||||
return option()->SetUnsigned(choice->GetSelection());
|
||||
}
|
||||
|
||||
VBAM_NOTREACHED();
|
||||
return false;
|
||||
}
|
||||
|
||||
OptionBoolValidator::OptionBoolValidator(config::OptionID option_id)
|
||||
: OptionValidator(option_id) {
|
||||
OptionBoolValidator::OptionBoolValidator(config::OptionID option_id) : OptionValidator(option_id) {
|
||||
VBAM_CHECK(option()->is_bool());
|
||||
}
|
||||
|
||||
|
@ -179,15 +181,23 @@ bool OptionBoolValidator::IsWindowValueValid() {
|
|||
|
||||
bool OptionBoolValidator::WriteToWindow() {
|
||||
wxCheckBox* checkbox = wxDynamicCast(GetWindow(), wxCheckBox);
|
||||
VBAM_CHECK(checkbox);
|
||||
checkbox->SetValue(option()->GetBool());
|
||||
return true;
|
||||
if (checkbox) {
|
||||
checkbox->SetValue(option()->GetBool());
|
||||
return true;
|
||||
}
|
||||
|
||||
VBAM_NOTREACHED();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OptionBoolValidator::WriteToOption() {
|
||||
const wxCheckBox* checkbox = wxDynamicCast(GetWindow(), wxCheckBox);
|
||||
VBAM_CHECK(checkbox);
|
||||
return option()->SetBool(checkbox->GetValue());
|
||||
if (checkbox) {
|
||||
return option()->SetBool(checkbox->GetValue());
|
||||
}
|
||||
|
||||
VBAM_NOTREACHED();
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace widgets
|
||||
|
|
|
@ -85,7 +85,7 @@ private:
|
|||
void OnValueChanged() final;
|
||||
};
|
||||
|
||||
// "Generic" validator for a wxChecBox or wxRadioButton widget with a kUnsigned
|
||||
// "Generic" validator for a wxCheckBox or wxRadioButton widget with a kUnsigned
|
||||
// Option. This will make sure the kUnsigned Option and the wxRadioButton or
|
||||
// wxCheckBox are kept in sync. The widget will be checked if the kUnsigned
|
||||
// Option matches the provided `value` parameter in the constructor.
|
||||
|
|
|
@ -36,10 +36,10 @@ public:
|
|||
|
||||
private:
|
||||
// Helper method to find a joystick state from a joystick ID.
|
||||
// Returns nullptr if not present. Called from the SDL worker thread.
|
||||
// Returns nullptr if not present.
|
||||
JoyState* FindJoyState(const SDL_JoystickID& joy_id);
|
||||
|
||||
// Remap all controllers. Called from the SDL worker thread.
|
||||
// Remap all controllers.
|
||||
void RemapControllers();
|
||||
|
||||
// Reconnects all controllers.
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
# This defines the `vbam-wx-widgets-test-fixture` library, which is used for
|
||||
# providing a base fixture for tests using wxWidgets.
|
||||
|
||||
if(NOT BUILD_TESTING)
|
||||
return()
|
||||
endif()
|
||||
|
||||
add_library(vbam-wx-widgets-test-fixture OBJECT)
|
||||
target_sources(vbam-wx-widgets-test-fixture
|
||||
PRIVATE
|
||||
test-app.cpp
|
||||
widgets-test.cpp
|
||||
|
||||
PUBLIC
|
||||
test-app.h
|
||||
widgets-test.h
|
||||
)
|
||||
configure_wx_target(vbam-wx-widgets-test-fixture)
|
||||
target_link_libraries(vbam-wx-widgets-test-fixture PUBLIC GTest::gtest)
|
|
@ -0,0 +1,22 @@
|
|||
#include "wx/widgets/test/test-app.h"
|
||||
|
||||
namespace widgets {
|
||||
|
||||
TestApp::TestApp() : previous_app_(wxApp::GetInstance()) {
|
||||
// Initialize the wxWidgets app.
|
||||
int argc = 0;
|
||||
wxApp::Initialize(argc, nullptr);
|
||||
|
||||
// Set the wxApp instance to this object.
|
||||
wxApp::SetInstance(this);
|
||||
}
|
||||
|
||||
TestApp::~TestApp() {
|
||||
// Clean up the wxWidgets app.
|
||||
wxApp::CleanUp();
|
||||
|
||||
// Restore the previous wxApp instance.
|
||||
wxApp::SetInstance(previous_app_);
|
||||
}
|
||||
|
||||
} // namespace widgets
|
|
@ -0,0 +1,23 @@
|
|||
#ifndef VBAM_WX_WIDGETS_TEST_TEST_APP_H_
|
||||
#define VBAM_WX_WIDGETS_TEST_TEST_APP_H_
|
||||
|
||||
#include <wx/app.h>
|
||||
|
||||
namespace widgets {
|
||||
|
||||
// While this object is in scope, wxApp::GetInstance() will return this object.
|
||||
class TestApp : public wxApp {
|
||||
public:
|
||||
TestApp();
|
||||
~TestApp() override;
|
||||
|
||||
bool OnInit() override { return true; }
|
||||
|
||||
private:
|
||||
// The previous wxApp instance, active before we set this one.
|
||||
wxAppConsole* const previous_app_;
|
||||
};
|
||||
|
||||
} // namespace widgets
|
||||
|
||||
#endif // VBAM_WX_WIDGETS_TEST_TEST_APP_H_
|
|
@ -0,0 +1,29 @@
|
|||
#include "wx/widgets/test/widgets-test.h"
|
||||
|
||||
#include <wx/xrc/xmlres.h>
|
||||
|
||||
namespace widgets {
|
||||
|
||||
WidgetsTest::WidgetsTest() {
|
||||
// wxWidgets can run multi-threaded so set this up for death tests.
|
||||
GTEST_FLAG_SET(death_test_style, "threadsafe");
|
||||
}
|
||||
|
||||
WidgetsTest::~WidgetsTest() = default;
|
||||
|
||||
void WidgetsTest::SetUp() {
|
||||
// Give the wxFrame a unique name and initialize it.
|
||||
const char* test_name(testing::UnitTest::GetInstance()->current_test_info()->name());
|
||||
frame_ = std::make_unique<wxFrame>(nullptr, wxXmlResource ::DoGetXRCID(test_name), test_name);
|
||||
}
|
||||
|
||||
void WidgetsTest::TearDown() {
|
||||
ASSERT_FALSE(frame_->IsShown());
|
||||
ASSERT_FALSE(frame_->IsBeingDeleted());
|
||||
|
||||
// Ensure the frame is destroyed before the app.
|
||||
frame_->Destroy();
|
||||
frame_.reset();
|
||||
}
|
||||
|
||||
} // namespace widgets
|
|
@ -0,0 +1,35 @@
|
|||
#ifndef VBAM_WX_WIDGETS_TEST_WIDGETS_TEST_H_
|
||||
#define VBAM_WX_WIDGETS_TEST_WIDGETS_TEST_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <wx/frame.h>
|
||||
|
||||
#include "wx/widgets/test/test-app.h"
|
||||
|
||||
namespace widgets {
|
||||
|
||||
// A base fixture for tests that use wxWidgets widgets. An app and a wxFrame are
|
||||
// provided for convenience. They will be deleted on test teardown.
|
||||
class WidgetsTest : public testing::Test {
|
||||
public:
|
||||
WidgetsTest();
|
||||
~WidgetsTest() override;
|
||||
|
||||
// testing::Test implementation.
|
||||
void SetUp() override;
|
||||
void TearDown() override;
|
||||
|
||||
protected:
|
||||
wxFrame* frame() { return frame_.get(); }
|
||||
|
||||
private:
|
||||
TestApp test_app_;
|
||||
std::unique_ptr<wxFrame> frame_;
|
||||
};
|
||||
|
||||
} // namespace widgets
|
||||
|
||||
#endif // VBAM_WX_WIDGETS_TEST_WIDGETS_TEST_H_
|
|
@ -39,7 +39,7 @@ public:
|
|||
// Returns the first pressed input, if any.
|
||||
nonstd::optional<config::UserInput> FirstReleasedInput() const;
|
||||
|
||||
// Mark `event_data` as processed and returns the new event filter. This is
|
||||
// Marks `user_input` as processed and returns the new event filter. This is
|
||||
// meant to be used with FilterEvent() to process global shortcuts before
|
||||
// sending the event to the next handler.
|
||||
int FilterProcessedInput(const config::UserInput& user_input);
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
// dummy webupdatedef.h for checklistctrl
|
||||
#ifndef WXDLLIMPEXP_WEBUPDATE
|
||||
// this will never be part of a DLL
|
||||
#define WXDLLIMPEXP_WEBUPDATE
|
||||
// why would I include it and not enable it?
|
||||
#define wxUSE_CHECKEDLISTCTRL 1
|
||||
// enable customizations:
|
||||
// - include wx/settings.h (bugfix; always enabled)
|
||||
// - make a dynamic class so it can be subclass in xrc
|
||||
// - only make col0 checkable
|
||||
// - use "native" checkbox (also requires CLC_USE_SYSICONS)
|
||||
#define CLC_VBAM_USAGE 1
|
||||
#define CLC_USE_SYSICONS 1
|
||||
#endif
|
Loading…
Reference in New Issue