28namespace sequoia::testing
30 enum class runner_mode { none=0, help=1, test=2, create=4, init=8};
32 enum class update_mode { none = 0, soft };
34 enum class recovery_mode { none = 0, recovery = 1, dump = 2 };
36 enum class prune_outcome { not_attempted, no_time_stamp, success };
45NAMESPACE_SEQUOIA_AS_BITMASK
48 struct as_bitmask<sequoia::testing::runner_mode> : std::true_type {};
51 struct as_bitmask<sequoia::testing::recovery_mode> : std::true_type {};
54namespace sequoia::testing
56 individual_materials_paths set_materials(
const std::filesystem::path& sourceFile,
const project_paths& projPaths, std::vector<std::filesystem::path>& materialsPaths);
64 : m_pTest{std::make_unique<essence<Test>>(std::forward<Test>(t))}
66 if constexpr(!is_parallelizable_v<Test>)
67 m_Parallelizable = parallelizable_candidate::no;
77 const std::string& name()
const noexcept
79 return m_pTest->name();
85 return m_pTest->summary_file_path();
89 std::filesystem::path source_file()
const
91 return m_pTest->source_file();
95 std::filesystem::path working_materials()
const
97 return m_pTest->working_materials();
101 std::filesystem::path predictive_materials()
const
103 return m_pTest->predictive_materials();
107 bool parallelizable()
const noexcept
109 return m_Parallelizable == parallelizable_candidate::yes;
113 log_summary execute(std::optional<std::size_t> index)
115 return m_pTest->execute(index);
118 void reset(
const project_paths& projPaths, std::vector<std::filesystem::path>& materialsPaths)
120 m_pTest->reset(projPaths, materialsPaths);
123 static void versioned_write(
const std::filesystem::path& file,
const failure_output& output);
124 static void versioned_write(
const std::filesystem::path& file, std::string_view text);
128 virtual ~soul() =
default;
130 virtual const std::string& name()
const noexcept = 0;
132 virtual std::filesystem::path source_file()
const = 0;
133 virtual std::filesystem::path working_materials()
const = 0;
134 virtual std::filesystem::path predictive_materials()
const = 0;
136 virtual log_summary execute(std::optional<std::size_t> index) = 0;
137 virtual void reset(
const project_paths& projPaths, std::vector<std::filesystem::path>& materialsPaths) = 0;
140 template<concrete_test Test>
141 class essence final :
public soul
144 essence(Test&& t) : m_Test{std::forward<Test>(t)}
148 std::filesystem::path source_file()
const final
150 return m_Test.source_file();
154 const std::string& name()
const noexcept final
156 return m_Test.name();
162 return m_Test.summary_file_path();
166 std::filesystem::path working_materials()
const final
168 return m_Test.working_materials();
172 std::filesystem::path predictive_materials()
const final
174 return m_Test.predictive_materials();
178 log_summary execute(std::optional<std::size_t> index)
final
186 catch(
const std::exception& e)
188 m_Test.log_critical_failure(m_Test.source_file(),
"Unexpected", e.what());
192 m_Test.log_critical_failure(m_Test.source_file(),
"Unknown",
"");
195 m_Test.write_instability_analysis_output(m_Test.source_file(), index);
197 return write_versioned_output(t);
200 void reset(
const project_paths& projPaths, std::vector<std::filesystem::path>& materialsPaths)
final
202 m_Test.reset_results();
203 set_materials(m_Test.source_file(), projPaths, materialsPaths);
208 auto summary{m_Test.summarize(t.time_elapsed())};
210 if(!m_Test.has_critical_failures())
212 versioned_write(m_Test.diagnostics_file_paths().false_positive_or_negative_file_path(), summary.diagnostics_output());
213 versioned_write(m_Test.diagnostics_file_paths().caught_exceptions_file_path(), summary.caught_exceptions_output());
222 enum class parallelizable_candidate :
bool { no, yes };
224 std::unique_ptr<soul> m_pTest{};
225 parallelizable_candidate m_Parallelizable{parallelizable_candidate::yes};
228 template<concrete_test T>
230 std::optional<std::string> get_output_discriminator(
const T& test){
231 if constexpr(has_discriminated_output_v<T>)
232 return test.output_discriminator();
237 template<concrete_test T>
239 std::optional<std::string> get_reduction_discriminator(
const T& test){
240 if constexpr(has_discriminated_summary_v<T>)
241 return test.summary_discriminator();
257 std::string copyright,
258 std::string codeIndent=
" ",
260 std::ostream& stream=std::cout);
269 requires (
sizeof...(Tests) > 0)
270 void add_test_suite(std::string_view name, Tests&&... tests)
272 using namespace object;
274 check_for_duplicates(name, tests...);
276 extract_suite_tree(name, m_Filter, std::forward<Tests>(tests)...);
279 template<
class... Suites>
280 requires (object::is_suite_v<Suites> && ...)
281 void add_test_suite(std::string_view name, Suites... s)
283 using namespace object;
285 extract_suite_tree(m_Filter,
suite{std::string{name}, std::move(s)...});
290 std::ostream& stream()
noexcept {
return *m_Stream; }
292 const project_paths& proj_paths()
const noexcept {
return m_ProjPaths; }
294 const std::string& copyright()
const noexcept {
return m_Copyright; }
296 const indentation& code_indent()
const noexcept {
return m_CodeIndent; }
299 enum class output_mode { standard = 0, verbose = 1 };
300 enum class instability_mode { none = 0, single_instance, coordinator, sandbox };
304 prune_mode mode{prune_mode::passive};
305 std::string include_cutoff{};
310 template<concrete_test Test>
312 normal_path operator()(
const Test& test)
const {
return test.source_file(); }
315 class path_equivalence
318 explicit path_equivalence(
const std::filesystem::path& repo)
326 const std::filesystem::path* m_Repo;
332 std::optional<test_vessel> optTest{};
338 std::string m_Copyright{};
341 std::ostream* m_Stream;
344 filter_type m_Filter{path_equivalence{proj_paths().tests().repo()}, test_to_path{}};
345 prune_info m_PruneInfo{};
347 runner_mode m_RunnerMode{runner_mode::none};
348 output_mode m_OutputMode{output_mode::standard};
349 update_mode m_UpdateMode{update_mode::none};
350 recovery_mode m_RecoveryMode{recovery_mode::none};
352 instability_mode m_InstabilityMode{instability_mode::none};
354 std::size_t m_NumReps{1},
358 void process_args(
int argc,
char** argv);
360 void check_argument_consistency();
362 void check_for_missing_tests();
365 bool concurrent_execution()
const noexcept {
return m_ConcurrencyMode != concurrency_mode::serial; }
371 void run_tests(std::optional<std::size_t>
id);
374 bool nothing_to_do();
377 bool in_mode(runner_mode m)
const noexcept {
return (m_RunnerMode & m) == m; }
382 prune_outcome do_prune();
384 template<
class Filter,
class Suite>
385 requires object::is_suite_v<Suite>
386 void extract_suite_tree(Filter&& filter, Suite&& s)
388 using namespace object;
390 if(!m_Suites.order())
392 m_Suites.add_node(suite_type::npos);
395 std::vector<std::filesystem::path> materialsPaths{};
398 const std::string suiteName{s.name};
400 extract_tree(std::forward<Suite>(s),
401 std::forward<Filter>(filter),
403 [] <
class... Ts> (
const suite<Ts...>&s) -> suite_node {
return {.summary{
log_summary{s.name}}}; },
404 [
this, &suiteName, &materialsPaths]<
concrete_test T>(T&& test) -> suite_node {
405 test = T{test.name(),
409 set_materials(test.source_file(), proj_paths(), materialsPaths),
410 make_active_recovery_paths(m_RecoveryMode, proj_paths()),
411 get_output_discriminator(test),
412 get_reduction_discriminator(test)};
414 return {.summary{
log_summary{test.name()}}, .optTest{std::move(test)}};
422 requires (
sizeof...(Tests) > 0)
423 void extract_suite_tree(std::string_view name, Filter&& filter, Tests&&... tests)
425 extract_suite_tree(std::forward<Filter>(filter),
object::suite{std::string{name}, std::forward<Tests>(tests)...});
429 requires (
sizeof...(Tests) > 0)
430 static void check_for_duplicates(std::string_view name,
const Tests&... tests)
432 using duplicate_set = std::set<std::pair<std::string_view, std::filesystem::path>>;
434 duplicate_set namesAndSources{};
438 if(!namesAndSources.emplace(test.name(), test.source_file()).second)
439 throw std::runtime_error{duplication_message(name, test.name(), test.source_file())};
447 static std::string duplication_message(std::string_view suiteName, std::string_view testName,
const std::filesystem::path& source);
Utilities to aid logical operations.
Facility to detect changes on disk and only run the relevant tests.
Restriction of Dynamic Graphs to Trees.
bool check(CheckType flavour, std::string description, test_logger< Mode > &logger, Iter first, Sentinel last, PredictionIter predictionFirst, PredictionSentinel predictionLast, tutor< Advisor > advisor={})
The workhorse for comparing the contents of ranges.
Definition: FreeCheckers.hpp:377
Platform-dependent utilities.
A collection of functions for formatting test output.
Utilities for defining a suite of objects, filtered at runtime.
Utilities for recording the outcome of tests.
concurrency_mode
Definition: TestRunner.hpp:38
@ dynamic
serial execution
@ fixed
determined implicitly by the stl
Tasks may be pushed, upon which they are immediately invoked.
Definition: ConcurrencyModels.hpp:150
Type-safe mechanism for indentations.
Definition: Indent.hpp:22
Definition: FileSystem.hpp:20
Summaries data generated by the logger, for the purposes of reporting.
Definition: TestLogger.hpp:299
Paths used by the project.
Definition: ProjectPaths.hpp:469
Consumes command-line arguments and holds all test suites.
Definition: TestRunner.hpp:253
Definition: IndividualTestPaths.hpp:90
Definition: TestRunner.hpp:59
Definition: FreeTestCore.hpp:31
Definition: Helpers.hpp:19
Definition: FreeTestCore.hpp:189
Definition: Utilities.hpp:73
Holds paths to files where recovery information will be written if the path is not empty.
Definition: TestLogger.hpp:36
Definition: ProjectPaths.hpp:472