All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.unitils.reflectionassert.report.impl.TreeDifferenceView Maven / Gradle / Ivy

Go to download

Unitils provides utilities to further simplify unit-testing with JUnit, DBUnit, EasyMock Hibernate and Spring. The goal is to make unit-testing easy and maintainable by offering utilities such as automatic DB-schema maintainance and equality assertion through reflection.

There is a newer version: 3.4.6
Show newest version
/*
 * Copyright 2008,  Unitils.org
 *
 * 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 org.unitils.reflectionassert.report.impl;

import org.unitils.reflectionassert.difference.*;
import org.unitils.reflectionassert.report.DifferenceView;
import static org.unitils.reflectionassert.report.impl.DefaultDifferenceReport.MatchType.NO_MATCH;
import org.unitils.core.util.ObjectFormatter;
import static org.apache.commons.lang.ClassUtils.getShortClassName;

import java.util.List;
import java.util.Map;

/**
 * Formatter that will output all objects in the difference tree. For an unordered collection difference,
 * the best matching differences are taken.
 *
 * @author Tim Ducheyne
 * @author Filip Neven
 */
public class TreeDifferenceView implements DifferenceView {

    /**
     * Formatter for object values.
     */
    protected ObjectFormatter objectFormatter = new ObjectFormatter();

    /**
     * The visitor for visiting the difference tree
     */
    protected TreeDifferenceFormatterVisitor treeDifferenceFormatterVisitor = new TreeDifferenceFormatterVisitor();


    /**
     * Creates a string representation of the given difference tree.
     *
     * @param difference The root difference, not null
     * @return The string representation, not null
     */
    public String createView(Difference difference) {
        return difference.accept(treeDifferenceFormatterVisitor, null);
    }


    /**
     * Creates a string representation of a simple difference.
     *
     * @param difference The difference, not null
     * @param fieldName  The current fieldName, null for root
     * @return The string representation, not null
     */
    protected String formatDifference(Difference difference, String fieldName) {
        return formatValues(fieldName, difference.getLeftValue(), difference.getRightValue());
    }


    /**
     * Creates a string representation of an object difference.
     *
     * @param objectDifference The difference, not null
     * @param fieldName        The current fieldName, null for root
     * @return The string representation, not null
     */
    protected String formatDifference(ObjectDifference objectDifference, String fieldName) {
        StringBuilder result = new StringBuilder();
        result.append(formatDifference((Difference) objectDifference, fieldName));

        for (Map.Entry fieldDifference : objectDifference.getFieldDifferences().entrySet()) {
            String innerFieldName = createFieldName(fieldName, fieldDifference.getKey(), true);
            result.append(fieldDifference.getValue().accept(treeDifferenceFormatterVisitor, innerFieldName));
        }
        return result.toString();
    }


    protected String formatDifference(ClassDifference classDifference, String fieldName) {
        StringBuilder result = new StringBuilder();
        result.append((fieldName == null) ? "" : fieldName + ":");
        result.append("Expected: object of type ").append(getShortClassName(classDifference.getLeftClass()));
        result.append(", actual: object of type ").append(getShortClassName(classDifference.getRightClass())).append("\n");
        return result.toString();
    }


    /**
     * Creates a string representation of a collection difference.
     *
     * @param collectionDifference The difference, not null
     * @param fieldName            The current fieldName, null for root
     * @return The string representation, not null
     */
    protected String formatDifference(CollectionDifference collectionDifference, String fieldName) {
        StringBuilder result = new StringBuilder();
        result.append(formatDifference((Difference) collectionDifference, fieldName));

        for (Map.Entry elementDifferences : collectionDifference.getElementDifferences().entrySet()) {
            String innerFieldName = createFieldName(fieldName, "[" + elementDifferences.getKey() + "]", false);
            result.append(elementDifferences.getValue().accept(treeDifferenceFormatterVisitor, innerFieldName));
        }

        List leftList = collectionDifference.getLeftList();
        List rightList = collectionDifference.getRightList();
        for (Integer leftIndex : collectionDifference.getLeftMissingIndexes()) {
            String innerFieldName = createFieldName(fieldName, "[" + leftIndex + "]", false);
            result.append(formatValues(innerFieldName, leftList.get(leftIndex), ""));
        }
        for (Integer rightIndex : collectionDifference.getRightMissingIndexes()) {
            String innerFieldName = createFieldName(fieldName, "[" + rightIndex + "]", false);
            result.append(formatValues(innerFieldName, "", rightList.get(rightIndex)));
        }
        return result.toString();
    }


