diff options
Diffstat (limited to 'tests/auto/gui')
33 files changed, 1567 insertions, 253 deletions
diff --git a/tests/auto/gui/image/qimage/qimage.pro b/tests/auto/gui/image/qimage/qimage.pro index b40866892e..0593cfbc23 100644 --- a/tests/auto/gui/image/qimage/qimage.pro +++ b/tests/auto/gui/image/qimage/qimage.pro @@ -7,7 +7,7 @@ qtConfig(c++11): CONFIG += c++11 android:!android-embedded: RESOURCES += qimage.qrc -win32:!winrt: LIBS += -lgdi32 -luser32 +win32:!winrt: QMAKE_USE += user32 gdi32 darwin: LIBS += -framework CoreGraphics TESTDATA += images/* diff --git a/tests/auto/gui/image/qpixmap/qpixmap.pro b/tests/auto/gui/image/qpixmap/qpixmap.pro index e6a020af1a..c9219dad1d 100644 --- a/tests/auto/gui/image/qpixmap/qpixmap.pro +++ b/tests/auto/gui/image/qpixmap/qpixmap.pro @@ -5,7 +5,7 @@ QT += core-private gui-private testlib qtHaveModule(widgets): QT += widgets widgets-private SOURCES += tst_qpixmap.cpp -win32:!winrt:LIBS += -lgdi32 -luser32 +win32:!winrt: QMAKE_USE += user32 gdi32 RESOURCES += qpixmap.qrc TESTDATA += convertFromImage/* convertFromToHICON/* loadFromData/* images/* diff --git a/tests/auto/gui/itemmodels/qstandarditemmodel/tst_qstandarditemmodel.cpp b/tests/auto/gui/itemmodels/qstandarditemmodel/tst_qstandarditemmodel.cpp index 550f70890e..bc8bc38da6 100644 --- a/tests/auto/gui/itemmodels/qstandarditemmodel/tst_qstandarditemmodel.cpp +++ b/tests/auto/gui/itemmodels/qstandarditemmodel/tst_qstandarditemmodel.cpp @@ -734,7 +734,7 @@ void tst_QStandardItemModel::data() currentRoles.clear(); // bad args m_model->setData(QModelIndex(), "bla", Qt::DisplayRole); - QCOMPARE(currentRoles, {}); + QCOMPARE(currentRoles, QVector<int>{}); QIcon icon; for (int r=0; r < m_model->rowCount(); ++r) { @@ -742,9 +742,9 @@ void tst_QStandardItemModel::data() m_model->setData(m_model->index(r,c), "initialitem", Qt::DisplayRole); QCOMPARE(currentRoles, QVector<int>({Qt::DisplayRole, Qt::EditRole})); m_model->setData(m_model->index(r,c), "tooltip", Qt::ToolTipRole); - QCOMPARE(currentRoles, {Qt::ToolTipRole}); + QCOMPARE(currentRoles, QVector<int>{Qt::ToolTipRole}); m_model->setData(m_model->index(r,c), icon, Qt::DecorationRole); - QCOMPARE(currentRoles, {Qt::DecorationRole}); + QCOMPARE(currentRoles, QVector<int>{Qt::DecorationRole}); } } @@ -761,7 +761,7 @@ void tst_QStandardItemModel::clearItemData() { currentRoles.clear(); QVERIFY(!m_model->clearItemData(QModelIndex())); - QCOMPARE(currentRoles, {}); + QCOMPARE(currentRoles, QVector<int>{}); const QModelIndex idx = m_model->index(0, 0); const QMap<int, QVariant> oldData = m_model->itemData(idx); m_model->setData(idx, QLatin1String("initialitem"), Qt::DisplayRole); @@ -773,7 +773,7 @@ void tst_QStandardItemModel::clearItemData() QCOMPARE(idx.data(Qt::ToolTipRole), QVariant()); QCOMPARE(idx.data(Qt::DisplayRole), QVariant()); QCOMPARE(idx.data(Qt::EditRole), QVariant()); - QCOMPARE(currentRoles, {}); + QCOMPARE(currentRoles, QVector<int>{}); m_model->setItemData(idx, oldData); currentRoles.clear(); } diff --git a/tests/auto/gui/kernel/noqteventloop/noqteventloop.pro b/tests/auto/gui/kernel/noqteventloop/noqteventloop.pro index 7e98704aea..293a6a8581 100644 --- a/tests/auto/gui/kernel/noqteventloop/noqteventloop.pro +++ b/tests/auto/gui/kernel/noqteventloop/noqteventloop.pro @@ -5,4 +5,4 @@ QT += core-private network gui-private testlib SOURCES += tst_noqteventloop.cpp -qtConfig(dynamicgl):win32:!winrt: LIBS += -luser32 +qtConfig(dynamicgl):win32:!winrt: QMAKE_USE += user32 diff --git a/tests/auto/gui/kernel/qguiapplication/tst_qguiapplication.cpp b/tests/auto/gui/kernel/qguiapplication/tst_qguiapplication.cpp index a304981cd1..09fec89de4 100644 --- a/tests/auto/gui/kernel/qguiapplication/tst_qguiapplication.cpp +++ b/tests/auto/gui/kernel/qguiapplication/tst_qguiapplication.cpp @@ -989,9 +989,13 @@ void tst_QGuiApplication::genericPluginsAndWindowSystemEvents() QCoreApplication::postEvent(&testReceiver, new QEvent(QEvent::User)); QCOMPARE(testReceiver.customEvents, 0); +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + QStaticPlugin testPluginInfo(qt_plugin_instance, qt_plugin_query_metadata); +#else QStaticPlugin testPluginInfo; testPluginInfo.instance = qt_plugin_instance; testPluginInfo.rawMetaData = qt_plugin_query_metadata; +#endif qRegisterStaticPluginFunction(testPluginInfo); int argc = 3; char *argv[] = { const_cast<char*>(QTest::currentAppName()), const_cast<char*>("-plugin"), const_cast<char*>("testplugin") }; diff --git a/tests/auto/gui/kernel/qkeyevent/tst_qkeyevent.cpp b/tests/auto/gui/kernel/qkeyevent/tst_qkeyevent.cpp index bad021c3b0..9a4c560a08 100644 --- a/tests/auto/gui/kernel/qkeyevent/tst_qkeyevent.cpp +++ b/tests/auto/gui/kernel/qkeyevent/tst_qkeyevent.cpp @@ -121,7 +121,7 @@ static QByteArray modifiersTestRowName(const QString &keySequence) if (uc > 32 && uc < 128) str << '"' << c << '"'; else - str << "U+" << hex << uc << dec; + str << "U+" << Qt::hex << uc << Qt::dec; if (i < size - 1) str << ','; } diff --git a/tests/auto/gui/kernel/qpalette/tst_qpalette.cpp b/tests/auto/gui/kernel/qpalette/tst_qpalette.cpp index 234793a7cf..6ce6422f48 100644 --- a/tests/auto/gui/kernel/qpalette/tst_qpalette.cpp +++ b/tests/auto/gui/kernel/qpalette/tst_qpalette.cpp @@ -141,7 +141,6 @@ void tst_QPalette::copySemantics() void tst_QPalette::moveSemantics() { -#ifdef Q_COMPILER_RVALUE_REFS QPalette src(Qt::red), dst; const QPalette control = src; QVERIFY(src != dst); @@ -163,9 +162,6 @@ void tst_QPalette::moveSemantics() QVERIFY(dst2.isCopyOf(dst)); QVERIFY(dst2.isCopyOf(control)); // check moved-from 'src' can still be destroyed (doesn't crash) -#else - QSKIP("Compiler doesn't support C++11 move semantics"); -#endif } void tst_QPalette::setBrush() diff --git a/tests/auto/gui/kernel/qwindow/BLACKLIST b/tests/auto/gui/kernel/qwindow/BLACKLIST index caf39742f6..1820499a53 100644 --- a/tests/auto/gui/kernel/qwindow/BLACKLIST +++ b/tests/auto/gui/kernel/qwindow/BLACKLIST @@ -17,6 +17,8 @@ android [modalWindowEnterEventOnHide_QTBUG35109] ubuntu-16.04 osx ci +[spuriousMouseMove] +windows ci # QTBUG-69162 android [modalDialogClosingOneOfTwoModal] diff --git a/tests/auto/gui/kernel/qwindow/qwindow.pro b/tests/auto/gui/kernel/qwindow/qwindow.pro index 844b3e8507..e7931ca773 100644 --- a/tests/auto/gui/kernel/qwindow/qwindow.pro +++ b/tests/auto/gui/kernel/qwindow/qwindow.pro @@ -5,4 +5,4 @@ QT += core-private gui-private testlib SOURCES += tst_qwindow.cpp -qtConfig(dynamicgl):win32:!winrt: LIBS += -luser32 +qtConfig(dynamicgl):win32:!winrt: QMAKE_USE += user32 diff --git a/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp b/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp index 9415908383..4f26950192 100644 --- a/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp +++ b/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp @@ -45,10 +45,6 @@ # include <QtCore/qt_windows.h> #endif -// For QSignalSpy slot connections. -Q_DECLARE_METATYPE(Qt::ScreenOrientation) -Q_DECLARE_METATYPE(QWindow::Visibility) - static bool isPlatformWinRT() { static const bool isWinRT = !QGuiApplication::platformName().compare(QLatin1String("winrt"), Qt::CaseInsensitive); @@ -185,7 +181,7 @@ void tst_QWindow::setParent() QVERIFY2(c.children().contains(&d), "Parent should have child in list of children"); a.create(); - b.setParent(0); + b.setParent(nullptr); QVERIFY2(!b.handle(), "Making window top level shouild not automatically create it"); QWindow e; @@ -228,7 +224,7 @@ void tst_QWindow::setVisible() f.setVisible(true); QVERIFY(!f.handle()); QVERIFY(!e.handle()); - f.setParent(0); + f.setParent(nullptr); QVERIFY2(f.handle(), "Making a visible but not created child window top level should create it"); QVERIFY(QTest::qWaitForWindowExposed(&f)); @@ -304,7 +300,7 @@ public: m_framePositionsOnMove.clear(); } - bool event(QEvent *event) + bool event(QEvent *event) override { m_received[event->type()]++; m_order << event->type(); @@ -323,6 +319,7 @@ public: case QEvent::WindowStateChange: lastReceivedWindowState = windowState(); + break; default: break; @@ -363,7 +360,7 @@ private: class ColoredWindow : public QRasterWindow { public: - explicit ColoredWindow(const QColor &color, QWindow *parent = 0) : QRasterWindow(parent), m_color(color) {} + explicit ColoredWindow(const QColor &color, QWindow *parent = nullptr) : QRasterWindow(parent), m_color(color) {} void paintEvent(QPaintEvent *) override { QPainter p(this); @@ -381,6 +378,7 @@ void tst_QWindow::eventOrderOnShow() QRect geometry(m_availableTopLeft + QPoint(80, 80), m_testWindowSize); Window window; + window.setTitle(QLatin1String(QTest::currentTestFunction())); window.setGeometry(geometry); window.show(); QCoreApplication::processEvents(); @@ -440,12 +438,12 @@ void tst_QWindow::exposeEventOnShrink_QTBUG54040() void tst_QWindow::positioning_data() { - QTest::addColumn<int>("windowflags"); + QTest::addColumn<Qt::WindowFlags>("windowflags"); - QTest::newRow("default") << int(Qt::Window | Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint | Qt::WindowFullscreenButtonHint); + QTest::newRow("default") << (Qt::Window | Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint | Qt::WindowFullscreenButtonHint); -#ifdef Q_OS_OSX - QTest::newRow("fake") << int(Qt::Window | Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint); +#ifdef Q_OS_MACOS + QTest::newRow("fake") << (Qt::Window | Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint); #endif } @@ -500,8 +498,8 @@ void tst_QWindow::positioning() // events, so set the width to suitably large value to avoid those. const QRect geometry(m_availableTopLeft + QPoint(80, 80), m_testWindowSize); - QFETCH(int, windowflags); - Window window((Qt::WindowFlags)windowflags); + QFETCH(Qt::WindowFlags, windowflags); + Window window(windowflags); window.setGeometry(QRect(m_availableTopLeft + QPoint(20, 20), m_testWindowSize)); window.setFramePosition(m_availableTopLeft + QPoint(40, 40)); // Move window around before show, size must not change. QCOMPARE(window.geometry().size(), m_testWindowSize); @@ -628,14 +626,12 @@ void tst_QWindow::childWindowPositioning() QFETCH(bool, showInsteadOfCreate); - QWindow* windows[] = { &topLevelWindowFirst, &childWindowAfter, &childWindowFirst, &topLevelWindowAfter, 0 }; - for (int i = 0; windows[i]; ++i) { - QWindow *window = windows[i]; - if (showInsteadOfCreate) { + QWindow *windows[] = {&topLevelWindowFirst, &childWindowAfter, &childWindowFirst, &topLevelWindowAfter}; + for (QWindow *window : windows) { + if (showInsteadOfCreate) window->showNormal(); - } else { + else window->create(); - } } if (showInsteadOfCreate) { @@ -712,7 +708,7 @@ void tst_QWindow::stateChange() // explicitly use non-fullscreen show. show() can be fullscreen on some platforms window.showNormal(); QVERIFY(QTest::qWaitForWindowExposed(&window)); - foreach (Qt::WindowState state, stateSequence) { + for (Qt::WindowState state : qAsConst(stateSequence)) { window.setWindowState(state); QCoreApplication::processEvents(); } @@ -726,15 +722,9 @@ class PlatformWindowFilter : public QObject { Q_OBJECT public: - PlatformWindowFilter(QObject *parent = 0) - : QObject(parent) - , m_window(nullptr) - , m_alwaysExisted(true) - {} - - void setWindow(Window *window) { m_window = window; } + explicit PlatformWindowFilter(Window *window) : m_window(window) {} - bool eventFilter(QObject *o, QEvent *e) + bool eventFilter(QObject *o, QEvent *e) override { // Check that the platform surface events are delivered synchronously. // If they are, the native platform surface should always exist when we @@ -749,7 +739,7 @@ public: private: Window *m_window; - bool m_alwaysExisted; + bool m_alwaysExisted = true; }; void tst_QWindow::platformSurface() @@ -757,8 +747,7 @@ void tst_QWindow::platformSurface() QRect geometry(m_availableTopLeft + QPoint(80, 80), m_testWindowSize); Window window; - PlatformWindowFilter filter; - filter.setWindow(&window); + PlatformWindowFilter filter(&window); window.installEventFilter(&filter); window.setGeometry(geometry); @@ -784,6 +773,7 @@ void tst_QWindow::isExposed() QRect geometry(m_availableTopLeft + QPoint(80, 80), m_testWindowSize); Window window; + window.setTitle(QLatin1String(QTest::currentTestFunction())); window.setGeometry(geometry); QCOMPARE(window.geometry(), geometry); window.show(); @@ -818,6 +808,7 @@ void tst_QWindow::isActive() QSKIP("QWindow::requestActivate() is not supported."); Window window; + window.setTitle(QLatin1String(QTest::currentTestFunction())); // Some platforms enforce minimum widths for windows, which can cause extra resize // events, so set the width to suitably large value to avoid those. window.setGeometry(QRect(m_availableTopLeft + QPoint(80, 80), m_testWindowSize)); @@ -916,13 +907,16 @@ void tst_QWindow::isActive() class InputTestWindow : public ColoredWindow { public: - void keyPressEvent(QKeyEvent *event) { + void keyPressEvent(QKeyEvent *event) override + { keyPressCode = event->key(); } - void keyReleaseEvent(QKeyEvent *event) { + void keyReleaseEvent(QKeyEvent *event) override + { keyReleaseCode = event->key(); } - void mousePressEvent(QMouseEvent *event) { + void mousePressEvent(QMouseEvent *event) override + { if (ignoreMouse) { event->ignore(); } else { @@ -935,7 +929,8 @@ public: QCoreApplication::processEvents(); } } - void mouseReleaseEvent(QMouseEvent *event) { + void mouseReleaseEvent(QMouseEvent *event) override + { if (ignoreMouse) { event->ignore(); } else { @@ -944,7 +939,8 @@ public: mouseReleaseButton = event->button(); } } - void mouseMoveEvent(QMouseEvent *event) { + void mouseMoveEvent(QMouseEvent *event) override + { buttonStateInGeneratedMove = event->buttons(); if (ignoreMouse) { event->ignore(); @@ -954,7 +950,8 @@ public: mouseMoveScreenPos = event->screenPos(); } } - void mouseDoubleClickEvent(QMouseEvent *event) { + void mouseDoubleClickEvent(QMouseEvent *event) override + { if (ignoreMouse) { event->ignore(); } else { @@ -962,7 +959,8 @@ public: mouseSequenceSignature += 'd'; } } - void touchEvent(QTouchEvent *event) { + void touchEvent(QTouchEvent *event) override + { if (ignoreTouch) { event->ignore(); return; @@ -987,7 +985,8 @@ public: } } } - bool event(QEvent *e) { + bool event(QEvent *e) override + { switch (e->type()) { case QEvent::Enter: ++enterEventCount; @@ -998,37 +997,31 @@ public: default: break; } - return QWindow::event(e); + return ColoredWindow::event(e); } - void resetCounters() { + void resetCounters() + { mousePressedCount = mouseReleasedCount = mouseMovedCount = mouseDoubleClickedCount = 0; - mouseSequenceSignature = QString(); + mouseSequenceSignature.clear(); touchPressedCount = touchReleasedCount = touchMovedCount = 0; enterEventCount = leaveEventCount = 0; } explicit InputTestWindow(const QColor &color = Qt::white, QWindow *parent = nullptr) - : ColoredWindow(color, parent) - { - keyPressCode = keyReleaseCode = 0; - mousePressButton = mouseReleaseButton = mouseMoveButton = 0; - ignoreMouse = ignoreTouch = false; - spinLoopWhenPressed = false; - resetCounters(); - } + : ColoredWindow(color, parent) {} - int keyPressCode, keyReleaseCode; - int mousePressButton, mouseReleaseButton, mouseMoveButton; - int mousePressedCount, mouseReleasedCount, mouseMovedCount, mouseDoubleClickedCount; + int keyPressCode = 0, keyReleaseCode = 0; + int mousePressButton = 0, mouseReleaseButton = 0, mouseMoveButton = 0; + int mousePressedCount = 0, mouseReleasedCount = 0, mouseMovedCount = 0, mouseDoubleClickedCount = 0; QString mouseSequenceSignature; QPointF mousePressScreenPos, mouseMoveScreenPos, mousePressLocalPos; - int touchPressedCount, touchReleasedCount, touchMovedCount; - QEvent::Type touchEventType; - int enterEventCount, leaveEventCount; + int touchPressedCount = 0, touchReleasedCount = 0, touchMovedCount = 0; + QEvent::Type touchEventType = QEvent::None; + int enterEventCount = 0, leaveEventCount = 0; - bool ignoreMouse, ignoreTouch; + bool ignoreMouse = false, ignoreTouch = false; - bool spinLoopWhenPressed; + bool spinLoopWhenPressed = false; Qt::MouseButtons buttonStateInGeneratedMove; }; @@ -1073,15 +1066,15 @@ void tst_QWindow::testInputEvents() window.mousePressButton = window.mouseReleaseButton = 0; const QPointF nonWindowGlobal(window.geometry().topRight() + QPoint(200, 50)); // not inside the window const QPointF deviceNonWindowGlobal = QHighDpi::toNativePixels(nonWindowGlobal, window.screen()); - QWindowSystemInterface::handleMouseEvent(0, deviceNonWindowGlobal, deviceNonWindowGlobal, Qt::LeftButton); - QWindowSystemInterface::handleMouseEvent(0, deviceNonWindowGlobal, deviceNonWindowGlobal, Qt::NoButton); + QWindowSystemInterface::handleMouseEvent(nullptr, deviceNonWindowGlobal, deviceNonWindowGlobal, Qt::LeftButton); + QWindowSystemInterface::handleMouseEvent(nullptr, deviceNonWindowGlobal, deviceNonWindowGlobal, Qt::NoButton); QCoreApplication::processEvents(); QCOMPARE(window.mousePressButton, 0); QCOMPARE(window.mouseReleaseButton, 0); const QPointF windowGlobal = window.mapToGlobal(local.toPoint()); const QPointF deviceWindowGlobal = QHighDpi::toNativePixels(windowGlobal, window.screen()); - QWindowSystemInterface::handleMouseEvent(0, deviceWindowGlobal, deviceWindowGlobal, Qt::LeftButton); - QWindowSystemInterface::handleMouseEvent(0, deviceWindowGlobal, deviceWindowGlobal, Qt::NoButton); + QWindowSystemInterface::handleMouseEvent(nullptr, deviceWindowGlobal, deviceWindowGlobal, Qt::LeftButton); + QWindowSystemInterface::handleMouseEvent(nullptr, deviceWindowGlobal, deviceWindowGlobal, Qt::NoButton); QCoreApplication::processEvents(); QCOMPARE(window.mousePressButton, int(Qt::LeftButton)); QCOMPARE(window.mouseReleaseButton, int(Qt::LeftButton)); @@ -1092,6 +1085,7 @@ void tst_QWindow::testInputEvents() void tst_QWindow::touchToMouseTranslation() { InputTestWindow window; + window.setTitle(QLatin1String(QTest::currentTestFunction())); window.ignoreTouch = true; window.setGeometry(QRect(m_availableTopLeft + QPoint(80, 80), m_testWindowSize)); window.show(); @@ -1145,7 +1139,7 @@ void tst_QWindow::touchToMouseTranslation() QTRY_COMPARE(window.mousePressButton, 0); QTRY_COMPARE(window.mouseReleaseButton, 0); - qApp->setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, false); + QCoreApplication::setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, false); window.ignoreTouch = true; points[0].state = Qt::TouchPointPressed; @@ -1156,7 +1150,7 @@ void tst_QWindow::touchToMouseTranslation() QWindowSystemInterface::handleTouchEvent(&window, touchDevice, points); QCoreApplication::processEvents(); - qApp->setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, true); + QCoreApplication::setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, true); // mouse event synthesizing disabled QTRY_COMPARE(window.mousePressButton, 0); @@ -1166,6 +1160,7 @@ void tst_QWindow::touchToMouseTranslation() void tst_QWindow::touchToMouseTranslationForDevices() { InputTestWindow window; + window.setTitle(QLatin1String(QTest::currentTestFunction())); window.ignoreTouch = true; window.setGeometry(QRect(m_availableTopLeft + QPoint(80, 80), m_testWindowSize)); window.show(); @@ -1194,9 +1189,10 @@ void tst_QWindow::touchToMouseTranslationForDevices() void tst_QWindow::mouseToTouchTranslation() { - qApp->setAttribute(Qt::AA_SynthesizeTouchForUnhandledMouseEvents, true); + QCoreApplication::setAttribute(Qt::AA_SynthesizeTouchForUnhandledMouseEvents, true); InputTestWindow window; + window.setTitle(QLatin1String(QTest::currentTestFunction())); window.ignoreMouse = true; window.setGeometry(QRect(m_availableTopLeft + QPoint(80, 80), m_testWindowSize)); window.show(); @@ -1206,12 +1202,12 @@ void tst_QWindow::mouseToTouchTranslation() QWindowSystemInterface::handleMouseEvent(&window, QPoint(10, 10), window.mapToGlobal(QPoint(10, 10)), Qt::NoButton); QCoreApplication::processEvents(); - qApp->setAttribute(Qt::AA_SynthesizeTouchForUnhandledMouseEvents, false); + QCoreApplication::setAttribute(Qt::AA_SynthesizeTouchForUnhandledMouseEvents, false); QTRY_COMPARE(window.touchPressedCount, 1); QTRY_COMPARE(window.touchReleasedCount, 1); - qApp->setAttribute(Qt::AA_SynthesizeTouchForUnhandledMouseEvents, true); + QCoreApplication::setAttribute(Qt::AA_SynthesizeTouchForUnhandledMouseEvents, true); window.ignoreMouse = false; @@ -1219,7 +1215,7 @@ void tst_QWindow::mouseToTouchTranslation() QWindowSystemInterface::handleMouseEvent(&window, QPoint(10, 10), window.mapToGlobal(QPoint(10, 10)), Qt::NoButton); QCoreApplication::processEvents(); - qApp->setAttribute(Qt::AA_SynthesizeTouchForUnhandledMouseEvents, false); + QCoreApplication::setAttribute(Qt::AA_SynthesizeTouchForUnhandledMouseEvents, false); // no new touch events should be generated since the input window handles the mouse events QTRY_COMPARE(window.touchPressedCount, 1); @@ -1241,10 +1237,12 @@ void tst_QWindow::mouseToTouchTranslation() void tst_QWindow::mouseToTouchLoop() { // make sure there's no infinite loop when synthesizing both ways - qApp->setAttribute(Qt::AA_SynthesizeTouchForUnhandledMouseEvents, true); - qApp->setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, true); + QCoreApplication::setAttribute(Qt::AA_SynthesizeTouchForUnhandledMouseEvents, true); + QCoreApplication::setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, true); InputTestWindow window; + window.setTitle(QLatin1String(QTest::currentTestFunction())); + window.ignoreMouse = true; window.ignoreTouch = true; window.setGeometry(QRect(m_availableTopLeft + QPoint(80, 80), m_testWindowSize)); @@ -1255,13 +1253,14 @@ void tst_QWindow::mouseToTouchLoop() QWindowSystemInterface::handleMouseEvent(&window, QPoint(10, 10), window.mapToGlobal(QPoint(10, 10)), Qt::NoButton); QCoreApplication::processEvents(); - qApp->setAttribute(Qt::AA_SynthesizeTouchForUnhandledMouseEvents, false); - qApp->setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, true); + QCoreApplication::setAttribute(Qt::AA_SynthesizeTouchForUnhandledMouseEvents, false); + QCoreApplication::setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, true); } void tst_QWindow::touchCancel() { InputTestWindow window; + window.setTitle(QLatin1String(QTest::currentTestFunction())); window.setGeometry(QRect(m_availableTopLeft + QPoint(80, 80), m_testWindowSize)); window.show(); QVERIFY(QTest::qWaitForWindowExposed(&window)); @@ -1321,6 +1320,7 @@ void tst_QWindow::touchCancel() void tst_QWindow::touchCancelWithTouchToMouse() { InputTestWindow window; + window.setTitle(QLatin1String(QTest::currentTestFunction())); window.ignoreTouch = true; window.setGeometry(QRect(m_availableTopLeft + QPoint(80, 80), m_testWindowSize)); window.show(); @@ -1343,7 +1343,7 @@ void tst_QWindow::touchCancelWithTouchToMouse() // Cancel the touch. Should result in a mouse release for windows that have // have an active touch-to-mouse sequence. - QWindowSystemInterface::handleTouchCancelEvent(0, touchDevice); + QWindowSystemInterface::handleTouchCancelEvent(nullptr, touchDevice); QCoreApplication::processEvents(); QTRY_COMPARE(window.mouseReleaseButton, int(Qt::LeftButton)); @@ -1358,7 +1358,7 @@ void tst_QWindow::touchCancelWithTouchToMouse() QTRY_COMPARE(window.mousePressButton, 0); // Cancel the touch. It should not result in a mouse release with this window. - QWindowSystemInterface::handleTouchCancelEvent(0, touchDevice); + QWindowSystemInterface::handleTouchCancelEvent(nullptr, touchDevice); QCoreApplication::processEvents(); QTRY_COMPARE(window.mouseReleaseButton, 0); } @@ -1369,6 +1369,7 @@ void tst_QWindow::touchInterruptedByPopup() QSKIP("Wayland: This test crashes with xdg-shell unstable v6"); InputTestWindow window; + window.setTitle(QLatin1String(QTest::currentTestFunction())); window.setGeometry(QRect(m_availableTopLeft + QPoint(80, 80), m_testWindowSize)); window.show(); QVERIFY(QTest::qWaitForWindowExposed(&window)); @@ -1489,6 +1490,7 @@ void tst_QWindow::sizes() void tst_QWindow::close() { QWindow a; + a.setTitle(QLatin1String(QTest::currentTestFunction())); QWindow b; QWindow c(&a); @@ -1506,8 +1508,9 @@ void tst_QWindow::activateAndClose() if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation)) QSKIP("QWindow::requestActivate() is not supported."); - for (int i = 0; i < 10; ++i) { + for (int i = 0; i < 10; ++i) { QWindow window; + window.setTitle(QLatin1String(QTest::currentTestFunction()) + QString::number(i)); #if defined(Q_OS_QNX) window.setSurfaceType(QSurface::OpenGLSurface); #endif @@ -1525,15 +1528,16 @@ void tst_QWindow::activateAndClose() #endif window.requestActivate(); QVERIFY(QTest::qWaitForWindowActive(&window)); - QCOMPARE(qGuiApp->focusWindow(), &window); + QCOMPARE(QGuiApplication::focusWindow(), &window); } } void tst_QWindow::mouseEventSequence() { - int doubleClickInterval = qGuiApp->styleHints()->mouseDoubleClickInterval(); + const auto doubleClickInterval = ulong(QGuiApplication::styleHints()->mouseDoubleClickInterval()); InputTestWindow window; + window.setTitle(QLatin1String(QTest::currentTestFunction())); window.setGeometry(QRect(m_availableTopLeft + QPoint(80, 80), m_testWindowSize)); window.show(); QVERIFY(QTest::qWaitForWindowExposed(&window)); @@ -1655,6 +1659,7 @@ void tst_QWindow::windowModality() void tst_QWindow::inputReentrancy() { InputTestWindow window; + window.setTitle(QLatin1String(QTest::currentTestFunction())); window.spinLoopWhenPressed = true; window.setGeometry(QRect(m_availableTopLeft + QPoint(80, 80), m_testWindowSize)); @@ -1700,17 +1705,20 @@ void tst_QWindow::inputReentrancy() class TabletTestWindow : public QWindow { public: - TabletTestWindow() : eventType(QEvent::None) { } - void tabletEvent(QTabletEvent *ev) { + void tabletEvent(QTabletEvent *ev) override + { eventType = ev->type(); eventGlobal = ev->globalPosF(); eventLocal = ev->posF(); eventDevice = ev->device(); } - QEvent::Type eventType; + + QEvent::Type eventType = QEvent::None; QPointF eventGlobal, eventLocal; - int eventDevice; - bool eventFilter(QObject *obj, QEvent *ev) { + int eventDevice = -1; + + bool eventFilter(QObject *obj, QEvent *ev) override + { if (ev->type() == QEvent::TabletEnterProximity || ev->type() == QEvent::TabletLeaveProximity) { eventType = ev->type(); @@ -1758,6 +1766,7 @@ void tst_QWindow::tabletEvents() void tst_QWindow::windowModality_QTBUG27039() { QWindow parent; + parent.setTitle(QLatin1String(QTest::currentTestFunction())); parent.setGeometry(QRect(m_availableTopLeft + QPoint(10, 10), m_testWindowSize)); parent.show(); @@ -1868,6 +1877,7 @@ void tst_QWindow::initialSize() QSize defaultSize(0,0); { Window w; + w.setTitle(QLatin1String(QTest::currentTestFunction())); w.showNormal(); QTRY_VERIFY(w.width() > 0); QTRY_VERIFY(w.height() > 0); @@ -1875,6 +1885,7 @@ void tst_QWindow::initialSize() } { Window w; + w.setTitle(QLatin1String(QTest::currentTestFunction())); w.setWidth(m_testWindowSize.width()); w.showNormal(); if (isPlatformWinRT()) @@ -1884,6 +1895,7 @@ void tst_QWindow::initialSize() } { Window w; + w.setTitle(QLatin1String(QTest::currentTestFunction())); const QSize testSize(m_testWindowSize.width(), 42); w.resize(testSize); w.showNormal(); @@ -1910,6 +1922,7 @@ void tst_QWindow::modalDialog() QSKIP("Test fails due to QTBUG-61965, and is slow due to QTBUG-61964"); QWindow normalWindow; + normalWindow.setTitle(QLatin1String(QTest::currentTestFunction())); normalWindow.setFramePosition(m_availableTopLeft + QPoint(80, 80)); normalWindow.resize(m_testWindowSize); normalWindow.show(); @@ -1945,6 +1958,7 @@ void tst_QWindow::modalDialogClosingOneOfTwoModal() QSKIP("QWindow::requestActivate() is not supported."); QWindow normalWindow; + normalWindow.setTitle(QLatin1String(QTest::currentTestFunction())); normalWindow.setFramePosition(m_availableTopLeft + QPoint(80, 80)); normalWindow.resize(m_testWindowSize); normalWindow.show(); @@ -1992,6 +2006,7 @@ void tst_QWindow::modalWithChildWindow() QSKIP("QWindow::requestActivate() is not supported."); QWindow normalWindow; + normalWindow.setTitle(QLatin1String(QTest::currentTestFunction())); normalWindow.setFramePosition(m_availableTopLeft + QPoint(80, 80)); normalWindow.resize(m_testWindowSize); normalWindow.show(); @@ -2028,6 +2043,7 @@ void tst_QWindow::modalWindowModallity() QSKIP("QWindow::requestActivate() is not supported."); QWindow normal_window; + normal_window.setTitle(QLatin1String(QTest::currentTestFunction())); normal_window.setFramePosition(m_availableTopLeft + QPoint(80, 80)); normal_window.resize(m_testWindowSize); normal_window.show(); @@ -2058,6 +2074,7 @@ void tst_QWindow::modalWindowModallity() void tst_QWindow::modalWindowPosition() { QWindow window; + window.setTitle(QLatin1String(QTest::currentTestFunction())); window.setGeometry(QRect(m_availableTopLeft + QPoint(100, 100), m_testWindowSize)); // Allow for any potential resizing due to constraints QRect origGeo = window.geometry(); @@ -2341,6 +2358,7 @@ void tst_QWindow::requestUpdate() QRect geometry(m_availableTopLeft + QPoint(80, 80), m_testWindowSize); Window window; + window.setTitle(QLatin1String(QTest::currentTestFunction())); window.setGeometry(geometry); window.show(); QCoreApplication::processEvents(); @@ -2370,10 +2388,10 @@ void tst_QWindow::flags() class EventWindow : public QWindow { public: - EventWindow() : QWindow(), gotBlocked(false) {} - bool gotBlocked; + bool gotBlocked = false; + protected: - bool event(QEvent *e) + bool event(QEvent *e) override { if (e->type() == QEvent::WindowBlocked) gotBlocked = true; @@ -2384,6 +2402,7 @@ protected: void tst_QWindow::testBlockingWindowShownAfterModalDialog() { EventWindow normalWindow; + normalWindow.setTitle(QLatin1String(QTest::currentTestFunction())); normalWindow.setFramePosition(m_availableTopLeft + QPoint(80, 80)); normalWindow.resize(m_testWindowSize); normalWindow.show(); @@ -2411,6 +2430,7 @@ void tst_QWindow::testBlockingWindowShownAfterModalDialog() void tst_QWindow::generatedMouseMove() { InputTestWindow w; + w.setTitle(QLatin1String(QTest::currentTestFunction())); w.setGeometry(QRect(m_availableTopLeft + QPoint(100, 100), m_testWindowSize)); w.setFlags(w.flags() | Qt::FramelessWindowHint); // ### FIXME: QTBUG-63542 w.show(); @@ -2422,34 +2442,34 @@ void tst_QWindow::generatedMouseMove() QTest::mouseMove(&w, point); QVERIFY(w.mouseMovedCount == 1); // A press event that does not change position should not generate mouse move - QTest::mousePress(&w, Qt::LeftButton, 0, point); - QTest::mousePress(&w, Qt::RightButton, 0, point); + QTest::mousePress(&w, Qt::LeftButton, Qt::KeyboardModifiers(), point); + QTest::mousePress(&w, Qt::RightButton, Qt::KeyboardModifiers(), point); QVERIFY(w.mouseMovedCount == 1); // Verify that a move event is generated for a mouse release event that changes position point += step; - QTest::mouseRelease(&w, Qt::LeftButton, 0, point); + QTest::mouseRelease(&w, Qt::LeftButton,Qt::KeyboardModifiers(), point); QVERIFY(w.mouseMovedCount == 2); QVERIFY(w.buttonStateInGeneratedMove == (Qt::LeftButton | Qt::RightButton)); point += step; - QTest::mouseRelease(&w, Qt::RightButton, 0, point); + QTest::mouseRelease(&w, Qt::RightButton, Qt::KeyboardModifiers(), point); QVERIFY(w.mouseMovedCount == 3); QVERIFY(w.buttonStateInGeneratedMove == Qt::RightButton); // Verify that a move event is generated for a mouse press event that changes position point += step; - QTest::mousePress(&w, Qt::LeftButton, 0, point); + QTest::mousePress(&w, Qt::LeftButton, Qt::KeyboardModifiers(), point); QVERIFY(w.mouseMovedCount == 4); QVERIFY(w.buttonStateInGeneratedMove == Qt::NoButton); point += step; - QTest::mousePress(&w, Qt::RightButton, 0, point); + QTest::mousePress(&w, Qt::RightButton, Qt::KeyboardModifiers(), point); QVERIFY(w.mouseMovedCount == 5); QVERIFY(w.buttonStateInGeneratedMove == Qt::LeftButton); // A release event that does not change position should not generate mouse move - QTest::mouseRelease(&w, Qt::RightButton, 0, point); - QTest::mouseRelease(&w, Qt::LeftButton, 0, point); + QTest::mouseRelease(&w, Qt::RightButton, Qt::KeyboardModifiers(), point); + QTest::mouseRelease(&w, Qt::LeftButton, Qt::KeyboardModifiers(), point); QVERIFY(w.mouseMovedCount == 5); } @@ -2458,6 +2478,7 @@ void tst_QWindow::keepPendingUpdateRequests() QRect geometry(m_availableTopLeft + QPoint(80, 80), m_testWindowSize); Window window; + window.setTitle(QLatin1String(QTest::currentTestFunction())); window.setGeometry(geometry); window.show(); QCoreApplication::processEvents(); diff --git a/tests/auto/gui/painting/qcolor/tst_qcolor.cpp b/tests/auto/gui/painting/qcolor/tst_qcolor.cpp index 4d92bdd382..90a216e14a 100644 --- a/tests/auto/gui/painting/qcolor/tst_qcolor.cpp +++ b/tests/auto/gui/painting/qcolor/tst_qcolor.cpp @@ -94,8 +94,8 @@ private slots: void convertTo(); - void light(); - void dark(); + void lighter(); + void darker(); void specConstructor_data(); void specConstructor(); @@ -1419,17 +1419,17 @@ void tst_QColor::convertTo() QCOMPARE(invalid.spec(), QColor::Invalid); } -void tst_QColor::light() +void tst_QColor::lighter() { QColor gray(Qt::gray); - QColor lighter = gray.light(); + QColor lighter = gray.lighter(); QVERIFY(lighter.value() > gray.value()); } -void tst_QColor::dark() +void tst_QColor::darker() { QColor gray(Qt::gray); - QColor darker = gray.dark(); + QColor darker = gray.darker(); QVERIFY(darker.value() < gray.value()); } diff --git a/tests/auto/gui/painting/qcolorspace/tst_qcolorspace.cpp b/tests/auto/gui/painting/qcolorspace/tst_qcolorspace.cpp index 35bca58854..7a88eb18b2 100644 --- a/tests/auto/gui/painting/qcolorspace/tst_qcolorspace.cpp +++ b/tests/auto/gui/painting/qcolorspace/tst_qcolorspace.cpp @@ -33,6 +33,8 @@ #include <qimage.h> #include <qimagereader.h> +#include <private/qcolorspace_p.h> + Q_DECLARE_METATYPE(QColorSpace::ColorSpaceId) Q_DECLARE_METATYPE(QColorSpace::Gamut) Q_DECLARE_METATYPE(QColorSpace::TransferFunction) @@ -59,6 +61,10 @@ private slots: void loadImage(); void gamut(); + void primariesXyz(); + void primaries2_data(); + void primaries2(); + void invalidPrimaries(); }; tst_QColorSpace::tst_QColorSpace() @@ -289,5 +295,67 @@ void tst_QColorSpace::gamut() QVERIFY(tgreen.blueF() > 0.2); } +void tst_QColorSpace::primariesXyz() +{ + QColorSpace sRgb = QColorSpace::SRgb; + QColorSpace adobeRgb = QColorSpace::AdobeRgb; + QColorSpace displayP3 = QColorSpace::DisplayP3; + QColorSpace proPhotoRgb = QColorSpace::ProPhotoRgb; + QColorSpace bt2020 = QColorSpace::Bt2020; + + // Check if our calculated matrices, match the precalculated ones. + QCOMPARE(sRgb.d_func()->toXyz, QColorMatrix::toXyzFromSRgb()); + QCOMPARE(adobeRgb.d_func()->toXyz, QColorMatrix::toXyzFromAdobeRgb()); + QCOMPARE(displayP3.d_func()->toXyz, QColorMatrix::toXyzFromDciP3D65()); + QCOMPARE(proPhotoRgb.d_func()->toXyz, QColorMatrix::toXyzFromProPhotoRgb()); + QCOMPARE(bt2020.d_func()->toXyz, QColorMatrix::toXyzFromBt2020()); +} + +void tst_QColorSpace::primaries2_data() +{ + QTest::addColumn<QColorSpace::Gamut>("gamut"); + + QTest::newRow("sRGB") << QColorSpace::Gamut::SRgb; + QTest::newRow("DCI-P3 (D65)") << QColorSpace::Gamut::DciP3D65; + QTest::newRow("Adobe RGB (1998)") << QColorSpace::Gamut::AdobeRgb; + QTest::newRow("ProPhoto RGB") << QColorSpace::Gamut::ProPhotoRgb; + QTest::newRow("BT.2020") << QColorSpace::Gamut::Bt2020; +} + +void tst_QColorSpace::primaries2() +{ + QFETCH(QColorSpace::Gamut, gamut); + QColorSpacePrimaries primaries(gamut); + + QColorSpace original(gamut, QColorSpace::TransferFunction::Linear); + QColorSpace custom1(primaries.whitePoint, primaries.redPoint, + primaries.greenPoint, primaries.bluePoint, QColorSpace::TransferFunction::Linear); + QCOMPARE(original, custom1); + + // A custom color swizzled color-space: + QColorSpace custom2(primaries.whitePoint, primaries.bluePoint, + primaries.greenPoint, primaries.redPoint, QColorSpace::TransferFunction::Linear); + + QVERIFY(custom1 != custom2); + QColor color1(255, 127, 63); + QColor color2 = custom1.transformationToColorSpace(custom2).map(color1); + QCOMPARE(color2.red(), color1.blue()); + QCOMPARE(color2.green(), color1.green()); + QCOMPARE(color2.blue(), color1.red()); + QCOMPARE(color2.alpha(), color1.alpha()); + QColor color3 = custom2.transformationToColorSpace(custom1).map(color2); + QCOMPARE(color3.red(), color1.red()); + QCOMPARE(color3.green(), color1.green()); + QCOMPARE(color3.blue(), color1.blue()); + QCOMPARE(color3.alpha(), color1.alpha()); +} + +void tst_QColorSpace::invalidPrimaries() +{ + QColorSpace custom(QPointF(), QPointF(), QPointF(), QPointF(), QColorSpace::TransferFunction::Linear); + QVERIFY(!custom.isValid()); + QCOMPARE(custom.colorSpaceId(), QColorSpace::Undefined); +} + QTEST_MAIN(tst_QColorSpace) #include "tst_qcolorspace.moc" diff --git a/tests/auto/gui/painting/qpainter/tst_qpainter.cpp b/tests/auto/gui/painting/qpainter/tst_qpainter.cpp index cec164b8b2..2b53169a45 100644 --- a/tests/auto/gui/painting/qpainter/tst_qpainter.cpp +++ b/tests/auto/gui/painting/qpainter/tst_qpainter.cpp @@ -370,10 +370,10 @@ void tst_QPainter::getSetCheck() // bool QPainter::matrixEnabled() // void QPainter::setMatrixEnabled(bool) - obj1.setMatrixEnabled(false); - QCOMPARE(false, obj1.matrixEnabled()); - obj1.setMatrixEnabled(true); - QCOMPARE(true, obj1.matrixEnabled()); + obj1.setWorldMatrixEnabled(false); + QCOMPARE(false, obj1.worldMatrixEnabled()); + obj1.setWorldMatrixEnabled(true); + QCOMPARE(true, obj1.worldMatrixEnabled()); // bool QPainter::viewTransformEnabled() // void QPainter::setViewTransformEnabled(bool) @@ -699,7 +699,7 @@ void tst_QPainter::initFrom() QCOMPARE(p.font(), font); QCOMPARE(p.pen().color(), pal.color(QPalette::Foreground)); - QCOMPARE(p.background(), pal.background()); + QCOMPARE(p.background(), pal.window()); delete widget; } @@ -3197,7 +3197,7 @@ void tst_QPainter::largeImagePainting() p.translate(4, 0); } - p.resetMatrix(); + p.resetTransform(); for (int i = 4; i < img.height(); i += 4) { p.translate(0, 4); diff --git a/tests/auto/gui/painting/qpdfwriter/tst_qpdfwriter.cpp b/tests/auto/gui/painting/qpdfwriter/tst_qpdfwriter.cpp index c1a8f7f0de..9e9b0db366 100644 --- a/tests/auto/gui/painting/qpdfwriter/tst_qpdfwriter.cpp +++ b/tests/auto/gui/painting/qpdfwriter/tst_qpdfwriter.cpp @@ -154,12 +154,7 @@ void tst_QPdfWriter::testPageMetrics() if (setMargins) { // Setup the given margins - QPdfWriter::Margins margins; - margins.left = leftMMf; - margins.right = rightMMf; - margins.top = topMMf; - margins.bottom = bottomMMf; - writer.setMargins(margins); + writer.setPageMargins({leftMMf, topMMf, rightMMf, bottomMMf}, QPageLayout::Millimeter); QCOMPARE(writer.margins().left, leftMMf); QCOMPARE(writer.margins().right, rightMMf); QCOMPARE(writer.margins().top, topMMf); @@ -169,7 +164,7 @@ void tst_QPdfWriter::testPageMetrics() // Set the given size, in Portrait mode if (pageSize < 0) { - writer.setPageSizeMM(sizeMMf); + writer.setPageSize(QPageSize(sizeMMf, QPageSize::Millimeter)); QCOMPARE(writer.pageSize(), QPdfWriter::Custom); QCOMPARE(writer.pageLayout().pageSize().id(), QPageSize::Custom); } else { @@ -221,7 +216,7 @@ void tst_QPdfWriter::testPageMetrics() // Now while in Landscape mode, set the size again, results should be the same if (pageSize < 0) { - writer.setPageSizeMM(sizeMMf); + writer.setPageSize(QPageSize(sizeMMf, QPageSize::Millimeter)); QCOMPARE(writer.pageSize(), QPdfWriter::Custom); QCOMPARE(writer.pageLayout().pageSize().id(), QPageSize::Custom); } else { @@ -255,7 +250,7 @@ void tst_QPdfWriter::qtbug59443() QTemporaryFile file; QVERIFY2(file.open(), qPrintable(file.errorString())); QPdfWriter writer(file.fileName()); - writer.setPageSize(QPdfWriter::A4); + writer.setPageSize(QPageSize(QPageSize::A4)); QTextDocument doc; doc.documentLayout()->setPaintDevice(&writer); diff --git a/tests/auto/gui/qopenglconfig/tst_qopenglconfig.cpp b/tests/auto/gui/qopenglconfig/tst_qopenglconfig.cpp index f8dfdbd3b0..b82b277781 100644 --- a/tests/auto/gui/qopenglconfig/tst_qopenglconfig.cpp +++ b/tests/auto/gui/qopenglconfig/tst_qopenglconfig.cpp @@ -200,7 +200,7 @@ static void dumpGlConfiguration(QOpenGLContext &context, QTextStream &str) << "\nShading language : " << reinterpret_cast<const char *>(functions.glGetString(GL_SHADING_LANGUAGE_VERSION)) << "\nFormat : " << context.format(); - QList<QByteArray> extensionList = context.extensions().toList(); + QList<QByteArray> extensionList = context.extensions().values(); std::sort(extensionList.begin(), extensionList.end()); const int extensionCount = extensionList.size(); str << "\n\nFound " << extensionCount << " extensions:\n"; @@ -233,9 +233,9 @@ void tst_QOpenGlConfig::testGlConfiguration() static inline QByteArray msgSetMismatch(const QSet<QString> &expected, const QSet<QString> &actual) { - const QString result = QStringList(expected.toList()).join(QLatin1Char(',')) + const QString result = QStringList(expected.values()).join(QLatin1Char(',')) + QLatin1String(" != ") - + QStringList(actual.toList()).join(QLatin1Char(',')); + + QStringList(actual.values()).join(QLatin1Char(',')); return result.toLatin1(); } diff --git a/tests/auto/gui/text/qfontdatabase/BLACKLIST b/tests/auto/gui/text/qfontdatabase/BLACKLIST new file mode 100644 index 0000000000..0870ca11d7 --- /dev/null +++ b/tests/auto/gui/text/qfontdatabase/BLACKLIST @@ -0,0 +1,2 @@ +[systemFixedFont] # QTBUG-54623 +b2qt diff --git a/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp b/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp index 68664cdd2f..2b69801b59 100644 --- a/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp +++ b/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp @@ -35,6 +35,8 @@ #include <private/qrawfont_p.h> #include <qpa/qplatformfontdatabase.h> +Q_LOGGING_CATEGORY(lcTests, "qt.text.tests") + class tst_QFontDatabase : public QObject { Q_OBJECT @@ -49,6 +51,7 @@ private slots: void fixedPitch_data(); void fixedPitch(); + void systemFixedFont(); #ifdef Q_OS_MAC void trickyFonts_data(); @@ -156,6 +159,16 @@ void tst_QFontDatabase::fixedPitch() QCOMPARE(fi.fixedPitch(), fixedPitch); } +void tst_QFontDatabase::systemFixedFont() // QTBUG-54623 +{ + QFont font = QFontDatabase::systemFont(QFontDatabase::FixedFont); + QFontInfo fontInfo(font); + bool fdbSaysFixed = QFontDatabase().isFixedPitch(fontInfo.family(), fontInfo.styleName()); + qCDebug(lcTests) << "system fixed font is" << font << "really fixed?" << fdbSaysFixed << fontInfo.fixedPitch(); + QVERIFY(fdbSaysFixed); + QVERIFY(fontInfo.fixedPitch()); +} + #ifdef Q_OS_MAC void tst_QFontDatabase::trickyFonts_data() { @@ -198,8 +211,8 @@ void tst_QFontDatabase::widthTwoTimes() f.setPixelSize(pixelSize); QFontMetrics fm(f); - int w1 = fm.charWidth(text, 0); - int w2 = fm.charWidth(text, 0); + int w1 = fm.horizontalAdvance(text, 0); + int w2 = fm.horizontalAdvance(text, 0); QCOMPARE(w1, w2); } diff --git a/tests/auto/gui/text/qstatictext/tst_qstatictext.cpp b/tests/auto/gui/text/qstatictext/tst_qstatictext.cpp index d00dc251d8..b091edb64d 100644 --- a/tests/auto/gui/text/qstatictext/tst_qstatictext.cpp +++ b/tests/auto/gui/text/qstatictext/tst_qstatictext.cpp @@ -681,7 +681,7 @@ static bool checkPixels(const QImage &image, if (pixel != expectedRgb1 && pixel != expectedRgb2) { QString message; QDebug(&message) << "Color mismatch in image" << image - << "at" << x << ',' << y << ':' << showbase << hex << pixel + << "at" << x << ',' << y << ':' << Qt::showbase << Qt::hex << pixel << "(expected: " << expectedRgb1 << ',' << expectedRgb2 << ')'; *errorMessage = message.toLocal8Bit(); return false; diff --git a/tests/auto/gui/text/qtextdocumentfragment/tst_qtextdocumentfragment.cpp b/tests/auto/gui/text/qtextdocumentfragment/tst_qtextdocumentfragment.cpp index fe0b6dae49..3a118f8c91 100644 --- a/tests/auto/gui/text/qtextdocumentfragment/tst_qtextdocumentfragment.cpp +++ b/tests/auto/gui/text/qtextdocumentfragment/tst_qtextdocumentfragment.cpp @@ -944,7 +944,7 @@ void tst_QTextDocumentFragment::namedAnchorFragments3() QCOMPARE(it.fragment().text(), QString::fromLatin1("T")); QVERIFY(it.fragment().charFormat().isAnchor()); - QCOMPARE(it.fragment().charFormat().anchorName(), QString("target")); + QCOMPARE(it.fragment().charFormat().anchorNames().constFirst(), QLatin1String("target")); QStringList targets; targets << "target" << "target2"; QCOMPARE(it.fragment().charFormat().anchorNames(), targets); diff --git a/tests/auto/gui/text/qtextdocumentlayout/tst_qtextdocumentlayout.cpp b/tests/auto/gui/text/qtextdocumentlayout/tst_qtextdocumentlayout.cpp index c79f787547..f66b16b970 100644 --- a/tests/auto/gui/text/qtextdocumentlayout/tst_qtextdocumentlayout.cpp +++ b/tests/auto/gui/text/qtextdocumentlayout/tst_qtextdocumentlayout.cpp @@ -59,6 +59,8 @@ private slots: void imageAtRightAlignedTab(); void blockVisibility(); + void largeImage(); + private: QTextDocument *doc; }; @@ -347,5 +349,63 @@ void tst_QTextDocumentLayout::blockVisibility() QCOMPARE(doc->size(), halfSize); } +void tst_QTextDocumentLayout::largeImage() +{ + auto img = QImage(400, 500, QImage::Format_ARGB32_Premultiplied); + img.fill(Qt::black); + + { + QTextDocument document; + + document.addResource(QTextDocument::ImageResource, + QUrl("data://test.png"), QVariant(img)); + document.setPageSize({500, 504}); + + auto html = "<img src=\"data://test.png\">"; + document.setHtml(html); + + QCOMPARE(document.pageCount(), 2); + } + + { + QTextDocument document; + + document.addResource(QTextDocument::ImageResource, + QUrl("data://test.png"), QVariant(img)); + document.setPageSize({500, 508}); + + auto html = "<img src=\"data://test.png\">"; + document.setHtml(html); + + QCOMPARE(document.pageCount(), 1); + } + + { + QTextDocument document; + + document.addResource(QTextDocument::ImageResource, + QUrl("data://test.png"), QVariant(img)); + document.setPageSize({585, 250}); + + auto html = "<img src=\"data://test.png\">"; + document.setHtml(html); + + QCOMPARE(document.pageCount(), 3); + } + + { + QTextDocument document; + + document.addResource(QTextDocument::ImageResource, + QUrl("data://test.png"), QVariant(img)); + document.setPageSize({585, 258}); + + auto html = "<img src=\"data://test.png\">"; + document.setHtml(html); + + QCOMPARE(document.pageCount(), 2); + } +} + QTEST_MAIN(tst_QTextDocumentLayout) #include "tst_qtextdocumentlayout.moc" diff --git a/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp b/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp index 9610e5b830..aee2f970fe 100644 --- a/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp +++ b/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp @@ -2228,7 +2228,6 @@ void tst_QTextLayout::superscriptCrash_qtbug53911() for (int j = 0; j < 4; ++j) { QTextLayout* newTextLayout = new QTextLayout(); newTextLayout->setText(layoutText); - QList<QTextLayout::FormatRange> formatRanges; QTextLayout::FormatRange formatRange; formatRange.format.setFont(QFont()); @@ -2257,8 +2256,7 @@ void tst_QTextLayout::superscriptCrash_qtbug53911() formatRange.start = 0; formatRange.length = layoutText.size(); - formatRanges << formatRange; - newTextLayout->setAdditionalFormats(formatRanges); + newTextLayout->setFormats({formatRange}); textLayouts.push_front(newTextLayout); } @@ -2289,10 +2287,7 @@ void tst_QTextLayout::nbspWithFormat() formatRange.length = 1; formatRange.format.setFontUnderline(true); - QList<QTextLayout::FormatRange> overrides; - overrides.append(formatRange); - - layout.setAdditionalFormats(overrides); + layout.setFormats({formatRange}); layout.beginLayout(); forever { @@ -2327,7 +2322,7 @@ void tst_QTextLayout::koreanWordWrap() QTextLine line = layout.createLine(); if (!line.isValid()) break; - line.setLineWidth(metrics.width(s) * 0.8); + line.setLineWidth(metrics.horizontalAdvance(s) * 0.8); } layout.endLayout(); QCOMPARE(layout.lineCount(), 2); diff --git a/tests/auto/gui/text/qtextlist/tst_qtextlist.cpp b/tests/auto/gui/text/qtextlist/tst_qtextlist.cpp index d623ce4044..93e40e7f23 100644 --- a/tests/auto/gui/text/qtextlist/tst_qtextlist.cpp +++ b/tests/auto/gui/text/qtextlist/tst_qtextlist.cpp @@ -314,7 +314,7 @@ void tst_QTextList::partialRemoval() selection.deleteChar(); // deletes the second list QVERIFY(!secondList); - QVERIFY(!firstList->isEmpty()); + QVERIFY(firstList->count() > 0); doc->undo(); } diff --git a/tests/auto/gui/text/qtextmarkdownimporter/data/headingBulletsContinuations.md b/tests/auto/gui/text/qtextmarkdownimporter/data/headingBulletsContinuations.md new file mode 100644 index 0000000000..99eb633d17 --- /dev/null +++ b/tests/auto/gui/text/qtextmarkdownimporter/data/headingBulletsContinuations.md @@ -0,0 +1,28 @@ +# heading +- bullet 1 + continuation line 1, indented via tab +- bullet 2 + continuation line 2, indented via 4 spaces +- bullet 3 + + continuation paragraph 3, indented via tab + + - bullet 3.1 + + continuation paragraph 3.1, indented via 4 spaces + + - bullet 3.2 + continuation line, indented via 2 tabs +- bullet 4 + + continuation paragraph 4, indented via 4 spaces + and continuing onto another line too + +- bullet 5 + + continuation paragraph 5, indented via 2 spaces and continuing onto another + line too + +- bullet 6 + +plain old paragraph at the end diff --git a/tests/auto/gui/text/qtextmarkdownimporter/data/thematicBreaks.md b/tests/auto/gui/text/qtextmarkdownimporter/data/thematicBreaks.md new file mode 100644 index 0000000000..7a0d5388ad --- /dev/null +++ b/tests/auto/gui/text/qtextmarkdownimporter/data/thematicBreaks.md @@ -0,0 +1,17 @@ +Heading +------- +*** +stars +- bullet + ** not a bullet or a rule, just two stars +- [ ] unchecked + + --- indented too far, so not a rule +* * * +stars with tabs between +*** +stars with whitespace after +--- +hyphens with whitespace after +_____ +underscores with whitespace after diff --git a/tests/auto/gui/text/qtextmarkdownimporter/qtextmarkdownimporter.pro b/tests/auto/gui/text/qtextmarkdownimporter/qtextmarkdownimporter.pro new file mode 100644 index 0000000000..7b7fb61244 --- /dev/null +++ b/tests/auto/gui/text/qtextmarkdownimporter/qtextmarkdownimporter.pro @@ -0,0 +1,9 @@ +CONFIG += testcase +TARGET = tst_qtextmarkdownimporter +QT += core-private gui-private testlib +SOURCES += tst_qtextmarkdownimporter.cpp +TESTDATA += \ + data/thematicBreaks.md \ + data/headingBulletsContinuations.md \ + +DEFINES += SRCDIR=\\\"$$PWD\\\" diff --git a/tests/auto/gui/text/qtextmarkdownimporter/tst_qtextmarkdownimporter.cpp b/tests/auto/gui/text/qtextmarkdownimporter/tst_qtextmarkdownimporter.cpp new file mode 100644 index 0000000000..8f51a7a474 --- /dev/null +++ b/tests/auto/gui/text/qtextmarkdownimporter/tst_qtextmarkdownimporter.cpp @@ -0,0 +1,163 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> +#include <QTextDocument> +#include <QTextCursor> +#include <QTextBlock> +#include <QTextList> +#include <QTextTable> +#include <QBuffer> +#include <QDebug> + +#include <private/qtextmarkdownimporter_p.h> + +// #define DEBUG_WRITE_HTML + +Q_LOGGING_CATEGORY(lcTests, "qt.text.tests") + +static const QChar LineBreak = QChar(0x2028); +static const QChar Tab = QLatin1Char('\t'); +static const QChar Space = QLatin1Char(' '); +static const QChar Period = QLatin1Char('.'); + +class tst_QTextMarkdownImporter : public QObject +{ + Q_OBJECT + +private slots: + void headingBulletsContinuations(); + void thematicBreaks(); +}; + +void tst_QTextMarkdownImporter::headingBulletsContinuations() +{ + const QStringList expectedBlocks = QStringList() << + "" << // we could do without this blank line before the heading, but currently it happens + "heading" << + "bullet 1 continuation line 1, indented via tab" << + "bullet 2 continuation line 2, indented via 4 spaces" << + "bullet 3" << + "continuation paragraph 3, indented via tab" << + "bullet 3.1" << + "continuation paragraph 3.1, indented via 4 spaces" << + "bullet 3.2 continuation line, indented via 2 tabs" << + "bullet 4" << + "continuation paragraph 4, indented via 4 spaces and continuing onto another line too" << + "bullet 5" << + // indenting by only 2 spaces is perhaps non-standard but currently is OK + "continuation paragraph 5, indented via 2 spaces and continuing onto another line too" << + "bullet 6" << + "plain old paragraph at the end"; + + QFile f(QFINDTESTDATA("data/headingBulletsContinuations.md")); + QVERIFY(f.open(QFile::ReadOnly | QIODevice::Text)); + QString md = QString::fromUtf8(f.readAll()); + f.close(); + + QTextDocument doc; + QTextMarkdownImporter(QTextMarkdownImporter::DialectGitHub).import(&doc, md); + QTextFrame::iterator iterator = doc.rootFrame()->begin(); + QTextFrame *currentFrame = iterator.currentFrame(); + QStringList::const_iterator expectedIt = expectedBlocks.constBegin(); + int i = 0; + while (!iterator.atEnd()) { + // There are no child frames + QCOMPARE(iterator.currentFrame(), currentFrame); + // Check whether we got the right child block + QTextBlock block = iterator.currentBlock(); + QCOMPARE(block.text().contains(LineBreak), false); + QCOMPARE(block.text().contains(Tab), false); + QVERIFY(!block.text().startsWith(Space)); + int expectedIndentation = 0; + if (block.text().contains(QLatin1String("continuation paragraph"))) + expectedIndentation = (block.text().contains(Period) ? 2 : 1); + qCDebug(lcTests) << i << "child block" << block.text() << "indentation" << block.blockFormat().indent(); + QVERIFY(expectedIt != expectedBlocks.constEnd()); + QCOMPARE(block.text(), *expectedIt); + if (i > 2) + QCOMPARE(block.blockFormat().indent(), expectedIndentation); + ++iterator; + ++expectedIt; + ++i; + } + QCOMPARE(expectedIt, expectedBlocks.constEnd()); + +#ifdef DEBUG_WRITE_HTML + { + QFile out("/tmp/headingBulletsContinuations.html"); + out.open(QFile::WriteOnly); + out.write(doc.toHtml().toLatin1()); + out.close(); + } +#endif +} + +void tst_QTextMarkdownImporter::thematicBreaks() +{ + int horizontalRuleCount = 0; + int textLinesCount = 0; + + QFile f(QFINDTESTDATA("data/thematicBreaks.md")); + QVERIFY(f.open(QFile::ReadOnly | QIODevice::Text)); + QString md = QString::fromUtf8(f.readAll()); + f.close(); + + QTextDocument doc; + QTextMarkdownImporter(QTextMarkdownImporter::DialectGitHub).import(&doc, md); + QTextFrame::iterator iterator = doc.rootFrame()->begin(); + QTextFrame *currentFrame = iterator.currentFrame(); + int i = 0; + while (!iterator.atEnd()) { + // There are no child frames + QCOMPARE(iterator.currentFrame(), currentFrame); + // Check whether the block is text or a horizontal rule + QTextBlock block = iterator.currentBlock(); + if (block.blockFormat().hasProperty(QTextFormat::BlockTrailingHorizontalRulerWidth)) + ++horizontalRuleCount; + else if (!block.text().isEmpty()) + ++textLinesCount; + qCDebug(lcTests) << i << (block.blockFormat().hasProperty(QTextFormat::BlockTrailingHorizontalRulerWidth) ? QLatin1String("- - -") : block.text()); + ++iterator; + ++i; + } + QCOMPARE(horizontalRuleCount, 5); + QCOMPARE(textLinesCount, 9); + +#ifdef DEBUG_WRITE_HTML + { + QFile out("/tmp/thematicBreaks.html"); + out.open(QFile::WriteOnly); + out.write(doc.toHtml().toLatin1()); + out.close(); + } +#endif +} + +QTEST_MAIN(tst_QTextMarkdownImporter) +#include "tst_qtextmarkdownimporter.moc" diff --git a/tests/auto/gui/text/qtextmarkdownwriter/BLACKLIST b/tests/auto/gui/text/qtextmarkdownwriter/BLACKLIST new file mode 100644 index 0000000000..fc9e5a9efe --- /dev/null +++ b/tests/auto/gui/text/qtextmarkdownwriter/BLACKLIST @@ -0,0 +1,3 @@ +[rewriteDocument] +winrt # QTBUG-54623 + diff --git a/tests/auto/gui/text/qtextmarkdownwriter/data/blockquotes.md b/tests/auto/gui/text/qtextmarkdownwriter/data/blockquotes.md new file mode 100644 index 0000000000..f429fcc21b --- /dev/null +++ b/tests/auto/gui/text/qtextmarkdownwriter/data/blockquotes.md @@ -0,0 +1,39 @@ +In 1958, Mahatma Gandhi was quoted as follows: + +> The Earth provides enough to satisfy every man's need but not for every man's +> greed. + +In [The CommonMark Specification](https://spec.commonmark.org/0.29/) John +MacFarlane writes: + +> What distinguishes Markdown from many other lightweight markup syntaxes, +> which are often easier to write, is its readability. As Gruber writes: + +> > The overriding design goal for Markdown's formatting syntax is to make it +> > as readable as possible. The idea is that a Markdown-formatted document should +> > be publishable as-is, as plain text, without looking like it's been marked up +> > with tags or formatting instructions. ( +> > [http://daringfireball.net/projects/markdown/](http://daringfireball.net/projects/markdown/)) + +> The point can be illustrated by comparing a sample of AsciiDoc with an +> equivalent sample of Markdown. Here is a sample of AsciiDoc from the AsciiDoc +> manual: + +> 1. List item one. +> + +> List item one continued with a second paragraph followed by an +> Indented block. +> + +> ................. +> $ ls *.sh +> $ mv *.sh ~/tmp +> ................. +> + +> List item continued with a third paragraph. +> +> 2. List item two continued with an open block. +> ... +> +The quotation includes an embedded quotation and a code quotation and ends with +an ellipsis due to being incomplete. + diff --git a/tests/auto/gui/text/qtextmarkdownwriter/data/example.md b/tests/auto/gui/text/qtextmarkdownwriter/data/example.md new file mode 100644 index 0000000000..0c3f34e09d --- /dev/null +++ b/tests/auto/gui/text/qtextmarkdownwriter/data/example.md @@ -0,0 +1,95 @@ +# QTextEdit + +The QTextEdit widget is an advanced editor that supports formatted rich text. +It can be used to display HTML and other rich document formats. Internally, +QTextEdit uses the QTextDocument class to describe both the high-level +structure of each document and the low-level formatting of paragraphs. + +If you are viewing this document in the textedit example, you can edit this +document to explore Qt's rich text editing features. We have included some +comments in each of the following sections to encourage you to experiment. + +## Font and Paragraph Styles + +QTextEdit supports **bold**, *italic*, and ~~strikethrough~~ font styles, and can +display multicolored text. Font families such as Times New Roman and `Courier` +can also be used directly. *If you place the cursor in a region of styled text, +the controls in the tool bars will change to reflect the current style.* + +Paragraphs can be formatted so that the text is left-aligned, right-aligned, +centered, or fully justified. + +*Try changing the alignment of some text and resize the editor to see how the +text layout changes.* + +## Lists + +Different kinds of lists can be included in rich text documents. Standard +bullet lists can be nested, using different symbols for each level of the list: + +- Disc symbols are typically used for top-level list items. + * Circle symbols can be used to distinguish between items in lower-level + lists. + + Square symbols provide a reasonable alternative to discs and circles. + +Ordered lists can be created that can be used for tables of contents. Different +characters can be used to enumerate items, and we can use both Roman and Arabic +numerals in the same list structure: + +1. Introduction +2. Qt Tools + 1) Qt Assistant + 2) Qt Designer + 1. Form Editor + 2. Component Architecture + 3) Qt Linguist + +The list will automatically be renumbered if you add or remove items. *Try +adding new sections to the above list or removing existing item to see the +numbers change.* + +## Images + +Inline images are treated like ordinary ranges of characters in the text +editor, so they flow with the surrounding text. Images can also be selected in +the same way as text, making it easy to cut, copy, and paste them. + +![image](images/logo32.png) *Try to select this image by clicking and dragging +over it with the mouse, or use the text cursor to select it by holding down +Shift and using the arrow keys. You can then cut or copy it, and paste it into +different parts of this document.* + +## Tables + +QTextEdit can arrange and format tables, supporting features such as row and +column spans, text formatting within cells, and size constraints for columns. + + +| |Development Tools |Programming Techniques |Graphical User Interfaces| +|-------------|------------------------------------|---------------------------|-------------------------| +|9:00 - 11:00 |Introduction to Qt ||| +|11:00 - 13:00|Using qmake |Object-oriented Programming|Layouts in Qt | +|13:00 - 15:00|Qt Designer Tutorial |Extreme Programming |Writing Custom Styles | +|15:00 - 17:00|Qt Linguist and Internationalization|Â |Â | + +*Try adding text to the cells in the table and experiment with the alignment of +the paragraphs.* + +## Hyperlinks + +QTextEdit is designed to support hyperlinks between documents, and this feature +is used extensively in +[Qt Assistant](http://doc.qt.io/qt-5/qtassistant-index.html). Hyperlinks are +automatically created when an HTML file is imported into an editor. Since the +rich text framework supports hyperlinks natively, they can also be created +programatically. + +## Undo and Redo + +Full support for undo and redo operations is built into QTextEdit and the +underlying rich text framework. Operations on a document can be packaged +together to make editing a more comfortable experience for the user. + +*Try making changes to this document and press `Ctrl+Z` to undo them. You can +always recover the original contents of the document.* + diff --git a/tests/auto/gui/text/qtextmarkdownwriter/qtextmarkdownwriter.pro b/tests/auto/gui/text/qtextmarkdownwriter/qtextmarkdownwriter.pro new file mode 100644 index 0000000000..6144710b99 --- /dev/null +++ b/tests/auto/gui/text/qtextmarkdownwriter/qtextmarkdownwriter.pro @@ -0,0 +1,9 @@ +CONFIG += testcase +TARGET = tst_qtextmarkdownwriter +QT += core-private gui-private testlib +SOURCES += tst_qtextmarkdownwriter.cpp +TESTDATA += \ + data/example.md \ + data/blockquotes.md \ + +DEFINES += SRCDIR=\\\"$$PWD\\\" diff --git a/tests/auto/gui/text/qtextmarkdownwriter/tst_qtextmarkdownwriter.cpp b/tests/auto/gui/text/qtextmarkdownwriter/tst_qtextmarkdownwriter.cpp new file mode 100644 index 0000000000..9998794762 --- /dev/null +++ b/tests/auto/gui/text/qtextmarkdownwriter/tst_qtextmarkdownwriter.cpp @@ -0,0 +1,456 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> +#include <QTextDocument> +#include <QTextCursor> +#include <QTextBlock> +#include <QTextList> +#include <QTextTable> +#include <QBuffer> +#include <QDebug> + +#include <private/qtextmarkdownwriter_p.h> + +// #define DEBUG_WRITE_OUTPUT + +class tst_QTextMarkdownWriter : public QObject +{ + Q_OBJECT +public slots: + void init(); + void cleanup(); + +private slots: + void testWriteParagraph_data(); + void testWriteParagraph(); + void testWriteList(); + void testWriteNestedBulletLists_data(); + void testWriteNestedBulletLists(); + void testWriteNestedNumericLists(); + void testWriteTable(); + void rewriteDocument_data(); + void rewriteDocument(); + void fromHtml_data(); + void fromHtml(); + +private: + QString documentToUnixMarkdown(); + +private: + QTextDocument *document; +}; + +void tst_QTextMarkdownWriter::init() +{ + document = new QTextDocument(); +} + +void tst_QTextMarkdownWriter::cleanup() +{ + delete document; +} + +void tst_QTextMarkdownWriter::testWriteParagraph_data() +{ + QTest::addColumn<QString>("input"); + QTest::addColumn<QString>("output"); + + QTest::newRow("empty") << "" << + ""; + QTest::newRow("spaces") << "foobar word" << + "foobar word\n\n"; + QTest::newRow("starting spaces") << " starting spaces" << + " starting spaces\n\n"; + QTest::newRow("trailing spaces") << "trailing spaces " << + "trailing spaces \n\n"; + QTest::newRow("tab") << "word\ttab x" << + "word\ttab x\n\n"; + QTest::newRow("tab2") << "word\t\ttab\tx" << + "word\t\ttab\tx\n\n"; + QTest::newRow("misc") << "foobar word\ttab x" << + "foobar word\ttab x\n\n"; + QTest::newRow("misc2") << "\t \tFoo" << + "\t \tFoo\n\n"; +} + +void tst_QTextMarkdownWriter::testWriteParagraph() +{ + QFETCH(QString, input); + QFETCH(QString, output); + + QTextCursor cursor(document); + cursor.insertText(input); + + QCOMPARE(documentToUnixMarkdown(), output); +} + +void tst_QTextMarkdownWriter::testWriteList() +{ + QTextCursor cursor(document); + QTextList *list = cursor.createList(QTextListFormat::ListDisc); + cursor.insertText("ListItem 1"); + list->add(cursor.block()); + cursor.insertBlock(); + cursor.insertText("ListItem 2"); + list->add(cursor.block()); + + QCOMPARE(documentToUnixMarkdown(), QString::fromLatin1( + "- ListItem 1\n- ListItem 2\n")); +} + +void tst_QTextMarkdownWriter::testWriteNestedBulletLists_data() +{ + QTest::addColumn<bool>("checkbox"); + QTest::addColumn<bool>("checked"); + QTest::addColumn<bool>("continuationLine"); + QTest::addColumn<bool>("continuationParagraph"); + QTest::addColumn<QString>("expectedOutput"); + + QTest::newRow("plain bullets") << false << false << false << false << + "- ListItem 1\n * ListItem 2\n + ListItem 3\n- ListItem 4\n * ListItem 5\n"; + QTest::newRow("bullets with continuation lines") << false << false << true << false << + "- ListItem 1\n * ListItem 2\n + ListItem 3 with text that won't fit on one line and thus needs a\n continuation\n- ListItem 4\n * ListItem 5 with text that won't fit on one line and thus needs a\n continuation\n"; + QTest::newRow("bullets with continuation paragraphs") << false << false << false << true << + "- ListItem 1\n\n * ListItem 2\n + ListItem 3\n\n continuation\n\n- ListItem 4\n\n * ListItem 5\n\n continuation\n\n"; + QTest::newRow("unchecked") << true << false << false << false << + "- [ ] ListItem 1\n * [ ] ListItem 2\n + [ ] ListItem 3\n- [ ] ListItem 4\n * [ ] ListItem 5\n"; + QTest::newRow("checked") << true << true << false << false << + "- [x] ListItem 1\n * [x] ListItem 2\n + [x] ListItem 3\n- [x] ListItem 4\n * [x] ListItem 5\n"; + QTest::newRow("checked with continuation lines") << true << true << true << false << + "- [x] ListItem 1\n * [x] ListItem 2\n + [x] ListItem 3 with text that won't fit on one line and thus needs a\n continuation\n- [x] ListItem 4\n * [x] ListItem 5 with text that won't fit on one line and thus needs a\n continuation\n"; + QTest::newRow("checked with continuation paragraphs") << true << true << false << true << + "- [x] ListItem 1\n\n * [x] ListItem 2\n + [x] ListItem 3\n\n continuation\n\n- [x] ListItem 4\n\n * [x] ListItem 5\n\n continuation\n\n"; +} + +void tst_QTextMarkdownWriter::testWriteNestedBulletLists() +{ + QFETCH(bool, checkbox); + QFETCH(bool, checked); + QFETCH(bool, continuationParagraph); + QFETCH(bool, continuationLine); + QFETCH(QString, expectedOutput); + + QTextCursor cursor(document); + QTextBlockFormat blockFmt = cursor.blockFormat(); + if (checkbox) { + blockFmt.setMarker(checked ? QTextBlockFormat::Checked : QTextBlockFormat::Unchecked); + cursor.setBlockFormat(blockFmt); + } + + QTextList *list1 = cursor.createList(QTextListFormat::ListDisc); + cursor.insertText("ListItem 1"); + list1->add(cursor.block()); + + QTextListFormat fmt2; + fmt2.setStyle(QTextListFormat::ListCircle); + fmt2.setIndent(2); + QTextList *list2 = cursor.insertList(fmt2); + cursor.insertText("ListItem 2"); + + QTextListFormat fmt3; + fmt3.setStyle(QTextListFormat::ListSquare); + fmt3.setIndent(3); + cursor.insertList(fmt3); + cursor.insertText(continuationLine ? + "ListItem 3 with text that won't fit on one line and thus needs a continuation" : + "ListItem 3"); + if (continuationParagraph) { + QTextBlockFormat blockFmt; + blockFmt.setIndent(2); + cursor.insertBlock(blockFmt); + cursor.insertText("continuation"); + } + + cursor.insertBlock(blockFmt); + cursor.insertText("ListItem 4"); + list1->add(cursor.block()); + + cursor.insertBlock(); + cursor.insertText(continuationLine ? + "ListItem 5 with text that won't fit on one line and thus needs a continuation" : + "ListItem 5"); + list2->add(cursor.block()); + if (continuationParagraph) { + QTextBlockFormat blockFmt; + blockFmt.setIndent(2); + cursor.insertBlock(blockFmt); + cursor.insertText("continuation"); + } + + QString output = documentToUnixMarkdown(); +#ifdef DEBUG_WRITE_OUTPUT + { + QFile out("/tmp/" + QLatin1String(QTest::currentDataTag()) + ".md"); + out.open(QFile::WriteOnly); + out.write(output.toUtf8()); + out.close(); + } +#endif + QCOMPARE(documentToUnixMarkdown(), expectedOutput); +} + +void tst_QTextMarkdownWriter::testWriteNestedNumericLists() +{ + QTextCursor cursor(document); + + QTextList *list1 = cursor.createList(QTextListFormat::ListDecimal); + cursor.insertText("ListItem 1"); + list1->add(cursor.block()); + + QTextListFormat fmt2; + fmt2.setStyle(QTextListFormat::ListLowerAlpha); + fmt2.setNumberSuffix(QLatin1String(")")); + fmt2.setIndent(2); + QTextList *list2 = cursor.insertList(fmt2); + cursor.insertText("ListItem 2"); + + QTextListFormat fmt3; + fmt3.setStyle(QTextListFormat::ListDecimal); + fmt3.setIndent(3); + cursor.insertList(fmt3); + cursor.insertText("ListItem 3"); + + cursor.insertBlock(); + cursor.insertText("ListItem 4"); + list1->add(cursor.block()); + + cursor.insertBlock(); + cursor.insertText("ListItem 5"); + list2->add(cursor.block()); + + // There's no QTextList API to set the starting number so we hard-coded all lists to start at 1 (QTBUG-65384) + QCOMPARE(documentToUnixMarkdown(), QString::fromLatin1( + "1. ListItem 1\n 1) ListItem 2\n 1. ListItem 3\n2. ListItem 4\n 2) ListItem 5\n")); +} + +void tst_QTextMarkdownWriter::testWriteTable() +{ + QTextCursor cursor(document); + QTextTable * table = cursor.insertTable(4, 3); + cursor = table->cellAt(0, 0).firstCursorPosition(); + // valid Markdown tables need headers, but QTextTable doesn't make that distinction + // so QTextMarkdownWriter assumes the first row of any table is a header + cursor.insertText("one"); + cursor.movePosition(QTextCursor::NextCell); + cursor.insertText("two"); + cursor.movePosition(QTextCursor::NextCell); + cursor.insertText("three"); + cursor.movePosition(QTextCursor::NextCell); + + cursor.insertText("alice"); + cursor.movePosition(QTextCursor::NextCell); + cursor.insertText("bob"); + cursor.movePosition(QTextCursor::NextCell); + cursor.insertText("carl"); + cursor.movePosition(QTextCursor::NextCell); + + cursor.insertText("dennis"); + cursor.movePosition(QTextCursor::NextCell); + cursor.insertText("eric"); + cursor.movePosition(QTextCursor::NextCell); + cursor.insertText("fiona"); + cursor.movePosition(QTextCursor::NextCell); + + cursor.insertText("gina"); + /* + |one |two |three| + |------|----|-----| + |alice |bob |carl | + |dennis|eric|fiona| + |gina | | | + */ + + QString md = documentToUnixMarkdown(); + +#ifdef DEBUG_WRITE_OUTPUT + { + QFile out("/tmp/table.md"); + out.open(QFile::WriteOnly); + out.write(md.toUtf8()); + out.close(); + } +#endif + + QString expected = QString::fromLatin1( + "\n|one |two |three|\n|------|----|-----|\n|alice |bob |carl |\n|dennis|eric|fiona|\n|gina | | |\n\n"); + QCOMPARE(md, expected); + + // create table with merged cells + document->clear(); + cursor = QTextCursor(document); + table = cursor.insertTable(3, 3); + table->mergeCells(0, 0, 1, 2); + table->mergeCells(1, 1, 1, 2); + cursor = table->cellAt(0, 0).firstCursorPosition(); + cursor.insertText("a"); + cursor.movePosition(QTextCursor::NextCell); + cursor.insertText("b"); + cursor.movePosition(QTextCursor::NextCell); + cursor.insertText("c"); + cursor.movePosition(QTextCursor::NextCell); + cursor.insertText("d"); + cursor.movePosition(QTextCursor::NextCell); + cursor.insertText("e"); + cursor.movePosition(QTextCursor::NextCell); + cursor.insertText("f"); + /* + +---+-+ + |a |b| + +---+-+ + |c| d| + +-+-+-+ + |e|f| | + +-+-+-+ + + generates + + |a ||b| + |-|-|-| + |c|d || + |e|f| | + + */ + + md = documentToUnixMarkdown(); + +#ifdef DEBUG_WRITE_OUTPUT + { + QFile out("/tmp/table-merged-cells.md"); + out.open(QFile::WriteOnly); + out.write(md.toUtf8()); + out.close(); + } +#endif + + QCOMPARE(md, QString::fromLatin1("\n|a ||b|\n|-|-|-|\n|c|d ||\n|e|f| |\n\n")); +} + +void tst_QTextMarkdownWriter::rewriteDocument_data() +{ + QTest::addColumn<QString>("inputFile"); + + QTest::newRow("block quotes") << "blockquotes.md"; + QTest::newRow("example") << "example.md"; +} + +void tst_QTextMarkdownWriter::rewriteDocument() +{ + QFETCH(QString, inputFile); + QTextDocument doc; + QFile f(QFINDTESTDATA("data/" + inputFile)); + QVERIFY(f.open(QFile::ReadOnly | QIODevice::Text)); + QString orig = QString::fromUtf8(f.readAll()); + f.close(); + doc.setMarkdown(orig); + QString md = doc.toMarkdown(); + +#ifdef DEBUG_WRITE_OUTPUT + QFile out("/tmp/rewrite-" + inputFile); + out.open(QFile::WriteOnly); + out.write(md.toUtf8()); + out.close(); +#endif + + QCOMPARE(md, orig); +} + +void tst_QTextMarkdownWriter::fromHtml_data() +{ + QTest::addColumn<QString>("expectedInput"); + QTest::addColumn<QString>("expectedOutput"); + + QTest::newRow("long URL") << + "<span style=\"font-style:italic;\">https://www.example.com/dir/subdir/subsubdir/subsubsubdir/subsubsubsubdir/subsubsubsubsubdir/</span>" << + "*https://www.example.com/dir/subdir/subsubdir/subsubsubdir/subsubsubsubdir/subsubsubsubsubdir/*\n\n"; + QTest::newRow("non-emphasis inline asterisk") << "3 * 4" << "3 * 4\n\n"; + QTest::newRow("arithmetic") << "(2 * a * x + b)^2 = b^2 - 4 * a * c" << "(2 * a * x + b)^2 = b^2 - 4 * a * c\n\n"; + QTest::newRow("escaped asterisk after newline") << + "The first sentence of this paragraph holds 80 characters, then there's a star. * This is wrapped, but is <em>not</em> a bullet point." << + "The first sentence of this paragraph holds 80 characters, then there's a star.\n\\* This is wrapped, but is *not* a bullet point.\n\n"; + QTest::newRow("escaped plus after newline") << + "The first sentence of this paragraph holds 80 characters, then there's a plus. + This is wrapped, but is <em>not</em> a bullet point." << + "The first sentence of this paragraph holds 80 characters, then there's a plus.\n\\+ This is wrapped, but is *not* a bullet point.\n\n"; + QTest::newRow("escaped hyphen after newline") << + "The first sentence of this paragraph holds 80 characters, then there's a minus. - This is wrapped, but is <em>not</em> a bullet point." << + "The first sentence of this paragraph holds 80 characters, then there's a minus.\n\\- This is wrapped, but is *not* a bullet point.\n\n"; + QTest::newRow("list items with indented continuations") << + "<ul><li>bullet<p>continuation paragraph</p></li><li>another bullet<br/>continuation line</li></ul>" << + "- bullet\n\n continuation paragraph\n\n- another bullet\n continuation line\n"; + QTest::newRow("nested list items with continuations") << + "<ul><li>bullet<p>continuation paragraph</p></li><li>another bullet<br/>continuation line</li><ul><li>bullet<p>continuation paragraph</p></li><li>another bullet<br/>continuation line</li></ul></ul>" << + "- bullet\n\n continuation paragraph\n\n- another bullet\n continuation line\n\n - bullet\n\n continuation paragraph\n\n - another bullet\n continuation line\n"; + QTest::newRow("nested ordered list items with continuations") << + "<ol><li>item<p>continuation paragraph</p></li><li>another item<br/>continuation line</li><ol><li>item<p>continuation paragraph</p></li><li>another item<br/>continuation line</li></ol><li>another</li><li>another</li></ol>" << + "1. item\n\n continuation paragraph\n\n2. another item\n continuation line\n\n 1. item\n\n continuation paragraph\n\n 2. another item\n continuation line\n\n3. another\n4. another\n"; + QTest::newRow("thematic break") << + "something<hr/>something else" << + "something\n\n- - -\nsomething else\n\n"; + QTest::newRow("block quote") << + "<p>In 1958, Mahatma Gandhi was quoted as follows:</p><blockquote>The Earth provides enough to satisfy every man's need but not for every man's greed.</blockquote>" << + "In 1958, Mahatma Gandhi was quoted as follows:\n\n> The Earth provides enough to satisfy every man's need but not for every man's\n> greed.\n\n"; + // TODO +// QTest::newRow("escaped number and paren after double newline") << +// "<p>(The first sentence of this paragraph is a line, the next paragraph has a number</p>13) but that's not part of an ordered list" << +// "(The first sentence of this paragraph is a line, the next paragraph has a number\n\n13\\) but that's not part of an ordered list\n\n"; +// QTest::newRow("preformats with embedded backticks") << +// "<pre>none `one` ``two``</pre><pre>```three``` ````four````</pre>plain" << +// "``` none `one` ``two`` ```\n\n````` ```three``` ````four```` `````\n\nplain\n\n"; +} + +void tst_QTextMarkdownWriter::fromHtml() +{ + QFETCH(QString, expectedInput); + QFETCH(QString, expectedOutput); + + document->setHtml(expectedInput); + QString output = documentToUnixMarkdown(); + +#ifdef DEBUG_WRITE_OUTPUT + { + QFile out("/tmp/" + QLatin1String(QTest::currentDataTag()) + ".md"); + out.open(QFile::WriteOnly); + out.write(output.toUtf8()); + out.close(); + } +#endif + + QCOMPARE(output, expectedOutput); +} + +QString tst_QTextMarkdownWriter::documentToUnixMarkdown() +{ + QString ret; + QTextStream ts(&ret, QIODevice::WriteOnly); + QTextMarkdownWriter writer(ts, QTextDocument::MarkdownDialectGitHub); + writer.writeAll(document); + return ret; +} + +QTEST_MAIN(tst_QTextMarkdownWriter) +#include "tst_qtextmarkdownwriter.moc" diff --git a/tests/auto/gui/text/text.pro b/tests/auto/gui/text/text.pro index 6b033fb506..794d9ea8d3 100644 --- a/tests/auto/gui/text/text.pro +++ b/tests/auto/gui/text/text.pro @@ -28,12 +28,16 @@ SUBDIRS=\ win32:SUBDIRS -= qtextpiecetable +qtConfig(textmarkdownreader): SUBDIRS += qtextmarkdownimporter +qtConfig(textmarkdownwriter): SUBDIRS += qtextmarkdownwriter + !qtConfig(private_tests): SUBDIRS -= \ qfontcache \ qcssparser \ qtextlayout \ qtextpiecetable \ qzip \ + qtextmarkdownwriter \ qtextodfwriter !qtHaveModule(xml): SUBDIRS -= \ diff --git a/tests/auto/gui/util/qshadergenerator/tst_qshadergenerator.cpp b/tests/auto/gui/util/qshadergenerator/tst_qshadergenerator.cpp index 82197f815e..59e93d127f 100644 --- a/tests/auto/gui/util/qshadergenerator/tst_qshadergenerator.cpp +++ b/tests/auto/gui/util/qshadergenerator/tst_qshadergenerator.cpp @@ -35,11 +35,13 @@ namespace { - QShaderFormat createFormat(QShaderFormat::Api api, int majorVersion, int minorVersion) + QShaderFormat createFormat(QShaderFormat::Api api, int majorVersion, int minorVersion, + QShaderFormat::ShaderType shaderType= QShaderFormat::Fragment) { auto format = QShaderFormat(); format.setApi(api); format.setVersion(QVersionNumber(majorVersion, minorVersion)); + format.setShaderType(shaderType); return format; } @@ -74,7 +76,7 @@ namespace return edge; } - QShaderGraph createGraph() + QShaderGraph createFragmentShaderGraph() { const auto openGLES2 = createFormat(QShaderFormat::OpenGLES, 2, 0); const auto openGL3 = createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0); @@ -135,7 +137,7 @@ namespace createPort(QShaderNodePort::Output, "color") }); sampleTexture.addRule(openGLES2, QShaderNode::Rule("highp vec4 $color = texture2D($sampler, $coord);")); - sampleTexture.addRule(openGL3, QShaderNode::Rule("vec4 $color = texture2D($sampler, $coord);")); + sampleTexture.addRule(openGL3, QShaderNode::Rule("vec4 $color = texture($sampler, $coord);")); auto lightFunction = createNode({ createPort(QShaderNodePort::Input, "baseColor"), @@ -194,6 +196,8 @@ private slots: void shouldProcessLanguageQualifierAndTypeEnums_data(); void shouldProcessLanguageQualifierAndTypeEnums(); void shouldGenerateDifferentCodeDependingOnActiveLayers(); + void shouldUseGlobalVariableRatherThanTemporaries(); + void shouldGenerateTemporariesWisely(); }; void tst_QShaderGenerator::shouldHaveDefaultState() @@ -213,7 +217,7 @@ void tst_QShaderGenerator::shouldGenerateShaderCode_data() QTest::addColumn<QShaderFormat>("format"); QTest::addColumn<QByteArray>("expectedCode"); - const auto graph = createGraph(); + const auto graph = createFragmentShaderGraph(); const auto openGLES2 = createFormat(QShaderFormat::OpenGLES, 2, 0); const auto openGL3 = createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0); @@ -234,15 +238,7 @@ void tst_QShaderGenerator::shouldGenerateShaderCode_data() << "" << "void main()" << "{" - << " highp vec2 v2 = texCoord;" - << " sampler2D v1 = texture;" - << " highp float v3 = lightIntensity;" - << " highp vec4 v5 = texture2D(v1, v2);" - << " highp vec3 v0 = worldPosition;" - << " highp float v4 = exposure;" - << " highp vec4 v6 = lightModel(v5, v0, v3);" - << " highp vec4 v7 = v6 * pow(2.0, v4);" - << " gl_fragColor = v7;" + << " gl_fragColor = (((((lightModel(((texture2D(texture, texCoord))), worldPosition, lightIntensity)))) * pow(2.0, exposure)));" << "}" << ""; @@ -256,15 +252,7 @@ void tst_QShaderGenerator::shouldGenerateShaderCode_data() << "" << "void main()" << "{" - << " vec2 v2 = texCoord;" - << " sampler2D v1 = texture;" - << " float v3 = lightIntensity;" - << " vec4 v5 = texture2D(v1, v2);" - << " vec3 v0 = worldPosition;" - << " float v4 = exposure;" - << " vec4 v6 = lightModel(v5, v0, v3);" - << " vec4 v7 = v6 * pow(2.0, v4);" - << " fragColor = v7;" + << " fragColor = (((((lightModel(((texture(texture, texCoord))), worldPosition, lightIntensity)))) * pow(2.0, exposure)));" << "}" << ""; @@ -580,120 +568,190 @@ void tst_QShaderGenerator::shouldProcessLanguageQualifierAndTypeEnums_data() QTest::addColumn<QShaderFormat>("format"); QTest::addColumn<QByteArray>("expectedCode"); - const auto es2 = createFormat(QShaderFormat::OpenGLES, 2, 0); - const auto es3 = createFormat(QShaderFormat::OpenGLES, 3, 0); - const auto gl2 = createFormat(QShaderFormat::OpenGLNoProfile, 2, 0); - const auto gl3 = createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0); - const auto gl4 = createFormat(QShaderFormat::OpenGLCoreProfile, 4, 0); - - const auto qualifierEnum = QMetaEnum::fromType<QShaderLanguage::StorageQualifier>(); - const auto typeEnum = QMetaEnum::fromType<QShaderLanguage::VariableType>(); - - for (int qualifierIndex = 0; qualifierIndex < qualifierEnum.keyCount(); qualifierIndex++) { - const auto qualifierName = qualifierEnum.key(qualifierIndex); - const auto qualifierValue = static_cast<QShaderLanguage::StorageQualifier>(qualifierEnum.value(qualifierIndex)); + { + const auto es2 = createFormat(QShaderFormat::OpenGLES, 2, 0); + const auto es3 = createFormat(QShaderFormat::OpenGLES, 3, 0); + const auto gl2 = createFormat(QShaderFormat::OpenGLNoProfile, 2, 0); + const auto gl3 = createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0); + const auto gl4 = createFormat(QShaderFormat::OpenGLCoreProfile, 4, 0); + + const auto qualifierEnum = QMetaEnum::fromType<QShaderLanguage::StorageQualifier>(); + const auto typeEnum = QMetaEnum::fromType<QShaderLanguage::VariableType>(); + + for (int qualifierIndex = 0; qualifierIndex < qualifierEnum.keyCount(); qualifierIndex++) { + const auto qualifierName = qualifierEnum.key(qualifierIndex); + const auto qualifierValue = static_cast<QShaderLanguage::StorageQualifier>(qualifierEnum.value(qualifierIndex)); + + for (int typeIndex = 0; typeIndex < typeEnum.keyCount(); typeIndex++) { + const auto typeName = typeEnum.key(typeIndex); + const auto typeValue = static_cast<QShaderLanguage::VariableType>(typeEnum.value(typeIndex)); + + auto graph = QShaderGraph(); + + auto worldPosition = createNode({ + createPort(QShaderNodePort::Output, "value") + }); + worldPosition.setParameter("name", "worldPosition"); + worldPosition.setParameter("qualifier", QVariant::fromValue<QShaderLanguage::StorageQualifier>(qualifierValue)); + worldPosition.setParameter("type", QVariant::fromValue<QShaderLanguage::VariableType>(typeValue)); + worldPosition.addRule(es2, QShaderNode::Rule("highp $type $value = $name;", + QByteArrayList() << "$qualifier highp $type $name;")); + worldPosition.addRule(gl2, QShaderNode::Rule("$type $value = $name;", + QByteArrayList() << "$qualifier $type $name;")); + worldPosition.addRule(gl3, QShaderNode::Rule("$type $value = $name;", + QByteArrayList() << "$qualifier $type $name;")); + + auto fragColor = createNode({ + createPort(QShaderNodePort::Input, "fragColor") + }); + fragColor.addRule(es2, QShaderNode::Rule("gl_fragColor = $fragColor;")); + fragColor.addRule(gl2, QShaderNode::Rule("gl_fragColor = $fragColor;")); + fragColor.addRule(gl3, QShaderNode::Rule("fragColor = $fragColor;", + QByteArrayList() << "out vec4 fragColor;")); + + graph.addNode(worldPosition); + graph.addNode(fragColor); + + graph.addEdge(createEdge(worldPosition.uuid(), "value", fragColor.uuid(), "fragColor")); + + const auto gl2Code = (QByteArrayList() << "#version 110" + << "" + << QStringLiteral("%1 %2 worldPosition;").arg(toGlsl(qualifierValue, gl2)) + .arg(toGlsl(typeValue)) + .toUtf8() + << "" + << "void main()" + << "{" + << " gl_fragColor = worldPosition;" + << "}" + << "").join("\n"); + const auto gl3Code = (QByteArrayList() << "#version 130" + << "" + << QStringLiteral("%1 %2 worldPosition;").arg(toGlsl(qualifierValue, gl3)) + .arg(toGlsl(typeValue)) + .toUtf8() + << "out vec4 fragColor;" + << "" + << "void main()" + << "{" + << " fragColor = worldPosition;" + << "}" + << "").join("\n"); + const auto gl4Code = (QByteArrayList() << "#version 400 core" + << "" + << QStringLiteral("%1 %2 worldPosition;").arg(toGlsl(qualifierValue, gl4)) + .arg(toGlsl(typeValue)) + .toUtf8() + << "out vec4 fragColor;" + << "" + << "void main()" + << "{" + << " fragColor = worldPosition;" + << "}" + << "").join("\n"); + const auto es2Code = (QByteArrayList() << "#version 100" + << "" + << QStringLiteral("%1 highp %2 worldPosition;").arg(toGlsl(qualifierValue, es2)) + .arg(toGlsl(typeValue)) + .toUtf8() + << "" + << "void main()" + << "{" + << " gl_fragColor = worldPosition;" + << "}" + << "").join("\n"); + const auto es3Code = (QByteArrayList() << "#version 300 es" + << "" + << QStringLiteral("%1 highp %2 worldPosition;").arg(toGlsl(qualifierValue, es3)) + .arg(toGlsl(typeValue)) + .toUtf8() + << "" + << "void main()" + << "{" + << " gl_fragColor = worldPosition;" + << "}" + << "").join("\n"); + + QTest::addRow("%s %s ES2", qualifierName, typeName) << graph << es2 << es2Code; + QTest::addRow("%s %s ES3", qualifierName, typeName) << graph << es3 << es3Code; + QTest::addRow("%s %s GL2", qualifierName, typeName) << graph << gl2 << gl2Code; + QTest::addRow("%s %s GL3", qualifierName, typeName) << graph << gl3 << gl3Code; + QTest::addRow("%s %s GL4", qualifierName, typeName) << graph << gl4 << gl4Code; + } + } + } - for (int typeIndex = 0; typeIndex < typeEnum.keyCount(); typeIndex++) { - const auto typeName = typeEnum.key(typeIndex); - const auto typeValue = static_cast<QShaderLanguage::VariableType>(typeEnum.value(typeIndex)); + { + const auto es2 = createFormat(QShaderFormat::OpenGLES, 2, 0, QShaderFormat::Vertex); + const auto es3 = createFormat(QShaderFormat::OpenGLES, 3, 0, QShaderFormat::Vertex); + const auto gl2 = createFormat(QShaderFormat::OpenGLNoProfile, 2, 0, QShaderFormat::Vertex); + const auto gl3 = createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0, QShaderFormat::Vertex); + const auto gl4 = createFormat(QShaderFormat::OpenGLCoreProfile, 4, 0, QShaderFormat::Vertex); auto graph = QShaderGraph(); - auto worldPosition = createNode({ + auto vertexPosition = createNode({ createPort(QShaderNodePort::Output, "value") }); - worldPosition.setParameter("name", "worldPosition"); - worldPosition.setParameter("qualifier", QVariant::fromValue<QShaderLanguage::StorageQualifier>(qualifierValue)); - worldPosition.setParameter("type", QVariant::fromValue<QShaderLanguage::VariableType>(typeValue)); - worldPosition.addRule(es2, QShaderNode::Rule("highp $type $value = $name;", + vertexPosition.setParameter("name", "vertexPosition"); + vertexPosition.setParameter("qualifier", QVariant::fromValue<QShaderLanguage::StorageQualifier>(QShaderLanguage::Input)); + vertexPosition.setParameter("type", QVariant::fromValue<QShaderLanguage::VariableType>(QShaderLanguage::Vec4)); + + vertexPosition.addRule(es2, QShaderNode::Rule("", QByteArrayList() << "$qualifier highp $type $name;")); - worldPosition.addRule(gl2, QShaderNode::Rule("$type $value = $name;", + vertexPosition.addRule(gl2, QShaderNode::Rule("", QByteArrayList() << "$qualifier $type $name;")); - worldPosition.addRule(gl3, QShaderNode::Rule("$type $value = $name;", + vertexPosition.addRule(gl3, QShaderNode::Rule("", QByteArrayList() << "$qualifier $type $name;")); - auto fragColor = createNode({ - createPort(QShaderNodePort::Input, "fragColor") - }); - fragColor.addRule(es2, QShaderNode::Rule("gl_fragColor = $fragColor;")); - fragColor.addRule(gl2, QShaderNode::Rule("gl_fragColor = $fragColor;")); - fragColor.addRule(gl3, QShaderNode::Rule("fragColor = $fragColor;", - QByteArrayList() << "out vec4 fragColor;")); - - graph.addNode(worldPosition); - graph.addNode(fragColor); - - graph.addEdge(createEdge(worldPosition.uuid(), "value", fragColor.uuid(), "fragColor")); + graph.addNode(vertexPosition); const auto gl2Code = (QByteArrayList() << "#version 110" << "" - << QStringLiteral("%1 %2 worldPosition;").arg(toGlsl(qualifierValue, gl2)) - .arg(toGlsl(typeValue)) - .toUtf8() + << "attribute vec4 vertexPosition;" << "" << "void main()" << "{" - << QStringLiteral(" %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8() - << " gl_fragColor = v0;" << "}" << "").join("\n"); const auto gl3Code = (QByteArrayList() << "#version 130" << "" - << QStringLiteral("%1 %2 worldPosition;").arg(toGlsl(qualifierValue, gl3)) - .arg(toGlsl(typeValue)) - .toUtf8() - << "out vec4 fragColor;" + << "in vec4 vertexPosition;" << "" << "void main()" << "{" - << QStringLiteral(" %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8() - << " fragColor = v0;" << "}" << "").join("\n"); const auto gl4Code = (QByteArrayList() << "#version 400 core" << "" - << QStringLiteral("%1 %2 worldPosition;").arg(toGlsl(qualifierValue, gl4)) - .arg(toGlsl(typeValue)) - .toUtf8() - << "out vec4 fragColor;" + << "in vec4 vertexPosition;" << "" << "void main()" << "{" - << QStringLiteral(" %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8() - << " fragColor = v0;" << "}" << "").join("\n"); const auto es2Code = (QByteArrayList() << "#version 100" << "" - << QStringLiteral("%1 highp %2 worldPosition;").arg(toGlsl(qualifierValue, es2)) - .arg(toGlsl(typeValue)) - .toUtf8() + << "attribute highp vec4 vertexPosition;" << "" << "void main()" << "{" - << QStringLiteral(" highp %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8() - << " gl_fragColor = v0;" << "}" << "").join("\n"); const auto es3Code = (QByteArrayList() << "#version 300 es" << "" - << QStringLiteral("%1 highp %2 worldPosition;").arg(toGlsl(qualifierValue, es3)) - .arg(toGlsl(typeValue)) - .toUtf8() + << "in highp vec4 vertexPosition;" << "" << "void main()" << "{" - << QStringLiteral(" highp %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8() - << " gl_fragColor = v0;" << "}" << "").join("\n"); - QTest::addRow("%s %s ES2", qualifierName, typeName) << graph << es2 << es2Code; - QTest::addRow("%s %s ES3", qualifierName, typeName) << graph << es3 << es3Code; - QTest::addRow("%s %s GL2", qualifierName, typeName) << graph << gl2 << gl2Code; - QTest::addRow("%s %s GL3", qualifierName, typeName) << graph << gl3 << gl3Code; - QTest::addRow("%s %s GL4", qualifierName, typeName) << graph << gl4 << gl4Code; - } + QTest::addRow("Attribute header substitution ES2") << graph << es2 << es2Code; + QTest::addRow("Attribute header substitution ES3") << graph << es3 << es3Code; + QTest::addRow("Attribute header substitution GL2") << graph << gl2 << gl2Code; + QTest::addRow("Attribute header substitution GL3") << graph << gl3 << gl3Code; + QTest::addRow("Attribute header substitution GL4") << graph << gl4 << gl4Code; } } @@ -806,10 +864,7 @@ void tst_QShaderGenerator::shouldGenerateDifferentCodeDependingOnActiveLayers() << "" << "void main()" << "{" - << " vec3 v1 = normalUniform;" - << " vec4 v0 = diffuseUniform;" - << " vec4 v2 = lightModel(v0, v1);" - << " fragColor = v2;" + << " fragColor = ((lightModel(diffuseUniform, normalUniform)));" << "}" << ""; QCOMPARE(code, expected.join("\n")); @@ -831,11 +886,7 @@ void tst_QShaderGenerator::shouldGenerateDifferentCodeDependingOnActiveLayers() << "" << "void main()" << "{" - << " vec2 v0 = texCoord;" - << " vec3 v2 = texture2D(normalTexture, v0).rgb;" - << " vec4 v1 = diffuseUniform;" - << " vec4 v3 = lightModel(v1, v2);" - << " fragColor = v3;" + << " fragColor = ((lightModel(diffuseUniform, texture2D(normalTexture, texCoord).rgb)));" << "}" << ""; QCOMPARE(code, expected.join("\n")); @@ -857,11 +908,7 @@ void tst_QShaderGenerator::shouldGenerateDifferentCodeDependingOnActiveLayers() << "" << "void main()" << "{" - << " vec2 v0 = texCoord;" - << " vec3 v2 = normalUniform;" - << " vec4 v1 = texture2D(diffuseTexture, v0);" - << " vec4 v3 = lightModel(v1, v2);" - << " fragColor = v3;" + << " fragColor = ((lightModel(texture2D(diffuseTexture, texCoord), normalUniform)));" << "}" << ""; QCOMPARE(code, expected.join("\n")); @@ -883,17 +930,305 @@ void tst_QShaderGenerator::shouldGenerateDifferentCodeDependingOnActiveLayers() << "" << "void main()" << "{" - << " vec2 v0 = texCoord;" - << " vec3 v2 = texture2D(normalTexture, v0).rgb;" - << " vec4 v1 = texture2D(diffuseTexture, v0);" - << " vec4 v3 = lightModel(v1, v2);" - << " fragColor = v3;" + << " fragColor = ((lightModel(texture2D(diffuseTexture, texCoord), texture2D(normalTexture, texCoord).rgb)));" << "}" << ""; QCOMPARE(code, expected.join("\n")); } } +void tst_QShaderGenerator::shouldUseGlobalVariableRatherThanTemporaries() +{ + // GIVEN + const auto gl4 = createFormat(QShaderFormat::OpenGLCoreProfile, 4, 0); + + { + // WHEN + auto vertexPosition = createNode({ + createPort(QShaderNodePort::Output, "vertexPosition") + }); + vertexPosition.addRule(gl4, QShaderNode::Rule("vec4 $vertexPosition = vertexPosition;", + QByteArrayList() << "in vec4 vertexPosition;")); + + auto fakeMultiPlyNoSpace = createNode({ + createPort(QShaderNodePort::Input, "varName"), + createPort(QShaderNodePort::Output, "out") + }); + fakeMultiPlyNoSpace.addRule(gl4, QShaderNode::Rule("vec4 $out = $varName*speed;")); + + auto fakeMultiPlySpace = createNode({ + createPort(QShaderNodePort::Input, "varName"), + createPort(QShaderNodePort::Output, "out") + }); + fakeMultiPlySpace.addRule(gl4, QShaderNode::Rule("vec4 $out = $varName * speed;")); + + auto fakeJoinNoSpace = createNode({ + createPort(QShaderNodePort::Input, "varName"), + createPort(QShaderNodePort::Output, "out") + }); + fakeJoinNoSpace.addRule(gl4, QShaderNode::Rule("vec4 $out = vec4($varName.xyz,$varName.w);")); + + auto fakeJoinSpace = createNode({ + createPort(QShaderNodePort::Input, "varName"), + createPort(QShaderNodePort::Output, "out") + }); + fakeJoinSpace.addRule(gl4, QShaderNode::Rule("vec4 $out = vec4($varName.xyz, $varName.w);")); + + auto fakeAdd = createNode({ + createPort(QShaderNodePort::Input, "varName"), + createPort(QShaderNodePort::Output, "out") + }); + fakeAdd.addRule(gl4, QShaderNode::Rule("vec4 $out = $varName.xyzw + $varName;")); + + auto fakeSub = createNode({ + createPort(QShaderNodePort::Input, "varName"), + createPort(QShaderNodePort::Output, "out") + }); + fakeSub.addRule(gl4, QShaderNode::Rule("vec4 $out = $varName.xyzw - $varName;")); + + auto fakeDiv = createNode({ + createPort(QShaderNodePort::Input, "varName"), + createPort(QShaderNodePort::Output, "out") + }); + fakeDiv.addRule(gl4, QShaderNode::Rule("vec4 $out = $varName / v0;")); + + auto fragColor = createNode({ + createPort(QShaderNodePort::Input, "input1"), + createPort(QShaderNodePort::Input, "input2"), + createPort(QShaderNodePort::Input, "input3"), + createPort(QShaderNodePort::Input, "input4"), + createPort(QShaderNodePort::Input, "input5"), + createPort(QShaderNodePort::Input, "input6"), + createPort(QShaderNodePort::Input, "input7") + }); + fragColor.addRule(gl4, QShaderNode::Rule("fragColor = $input1 + $input2 + $input3 + $input4 + $input5 + $input6 + $input7;", + QByteArrayList() << "out vec4 fragColor;")); + + const auto graph = [=] { + auto res = QShaderGraph(); + + res.addNode(vertexPosition); + res.addNode(fakeMultiPlyNoSpace); + res.addNode(fakeMultiPlySpace); + res.addNode(fakeJoinNoSpace); + res.addNode(fakeJoinSpace); + res.addNode(fakeAdd); + res.addNode(fakeSub); + res.addNode(fakeDiv); + res.addNode(fragColor); + + res.addEdge(createEdge(vertexPosition.uuid(), "vertexPosition", fakeMultiPlyNoSpace.uuid(), "varName")); + res.addEdge(createEdge(vertexPosition.uuid(), "vertexPosition", fakeMultiPlySpace.uuid(), "varName")); + res.addEdge(createEdge(vertexPosition.uuid(), "vertexPosition", fakeJoinNoSpace.uuid(), "varName")); + res.addEdge(createEdge(vertexPosition.uuid(), "vertexPosition", fakeJoinSpace.uuid(), "varName")); + res.addEdge(createEdge(vertexPosition.uuid(), "vertexPosition", fakeAdd.uuid(), "varName")); + res.addEdge(createEdge(vertexPosition.uuid(), "vertexPosition", fakeSub.uuid(), "varName")); + res.addEdge(createEdge(vertexPosition.uuid(), "vertexPosition", fakeDiv.uuid(), "varName")); + res.addEdge(createEdge(fakeMultiPlyNoSpace.uuid(), "out", fragColor.uuid(), "input1")); + res.addEdge(createEdge(fakeMultiPlySpace.uuid(), "out", fragColor.uuid(), "input2")); + res.addEdge(createEdge(fakeJoinNoSpace.uuid(), "out", fragColor.uuid(), "input3")); + res.addEdge(createEdge(fakeJoinSpace.uuid(), "out", fragColor.uuid(), "input4")); + res.addEdge(createEdge(fakeAdd.uuid(), "out", fragColor.uuid(), "input5")); + res.addEdge(createEdge(fakeSub.uuid(), "out", fragColor.uuid(), "input6")); + res.addEdge(createEdge(fakeDiv.uuid(), "out", fragColor.uuid(), "input7")); + + return res; + }(); + + auto generator = QShaderGenerator(); + generator.graph = graph; + generator.format = gl4; + + const auto code = generator.createShaderCode({"diffuseUniform", "normalUniform"}); + + // THEN + const auto expected = QByteArrayList() + << "#version 400 core" + << "" + << "in vec4 vertexPosition;" + << "out vec4 fragColor;" + << "" + << "void main()" + << "{" + << " fragColor = (((((((vertexPosition*speed + vertexPosition * speed + ((vec4(vertexPosition.xyz,vertexPosition.w))) + ((vec4(vertexPosition.xyz, vertexPosition.w))) + ((vertexPosition.xyzw + vertexPosition)) + ((vertexPosition.xyzw - vertexPosition)) + ((vertexPosition / vertexPosition)))))))));" + << "}" + << ""; + QCOMPARE(code, expected.join("\n")); + } +} + +void tst_QShaderGenerator::shouldGenerateTemporariesWisely() +{ + // GIVEN + const auto gl4 = createFormat(QShaderFormat::OpenGLCoreProfile, 4, 0); + + { + auto attribute = createNode({ + createPort(QShaderNodePort::Output, "vertexPosition") + }); + attribute.addRule(gl4, QShaderNode::Rule("vec4 $vertexPosition = vertexPosition;", + QByteArrayList() << "in vec4 vertexPosition;")); + + auto complexFunction = createNode({ + createPort(QShaderNodePort::Input, "inputVarName"), + createPort(QShaderNodePort::Output, "out") + }); + complexFunction.addRule(gl4, QShaderNode::Rule("vec4 $out = $inputVarName * 2.0;")); + + auto complexFunction2 = createNode({ + createPort(QShaderNodePort::Input, "inputVarName"), + createPort(QShaderNodePort::Output, "out") + }); + complexFunction2.addRule(gl4, QShaderNode::Rule("vec4 $out = $inputVarName * 4.0;")); + + auto complexFunction3 = createNode({ + createPort(QShaderNodePort::Input, "a"), + createPort(QShaderNodePort::Input, "b"), + createPort(QShaderNodePort::Output, "out") + }); + complexFunction3.addRule(gl4, QShaderNode::Rule("vec4 $out = $a + $b;")); + + auto shaderOutput1 = createNode({ + createPort(QShaderNodePort::Input, "input") + }); + + shaderOutput1.addRule(gl4, QShaderNode::Rule("shaderOutput1 = $input;", + QByteArrayList() << "out vec4 shaderOutput1;")); + + auto shaderOutput2 = createNode({ + createPort(QShaderNodePort::Input, "input") + }); + + shaderOutput2.addRule(gl4, QShaderNode::Rule("shaderOutput2 = $input;", + QByteArrayList() << "out vec4 shaderOutput2;")); + + { + // WHEN + const auto graph = [=] { + auto res = QShaderGraph(); + + res.addNode(attribute); + res.addNode(complexFunction); + res.addNode(shaderOutput1); + + res.addEdge(createEdge(attribute.uuid(), "vertexPosition", complexFunction.uuid(), "inputVarName")); + res.addEdge(createEdge(complexFunction.uuid(), "out", shaderOutput1.uuid(), "input")); + + return res; + }(); + + auto generator = QShaderGenerator(); + generator.graph = graph; + generator.format = gl4; + + const auto code = generator.createShaderCode(); + + // THEN + const auto expected = QByteArrayList() + << "#version 400 core" + << "" + << "in vec4 vertexPosition;" + << "out vec4 shaderOutput1;" + << "" + << "void main()" + << "{" + << " shaderOutput1 = vertexPosition * 2.0;" + << "}" + << ""; + QCOMPARE(code, expected.join("\n")); + } + + { + // WHEN + const auto graph = [=] { + auto res = QShaderGraph(); + + res.addNode(attribute); + res.addNode(complexFunction); + res.addNode(shaderOutput1); + res.addNode(shaderOutput2); + + res.addEdge(createEdge(attribute.uuid(), "vertexPosition", complexFunction.uuid(), "inputVarName")); + res.addEdge(createEdge(complexFunction.uuid(), "out", shaderOutput1.uuid(), "input")); + res.addEdge(createEdge(complexFunction.uuid(), "out", shaderOutput2.uuid(), "input")); + + return res; + }(); + + auto generator = QShaderGenerator(); + generator.graph = graph; + generator.format = gl4; + + const auto code = generator.createShaderCode(); + + // THEN + const auto expected = QByteArrayList() + << "#version 400 core" + << "" + << "in vec4 vertexPosition;" + << "out vec4 shaderOutput1;" + << "out vec4 shaderOutput2;" + << "" + << "void main()" + << "{" + << " vec4 v1 = vertexPosition * 2.0;" + << " shaderOutput2 = v1;" + << " shaderOutput1 = v1;" + << "}" + << ""; + QCOMPARE(code, expected.join("\n")); + } + + { + // WHEN + const auto graph = [=] { + auto res = QShaderGraph(); + + res.addNode(attribute); + res.addNode(complexFunction); + res.addNode(complexFunction2); + res.addNode(complexFunction3); + res.addNode(shaderOutput1); + res.addNode(shaderOutput2); + + res.addEdge(createEdge(attribute.uuid(), "vertexPosition", complexFunction.uuid(), "inputVarName")); + res.addEdge(createEdge(attribute.uuid(), "vertexPosition", complexFunction2.uuid(), "inputVarName")); + + res.addEdge(createEdge(complexFunction.uuid(), "out", complexFunction3.uuid(), "a")); + res.addEdge(createEdge(complexFunction2.uuid(), "out", complexFunction3.uuid(), "b")); + + res.addEdge(createEdge(complexFunction3.uuid(), "out", shaderOutput1.uuid(), "input")); + res.addEdge(createEdge(complexFunction2.uuid(), "out", shaderOutput2.uuid(), "input")); + + return res; + }(); + + auto generator = QShaderGenerator(); + generator.graph = graph; + generator.format = gl4; + + const auto code = generator.createShaderCode(); + + // THEN + const auto expected = QByteArrayList() + << "#version 400 core" + << "" + << "in vec4 vertexPosition;" + << "out vec4 shaderOutput1;" + << "out vec4 shaderOutput2;" + << "" + << "void main()" + << "{" + << " vec4 v2 = vertexPosition * 4.0;" + << " shaderOutput2 = v2;" + << " shaderOutput1 = (vertexPosition * 2.0 + v2);" + << "}" + << ""; + QCOMPARE(code, expected.join("\n")); + } + } +} + QTEST_MAIN(tst_QShaderGenerator) #include "tst_qshadergenerator.moc" |