From a3f3f3ab842dd8608f2d5197258117dc482a7972 Mon Sep 17 00:00:00 2001 From: Gerardo Tauriello <gerardo.tauriello@unibas.ch> Date: Tue, 9 Jul 2019 17:23:36 +0200 Subject: [PATCH] SCHWED-4246: Add mol.QueryQuoteName function. --- modules/mol/base/pymod/export_query.cc | 2 +- modules/mol/base/src/query.hh | 19 +++++++++++ modules/mol/base/tests/test_query.cc | 46 +++++++++++++++++++++++++- 3 files changed, 65 insertions(+), 2 deletions(-) diff --git a/modules/mol/base/pymod/export_query.cc b/modules/mol/base/pymod/export_query.cc index 7930cd426..8f1fc9460 100644 --- a/modules/mol/base/pymod/export_query.cc +++ b/modules/mol/base/pymod/export_query.cc @@ -68,5 +68,5 @@ void export_Query() return_value_policy<copy_const_reference>()) ; - + def("QueryQuoteName", &QueryQuoteName); } diff --git a/modules/mol/base/src/query.hh b/modules/mol/base/src/query.hh index c76454670..d855703c3 100644 --- a/modules/mol/base/src/query.hh +++ b/modules/mol/base/src/query.hh @@ -117,6 +117,25 @@ private: impl::QueryImplP impl_; }; +// inlined helper function to quote strings for use in queries (e.g. cname=..). +// throws Error if string cannot be quoted +inline String DLLEXPORT_OST_MOL QueryQuoteName(const String& name) { + // check what quotation marks to use + char quote = '\''; + if (name.find('\'') != String::npos) { + if (name.find('"') != String::npos) { + throw Error("Cannot quote chain name " + name + " because it contains '" + " and \" in its name."); + } + quote = '"'; + } + // check problematic \ at end (escapes quotation mark and breaks logic) + if (name[name.length() - 1] == '\\') { + throw Error("Cannot quote chain name " + name + "because it ends in \\."); + } + return quote + name + quote; +} + }} // ns #endif diff --git a/modules/mol/base/tests/test_query.cc b/modules/mol/base/tests/test_query.cc index 57fc557bf..5f8865ae5 100644 --- a/modules/mol/base/tests/test_query.cc +++ b/modules/mol/base/tests/test_query.cc @@ -286,7 +286,7 @@ BOOST_AUTO_TEST_CASE(test_query_throw) BOOST_CHECK_NO_THROW(e.Select("gcnotsetprop:0=1")); } -BOOST_AUTO_TEST_CASE(test_glob) +BOOST_AUTO_TEST_CASE(test_glob) { EntityHandle e=make_query_test_entity(); ensure_counts(e, "rname=MET and aname=C*", 1, 1, 5); @@ -299,4 +299,48 @@ BOOST_AUTO_TEST_CASE(test_glob) ensure_counts(e, "rname=LEU and aname=?D?", 1, 1, 2); } +BOOST_AUTO_TEST_CASE(test_quoting) +{ + // possible letters taken from mmCIF dictionary + // -> http://mmcif.wwpdb.org/dictionaries/mmcif_pdbx_v50.dic/Items/_atom_site.label_asym_id.html + // not ok for us: '\' alone + String single_letters = " ][_,.;:\"&<>()/{}'`~!@#$\%|+-" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefgh" + "ijklmnopqrstuvwxyz"; + // put into vector + std::vector<String> chain_names; + for (size_t i = 0; i < single_letters.length(); ++i) { + chain_names.push_back(String(1, single_letters[i])); + } + // add some multi letter names and empty chain name too + // not ok: mixing ' and ", '\' at end + chain_names.push_back("\\ ][_,.;:&<>()/{}'`~!@#$\%|+-"); + chain_names.push_back("ABCDEFGHIJKLMNOPQRSTU'VWXYZ0123456789abcdefgh"); + chain_names.push_back("ijklmno\"pqrstuvwxyz"); + chain_names.push_back(""); + // setup entity + EntityHandle ent = CreateEntity(); + XCSEditor edi = ent.EditXCS(); + for (size_t i = 0; i < chain_names.size(); ++i) { + edi.InsertChain(chain_names[i]); + } + // test quoting + String query_all = "cname="; + for (size_t i = 0; i < chain_names.size(); ++i) { + const String quoted_name = QueryQuoteName(chain_names[i]); + BOOST_CHECK_EQUAL(ent.Select("cname=" + quoted_name).GetChainCount(), 1); + query_all += quoted_name; + if (i != chain_names.size() - 1) query_all += ","; + } + BOOST_CHECK_EQUAL(ent.Select(query_all).GetChainCount(), + int(chain_names.size())); + // note: quoting * keeps it as wild card! + BOOST_CHECK_EQUAL(ent.Select("cname=" + QueryQuoteName("*")).GetChainCount(), + int(chain_names.size())); + // expected failures (mixing ' and ", '\' at end) + BOOST_CHECK_THROW(QueryQuoteName("'\""), Error); + BOOST_CHECK_THROW(QueryQuoteName("\\"), Error); + BOOST_CHECK_THROW(QueryQuoteName("a\\"), Error); +} + BOOST_AUTO_TEST_SUITE_END(); -- GitLab