]> git.basschouten.com Git - openhab-addons.git/blob
236568f26f9d4516b2090215aa1b781b4dac4228
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.voice.actiontemplatehli.internal;
14
15 import static org.hamcrest.MatcherAssert.assertThat;
16 import static org.hamcrest.core.Is.is;
17 import static org.openhab.voice.actiontemplatehli.internal.ActionTemplateInterpreterConstants.SERVICE_ID;
18
19 import java.io.IOException;
20 import java.util.List;
21 import java.util.Locale;
22 import java.util.Map;
23
24 import org.eclipse.jdt.annotation.NonNullByDefault;
25 import org.junit.jupiter.api.BeforeEach;
26 import org.junit.jupiter.api.Test;
27 import org.mockito.Mock;
28 import org.mockito.Mockito;
29 import org.mockito.MockitoAnnotations;
30 import org.openhab.core.events.EventPublisher;
31 import org.openhab.core.items.GroupItem;
32 import org.openhab.core.items.ItemRegistry;
33 import org.openhab.core.items.Metadata;
34 import org.openhab.core.items.MetadataKey;
35 import org.openhab.core.items.MetadataRegistry;
36 import org.openhab.core.items.events.ItemEventFactory;
37 import org.openhab.core.library.items.NumberItem;
38 import org.openhab.core.library.items.StringItem;
39 import org.openhab.core.library.items.SwitchItem;
40 import org.openhab.core.library.types.DecimalType;
41 import org.openhab.core.library.types.OnOffType;
42 import org.openhab.core.library.types.StringType;
43 import org.openhab.core.types.StateDescriptionFragmentBuilder;
44 import org.openhab.core.types.StateOption;
45 import org.openhab.core.voice.text.InterpretationException;
46 import org.openhab.voice.actiontemplatehli.internal.configuration.ActionTemplateConfiguration;
47 import org.openhab.voice.actiontemplatehli.internal.configuration.ActionTemplateGroupTargets;
48 import org.openhab.voice.actiontemplatehli.internal.configuration.ActionTemplatePlaceholder;
49
50 import com.fasterxml.jackson.databind.ObjectMapper;
51
52 /**
53  * The {@link ActionTemplateInterpreterTest} class contains the tests for the interpreter
54  *
55  * @author Miguel Álvarez - Initial contribution
56  */
57 @NonNullByDefault
58 public class ActionTemplateInterpreterTest {
59     private @Mock @NonNullByDefault({}) ItemRegistry itemRegistryMock;
60     private @Mock @NonNullByDefault({}) MetadataRegistry metadataRegistryMock;
61     private @Mock @NonNullByDefault({}) EventPublisher eventPublisherMock;
62     private @NonNullByDefault({}) ActionTemplateInterpreter interpreter;
63
64     @BeforeEach
65     public void setUp() throws IOException {
66         MockitoAnnotations.openMocks(this);
67         ObjectMapper mapper = new ObjectMapper();
68         // Prepare Switch
69         var switchItem = new SwitchItem("testSwitch");
70         switchItem.setState(OnOffType.OFF);
71         switchItem.setLabel("bedroom light");
72         switchItem.addTag("Light");
73         Mockito.when(itemRegistryMock.get(switchItem.getName())).thenReturn(switchItem);
74         // Prepare Switch Write action
75         var switchNPLWriteAction = new ActionTemplateConfiguration();
76         switchNPLWriteAction.template = "$onOff $itemLabel";
77         switchNPLWriteAction.value = "$onOff";
78         var onOffPlaceholder = new ActionTemplatePlaceholder();
79         onOffPlaceholder.label = "onOff";
80         onOffPlaceholder.nerStaticValues = new String[] { "turn on", "turn off" };
81         onOffPlaceholder.posStaticValues = Map.of("turn__on", "ON", "turn__off", "OFF");
82         switchNPLWriteAction.placeholders = List.of(onOffPlaceholder);
83         // Prepare Switch Read action
84         var switchNPLReadAction = new ActionTemplateConfiguration();
85         switchNPLReadAction.read = true;
86         switchNPLReadAction.template = "how is the $itemLabel";
87         switchNPLReadAction.value = "$itemLabel is $state";
88         // Prepare Group
89         var groupItem = new GroupItem("testGroup");
90         groupItem.setLabel("bedroom");
91         groupItem.addTag("Location");
92         Mockito.when(itemRegistryMock.get(groupItem.getName())).thenReturn(groupItem);
93         // TV channel
94         var numberItem = new NumberItem("testNumber");
95         numberItem.setState(DecimalType.valueOf("1"));
96         numberItem.setLabel("channel");
97         numberItem.addTag("tv_channel");
98         numberItem
99                 .setStateDescriptionService((text, locale) -> StateDescriptionFragmentBuilder
100                         .create().withOptions(List.of(new StateOption("1", "channel one"),
101                                 new StateOption("2", "channel two"), new StateOption("3", "channel three")))
102                         .build().toStateDescription());
103         Mockito.when(itemRegistryMock.get(numberItem.getName())).thenReturn(numberItem);
104         // Prepare Group Write action
105         var groupNPLWriteAction = new ActionTemplateConfiguration();
106         groupNPLWriteAction.template = "turn on $itemLabel lights";
107         groupNPLWriteAction.requiredItemTags = new String[] { "Location" };
108         groupNPLWriteAction.value = "ON";
109         groupNPLWriteAction.memberTargets = new ActionTemplateGroupTargets();
110         groupNPLWriteAction.memberTargets.itemType = "Switch";
111         groupNPLWriteAction.memberTargets.requiredItemTags = new String[] { "Light" };
112         // Prepare Group Read action
113         var groupNPLReadAction = new ActionTemplateConfiguration();
114         groupNPLReadAction.read = true;
115         groupNPLReadAction.requiredItemTags = new String[] { "Location" };
116         groupNPLReadAction.template = "how is the light in the $itemLabel";
117         groupNPLReadAction.value = "$itemLabel in $groupLabel is $state";
118         var statePlaceholder = new ActionTemplatePlaceholder();
119         statePlaceholder.label = "state";
120         statePlaceholder.posStaticValues = Map.of("ON", "on", "OFF", "off");
121         groupNPLReadAction.placeholders = List.of(statePlaceholder);
122         groupNPLReadAction.memberTargets = new ActionTemplateGroupTargets();
123         groupNPLReadAction.memberTargets.itemName = switchItem.getName();
124         groupNPLReadAction.memberTargets.requiredItemTags = new String[] { "Light" };
125         // Prepare group write action using item option
126         var groupNPLOptionWriteAction = new ActionTemplateConfiguration();
127         groupNPLOptionWriteAction.template = "set $itemLabel channel to $itemOption";
128         groupNPLOptionWriteAction.requiredItemTags = new String[] { "Location" };
129         groupNPLOptionWriteAction.value = "$itemOption";
130         groupNPLOptionWriteAction.memberTargets = new ActionTemplateGroupTargets();
131         groupNPLOptionWriteAction.memberTargets.itemType = "Number";
132         groupNPLOptionWriteAction.memberTargets.requiredItemTags = new String[] { "tv_channel" };
133         // Prepare group read action using item option
134         var groupNPLOptionReadAction = new ActionTemplateConfiguration();
135         groupNPLOptionReadAction.read = true;
136         groupNPLOptionReadAction.requiredItemTags = new String[] { "Location" };
137         groupNPLOptionReadAction.template = "what channel is on the $itemLabel tv";
138         groupNPLOptionReadAction.value = "$groupLabel tv is on $itemOption";
139         groupNPLOptionReadAction.memberTargets = new ActionTemplateGroupTargets();
140         groupNPLOptionReadAction.memberTargets.itemType = "Number";
141         groupNPLOptionReadAction.memberTargets.requiredItemTags = new String[] { "tv_channel" };
142         // Add switch member to group
143         groupItem.addMember(switchItem);
144         // Add number member to group
145         groupItem.addMember(numberItem);
146         // Prepare string
147         var stringItem = new StringItem("testString");
148         stringItem.setLabel("message example");
149         Mockito.when(itemRegistryMock.get(stringItem.getName())).thenReturn(stringItem);
150         // Prepare string write action
151         var stringNPLWriteAction = new ActionTemplateConfiguration();
152         stringNPLWriteAction.template = "send message $* to $contact";
153         stringNPLWriteAction.value = "$contact:$*";
154         stringNPLWriteAction.silent = true;
155         var contactPlaceholder = new ActionTemplatePlaceholder();
156         contactPlaceholder.label = "contact";
157         contactPlaceholder.nerStaticValues = new String[] { "Mark", "Andrea" };
158         contactPlaceholder.posStaticValues = Map.of("Mark", "+34000000000", "Andrea", "+34000000001");
159         stringNPLWriteAction.placeholders = List.of(contactPlaceholder);
160         var stringConfig = mapper.readValue(mapper.writeValueAsString(stringNPLWriteAction), Map.class);
161         // Mock metadata for 'testString'
162         Mockito.when(metadataRegistryMock.get(new MetadataKey(SERVICE_ID, stringItem.getName())))
163                 .thenReturn(new Metadata(new MetadataKey(SERVICE_ID, stringItem.getName()), "", stringConfig));
164         // Mock items
165         Mockito.when(itemRegistryMock.getAll()).thenReturn(List.of(switchItem, stringItem, groupItem, numberItem));
166
167         interpreter = new ActionTemplateInterpreter(itemRegistryMock, metadataRegistryMock, eventPublisherMock) {
168             @Override
169             protected ActionTemplateConfiguration[] getTypeActionConfigs(String itemType) {
170                 // mock type actions for testing
171                 if ("Switch".equals(itemType)) {
172                     return new ActionTemplateConfiguration[] { switchNPLWriteAction, switchNPLReadAction };
173                 }
174                 if ("Group".equals(itemType)) {
175                     return new ActionTemplateConfiguration[] { groupNPLWriteAction, groupNPLReadAction,
176                             groupNPLOptionReadAction, groupNPLOptionWriteAction };
177                 }
178                 return new ActionTemplateConfiguration[] {};
179             }
180         };
181     }
182
183     /**
184      * Test type write action
185      */
186     @Test
187     public void switchItemOnOffTest() throws InterpretationException {
188         var response = interpreter.interpret(Locale.ENGLISH, "turn on bedroom light");
189         assertThat(response, is("Done"));
190         Mockito.verify(eventPublisherMock).post(ItemEventFactory.createCommandEvent("testSwitch", OnOffType.ON));
191         response = interpreter.interpret(Locale.ENGLISH, "turn off bedroom light");
192         assertThat(response, is("Done"));
193         Mockito.verify(eventPublisherMock).post(ItemEventFactory.createCommandEvent("testSwitch", OnOffType.OFF));
194     }
195
196     /**
197      * Test type read action
198      */
199     @Test
200     public void switchItemReadTest() throws InterpretationException {
201         var response = interpreter.interpret(Locale.ENGLISH, "how is the bedroom light");
202         assertThat(response, is("bedroom light is OFF"));
203     }
204
205     /**
206      * Test group write action targeting members
207      */
208     @Test
209     public void groupItemMemberOnTest() throws InterpretationException {
210         var response = interpreter.interpret(Locale.ENGLISH, "turn on bedroom lights");
211         assertThat(response, is("Done"));
212         Mockito.verify(eventPublisherMock).post(ItemEventFactory.createCommandEvent("testSwitch", OnOffType.ON));
213     }
214
215     /**
216      * Test group read action targeting members
217      */
218     @Test
219     public void groupItemMemberReadTest() throws InterpretationException {
220         var response = interpreter.interpret(Locale.ENGLISH, "how is the light in the bedroom");
221         assertThat(response, is("bedroom light in bedroom is off"));
222     }
223
224     /**
225      * Test target a group member item using the itemOption placeholder
226      */
227     @Test
228     public void groupItemOptionTest() throws InterpretationException {
229         var response = interpreter.interpret(Locale.ENGLISH, "what channel is on the bedroom tv");
230         assertThat(response, is("bedroom tv is on channel one"));
231         response = interpreter.interpret(Locale.ENGLISH, "set bedroom channel to channel two");
232         assertThat(response, is("Done"));
233         Mockito.verify(eventPublisherMock)
234                 .post(ItemEventFactory.createCommandEvent("testNumber", new DecimalType("2")));
235     }
236
237     /**
238      * Test write action using the dynamic label
239      */
240     @Test
241     public void messageTest() throws InterpretationException {
242         var response = interpreter.interpret(Locale.ENGLISH, "send message please turn off the bedroom light to mark");
243         // silent mode is enabled so no response
244         assertThat(response, is(""));
245         Mockito.verify(eventPublisherMock).post(ItemEventFactory.createCommandEvent("testString",
246                 new StringType("+34000000000:please turn off the bedroom light")));
247     }
248 }