diff --git a/Makefile b/Makefile index f87f881a..10c1c7d6 100644 --- a/Makefile +++ b/Makefile @@ -21,6 +21,7 @@ build/dep/tinyexpr/tinyexpr.c.o: FLAGS += -DTE_POW_FROM_RIGHT -DTE_NAT_LOG FLAGS += -fPIC LDFLAGS += -shared +LDFLAGS += dep/lib/libCatch2.a ifdef ARCH_LIN SED := sed -i diff --git a/adapters/standalone.cpp b/adapters/standalone.cpp index 0e24be00..3d8ff913 100644 --- a/adapters/standalone.cpp +++ b/adapters/standalone.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -82,13 +83,14 @@ int main(int argc, char* argv[]) { {"system", required_argument, NULL, 's'}, {"user", required_argument, NULL, 'u'}, {"version", no_argument, NULL, 'v'}, + {"runtests", optional_argument, NULL, 'r'}, {"help", no_argument, NULL, 256}, {NULL, 0, NULL, 0} }; int c; opterr = 0; - while ((c = getopt_long(argc, argv, "adht:s:u:vp:", longOptions, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "adht:s:u:vrp:", longOptions, NULL)) != -1) { switch (c) { case 'a': { settings::safeMode = true; @@ -99,6 +101,12 @@ int main(int argc, char* argv[]) { case 'h': { settings::headless = true; } break; + case 'r': { + settings::runTests = true; + if (optarg) { + rack::runtests::testArgs = optarg; + } + } break; case 't': { screenshot = true; std::sscanf(optarg, "%f", &screenshotZoom); @@ -257,6 +265,9 @@ int main(int argc, char* argv[]) { printf("Press enter to exit.\n"); getchar(); } + else if (settings::runTests) { + rack::runtests::runTests(); + } else if (screenshot) { INFO("Taking screenshots of all modules at %gx zoom", screenshotZoom); APP->window->screenshotModules(asset::user("screenshots"), screenshotZoom); @@ -283,7 +294,7 @@ int main(int argc, char* argv[]) { } // Destroy environment - if (!settings::headless) { + if (!settings::headless && !settings::runTests) { INFO("Destroying window"); window::destroy(); INFO("Destroying UI"); diff --git a/compile.mk b/compile.mk index 011b4363..ca4da6b4 100644 --- a/compile.mk +++ b/compile.mk @@ -18,7 +18,8 @@ FLAGS += -O3 -funsafe-math-optimizations -fno-omit-frame-pointer # Warnings FLAGS += -Wall -Wextra -Wno-unused-parameter # C++ standard -CXXFLAGS += -std=c++11 +# CXXFLAGS += -std=c++11 +CXXFLAGS += -std=c++17 # Define compiler/linker target if cross-compiling ifdef CROSS_COMPILE diff --git a/dep/Catch2 b/dep/Catch2 new file mode 160000 index 00000000..efb39689 --- /dev/null +++ b/dep/Catch2 @@ -0,0 +1 @@ +Subproject commit efb39689d94e43132e4e48f01e676ae6a56d8df6 diff --git a/dep/Makefile b/dep/Makefile index 87c1278b..179cda53 100755 --- a/dep/Makefile +++ b/dep/Makefile @@ -18,6 +18,7 @@ ifdef ARCH_LIN libsamplerate = lib/libsamplerate.a rtmidi = lib/librtmidi.a rtaudio = lib/librtaudio.a + Catch2 = lib/libCatch2.a endif ifdef ARCH_MAC @@ -32,6 +33,7 @@ ifdef ARCH_MAC libsamplerate = lib/libsamplerate.a rtmidi = lib/librtmidi.a rtaudio = lib/librtaudio.a + Catch2 = lib/libCatch2.a endif ifdef ARCH_WIN @@ -46,6 +48,7 @@ ifdef ARCH_WIN libsamplerate = lib/libsamplerate.a rtmidi = lib/librtmidi.a rtaudio = lib/librtaudio.a + Catch2 = lib/libCatch2.a endif nanovg = include/nanovg.h @@ -76,6 +79,7 @@ DEPS += $(fuzzysearchdatabase) DEPS += $(ghcfilesystem) DEPS += $(tinyexpr) DEPS += $(simde) +DEPS += $(Catch2) DEP_LOCAL := . @@ -85,6 +89,12 @@ include $(RACK_DIR)/dep.mk # Targets # These targets are all order-only "|" because we usually don't care if a library was built before or after other libraries. +$(Catch2): | Catch2 + cd Catch2 && mkdir -p build + cd Catch2/build && $(CMAKE) .. + $(MAKE) -C Catch2/build + $(MAKE) -C Catch2/build install + glew-2.1.0: $(WGET) "https://github.com/nigels-com/glew/releases/download/glew-2.1.0/glew-2.1.0.tgz" $(SHA256) glew-2.1.0.tgz 04de91e7e6763039bc11940095cd9c7f880baba82196a7765f727ac05a993c95 @@ -264,7 +274,7 @@ $(simde): simde/simde # Helpers -src: glew-2.1.0 glfw jansson-2.12 libsamplerate-0.1.9 openssl-1.1.1k curl-7.79.1 zstd-1.4.5 libarchive-3.4.3 rtaudio nanovg nanosvg oui-blendish osdialog +src: Catch2 glew-2.1.0 glfw jansson-2.12 libsamplerate-0.1.9 openssl-1.1.1k curl-7.79.1 zstd-1.4.5 libarchive-3.4.3 rtaudio nanovg nanosvg oui-blendish osdialog clean: git clean -fdx diff --git a/include/runtests.hpp b/include/runtests.hpp new file mode 100644 index 00000000..ed469808 --- /dev/null +++ b/include/runtests.hpp @@ -0,0 +1,8 @@ +#include + +namespace rack { +namespace runtests { +extern std::string testArgs; +int runTests(); +} // namespace runtests +} // namespace rack \ No newline at end of file diff --git a/include/settings.hpp b/include/settings.hpp index 7c46dd26..f88fa871 100644 --- a/include/settings.hpp +++ b/include/settings.hpp @@ -24,6 +24,7 @@ extern std::string settingsPath; extern bool devMode; extern bool headless; extern bool isPlugin; +extern bool runTests; // Persistent state, serialized to settings.json. diff --git a/src/settings.cpp b/src/settings.cpp index b88be2c0..ba653f28 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -19,6 +19,7 @@ std::string settingsPath; bool devMode = false; bool headless = false; bool isPlugin = false; +bool runTests = false; bool safeMode = false; std::string token; diff --git a/src/tests/runtests.cpp b/src/tests/runtests.cpp new file mode 100644 index 00000000..2c3955a0 --- /dev/null +++ b/src/tests/runtests.cpp @@ -0,0 +1,43 @@ +#include "catch2/catch_session.hpp" +#include "runtests.hpp" +#include "app/Scene.hpp" +#include "logger.hpp" +#include + +namespace rack { +namespace runtests { + +std::string testArgs = ""; +int runTests() { + // Create Catch2 session + Catch::Session session; + + // Parse testArgs into argc, argv + std::istringstream iss(testArgs); + std::vector args; + for (std::string s; iss >> s;) + args.push_back(s); + std::vector argv; + argv.push_back("Rack"); + for (const auto& arg : args) + argv.push_back(arg.c_str()); + argv.push_back(nullptr); + + if (testArgs.empty()) + INFO("Running tests"); + else + INFO("Running tests with arguments %s", testArgs.c_str()); + // Apply command line arguments + int returnCode = session.applyCommandLine(args.size() + 1, argv.data()); + if (returnCode != 0) { + WARN("Catch2 command line error %d", returnCode); + return returnCode; + } + + // Run Catch2 tests + int numFailed = session.run(); + return numFailed; +} + +} // namespace runtests +} // namespace rack \ No newline at end of file