Skip to content

Commit

Permalink
added removal of trailing zeros
Browse files Browse the repository at this point in the history
  • Loading branch information
Eism committed Dec 9, 2024
1 parent dc9d0fb commit 1c56d9e
Show file tree
Hide file tree
Showing 4 changed files with 174 additions and 19 deletions.
5 changes: 5 additions & 0 deletions src/framework/uicomponents/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,11 @@ if (MUSE_MODULE_UI_DISABLE_MODALITY)
endif()

set(MODULE_USE_UNITY OFF)

setup_module()

if (MUSE_MODULE_UI_TESTS)
add_subdirectory(tests)
endif()


31 changes: 31 additions & 0 deletions src/framework/uicomponents/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# SPDX-License-Identifier: GPL-3.0-only
# MuseScore-CLA-applies
#
# MuseScore
# Music Composition & Notation
#
# Copyright (C) 2021 MuseScore BVBA and others
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 3 as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.

set(MODULE_TEST muse_uicomponents_tests)

set(MODULE_TEST_SRC
${CMAKE_CURRENT_LIST_DIR}/doubleinputvalidator_tests.cpp
)

set(MODULE_TEST_LINK
muse_uicomponents
)

include(SetupGTest)
100 changes: 100 additions & 0 deletions src/framework/uicomponents/tests/doubleinputvalidator_tests.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*
* SPDX-License-Identifier: GPL-3.0-only
* MuseScore-CLA-applies
*
* MuseScore
* Music Composition & Notation
*
* Copyright (C) 2024 MuseScore BVBA and others
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <gtest/gtest.h>

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

using namespace muse;
using namespace muse::uicomponents;

namespace muse::uicomponents {
class DoubleInputValidatorTests : public ::testing::Test, public QObject
{
public:
void SetUp() override
{
m_validator = new DoubleInputValidator(nullptr);
m_validator->setTop(100.0);
m_validator->setBottom(-100.0);
m_validator->setDecimal(2);
}

void TearDown() override
{
delete m_validator;
}

protected:
DoubleInputValidator* m_validator = nullptr;
};

TEST_F(DoubleInputValidatorTests, Validate_ValidInputs) {
std::vector<QString> validInputs = {
"-0.1",
"0",
"1.23",
"99.99",
"-100",
"2.5"
};

int pos = 0;
for (QString& input : validInputs) {
EXPECT_EQ(m_validator->validate(input, pos), QValidator::Acceptable);

QString fixInput = input;
m_validator->fixup(fixInput);
EXPECT_EQ(input, fixInput);
}
}

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

std::vector<Input> validInputs = {
{ "0.0", QValidator::Intermediate, "0" },
{ "00.", QValidator::Intermediate, "0" },
{ "2.00", QValidator::Intermediate, "2" },
{ "2.", QValidator::Intermediate, "2" },
{ "-100.1", QValidator::Intermediate, "-100" },
{ "100.1", QValidator::Intermediate, "100" },
{ "1.123", QValidator::Intermediate, "1.12" },
{ "abc", QValidator::Invalid, "" }
};

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

if (QValidator::Intermediate == input.expectedState) {
QString fixInput = input.str;
m_validator->fixup(fixInput);
EXPECT_EQ(input.fixedStr, fixInput);
}
}
}
}
57 changes: 38 additions & 19 deletions src/framework/uicomponents/view/validators/doubleinputvalidator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,67 +31,86 @@ DoubleInputValidator::DoubleInputValidator(QObject* parent)

void DoubleInputValidator::fixup(QString& string) const
{
auto zeros = [](int num)->QString {
QString s = QString();
for (int i = 0; i < num; i++) {
s.append("0");
auto removeTrailingZeros = [](QString str)->QString {
QString s = str;

if (!s.contains('.')) {
return s;
}

size_t num = s.size();
for (size_t i = num - 1; i > 0; i--) {
if (s[i] == '0') {
s.remove(i, 1);
} else if (s[i] == '.') {
s.remove(i, 1);
break;
} else {
break;
}
}
return s;
};

if (!string.contains(".")) {
string.append("." + zeros(m_decimal));
}

if (string.startsWith(".")) {
string.prepend("0");
}

if (string.endsWith(".")) {
string.append(zeros(m_decimal));
string.remove(string.size() - 1, 1);
}

QStringList strList = string.split(".", Qt::SkipEmptyParts);

QString intPart = strList.at(0);
QString floatPart = strList.at(1);

if (floatPart.length() < m_decimal) {
floatPart.append(zeros(m_decimal - floatPart.length()));
}
QString floatPart = strList.size() > 1 ? strList.at(1) : 0;

if (intPart.contains(QRegularExpression("^0{1,3}$"))) {
intPart = QString("0");
} else if (intPart.contains(QRegularExpression("^\\-0{0,3}$"))) {
intPart = QString("-0");
}

if (intPart == QString("-0") && floatPart == zeros(m_decimal)) {
if (intPart == QString("-0") && floatPart.isEmpty()) {
intPart = QString("0");
}

if (floatPart.size() > m_decimal) {
floatPart = floatPart.remove(m_decimal, floatPart.size() - m_decimal);
}

string = QString("%1.%2").arg(intPart).arg(floatPart);

if (string.toDouble() > m_top) {
string = QString::number(m_top, 'f', m_decimal);
} else if (string.toDouble() < m_bottom) {
string = QString::number(m_bottom, 'f', m_decimal);
}

string = removeTrailingZeros(string);
}

QValidator::State DoubleInputValidator::validate(QString& inputStr, int& cursorPos) const
{
QValidator::State state = Invalid;

if (inputStr.contains(QRegularExpression(QString("^\\-?\\d{1,3}\\.\\d{%1}$").arg(m_decimal)))) {
if (inputStr.contains(QRegularExpression("^\\-?0{2,3}\\."))
|| (inputStr.startsWith("-") && muse::RealIsNull(inputStr.toDouble()))) {
static const QRegularExpression validRegex(QString("^\\-?\\d{1,3}(\\.\\d{1,%1})?$").arg(m_decimal));

if (inputStr.contains(validRegex)) {
static const QRegularExpression invalidZeroRegex("^\\-?0{2,3}\\."); // for '-000.'
static const QRegularExpression invalidTrailingZeroRegex("^\\-?\\d+\\.0{1,}$"); // for '1.00'
static const QRegularExpression invalidTrailingDotRegex("^\\-?\\d+\\.$"); // for '1.'

if (inputStr.contains(invalidZeroRegex)
|| (inputStr.startsWith("-") && muse::RealIsNull(inputStr.toDouble())) // for "-000"
|| inputStr.contains(invalidTrailingZeroRegex)
|| inputStr.contains(invalidTrailingDotRegex)) {
state = Intermediate;
} else {
state = Acceptable;
}
} else if (inputStr.contains(QRegularExpression("^\\-?\\d{0,3}\\.?$"))
|| inputStr.contains(QRegularExpression(QString("^\\-?\\d{0,3}\\.\\d{0,%1}$").arg(m_decimal)))) {
|| inputStr.contains(QRegularExpression(QString("^\\-?\\d{0,3}\\.\\d{%1,}$").arg(m_decimal)))) {
state = Intermediate;
} else {
cursorPos = 0;
Expand Down

0 comments on commit 1c56d9e

Please sign in to comment.