main(int argc, char** argv) #endif { if ( argc < 2 ) { std::cout << "\nusage: testdriver [testfile_1] [testfile_2] ..." << std::endl; return 1; } int errors; Specification lSpec; std::string lModulePath; // Instantiate the store and the zorba query processor void* store = zorba::StoreManager::getStore(); if (store == NULL) return 20; zorba::Zorba * engine = zorba::Zorba::getInstance(store); if (engine == NULL) return 21; int i = 1; while (i < argc) { // std::cout << "i: " << i << ", argc: " << argc << std::endl; if (strcmp (argv [i], "--rbkt-src") == 0) { rbkt_src_dir = argv [i + 1]; i += 2; } else if (strcmp (argv [i], "--rbkt-bin") == 0) { rbkt_bin_dir = argv [i + 1]; i += 2; } else if (strcmp (argv [i], "--module-path") == 0) { lModulePath = argv [i + 1]; i += 2; } else break; } zorba::XQuery_t lQuery; TestDiagnosticHandler errHandler; DriverContext driverContext(engine); driverContext.theRbktSourceDir = rbkt_src_dir; driverContext.theRbktBinaryDir = rbkt_bin_dir; driverContext.theSpec = &lSpec; for (int testcnt = 1; i < argc; ++i, ++testcnt) { std::string lQueryFile( rbkt_src_dir ); zorba::fs::append( lQueryFile, "Queries" ); zorba::fs::append( lQueryFile, argv[i] ); #ifndef ZORBA_TEST_PLAN_SERIALIZATION_EXECUTION_ONLY if ( zorba::fs::get_type( lQueryFile ) != zorba::fs::file ) { std::cout << "\n query file " << lQueryFile << " does not exist or is not a file" << std::endl; return 2; } #endif /* ZORBA_TEST_PLAN_SERIALIZATION_EXECUTION_ONLY */ // Check if this is w3c_testsuite test. std::string path = lQueryFile; bool isW3CXQTStest = path.find( "w3c_testsuite" ) != std::string::npos; bool isW3CFTtest = path.find( "w3c_full_text_testsuite" ) != std::string::npos; bool isW3Ctest = isW3CFTtest || isW3CXQTStest; std::string lQueryWithoutSuffix = std::string(argv[i]).substr( 0, std::string(argv[i]).rfind('.') ); std::unique_ptr<zorba::TestSchemaURIMapper> smapper; std::unique_ptr<zorba::TestModuleURIMapper> mmapper; std::unique_ptr<zorba::TestCollectionURIMapper> cmapper; std::unique_ptr<zorba::TestSchemeURIMapper> dmapper; std::unique_ptr<zorba::TestURLResolver> tresolver; // Create the static context. If this is a w3c query, install special uri // resolvers in the static context. zorba::StaticContext_t lContext = engine->createStaticContext(); if ( isW3Ctest ) { #ifndef MY_D_WIN32 std::string w3cDataDir = "/Queries/w3c_testsuite/TestSources/"; #else std::string w3cDataDir = "/Queries/TestSources/"; #endif std::string uri_map_file = rbkt_src_dir + w3cDataDir + "uri.txt"; std::string mod_map_file = rbkt_src_dir + w3cDataDir + "module.txt"; std::string col_map_file = rbkt_src_dir + w3cDataDir + "collection.txt"; smapper.reset(new zorba::TestSchemaURIMapper(uri_map_file.c_str())); mmapper.reset(new zorba::TestModuleURIMapper (mod_map_file.c_str(), lQueryWithoutSuffix)); cmapper.reset( new zorba::TestCollectionURIMapper(driverContext.theXmlDataMgr, col_map_file.c_str(), rbkt_src_dir)); addURIMapper(driverContext, lContext, smapper.get() ); addURIMapper(driverContext, lContext, mmapper.get() ); addURIMapper(driverContext, lContext, cmapper.get() ); // the w3c testsuite always uses xquery 1.0 lContext->setXQueryVersion( zorba::xquery_version_1_0 ); zorba::Item lEnable = engine->getItemFactory()->createQName( "http://zorba.io/options/features", "", "enable"); zorba::Item lDisable = engine->getItemFactory()->createQName( "http://zorba.io/options/features", "", "disable"); lContext->declareOption(lDisable, "scripting"); } // Form the full pathname for the files that will receive the result or the // errors of this query. Then, delete these files if they exist already from // previous runs of the query. Finaly, create (if necessary) all the dirs // in the pathname of the result and error files. std::cout << "test " << lQueryWithoutSuffix << std::endl; #ifndef ZORBA_TEST_PLAN_SERIALIZATION_COMPILE_ONLY std::string lResultFile( rbkt_bin_dir ); zorba::fs::append( lResultFile, "QueryResults" ); zorba::fs::append( lResultFile, lQueryWithoutSuffix ); lResultFile += ".xml.res"; zorba::fs::remove( lResultFile, true ); // Form the full pathname for the .spec file that may be associated // with this query. If the .spec file exists, read its contents to // extract args to be passed to the query (e.g., external var bindings), // exprected errors, or the pathnames of reference-result files. std::string lSpecFile( rbkt_src_dir ); zorba::fs::append( lSpecFile, "Queries" ); zorba::fs::append( lSpecFile, lQueryWithoutSuffix ); lSpecFile += ".spec"; if ( zorba::fs::get_type( lSpecFile ) ) { bool lParsed = lSpec.parseFile(lSpecFile, rbkt_src_dir, rbkt_bin_dir); if (!lParsed) { std::cout << "Spec file " << lSpecFile << " is malformed!" << std::endl; return 1; } } // If --enable-uritestresolver is specified, enable our document // URI resolver for test:// scheme URIs as well as a silly URLResolver if (lSpec.getEnableUriTestResolver()) { dmapper.reset(new zorba::TestSchemeURIMapper(rbkt_src_dir)); addURIMapper(driverContext, lContext, dmapper.get()); tresolver.reset(new zorba::TestURLResolver()); addURLResolver(driverContext, lContext, tresolver.get()); } // Bind any options from the .spec file to the static context setOptions(driverContext, lContext); // Bind any full-text URI resolvers from the .spec file to the // static context setFullTextURIMappers(driverContext, lContext); // If command-line argument --module-path passed, set up module paths. setModulePaths(lModulePath, lContext); // Get the pathnames of the reference-result files found in the .spec // file (if any). std::vector<std::string> lRefFiles; bool lRefFileExists = false; for (std::vector<std::string>::const_iterator lIter = lSpec.resultsBegin(); lIter != lSpec.resultsEnd(); ++lIter) { std::string lRefFile(*lIter); if ( zorba::fs::get_type( lRefFile ) ) { lRefFileExists = true; } else { std::cout << "Warning: missing reference result file " << lRefFile << std::endl; } lRefFiles.push_back(lRefFile); } // If no ref-results file was specified in the .spec file, create a default // finename for that file. For w3c tests, the ref file is the same for // xqueryx and xquery tests, hence, we remove the string xqueryx or xquery // from the path if (lRefFiles.size () == 0) { std::string lRefFileTmpString = lQueryWithoutSuffix; if (isW3Ctest) { size_t pos = lQueryWithoutSuffix.find("XQueryX"); if (pos != std::string::npos) lRefFileTmpString = lRefFileTmpString.erase(pos, 8); pos = lQueryWithoutSuffix.find("XQuery"); if (pos != std::string::npos) lRefFileTmpString = lRefFileTmpString.erase(pos, 7); } std::string lRefFile( rbkt_src_dir ); zorba::fs::append( lRefFile, "ExpQueryResults" ); zorba::fs::append( lRefFile, lRefFileTmpString ); lRefFile += ".xml.res"; lRefFiles.push_back( lRefFile ); if ( zorba::fs::get_type( lRefFiles[0] ) ) lRefFileExists = true; } #endif//ZORBA_TEST_PLAN_SERIALIZATION_COMPILE_ONLY #ifndef ZORBA_TEST_PLAN_SERIALIZATION_EXECUTION_ONLY // print the query std::cout << "=== Query: ===" << std::endl; zorba::printFile(std::cout, lQueryFile); std::cout << "=== end of Query ===" << std::endl; #endif // Stopwatch starts now // QQQ this should use util/time.h #ifndef WIN32 struct timeval start_time, end_time; gettimeofday(&start_time, NULL); #else clock_t start_time, end_time; start_time = clock(); #endif #ifndef ZORBA_TEST_PLAN_SERIALIZATION_EXECUTION_ONLY // create and compile the query std::string lQueryString; slurp_file(lQueryFile.c_str(), lQueryString, rbkt_src_dir, rbkt_bin_dir); lQuery = engine->createQuery(&errHandler); lQuery->setFileName(lQueryFile); bool lJSONiqMode = (lQueryFile.rfind(".jq") == lQueryFile.size() - 3); if (lJSONiqMode) lContext->setJSONiqVersion(zorba::jsoniq_version_1_0); lQuery->compile(lQueryString.c_str(), lContext, getCompilerHints()); errors = -1; if ( errHandler.errors() ) { errors = analyzeError (lSpec, errHandler); if( errors == UNEXPECTED_ERROR ) return 6; std::cout << "testdriver: success" << std::endl; continue; } // no compilation errors #ifdef ZORBA_TEST_PLAN_SERIALIZATION try { clock_t t0, t1; std::string binary_path; binary_path = rbkt_bin_dir + "/QueryResults/" + lQueryWithoutSuffix + ".plan"; t0 = clock(); std::ofstream fbinary(binary_path.c_str(), std::ios_base::binary); if(!lQuery->saveExecutionPlan(fbinary)) { printf("save execution plan FAILED\n"); return 0x0badc0de; } fbinary.close(); t1 = clock(); printf("save execution plan in %f sec\n", (float)(t1-t0)/CLOCKS_PER_SEC); } catch(zorba::ZorbaException &err) { std::cout << err << std::endl; return -1; } #endif // ZORBA_TEST_PLAN_SERIALIZATION #endif // #ifndef ZORBA_TEST_PLAN_SERIALIZATION_EXECUTION_ONLY #ifndef ZORBA_TEST_PLAN_SERIALIZATION_COMPILE_ONLY #ifdef ZORBA_TEST_PLAN_SERIALIZATION try { clock_t t0, t1; std::string binary_path; binary_path = rbkt_bin_dir + "/QueryResults/" + lQueryWithoutSuffix + ".plan"; lQuery = engine->createQuery (&errHandler); t0 = clock(); std::ifstream ifbinary(binary_path.c_str(), std::ios_base::binary); if(!ifbinary.is_open()) { std::cout << "cannot open plan " << binary_path << std::endl; return 15; } bool load_ret; zorba::TestSerializationCallback serl_callback(driverContext.theURIMappers, driverContext.theURLResolvers); load_ret = lQuery->loadExecutionPlan(ifbinary, &serl_callback); if(!load_ret) { std::cout << "cannot load plan " << binary_path << std::endl; return 16; } t1 = clock(); printf("load execution plan in %f sec\n", (float)(t1-t0)/CLOCKS_PER_SEC); } catch(zorba::ZorbaException &err) { std::cout << err << std::endl; return -1; } #endif // Create dynamic context and set in it the external variables, the current // date & time, and the timezone. createDynamicContext(driverContext, lContext, lQuery, lSpec.getEnableDtd(), errHandler); Zorba_SerializerOptions lSerOptions; if (errHandler.errors()) { errors = analyzeError (lSpec, errHandler); } else { errors = -1; { // serialize xml/txt std::ofstream lResFileStream(lResultFile.c_str()); assert (lResFileStream.good()); // QQQ all this code should be in testdriver_common and used by // testdriver_mt as well // Initialize default serialization method lSerOptions.ser_method = ZORBA_SERIALIZATION_METHOD_JSON_XML_HYBRID; lSerOptions.omit_xml_declaration = ZORBA_OMIT_XML_DECLARATION_YES; // Now set any options specified in .spec file std::vector<Specification::Option>::const_iterator lIter; for (lIter = lSpec.serializerOptionsBegin(); lIter != lSpec.serializerOptionsEnd(); ++lIter) { try { lSerOptions.set(lIter->theOptName.c_str(), lIter->theOptValue.c_str()); } catch ( std::exception const &e ) { std::cerr << e.what() << std::endl; return -1; } } lQuery->execute(lResFileStream, &lSerOptions); } // Stopwatch ends here #ifndef WIN32 gettimeofday(&end_time, NULL); #else end_time = clock(); #endif if (! lRefFileExists ) { if (lSpec.getComparisonMethod() == "Ignore") { std::cout << "Since the comparison method is set to 'Ignore' the test is considered successful." << std::endl; return 0; } if(lSpec.errorsSize() == 0) { std::cout << "No reference result and no expected errors." << std::endl; return 3; } } if (errHandler.errors()) { errors = analyzeError (lSpec, errHandler); } else if ( lSpec.errorsSize() > 0 ) { if ( ! lRefFileExists ) { std::cout << "Expected error(s)"; for (std::vector<std::string>::const_iterator lIter = lSpec.errorsBegin(); lIter != lSpec.errorsEnd(); ++lIter) { std::cout << " " << *lIter; } zorba::fs::info fs_info; if ( zorba::fs::get_type( lResultFile, &fs_info ) && !fs_info.size ) { std::cout << " but got empty result" << std::endl; } else { std::cout << " but got result:" << std::endl; zorba::printFile(std::cout, lResultFile); std::cout << "=== end of result ===" << std::endl; } return 7; } } } if( errors == UNEXPECTED_ERROR) { return 6; } else if( errors == -1 ) { std::cout << "=== Result: ===" << std::endl; zorba::printFile(std::cout, lResultFile); std::cout << "=== end of result ===" << std::endl; std::cout.flush(); size_t i = 1; bool lResultMatches = false; for (std::vector<std::string>::const_iterator lIter = lRefFiles.begin(); lIter != lRefFiles.end(); ++lIter) { int lLine, lCol; // where do the files differ std::string lRefLine, lResultLine; bool lRes = zorba::fileEquals(lIter->c_str(), lResultFile.c_str(), lLine, lCol, lRefLine, lResultLine); if (lRes) { std::cout << "testdriver: success (non-canonical result # " << i << " matches)" << std::endl; lResultMatches = true; break; } std::cout << "testdriver: non-canonical result for reference result # " << i << " doesn't match." << std::endl; // Don't attempt canonical comparison for test cases using --indent; // can lead to false positives. if (lSerOptions.indent == ZORBA_INDENT_YES) { std::cout << "testdriver: skipping canonicalization " "when testing with indent==yes" << std::endl; } // Also skip canonicalization for tests using method==xhtml or html // (so we can test for correct serialization of empty elements) else if (lSerOptions.ser_method == ZORBA_SERIALIZATION_METHOD_XHTML || lSerOptions.ser_method == ZORBA_SERIALIZATION_METHOD_HTML) { std::cout << "testdriver: skipping canonicalization " "when testing with method=[x]html" << std::endl; } // Also skip canonicalization for tests using method==json else if (lSerOptions.ser_method == ZORBA_SERIALIZATION_METHOD_JSON) { std::cout << "testdriver: skipping canonicalization " "when testing with method=json" << std::endl; } else { int lCanonicalRes = zorba::canonicalizeAndCompare(lSpec.getComparisonMethod(), lIter->c_str(), lResultFile.c_str()); if (lCanonicalRes == 0) { std::cout << "testdriver: success (canonical result # " << i << " matches)" << std::endl; lResultMatches = true; break; } std::cout << "testdriver: canonical result for reference result # " << i << " doesn't match." << std::endl; } ++i; } // for if (!lResultMatches) { std::cout << "testdriver: none of the reference results matched" << std::endl; return 8; } } // Check timing // QQQ only do this if .spec file says to #ifndef WIN32 long mstime = ( (end_time.tv_sec - start_time.tv_sec) * 1000000 + (end_time.tv_usec - start_time.tv_usec) ); #else long mstime = (long)(((double)(end_time - start_time)) / CLOCKS_PER_SEC * 1000000); #endif std::cout << "testdriver: test runtime was " << mstime << "us" << std::endl; #endif//ifndef ZORBA_TEST_PLAN_SERIALIZATION_COMPILE_ONLY } // for (int testcnt = 1; i < argc; ++i, ++testcnt) std::cout << "testdriver: success" << std::endl; return 0; }
main(int argc, char** argv) #endif { if (argc != 2) { std::cout << "\nusage: testdriver [testfile]" << std::endl; return 1; } zorba::Zorba* engine = zorba::Zorba::getInstance(zorba::StoreManager::getStore()); zorba::XmlDataManager_t xmlDataMgr = engine->getXmlDataManager(); Specification lSpec; /* * Sanitize paths */ std::string srcDir = zorba::fs::normalize_path(zorba::UPDATE_SRC_DIR); std::string binDir = zorba::fs::normalize_path(zorba::UPDATE_BINARY_DIR); std::string argString = zorba::fs::normalize_path(std::string(argv[1])); std::string lSpecNoSuffix = argString.substr(0, argString.size()-5); std::string lSpecFile( srcDir ); zorba::fs::append( lSpecFile, "Queries" ); zorba::fs::append(lSpecFile, argString); std::string lSpecPath( zorba::fs::dir_name( lSpecFile ) ); if ( zorba::fs::get_type( lSpecFile ) != zorba::fs::file ) { std::cout << "\n spec file " << lSpecFile << " does not exist or is not a file" << std::endl; return 2; } std::cout << "test " << lSpecNoSuffix << std::endl; std::string lResultFile( binDir ); zorba::fs::append( lResultFile, "QueryResults" ); zorba::fs::append( lResultFile, lSpecNoSuffix ); lResultFile += ".res"; std::string lRefFile( srcDir ); zorba::fs::append( lRefFile, "ExpectedTestResults" ); zorba::fs::append( lRefFile, lSpecNoSuffix ); lRefFile += ".xml.res"; std::string lRefPath( zorba::fs::dir_name( lRefFile ) ); // read the xargs and errors if the spec file exists lSpec.parseFile(lSpecFile); Zorba_SerializerOptions lSerOptions; lSerOptions.omit_xml_declaration = ZORBA_OMIT_XML_DECLARATION_YES; std::unique_ptr<zorba::TestSchemaURIMapper> smapper; ulong numQueries = (ulong)lSpec.theStates.size(); // // For each query in the spec file // for(ulong curQuery = 0; curQuery < numQueries; ++curQuery) { State* lState = lSpec.theStates[curQuery]; zorba::XQuery_t lQuery; // // Open the query file // std::string qname_str; if(lSpecPath.find("XQueryX") == std::string::npos) qname_str = lState->theName + ".xq"; else qname_str = lState->theName + ".xqx"; std::cout << "query name = " << qname_str << std::endl; std::string lQueryFile(lSpecPath); zorba::fs::append( lQueryFile, qname_str ); std::cout << std::endl << "Query (Run " << curQuery+1 << "):" << std::endl; std::cout << "Query file " << lQueryFile << ": " << std::endl; zorba::printFile(std::cout, lQueryFile); std::cout << std::endl; std::ifstream lQueryStream(lQueryFile.c_str()); // // Create static context and set it up. // Create and compile the query object. // try { zorba::StaticContext_t lContext = engine->createStaticContext(); std::string path = lQueryFile; if (path.find("w3c_update_testsuite") != std::string::npos) { lContext->setXQueryVersion(zorba::xquery_version_1_0); std::string uri_map_file = zorba::fs::normalize_path(srcDir + "/Queries/w3c_update_testsuite/TestSources/uri.txt"); smapper.reset(new zorba::TestSchemaURIMapper( uri_map_file.c_str() )); lContext->registerURIMapper( smapper.get() ); zorba::Item lEnable = engine->getItemFactory()-> createQName("http://zorba.io/options/features", "", "enable"); zorba::Item lDisable = engine->getItemFactory()-> createQName("http://zorba.io/options/features", "", "disable"); lContext->declareOption(lDisable, "scripting"); #if 1 if (path.find("Val") != std::string::npos) lContext->setBoundarySpacePolicy(zorba::preserve_space); #endif #if 1 zorba::String lProlog = zorba::String(std::string("import schema 'http://www.w3.org/XML/1998/namespace';\n")); lContext->loadProlog(lProlog, getCompilerHints()); #endif } lQuery = engine->createQuery(); lQuery->setFileName (lQueryFile.c_str()); lQuery->compile(lQueryStream, lContext, getCompilerHints()); #ifdef ZORBA_TEST_PLAN_SERIALIZATION int save_retval; if((save_retval = save_load_plan(engine, lQuery, smapper.get(), lResultFile))) { return save_retval; } #endif } catch (zorba::ZorbaException &e) { if (isErrorExpected(e, lState)) { std::cout << "Expected compiler error:\n" << e << std::endl; std::cout << "updtestdriver: success" << std::endl; return 0; } else { std::cout << "Unexpected compiler error:\n" << e << std::endl; return 3; } } // // // try { zorba::DynamicContext* lDynCtx = lQuery->getDynamicContext(); if (lState->hasDate) { std::string lDateTime = lState->theDate; if (lDateTime.find("T") == std::string::npos) { lDateTime += "T00:00:00"; } lDynCtx->setCurrentDateTime(engine->getItemFactory()->createDateTime(lDateTime)); } std::vector<Variable*>::const_iterator lVarIter = lState->varsBegin(); std::vector<Variable*>::const_iterator lVarEnd = lState->varsEnd(); for(; lVarIter != lVarEnd; ++lVarIter) { Variable* lVar = *lVarIter; set_var( lVar->theInline, lVar->theName, lVar->theValue, xmlDataMgr.get(), lQuery->getStaticContext(), lDynCtx); } } catch (zorba::ZorbaException &e) { if (isErrorExpected(e, lState)) { std::cout << "Expected execution error:\n" << e << std::endl; continue; } else { std::cout << "Unexpected execution error:\n" << e << std::endl; return 6; } } // // // try { zorba::fs::remove( lResultFile, true ); std::ofstream lResFileStream(lResultFile.c_str()); lQuery->execute(lResFileStream, &lSerOptions); lResFileStream.flush(); if (lState->hasCompare) { bool lRes = false; bool anyMatch = false; ulong numRefs = (ulong)lState->theCompares.size(); for (ulong i = 0; i < numRefs && !lRes; i++) { std::string lRefFileTmpString = lRefPath; // the ref file is the same for xqueryx and xquery tests // hence, we remove the string xqueryx or xquery from the path size_t lPosOfW3C = lRefPath.find("w3c_update_testsuite"); if (lPosOfW3C != std::string::npos) { if (lRefPath.find("XQueryX", lPosOfW3C) != std::string::npos) lRefFileTmpString = lRefFileTmpString.erase(lPosOfW3C + 21, 8); else lRefFileTmpString = lRefFileTmpString.erase(lPosOfW3C + 21, 7); } std::string lRefFile( lRefFileTmpString ); zorba::fs::append( lRefFile, lState->theCompares[i] ); std::cout << std::endl << "Ref " << lRefFile << std::endl; int lLine, lCol; std::string lRefLine, lResultLine; lRes = zorba::fileEquals(lRefFile.c_str(), lResultFile.c_str(), lLine, lCol, lRefLine, lResultLine); // if the simple comparison doesn't work, we do the full-fledged // xml canonical comparison if (lRes) { std::cout << std::endl; std::cout << "updtestdriver: success (non-canonical result matches)" << std::endl; anyMatch = true; break; } else { std::cout << std::endl; std::cout << "Actual and Reference results are not identical" << std::endl << std::endl << "Actual Result " << lResultFile << ": " << std::endl << std::endl; zorba::printFile(std::cout, lResultFile); std::cout << std::endl << "Reference Result " << lRefFile << ": " << std::endl << std::endl; zorba::printFile(std::cout, lRefFile); std::cout << std::endl << std::endl; int lCanonicalRes = zorba::canonicalizeAndCompare(State::compareTypeStr(lState->theCompareTypes[i]), lRefFile.c_str(), lResultFile.c_str()); if (lCanonicalRes == 0) { anyMatch = true; break; } } } // multiple compare possible if (!anyMatch) { return 4; } } else if (lState->hasErrors && curQuery == numQueries-1) { std::cout << std::endl; std::cout << "Query must throw an error!" << std::endl; return 5; } else { std::cout << std::endl; std::cout << "Query returns result but no expected result defined!" << std::endl; zorba::printFile(std::cout, lResultFile); } } catch (zorba::ZorbaException &e) { if (isErrorExpected(e, lState)) { std::cout << std::endl; std::cout << "Expected execution error:\n" << e << std::endl; continue; } else { std::cout << std::endl; std::cout << "Unexpected execution error:\n" << e << std::endl; return 6; } } } // for each query described in the spec file std::cout << std::endl; std::cout << "updtestdriver: success" << std::endl; return 0; }