--- /dev/null
+<?xml version="1.0"?>
+
+<!--
+This file is currently duplicated to each directory containing reference data
+XML files. This is to make it compatible with more browsers.
+To keep these files in sync, please only modify the version in
+ src/testutils/
+and use the copy_xsl.sh script to copy it to relevant locations.
+-->
+<xsl:stylesheet version="1.0"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+<xsl:import href="common-referencedata.xsl"/>
+
+<xsl:template match="AnalysisData">
+ <xsl:variable name="has-columnspec"
+ select="DataFrame/Sequence[@Name='Y']/Int[@Name='FirstColumn']"/>
+ <table border="1">
+ <tr>
+ <th>Frame</th>
+ <th>X</th>
+ <xsl:if test="$has-columnspec">
+ <th>Columns</th>
+ </xsl:if>
+ <th>Values</th>
+ </tr>
+ <xsl:for-each select="DataFrame/Sequence[@Name='Y']">
+ <tr>
+ <td><xsl:value-of select="../@Name"/></td>
+ <td><xsl:value-of select="../Real[@Name='X']"/></td>
+ <xsl:if test="$has-columnspec">
+ <td>
+ <xsl:choose>
+ <xsl:when test="Int[@Name='FirstColumn']">
+ <xsl:value-of select="Int[@Name='FirstColumn']"/>
+ <xsl:text>-</xsl:text>
+ <xsl:value-of select="Int[@Name='LastColumn']"/>
+ </xsl:when>
+ <xsl:otherwise>all</xsl:otherwise>
+ </xsl:choose>
+ </td>
+ </xsl:if>
+ <td><xsl:call-template name="SequenceAsCSV"/></td>
+ </tr>
+ </xsl:for-each>
+ </table>
+</xsl:template>
+
+<xsl:template match="DataValue">
+ <xsl:value-of select="Real[@Name='Value']"/>
+</xsl:template>
+
+</xsl:stylesheet>
<!--
This file is currently duplicated to each directory containing reference data
XML files. This is to make it compatible with more browsers.
-If you modify one of these files, please keep others in sync.
+To keep these files in sync, please only modify the version in
+ src/testutils/
+and use the copy_xsl.sh script to copy it to relevant locations.
-->
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template name="SequenceAsCSV">
<xsl:param name="root" select="."/>
- <xsl:for-each select="$root/*[position() > 1]">
- <xsl:apply-templates select="."/>
- <xsl:if test="position() < last()">, </xsl:if>
+ <xsl:for-each select="$root/*">
+ <xsl:if test="not(.[@Name])">
+ <xsl:apply-templates select="."/>
+ <xsl:if test="position() < last()">, </xsl:if>
+ </xsl:if>
</xsl:for-each>
</xsl:template>
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:import href="common-referencedata.xsl"/>
+<xsl:import href="analysisdata-referencedata.xsl"/>
<xsl:template match="AnalysisData">
<h2><xsl:value-of select="@Name"/></h2>
- <table border="1">
- <tr>
- <th>Frame</th>
- <th>X</th>
- <th>Values</th>
- </tr>
- <xsl:for-each select="DataFrame/Sequence[@Name='Y']">
- <tr>
- <td><xsl:value-of select="../@Name"/></td>
- <td><xsl:value-of select="../Real[@Name='X']"/></td>
- <td><xsl:call-template name="SequenceAsCSV"/></td>
- </tr>
- </xsl:for-each>
- </table>
-</xsl:template>
-
-<xsl:template match="DataValue">
- <xsl:value-of select="Real[@Name='Value']"/>
+ <xsl:apply-imports />
</xsl:template>
</xsl:stylesheet>
<!--
This file is currently duplicated to each directory containing reference data
XML files. This is to make it compatible with more browsers.
-If you modify one of these files, please keep others in sync.
+To keep these files in sync, please only modify the version in
+ src/testutils/
+and use the copy_xsl.sh script to copy it to relevant locations.
-->
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template name="SequenceAsCSV">
<xsl:param name="root" select="."/>
- <xsl:for-each select="$root/*[position() > 1]">
- <xsl:apply-templates select="."/>
- <xsl:if test="position() < last()">, </xsl:if>
+ <xsl:for-each select="$root/*">
+ <xsl:if test="not(.[@Name])">
+ <xsl:apply-templates select="."/>
+ <xsl:if test="position() < last()">, </xsl:if>
+ </xsl:if>
</xsl:for-each>
</xsl:template>
--- /dev/null
+<?xml version="1.0"?>
+
+<!--
+This file is currently duplicated to each directory containing reference data
+XML files. This is to make it compatible with more browsers.
+To keep these files in sync, please only modify the version in
+ src/testutils/
+and use the copy_xsl.sh script to copy it to relevant locations.
+-->
+<xsl:stylesheet version="1.0"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+<xsl:import href="common-referencedata.xsl"/>
+
+<xsl:template match="AnalysisData">
+ <xsl:variable name="has-columnspec"
+ select="DataFrame/Sequence[@Name='Y']/Int[@Name='FirstColumn']"/>
+ <table border="1">
+ <tr>
+ <th>Frame</th>
+ <th>X</th>
+ <xsl:if test="$has-columnspec">
+ <th>Columns</th>
+ </xsl:if>
+ <th>Values</th>
+ </tr>
+ <xsl:for-each select="DataFrame/Sequence[@Name='Y']">
+ <tr>
+ <td><xsl:value-of select="../@Name"/></td>
+ <td><xsl:value-of select="../Real[@Name='X']"/></td>
+ <xsl:if test="$has-columnspec">
+ <td>
+ <xsl:choose>
+ <xsl:when test="Int[@Name='FirstColumn']">
+ <xsl:value-of select="Int[@Name='FirstColumn']"/>
+ <xsl:text>-</xsl:text>
+ <xsl:value-of select="Int[@Name='LastColumn']"/>
+ </xsl:when>
+ <xsl:otherwise>all</xsl:otherwise>
+ </xsl:choose>
+ </td>
+ </xsl:if>
+ <td><xsl:call-template name="SequenceAsCSV"/></td>
+ </tr>
+ </xsl:for-each>
+ </table>
+</xsl:template>
+
+<xsl:template match="DataValue">
+ <xsl:value-of select="Real[@Name='Value']"/>
+</xsl:template>
+
+</xsl:stylesheet>
--- /dev/null
+<?xml version="1.0"?>
+
+<!--
+This file is currently duplicated to each directory containing reference data
+XML files. This is to make it compatible with more browsers.
+To keep these files in sync, please only modify the version in
+ src/testutils/
+and use the copy_xsl.sh script to copy it to relevant locations.
+-->
+<xsl:stylesheet version="1.0"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+<xsl:template match="/">
+ <html><body>
+ <xsl:apply-templates/>
+ </body></html>
+</xsl:template>
+
+<xsl:template match="/ReferenceData">
+ <h1>Test Reference Data</h1>
+ <xsl:apply-templates/>
+</xsl:template>
+
+<xsl:template match="Vector">
+ (<xsl:value-of select="*[@Name='X']"/>;
+ <xsl:value-of select="*[@Name='Y']"/>;
+ <xsl:value-of select="*[@Name='Z']"/>)
+</xsl:template>
+
+<xsl:template name="SequenceAsHorizontalTable">
+ <xsl:param name="root" select="."/>
+ <table border="1">
+ <tr><th>Count</th><th>Items</th></tr>
+ <tr>
+ <td><xsl:value-of select="$root/Int[@Name='Length']"/></td>
+ <td>
+ <xsl:call-template name="SequenceAsCSV">
+ <xsl:with-param name="root" select="$root"/>
+ </xsl:call-template>
+ </td>
+ </tr>
+ </table>
+</xsl:template>
+
+<xsl:template name="SequenceAsCSV">
+ <xsl:param name="root" select="."/>
+ <xsl:for-each select="$root/*">
+ <xsl:if test="not(.[@Name])">
+ <xsl:apply-templates select="."/>
+ <xsl:if test="position() < last()">, </xsl:if>
+ </xsl:if>
+ </xsl:for-each>
+</xsl:template>
+
+<xsl:template name="Bool">
+ <xsl:value-of select="."/>
+</xsl:template>
+
+<xsl:template name="String">
+ <xsl:value-of select="."/>
+</xsl:template>
+
+<xsl:template name="Int">
+ <xsl:value-of select="."/>
+</xsl:template>
+
+<xsl:template name="Real">
+ <xsl:value-of select="."/>
+</xsl:template>
+
+</xsl:stylesheet>
--- /dev/null
+#!/bin/sh
+
+# Change to root of the source tree, no matter from where the script is
+# invoked.
+cd `dirname $0`
+cd ../../
+
+for destdir in analysisdata selection ; do
+ cp -f src/testutils/common-referencedata.xsl \
+ src/gromacs/$destdir/tests/refdata/
+done
+
+for destdir in analysisdata ; do
+ cp -f src/testutils/analysisdata-referencedata.xsl \
+ src/gromacs/$destdir/tests/refdata/
+done
//! Initializes a mock object with the given flags.
explicit Impl(int flags);
+ /*! \brief
+ * Callback used to initialize reference data checks
+ *
+ * Called in response to dataStarted().
+ * Records information about the source data for later use.
+ */
+ void startReferenceData(AbstractAnalysisData *data);
/*! \brief
* Callback used to check frame start against reference data.
*
int flags_;
//! Index of the current/next frame.
int frameIndex_;
+ //! Number of columns in the source data (for reference checking only).
+ int columnCount_;
};
} // namespace test
namespace
{
-/*! \brief
- * Helper callback function for TestReferenceData::checkCompound().
+/*! \internal \brief
+ * Checks a single AnalysisDataValue.
+ *
+ * \ingroup module_testutils
*/
void checkReferenceDataPoint(TestReferenceChecker *checker,
const AnalysisDataValue &value)
{
TestReferenceChecker compound(checker->checkCompound("DataValue", NULL));
compound.checkReal(value.value(), "Value");
- if (value.hasError())
+ if (compound.checkPresent(value.hasError(), "Error"))
{
compound.checkReal(value.error(), "Error");
}
- if (!value.isPresent())
+ if (compound.checkPresent(!value.isPresent(), "Present"))
{
compound.checkBoolean(value.isPresent(), "Present");
}
} // namespace
MockAnalysisDataModule::Impl::Impl(int flags)
- : flags_(flags), frameIndex_(0)
+ : flags_(flags), frameIndex_(0), columnCount_(-1)
+{
+}
+
+
+void
+MockAnalysisDataModule::Impl::startReferenceData(AbstractAnalysisData *data)
{
+ columnCount_ = data->columnCount();
}
EXPECT_TRUE(frameChecker_.get() != NULL);
if (frameChecker_.get() != NULL)
{
- frameChecker_->checkSequence(points.values().begin(), points.values().end(), "Y",
- &checkReferenceDataPoint);
+ TestReferenceChecker checker(
+ frameChecker_->checkSequenceCompound("Y",
+ points.columnCount()));
+ bool bAllColumns = (points.firstColumn() == 0
+ && points.columnCount() == columnCount_);
+ if (checker.checkPresent(!bAllColumns, "FirstColumn"))
+ {
+ checker.checkInteger(points.firstColumn(), "FirstColumn");
+ checker.checkInteger(points.lastColumn(), "LastColumn");
+ }
+ AnalysisDataValuesRef::const_iterator value;
+ for (value = points.values().begin(); value != points.values().end(); ++value)
+ {
+ checkReferenceDataPoint(&checker, *value);
+ }
}
}
using ::testing::Expectation;
using ::testing::Invoke;
- Expectation dataStart = EXPECT_CALL(*this, dataStarted(source));
+ Expectation dataStart = EXPECT_CALL(*this, dataStarted(source))
+ .WillOnce(Invoke(impl_.get(), &Impl::startReferenceData));
Expectation frameStart = EXPECT_CALL(*this, frameStarted(_))
.After(dataStart)
.WillRepeatedly(Invoke(impl_.get(), &Impl::startReferenceFrame));
//! Returns the path of this checker with \p id appended.
std::string appendPath(const char *id) const;
+ /*! \brief
+ * Finds a reference data node.
+ *
+ * \param[in] name Type of node to find (can be NULL, in which case
+ * any type is matched).
+ * \param[in] id Unique identifier of the node (can be NULL, in
+ * which case the next node without an id is matched).
+ * \returns Matching node, or NULL if no matching node found.
+ *
+ * Searches for a node in the reference data that matches the given
+ * \p name and \p id. Searching starts from the node that follows the
+ * previously matched node (relevant for performance, and if there are
+ * duplicate ids or nodes without ids). Note that the match pointer is
+ * not updated by this method.
+ */
+ xmlNodePtr findNode(const xmlChar *name, const char *id) const;
/*! \brief
* Finds/creates a reference data node to match against.
*
* (NULL is never returned in write mode).
* \throws TestException if node creation fails in write mode.
*
- * Searches for a node in the reference data that matches the given
- * \p name and \p id. Searching starts from the node that follows the
- * previously matched node (relevant for performance, and if there are
- * duplicate ids or nodes without ids). If a match is not found, the
- * method returns NULL in read mode and creates a new node in write
- * mode. If the creation fails in write mode, throws.
+ * Finds a node using findNode() and updates the match pointer is a
+ * match is found. If a match is not found, the method returns NULL in
+ * read mode and creates a new node in write mode. If the creation
+ * fails in write mode, throws.
*/
xmlNodePtr findOrCreateNode(const xmlChar *name, const char *id);
/*! \brief
xmlNodePtr
-TestReferenceChecker::Impl::findOrCreateNode(const xmlChar *name, const char *id)
+TestReferenceChecker::Impl::findNode(const xmlChar *name, const char *id) const
{
const xmlChar *xmlId = reinterpret_cast<const xmlChar *>(id);
xmlNodePtr node = _nextSearchNode;
- while (node != NULL && node->next != _nextSearchNode)
+ if (node == NULL)
+ {
+ return NULL;
+ }
+ do
{
- if (xmlStrcmp(node->name, name) == 0)
+ if (name == NULL || xmlStrcmp(node->name, name) == 0)
{
xmlChar *refId = xmlGetProp(node, cIdAttrName);
if (xmlId == NULL && refId == NULL)
{
- break;
+ return node;
}
if (refId != NULL)
{
if (xmlId != NULL && xmlStrcmp(refId, xmlId) == 0)
{
xmlFree(refId);
- break;
+ return node;
}
xmlFree(refId);
}
node = _currNode->xmlChildrenNode;
}
}
- if (node == NULL || node->next == _nextSearchNode)
+ while (node != NULL && node != _nextSearchNode);
+ return NULL;
+}
+
+
+xmlNodePtr
+TestReferenceChecker::Impl::findOrCreateNode(const xmlChar *name, const char *id)
+{
+ xmlNodePtr node = findNode(name, id);
+ if (node == NULL)
{
if (_bWrite)
{
node = xmlNewTextChild(_currNode, NULL, name, NULL);
- if (node != NULL && xmlId != NULL)
+ if (node != NULL && id != NULL)
{
+ const xmlChar *xmlId = reinterpret_cast<const xmlChar *>(id);
xmlAttrPtr prop = xmlNewProp(node, cIdAttrName, xmlId);
if (prop == NULL)
{
}
+bool TestReferenceChecker::checkPresent(bool bPresent, const char *id)
+{
+ if (isWriteMode())
+ {
+ return bPresent;
+ }
+ xmlNodePtr node = _impl->findNode(NULL, id);
+ bool bFound = (node != NULL);
+ if (bFound != bPresent)
+ {
+ ADD_FAILURE() << "Mismatch while checking reference data item'"
+ << _impl->appendPath(id) << "'\n"
+ << "Expected: " << (bPresent ? "it is present.\n" : "it is absent.\n")
+ << " Actual: " << (bFound ? "it is present." : "it is absent.");
+ }
+ if (bFound && bPresent)
+ {
+ _impl->_nextSearchNode = node;
+ return true;
+ }
+ return false;
+}
+
+
TestReferenceChecker TestReferenceChecker::checkCompound(const char *type, const char *id)
{
SCOPED_TRACE(_impl->traceString(id));
//! Returns true if reference data is currently being written.
bool isWriteMode() const;
+ /*! \brief
+ * Checks whether a data item is present.
+ *
+ * \param[in] bPresent Whether to check for presence or absence.
+ * \param[in] id Unique identifier of the item to check.
+ * \returns true if bPresent was true and the data item was found.
+ *
+ * If \p bPresent is true, checks that a data item with \p id is
+ * present, otherwise checks that the data item is absent.
+ * If the check fails, a non-fatal Google Test assertion is generated.
+ *
+ * If isWriteMode() returns true, the check always succeeds and the
+ * return value is \p bPresent.
+ *
+ * The main use of this method is to assign meaning for missing
+ * reference data. Example use:
+ * \code
+if (checker.checkPresent(bHaveVelocities, "Velocities"))
+{
+ // <check the velocities>
+}
+ * \endcode
+ */
+ bool checkPresent(bool bPresent, const char *id);
+
/*! \brief
* Initializes comparison of a group of related data items.
*
}
}
+TEST(ReferenceDataTest, HandlesPresenceChecks)
+{
+ using gmx::test::TestReferenceData;
+ using gmx::test::TestReferenceChecker;
+
+ {
+ TestReferenceData data(gmx::test::erefdataUpdateAll);
+ TestReferenceChecker checker(data.rootChecker());
+ EXPECT_TRUE(checker.checkPresent(true, "present"));
+ checker.checkInteger(1, "present");
+ EXPECT_FALSE(checker.checkPresent(false, "absent"));
+ }
+ {
+ TestReferenceData data(gmx::test::erefdataCompare);
+ TestReferenceChecker checker(data.rootChecker());
+ // Assigned to avoid warnings about potentially uninitialized value.
+ bool bRet = true;
+ EXPECT_TRUE(checker.checkPresent(true, "present"));
+ checker.checkInteger(1, "present");
+ EXPECT_NONFATAL_FAILURE(bRet = checker.checkPresent(false, "present"), "");
+ EXPECT_FALSE(bRet);
+ EXPECT_NONFATAL_FAILURE(bRet = checker.checkPresent(true, "absent"), "");
+ EXPECT_FALSE(bRet);
+ EXPECT_FALSE(checker.checkPresent(false, "absent"));
+ }
+}
+
TEST(ReferenceDataTest, HandlesStringBlockData)
{