summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc Mutz <marc.mutz@kdab.com>2017-04-24 09:54:02 +0200
committerMarc Mutz <marc.mutz@kdab.com>2017-04-26 09:11:27 +0000
commit979f9f4d3442ef9373e823cd681c5c23f84cc55b (patch)
treef69f51de19bf75a3f29ec1e0abbcd42c27ff3187
parent5677b70eee2e923eea8e5150500ac745d8d54974 (diff)
QLatin1String: fix qt_compare_strings(QLatin1String, QLatin1String) for null strings
qstrcmp sorts null strings before empty ones, while the Qt string classes consider them equal. The qt_compare_strings() overload for QLatin1String was using qstrcmp(), but is supposed to implement the semantics that Qt string classes use, so we need to add an extra check. Was uncovered by tests for QLatin1String::startsWith(), but added a new test for qCompareStrings() now, which is a bit more complicated than desired, due to the lack of QUtf8String. Change-Id: I0493c4491df928a68861a1bc7f0962f1c870a416 Reviewed-by: Edward Welbourne <edward.welbourne@qt.io> Reviewed-by: Lars Knoll <lars.knoll@qt.io>
-rw-r--r--src/corelib/tools/qstring.cpp2
-rw-r--r--tests/auto/corelib/tools/qstringapisymmetry/tst_qstringapisymmetry.cpp40
2 files changed, 42 insertions, 0 deletions
diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp
index e5e2376888..5d250df99c 100644
--- a/src/corelib/tools/qstring.cpp
+++ b/src/corelib/tools/qstring.cpp
@@ -695,6 +695,8 @@ static int qt_compare_strings(QStringView lhs, QLatin1String rhs, Qt::CaseSensit
static int qt_compare_strings(QLatin1String lhs, QLatin1String rhs, Qt::CaseSensitivity cs) Q_DECL_NOTHROW
{
+ if (lhs.isEmpty())
+ return lencmp(0, rhs.size());
const auto l = std::min(lhs.size(), rhs.size());
int r;
if (cs == Qt::CaseSensitive)
diff --git a/tests/auto/corelib/tools/qstringapisymmetry/tst_qstringapisymmetry.cpp b/tests/auto/corelib/tools/qstringapisymmetry/tst_qstringapisymmetry.cpp
index f2ca48d739..4c2219cf7a 100644
--- a/tests/auto/corelib/tools/qstringapisymmetry/tst_qstringapisymmetry.cpp
+++ b/tests/auto/corelib/tools/qstringapisymmetry/tst_qstringapisymmetry.cpp
@@ -319,6 +319,9 @@ void tst_QStringApiSymmetry::compare_data(bool hasConceptOfNullAndEmpty)
QTest::newRow("null <> empty") << QStringRef() << QLatin1String()
<< QStringRef(&empty) << QLatin1String("")
<< 0 << 0;
+ QTest::newRow("empty <> null") << QStringRef(&empty) << QLatin1String("")
+ << QStringRef() << QLatin1String()
+ << 0 << 0;
}
#define ROW(lhs, rhs) \
@@ -363,6 +366,38 @@ struct has_nothrow_compare {
};
template <typename LHS, typename RHS>
+struct has_qCompareStrings {
+ enum { value = !std::is_same<LHS, QChar>::value && !std::is_same<RHS, QChar>::value &&
+ !is_utf8_encoded<LHS>::value && !is_utf8_encoded<RHS>::value };
+};
+
+template <typename LHS, typename RHS>
+using if_has_qCompareStrings = typename std::enable_if<has_qCompareStrings<LHS, RHS>::value, bool>::type;
+
+template <typename LHS, typename RHS>
+using if_lacks_qCompareStrings = typename std::enable_if<!has_qCompareStrings<LHS, RHS>::value, bool>::type;
+
+static inline Q_DECL_CONSTEXPR int sign(int x) Q_DECL_NOTHROW
+{
+ return x < 0 ? -1 :
+ x > 0 ? +1 :
+ /*else*/ 0 ;
+}
+
+template <typename LHS, typename RHS, if_has_qCompareStrings<LHS, RHS> = true>
+int qCompareStringsWrapper(const LHS &lhs, const RHS &rhs, Qt::CaseSensitivity cs, int)
+ Q_DECL_NOEXCEPT_EXPR(noexcept(qCompareStrings(lhs, rhs, cs)))
+{
+ return qCompareStrings(lhs, rhs, cs);
+}
+
+template <typename LHS, typename RHS, if_lacks_qCompareStrings<LHS, RHS> = true>
+int qCompareStringsWrapper(const LHS &, const RHS &, Qt::CaseSensitivity, int result)
+{
+ return result;
+}
+
+template <typename LHS, typename RHS>
void tst_QStringApiSymmetry::compare_impl() const
{
QFETCH(QStringRef, lhsUnicode);
@@ -370,6 +405,7 @@ void tst_QStringApiSymmetry::compare_impl() const
QFETCH(QStringRef, rhsUnicode);
QFETCH(QLatin1String, rhsLatin1);
QFETCH(int, caseSensitiveCompareResult);
+ QFETCH(const int, caseInsensitiveCompareResult);
const auto lhsU8 = lhsUnicode.toUtf8();
const auto rhsU8 = rhsUnicode.toUtf8();
@@ -386,6 +422,10 @@ void tst_QStringApiSymmetry::compare_impl() const
# define QVERIFY_NOEXCEPT(expr)
#endif
+ QCOMPARE(sign(qCompareStringsWrapper(lhs, rhs, Qt::CaseSensitive, caseSensitiveCompareResult)),
+ sign(caseSensitiveCompareResult));
+ QCOMPARE(sign(qCompareStringsWrapper(lhs, rhs, Qt::CaseInsensitive, caseInsensitiveCompareResult)),
+ sign(caseInsensitiveCompareResult));
#define CHECK(op) \
QVERIFY_NOEXCEPT(lhs op rhs); \
do { if (caseSensitiveCompareResult op 0) { \