// native_bridge/juce_fx/editor_selftest.cpp // M1 selftest (KHÔNG ship): verify editor host API trên instance DSP thật. // juce_fx_selftest.exe "" // Main thread = JUCE message thread (initialiseJuce_GUI). Plugin không có // editor (createEditorIfNeeded null) → [FAIL] editor open — thử plugin khác. #include "JuceFxEngine.h" #include #include #include #include static int failures = 0; static void check(bool ok, const char* what) { std::printf("%s %s\n", ok ? "[PASS]" : "[FAIL]", what); if (!ok) ++failures; } int main(int argc, char** argv) { if (argc < 2) { std::fprintf(stderr, "usage: juce_fx_selftest \n"); return 2; } // Escape backslash + quote cho JSON path. std::string path(argv[1]), jpath; jpath.reserve(path.size() + 8); for (char c : path) { if (c == '\\' || c == '"') jpath += '\\'; jpath += c; } juce::initialiseJuce_GUI(); // main thread = message thread int rc = 1; { JuceFxEngine engine; const std::string chain = "[{\"type\":\"vst3\",\"path\":\"" + jpath + "\",\"bypass\":false}]"; engine.setChain(chain); engine.prepare(48000, 256); // Negative: slot ngoài chain — pump xử lý nhưng không có editor nào. engine.requestEditor(9, JuceFxEngine::EditorAction::Open); check(!engine.pumpEditorQueue(), "negative: slot 9 ngoài chain -> pump false"); // Open editor 400x300. engine.requestEditor(0, JuceFxEngine::EditorAction::Open, 400, 300); bool pumped = engine.pumpEditorQueue(); // Pump message queue ngắn: editor constructor có thể tạo timer/callback. juce::MessageManager::getInstance()->runDispatchLoopUntil(50); check(pumped, "open: pumpEditorQueue true"); check(engine.isEditorOpen(0), "open: isEditorOpen(0) true"); // Capture state — phải có dữ liệu nếu plugin đã nạp preset mặc định. engine.requestEditor(0, JuceFxEngine::EditorAction::Capture); check(engine.pumpEditorQueue(), "capture: pumpEditorQueue true"); std::string cap = engine.takeCapturedState(0); check(!cap.empty(), "capture: takeCapturedState non-empty"); std::string cap2 = engine.takeCapturedState(0); check(cap2.empty(), "capture: lần 2 rỗng (đã xoá)"); // Close — editor đóng, processor + state giữ nguyên. engine.requestEditor(0, JuceFxEngine::EditorAction::Close); check(engine.pumpEditorQueue(), "close: pumpEditorQueue true"); check(!engine.isEditorOpen(0), "close: isEditorOpen(0) false"); } // ~engine -> shutdown() (đóng editor trước graph) — trước shutdownJuce_GUI juce::shutdownJuce_GUI(); rc = (failures == 0) ? 0 : 1; std::printf(failures == 0 ? "SELFTEST OK\n" : "SELFTEST FAILED\n"); return rc; }