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