blob: c746bed89c8b515c9eec681931329ccf27e1dfd2 [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
7#include "base/file_util.h"
8#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]db78bca52012-01-27 01:53:5839 kConfigMac,
40 kConfigLinux,
41 kConfigChromeOS,
[email protected]61d7e5e2012-07-27 04:08:5742 kConfigAndroid,
[email protected]db78bca52012-01-27 01:53:5843 // gpu vendor
44 kConfigNVidia,
45 kConfigAMD,
46 kConfigIntel,
[email protected]830631c2012-06-13 05:06:0847 kConfigVMWare,
[email protected]db78bca52012-01-27 01:53:5848 // build type
49 kConfigRelease,
50 kConfigDebug,
51 // expectation
52 kExpectationPass,
53 kExpectationFail,
54 kExpectationFlaky,
55 kExpectationTimeout,
[email protected]55ab0192012-05-11 20:12:3756 kExpectationSkip,
[email protected]db78bca52012-01-27 01:53:5857 // separator
58 kSeparatorColon,
59 kSeparatorEqual,
60
61 kNumberOfExactMatchTokens,
62
63 // others
64 kConfigGPUDeviceID,
65 kTokenComment,
66 kTokenWord,
67};
68
69struct TokenInfo {
70 const char* name;
71 int32 flag;
72};
73
74const TokenInfo kTokenData[] = {
75 { "xp", GPUTestConfig::kOsWinXP },
76 { "vista", GPUTestConfig::kOsWinVista },
77 { "win7", GPUTestConfig::kOsWin7 },
[email protected]c9fc22f2012-11-16 23:39:5678 { "win8", GPUTestConfig::kOsWin8 },
[email protected]db78bca52012-01-27 01:53:5879 { "win", GPUTestConfig::kOsWin },
80 { "leopard", GPUTestConfig::kOsMacLeopard },
81 { "snowleopard", GPUTestConfig::kOsMacSnowLeopard },
82 { "lion", GPUTestConfig::kOsMacLion },
[email protected]c9fc22f2012-11-16 23:39:5683 { "mountainlion", GPUTestConfig::kOsMacMountainLion },
[email protected]db78bca52012-01-27 01:53:5884 { "mac", GPUTestConfig::kOsMac },
85 { "linux", GPUTestConfig::kOsLinux },
86 { "chromeos", GPUTestConfig::kOsChromeOS },
[email protected]61d7e5e2012-07-27 04:08:5787 { "android", GPUTestConfig::kOsAndroid },
[email protected]db78bca52012-01-27 01:53:5888 { "nvidia", 0x10DE },
89 { "amd", 0x1002 },
90 { "intel", 0x8086 },
[email protected]830631c2012-06-13 05:06:0891 { "vmware", 0x15ad },
[email protected]db78bca52012-01-27 01:53:5892 { "release", GPUTestConfig::kBuildTypeRelease },
93 { "debug", GPUTestConfig::kBuildTypeDebug },
94 { "pass", GPUTestExpectationsParser::kGpuTestPass },
95 { "fail", GPUTestExpectationsParser::kGpuTestFail },
96 { "flaky", GPUTestExpectationsParser::kGpuTestFlaky },
97 { "timeout", GPUTestExpectationsParser::kGpuTestTimeout },
[email protected]55ab0192012-05-11 20:12:3798 { "skip", GPUTestExpectationsParser::kGpuTestSkip },
[email protected]db78bca52012-01-27 01:53:5899 { ":", 0 },
100 { "=", 0 },
101};
102
103enum ErrorType {
104 kErrorFileIO = 0,
105 kErrorIllegalEntry,
106 kErrorInvalidEntry,
107 kErrorEntryWithOsConflicts,
108 kErrorEntryWithGpuVendorConflicts,
109 kErrorEntryWithBuildTypeConflicts,
110 kErrorEntryWithGpuDeviceIdConflicts,
111 kErrorEntryWithExpectationConflicts,
112 kErrorEntriesOverlap,
113
114 kNumberOfErrors,
115};
116
117const char* kErrorMessage[] = {
118 "file IO failed",
119 "entry with wrong format",
120 "entry invalid, likely wrong modifiers combination",
121 "entry with OS modifier conflicts",
122 "entry with GPU vendor modifier conflicts",
123 "entry with GPU build type conflicts",
124 "entry with GPU device id conflicts or malformat",
125 "entry with expectation modifier conflicts",
126 "two entries's configs overlap",
127};
128
129Token ParseToken(const std::string& word) {
130 if (StartsWithASCII(word, "//", false))
131 return kTokenComment;
132 if (StartsWithASCII(word, "0x", false))
133 return kConfigGPUDeviceID;
134
135 for (int32 i = 0; i < kNumberOfExactMatchTokens; ++i) {
136 if (LowerCaseEqualsASCII(word, kTokenData[i].name))
137 return static_cast<Token>(i);
138 }
139 return kTokenWord;
140}
141
[email protected]55ab0192012-05-11 20:12:37142// reference name can have the last character as *.
143bool NamesMatching(const std::string& ref, const std::string& test_name) {
144 size_t len = ref.length();
145 if (len == 0)
146 return false;
147 if (ref[len - 1] == '*') {
148 if (test_name.length() > len -1 &&
149 ref.compare(0, len - 1, test_name, 0, len - 1) == 0)
150 return true;
151 return false;
152 }
153 return (ref == test_name);
154}
155
[email protected]db78bca52012-01-27 01:53:58156} // namespace anonymous
157
158GPUTestExpectationsParser::GPUTestExpectationsParser() {
159 // Some sanity check.
160 DCHECK_EQ(static_cast<unsigned int>(kNumberOfExactMatchTokens),
161 sizeof(kTokenData) / sizeof(kTokenData[0]));
162 DCHECK_EQ(static_cast<unsigned int>(kNumberOfErrors),
163 sizeof(kErrorMessage) / sizeof(kErrorMessage[0]));
164}
165
166GPUTestExpectationsParser::~GPUTestExpectationsParser() {
167}
168
169bool GPUTestExpectationsParser::LoadTestExpectations(const std::string& data) {
170 entries_.clear();
171 error_messages_.clear();
172
173 std::vector<std::string> lines;
174 base::SplitString(data, '\n', &lines);
175 bool rt = true;
176 for (size_t i = 0; i < lines.size(); ++i) {
177 if (!ParseLine(lines[i], i + 1))
178 rt = false;
179 }
180 if (DetectConflictsBetweenEntries()) {
181 entries_.clear();
182 rt = false;
183 }
184
185 return rt;
186}
187
[email protected]d30a36f2013-02-07 04:16:26188bool GPUTestExpectationsParser::LoadTestExpectations(
189 const base::FilePath& path) {
[email protected]db78bca52012-01-27 01:53:58190 entries_.clear();
191 error_messages_.clear();
192
193 std::string data;
194 if (!file_util::ReadFileToString(path, &data)) {
195 error_messages_.push_back(kErrorMessage[kErrorFileIO]);
196 return false;
197 }
198 return LoadTestExpectations(data);
199}
200
201int32 GPUTestExpectationsParser::GetTestExpectation(
202 const std::string& test_name,
203 const GPUTestBotConfig& bot_config) const {
204 for (size_t i = 0; i < entries_.size(); ++i) {
[email protected]55ab0192012-05-11 20:12:37205 if (NamesMatching(entries_[i].test_name, test_name) &&
[email protected]db78bca52012-01-27 01:53:58206 bot_config.Matches(entries_[i].test_config))
207 return entries_[i].test_expectation;
208 }
209 return kGpuTestPass;
210}
211
212const std::vector<std::string>&
213GPUTestExpectationsParser::GetErrorMessages() const {
214 return error_messages_;
215}
216
[email protected]830631c2012-06-13 05:06:08217bool GPUTestExpectationsParser::ParseConfig(
218 const std::string& config_data, GPUTestConfig* config) {
219 DCHECK(config);
220 std::vector<std::string> tokens;
221 base::SplitStringAlongWhitespace(config_data, &tokens);
222
223 for (size_t i = 0; i < tokens.size(); ++i) {
224 Token token = ParseToken(tokens[i]);
225 switch (token) {
226 case kConfigWinXP:
227 case kConfigWinVista:
228 case kConfigWin7:
[email protected]c9fc22f2012-11-16 23:39:56229 case kConfigWin8:
[email protected]830631c2012-06-13 05:06:08230 case kConfigWin:
231 case kConfigMacLeopard:
232 case kConfigMacSnowLeopard:
233 case kConfigMacLion:
[email protected]c9fc22f2012-11-16 23:39:56234 case kConfigMacMountainLion:
[email protected]830631c2012-06-13 05:06:08235 case kConfigMac:
236 case kConfigLinux:
237 case kConfigChromeOS:
[email protected]61d7e5e2012-07-27 04:08:57238 case kConfigAndroid:
[email protected]830631c2012-06-13 05:06:08239 case kConfigNVidia:
240 case kConfigAMD:
241 case kConfigIntel:
242 case kConfigVMWare:
243 case kConfigRelease:
244 case kConfigDebug:
245 case kConfigGPUDeviceID:
246 if (token == kConfigGPUDeviceID) {
247 if (!UpdateTestConfig(config, tokens[i], 0))
248 return false;
249 } else {
250 if (!UpdateTestConfig(config, token, 0))
251 return false;
252 }
253 break;
254 default:
255 return false;
256 }
257 }
258 return true;
259}
260
[email protected]db78bca52012-01-27 01:53:58261bool GPUTestExpectationsParser::ParseLine(
262 const std::string& line_data, size_t line_number) {
263 std::vector<std::string> tokens;
264 base::SplitStringAlongWhitespace(line_data, &tokens);
265 int32 stage = kLineParserBegin;
266 GPUTestExpectationEntry entry;
267 entry.line_number = line_number;
268 GPUTestConfig& config = entry.test_config;
269 bool comments_encountered = false;
270 for (size_t i = 0; i < tokens.size() && !comments_encountered; ++i) {
271 Token token = ParseToken(tokens[i]);
272 switch (token) {
273 case kTokenComment:
274 comments_encountered = true;
275 break;
276 case kConfigWinXP:
277 case kConfigWinVista:
278 case kConfigWin7:
[email protected]c9fc22f2012-11-16 23:39:56279 case kConfigWin8:
[email protected]db78bca52012-01-27 01:53:58280 case kConfigWin:
281 case kConfigMacLeopard:
282 case kConfigMacSnowLeopard:
283 case kConfigMacLion:
[email protected]c9fc22f2012-11-16 23:39:56284 case kConfigMacMountainLion:
[email protected]db78bca52012-01-27 01:53:58285 case kConfigMac:
286 case kConfigLinux:
287 case kConfigChromeOS:
[email protected]61d7e5e2012-07-27 04:08:57288 case kConfigAndroid:
[email protected]db78bca52012-01-27 01:53:58289 case kConfigNVidia:
290 case kConfigAMD:
291 case kConfigIntel:
[email protected]830631c2012-06-13 05:06:08292 case kConfigVMWare:
[email protected]db78bca52012-01-27 01:53:58293 case kConfigRelease:
294 case kConfigDebug:
295 case kConfigGPUDeviceID:
296 // MODIFIERS, could be in any order, need at least one.
297 if (stage != kLineParserConfigs && stage != kLineParserBugID) {
298 PushErrorMessage(kErrorMessage[kErrorIllegalEntry],
299 line_number);
300 return false;
301 }
302 if (token == kConfigGPUDeviceID) {
303 if (!UpdateTestConfig(&config, tokens[i], line_number))
304 return false;
305 } else {
306 if (!UpdateTestConfig(&config, token, line_number))
307 return false;
308 }
309 if (stage == kLineParserBugID)
310 stage++;
311 break;
312 case kSeparatorColon:
313 // :
314 if (stage != kLineParserConfigs) {
315 PushErrorMessage(kErrorMessage[kErrorIllegalEntry],
316 line_number);
317 return false;
318 }
319 stage++;
320 break;
321 case kSeparatorEqual:
322 // =
323 if (stage != kLineParserTestName) {
324 PushErrorMessage(kErrorMessage[kErrorIllegalEntry],
325 line_number);
326 return false;
327 }
328 stage++;
329 break;
330 case kTokenWord:
331 // BUG_ID or TEST_NAME
332 if (stage == kLineParserBegin) {
333 // Bug ID is not used for anything; ignore it.
334 } else if (stage == kLineParserColon) {
335 entry.test_name = tokens[i];
336 } else {
337 PushErrorMessage(kErrorMessage[kErrorIllegalEntry],
338 line_number);
339 return false;
340 }
341 stage++;
342 break;
343 case kExpectationPass:
344 case kExpectationFail:
345 case kExpectationFlaky:
346 case kExpectationTimeout:
[email protected]55ab0192012-05-11 20:12:37347 case kExpectationSkip:
[email protected]db78bca52012-01-27 01:53:58348 // TEST_EXPECTATIONS
349 if (stage != kLineParserEqual && stage != kLineParserExpectations) {
350 PushErrorMessage(kErrorMessage[kErrorIllegalEntry],
351 line_number);
352 return false;
353 }
354 if ((kTokenData[token].flag & entry.test_expectation) != 0) {
355 PushErrorMessage(kErrorMessage[kErrorEntryWithExpectationConflicts],
356 line_number);
357 return false;
358 }
359 entry.test_expectation =
360 (kTokenData[token].flag | entry.test_expectation);
361 if (stage == kLineParserEqual)
362 stage++;
363 break;
364 default:
365 DCHECK(false);
366 break;
367 }
368 }
369 if (stage == kLineParserBegin) {
370 // The whole line is empty or all comments
371 return true;
372 }
373 if (stage == kLineParserExpectations) {
374 if (!config.IsValid()) {
375 PushErrorMessage(kErrorMessage[kErrorInvalidEntry], line_number);
376 return false;
377 }
378 entries_.push_back(entry);
379 return true;
380 }
381 PushErrorMessage(kErrorMessage[kErrorIllegalEntry], line_number);
382 return false;
383}
384
385bool GPUTestExpectationsParser::UpdateTestConfig(
386 GPUTestConfig* config, int32 token, size_t line_number) {
387 DCHECK(config);
388 switch (token) {
389 case kConfigWinXP:
390 case kConfigWinVista:
391 case kConfigWin7:
[email protected]c9fc22f2012-11-16 23:39:56392 case kConfigWin8:
[email protected]db78bca52012-01-27 01:53:58393 case kConfigWin:
394 case kConfigMacLeopard:
395 case kConfigMacSnowLeopard:
396 case kConfigMacLion:
[email protected]c9fc22f2012-11-16 23:39:56397 case kConfigMacMountainLion:
[email protected]db78bca52012-01-27 01:53:58398 case kConfigMac:
399 case kConfigLinux:
400 case kConfigChromeOS:
[email protected]61d7e5e2012-07-27 04:08:57401 case kConfigAndroid:
[email protected]db78bca52012-01-27 01:53:58402 if ((config->os() & kTokenData[token].flag) != 0) {
403 PushErrorMessage(kErrorMessage[kErrorEntryWithOsConflicts],
404 line_number);
405 return false;
406 }
407 config->set_os(config->os() | kTokenData[token].flag);
408 break;
409 case kConfigNVidia:
410 case kConfigAMD:
411 case kConfigIntel:
[email protected]830631c2012-06-13 05:06:08412 case kConfigVMWare:
[email protected]db78bca52012-01-27 01:53:58413 {
414 uint32 gpu_vendor =
415 static_cast<uint32>(kTokenData[token].flag);
416 for (size_t i = 0; i < config->gpu_vendor().size(); ++i) {
417 if (config->gpu_vendor()[i] == gpu_vendor) {
418 PushErrorMessage(
419 kErrorMessage[kErrorEntryWithGpuVendorConflicts],
420 line_number);
421 return false;
422 }
423 }
424 config->AddGPUVendor(gpu_vendor);
425 }
426 break;
427 case kConfigRelease:
428 case kConfigDebug:
429 if ((config->build_type() & kTokenData[token].flag) != 0) {
430 PushErrorMessage(
431 kErrorMessage[kErrorEntryWithBuildTypeConflicts],
432 line_number);
433 return false;
434 }
435 config->set_build_type(
436 config->build_type() | kTokenData[token].flag);
437 break;
438 default:
439 DCHECK(false);
440 break;
441 }
442 return true;
443}
444
445bool GPUTestExpectationsParser::UpdateTestConfig(
446 GPUTestConfig* config,
447 const std::string& gpu_device_id,
448 size_t line_number) {
449 DCHECK(config);
450 uint32 device_id = 0;
451 if (config->gpu_device_id() != 0 ||
452 !base::HexStringToInt(gpu_device_id,
453 reinterpret_cast<int*>(&device_id)) ||
454 device_id == 0) {
455 PushErrorMessage(kErrorMessage[kErrorEntryWithGpuDeviceIdConflicts],
456 line_number);
457 return false;
458 }
459 config->set_gpu_device_id(device_id);
460 return true;
461}
462
463bool GPUTestExpectationsParser::DetectConflictsBetweenEntries() {
464 bool rt = false;
465 for (size_t i = 0; i < entries_.size(); ++i) {
466 for (size_t j = i + 1; j < entries_.size(); ++j) {
467 if (entries_[i].test_name == entries_[j].test_name &&
468 entries_[i].test_config.OverlapsWith(entries_[j].test_config)) {
469 PushErrorMessage(kErrorMessage[kErrorEntriesOverlap],
470 entries_[i].line_number,
471 entries_[j].line_number);
472 rt = true;
473 }
474 }
475 }
476 return rt;
477}
478
479void GPUTestExpectationsParser::PushErrorMessage(
480 const std::string& message, size_t line_number) {
481 error_messages_.push_back(
482 base::StringPrintf("Line %d : %s",
483 static_cast<int>(line_number), message.c_str()));
484}
485
486void GPUTestExpectationsParser::PushErrorMessage(
487 const std::string& message,
488 size_t entry1_line_number,
489 size_t entry2_line_number) {
490 error_messages_.push_back(
491 base::StringPrintf("Line %d and %d : %s",
492 static_cast<int>(entry1_line_number),
493 static_cast<int>(entry2_line_number),
494 message.c_str()));
495}
496
[email protected]db78bca52012-01-27 01:53:58497GPUTestExpectationsParser:: GPUTestExpectationEntry::GPUTestExpectationEntry()
498 : test_expectation(0),
499 line_number(0) {
500}
501
[email protected]129f019e2013-05-28 23:38:02502} // namespace gpu
503