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
,
36 kConfigMacSnowLeopard
,
38 kConfigMacMountainLion
,
63 kNumberOfExactMatchTokens
,
76 const TokenInfo kTokenData
[] = {
77 { "xp", GPUTestConfig::kOsWinXP
},
78 { "vista", GPUTestConfig::kOsWinVista
},
79 { "win7", GPUTestConfig::kOsWin7
},
80 { "win8", GPUTestConfig::kOsWin8
},
81 { "win", GPUTestConfig::kOsWin
},
82 { "leopard", GPUTestConfig::kOsMacLeopard
},
83 { "snowleopard", GPUTestConfig::kOsMacSnowLeopard
},
84 { "lion", GPUTestConfig::kOsMacLion
},
85 { "mountainlion", GPUTestConfig::kOsMacMountainLion
},
86 { "mavericks", GPUTestConfig::kOsMacMavericks
},
87 { "yosemite", GPUTestConfig::kOsMacYosemite
},
88 { "mac", GPUTestConfig::kOsMac
},
89 { "linux", GPUTestConfig::kOsLinux
},
90 { "chromeos", GPUTestConfig::kOsChromeOS
},
91 { "android", GPUTestConfig::kOsAndroid
},
96 { "release", GPUTestConfig::kBuildTypeRelease
},
97 { "debug", GPUTestConfig::kBuildTypeDebug
},
98 { "pass", GPUTestExpectationsParser::kGpuTestPass
},
99 { "fail", GPUTestExpectationsParser::kGpuTestFail
},
100 { "flaky", GPUTestExpectationsParser::kGpuTestFlaky
},
101 { "timeout", GPUTestExpectationsParser::kGpuTestTimeout
},
102 { "skip", GPUTestExpectationsParser::kGpuTestSkip
},
111 kErrorEntryWithOsConflicts
,
112 kErrorEntryWithGpuVendorConflicts
,
113 kErrorEntryWithBuildTypeConflicts
,
114 kErrorEntryWithGpuDeviceIdConflicts
,
115 kErrorEntryWithExpectationConflicts
,
116 kErrorEntriesOverlap
,
121 const char* kErrorMessage
[] = {
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",
133 Token
ParseToken(const std::string
& word
) {
134 if (StartsWithASCII(word
, "//", false))
135 return kTokenComment
;
136 if (StartsWithASCII(word
, "0x", false))
137 return kConfigGPUDeviceID
;
139 for (int32 i
= 0; i
< kNumberOfExactMatchTokens
; ++i
) {
140 if (LowerCaseEqualsASCII(word
, kTokenData
[i
].name
))
141 return static_cast<Token
>(i
);
146 // reference name can have the last character as *.
147 bool NamesMatching(const std::string
& ref
, const std::string
& test_name
) {
148 size_t len
= ref
.length();
151 if (ref
[len
- 1] == '*') {
152 if (test_name
.length() > len
-1 &&
153 ref
.compare(0, len
- 1, test_name
, 0, len
- 1) == 0)
157 return (ref
== test_name
);
160 } // namespace anonymous
162 GPUTestExpectationsParser::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]));
170 GPUTestExpectationsParser::~GPUTestExpectationsParser() {
173 bool GPUTestExpectationsParser::LoadTestExpectations(const std::string
& data
) {
175 error_messages_
.clear();
177 std::vector
<std::string
> lines
;
178 base::SplitString(data
, '\n', &lines
);
180 for (size_t i
= 0; i
< lines
.size(); ++i
) {
181 if (!ParseLine(lines
[i
], i
+ 1))
184 if (DetectConflictsBetweenEntries()) {
192 bool GPUTestExpectationsParser::LoadTestExpectations(
193 const base::FilePath
& path
) {
195 error_messages_
.clear();
198 if (!base::ReadFileToString(path
, &data
)) {
199 error_messages_
.push_back(kErrorMessage
[kErrorFileIO
]);
202 return LoadTestExpectations(data
);
205 int32
GPUTestExpectationsParser::GetTestExpectation(
206 const std::string
& test_name
,
207 const GPUTestBotConfig
& bot_config
) const {
208 for (size_t i
= 0; i
< entries_
.size(); ++i
) {
209 if (NamesMatching(entries_
[i
].test_name
, test_name
) &&
210 bot_config
.Matches(entries_
[i
].test_config
))
211 return entries_
[i
].test_expectation
;
216 const std::vector
<std::string
>&
217 GPUTestExpectationsParser::GetErrorMessages() const {
218 return error_messages_
;
221 bool GPUTestExpectationsParser::ParseConfig(
222 const std::string
& config_data
, GPUTestConfig
* config
) {
224 std::vector
<std::string
> tokens
;
225 base::SplitStringAlongWhitespace(config_data
, &tokens
);
227 for (size_t i
= 0; i
< tokens
.size(); ++i
) {
228 Token token
= ParseToken(tokens
[i
]);
231 case kConfigWinVista
:
235 case kConfigMacLeopard
:
236 case kConfigMacSnowLeopard
:
238 case kConfigMacMountainLion
:
239 case kConfigMacMavericks
:
240 case kConfigMacYosemite
:
243 case kConfigChromeOS
:
251 case kConfigGPUDeviceID
:
252 if (token
== kConfigGPUDeviceID
) {
253 if (!UpdateTestConfig(config
, tokens
[i
], 0))
256 if (!UpdateTestConfig(config
, token
, 0))
267 bool 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
]);
280 comments_encountered
= true;
283 case kConfigWinVista
:
287 case kConfigMacLeopard
:
288 case kConfigMacSnowLeopard
:
290 case kConfigMacMountainLion
:
291 case kConfigMacMavericks
:
292 case kConfigMacYosemite
:
295 case kConfigChromeOS
:
303 case kConfigGPUDeviceID
:
304 // MODIFIERS, could be in any order, need at least one.
305 if (stage
!= kLineParserConfigs
&& stage
!= kLineParserBugID
) {
306 PushErrorMessage(kErrorMessage
[kErrorIllegalEntry
],
310 if (token
== kConfigGPUDeviceID
) {
311 if (!UpdateTestConfig(&config
, tokens
[i
], line_number
))
314 if (!UpdateTestConfig(&config
, token
, line_number
))
317 if (stage
== kLineParserBugID
)
320 case kSeparatorColon
:
322 if (stage
!= kLineParserConfigs
) {
323 PushErrorMessage(kErrorMessage
[kErrorIllegalEntry
],
329 case kSeparatorEqual
:
331 if (stage
!= kLineParserTestName
) {
332 PushErrorMessage(kErrorMessage
[kErrorIllegalEntry
],
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
];
345 PushErrorMessage(kErrorMessage
[kErrorIllegalEntry
],
351 case kExpectationPass
:
352 case kExpectationFail
:
353 case kExpectationFlaky
:
354 case kExpectationTimeout
:
355 case kExpectationSkip
:
357 if (stage
!= kLineParserEqual
&& stage
!= kLineParserExpectations
) {
358 PushErrorMessage(kErrorMessage
[kErrorIllegalEntry
],
362 if ((kTokenData
[token
].flag
& entry
.test_expectation
) != 0) {
363 PushErrorMessage(kErrorMessage
[kErrorEntryWithExpectationConflicts
],
367 entry
.test_expectation
=
368 (kTokenData
[token
].flag
| entry
.test_expectation
);
369 if (stage
== kLineParserEqual
)
377 if (stage
== kLineParserBegin
) {
378 // The whole line is empty or all comments
381 if (stage
== kLineParserExpectations
) {
382 if (!config
.IsValid()) {
383 PushErrorMessage(kErrorMessage
[kErrorInvalidEntry
], line_number
);
386 entries_
.push_back(entry
);
389 PushErrorMessage(kErrorMessage
[kErrorIllegalEntry
], line_number
);
393 bool GPUTestExpectationsParser::UpdateTestConfig(
394 GPUTestConfig
* config
, int32 token
, size_t line_number
) {
398 case kConfigWinVista
:
402 case kConfigMacLeopard
:
403 case kConfigMacSnowLeopard
:
405 case kConfigMacMountainLion
:
406 case kConfigMacMavericks
:
407 case kConfigMacYosemite
:
410 case kConfigChromeOS
:
412 if ((config
->os() & kTokenData
[token
].flag
) != 0) {
413 PushErrorMessage(kErrorMessage
[kErrorEntryWithOsConflicts
],
417 config
->set_os(config
->os() | kTokenData
[token
].flag
);
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
) {
429 kErrorMessage
[kErrorEntryWithGpuVendorConflicts
],
434 config
->AddGPUVendor(gpu_vendor
);
439 if ((config
->build_type() & kTokenData
[token
].flag
) != 0) {
441 kErrorMessage
[kErrorEntryWithBuildTypeConflicts
],
445 config
->set_build_type(
446 config
->build_type() | kTokenData
[token
].flag
);
455 bool GPUTestExpectationsParser::UpdateTestConfig(
456 GPUTestConfig
* config
,
457 const std::string
& gpu_device_id
,
458 size_t line_number
) {
460 uint32 device_id
= 0;
461 if (config
->gpu_device_id() != 0 ||
462 !base::HexStringToUInt(gpu_device_id
, &device_id
) ||
464 PushErrorMessage(kErrorMessage
[kErrorEntryWithGpuDeviceIdConflicts
],
468 config
->set_gpu_device_id(device_id
);
472 bool GPUTestExpectationsParser::DetectConflictsBetweenEntries() {
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
);
488 void 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()));
495 void 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
),
506 GPUTestExpectationsParser:: GPUTestExpectationEntry::GPUTestExpectationEntry()
507 : test_expectation(0),