1 /* 2 * 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.golden 18 19 import androidx.test.ext.junit.runners.AndroidJUnit4 20 import com.google.common.truth.Expect 21 import com.google.common.truth.Truth.assertThat 22 import org.json.JSONException 23 import org.json.JSONObject 24 import org.junit.Assert.assertThrows 25 import org.junit.Rule 26 import org.junit.Test 27 import org.junit.runner.RunWith 28 import platform.test.motion.golden.DataPoint.Companion.notFound 29 import platform.test.motion.golden.DataPoint.Companion.nullValue 30 import platform.test.motion.golden.DataPoint.Companion.unknownType 31 import platform.test.motion.testing.JsonSubject.Companion.json 32 33 @RunWith(AndroidJUnit4::class) 34 class JsonGoldenSerializerTest { 35 36 @get:Rule val expect: Expect = Expect.create() 37 assertConversionsnull38 private fun assertConversions(timeSeries: TimeSeries, json: String) { 39 expect 40 .withMessage("serialize to JSON") 41 .about(json()) 42 .that(JsonGoldenSerializer.toJson(timeSeries)) 43 .isEqualTo(JSONObject(json)) 44 45 expect 46 .withMessage("deserialize from JSON") 47 .that(JsonGoldenSerializer.fromJson(JSONObject(json), timeSeries.createTypeRegistry())) 48 .isEqualTo(timeSeries) 49 } 50 51 @Test emptyTimeSeriesnull52 fun emptyTimeSeries() { 53 assertConversions(TimeSeries(listOf(), listOf()), """{"frame_ids":[],"features":[]}""") 54 } 55 56 @Test timestampFrameId_asNumbernull57 fun timestampFrameId_asNumber() { 58 assertConversions( 59 TimeSeries(listOf(TimestampFrameId(33)), listOf()), 60 """{"frame_ids":[33],"features":[]}""", 61 ) 62 } 63 64 @Test supplementalFrameId_asStringnull65 fun supplementalFrameId_asString() { 66 assertConversions( 67 TimeSeries(listOf(SupplementalFrameId("foo")), listOf()), 68 """{"frame_ids":["foo"],"features":[]}""", 69 ) 70 } 71 72 @Test feature_withoutDataPoint_noTypenull73 fun feature_withoutDataPoint_noType() { 74 assertConversions( 75 TimeSeries(listOf(), listOf(Feature<Int>("foo", emptyList()))), 76 """{"frame_ids":[],"features":[{"name":"foo","data_points":[]}]}""", 77 ) 78 } 79 80 @Test feature_withSingleDataPoint_specifiesTypenull81 fun feature_withSingleDataPoint_specifiesType() { 82 assertConversions( 83 TimeSeries( 84 listOf(TimestampFrameId(1)), 85 listOf(Feature("foo", listOf(42.asDataPoint()))), 86 ), 87 """{"frame_ids":[1],"features":[{"name":"foo","type":"int","data_points":[42]}]}""", 88 ) 89 } 90 91 @Test feature_withMultipleDataPoints_specifiesTypenull92 fun feature_withMultipleDataPoints_specifiesType() { 93 assertConversions( 94 TimeSeries( 95 listOf(TimestampFrameId(1), TimestampFrameId(2)), 96 listOf(Feature("foo", listOf(42.asDataPoint(), 43.asDataPoint()))), 97 ), 98 """{"frame_ids":[1,2], 99 "features":[{"name":"foo","type":"int","data_points":[42,43]}]}}""", 100 ) 101 } 102 103 @Test feature_withNullDataPoints_specifiesTypeAndHandlesNullnull104 fun feature_withNullDataPoints_specifiesTypeAndHandlesNull() { 105 assertConversions( 106 TimeSeries( 107 listOf(TimestampFrameId(1), TimestampFrameId(2)), 108 listOf(Feature("foo", listOf(nullValue(), 43.asDataPoint()))), 109 ), 110 """{"frame_ids":[1,2], 111 "features":[{"name":"foo","type":"int","data_points":[null,43]}]}}""", 112 ) 113 } 114 115 @Test feature_withNotFoundDataPoints_specifiesTypeAndHandlesNotFoundnull116 fun feature_withNotFoundDataPoints_specifiesTypeAndHandlesNotFound() { 117 assertConversions( 118 TimeSeries( 119 listOf(TimestampFrameId(1), TimestampFrameId(2)), 120 listOf(Feature("foo", listOf(notFound(), 43.asDataPoint()))), 121 ), 122 """{"frame_ids":[1,2], 123 "features":[{"name":"foo","type":"int","data_points":[{"type":"not_found"},43]}]}}""", 124 ) 125 } 126 127 @Test feature_withNullOnlyDataPoints_noTypenull128 fun feature_withNullOnlyDataPoints_noType() { 129 assertConversions( 130 TimeSeries( 131 listOf(TimestampFrameId(1)), 132 listOf(Feature<Int>("foo", listOf(nullValue()))), 133 ), 134 """{"frame_ids":[1],"features":[{"name":"foo","data_points":[null]}]}""", 135 ) 136 } 137 138 @Test serialize_featureWithMultipleTypesPerDataPoint_throwsnull139 fun serialize_featureWithMultipleTypesPerDataPoint_throws() { 140 assertThrows(JSONException::class.java) { 141 JsonGoldenSerializer.toJson( 142 TimeSeries( 143 listOf(TimestampFrameId(1), TimestampFrameId(2)), 144 listOf(Feature("foo", listOf(42.asDataPoint(), 42f.asDataPoint()))), 145 ) 146 ) 147 } 148 } 149 150 @Test serialize_featureWithUnknownDataPoints_throwsnull151 fun serialize_featureWithUnknownDataPoints_throws() { 152 assertThrows(JSONException::class.java) { 153 JsonGoldenSerializer.toJson( 154 TimeSeries( 155 listOf(TimestampFrameId(1), TimestampFrameId(2)), 156 listOf(Feature("foo", listOf(42.asDataPoint(), unknownType()))), 157 ) 158 ) 159 } 160 } 161 162 @Test deserialize_featureWithUnknownType_producesUnknownnull163 fun deserialize_featureWithUnknownType_producesUnknown() { 164 val timeSeries = 165 JsonGoldenSerializer.fromJson( 166 JSONObject( 167 """{ 168 "frame_ids":[1,2], 169 "features":[{"name":"foo","type":"bar","data_points":[null,43]}] 170 }""" 171 ), 172 emptyMap(), 173 ) 174 175 assertThat(timeSeries) 176 .isEqualTo( 177 TimeSeries( 178 listOf(TimestampFrameId(1), TimestampFrameId(2)), 179 listOf(Feature<Any>("foo", listOf(nullValue(), unknownType()))), 180 ) 181 ) 182 } 183 } 184