    /**
     * Creates a string representation of a map difference.
     *
     * @param mapDifference The difference, not null
     * @param fieldName     The current fieldName, null for root
     * @return The string representation, not null
     */
    protected String formatDifference(MapDifference mapDifference, String fieldName) {
        StringBuilder result = new StringBuilder();
        result.append(formatDifference((Difference) mapDifference, fieldName));

        for (Map.Entry valueDifference : mapDifference.getValueDifferences().entrySet()) {
            String innerFieldName = createFieldName(fieldName, formatObject(valueDifference.getKey()), true);
            result.append(valueDifference.getValue().accept(treeDifferenceFormatterVisitor, innerFieldName));
        }

        Map leftMap = mapDifference.getLeftMap();
        Map rightMap = mapDifference.getRightMap();
        for (Object leftKey : mapDifference.getLeftMissingKeys()) {
            String innerFieldName = createFieldName(fieldName, formatObject(leftKey), true);
            result.append(formatValues(innerFieldName, leftMap.get(leftKey), ""));
        }
        for (Object rightKey : mapDifference.getRightMissingKeys()) {
            String innerFieldName = createFieldName(fieldName, formatObject(rightKey), true);
            result.append(formatValues(innerFieldName, rightMap.get(rightKey), ""));
        }
        return result.toString();
    }

    protected String formatObject(Object object) {
        if (object == NO_MATCH) {
            return "--no match--";
        }
        return objectFormatter.format(object);
    }


    /**
     * Creates a string representation of an unorder collection difference.
     *
     * @param unorderedCollectionDifference The difference, not null
     * @param fieldName                     The current fieldName, null for root
     * @return The string representation, not null
     */
    protected String formatDifference(UnorderedCollectionDifference unorderedCollectionDifference, String fieldName) {
        StringBuilder result = new StringBuilder();
        result.append(formatDifference((Difference) unorderedCollectionDifference, fieldName));

        Map bestMatchingIndexes = unorderedCollectionDifference.getBestMatchingIndexes();
        for (Map.Entry bestMatchingIndex : bestMatchingIndexes.entrySet()) {
            int leftIndex = bestMatchingIndex.getKey();
            int rightIndex = bestMatchingIndex.getValue();

            if (leftIndex == -1) {
                String innerFieldName = createFieldName(fieldName, "[x," + rightIndex + "]", false);
                result.append(formatValues(innerFieldName, NO_MATCH, unorderedCollectionDifference.getRightList().get(rightIndex)));
                continue;
            }
            if (rightIndex == -1) {
                String innerFieldName = createFieldName(fieldName, "[" + leftIndex + ",x]", false);
                result.append(formatValues(innerFieldName, unorderedCollectionDifference.getLeftList().get(leftIndex), NO_MATCH));
                continue;
            }

            Difference difference = unorderedCollectionDifference.getElementDifference(leftIndex, rightIndex);
            if (difference == null) {
                continue;
            }

            String innerFieldName = createFieldName(fieldName, "[" + leftIndex + "," + rightIndex + "]", false);
            result.append(difference.accept(treeDifferenceFormatterVisitor, innerFieldName));
        }
        return result.toString();
    }


    /**
     * Formats and appends the given fieldname and object values.
     *
     * @param fieldName  The field name, null if there is no field name
     * @param leftValue  The left value
     * @param rightValue The right value
     * @return The string representation, not null
     */
    protected String formatValues(String fieldName, Object leftValue, Object rightValue) {
        StringBuilder result = new StringBuilder();

        String prefix = (fieldName == null) ? "" : fieldName;
        result.append(prefix);
        result.append(" expected: ");
        result.append(formatObject(leftValue));
        result.append("\n");
        result.append(prefix);
        result.append("   actual: ");
        result.append(formatObject(rightValue));
        result.append("\n\n");
        return result.toString();
    }


    /**
     * Adds the inner field name to the given field name.
     *
     * @param fieldName      The field
     * @param innerFieldName The field to append, not null
     * @param includePoint   True if a point should be added
     * @return The field name
     */
    protected String createFieldName(String fieldName, String innerFieldName, boolean includePoint) {
        if (fieldName == null) {
            return innerFieldName;
        }
        StringBuilder result = new StringBuilder();
        result.append(fieldName);
        if (includePoint) {
            result.append(".");
        }
        result.append(innerFieldName);
        return result.toString();
    }


    /**
     * The visitor for visiting the difference tree.
     */
    protected class TreeDifferenceFormatterVisitor implements DifferenceVisitor {

        public String visit(Difference difference, String fieldName) {
            return formatDifference(difference, fieldName);
        }

        public String visit(ObjectDifference objectDifference, String fieldName) {
            return formatDifference(objectDifference, fieldName);
        }

        public String visit(ClassDifference classDifference, String fieldName) {
            return formatDifference(classDifference, fieldName);
        }

        public String visit(MapDifference mapDifference, String fieldName) {
            return formatDifference(mapDifference, fieldName);
        }

        public String visit(CollectionDifference collectionDifference, String fieldName) {
            return formatDifference(collectionDifference, fieldName);
        }

        public String visit(UnorderedCollectionDifference unorderedCollectionDifference, String fieldName) {
            return formatDifference(unorderedCollectionDifference, fieldName);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy