Skip to content

Commit

Permalink
QTranslator: rewrite loadLocale test, include failing cases
Browse files Browse the repository at this point in the history
Add test coverage for the bug reported in QTBUG-124898 with
QEXPECT_FAIL to document the failure in our truncation logic in
QTranslator.

The attempted fix in 9a11273 then
introduced QTBUG-129434, as we ignored the order of languages reported
by the system locale. Add a test case for that, and use a QSystemLocale
subclass inspired by the QLocale unit test to override the system locale
with a specific one that supports multiple languages for this test.

Pick-to: 6.8 6.5
Task-number: QTBUG-124898
Task-number: QTBUG-129434
Change-Id: Iaae80d29e267fd3a2d14df0e73db27ba4c58b31a
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
  • Loading branch information
vohi authored and ediosyncratic committed Oct 8, 2024
1 parent 1b3a7d5 commit 1f2ab46
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 27 deletions.
2 changes: 2 additions & 0 deletions tests/auto/corelib/kernel/qtranslator/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ endif()
qt_internal_add_test(tst_qtranslator
SOURCES
tst_qtranslator.cpp
LIBRARIES
Qt::CorePrivate
)

# Resources:
Expand Down
140 changes: 113 additions & 27 deletions tests/auto/corelib/kernel/qtranslator/tst_qtranslator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,55 @@
#include <qfile.h>
#include <qtemporarydir.h>

#include <QtCore/private/qlocale_p.h>

#ifdef Q_OS_ANDROID
#include <QDirIterator>
#endif

#if !defined(QT_NO_SYSTEMLOCALE) && defined(QT_BUILD_INTERNAL)
// from tst_qlocale.cpp; override the system locale with one that supports multiple
// languages
class MySystemLocale : public QSystemLocale
{
Q_DISABLE_COPY_MOVE(MySystemLocale)
public:
MySystemLocale(const QStringList &languages)
: m_languages(languages), m_locale(languages.first())
, m_id(QLocaleId::fromName(languages.first()))
{
}

QVariant query(QueryType type, QVariant &&/*in*/) const override
{
switch (type) {
case UILanguages:
return QVariant(m_languages);
case LanguageId:
return m_id.language_id;
case TerritoryId:
return m_id.territory_id;
case ScriptId:
return m_id.script_id;

default:
break;
}
return QVariant();
}

QLocale fallbackLocale() const override
{
return m_locale;
}

private:
QStringList m_languages;
const QLocale m_locale;
const QLocaleId m_id;
};
#endif // !defined(QT_NO_SYSTEMLOCALE) && defined(QT_BUILD_INTERNAL)

class tst_QTranslator : public QObject
{
Q_OBJECT
Expand All @@ -27,6 +72,7 @@ private slots:

void load_data();
void load();
void loadLocale_data();
void loadLocale();
void threadLoad();
void testLanguageChange();
Expand Down Expand Up @@ -116,12 +162,40 @@ void tst_QTranslator::load()
}
}

void tst_QTranslator::loadLocale_data()
{
QTest::addColumn<QLocale>("wantedLocale");
QTest::addColumn<QStringList>("languages");

// variation of translation files for the same language
QTest::addRow("US English")
<< QLocale("en-US")
<< QStringList{"en-US", "en"};
QTest::addRow("Australia")
<< QLocale("en-AU")
<< QStringList{"en-Latn-AU", "en-AU", "en"};

// This produces a QLocale::uiLanguages list of
// {"en-NO", "en-Latn-NO", "nb-NO", "nb-Latn-NO", "nb",
// "de-DE", "de-Latn-DE", "de", "zh-Hant-NO"}
QTest::addRow("System, mixed languages")
<< QLocale::system()
<< QStringList{"en-NO", "nb-NO", "de-DE", "zh-Hant-NO"};
}

