1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 */ 19 package org.apache.thrift; 20 21 import java.io.ByteArrayInputStream; 22 import java.io.ByteArrayOutputStream; 23 import java.io.ObjectInputStream; 24 import java.io.ObjectOutputStream; 25 import java.nio.ByteBuffer; 26 import java.util.HashMap; 27 import java.util.Map; 28 29 import junit.framework.TestCase; 30 31 import org.apache.thrift.meta_data.FieldMetaData; 32 import org.apache.thrift.meta_data.ListMetaData; 33 import org.apache.thrift.meta_data.MapMetaData; 34 import org.apache.thrift.meta_data.SetMetaData; 35 import org.apache.thrift.meta_data.StructMetaData; 36 import org.apache.thrift.protocol.TBinaryProtocol; 37 import org.apache.thrift.protocol.TType; 38 39 import thrift.test.Bonk; 40 import thrift.test.CrazyNesting; 41 import thrift.test.HolyMoley; 42 import thrift.test.Insanity; 43 import thrift.test.JavaTestHelper; 44 import thrift.test.Nesting; 45 import thrift.test.Numberz; 46 import thrift.test.OneOfEach; 47 import thrift.test.StructA; 48 import thrift.test.StructB; 49 import thrift.test.Xtruct; 50 51 public class TestStruct extends TestCase { testIdentity()52 public void testIdentity() throws Exception { 53 TSerializer binarySerializer = new TSerializer(new TBinaryProtocol.Factory()); 54 TDeserializer binaryDeserializer = new TDeserializer(new TBinaryProtocol.Factory()); 55 56 OneOfEach ooe = Fixtures.oneOfEach; 57 58 Nesting n = new Nesting(); 59 n.my_ooe = ooe; 60 n.my_ooe.integer16 = 16; 61 n.my_ooe.integer32 = 32; 62 n.my_ooe.integer64 = 64; 63 n.my_ooe.double_precision = (Math.sqrt(5)+1)/2; 64 n.my_ooe.some_characters = ":R (me going \"rrrr\")"; 65 n.my_ooe.zomg_unicode = "\u04c0\u216e\u039d\u0020\u041d\u03bf\u217f"+ 66 "\u043e\u0261\u0433\u0430\u03c1\u210e\u0020"+ 67 "\u0391\u0074\u0074\u03b1\u217d\u03ba\u01c3"+ 68 "\u203c"; 69 n.my_bonk = Fixtures.nesting.my_bonk; 70 71 HolyMoley hm = Fixtures.holyMoley; 72 73 OneOfEach ooe2 = new OneOfEach(); 74 binaryDeserializer.deserialize( 75 ooe2, 76 binarySerializer.serialize(ooe)); 77 78 assertEquals(ooe, ooe2); 79 assertEquals(ooe.hashCode(), ooe2.hashCode()); 80 81 82 Nesting n2 = new Nesting(); 83 binaryDeserializer.deserialize( 84 n2, 85 binarySerializer.serialize(n)); 86 87 assertEquals(n, n2); 88 assertEquals(n.hashCode(), n2.hashCode()); 89 90 HolyMoley hm2 = new HolyMoley(); 91 binaryDeserializer.deserialize( 92 hm2, 93 binarySerializer.serialize(hm)); 94 95 assertEquals(hm, hm2); 96 assertEquals(hm.hashCode(), hm2.hashCode()); 97 } 98 testDeepCopy()99 public void testDeepCopy() throws Exception { 100 TSerializer binarySerializer = new TSerializer(new TBinaryProtocol.Factory()); 101 TDeserializer binaryDeserializer = new TDeserializer(new TBinaryProtocol.Factory()); 102 103 HolyMoley hm = Fixtures.holyMoley; 104 105 byte[] binaryCopy = binarySerializer.serialize(hm); 106 HolyMoley hmCopy = new HolyMoley(); 107 binaryDeserializer.deserialize(hmCopy, binaryCopy); 108 HolyMoley hmCopy2 = new HolyMoley(hm); 109 110 assertEquals(hm, hmCopy); 111 assertEquals(hmCopy, hmCopy2); 112 113 // change binary value in original object 114 hm.big.get(0).base64.array()[0]++; 115 // make sure the change didn't propagate to the copied object 116 assertFalse(hm.equals(hmCopy2)); 117 hm.big.get(0).base64.array()[0]--; // undo change 118 119 hmCopy2.bonks.get("two").get(1).message = "What else?"; 120 121 assertFalse(hm.equals(hmCopy2)); 122 } 123 testCompareTo()124 public void testCompareTo() throws Exception { 125 Bonk bonk1 = new Bonk(); 126 Bonk bonk2 = new Bonk(); 127 128 // Compare empty thrift objects. 129 assertEquals(0, bonk1.compareTo(bonk2)); 130 131 bonk1.setMessage("m"); 132 133 // Compare one thrift object with a filled in field and another without it. 134 assertTrue(bonk1.compareTo(bonk2) > 0); 135 assertTrue(bonk2.compareTo(bonk1) < 0); 136 137 // Compare both have filled-in fields. 138 bonk2.setMessage("z"); 139 assertTrue(bonk1.compareTo(bonk2) < 0); 140 assertTrue(bonk2.compareTo(bonk1) > 0); 141 142 // Compare bonk1 has a field filled in that bonk2 doesn't. 143 bonk1.setType(123); 144 assertTrue(bonk1.compareTo(bonk2) > 0); 145 assertTrue(bonk2.compareTo(bonk1) < 0); 146 147 // Compare bonk1 and bonk2 equal. 148 bonk2.setType(123); 149 bonk2.setMessage("m"); 150 assertEquals(0, bonk1.compareTo(bonk2)); 151 } 152 153 public void testCompareToWithDataStructures() { 154 Insanity insanity1 = new Insanity(); 155 Insanity insanity2 = new Insanity(); 156 157 // Both empty. 158 expectEquals(insanity1, insanity2); 159 160 insanity1.setUserMap(new HashMap<Numberz, Long>()); 161 // insanity1.map = {}, insanity2.map = null 162 expectGreaterThan(insanity1, insanity2); 163 164 // insanity1.map = {2:1}, insanity2.map = null 165 insanity1.getUserMap().put(Numberz.TWO, 1l); 166 expectGreaterThan(insanity1, insanity2); 167 168 // insanity1.map = {2:1}, insanity2.map = {} 169 insanity2.setUserMap(new HashMap<Numberz, Long>()); 170 expectGreaterThan(insanity1, insanity2); 171 172 // insanity1.map = {2:1}, insanity2.map = {2:2} 173 insanity2.getUserMap().put(Numberz.TWO, 2l); 174 expectLessThan(insanity1, insanity2); 175 176 // insanity1.map = {2:1, 3:5}, insanity2.map = {2:2} 177 insanity1.getUserMap().put(Numberz.THREE, 5l); 178 expectGreaterThan(insanity1, insanity2); 179 180 // insanity1.map = {2:1, 3:5}, insanity2.map = {2:1, 4:5} 181 insanity2.getUserMap().put(Numberz.TWO, 1l); 182 insanity2.getUserMap().put(Numberz.FIVE, 5l); 183 expectLessThan(insanity1, insanity2); 184 } 185 186 private void expectLessThan(Insanity insanity1, Insanity insanity2) { 187 int compareTo = insanity1.compareTo(insanity2); 188 assertTrue(insanity1 + " should be less than " + insanity2 + ", but is: " + compareTo, compareTo < 0); 189 } 190 191 private void expectGreaterThan(Insanity insanity1, Insanity insanity2) { 192 int compareTo = insanity1.compareTo(insanity2); 193 assertTrue(insanity1 + " should be greater than " + insanity2 + ", but is: " + compareTo, compareTo > 0); 194 } 195 196 private void expectEquals(Insanity insanity1, Insanity insanity2) { 197 int compareTo = insanity1.compareTo(insanity2); 198 assertEquals(insanity1 + " should be equal to " + insanity2 + ", but is: " + compareTo, 0, compareTo); 199 } 200 201 public void testMetaData() throws Exception { 202 Map<CrazyNesting._Fields, FieldMetaData> mdMap = CrazyNesting.metaDataMap; 203 204 // Check for struct fields existence 205 assertEquals(4, mdMap.size()); 206 assertTrue(mdMap.containsKey(CrazyNesting._Fields.SET_FIELD)); 207 assertTrue(mdMap.containsKey(CrazyNesting._Fields.LIST_FIELD)); 208 assertTrue(mdMap.containsKey(CrazyNesting._Fields.STRING_FIELD)); 209 assertTrue(mdMap.containsKey(CrazyNesting._Fields.BINARY_FIELD)); 210 211 // Check for struct fields contents 212 assertEquals("string_field", mdMap.get(CrazyNesting._Fields.STRING_FIELD).fieldName); 213 assertEquals("list_field", mdMap.get(CrazyNesting._Fields.LIST_FIELD).fieldName); 214 assertEquals("set_field", mdMap.get(CrazyNesting._Fields.SET_FIELD).fieldName); 215 assertEquals("binary_field", mdMap.get(CrazyNesting._Fields.BINARY_FIELD).fieldName); 216 217 assertEquals(TFieldRequirementType.DEFAULT, mdMap.get(CrazyNesting._Fields.STRING_FIELD).requirementType); 218 assertEquals(TFieldRequirementType.REQUIRED, mdMap.get(CrazyNesting._Fields.LIST_FIELD).requirementType); 219 assertEquals(TFieldRequirementType.OPTIONAL, mdMap.get(CrazyNesting._Fields.SET_FIELD).requirementType); 220 221 assertEquals(TType.STRING, mdMap.get(CrazyNesting._Fields.STRING_FIELD).valueMetaData.type); 222 assertFalse(mdMap.get(CrazyNesting._Fields.STRING_FIELD).valueMetaData.isBinary()); 223 assertEquals(TType.LIST, mdMap.get(CrazyNesting._Fields.LIST_FIELD).valueMetaData.type); 224 assertEquals(TType.SET, mdMap.get(CrazyNesting._Fields.SET_FIELD).valueMetaData.type); 225 assertEquals(TType.STRING, mdMap.get(CrazyNesting._Fields.BINARY_FIELD).valueMetaData.type); 226 assertTrue(mdMap.get(CrazyNesting._Fields.BINARY_FIELD).valueMetaData.isBinary()); 227 228 // Check nested structures 229 assertTrue(mdMap.get(CrazyNesting._Fields.LIST_FIELD).valueMetaData.isContainer()); 230 231 assertFalse(mdMap.get(CrazyNesting._Fields.LIST_FIELD).valueMetaData.isStruct()); 232 233 assertEquals(TType.STRUCT, ((MapMetaData)((ListMetaData)((SetMetaData)((MapMetaData)((MapMetaData)((ListMetaData)mdMap.get(CrazyNesting._Fields.LIST_FIELD).valueMetaData).elemMetaData).valueMetaData).valueMetaData).elemMetaData).elemMetaData).keyMetaData.type); 234 235 assertEquals(Insanity.class, ((StructMetaData)((MapMetaData)((ListMetaData)((SetMetaData)((MapMetaData)((MapMetaData)((ListMetaData)mdMap.get(CrazyNesting._Fields.LIST_FIELD).valueMetaData).elemMetaData).valueMetaData).valueMetaData).elemMetaData).elemMetaData).keyMetaData).structClass); 236 237 // Check that FieldMetaData contains a map with metadata for all generated struct classes 238 assertNotNull(FieldMetaData.getStructMetaDataMap(CrazyNesting.class)); 239 assertNotNull(FieldMetaData.getStructMetaDataMap(Insanity.class)); 240 assertNotNull(FieldMetaData.getStructMetaDataMap(Xtruct.class)); 241 242 assertEquals(CrazyNesting.metaDataMap, FieldMetaData.getStructMetaDataMap(CrazyNesting.class)); 243 assertEquals(Insanity.metaDataMap, FieldMetaData.getStructMetaDataMap(Insanity.class)); 244 245 for (Map.Entry<? extends TFieldIdEnum, FieldMetaData> mdEntry : mdMap.entrySet()) { 246 assertEquals(mdEntry.getKey(), CrazyNesting._Fields.findByName(mdEntry.getValue().fieldName)); 247 } 248 249 MapMetaData vmd = (MapMetaData)Insanity.metaDataMap.get(Insanity._Fields.USER_MAP).valueMetaData; 250 assertTrue(vmd.valueMetaData.isTypedef()); 251 assertFalse(vmd.keyMetaData.isTypedef()); 252 } 253 254 public void testToString() throws Exception { 255 JavaTestHelper object = new JavaTestHelper(); 256 object.req_int = 0; 257 object.req_obj = ""; 258 259 object.req_bin = ByteBuffer.wrap(new byte[] { 260 0, -1, 2, -3, 4, -5, 6, -7, 8, -9, 10, -11, 12, -13, 14, -15, 261 16, -17, 18, -19, 20, -21, 22, -23, 24, -25, 26, -27, 28, -29, 262 30, -31, 32, -33, 34, -35, 36, -37, 38, -39, 40, -41, 42, -43, 44, 263 -45, 46, -47, 48, -49, 50, -51, 52, -53, 54, -55, 56, -57, 58, -59, 264 60, -61, 62, -63, 64, -65, 66, -67, 68, -69, 70, -71, 72, -73, 74, 265 -75, 76, -77, 78, -79, 80, -81, 82, -83, 84, -85, 86, -87, 88, -89, 266 90, -91, 92, -93, 94, -95, 96, -97, 98, -99, 100, -101, 102, -103, 267 104, -105, 106, -107, 108, -109, 110, -111, 112, -113, 114, -115, 268 116, -117, 118, -119, 120, -121, 122, -123, 124, -125, 126, -127, 269 }); 270 271 assertEquals("JavaTestHelper(req_int:0, req_obj:, req_bin:"+ 272 "00 FF 02 FD 04 FB 06 F9 08 F7 0A F5 0C F3 0E F1 10 EF 12 ED 14 "+ 273 "EB 16 E9 18 E7 1A E5 1C E3 1E E1 20 DF 22 DD 24 DB 26 D9 28 D7 "+ 274 "2A D5 2C D3 2E D1 30 CF 32 CD 34 CB 36 C9 38 C7 3A C5 3C C3 3E "+ 275 "C1 40 BF 42 BD 44 BB 46 B9 48 B7 4A B5 4C B3 4E B1 50 AF 52 AD "+ 276 "54 AB 56 A9 58 A7 5A A5 5C A3 5E A1 60 9F 62 9D 64 9B 66 99 68 "+ 277 "97 6A 95 6C 93 6E 91 70 8F 72 8D 74 8B 76 89 78 87 7A 85 7C 83 "+ 278 "7E 81)", 279 object.toString()); 280 281 object.req_bin = ByteBuffer.wrap(new byte[] { 282 0, -1, 2, -3, 4, -5, 6, -7, 8, -9, 10, -11, 12, -13, 14, -15, 283 16, -17, 18, -19, 20, -21, 22, -23, 24, -25, 26, -27, 28, -29, 284 30, -31, 32, -33, 34, -35, 36, -37, 38, -39, 40, -41, 42, -43, 44, 285 -45, 46, -47, 48, -49, 50, -51, 52, -53, 54, -55, 56, -57, 58, -59, 286 60, -61, 62, -63, 64, -65, 66, -67, 68, -69, 70, -71, 72, -73, 74, 287 -75, 76, -77, 78, -79, 80, -81, 82, -83, 84, -85, 86, -87, 88, -89, 288 90, -91, 92, -93, 94, -95, 96, -97, 98, -99, 100, -101, 102, -103, 289 104, -105, 106, -107, 108, -109, 110, -111, 112, -113, 114, -115, 290 116, -117, 118, -119, 120, -121, 122, -123, 124, -125, 126, -127, 291 0, 292 }); 293 294 assertEquals("JavaTestHelper(req_int:0, req_obj:, req_bin:"+ 295 "00 FF 02 FD 04 FB 06 F9 08 F7 0A F5 0C F3 0E F1 10 EF 12 ED 14 "+ 296 "EB 16 E9 18 E7 1A E5 1C E3 1E E1 20 DF 22 DD 24 DB 26 D9 28 D7 "+ 297 "2A D5 2C D3 2E D1 30 CF 32 CD 34 CB 36 C9 38 C7 3A C5 3C C3 3E "+ 298 "C1 40 BF 42 BD 44 BB 46 B9 48 B7 4A B5 4C B3 4E B1 50 AF 52 AD "+ 299 "54 AB 56 A9 58 A7 5A A5 5C A3 5E A1 60 9F 62 9D 64 9B 66 99 68 "+ 300 "97 6A 95 6C 93 6E 91 70 8F 72 8D 74 8B 76 89 78 87 7A 85 7C 83 "+ 301 "7E 81...)", 302 object.toString()); 303 304 object.req_bin = ByteBuffer.wrap(new byte[] {}); 305 object.setOpt_binIsSet(true); 306 307 assertEquals("JavaTestHelper(req_int:0, req_obj:, req_bin:)", 308 object.toString()); 309 } 310 311 private static void assertArrayEquals(byte[] expected, byte[] actual) { 312 if (!java.util.Arrays.equals(expected, actual)) { 313 fail("Expected byte array did not match actual."); 314 } 315 } 316 317 public void testBytesBufferFeatures() throws Exception { 318 319 final String testString = "testBytesBufferFeatures"; 320 final JavaTestHelper o = new JavaTestHelper(); 321 322 o.setReq_bin((ByteBuffer)null); 323 assertNull(o.getReq_bin()); 324 325 o.setReq_bin(ByteBuffer.wrap(testString.getBytes())); 326 assertArrayEquals(testString.getBytes(), o.getReq_bin()); 327 328 o.setReq_bin((byte[])null); 329 assertNull(o.getReq_bin()); 330 331 o.setReq_bin(testString.getBytes()); 332 assertArrayEquals(testString.getBytes(), o.getReq_bin()); 333 334 o.setFieldValue(JavaTestHelper._Fields.REQ_BIN, null); 335 assertNull(o.getReq_bin()); 336 337 o.setFieldValue(JavaTestHelper._Fields.REQ_BIN, testString.getBytes()); 338 assertArrayEquals(testString.getBytes(), o.getReq_bin()); 339 340 o.setFieldValue(JavaTestHelper._Fields.REQ_BIN, null); 341 assertNull(o.getReq_bin()); 342 343 o.setFieldValue(JavaTestHelper._Fields.REQ_BIN, ByteBuffer.wrap(testString.getBytes())); 344 assertArrayEquals(testString.getBytes(), o.getReq_bin()); 345 } 346 347 public void testJavaSerializable() throws Exception { 348 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 349 ObjectOutputStream oos = new ObjectOutputStream(baos); 350 351 OneOfEach ooe = Fixtures.oneOfEach; 352 353 // Serialize ooe the Java way... 354 oos.writeObject(ooe); 355 byte[] serialized = baos.toByteArray(); 356 357 // Attempt to deserialize it 358 ByteArrayInputStream bais = new ByteArrayInputStream(serialized); 359 ObjectInputStream ois = new ObjectInputStream(bais); 360 OneOfEach ooe2 = (OneOfEach) ois.readObject(); 361 362 assertEquals(ooe, ooe2); 363 } 364 365 public void testSubStructValidation() throws Exception { 366 StructA valid = new StructA("valid"); 367 StructA invalid = new StructA(); 368 369 StructB b = new StructB(); 370 try { 371 b.validate(); 372 fail(); 373 } catch (TException e) { 374 // expected 375 } 376 377 b = new StructB().setAb(valid); 378 b.validate(); 379 380 b = new StructB().setAb(invalid); 381 try { 382 b.validate(); 383 fail(); 384 } catch (TException e) { 385 // expected 386 } 387 388 b = new StructB().setAb(valid).setAa(invalid); 389 try { 390 b.validate(); 391 fail(); 392 } catch (TException e) { 393 // expected 394 } 395 } 396 } 397