QWidgetBaselineTest: Add QStyle widget baseline test

Change-Id: I2858baccb09ebf336ab7c2cde7efeb09aca6ef53
Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
This commit is contained in:
Tor Arne Vestbø 2025-08-08 16:49:48 +02:00
parent 3a3024e6ea
commit d23da67304
4 changed files with 291 additions and 1 deletions

View File

@ -8,4 +8,5 @@ if(TARGET Qt::Network AND TARGET Qt::Widgets)
add_subdirectory(widgets)
add_subdirectory(stylesheet)
add_subdirectory(text)
add_subdirectory(styles)
endif()

View File

@ -28,7 +28,7 @@ protected:
virtual void doInit() {}
virtual void doCleanup() {}
private slots:
protected slots:
void initTestCase();
void init();
void cleanup();

View File

@ -0,0 +1,23 @@
# Copyright (C) 2025 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
cmake_minimum_required(VERSION 3.16)
project(tst_baseline_styles LANGUAGES CXX)
find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
endif()
qt_internal_add_test(tst_baseline_styles
SOURCES
../shared/baselineprotocol.cpp ../shared/baselineprotocol.h ../shared/lookup3.cpp
../shared/qbaselinetest.cpp ../shared/qbaselinetest.h
../shared/qwidgetbaselinetest.cpp ../shared/qwidgetbaselinetest.h
tst_baseline_styles.cpp
INCLUDE_DIRECTORIES
../shared
LIBRARIES
Qt::Gui
Qt::Widgets
Qt::WidgetsPrivate
Qt::Network
)

View File

