Disable flaky UnloadTest.CrossSiteInfiniteBeforeUnloadSync on Mac.
[chromium-blink-merge.git] / gpu / config / gpu_test_expectations_parser.cc
blob8b3584a3f7e3138c4897af63376d3faf275aca83
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "gpu/config/gpu_test_expectations_parser.h"
7 #include "base/files/file_util.h"
8 #include "base/logging.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "base/strings/string_split.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/stringprintf.h"
14 namespace gpu {
16 namespace {
18 enum LineParserStage {
19 kLineParserBegin = 0,
20 kLineParserBugID,
21 kLineParserConfigs,
22 kLineParserColon,
23 kLineParserTestName,
24 kLineParserEqual,
25 kLineParserExpectations,
28 enum Token {
29 // os
30 kConfigWinXP = 0,
31 kConfigWinVista,
32 kConfigWin7,
33 kConfigWin8,
34 kConfigWin,
35 kConfigMacLeopard,
36 kConfigMacSnowLeopard,
37 kConfigMacLion,
38 kConfigMacMountainLion,
39 kConfigMacMavericks,
40 kConfigMacYosemite,
41 kConfigMac,
42 kConfigLinux,
43 kConfigChromeOS,
44 kConfigAndroid,
45 // gpu vendor
46 kConfigNVidia,
47 kConfigAMD,
48 kConfigIntel,
49 kConfigVMWare,
50 // build type
51 kConfigRelease,
52 kConfigDebug,
53 // expectation
54 kExpectationPass,
55 kExpectationFail,
56 kExpectationFlaky,
57 kExpectationTimeout,
58 kExpectationSkip,
59 // separator
60 kSeparatorColon,
61 kSeparatorEqual,
63 kNumberOfExactMatchTokens,
65 // others
66 kConfigGPUDeviceID,
67 kTokenComment,
68 kTokenWord,
71 struct TokenInfo {
72 const char* name;
73 int32 flag;
76 const TokenInfo kTokenData[] = {
77 { "xp", GPUTestConfig::kOsWinXP },
78 { "vista", GPUTestConfig::kOsWinVista },
79 { "win7", GPUTestConfig::kOsWin7 },
80 { "win8", GPUTestConfig::kOsWin8 },
81 { "win", GPUTestConfig::kOsWin },
82 { "leopard", GPUTestConfig::kOsMacLeopard },
83 { "snowleopard", GPUTestConfig::kOsMacSnowLeopard },
84 { "lion", GPUTestConfig::kOsMacLion },
85 { "mountainlion", GPUTestConfig::kOsMacMountainLion },
86 { "mavericks", GPUTestConfig::kOsMacMavericks },
87 { "yosemite", GPUTestConfig::kOsMacYosemite },
88 { "mac", GPUTestConfig::kOsMac },
89 { "linux", GPUTestConfig::kOsLinux },
90 { "chromeos", GPUTestConfig::kOsChromeOS },
91 { "android", GPUTestConfig::kOsAndroid },
92 { "nvidia", 0x10DE },
93 { "amd", 0x1002 },
94 { "intel", 0x8086 },
95 { "vmware", 0x15ad },
96 { "release", GPUTestConfig::kBuildTypeRelease },
97 { "debug", GPUTestConfig::kBuildTypeDebug },
98 { "pass", GPUTestExpectationsParser::kGpuTestPass },
99 { "fail", GPUTestExpectationsParser::kGpuTestFail },
100 { "flaky", GPUTestExpectationsParser::kGpuTestFlaky },
101 { "timeout", GPUTestExpectationsParser::kGpuTestTimeout },
102 { "skip", GPUTestExpectationsParser::kGpuTestSkip },
103 { ":", 0 },
104 { "=", 0 },
107 enum ErrorType {
108 kErrorFileIO = 0,
109 kErrorIllegalEntry,
110 kErrorInvalidEntry,
111 kErrorEntryWithOsConflicts,
112 kErrorEntryWithGpuVendorConflicts,
113 kErrorEntryWithBuildTypeConflicts,
114 kErrorEntryWithGpuDeviceIdConflicts,
115 kErrorEntryWithExpectationConflicts,
116 kErrorEntriesOverlap,
118 kNumberOfErrors,
121 const char* kErrorMessage[] = {
122 "file IO failed",
123 "entry with wrong format",
124 "entry invalid, likely wrong modifiers combination",
125 "entry with OS modifier conflicts",
126 "entry with GPU vendor modifier conflicts",
127 "entry with GPU build type conflicts",
128 "entry with GPU device id conflicts or malformat",
129 "entry with expectation modifier conflicts",
130 "two entries's configs overlap",
133 Token ParseToken(const std::string& word) {
134 if (StartsWithASCII(word, "//", false))
135 return kTokenComment;
136 if (StartsWithASCII(word, "0x", false))
137 return kConfigGPUDeviceID;
139 for (int32 i = 0; i < kNumberOfExactMatchTokens; ++i) {
140 if (LowerCaseEqualsASCII(word, kTokenData[i].name))
141 return static_cast<Token>(i);
143 return kTokenWord;
146 // reference name can have the last character as *.
147 bool NamesMatching(const std::string& ref, const std::string& test_name) {
148 size_t len = ref.length();
149 if (len == 0)
150 return false;
151 if (ref[len - 1] == '*') {
152 if (test_name.length() > len -1 &&
153 ref.compare(0, len - 1, test_name, 0, len - 1) == 0)
154 return true;
155 return false;
157 return (ref == test_name);
160 } // namespace anonymous
162 GPUTestExpectationsParser::GPUTestExpectationsParser() {
163 // Some sanity check.
164 DCHECK_EQ(static_cast<unsigned int>(kNumberOfExactMatchTokens),
165 sizeof(kTokenData) / sizeof(kTokenData[0]));
166 DCHECK_EQ(static_cast<unsigned int>(kNumberOfErrors),
167 sizeof(kErrorMessage) / sizeof(kErrorMessage[0]));
170 GPUTestExpectationsParser::~GPUTestExpectationsParser() {
173 bool GPUTestExpectationsParser::LoadTestExpectations(const std::string& data) {
174 entries_.clear();
175 error_messages_.clear();
177 std::vector<std::string> lines;
178 base::SplitString(data, '\n', &lines);
179 bool rt = true;
180 for (size_t i = 0; i < lines.size(); ++i) {
181 if (!ParseLine(lines[i], i + 1))
182 rt = false;
184 if (DetectConflictsBetweenEntries()) {
185 entries_.clear();
186 rt = false;
189 return rt;
192 bool GPUTestExpectationsParser::LoadTestExpectations(
193 const base::FilePath& path) {
194 entries_.clear();
195 error_messages_.clear();
197 std::string data;
198 if (!base::ReadFileToString(path, &data)) {
199 error_messages_.push_back(kErrorMessage[kErrorFileIO]);
200 return false;
202 return LoadTestExpectations(data);
205 int32 GPUTestExpectationsParser::GetTestExpectation(
206 const std::string& test_name,
207 const GPUTestBotConfig& bot_config) const {
208 for (size_t i = 0; i < entries_.size(); ++i) {
209 if (NamesMatching(entries_[i].test_name, test_name) &&
210 bot_config.Matches(entries_[i].test_config))
211 return entries_[i].test_expectation;
213 return kGpuTestPass;
216 const std::vector<std::string>&
217 GPUTestExpectationsParser::GetErrorMessages() const {
218 return error_messages_;
221 bool GPUTestExpectationsParser::ParseConfig(
222 const std::string& config_data, GPUTestConfig* config) {
223 DCHECK(config);
224 std::vector<std::string> tokens;
225 base::SplitStringAlongWhitespace(config_data, &tokens);
227 for (size_t i = 0; i < tokens.size(); ++i) {
228 Token token = ParseToken(tokens[i]);
229 switch (token) {
230 case kConfigWinXP:
231 case kConfigWinVista:
232 case kConfigWin7:
233 case kConfigWin8:
234 case kConfigWin:
235 case kConfigMacLeopard:
236 case kConfigMacSnowLeopard:
237 case kConfigMacLion:
238 case kConfigMacMountainLion:
239 case kConfigMacMavericks:
240 case kConfigMacYosemite:
241 case kConfigMac:
242 case kConfigLinux:
243 case kConfigChromeOS:
244 case kConfigAndroid:
245 case kConfigNVidia:
246 case kConfigAMD:
247 case kConfigIntel:
248 case kConfigVMWare:
249 case kConfigRelease:
250 case kConfigDebug:
251 case kConfigGPUDeviceID:
252 if (token == kConfigGPUDeviceID) {
253 if (!UpdateTestConfig(config, tokens[i], 0))
254 return false;
255 } else {
256 if (!UpdateTestConfig(config, token, 0))
257 return false;
259 break;
260 default:
261 return false;
264 return true;
267 bool GPUTestExpectationsParser::ParseLine(
268 const std::string& line_data, size_t line_number) {
269 std::vector<std::string> tokens;
270 base::SplitStringAlongWhitespace(line_data, &tokens);
271 int32 stage = kLineParserBegin;
272 GPUTestExpectationEntry entry;
273 entry.line_number = line_number;
274 GPUTestConfig& config = entry.test_config;
275 bool comments_encountered = false;
276 for (size_t i = 0; i < tokens.size() && !comments_encountered; ++i) {
277 Token token = ParseToken(tokens[i]);
278 switch (token) {
279 case kTokenComment:
280 comments_encountered = true;
281 break;
282 case kConfigWinXP:
283 case kConfigWinVista:
284 case kConfigWin7:
285 case kConfigWin8:
286 case kConfigWin:
287 case kConfigMacLeopard:
288 case kConfigMacSnowLeopard:
289 case kConfigMacLion:
290 case kConfigMacMountainLion:
291 case kConfigMacMavericks:
292 case kConfigMacYosemite:
293 case kConfigMac:
294 case kConfigLinux:
295 case kConfigChromeOS:
296 case kConfigAndroid:
297 case kConfigNVidia:
298 case kConfigAMD:
299 case kConfigIntel:
300 case kConfigVMWare:
301 case kConfigRelease:
302 case kConfigDebug:
303 case kConfigGPUDeviceID:
304 // MODIFIERS, could be in any order, need at least one.
305 if (stage != kLineParserConfigs && stage != kLineParserBugID) {
306 PushErrorMessage(kErrorMessage[kErrorIllegalEntry],
307 line_number);
308 return false;
310 if (token == kConfigGPUDeviceID) {
311 if (!UpdateTestConfig(&config, tokens[i], line_number))
312 return false;
313 } else {
314 if (!UpdateTestConfig(&config, token, line_number))
315 return false;
317 if (stage == kLineParserBugID)
318 stage++;
319 break;
320 case kSeparatorColon:
321 // :
322 if (stage != kLineParserConfigs) {
323 PushErrorMessage(kErrorMessage[kErrorIllegalEntry],
324 line_number);
325 return false;
327 stage++;
328 break;
329 case kSeparatorEqual:
330 // =
331 if (stage != kLineParserTestName) {
332 PushErrorMessage(kErrorMessage[kErrorIllegalEntry],
333 line_number);
334 return false;
336 stage++;
337 break;
338 case kTokenWord:
339 // BUG_ID or TEST_NAME
340 if (stage == kLineParserBegin) {
341 // Bug ID is not used for anything; ignore it.
342 } else if (stage == kLineParserColon) {
343 entry.test_name = tokens[i];
344 } else {
345 PushErrorMessage(kErrorMessage[kErrorIllegalEntry],
346 line_number);
347 return false;
349 stage++;
350 break;
351 case kExpectationPass:
352 case kExpectationFail:
353 case kExpectationFlaky:
354 case kExpectationTimeout:
355 case kExpectationSkip:
356 // TEST_EXPECTATIONS
357 if (stage != kLineParserEqual && stage != kLineParserExpectations) {
358 PushErrorMessage(kErrorMessage[kErrorIllegalEntry],
359 line_number);
360 return false;
362 if ((kTokenData[token].flag & entry.test_expectation) != 0) {
363 PushErrorMessage(kErrorMessage[kErrorEntryWithExpectationConflicts],
364 line_number);
365 return false;
367 entry.test_expectation =
368 (kTokenData[token].flag | entry.test_expectation);
369 if (stage == kLineParserEqual)
370 stage++;
371 break;
372 default:
373 DCHECK(false);
374 break;
377 if (stage == kLineParserBegin) {
378 // The whole line is empty or all comments
379 return true;
381 if (stage == kLineParserExpectations) {
382 if (!config.IsValid()) {
383 PushErrorMessage(kErrorMessage[kErrorInvalidEntry], line_number);
384 return false;
386 entries_.push_back(entry);
387 return true;
389 PushErrorMessage(kErrorMessage[kErrorIllegalEntry], line_number);
390 return false;
393 bool GPUTestExpectationsParser::UpdateTestConfig(
394 GPUTestConfig* config, int32 token, size_t line_number) {
395 DCHECK(config);
396 switch (token) {
397 case kConfigWinXP:
398 case kConfigWinVista:
399 case kConfigWin7:
400 case kConfigWin8:
401 case kConfigWin:
402 case kConfigMacLeopard:
403 case kConfigMacSnowLeopard:
404 case kConfigMacLion:
405 case kConfigMacMountainLion:
406 case kConfigMacMavericks:
407 case kConfigMacYosemite:
408 case kConfigMac:
409 case kConfigLinux:
410 case kConfigChromeOS:
411 case kConfigAndroid:
412 if ((config->os() & kTokenData[token].flag) != 0) {
413 PushErrorMessage(kErrorMessage[kErrorEntryWithOsConflicts],
414 line_number);
415 return false;
417 config->set_os(config->os() | kTokenData[token].flag);
418 break;
419 case kConfigNVidia:
420 case kConfigAMD:
421 case kConfigIntel:
422 case kConfigVMWare:
424 uint32 gpu_vendor =
425 static_cast<uint32>(kTokenData[token].flag);
426 for (size_t i = 0; i < config->gpu_vendor().size(); ++i) {
427 if (config->gpu_vendor()[i] == gpu_vendor) {
428 PushErrorMessage(
429 kErrorMessage[kErrorEntryWithGpuVendorConflicts],
430 line_number);
431 return false;
434 config->AddGPUVendor(gpu_vendor);
436 break;
437 case kConfigRelease:
438 case kConfigDebug:
439 if ((config->build_type() & kTokenData[token].flag) != 0) {
440 PushErrorMessage(
441 kErrorMessage[kErrorEntryWithBuildTypeConflicts],
442 line_number);
443 return false;
445 config->set_build_type(
446 config->build_type() | kTokenData[token].flag);
447 break;
448 default:
449 DCHECK(false);
450 break;
452 return true;
455 bool GPUTestExpectationsParser::UpdateTestConfig(
456 GPUTestConfig* config,
457 const std::string& gpu_device_id,
458 size_t line_number) {
459 DCHECK(config);
460 uint32 device_id = 0;
461 if (config->gpu_device_id() != 0 ||
462 !base::HexStringToUInt(gpu_device_id, &device_id) ||
463 device_id == 0) {
464 PushErrorMessage(kErrorMessage[kErrorEntryWithGpuDeviceIdConflicts],
465 line_number);
466 return false;
468 config->set_gpu_device_id(device_id);
469 return true;
472 bool GPUTestExpectationsParser::DetectConflictsBetweenEntries() {
473 bool rt = false;
474 for (size_t i = 0; i < entries_.size(); ++i) {
475 for (size_t j = i + 1; j < entries_.size(); ++j) {
476 if (entries_[i].test_name == entries_[j].test_name &&
477 entries_[i].test_config.OverlapsWith(entries_[j].test_config)) {
478 PushErrorMessage(kErrorMessage[kErrorEntriesOverlap],
479 entries_[i].line_number,
480 entries_[j].line_number);
481 rt = true;
485 return rt;
488 void GPUTestExpectationsParser::PushErrorMessage(
489 const std::string& message, size_t line_number) {
490 error_messages_.push_back(
491 base::StringPrintf("Line %d : %s",
492 static_cast<int>(line_number), message.c_str()));
495 void GPUTestExpectationsParser::PushErrorMessage(
496 const std::string& message,
497 size_t entry1_line_number,
498 size_t entry2_line_number) {
499 error_messages_.push_back(
500 base::StringPrintf("Line %d and %d : %s",
501 static_cast<int>(entry1_line_number),
502 static_cast<int>(entry2_line_number),
503 message.c_str()));
506 GPUTestExpectationsParser:: GPUTestExpectationEntry::GPUTestExpectationEntry()
507 : test_expectation(0),
508 line_number(0) {
511 } // namespace gpu