1 package junitparams.naming; 2 3 import junitparams.internal.TestMethod; 4 import junitparams.internal.Utils; 5 6 import java.util.Arrays; 7 import java.util.HashSet; 8 import java.util.Locale; 9 import java.util.regex.Pattern; 10 11 public class MacroSubstitutionNamingStrategy implements TestCaseNamingStrategy { 12 private static final String MACRO_PATTERN = "\\{[^\\}]{0,50}\\}"; 13 // Pattern that keeps delimiters in split result 14 private static final Pattern MACRO_SPLIT_PATTERN = Pattern.compile(String.format("(?=%s)|(?<=%s)", MACRO_PATTERN, MACRO_PATTERN)); 15 private static final String MACRO_START = "{"; 16 private static final String MACRO_END = "}"; 17 // Android-changed: CTS and AndroidJUnitRunner rely on specific format to test names, changing 18 // them will prevent CTS and AndroidJUnitRunner from working properly; see b/36541809 19 static final String DEFAULT_TEMPLATE = "{method}[{index}]"; 20 private TestMethod method; 21 MacroSubstitutionNamingStrategy(TestMethod testMethod)22 public MacroSubstitutionNamingStrategy(TestMethod testMethod) { 23 this.method = testMethod; 24 } 25 26 @Override getTestCaseName(int parametersIndex, Object parameters)27 public String getTestCaseName(int parametersIndex, Object parameters) { 28 TestCaseName testCaseName = method.getAnnotation(TestCaseName.class); 29 30 String template = getTemplate(testCaseName); 31 String builtName = buildNameByTemplate(template, parametersIndex, parameters); 32 33 if (builtName.trim().isEmpty()) { 34 return buildNameByTemplate(DEFAULT_TEMPLATE, parametersIndex, parameters); 35 } else { 36 return builtName; 37 } 38 } 39 getTemplate(TestCaseName testCaseName)40 private String getTemplate(TestCaseName testCaseName) { 41 if (testCaseName != null) { 42 // Android-changed: CTS and AndroidJUnitRunner rely on specific format to test names, 43 // changing them will prevent CTS and AndroidJUnitRunner from working properly; 44 // see b/36541809 45 throw new IllegalStateException( 46 "@TestCaseName not currently supported as it breaks running tests in CTS"); 47 // return testCaseName.value(); 48 } 49 50 return DEFAULT_TEMPLATE; 51 } 52 buildNameByTemplate(String template, int parametersIndex, Object parameters)53 private String buildNameByTemplate(String template, int parametersIndex, Object parameters) { 54 StringBuilder nameBuilder = new StringBuilder(); 55 56 String[] parts = MACRO_SPLIT_PATTERN.split(template); 57 58 for (String part : parts) { 59 String transformedPart = transformPart(part, parametersIndex, parameters); 60 nameBuilder.append(transformedPart); 61 } 62 63 return nameBuilder.toString(); 64 } 65 transformPart(String part, int parametersIndex, Object parameters)66 private String transformPart(String part, int parametersIndex, Object parameters) { 67 if (isMacro(part)) { 68 return lookupMacroValue(part, parametersIndex, parameters); 69 } 70 71 return part; 72 } 73 lookupMacroValue(String macro, int parametersIndex, Object parameters)74 private String lookupMacroValue(String macro, int parametersIndex, Object parameters) { 75 String macroKey = getMacroKey(macro); 76 77 switch (Macro.parse(macroKey)) { 78 case INDEX: return String.valueOf(parametersIndex); 79 case PARAMS: return Utils.stringify(parameters); 80 case METHOD: return method.name(); 81 default: return substituteDynamicMacro(macro, macroKey, parameters); 82 } 83 } 84 substituteDynamicMacro(String macro, String macroKey, Object parameters)85 private String substituteDynamicMacro(String macro, String macroKey, Object parameters) { 86 if (isMethodParameterIndex(macroKey)) { 87 int index = parseIndex(macroKey); 88 return Utils.getParameterStringByIndexOrEmpty(parameters, index); 89 } 90 91 return macro; 92 } 93 isMethodParameterIndex(String macroKey)94 private boolean isMethodParameterIndex(String macroKey) { 95 return macroKey.matches("\\d+"); 96 } 97 parseIndex(String macroKey)98 private int parseIndex(String macroKey) { 99 return Integer.parseInt(macroKey); 100 } 101 getMacroKey(String macro)102 private String getMacroKey(String macro) { 103 return macro 104 .substring(MACRO_START.length(), macro.length() - MACRO_END.length()) 105 .toUpperCase(Locale.ENGLISH); 106 } 107 isMacro(String part)108 private boolean isMacro(String part) { 109 return part.startsWith(MACRO_START) && part.endsWith(MACRO_END); 110 } 111 112 private enum Macro { 113 INDEX, 114 PARAMS, 115 METHOD, 116 NONE; 117 parse(String value)118 public static Macro parse(String value) { 119 if (macros.contains(value)) { 120 return Macro.valueOf(value); 121 } else { 122 return Macro.NONE; 123 } 124 } 125 126 private static final HashSet<String> macros = new HashSet<String>(Arrays.asList( 127 Macro.INDEX.toString(), Macro.PARAMS.toString(), Macro.METHOD.toString()) 128 ); 129 } 130 } 131