aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/qml/qqmllocale/tst_qqmllocale.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/qml/qqmllocale/tst_qqmllocale.cpp')
-rw-r--r--tests/auto/qml/qqmllocale/tst_qqmllocale.cpp519
1 files changed, 344 insertions, 175 deletions
diff --git a/tests/auto/qml/qqmllocale/tst_qqmllocale.cpp b/tests/auto/qml/qqmllocale/tst_qqmllocale.cpp
index 822fe33b83..a7ddf79ad5 100644
--- a/tests/auto/qml/qqmllocale/tst_qqmllocale.cpp
+++ b/tests/auto/qml/qqmllocale/tst_qqmllocale.cpp
@@ -1,50 +1,58 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
#include <qtest.h>
#include <QDebug>
+#include <private/qqmllocale_p.h>
+
#include <QtQml/qqmlengine.h>
+#include <QtQml/qqmlexpression.h>
#include <QtQml/qqmlcomponent.h>
#include <QtQml/qqmlcontext.h>
#include <QtCore/QDateTime>
+#include <QtCore/qtimezone.h>
#include <QtCore/qscopeguard.h>
#include <QtCore/qscopedpointer.h>
-#include <QtCore/qtimezone.h>
#include <qcolor.h>
-#include "../../shared/util.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
#include <time.h>
+#undef QT_CAN_CHANGE_SYSTEM_ZONE
+/* See QTBUG-56899. We don't (yet) have a proper way to reset the system zone,
+ Testing Date.timeZoneUpdated() is only possible on systems where we have a
+ way to change the system zone in use.
+*/
+#ifdef Q_OS_ANDROID
+/* Android's time_t-related system functions don't seem to care about the TZ
+ environment variable. If we can find a way to change the zone those functions
+ use, try implementing it here.
+*/
+#elif defined(Q_OS_UNIX)
+static void setTimeZone(const QByteArray &tz)
+{
+ if (tz.isEmpty())
+ qunsetenv("TZ");
+ else
+ qputenv("TZ", tz);
+ ::tzset();
+}
+#define QT_CAN_CHANGE_SYSTEM_ZONE
+#else
+/* On Windows, adjusting the timezone (such that GetTimeZoneInformation() will
+ notice) requires additional privileges that aren't normally enabled for a
+ process. This can be achieved by calling AdjustTokenPrivileges() and then
+ SetTimeZoneInformation(), which will require linking to a different library
+ to access that API.
+*/
+#endif
+
class tst_qqmllocale : public QQmlDataTest
{
Q_OBJECT
public:
- tst_qqmllocale() { }
+ tst_qqmllocale() : QQmlDataTest(QT_QMLTEST_DATADIR) { }
private slots:
void defaultLocale();
@@ -61,6 +69,8 @@ private slots:
void dayName();
void standaloneDayName_data();
void standaloneDayName();
+ void toString_data();
+ void toString();
void firstDayOfWeek_data();
void firstDayOfWeek();
void weekDays_data();
@@ -73,9 +83,11 @@ private slots:
void dateTimeFormat();
void timeFormat_data();
void timeFormat();
-#if defined(Q_OS_UNIX) && QT_CONFIG(timezone)
+#ifdef QT_CAN_CHANGE_SYSTEM_ZONE
void timeZoneUpdated();
#endif
+ void formattedDataSize_data();
+ void formattedDataSize();
void dateToLocaleString_data();
void dateToLocaleString();
@@ -118,6 +130,9 @@ private:
void addDateTimeFormatData(const QString &l);
void addDateFormatData(const QString &l);
void addTimeFormatData(const QString &l);
+ void addFormattedDataSizeDataForLocale(const QString &l);
+ void testFunctionCall();
+ void addTestFunctionCallDataColumns();
QQmlEngine engine;
};
@@ -125,7 +140,7 @@ void tst_qqmllocale::defaultLocale()
{
QQmlComponent c(&engine, testFileUrl("properties.qml"));
- QObject *obj = c.create();
+ QScopedPointer<QObject> obj(c.create());
QVERIFY(obj);
QCOMPARE(obj->property("name").toString(), QLocale().name());
@@ -146,7 +161,7 @@ void tst_qqmllocale::addPropertyData(const QString &l)
LOCALE_PROP(QString,amText),
LOCALE_PROP(QString,pmText),
LOCALE_PROP(QString,nativeLanguageName),
- LOCALE_PROP(QString,nativeCountryName),
+ LOCALE_PROP(QString,nativeTerritoryName),
LOCALE_PROP(QString,decimalPoint),
LOCALE_PROP(QString,groupSeparator),
LOCALE_PROP(QString,percent),
@@ -189,15 +204,13 @@ void tst_qqmllocale::properties()
QQmlComponent c(&engine, testFileUrl("properties.qml"));
- QObject *obj = c.create();
+ QScopedPointer<QObject> obj(c.create());
QVERIFY(obj);
- QMetaObject::invokeMethod(obj, "setLocale", Qt::DirectConnection,
+ QMetaObject::invokeMethod(obj.data(), "setLocale", Qt::DirectConnection,
Q_ARG(QVariant, QVariant(locale)));
QCOMPARE(obj->property(property), value);
-
- delete obj;
}
void tst_qqmllocale::addCurrencySymbolData(const QString &l)
@@ -233,7 +246,7 @@ void tst_qqmllocale::currencySymbol()
QQmlComponent c(&engine, testFileUrl("functions.qml"));
- QObject *obj = c.create();
+ QScopedPointer<QObject> obj(c.create());
QVERIFY(obj);
QLocale l(locale);
@@ -243,16 +256,14 @@ void tst_qqmllocale::currencySymbol()
if (param >= 0)
format = QLocale::CurrencySymbolFormat(param);
- QMetaObject::invokeMethod(obj, "setLocale", Qt::DirectConnection,
+ QMetaObject::invokeMethod(obj.data(), "setLocale", Qt::DirectConnection,
Q_ARG(QVariant, QVariant(locale)));
- QMetaObject::invokeMethod(obj, "currencySymbol", Qt::DirectConnection,
+ QMetaObject::invokeMethod(obj.data(), "currencySymbol", Qt::DirectConnection,
Q_RETURN_ARG(QVariant, val),
Q_ARG(QVariant, QVariant(int(format))));
QCOMPARE(val.toString(), l.currencySymbol(format));
-
- delete obj;
}
void tst_qqmllocale::addFormatNameData(const QString &l)
@@ -293,7 +304,7 @@ void tst_qqmllocale::monthName()
QQmlComponent c(&engine, testFileUrl("functions.qml"));
- QObject *obj = c.create();
+ QScopedPointer<QObject> obj(c.create());
QVERIFY(obj);
QLocale l(locale);
@@ -302,11 +313,11 @@ void tst_qqmllocale::monthName()
if (param >= 0)
format = QLocale::FormatType(param);
- QMetaObject::invokeMethod(obj, "setLocale", Qt::DirectConnection,
+ QMetaObject::invokeMethod(obj.data(), "setLocale", Qt::DirectConnection,
Q_ARG(QVariant, QVariant(locale)));
for (int i = 0; i <= 11; ++i) {
- QMetaObject::invokeMethod(obj, "monthName", Qt::DirectConnection,
+ QMetaObject::invokeMethod(obj.data(), "monthName", Qt::DirectConnection,
Q_RETURN_ARG(QVariant, val),
Q_ARG(QVariant, QVariant(i)),
Q_ARG(QVariant, QVariant(int(format))));
@@ -314,8 +325,6 @@ void tst_qqmllocale::monthName()
// QLocale January == 1, JS Date January == 0
QCOMPARE(val.toString(), l.monthName(i+1, format));
}
-
- delete obj;
}
void tst_qqmllocale::standaloneMonthName_data()
@@ -330,7 +339,7 @@ void tst_qqmllocale::standaloneMonthName()
QQmlComponent c(&engine, testFileUrl("functions.qml"));
- QObject *obj = c.create();
+ QScopedPointer<QObject> obj(c.create());
QVERIFY(obj);
QLocale l(locale);
@@ -339,11 +348,11 @@ void tst_qqmllocale::standaloneMonthName()
if (param >= 0)
format = QLocale::FormatType(param);
- QMetaObject::invokeMethod(obj, "setLocale", Qt::DirectConnection,
+ QMetaObject::invokeMethod(obj.data(), "setLocale", Qt::DirectConnection,
Q_ARG(QVariant, QVariant(locale)));
for (int i = 0; i <= 11; ++i) {
- QMetaObject::invokeMethod(obj, "standaloneMonthName", Qt::DirectConnection,
+ QMetaObject::invokeMethod(obj.data(), "standaloneMonthName", Qt::DirectConnection,
Q_RETURN_ARG(QVariant, val),
Q_ARG(QVariant, QVariant(i)),
Q_ARG(QVariant, QVariant(int(format))));
@@ -351,8 +360,6 @@ void tst_qqmllocale::standaloneMonthName()
// QLocale January == 1, JS Date January == 0
QCOMPARE(val.toString(), l.standaloneMonthName(i+1, format));
}
-
- delete obj;
}
void tst_qqmllocale::dayName_data()
@@ -367,7 +374,7 @@ void tst_qqmllocale::dayName()
QQmlComponent c(&engine, testFileUrl("functions.qml"));
- QObject *obj = c.create();
+ QScopedPointer<QObject> obj(c.create());
QVERIFY(obj);
QLocale l(locale);
@@ -376,19 +383,17 @@ void tst_qqmllocale::dayName()
if (param >= 0)
format = QLocale::FormatType(param);
- QMetaObject::invokeMethod(obj, "setLocale", Qt::DirectConnection,
+ QMetaObject::invokeMethod(obj.data(), "setLocale", Qt::DirectConnection,
Q_ARG(QVariant, QVariant(locale)));
for (int i = 1; i <= 7; ++i) {
- QMetaObject::invokeMethod(obj, "dayName", Qt::DirectConnection,
+ QMetaObject::invokeMethod(obj.data(), "dayName", Qt::DirectConnection,
Q_RETURN_ARG(QVariant, val),
Q_ARG(QVariant, QVariant(i)),
Q_ARG(QVariant, QVariant(int(format))));
QCOMPARE(val.toString(), l.dayName(i, format));
}
-
- delete obj;
}
void tst_qqmllocale::standaloneDayName_data()
@@ -403,26 +408,87 @@ void tst_qqmllocale::standaloneDayName()
QQmlComponent c(&engine, testFileUrl("functions.qml"));
- QObject *obj = c.create();
+ QScopedPointer<QObject> obj(c.create());
QVERIFY(obj);
QLocale l(locale);
QVariant val;
QLocale::FormatType format = param < 0 ? QLocale::LongFormat : QLocale::FormatType(param);
- QMetaObject::invokeMethod(obj, "setLocale", Qt::DirectConnection,
+ QMetaObject::invokeMethod(obj.data(), "setLocale", Qt::DirectConnection,
Q_ARG(QVariant, QVariant(locale)));
for (int i = 1; i <= 7; ++i) {
- QMetaObject::invokeMethod(obj, "standaloneDayName", Qt::DirectConnection,
+ QMetaObject::invokeMethod(obj.data(), "standaloneDayName", Qt::DirectConnection,
Q_RETURN_ARG(QVariant, val),
Q_ARG(QVariant, QVariant(i)),
Q_ARG(QVariant, QVariant(int(format))));
QCOMPARE(val.toString(), l.standaloneDayName(i, format));
}
+}
+
+void tst_qqmllocale::toString_data()
+{
+ addTestFunctionCallDataColumns();
+
+ // Test general error conditions which aren't overload or locale-specific.
+ QString functionCallScript = "locale.toString()";
+ QTest::newRow(qPrintable(functionCallScript)) << "en_AU" << functionCallScript
+ << "QLocale(English, Latin, Australia)" << QString();
+
+ functionCallScript = "locale.toString(1, 2, 3, 4)";
+ QString errorMessage = ".*Locale: toString\\(\\): Expected 1-3 arguments, but received 4";
+ QTest::newRow(qPrintable(functionCallScript)) << "en_AU" << functionCallScript << QString() << errorMessage;
+
+ // Test toString(int).
+ functionCallScript = "locale.toString(123)";
+ QTest::newRow(qPrintable(functionCallScript)) << "de_DE" << functionCallScript << "123" << QString();
+
+ // Test toString(double[, char][, int]).
+ functionCallScript = "locale.toString(123.456)";
+ QTest::newRow(qPrintable(functionCallScript)) << "de_DE" << functionCallScript << "123,456" << QString();
+
+ functionCallScript = "locale.toString(123.456, 'e')";
+ QTest::newRow(qPrintable(functionCallScript)) << "de_DE" << functionCallScript << "1,234560E+02" << QString();
+
+ functionCallScript = "locale.toString(123.456, 'e', 1)";
+ QTest::newRow(qPrintable(functionCallScript)) << "de_DE" << functionCallScript << "1,2E+02" << QString();
+
+ // Test toString(Date, string) and toString(Date[, FormatType]).
+ const QDateTime midnight2000(QDate(2000, 1, 1), QTime(0, 0));
+ // 12 AM might not exist in this timezone (some timezones have transitions at midnight).
+ if (midnight2000.isValid()) {
+ functionCallScript = "locale.toString(new Date(2000, 0, 1))";
+ const QLocale locale("en_AU");
+ QTest::newRow(qPrintable(functionCallScript)) << locale.name() << functionCallScript
+ << locale.toString(midnight2000, QLocale::LongFormat) << QString();
+ }
+
+ functionCallScript = "locale.toString(new Date(2022, 7, 16), [])";
+ errorMessage = ".*Locale: the second argument to the toString overloads whose "
+ "first argument is a Date should be a string or FormatType";
+ QTest::newRow(qPrintable(functionCallScript)) << "ar" << functionCallScript << QString() << errorMessage;
+
+ functionCallScript = "locale.toString([], 'd')";
+ errorMessage = ".*Locale: toString\\(\\) expects either an int, double, or Date as its first argument";
+ QTest::newRow(qPrintable(functionCallScript)) << "ar" << functionCallScript << QString() << errorMessage;
+
+ functionCallScript = "locale.toString(new Date(2022, 7, 16), 'd')";
+ QTest::newRow(qPrintable(functionCallScript)) << "ar" << functionCallScript << "١٦" << QString();
- delete obj;
+ functionCallScript = "locale.toString(new Date(2022, 7, 16), Locale.ShortFormat)";
+ QTest::newRow(qPrintable(functionCallScript))
+ << "en_AU" << functionCallScript << "16/8/22 12:00 am" << QString();
+
+ functionCallScript = "locale.toString(new Date(2022, 7, 16, 1, 23, 4), Locale.ShortFormat)";
+ QTest::newRow(qPrintable(functionCallScript))
+ << "en_AU" << functionCallScript << "16/8/22 1:23 am" << QString();
+}
+
+void tst_qqmllocale::toString()
+{
+ testFunctionCall();
}
void tst_qqmllocale::firstDayOfWeek_data()
@@ -443,10 +509,10 @@ void tst_qqmllocale::firstDayOfWeek()
QQmlComponent c(&engine, testFileUrl("properties.qml"));
- QObject *obj = c.create();
+ QScopedPointer<QObject> obj(c.create());
QVERIFY(obj);
- QMetaObject::invokeMethod(obj, "setLocale", Qt::DirectConnection,
+ QMetaObject::invokeMethod(obj.data(), "setLocale", Qt::DirectConnection,
Q_ARG(QVariant, QVariant(locale)));
QVariant val = obj->property("firstDayOfWeek");
@@ -456,8 +522,6 @@ void tst_qqmllocale::firstDayOfWeek()
if (day == 7) // JS Date days in range 0(Sunday) to 6(Saturday)
day = 0;
QCOMPARE(day, val.toInt());
-
- delete obj;
}
void tst_qqmllocale::weekDays_data()
@@ -478,28 +542,26 @@ void tst_qqmllocale::weekDays()
QQmlComponent c(&engine, testFileUrl("properties.qml"));
- QObject *obj = c.create();
+ QScopedPointer<QObject> obj(c.create());
QVERIFY(obj);
- QMetaObject::invokeMethod(obj, "setLocale", Qt::DirectConnection,
+ QMetaObject::invokeMethod(obj.data(), "setLocale", Qt::DirectConnection,
Q_ARG(QVariant, QVariant(locale)));
QVariant val = obj->property("weekDays");
- QCOMPARE(val.userType(), qMetaTypeId<QJSValue>());
+ QCOMPARE(val.metaType(), QMetaType::fromType<QList<QQmlLocale::DayOfWeek>>());
QList<QVariant> qmlDays = val.toList();
QList<Qt::DayOfWeek> days = QLocale(locale).weekdays();
- QCOMPARE(days.count(), qmlDays.count());
+ QCOMPARE(days.size(), qmlDays.size());
- for (int i = 0; i < days.count(); ++i) {
+ for (int i = 0; i < days.size(); ++i) {
int day = int(days.at(i));
if (day == 7) // JS Date days in range 0(Sunday) to 6(Saturday)
day = 0;
QCOMPARE(day, qmlDays.at(i).toInt());
}
-
- delete obj;
}
void tst_qqmllocale::uiLanguages_data()
@@ -520,25 +582,23 @@ void tst_qqmllocale::uiLanguages()
QQmlComponent c(&engine, testFileUrl("properties.qml"));
- QObject *obj = c.create();
+ QScopedPointer<QObject> obj(c.create());
QVERIFY(obj);
- QMetaObject::invokeMethod(obj, "setLocale", Qt::DirectConnection,
+ QMetaObject::invokeMethod(obj.data(), "setLocale", Qt::DirectConnection,
Q_ARG(QVariant, QVariant(locale)));
QVariant val = obj->property("uiLanguages");
- QCOMPARE(val.userType(), qMetaTypeId<QJSValue>());
+ QCOMPARE(val.metaType(), QMetaType::fromType<QStringList>());
QList<QVariant> qmlLangs = val.toList();
QStringList langs = QLocale(locale).uiLanguages();
- QCOMPARE(langs.count(), qmlLangs.count());
+ QCOMPARE(langs.size(), qmlLangs.size());
- for (int i = 0; i < langs.count(); ++i) {
+ for (int i = 0; i < langs.size(); ++i) {
QCOMPARE(langs.at(i), qmlLangs.at(i).toString());
}
-
- delete obj;
}
@@ -554,17 +614,17 @@ void tst_qqmllocale::dateTimeFormat()
QQmlComponent c(&engine, testFileUrl("functions.qml"));
- QObject *obj = c.create();
+ QScopedPointer<QObject> obj(c.create());
QVERIFY(obj);
QLocale l(locale);
QVariant val;
- QMetaObject::invokeMethod(obj, "setLocale", Qt::DirectConnection,
+ QMetaObject::invokeMethod(obj.data(), "setLocale", Qt::DirectConnection,
Q_ARG(QVariant, QVariant(locale)));
QLocale::FormatType format = param < 0 ? QLocale::LongFormat : QLocale::FormatType(param);
- QMetaObject::invokeMethod(obj, "dateTimeFormat", Qt::DirectConnection,
+ QMetaObject::invokeMethod(obj.data(), "dateTimeFormat", Qt::DirectConnection,
Q_RETURN_ARG(QVariant, val),
Q_ARG(QVariant, QVariant(param)));
@@ -583,17 +643,17 @@ void tst_qqmllocale::dateFormat()
QQmlComponent c(&engine, testFileUrl("functions.qml"));
- QObject *obj = c.create();
+ QScopedPointer<QObject> obj(c.create());
QVERIFY(obj);
QLocale l(locale);
QVariant val;
- QMetaObject::invokeMethod(obj, "setLocale", Qt::DirectConnection,
+ QMetaObject::invokeMethod(obj.data(), "setLocale", Qt::DirectConnection,
Q_ARG(QVariant, QVariant(locale)));
QLocale::FormatType format = param < 0 ? QLocale::LongFormat : QLocale::FormatType(param);
- QMetaObject::invokeMethod(obj, "dateFormat", Qt::DirectConnection,
+ QMetaObject::invokeMethod(obj.data(), "dateFormat", Qt::DirectConnection,
Q_RETURN_ARG(QVariant, val),
Q_ARG(QVariant, QVariant(param)));
@@ -612,23 +672,167 @@ void tst_qqmllocale::timeFormat()
QQmlComponent c(&engine, testFileUrl("functions.qml"));
- QObject *obj = c.create();
+ QScopedPointer<QObject> obj(c.create());
QVERIFY(obj);
QLocale l(locale);
QVariant val;
- QMetaObject::invokeMethod(obj, "setLocale", Qt::DirectConnection,
+ QMetaObject::invokeMethod(obj.data(), "setLocale", Qt::DirectConnection,
Q_ARG(QVariant, QVariant(locale)));
QLocale::FormatType format = param < 0 ? QLocale::LongFormat : QLocale::FormatType(param);
- QMetaObject::invokeMethod(obj, "timeFormat", Qt::DirectConnection,
+ QMetaObject::invokeMethod(obj.data(), "timeFormat", Qt::DirectConnection,
Q_RETURN_ARG(QVariant, val),
Q_ARG(QVariant, QVariant(param)));
QCOMPARE(val.toString(), l.timeFormat(format));
}
+void tst_qqmllocale::addFormattedDataSizeDataForLocale(const QString &localeStr)
+{
+ const QByteArray localeByteArray = localeStr.toLatin1();
+ QString functionCallScript;
+ QString expectedResult;
+ QString expectedErrorMessage;
+
+ const QLocale locale(localeStr);
+
+ const auto makeTag = [&](){
+ QRegularExpression argRegex("formattedDataSize\\((.*)\\)");
+ QString tag = functionCallScript;
+ const auto match = argRegex.match(functionCallScript);
+ if (match.hasMatch())
+ tag = match.captured(1);
+ return localeStr + QLatin1String(", ") + tag;
+ };
+
+ functionCallScript = QLatin1String("locale.formattedDataSize(1000000)");
+ expectedResult = locale.formattedDataSize(1000000);
+ QTest::newRow(qPrintable(makeTag())) << localeStr << functionCallScript << expectedResult << expectedErrorMessage;
+
+ functionCallScript = QLatin1String("locale.formattedDataSize(1000000, 3)");
+ expectedResult = locale.formattedDataSize(1000000, 3);
+ QTest::newRow(qPrintable(makeTag())) << localeStr << functionCallScript << expectedResult << expectedErrorMessage;
+
+ functionCallScript = QLatin1String("locale.formattedDataSize(1000000, 3, Locale.DataSizeIecFormat)");
+ expectedResult = locale.formattedDataSize(1000000, 3, QLocale::DataSizeIecFormat);
+ QTest::newRow(qPrintable(makeTag())) << localeStr << functionCallScript << expectedResult << expectedErrorMessage;
+
+ functionCallScript = QLatin1String("locale.formattedDataSize(1000000, 3, Locale.DataSizeTraditionalFormat)");
+ expectedResult = locale.formattedDataSize(1000000, 3, QLocale::DataSizeTraditionalFormat);
+ QTest::newRow(qPrintable(makeTag())) << localeStr << functionCallScript << expectedResult << expectedErrorMessage;
+
+ functionCallScript = QLatin1String("locale.formattedDataSize(1000000, 3, Locale.DataSizeSIFormat)");
+ expectedResult = locale.formattedDataSize(1000000, 3, QLocale::DataSizeSIFormat);
+ QTest::newRow(qPrintable(makeTag())) << localeStr << functionCallScript << expectedResult << expectedErrorMessage;
+}
+
+#define STOP_ON_FAILURE \
+ if (QTest::currentTestFailed()) \
+ return;
+
+/*!
+ To simplify the tests, this function calls a function and checks the
+ return value (a string). If it's expected that it fails, it checks
+ that the expected error message was printed.
+*/
+void tst_qqmllocale::testFunctionCall()
+{
+ QFETCH(QString, localeStr);
+ QFETCH(QString, functionCallScript);
+ QFETCH(QString, expectedResult);
+ QFETCH(QString, expectedErrorMessagePattern);
+
+ QQmlComponent component(&engine, testFileUrl("functions.qml"));
+ QVERIFY2(component.isReady(), qPrintable(component.errorString()));
+ STOP_ON_FAILURE
+
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object);
+ STOP_ON_FAILURE
+
+ QLocale locale(localeStr);
+ QVariant returnValue;
+
+ QVERIFY(QMetaObject::invokeMethod(object.data(), "setLocale", Qt::DirectConnection,
+ Q_ARG(QVariant, QVariant(localeStr))));
+ STOP_ON_FAILURE
+
+ // Make sure that we use the object's context rather than the root context,
+ // so that e.g. enums from the Locale type are available (QTBUG-91747).
+ QQmlExpression qmlExpression(qmlContext(object.data()), object.data(), functionCallScript);
+ const QVariant evaluationResult = qmlExpression.evaluate();
+ if (expectedErrorMessagePattern.isEmpty()) {
+ QVERIFY2(!qmlExpression.hasError(), qPrintable(qmlExpression.error().toString()));
+ STOP_ON_FAILURE
+ QVERIFY(evaluationResult.canConvert<QString>());
+ STOP_ON_FAILURE
+
+ // We're not interested in whether the spaces in the date/time format
+ // are breaking or non-breaking.
+ const QString resultWithBreakingSpaces
+ = evaluationResult.toString().replace(u'\u202f', u' ');
+ const QString expectedWithBreakingSpaces
+ = expectedResult.replace(u'\u202f', u' ');
+
+ QCOMPARE(resultWithBreakingSpaces, expectedWithBreakingSpaces);
+ STOP_ON_FAILURE
+ } else {
+ QVERIFY(qmlExpression.hasError());
+ STOP_ON_FAILURE
+ QRegularExpression errorRegex(expectedErrorMessagePattern);
+ QVERIFY(errorRegex.isValid());
+ STOP_ON_FAILURE
+ QVERIFY2(errorRegex.match(qmlExpression.error().toString()).hasMatch(),
+ qPrintable(QString::fromLatin1("Mismatch in actual vs expected error message:\n Actual: %1\n Expected: %2")
+ .arg(qmlExpression.error().toString()).arg(expectedErrorMessagePattern)));
+ STOP_ON_FAILURE
+ }
+}
+
+void tst_qqmllocale::addTestFunctionCallDataColumns()
+{
+ QTest::addColumn<QString>("localeStr");
+ QTest::addColumn<QString>("functionCallScript");
+ QTest::addColumn<QString>("expectedResult");
+ QTest::addColumn<QString>("expectedErrorMessagePattern");
+}
+
+void tst_qqmllocale::formattedDataSize_data()
+{
+ addTestFunctionCallDataColumns();
+
+ addFormattedDataSizeDataForLocale("en_US");
+ addFormattedDataSizeDataForLocale("de_DE");
+ addFormattedDataSizeDataForLocale("ar_SA");
+ addFormattedDataSizeDataForLocale("hi_IN");
+ addFormattedDataSizeDataForLocale("zh_CN");
+ addFormattedDataSizeDataForLocale("th_TH");
+
+ // Test error conditions (which aren't locale-specific).
+ QString functionCallScript = "locale.formattedDataSize()";
+ QString errorMessage = ".*Locale: formattedDataSize\\(\\): Expected 1-3 arguments, but received 0";
+ QTest::newRow("too few args") << "en_AU" << functionCallScript << QString() << errorMessage;
+
+ functionCallScript = "locale.formattedDataSize(10, 1, Locale.DataSizeIecFormat, \"foo\")";
+ errorMessage = ".*Locale: formattedDataSize\\(\\): Expected 1-3 arguments, but received 4";
+ QTest::newRow("too many args") << "en_AU" << functionCallScript << QString() << errorMessage;
+
+ functionCallScript = "locale.formattedDataSize(10, \"no\")";
+ errorMessage = ".*Locale: formattedDataSize\\(\\): Invalid argument \\('precision' must be an int\\)";
+ QTest::newRow("precision wrong type") << "en_AU" << functionCallScript << QString() << errorMessage;
+
+ functionCallScript = "locale.formattedDataSize(10, 1, \"no\")";
+ errorMessage = ".*Locale: formattedDataSize\\(\\): Invalid argument \\('format' must be DataSizeFormat\\)";
+ QTest::newRow("format wrong type") << "en_AU" << functionCallScript << QString() << errorMessage;
+}
+
+void tst_qqmllocale::formattedDataSize()
+{
+ testFunctionCall();
+}
+
void tst_qqmllocale::dateToLocaleString_data()
{
addStandardFormatData();
@@ -641,18 +845,18 @@ void tst_qqmllocale::dateToLocaleString()
QQmlComponent c(&engine, testFileUrl("date.qml"));
- QObject *obj = c.create();
+ QScopedPointer<QObject> obj(c.create());
QVERIFY(obj);
const QDateTime dt(QDate(2011, 10, 7), QTime(18, 53, 48, 345));
- QMetaObject::invokeMethod(obj, "setLocale", Qt::DirectConnection,
+ QMetaObject::invokeMethod(obj.data(), "setLocale", Qt::DirectConnection,
Q_ARG(QVariant, QVariant(locale)));
QLocale::FormatType format = param < 0 ? QLocale::LongFormat : QLocale::FormatType(param);
QVariant val;
- QMetaObject::invokeMethod(obj, "toLocaleString", Qt::DirectConnection,
+ QMetaObject::invokeMethod(obj.data(), "toLocaleString", Qt::DirectConnection,
Q_RETURN_ARG(QVariant, val),
Q_ARG(QVariant, QVariant(param)));
@@ -700,16 +904,16 @@ void tst_qqmllocale::dateToLocaleStringFormatted()
QQmlComponent c(&engine, testFileUrl("date.qml"));
- QObject *obj = c.create();
+ QScopedPointer<QObject> obj(c.create());
QVERIFY(obj);
const QDateTime dt(QDate(2011, 10, 7), QTime(18, 53, 48, 345));
- QMetaObject::invokeMethod(obj, "setLocale", Qt::DirectConnection,
+ QMetaObject::invokeMethod(obj.data(), "setLocale", Qt::DirectConnection,
Q_ARG(QVariant, QVariant(locale)));
QVariant val;
- QMetaObject::invokeMethod(obj, "toLocaleString", Qt::DirectConnection,
+ QMetaObject::invokeMethod(obj.data(), "toLocaleString", Qt::DirectConnection,
Q_RETURN_ARG(QVariant, val),
Q_ARG(QVariant, QVariant(format)));
@@ -729,18 +933,18 @@ void tst_qqmllocale::dateToLocaleDateString()
QQmlComponent c(&engine, testFileUrl("date.qml"));
- QObject *obj = c.create();
+ QScopedPointer<QObject> obj(c.create());
QVERIFY(obj);
const QDateTime dt(QDate(2011, 10, 7), QTime(18, 53, 48, 345));
- QMetaObject::invokeMethod(obj, "setLocale", Qt::DirectConnection,
+ QMetaObject::invokeMethod(obj.data(), "setLocale", Qt::DirectConnection,
Q_ARG(QVariant, QVariant(locale)));
QLocale::FormatType format = param < 0 ? QLocale::LongFormat : QLocale::FormatType(param);
QVariant val;
- QMetaObject::invokeMethod(obj, "toLocaleDateString", Qt::DirectConnection,
+ QMetaObject::invokeMethod(obj.data(), "toLocaleDateString", Qt::DirectConnection,
Q_RETURN_ARG(QVariant, val),
Q_ARG(QVariant, QVariant(param)));
@@ -788,16 +992,16 @@ void tst_qqmllocale::dateToLocaleDateStringFormatted()
QQmlComponent c(&engine, testFileUrl("date.qml"));
- QObject *obj = c.create();
+ QScopedPointer<QObject> obj(c.create());
QVERIFY(obj);
const QDateTime dt(QDate(2011, 10, 7), QTime(18, 53, 48, 345));
- QMetaObject::invokeMethod(obj, "setLocale", Qt::DirectConnection,
+ QMetaObject::invokeMethod(obj.data(), "setLocale", Qt::DirectConnection,
Q_ARG(QVariant, QVariant(locale)));
QVariant val;
- QMetaObject::invokeMethod(obj, "toLocaleString", Qt::DirectConnection,
+ QMetaObject::invokeMethod(obj.data(), "toLocaleString", Qt::DirectConnection,
Q_RETURN_ARG(QVariant, val),
Q_ARG(QVariant, QVariant(format)));
@@ -817,18 +1021,18 @@ void tst_qqmllocale::dateToLocaleTimeString()
QQmlComponent c(&engine, testFileUrl("date.qml"));
- QObject *obj = c.create();
+ QScopedPointer<QObject> obj(c.create());
QVERIFY(obj);
const QDateTime dt(QDate(2011, 10, 7), QTime(18, 53, 48, 345));
- QMetaObject::invokeMethod(obj, "setLocale", Qt::DirectConnection,
+ QMetaObject::invokeMethod(obj.data(), "setLocale", Qt::DirectConnection,
Q_ARG(QVariant, QVariant(locale)));
QLocale::FormatType format = param < 0 ? QLocale::LongFormat : QLocale::FormatType(param);
QVariant val;
- QMetaObject::invokeMethod(obj, "toLocaleTimeString", Qt::DirectConnection,
+ QMetaObject::invokeMethod(obj.data(), "toLocaleTimeString", Qt::DirectConnection,
Q_RETURN_ARG(QVariant, val),
Q_ARG(QVariant, QVariant(param)));
@@ -876,16 +1080,16 @@ void tst_qqmllocale::dateToLocaleTimeStringFormatted()
QQmlComponent c(&engine, testFileUrl("date.qml"));
- QObject *obj = c.create();
+ QScopedPointer<QObject> obj(c.create());
QVERIFY(obj);
const QDateTime dt(QDate(2011, 10, 7), QTime(18, 53, 48, 345));
- QMetaObject::invokeMethod(obj, "setLocale", Qt::DirectConnection,
+ QMetaObject::invokeMethod(obj.data(), "setLocale", Qt::DirectConnection,
Q_ARG(QVariant, QVariant(locale)));
QVariant val;
- QMetaObject::invokeMethod(obj, "toLocaleString", Qt::DirectConnection,
+ QMetaObject::invokeMethod(obj.data(), "toLocaleString", Qt::DirectConnection,
Q_RETURN_ARG(QVariant, val),
Q_ARG(QVariant, QVariant(format)));
@@ -916,18 +1120,18 @@ void tst_qqmllocale::dateFromLocaleString()
QQmlComponent c(&engine, testFileUrl("date.qml"));
- QObject *obj = c.create();
+ QScopedPointer<QObject> obj(c.create());
QVERIFY(obj);
const QDateTime dt(QDate(2011, 10, 7), QTime(18, 53, 48, 345));
- QMetaObject::invokeMethod(obj, "setLocale", Qt::DirectConnection,
+ QMetaObject::invokeMethod(obj.data(), "setLocale", Qt::DirectConnection,
Q_ARG(QVariant, QVariant(locale)));
QLocale l(locale);
const QString localeText(l.toString(dt, format));
QVariant val;
- QMetaObject::invokeMethod(obj, "fromLocaleString", Qt::DirectConnection,
+ QMetaObject::invokeMethod(obj.data(), "fromLocaleString", Qt::DirectConnection,
Q_RETURN_ARG(QVariant, val),
Q_ARG(QVariant, QVariant(localeText)),
Q_ARG(QVariant, QVariant(format)));
@@ -959,18 +1163,18 @@ void tst_qqmllocale::dateFromLocaleDateString()
QQmlComponent c(&engine, testFileUrl("date.qml"));
- QObject *obj = c.create();
+ QScopedPointer<QObject> obj(c.create());
QVERIFY(obj);
const QDateTime dt(QDate(2011, 10, 7), QTime(18, 53, 48, 345));
- QMetaObject::invokeMethod(obj, "setLocale", Qt::DirectConnection,
+ QMetaObject::invokeMethod(obj.data(), "setLocale", Qt::DirectConnection,
Q_ARG(QVariant, QVariant(locale)));
QLocale l(locale);
const QString localeText(l.toString(dt, format));
QVariant val;
- QMetaObject::invokeMethod(obj, "fromLocaleDateString", Qt::DirectConnection,
+ QMetaObject::invokeMethod(obj.data(), "fromLocaleDateString", Qt::DirectConnection,
Q_RETURN_ARG(QVariant, val),
Q_ARG(QVariant, QVariant(localeText)),
Q_ARG(QVariant, QVariant(format)));
@@ -1002,18 +1206,18 @@ void tst_qqmllocale::dateFromLocaleTimeString()
QQmlComponent c(&engine, testFileUrl("date.qml"));
- QObject *obj = c.create();
+ QScopedPointer<QObject> obj(c.create());
QVERIFY(obj);
const QDateTime dt(QDate(2011, 10, 7), QTime(18, 53, 48, 345));
- QMetaObject::invokeMethod(obj, "setLocale", Qt::DirectConnection,
+ QMetaObject::invokeMethod(obj.data(), "setLocale", Qt::DirectConnection,
Q_ARG(QVariant, QVariant(locale)));
QLocale l(locale);
const QString localeText(l.toString(dt, format));
QVariant val;
- QMetaObject::invokeMethod(obj, "fromLocaleTimeString", Qt::DirectConnection,
+ QMetaObject::invokeMethod(obj.data(), "fromLocaleTimeString", Qt::DirectConnection,
Q_RETURN_ARG(QVariant, val),
Q_ARG(QVariant, QVariant(localeText)),
Q_ARG(QVariant, QVariant(format)));
@@ -1046,17 +1250,17 @@ void tst_qqmllocale::numberToLocaleString()
QQmlComponent c(&engine, testFileUrl("number.qml"));
- QObject *obj = c.create();
+ QScopedPointer<QObject> obj(c.create());
QVERIFY(obj);
double number = 2344423.3289;
- QMetaObject::invokeMethod(obj, "setLocale", Qt::DirectConnection,
+ QMetaObject::invokeMethod(obj.data(), "setLocale", Qt::DirectConnection,
Q_ARG(QVariant, QVariant(locale)));
QLocale l(locale);
QVariant val;
- QMetaObject::invokeMethod(obj, "toLocaleString", Qt::DirectConnection,
+ QMetaObject::invokeMethod(obj.data(), "toLocaleString", Qt::DirectConnection,
Q_RETURN_ARG(QVariant, val),
Q_ARG(QVariant, QVariant(number)),
Q_ARG(QVariant, QVariant(QString(format))),
@@ -1087,17 +1291,17 @@ void tst_qqmllocale::numberToLocaleCurrencyString()
QQmlComponent c(&engine, testFileUrl("number.qml"));
- QObject *obj = c.create();
+ QScopedPointer<QObject> obj(c.create());
QVERIFY(obj);
double number = 2344423.3289;
- QMetaObject::invokeMethod(obj, "setLocale", Qt::DirectConnection,
+ QMetaObject::invokeMethod(obj.data(), "setLocale", Qt::DirectConnection,
Q_ARG(QVariant, QVariant(locale)));
QLocale l(locale);
QVariant val;
- QMetaObject::invokeMethod(obj, "toLocaleCurrencyString", Qt::DirectConnection,
+ QMetaObject::invokeMethod(obj.data(), "toLocaleCurrencyString", Qt::DirectConnection,
Q_RETURN_ARG(QVariant, val),
Q_ARG(QVariant, QVariant(number)),
Q_ARG(QVariant, QVariant(symbol)));
@@ -1127,17 +1331,17 @@ void tst_qqmllocale::numberFromLocaleString()
QQmlComponent c(&engine, testFileUrl("number.qml"));
- QObject *obj = c.create();
+ QScopedPointer<QObject> obj(c.create());
QVERIFY(obj);
QLocale l(locale);
QString strNumber = l.toString(number, 'f');
- QMetaObject::invokeMethod(obj, "setLocale", Qt::DirectConnection,
+ QMetaObject::invokeMethod(obj.data(), "setLocale", Qt::DirectConnection,
Q_ARG(QVariant, QVariant(locale)));
QVariant val;
- QMetaObject::invokeMethod(obj, "fromLocaleString", Qt::DirectConnection,
+ QMetaObject::invokeMethod(obj.data(), "fromLocaleString", Qt::DirectConnection,
Q_RETURN_ARG(QVariant, val),
Q_ARG(QVariant, QVariant(strNumber)));
@@ -1148,10 +1352,10 @@ void tst_qqmllocale::numberConstToLocaleString()
{
QQmlComponent c(&engine, testFileUrl("number.qml"));
- QObject *obj = c.create();
+ QScopedPointer<QObject> obj(c.create());
QVERIFY(obj);
- QMetaObject::invokeMethod(obj, "setLocale", Qt::DirectConnection,
+ QMetaObject::invokeMethod(obj.data(), "setLocale", Qt::DirectConnection,
Q_ARG(QVariant, QVariant("en_US")));
QLocale l("en_US");
@@ -1179,9 +1383,12 @@ void tst_qqmllocale::numberOptions()
}
}
)", QUrl("testdata"));
- QTest::ignoreMessage(QtMsgType::QtWarningMsg, "Error: Locale: Number.fromLocaleString(): Invalid format");
+ QTest::ignoreMessage(QtMsgType::QtWarningMsg,
+ "Error: Locale: Number.fromLocaleString(): Invalid format");
QScopedPointer<QObject> root {comp.create()};
- qDebug() << comp.errorString();
+ const auto error = comp.errorString();
+ if (!error.isEmpty())
+ qDebug() << error;
QVERIFY(root);
QCOMPARE(root->property("formatted").toString(), QLatin1String("10000,0000"));
QCOMPARE(root->property("caughtException").toBool(), true);
@@ -1217,7 +1424,7 @@ void tst_qqmllocale::stringLocaleCompare()
QQmlComponent c(&engine, testFileUrl("localeCompare.qml"));
- QObject *obj = c.create();
+ QScopedPointer<QObject> obj(c.create());
QVERIFY(obj);
obj->setProperty("string1", string1);
@@ -1252,7 +1459,8 @@ void tst_qqmllocale::localeAsCppProperty()
QVERIFY2(!component.isError(), qPrintable(component.errorString()));
QTRY_VERIFY(component.isReady());
- Calendar *item = qobject_cast<Calendar*>(component.create());
+ QScopedPointer<QObject> obj(component.create());
+ Calendar *item = qobject_cast<Calendar *>(obj.data());
QCOMPARE(item->property("locale").toLocale().name(), QLatin1String("en_GB"));
QVariant localeVariant(QLocale("nb_NO"));
@@ -1260,6 +1468,7 @@ void tst_qqmllocale::localeAsCppProperty()
QCOMPARE(item->property("testLocale").toLocale().name(), QLatin1String("nb_NO"));
}
+#ifdef QT_CAN_CHANGE_SYSTEM_ZONE
class DateFormatter : public QObject
{
Q_OBJECT
@@ -1276,49 +1485,21 @@ QString DateFormatter::getLocalizedForm(const QString &isoTimestamp)
return locale.toString(input);
}
-#if defined(Q_OS_UNIX) && QT_CONFIG(timezone)
-// Currently disabled on Windows as adjusting the timezone
-// requires additional privileges that aren't normally
-// enabled for a process. This can be achieved by calling
-// AdjustTokenPrivileges() and then SetTimeZoneInformation(),
-// which will require linking to a different library to access that API.
-static void setTimeZone(const QByteArray &tz)
-{
- if (tz.isEmpty())
- qunsetenv("TZ");
- else
- qputenv("TZ", tz);
- ::tzset();
-
-// following left for future reference, see comment above
-// #if defined(Q_OS_WIN32)
-// ::_tzset();
-// #endif
-}
-
void tst_qqmllocale::timeZoneUpdated()
{
- // Note: This test may not reliably hit the QEXPECT_FAIL clauses below if the initial
- // system time zone is equivalent to either Australia/Brisbane or Asia/Kalkota.
-
- // Initialize the system time zone, so that we actually _change_ something below.
- QVERIFY2(QTimeZone::systemTimeZone().isValid(),
- "You know, Toto, I do believe we're not in Kansas any more.");
-
QByteArray original(qgetenv("TZ"));
-
- // Set the timezone to Brisbane time, AEST-10:00
- setTimeZone(QByteArray("Australia/Brisbane"));
-
QScopedPointer<QObject> obj;
+
auto cleanup = qScopeGuard([&original, &obj] {
// Restore to original time zone
setTimeZone(original);
QMetaObject::invokeMethod(obj.data(), "resetTimeZone");
});
- DateFormatter formatter;
+ // Set the timezone to Brisbane time, AEST-10:00
+ setTimeZone(QByteArray("Australia/Brisbane"));
+ DateFormatter formatter;
QQmlEngine e;
e.rootContext()->setContextObject(&formatter);
@@ -1326,27 +1507,15 @@ void tst_qqmllocale::timeZoneUpdated()
QVERIFY2(!c.isError(), qPrintable(c.errorString()));
obj.reset(c.create());
QVERIFY(obj);
-
-#if !defined(Q_OS_LINUX) || defined(Q_OS_ANDROID)
- QEXPECT_FAIL("",
- "Date.timeZoneUpdated() only works on non-Android Linux with QT_CONFIG(timezone).",
- Continue);
-#endif
QVERIFY(obj->property("success").toBool());
// Change to Indian time, IST-05:30
setTimeZone(QByteArray("Asia/Kolkata"));
QMetaObject::invokeMethod(obj.data(), "check");
-
-#if !defined(Q_OS_LINUX) || defined(Q_OS_ANDROID)
- QEXPECT_FAIL("",
- "Date.timeZoneUpdated() only works on non-Android Linux with QT_CONFIG(timezone).",
- Continue);
-#endif
QVERIFY(obj->property("success").toBool());
}
-#endif // Unix && timezone
+#endif // QT_CAN_CHANGE_SYSTEM_ZONE
QTEST_MAIN(tst_qqmllocale)