1 /*
2  * Copyright (C) 2016 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 android.util.proto.cts;
18 
19 import android.util.Log;
20 import android.util.proto.ProtoOutputStream;
21 import static android.util.proto.ProtoOutputStream.*;
22 
23 import com.google.protobuf.nano.MessageNano;
24 import junit.framework.TestCase;
25 import org.junit.Assert;
26 
27 import java.util.HashMap;
28 import java.util.ArrayList;
29 
30 /**
31  * Tests that the write() functions produce the same values as their typed counterparts.
32  */
33 public class ProtoOutputStreamSwitchedWriteTest extends TestCase {
34     private static final String TAG = "ProtoOutputStreamSwitchedWriteTest";
35 
36     public static abstract class WriteTester {
37         public final String name;
38 
WriteTester(String n)39         public WriteTester(String n) {
40             name = n;
41         }
42 
write(Number val, long fieldId, ProtoOutputStream po)43         abstract void write(Number val, long fieldId, ProtoOutputStream po);
44     }
45 
46     private static final HashMap<Long,WriteTester> TYPED = new HashMap<Long,WriteTester>();
47     private static final ArrayList<WriteTester> SWITCHED = new ArrayList<WriteTester>();
48 
49     static {
50         TYPED.put(FIELD_TYPE_DOUBLE | FIELD_COUNT_SINGLE,
51                 new WriteTester("FIELD_TYPE_DOUBLE | FIELD_COUNT_SINGLE") {
52                     @Override
53                     public void write(Number val, long fieldId, ProtoOutputStream po) {
54                         po.writeDouble(fieldId, val.doubleValue());
55                     }
56                 });
57         TYPED.put(FIELD_TYPE_FLOAT | FIELD_COUNT_SINGLE,
58                 new WriteTester("FIELD_TYPE_FLOAT | FIELD_COUNT_SINGLE") {
59                     @Override
60                     public void write(Number val, long fieldId, ProtoOutputStream po) {
61                         po.writeFloat(fieldId, val.floatValue());
62                     }
63                 });
64         TYPED.put(FIELD_TYPE_INT32 | FIELD_COUNT_SINGLE,
65                 new WriteTester("FIELD_TYPE_INT32 | FIELD_COUNT_SINGLE") {
66                     @Override
67                     public void write(Number val, long fieldId, ProtoOutputStream po) {
68                         po.writeInt32(fieldId, val.intValue());
69                     }
70                 });
71         TYPED.put(FIELD_TYPE_INT64 | FIELD_COUNT_SINGLE,
72                 new WriteTester("FIELD_TYPE_INT64 | FIELD_COUNT_SINGLE") {
73                     @Override
74                     public void write(Number val, long fieldId, ProtoOutputStream po) {
75                         po.writeInt64(fieldId, val.longValue());
76                     }
77                 });
78         TYPED.put(FIELD_TYPE_UINT32 | FIELD_COUNT_SINGLE,
79                 new WriteTester("FIELD_TYPE_UINT32 | FIELD_COUNT_SINGLE") {
80                     @Override
81                     public void write(Number val, long fieldId, ProtoOutputStream po) {
82                         po.writeUInt32(fieldId, val.intValue());
83                     }
84                 });
85         TYPED.put(FIELD_TYPE_UINT64 | FIELD_COUNT_SINGLE,
86                 new WriteTester("FIELD_TYPE_UINT64 | FIELD_COUNT_SINGLE") {
87                     @Override
88                     public void write(Number val, long fieldId, ProtoOutputStream po) {
89                         po.writeUInt64(fieldId, val.longValue());
90                     }
91                 });
92         TYPED.put(FIELD_TYPE_SINT32 | FIELD_COUNT_SINGLE,
93                 new WriteTester("FIELD_TYPE_SINT32 | FIELD_COUNT_SINGLE") {
94                     @Override
95                     public void write(Number val, long fieldId, ProtoOutputStream po) {
96                         po.writeSInt32(fieldId, val.intValue());
97                     }
98                 });
99         TYPED.put(FIELD_TYPE_SINT64 | FIELD_COUNT_SINGLE,
100                 new WriteTester("FIELD_TYPE_SINT64 | FIELD_COUNT_SINGLE") {
101                     @Override
102                     public void write(Number val, long fieldId, ProtoOutputStream po) {
103                         po.writeSInt64(fieldId, val.longValue());
104                     }
105                 });
106         TYPED.put(FIELD_TYPE_FIXED32 | FIELD_COUNT_SINGLE,
107                 new WriteTester("FIELD_TYPE_FIXED32 | FIELD_COUNT_SINGLE") {
108                     @Override
109                     public void write(Number val, long fieldId, ProtoOutputStream po) {
110                         po.writeFixed32(fieldId, val.intValue());
111                     }
112                 });
113         TYPED.put(FIELD_TYPE_FIXED64 | FIELD_COUNT_SINGLE,
114                 new WriteTester("FIELD_TYPE_FIXED64 | FIELD_COUNT_SINGLE") {
115                     @Override
116                     public void write(Number val, long fieldId, ProtoOutputStream po) {
117                         po.writeFixed64(fieldId, val.longValue());
118                     }
119                 });
120         TYPED.put(FIELD_TYPE_SFIXED32 | FIELD_COUNT_SINGLE,
121                 new WriteTester("FIELD_TYPE_SFIXED32 | FIELD_COUNT_SINGLE") {
122                     @Override
123                     public void write(Number val, long fieldId, ProtoOutputStream po) {
124                         po.writeSFixed32(fieldId, val.intValue());
125                     }
126                 });
127         TYPED.put(FIELD_TYPE_SFIXED64 | FIELD_COUNT_SINGLE,
128                 new WriteTester("FIELD_TYPE_SFIXED64 | FIELD_COUNT_SINGLE") {
129                     @Override
130                     public void write(Number val, long fieldId, ProtoOutputStream po) {
131                         po.writeSFixed64(fieldId, val.longValue());
132                     }
133                 });
134         TYPED.put(FIELD_TYPE_BOOL | FIELD_COUNT_SINGLE,
135                 new WriteTester("FIELD_TYPE_BOOL | FIELD_COUNT_SINGLE") {
136                     @Override
137                     public void write(Number val, long fieldId, ProtoOutputStream po) {
138                         po.writeBool(fieldId, val.longValue() != 0);
139                     }
140                 });
141         TYPED.put(FIELD_TYPE_ENUM | FIELD_COUNT_SINGLE,
142                 new WriteTester("FIELD_TYPE_ENUM | FIELD_COUNT_SINGLE") {
143                     @Override
144                     public void write(Number val, long fieldId, ProtoOutputStream po) {
145                         po.writeEnum(fieldId, val.intValue());
146                     }
147                 });
148 
SWITCHED.add(new WriteTester("write(long, double)") { @Override public void write(Number val, long fieldId, ProtoOutputStream po) { po.write(fieldId, val.doubleValue()); } })149         SWITCHED.add(new WriteTester("write(long, double)") {
150                     @Override
151                     public void write(Number val, long fieldId, ProtoOutputStream po) {
152                         po.write(fieldId, val.doubleValue());
153                     }
154                 });
SWITCHED.add(new WriteTester("write(long, float)") { @Override public void write(Number val, long fieldId, ProtoOutputStream po) { po.write(fieldId, val.floatValue()); } })155         SWITCHED.add(new WriteTester("write(long, float)") {
156                     @Override
157                     public void write(Number val, long fieldId, ProtoOutputStream po) {
158                         po.write(fieldId, val.floatValue());
159                     }
160                 });
SWITCHED.add(new WriteTester("write(long, int)") { @Override public void write(Number val, long fieldId, ProtoOutputStream po) { po.write(fieldId, val.intValue()); } })161         SWITCHED.add(new WriteTester("write(long, int)") {
162                     @Override
163                     public void write(Number val, long fieldId, ProtoOutputStream po) {
164                         po.write(fieldId, val.intValue());
165                     }
166                 });
SWITCHED.add(new WriteTester("write(long, long)") { @Override public void write(Number val, long fieldId, ProtoOutputStream po) { po.write(fieldId, val.longValue()); } })167         SWITCHED.add(new WriteTester("write(long, long)") {
168                     @Override
169                     public void write(Number val, long fieldId, ProtoOutputStream po) {
170                         po.write(fieldId, val.longValue());
171                     }
172                 });
173     }
174 
testAWrite(Number val, long fieldId, WriteTester typed, WriteTester switched)175     private static void testAWrite(Number val, long fieldId,
176             WriteTester typed, WriteTester switched) {
177         final ProtoOutputStream switchedPo = new ProtoOutputStream();
178         final ProtoOutputStream typedPo = new ProtoOutputStream();
179 
180         typed.write(val, fieldId, typedPo);
181         switched.write(val, fieldId, switchedPo);
182 
183         final byte[] switchedResult = switchedPo.getBytes();
184         final byte[] typedResult = typedPo.getBytes();
185 
186         try {
187             Assert.assertArrayEquals(typedResult, switchedResult);
188         } catch (Throwable ex) {
189             throw new RuntimeException("Test for " + typed.name + " and "
190                     + switched.name + " value=" + val + " (" + val.getClass().getSimpleName()
191                     + ") failed: " + ex.getMessage(), ex);
192         }
193     }
194 
testWrites(Number val)195     public static void testWrites(Number val) {
196         for (HashMap.Entry<Long,WriteTester> entry: TYPED.entrySet()) {
197             final long fieldId = ((long)entry.getKey()) | 1;
198             final WriteTester typed = entry.getValue();
199 
200             for (WriteTester switched: SWITCHED) {
201                 testAWrite(val, fieldId, typed, switched);
202             }
203         }
204     }
205 /**
206      * Test double
207      */
testWriteDouble()208     public void testWriteDouble() {
209         testWrites(new Double(0));
210         testWrites(new Double(-1));
211         testWrites(new Double(1));
212         testWrites(new Double(100));
213     }
214 
215     /**
216      * Test float
217      */
testWriteFloat()218     public void testWriteFloat() {
219         testWrites(new Float(0));
220         testWrites(new Float(-1));
221         testWrites(new Float(1));
222         testWrites(new Float(100));
223     }
224 
225     /**
226      * Test int
227      */
testWriteInteger()228     public void testWriteInteger() {
229         testWrites(new Integer(0));
230         testWrites(new Integer(-1));
231         testWrites(new Integer(1));
232         testWrites(new Integer(100));
233     }
234 
235     /**
236      * Test long
237      */
testWriteLong()238     public void testWriteLong() {
239         testWrites(new Long(0));
240         testWrites(new Long(-1));
241         testWrites(new Long(1));
242         testWrites(new Long(100));
243     }
244 
245     /**
246      * Test single strings
247      */
testWriteString()248     public void testWriteString() {
249         final ProtoOutputStream typedPo = new ProtoOutputStream();
250         final ProtoOutputStream switchedPo = new ProtoOutputStream();
251 
252         testString(1, "", typedPo, switchedPo);
253         testString(2, null, typedPo, switchedPo);
254         testString(3, "ABCD", typedPo, switchedPo);
255 
256         final byte[] typedResult = typedPo.getBytes();
257         final byte[] switchedResult = switchedPo.getBytes();
258 
259         Assert.assertArrayEquals(typedResult, switchedResult);
260     }
261 
testString(int id, String val, ProtoOutputStream typed, ProtoOutputStream switched)262     private void testString(int id, String val,
263             ProtoOutputStream typed, ProtoOutputStream switched) {
264         switched.write(FIELD_TYPE_STRING | FIELD_COUNT_SINGLE | id, val);
265         typed.writeString(FIELD_TYPE_STRING | FIELD_COUNT_SINGLE | id, val);
266     }
267 
268     /**
269      * Test repeated strings
270      */
testWriteRepeatedString()271     public void testWriteRepeatedString() {
272         final ProtoOutputStream typedPo = new ProtoOutputStream();
273         final ProtoOutputStream switchedPo = new ProtoOutputStream();
274 
275         testRepeatedString(1, "", typedPo, switchedPo);
276         testRepeatedString(2, null, typedPo, switchedPo);
277         testRepeatedString(3, "ABCD", typedPo, switchedPo);
278 
279         final byte[] typedResult = typedPo.getBytes();
280         final byte[] switchedResult = switchedPo.getBytes();
281 
282         Assert.assertArrayEquals(typedResult, switchedResult);
283     }
284 
testRepeatedString(int id, String val, ProtoOutputStream typed, ProtoOutputStream switched)285     private void testRepeatedString(int id, String val,
286             ProtoOutputStream typed, ProtoOutputStream switched) {
287         switched.write(FIELD_TYPE_STRING | FIELD_COUNT_REPEATED | id, val);
288         typed.writeRepeatedString(FIELD_TYPE_STRING | FIELD_COUNT_REPEATED | id, val);
289     }
290 
291 }
292