keepassxc icon indicating copy to clipboard operation
keepassxc copied to clipboard

TestEntryModel fails with C locale

Open phoerious opened this issue 1 year ago • 5 comments

Have you searched for an existing issue?

  • [x] Yes, I tried searching and reviewed the pinned issues

Brief Summary

TestEntryModel fails in this line under the C locale:

https://github.com/keepassxreboot/keepassxc/blob/33a379607466bc80c75724d3990e1ba88ae35130/tests/TestEntryModel.cpp#L228

Steps to Reproduce

  1. export LC_ALL=C
  2. ./tests/testentrymodel

Expected Versus Actual Behavior

Test fails due to locale-dependent sorting:

FAIL!  : TestEntryModel::testAttributesModel() Compared values are not the same
   Actual   (model->data(model->index(1, 0)).toString()): "Test11"
   Expected (QString("Test2"))                          : "Test2"

KeePassXC Debug Information


Operating System

Linux

Linux Desktop Environment

None

Linux Windowing System

None

phoerious avatar Mar 04 '25 00:03 phoerious

Most likely cause: https://github.com/keepassxreboot/keepassxc/pull/10091

droidmonkey avatar Mar 04 '25 00:03 droidmonkey

Could probably be fixed with something similar to what was done here: https://github.com/keepassxreboot/keepassxc/pull/7780/files

apteryks avatar Mar 05 '25 07:03 apteryks

Setting LC_ALL instead of LANG as mentioned above works for me.

sebastianlipponer avatar Mar 20 '25 18:03 sebastianlipponer

It does need to be LC_ALL as that overrides other LC_* variables.

I have LC_COLLATE=C.UTF-8 in my default environment, and making that one change to tests/CMakeLists.txt is enough to avoid the failure.

dsalt avatar May 26 '25 03:05 dsalt

The root of the problem is that QCollator's numeric sorting mode doesn't work in the C locale. (glibc here.)

Is this sorting actually required or is it cosmetic?

If required, it seems to me that the proper fix is to test if the EntryAttributesModel collator is using C locale and, if so, change its locale. Otherwise it's to set LC_ALL instead of LANG for testing.

I tested the numeric sorting with this program:

#include <QString>
#include <QCollator>
#include <QLoggingCategory>

static void doTest(QList<QString>& list, QLocale::Language lang)
{
  QCollator collator(lang);

  qInfo() << Qt::endl << "Testing non-numeric" << lang;
  collator.setNumericMode(false);
  std::sort(list.begin(), list.end(), collator);
  for (auto i = list.begin(); i != list.end(); ++i)
    qInfo() << *i;
  qInfo() << (list[2] == "Test11" ? "- Fail" : "+ Pass");

  qInfo() << Qt::endl << "Testing numeric" << lang;
  collator.setNumericMode(true);
  std::sort(list.begin(), list.end(), collator);
  for (auto i = list.begin(); i != list.end(); ++i)
    qInfo() << *i;
  qInfo() << (list[2] == "Test2" ? "- Fail" : "+ Pass");
}

int main()
{
  QList<QString> list;
  list.append("Test1");
  list.append("Test11");
  list.append("Test2");

  doTest(list, QLocale::C);
  doTest(list, QLocale::English);
  doTest(list, QLocale::AnyLanguage);
}

Saved here as t.cpp and run using:

g++ t.cpp -o t $(pkg-config --cflags --libs Qt5Core) -fPIC && ./t

Output will be pass, fail, pass, pass, pass then either pass or fail depending on locale settings (LC_ALL, falling back on LANG, but ignoring LC_COLLATE).

dsalt avatar May 26 '25 14:05 dsalt