1 /* <lambda>null2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package platform.test.motion.truth 18 19 import androidx.test.ext.junit.runners.AndroidJUnit4 20 import com.google.common.truth.Correspondence 21 import com.google.common.truth.ExpectFailure 22 import com.google.common.truth.TruthFailureSubject 23 import org.junit.Test 24 import org.junit.runner.RunWith 25 import platform.test.motion.golden.Feature 26 import platform.test.motion.golden.SupplementalFrameId 27 import platform.test.motion.golden.TimeSeries 28 import platform.test.motion.golden.TimestampFrameId 29 import platform.test.motion.golden.asDataPoint 30 import platform.test.motion.truth.TimeSeriesSubject.Companion.assertThat 31 32 @RunWith(AndroidJUnit4::class) 33 class TimeSeriesSubjectTest { 34 35 @Test 36 fun isEqualTo_nonTimeSeriesObject_usesDefaultImplementation() { 37 with(assertThrows { assertThat(TimeSeries(listOf(), emptyList())).isEqualTo("foo") }) { 38 factValue("expected").isEqualTo("foo") 39 factValue("but was").isEqualTo("TimeSeries(frameIds=[], features={})") 40 } 41 } 42 43 @Test 44 fun isEqualTo_matchingTimeSeries() { 45 val timeSeries = createTimeSeries(2) 46 47 assertThat(timeSeries).isEqualTo(timeSeries.copy()) 48 } 49 50 @Test 51 fun isEqualTo_actualHasDifferentFrameTimes() { 52 val expected = createTimeSeries(2) 53 val actual = 54 expected.copy(frameIds = listOf(expected.frameIds[0], SupplementalFrameId("x"))) 55 56 with(assertThrows { assertThat(actual).isEqualTo(expected) }) { 57 factKeys().contains("TimeSeries.frames does not match") 58 factValue("| expected").isEqualTo("[0ms, 1ms]") 59 factValue("| but got").isEqualTo("[0ms, x]") 60 factValue("| unexpected (1)").isEqualTo("[x]") 61 factValue("| missing (1)").isEqualTo("[1ms]") 62 63 factKeys().comparingElementsUsing(startsWith).doesNotContain("TimeSeries.features") 64 } 65 } 66 67 @Test 68 fun isEqualTo_missingFrame() { 69 val expected = createTimeSeries(3) 70 val actual = createTimeSeries(2) 71 72 with(assertThrows { assertThat(actual).isEqualTo(expected) }) { 73 factKeys().contains("TimeSeries.frames does not match") 74 75 factValue("| expected").isEqualTo("[0ms, 1ms, 2ms]") 76 factValue("| but got").isEqualTo("[0ms, 1ms]") 77 factValue("| missing (1)").isEqualTo("[2ms]") 78 79 factKeys().comparingElementsUsing(startsWith).doesNotContain("TimeSeries.features") 80 } 81 } 82 83 @Test 84 fun isEqualTo_additionalFrame() { 85 val expected = createTimeSeries(1) 86 val actual = createTimeSeries(2) 87 88 with(assertThrows { assertThat(actual).isEqualTo(expected) }) { 89 factKeys().contains("TimeSeries.frames does not match") 90 91 factValue("| expected").isEqualTo("[0ms]") 92 factValue("| but got").isEqualTo("[0ms, 1ms]") 93 factValue("| unexpected (1)").isEqualTo("[1ms]") 94 95 factKeys().comparingElementsUsing(startsWith).doesNotContain("TimeSeries.features") 96 } 97 } 98 99 @Test 100 fun isEqualTo_missingFeature() { 101 val expected = createTimeSeries(2) 102 val actual = 103 expected.copy( 104 features = 105 buildMap { 106 putAll(expected.features) 107 remove("bar") 108 } 109 ) 110 111 with(assertThrows { assertThat(actual).isEqualTo(expected) }) { 112 factKeys().contains("TimeSeries.features does not match") 113 114 factValue("| missing (1)").isEqualTo("[bar]") 115 } 116 } 117 118 @Test 119 fun isEqualTo_additionalFeature() { 120 val expected = createTimeSeries(2) 121 val actual = 122 expected.copy( 123 features = 124 buildMap { 125 putAll(expected.features) 126 put("baz", createIntFeature("baz", 2)) 127 } 128 ) 129 130 with(assertThrows { assertThat(actual).isEqualTo(expected) }) { 131 factKeys().contains("TimeSeries.features does not match") 132 133 factValue("| unexpected (1)").isEqualTo("[baz]") 134 } 135 } 136 137 @Test 138 fun isEqualTo_actualHasDifferentDataPoint() { 139 val expected = 140 TimeSeries( 141 createFrames(2), 142 listOf(Feature("foo", listOf(1.asDataPoint(), 2.asDataPoint()))) 143 ) 144 val actual = 145 TimeSeries( 146 createFrames(2), 147 listOf(Feature("foo", listOf(1.asDataPoint(), 3.asDataPoint()))) 148 ) 149 150 with(assertThrows { assertThat(actual).isEqualTo(expected) }) { 151 factKeys() 152 .containsExactly( 153 "TimeSeries.features[foo].dataPoints do not match", 154 "| @1ms", 155 "| expected", 156 "| but was" 157 ) 158 .inOrder() 159 160 factValue("| expected").isEqualTo("2 (int)") 161 factValue("| but was").isEqualTo("3 (int)") 162 } 163 } 164 165 private fun createTimeSeries(frameCount: Int) = 166 TimeSeries( 167 createFrames(frameCount), 168 listOf(createIntFeature("foo", frameCount), createStringFeature("bar", frameCount)) 169 ) 170 171 private fun createFrames(frameCount: Int) = List(frameCount) { TimestampFrameId(it.toLong()) } 172 private fun createIntFeature(name: String, dataPoints: Int) = 173 Feature(name, List(dataPoints) { it.asDataPoint() }) 174 private fun createStringFeature(name: String, dataPoints: Int) = 175 Feature(name, List(dataPoints) { it.toString().asDataPoint() }) 176 177 private inline fun assertThrows(body: () -> Unit): TruthFailureSubject { 178 try { 179 body() 180 } catch (e: Throwable) { 181 if (e is AssertionError) { 182 return ExpectFailure.assertThat(e) 183 } 184 throw e 185 } 186 throw AssertionError("Body completed successfully. Expected AssertionError") 187 } 188 companion object { 189 val startsWith: Correspondence<String, String> = 190 Correspondence.from( 191 { actual, expected -> checkNotNull(actual).startsWith(checkNotNull(expected)) }, 192 "starts with" 193 ) 194 } 195 } 196