blob: 59a0c1c697e191ba59c8d3436db0079e517ec4b1 [file] [log] [blame]
epoger@google.com37269602013-01-19 04:21:27 +00001/*
2 * Copyright 2013 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#ifndef gm_expectations_DEFINED
8#define gm_expectations_DEFINED
9
10#include "gm.h"
11#include "SkBitmapChecksummer.h"
12#include "SkImageDecoder.h"
13#include "SkOSFile.h"
14#include "SkRefCnt.h"
15#include "SkTArray.h"
16
17#ifdef SK_BUILD_FOR_WIN
18 // json includes xlocale which generates warning 4530 because we're compiling without
19 // exceptions; see https://code.google.com/p/skia/issues/detail?id=1067
20 #pragma warning(push)
21 #pragma warning(disable : 4530)
22#endif
23#include "json/value.h"
24#ifdef SK_BUILD_FOR_WIN
25 #pragma warning(pop)
26#endif
27
28namespace skiagm {
29
30 // The actual type we use to represent a checksum is hidden in here.
31 typedef Json::UInt64 Checksum;
32 static inline Json::Value asJsonValue(Checksum checksum) {
33 return checksum;
34 }
35
36 static SkString make_filename(const char path[],
37 const char renderModeDescriptor[],
38 const char *name,
39 const char suffix[]) {
40 SkString filename(path);
41 if (filename.endsWith(SkPATH_SEPARATOR)) {
42 filename.remove(filename.size() - 1, 1);
43 }
44 filename.appendf("%c%s%s.%s", SkPATH_SEPARATOR,
45 name, renderModeDescriptor, suffix);
46 return filename;
47 }
48
49 /**
50 * Test expectations (allowed image checksums, etc.)
51 */
52 class Expectations {
53 public:
54 /**
55 * No expectations at all.
56 *
57 * We set ignoreFailure to false by default, but it doesn't really
58 * matter... the result will always be "no-comparison" anyway.
59 */
60 Expectations(bool ignoreFailure=false) {
61 fIgnoreFailure = ignoreFailure;
62 }
63
64 /**
65 * Allow exactly one checksum (appropriate for the case when we
66 * are comparing against a single PNG file).
67 *
68 * By default, DO NOT ignore failures.
69 */
70 Expectations(Checksum singleChecksum, bool ignoreFailure=false) {
71 fIgnoreFailure = ignoreFailure;
72 fAllowedChecksums.push_back() = singleChecksum;
73 }
74
75 /**
76 * Returns true iff we want to ignore failed expectations.
77 */
78 bool ignoreFailure() const { return this->fIgnoreFailure; }
79
80 /**
81 * Returns true iff there are no allowed checksums.
82 */
83 bool empty() const { return this->fAllowedChecksums.empty(); }
84
85 /**
86 * Returns true iff actualChecksum matches any allowedChecksum,
87 * regardless of fIgnoreFailure. (The caller can check
88 * that separately.)
89 */
90 bool match(Checksum actualChecksum) const {
91 for (int i=0; i < this->fAllowedChecksums.count(); i++) {
92 Checksum allowedChecksum = this->fAllowedChecksums[i];
93 if (allowedChecksum == actualChecksum) {
94 return true;
95 }
96 }
97 return false;
98 }
99
100 /**
101 * Return a JSON representation of the allowed checksums.
102 * This does NOT include any information about whether to
103 * ignore failures.
104 */
105 Json::Value allowedChecksumsAsJson() const {
106 Json::Value allowedChecksumArray;
107 if (!this->fAllowedChecksums.empty()) {
108 for (int i=0; i < this->fAllowedChecksums.count(); i++) {
109 Checksum allowedChecksum = this->fAllowedChecksums[i];
110 allowedChecksumArray.append(asJsonValue(allowedChecksum));
111 }
112 }
113 return allowedChecksumArray;
114 }
115
116 private:
117 SkTArray<Checksum> fAllowedChecksums;
118 bool fIgnoreFailure;
119 };
120
121 /**
122 * Abstract source of Expectations objects for individual tests.
123 */
124 class ExpectationsSource : public SkRefCnt {
125 public:
126 virtual Expectations get(const char *testName) = 0;
127 };
128
129 /**
130 * Return Expectations based on individual image files on disk.
131 */
132 class IndividualImageExpectationsSource : public ExpectationsSource {
133 public:
134 /**
135 * Create an ExpectationsSource that will return Expectations based on
136 * image files found within rootDir.
137 *
138 * rootDir: directory under which to look for image files
139 * (this string will be copied to storage within this object)
140 * notifyOfMissingFiles: whether to log a message to stderr if an image
141 * file cannot be found
142 */
143 IndividualImageExpectationsSource(const char *rootDir,
144 bool notifyOfMissingFiles) :
145 fRootDir(rootDir), fNotifyOfMissingFiles(notifyOfMissingFiles) {}
146
147 Expectations get(const char *testName) SK_OVERRIDE {
148 SkString path = make_filename(fRootDir.c_str(), "", testName,
149 "png");
150 SkBitmap referenceBitmap;
151 bool decodedReferenceBitmap =
152 SkImageDecoder::DecodeFile(path.c_str(), &referenceBitmap,
153 SkBitmap::kARGB_8888_Config,
154 SkImageDecoder::kDecodePixels_Mode,
155 NULL);
156 if (decodedReferenceBitmap) {
157 Checksum checksum = SkBitmapChecksummer::Compute64(
158 referenceBitmap);
159 return Expectations(checksum);
160 } else {
161 if (fNotifyOfMissingFiles) {
162 fprintf(stderr, "FAILED to read %s\n", path.c_str());
163 }
164 return Expectations();
165 }
166 }
167
168 private:
169 const SkString fRootDir;
170 const bool fNotifyOfMissingFiles;
171 };
172
173}
174#endif