// // Copyright (C) 2002-2021 Greg Landrum and other RDKit contributors // @@ 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 #include #include #include #include #include #include #include "FileParsers.h" #include "SequenceParsers.h" #include "SequenceWriters.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace RDKit; void test1() { BOOST_LOG(rdInfoLog) << "testing atom query parsing" << std::endl; std::string rdbase = getenv("RDBASE"); std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/list-query.mol"; RWMol *m = MolFileToMol(fName, false); // MolOps::sanitizeMol(*m); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 6); std::string sma = MolToSmarts(*m); TEST_ASSERT(sma == "[#6]1=[#6]-[#6]=[#6]-[#6]=[#6,#7,#15]-1"); std::string smi = MolToSmiles(*m); TEST_ASSERT(smi == "*1=CC=CC=C1"); m->updatePropertyCache(); smi = MolToSmarts(*m); TEST_ASSERT(smi == "[#6]1=[#6]-[#6]=[#6]-[#6]=[#6,#7,#15]-1"); smi = "C1=CC=CC=C1"; RWMol *m2 = SmilesToMol(smi, false, false); MatchVectType mv; TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 6); // sanitize it, which will aromatize the bonds... we will not match: MolOps::sanitizeMol(*m2); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 0); delete m2; smi = "N1=CC=CC=C1"; m2 = SmilesToMol(smi, false, false); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 6); delete m2; smi = "S1=CC=CC=C1"; m2 = SmilesToMol(smi, false, false); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 0); delete m2; smi = "P1=CC=CC=C1"; m2 = SmilesToMol(smi, false, false); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 6); delete m2; delete m; fName = rdbase + "/Code/GraphMol/FileParsers/test_data/not-list-query.mol"; m = MolFileToMol(fName); TEST_ASSERT(m); smi = "CC(=C)C"; m2 = SmilesToMol(smi, false, false); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 4); delete m2; smi = "CC(=O)C"; m2 = SmilesToMol(smi, false, false); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); delete m2; smi = "CC(=N)C"; m2 = SmilesToMol(smi, false, false); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); delete m2; smi = "CC(=O)C(=C)C"; m2 = SmilesToMol(smi, false, false); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 4); delete m2; smi = "C(=C)C"; m2 = SmilesToMol(smi, false, false); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); delete m2; // make sure new-style atom lists override old-style atom lists: delete m; fName = rdbase + "/Code/GraphMol/FileParsers/test_data/conflicting-list-query.mol"; m = MolFileToMol(fName); TEST_ASSERT(m); smi = "CC(=C)C"; m2 = SmilesToMol(smi, false, false); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 4); delete m2; smi = "CC(=O)C"; m2 = SmilesToMol(smi, false, false); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); delete m2; // longer list queries, this was issue 2413431: delete m; fName = rdbase + "/Code/GraphMol/FileParsers/test_data/list-query-long.mol"; m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getAtomWithIdx(14)->hasQuery()); smi = "C1COC2=CC3=CC4=C(C=CC=C4)C=C3C=C2C1"; m2 = SmilesToMol(smi); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); delete m2; smi = "C1C[Se]C2=CC3=CC4=C(C=CC=C4)C=C3C=C2C1"; m2 = SmilesToMol(smi); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); delete m2; smi = "C1C[Te]C2=CC3=CC4=C(C=CC=C4)C=C3C=C2C1"; m2 = SmilesToMol(smi); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); delete m2; smi = "C1C[As]C2=CC3=CC4=C(C=CC=C4)C=C3C=C2C1"; m2 = SmilesToMol(smi); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); delete m2; delete m; BOOST_LOG(rdInfoLog) << "done" << std::endl; } void test2() { BOOST_LOG(rdInfoLog) << "testing bond query parsing" << std::endl; std::string rdbase = getenv("RDBASE"); std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/bond-query.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m->getNumAtoms() == 5); std::string smi = MolToSmiles(*m); TEST_ASSERT(smi == "C=CC~CC"); smi = "C1=CC=CC=C1"; RWMol *m2 = SmilesToMol(smi, false, false); MatchVectType mv; TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 5); // sanitize it (making bonds aromatic) ... we will not match: MolOps::sanitizeMol(*m2); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 0); delete m2; smi = "C=CC=CC=C"; m2 = SmilesToMol(smi); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 5); delete m2; smi = "C=CCCC=C"; m2 = SmilesToMol(smi); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 5); fName = rdbase + "/Code/GraphMol/FileParsers/test_data/RingBondQuery.mol"; delete m; m = MolFileToMol(fName); TEST_ASSERT(m->getNumAtoms() == 5); delete m2; smi = "C1CCC1C"; m2 = SmilesToMol(smi); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); delete m2; smi = "C1CC2C1C2"; m2 = SmilesToMol(smi); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 5); fName = rdbase + "/Code/GraphMol/FileParsers/test_data/ChainBondQuery.mol"; delete m; m = MolFileToMol(fName); TEST_ASSERT(m->getNumAtoms() == 5); delete m2; smi = "C1CCC1C"; m2 = SmilesToMol(smi); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 5); delete m2; smi = "C1CC2C1C2"; m2 = SmilesToMol(smi); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); // - - - - - - - - - - - - - - - - - - - - - - - - // this was github issue #269 // - - - - - - - - - - - - - - - - - - - - - - - - fName = rdbase + "/Code/GraphMol/FileParsers/test_data/bond-query4.mol"; delete m; m = MolFileToMol(fName); TEST_ASSERT(m->getNumAtoms() == 5); delete m2; smi = "C1CCC1C"; m2 = SmilesToMol(smi); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); delete m2; smi = "C1CCC1=C"; m2 = SmilesToMol(smi); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 5); delete m2; smi = "C1C=CC1=C"; m2 = SmilesToMol(smi); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 5); delete m2; smi = "C1C#CC1=C"; m2 = SmilesToMol(smi); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); delete m2; smi = "CCCC=C"; m2 = SmilesToMol(smi); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); delete m2; smi = "CC=CC=C"; m2 = SmilesToMol(smi); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); delete m2; smi = "CC#CC=C"; m2 = SmilesToMol(smi); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); fName = rdbase + "/Code/GraphMol/FileParsers/test_data/bond-query5.mol"; delete m; m = MolFileToMol(fName); TEST_ASSERT(m->getNumAtoms() == 5); delete m2; smi = "C1CCC1C"; m2 = SmilesToMol(smi); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); delete m2; smi = "C1CCC1=C"; m2 = SmilesToMol(smi); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); delete m2; smi = "C1C=CC1=C"; m2 = SmilesToMol(smi); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); delete m2; smi = "C1C#CC1=C"; m2 = SmilesToMol(smi); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); delete m2; smi = "CCCC=C"; m2 = SmilesToMol(smi); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 5); delete m2; smi = "CC=CC=C"; m2 = SmilesToMol(smi); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 5); delete m2; smi = "CC#CC=C"; m2 = SmilesToMol(smi); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); fName = rdbase + "/Code/GraphMol/FileParsers/test_data/bond-query6.mol"; delete m; m = MolFileToMol(fName); TEST_ASSERT(m->getNumAtoms() == 5); delete m2; smi = "C1CCC1C"; m2 = SmilesToMol(smi); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); delete m2; smi = "C1CCC1=C"; m2 = SmilesToMol(smi); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); delete m2; smi = "C1C=CC1=C"; m2 = SmilesToMol(smi); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); delete m2; smi = "C1C#CC1=C"; m2 = SmilesToMol(smi); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); delete m2; smi = "CCCC=C"; m2 = SmilesToMol(smi); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 5); delete m2; smi = "CC=CC=C"; m2 = SmilesToMol(smi); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 5); delete m2; smi = "CC#CC=C"; m2 = SmilesToMol(smi); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); delete m2; delete m; BOOST_LOG(rdInfoLog) << "done" << std::endl; } void test4() { // basic writing test BOOST_LOG(rdInfoLog) << " ----------> Test4 " << std::endl; std::string rdbase = getenv("RDBASE"); rdbase += "/Code/GraphMol/FileParsers/"; std::string fName = rdbase + "test_data/mol1.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m); std::string smi = MolToSmiles(*m); CHECK_INVARIANT(smi == "c1cc[cH-]c1", smi); TEST_ASSERT(m->getConformer().is3D() == false); std::string molBlock = MolToMolBlock(*m); delete m; m = MolBlockToMol(molBlock); TEST_ASSERT(m); smi = MolToSmiles(*m); CHECK_INVARIANT(smi == "c1cc[cH-]c1", smi); TEST_ASSERT(m->getConformer().is3D() == false); delete m; BOOST_LOG(rdInfoLog) << " Finished <---------- " << std::endl; } void test5() { // formerly problematic molecules BOOST_LOG(rdInfoLog) << " ----------> Test5 " << std::endl; std::string rdbase = getenv("RDBASE"); rdbase += "/Code/GraphMol/FileParsers/"; std::string fName = rdbase + "test_data/issue123.mol"; RWMol *m = MolFileToMol(fName); CHECK_INVARIANT(m, ""); TEST_ASSERT(m->getNumAtoms() == 23); TEST_ASSERT(m->getConformer().is3D() == true); std::string molBlock = MolToMolBlock(*m); delete m; m = MolBlockToMol(molBlock); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 23); TEST_ASSERT(m->getConformer().is3D() == true); delete m; // now try without removing the Hs: m = MolFileToMol(fName, true, false); CHECK_INVARIANT(m, ""); TEST_ASSERT(m->getNumAtoms() == 39); delete m; } void test6() { BOOST_LOG(rdInfoLog) << "testing chirality parsing" << std::endl; for (const bool useLegacy : {true, false}) { UseLegacyStereoPerceptionFixture fx(useLegacy); std::string rdbase = getenv("RDBASE"); rdbase += "/Code/GraphMol/FileParsers/"; std::string fName = rdbase + "test_data/chiral1.mol"; RWMol *m; std::string smi, cip; m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 5); smi = MolToSmiles(*m, true); TEST_ASSERT(smi == "C[C@](F)(Cl)Br"); delete m; fName = rdbase + "test_data/chiral1a.mol"; m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 5); smi = MolToSmiles(*m, true); TEST_ASSERT(smi == "C[C@](F)(Cl)Br"); delete m; fName = rdbase + "test_data/chiral2.mol"; m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 5); smi = MolToSmiles(*m, true); TEST_ASSERT(smi == "C[C@@](F)(Cl)Br"); delete m; fName = rdbase + "test_data/chiral2a.mol"; m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 5); smi = MolToSmiles(*m, true); TEST_ASSERT(smi == "C[C@@](F)(Cl)Br"); delete m; fName = rdbase + "test_data/chiral3.mol"; m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 4); if (useLegacy) { MolOps::assignStereochemistry(*m); } else { CIPLabeler::assignCIPLabels(*m); } TEST_ASSERT(m->getAtomWithIdx(0)->hasProp(common_properties::_CIPCode)); m->getAtomWithIdx(0)->getProp(common_properties::_CIPCode, cip); TEST_ASSERT(cip == "R"); #if 1 smi = MolToSmiles(*m, true); // BOOST_LOG(rdInfoLog) << " smi: " << smi << std::endl; TEST_ASSERT(smi == "C[C@H](F)Cl"); #endif delete m; fName = rdbase + "test_data/chiral3a.mol"; m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 4); if (useLegacy) { MolOps::assignStereochemistry(*m); } else { CIPLabeler::assignCIPLabels(*m); } TEST_ASSERT(m->getAtomWithIdx(0)->hasProp(common_properties::_CIPCode)); m->getAtomWithIdx(0)->getProp(common_properties::_CIPCode, cip); TEST_ASSERT(cip == "R"); #if 1 smi = MolToSmiles(*m, true); TEST_ASSERT(smi == "C[C@H](F)Cl"); #endif delete m; fName = rdbase + "test_data/chiral4.mol"; m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 4); if (useLegacy) { MolOps::assignStereochemistry(*m); } else { CIPLabeler::assignCIPLabels(*m); } TEST_ASSERT(m->getAtomWithIdx(0)->hasProp(common_properties::_CIPCode)); m->getAtomWithIdx(0)->getProp(common_properties::_CIPCode, cip); TEST_ASSERT(cip == "S"); #if 1 smi = MolToSmiles(*m, true); TEST_ASSERT(smi == "C[C@@H](F)Cl"); #endif delete m; fName = rdbase + "test_data/chiral4a.mol"; m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 4); if (useLegacy) { MolOps::assignStereochemistry(*m); } else { CIPLabeler::assignCIPLabels(*m); } TEST_ASSERT(m->getAtomWithIdx(0)->hasProp(common_properties::_CIPCode)); m->getAtomWithIdx(0)->getProp(common_properties::_CIPCode, cip); TEST_ASSERT(cip == "S"); #if 1 smi = MolToSmiles(*m, true); TEST_ASSERT(smi == "C[C@@H](F)Cl"); #endif delete m; fName = rdbase + "test_data/chiral5.mol"; m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 5); if (useLegacy) { MolOps::assignStereochemistry(*m); } else { CIPLabeler::assignCIPLabels(*m); } TEST_ASSERT(!m->getAtomWithIdx(0)->hasProp(common_properties::_CIPCode)); #if 1 smi = MolToSmiles(*m, true); TEST_ASSERT(smi == "CC(C)(Cl)Br"); #endif delete m; } BOOST_LOG(rdInfoLog) << "done" << std::endl; } void test7() { BOOST_LOG(rdInfoLog) << "testing roundtrip chirality parsing" << std::endl; std::string rdbase = getenv("RDBASE"); rdbase += "/Code/GraphMol/FileParsers/"; RWMol *m, *m2; std::string fName; std::string smi, molBlock, smi2, cip; fName = rdbase + "test_data/chiral1.mol"; m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 5); smi = MolToSmiles(*m, true); TEST_ASSERT(smi == "C[C@](F)(Cl)Br"); molBlock = MolToMolBlock(*m); m2 = MolBlockToMol(molBlock); TEST_ASSERT(m2) smi2 = MolToSmiles(*m2, true); TEST_ASSERT(smi == smi2); delete m; delete m2; fName = rdbase + "test_data/chiral2.mol"; m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 5); smi = MolToSmiles(*m, true); TEST_ASSERT(smi == "C[C@@](F)(Cl)Br"); molBlock = MolToMolBlock(*m); m2 = MolBlockToMol(molBlock); TEST_ASSERT(m2) smi2 = MolToSmiles(*m2, true); TEST_ASSERT(smi == smi2); delete m; delete m2; fName = rdbase + "test_data/chiral3.mol"; m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 4); MolOps::assignStereochemistry(*m); TEST_ASSERT(m->getAtomWithIdx(0)->hasProp(common_properties::_CIPCode)); m->getAtomWithIdx(0)->getProp(common_properties::_CIPCode, cip); TEST_ASSERT(cip == "R"); #if 1 smi = MolToSmiles(*m, true); TEST_ASSERT(smi == "C[C@H](F)Cl"); molBlock = MolToMolBlock(*m); m2 = MolBlockToMol(molBlock); TEST_ASSERT(m2) MolOps::assignStereochemistry(*m2); TEST_ASSERT(m2->getAtomWithIdx(0)->hasProp(common_properties::_CIPCode)); m2->getAtomWithIdx(0)->getProp(common_properties::_CIPCode, cip); TEST_ASSERT(cip == "R"); smi2 = MolToSmiles(*m2, true); TEST_ASSERT(smi == smi2); delete m2; #endif delete m; fName = rdbase + "test_data/chiral4.mol"; m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 4); MolOps::assignStereochemistry(*m); TEST_ASSERT(m->getAtomWithIdx(0)->hasProp(common_properties::_CIPCode)); m->getAtomWithIdx(0)->getProp(common_properties::_CIPCode, cip); TEST_ASSERT(cip == "S"); #if 1 smi = MolToSmiles(*m, true); TEST_ASSERT(smi == "C[C@@H](F)Cl"); molBlock = MolToMolBlock(*m); // BOOST_LOG(rdInfoLog) << molBlock << std::endl; m2 = MolBlockToMol(molBlock); TEST_ASSERT(m2) MolOps::assignStereochemistry(*m2); TEST_ASSERT(m2->getAtomWithIdx(0)->hasProp(common_properties::_CIPCode)); m2->getAtomWithIdx(0)->getProp(common_properties::_CIPCode, cip); TEST_ASSERT(cip == "S"); // smi2 = MolToSmiles(*m2,true); // TEST_ASSERT(smi==smi2); delete m2; #endif delete m; fName = rdbase + "test_data/Issue142d.mol"; m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 4); MolOps::assignStereochemistry(*m); TEST_ASSERT(m->getAtomWithIdx(1)->hasProp(common_properties::_CIPCode)); m->getAtomWithIdx(1)->getProp(common_properties::_CIPCode, cip); TEST_ASSERT(cip == "R"); #if 1 smi = MolToSmiles(*m, true); m2 = SmilesToMol(smi); smi2 = MolToSmiles(*m2, true); if (smi != smi2) { BOOST_LOG(rdInfoLog) << "\n " << smi << "\n !=\n " << smi2 << std::endl; } TEST_ASSERT(smi == smi2); delete m2; BOOST_LOG(rdInfoLog) << "SMI: " << smi << std::endl; std::cout << "***************************************" << std::endl; molBlock = MolToMolBlock(*m); std::cout << "***************************************" << std::endl; BOOST_LOG(rdInfoLog) << molBlock << std::endl; m2 = MolBlockToMol(molBlock); TEST_ASSERT(m2) smi2 = MolToSmiles(*m2, true); if (smi != smi2) { BOOST_LOG(rdInfoLog) << "\n " << smi << "\n !=\n " << smi2 << std::endl; } TEST_ASSERT(smi == smi2); delete m2; #endif delete m; fName = rdbase + "test_data/Issue142b.mol"; m = MolFileToMol(fName); // BOOST_LOG(rdInfoLog) << m->getNumAtoms() << "\n"; // BOOST_LOG(rdInfoLog) << "-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-" << // std::endl; TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 9); MolOps::assignStereochemistry(*m); TEST_ASSERT(m->getAtomWithIdx(0)->hasProp(common_properties::_CIPCode)); m->getAtomWithIdx(0)->getProp(common_properties::_CIPCode, cip); TEST_ASSERT(cip == "R"); TEST_ASSERT(m->getAtomWithIdx(1)->hasProp(common_properties::_CIPCode)); m->getAtomWithIdx(1)->getProp(common_properties::_CIPCode, cip); TEST_ASSERT(cip == "R"); TEST_ASSERT(m->getAtomWithIdx(3)->hasProp(common_properties::_CIPCode)); m->getAtomWithIdx(3)->getProp(common_properties::_CIPCode, cip); TEST_ASSERT(cip == "R"); #if 1 smi = MolToSmiles(*m, true); m2 = SmilesToMol(smi); smi2 = MolToSmiles(*m2, true); if (smi != smi2) { BOOST_LOG(rdInfoLog) << "\n " << smi << "\n !=\n " << smi2 << std::endl; } TEST_ASSERT(smi == smi2); delete m2; // BOOST_LOG(rdInfoLog) << "SMI: "<< smi << std::endl; BOOST_LOG(rdInfoLog) << m->getNumAtoms() << " " << m->getConformer().getNumAtoms() << "\n"; molBlock = MolToMolBlock(*m); // BOOST_LOG(rdInfoLog) << molBlock << std::endl; m2 = MolBlockToMol(molBlock); TEST_ASSERT(m2) smi2 = MolToSmiles(*m2, true); if (smi != smi2) { BOOST_LOG(rdInfoLog) << "\n " << smi << "\n !=\n " << smi2 << std::endl; } TEST_ASSERT(smi == smi2); delete m2; #endif delete m; fName = rdbase + "test_data/issue142a.mol"; m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 28); #if 1 smi = MolToSmiles(*m, true); m2 = SmilesToMol(smi); smi2 = MolToSmiles(*m2, true); if (smi != smi2) { BOOST_LOG(rdInfoLog) << "\n " << smi << "\n !=\n " << smi2 << std::endl; } TEST_ASSERT(smi == smi2); delete m2; molBlock = MolToMolBlock(*m); // BOOST_LOG(rdInfoLog) << molBlock << std::endl; m2 = MolBlockToMol(molBlock); TEST_ASSERT(m2) smi2 = MolToSmiles(*m2, true); if (smi != smi2) { BOOST_LOG(rdInfoLog) << "\n " << smi << "\n !=\n " << smi2 << std::endl; } TEST_ASSERT(smi == smi2); delete m2; #endif delete m; BOOST_LOG(rdInfoLog) << "done" << std::endl; } void test8() { BOOST_LOG(rdInfoLog) << "testing reading without sanitization" << std::endl; std::string rdbase = getenv("RDBASE"); rdbase += "/Code/GraphMol/FileParsers/"; RWMol *m; std::string fName; std::string smi, molBlock, smi2; // in this case the test means to not remove Hs: fName = rdbase + "test_data/unsanitary.mol"; m = MolFileToMol(fName, false); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 6); delete m; m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 3); delete m; fName = rdbase + "test_data/unsanitary2.mol"; m = MolFileToMol(fName, false); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 9); delete m; BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testIssue145() { BOOST_LOG(rdInfoLog) << "testing Issue145:\n Mol parsing: molecule yields " "non-canonical smiles from mol block" << std::endl; std::string rdbase = getenv("RDBASE"); rdbase += "/Code/GraphMol/FileParsers/"; RWMol *m, *m2; std::string fName; std::string smi, molBlock, smi2; fName = rdbase + "test_data/issue145.mol"; m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 19); smi = MolToSmiles(*m, true); m2 = SmilesToMol(smi); smi2 = MolToSmiles(*m2, true); if (smi != smi2) { BOOST_LOG(rdInfoLog) << "\n " << smi << "\n !=\n " << smi2 << std::endl; } TEST_ASSERT(smi == smi2); delete m2; molBlock = MolToMolBlock(*m); m2 = MolBlockToMol(molBlock); TEST_ASSERT(m2) smi2 = MolToSmiles(*m2, true); if (smi != smi2) { BOOST_LOG(rdInfoLog) << "\n " << smi << "\n !=\n " << smi2 << std::endl; } TEST_ASSERT(smi == smi2); delete m; delete m2; BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testIssue148() { BOOST_LOG(rdInfoLog) << "testing Issue148:\n Mol files containing mis-drawn " "nitro groups not properly parsed" << std::endl; std::string rdbase = getenv("RDBASE"); rdbase += "/Code/GraphMol/FileParsers/"; RWMol *m; std::string fName; std::string smi, molBlock, smi2; fName = rdbase + "test_data/issue148.mol"; m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 9); TEST_ASSERT(m->getAtomWithIdx(0)->getFormalCharge() == 1); delete m; BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testIssue180() { BOOST_LOG(rdInfoLog) << "testing Issue180: bad Z/E assignments" << std::endl; std::string rdbase = getenv("RDBASE"); rdbase += "/Code/GraphMol/FileParsers/"; RWMol *m; std::string fName; std::string code; Bond *bond; fName = rdbase + "test_data/Issue180.mol"; m = MolFileToMol(fName); TEST_ASSERT(m); bond = m->getBondWithIdx(2); TEST_ASSERT(bond->getBondType() == Bond::DOUBLE); TEST_ASSERT(bond->getStereo() == Bond::STEREOZ); bond = m->getBondWithIdx(5); TEST_ASSERT(bond->getBondType() == Bond::DOUBLE); TEST_ASSERT(bond->getStereo() == Bond::STEREOE); delete m; BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testIssue264() { BOOST_LOG(rdInfoLog) << "testing Issue264: bad stereochemistry from mol files" << std::endl; std::string rdbase = getenv("RDBASE"); rdbase += "/Code/GraphMol/FileParsers/"; RWMol *m1, *m2; std::string smi1, smi2; std::string fName; fName = rdbase + "test_data/Issue264-1.mol"; m1 = MolFileToMol(fName); TEST_ASSERT(m1); fName = rdbase + "test_data/Issue264-2.mol"; m2 = MolFileToMol(fName); TEST_ASSERT(m2); smi1 = MolToSmiles(*m1, false); smi2 = MolToSmiles(*m2, false); TEST_ASSERT(smi1 == smi2); smi1 = MolToSmiles(*m1, true); smi2 = MolToSmiles(*m2, true); BOOST_LOG(rdInfoLog) << smi1 << std::endl; BOOST_LOG(rdInfoLog) << smi2 << std::endl; TEST_ASSERT(smi1 != smi2); delete m1; delete m2; BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testIssue399() { BOOST_LOG(rdInfoLog) << "testing Issue399: bond wedging cleanup" << std::endl; std::string rdbase = getenv("RDBASE"); rdbase += "/Code/GraphMol/FileParsers/test_data/"; RWMol *m1; std::string smi1, smi2; std::string fName; fName = rdbase + "Issue399a.mol"; m1 = MolFileToMol(fName); TEST_ASSERT(m1); #if 1 smi1 = MolToSmiles(*m1, true); TEST_ASSERT(smi1 == "C[C@H]1CO1"); #endif MolOps::assignStereochemistry(*m1); TEST_ASSERT(m1->getAtomWithIdx(1)->hasProp(common_properties::_CIPCode)); m1->getAtomWithIdx(1)->getProp(common_properties::_CIPCode, smi2); TEST_ASSERT(smi2 == "S"); #if 1 Chirality::wedgeMolBonds(*m1, &m1->getConformer()); TEST_ASSERT(m1->getBondWithIdx(0)->getBondDir() == Bond::BEGINWEDGE); TEST_ASSERT(m1->getBondWithIdx(1)->getBondDir() == Bond::NONE); TEST_ASSERT(m1->getBondWithIdx(2)->getBondDir() == Bond::NONE); TEST_ASSERT(m1->getBondWithIdx(3)->getBondDir() == Bond::NONE); #endif delete m1; // make sure we prefer wedging bonds to Hs: m1 = MolFileToMol(fName); TEST_ASSERT(m1); MolOps::addHs(*m1, false, true); TEST_ASSERT(m1->getAtomWithIdx(7)->getAtomicNum() == 1); TEST_ASSERT(m1->getBondBetweenAtoms(1, 7)); TEST_ASSERT(m1->getBondBetweenAtoms(1, 7)->getBondType() == Bond::SINGLE); TEST_ASSERT(m1->getBondBetweenAtoms(1, 7)->getBondDir() == Bond::NONE); Chirality::wedgeMolBonds(*m1, &m1->getConformer()); TEST_ASSERT(m1->getBondBetweenAtoms(1, 7)->getBondDir() == Bond::BEGINDASH); delete m1; BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testMolFileChgLines() { BOOST_LOG(rdInfoLog) << "testing handling of charge lines" << std::endl; std::string rdbase = getenv("RDBASE"); rdbase += "/Code/GraphMol/FileParsers/test_data/"; // SF.Net Issue1603923: problems with multiple chg lines { RWMol *m1; std::string fName; fName = rdbase + "MolFileChgBug.mol"; m1 = MolFileToMol(fName); TEST_ASSERT(m1); TEST_ASSERT(m1->getAtomWithIdx(24)->getFormalCharge() == -1); TEST_ASSERT(m1->getAtomWithIdx(25)->getFormalCharge() == -1); delete m1; } // many charges in one molecule: { RWMol *m1; std::string fName; fName = rdbase + "manycharges.mol"; m1 = MolFileToMol(fName); TEST_ASSERT(m1); TEST_ASSERT(m1->getAtomWithIdx(0)->getFormalCharge() == -1); TEST_ASSERT(m1->getAtomWithIdx(13)->getFormalCharge() == -1); std::string molBlock = MolToMolBlock(*m1); // std::cerr<debugMol(std::cerr); TEST_ASSERT(m1); TEST_ASSERT(m1->getAtomWithIdx(0)->getFormalCharge() == -1); TEST_ASSERT(m1->getAtomWithIdx(13)->getFormalCharge() == -1); delete m1; } BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testDblBondStereochem() { BOOST_LOG(rdInfoLog) << "testing basic double bond stereochemistry" << std::endl; std::string rdbase = getenv("RDBASE"); rdbase += "/Code/GraphMol/FileParsers/test_data/"; { RWMol *m1; std::string fName = rdbase + "simple_z.mol"; m1 = MolFileToMol(fName); TEST_ASSERT(m1); TEST_ASSERT(m1->getBondWithIdx(0)->getStereo() == Bond::STEREOZ); delete m1; } { RWMol *m1; std::string fName = rdbase + "simple_e.mol"; m1 = MolFileToMol(fName); TEST_ASSERT(m1); TEST_ASSERT(m1->getBondWithIdx(0)->getStereo() == Bond::STEREOE); delete m1; } { RWMol *m1; std::string fName = rdbase + "simple_either.mol"; m1 = MolFileToMol(fName); TEST_ASSERT(m1); TEST_ASSERT(m1->getBondWithIdx(0)->getStereo() == Bond::STEREOANY); delete m1; } // the next group for sf.net issue 3009836 BOOST_LOG(rdInfoLog) << " sub-test for issue 3099836" << std::endl; { RWMol *m1; std::string fName = rdbase + "Issue3009836.1.mol"; m1 = MolFileToMol(fName); TEST_ASSERT(m1); TEST_ASSERT(m1->getBondBetweenAtoms(3, 4)->getStereo() == Bond::STEREOZ); delete m1; } { RWMol *m1; std::string fName = rdbase + "Issue3009836.2.mol"; m1 = MolFileToMol(fName); TEST_ASSERT(m1); TEST_ASSERT(m1->getBondBetweenAtoms(3, 4)->getStereo() == Bond::STEREOZ); delete m1; } { RWMol *m1; std::string fName = rdbase + "Issue3009836.3.mol"; m1 = MolFileToMol(fName); TEST_ASSERT(m1); TEST_ASSERT(m1->getBondBetweenAtoms(6, 7)->getStereo() == Bond::STEREOE); TEST_ASSERT(m1->getBondBetweenAtoms(10, 11)->getStereo() == Bond::STEREOZ); delete m1; } BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testSymmetricDblBondStereochem() { // this was sf.net issue 1718794: // http://sourceforge.net/tracker/index.php?func=detail&aid=1718794&group_id=160139&atid=814650) BOOST_LOG(rdInfoLog) << "testing double bonds with symmetric substituents" << std::endl; std::string rdbase = getenv("RDBASE"); rdbase += "/Code/GraphMol/FileParsers/test_data/"; RWMol *m1; std::string fName, smi; fName = rdbase + "cistrans.1a.mol"; m1 = MolFileToMol(fName); TEST_ASSERT(m1); TEST_ASSERT(m1->getBondWithIdx(0)->getStereo() == Bond::STEREOE); smi = MolToSmiles(*m1, true); TEST_ASSERT(smi == "C/C=C/Cl"); fName = rdbase + "cistrans.2a.mol"; delete m1; m1 = MolFileToMol(fName); TEST_ASSERT(m1); TEST_ASSERT(m1->getBondWithIdx(0)->getStereo() == Bond::STEREOZ); smi = MolToSmiles(*m1, true); TEST_ASSERT(smi == "C/C=C\\Cl"); fName = rdbase + "cistrans.1.mol"; delete m1; m1 = MolFileToMol(fName); TEST_ASSERT(m1); TEST_ASSERT(m1->getBondWithIdx(0)->getStereo() == Bond::STEREOE); smi = MolToSmiles(*m1, true); TEST_ASSERT(smi == "C/C=C/C"); fName = rdbase + "cistrans.2.mol"; delete m1; m1 = MolFileToMol(fName); TEST_ASSERT(m1); TEST_ASSERT(m1->getBondWithIdx(0)->getStereo() == Bond::STEREOZ); smi = MolToSmiles(*m1, true); TEST_ASSERT(smi == "C/C=C\\C"); fName = rdbase + "cistrans.3.mol"; delete m1; m1 = MolFileToMol(fName); TEST_ASSERT(m1); TEST_ASSERT(m1->getBondWithIdx(0)->getStereo() == Bond::STEREOANY); smi = MolToSmiles(*m1, true); TEST_ASSERT(smi == "CC=CC"); delete m1; BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testRingDblBondStereochem() { // this was sf.net issue 1725068: // http://sourceforge.net/tracker/index.php?func=detail&aid=1725068&group_id=160139&atid=814650 BOOST_LOG(rdInfoLog) << "testing double bonds in rings with stereochem specifications" << std::endl; std::string rdbase = getenv("RDBASE"); rdbase += "/Code/GraphMol/FileParsers/test_data/"; RWMol *m1; std::string fName, smi; fName = rdbase + "badringstereochem3.mol"; m1 = MolFileToMol(fName); TEST_ASSERT(m1); smi = MolToSmiles(*m1, true); TEST_ASSERT(smi.find("/", 0) == std::string::npos); TEST_ASSERT(smi.find("\\", 0) == std::string::npos); delete m1; fName = rdbase + "badringstereochem2.mol"; m1 = MolFileToMol(fName); TEST_ASSERT(m1); smi = MolToSmiles(*m1, true); TEST_ASSERT(smi.find("/", 0) == std::string::npos); TEST_ASSERT(smi.find("\\", 0) == std::string::npos); delete m1; fName = rdbase + "badringstereochem.mol"; m1 = MolFileToMol(fName); TEST_ASSERT(m1); smi = MolToSmiles(*m1, true); TEST_ASSERT(smi.find("/", 0) == std::string::npos); TEST_ASSERT(smi.find("\\", 0) == std::string::npos); delete m1; BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testMolFileRGroups() { BOOST_LOG(rdInfoLog) << "testing mol file R-group parsing" << std::endl; std::string rdbase = getenv("RDBASE"); std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/rgroups1.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m); unsigned int idx; std::string label; TEST_ASSERT(m->getAtomWithIdx(3)->hasProp(common_properties::_MolFileRLabel)); m->getAtomWithIdx(3)->getProp(common_properties::_MolFileRLabel, idx); TEST_ASSERT(idx == 2); TEST_ASSERT(m->getAtomWithIdx(3)->getAtomicNum() == 0); TEST_ASSERT(feq(m->getAtomWithIdx(3)->getIsotope(), 2)); TEST_ASSERT(m->getAtomWithIdx(4)->hasProp(common_properties::_MolFileRLabel)); m->getAtomWithIdx(4)->getProp(common_properties::_MolFileRLabel, idx); TEST_ASSERT(idx == 1); TEST_ASSERT(m->getAtomWithIdx(4)->getAtomicNum() == 0); TEST_ASSERT(feq(m->getAtomWithIdx(4)->getIsotope(), 1)); // test sf.net issue 3316600: TEST_ASSERT(m->getAtomWithIdx(3)->hasProp(common_properties::dummyLabel)); m->getAtomWithIdx(3)->getProp(common_properties::dummyLabel, label); TEST_ASSERT(label == "R2"); TEST_ASSERT(m->getAtomWithIdx(3)->getSymbol() == "R2"); TEST_ASSERT(m->getAtomWithIdx(4)->hasProp(common_properties::dummyLabel)); m->getAtomWithIdx(4)->getProp(common_properties::dummyLabel, label); TEST_ASSERT(label == "R1"); TEST_ASSERT(m->getAtomWithIdx(4)->getSymbol() == "R1"); RWMol *m2; MatchVectType mv; std::string smi; smi = "C1C(O)C1C"; m2 = SmilesToMol(smi, false, false); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 5); delete m2; smi = "C1CC(O)C1C"; m2 = SmilesToMol(smi, false, false); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); delete m2; smi = "C1C(CO)C1CC"; m2 = SmilesToMol(smi, false, false); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 5); delete m2; smi = "CC(=O)CC"; m2 = SmilesToMol(smi, false, false); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); delete m2; delete m; fName = rdbase + "/Code/GraphMol/FileParsers/test_data/rgroups2.mol"; m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getAtomWithIdx(3)->hasProp(common_properties::_MolFileRLabel)); m->getAtomWithIdx(3)->getProp(common_properties::_MolFileRLabel, idx); TEST_ASSERT(idx == 1); TEST_ASSERT(m->getAtomWithIdx(3)->getAtomicNum() == 0); TEST_ASSERT(feq(m->getAtomWithIdx(3)->getIsotope(), 1)); TEST_ASSERT(m->getAtomWithIdx(4)->hasProp(common_properties::_MolFileRLabel)); m->getAtomWithIdx(4)->getProp(common_properties::_MolFileRLabel, idx); TEST_ASSERT(idx == 1); TEST_ASSERT(m->getAtomWithIdx(4)->getAtomicNum() == 0); TEST_ASSERT(feq(m->getAtomWithIdx(4)->getIsotope(), 1)); smi = "C1C(O)C1C"; m2 = SmilesToMol(smi, false, false); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 5); delete m2; smi = "C1CC(O)C1C"; m2 = SmilesToMol(smi, false, false); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); delete m2; smi = "C1C(CO)C1CC"; m2 = SmilesToMol(smi, false, false); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 5); delete m2; smi = "CC(=O)CC"; m2 = SmilesToMol(smi, false, false); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); delete m2; delete m; fName = rdbase + "/Code/GraphMol/FileParsers/test_data/rgroups3.mol"; m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getAtomWithIdx(3)->hasProp(common_properties::_MolFileRLabel)); m->getAtomWithIdx(3)->getProp(common_properties::_MolFileRLabel, idx); TEST_ASSERT(idx == 11); TEST_ASSERT(m->getAtomWithIdx(3)->getAtomicNum() == 0); TEST_ASSERT(feq(m->getAtomWithIdx(3)->getIsotope(), 11)); TEST_ASSERT(m->getAtomWithIdx(4)->hasProp(common_properties::_MolFileRLabel)); m->getAtomWithIdx(4)->getProp(common_properties::_MolFileRLabel, idx); TEST_ASSERT(idx == 503); TEST_ASSERT(m->getAtomWithIdx(4)->getAtomicNum() == 0); TEST_ASSERT(feq(m->getAtomWithIdx(4)->getIsotope(), 503)); delete m; BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testMolFileDegreeQueries() { BOOST_LOG(rdInfoLog) << "testing mol file degree queries" << std::endl; std::string rdbase = getenv("RDBASE"); std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/subst1.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m); RWMol *m2; MatchVectType mv; std::string smi; smi = "CC(=O)O"; m2 = SmilesToMol(smi, false, false); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 4); delete m2; smi = "CC(=O)C"; m2 = SmilesToMol(smi, false, false); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 4); delete m2; smi = "CC(=O)"; m2 = SmilesToMol(smi, false, false); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); delete m2; delete m; fName = rdbase + "/Code/GraphMol/FileParsers/test_data/subst2.mol"; m = MolFileToMol(fName); TEST_ASSERT(m); smi = "CC(=O)O"; m2 = SmilesToMol(smi, false, false); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 4); delete m2; smi = "CC(=O)C"; m2 = SmilesToMol(smi, false, false); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 4); delete m2; smi = "CC(O)C"; m2 = SmilesToMol(smi, false, false); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 4); delete m2; smi = "CC(O)"; m2 = SmilesToMol(smi, false, false); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); delete m2; smi = "CC(O)(C)C"; m2 = SmilesToMol(smi, false, false); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); delete m2; delete m; fName = rdbase + "/Code/GraphMol/FileParsers/test_data/subst3.mol"; m = MolFileToMol(fName); TEST_ASSERT(m); smi = "CC(=O)O"; m2 = SmilesToMol(smi, false, false); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 3); delete m2; smi = "CC(=O)C"; m2 = SmilesToMol(smi, false, false); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 3); delete m2; smi = "CC(O)C"; m2 = SmilesToMol(smi, false, false); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); delete m2; smi = "CC(O)"; m2 = SmilesToMol(smi, false, false); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); delete m2; smi = "CC(O)(C)C"; m2 = SmilesToMol(smi, false, false); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); delete m2; delete m; fName = rdbase + "/Code/GraphMol/FileParsers/test_data/subst4.mol"; m = MolFileToMol(fName); TEST_ASSERT(m); smi = "CC(=O)O"; m2 = SmilesToMol(smi, false, false); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); delete m2; { delete m; fName = rdbase + "/Code/GraphMol/FileParsers/test_data/combined.mol"; m = MolFileToMol(fName); TEST_ASSERT(m); smi = "CC(=O)[CH-]C"; m2 = SmilesToMol(smi, false, false); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 4); delete m2; smi = "CC(=O)[C-](C)C"; m2 = SmilesToMol(smi, false, false); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); delete m2; smi = "CC(=O)CC"; m2 = SmilesToMol(smi, false, false); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); delete m2; } delete m; BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testMolFileRBCQueries() { BOOST_LOG(rdInfoLog) << "testing mol file ring-bond count queries" << std::endl; std::string rdbase = getenv("RDBASE"); std::string fName; RWMol *m; RWMol *m2; MatchVectType mv; std::string smi; fName = rdbase + "/Code/GraphMol/FileParsers/test_data/ringcount_2.mol"; m = MolFileToMol(fName); TEST_ASSERT(m); smi = "CC"; m2 = SmilesToMol(smi); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 0); delete m2; smi = "C1CCC1"; m2 = SmilesToMol(smi); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 2); delete m2; smi = "C12C3C4C1C5C2C3C45"; m2 = SmilesToMol(smi); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 0); delete m2; delete m; fName = rdbase + "/Code/GraphMol/FileParsers/test_data/ringcount_3.mol"; m = MolFileToMol(fName); TEST_ASSERT(m); smi = "CC"; m2 = SmilesToMol(smi); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 0); delete m2; smi = "C1CCC1"; m2 = SmilesToMol(smi); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 0); delete m2; smi = "C12C3C4C1C5C2C3C45"; m2 = SmilesToMol(smi); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 2); delete m2; delete m; fName = rdbase + "/Code/GraphMol/FileParsers/test_data/ringcount_0.mol"; m = MolFileToMol(fName); TEST_ASSERT(m); smi = "CC"; m2 = SmilesToMol(smi); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 2); delete m2; smi = "C1CCC1"; m2 = SmilesToMol(smi); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 0); delete m2; delete m; fName = rdbase + "/Code/GraphMol/FileParsers/test_data/ringcount_4.mol"; m = MolFileToMol(fName); TEST_ASSERT(m); smi = "CC"; m2 = SmilesToMol(smi); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 0); delete m2; smi = "C1CCC1"; m2 = SmilesToMol(smi); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 0); delete m2; smi = "C12C3C4C1C5C2C3C45"; m2 = SmilesToMol(smi); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 0); delete m2; smi = "C1CS234C5CC2CC13CC4C5"; m2 = SmilesToMol(smi); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 2); delete m2; smi = "C1C2CC3CC4CC1S234"; m2 = SmilesToMol(smi); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 2); delete m; fName = rdbase + "/Code/GraphMol/FileParsers/test_data/ringcount_star.mol"; m = MolFileToMol(fName); TEST_ASSERT(m); delete m2; smi = "CC"; m2 = SmilesToMol(smi); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 2); delete m2; smi = "C1CCC1"; m2 = SmilesToMol(smi); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 0); delete m2; delete m; fName = rdbase + "/Code/GraphMol/FileParsers/test_data/ringcount_star2.mol"; m = MolFileToMol(fName); TEST_ASSERT(m); smi = "CC"; m2 = SmilesToMol(smi); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 0); delete m2; smi = "C1CCC1"; m2 = SmilesToMol(smi); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 4); delete m2; smi = "C1CC2C1CC2"; m2 = SmilesToMol(smi); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 4); delete m2; smi = "C12C3C4C1C5C2C3C45"; m2 = SmilesToMol(smi); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 0); delete m2; delete m; fName = rdbase + "/Code/GraphMol/FileParsers/test_data/ringcount_star3.mol"; m = MolFileToMol(fName); TEST_ASSERT(m); smi = "CC"; m2 = SmilesToMol(smi); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 0); delete m2; smi = "C1CCC1"; m2 = SmilesToMol(smi); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 4); delete m2; smi = "C1CC2C1CC2"; m2 = SmilesToMol(smi); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 0); delete m2; smi = "C12C3C4C1C5C2C3C45"; m2 = SmilesToMol(smi); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 0); delete m2; delete m; BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testMolFileUnsaturationQueries() { BOOST_LOG(rdInfoLog) << "testing mol file unsaturation queries" << std::endl; std::string rdbase = getenv("RDBASE"); std::string fName; RWMol *m; RWMol *m2; MatchVectType mv; std::string smi; fName = rdbase + "/Code/GraphMol/FileParsers/test_data/unsaturation.mol"; m = MolFileToMol(fName); TEST_ASSERT(m); smi = "CO"; m2 = SmilesToMol(smi); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 0); delete m2; smi = "C=O"; m2 = SmilesToMol(smi); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 2); delete m2; smi = "CCO"; m2 = SmilesToMol(smi); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 0); delete m2; smi = "C=CO"; m2 = SmilesToMol(smi); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 2); delete m2; smi = "C#CO"; m2 = SmilesToMol(smi); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 2); delete m2; delete m; BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testMolFileQueryToSmarts() { BOOST_LOG(rdInfoLog) << "testing mol file queries -> SMARTS " << std::endl; std::string rdbase = getenv("RDBASE"); std::string fName; RWMol *m; std::string sma; fName = rdbase + "/Code/GraphMol/FileParsers/test_data/ringcount_2.mol"; m = MolFileToMol(fName); TEST_ASSERT(m); sma = MolToSmarts(*m, true); TEST_ASSERT(sma == "[#6&x2]-[#6]") delete m; fName = rdbase + "/Code/GraphMol/FileParsers/test_data/ringcount_3.mol"; m = MolFileToMol(fName); TEST_ASSERT(m); sma = MolToSmarts(*m, true); TEST_ASSERT(sma == "[#6&x3]-[#6]") delete m; fName = rdbase + "/Code/GraphMol/FileParsers/test_data/ringcount_0.mol"; m = MolFileToMol(fName); TEST_ASSERT(m); sma = MolToSmarts(*m, true); TEST_ASSERT(sma == "[#6&x0]-[#6]") delete m; fName = rdbase + "/Code/GraphMol/FileParsers/test_data/ringcount_4.mol"; m = MolFileToMol(fName); TEST_ASSERT(m); sma = MolToSmarts(*m, true); TEST_ASSERT(sma == "[#16&x4]-[#6]") delete m; fName = rdbase + "/Code/GraphMol/FileParsers/test_data/ringcount_star.mol"; m = MolFileToMol(fName); TEST_ASSERT(m); sma = MolToSmarts(*m, true); TEST_ASSERT(sma == "[#6&x0]-[#6]") delete m; fName = rdbase + "/Code/GraphMol/FileParsers/test_data/ringcount_star2.mol"; m = MolFileToMol(fName); TEST_ASSERT(m); sma = MolToSmarts(*m, true); TEST_ASSERT(sma.find("[#6&x2]") != std::string::npos); delete m; fName = rdbase + "/Code/GraphMol/FileParsers/test_data/unsaturation.mol"; m = MolFileToMol(fName); TEST_ASSERT(m); sma = MolToSmarts(*m, true); TEST_ASSERT(sma == "[#6&$(*=,:,#*)]~[#8]") delete m; BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testMissingFiles() { BOOST_LOG(rdInfoLog) << "testing handling of missing files" << std::endl; std::string fName; bool ok; RWMol *m; (void)m; fName = "bogus_file.mol"; ok = false; try { m = MolFileToMol(fName); } catch (BadFileException &) { ok = true; } TEST_ASSERT(ok); ok = false; try { m = TPLFileToMol(fName); } catch (BadFileException &) { ok = true; } TEST_ASSERT(ok); BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testIssue1965035() { BOOST_LOG(rdInfoLog) << "testing issue Issue1965035: problems with WedgeMolBonds " << std::endl; std::string rdbase = getenv("RDBASE"); std::string fName; RWMol *m; std::string sma; fName = rdbase + "/Code/GraphMol/FileParsers/test_data/Issue1965035.mol"; m = MolFileToMol(fName); TEST_ASSERT(m); // the mol file parser removes bond wedging info: TEST_ASSERT(m->getBondWithIdx(4)->getBondDir() == Bond::NONE); // but a chiral tag is assigned: TEST_ASSERT(m->getAtomWithIdx(2)->getChiralTag() == Atom::CHI_TETRAHEDRAL_CW); WedgeMolBonds(*m, &m->getConformer()); TEST_ASSERT(m->getBondWithIdx(4)->getBondDir() == Bond::BEGINDASH); delete m; BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testRadicals() { BOOST_LOG(rdInfoLog) << "testing handling of radicals " << std::endl; std::string rdbase = getenv("RDBASE"); std::string fName; RWMol *m; std::string smiles; fName = rdbase + "/Code/GraphMol/FileParsers/test_data/radical.mol"; m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getAtomWithIdx(0)->getNumRadicalElectrons() == 0); TEST_ASSERT(m->getAtomWithIdx(1)->getNumRadicalElectrons() == 1); std::string molBlock = MolToMolBlock(*m); delete m; m = MolBlockToMol(molBlock); TEST_ASSERT(m); TEST_ASSERT(m->getAtomWithIdx(0)->getNumRadicalElectrons() == 0); TEST_ASSERT(m->getAtomWithIdx(1)->getNumRadicalElectrons() == 1); delete m; BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testBadBondOrders() { BOOST_LOG(rdInfoLog) << "testing handling of bogus bond orders (issue 2337369)" << std::endl; std::string rdbase = getenv("RDBASE"); std::string fName; RWMol *m; fName = rdbase + "/Code/GraphMol/FileParsers/test_data/bondorder0.mol"; m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getBondBetweenAtoms(0, 1)->getBondType() == Bond::UNSPECIFIED); TEST_ASSERT(!m->getBondBetweenAtoms(0, 1)->hasQuery()); delete m; fName = rdbase + "/Code/GraphMol/FileParsers/test_data/bondorder9.mol"; m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(!m->getBondBetweenAtoms(0, 1)->hasQuery()); TEST_ASSERT(m->getBondBetweenAtoms(0, 1)->getBondType() == Bond::DATIVE); delete m; BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testAtomParity() { BOOST_LOG(rdInfoLog) << "testing handling of atom stereo parity flags" << std::endl; std::string rdbase = getenv("RDBASE"); { int parity; std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/parity.simple1.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(!m->getAtomWithIdx(0)->hasProp(common_properties::molParity)); TEST_ASSERT(m->getAtomWithIdx(1)->hasProp(common_properties::molParity)); m->getAtomWithIdx(1)->getProp(common_properties::molParity, parity); TEST_ASSERT(parity == 1); // look for the parity flags on output: auto molBlock = MolToMolBlock(*m); auto m2 = MolBlockToMol(molBlock); TEST_ASSERT(m2); TEST_ASSERT(!m2->getAtomWithIdx(0)->hasProp(common_properties::molParity)); TEST_ASSERT(m2->getAtomWithIdx(1)->hasProp(common_properties::molParity)); m2->getAtomWithIdx(1)->getProp(common_properties::molParity, parity); TEST_ASSERT(parity == 1); delete m2; // if we clear the stereo, no parity flags end up in the output: m->getAtomWithIdx(1)->setChiralTag(Atom::ChiralType::CHI_UNSPECIFIED); molBlock = MolToMolBlock(*m); m2 = MolBlockToMol(molBlock); TEST_ASSERT(m2); TEST_ASSERT(!m2->getAtomWithIdx(0)->hasProp(common_properties::molParity)); TEST_ASSERT(!m2->getAtomWithIdx(1)->hasProp(common_properties::molParity)); delete m2; delete m; } { int parity; std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/parity.simple2.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(!m->getAtomWithIdx(0)->hasProp(common_properties::molParity)); TEST_ASSERT(m->getAtomWithIdx(1)->hasProp(common_properties::molParity)); m->getAtomWithIdx(1)->getProp(common_properties::molParity, parity); TEST_ASSERT(parity == 2); MolOps::assignChiralTypesFrom3D(*m); std::string molBlock = MolToMolBlock(*m); RWMol *m2 = MolBlockToMol(molBlock); TEST_ASSERT(m2); TEST_ASSERT(!m2->getAtomWithIdx(0)->hasProp(common_properties::molParity)); TEST_ASSERT(m2->getAtomWithIdx(1)->hasProp(common_properties::molParity)); m2->getAtomWithIdx(1)->getProp(common_properties::molParity, parity); TEST_ASSERT(parity == 2); delete m2; delete m; } { // a case with an H on the chiral center: int parity; std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/parity.simpleH1.mol"; RWMol *m = MolFileToMol(fName, true, false); TEST_ASSERT(m); TEST_ASSERT(!m->getAtomWithIdx(0)->hasProp(common_properties::molParity)); TEST_ASSERT(m->getAtomWithIdx(1)->hasProp(common_properties::molParity)); m->getAtomWithIdx(1)->getProp(common_properties::molParity, parity); TEST_ASSERT(parity == 1); MolOps::assignChiralTypesFrom3D(*m); std::string molBlock = MolToMolBlock(*m); RWMol *m2 = MolBlockToMol(molBlock, true, false); TEST_ASSERT(m2); TEST_ASSERT(!m2->getAtomWithIdx(0)->hasProp(common_properties::molParity)); TEST_ASSERT(m2->getAtomWithIdx(1)->hasProp(common_properties::molParity)); m2->getAtomWithIdx(1)->getProp(common_properties::molParity, parity); TEST_ASSERT(parity == 1); delete m2; // if we remove the H and write things out, we should // still get the right answer back: m2 = (RWMol *)MolOps::removeHs(*((ROMol *)m)); molBlock = MolToMolBlock(*m2); delete m2; m2 = MolBlockToMol(molBlock); TEST_ASSERT(m2); TEST_ASSERT(!m2->getAtomWithIdx(0)->hasProp(common_properties::molParity)); TEST_ASSERT(m2->getAtomWithIdx(1)->hasProp(common_properties::molParity)); m2->getAtomWithIdx(1)->getProp(common_properties::molParity, parity); TEST_ASSERT(parity == 1); delete m2; delete m; } { // a case with an H on the chiral center: int parity; std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/parity.simpleH2.mol"; RWMol *m = MolFileToMol(fName, true, false); TEST_ASSERT(m); TEST_ASSERT(!m->getAtomWithIdx(0)->hasProp(common_properties::molParity)); TEST_ASSERT(m->getAtomWithIdx(1)->hasProp(common_properties::molParity)); m->getAtomWithIdx(1)->getProp(common_properties::molParity, parity); TEST_ASSERT(parity == 2); MolOps::assignChiralTypesFrom3D(*m); std::string molBlock = MolToMolBlock(*m); RWMol *m2 = MolBlockToMol(molBlock, true, false); TEST_ASSERT(m2); TEST_ASSERT(!m2->getAtomWithIdx(0)->hasProp(common_properties::molParity)); TEST_ASSERT(m2->getAtomWithIdx(1)->hasProp(common_properties::molParity)); m2->getAtomWithIdx(1)->getProp(common_properties::molParity, parity); TEST_ASSERT(parity == 2); delete m2; m2 = (RWMol *)MolOps::removeHs(*((ROMol *)m)); molBlock = MolToMolBlock(*m2); delete m2; m2 = MolBlockToMol(molBlock); TEST_ASSERT(m2); TEST_ASSERT(!m2->getAtomWithIdx(0)->hasProp(common_properties::molParity)); TEST_ASSERT(m2->getAtomWithIdx(1)->hasProp(common_properties::molParity)); m2->getAtomWithIdx(1)->getProp(common_properties::molParity, parity); TEST_ASSERT(parity == 2); delete m2; delete m; } { // a case with an N as the "chiral" center int parity; std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/parity.nitrogen.mol"; RWMol *m = MolFileToMol(fName, true, false); TEST_ASSERT(m); TEST_ASSERT(!m->getAtomWithIdx(0)->hasProp(common_properties::molParity)); TEST_ASSERT(m->getAtomWithIdx(1)->hasProp(common_properties::molParity)); m->getAtomWithIdx(1)->getProp(common_properties::molParity, parity); TEST_ASSERT(parity == 1); MolOps::assignChiralTypesFrom3D(*m); std::string molBlock = MolToMolBlock(*m); RWMol *m2 = MolBlockToMol(molBlock, true, false); TEST_ASSERT(m2); TEST_ASSERT(!m2->getAtomWithIdx(0)->hasProp(common_properties::molParity)); TEST_ASSERT(!m2->getAtomWithIdx(1)->hasProp(common_properties::molParity)); delete m2; delete m; } { // a case with two Hs on the chiral center: std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/parity.twoHs.mol"; RWMol *m = MolFileToMol(fName, true, false); TEST_ASSERT(m); TEST_ASSERT(!m->getAtomWithIdx(0)->hasProp(common_properties::molParity)); TEST_ASSERT(!m->getAtomWithIdx(1)->hasProp(common_properties::molParity)); // add a bogus chiral spec: m->getAtomWithIdx(0)->setChiralTag(Atom::CHI_TETRAHEDRAL_CW); std::string molBlock = MolToMolBlock(*m); auto *m2 = (RWMol *)MolOps::removeHs(*((ROMol *)m)); molBlock = MolToMolBlock(*m2); delete m2; m2 = MolBlockToMol(molBlock, true, false); TEST_ASSERT(m2); TEST_ASSERT(!m2->getAtomWithIdx(0)->hasProp(common_properties::molParity)); TEST_ASSERT(!m2->getAtomWithIdx(1)->hasProp(common_properties::molParity)); delete m2; delete m; } BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testIssue2692246() { // basic writing test BOOST_LOG(rdInfoLog) << " Testing issue 2692246 " << std::endl; std::string smiles(120, 'C'); smiles += "[CH2+]"; RWMol *m = SmilesToMol(smiles); TEST_ASSERT(m); std::string molBlock = MolToMolBlock(*m); delete m; m = MolBlockToMol(molBlock); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 121); TEST_ASSERT(m->getAtomWithIdx(120)->getFormalCharge() == 1); delete m; BOOST_LOG(rdInfoLog) << " done" << std::endl; } void testKekulizationSkip() { // basic writing test BOOST_LOG(rdInfoLog) << " Testing mol blocks without kekulization " << std::endl; std::string smiles("c1ccccc1"); RWMol *m = SmilesToMol(smiles); TEST_ASSERT(m); std::string molBlock = MolToMolBlock(*m, true, -1, false); TEST_ASSERT(molBlock.find("1 2 4") != std::string::npos); TEST_ASSERT(molBlock.find("2 3 4") != std::string::npos); TEST_ASSERT(molBlock.find("3 4 4") != std::string::npos); molBlock = MolToMolBlock(*m); TEST_ASSERT(molBlock.find("1 2 4") == std::string::npos); TEST_ASSERT(molBlock.find("2 3 4") == std::string::npos); TEST_ASSERT(molBlock.find("3 4 4") == std::string::npos); delete m; BOOST_LOG(rdInfoLog) << " done" << std::endl; } void testMolFileAtomValues() { BOOST_LOG(rdInfoLog) << "testing atom values in mol files" << std::endl; std::string rdbase = getenv("RDBASE"); rdbase += "/Code/GraphMol/FileParsers/"; { RWMol *m; std::string fName, val; fName = rdbase + "test_data/AtomProps1.mol"; m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT( !m->getAtomWithIdx(0)->hasProp(common_properties::molFileValue)); TEST_ASSERT(m->getAtomWithIdx(1)->hasProp(common_properties::molFileValue)); m->getAtomWithIdx(1)->getProp(common_properties::molFileValue, val); TEST_ASSERT(val == "acidchloride"); TEST_ASSERT(getAtomValue(m->getAtomWithIdx(1)) == "acidchloride") TEST_ASSERT( m->getAtomWithIdx(0)->hasProp(common_properties::molAtomMapNumber)); TEST_ASSERT( m->getAtomWithIdx(1)->hasProp(common_properties::molAtomMapNumber)); TEST_ASSERT( m->getAtomWithIdx(2)->hasProp(common_properties::molAtomMapNumber)); TEST_ASSERT( !m->getAtomWithIdx(3)->hasProp(common_properties::molAtomMapNumber)); TEST_ASSERT(m->getAtomWithIdx(0)->getAtomMapNum() == 1); TEST_ASSERT(m->getAtomWithIdx(1)->getAtomMapNum() == 2); TEST_ASSERT(m->getAtomWithIdx(2)->getAtomMapNum() == 3); TEST_ASSERT(m->getAtomWithIdx(3)->getAtomMapNum() == 0); // round trip m->getAtomWithIdx(0)->setAtomMapNum(4); setAtomRLabel(m->getAtomWithIdx(3), 1); setAtomAlias(m->getAtomWithIdx(0), "acidchloride"); setAtomValue(m->getAtomWithIdx(0), "foobar"); RWMol *m2 = MolBlockToMol(MolToMolBlock(*m)); TEST_ASSERT(m2); TEST_ASSERT(m->getAtomWithIdx(0)->getAtomMapNum() == 4); TEST_ASSERT(m->getAtomWithIdx(1)->getAtomMapNum() == 2); TEST_ASSERT(m->getAtomWithIdx(2)->getAtomMapNum() == 3); TEST_ASSERT(m->getAtomWithIdx(3)->getAtomMapNum() == 0); TEST_ASSERT(getAtomRLabel(m->getAtomWithIdx(3)) == 1); TEST_ASSERT(getAtomAlias(m->getAtomWithIdx(0)) == "acidchloride"); TEST_ASSERT(getAtomValue(m->getAtomWithIdx(0)) == "foobar"); delete m; delete m2; } { RWMol *m; std::string fName, val; fName = rdbase + "test_data/AtomProps2.mol"; m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT( !m->getAtomWithIdx(0)->hasProp(common_properties::molFileValue)); TEST_ASSERT(m->getAtomWithIdx(1)->hasProp(common_properties::molFileValue)); m->getAtomWithIdx(1)->getProp(common_properties::molFileValue, val); TEST_ASSERT(val == "acidchloride"); TEST_ASSERT(m->getAtomWithIdx(2)->hasProp(common_properties::molFileValue)); m->getAtomWithIdx(2)->getProp(common_properties::molFileValue, val); TEST_ASSERT(val == "testing"); TEST_ASSERT(m->getAtomWithIdx(3)->getFormalCharge() == -1); delete m; } BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testMolFileAtomQueries() { BOOST_LOG(rdInfoLog) << "testing handling of A, Q, and * in mol files" << std::endl; std::string rdbase = getenv("RDBASE"); { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/query_star.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m); RWMol *m2; MatchVectType mv; std::string smi; smi = "[H]c1ccccc1"; m2 = SmilesToMol(smi, false, false); MolOps::sanitizeMol(*m2); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 7); delete m2; smi = "Cc1ccccc1"; m2 = SmilesToMol(smi); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 7); delete m2; smi = "Clc1ccccc1"; m2 = SmilesToMol(smi); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 7); delete m2; delete m; } { std::vector fNames = { rdbase + "/Code/GraphMol/FileParsers/test_data/query_A.mol", rdbase + "/Code/GraphMol/FileParsers/test_data/query_A.v3k.mol", }; for (const auto &fName : fNames) { std::unique_ptr m(MolFileToMol(fName)); TEST_ASSERT(m); TEST_ASSERT(m->getAtomWithIdx(6)->hasQuery()); TEST_ASSERT(m->getAtomWithIdx(6)->getQuery()->getTypeLabel() == "A"); RWMol *m2; MatchVectType mv; std::string smi; smi = "[H]c1ccccc1"; m2 = SmilesToMol(smi, false, false); MolOps::sanitizeMol(*m2); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); delete m2; smi = "Cc1ccccc1"; m2 = SmilesToMol(smi); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 7); delete m2; smi = "Clc1ccccc1"; m2 = SmilesToMol(smi); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 7); delete m2; } } { std::vector fNames = { rdbase + "/Code/GraphMol/FileParsers/test_data/query_Q.mol", rdbase + "/Code/GraphMol/FileParsers/test_data/query_Q.v3k.mol", }; for (const auto &fName : fNames) { std::unique_ptr m(MolFileToMol(fName)); TEST_ASSERT(m); TEST_ASSERT(m->getAtomWithIdx(6)->hasQuery()); TEST_ASSERT(m->getAtomWithIdx(6)->getQuery()->getTypeLabel() == "Q"); RWMol *m2; MatchVectType mv; std::string smi; smi = "[H]c1ccccc1"; m2 = SmilesToMol(smi, false, false); MolOps::sanitizeMol(*m2); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); delete m2; smi = "Cc1ccccc1"; m2 = SmilesToMol(smi); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); delete m2; smi = "Clc1ccccc1"; m2 = SmilesToMol(smi); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 7); delete m2; } } BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testListsAndValues() { BOOST_LOG(rdInfoLog) << "testing handling of mol files with atom lists and values" << std::endl; std::string rdbase = getenv("RDBASE"); { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/lists_plus_values.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m); std::string value; TEST_ASSERT(m->getAtomWithIdx(1)->hasProp(common_properties::molFileValue)); m->getAtomWithIdx(1)->getProp(common_properties::molFileValue, value); TEST_ASSERT(value == "halogen"); TEST_ASSERT(m->getAtomWithIdx(1)->hasQuery()); TEST_ASSERT(m->getAtomWithIdx(1)->getQuery()->getDescription() == "AtomOr"); delete m; } BOOST_LOG(rdInfoLog) << "done" << std::endl; } void test1V3K() { BOOST_LOG(rdInfoLog) << "testing basic handling of v3000 mol files" << std::endl; std::string rdbase = getenv("RDBASE"); { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/v3k.1.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 8); TEST_ASSERT(m->getNumBonds() == 8); delete m; } { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/v3k.3.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 9); TEST_ASSERT(m->getNumBonds() == 9); TEST_ASSERT(m->getAtomWithIdx(4)->getFormalCharge() == -1); TEST_ASSERT(m->getAtomWithIdx(4)->getIsotope() == 17); // m->debugMol(std::cerr); // TEST_ASSERT(m->getBondWithIdx(8)->getBondDir()==Bond::BEGINWEDGE); delete m; } { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/v3k.5a.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 5); TEST_ASSERT(m->getNumBonds() == 4); TEST_ASSERT(m->getAtomWithIdx(0)->getChiralTag() != Atom::CHI_UNSPECIFIED); delete m; } { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/v3k.5b.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 5); TEST_ASSERT(m->getNumBonds() == 4); TEST_ASSERT(m->getAtomWithIdx(0)->getChiralTag() == Atom::CHI_UNSPECIFIED); delete m; } { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/v3k.6a.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 4); TEST_ASSERT(m->getNumBonds() == 3); TEST_ASSERT(m->getBondWithIdx(0)->getStereo() == Bond::STEREOE); delete m; } { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/v3k.6b.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 4); TEST_ASSERT(m->getNumBonds() == 3); TEST_ASSERT(m->getBondWithIdx(0)->getStereo() == Bond::STEREOANY); delete m; } { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/v3k.crash1.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 7); TEST_ASSERT(m->getNumBonds() == 7); delete m; } BOOST_LOG(rdInfoLog) << "done" << std::endl; } void test2V3K() { BOOST_LOG(rdInfoLog) << "testing more queries from v3000 mol files" << std::endl; std::string rdbase = getenv("RDBASE"); { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/v3k.2.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 8); TEST_ASSERT(m->getNumBonds() == 8); std::string smiles = "O=C(O)C1OCCC1"; RWMol *m2 = SmilesToMol(smiles); MatchVectType mv; TEST_ASSERT(SubstructMatch(*m2, *m, mv)); delete m2; smiles = "O=C(O)C1OCCC1"; m2 = SmilesToMol(smiles); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); delete m2; smiles = "O=C(O)C1SCCS1"; m2 = SmilesToMol(smiles); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); delete m2; smiles = "O=C(O)C1OCCN1"; m2 = SmilesToMol(smiles); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); delete m2; smiles = "O=C(O)C1OCCO1"; m2 = SmilesToMol(smiles); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); delete m2; delete m; } { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/v3k.4a.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 2); TEST_ASSERT(m->getNumBonds() == 1); std::string smiles = "OC1OCC1"; RWMol *m2 = SmilesToMol(smiles); MatchVectType mv; TEST_ASSERT(SubstructMatch(*m2, *m, mv)); delete m2; smiles = "C1OCC1"; m2 = SmilesToMol(smiles); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); delete m2; smiles = "COCC"; m2 = SmilesToMol(smiles); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); delete m2; delete m; } { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/v3k.4b.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 2); TEST_ASSERT(m->getNumBonds() == 1); std::string smiles = "OC1OCC1"; RWMol *m2 = SmilesToMol(smiles); MatchVectType mv; TEST_ASSERT(SubstructMatch(*m2, *m, mv)); delete m2; smiles = "C1OCC1"; m2 = SmilesToMol(smiles); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); delete m2; smiles = "COCC"; m2 = SmilesToMol(smiles); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); delete m2; delete m; } { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/v3k.rbc.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 3); TEST_ASSERT(m->getNumBonds() == 2); std::string smiles = "C1CC1"; RWMol *m2 = SmilesToMol(smiles); TEST_ASSERT(m2); MatchVectType mv; TEST_ASSERT(SubstructMatch(*m2, *m, mv)); delete m2; smiles = "CCC"; m2 = SmilesToMol(smiles); TEST_ASSERT(m2); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); delete m2; smiles = "N1NC2NNC12"; m2 = SmilesToMol(smiles); TEST_ASSERT(m2); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); delete m2; delete m; } { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/chebi_15469.v3k.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 53); TEST_ASSERT(m->getNumBonds() == 55); TEST_ASSERT(m->getAtomWithIdx(52)->getAtomicNum() == 0); TEST_ASSERT(!m->getAtomWithIdx(52)->hasQuery()); delete m; } { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/chebi_57262.v3k.2.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 22); TEST_ASSERT(m->getNumBonds() == 21); TEST_ASSERT(m->getAtomWithIdx(18)->getAtomicNum() == 0); TEST_ASSERT(!m->getAtomWithIdx(18)->hasQuery()); TEST_ASSERT(m->getAtomWithIdx(18)->getIsotope() == 1); TEST_ASSERT(m->getAtomWithIdx(21)->getAtomicNum() == 0); TEST_ASSERT(!m->getAtomWithIdx(21)->hasQuery()); TEST_ASSERT(m->getAtomWithIdx(21)->getIsotope() == 2); delete m; } { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/chebi_57262.v3k.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 22); TEST_ASSERT(m->getNumBonds() == 21); TEST_ASSERT(m->getAtomWithIdx(18)->getAtomicNum() == 0); TEST_ASSERT(!m->getAtomWithIdx(18)->hasQuery()); TEST_ASSERT(m->getAtomWithIdx(18)->getIsotope() == 1); TEST_ASSERT(m->getAtomWithIdx(21)->getAtomicNum() == 0); TEST_ASSERT(!m->getAtomWithIdx(21)->hasQuery()); TEST_ASSERT(m->getAtomWithIdx(21)->getIsotope() == 2); delete m; } BOOST_LOG(rdInfoLog) << "done" << std::endl; } void test3V3K() { BOOST_LOG(rdInfoLog) << "testing basic writing of v3000 mol files" << std::endl; std::string rdbase = getenv("RDBASE"); rdbase += "/Code/GraphMol/FileParsers/test_data/"; std::string fName; { // charges fName = rdbase + "issue148.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 9); TEST_ASSERT(m->getAtomWithIdx(0)->getFormalCharge() == 1); std::string mb = MolToMolBlock(*m, true, -1, true, true); delete m; m = MolBlockToMol(mb); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 9); TEST_ASSERT(m->getAtomWithIdx(0)->getFormalCharge() == 1); delete m; } { // multiple charge lines fName = rdbase + "MolFileChgBug.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getAtomWithIdx(24)->getFormalCharge() == -1); TEST_ASSERT(m->getAtomWithIdx(25)->getFormalCharge() == -1); std::string mb = MolToMolBlock(*m, true, -1, true, true); delete m; m = MolBlockToMol(mb); TEST_ASSERT(m); TEST_ASSERT(m->getAtomWithIdx(24)->getFormalCharge() == -1); TEST_ASSERT(m->getAtomWithIdx(25)->getFormalCharge() == -1); delete m; } { // radicals fName = rdbase + "radical.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getAtomWithIdx(0)->getNumRadicalElectrons() == 0); TEST_ASSERT(m->getAtomWithIdx(1)->getNumRadicalElectrons() == 1); std::string mb = MolToMolBlock(*m, true, -1, true, true); delete m; m = MolBlockToMol(mb); TEST_ASSERT(m); TEST_ASSERT(m->getAtomWithIdx(0)->getNumRadicalElectrons() == 0); TEST_ASSERT(m->getAtomWithIdx(1)->getNumRadicalElectrons() == 1); delete m; } { // radical and valence fName = rdbase + "CH.v3k.mol"; RWMol *m = MolFileToMol(fName); // cxsmiles = "[CH] |(0,0,),^5:0|" TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 1); TEST_ASSERT(m->getAtomWithIdx(0)->getNoImplicit()); TEST_ASSERT(m->getAtomWithIdx(0)->getNumExplicitHs() == 1); TEST_ASSERT(m->getAtomWithIdx(0)->getNumRadicalElectrons() == 3); std::string mb = MolToMolBlock(*m, true, -1, true, true); delete m; // no bonds in this one, make sure there's no bond block: TEST_ASSERT(mb.find("BEGIN ATOM") != std::string::npos); TEST_ASSERT(mb.find("BEGIN BOND") == std::string::npos); m = MolBlockToMol(mb); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 1); TEST_ASSERT(m->getAtomWithIdx(0)->getNoImplicit()); TEST_ASSERT(m->getAtomWithIdx(0)->getNumExplicitHs() == 1); TEST_ASSERT(m->getAtomWithIdx(0)->getNumRadicalElectrons() == 3); delete m; } { // R Groups fName = rdbase + "rgroups1.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m); unsigned int idx; std::string label; TEST_ASSERT( m->getAtomWithIdx(3)->hasProp(common_properties::_MolFileRLabel)); m->getAtomWithIdx(3)->getProp(common_properties::_MolFileRLabel, idx); TEST_ASSERT(idx == 2); TEST_ASSERT(m->getAtomWithIdx(3)->getAtomicNum() == 0); TEST_ASSERT(feq(m->getAtomWithIdx(3)->getIsotope(), 2)); TEST_ASSERT( m->getAtomWithIdx(4)->hasProp(common_properties::_MolFileRLabel)); m->getAtomWithIdx(4)->getProp(common_properties::_MolFileRLabel, idx); TEST_ASSERT(idx == 1); TEST_ASSERT(m->getAtomWithIdx(4)->getAtomicNum() == 0); TEST_ASSERT(feq(m->getAtomWithIdx(4)->getIsotope(), 1)); TEST_ASSERT(m->getAtomWithIdx(3)->hasProp(common_properties::dummyLabel)); m->getAtomWithIdx(3)->getProp(common_properties::dummyLabel, label); TEST_ASSERT(label == "R2"); TEST_ASSERT(m->getAtomWithIdx(3)->getSymbol() == "R2"); TEST_ASSERT(m->getAtomWithIdx(4)->hasProp(common_properties::dummyLabel)); m->getAtomWithIdx(4)->getProp(common_properties::dummyLabel, label); TEST_ASSERT(label == "R1"); TEST_ASSERT(m->getAtomWithIdx(4)->getSymbol() == "R1"); std::string mb = MolToMolBlock(*m, true, -1, true, true); delete m; m = MolBlockToMol(mb); TEST_ASSERT(m); TEST_ASSERT( m->getAtomWithIdx(3)->hasProp(common_properties::_MolFileRLabel)); m->getAtomWithIdx(3)->getProp(common_properties::_MolFileRLabel, idx); TEST_ASSERT(idx == 2); TEST_ASSERT(m->getAtomWithIdx(3)->getAtomicNum() == 0); TEST_ASSERT(feq(m->getAtomWithIdx(3)->getIsotope(), 2)); TEST_ASSERT( m->getAtomWithIdx(4)->hasProp(common_properties::_MolFileRLabel)); m->getAtomWithIdx(4)->getProp(common_properties::_MolFileRLabel, idx); TEST_ASSERT(idx == 1); TEST_ASSERT(m->getAtomWithIdx(4)->getAtomicNum() == 0); TEST_ASSERT(feq(m->getAtomWithIdx(4)->getIsotope(), 1)); TEST_ASSERT(m->getAtomWithIdx(3)->hasProp(common_properties::dummyLabel)); m->getAtomWithIdx(3)->getProp(common_properties::dummyLabel, label); TEST_ASSERT(label == "R2"); TEST_ASSERT(m->getAtomWithIdx(3)->getSymbol() == "R2"); TEST_ASSERT(m->getAtomWithIdx(4)->hasProp(common_properties::dummyLabel)); m->getAtomWithIdx(4)->getProp(common_properties::dummyLabel, label); TEST_ASSERT(label == "R1"); TEST_ASSERT(m->getAtomWithIdx(4)->getSymbol() == "R1"); delete m; } { // automatic cut over to v3k std::string smiles(1024, 'C'); RWMol *m = SmilesToMol(smiles); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 1024); auto *conf = new Conformer(m->getNumAtoms()); m->addConformer(conf, true); std::string mb = MolToMolBlock(*m); TEST_ASSERT(mb.find("V2000") == std::string::npos); TEST_ASSERT(mb.find("V3000") != std::string::npos); delete m; } { // D in CTAB fName = rdbase + "D_in_CTAB.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 3); TEST_ASSERT(m->getAtomWithIdx(2)->getAtomicNum() == 1); TEST_ASSERT(m->getAtomWithIdx(2)->getIsotope() == 2); std::string mb = MolToMolBlock(*m, true, -1, true, true); delete m; m = MolBlockToMol(mb); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 3); TEST_ASSERT(m->getAtomWithIdx(2)->getAtomicNum() == 1); TEST_ASSERT(m->getAtomWithIdx(2)->getIsotope() == 2); delete m; } { // T in CTAB fName = rdbase + "T_in_CTAB.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 3); TEST_ASSERT(m->getAtomWithIdx(2)->getAtomicNum() == 1); TEST_ASSERT(m->getAtomWithIdx(2)->getIsotope() == 3); std::string mb = MolToMolBlock(*m, true, -1, true, true); delete m; m = MolBlockToMol(mb); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 3); TEST_ASSERT(m->getAtomWithIdx(2)->getAtomicNum() == 1); TEST_ASSERT(m->getAtomWithIdx(2)->getIsotope() == 3); delete m; } { // atom list fName = rdbase + "list-query.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 6); std::string sma = MolToSmarts(*m); TEST_ASSERT(sma == "[#6]1:[#6]:[#6]:[#6]:[#6]:[#6,#7,#15]:1"); std::string mb = MolToMolBlock(*m, true, -1, true, true); delete m; m = MolBlockToMol(mb); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 6); sma = MolToSmarts(*m); TEST_ASSERT(sma == "[#6]1:[#6]:[#6]:[#6]:[#6]:[#6,#7,#15]:1"); delete m; } { // not atom list fName = rdbase + "not-list-query.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 4); std::string sma = MolToSmarts(*m); TEST_ASSERT(sma == "[#6]-[#6](-[#6])=[!#7&!#8]"); std::string mb = MolToMolBlock(*m, true, -1, true, true); delete m; m = MolBlockToMol(mb); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 4); sma = MolToSmarts(*m); TEST_ASSERT(sma == "[#6]-[#6](-[#6])=[!#7&!#8]"); delete m; } BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testIssue2963522() { BOOST_LOG(rdInfoLog) << " Testing issue 2963522 " << std::endl; { std::string smiles = "CC=CC"; RWMol *m = SmilesToMol(smiles); TEST_ASSERT(m); TEST_ASSERT(m->getBondWithIdx(1)->getBondType() == Bond::DOUBLE); TEST_ASSERT(m->getBondWithIdx(1)->getStereo() == Bond::STEREONONE); auto *conf = new Conformer(m->getNumAtoms()); conf->setAtomPos(0, RDGeom::Point3D(-1, 1, 0)); conf->setAtomPos(1, RDGeom::Point3D(0, 1, 0)); conf->setAtomPos(2, RDGeom::Point3D(0, -1, 0)); conf->setAtomPos(3, RDGeom::Point3D(1, -1, 0)); m->addConformer(conf, true); std::string molBlock = MolToMolBlock(*m); delete m; m = MolBlockToMol(molBlock); TEST_ASSERT(m); TEST_ASSERT(m->getBondWithIdx(1)->getBondType() == Bond::DOUBLE); TEST_ASSERT(m->getBondWithIdx(1)->getStereo() == Bond::STEREOANY); delete m; } { std::string smiles = "C/C=C\\C"; RWMol *m = SmilesToMol(smiles); TEST_ASSERT(m); TEST_ASSERT(m->getBondWithIdx(1)->getBondType() == Bond::DOUBLE); TEST_ASSERT(m->getBondWithIdx(1)->getStereo() == Bond::STEREOZ); auto *conf = new Conformer(m->getNumAtoms()); conf->setAtomPos(0, RDGeom::Point3D(-1, 1, 0)); conf->setAtomPos(1, RDGeom::Point3D(0, 1, 0)); conf->setAtomPos(2, RDGeom::Point3D(0, -1, 0)); conf->setAtomPos(3, RDGeom::Point3D(-1, -1, 0)); m->addConformer(conf, true); std::string molBlock = MolToMolBlock(*m); delete m; m = MolBlockToMol(molBlock); TEST_ASSERT(m); TEST_ASSERT(m->getBondWithIdx(1)->getBondType() == Bond::DOUBLE); TEST_ASSERT(m->getBondWithIdx(1)->getStereo() == Bond::STEREOZ); delete m; } { std::string smiles = "C/C=C/C"; RWMol *m = SmilesToMol(smiles); TEST_ASSERT(m); TEST_ASSERT(m->getBondWithIdx(1)->getBondType() == Bond::DOUBLE); TEST_ASSERT(m->getBondWithIdx(1)->getStereo() == Bond::STEREOE); auto *conf = new Conformer(m->getNumAtoms()); conf->setAtomPos(0, RDGeom::Point3D(-1, 1, 0)); conf->setAtomPos(1, RDGeom::Point3D(0, 1, 0)); conf->setAtomPos(2, RDGeom::Point3D(0, -1, 0)); conf->setAtomPos(3, RDGeom::Point3D(1, -1, 0)); m->addConformer(conf, true); std::string molBlock = MolToMolBlock(*m); delete m; m = MolBlockToMol(molBlock); TEST_ASSERT(m); TEST_ASSERT(m->getBondWithIdx(1)->getBondType() == Bond::DOUBLE); TEST_ASSERT(m->getBondWithIdx(1)->getStereo() == Bond::STEREOE); delete m; } { std::string smiles = "C1C=CC1"; RWMol *m = SmilesToMol(smiles); TEST_ASSERT(m); TEST_ASSERT(m->getBondWithIdx(1)->getBondType() == Bond::DOUBLE); TEST_ASSERT(m->getBondWithIdx(1)->getStereo() == Bond::STEREONONE); auto *conf = new Conformer(m->getNumAtoms()); conf->setAtomPos(0, RDGeom::Point3D(-1, 1, 0)); conf->setAtomPos(1, RDGeom::Point3D(0, 1, 0)); conf->setAtomPos(2, RDGeom::Point3D(0, -1, 0)); conf->setAtomPos(3, RDGeom::Point3D(-1, -1, 0)); m->addConformer(conf, true); std::string molBlock = MolToMolBlock(*m); delete m; m = MolBlockToMol(molBlock); TEST_ASSERT(m); TEST_ASSERT(m->getBondWithIdx(1)->getBondType() == Bond::DOUBLE); TEST_ASSERT(m->getBondWithIdx(1)->getStereo() == Bond::STEREONONE); delete m; } { // this was issue 3009756: std::string smiles = "CC(=O)C"; RWMol *m = SmilesToMol(smiles); TEST_ASSERT(m); TEST_ASSERT(m->getBondWithIdx(1)->getBondType() == Bond::DOUBLE); TEST_ASSERT(m->getBondWithIdx(1)->getStereo() == Bond::STEREONONE); auto *conf = new Conformer(m->getNumAtoms()); conf->setAtomPos(0, RDGeom::Point3D(-1, 0, 0)); conf->setAtomPos(1, RDGeom::Point3D(0, 0, 0)); conf->setAtomPos(2, RDGeom::Point3D(0, 1, 0)); conf->setAtomPos(3, RDGeom::Point3D(1, 0, 0)); m->addConformer(conf, true); std::string molBlock = MolToMolBlock(*m); delete m; m = MolBlockToMol(molBlock); TEST_ASSERT(m); TEST_ASSERT(m->getBondWithIdx(1)->getBondType() == Bond::DOUBLE); TEST_ASSERT(m->getBondWithIdx(1)->getStereo() == Bond::STEREONONE); delete m; } { // this was issue 3009756: std::string smiles = "CC(=C)Cl"; RWMol *m = SmilesToMol(smiles); TEST_ASSERT(m); TEST_ASSERT(m->getBondWithIdx(1)->getBondType() == Bond::DOUBLE); TEST_ASSERT(m->getBondWithIdx(1)->getStereo() == Bond::STEREONONE); auto *conf = new Conformer(m->getNumAtoms()); conf->setAtomPos(0, RDGeom::Point3D(-1, 0, 0)); conf->setAtomPos(1, RDGeom::Point3D(0, 0, 0)); conf->setAtomPos(2, RDGeom::Point3D(0, 1, 0)); conf->setAtomPos(3, RDGeom::Point3D(1, 0, 0)); m->addConformer(conf, true); std::string molBlock = MolToMolBlock(*m); delete m; m = MolBlockToMol(molBlock); TEST_ASSERT(m); TEST_ASSERT(m->getBondWithIdx(1)->getBondType() == Bond::DOUBLE); TEST_ASSERT(m->getBondWithIdx(1)->getStereo() == Bond::STEREONONE); delete m; } BOOST_LOG(rdInfoLog) << " done" << std::endl; } void testIssue3073163() { BOOST_LOG(rdInfoLog) << " Testing issue 3073163 " << std::endl; { std::string smiles = "C[2H]"; RWMol *m = SmilesToMol(smiles); TEST_ASSERT(m); smiles = "[2#1]"; RWMol *p = SmartsToMol(smiles); TEST_ASSERT(p); MatchVectType mv; TEST_ASSERT(SubstructMatch(*m, *p, mv)); std::string mb = MolToMolBlock(*m); // std::cerr<<"mb:\n"<getNumAtoms() == 476); TEST_ASSERT(m->getNumBonds() == 531); std::cerr << "generating smiles" << std::endl; std::string smiles = MolToSmiles(*m, false, false, -1, false); std::cerr << "smiles: " << smiles << std::endl; std::cerr << "converting back" << std::endl; RWMol *m2 = SmilesToMol(smiles); TEST_ASSERT(m2); TEST_ASSERT(m2->getNumAtoms() == 476); TEST_ASSERT(m2->getNumBonds() == 531); MatchVectType mv; std::cerr << "check isomorphism" << std::endl; TEST_ASSERT(SubstructMatch(*m, *m2, mv)); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); delete m2; #if 1 BOOST_LOG(rdInfoLog) << "Large molecule canonical smiles test" << std::endl; std::string csmiles = MolToSmiles(*m); for (unsigned int i = 0; i < 50; ++i) { if (!(i % 10)) { BOOST_LOG(rdInfoLog) << "Iteration: " << i + 1 << " of 50" << std::endl; } std::string nsmiles = MolToSmiles(*m, false, false, 2 * i, false); RWMol *nm = SmilesToMol(nsmiles); TEST_ASSERT(nm); TEST_ASSERT(nm->getNumAtoms() == 476); TEST_ASSERT(nm->getNumBonds() == 531); nsmiles = MolToSmiles(*m); if (nsmiles != csmiles) { std::cerr << "MISMATCH:\n" << nsmiles << "\n" << csmiles << "\n"; } TEST_ASSERT(nsmiles == csmiles); delete nm; } #endif delete m; } BOOST_LOG(rdInfoLog) << " done" << std::endl; } void testIssue3228150() { BOOST_LOG(rdInfoLog) << "-------------------------------------" << std::endl; BOOST_LOG(rdInfoLog) << "Issue 3228150: round-trip stereochemistry failure" << std::endl; std::string rdbase = getenv("RDBASE"); { std::string fName; RWMol *m; fName = rdbase + "/Code/GraphMol/FileParsers/test_data/Issue3228150.sdf"; m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getBondWithIdx(0)->getBondType() == Bond::DOUBLE); TEST_ASSERT(m->getBondWithIdx(0)->getStereo() == Bond::STEREOZ); TEST_ASSERT(m->getBondWithIdx(2)->getBondType() == Bond::DOUBLE); TEST_ASSERT(m->getBondWithIdx(2)->getStereo() == Bond::STEREOZ); std::string smi1 = MolToSmiles(*m, true); BOOST_LOG(rdInfoLog) << " : " << smi1 << std::endl; m->clearComputedProps(); m->updatePropertyCache(); std::string smi2 = MolToSmiles(*m, true); BOOST_LOG(rdInfoLog) << " : " << smi2 << std::endl; TEST_ASSERT(smi1 == smi2); delete m; } { std::string fName; RWMol *m; fName = rdbase + "/Code/GraphMol/FileParsers/test_data/Issue3228150.full.sdf"; m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getBondWithIdx(2)->getBondType() == Bond::DOUBLE); TEST_ASSERT(m->getBondWithIdx(2)->getStereo() == Bond::STEREOZ); TEST_ASSERT(m->getBondWithIdx(4)->getBondType() == Bond::DOUBLE); TEST_ASSERT(m->getBondWithIdx(4)->getStereo() == Bond::STEREOZ); TEST_ASSERT(m->getBondWithIdx(6)->getBondType() == Bond::DOUBLE); TEST_ASSERT(m->getBondWithIdx(6)->getStereo() == Bond::STEREOZ); TEST_ASSERT(m->getBondWithIdx(8)->getBondType() == Bond::DOUBLE); TEST_ASSERT(m->getBondWithIdx(8)->getStereo() == Bond::STEREOZ); std::string smi1 = MolToSmiles(*m, true); BOOST_LOG(rdInfoLog) << " : " << smi1 << std::endl; MolOps::assignStereochemistry(*m, true, true); TEST_ASSERT(m->getBondWithIdx(2)->getBondType() == Bond::DOUBLE); TEST_ASSERT(m->getBondWithIdx(2)->getStereo() == Bond::STEREOZ); TEST_ASSERT(m->getBondWithIdx(4)->getBondType() == Bond::DOUBLE); TEST_ASSERT(m->getBondWithIdx(4)->getStereo() == Bond::STEREOZ); TEST_ASSERT(m->getBondWithIdx(6)->getBondType() == Bond::DOUBLE); TEST_ASSERT(m->getBondWithIdx(6)->getStereo() == Bond::STEREOZ); TEST_ASSERT(m->getBondWithIdx(8)->getBondType() == Bond::DOUBLE); TEST_ASSERT(m->getBondWithIdx(8)->getStereo() == Bond::STEREOZ); std::string smi2 = MolToSmiles(*m, true); smi2 = MolToSmiles(*m, true); BOOST_LOG(rdInfoLog) << " : " << smi2 << std::endl; TEST_ASSERT(smi1 == smi2); delete m; } BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testIssue3313540() { BOOST_LOG(rdInfoLog) << "testing writing mol file R-groups (issue 3313540)" << std::endl; std::string rdbase = getenv("RDBASE"); { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/rgroups1.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m); unsigned int idx; TEST_ASSERT( m->getAtomWithIdx(3)->hasProp(common_properties::_MolFileRLabel)); m->getAtomWithIdx(3)->getProp(common_properties::_MolFileRLabel, idx); TEST_ASSERT(idx == 2); TEST_ASSERT( m->getAtomWithIdx(4)->hasProp(common_properties::_MolFileRLabel)); m->getAtomWithIdx(4)->getProp(common_properties::_MolFileRLabel, idx); TEST_ASSERT(idx == 1); std::string mb = MolToMolBlock(*m); RWMol *m2 = MolBlockToMol(mb); TEST_ASSERT(m2); TEST_ASSERT( m2->getAtomWithIdx(3)->hasProp(common_properties::_MolFileRLabel)); m2->getAtomWithIdx(3)->getProp(common_properties::_MolFileRLabel, idx); TEST_ASSERT(idx == 2); TEST_ASSERT( m2->getAtomWithIdx(4)->hasProp(common_properties::_MolFileRLabel)); m2->getAtomWithIdx(4)->getProp(common_properties::_MolFileRLabel, idx); TEST_ASSERT(idx == 1); delete m; delete m2; } BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testIssue3359739() { // basic writing test BOOST_LOG(rdInfoLog) << " ----------> Test issue 3359739 " << std::endl; std::string smi = "[C]C"; RWMol *m = SmilesToMol(smi); TEST_ASSERT(m); TEST_ASSERT(m->getAtomWithIdx(0)->getNumRadicalElectrons() == 3); std::string molBlock = MolToMolBlock(*m); delete m; m = MolBlockToMol(molBlock); TEST_ASSERT(m); TEST_ASSERT(m->getAtomWithIdx(0)->getNumRadicalElectrons() == 3); delete m; BOOST_LOG(rdInfoLog) << " Finished <---------- " << std::endl; } void testIssue3374639() { // basic writing test BOOST_LOG(rdInfoLog) << " ----------> Test issue 3374639 " << std::endl; std::string rdbase = getenv("RDBASE"); { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/Issue3374639.2.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m->getAtomWithIdx(1)->hasProp(common_properties::_CIPCode)); std::string cip; m->getAtomWithIdx(1)->getProp(common_properties::_CIPCode, cip); TEST_ASSERT(cip == "S"); delete m; } { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/Issue3374639.1.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m->getAtomWithIdx(1)->hasProp(common_properties::_CIPCode)); std::string cip; m->getAtomWithIdx(1)->getProp(common_properties::_CIPCode, cip); TEST_ASSERT(cip == "S"); delete m; } { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/Issue3374639.full.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m->getAtomWithIdx(16)->hasProp(common_properties::_CIPCode)); std::string cip; m->getAtomWithIdx(16)->getProp(common_properties::_CIPCode, cip); TEST_ASSERT(cip == "S"); delete m; } BOOST_LOG(rdInfoLog) << " Finished <---------- " << std::endl; } void testThreeCoordinateChirality() { // basic writing test BOOST_LOG(rdInfoLog) << " ----------> Test three-coordinate chirality " << std::endl; std::string rdbase = getenv("RDBASE"); { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/three_coordinate_chirality.1.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m->getAtomWithIdx(1)->hasProp(common_properties::_CIPCode)); std::string cip; m->getAtomWithIdx(1)->getProp(common_properties::_CIPCode, cip); TEST_ASSERT(cip == "S"); delete m; } { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/three_coordinate_chirality.2.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m->getAtomWithIdx(1)->hasProp(common_properties::_CIPCode)); std::string cip; m->getAtomWithIdx(1)->getProp(common_properties::_CIPCode, cip); TEST_ASSERT(cip == "S"); delete m; } { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/three_coordinate_chirality.3.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(!m->getAtomWithIdx(1)->hasProp(common_properties::_CIPCode)); delete m; } { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/three_coordinate_chirality.4.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(!m->getAtomWithIdx(1)->hasProp(common_properties::_CIPCode)); delete m; } { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/three_coordinate_chirality.5.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m->getAtomWithIdx(1)->hasProp(common_properties::_CIPCode)); std::string cip; m->getAtomWithIdx(1)->getProp(common_properties::_CIPCode, cip); TEST_ASSERT(cip == "S"); delete m; } { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/three_coordinate_chirality.6.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m->getAtomWithIdx(1)->hasProp(common_properties::_CIPCode)); std::string cip; m->getAtomWithIdx(1)->getProp(common_properties::_CIPCode, cip); TEST_ASSERT(cip == "S"); delete m; } BOOST_LOG(rdInfoLog) << " Finished <---------- " << std::endl; } void testIssue3375647() { // basic writing test BOOST_LOG(rdInfoLog) << " ----------> Test issue 3375647 " << std::endl; std::string rdbase = getenv("RDBASE"); { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/Issue3375647.1.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m->getBondBetweenAtoms(2, 11)->getBondType() == Bond::DOUBLE); TEST_ASSERT(m->getBondBetweenAtoms(2, 11)->getBondDir() != Bond::EITHERDOUBLE); TEST_ASSERT(m->getBondBetweenAtoms(2, 11)->getStereo() == Bond::STEREOZ); delete m; } { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/Issue3375647.2.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m->getBondBetweenAtoms(2, 11)->getBondType() == Bond::DOUBLE); TEST_ASSERT(m->getBondBetweenAtoms(2, 11)->getBondDir() != Bond::EITHERDOUBLE); TEST_ASSERT(m->getBondBetweenAtoms(2, 11)->getStereo() == Bond::STEREOE); delete m; } BOOST_LOG(rdInfoLog) << " Finished <---------- " << std::endl; } void testIssue3375684() { // basic writing test BOOST_LOG(rdInfoLog) << " ----------> Test issue 3375684 " << std::endl; std::string rdbase = getenv("RDBASE"); { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/Issue3375684.1.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m->getBondBetweenAtoms(6, 7)->getBondType() == Bond::DOUBLE); TEST_ASSERT(m->getBondBetweenAtoms(6, 7)->getStereo() == Bond::STEREOANY); delete m; } { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/Issue3375684.2.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m->getBondBetweenAtoms(3, 9)->getBondType() == Bond::DOUBLE); TEST_ASSERT(m->getBondBetweenAtoms(3, 9)->getBondDir() != Bond::EITHERDOUBLE); TEST_ASSERT(m->getBondBetweenAtoms(3, 9)->getStereo() == Bond::STEREOE); delete m; } BOOST_LOG(rdInfoLog) << " Finished <---------- " << std::endl; } void testChiralPhosphorous() { // basic writing test BOOST_LOG(rdInfoLog) << " ----------> Test handling of chiral phosphorous " << std::endl; std::string rdbase = getenv("RDBASE"); { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/chiral_phosphorous.1.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getAtomWithIdx(5)->hasProp(common_properties::_CIPCode)); std::string cip; m->getAtomWithIdx(5)->getProp(common_properties::_CIPCode, cip); TEST_ASSERT(cip == "R"); delete m; } { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/chiral_phosphorous.2.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getAtomWithIdx(5)->hasProp(common_properties::_CIPCode)); std::string cip; m->getAtomWithIdx(5)->getProp(common_properties::_CIPCode, cip); TEST_ASSERT(cip == "S"); delete m; } { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/chiral_phosphorous.3.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(!m->getAtomWithIdx(5)->hasProp(common_properties::_CIPCode)); delete m; } { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/chiral_phosphorous.4.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(!m->getAtomWithIdx(5)->hasProp(common_properties::_CIPCode)); delete m; } BOOST_LOG(rdInfoLog) << " Finished <---------- " << std::endl; } void testIssue3392107() { // basic writing test BOOST_LOG(rdInfoLog) << " ----------> Test issue 3392107 " << std::endl; std::string rdbase = getenv("RDBASE"); { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/Issue3392107.1.mol"; RWMol *m = MolFileToMol(fName); std::string smi; MatchVectType mv; RWMol *m2; smi = "C1CCCCC1"; m2 = SmilesToMol(smi); TEST_ASSERT(m2); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 6); delete m2; smi = "C1CCCCN1"; m2 = SmilesToMol(smi); TEST_ASSERT(m2); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 6); delete m2; smi = "C1CCNCN1"; m2 = SmilesToMol(smi); TEST_ASSERT(m2); TEST_ASSERT(SubstructMatch(*m2, *m, mv)); TEST_ASSERT(mv.size() == 6); delete m2; smi = "C1NCNCN1"; m2 = SmilesToMol(smi); TEST_ASSERT(m2); TEST_ASSERT(!SubstructMatch(*m2, *m, mv)); delete m2; delete m; } BOOST_LOG(rdInfoLog) << " Finished <---------- " << std::endl; } void testIssue3432136() { BOOST_LOG(rdInfoLog) << " ----------> Test issue 3432136 " << std::endl; std::string rdbase = getenv("RDBASE"); { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/Issue3432136_1.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(!m); } { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/Issue3432136_1.v3k.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(!m); } { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/Issue3432136_2.v3k.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m); delete m; } { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/Issue3432136_2.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m); delete m; } BOOST_LOG(rdInfoLog) << " Finished <---------- " << std::endl; } void testIssue3477283() { BOOST_LOG(rdInfoLog) << " ----------> Test issue 3477283 " << std::endl; std::string rdbase = getenv("RDBASE"); { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/Issue3477283.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m); delete m; } BOOST_LOG(rdInfoLog) << " Finished <---------- " << std::endl; } void testIssue3484552() { BOOST_LOG(rdInfoLog) << " ----------> Test issue 3484552 " << std::endl; { std::string smi = "C[13CH3]"; RWMol *m = SmilesToMol(smi); TEST_ASSERT(m); TEST_ASSERT(m->getAtomWithIdx(1)->getMass() > 12.999); std::string molBlock = MolToMolBlock(*m); TEST_ASSERT(molBlock.find("M ISO") != std::string::npos); delete m; m = MolBlockToMol(molBlock); TEST_ASSERT(m); TEST_ASSERT(m->getAtomWithIdx(1)->getMass() > 12.999); delete m; } BOOST_LOG(rdInfoLog) << " Finished <---------- " << std::endl; } void testIssue3514824() { BOOST_LOG(rdInfoLog) << " ----------> Test issue 3514824 " << std::endl; std::string rdbase = getenv("RDBASE"); { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/Issue3514824.2.mol"; RWMol *m = MolFileToMol(fName, false); TEST_ASSERT(m); m->updatePropertyCache(); MolOps::findSSSR(*m); TEST_ASSERT(m->getRingInfo()); TEST_ASSERT(m->getRingInfo()->isInitialized()); TEST_ASSERT(m->getRingInfo()->numRings() == 6); delete m; } { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/Issue3514824.mol"; RWMol *m = MolFileToMol(fName, false); TEST_ASSERT(m); m->updatePropertyCache(); MolOps::findSSSR(*m); TEST_ASSERT(m->getRingInfo()); TEST_ASSERT(m->getRingInfo()->isInitialized()); TEST_ASSERT(m->getRingInfo()->numRings() == 8); delete m; } BOOST_LOG(rdInfoLog) << " Finished <---------- " << std::endl; } void testIssue3525799() { BOOST_LOG(rdInfoLog) << "-------------------------------------" << std::endl; BOOST_LOG(rdInfoLog) << "Issue 3525799: bad smiles for r groups" << std::endl; std::string rdbase = getenv("RDBASE"); { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/Issue3525799.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m); std::string smiles = MolToSmiles(*m, true); std::cerr << "smiles: " << smiles << std::endl; TEST_ASSERT(smiles == "[1*]c1c([2*])c([3*])c([4*])c(-c2c([9*])oc3c([8*])c([7*])c([6*]" ")c([5*])c3c2=O)c1[10*]"); delete m; } BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testIssue3557675() { BOOST_LOG(rdInfoLog) << "-------------------------------------" << std::endl; BOOST_LOG(rdInfoLog) << "Bad issue 3557676: handling of D and T in CTABs" << std::endl; std::string rdbase = getenv("RDBASE"); { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/D_in_CTAB.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 3); TEST_ASSERT(m->getAtomWithIdx(2)->getAtomicNum() == 1); TEST_ASSERT(m->getAtomWithIdx(2)->getIsotope() == 2); delete m; } { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/T_in_CTAB.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 3); TEST_ASSERT(m->getAtomWithIdx(2)->getAtomicNum() == 1); TEST_ASSERT(m->getAtomWithIdx(2)->getIsotope() == 3); delete m; } BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testSkipLines() { BOOST_LOG(rdInfoLog) << "-------------------------------------" << std::endl; BOOST_LOG(rdInfoLog) << "Testing skip lines in CTABs" << std::endl; std::string rdbase = getenv("RDBASE"); std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/SkipLines.sdf"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 1); delete m; BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testIssue269() { BOOST_LOG(rdInfoLog) << "-------------------------------------" << std::endl; BOOST_LOG(rdInfoLog) << "Bad issue 269: handling of bad atom symbols in CTABs" << std::endl; std::string rdbase = getenv("RDBASE"); { // since the new elements were added, the original version of this no longer // fails. The test input file has been updated to still have an atomic // symbol that is not recognized. We'll be ok until Mv is an element. :-) std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/Issue269.mol"; RWMol *m = nullptr; try { m = MolFileToMol(fName); } catch (...) { } TEST_ASSERT(!m); } BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testMolFileChiralFlag() { BOOST_LOG(rdInfoLog) << "testing handling of chiral flags" << std::endl; std::string rdbase = getenv("RDBASE"); rdbase += "/Code/GraphMol/FileParsers/test_data/"; // SF.Net Issue1603923: problems with multiple chg lines { RWMol *m1; std::string fName; fName = rdbase + "chiral_flag.mol"; m1 = MolFileToMol(fName); TEST_ASSERT(m1); TEST_ASSERT(m1->hasProp(common_properties::_MolFileChiralFlag)); unsigned int cflag; m1->getProp(common_properties::_MolFileChiralFlag, cflag); TEST_ASSERT(cflag == 1); delete m1; } BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testMolFileTotalValence() { BOOST_LOG(rdInfoLog) << "testing handling of mol file valence flags" << std::endl; std::string rdbase = getenv("RDBASE"); rdbase += "/Code/GraphMol/FileParsers/test_data/"; { RWMol *m1; std::string fName; fName = rdbase + "Na.mol"; m1 = MolFileToMol(fName); TEST_ASSERT(m1); TEST_ASSERT(m1->getNumAtoms() == 1); TEST_ASSERT(m1->getAtomWithIdx(0)->getNoImplicit()); TEST_ASSERT(m1->getAtomWithIdx(0)->getNumExplicitHs() == 0); TEST_ASSERT(m1->getAtomWithIdx(0)->getNumRadicalElectrons() == 1); delete m1; } { RWMol *m1; std::string fName; fName = rdbase + "CH.mol"; m1 = MolFileToMol(fName); // cxsmi = "[CH] |(-1.2375,2.1509,),^5:0|" TEST_ASSERT(m1); TEST_ASSERT(m1->getNumAtoms() == 1); TEST_ASSERT(m1->getAtomWithIdx(0)->getNoImplicit()); TEST_ASSERT(m1->getAtomWithIdx(0)->getNumExplicitHs() == 1); TEST_ASSERT(m1->getAtomWithIdx(0)->getNumRadicalElectrons() == 3); delete m1; } { RWMol *m1; std::string fName; fName = rdbase + "CH2.mol"; m1 = MolFileToMol(fName); TEST_ASSERT(m1); TEST_ASSERT(m1->getNumAtoms() == 1); TEST_ASSERT(m1->getAtomWithIdx(0)->getNoImplicit()); TEST_ASSERT(m1->getAtomWithIdx(0)->getNumExplicitHs() == 2); TEST_ASSERT(m1->getAtomWithIdx(0)->getNumRadicalElectrons() == 2); delete m1; } { RWMol *m1; std::string fName; fName = rdbase + "CH3.mol"; m1 = MolFileToMol(fName); TEST_ASSERT(m1); TEST_ASSERT(m1->getNumAtoms() == 1); TEST_ASSERT(m1->getAtomWithIdx(0)->getNoImplicit()); TEST_ASSERT(m1->getAtomWithIdx(0)->getNumExplicitHs() == 3); TEST_ASSERT(m1->getAtomWithIdx(0)->getNumRadicalElectrons() == 1); delete m1; } { // make sure we get it for v3k mol blocks too: RWMol *m1; std::string fName; fName = rdbase + "CH.v3k.mol"; m1 = MolFileToMol(fName); // cxsmiles = "[CH] |(0,0,),^5:0|" TEST_ASSERT(m1); TEST_ASSERT(m1->getNumAtoms() == 1); TEST_ASSERT(m1->getAtomWithIdx(0)->getNoImplicit()); TEST_ASSERT(m1->getAtomWithIdx(0)->getNumExplicitHs() == 1); TEST_ASSERT(m1->getAtomWithIdx(0)->getNumRadicalElectrons() == 3); delete m1; } BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testGithub88() { BOOST_LOG(rdInfoLog) << "testing github issue 88: M END not being read from V3K ctabs" << std::endl; std::string rdbase = getenv("RDBASE"); rdbase += "/Code/GraphMol/FileParsers/test_data/"; { std::string fName; fName = rdbase + "github88.v3k.mol"; bool ok = false; try { MolFileToMol(fName); } catch (FileParseException &) { ok = true; } TEST_ASSERT(ok); } BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testGithub82() { BOOST_LOG(rdInfoLog) << "testing github issue 82: stereochemistry only " "perceived if sanitization is done" << std::endl; std::string rdbase = getenv("RDBASE"); rdbase += "/Code/GraphMol/FileParsers/test_data/"; { std::string fName; fName = rdbase + "github82.1.mol"; ROMol *m; m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getAtomWithIdx(2)->getChiralTag() != Atom::CHI_UNSPECIFIED); TEST_ASSERT(m->getAtomWithIdx(3)->getChiralTag() != Atom::CHI_UNSPECIFIED); TEST_ASSERT(m->getAtomWithIdx(4)->getChiralTag() == Atom::CHI_UNSPECIFIED); delete m; m = MolFileToMol(fName, true, false); TEST_ASSERT(m); TEST_ASSERT(m->getAtomWithIdx(2)->getChiralTag() != Atom::CHI_UNSPECIFIED); TEST_ASSERT(m->getAtomWithIdx(3)->getChiralTag() != Atom::CHI_UNSPECIFIED); TEST_ASSERT(m->getAtomWithIdx(4)->getChiralTag() == Atom::CHI_UNSPECIFIED); delete m; m = MolFileToMol(fName, false, false); TEST_ASSERT(m); TEST_ASSERT(m->getAtomWithIdx(2)->getChiralTag() != Atom::CHI_UNSPECIFIED); TEST_ASSERT(m->getAtomWithIdx(3)->getChiralTag() != Atom::CHI_UNSPECIFIED); TEST_ASSERT(m->getAtomWithIdx(4)->getChiralTag() == Atom::CHI_UNSPECIFIED); delete m; } BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testMolFileWithHs() { BOOST_LOG(rdInfoLog) << "testing impact of Hs in mol files on stereochemistry" << std::endl; std::string rdbase = getenv("RDBASE"); rdbase += "/Code/GraphMol/FileParsers/test_data/"; { std::string fName; fName = rdbase + "chiral_3h.mol"; ROMol *m; m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getAtomWithIdx(3)->getChiralTag() != Atom::CHI_UNSPECIFIED); delete m; m = MolFileToMol(fName, true, false); TEST_ASSERT(m); TEST_ASSERT(m->getAtomWithIdx(3)->getChiralTag() != Atom::CHI_UNSPECIFIED); delete m; m = MolFileToMol(fName, false, false); TEST_ASSERT(m); TEST_ASSERT(m->getAtomWithIdx(3)->getChiralTag() != Atom::CHI_UNSPECIFIED); delete m; } BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testMolFileWithRxn() { BOOST_LOG(rdInfoLog) << "testing reading reactions in mol files" << std::endl; std::string rdbase = getenv("RDBASE"); rdbase += "/Code/GraphMol/FileParsers/test_data/"; { std::string fName; fName = rdbase + "rxn1.mol"; ROMol *m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 18); TEST_ASSERT(m->getNumBonds() == 16); TEST_ASSERT(m->getAtomWithIdx(0)->hasProp(common_properties::molRxnRole)); TEST_ASSERT( m->getAtomWithIdx(0)->getProp(common_properties::molRxnRole) == 1); TEST_ASSERT( m->getAtomWithIdx(0)->hasProp(common_properties::molRxnComponent)); TEST_ASSERT(m->getAtomWithIdx(0)->getProp( common_properties::molRxnComponent) == 1); TEST_ASSERT(m->getAtomWithIdx(17)->hasProp(common_properties::molRxnRole)); TEST_ASSERT(m->getAtomWithIdx(17)->getProp( common_properties::molRxnRole) == 2); TEST_ASSERT( m->getAtomWithIdx(17)->hasProp(common_properties::molRxnComponent)); TEST_ASSERT(m->getAtomWithIdx(17)->getProp( common_properties::molRxnComponent) == 3); delete m; } BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testPDBFile() { BOOST_LOG(rdInfoLog) << "testing reading pdb files" << std::endl; std::string rdbase = getenv("RDBASE"); rdbase += "/Code/GraphMol/FileParsers/test_data/"; { std::string fName; fName = rdbase + "1CRN.pdb"; ROMol *m = PDBFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 327); TEST_ASSERT(m->getNumBonds() == 337); TEST_ASSERT(m->getAtomWithIdx(0)->getMonomerInfo()); TEST_ASSERT(m->getAtomWithIdx(0)->getMonomerInfo()->getMonomerType() == AtomMonomerInfo::PDBRESIDUE); TEST_ASSERT(static_cast( m->getAtomWithIdx(0)->getMonomerInfo()) ->getSerialNumber() == 1); TEST_ASSERT(static_cast( m->getAtomWithIdx(0)->getMonomerInfo()) ->getResidueNumber() == 1); TEST_ASSERT(static_cast( m->getAtomWithIdx(9)->getMonomerInfo()) ->getSerialNumber() == 10); TEST_ASSERT(static_cast( m->getAtomWithIdx(9)->getMonomerInfo()) ->getResidueNumber() == 2); TEST_ASSERT(static_cast( m->getAtomWithIdx(0)->getMonomerInfo()) ->getName() == " N "); TEST_ASSERT(static_cast( m->getAtomWithIdx(0)->getMonomerInfo()) ->getResidueName() == "THR"); TEST_ASSERT(feq(static_cast( m->getAtomWithIdx(0)->getMonomerInfo()) ->getTempFactor(), 13.79)); TEST_ASSERT(m->getNumConformers() == 1); TEST_ASSERT(feq(m->getConformer().getAtomPos(0).x, 17.047)); TEST_ASSERT(feq(m->getConformer().getAtomPos(0).y, 14.099)); TEST_ASSERT(feq(m->getConformer().getAtomPos(0).z, 3.625)); std::string pkl; MolPickler::pickleMol(*m, pkl); RWMol m2(pkl); for (const auto atom : m->atoms()) { const auto atom2 = m2.getAtomWithIdx(atom->getIdx()); auto info1 = static_cast(atom->getMonomerInfo()); auto info2 = static_cast(atom2->getMonomerInfo()); // this is awkward because operator== isn't defined for AtomPDBResidueInfo // yet TEST_ASSERT(info1->getName() == info2->getName()); TEST_ASSERT(info1->getChainId() == info2->getChainId()); TEST_ASSERT(info1->getInsertionCode() == info2->getInsertionCode()); TEST_ASSERT(info1->getTempFactor() == info2->getTempFactor()); TEST_ASSERT(info1->getMonomerType() == info2->getMonomerType()); TEST_ASSERT(info1->getResidueName() == info2->getResidueName()); TEST_ASSERT(info1->getResidueNumber() == info2->getResidueNumber()); TEST_ASSERT(info1->getSerialNumber() == info2->getSerialNumber()); TEST_ASSERT(info1->getOccupancy() == info2->getOccupancy()); } std::string mb = MolToPDBBlock(*m); delete m; m = PDBBlockToMol(mb); TEST_ASSERT(m->getNumAtoms() == 327); TEST_ASSERT(m->getNumBonds() == 337); TEST_ASSERT(m->getAtomWithIdx(0)->getMonomerInfo()); TEST_ASSERT(m->getAtomWithIdx(0)->getMonomerInfo()->getMonomerType() == AtomMonomerInfo::PDBRESIDUE); TEST_ASSERT(static_cast( m->getAtomWithIdx(0)->getMonomerInfo()) ->getSerialNumber() == 1); TEST_ASSERT(static_cast( m->getAtomWithIdx(0)->getMonomerInfo()) ->getResidueNumber() == 1); TEST_ASSERT(static_cast( m->getAtomWithIdx(9)->getMonomerInfo()) ->getSerialNumber() == 10); TEST_ASSERT(static_cast( m->getAtomWithIdx(9)->getMonomerInfo()) ->getResidueNumber() == 2); TEST_ASSERT(static_cast( m->getAtomWithIdx(0)->getMonomerInfo()) ->getName() == " N "); TEST_ASSERT(static_cast( m->getAtomWithIdx(0)->getMonomerInfo()) ->getResidueName() == "THR"); TEST_ASSERT(feq(static_cast( m->getAtomWithIdx(0)->getMonomerInfo()) ->getTempFactor(), 13.79)); TEST_ASSERT(m->getNumConformers() == 1); TEST_ASSERT(feq(m->getConformer().getAtomPos(0).x, 17.047)); TEST_ASSERT(feq(m->getConformer().getAtomPos(0).y, 14.099)); TEST_ASSERT(feq(m->getConformer().getAtomPos(0).z, 3.625)); // test adding hydrogens ROMol *nm = MolOps::addHs(*m, false, false, nullptr, true); auto *info = (AtomPDBResidueInfo *)(nm->getAtomWithIdx(nm->getNumAtoms() - 1) ->getMonomerInfo()); TEST_ASSERT(info->getMonomerType() == AtomMonomerInfo::PDBRESIDUE); TEST_ASSERT(info->getName() == " H7 "); TEST_ASSERT(info->getResidueName() == "ASN"); delete nm; delete m; } { std::string fName; fName = rdbase + "2FVD.pdb"; ROMol *m = PDBFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 2501); TEST_ASSERT(m->getNumBonds() == 2383); TEST_ASSERT(m->getAtomWithIdx(0)->getMonomerInfo()); TEST_ASSERT(m->getAtomWithIdx(0)->getMonomerInfo()->getMonomerType() == AtomMonomerInfo::PDBRESIDUE); TEST_ASSERT(static_cast( m->getAtomWithIdx(0)->getMonomerInfo()) ->getSerialNumber() == 1); TEST_ASSERT(static_cast( m->getAtomWithIdx(0)->getMonomerInfo()) ->getResidueNumber() == 1); TEST_ASSERT(static_cast( m->getAtomWithIdx(0)->getMonomerInfo()) ->getIsHeteroAtom() == 0); TEST_ASSERT(static_cast( m->getAtomWithIdx(2292)->getMonomerInfo()) ->getSerialNumber() == 2294); TEST_ASSERT(static_cast( m->getAtomWithIdx(2292)->getMonomerInfo()) ->getResidueNumber() == 299); TEST_ASSERT(static_cast( m->getAtomWithIdx(2292)->getMonomerInfo()) ->getIsHeteroAtom() == 1); TEST_ASSERT(static_cast( m->getAtomWithIdx(2292)->getMonomerInfo()) ->getChainId() == "A"); TEST_ASSERT(static_cast( m->getAtomWithIdx(1)->getMonomerInfo()) ->getName() == " CA "); TEST_ASSERT(static_cast( m->getAtomWithIdx(1)->getMonomerInfo()) ->getResidueName() == "MET"); TEST_ASSERT(static_cast( m->getAtomWithIdx(2292)->getMonomerInfo()) ->getName() == " N1 "); TEST_ASSERT(static_cast( m->getAtomWithIdx(2292)->getMonomerInfo()) ->getResidueName() == "LIA"); std::string mb = MolToPDBBlock(*m, -1, 32); delete m; m = PDBBlockToMol(mb); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 2501); TEST_ASSERT(m->getNumBonds() == 2383); TEST_ASSERT(m->getAtomWithIdx(0)->getMonomerInfo()); TEST_ASSERT(m->getAtomWithIdx(0)->getMonomerInfo()->getMonomerType() == AtomMonomerInfo::PDBRESIDUE); TEST_ASSERT(static_cast( m->getAtomWithIdx(0)->getMonomerInfo()) ->getSerialNumber() == 1); TEST_ASSERT(static_cast( m->getAtomWithIdx(0)->getMonomerInfo()) ->getResidueNumber() == 1); TEST_ASSERT(static_cast( m->getAtomWithIdx(0)->getMonomerInfo()) ->getIsHeteroAtom() == 0); // FIX: // TEST_ASSERT(static_cast(m->getAtomWithIdx(2292)->getMonomerInfo())->getSerialNumber()==2294); TEST_ASSERT(static_cast( m->getAtomWithIdx(2292)->getMonomerInfo()) ->getResidueNumber() == 299); TEST_ASSERT(static_cast( m->getAtomWithIdx(2292)->getMonomerInfo()) ->getIsHeteroAtom() == 1); TEST_ASSERT(static_cast( m->getAtomWithIdx(2292)->getMonomerInfo()) ->getChainId() == "A"); TEST_ASSERT(static_cast( m->getAtomWithIdx(1)->getMonomerInfo()) ->getName() == " CA "); TEST_ASSERT(static_cast( m->getAtomWithIdx(1)->getMonomerInfo()) ->getResidueName() == "MET"); TEST_ASSERT(static_cast( m->getAtomWithIdx(2292)->getMonomerInfo()) ->getName() == " N1 "); TEST_ASSERT(static_cast( m->getAtomWithIdx(2292)->getMonomerInfo()) ->getResidueName() == "LIA"); delete m; } { // DNA std::string fName; fName = rdbase + "4BNA.pdb"; ROMol *m = PDBFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumHeavyAtoms() == 602); TEST_ASSERT(m->getAtomWithIdx(0)->getMonomerInfo()); TEST_ASSERT(m->getAtomWithIdx(0)->getMonomerInfo()->getMonomerType() == AtomMonomerInfo::PDBRESIDUE); TEST_ASSERT(static_cast( m->getAtomWithIdx(0)->getMonomerInfo()) ->getSerialNumber() == 1); TEST_ASSERT(static_cast( m->getAtomWithIdx(1)->getMonomerInfo()) ->getResidueName() == " DC"); TEST_ASSERT(static_cast( m->getAtomWithIdx(57)->getMonomerInfo()) ->getResidueName() == " DG"); std::string mb = MolToPDBBlock(*m); delete m; m = PDBBlockToMol(mb); TEST_ASSERT(m->getNumHeavyAtoms() == 602); TEST_ASSERT(m->getAtomWithIdx(0)->getMonomerInfo()); TEST_ASSERT(m->getAtomWithIdx(0)->getMonomerInfo()->getMonomerType() == AtomMonomerInfo::PDBRESIDUE); TEST_ASSERT(static_cast( m->getAtomWithIdx(1)->getMonomerInfo()) ->getResidueName() == " DC"); TEST_ASSERT(static_cast( m->getAtomWithIdx(57)->getMonomerInfo()) ->getResidueName() == " DG"); TEST_ASSERT(m->getBondBetweenAtoms(31, 33)->getBondType() == Bond::AROMATIC); TEST_ASSERT(m->getBondBetweenAtoms(120, 114)->getBondType() == Bond::AROMATIC); TEST_ASSERT(m->getBondBetweenAtoms(39, 38)->getBondType() == Bond::DOUBLE); TEST_ASSERT(m->getBondBetweenAtoms(138, 140)->getBondType() == Bond::AROMATIC); delete m; } { // RNA std::string fName; fName = rdbase + "4TNA.pdb"; ROMol *m = PDBFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumHeavyAtoms() == 1656); TEST_ASSERT(m->getAtomWithIdx(0)->getMonomerInfo()); TEST_ASSERT(m->getAtomWithIdx(0)->getMonomerInfo()->getMonomerType() == AtomMonomerInfo::PDBRESIDUE); TEST_ASSERT(static_cast( m->getAtomWithIdx(0)->getMonomerInfo()) ->getSerialNumber() == 1); TEST_ASSERT(static_cast( m->getAtomWithIdx(1)->getMonomerInfo()) ->getResidueName() == " G"); TEST_ASSERT(static_cast( m->getAtomWithIdx(90)->getMonomerInfo()) ->getResidueName() == " A"); TEST_ASSERT(static_cast( m->getAtomWithIdx(197)->getMonomerInfo()) ->getResidueName() == "2MG"); TEST_ASSERT(static_cast( m->getAtomWithIdx(197)->getMonomerInfo()) ->getIsHeteroAtom()); TEST_ASSERT(m->getBondBetweenAtoms(104, 103)->getBondType() == Bond::AROMATIC); TEST_ASSERT(m->getBondBetweenAtoms(60, 61)->getBondType() == Bond::DOUBLE); TEST_ASSERT(m->getBondBetweenAtoms(38, 37)->getBondType() == Bond::DOUBLE); TEST_ASSERT(m->getBondBetweenAtoms(148, 149)->getBondType() == Bond::DOUBLE); std::string mb = MolToPDBBlock(*m); delete m; m = PDBBlockToMol(mb); TEST_ASSERT(m->getNumHeavyAtoms() == 1656); TEST_ASSERT(static_cast( m->getAtomWithIdx(0)->getMonomerInfo()) ->getSerialNumber() == 1); TEST_ASSERT(static_cast( m->getAtomWithIdx(1)->getMonomerInfo()) ->getResidueName() == " G"); TEST_ASSERT(static_cast( m->getAtomWithIdx(90)->getMonomerInfo()) ->getResidueName() == " A"); TEST_ASSERT(static_cast( m->getAtomWithIdx(197)->getMonomerInfo()) ->getResidueName() == "2MG"); TEST_ASSERT(static_cast( m->getAtomWithIdx(197)->getMonomerInfo()) ->getIsHeteroAtom()); delete m; } BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testSequences() { BOOST_LOG(rdInfoLog) << "testing reading sequences" << std::endl; { std::string seq = "CGCGAATTACCGCG"; // made up int flavor = 6; // DNA ROMol *m = SequenceToMol(seq, true, flavor); TEST_ASSERT(m); TEST_ASSERT(static_cast( m->getAtomWithIdx(0)->getMonomerInfo()) ->getSerialNumber() == 1); TEST_ASSERT(static_cast( m->getAtomWithIdx(1)->getMonomerInfo()) ->getResidueName() == " DC"); seq = MolToSequence(*m); TEST_ASSERT(seq == "CGCGAATTACCGCG"); seq = MolToHELM(*m); // std::cerr << seq << std::endl; TEST_ASSERT(seq == "RNA1{[dR](C)P.[dR](G)P.[dR](C)P.[dR](G)P.[dR](A)P.[dR](A)P.[" "dR](T)P.[dR](T)P.[dR](A)P.[dR](C)P.[dR](C)P.[dR](G)P.[dR](C)P." "[dR](G)}$$$$"); { std::string lseq = MolToHELM(*m); TEST_ASSERT(lseq == seq); ROMol *m2 = HELMToMol(seq); TEST_ASSERT(m2) lseq = MolToSequence(*m2); TEST_ASSERT(lseq == "CGCGAATTACCGCG"); lseq = MolToHELM(*m2); TEST_ASSERT(lseq == seq); delete m2; } { ROMol *nm = MolOps::addHs(*m); TEST_ASSERT(nm); std::string pdb = MolToPDBBlock(*nm); delete nm; nm = PDBBlockToMol(pdb); TEST_ASSERT(nm); std::string lseq = MolToSequence(*nm); TEST_ASSERT(lseq == "CGCGAATTACCGCG"); delete nm; } delete m; } { std::string seq = "CGCGAAUUACCGCG"; // made up int flavor = 2; // RNA ROMol *m = SequenceToMol(seq, true, flavor); TEST_ASSERT(m); TEST_ASSERT(static_cast( m->getAtomWithIdx(0)->getMonomerInfo()) ->getSerialNumber() == 1); TEST_ASSERT(static_cast( m->getAtomWithIdx(1)->getMonomerInfo()) ->getResidueName() == " C"); seq = MolToSequence(*m); TEST_ASSERT(seq == "CGCGAAUUACCGCG"); seq = MolToHELM(*m); TEST_ASSERT(seq == "RNA1{R(C)P.R(G)P.R(C)P.R(G)P.R(A)P.R(A)P.R(U)P.R(U)P.R(A)P.R(" "C)P.R(C)P.R(G)P.R(C)P.R(G)}$$$$"); { std::string lseq = MolToHELM(*m); TEST_ASSERT(lseq == seq); ROMol *m2 = HELMToMol(seq); TEST_ASSERT(m2) lseq = MolToSequence(*m2); TEST_ASSERT(lseq == "CGCGAAUUACCGCG"); lseq = MolToHELM(*m2); TEST_ASSERT(lseq == seq); delete m2; } { ROMol *nm = MolOps::addHs(*m); TEST_ASSERT(nm); std::string pdb = MolToPDBBlock(*nm); delete nm; nm = PDBBlockToMol(pdb); TEST_ASSERT(nm); std::string lseq = MolToSequence(*nm); TEST_ASSERT(lseq == "CGCGAAUUACCGCG"); delete nm; } delete m; } } void testGithub1023() { BOOST_LOG(rdInfoLog) << "GetSSSR interrupted by segmentation fault" << std::endl; std::string rdbase = getenv("RDBASE"); rdbase += "/Code/GraphMol/FileParsers/test_data/"; { std::string fName; fName = rdbase + "github1023.pdb"; bool sanitize = false; ROMol *m = PDBFileToMol(fName, sanitize); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 119); TEST_ASSERT(m->getNumBonds() == 399); MolOps::findSSSR(*m); // this was seg faulting delete m; } BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testGithub166() { BOOST_LOG(rdInfoLog) << "testing Github 166: skipping sanitization on reading pdb files" << std::endl; std::string rdbase = getenv("RDBASE"); rdbase += "/Code/GraphMol/FileParsers/test_data/"; { std::string fName; fName = rdbase + "1CRN.pdb"; ROMol *m = PDBFileToMol(fName, false, false); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 327); TEST_ASSERT(m->getNumBonds() == 337); delete m; } BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testZBO() { BOOST_LOG(rdInfoLog) << "testing ZBO parsing" << std::endl; std::string rdbase = getenv("RDBASE"); rdbase += "/Code/GraphMol/FileParsers/test_data/"; { std::string fName; fName = rdbase + "FeCO5.mol"; ROMol *m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 11); TEST_ASSERT(m->getNumBonds() == 10); TEST_ASSERT(m->getBondWithIdx(0)->getBondType() == Bond::ZERO); TEST_ASSERT(m->getBondWithIdx(1)->getBondType() == Bond::ZERO); TEST_ASSERT(m->getBondWithIdx(2)->getBondType() == Bond::ZERO); TEST_ASSERT(m->getBondWithIdx(6)->getBondType() == Bond::ZERO); TEST_ASSERT(m->getBondWithIdx(7)->getBondType() == Bond::ZERO); delete m; } { std::string fName; fName = rdbase + "CrBz.mol"; ROMol *m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 7); TEST_ASSERT(m->getNumBonds() == 12); TEST_ASSERT(m->getBondWithIdx(6)->getBondType() == Bond::ZERO); TEST_ASSERT(m->getBondWithIdx(7)->getBondType() == Bond::ZERO); TEST_ASSERT(m->getBondWithIdx(8)->getBondType() == Bond::ZERO); TEST_ASSERT(m->getBondWithIdx(9)->getBondType() == Bond::ZERO); TEST_ASSERT(m->getBondWithIdx(10)->getBondType() == Bond::ZERO); TEST_ASSERT(m->getBondWithIdx(11)->getBondType() == Bond::ZERO); // make sure we don't screw up aromaticity: TEST_ASSERT(m->getBondWithIdx(0)->getIsAromatic()); delete m; } { std::string fName; fName = rdbase + "CrBz2.mol"; ROMol *m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 13); TEST_ASSERT(m->getNumBonds() == 24); TEST_ASSERT(m->getBondWithIdx(6)->getBondType() == Bond::ZERO); TEST_ASSERT(m->getBondWithIdx(7)->getBondType() == Bond::ZERO); TEST_ASSERT(m->getBondWithIdx(8)->getBondType() == Bond::ZERO); TEST_ASSERT(m->getBondWithIdx(9)->getBondType() == Bond::ZERO); TEST_ASSERT(m->getBondWithIdx(10)->getBondType() == Bond::ZERO); TEST_ASSERT(m->getBondWithIdx(11)->getBondType() == Bond::ZERO); TEST_ASSERT(m->getBondWithIdx(18)->getBondType() == Bond::ZERO); TEST_ASSERT(m->getBondWithIdx(19)->getBondType() == Bond::ZERO); TEST_ASSERT(m->getBondWithIdx(20)->getBondType() == Bond::ZERO); TEST_ASSERT(m->getBondWithIdx(21)->getBondType() == Bond::ZERO); TEST_ASSERT(m->getBondWithIdx(22)->getBondType() == Bond::ZERO); TEST_ASSERT(m->getBondWithIdx(23)->getBondType() == Bond::ZERO); delete m; } { std::string fName; fName = rdbase + "H3BNH3.mol"; ROMol *m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 2); TEST_ASSERT(m->getNumBonds() == 1); TEST_ASSERT(m->getBondWithIdx(0)->getBondType() == Bond::ZERO); TEST_ASSERT(m->getAtomWithIdx(0)->getFormalCharge() == 0); TEST_ASSERT(m->getAtomWithIdx(1)->getFormalCharge() == 0); TEST_ASSERT(m->getAtomWithIdx(0)->getNumExplicitHs() == 3); TEST_ASSERT(m->getAtomWithIdx(1)->getNumExplicitHs() == 0); TEST_ASSERT(m->getAtomWithIdx(0)->getTotalNumHs() == 3); TEST_ASSERT(m->getAtomWithIdx(1)->getTotalNumHs() == 3); delete m; } BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testGithub164() { BOOST_LOG(rdInfoLog) << "testing Github 164: problems with Xe from mol files" << std::endl; std::string rdbase = getenv("RDBASE"); rdbase += "/Code/GraphMol/FileParsers/test_data/"; { std::string fName; fName = rdbase + "Github164.mol"; ROMol *m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 3); TEST_ASSERT(m->getNumBonds() == 2); TEST_ASSERT(m->getAtomWithIdx(0)->getValence(Atom::ValenceType::EXPLICIT) == 2); delete m; } BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testGithub194() { BOOST_LOG(rdInfoLog) << "testing github issue 194: bad bond types from pdb" << std::endl; std::string rdbase = getenv("RDBASE"); rdbase += "/Code/GraphMol/FileParsers/test_data/"; { std::string fName; fName = rdbase + "1CRN.pdb"; ROMol *m = PDBFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 327); TEST_ASSERT(m->getNumBonds() == 337); TEST_ASSERT(m->getAtomWithIdx(0)->getMonomerInfo()); TEST_ASSERT(m->getAtomWithIdx(0)->getMonomerInfo()->getMonomerType() == AtomMonomerInfo::PDBRESIDUE); // the root cause: problems in SamePDBResidue: TEST_ASSERT(SamePDBResidue(static_cast( m->getAtomWithIdx(0)->getMonomerInfo()), static_cast( m->getAtomWithIdx(1)->getMonomerInfo()))); TEST_ASSERT(SamePDBResidue(static_cast( m->getAtomWithIdx(0)->getMonomerInfo()), static_cast( m->getAtomWithIdx(2)->getMonomerInfo()))); TEST_ASSERT(!SamePDBResidue(static_cast( m->getAtomWithIdx(0)->getMonomerInfo()), static_cast( m->getAtomWithIdx(9)->getMonomerInfo()))); // the symptom, bond orders: TEST_ASSERT(static_cast( m->getAtomWithIdx(2)->getMonomerInfo()) ->getName() == " C "); TEST_ASSERT(static_cast( m->getAtomWithIdx(3)->getMonomerInfo()) ->getName() == " O "); TEST_ASSERT(m->getBondBetweenAtoms(2, 3)); TEST_ASSERT(m->getBondBetweenAtoms(2, 3)->getBondType() == Bond::DOUBLE); delete m; } BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testGithub196() { BOOST_LOG(rdInfoLog) << "testing github issue 196: left justified bond topology" << std::endl; std::string rdbase = getenv("RDBASE"); rdbase += "/Code/GraphMol/FileParsers/test_data/"; { std::string fName; fName = rdbase + "github196.mol"; ROMol *m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 19); TEST_ASSERT(m->getNumBonds() == 20); delete m; } BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testGithub191() { BOOST_LOG(rdInfoLog) << "-----------------------\n Testing github issue 191: " "wavy bonds to Hs should affect attached double bond " "stereochemistry." << std::endl; { std::string pathName = getenv("RDBASE"); pathName += "/Code/GraphMol/FileParsers/test_data/"; RWMol *m = MolFileToMol(pathName + "github191.1.mol"); TEST_ASSERT(m); TEST_ASSERT(m->getBondWithIdx(0)->getBondType() == Bond::DOUBLE); TEST_ASSERT(m->getBondWithIdx(0)->getStereo() == Bond::STEREOE); std::string smi = MolToSmiles(*m, true); TEST_ASSERT(smi == "C/C=C/C"); delete m; } { std::string pathName = getenv("RDBASE"); pathName += "/Code/GraphMol/FileParsers/test_data/"; RWMol *m = MolFileToMol(pathName + "github191.2.mol"); TEST_ASSERT(m); TEST_ASSERT(m->getBondWithIdx(0)->getBondType() == Bond::DOUBLE); TEST_ASSERT(m->getBondWithIdx(0)->getStereo() == Bond::STEREOANY); std::string smi = MolToSmiles(*m, true); TEST_ASSERT(smi == "CC=CC"); delete m; } BOOST_LOG(rdInfoLog) << "Finished" << std::endl; } void testGithub210() { BOOST_LOG(rdInfoLog) << "-------------------------------------" << std::endl; BOOST_LOG(rdInfoLog) << "Testing Github 210: flag possible stereocenters " "when calling assignStereochemistry()" << std::endl; { std::string pathName = getenv("RDBASE"); pathName += "/Code/GraphMol/FileParsers/test_data/"; RWMol *m = MolFileToMol(pathName + "github210.mol"); TEST_ASSERT(m); TEST_ASSERT(m->getAtomWithIdx(1)->hasProp(common_properties::_CIPCode)); TEST_ASSERT( m->getAtomWithIdx(4)->hasProp(common_properties::_ChiralityPossible)); delete m; } BOOST_LOG(rdInfoLog) << "Finished" << std::endl; } namespace { std::string getResidue(const ROMol &, const Atom *at) { if (at->getMonomerInfo()->getMonomerType() != AtomMonomerInfo::PDBRESIDUE) { return ""; } return static_cast(at->getMonomerInfo()) ->getResidueName(); } } // namespace void testPDBResidues() { BOOST_LOG(rdInfoLog) << "testing splitting on PDB residues" << std::endl; std::string rdbase = getenv("RDBASE"); rdbase += "/Code/GraphMol/FileParsers/test_data/"; { std::string fName; fName = rdbase + "2NW4.pdb"; ROMol *m = PDBFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getAtomWithIdx(0)->getMonomerInfo()->getMonomerType() == AtomMonomerInfo::PDBRESIDUE); std::map> res = MolOps::getMolFragsWithQuery(*m, getResidue, false); TEST_ASSERT(res.size() == 22); TEST_ASSERT(res.find(std::string("8NH")) != res.end()); TEST_ASSERT(res.find(std::string("ALA")) != res.end()); TEST_ASSERT(res[std::string("8NH")]->getNumAtoms() == 21); const ROMol *lig = res[std::string("8NH")].get(); TEST_ASSERT(lig->getNumConformers() == 1); TEST_ASSERT(feq(lig->getConformer().getAtomPos(0).x, 23.517)); TEST_ASSERT(feq(lig->getConformer().getAtomPos(0).y, 5.263)); TEST_ASSERT(feq(lig->getConformer().getAtomPos(0).z, 4.399)); TEST_ASSERT(feq(lig->getConformer().getAtomPos(11).x, 27.589)); TEST_ASSERT(feq(lig->getConformer().getAtomPos(11).y, -0.311)); TEST_ASSERT(feq(lig->getConformer().getAtomPos(11).z, 3.743)); delete m; } { std::string fName; fName = rdbase + "2NW4.pdb"; ROMol *m = PDBFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getAtomWithIdx(0)->getMonomerInfo()->getMonomerType() == AtomMonomerInfo::PDBRESIDUE); std::vector keep; keep.emplace_back("8NH"); std::map> res = MolOps::getMolFragsWithQuery(*m, getResidue, false, &keep); TEST_ASSERT(res.size() == 1); TEST_ASSERT(res.find(std::string("8NH")) != res.end()); TEST_ASSERT(res[std::string("8NH")]->getNumAtoms() == 21); const ROMol *lig = res[std::string("8NH")].get(); TEST_ASSERT(lig->getNumConformers() == 1); TEST_ASSERT(feq(lig->getConformer().getAtomPos(0).x, 23.517)); TEST_ASSERT(feq(lig->getConformer().getAtomPos(0).y, 5.263)); TEST_ASSERT(feq(lig->getConformer().getAtomPos(0).z, 4.399)); TEST_ASSERT(feq(lig->getConformer().getAtomPos(11).x, 27.589)); TEST_ASSERT(feq(lig->getConformer().getAtomPos(11).y, -0.311)); TEST_ASSERT(feq(lig->getConformer().getAtomPos(11).z, 3.743)); delete m; } { std::string fName; fName = rdbase + "2NW4.pdb"; ROMol *m = PDBFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getAtomWithIdx(0)->getMonomerInfo()->getMonomerType() == AtomMonomerInfo::PDBRESIDUE); std::vector keep; keep.emplace_back("8NH"); std::map> res = MolOps::getMolFragsWithQuery(*m, getResidue, false, &keep, true); TEST_ASSERT(res.size() == 21); TEST_ASSERT(res.find(std::string("8NH")) == res.end()); TEST_ASSERT(res.find(std::string("ALA")) != res.end()); delete m; } BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testGithub337() { BOOST_LOG(rdInfoLog) << "-------------------------------------" << std::endl; BOOST_LOG(rdInfoLog) << "Testing Github 337: No double bond stereo " "perception from CTABs when sanitization is turned " "off" << std::endl; { std::string pathName = getenv("RDBASE"); pathName += "/Code/GraphMol/FileParsers/test_data/"; RWMol *m = MolFileToMol(pathName + "unsanitized_stereo.mol", false); TEST_ASSERT(m); TEST_ASSERT(m->getBondWithIdx(0)->getStereo() == Bond::STEREONONE); std::string molBlock = MolToMolBlock(*m); TEST_ASSERT(molBlock.find(" 1 2 2 0") != std::string::npos); delete m; } BOOST_LOG(rdInfoLog) << "Finished" << std::endl; } void testGithub360() { BOOST_LOG(rdInfoLog) << "-------------------------------------" << std::endl; BOOST_LOG(rdInfoLog) << "Testing Github 360: Computed props on non-sanitized " "molecule interfering with substructure matching" << std::endl; { std::string pathName = getenv("RDBASE"); pathName += "/Code/GraphMol/FileParsers/test_data/"; RWMol *dbm = SmilesToMol("C1Cc2ccccc2CN1"); TEST_ASSERT(dbm); RWMol *tmpl = MolFileToMol(pathName + "github360.mol", false); TEST_ASSERT(tmpl); MatchVectType mv; TEST_ASSERT(SubstructMatch(*dbm, *tmpl, mv)); delete dbm; delete tmpl; } BOOST_LOG(rdInfoLog) << "Finished" << std::endl; } void testGithub741() { BOOST_LOG(rdInfoLog) << "-------------------------------------" << std::endl; BOOST_LOG(rdInfoLog) << "Testing Github 741: Support CTABs where the second " "letter in atom symbols is capitalized" << std::endl; { std::string pathName = getenv("RDBASE"); pathName += "/Code/GraphMol/FileParsers/test_data/"; RWMol *mol = MolFileToMol(pathName + "github741.mol"); TEST_ASSERT(mol); TEST_ASSERT(mol->getAtomWithIdx(1)->getSymbol() == "Br"); TEST_ASSERT(mol->getAtomWithIdx(2)->getSymbol() == "Br"); delete mol; } { std::string pathName = getenv("RDBASE"); pathName += "/Code/GraphMol/FileParsers/test_data/"; RWMol *mol = MolFileToMol(pathName + "github741.v3k.mol"); TEST_ASSERT(mol); TEST_ASSERT(mol->getAtomWithIdx(1)->getSymbol() == "Br"); TEST_ASSERT(mol->getAtomWithIdx(2)->getSymbol() == "Br"); delete mol; } BOOST_LOG(rdInfoLog) << "Finished" << std::endl; } void testGithub188() { BOOST_LOG(rdInfoLog) << "-------------------------------------" << std::endl; BOOST_LOG(rdInfoLog) << "Testing Github 188: Bad E/Z assignment from CTAB" << std::endl; { std::string pathName = getenv("RDBASE"); pathName += "/Code/GraphMol/FileParsers/test_data/"; RWMol *mol = MolFileToMol(pathName + "github188.mol"); TEST_ASSERT(mol); TEST_ASSERT(mol->getBondBetweenAtoms(16, 17)); TEST_ASSERT(mol->getBondBetweenAtoms(16, 17)->getStereo() == Bond::STEREOZ); TEST_ASSERT(mol->getBondBetweenAtoms(13, 14)); TEST_ASSERT(mol->getBondBetweenAtoms(13, 14)->getStereo() == Bond::STEREOZ); delete mol; } { std::cerr << "----------------------------------" << std::endl; std::string pathName = getenv("RDBASE"); pathName += "/Code/GraphMol/FileParsers/test_data/"; RWMol *mol = MolFileToMol(pathName + "github188_2.mol"); TEST_ASSERT(mol); TEST_ASSERT(mol->getBondBetweenAtoms(16, 17)); TEST_ASSERT(mol->getBondBetweenAtoms(16, 17)->getStereo() == Bond::STEREOZ); TEST_ASSERT(mol->getBondBetweenAtoms(13, 14)); TEST_ASSERT(mol->getBondBetweenAtoms(13, 14)->getStereo() == Bond::STEREOZ); delete mol; } { std::cerr << "----------------------------------" << std::endl; std::string pathName = getenv("RDBASE"); pathName += "/Code/GraphMol/FileParsers/test_data/"; RWMol *mol = MolFileToMol(pathName + "github192.mol"); TEST_ASSERT(mol); for (unsigned int i = 0; i < mol->getNumBonds(); ++i) { const Bond *bnd = mol->getBondWithIdx(i); if (bnd->getBondType() == Bond::DOUBLE && i != mol->getBondBetweenAtoms(26, 27)->getIdx() && i != mol->getBondBetweenAtoms(6, 8)->getIdx()) { TEST_ASSERT(bnd->getStereo() == Bond::STEREOE); } } delete mol; } BOOST_LOG(rdInfoLog) << "Finished" << std::endl; } void testRCSBSdf() { BOOST_LOG(rdInfoLog) << "-------------------------------------" << std::endl; BOOST_LOG(rdInfoLog) << "Testing right-aligned elements in RCSB SDF files" << std::endl; std::string pathName = getenv("RDBASE"); pathName += "/Code/GraphMol/FileParsers/test_data/"; RWMol *mol = MolFileToMol(pathName + "s58_rcsb.mol"); TEST_ASSERT(mol); delete mol; BOOST_LOG(rdInfoLog) << "Finished" << std::endl; } void testParseCHG() { BOOST_LOG(rdInfoLog) << "-------------------------------------" << std::endl; BOOST_LOG(rdInfoLog) << "Testing PDB charge parsing" << std::endl; // BAD PDB Ligand with CHG line too long (>8) and right and mid-justified // symbols const std::string molblock_chg = "2D1G_DVT_B_2001\n" " RCSB PDB01151500373D\n" "Coordinates from PDB:2D1G:B:2001 Model:1 without hydrogens\n" " 38 60 0 0 0 0 999 V2000\n" " 19.0320 93.5880 16.2640 O 0 5 0 0 0 0 0 0 0 0 0 0\n" " 19.6400 94.8240 15.4350 V 0 5 0 0 0 0 0 0 0 0 0 0\n" " 18.1700 95.2990 14.2790 O 0 0 0 0 0 0 0 0 0 0 0 0\n" " 19.6000 96.2720 16.5920 O 0 0 0 0 0 0 0 0 0 0 0 0\n" " 20.3140 97.8870 15.9210 V 0 5 0 0 0 0 0 0 0 0 0 0\n" " 20.1880 98.9370 17.1150 O 0 5 0 0 0 0 0 0 0 0 0 0\n" " 21.5140 94.4720 15.5850 O 0 0 0 0 0 0 0 0 0 0 0 0\n" " 22.5590 95.9150 15.0470 V 0 5 0 0 0 0 0 0 0 0 0 0\n" " 20.6050 96.4040 14.1390 O 0 0 0 0 0 0 0 0 0 0 0 0\n" " 22.1700 97.4330 15.9940 O 0 0 0 0 0 0 0 0 0 0 0 0\n" " 23.1150 97.3160 13.7160 O 0 3 0 0 0 0 0 0 0 0 0 0\n" " 23.9960 95.5550 15.6610 O 0 5 0 0 0 0 0 0 0 0 0 0\n" " 22.6470 94.8660 13.3320 O 0 3 0 0 0 0 0 0 0 0 0 0\n" " 23.7710 96.1210 12.1910 V 0 5 0 0 0 0 0 0 0 0 0 0\n" " 24.0950 97.6940 11.3470 O 0 0 0 0 0 0 0 0 0 0 0 0\n" " 25.2350 95.8110 12.7760 O 0 5 0 0 0 0 0 0 0 0 0 0\n" " 23.5040 94.7850 10.9890 O 0 0 0 0 0 0 0 0 0 0 0 0\n" " 22.0160 95.1170 9.8340 V 0 5 0 0 0 0 0 0 0 0 0 0\n" " 20.1580 95.5900 9.6670 O 0 0 0 0 0 0 0 0 0 0 0 0\n" " 22.2300 94.0400 8.6680 O 0 5 0 0 0 0 0 0 0 0 0 0\n" " 22.6710 96.7240 9.1340 O 0 0 0 0 0 0 0 0 0 0 0 0\n" " 20.8370 94.9790 12.6510 V 0 5 0 0 0 0 0 0 0 0 0 0\n" " 21.1160 93.9980 11.2840 O 0 0 0 0 0 0 0 0 0 0 0 0\n" " 20.1410 93.8410 13.6860 O 0 0 0 0 0 0 0 0 0 0 0 0\n" " 21.6740 96.5770 11.6070 O 0 0 0 0 0 0 0 0 0 0 0 0\n" " 22.5990 98.1610 10.2810 V 0 5 0 0 0 0 0 0 0 0 0 0\n" " 23.1590 99.4050 9.4060 O 0 5 0 0 0 0 0 0 0 0 0 0\n" " 22.1350 99.1410 12.0500 O 0 0 0 0 0 0 0 0 0 0 0 0\n" " 21.4440 98.0120 13.0890 V 0 5 0 0 0 0 0 0 0 0 0 0\n" " 21.1330 99.0140 14.4480 O 0 0 0 0 0 0 0 0 0 0 0 0\n" " 19.1670 95.7180 12.0250 O 0 3 0 0 0 0 0 0 0 0 0 0\n" " 19.7240 97.0880 10.6480 V 0 5 0 0 0 0 0 0 0 0 0 0\n" " 20.7360 98.5460 10.1630 O 0 0 0 0 0 0 0 0 0 0 0 0\n" " 18.2530 97.4600 10.0390 O 0 5 0 0 0 0 0 0 0 0 0 0\n" " 19.6430 98.1340 12.3760 O 0 3 0 0 0 0 0 0 0 0 0 0\n" " 18.5370 96.9390 13.5530 V 0 5 0 0 0 0 0 0 0 0 0 0\n" " 18.8160 98.2640 14.7770 O 0 0 0 0 0 0 0 0 0 0 0 0\n" " 17.0530 97.2880 13.0100 O 0 5 0 0 0 0 0 0 0 0 0 0\n" " 1 2 1 0 0 0 0\n" " 2 3 1 0 0 0 0\n" " 2 4 1 0 0 0 0\n" " 2 7 1 0 0 0 0\n" " 2 9 1 0 0 0 0\n" " 2 24 1 0 0 0 0\n" " 3 36 1 0 0 0 0\n" " 4 5 1 0 0 0 0\n" " 5 6 1 0 0 0 0\n" " 5 9 1 0 0 0 0\n" " 5 10 1 0 0 0 0\n" " 5 30 1 0 0 0 0\n" " 5 37 1 0 0 0 0\n" " 7 8 1 0 0 0 0\n" " 8 9 1 0 0 0 0\n" " 8 10 1 0 0 0 0\n" " 8 11 1 0 0 0 0\n" " 8 12 1 0 0 0 0\n" " 8 13 1 0 0 0 0\n" " 9 22 1 0 0 0 0\n" " 9 29 1 0 0 0 0\n" " 9 36 1 0 0 0 0\n" " 11 14 1 0 0 0 0\n" " 11 29 1 0 0 0 0\n" " 13 14 1 0 0 0 0\n" " 13 22 1 0 0 0 0\n" " 14 15 1 0 0 0 0\n" " 14 16 1 0 0 0 0\n" " 14 17 1 0 0 0 0\n" " 14 28 1 0 0 0 0\n" " 15 26 1 0 0 0 0\n" " 17 18 1 0 0 0 0\n" " 18 19 1 0 0 0 0\n" " 18 20 1 0 0 0 0\n" " 18 21 1 0 0 0 0\n" " 18 23 1 0 0 0 0\n" " 18 28 1 0 0 0 0\n" " 19 32 1 0 0 0 0\n" " 21 26 1 0 0 0 0\n" " 22 23 1 0 0 0 0\n" " 22 24 1 0 0 0 0\n" " 22 28 1 0 0 0 0\n" " 22 31 1 0 0 0 0\n" " 25 26 1 0 0 0 0\n" " 25 29 1 0 0 0 0\n" " 26 27 1 0 0 0 0\n" " 26 28 1 0 0 0 0\n" " 26 33 1 0 0 0 0\n" " 28 29 1 0 0 0 0\n" " 28 32 1 0 0 0 0\n" " 29 30 1 0 0 0 0\n" " 29 35 1 0 0 0 0\n" " 31 32 1 0 0 0 0\n" " 31 36 1 0 0 0 0\n" " 32 33 1 0 0 0 0\n" " 32 34 1 0 0 0 0\n" " 32 35 1 0 0 0 0\n" " 35 36 1 0 0 0 0\n" " 36 37 1 0 0 0 0\n" " 36 38 1 0 0 0 0\n" "M CHG 24 1 -1 2 -1 5 -1 6 -1 8 -1 9 4 11 1 12 " "-1 13 1 14 -1 16 -1 18 -1 20 -1 22 -1 26 -1 27 -1 28 " " 4 29 -1 31 1 32 -1 34 -1 35 1 36 -1 38 -1\n" "M END\n"; const int charges[] = {1, -1, 2, -1, 5, -1, 6, -1, 8, -1, 9, 4, 11, 1, 12, -1, 13, 1, 14, -1, 16, -1, 18, -1, 20, -1, 22, -1, 26, -1, 27, -1, 28, 4, 29, -1, 31, 1, 32, -1, 34, -1, 35, 1, 36, -1, 38, -1, 0, 0}; // Shouldn't seg fault, throw exception or have a null mol bool sanitize = false; std::unique_ptr m(MolBlockToMol(molblock_chg, sanitize)); size_t i = 0; while (1) { if (charges[i] == 0) { break; } TEST_ASSERT( m->getAtomWithIdx((unsigned int)charges[i] - 1)->getFormalCharge() == charges[i + 1]); i += 2; } TEST_ASSERT(m); // Write it out in V3000 format, which makes counting the different charges // easier bool forceV3000(true); std::string out = MolToMolBlock(*m, true, -1, true, forceV3000); std::regex chg_all("CHG="), chg_m1("CHG=-1"), chg_p1("CHG=1"), chg_p4("CHG=4"); TEST_ASSERT( std::distance(std::sregex_iterator(out.begin(), out.end(), chg_all), std::sregex_iterator()) == 24); TEST_ASSERT( std::distance(std::sregex_iterator(out.begin(), out.end(), chg_m1), std::sregex_iterator()) == 18); TEST_ASSERT( std::distance(std::sregex_iterator(out.begin(), out.end(), chg_p1), std::sregex_iterator()) == 4); TEST_ASSERT( std::distance(std::sregex_iterator(out.begin(), out.end(), chg_p4), std::sregex_iterator()) == 2); BOOST_LOG(rdInfoLog) << "Finished" << std::endl; } void testMDLAtomProps() { BOOST_LOG(rdInfoLog) << "-------------------------------------" << std::endl; BOOST_LOG(rdInfoLog) << "Testing MDL atom properties" << std::endl; std::string smi = "CC"; ROMOL_SPTR mol(SmilesToMol(smi, false, false)); setAtomAlias(mol->getAtomWithIdx(0), "foo"); setAtomValue(mol->getAtomWithIdx(0), "bar"); setAtomRLabel(mol->getAtomWithIdx(0), 1); mol.reset(MolBlockToMol(MolToMolBlock(*mol.get()))); TEST_ASSERT(getAtomAlias(mol->getAtomWithIdx(0)) == "foo"); TEST_ASSERT(getAtomValue(mol->getAtomWithIdx(0)) == "bar"); TEST_ASSERT(getAtomRLabel(mol->getAtomWithIdx(0)) == 1); try { setAtomRLabel(mol->getAtomWithIdx(0), 100); TEST_ASSERT(0); } catch (...) { } BOOST_LOG(rdInfoLog) << "Finished" << std::endl; } void testSupplementalSmilesLabel() { BOOST_LOG(rdInfoLog) << "-------------------------------------" << std::endl; BOOST_LOG(rdInfoLog) << "Testing supplemental SMILES labels" << std::endl; std::string smi = "C"; ROMOL_SPTR mol(SmilesToMol(smi, false, false)); setSupplementalSmilesLabel(mol->getAtomWithIdx(0), "xxx"); smi = MolToSmiles(*mol.get()); TEST_ASSERT(smi == "Cxxx"); TEST_ASSERT(getSupplementalSmilesLabel(mol->getAtomWithIdx(0)) == "xxx"); BOOST_LOG(rdInfoLog) << "Finished" << std::endl; } void testGithub1034() { BOOST_LOG(rdInfoLog) << "Test github 1034: Squiggle bonds from CTABs lost post-parsing" << std::endl; std::string rdbase = getenv("RDBASE"); rdbase += "/Code/GraphMol/FileParsers/test_data/"; { // double bond std::string fName; fName = rdbase + "github1034.1.mol"; bool sanitize = true; RWMol *m = MolFileToMol(fName, sanitize); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 4); TEST_ASSERT(m->getBondWithIdx(0)->getBondType() == Bond::DOUBLE); TEST_ASSERT(m->getBondWithIdx(0)->getStereo() == Bond::STEREOANY); TEST_ASSERT(m->getBondWithIdx(1)->getBondType() == Bond::SINGLE); TEST_ASSERT(m->getBondWithIdx(2)->getBondType() == Bond::SINGLE); TEST_ASSERT(m->getBondWithIdx(2)->getBondDir() != Bond::UNKNOWN); TEST_ASSERT( m->getBondWithIdx(2)->hasProp(common_properties::_UnknownStereo)); delete m; } { // double bond std::string fName; fName = rdbase + "github1034.1.mol"; bool sanitize = false; RWMol *m = MolFileToMol(fName, sanitize); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 4); TEST_ASSERT(m->getBondWithIdx(2)->getBondType() == Bond::SINGLE); TEST_ASSERT(m->getBondWithIdx(2)->getBondDir() != Bond::UNKNOWN); int explicit_unknown_stereo; TEST_ASSERT( m->getBondWithIdx(2)->getPropIfPresent( common_properties::_UnknownStereo, explicit_unknown_stereo) && explicit_unknown_stereo) TEST_ASSERT(m->getBondWithIdx(0)->getBondType() == Bond::DOUBLE); TEST_ASSERT(m->getBondWithIdx(0)->getStereo() == Bond::STEREOANY); // now set in detectStereochemistry ROMol(*m).getBondWithIdx(0)->setStereo( Bond::STEREOCIS); // ensure we have stereo atoms MolOps::sanitizeMol(*m); TEST_ASSERT(m->getBondWithIdx(0)->getBondType() == Bond::DOUBLE); TEST_ASSERT(m->getBondWithIdx(0)->getStereo() == Bond::STEREOANY); TEST_ASSERT(m->getBondWithIdx(1)->getBondType() == Bond::SINGLE); TEST_ASSERT(m->getBondWithIdx(1)->getBondDir() == Bond::NONE); TEST_ASSERT(m->getBondWithIdx(2)->getBondType() == Bond::SINGLE); TEST_ASSERT(m->getBondWithIdx(2)->getBondDir() != Bond::UNKNOWN); MolOps::assignStereochemistry(*m, true, true); TEST_ASSERT(m->getBondWithIdx(0)->getStereo() == Bond::STEREOANY); delete m; } { // chiral center std::string fName; fName = rdbase + "github1034.2.mol"; bool sanitize = true; RWMol *m = MolFileToMol(fName, sanitize); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 5); TEST_ASSERT(m->getAtomWithIdx(0)->getChiralTag() == Atom::CHI_UNSPECIFIED); TEST_ASSERT(m->getBondWithIdx(3)->getBondType() == Bond::SINGLE); TEST_ASSERT(m->getBondWithIdx(3)->getBondDir() == Bond::NONE); TEST_ASSERT( m->getBondWithIdx(3)->hasProp(common_properties::_UnknownStereo)); delete m; } { // chiral center std::string fName; fName = rdbase + "github1034.2.mol"; bool sanitize = false; RWMol *m = MolFileToMol(fName, sanitize); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 5); TEST_ASSERT(m->getBondWithIdx(3)->getBondType() == Bond::SINGLE); TEST_ASSERT(m->getBondWithIdx(3)->getBondDir() != Bond::UNKNOWN); int explicit_unknown_stereo; TEST_ASSERT( m->getBondWithIdx(3)->getPropIfPresent( common_properties::_UnknownStereo, explicit_unknown_stereo) && explicit_unknown_stereo) MolOps::sanitizeMol(*m); TEST_ASSERT(m->getBondWithIdx(3)->getBondType() == Bond::SINGLE); TEST_ASSERT(m->getBondWithIdx(3)->getBondDir() != Bond::UNKNOWN); TEST_ASSERT(m->getAtomWithIdx(0)->getChiralTag() == Atom::CHI_UNSPECIFIED); delete m; } BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testGithub1049() { BOOST_LOG(rdInfoLog) << "Test github 1049: MolOps::cleanUp() being called by " "CTAB parser even when sanitization isn't on" << std::endl; std::string rdbase = getenv("RDBASE"); rdbase += "/Code/GraphMol/FileParsers/test_data/"; { // no stereo (this one worked before) std::string fName; fName = rdbase + "github1049.1.mol"; bool sanitize = false; RWMol *m = MolFileToMol(fName, sanitize); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 7); TEST_ASSERT(m->getAtomWithIdx(1)->getAtomicNum() == 7); TEST_ASSERT(m->getAtomWithIdx(1)->getFormalCharge() == 0); TEST_ASSERT(m->getAtomWithIdx(2)->getAtomicNum() == 8); TEST_ASSERT(m->getAtomWithIdx(2)->getFormalCharge() == 0); TEST_ASSERT(m->getAtomWithIdx(3)->getAtomicNum() == 8); TEST_ASSERT(m->getAtomWithIdx(3)->getFormalCharge() == 0); MolOps::sanitizeMol(*m); TEST_ASSERT(m->getAtomWithIdx(1)->getFormalCharge() == 1); TEST_ASSERT((m->getAtomWithIdx(2)->getFormalCharge() == -1 && m->getAtomWithIdx(3)->getFormalCharge() == 0) || (m->getAtomWithIdx(2)->getFormalCharge() == 0 && m->getAtomWithIdx(3)->getFormalCharge() == -1)); delete m; } { // with stereo (this one did not work) std::string fName; fName = rdbase + "github1049.2.mol"; bool sanitize = false; RWMol *m = MolFileToMol(fName, sanitize); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 7); TEST_ASSERT(m->getAtomWithIdx(1)->getAtomicNum() == 7); TEST_ASSERT(m->getAtomWithIdx(1)->getFormalCharge() == 0); TEST_ASSERT(m->getAtomWithIdx(2)->getAtomicNum() == 8); TEST_ASSERT(m->getAtomWithIdx(2)->getFormalCharge() == 0); TEST_ASSERT(m->getAtomWithIdx(3)->getAtomicNum() == 8); TEST_ASSERT(m->getAtomWithIdx(3)->getFormalCharge() == 0); MolOps::sanitizeMol(*m); TEST_ASSERT(m->getAtomWithIdx(1)->getFormalCharge() == 1); TEST_ASSERT((m->getAtomWithIdx(2)->getFormalCharge() == -1 && m->getAtomWithIdx(3)->getFormalCharge() == 0) || (m->getAtomWithIdx(2)->getFormalCharge() == 0 && m->getAtomWithIdx(3)->getFormalCharge() == -1)); delete m; } BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testMolFileDativeBonds() { BOOST_LOG(rdInfoLog) << "Test MDL molfiles with dative bonds (V3000 only)" << std::endl; std::string rdbase = getenv("RDBASE"); rdbase += "/Code/GraphMol/FileParsers/test_data/"; // Read molfiles with dative bonds. { std::string fName = rdbase + "dative_bonds_one.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumBonds() == 5); TEST_ASSERT(m->getBondWithIdx(4)->getBondType() == Bond::DATIVE); std::string smiles = MolToSmiles(*m); TEST_ASSERT(smiles == "CCC(=O)[OH]->[Cu]"); delete m; } { std::string fName = rdbase + "dative_bonds_two.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumBonds() == 10); TEST_ASSERT(m->getBondWithIdx(8)->getBondType() == Bond::DATIVE); TEST_ASSERT(m->getBondWithIdx(9)->getBondType() == Bond::DATIVE); std::string smiles = MolToSmiles(*m); TEST_ASSERT(smiles == "CCC(=O)[OH]->[Cu]<-[OH]C(O)CC"); delete m; } { std::string fName = rdbase + "DativeBond2000.mol"; RWMol *m = MolFileToMol(fName, false); TEST_ASSERT(m); TEST_ASSERT(m->getNumBonds() == 5); TEST_ASSERT(m->getBondWithIdx(4)->getBondType() == Bond::DATIVE); std::string smiles = MolToSmiles(*m); TEST_ASSERT(smiles == "C[CH2](C)->[Mg]([Cl])[Cl]"); delete m; } BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testGithub1251() { BOOST_LOG(rdInfoLog) << "Test github 1251: MolFromMolBlock sanitizing when it should not be" << std::endl; std::string rdbase = getenv("RDBASE"); rdbase += "/Code/GraphMol/FileParsers/test_data/"; { std::string fName = rdbase + "github1251.mol"; RWMol *m = MolFileToMol(fName, false); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 39); TEST_ASSERT(m->getNumBonds() == 44); delete m; } BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testGithub1029() { BOOST_LOG(rdInfoLog) << "Test github 1029: PDB reader fails for arginine explicit hydrogens " << std::endl; std::string rdbase = getenv("RDBASE"); rdbase += "/Code/GraphMol/FileParsers/test_data/"; { // the original bug report std::string fName = rdbase + "github1029.1.pdb"; bool sanitize = true, removeHs = false; ROMol *m = PDBFileToMol(fName, sanitize, removeHs); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 3268); TEST_ASSERT(m->getNumBonds() == 3302); TEST_ASSERT( m->getAtomWithIdx(121)->getValence(Atom::ValenceType::EXPLICIT) == 4); TEST_ASSERT(m->getAtomWithIdx(121)->getFormalCharge() == 1); delete m; } { // a second report that came in std::string fName = rdbase + "github1029.1jld_chaina.pdb"; bool sanitize = false, removeHs = false; ROMol *m = PDBFileToMol(fName, sanitize, removeHs); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 1533); TEST_ASSERT(m->getNumBonds() == 1545); TEST_ASSERT( m->getAtomWithIdx(123)->getValence(Atom::ValenceType::EXPLICIT) == 4); TEST_ASSERT(m->getAtomWithIdx(123)->getFormalCharge() == 1); delete m; } BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testGithub1340() { BOOST_LOG(rdInfoLog) << "Test github 1340: PDB parser creating H-H bonds " << std::endl; std::string rdbase = getenv("RDBASE"); rdbase += "/Code/GraphMol/FileParsers/test_data/"; { // a second report that came in std::string fName = rdbase + "github1340.1jld_snip.pdb"; bool sanitize = true, removeHs = false; ROMol *m = PDBFileToMol(fName, sanitize, removeHs); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 37); TEST_ASSERT(m->getNumBonds() == 35); TEST_ASSERT(m->getAtomWithIdx(10)->getAtomicNum() == 1); TEST_ASSERT(m->getAtomWithIdx(34)->getAtomicNum() == 1); RDGeom::Point3D p10 = m->getConformer().getAtomPos(10); RDGeom::Point3D p34 = m->getConformer().getAtomPos(34); TEST_ASSERT((p34 - p10).length() < 1.0); TEST_ASSERT(!m->getBondBetweenAtoms(10, 34)); delete m; } BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testMolBlockChirality() { BOOST_LOG(rdInfoLog) << "Test automatic generation of coordinates for mol block chirality " << std::endl; { std::string smi = "C[C@H](Cl)Br"; auto mol = SmilesToMol(smi); TEST_ASSERT(mol); auto mb = MolToMolBlock(*mol, true); auto mol2 = MolBlockToMol(mb); TEST_ASSERT(mol2); auto csmi1 = MolToSmiles(*mol, true); auto csmi2 = MolToSmiles(*mol2, true); TEST_ASSERT(csmi1.find("@") != std::string::npos); TEST_ASSERT(csmi1 == csmi2); delete mol; delete mol2; } BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testMolBlock3DStereochem() { BOOST_LOG(rdInfoLog) << "Test automatic perception of stereochem from 3D structure " << std::endl; std::string rdbase = getenv("RDBASE"); rdbase += "/Code/GraphMol/FileParsers/test_data/"; { std::string fName = rdbase + "stereo3d_1.mol"; auto m1 = MolFileToMol(fName); TEST_ASSERT(m1); std::string smi = "F[C@](Cl)(Br)I"; auto m2 = SmilesToMol(smi); TEST_ASSERT(m2); auto csmi1 = MolToSmiles(*m1, true); auto csmi2 = MolToSmiles(*m2, true); TEST_ASSERT(csmi1.find("@") != std::string::npos); TEST_ASSERT(csmi1 == csmi2); delete m1; delete m2; } { std::string fName = rdbase + "stereo3d_2.mol"; auto m1 = MolFileToMol(fName); TEST_ASSERT(m1); std::string smi = "F[C@@](Cl)(Br)I"; auto m2 = SmilesToMol(smi); TEST_ASSERT(m2); auto csmi1 = MolToSmiles(*m1, true); auto csmi2 = MolToSmiles(*m2, true); TEST_ASSERT(csmi1.find("@") != std::string::npos); TEST_ASSERT(csmi1 == csmi2); delete m1; delete m2; } { std::string fName = rdbase + "stereo3d_conflict.mol"; auto m1 = MolFileToMol(fName); TEST_ASSERT(m1); std::string smi = "F[C@](Cl)(Br)I"; auto m2 = SmilesToMol(smi); TEST_ASSERT(m2); auto csmi1 = MolToSmiles(*m1, true); auto csmi2 = MolToSmiles(*m2, true); TEST_ASSERT(csmi1.find("@") != std::string::npos); TEST_ASSERT(csmi1 == csmi2); delete m1; delete m2; } { std::string fName = rdbase + "stereo3d_unknown.mol"; auto m1 = MolFileToMol(fName); TEST_ASSERT(m1); std::string smi = "F[C](Cl)(Br)I"; auto m2 = SmilesToMol(smi); TEST_ASSERT(m2); auto csmi1 = MolToSmiles(*m1, true); auto csmi2 = MolToSmiles(*m2, true); TEST_ASSERT(csmi1.find("@") == std::string::npos); TEST_ASSERT(csmi1 == csmi2); delete m1; delete m2; } { std::string fName = rdbase + "stereo3d_trans.mol"; auto m1 = MolFileToMol(fName); TEST_ASSERT(m1); std::string smi = "F/C=C/F"; auto m2 = SmilesToMol(smi); TEST_ASSERT(m2); auto csmi1 = MolToSmiles(*m1, true); auto csmi2 = MolToSmiles(*m2, true); TEST_ASSERT(csmi1.find("/") != std::string::npos); TEST_ASSERT(csmi1 == csmi2); delete m1; delete m2; } { std::string fName = rdbase + "stereo3d_cis.mol"; auto m1 = MolFileToMol(fName); TEST_ASSERT(m1); std::string smi = "F/C=C\\F"; auto m2 = SmilesToMol(smi); TEST_ASSERT(m2); auto csmi1 = MolToSmiles(*m1, true); auto csmi2 = MolToSmiles(*m2, true); TEST_ASSERT(csmi1.find("/") != std::string::npos); TEST_ASSERT(csmi1.find("\\") != std::string::npos); TEST_ASSERT(csmi1 == csmi2); delete m1; delete m2; } { std::string fName = rdbase + "stereo3d_dblunknown.mol"; auto m1 = MolFileToMol(fName); TEST_ASSERT(m1); std::string smi = "FC=CF"; auto m2 = SmilesToMol(smi); TEST_ASSERT(m2); auto csmi1 = MolToSmiles(*m1, true); auto csmi2 = MolToSmiles(*m2, true); TEST_ASSERT(csmi1.find("/") == std::string::npos); TEST_ASSERT(csmi1.find("\\") == std::string::npos); TEST_ASSERT(csmi1 == csmi2); delete m1; delete m2; } } void testMarvinSMATag() { BOOST_LOG(rdInfoLog) << "Test Marvin MRV SMA tag " << std::endl; std::string rdbase = getenv("RDBASE"); rdbase += "/Code/GraphMol/FileParsers/test_data/"; { std::string fName = rdbase + "mrv-sma.mol"; RWMol *m = MolFileToMol(fName, false); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 4); TEST_ASSERT(m->getAtomWithIdx(0)->getProp( common_properties::MRV_SMA) == "[#6;r6]"); TEST_ASSERT(m->getAtomWithIdx(1)->getProp( common_properties::MRV_SMA) == "[#16;H1]"); TEST_ASSERT(m->getAtomWithIdx(2)->getProp( common_properties::MRV_SMA) == "[#6;r6]"); TEST_ASSERT(m->getAtomWithIdx(3)->getProp( common_properties::MRV_SMA) == "[#7;H2A]"); // this should be similar to [#7;AH2:4][c;r6:3]:[c;r6:1]-[#16H1:2] // RDKit makes these recursive smarts, not "ANDED" smarts which are a // simpler case std::string sma = MolToSmarts(*m); TEST_ASSERT(sma == "[#6&$([#6&r6]):1](-[#16&$([#16&H1]):2]):[#6&$([#6&r6]):3]-[#7&" "$([#7&H2&A]):4]"); delete m; } { std::string fName = rdbase + "mrv-sma-bad.mol"; bool ok = false; try { MolFileToMol(fName, false); } catch (FileParseException &e) { ok = true; TEST_ASSERT( std::string("Cannot parse smarts: 'MyDogHasFleas' on line 12") == e.what()); } TEST_ASSERT(ok); } BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testGithub1689() { BOOST_LOG(rdInfoLog) << "Test github 1689: Play nice with naughty MOL blocks" << std::endl; std::string molb = "rdkit_blank_line_before_M_END_test.sdf\n" " ChemDraw12181709392D\n" "\n" " 2 1 0 0 0 0 0 0 0 0999 V2000\n" " -0.3572 -0.2062 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" " 0.3572 0.2062 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" " 1 2 1 0 \n" "\n" "M END\n"; { bool sanitize = true, removeHs = true, strictParsing = false; ROMol *m = MolBlockToMol(molb, sanitize, removeHs, strictParsing); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 2); TEST_ASSERT(m->getNumBonds() == 1); delete m; } { bool sanitize = true, removeHs = true, strictParsing = true; bool ok = false; try { MolBlockToMol(molb, sanitize, removeHs, strictParsing); } catch (FileParseException &) { ok = true; } TEST_ASSERT(ok); } } void testWedgeBondToDoublebond() { BOOST_LOG(rdInfoLog) << "Test wedged bonds to double bonds " << std::endl; std::string rdbase = getenv("RDBASE"); rdbase += "/Code/GraphMol/FileParsers/test_data/"; { // a second report that came in std::string fName = rdbase + "wedged_single_to_double_bond.mol"; bool sanitize = false, removeHs = false; ROMol *m = MolFileToMol(fName, sanitize, removeHs); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms() == 49); TEST_ASSERT(m->getNumBonds() == 51); delete m; } BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testGithub1615() { BOOST_LOG(rdInfoLog) << "testing github #1615: add function WedgeBond()" << std::endl; std::string rdbase = getenv("RDBASE"); rdbase += "/Code/GraphMol/FileParsers/test_data/"; { RWMol *m1; std::string fName = rdbase + "Issue399a.mol"; m1 = MolFileToMol(fName); TEST_ASSERT(m1); TEST_ASSERT(m1->getAtomWithIdx(1)->hasProp(common_properties::_CIPCode)); TEST_ASSERT(m1->getAtomWithIdx(1)->getProp( common_properties::_CIPCode) == "S"); TEST_ASSERT(m1->getBondWithIdx(0)->getBondDir() == Bond::NONE); Chirality::wedgeBond(m1->getBondWithIdx(0), 1, &m1->getConformer()); TEST_ASSERT(m1->getBondWithIdx(0)->getBondDir() == Bond::BEGINWEDGE); delete m1; } { std::string mb = "example\n" " ChemDraw04050615582D\n" "\n" " 4 4 0 0 0 0 0 0 0 0999 V2000\n" " -0.7697 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 " "0\n" " 0.0553 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 " "0\n" " 0.7697 0.4125 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 " "0\n" " 0.7697 -0.4125 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 " "0\n" " 2 1 1 0\n" " 2 3 1 0\n" " 3 4 1 0\n" " 2 4 1 0\n" "M END\n"; RWMol *m1 = MolBlockToMol(mb); TEST_ASSERT(m1); TEST_ASSERT(!m1->getAtomWithIdx(1)->hasProp(common_properties::_CIPCode)); TEST_ASSERT(m1->getBondWithIdx(0)->getBondDir() == Bond::NONE); TEST_ASSERT(m1->getAtomWithIdx(1)->getChiralTag() == Atom::CHI_UNSPECIFIED); m1->getAtomWithIdx(1)->setChiralTag(Atom::CHI_TETRAHEDRAL_CW); MolOps::assignStereochemistry(*m1, true, true); TEST_ASSERT(m1->getAtomWithIdx(1)->hasProp(common_properties::_CIPCode)); TEST_ASSERT(m1->getAtomWithIdx(1)->getProp( common_properties::_CIPCode) == "S"); TEST_ASSERT(m1->getBondWithIdx(0)->getBondDir() == Bond::NONE); Chirality::wedgeBond(m1->getBondWithIdx(0), 1, &m1->getConformer()); TEST_ASSERT(m1->getBondWithIdx(0)->getBondDir() == Bond::BEGINWEDGE); delete m1; } BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testGithub2000() { BOOST_LOG(rdInfoLog) << "testing github #2000: Error while parsing empty atom list" << std::endl; std::string rdbase = getenv("RDBASE"); rdbase += "/Code/GraphMol/FileParsers/test_data/"; { std::string fName = rdbase + "github2000.sdf"; std::unique_ptr m1(MolFileToMol(fName)); TEST_ASSERT(m1); TEST_ASSERT(!m1->getAtomWithIdx(0)->hasQuery()); } { std::string fName = rdbase + "github2000.2.sdf"; bool ok = false; try { std::unique_ptr m1(MolFileToMol(fName)); } catch (FileParseException &) { ok = true; } TEST_ASSERT(ok); } BOOST_LOG(rdInfoLog) << "done" << std::endl; } void testAtomQueries() { BOOST_LOG(rdInfoLog) << "-------------------------------------" << std::endl; BOOST_LOG(rdInfoLog) << "Testing atom queries contains HCOUNT, RBCOUNT, UNSAT" << std::endl; { std::string pathName = getenv("RDBASE"); pathName += "/Code/GraphMol/FileParsers/test_data/"; std::unique_ptr testQuery( MolFileToMol(pathName + "AtomQuery1.mol", true, false, true)); TEST_ASSERT(testQuery); std::unique_ptr testMol( SmilesToMol("[H]C([H])([H])C1=CN=C(C=C)C(C2CCCCC2)=C1C")); TEST_ASSERT(testMol); MatchVectType mv; SubstructMatch(*testMol, *testQuery, mv); TEST_ASSERT(mv.size() > 0); testMol.reset(SmilesToMol("[H]CC1=CN=C(C=C)C(C2CCCCC2)=C1C")); TEST_ASSERT(testMol); SubstructMatch(*testMol, *testQuery, mv); TEST_ASSERT(mv.size() > 0); testMol.reset(SmilesToMol("CCC1=CN=C(C=C)C(C2CCCCC2)=C1C")); TEST_ASSERT(testMol); SubstructMatch(*testMol, *testQuery, mv); TEST_ASSERT(mv.size() == 0); // search fails } { std::string pathName = getenv("RDBASE"); pathName += "/Code/GraphMol/FileParsers/test_data/"; std::unique_ptr testQuery( MolFileToMol(pathName + "AtomQuery2.mol", true, false, true)); TEST_ASSERT(testQuery); std::unique_ptr testMol(SmilesToMol("C1(C)C(C)=CN=C(C)C=1C1CCCCC1")); TEST_ASSERT(testMol); MatchVectType mv; SubstructMatch(*testMol, *testQuery, mv); TEST_ASSERT(mv.size() > 0); testMol.reset(SmilesToMol("C1(C)C(C)=CN=C(C)C=1C12CCC(CC1)CC2")); TEST_ASSERT(testMol); SubstructMatch(*testMol, *testQuery, mv); TEST_ASSERT(mv.size() == 0); // search fails } { std::string pathName = getenv("RDBASE"); pathName += "/Code/GraphMol/FileParsers/test_data/"; std::unique_ptr testQuery( MolFileToMol(pathName + "AtomQuery3.mol", true, false, true)); TEST_ASSERT(testQuery); std::unique_ptr testMol( SmilesToMol("CCC1=CN=C(C=C)C(C2CCCCC2)=C1C")); TEST_ASSERT(testMol); MatchVectType mv; SubstructMatch(*testMol, *testQuery, mv); TEST_ASSERT(mv.size() > 0); testMol.reset(SmilesToMol("CCC1=CN=C(C3=CC=CC=C3)C(C2CCCCC2)=C1C")); TEST_ASSERT(testMol); SubstructMatch(*testMol, *testQuery, mv); TEST_ASSERT(mv.size() > 0); testMol.reset(SmilesToMol("CCC1=CN=C(C3CCCCC3)C(C2CCCCC2)=C1C")); TEST_ASSERT(testMol); SubstructMatch(*testMol, *testQuery, mv); TEST_ASSERT(mv.size() == 0); } BOOST_LOG(rdInfoLog) << "Finished" << std::endl; } void RunTests() { #if 1 test1(); test2(); test4(); test5(); test6(); testIssue145(); testIssue148(); test7(); test8(); testIssue180(); testIssue264(); testIssue399(); testMolFileChgLines(); testDblBondStereochem(); testSymmetricDblBondStereochem(); testRingDblBondStereochem(); testMolFileRGroups(); testMolFileDegreeQueries(); testMolFileRBCQueries(); testMolFileUnsaturationQueries(); testMolFileQueryToSmarts(); testMissingFiles(); testIssue1965035(); testRadicals(); testBadBondOrders(); testAtomParity(); testIssue2692246(); testKekulizationSkip(); testMolFileAtomValues(); testMolFileAtomQueries(); testListsAndValues(); // testCrash(); test1V3K(); testIssue2963522(); testIssue3073163(); testIssue3154208(); testIssue3228150(); testIssue3313540(); testIssue3359739(); testIssue3374639(); testThreeCoordinateChirality(); testIssue3375647(); testIssue3375684(); testChiralPhosphorous(); testIssue3392107(); testIssue3477283(); testIssue3484552(); testIssue3514824(); testIssue3525799(); testSkipLines(); testIssue269(); testMolFileChiralFlag(); testMolFileTotalValence(); testGithub88(); testGithub82(); testMolFileWithHs(); testMolFileWithRxn(); testGithub166(); testZBO(); testGithub164(); testGithub194(); testGithub196(); testIssue3557675(); test3V3K(); test2V3K(); testGithub191(); testGithub210(); testPDBResidues(); testGithub337(); testGithub360(); testGithub741(); testGithub188(); testRCSBSdf(); testParseCHG(); testMDLAtomProps(); testSupplementalSmilesLabel(); testGithub1023(); testGithub1049(); testPDBFile(); testSequences(); // testSequenceReaders(); testMolFileDativeBonds(); testGithub1251(); testMarvinSMATag(); testGithub1029(); testGithub1340(); testGithub1034(); testMolBlockChirality(); testMolBlock3DStereochem(); testGithub1689(); testWedgeBondToDoublebond(); testGithub1615(); testGithub2000(); testAtomQueries(); #endif } // must be in German Locale for test... void testLocaleSwitcher() { float d = -1.0; char buffer[1024]; sprintf(buffer, "%0.2f", d); if (std::string(buffer) != "-1,00") { BOOST_LOG(rdInfoLog) << " ---- no German locale support (skipping) ---- " << std::endl; return; } { RDKit::Utils::LocaleSwitcher ls; sprintf(buffer, "%0.2f", d); CHECK_INVARIANT(std::string(buffer) == "-1.00", "Locale Switcher Fail"); // test locale switcher recursion { RDKit::Utils::LocaleSwitcher ls; sprintf(buffer, "%0.2f", d); CHECK_INVARIANT(std::string(buffer) == "-1.00", "Locale Switcher Fail"); } // should still be in the "C" variant sprintf(buffer, "%0.2f", d); CHECK_INVARIANT(std::string(buffer) == "-1.00", "Locale Switcher Fail"); } // Should be back in German Locale sprintf(buffer, "%0.2f", d); CHECK_INVARIANT(std::string(buffer) == "-1,00", "Locale Switcher Fail"); } #ifdef RDK_TEST_MULTITHREADED #include #include namespace { void runblock() { std::setlocale(LC_ALL, "de_DE.UTF-8"); testLocaleSwitcher(); } } // namespace void testMultiThreadedSwitcher() { BOOST_LOG(rdErrorLog) << "-------------------------------------" << std::endl; BOOST_LOG(rdErrorLog) << " Test multithreading Locale Switching" << std::endl; std::vector> tg; unsigned int count = 100; for (unsigned int i = 0; i < count; ++i) { tg.emplace_back(std::async(std::launch::async, runblock)); } for (auto &fut : tg) { fut.get(); } BOOST_LOG(rdErrorLog) << " Test multithreading (Done)" << std::endl; BOOST_LOG(rdErrorLog) << "-------------------------------------" << std::endl; } #else void testMultiThreadedSwitcher() { BOOST_LOG(rdErrorLog) << "-------------------------------------" << std::endl; BOOST_LOG(rdInfoLog) << " ---- Multithreaded tests disabled ---- " << std::endl; } #endif int main(int argc, char *argv[]) { (void)argc; (void)argv; // std::locale::global(std::locale("de_DE.UTF-8")); RDLog::InitLogs(); BOOST_LOG(rdInfoLog) << " ---- Running with POSIX locale ----- " << std::endl; RunTests(); // run with C locale BOOST_LOG(rdInfoLog) << " ---- Running with German locale ----- " << std::endl; std::setlocale(LC_ALL, "de_DE.UTF-8"); std::cout << std::setlocale(LC_ALL, nullptr) << std::endl; testLocaleSwitcher(); testMultiThreadedSwitcher(); RunTests(); return 0; }