aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/junitparams/naming/MacroSubstitutionNamingStrategy.java
blob: 1bdcafba05e203f5cd5e6a310a5d820fb20b07e1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package junitparams.naming;

import junitparams.internal.TestMethod;
import junitparams.internal.Utils;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Locale;
import java.util.regex.Pattern;

public class MacroSubstitutionNamingStrategy implements TestCaseNamingStrategy {
    private static final String MACRO_PATTERN = "\\{[^\\}]{0,50}\\}";
    // Pattern that keeps delimiters in split result
    private static final Pattern MACRO_SPLIT_PATTERN = Pattern.compile(String.format("(?=%s)|(?<=%s)", MACRO_PATTERN, MACRO_PATTERN));
    private static final String MACRO_START = "{";
    private static final String MACRO_END = "}";
    // Android-changed: CTS and AndroidJUnitRunner rely on specific format to test names, changing
    // them will prevent CTS and AndroidJUnitRunner from working properly; see b/36541809
    static final String DEFAULT_TEMPLATE = "{method}[{index}]";
    private TestMethod method;

    public MacroSubstitutionNamingStrategy(TestMethod testMethod) {
        this.method = testMethod;
    }

    @Override
    public String getTestCaseName(int parametersIndex, Object parameters) {
        TestCaseName testCaseName = method.getAnnotation(TestCaseName.class);

        String template = getTemplate(testCaseName);
        String builtName = buildNameByTemplate(template, parametersIndex, parameters);

        if (builtName.trim().isEmpty()) {
            return buildNameByTemplate(DEFAULT_TEMPLATE, parametersIndex, parameters);
        } else {
            return builtName;
        }
    }

    private String getTemplate(TestCaseName testCaseName) {
        if (testCaseName != null) {
            // Android-changed: CTS and AndroidJUnitRunner rely on specific format to test names,
            // changing them will prevent CTS and AndroidJUnitRunner from working properly;
            // see b/36541809
            throw new IllegalStateException(
                    "@TestCaseName not currently supported as it breaks running tests in CTS");
            // return testCaseName.value();
        }

        return DEFAULT_TEMPLATE;
    }

    private String buildNameByTemplate(String template, int parametersIndex, Object parameters) {
        StringBuilder nameBuilder = new StringBuilder();

        String[] parts = MACRO_SPLIT_PATTERN.split(template);

        for (String part : parts) {
            String transformedPart = transformPart(part, parametersIndex, parameters);
            nameBuilder.append(transformedPart);
        }

        return nameBuilder.toString();
    }

    private String transformPart(String part, int parametersIndex, Object parameters) {
        if (isMacro(part)) {
            return lookupMacroValue(part, parametersIndex, parameters);
        }

        return part;
    }

    private String lookupMacroValue(String macro, int parametersIndex, Object parameters) {
        String macroKey = getMacroKey(macro);

        switch (Macro.parse(macroKey)) {
            case INDEX: return String.valueOf(parametersIndex);
            case PARAMS: return Utils.stringify(parameters);
            case METHOD: return method.name();
            default: return substituteDynamicMacro(macro, macroKey, parameters);
        }
    }

    private String substituteDynamicMacro(String macro, String macroKey, Object parameters) {
        if (isMethodParameterIndex(macroKey)) {
            int index = parseIndex(macroKey);
            return Utils.getParameterStringByIndexOrEmpty(parameters, index);
        }

        return macro;
    }

    private boolean isMethodParameterIndex(String macroKey) {
        return macroKey.matches("\\d+");
    }

    private int parseIndex(String macroKey) {
        return Integer.parseInt(macroKey);
    }

    private String getMacroKey(String macro) {
        return macro
                .substring(MACRO_START.length(), macro.length() - MACRO_END.length())
                .toUpperCase(Locale.ENGLISH);
    }

    private boolean isMacro(String part) {
        return part.startsWith(MACRO_START) && part.endsWith(MACRO_END);
    }

    private enum Macro {
        INDEX,
        PARAMS,
        METHOD,
        NONE;

        public static Macro parse(String value) {
            if (macros.contains(value)) {
                return Macro.valueOf(value);
            } else {
                return Macro.NONE;
            }
        }

        private static final HashSet<String> macros = new HashSet<String>(Arrays.asList(
                Macro.INDEX.toString(), Macro.PARAMS.toString(), Macro.METHOD.toString())
        );
    }
}