diff --git a/client/Doxygen/docker-finance.dox b/client/Doxygen/docker-finance.dox index 2c9b331..8668dd2 100644 --- a/client/Doxygen/docker-finance.dox +++ b/client/Doxygen/docker-finance.dox @@ -1,6 +1,6 @@ // docker-finance | modern accounting for the power-user // -// Copyright (C) 2021-2024 Aaron Fiore (Founder, Evergreen Crypto LLC) +// Copyright (C) 2021-2025 Aaron Fiore (Founder, Evergreen Crypto LLC) // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -100,6 +100,10 @@ //! \brief Group for testing framework (benchmarks, unit testing) //! \since docker-finance 1.0.0 +//! \defgroup cpp_common_impl docker-finance C++ shared common code +//! \brief Group for common functionality (internal and external) +//! \since docker-finance 1.1.0 + // // PHP // diff --git a/container/src/root/common/utility.hh b/container/src/root/common/utility.hh new file mode 100644 index 0000000..148146e --- /dev/null +++ b/container/src/root/common/utility.hh @@ -0,0 +1,134 @@ +// docker-finance | modern accounting for the power-user +// +// Copyright (C) 2021-2025 Aaron Fiore (Founder, Evergreen Crypto LLC) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! \file +//! \author Aaron Fiore (Founder, Evergreen Crypto LLC) +//! \note File intended to be loaded into ROOT.cern framework / Cling interpreter +//! \since docker-finance 1.1.0 + +#ifndef CONTAINER_SRC_ROOT_COMMON_UTILITY_HH_ +#define CONTAINER_SRC_ROOT_COMMON_UTILITY_HH_ + +#include +#include +#include +#include +#include +#include + +//! \namespace dfi +//! \since docker-finance 1.0.0 +namespace dfi +{ +//! \namespace dfi::common +//! \brief Shared common functionality +//! \since docker-finance 1.1.0 +namespace common +{ +//! \brief Wrapper to ROOT Cling commands +//! \ingroup cpp_common_impl +//! \since docker-finance 1.0.0 +class Command +{ + public: + Command() = default; + ~Command() = default; + + Command(const Command&) = default; + Command& operator=(const Command&) = default; + + Command(Command&&) = default; + Command& operator=(Command&&) = default; + + private: + static void cmd_handler(const std::initializer_list& command) + { + for (const auto& cmd : command) + { + std::cout << "Interpreting: '" << cmd << "'" << std::endl; + gInterpreter->ProcessLine(cmd.c_str()); + } + } + + public: + //! \brief Load given file path + static void load(const std::string& path) + { + std::filesystem::path p(path); + if (!std::filesystem::exists(p)) + { + throw std::runtime_error( + std::string{"'" + path + "' does not exist!"}.c_str()); + } + if (!std::filesystem::is_regular_file(p)) + { + throw std::runtime_error( + std::string{"'" + path + "' is not a regular file!"}.c_str()); + } + + std::string cmd{".L " + path}; + Command::cmd_handler({cmd}); + } + + //! \brief Load given file paths + static void load(const std::initializer_list& commands) + { + for (const auto& cmd : commands) + Command::load(cmd); + } + + // TODO(afiore): unload +}; + +//! \brief Get ROOT environment variable +//! \param var ROOT variable +//! \note ROOT environment variables include shell (and shell caller) environment +//! \since docker-finance 1.0.0 +std::string get_env(const std::string& var) +{ + const auto* env = gSystem->Getenv(var.c_str()); + if (!env) + throw std::runtime_error( + std::string{var + " is not set or is unavailable"}.c_str()); + return std::string{env}; +} + +//! \brief Execute command in shell +//! \param cmd Shell command [args] +//! \returns Return value of command +//! \since docker-finance 1.0.0 +int exec(const std::string& cmd) +{ + return gSystem->Exec(cmd.c_str()); +} + +//! \brief Make current timestamp +//! \return timestamp in "yyyy-mm-ddThh:mm:ssZ" format +//! \since docker-finance 1.0.0 +std::string make_timestamp() +{ + const std::time_t t{std::time({})}; + std::vector time(std::size("yyyy-mm-ddThh:mm:ssZ")); + std::strftime(time.data(), time.size(), "%FT%TZ", std::gmtime(&t)); + return std::string{time.data()}; +} +} // namespace common +} // namespace dfi + +#endif // CONTAINER_SRC_ROOT_COMMON_UTILITY_HH_ + +// # vim: sw=2 sts=2 si ai et diff --git a/container/src/root/macro/common/utility.hh b/container/src/root/macro/common/utility.hh index e819b1d..518082e 100644 --- a/container/src/root/macro/common/utility.hh +++ b/container/src/root/macro/common/utility.hh @@ -23,12 +23,10 @@ #ifndef CONTAINER_SRC_ROOT_MACRO_COMMON_UTILITY_HH_ #define CONTAINER_SRC_ROOT_MACRO_COMMON_UTILITY_HH_ -#include -#include #include -#include #include -#include + +#include "../../common/utility.hh" //! \namespace dfi //! \since docker-finance 1.0.0 @@ -44,95 +42,8 @@ namespace macro //! \since docker-finance 1.0.0 namespace common { -//! \brief Wrapper to ROOT Cling commands -//! \ingroup cpp_macro_impl -//! \since docker-finance 1.0.0 -class Command final -{ - public: - Command() = default; - ~Command() = default; - - Command(const Command&) = default; - Command& operator=(const Command&) = default; - - Command(Command&&) = default; - Command& operator=(Command&&) = default; - - private: - static void cmd_handler(const std::initializer_list& command) - { - for (const auto& cmd : command) - { - std::cout << "Interpreting: '" << cmd << "'" << std::endl; - gInterpreter->ProcessLine(cmd.c_str()); - } - } - - public: - //! \brief Load given file path - static void load(const std::string& path) - { - std::filesystem::path p(path); - if (!std::filesystem::exists(p)) - { - throw std::runtime_error( - std::string{"'" + path + "' does not exist!"}.c_str()); - } - if (!std::filesystem::is_regular_file(p)) - { - throw std::runtime_error( - std::string{"'" + path + "' is not a regular file!"}.c_str()); - } - - std::string cmd{".L " + path}; - Command::cmd_handler({cmd}); - } - - //! \brief Load given file paths - static void load(const std::initializer_list& commands) - { - for (const auto& cmd : commands) - Command::load(cmd); - } -}; - -//! \brief Get ROOT environment variable -//! \param var ROOT variable -//! \note ROOT environment variables include shell (and shell caller) environment -//! \since docker-finance 1.0.0 -std::string get_env(const std::string& var) -{ - const auto* env = gSystem->Getenv(var.c_str()); - if (!env) - throw std::runtime_error( - std::string{var + " is not set or is unavailable"}.c_str()); - return std::string{env}; -} - -//! \brief Execute command in shell -//! \param cmd Shell command [args] -//! \returns Return value of command -//! \since docker-finance 1.0.0 -int exec(const std::string& cmd) -{ - return gSystem->Exec(cmd.c_str()); -} - -//! \brief Make current timestamp -//! \return timestamp in "yyyy-mm-ddThh:mm:ssZ" format -//! \since docker-finance 1.0.0 -std::string make_timestamp() -{ - const std::time_t t{std::time({})}; - std::vector time(std::size("yyyy-mm-ddThh:mm:ssZ")); - std::strftime(time.data(), time.size(), "%FT%TZ", std::gmtime(&t)); - return std::string{time.data()}; -} -} // namespace common - //! \brief Load file by path -//! \ingroup cpp_macro +//! \ingroup cpp_macro_impl //! \details //! Example: //!
  root [0] dfi::macro::load("test/unit.C")
