Print the lists of tests that failed at the end of the test summary.

Test Plan: Broke a test, ran `buck test --all`, verified summary was displayed.
diff --git a/src/com/facebook/buck/event/listener/TestResultFormatter.java b/src/com/facebook/buck/event/listener/TestResultFormatter.java
index b2b705f..9400f08 100644
--- a/src/com/facebook/buck/event/listener/TestResultFormatter.java
+++ b/src/com/facebook/buck/event/listener/TestResultFormatter.java
@@ -22,7 +22,9 @@
 import com.facebook.buck.util.Ansi;
 import com.google.common.base.Joiner;
 import com.google.common.base.Preconditions;
+import com.google.common.collect.ArrayListMultimap;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ListMultimap;
 
 import java.util.List;
 
@@ -86,11 +88,14 @@
   public void runComplete(ImmutableList.Builder<String> addTo, List<TestResults> completedResults) {
     // Print whether each test succeeded or failed.
     boolean isAllTestsPassed = true;
+    ListMultimap<TestResults, TestCaseSummary> failingTests = ArrayListMultimap.create();
+
     int numFailures = 0;
     for (TestResults summary : completedResults) {
       if (!summary.isSuccess()) {
         isAllTestsPassed = false;
         numFailures += summary.getFailureCount();
+        failingTests.putAll(summary, summary.getFailures());
       }
     }
 
@@ -102,6 +107,12 @@
     } else {
       addTo.add(ansi.asHighlightedFailureText(
           String.format("TESTS FAILED: %d Failures", numFailures)));
+      for (TestResults results : failingTests.keySet()) {
+        addTo.add("Failed target: " + results.getBuildTarget().getFullyQualifiedName());
+        for (TestCaseSummary summary : failingTests.get(results)) {
+          addTo.add(summary.toString());
+        }
+      }
     }
   }
 }
diff --git a/src/com/facebook/buck/java/JavaTestRule.java b/src/com/facebook/buck/java/JavaTestRule.java
index 6160e4f..93fa6bd 100644
--- a/src/com/facebook/buck/java/JavaTestRule.java
+++ b/src/com/facebook/buck/java/JavaTestRule.java
@@ -258,7 +258,7 @@
         // were run by its deps. In this case, return an empty TestResults.
         Set<String> testClassNames = getClassNamesForSources(context);
         if (testClassNames.isEmpty()) {
-          return TestResults.getEmptyTestResults();
+          return new TestResults(getBuildTarget(), ImmutableList.<TestCaseSummary>of(), contacts);
         }
 
         List<TestCaseSummary> summaries = Lists.newArrayListWithCapacity(testClassNames.size());
@@ -270,7 +270,7 @@
           summaries.add(summary);
         }
 
-        return new TestResults(contacts, summaries);
+        return new TestResults(getBuildTarget(), summaries, contacts);
       }
 
     };
diff --git a/src/com/facebook/buck/shell/ShTestRule.java b/src/com/facebook/buck/shell/ShTestRule.java
index 677fa7a..1f8acae 100644
--- a/src/com/facebook/buck/shell/ShTestRule.java
+++ b/src/com/facebook/buck/shell/ShTestRule.java
@@ -141,7 +141,7 @@
             TestResultSummary.class);
         TestCaseSummary testCaseSummary = new TestCaseSummary(
             getFullyQualifiedName(), ImmutableList.of(testResultSummary));
-        return new TestResults(contacts, ImmutableList.of(testCaseSummary));
+        return new TestResults(getBuildTarget(), ImmutableList.of(testCaseSummary), contacts);
       }
 
     };
diff --git a/src/com/facebook/buck/test/BUCK b/src/com/facebook/buck/test/BUCK
index 0cc84c8..ab4384f 100644
--- a/src/com/facebook/buck/test/BUCK
+++ b/src/com/facebook/buck/test/BUCK
@@ -5,6 +5,7 @@
   deps = [
     '//lib:guava',
     '//lib:jsr305',
+    '//src/com/facebook/buck/model:model',
     '//src/com/facebook/buck/util:io',
     '//src/com/facebook/buck/util:util',
   ],
