Make tests output spin on the same line by default.

-v now gives a cleaned-up version of the existing output (every test timed, useless information removed)

Example output, default:
  [ 36/193] PathOpsCubicIntersectionOneOffTest
then later when finished...
  [193/193] BlurMaskFilter

Example output, -v:  (note, codereview is messing up my pretty spacing)
Skia UnitTests: --resourcePath resources SK_RELEASE SK_SCALAR_IS_FLOAT skia_arch_width=32
[  1/193]     0ms PathOpsSimplifyDontFailOneTest
[  2/193]     0ms PathOpsSimplifyFailOneTest
[  3/193]    30ms PathOpsSkpTest
[  4/193]    21ms PathOpsSimplifyFailTest
....
[182/193]  1026ms BlitRow
[183/193]   808ms AAClip
[184/193]  4333ms Math
[185/193]  5068ms PackBits
[186/193]  2265ms DrawText_DrawPosText
[187/193]  9163ms PathOpsRectsThreadedTest
[188/193]  5540ms GLPrograms
[189/193]     0ms GLInterfaceValidation
[190/193]     2ms DeferredCanvas
[191/193]     1ms ClipCache
[192/193]    30ms BlurMaskFilter
[193/193] 10396ms PathOpsOpCubicsThreadedTest
Finished 193 tests, 0 failures, 0 skipped.  (622610 internal tests)

BUG=
R=halcanary@google.com, mtklein@google.com, bungeman@google.com

Author: mtklein@google.com

Review URL: https://codereview.chromium.org/109513002

git-svn-id: http://skia.googlecode.com/svn/trunk@12860 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/tests/skia_test.cpp b/tests/skia_test.cpp
index a1d4bf7..26a7701 100644
--- a/tests/skia_test.cpp
+++ b/tests/skia_test.cpp
@@ -13,6 +13,7 @@
 #include "SkThreadPool.h"
 #include "SkTime.h"
 #include "Test.h"
+#include "OverwriteLine.h"
 
 #if SK_SUPPORT_GPU
 #include "GrContext.h"
@@ -20,105 +21,6 @@
 
 using namespace skiatest;
 
