diff --git a/include/xeus-cpp/xholder.hpp b/include/xeus-cpp/xholder.hpp index fd36acc2..4f7a38d6 100644 --- a/include/xeus-cpp/xholder.hpp +++ b/include/xeus-cpp/xholder.hpp @@ -16,12 +16,13 @@ #include #include "xpreamble.hpp" +#include "xeus_cpp_config.hpp" namespace nl = nlohmann; namespace xcpp { - class xholder_preamble + class XEUS_CPP_API xholder_preamble { public: diff --git a/test/test_interpreter.cpp b/test/test_interpreter.cpp index 392b58d9..26027db5 100644 --- a/test/test_interpreter.cpp +++ b/test/test_interpreter.cpp @@ -8,13 +8,14 @@ #include "doctest/doctest.h" #include "xeus-cpp/xinterpreter.hpp" +#include "xeus-cpp/xholder.hpp" +#include "xeus-cpp/xmanager.hpp" #include "xeus-cpp/xutils.hpp" TEST_SUITE("execute_request") { TEST_CASE("fetch_documentation") { - xcpp::interpreter interpreter(0, nullptr); std::string code = "?std::vector"; @@ -22,10 +23,10 @@ TEST_SUITE("execute_request") nl::json user_expressions = nl::json::object(); nl::json result = interpreter.execute_request( - code, - false, - false, - user_expressions, + code, + false, + false, + user_expressions, false ); @@ -48,3 +49,232 @@ TEST_SUITE("extract_filename") REQUIRE(argc == 2); } } + +TEST_SUITE("should_print_version") +{ + // This test case checks if the function `should_print_version` correctly identifies + // when the "--version" argument is passed. It sets up a scenario where "--version" + // is one of the command line arguments and checks if the function returns true. + TEST_CASE("should_print_version_with_version_arg") + { + char arg1[] = "program_name"; + char arg2[] = "--version"; + char* argv[] = {arg1, arg2}; + int argc = 2; + + bool result = xcpp::should_print_version(argc, argv); + + REQUIRE(result == true); + } + + // This test case checks if the function `should_print_version` correctly identifies + // when the "--version" argument is not passed. It sets up a scenario where "--version" + // is not one of the command line arguments and checks if the function returns false. + TEST_CASE("should_print_version_without_version_arg") + { + char arg1[] = "program_name"; + char arg2[] = "-f"; + char arg3[] = "filename"; + char* argv[] = {arg1, arg2, arg3}; + int argc = 3; + + bool result = xcpp::should_print_version(argc, argv); + + REQUIRE(result == false); + } +} + +TEST_SUITE("build_interpreter") +{ + // This test case checks if the function `build_interpreter` returns a non-null pointer + // when valid arguments are passed. It sets up a scenario with valid command line arguments + // and checks if the function returns a non-null pointer. + TEST_CASE("build_interpreter_pointer_not_null") + { + char arg1[] = "program_name"; + char arg2[] = "-option1"; + char* argv[] = {arg1, arg2}; + int argc = 2; + + interpreter_ptr interp_ptr = xcpp::build_interpreter(argc, argv); + + REQUIRE(interp_ptr != nullptr); + } +} + +TEST_SUITE("is_match_magics_manager") +{ + // This test case checks if the function `is_match` correctly identifies strings that match + // the regex pattern used in `xmagics_manager`. It sets up a scenario where strings that should + // match the pattern are passed and checks if the function returns true. + TEST_CASE("is_match_true") + { + xcpp::xmagics_manager manager; + + bool result1 = manager.is_match("%%magic"); + bool result2 = manager.is_match("%magic"); + + REQUIRE(result1 == true); + REQUIRE(result2 == true); + } + + // This test case checks if the function `is_match` correctly identifies strings that do not match + // the regex pattern used in `xmagics_manager`. It sets up a scenario where strings that should not + // match the pattern are passed and checks if the function returns false. + TEST_CASE("is_match_false") + { + xcpp::xmagics_manager manager; + + bool result1 = manager.is_match("not a magic"); + bool result2 = manager.is_match("%%"); + bool result3 = manager.is_match("%"); + + REQUIRE(result1 == false); + REQUIRE(result2 == false); + REQUIRE(result3 == false); + } +} + +TEST_SUITE("clone_magics_manager") +{ + // This test case checks if the function `clone_magics_manager` returns a non-null pointer + // when called. It doesn't require any specific setup as it's testing the default behavior + // of the function, and checks if the function returns a non-null pointer. + TEST_CASE("clone_magics_manager_not_null") + { + xcpp::xmagics_manager manager; + + xcpp::xpreamble* clone = manager.clone(); + + REQUIRE(clone != nullptr); + } + + // This test case checks if the function `clone_magics_manager` returns a cloned object + // of the same type as the original. It calls the function and checks if the type of the + // returned object matches the type of the original `magics_manager`. + TEST_CASE("clone_magics_manager_same_type") + { + xcpp::xmagics_manager manager; + + xcpp::xpreamble* clone = manager.clone(); + + REQUIRE(dynamic_cast(clone) != nullptr); + + delete clone; + } +} + +TEST_SUITE("xpreamble_manager_operator") +{ + // This test case checks if the `xpreamble_manager` correctly registers and accesses + // a `xpreamble` object. It sets up a scenario where a `xpreamble` object is registered + // with a name and checks if the object can be accessed using the same name. + TEST_CASE("register_and_access") + { + std::string name = "test"; + xcpp::xpreamble_manager manager; + xcpp::xmagics_manager* magics = new xcpp::xmagics_manager(); + manager.register_preamble(name, magics); + + xcpp::xholder_preamble& result = manager.operator[](name); + + REQUIRE(&(result.get_cast()) == magics); + } +} + +TEST_SUITE("xbuffer") +{ + // This test case checks if the `xoutput_buffer` correctly calls the callback function + // when the buffer is flushed. It sets up a scenario where a `xoutput_buffer` object is + // created with a callback function, and checks if the callback function is called when + // the buffer is flushed. + TEST_CASE("xoutput_buffer_calls_callback_on_sync") + { + std::string callback_output; + auto callback = [&callback_output](const std::string& value) + { + callback_output = value; + }; + xcpp::xoutput_buffer buffer(callback); + std::ostream stream(&buffer); + + stream << "Hello, world!"; + stream.flush(); + + REQUIRE(callback_output == "Hello, world!"); + } + + // This test case checks if the `xinput_buffer` correctly calls the callback function + // when the buffer is flushed. It sets up a scenario where a `xinput_buffer` object is + // created with a callback function, and checks if the callback function is called when + // the buffer is flushed. + TEST_CASE("xinput_buffer_calls_callback_on_underflow") + { + std::string callback_input; + auto callback = [&callback_input](std::string& value) + { + value = callback_input; + }; + xcpp::xinput_buffer buffer(callback); + std::istream stream(&buffer); + + callback_input = "Hello, world!"; + std::string output; + std::getline(stream, output); + + REQUIRE(output == "Hello, world!"); + } + + // This test case checks if the `xoutput_buffer` correctly handles an empty output. + // It sets up a scenario where the `xoutput_buffer` is given an empty output, then checks + // if the buffer correctly identifies and handles this situation without errors or exceptions. + TEST_CASE("xoutput_buffer_handles_empty_output") + { + std::string callback_output; + auto callback = [&callback_output](const std::string& value) + { + callback_output = value; + }; + + xcpp::xoutput_buffer buffer(callback); + std::ostream stream(&buffer); + + stream << ""; + stream.flush(); + + REQUIRE(callback_output == ""); + } + + // This test case checks if the `xinput_buffer` correctly handles an empty input. + // It sets up a scenario where the `xinput_buffer` is given an empty input, then checks + // if the buffer correctly identifies and handles this situation without errors or exceptions. + TEST_CASE("xinput_buffer_handles_empty_input") + { + std::string callback_input = ""; + auto callback = [&callback_input](std::string& value) + { + value = callback_input; + }; + + xcpp::xinput_buffer buffer(callback); + std::istream stream(&buffer); + + std::string output; + std::getline(stream, output); + + REQUIRE(output == ""); + } + + // This test case checks if the `xnull` correctly discards the output. + // It sets up a scenario where the `xnull` is given some output, then checks + // if the output is correctly discarded and not stored or returned. + TEST_CASE("xnull_discards_output") + { + xcpp::xnull null_buf; + std::ostream null_stream(&null_buf); + + null_stream << "Hello, world!"; + + REQUIRE(null_stream.good() == true); + } +} \ No newline at end of file