summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKeith Gardner <kreios4004@gmail.com>2014-03-28 21:45:33 -0500
committerOswald Buddenhagen <oswald.buddenhagen@digia.com>2014-08-09 09:00:24 +0200
commita332322de95f25ca3228102d80d6a92b73b6177d (patch)
tree3c97b56f0b5e1c0f2b98011332a47ec8f523e143
parent3750c677ee4cac5525f9c7be3978173037dd089d (diff)
Long live QVersionNumber!
The class provides compare operators, stream operators, and hashing functions. This class aims to be compatible with (but not restricted to) the Semantic Versioning 2.0 standard (semver.org). [ChangeLog][QtCore] Added QVersionNumber class Done-with: Marc Mutz <marc.mutz@kdab.com> Change-Id: I244c8ccc002909af03987a2df052734d1a8621a9 Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@digia.com>
-rw-r--r--src/corelib/doc/snippets/qversionnumber/main.cpp109
-rw-r--r--src/corelib/tools/qversionnumber.cpp484
-rw-r--r--src/corelib/tools/qversionnumber.h201
-rw-r--r--src/corelib/tools/tools.pri6
-rw-r--r--src/testlib/qtest.h6
-rw-r--r--src/testlib/qtestcase.cpp7
-rw-r--r--tests/auto/corelib/tools/qversionnumber/qversionnumber.pro4
-rw-r--r--tests/auto/corelib/tools/qversionnumber/tst_qversionnumber.cpp577
-rw-r--r--tests/auto/corelib/tools/tools.pro4
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
+