diff options
Diffstat (limited to 'tests/auto/gui/image/qpixmapcache/tst_qpixmapcache.cpp')
-rw-r--r-- | tests/auto/gui/image/qpixmapcache/tst_qpixmapcache.cpp | 149 |
1 files changed, 130 insertions, 19 deletions
diff --git a/tests/auto/gui/image/qpixmapcache/tst_qpixmapcache.cpp b/tests/auto/gui/image/qpixmapcache/tst_qpixmapcache.cpp index d4c39a2130..8384a46491 100644 --- a/tests/auto/gui/image/qpixmapcache/tst_qpixmapcache.cpp +++ b/tests/auto/gui/image/qpixmapcache/tst_qpixmapcache.cpp @@ -1,5 +1,5 @@ // Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> @@ -7,12 +7,16 @@ #include <qpixmapcache.h> #include "private/qpixmapcache_p.h" +#include <functional> + QT_BEGIN_NAMESPACE // The test requires QT_BUILD_INTERNAL Q_AUTOTEST_EXPORT void qt_qpixmapcache_flush_detached_pixmaps(); Q_AUTOTEST_EXPORT int qt_qpixmapcache_qpixmapcache_total_used(); Q_AUTOTEST_EXPORT int q_QPixmapCache_keyHashSize(); QT_END_NAMESPACE +using namespace Qt::StringLiterals; + class tst_QPixmapCache : public QObject { Q_OBJECT @@ -29,13 +33,22 @@ private slots: void setCacheLimit(); void find(); void insert(); + void failedInsertReturnsInvalidKey(); +#if QT_DEPRECATED_SINCE(6, 6) void replace(); +#endif void remove(); void clear(); void pixmapKey(); void noLeak(); + void clearDoesNotLeakStringKeys(); + void evictionDoesNotLeakStringKeys(); + void reducingCacheLimitDoesNotLeakStringKeys(); void strictCacheLimit(); void noCrashOnLargeInsert(); + +private: + void stringLeak_impl(std::function<void()> whenOp); }; static QPixmapCache::KeyData* getPrivate(QPixmapCache::Key &key) @@ -102,28 +115,32 @@ void tst_QPixmapCache::setCacheLimit() //The int part of the API p1 = new QPixmap(2, 3); QPixmapCache::Key key = QPixmapCache::insert(*p1); - QVERIFY(QPixmapCache::find(key, p1) != 0); + QVERIFY(QPixmapCache::find(key, p1)); delete p1; QPixmapCache::setCacheLimit(0); - QVERIFY(QPixmapCache::find(key, p1) == 0); + QVERIFY(!QPixmapCache::find(key, p1)); - p1 = new QPixmap(2, 3); QPixmapCache::setCacheLimit(1000); - QPixmapCache::replace(key, *p1); - QVERIFY(QPixmapCache::find(key, p1) == 0); +#if QT_DEPRECATED_SINCE(6, 6) + QT_WARNING_PUSH + QT_WARNING_DISABLE_DEPRECATED + p1 = new QPixmap(2, 3); + QVERIFY(!QPixmapCache::replace(key, *p1)); + QVERIFY(!QPixmapCache::find(key, p1)); delete p1; +#endif // QT_DEPRECATED_SINCE(6, 6) //Let check if keys are released when the pixmap cache is //full or has been flushed. QPixmapCache::clear(); p1 = new QPixmap(2, 3); key = QPixmapCache::insert(*p1); - QVERIFY(QPixmapCache::find(key, p1) != 0); + QVERIFY(QPixmapCache::find(key, p1)); p1->detach(); // dectach so that the cache thinks no-one is using it. QPixmapCache::setCacheLimit(0); - QVERIFY(QPixmapCache::find(key, p1) == 0); + QVERIFY(!QPixmapCache::find(key, p1)); QPixmapCache::setCacheLimit(1000); key = QPixmapCache::insert(*p1); QVERIFY(key.isValid()); @@ -137,7 +154,7 @@ void tst_QPixmapCache::setCacheLimit() QPixmap p2; p1 = new QPixmap(2, 3); key = QPixmapCache::insert(*p1); - QVERIFY(QPixmapCache::find(key, &p2) != 0); + QVERIFY(QPixmapCache::find(key, &p2)); //we flush the cache p1->detach(); p2.detach(); @@ -145,8 +162,8 @@ void tst_QPixmapCache::setCacheLimit() QPixmapCache::setCacheLimit(1000); QPixmapCache::Key key2 = QPixmapCache::insert(*p1); QCOMPARE(getPrivate(key2)->key, 1); - QVERIFY(QPixmapCache::find(key, &p2) == 0); - QVERIFY(QPixmapCache::find(key2, &p2) != 0); + QVERIFY(!QPixmapCache::find(key, &p2)); + QVERIFY(QPixmapCache::find(key2, &p2)); QCOMPARE(p2, *p1); delete p1; @@ -169,7 +186,7 @@ void tst_QPixmapCache::setCacheLimit() QCOMPARE(getPrivate(key2)->key, 1); //This old key is not valid anymore after the flush QVERIFY(!key.isValid()); - QVERIFY(QPixmapCache::find(key, &p2) == 0); + QVERIFY(!QPixmapCache::find(key, &p2)); delete p1; } @@ -207,7 +224,7 @@ void tst_QPixmapCache::find() QPixmapCache::insert(p5); //at that time the first key has been erase because no more place in the cache - QVERIFY(QPixmapCache::find(key, &p1) == 0); + QVERIFY(!QPixmapCache::find(key, &p1)); QVERIFY(!key.isValid()); } @@ -266,6 +283,7 @@ void tst_QPixmapCache::insert() for (int i = 0; i < numberOfKeys; ++i) { QPixmap p3(10,10); keys.append(QPixmapCache::insert(p3)); + QVERIFY(keys.back().isValid()); } num = 0; @@ -279,6 +297,35 @@ void tst_QPixmapCache::insert() QVERIFY(num <= estimatedNum); } +void tst_QPixmapCache::failedInsertReturnsInvalidKey() +{ + // + // GIVEN: a pixmap whose memory footprint exceeds the cache's limit: + // + QPixmapCache::setCacheLimit(20); + + QPixmap pm(256, 256); + pm.fill(Qt::transparent); + QCOMPARE_GT(pm.width() * pm.height() * pm.depth() / 8, + QPixmapCache::cacheLimit() * 1024); + + // + // WHEN: trying to add this pixmap to the cache + // + const auto success = QPixmapCache::insert(u"foo"_s, pm); // QString API + { QPixmap r; QVERIFY(!QPixmapCache::find(u"foo"_s, &r)); } + const auto key = QPixmapCache::insert(pm); // "int" API + + // + // THEN: failure is reported to the user + // + QVERIFY(!key.isValid()); // "int" API + QVERIFY(!success); // QString API +} + +#if QT_DEPRECATED_SINCE(6, 6) +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED void tst_QPixmapCache::replace() { //The int part of the API @@ -307,6 +354,8 @@ void tst_QPixmapCache::replace() //Broken keys QCOMPARE(QPixmapCache::replace(QPixmapCache::Key(), p2), false); } +QT_WARNING_POP +#endif // QT_DEPRECATED_SINCE(6, 6) void tst_QPixmapCache::remove() { @@ -340,11 +389,11 @@ void tst_QPixmapCache::remove() QVERIFY(p1.toImage() == p1.toImage()); // sanity check QPixmapCache::remove(key); - QVERIFY(QPixmapCache::find(key, &p1) == 0); + QVERIFY(!QPixmapCache::find(key, &p1)); //Broken key QPixmapCache::remove(QPixmapCache::Key()); - QVERIFY(QPixmapCache::find(QPixmapCache::Key(), &p1) == 0); + QVERIFY(!QPixmapCache::find(QPixmapCache::Key(), &p1)); //Test if keys are release QPixmapCache::clear(); @@ -358,7 +407,7 @@ void tst_QPixmapCache::remove() QPixmapCache::clear(); key = QPixmapCache::insert(p1); QCOMPARE(getPrivate(key)->key, 1); - QVERIFY(QPixmapCache::find(key, &p1) != 0); + QVERIFY(QPixmapCache::find(key, &p1)); QPixmapCache::remove(key); QCOMPARE(p1.isDetached(), true); @@ -368,8 +417,8 @@ void tst_QPixmapCache::remove() QPixmapCache::insert("red", p1); key = QPixmapCache::insert(p1); QPixmapCache::remove(key); - QVERIFY(QPixmapCache::find(key, &p1) == 0); - QVERIFY(QPixmapCache::find("red", &p1) != 0); + QVERIFY(!QPixmapCache::find(key, &p1)); + QVERIFY(QPixmapCache::find("red", &p1)); } void tst_QPixmapCache::clear() @@ -413,7 +462,7 @@ void tst_QPixmapCache::clear() QPixmapCache::clear(); for (int k = 0; k < numberOfKeys; ++k) { - QVERIFY(QPixmapCache::find(keys.at(k), &p1) == 0); + QVERIFY(!QPixmapCache::find(keys.at(k), &p1)); QVERIFY(!keys[k].isValid()); } } @@ -478,6 +527,68 @@ void tst_QPixmapCache::noLeak() QCOMPARE(oldSize, newSize); } +void tst_QPixmapCache::clearDoesNotLeakStringKeys() +{ + stringLeak_impl([] { QPixmapCache::clear(); }); +} + +void tst_QPixmapCache::evictionDoesNotLeakStringKeys() +{ + stringLeak_impl([] { + // fill the cache with other pixmaps to force eviction of "our" pixmap: + constexpr int Iterations = 10; + for (int i = 0; i < Iterations; ++i) { + QPixmap pm(64, 64); + pm.fill(Qt::transparent); + [[maybe_unused]] auto r = QPixmapCache::insert(pm); + } + }); +} + +void tst_QPixmapCache::reducingCacheLimitDoesNotLeakStringKeys() +{ + stringLeak_impl([] { + QPixmapCache::setCacheLimit(0); + }); +} + +void tst_QPixmapCache::stringLeak_impl(std::function<void()> whenOp) +{ + QVERIFY(whenOp); + + QPixmapCache::setCacheLimit(20); // 20KiB + // + // GIVEN: a QPixmap with QString key `key` in QPixmapCache + // + QString key; + { + QPixmap pm(64, 64); + QCOMPARE_LT(pm.width() * pm.height() * std::ceil(pm.depth() / 8.0), + QPixmapCache::cacheLimit() * 1024); + pm.fill(Qt::transparent); + key = u"theKey"_s.repeated(20); // avoid eventual QString SSO + QVERIFY(key.isDetached()); + QPixmapCache::insert(key, pm); + } + QVERIFY(!key.isDetached()); // was saved inside QPixmapCache + + // + // WHEN: performing the given operation + // + whenOp(); + if (QTest::currentTestFailed()) + return; + + // + // THEN: `key` is no longer referenced by QPixmapCache: + // + QVERIFY(key.isDetached()); + // verify that the pixmap is really gone from the cache + // (do it after the key check, because QPixmapCache cleans up `key` on a failed lookup) + QPixmap r; + QVERIFY(!QPixmapCache::find(key, &r)); +} + void tst_QPixmapCache::strictCacheLimit() { |