ok: add basic unit test support

Plenty TODO remaining.

This can actually kind of run without a test reporter or GrContext:
    $ out/ok test
    784 ok, 56 crashed
    ... lots of stack traces ...
Most tests don't use the reporter unless they're going to fail.

Change-Id: I7333e2c63ade5e671ebf60022d19390f1fc1c93a
Reviewed-on: https://skia-review.googlesource.com/10201
Commit-Queue: Mike Klein <mtklein@chromium.org>
Reviewed-by: Brian Salomon <bsalomon@google.com>
diff --git a/BUILD.gn b/BUILD.gn
index 41694d3..4999d74 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -969,12 +969,14 @@
     deps = [
       ":experimental_svg_model",
       ":flags",
-      ":gpu_tool_utils",
       ":skia",
       ":tool_utils",
       "//third_party/libpng",
       "//third_party/zlib",
     ]
+    public_deps = [
+      ":gpu_tool_utils",  # Test.h #includes headers from this target.
+    ]
   }
 
   import("gn/bench.gni")
@@ -1155,11 +1157,13 @@
       "tools/ok.cpp",
       "tools/ok_dsts.cpp",
       "tools/ok_srcs.cpp",
+      "tools/ok_test.cpp",
       "tools/ok_vias.cpp",
     ]
     deps = [
       ":gm",
       ":skia",
+      ":tests",
     ]
   }
 
diff --git a/tools/ok.cpp b/tools/ok.cpp
index a922f87..9022857 100644
--- a/tools/ok.cpp
+++ b/tools/ok.cpp
@@ -267,7 +267,17 @@
             }
         }
     }
-    if (!stream || !dst_factory) { return help(); }
+    if (!stream) { return help(); }
+    if (!dst_factory) {
+        // A default Dst that's enough for unit tests and not much else.
+        dst_factory = []{
+            struct : Dst {
+                bool draw(Src* src) override { return src->draw(nullptr); }
+                sk_sp<SkImage> image() override { return nullptr; }
+            } dst;
+            return move_unique(dst);
+        };
+    }
 
     std::unique_ptr<Engine> engine;
     if (jobs == 0) { engine.reset(new SerialEngine);                            }
diff --git a/tools/ok_test.cpp b/tools/ok_test.cpp
new file mode 100644
index 0000000..12f3c0f
--- /dev/null
+++ b/tools/ok_test.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "ok.h"
+#include "Test.h"
+
+struct TestStream : Stream {
+    const skiatest::TestRegistry* registry = skiatest::TestRegistry::Head();
+
+    static std::unique_ptr<Stream> Create(Options) {
+        TestStream stream;
+        return move_unique(stream);
+    }
+
+    struct TestSrc : Src {
+        skiatest::Test test {"", false, nullptr};
+
+        std::string name() override { return test.name; }
+        SkISize     size() override { return {0,0}; }
+
+        bool draw(SkCanvas*) override {
+            // TODO(mtklein): reporter, GrContext, return false on failure.
+            test.proc(nullptr, nullptr);
+            return true;
+        }
+    };
+
+    std::unique_ptr<Src> next() override {
+        if (!registry) {
+            return nullptr;
+        }
+        TestSrc src;
+        src.test = registry->factory();
+        registry = registry->next();
+        return move_unique(src);
+    }
+};
+static Register test{"test", TestStream::Create};
+
+// Hey, now why were these defined in DM.cpp?  That's kind of weird.
+namespace skiatest {
+#if SK_SUPPORT_GPU
+    bool IsGLContextType(sk_gpu_test::GrContextFactory::ContextType type) {
+        return kOpenGL_GrBackend == sk_gpu_test::GrContextFactory::ContextTypeBackend(type);
+    }
+    bool IsVulkanContextType(sk_gpu_test::GrContextFactory::ContextType type) {
+        return kVulkan_GrBackend == sk_gpu_test::GrContextFactory::ContextTypeBackend(type);
+    }
+    bool IsRenderingGLContextType(sk_gpu_test::GrContextFactory::ContextType type) {
+        return IsGLContextType(type) && sk_gpu_test::GrContextFactory::IsRenderingContext(type);
+    }
+    bool IsNullGLContextType(sk_gpu_test::GrContextFactory::ContextType type) {
+        return type == sk_gpu_test::GrContextFactory::kNullGL_ContextType;
+    }
+#else
+    bool IsGLContextType         (int) { return false; }
+    bool IsVulkanContextType     (int) { return false; }
+    bool IsRenderingGLContextType(int) { return false; }
+    bool IsNullGLContextType     (int) { return false; }
+#endif
+
+    void RunWithGPUTestContexts(GrContextTestFn* test, GrContextTypeFilterFn* contextTypeFilter,
+                                Reporter* reporter, sk_gpu_test::GrContextFactory* factory) {
+        // TODO(bsalomon)
+    }
+}