Home | History | Annotate | Download | only in cts
      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