info.novatec.testit.livingdoc.interpreter.collection.CollectionInterpreter.java Source code

Java tutorial

Introduction

Here is the source code for info.novatec.testit.livingdoc.interpreter.collection.CollectionInterpreter.java

Source

/* Copyright (c) 2006 Pyxis Technologies inc.
 *
 * This is free software; you can redistribute it and/or modify it under the
 * terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option) any later
 * version.
 *
 * This software is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 51
 * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF site:
 * http://www.fsf.org. */

package info.novatec.testit.livingdoc.interpreter.collection;

import static info.novatec.testit.livingdoc.LivingDoc.canContinue;
import static info.novatec.testit.livingdoc.LivingDoc.shouldStop;
import static info.novatec.testit.livingdoc.annotation.Annotations.exception;
import static info.novatec.testit.livingdoc.annotation.Annotations.ignored;
import static info.novatec.testit.livingdoc.util.LoggerConstants.ENTRY;
import static info.novatec.testit.livingdoc.util.LoggerConstants.ENTRY_WITH;
import static info.novatec.testit.livingdoc.util.LoggerConstants.ENTRY_WITH_THREE;
import static info.novatec.testit.livingdoc.util.LoggerConstants.ENTRY_WITH_TWO;
import static info.novatec.testit.livingdoc.util.LoggerConstants.EXIT;
import static info.novatec.testit.livingdoc.util.LoggerConstants.EXIT_WITH;
import static info.novatec.testit.livingdoc.util.LoggerConstants.EXIT_WITH_NULL;
import static info.novatec.testit.livingdoc.util.LoggerConstants.LOG_ERROR;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import info.novatec.testit.livingdoc.Call;
import info.novatec.testit.livingdoc.Example;
import info.novatec.testit.livingdoc.Interpreter;
import info.novatec.testit.livingdoc.Specification;
import info.novatec.testit.livingdoc.Statistics;
import info.novatec.testit.livingdoc.TypeConversion;
import info.novatec.testit.livingdoc.annotation.Annotations;
import info.novatec.testit.livingdoc.call.Annotate;
import info.novatec.testit.livingdoc.call.Compile;
import info.novatec.testit.livingdoc.interpreter.HeaderForm;
import info.novatec.testit.livingdoc.reflect.CollectionProvider;
import info.novatec.testit.livingdoc.reflect.Fixture;
import info.novatec.testit.livingdoc.reflect.NoSuchMessageException;

// TODO: STATS compile stats here and in derived classes (no test for that yet)
public abstract class CollectionInterpreter implements Interpreter {
    private static final Logger LOG = LoggerFactory.getLogger(CollectionInterpreter.class);

    private final Fixture fixture;
    protected final Statistics stats = new Statistics();

    public Statistics statistics() {
        return this.stats;
    }

    protected CollectionInterpreter(Fixture fixture) {
        this.fixture = fixture;
    }

    protected List<?> toList(Object results) {
        LOG.debug(ENTRY_WITH, results);
        if (results instanceof Object[]) {
            List<?> resultsAsList = Arrays.asList((Object[]) results);
            LOG.debug(EXIT_WITH, resultsAsList.toString());
            return resultsAsList;
        }
        if (results instanceof Collection) {
            List<?> newArrayList = new ArrayList<Object>((Collection<?>) results);
            LOG.debug(EXIT_WITH, newArrayList.toString());
            return newArrayList;
        }
        LOG.debug(EXIT_WITH, "null");
        return null;
    }

    protected void executeRow(Example valuesRow, Example headers, Fixture rowFixtureAdapter) {
        LOG.debug(ENTRY_WITH_THREE, valuesRow.toString(), headers.toString(), rowFixtureAdapter.toString());
        stats.right();
        valuesRow.annotate(Annotations.right());

        for (int i = 0; i != valuesRow.remainings(); ++i) {
            Example cell = valuesRow.at(i);

            if (i < headers.remainings()) {
                try {
                    Call call = new Call(rowFixtureAdapter.check(headers.at(i).getContent()));

                    if (!StringUtils.isBlank(cell.getContent())) {
                        call.expect(cell.getContent());
                    }
                    call.will(Annotate.withDetails(cell));

                    if (HeaderForm.parse(headers.at(i).getContent()).isExpected()) {
                        call.will(Compile.statistics(stats));
                    }

                    call.execute();
                } catch (InvocationTargetException e) {
                    cell.annotate(exception(e));
                    stats.exception();
                    LOG.error(LOG_ERROR, e);
                } catch (IllegalAccessException e) {
                    cell.annotate(exception(e));
                    stats.exception();
                    LOG.error(LOG_ERROR, e);
                } catch (NoSuchMessageException e) {
                    cell.annotate(exception(e));
                    stats.exception();
                    LOG.error(LOG_ERROR, e);
                }
            } else {
                cell.annotate(ignored(cell.getContent()));
            }
        }
        LOG.debug(EXIT);
    }

    protected void addSurplusRow(Example example, Example headers, Fixture rowFixtureAdapter) {
        LOG.debug(ENTRY_WITH_THREE, example.toString(), headers.toString(), rowFixtureAdapter.toString());
        Example row = example.addSibling();

        for (int i = 0; i < headers.remainings(); i++) {
            Example cell = row.addChild();
            try {
                Call call = new Call(rowFixtureAdapter.check(headers.at(i).getContent()));

                Object actual = call.execute();

                cell.setContent(TypeConversion.toString(actual));
                cell.annotate(Annotations.surplus());
                if (i == 0) // Notify test listener on first cell only
                {
                    stats.wrong();
                }
            } catch (InvocationTargetException e) {
                // TODO: STATS count stats?
                cell.annotate(ignored(e));
                LOG.error(LOG_ERROR, e);
            } catch (IllegalAccessException e) {
                // TODO: STATS count stats?
                cell.annotate(ignored(e));
                LOG.error(LOG_ERROR, e);
            } catch (NoSuchMessageException e) {
                // TODO: STATS count stats?
                cell.annotate(ignored(e));
                LOG.error(LOG_ERROR, e);
            }
        }
        LOG.debug(EXIT);
    }

