test: login_flow waits a fixed frame count between mouse move and click

The 0.1 s wall-clock waits could fit a single frame under ctest -j3, so the
shopkeeper pick missed about one run in four.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
shenlei
2026-09-28 14:17:26 +09:00
co-authored by Claude Opus 5.5
parent 3e270dccc1
commit d3fd5f8613
+21 -10
View File
@@ -162,6 +162,17 @@ static bool pump_until(double seconds, const std::function<bool()>& done)
return done();
}
// Runs a fixed number of frames: the wait between a mouse move and its click must not depend on how
// many frames a loaded machine fits into a wall-clock slice (ctest -j).
static void pump_frames(int count)
{
for (int i = 0; i < count && PythonBoot::IsAppLooping(); ++i)
{
PythonBoot::UIUpdate();
std::this_thread::sleep_for(std::chrono::milliseconds(16));
}
}
static void dump(FakeLoginServer& server)
{
std::fprintf(stderr, "server events:");
@@ -617,7 +628,7 @@ int main(int argc, char** argv)
// Holding ALT (game.GameWindow.ShowName) makes OnRender show every tail in range and project it after
// app.RenderGame; the item tail keeps that screen rect, which is what textTail.Pick tests.
PythonBoot::UIKey(DIK_LMENU, true);
pump_until(0.1, [] { return false; });
pump_frames(6);
PythonBoot::UIKey(DIK_LMENU, false);
int picked = -1, pick_x = 0, pick_y = 0;
for (int y = 0; y < 1200 && picked < 0; y += 2)
@@ -677,7 +688,7 @@ int main(int argc, char** argv)
if (main_instance)
main_instance->NEW_GetPixelPosition(&start);
PythonBoot::UIMouseButton(1, true, 400, 220);
pump_until(0.1, [] { return false; });
pump_frames(6);
PythonBoot::UIMouseButton(1, false, 400, 220);
CHECK(main_instance && pump_until(3, [&] { return walked() > 100.0f; }));
CHECK(main_instance && pump_until(10, [&] { return !main_instance->IsWalking(); }));
@@ -728,7 +739,7 @@ int main(int argc, char** argv)
auto [sx, sy] = dog_on_screen();
std::printf("port_login_flow_test: stray dog on screen at %d %d\n", sx, sy);
PythonBoot::UIMouseMove(sx, sy);
pump_until(0.1, [] { return false; });
pump_frames(6);
// game.GameWindow.OnMouseLeftButtonDown → player.SetMouseState(MBT_LEFT, MBS_PRESS): MBF_SMART on an
// actor is __OnPressActor, which walks into range (__ReserveClickActor) and attacks while the button is
// held; the cursor follows the dog as the camera follows the actor, as a player's hand would.
@@ -761,14 +772,14 @@ int main(int argc, char** argv)
// Zoom IN: positive wheel delta
PythonBoot::UIMouseWheel(120);
pump_until(0.1, [] { return false; });
pump_frames(6);
const float zoomed_in_dist = pkCmrCur->GetDistance();
std::printf("port_login_flow_test: zoomed in camera distance = %f\n", zoomed_in_dist);
CHECK(zoomed_in_dist < initial_dist);
// Zoom OUT: negative wheel delta
PythonBoot::UIMouseWheel(-240);
pump_until(0.1, [] { return false; });
pump_frames(6);
const float zoomed_out_dist = pkCmrCur->GetDistance();
std::printf("port_login_flow_test: zoomed out camera distance = %f\n", zoomed_out_dist);
CHECK(zoomed_out_dist > zoomed_in_dist);
@@ -796,7 +807,7 @@ int main(int argc, char** argv)
bool has_effects = false;
for (int step = 0; step < 10; ++step)
{
pump_until(0.1, [] { return false; });
pump_frames(6);
if (CEffectInstance::GetRenderingEffectCount() > 0)
has_effects = true;
}
@@ -833,9 +844,9 @@ int main(int argc, char** argv)
auto [kx, ky] = keeper_on_screen();
std::printf("port_login_flow_test: shopkeeper on screen at %d %d\n", kx, ky);
PythonBoot::UIMouseMove(kx, ky);
pump_until(0.1, [] { return false; });
pump_frames(6);
PythonBoot::UIMouseButton(1, true, kx, ky);
pump_until(0.1, [] { return false; });
pump_frames(6);
PythonBoot::UIMouseButton(1, false, kx, ky);
CHECK(pump_until(5, [&] { return server->Has("game2:click " + std::to_string(FakeLoginServer::kShopVID)); }));
CHECK(pump_until(2, [] { return py_true("__import__('shop').IsOpen() and _stream.curPhaseWindow.interface.dlgShop.IsShow()"); }));
@@ -1009,9 +1020,9 @@ int main(int argc, char** argv)
auto [sx, sy] = storekeeper_on_screen();
std::printf("port_login_flow_test: storekeeper on screen at %d %d\n", sx, sy);
PythonBoot::UIMouseMove(sx, sy);
pump_until(0.1, [] { return false; });
pump_frames(6);
PythonBoot::UIMouseButton(1, true, sx, sy);
pump_until(0.1, [] { return false; });
pump_frames(6);
PythonBoot::UIMouseButton(1, false, sx, sy);
CHECK(pump_until(5, [&] { return server->Has("game2:click " + std::to_string(FakeLoginServer::kSafeboxVID)); }));
CHECK(pump_until(2, [] {