Merge remote-tracking branch 'upstream/optimize-value-accuracy' into integration

This commit is contained in:
J. Nick Koston
2026-04-14 15:01:45 -10:00
@@ -6,6 +6,7 @@
#include <string>
#include "esphome/core/helpers.h"
#include "esphome/core/string_ref.h"
namespace esphome::core::testing {
@@ -149,4 +150,73 @@ TEST(ValueAccuracyToBuf, ReturnsCorrectLength) {
EXPECT_EQ(strlen(buf), len);
}
// --- value_accuracy_with_uom_to_buf ---
static std::string va_uom_to_string(float value, int8_t accuracy_decimals, const char *uom) {
char buf[VALUE_ACCURACY_MAX_LEN];
std::span<char, VALUE_ACCURACY_MAX_LEN> sp(buf);
StringRef ref(uom);
size_t len = value_accuracy_with_uom_to_buf(sp, value, accuracy_decimals, ref);
return std::string(buf, len);
}
static std::string va_uom_reference(float value, int8_t accuracy_decimals, const char *uom) {
char buf[VALUE_ACCURACY_MAX_LEN];
if (!uom || *uom == '\0') {
snprintf(buf, sizeof(buf), "%.*f", accuracy_decimals, value);
} else {
snprintf(buf, sizeof(buf), "%.*f %s", accuracy_decimals, value, uom);
}
return std::string(buf);
}
TEST(ValueAccuracyWithUomToBuf, BasicWithUnit) {
EXPECT_EQ(va_uom_to_string(23.456f, 2, "°C"), va_uom_reference(23.456f, 2, "°C"));
EXPECT_EQ(va_uom_to_string(1013.25f, 2, "hPa"), va_uom_reference(1013.25f, 2, "hPa"));
EXPECT_EQ(va_uom_to_string(-40.0f, 1, "°F"), va_uom_reference(-40.0f, 1, "°F"));
EXPECT_EQ(va_uom_to_string(100.0f, 0, "%"), va_uom_reference(100.0f, 0, "%"));
}
TEST(ValueAccuracyWithUomToBuf, EmptyUnit) {
EXPECT_EQ(va_uom_to_string(23.456f, 2, ""), "23.46");
EXPECT_EQ(va_uom_to_string(0.0f, 1, ""), "0.0");
}
TEST(ValueAccuracyWithUomToBuf, ReturnsCorrectLength) {
char buf[VALUE_ACCURACY_MAX_LEN];
std::span<char, VALUE_ACCURACY_MAX_LEN> sp(buf);
StringRef ref("°C");
size_t len = value_accuracy_with_uom_to_buf(sp, 23.46f, 2, ref);
EXPECT_EQ(strlen(buf), len);
EXPECT_EQ(len, strlen("23.46 °C"));
}
TEST(ValueAccuracyWithUomToBuf, NearBufferLimitTruncates) {
// Build a unit long enough that value + " " + unit exceeds VALUE_ACCURACY_MAX_LEN.
// "23.46" (5) + " " (1) + unit -> must cap at buf.size()-1 and stay null-terminated.
std::string long_unit(VALUE_ACCURACY_MAX_LEN, 'U');
char buf[VALUE_ACCURACY_MAX_LEN];
std::span<char, VALUE_ACCURACY_MAX_LEN> sp(buf);
StringRef ref(long_unit.c_str());
size_t len = value_accuracy_with_uom_to_buf(sp, 23.46f, 2, ref);
EXPECT_LT(len, VALUE_ACCURACY_MAX_LEN);
EXPECT_EQ(strlen(buf), len);
// Should begin with the formatted value and a separator.
EXPECT_EQ(std::string(buf, 6), "23.46 ");
}
TEST(ValueAccuracyWithUomToBuf, MatchesSnprintf) {
const char *units[] = {"°C", "hPa", "%", "W", "kWh", "m/s"};
float values[] = {0.0f, 23.456f, -40.0f, 1013.25f, 100.0f};
int8_t accs[] = {0, 1, 2, 3};
for (const char *u : units) {
for (float v : values) {
for (int8_t a : accs) {
EXPECT_EQ(va_uom_to_string(v, a, u), va_uom_reference(v, a, u))
<< "value=" << v << " acc=" << static_cast<int>(a) << " uom=" << u;
}
}
}
}
} // namespace esphome::core::testing