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