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.runner.Description;
027import org.junit.runner.manipulation.Filter;
028
029import java.util.Objects;
030
031/**
032 * Method filter wrapped around an original filter in {@link Spockito#filter(Filter)} to work around an Intellij problem
033 * when re-running individual tests.
034 */
035public final class MethodLevelFilter extends Filter {
036
037    private Filter delegate;
038
039    public MethodLevelFilter(final Filter delegate) {
040        this.delegate = Objects.requireNonNull(delegate);
041    }
042
043    @Override
044    public boolean shouldRun(final Description description) {
045        if (description.isTest()) {
046            return delegate.shouldRun(description);
047        }
048
049        // explicitly check if any children want to run
050        for (Description child : description.getChildren()) {
051            if (shouldRun(child)) {
052                return true;
053            }
054            //Intellij bug, we get the wrong description, let us test with a slightly modified one now
055            final Description relaxed = Description.createTestDescription(
056                    child.getTestClass(), getMethodName(child.getDisplayName())
057            );
058            if (shouldRun(relaxed)) {
059                return true;
060            }
061        }
062        return false;
063    }
064
065    private static String getMethodName(final String name) {
066        return name.substring(0, findFirstNonNameChar(name));
067    }
068
069    private static int findFirstNonNameChar(final String name) {
070        int index = 0;
071        if (index < name.length() && Character.isJavaIdentifierStart(name.charAt(index))) {
072            index++;
073            while (index < name.length() && Character.isJavaIdentifierPart(name.charAt(index))) {
074                index++;
075            }
076        }
077        return index;
078    }
079
080    @Override
081    public String describe() {
082        return delegate.describe();
083    }
084}