1e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson/*
2e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson * Copyright (c) 2007 Mockito contributors
3e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson * This program is made available under the terms of the MIT License.
4e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson */
5e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson
6e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinsonpackage org.mockito.internal.exceptions.stacktrace;
7e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson
8e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinsonimport org.mockito.exceptions.stacktrace.StackTraceCleaner;
9e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinsonimport org.mockito.internal.configuration.ClassPathLoader;
10e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson
11e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinsonimport java.io.Serializable;
12e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinsonimport java.util.ArrayList;
13e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinsonimport java.util.Arrays;
14e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinsonimport java.util.LinkedList;
15e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinsonimport java.util.List;
16e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson
17e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinsonpublic class StackTraceFilter implements Serializable {
18e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson
19e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson    static final long serialVersionUID = -5499819791513105700L;
20e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson
21e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson    private static StackTraceCleaner cleaner =
22e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson            ClassPathLoader.getStackTraceCleanerProvider().getStackTraceCleaner(new DefaultStackTraceCleaner());
23e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson
24e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson    /**
25e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson     * Example how the filter works (+/- means good/bad):
26e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson     * [a+, b+, c-, d+, e+, f-, g+] -> [a+, b+, g+]
27e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson     * Basically removes all bad from the middle. If any good are in the middle of bad those are also removed.
28e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson     */
29e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson    public StackTraceElement[] filter(StackTraceElement[] target, boolean keepTop) {
30e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson        //TODO: profile
31e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson        List<StackTraceElement> unfilteredStackTrace = Arrays.asList(target);
32e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson
33e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson        int lastBad = -1;
34e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson        int firstBad = -1;
35e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson        for (int i = 0; i < unfilteredStackTrace.size(); i++) {
36e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson            if (!cleaner.isOut(unfilteredStackTrace.get(i))) {
37e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson                continue;
38e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson            }
39e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson            lastBad = i;
40e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson            if (firstBad == -1) {
41e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson                firstBad = i;
42e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson            }
43e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson        }
44e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson
45e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson        List<StackTraceElement> top;
46e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson        if (keepTop && firstBad != -1) {
47e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson            top = unfilteredStackTrace.subList(0, firstBad);
48e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson        } else {
49e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson            top = new LinkedList<StackTraceElement>();
50e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson        }
51e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson
52e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson        List<StackTraceElement> bottom = unfilteredStackTrace.subList(lastBad + 1, unfilteredStackTrace.size());
53e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson        List<StackTraceElement> filtered = new ArrayList<StackTraceElement>(top);
54e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson        filtered.addAll(bottom);
55e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson        return filtered.toArray(new StackTraceElement[]{});
56e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson    }
57e0ae5d7e87b1dd6e789803c1b9615a84bd7488b7Ian Parkinson}