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.MatcherAssert.assertThat;
17 import static org.junit.jupiter.api.Assertions.*;
18 import static org.mockito.ArgumentMatchers.any;
19 import static org.mockito.Mockito.*;
21 import java.util.ArrayList;
22 import java.util.UUID;
24 import org.eclipse.jdt.annotation.NonNullByDefault;
25 import org.junit.jupiter.api.BeforeEach;
26 import org.junit.jupiter.api.Test;
27 import org.junit.jupiter.api.extension.ExtendWith;
28 import org.mockito.ArgumentCaptor;
29 import org.mockito.Captor;
30 import org.mockito.Mock;
31 import org.mockito.junit.jupiter.MockitoExtension;
32 import org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants;
33 import org.openhab.binding.boschshc.internal.devices.bridge.BridgeHandler;
34 import org.openhab.binding.boschshc.internal.devices.bridge.dto.Device;
35 import org.openhab.binding.boschshc.internal.devices.bridge.dto.Room;
36 import org.openhab.binding.boschshc.internal.devices.bridge.dto.UserDefinedState;
37 import org.openhab.core.config.discovery.DiscoveryListener;
38 import org.openhab.core.config.discovery.DiscoveryResult;
39 import org.openhab.core.config.discovery.DiscoveryService;
40 import org.openhab.core.thing.Bridge;
41 import org.openhab.core.thing.ThingUID;
44 * ThingDiscoveryService Tester.
46 * @author Gerd Zanker - Initial contribution
48 @ExtendWith(MockitoExtension.class)
50 class ThingDiscoveryServiceTest {
52 private @NonNullByDefault({}) ThingDiscoveryService fixture;
54 private @Mock @NonNullByDefault({}) BridgeHandler bridgeHandler;
55 private @Mock @NonNullByDefault({}) DiscoveryListener discoveryListener;
56 private @Captor @NonNullByDefault({}) ArgumentCaptor<DiscoveryService> discoveryServiceCaptor;
57 private @Captor @NonNullByDefault({}) ArgumentCaptor<DiscoveryResult> discoveryResultCaptor;
61 fixture = new ThingDiscoveryService();
62 fixture.addDiscoveryListener(discoveryListener);
63 fixture.setThingHandler(bridgeHandler);
66 private void mockBridgeCalls() {
67 // Set the Mock Bridge as the ThingHandler
68 ThingUID bridgeUID = new ThingUID(BoschSHCBindingConstants.THING_TYPE_SHC, "testSHC");
69 Bridge mockBridge = mock(Bridge.class);
70 when(mockBridge.getUID()).thenReturn(bridgeUID);
71 when(bridgeHandler.getThing()).thenReturn(mockBridge);
75 void testStartScan() throws InterruptedException {
81 verify(bridgeHandler).getRooms();
82 verify(bridgeHandler).getDevices();
89 void testStartScanWithoutBridgeHandler() {
92 // No fixture.setThingHandler(bridgeHandler);
96 // bridgeHandler not called, just no exception expected
102 void testSetGetThingHandler() {
103 fixture.setThingHandler(bridgeHandler);
104 assertThat(fixture.getThingHandler(), is(bridgeHandler));
108 void testAddDevices() {
111 ArrayList<Device> devices = new ArrayList<>();
112 ArrayList<Room> emptyRooms = new ArrayList<>();
114 Device device1 = new Device();
115 device1.deviceModel = "TWINGUARD";
116 device1.id = "testDevice:ID";
117 device1.name = "Test Name";
118 devices.add(device1);
119 Device device2 = new Device();
120 device2.deviceModel = "TWINGUARD";
121 device2.id = "testDevice:2";
122 device2.name = "Second device";
123 devices.add(device2);
125 verify(discoveryListener, never()).thingDiscovered(any(), any());
127 fixture.addDevices(devices, emptyRooms);
129 // two calls for the two devices expected
130 verify(discoveryListener, times(2)).thingDiscovered(any(), any());
134 void testAddDevicesWithNoDevices() {
135 ArrayList<Device> emptyDevices = new ArrayList<>();
136 ArrayList<Room> emptyRooms = new ArrayList<>();
138 verify(discoveryListener, never()).thingDiscovered(any(), any());
140 fixture.addDevices(emptyDevices, emptyRooms);
142 // nothing shall be discovered, but also no exception shall be thrown
143 verify(discoveryListener, never()).thingDiscovered(any(), any());
147 void testAddDevice() {
150 Device device = new Device();
151 device.deviceModel = "TWINGUARD";
152 device.id = "testDevice:ID";
153 device.name = "Test Name";
154 fixture.addDevice(device, "TestRoom");
156 verify(discoveryListener).thingDiscovered(discoveryServiceCaptor.capture(), discoveryResultCaptor.capture());
158 assertThat(discoveryServiceCaptor.getValue().getClass(), is(ThingDiscoveryService.class));
159 DiscoveryResult result = discoveryResultCaptor.getValue();
160 assertThat(result.getBindingId(), is(BoschSHCBindingConstants.BINDING_ID));
161 assertThat(result.getThingTypeUID(), is(BoschSHCBindingConstants.THING_TYPE_TWINGUARD));
162 assertThat(result.getThingUID().getId(), is("testDevice_ID"));
163 assertThat(result.getBridgeUID().getId(), is("testSHC"));
164 assertThat(result.getLabel(), is("Test Name"));
165 assertThat(String.valueOf(result.getProperties().get("Location")), is("TestRoom"));
169 void testAddDeviceWithNiceNameAndAppendedRoomName() {
170 assertDeviceNiceName("-RoomClimateControl-", "TestRoom", "Room Climate Control TestRoom");
174 void testAddDeviceWithNiceNameWithEmtpyRoomName() {
175 assertDeviceNiceName("-RoomClimateControl-", "", "Room Climate Control");
179 void testAddDeviceWithNiceNameWithoutAppendingRoomName() {
180 assertDeviceNiceName("-SmokeDetectionSystem-", "TestRoom", "Smoke Detection System");
184 void testAddDeviceWithNiceNameWithoutUsualName() {
185 assertDeviceNiceName("My other device", "TestRoom", "My other device");
188 private void assertDeviceNiceName(String deviceName, String roomName, String expectedNiceName) {
191 Device device = new Device();
192 device.deviceModel = "TWINGUARD";
193 device.id = "testDevice:ID";
194 device.name = deviceName;
195 fixture.addDevice(device, roomName);
196 verify(discoveryListener).thingDiscovered(discoveryServiceCaptor.capture(), discoveryResultCaptor.capture());
197 assertThat(discoveryServiceCaptor.getValue().getClass(), is(ThingDiscoveryService.class));
198 DiscoveryResult result = discoveryResultCaptor.getValue();
199 assertThat(result.getLabel(), is(expectedNiceName));
203 void testGetRoomForDevice() {
204 Device device = new Device();
206 ArrayList<Room> rooms = new ArrayList<>();
207 Room room1 = new Room();
209 room1.name = "Room1";
211 Room room2 = new Room();
213 room2.name = "Room 2";
216 device.roomId = "r1";
217 assertThat(fixture.getRoomNameForDevice(device, rooms), is("Room1"));
219 device.roomId = "r2";
220 assertThat(fixture.getRoomNameForDevice(device, rooms), is("Room 2"));
222 device.roomId = "unknown";
223 assertTrue(fixture.getRoomNameForDevice(device, rooms).isEmpty());
227 void testGetThingTypeUID() {
228 Device device = new Device();
230 device.deviceModel = "invalid";
231 assertNull(fixture.getThingTypeUID(device));
233 // just two spot checks
234 device.deviceModel = "BBL";
235 assertThat(fixture.getThingTypeUID(device), is(BoschSHCBindingConstants.THING_TYPE_SHUTTER_CONTROL));
236 device.deviceModel = "TWINGUARD";
237 assertThat(fixture.getThingTypeUID(device), is(BoschSHCBindingConstants.THING_TYPE_TWINGUARD));
241 void testAddUserDefinedStates() {
244 ArrayList<UserDefinedState> userStates = new ArrayList<>();
246 UserDefinedState userState1 = new UserDefinedState();
247 userState1.setId(UUID.randomUUID().toString());
248 userState1.setName("first defined state");
249 userState1.setState(true);
250 UserDefinedState userState2 = new UserDefinedState();
251 userState2.setId(UUID.randomUUID().toString());
252 userState2.setName("another defined state");
253 userState2.setState(false);
254 userStates.add(userState1);
255 userStates.add(userState2);
257 verify(discoveryListener, never()).thingDiscovered(any(), any());
259 fixture.addUserStates(userStates);
261 // two calls for the two devices expected
262 verify(discoveryListener, times(2)).thingDiscovered(any(), any());