@@ -141,105 +52,81 @@ std::string make_timestamp() //!
  root/macro/test/unit.C
//! //! \note Parent directory is `root/macro` +//! \todo Isolate for macros only (similar to plugins) void load(const std::string& path) { - common::Command::load(path); + ::dfi::common::Command::load(path); } //! \brief Wrapper to load files by list of paths -//! \ingroup cpp_macro +//! \ingroup cpp_macro_impl //! \details //! Example: -//!
  root [0] dfi::macro::load({"test/unit.C", "../src/hash.hh"})
+//!
  root [0] dfi::macro::load({"test/unit.C", "test/benchmark.C"})
//! //! Will load: -//!
  root/macro/test/unit.C and root/src/hash.hh
+//!
  root/macro/test/unit.C and root/test/benchmark.C
//! //! \note Parent directory is `root/macro` +//! \todo Isolate for macros only (similar to plugins) void load(const std::initializer_list& paths) { for (const auto& path : paths) - common::Command::load(path); + ::dfi::common::Command::load(path); } -} // namespace macro -//! \namespace dfi::plugin -//! \brief docker-finance plugins -//! \warning All plugins (repo/custom) must exist within this namespace -//! and work within their own inner namespace +//! \deprecated This will be removed in the v2 API; use `dfi::common` namespace instead +//! \todo Remove in 2.0.0 //! \since docker-finance 1.0.0 -namespace plugin +class Command : public ::dfi::common::Command { -//! \brief Load plugin by pseudo-paths -//! \details Wrapper to load from directory outside of default tree -//! \param path Must be of string "repo/file" or "custom/file" where file is -//! a plugin filename that exists in repository plugin path or -//! a client-side end-user's custom plugin path. -//! \ingroup cpp_plugin -//! \details -//! Example: -//!
  root [0] dfi::plugin::load("repo/example.cc")
