blob: debcb7930f6547f2fce38e406cc7923564ddfacc [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
5#include "content/test/gpu/gpu_test_expectations_parser.h"
6
[email protected]4f3e6302012-02-08 02:44:397#include "base/base_paths.h"
[email protected]db78bca52012-01-27 01:53:588#include "base/file_util.h"
9#include "base/logging.h"
[email protected]4f3e6302012-02-08 02:44:3910#include "base/path_service.h"
[email protected]db78bca52012-01-27 01:53:5811#include "base/string_number_conversions.h"
12#include "base/string_split.h"
13#include "base/string_util.h"
14#include "base/stringprintf.h"
[email protected]b5e34972012-09-26 03:50:2315#include "content/public/common/content_paths.h"
[email protected]db78bca52012-01-27 01:53:5816
17namespace {
18
19enum LineParserStage {
20 kLineParserBegin = 0,
21 kLineParserBugID,
22 kLineParserConfigs,
23 kLineParserColon,
24 kLineParserTestName,
25 kLineParserEqual,
26 kLineParserExpectations,
27};
28
29enum Token {
30 // os
31 kConfigWinXP = 0,
32 kConfigWinVista,
33 kConfigWin7,
[email protected]c9fc22f2012-11-16 23:39:5634 kConfigWin8,
[email protected]db78bca52012-01-27 01:53:5835 kConfigWin,
36 kConfigMacLeopard,
37 kConfigMacSnowLeopard,
38 kConfigMacLion,
[email protected]c9fc22f2012-11-16 23:39:5639 kConfigMacMountainLion,
[email protected]db78bca52012-01-27 01:53:5840 kConfigMac,
41 kConfigLinux,
42 kConfigChromeOS,
[email protected]61d7e5e2012-07-27 04:08:5743 kConfigAndroid,
[email protected]db78bca52012-01-27 01:53:5844 // gpu vendor
45 kConfigNVidia,
46 kConfigAMD,
47 kConfigIntel,
[email protected]830631c2012-06-13 05:06:0848 kConfigVMWare,
[email protected]db78bca52012-01-27 01:53:5849 // build type
50 kConfigRelease,
51 kConfigDebug,
52 // expectation
53 kExpectationPass,
54 kExpectationFail,
55 kExpectationFlaky,
56 kExpectationTimeout,
[email protected]55ab0192012-05-11 20:12:3757 kExpectationSkip,
[email protected]db78bca52012-01-27 01:53:5858 // separator
59 kSeparatorColon,
60 kSeparatorEqual,
61
62 kNumberOfExactMatchTokens,
63
64 // others
65 kConfigGPUDeviceID,
66 kTokenComment,
67 kTokenWord,
68};
69
70struct TokenInfo {
71 const char* name;
72 int32 flag;
73};
74
75const TokenInfo kTokenData[] = {
76 { "xp", GPUTestConfig::kOsWinXP },
77 { "vista", GPUTestConfig::kOsWinVista },
78 { "win7", GPUTestConfig::kOsWin7 },
[email protected]c9fc22f2012-11-16 23:39:5679 { "win8", GPUTestConfig::kOsWin8 },
[email protected]db78bca52012-01-27 01:53:5880 { "win", GPUTestConfig::kOsWin },
81 { "leopard", GPUTestConfig::kOsMacLeopard },
82 { "snowleopard", GPUTestConfig::kOsMacSnowLeopard },
83 { "lion", GPUTestConfig::kOsMacLion },
[email protected]c9fc22f2012-11-16 23:39:5684 { "mountainlion", GPUTestConfig::kOsMacMountainLion },
[email protected]db78bca52012-01-27 01:53:5885 { "mac", GPUTestConfig::kOsMac },
86 { "linux", GPUTestConfig::kOsLinux },
87 { "chromeos", GPUTestConfig::kOsChromeOS },
[email protected]61d7e5e2012-07-27 04:08:5788 { "android", GPUTestConfig::kOsAndroid },
[email protected]db78bca52012-01-27 01:53:5889 { "nvidia", 0x10DE },
90 { "amd", 0x1002 },
91 { "intel", 0x8086 },
[email protected]830631c2012-06-13 05:06:0892 { "vmware", 0x15ad },
[email protected]db78bca52012-01-27 01:53:5893 { "release", GPUTestConfig::kBuildTypeRelease },
94 { "debug", GPUTestConfig::kBuildTypeDebug },
95 { "pass", GPUTestExpectationsParser::kGpuTestPass },
96 { "fail", GPUTestExpectationsParser::kGpuTestFail },
97 { "flaky", GPUTestExpectationsParser::kGpuTestFlaky },
98 { "timeout", GPUTestExpectationsParser::kGpuTestTimeout },
[email protected]55ab0192012-05-11 20:12:3799 { "skip", GPUTestExpectationsParser::kGpuTestSkip },
[email protected]db78bca52012-01-27 01:53:58100 { ":", 0 },
101 { "=", 0 },
102};
103
104enum ErrorType {
105 kErrorFileIO = 0,
106 kErrorIllegalEntry,
107 kErrorInvalidEntry,
108 kErrorEntryWithOsConflicts,
109 kErrorEntryWithGpuVendorConflicts,
110 kErrorEntryWithBuildTypeConflicts,
111 kErrorEntryWithGpuDeviceIdConflicts,
112 kErrorEntryWithExpectationConflicts,
113 kErrorEntriesOverlap,
114
115 kNumberOfErrors,
116};
117
118const char* kErrorMessage[] = {
119 "file IO failed",
120 "entry with wrong format",
121 "entry invalid, likely wrong modifiers combination",
122 "entry with OS modifier conflicts",
123 "entry with GPU vendor modifier conflicts",
124 "entry with GPU build type conflicts",
125 "entry with GPU device id conflicts or malformat",
126 "entry with expectation modifier conflicts",
127 "two entries's configs overlap",
128};
129
130Token ParseToken(const std::string& word) {
131 if (StartsWithASCII(word, "//", false))
132 return kTokenComment;
133 if (StartsWithASCII(word, "0x", false))
134 return kConfigGPUDeviceID;
135
136 for (int32 i = 0; i < kNumberOfExactMatchTokens; ++i) {
137 if (LowerCaseEqualsASCII(word, kTokenData[i].name))
138 return static_cast<Token>(i);
139 }
140 return kTokenWord;
141}
142
[email protected]55ab0192012-05-11 20:12:37143// reference name can have the last character as *.
144bool NamesMatching(const std::string& ref, const std::string& test_name) {
145 size_t len = ref.length();
146 if (len == 0)
147 return false;
148 if (ref[len - 1] == '*') {
149 if (test_name.length() > len -1 &&
150 ref.compare(0, len - 1, test_name, 0, len - 1) == 0)
151 return true;
152 return false;
153 }
154 return (ref == test_name);
155}
156
[email protected]db78bca52012-01-27 01:53:58157} // namespace anonymous
158
159GPUTestExpectationsParser::GPUTestExpectationsParser() {
160 // Some sanity check.
161 DCHECK_EQ(static_cast<unsigned int>(kNumberOfExactMatchTokens),
162 sizeof(kTokenData) / sizeof(kTokenData[0]));
163 DCHECK_EQ(static_cast<unsigned int>(kNumberOfErrors),
164 sizeof(kErrorMessage) / sizeof(kErrorMessage[0]));
165}
166
167GPUTestExpectationsParser::~GPUTestExpectationsParser() {
168}
169
170bool GPUTestExpectationsParser::LoadTestExpectations(const std::string& data) {
171 entries_.clear();
172 error_messages_.clear();
173
174 std::vector<std::string> lines;
175 base::SplitString(data, '\n', &lines);
176 bool rt = true;
177 for (size_t i = 0; i < lines.size(); ++i) {
178 if (!ParseLine(lines[i], i + 1))
179 rt = false;
180 }
181 if (DetectConflictsBetweenEntries()) {
182 entries_.clear();
183 rt = false;
184 }
185
186 return rt;
187}
188
189bool GPUTestExpectationsParser::LoadTestExpectations(const FilePath& path) {
190 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
[email protected]4f3e6302012-02-08 02:44:39201bool GPUTestExpectationsParser::LoadTestExpectations(
202 GPUTestProfile profile) {
203 FilePath path;
204 if (!GetExpectationsPath(profile, &path))
205 return false;
206 return LoadTestExpectations(path);
207}
208
[email protected]db78bca52012-01-27 01:53:58209int32 GPUTestExpectationsParser::GetTestExpectation(
210 const std::string& test_name,
211 const GPUTestBotConfig& bot_config) const {
212 for (size_t i = 0; i < entries_.size(); ++i) {
[email protected]55ab0192012-05-11 20:12:37213 if (NamesMatching(entries_[i].test_name, test_name) &&
[email protected]db78bca52012-01-27 01:53:58214 bot_config.Matches(entries_[i].test_config))
215 return entries_[i].test_expectation;
216 }
217 return kGpuTestPass;
218}
219
220const std::vector<std::string>&
221GPUTestExpectationsParser::GetErrorMessages() const {
222 return error_messages_;
223}
224
[email protected]830631c2012-06-13 05:06:08225bool GPUTestExpectationsParser::ParseConfig(
226 const std::string& config_data, GPUTestConfig* config) {
227 DCHECK(config);
228 std::vector<std::string> tokens;
229 base::SplitStringAlongWhitespace(config_data, &tokens);
230
231 for (size_t i = 0; i < tokens.size(); ++i) {
232 Token token = ParseToken(tokens[i]);
233 switch (token) {
234 case kConfigWinXP:
235 case kConfigWinVista:
236 case kConfigWin7:
[email protected]c9fc22f2012-11-16 23:39:56237 case kConfigWin8:
[email protected]830631c2012-06-13 05:06:08238 case kConfigWin:
239 case kConfigMacLeopard:
240 case kConfigMacSnowLeopard:
241 case kConfigMacLion:
[email protected]c9fc22f2012-11-16 23:39:56242 case kConfigMacMountainLion:
[email protected]830631c2012-06-13 05:06:08243 case kConfigMac:
244 case kConfigLinux:
245 case kConfigChromeOS:
[email protected]61d7e5e2012-07-27 04:08:57246 case kConfigAndroid:
[email protected]830631c2012-06-13 05:06:08247 case kConfigNVidia:
248 case kConfigAMD:
249 case kConfigIntel:
250 case kConfigVMWare:
251 case kConfigRelease:
252 case kConfigDebug:
253 case kConfigGPUDeviceID:
254 if (token == kConfigGPUDeviceID) {
255 if (!UpdateTestConfig(config, tokens[i], 0))
256 return false;
257 } else {
258 if (!UpdateTestConfig(config, token, 0))
259 return false;
260 }
261 break;
262 default:
263 return false;
264 }
265 }
266 return true;
267}
268
[email protected]db78bca52012-01-27 01:53:58269bool GPUTestExpectationsParser::ParseLine(
270 const std::string& line_data, size_t line_number) {
271 std::vector<std::string> tokens;
272 base::SplitStringAlongWhitespace(line_data, &tokens);
273 int32 stage = kLineParserBegin;
274 GPUTestExpectationEntry entry;
275 entry.line_number = line_number;
276 GPUTestConfig& config = entry.test_config;
277 bool comments_encountered = false;
278 for (size_t i = 0; i < tokens.size() && !comments_encountered; ++i) {
279 Token token = ParseToken(tokens[i]);
280 switch (token) {
281 case kTokenComment:
282 comments_encountered = true;
283 break;
284 case kConfigWinXP:
285 case kConfigWinVista:
286 case kConfigWin7:
[email protected]c9fc22f2012-11-16 23:39:56287 case kConfigWin8:
[email protected]db78bca52012-01-27 01:53:58288 case kConfigWin:
289 case kConfigMacLeopard:
290 case kConfigMacSnowLeopard:
291 case kConfigMacLion:
[email protected]c9fc22f2012-11-16 23:39:56292 case kConfigMacMountainLion:
[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]db78bca52012-01-27 01:53:58406 case kConfigMac:
407 case kConfigLinux:
408 case kConfigChromeOS:
[email protected]61d7e5e2012-07-27 04:08:57409 case kConfigAndroid:
[email protected]db78bca52012-01-27 01:53:58410 if ((config->os() & kTokenData[token].flag) != 0) {
411 PushErrorMessage(kErrorMessage[kErrorEntryWithOsConflicts],
412 line_number);
413 return false;
414 }
415 config->set_os(config->os() | kTokenData[token].flag);
416 break;
417 case kConfigNVidia:
418 case kConfigAMD:
419 case kConfigIntel:
[email protected]830631c2012-06-13 05:06:08420 case kConfigVMWare:
[email protected]db78bca52012-01-27 01:53:58421 {
422 uint32 gpu_vendor =
423 static_cast<uint32>(kTokenData[token].flag);
424 for (size_t i = 0; i < config->gpu_vendor().size(); ++i) {
425 if (config->gpu_vendor()[i] == gpu_vendor) {
426 PushErrorMessage(
427 kErrorMessage[kErrorEntryWithGpuVendorConflicts],
428 line_number);
429 return false;
430 }
431 }
432 config->AddGPUVendor(gpu_vendor);
433 }
434 break;
435 case kConfigRelease:
436 case kConfigDebug:
437 if ((config->build_type() & kTokenData[token].flag) != 0) {
438 PushErrorMessage(
439 kErrorMessage[kErrorEntryWithBuildTypeConflicts],
440 line_number);
441 return false;
442 }
443 config->set_build_type(
444 config->build_type() | kTokenData[token].flag);
445 break;
446 default:
447 DCHECK(false);
448 break;
449 }
450 return true;
451}
452
453bool GPUTestExpectationsParser::UpdateTestConfig(
454 GPUTestConfig* config,
455 const std::string& gpu_device_id,
456 size_t line_number) {
457 DCHECK(config);
458 uint32 device_id = 0;
459 if (config->gpu_device_id() != 0 ||
460 !base::HexStringToInt(gpu_device_id,
461 reinterpret_cast<int*>(&device_id)) ||
462 device_id == 0) {
463 PushErrorMessage(kErrorMessage[kErrorEntryWithGpuDeviceIdConflicts],
464 line_number);
465 return false;
466 }
467 config->set_gpu_device_id(device_id);
468 return true;
469}
470
471bool GPUTestExpectationsParser::DetectConflictsBetweenEntries() {
472 bool rt = false;
473 for (size_t i = 0; i < entries_.size(); ++i) {
474 for (size_t j = i + 1; j < entries_.size(); ++j) {
475 if (entries_[i].test_name == entries_[j].test_name &&
476 entries_[i].test_config.OverlapsWith(entries_[j].test_config)) {
477 PushErrorMessage(kErrorMessage[kErrorEntriesOverlap],
478 entries_[i].line_number,
479 entries_[j].line_number);
480 rt = true;
481 }
482 }
483 }
484 return rt;
485}
486
487void GPUTestExpectationsParser::PushErrorMessage(
488 const std::string& message, size_t line_number) {
489 error_messages_.push_back(
490 base::StringPrintf("Line %d : %s",
491 static_cast<int>(line_number), message.c_str()));
492}
493
494void GPUTestExpectationsParser::PushErrorMessage(
495 const std::string& message,
496 size_t entry1_line_number,
497 size_t entry2_line_number) {
498 error_messages_.push_back(
499 base::StringPrintf("Line %d and %d : %s",
500 static_cast<int>(entry1_line_number),
501 static_cast<int>(entry2_line_number),
502 message.c_str()));
503}
504
[email protected]4f3e6302012-02-08 02:44:39505// static
506bool GPUTestExpectationsParser::GetExpectationsPath(
507 GPUTestProfile profile, FilePath* path) {
508 DCHECK(path);
509
510 bool rt = true;
511 switch (profile) {
512 case kWebGLConformanceTest:
[email protected]b5e34972012-09-26 03:50:23513 rt = PathService::Get(content::DIR_TEST_DATA, path);
[email protected]4f3e6302012-02-08 02:44:39514 if (rt) {
[email protected]b5e34972012-09-26 03:50:23515 *path = path->Append(FILE_PATH_LITERAL("gpu"))
[email protected]4f3e6302012-02-08 02:44:39516 .Append(FILE_PATH_LITERAL(
517 "webgl_conformance_test_expectations.txt"));
518 rt = file_util::PathExists(*path);
519 }
520 break;
521 default:
522 DCHECK(false);
523 }
524 return rt;
525}
526
[email protected]db78bca52012-01-27 01:53:58527GPUTestExpectationsParser:: GPUTestExpectationEntry::GPUTestExpectationEntry()
528 : test_expectation(0),
529 line_number(0) {
530}
531