diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0d08c58b..54d1a87f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -54,6 +54,13 @@ jobs: cd bld make install + - name: Test xeus-cpp C++ + shell: bash -l {0} + run: | + cd bld/test + ./test_xeus_cpp + timeout-minutes: 4 + - name: test shell: bash -l {0} run: | diff --git a/CMakeLists.txt b/CMakeLists.txt index 217d24b9..aea8d33e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,7 +50,8 @@ OPTION(XEUS_CPP_BUILD_EXECUTABLE "Build the xcpp executable" ON) OPTION(XEUS_CPP_USE_SHARED_XEUS "Link xcpp with the xeus shared library (instead of the static library)" ON) OPTION(XEUS_CPP_USE_SHARED_XEUS_CPP "Link xcpp with the xeus shared library (instead of the static library)" ON) - +# Test options +OPTION(XEUS_CPP_BUILD_TESTS "xeus-cpp test suite" ON) if(EMSCRIPTEN) add_compile_definitions(XEUS_CPP_EMSCRIPTEN_WASM_BUILD) @@ -305,6 +306,13 @@ if(EMSCRIPTEN) xeus_wasm_link_options(xcpp "web,worker") endif() +# Tests +# ===== + +if(XEUS_CPP_BUILD_TESTS) + add_subdirectory(test) +endif() + # Installation # ============ include(CMakePackageConfigHelpers) diff --git a/environment-dev.yml b/environment-dev.yml index 65476d59..0c2df603 100644 --- a/environment-dev.yml +++ b/environment-dev.yml @@ -20,3 +20,4 @@ dependencies: - jupyter_kernel_test>=0.4.3 - nbval - pytest-rerunfailures + - doctest \ No newline at end of file diff --git a/src/xinspect.hpp b/src/xinspect.hpp index 24eaf254..15b8d523 100644 --- a/src/xinspect.hpp +++ b/src/xinspect.hpp @@ -160,6 +160,7 @@ namespace xcpp tagfile = it->at("tagfile"); std::string filename = tagfiles_dir + "/" + tagfile; pugi::xml_document doc; + doc.load_file(filename.c_str()); class_member_predicate predicate{typename_, "function", method[2]}; auto node = doc.find_node(predicate); if (!node.empty()) @@ -193,6 +194,7 @@ namespace xcpp tagfile = it->at("tagfile"); std::string filename = tagfiles_dir + "/" + tagfile; pugi::xml_document doc; + doc.load_file(filename.c_str()); for (auto c : check) { node_predicate predicate{c, find_string}; @@ -262,5 +264,36 @@ namespace xcpp kernel_res["status"] = "ok"; } } + + class xintrospection : public xpreamble + { + public: + + using xpreamble::pattern; + const std::string spattern = R"(^\?)"; + + xintrospection(clang::Interpreter& p) + : m_interpreter{p} + { + pattern = spattern; + } + + void apply(const std::string& code, nl::json& kernel_res) override + { + std::regex re(spattern + R"((.*))"); + std::smatch to_inspect; + std::regex_search(code, to_inspect, re); + inspect(to_inspect[1], kernel_res, m_interpreter); + } + + virtual xpreamble* clone() const override + { + return new xintrospection(*this); + } + + private: + + clang::Interpreter& m_interpreter; + }; } #endif diff --git a/src/xinterpreter.cpp b/src/xinterpreter.cpp index c8364e43..09fb27ce 100644 --- a/src/xinterpreter.cpp +++ b/src/xinterpreter.cpp @@ -327,16 +327,8 @@ namespace xcpp // Attempt normal evaluation try - { std::string exp = R"(\w*(?:\:{2}|\<.*\>|\(.*\)|\[.*\])?)"; - std::regex re(R"((\w*(?:\:{2}|\<.*\>|\(.*\)|\[.*\])?)(\.?)*$)"); - auto inspect_request = is_inspect_request(code, re); - if (inspect_request.first) - { - inspect(inspect_request.second[0], kernel_res, *m_interpreter); - } - + { compilation_result = process_code(*m_interpreter, code, error_stream); - } catch (std::exception& e) { @@ -589,6 +581,7 @@ namespace xcpp void interpreter::init_preamble() { + preamble_manager.register_preamble("introspection", new xintrospection(*m_interpreter)); preamble_manager.register_preamble("magics", new xmagics_manager()); preamble_manager.register_preamble("shell", new xsystem()); } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 00000000..f235f241 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,69 @@ +############################################################################# +# Copyright (c) 2023, xeus-cpp contributors # +# # +# Distributed under the terms of the BSD 3-Clause License. # +# # +# The full license is in the file LICENSE, distributed with this software. # +############################################################################# + + +# Unit tests +# ========== + +cmake_minimum_required(VERSION 3.1) + +if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) + project(xeus-cpp-test) + + enable_testing() + + find_package(xeus-cpp REQUIRED CONFIG) +endif() + +include(CheckCXXCompilerFlag) + +string(TOUPPER "${CMAKE_BUILD_TYPE}" U_CMAKE_BUILD_TYPE) + +if(CMAKE_CXX_COMPILER_ID MATCHES Clang OR CMAKE_CXX_COMPILER_ID MATCHES GNU OR CMAKE_CXX_COMPILER_ID MATCHES Intel) + add_compile_options(-Wunused-parameter -Wextra -Wreorder -Wconversion -Wsign-conversion) + + CHECK_CXX_COMPILER_FLAG(-march=native HAS_MARCH_NATIVE) + if (HAS_MARCH_NATIVE) + add_compile_options(-march=native) + endif() +endif() + +if(CMAKE_CXX_COMPILER_ID MATCHES MSVC) + add_compile_options(/EHsc /MP /bigobj) + add_link_options(/MANIFEST:NO) +endif() + +find_package(doctest) +find_package(Threads) + +set(XEUS_CPP_TESTS + main.cpp + test_interpreter.cpp +) + +add_executable(test_xeus_cpp ${XEUS_CPP_TESTS}) + +if (APPLE) + set_target_properties(test_xeus_cpp PROPERTIES + MACOSX_RPATH ON + ) +else() + set_target_properties(test_xeus_cpp PROPERTIES + BUILD_WITH_INSTALL_RPATH 1 + SKIP_BUILD_RPATH FALSE + ) +endif() + +set_target_properties(test_xeus_cpp PROPERTIES + INSTALL_RPATH_USE_LINK_PATH TRUE +) + +target_link_libraries(test_xeus_cpp xeus-cpp doctest::doctest ${CMAKE_THREAD_LIBS_INIT}) +target_include_directories(test_xeus_cpp PRIVATE ${XEUS_CPP_INCLUDE_DIR}) + +add_custom_target(xtest COMMAND test_xeus_cpp DEPENDS test_xeus_cpp) diff --git a/test/main.cpp b/test/main.cpp new file mode 100644 index 00000000..1309050a --- /dev/null +++ b/test/main.cpp @@ -0,0 +1,10 @@ +/*************************************************************************** + * Copyright (c) 2023, xeus-cpp contributors + * + * Distributed under the terms of the BSD 3-Clause License. + * + * The full license is in the file LICENSE, distributed with this software. + ****************************************************************************/ + +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "doctest/doctest.h" \ No newline at end of file diff --git a/test/test_interpreter.cpp b/test/test_interpreter.cpp new file mode 100644 index 00000000..a14903fa --- /dev/null +++ b/test/test_interpreter.cpp @@ -0,0 +1,36 @@ +/*************************************************************************** + * Copyright (c) 2023, xeus-cpp contributors + * + * Distributed under the terms of the BSD 3-Clause License. + * + * The full license is in the file LICENSE, distributed with this software. + ****************************************************************************/ + +#include "doctest/doctest.h" +#include "xeus-cpp/xinterpreter.hpp" + +TEST_SUITE("execute_request") +{ + TEST_CASE("fetch_documentation") + { + + xcpp::interpreter interpreter(0, nullptr); + + std::string code = "?std::vector"; + std::string inspect_result = "https://en.cppreference.com/w/cpp/container/vector"; + nl::json user_expressions = nl::json::object(); + + nl::json result = interpreter.execute_request( + code, + false, + false, + user_expressions, + false + ); + + REQUIRE(result["payload"][0]["data"]["text/plain"] == inspect_result); + REQUIRE(result["user_expressions"] == nl::json::object()); + REQUIRE(result["found"] == true); + REQUIRE(result["status"] == "ok"); + } +} \ No newline at end of file