Release v0.6.39: isolate history UI and image clipboard memory
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
// Run with the resident stopped. The suite restores the original clipboard.
|
||||
#include "storage.h"
|
||||
#include "ocr.h"
|
||||
#include <psapi.h>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
static void require(bool ok, const char *name) {
|
||||
if (!ok) throw std::runtime_error(name);
|
||||
std::cout << "PASS " << name << '\n';
|
||||
}
|
||||
static HWND owner() {
|
||||
return CreateWindowExW(0,L"STATIC",L"Snapshot test",0,0,0,0,0,HWND_MESSAGE,nullptr,nullptr,nullptr);
|
||||
}
|
||||
static void child(const std::wstring &argument) {
|
||||
auto exe=ks::executable(), command=L"\""+exe+L"\" "+argument;
|
||||
STARTUPINFOW startup{sizeof(startup)}; startup.dwFlags=STARTF_USESHOWWINDOW; startup.wShowWindow=SW_HIDE;
|
||||
PROCESS_INFORMATION p{};
|
||||
if(!CreateProcessW(exe.c_str(),command.data(),nullptr,nullptr,FALSE,CREATE_NO_WINDOW,nullptr,nullptr,&startup,&p))
|
||||
throw std::runtime_error("start fixture process");
|
||||
CloseHandle(p.hThread);
|
||||
auto wait=WaitForSingleObject(p.hProcess,30000); DWORD code=1;
|
||||
if(wait!=WAIT_OBJECT_0) {TerminateProcess(p.hProcess,1);WaitForSingleObject(p.hProcess,INFINITE);}
|
||||
GetExitCodeProcess(p.hProcess,&code); CloseHandle(p.hProcess);
|
||||
if(code) throw std::runtime_error("fixture process failed");
|
||||
}
|
||||
static size_t resident() {
|
||||
ks::Bytes b(1024*1024); auto ws=reinterpret_cast<PSAPI_WORKING_SET_INFORMATION*>(b.data());
|
||||
if(!QueryWorkingSet(GetCurrentProcess(),ws,DWORD(b.size()))) throw std::runtime_error("working set query");
|
||||
size_t pages=0; for(size_t i=0;i<ws->NumberOfEntries;++i) if(!ws->WorkingSetInfo[i].Shared) ++pages;
|
||||
return pages*4096;
|
||||
}
|
||||
static void verifyImage(HWND w) {
|
||||
auto c=ks::readClipboard(w,64*1024*1024);
|
||||
for(auto id:{CF_DIB,CF_DIBV5}) {
|
||||
auto it=std::find_if(c.formats.begin(),c.formats.end(),[&](const auto &f){return f.id==UINT(id);});
|
||||
require(it!=c.formats.end(),"restores image representation");
|
||||
auto pixels=ks::decodeImage(ks::Clip{{*it}});
|
||||
require(pixels.width==1566 && pixels.height==1068 && pixels.bgra.front()==77,"preserves image pixels");
|
||||
}
|
||||
require(c.text()==L"Snapshot mixed text","preserves accompanying text");
|
||||
}
|
||||
int main(int argc,char**argv) {
|
||||
CoInitializeEx(nullptr,COINIT_MULTITHREADED);
|
||||
HWND w=owner(); int result=0; ks::Clip original; bool saved=false;
|
||||
try {
|
||||
std::string mode=argc>1?argv[1]:"suite";
|
||||
if(mode=="publish") {
|
||||
ks::Pixels p{1566,1068,ks::Bytes(1566*1068*4,255)}; p.bgra[0]=77;
|
||||
auto dib=ks::imageDib(p); auto v5=dib;
|
||||
BITMAPV5HEADER h{}; h.bV5Size=sizeof(h); h.bV5Width=p.width; h.bV5Height=-p.height;
|
||||
h.bV5Planes=1; h.bV5BitCount=32; h.bV5Compression=BI_BITFIELDS;
|
||||
h.bV5RedMask=0xff0000; h.bV5GreenMask=0xff00; h.bV5BlueMask=0xff; h.bV5AlphaMask=0xff000000;
|
||||
v5.id=CF_DIBV5; v5.data.resize(sizeof(h)+p.bgra.size());
|
||||
memcpy(v5.data.data(),&h,sizeof(h)); memcpy(v5.data.data()+sizeof(h),p.bgra.data(),p.bgra.size());
|
||||
auto clip=ks::textClip(L"Snapshot mixed text"); clip.formats.push_back(dib); clip.formats.push_back(v5);
|
||||
ks::writeClipboard(w,clip);
|
||||
} else if(mode=="old" || mode=="new") {
|
||||
child(L"publish"); auto baseline=resident();
|
||||
if(mode=="old") {
|
||||
auto clip=ks::readClipboard(w,64*1024*1024);
|
||||
ks::writeClipboard(w,ks::textClip(L"temporary")); ks::writeClipboard(w,clip);
|
||||
} else {
|
||||
ks::ClipboardSnapshot snapshot; snapshot.capture(w,GetClipboardSequenceNumber());
|
||||
auto seq=ks::writeClipboard(w,ks::textClip(L"temporary"));
|
||||
require(snapshot.restore(w,seq)==GetClipboardSequenceNumber(),"helper returns current sequence");
|
||||
}
|
||||
auto after=resident();
|
||||
auto report="baseline="+std::to_string(baseline)+" after="+std::to_string(after)+" delta="+std::to_string(int64_t(after)-int64_t(baseline))+"\n";
|
||||
auto path=std::filesystem::path(ks::executable()).parent_path()/(L"snapshot-memory-"+ks::wide(mode)+L".txt");
|
||||
ks::atomicWrite(path,ks::Bytes(report.begin(),report.end()));
|
||||
verifyImage(w); // Only after measuring: verification intentionally reads images.
|
||||
} else {
|
||||
original=ks::readClipboard(w,128*1024*1024); saved=true;
|
||||
child(L"old"); child(L"new"); child(L"publish");
|
||||
auto seq=GetClipboardSequenceNumber();
|
||||
auto selected=ks::readClipboard(w,32*1024*1024,ks::ClipboardRead::Selection);
|
||||
require(selected.formats.size()==1 && selected.text()==L"Snapshot mixed text","selection read excludes image data");
|
||||
bool rejected=false;
|
||||
try {ks::readClipboard(w,32*1024*1024,ks::ClipboardRead::WithoutImages,seq);} catch(...) {rejected=true;}
|
||||
require(rejected,"resident rejects images before reading their data");
|
||||
{
|
||||
ks::ClipboardSnapshot snapshot; snapshot.capture(w,seq);
|
||||
auto stale=ks::writeClipboard(w,ks::textClip(L"temporary"));
|
||||
ks::writeClipboard(w,ks::textClip(L"external copy")); rejected=false;
|
||||
try {snapshot.restore(w,stale);} catch(...) {rejected=true;}
|
||||
require(rejected && ks::readClipboard(w).text()==L"external copy","stale image restore preserves external copy");
|
||||
}
|
||||
{
|
||||
ks::ClipboardSnapshot snapshot; snapshot.capture(w,GetClipboardSequenceNumber());
|
||||
auto temporary=ks::writeClipboard(w,ks::textClip(L"temporary"));
|
||||
snapshot.restore(w,temporary);
|
||||
require(ks::readClipboard(w).text()==L"external copy","text snapshot fast path restores clipboard");
|
||||
}
|
||||
{
|
||||
ks::Clip empty; auto seqEmpty=ks::writeClipboard(w,empty);
|
||||
ks::ClipboardSnapshot snapshot; snapshot.capture(w,seqEmpty);
|
||||
snapshot.restore(w,ks::writeClipboard(w,ks::textClip(L"temporary")));
|
||||
require(ks::readClipboard(w).formats.empty(),"empty clipboard restored");
|
||||
}
|
||||
auto marked=ks::textClip(L"line"); marked.formats.push_back({0,L"MSDEVLineSelect",ks::Bytes{1}});
|
||||
ks::writeClipboard(w,marked);
|
||||
require(ks::readClipboard(w,1024,ks::ClipboardRead::Selection).formats.size()==2,"selection reader preserves editor guard metadata");
|
||||
std::cout<<"PASS clipboard snapshot suite\n";
|
||||
}
|
||||
} catch(const std::exception &e) {std::cerr<<"FAIL "<<e.what()<<'\n';result=1;}
|
||||
if(saved) try {ks::writeClipboard(w,original);} catch(...) {result=1;}
|
||||
DestroyWindow(w); CoUninitialize(); return result;
|
||||
}
|
||||
Reference in New Issue
Block a user