Skip to content

Commit 7a1def6

Browse files
authored
Merge pull request #1002 from SignalK/fix/threshold-from-json-roundtrip
fix(transforms): accept threshold config without out_range
2 parents 20dfbe3 + f18549f commit 7a1def6

2 files changed

Lines changed: 69 additions & 4 deletions

File tree

src/sensesp/transforms/threshold.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,8 @@ namespace sensesp {
1414
* @param max_value Maximum value of input for output to be the value of
1515
* in_range.
1616
*
17-
* @param in_range Output value if input value is in range.
18-
*
19-
* @param out_range Output value if input value is out of the range.
17+
* @param in_range Output value if input value is in range. The output is
18+
* the negation of this value when the input is out of range.
2019
*/
2120
template <typename C>
2221
class ThresholdTransform : public Transform<C, bool> {
@@ -42,7 +41,7 @@ class ThresholdTransform : public Transform<C, bool> {
4241
}
4342

4443
bool from_json(const JsonObject& root) override {
45-
String expected[] = {"min", "max", "in_range", "out_range"};
44+
String expected[] = {"min", "max", "in_range"};
4645
for (auto str : expected) {
4746

4847
if (!root[str].is<JsonVariant>()) {
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/**
2+
* @file threshold_roundtrip_test.cpp
3+
* @brief Round-trip and validation tests for ThresholdTransform JSON config.
4+
*
5+
* Regression coverage for the from_json/to_json asymmetry: to_json writes
6+
* {min, max, in_range}, so from_json must require exactly those keys. It
7+
* previously also required "out_range", which to_json never emits, so a
8+
* saved threshold config could never be reloaded.
9+
*/
10+
11+
#include <Arduino.h>
12+
13+
#include "sensesp/system/lambda_consumer.h"
14+
#include "sensesp/transforms/threshold.h"
15+
#include "unity.h"
16+
17+
using namespace sensesp;
18+
19+
void test_float_threshold_round_trip_preserves_behavior() {
20+
FloatThreshold original(10.0f, 20.0f, true);
21+
22+
JsonDocument doc;
23+
JsonObject obj = doc.to<JsonObject>();
24+
TEST_ASSERT_TRUE(original.to_json(obj));
25+
TEST_ASSERT_FLOAT_WITHIN(0.0001f, 10.0f, obj["min"].as<float>());
26+
TEST_ASSERT_FLOAT_WITHIN(0.0001f, 20.0f, obj["max"].as<float>());
27+
TEST_ASSERT_TRUE(obj["in_range"].as<bool>());
28+
29+
FloatThreshold restored(0.0f, 0.0f, false);
30+
JsonObject in = doc.as<JsonObject>();
31+
TEST_ASSERT_TRUE(restored.from_json(in));
32+
33+
bool received = false;
34+
LambdaConsumer<bool> consumer([&received](bool v) { received = v; });
35+
restored.connect_to(&consumer);
36+
37+
restored.set(15.0f); // in range -> in_range value (true)
38+
TEST_ASSERT_TRUE(received);
39+
40+
restored.set(25.0f); // out of range -> !in_range (false)
41+
TEST_ASSERT_FALSE(received);
42+
}
43+
44+
void test_threshold_from_json_rejects_missing_required_key() {
45+
FloatThreshold threshold(0.0f, 0.0f, true);
46+
47+
JsonDocument doc;
48+
doc["min"] = 1.0f;
49+
doc["max"] = 2.0f;
50+
// "in_range" intentionally missing
51+
JsonObject in = doc.as<JsonObject>();
52+
TEST_ASSERT_FALSE(threshold.from_json(in));
53+
}
54+
55+
void setup() {
56+
delay(2000);
57+
58+
UNITY_BEGIN();
59+
60+
RUN_TEST(test_float_threshold_round_trip_preserves_behavior);
61+
RUN_TEST(test_threshold_from_json_rejects_missing_required_key);
62+
63+
UNITY_END();
64+
}
65+
66+
void loop() {}

0 commit comments

Comments
 (0)