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.proto.ProtoOutputStream; 20 import android.util.proto.cts.nano.Test; 21 22 import com.google.protobuf.nano.MessageNano; 23 import junit.framework.TestCase; 24 import org.junit.Assert; 25 26 /** 27 * Test the enum methods on the ProtoOutputStream class. 28 * 29 * Nano proto CodedOutputByteBufferNano has writeEnum that writes a raw varint, 30 * but the generated code uses writeInt32. So we will follow that implementation. 31 */ 32 public class ProtoOutputStreamEnumTest extends TestCase { 33 34 // ---------------------------------------------------------------------- 35 // writeEnum 36 // ---------------------------------------------------------------------- 37 38 /** 39 * Test writeEnum. 40 */ 41 public void testWrite() throws Exception { 42 testWrite(0); 43 testWrite(1); 44 testWrite(5); 45 } 46 47 /** 48 * Implementation of testWrite with a given chunkSize. 49 */ 50 public void testWrite(int chunkSize) throws Exception { 51 final ProtoOutputStream po = new ProtoOutputStream(chunkSize); 52 final long fieldFlags = ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_ENUM; 53 54 po.writeEnum(ProtoOutputStream.makeFieldId(1, fieldFlags), 0); 55 po.writeEnum(ProtoOutputStream.makeFieldId(2, fieldFlags), 1); 56 po.writeEnum(ProtoOutputStream.makeFieldId(3, fieldFlags), -1); 57 po.writeEnum(ProtoOutputStream.makeFieldId(4, fieldFlags), Integer.MIN_VALUE); 58 po.writeEnum(ProtoOutputStream.makeFieldId(5, fieldFlags), Integer.MAX_VALUE); 59 60 final byte[] result = po.getBytes(); 61 Assert.assertArrayEquals(new byte[] { 62 // 1 -> 0 - default value, not written 63 // 2 -> 1 64 (byte)0x10, 65 (byte)0x01, 66 // 3 -> -1 67 (byte)0x18, 68 (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, 69 (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01, 70 // 4 -> MIN_VALUE 71 (byte)0x20, 72 (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0xf8, 73 (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01, 74 // 5 -> MAX_VALUE 75 (byte)0x28, 76 (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x07, 77 }, result); 78 } 79 80 /** 81 * Test that writing a with ProtoOutputStream matches, and can be read by standard proto. 82 */ 83 public void testWriteCompat() throws Exception { 84 testWriteCompat(0); 85 testWriteCompat(1); 86 testWriteCompat(-1); 87 testWriteCompat(Integer.MIN_VALUE); 88 testWriteCompat(Integer.MAX_VALUE); 89 } 90 91 /** 92 * Implementation of testWriteCompat with a given value. 93 */ 94 public void testWriteCompat(int val) throws Exception { 95 final int fieldId = 160; 96 final long fieldFlags = ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_ENUM; 97 98 final Test.All all = new Test.All(); 99 final ProtoOutputStream po = new ProtoOutputStream(0); 100 101 all.outsideField = val; 102 po.writeEnum(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val); 103 104 final byte[] result = po.getBytes(); 105 final byte[] expected = MessageNano.toByteArray(all); 106 107 Assert.assertArrayEquals(expected, result); 108 109 final Test.All readback = Test.All.parseFrom(result); 110 111 // The generated code filters the values, so only check those. 112 if (val == Test.OUTSIDE_0 || val == Test.OUTSIDE_1) { 113 assertEquals(val, readback.outsideField); 114 } 115 } 116 117 // ---------------------------------------------------------------------- 118 // writeRepeatedEnum 119 // ---------------------------------------------------------------------- 120 121 /** 122 * Test writeEnum. 123 */ 124 public void testRepeated() throws Exception { 125 testRepeated(0); 126 testRepeated(1); 127 testRepeated(5); 128 } 129 130 /** 131 * Implementation of testRepeated with a given chunkSize. 132 */ 133 public void testRepeated(int chunkSize) throws Exception { 134 final ProtoOutputStream po = new ProtoOutputStream(chunkSize); 135 final long fieldFlags = ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_ENUM; 136 137 po.writeRepeatedEnum(ProtoOutputStream.makeFieldId(1, fieldFlags), 0); 138 po.writeRepeatedEnum(ProtoOutputStream.makeFieldId(2, fieldFlags), 1); 139 po.writeRepeatedEnum(ProtoOutputStream.makeFieldId(3, fieldFlags), -1); 140 po.writeRepeatedEnum(ProtoOutputStream.makeFieldId(4, fieldFlags), Integer.MIN_VALUE); 141 po.writeRepeatedEnum(ProtoOutputStream.makeFieldId(5, fieldFlags), Integer.MAX_VALUE); 142 143 po.writeRepeatedEnum(ProtoOutputStream.makeFieldId(1, fieldFlags), 0); 144 po.writeRepeatedEnum(ProtoOutputStream.makeFieldId(2, fieldFlags), 1); 145 po.writeRepeatedEnum(ProtoOutputStream.makeFieldId(3, fieldFlags), -1); 146 po.writeRepeatedEnum(ProtoOutputStream.makeFieldId(4, fieldFlags), Integer.MIN_VALUE); 147 po.writeRepeatedEnum(ProtoOutputStream.makeFieldId(5, fieldFlags), Integer.MAX_VALUE); 148 149 final byte[] result = po.getBytes(); 150 Assert.assertArrayEquals(new byte[] { 151 // 1 -> 0 - default value, written when repeated 152 (byte)0x08, 153 (byte)0x00, 154 // 2 -> 1 155 (byte)0x10, 156 (byte)0x01, 157 // 3 -> -1 158 (byte)0x18, 159 (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, 160 (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01, 161 // 4 -> MIN_VALUE 162 (byte)0x20, 163 (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0xf8, 164 (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01, 165 // 5 -> MAX_VALUE 166 (byte)0x28, 167 (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x07, 168 169 // 1 -> 0 - default value, written when repeated 170 (byte)0x08, 171 (byte)0x00, 172 // 2 -> 1 173 (byte)0x10, 174 (byte)0x01, 175 // 3 -> -1 176 (byte)0x18, 177 (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, 178 (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01, 179 // 4 -> MIN_VALUE 180 (byte)0x20, 181 (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0xf8, 182 (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01, 183 // 5 -> MAX_VALUE 184 (byte)0x28, 185 (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x07, 186 }, result); 187 } 188 189 /** 190 * Test that writing a with ProtoOutputStream matches, and can be read by standard proto. 191 */ 192 public void testRepeatedCompat() throws Exception { 193 testRepeatedCompat(new int[0]); 194 testRepeatedCompat(new int[] { 0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE }); 195 } 196 197 /** 198 * Implementation of testRepeatedCompat with a given value. 199 */ 200 public void testRepeatedCompat(int[] val) throws Exception { 201 final int fieldId = 161; 202 final long fieldFlags = ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_ENUM; 203 204 final Test.All all = new Test.All(); 205 final ProtoOutputStream po = new ProtoOutputStream(0); 206 207 all.outsideFieldRepeated = val; 208 for (int i=0; i<val.length; i++) { 209 po.writeRepeatedEnum(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val[i]); 210 } 211 212 final byte[] result = po.getBytes(); 213 final byte[] expected = MessageNano.toByteArray(all); 214 215 Assert.assertArrayEquals(expected, result); 216 217 final Test.All readback = Test.All.parseFrom(result); 218 219 // Nano proto drops values that are outside the range, so disable 220 // this test. 221 /* 222 assertNotNull(readback.outsideFieldRepeated); 223 assertEquals(val.length, readback.outsideFieldRepeated.length); 224 for (int i=0; i<val.length; i++) { 225 assertEquals(val[i], readback.outsideFieldRepeated[i]); 226 } 227 */ 228 } 229 230 // ---------------------------------------------------------------------- 231 // writePackedEnum 232 // ---------------------------------------------------------------------- 233 234 /** 235 * Test writeEnum. 236 */ 237 public void testPacked() throws Exception { 238 testPacked(0); 239 testPacked(1); 240 testPacked(5); 241 } 242 243 /** 244 * Create an array of the val, and write it. 245 */ 246 private void writePackedEnum(ProtoOutputStream po, int fieldId, int val) { 247 final long fieldFlags = ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_ENUM; 248 po.writePackedEnum(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), new int[] { val, val }); 249 } 250 251 /** 252 * Implementation of testPacked with a given chunkSize. 253 */ 254 public void testPacked(int chunkSize) throws Exception { 255 final ProtoOutputStream po = new ProtoOutputStream(chunkSize); 256 final long fieldFlags = ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_ENUM; 257 258 po.writePackedEnum(ProtoOutputStream.makeFieldId(1000, fieldFlags), null); 259 po.writePackedEnum(ProtoOutputStream.makeFieldId(1001, fieldFlags), new int[0]); 260 writePackedEnum(po, 1, 0); 261 writePackedEnum(po, 2, 1); 262 writePackedEnum(po, 3, -1); 263 writePackedEnum(po, 4, Integer.MIN_VALUE); 264 writePackedEnum(po, 5, Integer.MAX_VALUE); 265 266 final byte[] result = po.getBytes(); 267 Assert.assertArrayEquals(new byte[] { 268 // 1 -> 0 - default value, written when repeated 269 (byte)0x0a, 270 (byte)0x02, 271 (byte)0x00, 272 (byte)0x00, 273 // 2 -> 1 274 (byte)0x12, 275 (byte)0x02, 276 (byte)0x01, 277 (byte)0x01, 278 // 3 -> -1 279 (byte)0x1a, 280 (byte)0x14, 281 (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, 282 (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01, 283 284 (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, 285 (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01, 286 287 // 4 -> MIN_VALUE 288 (byte)0x22, 289 (byte)0x14, 290 (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0xf8, 291 (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01, 292 293 (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0xf8, 294 (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x01, 295 296 // 5 -> MAX_VALUE 297 (byte)0x2a, 298 (byte)0x0a, 299 (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x07, 300 301 (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x07, 302 }, result); 303 } 304 305 /** 306 * Test that writing a with ProtoOutputStream matches, and can be read by standard proto. 307 */ 308 public void testPackedCompat() throws Exception { 309 testPackedCompat(new int[] {}); 310 testPackedCompat(new int[] { 0, 1 }); 311 312 // Nano proto has a bug. It gets the size with computeInt32SizeNoTag (correctly) 313 // but incorrectly uses writeRawVarint32 to write the value for negative numbers. 314 //testPackedCompat(new int[] { 0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE }); 315 } 316 317 /** 318 * Implementation of testPackedEnumCompat with a given value. 319 */ 320 public void testPackedCompat(int[] val) throws Exception { 321 final int fieldId = 162; 322 final long fieldFlags = ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_ENUM; 323 324 final Test.All all = new Test.All(); 325 final ProtoOutputStream po = new ProtoOutputStream(0); 326 327 all.outsideFieldPacked = val; 328 po.writePackedEnum(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val); 329 330 final byte[] result = po.getBytes(); 331 final byte[] expected = MessageNano.toByteArray(all); 332 333 Assert.assertArrayEquals(expected, result); 334 335 final Test.All readback = Test.All.parseFrom(result); 336 337 Assert.assertArrayEquals(val, readback.outsideFieldPacked); 338 } 339 340 /** 341 * Test that if you pass in the wrong type of fieldId, it throws. 342 */ 343 public void testBadFieldIds() { 344 // Single 345 346 // Good Count / Bad Type 347 try { 348 final ProtoOutputStream po = new ProtoOutputStream(); 349 po.writeEnum(ProtoOutputStream.makeFieldId(1, 350 ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_DOUBLE), 0); 351 } catch (IllegalArgumentException ex) { 352 // good 353 } 354 355 // Bad Count / Good Type 356 try { 357 final ProtoOutputStream po = new ProtoOutputStream(); 358 po.writeEnum(ProtoOutputStream.makeFieldId(1, 359 ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_ENUM), 0); 360 } catch (IllegalArgumentException ex) { 361 // good 362 } 363 364 // Repeated 365 366 // Good Count / Bad Type 367 try { 368 final ProtoOutputStream po = new ProtoOutputStream(); 369 po.writeRepeatedEnum(ProtoOutputStream.makeFieldId(1, 370 ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_DOUBLE), 0); 371 } catch (IllegalArgumentException ex) { 372 // good 373 } 374 375 // Bad Count / Good Type 376 try { 377 final ProtoOutputStream po = new ProtoOutputStream(); 378 po.writeRepeatedEnum(ProtoOutputStream.makeFieldId(1, 379 ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_ENUM), 0); 380 } catch (IllegalArgumentException ex) { 381 // good 382 } 383 384 // Packed 385 386 // Good Count / Bad Type 387 try { 388 final ProtoOutputStream po = new ProtoOutputStream(); 389 po.writePackedEnum(ProtoOutputStream.makeFieldId(1, 390 ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_DOUBLE), 391 new int[0]); 392 } catch (IllegalArgumentException ex) { 393 // good 394 } 395 396 // Bad Count / Good Type 397 try { 398 final ProtoOutputStream po = new ProtoOutputStream(); 399 po.writePackedEnum(ProtoOutputStream.makeFieldId(1, 400 ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_ENUM), 401 new int[0]); 402 } catch (IllegalArgumentException ex) { 403 // good 404 } 405 } 406 } 407 408