Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@

#include "../validators/doubleinputvalidator.h"

// Teach GoogleTest how to print QString so failure diffs are readable
// instead of a UTF-16 byte dump.
inline void PrintTo(const QString& s, std::ostream* os)
{
*os << '"' << s.toStdString() << '"';
}

using namespace muse;
using namespace muse::uicomponents;

Expand Down Expand Up @@ -56,8 +63,8 @@ TEST_F(DoubleInputValidatorTests, ValidateDotLocale) {
QLocale prev = QLocale();
QLocale::setDefault(QLocale("en_US"));

m_validator->setTop(100.0);
m_validator->setBottom(-100.0);
m_validator->setTop(1000.0);
m_validator->setBottom(-1000.0);
m_validator->setDecimal(2);

std::vector<Input> inputs = {
Expand All @@ -71,9 +78,11 @@ TEST_F(DoubleInputValidatorTests, ValidateDotLocale) {
{ "00.", QValidator::Intermediate, "0" },
{ "2.00", QValidator::Intermediate, "2" },
{ "2.", QValidator::Intermediate, "2" },
{ "-100.1", QValidator::Intermediate, "-100" },
{ "100.1", QValidator::Intermediate, "100" },
{ "-1000.1", QValidator::Intermediate, "-1,000" },
{ "1000.1", QValidator::Intermediate, "1,000" },
{ "1.123", QValidator::Invalid }, // more than 2 decimal places
{ "1000", QValidator::Acceptable, "1,000" },
{ "10000", QValidator::Invalid }, // more than top
{ "abc", QValidator::Invalid },
{ "", QValidator::Intermediate, "0" }
};
Expand Down Expand Up @@ -109,8 +118,8 @@ TEST_F(DoubleInputValidatorTests, ValidateCommaLocale) {
QLocale prev = QLocale();
QLocale::setDefault(QLocale("ro_RO"));

m_validator->setTop(100.0);
m_validator->setBottom(-100.0);
m_validator->setTop(1000.0);
m_validator->setBottom(-1000.0);
m_validator->setDecimal(2);

std::vector<Input> inputs = {
Expand All @@ -124,8 +133,8 @@ TEST_F(DoubleInputValidatorTests, ValidateCommaLocale) {
{ "00,", QValidator::Intermediate, "0" },
{ "2,00", QValidator::Intermediate, "2" },
{ "2,", QValidator::Intermediate, "2" },
{ "-100,1", QValidator::Intermediate, "-100" },
{ "100,1", QValidator::Intermediate, "100" },
{ "-1000,1", QValidator::Intermediate, "-1.000" },
{ "1000,1", QValidator::Intermediate, "1.000" },
{ "1,123", QValidator::Invalid }, // more than 2 decimal places
{ "abc", QValidator::Invalid },
{ "", QValidator::Intermediate, "0" }
Expand All @@ -149,4 +158,52 @@ TEST_F(DoubleInputValidatorTests, ValidateCommaLocale) {
// Restore previous locale
QLocale::setDefault(prev);
}

TEST_F(DoubleInputValidatorTests, ValidateSmallRange) {
struct Input
{
QString str;
QValidator::State expectedState;
QString fixedStr = {};
};

QLocale prev = QLocale();
QLocale::setDefault(QLocale("en_US"));

m_validator->setTop(1.0);
m_validator->setBottom(0.0);
m_validator->setDecimal(2);

std::vector<Input> inputs = {
{ "0", QValidator::Acceptable },
{ "1", QValidator::Acceptable },
{ "0.5", QValidator::Acceptable },
{ "0.99", QValidator::Acceptable },
{ "-0.1", QValidator::Intermediate, "0" }, // below bottom, clamp to 0
{ "2", QValidator::Intermediate, "1" }, // above top, clamp to 1
{ "1.", QValidator::Intermediate, "1" },
{ "0.0", QValidator::Intermediate, "0" },
{ "10", QValidator::Invalid }, // too many integer digits
{ "1.123", QValidator::Invalid }, // more than 2 decimal places
{ "abc", QValidator::Invalid },
{ "", QValidator::Intermediate, "0" }
};

int pos = 0;
for (Input& input : inputs) {
EXPECT_EQ(m_validator->validate(input.str, pos), input.expectedState);

if (QValidator::Invalid == input.expectedState) {
continue;
}

QString fixInput = input.str;
m_validator->fixup(fixInput);

QString expectedStr = QValidator::Acceptable == input.expectedState ? input.str : input.fixedStr;
EXPECT_EQ(expectedStr, fixInput);
}

QLocale::setDefault(prev);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,27 @@
#include "doubleinputvalidator.h"
#include "global/realfn.h"

#include <cmath>

using namespace muse::uicomponents;

namespace {
int maxIntegerDigits(qreal top, qreal bottom)
{
const qreal maxAbs = std::max(std::abs(top), std::abs(bottom));
Comment thread
saintmatthieu marked this conversation as resolved.
if (maxAbs < 1.0) {
return 1;
}
int digits = 1;
qreal v = std::floor(maxAbs);
while (v >= 10.0) {
v /= 10.0;
++digits;
}
return digits;
}
}
Comment thread
saintmatthieu marked this conversation as resolved.

DoubleInputValidator::DoubleInputValidator(QObject* parent)
: QValidator(parent)
{
Expand Down Expand Up @@ -72,9 +91,10 @@ void DoubleInputValidator::fixup(QString& string) const
QString intPart = strList.at(0);
QString floatPart = strList.size() > 1 ? strList.at(1) : 0;

if (intPart.contains(QRegularExpression("^0{1,3}$"))) {
const int maxIntDigits = maxIntegerDigits(m_top, m_bottom);
if (intPart.contains(QRegularExpression(QString("^0{1,%1}$").arg(maxIntDigits)))) {
intPart = QString("0");
} else if (intPart.contains(QRegularExpression("^\\-0{0,3}$"))) {
} else if (intPart.contains(QRegularExpression(QString("^\\-0{0,%1}$").arg(maxIntDigits)))) {
intPart = QString("-0");
}
Comment thread
saintmatthieu marked this conversation as resolved.

Expand Down Expand Up @@ -111,10 +131,12 @@ QValidator::State DoubleInputValidator::validate(QString& inputStr, int& cursorP
QValidator::State state = Invalid;

QString decimalSep = QRegularExpression::escape(locale.decimalPoint());
QRegularExpression validRegex(QString("^\\-?\\d{1,3}(" + decimalSep + "\\d{1,%1})?$").arg(m_decimal));
const int maxIntDigits = maxIntegerDigits(m_top, m_bottom);
QRegularExpression validRegex(QString("^\\-?\\d{1,%1}(" + decimalSep + "\\d{1,%2})?$")
.arg(maxIntDigits).arg(m_decimal));

if (inputStr.contains(validRegex)) {
QRegularExpression invalidZeroRegex("^\\-?0{2,3}" + decimalSep); // for '-000,' or '-000.'
QRegularExpression invalidZeroRegex(QString("^\\-?0{2,%1}").arg(std::max(maxIntDigits, 2)) + decimalSep); // e.g. '-000,' or '-000.'
QRegularExpression invalidTrailingZeroRegex("^\\-?\\d+" + decimalSep + "0{1,}$"); // for '1,00' or '1.00'
QRegularExpression invalidTrailingDotRegex("^\\-?\\d+" + decimalSep + "$"); // for '1,' or '1.'

Expand All @@ -128,8 +150,9 @@ QValidator::State DoubleInputValidator::validate(QString& inputStr, int& cursorP
} else {
state = Acceptable;
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
} else if (inputStr.contains(QRegularExpression("^\\-?\\d{0,3}" + decimalSep + "?$"))
|| inputStr.contains(QRegularExpression(QString("^\\-?\\d{0,3}" + decimalSep + "\\d{0,%1}$").arg(m_decimal)))) {
} else if (inputStr.contains(QRegularExpression(QString("^\\-?\\d{0,%1}" + decimalSep + "?$").arg(maxIntDigits)))
|| inputStr.contains(QRegularExpression(QString("^\\-?\\d{0,%1}" + decimalSep
+ "\\d{0,%2}$").arg(maxIntDigits).arg(m_decimal)))) {
state = Intermediate;
} else {
cursorPos = 0;
Expand Down
Loading