mirror of
https://github.com/NohamR/Reclass.git
synced 2026-05-10 19:59:21 +00:00
Instead of hiding the sentinel tab (which leaked space on macOS), repurpose it as a visible "+" button that creates a new struct tab on click. Compact 32px icon-only tab with pixel-perfect cross drawn via fillRect. Skips context menu and middle-click. Always positioned as the last tab in the group.
362 lines
12 KiB
C++
362 lines
12 KiB
C++
#include <QtTest/QTest>
|
|
#include <QApplication>
|
|
#include <Qsci/qsciscintilla.h>
|
|
#include <Qsci/qsciscintillabase.h>
|
|
#include <Qsci/qscilexercpp.h>
|
|
#include <QColor>
|
|
#include <QFont>
|
|
|
|
#include "core.h"
|
|
#include "generator.h"
|
|
|
|
// Raw Scintilla message IDs not exposed by QsciScintillaBase wrapper
|
|
static constexpr int SCI_GETSELBACK = 2477;
|
|
static constexpr int SCI_GETSELFORE = 2476;
|
|
|
|
// ── Helper: extract BGR long from QColor (Scintilla stores colors as 0x00BBGGRR) ──
|
|
|
|
static long toBGR(const QColor& c) {
|
|
return (long)c.red() | ((long)c.green() << 8) | ((long)c.blue() << 16);
|
|
}
|
|
|
|
// ── Replicates MainWindow::setupRenderedSci so the test stays in sync ──
|
|
|
|
static void setupRenderedSci(QsciScintilla* sci) {
|
|
QFont f("Consolas", 12);
|
|
f.setFixedPitch(true);
|
|
|
|
sci->setFont(f);
|
|
sci->setReadOnly(false);
|
|
sci->setWrapMode(QsciScintilla::WrapNone);
|
|
sci->setTabWidth(4);
|
|
sci->setIndentationsUseTabs(false);
|
|
sci->SendScintilla(QsciScintillaBase::SCI_SETEXTRAASCENT, (long)2);
|
|
sci->SendScintilla(QsciScintillaBase::SCI_SETEXTRADESCENT, (long)2);
|
|
|
|
// Line number margin
|
|
sci->setMarginType(0, QsciScintilla::NumberMargin);
|
|
sci->setMarginWidth(0, "00000");
|
|
sci->setMarginsBackgroundColor(QColor("#252526"));
|
|
sci->setMarginsForegroundColor(QColor("#858585"));
|
|
sci->setMarginsFont(f);
|
|
|
|
sci->setMarginWidth(1, 0);
|
|
sci->setMarginWidth(2, 0);
|
|
|
|
// Lexer FIRST — setLexer() resets caret/selection/paper colors
|
|
auto* lexer = new QsciLexerCPP(sci);
|
|
lexer->setFont(f);
|
|
lexer->setColor(QColor("#569cd6"), QsciLexerCPP::Keyword);
|
|
lexer->setColor(QColor("#569cd6"), QsciLexerCPP::KeywordSet2);
|
|
lexer->setColor(QColor("#b5cea8"), QsciLexerCPP::Number);
|
|
lexer->setColor(QColor("#ce9178"), QsciLexerCPP::DoubleQuotedString);
|
|
lexer->setColor(QColor("#ce9178"), QsciLexerCPP::SingleQuotedString);
|
|
lexer->setColor(QColor("#6a9955"), QsciLexerCPP::Comment);
|
|
lexer->setColor(QColor("#6a9955"), QsciLexerCPP::CommentLine);
|
|
lexer->setColor(QColor("#6a9955"), QsciLexerCPP::CommentDoc);
|
|
lexer->setColor(QColor("#d4d4d4"), QsciLexerCPP::Default);
|
|
lexer->setColor(QColor("#d4d4d4"), QsciLexerCPP::Identifier);
|
|
lexer->setColor(QColor("#c586c0"), QsciLexerCPP::PreProcessor);
|
|
lexer->setColor(QColor("#d4d4d4"), QsciLexerCPP::Operator);
|
|
for (int i = 0; i <= 127; i++) {
|
|
lexer->setPaper(QColor("#1e1e1e"), i);
|
|
lexer->setFont(f, i);
|
|
}
|
|
sci->setLexer(lexer);
|
|
sci->setBraceMatching(QsciScintilla::NoBraceMatch);
|
|
|
|
// Colors AFTER setLexer() — the lexer resets these on attach
|
|
sci->setPaper(QColor("#1e1e1e"));
|
|
sci->setColor(QColor("#d4d4d4"));
|
|
sci->setCaretForegroundColor(QColor("#d4d4d4"));
|
|
sci->setCaretLineVisible(true);
|
|
sci->setCaretLineBackgroundColor(QColor(43, 43, 43));
|
|
sci->setSelectionBackgroundColor(QColor("#264f78"));
|
|
sci->setSelectionForegroundColor(QColor("#d4d4d4"));
|
|
}
|
|
|
|
// ── Test tree helper ──
|
|
|
|
static rcx::NodeTree makeTestTree() {
|
|
rcx::NodeTree tree;
|
|
rcx::Node root;
|
|
root.kind = rcx::NodeKind::Struct;
|
|
root.name = "TestStruct";
|
|
root.structTypeName = "TestStruct";
|
|
root.parentId = 0;
|
|
root.offset = 0;
|
|
int ri = tree.addNode(root);
|
|
uint64_t rootId = tree.nodes[ri].id;
|
|
|
|
rcx::Node f1;
|
|
f1.kind = rcx::NodeKind::Int32;
|
|
f1.name = "health";
|
|
f1.parentId = rootId;
|
|
f1.offset = 0;
|
|
tree.addNode(f1);
|
|
|
|
rcx::Node f2;
|
|
f2.kind = rcx::NodeKind::Float;
|
|
f2.name = "speed";
|
|
f2.parentId = rootId;
|
|
f2.offset = 4;
|
|
tree.addNode(f2);
|
|
|
|
return tree;
|
|
}
|
|
|
|
// ── Test class ──
|
|
|
|
class TestRenderedView : public QObject {
|
|
Q_OBJECT
|
|
|
|
private slots:
|
|
|
|
// ── Verify caret line background is NOT yellow after setup ──
|
|
|
|
void testCaretLineBackgroundNotYellow() {
|
|
QsciScintilla sci;
|
|
setupRenderedSci(&sci);
|
|
sci.show();
|
|
sci.setText("struct Foo {\n int x;\n};\n");
|
|
QTest::qWait(50);
|
|
|
|
long bgr = sci.SendScintilla(QsciScintillaBase::SCI_GETCARETLINEBACK);
|
|
long expected = toBGR(QColor(43, 43, 43));
|
|
|
|
// Yellow would be 0x00FFFF or similar high-value — ours should be dark
|
|
long yellow = toBGR(QColor(255, 255, 0));
|
|
QVERIFY2(bgr != yellow,
|
|
qPrintable(QString("Caret line is yellow (0x%1), expected dark (0x%2)")
|
|
.arg(bgr, 6, 16, QChar('0'))
|
|
.arg(expected, 6, 16, QChar('0'))));
|
|
QCOMPARE(bgr, expected);
|
|
}
|
|
|
|
// ── Verify caret line is enabled ──
|
|
|
|
void testCaretLineEnabled() {
|
|
QsciScintilla sci;
|
|
setupRenderedSci(&sci);
|
|
|
|
long visible = sci.SendScintilla(QsciScintillaBase::SCI_GETCARETLINEVISIBLE);
|
|
QCOMPARE(visible, (long)1);
|
|
}
|
|
|
|
// ── Verify editor background (paper) is dark ──
|
|
|
|
void testPaperColor() {
|
|
QsciScintilla sci;
|
|
setupRenderedSci(&sci);
|
|
|
|
// Query default style background via Scintilla
|
|
long bgr = sci.SendScintilla(QsciScintillaBase::SCI_STYLEGETBACK,
|
|
(unsigned long)0 /*STYLE_DEFAULT*/);
|
|
long expected = toBGR(QColor("#1e1e1e"));
|
|
QCOMPARE(bgr, expected);
|
|
}
|
|
|
|
// ── Verify caret (cursor) foreground color ──
|
|
|
|
void testCaretForegroundColor() {
|
|
QsciScintilla sci;
|
|
setupRenderedSci(&sci);
|
|
|
|
long bgr = sci.SendScintilla(QsciScintillaBase::SCI_GETCARETFORE);
|
|
long expected = toBGR(QColor("#d4d4d4"));
|
|
QCOMPARE(bgr, expected);
|
|
}
|
|
|
|
// ── Verify selection colors are set (no direct Scintilla getter, but we can
|
|
// verify they survive a round-trip through the SCI_SETSEL* messages by
|
|
// checking the element colour API introduced in Scintilla 5.x) ──
|
|
|
|
void testSelectionColorsApplied() {
|
|
QsciScintilla sci;
|
|
setupRenderedSci(&sci);
|
|
sci.show();
|
|
sci.setText("int x = 42;\n");
|
|
QTest::qWait(50);
|
|
|
|
// Select text and verify rendering doesn't crash
|
|
sci.SendScintilla(QsciScintillaBase::SCI_SETSEL, (unsigned long)0, (long)3);
|
|
QTest::qWait(50);
|
|
|
|
// SCI_GETELEMENTCOLOUR (element 10 = SC_ELEMENT_SELECTION_BACK) returns
|
|
// the selection back colour on Scintilla >= 5.2. If not available, fall
|
|
// back to verifying the calls didn't throw and caret line is still correct.
|
|
constexpr int SCI_GETELEMENTCOLOUR = 2753;
|
|
constexpr int SC_ELEMENT_SELECTION_BACK = 10;
|
|
|
|
long selBack = sci.SendScintilla(SCI_GETELEMENTCOLOUR,
|
|
(unsigned long)SC_ELEMENT_SELECTION_BACK);
|
|
if (selBack != 0) {
|
|
// Scintilla 5.x: colour stored as 0xAABBGGRR (with alpha in high byte)
|
|
long bgrMask = selBack & 0x00FFFFFF;
|
|
long expected = toBGR(QColor("#264f78"));
|
|
QCOMPARE(bgrMask, expected);
|
|
} else {
|
|
// Older Scintilla: just verify caret line is still correct as a proxy
|
|
long caretBg = sci.SendScintilla(QsciScintillaBase::SCI_GETCARETLINEBACK);
|
|
long expected = toBGR(QColor(43, 43, 43));
|
|
QCOMPARE(caretBg, expected);
|
|
}
|
|
}
|
|
|
|
// ── Verify lexer keyword color is VS Code blue, not default ──
|
|
|
|
void testKeywordColor() {
|
|
QsciScintilla sci;
|
|
setupRenderedSci(&sci);
|
|
|
|
auto* lexer = qobject_cast<QsciLexerCPP*>(sci.lexer());
|
|
QVERIFY(lexer != nullptr);
|
|
|
|
QColor kw = lexer->color(QsciLexerCPP::Keyword);
|
|
QCOMPARE(kw, QColor("#569cd6"));
|
|
}
|
|
|
|
// ── Verify comment color is VS Code green ──
|
|
|
|
void testCommentColor() {
|
|
QsciScintilla sci;
|
|
setupRenderedSci(&sci);
|
|
|
|
auto* lexer = qobject_cast<QsciLexerCPP*>(sci.lexer());
|
|
QVERIFY(lexer != nullptr);
|
|
|
|
QCOMPARE(lexer->color(QsciLexerCPP::Comment), QColor("#6a9955"));
|
|
QCOMPARE(lexer->color(QsciLexerCPP::CommentLine), QColor("#6a9955"));
|
|
}
|
|
|
|
// ── Verify number color is VS Code light green ──
|
|
|
|
void testNumberColor() {
|
|
QsciScintilla sci;
|
|
setupRenderedSci(&sci);
|
|
|
|
auto* lexer = qobject_cast<QsciLexerCPP*>(sci.lexer());
|
|
QVERIFY(lexer != nullptr);
|
|
|
|
QCOMPARE(lexer->color(QsciLexerCPP::Number), QColor("#b5cea8"));
|
|
}
|
|
|
|
// ── Verify string color is VS Code orange ──
|
|
|
|
void testStringColor() {
|
|
QsciScintilla sci;
|
|
setupRenderedSci(&sci);
|
|
|
|
auto* lexer = qobject_cast<QsciLexerCPP*>(sci.lexer());
|
|
QVERIFY(lexer != nullptr);
|
|
|
|
QCOMPARE(lexer->color(QsciLexerCPP::DoubleQuotedString), QColor("#ce9178"));
|
|
QCOMPARE(lexer->color(QsciLexerCPP::SingleQuotedString), QColor("#ce9178"));
|
|
}
|
|
|
|
// ── Verify preprocessor color is VS Code purple ──
|
|
|
|
void testPreprocessorColor() {
|
|
QsciScintilla sci;
|
|
setupRenderedSci(&sci);
|
|
|
|
auto* lexer = qobject_cast<QsciLexerCPP*>(sci.lexer());
|
|
QVERIFY(lexer != nullptr);
|
|
|
|
QCOMPARE(lexer->color(QsciLexerCPP::PreProcessor), QColor("#c586c0"));
|
|
}
|
|
|
|
// ── Verify default/identifier text color ──
|
|
|
|
void testDefaultTextColor() {
|
|
QsciScintilla sci;
|
|
setupRenderedSci(&sci);
|
|
|
|
auto* lexer = qobject_cast<QsciLexerCPP*>(sci.lexer());
|
|
QVERIFY(lexer != nullptr);
|
|
|
|
QCOMPARE(lexer->color(QsciLexerCPP::Default), QColor("#d4d4d4"));
|
|
QCOMPARE(lexer->color(QsciLexerCPP::Identifier), QColor("#d4d4d4"));
|
|
QCOMPARE(lexer->color(QsciLexerCPP::Operator), QColor("#d4d4d4"));
|
|
}
|
|
|
|
// ── Verify all 128 lexer styles have dark paper ──
|
|
|
|
void testAllStylesHaveDarkPaper() {
|
|
QsciScintilla sci;
|
|
setupRenderedSci(&sci);
|
|
|
|
auto* lexer = qobject_cast<QsciLexerCPP*>(sci.lexer());
|
|
QVERIFY(lexer != nullptr);
|
|
|
|
QColor expected("#1e1e1e");
|
|
for (int i = 0; i <= 127; i++) {
|
|
QColor paper = lexer->paper(i);
|
|
QVERIFY2(paper == expected,
|
|
qPrintable(QString("Style %1 paper is %2, expected %3")
|
|
.arg(i).arg(paper.name()).arg(expected.name())));
|
|
}
|
|
}
|
|
|
|
// ── Verify margin colors match dark theme ──
|
|
|
|
void testMarginColors() {
|
|
QsciScintilla sci;
|
|
setupRenderedSci(&sci);
|
|
|
|
// Query margin background via Scintilla (style 33 = STYLE_LINENUMBER)
|
|
long marginBg = sci.SendScintilla(QsciScintillaBase::SCI_STYLEGETBACK,
|
|
(unsigned long)33);
|
|
long expectedBg = toBGR(QColor("#252526"));
|
|
QCOMPARE(marginBg, expectedBg);
|
|
|
|
long marginFg = sci.SendScintilla(QsciScintillaBase::SCI_STYLEGETFORE,
|
|
(unsigned long)33);
|
|
long expectedFg = toBGR(QColor("#858585"));
|
|
QCOMPARE(marginFg, expectedFg);
|
|
}
|
|
|
|
// ── End-to-end: generate C++ and load into rendered view ──
|
|
|
|
void testGeneratedCodeInRenderedView() {
|
|
auto tree = makeTestTree();
|
|
uint64_t rootId = tree.nodes[0].id;
|
|
QString code = rcx::renderCpp(tree, rootId);
|
|
|
|
// Verify generated code has no pragma pack / cstdint
|
|
QVERIFY(!code.contains("#pragma pack"));
|
|
QVERIFY(!code.contains("#include <cstdint>"));
|
|
QVERIFY(code.contains("#pragma once"));
|
|
QVERIFY(code.contains("struct TestStruct"));
|
|
|
|
// Load into rendered sci and verify colors survive
|
|
QsciScintilla sci;
|
|
setupRenderedSci(&sci);
|
|
sci.show();
|
|
sci.setText(code);
|
|
QTest::qWait(100);
|
|
|
|
// Caret line must still be dark after text load
|
|
long caretBg = sci.SendScintilla(QsciScintillaBase::SCI_GETCARETLINEBACK);
|
|
long expected = toBGR(QColor(43, 43, 43));
|
|
QCOMPARE(caretBg, expected);
|
|
|
|
// Paper must still be dark
|
|
long paperBg = sci.SendScintilla(QsciScintillaBase::SCI_STYLEGETBACK,
|
|
(unsigned long)0);
|
|
QCOMPARE(paperBg, toBGR(QColor("#1e1e1e")));
|
|
}
|
|
|
|
// ── Verify brace matching is disabled ──
|
|
|
|
void testBraceMatchDisabled() {
|
|
QsciScintilla sci;
|
|
setupRenderedSci(&sci);
|
|
|
|
QCOMPARE(sci.braceMatching(), QsciScintilla::NoBraceMatch);
|
|
}
|
|
};
|
|
|
|
QTEST_MAIN(TestRenderedView)
|
|
#include "test_rendered_view.moc"
|