-//! -//! Will load: -//!
  ${DOCKER_FINANCE_CONTAINER_REPO}/plugins/root/example.cc
-//! -//! Example: -//!
  root [0] dfi::plugin::load("custom/example.cc")
-//! -//! Will load: -//!
  ${DOCKER_FINANCE_CLIENT_PLUGINS}/root/example.cc
-//! -//! \note Parent directory for all plugins are outside of repository's `root` directory +}; + +//! \deprecated This will be removed in the v2 API; use `dfi::common` namespace instead +//! \todo Remove in 2.0.0 +//! \since docker-finance 1.0.0 +std::string get_env(const std::string& var) +{ + return ::dfi::common::get_env(var); +} + +//! \deprecated This will be removed in the v2 API; use `dfi::common` namespace instead +//! \todo Remove in 2.0.0 +//! \since docker-finance 1.0.0 +int exec(const std::string& cmd) +{ + return ::dfi::common::exec(cmd); +} + +//! \deprecated This will be removed in the v2 API; use `dfi::common` namespace instead +//! \todo Remove in 2.0.0 +//! \since docker-finance 1.0.0 +std::string make_timestamp() +{ + return ::dfi::common::make_timestamp(); +} +} // namespace common + +//! \brief Convenience wrapper to inner common loader +//! \ref dfi::macro::common::load(const std::string& path) +//! \ingroup cpp_macro +//! \since docker-finance 1.1.0 void load(const std::string& path) { - const std::string type{path.substr(0, path.find("/"))}; - - std::string file{path}; - file.erase(0, file.find("/") + 1); - - if (type == "repo") - { - file.insert( - 0, - macro::common::get_env("DOCKER_FINANCE_CONTAINER_REPO") - + "/plugins/root/"); - } - else if (type == "custom") - { - file.insert( - 0, - macro::common::get_env("DOCKER_FINANCE_CONTAINER_PLUGINS") - + "/root/"); - } - else - { - throw std::runtime_error( - "must be of type 'repo/' or 'custom/'"); - } - - macro::common::Command::load(file); + common::load(path); } - -//! \brief Wrapper to load plugins by list of pseudo-paths -//! \ingroup cpp_plugin -//! \param paths List must consist of string "repo/file" or "custom/file" where file is -//! a plugin filename that exists in repository plugin path or -//! a client-side end-user's custom plugin path. -//! \details -//! Example: -//!
  root [0] dfi::plugin::load({"repo/example.cc", "custom/example.cc"})
