blob: 6da9ff0a5e806419423e61bf7be2ef5d9327a558 [file] [log] [blame]
// 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.
#pragma once
#include <cstdio>
#include <fbl/string.h>
#include <fbl/vector.h>
#include <zxtest/base/assertion.h>
#include <zxtest/base/event-broadcaster.h>
#include <zxtest/base/observer.h>
#include <zxtest/base/reporter.h>
#include <zxtest/base/test-case.h>
#include <zxtest/base/test-driver.h>
#include <zxtest/base/test-info.h>
namespace zxtest {
namespace internal {
// Test Driver implementation for the runner. Observes lifecycle events to
// reset the test state correctly.
class TestDriverImpl : public TestDriver, public LifecycleObserver {
public:
TestDriverImpl();
~TestDriverImpl() final;
// Called when a test is skipped.
void Skip() final;
// Return true if the is allowed to continue execution.
bool Continue() const final;
// Returns the status of the current test.
TestStatus Status() const final { return status_; }
// Reports before every test starts.
void OnTestStart(const TestCase& test_case, const TestInfo& test) final;
// Reports when current test assert condition fails.
void OnAssertion(const Assertion& assertion) final;
// Reports after a test execution was skipped.
void OnTestSkip(const TestCase& test_case, const TestInfo& test) final;
// Reports after test execution completed with failures.
void OnTestFailure(const TestCase& test_case, const TestInfo& test) final;
// Reports after test execution completed with no failures.
void OnTestSuccess(const TestCase& test_case, const TestInfo& test) final;
// Resets the states for running new tests.
void Reset();
// Returns whether any test driven by this instance had any test failure.
// This is not cleared on |TestDriverImpl::Reset|.
bool HadAnyFailures() const { return had_any_failures_; }
private:
TestStatus status_ = TestStatus::kFailed;
bool has_fatal_failures_ = false;
bool had_any_failures_ = false;
};
} // namespace internal
// Struct used to safely reference a registered test. This is not affected
// by vector growth.
struct TestRef {
size_t test_case_index = 0;
size_t test_index = 0;
};
// Returns the amount of registered and active test and testcases.
struct RunnerSummary {
// Number of iterations to run.
size_t total_iterations = 1;
// Number of registered tests that match a filter.
size_t active_test_count = 0;
// Number of registered test cases that match a filter.
size_t active_test_case_count = 0;
// Number of registered tests.
size_t registered_test_count = 0;
// Number of registered test cases.
size_t registered_test_case_count = 0;
};
// Holds the pattern used for filtering.
struct FilterOp {
// Returns true if the test_case and test matches |pattern|.
bool operator()(const fbl::String& test_case, const fbl::String& test) const;
fbl::String pattern;
};
// This class is the entry point for test and constructs registration.
class Runner {
public:
struct Options {
// Parses the contents of argv into |Options|.
static Options FromArgs(int argc, char** argv, fbl::Vector<fbl::String>* errors);
// Prints the usage message into the |stream|.
static void Usage(char* bin, FILE* stream);
// Pattern for filtering tests. Empty pattern matches all.
fbl::String filter;
// Seed used for random decisions.
int seed = 0;
// Number of iterations to run.
int repeat = 1;
// When set test order within a test case are randomized.
bool shuffle = false;
// When set prints the help message.
bool help = false;
// When set list all registered tests.
bool list = false;
};
// Default Runner options.
static const Options kDefaultOptions;
// Returns process shared |Runner| instance.
static Runner* GetInstance();
Runner() = delete;
explicit Runner(Reporter&& reporter);
Runner(const Runner&) = delete;
Runner(Runner&&) = delete;
~Runner();
Runner& operator=(const Runner&) = delete;
Runner& operator=(Runner&&) = delete;
// Register a test for execution with the default factory.
template <typename TestBase, typename TestImpl>
TestRef RegisterTest(const fbl::String& test_case_name, const fbl::String& test_name,
const char* filename, int line) {
return RegisterTest<TestBase, TestImpl>(test_case_name, test_name, filename, line,
&Test::Create<TestImpl>);
}
// Register a test for execution with a customized factory.
template <typename TestBase, typename TestImpl>
TestRef RegisterTest(const fbl::String& test_case_name, const fbl::String& test_name,
const char* filename, int line, internal::TestFactory factory) {
static_assert(std::is_base_of<Test, TestImpl>::value, "Must inherit from Test");
SourceLocation location = {.filename = filename, .line_number = line};
return RegisterTest(test_case_name, test_name, location, std::move(factory),
&TestBase::SetUpTestCase, &TestBase::TearDownTestCase);
}
// Runs the registered tests with the specified |options|.
int Run(const Options& options);
// List tests according to options.
void List(const Options& options);
const RunnerSummary& summary() const { return summary_; }
const TestInfo& GetTestInfo(const TestRef& test_ref) {
return test_cases_[test_ref.test_case_index].GetTestInfo(test_ref.test_index);
}
// Provides an entry point for asertions. The runner will propagate the assertion to the
// interested parties. This is needed in a global scope, because helper methods do not have
// access to a |Test| instance and legacy tests are not part of a Fixture, but wrapped by one.
// If this is called without any test running, it will have no effect.
void NotifyAssertion(const Assertion& assertion);
// Returns true if the current test should be aborted. This happens as a result of a fatal
// failure.
bool ShouldAbortCurrentTest() { return !test_driver_.Continue(); }
private:
TestRef RegisterTest(const fbl::String& test_case_name, const fbl::String& test_name,
const SourceLocation& location, internal::TestFactory factory,
internal::SetUpTestCaseFn set_up, internal::TearDownTestCaseFn tear_down);
void Filter(const fbl::String& pattern);
// List of registered test cases.
fbl::Vector<TestCase> test_cases_;
// Serves as a |LifecycleObserver| list where events are sent to all subscribed observers.
internal::EventBroadcaster event_broadcaster_;
// Driver owned by the |Runner| instance, which drives tests registered for execution
// with the given instance. We need at the |Runner| level, to reduce the amount of piping
// and exposure of the internal classes, so we can propagate errors in Helper methods
// or those that are not within a Fixture scope.
internal::TestDriverImpl test_driver_;
// Provides human readable output.
Reporter reporter_;
// Runner information.
RunnerSummary summary_;
};
// Entry point for C++
int RunAllTests(int argc, char** argv);
} // namespace zxtest