From d7f6ce94c5cbdf03e1630c150f2fd34af9f15349 Mon Sep 17 00:00:00 2001 From: Bent Bisballe Nyeng Date: Sun, 28 Dec 2025 21:48:09 +0100 Subject: Port system-test shellscript to a c++ program for better portability. --- test/suite/test.cc | 333 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 333 insertions(+) create mode 100644 test/suite/test.cc (limited to 'test/suite/test.cc') diff --git a/test/suite/test.cc b/test/suite/test.cc new file mode 100644 index 0000000..b9a6cc3 --- /dev/null +++ b/test/suite/test.cc @@ -0,0 +1,333 @@ +// -*- c++ -*- +// Distributed under the BSD 2-Clause License. +// See accompanying file LICENSE for details. +#include "../../src/util.cc" +#include "../../src/pointerlist.cc" +#include "../../src/execute.cc" + +#include +#include +#include +#include +#include +#include + +std::vector tokenize(const std::string& str) +{ + std::vector tokens; + std::stringstream ss(str); + std::string token; + while(getline(ss, token, ' ')) + { + tokens.push_back(token); + } + return tokens; +} + +int fail(int value = 1, + const std::source_location location = std::source_location::current()) +{ + std::cout << "*** Failure at line " << location.line() << '\n'; + return value; +} + +int main() +{ + using namespace std::chrono_literals; + ctor::settings settings{}; + settings.verbose = 2; + auto paths = get_paths(); + + std::string CXX = "g++"; + get_env("CXX", CXX); + std::string CTORDIR = "../../build"; + get_env("CTORDIR", CTORDIR); + std::string BUILDDIR = "build"; + get_env("BUILDDIR", BUILDDIR); + std::string CXXFLAGS; + get_env("CXXFLAGS", CXXFLAGS); + std::string LDFLAGS; + get_env("LDFLAGS", LDFLAGS); + + auto cxx_prog = locate(CXX, paths); + + // Wipe the board + std::filesystem::remove_all(BUILDDIR); + std::filesystem::remove("configuration.cc"); + std::filesystem::remove("config.h"); + std::filesystem::remove("ctor"); + + ////////////////////////////////////////////////////////////////////////////// + std::cout << "** ctor_files/ctor.cc.base\n"; + std::filesystem::copy("ctor_files/ctor.cc.base", "ctor.cc", + std::filesystem::copy_options::overwrite_existing); + + // Compile bootstrap binary + std::vector args = + {"-pthread", "-std=c++20", "-L", CTORDIR, "-lctor", "-I", "../../src", + "ctor.cc", "-o", "ctor"}; + + // TODO: add support for quoted strings with spaces + if(!CXXFLAGS.empty()) + { + auto tokens = tokenize(CXXFLAGS); + for(const auto& token : tokens) + { + args.push_back(token); + } + } + if(!LDFLAGS.empty()) + { + auto tokens = tokenize(LDFLAGS); + for(const auto& token : tokens) + { + args.push_back(token); + } + } + + auto ret = execute(settings, cxx_prog, args); + if(ret != 0) + { + return fail(ret); + } + + // No build files should have been created yet + if(std::filesystem::exists(BUILDDIR)) + { + return fail(); + } + + // capture ctor binary before configure is called + auto ctor_bin = readFile("ctor"); + args = {"configure", "--ctor-includedir", "../../src", + "--ctor-libdir="+CTORDIR, "--build-dir="+BUILDDIR}; + ret = execute(settings, "./ctor", args); + if(ret != 0) + { + return fail(ret); + } + + // ctor should be rebuilt at this point, so binary should have changed + auto ctor_bin2 = readFile("ctor"); + if(ctor_bin == ctor_bin2) + { + return fail(); + } + + // configuration.cc should have been generated now + if(!std::filesystem::exists("configuration.cc")) + { + return fail(); + } + if(!std::filesystem::exists("config.h")) + { + return fail(); + } + + // Shouldn't compile anything yet - only configure + if(std::filesystem::exists(BUILDDIR+"/hello-hello_cc.o")) + { + return fail(); + } + + ctor_bin = readFile("ctor"); + + // Run normally to build project + args = {"-v"}; + ret = execute(settings, "./ctor", args); + if(ret != 0) + { + return fail(ret); + } + + // Compiled object should now exist + if(!std::filesystem::exists(BUILDDIR+"/hello-hello_cc.o")) + { + return fail(); + } + + // ctor should not have been rebuilt, so binary should be the same + ctor_bin2 = readFile("ctor"); + if(ctor_bin != ctor_bin2) + { + return fail(); + } + + std::this_thread::sleep_for(1100ms); + + auto time = std::filesystem::last_write_time(BUILDDIR+"/hello-hello_cc.o"); + std::filesystem::last_write_time("hello.cc", time + 1s); + std::this_thread::sleep_for(1100ms); + + // Run normally to rebuild hello.cc + args = {"-v"}; + ret = execute(settings, "./ctor", args); + if(ret != 0) + { + return fail(ret); + } + + // Object file should have been recompiled + auto time2 = std::filesystem::last_write_time(BUILDDIR+"/hello-hello_cc.o"); + if(time == time2) + { + return fail(); + } + + ////////////////////////////////////////////////////////////////////////////// + // Replace -DFOO with -DBAR in foo external.cxxflags + std::cout << "** ctor_files/ctor.cc.bar\n"; + std::filesystem::copy("ctor_files/ctor.cc.bar", "ctor.cc", + std::filesystem::copy_options::overwrite_existing); + + auto configuration_cc_bin = readFile("configuration.cc"); + ctor_bin = readFile("ctor"); + time = std::filesystem::last_write_time(BUILDDIR+"/hello-hello_cc.o"); + std::this_thread::sleep_for(1100ms); + + // Run normally to reconfigure, rebuild ctor and rebuild hello.cc + args = {"-v"}; + ret = execute(settings, "./ctor", args); + if(ret != 0) + { + return fail(ret); + } + + time2 = std::filesystem::last_write_time(BUILDDIR+"/hello-hello_cc.o"); + if(time == time2) + { + return fail(); + } + + auto configuration_cc_bin2 = readFile("configuration.cc"); + if(configuration_cc_bin == configuration_cc_bin2) + { + return fail(); + } + + ctor_bin2 = readFile("ctor"); + if(ctor_bin == ctor_bin2) + { + return fail(); + } + + ////////////////////////////////////////////////////////////////////////////// + std::cout << "** ctor_files/ctor.cc.multi\n"; + std::filesystem::copy("ctor_files/ctor.cc.multi", "ctor.cc", + std::filesystem::copy_options::overwrite_existing); + + configuration_cc_bin = readFile("configuration.cc"); + ctor_bin = readFile("ctor"); + time = std::filesystem::last_write_time(BUILDDIR+"/hello-hello_cc.o"); + std::this_thread::sleep_for(1100ms); + + // Run normally to reconfigure, rebuild ctor and rebuild hello.cc + args = {"-v"}; + ret = execute(settings, "./ctor", args); + if(ret != 0) + { + return fail(ret); + } + + time2 = std::filesystem::last_write_time(BUILDDIR+"/hello-hello_cc.o"); + if(time == time2) + { + return fail(); + } + + configuration_cc_bin2 = readFile("configuration.cc"); + if(configuration_cc_bin == configuration_cc_bin2) + { + return fail(); + } + + ctor_bin2 = readFile("ctor"); + if(ctor_bin == ctor_bin2) + { + return fail(); + } + + // now touching foobar.h, should retrigger re-configuration + time = std::filesystem::last_write_time("ctor"); + std::filesystem::last_write_time("foobar.h", time + 1s); + time = std::filesystem::last_write_time("ctor"); + std::this_thread::sleep_for(1100ms); + + // Run normally to reconfigure, rebuild ctor and rebuild hello.cc + args = {"-v"}; + ret = execute(settings, "./ctor", args); + if(ret != 0) + { + return fail(ret); + } + + time2 = std::filesystem::last_write_time("ctor"); + if(time == time2) + { + return fail(); + } + + ////////////////////////////////////////////////////////////////////////////// + std::cout << "** ctor_files/ctor.cc.generated\n"; + std::filesystem::copy("ctor_files/ctor.cc.generated", "ctor.cc", + std::filesystem::copy_options::overwrite_existing); + + std::filesystem::remove(BUILDDIR+"/world.cc"); + std::filesystem::remove(BUILDDIR+"/foo.cc"); + + configuration_cc_bin = readFile("configuration.cc"); + ctor_bin = readFile("ctor"); + std::this_thread::sleep_for(1100ms); + + // Run normally to reconfigure, rebuild ctor and build world.cc + args = {"-v", "world"}; + ret = execute(settings, "./ctor", args); + if(ret != 0) + { + return fail(ret); + } + + configuration_cc_bin2 = readFile("configuration.cc"); + if(configuration_cc_bin == configuration_cc_bin2) + { + return fail(); + } + + ctor_bin2 = readFile("ctor"); + if(ctor_bin == ctor_bin2) + { + return fail(); + } + + // foo.cc should not be generated at this point + if(std::filesystem::exists(BUILDDIR+"/foo.cc")) + { + return fail(); + } + + auto time_w = std::filesystem::last_write_time(BUILDDIR+"/world.cc"); + auto time_wo = std::filesystem::last_write_time(BUILDDIR+"/"+BUILDDIR+"/world-world_cc.o"); + std::this_thread::sleep_for(1100ms); + + // now touching hello.cc, should trigger regeneration of world.cc and rebuild + std::filesystem::last_write_time("hello.cc", time_w + 1s); + args = {"-v", "world"}; + ret = execute(settings, "./ctor", args); + if(ret != 0) + { + return fail(ret); + } + + auto time_w2 = std::filesystem::last_write_time(BUILDDIR+"/world.cc"); + auto time_wo2 = std::filesystem::last_write_time(BUILDDIR+"/"+BUILDDIR+"/world-world_cc.o"); + if(time_w == time_w2) + { + return fail(); + } + if(time_wo == time_wo2) + { + return fail(); + } + + return 0; +} -- cgit v1.2.3