Skip to content

Commit 993154e

Browse files
committed
Test: Replace the unit test framework with Boost.Test;
Add TestMouseMoveLatency; Fix the KeyboardTest bug
1 parent 29272b9 commit 993154e

6 files changed

Lines changed: 178 additions & 205 deletions

File tree

AhkDll.Test/AhkDll.Test.cpp

Lines changed: 133 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
1-
#include "pch.h"
1+
#include "../AhkDll/IbAhkSend.hpp"
2+
using namespace Send;
3+
4+
#define BOOST_TEST_MODULE AhkDll.Test
5+
#include <boost/test/unit_test.hpp>
6+
#include <fmt/core.h>
7+
28
#include <thread>
39
#include <mutex>
10+
#include <future>
411
#include <queue>
5-
#include <fmt/core.h>
6-
#include "CppUnitTest.h"
7-
812
#include <IbWinCppLib/WinCppLib.hpp>
9-
#include "../AhkDll/IbAhkSend.hpp"
1013

11-
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
1214

1315
class Measure {
1416
LARGE_INTEGER t;
@@ -31,40 +33,28 @@ class Measure {
3133
}
3234
};
3335

34-
void send_init(Send::SendType type, Send::InitFlags flags = 0, void* argument = nullptr) {
35-
//cannot be put in TEST_MODULE_INITIALIZE for unknown reason
36-
Send::Error error = IbAhkSendInit(type, flags, argument);
37-
Assert::AreEqual((uint32_t)Send::Error::Success, (uint32_t)error);
38-
}
36+
template <SendType TypeV>
37+
class InitTest {
38+
public:
39+
InitTest() {
40+
Send::Error error = IbAhkSendInit(TypeV, 0, nullptr);
41+
BOOST_REQUIRE(error == Send::Error::Success);
42+
}
3943

40-
class KeyboardTestBase
44+
~InitTest() {
45+
IbAhkSendDestroy();
46+
}
47+
};
48+
49+
template <SendType TypeV>
50+
class KeyboardTest : public InitTest<TypeV>
4151
{
42-
public:
4352
static inline HHOOK hook;
4453
static inline bool capture;
4554
static inline std::queue<DWORD> input_keys;
4655
static inline std::mutex mutex;
4756

48-
KeyboardTestBase() {
49-
capture = false;
50-
std::thread t([] {
51-
hook = SetWindowsHookExW(WH_KEYBOARD_LL, LowLevelKeyboardProc, GetModuleHandle(0), 0);
52-
Assert::AreNotEqual<void*>(NULL, hook);
53-
54-
MSG messages;
55-
while (GetMessageW(&messages, NULL, 0, 0))
56-
{
57-
TranslateMessage(&messages);
58-
DispatchMessageW(&messages);
59-
}
60-
});
61-
t.detach();
62-
}
63-
64-
~KeyboardTestBase() {
65-
IbAhkSendDestroy();
66-
UnhookWindowsHookEx(hook);
67-
}
57+
std::thread t;
6858

6959
static LRESULT CALLBACK LowLevelKeyboardProc(
7060
_In_ int nCode,
@@ -80,80 +70,90 @@ class KeyboardTestBase
8070
}
8171
return CallNextHookEx(hook, nCode, wParam, lParam);
8272
}
73+
public:
74+
KeyboardTest() {
75+
capture = false;
76+
std::promise<HHOOK> pro;
77+
std::future<HHOOK> fut = pro.get_future();
78+
t = std::thread([](std::promise<HHOOK>&& pro) {
79+
pro.set_value(SetWindowsHookExW(WH_KEYBOARD_LL, LowLevelKeyboardProc, GetModuleHandle(0), 0));
80+
81+
MSG messages;
82+
while (GetMessageW(&messages, NULL, 0, 0))
83+
{
84+
TranslateMessage(&messages);
85+
DispatchMessageW(&messages);
86+
}
87+
}, std::move(pro));
88+
hook = fut.get();
89+
BOOST_REQUIRE(hook != NULL);
90+
}
91+
92+
~KeyboardTest() {
93+
std::thread::id id = t.get_id();
94+
PostThreadMessageW(*(DWORD*)(&id), WM_QUIT, 0, 0);
95+
UnhookWindowsHookEx(hook);
96+
input_keys = {};
97+
98+
t.join();
99+
}
83100

