diff --git a/test/test_unit_strings.cpp b/test/test_unit_strings.cpp index 8ea92b4e..3d1fc924 100644 --- a/test/test_unit_strings.cpp +++ b/test/test_unit_strings.cpp @@ -944,6 +944,11 @@ TEST(stringToUnits, equivalents4) "nanomole of (1/2) cystine per milligram of protein"))); } +TEST(stringToUnits, commodityConsiderations) +{ + auto ut = unit_from_string("mile(USA){\\{}"); + EXPECT_NE(ut.commodity(), 0U); +} TEST(stringToUnits, electronVolt) { EXPECT_EQ(unit_from_string("eV"), precise::energy::eV); @@ -1166,9 +1171,34 @@ TEST(stringToUnit, handlingOfSquared) auto u2 = unit_from_string("pascal squared second"); EXPECT_EQ(u2, precise::Pa.pow(2) * precise::s); + auto u2b = unit_from_string("pascal squared per second squared"); + EXPECT_EQ(u2b, precise::Pa.pow(2) / precise::s.pow(2)); + + auto u2c = unit_from_string("pascal squared per second squared per kg"); + EXPECT_EQ(u2c, precise::Pa.pow(2) / precise::s.pow(2) / precise::kg); + + auto u2d = unit_from_string("pascal cubed second"); + EXPECT_EQ(u2d, precise::Pa.pow(3) * precise::s); + + auto u2e = unit_from_string("pascal cubed per second cubed"); + EXPECT_EQ(u2e, precise::Pa.pow(3) / precise::s.pow(3)); + + auto u2f = unit_from_string("pascal squared per second squared per kg"); + EXPECT_EQ(u2f, precise::Pa.pow(2) / precise::s.pow(2) / precise::kg); + + auto u2g = unit_from_string("pascal squared / second squared / kg"); + EXPECT_EQ(u2g, precise::Pa.pow(2) / precise::s.pow(2) / precise::kg); + auto u3 = unit_from_string("coulomb metre squared per volt"); EXPECT_EQ(u3, precise::C * precise::m.pow(2) / precise::V); + auto u3v = unit_from_string( + "kg per coulomb metre squared per second squared per volt"); + EXPECT_EQ( + u3v, + precise::kg / (precise::C * precise::m.pow(2)) / precise::V / + precise::s.pow(2)); + auto u4 = unit_from_string("ampere square metre per joule second"); EXPECT_EQ(u4, precise::A * precise::m.pow(2) / (precise::J * precise::s)); @@ -1216,6 +1246,21 @@ TEST(stringToUnits, modifiedStrings) EXPECT_EQ(u8, unit_from_string("[QT_US]")); } +TEST(stringToUnits, tempString) +{ + auto u4 = unit_from_string("calorie (20 degC)"); + EXPECT_EQ(u4, precise::energy::cal_20); + + u4 = unit_from_string("calorie 20C"); + EXPECT_EQ(u4, precise::energy::cal_20); + + u4 = unit_from_string("calorie at 20C"); + EXPECT_EQ(u4, precise::energy::cal_20); + + u4 = unit_from_string("calorie_20C"); + EXPECT_EQ(u4, precise::energy::cal_20); +} + TEST(stringToUnits, addition) { auto u1 = unit_from_string("cm+cm"); diff --git a/units/units.cpp b/units/units.cpp index 224ab52a..c4d2e061 100644 --- a/units/units.cpp +++ b/units/units.cpp @@ -2709,11 +2709,6 @@ bool bracketModifiers(std::string& unit_string) unit_string.replace(ploc + 1, cloc - ploc, modloc->second); unit_string[ploc] = '_'; - if (unit_string[ploc - 1] == ' ') { - unit_string.erase(ploc - 1, 1); - --ploc; - } - modified = true; } ploc = unit_string.find_first_of(seg[0], ploc + 1); @@ -3533,9 +3528,13 @@ static bool isolatePriorModifier( auto modfind = unit_string.find(modifier); if (modfind != std::string::npos) { auto offset = modfind + modifier.size(); + // LCOV_EXCL_START + // this condition is not used in current use cases but it is dangerous + // to make assumptions that will always be the case if (modifier.back() != ' ') { ++offset; } + // LCOV_EXCL_STOP auto kloc = unit_string.find_first_not_of(' ', offset); if (kloc != std::string::npos && (unit_string[kloc] == check1 || unit_string[kloc] == check2)) { @@ -4743,22 +4742,25 @@ static bool cleanUnitString(std::string& unit_string, std::uint64_t match_flags) return (changed || unit_string.size() != slen); } -static void modifyTailCodes(std::string& unit_string) +static bool modifyTailCodes(std::string& unit_string) { if (!unit_string.empty() && (unit_string.back() == 'F' || unit_string.back() == 'C')) { - static UNITS_CPP14_CONSTEXPR_OBJECT std::array + static UNITS_CPP14_CONSTEXPR_OBJECT std::array trailTempCodeReplacements{{ ckpair{"at39F", "[39]"}, ckpair{"39F", "[39]"}, ckpair{"at60F", "[60]"}, ckpair{"60F", "[60]"}, - ckpair{"at0C", "[00]"}, - ckpair{"0C", "[00]"}, + ckpair{"at20C", "[20]"}, + ckpair{"20C", "[20]"}, ckpair{"at23C", "[23]"}, ckpair{"23C", "[23]"}, ckpair{"at4C", "[04]"}, ckpair{"4C", "[04]"}, + ckpair{"at0C", "[00]"}, + ckpair{"0C", "[00]"}, + }}; for (const auto& endTemp : trailTempCodeReplacements) { @@ -4769,9 +4771,11 @@ static void modifyTailCodes(std::string& unit_string) if (unit_string[unit_string.size() - 5] != '_') { unit_string.insert(unit_string.size() - 4, 1, '_'); } + return true; } } } + return false; } /// cleanup phase 2 if things still aren't working @@ -5690,7 +5694,12 @@ static precise_unit unit_from_string_internal( } } - modifyTailCodes(unit_string); + if (modifyTailCodes(unit_string)) { + retunit = get_unit(unit_string, match_flags); + if (!is_error(retunit)) { + return retunit; + } + } if (!containsPer) { retunit = checkMultiplierCharacter(unit_string, match_flags, '-');