/* * Copyright 2014 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef image_expectations_DEFINED #define image_expectations_DEFINED #include "SkBitmap.h" #include "SkJSONCPP.h" #include "SkOSFile.h" namespace sk_tools { /** * The digest of an image (either an image we have generated locally, or an image expectation). * * Currently, this is always a uint64_t hash digest of an SkBitmap. */ class ImageDigest { public: /** * Create an ImageDigest of a bitmap. * * Computes the hash of the bitmap lazily, since that is an expensive operation. * * @param bitmap image to get the digest of */ explicit ImageDigest(const SkBitmap &bitmap); /** * Create an ImageDigest using a hashType/hashValue pair. * * @param hashType the algorithm used to generate the hash; for now, only * kJsonValue_Image_ChecksumAlgorithm_Bitmap64bitMD5 is allowed. * @param hashValue the value generated by the hash algorithm for a particular image. */ explicit ImageDigest(const SkString &hashType, uint64_t hashValue); /** * Returns true iff this and other ImageDigest represent identical images. */ bool equals(ImageDigest &other); /** * Returns the hash digest type as an SkString. * * For now, this always returns kJsonValue_Image_ChecksumAlgorithm_Bitmap64bitMD5 . */ SkString getHashType(); /** * Returns the hash digest value as a uint64_t. * * Since the hash is computed lazily, this may take some time, and it may modify * some fields on this object. */ uint64_t getHashValue(); private: const SkBitmap fBitmap; uint64_t fHashValue; bool fComputedHashValue; }; /** * Container that holds a reference to an SkBitmap and its ImageDigest. */ class BitmapAndDigest { public: explicit BitmapAndDigest(const SkBitmap &bitmap); const SkBitmap *getBitmapPtr() const; /** * Returns a pointer to the ImageDigest. * * Since the hash is computed lazily within the ImageDigest object, we cannot mandate * that it be held const. */ ImageDigest *getImageDigestPtr(); private: const SkBitmap fBitmap; ImageDigest fImageDigest; }; /** * Expected test result: expected image (if any), and whether we want to ignore failures on * this test or not. * * This is just an ImageDigest (or lack thereof, if there is no expectation) and a boolean * telling us whether to ignore failures. */ class Expectation { public: /** * No expectation at all. */ explicit Expectation(bool ignoreFailure=kDefaultIgnoreFailure); /** * Expect an image, passed as hashType/hashValue. */ explicit Expectation(const SkString &hashType, uint64_t hashValue, bool ignoreFailure=kDefaultIgnoreFailure); /** * Expect an image, passed as a bitmap. */ explicit Expectation(const SkBitmap& bitmap, bool ignoreFailure=kDefaultIgnoreFailure); /** * Returns true iff we want to ignore failed expectations. */ bool ignoreFailure() const; /** * Returns true iff there are no allowed results. */ bool empty() const; /** * Returns true iff we are expecting a particular image, and imageDigest matches it. * * If empty() returns true, this will return false. * * If this expectation DOES contain an image, and imageDigest doesn't match it, * this method will return false regardless of what ignoreFailure() would return. * (The caller can check that separately.) */ bool matches(ImageDigest &imageDigest); private: static const bool kDefaultIgnoreFailure = false; const bool fIsEmpty; const bool fIgnoreFailure; ImageDigest fImageDigest; // cannot be const, because it computes its hash lazily }; /** * Collects ImageDigests of actually rendered images, perhaps comparing to expectations. */ class ImageResultsAndExpectations { public: /** * Adds expectations from a JSON file, returning true if successful. * * If the file exists but is empty, it succeeds, and there will be no expectations. * If the file does not exist, this will fail. * * Reasoning: * Generating expectations the first time can be a tricky chicken-and-egg * proposition. "I need actual results to turn into expectations... but the only * way to get actual results is to run the tool, and the tool won't run without * expectations!" * We could make the tool run even if there is no expectations file at all, but it's * better for the tool to fail if the expectations file is not found--that will tell us * quickly if files are not being copied around as they should be. * Creating an empty file is an easy way to break the chicken-and-egg cycle and generate * the first real expectations. */ bool readExpectationsFile(const char *jsonPath); /** * Adds this image to the summary of results. * * @param sourceName name of the source file that generated this result * @param fileName relative path to the image output file on local disk * @param digest description of the image's contents * @param tileNumber if not NULL, pointer to tile number */ void add(const char *sourceName, const char *fileName, ImageDigest &digest, const int *tileNumber=NULL); /** * Adds a key/value pair to the descriptions dict within the summary of results. * * @param key key within the descriptions dict * @param value value to associate with that key */ void addDescription(const char *key, const char *value); /** * Adds the image base Google Storage URL to the summary of results. * * @param imageBaseGSUrl the image base Google Storage URL */ void setImageBaseGSUrl(const char *imageBaseGSUrl); /** * Returns the Expectation for this test. * * @param sourceName name of the source file that generated this result * @param tileNumber if not NULL, pointer to tile number * * TODO(stephana): To make this work for GMs, we will need to add parameters for * config, and maybe renderMode/builder? */ Expectation getExpectation(const char *sourceName, const int *tileNumber=NULL); /** * Writes the summary (as constructed so far) to a file. * * @param filename path to write the summary to */ void writeToFile(const char *filename) const; private: /** * Read the file contents from filePtr and parse them into jsonRoot. * * It is up to the caller to close filePtr after this is done. * * Returns true if successful. */ static bool Parse(SkFILE* filePtr, Json::Value *jsonRoot); Json::Value fActualResults; Json::Value fDescriptions; Json::Value fExpectedJsonRoot; Json::Value fExpectedResults; Json::Value fImageBaseGSUrl; }; } // namespace sk_tools #endif // image_expectations_DEFINED