diff options
Diffstat (limited to 'tests/auto/corelib/text/qbytearrayview')
3 files changed, 609 insertions, 0 deletions
diff --git a/tests/auto/corelib/text/qbytearrayview/CMakeLists.txt b/tests/auto/corelib/text/qbytearrayview/CMakeLists.txt new file mode 100644 index 0000000000..34476b8246 --- /dev/null +++ b/tests/auto/corelib/text/qbytearrayview/CMakeLists.txt @@ -0,0 +1,10 @@ +# Generated from qbytearrayview.pro. + +##################################################################### +## tst_qbytearrayview Test: +##################################################################### + +qt_add_test(tst_qbytearrayview + SOURCES + tst_qbytearrayview.cpp +) diff --git a/tests/auto/corelib/text/qbytearrayview/qbytearrayview.pro b/tests/auto/corelib/text/qbytearrayview/qbytearrayview.pro new file mode 100644 index 0000000000..23d0aed959 --- /dev/null +++ b/tests/auto/corelib/text/qbytearrayview/qbytearrayview.pro @@ -0,0 +1,4 @@ +CONFIG += testcase +TARGET = tst_qbytearrayview +QT = core testlib +SOURCES += tst_qbytearrayview.cpp diff --git a/tests/auto/corelib/text/qbytearrayview/tst_qbytearrayview.cpp b/tests/auto/corelib/text/qbytearrayview/tst_qbytearrayview.cpp new file mode 100644 index 0000000000..c1d80b47dc --- /dev/null +++ b/tests/auto/corelib/text/qbytearrayview/tst_qbytearrayview.cpp @@ -0,0 +1,595 @@ +/**************************************************************************** +** +** 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 <QByteArrayView> + +#include <QTest> + +// for negative testing (can't convert from) +#include <deque> +#include <list> + +template <typename T> +constexpr bool CanConvert = std::is_convertible_v<T, QByteArrayView>; + +static_assert(!CanConvert<QString>); +static_assert(!CanConvert<QStringView>); +static_assert(!CanConvert<const char16_t*>); + +static_assert(!CanConvert<char>); +static_assert(CanConvert<char[1]>); +static_assert(CanConvert<const char[1]>); +static_assert(CanConvert<char*>); +static_assert(CanConvert<const char*>); + +static_assert(!CanConvert<uchar>); +static_assert(CanConvert<uchar[1]>); +static_assert(CanConvert<const uchar[1]>); +static_assert(CanConvert<uchar*>); +static_assert(CanConvert<const uchar*>); + +static_assert(!CanConvert<signed char>); +static_assert(CanConvert<signed char[1]>); +static_assert(CanConvert<const signed char[1]>); +static_assert(CanConvert<signed char*>); +static_assert(CanConvert<const signed char*>); + +static_assert(!CanConvert<std::byte>); +static_assert(CanConvert<std::byte[1]>); +static_assert(CanConvert<const std::byte[1]>); +static_assert(CanConvert<std::byte*>); +static_assert(CanConvert<const std::byte*>); + +static_assert(CanConvert< QByteArray >); +static_assert(CanConvert<const QByteArray >); +static_assert(CanConvert< QByteArray&>); +static_assert(CanConvert<const QByteArray&>); + +static_assert(CanConvert< std::string >); +static_assert(CanConvert<const std::string >); +static_assert(CanConvert< std::string&>); +static_assert(CanConvert<const std::string&>); + +static_assert(CanConvert< std::string_view >); +static_assert(CanConvert<const std::string_view >); +static_assert(CanConvert< std::string_view&>); +static_assert(CanConvert<const std::string_view&>); + +static_assert(CanConvert< QVector<char> >); +static_assert(CanConvert<const QVector<char> >); +static_assert(CanConvert< QVector<char>&>); +static_assert(CanConvert<const QVector<char>&>); + +static_assert(CanConvert< QVarLengthArray<char> >); +static_assert(CanConvert<const QVarLengthArray<char> >); +static_assert(CanConvert< QVarLengthArray<char>&>); +static_assert(CanConvert<const QVarLengthArray<char>&>); + +static_assert(CanConvert< std::vector<char> >); +static_assert(CanConvert<const std::vector<char> >); +static_assert(CanConvert< std::vector<char>&>); +static_assert(CanConvert<const std::vector<char>&>); + +static_assert(CanConvert< std::array<char, 1> >); +static_assert(CanConvert<const std::array<char, 1> >); +static_assert(CanConvert< std::array<char, 1>&>); +static_assert(CanConvert<const std::array<char, 1>&>); + +static_assert(!CanConvert<std::deque<char>>); +static_assert(!CanConvert<std::list<char>>); + +class tst_QByteArrayView : public QObject +{ + Q_OBJECT +private slots: + void constExpr() const; + void basics() const; + void literals() const; + void literalsWithInternalNulls() const; + void at() const; + + void fromQByteArray() const; + + void fromCharStar() const + { + fromEmptyLiteral<char>(); + conversionTests("Hello, World!"); + } + + void fromUCharStar() const + { + fromEmptyLiteral<uchar>(); + + const uchar data[] = { 'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!', 0 }; + conversionTests(data); + } + + void fromSignedCharStar() const + { + fromEmptyLiteral<signed char>(); + + const signed char data[] = { 'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!', 0 }; + conversionTests(data); + } + + void fromStdByteArray() const + { + fromEmptyLiteral<std::byte>(); + + const std::byte data[] = {std::byte{'H'}, std::byte{'e'}, std::byte{'l'}, std::byte{'l'}, + std::byte{'o'}, std::byte{0}}; + conversionTests(data); + } + + void fromCharRange() const + { + const char data[] = { 'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!' }; + fromRange(std::begin(data), std::end(data)); + } + + void fromUCharRange() const + { + const uchar data[] = { 'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!', 0 }; + fromRange(std::begin(data), std::end(data)); + } + + void fromSignedCharRange() const + { + const signed char data[] = { 'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!', 0 }; + fromRange(std::begin(data), std::end(data)); + } + + void fromStdByteRange() const + { + const std::byte data[] = {std::byte{'H'}, std::byte{'e'}, std::byte{'l'}, std::byte{'l'}, + std::byte{'o'}, std::byte{0}}; + fromRange(std::begin(data), std::end(data)); + } + + void fromCharContainers() const + { + fromContainers<char>(); + } + + void fromUCharContainers() const + { + fromContainers<uchar>(); + } + + void fromSignedCharContainers() const + { + fromContainers<signed char>(); + } + + void fromStdByteContainers() const + { + fromContainers<std::byte>(); + } + + void comparison() const; + +private: + template <typename Data> + void conversionTests(Data arg) const; + template <typename Char> + void fromEmptyLiteral() const; + template <typename Char> + void fromRange(const Char *first, const Char *last) const; + template <typename Char, typename Container> + void fromContainer() const; + template <typename Char> + void fromContainers() const; +}; + +void tst_QByteArrayView::constExpr() const +{ + // compile-time checks + { + constexpr QByteArrayView bv; + static_assert(bv.size() == 0); + static_assert(bv.isNull()); + static_assert(bv.empty()); + static_assert(bv.isEmpty()); + static_assert(bv.data() == nullptr); + + constexpr QByteArrayView bv2(bv.data(), bv.data() + bv.size()); + static_assert(bv2.isNull()); + static_assert(bv2.empty()); + } + { + constexpr QByteArrayView bv = ""; + static_assert(bv.size() == 0); + static_assert(!bv.isNull()); + static_assert(bv.empty()); + static_assert(bv.isEmpty()); + static_assert(bv.data() != nullptr); + + constexpr QByteArrayView bv2(bv.data(), bv.data() + bv.size()); + static_assert(!bv2.isNull()); + static_assert(bv2.empty()); + } + { + static_assert(QByteArrayView("Hello").size() == 5); + constexpr QByteArrayView bv = "Hello"; + static_assert(bv.size() == 5); + static_assert(!bv.empty()); + static_assert(!bv.isEmpty()); + static_assert(!bv.isNull()); + static_assert(*bv.data() == 'H'); + static_assert(bv[0] == 'H'); + static_assert(bv.at(0) == 'H'); + static_assert(bv.front() == 'H'); + static_assert(bv.first() == 'H'); + static_assert(bv[4] == 'o'); + static_assert(bv.at(4) == 'o'); + static_assert(bv.back() == 'o'); + static_assert(bv.last() == 'o'); + + static_assert(*bv.begin() == 'H' ); + static_assert(*(bv.end() - 1) == 'o' ); + static_assert(*bv.cbegin() == 'H' ); + static_assert(*(bv.cend() - 1) == 'o' ); + static_assert(*bv.rbegin() == 'o' ); + static_assert(*bv.crbegin() == 'o' ); + + // This is just to test that rend()/crend() are constexpr. + static_assert(bv.rbegin() != bv.rend()); + static_assert(bv.crbegin() != bv.crend()); + + constexpr QByteArrayView bv2(bv.data(), bv.data() + bv.size()); + static_assert(!bv2.isNull()); + static_assert(!bv2.empty()); + static_assert(bv2.size() == 5); + } + { + static constexpr char hello[] = "Hello"; + constexpr QByteArrayView bv(hello); + static_assert(bv.size() == 5); + static_assert(!bv.empty()); + static_assert(!bv.isEmpty()); + static_assert(!bv.isNull()); + static_assert(*bv.data() == 'H'); + static_assert(bv[0] == 'H'); + static_assert(bv.at(0) == 'H'); + static_assert(bv.front() == 'H'); + static_assert(bv.first() == 'H'); + static_assert(bv[4] == 'o'); + static_assert(bv.at(4) == 'o'); + static_assert(bv.back() == 'o'); + static_assert(bv.last() == 'o'); + } + { + static constexpr char hello[] = { 'H', 'e', 'l', 'l', 'o' }; + constexpr QByteArrayView bv(hello, std::size(hello)); + static_assert(bv.size() == 5); + static_assert(!bv.empty()); + static_assert(!bv.isEmpty()); + static_assert(!bv.isNull()); + static_assert(*bv.data() == 'H'); + static_assert(bv[0] == 'H'); + static_assert(bv.at(0) == 'H'); + static_assert(bv.front() == 'H'); + static_assert(bv.first() == 'H'); + static_assert(bv[4] == 'o'); + static_assert(bv.at(4) == 'o'); + static_assert(bv.back() == 'o'); + static_assert(bv.last() == 'o'); + } + { + constexpr char *null = nullptr; + constexpr QByteArrayView bv(null); + static_assert(bv.isNull()); + static_assert(bv.isEmpty()); + static_assert(bv.size() == 0); + } +} + +void tst_QByteArrayView::basics() const +{ + QByteArrayView bv1; + + // a default-constructed QByteArrayView is null: + QVERIFY(bv1.isNull()); + // which implies it's empty(); + QVERIFY(bv1.isEmpty()); + + QByteArrayView bv2; + + QVERIFY(bv2 == bv1); + QVERIFY(!(bv2 != bv1)); +} + +void tst_QByteArrayView::literals() const +{ + const char hello[] = "Hello"; + + QCOMPARE(QByteArrayView(hello).size(), 5); + QCOMPARE(QByteArrayView(hello + 0).size(), 5); // forces decay to pointer + QByteArrayView bv = hello; + QCOMPARE(bv.size(), 5); + QVERIFY(!bv.empty()); + QVERIFY(!bv.isEmpty()); + QVERIFY(!bv.isNull()); + QCOMPARE(*bv.data(), 'H'); + QCOMPARE(bv[0], 'H'); + QCOMPARE(bv.at(0), 'H'); + QCOMPARE(bv.front(), 'H'); + QCOMPARE(bv.first(), 'H'); + QCOMPARE(bv[4], 'o'); + QCOMPARE(bv.at(4), 'o'); + QCOMPARE(bv.back(), 'o'); + QCOMPARE(bv.last(), 'o'); + + QByteArrayView bv2(bv.data(), bv.data() + bv.size()); + QVERIFY(!bv2.isNull()); + QVERIFY(!bv2.empty()); + QCOMPARE(bv2.size(), 5); +} + +void tst_QByteArrayView::literalsWithInternalNulls() const +{ + const char withnull[] = "a\0zzz"; + + // these are different results + QCOMPARE(size_t(QByteArrayView(withnull).size()), sizeof(withnull)/sizeof(withnull[0]) - 1); + QCOMPARE(QByteArrayView(withnull + 0).size(), 1); + + QByteArrayView nulled(withnull); + QCOMPARE(nulled[1], '\0'); + QCOMPARE(nulled.indexOf('\0'), 1); + QCOMPARE(nulled.indexOf('z'), 2); + QCOMPARE(nulled.lastIndexOf('z'), 4); + QCOMPARE(nulled.lastIndexOf('a'), 0); + QVERIFY(nulled.startsWith("a\0z")); + QVERIFY(!nulled.startsWith("a\0y")); + QVERIFY(nulled.endsWith("zz")); + QVERIFY(nulled.contains("z")); + QVERIFY(nulled.contains("\0z")); + QVERIFY(!nulled.contains("\0y")); + QCOMPARE(nulled.first(5), withnull); + QCOMPARE(nulled.last(5), withnull); + QCOMPARE(nulled.sliced(0), withnull); + QCOMPARE(nulled.sliced(2, 2), "zz"); + QCOMPARE(nulled.chopped(2), "a\0z"); + QVERIFY(nulled.chopped(2) != "a\0y"); + QCOMPARE(nulled.count('z'), 3); + + const char nullfirst[] = "\0buzz"; + QByteArrayView fromnull(nullfirst); + QVERIFY(!fromnull.isEmpty()); + + const char nullNotEnd[] = { 'b', 'o', 'w', '\0', 'a', 'f', 't', 'z' }; + QByteArrayView midNull(nullNotEnd); + QCOMPARE(midNull.back(), 't'); +} + +void tst_QByteArrayView::at() const +{ + QByteArray hello("Hello"); + QByteArrayView bv(hello); + QCOMPARE(bv.at(0), 'H'); QCOMPARE(bv[0], 'H'); + QCOMPARE(bv.at(1), 'e'); QCOMPARE(bv[1], 'e'); + QCOMPARE(bv.at(2), 'l'); QCOMPARE(bv[2], 'l'); + QCOMPARE(bv.at(3), 'l'); QCOMPARE(bv[3], 'l'); + QCOMPARE(bv.at(4), 'o'); QCOMPARE(bv[4], 'o'); +} + +void tst_QByteArrayView::fromQByteArray() const +{ + QByteArray null; + QByteArray empty = ""; + + QVERIFY(QByteArrayView(null).isNull()); + QVERIFY(!qToByteArrayViewIgnoringNull(null).isNull()); + + QVERIFY(QByteArrayView(null).isEmpty()); + QVERIFY(qToByteArrayViewIgnoringNull(null).isEmpty()); + + QVERIFY(QByteArrayView(empty).isEmpty()); + QVERIFY(qToByteArrayViewIgnoringNull(empty).isEmpty()); + + QVERIFY(!QByteArrayView(empty).isNull()); + QVERIFY(!qToByteArrayViewIgnoringNull(empty).isNull()); + + conversionTests(QByteArray("Hello World!")); +} + +namespace help { +template <typename T> +size_t size(const T &t) { return size_t(t.size()); } +template <typename T> +size_t size(const T *t) { return std::char_traits<T>::length(t); } + +template <typename T> +decltype(auto) cbegin(const T &t) { return t.begin(); } +template <typename T> +const T * cbegin(const T *t) { return t; } + +template <typename T> +decltype(auto) cend(const T &t) { return t.end(); } +template <typename T> +const T * cend(const T *t) { return t + size(t); } + +template <typename T> +decltype(auto) crbegin(const T &t) { return t.rbegin(); } +template <typename T> +std::reverse_iterator<const T*> crbegin(const T *t) { return std::reverse_iterator<const T*>(cend(t)); } + +template <typename T> +decltype(auto) crend(const T &t) { return t.rend(); } +template <typename T> +std::reverse_iterator<const T*> crend(const T *t) { return std::reverse_iterator<const T*>(cbegin(t)); } + +} // namespace help + +template <typename Data> +void tst_QByteArrayView::conversionTests(Data data) const +{ + // copy-construct: + { + QByteArrayView bv = data; + + QCOMPARE(help::size(bv), help::size(data)); + + const auto compare = [](auto v1, auto v2) { + if constexpr (std::is_same_v<decltype(v1), std::byte>) + return std::to_integer<char>(v1) == v2; + else + return v1 == v2; + }; + QVERIFY(std::equal(help::cbegin(data), help::cend(data), + QT_MAKE_CHECKED_ARRAY_ITERATOR(bv.cbegin(), bv.size()), compare)); + QVERIFY(std::equal(help::cbegin(data), help::cend(data), + QT_MAKE_CHECKED_ARRAY_ITERATOR(bv.begin(), bv.size()), compare)); + QVERIFY(std::equal(help::crbegin(data), help::crend(data), bv.crbegin(), compare)); + QVERIFY(std::equal(help::crbegin(data), help::crend(data), bv.rbegin(), compare)); + QCOMPARE(bv, data); + } + + QByteArrayView bv; + + // copy-assign: + { + bv = data; + + QCOMPARE(help::size(bv), help::size(data)); + + // check relational operators: + + QCOMPARE(bv, data); + QCOMPARE(data, bv); + + QVERIFY(!(bv != data)); + QVERIFY(!(data != bv)); + + QVERIFY(!(bv < data)); + QVERIFY(bv <= data); + QVERIFY(!(bv > data)); + QVERIFY(bv >= data); + + QVERIFY(!(data < bv)); + QVERIFY(data <= bv); + QVERIFY(!(data > bv)); + QVERIFY(data >= bv); + } + + // copy-construct from rvalue (QByteArrayView never assumes ownership): + { + QByteArrayView bv2 = std::move(data); + QCOMPARE(bv2, bv); + QCOMPARE(bv2, data); + } + + // copy-assign from rvalue (QByteArrayView never assumes ownership): + { + QByteArrayView bv2; + bv2 = std::move(data); + QCOMPARE(bv2, bv); + QCOMPARE(bv2, data); + } +} + +template <typename Char> +void tst_QByteArrayView::fromEmptyLiteral() const +{ + const Char *null = nullptr; + const Char empty[] = { Char{0} }; + + QCOMPARE(QByteArrayView(null).size(), 0); + QCOMPARE(QByteArrayView(null).data(), nullptr); + QCOMPARE(QByteArrayView(empty).size(), 0); + QCOMPARE(static_cast<const void*>(QByteArrayView(empty).data()), + static_cast<const void*>(empty)); + + QVERIFY(QByteArrayView(null).isNull()); + QVERIFY(QByteArrayView(null).isEmpty()); + QVERIFY(QByteArrayView(empty).isEmpty()); + QVERIFY(!QByteArrayView(empty).isNull()); +} + +template <typename Char> +void tst_QByteArrayView::fromRange(const Char *first, const Char *last) const +{ + const Char *null = nullptr; + QCOMPARE(QByteArrayView(null, null).size(), 0); + QCOMPARE(QByteArrayView(null, null).data(), nullptr); + QCOMPARE(QByteArrayView(first, first).size(), 0); + QCOMPARE(static_cast<const void*>(QByteArrayView(first, first).data()), + static_cast<const void*>(first)); + + const auto bv = QByteArrayView(first, last); + QCOMPARE(bv.size(), last - first); + QCOMPARE(static_cast<const void*>(bv.data()), + static_cast<const void*>(first)); + + QCOMPARE(static_cast<const void*>(bv.last(0).data()), + static_cast<const void*>(last)); + QCOMPARE(static_cast<const void*>(bv.sliced(bv.size()).data()), + static_cast<const void*>(last)); + + // can't call conversionTests() here, as it requires a single object +} + +template <typename Char, typename Container> +void tst_QByteArrayView::fromContainer() const +{ + const QByteArray s = "Hello World!"; + + Container c; + // unspecified whether empty containers make null QByteArrayView + QVERIFY(QByteArrayView(c).isEmpty()); + + QCOMPARE(sizeof(Char), sizeof(char)); + + const auto *data = reinterpret_cast<const Char *>(s.data()); + std::copy(data, data + s.size(), std::back_inserter(c)); + conversionTests(std::move(c)); +} + +template <typename Char> +void tst_QByteArrayView::fromContainers() const +{ + fromContainer<Char, QVector<Char>>(); + fromContainer<Char, QVarLengthArray<Char>>(); + fromContainer<Char, std::vector<Char>>(); + fromContainer<Char, std::basic_string<Char>>(); +} + +void tst_QByteArrayView::comparison() const +{ + const QByteArrayView aa = "aa"; + const QByteArrayView bb = "bb"; + + QVERIFY(aa == aa); + QVERIFY(aa != bb); + QVERIFY(aa < bb); + QVERIFY(bb > aa); +} + +QTEST_APPLESS_MAIN(tst_QByteArrayView) +#include "tst_qbytearrayview.moc" |