84-
void MeasureKeyboardLatency() {
101+
void TestKeyboardLatency() {
85102
Measure measure;
86103

87-
measure.begin();
88-
{
89-
INPUT input[2];
104+
INPUT input[2];
90105

91-
input[0].type = INPUT_KEYBOARD;
92-
input[0].ki = {};
93-
input[0].ki.wVk = VK_F12;
106+
input[0].type = INPUT_KEYBOARD;
107+
input[0].ki = {};
108+
input[0].ki.wVk = VK_F12;
94109

95-
input[1].type = INPUT_KEYBOARD;
96-
input[1].ki = {};
97-
input[1].ki.wVk = VK_F12;
98-
input[1].ki.dwFlags = KEYEVENTF_KEYUP;
110+
input[1].type = INPUT_KEYBOARD;
111+
input[1].ki = {};
112+
input[1].ki.wVk = VK_F12;
113+
input[1].ki.dwFlags = KEYEVENTF_KEYUP;
99114

100-
capture = true;
101-
IbAhkSendInput(2, input, sizeof INPUT);
102-
}
115+
capture = true;
116+
measure.begin();
117+
IbAhkSendInput(2, input, sizeof INPUT);
103118
uint64_t t1 = measure.end();
104-
119+
105120
measure.begin();
106121
{
107122
while (input_keys.size() < 2)
108123
_mm_pause();
109124
capture = false;
110125
}
111126
uint64_t t2 = measure.end();
112-
//SendInput: 600ns (0) //#TODO: bug for unknown reason
113-
//Logitech: 0.8~4ms
114127

115128
{
116129
std::lock_guard lock(mutex);
117-
Assert::AreEqual<DWORD>(VK_F12, input_keys.back());
130+
BOOST_CHECK(input_keys.back() == VK_F12);
118131
input_keys.pop();
119-
Assert::AreEqual<DWORD>(VK_F12, input_keys.back());
132+
BOOST_CHECK(input_keys.back() == VK_F12);
120133
input_keys.pop();
121134
}
122135

123-
Logger::WriteMessage(fmt::format("Duration: {}ns\n", t1).c_str());
124-
Logger::WriteMessage(fmt::format("Latency: {}ns\n", t2).c_str());
136+
BOOST_TEST_MESSAGE(fmt::format("Duration: {}ns\n", t1));
137+
//SendInput: 1~3ms
138+
//Logitech: 25~45us
139+
BOOST_TEST_MESSAGE(fmt::format("Latency: {}ns\n", t2));
140+
//SendInput: 100ns (0)
141+
//Logitech: 0.8~4ms
125142
}
126143
};
127144

