| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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. |
| */ |
| // Base header file. Must be first. |
| #include <xalanc/Include/PlatformDefinitions.hpp> |
| |
| |
| |
| #include <iomanip> |
| |
| |
| |
| #include <xalanc/Include/XalanMemoryManagement.hpp> |
| |
| |
| |
| #include <xalanc/XalanTransformer/XalanParsedSource.hpp> |
| |
| |
| |
| #include <xalanc/PlatformSupport/DOMStringHelper.hpp> |
| |
| |
| |
| #include <xalanc/XalanDOM/XalanDocument.hpp> |
| #include <xalanc/XalanDOM/XalanNode.hpp> |
| #include <xalanc/XalanDOM/XalanNamedNodeMap.hpp> |
| #include <xalanc/XalanDOM/XalanDOMString.hpp> |
| |
| |
| |
| #include <xalanc/Harness/XalanFileUtility.hpp> |
| |
| |
| |
| #include "Parameters.hpp" |
| #include "Utils.hpp" |
| |
| |
| |
| using xalanc::XalanTransformer; |
| using xalanc::XalanParsedSource; |
| using xalanc::XalanDocument; |
| using xalanc::XalanNode; |
| using xalanc::XalanNamedNodeMap; |
| using xalanc::XalanDOMString; |
| using xalanc::WideStringToLong; |
| using xalanc::compareIgnoreCaseASCII; |
| using xalanc::XalanMemMgrs; |
| using xalanc::MemoryManager; |
| using xalanc::XalanFileUtility; |
| using xalanc::XSLTInputSource; |
| |
| |
| |
| |
| |
| using std::endl; |
| |
| |
| |
| /** |
| * Processes parameters for the test harness |
| */ |
| Parameters::Parameters( |
| const XalanDOMString& runFileName, |
| const XalanDOMString& testDirectory, |
| const XalanDOMString& resultDirectory, |
| const XalanDOMString& baselineDirectory, |
| const XalanDOMString& reportDirectory, |
| XalanFileUtility& fileUtility, |
| Logger& logger) : |
| m_name("default"), |
| m_description(""), |
| m_resultDirectory(resultDirectory), |
| m_resultFile("results"), |
| m_threshold("5"), |
| m_baselineDirectory(baselineDirectory), |
| m_baselineFile(""), |
| m_defaultTestCase(), |
| m_testDirectory(testDirectory), |
| m_goldDirectory(""), |
| m_reportDirectory(reportDirectory), |
| m_transformer(), |
| m_uniqId(), |
| m_initialized(false) |
| { |
| fileUtility.generateUniqRunid(m_uniqId); |
| |
| if (parseConfigurationFile(runFileName, logger)) |
| { |
| if (m_testDirectory.empty()) |
| { |
| logger.error() << "No test directory specified on command line or in configuration file" << endl; |
| } |
| else |
| { |
| // configure directories |
| // result directory |
| if (m_resultDirectory.empty()) |
| { |
| m_resultDirectory = getWorkingDirectory(); |
| } |
| m_resultDirectory += getPathSep(); |
| |
| // gold directory |
| if (m_goldDirectory.empty()) |
| { |
| m_goldDirectory = m_testDirectory; |
| m_goldDirectory += XalanDOMString("-gold"); |
| } |
| |
| // test directory |
| m_testDirectory += getPathSep(); |
| |
| if (readTestCases(fileUtility, logger)) |
| { |
| m_initialized = true; |
| } |
| |
| // baseline directory |
| if (m_baselineDirectory.empty()) |
| { |
| m_baselineDirectory = m_resultDirectory; |
| } |
| else |
| { |
| m_baselineDirectory += getPathSep(); |
| } |
| |
| if (m_baselineFile.empty()) |
| { |
| m_baselineFile = m_resultFile; |
| m_baselineFile += XalanDOMString("_latest.xml"); |
| } |
| |
| // report directory |
| if (m_reportDirectory.empty()) |
| { |
| m_reportDirectory = getWorkingDirectory(); |
| } |
| m_reportDirectory += getPathSep(); |
| } |
| } |
| } |
| |
| |
| |
| const TestCasesType& |
| Parameters::getTestCases() |
| { |
| return m_testCases; |
| } |
| |
| |
| |
| bool |
| Parameters::parseConfigurationFile( |
| const XalanDOMString& runFileName, |
| Logger& logger) |
| { |
| // parse the configuration file and get default settings |
| |
| const XalanParsedSource* theParsedSource; |
| |
| XSLTInputSource confFile(runFileName, m_transformer.getMemoryManager()); |
| |
| if (m_transformer.parseSource(confFile, theParsedSource) < 0) |
| { |
| logger.error() << "Failed to parse: " |
| << runFileName.c_str() |
| << ", error: " |
| << m_transformer.getLastError() |
| << endl; |
| |
| return false; |
| } |
| |
| XalanDocument* document = theParsedSource->getDocument(); |
| |
| XalanNode* runNode = document->getFirstChild(); |
| |
| while (runNode->getNodeType() != XalanNode::ELEMENT_NODE) |
| { |
| runNode = runNode->getNextSibling(); |
| if (0 == runNode) |
| { |
| logger.error() << "Failed to parse: " |
| << runFileName.c_str() |
| << ", error: no <testconfig> found" |
| << endl; |
| |
| return false; |
| } |
| } |
| |
| if(!(runNode->getNodeName() == XalanDOMString("testconfig"))) |
| { |
| logger.error() << "Invalid configuration file: " |
| << runFileName.c_str() |
| << ", error: Missing <testconfig> tag" |
| << endl; |
| |
| return false; |
| } |
| |
| const XalanNamedNodeMap* attributes = runNode->getAttributes(); |
| |
| if (attributes != 0) |
| { |
| XalanNode* nameAttribute = attributes->getNamedItem(XalanDOMString("name")); |
| |
| if (nameAttribute != 0 && |
| !nameAttribute->getNodeValue().empty()) |
| { |
| m_name = nameAttribute->getNodeValue(); |
| } |
| else |
| { |
| logger.error() << "Invalid configuration file: " |
| << runFileName.c_str() |
| << ", error: Missing name attribute" |
| << endl; |
| |
| return false; |
| } |
| } |
| |
| XalanNode* currentNode = runNode->getFirstChild(); |
| |
| while(currentNode != 0) |
| { |
| if (currentNode->getNodeType() != XalanNode::ELEMENT_NODE) |
| { |
| currentNode = currentNode->getNextSibling(); |
| continue; |
| } |
| |
| // description element |
| if (currentNode->getNodeName() == XalanDOMString("description") && |
| currentNode->getFirstChild() != 0 && |
| currentNode->getFirstChild()->getNodeType() == XalanNode::TEXT_NODE) |
| { |
| m_description = currentNode->getFirstChild()->getNodeValue(); |
| } |
| // results element |
| else if (currentNode->getNodeName() == XalanDOMString("results")) |
| { |
| // file-path |
| const XalanNamedNodeMap* resultAttributes = currentNode->getAttributes(); |
| XalanNode * attributeNode = resultAttributes->getNamedItem(XalanDOMString("file-path")); |
| if (attributeNode != 0 && |
| attributeNode->getNodeType() == XalanNode::ATTRIBUTE_NODE) |
| { |
| if (!m_resultDirectory.empty()) |
| { |
| m_resultDirectory += getPathSep(); |
| } |
| m_resultDirectory += attributeNode->getNodeValue(); |
| } |
| |
| // result report file name |
| XalanNode * resultsNode = currentNode->getFirstChild(); |
| if (resultsNode != 0 |
| && resultsNode->getNodeType() == XalanNode::TEXT_NODE |
| && !resultsNode->getNodeValue().empty()) |
| { |
| m_resultFile = resultsNode->getNodeValue(); |
| } |
| } |
| // baseline element |
| else if (currentNode->getNodeName() == XalanDOMString("baseline")) |
| { |
| const XalanNamedNodeMap* attributeParams = currentNode->getAttributes(); |
| XalanNode* attributeNode; |
| // threshold |
| attributeNode = attributeParams->getNamedItem(XalanDOMString("threshold")); |
| if (attributeNode != 0 |
| && !attributeNode->getNodeValue().empty()) |
| { |
| m_threshold = attributeNode->getNodeValue().c_str(); |
| } |
| // file-path |
| attributeNode = attributeParams->getNamedItem(XalanDOMString("file-path")); |
| if (attributeNode != 0) |
| { |
| if (!m_baselineDirectory.empty()) |
| { |
| m_baselineDirectory += getPathSep(); |
| } |
| m_baselineDirectory += attributeNode->getNodeValue(); |
| } |
| // baseline file |
| XalanNode * baselineNode = currentNode->getFirstChild(); |
| if (baselineNode != 0 |
| && baselineNode->getNodeType() == XalanNode::TEXT_NODE |
| && !baselineNode->getNodeValue().empty()) |
| { |
| m_baselineFile += baselineNode->getNodeValue(); |
| } |
| } |
| // default parameters |
| else if (currentNode->getNodeName() == XalanDOMString("default-parameter-set")) |
| { |
| const XalanNamedNodeMap* attributeParams = currentNode->getAttributes(); |
| XalanNode* attributeNode; |
| attributeNode = attributeParams->getNamedItem(XalanDOMString("input-mode")); |
| if (attributeNode != 0 && |
| attributeNode->getNodeType() == XalanNode::ATTRIBUTE_NODE && |
| !attributeNode->getNodeValue().empty()) |
| { |
| m_defaultTestCase.inputMode = attributeNode->getNodeValue(); |
| } |
| // number of iterations |
| attributeNode = attributeParams->getNamedItem(XalanDOMString("num-iterations")); |
| if (attributeNode != 0 && |
| attributeNode->getNodeType() == XalanNode::ATTRIBUTE_NODE && |
| WideStringToLong(attributeNode->getNodeValue().c_str()) > 0) |
| { |
| m_defaultTestCase.numIterations = WideStringToLong(attributeNode->getNodeValue().c_str()); |
| } |
| // minimum time to execute |
| attributeNode = attributeParams->getNamedItem(XalanDOMString("min-time-to-execute")); |
| if (attributeNode != 0 && |
| attributeNode->getNodeType() == XalanNode::ATTRIBUTE_NODE && |
| WideStringToLong(attributeNode->getNodeValue().c_str()) > 0) |
| { |
| m_defaultTestCase.minTimeToExecute = WideStringToLong(attributeNode->getNodeValue().c_str()); |
| } |
| // verify the result |
| attributeNode = attributeParams->getNamedItem(XalanDOMString("verify-result")); |
| if (attributeNode != 0 && |
| attributeNode->getNodeType() == XalanNode::ATTRIBUTE_NODE && |
| compareIgnoreCaseASCII(attributeNode->getNodeValue().c_str(),XalanDOMString("yes").c_str()) == 0) |
| { |
| m_defaultTestCase.verifyResult = true; |
| } |
| // get processor specific parameters |
| XalanNode * options = currentNode->getFirstChild(); |
| while (options != 0) |
| { |
| if (options->getNodeType() != XalanNode::ELEMENT_NODE) |
| { |
| options = options->getNextSibling(); |
| continue; |
| } |
| |
| const XalanDOMString* processorName = 0; |
| |
| const XalanNamedNodeMap* optionAttributes = options->getAttributes(); |
| XalanNode* processorOption = optionAttributes->getNamedItem(XalanDOMString("processor")); |
| if (processorOption != 0 && |
| processorOption->getNodeType() == XalanNode::ATTRIBUTE_NODE) |
| { |
| processorName = &(processorOption->getNodeValue()); |
| } |
| |
| if (processorName != 0 && processorName->empty() == true) |
| { |
| options = options->getNextSibling(); |
| continue; |
| } |
| |
| if (options->getNodeName() == XalanDOMString("init-options")) |
| { |
| m_defaultTestCase.processorOptions[*processorName].initOptions = options->getFirstChild(); |
| } |
| else if (options->getNodeName() == XalanDOMString("compile-options")) |
| { |
| m_defaultTestCase.processorOptions[*processorName].compileOptions = options->getFirstChild(); |
| } |
| else if (options->getNodeName() == XalanDOMString("parse-options")) |
| { |
| m_defaultTestCase.processorOptions[*processorName].parseOptions = options->getFirstChild(); |
| } |
| else if (options->getNodeName() == XalanDOMString("result-options")) |
| { |
| m_defaultTestCase.processorOptions[*processorName].resultOptions = options->getFirstChild(); |
| } |
| else if (options->getNodeName() == XalanDOMString("transform-options")) |
| { |
| m_defaultTestCase.processorOptions[*processorName].transformOptions = options->getFirstChild(); |
| } |
| |
| options = options->getNextSibling(); |
| } |
| } |
| else if (currentNode->getNodeName() == XalanDOMString("testcases")) |
| { |
| // file-path |
| const XalanNamedNodeMap* testCasesAttributes = currentNode->getAttributes(); |
| XalanNode * attributeNode = testCasesAttributes->getNamedItem(XalanDOMString("file-path")); |
| if (attributeNode != 0 && |
| attributeNode->getNodeType() == XalanNode::ATTRIBUTE_NODE) |
| { |
| if (!m_testDirectory.empty()) |
| { |
| m_testDirectory += getPathSep(); |
| } |
| m_testDirectory += attributeNode->getNodeValue(); |
| } |
| // gold file-path |
| attributeNode = testCasesAttributes->getNamedItem(XalanDOMString("gold-file-path")); |
| if (attributeNode != 0 && |
| attributeNode->getNodeType() == XalanNode::ATTRIBUTE_NODE) |
| { |
| m_goldDirectory = attributeNode->getNodeValue(); |
| } |
| } |
| currentNode = currentNode->getNextSibling(); |
| } |
| |
| return true; |
| } |
| |
| |
| |
| bool |
| Parameters::readTestCases( |
| XalanFileUtility& fileUtility, |
| Logger& logger) |
| { |
| if (!fileUtility.checkDir(m_testDirectory)) |
| { |
| logger.error() << "Invalid test directory: " << m_testDirectory.c_str() << endl; |
| return false; |
| } |
| |
| if (m_goldDirectory.empty()) |
| { |
| logger.message() << "No gold directory specified" << endl; |
| if (!fileUtility.checkDir(m_goldDirectory)) |
| { |
| logger.warning() << "Invalid gold directory: " << m_goldDirectory.c_str() << endl; |
| } |
| } |
| |
| fileUtility.checkAndCreateDir(m_resultDirectory); |
| |
| typedef XalanFileUtility::FileNameVectorType FileNamesType; |
| FileNamesType dirNames; |
| |
| fileUtility.getDirectoryNames(m_testDirectory, dirNames); |
| |
| FileNamesType::iterator dirIter = dirNames.begin(); |
| |
| // for each test directory |
| while (dirIter != dirNames.end()) |
| { |
| |
| FileNamesType xslTestFiles; |
| fileUtility.getTestFileNames(m_testDirectory, *dirIter, true, xslTestFiles); |
| |
| FileNamesType::const_iterator xslIter = xslTestFiles.begin(); |
| |
| // for each stylesheet |
| while (xslIter != xslTestFiles.end()) |
| { |
| // configure the stylesheet |
| TestCase testCase = m_defaultTestCase; |
| testCase.stylesheet = m_testDirectory; |
| testCase.stylesheet += *dirIter; |
| testCase.stylesheet += getPathSep(); |
| testCase.stylesheet += *xslIter; |
| |
| |
| bool status = true; |
| |
| // configure the input document |
| fileUtility.generateFileName(testCase.stylesheet, "xml", testCase.inputDocument, &status); |
| if (status != true) |
| { |
| logger.warning() << "No matching input file for: " << testCase.stylesheet.c_str() << endl; |
| ++xslIter; |
| continue; |
| } |
| |
| // configure result directory |
| testCase.resultDirectory = m_resultDirectory; |
| testCase.resultDirectory += *dirIter; |
| |
| // configure result document |
| XalanDOMString outFile = testCase.resultDirectory; |
| outFile += getPathSep(); |
| outFile += *xslIter; |
| |
| fileUtility.generateFileName(outFile, "out", testCase.resultDocument); |
| |
| // configure gold result |
| outFile = m_goldDirectory; |
| outFile += getPathSep(); |
| outFile += *dirIter; |
| outFile += getPathSep(); |
| outFile += *xslIter; |
| |
| status = true; |
| fileUtility.generateFileName(outFile, "out", testCase.goldResult, &status); |
| if (true == testCase.verifyResult && !status) |
| { |
| logger.warning() << "Verification on, but no matching gold file: " << testCase.goldResult.c_str() << endl; |
| } |
| |
| m_testCases.push_back(testCase); |
| |
| ++xslIter; |
| } |
| |
| ++dirIter; |
| } |
| |
| return true; |
| } |