/**************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include #include #include #include #include #include #include namespace CheckContainerTraits { struct NotAContainer {}; static_assert(QContainerTraits::has_size_v>); static_assert(QContainerTraits::has_size_v>); static_assert(!QContainerTraits::has_size_v); static_assert(QContainerTraits::has_size_v>); static_assert(QContainerTraits::has_size_v>); static_assert(!QContainerTraits::has_size_v>); static_assert(QContainerTraits::has_clear_v>); static_assert(QContainerTraits::has_clear_v>); static_assert(!QContainerTraits::has_clear_v); static_assert(QContainerTraits::has_clear_v>); static_assert(QContainerTraits::has_clear_v>); static_assert(QContainerTraits::has_clear_v>); static_assert(QContainerTraits::has_at_v>); static_assert(!QContainerTraits::has_at_v>); static_assert(!QContainerTraits::has_at_v); static_assert(QContainerTraits::has_at_v>); static_assert(!QContainerTraits::has_at_v>); static_assert(!QContainerTraits::has_at_v>); static_assert(QContainerTraits::can_get_at_index_v>); static_assert(!QContainerTraits::can_get_at_index_v>); static_assert(!QContainerTraits::can_get_at_index_v); static_assert(QContainerTraits::can_get_at_index_v>); static_assert(!QContainerTraits::can_get_at_index_v>); static_assert(!QContainerTraits::can_get_at_index_v>); static_assert(QContainerTraits::can_set_at_index_v>); static_assert(!QContainerTraits::can_set_at_index_v>); static_assert(!QContainerTraits::can_set_at_index_v); static_assert(QContainerTraits::can_set_at_index_v>); static_assert(!QContainerTraits::can_set_at_index_v>); static_assert(!QContainerTraits::can_set_at_index_v>); static_assert(QContainerTraits::has_push_back_v>); static_assert(!QContainerTraits::has_push_back_v>); static_assert(!QContainerTraits::has_push_back_v); static_assert(QContainerTraits::has_push_back_v>); static_assert(!QContainerTraits::has_push_back_v>); static_assert(!QContainerTraits::has_push_back_v>); static_assert(QContainerTraits::has_push_front_v>); static_assert(!QContainerTraits::has_push_front_v>); static_assert(!QContainerTraits::has_push_front_v); static_assert(!QContainerTraits::has_push_front_v>); static_assert(!QContainerTraits::has_push_front_v>); static_assert(QContainerTraits::has_push_front_v>); static_assert(!QContainerTraits::has_insert_v>); static_assert(QContainerTraits::has_insert_v>); static_assert(!QContainerTraits::has_insert_v); static_assert(!QContainerTraits::has_insert_v>); static_assert(QContainerTraits::has_insert_v>); static_assert(!QContainerTraits::has_insert_v>); static_assert(QContainerTraits::has_pop_back_v>); static_assert(!QContainerTraits::has_pop_back_v>); static_assert(!QContainerTraits::has_pop_back_v); static_assert(QContainerTraits::has_pop_back_v>); static_assert(!QContainerTraits::has_pop_back_v>); static_assert(!QContainerTraits::has_pop_back_v>); static_assert(QContainerTraits::has_pop_front_v>); static_assert(!QContainerTraits::has_pop_front_v>); static_assert(!QContainerTraits::has_pop_front_v); static_assert(!QContainerTraits::has_pop_front_v>); static_assert(!QContainerTraits::has_pop_front_v>); static_assert(QContainerTraits::has_pop_front_v>); static_assert(QContainerTraits::has_iterator_v>); static_assert(QContainerTraits::has_iterator_v>); static_assert(!QContainerTraits::has_iterator_v); static_assert(QContainerTraits::has_iterator_v>); static_assert(QContainerTraits::has_iterator_v>); static_assert(QContainerTraits::has_iterator_v>); static_assert(QContainerTraits::has_const_iterator_v>); static_assert(QContainerTraits::has_const_iterator_v>); static_assert(!QContainerTraits::has_const_iterator_v); static_assert(QContainerTraits::has_const_iterator_v>); static_assert(QContainerTraits::has_const_iterator_v>); static_assert(QContainerTraits::has_const_iterator_v>); static_assert(QContainerTraits::can_get_at_iterator_v>); static_assert(QContainerTraits::can_get_at_iterator_v>); static_assert(!QContainerTraits::can_get_at_iterator_v); static_assert(QContainerTraits::can_get_at_iterator_v>); static_assert(QContainerTraits::can_get_at_iterator_v>); static_assert(QContainerTraits::can_get_at_iterator_v>); static_assert(QContainerTraits::can_set_at_iterator_v>); static_assert(!QContainerTraits::can_set_at_iterator_v>); static_assert(!QContainerTraits::can_get_at_iterator_v); static_assert(QContainerTraits::can_set_at_iterator_v>); static_assert(!QContainerTraits::can_set_at_iterator_v>); static_assert(QContainerTraits::can_set_at_iterator_v>); static_assert(QContainerTraits::can_insert_at_iterator_v>); static_assert(!QContainerTraits::can_insert_at_iterator_v>); static_assert(!QContainerTraits::can_insert_at_iterator_v); static_assert(QContainerTraits::can_insert_at_iterator_v>); static_assert(!QContainerTraits::can_insert_at_iterator_v>); // The iterator is only a hint, but syntactically indistinguishable from others. // It's explicitly there to be signature compatible with std::vector::insert, though. // Also, inserting into a set is not guaranteed to actually do anything. static_assert(QContainerTraits::can_insert_at_iterator_v>); static_assert(QContainerTraits::can_erase_at_iterator_v>); static_assert(QContainerTraits::can_erase_at_iterator_v>); static_assert(!QContainerTraits::can_erase_at_iterator_v); static_assert(QContainerTraits::can_erase_at_iterator_v>); static_assert(QContainerTraits::can_erase_at_iterator_v>); static_assert(!QContainerTraits::can_erase_at_iterator_v>); } class tst_QMetaContainer: public QObject { Q_OBJECT private: QVector qvector; std::vector stdvector; QSet qset; std::set stdset; std::forward_list forwardList; private slots: void init(); void testSequence_data(); void testSequence(); void cleanup(); }; void tst_QMetaContainer::init() { qvector = { QMetaType(), QMetaType::fromType(), QMetaType::fromType() }; stdvector = { QStringLiteral("foo"), QStringLiteral("bar"), QStringLiteral("baz") }; qset = { "aaa", "bbb", "ccc" }; stdset = { 1, 2, 3, 42, 45, 11 }; forwardList = { QMetaSequence::fromContainer>(), QMetaSequence::fromContainer>(), QMetaSequence::fromContainer>(), QMetaSequence::fromContainer>(), QMetaSequence::fromContainer>() }; } void tst_QMetaContainer::cleanup() { qvector.clear(); stdvector.clear(); qset.clear(); stdset.clear(); forwardList.clear(); } void tst_QMetaContainer::testSequence_data() { QTest::addColumn("container"); QTest::addColumn("metaSequence"); QTest::addColumn("metaType"); QTest::addColumn("hasSize"); QTest::addColumn("isIndexed"); QTest::addColumn("canRemove"); QTest::addColumn("hasBidirectionalIterator"); QTest::addColumn("hasRandomAccessIterator"); QTest::addColumn("canInsertAtIterator"); QTest::addColumn("canEraseAtIterator"); QTest::addColumn("isOrdered"); QTest::addRow("QVector") << static_cast(&qvector) << QMetaSequence::fromContainer>() << QMetaType::fromType() << true << true << true << true << true << true << true << true; QTest::addRow("std::vector") << static_cast(&stdvector) << QMetaSequence::fromContainer>() << QMetaType::fromType() << true << true << true << true << true << true << true << true; QTest::addRow("QSet") << static_cast(&qset) << QMetaSequence::fromContainer>() << QMetaType::fromType() << true << false << false << false << false << false << true << false; QTest::addRow("std::set") << static_cast(&stdset) << QMetaSequence::fromContainer>() << QMetaType::fromType() << true << false << false << true << false << true << true << false; QTest::addRow("std::forward_list") << static_cast(&forwardList) << QMetaSequence::fromContainer>() << QMetaType::fromType() << false << false << true << false << false << false << false << true; } void tst_QMetaContainer::testSequence() { QFETCH(void *, container); QFETCH(QMetaSequence, metaSequence); QFETCH(QMetaType, metaType); QFETCH(bool, hasSize); QFETCH(bool, isIndexed); QFETCH(bool, canRemove); QFETCH(bool, hasBidirectionalIterator); QFETCH(bool, hasRandomAccessIterator); QFETCH(bool, canInsertAtIterator); QFETCH(bool, canEraseAtIterator); QFETCH(bool, isOrdered); QVERIFY(metaSequence.canAddElement()); QCOMPARE(metaSequence.hasSize(), hasSize); QCOMPARE(metaSequence.canGetElementAtIndex(), isIndexed); QCOMPARE(metaSequence.canSetElementAtIndex(), isIndexed); QCOMPARE(metaSequence.canRemoveElement(), canRemove); QCOMPARE(metaSequence.hasBidirectionalIterator(), hasBidirectionalIterator); QCOMPARE(metaSequence.hasRandomAccessIterator(), hasRandomAccessIterator); QCOMPARE(metaSequence.canInsertElementAtIterator(), canInsertAtIterator); QCOMPARE(metaSequence.canEraseElementAtIterator(), canEraseAtIterator); QCOMPARE(metaSequence.isOrdered(), isOrdered); QVariant var1(metaType); QVariant var2(metaType); QVariant var3(metaType); if (hasSize) { const qsizetype size = metaSequence.size(container); // var1 is invalid, and our sets do not contain an invalid value so far. metaSequence.addElement(container, var1.constData()); QCOMPARE(metaSequence.size(container), size + 1); if (canRemove) { metaSequence.removeElement(container); QCOMPARE(metaSequence.size(container), size); } } else { metaSequence.addElement(container, var1.constData()); if (canRemove) metaSequence.removeElement(container); } if (isIndexed) { QVERIFY(hasSize); const qsizetype size = metaSequence.size(container); for (qsizetype i = 0; i < size; ++i) { metaSequence.elementAtIndex(container, i, var1.data()); metaSequence.elementAtIndex(container, size - i - 1, var2.data()); metaSequence.setElementAtIndex(container, i, var2.constData()); metaSequence.setElementAtIndex(container, size - i - 1, var1.constData()); metaSequence.elementAtIndex(container, i, var3.data()); QCOMPARE(var3, var2); metaSequence.elementAtIndex(container, size - i - 1, var3.data()); QCOMPARE(var3, var1); } } QVERIFY(metaSequence.hasIterator()); QVERIFY(metaSequence.hasConstIterator()); QVERIFY(metaSequence.canGetElementAtIterator()); QVERIFY(metaSequence.canGetElementAtConstIterator()); void *it = metaSequence.begin(container); void *end = metaSequence.end(container); QVERIFY(it); QVERIFY(end); void *constIt = metaSequence.constBegin(container); void *constEnd = metaSequence.constEnd(container); QVERIFY(constIt); QVERIFY(constEnd); const qsizetype size = metaSequence.diffIterator(end, it); QCOMPARE(size, metaSequence.diffConstIterator(constEnd, constIt)); if (hasSize) QCOMPARE(size, metaSequence.size(container)); qsizetype count = 0; for (; !metaSequence.compareIterator(it, end); metaSequence.advanceIterator(it, 1), metaSequence.advanceConstIterator(constIt, 1)) { metaSequence.elementAtIterator(it, var1.data()); if (isIndexed) { metaSequence.elementAtIndex(container, count, var2.data()); QCOMPARE(var1, var2); } metaSequence.elementAtConstIterator(constIt, var3.data()); QCOMPARE(var3, var1); ++count; } QCOMPARE(count, size); QVERIFY(metaSequence.compareConstIterator(constIt, constEnd)); metaSequence.destroyIterator(it); metaSequence.destroyIterator(end); metaSequence.destroyConstIterator(constIt); metaSequence.destroyConstIterator(constEnd); if (metaSequence.canSetElementAtIterator()) { void *it = metaSequence.begin(container); void *end = metaSequence.end(container); QVERIFY(it); QVERIFY(end); for (; !metaSequence.compareIterator(it, end); metaSequence.advanceIterator(it, 1)) { metaSequence.elementAtIterator(it, var1.data()); metaSequence.setElementAtIterator(it, var2.constData()); metaSequence.elementAtIterator(it, var3.data()); QCOMPARE(var2, var3); var2 = var1; } metaSequence.destroyIterator(it); metaSequence.destroyIterator(end); } if (metaSequence.hasBidirectionalIterator()) { void *it = metaSequence.end(container); void *end = metaSequence.begin(container); QVERIFY(it); QVERIFY(end); void *constIt = metaSequence.constEnd(container); void *constEnd = metaSequence.constBegin(container); QVERIFY(constIt); QVERIFY(constEnd); qsizetype size = 0; if (metaSequence.hasRandomAccessIterator()) { size = metaSequence.diffIterator(end, it); QCOMPARE(size, metaSequence.diffConstIterator(constEnd, constIt)); } else { size = -metaSequence.diffIterator(it, end); } if (hasSize) QCOMPARE(size, -metaSequence.size(container)); qsizetype count = 0; do { metaSequence.advanceIterator(it, -1); metaSequence.advanceConstIterator(constIt, -1); --count; metaSequence.elementAtIterator(it, var1.data()); if (isIndexed) { metaSequence.elementAtIndex(container, count - size, var2.data()); QCOMPARE(var1, var2); } metaSequence.elementAtConstIterator(constIt, var3.data()); QCOMPARE(var3, var1); } while (!metaSequence.compareIterator(it, end)); QCOMPARE(count, size); QVERIFY(metaSequence.compareConstIterator(constIt, constEnd)); metaSequence.destroyIterator(it); metaSequence.destroyIterator(end); metaSequence.destroyConstIterator(constIt); metaSequence.destroyConstIterator(constEnd); } if (canInsertAtIterator) { void *it = metaSequence.begin(container); void *end = metaSequence.end(container); const qsizetype size = metaSequence.diffIterator(end, it); metaSequence.destroyIterator(end); metaSequence.insertElementAtIterator(container, it, var1.constData()); metaSequence.destroyIterator(it); it = metaSequence.begin(container); metaSequence.insertElementAtIterator(container, it, var2.constData()); metaSequence.destroyIterator(it); it = metaSequence.begin(container); metaSequence.insertElementAtIterator(container, it, var3.constData()); metaSequence.destroyIterator(it); it = metaSequence.begin(container); end = metaSequence.end(container); const qsizetype newSize = metaSequence.diffIterator(end, it); if (metaSequence.isOrdered()) { QCOMPARE(newSize, size + 3); QVariant var4(metaType); metaSequence.elementAtIterator(it, var4.data()); QCOMPARE(var4, var3); metaSequence.advanceIterator(it, 1); metaSequence.elementAtIterator(it, var4.data()); QCOMPARE(var4, var2); metaSequence.advanceIterator(it, 1); metaSequence.elementAtIterator(it, var4.data()); QCOMPARE(var4, var1); } else { QVERIFY(newSize >= size); } if (canEraseAtIterator) { for (int i = 0; i < newSize; ++i) { metaSequence.destroyIterator(it); it = metaSequence.begin(container); metaSequence.eraseElementAtIterator(container, it); } metaSequence.destroyIterator(it); it = metaSequence.begin(container); metaSequence.destroyIterator(end); end = metaSequence.end(container); QVERIFY(metaSequence.compareIterator(it, end)); metaSequence.addElement(container, var1.constData()); metaSequence.addElement(container, var2.constData()); metaSequence.addElement(container, var3.constData()); } metaSequence.destroyIterator(end); metaSequence.destroyIterator(it); } QVERIFY(metaSequence.canClear()); constIt = metaSequence.constBegin(container); constEnd = metaSequence.constEnd(container); QVERIFY(!metaSequence.compareConstIterator(constIt, constEnd)); metaSequence.destroyConstIterator(constIt); metaSequence.destroyConstIterator(constEnd); metaSequence.clear(container); constIt = metaSequence.constBegin(container); constEnd = metaSequence.constEnd(container); QVERIFY(metaSequence.compareConstIterator(constIt, constEnd)); metaSequence.destroyConstIterator(constIt); metaSequence.destroyConstIterator(constEnd); } QTEST_MAIN(tst_QMetaContainer) #include "tst_qmetacontainer.moc"