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 TimeSeriesSubject.MANAGE_GOLDEN_DOCUMENTATION, 158 ) 159 .inOrder() 160 161 factValue("| expected").isEqualTo("2 (int)") 162 factValue("| but was").isEqualTo("3 (int)") 163 } 164 } 165 166 @Test 167 fun isEqualTo_manageGoldenMessageAddedOnError() { 168 val expected = 169 TimeSeries( 170 createFrames(2), 171 listOf(Feature("foo", listOf(1.asDataPoint(), 2.asDataPoint()))), 172 ) 173 val actual = 174 TimeSeries( 175 createFrames(2), 176 listOf(Feature("foo", listOf(1.asDataPoint(), 3.asDataPoint()))), 177 ) 178 179 with(assertThrows { assertThat(actual).isEqualTo(expected) }) { 180 factKeys().contains(TimeSeriesSubject.MANAGE_GOLDEN_DOCUMENTATION) 181 } 182 } 183 184 private fun createTimeSeries(frameCount: Int) = 185 TimeSeries( 186 createFrames(frameCount), 187 listOf(createIntFeature("foo", frameCount), createStringFeature("bar", frameCount)), 188 ) 189 190 private fun createFrames(frameCount: Int) = List(frameCount) { TimestampFrameId(it.toLong()) } 191 192 private fun createIntFeature(name: String, dataPoints: Int) = 193 Feature(name, List(dataPoints) { it.asDataPoint() }) 194 195 private fun createStringFeature(name: String, dataPoints: Int) = 196 Feature(name, List(dataPoints) { it.toString().asDataPoint() }) 197 198 private inline fun assertThrows(body: () -> Unit): TruthFailureSubject { 199 try { 200 body() 201 } catch (e: Throwable) { 202 if (e is AssertionError) { 203 return ExpectFailure.assertThat(e) 204 } 205 throw e 206 } 207 throw AssertionError("Body completed successfully. Expected AssertionError") 208 } 209 210 companion object { 211 val startsWith: Correspondence<String, String> = 212 Correspondence.from( 213 { actual, expected -> checkNotNull(actual).startsWith(checkNotNull(expected)) }, 214 "starts with", 215 ) 216 } 217 } 218