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 bytes methods on the ProtoOutputStream class. 28 */ 29 public class ProtoOutputStreamBytesTest extends TestCase { 30 private static byte[] makeData() { 31 final byte[] data = new byte[523]; 32 for (int i=0; i<data.length; i++) { 33 data[i] = (byte)i; 34 } 35 return data; 36 } 37 38 // ---------------------------------------------------------------------- 39 // writeBytes 40 // ---------------------------------------------------------------------- 41 42 /** 43 * Test writeBytes. 44 */ 45 public void testWrite() throws Exception { 46 testWrite(0); 47 testWrite(1); 48 testWrite(5); 49 } 50 51 /** 52 * Implementation of testWrite with a given chunkSize. 53 */ 54 public void testWrite(int chunkSize) throws Exception { 55 final ProtoOutputStream po = new ProtoOutputStream(chunkSize); 56 final long fieldFlags = ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_BYTES; 57 58 final byte[] data = makeData(); 59 60 po.writeBytes(ProtoOutputStream.makeFieldId(1, fieldFlags), data); 61 62 final byte[] expected = new byte[data.length + 3]; 63 expected[0] = (byte)0x0a; 64 expected[1] = (byte)0x8b; 65 expected[2] = (byte)0x04; 66 for (int i=0; i<data.length; i++) { 67 expected[i+3] = (byte)i; 68 } 69 70 Assert.assertArrayEquals(expected, po.getBytes()); 71 } 72 73 /** 74 * Test that writing a with ProtoOutputStream matches, and can be read by standard proto. 75 */ 76 public void testWriteCompat() throws Exception { 77 // Nano doesn't work with null. 78 // testWriteCompat(null); 79 80 testWriteCompat(new byte[0]); 81 testWriteCompat(new byte[] { 0 } ); 82 testWriteCompat(new byte[] { 1 } ); 83 testWriteCompat(makeData()); 84 } 85 86 /** 87 * Implementation of testWriteCompat with a given value. 88 */ 89 public void testWriteCompat(byte[] val) throws Exception { 90 final int fieldId = 150; 91 final long fieldFlags = ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_BYTES; 92 93 final Test.All all = new Test.All(); 94 final ProtoOutputStream po = new ProtoOutputStream(0); 95 96 all.bytesField = val; 97 po.writeBytes(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val); 98 99 final byte[] result = po.getBytes(); 100 final byte[] expected = MessageNano.toByteArray(all); 101 102 Assert.assertArrayEquals(expected, result); 103 104 final Test.All readback = Test.All.parseFrom(result); 105 106 Assert.assertArrayEquals(val, readback.bytesField); 107 } 108 109 // ---------------------------------------------------------------------- 110 // writeRepeatedBytes 111 // ---------------------------------------------------------------------- 112 113 /** 114 * Test writeBytes. 115 */ 116 public void testRepeated() throws Exception { 117 testRepeated(0); 118 testRepeated(1); 119 testRepeated(5); 120 } 121 122 /** 123 * Implementation of testRepeated with a given chunkSize. 124 */ 125 public void testRepeated(int chunkSize) throws Exception { 126 final ProtoOutputStream po = new ProtoOutputStream(chunkSize); 127 final long fieldFlags = ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_BYTES; 128 129 po.writeRepeatedBytes(ProtoOutputStream.makeFieldId(1, fieldFlags), null); 130 po.writeRepeatedBytes(ProtoOutputStream.makeFieldId(2, fieldFlags), new byte[0]); 131 po.writeRepeatedBytes(ProtoOutputStream.makeFieldId(3, fieldFlags), 132 new byte[] { 0, 1, 2, 3, 4, 5 }); 133 po.writeRepeatedBytes(ProtoOutputStream.makeFieldId(4, fieldFlags), 134 new byte[] { (byte)0xff, (byte)0xfe, (byte)0xfd, (byte)0xfc }); 135 136 po.writeRepeatedBytes(ProtoOutputStream.makeFieldId(1, fieldFlags), null); 137 po.writeRepeatedBytes(ProtoOutputStream.makeFieldId(2, fieldFlags), new byte[0]); 138 po.writeRepeatedBytes(ProtoOutputStream.makeFieldId(3, fieldFlags), 139 new byte[] { 0, 1, 2, 3, 4, 5 }); 140 po.writeRepeatedBytes(ProtoOutputStream.makeFieldId(4, fieldFlags), 141 new byte[] { (byte)0xff, (byte)0xfe, (byte)0xfd, (byte)0xfc }); 142 143 final byte[] result = po.getBytes(); 144 Assert.assertArrayEquals(new byte[] { 145 // 1 -> null - default value, written when repeated 146 (byte)0x0a, 147 (byte)0x00, 148 // 2 -> { } - default value, written when repeated 149 (byte)0x12, 150 (byte)0x00, 151 // 3 -> { 0, 1, 2, 3, 4, 5 } 152 (byte)0x1a, 153 (byte)0x06, 154 (byte)0x00, (byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04, (byte)0x05, 155 // 4 -> { (byte)0xff, (byte)0xfe, (byte)0xfd, (byte)0xfc } 156 (byte)0x22, 157 (byte)0x04, 158 (byte)0xff, (byte)0xfe, (byte)0xfd, (byte)0xfc, 159 160 // 1 -> null - default value, written when repeated 161 (byte)0x0a, 162 (byte)0x00, 163 // 2 -> { } - default value, written when repeated 164 (byte)0x12, 165 (byte)0x00, 166 // 3 -> { 0, 1, 2, 3, 4, 5 } 167 (byte)0x1a, 168 (byte)0x06, 169 (byte)0x00, (byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04, (byte)0x05, 170 // 4 -> { (byte)0xff, (byte)0xfe, (byte)0xfd, (byte)0xfc } 171 (byte)0x22, 172 (byte)0x04, 173 (byte)0xff, (byte)0xfe, (byte)0xfd, (byte)0xfc, 174 }, result); 175 } 176 177 /** 178 * Test that writing a with ProtoOutputStream matches, and can be read by standard proto. 179 */ 180 public void testRepeatedCompat() throws Exception { 181 testRepeatedCompat(new byte[0][]); 182 testRepeatedCompat(new byte[][] { 183 new byte[0], 184 new byte[] { 0 }, 185 new byte[] { 1 }, 186 makeData(), 187 }); 188 } 189 190 /** 191 * Implementation of testRepeatedCompat with a given value. 192 */ 193 public void testRepeatedCompat(byte[][] val) throws Exception { 194 final int fieldId = 151; 195 final long fieldFlags = ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_BYTES; 196 197 final Test.All all = new Test.All(); 198 final ProtoOutputStream po = new ProtoOutputStream(0); 199 200 all.bytesFieldRepeated = val; 201 for (int i=0; i<val.length; i++) { 202 po.writeRepeatedBytes(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val[i]); 203 } 204 205 final byte[] result = po.getBytes(); 206 final byte[] expected = MessageNano.toByteArray(all); 207 208 Assert.assertArrayEquals(expected, result); 209 210 final Test.All readback = Test.All.parseFrom(result); 211 212 assertNotNull(readback.bytesFieldRepeated); 213 assertEquals(val.length, readback.bytesFieldRepeated.length); 214 for (int i=0; i<val.length; i++) { 215 Assert.assertArrayEquals(val[i], readback.bytesFieldRepeated[i]); 216 } 217 } 218 219 /** 220 * Test that if you pass in the wrong type of fieldId, it throws. 221 */ 222 public void testBadFieldIds() { 223 // Single 224 225 // Good Count / Bad Type 226 try { 227 final ProtoOutputStream po = new ProtoOutputStream(); 228 po.writeBytes(ProtoOutputStream.makeFieldId(1, 229 ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_DOUBLE), 230 new byte[0]); 231 } catch (IllegalArgumentException ex) { 232 // good 233 } 234 235 // Bad Count / Good Type 236 try { 237 final ProtoOutputStream po = new ProtoOutputStream(); 238 po.writeBytes(ProtoOutputStream.makeFieldId(1, 239 ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_BYTES), 240 new byte[0]); 241 } catch (IllegalArgumentException ex) { 242 // good 243 } 244 245 // Repeated 246 247 // Good Count / Bad Type 248 try { 249 final ProtoOutputStream po = new ProtoOutputStream(); 250 po.writeRepeatedBytes(ProtoOutputStream.makeFieldId(1, 251 ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_DOUBLE), 252 new byte[0]); 253 } catch (IllegalArgumentException ex) { 254 // good 255 } 256 257 // Bad Count / Good Type 258 try { 259 final ProtoOutputStream po = new ProtoOutputStream(); 260 po.writeRepeatedBytes(ProtoOutputStream.makeFieldId(1, 261 ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_BYTES), 262 new byte[0]); 263 } catch (IllegalArgumentException ex) { 264 // good 265 } 266 } 267 } 268