1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.tradefed.result; 17 18 import com.android.ddmlib.testrunner.TestIdentifier; 19 20 import java.io.Serializable; 21 import java.lang.annotation.Annotation; 22 import java.util.Arrays; 23 import java.util.Collection; 24 import java.util.regex.Matcher; 25 import java.util.regex.Pattern; 26 27 /** Class representing information about a test case. */ 28 public final class TestDescription implements Serializable, Comparable<TestDescription> { 29 30 /** Regex for method parameterized. For example: testName[0] */ 31 public static final Pattern PARAMETERIZED_TEST_REGEX = Pattern.compile("([^\\[]+)\\[(.*)\\]$"); 32 33 private final String mClassName; 34 private final String mTestName; 35 private final String mTestNameNoParams; 36 private Annotation[] mAnnotations; 37 38 /** 39 * Constructor 40 * 41 * @param className The name of the class holding the test. 42 * @param testName The test (method) name. 43 */ TestDescription(String className, String testName)44 public TestDescription(String className, String testName) { 45 if (className == null || testName == null) { 46 throw new IllegalArgumentException("className and testName must be non-null"); 47 } 48 mClassName = className; 49 mTestName = testName; 50 mAnnotations = new Annotation[0]; 51 52 // If the method looks parameterized, track the base non-parameterized name. 53 Matcher m = PARAMETERIZED_TEST_REGEX.matcher(testName); 54 if (m.find()) { 55 mTestNameNoParams = m.group(1); 56 } else { 57 mTestNameNoParams = testName; 58 } 59 } 60 61 /** 62 * Constructor 63 * 64 * @param className The name of the class holding the test. 65 * @param testName The test (method) name. 66 * @param annotations List of {@link Annotation} associated with the test case. 67 */ TestDescription(String className, String testName, Annotation... annotations)68 public TestDescription(String className, String testName, Annotation... annotations) { 69 this(className, testName); 70 mAnnotations = annotations; 71 } 72 73 /** 74 * Constructor 75 * 76 * @param className The name of the class holding the test. 77 * @param testName The test (method) name. 78 * @param annotations Collection of {@link Annotation} associated with the test case. 79 */ TestDescription(String className, String testName, Collection<Annotation> annotations)80 public TestDescription(String className, String testName, Collection<Annotation> annotations) { 81 this(className, testName, annotations.toArray(new Annotation[annotations.size()])); 82 } 83 84 /** 85 * @return the annotation of type annotationType that is attached to this description node, or 86 * null if none exists 87 */ getAnnotation(Class<T> annotationType)88 public <T extends Annotation> T getAnnotation(Class<T> annotationType) { 89 for (Annotation each : mAnnotations) { 90 if (each.annotationType().equals(annotationType)) { 91 return annotationType.cast(each); 92 } 93 } 94 return null; 95 } 96 97 /** @return all of the annotations attached to this description node */ getAnnotations()98 public Collection<Annotation> getAnnotations() { 99 return Arrays.asList(mAnnotations); 100 } 101 102 /** Returns the fully qualified class name of the test. */ getClassName()103 public String getClassName() { 104 return mClassName; 105 } 106 107 /** 108 * Returns the name of the test with the parameters, if it's parameterized test. Returns the 109 * regular test name if not a parameterized test. 110 */ getTestName()111 public String getTestName() { 112 return mTestName; 113 } 114 115 /** Returns the name of the test without any parameters (if it's a parameterized method). */ getTestNameWithoutParams()116 public String getTestNameWithoutParams() { 117 return mTestNameNoParams; 118 } 119 120 @Override hashCode()121 public int hashCode() { 122 final int prime = 31; 123 int result = 1; 124 result = prime * result + ((mClassName == null) ? 0 : mClassName.hashCode()); 125 result = prime * result + ((mTestName == null) ? 0 : mTestName.hashCode()); 126 return result; 127 } 128 129 @Override equals(Object obj)130 public boolean equals(Object obj) { 131 if (this == obj) return true; 132 if (obj == null) return false; 133 if (getClass() != obj.getClass()) return false; 134 TestDescription other = (TestDescription) obj; 135 136 if (!mClassName.equals(other.mClassName) || !mTestName.equals(other.mTestName)) { 137 return false; 138 } 139 return true; 140 } 141 142 @Override compareTo(TestDescription o)143 public int compareTo(TestDescription o) { 144 return toString().compareTo(o.toString()); 145 } 146 147 @Override toString()148 public String toString() { 149 return String.format("%s#%s", getClassName(), getTestName()); 150 } 151 152 /** 153 * Create a {@link TestDescription} from its {@link #toString()}} representation. 154 * 155 * @param data the String representation. Expected format: classname#methodname 156 * @return the TestDescription or null if it could not be parsed 157 */ fromString(String data)158 public static TestDescription fromString(String data) { 159 String[] segments = data.split("#"); 160 if (segments.length == 2) { 161 return new TestDescription(segments[0], segments[1]); 162 } 163 return null; 164 } 165 166 /** 167 * Create a {@link TestDescription} from a {@link TestIdentifier}. Used for ease of conversion 168 * from one to another. 169 * 170 * @param testId The {@link TestIdentifier} to convert. 171 * @return the created {@link TestDescription} with the TestIdentifier values. 172 */ createFromTestIdentifier(TestIdentifier testId)173 public static TestDescription createFromTestIdentifier(TestIdentifier testId) { 174 return new TestDescription(testId.getClassName(), testId.getTestName()); 175 } 176 177 /** 178 * Create a {@link TestIdentifier} from a {@link TestDescription}. Useful for converting a 179 * description during testing. 180 * 181 * @param desc The {@link TestDescription} to convert. 182 * @return The created {@link TestIdentifier} with the TestDescription values. 183 */ convertToIdentifier(TestDescription desc)184 public static TestIdentifier convertToIdentifier(TestDescription desc) { 185 return new TestIdentifier(desc.getClassName(), desc.getTestName()); 186 } 187 } 188