1 //
2 // Copyright 2019 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 #include "GPUTestExpectationsParser.h"
8
9 #include <stddef.h>
10 #include <stdint.h>
11 #include <string.h>
12
13 #include "common/angleutils.h"
14 #include "common/debug.h"
15 #include "common/string_utils.h"
16
17 namespace angle
18 {
19
20 namespace
21 {
22
23 enum LineParserStage
24 {
25 kLineParserBegin = 0,
26 kLineParserBugID,
27 kLineParserConfigs,
28 kLineParserColon,
29 kLineParserTestName,
30 kLineParserEqual,
31 kLineParserExpectations,
32 };
33
34 enum Token
35 {
36 // os
37 kConfigWinXP = 0,
38 kConfigWinVista,
39 kConfigWin7,
40 kConfigWin8,
41 kConfigWin10,
42 kConfigWin,
43 kConfigMacLeopard,
44 kConfigMacSnowLeopard,
45 kConfigMacLion,
46 kConfigMacMountainLion,
47 kConfigMacMavericks,
48 kConfigMacYosemite,
49 kConfigMacElCapitan,
50 kConfigMacSierra,
51 kConfigMacHighSierra,
52 kConfigMacMojave,
53 kConfigMac,
54 kConfigIOS,
55 kConfigLinux,
56 kConfigChromeOS,
57 kConfigAndroid,
58 // gpu vendor
59 kConfigNVIDIA,
60 kConfigAMD,
61 kConfigIntel,
62 kConfigVMWare,
63 kConfigApple,
64 // build type
65 kConfigRelease,
66 kConfigDebug,
67 // ANGLE renderer
68 kConfigD3D9,
69 kConfigD3D11,
70 kConfigGLDesktop,
71 kConfigGLES,
72 kConfigVulkan,
73 kConfigSwiftShader,
74 kConfigMetal,
75 kConfigWgpu,
76 // Android devices
77 kConfigNexus5X,
78 kConfigPixel2,
79 kConfigPixel4,
80 kConfigPixel6,
81 kConfigPixel7,
82 kConfigFlipN2,
83 kConfigMaliG710,
84 kConfigGalaxyA23,
85 kConfigGalaxyA34,
86 kConfigGalaxyA54,
87 kConfigGalaxyS22,
88 kConfigGalaxyS23,
89 kConfigGalaxyQualcomm,
90 kConfigFindX6,
91 kConfigPineapple,
92 // GPU devices
93 kConfigNVIDIAQuadroP400,
94 kConfigNVIDIAGTX1660,
95 // PreRotation
96 kConfigPreRotation,
97 kConfigPreRotation90,
98 kConfigPreRotation180,
99 kConfigPreRotation270,
100 // Sanitizers
101 kConfigNoSan,
102 kConfigASan,
103 kConfigTSan,
104 kConfigUBSan,
105 // expectation
106 kExpectationPass,
107 kExpectationFail,
108 kExpectationFlaky,
109 kExpectationTimeout,
110 kExpectationSkip,
111 // separator
112 kSeparatorColon,
113 kSeparatorEqual,
114
115 kNumberOfExactMatchTokens,
116
117 // others
118 kTokenComment,
119 kTokenWord,
120
121 kNumberOfTokens,
122 };
123
124 enum ErrorType
125 {
126 kErrorFileIO = 0,
127 kErrorIllegalEntry,
128 kErrorInvalidEntry,
129 kErrorEntryWithExpectationConflicts,
130 kErrorEntryWithDisallowedExpectation,
131 kErrorEntriesOverlap,
132
133 kNumberOfErrors,
134 };
135
136 struct TokenInfo
137 {
TokenInfoangle::__anon72d7549a0111::TokenInfo138 constexpr TokenInfo()
139 : name(nullptr),
140 condition(GPUTestConfig::kConditionNone),
141 expectation(GPUTestExpectationsParser::kGpuTestPass)
142 {}
143
TokenInfoangle::__anon72d7549a0111::TokenInfo144 constexpr TokenInfo(const char *nameIn,
145 GPUTestConfig::Condition conditionIn,
146 GPUTestExpectationsParser::GPUTestExpectation expectationIn)
147 : name(nameIn), condition(conditionIn), expectation(expectationIn)
148 {}
149
TokenInfoangle::__anon72d7549a0111::TokenInfo150 constexpr TokenInfo(const char *nameIn, GPUTestConfig::Condition conditionIn)
151 : TokenInfo(nameIn, conditionIn, GPUTestExpectationsParser::kGpuTestPass)
152 {}
153
154 const char *name;
155 GPUTestConfig::Condition condition;
156 GPUTestExpectationsParser::GPUTestExpectation expectation;
157 };
158
159 constexpr TokenInfo kTokenData[kNumberOfTokens] = {
160 {"xp", GPUTestConfig::kConditionWinXP},
161 {"vista", GPUTestConfig::kConditionWinVista},
162 {"win7", GPUTestConfig::kConditionWin7},
163 {"win8", GPUTestConfig::kConditionWin8},
164 {"win10", GPUTestConfig::kConditionWin10},
165 {"win", GPUTestConfig::kConditionWin},
166 {"leopard", GPUTestConfig::kConditionMacLeopard},
167 {"snowleopard", GPUTestConfig::kConditionMacSnowLeopard},
168 {"lion", GPUTestConfig::kConditionMacLion},
169 {"mountainlion", GPUTestConfig::kConditionMacMountainLion},
170 {"mavericks", GPUTestConfig::kConditionMacMavericks},
171 {"yosemite", GPUTestConfig::kConditionMacYosemite},
172 {"elcapitan", GPUTestConfig::kConditionMacElCapitan},
173 {"sierra", GPUTestConfig::kConditionMacSierra},
174 {"highsierra", GPUTestConfig::kConditionMacHighSierra},
175 {"mojave", GPUTestConfig::kConditionMacMojave},
176 {"mac", GPUTestConfig::kConditionMac},
177 {"ios", GPUTestConfig::kConditionIOS},
178 {"linux", GPUTestConfig::kConditionLinux},
179 {"chromeos", GPUTestConfig::kConditionNone}, // https://anglebug.com/3363 CrOS not supported
180 {"android", GPUTestConfig::kConditionAndroid},
181 {"nvidia", GPUTestConfig::kConditionNVIDIA},
182 {"amd", GPUTestConfig::kConditionAMD},
183 {"intel", GPUTestConfig::kConditionIntel},
184 {"vmware", GPUTestConfig::kConditionVMWare},
185 {"apple", GPUTestConfig::kConditionApple},
186 {"release", GPUTestConfig::kConditionRelease},
187 {"debug", GPUTestConfig::kConditionDebug},
188 {"d3d9", GPUTestConfig::kConditionD3D9},
189 {"d3d11", GPUTestConfig::kConditionD3D11},
190 {"opengl", GPUTestConfig::kConditionGLDesktop},
191 {"gles", GPUTestConfig::kConditionGLES},
192 {"vulkan", GPUTestConfig::kConditionVulkan},
193 {"swiftshader", GPUTestConfig::kConditionSwiftShader},
194 {"metal", GPUTestConfig::kConditionMetal},
195 {"wgpu", GPUTestConfig::kConditionWgpu},
196 {"nexus5x", GPUTestConfig::kConditionNexus5X},
197 {"pixel2orxl", GPUTestConfig::kConditionPixel2OrXL},
198 {"pixel4orxl", GPUTestConfig::kConditionPixel4OrXL},
199 {"pixel6", GPUTestConfig::kConditionPixel6},
200 {"pixel7", GPUTestConfig::kConditionPixel7},
201 {"flipn2", GPUTestConfig::kConditionFlipN2},
202 {"malig710", GPUTestConfig::kConditionMaliG710},
203 {"galaxya23", GPUTestConfig::kConditionGalaxyA23},
204 {"galaxya34", GPUTestConfig::kConditionGalaxyA34},
205 {"galaxya54", GPUTestConfig::kConditionGalaxyA54},
206 {"galaxys22", GPUTestConfig::kConditionGalaxyS22},
207 {"galaxys23", GPUTestConfig::kConditionGalaxyS23},
208 {"galaxyqualcomm", GPUTestConfig::kConditionGalaxyQualcomm},
209 {"findx6", GPUTestConfig::kConditionFindX6},
210 {"pineapple", GPUTestConfig::kConditionPineapple},
211 {"quadrop400", GPUTestConfig::kConditionNVIDIAQuadroP400},
212 {"gtx1660", GPUTestConfig::kConditionNVIDIAGTX1660},
213 {"prerotation", GPUTestConfig::kConditionPreRotation},
214 {"prerotation90", GPUTestConfig::kConditionPreRotation90},
215 {"prerotation180", GPUTestConfig::kConditionPreRotation180},
216 {"prerotation270", GPUTestConfig::kConditionPreRotation270},
217 {"nosan", GPUTestConfig::kConditionNoSan},
218 {"asan", GPUTestConfig::kConditionASan},
219 {"tsan", GPUTestConfig::kConditionTSan},
220 {"ubsan", GPUTestConfig::kConditionUBSan},
221 {"pass", GPUTestConfig::kConditionNone, GPUTestExpectationsParser::kGpuTestPass},
222 {"fail", GPUTestConfig::kConditionNone, GPUTestExpectationsParser::kGpuTestFail},
223 {"flaky", GPUTestConfig::kConditionNone, GPUTestExpectationsParser::kGpuTestFlaky},
224 {"timeout", GPUTestConfig::kConditionNone, GPUTestExpectationsParser::kGpuTestTimeout},
225 {"skip", GPUTestConfig::kConditionNone, GPUTestExpectationsParser::kGpuTestSkip},
226 {":", GPUTestConfig::kConditionNone}, // kSeparatorColon
227 {"=", GPUTestConfig::kConditionNone}, // kSeparatorEqual
228 {}, // kNumberOfExactMatchTokens
229 {}, // kTokenComment
230 {}, // kTokenWord
231 };
232
233 const char *kErrorMessage[kNumberOfErrors] = {
234 "file IO failed",
235 "entry with wrong format",
236 "entry invalid, likely unimplemented modifiers",
237 "entry with expectation modifier conflicts",
238 "entry with unsupported expectation",
239 "two entries' configs overlap",
240 };
241
StartsWithASCII(const std::string & str,const std::string & search,bool caseSensitive)242 inline bool StartsWithASCII(const std::string &str, const std::string &search, bool caseSensitive)
243 {
244 ASSERT(!caseSensitive);
245 return str.compare(0, search.length(), search) == 0;
246 }
247
248 template <class Char>
ToLowerASCII(Char c)249 inline Char ToLowerASCII(Char c)
250 {
251 return (c >= 'A' && c <= 'Z') ? (c + ('a' - 'A')) : c;
252 }
253
254 template <typename Iter>
DoLowerCaseEqualsASCII(Iter a_begin,Iter a_end,const char * b)255 inline bool DoLowerCaseEqualsASCII(Iter a_begin, Iter a_end, const char *b)
256 {
257 for (Iter it = a_begin; it != a_end; ++it, ++b)
258 {
259 if (!*b || ToLowerASCII(*it) != *b)
260 return false;
261 }
262 return *b == 0;
263 }
264
LowerCaseEqualsASCII(const std::string & a,const char * b)265 inline bool LowerCaseEqualsASCII(const std::string &a, const char *b)
266 {
267 return DoLowerCaseEqualsASCII(a.begin(), a.end(), b);
268 }
269
ParseToken(const std::string & word)270 inline Token ParseToken(const std::string &word)
271 {
272 if (StartsWithASCII(word, "//", false))
273 return kTokenComment;
274
275 for (int32_t i = 0; i < kNumberOfExactMatchTokens; ++i)
276 {
277 if (LowerCaseEqualsASCII(word, kTokenData[i].name))
278 return static_cast<Token>(i);
279 }
280 return kTokenWord;
281 }
282
ConditionArrayIsSubset(const GPUTestConfig::ConditionArray & subset,const GPUTestConfig::ConditionArray & superset)283 bool ConditionArrayIsSubset(const GPUTestConfig::ConditionArray &subset,
284 const GPUTestConfig::ConditionArray &superset)
285 {
286 for (size_t subsetCondition : subset)
287 {
288 bool foundCondition = false;
289 for (size_t supersetCondition : superset)
290 {
291 if (subsetCondition == supersetCondition)
292 {
293 foundCondition = true;
294 break;
295 }
296 }
297
298 if (!foundCondition)
299 {
300 return false;
301 }
302 }
303
304 return true;
305 }
306
307 // If one array is completely contained within the other, then we say the conditions overlap.
ConditionsOverlap(const GPUTestConfig::ConditionArray & conditionsI,const GPUTestConfig::ConditionArray & conditionsJ)308 bool ConditionsOverlap(const GPUTestConfig::ConditionArray &conditionsI,
309 const GPUTestConfig::ConditionArray &conditionsJ)
310 {
311 return ConditionArrayIsSubset(conditionsI, conditionsJ) ||
312 ConditionArrayIsSubset(conditionsJ, conditionsI);
313 }
314 } // anonymous namespace
315
GetConditionName(uint32_t condition)316 const char *GetConditionName(uint32_t condition)
317 {
318 if (condition == GPUTestConfig::kConditionNone)
319 {
320 return nullptr;
321 }
322
323 for (const TokenInfo &info : kTokenData)
324 {
325 if (info.condition == condition)
326 {
327 // kConditionNone is used to tag tokens that aren't conditions, but this case has been
328 // handled above.
329 ASSERT(info.condition != GPUTestConfig::kConditionNone);
330 return info.name;
331 }
332 }
333
334 return nullptr;
335 }
336
GPUTestExpectationsParser()337 GPUTestExpectationsParser::GPUTestExpectationsParser()
338 : mExpectationsAllowMask(
339 GPUTestExpectationsParser::kGpuTestPass | GPUTestExpectationsParser::kGpuTestFail |
340 GPUTestExpectationsParser::kGpuTestFlaky | GPUTestExpectationsParser::kGpuTestTimeout |
341 GPUTestExpectationsParser::kGpuTestSkip)
342 {
343 // Some initial checks.
344 ASSERT((static_cast<unsigned int>(kNumberOfTokens)) ==
345 (sizeof(kTokenData) / sizeof(kTokenData[0])));
346 ASSERT((static_cast<unsigned int>(kNumberOfErrors)) ==
347 (sizeof(kErrorMessage) / sizeof(kErrorMessage[0])));
348 }
349
350 GPUTestExpectationsParser::~GPUTestExpectationsParser() = default;
351
loadTestExpectationsImpl(const GPUTestConfig * config,const std::string & data)352 bool GPUTestExpectationsParser::loadTestExpectationsImpl(const GPUTestConfig *config,
353 const std::string &data)
354 {
355 mEntries.clear();
356 mErrorMessages.clear();
357
358 std::vector<std::string> lines = SplitString(data, "\n", TRIM_WHITESPACE, SPLIT_WANT_ALL);
359 bool rt = true;
360 for (size_t i = 0; i < lines.size(); ++i)
361 {
362 if (!parseLine(config, lines[i], i + 1))
363 rt = false;
364 }
365 if (detectConflictsBetweenEntries())
366 {
367 mEntries.clear();
368 rt = false;
369 }
370
371 return rt;
372 }
373
loadTestExpectations(const GPUTestConfig & config,const std::string & data)374 bool GPUTestExpectationsParser::loadTestExpectations(const GPUTestConfig &config,
375 const std::string &data)
376 {
377 return loadTestExpectationsImpl(&config, data);
378 }
379
loadAllTestExpectations(const std::string & data)380 bool GPUTestExpectationsParser::loadAllTestExpectations(const std::string &data)
381 {
382 return loadTestExpectationsImpl(nullptr, data);
383 }
384
loadTestExpectationsFromFileImpl(const GPUTestConfig * config,const std::string & path)385 bool GPUTestExpectationsParser::loadTestExpectationsFromFileImpl(const GPUTestConfig *config,
386 const std::string &path)
387 {
388 mEntries.clear();
389 mErrorMessages.clear();
390
391 std::string data;
392 if (!ReadFileToString(path, &data))
393 {
394 mErrorMessages.push_back(kErrorMessage[kErrorFileIO]);
395 return false;
396 }
397 return loadTestExpectationsImpl(config, data);
398 }
399
loadTestExpectationsFromFile(const GPUTestConfig & config,const std::string & path)400 bool GPUTestExpectationsParser::loadTestExpectationsFromFile(const GPUTestConfig &config,
401 const std::string &path)
402 {
403 return loadTestExpectationsFromFileImpl(&config, path);
404 }
405
loadAllTestExpectationsFromFile(const std::string & path)406 bool GPUTestExpectationsParser::loadAllTestExpectationsFromFile(const std::string &path)
407 {
408 return loadTestExpectationsFromFileImpl(nullptr, path);
409 }
410
getTestExpectationImpl(const GPUTestConfig * config,const std::string & testName)411 int32_t GPUTestExpectationsParser::getTestExpectationImpl(const GPUTestConfig *config,
412 const std::string &testName)
413 {
414 for (GPUTestExpectationEntry &entry : mEntries)
415 {
416 if (NamesMatchWithWildcard(entry.testName.c_str(), testName.c_str()))
417 {
418 // Filter by condition first.
419 bool satisfiesConditions = true;
420 if (config)
421 {
422 for (size_t condition : entry.conditions)
423 {
424 if (!config->getConditions()[condition])
425 {
426 satisfiesConditions = false;
427 break;
428 }
429 }
430 }
431
432 // Use the first matching expectation in the file as the matching expression.
433 if (satisfiesConditions)
434 {
435 entry.used = true;
436 return entry.testExpectation;
437 }
438 }
439 }
440 return kGpuTestPass;
441 }
442
getTestExpectation(const std::string & testName)443 int32_t GPUTestExpectationsParser::getTestExpectation(const std::string &testName)
444 {
445 return getTestExpectationImpl(nullptr, testName);
446 }
447
getTestExpectationWithConfig(const GPUTestConfig & config,const std::string & testName)448 int32_t GPUTestExpectationsParser::getTestExpectationWithConfig(const GPUTestConfig &config,
449 const std::string &testName)
450 {
451 return getTestExpectationImpl(&config, testName);
452 }
453
getErrorMessages() const454 const std::vector<std::string> &GPUTestExpectationsParser::getErrorMessages() const
455 {
456 return mErrorMessages;
457 }
458
getUnusedExpectationsMessages() const459 std::vector<std::string> GPUTestExpectationsParser::getUnusedExpectationsMessages() const
460 {
461 std::vector<std::string> messages;
462 std::vector<GPUTestExpectationsParser::GPUTestExpectationEntry> unusedExpectations =
463 getUnusedExpectations();
464 for (size_t i = 0; i < unusedExpectations.size(); ++i)
465 {
466 std::string message =
467 "Line " + ToString(unusedExpectations[i].lineNumber) + ": expectation was unused.";
468 messages.push_back(message);
469 }
470 return messages;
471 }
472
parseLine(const GPUTestConfig * config,const std::string & lineData,size_t lineNumber)473 bool GPUTestExpectationsParser::parseLine(const GPUTestConfig *config,
474 const std::string &lineData,
475 size_t lineNumber)
476 {
477 std::vector<std::string> tokens =
478 SplitString(lineData, kWhitespaceASCII, KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY);
479 int32_t stage = kLineParserBegin;
480 GPUTestExpectationEntry entry;
481 entry.lineNumber = lineNumber;
482 entry.used = false;
483 bool skipLine = false;
484 for (size_t i = 0; i < tokens.size() && !skipLine; ++i)
485 {
486 Token token = ParseToken(tokens[i]);
487 switch (token)
488 {
489 case kTokenComment:
490 skipLine = true;
491 break;
492 case kConfigWinXP:
493 case kConfigWinVista:
494 case kConfigWin7:
495 case kConfigWin8:
496 case kConfigWin10:
497 case kConfigWin:
498 case kConfigMacLeopard:
499 case kConfigMacSnowLeopard:
500 case kConfigMacLion:
501 case kConfigMacMountainLion:
502 case kConfigMacMavericks:
503 case kConfigMacYosemite:
504 case kConfigMacElCapitan:
505 case kConfigMacSierra:
506 case kConfigMacHighSierra:
507 case kConfigMacMojave:
508 case kConfigMac:
509 case kConfigIOS:
510 case kConfigLinux:
511 case kConfigChromeOS:
512 case kConfigAndroid:
513 case kConfigNVIDIA:
514 case kConfigAMD:
515 case kConfigIntel:
516 case kConfigVMWare:
517 case kConfigApple:
518 case kConfigRelease:
519 case kConfigDebug:
520 case kConfigD3D9:
521 case kConfigD3D11:
522 case kConfigGLDesktop:
523 case kConfigGLES:
524 case kConfigVulkan:
525 case kConfigSwiftShader:
526 case kConfigMetal:
527 case kConfigWgpu:
528 case kConfigNexus5X:
529 case kConfigPixel2:
530 case kConfigPixel4:
531 case kConfigPixel6:
532 case kConfigPixel7:
533 case kConfigFlipN2:
534 case kConfigMaliG710:
535 case kConfigGalaxyA23:
536 case kConfigGalaxyA34:
537 case kConfigGalaxyA54:
538 case kConfigGalaxyS22:
539 case kConfigGalaxyS23:
540 case kConfigGalaxyQualcomm:
541 case kConfigFindX6:
542 case kConfigPineapple:
543 case kConfigNVIDIAQuadroP400:
544 case kConfigNVIDIAGTX1660:
545 case kConfigPreRotation:
546 case kConfigPreRotation90:
547 case kConfigPreRotation180:
548 case kConfigPreRotation270:
549 case kConfigNoSan:
550 case kConfigASan:
551 case kConfigTSan:
552 case kConfigUBSan:
553 // MODIFIERS, check each condition and add accordingly.
554 if (stage != kLineParserConfigs && stage != kLineParserBugID)
555 {
556 pushErrorMessage(kErrorMessage[kErrorIllegalEntry], lineNumber);
557 return false;
558 }
559 {
560 bool err = false;
561 if (config)
562 {
563 if (!checkTokenCondition(*config, err, token, lineNumber))
564 {
565 skipLine = true; // Move to the next line without adding this one.
566 }
567 }
568 else
569 {
570 // Store the conditions for later comparison if we don't have a config.
571 entry.conditions[kTokenData[token].condition] = true;
572 }
573 if (err)
574 {
575 return false;
576 }
577 }
578 if (stage == kLineParserBugID)
579 {
580 stage++;
581 }
582 break;
583 case kSeparatorColon:
584 // :
585 // If there are no modifiers, move straight to separator colon
586 if (stage == kLineParserBugID)
587 {
588 stage++;
589 }
590 if (stage != kLineParserConfigs)
591 {
592 pushErrorMessage(kErrorMessage[kErrorIllegalEntry], lineNumber);
593 return false;
594 }
595 stage++;
596 break;
597 case kSeparatorEqual:
598 // =
599 if (stage != kLineParserTestName)
600 {
601 pushErrorMessage(kErrorMessage[kErrorIllegalEntry], lineNumber);
602 return false;
603 }
604 stage++;
605 break;
606 case kTokenWord:
607 // BUG_ID or TEST_NAME
608 if (stage == kLineParserBegin)
609 {
610 // Bug ID is not used for anything; ignore it.
611 }
612 else if (stage == kLineParserColon)
613 {
614 entry.testName = tokens[i];
615 }
616 else
617 {
618 pushErrorMessage(kErrorMessage[kErrorIllegalEntry], lineNumber);
619 return false;
620 }
621 stage++;
622 break;
623 case kExpectationPass:
624 case kExpectationFail:
625 case kExpectationFlaky:
626 case kExpectationTimeout:
627 case kExpectationSkip:
628 // TEST_EXPECTATIONS
629 if (stage != kLineParserEqual && stage != kLineParserExpectations)
630 {
631 pushErrorMessage(kErrorMessage[kErrorIllegalEntry], lineNumber);
632 return false;
633 }
634 if (entry.testExpectation != 0)
635 {
636 pushErrorMessage(kErrorMessage[kErrorEntryWithExpectationConflicts],
637 lineNumber);
638 return false;
639 }
640 if ((mExpectationsAllowMask & kTokenData[token].expectation) == 0)
641 {
642 pushErrorMessage(kErrorMessage[kErrorEntryWithDisallowedExpectation],
643 lineNumber);
644 return false;
645 }
646 entry.testExpectation = kTokenData[token].expectation;
647 if (stage == kLineParserEqual)
648 stage++;
649 break;
650 default:
651 ASSERT(false);
652 break;
653 }
654 }
655 if (stage == kLineParserBegin || skipLine)
656 {
657 // The whole line is empty or all comments, or has been skipped to to a condition token.
658 return true;
659 }
660 if (stage == kLineParserExpectations)
661 {
662 mEntries.push_back(entry);
663 return true;
664 }
665 pushErrorMessage(kErrorMessage[kErrorIllegalEntry], lineNumber);
666 return false;
667 }
668
checkTokenCondition(const GPUTestConfig & config,bool & err,int32_t token,size_t lineNumber)669 bool GPUTestExpectationsParser::checkTokenCondition(const GPUTestConfig &config,
670 bool &err,
671 int32_t token,
672 size_t lineNumber)
673 {
674 if (token >= kNumberOfTokens)
675 {
676 pushErrorMessage(kErrorMessage[kErrorIllegalEntry], lineNumber);
677 err = true;
678 return false;
679 }
680
681 if (kTokenData[token].condition == GPUTestConfig::kConditionNone ||
682 kTokenData[token].condition >= GPUTestConfig::kNumberOfConditions)
683 {
684 pushErrorMessage(kErrorMessage[kErrorInvalidEntry], lineNumber);
685 // error on any unsupported conditions
686 err = true;
687 return false;
688 }
689 err = false;
690 return config.getConditions()[kTokenData[token].condition];
691 }
692
detectConflictsBetweenEntries()693 bool GPUTestExpectationsParser::detectConflictsBetweenEntries()
694 {
695 bool rt = false;
696 for (size_t i = 0; i < mEntries.size(); ++i)
697 {
698 for (size_t j = i + 1; j < mEntries.size(); ++j)
699 {
700 const GPUTestExpectationEntry &entryI = mEntries[i];
701 const GPUTestExpectationEntry &entryJ = mEntries[j];
702 if (entryI.testName == entryJ.testName &&
703 ConditionsOverlap(entryI.conditions, entryJ.conditions))
704 {
705 pushErrorMessage(kErrorMessage[kErrorEntriesOverlap], entryI.lineNumber,
706 entryJ.lineNumber);
707 rt = true;
708 }
709 }
710 }
711 return rt;
712 }
713
714 std::vector<GPUTestExpectationsParser::GPUTestExpectationEntry>
getUnusedExpectations() const715 GPUTestExpectationsParser::getUnusedExpectations() const
716 {
717 std::vector<GPUTestExpectationsParser::GPUTestExpectationEntry> unusedExpectations;
718 for (size_t i = 0; i < mEntries.size(); ++i)
719 {
720 if (!mEntries[i].used)
721 {
722 unusedExpectations.push_back(mEntries[i]);
723 }
724 }
725 return unusedExpectations;
726 }
727
pushErrorMessage(const std::string & message,size_t lineNumber)728 void GPUTestExpectationsParser::pushErrorMessage(const std::string &message, size_t lineNumber)
729 {
730 mErrorMessages.push_back("Line " + ToString(lineNumber) + " : " + message.c_str());
731 }
732
pushErrorMessage(const std::string & message,size_t entry1LineNumber,size_t entry2LineNumber)733 void GPUTestExpectationsParser::pushErrorMessage(const std::string &message,
734 size_t entry1LineNumber,
735 size_t entry2LineNumber)
736 {
737 mErrorMessages.push_back("Line " + ToString(entry1LineNumber) + " and " +
738 ToString(entry2LineNumber) + " : " + message.c_str());
739 }
740
GPUTestExpectationEntry()741 GPUTestExpectationsParser::GPUTestExpectationEntry::GPUTestExpectationEntry()
742 : testExpectation(0), lineNumber(0)
743 {}
744
745 } // namespace angle
746