/**********************************************************************
smartstest.cpp - Test SMARTS algorithms and atom typing.
This file is part of the Open Babel project.
For more information, see
Copyright (C) 1998-2001 by OpenEye Scientific Software, Inc.
Some portions Copyright (C) 2001-2005 Geoffrey R. Hutchison
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
***********************************************************************/
// used to set import/export for Cygwin DLLs
#ifdef WIN32
#define USING_OBDLL
#endif
#include
#include
#include
#include
namespace OpenBabel
{
bool SafeOpen(std::ifstream &fs, const char *filename);
bool SafeOpen(std::ofstream &fs, const char *filename);
}
using namespace std;
using namespace OpenBabel;
void GenerateSmartsReference();
#ifdef TESTDATADIR
string testdatadir = TESTDATADIR;
string smarts_file = testdatadir + "smartstest.txt";
string results_file = testdatadir + "smartsresults.txt";
string smilestypes_file = testdatadir + "attype.00.smi";
#else
string smarts_file = "files/smartstest.txt";
string results_file = "files/smartsresults.txt";
string smilestypes_file = "files/attype.00.smi";
#endif
int main(int argc,char *argv[])
{
// turn off slow sync with C-style output (we don't use it anyway).
std::ios::sync_with_stdio(false);
if (argc != 1)
{
if (strncmp(argv[1], "-g", 2))
{
cout << "Usage: smartstest\n";
cout << " Tests Open Babel SMILES/SMARTS pattern matching." << endl;
return 0;
}
else
{
GenerateSmartsReference();
return 0;
}
}
cout << endl << "# Testing SMARTS... \n";
std::ifstream ifs;
if (!SafeOpen(ifs, smarts_file.c_str()))
{
cout << "Bail out! Cannot read " << smarts_file << endl;
return -1; // test failed
}
//read in the SMARTS test patterns
char buffer[BUFF_SIZE];
vector vsp;
for (;ifs.getline(buffer,BUFF_SIZE);)
{
if (buffer[0] == '#') // skip comment line
continue;
OBSmartsPattern *sp = new OBSmartsPattern;
if (sp->Init(buffer))
vsp.push_back(sp);
else
delete sp;
}
ifs.close();
std::ifstream rifs;
if (!SafeOpen(rifs, results_file.c_str()))
{
cout << "Bail out! Cannot read in results file " << results_file << endl;
return -1; // test failed
}
unsigned int npats;
rifs.getline(buffer,BUFF_SIZE);
sscanf(buffer,"%d %*s",&npats);
//make sure the number of SMARTS patterns is the same as in the
//reference data
if (npats != vsp.size())
{
cout << "Bail out! Correct number of patterns not read in" <<
"Read in " << vsp.size() << " expected " << npats << endl;
return -1; // test failed
}
std::ifstream mifs;
if (!SafeOpen(mifs, smilestypes_file.c_str()))
{
cout << "Bail out! Cannot read atom types " << smilestypes_file << endl;
return -1; // test failed
}
unsigned int k;
unsigned int res_line = 0;
OBMol mol;
vector vs;
vector::iterator i;
vector > mlist;
unsigned int currentMol = 0; // each molecule is a separate test
bool molPassed = true;
OBConversion conv(&mifs, &cout);
if (! conv.SetInAndOutFormats("SMI","SMI"))
{
cout << "Bail out! SMILES format is not loaded" << endl;
return -1;
}
//read in molecules, match SMARTS, and compare results to reference data
for (;mifs;)
{
mol.Clear();
conv.Read(&mol);
if (mol.Empty())
continue;
currentMol++;
molPassed = true;
for (i = vsp.begin();i != vsp.end();i++)
{
if (!rifs.getline(buffer,BUFF_SIZE))
{
cout << "Bail out! Error reading reference data" << endl;
return -1; // test failed
}
res_line++;
tokenize(vs,buffer);
(*i)->Match(mol);
mlist = (*i)->GetMapList();
if (mlist.size() != vs.size())
{
cout << "not ok " << currentMol
<< " # number of matches different than reference\n";
cout << "# Expected " << vs.size() << " matches, found "
<< mlist.size() << "\n";
cout << "# Error with molecule " << mol.GetTitle();
cout << "# on pattern " << (*i)->GetSMARTS() << "\n";
if (mlist.size())
cout << "# First match: atom #" << mlist[0][0] << "\n";
molPassed = false;
break;
}
if (mlist.size())
{
for (k = 0;k < vs.size();k++)
{
if (atoi(vs[k].c_str()) != mlist[k][0])
{
cout << "not ok " << currentMol
<< "# matching atom numbers different than reference\n";
cout << "# Expected " << vs[k] << " but found "
<< mlist[k][0] << "\n";
cout << "# Molecule: " << mol.GetTitle() << "\n";
cout << "# Pattern: " << (*i)->GetSMARTS() << "\n";
molPassed = false;
break;
}
}
if (k != vs.size())
{
molPassed = false;
break;
}
}
}
if (molPassed)
cout << "ok " << currentMol << " # molecule passed tests\n";
}
// output the number of tests run
cout << "1.." << currentMol << endl;
// Passed Test
return 0;
}
void GenerateSmartsReference()
{
std::ifstream ifs;
if (!SafeOpen(ifs,smarts_file.c_str()))
return;
char buffer[BUFF_SIZE];
vector vsp;
for (;ifs.getline(buffer,BUFF_SIZE);)
{
if (buffer[0] == '#') // skip comment line
continue;
OBSmartsPattern *sp = new OBSmartsPattern;
if (sp->Init(buffer))
vsp.push_back(sp);
else
delete sp;
}
std::ofstream ofs;
if (!SafeOpen(ofs, results_file.c_str()))
return;
ofs << vsp.size() << " patterns" << endl;
std::ifstream mifs;
if (!SafeOpen(mifs, smilestypes_file.c_str()))
return;
vector vm;
vector > mlist;
vector >::iterator j;
vector::iterator i;
OBMol mol;
OBConversion conv(&mifs, &cout);
if(! conv.SetInAndOutFormats("SMI","SMI"))
{
cerr << "SMILES format is not loaded" << endl;
return;
}
for (;mifs;)
{
mol.Clear();
conv.Read(&mol);
if (mol.Empty())
continue;
for (i = vsp.begin();i != vsp.end();i++)
{
(*i)->Match(mol);
mlist = (*i)->GetMapList();
for (j = mlist.begin();j != mlist.end();j++)
{
sprintf(buffer,"%3d",*(j->begin()));
ofs << buffer;
}
ofs << endl;
}
}
cerr << " SMARTS test results written successfully" << endl;
return;
}