blob: d210cbdceec8ffe92bcb6492af59955efebb9147 [file] [log] [blame]
[email protected]db78bca52012-01-27 01:53:581// 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.
4
[email protected]129f019e2013-05-28 23:38:025#include "gpu/config/gpu_test_expectations_parser.h"
[email protected]db78bca52012-01-27 01:53:586
thestigc9e38a22014-09-13 01:02:117#include "base/files/file_util.h"
[email protected]db78bca52012-01-27 01:53:588#include "base/logging.h"
[email protected]f4390962013-06-11 07:29:229#include "base/strings/string_number_conversions.h"
[email protected]27c05732013-02-15 21:55:4910#include "base/strings/string_split.h"
[email protected]f4390962013-06-11 07:29:2211#include "base/strings/string_util.h"
12#include "base/strings/stringprintf.h"
[email protected]129f019e2013-05-28 23:38:0213
14namespace gpu {
[email protected]db78bca52012-01-27 01:53:5815
16namespace {
17
18enum LineParserStage {
19 kLineParserBegin = 0,
20 kLineParserBugID,
21 kLineParserConfigs,
22 kLineParserColon,
23 kLineParserTestName,
24 kLineParserEqual,
25 kLineParserExpectations,
26};
27
28enum Token {
29 // os
30 kConfigWinXP = 0,
31 kConfigWinVista,
32 kConfigWin7,
[email protected]c9fc22f2012-11-16 23:39:5633 kConfigWin8,
[email protected]db78bca52012-01-27 01:53:5834 kConfigWin,
35 kConfigMacLeopard,
36 kConfigMacSnowLeopard,
37 kConfigMacLion,
[email protected]c9fc22f2012-11-16 23:39:5638 kConfigMacMountainLion,
[email protected]710089b92014-02-04 01:16:0939 kConfigMacMavericks,
iceman3197ce82015-04-15 11:02:3240 kConfigMacYosemite,
[email protected]db78bca52012-01-27 01:53:5841 kConfigMac,
42 kConfigLinux,
43 kConfigChromeOS,
[email protected]61d7e5e2012-07-27 04:08:5744 kConfigAndroid,
[email protected]db78bca52012-01-27 01:53:5845 // gpu vendor
46 kConfigNVidia,
47 kConfigAMD,
48 kConfigIntel,
[email protected]830631c2012-06-13 05:06:0849 kConfigVMWare,
[email protected]db78bca52012-01-27 01:53:5850 // build type
51 kConfigRelease,
52 kConfigDebug,
53 // expectation
54 kExpectationPass,
55 kExpectationFail,
56 kExpectationFlaky,
57 kExpectationTimeout,
[email protected]55ab0192012-05-11 20:12:3758 kExpectationSkip,
[email protected]db78bca52012-01-27 01:53:5859 // separator
60 kSeparatorColon,
61 kSeparatorEqual,
62
63 kNumberOfExactMatchTokens,
64
65 // others
66 kConfigGPUDeviceID,
67 kTokenComment,
68 kTokenWord,
69};
70
71struct TokenInfo {
72 const char* name;
73 int32 flag;
74};
75
76const TokenInfo kTokenData[] = {
77 { "xp", GPUTestConfig::kOsWinXP },
78 { "vista", GPUTestConfig::kOsWinVista },
79 { "win7", GPUTestConfig::kOsWin7 },
[email protected]c9fc22f2012-11-16 23:39:5680 { "win8", GPUTestConfig::kOsWin8 },
[email protected]db78bca52012-01-27 01:53:5881 { "win", GPUTestConfig::kOsWin },
82 { "leopard", GPUTestConfig::kOsMacLeopard },
83 { "snowleopard", GPUTestConfig::kOsMacSnowLeopard },
84 { "lion", GPUTestConfig::kOsMacLion },
[email protected]c9fc22f2012-11-16 23:39:5685 { "mountainlion", GPUTestConfig::kOsMacMountainLion },
[email protected]710089b92014-02-04 01:16:0986 { "mavericks", GPUTestConfig::kOsMacMavericks },
iceman3197ce82015-04-15 11:02:3287 { "yosemite", GPUTestConfig::kOsMacYosemite },
[email protected]db78bca52012-01-27 01:53:5888 { "mac", GPUTestConfig::kOsMac },
89 { "linux", GPUTestConfig::kOsLinux },
90 { "chromeos", GPUTestConfig::kOsChromeOS },
[email protected]61d7e5e2012-07-27 04:08:5791 { "android", GPUTestConfig::kOsAndroid },
[email protected]db78bca52012-01-27 01:53:5892 { "nvidia", 0x10DE },
93 { "amd", 0x1002 },
94 { "intel", 0x8086 },
[email protected]830631c2012-06-13 05:06:0895 { "vmware", 0x15ad },
[email protected]db78bca52012-01-27 01:53:5896 { "release", GPUTestConfig::kBuildTypeRelease },
97 { "debug", GPUTestConfig::kBuildTypeDebug },
98 { "pass", GPUTestExpectationsParser::kGpuTestPass },
99 { "fail", GPUTestExpectationsParser::kGpuTestFail },
100 { "flaky", GPUTestExpectationsParser::kGpuTestFlaky },
101 { "timeout", GPUTestExpectationsParser::kGpuTestTimeout },
[email protected]55ab0192012-05-11 20:12:37102 { "skip", GPUTestExpectationsParser::kGpuTestSkip },
[email protected]db78bca52012-01-27 01:53:58103 { ":", 0 },
104 { "=", 0 },
105};
106
107enum ErrorType {
108 kErrorFileIO = 0,
109 kErrorIllegalEntry,
110 kErrorInvalidEntry,
111 kErrorEntryWithOsConflicts,
112 kErrorEntryWithGpuVendorConflicts,
113 kErrorEntryWithBuildTypeConflicts,
114 kErrorEntryWithGpuDeviceIdConflicts,
115 kErrorEntryWithExpectationConflicts,
116 kErrorEntriesOverlap,
117
118 kNumberOfErrors,
119};
120
121const 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",
131};
132
133Token ParseToken(const std::string& word) {
134 if (StartsWithASCII(word, "//", false))
135 return kTokenComment;
136 if (StartsWithASCII(word, "0x", false))
137 return kConfigGPUDeviceID;
138
139 for (int32 i = 0; i < kNumberOfExactMatchTokens; ++i) {
brettwbc17d2c82015-06-09 22:39:08140 if (base::LowerCaseEqualsASCII(word, kTokenData[i].name))
[email protected]db78bca52012-01-27 01:53:58141 return static_cast<Token>(i);
142 }
143 return kTokenWord;
144}
145
[email protected]55ab0192012-05-11 20:12:37146// reference name can have the last character as *.
147bool 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;
156 }
157 return (ref == test_name);
158}
159
[email protected]db78bca52012-01-27 01:53:58160} // namespace anonymous
161
162GPUTestExpectationsParser::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]));
168}
169
170GPUTestExpectationsParser::~GPUTestExpectationsParser() {
171}
172
173bool GPUTestExpectationsParser::LoadTestExpectations(const std::string& data) {
174 entries_.clear();
175 error_messages_.clear();
176
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;
183 }
184 if (DetectConflictsBetweenEntries()) {
185 entries_.clear();
186 rt = false;
187 }
188
189 return rt;
190}
191
[email protected]d30a36f2013-02-07 04:16:26192bool GPUTestExpectationsParser::LoadTestExpectations(
193 const base::FilePath& path) {
[email protected]db78bca52012-01-27 01:53:58194 entries_.clear();
195 error_messages_.clear();
196
197 std::string data;
[email protected]82f84b92013-08-30 18:23:50198 if (!base::ReadFileToString(path, &data)) {
[email protected]db78bca52012-01-27 01:53:58199 error_messages_.push_back(kErrorMessage[kErrorFileIO]);
200 return false;
201 }
202 return LoadTestExpectations(data);
203}
204
205int32 GPUTestExpectationsParser::GetTestExpectation(
206 const std::string& test_name,
207 const GPUTestBotConfig& bot_config) const {
208 for (size_t i = 0; i < entries_.size(); ++i) {
[email protected]55ab0192012-05-11 20:12:37209 if (NamesMatching(entries_[i].test_name, test_name) &&
[email protected]db78bca52012-01-27 01:53:58210 bot_config.Matches(entries_[i].test_config))
211 return entries_[i].test_expectation;
212 }
213 return kGpuTestPass;
214}
215
216const std::vector<std::string>&
217GPUTestExpectationsParser::GetErrorMessages() const {
218 return error_messages_;
219}
220
[email protected]830631c2012-06-13 05:06:08221bool 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);
226
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:
[email protected]c9fc22f2012-11-16 23:39:56233 case kConfigWin8:
[email protected]830631c2012-06-13 05:06:08234 case kConfigWin:
235 case kConfigMacLeopard:
236 case kConfigMacSnowLeopard:
237 case kConfigMacLion:
[email protected]c9fc22f2012-11-16 23:39:56238 case kConfigMacMountainLion:
[email protected]710089b92014-02-04 01:16:09239 case kConfigMacMavericks:
iceman3197ce82015-04-15 11:02:32240 case kConfigMacYosemite:
[email protected]830631c2012-06-13 05:06:08241 case kConfigMac:
242 case kConfigLinux:
243 case kConfigChromeOS:
[email protected]61d7e5e2012-07-27 04:08:57244 case kConfigAndroid:
[email protected]830631c2012-06-13 05:06:08245 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;
258 }
259 break;
260 default:
261 return false;
262 }
263 }
264 return true;
265}
266
[email protected]db78bca52012-01-27 01:53:58267bool 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:
[email protected]c9fc22f2012-11-16 23:39:56285 case kConfigWin8:
[email protected]db78bca52012-01-27 01:53:58286 case kConfigWin:
287 case kConfigMacLeopard:
288 case kConfigMacSnowLeopard:
289 case kConfigMacLion:
[email protected]c9fc22f2012-11-16 23:39:56290 case kConfigMacMountainLion:
[email protected]710089b92014-02-04 01:16:09291 case kConfigMacMavericks:
iceman3197ce82015-04-15 11:02:32292 case kConfigMacYosemite:
[email protected]db78bca52012-01-27 01:53:58293 case kConfigMac:
294 case kConfigLinux:
295 case kConfigChromeOS:
[email protected]61d7e5e2012-07-27 04:08:57296 case kConfigAndroid:
[email protected]db78bca52012-01-27 01:53:58297 case kConfigNVidia:
298 case kConfigAMD:
299 case kConfigIntel:
[email protected]830631c2012-06-13 05:06:08300 case kConfigVMWare:
[email protected]db78bca52012-01-27 01:53:58301 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;
309 }
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;
316 }
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;
326 }
327 stage++;
328 break;
329 case kSeparatorEqual:
330 // =
331 if (stage != kLineParserTestName) {
332 PushErrorMessage(kErrorMessage[kErrorIllegalEntry],
333 line_number);
334 return false;
335 }
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;
348 }
349 stage++;
350 break;
351 case kExpectationPass:
352 case kExpectationFail:
353 case kExpectationFlaky:
354 case kExpectationTimeout:
[email protected]55ab0192012-05-11 20:12:37355 case kExpectationSkip:
[email protected]db78bca52012-01-27 01:53:58356 // TEST_EXPECTATIONS
357 if (stage != kLineParserEqual && stage != kLineParserExpectations) {
358 PushErrorMessage(kErrorMessage[kErrorIllegalEntry],
359 line_number);
360 return false;
361 }
362 if ((kTokenData[token].flag & entry.test_expectation) != 0) {
363 PushErrorMessage(kErrorMessage[kErrorEntryWithExpectationConflicts],
364 line_number);
365 return false;
366 }
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;
375 }
376 }
377 if (stage == kLineParserBegin) {
378 // The whole line is empty or all comments
379 return true;
380 }
381 if (stage == kLineParserExpectations) {
382 if (!config.IsValid()) {
383 PushErrorMessage(kErrorMessage[kErrorInvalidEntry], line_number);
384 return false;
385 }
386 entries_.push_back(entry);
387 return true;
388 }
389 PushErrorMessage(kErrorMessage[kErrorIllegalEntry], line_number);
390 return false;
391}
392
393bool 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:
[email protected]c9fc22f2012-11-16 23:39:56400 case kConfigWin8:
[email protected]db78bca52012-01-27 01:53:58401 case kConfigWin:
402 case kConfigMacLeopard:
403 case kConfigMacSnowLeopard:
404 case kConfigMacLion:
[email protected]c9fc22f2012-11-16 23:39:56405 case kConfigMacMountainLion:
[email protected]710089b92014-02-04 01:16:09406 case kConfigMacMavericks:
iceman3197ce82015-04-15 11:02:32407 case kConfigMacYosemite:
[email protected]db78bca52012-01-27 01:53:58408 case kConfigMac:
409 case kConfigLinux:
410 case kConfigChromeOS:
[email protected]61d7e5e2012-07-27 04:08:57411 case kConfigAndroid:
[email protected]db78bca52012-01-27 01:53:58412 if ((config->os() & kTokenData[token].flag) != 0) {
413 PushErrorMessage(kErrorMessage[kErrorEntryWithOsConflicts],
414 line_number);
415 return false;
416 }
417 config->set_os(config->os() | kTokenData[token].flag);
418 break;
419 case kConfigNVidia:
420 case kConfigAMD:
421 case kConfigIntel:
[email protected]830631c2012-06-13 05:06:08422 case kConfigVMWare:
[email protected]db78bca52012-01-27 01:53:58423 {
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;
432 }
433 }
434 config->AddGPUVendor(gpu_vendor);
435 }
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;
444 }
445 config->set_build_type(
446 config->build_type() | kTokenData[token].flag);
447 break;
448 default:
449 DCHECK(false);
450 break;
451 }
452 return true;
453}
454
455bool 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 ||
[email protected]3fb01692013-10-23 13:37:04462 !base::HexStringToUInt(gpu_device_id, &device_id) ||
[email protected]db78bca52012-01-27 01:53:58463 device_id == 0) {
464 PushErrorMessage(kErrorMessage[kErrorEntryWithGpuDeviceIdConflicts],
465 line_number);
466 return false;
467 }
468 config->set_gpu_device_id(device_id);
469 return true;
470}
471
472bool 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;
482 }
483 }
484 }
485 return rt;
486}
487
488void 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()));
493}
494
495void 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()));
504}
505
[email protected]db78bca52012-01-27 01:53:58506GPUTestExpectationsParser:: GPUTestExpectationEntry::GPUTestExpectationEntry()
507 : test_expectation(0),
508 line_number(0) {
509}
510
[email protected]129f019e2013-05-28 23:38:02511} // namespace gpu
512