Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ default byte[] mapByteString(ByteString in) {
}

default ByteString mapByteStringToString(String string) {
return ByteString.copyFromUtf8(string);
return ByteString.copyFromUtf8(string != null ? string : "");
}

default String mapStringToByteString(ByteString in) {
Expand All @@ -74,15 +74,18 @@ default String mapStringToByteString(ByteString in) {
}

default com.google.type.Date mapLocalDate(LocalDate t) {
return com.google.type.Date.newBuilder().setYear(t.getYear()).setMonth(t.getMonthValue()).setDay(t.getDayOfMonth()).build();
return t != null ? com.google.type.Date.newBuilder().setYear(t.getYear()).setMonth(t.getMonthValue()).setDay(t.getDayOfMonth()).build()
: com.google.type.Date.getDefaultInstance();
}

default LocalDate mapDate(com.google.type.Date t) {
return LocalDate.of(t.getYear(), t.getMonth(), t.getDay());
}

default com.google.type.TimeOfDay mapLocalTime(LocalTime t) {
return com.google.type.TimeOfDay.newBuilder().setHours(t.getHour()).setMinutes(t.getMinute()).setSeconds(t.getSecond()).setNanos(t.getNano()).build();
return t != null
? com.google.type.TimeOfDay.newBuilder().setHours(t.getHour()).setMinutes(t.getMinute()).setSeconds(t.getSecond()).setNanos(t.getNano()).build()
: com.google.type.TimeOfDay.getDefaultInstance();
}

default LocalTime mapTimeOfDay(com.google.type.TimeOfDay t) {
Expand All @@ -91,7 +94,7 @@ default LocalTime mapTimeOfDay(com.google.type.TimeOfDay t) {

default Timestamp map(LocalDateTime i) {
if (i == null) {
return null;
return Timestamp.getDefaultInstance();
}

TimeZone systemDefault = TimeZone.getDefault();
Expand All @@ -103,7 +106,7 @@ default Timestamp map(LocalDateTime i) {
}

default Timestamp map(OffsetDateTime in) {
return Timestamp.newBuilder().setSeconds(in.toEpochSecond()).setNanos(0).build();
return in != null ? Timestamp.newBuilder().setSeconds(in.toEpochSecond()).setNanos(0).build() : Timestamp.getDefaultInstance();
}

default float map(FloatValue f) {
Expand Down Expand Up @@ -143,22 +146,16 @@ default ByteString map(BytesValue f) {
}

default Instant mapToInstant(Timestamp t) {
if (t == null) {
if (t == null || Timestamp.getDefaultInstance().equals(t)) {
return null;
}

Timestamp sanitized = Timestamps.sanitize(t);

if (sanitized != null) {
return Instant.ofEpochSecond(sanitized.getSeconds(), sanitized.getNanos());
} else {
return null;
}
return Instant.ofEpochSecond(sanitized.getSeconds(), sanitized.getNanos());
}

default Timestamp mapToTimestamp(Instant i) {
if (i == null) {
return null;
return Timestamp.getDefaultInstance();
}

Timestamp t = Timestamp.newBuilder().setSeconds(i.getEpochSecond()).setNanos(i.getNano()).build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,6 @@ public class Timestamps {
* Sanitize Timestamps outside legal range where possible.
*/
public static Timestamp sanitize(Timestamp t) {
if (t.getSeconds() == 0 && t.getNanos() == 0) {
return null; // Assuming null for epoch, cannot differentiate
}
if (t.getNanos() < 0 || t.getNanos() >= NANOS_PER_SECOND) {
throw new IllegalArgumentException(String.format(
"Timestamp is not valid. See proto definition for valid values. Seconds (%s) must be in range [-62,135,596,800, +253,402,300,799]. Nanos (%s) must be in range [0, +999,999,999].",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,8 @@ default Long toEpochMilliseconds(Timestamp instance) {
return instant == null ? null : instant.toEpochMilli();
}

default Timestamp fromEpochMilliseconds(Long instance) {
if (instance == null) {
return null;
}
Instant instant = Instant.ofEpochMilli(instance);
default Timestamp fromEpochMilliseconds(Long millis) {
Instant instant = Instant.ofEpochMilli(millis != null ? millis : 0L);
return mapToTimestamp(instant);
}

Expand All @@ -61,6 +58,9 @@ default Duration mapDuration(com.google.protobuf.Duration t) {
}

default com.google.protobuf.Duration mapDuration(Duration t) {
if (t == null) {
return com.google.protobuf.Duration.getDefaultInstance();
}
long seconds = t.getSeconds();
int nanos = t.getNano();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ default com.google.protobuf.Duration mapDuration(Duration t) {
if (t != null) {
return Durations.fromNanos(t.toNanos());
} else {
return null;
return com.google.protobuf.Duration.getDefaultInstance();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,120 +23,163 @@
* #L%
*/

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import com.google.protobuf.ByteString;
import com.google.protobuf.Timestamp;
import com.google.protobuf.util.Durations;
import com.google.type.TimeOfDay;
import no.entur.abt.mapstruct.common.Timestamps;
import org.junit.jupiter.api.Test;

import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.concurrent.TimeUnit;

import org.junit.jupiter.api.Test;

import com.google.protobuf.Timestamp;
import com.google.protobuf.util.Durations;

import no.entur.abt.mapstruct.common.Timestamps;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;

public class ProtobufStandardMappingsTest {

no.entur.abt.mapstruct.ProtobufStandardMappings MAPPER = no.entur.abt.mapstruct.ProtobufStandardMappings.INSTANCE;

@Test
public void testMapLocalDateToTimestampSummertime() {
LocalDateTime l = LocalDateTime.of(2000, 6, 1, 12, 0);

Timestamp timestamp = MAPPER.map(l);
Instant instant = MAPPER.mapToInstant(timestamp);

LocalDateTime back = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());

assertEquals(l, back);
}

@Test
public void testMapLocalDateToTimestampWintertime() {
LocalDateTime l = LocalDateTime.of(2000, 2, 1, 12, 0);

Timestamp timestamp = MAPPER.map(l);
Instant instant = MAPPER.mapToInstant(timestamp);

LocalDateTime back = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());

assertEquals(l, back);
}

@Test
public void mapToInstant_whenSecondsAndNanosIs0_thenMapToNull() {
assertNull(MAPPER.mapToInstant(Timestamp.newBuilder().build()));
}

@Test
public void mapToInstant_whenSecondsAndNanosIsNull_thenMapToNull() {
assertNull(MAPPER.mapToInstant(null));
}

@Test
public void mapToInstant_whenNanosIsSet_thenMapToInstant() {
assertEquals(3000, MAPPER.mapToInstant(Timestamp.newBuilder().setNanos(3000).build()).getNano());
}

@Test
public void mapToInstant_whenValueIsTooLargeForRangeForTimestamp_thenMapFromMaxValidTimestamp() {
assertEquals(MAPPER.mapToInstant(Timestamps.MAX_VALUE), MAPPER.mapToInstant(Timestamp.newBuilder().setSeconds(Long.MAX_VALUE).build()));
}

@Test
public void mapToInstant_whenValueIsTooSmallForRangeForTimestamp_thenMapFromMinValidTimestamp() {
assertEquals(MAPPER.mapToInstant(Timestamps.MIN_VALUE), MAPPER.mapToInstant(Timestamp.newBuilder().setSeconds(-Long.MAX_VALUE).build()));
}

@Test
public void mapInstantToTimestamp_whenValueIsTooLargeForRangeForTimestamp_thenMapToMaxValidTimestamp() {
assertEquals(Timestamps.MAX_VALUE, MAPPER.mapToTimestamp(Instant.now().plus(Integer.MAX_VALUE, ChronoUnit.DAYS)));
}

@Test
public void mapInstantToTimestamp_whenValueIsTooSmallForRangeForTimestamp_thenMapToMinValidTimestamp() {
assertEquals(Timestamps.MIN_VALUE, MAPPER.mapToTimestamp(Instant.now().minus(Integer.MAX_VALUE, ChronoUnit.DAYS)));
}

@Test
public void mapPositiveDuration() {
Duration duration = Duration.of(3, ChronoUnit.NANOS);
no.entur.abt.mapstruct.ProtobufStandardMappings MAPPER = no.entur.abt.mapstruct.ProtobufStandardMappings.INSTANCE;

com.google.protobuf.Duration pbDuration = MAPPER.mapDuration(duration);
Durations.checkValid(pbDuration);
assertEquals(duration, MAPPER.mapDuration(pbDuration));
}
@Test
public void testMapLocalDateToTimestampSummertime() {
LocalDateTime l = LocalDateTime.of(2000, 6, 1, 12, 0);

@Test
public void mapNegativeDurationToProto_whenSecondsAreNegativeAndNanoPositive() {
Duration duration = Duration.ofSeconds(-3, 2);
Timestamp timestamp = MAPPER.map(l);
Instant instant = MAPPER.mapToInstant(timestamp);

com.google.protobuf.Duration pbDuration = MAPPER.mapDuration(duration);
Durations.checkValid(pbDuration);
assertEquals(duration, MAPPER.mapDuration(pbDuration));
}
LocalDateTime back = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());

assertEquals(l, back);
}

@Test
public void mapNegativeDurationToProto_whenSecondsArePositiveAndNanoNegative() {
// Duration.ofSeconds accepts negative values. Will still be stored as positive values in Duration
Duration duration = Duration.ofSeconds(3, -(TimeUnit.SECONDS.toNanos(1) - 2));
@Test
public void testMapLocalDateToTimestampWintertime() {
LocalDateTime l = LocalDateTime.of(2000, 2, 1, 12, 0);

com.google.protobuf.Duration pbDuration = MAPPER.mapDuration(duration);
Durations.checkValid(pbDuration);
assertEquals(duration, MAPPER.mapDuration(pbDuration));
}
Timestamp timestamp = MAPPER.map(l);
Instant instant = MAPPER.mapToInstant(timestamp);

LocalDateTime back = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());

assertEquals(l, back);
}

@Test
public void mapToInstant_whenSecondsAndNanosIs0_thenMapToNull() {
assertNull(MAPPER.mapToInstant(Timestamp.newBuilder().build()));
}

@Test
public void mapToInstant_whenSecondsAndNanosIsNull_thenMapToNull() {
assertNull(MAPPER.mapToInstant(null));
}

@Test
public void mapToInstant_whenNanosIsSet_thenMapToInstant() {
assertEquals(3000, MAPPER.mapToInstant(Timestamp.newBuilder().setNanos(3000).build()).getNano());
}

@Test
public void mapToInstant_whenValueIsTooLargeForRangeForTimestamp_thenMapFromMaxValidTimestamp() {
assertEquals(MAPPER.mapToInstant(Timestamps.MAX_VALUE), MAPPER.mapToInstant(Timestamp.newBuilder().setSeconds(Long.MAX_VALUE).build()));
}

@Test
public void mapToInstant_whenValueIsTooSmallForRangeForTimestamp_thenMapFromMinValidTimestamp() {
assertEquals(MAPPER.mapToInstant(Timestamps.MIN_VALUE), MAPPER.mapToInstant(Timestamp.newBuilder().setSeconds(-Long.MAX_VALUE).build()));
}

@Test
public void mapInstantToTimestamp_whenValueIsTooLargeForRangeForTimestamp_thenMapToMaxValidTimestamp() {
assertEquals(Timestamps.MAX_VALUE, MAPPER.mapToTimestamp(Instant.now().plus(Integer.MAX_VALUE, ChronoUnit.DAYS)));
}

@Test
public void mapInstantToTimestamp_whenValueIsTooSmallForRangeForTimestamp_thenMapToMinValidTimestamp() {
assertEquals(Timestamps.MIN_VALUE, MAPPER.mapToTimestamp(Instant.now().minus(Integer.MAX_VALUE, ChronoUnit.DAYS)));
}

@Test
public void mapToInstant_whenEpoch_thenReturnDefaultTimestamp() {
assertEquals(Timestamp.getDefaultInstance(), MAPPER.mapToTimestamp(Instant.ofEpochSecond(0)));
}

@Test
public void mapPositiveDuration() {
Duration duration = Duration.of(3, ChronoUnit.NANOS);

com.google.protobuf.Duration pbDuration = MAPPER.mapDuration(duration);
Durations.checkValid(pbDuration);
assertEquals(duration, MAPPER.mapDuration(pbDuration));
}

@Test
public void mapNegativeDurationToProto_whenSecondsAreNegativeAndNanoPositive() {
Duration duration = Duration.ofSeconds(-3, 2);

com.google.protobuf.Duration pbDuration = MAPPER.mapDuration(duration);
Durations.checkValid(pbDuration);
assertEquals(duration, MAPPER.mapDuration(pbDuration));
}

@Test
public void mapNegativeDurationToProto_whenSecondsArePositiveAndNanoNegative() {
// Duration.ofSeconds accepts negative values. Will still be stored as positive values in Duration
Duration duration = Duration.ofSeconds(3, -(TimeUnit.SECONDS.toNanos(1) - 2));

com.google.protobuf.Duration pbDuration = MAPPER.mapDuration(duration);
Durations.checkValid(pbDuration);
assertEquals(duration, MAPPER.mapDuration(pbDuration));
}

@Test
public void mapNegativeDuration_fromProto() {
com.google.protobuf.Duration pbDuration = com.google.protobuf.Duration.newBuilder().setSeconds(-10).setNanos(-5).build();

Duration duration = MAPPER.mapDuration(pbDuration);
Durations.checkValid(pbDuration);
assertEquals(pbDuration, MAPPER.mapDuration(duration));
}

@Test
public void mapDurationToProto_whenNull_thenReturnDefaultInstance() {
assertEquals(com.google.protobuf.Duration.getDefaultInstance(), MAPPER.mapDuration((Duration) null));
}

@Test
public void mapLocalDateToProto_whenNull_thenReturnDefaultInstance() {
assertEquals(com.google.type.Date.getDefaultInstance(), MAPPER.mapLocalDate(null));
}

@Test
public void mapLocalDateTimeToProto_whenNull_thenReturnDefaultInstance() {
assertEquals(Timestamp.getDefaultInstance(), MAPPER.map((LocalDateTime) null));
}

@Test
public void mapOffsetDateTimeToProto_whenNull_thenReturnDefaultInstance() {
assertEquals(Timestamp.getDefaultInstance(), MAPPER.map((OffsetDateTime) null));
}

@Test
public void mapInstantToProto_whenNull_thenReturnDefaultInstance() {
assertEquals(Timestamp.getDefaultInstance(), MAPPER.mapToTimestamp(null));
}

@Test
public void mapLocalTimeToProto_whenNull_thenReturnDefaultInstance() {
assertEquals(TimeOfDay.getDefaultInstance(), MAPPER.mapLocalTime(null));
}

@Test
public void mapByteArrayToProto_whenNull_thenReturnEmpty() {
assertEquals(ByteString.empty(), MAPPER.mapByteString((byte[]) null));
}

@Test
public void mapNegativeDuration_fromProto() {
com.google.protobuf.Duration pbDuration = com.google.protobuf.Duration.newBuilder().setSeconds(-10).setNanos(-5).build();

Duration duration = MAPPER.mapDuration(pbDuration);
Durations.checkValid(pbDuration);
assertEquals(pbDuration, MAPPER.mapDuration(duration));
}
}