15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Copyright 2014 Google Inc.
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Use of this source code is governed by a BSD-style license that can be
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * found in the LICENSE file.
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#ifndef image_expectations_DEFINED
9d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#define image_expectations_DEFINED
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkBitmap.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkJSONCPP.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkOSFile.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace sk_tools {
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * The digest of an image (either an image we have generated locally, or an image expectation).
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     *
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Currently, this is always a uint64_t hash digest of an SkBitmap.
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     */
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    class ImageDigest {
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    public:
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        /**
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         * Create an ImageDigest of a bitmap.
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         *
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         * Computes the hash of the bitmap lazily, since that is an expensive operation.
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         *
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         * @param bitmap image to get the digest of
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         */
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        explicit ImageDigest(const SkBitmap &bitmap);
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        /**
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         * Create an ImageDigest using a hashType/hashValue pair.
35         *
36         * @param hashType the algorithm used to generate the hash; for now, only
37         *     kJsonValue_Image_ChecksumAlgorithm_Bitmap64bitMD5 is allowed.
38         * @param hashValue the value generated by the hash algorithm for a particular image.
39         */
40        explicit ImageDigest(const SkString &hashType, uint64_t hashValue);
41
42        /**
43         * Returns true iff this and other ImageDigest represent identical images.
44         */
45        bool equals(ImageDigest &other);
46
47        /**
48         * Returns the hash digest type as an SkString.
49         *
50         * For now, this always returns kJsonValue_Image_ChecksumAlgorithm_Bitmap64bitMD5 .
51         */
52        SkString getHashType();
53
54        /**
55         * Returns the hash digest value as a uint64_t.
56         *
57         * Since the hash is computed lazily, this may take some time, and it may modify
58         * some fields on this object.
59         */
60        uint64_t getHashValue();
61
62    private:
63        const SkBitmap fBitmap;
64        uint64_t fHashValue;
65        bool fComputedHashValue;
66    };
67
68    /**
69     * Container that holds a reference to an SkBitmap and its ImageDigest.
70     */
71    class BitmapAndDigest {
72    public:
73        explicit BitmapAndDigest(const SkBitmap &bitmap);
74
75        const SkBitmap *getBitmapPtr() const;
76
77        /**
78         * Returns a pointer to the ImageDigest.
79         *
80         * Since the hash is computed lazily within the ImageDigest object, we cannot mandate
81         * that it be held const.
82         */
83        ImageDigest *getImageDigestPtr();
84    private:
85        const SkBitmap fBitmap;
86        ImageDigest fImageDigest;
87    };
88
89    /**
90     * Expected test result: expected image (if any), and whether we want to ignore failures on
91     * this test or not.
92     *
93     * This is just an ImageDigest (or lack thereof, if there is no expectation) and a boolean
94     * telling us whether to ignore failures.
95     */
96    class Expectation {
97    public:
98        /**
99         * No expectation at all.
100         */
101        explicit Expectation(bool ignoreFailure=kDefaultIgnoreFailure);
102
103        /**
104         * Expect an image, passed as hashType/hashValue.
105         */
106        explicit Expectation(const SkString &hashType, uint64_t hashValue,
107                             bool ignoreFailure=kDefaultIgnoreFailure);
108
109        /**
110         * Expect an image, passed as a bitmap.
111         */
112        explicit Expectation(const SkBitmap& bitmap,
113                             bool ignoreFailure=kDefaultIgnoreFailure);
114
115        /**
116         * Returns true iff we want to ignore failed expectations.
117         */
118        bool ignoreFailure() const;
119
120        /**
121         * Returns true iff there are no allowed results.
122         */
123        bool empty() const;
124
125        /**
126         * Returns true iff we are expecting a particular image, and imageDigest matches it.
127         *
128         * If empty() returns true, this will return false.
129         *
130         * If this expectation DOES contain an image, and imageDigest doesn't match it,
131         * this method will return false regardless of what ignoreFailure() would return.
132         * (The caller can check that separately.)
133         */
134        bool matches(ImageDigest &imageDigest);
135
136    private:
137        static const bool kDefaultIgnoreFailure = false;
138
139        const bool fIsEmpty;
140        const bool fIgnoreFailure;
141        ImageDigest fImageDigest;  // cannot be const, because it computes its hash lazily
142    };
143
144    /**
145     * Collects ImageDigests of actually rendered images, perhaps comparing to expectations.
146     */
147    class ImageResultsAndExpectations {
148    public:
149        /**
150         * Adds expectations from a JSON file, returning true if successful.
151         *
152         * If the file exists but is empty, it succeeds, and there will be no expectations.
153         * If the file does not exist, this will fail.
154         *
155         * Reasoning:
156         * Generating expectations the first time can be a tricky chicken-and-egg
157         * proposition.  "I need actual results to turn into expectations... but the only
158         * way to get actual results is to run the tool, and the tool won't run without
159         * expectations!"
160         * We could make the tool run even if there is no expectations file at all, but it's
161         * better for the tool to fail if the expectations file is not found--that will tell us
162         * quickly if files are not being copied around as they should be.
163         * Creating an empty file is an easy way to break the chicken-and-egg cycle and generate
164         * the first real expectations.
165         */
166        bool readExpectationsFile(const char *jsonPath);
167
168        /**
169         * Adds this image to the summary of results.
170         *
171         * @param sourceName name of the source file that generated this result
172         * @param fileName relative path to the image output file on local disk
173         * @param digest description of the image's contents
174         * @param tileNumber if not NULL, pointer to tile number
175         */
176        void add(const char *sourceName, const char *fileName, ImageDigest &digest,
177                 const int *tileNumber=NULL);
178
179        /**
180         * Adds a key/value pair to the descriptions dict within the summary of results.
181         *
182         * @param key key within the descriptions dict
183         * @param value value to associate with that key
184         */
185        void addDescription(const char *key, const char *value);
186
187        /**
188         * Adds the image base Google Storage URL to the summary of results.
189         *
190         * @param imageBaseGSUrl the image base Google Storage URL
191         */
192        void setImageBaseGSUrl(const char *imageBaseGSUrl);
193
194        /**
195         * Returns the Expectation for this test.
196         *
197         * @param sourceName name of the source file that generated this result
198         * @param tileNumber if not NULL, pointer to tile number
199         *
200         * TODO(stephana): To make this work for GMs, we will need to add parameters for
201         * config, and maybe renderMode/builder?
202         */
203        Expectation getExpectation(const char *sourceName, const int *tileNumber=NULL);
204
205        /**
206         * Writes the summary (as constructed so far) to a file.
207         *
208         * @param filename path to write the summary to
209         */
210        void writeToFile(const char *filename) const;
211
212    private:
213
214        /**
215         * Read the file contents from filePtr and parse them into jsonRoot.
216         *
217         * It is up to the caller to close filePtr after this is done.
218         *
219         * Returns true if successful.
220         */
221        static bool Parse(SkFILE* filePtr, Json::Value *jsonRoot);
222
223        Json::Value fActualResults;
224        Json::Value fDescriptions;
225        Json::Value fExpectedJsonRoot;
226        Json::Value fExpectedResults;
227        Json::Value fImageBaseGSUrl;
228    };
229
230} // namespace sk_tools
231
232#endif  // image_expectations_DEFINED
233