1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2008 Google Inc. All rights reserved. 3 // https://developers.google.com/protocol-buffers/ 4 // 5 // Redistribution and use in source and binary forms, with or without 6 // modification, are permitted provided that the following conditions are 7 // met: 8 // 9 // * Redistributions of source code must retain the above copyright 10 // notice, this list of conditions and the following disclaimer. 11 // * Redistributions in binary form must reproduce the above 12 // copyright notice, this list of conditions and the following disclaimer 13 // in the documentation and/or other materials provided with the 14 // distribution. 15 // * Neither the name of Google Inc. nor the names of its 16 // contributors may be used to endorse or promote products derived from 17 // this software without specific prior written permission. 18 // 19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31 package com.google.protobuf; 32 33 import java.io.ByteArrayInputStream; 34 import java.io.ByteArrayOutputStream; 35 import java.io.InputStream; 36 import java.io.ObjectInputStream; 37 import java.io.ObjectOutputStream; 38 import java.io.UnsupportedEncodingException; 39 import java.util.Arrays; 40 import java.util.Iterator; 41 42 /** 43 * This class tests {@link RopeByteString} by inheriting the tests from {@link 44 * LiteralByteStringTest}. Only a couple of methods are overridden. 45 * 46 * <p>A full test of the result of {@link RopeByteString#substring(int, int)} is found in the 47 * separate class {@link RopeByteStringSubstringTest}. 48 * 49 * @author carlanton@google.com (Carl Haverl) 50 */ 51 public class RopeByteStringTest extends LiteralByteStringTest { 52 53 @Override setUp()54 protected void setUp() throws Exception { 55 classUnderTest = "RopeByteString"; 56 referenceBytes = ByteStringTest.getTestBytes(22341, 22337766L); 57 Iterator<ByteString> iter = ByteStringTest.makeConcretePieces(referenceBytes).iterator(); 58 stringUnderTest = iter.next(); 59 while (iter.hasNext()) { 60 stringUnderTest = stringUnderTest.concat(iter.next()); 61 } 62 expectedHashCode = -1214197238; 63 } 64 testMinLength()65 public void testMinLength() { 66 // minLength should match the Fibonacci sequence 67 int a = 1; 68 int b = 1; 69 int i; 70 for (i = 0; a > 0; i++) { 71 assertEquals(a, RopeByteString.minLength(i)); 72 int c = a + b; 73 a = b; 74 b = c; 75 } 76 assertEquals(Integer.MAX_VALUE, RopeByteString.minLength(i)); 77 assertEquals(Integer.MAX_VALUE, RopeByteString.minLength(i + 1)); 78 assertEquals(i + 1, RopeByteString.minLengthByDepth.length); 79 } 80 81 @Override testGetTreeDepth()82 public void testGetTreeDepth() { 83 assertEquals( 84 classUnderTest + " must have the expected tree depth", 4, stringUnderTest.getTreeDepth()); 85 } 86 testBalance()87 public void testBalance() { 88 int numberOfPieces = 10000; 89 int pieceSize = 64; 90 byte[] testBytes = ByteStringTest.getTestBytes(numberOfPieces * pieceSize, 113377L); 91 92 // Build up a big ByteString from smaller pieces to force a rebalance 93 ByteString concatenated = ByteString.EMPTY; 94 for (int i = 0; i < numberOfPieces; ++i) { 95 concatenated = concatenated.concat(ByteString.copyFrom(testBytes, i * pieceSize, pieceSize)); 96 } 97 98 assertEquals( 99 classUnderTest + " from string must have the expected type", 100 classUnderTest, 101 getActualClassName(concatenated)); 102 assertTrue( 103 classUnderTest + " underlying bytes must match after balancing", 104 Arrays.equals(testBytes, concatenated.toByteArray())); 105 ByteString testString = ByteString.copyFrom(testBytes); 106 assertEquals( 107 classUnderTest + " balanced string must equal flat string", testString, concatenated); 108 assertEquals( 109 classUnderTest + " flat string must equal balanced string", concatenated, testString); 110 assertEquals( 111 classUnderTest + " balanced string must have same hash code as flat string", 112 testString.hashCode(), 113 concatenated.hashCode()); 114 } 115 116 @Override testToString()117 public void testToString() throws UnsupportedEncodingException { 118 String sourceString = "I love unicode \u1234\u5678 characters"; 119 ByteString sourceByteString = ByteString.copyFromUtf8(sourceString); 120 int copies = 250; 121 122 // By building the RopeByteString by concatenating, this is actually a fairly strenuous test. 123 StringBuilder builder = new StringBuilder(copies * sourceString.length()); 124 ByteString unicode = ByteString.EMPTY; 125 for (int i = 0; i < copies; ++i) { 126 builder.append(sourceString); 127 unicode = RopeByteString.concatenate(unicode, sourceByteString); 128 } 129 String testString = builder.toString(); 130 131 assertEquals( 132 classUnderTest + " from string must have the expected type", 133 classUnderTest, 134 getActualClassName(unicode)); 135 String roundTripString = unicode.toString(UTF_8); 136 assertEquals(classUnderTest + " unicode bytes must match", testString, roundTripString); 137 ByteString flatString = ByteString.copyFromUtf8(testString); 138 assertEquals(classUnderTest + " string must equal the flat string", flatString, unicode); 139 assertEquals( 140 classUnderTest + " string must must have same hashCode as the flat string", 141 flatString.hashCode(), 142 unicode.hashCode()); 143 } 144 145 @Override testCharsetToString()146 public void testCharsetToString() { 147 String sourceString = "I love unicode \u1234\u5678 characters"; 148 ByteString sourceByteString = ByteString.copyFromUtf8(sourceString); 149 int copies = 250; 150 151 // By building the RopeByteString by concatenating, this is actually a fairly strenuous test. 152 StringBuilder builder = new StringBuilder(copies * sourceString.length()); 153 ByteString unicode = ByteString.EMPTY; 154 for (int i = 0; i < copies; ++i) { 155 builder.append(sourceString); 156 unicode = RopeByteString.concatenate(unicode, sourceByteString); 157 } 158 String testString = builder.toString(); 159 160 assertEquals( 161 classUnderTest + " from string must have the expected type", 162 classUnderTest, 163 getActualClassName(unicode)); 164 String roundTripString = unicode.toString(Internal.UTF_8); 165 assertEquals(classUnderTest + " unicode bytes must match", testString, roundTripString); 166 ByteString flatString = ByteString.copyFromUtf8(testString); 167 assertEquals(classUnderTest + " string must equal the flat string", flatString, unicode); 168 assertEquals( 169 classUnderTest + " string must must have same hashCode as the flat string", 170 flatString.hashCode(), 171 unicode.hashCode()); 172 } 173 174 @Override testToString_returnsCanonicalEmptyString()175 public void testToString_returnsCanonicalEmptyString() { 176 RopeByteString ropeByteString = 177 RopeByteString.newInstanceForTest(ByteString.EMPTY, ByteString.EMPTY); 178 assertSame( 179 classUnderTest + " must be the same string references", 180 ByteString.EMPTY.toString(Internal.UTF_8), 181 ropeByteString.toString(Internal.UTF_8)); 182 } 183 184 @Override testToString_raisesException()185 public void testToString_raisesException() { 186 try { 187 ByteString byteString = RopeByteString.newInstanceForTest(ByteString.EMPTY, ByteString.EMPTY); 188 byteString.toString("invalid"); 189 fail("Should have thrown an exception."); 190 } catch (UnsupportedEncodingException expected) { 191 // This is success 192 } 193 194 try { 195 ByteString byteString = 196 RopeByteString.concatenate( 197 ByteString.copyFromUtf8("foo"), ByteString.copyFromUtf8("bar")); 198 byteString.toString("invalid"); 199 fail("Should have thrown an exception."); 200 } catch (UnsupportedEncodingException expected) { 201 // This is success 202 } 203 } 204 205 @Override testJavaSerialization()206 public void testJavaSerialization() throws Exception { 207 ByteArrayOutputStream out = new ByteArrayOutputStream(); 208 ObjectOutputStream oos = new ObjectOutputStream(out); 209 oos.writeObject(stringUnderTest); 210 oos.close(); 211 byte[] pickled = out.toByteArray(); 212 InputStream in = new ByteArrayInputStream(pickled); 213 ObjectInputStream ois = new ObjectInputStream(in); 214 Object o = ois.readObject(); 215 assertTrue("Didn't get a ByteString back", o instanceof ByteString); 216 assertEquals("Should get an equal ByteString back", stringUnderTest, o); 217 } 218 } 219