-//! -//! Will load: -//!
  ${DOCKER_FINANCE_CONTAINER_REPO}/plugins/root/example.cc -//! and ${DOCKER_FINANCE_CLIENT_PLUGINS}/root/example.cc
-//! -//! \note Parent directory for all plugins are outside of repository's `root` directory +//! \brief Convenience wrapper to inner common loader +//! \ref dfi::macro::common::load(const std::initializer_list& paths) +//! \ingroup cpp_macro +//! \since docker-finance 1.1.0 void load(const std::initializer_list& paths) { - for (const auto& path : paths) - macro::common::Command::load(path); + common::load(paths); } -} // namespace plugin + +// TODO(afiore): unload + +} // namespace macro } // namespace dfi #endif // CONTAINER_SRC_ROOT_MACRO_COMMON_UTILITY_HH_ diff --git a/container/src/root/macro/rootlogon.C b/container/src/root/macro/rootlogon.C index d36967c..5963eba 100644 --- a/container/src/root/macro/rootlogon.C +++ b/container/src/root/macro/rootlogon.C @@ -25,9 +25,6 @@ #include -// NOTE: the one-and-only header at startup that's not manually loaded -#include "./common/utility.hh" - //! \namespace dfi //! \since docker-finance 1.0.0 namespace dfi @@ -182,7 +179,7 @@ void rootlogon() // Add nested directory headers gInterpreter->AddIncludePath("/usr/include/botan-3"); - // Link libraries + // Link default packaged libraries gSystem->AddLinkedLibs("-lgtest"); // gtest/gmock gSystem->AddLinkedLibs("-lbenchmark"); // gbenchmark gSystem->AddLinkedLibs("-pthread"); // gtest/gmock/gbenchmark @@ -191,7 +188,9 @@ void rootlogon() gSystem->AddLinkedLibs("-lcryptopp"); // Crypto++ gSystem->AddLinkedLibs("-lsodium"); // libsodium - // Load docker-finance public API source + // Load default `dfi` public consumables + gInterpreter->ProcessLine(".L ../plugin/common/utility.hh"); + gInterpreter->ProcessLine(".L ../macro/common/utility.hh"); gInterpreter->ProcessLine(".L ../src/hash.hh"); gInterpreter->ProcessLine(".L ../src/random.hh"); gInterpreter->ProcessLine(".L ../src/utility.hh"); diff --git a/container/src/root/macro/test/benchmark.C b/container/src/root/macro/test/benchmark.C index 975e3e4..26b1384 100644 --- a/container/src/root/macro/test/benchmark.C +++ b/container/src/root/macro/test/benchmark.C @@ -28,7 +28,7 @@ #include #include -#include "../common/utility.hh" +#include "../../common/utility.hh" //! \namespace dfi //! \since docker-finance 1.0.0 @@ -70,10 +70,9 @@ class Benchmark {"../test/benchmark/random.hh"}, {"../test/benchmark/utility.hh"}}; - namespace common = ::dfi::macro::common; if (!loaded) { - common::Command::load(paths); + ::dfi::common::Command::load(paths); loaded = true; } diff --git a/container/src/root/macro/test/unit.C b/container/src/root/macro/test/unit.C index 37abafe..0670538 100644 --- a/container/src/root/macro/test/unit.C +++ b/container/src/root/macro/test/unit.C @@ -28,7 +28,7 @@ #include #include -#include "../common/utility.hh" +#include "../../common/utility.hh" //! \namespace dfi //! \since docker-finance 1.0.0 @@ -71,10 +71,9 @@ class Unit {"../test/unit/type.hh"}, {"../test/unit/utility.hh"}}; - namespace common = ::dfi::macro::common; if (!loaded) { - common::Command::load(paths); + ::dfi::common::Command::load(paths); loaded = true; } diff --git a/container/src/root/plugin/common/utility.hh b/container/src/root/plugin/common/utility.hh new file mode 100644 index 0000000..a124f5d --- /dev/null +++ b/container/src/root/plugin/common/utility.hh @@ -0,0 +1,140 @@ +// docker-finance | modern accounting for the power-user +// +// Copyright (C) 2021-2025 Aaron Fiore (Founder, Evergreen Crypto LLC) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! \file +//! \author Aaron Fiore (Founder, Evergreen Crypto LLC) +//! \note File intended to be loaded into ROOT.cern framework / Cling interpreter +//! \since docker-finance 1.1.0 + +#ifndef CONTAINER_SRC_ROOT_PLUGIN_COMMON_UTILITY_HH_ +#define CONTAINER_SRC_ROOT_PLUGIN_COMMON_UTILITY_HH_ + +#include +#include + +#include "../../common/utility.hh" + +//! \namespace dfi +//! \since docker-finance 1.0.0 +namespace dfi +{ +//! \namespace dfi::plugin +//! \brief docker-finance plugins +//! \warning All plugins (repo/custom) must exist within this namespace +//! and work within their own inner namespace +//! \since docker-finance 1.0.0 +namespace plugin +{ +//! \namespace dfi::plugin::common +//! \brief Shared ROOT plugin-related functionality +//! \since docker-finance 1.1.0 +namespace common +{ +//! \brief Load plugin by pseudo-paths +//! \details Wrapper to load from directory outside of default tree +//! \param path Must be of string "repo/file" or "custom/file" where file is +//! a plugin filename that exists in repository plugin path or +//! a client-side end-user's custom plugin path. +//! \ingroup cpp_plugin_impl +//! \details +//! Example: +//!
  root [0] dfi::plugin::load("repo/example.cc")
