// Copyright 2012 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package com.google.collide.dtogen.server; import com.google.collide.dtogen.definitions.ComplicatedDto; import com.google.collide.dtogen.definitions.ComplicatedDto.SimpleEnum; import com.google.collide.dtogen.definitions.NotRoutable; import com.google.collide.dtogen.definitions.SimpleDto; import com.google.collide.dtogen.server.TestDtoServerImpls.ComplicatedDtoImpl; import com.google.collide.dtogen.server.TestDtoServerImpls.NotRoutableImpl; import com.google.collide.dtogen.server.TestDtoServerImpls.SimpleDtoImpl; import com.google.collide.dtogen.server.TestDtoServerImpls.SimpleDtoSubTypeImpl; import com.google.collide.dtogen.shared.ServerToClientDto; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.google.gson.JsonPrimitive; import junit.framework.TestCase; import java.util.HashSet; import java.util.Map; import java.util.Set; /** * Tests that the interfaces specified in com.google.gwt.dto.definitions have * corresponding generated Server impls. */ public class ServerImplTest extends TestCase { public void testComplicatedDtoImpl() { final String fooString = "Something"; final int intId = 1; ComplicatedDtoImpl dtoImpl = ComplicatedDtoImpl.make(); dtoImpl.setIntId(intId); dtoImpl.setSimpleEnum(SimpleEnum.TWO); dtoImpl.getFooStrings().add(fooString); dtoImpl.getNightmare(); dtoImpl.getArrayOfArrayOfEnum(); // Assume that SimpleDto works. Use it to test nested objects SimpleDtoImpl simpleDto = SimpleDtoImpl.make(); simpleDto.setName(fooString); simpleDto.setIDontStartWithGet(intId); dtoImpl.getSimpleDtos().add(simpleDto); dtoImpl.getMap().put(fooString, simpleDto); // Check to make sure things are in a sane state. ComplicatedDto dto = dtoImpl; assertEquals(intId, dto.getIntId()); assertEquals(fooString, dto.getFooStrings().get(0)); // Should be reference equal initially. assertEquals(dto.getSimpleDtos().get(0), simpleDto); assertEquals(dto.getMap().get(fooString), simpleDto); assertEquals(ComplicatedDto.TYPE, dto.getType()); // Make it json and pull it back out. Gson gson = new Gson(); String serialized = dtoToJson(gson, dtoImpl); ComplicatedDtoImpl deserialized = ComplicatedDtoImpl.fromJsonString(serialized); // Test correctness of JSON serialization. assertEquals(serialized, dtoImpl.toJson()); assertEquals(intId, deserialized.getIntId()); assertEquals(fooString, deserialized.getFooStrings().get(0)); assertEquals(ComplicatedDto.TYPE, deserialized.getType()); // Pull it out using the DTO's deserializer. JsonElement jsonElement = new JsonParser().parse(serialized); ComplicatedDtoImpl deserialized2 = ComplicatedDtoImpl.fromJsonElement(jsonElement); assertEquals(intId, deserialized2.getIntId()); assertEquals(fooString, deserialized2.getFooStrings().get(0)); assertEquals(ComplicatedDto.TYPE, deserialized2.getType()); // Verify that the hasFields() are correct when using the DTO's deserializer. assertTrue(deserialized2.hasIntId()); // Check that the SimpleDto object looks correct. checkSimpleDto(dto.getSimpleDtos().get(0), simpleDto.getName(), simpleDto.iDontStartWithGet()); checkSimpleDto(dto.getMap().get(fooString), simpleDto.getName(), simpleDto.iDontStartWithGet()); } public void testNotRoutableImpl() { final String fooString = "Something"; NotRoutableImpl dtoImpl = new NotRoutableImpl(); dtoImpl.setSomeField(fooString); // Make it json and pull it back out. Gson gson = new Gson(); String serialized = gson.toJson(dtoImpl); NotRoutable dto = NotRoutableImpl.fromJsonString(serialized); assertEquals(fooString, dto.getSomeField()); } public void testNullEnum() { ComplicatedDtoImpl dtoImpl = ComplicatedDtoImpl.make(); dtoImpl.setIntId(1); dtoImpl.setSimpleEnum(null); // Make it json and pull it back out. Gson gson = new GsonBuilder().serializeNulls().create(); String serialized = dtoImpl.toJson(); assertEquals(dtoToJson(gson, dtoImpl), serialized); ComplicatedDto dto = ComplicatedDtoImpl.fromJsonString(serialized); assertEquals(1, dto.getIntId()); assertNull(dto.getSimpleEnum()); } public void testSimpleDtoImpl() { final String fooString = "Something"; final int intValue = 1; SimpleDtoImpl dtoImpl = SimpleDtoImpl.make(); dtoImpl.setName("Something"); dtoImpl.setIDontStartWithGet(intValue); checkSimpleDto(dtoImpl, fooString, intValue); // Make it json and pull it back out. Gson gson = new Gson(); String serialized = gson.toJson(dtoImpl); SimpleDto dto = SimpleDtoImpl.fromJsonString(serialized); checkSimpleDto(dto, fooString, intValue); } public void testSimpleDtoImpl_deserialize() { final String fooString = "Something"; JsonObject json = new JsonObject(); json.add("name", new JsonPrimitive(fooString)); SimpleDtoImpl deserialized = SimpleDtoImpl.fromJsonElement(json); assertTrue(deserialized.hasName()); assertFalse(deserialized.hasIDontStartWithGet()); checkSimpleDto(deserialized, fooString, 0); } public void testSimpleDtoImpl_nullStringSerialization() { final String fooString = null; final int intValue = 1; SimpleDtoImpl dtoImpl = SimpleDtoImpl.make(); dtoImpl.setName(fooString); dtoImpl.setIDontStartWithGet(intValue); checkSimpleDto(dtoImpl, fooString, intValue); // Make it json and pull it back out. Gson gson = new GsonBuilder().serializeNulls().create(); String serialized = dtoImpl.toJson(); assertEquals(dtoToJson(gson, dtoImpl), serialized); SimpleDto dto = SimpleDtoImpl.fromJsonString(serialized); checkSimpleDto(dto, fooString, intValue); } private void checkSimpleDto(SimpleDto dto, String expectedName, int expectedNum) { assertEquals(expectedName, dto.getName()); assertEquals(expectedNum, dto.iDontStartWithGet()); assertEquals(SimpleDto.TYPE, dto.getType()); } public void testSimpleDtoSubtypeImpl() { final String valueForFieldOnSupertype = "valueForFieldOnSupertype"; final String valueForFieldOnSelf = "valueForFieldOnSelf"; SimpleDtoSubTypeImpl dto = SimpleDtoSubTypeImpl.make(); dto.setName(valueForFieldOnSupertype); dto.setAnotherField(valueForFieldOnSelf); String json = dto.toJson(); assertTrue(json.contains(valueForFieldOnSelf)); assertTrue(json.contains(valueForFieldOnSupertype)); } public void testEqualsAndHashCode() { final String fooString = "something"; final String barString = "something else"; final String bazString = "something else, again"; final String fluxString = "yet something ELSE"; final int fooNum = 4; final int barNum = 5; SimpleDtoSubTypeImpl dtoA = SimpleDtoSubTypeImpl.make(); SimpleDtoSubTypeImpl dtoB = SimpleDtoSubTypeImpl.make(); checkEqualsAndHashCode(dtoA, dtoB, true); // test on an object field dtoA.setName(fooString); assert(dtoA.hasName()); assertFalse(dtoB.hasName()); checkEqualsAndHashCode(dtoA, dtoB, false); dtoB.setName(fooString); checkEqualsAndHashCode(dtoA, dtoB, true); dtoA.setName(barString); checkEqualsAndHashCode(dtoA, dtoB, false); dtoA.setName(fooString); checkEqualsAndHashCode(dtoA, dtoB, true); // test on a primitive field dtoA.setNumber(fooNum); checkEqualsAndHashCode(dtoA, dtoB, false); dtoB.setNumber(fooNum); checkEqualsAndHashCode(dtoA, dtoB, true); dtoA.setNumber(barNum); checkEqualsAndHashCode(dtoA, dtoB, false); dtoA.setNumber(fooNum); checkEqualsAndHashCode(dtoA, dtoB, true); // test on a subclass' field dtoA.setAnotherField(bazString); checkEqualsAndHashCode(dtoA, dtoB, false); dtoB.setAnotherField(bazString); checkEqualsAndHashCode(dtoA, dtoB, true); dtoA.setAnotherField(fluxString); checkEqualsAndHashCode(dtoA, dtoB, false); dtoA.setAnotherField(bazString); checkEqualsAndHashCode(dtoA, dtoB, true); } private void checkEqualsAndHashCode(Object a, Object b, boolean shouldBeEqual) { assertTrue(a.equals(a)); assertTrue(b.equals(b)); assertTrue(a.equals(b) == shouldBeEqual); assertTrue(b.equals(a) == shouldBeEqual); if (shouldBeEqual) { assertEquals(a, b); assertEquals(b, a); } // if a and b are not equal, their hashcodes could still collide if we are unlucky, but since // this test uses static data for all objects, we can ensure this doesn't happen assertTrue((a.hashCode() == b.hashCode()) == shouldBeEqual); } /** * Converts the object to JSON, removing all _has fields. * * @param gson the Gson used to parse the object */ private String dtoToJson(Gson gson, ServerToClientDto dtoImpl) { com.google.gson.JsonObject jsonObj = gson.toJsonTree(dtoImpl).getAsJsonObject(); stripHasFields(jsonObj); return gson.toJson(jsonObj); } /** * Recursively strip fields that start with _has from the specified object. Modifies the object. */ private void stripHasFields(JsonElement jsonElem) { if (jsonElem.isJsonObject()) { com.google.gson.JsonObject jsonObj = jsonElem.getAsJsonObject(); // Determine which fields should be removed. Set<String> hasFields = new HashSet<String>(); for (Map.Entry<String, JsonElement> field : jsonObj.entrySet()) { if (field.getKey().startsWith("_has")) { // Remove the _hasAbc field. hasFields.add(field.getKey()); } else { // Recursively strip fields on the child. stripHasFields(field.getValue()); } } // Remove the fields. for (String hasField : hasFields) { jsonObj.remove(hasField); } } else if (jsonElem.isJsonArray()) { JsonArray array = jsonElem.getAsJsonArray(); // Recursively call on child objects in an array. for (int i = 0; i < array.size(); i++) { stripHasFields(array.get(i)); } } } }