Fix padded Wine review strings

This commit is contained in:
deedra committed 2026-10-11 22:07:14 -07:00
1 parent a8cb350467
commit f40e471938
7 files changed
+416 -33

No files matched your search

+63 -1
View File
@@ -9,6 +9,17 @@
#include "../review_capture.h"
#define HAS_CAPTURE 1
#endif
static LRESULT CALLBACK padded_name_proc(HWND window,UINT message,WPARAM wp,LPARAM lp) {
const WCHAR text[]={L'R',L'e',L'a',L'd',L'y',0,0xd800,0};
if(message==WM_GETTEXTLENGTH)return 7;
if(message==WM_GETTEXT && wp) {
const size_t copied=std::min<size_t>(7,wp-1);
std::copy_n(text,copied,reinterpret_cast<WCHAR*>(lp));
reinterpret_cast<WCHAR*>(lp)[copied]=0;
return copied;
}
return DefWindowProcW(window,message,wp,lp);
}
static bool check(bool value, const char *message) {
if (!value) std::fprintf(stderr, "FAIL: %s\n", message);
@@ -67,15 +78,18 @@ int main(int argc, char **argv) {
ok &= check(text.find("private-review-secret") == std::string::npos && text.find("hidden-review-secret") == std::string::npos,
"password and hidden contents excluded");
ok &= check(SendMessageW(window, WM_APP + 11, 0, 0), "review preserves focus and selection");
for (int mode : {1, 2, 3, 4, 5, 6, 7, 8, 9, 14, 15, 17, 18, 21, 22, 23, 24, 25}) {
for (int mode : {1, 2, 3, 4, 5, 6, 7, 8, 9, 14, 15, 17, 18, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33}) {
std::fprintf(stderr, "capture test: mode %d\n", mode);
SendMessageW(window, WM_APP + 10, mode, 0);
auto started=GetTickCount64();
auto result = capture();
std::fprintf(stderr,"capture test: status=%s elapsed=%llu ms\n",result.status.c_str(),static_cast<unsigned long long>(GetTickCount64()-started));
const auto value = joined(result);
if (mode == 7) ok &= check(result.status == "limited" && result.nodes.empty(), "source limit rejects partial capture");
else if (mode == 9) ok &= check(result.status == "stale" && result.nodes.empty(), "same-length update during capture rejects mixed data");
else if (mode == 14 || mode == 15 || mode == 18 || mode == 23) ok &= check(result.status == "stale" && result.nodes.empty(), "protection/list/viewport transition rejects old capture");
else if (mode == 21) ok &= check(result.status != "ok" && result.nodes.empty(), "delayed native call respects capture deadline");
else if (mode == 27) ok &= check(result.status != "ok" && result.nodes.empty() && GetTickCount64()-started<600,"delayed scalar batch respects capture deadline");
else ok &= check(result.status == "ok", "configured capture succeeds");
ok &= check(value.find("private-review-secret") == std::string::npos && value.find("hidden-review-secret") == std::string::npos,
"all captures exclude protected/hidden text");
@@ -102,6 +116,37 @@ int main(int argc, char **argv) {
if (mode == 14) ok &= check(SendMessageW(window,WM_APP + 14,0,0), "password transition is excluded before copying text");
if (mode == 17) ok &= check(value.find("table & item") != std::string::npos && value.find("ready") != std::string::npos, "visible native ListView cells retain text and ampersands");
if (mode == 25) ok &= check(value.find("literal & label") != std::string::npos, "SS_NOPREFIX captions retain literal ampersands");
if (mode == 26) {
size_t visible_lines=0;
for(const auto &node:result.nodes)for(const auto &range:node.ranges)
if(range.text=="stable buffered output line")++visible_lines;
ok &= check(visible_lines>=15,"frame-pumped multiline output captures within the deadline");
}
if(mode==27){
Sleep(750);SendMessageW(window,WM_APP+10,0,0);
auto recovered=capture();
ok &= check(recovered.status=="ok" && joined(recovered).find("alpha beta")!=std::string::npos,"late scalar callbacks preserve storage and allow a fresh capture");
}
if(mode==28)ok &= check(value.find("top clipped visible line")!=std::string::npos,"top-clipped Edit captures its lower visible rows");
if(mode==29)ok &= check(value.find("nested output ready")!=std::string::npos && SendMessageW(window,WM_APP+16,0,0),"native containers do not synthesize duplicate accessibility trees");
if(mode==30)ok &= check(value.find("active mdi text")!=std::string::npos && value.find("covered mdi text")==std::string::npos,"maximized MDI child excludes covered background text");
if(mode==31)ok &= check(value.find("active mdi text")!=std::string::npos && value.find("covered mdi text")!=std::string::npos,"side-by-side MDI children retain both visible documents");
if (mode == 31) ok &= check(value.find("Active") != std::string::npos && value.find("Background") != std::string::npos,
"side-by-side MDI window titles remain available for review");
if (mode == 32) ok &= check(value.find("deep clipped visible line") != std::string::npos,
"hundreds of clipped rows do not hide the visible tail");
if (mode == 33) {
bool safe=true, status_present=false;
const auto status_id=store.identity(GetDlgItem(window,114))+"_a";
for(const auto &node:result.nodes) {
if(node.id==status_id)status_present=true;
safe &= node.name.find('\0')==std::string::npos;
for(const auto &range:node.ranges)safe &= range.text.find('\0')==std::string::npos;
}
ok &= check(status_present && safe,"padded MSAA status name produces D-Bus-safe accessibility text");
ok &= check(value.find("Ready")!=std::string::npos,
"status bar retains its exposed label");
}
if (mode == 21) {
Sleep(750);
ok &= check(SendMessageW(window,WM_APP + 15,0,0), "remote buffer lives until the delayed target returns");
@@ -128,6 +173,23 @@ int main(int argc, char **argv) {
}
if (mode != 4) ok &= check(SendMessageW(window, WM_APP + 11, 0, 0), "capture leaves caret and focus unchanged");
}
// A local provider avoids cross-process WM_GETTEXT marshalling, which
// itself truncates at the first NUL. Its BSTR retains malformed padding.
WNDCLASSW local{};local.hInstance=GetModuleHandleW(nullptr);
local.lpfnWndProc=DefWindowProcW;local.lpszClassName=L"WineReviewLocalRoot";
RegisterClassW(&local);
HWND local_root=CreateWindowW(local.lpszClassName,L"Padded MSAA name",WS_OVERLAPPEDWINDOW,
100,100,400,200,nullptr,nullptr,local.hInstance,nullptr);
local.lpfnWndProc=padded_name_proc;local.lpszClassName=L"WineReviewPaddedName";
RegisterClassW(&local);
HWND padded=CreateWindowW(local.lpszClassName,L"",WS_CHILD|WS_VISIBLE,
10,10,200,30,local_root,nullptr,local.hInstance,nullptr);
ShowWindow(local_root,SW_SHOW);SetForegroundWindow(local_root);SetFocus(padded);
auto padded_focus=store.observe_foreground();
auto padded_capture=capture_review_window(store,padded_focus,GetTickCount64()+500);
ok &= check(padded_capture.status=="ok" && joined(padded_capture).find("Ready")!=std::string::npos,
"malformed UTF-16 padding does not discard the valid MSAA label");
DestroyWindow(local_root);
CoUninitialize();
#endif
PostMessageW(window, WM_CLOSE, 0, 0);