+//! +//! Will load: +//!
  ${DOCKER_FINANCE_CONTAINER_REPO}/plugins/root/example.cc
+//! +//! Example: +//!
  root [0] dfi::plugin::load("custom/example.cc")
+//! +//! Will load: +//!
  ${DOCKER_FINANCE_CLIENT_PLUGINS}/root/example.cc
+//! +//! \note Parent directory for all plugins are outside of repository's `root` directory +void load(const std::string& path) +{ + const std::string type{path.substr(0, path.find("/"))}; + + std::string file{path}; + file.erase(0, file.find("/") + 1); + + if (type == "repo") + { + file.insert( + 0, + ::dfi::common::get_env("DOCKER_FINANCE_CONTAINER_REPO") + + "/plugins/root/"); + } + else if (type == "custom") + { + file.insert( + 0, + ::dfi::common::get_env("DOCKER_FINANCE_CONTAINER_PLUGINS") + + "/root/"); + } + else + { + throw std::runtime_error( + "must be of type 'repo/' or 'custom/'"); + } + + ::dfi::common::Command::load(file); +} + +//! \brief Wrapper to load plugins by list of pseudo-paths +//! \ingroup cpp_plugin_impl +//! \param paths List must consist of string "repo/file" or "custom/file" where file is +//! a plugin filename that exists in repository plugin path or +//! a client-side end-user's custom plugin path. +//! \details +//! Example: +//!
  root [0] dfi::plugin::load({"repo/example.cc", "custom/example.cc"})
+//! +//! Will load: +//!
  ${DOCKER_FINANCE_CONTAINER_REPO}/plugins/root/example.cc +//! and ${DOCKER_FINANCE_CLIENT_PLUGINS}/root/example.cc
