/* * � Copyright IBM Corp. 2013 * * 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. */ /* * Author: Maire Kehoe (mkehoe@ie.ibm.com) * Date: 27 Apr 2011 * SerializationComparatorSet.java */ package com.ibm.xsp.test.framework.serialize; import java.lang.reflect.Array; import java.util.Date; import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.TimeZone; import javax.faces.model.SelectItem; import com.ibm.commons.util.StringUtil; import com.ibm.xsp.FacesExceptionEx; import com.ibm.xsp.exception.EvaluationExceptionEx; import com.ibm.xsp.test.framework.XspTestUtil; /** * Used by {@link ReflectionCompareSerializer} when comparing the restored * UIComponent tree to the initial tree, these comparators compare individual * non-container objects. They compare the primitive Java types, but should not * compare UIComponent nor complex-type classes, nor containers like lists, * arrays, collections, nor any objects that can contain complex-types or lists, * arrays or collections. Those more complicated comparisons are done in * {@link SerializationStructureCompare}. * * @author Maire Kehoe (mkehoe@ie.ibm.com) */ public class SerializationComparatorSet { public static interface PostSerializationComparator { String compare(SerializationCompareContext context, String message, String methodName, Object object1, Object object2); } private static final class DoubleComparator implements PostSerializationComparator { public String compare(SerializationCompareContext context, String message, String methodName, Object object1, Object object2) { if (object1 instanceof Double && object2 instanceof Double) { double tolerance = 0.0001; // allowed difference double d1 = (Double) object1; double d2 = (Double) object2; if (Math.abs(d1 - d2) < tolerance) { return ""; } } return checkEqual(message, object1.toString(), object2.toString()); } } public static final class EqualsComparator implements PostSerializationComparator { public String compare(SerializationCompareContext context, String message, String methodName, Object object1, Object object2) { // Note, for Dates this had been changed to ignore the time part of // the Date // because the dates being compared were not actually serialized, // they were computed using @Now. That has been fixed in // SerializationFullComparator where it now ignores a computed UIOutput "value". // So this is testing both the date and the time again using the // .equals mtd // so that serialized Dates can be handled correctly. if (!StringUtil.equals(object1, object2)) { return message + " expected:<" + object1 + "> but was:<" + object2 + ">\n"; } return ""; } } private static final class PrimitiveArrayComparator implements PostSerializationComparator{ public String compare(SerializationCompareContext context, String message, String methodName, Object object1, Object object2) { String fails = ""; fails += checkEqual(message+".getClass().isArray()", ((Boolean)object1.getClass().isArray()).toString(), ((Boolean)object2.getClass().isArray()).toString()); if( fails.length() > 0 ){ return fails; } fails += checkEqual(message+".getClass()", object1.getClass().getComponentType().getName()+"[]", object2.getClass().getComponentType().getName()+"[]"); if( fails.length() > 0 ){ return fails; } fails += checkEqual(message+".length", ((Integer)Array.getLength(object1)).toString(), ((Integer)Array.getLength(object2)).toString()); if( fails.length() > 0 ){ return fails; } int length = Array.getLength(object1); for (int i = 0; i < length; i++) { Object value1 = Array.get(object2, i); Object value2 = Array.get(object2, i); fails += checkEqual(message+"["+i+"]", value1.toString(), value2.toString()); if( fails.length() > 0 ){ return fails; } } return ""; } } private static final class TimeZoneComparator implements PostSerializationComparator{ public String compare(SerializationCompareContext context, String message, String methodName, Object object1, Object object2) { TimeZone zone1 = (TimeZone) object1; TimeZone zone2 = (TimeZone) object2; String fails = ""; fails += checkEqual(message+".getID()", zone1.getID(), zone2.getID()); if( fails.length() > 0 ){ return fails; } fails += checkEqual(message+".getDisplayName()", zone1.getDisplayName(/*daylight*/false, /*style*/TimeZone.SHORT, Locale.US), zone2.getDisplayName(/*daylight*/false, /*style*/TimeZone.SHORT, Locale.US)); if( fails.length() > 0 ){ return fails; } fails += checkEqual(message+".getDSTSavings()", ((Integer)zone1.getDSTSavings()).toString(), ((Integer)zone2.getDSTSavings()).toString()); if( fails.length() > 0 ){ return fails; } fails += checkEqual(message+".getRawOffset()", ((Integer)zone1.getRawOffset()).toString(), ((Integer)zone2.getRawOffset()).toString()); if( fails.length() > 0 ){ return fails; } return fails; } } public final class ExceptionComparator implements PostSerializationComparator { public String compare(SerializationCompareContext context, String message, String methodName, Object object1, Object object2) { String fails = ""; Exception ex1 = (Exception) object1; Exception ex2 = (Exception) object2; String messageForEx = message + " thrown " + XspTestUtil.getShortClass(ex1) + " "; fails += applyComparator(context, messageForEx + ".message", methodName, ex1.getMessage(), ex2.getMessage()); StackTraceElement trace1 = ex1.getStackTrace()[0]; StackTraceElement trace2 = ex2.getStackTrace()[0]; messageForEx = messageForEx + ".trace[0]"; fails += applyComparator(context, messageForEx + ".className", methodName, trace1.getClassName(), trace2.getClassName()); fails += applyComparator(context, messageForEx + ".methodName", methodName, trace1.getMethodName(), trace2.getMethodName()); fails += applyComparator(context, messageForEx + ".lineNumber", methodName, trace1.getLineNumber(), trace2.getLineNumber()); if( fails.length() > 0 ){ ex2.printStackTrace(); return fails; } Throwable cause1 = ex1.getCause(); Throwable cause2 = ex2.getCause(); if( null != cause1 || null != cause2 ){ String messageForCause = message+"("+XspTestUtil.getShortClass(ex1.getClass()) +").cause"; int depth = 0; while( null != cause1 && null != cause2 ){ String msgN = messageForCause+"[" +depth+"]"; fails += checkEqual(msgN+".toString()", ""+cause1, ""+cause2); if( fails.length() > 0 ){ break; } cause1 = cause1.getCause(); cause2 = cause2.getCause(); depth++; } } if( fails.length() > 0 ){ ex2.printStackTrace(); return fails; } System.out.println("SerializationUtil.compareObjects() " + message + " Same exceptions thrown:"); Exception ex = ex1; while (null != ex) { System.out.println(ex); ex = (Exception) ex.getCause(); } System.out.println(); // ex1.printStackTrace(); return "";//pass } } private final class SelectItemComparator implements PostSerializationComparator { public String compare(SerializationCompareContext context, String message, String methodName, Object object1, Object object2) { SelectItem item1 = (SelectItem) object1; SelectItem item2 = (SelectItem) object2; message += "-> SelectItem"; String fails = ""; fails += applyComparator(context, message, ".disabled", item1.isDisabled(), item2.isDisabled()); fails += applyComparator(context, message, ".label", item1.getLabel(), item2.getLabel()); fails += applyComparator(context, message, ".description", item1.getDescription(), item2.getDescription()); Object value1 = item1.getValue(); Object value2 = item2.getValue(); fails += applyComparator(context, message + ".value", ".getClass()", null == value1 ? null : value1.getClass(), null == value2 ? null : value2.getClass()); fails += applyComparator(context, message + ".value", ".toString()", "" + value1, "" + value2); return fails; } } public static final class ToStringComparator implements PostSerializationComparator { public String compare(SerializationCompareContext context, String message, String methodName, Object object1, Object object2) { return checkEqual(message, object1.toString(), object2.toString()); } } private Map<Class<?>, PostSerializationComparator> comparators = new HashMap<Class<?>, PostSerializationComparator>(); public SerializationComparatorSet() { comparators.put(Class.class, new ToStringComparator()); comparators.put(String.class, new ToStringComparator()); comparators.put(Character.class, new ToStringComparator()); comparators.put(Byte.class, new ToStringComparator()); comparators.put(Short.class, new ToStringComparator()); comparators.put(Integer.class, new ToStringComparator()); comparators.put(Long.class, new ToStringComparator()); comparators.put(Float.class, new ToStringComparator()); comparators.put(Double.class, new DoubleComparator()); comparators.put(Boolean.class, new ToStringComparator()); comparators.put(Locale.class, new ToStringComparator()); comparators.put(Date.class, new EqualsComparator()); comparators.put(TimeZone.getDefault().getClass(), new TimeZoneComparator()); comparators.put(SelectItem.class, new SelectItemComparator()); comparators.put(char[].class, new PrimitiveArrayComparator()); comparators.put(byte[].class, new PrimitiveArrayComparator()); comparators.put(short[].class, new PrimitiveArrayComparator()); comparators.put(int[].class, new PrimitiveArrayComparator()); comparators.put(long[].class, new PrimitiveArrayComparator()); comparators.put(float[].class, new PrimitiveArrayComparator()); comparators.put(double[].class, new PrimitiveArrayComparator()); comparators.put(boolean[].class, new PrimitiveArrayComparator()); // Commented out to prevent "Same exceptions thrown:" being printed twice. // comparators.put(Exception.class, createExceptionComparator()); comparators.put(NullPointerException.class, createExceptionComparator()); comparators.put(FacesExceptionEx.class, createExceptionComparator()); comparators.put(IllegalArgumentException.class, createExceptionComparator()); comparators.put(EvaluationExceptionEx.class, createExceptionComparator()); } public PostSerializationComparator addComparator(Class<?> targetClass, PostSerializationComparator comparator) { return comparators.put(targetClass, comparator); } public String applyComparator(SerializationCompareContext context, String message, String methodName, Object object1, Object object2) { if (null == object1 || null == object2) { if (null == object1 && null == object2) { // both are null. return ""; } // one is null but the other isn't // using the classname instead of .toString so results are skippable return checkEqual(message, ""+object1, ""+object2); } String fails = ""; Class<?> class1 = object1.getClass(); if (!StringUtil.equals(class1, object2.getClass())) { fails += checkEqual(message, class1.getName(), object2.getClass() .getName()); if( fails.length() > 0 ){ return fails; } } boolean exactComparatorFound = false; for (Entry<Class<?>, PostSerializationComparator> i : comparators .entrySet()) { if (i.getKey().isAssignableFrom(class1)) { PostSerializationComparator comparator = i.getValue(); fails += comparator.compare(context, message, methodName, object1, object2); if( fails.length() > 0 ){ return fails; } if (!exactComparatorFound) { exactComparatorFound = i.getKey().equals(class1); } } } if (!exactComparatorFound) { fails += "No exact comparator for " + class1.getName() + "\n"; if( fails.length() > 0 ){ return fails; } } return ""; // pass } public boolean isHasComparator(Class<?> objClass) { return comparators.containsKey(objClass); } private static String checkEqual(String message, String str1, String str2) { if (!StringUtil.equals(str1, str2)) { return message + " expected:<" + str1 + "> but was:<" + str2 + ">\n"; } return ""; } public ExceptionComparator createExceptionComparator(){ // create an ExceptionComparator that has access to this ..Set return this.new ExceptionComparator(); } }