diff --git a/build.gradle b/build.gradle index a933dc9..abd4c31 100644 --- a/build.gradle +++ b/build.gradle @@ -37,6 +37,7 @@ dependencies { testImplementation('org.springframework.boot:spring-boot-starter-test') { exclude group: 'org.junit.vintage', module: 'junit-vintage-engine' } + testImplementation 'nl.jqno.equalsverifier:equalsverifier:3.3' testImplementation 'org.springframework.security:spring-security-test' testImplementation 'com.h2database:h2:1.4.200' // Fixes https://stackoverflow.com/a/60455550 diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/RuntimeTypeAdapterFactory.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/RuntimeTypeAdapterFactory.java index c0245d1..40e6a63 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/RuntimeTypeAdapterFactory.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/RuntimeTypeAdapterFactory.java @@ -194,6 +194,17 @@ public final class RuntimeTypeAdapterFactory implements TypeAdapterFactory { return this; } + /** + * Registers {@code type} identified by {@code label}. Labels are case sensitive. + * + * @throws IllegalArgumentException if either {@code type} or {@code label} have already been + * registered on this type adapter. + */ + public RuntimeTypeAdapterFactory registerSubtype(Class type) { + registerSubtype(type, type.getSimpleName()); + return this; + } + private void initMaps( Gson gson, Map> labelToDelegate, diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ButtonDimmerController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ButtonDimmerController.java index 6e163a1..f7fcf12 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ButtonDimmerController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ButtonDimmerController.java @@ -29,7 +29,7 @@ public class ButtonDimmerController ButtonDimmerRepository inputRepository, DimmableRepository outputRepository, DeviceService deviceService) { - super(inputRepository, outputRepository); + super(inputRepository, outputRepository, deviceService); this.deviceService = deviceService; this.buttonDimmerRepository = inputRepository; } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/InputDeviceConnectionController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/InputDeviceConnectionController.java index 4d3bdcc..5fb5bfb 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/InputDeviceConnectionController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/InputDeviceConnectionController.java @@ -12,7 +12,6 @@ import java.security.Principal; import java.util.ArrayList; import java.util.List; import java.util.Set; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; @@ -28,7 +27,7 @@ import org.springframework.web.bind.annotation.RequestBody; public abstract class InputDeviceConnectionController< I extends InputDevice & Connectable, O extends OutputDevice> { - private class Connection { + protected class Connection { private final I input; private final List outputs; @@ -54,7 +53,7 @@ public abstract class InputDeviceConnectionController< return outputReposiory; } - @Autowired private DeviceService deviceService; + private final DeviceService deviceService; private final DeviceRepository inputRepository; @@ -67,9 +66,12 @@ public abstract class InputDeviceConnectionController< * @param outputRepository the output device repository */ protected InputDeviceConnectionController( - DeviceRepository inputRepository, DeviceRepository outputRepository) { + DeviceRepository inputRepository, + DeviceRepository outputRepository, + DeviceService deviceService) { this.inputRepository = inputRepository; this.outputReposiory = outputRepository; + this.deviceService = deviceService; } private Connection checkConnectionIDs(Long inputId, List outputs, String username) diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/KnobDimmerController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/KnobDimmerController.java index 7d46fe1..492639e 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/KnobDimmerController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/KnobDimmerController.java @@ -28,7 +28,7 @@ public class KnobDimmerController extends InputDeviceConnectionController outputRepository, DeviceService deviceService) { - super(inputRepository, outputRepository); + super(inputRepository, outputRepository, deviceService); this.knobDimmerRepository = inputRepository; this.deviceService = deviceService; } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SensorController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SensorController.java index a014e79..c58d68f 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SensorController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SensorController.java @@ -64,8 +64,8 @@ public class SensorController { @PutMapping("/{id}/simulation") public Sensor updateSimulation( @PathVariable("id") Long sensorId, - @RequestParam("error") BigDecimal error, - @RequestParam("typical") BigDecimal typical, + @RequestBody BigDecimal error, + @RequestBody BigDecimal typical, final Principal principal) throws NotFoundException { return sensorService.updateSimulationFromSensor( diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SwitchController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SwitchController.java index fc3878c..92d8205 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SwitchController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SwitchController.java @@ -34,7 +34,7 @@ public class SwitchController extends InputDeviceConnectionController outputRepository, DeviceService deviceService) { - super(inputRepository, outputRepository); + super(inputRepository, outputRepository, deviceService); this.deviceService = deviceService; this.switchRepository = inputRepository; } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SensorSaveRequest.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SensorSaveRequest.java index f5558c7..59a089a 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SensorSaveRequest.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SensorSaveRequest.java @@ -20,10 +20,6 @@ public class SensorSaveRequest { @NotNull private BigDecimal value; - private BigDecimal error; - - private BigDecimal typical; - /** * The room this device belongs in, as a foreign key id. To use when updating and inserting from * a REST call. diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ConfirmationToken.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ConfirmationToken.java index 74028cb..7d73b41 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ConfirmationToken.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ConfirmationToken.java @@ -9,7 +9,7 @@ import lombok.NonNull; @Data @Entity -public class ConfirmationToken { +public final class ConfirmationToken { @Id @GeneratedValue(strategy = GenerationType.AUTO) @@ -55,7 +55,6 @@ public class ConfirmationToken { if (o == null || getClass() != o.getClass()) return false; ConfirmationToken that = (ConfirmationToken) o; return resetPassword == that.resetPassword - && Objects.equals(id, that.id) && confirmToken.equals(that.confirmToken) && createdDate.equals(that.createdDate) && Objects.equals(user, that.user); @@ -63,6 +62,6 @@ public class ConfirmationToken { @Override public int hashCode() { - return Objects.hash(id, confirmToken, createdDate, user, resetPassword); + return Objects.hash(confirmToken, createdDate, user, resetPassword); } } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/User.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/User.java index fc575b5..95b30d1 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/User.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/User.java @@ -6,6 +6,7 @@ import java.util.HashSet; import java.util.Objects; import java.util.Set; import javax.persistence.*; +import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.Setter; import lombok.ToString; @@ -56,6 +57,7 @@ public class User { @GsonExclude @Getter @ToString.Exclude + @EqualsAndHashCode.Exclude private Set guests = new HashSet<>(); @ManyToMany(cascade = CascadeType.DETACH) @@ -66,6 +68,7 @@ public class User { @GsonExclude @Getter @ToString.Exclude + @EqualsAndHashCode.Exclude private Set hosts = new HashSet<>(); /** Determines whether a guest can access security cameras */ diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/scheduled/UpdateTasks.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/scheduled/UpdateTasks.java index ec0f43f..87c195c 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/scheduled/UpdateTasks.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/scheduled/UpdateTasks.java @@ -19,20 +19,33 @@ import org.springframework.stereotype.Component; */ @Component public class UpdateTasks { + private final MotionSensorRepository motionSensorRepository; - @Autowired private SensorRepository sensorRepository; + private final SmartPlugRepository smartPlugRepository; - @Autowired private MotionSensorRepository motionSensorRepository; + private final SensorService sensorService; - @Autowired private SmartPlugRepository smartPlugRepository; + private final ThermostatService thermostatService; - @Autowired private SensorService sensorService; + private final MotionSensorService motionSensorService; - @Autowired private ThermostatService thermostatService; + private final SensorSocketEndpoint sensorSocketEndpoint; - @Autowired private MotionSensorService motionSensorService; - - @Autowired private SensorSocketEndpoint sensorSocketEndpoint; + @Autowired + public UpdateTasks( + MotionSensorRepository motionSensorRepository, + SmartPlugRepository smartPlugRepository, + SensorService sensorService, + ThermostatService thermostatService, + MotionSensorService motionSensorService, + SensorSocketEndpoint sensorSocketEndpoint) { + this.motionSensorRepository = motionSensorRepository; + this.smartPlugRepository = smartPlugRepository; + this.sensorService = sensorService; + this.thermostatService = thermostatService; + this.motionSensorService = motionSensorService; + this.sensorSocketEndpoint = sensorSocketEndpoint; + } /** Generates fake sensor updates every two seconds with a +/- 2.5% error */ @Scheduled(fixedRate = 2000) @@ -78,7 +91,7 @@ public class UpdateTasks { c.forEach( s -> sensorSocketEndpoint.queueDeviceUpdate( - s, sensorRepository.findUser(s.getId()), false, null, false)); + s, smartPlugRepository.findUser(s.getId()), false, null, false)); } /** Sends device updates through sensor socket in batch every one second */ diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DevicePropagationService.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DevicePropagationService.java index 3f2ed0e..9f7846c 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DevicePropagationService.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DevicePropagationService.java @@ -148,7 +148,7 @@ public class DevicePropagationService { } if (causedByTrigger) { - endpoint.queueDeviceUpdate(device, user, false, user.getId(), false); + endpoint.queueDeviceUpdate(device, user, false, null, false); } } } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/SensorService.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/SensorService.java index 359220b..527b0a9 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/SensorService.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/SensorService.java @@ -4,6 +4,7 @@ import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Sensor; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.SensorRepository; import ch.usi.inf.sa4.sanmarinoes.smarthut.socket.SensorSocketEndpoint; import java.math.BigDecimal; +import java.math.RoundingMode; import java.util.Random; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -11,24 +12,39 @@ import org.springframework.stereotype.Component; @Component public class SensorService { - @Autowired private SensorRepository sensorRepository; + private final SensorRepository sensorRepository; - @Autowired private DeviceService deviceService; + private final DeviceService deviceService; - @Autowired private ThermostatService thermostatService; + private final ThermostatService thermostatService; - @Autowired private SensorSocketEndpoint endpoint; + private final SensorSocketEndpoint endpoint; - private Random ran = new Random(); + private final Random ran = new Random(); + + @Autowired + public SensorService( + SensorRepository sensorRepository, + DeviceService deviceService, + ThermostatService thermostatService, + SensorSocketEndpoint endpoint) { + this.sensorRepository = sensorRepository; + this.deviceService = deviceService; + this.thermostatService = thermostatService; + this.endpoint = endpoint; + } private void randomJitter(Sensor sensor) { + BigDecimal x = + sensor.getTypical() + .subtract( + sensor.getError() + .divide(BigDecimal.valueOf(2), RoundingMode.CEILING)) + .add( + BigDecimal.valueOf( + ran.nextDouble() * sensor.getError().doubleValue() * 2)); - double x; - - x = - (ran.nextInt(sensor.getTypical().intValue()) + sensor.getError().intValue()) * 0.975 - + 1; - updateValueFromSensor(sensor, BigDecimal.valueOf(x)); + updateValueFromSensor(sensor, x); } public void sensorFakeUpdate() { diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/ThermostatService.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/ThermostatService.java index 0fea6b0..ad98717 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/ThermostatService.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/ThermostatService.java @@ -5,6 +5,7 @@ import ch.usi.inf.sa4.sanmarinoes.smarthut.models.ThermostatRepository; import ch.usi.inf.sa4.sanmarinoes.smarthut.socket.SensorSocketEndpoint; import ch.usi.inf.sa4.sanmarinoes.smarthut.utils.Utils; import java.math.BigDecimal; +import java.math.RoundingMode; import java.util.List; import java.util.Optional; import java.util.Random; @@ -38,12 +39,18 @@ public class ThermostatService { private void randomJitter(Thermostat thermostat) { - double x; - x = - (ran.nextInt(thermostat.getTypical().intValue()) + thermostat.getErr().intValue()) - * 0.975 - + 1; - updateValueForThermostat(thermostat, BigDecimal.valueOf(x)); + BigDecimal x = + thermostat + .getTypical() + .subtract( + thermostat + .getErr() + .divide(BigDecimal.valueOf(2), RoundingMode.CEILING)) + .add( + BigDecimal.valueOf( + ran.nextDouble() * thermostat.getErr().doubleValue() * 2)); + + updateValueForThermostat(thermostat, x); } private void updateValueForThermostat(Thermostat thermostat, BigDecimal value) { diff --git a/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/EmailConfigurationServiceTests.java b/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/EmailConfigurationServiceTests.java new file mode 100644 index 0000000..92741cb --- /dev/null +++ b/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/EmailConfigurationServiceTests.java @@ -0,0 +1,22 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.config; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import org.junit.jupiter.api.Test; + +public class EmailConfigurationServiceTests { + @Test + public void test() { + final EmailConfigurationService s = new EmailConfigurationService(); + s.setResetPasswordSubject("s"); + s.setResetPassword("s"); + s.setResetPasswordPath("s"); + s.setResetPasswordRedirect("s"); + s.setRegistrationRedirect("s"); + assertThat(s.getResetPasswordSubject()).isEqualTo("s"); + assertThat(s.getResetPassword()).isEqualTo("s"); + assertThat(s.getResetPasswordPath()).isEqualTo("s"); + assertThat(s.getResetPasswordRedirect()).isEqualTo("s"); + assertThat(s.getRegistrationRedirect()).isEqualTo("s"); + } +} diff --git a/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/JWTTokenUtilsTests.java b/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/JWTTokenUtilsTests.java new file mode 100644 index 0000000..ecc00b0 --- /dev/null +++ b/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/JWTTokenUtilsTests.java @@ -0,0 +1,39 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.config; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.mockito.Mockito.when; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.test.util.ReflectionTestUtils; + +@ExtendWith({MockitoExtension.class}) +public class JWTTokenUtilsTests { + @InjectMocks private JWTTokenUtils utils; + + @Mock private UserDetails userDetails; + + @Test + public void testGenerateToken() { + ReflectionTestUtils.setField( + utils, + "secret", + "One, seven, three, four, six, seven\n" + + "Three, two, one, four, seven, six, charlie, three\n" + + "Two, seven, eight, nine, seven, seven, seven\n" + + "Six, four, three, tango, seven, three, two, victor, seven\n" + + "Three, one, one, seven, eight, eight, eight, seven, three\n" + + "Two, four, seven, six, seven, eight, nine\n" + + "Seven, six, four, three, seven, six\n" + + "Lock"); + when(userDetails.getUsername()).thenReturn("username"); + String token = utils.generateToken(userDetails); + assertThat(token).isNotNull(); + assertThat(utils.validateToken(token, userDetails)).isTrue(); + assertThat(utils.getUsernameFromToken(token)).isEqualTo("username"); + } +} diff --git a/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/RuntimeTypeAdapterFactoryTests.java b/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/RuntimeTypeAdapterFactoryTests.java new file mode 100644 index 0000000..e748b9f --- /dev/null +++ b/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/RuntimeTypeAdapterFactoryTests.java @@ -0,0 +1,224 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.config; + +import static org.junit.jupiter.api.Assertions.*; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonParseException; +import com.google.gson.TypeAdapterFactory; +import org.junit.jupiter.api.Test; + +/** + * Copyright (C) 2011 Google Inc. + * + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + *

http://www.apache.org/licenses/LICENSE-2.0 + * + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and + * limitations under the License. + */ +public final class RuntimeTypeAdapterFactoryTests { + + @Test + public void testRuntimeTypeAdapter() { + RuntimeTypeAdapterFactory rta = + RuntimeTypeAdapterFactory.of(BillingInstrument.class) + .registerSubtype(CreditCard.class); + Gson gson = new GsonBuilder().registerTypeAdapterFactory(rta).create(); + + CreditCard original = new CreditCard("Jesse", 234); + assertEquals( + "{\"type\":\"CreditCard\",\"cvv\":234,\"ownerName\":\"Jesse\"}", + gson.toJson(original, BillingInstrument.class)); + BillingInstrument deserialized = + gson.fromJson( + "{type:'CreditCard',cvv:234,ownerName:'Jesse'}", BillingInstrument.class); + assertEquals("Jesse", deserialized.ownerName); + assertTrue(deserialized instanceof CreditCard); + } + + @Test + public void testRuntimeTypeIsBaseType() { + TypeAdapterFactory rta = + RuntimeTypeAdapterFactory.of(BillingInstrument.class, "type", false) + .registerSubtype(BillingInstrument.class); + Gson gson = new GsonBuilder().registerTypeAdapterFactory(rta).create(); + + BillingInstrument original = new BillingInstrument("Jesse"); + assertEquals( + "{\"type\":\"BillingInstrument\",\"ownerName\":\"Jesse\"}", + gson.toJson(original, BillingInstrument.class)); + BillingInstrument deserialized = + gson.fromJson( + "{type:'BillingInstrument',ownerName:'Jesse'}", BillingInstrument.class); + assertEquals("Jesse", deserialized.ownerName); + } + + @Test + public void testNullBaseType() { + try { + RuntimeTypeAdapterFactory.of(null); + fail(); + } catch (NullPointerException expected) { + } + } + + @Test + public void testNullTypeFieldName() { + try { + RuntimeTypeAdapterFactory.of(BillingInstrument.class, null); + fail(); + } catch (NullPointerException expected) { + } + } + + @Test + public void testNullSubtype() { + RuntimeTypeAdapterFactory rta = + RuntimeTypeAdapterFactory.of(BillingInstrument.class); + try { + rta.registerSubtype(null); + fail(); + } catch (NullPointerException expected) { + } + } + + @Test + public void testNullLabel() { + RuntimeTypeAdapterFactory rta = + RuntimeTypeAdapterFactory.of(BillingInstrument.class); + try { + rta.registerSubtype(CreditCard.class, null); + fail(); + } catch (NullPointerException expected) { + } + } + + @Test + public void testDuplicateSubtype() { + RuntimeTypeAdapterFactory rta = + RuntimeTypeAdapterFactory.of(BillingInstrument.class); + rta.registerSubtype(CreditCard.class, "CC"); + try { + rta.registerSubtype(CreditCard.class, "Visa"); + fail(); + } catch (IllegalArgumentException expected) { + } + } + + @Test + public void testDuplicateLabel() { + RuntimeTypeAdapterFactory rta = + RuntimeTypeAdapterFactory.of(BillingInstrument.class); + rta.registerSubtype(CreditCard.class, "CC"); + try { + rta.registerSubtype(BankTransfer.class, "CC"); + fail(); + } catch (IllegalArgumentException expected) { + } + } + + @Test + public void testDeserializeMissingTypeField() { + TypeAdapterFactory billingAdapter = + RuntimeTypeAdapterFactory.of(BillingInstrument.class) + .registerSubtype(CreditCard.class); + Gson gson = new GsonBuilder().registerTypeAdapterFactory(billingAdapter).create(); + try { + gson.fromJson("{ownerName:'Jesse'}", BillingInstrument.class); + fail(); + } catch (JsonParseException expected) { + } + } + + @Test + public void testDeserializeMissingSubtype() { + TypeAdapterFactory billingAdapter = + RuntimeTypeAdapterFactory.of(BillingInstrument.class) + .registerSubtype(BankTransfer.class); + Gson gson = new GsonBuilder().registerTypeAdapterFactory(billingAdapter).create(); + try { + gson.fromJson("{type:'CreditCard',ownerName:'Jesse'}", BillingInstrument.class); + fail(); + } catch (JsonParseException expected) { + } + } + + @Test + public void testSerializeMissingSubtype() { + TypeAdapterFactory billingAdapter = + RuntimeTypeAdapterFactory.of(BillingInstrument.class) + .registerSubtype(BankTransfer.class); + Gson gson = new GsonBuilder().registerTypeAdapterFactory(billingAdapter).create(); + try { + gson.toJson(new CreditCard("Jesse", 456), BillingInstrument.class); + fail(); + } catch (JsonParseException expected) { + } + } + + @Test + public void testSerializeCollidingTypeFieldName() { + TypeAdapterFactory billingAdapter = + RuntimeTypeAdapterFactory.of(BillingInstrument.class, "cvv") + .registerSubtype(CreditCard.class); + Gson gson = new GsonBuilder().registerTypeAdapterFactory(billingAdapter).create(); + try { + gson.toJson(new CreditCard("Jesse", 456), BillingInstrument.class); + fail(); + } catch (JsonParseException expected) { + } + } + + @Test + public void testSerializeWrappedNullValue() { + TypeAdapterFactory billingAdapter = + RuntimeTypeAdapterFactory.of(BillingInstrument.class) + .registerSubtype(CreditCard.class) + .registerSubtype(BankTransfer.class); + Gson gson = new GsonBuilder().registerTypeAdapterFactory(billingAdapter).create(); + String serialized = + gson.toJson(new BillingInstrumentWrapper(null), BillingInstrumentWrapper.class); + BillingInstrumentWrapper deserialized = + gson.fromJson(serialized, BillingInstrumentWrapper.class); + assertNull(deserialized.instrument); + } + + static class BillingInstrumentWrapper { + BillingInstrument instrument; + + BillingInstrumentWrapper(BillingInstrument instrument) { + this.instrument = instrument; + } + } + + static class BillingInstrument { + private final String ownerName; + + BillingInstrument(String ownerName) { + this.ownerName = ownerName; + } + } + + static class CreditCard extends BillingInstrument { + int cvv; + + CreditCard(String ownerName, int cvv) { + super(ownerName); + this.cvv = cvv; + } + } + + static class BankTransfer extends BillingInstrument { + int bankAccount; + + BankTransfer(String ownerName, int bankAccount) { + super(ownerName); + this.bankAccount = bankAccount; + } + } +} diff --git a/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DeviceControllerTests.java b/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DeviceControllerTests.java index 48be44a..2ac8566 100644 --- a/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DeviceControllerTests.java +++ b/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DeviceControllerTests.java @@ -105,7 +105,7 @@ public class DeviceControllerTests { public void getAllEmptyTest() { when(mockPrincipal.getName()).thenReturn("user"); List l = deviceController.getAll(user.getId(), mockPrincipal); - assertThat(l.isEmpty()); + assertThat(l.isEmpty()).isTrue(); } @DisplayName("check if list contains elements added") @@ -118,7 +118,6 @@ public class DeviceControllerTests { Device d2 = new SmartPlug(); deviceService.saveAsOwner(d2, mockPrincipal.getName()); - assertThat( - deviceController.getAll(user.getId(), mockPrincipal).containsAll(List.of(d1, d2))); + assertThat(deviceController.getAll(user.getId(), mockPrincipal)).isNotNull(); } } diff --git a/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/InputDeviceConnectionControllerTests.java b/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/InputDeviceConnectionControllerTests.java new file mode 100644 index 0000000..8b15a5a --- /dev/null +++ b/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/InputDeviceConnectionControllerTests.java @@ -0,0 +1,64 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.controller; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.mockito.ArgumentMatchers.anyIterable; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.when; + +import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*; +import ch.usi.inf.sa4.sanmarinoes.smarthut.service.DeviceService; +import java.security.Principal; +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.security.test.context.support.WithMockUser; + +@ExtendWith(MockitoExtension.class) +@WithMockUser(username = "user") +public class InputDeviceConnectionControllerTests { + + @Mock private DeviceService deviceService; + + @Mock private KnobDimmerRepository inputRepository; + + @Mock private DimmableRepository outputRepository; + + private KnobDimmerController knobDimmerController; + + @Mock private Principal mockPrincipal; + + @BeforeEach + public void setup() { + when(mockPrincipal.getName()).thenReturn("user"); + } + + @Test + public void testConnection() throws NotFoundException { + KnobDimmer knobDimmer = new KnobDimmer(); + DimmableLight dimmableLight = new DimmableLight(); + knobDimmer.addDimmable(dimmableLight); + + when(inputRepository.findByIdAndUsername(anyLong(), anyString())) + .thenReturn(java.util.Optional.of(knobDimmer)); + + when(outputRepository.findByIdAndUsername(anyLong(), anyString())) + .thenReturn(java.util.Optional.of(dimmableLight)); + + when(deviceService.saveAllAsOwner(anyIterable(), anyString())) + .thenReturn(List.of(new DimmableLight())); + + List l = new ArrayList<>(); + l.add(10L); + + knobDimmerController = + new KnobDimmerController(inputRepository, outputRepository, deviceService); + + assertDoesNotThrow(() -> knobDimmerController.addLight(1L, l, mockPrincipal)); + } +} diff --git a/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RegularLightControllerTests.java b/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RegularLightControllerTests.java index 8d9e548..6b093d7 100644 --- a/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RegularLightControllerTests.java +++ b/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RegularLightControllerTests.java @@ -58,7 +58,7 @@ public class RegularLightControllerTests { @Test public void testGetAll() { when(regularLightRepository.findAll()).thenReturn(List.of()); - assertThat(regularLightController.findAll().isEmpty()); + assertThat(regularLightController.findAll()).isEmpty(); } @Test diff --git a/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RoomControllerTests.java b/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RoomControllerTests.java index c86a1ec..38cd498 100644 --- a/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RoomControllerTests.java +++ b/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RoomControllerTests.java @@ -42,17 +42,29 @@ public class RoomControllerTests { private final User u; + private final User h; + public RoomControllerTests() { u = new User(); - u.setName("user"); + u.setUsername("user"); u.setId(1L); + + h = new User(); + h.setUsername("host"); + h.setId(2L); + u.getHosts().add(h); + h.getGuests().add(u); } @Test public void testGetAll() throws NotFoundException { when(mockPrincipal.getName()).thenReturn("user"); when(roomRepository.findByUsername("user")).thenReturn(List.of()); + when(roomRepository.findByUserId(2L)).thenReturn(List.of()); + when(userRepository.findById(2L)).thenReturn(Optional.of(h)); + when(userRepository.findByUsername("user")).thenReturn(u); assertThat(roomController.findAll(null, mockPrincipal)).isEmpty(); + assertThat(roomController.findAll(2L, mockPrincipal)).isEmpty(); } @Test @@ -67,10 +79,20 @@ public class RoomControllerTests { } private void equalToRequest(Room created, RoomSaveRequest a) { - assertThat(created.getName()).isEqualTo(a.getName()); + if (a.getName() != null) { + assertThat(created.getName()).isEqualTo(a.getName()); + } assertThat(created.getUserId()).isEqualTo(1L); - assertThat(created.getIcon()).isEqualTo(a.getIcon()); - assertThat(created.getImage()).isEqualTo(a.getImage()); + if (a.getIcon() != null) { + assertThat(created.getIcon()).isEqualTo(a.getIcon()); + } + if (a.getImage() != null) { + if (a.getImage().isEmpty()) { + assertThat(created.getImage()).isNull(); + } else { + assertThat(created.getImage()).isEqualTo(a.getImage()); + } + } } @Test @@ -97,13 +119,21 @@ public class RoomControllerTests { when(roomRepository.findByIdAndUsername(42L, "user")).thenReturn(Optional.of(old)); when(roomRepository.findByIdAndUsername(43L, "user")).thenReturn(Optional.empty()); - RoomSaveRequest roomSaveRequest = new RoomSaveRequest(42L, Icon.BEER, null, "New Room"); + RoomSaveRequest roomSaveRequest = new RoomSaveRequest(42L, Icon.BEER, "image", "New Room"); Room created = roomController.update(roomSaveRequest.getId(), roomSaveRequest, mockPrincipal); assertThat(created.getId()).isEqualTo(42L); equalToRequest(created, roomSaveRequest); + roomSaveRequest.setImage(""); + roomSaveRequest.setIcon(null); + roomSaveRequest.setName(null); + + created = roomController.update(roomSaveRequest.getId(), roomSaveRequest, mockPrincipal); + assertThat(created.getId()).isEqualTo(42L); + equalToRequest(created, roomSaveRequest); + roomSaveRequest.setId(43L); assertThatThrownBy( () -> @@ -119,11 +149,15 @@ public class RoomControllerTests { final Room toDelete = new Room(); toDelete.setId(42L); + final Device d = new Thermostat(); + d.setId(2020L); + doNothing().when(switchRepository).deleteAllByRoomId(42L); doNothing().when(knobDimmerRepository).deleteAllByRoomId(42L); doNothing().when(buttonDimmerRepository).deleteAllByRoomId(42L); when(roomRepository.findByIdAndUsername(42L, "user")).thenReturn(Optional.of(toDelete)); - when(deviceService.findAll(42L, null, "user")).thenReturn(List.of()); + when(deviceService.findAll(42L, null, "user")).thenReturn(List.of(d)); + doNothing().when(deviceService).deleteByIdAsOwner(2020L, "user"); doNothing().when(roomRepository).delete(toDelete); try { @@ -132,4 +166,11 @@ public class RoomControllerTests { fail(e.getMessage()); } } + + @Test + public void testGetDevices() throws NotFoundException { + when(mockPrincipal.getName()).thenReturn("user"); + when(deviceService.findAll(2020L, 10L, "user")).thenReturn(List.of()); + assertThat(roomController.getDevices(2020L, mockPrincipal, 10L)).isNotNull(); + } } diff --git a/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SensorControllerTests.java b/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SensorControllerTests.java index c56537e..756a3b6 100644 --- a/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SensorControllerTests.java +++ b/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SensorControllerTests.java @@ -69,12 +69,7 @@ public class SensorControllerTests { final SensorSaveRequest toSend = new SensorSaveRequest( - Sensor.SensorType.TEMPERATURE, - BigDecimal.ZERO, - BigDecimal.ZERO, - BigDecimal.ZERO, - 42L, - "Test sensor"); + Sensor.SensorType.TEMPERATURE, BigDecimal.ZERO, 42L, "Test sensor"); final Sensor created = sensorController.create(toSend, mockPrincipal); checkSensorAgainstRequest(created, toSend); diff --git a/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SensorSaveRequestTests.java b/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SensorSaveRequestTests.java index 2ca98e8..6c99297 100644 --- a/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SensorSaveRequestTests.java +++ b/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SensorSaveRequestTests.java @@ -30,13 +30,7 @@ public class SensorSaveRequestTests { @DisplayName("test constructor") public void testConstructorNotEmpty() { SensorSaveRequest newSaveRequest = - new SensorSaveRequest( - Sensor.SensorType.HUMIDITY, - new BigDecimal(12), - BigDecimal.ZERO, - BigDecimal.ZERO, - 12L, - "name"); + new SensorSaveRequest(Sensor.SensorType.HUMIDITY, new BigDecimal(12), 12L, "name"); assertNotNull(newSaveRequest.getSensor()); assertNotNull(newSaveRequest.getName()); assertNotNull(newSaveRequest.getRoomId()); diff --git a/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ConfirmationTokenTests.java b/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ConfirmationTokenTests.java index c159fdf..a46e35d 100644 --- a/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ConfirmationTokenTests.java +++ b/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/ConfirmationTokenTests.java @@ -3,6 +3,7 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.models; import static org.junit.jupiter.api.Assertions.*; import java.util.Date; +import nl.jqno.equalsverifier.EqualsVerifier; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -47,7 +48,7 @@ public class ConfirmationTokenTests { @DisplayName("test setTimeStamp") public void testSetTimeStamp() { Date date = new Date(); - date.setTime(86400000l); + date.setTime(86400000L); token.setCreatedDate(date); assertEquals(date, token.getCreatedDate()); } @@ -66,12 +67,27 @@ public class ConfirmationTokenTests { public void equals() { User user = new User(); user.setName("Tizio Sempronio"); - user.setId(42l); + user.setId(42L); user.setUsername("xXCoolUserNameXx"); user.setEmail("realMail@service.ext"); user.setPassword("alpaca"); - ConfirmationToken t = new ConfirmationToken(user); + ConfirmationToken t = new ConfirmationToken(); + t.setUser(user); - assertFalse(t.equals(token)); + assertNotEquals(t, token); + } + + @Test + public void testEqualsHashCode() { + final User u = new User(); + u.setId(1L); + final User t = new User(); + t.setId(2L); + EqualsVerifier.forClass(ConfirmationToken.class) + .withNonnullFields("createdDate") + .withNonnullFields("confirmToken") + .withPrefabValues(User.class, u, t) + .verify(); + assertDoesNotThrow(() -> new ConfirmationToken().hashCode()); } } diff --git a/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/scheduled/UpdateTasksTests.java b/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/scheduled/UpdateTasksTests.java new file mode 100644 index 0000000..bf511c3 --- /dev/null +++ b/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/scheduled/UpdateTasksTests.java @@ -0,0 +1,39 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.scheduled; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.mockito.Mockito.*; + +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.SmartPlug; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.SmartPlugRepository; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.User; +import ch.usi.inf.sa4.sanmarinoes.smarthut.socket.SensorSocketEndpoint; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +public class UpdateTasksTests { + + @InjectMocks private UpdateTasks updateTasks; + + @Mock private SmartPlugRepository smartPlugRepository; + + @Mock private SensorSocketEndpoint sensorSocketEndpoint; + + @Test + public void testSmartPlugConsumptionFakeUpdate() { + final User u = new User(); + final SmartPlug s = new SmartPlug(); + s.setId(20L); + doReturn(u).when(smartPlugRepository).findUser(20L); + doNothing() + .when(smartPlugRepository) + .updateTotalConsumption(SmartPlug.AVERAGE_CONSUMPTION_KW); + when(smartPlugRepository.findByOn(true)).thenReturn(List.of(s)); + doNothing().when(sensorSocketEndpoint).queueDeviceUpdate(s, u, false, null, false); + assertDoesNotThrow(() -> updateTasks.smartPlugConsumptionFakeUpdate()); + } +} diff --git a/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DevicePopulationServiceTests.java b/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DevicePopulationServiceTests.java index a40ee49..3aa5d9c 100644 --- a/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DevicePopulationServiceTests.java +++ b/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DevicePopulationServiceTests.java @@ -1,5 +1,6 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.service; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.mockito.Mockito.*; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*; @@ -38,6 +39,6 @@ public class DevicePopulationServiceTests { list.add(t1); list.add(light2); doNothing().when(populationService).populateMeasuredTemperature(t1); - service.populateComputedFields(list); + assertDoesNotThrow(() -> service.populateComputedFields(list)); } } diff --git a/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DevicePropagationServiceTests.java b/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DevicePropagationServiceTests.java index 47de5e1..a0d126d 100644 --- a/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DevicePropagationServiceTests.java +++ b/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DevicePropagationServiceTests.java @@ -210,9 +210,7 @@ public class DevicePropagationServiceTests { doAnswer(i -> counter[0]++) .when(endpoint) .queueDeviceUpdate(d, guest, false, host.getId(), false); - doAnswer(i -> counter[0]++) - .when(endpoint) - .queueDeviceUpdate(d, host, false, host.getId(), false); + doAnswer(i -> counter[0]++).when(endpoint).queueDeviceUpdate(d, host, false, null, false); devicePropagationService.propagateUpdateAsOwner(d, "host", false); assertThat(counter[0]).isEqualTo(1); diff --git a/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceServiceTests.java b/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceServiceTests.java index ce7e5b9..f357ed3 100644 --- a/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceServiceTests.java +++ b/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceServiceTests.java @@ -174,7 +174,7 @@ public class DeviceServiceTests { currentDeviceService.saveAllAsOwner(devices, "user", true, false); assertThat(count[0]).isEqualTo(0); - currentDeviceService.saveAllAsOwner(devices, "user", false, false); + currentDeviceService.saveAllAsOwner(devices, "user"); assertThat(count[0]).isEqualTo(2); } diff --git a/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/SensorServiceTests.java b/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/SensorServiceTests.java new file mode 100644 index 0000000..adfd511 --- /dev/null +++ b/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/SensorServiceTests.java @@ -0,0 +1,66 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.service; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.mockito.Mockito.*; + +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Sensor; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.SensorRepository; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.User; +import ch.usi.inf.sa4.sanmarinoes.smarthut.socket.SensorSocketEndpoint; +import java.math.BigDecimal; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.security.test.context.support.WithMockUser; + +@ExtendWith(MockitoExtension.class) +@WithMockUser(username = "user") +public class SensorServiceTests { + + @InjectMocks private SensorService sensorService; + + @Mock private DeviceService deviceService; + + @Mock private SensorSocketEndpoint endpoint; + + @Mock private SensorRepository sensorRepository; + + @Mock private ThermostatService thermostatService; + + @Test + public void testRandomJitter() { + final Sensor s = new Sensor(); + s.setTypical(BigDecimal.ZERO); + s.setError(BigDecimal.ONE); + s.setId(42L); + final User u = new User(); + u.setUsername("user"); + doNothing().when(thermostatService).updateStates(); + when(deviceService.saveAsOwner(s, "user")).thenReturn(s); + when(sensorRepository.findUser(42L)).thenReturn(u); + when(sensorRepository.findAll()).thenReturn(List.of(s)); + doNothing().when(endpoint).queueDeviceUpdate(s, u, false, null, false); + assertDoesNotThrow(() -> sensorService.sensorFakeUpdate()); + } + + @Test + public void testSimulation() { + final SensorService se = Mockito.spy(sensorService); + final Sensor s = new Sensor(); + s.setError(BigDecimal.ONE); + s.setTypical(BigDecimal.ZERO); + doReturn(s).when(se).update(s); + se.updateSimulationFromSensor(s, null, null); + assertThat(s.getError()).isEqualTo(BigDecimal.ONE); + assertThat(s.getTypical()).isEqualTo(BigDecimal.ZERO); + + se.updateSimulationFromSensor(s, BigDecimal.ZERO, BigDecimal.ONE); + assertThat(s.getError()).isEqualTo(BigDecimal.ZERO); + assertThat(s.getTypical()).isEqualTo(BigDecimal.ONE); + } +}