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() assertConversionsnull37 private fun assertConversions(timeSeries: TimeSeries, json: String) { 38 expect 39 .withMessage("serialize to JSON") 40 .about(json()) 41 .that(JsonGoldenSerializer.toJson(timeSeries)) 42 .isEqualTo(JSONObject(json)) 43 44 expect 45 .withMessage("deserialize from JSON") 46 .that(JsonGoldenSerializer.fromJson(JSONObject(json), timeSeries.createTypeRegistry())) 47 .isEqualTo(timeSeries) 48 } 49 50 @Test emptyTimeSeriesnull51 fun emptyTimeSeries() { 52 assertConversions(TimeSeries(listOf(), listOf()), """{"frame_ids":[],"features":[]}""") 53 } 54 55 @Test timestampFrameId_asNumbernull56 fun timestampFrameId_asNumber() { 57 assertConversions( 58 TimeSeries(listOf(TimestampFrameId(33)), listOf()), 59 """{"frame_ids":[33],"features":[]}""" 60 ) 61 } 62 63 @Test supplementalFrameId_asStringnull64 fun supplementalFrameId_asString() { 65 assertConversions( 66 TimeSeries(listOf(SupplementalFrameId("foo")), listOf()), 67 """{"frame_ids":["foo"],"features":[]}""" 68 ) 69 } 70 71 @Test feature_withoutDataPoint_noTypenull72 fun feature_withoutDataPoint_noType() { 73 assertConversions( 74 TimeSeries(listOf(), listOf(Feature<Int>("foo", emptyList()))), 75 """{"frame_ids":[],"features":[{"name":"foo","data_points":[]}]}""" 76 ) 77 } 78 79 @Test feature_withSingleDataPoint_specifiesTypenull80 fun feature_withSingleDataPoint_specifiesType() { 81 assertConversions( 82 TimeSeries( 83 listOf(TimestampFrameId(1)), 84 listOf(Feature("foo", listOf(42.asDataPoint()))) 85 ), 86 """{"frame_ids":[1],"features":[{"name":"foo","type":"int","data_points":[42]}]}""" 87 ) 88 } 89 90 @Test feature_withMultipleDataPoints_specifiesTypenull91 fun feature_withMultipleDataPoints_specifiesType() { 92 assertConversions( 93 TimeSeries( 94 listOf(TimestampFrameId(1), TimestampFrameId(2)), 95 listOf(Feature("foo", listOf(42.asDataPoint(), 43.asDataPoint()))) 96 ), 97 """{"frame_ids":[1,2], 98 "features":[{"name":"foo","type":"int","data_points":[42,43]}]}}""" 99 ) 100 } 101 102 @Test feature_withNullDataPoints_specifiesTypeAndHandlesNullnull103 fun feature_withNullDataPoints_specifiesTypeAndHandlesNull() { 104 assertConversions( 105 TimeSeries( 106 listOf(TimestampFrameId(1), TimestampFrameId(2)), 107 listOf(Feature("foo", listOf(nullValue(), 43.asDataPoint()))) 108 ), 109 """{"frame_ids":[1,2], 110 "features":[{"name":"foo","type":"int","data_points":[null,43]}]}}""" 111 ) 112 } 113 114 @Test feature_withNotFoundDataPoints_specifiesTypeAndHandlesNotFoundnull115 fun feature_withNotFoundDataPoints_specifiesTypeAndHandlesNotFound() { 116 assertConversions( 117 TimeSeries( 118 listOf(TimestampFrameId(1), TimestampFrameId(2)), 119 listOf(Feature("foo", listOf(notFound(), 43.asDataPoint()))) 120 ), 121 """{"frame_ids":[1,2], 122 "features":[{"name":"foo","type":"int","data_points":[{"type":"not_found"},43]}]}}""" 123 ) 124 } 125 126 @Test feature_withNullOnlyDataPoints_noTypenull127 fun feature_withNullOnlyDataPoints_noType() { 128 assertConversions( 129 TimeSeries( 130 listOf(TimestampFrameId(1)), 131 listOf(Feature<Int>("foo", listOf(nullValue()))) 132 ), 133 """{"frame_ids":[1],"features":[{"name":"foo","data_points":[null]}]}""" 134 ) 135 } 136 137 @Test serialize_featureWithMultipleTypesPerDataPoint_throwsnull138 fun serialize_featureWithMultipleTypesPerDataPoint_throws() { 139 assertThrows(JSONException::class.java) { 140 JsonGoldenSerializer.toJson( 141 TimeSeries( 142 listOf(TimestampFrameId(1), TimestampFrameId(2)), 143 listOf(Feature("foo", listOf(42.asDataPoint(), 42f.asDataPoint()))) 144 ) 145 ) 146 } 147 } 148 149 @Test serialize_featureWithUnknownDataPoints_throwsnull150 fun serialize_featureWithUnknownDataPoints_throws() { 151 assertThrows(JSONException::class.java) { 152 JsonGoldenSerializer.toJson( 153 TimeSeries( 154 listOf(TimestampFrameId(1), TimestampFrameId(2)), 155 listOf(Feature("foo", listOf(42.asDataPoint(), unknownType()))) 156 ) 157 ) 158 } 159 } 160 161 @Test deserialize_featureWithUnknownType_producesUnknownnull162 fun deserialize_featureWithUnknownType_producesUnknown() { 163 val timeSeries = 164 JsonGoldenSerializer.fromJson( 165 JSONObject( 166 """{ 167 "frame_ids":[1,2], 168 "features":[{"name":"foo","type":"bar","data_points":[null,43]}] 169 }""" 170 ), 171 emptyMap() 172 ) 173 174 assertThat(timeSeries) 175 .isEqualTo( 176 TimeSeries( 177 listOf(TimestampFrameId(1), TimestampFrameId(2)), 178 listOf(Feature<Any>("foo", listOf(nullValue(), unknownType()))) 179 ) 180 ) 181 } 182 } 183