From ba04d2889a4e017c6043bac9951f722e60b63bc5 Mon Sep 17 00:00:00 2001 From: Bent Bisballe Nyeng Date: Tue, 14 Sep 2021 07:46:43 +0200 Subject: Add suport for building and running unittests with the 'check' target. --- .gitmodules | 3 +++ bootstrap.sh | 2 +- src/build.cc | 38 ++++++++++++++++++++++++++++++++++-- src/build.h | 6 ++++++ src/libctor.cc | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++------- src/libctor.h | 1 + src/task_ld.cc | 7 +++++-- src/tasks.cc | 16 +++++++++++---- src/tasks.h | 3 ++- src/unittest.cc | 34 ++++++++++++++++++++++++++++++++ src/unittest.h | 10 ++++++++++ test/ctor.cc | 28 +++++++++++++++++++++++++++ test/uunit | 1 + 13 files changed, 192 insertions(+), 17 deletions(-) create mode 100644 src/unittest.cc create mode 100644 src/unittest.h create mode 100644 test/ctor.cc create mode 160000 test/uunit diff --git a/.gitmodules b/.gitmodules index 3e401a5..c765825 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "getoptpp"] path = src/getoptpp url = git://git.drumgizmo.org/getoptpp.git +[submodule "test/uunit"] + path = test/uunit + url = git://git.drumgizmo.org/uunit.git diff --git a/bootstrap.sh b/bootstrap.sh index e589a2c..833d3be 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -1,4 +1,4 @@ #!/bin/bash echo "Bootstrapping..." -g++ -std=c++17 -I. -Isrc -pthread src/*.cc ctor.cc -o ctor && \ +g++ -std=c++17 -I. -Isrc -pthread src/*.cc ctor.cc test/ctor.cc -o ctor && \ echo "Done. Now run ./ctor to build." diff --git a/src/build.cc b/src/build.cc index 445979e..4cec3b9 100644 --- a/src/build.cc +++ b/src/build.cc @@ -7,8 +7,6 @@ #include #include -#include "tasks.h" - using namespace std::chrono_literals; int build(const Settings& settings, @@ -171,3 +169,39 @@ int build(const Settings& settings, return 0; } + +int build(const Settings& settings, + const std::string& name, + const std::vector& targets, + const std::list>& all_tasks) +{ + bool task_found{false}; + std::list> ts; + + for(const auto& target : targets) + { + for(auto task : all_tasks) + { + if(task->name() == target.config.target || + task->target() == target.config.target) + { + std::cout << target.config.target << "\n"; + task_found = true; + + auto depSet = getDepTasks(task); + for(const auto& task : depSet) + { + ts.push_back(task); + } + } + } + } + + if(!task_found) + { + std::cerr << "*** No rule to make target '" << name << "'. Stop.\n"; + return 1; + } + + return build(settings, name, ts, all_tasks); +} diff --git a/src/build.h b/src/build.h index 36e48ad..0c4c3fd 100644 --- a/src/build.h +++ b/src/build.h @@ -7,6 +7,7 @@ #include "task.h" #include "settings.h" +#include "tasks.h" int build(const Settings& settings, const std::string& name, @@ -16,3 +17,8 @@ int build(const Settings& settings, int build(const Settings& settings, const std::string& name, const std::list>& all_tasks); + +int build(const Settings& settings, + const std::string& name, + const std::vector& targets, + const std::list>& all_tasks); diff --git a/src/libctor.cc b/src/libctor.cc index c7a7400..e166e51 100644 --- a/src/libctor.cc +++ b/src/libctor.cc @@ -22,6 +22,7 @@ #include "rebuild.h" #include "tasks.h" #include "build.h" +#include "unittest.h" int main(int argc, char* argv[]) { if(argc > 1 && std::string(argv[1]) == "configure") @@ -46,6 +47,7 @@ int main(int argc, char* argv[]) bool list_files{false}; bool list_targets{false}; bool no_relaunch{false}; // true means no re-launch after rebuild. + bool run_unittests{false}; dg::Options opt; int key{128}; @@ -206,12 +208,10 @@ Options: if(list_targets) { no_default_build = true; - for(const auto& task : all_tasks) + auto& targets = getTargets(settings); + for(const auto& target : targets) { - if(task->targetType() != TargetType::Object) - { - std::cout << task->name() << "\n"; - } + std::cout << target.config.target << "\n"; } } @@ -286,13 +286,44 @@ Options: } } } + else if(arg == "check") + { + build_all = false; + run_unittests = true; + + std::vector unittest_targets; + auto& targets = getTargets(settings); + for(const auto& target : targets) + { + if(target.config.type == TargetType::UnitTest) + { + unittest_targets.push_back(target); + } + } + + auto ret = build(settings, "check", unittest_targets, all_tasks); + if(ret != 0) + { + return ret; + } + } else { build_all = false; if(arg == "all") { - auto ret = build(settings, "all", all_tasks, all_tasks); + std::vector non_unittest_targets; + auto& targets = getTargets(settings); + for(const auto& target : targets) + { + if(target.config.type != TargetType::UnitTest) + { + non_unittest_targets.push_back(target); + } + } + + auto ret = build(settings, "all", non_unittest_targets, all_tasks); if(ret != 0) { return ret; @@ -311,12 +342,27 @@ Options: if(build_all) { - auto ret = build(settings, "all", all_tasks, all_tasks); + std::vector non_unittest_targets; + auto& targets = getTargets(settings); + for(const auto& target : targets) + { + if(target.config.type != TargetType::UnitTest) + { + non_unittest_targets.push_back(target); + } + } + + auto ret = build(settings, "all", non_unittest_targets, all_tasks); if(ret != 0) { return ret; } } + if(run_unittests) + { + return runUnitTests(all_tasks, settings); + } + return 0; } diff --git a/src/libctor.h b/src/libctor.h index d0a0080..4ad0e32 100644 --- a/src/libctor.h +++ b/src/libctor.h @@ -13,6 +13,7 @@ enum class TargetType StaticLibrary, DynamicLibrary, Object, + UnitTest, }; enum class Language diff --git a/src/task_ld.cc b/src/task_ld.cc index 4a77c72..ec68190 100644 --- a/src/task_ld.cc +++ b/src/task_ld.cc @@ -44,7 +44,11 @@ TaskLD::TaskLD(const BuildConfiguration& config, , config(config) , settings(settings) { - target_type = TargetType::Executable; + target_type = config.type; + if(target_type == TargetType::Auto) + { + target_type = TargetType::Executable; + } targetFile = settings.builddir; targetFile /= target; @@ -65,7 +69,6 @@ TaskLD::TaskLD(const BuildConfiguration& config, flagsFile = settings.builddir / targetFile.stem(); flagsFile += ".flags"; - target_type = TargetType::Executable; source_language = Language::C; for(const auto& source : config.sources) { diff --git a/src/tasks.cc b/src/tasks.cc index 1607b37..3113564 100644 --- a/src/tasks.cc +++ b/src/tasks.cc @@ -3,6 +3,7 @@ #include #include #include +#include #include "settings.h" #include "libctor.h" @@ -101,6 +102,7 @@ std::list> taskFactory(const BuildConfiguration& config, break; case TargetType::Executable: + case TargetType::UnitTest: tasks.emplace_back(std::make_shared(config, settings, config.target, objects)); break; @@ -111,6 +113,7 @@ std::list> taskFactory(const BuildConfiguration& config, return tasks; } +} std::shared_ptr getNextTask(const std::list>& allTasks, std::list>& dirtyTasks) @@ -131,15 +134,20 @@ std::shared_ptr getNextTask(const std::list>& allTas return nullptr; } -std::list> getTasks(const Settings& settings) +std::list> getTasks(const Settings& settings, + const std::vector names) { auto& targets = getTargets(settings); std::list> tasks; for(const auto& target : targets) { - std::vector objects; - auto t = taskFactory(target.config, settings, target.path); - tasks.insert(tasks.end(), t.begin(), t.end()); + if(names.empty() || + std::find(std::begin(names), std::end(names), target.config.target) != std::end(names)) + { + std::vector objects; + auto t = taskFactory(target.config, settings, target.path); + tasks.insert(tasks.end(), t.begin(), t.end()); + } } return tasks; diff --git a/src/tasks.h b/src/tasks.h index 04610e6..e5d1daf 100644 --- a/src/tasks.h +++ b/src/tasks.h @@ -21,4 +21,5 @@ const std::deque& getTargets(const Settings& settings); std::shared_ptr getNextTask(const std::list>& allTasks, std::list>& dirtyTasks); -std::list> getTasks(const Settings& settings); +std::list> getTasks(const Settings& settings, + const std::vector names = {}); diff --git a/src/unittest.cc b/src/unittest.cc new file mode 100644 index 0000000..d2d5167 --- /dev/null +++ b/src/unittest.cc @@ -0,0 +1,34 @@ +#include "unittest.h" + +#include + +#include "execute.h" +#include "settings.h" +#include "task.h" + +int runUnitTests(std::list>& tasks, + const Settings& settings) +{ + bool ok{true}; + std::cout << "Running unit-tests:\n"; + // Run unit-tests + for(const auto& task : tasks) + { + if(task->targetType() == TargetType::UnitTest) + { + std::cout << task->name() << ": "; + auto ret = execute(task->target(), {}, false); + ok &= ret == 0; + if(ret == 0) + { + std::cout << "OK\n"; + } + else + { + std::cout << "FAILED\n"; + } + } + } + + return ok ? 0 : 1; +} diff --git a/src/unittest.h b/src/unittest.h new file mode 100644 index 0000000..144dbdb --- /dev/null +++ b/src/unittest.h @@ -0,0 +1,10 @@ +#pragma once + +#include +#include + +class Task; +class Settings; + +int runUnitTests(std::list>& tasks, + const Settings& settings); diff --git a/test/ctor.cc b/test/ctor.cc new file mode 100644 index 0000000..aed3ee5 --- /dev/null +++ b/test/ctor.cc @@ -0,0 +1,28 @@ +#include "libctor.h" + +namespace +{ +BuildConfigurations ctorTestConfigs() +{ + return + { + { + .type = TargetType::UnitTest, + .target = "execute_test", + .sources = { + "execute_test.cc", + "uunit/uunit.cc", + "../src/execute.cc", + }, + .cxxflags = { + "-std=c++17", "-O3", "-s", "-Wall", "-Werror", + "-I../src", "-Iuunit", + "-DOUTPUT=\"execute\"", + }, + } + }; +} +} + +// Convenience macro +REG(ctorTestConfigs); diff --git a/test/uunit b/test/uunit new file mode 160000 index 0000000..fd83de8 --- /dev/null +++ b/test/uunit @@ -0,0 +1 @@ +Subproject commit fd83de802d05a227cc00489f66ea70fccb4dda05 -- cgit v1.2.3