summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBent Bisballe Nyeng <deva@aasimon.org>2021-09-14 07:46:43 +0200
committerBent Bisballe Nyeng <deva@aasimon.org>2021-09-14 07:46:43 +0200
commitba04d2889a4e017c6043bac9951f722e60b63bc5 (patch)
tree1267f9264dfe81aadeac46446ee6122a5abe5190
parentf7fda8ca8841552b54ce72ed8ca9156cc09368d0 (diff)
Add suport for building and running unittests with the 'check' target.
-rw-r--r--.gitmodules3
-rwxr-xr-xbootstrap.sh2
-rw-r--r--src/build.cc38
-rw-r--r--src/build.h6
-rw-r--r--src/libctor.cc60
-rw-r--r--src/libctor.h1
-rw-r--r--src/task_ld.cc7
-rw-r--r--src/tasks.cc16
-rw-r--r--src/tasks.h3
-rw-r--r--src/unittest.cc34
-rw-r--r--src/unittest.h10
-rw-r--r--test/ctor.cc28
m---------test/uunit0
13 files changed, 191 insertions, 17 deletions
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 <set>
#include <thread>
-#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<Target>& targets,
+ const std::list<std::shared_ptr<Task>>& all_tasks)
+{
+ bool task_found{false};
+ std::list<std::shared_ptr<Task>> 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<std::shared_ptr<Task>>& all_tasks);
+
+int build(const Settings& settings,
+ const std::string& name,
+ const std::vector<Target>& targets,
+ const std::list<std::shared_ptr<Task>>& 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<Target> 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<Target> 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<Target> 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 <filesystem>
#include <deque>
#include <iostream>
+#include <algorithm>
#include "settings.h"
#include "libctor.h"
@@ -101,6 +102,7 @@ std::list<std::shared_ptr<Task>> taskFactory(const BuildConfiguration& config,
break;
case TargetType::Executable:
+ case TargetType::UnitTest:
tasks.emplace_back(std::make_shared<TaskLD>(config, settings, config.target,
objects));
break;
@@ -111,6 +113,7 @@ std::list<std::shared_ptr<Task>> taskFactory(const BuildConfiguration& config,
return tasks;
}
+}
std::shared_ptr<Task> getNextTask(const std::list<std::shared_ptr<Task>>& allTasks,
std::list<std::shared_ptr<Task>>& dirtyTasks)
@@ -131,15 +134,20 @@ std::shared_ptr<Task> getNextTask(const std::list<std::shared_ptr<Task>>& allTas
return nullptr;
}
-std::list<std::shared_ptr<Task>> getTasks(const Settings& settings)
+std::list<std::shared_ptr<Task>> getTasks(const Settings& settings,
+ const std::vector<std::string> names)
{
auto& targets = getTargets(settings);
std::list<std::shared_ptr<Task>> tasks;
for(const auto& target : targets)
{
- std::vector<std::string> 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<std::string> 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<Target>& getTargets(const Settings& settings);
std::shared_ptr<Task> getNextTask(const std::list<std::shared_ptr<Task>>& allTasks,
std::list<std::shared_ptr<Task>>& dirtyTasks);
-std::list<std::shared_ptr<Task>> getTasks(const Settings& settings);
+std::list<std::shared_ptr<Task>> getTasks(const Settings& settings,
+ const std::vector<std::string> 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 <iostream>
+
+#include "execute.h"
+#include "settings.h"
+#include "task.h"
+
+int runUnitTests(std::list<std::shared_ptr<Task>>& 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 <list>
+#include <memory>
+
+class Task;
+class Settings;
+
+int runUnitTests(std::list<std::shared_ptr<Task>>& 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
+Subproject fd83de802d05a227cc00489f66ea70fccb4dda0