166 lines
5.3 KiB
C++
166 lines
5.3 KiB
C++
|
|
// Copyright 2019 The Chromium Authors
|
||
|
|
// Use of this source code is governed by a BSD-style license that can be
|
||
|
|
// found in the LICENSE file.
|
||
|
|
|
||
|
|
#include "base/test/launcher/test_launcher_test_utils.h"
|
||
|
|
|
||
|
|
#include "base/files/file_util.h"
|
||
|
|
#include "base/json/json_reader.h"
|
||
|
|
#include "base/json/json_writer.h"
|
||
|
|
#include "base/test/gtest_util.h"
|
||
|
|
#include "base/test/launcher/test_result.h"
|
||
|
|
#include "third_party/abseil-cpp/absl/types/optional.h"
|
||
|
|
|
||
|
|
namespace base {
|
||
|
|
|
||
|
|
namespace test_launcher_utils {
|
||
|
|
|
||
|
|
namespace {
|
||
|
|
|
||
|
|
// Helper function to return |Value::Dict::FindString| by value instead of
|
||
|
|
// pointer to string, or empty string if nullptr.
|
||
|
|
std::string FindStringKeyOrEmpty(const Value::Dict& dict,
|
||
|
|
const std::string& key) {
|
||
|
|
const std::string* value = dict.FindString(key);
|
||
|
|
return value ? *value : std::string();
|
||
|
|
}
|
||
|
|
|
||
|
|
// Find and return test case with name |test_case_name|,
|
||
|
|
// return null if missing.
|
||
|
|
const testing::TestCase* GetTestCase(const std::string& test_case_name) {
|
||
|
|
testing::UnitTest* const unit_test = testing::UnitTest::GetInstance();
|
||
|
|
for (int i = 0; i < unit_test->total_test_case_count(); ++i) {
|
||
|
|
const testing::TestCase* test_case = unit_test->GetTestCase(i);
|
||
|
|
if (test_case->name() == test_case_name)
|
||
|
|
return test_case;
|
||
|
|
}
|
||
|
|
return nullptr;
|
||
|
|
}
|
||
|
|
|
||
|
|
} // namespace
|
||
|
|
|
||
|
|
bool ValidateKeyValue(const Value::Dict& dict,
|
||
|
|
const std::string& key,
|
||
|
|
const std::string& expected_value) {
|
||
|
|
std::string actual_value = FindStringKeyOrEmpty(dict, key);
|
||
|
|
bool result = !actual_value.compare(expected_value);
|
||
|
|
if (!result)
|
||
|
|
ADD_FAILURE() << key << " expected value: " << expected_value
|
||
|
|
<< ", actual: " << actual_value;
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool ValidateKeyValue(const Value::Dict& dict,
|
||
|
|
const std::string& key,
|
||
|
|
int64_t expected_value) {
|
||
|
|
int actual_value = dict.FindInt(key).value_or(0);
|
||
|
|
bool result = (actual_value == expected_value);
|
||
|
|
if (!result)
|
||
|
|
ADD_FAILURE() << key << " expected value: " << expected_value
|
||
|
|
<< ", actual: " << actual_value;
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool ValidateTestResult(const Value::Dict& iteration_data,
|
||
|
|
const std::string& test_name,
|
||
|
|
const std::string& status,
|
||
|
|
size_t result_part_count,
|
||
|
|
bool have_running_info) {
|
||
|
|
const Value::List* results = iteration_data.FindList(test_name);
|
||
|
|
if (!results) {
|
||
|
|
ADD_FAILURE() << "Cannot find result";
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
if (1u != results->size()) {
|
||
|
|
ADD_FAILURE() << "Expected one result";
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
const Value::Dict* dict = (*results)[0].GetIfDict();
|
||
|
|
if (!dict) {
|
||
|
|
ADD_FAILURE() << "Value must be of type DICTIONARY";
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!ValidateKeyValue(*dict, "status", status))
|
||
|
|
return false;
|
||
|
|
|
||
|
|
// Verify the keys that only exists when have_running_info, if the test didn't
|
||
|
|
// run, it wouldn't have these information.
|
||
|
|
for (auto* key : {"process_num", "thread_id", "timestamp"}) {
|
||
|
|
bool have_key = dict->Find(key);
|
||
|
|
if (have_running_info && !have_key) {
|
||
|
|
ADD_FAILURE() << "Result must contain '" << key << "' key";
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
if (!have_running_info && have_key) {
|
||
|
|
ADD_FAILURE() << "Result shouldn't contain '" << key << "' key";
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
const Value::List* list = dict->FindList("result_parts");
|
||
|
|
if (!list) {
|
||
|
|
ADD_FAILURE() << "Result must contain 'result_parts' key";
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (result_part_count != list->size()) {
|
||
|
|
ADD_FAILURE() << "result_parts count expected: " << result_part_count
|
||
|
|
<< ", actual:" << list->size();
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool ValidateTestLocations(const Value::Dict& test_locations,
|
||
|
|
const std::string& test_case_name) {
|
||
|
|
const testing::TestCase* test_case = GetTestCase(test_case_name);
|
||
|
|
if (test_case == nullptr) {
|
||
|
|
ADD_FAILURE() << "Could not find test case " << test_case_name;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
bool result = true;
|
||
|
|
for (int j = 0; j < test_case->total_test_count(); ++j) {
|
||
|
|
const testing::TestInfo* test_info = test_case->GetTestInfo(j);
|
||
|
|
std::string full_name =
|
||
|
|
FormatFullTestName(test_case->name(), test_info->name());
|
||
|
|
result &= ValidateTestLocation(test_locations, full_name, test_info->file(),
|
||
|
|
test_info->line());
|
||
|
|
}
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool ValidateTestLocation(const Value::Dict& test_locations,
|
||
|
|
const std::string& test_name,
|
||
|
|
const std::string& file,
|
||
|
|
int line) {
|
||
|
|
const Value::Dict* dict =
|
||
|
|
test_locations.FindDict(TestNameWithoutDisabledPrefix(test_name));
|
||
|
|
if (!dict) {
|
||
|
|
ADD_FAILURE() << "|test_locations| missing location for " << test_name;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool result = ValidateKeyValue(*dict, "file", file);
|
||
|
|
result &= ValidateKeyValue(*dict, "line", line);
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
absl::optional<Value::Dict> ReadSummary(const FilePath& path) {
|
||
|
|
absl::optional<Value::Dict> result;
|
||
|
|
File resultFile(path, File::FLAG_OPEN | File::FLAG_READ);
|
||
|
|
const int size = 2e7;
|
||
|
|
std::string json;
|
||
|
|
CHECK(ReadFileToStringWithMaxSize(path, &json, size));
|
||
|
|
absl::optional<Value> value = JSONReader::Read(json);
|
||
|
|
if (value && value->is_dict())
|
||
|
|
result = std::move(*value).TakeDict();
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
} // namespace test_launcher_utils
|
||
|
|
|
||
|
|
} // namespace base
|