1 /*
2  * Copyright 2017 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 
8 #include "bmhParser.h"
9 #include "fiddleParser.h"
10 
11 // could make this more elaborate and look up the example definition in the bmh file;
12 // see if a simpler hint provided is sufficient
report_error(const char * blockName,const char * errorMessage)13 static bool report_error(const char* blockName, const char* errorMessage) {
14     SkDebugf("%s: %s\n", blockName, errorMessage);
15     return false;
16 }
17 
findExample(string name) const18 Definition* FiddleBase::findExample(string name) const {
19     return fBmhParser->findExample(name);
20 }
21 
parseFiddles()22 bool FiddleBase::parseFiddles() {
23     if (fStack.empty()) {
24         return false;
25     }
26     JsonStatus* status = &fStack.back();
27     while (status->fIter != status->fObject.end()) {
28         const char* blockName = status->fIter.memberName();
29         Definition* example = nullptr;
30         string textString;
31         if (!status->fObject.isObject()) {
32             return report_error(blockName, "expected object");
33         }
34         for (auto iter = status->fIter->begin(); status->fIter->end() != iter; ++iter) {
35             const char* memberName = iter.memberName();
36             if (!strcmp("compile_errors", memberName)) {
37                 if (!iter->isArray()) {
38                     return report_error(blockName, "expected array");
39                 }
40                 if (iter->size()) {
41                     return report_error(blockName, "fiddle compiler error");
42                 }
43                 continue;
44             }
45             if (!strcmp("runtime_error", memberName)) {
46                 if (!iter->isString()) {
47                     return report_error(blockName, "expected string 1");
48                 }
49                 if (iter->asString().length()) {
50                     return report_error(blockName, "fiddle runtime error");
51                 }
52                 continue;
53             }
54             if (!strcmp("fiddleHash", memberName)) {
55                 if (!iter->isString()) {
56                     return report_error(blockName, "expected string 2");
57                 }
58                 example = this->findExample(blockName);
59                 if (!example) {
60                     return report_error(blockName, "missing example");
61                 }
62                 if (example->fHash.length() && example->fHash != iter->asString()) {
63                     return example->reportError<bool>("mismatched hash");
64                 }
65                 example->fHash = iter->asString();
66                 continue;
67             }
68             if (!strcmp("text", memberName)) {
69                 if (!iter->isString()) {
70                     return report_error(blockName, "expected string 3");
71                 }
72                 textString = iter->asString();
73                 continue;
74             }
75             return report_error(blockName, "unexpected key");
76         }
77         if (!example) {
78             return report_error(blockName, "missing fiddleHash");
79         }
80         size_t strLen = textString.length();
81         if (strLen) {
82             if (fTextOut
83                     && !this->textOut(example, textString.c_str(), textString.c_str() + strLen)) {
84                 return false;
85             }
86         } else if (fPngOut && !this->pngOut(example)) {
87             return false;
88         }
89         status->fIter++;
90     }
91     return true;
92 }
93 
parseFromFile(const char * path)94 bool FiddleParser::parseFromFile(const char* path)  {
95     if (!INHERITED::parseFromFile(path)) {
96         return false;
97     }
98     fBmhParser->resetExampleHashes();
99     if (!INHERITED::parseFiddles()) {
100         return false;
101     }
102     return fBmhParser->checkExampleHashes();
103 }
104 
textOut(Definition * example,const char * stdOutStart,const char * stdOutEnd)105 bool FiddleParser::textOut(Definition* example, const char* stdOutStart,
106         const char* stdOutEnd) {
107     bool foundStdOut = false;
108     for (auto& textOut : example->fChildren) {
109         if (MarkType::kStdOut != textOut->fMarkType) {
110             continue;
111         }
112         foundStdOut = true;
113         bool foundVolatile = false;
114         for (auto& stdOutChild : textOut->fChildren) {
115                 if (MarkType::kVolatile == stdOutChild->fMarkType) {
116                     foundVolatile = true;
117                     break;
118                 }
119         }
120         TextParser bmh(textOut);
121         EscapeParser fiddle(stdOutStart, stdOutEnd);
122         do {
123             bmh.skipWhiteSpace();
124             fiddle.skipWhiteSpace();
125             const char* bmhEnd = bmh.trimmedLineEnd();
126             const char* fiddleEnd = fiddle.trimmedLineEnd();
127             ptrdiff_t bmhLen = bmhEnd - bmh.fChar;
128             SkASSERT(bmhLen > 0);
129             ptrdiff_t fiddleLen = fiddleEnd - fiddle.fChar;
130             SkASSERT(fiddleLen > 0);
131             if (bmhLen != fiddleLen) {
132                 if (!foundVolatile) {
133                     bmh.reportError("mismatched stdout len\n");
134                 }
135             } else  if (strncmp(bmh.fChar, fiddle.fChar, fiddleLen)) {
136                 if (!foundVolatile) {
137                     SkDebugf("%.*s\n", fiddleLen, fiddle.fChar);
138                     bmh.reportError("mismatched stdout text\n");
139                 }
140             }
141             bmh.skipToLineStart();
142             fiddle.skipToLineStart();
143         } while (!bmh.eof() && !fiddle.eof());
144         if (!foundStdOut) {
145             bmh.reportError("bmh %s missing stdout\n");
146         } else if (!bmh.eof() || !fiddle.eof()) {
147             if (!foundVolatile) {
148                 bmh.reportError("%s mismatched stdout eof\n");
149             }
150         }
151     }
152     return true;
153 }
154