]> git.basschouten.com Git - openhab-addons.git/blob
793307d9f1dc5b55c9c0730face49c084ee81215
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2021 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.binding.bmwconnecteddrive.internal.dto;
14
15 import static org.junit.jupiter.api.Assertions.*;
16 import static org.openhab.binding.bmwconnecteddrive.internal.ConnectedDriveConstants.*;
17
18 import java.util.HashMap;
19 import java.util.List;
20 import java.util.Map;
21
22 import javax.measure.Unit;
23 import javax.measure.quantity.Length;
24 import javax.measure.quantity.Time;
25
26 import org.eclipse.jdt.annotation.NonNullByDefault;
27 import org.eclipse.jdt.annotation.Nullable;
28 import org.openhab.binding.bmwconnecteddrive.internal.ConnectedDriveConstants.VehicleType;
29 import org.openhab.binding.bmwconnecteddrive.internal.dto.status.Doors;
30 import org.openhab.binding.bmwconnecteddrive.internal.dto.status.VehicleStatus;
31 import org.openhab.binding.bmwconnecteddrive.internal.dto.status.VehicleStatusContainer;
32 import org.openhab.binding.bmwconnecteddrive.internal.dto.status.Windows;
33 import org.openhab.binding.bmwconnecteddrive.internal.utils.Constants;
34 import org.openhab.binding.bmwconnecteddrive.internal.utils.Converter;
35 import org.openhab.binding.bmwconnecteddrive.internal.utils.VehicleStatusUtils;
36 import org.openhab.core.library.types.DateTimeType;
37 import org.openhab.core.library.types.PointType;
38 import org.openhab.core.library.types.QuantityType;
39 import org.openhab.core.library.types.StringType;
40 import org.openhab.core.library.unit.ImperialUnits;
41 import org.openhab.core.library.unit.Units;
42 import org.openhab.core.thing.ChannelUID;
43 import org.openhab.core.types.State;
44 import org.openhab.core.types.UnDefType;
45
46 import com.google.gson.Gson;
47
48 /**
49  * The {@link StatusWrapper} Test json responses from ConnectedDrive Portal
50  *
51  * @author Bernd Weymann - Initial contribution
52  */
53 @NonNullByDefault
54 @SuppressWarnings("null")
55 public class StatusWrapper {
56     private static final Gson GSON = new Gson();
57     private static final Unit<Length> KILOMETRE = Constants.KILOMETRE_UNIT;
58     private static final double ALLOWED_MILE_CONVERSION_DEVIATION = 1.5;
59     private static final double ALLOWED_KM_ROUND_DEVIATION = 0.1;
60
61     private VehicleStatus vStatus;
62     private boolean imperial;
63     private boolean isElectric;
64     private boolean hasFuel;
65     private boolean isHybrid;
66
67     private Map<String, State> specialHandlingMap = new HashMap<String, State>();
68
69     public StatusWrapper(String type, boolean imperial, String statusJson) {
70         this.imperial = imperial;
71         hasFuel = type.equals(VehicleType.CONVENTIONAL.toString()) || type.equals(VehicleType.PLUGIN_HYBRID.toString())
72                 || type.equals(VehicleType.ELECTRIC_REX.toString());
73         isElectric = type.equals(VehicleType.PLUGIN_HYBRID.toString())
74                 || type.equals(VehicleType.ELECTRIC_REX.toString()) || type.equals(VehicleType.ELECTRIC.toString());
75         isHybrid = hasFuel && isElectric;
76         VehicleStatusContainer container = GSON.fromJson(statusJson, VehicleStatusContainer.class);
77         assertNotNull(container);
78         assertNotNull(container.vehicleStatus);
79         vStatus = container.vehicleStatus;
80     }
81
82     /**
83      * Test results auctomatically against json values
84      *
85      * @param channels
86      * @param states
87      * @return
88      */
89     public boolean checkResults(@Nullable List<ChannelUID> channels, @Nullable List<State> states) {
90         assertNotNull(channels);
91         assertNotNull(states);
92         assertTrue(channels.size() == states.size(), "Same list sizes");
93         for (int i = 0; i < channels.size(); i++) {
94             checkResult(channels.get(i), states.get(i));
95         }
96         return true;
97     }
98
99     /**
100      * Add a specific check for a value e.g. hard coded "Upcoming Service" in order to check the right ordering
101      *
102      * @param specialHand
103      * @return
104      */
105     public StatusWrapper append(Map<String, State> compareMap) {
106         specialHandlingMap.putAll(compareMap);
107         return this;
108     }
109
110     @SuppressWarnings({ "unchecked", "rawtypes" })
111     private void checkResult(ChannelUID channelUID, State state) {
112         String cUid = channelUID.getIdWithoutGroup();
113         String gUid = channelUID.getGroupId();
114         QuantityType<Length> qt;
115         QuantityType<Time> qtt;
116         StringType st;
117         StringType wanted;
118         DateTimeType dtt;
119         PointType pt;
120         switch (cUid) {
121             case MILEAGE:
122                 assertTrue(state instanceof QuantityType);
123                 qt = ((QuantityType) state);
124                 if (imperial) {
125                     assertEquals(ImperialUnits.MILE, qt.getUnit(), "Miles");
126                 } else {
127                     assertEquals(KILOMETRE, qt.getUnit(), "KM");
128                 }
129                 switch (gUid) {
130                     case CHANNEL_GROUP_RANGE:
131                         assertEquals(qt.intValue(), vStatus.mileage, "Mileage");
132                         break;
133                     case CHANNEL_GROUP_SERVICE:
134                         if (vStatus.cbsData.isEmpty()) {
135                             assertEquals(qt.intValue(), -1, "Service Mileage");
136                         } else {
137                             assertEquals(qt.intValue(), vStatus.cbsData.get(0).cbsRemainingMileage, "Service Mileage");
138                         }
139                         break;
140                     case CHANNEL_GROUP_CHECK_CONTROL:
141                         if (vStatus.checkControlMessages.isEmpty()) {
142                             assertEquals(qt.intValue(), -1, "CheckControl Mileage");
143                         } else {
144                             assertEquals(qt.intValue(), vStatus.checkControlMessages.get(0).ccmMileage,
145                                     "CheckControl Mileage");
146                         }
147                         break;
148                     default:
149                         assertFalse(true, "Channel " + channelUID + " " + state + " not found");
150                         break;
151                 }
152                 break;
153             case RANGE_ELECTRIC:
154                 assertTrue(isElectric, "Is Eelctric");
155                 assertTrue(state instanceof QuantityType);
156                 qt = ((QuantityType) state);
157                 if (imperial) {
158                     assertEquals(ImperialUnits.MILE, qt.getUnit(), "Miles");
159                     assertEquals(Converter.round(qt.floatValue()), Converter.round(vStatus.remainingRangeElectricMls),
160                             ALLOWED_MILE_CONVERSION_DEVIATION, "Mileage");
161                 } else {
162                     assertEquals(KILOMETRE, qt.getUnit(), "KM");
163                     assertEquals(Converter.round(qt.floatValue()), Converter.round(vStatus.remainingRangeElectric),
164                             ALLOWED_KM_ROUND_DEVIATION, "Mileage");
165                 }
166                 break;
167             case RANGE_ELECTRIC_MAX:
168                 assertTrue(isElectric, "Is Eelctric");
169                 assertTrue(state instanceof QuantityType);
170                 qt = ((QuantityType) state);
171                 if (imperial) {
172                     assertEquals(ImperialUnits.MILE, qt.getUnit(), "Miles");
173                     assertEquals(Converter.round(qt.floatValue()), Converter.round(vStatus.maxRangeElectricMls),
174                             ALLOWED_MILE_CONVERSION_DEVIATION, "Mileage");
175                 } else {
176                     assertEquals(KILOMETRE, qt.getUnit(), "KM");
177                     assertEquals(Converter.round(qt.floatValue()), Converter.round(vStatus.maxRangeElectric),
178                             ALLOWED_KM_ROUND_DEVIATION, "Mileage");
179                 }
180                 break;
181             case RANGE_FUEL:
182                 assertTrue(hasFuel, "Has Fuel");
183                 if (!(state instanceof UnDefType)) {
184                     assertTrue(state instanceof QuantityType);
185                     qt = ((QuantityType) state);
186                     if (imperial) {
187                         assertEquals(ImperialUnits.MILE, qt.getUnit(), "Miles");
188                         assertEquals(Converter.round(qt.floatValue()), Converter.round(vStatus.remainingRangeFuelMls),
189                                 ALLOWED_MILE_CONVERSION_DEVIATION, "Mileage");
190                     } else {
191                         assertEquals(KILOMETRE, qt.getUnit(), "KM");
192                         assertEquals(Converter.round(qt.floatValue()), Converter.round(vStatus.remainingRangeFuel),
193                                 ALLOWED_KM_ROUND_DEVIATION, "Mileage");
194                     }
195                 }
196                 break;
197             case RANGE_HYBRID:
198                 assertTrue(isHybrid, "Is Hybrid");
199                 assertTrue(state instanceof QuantityType);
200                 qt = ((QuantityType) state);
201                 if (imperial) {
202                     assertEquals(ImperialUnits.MILE, qt.getUnit(), "Miles");
203                     assertEquals(Converter.round(qt.floatValue()),
204                             Converter.round(vStatus.remainingRangeElectricMls + vStatus.remainingRangeFuelMls),
205                             ALLOWED_MILE_CONVERSION_DEVIATION, "Mileage");
206                 } else {
207                     assertEquals(KILOMETRE, qt.getUnit(), "KM");
208                     assertEquals(Converter.round(qt.floatValue()),
209                             Converter.round(vStatus.remainingRangeElectric + vStatus.remainingRangeFuel),
210                             ALLOWED_KM_ROUND_DEVIATION, "Mileage");
211                 }
212                 break;
213             case RANGE_HYBRID_MAX:
214                 assertTrue(isHybrid, "Is Hybrid");
215                 assertTrue(state instanceof QuantityType);
216                 qt = ((QuantityType) state);
217                 if (imperial) {
218                     assertEquals(ImperialUnits.MILE, qt.getUnit(), "Miles");
219                     assertEquals(Converter.round(qt.floatValue()),
220                             Converter.round(vStatus.maxRangeElectricMls + vStatus.remainingRangeFuelMls),
221                             ALLOWED_MILE_CONVERSION_DEVIATION, "Mileage");
222                 } else {
223                     assertEquals(KILOMETRE, qt.getUnit(), "KM");
224                     assertEquals(Converter.round(qt.floatValue()),
225                             Converter.round(vStatus.maxRangeElectric + vStatus.remainingRangeFuel),
226                             ALLOWED_KM_ROUND_DEVIATION, "Mileage");
227                 }
228                 break;
229             case REMAINING_FUEL:
230                 assertTrue(hasFuel, "Has Fuel");
231                 assertTrue(state instanceof QuantityType);
232                 qt = ((QuantityType) state);
233                 assertEquals(Units.LITRE, qt.getUnit(), "Liter Unit");
234                 assertEquals(Converter.round(vStatus.remainingFuel), Converter.round(qt.floatValue()), 0.01,
235                         "Fuel Level");
236                 break;
237             case SOC:
238                 assertTrue(isElectric, "Is Eelctric");
239                 assertTrue(state instanceof QuantityType);
240                 qt = ((QuantityType) state);
241                 assertEquals(Units.PERCENT, qt.getUnit(), "Percent");
242                 assertEquals(Converter.round(vStatus.chargingLevelHv), Converter.round(qt.floatValue()), 0.01,
243                         "Charge Level");
244                 break;
245             case SOC_MAX:
246                 assertTrue(isElectric, "Is Eelctric");
247                 assertTrue(state instanceof QuantityType);
248                 qt = ((QuantityType) state);
249                 assertEquals(Units.KILOWATT_HOUR, qt.getUnit(), "kw/h");
250                 assertEquals(Converter.round(vStatus.chargingLevelHv), Converter.round(qt.floatValue()), 0.01,
251                         "SOC Max");
252                 break;
253             case LOCK:
254                 assertTrue(state instanceof StringType);
255                 st = (StringType) state;
256                 assertEquals(Converter.toTitleCase(vStatus.doorLockState), st.toString(), "Vehicle locked");
257                 break;
258             case DOORS:
259                 assertTrue(state instanceof StringType);
260                 st = (StringType) state;
261                 Doors doorState = GSON.fromJson(GSON.toJson(vStatus), Doors.class);
262                 if (doorState != null) {
263                     assertEquals(VehicleStatusUtils.checkClosed(doorState), st.toString(), "Doors Closed");
264                 } else {
265                     assertTrue(false);
266                 }
267
268                 break;
269             case WINDOWS:
270                 assertTrue(state instanceof StringType);
271                 st = (StringType) state;
272                 Windows windowState = GSON.fromJson(GSON.toJson(vStatus), Windows.class);
273                 if (windowState != null) {
274                     if (specialHandlingMap.containsKey(WINDOWS)) {
275                         assertEquals(specialHandlingMap.get(WINDOWS).toString(), st.toString(), "Windows");
276                     } else {
277                         assertEquals(VehicleStatusUtils.checkClosed(windowState), st.toString(), "Windows");
278                     }
279                 } else {
280                     assertTrue(false);
281                 }
282
283                 break;
284             case CHECK_CONTROL:
285                 assertTrue(state instanceof StringType);
286                 st = (StringType) state;
287                 if (specialHandlingMap.containsKey(CHECK_CONTROL)) {
288                     assertEquals(specialHandlingMap.get(CHECK_CONTROL).toString(), st.toString(), "Check Control");
289                 } else {
290                     assertEquals(Converter.toTitleCase(VehicleStatusUtils.checkControlActive(vStatus)), st.toString(),
291                             "Check Control");
292                 }
293                 break;
294             case CHARGE_STATUS:
295                 assertTrue(isElectric, "Is Electric");
296                 assertTrue(state instanceof StringType);
297                 st = (StringType) state;
298                 if (vStatus.chargingStatus.contentEquals(Constants.INVALID)) {
299                     assertEquals(Converter.toTitleCase(vStatus.lastChargingEndReason), st.toString(), "Charge Status");
300                 } else {
301                     assertEquals(Converter.toTitleCase(vStatus.chargingStatus), st.toString(), "Charge Status");
302                 }
303                 break;
304             case CHARGE_REMAINING:
305                 assertTrue(isElectric, "Is Electric");
306                 if (vStatus.chargingTimeRemaining == null) {
307                     assertTrue(state instanceof UnDefType, "expected UndefType");
308                 } else {
309                     assertTrue(state instanceof QuantityType);
310                     qtt = ((QuantityType) state);
311                     assertEquals(qtt.doubleValue(), vStatus.chargingTimeRemaining);
312                     assertEquals(Units.MINUTE, qtt.getUnit(), "Minutes");
313                 }
314                 break;
315             case PLUG_CONNECTION:
316                 assertTrue(state instanceof StringType);
317                 st = (StringType) state;
318                 wanted = StringType.valueOf(Converter.toTitleCase(vStatus.connectionStatus));
319                 assertEquals(wanted.toString(), st.toString(), "Plug Connection State");
320                 break;
321             case LAST_UPDATE:
322                 assertTrue(state instanceof DateTimeType);
323                 dtt = (DateTimeType) state;
324                 DateTimeType expected = DateTimeType
325                         .valueOf(Converter.getLocalDateTime(VehicleStatusUtils.getUpdateTime(vStatus)));
326                 assertEquals(expected.toString(), dtt.toString(), "Last Update");
327                 break;
328             case LAST_UPDATE_REASON:
329                 assertTrue(state instanceof StringType);
330                 st = (StringType) state;
331                 wanted = StringType.valueOf(Converter.toTitleCase(vStatus.updateReason));
332                 assertEquals(wanted.toString(), st.toString(), "Last Update");
333                 break;
334             case GPS:
335                 assertTrue(state instanceof PointType);
336                 pt = (PointType) state;
337                 assertNotNull(vStatus.position);
338                 assertEquals(vStatus.position.getCoordinates(), pt.toString(), "Coordinates");
339                 break;
340             case HEADING:
341                 assertTrue(state instanceof QuantityType);
342                 qt = ((QuantityType) state);
343                 assertEquals(Units.DEGREE_ANGLE, qt.getUnit(), "Angle Unit");
344                 assertNotNull(vStatus.position);
345                 assertEquals(vStatus.position.heading, qt.intValue(), 0.01, "Heading");
346                 break;
347             case RANGE_RADIUS_ELECTRIC:
348                 assertTrue(state instanceof QuantityType);
349                 assertTrue(isElectric);
350                 qt = (QuantityType) state;
351                 if (imperial) {
352                     assertEquals(Converter.guessRangeRadius(vStatus.remainingRangeElectricMls), qt.floatValue(), 1,
353                             "Range Radius Electric mi");
354                 } else {
355                     assertEquals(Converter.guessRangeRadius(vStatus.remainingRangeElectric), qt.floatValue(), 0.1,
356                             "Range Radius Electric km");
357                 }
358                 break;
359             case RANGE_RADIUS_ELECTRIC_MAX:
360                 assertTrue(state instanceof QuantityType);
361                 assertTrue(isElectric);
362                 qt = (QuantityType) state;
363                 if (imperial) {
364                     assertEquals(Converter.guessRangeRadius(vStatus.maxRangeElectricMls), qt.floatValue(), 1,
365                             "Range Radius Electric mi");
366                 } else {
367                     assertEquals(Converter.guessRangeRadius(vStatus.maxRangeElectric), qt.floatValue(), 0.1,
368                             "Range Radius Electric km");
369                 }
370                 break;
371             case RANGE_RADIUS_FUEL:
372                 assertTrue(state instanceof QuantityType);
373                 assertTrue(hasFuel);
374                 qt = (QuantityType) state;
375                 if (imperial) {
376                     assertEquals(Converter.guessRangeRadius(vStatus.remainingRangeFuelMls), qt.floatValue(), 1,
377                             "Range Radius Fuel mi");
378                 } else {
379                     assertEquals(Converter.guessRangeRadius(vStatus.remainingRangeFuel), qt.floatValue(), 0.1,
380                             "Range Radius Fuel km");
381                 }
382                 break;
383             case RANGE_RADIUS_HYBRID:
384                 assertTrue(state instanceof QuantityType);
385                 assertTrue(isHybrid);
386                 qt = (QuantityType) state;
387                 if (imperial) {
388                     assertEquals(
389                             Converter.guessRangeRadius(
390                                     vStatus.remainingRangeElectricMls + vStatus.remainingRangeFuelMls),
391                             qt.floatValue(), ALLOWED_MILE_CONVERSION_DEVIATION, "Range Radius Hybrid mi");
392                 } else {
393                     assertEquals(
394                             Converter.guessRangeRadius(vStatus.remainingRangeElectric + vStatus.remainingRangeFuel),
395                             qt.floatValue(), ALLOWED_KM_ROUND_DEVIATION, "Range Radius Hybrid km");
396                 }
397                 break;
398             case RANGE_RADIUS_HYBRID_MAX:
399                 assertTrue(state instanceof QuantityType);
400                 assertTrue(isHybrid);
401                 qt = (QuantityType) state;
402                 if (imperial) {
403                     assertEquals(
404                             Converter.guessRangeRadius(vStatus.maxRangeElectricMls + vStatus.remainingRangeFuelMls),
405                             qt.floatValue(), ALLOWED_MILE_CONVERSION_DEVIATION, "Range Radius Hybrid Max mi");
406                 } else {
407                     assertEquals(Converter.guessRangeRadius(vStatus.maxRangeElectric + vStatus.remainingRangeFuel),
408                             qt.floatValue(), ALLOWED_KM_ROUND_DEVIATION, "Range Radius Hybrid Max km");
409                 }
410                 break;
411             case DOOR_DRIVER_FRONT:
412                 assertTrue(state instanceof StringType);
413                 st = (StringType) state;
414                 wanted = StringType.valueOf(Converter.toTitleCase(vStatus.doorDriverFront));
415                 assertEquals(wanted.toString(), st.toString(), "Door");
416                 break;
417             case DOOR_DRIVER_REAR:
418                 assertTrue(state instanceof StringType);
419                 st = (StringType) state;
420                 wanted = StringType.valueOf(Converter.toTitleCase(vStatus.doorDriverRear));
421                 assertEquals(wanted.toString(), st.toString(), "Door");
422                 break;
423             case DOOR_PASSENGER_FRONT:
424                 assertTrue(state instanceof StringType);
425                 st = (StringType) state;
426                 wanted = StringType.valueOf(Converter.toTitleCase(vStatus.doorPassengerFront));
427                 assertEquals(wanted.toString(), st.toString(), "Door");
428                 break;
429             case DOOR_PASSENGER_REAR:
430                 assertTrue(state instanceof StringType);
431                 st = (StringType) state;
432                 wanted = StringType.valueOf(Converter.toTitleCase(vStatus.doorPassengerRear));
433                 assertEquals(wanted.toString(), st.toString(), "Door");
434                 break;
435             case TRUNK:
436                 assertTrue(state instanceof StringType);
437                 st = (StringType) state;
438                 wanted = StringType.valueOf(Converter.toTitleCase(vStatus.trunk));
439                 assertEquals(wanted.toString(), st.toString(), "Door");
440                 break;
441             case HOOD:
442                 assertTrue(state instanceof StringType);
443                 st = (StringType) state;
444                 wanted = StringType.valueOf(Converter.toTitleCase(vStatus.hood));
445                 assertEquals(wanted.toString(), st.toString(), "Door");
446                 break;
447             case WINDOW_DOOR_DRIVER_FRONT:
448                 assertTrue(state instanceof StringType);
449                 st = (StringType) state;
450                 wanted = StringType.valueOf(Converter.toTitleCase(vStatus.windowDriverFront));
451                 assertEquals(wanted.toString(), st.toString(), "Window");
452                 break;
453             case WINDOW_DOOR_DRIVER_REAR:
454                 assertTrue(state instanceof StringType);
455                 st = (StringType) state;
456                 wanted = StringType.valueOf(Converter.toTitleCase(vStatus.windowDriverRear));
457                 assertEquals(wanted.toString(), st.toString(), "Window");
458                 break;
459             case WINDOW_DOOR_PASSENGER_FRONT:
460                 assertTrue(state instanceof StringType);
461                 st = (StringType) state;
462                 wanted = StringType.valueOf(Converter.toTitleCase(vStatus.windowPassengerFront));
463                 assertEquals(wanted.toString(), st.toString(), "Window");
464                 break;
465             case WINDOW_DOOR_PASSENGER_REAR:
466                 assertTrue(state instanceof StringType);
467                 st = (StringType) state;
468                 wanted = StringType.valueOf(Converter.toTitleCase(vStatus.windowPassengerRear));
469                 assertEquals(wanted.toString(), st.toString(), "Window");
470                 break;
471             case WINDOW_REAR:
472                 assertTrue(state instanceof StringType);
473                 st = (StringType) state;
474                 wanted = StringType.valueOf(Converter.toTitleCase(vStatus.rearWindow));
475                 assertEquals(wanted.toString(), st.toString(), "Window");
476                 break;
477             case SUNROOF:
478                 assertTrue(state instanceof StringType);
479                 st = (StringType) state;
480                 wanted = StringType.valueOf(Converter.toTitleCase(vStatus.sunroof));
481                 assertEquals(wanted.toString(), st.toString(), "Window");
482                 break;
483             case SERVICE_DATE:
484                 assertTrue(state instanceof DateTimeType);
485                 dtt = (DateTimeType) state;
486                 if (gUid.contentEquals(CHANNEL_GROUP_STATUS)) {
487                     if (specialHandlingMap.containsKey(SERVICE_DATE)) {
488                         assertEquals(specialHandlingMap.get(SERVICE_DATE).toString(), dtt.toString(), "Next Service");
489                     } else {
490                         String dueDateString = VehicleStatusUtils.getNextServiceDate(vStatus);
491                         DateTimeType expectedDTT = DateTimeType.valueOf(Converter.getLocalDateTime(dueDateString));
492                         assertEquals(expectedDTT.toString(), dtt.toString(), "Next Service");
493                     }
494                 } else if (gUid.equals(CHANNEL_GROUP_SERVICE)) {
495                     String dueDateString = vStatus.cbsData.get(0).getDueDate();
496                     DateTimeType expectedDTT = DateTimeType.valueOf(Converter.getLocalDateTime(dueDateString));
497                     assertEquals(expectedDTT.toString(), dtt.toString(), "First Service Date");
498                 }
499                 break;
500             case SERVICE_MILEAGE:
501                 assertTrue(state instanceof QuantityType);
502                 qt = ((QuantityType) state);
503                 if (gUid.contentEquals(CHANNEL_GROUP_STATUS)) {
504                     if (imperial) {
505                         assertEquals(ImperialUnits.MILE, qt.getUnit(), "Next Service Miles");
506                         assertEquals(VehicleStatusUtils.getNextServiceMileage(vStatus), qt.intValue(), "Mileage");
507                     } else {
508                         assertEquals(KILOMETRE, qt.getUnit(), "Next Service KM");
509                         assertEquals(VehicleStatusUtils.getNextServiceMileage(vStatus), qt.intValue(), "Mileage");
510                     }
511                 } else if (gUid.equals(CHANNEL_GROUP_SERVICE)) {
512                     if (imperial) {
513                         assertEquals(ImperialUnits.MILE, qt.getUnit(), "First Service Miles");
514                         assertEquals(vStatus.cbsData.get(0).cbsRemainingMileage, qt.intValue(),
515                                 "First Service Mileage");
516                     } else {
517                         assertEquals(KILOMETRE, qt.getUnit(), "First Service KM");
518                         assertEquals(vStatus.cbsData.get(0).cbsRemainingMileage, qt.intValue(),
519                                 "First Service Mileage");
520                     }
521                 }
522                 break;
523             case NAME:
524                 assertTrue(state instanceof StringType);
525                 st = (StringType) state;
526                 switch (gUid) {
527                     case CHANNEL_GROUP_SERVICE:
528                         wanted = StringType.valueOf(Converter.toTitleCase(Constants.NO_ENTRIES));
529                         if (!vStatus.cbsData.isEmpty()) {
530                             wanted = StringType.valueOf(Converter.toTitleCase(vStatus.cbsData.get(0).getType()));
531                         }
532                         assertEquals(wanted.toString(), st.toString(), "Service Name");
533                         break;
534                     case CHANNEL_GROUP_CHECK_CONTROL:
535                         wanted = StringType.valueOf(Constants.NO_ENTRIES);
536                         if (!vStatus.checkControlMessages.isEmpty()) {
537                             wanted = StringType.valueOf(vStatus.checkControlMessages.get(0).ccmDescriptionShort);
538                         }
539                         assertEquals(wanted.toString(), st.toString(), "CheckControl Name");
540                         break;
541                     default:
542                         assertFalse(true, "Channel " + channelUID + " " + state + " not found");
543                         break;
544                 }
545                 break;
546             case DETAILS:
547                 assertTrue(state instanceof StringType);
548                 st = (StringType) state;
549                 switch (gUid) {
550                     case CHANNEL_GROUP_SERVICE:
551                         wanted = StringType.valueOf(Converter.toTitleCase(Constants.NO_ENTRIES));
552                         if (!vStatus.cbsData.isEmpty()) {
553                             wanted = StringType.valueOf(Converter.toTitleCase(vStatus.cbsData.get(0).getDescription()));
554                         }
555                         assertEquals(wanted.toString(), st.toString(), "Service Details");
556                         break;
557                     case CHANNEL_GROUP_CHECK_CONTROL:
558                         wanted = StringType.valueOf(Constants.NO_ENTRIES);
559                         if (!vStatus.checkControlMessages.isEmpty()) {
560                             wanted = StringType.valueOf(vStatus.checkControlMessages.get(0).ccmDescriptionLong);
561                         }
562                         assertEquals(wanted.toString(), st.toString(), "CheckControl Details");
563                         break;
564                     default:
565                         assertFalse(true, "Channel " + channelUID + " " + state + " not found");
566                         break;
567                 }
568                 break;
569             case DATE:
570                 assertTrue(state instanceof DateTimeType);
571                 dtt = (DateTimeType) state;
572                 switch (gUid) {
573                     case CHANNEL_GROUP_SERVICE:
574                         String dueDateString = Constants.NULL_DATE;
575                         if (!vStatus.cbsData.isEmpty()) {
576                             dueDateString = vStatus.cbsData.get(0).getDueDate();
577                         }
578                         DateTimeType expectedDTT = DateTimeType.valueOf(Converter.getLocalDateTime(dueDateString));
579                         assertEquals(expectedDTT.toString(), dtt.toString(), "ServiceSate");
580                         break;
581                     default:
582                         assertFalse(true, "Channel " + channelUID + " " + state + " not found");
583                         break;
584                 }
585                 break;
586             default:
587                 // fail in case of unknown update
588                 assertFalse(true, "Channel " + channelUID + " " + state + " not found");
589                 break;
590         }
591     }
592 }