128-
#define CODE_GENERATE_KEYBOARDTEST(type) \
129-
TEST_CLASS(KeyboardTest), private KeyboardTestBase { \
130-
using base = KeyboardTestBase; \
131-
public: \
132-
KeyboardTest() { \
133-
send_init(Send::SendType::type); \
134-
} \
135-
\
136-
TEST_METHOD(MeasureKeyboardLatency) { \
137-
base::MeasureKeyboardLatency(); \
138-
} \
139-
};
140-
141-
class MouseTestBase {
145+
template <SendType TypeV>
146+
class MouseTest : public InitTest<TypeV> {
142147
public:
143-
MouseTestBase() {}
144-
145-
~MouseTestBase() {
146-
IbAhkSendDestroy();
147-
}
148-
149-
void MeasureMouseMoveDuration() {
150-
Measure t;
151-
152-
t.begin();
148+
void TestMouseMove() {
149+
Measure measure;
150+
153151
INPUT input;
154152
input.type = INPUT_MOUSE;
155153
input.mi = {};
156154
input.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_MOVE_NOCOALESCE;
155+
156+
measure.begin();
157157
for (size_t i = 0; i < 10000 / 200; i++) {
158158
input.mi.dx = input.mi.dy = 1;
159159
for (size_t i = 0; i < 100; i++)
@@ -163,13 +163,37 @@ class MouseTestBase {
163163
for (size_t i = 0; i < 100; i++)
164164
IbAhkSendInput(1, &input, sizeof INPUT);
165165
}
166-
uint64_t d = t.end();
167-
Logger::WriteMessage(fmt::format("{}ns\n", d / 10000).c_str());
168-
//SendInput: 245us
169-
//Logitech: 3us
166+
uint64_t t = measure.end();
167+
BOOST_TEST_MESSAGE(fmt::format("Duration: {}ns\n", t / 10000));
168+
//SendInput: 200~800us
169+
//Logitech: 3~10us
170170
}
171171

172-
void MeasureMouseMovement() {
172+
void TestMouseMoveLatency() {
173+
Measure measure;
174+
175+
POINT p1, p2, d;
176+
GetCursorPos(&p1);
177+
178+
INPUT input;
179+
input.type = INPUT_MOUSE;
180+
input.mi = {};
181+
input.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_MOVE_NOCOALESCE;
182+
input.mi.dx = input.mi.dy = 100;
183+
IbAhkSendInput(1, &input, sizeof INPUT);
184+
185+
measure.begin();
186+
do {
187+
GetCursorPos(&p2);
188+
d = { p2.x - p1.x, p2.y - p1.y };
189+
} while (!(d.x >= 50 && d.y >= 50));
190+
uint64_t latency = measure.end();
191+
BOOST_TEST_MESSAGE(fmt::format("Latency: {}ns\n", latency));
192+
//SendInput: 3~200us
193+
//Logitech: 900~4000us (0.9~4ms)
194+
}
195+
196+
void TestMouseMoveDistance() {
173197
POINT p1, p2, d1, d2;
174198
GetCursorPos(&p1);
175199

@@ -187,43 +211,37 @@ class MouseTestBase {
187211

188212
GetCursorPos(&p2);
189213
d2 = { p2.x - p1.x, p2.y - p1.y };
214+
BOOST_CHECK((abs(d2.x - 100) <= 10 && abs(d2.y - 100) <= 100));
190215

191-
Logger::WriteMessage(fmt::format("0ms: ({}, {})\n", d1.x, d1.y).c_str());
192-
Logger::WriteMessage(fmt::format("10ms: ({}, {})\n", d2.x, d2.y).c_str());
216+
BOOST_TEST_MESSAGE(fmt::format("0ms: ({}, {})\n", d1.x, d1.y));
217+
BOOST_TEST_MESSAGE(fmt::format("10ms: ({}, {})\n", d2.x, d2.y));
193218
}
194219
};
195220

196-
#define CODE_GENERATE_MOUSETEST(type) \
197-
TEST_CLASS(MouseTest), private MouseTestBase { \
198-
using base = MouseTestBase; \
199-
public: \
200-
MouseTest() { \
201-
send_init(Send::SendType::type); \
221+
#define CODE_GENERATE_TEST_NAME(name, type) \
222+
BOOST_AUTO_TEST_SUITE(name) \
223+
BOOST_FIXTURE_TEST_SUITE(Keyboard, KeyboardTest<SendType::type>) \
224+
using base = BOOST_AUTO_TEST_CASE_FIXTURE; \
225+
BOOST_AUTO_TEST_CASE(TestKeyboardLatency) { \
226+
base::TestKeyboardLatency(); \
202227
} \
203-
\
204-
TEST_METHOD(MeasureMouseMoveDuration) { \
205-
base::MeasureMouseMoveDuration(); \
228+
BOOST_AUTO_TEST_SUITE_END() \
229+
\
230+
BOOST_FIXTURE_TEST_SUITE(Mouse, MouseTest<SendType::type>) \
231+
using base = BOOST_AUTO_TEST_CASE_FIXTURE; \
232+
BOOST_AUTO_TEST_CASE(TestMouseMove) { \
233+
base::TestMouseMove(); \
206234
} \
207-
\
208-
TEST_METHOD(MeasureMouseMovement) { \
209-
base::MeasureMouseMovement(); \
235+
BOOST_AUTO_TEST_CASE(TestMouseMoveLatency) { \
236+
base::TestMouseMoveLatency(); \
210237
} \
211-
};
212-
213-
namespace AnyDriverTest
214-
{
215-
CODE_GENERATE_KEYBOARDTEST(AnyDriver)
216-
CODE_GENERATE_MOUSETEST(AnyDriver)
217-
}
218-
219-
namespace SendInputTest
220-
{
221-
CODE_GENERATE_KEYBOARDTEST(SendInput)
222-
CODE_GENERATE_MOUSETEST(SendInput)
223-
}
238+
BOOST_AUTO_TEST_CASE(TestMouseMoveDistance) { \
239+
base::TestMouseMoveDistance(); \
240+
} \
241+
BOOST_AUTO_TEST_SUITE_END() \
242+
BOOST_AUTO_TEST_SUITE_END()
243+
#define CODE_GENERATE_TEST(type) CODE_GENERATE_TEST_NAME(type, type)
224244

225-
namespace LogitechTest
226-
{
227-
CODE_GENERATE_KEYBOARDTEST(Logitech)
228-
CODE_GENERATE_MOUSETEST(Logitech)
229-
}
245+
CODE_GENERATE_TEST_NAME(SendInput_, SendInput)
246+
CODE_GENERATE_TEST(AnyDriver)
247+
CODE_GENERATE_TEST(Logitech)

0 commit comments

Comments
 (0)