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.mybmw.internal.dto.charge;
15 import static org.junit.jupiter.api.Assertions.assertNotNull;
16 import static org.junit.jupiter.api.Assertions.assertTrue;
17 import static org.junit.jupiter.api.Assertions.fail;
18 import static org.mockito.Mockito.mock;
19 import static org.mockito.Mockito.times;
20 import static org.mockito.Mockito.verify;
21 import static org.mockito.Mockito.when;
23 import java.lang.reflect.Field;
24 import java.lang.reflect.Method;
25 import java.time.ZoneId;
26 import java.util.List;
28 import java.util.Optional;
30 import org.eclipse.jdt.annotation.NonNullByDefault;
31 import org.eclipse.jdt.annotation.Nullable;
32 import org.junit.jupiter.api.Test;
33 import org.mockito.ArgumentCaptor;
34 import org.openhab.binding.mybmw.internal.MyBMWConstants.VehicleType;
35 import org.openhab.binding.mybmw.internal.MyBMWVehicleConfiguration;
36 import org.openhab.binding.mybmw.internal.dto.ChargingStatisticsWrapper;
37 import org.openhab.binding.mybmw.internal.handler.MyBMWCommandOptionProvider;
38 import org.openhab.binding.mybmw.internal.handler.VehicleHandler;
39 import org.openhab.binding.mybmw.internal.handler.backend.JsonStringDeserializer;
40 import org.openhab.binding.mybmw.internal.util.FileReader;
41 import org.openhab.binding.mybmw.internal.utils.Constants;
42 import org.openhab.core.i18n.LocationProvider;
43 import org.openhab.core.i18n.TimeZoneProvider;
44 import org.openhab.core.thing.ChannelUID;
45 import org.openhab.core.thing.Thing;
46 import org.openhab.core.thing.ThingUID;
47 import org.openhab.core.thing.binding.ThingHandlerCallback;
48 import org.openhab.core.types.State;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
53 * The {@link ChargingStatisticsTest} is responsible for handling commands, which
55 * sent to one of the channels.
57 * @author Bernd Weymann - Initial contribution
58 * @author Martin Grassl - updated to new vehicles
61 @SuppressWarnings("null")
62 public class ChargingStatisticsTest {
63 private final Logger logger = LoggerFactory.getLogger(VehicleHandler.class);
65 private static final int EXPECTED_UPDATE_COUNT = 3;
68 ArgumentCaptor<ChannelUID> channelCaptor;
70 ArgumentCaptor<State> stateCaptor;
72 ThingHandlerCallback thingHandlerCallback;
74 VehicleHandler vehicleHandler;
76 List<ChannelUID> allChannels;
78 List<State> allStates;
79 String driveTrain = Constants.EMPTY;
83 * Prepare environment for Vehicle Status Updates
85 public void setup(String type, boolean imperial) {
87 this.imperial = imperial;
88 Thing thing = mock(Thing.class);
89 when(thing.getUID()).thenReturn(new ThingUID("testbinding", "test"));
90 MyBMWCommandOptionProvider myBmwCommandOptionProvider = mock(MyBMWCommandOptionProvider.class);
91 LocationProvider locationProvider = mock(LocationProvider.class);
92 TimeZoneProvider timeZoneProvider = mock(TimeZoneProvider.class);
93 when(timeZoneProvider.getTimeZone()).thenReturn(ZoneId.systemDefault());
94 vehicleHandler = new VehicleHandler(thing, myBmwCommandOptionProvider, locationProvider, timeZoneProvider,
96 MyBMWVehicleConfiguration vc = new MyBMWVehicleConfiguration();
97 vc.setVin(Constants.ANONYMOUS);
100 Field vehicleConfigurationField = VehicleHandler.class.getDeclaredField("vehicleConfiguration");
101 vehicleConfigurationField.setAccessible(true);
102 vehicleConfigurationField.set(vehicleHandler, Optional.of(vc));
103 } catch (Exception e) {
104 logger.error("vehicleConfiguration could not be set", e);
105 fail("vehicleConfiguration could not be set", e);
107 thingHandlerCallback = mock(ThingHandlerCallback.class);
108 vehicleHandler.setCallback(thingHandlerCallback);
109 channelCaptor = ArgumentCaptor.forClass(ChannelUID.class);
110 stateCaptor = ArgumentCaptor.forClass(State.class);
113 private boolean testVehicle(String statusContent, int callbacksExpected,
114 Optional<Map<String, State>> concreteChecks) {
115 assertNotNull(statusContent);
118 Method updateChargeStatisticsMethod = VehicleHandler.class.getDeclaredMethod("updateChargingStatistics",
119 ChargingStatisticsContainer.class, String.class);
120 updateChargeStatisticsMethod.setAccessible(true);
121 updateChargeStatisticsMethod.invoke(vehicleHandler,
122 JsonStringDeserializer.getChargingStatistics(statusContent), null);
123 } catch (Exception e) {
124 logger.error("chargeStatistics could not be set", e);
125 fail("chargeStatistics could not be set", e);
127 verify(thingHandlerCallback, times(callbacksExpected)).stateUpdated(channelCaptor.capture(),
128 stateCaptor.capture());
129 allChannels = channelCaptor.getAllValues();
130 allStates = stateCaptor.getAllValues();
132 assertNotNull(driveTrain);
133 ChargingStatisticsWrapper checker = new ChargingStatisticsWrapper(statusContent);
135 return checker.checkResults(allChannels, allStates);
138 private void trace() {
139 for (int i = 0; i < allChannels.size(); i++) {
140 logger.info("Channel {} {}", allChannels.get(i), allStates.get(i));
145 public void testBevIx() {
146 logger.info("{}", Thread.currentThread().getStackTrace()[1].getMethodName());
147 setup(VehicleType.ELECTRIC_REX.toString(), false);
148 String content = FileReader.fileToString("responses/BEV/charging_statistics.json");
149 assertTrue(testVehicle(content, EXPECTED_UPDATE_COUNT, Optional.empty()));
153 public void testBevIX3() {
154 logger.info("{}", Thread.currentThread().getStackTrace()[1].getMethodName());
155 setup(VehicleType.ELECTRIC_REX.toString(), false);
156 String content = FileReader.fileToString("responses/BEV3/charging_statistics.json");
157 assertTrue(testVehicle(content, EXPECTED_UPDATE_COUNT, Optional.empty()));
161 public void testIceX320d() {
162 logger.info("{}", Thread.currentThread().getStackTrace()[1].getMethodName());
163 setup(VehicleType.PLUGIN_HYBRID.toString(), false);
164 String content = FileReader.fileToString("responses/ICE2/charging_statistics.json");
165 assertTrue(testVehicle(content, EXPECTED_UPDATE_COUNT, Optional.empty()));
169 public void testPhev330e() {
170 logger.info("{}", Thread.currentThread().getStackTrace()[1].getMethodName());
171 setup(VehicleType.PLUGIN_HYBRID.toString(), false);
172 String content = FileReader.fileToString("responses/PHEV2/charging_statistics.json");
173 assertTrue(testVehicle(content, EXPECTED_UPDATE_COUNT, Optional.empty()));