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 string methods on the ProtoOutputStream class. 28 */ 29 public class ProtoOutputStreamStringTest extends TestCase { 30 31 // ---------------------------------------------------------------------- 32 // writeString 33 // ---------------------------------------------------------------------- 34 35 private static String makeLongString() { 36 final StringBuilder sb = new StringBuilder(0x9fff-0x4E00); 37 // All of the unicode unified CJK characters 38 for (int i=0x4E00; i<=0x9fff; i++) { 39 sb.append((char)(0x4E00 + i)); 40 } 41 return sb.toString(); 42 } 43 44 private static final String LONG_STRING = makeLongString(); 45 46 public void testWriteLongString() throws Exception { 47 testWriteLongString(0); 48 testWriteLongString(1); 49 testWriteLongString(5); 50 testWriteLongString(1024 * 1024); 51 } 52 53 public void testWriteLongString(int chunkSize) throws Exception { 54 final ProtoOutputStream po = new ProtoOutputStream(chunkSize); 55 final long fieldFlags = ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_STRING; 56 57 final String string = LONG_STRING; 58 59 po.writeString(ProtoOutputStream.makeFieldId(1, fieldFlags), string); 60 61 final byte[] utf8 = string.getBytes("UTF-8"); 62 byte[] expected = new byte[utf8.length + 4]; 63 64 // tag 65 expected[0] = (byte)0x0a; 66 // size 67 expected[1] = (byte)0x82; 68 expected[2] = (byte)0xcc; 69 expected[3] = (byte)0x03; 70 // data 71 System.arraycopy(utf8, 0, expected, 4, utf8.length); 72 73 Assert.assertArrayEquals(expected, po.getBytes()); 74 } 75 76 /** 77 * Test writeString. 78 */ 79 public void testWrite() throws Exception { 80 testWrite(0); 81 testWrite(1); 82 testWrite(5); 83 } 84 85 /** 86 * Implementation of testWrite with a given chunkSize. 87 */ 88 public void testWrite(int chunkSize) throws Exception { 89 final ProtoOutputStream po = new ProtoOutputStream(chunkSize); 90 final long fieldFlags = ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_STRING; 91 92 po.writeString(ProtoOutputStream.makeFieldId(1, fieldFlags), null); 93 po.writeString(ProtoOutputStream.makeFieldId(2, fieldFlags), ""); 94 po.writeString(ProtoOutputStream.makeFieldId(3, fieldFlags), "abcd\u3110!"); 95 po.writeString(ProtoOutputStream.makeFieldId(4, fieldFlags), "Hi"); 96 97 final byte[] result = po.getBytes(); 98 Assert.assertArrayEquals(new byte[] { 99 // 1 -> null - default value, not written 100 // 2 -> "" - default value, not written 101 // 3 -> "abcd\u3110!" 102 (byte)0x1a, 103 (byte)0x08, 104 (byte)0x61, (byte)0x62, (byte)0x63, (byte)0x64, 105 (byte)0xe3, (byte)0x84, (byte)0x90, (byte)0x21, 106 // 4 -> "Hi" 107 (byte)0x22, 108 (byte)0x02, 109 (byte)0x48, (byte)0x69, 110 }, result); 111 } 112 113 /** 114 * Test that writing a with ProtoOutputStream matches, and can be read by standard proto. 115 */ 116 public void testWriteCompat() throws Exception { 117 // Nano doesn't work with null. 118 // testWriteCompat(null); 119 120 testWriteCompat(""); 121 testWriteCompat("abcd\u3110!"); 122 } 123 124 /** 125 * Implementation of testWriteCompat with a given value. 126 */ 127 public void testWriteCompat(String val) throws Exception { 128 final int fieldId = 140; 129 final long fieldFlags = ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_STRING; 130 131 final Test.All all = new Test.All(); 132 final ProtoOutputStream po = new ProtoOutputStream(0); 133 134 all.stringField = val; 135 po.writeString(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val); 136 137 final byte[] result = po.getBytes(); 138 final byte[] expected = MessageNano.toByteArray(all); 139 140 Assert.assertArrayEquals(expected, result); 141 142 final Test.All readback = Test.All.parseFrom(result); 143 144 assertEquals(val, readback.stringField); 145 } 146 147 // ---------------------------------------------------------------------- 148 // writeRepeatedString 149 // ---------------------------------------------------------------------- 150 151 /** 152 * Test writeString. 153 */ 154 public void testRepeated() throws Exception { 155 testRepeated(0); 156 testRepeated(1); 157 testRepeated(5); 158 } 159 160 /** 161 * Implementation of testRepeated with a given chunkSize. 162 */ 163 public void testRepeated(int chunkSize) throws Exception { 164 final ProtoOutputStream po = new ProtoOutputStream(chunkSize); 165 final long fieldFlags = ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_STRING; 166 167 po.writeRepeatedString(ProtoOutputStream.makeFieldId(1, fieldFlags), null); 168 po.writeRepeatedString(ProtoOutputStream.makeFieldId(2, fieldFlags), ""); 169 po.writeRepeatedString(ProtoOutputStream.makeFieldId(3, fieldFlags), "abcd\u3110!"); 170 po.writeRepeatedString(ProtoOutputStream.makeFieldId(4, fieldFlags), "Hi"); 171 172 po.writeRepeatedString(ProtoOutputStream.makeFieldId(1, fieldFlags), null); 173 po.writeRepeatedString(ProtoOutputStream.makeFieldId(2, fieldFlags), ""); 174 po.writeRepeatedString(ProtoOutputStream.makeFieldId(3, fieldFlags), "abcd\u3110!"); 175 po.writeRepeatedString(ProtoOutputStream.makeFieldId(4, fieldFlags), "Hi"); 176 177 final byte[] result = po.getBytes(); 178 Assert.assertArrayEquals(new byte[] { 179 // 1 -> null - default value, written when repeated 180 (byte)0x0a, 181 (byte)0x00, 182 // 2 -> "" - default value, written when repeated 183 (byte)0x12, 184 (byte)0x00, 185 // 3 -> "abcd\u3110!" 186 (byte)0x1a, 187 (byte)0x08, 188 (byte)0x61, (byte)0x62, (byte)0x63, (byte)0x64, 189 (byte)0xe3, (byte)0x84, (byte)0x90, (byte)0x21, 190 // 4 -> "Hi" 191 (byte)0x22, 192 (byte)0x02, 193 (byte)0x48, (byte)0x69, 194 195 // 1 -> null - default value, written when repeated 196 (byte)0x0a, 197 (byte)0x00, 198 // 2 -> "" - default value, written when repeated 199 (byte)0x12, 200 (byte)0x00, 201 // 3 -> "abcd\u3110!" 202 (byte)0x1a, 203 (byte)0x08, 204 (byte)0x61, (byte)0x62, (byte)0x63, (byte)0x64, 205 (byte)0xe3, (byte)0x84, (byte)0x90, (byte)0x21, 206 // 4 -> "Hi" 207 (byte)0x22, 208 (byte)0x02, 209 (byte)0x48, (byte)0x69, 210 }, result); 211 } 212 213 /** 214 * Test that writing a with ProtoOutputStream matches, and can be read by standard proto. 215 */ 216 public void testRepeatedCompat() throws Exception { 217 // Nano doesn't work with null. 218 testRepeatedCompat(new String[0]); 219 testRepeatedCompat(new String[] { "", "abcd\u3110!", "Hi", }); 220 } 221 222 /** 223 * Implementation of testRepeatedCompat with a given value. 224 */ 225 public void testRepeatedCompat(String[] val) throws Exception { 226 final int fieldId = 141; 227 final long fieldFlags = ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_STRING; 228 229 final Test.All all = new Test.All(); 230 final ProtoOutputStream po = new ProtoOutputStream(0); 231 232 all.stringFieldRepeated = val; 233 for (int i=0; i<val.length; i++) { 234 po.writeRepeatedString(ProtoOutputStream.makeFieldId(fieldId, fieldFlags), val[i]); 235 } 236 237 final byte[] result = po.getBytes(); 238 final byte[] expected = MessageNano.toByteArray(all); 239 240 Assert.assertArrayEquals(expected, result); 241 242 final Test.All readback = Test.All.parseFrom(result); 243 244 assertNotNull(readback.stringFieldRepeated); 245 assertEquals(val.length, readback.stringFieldRepeated.length); 246 for (int i=0; i<val.length; i++) { 247 assertEquals(val[i], readback.stringFieldRepeated[i]); 248 } 249 } 250 251 /** 252 * Test that if you pass in the wrong type of fieldId, it throws. 253 */ 254 public void testBadFieldIds() { 255 // Single 256 257 // Good Count / Bad Type 258 try { 259 final ProtoOutputStream po = new ProtoOutputStream(); 260 po.writeString(ProtoOutputStream.makeFieldId(1, 261 ProtoOutputStream.FIELD_COUNT_SINGLE | ProtoOutputStream.FIELD_TYPE_DOUBLE), ""); 262 } catch (IllegalArgumentException ex) { 263 // good 264 } 265 266 // Bad Count / Good Type 267 try { 268 final ProtoOutputStream po = new ProtoOutputStream(); 269 po.writeString(ProtoOutputStream.makeFieldId(1, 270 ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_STRING), ""); 271 } catch (IllegalArgumentException ex) { 272 // good 273 } 274 275 // Repeated 276 277 // Good Count / Bad Type 278 try { 279 final ProtoOutputStream po = new ProtoOutputStream(); 280 po.writeRepeatedString(ProtoOutputStream.makeFieldId(1, 281 ProtoOutputStream.FIELD_COUNT_REPEATED | ProtoOutputStream.FIELD_TYPE_DOUBLE), ""); 282 } catch (IllegalArgumentException ex) { 283 // good 284 } 285 286 // Bad Count / Good Type 287 try { 288 final ProtoOutputStream po = new ProtoOutputStream(); 289 po.writeRepeatedString(ProtoOutputStream.makeFieldId(1, 290 ProtoOutputStream.FIELD_COUNT_PACKED | ProtoOutputStream.FIELD_TYPE_STRING), ""); 291 } catch (IllegalArgumentException ex) { 292 // good 293 } 294 } 295 } 296