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.console;
15 import static org.hamcrest.CoreMatchers.is;
16 import static org.hamcrest.MatcherAssert.assertThat;
17 import static org.hamcrest.Matchers.allOf;
18 import static org.hamcrest.Matchers.containsString;
19 import static org.mockito.ArgumentMatchers.any;
20 import static org.mockito.Mockito.*;
22 import java.io.IOException;
23 import java.nio.file.Files;
24 import java.nio.file.Path;
25 import java.nio.file.Paths;
26 import java.util.ArrayList;
27 import java.util.Arrays;
28 import java.util.Collections;
29 import java.util.List;
30 import java.util.concurrent.ExecutionException;
31 import java.util.concurrent.TimeoutException;
32 import java.util.stream.Collectors;
34 import org.eclipse.jdt.annotation.NonNullByDefault;
35 import org.junit.jupiter.api.BeforeEach;
36 import org.junit.jupiter.api.Test;
37 import org.junit.jupiter.api.extension.ExtendWith;
38 import org.mockito.Mock;
39 import org.mockito.junit.jupiter.MockitoExtension;
40 import org.openhab.binding.boschshc.internal.devices.bridge.BridgeHandler;
41 import org.openhab.binding.boschshc.internal.devices.bridge.dto.Device;
42 import org.openhab.binding.boschshc.internal.devices.bridge.dto.PublicInformation;
43 import org.openhab.binding.boschshc.internal.devices.bridge.dto.SoftwareUpdateState;
44 import org.openhab.binding.boschshc.internal.exceptions.BoschSHCException;
45 import org.openhab.core.io.console.Console;
46 import org.openhab.core.thing.Bridge;
47 import org.openhab.core.thing.Thing;
48 import org.openhab.core.thing.ThingRegistry;
51 * Unit tests for Console command to list Bosch SHC devices and openhab support.
53 * @author Gerd Zanker - Initial contribution
55 @ExtendWith(MockitoExtension.class)
57 class BoschShcCommandExtensionTest {
59 private @NonNullByDefault({}) BoschShcCommandExtension fixture;
61 private @Mock @NonNullByDefault({}) ThingRegistry thingRegistry;
65 fixture = new BoschShcCommandExtension(thingRegistry);
70 // only sanity checks, content is tested with the functions called by execute
71 Console consoleMock = mock(Console.class);
72 when(thingRegistry.getAll()).thenReturn(Collections.emptyList());
74 fixture.execute(new String[] {}, consoleMock);
75 verify(consoleMock, times(5)).printUsage(any());
76 fixture.execute(new String[] { "" }, consoleMock);
77 verify(consoleMock, times(10)).printUsage(any());
79 fixture.execute(new String[] { BoschShcCommandExtension.SHOW_BINDINGINFO }, consoleMock);
80 verify(consoleMock, atLeastOnce()).print(any());
81 fixture.execute(new String[] { BoschShcCommandExtension.SHOW_DEVICES }, consoleMock);
82 verify(consoleMock, atLeastOnce()).print(any());
83 fixture.execute(new String[] { BoschShcCommandExtension.SHOW_SERVICES }, consoleMock);
84 verify(consoleMock, atLeastOnce()).print(any());
86 fixture.execute(new String[] { BoschShcCommandExtension.GET_BRIDGEINFO }, consoleMock);
87 verify(consoleMock, atLeastOnce()).print(any());
88 fixture.execute(new String[] { BoschShcCommandExtension.GET_DEVICES }, consoleMock);
89 verify(consoleMock, atLeastOnce()).print(any());
94 assertThat(fixture.getCompleter(), is(fixture));
99 List<String> strings = fixture.getUsages();
100 assertThat(strings.size(), is(5));
101 assertThat(strings.get(0), is("boschshc showBindingInfo - list detailed information about this binding"));
102 assertThat(strings.get(1), is("boschshc showDevices - list all devices supported by this binding"));
107 ArrayList<String> candidates = new ArrayList<>();
108 assertThat(fixture.complete(new String[] { "" }, 1, 0, candidates), is(false));
109 assertThat(fixture.complete(new String[] { "" }, 0, 0, candidates), is(true));
110 // for empty arguments, the completer suggest all usage commands
111 assertThat(candidates.size(), is(fixture.getUsages().size()));
115 void printBridgeInfo() throws BoschSHCException, ExecutionException, InterruptedException, TimeoutException {
117 when(thingRegistry.getAll()).thenReturn(Collections.emptyList());
118 assertThat(fixture.buildBridgeInfo(), is(""));
121 PublicInformation publicInformation = new PublicInformation();
122 publicInformation.shcGeneration = "Gen-T";
123 publicInformation.shcIpAddress = "1.2.3.4";
124 publicInformation.softwareUpdateState = new SoftwareUpdateState();
125 Bridge mockBridge = mock(Bridge.class);
126 when(mockBridge.getLabel()).thenReturn("TestLabel");
127 BridgeHandler mockBridgeHandler = mock(BridgeHandler.class);
128 when(mockBridgeHandler.getThing()).thenReturn(mockBridge);
129 when(mockBridgeHandler.getPublicInformation()).thenReturn(publicInformation);
130 Thing mockBridgeThing = mock(Thing.class);
131 when(mockBridgeThing.getHandler()).thenReturn(mockBridgeHandler);
132 when(thingRegistry.getAll()).thenReturn(Collections.singletonList(mockBridgeThing));
133 assertThat(fixture.buildBridgeInfo(),
134 allOf(containsString("Bridge: TestLabel"), containsString("access possible: false"),
135 containsString("SHC Generation: Gen-T"), containsString("IP Address: 1.2.3.4")));
138 PublicInformation publicInformation2 = new PublicInformation();
139 publicInformation2.shcGeneration = "Gen-U";
140 publicInformation2.shcIpAddress = "11.22.33.44";
141 publicInformation2.softwareUpdateState = new SoftwareUpdateState();
142 Bridge mockBridge2 = mock(Bridge.class);
143 when(mockBridge2.getLabel()).thenReturn("Bridge 2");
144 BridgeHandler mockBridgeHandler2 = mock(BridgeHandler.class);
145 when(mockBridgeHandler2.getThing()).thenReturn(mockBridge2);
146 when(mockBridgeHandler2.getPublicInformation()).thenReturn(publicInformation2);
147 Thing mockBridgeThing2 = mock(Thing.class);
148 when(mockBridgeThing2.getHandler()).thenReturn(mockBridgeHandler2);
149 when(thingRegistry.getAll()).thenReturn(Arrays.asList(mockBridgeThing, mockBridgeThing2));
150 assertThat(fixture.buildBridgeInfo(),
151 allOf(containsString("Bridge: TestLabel"), containsString("access possible: false"),
152 containsString("SHC Generation: Gen-T"), containsString("IP Address: 1.2.3.4"),
153 containsString("Bridge: Bridge 2"), containsString("access possible: false"),
154 containsString("SHC Generation: Gen-U"), containsString("IP Address: 11.22.33.44")));
158 void printDeviceInfo() throws InterruptedException {
160 when(thingRegistry.getAll()).thenReturn(Collections.emptyList());
161 assertThat(fixture.buildDeviceInfo(), is(""));
163 // One bridge, No device
164 BridgeHandler mockBridgeHandler = mock(BridgeHandler.class);
165 Thing mockBridgeThing = mock(Thing.class);
166 when(mockBridgeThing.getLabel()).thenReturn("TestLabel");
167 when(mockBridgeThing.getHandler()).thenReturn(mockBridgeHandler);
168 when(thingRegistry.getAll()).thenReturn(Collections.singletonList(mockBridgeThing));
169 assertThat(fixture.buildDeviceInfo(), allOf(containsString("thing: TestLabel"), containsString("devices (0)")));
171 // One bridge, One UNsupported device
172 Device mockShcDevice = mock(Device.class);
173 mockShcDevice.deviceModel = "";
174 mockShcDevice.deviceServiceIds = Collections.emptyList();
175 when(mockBridgeHandler.getDevices()).thenReturn(List.of(mockShcDevice));
176 assertThat(fixture.buildDeviceInfo(), allOf(containsString("thing: TestLabel"), containsString("devices (1)"),
177 containsString("!UNSUPPORTED!")));
179 // One bridge, One supported device
180 mockShcDevice.deviceModel = "TWINGUARD";
181 mockShcDevice.deviceServiceIds = Collections.emptyList();
182 when(mockBridgeHandler.getDevices()).thenReturn(List.of(mockShcDevice));
183 assertThat(fixture.buildDeviceInfo(), allOf(containsString("thing: TestLabel"), containsString("devices (1)"),
184 containsString("TWINGUARD -> twinguard")));
186 // One bridge, One supported device with services
187 mockShcDevice.deviceModel = "TWINGUARD";
188 mockShcDevice.deviceServiceIds = List.of("unknownService", "batterylevel");
189 when(mockBridgeHandler.getDevices()).thenReturn(List.of(mockShcDevice));
190 assertThat(fixture.buildDeviceInfo(), allOf(containsString("thing: TestLabel"), containsString("devices (1)"),
191 containsString("TWINGUARD -> twinguard"), containsString("service: unknownService -> !UNSUPPORTED!"),
192 containsString("batterylevel -> batterylevel")));
196 void printBindingInfo() {
197 assertThat(fixture.buildBindingInfo(), containsString("Bosch SHC Binding"));
201 void printSupportedDevices() {
202 assertThat(fixture.buildSupportedDeviceStatus(),
203 allOf(containsString("Supported Devices"), containsString("BBL = boschshc:shutter-control")));
207 void printSupportedServices() {
208 assertThat(fixture.buildSupportedServiceStatus(),
209 allOf(containsString("Supported Services"), containsString("airqualitylevel")));
213 * The list of services returned by getAllBoschShcServices() shall match
214 * the implemented services in org.openhab.bindings.boschshc.internal.services.
215 * Because reflection doesn't return all services classes during runtime
216 * this test supports consistency between the lists of services and the implemented services.
219 void getAllBoschShcServices() throws IOException {
220 List<String> services = Files
221 .walk(Paths.get("src/main/java/org/openhab/binding/boschshc/internal/services").toAbsolutePath(), 1)
222 .filter(Files::isDirectory).map(Path::getFileName).map(Path::toString)
223 // exclude folders which no service implementation
224 .filter(name -> !name.equals("dto")).filter(name -> !name.equals("services")).sorted()
225 .collect(Collectors.toList());
226 assertThat(services, is(fixture.getAllBoschShcServices()));