blob: e9beafd6eb8f2268e220ee068ebaa20c818fd8f7 [file] [log] [blame]
Moritz Pflanzerfc95ed22017-07-05 11:07:07 +01001/*
2 * Copyright (c) 2017 ARM Limited.
3 *
4 * SPDX-License-Identifier: MIT
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in all
14 * copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24#ifndef ARM_COMPUTE_TEST_FRAMEWORK
25#define ARM_COMPUTE_TEST_FRAMEWORK
26
27#include "TestCase.h"
28#include "TestCaseFactory.h"
29#include "TestResult.h"
30#include "Utils.h"
31
32#include <algorithm>
33#include <chrono>
34#include <map>
35#include <memory>
36#include <numeric>
37#include <ostream>
38#include <regex>
39#include <set>
40#include <sstream>
41#include <string>
42#include <tuple>
43#include <vector>
44
45namespace arm_compute
46{
47namespace test
48{
49namespace framework
50{
51/** Main framework class.
52 *
53 * Keeps track of the global state, owns all test cases and collects results.
54 */
55class Framework final
56{
57public:
58 /** Type of a test identifier.
59 *
60 * A test can be identified either via its id or via its name.
61 *
62 * @note The mapping between test id and test name is not guaranteed to be
63 * stable. It is subject to change as new test are added.
64 */
65 using TestId = std::pair<int, std::string>;
66
67 /** Access to the singleton.
68 *
69 * @return Unique instance of the framework class.
70 */
71 static Framework &get();
72
73 /** Init the framework.
74 *
75 * @param[in] num_iterations Number of iterations per test.
76 * @param[in] name_filter Regular expression to filter tests by name. Only matching tests will be executed.
77 * @param[in] id_filter Regular expression to filter tests by id. Only matching tests will be executed.
78 */
79 void init(int num_iterations, const std::string &name_filter, const std::string &id_filter);
80
81 /** Add a new test suite.
82 *
83 * @warning Cannot be used at execution time. It can only be used for
84 * registering test cases.
85 *
86 * @param[in] name Name of the added test suite.
87 *
88 * @return Name of the current test suite.
89 */
90 void push_suite(std::string name);
91
92 /** Remove innermost test suite.
93 *
94 * @warning Cannot be used at execution time. It can only be used for
95 * registering test cases.
96 */
97 void pop_suite();
98
99 /** Add a test case to the framework.
100 *
101 * @param[in] test_name Name of the new test case.
102 */
103 template <typename T>
104 void add_test_case(std::string test_name);
105
106 /** Add a data test case to the framework.
107 *
108 * @param[in] test_name Name of the new test case.
109 * @param[in] description Description of @p data.
110 * @param[in] data Data that will be used as input to the test.
111 */
112 template <typename T, typename D>
113 void add_data_test_case(std::string test_name, std::string description, D &&data);
114
115 /** Tell the framework that execution of a test starts.
116 *
117 * @param[in] test_name Name of the started test case.
118 */
119 void log_test_start(const std::string &test_name);
120
121 /** Tell the framework that a test case is skipped.
122 *
123 * @param[in] test_name Name of the skipped test case.
124 */
125 void log_test_skipped(const std::string &test_name);
126
127 /** Tell the framework that a test case finished.
128 *
129 * @param[in] test_name Name of the finished test case.
130 */
131 void log_test_end(const std::string &test_name);
132
133 /** Tell the framework that the currently running test case failed a non-fatal expectation.
134 *
135 * @param[in] msg Description of the failure.
136 */
137 void log_failed_expectation(const std::string &msg);
138
139 /** Number of iterations per test case.
140 *
141 * @return Number of iterations per test case.
142 */
143 int num_iterations() const;
144
145 /** Set number of iterations per test case.
146 *
147 * @param[in] num_iterations Number of iterations per test case.
148 */
149 void set_num_iterations(int num_iterations);
150
151 /** Should errors be caught or thrown by the framework.
152 *
153 * @return True if errors are thrown.
154 */
155 bool throw_errors() const;
156
157 /** Set whether errors are caught or thrown by the framework.
158 *
159 * @param[in] throw_errors True if errors should be thrown.
160 */
161 void set_throw_errors(bool throw_errors);
162
163 /** Check if a test case would be executed.
164 *
165 * @param[in] id Id of the test case.
166 *
167 * @return True if the test case would be executed.
168 */
169 bool is_enabled(const TestId &id) const;
170
171 /** Run all enabled test cases.
172 *
173 * @return True if all test cases executed successful.
174 */
175 bool run();
176
177 /** Set the result for an executed test case.
178 *
179 * @param[in] test_case_name Name of the executed test case.
180 * @param[in] result Execution result.
181 */
182 void set_test_result(std::string test_case_name, TestResult result);
183
184 /** List of @ref TestId's.
185 *
186 * @return Vector with all test ids.
187 */
188 std::vector<Framework::TestId> test_ids() const;
189
190private:
191 Framework() = default;
192 ~Framework() = default;
193
194 Framework(const Framework &) = delete;
195 Framework &operator=(const Framework &) = delete;
196
197 void run_test(TestCaseFactory &test_factory);
198 std::tuple<int, int, int> count_test_results() const;
199
200 /** Returns the current test suite name.
201 *
202 * @warning Cannot be used at execution time to get the test suite of the
203 * currently executed test case. It can only be used for registering test
204 * cases.
205 *
206 * @return Name of the current test suite.
207 */
208 std::string current_suite_name() const;
209
210 std::vector<std::string> _test_suite_name{};
211 std::vector<std::unique_ptr<TestCaseFactory>> _test_factories{};
212 std::map<std::string, TestResult> _test_results{};
213 std::chrono::seconds _runtime{ 0 };
214 int _num_iterations{ 1 };
215 bool _throw_errors{ false };
216
217 std::regex _test_name_filter{ ".*" };
218 std::regex _test_id_filter{ ".*" };
219};
220
221template <typename T>
222inline void Framework::add_test_case(std::string test_name)
223{
224 _test_factories.emplace_back(support::cpp14::make_unique<SimpleTestCaseFactory<T>>(current_suite_name(), std::move(test_name)));
225}
226
227template <typename T, typename D>
228inline void Framework::add_data_test_case(std::string test_name, std::string description, D &&data)
229{
230 // WORKAROUND for GCC 4.9
231 // The function should get *it which is tuple but that seems to trigger a
232 // bug in the compiler.
233 auto tmp = std::unique_ptr<DataTestCaseFactory<T, decltype(*std::declval<D>())>>(new DataTestCaseFactory<T, decltype(*std::declval<D>())>(current_suite_name(), std::move(test_name),
234 std::move(description), *data));
235 _test_factories.emplace_back(std::move(tmp));
236}
237} // namespace framework
238} // namespace test
239} // namespace arm_compute
240#endif /* ARM_COMPUTE_TEST_FRAMEWORK */