Step 342-343: PanelManager + Icons + KeybindingRegistry (24/24 tests)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
183
editor/tests/step342_test.cpp
Normal file
183
editor/tests/step342_test.cpp
Normal file
@@ -0,0 +1,183 @@
|
||||
// Step 342: DockingLayout + PanelManager Infrastructure (12 tests)
|
||||
// Tests panel registration, docking layout, visibility, focus, JSON persistence
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include "PanelManager.h"
|
||||
|
||||
int main() {
|
||||
int passed = 0;
|
||||
|
||||
// Test 1: Register 8 default panels
|
||||
{
|
||||
PanelManager pm;
|
||||
pm.registerDefaults();
|
||||
assert(pm.panelCount() == 8);
|
||||
std::cout << "Test 1 PASSED: Register 8 default panels\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// Test 2: All default panels visible by default
|
||||
{
|
||||
PanelManager pm;
|
||||
pm.registerDefaults();
|
||||
auto visible = pm.getVisiblePanels();
|
||||
assert(visible.size() == 8);
|
||||
std::cout << "Test 2 PASSED: All default panels visible\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// Test 3: Panels in correct dock positions
|
||||
{
|
||||
PanelManager pm;
|
||||
pm.registerDefaults();
|
||||
auto left = pm.getPanelsByDock(DockPosition::Left);
|
||||
auto right = pm.getPanelsByDock(DockPosition::Right);
|
||||
auto bottom = pm.getPanelsByDock(DockPosition::Bottom);
|
||||
auto center = pm.getPanelsByDock(DockPosition::CenterTop);
|
||||
assert(left.size() == 1); // file-tree
|
||||
assert(right.size() == 3); // ast-view, annotations, properties
|
||||
assert(bottom.size() == 3); // diagnostics, output, workflow
|
||||
assert(center.size() == 1); // code-editor
|
||||
assert(left[0].id == "file-tree");
|
||||
assert(center[0].id == "code-editor");
|
||||
std::cout << "Test 3 PASSED: Panels in correct dock positions\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// Test 4: Toggle panel visibility
|
||||
{
|
||||
PanelManager pm;
|
||||
pm.registerDefaults();
|
||||
assert(pm.isVisible("ast-view"));
|
||||
pm.togglePanel("ast-view");
|
||||
assert(!pm.isVisible("ast-view"));
|
||||
pm.togglePanel("ast-view");
|
||||
assert(pm.isVisible("ast-view"));
|
||||
std::cout << "Test 4 PASSED: Toggle panel visibility\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// Test 5: Hidden panel not in visible list
|
||||
{
|
||||
PanelManager pm;
|
||||
pm.registerDefaults();
|
||||
pm.setVisible("properties", false);
|
||||
auto visible = pm.getVisiblePanels();
|
||||
assert(visible.size() == 7);
|
||||
bool found = false;
|
||||
for (const auto& p : visible) {
|
||||
if (p.id == "properties") found = true;
|
||||
}
|
||||
assert(!found);
|
||||
std::cout << "Test 5 PASSED: Hidden panel excluded from visible list\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// Test 6: Focus panel
|
||||
{
|
||||
PanelManager pm;
|
||||
pm.registerDefaults();
|
||||
pm.focusPanel("diagnostics");
|
||||
assert(pm.getFocusedPanel() == "diagnostics");
|
||||
pm.focusPanel("ast-view");
|
||||
assert(pm.getFocusedPanel() == "ast-view");
|
||||
std::cout << "Test 6 PASSED: Focus panel tracking\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// Test 7: Move panel to different dock
|
||||
{
|
||||
PanelManager pm;
|
||||
pm.registerDefaults();
|
||||
pm.movePanelToDock("diagnostics", DockPosition::Right);
|
||||
auto right = pm.getPanelsByDock(DockPosition::Right);
|
||||
bool found = false;
|
||||
for (const auto& p : right) {
|
||||
if (p.id == "diagnostics") found = true;
|
||||
}
|
||||
assert(found);
|
||||
auto bottom = pm.getPanelsByDock(DockPosition::Bottom);
|
||||
bool stillInBottom = false;
|
||||
for (const auto& p : bottom) {
|
||||
if (p.id == "diagnostics") stillInBottom = true;
|
||||
}
|
||||
assert(!stillInBottom);
|
||||
std::cout << "Test 7 PASSED: Move panel to different dock\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// Test 8: DockingLayout default proportions
|
||||
{
|
||||
PanelManager pm;
|
||||
pm.registerDefaults();
|
||||
assert(pm.layout().leftWidth == 20.0f);
|
||||
assert(pm.layout().rightWidth == 20.0f);
|
||||
assert(pm.layout().bottomHeight == 25.0f);
|
||||
std::cout << "Test 8 PASSED: Default layout proportions\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// Test 9: Panel ordering preserved
|
||||
{
|
||||
PanelManager pm;
|
||||
pm.registerDefaults();
|
||||
auto all = pm.getPanelList();
|
||||
assert(all[0].id == "file-tree");
|
||||
assert(all[1].id == "code-editor");
|
||||
// Higher order panels come later
|
||||
assert(all.back().id == "workflow");
|
||||
std::cout << "Test 9 PASSED: Panel ordering preserved\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// Test 10: JSON roundtrip — panels + layout
|
||||
{
|
||||
PanelManager pm;
|
||||
pm.registerDefaults();
|
||||
pm.setVisible("workflow", false);
|
||||
pm.focusPanel("code-editor");
|
||||
pm.layout().leftWidth = 25.0f;
|
||||
|
||||
nlohmann::json j = pm.toJson();
|
||||
PanelManager restored = PanelManager::fromJson(j);
|
||||
|
||||
assert(restored.panelCount() == 8);
|
||||
assert(!restored.isVisible("workflow"));
|
||||
assert(restored.getFocusedPanel() == "code-editor");
|
||||
assert(restored.layout().leftWidth == 25.0f);
|
||||
std::cout << "Test 10 PASSED: JSON roundtrip (panels + layout)\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// Test 11: Panel info fields correct
|
||||
{
|
||||
PanelManager pm;
|
||||
pm.registerDefaults();
|
||||
auto info = pm.getPanel("file-tree");
|
||||
assert(info.id == "file-tree");
|
||||
assert(info.title == "File Tree");
|
||||
assert(info.defaultDock == DockPosition::Left);
|
||||
assert(info.category == "navigation");
|
||||
assert(!info.icon.empty());
|
||||
std::cout << "Test 11 PASSED: Panel info fields correct\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// Test 12: DockPosition string roundtrip
|
||||
{
|
||||
assert(dockPositionToString(DockPosition::Left) == "left");
|
||||
assert(dockPositionToString(DockPosition::CenterTop) == "center-top");
|
||||
assert(dockPositionToString(DockPosition::Bottom) == "bottom");
|
||||
assert(dockPositionFromString("left") == DockPosition::Left);
|
||||
assert(dockPositionFromString("right") == DockPosition::Right);
|
||||
assert(dockPositionFromString("center-top") == DockPosition::CenterTop);
|
||||
std::cout << "Test 12 PASSED: DockPosition string roundtrip\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
std::cout << "\nResults: " << passed << "/12\n";
|
||||
assert(passed == 12);
|
||||
return 0;
|
||||
}
|
||||
188
editor/tests/step343_test.cpp
Normal file
188
editor/tests/step343_test.cpp
Normal file
@@ -0,0 +1,188 @@
|
||||
// Step 343: Panel Registration + Icons + Keybinding Foundation (12 tests)
|
||||
// Tests PanelManager registration, Icons system, and KeybindingRegistry basics
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include "PanelManager.h"
|
||||
#include "Icons.h"
|
||||
#include "KeybindingRegistry.h"
|
||||
|
||||
int main() {
|
||||
int passed = 0;
|
||||
|
||||
// Test 1: Panel categories correct
|
||||
{
|
||||
PanelManager pm;
|
||||
pm.registerDefaults();
|
||||
auto all = pm.getPanelList();
|
||||
int nav = 0, editor = 0, analysis = 0, output = 0;
|
||||
for (const auto& p : all) {
|
||||
if (p.category == "navigation") nav++;
|
||||
if (p.category == "editor") editor++;
|
||||
if (p.category == "analysis") analysis++;
|
||||
if (p.category == "output") output++;
|
||||
}
|
||||
assert(nav == 1); // file-tree
|
||||
assert(editor == 1); // code-editor
|
||||
assert(analysis == 3); // ast-view, annotations, properties
|
||||
assert(output == 3); // diagnostics, output, workflow
|
||||
std::cout << "Test 1 PASSED: Panel categories correct\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// Test 2: Panel JSON roundtrip preserves all fields
|
||||
{
|
||||
PanelManager pm;
|
||||
pm.registerPanel("test-panel", "Test Panel", DockPosition::Right,
|
||||
WhetstoneIcons::NodeFunction, "analysis", 10);
|
||||
pm.setVisible("test-panel", false);
|
||||
pm.movePanelToDock("test-panel", DockPosition::Bottom);
|
||||
|
||||
auto j = pm.toJson();
|
||||
auto restored = PanelManager::fromJson(j);
|
||||
auto info = restored.getPanel("test-panel");
|
||||
assert(info.title == "Test Panel");
|
||||
assert(!info.isVisible);
|
||||
assert(info.currentDock == DockPosition::Bottom);
|
||||
assert(info.defaultDock == DockPosition::Right);
|
||||
assert(info.order == 10);
|
||||
std::cout << "Test 2 PASSED: Panel JSON roundtrip preserves all fields\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// Test 3: Icon constants defined and non-empty
|
||||
{
|
||||
assert(std::string(WhetstoneIcons::DiagError).size() > 0);
|
||||
assert(std::string(WhetstoneIcons::DiagWarning).size() > 0);
|
||||
assert(std::string(WhetstoneIcons::DiagInfo).size() > 0);
|
||||
assert(std::string(WhetstoneIcons::Pending).size() > 0);
|
||||
assert(std::string(WhetstoneIcons::Complete).size() > 0);
|
||||
assert(std::string(WhetstoneIcons::NodeFunction).size() > 0);
|
||||
assert(std::string(WhetstoneIcons::NodeClass).size() > 0);
|
||||
assert(std::string(WhetstoneIcons::Folder).size() > 0);
|
||||
std::cout << "Test 3 PASSED: Icon constants defined and non-empty\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// Test 4: Icon for node type
|
||||
{
|
||||
assert(WhetstoneIcons::iconForNodeType("Function") == WhetstoneIcons::NodeFunction);
|
||||
assert(WhetstoneIcons::iconForNodeType("ClassDeclaration") == WhetstoneIcons::NodeClass);
|
||||
assert(WhetstoneIcons::iconForNodeType("Variable") == WhetstoneIcons::NodeVariable);
|
||||
assert(WhetstoneIcons::iconForNodeType("Module") == WhetstoneIcons::NodeModule);
|
||||
assert(WhetstoneIcons::iconForNodeType("IntentAnnotation") == WhetstoneIcons::NodeAnnotation);
|
||||
std::cout << "Test 4 PASSED: Icon for node type\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// Test 5: Icon for severity
|
||||
{
|
||||
assert(WhetstoneIcons::iconForSeverity(1) == WhetstoneIcons::DiagError);
|
||||
assert(WhetstoneIcons::iconForSeverity(2) == WhetstoneIcons::DiagWarning);
|
||||
assert(WhetstoneIcons::iconForSeverity(3) == WhetstoneIcons::DiagInfo);
|
||||
assert(WhetstoneIcons::iconForSeverity(4) == WhetstoneIcons::DiagHint);
|
||||
std::cout << "Test 5 PASSED: Icon for severity\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// Test 6: Icon fallback text
|
||||
{
|
||||
assert(WhetstoneIcons::fallback(WhetstoneIcons::DiagError) == "[ERR]");
|
||||
assert(WhetstoneIcons::fallback(WhetstoneIcons::DiagWarning) == "[WARN]");
|
||||
assert(WhetstoneIcons::fallback(WhetstoneIcons::Complete) == "[OK]");
|
||||
assert(WhetstoneIcons::fallback(WhetstoneIcons::NodeFunction) == "fn");
|
||||
std::cout << "Test 6 PASSED: Icon fallback text\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// Test 7: KeybindingRegistry default bindings loaded
|
||||
{
|
||||
KeybindingRegistry reg;
|
||||
reg.loadDefaults();
|
||||
assert(reg.actionCount() >= 20);
|
||||
assert(reg.bindingCount() >= 14);
|
||||
std::cout << "Test 7 PASSED: Default bindings loaded (" << reg.actionCount()
|
||||
<< " actions, " << reg.bindingCount() << " bindings)\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// Test 8: KeyCombo toString
|
||||
{
|
||||
auto combo = KeyCombo::ctrl("S");
|
||||
assert(combo.toString() == "Ctrl+S");
|
||||
auto combo2 = KeyCombo::ctrlShift("Z");
|
||||
assert(combo2.toString() == "Ctrl+Shift+Z");
|
||||
auto combo3 = KeyCombo::fkey("F5");
|
||||
assert(combo3.toString() == "F5");
|
||||
std::cout << "Test 8 PASSED: KeyCombo toString\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// Test 9: Key symbols for save action
|
||||
{
|
||||
KeybindingRegistry reg;
|
||||
reg.loadDefaults();
|
||||
std::string sym = reg.getSymbols("save-buffer");
|
||||
assert(sym == "Ctrl+S");
|
||||
std::string undo = reg.getSymbols("undo");
|
||||
assert(undo == "Ctrl+Z");
|
||||
std::string pipeline = reg.getSymbols("run-pipeline");
|
||||
assert(pipeline == "F5");
|
||||
std::cout << "Test 9 PASSED: Key symbols for actions\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// Test 10: Conflict detection
|
||||
{
|
||||
KeybindingRegistry reg;
|
||||
reg.loadDefaults();
|
||||
// Ctrl+S is already bound to save-buffer
|
||||
auto conflict = reg.findConflict("close-buffer", KeyCombo::ctrl("S"));
|
||||
assert(conflict.has_value());
|
||||
assert(conflict.value() == "save-buffer");
|
||||
// Ctrl+Q is not bound
|
||||
auto noConflict = reg.findConflict("close-buffer", KeyCombo::ctrl("Q"));
|
||||
assert(!noConflict.has_value());
|
||||
std::cout << "Test 10 PASSED: Conflict detection\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// Test 11: Actions by category
|
||||
{
|
||||
KeybindingRegistry reg;
|
||||
reg.loadDefaults();
|
||||
auto fileActions = reg.getActionsByCategory("File");
|
||||
assert(fileActions.size() >= 3);
|
||||
auto editActions = reg.getActionsByCategory("Edit");
|
||||
assert(editActions.size() >= 4);
|
||||
auto viewActions = reg.getActionsByCategory("View");
|
||||
assert(viewActions.size() >= 4);
|
||||
std::cout << "Test 11 PASSED: Actions by category\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
// Test 12: Keybinding JSON persistence roundtrip
|
||||
{
|
||||
KeybindingRegistry reg;
|
||||
reg.loadDefaults();
|
||||
// Rebind save
|
||||
reg.bind("save-buffer", KeyCombo::ctrl("W"));
|
||||
|
||||
auto j = reg.toJson();
|
||||
KeybindingRegistry restored;
|
||||
restored.loadDefaults();
|
||||
restored.loadFromJson(j);
|
||||
|
||||
auto combo = restored.getBinding("save-buffer");
|
||||
assert(combo.toString() == "Ctrl+W");
|
||||
// Other bindings still intact
|
||||
assert(restored.getBinding("undo").toString() == "Ctrl+Z");
|
||||
std::cout << "Test 12 PASSED: Keybinding JSON persistence roundtrip\n";
|
||||
passed++;
|
||||
}
|
||||
|
||||
std::cout << "\nResults: " << passed << "/12\n";
|
||||
assert(passed == 12);
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user