From 223513a76e56d3474adb133c96504bbb8cf322f6 Mon Sep 17 00:00:00 2001 From: Greg Landrum Date: Tue, 4 Sep 2018 16:32:17 +0200 Subject: [PATCH] Start to use Catch2 for new tests (#1732) * backup * build works * works * builds on linux * rename the test * add another test to make sure that works --- CMakeLists.txt | 7 ++++ Code/GraphMol/CMakeLists.txt | 3 ++ Code/GraphMol/SmilesParse/CMakeLists.txt | 1 + Code/GraphMol/SmilesParse/catch_tests.cpp | 48 +++++++++++++++++++++++ Code/GraphMol/catch_tests.cpp | 45 +++++++++++++++++++++ Code/cmake/Modules/RDKitUtils.cmake | 15 +++++++ External/catch/CMakeLists.txt | 22 +++++++++++ 7 files changed, 141 insertions(+) create mode 100644 Code/GraphMol/SmilesParse/catch_tests.cpp create mode 100644 Code/GraphMol/catch_tests.cpp create mode 100644 External/catch/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 8b99a3161..a999a579e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/Code/cmake/Modules/") add_library(rdkit_base INTERFACE) +add_dependencies(rdkit_base catch) option(RDK_BUILD_SWIG_WRAPPERS "build the SWIG wrappers" OFF ) option(RDK_BUILD_PYTHON_WRAPPERS "build the standard python wrappers" ON ) @@ -100,6 +101,12 @@ string(REGEX REPLACE "^0" "" RDKit_intMonth ${RDKit_Month} ) set(RDKit_CodeDir "${CMAKE_CURRENT_SOURCE_DIR}/Code") set(RDKit_ExternalDir "${CMAKE_CURRENT_SOURCE_DIR}/External") +#include catch +add_subdirectory(${RDKit_ExternalDir}/catch) + + +include_directories(${CATCH_INCLUDE_DIR} ${COMMON_INCLUDES}) + if(RDK_INSTALL_INTREE) set(RDKit_BinDir "${CMAKE_SOURCE_DIR}/bin") set(RDKit_LibDir "${CMAKE_SOURCE_DIR}/lib") diff --git a/Code/GraphMol/CMakeLists.txt b/Code/GraphMol/CMakeLists.txt index 2cea2d3a8..623d29237 100644 --- a/Code/GraphMol/CMakeLists.txt +++ b/Code/GraphMol/CMakeLists.txt @@ -136,3 +136,6 @@ rdkit_test(molBundleTest testMolBundle.cpp LINK_LIBRARIES SmilesParse GraphMol RDGeometryLib RDGeneral SubstructMatch FileParsers) rdkit_test(test-valgrind test-valgrind.cpp LINK_LIBRARIES SmilesParse GraphMol RDGeneral) + +rdkit_catch_test(testsCatch catch_tests.cpp + LINK_LIBRARIES SubstructMatch FileParsers SmilesParse GraphMol RDGeometryLib RDGeneral) diff --git a/Code/GraphMol/SmilesParse/CMakeLists.txt b/Code/GraphMol/SmilesParse/CMakeLists.txt index e7ea17b74..7ba0ccfca 100644 --- a/Code/GraphMol/SmilesParse/CMakeLists.txt +++ b/Code/GraphMol/SmilesParse/CMakeLists.txt @@ -71,3 +71,4 @@ rdkit_test(smiTest2 test2.cpp LINK_LIBRARIES SmilesParse GraphMol RDGeneral RDGe rdkit_test(cxsmilesTest cxsmiles_test.cpp LINK_LIBRARIES FileParsers SmilesParse GraphMol RDGeneral RDGeometryLib ) rdkit_test(smaTest1 smatest.cpp LINK_LIBRARIES SmilesParse SubstructMatch GraphMol RDGeneral RDGeometryLib ) +rdkit_catch_test(smiTestCatch catch_tests.cpp LINK_LIBRARIES FileParsers SmilesParse GraphMol RDGeneral RDGeometryLib ) diff --git a/Code/GraphMol/SmilesParse/catch_tests.cpp b/Code/GraphMol/SmilesParse/catch_tests.cpp new file mode 100644 index 000000000..e49247700 --- /dev/null +++ b/Code/GraphMol/SmilesParse/catch_tests.cpp @@ -0,0 +1,48 @@ +#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do + // this in one cpp file +#include "catch.hpp" + +#include +#include +#include + +using namespace RDKit; + +TEST_CASE("Github #1972", "[SMILES,bug]") { + SECTION("basics") { + std::vector> smiles = { + {"[C@@]1(Cl)(F)(I).Br1", "[C@@](Br)(Cl)(F)(I)"}, + {"[C@@](Cl)(F)(I)1.Br1", "[C@@](Cl)(F)(I)Br"}, + {"[C@@](Cl)1(F)(I).Br1", "[C@@](Cl)(Br)(F)(I)"}, + {"[C@@](Cl)(F)1(I).Br1", "[C@@](Cl)(F)(Br)(I)"}}; + for (const auto &pr : smiles) { + std::unique_ptr m1(SmilesToMol(pr[0])); + std::unique_ptr m2(SmilesToMol(pr[1])); + REQUIRE(m1); + REQUIRE(m2); + auto csmi1 = MolToSmiles(*m1); + auto csmi2 = MolToSmiles(*m2); + CHECK(csmi1 == csmi2); + } + } + SECTION("further examples") { + std::vector> smiles = { + {"[C@@]1(Cl)2(I).Br1.F2", "[C@@](Br)(Cl)(F)(I)"}, + {"[C@@](Cl)2(I)1.Br1.F2", "[C@@](Cl)(F)(I)Br"}, + {"[C@@]12(Cl)(I).Br1.F2", "[C@@](Br)(F)(Cl)(I)"}, + {"[C@@]21(Cl)(I).Br1.F2", "[C@@](F)(Br)(Cl)(I)"}, + {"[C@@](Cl)12(I).Br1.F2", "[C@@](Cl)(Br)(F)(I)"}, + {"[C@@](Cl)21(I).Br1.F2", "[C@@](Cl)(F)(Br)(I)"}, + {"[C@@](Cl)(I)21.Br1.F2", "[C@@](Cl)(I)(F)(Br)"}, + {"[C@@](Cl)(I)12.Br1.F2", "[C@@](Cl)(I)(Br)(F)"}}; + for (const auto &pr : smiles) { + std::unique_ptr m1(SmilesToMol(pr[0])); + std::unique_ptr m2(SmilesToMol(pr[1])); + REQUIRE(m1); + REQUIRE(m2); + auto csmi1 = MolToSmiles(*m1); + auto csmi2 = MolToSmiles(*m2); + CHECK(csmi1 == csmi2); + } + } +} diff --git a/Code/GraphMol/catch_tests.cpp b/Code/GraphMol/catch_tests.cpp new file mode 100644 index 000000000..eabdcafa7 --- /dev/null +++ b/Code/GraphMol/catch_tests.cpp @@ -0,0 +1,45 @@ +#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do + // this in one cpp file +#include "catch.hpp" + +#include +#include +#include +#include +#include +#include + +using namespace RDKit; + +TEST_CASE("SMILES Parsing works", "[molops]") { + std::unique_ptr mol(SmilesToMol("C1CC1")); + REQUIRE(mol); + REQUIRE(mol->getNumAtoms() == 3); +} + +TEST_CASE("Sanitization tests", "[molops]") { + std::unique_ptr mol(SmilesToMol("C1=CC=CC=C1Cc2ccccc2", false, false)); + REQUIRE(mol); + REQUIRE(mol->getNumAtoms() == 13); + + SECTION("properties") { + mol->updatePropertyCache(); + CHECK(mol->getAtomWithIdx(0)->getTotalNumHs() == 1); + CHECK(!mol->getAtomWithIdx(0)->getIsAromatic()); + CHECK(mol->getAtomWithIdx(7)->getIsAromatic()); + SECTION("aromaticity") { + unsigned int opThatFailed; + MolOps::sanitizeMol(*mol, opThatFailed, MolOps::SANITIZE_SETAROMATICITY); + // mol->debugMol(std::cerr); + CHECK(mol->getAtomWithIdx(7)->getIsAromatic()); + // blocked by #1730 + // CHECK(mol->getAtomWithIdx(0)->getIsAromatic()); + } + SECTION("kekulize") { + unsigned int opThatFailed; + MolOps::sanitizeMol(*mol, opThatFailed, MolOps::SANITIZE_KEKULIZE); + CHECK(!mol->getAtomWithIdx(0)->getIsAromatic()); + CHECK(!mol->getAtomWithIdx(7)->getIsAromatic()); + } + } +} diff --git a/Code/cmake/Modules/RDKitUtils.cmake b/Code/cmake/Modules/RDKitUtils.cmake index 17fe098e7..aee8601d7 100644 --- a/Code/cmake/Modules/RDKitUtils.cmake +++ b/Code/cmake/Modules/RDKitUtils.cmake @@ -154,6 +154,21 @@ macro(rdkit_test) endif(RDK_BUILD_CPP_TESTS) endmacro(rdkit_test) +macro(rdkit_catch_test) + PARSE_ARGUMENTS(RDKTEST + "LINK_LIBRARIES;DEPENDS;DEST" + "" + ${ARGN}) + CAR(RDKTEST_NAME ${RDKTEST_DEFAULT_ARGS}) + CDR(RDKTEST_SOURCES ${RDKTEST_DEFAULT_ARGS}) + if(RDK_BUILD_CPP_TESTS) + add_executable(${RDKTEST_NAME} ${RDKTEST_SOURCES}) + target_link_libraries(${RDKTEST_NAME} ${RDKTEST_LINK_LIBRARIES}) + add_test(${RDKTEST_NAME} ${EXECUTABLE_OUTPUT_PATH}/${RDKTEST_NAME}) + #ParseAndAddCatchTests(${RDKTEST_NAME}) + endif(RDK_BUILD_CPP_TESTS) +endmacro(rdkit_catch_test) + macro(add_pytest) PARSE_ARGUMENTS(PYTEST "LINK_LIBRARIES;DEPENDS;DEST" diff --git a/External/catch/CMakeLists.txt b/External/catch/CMakeLists.txt new file mode 100644 index 000000000..aecb30bfa --- /dev/null +++ b/External/catch/CMakeLists.txt @@ -0,0 +1,22 @@ +project(catch_builder CXX) + +# Includes Catch in the project: +include(ExternalProject) + +ExternalProject_Add( + catch + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/catch + GIT_REPOSITORY https://github.com/philsquared/Catch.git + GIT_TAG "v2.1.1" + TIMEOUT 10 + UPDATE_COMMAND "" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + LOG_DOWNLOAD ON + ) + +# Expose required variable (CATCH_INCLUDE_DIR) to parent scope +ExternalProject_Get_Property(catch source_dir) +set(CATCH_MODULE_PATH ${source_dir} CACHE INTERNAL "location of Catch") +set(CATCH_INCLUDE_DIR ${CATCH_MODULE_PATH}/single_include CACHE INTERNAL "Path to include folder for Catch")