// Standalone tests for reasampler::ui::window_origin — no REAPER, no Win32, no test framework. // Asserts the per-window code fold and the chain rule the plugin-editor hand-off proof rests on. #include "../src/core/ui/window_origin.h" #include #include #include using namespace reasampler::ui; static int g_fail = 0; #define CHECK(cond) do { if(!(cond)) { \ std::printf("FAIL line %d: %s\n", __LINE__, #cond); ++g_fail; } } while(0) static const std::string kWinDir = "C:\\Windows"; static WindowFacts inModule(const std::string& path, bool host = false) { WindowFacts f; f.procResolved = true; f.hostModule = host; f.modulePath = path; return f; } // --- classifyWindowCode -------------------------------------------------------- // REAPER's own chrome and containers: the class procedure lives in the executable. static void testHostExecutableIsHost() { CHECK(classifyWindowCode(inModule("C:\\Program Files\\REAPER (x64)\\reaper.exe", true), kWinDir) == WindowCode::Host); } // Standard controls and the dialog class are implemented by OS modules, wherever the OS keeps // them — System32, SysWOW64 for a 32-bit host, and the side-by-side store comctl32 v6 loads from. static void testOsModulesAreSystem() { CHECK(classifyWindowCode(inModule("C:\\Windows\\System32\\user32.dll"), kWinDir) == WindowCode::System); CHECK(classifyWindowCode(inModule("C:\\Windows\\SysWOW64\\user32.dll"), kWinDir) == WindowCode::System); CHECK(classifyWindowCode( inModule("C:\\Windows\\WinSxS\\amd64_microsoft.windows.common-controls_6595b64144ccf1df" "_6.0.26100.1_none_x\\comctl32.dll"), kWinDir) == WindowCode::System); } // The same directory spelled differently by two APIs still compares equal: case, separator // direction, a trailing separator on the root, and the long-path prefix. static void testSystemMatchIgnoresSpelling() { CHECK(classifyWindowCode(inModule("c:/WINDOWS/system32/USER32.DLL"), kWinDir) == WindowCode::System); CHECK(classifyWindowCode(inModule("C:\\Windows\\System32\\user32.dll"), "C:\\WINDOWS\\") == WindowCode::System); CHECK(classifyWindowCode(inModule("\\\\?\\C:\\Windows\\System32\\user32.dll"), kWinDir) == WindowCode::System); } // Containment, not string prefix: a sibling directory whose name merely starts with the OS // directory's is plugin territory, and so is the OS directory itself named as a file path. static void testSiblingDirectoryIsNotSystem() { CHECK(classifyWindowCode(inModule("C:\\WindowsApps\\thing.dll"), kWinDir) == WindowCode::Plugin); CHECK(classifyWindowCode(inModule("C:\\Windows2\\thing.dll"), kWinDir) == WindowCode::Plugin); CHECK(classifyWindowCode(inModule("C:\\Windows"), kWinDir) == WindowCode::Plugin); } // A plugin binary anywhere outside the OS directory — the VST3 bundle, a VST2 folder, a helper // DLL a plugin loads beside itself — is Plugin. static void testPluginBinariesArePlugin() { CHECK(classifyWindowCode( inModule("C:\\Program Files\\Common Files\\VST3\\Serum2.vst3\\Contents\\x86_64-win\\" "Serum2.vst3"), kWinDir) == WindowCode::Plugin); CHECK(classifyWindowCode(inModule("D:\\VstPlugins\\Qt5Widgets.dll"), kWinDir) == WindowCode::Plugin); } // Another process's window is plugin code by the process boundary alone, whatever its other facts // claim: a procedure address from another process resolved in ours is meaningless. static void testOtherProcessIsPluginRegardlessOfModule() { WindowFacts f = inModule("C:\\Program Files\\REAPER (x64)\\reaper.exe", true); f.otherProcess = true; CHECK(classifyWindowCode(f, kWinDir) == WindowCode::Plugin); WindowFacts g; g.otherProcess = true; // nothing resolved at all CHECK(classifyWindowCode(g, kWinDir) == WindowCode::Plugin); } // No module (a charset-mismatch handle, generated code) is no evidence — never Plugin. static void testUnresolvedProcIsUnknown() { WindowFacts f; f.modulePath = "C:\\VST\\x.dll"; // ignored without a resolved procedure CHECK(classifyWindowCode(f, kWinDir) == WindowCode::Unknown); } // Without the OS directory a standard control cannot be told from plugin code, so every non-host // module degrades to Unknown — the failure must not read REAPER's buttons as a plugin. static void testMissingSystemRootNeverYieldsPlugin() { CHECK(classifyWindowCode(inModule("C:\\Windows\\System32\\user32.dll"), "") == WindowCode::Unknown); CHECK(classifyWindowCode(inModule("C:\\VST\\x.dll"), "") == WindowCode::Unknown); CHECK(classifyWindowCode(inModule("C:\\VST\\x.dll"), "\\") == WindowCode::Unknown); CHECK(classifyWindowCode(inModule("C:\\REAPER\\reaper.exe", true), "") == WindowCode::Host); } // --- isPluginEditorChain ------------------------------------------------------- // Pointer on REAPER's FX-window chrome: a standard control or a REAPER container, under the // dialog-class root. No plugin code anywhere in the chain. static void testChromeChainIsNotPlugin() { CHECK(!isPluginEditorChain({WindowCode::System, WindowCode::Host, WindowCode::System})); CHECK(!isPluginEditorChain({WindowCode::Host, WindowCode::System})); CHECK(!isPluginEditorChain({WindowCode::Host})); } // Pointer on the plugin's editor window itself. static void testPluginWindowChainIsPlugin() { CHECK(isPluginEditorChain({WindowCode::Plugin, WindowCode::Host, WindowCode::System})); } // A standard control INSIDE the plugin's editor (a native text box) is System on its own; the // plugin's window above it is what makes the point the plugin's. static void testStandardControlInsidePluginIsPlugin() { CHECK(isPluginEditorChain( {WindowCode::System, WindowCode::Plugin, WindowCode::Host, WindowCode::System})); } // A bridged plugin's editor embedded across the process boundary: the hit window is Plugin by // process, REAPER's container and root above it are in-process. static void testBridgedEmbeddedEditorIsPlugin() { WindowFacts bridged; bridged.otherProcess = true; CHECK(isPluginEditorChain({classifyWindowCode(bridged, kWinDir), WindowCode::Host, WindowCode::System})); } // Unknown anywhere, and nothing else, is not proof; an empty chain (no window at all) is not. static void testUnknownAndEmptyChainsAreNotPlugin() { CHECK(!isPluginEditorChain({WindowCode::Unknown, WindowCode::Host, WindowCode::System})); CHECK(!isPluginEditorChain({WindowCode::Unknown})); CHECK(!isPluginEditorChain({})); } int main() { testHostExecutableIsHost(); testOsModulesAreSystem(); testSystemMatchIgnoresSpelling(); testSiblingDirectoryIsNotSystem(); testPluginBinariesArePlugin(); testOtherProcessIsPluginRegardlessOfModule(); testUnresolvedProcIsUnknown(); testMissingSystemRootNeverYieldsPlugin(); testChromeChainIsNotPlugin(); testPluginWindowChainIsPlugin(); testStandardControlInsidePluginIsPlugin(); testBridgedEmbeddedEditorIsPlugin(); testUnknownAndEmptyChainsAreNotPlugin(); if (g_fail == 0) std::printf("All tests passed.\n"); return g_fail ? 1 : 0; }