// 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.0.0 #ifndef CONTAINER_SRC_ROOT_TEST_UNIT_UTILITY_HH_ #define CONTAINER_SRC_ROOT_TEST_UNIT_UTILITY_HH_ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../common/utility.hh" //! \namespace dfi //! \since docker-finance 1.0.0 namespace dfi { //! \namespace dfi::tests //! \brief docker-finance common test framework //! \ingroup cpp_tests //! \since docker-finance 1.0.0 namespace tests { //! \namespace dfi::tests::unit //! \brief docker-finance unit test cases //! \ingroup cpp_tests //! \since docker-finance 1.0.0 namespace unit { namespace common = ::dfi::common; //! \brief Tools utility fixture //! \since docker-finance 1.0.0 struct Tools : public ::testing::Test, public tests::ToolsFixture { }; TEST_F(Tools, random_dist_TRandom1) { ASSERT_NO_THROW(tools.dist_range<::TRandom1>(min, max)); } TEST_F(Tools, random_dist_TRandom2) { ASSERT_NO_THROW(tools.dist_range<::TRandom2>(min, max)); } TEST_F(Tools, random_dist_TRandom3) { ASSERT_NO_THROW(tools.dist_range<::TRandom3>(min, max)); } TEST_F(Tools, random_dist_TRandomMixMax) { ASSERT_NO_THROW(tools.dist_range<::TRandomMixMax>(min, max)); } TEST_F(Tools, random_dist_TRandomMixMax17) { ASSERT_NO_THROW(tools.dist_range<::TRandomMixMax17>(min, max)); } TEST_F(Tools, random_dist_TRandomMixMax256) { ASSERT_NO_THROW(tools.dist_range<::TRandomMixMax256>(min, max)); } TEST_F(Tools, random_dist_TRandomMT64) { ASSERT_NO_THROW(tools.dist_range<::TRandomMT64>(min, max)); } TEST_F(Tools, random_dist_TRandomRanlux48) { ASSERT_NO_THROW(tools.dist_range<::TRandomRanlux48>(min, max)); } TEST_F(Tools, random_dist_TRandomRanluxpp) { ASSERT_NO_THROW(tools.dist_range<::TRandomRanluxpp>(min, max)); } //! \brief Byte transformation fixture //! \since docker-finance 1.0.0 struct ByteTransform : public ::testing::Test, public tests::ByteFixture { }; TEST_F(ByteTransform, byte) { ASSERT_EQ(byte.encode(uint8_t{0x01}), std::byte{0x01}); ASSERT_EQ(byte.decode(std::byte{0x01}), uint8_t{0x01}); } TEST_F(ByteTransform, basic_string) { using t_one = std::basic_string; t_one one{fixed_bytes()()}; using t_two = std::basic_string; t_two two{fixed_bytes()()}; ASSERT_EQ(byte.encode(one), two); ASSERT_EQ(byte.decode(two), one); } TEST_F(ByteTransform, vector) { using t_one = std::vector; t_one one{fixed_bytes()()}; using t_two = std::vector; t_two two{fixed_bytes()()}; ASSERT_EQ(byte.encode(one), two); ASSERT_EQ(byte.decode(two), one); } TEST_F(ByteTransform, deque) { using t_one = std::deque; t_one one{fixed_bytes()()}; using t_two = std::deque; t_two two{fixed_bytes()()}; ASSERT_EQ(byte.encode(one), two); ASSERT_EQ(byte.decode(two), one); } TEST_F(ByteTransform, list) { using t_one = std::list; t_one one{fixed_bytes()()}; using t_two = std::list; t_two two{fixed_bytes()()}; ASSERT_EQ(byte.encode(one), two); ASSERT_EQ(byte.decode(two), one); } TEST_F(ByteTransform, forward_list) { using t_one = std::forward_list; t_one one{fixed_bytes()()}; using t_two = std::forward_list; t_two two{fixed_bytes()()}; ASSERT_EQ(byte.encode(one), two); ASSERT_EQ(byte.decode(two), one); } TEST_F(ByteTransform, map) { using t_one = std::map; t_one one{fixed_bytes()()}; using t_two = std::map; t_two two{fixed_bytes()()}; ASSERT_EQ(byte.encode(one), two); ASSERT_EQ(byte.decode(two), one); } TEST_F(ByteTransform, multimap) { using t_one = std::multimap; t_one one{fixed_bytes()()}; using t_two = std::multimap; t_two two{fixed_bytes()()}; ASSERT_EQ(byte.encode(one), two); ASSERT_EQ(byte.decode(two), one); } TEST_F(ByteTransform, multiset) { using t_one = std::multiset; t_one one{fixed_bytes()()}; using t_two = std::multiset; t_two two{fixed_bytes()()}; ASSERT_EQ(byte.encode(one), two); ASSERT_EQ(byte.decode(two), one); } TEST_F(ByteTransform, set) { using t_one = std::set; t_one one{fixed_bytes()()}; using t_two = std::set; t_two two{fixed_bytes()()}; ASSERT_EQ(byte.encode(one), two); ASSERT_EQ(byte.decode(two), one); } TEST_F(ByteTransform, unordered_map) { using t_one = std::unordered_map; t_one one{fixed_bytes()()}; using t_two = std::unordered_map; t_two two{fixed_bytes()()}; ASSERT_EQ(byte.encode(one), two); ASSERT_EQ(byte.decode(two), one); } TEST_F(ByteTransform, unordered_multimap) { using t_one = std::unordered_multimap; t_one one{fixed_bytes()()}; using t_two = std::unordered_multimap; t_two two{fixed_bytes()()}; ASSERT_EQ(byte.encode(one), two); ASSERT_EQ(byte.decode(two), one); } TEST_F(ByteTransform, unordered_multiset) { using t_one = std::unordered_multiset; t_one one{fixed_bytes()()}; using t_two = std::unordered_multiset; t_two two{fixed_bytes()()}; ASSERT_EQ(byte.encode(one), two); ASSERT_EQ(byte.decode(two), one); } TEST_F(ByteTransform, unordered_set) { using t_one = std::unordered_set; t_one one{fixed_bytes()()}; using t_two = std::unordered_set; t_two two{fixed_bytes()()}; ASSERT_EQ(byte.encode(one), two); ASSERT_EQ(byte.decode(two), one); } //! \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, Line) { ASSERT_NO_THROW(common::line("")); ASSERT_THROW(common::line("a bar without a foo"), type::RuntimeError); ASSERT_NO_THROW(common::line("#define FOO 1")); } TEST_F(CommonFree, add_include_dir) { ASSERT_THROW( common::add_include_dir("/should-not-exist"), type::RuntimeError); ASSERT_NO_THROW(common::add_include_dir("/usr/include")); } TEST_F(CommonFree, add_linked_lib) { ASSERT_THROW( common::add_linked_lib("/should-not-exist.so"), type::RuntimeError); ASSERT_NO_THROW(common::add_linked_lib("/usr/lib/LLVMgold.so")); } TEST_F(CommonFree, remove_linked_lib) { ASSERT_THROW( common::remove_linked_lib("/should-not-exist.so"), type::RuntimeError); ASSERT_NO_THROW(common::add_linked_lib("/usr/lib/LLVMgold.so")); ASSERT_NO_THROW(common::remove_linked_lib("/usr/lib/LLVMgold.so")); } TEST_F(CommonFree, get_env) { ASSERT_THROW(common::get_env("should-not-exist"), type::RuntimeError); ASSERT_NO_THROW(common::get_env("DOCKER_FINANCE_VERSION")); } TEST_F(CommonFree, exec) { ASSERT_NE(common::exec("should-not-exist"), 0); ASSERT_EQ(common::exec("pwd"), 0); } TEST_F(CommonFree, make_timestamp) { ASSERT_EQ(common::make_timestamp().size(), 20); } //! \brief Common fixture (raw files) //! \note Not a 'common' fixture but rather a fixture for 'common' //! \since docker-finance 1.1.0 struct CommonFreeFiles : 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 (...) { common::throw_ex("could not generate path"); } std::ofstream file_1(path_1), file_2(path_2); common::throw_ex_if( !file_1.is_open() || !file_2.is_open(), "could not create file"); file_1 << "using my_foo = int;\n"; file_1.close(); file_2 << "using my_bar = char;\n"; file_2.close(); common::throw_ex_if( file_1.bad() || file_2.bad(), "could not write to file"); } void TearDown() override { common::throw_ex_if( std::remove(path_1.c_str()), "could not remove file '" + path_1 + "'"); common::throw_ex_if( std::remove(path_2.c_str()), "could not remove file '" + path_2 + "'"); } }; TEST_F(CommonFreeFiles, LoadSingle) { ASSERT_THROW(common::load({path_1 + "should-not-exist"}), type::RuntimeError); ASSERT_THROW(common::line("my_foo foo;"), type::RuntimeError); ASSERT_NO_THROW(common::load(path_1)); ASSERT_NO_THROW(common::line("my_foo foo;")); } TEST_F(CommonFreeFiles, LoadMultiple) { ASSERT_THROW( common::load( {{path_1 + "should-not-exist"}, {path_2 + "nor-should-this"}}), type::RuntimeError); ASSERT_THROW(common::line("my_bar bar;"), type::RuntimeError); ASSERT_NO_THROW(common::load({path_1, path_2})); ASSERT_NO_THROW(common::line("my_bar bar;")); } TEST_F(CommonFreeFiles, UnloadSingle) { ASSERT_NO_THROW(common::load(path_1)); ASSERT_NO_THROW(common::line("my_foo foo;")); ASSERT_NO_THROW(common::unload(path_1)); ASSERT_THROW(common::line("my_foo foo;"), type::RuntimeError); } TEST_F(CommonFreeFiles, UnloadMultiple) { ASSERT_NO_THROW(common::load({path_1, path_2})); ASSERT_NO_THROW(common::line("my_foo foo;")); ASSERT_NO_THROW(common::line("my_bar bar;")); ASSERT_NO_THROW(common::unload({path_1, path_2})); ASSERT_THROW(common::line("my_foo foo;"), type::RuntimeError); ASSERT_THROW(common::line("my_bar bar;"), type::RuntimeError); } TEST_F(CommonFreeFiles, ReloadSingle) { ASSERT_NO_THROW(common::load(path_1)); ASSERT_NO_THROW(common::line("my_foo foo;")); ASSERT_NO_THROW(common::reload(path_1)); ASSERT_NO_THROW(common::line("my_foo foo;")); } TEST_F(CommonFreeFiles, ReloadMultiple) { ASSERT_NO_THROW(common::load({path_1, path_2})); ASSERT_NO_THROW(common::line("my_foo foo;")); ASSERT_NO_THROW(common::line("my_bar bar;")); ASSERT_NO_THROW(common::reload({path_1, path_2})); ASSERT_NO_THROW(common::line("my_foo foo;")); ASSERT_NO_THROW(common::line("my_bar bar;")); } //! \brief MacroFreeFiles fixture //! \since docker-finance 1.1.0 //! \todo Move to Macro tests struct MacroFreeFiles : public ::testing::Test, public ::dfi::tests::CommonFixture { }; TEST_F(MacroFreeFiles, LoadSingle) { ASSERT_THROW( ::dfi::macro::load("macro/should-not/exist.C"), type::RuntimeError); ASSERT_THROW( common::line("dfi::macro::common::crypto::botan::Hash h;"), type::RuntimeError); // TODO(afiore): macro loading should not need to be prepended with "macro/" // (see TODO in common impl regarding plugins-like functionality) ASSERT_NO_THROW(::dfi::macro::load("macro/crypto/hash.C")); ASSERT_NO_THROW(common::line("dfi::macro::common::crypto::botan::Hash h;")); } // TODO(afiore): multiple load // TODO(afiore): unload, reload //! \brief PluginFreeFiles fixture //! \since docker-finance 1.1.0 //! \todo Move to Plugin tests struct PluginFreeFiles : public ::testing::Test, public ::dfi::tests::CommonFixture { // NOTE: custom plugin bind-mount is read-only }; TEST_F(PluginFreeFiles, LoadSingle) { ASSERT_THROW( ::dfi::plugin::load("repo/should-not/exist.cc"), type::RuntimeError); ASSERT_THROW( common::line("dfi::plugin::my_plugin_namespace::example2();"), type::RuntimeError); ASSERT_NO_THROW(::dfi::plugin::load("repo/example.cc")); ASSERT_NO_THROW( common::line("dfi::plugin::my_plugin_namespace::example2();")); } // TODO(afiore): multiple load // TODO(afiore): unload, reload } // namespace unit } // namespace tests } // namespace dfi #endif // CONTAINER_SRC_ROOT_TEST_UNIT_UTILITY_HH_ // # vim: sw=2 sts=2 si ai et