// Run with the resident stopped. The suite restores the original clipboard. #include "storage.h" #include "ocr.h" #include #include #include 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(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;iNumberOfEntries;++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 "<