diff --git a/src/com/facebook/buck/test/TestResults.java b/src/com/facebook/buck/test/TestResults.java
index 644df24..d74ea78 100644
--- a/src/com/facebook/buck/test/TestResults.java
+++ b/src/com/facebook/buck/test/TestResults.java
@@ -16,12 +16,15 @@
 
 package com.facebook.buck.test;
 
+import com.facebook.buck.model.BuildTarget;
 import com.google.common.annotations.Beta;
+import com.google.common.annotations.VisibleForTesting;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 
 import java.util.List;
 
+import javax.annotation.Nullable;
 import javax.annotation.concurrent.Immutable;
 
 /**
@@ -30,18 +33,26 @@
 @Immutable
 public class TestResults {
 
-  private static final TestResults EMPTY_TEST_RESULTS = new TestResults(
-      null, ImmutableList.<TestCaseSummary>of());
-
-  private final ImmutableSet<String> contacts;
+  private final BuildTarget source;
   private final ImmutableList<TestCaseSummary> testCases;
-  private final List<TestCaseSummary> failures;
+  private final ImmutableList<TestCaseSummary> failures;
   private final int failureCount;
+  private final ImmutableSet<String> contacts;
+
+  @VisibleForTesting
+  public TestResults(List<TestCaseSummary> testCases) {
+    this(/* source */ null, testCases, /* contacts */ ImmutableSet.<String>of());
+  }
+
+  // TODO(mbolin): Require source to be non-null once D963189 is submitted.
 
   @Beta
