Files
archived-Reclass/tests/test_rendered_view.cpp
IChooseYou d22661446b feat: turn sentinel dock tab into "+" new tab button
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.
2026-03-16 07:39:18 -06:00

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"