blob: 25629dbb2b8d8c4852e5b4aba00896a5b4c7f8b4 [file] [log] [blame] [edit]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <zircon/assert.h>
#include <algorithm>
#include <cstdlib>
#include <memory>
#include <utility>
#include <fbl/auto_call.h>
#include <zxtest/base/test-case.h>
#include <zxtest/base/types.h>
namespace zxtest {
namespace {
using internal::SetUpTestCaseFn;
using internal::TearDownTestCaseFn;
using internal::TestDriver;
using internal::TestStatus;
} // namespace
TestCase::TestCase(const fbl::String& name, SetUpTestCaseFn set_up, TearDownTestCaseFn tear_down)
: name_(name), set_up_(std::move(set_up)), tear_down_(std::move(tear_down)) {
ZX_ASSERT_MSG(set_up_, "Invalid SetUpTestCaseFn");
ZX_ASSERT_MSG(tear_down_, "Invalid TearDownTestCaseFn");
}
TestCase::TestCase(TestCase&& other) = default;
TestCase::~TestCase() = default;
size_t TestCase::TestCount() const { return test_infos_.size(); }
size_t TestCase::MatchingTestCount() const { return selected_indexes_.size(); }
void TestCase::Filter(TestCase::FilterFn filter) {
fbl::Vector<unsigned long> filtered_indexes;
filtered_indexes.reserve(test_infos_.size());
for (unsigned long i = 0; i < test_infos_.size(); ++i) {
const auto& test_info = test_infos_[i];
if (!filter || filter(name_, test_info.name())) {
filtered_indexes.push_back(i);
}
}
selected_indexes_.swap(filtered_indexes);
}
void TestCase::Shuffle(uint32_t random_seed) {
for (unsigned long i = 1; i < selected_indexes_.size(); ++i) {
unsigned long j = rand_r(&random_seed) % (i + 1);
if (j != i) {
std::swap(selected_indexes_[i], selected_indexes_[j]);
}
}
}
void TestCase::UnShuffle() {
for (unsigned long i = 0; i < selected_indexes_.size(); ++i) {
selected_indexes_[i] = i;
}
}
bool TestCase::RegisterTest(const fbl::String& name, const SourceLocation& location,
internal::TestFactory factory) {
auto it = std::find_if(test_infos_.begin(), test_infos_.end(),
[&name](const TestInfo& info) { return info.name() == name; });
// Test already registered.
if (it != test_infos_.end()) {
return false;
}
selected_indexes_.push_back(selected_indexes_.size());
test_infos_.push_back(TestInfo(name, location, std::move(factory)));
return true;
}
void TestCase::Run(LifecycleObserver* event_broadcaster, TestDriver* driver) {
if (selected_indexes_.size() == 0) {
return;
}
auto tear_down = fbl::MakeAutoCall([this, event_broadcaster] {
tear_down_();
event_broadcaster->OnTestCaseEnd(*this);
});
event_broadcaster->OnTestCaseStart(*this);
set_up_();
if (!driver->Continue()) {
return;
}
for (unsigned long i = 0; i < selected_indexes_.size(); ++i) {
const auto& test_info = test_infos_[selected_indexes_[i]];
{
// This block enforces that the destructor is called before
// completing the test, for accurate error reporting.
// This prevents buggy destructors from crashing after a test completed,
// marking it as a success.
event_broadcaster->OnTestStart(*this, test_info);
std::unique_ptr<Test> test = test_info.Instantiate(driver);
test->Run();
}
switch (driver->Status()) {
case TestStatus::kPassed:
event_broadcaster->OnTestSuccess(*this, test_info);
break;
case TestStatus::kSkipped:
event_broadcaster->OnTestSkip(*this, test_info);
break;
case TestStatus::kFailed:
event_broadcaster->OnTestFailure(*this, test_info);
if (return_on_failure_) {
return;
}
break;
default:
break;
}
}
}
} // namespace zxtest