-// need to explicitly declare this, or we get some weird infinite loop llist
-template TestRegistry* TestRegistry::gHead;
-
-class Iter {
-public:
-    Iter(Reporter* r) : fReporter(r) {
-        r->ref();
-        this->reset();
-    }
-
-    void reset() {
-        fReg = TestRegistry::Head();
-    }
-
-    ~Iter() {
-        fReporter->unref();
-    }
-
-    Test* next() {
-        if (fReg) {
-            TestRegistry::Factory fact = fReg->factory();
-            fReg = fReg->next();
-            Test* test = fact(NULL);
-            test->setReporter(fReporter);
-            return test;
-        }
-        return NULL;
-    }
-
-private:
-    Reporter* fReporter;
-    const TestRegistry* fReg;
-};
-
-class DebugfReporter : public Reporter {
-public:
-    DebugfReporter(bool allowExtendedTest, bool allowThreaded, bool verbose)
-        : fNextIndex(0)
-        , fPending(0)
-        , fTotal(0)
-        , fAllowExtendedTest(allowExtendedTest)
-        , fAllowThreaded(allowThreaded)
-        , fVerbose(verbose) {
-    }
-
-    void setTotal(int total) {
-        fTotal = total;
-    }
-
-    virtual bool allowExtendedTest() const SK_OVERRIDE {
-        return fAllowExtendedTest;
-    }
-
-    virtual bool allowThreaded() const SK_OVERRIDE {
-        return fAllowThreaded;
-    }
-
-    virtual bool verbose() const SK_OVERRIDE {
-        return fVerbose;
-    }
-
-protected:
-    virtual void onStart(Test* test) {
-        SkAutoMutexAcquire lock(fStartEndMutex);
-        fNextIndex++;
-        fPending++;
-        SkDebugf("[%3d/%3d] (%d) %s\n", fNextIndex, fTotal, fPending, test->getName());
-    }
-
-    virtual void onReportFailed(const SkString& desc) {
-        SkDebugf("\tFAILED: %s\n", desc.c_str());
-    }
-
-    virtual void onEnd(Test* test) {
-        SkAutoMutexAcquire lock(fStartEndMutex);
-        if (!test->passed()) {
-            SkDebugf("---- %s FAILED\n", test->getName());
-        }
-
-        fPending--;
-        if (fNextIndex == fTotal) {
-            // Just waiting on straggler tests.  Shame them by printing their name and runtime.
-            SkDebugf("          (%d) %5.1fs %s\n",
-                     fPending, test->elapsedMs() / 1e3, test->getName());
-        }
-    }
-
-private:
-    SkMutex fStartEndMutex;  // Guards fNextIndex and fPending.
-    int32_t fNextIndex;
-    int32_t fPending;
-
-    // Once the tests get going, these are logically const.
-    int fTotal;
-    bool fAllowExtendedTest;
-    bool fAllowThreaded;
-    bool fVerbose;
-};
-
 DEFINE_string2(match, m, NULL, "[~][^]substring[$] [...] of test name to run.\n" \
                                "Multiple matches may be separated by spaces.\n" \
                                "~ causes a matching test to always be skipped\n" \
@@ -135,6 +37,63 @@
 DEFINE_int32(threads, SkThreadPool::kThreadPerCore,
              "Run threadsafe tests on a threadpool with this many threads.");
 
+// need to explicitly declare this, or we get some weird infinite loop llist
+template TestRegistry* TestRegistry::gHead;
+
+class Iter {
+public:
+    Iter() { this->reset(); }
+    void reset() { fReg = TestRegistry::Head(); }
+
+    Test* next(Reporter* r) {
+        if (fReg) {
+            TestRegistry::Factory fact = fReg->factory();
+            fReg = fReg->next();
+            Test* test = fact(NULL);
+            test->setReporter(r);
+            return test;
+        }
+        return NULL;
+    }
+
+private:
+    const TestRegistry* fReg;
+};
+
+class DebugfReporter : public Reporter {
+public:
+    explicit DebugfReporter(int total) : fDone(0), fTotal(total) {}
+
+    virtual bool allowExtendedTest() const SK_OVERRIDE { return FLAGS_extendedTest; }
+    virtual bool allowThreaded()     const SK_OVERRIDE { return !FLAGS_single; }
+    virtual bool verbose()           const SK_OVERRIDE { return FLAGS_verbose; }
+
+protected:
+    virtual void onReportFailed(const SkString& desc) SK_OVERRIDE {
+        SkDebugf("\nFAILED: %s", desc.c_str());
+    }
+
+    virtual void onEnd(Test* test) SK_OVERRIDE {
+        const int done = 1 + sk_atomic_inc(&fDone);
+
+        if (!test->passed()) {
+            SkDebugf("\n---- %s FAILED", test->getName());
+        }
+
+        SkString prefix(kSkOverwriteLine);
+        SkString time;
+        if (FLAGS_verbose) {
+            prefix.printf("\n");
+            time.printf("%5dms ", test->elapsedMs());
+        }
+        SkDebugf("%s[%3d/%3d] %s%s", prefix.c_str(), done, fTotal, time.c_str(), test->getName());
+    }
+
+private:
+    int32_t fDone;  // atomic
+    const int fTotal;
+};
+
 SkString Test::GetTmpDir() {
     const char* tmpDir = FLAGS_tmpDir.isEmpty() ? NULL : FLAGS_tmpDir[0];
     return SkString(tmpDir);
@@ -197,18 +156,17 @@
         header.append(" SK_RELEASE");
 #endif
         header.appendf(" skia_arch_width=%d", (int)sizeof(void*) * 8);
-        SkDebugf("%s\n", header.c_str());
+        SkDebugf(header.c_str());
     }
 
-    DebugfReporter reporter(FLAGS_extendedTest, !FLAGS_single, FLAGS_verbose);
-    Iter iter(&reporter);
 
     // Count tests first.
     int total = 0;
     int toRun = 0;
     Test* test;
 
-    while ((test = iter.next()) != NULL) {
+    Iter iter;
+    while ((test = iter.next(NULL/*reporter not needed*/)) != NULL) {
         SkAutoTDelete<Test> owned(test);
 
         if(!SkCommandLineFlags::ShouldSkip(FLAGS_match, test->getName())) {
@@ -216,7 +174,6 @@
         }
         total++;
     }
-    reporter.setTotal(toRun);
 
     // Now run them.
     iter.reset();
@@ -225,8 +182,10 @@
 
     SkThreadPool threadpool(FLAGS_threads);
     SkTArray<Test*> unsafeTests;  // Always passes ownership to an SkTestRunnable
+
+    DebugfReporter reporter(toRun);
     for (int i = 0; i < total; i++) {
-        SkAutoTDelete<Test> test(iter.next());
+        SkAutoTDelete<Test> test(iter.next(&reporter));
         if (SkCommandLineFlags::ShouldSkip(FLAGS_match, test->getName())) {
             ++skipCount;
         } else if (!test->isThreadsafe()) {
@@ -244,15 +203,14 @@
     // Block until threaded tests finish.
     threadpool.wait();
 
-    SkDebugf("Finished %d tests, %d failures, %d skipped.\n",
-             toRun, failCount, skipCount);
-    const int testCount = reporter.countTests();
-    if (FLAGS_verbose && testCount > 0) {
-        SkDebugf("Ran %d Internal tests.\n", testCount);
+    if (FLAGS_verbose) {
+        SkDebugf("\nFinished %d tests, %d failures, %d skipped. (%d internal tests)",
+                 toRun, failCount, skipCount, reporter.countTests());
     }
     SkGraphics::Term();
     GpuTest::DestroyContexts();
 
+    SkDebugf("\n");
     return (failCount == 0) ? 0 : 1;
 }