Chromium Code Reviews| Index: base/test/android/javatests/src/org/chromium/base/test/TestListInstrumentationRunListener.java |
| diff --git a/base/test/android/javatests/src/org/chromium/base/test/TestListInstrumentationRunListener.java b/base/test/android/javatests/src/org/chromium/base/test/TestListInstrumentationRunListener.java |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..c3431e858db6b25bae761cd2543161104e327f08 |
| --- /dev/null |
| +++ b/base/test/android/javatests/src/org/chromium/base/test/TestListInstrumentationRunListener.java |
| @@ -0,0 +1,154 @@ |
| +// Copyright 2017 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +package org.chromium.base.test; |
| + |
| +import android.support.test.internal.runner.listener.InstrumentationRunListener; |
| + |
| +import org.json.JSONArray; |
| +import org.json.JSONObject; |
| +import org.junit.runner.Description; |
| +import org.junit.runner.Result; |
| + |
| +import org.chromium.base.Log; |
| + |
| +import java.io.File; |
| +import java.io.FileOutputStream; |
| +import java.io.IOException; |
| +import java.io.OutputStreamWriter; |
| +import java.io.Writer; |
| +import java.lang.annotation.Annotation; |
| +import java.lang.reflect.Method; |
| +import java.util.Arrays; |
| +import java.util.Collection; |
| +import java.util.HashMap; |
| +import java.util.HashSet; |
| +import java.util.LinkedList; |
| +import java.util.List; |
| +import java.util.Map; |
| +import java.util.Set; |
| + |
| +/** |
| + * A RunListener that list out all the test information into a json file. |
| + */ |
| +public class TestListInstrumentationRunListener extends InstrumentationRunListener { |
| + private static final String TAG = "TestListRunListener"; |
| + private static final Set<String> SKIP_METHODS = new HashSet<>( |
| + Arrays.asList(new String[] {"toString", "hashCode", "annotationType", "equals"})); |
| + |
| + private final Map<Class<?>, List<JSONObject>> mTestClassJSONObjects = new HashMap<>(); |
|
mikecase (-- gone --)
2017/07/19 17:11:01
why not JSONArray instead of List<JSONObject>?
the real yoland
2017/07/20 02:04:32
I think this was done for perf reasons, but I don'
|
| + private final String mOutputPath; |
| + |
| + public TestListInstrumentationRunListener(String outputPath) { |
| + super(); |
| + mOutputPath = outputPath; |
| + } |
| + |
| + /** |
| + * Store the test method description to a Map at the beginning of a test run. |
| + */ |
| + @Override |
| + public void testStarted(Description desc) throws Exception { |
| + if (!mTestClassJSONObjects.containsKey(desc.getTestClass())) { |
| + mTestClassJSONObjects.put(desc.getTestClass(), new LinkedList<JSONObject>()); |
| + } |
| + mTestClassJSONObjects.get(desc.getTestClass()).add(getTestMethodJSON(desc)); |
|
mikecase (-- gone --)
2017/07/19 17:11:01
I thought this was kinda confusing the way the cod
the real yoland
2017/07/20 02:04:33
Done
|
| + } |
| + |
| + /** |
| + * Create a JSONArray with all the test class JSONObjects and save it to listed output path. |
| + */ |
| + @Override |
| + public void testRunFinished(Result result) throws Exception { |
| + List<JSONObject> allTestClasses = new LinkedList<>(); |
|
mikecase (-- gone --)
2017/07/19 17:11:01
Could this just be a JSONArray instead of creating
the real yoland
2017/07/20 02:04:33
Done
|
| + for (Map.Entry<Class<?>, List<JSONObject>> entry : mTestClassJSONObjects.entrySet()) { |
| + Class<?> testClass = entry.getKey(); |
| + JSONObject classObject = |
| + new JSONObject() |
| + .put("class", testClass.getName()) |
| + .put("superclass", testClass.getSuperclass().getName()) |
| + .put("annotations", |
| + getAnnotationJSON(Arrays.asList(testClass.getAnnotations()))) |
| + .put("methods", new JSONArray(entry.getValue())); |
| + allTestClasses.add(classObject); |
|
mikecase (-- gone --)
2017/07/19 17:11:01
As mentioned, I think the code would be more nicel
jbudorick
2017/07/19 20:43:34
w/ this suggestion, testRunFinished would just be
the real yoland
2017/07/20 02:04:32
Done
the real yoland
2017/07/20 02:04:33
Done
|
| + } |
| + Writer writer = null; |
| + File file = new File(mOutputPath); |
| + try { |
| + writer = new OutputStreamWriter(new FileOutputStream(file), "UTF-8"); |
| + JSONArray allTestClassesJSON = new JSONArray(allTestClasses); |
| + writer.write(allTestClassesJSON.toString()); |
| + } catch (Exception e) { |
| + Log.e(TAG, "failed to write json to file", e); |
| + } finally { |
| + if (writer != null) { |
| + try { |
| + writer.close(); |
| + } catch (IOException e) { |
| + } |
| + } |
| + } |
| + } |
| + |
| + /** |
| + * Return a JSONOject that represent a Description of a method". |
| + */ |
| + static JSONObject getTestMethodJSON(Description desc) throws Exception { |
| + return new JSONObject() |
| + .put("method", desc.getMethodName()) |
| + .put("annotations", getAnnotationJSON(desc.getAnnotations())); |
| + } |
| + |
| + /** |
| + * Create a JSONObject that represent a collection of anntations. |
| + * |
| + * For example, for the following group of annotations for ExampleClass |
| + * <code> |
| + * @A |
| + * @B(message = "hello", level = 3) |
| + * public class ExampleClass() {} |
| + * </code> |
| + * |
| + * This method would return a JSONObject as such: |
| + * <code> |
| + * { |
| + * "A": {}, |
| + * "B": { |
| + * "message": "hello", |
| + * "level": "3" |
| + * } |
| + * } |
| + * </code> |
| + * |
| + * The method accomplish this by though through each annotation and reflectively call the |
| + * annotation's method to get the element value, with exceptions to methods like "equals()" |
| + * or "hashCode". |
| + */ |
| + static JSONObject getAnnotationJSON(Collection<Annotation> annotations) |
| + throws Exception { |
| + JSONObject annotationsJsons = new JSONObject(); |
| + for (Annotation a : annotations) { |
| + JSONObject elementJsonObject = new JSONObject(); |
| + for (Method method : a.annotationType().getMethods()) { |
| + if (SKIP_METHODS.contains(method.getName())) { |
| + continue; |
| + } |
| + try { |
| + Object value = method.invoke(a); |
| + if (value == null) { |
| + elementJsonObject.put(method.getName(), null); |
| + } else { |
| + elementJsonObject.put(method.getName(), |
| + value.getClass().isArray() |
| + ? new JSONArray(Arrays.asList((Object[]) value)) |
| + : value.toString()); |
| + } |
| + } catch (IllegalArgumentException e) { |
| + } |
| + } |
| + annotationsJsons.put(a.annotationType().getSimpleName(), elementJsonObject); |
| + } |
| + return annotationsJsons; |
| + } |
| +} |