mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 07:02:02 +01:00
[aWATTar] push test coverage and improve code readability
Signed-off-by: Thomas Leber <thomas@tl-photography.at>
This commit is contained in:
parent
2cd8902017
commit
71b17c018e
@ -12,6 +12,8 @@
|
||||
*/
|
||||
package org.openhab.binding.awattar.internal;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
@ -47,7 +49,18 @@ public abstract class AwattarBestPriceResult {
|
||||
}
|
||||
}
|
||||
|
||||
public abstract boolean isActive();
|
||||
/**
|
||||
* Returns true if the best price is active.
|
||||
*
|
||||
* @param now the current time
|
||||
* @return true if the best price is active, false otherwise
|
||||
*/
|
||||
public abstract boolean isActive(Instant now);
|
||||
|
||||
/**
|
||||
* Returns the hours of the best price.
|
||||
*
|
||||
* @return the hours of the best price as a string
|
||||
*/
|
||||
public abstract String getHours();
|
||||
}
|
||||
|
@ -76,8 +76,8 @@ public class AwattarConsecutiveBestPriceResult extends AwattarBestPriceResult {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive() {
|
||||
return contains(Instant.now().toEpochMilli());
|
||||
public boolean isActive(Instant now) {
|
||||
return contains(now.toEpochMilli());
|
||||
}
|
||||
|
||||
public boolean contains(long timestamp) {
|
||||
|
@ -64,8 +64,8 @@ public class AwattarNonConsecutiveBestPriceResult extends AwattarBestPriceResult
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive() {
|
||||
return members.stream().anyMatch(x -> x.timerange().contains(Instant.now().toEpochMilli()));
|
||||
public boolean isActive(Instant now) {
|
||||
return members.stream().anyMatch(x -> x.timerange().contains(now.toEpochMilli()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -73,16 +73,9 @@ public class AwattarNonConsecutiveBestPriceResult extends AwattarBestPriceResult
|
||||
return String.format("NonConsecutiveBestpriceResult with %s", members.toString());
|
||||
}
|
||||
|
||||
private void sort() {
|
||||
if (!sorted) {
|
||||
members.sort(Comparator.comparingLong(p -> p.timerange().start()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHours() {
|
||||
boolean second = false;
|
||||
sort();
|
||||
StringBuilder res = new StringBuilder();
|
||||
|
||||
for (AwattarPrice price : members) {
|
||||
|
@ -23,7 +23,6 @@ import static org.openhab.binding.awattar.internal.AwattarUtil.getCalendarForHou
|
||||
import static org.openhab.binding.awattar.internal.AwattarUtil.getDuration;
|
||||
import static org.openhab.binding.awattar.internal.AwattarUtil.getMillisToNextMinute;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.ArrayList;
|
||||
@ -163,7 +162,7 @@ public class AwattarBestPriceHandler extends BaseThingHandler {
|
||||
long diff;
|
||||
switch (channelId) {
|
||||
case CHANNEL_ACTIVE:
|
||||
state = OnOffType.from(result.isActive());
|
||||
state = OnOffType.from(result.isActive(getNow(zoneId).toInstant()));
|
||||
break;
|
||||
case CHANNEL_START:
|
||||
state = new DateTimeType(Instant.ofEpochMilli(result.getStart()));
|
||||
@ -172,7 +171,7 @@ public class AwattarBestPriceHandler extends BaseThingHandler {
|
||||
state = new DateTimeType(Instant.ofEpochMilli(result.getEnd()));
|
||||
break;
|
||||
case CHANNEL_COUNTDOWN:
|
||||
diff = result.getStart() - Instant.now().toEpochMilli();
|
||||
diff = result.getStart() - getNow(zoneId).toInstant().toEpochMilli();
|
||||
if (diff >= 0) {
|
||||
state = getDuration(diff);
|
||||
} else {
|
||||
@ -180,8 +179,8 @@ public class AwattarBestPriceHandler extends BaseThingHandler {
|
||||
}
|
||||
break;
|
||||
case CHANNEL_REMAINING:
|
||||
if (result.isActive()) {
|
||||
diff = result.getEnd() - Instant.now().toEpochMilli();
|
||||
if (result.isActive(getNow(zoneId).toInstant())) {
|
||||
diff = result.getEnd() - getNow(zoneId).toInstant().toEpochMilli();
|
||||
state = getDuration(diff);
|
||||
} else {
|
||||
state = QuantityType.valueOf(0, Units.MINUTE);
|
||||
@ -216,20 +215,49 @@ public class AwattarBestPriceHandler extends BaseThingHandler {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the time range for the given start hour and duration.
|
||||
*
|
||||
* @param start the start hour (0-23)
|
||||
* @param duration the duration in hours
|
||||
* @param zoneId the time zone to use
|
||||
* @return the range
|
||||
*/
|
||||
protected TimeRange getRange(int start, int duration, ZoneId zoneId) {
|
||||
ZonedDateTime startCal = getCalendarForHour(start, zoneId);
|
||||
ZonedDateTime endCal = startCal.plusHours(duration);
|
||||
ZonedDateTime now = ZonedDateTime.now(zoneId);
|
||||
ZonedDateTime startTime = getStarTime(start, zoneId);
|
||||
ZonedDateTime endTime = startTime.plusHours(duration);
|
||||
ZonedDateTime now = getNow(zoneId);
|
||||
if (now.getHour() < start) {
|
||||
// we are before the range, so we might be still within the last range
|
||||
startCal = startCal.minusDays(1);
|
||||
endCal = endCal.minusDays(1);
|
||||
startTime = startTime.minusDays(1);
|
||||
endTime = endTime.minusDays(1);
|
||||
}
|
||||
if (endCal.toInstant().toEpochMilli() < Instant.now().toEpochMilli()) {
|
||||
if (endTime.toInstant().toEpochMilli() < now.toInstant().toEpochMilli()) {
|
||||
// span is in the past, add one day
|
||||
startCal = startCal.plusDays(1);
|
||||
endCal = endCal.plusDays(1);
|
||||
startTime = startTime.plusDays(1);
|
||||
endTime = endTime.plusDays(1);
|
||||
}
|
||||
return new TimeRange(startCal.toInstant().toEpochMilli(), endCal.toInstant().toEpochMilli());
|
||||
return new TimeRange(startTime.toInstant().toEpochMilli(), endTime.toInstant().toEpochMilli());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the start time for the given hour.
|
||||
*
|
||||
* @param start the hour. Must be between 0 and 23.
|
||||
* @param zoneId the time zone
|
||||
* @return the start time
|
||||
*/
|
||||
protected ZonedDateTime getStarTime(int start, ZoneId zoneId) {
|
||||
return getCalendarForHour(start, zoneId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current time.
|
||||
*
|
||||
* @param zoneId the time zone
|
||||
* @return the current time
|
||||
*/
|
||||
protected ZonedDateTime getNow(ZoneId zoneId) {
|
||||
return ZonedDateTime.now(zoneId);
|
||||
}
|
||||
}
|
||||
|
@ -20,14 +20,18 @@ import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.openhab.binding.awattar.internal.AwattarBindingConstants.CHANNEL_ACTIVE;
|
||||
import static org.openhab.binding.awattar.internal.AwattarBindingConstants.CHANNEL_COUNTDOWN;
|
||||
import static org.openhab.binding.awattar.internal.AwattarBindingConstants.CHANNEL_END;
|
||||
import static org.openhab.binding.awattar.internal.AwattarBindingConstants.CHANNEL_HOURS;
|
||||
import static org.openhab.binding.awattar.internal.AwattarBindingConstants.CHANNEL_REMAINING;
|
||||
import static org.openhab.binding.awattar.internal.AwattarBindingConstants.CHANNEL_START;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -58,6 +62,8 @@ import org.openhab.binding.awattar.internal.dto.AwattarApiData;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.i18n.TimeZoneProvider;
|
||||
import org.openhab.core.library.types.DateTimeType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.test.java.JavaTest;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
@ -166,31 +172,98 @@ public class AwattarBridgeHandlerTest extends JavaTest {
|
||||
|
||||
public static Stream<Arguments> testBestpriceHandler() {
|
||||
return Stream.of( //
|
||||
Arguments.of(1, true, CHANNEL_START, new DateTimeType("2024-06-15T14:00:00.000+0200")),
|
||||
Arguments.of(1, true, CHANNEL_END, new DateTimeType("2024-06-15T15:00:00.000+0200")),
|
||||
Arguments.of(1, true, CHANNEL_HOURS, new StringType("14")),
|
||||
Arguments.of(1, false, CHANNEL_START, new DateTimeType("2024-06-15T14:00:00.000+0200")),
|
||||
Arguments.of(1, false, CHANNEL_END, new DateTimeType("2024-06-15T15:00:00.000+0200")),
|
||||
Arguments.of(1, false, CHANNEL_HOURS, new StringType("14")),
|
||||
Arguments.of(2, true, CHANNEL_START, new DateTimeType("2024-06-15T13:00:00.000+0200")),
|
||||
Arguments.of(2, true, CHANNEL_END, new DateTimeType("2024-06-15T15:00:00.000+0200")),
|
||||
Arguments.of(2, true, CHANNEL_HOURS, new StringType("13,14")),
|
||||
Arguments.of(2, false, CHANNEL_START, new DateTimeType("2024-06-15T13:00:00.000+0200")),
|
||||
Arguments.of(2, false, CHANNEL_END, new DateTimeType("2024-06-15T15:00:00.000+0200")),
|
||||
Arguments.of(2, false, CHANNEL_HOURS, new StringType("13,14")));
|
||||
Arguments.of(24, 1, true, CHANNEL_START, new DateTimeType("2024-06-15T14:00:00.000+0200")),
|
||||
Arguments.of(24, 1, true, CHANNEL_END, new DateTimeType("2024-06-15T15:00:00.000+0200")),
|
||||
Arguments.of(24, 1, true, CHANNEL_HOURS, new StringType("14")),
|
||||
Arguments.of(24, 1, false, CHANNEL_START, new DateTimeType("2024-06-15T14:00:00.000+0200")),
|
||||
Arguments.of(24, 1, false, CHANNEL_END, new DateTimeType("2024-06-15T15:00:00.000+0200")),
|
||||
Arguments.of(24, 1, false, CHANNEL_HOURS, new StringType("14")),
|
||||
Arguments.of(24, 2, true, CHANNEL_START, new DateTimeType("2024-06-15T13:00:00.000+0200")),
|
||||
Arguments.of(24, 2, true, CHANNEL_END, new DateTimeType("2024-06-15T15:00:00.000+0200")),
|
||||
Arguments.of(24, 2, true, CHANNEL_HOURS, new StringType("13,14")),
|
||||
Arguments.of(24, 2, false, CHANNEL_START, new DateTimeType("2024-06-15T13:00:00.000+0200")),
|
||||
Arguments.of(24, 2, false, CHANNEL_END, new DateTimeType("2024-06-15T15:00:00.000+0200")),
|
||||
Arguments.of(24, 2, false, CHANNEL_HOURS, new StringType("13,14")),
|
||||
Arguments.of(34, 4, false, CHANNEL_START, new DateTimeType("2024-06-15T12:00:00.000+0200")),
|
||||
Arguments.of(34, 4, false, CHANNEL_END, new DateTimeType("2024-06-15T16:00:00.000+0200")),
|
||||
Arguments.of(34, 4, false, CHANNEL_HOURS, new StringType("12,13,14,15")),
|
||||
Arguments.of(34, 8, false, CHANNEL_START, new DateTimeType("2024-06-15T12:00:00.000+0200")),
|
||||
Arguments.of(34, 8, false, CHANNEL_END, new DateTimeType("2024-06-16T16:00:00.000+0200")),
|
||||
Arguments.of(34, 8, false, CHANNEL_HOURS, new StringType("12,13,14,15,16,13,14,15")));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource
|
||||
void testBestpriceHandler(int length, boolean consecutive, String channelId, State expectedState) {
|
||||
void testBestpriceHandler(int rangeDuration, int length, boolean consecutive, String channelId,
|
||||
State expectedState) {
|
||||
ThingUID bestPriceUid = new ThingUID(AwattarBindingConstants.THING_TYPE_BESTPRICE, "foo");
|
||||
Map<String, Object> config = Map.of("length", length, "consecutive", consecutive);
|
||||
Map<String, Object> config = Map.of("rangeDuration", rangeDuration, "length", length, "consecutive",
|
||||
consecutive);
|
||||
when(bestpriceMock.getConfiguration()).thenReturn(new Configuration(config));
|
||||
|
||||
AwattarBestPriceHandler handler = new AwattarBestPriceHandler(bestpriceMock, timeZoneProviderMock) {
|
||||
@Override
|
||||
protected TimeRange getRange(int start, int duration, ZoneId zoneId) {
|
||||
return new TimeRange(1718402400000L, 1718488800000L);
|
||||
protected ZonedDateTime getStarTime(int start, ZoneId zoneId) {
|
||||
return ZonedDateTime.of(2024, 6, 15, 12, 0, 0, 0, zoneId);
|
||||
}
|
||||
|
||||
protected ZonedDateTime getNow(ZoneId zoneId) {
|
||||
return ZonedDateTime.of(2024, 6, 15, 12, 0, 0, 0, zoneId);
|
||||
}
|
||||
};
|
||||
|
||||
handler.setCallback(bestPriceCallbackMock);
|
||||
|
||||
ChannelUID channelUID = new ChannelUID(bestPriceUid, channelId);
|
||||
handler.refreshChannel(channelUID);
|
||||
verify(bestPriceCallbackMock).stateUpdated(channelUID, expectedState);
|
||||
}
|
||||
|
||||
public static Stream<Arguments> testBestpriceHandler_channels() {
|
||||
return Stream.of( //
|
||||
Arguments.of(12, 0, 24, 1, true, CHANNEL_HOURS, new StringType("14")),
|
||||
Arguments.of(12, 0, 24, 1, true, CHANNEL_ACTIVE, OnOffType.from(false)),
|
||||
Arguments.of(12, 0, 24, 1, true, CHANNEL_COUNTDOWN, new QuantityType<>("120 min")),
|
||||
Arguments.of(12, 0, 24, 1, true, CHANNEL_REMAINING, new QuantityType<>("0 min")),
|
||||
|
||||
Arguments.of(13, 59, 24, 1, true, CHANNEL_COUNTDOWN, new QuantityType<>("1 min")),
|
||||
Arguments.of(13, 59, 24, 1, true, CHANNEL_REMAINING, new QuantityType<>("0 min")),
|
||||
Arguments.of(13, 59, 24, 1, false, CHANNEL_ACTIVE, OnOffType.from(false)),
|
||||
Arguments.of(13, 59, 24, 1, true, CHANNEL_ACTIVE, OnOffType.from(false)),
|
||||
|
||||
Arguments.of(14, 01, 24, 1, true, CHANNEL_COUNTDOWN, new QuantityType<>("0 min")),
|
||||
Arguments.of(14, 01, 24, 1, true, CHANNEL_REMAINING, new QuantityType<>("59 min")),
|
||||
Arguments.of(14, 01, 24, 1, false, CHANNEL_ACTIVE, OnOffType.from(true)),
|
||||
Arguments.of(14, 01, 24, 1, true, CHANNEL_ACTIVE, OnOffType.from(true)),
|
||||
|
||||
Arguments.of(14, 59, 24, 1, true, CHANNEL_COUNTDOWN, new QuantityType<>("0 min")),
|
||||
Arguments.of(14, 59, 24, 1, true, CHANNEL_REMAINING, new QuantityType<>("1 min")),
|
||||
Arguments.of(14, 59, 24, 1, false, CHANNEL_ACTIVE, OnOffType.from(true)),
|
||||
Arguments.of(14, 59, 24, 1, true, CHANNEL_ACTIVE, OnOffType.from(true)),
|
||||
|
||||
Arguments.of(15, 00, 24, 1, true, CHANNEL_COUNTDOWN, new QuantityType<>("0 min")),
|
||||
Arguments.of(15, 00, 24, 1, true, CHANNEL_REMAINING, new QuantityType<>("0 min")),
|
||||
Arguments.of(15, 00, 24, 1, false, CHANNEL_ACTIVE, OnOffType.from(false)),
|
||||
Arguments.of(15, 00, 24, 1, true, CHANNEL_ACTIVE, OnOffType.from(false)),
|
||||
|
||||
Arguments.of(12, 0, 24, 1, true, CHANNEL_REMAINING, new QuantityType<>("0 min")));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource
|
||||
void testBestpriceHandler_channels(int currentHour, int currentMinute, int rangeDuration, int length,
|
||||
boolean consecutive, String channelId, State expectedState) {
|
||||
ThingUID bestPriceUid = new ThingUID(AwattarBindingConstants.THING_TYPE_BESTPRICE, "foo");
|
||||
Map<String, Object> config = Map.of("rangeDuration", rangeDuration, "length", length, "consecutive",
|
||||
consecutive);
|
||||
when(bestpriceMock.getConfiguration()).thenReturn(new Configuration(config));
|
||||
|
||||
AwattarBestPriceHandler handler = new AwattarBestPriceHandler(bestpriceMock, timeZoneProviderMock) {
|
||||
protected ZonedDateTime getStarTime(int start, ZoneId zoneId) {
|
||||
return ZonedDateTime.of(2024, 6, 15, 0, 0, 0, 0, zoneId);
|
||||
}
|
||||
|
||||
protected ZonedDateTime getNow(ZoneId zoneId) {
|
||||
return ZonedDateTime.of(2024, 6, 15, currentHour, currentMinute, 0, 0, zoneId);
|
||||
}
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user