blob: 0af18c157084a3146e08e23bbb7e99e1300396a6 [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"
epoger@google.com84a18022013-02-01 20:39:15 +000011#include "SkBitmap.h"
epoger@google.com908f5832013-04-12 02:23:55 +000012#include "SkBitmapHasher.h"
epoger@google.comd271d242013-02-13 18:14:48 +000013#include "SkData.h"
epoger@google.com37269602013-01-19 04:21:27 +000014#include "SkOSFile.h"
15#include "SkRefCnt.h"
epoger@google.comd271d242013-02-13 18:14:48 +000016#include "SkStream.h"
epoger@google.com37269602013-01-19 04:21:27 +000017#include "SkTArray.h"
18
19#ifdef SK_BUILD_FOR_WIN
20 // json includes xlocale which generates warning 4530 because we're compiling without
21 // exceptions; see https://code.google.com/p/skia/issues/detail?id=1067
22 #pragma warning(push)
23 #pragma warning(disable : 4530)
24#endif
epoger@google.comd271d242013-02-13 18:14:48 +000025#include "json/reader.h"
epoger@google.com37269602013-01-19 04:21:27 +000026#include "json/value.h"
27#ifdef SK_BUILD_FOR_WIN
28 #pragma warning(pop)
29#endif
30
31namespace skiagm {
32
33 // The actual type we use to represent a checksum is hidden in here.
34 typedef Json::UInt64 Checksum;
35 static inline Json::Value asJsonValue(Checksum checksum) {
36 return checksum;
37 }
epoger@google.comd271d242013-02-13 18:14:48 +000038 static inline Checksum asChecksum(Json::Value jsonValue) {
39 return jsonValue.asUInt64();
40 }
epoger@google.com37269602013-01-19 04:21:27 +000041
scroggo@google.com6843bdb2013-05-08 19:14:23 +000042 void gm_fprintf(FILE *stream, const char format[], ...);
epoger@google.com5efdd0c2013-03-13 14:18:40 +000043
scroggo@google.com6843bdb2013-05-08 19:14:23 +000044 SkString make_filename(const char path[],
45 const char renderModeDescriptor[],
46 const char *name,
47 const char suffix[]);
epoger@google.com37269602013-01-19 04:21:27 +000048
epoger@google.com76c913d2013-04-26 15:06:44 +000049 Json::Value ActualResultAsJsonValue(const SkHashDigest& result);
50
51 Json::Value CreateJsonTree(Json::Value expectedResults,
52 Json::Value actualResultsFailed,
53 Json::Value actualResultsFailureIgnored,
54 Json::Value actualResultsNoComparison,
55 Json::Value actualResultsSucceeded);
56
epoger@google.com37269602013-01-19 04:21:27 +000057 /**
58 * Test expectations (allowed image checksums, etc.)
59 */
60 class Expectations {
61 public:
62 /**
63 * No expectations at all.
epoger@google.com37269602013-01-19 04:21:27 +000064 */
epoger@google.com76c913d2013-04-26 15:06:44 +000065 Expectations(bool ignoreFailure=kDefaultIgnoreFailure);
epoger@google.com37269602013-01-19 04:21:27 +000066
67 /**
epoger@google.com84a18022013-02-01 20:39:15 +000068 * Expect exactly one image (appropriate for the case when we
epoger@google.com37269602013-01-19 04:21:27 +000069 * are comparing against a single PNG file).
epoger@google.com37269602013-01-19 04:21:27 +000070 */
epoger@google.com76c913d2013-04-26 15:06:44 +000071 Expectations(const SkBitmap& bitmap, bool ignoreFailure=kDefaultIgnoreFailure);
epoger@google.com37269602013-01-19 04:21:27 +000072
73 /**
epoger@google.comd271d242013-02-13 18:14:48 +000074 * Create Expectations from a JSON element as found within the
75 * kJsonKey_ExpectedResults section.
76 *
77 * It's fine if the jsonElement is null or empty; in that case, we just
78 * don't have any expectations.
79 */
epoger@google.com76c913d2013-04-26 15:06:44 +000080 Expectations(Json::Value jsonElement);
epoger@google.comd271d242013-02-13 18:14:48 +000081
82 /**
epoger@google.com37269602013-01-19 04:21:27 +000083 * Returns true iff we want to ignore failed expectations.
84 */
85 bool ignoreFailure() const { return this->fIgnoreFailure; }
86
87 /**
88 * Returns true iff there are no allowed checksums.
89 */
epoger@google.com366a7702013-05-07 15:51:54 +000090 bool empty() const { return this->fAllowedBitmapChecksums.empty(); }
epoger@google.com37269602013-01-19 04:21:27 +000091
92 /**
93 * Returns true iff actualChecksum matches any allowedChecksum,
94 * regardless of fIgnoreFailure. (The caller can check
95 * that separately.)
96 */
epoger@google.com76c913d2013-04-26 15:06:44 +000097 bool match(Checksum actualChecksum) const;
epoger@google.com37269602013-01-19 04:21:27 +000098
99 /**
epoger@google.com84a18022013-02-01 20:39:15 +0000100 * If this Expectation is based on a single SkBitmap, return a
101 * pointer to that SkBitmap. Otherwise (if the Expectation is
102 * empty, or if it was based on a list of checksums rather
103 * than a single bitmap), returns NULL.
104 */
105 const SkBitmap *asBitmap() const {
106 return (SkBitmap::kNo_Config == fBitmap.config()) ? NULL : &fBitmap;
107 }
108
109 /**
epoger@google.com76c913d2013-04-26 15:06:44 +0000110 * Return a JSON representation of the expectations.
epoger@google.com37269602013-01-19 04:21:27 +0000111 */
epoger@google.com76c913d2013-04-26 15:06:44 +0000112 Json::Value asJsonValue() const;
epoger@google.com37269602013-01-19 04:21:27 +0000113
114 private:
epoger@google.comd271d242013-02-13 18:14:48 +0000115 const static bool kDefaultIgnoreFailure = false;
116
epoger@google.com366a7702013-05-07 15:51:54 +0000117 SkTArray<Checksum> fAllowedBitmapChecksums;
epoger@google.com37269602013-01-19 04:21:27 +0000118 bool fIgnoreFailure;
epoger@google.com84a18022013-02-01 20:39:15 +0000119 SkBitmap fBitmap;
epoger@google.com37269602013-01-19 04:21:27 +0000120 };
121
122 /**
123 * Abstract source of Expectations objects for individual tests.
124 */
125 class ExpectationsSource : public SkRefCnt {
126 public:
127 virtual Expectations get(const char *testName) = 0;
128 };
129
130 /**
131 * Return Expectations based on individual image files on disk.
132 */
133 class IndividualImageExpectationsSource : public ExpectationsSource {
134 public:
135 /**
136 * Create an ExpectationsSource that will return Expectations based on
137 * image files found within rootDir.
138 *
139 * rootDir: directory under which to look for image files
140 * (this string will be copied to storage within this object)
epoger@google.com37269602013-01-19 04:21:27 +0000141 */
epoger@google.comb0f8b432013-04-10 18:46:25 +0000142 IndividualImageExpectationsSource(const char *rootDir) : fRootDir(rootDir) {}
epoger@google.com37269602013-01-19 04:21:27 +0000143
epoger@google.com76c913d2013-04-26 15:06:44 +0000144 Expectations get(const char *testName) SK_OVERRIDE ;
epoger@google.com37269602013-01-19 04:21:27 +0000145
146 private:
147 const SkString fRootDir;
epoger@google.com37269602013-01-19 04:21:27 +0000148 };
149
epoger@google.comd271d242013-02-13 18:14:48 +0000150 /**
151 * Return Expectations based on JSON summary file.
152 */
153 class JsonExpectationsSource : public ExpectationsSource {
154 public:
155 /**
156 * Create an ExpectationsSource that will return Expectations based on
157 * a JSON file.
158 *
159 * jsonPath: path to JSON file to read
160 */
epoger@google.com76c913d2013-04-26 15:06:44 +0000161 JsonExpectationsSource(const char *jsonPath);
epoger@google.comd271d242013-02-13 18:14:48 +0000162
epoger@google.com76c913d2013-04-26 15:06:44 +0000163 Expectations get(const char *testName) SK_OVERRIDE;
epoger@google.comd271d242013-02-13 18:14:48 +0000164
165 private:
166
167 /**
168 * Read as many bytes as possible (up to maxBytes) from the stream into
169 * an SkData object.
170 *
171 * If the returned SkData contains fewer than maxBytes, then EOF has been
172 * reached and no more data would be available from subsequent calls.
173 * (If EOF has already been reached, then this call will return an empty
174 * SkData object immediately.)
175 *
176 * If there are fewer than maxBytes bytes available to read from the
177 * stream, but the stream has not been closed yet, this call will block
178 * until there are enough bytes to read or the stream has been closed.
179 *
180 * It is up to the caller to call unref() on the returned SkData object
181 * once the data is no longer needed, so that the underlying buffer will
182 * be freed. For example:
183 *
184 * {
185 * size_t maxBytes = 256;
186 * SkAutoDataUnref dataRef(readIntoSkData(stream, maxBytes));
187 * if (NULL != dataRef.get()) {
188 * size_t bytesActuallyRead = dataRef.get()->size();
189 * // use the data...
190 * }
191 * }
192 * // underlying buffer has been freed, thanks to auto unref
193 *
194 */
195 // TODO(epoger): Move this, into SkStream.[cpp|h] as attempted in
196 // https://codereview.appspot.com/7300071 ?
scroggo@google.com6843bdb2013-05-08 19:14:23 +0000197 // And maybe ReadFileIntoSkData() also?
198 static SkData* ReadIntoSkData(SkStream &stream, size_t maxBytes);
epoger@google.comd271d242013-02-13 18:14:48 +0000199
200 /**
scroggo@google.com6843bdb2013-05-08 19:14:23 +0000201 * Wrapper around ReadIntoSkData for files: reads the entire file into
epoger@google.comd271d242013-02-13 18:14:48 +0000202 * an SkData object.
203 */
scroggo@google.com6843bdb2013-05-08 19:14:23 +0000204 static SkData* ReadFileIntoSkData(SkFILEStream &stream) {
205 return ReadIntoSkData(stream, stream.getLength());
epoger@google.comd271d242013-02-13 18:14:48 +0000206 }
207
208 /**
209 * Read the file contents from jsonPath and parse them into jsonRoot.
210 *
211 * Returns true if successful.
212 */
scroggo@google.com6843bdb2013-05-08 19:14:23 +0000213 static bool Parse(const char *jsonPath, Json::Value *jsonRoot);
epoger@google.comd271d242013-02-13 18:14:48 +0000214
215 Json::Value fJsonRoot;
216 Json::Value fJsonExpectedResults;
217 };
218
epoger@google.com37269602013-01-19 04:21:27 +0000219}
220#endif