diff --git a/firebase-dataconnect/connectors/src/androidTest/kotlin/com/google/firebase/dataconnect/connectors/demo/DateScalarIntegrationTest.kt b/firebase-dataconnect/connectors/src/androidTest/kotlin/com/google/firebase/dataconnect/connectors/demo/DateScalarIntegrationTest.kt index ba1ba058141..ce5a6a052bc 100644 --- a/firebase-dataconnect/connectors/src/androidTest/kotlin/com/google/firebase/dataconnect/connectors/demo/DateScalarIntegrationTest.kt +++ b/firebase-dataconnect/connectors/src/androidTest/kotlin/com/google/firebase/dataconnect/connectors/demo/DateScalarIntegrationTest.kt @@ -16,20 +16,26 @@ package com.google.firebase.dataconnect.connectors.demo -import com.google.common.truth.Truth.assertThat import com.google.firebase.dataconnect.DataConnectException import com.google.firebase.dataconnect.connectors.demo.testutil.DemoConnectorIntegrationTestBase import com.google.firebase.dataconnect.generated.GeneratedMutation import com.google.firebase.dataconnect.generated.GeneratedQuery -import com.google.firebase.dataconnect.testutil.MAX_DATE -import com.google.firebase.dataconnect.testutil.MIN_DATE +import com.google.firebase.dataconnect.testutil.EdgeCases import com.google.firebase.dataconnect.testutil.ZERO_DATE -import com.google.firebase.dataconnect.testutil.assertThrows +import com.google.firebase.dataconnect.testutil.dateAndString +import com.google.firebase.dataconnect.testutil.dateAndStringOffDayBoundary import com.google.firebase.dataconnect.testutil.dateFromYearMonthDayUTC import com.google.firebase.dataconnect.testutil.executeWithEmptyVariables -import com.google.firebase.dataconnect.testutil.randomDate import com.google.firebase.dataconnect.testutil.withDataDeserializer import com.google.firebase.dataconnect.testutil.withVariablesSerializer +import io.kotest.assertions.assertSoftly +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.assertions.withClue +import io.kotest.matchers.shouldBe +import io.kotest.property.Arb +import io.kotest.property.arbitrary.int +import io.kotest.property.arbitrary.next +import io.kotest.property.checkAll import java.util.Date import kotlinx.coroutines.test.runTest import kotlinx.serialization.Serializable @@ -39,26 +45,25 @@ import org.junit.Test class DateScalarIntegrationTest : DemoConnectorIntegrationTestBase() { @Test - fun insertTypicalValueForNonNullField() = runTest { - val date = dateFromYearMonthDayUTC(1944, 1, 1) - val key = connector.insertNonNullDate.execute(date).data.key - assertNonNullDateByKeyEquals(key, "1944-01-01") - } - - @Test - fun insertMaxValueForNonNullDateField() = runTest { - val key = connector.insertNonNullDate.execute(MIN_DATE).data.key - assertNonNullDateByKeyEquals(key, "1583-01-01") + fun nonNullDate_insert_NormalCases() = runTest { + checkAll(20, Arb.dateAndString()) { + val key = connector.insertNonNullDate.execute(it.date).data.key + assertNonNullDateByKeyEquals(key, it.string) + } } @Test - fun insertMinValueForNonNullDateField() = runTest { - val key = connector.insertNonNullDate.execute(MAX_DATE).data.key - assertNonNullDateByKeyEquals(key, "9999-12-31") + fun nonNullDate_insert_EdgeCases() = runTest { + assertSoftly { + EdgeCases.dateAndStrings.forEach { + val key = connector.insertNonNullDate.execute(it.date).data.key + assertNonNullDateByKeyEquals(key, it.string) + } + } } @Test - fun insertValueWithTimeForNonNullDateField() = runTest { + fun nonNullDate_insert_ShouldIgnoreTimeZone() = runTest { // Use a date that, when converted to UTC, in on a different date to verify that the server does // the expected thing; that is, that it _drops_ the time zone information (rather than // converting the date to UTC then taking the YYYY-MM-DD of that). The server would use the date @@ -69,16 +74,15 @@ class DateScalarIntegrationTest : DemoConnectorIntegrationTestBase() { } @Test - fun insertDateNotOnExactDateBoundaryForNonNullDateField() = runTest { - val dateOnDateBoundary = dateFromYearMonthDayUTC(2000, 9, 14) - val dateOffDateBoundary = Date(dateOnDateBoundary.time + 7200) - - val key = connector.insertNonNullDate.execute(dateOffDateBoundary).data.key - assertNonNullDateByKeyEquals(key, dateOnDateBoundary) + fun nonNullDate_insert_ShouldIgnoreTime() = runTest { + checkAll(20, Arb.dateAndStringOffDayBoundary()) { + val key = connector.insertNonNullDate.execute(it.date).data.key + assertNonNullDateByKeyEquals(key, it.string) + } } @Test - fun insertNoVariablesForNonNullDateFieldsWithSchemaDefaults() = runTest { + fun nonNullDatesWithDefaults_insert_ShouldUseDefaultValuesIfNoVariablesSpecified() = runTest { val key = connector.insertNonNullDatesWithDefaults.execute {}.data.key val queryResult = connector.getNonNullDatesWithDefaultsByKey.execute(key) @@ -86,117 +90,113 @@ class DateScalarIntegrationTest : DemoConnectorIntegrationTestBase() { // value is used for both fields to which it is set. val expectedRequestTime = queryResult.data.nonNullDatesWithDefaults!!.requestTime1 - assertThat( - queryResult.equals( - GetNonNullDatesWithDefaultsByKeyQuery.Data( - GetNonNullDatesWithDefaultsByKeyQuery.Data.NonNullDatesWithDefaults( - valueWithVariableDefault = dateFromYearMonthDayUTC(6904, 11, 30), - valueWithSchemaDefault = dateFromYearMonthDayUTC(2112, 1, 31), - epoch = ZERO_DATE, - requestTime1 = expectedRequestTime, - requestTime2 = expectedRequestTime, - ) + queryResult.data shouldBe + GetNonNullDatesWithDefaultsByKeyQuery.Data( + GetNonNullDatesWithDefaultsByKeyQuery.Data.NonNullDatesWithDefaults( + valueWithVariableDefault = dateFromYearMonthDayUTC(6904, 11, 30), + valueWithSchemaDefault = dateFromYearMonthDayUTC(2112, 1, 31), + epoch = ZERO_DATE, + requestTime1 = expectedRequestTime, + requestTime2 = expectedRequestTime, ) ) - ) } @Test - fun insertNullForNonNullDateFieldShouldFail() = runTest { - assertThrows(DataConnectException::class) { + fun nonNullDate_insert_ShouldFailIfDateVariableIsNull() = runTest { + shouldThrow { connector.insertNonNullDate.executeWithStringVariables(null).data.key } } @Test - fun insertIntForNonNullDateFieldShouldFail() = runTest { - assertThrows(DataConnectException::class) { - connector.insertNonNullDate.executeWithIntVariables(999_888).data.key + fun nonNullDate_insert_ShouldFailIfDateVariableIsAnInt() = runTest { + shouldThrow { + connector.insertNonNullDate.executeWithIntVariables(Arb.int().next(rs)).data.key } } @Test - fun insertWithMissingValueNonNullDateFieldShouldFail() = runTest { - assertThrows(DataConnectException::class) { + fun nonNullDate_insert_ShouldFailIfDateVariableIsOmitted() = runTest { + shouldThrow { connector.insertNonNullDate.executeWithEmptyVariables().data.key } } @Test - fun insertInvalidDatesValuesForNonNullDateFieldShouldFail() = runTest { + fun nonNullDate_insert_ShouldFailIfDateVariableIsMalformed() = runTest { for (invalidDate in invalidDates) { - assertThrows(DataConnectException::class) { + shouldThrow { connector.insertNonNullDate.executeWithStringVariables(invalidDate).data.key } } } @Test - fun updateNonNullDateFieldToAnotherValidValue() = runTest { - val date1 = randomDate() - val date2 = dateFromYearMonthDayUTC(5654, 12, 1) - val key = connector.insertNonNullDate.execute(date1).data.key - connector.updateNonNullDate.execute(key) { value = date2 } - assertNonNullDateByKeyEquals(key, "5654-12-01") - } - - @Test - fun updateNonNullDateFieldToMinValue() = runTest { - val date = randomDate() - val key = connector.insertNonNullDate.execute(date).data.key - connector.updateNonNullDate.execute(key) { value = MIN_DATE } - assertNonNullDateByKeyEquals(key, "1583-01-01") + fun nonNullDate_update_NormalCases() = runTest { + checkAll(20, Arb.dateAndString(), Arb.dateAndString()) { date1, date2 -> + val key = connector.insertNonNullDate.execute(date1.date).data.key + connector.updateNonNullDate.execute(key) { value = date2.date } + assertNonNullDateByKeyEquals(key, date2.string) + } } @Test - fun updateNonNullDateFieldToMaxValue() = runTest { - val date = randomDate() - val key = connector.insertNonNullDate.execute(date).data.key - connector.updateNonNullDate.execute(key) { value = MAX_DATE } - assertNonNullDateByKeyEquals(key, "9999-12-31") + fun nonNullDate_update_EdgeCases() = runTest { + val edgeCases = EdgeCases.dateAndStrings + val dates1 = edgeCases + List(edgeCases.size) { Arb.dateAndString().next(rs) } + edgeCases + val dates2 = List(edgeCases.size) { Arb.dateAndString().next(rs) } + edgeCases + edgeCases + + assertSoftly { + for ((date1, date2) in dates1.zip(dates2)) { + withClue("date1=${date1.string} date2=${date2.string}") { + val key = connector.insertNonNullDate.execute(date1.date).data.key + connector.updateNonNullDate.execute(key) { value = date2.date } + assertNonNullDateByKeyEquals(key, date2.string) + } + } + } } @Test - fun updateNonNullDateFieldToAnUndefinedValue() = runTest { - val date = randomDate() - val key = connector.insertNonNullDate.execute(date).data.key + fun nonNullDate_update_DateVariableOmitted() = runTest { + val date = Arb.dateAndString().next(rs) + val key = connector.insertNonNullDate.execute(date.date).data.key connector.updateNonNullDate.execute(key) {} - assertNonNullDateByKeyEquals(key, date) + assertNonNullDateByKeyEquals(key, date.date) } @Test - fun insertTypicalValueForNullableField() = runTest { - val date = dateFromYearMonthDayUTC(7611, 12, 1) - val key = connector.insertNullableDate.execute { value = date }.data.key - assertNullableDateByKeyEquals(key, "7611-12-01") - } - - @Test - fun insertMaxValueForNullableDateField() = runTest { - val key = connector.insertNullableDate.execute { value = MIN_DATE }.data.key - assertNullableDateByKeyEquals(key, "1583-01-01") - } - - @Test - fun insertMinValueForNullableDateField() = runTest { - val key = connector.insertNullableDate.execute { value = MAX_DATE }.data.key - assertNullableDateByKeyEquals(key, "9999-12-31") + fun nullableDate_insert_NormalCases() = runTest { + checkAll(20, Arb.dateAndString()) { + val key = connector.insertNullableDate.execute { value = it.date }.data.key + assertNullableDateByKeyEquals(key, it.string) + } } @Test - fun insertNullForNullableDateField() = runTest { - val key = connector.insertNullableDate.execute { value = null }.data.key - assertNullableDateByKeyEquals(key, null) + fun nullableDate_insert_EdgeCases() = runTest { + val edgeCases = EdgeCases.dateAndStrings + listOf(null) + assertSoftly { + edgeCases.forEach { + val key = connector.insertNullableDate.execute { value = it?.date }.data.key + if (it === null) { + assertNullableDateByKeyHasNullInnerValue(key) + } else { + assertNullableDateByKeyEquals(key, it.string) + } + } + } } @Test - fun insertUndefinedForNullableDateField() = runTest { + fun nullableDate_insert_ShouldUseNullIfDateVariableIsOmitted() = runTest { val key = connector.insertNullableDate.execute {}.data.key - assertNullableDateByKeyEquals(key, null) + assertNullableDateByKeyHasNullInnerValue(key) } @Test - fun insertValueWithTimeForNullableDateField() = runTest { + fun nullableDate_insert_ShouldIgnoreTimeZone() = runTest { // Use a date that, when converted to UTC, in on a different date to verify that the server does // the expected thing; that is, that it _drops_ the time zone information (rather than // converting the date to UTC then taking the YYYY-MM-DD of that). The server would use the date @@ -207,32 +207,31 @@ class DateScalarIntegrationTest : DemoConnectorIntegrationTestBase() { } @Test - fun insertDateNotOnExactDateBoundaryForNullableDateField() = runTest { - val dateOnDateBoundary = dateFromYearMonthDayUTC(1812, 12, 22) - val dateOffDateBoundary = Date(dateOnDateBoundary.time + 7200) - - val key = connector.insertNullableDate.execute { value = dateOffDateBoundary }.data.key - assertNullableDateByKeyEquals(key, dateOnDateBoundary) + fun nullableDate_insert_ShouldIgnoreTime() = runTest { + checkAll(20, Arb.dateAndStringOffDayBoundary()) { + val key = connector.insertNullableDate.execute { value = it.date }.data.key + assertNullableDateByKeyEquals(key, it.string) + } } @Test - fun insertIntForNullableDateFieldShouldFail() = runTest { - assertThrows(DataConnectException::class) { - connector.insertNullableDate.executeWithIntVariables(999_888).data.key + fun nullableDate_insert_ShouldFailIfDateVariableIsAnInt() = runTest { + shouldThrow { + connector.insertNullableDate.executeWithIntVariables(Arb.int().next(rs)).data.key } } @Test - fun insertInvalidDatesValuesForNullableDateFieldShouldFail() = runTest { + fun nullableDate_insert_ShouldFailIfDateVariableIsMalformed() = runTest { for (invalidDate in invalidDates) { - assertThrows(DataConnectException::class) { - connector.insertNullableDate.executeWithStringVariables(invalidDate).data.key + shouldThrow { + connector.insertNonNullDate.executeWithStringVariables(invalidDate).data.key } } } @Test - fun insertNoVariablesForNullableDateFieldsWithSchemaDefaults() = runTest { + fun nullableDatesWithDefaults_insert_ShouldUseDefaultValuesIfNoVariablesSpecified() = runTest { val key = connector.insertNullableDatesWithDefaults.execute {}.data.key val queryResult = connector.getNullableDatesWithDefaultsByKey.execute(key) @@ -240,65 +239,63 @@ class DateScalarIntegrationTest : DemoConnectorIntegrationTestBase() { // value is used for both fields to which it is set. val expectedRequestTime = queryResult.data.nullableDatesWithDefaults!!.requestTime1 - assertThat( - queryResult.equals( - GetNullableDatesWithDefaultsByKeyQuery.Data( - GetNullableDatesWithDefaultsByKeyQuery.Data.NullableDatesWithDefaults( - valueWithVariableDefault = dateFromYearMonthDayUTC(8113, 2, 9), - valueWithSchemaDefault = dateFromYearMonthDayUTC(1921, 12, 2), - epoch = ZERO_DATE, - requestTime1 = expectedRequestTime, - requestTime2 = expectedRequestTime, - ) + queryResult.data shouldBe + GetNullableDatesWithDefaultsByKeyQuery.Data( + GetNullableDatesWithDefaultsByKeyQuery.Data.NullableDatesWithDefaults( + valueWithVariableDefault = dateFromYearMonthDayUTC(8113, 2, 9), + valueWithSchemaDefault = dateFromYearMonthDayUTC(1921, 12, 2), + epoch = ZERO_DATE, + requestTime1 = expectedRequestTime, + requestTime2 = expectedRequestTime, ) ) - ) } @Test - fun updateNullableDateFieldToAnotherValidValue() = runTest { - val date1 = randomDate() - val date2 = dateFromYearMonthDayUTC(5654, 12, 1) - val key = connector.insertNullableDate.execute { value = date1 }.data.key - connector.updateNullableDate.execute(key) { value = date2 } - assertNullableDateByKeyEquals(key, "5654-12-01") - } - - @Test - fun updateNullableDateFieldToMinValue() = runTest { - val date = randomDate() - val key = connector.insertNullableDate.execute { value = date }.data.key - connector.updateNullableDate.execute(key) { value = MIN_DATE } - assertNullableDateByKeyEquals(key, "1583-01-01") + fun nullableDate_update_NormalCases() = runTest { + checkAll(20, Arb.dateAndString(), Arb.dateAndString()) { date1, date2 -> + val key = connector.insertNullableDate.execute { value = date1.date }.data.key + connector.updateNullableDate.execute(key) { value = date2.date } + assertNullableDateByKeyEquals(key, date2.string) + } } @Test - fun updateNullableDateFieldToMaxValue() = runTest { - val date = randomDate() - val key = connector.insertNullableDate.execute { value = date }.data.key - connector.updateNullableDate.execute(key) { value = MAX_DATE } - assertNullableDateByKeyEquals(key, "9999-12-31") + fun nullableDate_update_EdgeCases() = runTest { + val edgeCases = EdgeCases.dateAndStrings + val dates1 = edgeCases + List(edgeCases.size) { Arb.dateAndString().next(rs) } + edgeCases + val dates2 = List(edgeCases.size) { Arb.dateAndString().next(rs) } + edgeCases + edgeCases + + assertSoftly { + for ((date1, date2) in dates1.zip(dates2)) { + withClue("date1=${date1.string} date2=${date2.string}") { + val key = connector.insertNullableDate.execute { value = date1.date }.data.key + connector.updateNullableDate.execute(key) { value = date2.date } + assertNullableDateByKeyEquals(key, date2.string) + } + } + } } @Test - fun updateNullableDateFieldToNull() = runTest { - val date = randomDate() + fun nullableDate_update_UpdateNonNullValueToNull() = runTest { + val date = Arb.dateAndString().next(rs).date val key = connector.insertNullableDate.execute { value = date }.data.key connector.updateNullableDate.execute(key) { value = null } - assertNullableDateByKeyEquals(key, null) + assertNullableDateByKeyHasNullInnerValue(key) } @Test - fun updateNullableDateFieldToNonNull() = runTest { - val date = randomDate() + fun nullableDate_update_UpdateNullValueToNonNull() = runTest { + val date = Arb.dateAndString().next(rs).date val key = connector.insertNullableDate.execute { value = null }.data.key connector.updateNullableDate.execute(key) { value = date } assertNullableDateByKeyEquals(key, date) } @Test - fun updateNullableDateFieldToAnUndefinedValue() = runTest { - val date = randomDate() + fun nullableDate_update_DateVariableOmitted() = runTest { + val date = Arb.dateAndString().next(rs).date val key = connector.insertNullableDate.execute { value = date }.data.key connector.updateNullableDate.execute(key) {} assertNullableDateByKeyEquals(key, date) @@ -309,13 +306,22 @@ class DateScalarIntegrationTest : DemoConnectorIntegrationTestBase() { connector.getNonNullDateByKey .withDataDeserializer(serializer()) .execute(key) - assertThat(queryResult.data).isEqualTo(GetDateByKeyQueryStringData(expected)) + queryResult.data shouldBe GetDateByKeyQueryStringData(expected) } private suspend fun assertNonNullDateByKeyEquals(key: NonNullDateKey, expected: Date) { val queryResult = connector.getNonNullDateByKey.execute(key) - assertThat(queryResult.data) - .isEqualTo(GetNonNullDateByKeyQuery.Data(GetNonNullDateByKeyQuery.Data.Value(expected))) + queryResult.data shouldBe + GetNonNullDateByKeyQuery.Data(GetNonNullDateByKeyQuery.Data.Value(expected)) + } + + private suspend fun assertNullableDateByKeyHasNullInnerValue(key: NullableDateKey) { + val queryResult = + connector.getNullableDateByKey + .withDataDeserializer(serializer()) + .execute(key) + queryResult.data shouldBe + GetDateByKeyQueryStringData(GetDateByKeyQueryStringData.DateStringValue(null)) } private suspend fun assertNullableDateByKeyEquals(key: NullableDateKey, expected: String) { @@ -323,13 +329,13 @@ class DateScalarIntegrationTest : DemoConnectorIntegrationTestBase() { connector.getNullableDateByKey .withDataDeserializer(serializer()) .execute(key) - assertThat(queryResult.data).isEqualTo(GetDateByKeyQueryStringData(expected)) + queryResult.data shouldBe GetDateByKeyQueryStringData(expected) } - private suspend fun assertNullableDateByKeyEquals(key: NullableDateKey, expected: Date?) { + private suspend fun assertNullableDateByKeyEquals(key: NullableDateKey, expected: Date) { val queryResult = connector.getNullableDateByKey.execute(key) - assertThat(queryResult.data) - .isEqualTo(GetNullableDateByKeyQuery.Data(GetNullableDateByKeyQuery.Data.Value(expected))) + queryResult.data shouldBe + GetNullableDateByKeyQuery.Data(GetNullableDateByKeyQuery.Data.Value(expected)) } /** @@ -340,7 +346,8 @@ class DateScalarIntegrationTest : DemoConnectorIntegrationTestBase() { @Serializable private data class GetDateByKeyQueryStringData(val value: DateStringValue?) { constructor(value: String) : this(DateStringValue(value)) - @Serializable data class DateStringValue(val value: String) + + @Serializable data class DateStringValue(val value: String?) } /** diff --git a/firebase-dataconnect/testutil/src/main/kotlin/com/google/firebase/dataconnect/testutil/Arbs.kt b/firebase-dataconnect/testutil/src/main/kotlin/com/google/firebase/dataconnect/testutil/Arbs.kt index 98a65552747..a4a0b1d6ca2 100644 --- a/firebase-dataconnect/testutil/src/main/kotlin/com/google/firebase/dataconnect/testutil/Arbs.kt +++ b/firebase-dataconnect/testutil/src/main/kotlin/com/google/firebase/dataconnect/testutil/Arbs.kt @@ -19,6 +19,8 @@ package com.google.firebase.dataconnect.testutil import com.google.firebase.dataconnect.ConnectorConfig import com.google.firebase.dataconnect.DataConnectSettings import com.google.firebase.dataconnect.FirebaseDataConnect.CallerSdkType +import com.google.firebase.dataconnect.testutil.EdgeCases.Dates.MAX_YEAR +import com.google.firebase.dataconnect.testutil.EdgeCases.Dates.MIN_YEAR import com.google.firebase.util.nextAlphanumericString import io.kotest.property.Arb import io.kotest.property.arbitrary.Codepoint @@ -35,11 +37,14 @@ import io.kotest.property.arbitrary.filter import io.kotest.property.arbitrary.filterIsInstance import io.kotest.property.arbitrary.filterNot import io.kotest.property.arbitrary.int +import io.kotest.property.arbitrary.long import io.kotest.property.arbitrary.map import io.kotest.property.arbitrary.merge import io.kotest.property.arbitrary.next import io.kotest.property.arbitrary.of import io.kotest.property.arbitrary.string +import java.util.Date +import kotlin.random.nextInt fun Arb.filterNotNull(): Arb = filter { it !== null }.map { it!! } @@ -168,3 +173,55 @@ fun Arb.Companion.callerSdkType(): Arb = arbitrary { fun Arb.Companion.tag(): Arb = arbitrary { "tag" + Arb.string(size = 10, Codepoint.alphanumeric()).bind() } + +private fun maxDayForMonth(month: Int): Int { + return when (month) { + 1 -> 31 + 2 -> 28 + 3 -> 31 + 4 -> 30 + 5 -> 31 + 6 -> 30 + 7 -> 31 + 8 -> 31 + 9 -> 30 + 10 -> 31 + 11 -> 30 + 12 -> 31 + else -> + throw IllegalArgumentException("invalid month: $month (must be between 1 and 12, inclusive)") + } +} + +data class DateAndString(val date: Date, val string: String) + +fun Arb.Companion.dateAndString(): Arb = + arbitrary(edgecases = EdgeCases.dateAndStrings) { rs -> + val year = rs.random.nextInt(MIN_YEAR..MAX_YEAR) + val month = rs.random.nextInt(1..12) + val day = rs.random.nextInt(1..maxDayForMonth(month)) + + val date = dateFromYearMonthDayUTC(year, month, day) + + val yearStr = "$year" + val monthStr = "$month".padStart(2, '0') + val dayStr = "$day".padStart(2, '0') + val string = "$yearStr-$monthStr-$dayStr" + + DateAndString(date, string) + } + +fun Arb.Companion.dateAndStringOffDayBoundary(): Arb = + arbitrary(edgecases = EdgeCases.dateAndStringOffDayBoundary) { + // Skip dates with the maximum year, as adding non-zero milliseconds will result in the year + // 10,000, which is invalid. + val dateAndStrings = Arb.dateAndString().filterNot { it.string.contains("9999") } + // Don't add more than 86_400_000L, the number of milliseconds per day, to the date. + val millisOffsets = Arb.long(0L until 86_400_000L) + + val dateAndString = dateAndStrings.bind() + val millisOffset = millisOffsets.bind() + val dateOffDayBoundary = Date(dateAndString.date.time + millisOffset) + + DateAndString(dateOffDayBoundary, dateAndString.string) + } diff --git a/firebase-dataconnect/testutil/src/main/kotlin/com/google/firebase/dataconnect/testutil/EdgeCases.kt b/firebase-dataconnect/testutil/src/main/kotlin/com/google/firebase/dataconnect/testutil/EdgeCases.kt index a0d8d4088c6..ab09ffa2082 100644 --- a/firebase-dataconnect/testutil/src/main/kotlin/com/google/firebase/dataconnect/testutil/EdgeCases.kt +++ b/firebase-dataconnect/testutil/src/main/kotlin/com/google/firebase/dataconnect/testutil/EdgeCases.kt @@ -16,6 +16,10 @@ package com.google.firebase.dataconnect.testutil +import java.util.Date +import java.util.GregorianCalendar +import java.util.TimeZone + object EdgeCases { val numbers: List = @@ -82,4 +86,50 @@ object EdgeCases { } val anyScalars: List = primitives + lists + maps + listOf(null) + + object Dates { + const val MIN_YEAR = 1583 + const val MAX_YEAR = 9999 + + val MIN: Date + get() = dateFromYearMonthDayUTC(MIN_YEAR, 1, 1) + val MIN_DATE_AND_STRING: DateAndString + get() = DateAndString(MIN, "$MIN_YEAR-01-01") + + val MAX: Date + get() = dateFromYearMonthDayUTC(MAX_YEAR, 12, 31) + val MAX_DATE_AND_STRING: DateAndString + get() = DateAndString(MAX, "$MAX_YEAR-12-31") + + val ZERO: Date + get() = GregorianCalendar(TimeZone.getTimeZone("UTC")).apply { timeInMillis = 0 }.time + val ZERO_DATE_AND_STRING: DateAndString + get() = DateAndString(ZERO, "1970-01-01") + } + + val dates: List = listOf(Dates.MIN, Dates.MAX, Dates.ZERO) + + val dateAndStrings: List = + listOf( + Dates.MIN_DATE_AND_STRING, + Dates.MAX_DATE_AND_STRING, + Dates.ZERO_DATE_AND_STRING, + ) + + val dateAndStringOffDayBoundary: List = + listOf( + DateAndString( + Date(Dates.MIN_DATE_AND_STRING.date.time + 1), + Dates.MIN_DATE_AND_STRING.string + ), + DateAndString( + Date(Dates.MAX_DATE_AND_STRING.date.time + 1), + Dates.MAX_DATE_AND_STRING.string + ), + DateAndString( + Date(Dates.ZERO_DATE_AND_STRING.date.time + 1), + Dates.ZERO_DATE_AND_STRING.string + ), + DateAndString(Date(Dates.ZERO_DATE_AND_STRING.date.time - 1), "1969-12-31"), + ) }