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.boschshc.internal.discovery;
15 import static org.hamcrest.CoreMatchers.is;
16 import static org.hamcrest.CoreMatchers.nullValue;
17 import static org.hamcrest.MatcherAssert.assertThat;
18 import static org.junit.jupiter.api.Assertions.assertNull;
19 import static org.junit.jupiter.api.Assertions.assertTrue;
20 import static org.mockito.ArgumentMatchers.any;
21 import static org.mockito.Mockito.mock;
22 import static org.mockito.Mockito.never;
23 import static org.mockito.Mockito.times;
24 import static org.mockito.Mockito.verify;
25 import static org.mockito.Mockito.when;
27 import java.util.ArrayList;
28 import java.util.UUID;
30 import org.eclipse.jdt.annotation.NonNullByDefault;
31 import org.junit.jupiter.api.BeforeEach;
32 import org.junit.jupiter.api.Test;
33 import org.junit.jupiter.api.extension.ExtendWith;
34 import org.mockito.ArgumentCaptor;
35 import org.mockito.Captor;
36 import org.mockito.Mock;
37 import org.mockito.junit.jupiter.MockitoExtension;
38 import org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants;
39 import org.openhab.binding.boschshc.internal.devices.bridge.BridgeHandler;
40 import org.openhab.binding.boschshc.internal.devices.bridge.dto.Device;
41 import org.openhab.binding.boschshc.internal.devices.bridge.dto.Room;
42 import org.openhab.binding.boschshc.internal.devices.bridge.dto.UserDefinedState;
43 import org.openhab.core.config.discovery.DiscoveryListener;
44 import org.openhab.core.config.discovery.DiscoveryResult;
45 import org.openhab.core.config.discovery.DiscoveryService;
46 import org.openhab.core.thing.Bridge;
47 import org.openhab.core.thing.ThingUID;
50 * Unit tests for {@link ThingDiscoveryService}.
52 * @author Gerd Zanker - Initial contribution
54 @ExtendWith(MockitoExtension.class)
56 class ThingDiscoveryServiceTest {
58 private @NonNullByDefault({}) ThingDiscoveryService fixture;
60 private @Mock @NonNullByDefault({}) BridgeHandler bridgeHandler;
61 private @Mock @NonNullByDefault({}) DiscoveryListener discoveryListener;
62 private @Captor @NonNullByDefault({}) ArgumentCaptor<DiscoveryService> discoveryServiceCaptor;
63 private @Captor @NonNullByDefault({}) ArgumentCaptor<DiscoveryResult> discoveryResultCaptor;
67 fixture = new ThingDiscoveryService();
68 fixture.addDiscoveryListener(discoveryListener);
69 fixture.setThingHandler(bridgeHandler);
72 private void mockBridgeCalls() {
73 // Set the Mock Bridge as the ThingHandler
74 ThingUID bridgeUID = new ThingUID(BoschSHCBindingConstants.THING_TYPE_SHC, "testSHC");
75 Bridge mockBridge = mock(Bridge.class);
76 when(mockBridge.getUID()).thenReturn(bridgeUID);
77 when(bridgeHandler.getThing()).thenReturn(mockBridge);
81 void testStartScan() throws InterruptedException {
87 verify(bridgeHandler).getRooms();
88 verify(bridgeHandler).getDevices();
95 void testStartScanWithoutBridgeHandler() {
98 // No fixture.setThingHandler(bridgeHandler);
102 // bridgeHandler not called, just no exception expected
104 fixture.deactivate();
108 void testSetGetThingHandler() {
109 fixture.setThingHandler(bridgeHandler);
110 assertThat(fixture.getThingHandler(), is(bridgeHandler));
114 void testAddDevices() {
117 ArrayList<Device> devices = new ArrayList<>();
118 ArrayList<Room> emptyRooms = new ArrayList<>();
120 Device device1 = new Device();
121 device1.deviceModel = "TWINGUARD";
122 device1.id = "testDevice:ID";
123 device1.name = "Test Name";
124 devices.add(device1);
125 Device device2 = new Device();
126 device2.deviceModel = "TWINGUARD";
127 device2.id = "testDevice:2";
128 device2.name = "Second device";
129 devices.add(device2);
131 verify(discoveryListener, never()).thingDiscovered(any(), any());
133 fixture.addDevices(devices, emptyRooms);
135 // two calls for the two devices expected
136 verify(discoveryListener, times(2)).thingDiscovered(any(), any());
140 void testAddDevicesWithNoDevices() {
141 ArrayList<Device> emptyDevices = new ArrayList<>();
142 ArrayList<Room> emptyRooms = new ArrayList<>();
144 verify(discoveryListener, never()).thingDiscovered(any(), any());
146 fixture.addDevices(emptyDevices, emptyRooms);
148 // nothing shall be discovered, but also no exception shall be thrown
149 verify(discoveryListener, never()).thingDiscovered(any(), any());
153 void testAddDevice() {
156 Device device = new Device();
157 device.deviceModel = "TWINGUARD";
158 device.id = "testDevice:ID";
159 device.name = "Test Name";
160 fixture.addDevice(device, "TestRoom");
162 verify(discoveryListener).thingDiscovered(discoveryServiceCaptor.capture(), discoveryResultCaptor.capture());
164 assertThat(discoveryServiceCaptor.getValue().getClass(), is(ThingDiscoveryService.class));
165 DiscoveryResult result = discoveryResultCaptor.getValue();
166 assertThat(result.getBindingId(), is(BoschSHCBindingConstants.BINDING_ID));
167 assertThat(result.getThingTypeUID(), is(BoschSHCBindingConstants.THING_TYPE_TWINGUARD));
168 assertThat(result.getThingUID().getId(), is("testDevice_ID"));
169 assertThat(result.getBridgeUID().getId(), is("testSHC"));
170 assertThat(result.getLabel(), is("Test Name"));
171 assertThat(String.valueOf(result.getProperties().get("Location")), is("TestRoom"));
175 void testAddDeviceWithNiceNameAndAppendedRoomName() {
176 assertDeviceNiceName("-RoomClimateControl-", "TestRoom", "Room Climate Control TestRoom");
180 void testAddDeviceWithNiceNameWithEmtpyRoomName() {
181 assertDeviceNiceName("-RoomClimateControl-", "", "Room Climate Control");
185 void testAddDeviceWithNiceNameWithoutAppendingRoomName() {
186 assertDeviceNiceName("-SmokeDetectionSystem-", "TestRoom", "Smoke Detection System");
190 void testAddDeviceWithNiceNameWithoutUsualName() {
191 assertDeviceNiceName("My other device", "TestRoom", "My other device");
194 private void assertDeviceNiceName(String deviceName, String roomName, String expectedNiceName) {
197 Device device = new Device();
198 device.deviceModel = "TWINGUARD";
199 device.id = "testDevice:ID";
200 device.name = deviceName;
201 fixture.addDevice(device, roomName);
202 verify(discoveryListener).thingDiscovered(discoveryServiceCaptor.capture(), discoveryResultCaptor.capture());
203 assertThat(discoveryServiceCaptor.getValue().getClass(), is(ThingDiscoveryService.class));
204 DiscoveryResult result = discoveryResultCaptor.getValue();
205 assertThat(result.getLabel(), is(expectedNiceName));
209 void testGetRoomForDevice() {
210 Device device = new Device();
212 ArrayList<Room> rooms = new ArrayList<>();
213 Room room1 = new Room();
215 room1.name = "Room1";
217 Room room2 = new Room();
219 room2.name = "Room 2";
222 device.roomId = "r1";
223 assertThat(fixture.getRoomNameForDevice(device, rooms), is("Room1"));
225 device.roomId = "r2";
226 assertThat(fixture.getRoomNameForDevice(device, rooms), is("Room 2"));
228 device.roomId = "unknown";
229 assertTrue(fixture.getRoomNameForDevice(device, rooms).isEmpty());
233 void testGetThingTypeUID() {
234 Device device = new Device();
236 device.deviceModel = "invalid";
237 assertNull(fixture.getThingTypeUID(device));
239 // just two spot checks
240 device.deviceModel = "BBL";
241 assertThat(fixture.getThingTypeUID(device), is(BoschSHCBindingConstants.THING_TYPE_SHUTTER_CONTROL));
242 device.deviceModel = "TWINGUARD";
243 assertThat(fixture.getThingTypeUID(device), is(BoschSHCBindingConstants.THING_TYPE_TWINGUARD));
247 void testAddUserDefinedStates() {
250 ArrayList<UserDefinedState> userStates = new ArrayList<>();
252 UserDefinedState userState1 = new UserDefinedState();
253 userState1.setId(UUID.randomUUID().toString());
254 userState1.setName("first defined state");
255 userState1.setState(true);
256 UserDefinedState userState2 = new UserDefinedState();
257 userState2.setId(UUID.randomUUID().toString());
258 userState2.setName("another defined state");
259 userState2.setState(false);
260 userStates.add(userState1);
261 userStates.add(userState2);
263 verify(discoveryListener, never()).thingDiscovered(any(), any());
265 fixture.addUserStates(userStates);
267 // two calls for the two devices expected
268 verify(discoveryListener, times(2)).thingDiscovered(any(), any());
272 void getThingTypeUIDLightControl2ChildDevice() {
273 Device device = new Device();
274 device.deviceModel = ThingDiscoveryService.DEVICE_MODEL_LIGHT_CONTROL_CHILD_DEVICE;
276 assertThat(fixture.getThingTypeUID(device), is(nullValue()));