1 // Copyright 2018 The Fuchsia 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.
4
5 #include <algorithm>
6 #include <cstdlib>
7 #include <memory>
8 #include <utility>
9
10 #include <fbl/auto_call.h>
11 #include <zircon/assert.h>
12 #include <zxtest/base/test-case.h>
13
14 namespace zxtest {
15
16 namespace {
17
18 using internal::SetUpTestCaseFn;
19 using internal::TearDownTestCaseFn;
20 using internal::TestDriver;
21 using internal::TestStatus;
22
23 } // namespace
24
TestCase(const fbl::String & name,SetUpTestCaseFn set_up,TearDownTestCaseFn tear_down)25 TestCase::TestCase(const fbl::String& name, SetUpTestCaseFn set_up, TearDownTestCaseFn tear_down)
26 : name_(name), set_up_(std::move(set_up)), tear_down_(std::move(tear_down)) {
27 ZX_ASSERT_MSG(set_up_, "Invalid SetUpTestCaseFn");
28 ZX_ASSERT_MSG(tear_down_, "Invalid TearDownTestCaseFn");
29 }
30 TestCase::TestCase(TestCase&& other) = default;
31 TestCase::~TestCase() = default;
32
TestCount() const33 size_t TestCase::TestCount() const {
34 return test_infos_.size();
35 }
36
MatchingTestCount() const37 size_t TestCase::MatchingTestCount() const {
38 return selected_indexes_.size();
39 }
40
Filter(TestCase::FilterFn filter)41 void TestCase::Filter(TestCase::FilterFn filter) {
42 fbl::Vector<unsigned long> filtered_indexes;
43 filtered_indexes.reserve(test_infos_.size());
44 for (unsigned long i = 0; i < test_infos_.size(); ++i) {
45 const auto& test_info = test_infos_[i];
46 if (!filter || filter(name_, test_info.name())) {
47 filtered_indexes.push_back(i);
48 }
49 }
50 selected_indexes_.swap(filtered_indexes);
51 }
52
Shuffle(std::uint32_t random_seed)53 void TestCase::Shuffle(std::uint32_t random_seed) {
54 for (unsigned long i = 1; i < selected_indexes_.size(); ++i) {
55 unsigned long j = rand_r(&random_seed) % (i + 1);
56 if (j != i) {
57 std::swap(selected_indexes_[i], selected_indexes_[j]);
58 }
59 }
60 }
61
UnShuffle()62 void TestCase::UnShuffle() {
63 for (unsigned long i = 0; i < selected_indexes_.size(); ++i) {
64 selected_indexes_[i] = i;
65 }
66 }
67
RegisterTest(const fbl::String & name,const SourceLocation & location,internal::TestFactory factory)68 bool TestCase::RegisterTest(const fbl::String& name, const SourceLocation& location,
69 internal::TestFactory factory) {
70 auto it = std::find_if(test_infos_.begin(), test_infos_.end(),
71 [&name](const TestInfo& info) { return info.name() == name; });
72
73 // Test already registered.
74 if (it != test_infos_.end()) {
75 return false;
76 }
77
78 selected_indexes_.push_back(selected_indexes_.size());
79 test_infos_.push_back(TestInfo(name, location, std::move(factory)));
80 return true;
81 }
82
Run(LifecycleObserver * event_broadcaster,TestDriver * driver)83 void TestCase::Run(LifecycleObserver* event_broadcaster, TestDriver* driver) {
84 auto tear_down = fbl::MakeAutoCall([this, event_broadcaster] {
85 tear_down_();
86 event_broadcaster->OnTestCaseEnd(*this);
87 });
88 event_broadcaster->OnTestCaseStart(*this);
89 set_up_();
90
91 if (!driver->Continue()) {
92 return;
93 }
94
95 for (unsigned long i = 0; i < selected_indexes_.size(); ++i) {
96 const auto& test_info = test_infos_[selected_indexes_[i]];
97 std::unique_ptr<Test> test = test_info.Instantiate(driver);
98 event_broadcaster->OnTestStart(*this, test_info);
99 test->Run();
100 switch (driver->Status()) {
101 case TestStatus::kPassed:
102 event_broadcaster->OnTestSuccess(*this, test_info);
103 break;
104 case TestStatus::kSkipped:
105 event_broadcaster->OnTestSkip(*this, test_info);
106 break;
107 case TestStatus::kFailed:
108 event_broadcaster->OnTestFailure(*this, test_info);
109 break;
110 default:
111 break;
112 }
113 }
114 }
115
116 } // namespace zxtest
117