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