+//! +//! \note Parent directory for all plugins are outside of repository's `root` directory +void load(const std::initializer_list& paths) +{ + for (const auto& path : paths) + ::dfi::plugin::common::load(path); +} +} // namespace common + +//! \brief Convenience wrapper to inner common loader +//! \ingroup cpp_plugin +//! \since docker-finance 1.1.0 +void load(const std::string& path) +{ + common::load(path); +} +//! \brief Convenience wrapper to inner common loader +//! \ingroup cpp_plugin +//! \since docker-finance 1.1.0 +void load(const std::initializer_list& paths) +{ + common::load(paths); +} + +// TODO(afiore): unload + +} // namespace plugin +} // namespace dfi + +#endif // CONTAINER_SRC_ROOT_PLUGIN_COMMON_UTILITY_HH_ + +// # vim: sw=2 sts=2 si ai et diff --git a/container/src/root/test/common/utility.hh b/container/src/root/test/common/utility.hh index 572877d..e845446 100644 --- a/container/src/root/test/common/utility.hh +++ b/container/src/root/test/common/utility.hh @@ -25,9 +25,11 @@ #include #include +#include #include #include +#include "../../common/utility.hh" #include "../../src/utility.hh" //! \namespace dfi @@ -93,6 +95,17 @@ struct ByteFixture t_byte byte; }; + +//! \brief Common fixture +//! \note Not a 'common' fixture but rather a fixture for 'common' +//! \since docker-finance 1.1.0 +struct CommonFixture +{ + protected: + using EErrorCode = ::TInterpreter::EErrorCode; + std::unique_ptr ecode; + CommonFixture() { ecode = std::make_unique(); } +}; } // namespace tests } // namespace dfi diff --git a/container/src/root/test/unit/utility.hh b/container/src/root/test/unit/utility.hh index 4cca4e4..e6f2dee 100644 --- a/container/src/root/test/unit/utility.hh +++ b/container/src/root/test/unit/utility.hh @@ -28,8 +28,11 @@ #include #include #include +#include #include #include +#include +#include #include #include #include @@ -275,6 +278,159 @@ TEST_F(ByteTransform, unordered_set) ASSERT_EQ(byte.encode(one), two); ASSERT_EQ(byte.decode(two), one); } + +//! \brief Common fixture (raw files) +//! \note Not a 'common' fixture but rather a fixture for 'common' +//! \since docker-finance 1.1.0 +struct CommonRawFiles : public ::testing::Test, + public ::dfi::tests::CommonFixture +{ + std::string path_1, path_2; + + void SetUp() override + { + try + { + path_1 = std::tmpnam(nullptr); + path_2 = std::tmpnam(nullptr); + } + catch (...) + { + THROW(std::runtime_error, "could not generate path"); + } + + std::ofstream file_1(path_1), file_2(path_2); + THROW_IF( + !file_1.is_open() || !file_2.is_open(), + std::runtime_error, + "could not create file"); + + file_1 << "using my_foo = int;\n"; + file_1.close(); + file_2 << "using my_bar = char;\n"; + file_2.close(); + + THROW_IF( + file_1.bad() || file_2.bad(), + std::runtime_error, + "could not write to file"); + } + + void TearDown() override + { + THROW_IF( + std::remove(path_1.c_str()), + std::runtime_error, + "could not remove file '" + path_1 + "'"); + + THROW_IF( + std::remove(path_2.c_str()), + std::runtime_error, + "could not remove file '" + path_2 + "'"); + } +}; + +TEST_F(CommonRawFiles, RawLoadSingle) +{ + ASSERT_THROW( + ::dfi::common::Command::load({path_1 + "should-not-exist"}), + std::runtime_error); + gInterpreter->ProcessLine("my_foo foo;", ecode.get()); + ASSERT_NE(ecode, nullptr); + EXPECT_NE(*ecode, EErrorCode::kNoError); + + ASSERT_NO_THROW(::dfi::common::Command::load(path_1)); + gInterpreter->ProcessLine("my_foo foo;", ecode.get()); + ASSERT_NE(ecode, nullptr); + EXPECT_EQ(*ecode, EErrorCode::kNoError); +} + +TEST_F(CommonRawFiles, RawLoadMultiple) +{ + ASSERT_THROW( + ::dfi::common::Command::load( + {{path_1 + "should-not-exist"}, {path_2 + "nor-should-this"}}), + std::runtime_error); + gInterpreter->ProcessLine("my_bar bar;", ecode.get()); + ASSERT_NE(ecode, nullptr); + EXPECT_NE(*ecode, EErrorCode::kNoError); + + ASSERT_NO_THROW(::dfi::common::Command::load({path_1, path_2})); + gInterpreter->ProcessLine("my_bar bar;", ecode.get()); + ASSERT_NE(ecode, nullptr); + EXPECT_EQ(*ecode, EErrorCode::kNoError); +} +// TODO(afiore): RawUnload + +//! \brief Common fixture (repo files) +//! \note Not a 'common' fixture but rather a fixture for 'common' +//! \since docker-finance 1.1.0 +struct CommonRepoFiles : public ::testing::Test, + public ::dfi::tests::CommonFixture +{ +}; + +TEST_F(CommonRepoFiles, MacroLoad) +{ + ASSERT_THROW( + ::dfi::macro::load("macro/should-not/exist.C"), std::runtime_error); + gInterpreter->ProcessLine( + "dfi::macro::common::crypto::botan::Hash h;", ecode.get()); + ASSERT_NE(ecode, nullptr); + EXPECT_NE(*ecode, EErrorCode::kNoError); + + ASSERT_NO_THROW(::dfi::macro::load("crypto/hash.C")); + gInterpreter->ProcessLine( + "dfi::macro::common::crypto::botan::Hash h;", ecode.get()); + ASSERT_NE(ecode, nullptr); + EXPECT_EQ(*ecode, EErrorCode::kNoError); + // TODO(afiore): multiple load +} +// TODO(afiore): MacroUnload + +TEST_F(CommonRepoFiles, PluginLoad) +{ + ASSERT_THROW( + ::dfi::plugin::load("repo/should-not/exist.cc"), std::runtime_error); + gInterpreter->ProcessLine( + "dfi::plugin::my_plugin_namespace::example2();", ecode.get()); + ASSERT_NE(ecode, nullptr); + EXPECT_NE(*ecode, EErrorCode::kNoError); + + ASSERT_NO_THROW(::dfi::plugin::load("repo/example.cc")); + gInterpreter->ProcessLine( + "dfi::plugin::my_plugin_namespace::example2();", ecode.get()); + ASSERT_NE(ecode, nullptr); + EXPECT_EQ(*ecode, EErrorCode::kNoError); + + // TODO(afiore): multiple load +} +// TODO(afiore): PluginUnload + +//! \brief Common fixture (free functions) +//! \note Not a 'common' fixture but rather a fixture for 'common' +//! \since docker-finance 1.1.0 +struct CommonFree : public ::testing::Test, public ::dfi::tests::CommonFixture +{ +}; + +TEST_F(CommonFree, env) +{ + ASSERT_THROW(::dfi::common::get_env("should-not-exist"), std::runtime_error); + ASSERT_NO_THROW(::dfi::common::get_env("DOCKER_FINANCE_VERSION")); +} + +TEST_F(CommonFree, exec) +{ + ASSERT_NE(::dfi::common::exec("should-not-exist"), 0); + ASSERT_EQ(::dfi::common::exec("pwd"), 0); +} + +TEST_F(CommonFree, make_timestamp) +{ + ASSERT_EQ(::dfi::common::make_timestamp().size(), 20); +} + } // namespace unit } // namespace tests } // namespace dfi