From 3b0c78795d519b8ed8c44c3b31b701e2bfd98855 Mon Sep 17 00:00:00 2001 From: jimtng <2554958+jimtng@users.noreply.github.com> Date: Sat, 18 Jan 2025 01:41:08 +1000 Subject: [PATCH] [basicprofiles] Support double quoted strings in state filter (#18117) Signed-off-by: Jimmy Tanagra --- .../org.openhab.transform.basicprofiles/README.md | 2 +- .../internal/profiles/StateFilterProfile.java | 7 ++++++- .../internal/profiles/StateFilterProfileTest.java | 15 ++++++++++++++- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/bundles/org.openhab.transform.basicprofiles/README.md b/bundles/org.openhab.transform.basicprofiles/README.md index ac6db7b2787..a7538bc8433 100644 --- a/bundles/org.openhab.transform.basicprofiles/README.md +++ b/bundles/org.openhab.transform.basicprofiles/README.md @@ -218,7 +218,7 @@ The `LHS_OPERAND` and the `RHS_OPERAND` can be either one of these: - An item name, which will be evaluated to its state. - A type constant, such as `ON`, `OFF`, `UNDEF`, `NULL`, `OPEN`, `CLOSED`, `PLAY`, `PAUSE`, `UP`, `DOWN`, etc. Note that these are unquoted. -- A String value, enclosed with single quotes, e.g. `'ON'`. +- A String value, enclosed with single or double quotes, e.g. `'ON'`, `"FOO"`. A string value is different to the actual `OnOffType.ON`. To compare against an actual OnOffType, use an unquoted `ON`. - A plain number to represent a `DecimalType`. diff --git a/bundles/org.openhab.transform.basicprofiles/src/main/java/org/openhab/transform/basicprofiles/internal/profiles/StateFilterProfile.java b/bundles/org.openhab.transform.basicprofiles/src/main/java/org/openhab/transform/basicprofiles/internal/profiles/StateFilterProfile.java index c8f88dc7511..bbb483c6f50 100644 --- a/bundles/org.openhab.transform.basicprofiles/src/main/java/org/openhab/transform/basicprofiles/internal/profiles/StateFilterProfile.java +++ b/bundles/org.openhab.transform.basicprofiles/src/main/java/org/openhab/transform/basicprofiles/internal/profiles/StateFilterProfile.java @@ -248,7 +248,7 @@ public class StateFilterProfile implements StateProfile { // Quoted strings are parsed as StringType if (stateString == null || stateString.isEmpty()) { return null; - } else if (stateString.startsWith("'") && stateString.endsWith("'")) { + } else if (isQuotedString(stateString)) { return new StringType(stateString.substring(1, stateString.length() - 1)); } else if (parseFunction(stateString) instanceof FunctionType function) { return function; @@ -258,6 +258,11 @@ public class StateFilterProfile implements StateProfile { return null; } + private boolean isQuotedString(String value) { + return (value.startsWith("'") && value.endsWith("'")) || // + (value.startsWith("\"") && value.endsWith("\"")); + } + @Nullable FunctionType parseFunction(String functionDefinition) { if (!functionDefinition.startsWith("$")) { diff --git a/bundles/org.openhab.transform.basicprofiles/src/test/java/org/openhab/transform/basicprofiles/internal/profiles/StateFilterProfileTest.java b/bundles/org.openhab.transform.basicprofiles/src/test/java/org/openhab/transform/basicprofiles/internal/profiles/StateFilterProfileTest.java index 51db627d46b..ee781be0f49 100644 --- a/bundles/org.openhab.transform.basicprofiles/src/test/java/org/openhab/transform/basicprofiles/internal/profiles/StateFilterProfileTest.java +++ b/bundles/org.openhab.transform.basicprofiles/src/test/java/org/openhab/transform/basicprofiles/internal/profiles/StateFilterProfileTest.java @@ -173,7 +173,7 @@ public class StateFilterProfileTest { } @Test - public void testSingleConditionMatchQuoted() throws ItemNotFoundException { + public void testSingleConditionMatchSingleQuoted() throws ItemNotFoundException { when(mockContext.getConfiguration()).thenReturn(new Configuration(Map.of("conditions", "ItemName eq 'Value'"))); when(mockItemRegistry.getItem("ItemName")).thenReturn(stringItemWithState("ItemName", "Value")); @@ -184,6 +184,19 @@ public class StateFilterProfileTest { verify(mockCallback, times(1)).sendUpdate(eq(expectation)); } + @Test + public void testSingleConditionMatchDoubleQuoted() throws ItemNotFoundException { + when(mockContext.getConfiguration()) + .thenReturn(new Configuration(Map.of("conditions", "ItemName eq \"Value\""))); + when(mockItemRegistry.getItem("ItemName")).thenReturn(stringItemWithState("ItemName", "Value")); + + StateFilterProfile profile = new StateFilterProfile(mockCallback, mockContext, mockItemRegistry); + + State expectation = new StringType("NewValue"); + profile.onStateUpdateFromHandler(expectation); + verify(mockCallback, times(1)).sendUpdate(eq(expectation)); + } + private Item stringItemWithState(String itemName, String value) { StringItem item = new StringItem(itemName); item.setState(new StringType(value));