Show incremental progress of unit test.
Summary:
By running a unit test, you can see the progress of
the unit test interactively in the message window.
diff --git a/plugin/src/com/facebook/buck/plugin/intellij/BuckPluginComponent.java b/plugin/src/com/facebook/buck/plugin/intellij/BuckPluginComponent.java
index 9b971ff..db40f3c 100644
--- a/plugin/src/com/facebook/buck/plugin/intellij/BuckPluginComponent.java
+++ b/plugin/src/com/facebook/buck/plugin/intellij/BuckPluginComponent.java
@@ -25,6 +25,7 @@
import com.facebook.buck.plugin.intellij.commands.event.Event;
import com.facebook.buck.plugin.intellij.commands.event.RuleEnd;
import com.facebook.buck.plugin.intellij.commands.event.RuleStart;
+import com.facebook.buck.plugin.intellij.commands.event.TestResultsAvailable;
import com.facebook.buck.plugin.intellij.ui.BuckUI;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
@@ -219,6 +220,8 @@
buckUI.getProgressPanel().startRule((RuleStart) event);
} else if (event instanceof RuleEnd) {
buckUI.getProgressPanel().endRule((RuleEnd) event);
+ } else if (event instanceof TestResultsAvailable) {
+ buckUI.getProgressPanel().testResult((TestResultsAvailable) event);
}
}
}
diff --git a/plugin/src/com/facebook/buck/plugin/intellij/commands/event/EventFactory.java b/plugin/src/com/facebook/buck/plugin/intellij/commands/event/EventFactory.java
index 90a9160..2de78d0 100644
--- a/plugin/src/com/facebook/buck/plugin/intellij/commands/event/EventFactory.java
+++ b/plugin/src/com/facebook/buck/plugin/intellij/commands/event/EventFactory.java
@@ -25,6 +25,7 @@
public static final String RULE_START = "BuildRuleStarted";
public static final String RULE_END = "BuildRuleFinished";
+ public static final String TEST_RESULTS_AVAILABLE = "ResultsAvailable";
private static final Logger LOG = Logger.getInstance(EventFactory.class);
private EventFactory() {}
@@ -35,14 +36,16 @@
int timestamp = object.get("timestamp").getAsInt();
String buildId = object.get("buildId").getAsString();
int threadId = object.get("threadId").getAsInt();
- if (type.equals(RULE_START)) {
+ if (RULE_START.equals(type)) {
String name = object.get("buildRule").getAsJsonObject().get("name").getAsString();
return new RuleStart(timestamp, buildId, threadId, name);
- } else if (type.equals(RULE_END)) {
+ } else if (RULE_END.equals(type)) {
String name = object.get("buildRule").getAsJsonObject().get("name").getAsString();
String status = object.get("status").getAsString();
String cache = object.get("cacheResult").getAsString();
return new RuleEnd(timestamp, buildId, threadId, name, status, cache.equals("HIT"));
+ } else if (TEST_RESULTS_AVAILABLE.equals(type)) {
+ return TestResultsAvailable.factory(object, timestamp, buildId, threadId);
} else {
LOG.warn("Unhandled message: " + object.toString());
}
diff --git a/plugin/src/com/facebook/buck/plugin/intellij/commands/event/TestResultsAvailable.java b/plugin/src/com/facebook/buck/plugin/intellij/commands/event/TestResultsAvailable.java
new file mode 100644
index 0000000..450b891
--- /dev/null
+++ b/plugin/src/com/facebook/buck/plugin/intellij/commands/event/TestResultsAvailable.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2013-present Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License. You may obtain
+ * a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+package com.facebook.buck.plugin.intellij.commands.event;
+
+import com.facebook.buck.plugin.intellij.ui.ProgressNode;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+
+import javax.annotation.Nullable;
+
+public class TestResultsAvailable extends Event {
+
+ private final ImmutableList<TestCase> testCases;
+
+ private TestResultsAvailable(int timestamp,
+ String buildId,
+ int threadId,
+ ImmutableList<TestCase> testCases) {
+ super(EventFactory.TEST_RESULTS_AVAILABLE, timestamp, buildId, threadId);
+ this.testCases = Preconditions.checkNotNull(testCases);
+ }
+
+ public static TestResultsAvailable factory(JsonObject object,
+ int timestamp,
+ String buildId,
+ int threadId) {
+ JsonObject resultsObject = object.get("results").getAsJsonObject();
+ JsonArray testCasesObject = resultsObject.get("testCases").getAsJsonArray();
+ ImmutableList.Builder<TestCase> testCasesBuilder = ImmutableList.builder();
+ for (JsonElement element : testCasesObject) {
+ JsonObject testCaseObject = element.getAsJsonObject();
+ TestCase testCase = TestCase.factory(testCaseObject);
+ testCasesBuilder.add(testCase);
+ }
+ ImmutableList<TestCase> testCases = testCasesBuilder.build();
+ return new TestResultsAvailable(timestamp, buildId, threadId, testCases);
+ }
+
+ public ImmutableList<ProgressNode> createTreeNodes() {
+ ImmutableList.Builder<ProgressNode> builder = ImmutableList.builder();
+ for (TestCase testCase : testCases) {
+ builder.add(testCase.createTreeNode(this));
+ }
+ return builder.build();
+ }
+
+ private static class TestCase {
+ private final String testCaseName;
+ private final int totalTime;
+ private final boolean success;
+ private final ImmutableList<TestResult> testResults;
+
+ private TestCase(String testCaseName,
+ int totalTime,
+ boolean success,
+ ImmutableList<TestResult> testResults) {
+ this.testCaseName = Preconditions.checkNotNull(testCaseName);
+ this.totalTime = totalTime;
+ this.success = success;
+ this.testResults = Preconditions.checkNotNull(testResults);
+ }
+
+ public static TestCase factory(JsonObject testCase) {
+ String testCaseName = testCase.get("testCaseName").getAsString();
+ int totalTime = testCase.get("totalTime").getAsInt();
+ boolean success = testCase.get("success").getAsBoolean();
+ JsonArray testResultsObject = testCase.get("testResults").getAsJsonArray();
+ ImmutableList.Builder<TestResult> testResultsBuilder = ImmutableList.builder();
+ for (JsonElement element : testResultsObject) {
+ JsonObject testResultObject = element.getAsJsonObject();
+ TestResult testResult = TestResult.factory(testResultObject);
+ testResultsBuilder.add(testResult);
+ }
+ ImmutableList<TestResult> testResults = testResultsBuilder.build();
+ return new TestCase(testCaseName, totalTime, success, testResults);
+ }
+
+ public ProgressNode createTreeNode(TestResultsAvailable event) {
+ ProgressNode testCaseNode;
+ if (success) {
+ String title = String.format("[%d ms] %s", totalTime, testCaseName);
+ testCaseNode = new ProgressNode(ProgressNode.Type.TEST_CASE_SUCCESS, title, event);
+ } else {
+ testCaseNode = new ProgressNode(ProgressNode.Type.TEST_CASE_FAILURE, testCaseName, event);
+ }
+ for (TestResult testResult : testResults) {
+ ProgressNode testResultNode = testResult.createTreeNode(event);
+ testCaseNode.add(testResultNode);
+ }
+ return testCaseNode;
+ }
+
+ private static class TestResult {
+ private final String testName;
+ private final boolean success;
+ private final int time;
+ @Nullable
+ private final String message;
+ @Nullable
+ @SuppressWarnings("unused")
+ private final String stacktrace;
+ @Nullable
+ @SuppressWarnings("unused")
+ private final String stdOut;
+ @Nullable
+ @SuppressWarnings("unused")
+ private final String stdErr;
+
+ private TestResult(String testName,
+ boolean success,
+ int time,
+ String message,
+ String stacktrace,
+ String stdOut,
+ String stdErr) {
+ this.testName = Preconditions.checkNotNull(testName);
+ this.success = success;
+ this.time = time;
+ this.message = message;
+ this.stacktrace = stacktrace;
+ this.stdOut = stdOut;
+ this.stdErr = stdErr;
+ }
+
+ public static TestResult factory(JsonObject testResult) {
+ String testName = testResult.get("testName").getAsString();
+ boolean success = testResult.get("success").getAsBoolean();
+ int time = testResult.get("time").getAsInt();
+ String message = null;
+ if (!testResult.get("message").isJsonNull()) {
+ message = testResult.get("message").getAsString();
+ }
+ String stacktrace = null;
+ if (!testResult.get("stacktrace").isJsonNull()) {
+ stacktrace = testResult.get("stacktrace").getAsString();
+ }
+ String stdOut = null;
+ if (!testResult.get("stdOut").isJsonNull()) {
+ stdOut = testResult.get("stdOut").getAsString();
+ }
+ String stdErr = null;
+ if (!testResult.get("stdErr").isJsonNull()) {
+ stdErr = testResult.get("stdErr").getAsString();
+ }
+ return new TestResult(testName, success, time, message, stacktrace, stdOut, stdErr);
+ }
+
+ public ProgressNode createTreeNode(TestResultsAvailable event) {
+ if (success) {
+ String title = String.format("[%d ms] %s", time, testName);
+ return new ProgressNode(ProgressNode.Type.TEST_RESULT_SUCCESS, title, event);
+ } else {
+ String title = String.format("%s %s", testName, message);
+ return new ProgressNode(ProgressNode.Type.TEST_RESULT_FAILURE, title, event);
+ }
+ }
+ }
+ }
+}
diff --git a/plugin/src/com/facebook/buck/plugin/intellij/ui/BuckProgressPanel.java b/plugin/src/com/facebook/buck/plugin/intellij/ui/BuckProgressPanel.java
index 4ae5f24..581883c 100644
--- a/plugin/src/com/facebook/buck/plugin/intellij/ui/BuckProgressPanel.java
+++ b/plugin/src/com/facebook/buck/plugin/intellij/ui/BuckProgressPanel.java
@@ -18,7 +18,9 @@
import com.facebook.buck.plugin.intellij.commands.event.RuleEnd;
import com.facebook.buck.plugin.intellij.commands.event.RuleStart;
+import com.facebook.buck.plugin.intellij.commands.event.TestResultsAvailable;
import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.intellij.ui.treeStructure.Tree;
import com.intellij.util.ui.tree.TreeUtil;
@@ -38,6 +40,7 @@
public static final String TREE_ROOT = "Buck";
public static final String BUILDING_ROOT = "Building";
public static final String BUILT_ROOT = "Built";
+ private static final String TEST_ROOT = "Test";
private JPanel panel;
private JTree tree;
@@ -47,9 +50,11 @@
private ProgressNode treeRoot;
private ProgressNode buildingRoot;
private ProgressNode builtRoot;
+ private ProgressNode testRoot;
private TreePath rootPath;
private TreePath buildingPath;
private TreePath builtPath;
+ private TreePath testPath;
private List<ProgressNode> items;
public JPanel getPanel() {
@@ -97,6 +102,21 @@
});
}
+ public void testResult(TestResultsAvailable event) {
+ Preconditions.checkNotNull(event);
+ final ImmutableList<ProgressNode> nodes = event.createTreeNodes();
+ EventQueue.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ for (ProgressNode node : nodes) {
+ treeModel.insertNodeInto(node, testRoot, testRoot.getChildCount());
+ expand();
+ scrollTo(node);
+ }
+ }
+ });
+ }
+
private ProgressNode findBuildingNode(RuleEnd current) {
Preconditions.checkNotNull(current);
for (ProgressNode item : items) {
@@ -123,15 +143,17 @@
rootPath = new TreePath(treeRoot);
treeModel = new DefaultTreeModel(treeRoot);
- builtRoot = new ProgressNode(
- ProgressNode.Type.DIRECTORY, BUILT_ROOT, null);
+ builtRoot = new ProgressNode(ProgressNode.Type.DIRECTORY, BUILT_ROOT, null);
builtPath = new TreePath(builtRoot);
treeModel.insertNodeInto(builtRoot, treeRoot, treeRoot.getChildCount());
- buildingRoot = new ProgressNode(
- ProgressNode.Type.DIRECTORY, BUILDING_ROOT, null);
+ buildingRoot = new ProgressNode(ProgressNode.Type.DIRECTORY, BUILDING_ROOT, null);
buildingPath = new TreePath(buildingRoot);
treeModel.insertNodeInto(buildingRoot, treeRoot, treeRoot.getChildCount());
+
+ testRoot = new ProgressNode(ProgressNode.Type.DIRECTORY, TEST_ROOT, null);
+ testPath = new TreePath(testRoot);
+ treeModel.insertNodeInto(testRoot, treeRoot, treeRoot.getChildCount());
}
private void expand() {
@@ -144,6 +166,9 @@
if (!tree.hasBeenExpanded(builtPath)) {
tree.expandPath(builtPath);
}
+ if (!tree.hasBeenExpanded(testPath)) {
+ tree.expandPath(testPath);
+ }
}
private void scrollTo(ProgressNode node) {
diff --git a/plugin/src/com/facebook/buck/plugin/intellij/ui/MessageTreeRenderer.java b/plugin/src/com/facebook/buck/plugin/intellij/ui/MessageTreeRenderer.java
index 9bdcdc8..1eb7ce1 100644
--- a/plugin/src/com/facebook/buck/plugin/intellij/ui/MessageTreeRenderer.java
+++ b/plugin/src/com/facebook/buck/plugin/intellij/ui/MessageTreeRenderer.java
@@ -69,6 +69,22 @@
prefix = "Error";
icon = AllIcons.General.Error;
break;
+ case TEST_CASE_SUCCESS:
+ prefix = "Test";
+ icon = AllIcons.Modules.TestRoot;
+ break;
+ case TEST_CASE_FAILURE:
+ prefix = "Test Failure";
+ icon = AllIcons.General.Error;
+ break;
+ case TEST_RESULT_SUCCESS:
+ prefix = "";
+ icon = AllIcons.Nodes.Advice;
+ break;
+ case TEST_RESULT_FAILURE:
+ prefix = "";
+ icon = AllIcons.General.Error;
+ break;
default:
icon = AllIcons.General.Error;
prefix = "";
diff --git a/plugin/src/com/facebook/buck/plugin/intellij/ui/ProgressNode.java b/plugin/src/com/facebook/buck/plugin/intellij/ui/ProgressNode.java
index 0de1f46..734c36b7 100644
--- a/plugin/src/com/facebook/buck/plugin/intellij/ui/ProgressNode.java
+++ b/plugin/src/com/facebook/buck/plugin/intellij/ui/ProgressNode.java
@@ -29,7 +29,11 @@
BUILDING,
BUILT,
BUILT_CACHED,
- BUILD_ERROR
+ BUILD_ERROR,
+ TEST_CASE_SUCCESS,
+ TEST_CASE_FAILURE,
+ TEST_RESULT_SUCCESS,
+ TEST_RESULT_FAILURE
}
private String name;