From be99f2960c70bbb1f043f8bccad63df3ad674bb6 Mon Sep 17 00:00:00 2001 From: Donald Clark Jackson Date: Sat, 10 Oct 2026 14:16:23 -0700 Subject: [PATCH] Refuse non-finite floats instead of publishing nan or inf homie_format_float() and homie_format_double() wrote "nan", "inf" or "-inf", and Property::setValue(float) published it, but the float payload grammar has no spelling for them. The formatters now return false with an empty string, and setValue() logs and keeps the previous value. A new suite runs the 434 float32 vectors shared with python-sdk and rust-sdk. Fixes #27. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01Vz59zZzRfxFkWjW16egZoy --- CHANGELOG.md | 8 + homie/include/ebus/homie/homie_datatype.h | 8 +- homie/src/Property.cpp | 8 +- homie/src/homie_datatype.cpp | 15 +- .../float32_vectors.h | 447 ++++++++++++++++++ .../test_homie_float_vectors.cpp | 34 ++ .../test_property_publish.cpp | 13 + 7 files changed, 521 insertions(+), 12 deletions(-) create mode 100644 test/test_homie_float_vectors/float32_vectors.h create mode 100644 test/test_homie_float_vectors/test_homie_float_vectors.cpp diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ff0b6a..684307e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,14 @@ All notable changes to `cpp-sdk` are recorded here. Format follows [Keep a Chang ## [Unreleased] +### Fixed + +- `Property::setValue(float)` published `nan`, `inf` or `-inf`, which the float payload grammar does not allow. `homie_format_float()` and `homie_format_double()` now return `false` with an empty string for a NaN or infinity, and `setValue()` logs and keeps the previous value. ([#27](https://github.com/electrification-bus/cpp-sdk/issues/27)) + +### Added + +- `test_homie_float_vectors`: the 434 float32 vectors shared with python-sdk and rust-sdk. + ## [0.7.0] - 2026-10-10 ### Changed diff --git a/homie/include/ebus/homie/homie_datatype.h b/homie/include/ebus/homie/homie_datatype.h index a74be55..e673da2 100644 --- a/homie/include/ebus/homie/homie_datatype.h +++ b/homie/include/ebus/homie/homie_datatype.h @@ -95,9 +95,9 @@ bool homie_validate_number(double value, const char* format, double* coerced); // Format a float payload: the shortest decimal that reads back as the same float, laid // out like Python's repr() without the exponent '+' (fixed notation with at least one // fraction digit for exponents -4..15, else d.ddde-XX), so "21.4", "40.0", "1e-05", -// "1e16". This is python-sdk's float text. Writes NUL-terminated text to out (n >= 32); -// a non-finite value is written as "nan", "inf" or "-inf", which is not a valid payload. -void homie_format_float(float value, char* out, size_t n); +// "1e16". This is python-sdk's float text. Writes NUL-terminated text to out (n >= 32) +// and returns true. A NaN or infinity has no float payload: returns false, out is "". +bool homie_format_float(float value, char* out, size_t n); // The same for a double: the shortest decimal that reads back as the same double. -void homie_format_double(double value, char* out, size_t n); +bool homie_format_double(double value, char* out, size_t n); diff --git a/homie/src/Property.cpp b/homie/src/Property.cpp index e8a46e9..6e60194 100644 --- a/homie/src/Property.cpp +++ b/homie/src/Property.cpp @@ -81,8 +81,14 @@ void Property::setValue(int64_t value) { _has_value = true; } void Property::setValue(float value) { + char text[32]; + if (!homie_format_float(value, text, sizeof(text))) { + homie_logf("Property: '%s' - %f is not a float payload; keeping the previous value\n", + _id, (double)value); + return; + } _floatValue = value; - homie_format_float(value, _value, sizeof(_value)); + snprintf(_value, sizeof(_value), "%s", text); _has_value = true; } void Property::setValue(const char* value) { diff --git a/homie/src/homie_datatype.cpp b/homie/src/homie_datatype.cpp index 16f3f94..4c34dfb 100644 --- a/homie/src/homie_datatype.cpp +++ b/homie/src/homie_datatype.cpp @@ -295,10 +295,10 @@ bool homie_validate_duration(const char* payload) { // Shortest round trip: the fewest significant digits whose text reads back as `value`, // through strtof() for a float (nine digits always suffice) or strtod() for a double // (seventeen). -static void format_shortest(double value, bool is_float, char* out, size_t n) { +static bool format_shortest(double value, bool is_float, char* out, size_t n) { if (!isfinite(value)) { - snprintf(out, n, "%g", value); - return; + if (n > 0) out[0] = '\0'; + return false; } char sci[32]; const int max_prec = is_float ? 8 : 16; @@ -346,12 +346,13 @@ static void format_shortest(double value, bool is_float, char* out, size_t n) { snprintf(buf + len, sizeof(buf) - len, "e%s%02d", exp10 < 0 ? "-" : "", abs(exp10)); } snprintf(out, n, "%s", buf); + return true; } -void homie_format_float(float value, char* out, size_t n) { - format_shortest(value, true, out, n); +bool homie_format_float(float value, char* out, size_t n) { + return format_shortest(value, true, out, n); } -void homie_format_double(double value, char* out, size_t n) { - format_shortest(value, false, out, n); +bool homie_format_double(double value, char* out, size_t n) { + return format_shortest(value, false, out, n); } diff --git a/test/test_homie_float_vectors/float32_vectors.h b/test/test_homie_float_vectors/float32_vectors.h new file mode 100644 index 0000000..d311119 --- /dev/null +++ b/test/test_homie_float_vectors/float32_vectors.h @@ -0,0 +1,447 @@ +// The float32 vectors in rust-sdk's vectors/python-sdk/float32-format.json at c31562c +// (generated by rust-sdk tools/gen_vectors.py from python-sdk 0.26.0): each bit pattern +// and the payload python-sdk publishes for it, or nullptr where it publishes none. +#pragma once +#include + +struct Float32Vector { + uint32_t bits; + const char* payload; +}; + +static const Float32Vector FLOAT32_VECTORS[] = { + {0x00000000U, "0.0"}, + {0x80000000U, "-0.0"}, + {0x3f800000U, "1.0"}, + {0xbf800000U, "-1.0"}, + {0x41ab3333U, "21.4"}, + {0xc1ab3333U, "-21.4"}, + {0x42200000U, "40.0"}, + {0x3dcccccdU, "0.1"}, + {0x3e4ccccdU, "0.2"}, + {0x3e99999aU, "0.3"}, + {0x3eaaaaabU, "0.33333334"}, + {0x3f000000U, "0.5"}, + {0x40200000U, "2.5"}, + {0x42c80000U, "100.0"}, + {0x449a5000U, "1234.5"}, + {0x4ceb79a3U, "123456790.0"}, + {0x4b800000U, "16777216.0"}, + {0x4f000000U, "2147483600.0"}, + {0x5f000000U, "9.223372e18"}, + {0x38d1b717U, "0.0001"}, + {0x38d1b1b9U, "9.999e-05"}, + {0x3727c5acU, "1e-05"}, + {0x377ba882U, "1.5e-05"}, + {0x3901725bU, "0.00012345"}, + {0x58635fa9U, "1000000000000000.0"}, + {0x5a0e1bcaU, "1e16"}, + {0x5a5529afU, "1.5e16"}, + {0x006ce3eeU, "1e-38"}, + {0x7e967699U, "1e38"}, + {0x7f7fffffU, "3.4028235e38"}, + {0xff7fffffU, "-3.4028235e38"}, + {0x00800000U, "1.1754944e-38"}, + {0x80800000U, "-1.1754944e-38"}, + {0x00000001U, "1e-45"}, + {0x00000002U, "3e-45"}, + {0x000116c2U, "1e-40"}, + {0x4a000001U, "2097152.2"}, + {0x4a000007U, "2097153.8"}, + {0x40490fd0U, "3.14159"}, + {0x402df854U, "2.7182817"}, + {0x66ff0c2eU, "6.0221406e23"}, + {0x4d8ef3c2U, "299792450.0"}, + {0x477fff00U, "65535.0"}, + {0x4f800000U, "4294967300.0"}, + {0x42c7fae1U, "99.99"}, + {0x3a83126fU, "0.001"}, + {0xba83126fU, "-0.001"}, + {0x41480000U, "12.5"}, + {0x7f800000U, nullptr}, + {0xff800000U, nullptr}, + {0x7fc00000U, nullptr}, + {0x00000003U, "4e-45"}, + {0x007fffffU, "1.1754942e-38"}, + {0x00400000U, "5.877472e-39"}, + {0x80000001U, "-1e-45"}, + {0x7f7ffffeU, "3.4028233e38"}, + {0x00000007U, "1e-44"}, + {0x00000008U, "1.1e-44"}, + {0x00000006U, "8e-45"}, + {0x00000047U, "1e-43"}, + {0x00000048U, "1.01e-43"}, + {0x00000046U, "9.8e-44"}, + {0x000002caU, "1e-42"}, + {0x000002cbU, "1.002e-42"}, + {0x000002c9U, "9.99e-43"}, + {0x00001be0U, "1e-41"}, + {0x00001be1U, "1.0001e-41"}, + {0x00001bdfU, "9.998e-42"}, + {0x000116c3U, "1.00001e-40"}, + {0x000116c1U, "9.9998e-41"}, + {0x000ae398U, "1e-39"}, + {0x000ae399U, "1.000002e-39"}, + {0x000ae397U, "9.99999e-40"}, + {0x006ce3efU, "1.0000001e-38"}, + {0x006ce3edU, "9.999998e-39"}, + {0x02081ceaU, "1e-37"}, + {0x02081cebU, "1.0000001e-37"}, + {0x02081ce9U, "9.999999e-38"}, + {0x03aa2425U, "1e-36"}, + {0x03aa2426U, "1.0000001e-36"}, + {0x03aa2424U, "9.9999995e-37"}, + {0x0554ad2eU, "1e-35"}, + {0x0554ad2fU, "1.0000001e-35"}, + {0x0554ad2dU, "9.9999995e-36"}, + {0x0704ec3dU, "1e-34"}, + {0x0704ec3eU, "1.0000002e-34"}, + {0x0704ec3cU, "9.999999e-35"}, + {0x08a6274cU, "1e-33"}, + {0x08a6274dU, "1.0000001e-33"}, + {0x08a6274bU, "9.999999e-34"}, + {0x0a4fb11fU, "1e-32"}, + {0x0a4fb120U, "1.0000001e-32"}, + {0x0a4fb11eU, "9.9999995e-33"}, + {0x0c01ceb3U, "1e-31"}, + {0x0c01ceb4U, "1.0000001e-31"}, + {0x0c01ceb2U, "9.999999e-32"}, + {0x0da24260U, "1e-30"}, + {0x0da24261U, "1.0000001e-30"}, + {0x0da2425fU, "9.999999e-31"}, + {0x0f4ad2f8U, "1e-29"}, + {0x0f4ad2f9U, "1.0000001e-29"}, + {0x0f4ad2f7U, "9.999999e-30"}, + {0x10fd87b6U, "1e-28"}, + {0x10fd87b7U, "1.00000006e-28"}, + {0x10fd87b5U, "9.9999994e-29"}, + {0x129e74d2U, "1e-27"}, + {0x129e74d3U, "1.0000001e-27"}, + {0x129e74d1U, "9.999999e-28"}, + {0x14461206U, "1e-26"}, + {0x14461207U, "1.0000001e-26"}, + {0x14461205U, "9.999999e-27"}, + {0x15f79688U, "1e-25"}, + {0x15f79689U, "1.0000001e-25"}, + {0x15f79687U, "9.9999996e-26"}, + {0x179abe15U, "1e-24"}, + {0x179abe16U, "1.0000001e-24"}, + {0x179abe14U, "9.999999e-25"}, + {0x19416d9aU, "1e-23"}, + {0x19416d9bU, "1.0000001e-23"}, + {0x19416d99U, "9.999999e-24"}, + {0x1af1c901U, "1e-22"}, + {0x1af1c902U, "1.0000001e-22"}, + {0x1af1c900U, "9.9999997e-23"}, + {0x1c971da0U, "1e-21"}, + {0x1c971da1U, "1.0000001e-21"}, + {0x1c971d9fU, "9.999999e-22"}, + {0x1e3ce508U, "1e-20"}, + {0x1e3ce509U, "1.00000005e-20"}, + {0x1e3ce507U, "9.999999e-21"}, + {0x1fec1e4aU, "1e-19"}, + {0x1fec1e4bU, "1.00000003e-19"}, + {0x1fec1e49U, "9.999999e-20"}, + {0x219392efU, "1e-18"}, + {0x219392f0U, "1.0000001e-18"}, + {0x219392eeU, "9.999999e-19"}, + {0x233877aaU, "1e-17"}, + {0x233877abU, "1.0000001e-17"}, + {0x233877a9U, "9.999999e-18"}, + {0x24e69595U, "1e-16"}, + {0x24e69596U, "1.0000001e-16"}, + {0x24e69594U, "9.9999995e-17"}, + {0x26901d7dU, "1e-15"}, + {0x26901d7eU, "1.0000001e-15"}, + {0x26901d7cU, "9.999999e-16"}, + {0x283424dcU, "1e-14"}, + {0x283424ddU, "1.0000001e-14"}, + {0x283424dbU, "9.999999e-15"}, + {0x29e12e13U, "1e-13"}, + {0x29e12e14U, "1.00000005e-13"}, + {0x29e12e12U, "9.999999e-14"}, + {0x2b8cbcccU, "1e-12"}, + {0x2b8cbccdU, "1.0000001e-12"}, + {0x2b8cbccbU, "9.999999e-13"}, + {0x2d2febffU, "1e-11"}, + {0x2d2fec00U, "1.0000001e-11"}, + {0x2d2febfeU, "9.999999e-12"}, + {0x2edbe6ffU, "1e-10"}, + {0x2edbe700U, "1.0000001e-10"}, + {0x2edbe6feU, "9.9999994e-11"}, + {0x3089705fU, "1e-09"}, + {0x30897060U, "1.0000001e-09"}, + {0x3089705eU, "9.999999e-10"}, + {0x322bcc77U, "1e-08"}, + {0x322bcc78U, "1.0000001e-08"}, + {0x322bcc76U, "9.999999e-09"}, + {0x33d6bf95U, "1e-07"}, + {0x33d6bf96U, "1.0000001e-07"}, + {0x33d6bf94U, "9.9999994e-08"}, + {0x358637bdU, "1e-06"}, + {0x358637beU, "1.0000001e-06"}, + {0x358637bcU, "9.999999e-07"}, + {0x3727c5adU, "1.0000001e-05"}, + {0x3727c5abU, "9.999999e-06"}, + {0x38d1b718U, "0.000100000005"}, + {0x38d1b716U, "9.999999e-05"}, + {0x3a831270U, "0.0010000002"}, + {0x3a83126eU, "0.0009999999"}, + {0x3c23d70aU, "0.01"}, + {0x3c23d70bU, "0.010000001"}, + {0x3c23d709U, "0.009999999"}, + {0x3dccccceU, "0.10000001"}, + {0x3dccccccU, "0.099999994"}, + {0x3f800001U, "1.0000001"}, + {0x3f7fffffU, "0.99999994"}, + {0x41200000U, "10.0"}, + {0x41200001U, "10.000001"}, + {0x411fffffU, "9.999999"}, + {0x42c80001U, "100.00001"}, + {0x42c7ffffU, "99.99999"}, + {0x447a0000U, "1000.0"}, + {0x447a0001U, "1000.00006"}, + {0x4479ffffU, "999.99994"}, + {0x461c4000U, "10000.0"}, + {0x461c4001U, "10000.001"}, + {0x461c3fffU, "9999.999"}, + {0x47c35000U, "100000.0"}, + {0x47c35001U, "100000.01"}, + {0x47c34fffU, "99999.99"}, + {0x49742400U, "1000000.0"}, + {0x49742401U, "1000000.06"}, + {0x497423ffU, "999999.94"}, + {0x4b189680U, "10000000.0"}, + {0x4b189681U, "10000001.0"}, + {0x4b18967fU, "9999999.0"}, + {0x4cbebc20U, "100000000.0"}, + {0x4cbebc21U, "100000010.0"}, + {0x4cbebc1fU, "99999990.0"}, + {0x4e6e6b28U, "1000000000.0"}, + {0x4e6e6b29U, "1000000060.0"}, + {0x4e6e6b27U, "999999940.0"}, + {0x501502f9U, "10000000000.0"}, + {0x501502faU, "10000001000.0"}, + {0x501502f8U, "9999999000.0"}, + {0x51ba43b7U, "100000000000.0"}, + {0x51ba43b8U, "100000010000.0"}, + {0x51ba43b6U, "99999990000.0"}, + {0x5368d4a5U, "1000000000000.0"}, + {0x5368d4a6U, "1000000060000.0"}, + {0x5368d4a4U, "999999900000.0"}, + {0x551184e7U, "10000000000000.0"}, + {0x551184e8U, "10000001000000.0"}, + {0x551184e6U, "9999999000000.0"}, + {0x56b5e621U, "100000000000000.0"}, + {0x56b5e622U, "100000010000000.0"}, + {0x56b5e620U, "99999990000000.0"}, + {0x58635faaU, "1000000050000000.0"}, + {0x58635fa8U, "999999900000000.0"}, + {0x5a0e1bcbU, "1.0000001e16"}, + {0x5a0e1bc9U, "9999999000000000.0"}, + {0x5bb1a2bcU, "1e17"}, + {0x5bb1a2bdU, "1.0000001e17"}, + {0x5bb1a2bbU, "9.999999e16"}, + {0x5d5e0b6bU, "1e18"}, + {0x5d5e0b6cU, "1.00000005e18"}, + {0x5d5e0b6aU, "9.999999e17"}, + {0x5f0ac723U, "1e19"}, + {0x5f0ac724U, "1.0000001e19"}, + {0x5f0ac722U, "9.999999e18"}, + {0x60ad78ecU, "1e20"}, + {0x60ad78edU, "1.0000001e20"}, + {0x60ad78ebU, "9.999999e19"}, + {0x6258d727U, "1e21"}, + {0x6258d728U, "1.0000001e21"}, + {0x6258d726U, "9.9999995e20"}, + {0x64078678U, "1e22"}, + {0x64078679U, "1.0000001e22"}, + {0x64078677U, "9.999999e21"}, + {0x65a96816U, "1e23"}, + {0x65a96817U, "1.0000001e23"}, + {0x65a96815U, "9.999999e22"}, + {0x6753c21cU, "1e24"}, + {0x6753c21dU, "1.0000001e24"}, + {0x6753c21bU, "9.9999994e23"}, + {0x69045951U, "1e25"}, + {0x69045952U, "1.0000001e25"}, + {0x69045950U, "9.999998e24"}, + {0x6aa56fa6U, "1e26"}, + {0x6aa56fa7U, "1.0000001e26"}, + {0x6aa56fa5U, "9.999999e25"}, + {0x6c4ecb8fU, "1e27"}, + {0x6c4ecb90U, "1.00000006e27"}, + {0x6c4ecb8eU, "9.999999e26"}, + {0x6e013f39U, "1e28"}, + {0x6e013f3aU, "1.0000001e28"}, + {0x6e013f38U, "9.999998e27"}, + {0x6fa18f08U, "1e29"}, + {0x6fa18f09U, "1.0000001e29"}, + {0x6fa18f07U, "9.999999e28"}, + {0x7149f2caU, "1e30"}, + {0x7149f2cbU, "1.0000001e30"}, + {0x7149f2c9U, "9.9999994e29"}, + {0x72fc6f7cU, "1e31"}, + {0x72fc6f7dU, "1.00000005e31"}, + {0x72fc6f7bU, "9.999999e30"}, + {0x749dc5aeU, "1e32"}, + {0x749dc5afU, "1.0000001e32"}, + {0x749dc5adU, "9.999999e31"}, + {0x76453719U, "1e33"}, + {0x7645371aU, "1.0000001e33"}, + {0x76453718U, "9.999999e32"}, + {0x77f684dfU, "1e34"}, + {0x77f684e0U, "1.00000004e34"}, + {0x77f684deU, "9.999999e33"}, + {0x799a130cU, "1e35"}, + {0x799a130dU, "1.0000001e35"}, + {0x799a130bU, "9.999999e34"}, + {0x7b4097ceU, "1e36"}, + {0x7b4097cfU, "1.00000004e36"}, + {0x7b4097cdU, "9.999999e35"}, + {0x7cf0bdc2U, "1e37"}, + {0x7cf0bdc3U, "1.00000006e37"}, + {0x7cf0bdc1U, "9.999999e36"}, + {0x7e96769aU, "1.0000001e38"}, + {0x7e967698U, "9.999999e37"}, + {0xc67ea36fU, "-16296.858"}, + {0xc604b180U, "-8492.375"}, + {0xc8d7e2aeU, "-442133.44"}, + {0xc9609b5eU, "-919989.9"}, + {0xc71cbe9fU, "-40126.62"}, + {0x48b8fc0dU, "378848.4"}, + {0x48c8950fU, "410792.47"}, + {0x48ffa0aaU, "523525.3"}, + {0xc89716caU, "-309430.3"}, + {0x495b2157U, "897557.44"}, + {0x484cd056U, "209729.34"}, + {0x492f7972U, "718743.1"}, + {0xc75a2bbbU, "-55851.73"}, + {0xc96749e5U, "-947358.3"}, + {0xc903bcd4U, "-539597.25"}, + {0x493e40a4U, "779274.25"}, + {0xc8fbe426U, "-515873.2"}, + {0xc914f0f7U, "-610063.44"}, + {0x4941a865U, "793222.3"}, + {0x48cf326fU, "424339.47"}, + {0x4856cf24U, "219964.56"}, + {0xc96c3e6eU, "-967654.9"}, + {0xc8ecd75cU, "-485050.88"}, + {0xc8206565U, "-164245.58"}, + {0xc892110aU, "-299144.3"}, + {0x48e3dc87U, "466660.22"}, + {0xc8befcbaU, "-391141.8"}, + {0x492aa56bU, "698966.7"}, + {0x468c9fb0U, "17999.844"}, + {0x48b7be07U, "376304.22"}, + {0x48b8caffU, "378455.97"}, + {0xc952a54eU, "-862804.9"}, + {0x4934cdabU, "740570.7"}, + {0xc89a4974U, "-315979.62"}, + {0xc883b617U, "-269744.72"}, + {0xc8af82b5U, "-359445.66"}, + {0x4936e1b9U, "749083.56"}, + {0x491671e3U, "616222.2"}, + {0xc9094bb2U, "-562363.1"}, + {0xc93acedeU, "-765165.9"}, + {0xc903c13cU, "-539667.75"}, + {0x486c0919U, "241700.39"}, + {0xc8f95e2cU, "-510705.38"}, + {0x4934c82dU, "740482.8"}, + {0xc91c9cf7U, "-641487.44"}, + {0x492f53bcU, "718139.75"}, + {0xc8c15d9bU, "-396012.84"}, + {0xc8d2d29bU, "-431764.84"}, + {0x47ea85fbU, "120075.96"}, + {0x49133d9dU, "603097.8"}, + {0xc90a819dU, "-567321.8"}, + {0xc845fa42U, "-202729.03"}, + {0xc88218e1U, "-266439.03"}, + {0x4832224aU, "182409.16"}, + {0x4945d2bdU, "810283.8"}, + {0xc942964cU, "-797028.75"}, + {0x4869f33fU, "239564.98"}, + {0xc72cbe94U, "-44222.58"}, + {0xc90e15beU, "-581979.9"}, + {0x4953bddaU, "867293.6"}, + {0x9d3f6befU, "-2.533444e-21"}, + {0x5071b149U, "16219710000.0"}, + {0x857da3bfU, "-1.1926078e-35"}, + {0x83d4f988U, "-1.251753e-36"}, + {0xee0a9b36U, "-1.0724142e28"}, + {0xa2373dc7U, "-2.483383e-18"}, + {0xbcfe62abU, "-0.031052908"}, + {0xc3323cfcU, "-178.23822"}, + {0xb8b24ba5U, "-8.501791e-05"}, + {0x8facb448U, "-1.7029951e-29"}, + {0x4542ec05U, "3118.7512"}, + {0xb0b0b009U, "-1.2855718e-09"}, + {0xf9c02fb9U, "-1.2473612e35"}, + {0x2e4a48adU, "4.599403e-11"}, + {0x9a6ac529U, "-4.854933e-23"}, + {0x74b50f0cU, "1.1475963e32"}, + {0x1845f640U, "2.5585978e-24"}, + {0xea655492U, "-6.9310846e25"}, + {0xbd934804U, "-0.0719147"}, + {0xd667fe11U, "-63769600000000.0"}, + {0x9b496043U, "-1.6657434e-22"}, + {0x684d6099U, "3.8794682e24"}, + {0x9ddfc989U, "-5.923599e-21"}, + {0x569559b7U, "82106280000000.0"}, + {0xe961174eU, "-1.7007398e25"}, + {0x9de5bf24U, "-6.081343e-21"}, + {0xc4398c16U, "-742.18884"}, + {0x323c7f7dU, "1.0972028e-08"}, + {0x8875579cU, "-7.382999e-34"}, + {0xdc618ee3U, "-2.539559e17"}, + {0xa637a616U, "-6.371597e-16"}, + {0xdc1ffd9fU, "-1.8013352e17"}, + {0x01f454beU, "8.9753043e-38"}, + {0x6262410cU, "1.0434128e21"}, + {0xdabae87fU, "-2.6304989e16"}, + {0x7dd0b5a4U, "3.467782e37"}, + {0x1e8d7fffU, "1.4981894e-20"}, + {0x55e5cd7bU, "31583837000000.0"}, + {0xdbaa7a8fU, "-9.5971e16"}, + {0x271b656dU, "2.1565554e-15"}, + {0xd3ac8244U, "-1481839700000.0"}, + {0x54ac9bccU, "5930785700000.0"}, + {0x7382c268U, "2.0719654e31"}, + {0xc2c46f5aU, "-98.21748"}, + {0x5ee528d7U, "8.256342e18"}, + {0x02d4533cU, "3.1198374e-37"}, + {0xf9de5542U, "-1.4430239e35"}, + {0x66cb14e5U, "4.795129e23"}, + {0xbe101a98U, "-0.14072645"}, + {0x31bf0f3fU, "5.560565e-09"}, + {0x7148abb9U, "9.936736e29"}, + {0x4cc7cf11U, "104757384.0"}, + {0x4f911c0fU, "4869070300.0"}, + {0xc03584a9U, "-2.836222"}, + {0x83a87d2eU, "-9.902892e-37"}, + {0x03f577ebU, "1.4427338e-36"}, + {0x8a9f465cU, "-1.533761e-32"}, + {0x9830d454U, "-2.2854665e-24"}, + {0xc9ed53b7U, "-1944182.9"}, + {0x084ac916U, "6.102354e-34"}, + {0x4c2d7f5fU, "45481340.0"}, + {0x5307e9a3U, "583740360000.0"}, + {0x331a35c0U, "3.5904804e-08"}, + {0x51be971cU, "102322370000.0"}, + {0x3ee11f72U, "0.43969303"}, + {0x22dab6eaU, "5.9282686e-18"}, + {0x5eb63793U, "6.5650624e18"}, + {0x339c6325U, "7.2823504e-08"}, + {0x3cfe69a1U, "0.031056227"}, + {0x38cf2bdfU, "9.878701e-05"}, + {0x3146fb56U, "2.895566e-09"}, + {0x51754ea6U, "65849156000.0"}, + {0x1fcefd10U, "8.766305e-20"}, + {0x3dc870c7U, "0.097871356"}, + {0x4051759fU, "3.272804"}, + {0x58589796U, "952582300000000.0"}, + {0x5afb4316U, "3.536199e16"}, + {0x4909e82dU, "564866.8"}, + {0x2b764cdcU, "8.750342e-13"}, + {0x45b4b13cU, "5782.1543"}, +}; diff --git a/test/test_homie_float_vectors/test_homie_float_vectors.cpp b/test/test_homie_float_vectors/test_homie_float_vectors.cpp new file mode 100644 index 0000000..e8eb813 --- /dev/null +++ b/test/test_homie_float_vectors/test_homie_float_vectors.cpp @@ -0,0 +1,34 @@ +// homie_format_float() against the float32 vectors shared with python-sdk and rust-sdk. + +#include +#include +#include +#include +#include "float32_vectors.h" + +void setUp(void) {} +void tearDown(void) {} + +static void test_every_float32_vector_formats_as_python_sdk_publishes_it(void) { + char out[32]; + char msg[64]; + for (const Float32Vector& v : FLOAT32_VECTORS) { + float value; + memcpy(&value, &v.bits, sizeof(value)); + bool ok = homie_format_float(value, out, sizeof(out)); + snprintf(msg, sizeof(msg), "bits 0x%08lx", (unsigned long)v.bits); + if (v.payload == nullptr) { + TEST_ASSERT_FALSE_MESSAGE(ok, msg); + TEST_ASSERT_EQUAL_STRING_MESSAGE("", out, msg); + } else { + TEST_ASSERT_TRUE_MESSAGE(ok, msg); + TEST_ASSERT_EQUAL_STRING_MESSAGE(v.payload, out, msg); + } + } +} + +int main(int, char**) { + UNITY_BEGIN(); + RUN_TEST(test_every_float32_vector_formats_as_python_sdk_publishes_it); + return UNITY_END(); +} diff --git a/test/test_property_publish/test_property_publish.cpp b/test/test_property_publish/test_property_publish.cpp index 38a3663..277af49 100644 --- a/test/test_property_publish/test_property_publish.cpp +++ b/test/test_property_publish/test_property_publish.cpp @@ -245,6 +245,18 @@ static void test_subscribe_while_disconnected_does_nothing(void) { TEST_ASSERT_EQUAL_INT(0, settable_count()); } +static void test_non_finite_float_keeps_the_previous_value(void) { + static Property p; + add(p, "temp", "float"); + p.setValue(21.4f); + p.setValue(__builtin_nanf("")); + p.setValue(__builtin_inff()); + TEST_ASSERT_TRUE(p.has_value()); + TEST_ASSERT_EQUAL_STRING("21.4", p.value()); + TEST_ASSERT_TRUE(p.publish_value()); + TEST_ASSERT_EQUAL_STRING("21.4", t.at(0).payload); +} + int main(int argc, char** argv) { (void)argc; (void)argv; @@ -261,5 +273,6 @@ int main(int argc, char** argv) { RUN_TEST(test_subscribe_registers_the_set_topic_at_qos_0); RUN_TEST(test_subscribe_retries_twice_then_gives_up); RUN_TEST(test_subscribe_while_disconnected_does_nothing); + RUN_TEST(test_non_finite_float_keeps_the_previous_value); return UNITY_END(); }