Improve analysisdata reference checks.
authorTeemu Murtola <teemu.murtola@gmail.com>
Thu, 24 May 2012 05:12:46 +0000 (08:12 +0300)
committerTeemu Murtola <teemu.murtola@gmail.com>
Thu, 24 May 2012 15:26:06 +0000 (18:26 +0300)
The reference checking for AnalysisData objects now supports more
scenarios with multipoint data, i.e., cases where there are point sets
that do not cover all columns.

Supporting changes:
 - Add a TestReferenceChecker::checkPresent() method that allows to
   assign meaning to absence of a reference data item (and to check for
   that).
 - Split common analysisdata XML stylesheet elements to a separate xsl
   file.
 - Add a script for copying the XML stylesheets to the reference data
   directories for easier maintenance.  Master copies of shared
   stylesheets are now kept in src/testutils/.

Needed for #920, but split from the main change to keep it smaller.

Change-Id: I108c013833052c37a4f2e6c73be6161c0dae1c78

13 files changed:
src/gromacs/analysisdata/tests/refdata/analysisdata-referencedata.xsl [new file with mode: 0644]
src/gromacs/analysisdata/tests/refdata/common-referencedata.xsl
src/gromacs/analysisdata/tests/refdata/referencedata.xsl
src/gromacs/selection/tests/refdata/common-referencedata.xsl
src/testutils/analysisdata-referencedata.xsl [new file with mode: 0644]
src/testutils/common-referencedata.xsl [new file with mode: 0644]
src/testutils/copy_xsl.sh [new file with mode: 0755]
src/testutils/mock_datamodule-impl.h
src/testutils/mock_datamodule.cpp
src/testutils/refdata-impl.h
src/testutils/refdata.cpp
src/testutils/refdata.h
src/testutils/tests/refdata.cpp

diff --git a/src/gromacs/analysisdata/tests/refdata/analysisdata-referencedata.xsl b/src/gromacs/analysisdata/tests/refdata/analysisdata-referencedata.xsl
new file mode 100644 (file)
index 0000000..099384f
--- /dev/null
@@ -0,0 +1,53 @@
+<?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>
index 1df2ad74b7897aaf95bfdc3e26fc9e7918f1d112..1ae38d84525b8dfc62b0f5178ad9305cb3948268 100644 (file)
@@ -3,7 +3,9 @@
 <!--
 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">
@@ -42,9 +44,11 @@ If you modify one of these files, please keep others in sync.
 
 <xsl:template name="SequenceAsCSV">
     <xsl:param name="root" select="."/>
-    <xsl:for-each select="$root/*[position() &gt; 1]">
-        <xsl:apply-templates select="."/>
-        <xsl:if test="position() &lt; last()">, </xsl:if>
+    <xsl:for-each select="$root/*">
+        <xsl:if test="not(.[@Name])">
+            <xsl:apply-templates select="."/>
+            <xsl:if test="position() &lt; last()">, </xsl:if>
+        </xsl:if>
     </xsl:for-each>
 </xsl:template>
 
index 73f69eb12df3c7e51143506780e3ee9dda60c0bd..6b1a637adb4555845c8f621871fd8aebb52cb7ae 100644 (file)
@@ -4,27 +4,11 @@
     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>
index 1df2ad74b7897aaf95bfdc3e26fc9e7918f1d112..1ae38d84525b8dfc62b0f5178ad9305cb3948268 100644 (file)
@@ -3,7 +3,9 @@
 <!--
 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">
@@ -42,9 +44,11 @@ If you modify one of these files, please keep others in sync.
 
 <xsl:template name="SequenceAsCSV">
     <xsl:param name="root" select="."/>
-    <xsl:for-each select="$root/*[position() &gt; 1]">
-        <xsl:apply-templates select="."/>
-        <xsl:if test="position() &lt; last()">, </xsl:if>
+    <xsl:for-each select="$root/*">
+        <xsl:if test="not(.[@Name])">
+            <xsl:apply-templates select="."/>
+            <xsl:if test="position() &lt; last()">, </xsl:if>
+        </xsl:if>
     </xsl:for-each>
 </xsl:template>
 
diff --git a/src/testutils/analysisdata-referencedata.xsl b/src/testutils/analysisdata-referencedata.xsl
new file mode 100644 (file)
index 0000000..099384f
--- /dev/null
@@ -0,0 +1,53 @@
+<?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>
diff --git a/src/testutils/common-referencedata.xsl b/src/testutils/common-referencedata.xsl
new file mode 100644 (file)
index 0000000..1ae38d8
--- /dev/null
@@ -0,0 +1,71 @@
+<?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() &lt; 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>
diff --git a/src/testutils/copy_xsl.sh b/src/testutils/copy_xsl.sh
new file mode 100755 (executable)
index 0000000..d4c9430
--- /dev/null
@@ -0,0 +1,16 @@
+#!/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
index 4fc7075acc4c360cb5a0e19a6f547bdf5966a113..2cdf4fa5e71d17cce0595e7d5ac54796702fb497 100644 (file)
@@ -58,6 +58,13 @@ class MockAnalysisDataModule::Impl
         //! 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.
          *
@@ -97,6 +104,8 @@ class MockAnalysisDataModule::Impl
         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
index 24242806970d01202a10f0036e466b80cadc9d92..6dbda3ead5d40c7cd2d1918481535b8818117ccd 100644 (file)
@@ -62,19 +62,21 @@ 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");
     }
@@ -83,8 +85,15 @@ void checkReferenceDataPoint(TestReferenceChecker *checker,
 } // 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();
 }
 
 
@@ -110,8 +119,21 @@ MockAnalysisDataModule::Impl::checkReferencePoints(
     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);
+        }
     }
 }
 
@@ -465,7 +487,8 @@ MockAnalysisDataModule::setupReferenceCheck(const TestReferenceChecker &checker,
     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));
index 48b0a4891da16c1a1447a81ef4090ece158fa492..579ddc67976bf8f1b0ec31f1f22b7141eba6853b 100644 (file)
@@ -125,6 +125,22 @@ class TestReferenceChecker::Impl
         //! 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.
          *
@@ -135,12 +151,10 @@ class TestReferenceChecker::Impl
          *      (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
index 19c40e10f2d898170c1d5101a3a6e56fb31e7679..711a28825a6f4365a14249cc1dd51eabbff22958 100644 (file)
@@ -270,25 +270,29 @@ TestReferenceChecker::Impl::appendPath(const char *id) const
 
 
 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);
             }
@@ -299,13 +303,23 @@ TestReferenceChecker::Impl::findOrCreateNode(const xmlChar *name, const char *id
             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)
                 {
@@ -461,6 +475,30 @@ bool TestReferenceChecker::isWriteMode() const
 }
 
 
+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));
index 96a54e6ddfd8ff7b7d17cbd7627035b788ef3db8..4eace4a38aeab2c89daede58473736d988a2b038 100644 (file)
@@ -234,6 +234,31 @@ class TestReferenceChecker
         //! 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.
          *
index 94466eba922c63016ecd249bdfd2ef207763a647..3aa042f9422fc2a590dbb1ecd82d16bcca6351ec 100644 (file)
@@ -68,6 +68,33 @@ TEST(ReferenceDataTest, HandlesSimpleData)
     }
 }
 
+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)
 {