// // Copyright (C) 2019 Greg Landrum // @@ All Rights Reserved @@ // This file is part of the RDKit. // The contents are covered by the terms of the BSD license // which is included in the file license.txt, found at the root // of the RDKit source tree. // #include "RDGeneral/test.h" #include #include #include #include #include #include using namespace RDKit; TEST_CASE("Property list conversion", "[atom_list_properties]") { SECTION("basics: iprops") { auto m = "COC"_smiles; REQUIRE(m); m->setProp("atom.iprop.foo1", "1 6 9"); m->setProp("atom.iprop.foo2", "3 n/a 9"); m->setProp("atom.iprop.foo3", "[?] 5 1 ?"); m->setProp("atom.iprop.foo4", "[foo] 3 foo 9"); FileParserUtils::applyMolListPropsToAtoms(*m, "atom.iprop."); CHECK(m->getAtomWithIdx(0)->hasProp("foo1")); CHECK(m->getAtomWithIdx(1)->hasProp("foo1")); CHECK(m->getAtomWithIdx(2)->hasProp("foo1")); CHECK(m->getAtomWithIdx(0)->hasProp("foo2")); CHECK(!m->getAtomWithIdx(1)->hasProp("foo2")); CHECK(m->getAtomWithIdx(2)->hasProp("foo2")); CHECK(m->getAtomWithIdx(0)->hasProp("foo3")); CHECK(m->getAtomWithIdx(1)->hasProp("foo3")); CHECK(!m->getAtomWithIdx(2)->hasProp("foo3")); CHECK(m->getAtomWithIdx(0)->hasProp("foo4")); CHECK(!m->getAtomWithIdx(1)->hasProp("foo4")); CHECK(m->getAtomWithIdx(2)->hasProp("foo4")); CHECK(m->getAtomWithIdx(1)->getProp("foo1") == 6); CHECK(m->getAtomWithIdx(2)->getProp("foo2") == 9); CHECK(m->getAtomWithIdx(1)->getProp("foo3") == 1); CHECK(m->getAtomWithIdx(1)->getProp("foo3") == "1"); } SECTION("basics: dprops") { auto m = "COC"_smiles; REQUIRE(m); m->setProp("atom.dprop.foo1", "1 6 9"); m->setProp("atom.dprop.foo2", "3 n/a 9"); m->setProp("atom.dprop.foo3", "[?] 5 1 ?"); FileParserUtils::applyMolListPropsToAtoms(*m, "atom.dprop."); CHECK(m->getAtomWithIdx(0)->hasProp("foo1")); CHECK(m->getAtomWithIdx(1)->hasProp("foo1")); CHECK(m->getAtomWithIdx(2)->hasProp("foo1")); CHECK(m->getAtomWithIdx(0)->hasProp("foo2")); CHECK(!m->getAtomWithIdx(1)->hasProp("foo2")); CHECK(m->getAtomWithIdx(2)->hasProp("foo2")); CHECK(m->getAtomWithIdx(0)->hasProp("foo3")); CHECK(m->getAtomWithIdx(1)->hasProp("foo3")); CHECK(!m->getAtomWithIdx(2)->hasProp("foo3")); CHECK(m->getAtomWithIdx(1)->getProp("foo1") == 6); CHECK(m->getAtomWithIdx(2)->getProp("foo2") == 9); CHECK(m->getAtomWithIdx(1)->getProp("foo3") == 1); } SECTION("basics: props") { auto m = "COC"_smiles; REQUIRE(m); m->setProp("atom.prop.foo1", "1 6 9"); m->setProp("atom.prop.foo2", "3 n/a 9"); m->setProp("atom.prop.foo3", "[?] 5 1 ?"); FileParserUtils::applyMolListPropsToAtoms(*m, "atom.prop."); CHECK(m->getAtomWithIdx(0)->hasProp("foo1")); CHECK(m->getAtomWithIdx(1)->hasProp("foo1")); CHECK(m->getAtomWithIdx(2)->hasProp("foo1")); CHECK(m->getAtomWithIdx(0)->hasProp("foo2")); CHECK(!m->getAtomWithIdx(1)->hasProp("foo2")); CHECK(m->getAtomWithIdx(2)->hasProp("foo2")); CHECK(m->getAtomWithIdx(0)->hasProp("foo3")); CHECK(m->getAtomWithIdx(1)->hasProp("foo3")); CHECK(!m->getAtomWithIdx(2)->hasProp("foo3")); CHECK(m->getAtomWithIdx(1)->getProp("foo1") == "6"); CHECK(m->getAtomWithIdx(2)->getProp("foo2") == "9"); CHECK(m->getAtomWithIdx(1)->getProp("foo3") == "1"); } SECTION("basics: bprops") { auto m = "COC"_smiles; REQUIRE(m); m->setProp("atom.bprop.foo1", "1 0 0"); m->setProp("atom.bprop.foo2", "0 n/a 1"); m->setProp("atom.bprop.foo3", "[?] 0 1 ?"); FileParserUtils::applyMolListPropsToAtoms(*m, "atom.bprop."); CHECK(m->getAtomWithIdx(0)->hasProp("foo1")); CHECK(m->getAtomWithIdx(1)->hasProp("foo1")); CHECK(m->getAtomWithIdx(2)->hasProp("foo1")); CHECK(m->getAtomWithIdx(0)->hasProp("foo2")); CHECK(!m->getAtomWithIdx(1)->hasProp("foo2")); CHECK(m->getAtomWithIdx(2)->hasProp("foo2")); CHECK(m->getAtomWithIdx(0)->hasProp("foo3")); CHECK(m->getAtomWithIdx(1)->hasProp("foo3")); CHECK(!m->getAtomWithIdx(2)->hasProp("foo3")); CHECK(m->getAtomWithIdx(1)->getProp("foo1") == false); CHECK(m->getAtomWithIdx(2)->getProp("foo2") == true); CHECK(m->getAtomWithIdx(1)->getProp("foo3") == true); } } TEST_CASE("processMolPropertyLists", "[atom_list_properties]") { SECTION("basics") { auto m = "COC"_smiles; REQUIRE(m); m->setProp("atom.iprop.foo1", "1 6 9"); m->setProp("atom.dprop.foo2", "3 n/a 9"); m->setProp("atom.prop.foo3", "[?] 5 1 ?"); m->setProp("atom.bprop.foo4", "1 0 0"); FileParserUtils::processMolPropertyLists(*m); CHECK(m->getAtomWithIdx(0)->hasProp("foo1")); CHECK(m->getAtomWithIdx(1)->hasProp("foo1")); CHECK(m->getAtomWithIdx(2)->hasProp("foo1")); CHECK(m->getAtomWithIdx(0)->hasProp("foo2")); CHECK(!m->getAtomWithIdx(1)->hasProp("foo2")); CHECK(m->getAtomWithIdx(2)->hasProp("foo2")); CHECK(m->getAtomWithIdx(0)->hasProp("foo3")); CHECK(m->getAtomWithIdx(1)->hasProp("foo3")); CHECK(!m->getAtomWithIdx(2)->hasProp("foo3")); CHECK(m->getAtomWithIdx(0)->hasProp("foo4")); CHECK(m->getAtomWithIdx(1)->hasProp("foo4")); CHECK(m->getAtomWithIdx(2)->hasProp("foo4")); CHECK(m->getAtomWithIdx(1)->getProp("foo1") == 6); CHECK(m->getAtomWithIdx(2)->getProp("foo2") == 9); CHECK(m->getAtomWithIdx(1)->getProp("foo3") == "1"); CHECK(m->getAtomWithIdx(1)->getProp("foo4") == false); } } TEST_CASE("basic SDF handling", "[SDF][atom_list_properties]") { std::string sdf = R"SDF( RDKit 2D 3 3 0 0 0 0 0 0 0 0999 V2000 0.8660 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 -0.4330 0.7500 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 -0.4330 -0.7500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 1 2 1 0 2 3 1 0 3 1 1 0 M END > (1) 0.008 -0.314 0.008 > (1) 2 2 2 > (1) C1 N2 C3 > (1) 1 0 1 > (1) one n/a three > (1) [?] 2 2 ? $$$$ )SDF"; SECTION("no processing") { RDKit::SDMolSupplier suppl; suppl.setData(sdf); suppl.setProcessPropertyLists(false); std::unique_ptr m(suppl[0]); REQUIRE(m); CHECK(m->hasProp("atom.prop.AtomLabel")); CHECK(!m->getAtomWithIdx(0)->hasProp("AtomLabel")); } SECTION("with processing") { RDKit::SDMolSupplier suppl; suppl.setData(sdf); std::unique_ptr m(suppl[0]); REQUIRE(m); CHECK(m->hasProp("atom.prop.AtomLabel")); CHECK(m->getAtomWithIdx(0)->hasProp("AtomLabel")); } } TEST_CASE("createAtomPropertyLists", "[atom_list_properties]") { SECTION("basics") { auto m = "COC"_smiles; REQUIRE(m); m->getAtomWithIdx(0)->setProp("foo1", 1); m->getAtomWithIdx(2)->setProp("foo1", 9); FileParserUtils::createAtomIntPropertyList(*m, "foo1"); REQUIRE(m->hasProp("atom.iprop.foo1")); CHECK(m->getProp("atom.iprop.foo1") == "1 n/a 9"); m->getAtomWithIdx(0)->setProp("foo2", 1); m->getAtomWithIdx(1)->setProp("foo2", 4); m->getAtomWithIdx(2)->setProp("foo2", 9); FileParserUtils::createAtomDoublePropertyList(*m, "foo2"); REQUIRE(m->hasProp("atom.dprop.foo2")); CHECK(m->getProp("atom.dprop.foo2") == "1 4 9"); m->getAtomWithIdx(0)->setProp("foo3", "1"); m->getAtomWithIdx(1)->setProp("foo3", "4"); FileParserUtils::createAtomStringPropertyList(*m, "foo3", "?"); REQUIRE(m->hasProp("atom.prop.foo3")); CHECK(m->getProp("atom.prop.foo3") == "[?] 1 4 ?"); m->getAtomWithIdx(0)->setProp("foo4", 1); m->getAtomWithIdx(1)->setProp("foo4", 0); m->getAtomWithIdx(2)->setProp("foo4", 0); FileParserUtils::createAtomBoolPropertyList(*m, "foo4"); REQUIRE(m->hasProp("atom.bprop.foo4")); CHECK(m->getProp("atom.bprop.foo4") == "1 0 0"); } SECTION("long lines") { auto m = "COC"_smiles; REQUIRE(m); m->getAtomWithIdx(0)->setProp("foo1", std::string(80, 'a')); m->getAtomWithIdx(1)->setProp("foo1", std::string(80, 'b')); m->getAtomWithIdx(2)->setProp("foo1", std::string(80, 'c')); FileParserUtils::createAtomStringPropertyList(*m, "foo1"); REQUIRE(m->hasProp("atom.prop.foo1")); std::string ps = m->getProp("atom.prop.foo1"); CHECK(ps.length() > 240); CHECK(ps.find("\n") != std::string::npos); for (auto &atom : m->atoms()) { atom->clearProp("foo1"); } FileParserUtils::applyMolListPropsToAtoms(*m, "atom.prop."); CHECK(m->getAtomWithIdx(0)->getProp("foo1") == std::string(80, 'a')); CHECK(m->getAtomWithIdx(1)->getProp("foo1") == std::string(80, 'b')); CHECK(m->getAtomWithIdx(2)->getProp("foo1") == std::string(80, 'c')); } }