001/**
002 * The MIT License (MIT)
003 *
004 * Copyright (c) 2017 tools4j.org (Marco Terzer)
005 *
006 * Permission is hereby granted, free of charge, to any person obtaining a copy
007 * of this software and associated documentation files (the "Software"), to deal
008 * in the Software without restriction, including without limitation the rights
009 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
010 * copies of the Software, and to permit persons to whom the Software is
011 * furnished to do so, subject to the following conditions:
012 *
013 * The above copyright notice and this permission notice shall be included in all
014 * copies or substantial portions of the Software.
015 *
016 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
017 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
018 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
019 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
020 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
021 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
022 * SOFTWARE.
023 */
024package org.tools4j.spockito;
025
026import org.junit.Test;
027import org.junit.runners.model.FrameworkMethod;
028import org.junit.runners.model.InitializationError;
029
030import java.util.ArrayList;
031import java.util.List;
032import java.util.Objects;
033
034/**
035 * A runner for the situation where a test method is to be run multiple times with all the rows of an unroll table.
036 * This case applies if the {@link org.tools4j.spockito.Spockito.Unroll} annotation is present at test method level.
037 */
038public class SingleTestMultiRowRunner extends AbstractSpockitoTestRunner {
039
040    private final FrameworkMethod testMethod;
041    private final ValueConverter methodValueConverter;
042
043    public SingleTestMultiRowRunner(final Class<?> clazz,
044                                    final FrameworkMethod testMethod,
045                                    final ValueConverter methodValueConverter) throws InitializationError {
046        super(clazz);
047        this.testMethod = Objects.requireNonNull(testMethod);
048        this.methodValueConverter = Objects.requireNonNull(methodValueConverter);
049        validate();
050    }
051
052    @Override
053    protected String getName() {
054        return testMethod.getName();
055    }
056
057    @Override
058    protected String testName(final FrameworkMethod method) {
059        if (method instanceof UnrolledTestMethod) {
060            return method.getName() + Spockito.getName(method.getMethod(), ((UnrolledTestMethod)method).getTableRow());
061        }
062        return super.testName(method);
063    }
064
065    @Override
066    protected List<FrameworkMethod> computeTestMethods() {
067        final List<FrameworkMethod> testMethods = new ArrayList<>();
068        final Spockito.Unroll unroll = testMethod.getAnnotation(Spockito.Unroll.class);
069        if (unroll == null) {
070            testMethods.add(testMethod);
071        } else {
072            final Table table = Table.parse(unroll.value());
073            testMethods.addAll(unroll(table));
074        }
075        return testMethods;
076    }
077
078    private List<UnrolledTestMethod> unroll(final Table table) {
079        final List<UnrolledTestMethod> unrolled = new ArrayList<>(table.getRowCount());
080        for (final TableRow row : table) {
081            final UnrolledTestMethod unrolledTestMethod = new UnrolledTestMethod(testMethod.getMethod(), row, methodValueConverter);
082            unrolled.add(unrolledTestMethod);
083        }
084        return unrolled;
085    }
086
087    protected void validate() throws InitializationError {
088        final List<Throwable> errors = new ArrayList<>();
089        try {
090            super.collectInitializationErrors(errors);
091        } catch (final Exception e) {
092            errors.add(e);
093        }
094        if (!errors.isEmpty()) {
095            throw new InitializationError(testMethod + ": " + errors.get(0));
096        }
097    }
098
099    @Override
100    protected void validateTestMethods(final List<Throwable> errors) {
101        final List<FrameworkMethod> methods = getTestClass().getAnnotatedMethods(Test.class);
102        for (final FrameworkMethod method : methods) {
103            final Spockito.Unroll unroll = method.getAnnotation(Spockito.Unroll.class);
104            if (unroll == null) {
105                method.validatePublicVoidNoArg(false, errors);
106            } else {
107                method.validatePublicVoid(false, errors);
108                method.validateNoTypeParametersOnArgs(errors);
109            }
110        }
111    }
112
113}