@ -0,0 +1,266 @@
// Copyright (C) 2025 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <qbaselinetest.h>
#include <qwidgetbaselinetest.h>
#include <QtWidgets>
class tst_QStyles : public QWidgetBaselineTest
{
Q_OBJECT
public:
tst_QStyles() = default;
private slots:
void initTestCase_data();
void drawPrimitive_data();
void drawPrimitive();
void drawControl_data();
void drawControl();
void drawComplexControl_data();
void drawComplexControl();
private:
void doInit() override;
template <typename E>
void addData();
template <typename Func, typename StyleOption>
void testStyle(Func&& func, StyleOption *styleOption, const char *name);
};
#define QBASELINE_CHECK_STYLE(name) \
testStyle([&](auto *style, auto *styleOption, auto *painter, QWidget *widget) { \
(style->*drawFunction)(styleElement, styleOption, painter, widget); \
}, styleOption.get(), name);
void tst_QStyles::initTestCase_data()
{
// FIXME: Check all styles via global data when baseline tests support global tags
}
void tst_QStyles::doInit()
{
testWindow()->resize(140, 140);
}
void tst_QStyles::drawPrimitive_data()
{
addData<QStyle::PrimitiveElement>();
}
QStyleOption *styleOptionFor(QStyle::PrimitiveElement element)
{
switch (element) {
case QStyle::PE_FrameTabBarBase:
return new QStyleOptionTabBarBase();
case QStyle::PE_IndicatorHeaderArrow:
return new QStyleOptionHeader();
case QStyle::PE_IndicatorCheckBox:
case QStyle::PE_PanelButtonCommand:
return new QStyleOptionFocusRect();
case QStyle::PE_FrameFocusRect:
return new QStyleOptionFocusRect();
case QStyle::PE_Frame:
case QStyle::PE_FrameMenu:
case QStyle::PE_PanelMenuBar:
case QStyle::PE_FrameGroupBox:
case QStyle::PE_FrameDockWidget:
case QStyle::PE_PanelLineEdit:
case QStyle::PE_FrameLineEdit:
case QStyle::PE_FrameWindow:
case QStyle::PE_FrameButtonBevel:
case QStyle::PE_FrameButtonTool:
return new QStyleOptionFrame();
case QStyle::PE_FrameTabWidget:
return new QStyleOptionTabWidgetFrame();
case QStyle::PE_IndicatorTabTear:
return new QStyleOptionTab();
case QStyle::PE_IndicatorColumnViewArrow:
case QStyle::PE_PanelItemViewRow:
case QStyle::PE_PanelItemViewItem:
case QStyle::PE_IndicatorItemViewItemCheck:
return new QStyleOptionViewItem();
default:
return new QStyleOption();
};
}
void tst_QStyles::drawPrimitive()
{
QFETCH(QStyle::PrimitiveElement, styleElement);
auto drawFunction = &QStyle::drawPrimitive;
std::unique_ptr<QStyleOption> styleOption(styleOptionFor(styleElement));
styleOption->initFrom(testWindow());
QBASELINE_CHECK_STYLE("default");
if (auto *headerOption = qstyleoption_cast<QStyleOptionHeader*>(styleOption.get())) {
headerOption->sortIndicator = QStyleOptionHeader::SortDown;
QBASELINE_CHECK_STYLE("down");
headerOption->sortIndicator = QStyleOptionHeader::SortUp;
QBASELINE_CHECK_STYLE("up");
}
}
void tst_QStyles::drawControl_data()
{
addData<QStyle::ControlElement>();
}
QStyleOption *styleOptionFor(QStyle::ControlElement element)
{
switch (element) {
case QStyle::CE_PushButton:
case QStyle::CE_PushButtonBevel:
case QStyle::CE_PushButtonLabel:
case QStyle::CE_RadioButton:
case QStyle::CE_RadioButtonLabel:
case QStyle::CE_CheckBox:
case QStyle::CE_CheckBoxLabel: {
auto *buttonStyle = new QStyleOptionButton;
buttonStyle->text = QString("Hello");
return buttonStyle;
}
case QStyle::CE_MenuBarItem:
return new QStyleOptionMenuItem;
case QStyle::CE_ProgressBar:
case QStyle::CE_ProgressBarLabel:
case QStyle::CE_ProgressBarContents:
return new QStyleOptionProgressBar;
case QStyle::CE_Header:
case QStyle::CE_HeaderLabel:
case QStyle::CE_HeaderSection:
return new QStyleOptionHeader;
case QStyle::CE_ToolButtonLabel:
return new QStyleOptionToolButton;
case QStyle::CE_ToolBoxTab:
case QStyle::CE_ToolBoxTabShape:
case QStyle::CE_ToolBoxTabLabel:
return new QStyleOptionToolBox;
case QStyle::CE_TabBarTab:
case QStyle::CE_TabBarTabShape:
case QStyle::CE_TabBarTabLabel:
return new QStyleOptionTab;
case QStyle::CE_RubberBand:
return new QStyleOptionRubberBand;
case QStyle::CE_DockWidgetTitle:
return new QStyleOptionDockWidget;
case QStyle::CE_ComboBoxLabel:
return new QStyleOptionComboBox;
case QStyle::CE_ToolBar:
return new QStyleOptionToolBar;
case QStyle::CE_ItemViewItem:
return new QStyleOptionViewItem;
case QStyle::CE_ShapedFrame:
return new QStyleOptionFrame;
default:
return new QStyleOption;
};
}
void tst_QStyles::drawControl()
{
QFETCH(QStyle::ControlElement, styleElement);
auto drawFunction = &QStyle::drawControl;
std::unique_ptr<QStyleOption> styleOption(styleOptionFor(styleElement));
styleOption->state = QStyle::State_Active
| QStyle::State_Enabled
| QStyle::State_HasFocus
| QStyle::State_On;
QBASELINE_CHECK_STYLE("default");
}
void tst_QStyles::drawComplexControl_data()
{
addData<QStyle::ComplexControl>();
}
QStyleOptionComplex *styleOptionFor(QStyle::ComplexControl element)
{
switch (element) {
case QStyle::CC_Slider:
case QStyle::CC_ScrollBar:
return new QStyleOptionSlider();
case QStyle::CC_ToolButton:
return new QStyleOptionToolButton();
case QStyle::CC_SpinBox:
return new QStyleOptionSpinBox();
case QStyle::CC_TitleBar:
return new QStyleOptionTitleBar();
case QStyle::CC_ComboBox:
return new QStyleOptionComboBox();
case QStyle::CC_GroupBox:
return new QStyleOptionGroupBox();
default:
return new QStyleOptionComplex();
};
}
void tst_QStyles::drawComplexControl()
{
QFETCH(QStyle::ComplexControl, styleElement);
auto drawFunction = &QStyle::drawComplexControl;
std::unique_ptr<QStyleOptionComplex> styleOption(styleOptionFor(styleElement));
styleOption->initFrom(testWindow());
styleOption->subControls = QStyle::SC_All;
QBASELINE_CHECK_STYLE("default");
}
template <typename E>
void tst_QStyles::addData()
{
auto metaEnum = QMetaEnum::fromType<E>();
QTest::addColumn<E>("styleElement");
for (int i = 0; i < metaEnum.keyCount() - 1; ++i) {
auto value = E(metaEnum.value(i));
QTest::newRow(metaEnum.key(i)) << value;
}
}
template <typename Func, typename StyleOption>
void tst_QStyles::testStyle(Func&& drawFunc, StyleOption *styleOption, const char *name)
{
QStyle *style = qApp->style();
QWidget *w = testWindow();
const auto dpr = w->devicePixelRatio();
const auto size = w->size();
QImage image(size * dpr, QImage::Format_ARGB32_Premultiplied);
image.setDevicePixelRatio(dpr);
QPainter painter(&image);
QBrush checkerboardBackground = w->parentWidget()->palette().brush(QPalette::Window);
painter.fillRect(QRect({}, size), checkerboardBackground);
styleOption->rect = w->rect() -= QMargins(20, 20, 20, 20);
drawFunc(style, styleOption, &painter, w);
painter.end();
if (!debugRects.isEmpty()) {
QJsonDocument doc(debugRects);
image.setText("DebugRects", doc.toJson(QJsonDocument::Compact));
}
QBASELINE_CHECK(image, name);
}
QBASELINETEST_MAIN(tst_QStyles)
#include "tst_baseline_styles.moc"