skia_test.cpp revision 5a6324e3140eb16cd5255867eae02a2c88d54271
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)
66        : fIndex(0)
67        , fTotal(0)
68        , fAllowExtendedTest(allowExtendedTest) {
69    }
70
71    void setIndexOfTotal(int index, int total) {
72        fIndex = index;
73        fTotal = total;
74    }
75
76    virtual bool allowExtendedTest() const {
77        return fAllowExtendedTest;
78    }
79
80protected:
81    virtual void onStart(Test* test) {
82        SkDebugf("[%d/%d] %s...\n", fIndex+1, fTotal, test->getName());
83    }
84    virtual void onReport(const char desc[], Reporter::Result result) {
85        SkDebugf("\t%s: %s\n", result2string(result), desc);
86    }
87    virtual void onEnd(Test*) {
88        if (!this->getCurrSuccess()) {
89            SkDebugf("---- FAILED\n");
90        }
91    }
92private:
93    int fIndex, fTotal;
94    bool fAllowExtendedTest;
95};
96
97static const char* make_canonical_dir_path(const char* path, SkString* storage) {
98    if (path) {
99        // clean it up so it always has a trailing searator
100        size_t len = strlen(path);
101        if (0 == len) {
102            path = NULL;
103        } else if (SkPATH_SEPARATOR != path[len - 1]) {
104            // resize to len + 1, to make room for searator
105            storage->set(path, len + 1);
106            storage->writable_str()[len] = SkPATH_SEPARATOR;
107            path = storage->c_str();
108        }
109    }
110    return path;
111}
112
113static SkString gTmpDir;
114
115const SkString& Test::GetTmpDir() {
116    return gTmpDir;
117}
118
119static SkString gResourcePath;
120
121const SkString& Test::GetResourcePath() {
122    return gResourcePath;
123}
124
125DEFINE_string2(match, m, NULL, "substring of test name to run.");
126DEFINE_string2(tmpDir, t, NULL, "tmp directory for tests to use.");
127DEFINE_string2(resourcePath, i, NULL, "directory for test resources.");
128DEFINE_bool2(extendedTest, x, false, "run extended tests for pathOps.");
129DEFINE_bool2(verbose, v, false, "enable verbose output.");
130
131int tool_main(int argc, char** argv);
132int tool_main(int argc, char** argv) {
133    SkCommandLineFlags::SetUsage("");
134    SkCommandLineFlags::Parse(argc, argv);
135
136    if (!FLAGS_tmpDir.isEmpty()) {
137        make_canonical_dir_path(FLAGS_tmpDir[0], &gTmpDir);
138    }
139    if (!FLAGS_resourcePath.isEmpty()) {
140        make_canonical_dir_path(FLAGS_resourcePath[0], &gResourcePath);
141    }
142
143#if SK_ENABLE_INST_COUNT
144    gPrintInstCount = true;
145#endif
146
147    SkGraphics::Init();
148
149    {
150        SkString header("Skia UnitTests:");
151        if (!FLAGS_match.isEmpty()) {
152            header.appendf(" --match %s", FLAGS_match[0]);
153        }
154        if (!gTmpDir.isEmpty()) {
155            header.appendf(" --tmpDir %s", gTmpDir.c_str());
156        }
157        if (!gResourcePath.isEmpty()) {
158            header.appendf(" --resourcePath %s", gResourcePath.c_str());
159        }
160#ifdef SK_DEBUG
161        header.append(" SK_DEBUG");
162#else
163        header.append(" SK_RELEASE");
164#endif
165#ifdef SK_SCALAR_IS_FIXED
166        header.append(" SK_SCALAR_IS_FIXED");
167#else
168        header.append(" SK_SCALAR_IS_FLOAT");
169#endif
170        SkDebugf("%s\n", header.c_str());
171    }
172
173    DebugfReporter reporter(FLAGS_extendedTest);
174    Iter iter(&reporter);
175    Test* test;
176
177    const int count = Iter::Count();
178    int index = 0;
179    int failCount = 0;
180    int skipCount = 0;
181    while ((test = iter.next()) != NULL) {
182        reporter.setIndexOfTotal(index, count);
183        if (!FLAGS_match.isEmpty() && !strstr(test->getName(), FLAGS_match[0])) {
184            ++skipCount;
185        } else {
186            if (!test->run()) {
187                ++failCount;
188            }
189        }
190        SkDELETE(test);
191        index += 1;
192    }
193
194    SkDebugf("Finished %d tests, %d failures, %d skipped.\n",
195             count, failCount, skipCount);
196    int testCount = reporter.countTests();
197    if (FLAGS_verbose && testCount > 0) {
198        SkDebugf("Ran %d Internal tests.\n", testCount);
199    }
200#if SK_SUPPORT_GPU
201
202#if GR_CACHE_STATS
203    GrContext *gr = GpuTest::GetContext();
204
205    gr->printCacheStats();
206#endif
207
208#endif
209
210    SkGraphics::Term();
211    GpuTest::DestroyContexts();
212
213    return (failCount == 0) ? 0 : 1;
214}
215
216#if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL)
217int main(int argc, char * const argv[]) {
218    return tool_main(argc, (char**) argv);
219}
220#endif
221