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"
18 enum LineParserStage
{
25 kLineParserExpectations
,
37 kConfigMacSnowLeopard
,
39 kConfigMacMountainLion
,
69 kNumberOfExactMatchTokens
,
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
},
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
},
122 kErrorEntryWithOsConflicts
,
123 kErrorEntryWithGpuVendorConflicts
,
124 kErrorEntryWithBuildTypeConflicts
,
125 kErrorEntryWithAPIConflicts
,
126 kErrorEntryWithGpuDeviceIdConflicts
,
127 kErrorEntryWithExpectationConflicts
,
128 kErrorEntriesOverlap
,
133 const char* kErrorMessage
[] = {
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
);
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();
164 if (ref
[len
- 1] == '*') {
165 if (test_name
.length() > len
-1 &&
166 ref
.compare(0, len
- 1, test_name
, 0, len
- 1) == 0)
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
) {
188 error_messages_
.clear();
190 std::vector
<std::string
> lines
;
191 base::SplitString(data
, '\n', &lines
);
193 for (size_t i
= 0; i
< lines
.size(); ++i
) {
194 if (!ParseLine(lines
[i
], i
+ 1))
197 if (DetectConflictsBetweenEntries()) {
205 bool GPUTestExpectationsParser::LoadTestExpectations(
206 const base::FilePath
& path
) {
208 error_messages_
.clear();
211 if (!base::ReadFileToString(path
, &data
)) {
212 error_messages_
.push_back(kErrorMessage
[kErrorFileIO
]);
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
;
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
) {
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
]);
244 case kConfigWinVista
:
249 case kConfigMacLeopard
:
250 case kConfigMacSnowLeopard
:
252 case kConfigMacMountainLion
:
253 case kConfigMacMavericks
:
254 case kConfigMacYosemite
:
257 case kConfigChromeOS
:
267 case kConfigGLDesktop
:
269 case kConfigGPUDeviceID
:
270 if (token
== kConfigGPUDeviceID
) {
271 if (!UpdateTestConfig(config
, tokens
[i
], 0))
274 if (!UpdateTestConfig(config
, token
, 0))
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
]);
298 comments_encountered
= true;
301 case kConfigWinVista
:
306 case kConfigMacLeopard
:
307 case kConfigMacSnowLeopard
:
309 case kConfigMacMountainLion
:
310 case kConfigMacMavericks
:
311 case kConfigMacYosemite
:
314 case kConfigChromeOS
:
324 case kConfigGLDesktop
:
326 case kConfigGPUDeviceID
:
327 // MODIFIERS, could be in any order, need at least one.
328 if (stage
!= kLineParserConfigs
&& stage
!= kLineParserBugID
) {
329 PushErrorMessage(kErrorMessage
[kErrorIllegalEntry
],
333 if (token
== kConfigGPUDeviceID
) {
334 if (!UpdateTestConfig(&config
, tokens
[i
], line_number
))
337 if (!UpdateTestConfig(&config
, token
, line_number
))
340 if (stage
== kLineParserBugID
)
343 case kSeparatorColon
:
345 if (stage
!= kLineParserConfigs
) {
346 PushErrorMessage(kErrorMessage
[kErrorIllegalEntry
],
352 case kSeparatorEqual
:
354 if (stage
!= kLineParserTestName
) {
355 PushErrorMessage(kErrorMessage
[kErrorIllegalEntry
],
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
];
368 PushErrorMessage(kErrorMessage
[kErrorIllegalEntry
],
374 case kExpectationPass
:
375 case kExpectationFail
:
376 case kExpectationFlaky
:
377 case kExpectationTimeout
:
378 case kExpectationSkip
:
380 if (stage
!= kLineParserEqual
&& stage
!= kLineParserExpectations
) {
381 PushErrorMessage(kErrorMessage
[kErrorIllegalEntry
],
385 if ((kTokenData
[token
].flag
& entry
.test_expectation
) != 0) {
386 PushErrorMessage(kErrorMessage
[kErrorEntryWithExpectationConflicts
],
390 entry
.test_expectation
=
391 (kTokenData
[token
].flag
| entry
.test_expectation
);
392 if (stage
== kLineParserEqual
)
400 if (stage
== kLineParserBegin
) {
401 // The whole line is empty or all comments
404 if (stage
== kLineParserExpectations
) {
405 if (!config
.IsValid()) {
406 PushErrorMessage(kErrorMessage
[kErrorInvalidEntry
], line_number
);
409 entries_
.push_back(entry
);
412 PushErrorMessage(kErrorMessage
[kErrorIllegalEntry
], line_number
);
416 bool GPUTestExpectationsParser::UpdateTestConfig(
417 GPUTestConfig
* config
, int32 token
, size_t line_number
) {
421 case kConfigWinVista
:
426 case kConfigMacLeopard
:
427 case kConfigMacSnowLeopard
:
429 case kConfigMacMountainLion
:
430 case kConfigMacMavericks
:
431 case kConfigMacYosemite
:
434 case kConfigChromeOS
:
436 if ((config
->os() & kTokenData
[token
].flag
) != 0) {
437 PushErrorMessage(kErrorMessage
[kErrorEntryWithOsConflicts
],
441 config
->set_os(config
->os() | kTokenData
[token
].flag
);
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
) {
453 kErrorMessage
[kErrorEntryWithGpuVendorConflicts
],
458 config
->AddGPUVendor(gpu_vendor
);
463 if ((config
->build_type() & kTokenData
[token
].flag
) != 0) {
465 kErrorMessage
[kErrorEntryWithBuildTypeConflicts
],
469 config
->set_build_type(
470 config
->build_type() | kTokenData
[token
].flag
);
474 case kConfigGLDesktop
:
476 if ((config
->api() & kTokenData
[token
].flag
) != 0) {
477 PushErrorMessage(kErrorMessage
[kErrorEntryWithAPIConflicts
],
481 config
->set_api(config
->api() | kTokenData
[token
].flag
);
490 bool GPUTestExpectationsParser::UpdateTestConfig(
491 GPUTestConfig
* config
,
492 const std::string
& gpu_device_id
,
493 size_t line_number
) {
495 uint32 device_id
= 0;
496 if (config
->gpu_device_id() != 0 ||
497 !base::HexStringToUInt(gpu_device_id
, &device_id
) ||
499 PushErrorMessage(kErrorMessage
[kErrorEntryWithGpuDeviceIdConflicts
],
503 config
->set_gpu_device_id(device_id
);
507 bool GPUTestExpectationsParser::DetectConflictsBetweenEntries() {
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
);
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
),
541 GPUTestExpectationsParser:: GPUTestExpectationEntry::GPUTestExpectationEntry()
542 : test_expectation(0),