dbertoni 2004/08/03 08:59:09
Added: c/src/xalanc/Harness XalanFileUtility.cpp
XalanFileUtility.hpp XalanHarnessDefinitions.hpp
XalanXMLFileReporter.cpp XalanXMLFileReporter.hpp
Log:
Initial revision.
Revision Changes Path
1.1 xml-xalan/c/src/xalanc/Harness/XalanFileUtility.cpp
Index: XalanFileUtility.cpp
===================================================================
/*
* 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
1.1 xml-xalan/c/src/xalanc/Harness/XalanFileUtility.hpp
Index: XalanFileUtility.hpp
===================================================================
/*
* 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.
*/
#if !defined(XALAN_FILEUTILITY_HEADER_GUARD_1357924680)
#define XALAN_FILEUTILITY_HEADER_GUARD_1357924680
#include "xalanc/Harness/XalanHarnessDefinitions.hpp"
#include <vector>
#if defined(XALAN_CLASSIC_IOSTREAMS)
#include <strstream.h>
#else
#include <strstream>
#endif
#include "xalanc/XalanDOM/XalanDOMString.hpp"
XALAN_CPP_NAMESPACE_BEGIN
class FormatterListener;
class PrintWriter;
class StylesheetRoot;
class XalanCompiledStylesheet;
class XalanDocument;
class XalanNode;
class XalanSourceTreeDocument;
class XalanTransformer;
class XalanXMLFileReporter;
class XSLTInputSource;
// This class is exported from the Harness.dll
class XALAN_HARNESS_EXPORT XalanFileUtility
{
public:
// A vector to hold directory names and file names.
#if defined(XALAN_NO_STD_NAMESPACE)
typedef vector<XalanDOMString> FileNameVectorType;
#else
typedef std::vector<XalanDOMString> FileNameVectorType;
#endif
struct XALAN_HARNESS_EXPORT reportStruct
{
XalanDOMString theDrive;
XalanDOMString testOrFile;
XalanDOMString xmlFileURL;
XalanDOMString xslFileURL;
XalanDOMString xmlFormat;
const char* msg;
XalanDOMString currentNode;
XalanDOMString actual;
XalanDOMString expected;
int pass;
int fail;
int nogold;
reportStruct();
void
reset();
} data;
struct XALAN_HARNESS_EXPORT cmdParams
{
private:
#if defined(XALAN_NO_STD_NAMESPACE)
typedef ostrstream StreamType;
#else
typedef std::ostrstream StreamType;
#endif
StreamType help;
public:
XalanDOMString base;
XalanDOMString output;
XalanDOMString gold;
XalanDOMString sub;
int source;
bool skip;
long iters;
cmdParams();
~cmdParams()
{
}
const char*
getHelpMessage();
StreamType&
getHelpStream()
{
return help;
}
} args;
/** Simple constructor, does not perform initialization. */
XalanFileUtility();
~XalanFileUtility();
/**
* Utility method used to get test files from a specific directory.
* @returns a vector containing test files.
*/
XalanDOMString
getDrive();
bool
getParams(
int argc,
char* argv[],
const char* outDir,
bool fsetGold = true);
FileNameVectorType
getTestFileNames(
const XalanDOMString& baseDir,
const XalanDOMString& relDir,
bool useDirPrefix);
/**
* Utility method used to get subdirectories from a specific directory.
* @returns a vector containing directory files.
*/
FileNameVectorType
getDirectoryNames(const XalanDOMString& rootDirectory);
/**
* Utility method used to create default directories when neccessary
*/
void
checkAndCreateDir(const XalanDOMString& directory);
/**
* Utility method determines if directory exists.
*/
bool
checkDir(const XalanDOMString& directory);
/**
* Utility method used to get XSL file based on XML file.
* @returns a XalanDOMString.
*/
XalanDOMString
getXSLFileName(const XalanDOMString& theXMLFileName);
/**
* Utility method used to get OUT file based on XML file.
* @returns a XalanDOMString.
*/
XalanDOMString
generateFileName(
const XalanDOMString& theXMLFileName,
const char* suffix,
bool* status = 0);
/**
* Utility method used to generate UniqRunid.
* @returns a XalanDOMString.
*/
XalanDOMString
generateUniqRunid();
/**
* Utility methods used to get Xerces Version number.
* @returns a XalanDOMString.
*/
XalanDOMString
getXercesVersion();
void
checkResults(
const XalanDOMString& outputFile,
const XalanDOMString& goldFile,
XalanXMLFileReporter& logfile);
void
checkAPIResults(
const XalanDOMString& actual,
const XalanDOMString& expected,
const char* msg,
XalanXMLFileReporter& logfile,
const XalanDOMString& outputFile,
const XalanDOMString& goldFile,
bool containsOnly = false);
void
checkAPIResults(
const char* actual,
const char* expected,
const char* msg,
XalanXMLFileReporter& logfile,
const XalanDOMString& outputFile,
const XalanDOMString& goldFile,
bool containsOnly = false)
{
checkAPIResults(
XalanDOMString(actual),
XalanDOMString(expected),
msg,
logfile,
outputFile,
goldFile,
containsOnly);
}
/**
* Utility method used to compare the results. It inturn
* call domCompare.
* @returns Void.
*/
void
checkDOMResults(
const XalanDOMString& theOutputFile,
const XalanCompiledStylesheet* compiledSS,
const XalanSourceTreeDocument* dom,
const XSLTInputSource& goldInputSource,
XalanXMLFileReporter& logfile);
bool
compareSerializedResults(
const XalanDOMString& transformResult,
const XalanDOMString& goldInputSource);
/**
* Utility method used to create a FormatterToXML FormatterListener.
* This is required to DOM comparisions.
* @returns a pointer to a FormatterListener.
*/
FormatterListener*
getXMLFormatter(
PrintWriter& resultWriter,
int indentAmount,
const XalanDOMString& mimeEncoding,
const StylesheetRoot* stylesheet);
bool
fileCompare(
const char* goldFile,
const char* outputFile);
/**
* Utility methods used to perform a DOM Compare
* @returns boolean
*/
bool
domCompare(const XalanNode& gold, const XalanNode& doc);
/**
* Utility methods used to perform a DOM Compare
* @returns boolean
*/
bool
domCompare(
const XalanDocument& gold,
const XalanDocument& doc);
/**
* Utility methods used to diff two Element nodes.
* @returns boolean.
*/
bool
diffElement(const XalanNode& gold, const XalanNode& doc);
/**
* Utility methods used to diff two nodes.
* @returns true if the nodes are equal, and false if not.
*/
bool
diffNode(
const XalanNode& gold,
const XalanNode& doc);
/**
* Utility methods used to diff two nodes.
* @returns true if the nodes are equal, and false if not.
*/
bool
diffNode(
const XalanNode* gold,
const XalanNode* doc);
/**
* Utility methods used to diff two Element nodes.
* @returns boolean.
*/
bool
diffElement2(
const XalanNode& gold,
const XalanNode& doc);
/**
* Utility methods used to diff two attribute nodes.
* @returns boolean.
*/
bool
diffAttr(const XalanNode* gAttr, const XalanNode* dAttr);
/**
* Utility methods used to report Pass/Fail numbers.
* @returns void.
*/
void
reportPassFail(XalanXMLFileReporter& logfile);
void
reportPassFail(XalanXMLFileReporter& logfile, const XalanDOMString&
runid);
void
analyzeResults(XalanTransformer& xalan, const XalanDOMString&
resultsFile);
static const XalanDOMChar s_xmlSuffix[];
static const XalanDOMChar s_pathSep[];
private:
static const XalanDOMString s_emptyString;
XalanDOMString
getProgramName(const char* fullName);
/**
* Utility methods used to collect information about compare failures.
* @returns void.
*/
void
collectData(
const char* errmsg,
const XalanDOMString& currentnode,
const XalanDOMString& actdata,
const XalanDOMString& expdata);
/**
* Utility methods used to report DOM compare errors.
* @returns void.
*/
void
reportError();
#if defined(NDEBUG)
void
debugNodeData(const XalanDOMString& /* value */) const
{
}
void
debugNodeData(
const XalanDOMString& /* node */,
const XalanDOMString& /* value */) const
{
}
void
debugAttributeData(const XalanDOMString& /* value */) const
{
}
#else
void
debugNodeData(const XalanDOMString& value) const;
void
debugNodeData(
const XalanDOMString& node,
const XalanDOMString& value) const;
void
debugAttributeData(const XalanDOMString& value) const;
#endif
}; // end of class FileUtility
XALAN_CPP_NAMESPACE_END
#endif // XALAN_FILEUTILITY_HEADER_GUARD_1357924680
1.1
xml-xalan/c/src/xalanc/Harness/XalanHarnessDefinitions.hpp
Index: XalanHarnessDefinitions.hpp
===================================================================
/*
* 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.
*/
#if !defined(XALAN_HARNESSDEFINITIONS_HEADER_GUARD_1357924680)
#define XALAN_HARNESSDEFINITIONS_HEADER_GUARD_1357924680
#include "xalanc/Include/PlatformDefinitions.hpp"
#if defined(XALAN_HARNESS_BUILD_DLL)
# define XALAN_HARNESS_EXPORT XALAN_PLATFORM_EXPORT
# define XALAN_HARNESS_EXPORT_FUNCTION(T) XALAN_PLATFORM_EXPORT_FUNCTION(T)
#else
# define XALAN_HARNESS_EXPORT XALAN_PLATFORM_IMPORT
# define XALAN_HARNESS_EXPORT_FUNCTION(T) XALAN_PLATFORM_IMPORT_FUNCTION(T)
#endif
#endif // XALAN_HARNESSDEFINITIONS_HEADER_GUARD_1357924680
1.1 xml-xalan/c/src/xalanc/Harness/XalanXMLFileReporter.cpp
Index: XalanXMLFileReporter.cpp
===================================================================
/*
* 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 "XalanXMLFileReporter.hpp"
#include <cstdlib>
#include <ctime>
#include "xalanc/PlatformSupport/DOMStringHelper.hpp"
#include "xalanc/PlatformSupport/XalanUnicode.hpp"
XALAN_CPP_NAMESPACE_BEGIN
XalanXMLFileReporter::XalanXMLFileReporter(const XalanDOMString& fileName) :
OPT_FILENAME(),
ELEM_RESULTSFILE(),
ELEM_TESTFILE(),
ELEM_FILERESULT(),
ELEM_TESTCASE(),
ELEM_CASERESULT(),
ELEM_CHECKRESULT(),
ELEM_STATISTIC(),
ELEM_LONGVAL(),
ELEM_DOUBLEVAL(),
ELEM_MESSAGE(),
ELEM_ARBITRARY(),
ELEM_HASHTABLE(),
ELEM_HASHITEM(),
ATTR_LEVEL(),
ATTR_DESC(),
ATTR_TIME(),
ATTR_RESULT(),
ATTR_KEY(),
ATTR_FILENAME(),
LESS_THAN(),
GREATER_THAN(),
EQUALS_QUOTE(),
SPACE(),
QUOTE(),
QUOTE_SPACE(),
QUOTE_GREATER_THAN(),
QUOTE_SOLIDUS_GREATER_THAN(),
PASS(),
AMBG(),
ERRR(),
FAIL(),
LESS_THAN_SOLIDUS(),
XML_HEADER(),
REASON_EQUALS_QUOTE(),
TESTCASEINIT_HDR(),
TESTCASECLOSE_HDR(),
MESSAGE_HDR(),
STATISTIC_HDR(),
ARBITRARY_HDR(),
HASHTABLE_HDR(),
HASHITEM_HDR(),
CHECKPASS_HDR(),
CHECKAMBG_HDR(),
CHECKERRR_HDR(),
CHECKFAIL_HDR(),
CHECKFAIL_FTR(),
m_anyOutput(false),
m_fileName(fileName),
m_fileHandle(0),
m_ready(false),
m_error(false),
m_flushOnCaseClose(true)
{
if (m_fileName.empty() == false)
{
m_ready = initialize();
}
}
bool
XalanXMLFileReporter::initialize()
{
if (m_fileName.empty() == true)
{
// We don't have a valid file, so bail
m_error = true;
m_ready = false;
fprintf(stderr, "XalanXMLFileReporter.initialize() ERROR: No file
name specified");
}
else
{
// Transcode down the file name...
CharVectorType theTranscodedFileName;
TranscodeToLocalCodePage(m_fileName, theTranscodedFileName, true);
const char* const theTranscodedFileNamePointer =
&theTranscodedFileName.front();
// Create a file and ensure it has a place to live
m_fileHandle = fopen(theTranscodedFileNamePointer, "w");
if (m_fileHandle == 0)
{
// Couldn't create or find the directory for the file to live in,
so bail
m_error = true;
m_ready = false;
fprintf(stderr, "XalanXMLFileReporter.initialize() ERROR: unble
to open file, %s", theTranscodedFileNamePointer);
return(false);
}
else
{
m_ready = true;
initStrings();
startResultsFile();
// fprintf(stderr, "DEBUG:XalanXMLFileReporter.initialize()
complete with " + fileName);
}
}
return m_ready;
}
bool
XalanXMLFileReporter::getFlushOnCaseClose()
{
return(m_flushOnCaseClose);
}
const XalanDOMString&
XalanXMLFileReporter::getFileName() const
{
return(m_fileName);
}
void
XalanXMLFileReporter::setFileName(const XalanDOMString& fileName)
{
m_fileName = fileName;
}
bool
XalanXMLFileReporter::checkError()
{
// Ensure our underlying reporter, if one, is still OK
if (m_fileHandle == 0)
{
m_error = true;
}
return(m_error);
}
bool
XalanXMLFileReporter::isReady()
{
// Ensure our underlying reporter, if one, is still OK
if (m_fileHandle == 0)
{
// NEEDSWORK: should we set m_ready = false in this case?
// errors in the PrintStream are not necessarily fatal
m_error = true;
m_ready = false;
}
return(m_ready);
}
void
XalanXMLFileReporter::flush()
{
if (isReady())
{
fflush(m_fileHandle);
}
}
void
XalanXMLFileReporter::close()
{
fflush(m_fileHandle);
if (isReady())
{
if (m_fileHandle != 0)
{
closeResultsFile();
fclose(m_fileHandle);
}
}
m_ready = false;
}
void
XalanXMLFileReporter::logTestFileInit(const XalanDOMString& msg)
{
if (isReady())
{
printToFile(LESS_THAN + ELEM_TESTFILE
+ SPACE + ATTR_DESC + EQUALS_QUOTE +
escapestring(msg) + QUOTE_SPACE + ATTR_TIME + EQUALS_QUOTE +
getDateTimeString() + QUOTE_GREATER_THAN);
}
}
void
XalanXMLFileReporter::logTestFileClose(const XalanDOMString& /* msg */, const
XalanDOMString& /* result */)
{
if (isReady())
{
// printToFile(LESS_THAN + ELEM_FILERESULT
// + SPACE + ATTR_DESC + EQUALS_QUOTE +
escapestring(msg) + QUOTE_SPACE + ATTR_RESULT + EQUALS_QUOTE + result +
QUOTE_SPACE + ATTR_TIME + EQUALS_QUOTE + getDateTimeString() +
QUOTE_SOLIDUS_GREATER_THAN);
printToFile(LESS_THAN_SOLIDUS + ELEM_TESTFILE + GREATER_THAN);
}
flush();
}
void
XalanXMLFileReporter::logTestCaseInit(const XalanDOMString& msg)
{
if (isReady())
{
printToFile(TESTCASEINIT_HDR + escapestring(msg) +
QUOTE_GREATER_THAN);
}
}
void
XalanXMLFileReporter::logTestCaseClose(const XalanDOMString& /* msg */, const
XalanDOMString& /* result */)
{
if (isReady())
{
//printToFile(TESTCASECLOSE_HDR + escapestring(msg) + QUOTE_SPACE +
ATTR_RESULT + EQUALS_QUOTE + result + QUOTE_SOLIDUS_GREATER_THAN);
printToFile(LESS_THAN_SOLIDUS + ELEM_TESTCASE + GREATER_THAN);
}
if (getFlushOnCaseClose())
{
flush();
}
}
void
XalanXMLFileReporter::logMessage(int level, const XalanDOMString& msg)
{
char tmp[20];
sprintf(tmp, "%d", level);
if (isReady())
{
printToFile(MESSAGE_HDR + tmp + QUOTE_GREATER_THAN);
printToFile(escapestring(msg));
printToFile(LESS_THAN_SOLIDUS + ELEM_MESSAGE + GREATER_THAN);
}
}
void XalanXMLFileReporter::addMetricToAttrs(char* desc, double theMetric,
Hashtable& attrs)
{
XalanDOMString temp;
DoubleToDOMString(theMetric, temp);
attrs.insert(Hashtable::value_type(XalanDOMString(desc), temp));
return;
}
void
XalanXMLFileReporter::logElementWAttrs(int /* level */, const XalanDOMString&
element, Hashtable attrs, const XalanDOMString& msg)
{
if (isReady() && !element.empty()&& !attrs.empty())
{
// char tmp[20];
// sprintf(tmp, "%d", level);
//
// Took out this level attribute cuz we don't use it.
// printToFile(LESS_THAN + element + SPACE + ATTR_LEVEL + EQUALS_QUOTE
// + tmp + QUOTE);
printToFile(LESS_THAN + element + SPACE);
Hashtable::iterator theEnd = attrs.end();
for(Hashtable::iterator i = attrs.begin(); i != theEnd; ++i)
{
printToFile((*i).first + EQUALS_QUOTE
+ (*i).second + QUOTE);
}
printToFile(GREATER_THAN);
if (msg.empty() != 0)
printToFile(escapestring(msg));
printToFile(LESS_THAN_SOLIDUS + element + GREATER_THAN);
}
}
void
XalanXMLFileReporter::logElement(const XalanDOMString& element, const
XalanDOMString& msg)
{
if (isReady() && !element.empty() && !msg.empty())
{
printToFile(LESS_THAN + element + GREATER_THAN + escapestring(msg) +
LESS_THAN_SOLIDUS + element + GREATER_THAN);
}
}
void
XalanXMLFileReporter::logStatistic (int level, long lVal, double dVal, const
XalanDOMString& msg)
{
if (isReady())
{
char tmp[40];
sprintf(tmp, "%d", level);
printToFile(STATISTIC_HDR + tmp + QUOTE_SPACE + ATTR_DESC +
EQUALS_QUOTE + escapestring(msg) + QUOTE_GREATER_THAN);
sprintf(tmp, "%ld", lVal);
printToFile(LESS_THAN + ELEM_LONGVAL + GREATER_THAN + tmp +
LESS_THAN_SOLIDUS + ELEM_LONGVAL + GREATER_THAN);
sprintf(tmp, "%f", dVal);
printToFile(LESS_THAN + ELEM_DOUBLEVAL + GREATER_THAN + tmp +
LESS_THAN_SOLIDUS + ELEM_DOUBLEVAL + GREATER_THAN);
printToFile(LESS_THAN_SOLIDUS + ELEM_STATISTIC + GREATER_THAN);
}
}
void
XalanXMLFileReporter::logArbitraryMessage (int level, const XalanDOMString&
msg)
{
char tmp[20];
sprintf(tmp, "%d", level);
if (isReady())
{
printToFile(ARBITRARY_HDR + tmp + QUOTE_GREATER_THAN);
printToFile(escapestring(msg));
printToFile(LESS_THAN_SOLIDUS + ELEM_ARBITRARY + GREATER_THAN);
}
}
/*
void logHashtable (int level, Hashtable hash, XalanDOMString msg)
{
if (isReady())
{
printToFile(HASHTABLE_HDR + level + QUOTE_SPACE + ATTR_DESC +
EQUALS_QUOTE + msg + QUOTE_GREATER_THAN);
if (hash == null)
{
printToFile(LESS_THAN + ELEM_HASHITEM + SPACE + ATTR_KEY +
"=\"null\">");
printToFile(LESS_THAN_SOLIDUS + ELEM_HASHITEM + GREATER_THAN);
}
try
{
for (Enumeration enum = hash.keys(); enum.hasMoreElements();)
{
Object key = enum.nextElement();
// Ensure we'll have clean output by pre-fetching value
before outputting anything
XalanDOMString value = hash.get(key).tostring();
printToFile(HASHITEM_HDR + key.tostring() +
QUOTE_GREATER_THAN);
printToFile(value);
printToFile(LESS_THAN_SOLIDUS + ELEM_HASHITEM + GREATER_THAN);
}
}
catch (Exception e)
{
// No-op: should ensure we have clean output
}
printToFile(LESS_THAN_SOLIDUS + ELEM_HASHTABLE + GREATER_THAN);
}
}
*/
void
XalanXMLFileReporter::logCheckPass(const XalanDOMString& comment)
{
if (isReady())
{
printToFile(CHECKPASS_HDR + escapestring(comment) +
QUOTE_SOLIDUS_GREATER_THAN);
}
}
void
XalanXMLFileReporter::logCheckFail(const XalanDOMString& comment)
{
if (isReady())
{
printToFile(CHECKFAIL_HDR + escapestring(comment) +
QUOTE_SOLIDUS_GREATER_THAN);
}
}
void
XalanXMLFileReporter::logCheckFail(const XalanDOMString& test, Hashtable
actexp)
{
if (isReady())
{
printToFile(CHECKFAIL_HDR + escapestring(test) + QUOTE);
printToFile(GREATER_THAN);
Hashtable::iterator aeEnd = actexp.end();
for(Hashtable::iterator ii = actexp.begin(); ii != aeEnd; ++ii)
{
logElement((*ii).first, (*ii).second);
}
printToFile(CHECKFAIL_FTR);
}
}
void
XalanXMLFileReporter::logCheckFail(const XalanDOMString& test, Hashtable
attrs, Hashtable actexp)
{
if (isReady())
{
printToFile(CHECKFAIL_HDR + escapestring(test) + QUOTE);
Hashtable::iterator fdEnd = attrs.end();
for(Hashtable::iterator i = attrs.begin(); i != fdEnd; ++i)
{
printToFile((*i).first + EQUALS_QUOTE
+ (*i).second + QUOTE);
}
printToFile(GREATER_THAN);
Hashtable::iterator aeEnd = actexp.end();
for(Hashtable::iterator ii = actexp.begin(); ii != aeEnd; ++ii)
{
logElement((*ii).first, (*ii).second);
}
printToFile(CHECKFAIL_FTR);
}
}
void
XalanXMLFileReporter::logCheckAmbiguous(const XalanDOMString& comment)
{
if (isReady())
{
printToFile(CHECKAMBG_HDR + escapestring(comment) +
QUOTE_SOLIDUS_GREATER_THAN);
}
}
void
XalanXMLFileReporter::logErrorResult(const XalanDOMString& test, const
XalanDOMString& reason)
{
if (isReady())
{
printToFile(CHECKFAIL_HDR + escapestring(test) + QUOTE_SPACE +
XalanDOMString(REASON_EQUALS_QUOTE) + escapestring(reason) +
QUOTE_SOLIDUS_GREATER_THAN);
}
}
void
XalanXMLFileReporter::logCheckErr(const XalanDOMString& comment)
{
if (isReady())
{
printToFile(CHECKERRR_HDR + escapestring(comment) +
QUOTE_SOLIDUS_GREATER_THAN);
}
}
static const XalanDOMChar theAmpersandString[] =
{
XalanUnicode::charAmpersand,
XalanUnicode::charLetter_a,
XalanUnicode::charLetter_m,
XalanUnicode::charLetter_p,
XalanUnicode::charSemicolon,
0
};
static const XalanDOMChar theApostropheString[] =
{
XalanUnicode::charAmpersand,
XalanUnicode::charLetter_a,
XalanUnicode::charLetter_p,
XalanUnicode::charLetter_o,
XalanUnicode::charLetter_s,
XalanUnicode::charSemicolon,
0
};
static const XalanDOMChar theLessThanString[] =
{
XalanUnicode::charAmpersand,
XalanUnicode::charLetter_l,
XalanUnicode::charLetter_t,
XalanUnicode::charSemicolon,
0
};
static const XalanDOMChar theGreaterThanString[] =
{
XalanUnicode::charAmpersand,
XalanUnicode::charLetter_g,
XalanUnicode::charLetter_t,
XalanUnicode::charSemicolon,
0
};
static const XalanDOMChar theQuoteString[] =
{
XalanUnicode::charAmpersand,
XalanUnicode::charLetter_q,
XalanUnicode::charLetter_u,
XalanUnicode::charLetter_o,
XalanUnicode::charLetter_t,
XalanUnicode::charSemicolon,
0
};
XalanDOMString
XalanXMLFileReporter::escapestring(const XalanDOMString& s)
{
XalanDOMString sb;
const XalanDOMString::size_type length = s.length();
sb.reserve(length);
for (XalanDOMString::size_type i = 0; i < length; i++)
{
const XalanDOMChar ch = charAt(s, i);
if (XalanUnicode::charLessThanSign == ch)
{
append(sb, theLessThanString);
}
else if (XalanUnicode::charGreaterThanSign == ch)
{
append(sb, theGreaterThanString);
}
else if (XalanUnicode::charAmpersand == ch)
{
append(sb, theAmpersandString);
}
else if (XalanUnicode::charQuoteMark == ch)
{
append(sb, theQuoteString);
}
else if (XalanUnicode::charApostrophe == ch)
{
append(sb, theApostropheString);
}
else
{
append(sb, ch);
}
}
return sb;
}
bool
XalanXMLFileReporter::startResultsFile()
{
if (isReady())
{
// Write out XML header and root test result element
printToFile(XML_HEADER);
// Note: this tag is closed in our .close() method, which the caller
had better call!
printToFile(LESS_THAN + ELEM_RESULTSFILE + SPACE + ATTR_FILENAME +
EQUALS_QUOTE + m_fileName + QUOTE_GREATER_THAN);
return true;
}
else
{
return false;
}
}
bool
XalanXMLFileReporter::closeResultsFile()
{
if (isReady() == false)
{
return false;
}
else
{
printToFile(LESS_THAN_SOLIDUS + ELEM_RESULTSFILE + GREATER_THAN);
return true;
}
}
bool
XalanXMLFileReporter::printToFile(const XalanDOMString& output)
{
if (isReady() == false)
{
return false;
}
else
{
const CharVectorType theResult(TranscodeToLocalCodePage(output));
if(!theResult.size())
{
fputs("Error transcoding text to local codepage", m_fileHandle);
}
else
{
fputs(c_str(theResult), m_fileHandle);
}
fputs("\n", m_fileHandle);
return true;
}
}
XalanDOMString
XalanXMLFileReporter::getDateTimeString()
{
#if defined(XALAN_STRICT_ANSI_HEADERS)
using std::tm;
using std::time;
using std::localtime;
using std::asctime;
using std::strlen;
#endif
struct tm *tmNow;
time_t time_tNow;
time(&time_tNow);
tmNow = localtime(&time_tNow);
const char* const theTime = asctime(tmNow);
return XalanDOMString(theTime, XalanDOMString::length(theTime) - 1);
}
void
XalanXMLFileReporter::initStrings()
{
OPT_FILENAME = XALAN_STATIC_UCODE_STRING("filename");
ELEM_RESULTSFILE = XALAN_STATIC_UCODE_STRING("resultsfile");
ELEM_TESTFILE = XALAN_STATIC_UCODE_STRING("testfile");
ELEM_FILERESULT = XALAN_STATIC_UCODE_STRING("fileresult");
ELEM_TESTCASE = XALAN_STATIC_UCODE_STRING("Test_Dir");
ELEM_CASERESULT = XALAN_STATIC_UCODE_STRING("Dir-result");
ELEM_CHECKRESULT = XALAN_STATIC_UCODE_STRING("Testcase");
ELEM_STATISTIC = XALAN_STATIC_UCODE_STRING("statistic");
ELEM_LONGVAL = XALAN_STATIC_UCODE_STRING("longval");
ELEM_DOUBLEVAL = XALAN_STATIC_UCODE_STRING("doubleval");
ELEM_MESSAGE = XALAN_STATIC_UCODE_STRING("message");
ELEM_ARBITRARY = XALAN_STATIC_UCODE_STRING("arbitrary");
ELEM_HASHTABLE = XALAN_STATIC_UCODE_STRING("hashtable");
ELEM_HASHITEM = XALAN_STATIC_UCODE_STRING("hashitem");
ATTR_LEVEL = XALAN_STATIC_UCODE_STRING("level");
ATTR_DESC = XALAN_STATIC_UCODE_STRING("desc");
ATTR_TIME = XALAN_STATIC_UCODE_STRING("time");
ATTR_RESULT = XALAN_STATIC_UCODE_STRING("result");
ATTR_KEY = XALAN_STATIC_UCODE_STRING("key");
ATTR_FILENAME = OPT_FILENAME;
LESS_THAN = XALAN_STATIC_UCODE_STRING("<");
GREATER_THAN = XALAN_STATIC_UCODE_STRING(">");
EQUALS_QUOTE = XALAN_STATIC_UCODE_STRING("=\"");
SPACE = XALAN_STATIC_UCODE_STRING(" ");
QUOTE = XALAN_STATIC_UCODE_STRING("\"");
QUOTE_SPACE = XALAN_STATIC_UCODE_STRING("\" ");
QUOTE_GREATER_THAN = XALAN_STATIC_UCODE_STRING("\">");
QUOTE_SOLIDUS_GREATER_THAN = XALAN_STATIC_UCODE_STRING("\"/>");
PASS = XALAN_STATIC_UCODE_STRING("PASS");
AMBG = XALAN_STATIC_UCODE_STRING("AMBG");
ERRR = XALAN_STATIC_UCODE_STRING("ERRR");
FAIL = XALAN_STATIC_UCODE_STRING("FAIL");
LESS_THAN_SOLIDUS = XALAN_STATIC_UCODE_STRING("</");
XML_HEADER = XALAN_STATIC_UCODE_STRING("<?xml version=\"1.0\"?>");
REASON_EQUALS_QUOTE = XALAN_STATIC_UCODE_STRING("reason=\"");
TESTCASEINIT_HDR = LESS_THAN + ELEM_TESTCASE + SPACE + ATTR_DESC +
EQUALS_QUOTE;
TESTCASECLOSE_HDR = LESS_THAN + ELEM_CASERESULT + SPACE + ATTR_DESC +
EQUALS_QUOTE;
MESSAGE_HDR = LESS_THAN + ELEM_MESSAGE + SPACE + ATTR_LEVEL +
EQUALS_QUOTE;
STATISTIC_HDR = LESS_THAN + ELEM_STATISTIC + SPACE + ATTR_LEVEL +
EQUALS_QUOTE;
ARBITRARY_HDR = LESS_THAN + ELEM_ARBITRARY + SPACE + ATTR_LEVEL +
EQUALS_QUOTE;
HASHTABLE_HDR = LESS_THAN + ELEM_HASHTABLE + SPACE + ATTR_LEVEL +
EQUALS_QUOTE;
HASHITEM_HDR = LESS_THAN + ELEM_HASHITEM + SPACE + ATTR_KEY +
EQUALS_QUOTE;
CHECKPASS_HDR = LESS_THAN + ELEM_CHECKRESULT + SPACE + ATTR_RESULT +
EQUALS_QUOTE + PASS + QUOTE_SPACE + ATTR_DESC + EQUALS_QUOTE;
CHECKAMBG_HDR = LESS_THAN + ELEM_CHECKRESULT + SPACE + ATTR_RESULT +
EQUALS_QUOTE + AMBG + QUOTE_SPACE + ATTR_DESC + EQUALS_QUOTE;
CHECKERRR_HDR = LESS_THAN + ELEM_CHECKRESULT + SPACE + ATTR_RESULT +
EQUALS_QUOTE + ERRR + QUOTE_SPACE + ATTR_DESC + EQUALS_QUOTE;
CHECKFAIL_HDR = LESS_THAN + ELEM_CHECKRESULT + SPACE + ATTR_RESULT +
EQUALS_QUOTE + FAIL + QUOTE_SPACE + ATTR_DESC + EQUALS_QUOTE;
CHECKFAIL_FTR = LESS_THAN_SOLIDUS + ELEM_CHECKRESULT + GREATER_THAN;
}
XALAN_CPP_NAMESPACE_END
1.1 xml-xalan/c/src/xalanc/Harness/XalanXMLFileReporter.hpp
Index: XalanXMLFileReporter.hpp
===================================================================
/*
* 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.
*/
#if !defined(HARNESS_HEADER_GUARD_1357924680)
#define HARNESS_HEADER_GUARD_1357924680
#include "xalanc/Harness/XalanHarnessDefinitions.hpp"
#include <cstdio>
#include <map>
#include "xalanc/XalanDOM/XalanDOMString.hpp"
XALAN_CPP_NAMESPACE_BEGIN
// This class is exported from the Harness.dll
class XALAN_HARNESS_EXPORT XalanXMLFileReporter
{
public:
#if defined(XALAN_NO_STD_NAMESPACE)
typedef map<XalanDOMString, XalanDOMString, less<XalanDOMString> >
Hashtable;
#else
typedef std::map<XalanDOMString, XalanDOMString> Hashtable;
#endif
#if defined(XALAN_STRICT_ANSI_HEADERS)
typedef std::FILE FileHandleType;
#else
typedef FILE FileHandleType;
#endif
public:
// Construct and initialize this reporter with specified filename, if
// the filename is not empty.
XalanXMLFileReporter(const XalanDOMString& fileName = XalanDOMString());
// Initialize this XalanXMLFileReporter. Must be called before
attempting to log anything.
bool initialize();
// Accessor for flushing; is set from properties.
bool getFlushOnCaseClose();
// Accessor methods for our properties block.
const XalanDOMString& getFileName() const;
// Accessor methods for our properties block.
void setFileName(const XalanDOMString& fileName);
// Accessor methods for our properties block.
void setFileName(const char* fileName)
{
setFileName(XalanDOMString(fileName));
}
//
// Is this Reporter still running OK?
// @returns status - true if an error has occoured, false if it's still
working fine
bool checkError();
//
// Is this Reporter ready to log results?
// @returns status - true if it's ready to report, false otherwise
bool isReady();
// Flush this reporter - ensure our File is flushed.
void flush();
// Close this reporter - ensure our File, etc. are closed.
void close();
//-----------------------------------------------------
//-------- Testfile / Testcase start and stop routines --------
//-----------------------------------------------------
/**
* Report that a testfile has started.
* @param msg message to log out
*/
void logTestFileInit(const XalanDOMString& msg);
void logTestFileInit(const char* msg)
{
logTestFileInit(XalanDOMString(msg));
}
/**
* Report that a testfile has finished, and report it's result.
* @param msg message to log out
* @param result result of testfile
*/
void logTestFileClose(const XalanDOMString& msg, const XalanDOMString&
result);
void logTestFileClose(const char* msg, const char* result)
{
logTestFileClose(XalanDOMString(msg), XalanDOMString(result));
}
void logTestCaseInit(const XalanDOMString& msg);
void logTestCaseInit(const char* msg)
{
logTestCaseInit(XalanDOMString(msg));
}
/**
* Report that a testcase has finished, and report it's result.
* @param msg message to log out
* @param result result of testfile
*/
void logTestCaseClose(const XalanDOMString& msg, const XalanDOMString&
result);
void logTestCaseClose(const char* msg, const char* result)
{
logTestCaseClose(XalanDOMString(msg), XalanDOMString(result));
}
//-----------------------------------------------------
//-------- Test results reporting and logging routines --------
//-----------------------------------------------------
/**
* Report a comment to result file with specified severity.
* <P>Record format: <message level="##">msg</message></P>
* @param level severity or class of message.
* @param msg comment to log out.
*/
void logMessage(int level, const XalanDOMString& msg);
/**
* Logs out statistics to result file with specified severity.
* <P>Record format: <statistic level="##"
desc="msg"><longval>1234</longval><doubleval>1.234</doubleval></statistic></P>
* @param level severity of message.
* @param lVal statistic in long format.
* @param dVal statistic in double format.
* @param msg comment to log out.
*/
void logStatistic (int level, long lVal, double dVal, const
XalanDOMString& msg);
void logStatistic (int level, long lVal, double dVal, const char* msg)
{
logStatistic(level, lVal, dVal, XalanDOMString(msg));
}
// This routine will add an attribute to the attribute list.
void addMetricToAttrs(char* desc, double theMetric, Hashtable& attrs);
/**
* Logs out a element to results with specified severity.
* Uses user-supplied element name and attribute list. Currently
* attribute values and msg are forced .toString(). Also,
* 'level' is forced to be the first attribute of the element.
* @param level severity of message.
* @param element name of enclosing element
* @param attrs hash of name=value attributes; note that the
* caller must ensure they're legal XML
* @param msg comment to log out.
*/
void logElementWAttrs(int level, const XalanDOMString& element, Hashtable
attrs, const XalanDOMString& msg);
void logElementWAttrs(int level, const char* element, Hashtable attrs,
const char* msg)
{
logElementWAttrs(level, XalanDOMString(element), attrs,
XalanDOMString(msg));
}
void logElement(int level, const XalanDOMString& element, const
XalanDOMString& msg);
void logElement(const XalanDOMString& element, const XalanDOMString& msg);
/**
* Report an arbitrary XalanDOMString to result file with specified
severity.
* <P>Appends and prepends \\n newline characters at the start and
* end of the message to separate it from the tags.</P>
* <P>Record format: <arbitrary level="##"><BR/>
* msg<BR/>
* </arbitrary>
* </P>
* @param level severity or class of message.
* @param msg arbitrary XalanDOMString to log out.
*/
void logArbitraryMessage (int level, const XalanDOMString& msg);
/**
* Report a complete Hashtable to result file with specified severity.
* <P>Indents each hashitem within the table.</P>
* <P>Record format: <hashtable level="##" desc="msg"/><BR/>
* <hashitem key="key1">value1</hashitem><BR/>
* <hashitem key="key2">value2</hashitem><BR/>
* </hashtable>
* </P>
* @param level severity or class of message.
* @param hash Hashtable to log the contents of.
* @param msg decription of the Hashtable.
*/
/*
void logHashtable (int level, Hashtable hash, const XalanDOMString& msg);
*/
/**
* Writes out a Pass record with comment.
* <P>Record format: <checkresult result="PASS" desc="comment"/></P>
* @param comment comment to log with the pass record.
*/
void logCheckPass(const XalanDOMString& comment);
/**
* Writes out an ambiguous record with comment.
* <P>Record format: <checkresult result="AMBG" desc="comment"/></P>
* @param comment comment to log with the ambg record.
*/
void logCheckAmbiguous(const XalanDOMString& comment);
/**
* Writes out a Fail record with comment.
* <P>Record format: <checkresult result="FAIL" desc="comment"/></P>
* @param comment comment to log with the fail record.
*/
void logCheckFail(const XalanDOMString& comment);
void logCheckFail(const XalanDOMString& test, Hashtable faildata,
Hashtable actexp);
void logCheckFail(const XalanDOMString& test, Hashtable actexp);
void logErrorResult(const XalanDOMString& test, const XalanDOMString&
reason);
/**
* Writes out a Error record with comment.
* <P>Record format: <checkresult result="ERRR" desc="comment"/></P>
* @param comment comment to log with the error record.
*/
void logCheckErr(const XalanDOMString& comment);
/**
* Escapes a XalanDOMString to remove <, >, ', &, and " so it's valid XML.
* <P>Stolen mostly from Xalan applet sample.</P>
* @param s XalanDOMString to escape.
* @return XalanDOMString that has been escaped.
*/
XalanDOMString escapestring(const XalanDOMString& s);
private:
/**
* worker method to dump the xml header and open the resultsfile element.
*/
bool startResultsFile();
/**
* worker method to close the resultsfile element.
*/
bool closeResultsFile();
/**
* worker method to prints to the resultsfile.
*/
bool printToFile(const XalanDOMString& output);
void
initStrings();
/**
* worker method to prints to the resultsfile.
*/
XalanDOMString getDateTimeString();
/** Key for Properties block that denotes our output filename. */
XalanDOMString OPT_FILENAME;
/** XML tagnames for results file structure. */
XalanDOMString ELEM_RESULTSFILE;
XalanDOMString ELEM_TESTFILE;
XalanDOMString ELEM_FILERESULT;
XalanDOMString ELEM_TESTCASE;
XalanDOMString ELEM_CASERESULT;
XalanDOMString ELEM_CHECKRESULT;
XalanDOMString ELEM_STATISTIC;
XalanDOMString ELEM_LONGVAL;
XalanDOMString ELEM_DOUBLEVAL;
XalanDOMString ELEM_MESSAGE;
XalanDOMString ELEM_ARBITRARY;
XalanDOMString ELEM_HASHTABLE;
XalanDOMString ELEM_HASHITEM;
/** XML attribute names for results file structure. */
XalanDOMString ATTR_LEVEL;
XalanDOMString ATTR_DESC;
XalanDOMString ATTR_TIME;
XalanDOMString ATTR_RESULT;
XalanDOMString ATTR_KEY;
XalanDOMString ATTR_FILENAME;
XalanDOMString LESS_THAN;
XalanDOMString GREATER_THAN;
XalanDOMString EQUALS_QUOTE;
XalanDOMString SPACE;
XalanDOMString QUOTE;
XalanDOMString QUOTE_SPACE;
XalanDOMString QUOTE_GREATER_THAN;
XalanDOMString QUOTE_SOLIDUS_GREATER_THAN;
XalanDOMString PASS;
XalanDOMString AMBG;
XalanDOMString ERRR;
XalanDOMString FAIL;
XalanDOMString LESS_THAN_SOLIDUS;
XalanDOMString XML_HEADER;
XalanDOMString REASON_EQUALS_QUOTE;
/**
* Optimization: for heavy use methods, form pre-defined constants to save
on XalanDOMString concatenation.
* <P>Note the indent; must be updated if we ever switch to another
indenting method.</P>
*/
XalanDOMString TESTCASEINIT_HDR;
XalanDOMString TESTCASECLOSE_HDR;
XalanDOMString MESSAGE_HDR;
XalanDOMString STATISTIC_HDR;
XalanDOMString ARBITRARY_HDR;
XalanDOMString HASHTABLE_HDR;
XalanDOMString HASHITEM_HDR;
XalanDOMString CHECKPASS_HDR;
XalanDOMString CHECKAMBG_HDR;
XalanDOMString CHECKERRR_HDR;
XalanDOMString CHECKFAIL_HDR;
XalanDOMString CHECKFAIL_FTR;
/** If we have output anything yet. */
bool m_anyOutput;
/** Name of the file we're outputing to. */
XalanDOMString m_fileName;
/** File reference and other internal convenience variables. */
FileHandleType* m_fileHandle;
/** If we're ready to start outputting yet. */
bool m_ready;
/** If an error has occoured in this Reporter. */
bool m_error;
/** If we should flush after every logTestCaseClose. */
bool m_flushOnCaseClose;
}; // end of class XalanXMLFileReporter
XALAN_CPP_NAMESPACE_END
#endif
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]