package org.glukit.dexcom.sync; import org.glukit.dexcom.sync.g4.DexcomG4Constants; import org.glukit.dexcom.sync.model.DexcomSyncData; import org.glukit.dexcom.sync.model.GlucoseReadRecord; import org.glukit.dexcom.sync.model.ManufacturingParameters; import org.glukit.dexcom.sync.model.UserEventRecord; import org.glukit.sync.api.*; import org.junit.Test; import org.threeten.bp.Duration; import org.threeten.bp.Instant; import org.threeten.bp.LocalDateTime; import org.threeten.bp.ZoneId; import java.util.Arrays; import java.util.Collections; import java.util.List; import static java.lang.String.format; import static org.glukit.dexcom.sync.DexcomAdapterService.SPECIAL_GLUCOSE_VALUES; import static org.glukit.sync.api.InsulinInjection.InsulinType.UNKNOWN; import static org.glukit.sync.api.InsulinInjection.UNAVAILABLE_INSULIN_NAME; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; /** * Unit test of {@link DexcomAdapterService}. * * @author alexandre.normand */ public class TestDexcomAdapterService { private static final String SERIAL_NUMBER = "serial"; private static final String HARDWARE_REVISION = "revision1"; private static final String HARDWARE_ID = "hardwareId"; private static final Integer NORMAL_READ_TEST_VALUE = 83; private static final List<GlucoseRead> EMPTY_GLUCOSE_READS = Collections.emptyList(); private static final List<GlucoseReadRecord> EMPTY_GLUCOSE_READ_RECORDS = Collections.emptyList(); private static final List<InsulinInjection> EMPTY_INSULIN_INJECTIONS = Collections.emptyList(); private static final List<UserEventRecord> EMPTY_USER_EVENT_RECORDS = Collections.emptyList(); private static final List<FoodEvent> EMPTY_FOOD_EVENTS = Collections.emptyList(); private static final List<ExerciseSession> EMPTY_EXERCISE_SESSIONS = Collections.emptyList(); private static final Instant TEST_TIME = Instant.ofEpochMilli(100L); @Test public void noReadsShouldConvertSuccessfully() throws Exception { DexcomAdapterService dexcomAdapterService = new DexcomAdapterService(); SyncData syncData = dexcomAdapterService.convertData( new DexcomSyncData(EMPTY_GLUCOSE_READ_RECORDS, EMPTY_USER_EVENT_RECORDS, new ManufacturingParameters(SERIAL_NUMBER, "partNumber", HARDWARE_REVISION, "2013-10-18 10:10", HARDWARE_ID), TEST_TIME)); SyncData expectedSyncData = new SyncData(EMPTY_GLUCOSE_READS, EMPTY_INSULIN_INJECTIONS, EMPTY_FOOD_EVENTS, EMPTY_EXERCISE_SESSIONS, new DeviceInfo(SERIAL_NUMBER, HARDWARE_ID, HARDWARE_REVISION), TEST_TIME); assertThat(syncData, is(equalTo(expectedSyncData))); } @Test public void singleReadShouldConvertSuccessfully() throws Exception { DexcomAdapterService dexcomAdapterService = new DexcomAdapterService(); List<GlucoseReadRecord> glucoseRecords = Arrays.asList(new GlucoseReadRecord(1000, 1000, NORMAL_READ_TEST_VALUE, (byte) 0, 1L, 1L)); SyncData syncData = dexcomAdapterService.convertData(new DexcomSyncData(glucoseRecords, EMPTY_USER_EVENT_RECORDS, new ManufacturingParameters(SERIAL_NUMBER, "partNumber", HARDWARE_REVISION, "2013-10-18 10:10", HARDWARE_ID), TEST_TIME)); GlucoseRead expectedRead = new GlucoseRead( internalTimeFromSeconds(1000L), localDateTimeFromSeconds(1000L), NORMAL_READ_TEST_VALUE.floatValue(), GlucoseRead.Unit.MG_PER_DL); SyncData expectedSyncData = new SyncData(Arrays.asList(expectedRead), EMPTY_INSULIN_INJECTIONS, EMPTY_FOOD_EVENTS, EMPTY_EXERCISE_SESSIONS, new DeviceInfo(SERIAL_NUMBER, HARDWARE_ID, HARDWARE_REVISION), TEST_TIME); assertThat(syncData, is(equalTo(expectedSyncData))); } @Test public void multipleReadsShouldAllBeConverted() throws Exception { DexcomAdapterService dexcomAdapterService = new DexcomAdapterService(); List<GlucoseReadRecord> glucoseRecords = Arrays.asList(new GlucoseReadRecord(1000, 1000, NORMAL_READ_TEST_VALUE, (byte) 0, 1L, 1L), new GlucoseReadRecord(2000, 2000, NORMAL_READ_TEST_VALUE, (byte) 0, 1L, 1L)); SyncData syncData = dexcomAdapterService.convertData(new DexcomSyncData(glucoseRecords, EMPTY_USER_EVENT_RECORDS, new ManufacturingParameters(SERIAL_NUMBER, "partNumber", HARDWARE_REVISION, "2013-10-18 10:10", HARDWARE_ID), TEST_TIME)); GlucoseRead expectedRead1 = new GlucoseRead( internalTimeFromSeconds(1000L), localDateTimeFromSeconds(1000L), NORMAL_READ_TEST_VALUE.floatValue(), GlucoseRead.Unit.MG_PER_DL); GlucoseRead expectedRead2 = new GlucoseRead( internalTimeFromSeconds(2000L), localDateTimeFromSeconds(2000L), NORMAL_READ_TEST_VALUE.floatValue(), GlucoseRead.Unit.MG_PER_DL); SyncData expectedSyncData = new SyncData(Arrays.asList(expectedRead1, expectedRead2), EMPTY_INSULIN_INJECTIONS, EMPTY_FOOD_EVENTS, EMPTY_EXERCISE_SESSIONS, new DeviceInfo(SERIAL_NUMBER, HARDWARE_ID, HARDWARE_REVISION), TEST_TIME); assertThat(syncData, is(equalTo(expectedSyncData))); } @Test public void displayOnlyReadShouldNotBeIncluded() throws Exception { DexcomAdapterService dexcomAdapterService = new DexcomAdapterService(); List<GlucoseReadRecord> glucoseRecords = Arrays.asList(new GlucoseReadRecord(1000, 1000, 32781, (byte) 0, 1L, 1L)); SyncData syncData = dexcomAdapterService.convertData(new DexcomSyncData(glucoseRecords, EMPTY_USER_EVENT_RECORDS, new ManufacturingParameters(SERIAL_NUMBER, "partNumber", HARDWARE_REVISION, "2013-10-18 10:10", HARDWARE_ID), TEST_TIME)); SyncData expectedSyncData = new SyncData(EMPTY_GLUCOSE_READS, EMPTY_INSULIN_INJECTIONS, EMPTY_FOOD_EVENTS, EMPTY_EXERCISE_SESSIONS, new DeviceInfo(SERIAL_NUMBER, HARDWARE_ID, HARDWARE_REVISION), TEST_TIME); assertThat(syncData, is(equalTo(expectedSyncData))); } @Test public void specialValuesShouldNotBeIncluded() throws Exception { DexcomAdapterService dexcomAdapterService = new DexcomAdapterService(); // Test all special values for (int specialGlucoseValue : SPECIAL_GLUCOSE_VALUES) { List<GlucoseReadRecord> glucoseRecords = Arrays.asList(new GlucoseReadRecord(1000, 1000, specialGlucoseValue, (byte) 0, 1L, 1L)); SyncData syncData = dexcomAdapterService.convertData(new DexcomSyncData(glucoseRecords, EMPTY_USER_EVENT_RECORDS, new ManufacturingParameters(SERIAL_NUMBER, "partNumber", HARDWARE_REVISION, "2013-10-18 10:10", HARDWARE_ID), TEST_TIME)); SyncData expectedSyncData = new SyncData(EMPTY_GLUCOSE_READS, EMPTY_INSULIN_INJECTIONS, EMPTY_FOOD_EVENTS, EMPTY_EXERCISE_SESSIONS, new DeviceInfo(SERIAL_NUMBER, HARDWARE_ID, HARDWARE_REVISION), TEST_TIME); assertThat(format("Glucose value [%d] should not be included in the conversion result", specialGlucoseValue), syncData, is(equalTo(expectedSyncData))); } } @Test public void insulinUserRecordShouldBeConverted() throws Exception { DexcomAdapterService dexcomAdapterService = new DexcomAdapterService(); SyncData syncData = dexcomAdapterService.convertData( new DexcomSyncData(EMPTY_GLUCOSE_READ_RECORDS, Arrays.asList(new UserEventRecord(1000L, 2000L, 1500L, UserEventRecord.UserEventType.INSULIN, (byte) 0, 350)), new ManufacturingParameters(SERIAL_NUMBER, "partNumber", HARDWARE_REVISION, "2013-10-18 10:10", HARDWARE_ID), TEST_TIME)); InsulinInjection expectedInsulinInjection = new InsulinInjection(internalTimeFromSeconds(1000L), localDateTimeFromSeconds(2000L), localDateTimeFromSeconds(1500L), 3.5f, UNKNOWN, UNAVAILABLE_INSULIN_NAME); SyncData expectedSyncData = new SyncData(EMPTY_GLUCOSE_READS, Arrays.asList(expectedInsulinInjection), EMPTY_FOOD_EVENTS, EMPTY_EXERCISE_SESSIONS, new DeviceInfo(SERIAL_NUMBER, HARDWARE_ID, HARDWARE_REVISION), TEST_TIME); assertThat(syncData, is(equalTo(expectedSyncData))); } @Test public void exerciseUserRecordShouldBeConverted() throws Exception { DexcomAdapterService dexcomAdapterService = new DexcomAdapterService(); SyncData syncData = dexcomAdapterService.convertData( new DexcomSyncData(EMPTY_GLUCOSE_READ_RECORDS, Arrays.asList(new UserEventRecord(1000L, 2000L, 1500L, UserEventRecord.UserEventType.EXERCISE, UserEventRecord.ExerciseIntensity.LIGHT.getId(), 10)), new ManufacturingParameters(SERIAL_NUMBER, "partNumber", HARDWARE_REVISION, "2013-10-18 10:10", HARDWARE_ID), TEST_TIME)); ExerciseSession expectedExerciseSession = new ExerciseSession(internalTimeFromSeconds(1000L), localDateTimeFromSeconds(2000L), localDateTimeFromSeconds(1500L), ExerciseSession.Intensity.LIGHT, Duration.ofMinutes(10), ExerciseSession.EMPTY_DESCRIPTION); SyncData expectedSyncData = new SyncData(EMPTY_GLUCOSE_READS, EMPTY_INSULIN_INJECTIONS, EMPTY_FOOD_EVENTS, Arrays.asList(expectedExerciseSession), new DeviceInfo(SERIAL_NUMBER, HARDWARE_ID, HARDWARE_REVISION), TEST_TIME); assertThat(syncData, is(equalTo(expectedSyncData))); } @Test public void carbUserRecordShouldBeConverted() throws Exception { DexcomAdapterService dexcomAdapterService = new DexcomAdapterService(); SyncData syncData = dexcomAdapterService.convertData( new DexcomSyncData(EMPTY_GLUCOSE_READ_RECORDS, Arrays.asList(new UserEventRecord(1000L, 2000L, 1500L, UserEventRecord.UserEventType.CARBS, (byte) 0, 12)), new ManufacturingParameters(SERIAL_NUMBER, "partNumber", HARDWARE_REVISION, "2013-10-18 10:10", HARDWARE_ID), TEST_TIME)); FoodEvent foodEvent = new FoodEvent(internalTimeFromSeconds(1000L), localDateTimeFromSeconds(2000L), localDateTimeFromSeconds(1500L), 12f, 0f); SyncData expectedSyncData = new SyncData(EMPTY_GLUCOSE_READS, EMPTY_INSULIN_INJECTIONS, Arrays.asList(foodEvent), EMPTY_EXERCISE_SESSIONS, new DeviceInfo(SERIAL_NUMBER, HARDWARE_ID, HARDWARE_REVISION), TEST_TIME); assertThat(syncData, is(equalTo(expectedSyncData))); } private Instant internalTimeFromSeconds(long secondsToAdd) { return DexcomG4Constants.DEXCOM_EPOCH.plusSeconds(secondsToAdd); } private LocalDateTime localDateTimeFromSeconds(long secondsToAdd) { return LocalDateTime.ofInstant(internalTimeFromSeconds(secondsToAdd), ZoneId.of("UTC")); } }