mirror of
https://github.com/NohamR/Reclass.git
synced 2026-05-10 19:59:21 +00:00
Dim command row address, fix source picker zoom/styling, lowercase menu items, margin spacing
- Apply IND_HEX_DIM to base address on command row so it matches source/struct grey - Source picker QMenu respects Scintilla zoom level for font size - Style source picker with dark theme selection color instead of system blue - Disable blue selection background for picker-based edit targets (Source, Type, etc.) - Rename menu items File/Process to file/process - Add trailing space to margin offset text for breathing room
This commit is contained in:
@@ -21,7 +21,7 @@ static QString buildCommandRow(const Provider& prov, uint64_t baseAddress) {
|
||||
QString src = buildSourceLabel(prov);
|
||||
QString addr = QStringLiteral("0x") +
|
||||
QString::number(baseAddress, 16).toUpper();
|
||||
return QStringLiteral(" %1 \u203A %2").arg(src, addr);
|
||||
return QStringLiteral(" %1 \u00B7 %2").arg(src, addr);
|
||||
}
|
||||
|
||||
// -- Replicate commandRowSrcSpan for testing
|
||||
@@ -32,7 +32,7 @@ struct TestColumnSpan {
|
||||
};
|
||||
|
||||
static TestColumnSpan commandRowSrcSpan(const QString& lineText) {
|
||||
int idx = lineText.indexOf(QStringLiteral(" \u203A"));
|
||||
int idx = lineText.indexOf(QStringLiteral(" \u00B7"));
|
||||
if (idx < 0) return {};
|
||||
int start = 0;
|
||||
while (start < idx && !lineText[start].isLetterOrNumber()
|
||||
@@ -77,13 +77,13 @@ private slots:
|
||||
void row_nullProvider() {
|
||||
NullProvider p;
|
||||
QString row = buildCommandRow(p, 0);
|
||||
QCOMPARE(row, QStringLiteral(" source\u25BE \u203A 0x0"));
|
||||
QCOMPARE(row, QStringLiteral(" source\u25BE \u00B7 0x0"));
|
||||
}
|
||||
|
||||
void row_fileProvider() {
|
||||
BufferProvider p(QByteArray(4, '\0'), "test.bin");
|
||||
QString row = buildCommandRow(p, 0x140000000ULL);
|
||||
QCOMPARE(row, QStringLiteral(" 'test.bin'\u25BE \u203A 0x140000000"));
|
||||
QCOMPARE(row, QStringLiteral(" 'test.bin'\u25BE \u00B7 0x140000000"));
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
@@ -110,7 +110,7 @@ private slots:
|
||||
void span_processProvider_simulated() {
|
||||
// Simulate a process provider without needing Windows APIs
|
||||
// by building the string directly
|
||||
QString row = QStringLiteral(" 'notepad.exe'\u25BE \u203A 0x7FF600000000");
|
||||
QString row = QStringLiteral(" 'notepad.exe'\u25BE \u00B7 0x7FF600000000");
|
||||
auto span = commandRowSrcSpan(row);
|
||||
QVERIFY(span.valid);
|
||||
QString extracted = row.mid(span.start, span.end - span.start);
|
||||
|
||||
@@ -35,30 +35,24 @@ private slots:
|
||||
NullProvider prov;
|
||||
ComposeResult result = compose(tree, prov);
|
||||
|
||||
// CommandRow + Blank + CommandRow2 + 2 fields + root footer = 6
|
||||
QCOMPARE(result.meta.size(), 6);
|
||||
// CommandRow + 2 fields + root footer = 4
|
||||
QCOMPARE(result.meta.size(), 4);
|
||||
|
||||
// Line 0 is CommandRow
|
||||
QCOMPARE(result.meta[0].lineKind, LineKind::CommandRow);
|
||||
|
||||
// Line 1 is Blank separator
|
||||
QCOMPARE(result.meta[1].lineKind, LineKind::Blank);
|
||||
|
||||
// Line 2 is CommandRow2
|
||||
QCOMPARE(result.meta[2].lineKind, LineKind::CommandRow2);
|
||||
|
||||
// Fields at depth 1
|
||||
QVERIFY(!result.meta[3].foldHead);
|
||||
QCOMPARE(result.meta[3].depth, 1);
|
||||
QVERIFY(!result.meta[4].foldHead);
|
||||
QCOMPARE(result.meta[4].depth, 1);
|
||||
QVERIFY(!result.meta[1].foldHead);
|
||||
QCOMPARE(result.meta[1].depth, 1);
|
||||
QVERIFY(!result.meta[2].foldHead);
|
||||
QCOMPARE(result.meta[2].depth, 1);
|
||||
|
||||
// Offset text
|
||||
QCOMPARE(result.meta[3].offsetText, QString("0"));
|
||||
QCOMPARE(result.meta[4].offsetText, QString("4"));
|
||||
QCOMPARE(result.meta[1].offsetText, QString("0"));
|
||||
QCOMPARE(result.meta[2].offsetText, QString("4"));
|
||||
|
||||
// Line 5 is root footer
|
||||
QCOMPARE(result.meta[5].lineKind, LineKind::Footer);
|
||||
// Line 3 is root footer
|
||||
QCOMPARE(result.meta[3].lineKind, LineKind::Footer);
|
||||
}
|
||||
|
||||
void testVec3SingleLine() {
|
||||
@@ -82,17 +76,17 @@ private slots:
|
||||
NullProvider prov;
|
||||
ComposeResult result = compose(tree, prov);
|
||||
|
||||
// CommandRow + Blank + CommandRow2 + 1 Vec3 line + root footer = 5
|
||||
QCOMPARE(result.meta.size(), 5);
|
||||
// CommandRow + 1 Vec3 line + root footer = 3
|
||||
QCOMPARE(result.meta.size(), 3);
|
||||
|
||||
// Line 3: single Vec3 line, not continuation, depth 1
|
||||
QVERIFY(!result.meta[3].isContinuation);
|
||||
QCOMPARE(result.meta[3].offsetText, QString("0"));
|
||||
QCOMPARE(result.meta[3].depth, 1);
|
||||
QCOMPARE(result.meta[3].nodeKind, NodeKind::Vec3);
|
||||
// Line 1: single Vec3 line, not continuation, depth 1
|
||||
QVERIFY(!result.meta[1].isContinuation);
|
||||
QCOMPARE(result.meta[1].offsetText, QString("0"));
|
||||
QCOMPARE(result.meta[1].depth, 1);
|
||||
QCOMPARE(result.meta[1].nodeKind, NodeKind::Vec3);
|
||||
|
||||
// Line 4 is root footer
|
||||
QCOMPARE(result.meta[4].lineKind, LineKind::Footer);
|
||||
// Line 2 is root footer
|
||||
QCOMPARE(result.meta[2].lineKind, LineKind::Footer);
|
||||
}
|
||||
|
||||
void testPaddingMarker() {
|
||||
@@ -116,13 +110,13 @@ private slots:
|
||||
NullProvider prov;
|
||||
ComposeResult result = compose(tree, prov);
|
||||
|
||||
// CommandRow + Blank + CommandRow2 + padding + root footer = 5
|
||||
QCOMPARE(result.meta.size(), 5);
|
||||
QVERIFY(result.meta[3].markerMask & (1u << M_PAD));
|
||||
QCOMPARE(result.meta[3].depth, 1);
|
||||
// CommandRow + padding + root footer = 3
|
||||
QCOMPARE(result.meta.size(), 3);
|
||||
QVERIFY(result.meta[1].markerMask & (1u << M_PAD));
|
||||
QCOMPARE(result.meta[1].depth, 1);
|
||||
|
||||
// Line 4 is root footer
|
||||
QCOMPARE(result.meta[4].lineKind, LineKind::Footer);
|
||||
// Line 2 is root footer
|
||||
QCOMPARE(result.meta[2].lineKind, LineKind::Footer);
|
||||
}
|
||||
|
||||
void testNullPointerMarker() {
|
||||
@@ -148,14 +142,14 @@ private slots:
|
||||
BufferProvider prov(data);
|
||||
ComposeResult result = compose(tree, prov);
|
||||
|
||||
// CommandRow + Blank + CommandRow2 + ptr + root footer = 5
|
||||
QCOMPARE(result.meta.size(), 5);
|
||||
// CommandRow + ptr + root footer = 3
|
||||
QCOMPARE(result.meta.size(), 3);
|
||||
// No ambient validation markers — M_PTR0 is no longer set
|
||||
QVERIFY(!(result.meta[3].markerMask & (1u << M_PTR0)));
|
||||
QCOMPARE(result.meta[3].depth, 1);
|
||||
QVERIFY(!(result.meta[1].markerMask & (1u << M_PTR0)));
|
||||
QCOMPARE(result.meta[1].depth, 1);
|
||||
|
||||
// Line 4 is root footer
|
||||
QCOMPARE(result.meta[4].lineKind, LineKind::Footer);
|
||||
// Line 2 is root footer
|
||||
QCOMPARE(result.meta[2].lineKind, LineKind::Footer);
|
||||
}
|
||||
|
||||
void testCollapsedStruct() {
|
||||
@@ -181,11 +175,11 @@ private slots:
|
||||
ComposeResult result = compose(tree, prov);
|
||||
|
||||
// Collapsed root: isRootHeader overrides collapse, so children + footer still render
|
||||
// CommandRow + Blank + CommandRow2 + field + root footer = 5
|
||||
QCOMPARE(result.meta.size(), 5);
|
||||
QCOMPARE(result.meta[3].lineKind, LineKind::Field);
|
||||
QCOMPARE(result.meta[3].depth, 1);
|
||||
QCOMPARE(result.meta[4].lineKind, LineKind::Footer);
|
||||
// CommandRow + field + root footer = 3
|
||||
QCOMPARE(result.meta.size(), 3);
|
||||
QCOMPARE(result.meta[1].lineKind, LineKind::Field);
|
||||
QCOMPARE(result.meta[1].depth, 1);
|
||||
QCOMPARE(result.meta[2].lineKind, LineKind::Footer);
|
||||
}
|
||||
|
||||
void testUnreadablePointerNoRead() {
|
||||
@@ -212,15 +206,15 @@ private slots:
|
||||
BufferProvider prov(data);
|
||||
ComposeResult result = compose(tree, prov);
|
||||
|
||||
// CommandRow + Blank + CommandRow2 + ptr + root footer = 5
|
||||
QCOMPARE(result.meta.size(), 5);
|
||||
// CommandRow + ptr + root footer = 3
|
||||
QCOMPARE(result.meta.size(), 3);
|
||||
// No ambient validation markers
|
||||
QVERIFY(!(result.meta[3].markerMask & (1u << M_ERR)));
|
||||
QVERIFY(!(result.meta[3].markerMask & (1u << M_PTR0)));
|
||||
QCOMPARE(result.meta[3].depth, 1);
|
||||
QVERIFY(!(result.meta[1].markerMask & (1u << M_ERR)));
|
||||
QVERIFY(!(result.meta[1].markerMask & (1u << M_PTR0)));
|
||||
QCOMPARE(result.meta[1].depth, 1);
|
||||
|
||||
// Line 4 is root footer
|
||||
QCOMPARE(result.meta[4].lineKind, LineKind::Footer);
|
||||
// Line 2 is root footer
|
||||
QCOMPARE(result.meta[2].lineKind, LineKind::Footer);
|
||||
}
|
||||
|
||||
void testFoldLevels() {
|
||||
@@ -253,13 +247,13 @@ private slots:
|
||||
ComposeResult result = compose(tree, prov);
|
||||
|
||||
// Child header (depth 1, fold head) — root header no longer emitted
|
||||
QCOMPARE(result.meta[3].foldLevel, 0x401 | 0x2000);
|
||||
QCOMPARE(result.meta[3].depth, 1);
|
||||
QVERIFY(result.meta[3].foldHead);
|
||||
QCOMPARE(result.meta[1].foldLevel, 0x401 | 0x2000);
|
||||
QCOMPARE(result.meta[1].depth, 1);
|
||||
QVERIFY(result.meta[1].foldHead);
|
||||
|
||||
// Leaf (depth 2, not head)
|
||||
QCOMPARE(result.meta[4].foldLevel, 0x402);
|
||||
QCOMPARE(result.meta[4].depth, 2);
|
||||
QCOMPARE(result.meta[2].foldLevel, 0x402);
|
||||
QCOMPARE(result.meta[2].depth, 2);
|
||||
}
|
||||
|
||||
void testNestedStruct() {
|
||||
@@ -306,31 +300,31 @@ private slots:
|
||||
NullProvider prov;
|
||||
ComposeResult result = compose(tree, prov);
|
||||
|
||||
// CommandRow + Blank + CommandRow2 + flags + Inner header + x + y + Inner footer + root footer = 9
|
||||
QCOMPARE(result.meta.size(), 9);
|
||||
// CommandRow + flags + Inner header + x + y + Inner footer + root footer = 7
|
||||
QCOMPARE(result.meta.size(), 7);
|
||||
|
||||
// flags field (depth 1)
|
||||
QCOMPARE(result.meta[3].lineKind, LineKind::Field);
|
||||
QCOMPARE(result.meta[3].depth, 1);
|
||||
QCOMPARE(result.meta[1].lineKind, LineKind::Field);
|
||||
QCOMPARE(result.meta[1].depth, 1);
|
||||
|
||||
// Inner header (depth 1, fold head)
|
||||
QCOMPARE(result.meta[4].lineKind, LineKind::Header);
|
||||
QCOMPARE(result.meta[4].depth, 1);
|
||||
QVERIFY(result.meta[4].foldHead);
|
||||
QCOMPARE(result.meta[4].foldLevel, 0x401 | 0x2000);
|
||||
QCOMPARE(result.meta[2].lineKind, LineKind::Header);
|
||||
QCOMPARE(result.meta[2].depth, 1);
|
||||
QVERIFY(result.meta[2].foldHead);
|
||||
QCOMPARE(result.meta[2].foldLevel, 0x401 | 0x2000);
|
||||
|
||||
// Inner fields at depth 2
|
||||
QCOMPARE(result.meta[5].depth, 2);
|
||||
QCOMPARE(result.meta[5].foldLevel, 0x402);
|
||||
QCOMPARE(result.meta[6].depth, 2);
|
||||
QCOMPARE(result.meta[3].depth, 2);
|
||||
QCOMPARE(result.meta[3].foldLevel, 0x402);
|
||||
QCOMPARE(result.meta[4].depth, 2);
|
||||
|
||||
// Inner footer
|
||||
QCOMPARE(result.meta[7].lineKind, LineKind::Footer);
|
||||
QCOMPARE(result.meta[7].depth, 1);
|
||||
QCOMPARE(result.meta[5].lineKind, LineKind::Footer);
|
||||
QCOMPARE(result.meta[5].depth, 1);
|
||||
|
||||
// Root footer
|
||||
QCOMPARE(result.meta[8].lineKind, LineKind::Footer);
|
||||
QCOMPARE(result.meta[8].depth, 0);
|
||||
QCOMPARE(result.meta[6].lineKind, LineKind::Footer);
|
||||
QCOMPARE(result.meta[6].depth, 0);
|
||||
}
|
||||
|
||||
void testPointerDerefExpansion() {
|
||||
@@ -398,28 +392,28 @@ private slots:
|
||||
|
||||
ComposeResult result = compose(tree, prov);
|
||||
|
||||
// CommandRow + Blank + CommandRow2 + magic + ptr(merged fold header) + fn1 + fn2 + ptr footer + Main footer = 9
|
||||
// CommandRow + magic + ptr(merged fold header) + fn1 + fn2 + ptr footer + Main footer = 7
|
||||
// VTable standalone: header + fn1 + fn2 + footer = 4
|
||||
// Total = 13
|
||||
QCOMPARE(result.meta.size(), 13);
|
||||
// Total = 11
|
||||
QCOMPARE(result.meta.size(), 11);
|
||||
|
||||
// magic field (depth 1)
|
||||
QCOMPARE(result.meta[3].lineKind, LineKind::Field);
|
||||
QCOMPARE(result.meta[3].depth, 1);
|
||||
QCOMPARE(result.meta[1].lineKind, LineKind::Field);
|
||||
QCOMPARE(result.meta[1].depth, 1);
|
||||
|
||||
// Pointer as merged fold header: "VTable* ptr {"
|
||||
QCOMPARE(result.meta[4].lineKind, LineKind::Header);
|
||||
QCOMPARE(result.meta[4].depth, 1);
|
||||
QVERIFY(result.meta[4].foldHead);
|
||||
QCOMPARE(result.meta[4].nodeKind, NodeKind::Pointer64);
|
||||
QCOMPARE(result.meta[2].lineKind, LineKind::Header);
|
||||
QCOMPARE(result.meta[2].depth, 1);
|
||||
QVERIFY(result.meta[2].foldHead);
|
||||
QCOMPARE(result.meta[2].nodeKind, NodeKind::Pointer64);
|
||||
|
||||
// Expanded fields at depth 2 (struct header merged into pointer)
|
||||
QCOMPARE(result.meta[5].depth, 2);
|
||||
QCOMPARE(result.meta[6].depth, 2);
|
||||
QCOMPARE(result.meta[3].depth, 2);
|
||||
QCOMPARE(result.meta[4].depth, 2);
|
||||
|
||||
// Pointer fold footer
|
||||
QCOMPARE(result.meta[7].lineKind, LineKind::Footer);
|
||||
QCOMPARE(result.meta[7].depth, 1);
|
||||
QCOMPARE(result.meta[5].lineKind, LineKind::Footer);
|
||||
QCOMPARE(result.meta[5].depth, 1);
|
||||
}
|
||||
|
||||
void testPointerDerefNull() {
|
||||
@@ -463,22 +457,22 @@ private slots:
|
||||
|
||||
ComposeResult result = compose(tree, prov);
|
||||
|
||||
// CommandRow + Blank + CommandRow2 + ptr(merged fold header) + target field + ptr footer + Main footer = 7
|
||||
// CommandRow + ptr(merged fold header) + target field + ptr footer + Main footer = 5
|
||||
// Target standalone: header + field + footer = 3
|
||||
// Total = 10 (null ptr still shows template preview)
|
||||
QCOMPARE(result.meta.size(), 10);
|
||||
// Total = 8 (null ptr still shows template preview)
|
||||
QCOMPARE(result.meta.size(), 8);
|
||||
|
||||
// Pointer as merged fold header (expanded — shows template at offset 0)
|
||||
QCOMPARE(result.meta[3].lineKind, LineKind::Header);
|
||||
QCOMPARE(result.meta[3].depth, 1);
|
||||
QVERIFY(result.meta[3].foldHead);
|
||||
QCOMPARE(result.meta[1].lineKind, LineKind::Header);
|
||||
QCOMPARE(result.meta[1].depth, 1);
|
||||
QVERIFY(result.meta[1].foldHead);
|
||||
|
||||
// Target field shown as template preview
|
||||
QCOMPARE(result.meta[4].lineKind, LineKind::Field);
|
||||
QCOMPARE(result.meta[4].depth, 2);
|
||||
QCOMPARE(result.meta[2].lineKind, LineKind::Field);
|
||||
QCOMPARE(result.meta[2].depth, 2);
|
||||
|
||||
// Pointer fold footer
|
||||
QCOMPARE(result.meta[5].lineKind, LineKind::Footer);
|
||||
QCOMPARE(result.meta[3].lineKind, LineKind::Footer);
|
||||
}
|
||||
|
||||
void testPointerDerefCollapsed() {
|
||||
@@ -525,14 +519,14 @@ private slots:
|
||||
|
||||
ComposeResult result = compose(tree, prov);
|
||||
|
||||
// CommandRow + Blank + CommandRow2 + ptr(fold head, collapsed) + Main footer = 5
|
||||
// CommandRow + ptr(fold head, collapsed) + Main footer = 3
|
||||
// Target standalone: header + field + footer = 3
|
||||
// Total = 8
|
||||
QCOMPARE(result.meta.size(), 8);
|
||||
// Total = 6
|
||||
QCOMPARE(result.meta.size(), 6);
|
||||
|
||||
// Pointer is fold head (depth 1)
|
||||
QVERIFY(result.meta[3].foldHead);
|
||||
QCOMPARE(result.meta[3].depth, 1);
|
||||
QVERIFY(result.meta[1].foldHead);
|
||||
QCOMPARE(result.meta[1].depth, 1);
|
||||
}
|
||||
|
||||
void testPointerDerefCycle() {
|
||||
@@ -595,12 +589,12 @@ private slots:
|
||||
QVERIFY(result.meta.size() > 0);
|
||||
QVERIFY(result.meta.size() < 100); // sanity: bounded output
|
||||
|
||||
// CommandRow + Blank + CommandRow2 + ptr merged header + data + self merged header
|
||||
// CommandRow + ptr merged header + data + self merged header
|
||||
// Second expansion blocked by cycle guard: no children under self
|
||||
// Then: self footer + ptr footer + Main footer + standalone Recursive rendering
|
||||
QVERIFY(result.meta[3].foldHead); // ptr merged fold head
|
||||
QCOMPARE(result.meta[3].lineKind, LineKind::Header); // ptr merged header
|
||||
QCOMPARE(result.meta[4].lineKind, LineKind::Field); // data field (first child of Recursive)
|
||||
QVERIFY(result.meta[1].foldHead); // ptr merged fold head
|
||||
QCOMPARE(result.meta[1].lineKind, LineKind::Header); // ptr merged header
|
||||
QCOMPARE(result.meta[2].lineKind, LineKind::Field); // data field (first child of Recursive)
|
||||
}
|
||||
|
||||
void testStructFooterSimple() {
|
||||
@@ -664,21 +658,12 @@ private slots:
|
||||
ComposeResult result = compose(tree, prov);
|
||||
|
||||
for (int i = 0; i < result.meta.size(); i++) {
|
||||
// Skip CommandRow / Blank / CommandRow2 (synthetic lines with sentinel nodeId)
|
||||
// Skip CommandRow (synthetic line with sentinel nodeId)
|
||||
if (result.meta[i].lineKind == LineKind::CommandRow) {
|
||||
QCOMPARE(result.meta[i].nodeId, kCommandRowId);
|
||||
QCOMPARE(result.meta[i].nodeIdx, -1);
|
||||
continue;
|
||||
}
|
||||
if (result.meta[i].lineKind == LineKind::Blank) {
|
||||
QCOMPARE(result.meta[i].nodeIdx, -1);
|
||||
continue;
|
||||
}
|
||||
if (result.meta[i].lineKind == LineKind::CommandRow2) {
|
||||
QCOMPARE(result.meta[i].nodeId, kCommandRow2Id);
|
||||
QCOMPARE(result.meta[i].nodeIdx, -1);
|
||||
continue;
|
||||
}
|
||||
QVERIFY2(result.meta[i].nodeId != 0,
|
||||
qPrintable(QString("Line %1 has nodeId=0").arg(i)));
|
||||
int ni = result.meta[i].nodeIdx;
|
||||
@@ -955,16 +940,16 @@ private slots:
|
||||
NullProvider prov;
|
||||
ComposeResult result = compose(tree, prov);
|
||||
|
||||
// CommandRow + Blank + CommandRow2 + Array header(collapsed) + root footer = 5
|
||||
QCOMPARE(result.meta.size(), 5);
|
||||
// CommandRow + Array header(collapsed) + root footer = 3
|
||||
QCOMPARE(result.meta.size(), 3);
|
||||
|
||||
// Array header is collapsed (at index 3)
|
||||
// Array header is collapsed (at index 1)
|
||||
int arrLine = -1;
|
||||
for (int i = 0; i < result.meta.size(); i++) {
|
||||
if (result.meta[i].isArrayHeader) { arrLine = i; break; }
|
||||
}
|
||||
QVERIFY(arrLine >= 0);
|
||||
QCOMPARE(arrLine, 3);
|
||||
QCOMPARE(arrLine, 1);
|
||||
QVERIFY(result.meta[arrLine].foldCollapsed);
|
||||
|
||||
// Header text should NOT contain "{"
|
||||
@@ -1826,10 +1811,10 @@ private slots:
|
||||
QCOMPARE(tree.computeStructAlignment(rootId), 1);
|
||||
}
|
||||
|
||||
void testCommandRow2NameSpan() {
|
||||
// Name span should cover the class name
|
||||
QString text = "struct\u25BE MyClass";
|
||||
ColumnSpan nameSpan = commandRow2NameSpan(text);
|
||||
void testCommandRowRootNameSpan() {
|
||||
// Name span should cover the class name in the merged command row
|
||||
QString text = "source\u25BE \u00B7 0x0 \u00B7 struct\u25BE MyClass {";
|
||||
ColumnSpan nameSpan = commandRowRootNameSpan(text);
|
||||
QVERIFY(nameSpan.valid);
|
||||
|
||||
QString nameText = text.mid(nameSpan.start, nameSpan.end - nameSpan.start);
|
||||
@@ -1881,11 +1866,10 @@ private slots:
|
||||
QVERIFY2(result.meta.size() >= 5,
|
||||
qPrintable(QString("Expected >= 5 lines, got %1").arg(result.meta.size())));
|
||||
|
||||
// Every non-blank line should have text content
|
||||
// Every line should have text content
|
||||
QStringList lines = result.text.split('\n');
|
||||
QCOMPARE(lines.size(), result.meta.size());
|
||||
for (int i = 0; i < lines.size(); i++) {
|
||||
if (result.meta[i].lineKind == LineKind::Blank) continue;
|
||||
QVERIFY2(!lines[i].isEmpty(),
|
||||
qPrintable(QString("Line %1 is empty").arg(i)));
|
||||
}
|
||||
|
||||
@@ -376,7 +376,7 @@ private slots:
|
||||
|
||||
// Set CommandRow text with an ADDR value (simulates controller.updateCommandRow)
|
||||
m_editor->setCommandRowText(
|
||||
QStringLiteral("source\u25BE \u203A 0xD87B5E5000"));
|
||||
QStringLiteral("source\u25BE \u00B7 0xD87B5E5000"));
|
||||
|
||||
// BaseAddress should be ALLOWED on CommandRow (ADDR field)
|
||||
bool ok = m_editor->beginInlineEdit(EditTarget::BaseAddress, 0);
|
||||
@@ -394,7 +394,7 @@ private slots:
|
||||
|
||||
// ── Test: inline edit lifecycle (begin → commit → re-edit) ──
|
||||
void testInlineEditReEntry() {
|
||||
// Move cursor to line 3 (first field; 0=CommandRow, 1=Blank, 2=CommandRow2, root header suppressed)
|
||||
// Move cursor to first data line (0=CommandRow, root header suppressed)
|
||||
m_editor->scintilla()->setCursorPosition(kFirstDataLine, 0);
|
||||
|
||||
// Should not be editing
|
||||
@@ -712,7 +712,7 @@ private slots:
|
||||
void testSelectedNodeIndices() {
|
||||
m_editor->applyDocument(m_result);
|
||||
|
||||
// Put cursor on first field line (kFirstDataLine; 0=CommandRow, 1=Blank, 2=CommandRow2)
|
||||
// Put cursor on first field line (kFirstDataLine; 0=CommandRow)
|
||||
m_editor->scintilla()->setCursorPosition(kFirstDataLine, 0);
|
||||
QSet<int> sel = m_editor->selectedNodeIndices();
|
||||
QCOMPARE(sel.size(), 1);
|
||||
@@ -750,7 +750,7 @@ private slots:
|
||||
|
||||
// Set CommandRow text with ADDR value (simulates controller)
|
||||
m_editor->setCommandRowText(
|
||||
QStringLiteral("source\u25BE \u203A 0xD87B5E5000"));
|
||||
QStringLiteral("source\u25BE \u00B7 0xD87B5E5000"));
|
||||
|
||||
// Line 0 is CommandRow
|
||||
const LineMeta* lm = m_editor->metaForLine(0);
|
||||
@@ -902,7 +902,7 @@ private slots:
|
||||
|
||||
// Set CommandRow text with ADDR value (simulates controller)
|
||||
m_editor->setCommandRowText(
|
||||
QStringLiteral("source\u25BE \u203A 0xD87B5E5000"));
|
||||
QStringLiteral("source\u25BE \u00B7 0xD87B5E5000"));
|
||||
|
||||
// Begin base address edit on line 0 (CommandRow ADDR field)
|
||||
bool ok = m_editor->beginInlineEdit(EditTarget::BaseAddress, 0);
|
||||
@@ -978,7 +978,7 @@ private slots:
|
||||
m_editor->applyDocument(m_result);
|
||||
QApplication::processEvents();
|
||||
|
||||
// Root header (line 2) has fold suppressed; find a nested struct with foldHead
|
||||
// Root header is suppressed; find a nested struct with foldHead
|
||||
int foldLine = -1;
|
||||
for (int i = 0; i < m_result.meta.size(); i++) {
|
||||
if (m_result.meta[i].foldHead && m_result.meta[i].lineKind == LineKind::Header) {
|
||||
@@ -1033,57 +1033,54 @@ private slots:
|
||||
QVERIFY(!m_editor->isEditing());
|
||||
}
|
||||
|
||||
// ── Test: CommandRow2 exists at kCommandRow2Line ──
|
||||
void testCommandRow2Exists() {
|
||||
// ── Test: CommandRow root class edits on line 0 ──
|
||||
void testCommandRowRootClassEdits() {
|
||||
m_editor->applyDocument(m_result);
|
||||
|
||||
// kCommandRow2Line should be CommandRow2
|
||||
const LineMeta* lm = m_editor->metaForLine(kCommandRow2Line);
|
||||
QVERIFY(lm);
|
||||
QCOMPARE(lm->lineKind, LineKind::CommandRow2);
|
||||
QCOMPARE(lm->nodeId, kCommandRow2Id);
|
||||
QCOMPARE(lm->nodeIdx, -1);
|
||||
// Set CommandRow text with root class (simulates controller.updateCommandRow)
|
||||
m_editor->setCommandRowText(
|
||||
QStringLiteral("source\u25BE \u00B7 0xD87B5E5000 \u00B7 struct\u25BE _PEB64 {"));
|
||||
|
||||
// Type/Name/Value should be rejected on CommandRow2
|
||||
QVERIFY(!m_editor->beginInlineEdit(EditTarget::Type, kCommandRow2Line));
|
||||
QVERIFY(!m_editor->beginInlineEdit(EditTarget::Name, kCommandRow2Line));
|
||||
QVERIFY(!m_editor->beginInlineEdit(EditTarget::Value, kCommandRow2Line));
|
||||
QVERIFY(!m_editor->isEditing());
|
||||
// RootClassName should be allowed on CommandRow (line 0)
|
||||
bool ok = m_editor->beginInlineEdit(EditTarget::RootClassName, 0);
|
||||
QVERIFY2(ok, "RootClassName edit should be allowed on CommandRow");
|
||||
QVERIFY(m_editor->isEditing());
|
||||
m_editor->cancelInlineEdit();
|
||||
|
||||
// RootClassName should be allowed on CommandRow2
|
||||
m_editor->setCommandRow2Text(QStringLiteral("struct\u25BE _PEB64"));
|
||||
bool ok = m_editor->beginInlineEdit(EditTarget::RootClassName, kCommandRow2Line);
|
||||
QVERIFY2(ok, "RootClassName edit should be allowed on CommandRow2");
|
||||
// RootClassType should be allowed on CommandRow (line 0)
|
||||
ok = m_editor->beginInlineEdit(EditTarget::RootClassType, 0);
|
||||
QVERIFY2(ok, "RootClassType edit should be allowed on CommandRow");
|
||||
QVERIFY(m_editor->isEditing());
|
||||
m_editor->cancelInlineEdit();
|
||||
}
|
||||
|
||||
// ── Test: CommandRow2 has class type and name but no alignas ──
|
||||
void testCommandRow2NoAlignas() {
|
||||
// ── Test: CommandRow root class name editable ──
|
||||
void testCommandRowRootClassName() {
|
||||
m_editor->applyDocument(m_result);
|
||||
|
||||
// Set CommandRow2 without alignas
|
||||
m_editor->setCommandRow2Text(QStringLiteral("struct\u25BE _PEB64"));
|
||||
// Set CommandRow with root class
|
||||
m_editor->setCommandRowText(
|
||||
QStringLiteral("source\u25BE \u00B7 0xD87B5E5000 \u00B7 struct\u25BE _PEB64 {"));
|
||||
|
||||
// kCommandRow2Line is CommandRow2
|
||||
const LineMeta* lm = m_editor->metaForLine(kCommandRow2Line);
|
||||
// Line 0 is CommandRow
|
||||
const LineMeta* lm = m_editor->metaForLine(0);
|
||||
QVERIFY(lm);
|
||||
QCOMPARE(lm->lineKind, LineKind::CommandRow2);
|
||||
QCOMPARE(lm->lineKind, LineKind::CommandRow);
|
||||
|
||||
// RootClassName should work
|
||||
QVERIFY(m_editor->beginInlineEdit(EditTarget::RootClassName, kCommandRow2Line));
|
||||
QVERIFY(m_editor->beginInlineEdit(EditTarget::RootClassName, 0));
|
||||
QVERIFY(m_editor->isEditing());
|
||||
m_editor->cancelInlineEdit();
|
||||
|
||||
m_editor->applyDocument(m_result);
|
||||
}
|
||||
|
||||
// ── Test: root header/footer are suppressed (CommandRow2 replaces them) ──
|
||||
// ── Test: root header/footer are suppressed (CommandRow replaces them) ──
|
||||
void testRootFoldSuppressed() {
|
||||
m_editor->applyDocument(m_result);
|
||||
|
||||
// Root struct header is completely suppressed from output.
|
||||
// Line 0 = CommandRow, Line 1 = Blank, Line 2 = CommandRow2, Line 3 = first field.
|
||||
// Line 0 = CommandRow, Line 1 = first field.
|
||||
const LineMeta* lm2 = m_editor->metaForLine(kFirstDataLine);
|
||||
QVERIFY(lm2);
|
||||
QCOMPARE(lm2->lineKind, LineKind::Field);
|
||||
|
||||
@@ -441,11 +441,9 @@ private slots:
|
||||
NullProvider prov;
|
||||
ComposeResult result = compose(tree, prov, 99999);
|
||||
|
||||
// Only command rows + blank
|
||||
QCOMPARE(result.meta.size(), 3);
|
||||
// Only command row
|
||||
QCOMPARE(result.meta.size(), 1);
|
||||
QCOMPARE(result.meta[0].lineKind, LineKind::CommandRow);
|
||||
QCOMPARE(result.meta[1].lineKind, LineKind::Blank);
|
||||
QCOMPARE(result.meta[2].lineKind, LineKind::CommandRow2);
|
||||
}
|
||||
|
||||
void testCompose_viewRootId_singleRoot() {
|
||||
@@ -882,13 +880,13 @@ private slots:
|
||||
NullProvider prov;
|
||||
ComposeResult result = compose(tree, prov);
|
||||
|
||||
// CommandRow + Blank + CommandRow2 + 1 Vec4 line + footer = 5
|
||||
QCOMPARE(result.meta.size(), 5);
|
||||
// CommandRow + 1 Vec4 line + footer = 3
|
||||
QCOMPARE(result.meta.size(), 3);
|
||||
|
||||
// The Vec4 line (index 3) is a single field line, not continuation
|
||||
QCOMPARE(result.meta[3].lineKind, LineKind::Field);
|
||||
QCOMPARE(result.meta[3].nodeKind, NodeKind::Vec4);
|
||||
QVERIFY(!result.meta[3].isContinuation);
|
||||
// The Vec4 line (index 1) is a single field line, not continuation
|
||||
QCOMPARE(result.meta[1].lineKind, LineKind::Field);
|
||||
QCOMPARE(result.meta[1].nodeKind, NodeKind::Vec4);
|
||||
QVERIFY(!result.meta[1].isContinuation);
|
||||
|
||||
// Copy text (equivalent to editor's "Copy All as Text")
|
||||
QString text = result.text;
|
||||
@@ -896,9 +894,9 @@ private slots:
|
||||
QVERIFY(text.contains("0.f, 0.f, 0.f, 0.f"));
|
||||
// Confirm type, name, and values all on the same line
|
||||
QStringList lines = text.split('\n');
|
||||
QVERIFY(lines[3].contains("vec4"));
|
||||
QVERIFY(lines[3].contains("position"));
|
||||
QVERIFY(lines[3].contains("0.f, 0.f, 0.f, 0.f"));
|
||||
QVERIFY(lines[1].contains("vec4"));
|
||||
QVERIFY(lines[1].contains("position"));
|
||||
QVERIFY(lines[1].contains("0.f, 0.f, 0.f, 0.f"));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user