diff options
-rw-r--r-- | src/corelib/doc/snippets/qversionnumber/main.cpp | 109 | ||||
-rw-r--r-- | src/corelib/tools/qversionnumber.cpp | 484 | ||||
-rw-r--r-- | src/corelib/tools/qversionnumber.h | 201 | ||||
-rw-r--r-- | src/corelib/tools/tools.pri | 6 | ||||
-rw-r--r-- | src/testlib/qtest.h | 6 | ||||
-rw-r--r-- | src/testlib/qtestcase.cpp | 7 | ||||
-rw-r--r-- | tests/auto/corelib/tools/qversionnumber/qversionnumber.pro | 4 | ||||
-rw-r--r-- | tests/auto/corelib/tools/qversionnumber/tst_qversionnumber.cpp | 577 | ||||
-rw-r--r-- | tests/auto/corelib/tools/tools.pro | 4 |
9 files changed, 1395 insertions, 3 deletions
diff --git a/src/corelib/doc/snippets/qversionnumber/main.cpp b/src/corelib/doc/snippets/qversionnumber/main.cpp new file mode 100644 index 0000000000..ba72a52816 --- /dev/null +++ b/src/corelib/doc/snippets/qversionnumber/main.cpp @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Keith Gardner <kreios4004@gmail.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QVersionNumber> + +class Object +{ +public: + static void genericExample(); + static void equalityExample(); + static void isPrefixOf(); + static void parse(); + static void equivalent(); +}; + +void Object::genericExample() +{ + //! [0] + QVersionNumber version(1, 2, 3); // 1.2.3 + //! [0] +} + +void Object::equalityExample() +{ + //! [1] + QVersionNumber v1(1, 2); + QVersionNumber v2(1, 2, 0); + int compare = QVersionNumber::compare(v1, v2); // compare == -1 + //! [1] +} + +void Object::isPrefixOf() +{ + //! [2] + QVersionNumber v1(5, 3); + QVersionNumber v2(5, 3, 1); + bool value = v1.isPrefixOf(v2); // true + //! [2] +} + +void QObject::parse() +{ + //! [3] + QString string("5.4.0-alpha"); + int suffixIndex; + QVersionNumber version = QVersionNumber::fromString(string, &suffixIndex); + // version is 5.4.0 + // suffixIndex is 5 + //! [3] +} + +void Object::equivalent() +{ + //! [4] + QVersionNumber v1(5, 4); + QVersionNumber v2(5, 4, 0); + bool equivalent = v1.normalized() == v2.normalized(); + bool equal = v1 == v2; + // equivalent is true + // equal is false + //! [4] +} + +int main() +{ + Object::genericExample(); + Object::equalityExample(); + Object::isPrefixOf(); + Object::parse(); + Object::equivalent(); +} diff --git a/src/corelib/tools/qversionnumber.cpp b/src/corelib/tools/qversionnumber.cpp new file mode 100644 index 0000000000..933f7fa6b3 --- /dev/null +++ b/src/corelib/tools/qversionnumber.cpp @@ -0,0 +1,484 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Keith Gardner <kreios4004@gmail.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/qversionnumber.h> +#include <QtCore/qhash.h> +#include <QtCore/private/qlocale_tools_p.h> +#include <QtCore/qcollator.h> + +#ifndef QT_NO_DATASTREAM +# include <QtCore/qdatastream.h> +#endif + +#ifndef QT_NO_DEBUG_STREAM +# include <QtCore/qdebug.h> +#endif + +#include <algorithm> + +QT_BEGIN_NAMESPACE + +/*! + \class QVersionNumber + \inmodule QtCore + \since 5.4 + \brief The QVersionNumber class contains a version number with an arbitrary + number of segments. + + \snippet qversionnumber/main.cpp 0 +*/ + +/*! + \fn QVersionNumber::QVersionNumber() + + Produces a null version. + + \sa isNull() +*/ + +/*! + \fn QVersionNumber::QVersionNumber(int maj) + + Constructs a QVersionNumber consisting of just the major version number \a maj. +*/ + +/*! + \fn QVersionNumber::QVersionNumber(int maj, int min) + + Constructs a QVersionNumber consisting of the major and minor + version numbers \a maj and \a min, respectively. +*/ + +/*! + \fn QVersionNumber::QVersionNumber(int maj, int min, int mic) + + Constructs a QVersionNumber consisting of the major, minor, and + micro version numbers \a maj, \a min and \a mic, respectively. +*/ + +/*! + \fn QVersionNumber::QVersionNumber(const QVector<int> &seg) + + Constructs a version number from the list of numbers contained in \a seg. +*/ + +/*! + \fn QVersionNumber::QVersionNumber(QVector<int> &&seg) + + Move-constructs a version number from the list of numbers contained in \a seg. + + This constructor is only enabled if the compiler supports C++11 move semantics. +*/ + +/*! + \fn QVersionNumber::QVersionNumber(std::initializer_list<int> args) + + Construct a version number from the std::initializer_list specified by + \a args. + + This constructor is only enabled if the compiler supports C++11 initializer + lists. +*/ + +/*! + \fn bool QVersionNumber::isNull() const + + Returns \c true if there are zero numerical segments, otherwise returns + \c false. + + \sa segments() +*/ + +/*! + \fn bool QVersionNumber::isNormalized() const + + Returns \c true if the version number does not contain any trailing zeros, + otherwise returns \c false. + + \sa normalized() +*/ + +/*! + \fn int QVersionNumber::majorVersion() const + + Returns the major version number, that is, the first segment. + This function is equivalent to segmentAt(0). If this QVersionNumber object + is null, this function returns 0. + + \sa isNull(), segmentAt() +*/ + +/*! + \fn int QVersionNumber::minorVersion() const + + Returns the minor version number, that is, the second segment. + This function is equivalent to segmentAt(1). If this QVersionNumber object + does not contain a minor number, this function returns 0. + + \sa isNull(), segmentAt() +*/ + +/*! + \fn int QVersionNumber::microVersion() const + + Returns the micro version number, that is, the third segment. + This function is equivalent to segmentAt(2). If this QVersionNumber object + does not contain a micro number, this function returns 0. + + \sa isNull(), segmentAt() +*/ + +/*! + \fn const QVector<int>& QVersionNumber::segments() const + + Returns all of the numerical segments. + + \sa majorVersion(), minorVersion(), microVersion() +*/ + +/*! + \fn int QVersionNumber::segmentAt(int index) const + + Returns the segement value at \a index. If the index does not exist, + returns 0. + + \sa segments(), segmentCount() +*/ + +/*! + \fn int QVersionNumber::segmentCount() const + + Returns the number of integers stored in segments(). + + \sa segments() +*/ + +/*! + \fn QVersionNumber QVersionNumber::normalized() const + + Returns an equivalent version number but with all trailing zeros removed. + + To check if two numbers are equivalent, use normalized() on both version + numbers before perforing the compare. + + \snippet qversionnumber/main.cpp 4 + */ + +/*! + \fn bool QVersionNumber::isPrefixOf(const QVersionNumber &other) const + + Returns \c true if the current version number is contained in the \a other + version number, otherwise returns \c false. + + \snippet qversionnumber/main.cpp 2 + + \sa commonPrefix() +*/ +bool QVersionNumber::isPrefixOf(const QVersionNumber &other) const Q_DECL_NOTHROW +{ + return m_segments.size() <= other.m_segments.size() && + std::equal(m_segments.begin(), m_segments.end(), other.m_segments.begin()); +} + +/*! + \fn int QVersionNumber::compare(const QVersionNumber &v1, + const QVersionNumber &v2) + + Compares \a v1 with \a v2 and returns an integer less than, equal to, or + greater than zero, depending on whether \a v1 is less than, equal to, or + greater than \a v2, respectively. + + Comparisons are performed by comparing the segments of \a v1 and \a v2 + starting at index 0 and working towards the end of the longer list. + + \snippet qversionnumber/main.cpp 1 +*/ +int QVersionNumber::compare(const QVersionNumber &v1, const QVersionNumber &v2) Q_DECL_NOTHROW +{ + QVector<int>::const_iterator i1 = v1.m_segments.constBegin(); + const QVector<int>::const_iterator e1 = v1.m_segments.constEnd(); + QVector<int>::const_iterator i2 = v2.m_segments.constBegin(); + const QVector<int>::const_iterator e2 = v2.m_segments.constEnd(); + + while (i1 != e1 && i2 != e2) { + if (*i1 != *i2) + return (*i1 - *i2); + ++i1; + ++i2; + } + + // ran out of segments in v1 and/or v2 and need to check the first trailing + // segment to finish the compare + if (i1 != e1) { + // v1 is longer + if (*i1 != 0) + return *i1; + else + return 1; + } else if (i2 != e2) { + // v2 is longer + if (*i2 != 0) + return -*i2; + else + return -1; + } + + // the two version numbers are the same + return 0; +} + +/*! + QVersionNumber QVersionNumber::commonPrefix(const QVersionNumber &v1, + const QVersionNumber &v2) + + Returns a version number that is a parent version of both \a v1 and \a v2. + + \sa isPrefixOf() +*/ +QVersionNumber QVersionNumber::commonPrefix(const QVersionNumber &v1, + const QVersionNumber &v2) +{ + int min = qMin(v1.m_segments.size(), v2.m_segments.size()); + QVector<int>::const_iterator i1 = v1.m_segments.begin(); + QVector<int>::const_iterator e1; + e1 = std::mismatch(i1, + v1.m_segments.begin() + min, + v2.m_segments.begin()).first; + return QVersionNumber(v1.m_segments.mid(0, e1 - i1)); +} + +/*! + \fn bool operator<(const QVersionNumber &lhs, const QVersionNumber &rhs) + \relates QVersionNumber + + Returns \c true if \a lhs is less than \a rhs; otherwise returns \c false. + + \sa QVersionNumber::compare() +*/ + +/*! + \fn bool operator<=(const QVersionNumber &lhs, const QVersionNumber &rhs) + \relates QVersionNumber + + Returns \c true if \a lhs is less than or equal to \a rhs; otherwise + returns \c false. + + \sa QVersionNumber::compare() +*/ + +/*! + \fn bool operator>(const QVersionNumber &lhs, const QVersionNumber &rhs) + \relates QVersionNumber + + Returns \c true if \a lhs is greater than \a rhs; otherwise returns \c + false. + + \sa QVersionNumber::compare() +*/ + +/*! + \fn bool operator>=(const QVersionNumber &lhs, const QVersionNumber &rhs) + \relates QVersionNumber + + Returns \c true if \a lhs is greater than or equal to \a rhs; otherwise + returns \c false. + + \sa QVersionNumber::compare() +*/ + +/*! + \fn bool operator==(const QVersionNumber &lhs, const QVersionNumber &rhs) + \relates QVersionNumber + + Returns \c true if \a lhs is equal to \a rhs; otherwise returns \c false. + + \sa QVersionNumber::compare() +*/ + +/*! + \fn bool operator!=(const QVersionNumber &lhs, const QVersionNumber &rhs) + \relates QVersionNumber + + Returns \c true if \a lhs is not equal to \a rhs; otherwise returns + \c false. + + \sa QVersionNumber::compare() +*/ + +/*! + \fn QString QVersionNumber::toString() const + + Returns a string with all of the segments delimited by a '.'. + + \sa majorVersion(), minorVersion(), microVersion(), segments() +*/ +QString QVersionNumber::toString() const +{ + QString version; + version.reserve(qMax(m_segments.size() * 2 - 1, 0)); + bool first = true; + for (QVector<int>::const_iterator it = m_segments.begin(), end = m_segments.end(); it != end; ++it) { + if (!first) + version += QLatin1Char('.'); + version += QString::number(*it); + first = false; + } + return version; +} + +/*! + \fn QVersionNumber QVersionNumber::fromString(const QString &string, + int *suffixIndex) + + Constructs a QVersionNumber from a specially formatted \a string of + non-negative decimal numbers delimited by '.'. + + Once the numerical segments have been parsed, the remainder of the string + is considered to be the suffix string. The start index of that string will be + stored in \a suffixIndex if it is not null. + + \snippet qversionnumber/main.cpp 3 + + \sa isNull() +*/ +QVersionNumber QVersionNumber::fromString(const QString &string, int *suffixIndex) +{ + QVector<int> seg; + + const QByteArray cString(string.toLatin1()); + + const char *start = cString.constData(); + const char *end = start; + const char *lastGoodEnd = start; + const char *endOfString = cString.constData() + cString.size(); + int value; + + do { + bool ok = false; + value = int(qstrtoull(start, &end, 10, &ok)); + if (!ok) + break; + seg.append(value); + start = end + 1; + lastGoodEnd = end; + } while (start < endOfString && (end < endOfString && *end == '.')); + + if (suffixIndex) + *suffixIndex = int(lastGoodEnd - cString.constData()); + + return QVersionNumber(qMove(seg)); +} + +/*! + \fn QVersionNumber QVersionNumber::normalizedImpl(QVector<int> &segs) + + Implementation of the normalized() function. Takes the movable list \a segs + and normalizes them. + + \internal + */ +QVersionNumber QVersionNumber::normalizedImpl(QVector<int> &segs) +{ + while (segs.size() && segs.last() == 0) + segs.pop_back(); + return QVersionNumber(qMove(segs)); +} + +#ifndef QT_NO_DATASTREAM +/*! + \fn QDataStream& operator<<(QDataStream &out, + const QVersionNumber &version) + \relates QVersionNumber + + Writes the version number \a version to stream \a out. + + Note that this has nothing to do with QDataStream::version(). + */ +QDataStream& operator<<(QDataStream &out, const QVersionNumber &version) +{ + out << version.segments(); + return out; +} + +/*! + \fn QDataStream& operator>>(QDataStream &in, QVersionNumber &version) + \relates QVersionNumber + + Reads a version number from stream \a in and stores it in \a version. + + Note that this has nothing to do with QDataStream::version(). + */ +QDataStream& operator>>(QDataStream &in, QVersionNumber &version) +{ + in >> version.m_segments; + return in; +} +#endif + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug debug, const QVersionNumber &version) +{ + debug.noquote() << version.toString(); + return debug.quote(); +} +#endif + +/*! + \fn uint qHash(const QVersionNumber &key, uint seed) + \relates QHash + \since 5.4 + + Returns the hash value for the \a key, using \a seed to seed the + calculation. +*/ +uint qHash(const QVersionNumber &key, uint seed) +{ + uint hash = seed; + for (QVector<int>::const_iterator it = key.m_segments.begin(), end = key.m_segments.end(); it != end; ++it) { + // used to preserve order + // see N3876 for more information + hash ^= qHash(*it) + 0x9e3779b9 + (hash << 6) + (hash >> 2); + } + return hash; +} + +QT_END_NAMESPACE diff --git a/src/corelib/tools/qversionnumber.h b/src/corelib/tools/qversionnumber.h new file mode 100644 index 0000000000..a951b2f1a0 --- /dev/null +++ b/src/corelib/tools/qversionnumber.h @@ -0,0 +1,201 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Keith Gardner <kreios4004@gmail.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QVERSIONNUMBER_H +#define QVERSIONNUMBER_H + +#include <QtCore/qnamespace.h> +#include <QtCore/qstring.h> +#include <QtCore/qvector.h> +#include <QtCore/qmetatype.h> +#include <QtCore/qtypeinfo.h> + +QT_BEGIN_NAMESPACE + +class QVersionNumber; +Q_CORE_EXPORT uint qHash(const QVersionNumber &key, uint seed = 0); + +#ifndef QT_NO_DATASTREAM +Q_CORE_EXPORT QDataStream& operator<<(QDataStream &out, const QVersionNumber &version); +Q_CORE_EXPORT QDataStream& operator>>(QDataStream &in, QVersionNumber &version); +#endif + +class Q_CORE_EXPORT QVersionNumber +{ +public: + inline QVersionNumber() Q_DECL_NOTHROW + : m_segments() + {} + // compiler-generated copy/move ctor/assignment operators are ok + + inline explicit QVersionNumber(const QVector<int> &seg) Q_DECL_NOTHROW + : m_segments(seg) + {} +#ifdef Q_COMPILER_RVALUE_REFS + inline explicit QVersionNumber(QVector<int> &&seg) Q_DECL_NOTHROW + : m_segments(qMove(seg)) + {} +#endif +#ifdef Q_COMPILER_INITIALIZER_LISTS + inline QVersionNumber(std::initializer_list<int> args) + : m_segments(args) + {} +#endif + + inline explicit QVersionNumber(int maj) + { m_segments.reserve(1); m_segments << maj; } + + inline explicit QVersionNumber(int maj, int min) + { m_segments.reserve(2); m_segments << maj << min; } + + inline explicit QVersionNumber(int maj, int min, int mic) + { m_segments.reserve(3); m_segments << maj << min << mic; } + + inline bool isNull() const Q_DECL_NOTHROW Q_REQUIRED_RESULT + { return m_segments.isEmpty(); } + + inline bool isNormalized() const Q_DECL_NOTHROW Q_REQUIRED_RESULT + { return isNull() || m_segments.last() != 0; } + + inline int majorVersion() const Q_DECL_NOTHROW Q_REQUIRED_RESULT + { return segmentAt(0); } + + inline int minorVersion() const Q_DECL_NOTHROW Q_REQUIRED_RESULT + { return segmentAt(1); } + + inline int microVersion() const Q_DECL_NOTHROW Q_REQUIRED_RESULT + { return segmentAt(2); } + +#if defined(Q_COMPILER_REF_QUALIFIERS) +# if defined(Q_CC_GNU) + // required due to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61941 +# pragma push_macro("Q_REQUIRED_RESULT") +# undef Q_REQUIRED_RESULT +# define Q_REQUIRED_RESULT +# define Q_REQUIRED_RESULT_pushed +# endif + inline QVersionNumber normalized() const & Q_REQUIRED_RESULT + { + QVector<int> segs(m_segments); + return normalizedImpl(segs); + } + + inline QVersionNumber normalized() && Q_REQUIRED_RESULT + { + return normalizedImpl(m_segments); + } + + inline QVector<int> segments() const & Q_DECL_NOTHROW Q_REQUIRED_RESULT + { return m_segments; } + + inline QVector<int> segments() && Q_DECL_NOTHROW Q_REQUIRED_RESULT + { return qMove(m_segments); } + +# ifdef Q_REQUIRED_RESULT_pushed +# pragma pop_macro("Q_REQUIRED_RESULT") +# endif +#else + inline QVersionNumber normalized() const Q_REQUIRED_RESULT + { + QVector<int> segs(m_segments); + return normalizedImpl(segs); + } + + inline QVector<int> segments() const Q_DECL_NOTHROW Q_REQUIRED_RESULT + { return m_segments; } +#endif + + inline int segmentAt(int index) const Q_DECL_NOTHROW Q_REQUIRED_RESULT + { return (m_segments.size() > index) ? m_segments.at(index) : 0; } + + inline int segmentCount() const Q_DECL_NOTHROW Q_REQUIRED_RESULT + { return m_segments.size(); } + + bool isPrefixOf(const QVersionNumber &other) const Q_DECL_NOTHROW Q_REQUIRED_RESULT; + + static int compare(const QVersionNumber &v1, const QVersionNumber &v2) Q_DECL_NOTHROW Q_REQUIRED_RESULT; + + static Q_DECL_PURE_FUNCTION QVersionNumber commonPrefix(const QVersionNumber &v1, const QVersionNumber &v2) Q_REQUIRED_RESULT; + + QString toString() const Q_REQUIRED_RESULT; + static Q_DECL_PURE_FUNCTION QVersionNumber fromString(const QString &string, int *suffixIndex = 0) Q_REQUIRED_RESULT; + +private: + static QVersionNumber normalizedImpl(QVector<int> &segs) Q_REQUIRED_RESULT; + +#ifndef QT_NO_DATASTREAM + friend Q_CORE_EXPORT QDataStream& operator>>(QDataStream &in, QVersionNumber &version); +#endif + friend Q_CORE_EXPORT uint qHash(const QVersionNumber &key, uint seed); + + QVector<int> m_segments; +}; + +Q_DECLARE_TYPEINFO(QVersionNumber, Q_MOVABLE_TYPE); + +#ifndef QT_NO_DEBUG_STREAM +Q_CORE_EXPORT QDebug operator<<(QDebug, const QVersionNumber &version); +#endif + +Q_REQUIRED_RESULT inline bool operator> (const QVersionNumber &lhs, const QVersionNumber &rhs) Q_DECL_NOTHROW +{ return QVersionNumber::compare(lhs, rhs) > 0; } + +Q_REQUIRED_RESULT inline bool operator>=(const QVersionNumber &lhs, const QVersionNumber &rhs) Q_DECL_NOTHROW +{ return QVersionNumber::compare(lhs, rhs) >= 0; } + +Q_REQUIRED_RESULT inline bool operator< (const QVersionNumber &lhs, const QVersionNumber &rhs) Q_DECL_NOTHROW +{ return QVersionNumber::compare(lhs, rhs) < 0; } + +Q_REQUIRED_RESULT inline bool operator<=(const QVersionNumber &lhs, const QVersionNumber &rhs) Q_DECL_NOTHROW +{ return QVersionNumber::compare(lhs, rhs) <= 0; } + +Q_REQUIRED_RESULT inline bool operator==(const QVersionNumber &lhs, const QVersionNumber &rhs) Q_DECL_NOTHROW +{ return QVersionNumber::compare(lhs, rhs) == 0; } + +Q_REQUIRED_RESULT inline bool operator!=(const QVersionNumber &lhs, const QVersionNumber &rhs) Q_DECL_NOTHROW +{ return QVersionNumber::compare(lhs, rhs) != 0; } + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QVersionNumber) + +#endif //QVERSIONNUMBER_H diff --git a/src/corelib/tools/tools.pri b/src/corelib/tools/tools.pri index d1208a1fe6..467f870249 100644 --- a/src/corelib/tools/tools.pri +++ b/src/corelib/tools/tools.pri @@ -69,7 +69,8 @@ HEADERS += \ tools/qunicodetables_p.h \ tools/qunicodetools_p.h \ tools/qvarlengtharray.h \ - tools/qvector.h + tools/qvector.h \ + tools/qversionnumber.h SOURCES += \ @@ -113,7 +114,8 @@ SOURCES += \ tools/qtimezoneprivate.cpp \ tools/qunicodetools.cpp \ tools/qvector.cpp \ - tools/qvsnprintf.cpp + tools/qvsnprintf.cpp \ + tools/qversionnumber.cpp NO_PCH_SOURCES = tools/qstring_compat.cpp msvc: NO_PCH_SOURCES += tools/qvector_msvc.cpp diff --git a/src/testlib/qtest.h b/src/testlib/qtest.h index 7d2f3cea72..8a18ea7541 100644 --- a/src/testlib/qtest.h +++ b/src/testlib/qtest.h @@ -54,6 +54,7 @@ #include <QtCore/qobject.h> #include <QtCore/qvariant.h> #include <QtCore/qurl.h> +#include <QtCore/qversionnumber.h> #include <QtCore/qpoint.h> #include <QtCore/qsize.h> @@ -171,6 +172,11 @@ template<> inline char *toString(const QVariant &v) return qstrdup(vstring.constData()); } +template<> inline char *toString(const QVersionNumber &version) +{ + return toString(version.toString()); +} + template<> inline bool qCompare(QString const &t1, QLatin1String const &t2, const char *actual, const char *expected, const char *file, int line) diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp index 703e547f6b..739d341233 100644 --- a/src/testlib/qtestcase.cpp +++ b/src/testlib/qtestcase.cpp @@ -1034,6 +1034,13 @@ QT_BEGIN_NAMESPACE Returns a textual representation of the given \a variant. */ +/*! + \fn char *QTest::toString(const QVersionNumber &version) + \overload + + Returns a textual representation of the given \a version. +*/ + /*! \fn void QTest::qWait(int ms) Waits for \a ms milliseconds. While waiting, events will be processed and diff --git a/tests/auto/corelib/tools/qversionnumber/qversionnumber.pro b/tests/auto/corelib/tools/qversionnumber/qversionnumber.pro new file mode 100644 index 0000000000..08ee0dd3d9 --- /dev/null +++ b/tests/auto/corelib/tools/qversionnumber/qversionnumber.pro @@ -0,0 +1,4 @@ +CONFIG += testcase parallel_test +TARGET = tst_qversionnumber +QT = core testlib +SOURCES = tst_qversionnumber.cpp diff --git a/tests/auto/corelib/tools/qversionnumber/tst_qversionnumber.cpp b/tests/auto/corelib/tools/qversionnumber/tst_qversionnumber.cpp new file mode 100644 index 0000000000..a43bb3ee68 --- /dev/null +++ b/tests/auto/corelib/tools/qversionnumber/tst_qversionnumber.cpp @@ -0,0 +1,577 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Keith Gardner <kreios4004@gmail.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> +#include <qversionnumber.h> + +class tst_QVersionNumber : public QObject +{ + Q_OBJECT + +private: + void singleInstanceData(); + void comparisonData(); + +private slots: + void initTestCase(); + void constructorDefault(); + void constructorVersioned_data(); + void constructorVersioned(); + void constructorExplicit(); + void constructorCopy_data(); + void constructorCopy(); + void compareGreater_data(); + void compareGreater(); + void compareGreaterEqual_data(); + void compareGreaterEqual(); + void compareLess_data(); + void compareLess(); + void compareLessEqual_data(); + void compareLessEqual(); + void compareEqual_data(); + void compareEqual(); + void compareNotEqual_data(); + void compareNotEqual(); + void compare_data(); + void compare(); + void isPrefixOf_data(); + void isPrefixOf(); + void commonPrefix_data(); + void commonPrefix(); + void normalized_data(); + void normalized(); + void isNormalized_data(); + void isNormalized(); + void assignment_data(); + void assignment(); + void fromString_data(); + void fromString(); + void toString_data(); + void toString(); + void isNull_data(); + void isNull(); + void serialize_data(); + void serialize(); + void moveSemantics(); +}; + +void tst_QVersionNumber::singleInstanceData() +{ + QTest::addColumn<QVector<int> >("segments"); + QTest::addColumn<QVersionNumber>("expectedVersion"); + QTest::addColumn<QString>("expectedString"); + QTest::addColumn<QString>("constructionString"); + QTest::addColumn<int>("suffixIndex"); + QTest::addColumn<bool>("isNull"); + + // segments expectedVersion expectedString constructionString suffixIndex null + QTest::newRow("null") << QVector<int>() << QVersionNumber(QVector<int>()) << QString() << QString() << 0 << true; + QTest::newRow("text") << QVector<int>() << QVersionNumber(QVector<int>()) << QString() << QStringLiteral("text") << 0 << true; + QTest::newRow(" text") << QVector<int>() << QVersionNumber(QVector<int>()) << QString() << QStringLiteral(" text") << 0 << true; + QTest::newRow("Empty String") << QVector<int>() << QVersionNumber(QVector<int>()) << QString() << QStringLiteral("Empty String") << 0 << true; + QTest::newRow("-1.-2") << (QVector<int>()) << QVersionNumber() << QStringLiteral("") << QStringLiteral("-1.-2") << 0 << true; + QTest::newRow("1.-2-3") << (QVector<int>() << 1) << QVersionNumber(QVector<int>() << 1) << QStringLiteral("1") << QStringLiteral("1.-2-3") << 1 << false; + QTest::newRow("1.2-3") << (QVector<int>() << 1 << 2) << QVersionNumber(QVector<int>() << 1 << 2) << QStringLiteral("1.2") << QStringLiteral("1.2-3") << 3 << false; + QTest::newRow("0") << (QVector<int>() << 0) << QVersionNumber(QVector<int>() << 0) << QStringLiteral("0") << QStringLiteral("0") << 1 << false; + QTest::newRow("0.1") << (QVector<int>() << 0 << 1) << QVersionNumber(QVector<int>() << 0 << 1) << QStringLiteral("0.1") << QStringLiteral("0.1") << 3 << false; + QTest::newRow("0.1.2") << (QVector<int>() << 0 << 1 << 2) << QVersionNumber(0, 1, 2) << QStringLiteral("0.1.2") << QStringLiteral("0.1.2") << 5 << false; + QTest::newRow("0.1.2alpha") << (QVector<int>() << 0 << 1 << 2) << QVersionNumber(0, 1, 2) << QStringLiteral("0.1.2") << QStringLiteral("0.1.2alpha") << 5 << false; + QTest::newRow("0.1.2-alpha") << (QVector<int>() << 0 << 1 << 2) << QVersionNumber(0, 1, 2) << QStringLiteral("0.1.2") << QStringLiteral("0.1.2-alpha") << 5 << false; + QTest::newRow("0.1.2.alpha") << (QVector<int>() << 0 << 1 << 2) << QVersionNumber(0, 1, 2) << QStringLiteral("0.1.2") << QStringLiteral("0.1.2.alpha") << 5 << false; + QTest::newRow("0.1.2.3.4.alpha") << (QVector<int>() << 0 << 1 << 2 << 3 << 4) << QVersionNumber(QVector<int>() << 0 << 1 << 2 << 3 << 4) << QStringLiteral("0.1.2.3.4") << QStringLiteral("0.1.2.3.4.alpha") << 9 << false; + QTest::newRow("0.1.2.3.4 alpha") << (QVector<int>() << 0 << 1 << 2 << 3 << 4) << QVersionNumber(QVector<int>() << 0 << 1 << 2 << 3 << 4) << QStringLiteral("0.1.2.3.4") << QStringLiteral("0.1.2.3.4 alpha") << 9 << false; + QTest::newRow("0.1.2.3.4 alp ha") << (QVector<int>() << 0 << 1 << 2 << 3 << 4) << QVersionNumber(QVector<int>() << 0 << 1 << 2 << 3 << 4) << QStringLiteral("0.1.2.3.4") << QStringLiteral("0.1.2.3.4 alp ha") << 9 << false; + QTest::newRow("0.1.2.3.4alp ha") << (QVector<int>() << 0 << 1 << 2 << 3 << 4) << QVersionNumber(QVector<int>() << 0 << 1 << 2 << 3 << 4) << QStringLiteral("0.1.2.3.4") << QStringLiteral("0.1.2.3.4alp ha") << 9 << false; + QTest::newRow("0.1.2.3.4alpha ") << (QVector<int>() << 0 << 1 << 2 << 3 << 4) << QVersionNumber(QVector<int>() << 0 << 1 << 2 << 3 << 4) << QStringLiteral("0.1.2.3.4") << QStringLiteral("0.1.2.3.4alpha ") << 9 << false; + QTest::newRow("10.09") << (QVector<int>() << 10 << 9) << QVersionNumber(QVector<int>() << 10 << 9) << QStringLiteral("10.9") << QStringLiteral("10.09") << 5 << false; + QTest::newRow("10.0x") << (QVector<int>() << 10 << 0) << QVersionNumber(QVector<int>() << 10 << 0) << QStringLiteral("10.0") << QStringLiteral("10.0x") << 4 << false; + QTest::newRow("10.0xTest") << (QVector<int>() << 10 << 0) << QVersionNumber(QVector<int>() << 10 << 0) << QStringLiteral("10.0") << QStringLiteral("10.0xTest") << 4 << false; +} + +void tst_QVersionNumber::comparisonData() +{ + QTest::addColumn<QVersionNumber>("lhs"); + QTest::addColumn<QVersionNumber>("rhs"); + QTest::addColumn<bool>("equal"); + QTest::addColumn<bool>("notEqual"); + QTest::addColumn<bool>("lessThan"); + QTest::addColumn<bool>("lessThanOrEqual"); + QTest::addColumn<bool>("greaterThan"); + QTest::addColumn<bool>("greaterThanOrEqual"); + QTest::addColumn<int>("compareResult"); + QTest::addColumn<bool>("isPrefix"); + QTest::addColumn<QVersionNumber>("common"); + + // LHS RHS == != < <= > >= compareResult isPrefixOf commonPrefix + QTest::newRow("null, null") << QVersionNumber() << QVersionNumber() << true << false << false << true << false << true << 0 << true << QVersionNumber(); + QTest::newRow("null, 0") << QVersionNumber() << QVersionNumber(0) << false << true << true << true << false << false << -1 << true << QVersionNumber(); + QTest::newRow("0, null") << QVersionNumber(0) << QVersionNumber() << false << true << false << false << true << true << 1 << false << QVersionNumber(); + QTest::newRow("0, 0") << QVersionNumber(0) << QVersionNumber(0) << true << false << false << true << false << true << 0 << true << QVersionNumber(0); + QTest::newRow("1.0, 1.0") << QVersionNumber(1, 0) << QVersionNumber(1, 0) << true << false << false << true << false << true << 0 << true << QVersionNumber(1, 0); + QTest::newRow("1, 1.0") << QVersionNumber(1) << QVersionNumber(1, 0) << false << true << true << true << false << false << -1 << true << QVersionNumber(1); + QTest::newRow("1.0, 1") << QVersionNumber(1, 0) << QVersionNumber(1) << false << true << false << false << true << true << 1 << false << QVersionNumber(1); + QTest::newRow("0.1.2, 0.1") << QVersionNumber(0, 1, 2) << QVersionNumber(0, 1) << false << true << false << false << true << true << 2 << false << QVersionNumber(0, 1); + QTest::newRow("0.1, 0.1.2") << QVersionNumber(0, 1) << QVersionNumber(0, 1, 2) << false << true << true << true << false << false << -2 << true << QVersionNumber(0, 1); + QTest::newRow("0.1.2, 0.1.2") << QVersionNumber(0, 1, 2) << QVersionNumber(0, 1, 2) << true << false << false << true << false << true << 0 << true << QVersionNumber(0, 1, 2); + QTest::newRow("0.1.2, 1.1.2") << QVersionNumber(0, 1, 2) << QVersionNumber(1, 1, 2) << false << true << true << true << false << false << -1 << false << QVersionNumber(); + QTest::newRow("1.1.2, 0.1.2") << QVersionNumber(1, 1, 2) << QVersionNumber(0, 1, 2) << false << true << false << false << true << true << 1 << false << QVersionNumber(); + QTest::newRow("1, -1") << QVersionNumber(1) << QVersionNumber(-1) << false << true << false << false << true << true << 2 << false << QVersionNumber(); + QTest::newRow("-1, 1") << QVersionNumber(-1) << QVersionNumber(1) << false << true << true << true << false << false << -2 << false << QVersionNumber(); + QTest::newRow("0.1, 0.-1") << QVersionNumber(0, 1) << QVersionNumber(0, -1) << false << true << false << false << true << true << 2 << false << QVersionNumber(0); + QTest::newRow("0.-1, 0.1") << QVersionNumber(0, -1) << QVersionNumber(0, 1) << false << true << true << true << false << false << -2 << false << QVersionNumber(0); + QTest::newRow("0.-1, 0") << QVersionNumber(0, -1) << QVersionNumber(0) << false << true << true << true << false << false << -1 << false << QVersionNumber(0); + QTest::newRow("0, 0.-1") << QVersionNumber(0) << QVersionNumber(0, -1) << false << true << false << false << true << true << 1 << true << QVersionNumber(0); +} + +void tst_QVersionNumber::initTestCase() +{ + qRegisterMetaType<QVector<int> >(); +} + +void tst_QVersionNumber::constructorDefault() +{ + QVersionNumber version; + + QCOMPARE(version.majorVersion(), 0); + QCOMPARE(version.minorVersion(), 0); + QCOMPARE(version.microVersion(), 0); + QCOMPARE(version.segments(), QVector<int>()); +} + +void tst_QVersionNumber::constructorVersioned_data() +{ + singleInstanceData(); +} + +void tst_QVersionNumber::constructorVersioned() +{ + QFETCH(QVector<int>, segments); + QFETCH(QVersionNumber, expectedVersion); + + QVersionNumber version(segments); + QCOMPARE(version.majorVersion(), expectedVersion.majorVersion()); + QCOMPARE(version.minorVersion(), expectedVersion.minorVersion()); + QCOMPARE(version.microVersion(), expectedVersion.microVersion()); + QCOMPARE(version.segments(), expectedVersion.segments()); +} + +void tst_QVersionNumber::constructorExplicit() +{ + QVersionNumber v1(1); + QVersionNumber v2(QVector<int>() << 1); + + QCOMPARE(v1.segments(), v2.segments()); + + QVersionNumber v3(1, 2); + QVersionNumber v4(QVector<int>() << 1 << 2); + + QCOMPARE(v3.segments(), v4.segments()); + + QVersionNumber v5(1, 2, 3); + QVersionNumber v6(QVector<int>() << 1 << 2 << 3); + + QCOMPARE(v5.segments(), v6.segments()); + +#ifdef Q_COMPILER_INITIALIZER_LISTS + QVersionNumber v7(4, 5, 6); + QVersionNumber v8 = {4, 5, 6}; + + QCOMPARE(v7.segments(), v8.segments()); +#endif +} + +void tst_QVersionNumber::constructorCopy_data() +{ + singleInstanceData(); +} + +void tst_QVersionNumber::constructorCopy() +{ + QFETCH(QVector<int>, segments); + QFETCH(QVersionNumber, expectedVersion); + + QVersionNumber original(segments); + QVersionNumber version(original); + + QCOMPARE(version.majorVersion(), expectedVersion.majorVersion()); + QCOMPARE(version.minorVersion(), expectedVersion.minorVersion()); + QCOMPARE(version.microVersion(), expectedVersion.microVersion()); + QCOMPARE(version.segments(), expectedVersion.segments()); +} + +void tst_QVersionNumber::compareGreater_data() +{ + comparisonData(); +} + +void tst_QVersionNumber::compareGreater() +{ + QFETCH(QVersionNumber, lhs); + QFETCH(QVersionNumber, rhs); + QFETCH(bool, greaterThan); + + QCOMPARE(lhs > rhs, greaterThan); +} + +void tst_QVersionNumber::compareGreaterEqual_data() +{ + comparisonData(); +} + +void tst_QVersionNumber::compareGreaterEqual() +{ + QFETCH(QVersionNumber, lhs); + QFETCH(QVersionNumber, rhs); + QFETCH(bool, greaterThanOrEqual); + + QCOMPARE(lhs >= rhs, greaterThanOrEqual); +} + +void tst_QVersionNumber::compareLess_data() +{ + comparisonData(); +} + +void tst_QVersionNumber::compareLess() +{ + QFETCH(QVersionNumber, lhs); + QFETCH(QVersionNumber, rhs); + QFETCH(bool, lessThan); + + QCOMPARE(lhs < rhs, lessThan); +} + +void tst_QVersionNumber::compareLessEqual_data() +{ + comparisonData(); +} + +void tst_QVersionNumber::compareLessEqual() +{ + QFETCH(QVersionNumber, lhs); + QFETCH(QVersionNumber, rhs); + QFETCH(bool, lessThanOrEqual); + + QCOMPARE(lhs <= rhs, lessThanOrEqual); +} + +void tst_QVersionNumber::compareEqual_data() +{ + comparisonData(); +} + +void tst_QVersionNumber::compareEqual() +{ + QFETCH(QVersionNumber, lhs); + QFETCH(QVersionNumber, rhs); + QFETCH(bool, equal); + + QCOMPARE(lhs == rhs, equal); +} + +void tst_QVersionNumber::compareNotEqual_data() +{ + comparisonData(); +} + +void tst_QVersionNumber::compareNotEqual() +{ + QFETCH(QVersionNumber, lhs); + QFETCH(QVersionNumber, rhs); + QFETCH(bool, notEqual); + + QCOMPARE(lhs != rhs, notEqual); +} + +void tst_QVersionNumber::compare_data() +{ + comparisonData(); +} + +void tst_QVersionNumber::compare() +{ + QFETCH(QVersionNumber, lhs); + QFETCH(QVersionNumber, rhs); + QFETCH(int, compareResult); + + QCOMPARE(QVersionNumber::compare(lhs, rhs), compareResult); +} + +void tst_QVersionNumber::isPrefixOf_data() +{ + comparisonData(); +} + +void tst_QVersionNumber::isPrefixOf() +{ + QFETCH(QVersionNumber, lhs); + QFETCH(QVersionNumber, rhs); + QFETCH(bool, isPrefix); + + QCOMPARE(lhs.isPrefixOf(rhs), isPrefix); +} + +void tst_QVersionNumber::commonPrefix_data() +{ + comparisonData(); +} + +void tst_QVersionNumber::commonPrefix() +{ + QFETCH(QVersionNumber, lhs); + QFETCH(QVersionNumber, rhs); + QFETCH(QVersionNumber, common); + + QVersionNumber calculatedPrefix = QVersionNumber::commonPrefix(lhs, rhs); + QCOMPARE(calculatedPrefix, common); + QCOMPARE(calculatedPrefix.segments(), common.segments()); +} + +void tst_QVersionNumber::normalized_data() +{ + QTest::addColumn<QVersionNumber>("version"); + QTest::addColumn<QVersionNumber>("expected"); + + QTest::newRow("0") << QVersionNumber(0) << QVersionNumber(); + QTest::newRow("1") << QVersionNumber(1) << QVersionNumber(1); + QTest::newRow("1.2") << QVersionNumber(1, 2) << QVersionNumber(1, 2); + QTest::newRow("1.0") << QVersionNumber(1, 0) << QVersionNumber(1); + QTest::newRow("1.0.0") << QVersionNumber(1, 0, 0) << QVersionNumber(1); + QTest::newRow("1.0.1") << QVersionNumber(1, 0, 1) << QVersionNumber(1, 0, 1); + QTest::newRow("1.0.1.0") << QVersionNumber(QVector<int>() << 1 << 0 << 1 << 0) << QVersionNumber(1, 0, 1); + QTest::newRow("0.0.1.0") << QVersionNumber(QVector<int>() << 0 << 0 << 1 << 0) << QVersionNumber(0, 0, 1); +} + +void tst_QVersionNumber::normalized() +{ + QFETCH(QVersionNumber, version); + QFETCH(QVersionNumber, expected); + + QCOMPARE(version.normalized(), expected); + QCOMPARE(qMove(version).normalized(), expected); +} + +void tst_QVersionNumber::isNormalized_data() +{ + QTest::addColumn<QVersionNumber>("version"); + QTest::addColumn<bool>("expected"); + + QTest::newRow("null") << QVersionNumber() << true; + QTest::newRow("0") << QVersionNumber(0) << false; + QTest::newRow("1") << QVersionNumber(1) << true; + QTest::newRow("1.2") << QVersionNumber(1, 2) << true; + QTest::newRow("1.0") << QVersionNumber(1, 0) << false; + QTest::newRow("1.0.0") << QVersionNumber(1, 0, 0) << false; + QTest::newRow("1.0.1") << QVersionNumber(1, 0, 1) << true; +} + +void tst_QVersionNumber::isNormalized() +{ + QFETCH(QVersionNumber, version); + QFETCH(bool, expected); + + QCOMPARE(version.isNormalized(), expected); +} + +void tst_QVersionNumber::assignment_data() +{ + singleInstanceData(); +} + +void tst_QVersionNumber::assignment() +{ + QFETCH(QVector<int>, segments); + QFETCH(QVersionNumber, expectedVersion); + + QVersionNumber original(segments); + QVersionNumber version; + version = original; + + QCOMPARE(version.majorVersion(), expectedVersion.majorVersion()); + QCOMPARE(version.minorVersion(), expectedVersion.minorVersion()); + QCOMPARE(version.microVersion(), expectedVersion.microVersion()); + QCOMPARE(version.segments(), expectedVersion.segments()); +} + +void tst_QVersionNumber::fromString_data() +{ + singleInstanceData(); +} + +void tst_QVersionNumber::fromString() +{ + QFETCH(QString, constructionString); + QFETCH(QVersionNumber, expectedVersion); + QFETCH(int, suffixIndex); + + int index; + QCOMPARE(QVersionNumber::fromString(constructionString), expectedVersion); + QCOMPARE(QVersionNumber::fromString(constructionString, &index), expectedVersion); + QCOMPARE(index, suffixIndex); +} + +void tst_QVersionNumber::toString_data() +{ + singleInstanceData(); + + // segments expectedVersion expectedString constructionString suffixIndex null + QTest::newRow("-1") << (QVector<int>() << -1) << QVersionNumber(-1) << QString("-1") << QString() << 0 << true; + QTest::newRow("-1.0") << (QVector<int>() << -1 << 0) << QVersionNumber(-1, 0) << QString("-1.0") << QString() << 0 << true; + QTest::newRow("1.-2") << (QVector<int>() << 1 << -2) << QVersionNumber(1, -2) << QString("1.-2") << QString() << 0 << true; +} + +void tst_QVersionNumber::toString() +{ + QFETCH(QVersionNumber, expectedVersion); + QFETCH(QString, expectedString); + + QCOMPARE(expectedVersion.toString(), expectedString); +} + +void tst_QVersionNumber::isNull_data() +{ + singleInstanceData(); +} + +void tst_QVersionNumber::isNull() +{ + QFETCH(QVector<int>, segments); + QFETCH(bool, isNull); + + QVersionNumber version(segments); + + QCOMPARE(version.isNull(), isNull); +} + +void tst_QVersionNumber::serialize_data() +{ + singleInstanceData(); +} + +void tst_QVersionNumber::serialize() +{ + QFETCH(QVector<int>, segments); + + QVersionNumber original(segments); + QVersionNumber version; + + QByteArray buffer; + { + QDataStream ostream(&buffer, QIODevice::WriteOnly); + ostream << original; + } + { + QDataStream istream(buffer); + istream >> version; + } + + QCOMPARE(version.majorVersion(), original.majorVersion()); + QCOMPARE(version.minorVersion(), original.minorVersion()); + QCOMPARE(version.microVersion(), original.microVersion()); + QCOMPARE(version.segments(), original.segments()); +} + +void tst_QVersionNumber::moveSemantics() +{ +#if defined(_MSC_VER) && _MSC_VER == 1600 +# define Q_MSVC_2010 +#endif +#if defined(Q_COMPILER_RVALUE_REFS) && !defined(Q_MSVC_2010) + // QVersionNumber(QVersionNumber &&) + { + QVersionNumber v1(1, 2, 3); + QVersionNumber v2 = qMove(v1); + QCOMPARE(v2, QVersionNumber(1, 2, 3)); + } + // QVersionNumber &operator=(QVersionNumber &&) + { + QVersionNumber v1(1, 2, 3); + QVersionNumber v2; + v2 = qMove(v1); + QCOMPARE(v2, QVersionNumber(1, 2, 3)); + } + // QVersionNumber(QVector<int> &&) + { + QVector<int> segments = QVector<int>() << 1 << 2 << 3; + QVersionNumber v1(segments); + QVersionNumber v2(qMove(segments)); + QVERIFY(!v1.isNull()); + QVERIFY(!v2.isNull()); + QCOMPARE(v1, v2); + } +#endif +#if defined(Q_COMPILER_REF_QUALIFIERS) && !defined(Q_MSVC_2010) + // normalized() + { + QVersionNumber v(1, 0, 0); + QVERIFY(!v.isNull()); + QVersionNumber nv; + nv = v.normalized(); + QVERIFY(!v.isNull()); + QVERIFY(!nv.isNull()); + QVERIFY(nv.isNormalized()); + nv = qMove(v).normalized(); + QVERIFY(!nv.isNull()); + QVERIFY(nv.isNormalized()); + } + // segments() + { + QVersionNumber v(1, 2, 3); + QVERIFY(!v.isNull()); + QVector<int> segments; + segments = v.segments(); + QVERIFY(!v.isNull()); + QVERIFY(!segments.empty()); + segments = qMove(v).segments(); + QVERIFY(!segments.empty()); + } +#endif +#if !defined(Q_COMPILER_RVALUE_REFS) && !defined(Q_COMPILER_REF_QUALIFIERS) && !defined(Q_MSVC_2010) + QSKIP("This test requires C++11 move semantics support in the compiler."); +#elif defined(Q_MSVC_2010) + QSKIP("This test requires compiler generated move constructors and operators."); +#endif +} + +QTEST_APPLESS_MAIN(tst_QVersionNumber) + +#include "tst_qversionnumber.moc" diff --git a/tests/auto/corelib/tools/tools.pro b/tests/auto/corelib/tools/tools.pro index 352cf88d44..19cb060960 100644 --- a/tests/auto/corelib/tools/tools.pro +++ b/tests/auto/corelib/tools/tools.pro @@ -59,4 +59,6 @@ SUBDIRS=\ qtimeline \ qvarlengtharray \ qvector \ - qvector_strictiterators + qvector_strictiterators \ + qversionnumber + |