| /* |
| * Copyright 1999-2004 The Apache Software Foundation. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "XalanFileUtility.hpp" |
| |
| |
| |
| #include <cstdlib> |
| #include <cstdio> |
| #include <ctime> |
| #include <vector> |
| #include <climits> |
| #include <cstring> |
| |
| #if defined(WIN32) |
| #include <direct.h> |
| #define PATH_MAX _MAX_PATH |
| #define chdir _chdir |
| #define getcwd _getcwd |
| #define mkdir _mkdir |
| #else |
| #if !defined(PATH_MAX) |
| #define PATH_MAX 2000 |
| #endif |
| #define DIR_MODE_BITS 509 |
| #include <dirent.h> |
| #include <unistd.h> |
| |
| #include <sys/stat.h> |
| #endif |
| |
| |
| #if defined(XALAN_CLASSIC_IOSTREAMS) |
| #include <iostream.h> |
| #include <strstream.h> |
| #else |
| #include <iostream> |
| #include <strstream> |
| #endif |
| |
| #if !defined(NDEBUG) && defined(_MSC_VER) |
| #include <crtdbg.h> |
| #endif |
| |
| |
| |
| #include "xercesc/sax/SAXException.hpp" |
| |
| |
| |
| #include "xalanc/PlatformSupport/DirectoryEnumerator.hpp" |
| #include "xalanc/PlatformSupport/DOMStringHelper.hpp" |
| #include "xalanc/PlatformSupport/XalanOutputStreamPrintWriter.hpp" |
| #include "xalanc/PlatformSupport/XalanFileOutputStream.hpp" |
| #include "xalanc/PlatformSupport/XalanUnicode.hpp" |
| |
| |
| |
| #include "xalanc/XMLSupport/FormatterToXML.hpp" |
| #include "xalanc/XMLSupport/FormatterTreeWalker.hpp" |
| |
| |
| |
| #include "xalanc/XalanSourceTree/XalanSourceTreeDOMSupport.hpp" |
| #include "xalanc/XalanSourceTree/XalanSourceTreeParserLiaison.hpp" |
| #include "xalanc/XalanSourceTree/XalanSourceTreeDocument.hpp" |
| |
| |
| |
| #include "xalanc/XSLT/StylesheetRoot.hpp" |
| |
| |
| |
| #include "xalanc/XalanTransformer/XalanCompiledStylesheet.hpp" |
| #include "xalanc/XalanTransformer/XalanTransformer.hpp" |
| |
| |
| |
| #include "XalanXMLFileReporter.hpp" |
| |
| |
| |
| XALAN_CPP_NAMESPACE_BEGIN |
| |
| |
| |
| |
| const char* const xalanNodeTypes[] = |
| { |
| "UNKNOWN_NODE", |
| "ELEMENT_NODE", |
| "ATTRIBUTE_NODE", |
| "TEXT_NODE", |
| "CDATA_SECTION_NODE", |
| "ENTITY_REFERENCE_NODE", |
| "ENTITY_NODE", |
| "PROCESSING_INSTRUCTION_NODE", |
| "COMMENT_NODE", |
| "DOCUMENT_NODE", |
| "DOCUMENT_TYPE_NODE", |
| "DOCUMENT_FRAGMENT_NODE", |
| "NOTATION_NODE" |
| }; |
| |
| |
| |
| XALAN_USING_STD(cerr) |
| XALAN_USING_STD(cout) |
| XALAN_USING_STD(endl) |
| |
| |
| const XalanDOMString XalanFileUtility::s_emptyString; |
| |
| |
| |
| XalanFileUtility::reportStruct::reportStruct() : |
| theDrive(), |
| testOrFile(), |
| xmlFileURL(), |
| xslFileURL(), |
| xmlFormat(), |
| msg(0), |
| currentNode(), |
| actual(), |
| expected(), |
| pass(0), |
| fail(0), |
| nogold(0) |
| { |
| } |
| |
| |
| |
| void |
| XalanFileUtility::reportStruct::reset() |
| { |
| clear(testOrFile); |
| msg = ""; |
| clear(currentNode); |
| clear(actual); |
| clear(expected); |
| } |
| |
| |
| |
| XalanFileUtility::cmdParams::cmdParams() : |
| help(), |
| base(), |
| output(), |
| gold(), |
| sub(), |
| source(0), |
| skip(false), |
| iters(0) |
| { |
| } |
| |
| |
| |
| const char* |
| XalanFileUtility::cmdParams::getHelpMessage() |
| { |
| help << '\0'; |
| |
| const char* const data = help.str(); |
| |
| #if defined(HPUX) |
| help.rdbuf() -> freeze(false); |
| #else |
| help.freeze(false); |
| #endif |
| |
| return data; |
| } |
| |
| |
| |
| XalanFileUtility::XalanFileUtility() : |
| data(), |
| args() |
| { |
| cout << endl |
| << "Using Xalan version " |
| << XALAN_FULLVERSIONDOT |
| << endl |
| << "Using Xerces version " |
| << XERCES_FULLVERSIONDOT |
| << endl |
| << endl; |
| } |
| |
| |
| |
| XalanFileUtility::~XalanFileUtility() |
| { |
| } |
| |
| |
| |
| #if !defined(WIN32) |
| XalanDOMString |
| XalanFileUtility::getDrive() |
| { |
| return XalanDOMString(); |
| } |
| #else |
| XalanDOMString |
| XalanFileUtility::getDrive() |
| { |
| const char temp[] = |
| { |
| char(_getdrive() + 'A' - 1), |
| ':', |
| '\0' |
| }; |
| |
| return XalanDOMString(temp, sizeof(temp) - 1); |
| } |
| #endif |
| |
| |
| bool |
| XalanFileUtility::getParams( |
| int argc, |
| char* argv[], |
| const char* outDir, |
| bool fsetGold) |
| { |
| bool fSuccess = true; // Used to continue argument loop |
| bool fsetOut = true; // Set default output directory, set to false if data is provided |
| |
| args.skip = true; // Default values for performance testing parameters. |
| args.iters = 3; |
| |
| // Insure that required "-base" argument is there. |
| // |
| if (argc == 1 || argv[1][0] == '-') |
| { |
| cout << args.getHelpMessage(); |
| return false; |
| } |
| else |
| { |
| if (checkDir(XalanDOMString(argv[1]))) |
| { |
| assign(args.base, XalanDOMString(argv[1])); |
| } |
| else |
| { |
| cout << endl << "Given base directory \"" << argv[1] << "\" does not exist" << endl; |
| cout << args.getHelpMessage(); |
| return false; |
| } |
| } |
| |
| // Get the rest of the arguments. |
| // |
| for (int i = 2; i < argc && fSuccess == true; ++i) |
| { |
| if(!stricmp("-out", argv[i])) |
| { |
| ++i; |
| if(i < argc && argv[i][0] != '-') |
| { |
| assign(args.output, XalanDOMString(argv[i])); |
| append(args.output, s_pathSep); |
| checkAndCreateDir(args.output); |
| fsetOut = false; |
| } |
| else |
| { |
| cout << args.getHelpMessage(); |
| fSuccess = false; |
| } |
| } |
| else if(!stricmp("-gold", argv[i])) |
| { |
| ++i; |
| if(i < argc && argv[i][0] != '-') |
| { |
| assign(args.gold, XalanDOMString(argv[i])); |
| |
| if ( !checkDir(args.gold) ) |
| { |
| cout << "Given Gold dir - " << c_str(TranscodeToLocalCodePage(args.gold)) << " - does not exist" << endl; |
| fSuccess = false; |
| } |
| |
| append(args.gold, s_pathSep); |
| fsetGold = false; |
| } |
| else |
| { |
| cout << args.getHelpMessage(); |
| fSuccess = false; |
| } |
| } |
| else if(!stricmp("-source", argv[i])) |
| { |
| ++i; |
| if(i < argc && argv[i][0] != '-') |
| { |
| if (stricmp(argv[i],"XPL") == 0) |
| { |
| args.source = 1; |
| outDir = "DOM-XALAN"; |
| } |
| else if (stricmp(argv[i], "DOM") == 0) |
| { |
| args.source = 2; |
| outDir = "DOM-XERCES"; |
| } |
| else |
| { |
| cout << args.getHelpMessage(); |
| fSuccess = false; |
| } |
| } |
| else |
| { |
| cout << args.getHelpMessage(); |
| fSuccess = false; |
| } |
| } |
| else if(!stricmp("-sub", argv[i])) |
| { |
| ++i; |
| if(i < argc && argv[i][0] != '-') |
| { |
| assign(args.sub, XalanDOMString(argv[i])); |
| } |
| else |
| { |
| cout << args.getHelpMessage(); |
| fSuccess = false; |
| } |
| } |
| else if(!stricmp("-i", argv[i])) |
| { |
| args.skip = false; |
| } |
| else if(!stricmp("-iter", argv[i])) |
| { |
| ++i; |
| |
| // Make sure number is there and is greater then zero |
| if(i < argc && atol(argv[i]) > 0) |
| { |
| args.iters = atol(argv[i]); |
| } |
| else |
| { |
| cout << args.getHelpMessage(); |
| fSuccess = false; |
| } |
| } |
| else |
| { |
| cout << args.getHelpMessage(); |
| fSuccess = false; |
| } |
| |
| } // End of for-loop |
| |
| // Do we need to set the default output directory?? |
| // |
| if (fsetOut) |
| { |
| unsigned int ii = lastIndexOf(args.base, s_pathSep[0]); |
| |
| if (ii < length(args.base)) |
| { |
| args.output.assign(args.base, 0, ii + 1); |
| } |
| |
| append(args.output,XalanDOMString(outDir)); |
| checkAndCreateDir(args.output); |
| append(args.output,s_pathSep); |
| |
| } |
| // Do we need to set the default gold directory?? |
| // |
| if (fsetGold) |
| { |
| args.gold = args.base; |
| append(args.gold,XalanDOMString("-gold")); |
| if ( !checkDir(args.gold) ) |
| { |
| cout << "Assumed Gold dir - " << c_str(TranscodeToLocalCodePage(args.gold)) << " - does not exist" << endl; |
| fSuccess = false; |
| } |
| append(args.gold,s_pathSep); |
| } |
| |
| // Add the path seperator to the end of the base directory |
| // here after we've finished using it for all directory creation. |
| // |
| append(args.base,s_pathSep); |
| |
| return fSuccess; |
| } |
| |
| |
| |
| // This routine retrieves test file names from specified directories. |
| // Inputs: baseDir: typically "conf" or "perf" |
| // relDir: sub-directory to search. |
| // |
| // Notes: It builds the searchSpecification by concatenating all the |
| // necessary components. |
| // |
| XalanFileUtility::FileNameVectorType |
| XalanFileUtility::getTestFileNames( |
| const XalanDOMString& baseDir, |
| const XalanDOMString& relDir, |
| bool useDirPrefix) |
| { |
| char buffer3[PATH_MAX]; |
| getcwd(buffer3, PATH_MAX); |
| |
| const XalanDOMString searchSuffix(XALAN_STATIC_UCODE_STRING("*.xsl")); |
| XalanDOMString searchSpecification; |
| |
| // Allow directory search w/o mandating files start with directory name. Required for files |
| // garnered from XSLTMARK performance directory exm. |
| if (useDirPrefix) |
| { |
| assign(searchSpecification, baseDir + relDir + s_pathSep + relDir + searchSuffix); |
| } |
| else |
| { |
| assign(searchSpecification, baseDir + relDir + s_pathSep + searchSuffix); |
| } |
| |
| |
| DirectoryEnumeratorFunctor<FileNameVectorType, XalanDOMString> theEnumerator; |
| FileNameVectorType theFiles; |
| theEnumerator(searchSpecification, theFiles); |
| |
| chdir(buffer3); |
| |
| return theFiles; |
| } |
| |
| /* This routine retrieves all sub-directories from the specified directories. |
| // Inputs: rootDirectory: typically "conf" or "perf" |
| // |
| // Notes: The searchSpecification in this case is just "*". |
| // */ |
| XalanFileUtility::FileNameVectorType |
| XalanFileUtility::getDirectoryNames(const XalanDOMString& rootDirectory) |
| { |
| char buffer2[PATH_MAX]; |
| getcwd(buffer2, PATH_MAX); |
| |
| const XalanDOMString dirSpec(XALAN_STATIC_UCODE_STRING("*")); |
| |
| DirectoryEnumeratorFunctor<FileNameVectorType, XalanDOMString, DirectoryFilterPredicate> theEnumerator; |
| FileNameVectorType theFiles; |
| theEnumerator(XalanDOMString(rootDirectory), XalanDOMString(dirSpec), theFiles); |
| |
| chdir(buffer2); |
| |
| return theFiles; |
| } |
| |
| |
| bool XalanFileUtility::checkDir(const XalanDOMString& directory ) |
| { |
| char buffer[PATH_MAX]; |
| |
| getcwd(buffer, PATH_MAX); |
| |
| bool fResult = false; |
| |
| if ( !chdir(c_str(TranscodeToLocalCodePage(directory))) ) |
| { |
| fResult = true; |
| } |
| |
| chdir(buffer); |
| |
| return fResult; |
| } |
| |
| |
| void XalanFileUtility::checkAndCreateDir(const XalanDOMString& directory) |
| { |
| char buffer[PATH_MAX]; |
| |
| getcwd(buffer, PATH_MAX); |
| |
| if ( (chdir(c_str(TranscodeToLocalCodePage(directory)))) ) |
| { |
| //cout << "Couldn't change to " << directory << ", will create it." << endl; |
| #if defined(WIN32) |
| if ( !mkdir(c_str(TranscodeToLocalCodePage(directory)))) |
| #else |
| if ( !mkdir(c_str(TranscodeToLocalCodePage(directory)), DIR_MODE_BITS)) |
| #endif |
| { |
| cout << directory << " created." << endl; |
| } |
| else |
| { |
| cout << directory << " NOT created." << endl; |
| } |
| } |
| |
| chdir(buffer); |
| } |
| |
| /* This routine generates file names based on the provide suffix |
| // Inputs: theXMLFileName: typically "conf" or "perf" |
| // suffix: typically "xsl" or "out". |
| // |
| // Notes: |
| */ |
| |
| XalanDOMString |
| XalanFileUtility::generateFileName( |
| const XalanDOMString& theXMLFileName, |
| const char* suffix, |
| bool* status) |
| { |
| XalanDOMString targetFile; |
| int thePeriodIndex = -1; |
| const int theLength = length(theXMLFileName); |
| |
| for (int i = theLength - 1; i > 0; i--) |
| { |
| if (charAt(theXMLFileName, i) == XalanUnicode::charFullStop) |
| { |
| thePeriodIndex = i; // charFullStop is the dot (x2E) |
| break; |
| } |
| } |
| |
| if (thePeriodIndex != -1) |
| { |
| targetFile.assign(theXMLFileName, 0, thePeriodIndex + 1); |
| |
| targetFile += XalanDOMString(suffix); |
| } |
| |
| // Check the .xml file exists. |
| if (!strcmp(suffix,"xml")) |
| { |
| FILE* fileHandle = fopen(c_str(TranscodeToLocalCodePage(targetFile)), "r"); |
| if (fileHandle == 0) |
| { |
| cout << "TEST ERROR: File Missing: " << targetFile << endl; |
| |
| if (status != 0) |
| { |
| *status = false; |
| } |
| } |
| else |
| { |
| fclose(fileHandle); |
| } |
| } |
| |
| return targetFile; |
| } |
| |
| |
| /* This routine generates a Unique Runid. |
| // Inputs: None |
| // |
| // Notes: The format is mmddhhmm. For example |
| // 03151046 is "Mar 15 10:46" |
| */ |
| |
| XalanDOMString |
| XalanFileUtility::generateUniqRunid() |
| { |
| #if defined(XALAN_STRICT_ANSI_HEADERS) |
| using std::tm; |
| using std::time; |
| using std::localtime; |
| using std::strftime; |
| #endif |
| |
| struct tm *newtime; |
| time_t long_time; |
| char tmpbuf[10]; |
| |
| time( &long_time ); /* Get time as long integer. */ |
| newtime = localtime( &long_time ); /* Convert to local time. */ |
| |
| strftime( tmpbuf, 10,"%m%d%H%M",newtime ); |
| |
| return XalanDOMString(tmpbuf); |
| } |
| |
| |
| // This routine gets Xerces Version number. It's used to put the Xerces Version |
| // into the output xml results file as an attribute of 'PerfData' element. |
| // Inputs: None |
| // |
| |
| XalanDOMString |
| XalanFileUtility::getXercesVersion() |
| { |
| |
| return XalanDOMString(gXercesFullVersionStr); |
| } |
| |
| /* This routine creates a FormatterToXML FormatterListener. This is used to format |
| // the output DOM so a comparision can be done with the expected GOLD file. |
| // Inputs: None |
| // |
| */ |
| |
| |
| FormatterListener* |
| XalanFileUtility::getXMLFormatter( |
| PrintWriter& resultWriter, |
| int indentAmount, |
| const XalanDOMString& mimeEncoding, |
| const StylesheetRoot* stylesheet) |
| { |
| XalanDOMString version; |
| bool outputIndent= 0; |
| XalanDOMString mediatype; |
| XalanDOMString doctypeSystem; |
| XalanDOMString doctypePublic; |
| XalanDOMString standalone; |
| |
| if (stylesheet != 0) |
| { |
| version = stylesheet->getOutputVersion(); |
| |
| mediatype = stylesheet->getOutputMediaType(); |
| doctypeSystem = stylesheet->getOutputDoctypeSystem(); |
| doctypePublic = stylesheet->getOutputDoctypePublic(); |
| standalone = stylesheet->getOutputStandalone(); |
| outputIndent = stylesheet->getOutputIndent(); |
| } |
| |
| return new FormatterToXML( |
| resultWriter, |
| version, |
| outputIndent, |
| indentAmount, |
| mimeEncoding, |
| mediatype, |
| doctypeSystem, |
| doctypePublic, |
| true, // xmlDecl |
| standalone); |
| } |
| |
| |
| /* This routine is used to compares the results of a transform and report the results. |
| // When a failure is detected the 'data' structure used to report detailed info about |
| // a failure is filled in. |
| // Inputs: |
| // goldFile - Name of gold file |
| // outputFile - Name of result file. |
| // logfile - Name of log file reporter. |
| // |
| // Returns: |
| // Void |
| */ |
| void |
| XalanFileUtility::checkResults( |
| const XalanDOMString& outputFile, |
| const XalanDOMString& goldFile, |
| XalanXMLFileReporter& logfile) |
| { |
| int ambgFlag = data.nogold; // get the current number of tests w/o gold files. |
| |
| // Compare the results, report success if compareSerializedResults returns true. |
| if(compareSerializedResults(outputFile, goldFile)) |
| { |
| cout << "Passed: " << data.testOrFile << endl; |
| logfile.logCheckPass(data.testOrFile); |
| data.pass += 1; |
| } |
| else |
| { |
| typedef XalanXMLFileReporter::Hashtable Hashtable; |
| |
| // if the compairson fails gather up the failure data and determine if it failed |
| // due to bad output or missing Gold file. Lastly, log the failure. |
| Hashtable attrs; |
| Hashtable actexp; |
| |
| reportError(); |
| |
| attrs.insert(Hashtable::value_type(XalanDOMString("reason"), XalanDOMString(data.msg))); |
| attrs.insert(Hashtable::value_type(XalanDOMString("atNode"), data.currentNode)); |
| actexp.insert(Hashtable::value_type(XalanDOMString("exp"), data.expected)); |
| actexp.insert(Hashtable::value_type(XalanDOMString("act"), data.actual)); |
| |
| actexp.insert(Hashtable::value_type(XalanDOMString("xsl"), data.xslFileURL)); |
| actexp.insert(Hashtable::value_type(XalanDOMString("xml"), data.xmlFileURL)); |
| actexp.insert(Hashtable::value_type(XalanDOMString("result"), outputFile)); |
| actexp.insert(Hashtable::value_type(XalanDOMString("gold"), goldFile)); |
| |
| if (ambgFlag < data.nogold) |
| { |
| logfile.logCheckAmbiguous(data.testOrFile); |
| } |
| else |
| { |
| logfile.logCheckFail(data.testOrFile, attrs, actexp); |
| } |
| } |
| } |
| |
| void |
| XalanFileUtility::checkAPIResults( |
| const XalanDOMString& actual, |
| const XalanDOMString& expected, |
| const char* msg, |
| XalanXMLFileReporter& logfile, |
| const XalanDOMString& outputFile, |
| const XalanDOMString& goldFile, |
| bool containsOnly) |
| { |
| if(actual == expected || |
| (containsOnly == true && indexOf(actual, expected) != XalanDOMString::npos)) |
| { |
| data.pass += 1; |
| cout << "Passed: " << data.testOrFile << endl; |
| logfile.logCheckPass(data.testOrFile); |
| } |
| else |
| { data.actual = actual; |
| data.expected = expected; |
| data.currentNode = "API Test"; |
| data.msg = msg; |
| data.fail += 1; |
| |
| reportError(); |
| |
| typedef XalanXMLFileReporter::Hashtable Hashtable; |
| |
| Hashtable actexp; |
| |
| actexp.insert(Hashtable::value_type(XalanDOMString("exp"), expected)); |
| actexp.insert(Hashtable::value_type(XalanDOMString("act"), actual)); |
| actexp.insert(Hashtable::value_type(XalanDOMString("xsl"), data.xslFileURL)); |
| actexp.insert(Hashtable::value_type(XalanDOMString("xml"), data.xmlFileURL)); |
| actexp.insert(Hashtable::value_type(XalanDOMString("result"), outputFile)); |
| actexp.insert(Hashtable::value_type(XalanDOMString("gold"), goldFile)); |
| |
| // Todo: Need to determine if I should check for missing gold in these cases. |
| logfile.logCheckFail(data.testOrFile, actexp); |
| } |
| } |
| |
| |
| |
| /* This routine compares the results of a transform with the gold file. |
| // It in turn call the domCompare routine to do the actual comparision. |
| // Inputs: |
| // gold - Dom tree for the expected results |
| // doc - Dom tree created during transformation |
| // filename - Current filename |
| // |
| // Returns: |
| // Void |
| // |
| */ |
| void |
| XalanFileUtility::checkDOMResults( |
| const XalanDOMString& theOutputFile, |
| const XalanCompiledStylesheet* compiledSS, |
| const XalanSourceTreeDocument* dom, |
| const XSLTInputSource& goldInputSource, |
| XalanXMLFileReporter& logfile) |
| { |
| const int ambgFlag = data.nogold; |
| |
| const XalanDOMString mimeEncoding(""); |
| |
| XalanFileOutputStream myOutput(theOutputFile); |
| XalanOutputStreamPrintWriter myResultWriter(myOutput); |
| |
| FormatterListener* const theFormatter = |
| getXMLFormatter( |
| myResultWriter, |
| 0, |
| mimeEncoding, |
| compiledSS->getStylesheetRoot()); |
| |
| FormatterTreeWalker theTreeWalker(*theFormatter); |
| |
| theTreeWalker.traverse(dom); |
| |
| delete theFormatter; |
| |
| XalanSourceTreeDOMSupport domSupport; |
| XalanSourceTreeParserLiaison parserLiaison(domSupport); |
| |
| domSupport.setParserLiaison(&parserLiaison); |
| |
| const XalanDocument* const goldDom = |
| parserLiaison.parseXMLStream(goldInputSource); |
| |
| if(domCompare(*goldDom, *dom)) |
| { |
| cout << "Passed: " << data.testOrFile << endl; |
| logfile.logCheckPass(data.testOrFile); |
| data.pass += 1; |
| } |
| else |
| { |
| typedef XalanXMLFileReporter::Hashtable Hashtable; |
| |
| // if the compairson fails gather up the failure data and determine if it failed |
| // due to bad output or missing Gold file. Lastly, log the failure. |
| Hashtable attrs; |
| Hashtable actexp; |
| |
| reportError(); |
| |
| attrs.insert(Hashtable::value_type(XalanDOMString("reason"), XalanDOMString(data.msg))); |
| attrs.insert(Hashtable::value_type(XalanDOMString("atNode"), data.currentNode)); |
| actexp.insert(Hashtable::value_type(XalanDOMString("exp"), data.expected)); |
| actexp.insert(Hashtable::value_type(XalanDOMString("act"), data.actual)); |
| |
| if (ambgFlag < data.nogold) |
| { |
| logfile.logCheckAmbiguous(data.testOrFile); |
| } |
| else |
| { |
| logfile.logCheckFail(data.testOrFile, attrs, actexp); |
| } |
| } |
| } |
| |
| /* This routine takes the result file and gold file and parses them. |
| // If either of the files fails to parse and a SAXException is throw, |
| // then the files are compared using a char by char file compare, |
| // otherwise the domCompare routine is used. |
| // Inputs: |
| // outputFile: Name of result file |
| // goldFile: Name of gold file |
| // |
| // Returns: |
| // True or False |
| // |
| */ |
| bool |
| XalanFileUtility::compareSerializedResults( |
| const XalanDOMString& outputFile, |
| const XalanDOMString& goldFile) |
| { |
| |
| const XSLTInputSource resultInputSource(outputFile); |
| const XSLTInputSource goldInputSource(goldFile); |
| |
| XalanSourceTreeDOMSupport domSupport; |
| XalanSourceTreeParserLiaison parserLiaison(domSupport); |
| |
| domSupport.setParserLiaison(&parserLiaison); |
| |
| try |
| { |
| const XalanDocument* const transformDom = |
| parserLiaison.parseXMLStream(resultInputSource); |
| assert(transformDom != 0); |
| |
| const XalanDocument* const goldDom = |
| parserLiaison.parseXMLStream(goldInputSource); |
| assert(goldDom != 0); |
| |
| return domCompare(*goldDom, *transformDom); |
| } |
| // This exception is being reported prior to this Catch, however, however, I clarify that it's a SAX exception. |
| // It's a good indication that the Gold file is not a valid XML. When this happens the transform result needs |
| // to be compared with the Gold, with a character by character basis, not via the DOM compair. |
| catch (const XERCES_CPP_NAMESPACE_QUALIFIER SAXException&) |
| { |
| cout << "SAXException: Using fileCompare to check output.\n"; |
| |
| return fileCompare(c_str(TranscodeToLocalCodePage(goldFile)), c_str(TranscodeToLocalCodePage(outputFile))); |
| } |
| |
| } |
| |
| |
| |
| static void |
| replaceNonAsciiCharacters( |
| char* theBuffer, |
| char theReplacementChar) |
| { |
| while(*theBuffer) |
| { |
| if (unsigned(*theBuffer) > 127) |
| { |
| *theBuffer = theReplacementChar; |
| } |
| |
| ++theBuffer; |
| } |
| } |
| |
| |
| |
| /* This routine is used to compare the results against the gold when one or both of |
| // fails to parse without throwing a SAXException. When a failure is detected the 'data' |
| // structure used to report detailed info about a failure is filled in. |
| // Inputs: |
| // outputFile: Name of result file |
| // goldFile: Name of gold file |
| // |
| // Returns: |
| // True or False |
| // |
| */ |
| bool |
| XalanFileUtility::fileCompare( |
| const char* goldFile, |
| const char* outputFile) |
| { |
| const unsigned long maxBuffer = 132; |
| |
| char rline[maxBuffer] = {'0'}; // declare buffers to hold single line from file |
| char gline[maxBuffer] = {'0'}; |
| char temp[10]; // buffer to hold line number |
| char lineNum = 1; |
| |
| // Set fail data incase there are i/o problems with the files to compare. |
| data.expected = XalanDOMString(" "); |
| data.actual = XalanDOMString(" "); |
| data.currentNode = XalanDOMString("Line: 0"); |
| |
| // Attempt to open the files. |
| FILE* const result = fopen(outputFile, "r"); |
| FILE* const gold = fopen(goldFile, "r"); |
| |
| // If the result file fails to open report this as a failure. |
| if (!result) |
| { |
| data.msg = "No Result (Transform failed)"; |
| data.fail += 1; |
| return false; |
| } |
| |
| // If the gold file fails to open report this as ambiguous. |
| if (!gold) |
| { |
| data.msg = "No Gold file"; |
| data.nogold += 1; |
| return false; |
| } |
| |
| // Start file comparison, line by line.. |
| while(!feof(result) && !feof(gold)) |
| { |
| fgets(gline, sizeof(gline), gold ); |
| fgets(rline, sizeof(rline), result ); |
| sprintf(temp,"%d",lineNum); |
| |
| if (ferror(gold) || ferror(result)) |
| { |
| data.msg = "Read Error - Gold/Result file"; |
| data.currentNode = XalanDOMString("Line: ") + XalanDOMString(temp); |
| return false; |
| } |
| |
| // Compare the lines character by charcter .... |
| unsigned int i = 0; |
| while(i < strlen(gline)) |
| { |
| if (gline[i] == rline[i]) |
| { |
| i++; |
| } |
| else |
| { // If there is a mismatch collect up the fail data and return false. To ensure that |
| // the results can be seen in the browser enclose the actual/expected in CDATA Sections. |
| |
| // Replace any non-ASCII characters. Otherwise, we would have to encode them |
| // in UTF-8, which is a huge pain. |
| replaceNonAsciiCharacters(gline, '?'); |
| replaceNonAsciiCharacters(rline, '?'); |
| |
| data.msg = "Text based comparison failure"; |
| data.expected = XalanDOMString("<![CDATA[") + XalanDOMString(gline) + XalanDOMString("]]>"); |
| data.actual = XalanDOMString("<![CDATA[") + XalanDOMString(rline) + XalanDOMString("]]>"); |
| data.currentNode = XalanDOMString("Line: ") + XalanDOMString(temp); |
| data.fail += 1; |
| fclose(result); fclose(gold); |
| return false; |
| } |
| } |
| |
| lineNum += 1; |
| } |
| fclose(result); fclose(gold); |
| return true; |
| } |
| |
| |
| |
| /* This routine performs a DOM Comparision. |
| // Inputs: |
| // gold - Dom tree for the expected results |
| // doc - Dom tree created during transformation |
| // filename - Current filename |
| // |
| // Returns: |
| // True or False |
| // |
| */ |
| bool |
| XalanFileUtility::domCompare( |
| const XalanNode& gold, |
| const XalanNode& doc) |
| { |
| const XalanNode::NodeType docNodeType = doc.getNodeType(); |
| const XalanNode::NodeType goldNodeType = gold.getNodeType(); |
| |
| const XalanDOMString& docNodeName = doc.getNodeName(); |
| |
| if (goldNodeType != docNodeType) |
| { |
| collectData("NodeType mismatch.", |
| docNodeName, |
| XalanDOMString(xalanNodeTypes[docNodeType]), |
| XalanDOMString(xalanNodeTypes[goldNodeType])); |
| |
| return false; |
| } |
| |
| switch (goldNodeType) |
| { |
| case XalanNode::ELEMENT_NODE: // ATTRIBUTE_NODEs are processed with diffElement(). |
| { |
| if (diffElement(gold, doc) == false) |
| { |
| return false; |
| } |
| } |
| break; |
| |
| case XalanNode::CDATA_SECTION_NODE: |
| case XalanNode::TEXT_NODE: |
| { |
| const XalanDOMString& docNodeValue = doc.getNodeValue(); |
| const XalanDOMString& goldNodeValue = gold.getNodeValue(); |
| |
| //debugNodeData(docNodeName, docNodeValue); |
| |
| if(goldNodeValue != docNodeValue) |
| { |
| collectData("Text node mismatch. ", |
| docNodeName, |
| goldNodeValue, |
| docNodeValue); |
| return false; |
| } |
| } |
| break; |
| |
| case XalanNode::PROCESSING_INSTRUCTION_NODE: |
| { |
| const XalanDOMString& goldNodeName = gold.getNodeName(); |
| |
| if (goldNodeName != docNodeName) |
| { |
| collectData("processing-instruction target mismatch. ", |
| docNodeName, |
| goldNodeName, |
| docNodeName); |
| |
| return false; |
| } |
| else |
| { |
| const XalanDOMString& docNodeValue = doc.getNodeValue(); |
| const XalanDOMString& goldNodeValue = gold.getNodeValue(); |
| |
| if (goldNodeValue != docNodeValue) |
| { |
| collectData("processing-instruction data mismatch. ", |
| docNodeName, |
| goldNodeValue, |
| docNodeValue); |
| |
| return false; |
| } |
| } |
| } |
| break; |
| |
| case XalanNode::COMMENT_NODE: |
| { |
| const XalanDOMString& docNodeValue = doc.getNodeValue(); |
| const XalanDOMString& goldNodeValue = gold.getNodeValue(); |
| |
| if (goldNodeValue != docNodeValue) |
| { |
| collectData("comment data mismatch. ", |
| docNodeName, |
| goldNodeValue, |
| docNodeValue); |
| |
| return false; |
| } |
| } |
| break; |
| |
| case XalanNode::DOCUMENT_NODE: |
| { |
| //debugNodeData(docNodeName); |
| |
| const XalanNode *goldNextNode; |
| const XalanNode *domNextNode; |
| |
| goldNextNode = gold.getFirstChild(); |
| domNextNode = doc.getFirstChild(); |
| |
| if (0 != goldNextNode) |
| { |
| if(domCompare(*goldNextNode,*domNextNode) == false) |
| { |
| return false; |
| } |
| } |
| } |
| break; |
| |
| case XalanNode::ENTITY_REFERENCE_NODE: |
| case XalanNode::ENTITY_NODE: |
| case XalanNode::DOCUMENT_TYPE_NODE: |
| case XalanNode::DOCUMENT_FRAGMENT_NODE: |
| case XalanNode::NOTATION_NODE: |
| default: |
| cerr << "Unexpected node type: " << goldNodeType << endl; |
| |
| return false; |
| } |
| |
| // Need to process siblings. Children are processed in diffElement, since |
| // only they can have children in the XPath data model. |
| const XalanNode* const goldNextNode = gold.getNextSibling(); |
| const XalanNode* const domNextNode = doc.getNextSibling(); |
| |
| if (0 != goldNextNode) |
| { |
| if (0 != domNextNode) |
| { |
| if (domCompare(*goldNextNode, *domNextNode) == false) |
| { |
| return false; |
| } |
| } |
| else |
| { |
| collectData("Missing sibling node. ", |
| docNodeName, |
| goldNextNode->getNodeName(), |
| goldNextNode->getNodeName()); |
| |
| return false; |
| } |
| } |
| else if (0 != domNextNode) |
| { |
| collectData("Extra sibling node. ", |
| docNodeName, |
| domNextNode->getNodeName(), |
| domNextNode->getNodeName()); |
| |
| return false; |
| } |
| |
| return true; |
| } |
| |
| |
| |
| bool |
| XalanFileUtility::domCompare( |
| const XalanDocument& gold, |
| const XalanDocument& doc) |
| { |
| const XalanNode* theGoldPos = &gold; |
| const XalanNode* theDocPos = &doc; |
| |
| bool fEqual = true; |
| |
| do |
| { |
| fEqual = diffNode(theGoldPos, theDocPos); |
| |
| if (fEqual == true) |
| { |
| assert(theGoldPos != 0 && theDocPos != 0); |
| |
| const XalanNode* nextGoldNode = theGoldPos->getFirstChild(); |
| const XalanNode* nextDocNode = theDocPos->getFirstChild(); |
| |
| bool fBreak = false; |
| |
| while( |
| nextGoldNode == 0 && |
| nextDocNode == 0 && |
| fBreak == false) |
| { |
| // Move to the next sibling of each node, |
| // since we would get here only if both have |
| // no children. |
| nextGoldNode = theGoldPos->getNextSibling(); |
| nextDocNode = theDocPos->getNextSibling(); |
| |
| // If there is no next sibling, move up to the |
| // parent. If one, but not both, has a sibling, |
| // we'll end up back at the top of the do/while |
| // loop and the difference will be reported. |
| if(0 == nextGoldNode && 0 == nextDocNode) |
| { |
| theGoldPos = theGoldPos->getParentNode(); |
| theDocPos = theDocPos->getParentNode(); |
| |
| // If the parent is null, then we've reached |
| // the end of the document. Note that if we |
| // got here, then there must also be a parent |
| // node in the document we're verifying, so we |
| // could simply assert that theDocPos is either |
| // null if theGoldPos is null, or it is not-null |
| // if theGoldPos is not-null. |
| if(0 == theGoldPos) |
| { |
| nextGoldNode = theGoldPos; |
| |
| fBreak = true; |
| } |
| |
| if(0 == theDocPos) |
| { |
| nextDocNode = theDocPos; |
| |
| fBreak = true; |
| } |
| } |
| } |
| |
| theGoldPos = nextGoldNode; |
| theDocPos = nextDocNode; |
| } |
| } while((theGoldPos != 0 || theDocPos != 0) && fEqual == true); |
| |
| |
| return fEqual; |
| } |
| |
| |
| |
| bool |
| XalanFileUtility::diffNode( |
| const XalanNode& gold, |
| const XalanNode& doc) |
| { |
| const XalanNode::NodeType docNodeType = doc.getNodeType(); |
| const XalanNode::NodeType goldNodeType = gold.getNodeType(); |
| |
| const XalanDOMString& docNodeName = doc.getNodeName(); |
| |
| if (goldNodeType != docNodeType) |
| { |
| collectData("NodeType mismatch.", |
| docNodeName, |
| XalanDOMString(xalanNodeTypes[docNodeType]), |
| XalanDOMString(xalanNodeTypes[goldNodeType])); |
| |
| return false; |
| } |
| |
| switch (goldNodeType) |
| { |
| case XalanNode::ELEMENT_NODE: // ATTRIBUTE_NODEs are processed with diffElement(). |
| return diffElement2(gold, doc); |
| break; |
| |
| case XalanNode::CDATA_SECTION_NODE: |
| case XalanNode::TEXT_NODE: |
| { |
| const XalanDOMString& docNodeValue = doc.getNodeValue(); |
| const XalanDOMString& goldNodeValue = gold.getNodeValue(); |
| |
| //debugNodeData(docNodeName, docNodeValue); |
| |
| if(goldNodeValue != docNodeValue) |
| { |
| collectData("Text node mismatch. ", |
| docNodeName, |
| goldNodeValue, |
| docNodeValue); |
| return false; |
| } |
| } |
| break; |
| |
| case XalanNode::PROCESSING_INSTRUCTION_NODE: |
| { |
| const XalanDOMString& goldNodeName = gold.getNodeName(); |
| |
| if (goldNodeName != docNodeName) |
| { |
| collectData("processing-instruction target mismatch. ", |
| docNodeName, |
| goldNodeName, |
| docNodeName); |
| |
| return false; |
| } |
| else |
| { |
| const XalanDOMString& docNodeValue = doc.getNodeValue(); |
| const XalanDOMString& goldNodeValue = gold.getNodeValue(); |
| |
| if (goldNodeValue != docNodeValue) |
| { |
| collectData("processing-instruction data mismatch. ", |
| docNodeName, |
| goldNodeValue, |
| docNodeValue); |
| |
| return false; |
| } |
| } |
| } |
| break; |
| |
| case XalanNode::COMMENT_NODE: |
| { |
| const XalanDOMString& docNodeValue = doc.getNodeValue(); |
| const XalanDOMString& goldNodeValue = gold.getNodeValue(); |
| |
| if (goldNodeValue != docNodeValue) |
| { |
| collectData("comment data mismatch. ", |
| docNodeName, |
| goldNodeValue, |
| docNodeValue); |
| |
| return false; |
| } |
| } |
| break; |
| |
| case XalanNode::DOCUMENT_NODE: |
| break; |
| |
| case XalanNode::ENTITY_REFERENCE_NODE: |
| case XalanNode::ENTITY_NODE: |
| case XalanNode::DOCUMENT_TYPE_NODE: |
| case XalanNode::DOCUMENT_FRAGMENT_NODE: |
| case XalanNode::NOTATION_NODE: |
| default: |
| cerr << "Unexpected node type: " << goldNodeType << endl; |
| |
| return false; |
| } |
| |
| return true; |
| } |
| |
| |
| |
| bool |
| XalanFileUtility::diffNode( |
| const XalanNode* gold, |
| const XalanNode* doc) |
| { |
| if (gold != 0 && doc != 0) |
| { |
| return diffNode(*gold, *doc); |
| } |
| else if (gold != 0) |
| { |
| const XalanNode* const parent = |
| gold->getParentNode(); |
| |
| collectData( |
| "Missing sibling node. ", |
| parent == 0 ? s_emptyString : parent->getNodeName(), |
| s_emptyString, |
| gold->getNodeName()); |
| |
| return false; |
| } |
| else |
| { |
| assert(doc != 0 && gold == 0); |
| |
| const XalanNode* const parent = |
| doc->getParentNode(); |
| |
| collectData( |
| "Extra sibling node. ", |
| parent == 0 ? s_emptyString : parent->getNodeName(), |
| doc->getNodeName(), |
| s_emptyString); |
| |
| return false; |
| } |
| } |
| |
| |
| |
| /* This routine compares two element nodes. |
| // Inputs: |
| // gold - Dom tree for the expected results |
| // doc - Dom tree created during transformation |
| // filename - Current filenam |
| // |
| // Returns: |
| // True or False |
| // |
| */ |
| |
| bool |
| XalanFileUtility::diffElement( |
| const XalanNode& gold, |
| const XalanNode& doc) |
| { |
| assert(gold.getNodeType() == XalanNode::ELEMENT_NODE); |
| assert(gold.getNodeType() == XalanNode::ELEMENT_NODE); |
| |
| const XalanDOMString& docNodeName = doc.getNodeName(); |
| const XalanDOMString& goldNodeName = gold.getNodeName(); |
| |
| const XalanDOMString& docNsUri = doc.getNamespaceURI(); |
| const XalanDOMString& goldNsUri = gold.getNamespaceURI(); |
| |
| //debugNodeData(docNodeName); |
| |
| // This essentially checks 2 things, that the prefix and localname are the |
| // same. So specific checks of these items are not necessary. |
| if (goldNodeName != docNodeName) |
| { |
| collectData("Element mismatch. ", |
| docNodeName, |
| goldNodeName, |
| docNodeName); |
| return false; |
| } |
| |
| if ( goldNsUri != docNsUri) |
| { |
| collectData("Element NamespaceURI mismatch. ", |
| docNodeName, |
| goldNsUri, |
| docNsUri); |
| return false; |
| } |
| |
| // Get Attributes for each Element Node. |
| const XalanNamedNodeMap* const goldAttrs = gold.getAttributes(); |
| const XalanNamedNodeMap* const docAttrs = doc.getAttributes(); |
| |
| // Get number of Attributes |
| const unsigned int numGoldAttr = goldAttrs->getLength(); |
| const unsigned int numDomAttr = docAttrs ->getLength(); |
| |
| /* |
| // This needs to be uncommented if 'compare.exe' is to work. |
| // If this is the 'root' element strip off the xmlns:xml namespace attribute, |
| // that is lurking around on the gold file, but not the dom. This is necessary |
| // only for the 'compare' test, that uses a pure DOM, that has not been serialized. |
| //if (goldNodeName == XalanDOMString("root")) |
| { |
| numGoldAttr -= 1; |
| XalanNode *gXMLAttr = goldAttrs->item(1); |
| } |
| */ |
| // Check that each Element has same number of Attributes. If they don't report error |
| if ( numGoldAttr == numDomAttr ) |
| { |
| // Compare Attributes one at a time. |
| //for (int i=1; i < numGoldAttr; i++) // To be used with 'compare' |
| for (unsigned int i = 0; i < numGoldAttr; ++i) |
| { |
| // Attribute order is irrelvant, so comparision is base on Attribute name. |
| const XalanNode* const gAttr = goldAttrs->item(i); |
| const XalanDOMString& goldAttrName = gAttr->getNodeName(); |
| |
| const XalanNode* const dAttr = docAttrs->getNamedItem(goldAttrName); |
| |
| if (dAttr != 0) |
| { |
| if( ! (diffAttr(gAttr, dAttr)) ) |
| return false; |
| } |
| else |
| { |
| collectData("Element missing named Attribute. ", |
| docNodeName, |
| goldAttrName, |
| XalanDOMString("NOTHING")); |
| |
| return false; |
| } |
| } |
| } |
| else |
| { |
| char buf1[2], buf2[2]; |
| sprintf(buf1, "%u", numGoldAttr); |
| sprintf(buf2, "%u", numDomAttr); |
| collectData("Wrong number of attributes. ", |
| docNodeName, |
| XalanDOMString(buf1), |
| XalanDOMString(buf2)); |
| return false; |
| } |
| |
| const XalanNode* goldNextNode = gold.getFirstChild(); |
| const XalanNode* domNextNode = doc.getFirstChild(); |
| |
| if (0 != goldNextNode) |
| { |
| if (0 != domNextNode) |
| { |
| if ( ! domCompare(*goldNextNode, *domNextNode) ) |
| return false; |
| } |
| else |
| { |
| collectData("Element missing ChildNode. ", |
| docNodeName, |
| XalanDOMString(goldNextNode->getNodeName()), |
| XalanDOMString("NOTHING")); |
| return false; |
| } |
| } |
| else if (domNextNode != 0) |
| { |
| // The result doc has additional Children. If the additional node is a text node |
| // then gather up the text and print it out. |
| if ( domNextNode->getNodeType() == XalanNode::TEXT_NODE) |
| { |
| collectData("Result has additional Child node: ", |
| docNodeName, |
| XalanDOMString("NOTHING"), |
| XalanDOMString(domNextNode->getNodeName()) + XalanDOMString(" \"") + |
| XalanDOMString(domNextNode->getNodeValue()) + XalanDOMString("\"")); |
| } |
| // Additional node is NOT text, so just print it's Name. |
| else |
| { |
| collectData("Result has additional Child node: ", |
| docNodeName, |
| XalanDOMString("NOTHING"), |
| XalanDOMString(domNextNode->getNodeName())); |
| |
| } |
| return false; |
| |
| } |
| |
| return true; |
| } |
| |
| |
| bool |
| XalanFileUtility::diffElement2( |
| const XalanNode& gold, |
| const XalanNode& doc) |
| { |
| assert(gold.getNodeType() == XalanNode::ELEMENT_NODE); |
| assert(gold.getNodeType() == XalanNode::ELEMENT_NODE); |
| |
| const XalanDOMString& docNodeName = doc.getNodeName(); |
| const XalanDOMString& goldNodeName = gold.getNodeName(); |
| |
| const XalanDOMString& docNsUri = doc.getNamespaceURI(); |
| const XalanDOMString& goldNsUri = gold.getNamespaceURI(); |
| |
| //debugNodeData(docNodeName); |
| |
| // This essentially checks 2 things, that the prefix and localname are the |
| // same. So specific checks of these items are not necessary. |
| if (goldNodeName != docNodeName) |
| { |
| collectData("Element mismatch. ", |
| docNodeName, |
| goldNodeName, |
| docNodeName); |
| return false; |
| } |
| |
| if ( goldNsUri != docNsUri) |
| { |
| collectData("Element NamespaceURI mismatch. ", |
| docNodeName, |
| goldNsUri, |
| docNsUri); |
| return false; |
| } |
| |
| // Get Attributes for each Element Node. |
| const XalanNamedNodeMap* const goldAttrs = gold.getAttributes(); |
| assert(goldAttrs != 0); |
| |
| const XalanNamedNodeMap* const docAttrs = doc.getAttributes(); |
| assert(docAttrs != 0); |
| |
| // Get number of Attributes |
| const unsigned int numGoldAttr = goldAttrs->getLength(); |
| const unsigned int numDomAttr = docAttrs ->getLength(); |
| |
| // Check that each Element has same number of Attributes. If they don't report error |
| if ( numGoldAttr == numDomAttr ) |
| { |
| // Compare Attributes one at a time. |
| //for (int i=1; i < numGoldAttr; i++) // To be used with 'compare' |
| for (unsigned int i = 0; i < numGoldAttr; ++i) |
| { |
| // Attribute order is irrelvant, so comparision is base on Attribute name. |
| const XalanNode* const gAttr = goldAttrs->item(i); |
| const XalanDOMString& goldAttrName = gAttr->getNodeName(); |
| |
| const XalanNode* const dAttr = docAttrs->getNamedItem(goldAttrName); |
| |
| if (dAttr != 0) |
| { |
| if( ! (diffAttr(gAttr, dAttr)) ) |
| return false; |
| } |
| else |
| { |
| collectData("Element missing named Attribute. ", |
| docNodeName, |
| goldAttrName, |
| XalanDOMString("NOTHING")); |
| |
| return false; |
| } |
| } |
| } |
| else |
| { |
| char buf1[2], buf2[2]; |
| sprintf(buf1, "%u", numGoldAttr); |
| sprintf(buf2, "%u", numDomAttr); |
| collectData("Wrong number of attributes. ", |
| docNodeName, |
| XalanDOMString(buf1), |
| XalanDOMString(buf2)); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| |
| /* This routine compares two attribute nodes. |
| // Inputs: |
| // gAttr - attribute from Gold dom tree |
| // dAttr - attribute from Dom tree created during transformation |
| // fileName - Current filenam |
| // |
| // Returns: |
| // True or False |
| // |
| */ |
| |
| bool XalanFileUtility::diffAttr(const XalanNode* gAttr, const XalanNode* dAttr) |
| { |
| |
| const XalanDOMString& docAttrName = dAttr->getNodeName(); |
| |
| //debugAttributeData(goldAttrName); |
| |
| const XalanDOMString& goldAttrValue = gAttr->getNodeValue(); |
| const XalanDOMString& docAttrValue = dAttr->getNodeValue(); |
| |
| if (goldAttrValue != docAttrValue) |
| { |
| collectData( |
| "Attribute Value mismatch. ", |
| docAttrName, |
| goldAttrValue, |
| docAttrValue); |
| |
| return false; |
| } |
| |
| const XalanDOMString& goldAttrNsUri = gAttr->getNamespaceURI(); |
| const XalanDOMString& docAttrNsUri = dAttr->getNamespaceURI(); |
| |
| if (goldAttrNsUri != docAttrNsUri) |
| { |
| collectData( |
| "Attribute NamespaceURI mismatch. ", |
| docAttrName, |
| goldAttrNsUri, |
| docAttrNsUri); |
| |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /* This routine reports DOM comparison errors. |
| // Inputs: |
| // file - Name of current file |
| // node - Current node that fails |
| // msg - Failure message |
| // |
| */ |
| void |
| XalanFileUtility::reportError() |
| { |
| |
| cout << endl |
| << "* Failed " |
| << data.testOrFile |
| << " Error: " |
| << data.msg |
| << endl |
| << " " |
| << "Processing Node: " |
| << data.currentNode |
| << endl |
| << " Expected: " |
| << data.expected |
| << endl |
| << " Actual: " |
| << data.actual |
| << endl |
| << endl; |
| } |
| |
| |
| #if !defined(NDEBUG) |
| void |
| XalanFileUtility::debugNodeData(const XalanDOMString& value) const |
| { |
| cout << "Node is: " << c_str(TranscodeToLocalCodePage(value)) << endl; |
| } |
| |
| |
| |
| void |
| XalanFileUtility::debugNodeData( |
| const XalanDOMString& node, |
| const XalanDOMString& value) const |
| { |
| cout << "Node is: " << c_str(TranscodeToLocalCodePage(node)) << " " |
| << "Value is: \"" << c_str(TranscodeToLocalCodePage(value)) << "\"\n"; |
| } |
| |
| |
| |
| void |
| XalanFileUtility::debugAttributeData(const XalanDOMString& value) const |
| { |
| cout << "Attribute is: " << c_str(TranscodeToLocalCodePage(value)) << endl; |
| } |
| |
| #endif |
| |
| |
| |
| /* This routine collects up data pertinent to a dom comparison failure. |
| // Inputs: |
| // errmsg: Reason for the failure. |
| // currentnode: Node in the dom tree where the mismatch occured |
| // expdata: Expected data based on the Gold file. |
| // actdata: Actual data returned in the result file. |
| // Returns: Void |
| */ |
| void |
| XalanFileUtility::collectData( |
| const char* errmsg, |
| const XalanDOMString& currentnode, |
| const XalanDOMString& expdata, |
| const XalanDOMString& actdata) |
| { |
| data.msg = errmsg; |
| data.currentNode = currentnode; |
| data.expected = expdata; |
| data.actual = actdata; |
| data.fail += 1; |
| } |
| |
| |
| /* Routine prints the result to the console, as well as adds summary info into the logfile. |
| // Inputs: |
| // logfile: Current log file |
| // runid: Unique runid |
| // Returns: Void |
| */ |
| void |
| XalanFileUtility::reportPassFail( |
| XalanXMLFileReporter& logfile, |
| const XalanDOMString& runid) |
| { |
| typedef XalanXMLFileReporter::Hashtable Hashtable; |
| |
| Hashtable runResults; |
| |
| char temp[5]; |
| |
| // Create entrys that contain runid, xerces version, and numbers for Pass, Fail and No Gold. |
| |
| runResults.insert(Hashtable::value_type(XalanDOMString("UniqRunid"), runid)); |
| runResults.insert(Hashtable::value_type(XalanDOMString("Xerces-Version "), getXercesVersion())); |
| runResults.insert(Hashtable::value_type(XalanDOMString("BaseDrive "), XalanDOMString(getDrive()))); |
| runResults.insert(Hashtable::value_type(XalanDOMString("TestBase "), XalanDOMString(args.base))); |
| runResults.insert(Hashtable::value_type(XalanDOMString("xmlFormat "), data.xmlFormat)); |
| sprintf(temp, "%ld", args.iters); |
| runResults.insert(Hashtable::value_type(XalanDOMString("Iters "), XalanDOMString(temp))); |
| |
| sprintf(temp, "%d", data.pass); |
| runResults.insert(Hashtable::value_type(XalanDOMString("Passed"), XalanDOMString(temp))); |
| |
| sprintf(temp, "%d", data.fail); |
| runResults.insert(Hashtable::value_type(XalanDOMString("Failed"), XalanDOMString(temp))); |
| |
| sprintf(temp, "%d", data.nogold); |
| runResults.insert(Hashtable::value_type(XalanDOMString("No_Gold_Files"), XalanDOMString(temp))); |
| |
| logfile.logElementWAttrs(10, "RunResults", runResults, "xxx"); |
| |
| cout << "\nPassed " << data.pass; |
| cout << "\nFailed " << data.fail; |
| cout << "\nMissing Gold " << data.nogold << endl; |
| |
| } |
| |
| /* Routine runs a stylesheet on the log file and displays the results in HTML. |
| // Inputs: |
| // xalan: An instance of the transformer |
| // resultsFile: logfile |
| // Returns: Void |
| */ |
| void |
| XalanFileUtility::analyzeResults(XalanTransformer& xalan, const XalanDOMString& resultsFile) |
| { |
| XalanDOMString paramValue; |
| bool fileStatus; |
| |
| #if defined(AIX) || defined(SOLARIS) || defined(LINUX) || defined(HPUX) |
| |
| bool pathStatus; |
| CharVectorType withPath; |
| TranscodeToLocalCodePage(resultsFile, withPath, false); |
| if (withPath[0] == '/') |
| pathStatus=true; |
| else |
| pathStatus=false; |
| |
| char buffer5[PATH_MAX]; |
| XalanDOMString resultPath= XalanDOMString(getcwd(buffer5, PATH_MAX)); |
| append(resultPath, s_pathSep); |
| #endif |
| |
| |
| // Pass the results .xml file as a parameter to the stylesheet. It must be wrapped in single |
| // quotes so that it is not considered an expression. |
| // |
| #if defined (AIX) || defined(SOLARIS) || defined(LINUX) || defined(HPUX) |
| assign(paramValue, XalanDOMString("\'")); |
| if ( !pathStatus ) |
| append(paramValue, resultPath); |
| append(paramValue, resultsFile); |
| append(paramValue, XalanDOMString("\'")); |
| #else |
| assign(paramValue, XalanDOMString("'")); |
| append(paramValue, resultsFile); |
| append(paramValue, XalanDOMString("'")); |
| #endif |
| |
| // Set the parameter |
| // |
| xalan.setStylesheetParam(XalanDOMString("testfile"), paramValue); |
| |
| // Generate the input and output file names. |
| // |
| const XalanDOMString theHTMLFile = generateFileName(resultsFile,"html", &fileStatus); |
| const XalanDOMString theStylesheet = args.base + XalanDOMString("cconf.xsl"); |
| const XalanDOMString theXMLSource = args.base + XalanDOMString("cconf.xml"); |
| |
| // Check that we can find the stylesheet to analyze the results. |
| // |
| FILE* fileHandle = fopen(c_str(TranscodeToLocalCodePage(theStylesheet)), "r"); |
| if (fileHandle == 0) |
| { |
| cout << "ANALYSIS ERROR: File Missing: " << c_str(TranscodeToLocalCodePage(theStylesheet)) << endl; |
| return; |
| } |
| else |
| { |
| fclose(fileHandle); |
| } |
| |
| // Create the InputSources and ResultTarget. |
| const XSLTInputSource xslInputSource(theStylesheet); |
| const XSLTInputSource xmlInputSource(theXMLSource); |
| const XSLTResultTarget resultFile(theHTMLFile); |
| |
| // Do the transform, display the output HTML, or report any failure. |
| const int result = xalan.transform(xmlInputSource, xslInputSource, resultFile); |
| |
| if (result == 0) |
| { |
| #if defined(_MSC_VER) |
| system(c_str(TranscodeToLocalCodePage(theHTMLFile))); |
| #else |
| cout << "The HTML output: " << theHTMLFile << " was created" << endl; |
| #endif |
| } |
| else |
| { |
| cout << "Analysis failed due to following error: " |
| << xalan.getLastError() |
| << endl; |
| } |
| } |
| |
| |
| |
| const XalanDOMChar XalanFileUtility::s_xmlSuffix[] = |
| { |
| XalanUnicode::charFullStop, |
| XalanUnicode::charLetter_x, |
| XalanUnicode::charLetter_m, |
| XalanUnicode::charLetter_l, |
| 0 |
| }; |
| |
| const XalanDOMChar XalanFileUtility::s_pathSep[] = |
| { |
| #if defined(WIN32) |
| XalanUnicode::charReverseSolidus, |
| #else |
| XalanUnicode::charSolidus, |
| #endif |
| 0 |
| }; |
| |
| |
| |
| XALAN_CPP_NAMESPACE_END |