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.hue.internal.clip2;
15 import static org.hamcrest.CoreMatchers.*;
16 import static org.hamcrest.MatcherAssert.assertThat;
17 import static org.junit.jupiter.api.Assertions.assertThrows;
19 import java.util.ArrayList;
20 import java.util.List;
21 import java.util.stream.Stream;
23 import org.eclipse.jdt.annotation.NonNullByDefault;
24 import org.junit.jupiter.api.Test;
25 import org.junit.jupiter.params.ParameterizedTest;
26 import org.junit.jupiter.params.provider.Arguments;
27 import org.junit.jupiter.params.provider.MethodSource;
28 import org.openhab.binding.hue.internal.api.dto.clip2.ColorTemperature;
29 import org.openhab.binding.hue.internal.api.dto.clip2.Dimming;
30 import org.openhab.binding.hue.internal.api.dto.clip2.Effects;
31 import org.openhab.binding.hue.internal.api.dto.clip2.OnState;
32 import org.openhab.binding.hue.internal.api.dto.clip2.Resource;
33 import org.openhab.binding.hue.internal.api.dto.clip2.enums.ResourceType;
34 import org.openhab.binding.hue.internal.api.dto.clip2.helper.Setters;
35 import org.openhab.binding.hue.internal.exceptions.DTOPresentButEmptyException;
38 * Tests for {@link Setters}.
40 * @author Jacob Laursen - Initial contribution
43 public class SettersTest {
46 * Tests merging of on state and dimming for same resource.
49 * - Resource 1: type=light/grouped_light, sparse, id=1, on=on
50 * - Resource 2: type=light/grouped_light, sparse, id=1, dimming=50
53 * - Resource 1: type=light/grouped_light, sparse, id=1, on=on, dimming=50
55 * @throws DTOPresentButEmptyException
58 @MethodSource("provideLightResourceTypes")
59 void mergeLightResourcesMergeOnStateAndDimmingWhenSparseAndSameId(ResourceType resourceType)
60 throws DTOPresentButEmptyException {
61 List<Resource> resources = new ArrayList<>();
63 Resource resource1 = createResource(resourceType, "1");
64 resource1.setOnState(createOnState(true));
65 resources.add(resource1);
67 Resource resource2 = createResource(resourceType, "1");
68 resource2.setDimming(createDimming(50));
69 resources.add(resource2);
71 Setters.mergeLightResources(resources);
73 assertThat(resources.size(), is(equalTo(1)));
74 Resource mergedResource = resources.get(0);
75 assertThat(mergedResource.getId(), is(equalTo(resource1.getId())));
76 assertThat(mergedResource.getType(), is(equalTo(resourceType)));
77 assertThat(mergedResource.hasFullState(), is(false));
78 OnState actualOnState = mergedResource.getOnState();
79 assertThat(actualOnState, is(notNullValue()));
80 if (actualOnState != null) {
81 assertThat(actualOnState.isOn(), is(true));
83 Dimming actualDimming = mergedResource.getDimming();
84 assertThat(actualDimming, is(notNullValue()));
85 if (actualDimming != null) {
86 assertThat(actualDimming.getBrightness(), is(equalTo(50.0)));
90 private static Stream<Arguments> provideLightResourceTypes() {
91 return Stream.of(Arguments.of(ResourceType.LIGHT), Arguments.of(ResourceType.GROUPED_LIGHT));
95 * Tests merging of dimming for same resource where last value wins.
98 * - Resource 1: type=light, sparse, id=1, dimming=49
99 * - Resource 2: type=light, sparse, id=1, dimming=50
102 * - Resource 1: type=light, sparse, id=1, dimming=50
104 * @throws DTOPresentButEmptyException
107 void mergeLightResourcesMergeDimmingToLatestValueWhenSparseAndSameId() throws DTOPresentButEmptyException {
108 List<Resource> resources = new ArrayList<>();
110 Resource resource1 = createResource(ResourceType.LIGHT, "1");
111 resource1.setDimming(createDimming(49));
112 resources.add(resource1);
114 Resource resource2 = createResource(ResourceType.LIGHT, "1");
115 resource2.setDimming(createDimming(50));
116 resources.add(resource2);
118 Setters.mergeLightResources(resources);
120 assertThat(resources.size(), is(equalTo(1)));
121 Resource mergedResource = resources.get(0);
122 assertThat(mergedResource.hasFullState(), is(false));
123 Dimming actualDimming = mergedResource.getDimming();
124 assertThat(actualDimming, is(notNullValue()));
125 if (actualDimming != null) {
126 assertThat(actualDimming.getBrightness(), is(equalTo(50.0)));
131 * Tests merging of HSB type fields while keeping resource with effects.
134 * - Resource 1: type=light, sparse, id=1, dimming=49
135 * - Resource 2: type=light, sparse, id=1, on=on, dimming=50, effect=xxx
138 * - Resource 1: type=light, sparse, id=1, on=on, dimming=50
139 * - Resource 2: type=light, sparse, id=1, effect=xxx
141 * @throws DTOPresentButEmptyException
144 void mergeLightResourcesMergeHSBFieldsDoNotRemoveResourceWithEffect() throws DTOPresentButEmptyException {
145 List<Resource> resources = new ArrayList<>();
147 Resource resource1 = createResource(ResourceType.LIGHT, "1");
148 resource1.setDimming(createDimming(49));
149 resources.add(resource1);
151 Resource resource2 = createResource(ResourceType.LIGHT, "1");
152 resource2.setDimming(createDimming(50));
153 resource2.setOnState(createOnState(true));
154 resource2.setFixedEffects(new Effects());
155 resources.add(resource2);
157 Setters.mergeLightResources(resources);
159 assertThat(resources.size(), is(equalTo(2)));
160 Resource mergedResource = resources.get(0);
161 assertThat(mergedResource.hasFullState(), is(false));
162 OnState actualOnState = mergedResource.getOnState();
163 assertThat(actualOnState, is(notNullValue()));
164 if (actualOnState != null) {
165 assertThat(actualOnState.isOn(), is(true));
167 Dimming actualDimming = mergedResource.getDimming();
168 assertThat(actualDimming, is(notNullValue()));
169 if (actualDimming != null) {
170 assertThat(actualDimming.getBrightness(), is(equalTo(50.0)));
173 Resource effectsResource = resources.get(1);
174 assertThat(effectsResource.hasFullState(), is(false));
175 assertThat(effectsResource.getFixedEffects(), is(notNullValue()));
179 * Tests leaving different resources separated.
182 * - Resource 1: type=light, sparse, id=1, on=on
183 * - Resource 2: type=light, sparse, id=2, dimming=50
186 * - Resource 1: type=light, sparse, id=1, on=on
187 * - Resource 2: type=light, sparse, id=2, dimming=50
189 * @throws DTOPresentButEmptyException
192 void mergeLightResourcesDoNotMergeOnStateAndDimmingWhenSparseAndDifferentId() throws DTOPresentButEmptyException {
193 List<Resource> resources = new ArrayList<>();
195 Resource resource1 = createResource(ResourceType.LIGHT, "1");
196 resource1.setOnState(createOnState(true));
197 resources.add(resource1);
199 Resource resource2 = createResource(ResourceType.LIGHT, "2");
200 resource2.setDimming(createDimming(50));
201 resources.add(resource2);
203 Setters.mergeLightResources(resources);
205 assertThat(resources.size(), is(equalTo(2)));
206 Resource firstResource = resources.get(0);
207 OnState actualOnState = firstResource.getOnState();
208 assertThat(actualOnState, is(notNullValue()));
209 if (actualOnState != null) {
210 assertThat(actualOnState.isOn(), is(true));
212 assertThat(firstResource.getDimming(), is(nullValue()));
214 Resource secondResource = resources.get(1);
215 assertThat(secondResource.getOnState(), is(nullValue()));
216 Dimming actualDimming = secondResource.getDimming();
217 assertThat(actualDimming, is(notNullValue()));
218 if (actualDimming != null) {
219 assertThat(actualDimming.getBrightness(), is(equalTo(50.0)));
224 * Tests merging of on state and dimming for same resource when full is first.
227 * - Resource 1: type=light, full, id=1, on=on
230 * - Exception thrown, full state is not supported/expected.
232 * @throws DTOPresentButEmptyException
235 void mergeLightResourcesMergeOnStateAndDimmingWhenFullStateFirstAndSameId() throws DTOPresentButEmptyException {
236 List<Resource> resources = new ArrayList<>();
238 Resource resource = new Resource(ResourceType.LIGHT);
241 resources.add(resource);
243 assertThrows(IllegalStateException.class, () -> Setters.mergeLightResources(resources));
247 * Tests leaving resources with on state and color temperature separated.
248 * In this case they could be merged, but it's not needed.
251 * - Resource 1: type=light, sparse, id=1, on=on
252 * - Resource 2: type=light, sparse, id=1, color temperature=370 mirek
255 * - Resource 1: type=light, sparse, id=1, on=on
256 * - Resource 2: type=light, sparse, id=1, color temperature=370 mirek
258 * @throws DTOPresentButEmptyException
261 void mergeLightResourcesDoNotMergeOnStateAndColorTemperatureWhenSparseAndSameId()
262 throws DTOPresentButEmptyException {
263 List<Resource> resources = new ArrayList<>();
265 Resource resource1 = createResource(ResourceType.LIGHT, "1");
266 resource1.setOnState(createOnState(true));
267 resources.add(resource1);
269 Resource resource2 = createResource(ResourceType.LIGHT, "1");
270 resource2.setColorTemperature(createColorTemperature(370));
271 resources.add(resource2);
273 Setters.mergeLightResources(resources);
275 assertThat(resources.size(), is(equalTo(2)));
276 Resource firstResource = resources.get(0);
277 OnState actualOnState = firstResource.getOnState();
278 assertThat(actualOnState, is(notNullValue()));
279 if (actualOnState != null) {
280 assertThat(actualOnState.isOn(), is(true));
282 assertThat(firstResource.getColorTemperature(), is(nullValue()));
284 Resource secondResource = resources.get(1);
285 assertThat(secondResource.getOnState(), is(nullValue()));
286 ColorTemperature actualColorTemperature = secondResource.getColorTemperature();
287 assertThat(actualColorTemperature, is(notNullValue()));
288 if (actualColorTemperature != null) {
289 assertThat(actualColorTemperature.getMirek(), is(equalTo(370L)));
294 * Tests merging resources with on state/color and leaving color temperature separated.
295 * In this case they could be merged, but it's not needed.
298 * - Resource 1: type=light, sparse, id=1, on=on
299 * - Resource 2: type=light, sparse, id=1, dimming=50, color temperature=370 mirek
302 * - Resource 1: type=light, sparse, id=1, on=on, dimming=50
303 * - Resource 2: type=light, sparse, id=1, color temperature=370 mirek
305 * @throws DTOPresentButEmptyException
308 void mergeLightResourcesMergeOnStateAndDimmingButNotColorTemperatureWhenSparseAndSameId()
309 throws DTOPresentButEmptyException {
310 List<Resource> resources = new ArrayList<>();
312 Resource resource1 = createResource(ResourceType.LIGHT, "1");
313 resource1.setOnState(createOnState(true));
314 resources.add(resource1);
316 Resource resource2 = createResource(ResourceType.LIGHT, "1");
317 resource2.setDimming(createDimming(50));
318 resource2.setColorTemperature(createColorTemperature(370));
319 resources.add(resource2);
321 Setters.mergeLightResources(resources);
323 assertThat(resources.size(), is(equalTo(2)));
324 Resource firstResource = resources.get(0);
325 OnState actualOnState = firstResource.getOnState();
326 assertThat(actualOnState, is(notNullValue()));
327 if (actualOnState != null) {
328 assertThat(actualOnState.isOn(), is(true));
330 Dimming actualDimming = firstResource.getDimming();
331 assertThat(actualDimming, is(notNullValue()));
332 if (actualDimming != null) {
333 assertThat(actualDimming.getBrightness(), is(equalTo(50.0)));
335 assertThat(firstResource.getColorTemperature(), is(nullValue()));
337 Resource secondResource = resources.get(1);
338 assertThat(secondResource.getOnState(), is(nullValue()));
339 assertThat(secondResource.getDimming(), is(nullValue()));
340 ColorTemperature actualColorTemperature = secondResource.getColorTemperature();
341 assertThat(actualColorTemperature, is(notNullValue()));
342 if (actualColorTemperature != null) {
343 assertThat(actualColorTemperature.getMirek(), is(equalTo(370L)));
348 * Tests preserving resource with on state and color temperature.
351 * - Resource 1: type=light, sparse, id=1, on=on, color temperature=370
354 * - Resource 1: type=light, sparse, id=1, on=on, color temperature=370
356 * @throws DTOPresentButEmptyException
359 void mergeLightResourcesSeparateOnStateAndColorTemperatureWhenSparseAndSameId() throws DTOPresentButEmptyException {
360 List<Resource> resources = new ArrayList<>();
362 Resource resource = createResource(ResourceType.LIGHT, "1");
363 resource.setOnState(createOnState(true));
364 resource.setColorTemperature(createColorTemperature(370));
365 resources.add(resource);
367 Setters.mergeLightResources(resources);
369 assertThat(resources.size(), is(equalTo(1)));
371 Resource firstResource = resources.get(0);
372 OnState actualOnState = firstResource.getOnState();
373 assertThat(actualOnState, is(notNullValue()));
374 if (actualOnState != null) {
375 assertThat(actualOnState.isOn(), is(true));
377 ColorTemperature actualColorTemperature = firstResource.getColorTemperature();
378 assertThat(actualColorTemperature, is(notNullValue()));
379 if (actualColorTemperature != null) {
380 assertThat(actualColorTemperature.getMirek(), is(equalTo(370L)));
385 * Tests that resources that are not light or grouped_light will not throw.
388 * - Resource 1: type=motion, sparse, id=1
391 * - Resource 1: type=motion, sparse, id=1
393 * @throws DTOPresentButEmptyException
396 void mergeLightResourcesNonLightResourceShouldNotThrow() throws DTOPresentButEmptyException {
397 List<Resource> resources = new ArrayList<>();
399 Resource resource = createResource(ResourceType.MOTION, "1");
400 resources.add(resource);
402 Setters.mergeLightResources(resources);
404 assertThat(resources.size(), is(equalTo(1)));
406 Resource firstResource = resources.get(0);
407 assertThat(firstResource.getType(), is(equalTo(ResourceType.MOTION)));
410 private OnState createOnState(boolean on) {
411 OnState onState = new OnState();
417 private Dimming createDimming(double brightness) {
418 Dimming dimming = new Dimming();
419 dimming.setBrightness(brightness);
424 private ColorTemperature createColorTemperature(double mirek) {
425 ColorTemperature colorTemperature = new ColorTemperature();
426 colorTemperature.setMirek(mirek);
428 return colorTemperature;
431 private Resource createResource(ResourceType resourceType, String id) {
432 Resource resource = new Resource(resourceType);
434 resource.markAsSparse();