mirror of
https://github.com/vczh-libraries/Release.git
synced 2026-02-06 20:11:41 +08:00
1221 lines
42 KiB
C++
1221 lines
42 KiB
C++
/***********************************************************************
|
|
THIS FILE IS AUTOMATICALLY GENERATED. DO NOT MODIFY
|
|
DEVELOPER: Zihan Chen(vczh)
|
|
***********************************************************************/
|
|
#include "GacUI.h"
|
|
#include "VlppGlrParser.h"
|
|
#include "VlppWorkflowLibrary.h"
|
|
#include "VlppReflection.h"
|
|
#include "VlppOS.h"
|
|
#include "Vlpp.h"
|
|
#include "VlppRegex.h"
|
|
#include "GacUIReflection.h"
|
|
#include "VlppWorkflowCompiler.h"
|
|
#include "VlppWorkflowRuntime.h"
|
|
|
|
/***********************************************************************
|
|
.\GUIUNITTESTPROTOCOL_SHARED.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Vczh Library++ 3.0
|
|
Developer: Zihan Chen(vczh)
|
|
Unit Test Snapsnot and other Utilities
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_PRESENTATION_GUIUNITTESTPROTOCOL_SHARED
|
|
#define VCZH_PRESENTATION_GUIUNITTESTPROTOCOL_SHARED
|
|
|
|
|
|
namespace vl::presentation::unittest
|
|
{
|
|
struct WindowStyleConfig
|
|
{
|
|
WString title;
|
|
bool enabled = true;
|
|
bool topMost = false;
|
|
bool showInTaskBar = true;
|
|
|
|
bool customFrameMode = false;
|
|
bool maximizedBox = true;
|
|
bool minimizedBox = true;
|
|
bool border = true;
|
|
bool sizeBox = true;
|
|
bool iconVisible = true;
|
|
bool titleBar = true;
|
|
bool activated = false;
|
|
|
|
auto operator<=>(const WindowStyleConfig&) const = default;
|
|
};
|
|
|
|
enum class UnitTestRemoteChannel
|
|
{
|
|
None,
|
|
Sync,
|
|
Async,
|
|
};
|
|
|
|
struct UnitTestScreenConfig
|
|
{
|
|
using FontConfig = vl::presentation::remoteprotocol::FontConfig;
|
|
using ScreenConfig = vl::presentation::remoteprotocol::ScreenConfig;
|
|
|
|
WString executablePath;
|
|
NativeMargin customFramePadding;
|
|
FontConfig fontConfig;
|
|
ScreenConfig screenConfig;
|
|
bool useDomDiff = false;
|
|
UnitTestRemoteChannel useChannel = UnitTestRemoteChannel::None;
|
|
|
|
void FastInitialize(vint width, vint height, vint taskBarHeight = 0);
|
|
};
|
|
|
|
class UnitTestRemoteProtocolBase : public Object, protected virtual IGuiRemoteProtocol
|
|
{
|
|
protected:
|
|
IGuiRemoteProtocolEvents* events = nullptr;
|
|
UnitTestScreenConfig globalConfig;
|
|
|
|
public:
|
|
UnitTestRemoteProtocolBase(const UnitTestScreenConfig& _globalConfig)
|
|
: globalConfig(_globalConfig)
|
|
{
|
|
}
|
|
|
|
IGuiRemoteProtocol* GetProtocol()
|
|
{
|
|
return this;
|
|
}
|
|
|
|
IGuiRemoteProtocolEvents* GetEvents() const
|
|
{
|
|
return events;
|
|
}
|
|
|
|
const UnitTestScreenConfig& GetGlobalConfig() const
|
|
{
|
|
return globalConfig;
|
|
}
|
|
|
|
protected:
|
|
|
|
#define MESSAGE_NOREQ_NORES(NAME, REQUEST, RESPONSE) void Impl_ ## NAME() { CHECK_FAIL(L"Not Implemented!"); }
|
|
#define MESSAGE_NOREQ_RES(NAME, REQUEST, RESPONSE) void Impl_ ## NAME(vint id) { CHECK_FAIL(L"Not Implemented!"); }
|
|
#define MESSAGE_REQ_NORES(NAME, REQUEST, RESPONSE) void Impl_ ## NAME(const REQUEST& arguments) { CHECK_FAIL(L"Not Implemented!"); }
|
|
#define MESSAGE_REQ_RES(NAME, REQUEST, RESPONSE) void Impl_ ## NAME(vint id, const REQUEST& arguments) { CHECK_FAIL(L"Not Implemented!"); }
|
|
#define MESSAGE_HANDLER(NAME, REQUEST, RESPONSE, REQTAG, RESTAG, ...) MESSAGE_ ## REQTAG ## _ ## RESTAG(NAME, REQUEST, RESPONSE)
|
|
GACUI_REMOTEPROTOCOL_MESSAGES(MESSAGE_HANDLER)
|
|
#undef MESSAGE_HANDLER
|
|
#undef MESSAGE_REQ_RES
|
|
#undef MESSAGE_REQ_NORES
|
|
#undef MESSAGE_NOREQ_RES
|
|
#undef MESSAGE_NOREQ_NORES
|
|
|
|
/***********************************************************************
|
|
IGuiRemoteProtocol
|
|
***********************************************************************/
|
|
|
|
void Initialize(IGuiRemoteProtocolEvents* _events) override
|
|
{
|
|
events = _events;
|
|
}
|
|
|
|
WString GetExecutablePath() override
|
|
{
|
|
return globalConfig.executablePath;
|
|
}
|
|
};
|
|
}
|
|
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\GUIUNITTESTPROTOCOL_IO.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Vczh Library++ 3.0
|
|
Developer: Zihan Chen(vczh)
|
|
Unit Test Snapsnot and other Utilities
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_PRESENTATION_GUIUNITTESTPROTOCOL_IO
|
|
#define VCZH_PRESENTATION_GUIUNITTESTPROTOCOL_IO
|
|
|
|
|
|
namespace vl::presentation::unittest
|
|
{
|
|
class UnitTestRemoteProtocol_IO : public virtual UnitTestRemoteProtocolBase
|
|
{
|
|
using GlobalShortcutKey = remoteprotocol::GlobalShortcutKey;
|
|
using GlobalShortcutKeyList = collections::List<GlobalShortcutKey>;
|
|
public:
|
|
bool capturing = false;
|
|
GlobalShortcutKeyList globalShortcutKeys;
|
|
|
|
UnitTestRemoteProtocol_IO(const UnitTestScreenConfig& _globalConfig)
|
|
: UnitTestRemoteProtocolBase(_globalConfig)
|
|
{
|
|
}
|
|
|
|
protected:
|
|
|
|
/***********************************************************************
|
|
IGuiRemoteProtocolMessages (IO)
|
|
***********************************************************************/
|
|
|
|
void Impl_IOUpdateGlobalShortcutKey(const Ptr<GlobalShortcutKeyList>& arguments)
|
|
{
|
|
if (arguments)
|
|
{
|
|
CopyFrom(globalShortcutKeys, *arguments.Obj());
|
|
}
|
|
else
|
|
{
|
|
globalShortcutKeys.Clear();
|
|
}
|
|
}
|
|
|
|
void Impl_IORequireCapture()
|
|
{
|
|
capturing = true;
|
|
}
|
|
|
|
void Impl_IOReleaseCapture()
|
|
{
|
|
capturing = false;
|
|
}
|
|
|
|
void Impl_IOIsKeyPressing(vint id, const VKEY& arguments)
|
|
{
|
|
CHECK_FAIL(L"Not Implemented!");
|
|
}
|
|
|
|
void Impl_IOIsKeyToggled(vint id, const VKEY& arguments)
|
|
{
|
|
CHECK_FAIL(L"Not Implemented!");
|
|
}
|
|
};
|
|
}
|
|
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\GUIUNITTESTPROTOCOL_IOCOMMANDS.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Vczh Library++ 3.0
|
|
Developer: Zihan Chen(vczh)
|
|
Unit Test Snapsnot and other Utilities
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_PRESENTATION_GUIUNITTESTPROTOCOL_IOCOMMANDS
|
|
#define VCZH_PRESENTATION_GUIUNITTESTPROTOCOL_IOCOMMANDS
|
|
|
|
|
|
namespace vl::presentation::unittest
|
|
{
|
|
|
|
/***********************************************************************
|
|
UnitTestRemoteProtocol
|
|
***********************************************************************/
|
|
|
|
class UnitTestRemoteProtocol_IOCommands : public virtual UnitTestRemoteProtocolBase
|
|
{
|
|
protected:
|
|
Nullable<NativePoint> mousePosition;
|
|
collections::SortedList<VKEY> pressingKeys;
|
|
bool leftPressing = false;
|
|
bool middlePressing = false;
|
|
bool rightPressing = false;
|
|
bool capslockToggled = false;
|
|
|
|
IGuiRemoteProtocolEvents& UseEvents()
|
|
{
|
|
return *this->GetEvents();
|
|
}
|
|
|
|
bool IsPressing(VKEY key)
|
|
{
|
|
return pressingKeys.Contains(key);
|
|
}
|
|
|
|
NativeWindowMouseInfo MakeMouseInfo()
|
|
{
|
|
NativeWindowMouseInfo info;
|
|
info.ctrl = IsPressing(VKEY::KEY_CONTROL) || IsPressing(VKEY::KEY_LCONTROL) || IsPressing(VKEY::KEY_RCONTROL);
|
|
info.shift = IsPressing(VKEY::KEY_SHIFT) || IsPressing(VKEY::KEY_LSHIFT) || IsPressing(VKEY::KEY_RSHIFT);
|
|
info.left = leftPressing;
|
|
info.middle = middlePressing;
|
|
info.right = rightPressing;
|
|
info.x = mousePosition.Value().x.value;
|
|
info.y = mousePosition.Value().y.value;
|
|
info.wheel = 0;
|
|
info.nonClient = false;
|
|
return info;
|
|
}
|
|
|
|
NativeWindowKeyInfo MakeKeyInfo(VKEY key, bool autoRepeatKeyDown = false)
|
|
{
|
|
NativeWindowKeyInfo info;
|
|
info.code = key;
|
|
info.ctrl = IsPressing(VKEY::KEY_CONTROL) || IsPressing(VKEY::KEY_LCONTROL) || IsPressing(VKEY::KEY_RCONTROL);
|
|
info.shift = IsPressing(VKEY::KEY_SHIFT) || IsPressing(VKEY::KEY_LSHIFT) || IsPressing(VKEY::KEY_RSHIFT);
|
|
info.alt = IsPressing(VKEY::KEY_MENU) || IsPressing(VKEY::KEY_LMENU) || IsPressing(VKEY::KEY_RMENU);
|
|
info.capslock = capslockToggled;
|
|
info.autoRepeatKeyDown = autoRepeatKeyDown;
|
|
return info;
|
|
}
|
|
|
|
NativeWindowCharInfo MakeCharInfo(wchar_t ch)
|
|
{
|
|
NativeWindowCharInfo info;
|
|
info.code = ch;
|
|
info.ctrl = IsPressing(VKEY::KEY_CONTROL) || IsPressing(VKEY::KEY_LCONTROL) || IsPressing(VKEY::KEY_RCONTROL);
|
|
info.shift = IsPressing(VKEY::KEY_SHIFT) || IsPressing(VKEY::KEY_LSHIFT) || IsPressing(VKEY::KEY_RSHIFT);
|
|
info.alt = IsPressing(VKEY::KEY_MENU) || IsPressing(VKEY::KEY_LMENU) || IsPressing(VKEY::KEY_RMENU);
|
|
info.capslock = capslockToggled;
|
|
return info;
|
|
}
|
|
|
|
public:
|
|
|
|
UnitTestRemoteProtocol_IOCommands(const UnitTestScreenConfig& _globalConfig)
|
|
: UnitTestRemoteProtocolBase(_globalConfig)
|
|
{
|
|
}
|
|
|
|
/***********************************************************************
|
|
Helper Functions
|
|
***********************************************************************/
|
|
|
|
NativePoint LocationOf(compositions::GuiGraphicsComposition* composition, double ratioX = 0.5, double ratioY = 0.5, vint offsetX = 0, vint offsetY = 0)
|
|
{
|
|
INativeWindow* nativeWindow = composition->GetRelatedControlHost()->GetNativeWindow();
|
|
Rect bounds = composition->GetGlobalBounds();
|
|
NativeRect nativeBounds = { nativeWindow->Convert(bounds.LeftTop()),nativeWindow->Convert(bounds.GetSize()) };
|
|
vint x = nativeBounds.x1.value + (vint)(nativeBounds.Width().value * ratioX) + offsetX;
|
|
vint y = nativeBounds.y1.value + (vint)(nativeBounds.Height().value * ratioY) + offsetY;
|
|
NativePoint windowLocation = nativeWindow->GetBounds().LeftTop();
|
|
return { windowLocation.x.value + x,windowLocation.y.value + y };
|
|
}
|
|
|
|
NativePoint LocationOf(controls::GuiControl* control, double ratioX = 0.5, double ratioY = 0.5, vint offsetX = 0, vint offsetY = 0)
|
|
{
|
|
return LocationOf(control->GetBoundsComposition(), ratioX, ratioY, offsetX, offsetY);
|
|
}
|
|
|
|
#define CLASS_PREFIX L"vl::presentation::unittest::UnitTestRemoteProtocol_IOCommands::"
|
|
|
|
/***********************************************************************
|
|
Keys
|
|
***********************************************************************/
|
|
|
|
void _KeyDown(VKEY key)
|
|
{
|
|
#define ERROR_MESSAGE_PREFIX CLASS_PREFIX L"_KeyDown(...)#"
|
|
CHECK_ERROR(!pressingKeys.Contains(key), ERROR_MESSAGE_PREFIX L"The key is already being pressed.");
|
|
pressingKeys.Add(key);
|
|
if (key == VKEY::KEY_CAPITAL)
|
|
{
|
|
capslockToggled = !capslockToggled;
|
|
}
|
|
UseEvents().OnIOKeyDown(MakeKeyInfo(key, false));
|
|
#undef ERROR_MESSAGE_PREFIX
|
|
}
|
|
|
|
void _KeyDownRepeat(VKEY key)
|
|
{
|
|
#define ERROR_MESSAGE_PREFIX CLASS_PREFIX L"_KeyDownRepeat(...)#"
|
|
CHECK_ERROR(pressingKeys.Contains(key), ERROR_MESSAGE_PREFIX L"The key is not being pressed.");
|
|
UseEvents().OnIOKeyDown(MakeKeyInfo(key, true));
|
|
#undef ERROR_MESSAGE_PREFIX
|
|
}
|
|
|
|
void _KeyUp(VKEY key)
|
|
{
|
|
#define ERROR_MESSAGE_PREFIX CLASS_PREFIX L"_KeyUp(...)#"
|
|
CHECK_ERROR(pressingKeys.Contains(key), ERROR_MESSAGE_PREFIX L"The key is not being pressed.");
|
|
pressingKeys.Remove(key);
|
|
UseEvents().OnIOKeyUp(MakeKeyInfo(key, false));
|
|
#undef ERROR_MESSAGE_PREFIX
|
|
}
|
|
|
|
void KeyPress(VKEY key)
|
|
{
|
|
_KeyDown(key);
|
|
_KeyUp(key);
|
|
}
|
|
|
|
void KeyPress(VKEY key, bool ctrl, bool shift, bool alt)
|
|
{
|
|
if (ctrl) _KeyDown(VKEY::KEY_CONTROL);
|
|
if (shift) _KeyDown(VKEY::KEY_SHIFT);
|
|
if (alt) _KeyDown(VKEY::KEY_MENU);
|
|
KeyPress(key);
|
|
if (alt) _KeyUp(VKEY::KEY_MENU);
|
|
if (shift) _KeyUp(VKEY::KEY_SHIFT);
|
|
if (ctrl) _KeyUp(VKEY::KEY_CONTROL);
|
|
}
|
|
|
|
// Emits plain IOChar events without synthesizing key presses; expand in future iterations when modifiers are required.
|
|
void TypeString(const WString& text)
|
|
{
|
|
if (text.Length() == 0) return;
|
|
for (vint i = 0; i < text.Length(); i++)
|
|
{
|
|
UseEvents().OnIOChar(MakeCharInfo(text[i]));
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
Mouse Move Events
|
|
***********************************************************************/
|
|
|
|
void MouseMove(NativePoint position)
|
|
{
|
|
if (!mousePosition)
|
|
{
|
|
UseEvents().OnIOMouseEntered();
|
|
goto DO_MOUSE_MOVE;
|
|
}
|
|
|
|
if (mousePosition.Value() == position) return;
|
|
DO_MOUSE_MOVE:
|
|
|
|
mousePosition = position;
|
|
UseEvents().OnIOMouseMoving(MakeMouseInfo());
|
|
}
|
|
|
|
NativePoint GetMousePosition()
|
|
{
|
|
#define ERROR_MESSAGE_PREFIX CLASS_PREFIX L"GetMousePosition()#"
|
|
CHECK_ERROR(mousePosition, CLASS_PREFIX L"The mouse position is not set.");
|
|
return mousePosition.Value();
|
|
#undef ERROR_MESSAGE_PREFIX
|
|
}
|
|
|
|
/***********************************************************************
|
|
Mouse Wheel Events
|
|
***********************************************************************/
|
|
|
|
void _Wheel(vint up, Nullable<NativePoint> position = {})
|
|
{
|
|
if (position) MouseMove(position.Value());
|
|
auto info = MakeMouseInfo();
|
|
info.wheel = up;
|
|
UseEvents().OnIOVWheel(info);
|
|
}
|
|
|
|
void _Wheel(vint up, Nullable<NativePoint> position, bool ctrl, bool shift, bool alt)
|
|
{
|
|
if (ctrl) _KeyDown(VKEY::KEY_CONTROL);
|
|
if (shift) _KeyDown(VKEY::KEY_SHIFT);
|
|
if (alt) _KeyDown(VKEY::KEY_MENU);
|
|
_Wheel(up, position);
|
|
if (alt) _KeyUp(VKEY::KEY_MENU);
|
|
if (shift) _KeyUp(VKEY::KEY_SHIFT);
|
|
if (ctrl) _KeyUp(VKEY::KEY_CONTROL);
|
|
}
|
|
|
|
void _HWheel(vint right, Nullable<NativePoint> position = {})
|
|
{
|
|
if (position) MouseMove(position.Value());
|
|
auto info = MakeMouseInfo();
|
|
info.wheel = right;
|
|
UseEvents().OnIOHWheel(info);
|
|
}
|
|
|
|
void _HWheel(vint right, Nullable<NativePoint> position, bool ctrl, bool shift, bool alt)
|
|
{
|
|
if (ctrl) _KeyDown(VKEY::KEY_CONTROL);
|
|
if (shift) _KeyDown(VKEY::KEY_SHIFT);
|
|
if (alt) _KeyDown(VKEY::KEY_MENU);
|
|
_HWheel(right, position);
|
|
if (alt) _KeyUp(VKEY::KEY_MENU);
|
|
if (shift) _KeyUp(VKEY::KEY_SHIFT);
|
|
if (ctrl) _KeyUp(VKEY::KEY_CONTROL);
|
|
}
|
|
|
|
void WheelDown(vint jumps = 1, Nullable<NativePoint> position = {})
|
|
{
|
|
_Wheel(-jumps * 120, position);
|
|
}
|
|
|
|
void WheelDown(vint jumps, Nullable<NativePoint> position, bool ctrl, bool shift, bool alt)
|
|
{
|
|
_Wheel(-jumps * 120, position, ctrl, shift, alt);
|
|
}
|
|
|
|
void WheelUp(vint jumps = 1, Nullable<NativePoint> position = {})
|
|
{
|
|
_Wheel(jumps * 120, position);
|
|
}
|
|
|
|
void WheelUp(vint jumps, Nullable<NativePoint> position, bool ctrl, bool shift, bool alt)
|
|
{
|
|
_Wheel(jumps * 120, position, ctrl, shift, alt);
|
|
}
|
|
|
|
void HWheelLeft(vint jumps = 1, Nullable<NativePoint> position = {})
|
|
{
|
|
_HWheel(-jumps * 120, position);
|
|
}
|
|
|
|
void HWheelLeft(vint jumps, Nullable<NativePoint> position, bool ctrl, bool shift, bool alt)
|
|
{
|
|
_HWheel(-jumps * 120, position, ctrl, shift, alt);
|
|
}
|
|
|
|
void HWheelRight(vint jumps = 1, Nullable<NativePoint> position = {})
|
|
{
|
|
_HWheel(jumps * 120, position);
|
|
}
|
|
|
|
void HWheelRight(vint jumps, Nullable<NativePoint> position, bool ctrl, bool shift, bool alt)
|
|
{
|
|
_HWheel(jumps * 120, position, ctrl, shift, alt);
|
|
}
|
|
|
|
/***********************************************************************
|
|
Mouse Click Events
|
|
***********************************************************************/
|
|
|
|
#define DEFINE_MOUSE_ACTIONS(PREFIX, LOWER, UPPER)\
|
|
void _ ## PREFIX ## Down(Nullable<NativePoint> position = {})\
|
|
{\
|
|
if (position) MouseMove(position.Value());\
|
|
CHECK_ERROR(!LOWER ## Pressing, CLASS_PREFIX L"_" L ## #PREFIX L"Down(...)#" L"The button should not be being pressed.");\
|
|
LOWER ## Pressing = true;\
|
|
UseEvents().OnIOButtonDown({ remoteprotocol::IOMouseButton::UPPER,MakeMouseInfo() });\
|
|
}\
|
|
void _ ## PREFIX ## Up(Nullable<NativePoint> position = {})\
|
|
{\
|
|
if (position) MouseMove(position.Value());\
|
|
CHECK_ERROR(LOWER ## Pressing, CLASS_PREFIX L"_" L ## #PREFIX L"Up(...)#" L"The button should be being pressed.");\
|
|
LOWER ## Pressing = false;\
|
|
UseEvents().OnIOButtonUp({ remoteprotocol::IOMouseButton::UPPER,MakeMouseInfo() });\
|
|
}\
|
|
void _ ## PREFIX ## DBClick(Nullable<NativePoint> position = {})\
|
|
{\
|
|
if (position) MouseMove(position.Value());\
|
|
CHECK_ERROR(!LOWER ## Pressing, CLASS_PREFIX L"_" L ## #PREFIX L"DBClick(...)#" L"The button should not be being pressed.");\
|
|
LOWER ## Pressing = true;\
|
|
UseEvents().OnIOButtonDoubleClick({ remoteprotocol::IOMouseButton::UPPER,MakeMouseInfo() });\
|
|
}\
|
|
void PREFIX ## Click(Nullable<NativePoint> position = {})\
|
|
{\
|
|
_ ## PREFIX ## Down(position);\
|
|
_ ## PREFIX ## Up(position);\
|
|
}\
|
|
void PREFIX ## Click(Nullable<NativePoint> position, bool ctrl, bool shift, bool alt)\
|
|
{\
|
|
if (ctrl) _KeyDown(VKEY::KEY_CONTROL);\
|
|
if (shift) _KeyDown(VKEY::KEY_SHIFT);\
|
|
if (alt) _KeyDown(VKEY::KEY_MENU);\
|
|
PREFIX ## Click(position);\
|
|
if (alt) _KeyUp(VKEY::KEY_MENU);\
|
|
if (shift) _KeyUp(VKEY::KEY_SHIFT);\
|
|
if (ctrl) _KeyUp(VKEY::KEY_CONTROL);\
|
|
}\
|
|
void PREFIX ## DBClick(Nullable<NativePoint> position = {})\
|
|
{\
|
|
_ ## PREFIX ## Down(position);\
|
|
_ ## PREFIX ## Up(position);\
|
|
_ ## PREFIX ## DBClick(position);\
|
|
_ ## PREFIX ## Up(position);\
|
|
}\
|
|
void PREFIX ## DBClick(Nullable<NativePoint> position, bool ctrl, bool shift, bool alt)\
|
|
{\
|
|
if (ctrl) _KeyDown(VKEY::KEY_CONTROL);\
|
|
if (shift) _KeyDown(VKEY::KEY_SHIFT);\
|
|
if (alt) _KeyDown(VKEY::KEY_MENU);\
|
|
PREFIX ## DBClick(position);\
|
|
if (alt) _KeyUp(VKEY::KEY_MENU);\
|
|
if (shift) _KeyUp(VKEY::KEY_SHIFT);\
|
|
if (ctrl) _KeyUp(VKEY::KEY_CONTROL);\
|
|
}\
|
|
|
|
DEFINE_MOUSE_ACTIONS(L, left, Left);
|
|
DEFINE_MOUSE_ACTIONS(M, middle, Middle);
|
|
DEFINE_MOUSE_ACTIONS(R, right, Right);
|
|
|
|
#undef DEFINE_MOUSE_ACTIONS
|
|
|
|
#undef CLASS_PREFIX
|
|
};
|
|
}
|
|
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\GUIUNITTESTPROTOCOL_MAINWINDOW.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Vczh Library++ 3.0
|
|
Developer: Zihan Chen(vczh)
|
|
Unit Test Snapsnot and other Utilities
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_PRESENTATION_GUIUNITTESTPROTOCOL_MAINWINDOW
|
|
#define VCZH_PRESENTATION_GUIUNITTESTPROTOCOL_MAINWINDOW
|
|
|
|
|
|
namespace vl::presentation::unittest
|
|
{
|
|
class UnitTestRemoteProtocol_MainWindow : public virtual UnitTestRemoteProtocolBase
|
|
{
|
|
using WindowSizingConfig = remoteprotocol::WindowSizingConfig;
|
|
using WindowShowing = remoteprotocol::WindowShowing;
|
|
public:
|
|
WindowSizingConfig sizingConfig;
|
|
WindowStyleConfig styleConfig;
|
|
NativeRect lastRestoredSize;
|
|
|
|
UnitTestRemoteProtocol_MainWindow(const UnitTestScreenConfig& _globalConfig)
|
|
: UnitTestRemoteProtocolBase(_globalConfig)
|
|
{
|
|
sizingConfig.bounds = { 0,0,0,0 };
|
|
sizingConfig.clientBounds = { 0,0,0,0 };
|
|
sizingConfig.customFramePadding = this->GetGlobalConfig().customFramePadding;
|
|
sizingConfig.sizeState = INativeWindow::Restored;
|
|
}
|
|
|
|
protected:
|
|
|
|
/***********************************************************************
|
|
IGuiRemoteProtocolMessages (Controller)
|
|
***********************************************************************/
|
|
|
|
void Impl_ControllerGetFontConfig(vint id)
|
|
{
|
|
this->GetEvents()->RespondControllerGetFontConfig(id, this->GetGlobalConfig().fontConfig);
|
|
}
|
|
|
|
void Impl_ControllerGetScreenConfig(vint id)
|
|
{
|
|
this->GetEvents()->RespondControllerGetScreenConfig(id, this->GetGlobalConfig().screenConfig);
|
|
}
|
|
|
|
/***********************************************************************
|
|
IGuiRemoteProtocolMessages (Window)
|
|
***********************************************************************/
|
|
|
|
void Impl_WindowGetBounds(vint id)
|
|
{
|
|
this->GetEvents()->RespondWindowGetBounds(id, sizingConfig);
|
|
}
|
|
|
|
void Impl_WindowNotifySetTitle(const ::vl::WString& arguments)
|
|
{
|
|
styleConfig.title = arguments;
|
|
}
|
|
|
|
void Impl_WindowNotifySetEnabled(const bool& arguments)
|
|
{
|
|
styleConfig.enabled = arguments;
|
|
}
|
|
|
|
void Impl_WindowNotifySetTopMost(const bool& arguments)
|
|
{
|
|
styleConfig.topMost = arguments;
|
|
}
|
|
|
|
void Impl_WindowNotifySetShowInTaskBar(const bool& arguments)
|
|
{
|
|
styleConfig.showInTaskBar = arguments;
|
|
}
|
|
|
|
void OnBoundsUpdated()
|
|
{
|
|
sizingConfig.clientBounds = sizingConfig.bounds;
|
|
if (sizingConfig.sizeState == INativeWindow::Restored)
|
|
{
|
|
lastRestoredSize = sizingConfig.bounds;
|
|
}
|
|
this->GetEvents()->OnWindowBoundsUpdated(sizingConfig);
|
|
}
|
|
|
|
void Impl_WindowNotifySetBounds(const NativeRect& arguments)
|
|
{
|
|
sizingConfig.bounds = arguments;
|
|
OnBoundsUpdated();
|
|
}
|
|
|
|
void Impl_WindowNotifySetClientSize(const NativeSize& arguments)
|
|
{
|
|
sizingConfig.bounds = { sizingConfig.bounds.LeftTop(), arguments };
|
|
OnBoundsUpdated();
|
|
}
|
|
|
|
void Impl_WindowNotifySetCustomFrameMode(const bool& arguments) { styleConfig.customFrameMode = arguments; this->GetEvents()->OnWindowBoundsUpdated(sizingConfig); }
|
|
void Impl_WindowNotifySetMaximizedBox(const bool& arguments) { styleConfig.maximizedBox = arguments; this->GetEvents()->OnWindowBoundsUpdated(sizingConfig); }
|
|
void Impl_WindowNotifySetMinimizedBox(const bool& arguments) { styleConfig.minimizedBox = arguments; this->GetEvents()->OnWindowBoundsUpdated(sizingConfig); }
|
|
void Impl_WindowNotifySetBorder(const bool& arguments) { styleConfig.border = arguments; this->GetEvents()->OnWindowBoundsUpdated(sizingConfig); }
|
|
void Impl_WindowNotifySetSizeBox(const bool& arguments) { styleConfig.sizeBox = arguments; this->GetEvents()->OnWindowBoundsUpdated(sizingConfig); }
|
|
void Impl_WindowNotifySetIconVisible(const bool& arguments) { styleConfig.iconVisible = arguments; this->GetEvents()->OnWindowBoundsUpdated(sizingConfig); }
|
|
void Impl_WindowNotifySetTitleBar(const bool& arguments) { styleConfig.titleBar = arguments; this->GetEvents()->OnWindowBoundsUpdated(sizingConfig); }
|
|
void Impl_WindowNotifyActivate() { styleConfig.activated = true; }
|
|
void Impl_WindowNotifyMinSize(const NativeSize& arguments) {}
|
|
|
|
void Impl_WindowNotifyShow(const WindowShowing& arguments)
|
|
{
|
|
styleConfig.activated = arguments.activate;
|
|
if (sizingConfig.sizeState != arguments.sizeState)
|
|
{
|
|
sizingConfig.sizeState = arguments.sizeState;
|
|
switch (arguments.sizeState)
|
|
{
|
|
case INativeWindow::Maximized:
|
|
sizingConfig.bounds = this->GetGlobalConfig().screenConfig.clientBounds;
|
|
OnBoundsUpdated();
|
|
break;
|
|
case INativeWindow::Minimized:
|
|
sizingConfig.bounds = NativeRect(
|
|
{
|
|
this->GetGlobalConfig().screenConfig.bounds.x2,
|
|
this->GetGlobalConfig().screenConfig.bounds.y2
|
|
},
|
|
{ 1,1 }
|
|
);
|
|
OnBoundsUpdated();
|
|
break;
|
|
case INativeWindow::Restored:
|
|
if (sizingConfig.bounds != lastRestoredSize)
|
|
{
|
|
sizingConfig.bounds = lastRestoredSize;
|
|
OnBoundsUpdated();
|
|
}
|
|
else
|
|
{
|
|
this->GetEvents()->OnWindowBoundsUpdated(sizingConfig);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\GUIUNITTESTPROTOCOL_RENDERING.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Vczh Library++ 3.0
|
|
Developer: Zihan Chen(vczh)
|
|
Unit Test Snapsnot and other Utilities
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_PRESENTATION_GUIUNITTESTPROTOCOL_RENDERING
|
|
#define VCZH_PRESENTATION_GUIUNITTESTPROTOCOL_RENDERING
|
|
|
|
|
|
namespace vl::presentation::unittest
|
|
{
|
|
|
|
/***********************************************************************
|
|
DocumentParagraphState
|
|
***********************************************************************/
|
|
|
|
struct DocumentParagraphCharLayout
|
|
{
|
|
double x; // X position of character start
|
|
double width; // Character width
|
|
vint lineIndex; // Which line this character belongs to
|
|
vint height; // Character height (font size or inline object height)
|
|
vint baseline; // Distance from top to baseline (for alignment)
|
|
bool isInlineObject; // True if this position is part of an inline object
|
|
};
|
|
|
|
struct DocumentParagraphLineInfo
|
|
{
|
|
vint startPos; // Text position of line start (inclusive)
|
|
vint endPos; // Text position of line end (exclusive)
|
|
vint y; // Y coordinate of line top
|
|
vint height; // Line height (computed from baseline alignment)
|
|
vint baseline; // Line baseline position from line top
|
|
vint width; // Line width (for alignment calculation)
|
|
};
|
|
|
|
struct DocumentParagraphState
|
|
{
|
|
WString text;
|
|
bool wrapLine = false;
|
|
vint maxWidth = -1;
|
|
remoteprotocol::ElementHorizontalAlignment alignment = remoteprotocol::ElementHorizontalAlignment::Left;
|
|
|
|
elements::DocumentTextRunPropertyMap textRuns;
|
|
elements::DocumentInlineObjectRunPropertyMap inlineObjectRuns;
|
|
elements::DocumentRunPropertyMap mergedRuns;
|
|
|
|
collections::List<DocumentParagraphCharLayout> characterLayouts;
|
|
collections::List<DocumentParagraphLineInfo> lines;
|
|
Size cachedSize;
|
|
collections::Dictionary<vint, Rect> cachedInlineObjectBounds;
|
|
};
|
|
|
|
/***********************************************************************
|
|
UnitTestRemoteProtocol
|
|
***********************************************************************/
|
|
|
|
using ElementDescVariant = remoteprotocol::UnitTest_ElementDescVariant;
|
|
using UnitTestRenderingDom = remoteprotocol::RenderingDom;
|
|
|
|
struct UnitTestLoggedFrame
|
|
{
|
|
vint frameId;
|
|
collections::List<WString> renderingCommandsLog;
|
|
Nullable<remoteprotocol::RenderingDom_DiffsInOrder> renderingDiffs;
|
|
Ptr<UnitTestRenderingDom> renderingDom;
|
|
};
|
|
|
|
using UnitTestLoggedFrameList = collections::List<Ptr<UnitTestLoggedFrame>>;
|
|
|
|
class UnitTestRemoteProtocol_Rendering : public virtual UnitTestRemoteProtocolBase
|
|
{
|
|
using IdSet = collections::SortedList<vint>;
|
|
using Base64ToImageMetadataMap = collections::Dictionary<WString, remoteprotocol::ImageMetadata>;
|
|
using ElementDescMap = collections::Dictionary<vint, ElementDescVariant>;
|
|
using ImageMetadataMap = collections::Dictionary<vint, remoteprotocol::ImageMetadata>;
|
|
|
|
protected:
|
|
remoteprotocol::RenderingDomBuilder renderingDomBuilder;
|
|
remoteprotocol::UnitTest_RenderingTrace loggedTrace;
|
|
UnitTestLoggedFrameList loggedFrames;
|
|
bool lastRenderingCommandsOpening = false;
|
|
|
|
Ptr<remoteprotocol::RenderingDom> receivedDom;
|
|
remoteprotocol::DomIndex receivedDomIndex;
|
|
bool receivedDomDiffMessage = false;
|
|
bool receivedElementMessage = false;
|
|
|
|
ElementDescMap lastElementDescs;
|
|
IdSet removedElementIds;
|
|
IdSet removedImageIds;
|
|
Ptr<Base64ToImageMetadataMap> cachedImageMetadatas;
|
|
|
|
remoteprotocol::ElementMeasurings measuringForNextRendering;
|
|
regex::Regex regexCrLf{ L"/n|/r(/n)?" };
|
|
|
|
collections::Dictionary<vint, Ptr<DocumentParagraphState>> paragraphStates;
|
|
|
|
void ResetCreatedObjects()
|
|
{
|
|
loggedTrace.createdElements = Ptr(new collections::Dictionary<vint, remoteprotocol::RendererType>);
|
|
loggedTrace.imageCreations = Ptr(new remoteprotocol::ArrayMap<vint, remoteprotocol::ImageCreation, &remoteprotocol::ImageCreation::id>);
|
|
loggedTrace.imageMetadatas = Ptr(new remoteprotocol::ArrayMap<vint, remoteprotocol::ImageMetadata, &remoteprotocol::ImageMetadata::id>);
|
|
lastElementDescs.Clear();
|
|
}
|
|
public:
|
|
|
|
UnitTestRemoteProtocol_Rendering(const UnitTestScreenConfig& _globalConfig)
|
|
: UnitTestRemoteProtocolBase(_globalConfig)
|
|
{
|
|
ResetCreatedObjects();
|
|
loggedTrace.frames = Ptr(new collections::List<remoteprotocol::UnitTest_RenderingFrame>);
|
|
}
|
|
|
|
protected:
|
|
|
|
/***********************************************************************
|
|
IGuiRemoteProtocolMessages (Rendering)
|
|
***********************************************************************/
|
|
|
|
Ptr<UnitTestLoggedFrame> GetLastRenderingFrame();
|
|
Ptr<UnitTestLoggedFrame> TryGetLastRenderingFrameAndReset();
|
|
void Impl_RendererBeginRendering(const remoteprotocol::ElementBeginRendering& arguments);
|
|
void Impl_RendererEndRendering(vint id);
|
|
|
|
/***********************************************************************
|
|
IGuiRemoteProtocolMessages (Rendering - Element)
|
|
***********************************************************************/
|
|
|
|
void Impl_RendererBeginBoundary(const remoteprotocol::ElementBoundary& arguments);
|
|
void Impl_RendererEndBoundary();
|
|
void EnsureRenderedElement(vint id, Rect bounds);
|
|
void Impl_RendererRenderElement(const remoteprotocol::ElementRendering& arguments);
|
|
|
|
/***********************************************************************
|
|
IGuiRemoteProtocolMessages (Rendering - Dom)
|
|
***********************************************************************/
|
|
|
|
void CalculateSolidLabelSizesIfNecessary(Ptr<remoteprotocol::RenderingDom> dom);
|
|
void Impl_RendererRenderDom(const Ptr<remoteprotocol::RenderingDom>& arguments);
|
|
void Impl_RendererRenderDomDiff(const remoteprotocol::RenderingDom_DiffsInOrder& arguments);
|
|
|
|
/***********************************************************************
|
|
IGuiRemoteProtocolMessages (Elements)
|
|
***********************************************************************/
|
|
|
|
void Impl_RendererCreated(const Ptr<collections::List<remoteprotocol::RendererCreation>>& arguments);
|
|
void Impl_RendererDestroyed(const Ptr<collections::List<vint>>& arguments);
|
|
|
|
template<remoteprotocol::RendererType RendererType, typename TElementDesc>
|
|
void RequestRendererUpdateElement(const TElementDesc& arguments, const wchar_t* emWrongId, const wchar_t* emWrongType)
|
|
{
|
|
vint index = loggedTrace.createdElements->Keys().IndexOf(arguments.id);
|
|
CHECK_ERROR(index != -1, emWrongId);
|
|
CHECK_ERROR(loggedTrace.createdElements->Values()[index] == RendererType, emWrongType);
|
|
lastElementDescs.Set(arguments.id, arguments);
|
|
}
|
|
|
|
void Impl_RendererUpdateElement_SolidBorder(const remoteprotocol::ElementDesc_SolidBorder& arguments);
|
|
void Impl_RendererUpdateElement_SinkBorder(const remoteprotocol::ElementDesc_SinkBorder& arguments);
|
|
void Impl_RendererUpdateElement_SinkSplitter(const remoteprotocol::ElementDesc_SinkSplitter& arguments);
|
|
void Impl_RendererUpdateElement_SolidBackground(const remoteprotocol::ElementDesc_SolidBackground& arguments);
|
|
void Impl_RendererUpdateElement_GradientBackground(const remoteprotocol::ElementDesc_GradientBackground& arguments);
|
|
void Impl_RendererUpdateElement_InnerShadow(const remoteprotocol::ElementDesc_InnerShadow& arguments);
|
|
void Impl_RendererUpdateElement_Polygon(const remoteprotocol::ElementDesc_Polygon& arguments);
|
|
|
|
/***********************************************************************
|
|
IGuiRemoteProtocolMessages (Elements - SolidLabel)
|
|
***********************************************************************/
|
|
|
|
void CalculateSolidLabelSizeIfNecessary(vint width, vint height, const remoteprotocol::ElementDesc_SolidLabel& arguments);
|
|
void Impl_RendererUpdateElement_SolidLabel(const remoteprotocol::ElementDesc_SolidLabel& arguments);
|
|
|
|
/***********************************************************************
|
|
IGuiRemoteProtocolMessages (Elements - Image)
|
|
***********************************************************************/
|
|
|
|
WString GetBinaryKeyFromBinary(stream::IStream& binary);
|
|
WString GetBinaryKeyFromImage(Ptr<INativeImage> image);
|
|
remoteprotocol::ImageMetadata MakeImageMetadata(const remoteprotocol::ImageCreation& arguments);
|
|
void Impl_ImageCreated(vint id, const remoteprotocol::ImageCreation& arguments);
|
|
void Impl_ImageDestroyed(const vint& arguments);
|
|
void Impl_RendererUpdateElement_ImageFrame(const remoteprotocol::ElementDesc_ImageFrame& arguments);
|
|
|
|
/***********************************************************************
|
|
IGuiRemoteProtocolMessages (Elements - Document)
|
|
***********************************************************************/
|
|
|
|
void Impl_RendererUpdateElement_DocumentParagraph(vint id, const remoteprotocol::ElementDesc_DocumentParagraph& arguments);
|
|
void Impl_DocumentParagraph_GetCaret(vint id, const remoteprotocol::GetCaretRequest& arguments);
|
|
void Impl_DocumentParagraph_GetCaretBounds(vint id, const remoteprotocol::GetCaretBoundsRequest& arguments);
|
|
void Impl_DocumentParagraph_GetInlineObjectFromPoint(vint id, const remoteprotocol::GetInlineObjectFromPointRequest & arguments);
|
|
void Impl_DocumentParagraph_GetNearestCaretFromTextPos(vint id, const remoteprotocol::GetCaretBoundsRequest& arguments);
|
|
void Impl_DocumentParagraph_IsValidCaret(vint id, const remoteprotocol::IsValidCaretRequest& arguments);
|
|
void Impl_DocumentParagraph_OpenCaret(const remoteprotocol::OpenCaretRequest& arguments);
|
|
void Impl_DocumentParagraph_CloseCaret(const vint& arguments);
|
|
};
|
|
}
|
|
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\GUIUNITTESTPROTOCOL.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Vczh Library++ 3.0
|
|
Developer: Zihan Chen(vczh)
|
|
Unit Test Snapsnot and other Utilities
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_PRESENTATION_GUIUNITTESTPROTOCOL
|
|
#define VCZH_PRESENTATION_GUIUNITTESTPROTOCOL
|
|
|
|
|
|
namespace vl::presentation::unittest
|
|
{
|
|
|
|
/***********************************************************************
|
|
UnitTestFrameworkConfig
|
|
***********************************************************************/
|
|
|
|
struct UnitTestFrameworkConfig
|
|
{
|
|
filesystem::FilePath snapshotFolder;
|
|
filesystem::FilePath resourceFolder;
|
|
};
|
|
|
|
extern const UnitTestFrameworkConfig& GetUnitTestFrameworkConfig();
|
|
|
|
/***********************************************************************
|
|
UnitTestRemoteProtocol
|
|
***********************************************************************/
|
|
|
|
class UnitTestRemoteProtocolFeatures :
|
|
public UnitTestRemoteProtocol_MainWindow,
|
|
public UnitTestRemoteProtocol_IO,
|
|
public UnitTestRemoteProtocol_Rendering,
|
|
public UnitTestRemoteProtocol_IOCommands
|
|
{
|
|
protected:
|
|
bool stopped = false;
|
|
bool everRendered = false;
|
|
Ptr<UnitTestLoggedFrame> candidateFrame;
|
|
vint idlingCounter = 0;
|
|
|
|
bool LogRenderingResult()
|
|
{
|
|
#define ERROR_MESSAGE_PREFIX L"vl::presentation::unittest::UnitTestRemoteProtocolFeatures::LogRenderingResult()#"
|
|
if (auto lastFrame = this->TryGetLastRenderingFrameAndReset())
|
|
{
|
|
candidateFrame = lastFrame;
|
|
everRendered = true;
|
|
}
|
|
else if (everRendered)
|
|
{
|
|
if (candidateFrame)
|
|
{
|
|
idlingCounter = 0;
|
|
auto descs = Ptr(new collections::Dictionary<vint, ElementDescVariant>);
|
|
CopyFrom(*descs.Obj(), this->lastElementDescs);
|
|
this->loggedTrace.frames->Add({
|
|
candidateFrame->frameId,
|
|
{},
|
|
this->sizingConfig,
|
|
descs,
|
|
candidateFrame->renderingDom
|
|
});
|
|
candidateFrame = {};
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
idlingCounter++;
|
|
if (idlingCounter == 100)
|
|
{
|
|
CHECK_ERROR(
|
|
idlingCounter < 100,
|
|
ERROR_MESSAGE_PREFIX L"The last frame didn't trigger UI updating. The action registered by OnNextIdleFrame should always make any element or layout to change."
|
|
);
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
#undef ERROR_MESSAGE_PREFIX
|
|
}
|
|
|
|
public:
|
|
UnitTestRemoteProtocolFeatures(const UnitTestScreenConfig& _globalConfig)
|
|
: UnitTestRemoteProtocol_MainWindow(_globalConfig)
|
|
, UnitTestRemoteProtocol_IO(_globalConfig)
|
|
, UnitTestRemoteProtocol_Rendering(_globalConfig)
|
|
, UnitTestRemoteProtocol_IOCommands(_globalConfig)
|
|
{
|
|
}
|
|
|
|
const auto& GetLoggedTrace()
|
|
{
|
|
return this->loggedTrace;
|
|
}
|
|
|
|
const auto& GetLoggedFrames()
|
|
{
|
|
return this->loggedFrames;
|
|
}
|
|
|
|
/***********************************************************************
|
|
IGuiRemoteProtocolMessages (Initialization)
|
|
***********************************************************************/
|
|
|
|
protected:
|
|
|
|
void Impl_ControllerConnectionEstablished()
|
|
{
|
|
ResetCreatedObjects();
|
|
}
|
|
|
|
void Impl_ControllerConnectionStopped()
|
|
{
|
|
stopped = true;
|
|
}
|
|
};
|
|
|
|
class UnitTestRemoteProtocol
|
|
: public UnitTestRemoteProtocolFeatures
|
|
, protected virtual IGuiRemoteEventProcessor
|
|
{
|
|
using EventPair = collections::Pair<Nullable<WString>, Func<void()>>;
|
|
protected:
|
|
const UnitTestFrameworkConfig& frameworkConfig;
|
|
WString appName;
|
|
collections::List<EventPair> processRemoteEvents;
|
|
vint lastFrameIndex = -1;
|
|
vint nextEventIndex = 0;
|
|
bool frameExecuting = false;
|
|
|
|
public:
|
|
|
|
UnitTestRemoteProtocol(const WString& _appName, UnitTestScreenConfig _globalConfig)
|
|
: UnitTestRemoteProtocolBase(_globalConfig)
|
|
, UnitTestRemoteProtocolFeatures(_globalConfig)
|
|
, frameworkConfig(GetUnitTestFrameworkConfig())
|
|
, appName(_appName)
|
|
{
|
|
}
|
|
|
|
template<typename TCallback>
|
|
void OnNextIdleFrame(TCallback&& callback)
|
|
{
|
|
processRemoteEvents.Add({ Nullable<WString>{},std::forward<TCallback&&>(callback) });
|
|
}
|
|
|
|
template<typename TCallback>
|
|
void OnNextIdleFrame(const WString& name, TCallback&& callback)
|
|
{
|
|
processRemoteEvents.Add({ name,std::forward<TCallback&&>(callback) });
|
|
}
|
|
|
|
/***********************************************************************
|
|
IGuiRemoteProtocolMessages
|
|
***********************************************************************/
|
|
|
|
#define MESSAGE_NOREQ_NORES(NAME, REQUEST, RESPONSE) void Request ## NAME() override { UnitTestRemoteProtocolFeatures::Impl_ ## NAME(); }
|
|
#define MESSAGE_NOREQ_RES(NAME, REQUEST, RESPONSE) void Request ## NAME(vint id) override { UnitTestRemoteProtocolFeatures::Impl_ ## NAME(id); }
|
|
#define MESSAGE_REQ_NORES(NAME, REQUEST, RESPONSE) void Request ## NAME(const REQUEST& arguments) override { UnitTestRemoteProtocolFeatures::Impl_ ## NAME(arguments); }
|
|
#define MESSAGE_REQ_RES(NAME, REQUEST, RESPONSE) void Request ## NAME(vint id, const REQUEST& arguments) override { UnitTestRemoteProtocolFeatures::Impl_ ## NAME(id, arguments); }
|
|
#define MESSAGE_HANDLER(NAME, REQUEST, RESPONSE, REQTAG, RESTAG, ...) MESSAGE_ ## REQTAG ## _ ## RESTAG(NAME, REQUEST, RESPONSE)
|
|
GACUI_REMOTEPROTOCOL_MESSAGES(MESSAGE_HANDLER)
|
|
#undef MESSAGE_HANDLER
|
|
#undef MESSAGE_REQ_RES
|
|
#undef MESSAGE_REQ_NORES
|
|
#undef MESSAGE_NOREQ_RES
|
|
#undef MESSAGE_NOREQ_NORES
|
|
|
|
/***********************************************************************
|
|
IGuiRemoteProtocol
|
|
***********************************************************************/
|
|
|
|
void Submit(bool& disconnected) override
|
|
{
|
|
// TODO: Failure injection to disconnected
|
|
}
|
|
|
|
void ProcessRemoteEvents() override
|
|
{
|
|
#define ERROR_MESSAGE_PREFIX L"vl::presentation::unittest::UnitTestRemoteProtocol::ProcessRemoteEvents()#"
|
|
if (!stopped)
|
|
{
|
|
if (LogRenderingResult())
|
|
{
|
|
auto [name, func] = processRemoteEvents[nextEventIndex];
|
|
CHECK_ERROR(!frameExecuting, ERROR_MESSAGE_PREFIX L"The action registered by OnNextIdleFrame should not call any blocking function, consider using InvokeInMainThread.");
|
|
vl::unittest::UnitTest::PrintMessage(L"Execute idle frame[" + (name ? name.Value() : itow(nextEventIndex)) + L"]", vl::unittest::UnitTest::MessageKind::Info);
|
|
CHECK_ERROR(lastFrameIndex != loggedTrace.frames->Count() - 1, ERROR_MESSAGE_PREFIX L"No rendering occured after the last idle frame.");
|
|
lastFrameIndex = loggedTrace.frames->Count() - 1;
|
|
|
|
if (name)
|
|
{
|
|
auto&& lastFrame = (*loggedTrace.frames.Obj())[loggedTrace.frames->Count() - 1];
|
|
lastFrame.frameName = name;
|
|
}
|
|
frameExecuting = true;
|
|
func();
|
|
frameExecuting = false;
|
|
nextEventIndex++;
|
|
}
|
|
}
|
|
#undef ERROR_MESSAGE_PREFIX
|
|
}
|
|
|
|
IGuiRemoteEventProcessor* GetRemoteEventProcessor() override
|
|
{
|
|
return this;
|
|
}
|
|
};
|
|
}
|
|
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\GUIUNITTESTUTILITIES.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Vczh Library++ 3.0
|
|
Developer: Zihan Chen(vczh)
|
|
Unit Test Snapsnot and other Utilities
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_PRESENTATION_GUIUNITTESTUTILITIES
|
|
#define VCZH_PRESENTATION_GUIUNITTESTUTILITIES
|
|
|
|
|
|
namespace vl::presentation::unittest
|
|
{
|
|
class IUnitTestContext : public virtual Interface
|
|
{
|
|
public:
|
|
};
|
|
|
|
using UnitTestMainFunc = vl::Func<void(UnitTestRemoteProtocol*, IUnitTestContext*)>;
|
|
using UnitTestLinkFunc = vl::Func<void(UnitTestRemoteProtocol*, IUnitTestContext*, const UnitTestMainFunc&)>;
|
|
}
|
|
|
|
extern void GacUIUnitTest_Initialize(const vl::presentation::unittest::UnitTestFrameworkConfig* config);
|
|
extern void GacUIUnitTest_Finalize();
|
|
extern void GacUIUnitTest_SetGuiMainProxy(const vl::presentation::unittest::UnitTestMainFunc& proxy);
|
|
extern void GacUIUnitTest_LinkGuiMainProxy(const vl::presentation::unittest::UnitTestLinkFunc& proxy);
|
|
extern void GacUIUnitTest_Start(const vl::WString& appName, vl::Nullable<vl::presentation::unittest::UnitTestScreenConfig> config = {});
|
|
extern void GacUIUnitTest_StartAsync(const vl::WString& appName, vl::Nullable<vl::presentation::unittest::UnitTestScreenConfig> config = {});
|
|
extern void GacUIUnitTest_Start_WithResourceAsText(const vl::WString& appName, vl::Nullable<vl::presentation::unittest::UnitTestScreenConfig> config, const vl::WString& resourceText);
|
|
extern vl::Ptr<vl::presentation::GuiResource> GacUIUnitTest_CompileAndLoad(const vl::WString& xmlResource);
|
|
|
|
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
|
|
|
|
struct GacUIUnitTest_Installer
|
|
{
|
|
vl::Func<void()> initialize;
|
|
vl::Func<void()> finalize;
|
|
vl::Func<void(vl::presentation::controls::GuiWindow*)> installWindow;
|
|
vl::Nullable<vl::presentation::unittest::UnitTestScreenConfig> config;
|
|
};
|
|
|
|
template<typename TTheme>
|
|
void GacUIUnitTest_StartFast_WithResourceAsText(
|
|
const vl::WString& appName,
|
|
const vl::WString& windowTypeFullName,
|
|
const vl::WString& resourceText,
|
|
GacUIUnitTest_Installer installer = {}
|
|
)
|
|
{
|
|
GacUIUnitTest_LinkGuiMainProxy([=](
|
|
vl::presentation::unittest::UnitTestRemoteProtocol* protocol,
|
|
vl::presentation::unittest::IUnitTestContext* context,
|
|
const vl::presentation::unittest::UnitTestMainFunc& previousMainProxy
|
|
)
|
|
{
|
|
{
|
|
vl::presentation::remoteprotocol::ControllerGlobalConfig globalConfig;
|
|
#if defined VCZH_WCHAR_UTF16
|
|
globalConfig.documentCaretFromEncoding = vl::presentation::remoteprotocol::CharacterEncoding::UTF16;
|
|
#elif defined VCZH_WCHAR_UTF32
|
|
globalConfig.documentCaretFromEncoding = vl::presentation::remoteprotocol::CharacterEncoding::UTF32;
|
|
#endif
|
|
protocol->GetEvents()->OnControllerConnect(globalConfig);
|
|
}
|
|
auto theme = vl::Ptr(new TTheme);
|
|
vl::presentation::theme::RegisterTheme(theme);
|
|
{
|
|
if(installer.initialize)
|
|
{
|
|
installer.initialize();
|
|
}
|
|
auto windowValue = vl::reflection::description::Value::Create(windowTypeFullName);
|
|
TEST_ASSERT(windowValue.GetRawPtr());
|
|
|
|
auto window = vl::Ptr(windowValue.GetRawPtr()->SafeAggregationCast<vl::presentation::controls::GuiWindow>());
|
|
TEST_ASSERT(window);
|
|
|
|
if (installer.installWindow)
|
|
{
|
|
installer.installWindow(window.Obj());
|
|
}
|
|
window->MoveToScreenCenter();
|
|
previousMainProxy(protocol, context);
|
|
vl::presentation::controls::GetApplication()->Run(window.Obj());
|
|
if (installer.finalize)
|
|
{
|
|
installer.finalize();
|
|
}
|
|
}
|
|
vl::presentation::theme::UnregisterTheme(theme->Name);
|
|
});
|
|
GacUIUnitTest_Start_WithResourceAsText(appName, installer.config, resourceText);
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif
|