diff --git a/ostd/environ.hh b/ostd/environ.hh new file mode 100644 index 0000000..0493d87 --- /dev/null +++ b/ostd/environ.hh @@ -0,0 +1,62 @@ +/* Environment handling. + * + * This file is part of OctaSTD. See COPYING.md for futher information. + */ + +#ifndef OSTD_ENVIRON_HH +#define OSTD_ENVIRON_HH + +#include +#include + +#include "ostd/maybe.hh" +#include "ostd/string.hh" + +namespace ostd { +namespace environ { + +inline Maybe get(ConstCharRange name) { + char buf[256]; + const char *ret = nullptr; + if (name.size() < sizeof(buf)) { + memcpy(buf, name.data(), name.size()); + buf[name.size()] = '\0'; + ret = getenv(buf); + } else { + ret = getenv(String(name).data()); + } + if (!ret) return ostd::nothing; + return ostd::move(ConstCharRange(ret)); +} + +inline bool set(ConstCharRange name, ConstCharRange value, + bool update = true) { + char sbuf[2048]; + char *buf = sbuf; + bool alloc = (name.size() + value.size() + 2) > sizeof(sbuf); + if (alloc) + buf = new char[name.size() + value.size() + 2]; + memcpy(buf, name.data(), name.size()); + buf[name.size()] = '\0'; + memcpy(&buf[name.size() + 1], value.data(), value.size()); + buf[name.size() + value.size() + 1] = '\0'; + bool ret = !setenv(buf, &buf[name.size() + 1], update); + if (alloc) + delete[] buf; + return ret; +} + +inline bool unset(ConstCharRange name) { + char buf[256]; + if (name.size() < sizeof(buf)) { + memcpy(buf, name.data(), name.size()); + buf[name.size()] = '\0'; + return !unsetenv(buf); + } + return !unsetenv(String(name).data()); +} + +} /* namespace environ */ +} /* namespace ostd */ + +#endif diff --git a/test_runner.cc b/test_runner.cc index 14f49f7..2812962 100644 --- a/test_runner.cc +++ b/test_runner.cc @@ -1,102 +1,90 @@ -#include -#include - #include #include #include #include #include +#include using namespace ostd; -ConstCharRange get_env(ConstCharRange var, ConstCharRange def = nullptr) { - const char *ret = getenv(String(var).data()); - if (!ret || !ret[0]) - return def; - return ret; -} +#ifndef OSTD_PLATFORM_WIN32 +constexpr auto ColorRed = "\033[91m"; +constexpr auto ColorGreen = "\033[92m"; +constexpr auto ColorBlue = "\033[94m"; +constexpr auto ColorBold = "\033[1m"; +constexpr auto ColorEnd = "\033[0m"; +#else +constexpr auto ColorRed = ""; +constexpr auto ColorGreen = ""; +constexpr auto ColorBlue = ""; +constexpr auto ColorBold = ""; +constexpr auto ColorEnd = ""; +#endif int main() { - ConstCharRange compiler = get_env("CXX", "c++"); - ConstCharRange cxxflags = "-std=c++14 -Wall -Wextra -Wshadow " - "-Wno-missing-braces " /* clang false positive */ - "-I."; - ConstCharRange testdir = get_env("TESTDIR", "tests"); - ConstCharRange srcext = ".cc"; + /* configurable section */ - Map colors = { -#ifndef OSTD_PLATFORM_WIN32 - { "red", "\033[91m" }, - { "green", "\033[92m" }, - { "blue", "\033[94m" }, - { "bold", "\033[1m" }, - { "end", "\033[0m" } -#else - { "red", "" }, - { "green", "" }, - { "blue", "" }, - { "bold", "" }, - { "end", "" } -#endif - }; + auto compiler = environ::get("CXX").value_or("c++"); + auto cxxflags = "-std=c++14 -Wall -Wextra -Wshadow " + "-Wno-missing-braces " /* clang false positive */ + "-I."; + auto testdir = environ::get("TESTDIR").value_or("tests"); + auto srcext = ".cc"; + + auto userflags = environ::get("CXXFLAGS").value_or(""); + + /* do not change past this point */ - ConstCharRange userflags = get_env("CXXFLAGS", ""); int nsuccess = 0, nfailed = 0; + ConstCharRange modname = nullptr; - auto print_result = [&colors, &nsuccess, &nfailed] - (ConstCharRange modname, ConstCharRange fmsg = nullptr) { + auto print_result = [&](ConstCharRange fmsg = nullptr) { write(modname, "...\t"); if (!fmsg.empty()) { - writeln(colors["red"], colors["bold"], "(", fmsg, ")", colors["end"]); + writeln(ColorRed, ColorBold, "(", fmsg, ")", ColorEnd); ++nfailed; } else { - writeln(colors["green"], colors["bold"], "(success)", colors["end"]); + writeln(ColorGreen, ColorBold, "(success)", ColorEnd); ++nsuccess; } }; DirectoryStream ds(testdir); for (auto v: ds.iter()) { - if (v.type() != FileType::regular) - continue; - if (v.extension() != srcext) + if ((v.type() != FileType::regular) || (v.extension() != srcext)) continue; + modname = v.stem(); + String exepath = testdir; exepath += PathSeparator; - exepath += v.stem(); + exepath += modname; - String cxxcmd = compiler; - cxxcmd += " "; - cxxcmd += testdir; - cxxcmd += PathSeparator; - cxxcmd += v.filename(); - cxxcmd += " -o "; - cxxcmd += exepath; - cxxcmd += " "; - cxxcmd += cxxflags; + auto cxxcmd = appender(); + format(cxxcmd, "%s %s%s%s -o %s %s", compiler, testdir, PathSeparator, + v.filename(), exepath, cxxflags); if (!userflags.empty()) { - cxxcmd += " "; - cxxcmd += userflags; + cxxcmd.get() += " "; + cxxcmd.get() += userflags; } - int ret = system(cxxcmd.data()); + int ret = system(cxxcmd.get().data()); if (ret) { - print_result(v.stem(), "compile errror"); + print_result("compile errror"); continue; } ret = system(exepath.data()); if (ret) { - print_result(v.stem(), "runtime error"); + print_result("runtime error"); continue; } remove(exepath.data()); - print_result(v.stem()); + print_result(); } - writeln("\n", colors["blue"], colors["bold"], "testing done:", colors["end"]); - writeln(colors["green"], "SUCCESS: ", nsuccess, colors["end"]); - writeln(colors["red"], "FAILURE: ", nfailed, colors["end"]); + writeln("\n", ColorBlue, ColorBold, "testing done:", ColorEnd); + writeln(ColorGreen, "SUCCESS: ", nsuccess, ColorEnd); + writeln(ColorRed, "FAILURE: ", nfailed, ColorEnd); }