-  public TestResults(ImmutableSet<String> contacts, List<TestCaseSummary> testCases) {
-    this.contacts = contacts;
+  public TestResults(@Nullable BuildTarget source,
+      List<TestCaseSummary> testCases,
+      ImmutableSet<String> contacts) {
+    this.source = source;
     this.testCases = ImmutableList.copyOf(testCases);
+    this.contacts = ImmutableSet.copyOf(contacts);
 
     int failureCount = 0;
     ImmutableList.Builder<TestCaseSummary> failures = ImmutableList.builder();
@@ -55,8 +66,8 @@
     this.failureCount = failureCount;
   }
 
-  public static TestResults getEmptyTestResults() {
-    return EMPTY_TEST_RESULTS;
+  public BuildTarget getBuildTarget() {
+    return source;
   }
 
   public boolean isSuccess() {
@@ -67,6 +78,10 @@
     return failureCount;
   }
 
+  public ImmutableList<TestCaseSummary> getFailures() {
+    return failures;
+  }
+
   public ImmutableList<TestCaseSummary> getTestCases() {
     return testCases;
   }
diff --git a/test/com/facebook/buck/cli/TestCommandTest.java b/test/com/facebook/buck/cli/TestCommandTest.java
index a513637..7cf38bb 100644
--- a/test/com/facebook/buck/cli/TestCommandTest.java
+++ b/test/com/facebook/buck/cli/TestCommandTest.java
@@ -322,7 +322,7 @@
     TestCaseSummary testCase = new TestCaseSummary("TestCase", resultList);
     List<TestCaseSummary> testCases = ImmutableList.of(testCase);
 
-    TestResults testResults = new TestResults(ImmutableSet.<String>of(), testCases);
+    TestResults testResults = new TestResults(testCases);
     List<TestResults> testResultsList = ImmutableList.of(testResults);
 
     // Call the XML generation method with our test data.
diff --git a/test/com/facebook/buck/event/listener/TestResultFormatterTest.java b/test/com/facebook/buck/event/listener/TestResultFormatterTest.java
index 0e01d60..711f68b 100644
--- a/test/com/facebook/buck/event/listener/TestResultFormatterTest.java
+++ b/test/com/facebook/buck/event/listener/TestResultFormatterTest.java
@@ -18,6 +18,7 @@
 
 import static org.junit.Assert.assertEquals;
 
+import com.facebook.buck.model.BuildTargetFactory;
 import com.facebook.buck.test.TestCaseSummary;
 import com.facebook.buck.test.TestResultSummary;
 import com.facebook.buck.test.TestResults;
@@ -99,7 +100,7 @@
   public void allTestsPassingShouldBeAcknowledged() {
     TestCaseSummary summary = new TestCaseSummary(
         "com.example.FooTest", ImmutableList.of(successTest));
-    TestResults results = new TestResults(ImmutableSet.<String>of(), ImmutableList.of(summary));
+    TestResults results = new TestResults(ImmutableList.of(summary));
     ImmutableList.Builder<String> builder = ImmutableList.builder();
 
     formatter.runComplete(builder, ImmutableList.of(results));
@@ -111,19 +112,26 @@
   public void shouldReportTheNumberOfFailingTests() {
     TestCaseSummary summary = new TestCaseSummary(
         "com.example.FooTest", ImmutableList.of(successTest, failingTest));
-    TestResults results = new TestResults(ImmutableSet.<String>of(), ImmutableList.of(summary));
+    TestResults results = new TestResults(
+        BuildTargetFactory.newInstance("//foo:bar"),
+        ImmutableList.of(summary),
+        /* contacts */ ImmutableSet.<String>of());
     ImmutableList.Builder<String> builder = ImmutableList.builder();
 
     formatter.runComplete(builder, ImmutableList.of(results));
 
-    assertEquals("TESTS FAILED: 1 Failures", toString(builder));
+    String expectedOutput = Joiner.on('\n').join(
+        "TESTS FAILED: 1 Failures",
+        "Failed target: //foo:bar",
+        "FAIL com.example.FooTest");
+    assertEquals(expectedOutput, toString(builder));
   }
 
   @Test
   public void shouldReportMinimalInformationForAPassingTest() {
     TestCaseSummary summary = new TestCaseSummary(
         "com.example.FooTest", ImmutableList.of(successTest));
-    TestResults results = new TestResults(ImmutableSet.<String>of(), ImmutableList.of(summary));
+    TestResults results = new TestResults(ImmutableList.of(summary));
     ImmutableList.Builder<String> builder = ImmutableList.builder();
 
     formatter.reportResult(builder, results);
@@ -136,7 +144,7 @@
   public void shouldOutputStackTraceStdOutAndStdErrOfFailingTest() {
     TestCaseSummary summary = new TestCaseSummary(
         "com.example.FooTest", ImmutableList.of(failingTest));
-    TestResults results = new TestResults(ImmutableSet.<String>of(), ImmutableList.of(summary));
+    TestResults results = new TestResults(ImmutableList.of(summary));
     ImmutableList.Builder<String> builder = ImmutableList.builder();
 
     formatter.reportResult(builder, results);
diff --git a/test/com/facebook/buck/rules/IndividualTestEventTest.java b/test/com/facebook/buck/rules/IndividualTestEventTest.java
index 7ede3e9..7770c3a 100644
--- a/test/com/facebook/buck/rules/IndividualTestEventTest.java
+++ b/test/com/facebook/buck/rules/IndividualTestEventTest.java
@@ -22,7 +22,6 @@
 import com.facebook.buck.test.TestCaseSummary;
 import com.facebook.buck.test.TestResults;
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
 
 import org.junit.Test;
 
@@ -33,7 +32,7 @@
 
     IndividualTestEvent.Started started = IndividualTestEvent.started(tests);
     IndividualTestEvent.Finished finished = IndividualTestEvent.finished(
-        tests, new TestResults(ImmutableSet.<String>of(), ImmutableList.<TestCaseSummary>of()));
+        tests, new TestResults(ImmutableList.<TestCaseSummary>of()));
 
     assertTrue(started.eventsArePair(finished));
     assertTrue(finished.eventsArePair(started));
@@ -46,7 +45,7 @@
 
     IndividualTestEvent.Started started = IndividualTestEvent.started(tests);
     IndividualTestEvent.Finished finished = IndividualTestEvent.finished(
-        otherTests, new TestResults(ImmutableSet.<String>of(), ImmutableList.<TestCaseSummary>of()));
+        otherTests, new TestResults(ImmutableList.<TestCaseSummary>of()));
 
     assertFalse(started.eventsArePair(finished));
     assertFalse(finished.eventsArePair(started));