media: centralize signaling of skipped tests
Bug: 18513091
Change-Id: I5ffb1399de98fc8a6110ddd8877e56cf2c7c1d4b
diff --git a/libs/deviceutil/src/android/cts/util/MediaUtils.java b/libs/deviceutil/src/android/cts/util/MediaUtils.java
index 18e804f..8e88b47 100644
--- a/libs/deviceutil/src/android/cts/util/MediaUtils.java
+++ b/libs/deviceutil/src/android/cts/util/MediaUtils.java
@@ -20,6 +20,10 @@
import android.media.MediaCodecList;
import android.media.MediaExtractor;
import android.media.MediaFormat;
+import java.lang.reflect.Method;
+import static java.lang.reflect.Modifier.isPublic;
+import static java.lang.reflect.Modifier.isStatic;
+import java.util.Map;
import android.util.Log;
import java.io.IOException;
@@ -28,6 +32,92 @@
final public static String TAG = "MediaUtils";
/**
+ * Finds test name (heuristically) and prints out standard skip message.
+ *
+ * Since it uses heuristics, this method has only been verified for media
+ * tests. This centralizes the way to signal a skipped test.
+ */
+ public static void skipTest(String tag, String reason) {
+ int bestScore = -1;
+ String testName = "test???";
+ Map<Thread, StackTraceElement[]> traces = Thread.getAllStackTraces();
+ for (Map.Entry<Thread, StackTraceElement[]> entry : traces.entrySet()) {
+ StackTraceElement[] stack = entry.getValue();
+ for (int index = 0; index < stack.length; ++index) {
+ // method name must start with "test"
+ String methodName = stack[index].getMethodName();
+ if (!methodName.startsWith("test")) {
+ continue;
+ }
+
+ int score = 0;
+ // see if there is a public non-static void method that takes no argument
+ Class<?> clazz;
+ try {
+ clazz = Class.forName(stack[index].getClassName());
+ ++score;
+ for (final Method method : clazz.getDeclaredMethods()) {
+ if (method.getName().equals(methodName)
+ && isPublic(method.getModifiers())
+ && !isStatic(method.getModifiers())
+ && method.getParameterTypes().length == 0
+ && method.getReturnType().equals(Void.TYPE)) {
+ ++score;
+ break;
+ }
+ }
+ if (score == 1) {
+ // if we could read the class, but method is not public void, it is
+ // not a candidate
+ continue;
+ }
+ } catch (ClassNotFoundException e) {
+ }
+
+ // even if we cannot verify the method signature, there are signals in the stack
+
+ // usually test method is invoked by reflection
+ int depth = 1;
+ while (index + depth < stack.length
+ && stack[index + depth].getMethodName().equals("invoke")
+ && stack[index + depth].getClassName().equals(
+ "java.lang.reflect.Method")) {
+ ++depth;
+ }
+ if (depth > 1) {
+ ++score;
+ // and usually test method is run by runMethod method in android.test package
+ if (index + depth < stack.length) {
+ if (stack[index + depth].getClassName().startsWith("android.test.")) {
+ ++score;
+ }
+ if (stack[index + depth].getMethodName().equals("runMethod")) {
+ ++score;
+ }
+ }
+ }
+
+ if (score > bestScore) {
+ bestScore = score;
+ testName = methodName;
+ }
+ }
+ }
+
+ Log.i(tag, "SKIPPING " + testName + "(): " + reason);
+ }
+
+ /**
+ * Finds test name (heuristically) and prints out standard skip message.
+ *
+ * Since it uses heuristics, this method has only been verified for media
+ * tests. This centralizes the way to signal a skipped test.
+ */
+ public static void skipTest(String reason) {
+ skipTest(TAG, reason);
+ }
+
+ /**
* return true iff all audio and video tracks are supported
*/
public static boolean hasCodecsForMedia(MediaExtractor ex) {