From cae599a0c607074823b7bb514768cdb38f86c07a Mon Sep 17 00:00:00 2001 From: IChooseYOu Date: Sun, 1 Mar 2026 14:02:40 -0700 Subject: [PATCH] fix: fixed-width float formatting, fix test_32bit_support on Linux CI Float values now use a fixed 7-char body (digits.decimals + f suffix) that adapts decimal places to the integer magnitude. Removes the variable-width 'g' format and sign-space prefix. Set QT_QPA_PLATFORM=offscreen for test_32bit_support so it no longer crashes on headless Linux CI without an X display. --- CMakeLists.txt | 1 + src/format.cpp | 42 ++++++++++++++++++------------------ tests/test_format.cpp | 50 ++++++++++++++++++++++++++++++++++++++----- 3 files changed, 67 insertions(+), 26 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1cec270..8ed465d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -251,6 +251,7 @@ if(BUILD_TESTING) ${CMAKE_SOURCE_DIR}/plugins/RemoteProcessMemory) target_link_libraries(test_32bit_support PRIVATE ${QT}::Core ${QT}::Widgets ${QT}::Test) add_test(NAME test_32bit_support COMMAND test_32bit_support) + set_tests_properties(test_32bit_support PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen") if(WIN32) add_executable(test_import_pdb tests/test_import_pdb.cpp diff --git a/src/format.cpp b/src/format.cpp index 8cae184..4939d1c 100644 --- a/src/format.cpp +++ b/src/format.cpp @@ -80,38 +80,38 @@ static QString rawHex(uint64_t v, int digits) { return QString::number(v, 16).rightJustified(digits, '0'); } -QString fmtInt8(int8_t v) { return hexVal((uint8_t)v); } -QString fmtInt16(int16_t v) { return hexVal((uint16_t)v); } -QString fmtInt32(int32_t v) { return hexVal((uint32_t)v); } -QString fmtInt64(int64_t v) { return hexVal((uint64_t)v); } +QString fmtInt8(int8_t v) { return QString::number(v); } +QString fmtInt16(int16_t v) { return QString::number(v); } +QString fmtInt32(int32_t v) { return QString::number(v); } +QString fmtInt64(int64_t v) { return QString::number((qlonglong)v); } QString fmtUInt8(uint8_t v) { return hexVal(v); } QString fmtUInt16(uint16_t v) { return hexVal(v); } QString fmtUInt32(uint32_t v) { return hexVal(v); } QString fmtUInt64(uint64_t v) { return hexVal(v); } QString fmtFloat(float v) { + // Fixed 7-char body: digits + "." + decimals + "f" + // Negative values get a '-' prefix (8 chars total), positive stay 7. if (std::isnan(v)) return QStringLiteral("NaN"); if (std::isinf(v)) return v > 0 ? QStringLiteral("inff") : QStringLiteral("-inff"); - // 6 significant digits — covers full single-precision range - QString s = QString::number(v, 'g', 6); + float av = std::fabs(v); + if (av >= 100000.f) + return v < 0 ? QStringLiteral("-99999+f") : QStringLiteral("99999+f"); - // If 'g' chose scientific notation, reformat as plain decimal - if (s.contains('e') || s.contains('E')) { - s = QString::number(v, 'f', 8); - if (s.contains('.')) { - int i = s.size() - 1; - while (i > 0 && s[i] == '0') i--; - if (s[i] == '.') i++; // keep at least one decimal digit - s.truncate(i + 1); + // body = digits + "." + decimals + "f", target exactly 7 chars. + // Start with max decimals, reduce if integer part is wide or rounding overflows. + for (int dec = 4; dec >= 0; dec--) { + QString body = QString::number(av, 'f', dec); + body += (dec == 0) ? QStringLiteral(".f") : QStringLiteral("f"); + if (body.size() == 7) { + if (v < 0.f) body.prepend('-'); + return body; } } - if (!s.contains('.')) - s += QStringLiteral(".f"); - else - s += QLatin1Char('f'); - return s; + // Rounding pushed past 99999 — use overflow cap + return v < 0 ? QStringLiteral("-99999+f") : QStringLiteral("99999+f"); } QString fmtDouble(double v) { QString s = QString::number(v, 'g', 6); @@ -333,7 +333,7 @@ static QString readValueImpl(const Node& node, const Provider& prov, int count = sizeForKind(node.kind) / 4; QStringList parts; for (int i = 0; i < count; i++) - parts << fmtFloat(prov.readF32(addr + i * 4)).trimmed(); + parts << fmtFloat(prov.readF32(addr + i * 4)); return parts.join(QStringLiteral(", ")); } case NodeKind::Mat4x4: { @@ -342,7 +342,7 @@ static QString readValueImpl(const Node& node, const Provider& prov, QString line = QStringLiteral("row%1 [").arg(subLine); for (int c = 0; c < 4; c++) { if (c > 0) line += QStringLiteral(", "); - line += fmtFloat(prov.readF32(addr + (subLine * 4 + c) * 4)).trimmed(); + line += fmtFloat(prov.readF32(addr + (subLine * 4 + c) * 4)); } line += QStringLiteral("]"); return line; diff --git a/tests/test_format.cpp b/tests/test_format.cpp index 6c65c46..45a7636 100644 --- a/tests/test_format.cpp +++ b/tests/test_format.cpp @@ -13,14 +13,54 @@ private slots: } void testFmtInt32() { - // fmtInt32 outputs hex representation (0xffffffd6 for -42) - QCOMPARE(fmt::fmtInt32(-42), QString("0xffffffd6")); - QCOMPARE(fmt::fmtInt32(0), QString("0x0")); + // fmtInt32 outputs decimal representation + QCOMPARE(fmt::fmtInt32(-42), QString("-42")); + QCOMPARE(fmt::fmtInt32(0), QString("0")); } void testFmtFloat() { - QString s = fmt::fmtFloat(3.14159f); - QVERIFY(s.contains("3.14")); + // Positive: 7 chars body. Negative: '-' + 7 chars = 8. + auto check = [](float v, const char* expected) { + QString s = fmt::fmtFloat(v); + QCOMPARE(s, QString(expected)); + }; + + // Basic positive/negative + check( 3.14159f, "3.1416f"); + check(-3.14159f, "-3.1416f"); + + // Zero + check( 0.f, "0.0000f"); + + // Small values + check( 0.02f, "0.0200f"); + check(-0.069f, "-0.0690f"); + + // Values >= 10 — 3 decimal places + check( 15.6543f, "15.654f"); + check(-77.6624f, "-77.662f"); + + // Values >= 100 — 2 decimal places + check( 500.f, "500.00f"); + + // Values >= 1000 — 1 decimal place + check( 5000.f, "5000.0f"); + + // Values >= 10000 — 0 decimal places + "." + check( 50000.f, "50000.f"); + + // Overflow cap + check( 100000.f, "99999+f"); + check(-100000.f, "-99999+f"); + + // Special values + check( 1.f / 0.f, "inff"); + check(-1.f / 0.f, "-inff"); + QCOMPARE(fmt::fmtFloat(std::nanf("")), QString("NaN")); + + // 1.0 exactly + check( 1.f, "1.0000f"); + check(-1.f, "-1.0000f"); } void testFmtBool() {