Merge remote-tracking branch 'origin/5.14' into 5.15
Conflicts: tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp Change-Id: Ifaa56153f5f0d687a6b4d94f84fcfa1e1751afd2
This commit is contained in:
commit
947e1f45c7
@ -3,8 +3,9 @@ QT_FOR_CONFIG += gui
|
|||||||
defineTest(prependOpenGlLib) {
|
defineTest(prependOpenGlLib) {
|
||||||
path = $$QT.core.libs/$$QMAKE_PREFIX_STATICLIB$$1
|
path = $$QT.core.libs/$$QMAKE_PREFIX_STATICLIB$$1
|
||||||
ext = .$$QMAKE_EXTENSION_STATICLIB
|
ext = .$$QMAKE_EXTENSION_STATICLIB
|
||||||
|
!mingw|qtConfig(debug_and_release): debug_suffix = "d"
|
||||||
QMAKE_LIBS_OPENGL_ES2 = $${path}$${ext} $$QMAKE_LIBS_OPENGL_ES2
|
QMAKE_LIBS_OPENGL_ES2 = $${path}$${ext} $$QMAKE_LIBS_OPENGL_ES2
|
||||||
QMAKE_LIBS_OPENGL_ES2_DEBUG = $${path}d$${ext} $$QMAKE_LIBS_OPENGL_ES2_DEBUG
|
QMAKE_LIBS_OPENGL_ES2_DEBUG = $${path}$${debug_suffix}$${ext} $$QMAKE_LIBS_OPENGL_ES2_DEBUG
|
||||||
export(QMAKE_LIBS_OPENGL_ES2)
|
export(QMAKE_LIBS_OPENGL_ES2)
|
||||||
export(QMAKE_LIBS_OPENGL_ES2_DEBUG)
|
export(QMAKE_LIBS_OPENGL_ES2_DEBUG)
|
||||||
}
|
}
|
||||||
|
37
src/3rdparty/tinycbor/tests/parser/data.cpp
vendored
37
src/3rdparty/tinycbor/tests/parser/data.cpp
vendored
@ -338,7 +338,7 @@ void addValidationColumns()
|
|||||||
QTest::addColumn<CborError>("expectedError");
|
QTest::addColumn<CborError>("expectedError");
|
||||||
}
|
}
|
||||||
|
|
||||||
void addValidationData()
|
void addValidationData(size_t minInvalid = ~size_t(0))
|
||||||
{
|
{
|
||||||
// illegal numbers are future extension points
|
// illegal numbers are future extension points
|
||||||
QTest::newRow("illegal-number-in-unsigned-1") << raw("\x81\x1c") << 0 << CborErrorIllegalNumber;
|
QTest::newRow("illegal-number-in-unsigned-1") << raw("\x81\x1c") << 0 << CborErrorIllegalNumber;
|
||||||
@ -488,26 +488,35 @@ void addValidationData()
|
|||||||
QTest::newRow("map-break-after-value-tag2") << raw("\x81\xbf\0\xd8\x20\xff") << 0 << CborErrorUnexpectedBreak;
|
QTest::newRow("map-break-after-value-tag2") << raw("\x81\xbf\0\xd8\x20\xff") << 0 << CborErrorUnexpectedBreak;
|
||||||
|
|
||||||
// check for pointer additions wrapping over the limit of the address space
|
// check for pointer additions wrapping over the limit of the address space
|
||||||
CborError tooLargeOn32bit = (sizeof(void *) == 4) ? CborErrorDataTooLarge : CborErrorUnexpectedEOF;
|
auto wraparoundError = [minInvalid](uint64_t encodedSize) {
|
||||||
|
if (encodedSize > minInvalid)
|
||||||
|
return CborErrorDataTooLarge;
|
||||||
|
return CborErrorUnexpectedEOF;
|
||||||
|
};
|
||||||
|
constexpr uint64_t FourGB = UINT32_MAX + UINT64_C(1);
|
||||||
// on 32-bit systems, this is a -1
|
// on 32-bit systems, this is a -1
|
||||||
QTest::newRow("bytearray-wraparound1") << raw("\x81\x5a\xff\xff\xff\xff") << 0 << CborErrorUnexpectedEOF;
|
QTest::newRow("bytearray-wraparound1") << raw("\x81\x5a\xff\xff\xff\xff") << 0 << wraparoundError(UINT32_MAX);
|
||||||
QTest::newRow("string-wraparound1") << raw("\x81\x7a\xff\xff\xff\xff") << 0 << CborErrorUnexpectedEOF;
|
QTest::newRow("string-wraparound1") << raw("\x81\x7a\xff\xff\xff\xff") << 0 << wraparoundError(UINT32_MAX);
|
||||||
// on 32-bit systems, a 4GB addition could be dropped
|
// on 32-bit systems, a 4GB addition could be dropped
|
||||||
QTest::newRow("bytearray-wraparound2") << raw("\x81\x5b\0\0\0\1\0\0\0\0") << 0 << tooLargeOn32bit;
|
QTest::newRow("bytearray-wraparound2") << raw("\x81\x5b\0\0\0\1\0\0\0\0") << 0 << wraparoundError(FourGB);
|
||||||
QTest::newRow("string-wraparound2") << raw("\x81\x7b\0\0\0\1\0\0\0\0") << 0 << tooLargeOn32bit;
|
QTest::newRow("string-wraparound2") << raw("\x81\x7b\0\0\0\1\0\0\0\0") << 0 << wraparoundError(FourGB);
|
||||||
// on 64-bit systems, this could be a -1
|
// on 64-bit systems, this could be a -1
|
||||||
QTest::newRow("bytearray-wraparound3") << raw("\x81\x5b\xff\xff\xff\xff\xff\xff\xff\xff") << 0 << tooLargeOn32bit;
|
QTest::newRow("bytearray-wraparound3") << raw("\x81\x5b\xff\xff\xff\xff\xff\xff\xff\xff") << 0
|
||||||
QTest::newRow("string-wraparound3") << raw("\x81\x7b\xff\xff\xff\xff\xff\xff\xff\xff") << 0 << tooLargeOn32bit;
|
<< wraparoundError(UINT64_MAX);
|
||||||
|
QTest::newRow("string-wraparound3") << raw("\x81\x7b\xff\xff\xff\xff\xff\xff\xff\xff") << 0
|
||||||
|
<< wraparoundError(UINT64_MAX);
|
||||||
|
|
||||||
// ditto on chunks
|
// ditto on chunks
|
||||||
QTest::newRow("bytearray-chunk-wraparound1") << raw("\x81\x5f\x5a\xff\xff\xff\xff") << 0 << CborErrorUnexpectedEOF;
|
QTest::newRow("bytearray-chunk-wraparound1") << raw("\x81\x5f\x5a\xff\xff\xff\xff") << 0 << wraparoundError(UINT32_MAX);
|
||||||
QTest::newRow("string-chunk-wraparound1") << raw("\x81\x7f\x7a\xff\xff\xff\xff") << 0 << CborErrorUnexpectedEOF;
|
QTest::newRow("string-chunk-wraparound1") << raw("\x81\x7f\x7a\xff\xff\xff\xff") << 0 << wraparoundError(UINT32_MAX);
|
||||||
// on 32-bit systems, a 4GB addition could be dropped
|
// on 32-bit systems, a 4GB addition could be dropped
|
||||||
QTest::newRow("bytearray-chunk-wraparound2") << raw("\x81\x5f\x5b\0\0\0\1\0\0\0\0") << 0 << tooLargeOn32bit;
|
QTest::newRow("bytearray-chunk-wraparound2") << raw("\x81\x5f\x5b\0\0\0\1\0\0\0\0") << 0 << wraparoundError(FourGB);
|
||||||
QTest::newRow("string-chunk-wraparound2") << raw("\x81\x7f\x7b\0\0\0\1\0\0\0\0") << 0 << tooLargeOn32bit;
|
QTest::newRow("string-chunk-wraparound2") << raw("\x81\x7f\x7b\0\0\0\1\0\0\0\0") << 0 << wraparoundError(FourGB);
|
||||||
// on 64-bit systems, this could be a -1
|
// on 64-bit systems, this could be a -1
|
||||||
QTest::newRow("bytearray-chunk-wraparound3") << raw("\x81\x5f\x5b\xff\xff\xff\xff\xff\xff\xff\xff") << 0 << tooLargeOn32bit;
|
QTest::newRow("bytearray-chunk-wraparound3") << raw("\x81\x5f\x5b\xff\xff\xff\xff\xff\xff\xff\xff") << 0
|
||||||
QTest::newRow("string-chunk-wraparound3") << raw("\x81\x7f\x7b\xff\xff\xff\xff\xff\xff\xff\xff") << 0 << tooLargeOn32bit;
|
<< wraparoundError(UINT64_MAX);
|
||||||
|
QTest::newRow("string-chunk-wraparound3") << raw("\x81\x7f\x7b\xff\xff\xff\xff\xff\xff\xff\xff") << 0
|
||||||
|
<< wraparoundError(UINT64_MAX);
|
||||||
|
|
||||||
QTest::newRow("eof-after-array") << raw("\x81") << 0 << CborErrorUnexpectedEOF;
|
QTest::newRow("eof-after-array") << raw("\x81") << 0 << CborErrorUnexpectedEOF;
|
||||||
QTest::newRow("eof-after-array2") << raw("\x81\x78\x20") << 0 << CborErrorUnexpectedEOF;
|
QTest::newRow("eof-after-array2") << raw("\x81\x78\x20") << 0 << CborErrorUnexpectedEOF;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
**
|
**
|
||||||
** Copyright (C) 2018 Intel Corporation.
|
** Copyright (C) 2020 Intel Corporation.
|
||||||
** Contact: https://www.qt.io/licensing/
|
** Contact: https://www.qt.io/licensing/
|
||||||
**
|
**
|
||||||
** This file is part of the QtCore module of the Qt Toolkit.
|
** This file is part of the QtCore module of the Qt Toolkit.
|
||||||
@ -42,6 +42,7 @@
|
|||||||
#define CBOR_NO_ENCODER_API
|
#define CBOR_NO_ENCODER_API
|
||||||
#include <private/qcborcommon_p.h>
|
#include <private/qcborcommon_p.h>
|
||||||
|
|
||||||
|
#include <private/qbytearray_p.h>
|
||||||
#include <private/qnumeric_p.h>
|
#include <private/qnumeric_p.h>
|
||||||
#include <private/qutfcodec_p.h>
|
#include <private/qutfcodec_p.h>
|
||||||
#include <qdebug.h>
|
#include <qdebug.h>
|
||||||
@ -1055,6 +1056,10 @@ bool QCborStreamReader::next(int maxRecursion)
|
|||||||
} else if (isString() || isByteArray()) {
|
} else if (isString() || isByteArray()) {
|
||||||
auto r = _readByteArray_helper();
|
auto r = _readByteArray_helper();
|
||||||
while (r.status == Ok) {
|
while (r.status == Ok) {
|
||||||
|
if (isString() && r.data.size() > MaxStringSize) {
|
||||||
|
d->handleError(CborErrorDataTooLarge);
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (isString() && !QUtf8::isValidUtf8(r.data, r.data.size()).isValidUtf8) {
|
if (isString() && !QUtf8::isValidUtf8(r.data, r.data.size()).isValidUtf8) {
|
||||||
d->handleError(CborErrorInvalidUtf8TextString);
|
d->handleError(CborErrorInvalidUtf8TextString);
|
||||||
break;
|
break;
|
||||||
@ -1337,15 +1342,23 @@ QCborStreamReader::StringResult<QString> QCborStreamReader::_readString_helper()
|
|||||||
result.status = r.status;
|
result.status = r.status;
|
||||||
|
|
||||||
if (r.status == Ok) {
|
if (r.status == Ok) {
|
||||||
|
// See QUtf8::convertToUnicode() a detailed explanation of why this
|
||||||
|
// conversion uses the same number of words or less.
|
||||||
|
CborError err = CborNoError;
|
||||||
|
if (r.data.size() > MaxStringSize) {
|
||||||
|
err = CborErrorDataTooLarge;
|
||||||
|
} else {
|
||||||
QTextCodec::ConverterState cs;
|
QTextCodec::ConverterState cs;
|
||||||
result.data = QUtf8::convertToUnicode(r.data, r.data.size(), &cs);
|
result.data = QUtf8::convertToUnicode(r.data, r.data.size(), &cs);
|
||||||
if (cs.invalidChars == 0 && cs.remainingChars == 0)
|
if (cs.invalidChars != 0 || cs.remainingChars != 0)
|
||||||
return result;
|
err = CborErrorInvalidUtf8TextString;
|
||||||
|
}
|
||||||
|
|
||||||
d->handleError(CborErrorInvalidUtf8TextString);
|
if (err) {
|
||||||
|
d->handleError(err);
|
||||||
result.data.clear();
|
result.data.clear();
|
||||||
result.status = Error;
|
result.status = Error;
|
||||||
return result;
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -1373,6 +1386,10 @@ QCborStreamReader::StringResult<QByteArray> QCborStreamReader::_readByteArray_he
|
|||||||
qsizetype len = _currentStringChunkSize();
|
qsizetype len = _currentStringChunkSize();
|
||||||
if (len < 0)
|
if (len < 0)
|
||||||
return result;
|
return result;
|
||||||
|
if (len > MaxByteArraySize) {
|
||||||
|
d->handleError(CborErrorDataTooLarge);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
result.data.resize(len);
|
result.data.resize(len);
|
||||||
auto r = readStringChunk(result.data.data(), len);
|
auto r = readStringChunk(result.data.data(), len);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
**
|
**
|
||||||
** Copyright (C) 2018 Intel Corporation.
|
** Copyright (C) 2020 Intel Corporation.
|
||||||
** Contact: https://www.qt.io/licensing/
|
** Contact: https://www.qt.io/licensing/
|
||||||
**
|
**
|
||||||
** This file is part of the QtCore module of the Qt Toolkit.
|
** This file is part of the QtCore module of the Qt Toolkit.
|
||||||
@ -53,6 +53,7 @@
|
|||||||
|
|
||||||
#include <qendian.h>
|
#include <qendian.h>
|
||||||
#include <qlocale.h>
|
#include <qlocale.h>
|
||||||
|
#include <private/qbytearray_p.h>
|
||||||
#include <private/qnumeric_p.h>
|
#include <private/qnumeric_p.h>
|
||||||
#include <private/qsimd_p.h>
|
#include <private/qsimd_p.h>
|
||||||
|
|
||||||
@ -1553,6 +1554,8 @@ void QCborContainerPrivate::decodeStringFromCbor(QCborStreamReader &reader)
|
|||||||
// and calculate the final size
|
// and calculate the final size
|
||||||
if (add_overflow(offset, increment, &newSize))
|
if (add_overflow(offset, increment, &newSize))
|
||||||
return -1;
|
return -1;
|
||||||
|
if (newSize > MaxByteArraySize)
|
||||||
|
return -1;
|
||||||
|
|
||||||
// since usedData <= data.size(), this can't overflow
|
// since usedData <= data.size(), this can't overflow
|
||||||
usedData += increment;
|
usedData += increment;
|
||||||
@ -1627,13 +1630,6 @@ void QCborContainerPrivate::decodeStringFromCbor(QCborStreamReader &reader)
|
|||||||
setErrorInReader(reader, { QCborError::DataTooLarge });
|
setErrorInReader(reader, { QCborError::DataTooLarge });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r.status == QCborStreamReader::Error) {
|
|
||||||
// There can only be errors if there was data to be read.
|
|
||||||
Q_ASSERT(e.flags & Element::HasByteData);
|
|
||||||
data.truncate(e.value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// update size
|
// update size
|
||||||
if (e.flags & Element::HasByteData) {
|
if (e.flags & Element::HasByteData) {
|
||||||
auto b = new (dataPtr() + e.value) ByteData;
|
auto b = new (dataPtr() + e.value) ByteData;
|
||||||
@ -1645,6 +1641,21 @@ void QCborContainerPrivate::decodeStringFromCbor(QCborStreamReader &reader)
|
|||||||
Q_ASSERT(e.type == QCborValue::String);
|
Q_ASSERT(e.type == QCborValue::String);
|
||||||
e.flags |= Element::StringIsAscii;
|
e.flags |= Element::StringIsAscii;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check that this UTF-8 text string can be loaded onto a QString
|
||||||
|
if (e.type == QCborValue::String) {
|
||||||
|
if (Q_UNLIKELY(b->len > MaxStringSize)) {
|
||||||
|
setErrorInReader(reader, { QCborError::DataTooLarge });
|
||||||
|
r.status = QCborStreamReader::Error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r.status == QCborStreamReader::Error) {
|
||||||
|
// There can only be errors if there was data to be read.
|
||||||
|
Q_ASSERT(e.flags & Element::HasByteData);
|
||||||
|
data.truncate(e.value);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
elements.append(e);
|
elements.append(e);
|
||||||
|
@ -56,10 +56,9 @@
|
|||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
enum {
|
// -1 because of the terminating NUL
|
||||||
// Define as enum to force inlining. Don't expose MaxAllocSize in a public header.
|
constexpr qsizetype MaxByteArraySize = MaxAllocSize - sizeof(std::remove_pointer<QByteArray::DataPtr>::type) - 1;
|
||||||
MaxByteArraySize = MaxAllocSize - sizeof(std::remove_pointer<QByteArray::DataPtr>::type)
|
constexpr qsizetype MaxStringSize = (MaxAllocSize - sizeof(std::remove_pointer<QByteArray::DataPtr>::type)) / 2 - 1;
|
||||||
};
|
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
@ -288,6 +288,12 @@ QAbstractItemModelTester::FailureReportingMode QAbstractItemModelTester::failure
|
|||||||
return d->failureReportingMode;
|
return d->failureReportingMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool QAbstractItemModelTester::verify(bool statement, const char *statementStr, const char *description, const char *file, int line)
|
||||||
|
{
|
||||||
|
Q_D(QAbstractItemModelTester);
|
||||||
|
return d->verify(statement, statementStr, description, file, line);
|
||||||
|
}
|
||||||
|
|
||||||
QAbstractItemModelTesterPrivate::QAbstractItemModelTesterPrivate(QAbstractItemModel *model, QAbstractItemModelTester::FailureReportingMode failureReportingMode)
|
QAbstractItemModelTesterPrivate::QAbstractItemModelTesterPrivate(QAbstractItemModel *model, QAbstractItemModelTester::FailureReportingMode failureReportingMode)
|
||||||
: model(model),
|
: model(model),
|
||||||
failureReportingMode(failureReportingMode),
|
failureReportingMode(failureReportingMode),
|
||||||
|
@ -1844,10 +1844,16 @@ void QAbstractItemView::mouseMoveEvent(QMouseEvent *event)
|
|||||||
|| edit(index, NoEditTriggers, event))
|
|| edit(index, NoEditTriggers, event))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (d->selectionMode != SingleSelection)
|
if (d->selectionMode != SingleSelection) {
|
||||||
topLeft = d->pressedPosition - d->offset();
|
// Use the current selection start index if it is valid as this will be based on the
|
||||||
else
|
// start of the selection and not the last item being pressed which can be different
|
||||||
|
// when in extended selection
|
||||||
|
topLeft = d->currentSelectionStartIndex.isValid()
|
||||||
|
? visualRect(d->currentSelectionStartIndex).center()
|
||||||
|
: d->pressedPosition - d->offset();
|
||||||
|
} else {
|
||||||
topLeft = bottomRight;
|
topLeft = bottomRight;
|
||||||
|
}
|
||||||
|
|
||||||
d->checkMouseMove(index);
|
d->checkMouseMove(index);
|
||||||
|
|
||||||
|
@ -505,7 +505,7 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event)
|
|||||||
QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::ContextMenuOnMouseRelease).toBool() ?
|
QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::ContextMenuOnMouseRelease).toBool() ?
|
||||||
QEvent::MouseButtonRelease : QEvent::MouseButtonPress;
|
QEvent::MouseButtonRelease : QEvent::MouseButtonPress;
|
||||||
if (QApplicationPrivate::inPopupMode()) {
|
if (QApplicationPrivate::inPopupMode()) {
|
||||||
QWidget *activePopupWidget = QApplication::activePopupWidget();
|
QPointer<QWidget> activePopupWidget = QApplication::activePopupWidget();
|
||||||
QPoint mapped = event->pos();
|
QPoint mapped = event->pos();
|
||||||
if (activePopupWidget != m_widget)
|
if (activePopupWidget != m_widget)
|
||||||
mapped = activePopupWidget->mapFromGlobal(event->globalPos());
|
mapped = activePopupWidget->mapFromGlobal(event->globalPos());
|
||||||
@ -565,9 +565,11 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event)
|
|||||||
#endif
|
#endif
|
||||||
if ((event->type() != QEvent::MouseButtonPress)
|
if ((event->type() != QEvent::MouseButtonPress)
|
||||||
|| !(event->flags().testFlag(Qt::MouseEventCreatedDoubleClick))) {
|
|| !(event->flags().testFlag(Qt::MouseEventCreatedDoubleClick))) {
|
||||||
|
// if the widget that was pressed is gone, then deliver move events without buttons
|
||||||
|
const auto buttons = event->type() == QEvent::MouseMove && qt_button_down == nullptr
|
||||||
|
? Qt::NoButton : event->buttons();
|
||||||
QMouseEvent e(event->type(), widgetPos, event->windowPos(), event->screenPos(),
|
QMouseEvent e(event->type(), widgetPos, event->windowPos(), event->screenPos(),
|
||||||
event->button(), event->buttons(), event->modifiers(), event->source());
|
event->button(), buttons, event->modifiers(), event->source());
|
||||||
e.setTimestamp(event->timestamp());
|
e.setTimestamp(event->timestamp());
|
||||||
QApplicationPrivate::sendMouseEvent(receiver, &e, receiver, receiver->window(), &qt_button_down, qt_last_mouse_receiver);
|
QApplicationPrivate::sendMouseEvent(receiver, &e, receiver, receiver->window(), &qt_button_down, qt_last_mouse_receiver);
|
||||||
qt_last_mouse_receiver = receiver;
|
qt_last_mouse_receiver = receiver;
|
||||||
|
134
tests/auto/corelib/serialization/cborlargedatavalidation.cpp
Normal file
134
tests/auto/corelib/serialization/cborlargedatavalidation.cpp
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2020 Intel Corporation.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of the QtCore module of the Qt Toolkit.
|
||||||
|
**
|
||||||
|
** $QT_BEGIN_LICENSE:LGPL$
|
||||||
|
** 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 Lesser General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||||
|
** packaging of this file. Please review the following information to
|
||||||
|
** ensure the GNU Lesser General Public License version 3 requirements
|
||||||
|
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 2.0 or (at your option) the GNU General
|
||||||
|
** Public license version 3 or any later version approved by the KDE Free
|
||||||
|
** Qt Foundation. The licenses are as published by the Free Software
|
||||||
|
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
||||||
|
** 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-2.0.html and
|
||||||
|
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
** $QT_END_LICENSE$
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include <QtTest/QtTest>
|
||||||
|
#include <cbor.h>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
// A QIODevice that supplies a fixed header followed by a large sequence of
|
||||||
|
// null bytes up until a pre-determined size.
|
||||||
|
class LargeIODevice final : public QIODevice
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
qint64 realSize;
|
||||||
|
QByteArray start;
|
||||||
|
|
||||||
|
LargeIODevice(const QByteArray &start, qint64 size, QObject *parent = nullptr)
|
||||||
|
: QIODevice(parent), realSize(size), start(start)
|
||||||
|
{}
|
||||||
|
|
||||||
|
qint64 size() const override { return realSize; }
|
||||||
|
bool isSequential() const override { return false; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
qint64 readData(char *data, qint64 maxlen) override;
|
||||||
|
qint64 writeData(const char *, qint64) override { return -1; }
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
qint64 LargeIODevice::readData(char *data, qint64 maxlen)
|
||||||
|
{
|
||||||
|
qint64 p = pos();
|
||||||
|
if (maxlen > realSize - p)
|
||||||
|
maxlen = realSize - p;
|
||||||
|
memset(data, '\0', maxlen);
|
||||||
|
|
||||||
|
qint64 fromstart = start.size() - p;
|
||||||
|
if (fromstart > maxlen)
|
||||||
|
fromstart = maxlen;
|
||||||
|
else if (fromstart < 0)
|
||||||
|
fromstart = 0;
|
||||||
|
if (fromstart)
|
||||||
|
memcpy(data, start.constData() + p, fromstart);
|
||||||
|
return maxlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addValidationLargeData(qsizetype minInvalid, qsizetype maxInvalid)
|
||||||
|
{
|
||||||
|
char toolong[2 + sizeof(qsizetype)] = { char(0x81) };
|
||||||
|
for (qsizetype v = maxInvalid; v >= minInvalid; --v) {
|
||||||
|
// 0x5a for 32-bit, 0x5b for 64-bit
|
||||||
|
toolong[1] = sizeof(v) > 4 ? 0x5b : 0x5a;
|
||||||
|
qToBigEndian(v, toolong + 2);
|
||||||
|
|
||||||
|
QTest::addRow("bytearray-too-big-for-qbytearray-%llx", v)
|
||||||
|
<< QByteArray(toolong, sizeof(toolong)) << 0 << CborErrorDataTooLarge;
|
||||||
|
toolong[1] |= 0x20;
|
||||||
|
|
||||||
|
// QCborStreamReader::readString copies to a QByteArray first
|
||||||
|
QTest::addRow("string-too-big-for-qbytearray-%llx", v)
|
||||||
|
<< QByteArray(toolong, sizeof(toolong)) << 0 << CborErrorDataTooLarge;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void addValidationHugeDevice(qsizetype byteArrayInvalid, qsizetype stringInvalid)
|
||||||
|
{
|
||||||
|
qRegisterMetaType<QSharedPointer<QIODevice>>();
|
||||||
|
QTest::addColumn<QSharedPointer<QIODevice>>("device");
|
||||||
|
QTest::addColumn<CborError>("expectedError");
|
||||||
|
|
||||||
|
char buf[1 + sizeof(quint64)];
|
||||||
|
auto device = [&buf](QCborStreamReader::Type t, quint64 size) {
|
||||||
|
buf[0] = quint8(t) | 0x1b;
|
||||||
|
qToBigEndian(size, buf + 1);
|
||||||
|
size += sizeof(buf);
|
||||||
|
QSharedPointer<QIODevice> p =
|
||||||
|
QSharedPointer<LargeIODevice>::create(QByteArray(buf, sizeof(buf)), size);
|
||||||
|
return p;
|
||||||
|
};
|
||||||
|
|
||||||
|
// do the exact limits
|
||||||
|
QTest::newRow("bytearray-just-too-big")
|
||||||
|
<< device(QCborStreamReader::ByteArray, byteArrayInvalid) << CborErrorDataTooLarge;
|
||||||
|
QTest::newRow("string-just-too-big")
|
||||||
|
<< device(QCborStreamReader::String, stringInvalid) << CborErrorDataTooLarge;
|
||||||
|
|
||||||
|
auto addSize = [=](const char *sizename, qint64 size) {
|
||||||
|
if (byteArrayInvalid < size)
|
||||||
|
QTest::addRow("bytearray-%s", sizename)
|
||||||
|
<< device(QCborStreamReader::ByteArray, size) << CborErrorDataTooLarge;
|
||||||
|
if (stringInvalid < size)
|
||||||
|
QTest::addRow("string-%s", sizename)
|
||||||
|
<< device(QCborStreamReader::String, size) << CborErrorDataTooLarge;
|
||||||
|
};
|
||||||
|
addSize("1GB", quint64(1) << 30);
|
||||||
|
addSize("2GB", quint64(1) << 31);
|
||||||
|
addSize("4GB", quint64(1) << 32);
|
||||||
|
addSize("max", std::numeric_limits<qint64>::max() - sizeof(buf));
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
QT = core testlib
|
QT = core-private testlib
|
||||||
TARGET = tst_qcborstreamreader
|
TARGET = tst_qcborstreamreader
|
||||||
CONFIG += testcase
|
CONFIG += testcase
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
**
|
**
|
||||||
** Copyright (C) 2018 Intel Corporation.
|
** Copyright (C) 2020 Intel Corporation.
|
||||||
** Contact: https://www.qt.io/licensing/
|
** Contact: https://www.qt.io/licensing/
|
||||||
**
|
**
|
||||||
** This file is part of the QtCore module of the Qt Toolkit.
|
** This file is part of the QtCore module of the Qt Toolkit.
|
||||||
@ -40,6 +40,8 @@
|
|||||||
#include <QtCore/qcborstream.h>
|
#include <QtCore/qcborstream.h>
|
||||||
#include <QtTest>
|
#include <QtTest>
|
||||||
|
|
||||||
|
#include <QtCore/private/qbytearray_p.h>
|
||||||
|
|
||||||
class tst_QCborStreamReader : public QObject
|
class tst_QCborStreamReader : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@ -73,6 +75,8 @@ private Q_SLOTS:
|
|||||||
void next();
|
void next();
|
||||||
void validation_data();
|
void validation_data();
|
||||||
void validation();
|
void validation();
|
||||||
|
void hugeDeviceValidation_data();
|
||||||
|
void hugeDeviceValidation();
|
||||||
void recursionLimit_data();
|
void recursionLimit_data();
|
||||||
void recursionLimit();
|
void recursionLimit();
|
||||||
|
|
||||||
@ -902,16 +906,26 @@ void tst_QCborStreamReader::next()
|
|||||||
QVERIFY(doit("\xbf\x9f\1\xff\x9f" + data + "\xff\xff"));
|
QVERIFY(doit("\xbf\x9f\1\xff\x9f" + data + "\xff\xff"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include "../cborlargedatavalidation.cpp"
|
||||||
|
|
||||||
void tst_QCborStreamReader::validation_data()
|
void tst_QCborStreamReader::validation_data()
|
||||||
{
|
{
|
||||||
|
// Add QCborStreamReader-specific limitations due to use of QByteArray and
|
||||||
|
// QString, which are allocated by QArrayData::allocate().
|
||||||
|
const qsizetype MaxInvalid = std::numeric_limits<QByteArray::size_type>::max();
|
||||||
|
const qsizetype MinInvalid = MaxByteArraySize + 1;
|
||||||
|
|
||||||
addValidationColumns();
|
addValidationColumns();
|
||||||
addValidationData();
|
addValidationData(MinInvalid);
|
||||||
|
addValidationLargeData(MinInvalid, MaxInvalid);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_QCborStreamReader::validation()
|
void tst_QCborStreamReader::validation()
|
||||||
{
|
{
|
||||||
QFETCH_GLOBAL(bool, useDevice);
|
QFETCH_GLOBAL(bool, useDevice);
|
||||||
QFETCH(QByteArray, data);
|
QFETCH(QByteArray, data);
|
||||||
|
QFETCH(CborError, expectedError);
|
||||||
|
QCborError error = { QCborError::Code(expectedError) };
|
||||||
|
|
||||||
QBuffer buffer(&data);
|
QBuffer buffer(&data);
|
||||||
QCborStreamReader reader(data);
|
QCborStreamReader reader(data);
|
||||||
@ -920,12 +934,39 @@ void tst_QCborStreamReader::validation()
|
|||||||
reader.setDevice(&buffer);
|
reader.setDevice(&buffer);
|
||||||
}
|
}
|
||||||
parse(reader, data);
|
parse(reader, data);
|
||||||
QVERIFY(reader.lastError() != QCborError::NoError);
|
QCOMPARE(reader.lastError(), error);
|
||||||
|
|
||||||
// next() should fail
|
// next() should fail
|
||||||
reader.reset();
|
reader.reset();
|
||||||
QVERIFY(!reader.next());
|
QVERIFY(!reader.next());
|
||||||
QVERIFY(reader.lastError() != QCborError::NoError);
|
QCOMPARE(reader.lastError(), error);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_QCborStreamReader::hugeDeviceValidation_data()
|
||||||
|
{
|
||||||
|
addValidationHugeDevice(MaxByteArraySize + 1, MaxStringSize + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_QCborStreamReader::hugeDeviceValidation()
|
||||||
|
{
|
||||||
|
QFETCH_GLOBAL(bool, useDevice);
|
||||||
|
if (!useDevice)
|
||||||
|
return;
|
||||||
|
|
||||||
|
QFETCH(QSharedPointer<QIODevice>, device);
|
||||||
|
QFETCH(CborError, expectedError);
|
||||||
|
QCborError error = { QCborError::Code(expectedError) };
|
||||||
|
|
||||||
|
device->open(QIODevice::ReadOnly | QIODevice::Unbuffered);
|
||||||
|
QCborStreamReader reader(device.data());
|
||||||
|
|
||||||
|
QVERIFY(parseOne(reader).isEmpty());
|
||||||
|
QCOMPARE(reader.lastError(), error);
|
||||||
|
|
||||||
|
// next() should fail
|
||||||
|
reader.reset();
|
||||||
|
QVERIFY(!reader.next());
|
||||||
|
QCOMPARE(reader.lastError(), error);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const int Recursions = 3;
|
static const int Recursions = 3;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
QT = core testlib
|
QT = core-private testlib
|
||||||
TARGET = tst_qcborvalue
|
TARGET = tst_qcborvalue
|
||||||
CONFIG += testcase
|
CONFIG += testcase
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
**
|
**
|
||||||
** Copyright (C) 2018 Intel Corporation.
|
** Copyright (C) 2020 Intel Corporation.
|
||||||
** Contact: https://www.qt.io/licensing/
|
** Contact: https://www.qt.io/licensing/
|
||||||
**
|
**
|
||||||
** This file is part of the QtCore module of the Qt Toolkit.
|
** This file is part of the QtCore module of the Qt Toolkit.
|
||||||
@ -40,6 +40,8 @@
|
|||||||
#include <QtCore/qcborvalue.h>
|
#include <QtCore/qcborvalue.h>
|
||||||
#include <QtTest>
|
#include <QtTest>
|
||||||
|
|
||||||
|
#include <QtCore/private/qbytearray_p.h>
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(QCborKnownTags)
|
Q_DECLARE_METATYPE(QCborKnownTags)
|
||||||
Q_DECLARE_METATYPE(QCborValue)
|
Q_DECLARE_METATYPE(QCborValue)
|
||||||
Q_DECLARE_METATYPE(QCborValue::EncodingOptions)
|
Q_DECLARE_METATYPE(QCborValue::EncodingOptions)
|
||||||
@ -102,6 +104,8 @@ private slots:
|
|||||||
void fromCborStreamReaderIODevice();
|
void fromCborStreamReaderIODevice();
|
||||||
void validation_data();
|
void validation_data();
|
||||||
void validation();
|
void validation();
|
||||||
|
void hugeDeviceValidation_data();
|
||||||
|
void hugeDeviceValidation();
|
||||||
void recursionLimit_data();
|
void recursionLimit_data();
|
||||||
void recursionLimit();
|
void recursionLimit();
|
||||||
void toDiagnosticNotation_data();
|
void toDiagnosticNotation_data();
|
||||||
@ -1689,39 +1693,75 @@ void tst_QCborValue::fromCborStreamReaderIODevice()
|
|||||||
fromCbor_common(doCheck);
|
fromCbor_common(doCheck);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include "../cborlargedatavalidation.cpp"
|
||||||
|
|
||||||
void tst_QCborValue::validation_data()
|
void tst_QCborValue::validation_data()
|
||||||
{
|
{
|
||||||
|
// Add QCborStreamReader-specific limitations due to use of QByteArray and
|
||||||
|
// QString, which are allocated by QArrayData::allocate().
|
||||||
|
const qsizetype MaxInvalid = std::numeric_limits<QByteArray::size_type>::max();
|
||||||
|
const qsizetype MinInvalid = MaxByteArraySize + 1;
|
||||||
addValidationColumns();
|
addValidationColumns();
|
||||||
addValidationData();
|
addValidationData(MinInvalid);
|
||||||
|
addValidationLargeData(MinInvalid, MaxInvalid);
|
||||||
|
|
||||||
// These tests say we have arrays and maps with very large item counts.
|
// These tests say we have arrays and maps with very large item counts.
|
||||||
// They are meant to ensure we don't pre-allocate a lot of memory
|
// They are meant to ensure we don't pre-allocate a lot of memory
|
||||||
// unnecessarily and possibly crash the application. The actual number of
|
// unnecessarily and possibly crash the application. The actual number of
|
||||||
// elements in the stream is only 2, so we should get an unexpected EOF
|
// elements in the stream is only 2, so we should get an unexpected EOF
|
||||||
// error. QCborValue internally uses 16 bytes per element, so we get to
|
// error. QCborValue internally uses 16 bytes per element, so we get to 2
|
||||||
// 2 GB at 2^27 elements.
|
// GB at 2^27 elements (32-bit) or, theoretically, 2^63 bytes at 2^59
|
||||||
QTest::addRow("very-large-array-no-overflow") << raw("\x9a\x07\xff\xff\xff" "\0\0");
|
// elements (64-bit).
|
||||||
QTest::addRow("very-large-array-overflow1") << raw("\x9a\x40\0\0\0" "\0\0");
|
if (sizeof(QVector<int>::size_type) == sizeof(int)) {
|
||||||
|
// 32-bit sizes (Qt 5 and 32-bit platforms)
|
||||||
|
QTest::addRow("very-large-array-no-overflow") << raw("\x9a\x07\xff\xff\xff" "\0\0") << 0 << CborErrorUnexpectedEOF;
|
||||||
|
QTest::addRow("very-large-array-overflow1") << raw("\x9a\x40\0\0\0" "\0\0") << 0 << CborErrorUnexpectedEOF;
|
||||||
|
|
||||||
// this makes sure we don't accidentally clip to 32-bit: sending 2^32+2 elements
|
// this makes sure we don't accidentally clip to 32-bit: sending 2^32+2 elements
|
||||||
QTest::addRow("very-large-array-overflow2") << raw("\x9b\0\0\0\1""\0\0\0\2" "\0\0");
|
QTest::addRow("very-large-array-overflow2") << raw("\x9b\0\0\0\1""\0\0\0\2" "\0\0") << 0 << CborErrorDataTooLarge;
|
||||||
|
} else {
|
||||||
|
// 64-bit Qt 6
|
||||||
|
QTest::addRow("very-large-array-no-overflow") << raw("\x9b\x07\xff\xff\xff" "\xff\xff\xff\xff" "\0\0");
|
||||||
|
QTest::addRow("very-large-array-overflow") << raw("\x9b\x40\0\0\0" "\0\0\0\0" "\0\0");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_QCborValue::validation()
|
void tst_QCborValue::validation()
|
||||||
{
|
{
|
||||||
QFETCH(QByteArray, data);
|
QFETCH(QByteArray, data);
|
||||||
|
QFETCH(CborError, expectedError);
|
||||||
|
QCborError error = { QCborError::Code(expectedError) };
|
||||||
|
|
||||||
QCborParserError error;
|
QCborParserError parserError;
|
||||||
QCborValue decoded = QCborValue::fromCbor(data, &error);
|
QCborValue decoded = QCborValue::fromCbor(data, &parserError);
|
||||||
QVERIFY(error.error != QCborError{});
|
QCOMPARE(parserError.error, error);
|
||||||
|
|
||||||
if (data.startsWith('\x81')) {
|
if (data.startsWith('\x81')) {
|
||||||
// decode without the array prefix
|
// decode without the array prefix
|
||||||
decoded = QCborValue::fromCbor(data.mid(1), &error);
|
char *ptr = const_cast<char *>(data.constData());
|
||||||
QVERIFY(error.error != QCborError{});
|
QByteArray mid = QByteArray::fromRawData(ptr + 1, data.size() - 1);
|
||||||
|
decoded = QCborValue::fromCbor(mid, &parserError);
|
||||||
|
QCOMPARE(parserError.error, error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_QCborValue::hugeDeviceValidation_data()
|
||||||
|
{
|
||||||
|
addValidationHugeDevice(MaxByteArraySize + 1, MaxStringSize + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_QCborValue::hugeDeviceValidation()
|
||||||
|
{
|
||||||
|
QFETCH(QSharedPointer<QIODevice>, device);
|
||||||
|
QFETCH(CborError, expectedError);
|
||||||
|
QCborError error = { QCborError::Code(expectedError) };
|
||||||
|
|
||||||
|
device->open(QIODevice::ReadOnly | QIODevice::Unbuffered);
|
||||||
|
QCborStreamReader reader(device.data());
|
||||||
|
QCborValue decoded = QCborValue::fromCbor(reader);
|
||||||
|
QCOMPARE(reader.lastError(), error);
|
||||||
|
}
|
||||||
|
|
||||||
void tst_QCborValue::recursionLimit_data()
|
void tst_QCborValue::recursionLimit_data()
|
||||||
{
|
{
|
||||||
constexpr int RecursionAttempts = 4096;
|
constexpr int RecursionAttempts = 4096;
|
||||||
|
@ -149,6 +149,7 @@ private slots:
|
|||||||
void currentFollowsIndexWidget();
|
void currentFollowsIndexWidget();
|
||||||
void checkFocusAfterActivationChanges_data();
|
void checkFocusAfterActivationChanges_data();
|
||||||
void checkFocusAfterActivationChanges();
|
void checkFocusAfterActivationChanges();
|
||||||
|
void dragSelectAfterNewPress();
|
||||||
private:
|
private:
|
||||||
static QAbstractItemView *viewFromString(const QByteArray &viewType, QWidget *parent = nullptr)
|
static QAbstractItemView *viewFromString(const QByteArray &viewType, QWidget *parent = nullptr)
|
||||||
{
|
{
|
||||||
@ -2453,5 +2454,62 @@ void tst_QAbstractItemView::checkFocusAfterActivationChanges()
|
|||||||
QVERIFY(view->hasFocus());
|
QVERIFY(view->hasFocus());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_QAbstractItemView::dragSelectAfterNewPress()
|
||||||
|
{
|
||||||
|
QStandardItemModel model;
|
||||||
|
for (int i = 0; i < 10; ++i) {
|
||||||
|
QStandardItem *item = new QStandardItem(QString::number(i));
|
||||||
|
model.setItem(i, 0, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
QListView view;
|
||||||
|
view.setFixedSize(160, 650); // Minimum width for windows with frame on Windows 8
|
||||||
|
view.setSelectionMode(QListView::ExtendedSelection);
|
||||||
|
view.setModel(&model);
|
||||||
|
centerOnScreen(&view);
|
||||||
|
moveCursorAway(&view);
|
||||||
|
view.show();
|
||||||
|
QVERIFY(QTest::qWaitForWindowExposed(&view));
|
||||||
|
|
||||||
|
QModelIndex index0 = model.index(0, 0);
|
||||||
|
QModelIndex index2 = model.index(2, 0);
|
||||||
|
|
||||||
|
view.setCurrentIndex(index0);
|
||||||
|
QCOMPARE(view.currentIndex(), index0);
|
||||||
|
|
||||||
|
// Select item 0 using a single click
|
||||||
|
QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::NoModifier,
|
||||||
|
view.visualRect(index0).center());
|
||||||
|
QCOMPARE(view.currentIndex(), index0);
|
||||||
|
|
||||||
|
// Press to select item 2
|
||||||
|
QTest::mousePress(view.viewport(), Qt::LeftButton, Qt::ShiftModifier,
|
||||||
|
view.visualRect(index2).center());
|
||||||
|
QCOMPARE(view.currentIndex(), index2);
|
||||||
|
|
||||||
|
// Verify that the selection worked OK
|
||||||
|
QModelIndexList selected = view.selectionModel()->selectedIndexes();
|
||||||
|
QCOMPARE(selected.count(), 3);
|
||||||
|
for (int i = 0; i < 2; ++i)
|
||||||
|
QVERIFY(selected.contains(model.index(i, 0)));
|
||||||
|
|
||||||
|
QModelIndex index5 = model.index(5, 0);
|
||||||
|
const QPoint releasePos = view.visualRect(index5).center();
|
||||||
|
// The mouse move event has to be created manually because the QTest framework does not
|
||||||
|
// contain a function for mouse moves with buttons pressed
|
||||||
|
QMouseEvent moveEvent2(QEvent::MouseMove, releasePos, Qt::NoButton, Qt::LeftButton,
|
||||||
|
Qt::ShiftModifier);
|
||||||
|
const bool moveEventReceived = qApp->notify(view.viewport(), &moveEvent2);
|
||||||
|
QVERIFY(moveEventReceived);
|
||||||
|
QTest::mouseRelease(view.viewport(), Qt::LeftButton, Qt::ShiftModifier, releasePos);
|
||||||
|
QCOMPARE(view.currentIndex(), index5);
|
||||||
|
|
||||||
|
// Verify that the selection worked OK
|
||||||
|
selected = view.selectionModel()->selectedIndexes();
|
||||||
|
QCOMPARE(selected.count(), 6);
|
||||||
|
for (int i = 0; i < 5; ++i)
|
||||||
|
QVERIFY(selected.contains(model.index(i, 0)));
|
||||||
|
}
|
||||||
|
|
||||||
QTEST_MAIN(tst_QAbstractItemView)
|
QTEST_MAIN(tst_QAbstractItemView)
|
||||||
#include "tst_qabstractitemview.moc"
|
#include "tst_qabstractitemview.moc"
|
||||||
|
Loading…
Reference in New Issue
Block a user