Reduce coupling between refdata and libxml2
authorTeemu Murtola <teemu.murtola@gmail.com>
Mon, 3 Aug 2015 17:52:53 +0000 (20:52 +0300)
committerMark Abraham <mark.j.abraham@gmail.com>
Tue, 8 Sep 2015 11:14:32 +0000 (13:14 +0200)
Instead of directly manipulating the libxml2 XML tree in refdata.cpp,
make the reference data operations act on an internal data structure
(declared in refdata-impl.h).  Move all libxml2 interaction into
separate refdata-xml.* files.

This has several advantages:
- The internal data structure more clearly communicates the organization
  of the reference data, making the code easier to understand.
- The internal data structure can be extended to include information
  that is not easily possible to store in the XML tree, such as state
  information about what reference data items have been actually used in
  the test.
- Coupling to libxml2 is reduced, and the operations in refdata-xml.cpp
  are very standard XML manipulation commands (basically, just writing
  out a tree of elements sequentially, or reading them in), making it
  easier to make these use a common wrapper if such a wrapper is needed
  in the future for other XML operations.

One behavior change affects the tests, where the old behavior was not
worth preserving: now checkString() and checkStringBlock() can check
against the same reference data, instead of giving very obscure
assertion failures if a mismatch occurred.

Change-Id: Ie067ba65eb4ccf017ab1950b3746a9abd30da2b6

src/testutils/CMakeLists.txt
src/testutils/refdata-impl.h [new file with mode: 0644]
src/testutils/refdata-xml.cpp [new file with mode: 0644]
src/testutils/refdata-xml.h [new file with mode: 0644]
src/testutils/refdata.cpp
src/testutils/tests/refdata_tests.cpp

