summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorEdward Welbourne <edward.welbourne@qt.io>2016-07-28 13:20:41 +0200
committerEdward Welbourne <edward.welbourne@qt.io>2016-08-01 18:20:00 +0200
commitf6fc34294f5691da8aa7ab8dc0452c6fa9036b67 (patch)
tree3b8fe9841f88aa81e2f8f2d57cbbca2c4736ca6f /tests
parent6f75096afc000991111bb0fd7a7e530ce3518627 (diff)
parent0eb77c3011ee4d6bbc46dd2d40c9324e9bfcbecf (diff)
Merge remote-tracking branch 'origin/5.7' into dev
Conflicts: configure 5.7 now supports clang on android; but dev re-worked configure src/gui/kernel/qevent.h One side renamed a parameter of a constructor; the other added an alternate constructor on the next line. Applied the rename to both for consistency. tests/auto/tools/moc/tst_moc.cpp Each side added a new test at the end. .qmake.conf Ignored 5.7's change to MODULE_VERSION. configure.json No conflict noticed by git; but changes in 5.7 were needed for the re-worked configure to accommodate 5.7's stricter handling of C++11. Change-Id: I9cda53836a32d7bf83828212c7ea00b1de3e09d2
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/corelib/io/qdatastream/tst_qdatastream.cpp144
-rw-r--r--tests/auto/corelib/io/qtemporarydir/tst_qtemporarydir.cpp41
-rw-r--r--tests/auto/corelib/io/qtemporaryfile/tst_qtemporaryfile.cpp41
-rw-r--r--tests/auto/corelib/tools/qvector/tst_qvector.cpp22
-rw-r--r--tests/auto/corelib/xml/qxmlstream/tst_qxmlstream.cpp59
-rw-r--r--tests/auto/gui/image/qimage/tst_qimage.cpp38
-rw-r--r--tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp6
-rw-r--r--tests/auto/other/qobjectrace/tst_qobjectrace.cpp175
-rw-r--r--tests/auto/tools/moc/tst_moc.cpp7
-rw-r--r--tests/auto/widgets/itemviews/qitemdelegate/qitemdelegate.pro2
-rw-r--r--tests/auto/widgets/itemviews/qitemdelegate/tst_qitemdelegate.cpp62
-rw-r--r--tests/manual/embeddedintoforeignwindow/embeddedintoforeignwindow.pro7
-rw-r--r--tests/manual/embeddedintoforeignwindow/itemwindow.cpp72
-rw-r--r--tests/manual/embeddedintoforeignwindow/itemwindow.h126
-rw-r--r--tests/manual/embeddedintoforeignwindow/main.cpp287
-rw-r--r--tests/manual/manual.pro4
16 files changed, 1036 insertions, 57 deletions
diff --git a/tests/auto/corelib/io/qdatastream/tst_qdatastream.cpp b/tests/auto/corelib/io/qdatastream/tst_qdatastream.cpp
index de6884d454..5b03b35780 100644
--- a/tests/auto/corelib/io/qdatastream/tst_qdatastream.cpp
+++ b/tests/auto/corelib/io/qdatastream/tst_qdatastream.cpp
@@ -2723,27 +2723,43 @@ void tst_QDataStream::status_QBitArray()
}
#define MAP_TEST(byteArray, initialStatus, expectedStatus, expectedHash) \
- { \
- QByteArray ba = byteArray; \
- QDataStream stream(&ba, QIODevice::ReadOnly); \
- stream.setStatus(initialStatus); \
- stream >> hash; \
- QCOMPARE((int)stream.status(), (int)expectedStatus); \
- QCOMPARE(hash.size(), expectedHash.size()); \
- QCOMPARE(hash, expectedHash); \
- } \
- { \
- QByteArray ba = byteArray; \
- StringMap expectedMap; \
- StringHash::const_iterator it = expectedHash.constBegin(); \
- for (; it != expectedHash.constEnd(); ++it) \
- expectedMap.insert(it.key(), it.value()); \
- QDataStream stream(&ba, QIODevice::ReadOnly); \
- stream.setStatus(initialStatus); \
- stream >> map; \
- QCOMPARE((int)stream.status(), (int)expectedStatus); \
- QCOMPARE(map.size(), expectedMap.size()); \
- QCOMPARE(map, expectedMap); \
+ for (bool inTransaction = false;; inTransaction = true) { \
+ { \
+ QByteArray ba = byteArray; \
+ QDataStream stream(&ba, QIODevice::ReadOnly); \
+ if (inTransaction) \
+ stream.startTransaction(); \
+ stream.setStatus(initialStatus); \
+ stream >> hash; \
+ QCOMPARE((int)stream.status(), (int)expectedStatus); \
+ if (!inTransaction || stream.commitTransaction()) { \
+ QCOMPARE(hash.size(), expectedHash.size()); \
+ QCOMPARE(hash, expectedHash); \
+ } else { \
+ QVERIFY(hash.isEmpty()); \
+ } \
+ } \
+ { \
+ QByteArray ba = byteArray; \
+ StringMap expectedMap; \
+ StringHash::const_iterator it = expectedHash.constBegin(); \
+ for (; it != expectedHash.constEnd(); ++it) \
+ expectedMap.insert(it.key(), it.value()); \
+ QDataStream stream(&ba, QIODevice::ReadOnly); \
+ if (inTransaction) \
+ stream.startTransaction(); \
+ stream.setStatus(initialStatus); \
+ stream >> map; \
+ QCOMPARE((int)stream.status(), (int)expectedStatus); \
+ if (!inTransaction || stream.commitTransaction()) { \
+ QCOMPARE(map.size(), expectedMap.size()); \
+ QCOMPARE(map, expectedMap); \
+ } else { \
+ QVERIFY(map.isEmpty()); \
+ } \
+ } \
+ if (inTransaction) \
+ break; \
}
void tst_QDataStream::status_QHash_QMap()
@@ -2788,38 +2804,60 @@ void tst_QDataStream::status_QHash_QMap()
}
#define LIST_TEST(byteArray, initialStatus, expectedStatus, expectedList) \
- { \
- QByteArray ba = byteArray; \
- QDataStream stream(&ba, QIODevice::ReadOnly); \
- stream.setStatus(initialStatus); \
- stream >> list; \
- QCOMPARE((int)stream.status(), (int)expectedStatus); \
- QCOMPARE(list.size(), expectedList.size()); \
- QCOMPARE(list, expectedList); \
- } \
- { \
- LinkedList expectedLinkedList; \
- for (int i = 0; i < expectedList.count(); ++i) \
- expectedLinkedList << expectedList.at(i); \
- QByteArray ba = byteArray; \
- QDataStream stream(&ba, QIODevice::ReadOnly); \
- stream.setStatus(initialStatus); \
- stream >> linkedList; \
- QCOMPARE((int)stream.status(), (int)expectedStatus); \
- QCOMPARE(linkedList.size(), expectedLinkedList.size()); \
- QCOMPARE(linkedList, expectedLinkedList); \
- } \
- { \
- Vector expectedVector; \
- for (int i = 0; i < expectedList.count(); ++i) \
- expectedVector << expectedList.at(i); \
- QByteArray ba = byteArray; \
- QDataStream stream(&ba, QIODevice::ReadOnly); \
- stream.setStatus(initialStatus); \
- stream >> vector; \
- QCOMPARE((int)stream.status(), (int)expectedStatus); \
- QCOMPARE(vector.size(), expectedVector.size()); \
- QCOMPARE(vector, expectedVector); \
+ for (bool inTransaction = false;; inTransaction = true) { \
+ { \
+ QByteArray ba = byteArray; \
+ QDataStream stream(&ba, QIODevice::ReadOnly); \
+ if (inTransaction) \
+ stream.startTransaction(); \
+ stream.setStatus(initialStatus); \
+ stream >> list; \
+ QCOMPARE((int)stream.status(), (int)expectedStatus); \
+ if (!inTransaction || stream.commitTransaction()) { \
+ QCOMPARE(list.size(), expectedList.size()); \
+ QCOMPARE(list, expectedList); \
+ } else { \
+ QVERIFY(list.isEmpty()); \
+ } \
+ } \
+ { \
+ LinkedList expectedLinkedList; \
+ for (int i = 0; i < expectedList.count(); ++i) \
+ expectedLinkedList << expectedList.at(i); \
+ QByteArray ba = byteArray; \
+ QDataStream stream(&ba, QIODevice::ReadOnly); \
+ if (inTransaction) \
+ stream.startTransaction(); \
+ stream.setStatus(initialStatus); \
+ stream >> linkedList; \
+ QCOMPARE((int)stream.status(), (int)expectedStatus); \
+ if (!inTransaction || stream.commitTransaction()) { \
+ QCOMPARE(linkedList.size(), expectedLinkedList.size()); \
+ QCOMPARE(linkedList, expectedLinkedList); \
+ } else { \
+ QVERIFY(linkedList.isEmpty()); \
+ } \
+ } \
+ { \
+ Vector expectedVector; \
+ for (int i = 0; i < expectedList.count(); ++i) \
+ expectedVector << expectedList.at(i); \
+ QByteArray ba = byteArray; \
+ QDataStream stream(&ba, QIODevice::ReadOnly); \
+ if (inTransaction) \
+ stream.startTransaction(); \
+ stream.setStatus(initialStatus); \
+ stream >> vector; \
+ QCOMPARE((int)stream.status(), (int)expectedStatus); \
+ if (!inTransaction || stream.commitTransaction()) { \
+ QCOMPARE(vector.size(), expectedVector.size()); \
+ QCOMPARE(vector, expectedVector); \
+ } else { \
+ QVERIFY(vector.isEmpty()); \
+ } \
+ } \
+ if (inTransaction) \
+ break; \
}
void tst_QDataStream::status_QLinkedList_QList_QVector()
diff --git a/tests/auto/corelib/io/qtemporarydir/tst_qtemporarydir.cpp b/tests/auto/corelib/io/qtemporarydir/tst_qtemporarydir.cpp
index f0b9c05810..487c13be94 100644
--- a/tests/auto/corelib/io/qtemporarydir/tst_qtemporarydir.cpp
+++ b/tests/auto/corelib/io/qtemporarydir/tst_qtemporarydir.cpp
@@ -34,6 +34,7 @@
#include <qfile.h>
#include <qdir.h>
#include <qset.h>
+#include <qtextcodec.h>
#ifdef Q_OS_WIN
# include <windows.h>
#endif
@@ -108,6 +109,38 @@ void tst_QTemporaryDir::getSetCheck()
QCOMPARE(true, obj1.autoRemove());
}
+static inline bool canHandleUnicodeFileNames()
+{
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
+ return true;
+#else
+ // Check for UTF-8 by converting the Euro symbol (see tst_utf8)
+ return QFile::encodeName(QString(QChar(0x20AC))) == QByteArrayLiteral("\342\202\254");
+#endif
+}
+
+static QString hanTestText()
+{
+ QString text;
+ text += QChar(0x65B0);
+ text += QChar(0x5E10);
+ text += QChar(0x6237);
+ return text;
+}
+
+static QString umlautTestText()
+{
+ QString text;
+ text += QChar(0xc4);
+ text += QChar(0xe4);
+ text += QChar(0xd6);
+ text += QChar(0xf6);
+ text += QChar(0xdc);
+ text += QChar(0xfc);
+ text += QChar(0xdf);
+ return text;
+}
+
void tst_QTemporaryDir::fileTemplate_data()
{
QTest::addColumn<QString>("constructorTemplate");
@@ -124,6 +157,14 @@ void tst_QTemporaryDir::fileTemplate_data()
QTest::newRow("constructor with XXXX suffix") << "qt_XXXXXX_XXXX" << "qt_";
QTest::newRow("constructor with XXXX prefix") << "qt_XXXX" << "qt_";
QTest::newRow("constructor with XXXXX prefix") << "qt_XXXXX" << "qt_";
+ if (canHandleUnicodeFileNames()) {
+ // Test Umlauts (contained in Latin1)
+ QString prefix = "qt_" + umlautTestText();
+ QTest::newRow("Umlauts") << (prefix + "XXXXXX") << prefix;
+ // Test Chinese
+ prefix = "qt_" + hanTestText();
+ QTest::newRow("Chinese characters") << (prefix + "XXXXXX") << prefix;
+ }
}
void tst_QTemporaryDir::fileTemplate()
diff --git a/tests/auto/corelib/io/qtemporaryfile/tst_qtemporaryfile.cpp b/tests/auto/corelib/io/qtemporaryfile/tst_qtemporaryfile.cpp
index 9b46121981..59cd3a8411 100644
--- a/tests/auto/corelib/io/qtemporaryfile/tst_qtemporaryfile.cpp
+++ b/tests/auto/corelib/io/qtemporaryfile/tst_qtemporaryfile.cpp
@@ -34,6 +34,7 @@
#include <qfile.h>
#include <qdir.h>
#include <qset.h>
+#include <qtextcodec.h>
#if defined(Q_OS_WIN)
# include <windows.h>
@@ -140,6 +141,38 @@ void tst_QTemporaryFile::getSetCheck()
QCOMPARE(true, obj1.autoRemove());
}
+static inline bool canHandleUnicodeFileNames()
+{
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
+ return true;
+#else
+ // Check for UTF-8 by converting the Euro symbol (see tst_utf8)
+ return QFile::encodeName(QString(QChar(0x20AC))) == QByteArrayLiteral("\342\202\254");
+#endif
+}
+
+static QString hanTestText()
+{
+ QString text;
+ text += QChar(0x65B0);
+ text += QChar(0x5E10);
+ text += QChar(0x6237);
+ return text;
+}
+
+static QString umlautTestText()
+{
+ QString text;
+ text += QChar(0xc4);
+ text += QChar(0xe4);
+ text += QChar(0xd6);
+ text += QChar(0xf6);
+ text += QChar(0xdc);
+ text += QChar(0xfc);
+ text += QChar(0xdf);
+ return text;
+}
+
void tst_QTemporaryFile::fileTemplate_data()
{
QTest::addColumn<QString>("constructorTemplate");
@@ -166,6 +199,14 @@ void tst_QTemporaryFile::fileTemplate_data()
QTest::newRow("set template, with xxx") << "" << "qt_" << ".xxx" << "qt_XXXXXX.xxx";
QTest::newRow("set template, with >6 X's") << "" << "qt_" << ".xxx" << "qt_XXXXXXXXXXXXXX.xxx";
QTest::newRow("set template, with >6 X's, no suffix") << "" << "qt_" << "" << "qt_XXXXXXXXXXXXXX";
+ if (canHandleUnicodeFileNames()) {
+ // Test Umlauts (contained in Latin1)
+ QString prefix = "qt_" + umlautTestText();
+ QTest::newRow("Umlauts") << (prefix + "XXXXXX") << prefix << QString() << QString();
+ // Test Chinese
+ prefix = "qt_" + hanTestText();
+ QTest::newRow("Chinese characters") << (prefix + "XXXXXX") << prefix << QString() << QString();
+ }
}
void tst_QTemporaryFile::fileTemplate()
diff --git a/tests/auto/corelib/tools/qvector/tst_qvector.cpp b/tests/auto/corelib/tools/qvector/tst_qvector.cpp
index 825cb05d74..374fec221e 100644
--- a/tests/auto/corelib/tools/qvector/tst_qvector.cpp
+++ b/tests/auto/corelib/tools/qvector/tst_qvector.cpp
@@ -271,6 +271,7 @@ private slots:
void testOperators() const;
void reserve();
+ void reserveZero();
void reallocAfterCopy_data();
void reallocAfterCopy();
void initializeListInt();
@@ -2365,13 +2366,34 @@ void tst_QVector::reserve()
{
QVector<Foo> a;
a.resize(2);
+ QCOMPARE(fooCtor, 2);
QVector<Foo> b(a);
b.reserve(1);
QCOMPARE(b.size(), a.size());
+ QCOMPARE(fooDtor, 0);
}
QCOMPARE(fooCtor, fooDtor);
}
+// This is a regression test for QTBUG-51758
+void tst_QVector::reserveZero()
+{
+ QVector<int> vec;
+ vec.detach();
+ vec.reserve(0); // should not crash
+ QCOMPARE(vec.size(), 0);
+ QCOMPARE(vec.capacity(), 0);
+ vec.squeeze();
+ QCOMPARE(vec.size(), 0);
+ QCOMPARE(vec.capacity(), 0);
+ vec.reserve(-1);
+ QCOMPARE(vec.size(), 0);
+ QCOMPARE(vec.capacity(), 0);
+ vec.append(42);
+ QCOMPARE(vec.size(), 1);
+ QVERIFY(vec.capacity() >= 1);
+}
+
// This is a regression test for QTBUG-11763, where memory would be reallocated
// soon after copying a QVector.
void tst_QVector::reallocAfterCopy_data()
diff --git a/tests/auto/corelib/xml/qxmlstream/tst_qxmlstream.cpp b/tests/auto/corelib/xml/qxmlstream/tst_qxmlstream.cpp
index 26d443c2c6..9556a167c5 100644
--- a/tests/auto/corelib/xml/qxmlstream/tst_qxmlstream.cpp
+++ b/tests/auto/corelib/xml/qxmlstream/tst_qxmlstream.cpp
@@ -557,6 +557,8 @@ private slots:
void checkCommentIndentation_data() const;
void crashInXmlStreamReader() const;
void write8bitCodec() const;
+ void invalidStringCharacters_data() const;
+ void invalidStringCharacters() const;
void hasError() const;
private:
@@ -1614,6 +1616,63 @@ void tst_QXmlStream::write8bitCodec() const
QVERIFY(decodedText.startsWith(expected));
}
+void tst_QXmlStream::invalidStringCharacters() const
+{
+ // test scan in attributes
+ QFETCH(QString, testString);
+ QFETCH(bool, expectedResultNoError);
+
+ QByteArray values = testString.toUtf8();
+ QBuffer inBuffer;
+ inBuffer.setData(values);
+ QVERIFY(inBuffer.open(QIODevice::ReadOnly));
+ QXmlStreamReader reader(&inBuffer);
+ do {
+ reader.readNext();
+ } while (!reader.atEnd());
+ QCOMPARE((reader.error() == QXmlStreamReader::NoError), expectedResultNoError);
+}
+
+void tst_QXmlStream::invalidStringCharacters_data() const
+{
+ // test scan in attributes
+ QTest::addColumn<bool>("expectedResultNoError");
+ QTest::addColumn<QString>("testString");
+ QChar ctrl(0x1A);
+ QTest::newRow("utf8, attributes, legal") << true << QString("<?xml version=\"1.0\" encoding=\"UTF-8\"?><root attr='aa'/>");
+ QTest::newRow("utf8, attributes, only char, control") << false << QString("<?xml version=\"1.0\" encoding=\"UTF-8\"?><root attr='")+ctrl+QString("'/>");
+ QTest::newRow("utf8, attributes, 1st char, control") << false << QString("<?xml version=\"1.0\" encoding=\"UTF-8\"?><root attr='")+ctrl+QString("abc'/>");
+ QTest::newRow("utf8, attributes, middle char, control") << false << QString("<?xml version=\"1.0\" encoding=\"UTF-8\"?><root attr='abc")+ctrl+QString("efgx'/>");
+ QTest::newRow("utf8, attributes, last char, control") << false << QString("<?xml version=\"1.0\" encoding=\"UTF-8\"?><root attr='abcde")+ctrl+QString("'/>");
+ //
+ QTest::newRow("utf8, text, legal") << true << QString("<?xml version=\"1.0\" encoding=\"UTF-8\"?><root attr='aa'>abcx1A</root>");
+ QTest::newRow("utf8, text, only, control") << false << QString("<?xml version=\"1.0\" encoding=\"UTF-8\"?><root attr='aa'>")+ctrl+QString("</root>");
+ QTest::newRow("utf8, text, 1st char, control") << false << QString("<?xml version=\"1.0\" encoding=\"UTF-8\"?><root attr='aa'>abc")+ctrl+QString("def</root>");
+ QTest::newRow("utf8, text, middle char, control") << false << QString("<?xml version=\"1.0\" encoding=\"UTF-8\"?><root attr='aa'>abc")+ctrl+QString("efg</root>");
+ QTest::newRow("utf8, text, last char, control") << false << QString("<?xml version=\"1.0\" encoding=\"UTF-8\"?><root attr='aa'>abc")+ctrl+QString("</root>");
+ //
+ QTest::newRow("utf8, cdata text, legal") << true << QString("<?xml version=\"1.0\" encoding=\"UTF-8\"?><root attr='aa'><![CDATA[abcdefghi]]></root>");
+ QTest::newRow("utf8, cdata text, only, control") << false << QString("<?xml version=\"1.0\" encoding=\"UTF-8\"?><root attr='aa'><![CDATA[")+ctrl+QString("]]></root>");
+ QTest::newRow("utf8, cdata text, 1st char, control") << false << QString("<?xml version=\"1.0\" encoding=\"UTF-8\"?><root attr='aa'><![CDATA[")+ctrl+QString("abcdefghi]]></root>");
+ QTest::newRow("utf8, cdata text, middle char, control") << false << QString("<?xml version=\"1.0\" encoding=\"UTF-8\"?><root attr='aa'><![CDATA[abcd")+ctrl+QString("efghi]]></root>");
+ QTest::newRow("utf8, cdata text, last char, control") << false << QString("<?xml version=\"1.0\" encoding=\"UTF-8\"?><root attr='aa'><![CDATA[abcdefghi")+ctrl+QString("]]></root>");
+ //
+ QTest::newRow("utf8, mixed, control") << false << QString("<?xml version=\"1.0\" encoding=\"UTF-8\"?><root attr='a")+ctrl+QString("a'><![CDATA[abcdefghi")+ctrl+QString("]]></root>");
+ QTest::newRow("utf8, tag") << false << QString("<?xml version=\"1.0\" encoding=\"UTF-8\"?><roo")+ctrl+QString("t attr='aa'><![CDATA[abcdefghi]]></roo")+ctrl+QString("t>");
+ //
+ QTest::newRow("utf8, attributes, 1st char, legal escaping hex") << true << QString("<?xml version=\"1.0\" encoding=\"UTF-8\"?><root attr='a&#xA0;'/>");
+ QTest::newRow("utf8, attributes, 1st char, control escaping hex") << false << QString("<?xml version=\"1.0\" encoding=\"UTF-8\"?><root attr='&#x1A;aaa'/>");
+ QTest::newRow("utf8, attributes, middle char, legal escaping hex") << false << QString("<?xml version=\"1.0\" encoding=\"UTF-8\"?><root attr='aaa&#x1A;aaa'/>");
+ QTest::newRow("utf8, attributes, last char, control escaping hex") << false << QString("<?xml version=\"1.0\" encoding=\"UTF-8\"?><root attr='aaa&#x1A;'/>");
+ QTest::newRow("utf8, attributes, 1st char, legal escaping dec") << true << QString("<?xml version=\"1.0\" encoding=\"UTF-8\"?><root attr='a&#160;'/>");
+ QTest::newRow("utf8, attributes, 1st char, control escaping dec") << false << QString("<?xml version=\"1.0\" encoding=\"UTF-8\"?><root attr='&#26;aaaa'/>");
+ QTest::newRow("utf8, attributes, middle char, legal escaping dec") << false << QString("<?xml version=\"1.0\" encoding=\"UTF-8\"?><root attr='aaa&#26;aaaaa'/>");
+ QTest::newRow("utf8, attributes, last char, control escaping dec") << false << QString("<?xml version=\"1.0\" encoding=\"UTF-8\"?><root attr='aaaaaa&#26;'/>");
+ QTest::newRow("utf8, tag escaping") << false << QString("<?xml version=\"1.0\" encoding=\"UTF-8\"?><roo&#x1A;t attr='aa'><![CDATA[abcdefghi]]></roo&#x1A;t>");
+ //
+ QTest::newRow("utf8, mix of illegal control") << false << QString("<?xml version=\"1.0\" encoding=\"UTF-8\"?><root attr='a&#0;&#x4;&#x1c;a'><![CDATA[abcdefghi]]></root>");
+ //
+}
#include "tst_qxmlstream.moc"
// vim: et:ts=4:sw=4:sts=4
diff --git a/tests/auto/gui/image/qimage/tst_qimage.cpp b/tests/auto/gui/image/qimage/tst_qimage.cpp
index 7e1a02d716..18812fd090 100644
--- a/tests/auto/gui/image/qimage/tst_qimage.cpp
+++ b/tests/auto/gui/image/qimage/tst_qimage.cpp
@@ -94,6 +94,8 @@ private slots:
void setPixel_data();
void setPixel();
+ void defaultColorTable_data();
+ void defaultColorTable();
void setColorCount();
void setColor();
@@ -1450,6 +1452,38 @@ void tst_QImage::convertToFormatPreserveText()
QCOMPARE(imgResult2.textKeys(), listResult);
}
+void tst_QImage::defaultColorTable_data()
+{
+ QTest::addColumn<QImage::Format>("format");
+ QTest::addColumn<int>("createdDataCount");
+ QTest::addColumn<int>("externalDataCount");
+
+ // For historical reasons, internally created mono images get a default colormap.
+ // Externally created and Indexed8 images do not.
+ QTest::newRow("Mono") << QImage::Format_Mono << 2 << 0;
+ QTest::newRow("MonoLSB") << QImage::Format_MonoLSB << 2 << 0;
+ QTest::newRow("Indexed8") << QImage::Format_Indexed8 << 0 << 0;
+ QTest::newRow("ARGB32_PM") << QImage::Format_A2BGR30_Premultiplied << 0 << 0;
+}
+
+void tst_QImage::defaultColorTable()
+{
+ QFETCH(QImage::Format, format);
+ QFETCH(int, createdDataCount);
+ QFETCH(int, externalDataCount);
+
+ QImage img1(1, 1, format);
+ QCOMPARE(img1.colorCount(), createdDataCount);
+ QCOMPARE(img1.colorTable().size(), createdDataCount);
+
+ quint32 buf;
+ QImage img2(reinterpret_cast<uchar *>(&buf), 1, 1, format);
+ QCOMPARE(img2.colorCount(), externalDataCount);
+
+ QImage nullImg(0, 0, format);
+ QCOMPARE(nullImg.colorCount(), 0);
+}
+
void tst_QImage::setColorCount()
{
QImage img(0, 0, QImage::Format_Indexed8);
@@ -3194,8 +3228,8 @@ void tst_QImage::pixel()
QImage monolsb(&a, 1, 1, QImage::Format_MonoLSB);
QImage indexed(&a, 1, 1, QImage::Format_Indexed8);
- QCOMPARE(QColor(mono.pixel(0, 0)), QColor(Qt::black));
- QCOMPARE(QColor(monolsb.pixel(0, 0)), QColor(Qt::black));
+ mono.pixel(0, 0); // Don't crash
+ monolsb.pixel(0, 0); // Don't crash
indexed.pixel(0, 0); // Don't crash
}
}
diff --git a/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp b/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp
index 6bb502edcb..fb6b0c6e32 100644
--- a/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp
+++ b/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp
@@ -673,6 +673,12 @@ void tst_QTcpSocket::bindThenResolveHost()
const quint16 port = 80;
socket->connectToHost(hostName, port);
+ // Additionally, initiate a delayed close before the socket connects
+ // to ensure that we don't lose the socket engine in HostLookupState.
+ // After a connection has been established, socket should send all
+ // the pending data and close the socket engine automatically.
+ QVERIFY(socket->putChar(0));
+ socket->close();
QVERIFY2(socket->waitForConnected(), (hostName.toLocal8Bit() + ": " + QByteArray::number(port) + ' '
+ QtNetworkSettings::msgSocketError(*socket)).constData());
diff --git a/tests/auto/other/qobjectrace/tst_qobjectrace.cpp b/tests/auto/other/qobjectrace/tst_qobjectrace.cpp
index ae5953aa35..aa78d70716 100644
--- a/tests/auto/other/qobjectrace/tst_qobjectrace.cpp
+++ b/tests/auto/other/qobjectrace/tst_qobjectrace.cpp
@@ -46,6 +46,7 @@ class tst_QObjectRace: public QObject
private slots:
void moveToThreadRace();
void destroyRace();
+ void disconnectRace();
};
class RaceObject : public QObject
@@ -293,6 +294,180 @@ void tst_QObjectRace::destroyRace()
delete threads[i];
}
+static QAtomicInteger<unsigned> countedStructObjectsCount;
+struct CountedFunctor
+{
+ CountedFunctor() : destroyed(false) { countedStructObjectsCount.fetchAndAddRelaxed(1); }
+ CountedFunctor(const CountedFunctor &) : destroyed(false) { countedStructObjectsCount.fetchAndAddRelaxed(1); }
+ CountedFunctor &operator=(const CountedFunctor &) { return *this; }
+ ~CountedFunctor() { destroyed = true; countedStructObjectsCount.fetchAndAddRelaxed(-1);}
+ void operator()() const {QCOMPARE(destroyed, false);}
+
+private:
+ bool destroyed;
+};
+
+class DisconnectRaceSenderObject : public QObject
+{
+ Q_OBJECT
+signals:
+ void theSignal();
+};
+
+class DisconnectRaceThread : public QThread
+{
+ Q_OBJECT
+
+ DisconnectRaceSenderObject *sender;
+ bool emitSignal;
+public:
+ DisconnectRaceThread(DisconnectRaceSenderObject *s, bool emitIt)
+ : QThread(), sender(s), emitSignal(emitIt)
+ {
+ }
+
+ void run()
+ {
+ while (!isInterruptionRequested()) {
+ QMetaObject::Connection conn = connect(sender, &DisconnectRaceSenderObject::theSignal,
+ sender, CountedFunctor(), Qt::BlockingQueuedConnection);
+ if (emitSignal)
+ emit sender->theSignal();
+ disconnect(conn);
+ yieldCurrentThread();
+ }
+ }
+};
+
+class DeleteReceiverRaceSenderThread : public QThread
+{
+ Q_OBJECT
+
+ DisconnectRaceSenderObject *sender;
+public:
+ DeleteReceiverRaceSenderThread(DisconnectRaceSenderObject *s)
+ : QThread(), sender(s)
+ {
+ }
+
+ void run()
+ {
+ while (!isInterruptionRequested()) {
+ emit sender->theSignal();
+ yieldCurrentThread();
+ }
+ }
+};
+
+class DeleteReceiverRaceReceiver : public QObject
+{
+ Q_OBJECT
+
+ DisconnectRaceSenderObject *sender;
+ QObject *receiver;
+ QTimer *timer;
+public:
+ DeleteReceiverRaceReceiver(DisconnectRaceSenderObject *s)
+ : QObject(), sender(s), receiver(0)
+ {
+ timer = new QTimer(this);
+ connect(timer, &QTimer::timeout, this, &DeleteReceiverRaceReceiver::onTimeout);
+ timer->start(1);
+ }
+
+ void onTimeout()
+ {
+ if (receiver)
+ delete receiver;
+ receiver = new QObject;
+ connect(sender, &DisconnectRaceSenderObject::theSignal, receiver, CountedFunctor(), Qt::BlockingQueuedConnection);
+ }
+};
+
+class DeleteReceiverRaceReceiverThread : public QThread
+{
+ Q_OBJECT
+
+ DisconnectRaceSenderObject *sender;
+public:
+ DeleteReceiverRaceReceiverThread(DisconnectRaceSenderObject *s)
+ : QThread(), sender(s)
+ {
+ }
+
+ void run()
+ {
+ QScopedPointer<DeleteReceiverRaceReceiver> receiver(new DeleteReceiverRaceReceiver(sender));
+ exec();
+ }
+};
+
+void tst_QObjectRace::disconnectRace()
+{
+ enum { ThreadCount = 20, TimeLimit = 3000 };
+
+ QCOMPARE(countedStructObjectsCount.load(), 0u);
+
+ {
+ QScopedPointer<DisconnectRaceSenderObject> sender(new DisconnectRaceSenderObject());
+ QScopedPointer<QThread> senderThread(new QThread());
+ senderThread->start();
+ sender->moveToThread(senderThread.data());
+
+ DisconnectRaceThread *threads[ThreadCount];
+ for (int i = 0; i < ThreadCount; ++i) {
+ threads[i] = new DisconnectRaceThread(sender.data(), !(i % 10));
+ threads[i]->start();
+ }
+
+ QTime timeLimiter;
+ timeLimiter.start();
+
+ while (timeLimiter.elapsed() < TimeLimit)
+ QTest::qWait(10);
+
+ for (int i = 0; i < ThreadCount; ++i) {
+ threads[i]->requestInterruption();
+ QVERIFY(threads[i]->wait(300));
+ delete threads[i];
+ }
+
+ senderThread->quit();
+ QVERIFY(senderThread->wait(300));
+ }
+
+ QCOMPARE(countedStructObjectsCount.load(), 0u);
+
+ {
+ QScopedPointer<DisconnectRaceSenderObject> sender(new DisconnectRaceSenderObject());
+ QScopedPointer<DeleteReceiverRaceSenderThread> senderThread(new DeleteReceiverRaceSenderThread(sender.data()));
+ senderThread->start();
+ sender->moveToThread(senderThread.data());
+
+ DeleteReceiverRaceReceiverThread *threads[ThreadCount];
+ for (int i = 0; i < ThreadCount; ++i) {
+ threads[i] = new DeleteReceiverRaceReceiverThread(sender.data());
+ threads[i]->start();
+ }
+
+ QTime timeLimiter;
+ timeLimiter.start();
+
+ while (timeLimiter.elapsed() < TimeLimit)
+ QTest::qWait(10);
+
+ senderThread->requestInterruption();
+ QVERIFY(senderThread->wait(300));
+
+ for (int i = 0; i < ThreadCount; ++i) {
+ threads[i]->quit();
+ QVERIFY(threads[i]->wait(300));
+ delete threads[i];
+ }
+ }
+
+ QCOMPARE(countedStructObjectsCount.load(), 0u);
+}
QTEST_MAIN(tst_QObjectRace)
#include "tst_qobjectrace.moc"
diff --git a/tests/auto/tools/moc/tst_moc.cpp b/tests/auto/tools/moc/tst_moc.cpp
index 94df29f539..dc28422294 100644
--- a/tests/auto/tools/moc/tst_moc.cpp
+++ b/tests/auto/tools/moc/tst_moc.cpp
@@ -2034,6 +2034,13 @@ void tst_Moc::warnings_data()
<< 0
<< QString("IGNORE_ALL_STDOUT")
<< QStringLiteral("Warning: Failed to resolve include \"doesnotexist.h\" for moc file <standard input>");
+
+ QTest::newRow("QTBUG-54815: Crash on invalid input")
+ << QByteArray("class M{(})F<{}d000000000000000#0")
+ << QStringList()
+ << 0
+ << QString()
+ << QString("standard input:1: Note: No relevant classes found. No output generated.");
}
void tst_Moc::warnings()
diff --git a/tests/auto/widgets/itemviews/qitemdelegate/qitemdelegate.pro b/tests/auto/widgets/itemviews/qitemdelegate/qitemdelegate.pro
index 9405c33a48..10cd1dcc54 100644
--- a/tests/auto/widgets/itemviews/qitemdelegate/qitemdelegate.pro
+++ b/tests/auto/widgets/itemviews/qitemdelegate/qitemdelegate.pro
@@ -1,6 +1,6 @@
CONFIG += testcase
TARGET = tst_qitemdelegate
-QT += widgets testlib
+QT += widgets widgets-private testlib
SOURCES += tst_qitemdelegate.cpp
win32:!winrt: LIBS += -luser32
diff --git a/tests/auto/widgets/itemviews/qitemdelegate/tst_qitemdelegate.cpp b/tests/auto/widgets/itemviews/qitemdelegate/tst_qitemdelegate.cpp
index e67edfcccb..0720a4f766 100644
--- a/tests/auto/widgets/itemviews/qitemdelegate/tst_qitemdelegate.cpp
+++ b/tests/auto/widgets/itemviews/qitemdelegate/tst_qitemdelegate.cpp
@@ -51,6 +51,8 @@
#include <QPlainTextEdit>
#include <QDialog>
+#include <QtWidgets/private/qabstractitemdelegate_p.h>
+
Q_DECLARE_METATYPE(QAbstractItemDelegate::EndEditHint)
#if defined (Q_OS_WIN) && !defined(Q_OS_WINRT)
@@ -216,6 +218,8 @@ private slots:
void task257859_finalizeEdit();
void QTBUG4435_keepSelectionOnCheck();
+
+ void QTBUG16469_textForRole();
};
@@ -1521,6 +1525,64 @@ void tst_QItemDelegate::testLineEditValidation()
QCOMPARE(item->data(Qt::DisplayRole).toString(), QStringLiteral("abc,def"));
}
+void tst_QItemDelegate::QTBUG16469_textForRole()
+{
+#ifndef QT_BUILD_INTERNAL
+ QSKIP("This test requires a developer build");
+#else
+ struct TestDelegate : public QItemDelegate
+ {
+ QString textForRole(Qt::ItemDataRole role, const QVariant &value, const QLocale &locale)
+ {
+ QAbstractItemDelegatePrivate *d = reinterpret_cast<QAbstractItemDelegatePrivate *>(qGetPtrHelper(d_ptr));
+ return d->textForRole(role, value, locale);
+ }
+ } delegate;
+ QLocale locale;
+
+ const float f = 123.456f;
+ QCOMPARE(delegate.textForRole(Qt::DisplayRole, f, locale), locale.toString(f));
+ QCOMPARE(delegate.textForRole(Qt::ToolTipRole, f, locale), locale.toString(f));
+ const double d = 123.456;
+ QCOMPARE(delegate.textForRole(Qt::DisplayRole, d, locale), locale.toString(d, 'g', 6));
+ QCOMPARE(delegate.textForRole(Qt::ToolTipRole, d, locale), locale.toString(d, 'g', 6));
+ const int i = 1234567;
+ QCOMPARE(delegate.textForRole(Qt::DisplayRole, i, locale), locale.toString(i));
+ QCOMPARE(delegate.textForRole(Qt::ToolTipRole, i, locale), locale.toString(i));
+ const qlonglong ll = 1234567;
+ QCOMPARE(delegate.textForRole(Qt::DisplayRole, ll, locale), locale.toString(ll));
+ QCOMPARE(delegate.textForRole(Qt::ToolTipRole, ll, locale), locale.toString(ll));
+ const uint ui = 1234567;
+ QCOMPARE(delegate.textForRole(Qt::DisplayRole, ui, locale), locale.toString(ui));
+ QCOMPARE(delegate.textForRole(Qt::ToolTipRole, ui, locale), locale.toString(ui));
+ const qulonglong ull = 1234567;
+ QCOMPARE(delegate.textForRole(Qt::DisplayRole, ull, locale), locale.toString(ull));
+ QCOMPARE(delegate.textForRole(Qt::ToolTipRole, ull, locale), locale.toString(ull));
+
+ const QDateTime dateTime = QDateTime::currentDateTime();
+ const QDate date = dateTime.date();
+ const QTime time = dateTime.time();
+ const QString shortDate = locale.toString(date, QLocale::ShortFormat);
+ const QString longDate = locale.toString(date, QLocale::LongFormat);
+ const QString shortTime = locale.toString(time, QLocale::ShortFormat);
+ const QString longTime = locale.toString(time, QLocale::LongFormat);
+ QCOMPARE(delegate.textForRole(Qt::DisplayRole, date, locale), shortDate);
+ QCOMPARE(delegate.textForRole(Qt::ToolTipRole, date, locale), longDate);
+ QCOMPARE(delegate.textForRole(Qt::DisplayRole, time, locale), shortTime);
+ QCOMPARE(delegate.textForRole(Qt::ToolTipRole, time, locale), longTime);
+ QCOMPARE(delegate.textForRole(Qt::DisplayRole, dateTime, locale), shortDate + QLatin1Char(' ') + shortTime);
+ QCOMPARE(delegate.textForRole(Qt::ToolTipRole, dateTime, locale), longDate + QLatin1Char(' ') + longTime);
+
+ const QString text("text");
+ QCOMPARE(delegate.textForRole(Qt::DisplayRole, text, locale), text);
+ QCOMPARE(delegate.textForRole(Qt::ToolTipRole, text, locale), text);
+ const QString multipleLines("multiple\nlines");
+ QString multipleLines2 = multipleLines;
+ multipleLines2.replace(QLatin1Char('\n'), QChar::LineSeparator);
+ QCOMPARE(delegate.textForRole(Qt::DisplayRole, multipleLines, locale), multipleLines2);
+ QCOMPARE(delegate.textForRole(Qt::ToolTipRole, multipleLines, locale), multipleLines);
+#endif
+}
// ### _not_ covered:
diff --git a/tests/manual/embeddedintoforeignwindow/embeddedintoforeignwindow.pro b/tests/manual/embeddedintoforeignwindow/embeddedintoforeignwindow.pro
new file mode 100644
index 0000000000..93da4b8c91
--- /dev/null
+++ b/tests/manual/embeddedintoforeignwindow/embeddedintoforeignwindow.pro
@@ -0,0 +1,7 @@
+TEMPLATE = app
+QT += gui-private
+CONFIG += console c++11
+CONFIG -= app_bundle
+SOURCES += main.cpp itemwindow.cpp
+HEADERS += itemwindow.h
+include(../diaglib/diaglib.pri)
diff --git a/tests/manual/embeddedintoforeignwindow/itemwindow.cpp b/tests/manual/embeddedintoforeignwindow/itemwindow.cpp
new file mode 100644
index 0000000000..32a2e6557c
--- /dev/null
+++ b/tests/manual/embeddedintoforeignwindow/itemwindow.cpp
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** 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 http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://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 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "itemwindow.h"
+
+#include <QtGui/QPainter>
+#include <QtGui/QPaintEvent>
+
+void TextItem::paint(QPainter &painter)
+{
+ painter.fillRect(m_rect, m_col);
+ painter.drawRect(m_rect);
+ QTextOption textOption;
+ textOption.setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
+ painter.drawText(m_rect, m_text, textOption);
+}
+
+void ButtonItem::mouseEvent(QMouseEvent *mouseEvent)
+{
+ if (mouseEvent->type() == QEvent::MouseButtonPress && rect().contains(mouseEvent->pos())) {
+ mouseEvent->accept();
+ emit clicked();
+ }
+}
+
+void ButtonItem::keyEvent(QKeyEvent *keyEvent)
+{
+ if (m_shortcut && keyEvent->type() == QEvent::KeyPress
+ && (keyEvent->key() + int(keyEvent->modifiers())) == m_shortcut) {
+ keyEvent->accept();
+ emit clicked();
+ }
+}
+
+void ItemWindow::paintEvent(QPaintEvent *)
+{
+ QPainter painter(this);
+ QRect rect(QPoint(0, 0), size());
+ painter.fillRect(rect, m_background);
+ foreach (Item *i, m_items)
+ i->paint(painter);
+}
diff --git a/tests/manual/embeddedintoforeignwindow/itemwindow.h b/tests/manual/embeddedintoforeignwindow/itemwindow.h
new file mode 100644
index 0000000000..8ea9adaa16
--- /dev/null
+++ b/tests/manual/embeddedintoforeignwindow/itemwindow.h
@@ -0,0 +1,126 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** 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 http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://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 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ITEMWINDOW_H
+#define ITEMWINDOW_H
+
+#include <QtGui/QKeySequence>
+#include <QtGui/QRasterWindow>
+
+QT_USE_NAMESPACE
+
+// ItemWindow: Primitive UI item classes for use with a ItemWindow based
+// on QRasterWindow without widgets allowing a simple UI without widgets.
+
+// Basic item to be used in a ItemWindow
+class Item : public QObject {
+ Q_OBJECT
+public:
+ explicit Item(QObject *parent = nullptr) : QObject(parent) {}
+
+ virtual void paint(QPainter &painter) = 0;
+ virtual void mouseEvent(QMouseEvent *) {}
+ virtual void keyEvent(QKeyEvent *) {}
+};
+
+// Positionable text item
+class TextItem : public Item {
+ Q_OBJECT
+public:
+ explicit TextItem(const QString &text, const QRect &rect, const QColor &col,
+ QObject *parent = nullptr)
+ : Item(parent), m_text(text), m_rect(rect), m_col(col) {}
+
+ void paint(QPainter &painter) override;
+
+ QRect rect() const { return m_rect; }
+
+private:
+ const QString m_text;
+ const QRect m_rect;
+ const QColor m_col;
+};
+
+// "button" item
+class ButtonItem : public TextItem {
+ Q_OBJECT
+public:
+ explicit ButtonItem(const QString &text, const QRect &rect, const QColor &col,
+ QObject *parent = nullptr)
+ : TextItem(text, rect, col, parent), m_shortcut(0) {}
+
+ void mouseEvent(QMouseEvent *mouseEvent) override;
+ void keyEvent(QKeyEvent *keyEvent) override;
+
+ int shortcut() const { return m_shortcut; }
+ void setShortcut(int shortcut) { m_shortcut = shortcut; }
+
+signals:
+ void clicked();
+
+private:
+ int m_shortcut;
+};
+
+#define PROPAGATE_EVENT(windowHandler, eventClass, itemHandler) \
+void windowHandler(eventClass *e) override \
+{ \
+ foreach (Item *i, m_items) \
+ i->itemHandler(e); \
+}
+
+class ItemWindow : public QRasterWindow {
+ Q_OBJECT
+public:
+ explicit ItemWindow(QWindow *parent = nullptr) : QRasterWindow(parent), m_background(Qt::white) {}
+
+ void addItem(Item *item) { m_items.append(item); }
+
+ QColor background() const { return m_background; }
+ void setBackground(const QColor &background) { m_background = background; }
+
+protected:
+ void paintEvent(QPaintEvent *) override;
+ PROPAGATE_EVENT(mousePressEvent, QMouseEvent, mouseEvent)
+ PROPAGATE_EVENT(mouseReleaseEvent, QMouseEvent, mouseEvent)
+ PROPAGATE_EVENT(mouseDoubleClickEvent, QMouseEvent, mouseEvent)
+ PROPAGATE_EVENT(mouseMoveEvent, QMouseEvent, mouseEvent)
+ PROPAGATE_EVENT(keyPressEvent, QKeyEvent, keyEvent)
+ PROPAGATE_EVENT(keyReleaseEvent, QKeyEvent, keyEvent)
+
+private:
+ QList<Item *> m_items;
+ QColor m_background;
+};
+
+#endif // ITEMWINDOW_H
diff --git a/tests/manual/embeddedintoforeignwindow/main.cpp b/tests/manual/embeddedintoforeignwindow/main.cpp
new file mode 100644
index 0000000000..d7b33683a7
--- /dev/null
+++ b/tests/manual/embeddedintoforeignwindow/main.cpp
@@ -0,0 +1,287 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** 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 http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://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 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "itemwindow.h"
+
+#include <QtGui/QGuiApplication>
+
+#include <QtCore/QCommandLineOption>
+#include <QtCore/QCommandLineParser>
+#include <QtCore/QDebug>
+#include <QtCore/QStringList>
+
+#ifdef Q_OS_WIN
+# include <qpa/qplatformnativeinterface.h>
+# include <QtCore/QMetaObject>
+# include <QtCore/qt_windows.h>
+#endif
+
+#include <eventfilter.h> // diaglib
+#include <qwindowdump.h>
+
+#include <iostream>
+
+QT_USE_NAMESPACE
+
+static const char usage[] =
+ "\nEmbeds a QWindow into a native foreign window passed on the command line.\n"
+ "When no window ID is passed, a test window is created (Windows only).";
+
+static QString windowTitle()
+{
+ return QLatin1String(QT_VERSION_STR) + QLatin1Char(' ') + QGuiApplication::platformName();
+}
+
+#ifdef Q_OS_WIN
+// Helper to create a native test window (Windows)
+static QString registerWindowClass(const QString &name)
+{
+ QString result;
+ void *proc = DefWindowProc;
+ QPlatformNativeInterface *ni = QGuiApplication::platformNativeInterface();
+ if (!QMetaObject::invokeMethod(ni, "registerWindowClass", Qt::DirectConnection,
+ Q_RETURN_ARG(QString, result),
+ Q_ARG(QString, name),
+ Q_ARG(void *, proc))) {
+ qWarning("registerWindowClass failed");
+ }
+ return result;
+}
+
+static HWND createNativeWindow(const QString &name)
+{
+ const HWND hwnd =
+ CreateWindowEx(0, reinterpret_cast<const wchar_t *>(name.utf16()),
+ L"NativeWindow", WS_OVERLAPPEDWINDOW,
+ CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
+ 0, 0, GetModuleHandle(NULL), NULL);
+
+ if (!hwnd) {
+ qErrnoWarning("Cannot create window \"%s\"", qPrintable(name));
+ return 0;
+ }
+
+ const QString text = windowTitle() + QLatin1String(" 0x") + QString::number(quint64(hwnd), 16);
+ SetWindowText(hwnd, reinterpret_cast<const wchar_t *>(text.utf16()));
+ return hwnd;
+}
+#endif // Q_OS_WIN
+
+// Helper functions for simple management of native windows.
+static WId createNativeTestWindow()
+{
+ WId result = 0;
+#ifdef Q_OS_WIN
+ const QString className = registerWindowClass(QLatin1String("TestClass") + windowTitle());
+ const HWND nativeWin = createNativeWindow(className);
+ result = WId(nativeWin);
+#else // Q_OS_WIN
+ Q_UNIMPLEMENTED();
+#endif
+ return result;
+}
+
+static void showNativeWindow(WId wid)
+{
+#ifdef Q_OS_WIN
+ ShowWindow(HWND(wid), SW_SHOW);
+#else // Q_OS_WIN
+ Q_UNUSED(wid)
+ Q_UNIMPLEMENTED();
+#endif
+}
+
+static void setFocusToNativeWindow(WId wid)
+{
+#ifdef Q_OS_WIN
+ SetFocus(HWND(wid));
+#else // Q_OS_WIN
+ Q_UNUSED(wid)
+ Q_UNIMPLEMENTED();
+#endif
+}
+
+static void destroyNativeWindow(WId wid)
+{
+#ifdef Q_OS_WIN
+ DestroyWindow(HWND(wid));
+#else // Q_OS_WIN
+ Q_UNUSED(wid)
+ Q_UNIMPLEMENTED();
+#endif
+}
+
+// Main test window to be embedded into foreign window with some buttons.
+class EmbeddedTestWindow : public ItemWindow {
+ Q_OBJECT
+public:
+ explicit EmbeddedTestWindow(QWindow *parent = nullptr) : ItemWindow(parent)
+ {
+ const int spacing = 10;
+ const QSize buttonSize(100, 30);
+ const int width = 3 * buttonSize.width() + 4 * spacing;
+
+ QPoint pos(spacing, spacing);
+ addItem(new TextItem(::windowTitle(), QRect(pos, QSize(width - 2 * spacing, buttonSize.height())),
+ Qt::white));
+
+ pos.ry() += 2 * spacing + buttonSize.height();
+
+ ButtonItem *mgi = new ButtonItem("Map to global", QRect(pos, buttonSize),
+ QColor(Qt::yellow).lighter(), this);
+ connect(mgi, &ButtonItem::clicked, this, &EmbeddedTestWindow::testMapToGlobal);
+ addItem(mgi);
+
+ pos.rx() += buttonSize.width() + spacing;
+ ButtonItem *di = new ButtonItem("Dump Wins", QRect(pos, buttonSize),
+ QColor(Qt::cyan).lighter(), this);
+ connect(di, &ButtonItem::clicked, this, [] () { QtDiag::dumpAllWindows(); });
+ addItem(di);
+
+ pos.rx() += buttonSize.width() + spacing;
+ ButtonItem *qi = new ButtonItem("Quit", QRect(pos, buttonSize),
+ QColor(Qt::red).lighter(), this);
+ qi->setShortcut(Qt::CTRL + Qt::Key_Q);
+ connect(qi, &ButtonItem::clicked, qApp, &QCoreApplication::quit);
+ addItem(qi);
+
+ setBackground(Qt::lightGray);
+ resize(width, pos.y() + buttonSize.height() + spacing);
+ }
+
+public slots:
+ void testMapToGlobal();
+};
+
+void EmbeddedTestWindow::testMapToGlobal()
+{
+ const QPoint globalPos = mapToGlobal(QPoint(0,0));
+ qDebug() << "mapToGlobal(QPoint(0,0)" << globalPos
+ << "cursor at:" << QCursor::pos();
+}
+
+struct EventFilterOption
+{
+ const char *name;
+ const char *description;
+ QtDiag::EventFilter::EventCategories categories;
+};
+
+EventFilterOption eventFilterOptions[] = {
+{"mouse-events", "Dump mouse events.", QtDiag::EventFilter::MouseEvents},
+{"keyboard-events", "Dump keyboard events.", QtDiag::EventFilter::KeyEvents},
+{"state-events", "Dump state/focus change events.", QtDiag::EventFilter::StateChangeEvents | QtDiag::EventFilter::FocusEvents}
+};
+
+static inline bool isOptionSet(int argc, char *argv[], const char *option)
+{
+ return (argv + argc) !=
+ std::find_if(argv + 1, argv + argc,
+ [option] (const char *arg) { return !qstrcmp(arg, option); });
+}
+
+int main(int argc, char *argv[])
+{
+ // Check for no scaling before QApplication is instantiated.
+ if (isOptionSet(argc, argv, "-s"))
+ QCoreApplication::setAttribute(Qt::AA_DisableHighDpiScaling);
+ QCoreApplication::setApplicationVersion(QLatin1String(QT_VERSION_STR));
+ QGuiApplication::setApplicationDisplayName("Foreign Window Embedding Tester");
+
+ QGuiApplication app(argc, argv);
+
+ // Process command line
+ QCommandLineParser parser;
+ parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions);
+ parser.setApplicationDescription(QLatin1String(usage));
+ parser.addHelpOption();
+ parser.addVersionOption();
+ QCommandLineOption noScalingDummy(QStringLiteral("s"),
+ QStringLiteral("Disable High DPI scaling."));
+ parser.addOption(noScalingDummy);
+ const int eventFilterOptionCount = int(sizeof(eventFilterOptions) / sizeof(eventFilterOptions[0]));
+ for (int i = 0; i < eventFilterOptionCount; ++i) {
+ parser.addOption(QCommandLineOption(QLatin1String(eventFilterOptions[i].name),
+ QLatin1String(eventFilterOptions[i].description)));
+ }
+ parser.addPositionalArgument(QStringLiteral("[windows]"), QStringLiteral("Window ID."));
+
+ parser.process(QCoreApplication::arguments());
+
+ QtDiag::EventFilter::EventCategories eventCategories = 0;
+ for (int i = 0; i < eventFilterOptionCount; ++i) {
+ if (parser.isSet(QLatin1String(eventFilterOptions[i].name)))
+ eventCategories |= eventFilterOptions[i].categories;
+ }
+ if (eventCategories)
+ app.installEventFilter(new QtDiag::EventFilter(eventCategories, &app));
+
+ // Obtain foreign window to test with.
+ WId testForeignWinId = 0;
+ bool createdTestWindow = false;
+ if (parser.positionalArguments().isEmpty()) {
+ testForeignWinId = createNativeTestWindow();
+ if (!testForeignWinId)
+ parser.showHelp(-1);
+ showNativeWindow(testForeignWinId);
+ createdTestWindow = true;
+ } else {
+ bool ok;
+ const QString &winIdArgument = parser.positionalArguments().constFirst();
+ testForeignWinId = winIdArgument.toULongLong(&ok, 0);
+ if (!ok) {
+ std::cerr << "Invalid window id: \"" << qPrintable(winIdArgument) << "\"\n";
+ return -1;
+ }
+ }
+ if (!testForeignWinId)
+ parser.showHelp(1);
+
+ QWindow *foreignWindow = QWindow::fromWinId(testForeignWinId);
+ if (!foreignWindow)
+ return -2;
+ foreignWindow->setObjectName("ForeignWindow");
+ EmbeddedTestWindow *embeddedTestWindow = new EmbeddedTestWindow(foreignWindow);
+ embeddedTestWindow->setObjectName("EmbeddedTestWindow");
+ embeddedTestWindow->show();
+ setFocusToNativeWindow(embeddedTestWindow->winId()); // Windows: Set keyboard focus.
+
+ const int exitCode = app.exec();
+ delete embeddedTestWindow;
+ delete foreignWindow;
+ if (createdTestWindow)
+ destroyNativeWindow(testForeignWinId);
+ return exitCode;
+}
+
+#include "main.moc"
diff --git a/tests/manual/manual.pro b/tests/manual/manual.pro
index 6f77c82dc5..b9789c354d 100644
--- a/tests/manual/manual.pro
+++ b/tests/manual/manual.pro
@@ -2,8 +2,10 @@ TEMPLATE=subdirs
SUBDIRS = bearerex \
filetest \
+embeddedintoforeignwindow \
foreignwindows \
gestures \
+highdpi \
inputmethodhints \
keypadnavigation \
lance \
@@ -62,4 +64,4 @@ win32: SUBDIRS -= network_remote_stresstest network_stresstest
lessThan(QT_MAJOR_VERSION, 5): SUBDIRS -= bearerex lance qnetworkaccessmanager/qget qmimedatabase qnetworkreply \
qpainfo qscreen socketengine xembed-raster xembed-widgets windowtransparency \
-foreignwindows
+embeddedintoforeignwindow foreignwindows