Add ICU message format support
[chromium-blink-merge.git] / gpu / config / gpu_test_expectations_parser.cc
blobd44e5bb29846adb915f6104d7b497c6156317fa1
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 kConfigWin10,
35 kConfigWin,
36 kConfigMacLeopard,
37 kConfigMacSnowLeopard,
38 kConfigMacLion,
39 kConfigMacMountainLion,
40 kConfigMacMavericks,
41 kConfigMacYosemite,
42 kConfigMac,
43 kConfigLinux,
44 kConfigChromeOS,
45 kConfigAndroid,
46 // gpu vendor
47 kConfigNVidia,
48 kConfigAMD,
49 kConfigIntel,
50 kConfigVMWare,
51 // build type
52 kConfigRelease,
53 kConfigDebug,
54 // ANGLE renderer
55 kConfigD3D9,
56 kConfigD3D11,
57 kConfigGLDesktop,
58 kConfigGLES,
59 // expectation
60 kExpectationPass,
61 kExpectationFail,
62 kExpectationFlaky,
63 kExpectationTimeout,
64 kExpectationSkip,
65 // separator
66 kSeparatorColon,
67 kSeparatorEqual,
69 kNumberOfExactMatchTokens,
71 // others
72 kConfigGPUDeviceID,
73 kTokenComment,
74 kTokenWord,
77 struct TokenInfo {
78 const char* name;
79 int32 flag;
82 const TokenInfo kTokenData[] = {
83 {"xp", GPUTestConfig::kOsWinXP},
84 {"vista", GPUTestConfig::kOsWinVista},
85 {"win7", GPUTestConfig::kOsWin7},
86 {"win8", GPUTestConfig::kOsWin8},
87 {"win10", GPUTestConfig::kOsWin10},
88 {"win", GPUTestConfig::kOsWin},
89 {"leopard", GPUTestConfig::kOsMacLeopard},
90 {"snowleopard", GPUTestConfig::kOsMacSnowLeopard},
91 {"lion", GPUTestConfig::kOsMacLion},
92 {"mountainlion", GPUTestConfig::kOsMacMountainLion},
93 {"mavericks", GPUTestConfig::kOsMacMavericks},
94 {"yosemite", GPUTestConfig::kOsMacYosemite},
95 {"mac", GPUTestConfig::kOsMac},
96 {"linux", GPUTestConfig::kOsLinux},
97 {"chromeos", GPUTestConfig::kOsChromeOS},
98 {"android", GPUTestConfig::kOsAndroid},
99 {"nvidia", 0x10DE},
100 {"amd", 0x1002},
101 {"intel", 0x8086},
102 {"vmware", 0x15ad},
103 {"release", GPUTestConfig::kBuildTypeRelease},
104 {"debug", GPUTestConfig::kBuildTypeDebug},
105 {"d3d9", GPUTestConfig::kAPID3D9},
106 {"d3d11", GPUTestConfig::kAPID3D11},
107 {"opengl", GPUTestConfig::kAPIGLDesktop},
108 {"gles", GPUTestConfig::kAPIGLES},
109 {"pass", GPUTestExpectationsParser::kGpuTestPass},
110 {"fail", GPUTestExpectationsParser::kGpuTestFail},
111 {"flaky", GPUTestExpectationsParser::kGpuTestFlaky},
112 {"timeout", GPUTestExpectationsParser::kGpuTestTimeout},
113 {"skip", GPUTestExpectationsParser::kGpuTestSkip},
114 {":", 0},
115 {"=", 0},
118 enum ErrorType {
119 kErrorFileIO = 0,
120 kErrorIllegalEntry,
121 kErrorInvalidEntry,
122 kErrorEntryWithOsConflicts,
123 kErrorEntryWithGpuVendorConflicts,
124 kErrorEntryWithBuildTypeConflicts,
125 kErrorEntryWithAPIConflicts,
126 kErrorEntryWithGpuDeviceIdConflicts,
127 kErrorEntryWithExpectationConflicts,
128 kErrorEntriesOverlap,
130 kNumberOfErrors,
133 const char* kErrorMessage[] = {
134 "file IO failed",
135 "entry with wrong format",
136 "entry invalid, likely wrong modifiers combination",
137 "entry with OS modifier conflicts",
138 "entry with GPU vendor modifier conflicts",
139 "entry with GPU build type conflicts",
140 "entry with GPU API conflicts",
141 "entry with GPU device id conflicts or malformat",
142 "entry with expectation modifier conflicts",
143 "two entries' configs overlap",
146 Token ParseToken(const std::string& word) {
147 if (base::StartsWith(word, "//", base::CompareCase::INSENSITIVE_ASCII))
148 return kTokenComment;
149 if (base::StartsWith(word, "0x", base::CompareCase::INSENSITIVE_ASCII))
150 return kConfigGPUDeviceID;
152 for (int32 i = 0; i < kNumberOfExactMatchTokens; ++i) {
153 if (base::LowerCaseEqualsASCII(word, kTokenData[i].name))
154 return static_cast<Token>(i);
156 return kTokenWord;
159 // reference name can have the last character as *.
160 bool NamesMatching(const std::string& ref, const std::string& test_name) {
161 size_t len = ref.length();
162 if (len == 0)
163 return false;
164 if (ref[len - 1] == '*') {
165 if (test_name.length() > len -1 &&
166 ref.compare(0, len - 1, test_name, 0, len - 1) == 0)
167 return true;
168 return false;
170 return (ref == test_name);
173 } // namespace anonymous
175 GPUTestExpectationsParser::GPUTestExpectationsParser() {
176 // Some sanity check.
177 DCHECK_EQ(static_cast<unsigned int>(kNumberOfExactMatchTokens),
178 sizeof(kTokenData) / sizeof(kTokenData[0]));
179 DCHECK_EQ(static_cast<unsigned int>(kNumberOfErrors),
180 sizeof(kErrorMessage) / sizeof(kErrorMessage[0]));
183 GPUTestExpectationsParser::~GPUTestExpectationsParser() {
186 bool GPUTestExpectationsParser::LoadTestExpectations(const std::string& data) {
187 entries_.clear();
188 error_messages_.clear();
190 std::vector<std::string> lines;
191 base::SplitString(data, '\n', &lines);
192 bool rt = true;
193 for (size_t i = 0; i < lines.size(); ++i) {
194 if (!ParseLine(lines[i], i + 1))
195 rt = false;
197 if (DetectConflictsBetweenEntries()) {
198 entries_.clear();
199 rt = false;
202 return rt;
205 bool GPUTestExpectationsParser::LoadTestExpectations(
206 const base::FilePath& path) {
207 entries_.clear();
208 error_messages_.clear();
210 std::string data;
211 if (!base::ReadFileToString(path, &data)) {
212 error_messages_.push_back(kErrorMessage[kErrorFileIO]);
213 return false;
215 return LoadTestExpectations(data);
218 int32 GPUTestExpectationsParser::GetTestExpectation(
219 const std::string& test_name,
220 const GPUTestBotConfig& bot_config) const {
221 for (size_t i = 0; i < entries_.size(); ++i) {
222 if (NamesMatching(entries_[i].test_name, test_name) &&
223 bot_config.Matches(entries_[i].test_config))
224 return entries_[i].test_expectation;
226 return kGpuTestPass;
229 const std::vector<std::string>&
230 GPUTestExpectationsParser::GetErrorMessages() const {
231 return error_messages_;
234 bool GPUTestExpectationsParser::ParseConfig(
235 const std::string& config_data, GPUTestConfig* config) {
236 DCHECK(config);
237 std::vector<std::string> tokens;
238 base::SplitStringAlongWhitespace(config_data, &tokens);
240 for (size_t i = 0; i < tokens.size(); ++i) {
241 Token token = ParseToken(tokens[i]);
242 switch (token) {
243 case kConfigWinXP:
244 case kConfigWinVista:
245 case kConfigWin7:
246 case kConfigWin8:
247 case kConfigWin10:
248 case kConfigWin:
249 case kConfigMacLeopard:
250 case kConfigMacSnowLeopard:
251 case kConfigMacLion:
252 case kConfigMacMountainLion:
253 case kConfigMacMavericks:
254 case kConfigMacYosemite:
255 case kConfigMac:
256 case kConfigLinux:
257 case kConfigChromeOS:
258 case kConfigAndroid:
259 case kConfigNVidia:
260 case kConfigAMD:
261 case kConfigIntel:
262 case kConfigVMWare:
263 case kConfigRelease:
264 case kConfigDebug:
265 case kConfigD3D9:
266 case kConfigD3D11:
267 case kConfigGLDesktop:
268 case kConfigGLES:
269 case kConfigGPUDeviceID:
270 if (token == kConfigGPUDeviceID) {
271 if (!UpdateTestConfig(config, tokens[i], 0))
272 return false;
273 } else {
274 if (!UpdateTestConfig(config, token, 0))
275 return false;
277 break;
278 default:
279 return false;
282 return true;
285 bool GPUTestExpectationsParser::ParseLine(
286 const std::string& line_data, size_t line_number) {
287 std::vector<std::string> tokens;
288 base::SplitStringAlongWhitespace(line_data, &tokens);
289 int32 stage = kLineParserBegin;
290 GPUTestExpectationEntry entry;
291 entry.line_number = line_number;
292 GPUTestConfig& config = entry.test_config;
293 bool comments_encountered = false;
294 for (size_t i = 0; i < tokens.size() && !comments_encountered; ++i) {
295 Token token = ParseToken(tokens[i]);
296 switch (token) {
297 case kTokenComment:
298 comments_encountered = true;
299 break;
300 case kConfigWinXP:
301 case kConfigWinVista:
302 case kConfigWin7:
303 case kConfigWin8:
304 case kConfigWin10:
305 case kConfigWin:
306 case kConfigMacLeopard:
307 case kConfigMacSnowLeopard:
308 case kConfigMacLion:
309 case kConfigMacMountainLion:
310 case kConfigMacMavericks:
311 case kConfigMacYosemite:
312 case kConfigMac:
313 case kConfigLinux:
314 case kConfigChromeOS:
315 case kConfigAndroid:
316 case kConfigNVidia:
317 case kConfigAMD:
318 case kConfigIntel:
319 case kConfigVMWare:
320 case kConfigRelease:
321 case kConfigDebug:
322 case kConfigD3D9:
323 case kConfigD3D11:
324 case kConfigGLDesktop:
325 case kConfigGLES:
326 case kConfigGPUDeviceID:
327 // MODIFIERS, could be in any order, need at least one.
328 if (stage != kLineParserConfigs && stage != kLineParserBugID) {
329 PushErrorMessage(kErrorMessage[kErrorIllegalEntry],
330 line_number);
331 return false;
333 if (token == kConfigGPUDeviceID) {
334 if (!UpdateTestConfig(&config, tokens[i], line_number))
335 return false;
336 } else {
337 if (!UpdateTestConfig(&config, token, line_number))
338 return false;
340 if (stage == kLineParserBugID)
341 stage++;
342 break;
343 case kSeparatorColon:
344 // :
345 if (stage != kLineParserConfigs) {
346 PushErrorMessage(kErrorMessage[kErrorIllegalEntry],
347 line_number);
348 return false;
350 stage++;
351 break;
352 case kSeparatorEqual:
353 // =
354 if (stage != kLineParserTestName) {
355 PushErrorMessage(kErrorMessage[kErrorIllegalEntry],
356 line_number);
357 return false;
359 stage++;
360 break;
361 case kTokenWord:
362 // BUG_ID or TEST_NAME
363 if (stage == kLineParserBegin) {
364 // Bug ID is not used for anything; ignore it.
365 } else if (stage == kLineParserColon) {
366 entry.test_name = tokens[i];
367 } else {
368 PushErrorMessage(kErrorMessage[kErrorIllegalEntry],
369 line_number);
370 return false;
372 stage++;
373 break;
374 case kExpectationPass:
375 case kExpectationFail:
376 case kExpectationFlaky:
377 case kExpectationTimeout:
378 case kExpectationSkip:
379 // TEST_EXPECTATIONS
380 if (stage != kLineParserEqual && stage != kLineParserExpectations) {
381 PushErrorMessage(kErrorMessage[kErrorIllegalEntry],
382 line_number);
383 return false;
385 if ((kTokenData[token].flag & entry.test_expectation) != 0) {
386 PushErrorMessage(kErrorMessage[kErrorEntryWithExpectationConflicts],
387 line_number);
388 return false;
390 entry.test_expectation =
391 (kTokenData[token].flag | entry.test_expectation);
392 if (stage == kLineParserEqual)
393 stage++;
394 break;
395 default:
396 DCHECK(false);
397 break;
400 if (stage == kLineParserBegin) {
401 // The whole line is empty or all comments
402 return true;
404 if (stage == kLineParserExpectations) {
405 if (!config.IsValid()) {
406 PushErrorMessage(kErrorMessage[kErrorInvalidEntry], line_number);
407 return false;
409 entries_.push_back(entry);
410 return true;
412 PushErrorMessage(kErrorMessage[kErrorIllegalEntry], line_number);
413 return false;
416 bool GPUTestExpectationsParser::UpdateTestConfig(
417 GPUTestConfig* config, int32 token, size_t line_number) {
418 DCHECK(config);
419 switch (token) {
420 case kConfigWinXP:
421 case kConfigWinVista:
422 case kConfigWin7:
423 case kConfigWin8:
424 case kConfigWin10:
425 case kConfigWin:
426 case kConfigMacLeopard:
427 case kConfigMacSnowLeopard:
428 case kConfigMacLion:
429 case kConfigMacMountainLion:
430 case kConfigMacMavericks:
431 case kConfigMacYosemite:
432 case kConfigMac:
433 case kConfigLinux:
434 case kConfigChromeOS:
435 case kConfigAndroid:
436 if ((config->os() & kTokenData[token].flag) != 0) {
437 PushErrorMessage(kErrorMessage[kErrorEntryWithOsConflicts],
438 line_number);
439 return false;
441 config->set_os(config->os() | kTokenData[token].flag);
442 break;
443 case kConfigNVidia:
444 case kConfigAMD:
445 case kConfigIntel:
446 case kConfigVMWare:
448 uint32 gpu_vendor =
449 static_cast<uint32>(kTokenData[token].flag);
450 for (size_t i = 0; i < config->gpu_vendor().size(); ++i) {
451 if (config->gpu_vendor()[i] == gpu_vendor) {
452 PushErrorMessage(
453 kErrorMessage[kErrorEntryWithGpuVendorConflicts],
454 line_number);
455 return false;
458 config->AddGPUVendor(gpu_vendor);
460 break;
461 case kConfigRelease:
462 case kConfigDebug:
463 if ((config->build_type() & kTokenData[token].flag) != 0) {
464 PushErrorMessage(
465 kErrorMessage[kErrorEntryWithBuildTypeConflicts],
466 line_number);
467 return false;
469 config->set_build_type(
470 config->build_type() | kTokenData[token].flag);
471 break;
472 case kConfigD3D9:
473 case kConfigD3D11:
474 case kConfigGLDesktop:
475 case kConfigGLES:
476 if ((config->api() & kTokenData[token].flag) != 0) {
477 PushErrorMessage(kErrorMessage[kErrorEntryWithAPIConflicts],
478 line_number);
479 return false;
481 config->set_api(config->api() | kTokenData[token].flag);
482 break;
483 default:
484 DCHECK(false);
485 break;
487 return true;
490 bool GPUTestExpectationsParser::UpdateTestConfig(
491 GPUTestConfig* config,
492 const std::string& gpu_device_id,
493 size_t line_number) {
494 DCHECK(config);
495 uint32 device_id = 0;
496 if (config->gpu_device_id() != 0 ||
497 !base::HexStringToUInt(gpu_device_id, &device_id) ||
498 device_id == 0) {
499 PushErrorMessage(kErrorMessage[kErrorEntryWithGpuDeviceIdConflicts],
500 line_number);
501 return false;
503 config->set_gpu_device_id(device_id);
504 return true;
507 bool GPUTestExpectationsParser::DetectConflictsBetweenEntries() {
508 bool rt = false;
509 for (size_t i = 0; i < entries_.size(); ++i) {
510 for (size_t j = i + 1; j < entries_.size(); ++j) {
511 if (entries_[i].test_name == entries_[j].test_name &&
512 entries_[i].test_config.OverlapsWith(entries_[j].test_config)) {
513 PushErrorMessage(kErrorMessage[kErrorEntriesOverlap],
514 entries_[i].line_number,
515 entries_[j].line_number);
516 rt = true;
520 return rt;
523 void GPUTestExpectationsParser::PushErrorMessage(
524 const std::string& message, size_t line_number) {
525 error_messages_.push_back(
526 base::StringPrintf("Line %d : %s",
527 static_cast<int>(line_number), message.c_str()));
530 void GPUTestExpectationsParser::PushErrorMessage(
531 const std::string& message,
532 size_t entry1_line_number,
533 size_t entry2_line_number) {
534 error_messages_.push_back(
535 base::StringPrintf("Line %d and %d : %s",
536 static_cast<int>(entry1_line_number),
537 static_cast<int>(entry2_line_number),
538 message.c_str()));
541 GPUTestExpectationsParser:: GPUTestExpectationEntry::GPUTestExpectationEntry()
542 : test_expectation(0),
543 line_number(0) {
546 } // namespace gpu