index 42cf92c5c6eee2de2adbdc3df418d24f712a81fb..f38e9d16503f7f7da6dcc8019b814c2276942e0a 100644 (file)
@@ -40,6 +40,7 @@ set(TESTUTILS_SOURCES
     interactivetest.cpp
     mpi-printer.cpp
     refdata.cpp
+    refdata-xml.cpp
     stringtest.cpp
     testasserts.cpp
     testfilemanager.cpp
diff --git a/src/testutils/refdata-impl.h b/src/testutils/refdata-impl.h
new file mode 100644 (file)
index 0000000..2a33540
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2015, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \internal \file
+ * \brief
+ * Declares internal data structures for the reference data framework.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \ingroup module_testutils
+ */
+#ifndef GMX_TESTUTILS_REFDATA_IMPL_H
+#define GMX_TESTUTILS_REFDATA_IMPL_H
+
+#include <list>
+#include <string>
+
+#include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/uniqueptr.h"
+
+namespace gmx
+{
+namespace test
+{
+
+class ReferenceDataEntry
+{
+    public:
+        typedef gmx_unique_ptr<ReferenceDataEntry>::type EntryPointer;
+        typedef std::list<EntryPointer> ChildList;
+        typedef ChildList::const_iterator ChildIterator;
+
+        static EntryPointer createRoot()
+        {
+            return EntryPointer(new ReferenceDataEntry("", ""));
+        }
+
+        ReferenceDataEntry(const char *type, const char *id)
+            : type_(type), id_(id != NULL ? id : ""), isTextBlock_(false)
+        {
+        }
+
+        const std::string &type() const { return type_; }
+        const std::string &id() const { return id_; }
+        bool isCompound() const { return !children_.empty(); }
+        bool isTextBlock() const { return isTextBlock_; }
+        const std::string &value() const { return value_; }
+        const ChildList &children() const { return children_; }
+
+        void setValue(const std::string &value)
+        {
+            GMX_RELEASE_ASSERT(!isCompound(),
+                               "Cannot have a value for a compound entry");
+            value_ = value;
+        }
+        void setTextBlockValue(const std::string &value)
+        {
+            GMX_RELEASE_ASSERT(!isCompound(),
+                               "Cannot have a value for a compound entry");
+            value_       = value;
+            isTextBlock_ = true;
+        }
+        ChildIterator addChild(EntryPointer child)
+        {
+            GMX_RELEASE_ASSERT(isCompound() || value_.empty(),
+                               "Cannot make an entry with a value to a compound");
+            return children_.insert(children_.end(), move(child));
+        }
+
+    private:
+        std::string  type_;
+        std::string  id_;
+        std::string  value_;
+        bool         isTextBlock_;
+        ChildList    children_;
+};
+
+} // namespace test
+} // namespace gmx
+
+#endif
diff --git a/src/testutils/refdata-xml.cpp b/src/testutils/refdata-xml.cpp
new file mode 100644 (file)
index 0000000..ae5a838
--- /dev/null
@@ -0,0 +1,369 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2015, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \internal \file
+ * \brief
+ * Implements reference data XML persistence.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \ingroup module_testutils
+ */
+#include "gmxpre.h"
+
+#include "refdata-xml.h"
+
+#include <libxml/parser.h>
+#include <libxml/xmlmemory.h>
+
+#include "gromacs/utility/exceptions.h"
+#include "gromacs/utility/scoped_cptr.h"
+
+#include "testutils/refdata-impl.h"
+#include "testutils/testexceptions.h"
+
+namespace gmx
+{
+namespace test
+{
+
+namespace
+{
+
+//! XML version used for writing the reference data.
+const xmlChar *const cXmlVersion =
+    reinterpret_cast<const xmlChar *>("1.0");
+//! Name of the XML processing instruction used for XSLT reference.
+const xmlChar *const cXmlStyleSheetNodeName =
+    reinterpret_cast<const xmlChar *>("xml-stylesheet");
+//! XSLT reference written to the reference data XML files.
+const xmlChar *const cXmlStyleSheetContent =
+    reinterpret_cast<const xmlChar *>("type=\"text/xsl\" href=\"referencedata.xsl\"");
+//! Name of the root element in reference data XML files.
+const xmlChar *const cRootNodeName =
+    reinterpret_cast<const xmlChar *>("ReferenceData");
+//! Name of the XML attribute used to store identifying strings for reference data elements.
+const xmlChar *const cIdAttrName =
+    reinterpret_cast<const xmlChar *>("Name");
+
+/********************************************************************
+ * Generic helper functions and classes
+ */
+
+//! Helper function to convert strings to xmlChars.
+const xmlChar *toXmlString(const std::string &str)
+{
+    // TODO: Consider asserting that str is ASCII.
+    return reinterpret_cast<const xmlChar *>(str.c_str());
+}
+
+//! Helper function to convert strings from xmlChars.
+const char *fromXmlString(const xmlChar *str)
+{
+    // TODO: Consider asserting that str is ASCII.
+    return reinterpret_cast<const char *>(str);
+}
+
+class XmlString
+{
+    public:
+        explicit XmlString(xmlChar *str) : str_(str) {}
+        ~XmlString()
+        {
+            if (str_ != NULL)
+            {
+                xmlFree(str_);
+            }
+        }
+
+        std::string toString() const
+        {
+            if (str_ == NULL)
+            {
+                return std::string();
+            }
+            return std::string(fromXmlString(str_));
+        }
+
+    private:
+        xmlChar *str_;
+};
+
+//! C++ wrapper for xmlDocPtr for exception safety.
+typedef scoped_cptr<xmlDoc, xmlFreeDoc> XmlDocumentPointer;
+
+}       // namespace
+
+/********************************************************************
+ * XML reading
+ */
+
+namespace
+{
+
+//! \name Helper functions for XML reading
+//! \{
+
+void readEntry(xmlNodePtr node, ReferenceDataEntry *entry);
+
+xmlNodePtr getCDataChildNode(xmlNodePtr node)
+{
+    xmlNodePtr cdata = node->children;
+    while (cdata != NULL && cdata->type != XML_CDATA_SECTION_NODE)
+    {
+        cdata = cdata->next;
+    }
+    // TODO: Consider checking that there is no more than one CDATA section.
+    return cdata;
+}
+
+bool hasCDataContent(xmlNodePtr node)
+{
+    return getCDataChildNode(node) != NULL;
+}
+
+xmlNodePtr findContentNode(xmlNodePtr node)
+{
+    xmlNodePtr cdata = getCDataChildNode(node);
+    return cdata != NULL ? cdata : node;
+}
+
+std::string getValueFromLeafElement(xmlNodePtr node)
+{
+    xmlNodePtr  contentNode = findContentNode(node);
+    XmlString   content(xmlNodeGetContent(contentNode));
+    std::string value(content.toString());
+    if (hasCDataContent(node))
+    {
+        if (value.empty() || value[0] != '\n')
+        {
+            GMX_THROW(TestException("Invalid CDATA string block in reference data"));
+        }
+        value.erase(0, 1);
+    }
+    return value;
+}
+
+ReferenceDataEntry::EntryPointer createEntry(xmlNodePtr element)
+{
+    XmlString id(xmlGetProp(element, cIdAttrName));
+    ReferenceDataEntry::EntryPointer entry(
+            new ReferenceDataEntry(fromXmlString(element->name),
+                                   id.toString().c_str()));
+    return move(entry);
+}
+
+void readChildEntries(xmlNodePtr parentElement, ReferenceDataEntry *entry)
+{
+    xmlNodePtr childElement = xmlFirstElementChild(parentElement);
+    while (childElement != NULL)
+    {
+        ReferenceDataEntry::EntryPointer child(createEntry(childElement));
+        readEntry(childElement, child.get());
+        entry->addChild(move(child));
+        childElement = xmlNextElementSibling(childElement);
+    }
+}
+
+bool isCompoundElement(xmlNodePtr node)
+{
+    return xmlFirstElementChild(node) != NULL;
+}
+
+void readEntry(xmlNodePtr element, ReferenceDataEntry *entry)
+{
+    if (isCompoundElement(element))
+    {
+        readChildEntries(element, entry);
+    }
+    else
+    {
+        entry->setValue(getValueFromLeafElement(element));
+    }
+}
+
+//! \}
+
+}       // namespace
+
+//! \cond internal
+ReferenceDataEntry::EntryPointer
+readReferenceDataFile(const std::string &path)
+{
+    XmlDocumentPointer document(xmlParseFile(path.c_str()));
+    if (!document)
+    {
+        GMX_THROW(TestException("Reference data not parsed successfully: " + path));
+    }
+    xmlNodePtr rootNode = xmlDocGetRootElement(document.get());
+    if (rootNode == NULL)
+    {
+        GMX_THROW(TestException("Reference data is empty: " + path));
+    }
+    if (xmlStrcmp(rootNode->name, cRootNodeName) != 0)
+    {
+        GMX_THROW(TestException("Invalid root node type in " + path));
+    }
+
+    ReferenceDataEntry::EntryPointer rootEntry(ReferenceDataEntry::createRoot());
+    readEntry(rootNode, rootEntry.get());
+    return move(rootEntry);
+}
+//! \endcond
+
+/********************************************************************
+ * XML writing
+ */
+
+namespace
+{
+
+//! \name Helper functions for XML writing
+//! \{
+
+void createElementAndContents(xmlNodePtr                parentNode,
+                              const ReferenceDataEntry &entry);
+
+void setIdAttribute(xmlNodePtr node, const std::string &id)
+{
+    if (!id.empty())
+    {
+        const xmlChar *xmlId = toXmlString(id);
+        xmlAttrPtr     prop  = xmlNewProp(node, cIdAttrName, xmlId);
+        if (prop == NULL)
+        {
+            GMX_THROW(TestException("XML attribute creation failed"));
+        }
+    }
+}
+
+xmlNodePtr createElement(xmlNodePtr parentNode, const ReferenceDataEntry &entry)
+{
+    xmlNodePtr node = xmlNewTextChild(parentNode, NULL, toXmlString(entry.type()), NULL);
+    if (node == NULL)
+    {
+        GMX_THROW(TestException("XML element creation failed"));
+    }
+    setIdAttribute(node, entry.id());
+    return node;
+}
+
+void createChildElements(xmlNodePtr parentNode, const ReferenceDataEntry &entry)
+{
+    const ReferenceDataEntry::ChildList &children(entry.children());
+    ReferenceDataEntry::ChildIterator    child;
+    for (child = children.begin(); child != children.end(); ++child)
+    {
+        createElementAndContents(parentNode, **child);
+    }
+}
+
+void createElementContents(xmlNodePtr node, const ReferenceDataEntry &entry)
+{
+    if (entry.isCompound())
+    {
+        createChildElements(node, entry);
+    }
+    else if (entry.isTextBlock())
+    {
+        // An extra newline is written in the beginning to make lines align
+        // in the output xml (otherwise, the first line would be off by the length
+        // of the starting CDATA tag).
+        const std::string adjustedValue = "\n" + entry.value();
+        // TODO: Figure out if \r and \r\n can be handled without them changing
+        // to \n in the roundtrip
+        xmlNodePtr cdata
+            = xmlNewCDataBlock(node->doc, toXmlString(adjustedValue),
+                               static_cast<int>(adjustedValue.length()));
+        xmlAddChild(node, cdata);
+    }
+    else
+    {
+        xmlNodeAddContent(node, toXmlString(entry.value()));
+    }
+}
+
+void createElementAndContents(xmlNodePtr parentNode, const ReferenceDataEntry &entry)
+{
+    xmlNodePtr node = createElement(parentNode, entry);
+    createElementContents(node, entry);
+}
+
+xmlNodePtr createRootElement(xmlDocPtr document)
+{
+    xmlNodePtr rootElement = xmlNewDocNode(document, NULL, cRootNodeName, NULL);
+    xmlDocSetRootElement(document, rootElement);
+    return rootElement;
+}
+
+void createXsltReference(xmlDocPtr document, xmlNodePtr rootElement)
+{
+    xmlNodePtr xslNode = xmlNewDocPI(document, cXmlStyleSheetNodeName,
+                                     cXmlStyleSheetContent);
+    xmlAddPrevSibling(rootElement, xslNode);
+}
+
+//! \}
+
+}       // namespace
+
+//! \cond internal
+void writeReferenceDataFile(const std::string        &path,
+                            const ReferenceDataEntry &rootEntry)
+{
+    // TODO: Error checking
+    XmlDocumentPointer  document(xmlNewDoc(cXmlVersion));
+    xmlNodePtr          rootElement = createRootElement(document.get());
+    createXsltReference(document.get(), rootElement);
+    createChildElements(rootElement, rootEntry);
+
+    if (xmlSaveFormatFile(path.c_str(), document.get(), 1) == -1)
+    {
+        GMX_THROW(TestException("Reference data saving failed in " + path));
+    }
+}
+//! \endcond
+
+/********************************************************************
+ * Cleanup
+ */
+
+//! \cond internal
+void cleanupReferenceData()
+{
+    xmlCleanupParser();
+}
+//! \endcond
+
+} // namespace test
+} // namespace gmx
diff --git a/src/testutils/refdata-xml.h b/src/testutils/refdata-xml.h
new file mode 100644 (file)
index 0000000..039ebe2
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2015, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \internal \file
+ * \brief
+ * Declares functions for reference data XML persistence.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \ingroup module_testutils
+ */
+#ifndef GMX_TESTUTILS_REFDATA_XML_H
+#define GMX_TESTUTILS_REFDATA_XML_H
+
+#include <string>
+
+#include "testutils/refdata-impl.h"
+
+namespace gmx
+{
+namespace test
+{
+
+class ReferenceDataEntry;
+
+//! \cond internal
+/*! \internal
+ * \brief
+ * Loads reference data from an XML file.
+ *
+ * \param[in] path  Path to the file from which the data is loaded.
+ * \returns   Root entry for the reference data parsed from the file.
+ * \throws    TestException if there is a problem reading the file.
+ *
+ * \ingroup module_testutils
+ */
+ReferenceDataEntry::EntryPointer
+readReferenceDataFile(const std::string &path);
+/*! \internal
+ * \brief
+ * Saves reference data to an XML file.
+ *
+ * \param[in] path  Path to the file to which the data is saved.
+ * \param[in] root  Root entry for the reference data to write.
+ * \throws    TestException if there is a problem writing the file.
+ *
+ * \ingroup module_testutils
+ */
+void writeReferenceDataFile(const std::string        &path,
+                            const ReferenceDataEntry &root);
+/*! \internal
+ * \brief
+ * Cleans up static memory allocated by the reference data persistence routines.
+ *
+ * \ingroup module_testutils
+ */
+void cleanupReferenceData();
+//! \endcond
+
+} // namespace test
+} // namespace gmx
+
+#endif
index afed65abbaced4e911abceaaae6aa85452aaed8d..9324d85c18a685612801339c38b2f5927be08e28 100644 (file)
 
 #include "refdata.h"
 
-#include <cstdio>
 #include <cstdlib>
 
 #include <limits>
 #include <string>
 
 #include <gtest/gtest.h>
-#include <libxml/parser.h>
-#include <libxml/xmlmemory.h>
 
 #include "gromacs/options/basicoptions.h"
 #include "gromacs/options/ioptionscontainer.h"
@@ -60,6 +57,8 @@
 #include "gromacs/utility/path.h"
 #include "gromacs/utility/stringutil.h"
 
+#include "testutils/refdata-impl.h"
+#include "testutils/refdata-xml.h"
 #include "testutils/testasserts.h"
 #include "testutils/testexceptions.h"
 #include "testutils/testfilemanager.h"
@@ -84,18 +83,8 @@ namespace internal
 class TestReferenceDataImpl
 {
     public:
-        //! String constant for output XML version string.
-        static const xmlChar * const cXmlVersion;
-        //! String constant for XML stylesheet processing instruction name.
-        static const xmlChar * const cXmlStyleSheetNodeName;
-        //! String constant for XML stylesheet reference.
-        static const xmlChar * const cXmlStyleSheetContent;
-        //! String constant for naming the root XML element.
-        static const xmlChar * const cRootNodeName;
-
         //! Initializes a checker in the given mode.
         TestReferenceDataImpl(ReferenceDataMode mode, bool bSelfTestMode);
-        ~TestReferenceDataImpl();
 
         //! Performs final reference data processing when test ends.
         void onTestEnd();
@@ -103,11 +92,11 @@ class TestReferenceDataImpl
         //! Full path of the reference data file.
         std::string             fullFilename_;
         /*! \brief
-         * XML document for the reference data.
+         * Root entry for the reference data.
          *
-         * May be NULL if there was an I/O error in initialization.
+         * If null after construction, the reference data is not present.
          */
-        xmlDocPtr               refDoc_;
+        ReferenceDataEntry::EntryPointer  rootEntry_;
         /*! \brief
          * Whether the reference data is being written (true) or compared
          * (false).
@@ -130,7 +119,7 @@ class TestReferenceDataImpl
 namespace
 {
 
-//! Convenience typedef for a smart pointer to TestReferenceDataImpl;
+//! Convenience typedef for a smart pointer to TestReferenceDataImpl.
 typedef boost::shared_ptr<internal::TestReferenceDataImpl>
     TestReferenceDataImplPointer;
 
@@ -191,7 +180,7 @@ class ReferenceDataTestEventListener : public ::testing::EmptyTestEventListener
         // Frees internal buffers allocated by libxml2.
         virtual void OnTestProgramEnd(const ::testing::UnitTest &)
         {
-            xmlCleanupParser();
+            cleanupReferenceData();
         }
 };
 
@@ -217,19 +206,9 @@ void initReferenceData(IOptionsContainer *options)
 namespace internal
 {
 
-const xmlChar * const TestReferenceDataImpl::cXmlVersion =
-    (const xmlChar *)"1.0";
-const xmlChar * const TestReferenceDataImpl::cXmlStyleSheetNodeName =
-    (const xmlChar *)"xml-stylesheet";
-const xmlChar * const TestReferenceDataImpl::cXmlStyleSheetContent =
-    (const xmlChar *)"type=\"text/xsl\" href=\"referencedata.xsl\"";
-const xmlChar * const TestReferenceDataImpl::cRootNodeName =
-    (const xmlChar *)"ReferenceData";
-
-
 TestReferenceDataImpl::TestReferenceDataImpl(
         ReferenceDataMode mode, bool bSelfTestMode)
-    : refDoc_(NULL), bWrite_(false), bSelfTestMode_(bSelfTestMode), bInUse_(false)
+    : bWrite_(false), bSelfTestMode_(bSelfTestMode), bInUse_(false)
 {
     const std::string dirname =
         bSelfTestMode
@@ -241,11 +220,9 @@ TestReferenceDataImpl::TestReferenceDataImpl(
     bWrite_ = true;
     if (mode != erefdataUpdateAll)
     {
-        FILE *fp = std::fopen(fullFilename_.c_str(), "r");
-        if (fp != NULL)
+        if (File::exists(fullFilename_))
         {
             bWrite_ = false;
-            fclose(fp);
         }
         else if (mode == erefdataCompare)
         {
@@ -255,59 +232,27 @@ TestReferenceDataImpl::TestReferenceDataImpl(
     }
     if (bWrite_)
     {
-        // TODO: Error checking
-        refDoc_ = xmlNewDoc(cXmlVersion);
-        xmlNodePtr rootNode = xmlNewDocNode(refDoc_, NULL, cRootNodeName, NULL);
-        xmlDocSetRootElement(refDoc_, rootNode);
-        xmlNodePtr xslNode = xmlNewDocPI(refDoc_, cXmlStyleSheetNodeName,
-                                         cXmlStyleSheetContent);
-        xmlAddPrevSibling(rootNode, xslNode);
+        rootEntry_ = ReferenceDataEntry::createRoot();
     }
     else
     {
-        refDoc_ = xmlParseFile(fullFilename_.c_str());
-        if (refDoc_ == NULL)
-        {
-            GMX_THROW(TestException("Reference data not parsed successfully: " + fullFilename_));
-        }
-        xmlNodePtr rootNode = xmlDocGetRootElement(refDoc_);
-        if (rootNode == NULL)
-        {
-            xmlFreeDoc(refDoc_);
-            GMX_THROW(TestException("Reference data is empty: " + fullFilename_));
-        }
-        if (xmlStrcmp(rootNode->name, cRootNodeName) != 0)
-        {
-            xmlFreeDoc(refDoc_);
-            GMX_THROW(TestException("Invalid root node type in " + fullFilename_));
-        }
-    }
-}
-
-TestReferenceDataImpl::~TestReferenceDataImpl()
-{
-    if (refDoc_ != NULL)
-    {
-        xmlFreeDoc(refDoc_);
+        rootEntry_ = readReferenceDataFile(fullFilename_);
     }
 }
 
 void TestReferenceDataImpl::onTestEnd()
 {
-    if (bWrite_ && bInUse_ && refDoc_ != NULL)
+    if (bWrite_ && bInUse_ && rootEntry_)
     {
         std::string dirname = Path::getParentPath(fullFilename_);
         if (!Directory::exists(dirname))
         {
             if (Directory::create(dirname) != 0)
             {
-                ADD_FAILURE() << "Creation of reference data directory failed for " << dirname;
+                GMX_THROW(TestException("Creation of reference data directory failed: " + dirname));
             }
         }
-        if (xmlSaveFormatFile(fullFilename_.c_str(), refDoc_, 1) == -1)
-        {
-            ADD_FAILURE() << "Saving reference data failed for " + fullFilename_;
-        }
+        writeReferenceDataFile(fullFilename_, *rootEntry_);
     }
 }
 
@@ -327,19 +272,19 @@ class TestReferenceChecker::Impl
 {
     public:
         //! String constant for naming XML elements for boolean values.
-        static const xmlChar * const cBooleanNodeName;
+        static const char * const    cBooleanNodeName;
         //! String constant for naming XML elements for string values.
-        static const xmlChar * const cStringNodeName;
+        static const char * const    cStringNodeName;
         //! String constant for naming XML elements for integer values.
-        static const xmlChar * const cIntegerNodeName;
+        static const char * const    cIntegerNodeName;
         //! String constant for naming XML elements for int64 values.
-        static const xmlChar * const cInt64NodeName;
+        static const char * const    cInt64NodeName;
         //! String constant for naming XML elements for unsigned int64 values.
-        static const xmlChar * const cUInt64NodeName;
+        static const char * const    cUInt64NodeName;
         //! String constant for naming XML elements for floating-point values.
-        static const xmlChar * const cRealNodeName;
+        static const char * const    cRealNodeName;
         //! String constant for naming XML attribute for value identifiers.
-        static const xmlChar * const cIdAttrName;
+        static const char * const    cIdAttrName;
         //! String constant for naming compounds for vectors.
         static const char * const    cVectorType;
         //! String constant for naming compounds for sequences.
@@ -349,8 +294,8 @@ class TestReferenceChecker::Impl
 
         //! Creates a checker that does nothing.
         explicit Impl(bool bWrite);
-        //! Creates a checker with a given root node.
-        Impl(const std::string &path, xmlNodePtr rootNode, bool bWrite,
+        //! Creates a checker with a given root entry.
+        Impl(const std::string &path, ReferenceDataEntry *rootEntry, bool bWrite,
              bool bSelfTestMode, const FloatingPointTolerance &defaultTolerance);
 
         //! Returns a string for SCOPED_TRACE() for checking element \p id.
@@ -358,41 +303,51 @@ class TestReferenceChecker::Impl
         //! Returns the path of this checker with \p id appended.
         std::string appendPath(const char *id) const;
 
+        //! Returns whether an iterator returned by findEntry() is valid.
+        bool isValidEntry(const ReferenceDataEntry::ChildIterator &iter) const
+        {
+            if (rootEntry_ == NULL)
+            {
+                return false;
+            }
+            return iter != rootEntry_->children().end();
+        }
+
         /*! \brief
-         * Finds a reference data node.
+         * Finds a reference data entry.
          *
-         * \param[in]  name   Type of node to find (can be NULL, in which case
+         * \param[in]  type   Type of entry 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.
+         * \param[in]  id     Unique identifier of the entry (can be NULL, in
+         *      which case the next entry without an id is matched).
+         * \returns    Matching entry, or an invalid iterator (see
+         *      isValidEntry()) if no matching entry 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.
+         * Searches for an entry in the reference data that matches the given
+         * \p name and \p id.  Searching starts from the entry that follows the
+         * previously matched entry (relevant for performance, and if there are
+         * nodes without ids).  Note that the match pointer is not updated by
+         * this method.
          */
-        xmlNodePtr findNode(const xmlChar *name, const char *id) const;
+        ReferenceDataEntry::ChildIterator
+        findEntry(const char *type, const char *id) const;
         /*! \brief
-         * Finds/creates a reference data node to match against.
+         * Finds/creates a reference data entry to match against.
          *
-         * \param[in]  name   Type of node to find.
-         * \param[in]  id     Unique identifier of the node (can be NULL, in
-         *      which case the next node without an id is matched).
-         * \param[out] bFound Whether the node was found (false if the node was
-         *      created in write mode).
-         * \returns Matching node, or NULL if no matching node found
+         * \param[in]  type   Type of entry to find.
+         * \param[in]  id     Unique identifier of the entry (can be NULL, in
+         *      which case the next entry without an id is matched).
+         * \param[out] bFound Whether the entry was found (false if the entry
+         *      was created in write mode).
+         * \returns Matching entry, or NULL if no matching entry found
          *      (NULL is never returned in write mode).
-         * \throws  TestException if node creation fails in write mode.
          *
-         * Finds a node using findNode() and updates the match pointer is a
+         * Finds an entry using findEntry() and updates the match pointer if 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.
+         * read mode and creates a new entry in write mode.
          */
-        xmlNodePtr findOrCreateNode(const xmlChar *name, const char *id,
-                                    bool *bFound);
+        ReferenceDataEntry *findOrCreateEntry(const char *type, const char *id,
+                                              bool *bFound);
         /*! \brief
          * Helper method for checking a reference data value.
          *
@@ -402,7 +357,6 @@ class TestReferenceChecker::Impl
          * \param[in]  value  String value of the value to be compared.
          * \param[out] bFound true if a matchin value was found.
          * \returns String value for the reference value.
-         * \throws  TestException if node creation fails in write mode.
          *
          * Performs common tasks in checking a reference value:
          * finding/creating the correct XML node and reading/writing its string
@@ -416,10 +370,10 @@ class TestReferenceChecker::Impl
          * In write mode, creates the node if it is not found, sets its value
          * as \p value and returns \p value.
          */
-        std::string processItem(const xmlChar *name, const char *id,
+        std::string processItem(const char *name, const char *id,
                                 const char *value, bool *bFound);
         //! Convenience wrapper that takes a std::string.
-        std::string processItem(const xmlChar *name, const char *id,
+        std::string processItem(const char *name, const char *id,
                                 const std::string &value, bool *bFound);
         /*! \brief
          * Whether the checker should ignore all validation calls.
@@ -443,26 +397,23 @@ class TestReferenceChecker::Impl
         /*! \brief
          * Current node under which reference data is searched.
          *
-         * Points to either the root of TestReferenceData::Impl::refDoc_, or to
-         * a compound node.
+         * Points to either the TestReferenceDataImpl::rootEntry_, or to
+         * a compound entry in the tree rooted at that entry.
          *
          * Can be NULL, in which case this checker does nothing (doesn't even
          * report errors, see shouldIgnore()).
          */
-        xmlNodePtr              currNode_;
+        ReferenceDataEntry     *rootEntry_;
         /*! \brief
-         * Points to a child of \a currNode_ that was last found.
+         * Iterator to a child of \a rootEntry_ that was last found.
          *
-         * On initialization, is initialized to NULL.  After every check, is
-         * updated to point to the node that was used for the check.
+         * If isValidEntry() returns false, no entry has been found yet.
+         * After every check, is updated to point to the entry that was used
+         * for the check.
          * Subsequent checks start the search for the matching node on this
          * node.
-         *
-         * Is NULL if \a currNode_ contains no children or if no checks have
-         * yet been made.
-         * Otherwise, always points to a direct child of \a currNode_.
          */
-        xmlNodePtr              prevFoundNode_;
+        ReferenceDataEntry::ChildIterator prevFoundNode_;
         /*! \brief
          * Whether the reference data is being written (true) or compared
          * (false).
@@ -478,42 +429,32 @@ class TestReferenceChecker::Impl
         int                     seqIndex_;
 };
 
-const xmlChar * const TestReferenceChecker::Impl::cBooleanNodeName =
-    (const xmlChar *)"Bool";
-const xmlChar * const TestReferenceChecker::Impl::cStringNodeName =
-    (const xmlChar *)"String";
-const xmlChar * const TestReferenceChecker::Impl::cIntegerNodeName  =
-    (const xmlChar *)"Int";
-const xmlChar * const TestReferenceChecker::Impl::cInt64NodeName  =
-    (const xmlChar *)"Int64";
-const xmlChar * const TestReferenceChecker::Impl::cUInt64NodeName  =
-    (const xmlChar *)"UInt64";
-const xmlChar * const TestReferenceChecker::Impl::cRealNodeName =
-    (const xmlChar *)"Real";
-const xmlChar * const TestReferenceChecker::Impl::cIdAttrName =
-    (const xmlChar *)"Name";
-const char * const    TestReferenceChecker::Impl::cVectorType =
-    "Vector";
-const char * const    TestReferenceChecker::Impl::cSequenceType =
-    "Sequence";
-const char * const    TestReferenceChecker::Impl::cSequenceLengthName =
-    "Length";
+const char *const TestReferenceChecker::Impl::cBooleanNodeName    = "Bool";
+const char *const TestReferenceChecker::Impl::cStringNodeName     = "String";
+const char *const TestReferenceChecker::Impl::cIntegerNodeName    = "Int";
+const char *const TestReferenceChecker::Impl::cInt64NodeName      = "Int64";
+const char *const TestReferenceChecker::Impl::cUInt64NodeName     = "UInt64";
+const char *const TestReferenceChecker::Impl::cRealNodeName       = "Real";
+const char *const TestReferenceChecker::Impl::cIdAttrName         = "Name";
+const char *const TestReferenceChecker::Impl::cVectorType         = "Vector";
+const char *const TestReferenceChecker::Impl::cSequenceType       = "Sequence";
+const char *const TestReferenceChecker::Impl::cSequenceLengthName = "Length";
 
 
 TestReferenceChecker::Impl::Impl(bool bWrite)
     : defaultTolerance_(defaultRealTolerance()),
-      currNode_(NULL), prevFoundNode_(NULL), bWrite_(bWrite),
+      rootEntry_(NULL), bWrite_(bWrite),
       bSelfTestMode_(false), seqIndex_(0)
 {
 }
 
 
-TestReferenceChecker::Impl::Impl(const std::string &path, xmlNodePtr rootNode,
+TestReferenceChecker::Impl::Impl(const std::string &path, ReferenceDataEntry *rootEntry,
                                  bool bWrite, bool bSelfTestMode,
                                  const FloatingPointTolerance &defaultTolerance)
     : defaultTolerance_(defaultTolerance), path_(path + "/"),
-      currNode_(rootNode), prevFoundNode_(NULL), bWrite_(bWrite),
-      bSelfTestMode_(bSelfTestMode), seqIndex_(0)
+      rootEntry_(rootEntry), prevFoundNode_(rootEntry->children().end()),
+      bWrite_(bWrite), bSelfTestMode_(bSelfTestMode), seqIndex_(0)
 {
 }
 
@@ -533,105 +474,89 @@ TestReferenceChecker::Impl::appendPath(const char *id) const
 }
 
 
-xmlNodePtr
-TestReferenceChecker::Impl::findNode(const xmlChar *name, const char *id) const
+ReferenceDataEntry::ChildIterator
+TestReferenceChecker::Impl::findEntry(const char *type, const char *id) const
 {
-    if (currNode_ == NULL || currNode_->children == NULL)
+    const ReferenceDataEntry::ChildList &children = rootEntry_->children();
+    if (children.empty())
     {
-        return NULL;
+        return children.end();
     }
-    const xmlChar *xmlId = reinterpret_cast<const xmlChar *>(id);
-    xmlNodePtr     node  = prevFoundNode_;
-    bool           bWrap = true;
-    if (node != NULL)
+    ReferenceDataEntry::ChildIterator  node  = prevFoundNode_;
+    bool                               bWrap = true;
+    if (node != children.end())
     {
         if (id == NULL)
         {
-            xmlChar *refId = xmlGetProp(node, cIdAttrName);
-            if (refId == NULL)
+            if ((*node)->id().empty())
             {
-                if (name == NULL || xmlStrcmp(node->name, name) == 0)
+                if (type == NULL || (*node)->type() == type)
                 {
                     bWrap = false;
-                    node  = node->next;
-                    if (node == NULL)
+                    ++node;
+                    if (node == children.end())
                     {
-                        return NULL;
+                        return children.end();
                     }
                 }
             }
-            else
-            {
-                xmlFree(refId);
-            }
         }
     }
     else
     {
-        node  = currNode_->children;
+        node  = children.begin();
         bWrap = false;
     }
     do
     {
-        if (name == NULL || xmlStrcmp(node->name, name) == 0)
+        if (type == NULL || (*node)->type() == type)
         {
-            xmlChar *refId = xmlGetProp(node, cIdAttrName);
-            if (xmlId == NULL && refId == NULL)
+            if (id == NULL && (*node)->id().empty())
             {
                 return node;
             }
-            if (refId != NULL)
+            if (!(*node)->id().empty())
             {
-                if (xmlId != NULL && xmlStrcmp(refId, xmlId) == 0)
+                if (id != NULL && (*node)->id() == id)
                 {
-                    xmlFree(refId);
                     return node;
                 }
-                xmlFree(refId);
             }
         }
-        node = node->next;
-        if (bWrap && node == NULL)
+        ++node;
+        if (bWrap && node == children.end())
         {
-            node = currNode_->children;
+            node = children.begin();
         }
     }
-    while (node != NULL && node != prevFoundNode_);
-    return NULL;
+    while (node != children.end() && node != prevFoundNode_);
+    return children.end();
 }
 
 
-xmlNodePtr
-TestReferenceChecker::Impl::findOrCreateNode(const xmlChar *name,
-                                             const char    *id,
-                                             bool          *bFound)
+ReferenceDataEntry *
+TestReferenceChecker::Impl::findOrCreateEntry(const char *type,
+                                              const char *id,
+                                              bool       *bFound)
 {
     *bFound = false;
-    xmlNodePtr node = findNode(name, id);
-    if (node != NULL)
+    if (rootEntry_ == NULL)
+    {
+        return NULL;
+    }
+    ReferenceDataEntry::ChildIterator node = findEntry(type, id);
+    if (isValidEntry(node))
     {
         *bFound        = true;
         prevFoundNode_ = node;
     }
-    if (node == NULL)
+    else
     {
         if (bWrite_)
         {
-            node = xmlNewTextChild(currNode_, NULL, name, NULL);
-            if (node != NULL && id != NULL)
-            {
-                const xmlChar *xmlId = reinterpret_cast<const xmlChar *>(id);
-                xmlAttrPtr     prop  = xmlNewProp(node, cIdAttrName, xmlId);
-                if (prop == NULL)
-                {
-                    xmlFreeNode(node);
-                    node = NULL;
-                }
-            }
-            if (node == NULL)
-            {
-                GMX_THROW(TestException("XML node creation failed"));
-            }
+            ReferenceDataEntry::EntryPointer newEntry(
+                    new ReferenceDataEntry(type, id));
+            node           = rootEntry_->addChild(move(newEntry));
             prevFoundNode_ = node;
         }
         else
@@ -641,47 +566,44 @@ TestReferenceChecker::Impl::findOrCreateNode(const xmlChar *name,
     }
     seqIndex_ = (id == NULL) ? seqIndex_+1 : 0;
 
-    return node;
+    return isValidEntry(node) ? node->get() : NULL;
 }
 
 
 std::string
-TestReferenceChecker::Impl::processItem(const xmlChar *name, const char *id,
+TestReferenceChecker::Impl::processItem(const char *type, const char *id,
                                         const char *value, bool *bFound)
 {
-    xmlNodePtr node = findOrCreateNode(name, id, bFound);
+    ReferenceDataEntry *node = findOrCreateEntry(type, id, bFound);
     if (node == NULL)
     {
         return std::string();
     }
     if (bWrite_ && !*bFound)
     {
-        xmlNodeAddContent(node, reinterpret_cast<const xmlChar *>(value));
+        node->setValue(value);
         *bFound = true;
         return std::string(value);
     }
     else
     {
-        xmlChar    *refXmlValue = xmlNodeGetContent(node);
-        std::string refValue(reinterpret_cast<const char *>(refXmlValue));
-        xmlFree(refXmlValue);
-        return refValue;
+        return node->value();
     }
 }
 
 
 std::string
-TestReferenceChecker::Impl::processItem(const xmlChar *name, const char *id,
+TestReferenceChecker::Impl::processItem(const char *type, const char *id,
                                         const std::string &value, bool *bFound)
 {
-    return processItem(name, id, value.c_str(), bFound);
+    return processItem(type, id, value.c_str(), bFound);
 }
 
 
 bool
 TestReferenceChecker::Impl::shouldIgnore() const
 {
-    return currNode_ == NULL;
+    return rootEntry_ == NULL;
 }
 
 
@@ -714,22 +636,19 @@ bool TestReferenceData::isWriteMode() const
 
 TestReferenceChecker TestReferenceData::rootChecker()
 {
-    if (!isWriteMode() && !impl_->bInUse_ && impl_->refDoc_ == NULL)
+    if (!isWriteMode() && !impl_->bInUse_ && !impl_->rootEntry_)
     {
         ADD_FAILURE() << "Reference data file not found: "
         << impl_->fullFilename_;
     }
     impl_->bInUse_ = true;
-    if (impl_->refDoc_ == NULL)
+    if (!impl_->rootEntry_)
     {
         return TestReferenceChecker(new TestReferenceChecker::Impl(isWriteMode()));
     }
-    xmlNodePtr rootNode = xmlDocGetRootElement(impl_->refDoc_);
-    // TODO: The default tolerance for double-precision builds that explicitly
-    // call checkFloat() may not be ideal.
     return TestReferenceChecker(
-            new TestReferenceChecker::Impl("", rootNode, isWriteMode(),
-                                           impl_->bSelfTestMode_,
+            new TestReferenceChecker::Impl("", impl_->rootEntry_.get(),
+                                           isWriteMode(), impl_->bSelfTestMode_,
                                            defaultRealTolerance()));
 }
 
@@ -782,8 +701,8 @@ bool TestReferenceChecker::checkPresent(bool bPresent, const char *id)
     {
         return bPresent;
     }
-    xmlNodePtr node   = impl_->findNode(NULL, id);
-    bool       bFound = (node != NULL);
+    ReferenceDataEntry::ChildIterator  node   = impl_->findEntry(NULL, id);
+    bool                               bFound = impl_->isValidEntry(node);
     if (bFound != bPresent)
     {
         ADD_FAILURE() << "Mismatch while checking reference data item '"
@@ -807,9 +726,8 @@ TestReferenceChecker TestReferenceChecker::checkCompound(const char *type, const
     {
         return TestReferenceChecker(new Impl(isWriteMode()));
     }
-    const xmlChar *xmlNodeName = reinterpret_cast<const xmlChar *>(type);
-    bool           bFound;
-    xmlNodePtr     newNode     = impl_->findOrCreateNode(xmlNodeName, id, &bFound);
+    bool                bFound;
+    ReferenceDataEntry *newNode = impl_->findOrCreateEntry(type, id, &bFound);
     if (newNode == NULL)
     {
         return TestReferenceChecker(new Impl(isWriteMode()));
@@ -869,49 +787,19 @@ void TestReferenceChecker::checkStringBlock(const std::string &value,
         return;
     }
     SCOPED_TRACE(impl_->traceString(id));
-    bool       bFound;
-    xmlNodePtr node = impl_->findOrCreateNode(Impl::cStringNodeName, id, &bFound);
+    bool                bFound;
+    ReferenceDataEntry *node = impl_->findOrCreateEntry(Impl::cStringNodeName, id, &bFound);
     if (node == NULL)
     {
         return;
     }
-    // An extra newline is written in the beginning to make lines align
-    // in the output xml (otherwise, the first line would be off by the length
-    // of the starting CDATA tag).
     if (isWriteMode() && !bFound)
     {
-        std::string    adjustedValue = "\n" + value;
-        const xmlChar *xmlValue
-            = reinterpret_cast<const xmlChar *>(adjustedValue.c_str());
-        // TODO: Figure out if \r and \r\n can be handled without them changing
-        // to \n in the roundtrip
-        xmlNodePtr cdata
-            = xmlNewCDataBlock(node->doc, xmlValue,
-                               static_cast<int>(adjustedValue.length()));
-        xmlAddChild(node, cdata);
+        node->setTextBlockValue(value);
     }
     else
     {
-        xmlNodePtr cdata = node->children;
-        while (cdata != NULL && cdata->type != XML_CDATA_SECTION_NODE)
-        {
-            cdata = cdata->next;
-        }
-        if (cdata == NULL)
-        {
-            ADD_FAILURE() << "Invalid string block element";
-            return;
-        }
-        xmlChar *refXmlValue = xmlNodeGetContent(cdata);
-        if (refXmlValue[0] != '\n')
-        {
-            ADD_FAILURE() << "Invalid string block element";
-            xmlFree(refXmlValue);
-            return;
-        }
-        std::string refValue(reinterpret_cast<const char *>(refXmlValue + 1));
-        xmlFree(refXmlValue);
-        EXPECT_EQ(refValue, value);
+        EXPECT_EQ(node->value(), value);
     }
 }
 
index ec095624591f0f48dded05a5ce44225874494e30..d7f0853e8f455842f88486458b3eb06d0946186e 100644 (file)
@@ -145,8 +145,8 @@ TEST(ReferenceDataTest, HandlesStringBlockData)
         TestReferenceData    data(gmx::test::erefdataCompare);
         TestReferenceChecker checker(data.rootChecker());
         checker.checkStringBlock("Line1\nLine2\n", "block");
-        EXPECT_NONFATAL_FAILURE(checker.checkString("Line1\nLine2\n", "block"), "");
-        EXPECT_NONFATAL_FAILURE(checker.checkStringBlock("Test", "string"), "");
+        checker.checkString("Line1\nLine2\n", "block");
+        checker.checkStringBlock("Test", "string");
     }
 }