skia_test.cpp revision 16cfe40276bfb0a4d98c9ad995b8e5b134a49b19
1/*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkCommandLineFlags.h"
9#include "SkGraphics.h"
10#include "Test.h"
11#include "SkOSFile.h"
12
13#if SK_SUPPORT_GPU
14#include "GrContext.h"
15#endif
16
17using namespace skiatest;
18
19// need to explicitly declare this, or we get some weird infinite loop llist
20template TestRegistry* TestRegistry::gHead;
21
22class Iter {
23public:
24    Iter(Reporter* r) : fReporter(r) {
25        r->ref();
26        fReg = TestRegistry::Head();
27    }
28
29    ~Iter() {
30        fReporter->unref();
31    }
32
33    Test* next() {
34        if (fReg) {
35            TestRegistry::Factory fact = fReg->factory();
36            fReg = fReg->next();
37            Test* test = fact(NULL);
38            test->setReporter(fReporter);
39            return test;
40        }
41        return NULL;
42    }
43
44    static int Count() {
45        const TestRegistry* reg = TestRegistry::Head();
46        int count = 0;
47        while (reg) {
48            count += 1;
49            reg = reg->next();
50        }
51        return count;
52    }
53
54private:
55    Reporter* fReporter;
56    const TestRegistry* fReg;
57};
58
59static const char* result2string(Reporter::Result result) {
60    return result == Reporter::kPassed ? "passed" : "FAILED";
61}
62
63class DebugfReporter : public Reporter {
64public:
65    DebugfReporter(bool allowExtendedTest, bool allowThreaded)
66        : fIndex(0)
67        , fTotal(0)
68        , fAllowExtendedTest(allowExtendedTest)
69        , fAllowThreaded(allowThreaded) {
70    }
71
72    void setIndexOfTotal(int index, int total) {
73        fIndex = index;
74        fTotal = total;
75    }
76
77    virtual bool allowExtendedTest() const {
78        return fAllowExtendedTest;
79    }
80
81    virtual bool allowThreaded() const {
82        return fAllowThreaded;
83    }
84
85protected:
86    virtual void onStart(Test* test) {
87        SkDebugf("[%d/%d] %s...\n", fIndex+1, fTotal, test->getName());
88    }
89    virtual void onReport(const char desc[], Reporter::Result result) {
90        SkDebugf("\t%s: %s\n", result2string(result), desc);
91    }
92    virtual void onEnd(Test*) {
93        if (!this->getCurrSuccess()) {
94            SkDebugf("---- FAILED\n");
95        }
96    }
97private:
98    int fIndex, fTotal;
99    bool fAllowExtendedTest;
100    bool fAllowThreaded;
101};
102
103static const char* make_canonical_dir_path(const char* path, SkString* storage) {
104    if (path) {
105        // clean it up so it always has a trailing searator
106        size_t len = strlen(path);
107        if (0 == len) {
108            path = NULL;
109        } else if (SkPATH_SEPARATOR != path[len - 1]) {
110            // resize to len + 1, to make room for searator
111            storage->set(path, len + 1);
112            storage->writable_str()[len] = SkPATH_SEPARATOR;
113            path = storage->c_str();
114        }
115    }
116    return path;
117}
118
119static SkString gTmpDir;
120
121const SkString& Test::GetTmpDir() {
122    return gTmpDir;
123}
124
125static SkString gResourcePath;
126
127const SkString& Test::GetResourcePath() {
128    return gResourcePath;
129}
130
131DEFINE_string2(match, m, NULL, "substring of test name to run.");
132DEFINE_string2(tmpDir, t, NULL, "tmp directory for tests to use.");
133DEFINE_string2(resourcePath, i, NULL, "directory for test resources.");
134DEFINE_bool2(extendedTest, x, false, "run extended tests for pathOps.");
135DEFINE_bool2(threaded, z, false, "allow tests to use multiple threads.");
136DEFINE_bool2(verbose, v, false, "enable verbose output.");
137
138int tool_main(int argc, char** argv);
139int tool_main(int argc, char** argv) {
140    SkCommandLineFlags::SetUsage("");
141    SkCommandLineFlags::Parse(argc, argv);
142
143    if (!FLAGS_tmpDir.isEmpty()) {
144        make_canonical_dir_path(FLAGS_tmpDir[0], &gTmpDir);
145    }
146    if (!FLAGS_resourcePath.isEmpty()) {
147        make_canonical_dir_path(FLAGS_resourcePath[0], &gResourcePath);
148    }
149
150#if SK_ENABLE_INST_COUNT
151    gPrintInstCount = true;
152#endif
153
154    SkGraphics::Init();
155
156    {
157        SkString header("Skia UnitTests:");
158        if (!FLAGS_match.isEmpty()) {
159            header.appendf(" --match %s", FLAGS_match[0]);
160        }
161        if (!gTmpDir.isEmpty()) {
162            header.appendf(" --tmpDir %s", gTmpDir.c_str());
163        }
164        if (!gResourcePath.isEmpty()) {
165            header.appendf(" --resourcePath %s", gResourcePath.c_str());
166        }
167#ifdef SK_DEBUG
168        header.append(" SK_DEBUG");
169#else
170        header.append(" SK_RELEASE");
171#endif
172#ifdef SK_SCALAR_IS_FIXED
173        header.append(" SK_SCALAR_IS_FIXED");
174#else
175        header.append(" SK_SCALAR_IS_FLOAT");
176#endif
177        SkDebugf("%s\n", header.c_str());
178    }
179
180    DebugfReporter reporter(FLAGS_extendedTest, FLAGS_threaded);
181    Iter iter(&reporter);
182    Test* test;
183
184    const int count = Iter::Count();
185    int index = 0;
186    int failCount = 0;
187    int skipCount = 0;
188    while ((test = iter.next()) != NULL) {
189        reporter.setIndexOfTotal(index, count);
190        if (!FLAGS_match.isEmpty() && !strstr(test->getName(), FLAGS_match[0])) {
191            ++skipCount;
192        } else {
193            if (!test->run()) {
194                ++failCount;
195            }
196        }
197        SkDELETE(test);
198        index += 1;
199    }
200
201    SkDebugf("Finished %d tests, %d failures, %d skipped.\n",
202             count, failCount, skipCount);
203    int testCount = reporter.countTests();
204    if (FLAGS_verbose && testCount > 0) {
205        SkDebugf("Ran %d Internal tests.\n", testCount);
206    }
207#if SK_SUPPORT_GPU
208
209#if GR_CACHE_STATS
210    GrContext *gr = GpuTest::GetContext();
211
212    gr->printCacheStats();
213#endif
214
215#endif
216
217    SkGraphics::Term();
218    GpuTest::DestroyContexts();
219
220    return (failCount == 0) ? 0 : 1;
221}
222
223#if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL)
224int main(int argc, char * const argv[]) {
225    return tool_main(argc, (char**) argv);
226}
227#endif
228