    protected void missingRow(Example row) {
        LOG.debug(ENTRY_WITH, row.toString());
        Example firstChild = row.firstChild();

        firstChild.annotate(Annotations.missing());
        stats.wrong();

        if (firstChild.hasSibling()) {
            for (Example cell : firstChild.nextSibling()) {
                cell.annotate(Annotations.missing());
            }
        }
        LOG.debug(EXIT);
    }

    private List<?> getCollectionProvider() {
        LOG.trace(ENTRY);
        Object target = fixture.getTarget();

        for (Method method : target.getClass().getMethods()) {
            if (method.isAnnotationPresent(CollectionProvider.class)) {
                List<?> result = toList(invoke(target, method));
                LOG.trace(EXIT_WITH, result.toString());
                return result;
            }
        }
        LOG.trace(EXIT_WITH_NULL);
        return null;
    }

    private Object invoke(Object target, Method method) {
        LOG.trace(ENTRY_WITH_TWO, target.toString(), method.toString());
        Object result = null;
        try {
            result = method.invoke(target);
            LOG.trace(EXIT_WITH, result.toString());
        } catch (InvocationTargetException e) {
            LOG.error(LOG_ERROR, e);
            LOG.trace(EXIT_WITH_NULL);
        } catch (IllegalAccessException e) {
            LOG.error(LOG_ERROR, e);
            LOG.trace(EXIT_WITH_NULL);
        }
        return result;
    }

    protected List<Fixture> getFixtureList()
            throws IllegalArgumentException, InvocationTargetException, IllegalAccessException {
        LOG.debug(ENTRY);
        List<?> results = getCollectionProvider();

        if (results == null) {
            results = toList(fixture.getTarget());
        }

        if (results == null) {
            Call query = new Call(fixture.check("query"));
            results = toList(query.execute());
        }

        if (results == null) {
            throw new IllegalArgumentException("results parameter is neither an Object[] nor a Collection");
        }

        List<Fixture> fixtures = new ArrayList<Fixture>();
        for (Object object : results) {
            fixtures.add(fixture.fixtureFor(object));
        }

        LOG.debug(EXIT_WITH, fixtures.toString());
        return fixtures;
    }

    protected boolean mustProcessMissing() {
        LOG.debug(ENTRY);
        LOG.debug(EXIT_WITH, false);
        return false;
    }

    protected boolean mustProcessSurplus() {
        LOG.debug(ENTRY);
        LOG.debug(EXIT_WITH, false);
        return false;
    }

    @Override
    public void interpret(Specification specification) {
        LOG.debug(ENTRY_WITH, specification.toString());
        Example table = specification.nextExample();
        execute(table.at(0, 1));
        specification.exampleDone(stats);
        LOG.debug(EXIT);
    }

    public void execute(Example example) {
        LOG.debug(ENTRY_WITH, example.toString());
        try {
            List<Fixture> fixtures = getFixtureList();

            Example headers = example.at(0, 0);

            RowFixtureSplitter splitter = new RowFixtureSplitter();

            splitter.split(example.at(1), fixtures, headers);

            for (RowFixture rowFixture : splitter.getMatch()) {
                Example row = rowFixture.getRow();
                executeRow(row.firstChild(), headers, rowFixture.getAdapter());

                if (shouldStop(stats)) {
                    row.addChild().annotate(Annotations.stopped());
                    break;
                }
            }

            if (mustProcessMissing() && canContinue(stats)) {
                for (Example row : splitter.getMissing()) {
                    missingRow(row);

                    if (shouldStop(stats)) {
                        row.addChild().annotate(Annotations.stopped());
                        break;
                    }
                }
            }

            if (mustProcessSurplus() && canContinue(stats)) {
                for (Fixture adapter : splitter.getSurplus()) {
                    addSurplusRow(example, headers, adapter);

                    if (shouldStop(stats)) {
                        example.lastSibling().addChild().annotate(Annotations.stopped());
                        break;
                    }
                }
            }
        } catch (InvocationTargetException e) {
            stats.exception();
            example.firstChild().annotate(exception(e));

            if (shouldStop(stats)) {
                example.addChild().annotate(Annotations.stopped());
            }
            LOG.error(LOG_ERROR, e);
        } catch (IllegalAccessException e) {
            stats.exception();
            example.firstChild().annotate(exception(e));

            if (shouldStop(stats)) {
                example.addChild().annotate(Annotations.stopped());
            }
            LOG.error(LOG_ERROR, e);
        } catch (NoSuchMessageException e) {
            stats.exception();
            example.firstChild().annotate(exception(e));

            if (shouldStop(stats)) {
                example.addChild().annotate(Annotations.stopped());
            }
            LOG.error(LOG_ERROR, e);
        }
    }

    protected void applyRowStatistic(Statistics rowStats) {
        LOG.debug(ENTRY_WITH, rowStats.toString());
        if (rowStats.exceptionCount() > 0) {
            stats.exception();
        } else if (rowStats.wrongCount() > 0) {
            stats.wrong();
        } else if (rowStats.rightCount() > 0) {
            stats.right();
        } else {
            stats.ignored();
        }
        LOG.debug(EXIT);
    }
}