dlvhex  2.5.0
testsuite/TestHexParserModule.cpp
Go to the documentation of this file.
00001 /* dlvhex -- Answer-Set Programming with external interfaces.
00002  * Copyright (C) 2005, 2006, 2007 Roman Schindlauer
00003  * Copyright (C) 2006, 2007, 2008, 2009, 2010 Thomas Krennwallner
00004  * Copyright (C) 2009, 2010 Peter Schüller
00005  * 
00006  * This file is part of dlvhex.
00007  *
00008  * dlvhex is free software; you can redistribute it and/or modify it
00009  * under the terms of the GNU Lesser General Public License as
00010  * published by the Free Software Foundation; either version 2.1 of
00011  * the License, or (at your option) any later version.
00012  *
00013  * dlvhex is distributed in the hope that it will be useful, but
00014  * WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  * Lesser General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Lesser General Public
00019  * License along with dlvhex; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
00021  * 02110-1301 USA.
00022  */
00023 
00031 #ifdef HAVE_CONFIG_H
00032 #include "config.h"
00033 #endif // HAVE_CONFIG_H
00034 
00035 #include <boost/cstdint.hpp>
00036 #include "dlvhex2/HexParser.h"
00037 #include "dlvhex2/InputProvider.h"
00038 #include "dlvhex2/ProgramCtx.h"
00039 #include "dlvhex2/Printer.h"
00040 #include "dlvhex2/Registry.h"
00041 #include "dlvhex2/Interpretation.h"
00042 #include "dlvhex2/MLPSyntaxChecker.h"
00043 //#include "dlvhex2/MLPSolver.hpp"
00044 
00045 #define BOOST_TEST_MODULE "TestHexParserModule"
00046 #include <boost/test/unit_test.hpp>
00047 
00048 #include <iostream>
00049 #include <fstream>
00050 
00051 #define LOG_REGISTRY_PROGRAM(ctx) \
00052   LOG(INFO, *ctx.registry()); \
00053     RawPrinter printer(std::cerr, ctx.registry()); \
00054     std::cerr << "first edb = " << *ctx.edbList.front() << std::endl; \
00055     LOG(DBG, "first idb"); \
00056     printer.printmany(ctx.idbList.front(),"\n"); \
00057     std::cerr << std::endl; \
00058     LOG(DBG, "idb end");
00059 
00060 /*
00061 #define LOG_REGISTRY_PROGRAM(ctx) \
00062   LOG(*ctx.registry); \
00063     RawPrinter printer(std::cerr, ctx.registry); \
00064     std::cerr << "edb = " << *ctx.edb << std::endl; \
00065     LOG("idb"); \
00066     printer.printmany(ctx.idb,"\n"); \ 
00067     std::cerr << std::endl; \
00068     LOG("idb end");*/
00069 
00070 
00071 LOG_INIT(Logger::ERROR | Logger::WARNING)
00072 
00073 DLVHEX_NAMESPACE_USE
00074 
00075 
00076 BOOST_AUTO_TEST_CASE(testHexParserModuleAtoms) 
00077 {
00078   ProgramCtx ctx;
00079   ctx.setupRegistry(RegistryPtr(new Registry));
00080   
00081   //.. put into different files
00082 
00083   char *TOP_SRCDIR = getenv("TOP_SRCDIR");
00084   assert(TOP_SRCDIR != 0);
00085 
00086   std::string filename1(TOP_SRCDIR);
00087   std::string filename2(TOP_SRCDIR);
00088   std::string filename3(TOP_SRCDIR);
00089 
00090   filename1 += "/examples/module1.mlp";
00091   filename2 += "/examples/module2.mlp";
00092   filename3 += "/examples/module3.mlp";
00093   std::ifstream ifs;
00094   std::ostringstream buf;
00095 
00096   ifs.open(filename1.c_str());
00097   BOOST_REQUIRE(ifs.is_open());
00098   buf << ifs.rdbuf();
00099   ifs.close();
00100 
00101   ifs.open(filename2.c_str());
00102   BOOST_REQUIRE(ifs.is_open());
00103   buf << ifs.rdbuf();
00104   ifs.close();
00105 
00106   ifs.open(filename3.c_str());
00107   BOOST_REQUIRE(ifs.is_open());
00108   buf << ifs.rdbuf();
00109   ifs.close();
00110 
00111   std::stringstream ss;
00112   ss << buf.str();
00113   std::cout << ss.str() << std::endl;
00114 
00115 /*
00116   std::stringstream ss;
00117   ss <<
00118   "#module(p1,[q1/1])." << std::endl <<
00119   "q1(a)." << std::endl <<
00120   "q1(b)." << std::endl <<
00121   "ok :- @p2[q1]::even(c)." << std::endl <<
00122   "#module(p2,[q2/1])." << std::endl <<
00123   "q2i(X) v q2i(Y) :- q2(X), q2(Y), X!=Y." << std::endl <<
00124   "skip2   :- q2(X), not q2i(X)." << std::endl <<
00125   "even(c) :- not skip2." << std::endl <<
00126   "even(c) :- skip2, @p3[q2i]::odd." << std::endl << 
00127     std::endl << 
00128   "#module(p3,[q3/1])." << std::endl <<
00129   "q3i(X) v q3i(Y) :- q3(X), q3(Y), X!=Y." << std::endl <<
00130   "skip3  :- q3(X), not q3i(X)." << std::endl <<
00131   "odd :- skip3, @p2[q3i]::even(c).";
00132 */
00133 
00134   InputProviderPtr ip(new InputProvider);
00135   ip->addStreamInput(ss, "testinput");
00136   ModuleHexParser parser;
00137   BOOST_REQUIRE_NO_THROW(parser.parse(ip, ctx));
00138 
00139   // after parser, print ctx
00140   LOG_REGISTRY_PROGRAM(ctx);
00141   
00142   // check some atoms (got the idea from TestHexParser.cpp)
00143   ID idp = ctx.registry()->preds.getIDByString("p1__q1");
00144   ID idq = ctx.registry()->preds.getIDByString("p2__q2");
00145   ID idr = ctx.registry()->preds.getIDByString("p3__q3");
00146   ID idb = ctx.registry()->preds.getIDByString("p1__ok");
00147   ID idc = ctx.registry()->preds.getIDByString("p2__even");
00148   ID idmymod = ctx.registry()->preds.getIDByString("p3__p2");
00149   
00150   // the id should not fail
00151   BOOST_REQUIRE((idp) != ID_FAIL);
00152   BOOST_REQUIRE((idq) != ID_FAIL);
00153   BOOST_REQUIRE((idr) != ID_FAIL);
00154   BOOST_REQUIRE((idb) != ID_FAIL);
00155   BOOST_REQUIRE((idc) != ID_FAIL);
00156   BOOST_REQUIRE((idmymod) != ID_FAIL);
00157   ID mod1(ID::MAINKIND_ATOM | ID::SUBKIND_ATOM_MODULE, 0);
00158   BOOST_REQUIRE( ctx.registry()->matoms.getByID(mod1).actualModuleName == "p2" );
00159   ID mod2(ID::MAINKIND_ATOM | ID::SUBKIND_ATOM_MODULE, 1);
00160   BOOST_REQUIRE( ctx.registry()->matoms.getByID(mod2).actualModuleName == "p3" );
00161   ID mod3(ID::MAINKIND_ATOM | ID::SUBKIND_ATOM_MODULE, 2);
00162   BOOST_REQUIRE( ctx.registry()->matoms.getByID(mod3).actualModuleName == "p2" );
00163 //  BOOST_REQUIRE(ctx.edb != 0);
00164 //  BOOST_REQUIRE(ctx.idb.size() == 3);
00165   {
00166     const Rule& r = ctx.registry()->rules.getByID(ctx.idbList.back()[2]);
00167     BOOST_CHECK(r.kind == (ID::MAINKIND_RULE | ID::SUBKIND_RULE_REGULAR | ID::PROPERTY_RULE_MODATOMS));
00168     BOOST_CHECK(r.weight == ID_FAIL);
00169     BOOST_CHECK(r.level == ID_FAIL);
00170     BOOST_CHECK(r.head.size() == 1);
00171     BOOST_REQUIRE(r.body.size() == 2);
00172     {
00173       ID idlit = r.body[1];
00174       BOOST_CHECK(idlit.isLiteral());
00175       BOOST_CHECK(idlit.isModuleAtom());
00176     }
00177   }
00178 
00179   // syntax verifying:
00180   MLPSyntaxChecker sC(ctx);
00181   BOOST_REQUIRE( sC.verifySyntax() == true );
00182 
00183 }
00184 
00185 
00186 
00187 // test case if we call a module that is not exist
00188 BOOST_AUTO_TEST_CASE(testCallNotExistModule)
00189 {
00190   ProgramCtx ctx;
00191   ctx.setupRegistry(RegistryPtr(new Registry));
00192 
00193   //.. put into different files
00194   char *TOP_SRCDIR = getenv("TOP_SRCDIR");
00195   assert(TOP_SRCDIR != 0);
00196 
00197   std::string filename1(TOP_SRCDIR);
00198   filename1 += "/examples/module1.mlp";
00199   std::ifstream ifs;
00200   std::ostringstream buf;
00201 
00202   ifs.open(filename1.c_str());
00203   BOOST_REQUIRE(ifs.is_open());
00204   buf << ifs.rdbuf();
00205   std::string input1 = buf.str();
00206   ifs.close();
00207 
00208   std::stringstream ss;
00209   ss << input1;
00210 
00211   InputProviderPtr ip(new InputProvider);
00212   ip->addStreamInput(ss, "testinput");
00213   ModuleHexParser parser;
00214   BOOST_REQUIRE_NO_THROW(parser.parse(ip, ctx));
00215 
00216   LOG_REGISTRY_PROGRAM(ctx);
00217 
00218   MLPSyntaxChecker sC(ctx);
00219   // BOOST_REQUIRE( sC.verifySyntax() == false );
00220   BOOST_REQUIRE_THROW(sC.verifySyntax(), FatalError);
00221 }
00222 
00223 
00224 // test case if there is a predicate input in module header (is okay)
00225 // that is not exist in module body
00226 BOOST_AUTO_TEST_CASE(testPredInputsNotExistModuleHeader) 
00227 {
00228   ProgramCtx ctx;
00229   ctx.setupRegistry(RegistryPtr(new Registry));
00230 
00231   char *TOP_SRCDIR = getenv("TOP_SRCDIR");
00232   assert(TOP_SRCDIR != 0);
00233 
00234   std::string filename1(TOP_SRCDIR);
00235   filename1 += "/examples/module1-NotExist.mlp";
00236   std::ifstream ifs;
00237   std::ostringstream buf;
00238 
00239   ifs.open(filename1.c_str());
00240   BOOST_REQUIRE(ifs.is_open());
00241   buf << ifs.rdbuf();
00242   ifs.close();
00243 
00244   std::stringstream ss;
00245   ss << buf.str();
00246 
00247   InputProviderPtr ip(new InputProvider);
00248   ip->addStreamInput(ss, "testinput");
00249   ModuleHexParser parser;
00250   BOOST_REQUIRE_NO_THROW(parser.parse(ip, ctx));
00251 
00252   LOG_REGISTRY_PROGRAM(ctx);
00253 
00254   MLPSyntaxChecker sC(ctx);
00255   BOOST_REQUIRE( sC.verifySyntax() == true );
00256 }
00257 
00258 
00259 
00260 // test case if there are too many predicate inputs in module calls 
00261 // for example: call p2[p,q,r]::q(a) but actually module p2 need only 2 predicate inputs
00262 BOOST_AUTO_TEST_CASE(testTooManyPredInputsModuleCalls) 
00263 {
00264   ProgramCtx ctx;
00265   ctx.setupRegistry(RegistryPtr(new Registry));
00266 
00267   std::ifstream ifs;
00268   std::ostringstream buf;
00269 
00270   char *TOP_SRCDIR = getenv("TOP_SRCDIR");
00271   assert(TOP_SRCDIR != 0);
00272 
00273   std::string filename1(TOP_SRCDIR);
00274   filename1 += "/examples/module2-TooMany.mlp";
00275 
00276   ifs.open(filename1.c_str());
00277   BOOST_REQUIRE(ifs.is_open());
00278   buf << ifs.rdbuf();
00279   ifs.close();
00280 
00281   std::string filename2(TOP_SRCDIR);
00282   filename2 += "/examples/module3.mlp";
00283   ifs.open(filename2.c_str());
00284   BOOST_REQUIRE(ifs.is_open());
00285   buf << ifs.rdbuf();
00286   ifs.close();
00287 
00288   std::stringstream ss;
00289   ss << buf.str();
00290 
00291   InputProviderPtr ip(new InputProvider);
00292   ip->addStreamInput(ss, "testinput");
00293   ModuleHexParser parser;
00294   BOOST_REQUIRE_NO_THROW(parser.parse(ip, ctx));
00295 
00296   LOG_REGISTRY_PROGRAM(ctx);
00297 
00298   MLPSyntaxChecker sC(ctx);
00299   //rmv. BOOST_REQUIRE( sC.verifySyntax() == false );
00300   BOOST_REQUIRE_THROW(sC.verifySyntax(), FatalError);
00301 }
00302 
00303 
00304 // test case if there are too few predicate inputs in module calls 
00305 // for example: call p2[p]::q(a) but actually module p2 need 2 predicate inputs
00306 BOOST_AUTO_TEST_CASE(testTooFewPredInputsModuleCalls) 
00307 {
00308   ProgramCtx ctx;
00309   ctx.setupRegistry(RegistryPtr(new Registry));
00310 
00311   char *TOP_SRCDIR = getenv("TOP_SRCDIR");
00312   assert(TOP_SRCDIR != 0);
00313 
00314   std::string filename1(TOP_SRCDIR);
00315   std::ifstream ifs;
00316   std::ostringstream buf;
00317   filename1 += "/examples/module2-TooFew.mlp";
00318 
00319   ifs.open(filename1.c_str());
00320   BOOST_REQUIRE(ifs.is_open());
00321   buf << ifs.rdbuf();
00322   ifs.close();
00323 
00324   std::string filename2(TOP_SRCDIR);
00325   filename2 += "/examples/module3.mlp";
00326   ifs.open(filename2.c_str());
00327   BOOST_REQUIRE(ifs.is_open());
00328   buf << ifs.rdbuf();
00329   ifs.close();
00330 
00331   std::stringstream ss;
00332   ss << buf.str();
00333 
00334   InputProviderPtr ip(new InputProvider);
00335   ip->addStreamInput(ss, "testinput");
00336   ModuleHexParser parser;
00337   BOOST_REQUIRE_NO_THROW(parser.parse(ip, ctx));
00338 
00339   LOG_REGISTRY_PROGRAM(ctx);
00340 
00341   MLPSyntaxChecker sC(ctx);
00342   //rmv. BOOST_REQUIRE( sC.verifySyntax() == false );
00343   BOOST_REQUIRE_THROW(sC.verifySyntax(), FatalError);
00344 }
00345 
00346 
00347 // test case if the arity of predicate inputs in module calls are different 
00348 // from the one specified in the module header
00349 // for example: p2[p]::q(a,c) where p is a predicate with arity 2
00350 //              but actually we have #module(p2, p/1).
00351 BOOST_AUTO_TEST_CASE(testDifferentArityPredInputsModuleCalls) 
00352 {
00353   ProgramCtx ctx;
00354   ctx.setupRegistry(RegistryPtr(new Registry));
00355 
00356   char *TOP_SRCDIR = getenv("TOP_SRCDIR");
00357   assert(TOP_SRCDIR != 0);
00358 
00359   std::string filename1(TOP_SRCDIR);
00360   std::ifstream ifs;
00361   std::ostringstream buf;
00362   filename1 += "/examples/module2-DiffArity.mlp";
00363 
00364   ifs.open(filename1.c_str());
00365   BOOST_REQUIRE(ifs.is_open());
00366   buf << ifs.rdbuf();
00367   ifs.close();
00368 
00369   std::string filename2(TOP_SRCDIR);
00370   filename2 += "/examples/module3.mlp";
00371   ifs.open(filename2.c_str());
00372   BOOST_REQUIRE(ifs.is_open());
00373   buf << ifs.rdbuf();
00374   ifs.close();
00375 
00376   std::stringstream ss;
00377   ss << buf.str();
00378 
00379   InputProviderPtr ip(new InputProvider);
00380   ip->addStreamInput(ss, "testinput");
00381   ModuleHexParser parser;
00382   BOOST_REQUIRE_NO_THROW(parser.parse(ip, ctx));
00383 
00384   LOG_REGISTRY_PROGRAM(ctx);
00385 
00386   MLPSyntaxChecker sC(ctx);
00387   //rmv. BOOST_REQUIRE( sC.verifySyntax() == false );
00388   BOOST_REQUIRE_THROW(sC.verifySyntax(), FatalError);
00389 }
00390 
00391 
00392 // test case if the predicate output in the module call
00393 // not exist in the module that being called
00394 BOOST_AUTO_TEST_CASE(testPredOutputsModuleCallsNotExist) 
00395 {
00396   ProgramCtx ctx;
00397   ctx.setupRegistry(RegistryPtr(new Registry));
00398 
00399   char *TOP_SRCDIR = getenv("TOP_SRCDIR");
00400   assert(TOP_SRCDIR != 0);
00401 
00402   std::string filename1(TOP_SRCDIR);
00403   std::ifstream ifs;
00404   std::ostringstream buf;
00405   filename1 += "/examples/module3-NotExist.mlp";
00406 
00407   ifs.open(filename1.c_str());
00408   BOOST_REQUIRE(ifs.is_open());
00409   buf << ifs.rdbuf();
00410   ifs.close();
00411 
00412   std::string filename2(TOP_SRCDIR);
00413   filename2 += "/examples/module2.mlp";
00414   ifs.open(filename2.c_str());
00415   BOOST_REQUIRE(ifs.is_open());
00416   buf << ifs.rdbuf();
00417   ifs.close();
00418 
00419   std::stringstream ss;
00420   ss << buf.str();
00421 
00422   InputProviderPtr ip(new InputProvider);
00423   ip->addStreamInput(ss, "testinput");
00424   ModuleHexParser parser;
00425   BOOST_REQUIRE_NO_THROW(parser.parse(ip, ctx));
00426 
00427   LOG_REGISTRY_PROGRAM(ctx);
00428 
00429   MLPSyntaxChecker sC(ctx);
00430   //rmv. BOOST_REQUIRE( sC.verifySyntax() == false );
00431   BOOST_REQUIRE_THROW(sC.verifySyntax(), FatalError);
00432 }
00433 
00434 
00435 // test case if predicate output in the module call have a different arity
00436 // with the one inside the module that being called
00437 BOOST_AUTO_TEST_CASE(testDifferentArityPredOutputsModuleCalls) 
00438 {
00439   ProgramCtx ctx;
00440   ctx.setupRegistry(RegistryPtr(new Registry));
00441 
00442   char *TOP_SRCDIR = getenv("TOP_SRCDIR");
00443   assert(TOP_SRCDIR != 0);
00444 
00445   std::string filename1(TOP_SRCDIR);
00446   std::ifstream ifs;
00447   std::ostringstream buf;
00448   filename1 += "/examples/module3-DiffArity.mlp";
00449 
00450   ifs.open(filename1.c_str());
00451   BOOST_REQUIRE(ifs.is_open());
00452   buf << ifs.rdbuf();
00453   ifs.close();
00454 
00455   std::string filename2(TOP_SRCDIR);
00456   filename2 += "/examples/module2.mlp";
00457   ifs.open(filename2.c_str());
00458   BOOST_REQUIRE(ifs.is_open());
00459   buf << ifs.rdbuf();
00460   ifs.close();
00461 
00462   std::stringstream ss;
00463   ss << buf.str();
00464 
00465   InputProviderPtr ip(new InputProvider);
00466   ip->addStreamInput(ss, "testinput");
00467   ModuleHexParser parser;
00468   BOOST_REQUIRE_NO_THROW(parser.parse(ip, ctx));
00469 
00470   LOG_REGISTRY_PROGRAM(ctx);
00471 
00472   MLPSyntaxChecker sC(ctx);
00473   //rmv. BOOST_REQUIRE( sC.verifySyntax() == false );
00474   BOOST_REQUIRE_THROW(sC.verifySyntax(), FatalError);
00475 }
00476 
00477 
00478 // test case for module call with different order of arity
00479 // for example: @p3[q, r]::even, where q is predicate with arity 1 and r is a predicate with arity 0
00480 // but we have #module(p3, [s/0, t/1]).
00481 BOOST_AUTO_TEST_CASE(testSwapArityPredInputsModuleCalls) 
00482 {
00483   ProgramCtx ctx;
00484   ctx.setupRegistry(RegistryPtr(new Registry));
00485 
00486   char *TOP_SRCDIR = getenv("TOP_SRCDIR");
00487   assert(TOP_SRCDIR != 0);
00488 
00489   std::string filename1(TOP_SRCDIR);
00490   std::ifstream ifs;
00491   std::ostringstream buf;
00492   filename1 += "/examples/module3-SwapArity.mlp";
00493 
00494   ifs.open(filename1.c_str());
00495   BOOST_REQUIRE(ifs.is_open());
00496   buf << ifs.rdbuf();
00497   ifs.close();
00498 
00499   std::string filename2(TOP_SRCDIR);
00500   filename2 += "/examples/module2-SwapArity.mlp";
00501   ifs.open(filename2.c_str());
00502   BOOST_REQUIRE(ifs.is_open());
00503   buf << ifs.rdbuf();
00504   ifs.close();
00505 
00506   std::stringstream ss;
00507   ss << buf.str();
00508 
00509   InputProviderPtr ip(new InputProvider);
00510   ip->addStreamInput(ss, "testinput");
00511   ModuleHexParser parser;
00512   BOOST_REQUIRE_NO_THROW(parser.parse(ip, ctx));
00513 
00514   LOG_REGISTRY_PROGRAM(ctx);
00515 
00516   MLPSyntaxChecker sC(ctx);
00517   //rmv. BOOST_REQUIRE( sC.verifySyntax() == false );
00518   BOOST_REQUIRE_THROW(sC.verifySyntax(), FatalError);
00519 }
00520 
00521 
00522 
00523 
00524 /* TODO handle this?
00525 // test case if the predicate inputs specified in the module header have a different arity
00526 // with the one in the module body
00527 BOOST_AUTO_TEST_CASE(testDifferentArityModuleHeader) 
00528 {
00529   ProgramCtx ctx;
00530   ctx.registry = RegistryPtr(new Registry);
00531 
00532   std::string filename1 = "../../examples/module1-DiffArity.mlp";
00533   std::ifstream ifs;
00534   std::ostringstream buf;
00535 
00536   ifs.open(filename1.c_str());
00537   BOOST_REQUIRE(ifs.is_open());
00538   buf << ifs.rdbuf();
00539   ifs.close();
00540 
00541   std::stringstream ss;
00542   ss << buf.str();
00543 
00544   HexParser parser(ctx);
00545   BOOST_REQUIRE_NO_THROW(parser.parse(ss));
00546   LOG_REGISTRY_PROGRAM(ctx);
00547 
00548   MLPSyntaxChecker sC(ctx);
00549   BOOST_REQUIRE( sC.verifySyntax() == false );
00550 }
00551 */
00552 
00553 /*
00554 BOOST_AUTO_TEST_CASE(testDuplicateModuleHeader) 
00555 {
00556   ProgramCtx ctx;
00557   ctx.setupRegistry(RegistryPtr(new Registry));
00558 
00559   std::string filename1 = "../../examples/module1.mlp";
00560   std::ifstream ifs;
00561   std::ostringstream buf;
00562 
00563   ifs.open(filename1.c_str());
00564   BOOST_REQUIRE(ifs.is_open());
00565   buf << ifs.rdbuf();
00566   buf << ifs.rdbuf();
00567   ifs.close();
00568 
00569   std::stringstream ss;
00570   ss << buf.str();
00571 
00572   HexParser parser(ctx);
00573   BOOST_CHECK_THROW(parser.parse(ss), SyntaxError);
00574 }
00575 
00576 BOOST_AUTO_TEST_CASE(EndMessage) 
00577 {
00578   std::cout << "[TestHexParserModule::BOOST_AUTO_TEST_CASE(EndMessage)] *** 1 failure ( from BOOST_AUTO_TEST_CASE(testDuplicateModuleHeader) ) is expected *** " <<std::endl; 
00579 }
00580 */
00581