2 * Copyright (c) 2010-2024 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.mqtt.generic.values;
15 import static org.hamcrest.CoreMatchers.is;
16 import static org.hamcrest.MatcherAssert.assertThat;
17 import static org.junit.jupiter.api.Assertions.*;
19 import java.math.BigDecimal;
20 import java.util.Objects;
22 import org.eclipse.jdt.annotation.NonNullByDefault;
23 import org.junit.jupiter.api.Test;
24 import org.openhab.binding.mqtt.generic.mapping.ColorMode;
25 import org.openhab.core.library.types.DecimalType;
26 import org.openhab.core.library.types.HSBType;
27 import org.openhab.core.library.types.IncreaseDecreaseType;
28 import org.openhab.core.library.types.OnOffType;
29 import org.openhab.core.library.types.OpenClosedType;
30 import org.openhab.core.library.types.PercentType;
31 import org.openhab.core.library.types.QuantityType;
32 import org.openhab.core.library.types.StopMoveType;
33 import org.openhab.core.library.types.StringType;
34 import org.openhab.core.library.types.UpDownType;
35 import org.openhab.core.library.unit.MetricPrefix;
36 import org.openhab.core.library.unit.Units;
37 import org.openhab.core.types.Command;
38 import org.openhab.core.types.TypeParser;
39 import org.openhab.core.types.UnDefType;
42 * Test cases for the value classes. They should throw exceptions if the wrong command type is used
43 * for an update. The percent value class should raise an exception if the value is out of range.
45 * The on/off value class should accept a multitude of values including the custom defined ones.
47 * The string value class states are tested.
49 * @author David Graeff - Initial contribution
52 public class ValueTests {
53 private Command p(Value v, String str) {
54 return Objects.requireNonNull(TypeParser.parseCommand(v.getSupportedCommandTypes(), str));
58 public void illegalTextStateUpdate() {
59 TextValue v = new TextValue("one,two".split(","));
60 assertThrows(IllegalArgumentException.class, () -> v.parseCommand(p(v, "three")));
64 public void textStateUpdate() {
65 TextValue v = new TextValue("one,two".split(","));
66 v.parseCommand(p(v, "one"));
70 public void colorUpdate() {
71 ColorValue v = new ColorValue(ColorMode.RGB, "fancyON", "fancyOFF", 77);
72 v.update(v.parseCommand(p(v, "255,255,255")));
74 HSBType hsb = v.parseCommand(p(v, "OFF"));
75 assertThat(hsb.getBrightness().intValue(), is(0));
77 hsb = v.parseCommand(p(v, "ON"));
78 assertThat(hsb.getBrightness().intValue(), is(77));
80 hsb = v.parseCommand(p(v, "0"));
81 assertThat(hsb.getBrightness().intValue(), is(0));
82 hsb = v.parseCommand(p(v, "1"));
83 assertThat(hsb.getBrightness().intValue(), is(1));
85 assertThat(v.parseMessage(new StringType("")), is(UnDefType.NULL));
89 public void illegalColorUpdate() {
90 ColorValue v = new ColorValue(ColorMode.RGB, null, null, 10);
91 assertThrows(IllegalArgumentException.class, () -> v.parseCommand(p(v, "255,255,abc")));
95 public void illegalNumberCommand() {
96 NumberValue v = new NumberValue(null, null, null, null);
97 assertThrows(IllegalArgumentException.class, () -> v.parseCommand(OnOffType.OFF));
101 public void illegalPercentCommand() {
102 PercentageValue v = new PercentageValue(null, null, null, null, null);
103 assertThrows(IllegalStateException.class, () -> v.parseCommand(new StringType("demo")));
107 public void illegalOnOffCommand() {
108 OnOffValue v = new OnOffValue(null, null);
109 assertThrows(IllegalArgumentException.class, () -> v.parseCommand(new DecimalType(101.0)));
113 public void illegalPercentUpdate() {
114 PercentageValue v = new PercentageValue(null, null, null, null, null);
115 assertThrows(IllegalArgumentException.class, () -> v.parseCommand(new DecimalType(101.0)));
119 public void onoffUpdate() {
120 OnOffValue v = new OnOffValue("fancyON", "fancyOff");
123 assertThat(v.parseCommand(OnOffType.OFF), is(OnOffType.OFF));
124 assertThat(v.parseCommand(OnOffType.ON), is(OnOffType.ON));
126 // Test with string, representing the command
127 assertThat(v.parseCommand(new StringType("OFF")), is(OnOffType.OFF));
128 assertThat(v.parseCommand(new StringType("ON")), is(OnOffType.ON));
130 // Test with custom string, setup in the constructor
131 assertThat(v.parseCommand(new StringType("fancyOff")), is(OnOffType.OFF));
132 assertThat(v.parseCommand(new StringType("fancyON")), is(OnOffType.ON));
134 // Test basic formatting
135 assertThat(v.getMQTTpublishValue(OnOffType.ON, null), is("fancyON"));
136 assertThat(v.getMQTTpublishValue(OnOffType.OFF, null), is("fancyOff"));
138 // Test custom formatting
139 assertThat(v.getMQTTpublishValue(OnOffType.OFF, "=%s"), is("=fancyOff"));
140 assertThat(v.getMQTTpublishValue(OnOffType.ON, "=%s"), is("=fancyON"));
142 assertThat(v.parseMessage(new StringType("")), is(UnDefType.NULL));
146 public void onoffMultiStates() {
147 OnOffValue v = new OnOffValue(new String[] { "LOCKED" }, new String[] { "UNLOCKED", "JAMMED" }, "LOCK",
150 assertThat(v.parseCommand(new StringType("LOCKED")), is(OnOffType.ON));
151 assertThat(v.parseCommand(new StringType("UNLOCKED")), is(OnOffType.OFF));
152 assertThat(v.parseCommand(new StringType("JAMMED")), is(OnOffType.OFF));
156 public void openCloseUpdate() {
157 OpenCloseValue v = new OpenCloseValue("fancyON", "fancyOff");
160 assertThat(v.parseCommand(OpenClosedType.CLOSED), is(OpenClosedType.CLOSED));
161 assertThat(v.parseCommand(OpenClosedType.OPEN), is(OpenClosedType.OPEN));
163 // Test with string, representing the command
164 assertThat(v.parseCommand(new StringType("CLOSED")), is(OpenClosedType.CLOSED));
165 assertThat(v.parseCommand(new StringType("OPEN")), is(OpenClosedType.OPEN));
167 // Test with custom string, setup in the constructor
168 assertThat(v.parseCommand(new StringType("fancyOff")), is(OpenClosedType.CLOSED));
169 assertThat(v.parseCommand(new StringType("fancyON")), is(OpenClosedType.OPEN));
171 // Test basic formatting
172 assertThat(v.getMQTTpublishValue(OpenClosedType.CLOSED, null), is("fancyOff"));
173 assertThat(v.getMQTTpublishValue(OpenClosedType.OPEN, null), is("fancyON"));
175 assertThat(v.parseMessage(new StringType("")), is(UnDefType.NULL));
179 public void numberUpdate() {
180 NumberValue v = new NumberValue(null, null, new BigDecimal(10), Units.WATT);
182 // Test with command with units
183 Command command = v.parseCommand(new QuantityType<>(20, Units.WATT));
184 assertThat(command, is(new QuantityType<>(20, Units.WATT)));
185 assertThat(v.getMQTTpublishValue(command, null), is("20"));
186 command = v.parseCommand(new QuantityType<>(20, MetricPrefix.KILO(Units.WATT)));
187 assertThat(command, is(new QuantityType<>(20, MetricPrefix.KILO(Units.WATT))));
188 assertThat(v.getMQTTpublishValue(command, null), is("20000"));
190 // Test with command without units
191 command = v.parseCommand(new QuantityType<>("20"));
192 assertThat(command, is(new QuantityType<>(20, Units.WATT)));
193 assertThat(v.getMQTTpublishValue(command, null), is("20"));
195 assertThat(v.parseMessage(new StringType("NaN")), is(UnDefType.UNDEF));
196 assertThat(v.parseMessage(new StringType("nan")), is(UnDefType.UNDEF));
197 assertThat(v.parseMessage(new StringType("-NaN")), is(UnDefType.UNDEF));
198 assertThat(v.parseMessage(new StringType("-nan")), is(UnDefType.UNDEF));
200 assertThat(v.parseMessage(new StringType("")), is(UnDefType.NULL));
204 public void numberUpdateMireds() {
205 NumberValue v = new NumberValue(null, null, new BigDecimal(10), Units.MIRED);
207 Command command = v.parseCommand(new QuantityType<>(2700, Units.KELVIN));
208 assertThat(v.getMQTTpublishValue(command, "%.0f"), is("370"));
212 public void numberPercentageUpdate() {
213 NumberValue v = new NumberValue(null, null, new BigDecimal(10), Units.PERCENT);
215 // Test with command with units
216 Command command = v.parseCommand(new QuantityType<>(20, Units.PERCENT));
217 assertThat(command, is(new QuantityType<>(20, Units.PERCENT)));
218 assertThat(v.getMQTTpublishValue(command, null), is("20"));
220 // Test with command with units.ONE
221 command = v.parseCommand(new QuantityType<>("0.2"));
222 assertThat(command, is(new QuantityType<>(20, Units.PERCENT)));
223 assertThat(v.getMQTTpublishValue(command, null), is("20"));
225 // Test with command with DecimalType
226 command = v.parseCommand(new DecimalType(20));
227 assertThat(command, is(new QuantityType<>(20, Units.PERCENT)));
228 assertThat(v.getMQTTpublishValue(command, null), is("20"));
232 public void rollershutterUpdateWithStrings() {
233 RollershutterValue v = new RollershutterValue("fancyON", "fancyOff", "fancyStop");
234 // Test with UP/DOWN/STOP command
235 assertThat(v.parseCommand(UpDownType.UP), is(UpDownType.UP));
236 assertThat(v.getMQTTpublishValue(UpDownType.UP, null), is("fancyON"));
237 assertThat(v.parseCommand(UpDownType.DOWN), is(UpDownType.DOWN));
238 assertThat(v.getMQTTpublishValue(UpDownType.DOWN, null), is("fancyOff"));
239 assertThat(v.parseCommand(StopMoveType.STOP), is(StopMoveType.STOP));
240 assertThat(v.getMQTTpublishValue(StopMoveType.STOP, null), is("fancyStop"));
242 // Test with custom string
243 assertThat(v.parseCommand(new StringType("fancyON")), is(UpDownType.UP));
244 assertThat(v.parseCommand(new StringType("fancyOff")), is(UpDownType.DOWN));
246 // Test with exact percent
247 Command command = new PercentType(27);
248 assertThat(v.parseCommand(command), is(command));
249 assertThat(v.getMQTTpublishValue(command, null), is("27"));
251 // Test formatting 0/100
252 assertThat(v.getMQTTpublishValue(PercentType.ZERO, null), is("fancyON"));
253 assertThat(v.getMQTTpublishValue(PercentType.HUNDRED, null), is("fancyOff"));
255 // Test parsing from MQTT
256 assertThat(v.parseMessage(new StringType("fancyON")), is(UpDownType.UP));
257 assertThat(v.parseMessage(new StringType("fancyOff")), is(UpDownType.DOWN));
259 assertThat(v.parseMessage(new StringType("")), is(UnDefType.NULL));
263 public void rollershutterUpdateWithDiscreteCommandAndStateStrings() {
264 RollershutterValue v = new RollershutterValue("OPEN", "CLOSE", "STOP", "open", "closed", false, true);
265 // Test with UP/DOWN/STOP command
266 assertThat(v.parseCommand(UpDownType.UP), is(UpDownType.UP));
267 assertThat(v.getMQTTpublishValue(UpDownType.UP, null), is("OPEN"));
268 assertThat(v.parseCommand(UpDownType.DOWN), is(UpDownType.DOWN));
269 assertThat(v.getMQTTpublishValue(UpDownType.DOWN, null), is("CLOSE"));
270 assertThat(v.parseCommand(StopMoveType.STOP), is(StopMoveType.STOP));
271 assertThat(v.getMQTTpublishValue(StopMoveType.STOP, null), is("STOP"));
273 // Test with custom string
274 assertThat(v.parseCommand(new StringType("OPEN")), is(UpDownType.UP));
275 assertThat(v.parseCommand(new StringType("CLOSE")), is(UpDownType.DOWN));
277 // Test with exact percent
278 Command command = new PercentType(27);
279 assertThat(v.parseCommand(command), is(command));
280 assertThat(v.getMQTTpublishValue(command, null), is("27"));
282 // Test formatting 0/100
283 assertThat(v.getMQTTpublishValue(PercentType.ZERO, null), is("OPEN"));
284 assertThat(v.getMQTTpublishValue(PercentType.HUNDRED, null), is("CLOSE"));
286 // Test parsing from MQTT
287 assertThat(v.parseMessage(new StringType("open")), is(UpDownType.UP));
288 assertThat(v.parseMessage(new StringType("closed")), is(UpDownType.DOWN));
292 public void rollershutterUpdateWithOutStrings() {
293 RollershutterValue v = new RollershutterValue(null, null, "fancyStop");
295 assertThat(v.parseCommand(UpDownType.UP), is(PercentType.ZERO));
296 assertThat(v.parseCommand(UpDownType.DOWN), is(PercentType.HUNDRED));
298 // Test with custom string
299 // Test formatting 0/100
300 assertThat(v.getMQTTpublishValue(PercentType.ZERO, null), is("0"));
301 assertThat(v.getMQTTpublishValue(PercentType.HUNDRED, null), is("100"));
305 public void percentCalc() {
306 PercentageValue v = new PercentageValue(new BigDecimal(10.0), new BigDecimal(110.0), new BigDecimal(1.0), null,
308 assertThat(v.parseCommand(new DecimalType("110.0")), is(PercentType.HUNDRED));
309 assertThat(v.getMQTTpublishValue(PercentType.HUNDRED, null), is("110"));
310 assertThat(v.parseCommand(new DecimalType(10.0)), is(PercentType.ZERO));
311 assertThat(v.getMQTTpublishValue(PercentType.ZERO, null), is("10"));
313 assertThat(v.parseCommand(OnOffType.ON), is(PercentType.HUNDRED));
314 assertThat(v.parseCommand(OnOffType.OFF), is(PercentType.ZERO));
318 public void percentMQTTValue() {
319 PercentageValue v = new PercentageValue(null, null, null, null, null);
320 assertThat(v.parseCommand(new DecimalType("10.10000")), is(new PercentType("10.1")));
321 assertThat(v.getMQTTpublishValue(new PercentType("10.1"), null), is("10.1"));
323 for (int i = 0; i <= 100; i++) {
324 command = v.parseCommand(new DecimalType(i));
325 assertThat(v.getMQTTpublishValue(command, null), is("" + i));
328 assertThat(v.parseMessage(new StringType("")), is(UnDefType.NULL));
332 public void percentCustomOnOff() {
333 PercentageValue v = new PercentageValue(new BigDecimal("0.0"), new BigDecimal("100.0"), new BigDecimal("1.0"),
335 assertThat(v.parseCommand(new StringType("on")), is(PercentType.HUNDRED));
336 assertThat(v.parseCommand(new StringType("off")), is(PercentType.ZERO));
340 public void decimalCalc() {
341 PercentageValue v = new PercentageValue(new BigDecimal("0.1"), new BigDecimal("1.0"), new BigDecimal("0.1"),
343 assertThat(v.parseCommand(new DecimalType(1.0)), is(PercentType.HUNDRED));
344 assertThat(v.parseCommand(new DecimalType(0.1)), is(PercentType.ZERO));
345 PercentType command = v.parseCommand(new DecimalType(0.2));
346 assertEquals(command.floatValue(), 11.11f, 0.01f);
350 public void increaseDecreaseCalc() {
351 PercentageValue v = new PercentageValue(new BigDecimal("1.0"), new BigDecimal("11.0"), new BigDecimal("0.5"),
355 PercentType command = v.parseCommand(new DecimalType("6.0"));
356 assertEquals(command.floatValue(), 50.0f, 0.01f);
358 command = v.parseCommand(IncreaseDecreaseType.INCREASE);
359 assertEquals(command.floatValue(), 55.0f, 0.01f);
360 command = v.parseCommand(IncreaseDecreaseType.DECREASE);
361 assertEquals(command.floatValue(), 45.0f, 0.01f);
364 command = v.parseCommand(new DecimalType("1.1"));
365 assertEquals(command.floatValue(), 1.0f, 0.01f);
367 command = v.parseCommand(IncreaseDecreaseType.DECREASE);
368 assertEquals(command.floatValue(), 0.0f, 0.01f);
371 command = v.parseCommand(new DecimalType("10.8"));
372 assertEquals(command.floatValue(), 98.0f, 0.01f);
374 command = v.parseCommand(IncreaseDecreaseType.INCREASE);
375 assertEquals(command.floatValue(), 100.0f, 0.01f);
379 public void upDownCalc() {
380 PercentageValue v = new PercentageValue(new BigDecimal("1.0"), new BigDecimal("11.0"), new BigDecimal("0.5"),
384 PercentType command = v.parseCommand(new DecimalType("6.0"));
385 assertEquals(command.floatValue(), 50.0f, 0.01f);
387 command = v.parseCommand(UpDownType.UP);
388 assertEquals(command.floatValue(), 55.0f, 0.01f);
389 command = v.parseCommand(UpDownType.DOWN);
390 assertEquals(command.floatValue(), 45.0f, 0.01f);
393 command = v.parseCommand(new DecimalType("1.1"));
394 assertEquals(command.floatValue(), 1.0f, 0.01f);
396 command = v.parseCommand(UpDownType.DOWN);
397 assertEquals(command.floatValue(), 0.0f, 0.01f);
400 command = v.parseCommand(new DecimalType("10.8"));
401 assertEquals(command.floatValue(), 98.0f, 0.01f);
403 command = v.parseCommand(UpDownType.UP);
404 assertEquals(command.floatValue(), 100.0f, 0.01f);
408 public void percentCalcInvalid() {
409 PercentageValue v = new PercentageValue(new BigDecimal(10.0), new BigDecimal(110.0), new BigDecimal(1.0), null,
411 assertThrows(IllegalArgumentException.class, () -> v.parseCommand(new DecimalType(9.0)));
415 public void textUpdate() {
416 TextValue v = new TextValue();
418 assertThat(v.parseMessage(new StringType("")), is(new StringType("")));
419 assertThat(v.parseMessage(new StringType("NULL")), is(new StringType("NULL")));
422 assertThat(v.parseMessage(new StringType("")), is(UnDefType.NULL));
423 assertThat(v.parseMessage(new StringType("NULL")), is(new StringType("NULL")));
425 v.setNullValue("NULL");
426 assertThat(v.parseMessage(new StringType("NULL")), is(UnDefType.NULL));
427 assertThat(v.parseMessage(new StringType("")), is(new StringType("")));