void tst_QTranslator::loadLocale()
{
QLocale locale;
auto localeName = locale.uiLanguages(QLocale::TagSeparator::Underscore).value(0);
if (localeName.isEmpty())
QSKIP("This test requires at least one available UI language.");
QFETCH(const QLocale, wantedLocale);
QFETCH(const QStringList, languages);

#if !defined(QT_NO_SYSTEMLOCALE) && defined(QT_BUILD_INTERNAL)
std::unique_ptr<MySystemLocale> systemLocaleOverride;
if (wantedLocale == QLocale::system())
systemLocaleOverride.reset(new MySystemLocale(languages));
#else
if (wantedLocale == QLocale::system())
QSKIP("Test only applicable in developer builds with system locale");
#endif

QByteArray ba;
{
Expand All @@ -134,36 +208,20 @@ void tst_QTranslator::loadLocale()
QTemporaryDir dir;
QVERIFY(dir.isValid());

auto path = dir.path();
const auto path = dir.path();
QFile file(path + "/dummy");
QVERIFY2(file.open(QFile::WriteOnly), qPrintable(file.errorString()));
QCOMPARE(file.write(ba), ba.size());
file.close();

/*
Test the following order:
/tmp/tmpDir/foo-en_US.qm
/tmp/tmpDir/foo-en_US
/tmp/tmpDir/foo-en.qm
/tmp/tmpDir/foo-en
/tmp/tmpDir/foo.qm
/tmp/tmpDir/foo-
/tmp/tmpDir/foo
*/

QStringList files;
while (true) {
files.append(path + "/foo-" + localeName + ".qm");
for (auto language : languages) {
language.replace('-', '_');
const QString filename = path + "/foo-" + language;
files.append(filename + ".qm");
QVERIFY2(file.copy(files.last()), qPrintable(file.errorString()));

files.append(path + "/foo-" + localeName);
files.append(filename);
QVERIFY2(file.copy(files.last()), qPrintable(file.errorString()));

int rightmost = localeName.lastIndexOf(QLatin1Char('_'));
if (rightmost <= 0)
break;
localeName.truncate(rightmost);
}

files.append(path + "/foo.qm");
Expand All @@ -175,9 +233,37 @@ void tst_QTranslator::loadLocale()
files.append(path + "/foo");
QVERIFY2(file.rename(files.last()), qPrintable(file.errorString()));

// Verify that all files exist. They are removed at the latest when
// the temporary directory is destroyed.
for (const auto &filePath : files)
QVERIFY(QFile::exists(filePath));

const QRegularExpression localeExpr("foo-(.*)(\\.qm|$)");
QTranslator tor;
// Load the translation for the wanted locale
QVERIFY(tor.load(wantedLocale, "foo", "-", path, ".qm"));
// The loaded translation file should be for the preferred language.
const QFileInfo fileInfo(tor.filePath());
const auto matches = localeExpr.match(fileInfo.fileName());
QVERIFY(matches.hasMatch());
QVERIFY(matches.hasCaptured(1));
const QLocale matchedLocale(matches.captured(1));
QCOMPARE(matchedLocale.language(), wantedLocale.language());

// Remove one file at a time, and verify that QTranslator falls back to the
// more general alternatives, or to languages with lower priority.
for (const auto &filePath : files) {
QVERIFY(tor.load(locale, "foo", "-", path, ".qm"));
QVERIFY(tor.load(wantedLocale, "foo", "-", path, ".qm"));
// we search 'en_Latn_US/AU', 'en_Latn', and 'en', but never 'en_US/AU'
if (filePath.endsWith("en_US") || filePath.endsWith("en_US.qm")) {
QEXPECT_FAIL("US English",
"QTBUG-124898 - we search 'en_Latn_US', 'en_Latn', and 'en', but never 'en_US",
Continue);
} else if (filePath.endsWith("en_AU") || filePath.endsWith("en_AU.qm")) {
QEXPECT_FAIL("Australia",
"QTBUG-124898 - we search 'en_Latn_AU', 'en_Latn', and 'en', but never 'en_AU",
Continue);
}
QCOMPARE(tor.filePath(), filePath);
QVERIFY2(file.remove(filePath), qPrintable(file.errorString()));
}
Expand Down

0 comments on commit 1f2ab46

Please sign in to comment.