summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/.clang-tidy16
-rw-r--r--tests/TestClient.hpp26
-rw-r--r--tests/connect_disconnect_node_patch.ttl6
-rw-r--r--tests/ingen_bench.cpp89
-rw-r--r--tests/ingen_test.cpp165
-rw-r--r--tests/lint/meson.build24
-rw-r--r--tests/meson.build100
-rw-r--r--tests/test_utils.hpp35
-rw-r--r--tests/tst_FilePath.cpp108
9 files changed, 330 insertions, 239 deletions
diff --git a/tests/.clang-tidy b/tests/.clang-tidy
new file mode 100644
index 00000000..6c26f23c
--- /dev/null
+++ b/tests/.clang-tidy
@@ -0,0 +1,16 @@
+Checks: >
+ -*-no-malloc,
+ -*-vararg,
+ -android-cloexec-fopen,
+ -cert-err33-c,
+ -concurrency-mt-unsafe,
+ -cppcoreguidelines-avoid-non-const-global-variables,
+ -cppcoreguidelines-owning-memory,
+ -cppcoreguidelines-pro-bounds-pointer-arithmetic,
+ -cppcoreguidelines-pro-type-reinterpret-cast,
+ -cppcoreguidelines-pro-type-union-access,
+ -fuchsia-statically-constructed-objects,
+ -google-readability-todo,
+ -llvm-header-guard,
+ -readability-function-cognitive-complexity,
+InheritParentConfig: true
diff --git a/tests/TestClient.hpp b/tests/TestClient.hpp
index e76e4aa5..72265b14 100644
--- a/tests/TestClient.hpp
+++ b/tests/TestClient.hpp
@@ -17,23 +17,29 @@
#ifndef INGEN_TESTCLIENT_HPP
#define INGEN_TESTCLIENT_HPP
-#include "ingen/Interface.hpp"
-#include "ingen/Log.hpp"
+#include <ingen/Interface.hpp>
+#include <ingen/Log.hpp>
+#include <ingen/Message.hpp>
+#include <ingen/Status.hpp>
+#include <ingen/URI.hpp>
-#include <boost/variant/get.hpp>
+#include <variant>
-using namespace ingen;
+#include <cstdlib>
-class TestClient : public ingen::Interface
+namespace ingen {
+
+class TestClient : public Interface
{
public:
- explicit TestClient(Log& log) : _log(log) {}
- ~TestClient() {}
+ explicit TestClient(Log& log) noexcept : _log(log) {}
+
+ ~TestClient() override = default;
URI uri() const override { return URI("ingen:testClient"); }
void message(const Message& msg) override {
- if (const Response* const response = boost::get<Response>(&msg)) {
+ if (const Response* const response = std::get_if<Response>(&msg)) {
if (response->status != Status::SUCCESS) {
_log.error("error on message %1%: %2% (%3%)\n",
response->id,
@@ -41,7 +47,7 @@ public:
response->subject);
exit(EXIT_FAILURE);
}
- } else if (const Error* const error = boost::get<Error>(&msg)) {
+ } else if (const Error* const error = std::get_if<Error>(&msg)) {
_log.error("error: %1%\n", error->message);
exit(EXIT_FAILURE);
}
@@ -51,4 +57,6 @@ private:
Log& _log;
};
+} // namespace ingen
+
#endif // INGEN_TESTCLIENT_HPP
diff --git a/tests/connect_disconnect_node_patch.ttl b/tests/connect_disconnect_node_patch.ttl
index 77ada2ad..373b5cbf 100644
--- a/tests/connect_disconnect_node_patch.ttl
+++ b/tests/connect_disconnect_node_patch.ttl
@@ -13,10 +13,10 @@
<msg1>
a patch:Put ;
- patch:subject <ingen:/main/sampler> ;
+ patch:subject <ingen:/main/metro> ;
patch:body [
a ingen:Block ;
- lv2:prototype <http://lv2plug.in/plugins/eg-sampler>
+ lv2:prototype <http://lv2plug.in/plugins/eg-metro>
] .
<msg2>
@@ -85,7 +85,7 @@
patch:body [
a ingen:Arc ;
ingen:tail <ingen:/main/control> ;
- ingen:head <ingen:/main/sampler/control>
+ ingen:head <ingen:/main/metro/control>
] .
<msg10>
diff --git a/tests/ingen_bench.cpp b/tests/ingen_bench.cpp
index 99abee97..ee890401 100644
--- a/tests/ingen_bench.cpp
+++ b/tests/ingen_bench.cpp
@@ -14,62 +14,61 @@
along with Ingen. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "ingen/Atom.hpp"
-#include "ingen/Clock.hpp"
-#include "ingen/Configuration.hpp"
-#include "ingen/EngineBase.hpp"
-#include "ingen/Forge.hpp"
-#include "ingen/Parser.hpp"
-#include "ingen/World.hpp"
-#include "ingen/runtime_paths.hpp"
-#include "ingen/types.hpp"
+#include <ingen/Atom.hpp>
+#include <ingen/Clock.hpp>
+#include <ingen/Configuration.hpp>
+#include <ingen/EngineBase.hpp>
+#include <ingen/Forge.hpp>
+#include <ingen/Parser.hpp>
+#include <ingen/World.hpp>
+#include <ingen/runtime_paths.hpp>
#include <chrono>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
+#include <exception>
#include <iostream>
#include <memory>
#include <string>
-using namespace std;
-using namespace ingen;
+namespace ingen::bench {
+namespace {
-unique_ptr<World> world;
+std::unique_ptr<ingen::World> world;
-static void
+void
ingen_try(bool cond, const char* msg)
{
if (!cond) {
- cerr << "ingen: Error: " << msg << endl;
+ std::cerr << "ingen: Error: " << msg << "\n";
world.reset();
exit(EXIT_FAILURE);
}
}
-static std::string
+std::string
real_path(const char* path)
{
char* const c_real_path = realpath(path, nullptr);
- const std::string result(c_real_path ? c_real_path : "");
+ std::string result(c_real_path ? c_real_path : "");
free(c_real_path);
return result;
}
int
-main(int argc, char** argv)
+run(int argc, char** argv)
{
- set_bundle_path_from_code((void*)&ingen_try);
-
// Create world
try {
- world = unique_ptr<World>{new World(nullptr, nullptr, nullptr)};
+ world = std::make_unique<ingen::World>(nullptr, nullptr, nullptr);
+
world->conf().add(
"output", "output", 'O', "File to write benchmark output",
ingen::Configuration::SESSION, world->forge().String, Atom());
world->load_configuration(argc, argv);
} catch (std::exception& e) {
- cout << "ingen: " << e.what() << endl;
+ std::cout << "ingen: " << e.what() << "\n";
return EXIT_FAILURE;
}
@@ -77,17 +76,19 @@ main(int argc, char** argv)
const Atom& load = world->conf().option("load");
const Atom& out = world->conf().option("output");
if (!load.is_valid() || !out.is_valid()) {
- cerr << "Usage: ingen_bench --load START_GRAPH --output OUT_FILE" << endl;
+ std::cerr << "Usage: ingen_bench --load START_GRAPH --output OUT_FILE\n";
return EXIT_FAILURE;
}
// Get start graph and output file options
- const std::string start_graph = real_path((const char*)load.get_body());
- const std::string out_file = (const char*)out.get_body();
+ const std::string start_graph =
+ real_path(static_cast<const char*>(load.get_body()));
+
+ const std::string out_file = static_cast<const char*>(out.get_body());
if (start_graph.empty()) {
- cerr << "error: initial graph '"
- << ((const char*)load.get_body())
- << "' does not exist" << endl;
+ std::cerr << "error: initial graph '"
+ << static_cast<const char*>(load.get_body())
+ << "' does not exist\n";
return EXIT_FAILURE;
}
@@ -96,24 +97,26 @@ main(int argc, char** argv)
"Unable to load server module");
// Initialise engine
- ingen_try(bool(world->engine()),
+ ingen_try(!!world->engine(),
"Unable to create engine");
world->engine()->init(48000.0, 4096, 4096);
world->engine()->activate();
// Load graph
if (!world->parser()->parse_file(*world, *world->interface(), start_graph)) {
- cerr << "error: failed to load initial graph " << start_graph << endl;
+ std::cerr << "error: failed to load initial graph " << start_graph
+ << "\n";
+
return EXIT_FAILURE;
}
world->engine()->flush_events(std::chrono::milliseconds(20));
// Run benchmark
// TODO: Set up real-time scheduling for this and worker threads
- ingen::Clock clock;
- const uint32_t n_test_frames = 1 << 20;
- const uint32_t block_length = 4096;
- const uint64_t t_start = clock.now_microseconds();
+ const ingen::Clock clock;
+ const uint32_t n_test_frames = 1 << 20;
+ const uint32_t block_length = 4096;
+ const uint64_t t_start = clock.now_microseconds();
for (uint32_t i = 0; i < n_test_frames; i += block_length) {
world->engine()->advance(block_length);
world->engine()->run(block_length);
@@ -122,14 +125,14 @@ main(int argc, char** argv)
const uint64_t t_end = clock.now_microseconds();
// Write log output
- std::unique_ptr<FILE, decltype(&fclose)> log{fopen(out_file.c_str(), "a"),
- &fclose};
+ const std::unique_ptr<FILE, int (*)(FILE*)> log{fopen(out_file.c_str(), "a"),
+ &fclose};
if (ftell(log.get()) == 0) {
fprintf(log.get(), "# n_threads\trun_time\treal_time\n");
}
- fprintf(log.get(), "%u\t%f\t%f\n",
+ fprintf(log.get(), "%d\t%f\t%f\n",
world->conf().option("threads").get<int32_t>(),
- (t_end - t_start) / 1000000.0,
+ static_cast<double>(t_end - t_start) / 1000000.0,
(n_test_frames / 48000.0));
// Shut down
@@ -137,3 +140,15 @@ main(int argc, char** argv)
return EXIT_SUCCESS;
}
+
+} // namespace
+} // namespace ingen::bench
+
+int
+main(int argc, char** argv)
+{
+ ingen::set_bundle_path_from_code(
+ reinterpret_cast<void (*)()>(&ingen::bench::ingen_try));
+
+ return ingen::bench::run(argc, argv);
+}
diff --git a/tests/ingen_test.cpp b/tests/ingen_test.cpp
index 476fab64..215d20a1 100644
--- a/tests/ingen_test.cpp
+++ b/tests/ingen_test.cpp
@@ -15,73 +15,74 @@
*/
#include "TestClient.hpp"
-#include "ingen_config.h"
-
-#include "ingen/Atom.hpp"
-#include "ingen/AtomForge.hpp"
-#include "ingen/AtomReader.hpp"
-#include "ingen/AtomWriter.hpp"
-#include "ingen/Configuration.hpp"
-#include "ingen/EngineBase.hpp"
-#include "ingen/FilePath.hpp"
-#include "ingen/Interface.hpp"
-#include "ingen/Parser.hpp"
-#include "ingen/Properties.hpp"
-#include "ingen/Serialiser.hpp"
-#include "ingen/Store.hpp"
-#include "ingen/URI.hpp"
-#include "ingen/URIMap.hpp"
-#include "ingen/World.hpp"
-#include "ingen/filesystem.hpp"
-#include "ingen/fmt.hpp"
-#include "ingen/runtime_paths.hpp"
-#include "ingen/types.hpp"
-#include "raul/Path.hpp"
-#include "serd/serd.h"
-#include "sord/sordmm.hpp"
-#include "sratom/sratom.h"
+
+#include <ingen/Atom.hpp>
+#include <ingen/AtomForge.hpp>
+#include <ingen/AtomReader.hpp>
+#include <ingen/Configuration.hpp>
+#include <ingen/EngineBase.hpp>
+#include <ingen/FilePath.hpp>
+#include <ingen/Interface.hpp>
+#include <ingen/Parser.hpp>
+#include <ingen/Serialiser.hpp>
+#include <ingen/Store.hpp>
+#include <ingen/URI.hpp>
+#include <ingen/URIMap.hpp>
+#include <ingen/World.hpp>
+#include <ingen/fmt.hpp>
+#include <ingen/memory.hpp>
+#include <ingen/runtime_paths.hpp>
+#include <raul/Path.hpp>
+#include <serd/serd.h>
+#include <sord/sordmm.hpp>
+#include <sratom/sratom.h>
#include <chrono>
#include <cstdint>
#include <cstdlib>
+#include <exception>
+#include <filesystem>
#include <iostream>
+#include <map>
+#include <memory>
#include <string>
#include <utility>
-using namespace std;
-using namespace ingen;
+// #define DUMP_EVENTS 1
+
+namespace ingen::test {
+namespace {
-unique_ptr<World> world;
+std::unique_ptr<World> world;
-static void
+void
ingen_try(bool cond, const char* msg)
{
if (!cond) {
- cerr << "ingen: Error: " << msg << endl;
+ std::cerr << "ingen: Error: " << msg << "\n";
world.reset();
exit(EXIT_FAILURE);
}
}
-static FilePath
+FilePath
real_file_path(const char* path)
{
- UPtr<char, FreeDeleter<char>> real_path{realpath(path, nullptr)};
+ const std::unique_ptr<char, FreeDeleter<char>> real_path{realpath(path, nullptr),
+ FreeDeleter<char>{}};
return FilePath{real_path.get()};
}
int
-main(int argc, char** argv)
+run(int argc, char** argv)
{
- set_bundle_path_from_code((void*)&ingen_try);
-
// Create world
try {
- world = unique_ptr<World>{new World(nullptr, nullptr, nullptr)};
+ world = std::make_unique<World>(nullptr, nullptr, nullptr);
world->load_configuration(argc, argv);
- } catch (std::exception& e) {
- cout << "ingen: " << e.what() << endl;
+ } catch (const std::exception& e) {
+ std::cerr << "ingen: " << e.what() << "\n";
return EXIT_FAILURE;
}
@@ -89,19 +90,23 @@ main(int argc, char** argv)
const Atom& load = world->conf().option("load");
const Atom& execute = world->conf().option("execute");
if (!load.is_valid() || !execute.is_valid()) {
- cerr << "Usage: ingen_test --load START_GRAPH --execute COMMANDS_FILE" << endl;
+ std::cerr
+ << "Usage: ingen_test --load START_GRAPH --execute COMMANDS_FILE\n";
+
return EXIT_FAILURE;
}
// Get start graph and commands file options
- const FilePath load_path = real_file_path((const char*)load.get_body());
- const FilePath run_path = real_file_path((const char*)execute.get_body());
+ const FilePath load_path = real_file_path(static_cast<const char*>(load.get_body()));
+ const FilePath run_path = real_file_path(static_cast<const char*>(execute.get_body()));
if (load_path.empty()) {
- cerr << "error: initial graph '" << load_path << "' does not exist" << endl;
+ std::cerr << "error: initial graph '" << load_path << "' does not exist\n";
return EXIT_FAILURE;
- } else if (run_path.empty()) {
- cerr << "error: command file '" << run_path << "' does not exist" << endl;
+ }
+
+ if (run_path.empty()) {
+ std::cerr << "error: command file '" << run_path << "' does not exist\n";
return EXIT_FAILURE;
}
@@ -110,21 +115,21 @@ main(int argc, char** argv)
"Unable to load server module");
// Initialise engine
- ingen_try(bool(world->engine()),
+ ingen_try(!!world->engine(),
"Unable to create engine");
world->engine()->init(48000.0, 4096, 4096);
world->engine()->activate();
// Load graph
if (!world->parser()->parse_file(*world, *world->interface(), load_path)) {
- cerr << "error: failed to load initial graph " << load_path << endl;
+ std::cerr << "error: failed to load initial graph " << load_path << "\n";
return EXIT_FAILURE;
}
world->engine()->flush_events(std::chrono::milliseconds(20));
// Read commands
- AtomForge forge(world->uri_map().urid_map_feature()->urid_map);
+ AtomForge forge(world->uri_map().urid_map());
sratom_set_object_mode(&forge.sratom(), SRATOM_OBJECT_MODE_BLANK_SUBJECT);
@@ -132,29 +137,35 @@ main(int argc, char** argv)
AtomReader atom_reader(world->uri_map(),
world->uris(),
world->log(),
- *world->interface().get());
+ *world->interface());
// AtomWriter to serialise responses from the engine
- SPtr<Interface> client(new TestClient(world->log()));
+ const std::shared_ptr<Interface> client{new TestClient(world->log())};
world->interface()->set_respondee(client);
world->engine()->register_client(client);
SerdURI cmds_base;
SerdNode cmds_file_uri = serd_node_new_file_uri(
- (const uint8_t*)run_path.c_str(),
+ reinterpret_cast<const uint8_t*>(run_path.c_str()),
nullptr, &cmds_base, true);
- Sord::Model* cmds = new Sord::Model(*world->rdf_world(),
- (const char*)cmds_file_uri.buf);
+
+ auto* cmds =
+ new Sord::Model(*world->rdf_world(),
+ reinterpret_cast<const char*>(cmds_file_uri.buf));
+
SerdEnv* env = serd_env_new(&cmds_file_uri);
cmds->load_file(env, SERD_TURTLE, run_path);
- Sord::Node nil;
- int n_events = 0;
+ const Sord::Node nil;
+ int n_events = 0;
for (;; ++n_events) {
- std::string subject_str = fmt("msg%1%", n_events);
- Sord::URI subject(*world->rdf_world(), subject_str,
- (const char*)cmds_file_uri.buf);
- Sord::Iter iter = cmds->find(subject, nil, nil);
+ const std::string subject_str = fmt("msg%1%", n_events);
+
+ Sord::URI subject(*world->rdf_world(),
+ subject_str,
+ reinterpret_cast<const char*>(cmds_file_uri.buf));
+
+ auto iter = cmds->find(subject, nil, nil);
if (iter.end()) {
break;
}
@@ -162,9 +173,9 @@ main(int argc, char** argv)
forge.clear();
forge.read(*world->rdf_world(), cmds->c_obj(), subject.c_obj());
-#if 0
+#ifdef DUMP_EVENTS
const LV2_Atom* atom = forge.atom();
- cerr << "READ " << atom->size << " BYTES" << endl;
+ cerr << "READ " << atom->size << " BYTES\n";
cerr << sratom_to_turtle(
sratom,
&world->uri_map().urid_unmap_feature()->urid_unmap,
@@ -173,6 +184,7 @@ main(int argc, char** argv)
#endif
if (!atom_reader.write(forge.atom(), n_events + 1)) {
+ delete cmds;
return EXIT_FAILURE;
}
@@ -182,34 +194,34 @@ main(int argc, char** argv)
delete cmds;
// Save resulting graph
- auto r = world->store()->find(Raul::Path("/"));
+ auto r = world->store()->find(raul::Path("/"));
const std::string base = run_path.stem();
const std::string out_name = base.substr(0, base.find('.')) + ".out.ingen";
- const FilePath out_path = filesystem::current_path() / out_name;
+ const FilePath out_path = std::filesystem::current_path() / out_name;
world->serialiser()->write_bundle(r->second, URI(out_path));
- // Undo every event (should result in a graph identical to the original)
+ // Undo every event (makes the graph identical to the original)
for (int i = 0; i < n_events; ++i) {
world->interface()->undo();
world->engine()->flush_events(std::chrono::milliseconds(20));
}
// Save completely undone graph
- r = world->store()->find(Raul::Path("/"));
+ r = world->store()->find(raul::Path("/"));
const std::string undo_name = base.substr(0, base.find('.')) + ".undo.ingen";
- const FilePath undo_path = filesystem::current_path() / undo_name;
+ const FilePath undo_path = std::filesystem::current_path() / undo_name;
world->serialiser()->write_bundle(r->second, URI(undo_path));
- // Redo every event (should result in a graph identical to the pre-undo output)
+ // Redo every event (makes the graph identical to the pre-undo output)
for (int i = 0; i < n_events; ++i) {
world->interface()->redo();
world->engine()->flush_events(std::chrono::milliseconds(20));
}
// Save completely redone graph
- r = world->store()->find(Raul::Path("/"));
+ r = world->store()->find(raul::Path("/"));
const std::string redo_name = base.substr(0, base.find('.')) + ".redo.ingen";
- const FilePath redo_path = filesystem::current_path() / redo_name;
+ const FilePath redo_path = std::filesystem::current_path() / redo_name;
world->serialiser()->write_bundle(r->second, URI(redo_path));
serd_env_free(env);
@@ -220,3 +232,20 @@ main(int argc, char** argv)
return EXIT_SUCCESS;
}
+
+} // namespace
+} // namespace ingen::test
+
+int
+main(int argc, char** argv)
+{
+ try {
+ ingen::set_bundle_path_from_code(
+ reinterpret_cast<void (*)()>(&ingen::test::ingen_try));
+
+ return ingen::test::run(argc, argv);
+ } catch (const std::exception& e) {
+ std::cerr << "ingen: " << e.what() << "\n";
+ return EXIT_FAILURE;
+ }
+}
diff --git a/tests/lint/meson.build b/tests/lint/meson.build
new file mode 100644
index 00000000..c641cbaa
--- /dev/null
+++ b/tests/lint/meson.build
@@ -0,0 +1,24 @@
+# Copyright 2019-2024 David Robillard <d@drobilla.net>
+# SPDX-License-Identifier: 0BSD OR GPL-3.0-or-later
+
+if not meson.is_subproject()
+ # Check code with cppcheck
+ cppcheck = find_program('cppcheck', required: false)
+ if cppcheck.found()
+ compdb_path = join_paths(ingen_build_root, 'compile_commands.json')
+ suppress_path = join_paths(ingen_src_root, '.suppress.cppcheck')
+ test(
+ 'cppcheck',
+ cppcheck,
+ args: [
+ '--cppcheck-build-dir=' + meson.current_build_dir(),
+ '--enable=warning,style,performance,portability',
+ '--error-exitcode=1',
+ '--project=' + compdb_path,
+ '--suppressions-list=' + suppress_path,
+ '-q',
+ ],
+ suite: 'code',
+ )
+ endif
+endif
diff --git a/tests/meson.build b/tests/meson.build
new file mode 100644
index 00000000..1637230b
--- /dev/null
+++ b/tests/meson.build
@@ -0,0 +1,100 @@
+# Copyright 2019-2022 David Robillard <d@drobilla.net>
+# SPDX-License-Identifier: 0BSD OR GPL-3.0-or-later
+
+#####################
+# Integration Tests #
+#####################
+
+ingen_test = executable(
+ 'ingen_test',
+ files('ingen_test.cpp'),
+ cpp_args: cpp_suppressions + platform_defines,
+ dependencies: [ingen_dep],
+)
+
+ingen_bench = executable(
+ 'ingen_bench',
+ files('ingen_bench.cpp'),
+ cpp_args: cpp_suppressions + platform_defines,
+ dependencies: [ingen_dep],
+)
+
+empty_manifest = files('empty.ingen/manifest.ttl')
+empty_main = files('empty.ingen/main.ttl')
+
+integration_tests = [
+ 'connect_disconnect_node_node',
+ 'connect_disconnect_node_patch',
+ 'connect_disconnect_patch_patch',
+ 'copy_node',
+ 'create_delete_node',
+ 'create_delete_patch',
+ 'create_delete_poly_patch',
+ 'create_delete_port',
+ 'disconnect_all_node',
+ 'disconnect_all_port',
+ 'duplicate_node',
+ 'enable_graph',
+ 'get_engine',
+ 'get_node',
+ 'get_patch',
+ 'get_plugin',
+ 'get_plugins',
+ 'get_port',
+ 'load_graph',
+ 'move_node',
+ 'move_port',
+ 'move_root_port',
+ 'poly',
+ 'put_audio_in',
+ 'save_graph',
+ 'set_graph_poly',
+ 'set_patch_port_value',
+]
+
+test_env = environment(
+ {
+ 'INGEN_MODULE_PATH': ':'.join(
+ [
+ ingen_build_root / 'src',
+ ingen_build_root / 'src' / 'client',
+ ingen_build_root / 'src' / 'gui',
+ ingen_build_root / 'src' / 'server',
+ ],
+ ),
+ 'LV2_PATH': ':'.join(
+ [
+ lv2_dep.get_variable(
+ default_value: lv2dir,
+ internal: 'lv2dir',
+ pkgconfig: 'lv2dir',
+ ),
+ lv2_dep.get_variable(
+ default_value: lv2dir,
+ internal: 'plugindir',
+ pkgconfig: 'plugindir',
+ ),
+ ],
+ ),
+ },
+)
+
+foreach test : integration_tests
+ test(
+ test,
+ ingen_test,
+ env: test_env,
+ args: [
+ ['--load', empty_manifest],
+ ['--execute', files(test + '.ttl')],
+ ],
+ )
+endforeach
+
+########
+# Lint #
+########
+
+if get_option('lint')
+ subdir('lint')
+endif
diff --git a/tests/test_utils.hpp b/tests/test_utils.hpp
index 48e3a588..4c358739 100644
--- a/tests/test_utils.hpp
+++ b/tests/test_utils.hpp
@@ -14,25 +14,32 @@
along with Ingen. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "ingen/fmt.hpp"
+#include <ingen/fmt.hpp>
#include <iostream>
+#include <string>
#define EXPECT_TRUE(value) \
- if (!(value)) { \
- std::cerr << fmt("error: %1%:%2%: !%3%\n", \
- __FILE__, __LINE__, (#value)); \
- }
+ do { \
+ if (!(value)) { \
+ std::cerr << fmt("error: %1%:%2%: !%3%\n", \
+ __FILE__, __LINE__, (#value)); \
+ } \
+ } while (0)
#define EXPECT_FALSE(value) \
- if ((value)) { \
- std::cerr << (fmt("error: %1%:%2%: !%3%\n", \
- __FILE__, __LINE__, (#value))); \
- }
+ do { \
+ if ((value)) { \
+ std::cerr << (fmt("error: %1%:%2%: !%3%\n", \
+ __FILE__, __LINE__, (#value))); \
+ } \
+ } while (0)
#define EXPECT_EQ(value, expected) \
- if (!((value) == (expected))) { \
- std::cerr << fmt("error: %1%:%2%: %3% != %4%\n", \
- __FILE__, __LINE__, (#value), (#expected)); \
- std::cerr << "note: actual value: " << value << std::endl; \
- }
+ do { \
+ if (!((value) == (expected))) { \
+ std::cerr << fmt("error: %1%:%2%: %3% != %4%\n", \
+ __FILE__, __LINE__, (#value), (#expected)); \
+ std::cerr << "note: actual value: " << (value) << std::endl; \
+ } \
+ } while (0)
diff --git a/tests/tst_FilePath.cpp b/tests/tst_FilePath.cpp
deleted file mode 100644
index 768371fe..00000000
--- a/tests/tst_FilePath.cpp
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2018 David Robillard <http://drobilla.net/>
-
- Ingen is free software: you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free
- Software Foundation, either version 3 of the License, or any later version.
-
- Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
-
- You should have received a copy of the GNU Affero General Public License
- along with Ingen. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "test_utils.hpp"
-
-#include "ingen/FilePath.hpp"
-#include "ingen/fmt.hpp"
-
-#include <boost/utility/string_view.hpp>
-
-#include <string>
-
-using ingen::FilePath;
-using ingen::fmt;
-
-int
-main(int, char**)
-{
- EXPECT_EQ(FilePath("/").parent_path(), FilePath("/"));
-
- EXPECT_TRUE(FilePath("/abs").is_absolute())
- EXPECT_FALSE(FilePath("/abs").is_relative())
- EXPECT_EQ(FilePath("/abs").root_name(), FilePath());
- EXPECT_EQ(FilePath("/abs").root_directory(), FilePath("/"));
- EXPECT_EQ(FilePath("/abs").root_path(), FilePath("/"));
- EXPECT_EQ(FilePath("/abs").relative_path(), FilePath("abs"));
- EXPECT_EQ(FilePath("/abs").parent_path(), FilePath("/"));
- EXPECT_EQ(FilePath("/abs").filename(), FilePath("abs"));
- EXPECT_EQ(FilePath("/abs").stem(), FilePath("abs"));
- EXPECT_EQ(FilePath("/abs").extension(), FilePath());
-
- EXPECT_FALSE(FilePath("rel").is_absolute())
- EXPECT_TRUE(FilePath("rel").is_relative())
- EXPECT_EQ(FilePath("rel").root_name(), FilePath());
- EXPECT_EQ(FilePath("rel").root_directory(), FilePath());
- EXPECT_EQ(FilePath("rel").root_path(), FilePath());
- EXPECT_EQ(FilePath("rel").relative_path(), FilePath());
- EXPECT_EQ(FilePath("rel").parent_path(), FilePath());
- EXPECT_EQ(FilePath("rel").filename(), "rel");
- EXPECT_EQ(FilePath("rel").stem(), "rel");
- EXPECT_EQ(FilePath("rel").extension(), FilePath());
-
- EXPECT_FALSE(FilePath("file.txt").is_absolute())
- EXPECT_TRUE(FilePath("file.txt").is_relative())
- EXPECT_EQ(FilePath("file.txt").filename(), "file.txt");
- EXPECT_EQ(FilePath("file.txt").stem(), "file");
- EXPECT_EQ(FilePath("file.txt").extension(), ".txt");
-
- EXPECT_TRUE(FilePath("/abs/file.txt").is_absolute())
- EXPECT_FALSE(FilePath("/abs/file.txt").is_relative())
- EXPECT_EQ(FilePath("/abs/file.txt").filename(), "file.txt");
- EXPECT_EQ(FilePath("/abs/file.txt").stem(), "file");
- EXPECT_EQ(FilePath("/abs/file.txt").extension(), ".txt");
-
- EXPECT_FALSE(FilePath("rel/file.txt").is_absolute())
- EXPECT_TRUE(FilePath("rel/file.txt").is_relative())
- EXPECT_EQ(FilePath("rel/file.txt").filename(), "file.txt");
- EXPECT_EQ(FilePath("rel/file.txt").stem(), "file");
- EXPECT_EQ(FilePath("rel/file.txt").extension(), ".txt");
-
- FilePath path("/x");
- EXPECT_EQ(path, "/x");
- path = std::string("/a");
- EXPECT_EQ(path, "/a");
-
- path /= FilePath("b");
- EXPECT_EQ(path, "/a/b");
-
- path += FilePath("ar");
- EXPECT_EQ(path, "/a/bar");
-
- path += std::string("/c");
- EXPECT_EQ(path, "/a/bar/c");
-
- path += "a";
- EXPECT_EQ(path, "/a/bar/ca");
-
- path += 'r';
- EXPECT_EQ(path, "/a/bar/car");
-
- path += boost::string_view("/d");
- EXPECT_EQ(path, "/a/bar/car/d");
-
- const FilePath apple("apple");
- const FilePath zebra("zebra");
- EXPECT_TRUE(apple == apple);
- EXPECT_TRUE(apple != zebra);
- EXPECT_TRUE(apple < zebra);
- EXPECT_TRUE(apple <= zebra);
- EXPECT_TRUE(apple <= apple);
- EXPECT_TRUE(zebra > apple);
- EXPECT_TRUE(zebra >= apple);
- EXPECT_TRUE(zebra >= zebra);
- return 0;
-}