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