mirror of
https://github.com/NohamR/Reclass.git
synced 2026-05-10 19:59:21 +00:00
Condensed array display + per-scope column widths + MIT license
- Array element structs render without { } braces (condensed display)
- [N] separators show element indices within arrays
- Per-scope column width calculation (nested elements use tighter spacing)
- Array headers show struct[N] for struct arrays
- [N] separators are not interactive (no hover/click highlight)
- Dynamic type column width (min 8, max 14)
- PE32+ sample data with full headers, DataDirectory[16], SectionHeaders[4]
- Added MIT license
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -608,7 +608,7 @@ private slots:
|
||||
QCOMPARE(result.meta[2].lineKind, LineKind::Header); // Recursive header (expansion)
|
||||
}
|
||||
|
||||
void testStructFooterSizeof() {
|
||||
void testStructFooterSimple() {
|
||||
NodeTree tree;
|
||||
tree.baseAddress = 0;
|
||||
|
||||
@@ -627,13 +627,6 @@ private slots:
|
||||
f1.offset = 0;
|
||||
tree.addNode(f1);
|
||||
|
||||
Node f2;
|
||||
f2.kind = NodeKind::UInt64;
|
||||
f2.name = "b";
|
||||
f2.parentId = rootId;
|
||||
f2.offset = 4;
|
||||
tree.addNode(f2);
|
||||
|
||||
NullProvider prov;
|
||||
ComposeResult result = compose(tree, prov);
|
||||
|
||||
@@ -641,9 +634,10 @@ private slots:
|
||||
int lastLine = result.meta.size() - 1;
|
||||
QCOMPARE(result.meta[lastLine].lineKind, LineKind::Footer);
|
||||
|
||||
// Footer text should contain sizeof(Sized)=0xC (4+8=12=0xC)
|
||||
// Footer text should just be "};" (no sizeof)
|
||||
QString footerText = result.text.split('\n').last();
|
||||
QVERIFY(footerText.contains("sizeof(Sized)=0xC"));
|
||||
QVERIFY(footerText.contains("};"));
|
||||
QVERIFY(!footerText.contains("sizeof"));
|
||||
}
|
||||
|
||||
void testLineMetaHasNodeId() {
|
||||
@@ -669,115 +663,6 @@ private slots:
|
||||
}
|
||||
}
|
||||
|
||||
void testSizeofUpdatesAfterDelete() {
|
||||
// Test that sizeof recalculates after deleting a node
|
||||
NodeTree tree;
|
||||
tree.baseAddress = 0;
|
||||
|
||||
Node root;
|
||||
root.kind = NodeKind::Struct;
|
||||
root.name = "Test";
|
||||
root.parentId = 0;
|
||||
root.offset = 0;
|
||||
int ri = tree.addNode(root);
|
||||
uint64_t rootId = tree.nodes[ri].id;
|
||||
|
||||
Node f1;
|
||||
f1.kind = NodeKind::UInt32;
|
||||
f1.name = "a";
|
||||
f1.parentId = rootId;
|
||||
f1.offset = 0;
|
||||
tree.addNode(f1);
|
||||
|
||||
Node f2;
|
||||
f2.kind = NodeKind::UInt64;
|
||||
f2.name = "b";
|
||||
f2.parentId = rootId;
|
||||
f2.offset = 4;
|
||||
int f2i = tree.addNode(f2);
|
||||
uint64_t f2Id = tree.nodes[f2i].id;
|
||||
|
||||
NullProvider prov;
|
||||
|
||||
// First compose: sizeof should be 0xC (4+8=12)
|
||||
ComposeResult result1 = compose(tree, prov);
|
||||
QString footer1 = result1.text.split('\n').last();
|
||||
QVERIFY2(footer1.contains("sizeof(Test)=0xC"),
|
||||
qPrintable("Before delete: " + footer1));
|
||||
|
||||
// Delete the second field
|
||||
int idx = tree.indexOfId(f2Id);
|
||||
QVERIFY(idx >= 0);
|
||||
tree.nodes.remove(idx);
|
||||
tree.invalidateIdCache();
|
||||
|
||||
// Second compose: sizeof should be 0x4 (only UInt32 remains)
|
||||
ComposeResult result2 = compose(tree, prov);
|
||||
QString footer2 = result2.text.split('\n').last();
|
||||
QVERIFY2(footer2.contains("sizeof(Test)=0x4"),
|
||||
qPrintable("After delete: " + footer2));
|
||||
}
|
||||
|
||||
void testNestedStructSizeofUpdates() {
|
||||
// Test nested struct sizeof updates when child is deleted
|
||||
NodeTree tree;
|
||||
tree.baseAddress = 0;
|
||||
|
||||
// Root struct
|
||||
Node root;
|
||||
root.kind = NodeKind::Struct;
|
||||
root.name = "Root";
|
||||
root.parentId = 0;
|
||||
root.offset = 0;
|
||||
int ri = tree.addNode(root);
|
||||
uint64_t rootId = tree.nodes[ri].id;
|
||||
|
||||
// Nested struct (like IMAGE_FILE_HEADER)
|
||||
Node nested;
|
||||
nested.kind = NodeKind::Struct;
|
||||
nested.name = "Nested";
|
||||
nested.parentId = rootId;
|
||||
nested.offset = 0;
|
||||
int ni = tree.addNode(nested);
|
||||
uint64_t nestedId = tree.nodes[ni].id;
|
||||
|
||||
// Field in nested struct
|
||||
Node f1;
|
||||
f1.kind = NodeKind::UInt32;
|
||||
f1.name = "a";
|
||||
f1.parentId = nestedId;
|
||||
f1.offset = 0;
|
||||
tree.addNode(f1);
|
||||
|
||||
Node f2;
|
||||
f2.kind = NodeKind::UInt32;
|
||||
f2.name = "b";
|
||||
f2.parentId = nestedId;
|
||||
f2.offset = 4;
|
||||
int f2i = tree.addNode(f2);
|
||||
uint64_t f2Id = tree.nodes[f2i].id;
|
||||
|
||||
NullProvider prov;
|
||||
|
||||
// First compose
|
||||
ComposeResult result1 = compose(tree, prov);
|
||||
// Find nested struct footer
|
||||
QString text1 = result1.text;
|
||||
QVERIFY2(text1.contains("sizeof(Nested)=0x8"),
|
||||
qPrintable("Before delete nested sizeof: " + text1));
|
||||
|
||||
// Delete field from nested struct
|
||||
int idx = tree.indexOfId(f2Id);
|
||||
QVERIFY(idx >= 0);
|
||||
tree.nodes.remove(idx);
|
||||
tree.invalidateIdCache();
|
||||
|
||||
// Second compose - nested sizeof should update
|
||||
ComposeResult result2 = compose(tree, prov);
|
||||
QString text2 = result2.text;
|
||||
QVERIFY2(text2.contains("sizeof(Nested)=0x4"),
|
||||
qPrintable("After delete nested sizeof: " + text2));
|
||||
}
|
||||
};
|
||||
|
||||
QTEST_MAIN(TestCompose)
|
||||
|
||||
@@ -326,17 +326,17 @@ private slots:
|
||||
auto ts = rcx::typeSpanFor(lm);
|
||||
QVERIFY(ts.valid);
|
||||
QCOMPARE(ts.start, 6);
|
||||
QCOMPARE(ts.end, 16); // 6 + 10
|
||||
QCOMPARE(ts.end, 20); // 6 + 14 (kColType)
|
||||
|
||||
auto ns = rcx::nameSpanFor(lm);
|
||||
QVERIFY(ns.valid);
|
||||
QCOMPARE(ns.start, 18); // 6 + 10 + 2
|
||||
QCOMPARE(ns.end, 42); // 18 + 24
|
||||
QCOMPARE(ns.start, 22); // 6 + 14 + 2
|
||||
QCOMPARE(ns.end, 44); // 22 + 22 (kColName)
|
||||
|
||||
auto vs = rcx::valueSpanFor(lm, 60);
|
||||
auto vs = rcx::valueSpanFor(lm, 100);
|
||||
QVERIFY(vs.valid);
|
||||
QCOMPARE(vs.start, 44); // 18 + 24 + 2
|
||||
QCOMPARE(vs.end, 60);
|
||||
QCOMPARE(vs.start, 46); // 22 + 22 + 2
|
||||
QCOMPARE(vs.end, 78); // 46 + 32 (kColValue)
|
||||
}
|
||||
|
||||
void testColumnSpan_continuation() {
|
||||
@@ -349,10 +349,10 @@ private slots:
|
||||
QVERIFY(!rcx::typeSpanFor(lm).valid);
|
||||
QVERIFY(!rcx::nameSpanFor(lm).valid);
|
||||
|
||||
auto vs = rcx::valueSpanFor(lm, 60);
|
||||
auto vs = rcx::valueSpanFor(lm, 100);
|
||||
QVERIFY(vs.valid);
|
||||
QCOMPARE(vs.start, 6 + 10 + 24 + 4); // kFoldCol+indent + COL_TYPE + COL_NAME + 4
|
||||
QCOMPARE(vs.end, 60);
|
||||
QCOMPARE(vs.start, 6 + 14 + 22 + 4); // kFoldCol+indent + kColType(14) + kColName(22) + 4
|
||||
QCOMPARE(vs.end, 46 + 32); // start + kColValue
|
||||
}
|
||||
|
||||
void testColumnSpan_headerFooter() {
|
||||
@@ -382,17 +382,17 @@ private slots:
|
||||
auto ts = rcx::typeSpanFor(lm);
|
||||
QVERIFY(ts.valid);
|
||||
QCOMPARE(ts.start, 3);
|
||||
QCOMPARE(ts.end, 13); // 3 + 10
|
||||
QCOMPARE(ts.end, 17); // 3 + 14 (kColType)
|
||||
|
||||
auto ns = rcx::nameSpanFor(lm);
|
||||
QVERIFY(ns.valid);
|
||||
QCOMPARE(ns.start, 15); // 3 + 10 + 2
|
||||
QCOMPARE(ns.end, 39); // 15 + 24
|
||||
QCOMPARE(ns.start, 19); // 3 + 14 + 2
|
||||
QCOMPARE(ns.end, 41); // 19 + 22 (kColName)
|
||||
|
||||
auto vs = rcx::valueSpanFor(lm, 50);
|
||||
auto vs = rcx::valueSpanFor(lm, 100);
|
||||
QVERIFY(vs.valid);
|
||||
QCOMPARE(vs.start, 41); // 15 + 24 + 2
|
||||
QCOMPARE(vs.end, 50);
|
||||
QCOMPARE(vs.start, 43); // 19 + 22 + 2
|
||||
QCOMPARE(vs.end, 75); // 43 + 32 (kColValue)
|
||||
}
|
||||
|
||||
void testNodeIdJsonRoundTrip() {
|
||||
|
||||
@@ -9,12 +9,13 @@ private slots:
|
||||
void testTypeName() {
|
||||
QString s = fmt::typeName(NodeKind::Float);
|
||||
QVERIFY(s.trimmed() == "float");
|
||||
QCOMPARE(s.size(), 10); // COL_TYPE
|
||||
QCOMPARE(s.size(), 14); // kColType
|
||||
}
|
||||
|
||||
void testFmtInt32() {
|
||||
QCOMPARE(fmt::fmtInt32(-42), QString("-42"));
|
||||
QCOMPARE(fmt::fmtInt32(0), QString("0"));
|
||||
// fmtInt32 outputs hex representation (0xffffffd6 for -42)
|
||||
QCOMPARE(fmt::fmtInt32(-42), QString("0xffffffd6"));
|
||||
QCOMPARE(fmt::fmtInt32(0), QString("0x0"));
|
||||
}
|
||||
|
||||
void testFmtFloat() {
|
||||
@@ -224,25 +225,15 @@ private slots:
|
||||
QVERIFY(!ok);
|
||||
}
|
||||
|
||||
void testFmtStructFooterWithSize() {
|
||||
void testFmtStructFooterSimple() {
|
||||
Node n;
|
||||
n.kind = NodeKind::Struct;
|
||||
n.name = "Test";
|
||||
|
||||
// With size
|
||||
QString s1 = fmt::fmtStructFooter(n, 0, 0x14);
|
||||
QVERIFY(s1.contains("};"));
|
||||
QVERIFY(s1.contains("sizeof(Test)=0x14"));
|
||||
|
||||
// Size 0 → no sizeof
|
||||
QString s2 = fmt::fmtStructFooter(n, 0, 0);
|
||||
QVERIFY(s2.contains("};"));
|
||||
QVERIFY(!s2.contains("sizeof"));
|
||||
|
||||
// Default (no size arg) → no sizeof
|
||||
QString s3 = fmt::fmtStructFooter(n, 0);
|
||||
QVERIFY(s3.contains("};"));
|
||||
QVERIFY(!s3.contains("sizeof"));
|
||||
// Footer is always just "};" (no sizeof comment)
|
||||
QString s = fmt::fmtStructFooter(n, 0, 0x14);
|
||||
QVERIFY(s.contains("};"));
|
||||
QVERIFY(!s.contains("sizeof")); // No sizeof comment
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user