Correct nrdf for 1D/2D systems
[gromacs/AngularHB.git] / src / testutils / refdata.cpp
blobf9bab1ecf394b2dfa9b4e2971c627aa625bd6c8d
1 /*
2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2011,2012,2013,2014,2015, by the GROMACS development team, led by
5 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6 * and including many others, as listed in the AUTHORS file in the
7 * top-level source directory and at http://www.gromacs.org.
9 * GROMACS is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1
12 * of the License, or (at your option) any later version.
14 * GROMACS is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with GROMACS; if not, see
21 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 * If you want to redistribute modifications to GROMACS, please
25 * consider that scientific software is very special. Version
26 * control is crucial - bugs must be traceable. We will be happy to
27 * consider code for inclusion in the official distribution, but
28 * derived work must not be called official GROMACS. Details are found
29 * in the README & COPYING files - if they are missing, get the
30 * official version at http://www.gromacs.org.
32 * To help us fund GROMACS development, we humbly ask that you cite
33 * the research papers on the package. Check out http://www.gromacs.org.
35 /*! \internal \file
36 * \brief
37 * Implements classes and functions from refdata.h.
39 * \author Teemu Murtola <teemu.murtola@gmail.com>
40 * \ingroup module_testutils
42 #include "gmxpre.h"
44 #include "refdata.h"
46 #include <cstdio>
47 #include <cstdlib>
49 #include <limits>
50 #include <string>
52 #include <gtest/gtest.h>
53 #include <libxml/parser.h>
54 #include <libxml/xmlmemory.h>
56 #include "gromacs/options/basicoptions.h"
57 #include "gromacs/options/options.h"
58 #include "gromacs/utility/exceptions.h"
59 #include "gromacs/utility/gmxassert.h"
60 #include "gromacs/utility/path.h"
61 #include "gromacs/utility/stringutil.h"
63 #include "testutils/testasserts.h"
64 #include "testutils/testexceptions.h"
65 #include "testutils/testfilemanager.h"
67 namespace
70 /*! \internal \brief
71 * Global test environment for freeing up libxml2 internal buffers.
73 class TestReferenceDataEnvironment : public ::testing::Environment
75 public:
76 //! Frees internal buffers allocated by libxml2.
77 virtual void TearDown()
79 xmlCleanupParser();
83 //! Global reference data mode set with gmx::test::setReferenceDataMode().
84 // TODO: Make this a real enum; requires solving a TODO in StringOption.
85 int g_referenceDataMode = gmx::test::erefdataCompare;
87 //! Returns the global reference data mode.
88 gmx::test::ReferenceDataMode getReferenceDataMode()
90 return static_cast<gmx::test::ReferenceDataMode>(g_referenceDataMode);
93 } // namespace
95 namespace gmx
97 namespace test
100 void initReferenceData(Options *options)
102 // Needs to correspond to the enum order in refdata.h.
103 const char *const refDataEnum[] = { "check", "create", "update" };
104 options->addOption(
105 StringOption("ref-data").enumValue(refDataEnum)
106 .defaultEnumIndex(0)
107 .storeEnumIndex(&g_referenceDataMode)
108 .description("Operation mode for tests that use reference data"));
109 ::testing::AddGlobalTestEnvironment(new TestReferenceDataEnvironment);
112 /********************************************************************
113 * TestReferenceData::Impl
116 /*! \internal \brief
117 * Private implementation class for TestReferenceData.
119 * \ingroup module_testutils
121 class TestReferenceData::Impl
123 public:
124 //! String constant for output XML version string.
125 static const xmlChar * const cXmlVersion;
126 //! String constant for XML stylesheet processing instruction name.
127 static const xmlChar * const cXmlStyleSheetNodeName;
128 //! String constant for XML stylesheet reference.
129 static const xmlChar * const cXmlStyleSheetContent;
130 //! String constant for naming the root XML element.
131 static const xmlChar * const cRootNodeName;
133 //! Initializes a checker in the given mode.
134 Impl(ReferenceDataMode mode, bool bSelfTestMode);
135 ~Impl();
137 //! Full path of the reference data file.
138 std::string fullFilename_;
139 /*! \brief
140 * XML document for the reference data.
142 * May be NULL if there was an I/O error in initialization.
144 xmlDocPtr refDoc_;
145 /*! \brief
146 * Whether the reference data is being written (true) or compared
147 * (false).
149 bool bWrite_;
150 //! `true` if self-testing (enables extra failure messages).
151 bool bSelfTestMode_;
152 /*! \brief
153 * Whether any reference checkers have been created for this data.
155 bool bInUse_;
158 const xmlChar * const TestReferenceData::Impl::cXmlVersion =
159 (const xmlChar *)"1.0";
160 const xmlChar * const TestReferenceData::Impl::cXmlStyleSheetNodeName =
161 (const xmlChar *)"xml-stylesheet";
162 const xmlChar * const TestReferenceData::Impl::cXmlStyleSheetContent =
163 (const xmlChar *)"type=\"text/xsl\" href=\"referencedata.xsl\"";
164 const xmlChar * const TestReferenceData::Impl::cRootNodeName =
165 (const xmlChar *)"ReferenceData";
168 TestReferenceData::Impl::Impl(ReferenceDataMode mode, bool bSelfTestMode)
169 : refDoc_(NULL), bWrite_(false), bSelfTestMode_(bSelfTestMode), bInUse_(false)
171 const std::string dirname =
172 bSelfTestMode
173 ? TestFileManager::getGlobalOutputTempDirectory()
174 : TestFileManager::getInputDataDirectory();
175 const std::string filename = TestFileManager::getTestSpecificFileName(".xml");
176 fullFilename_ = Path::join(dirname, "refdata", filename);
178 bWrite_ = true;
179 if (mode != erefdataUpdateAll)
181 FILE *fp = std::fopen(fullFilename_.c_str(), "r");
182 if (fp != NULL)
184 bWrite_ = false;
185 fclose(fp);
187 else if (mode == erefdataCompare)
189 bWrite_ = false;
190 return;
193 if (bWrite_)
195 // TODO: Error checking
196 refDoc_ = xmlNewDoc(cXmlVersion);
197 xmlNodePtr rootNode = xmlNewDocNode(refDoc_, NULL, cRootNodeName, NULL);
198 xmlDocSetRootElement(refDoc_, rootNode);
199 xmlNodePtr xslNode = xmlNewDocPI(refDoc_, cXmlStyleSheetNodeName,
200 cXmlStyleSheetContent);
201 xmlAddPrevSibling(rootNode, xslNode);
203 else
205 refDoc_ = xmlParseFile(fullFilename_.c_str());
206 if (refDoc_ == NULL)
208 GMX_THROW(TestException("Reference data not parsed successfully: " + fullFilename_));
210 xmlNodePtr rootNode = xmlDocGetRootElement(refDoc_);
211 if (rootNode == NULL)
213 xmlFreeDoc(refDoc_);
214 GMX_THROW(TestException("Reference data is empty: " + fullFilename_));
216 if (xmlStrcmp(rootNode->name, cRootNodeName) != 0)
218 xmlFreeDoc(refDoc_);
219 GMX_THROW(TestException("Invalid root node type in " + fullFilename_));
225 TestReferenceData::Impl::~Impl()
227 if (bWrite_ && bInUse_ && refDoc_ != NULL)
229 std::string dirname = Path::getParentPath(fullFilename_);
230 if (!Directory::exists(dirname))
232 if (Directory::create(dirname) != 0)
234 ADD_FAILURE() << "Creation of reference data directory failed for " << dirname;
237 if (xmlSaveFormatFile(fullFilename_.c_str(), refDoc_, 1) == -1)
239 ADD_FAILURE() << "Saving reference data failed for " + fullFilename_;
242 if (refDoc_ != NULL)
244 xmlFreeDoc(refDoc_);
249 /********************************************************************
250 * TestReferenceChecker::Impl
253 /*! \internal \brief
254 * Private implementation class for TestReferenceChecker.
256 * \ingroup module_testutils
258 class TestReferenceChecker::Impl
260 public:
261 //! String constant for naming XML elements for boolean values.
262 static const xmlChar * const cBooleanNodeName;
263 //! String constant for naming XML elements for string values.
264 static const xmlChar * const cStringNodeName;
265 //! String constant for naming XML elements for integer values.
266 static const xmlChar * const cIntegerNodeName;
267 //! String constant for naming XML elements for int64 values.
268 static const xmlChar * const cInt64NodeName;
269 //! String constant for naming XML elements for unsigned int64 values.
270 static const xmlChar * const cUInt64NodeName;
271 //! String constant for naming XML elements for floating-point values.
272 static const xmlChar * const cRealNodeName;
273 //! String constant for naming XML attribute for value identifiers.
274 static const xmlChar * const cIdAttrName;
275 //! String constant for naming compounds for vectors.
276 static const char * const cVectorType;
277 //! String constant for naming compounds for sequences.
278 static const char * const cSequenceType;
279 //! String constant for value identifier for sequence length.
280 static const char * const cSequenceLengthName;
282 //! Creates a checker that does nothing.
283 explicit Impl(bool bWrite);
284 //! Creates a checker with a given root node.
285 Impl(const std::string &path, xmlNodePtr rootNode, bool bWrite,
286 bool bSelfTestMode, const FloatingPointTolerance &defaultTolerance);
288 //! Returns a string for SCOPED_TRACE() for checking element \p id.
289 std::string traceString(const char *id) const;
290 //! Returns the path of this checker with \p id appended.
291 std::string appendPath(const char *id) const;
293 /*! \brief
294 * Finds a reference data node.
296 * \param[in] name Type of node to find (can be NULL, in which case
297 * any type is matched).
298 * \param[in] id Unique identifier of the node (can be NULL, in
299 * which case the next node without an id is matched).
300 * \returns Matching node, or NULL if no matching node found.
302 * Searches for a node in the reference data that matches the given
303 * \p name and \p id. Searching starts from the node that follows the
304 * previously matched node (relevant for performance, and if there are
305 * duplicate ids or nodes without ids). Note that the match pointer is
306 * not updated by this method.
308 xmlNodePtr findNode(const xmlChar *name, const char *id) const;
309 /*! \brief
310 * Finds/creates a reference data node to match against.
312 * \param[in] name Type of node to find.
313 * \param[in] id Unique identifier of the node (can be NULL, in
314 * which case the next node without an id is matched).
315 * \param[out] bFound Whether the node was found (false if the node was
316 * created in write mode).
317 * \returns Matching node, or NULL if no matching node found
318 * (NULL is never returned in write mode).
319 * \throws TestException if node creation fails in write mode.
321 * Finds a node using findNode() and updates the match pointer is a
322 * match is found. If a match is not found, the method returns NULL in
323 * read mode and creates a new node in write mode. If the creation
324 * fails in write mode, throws.
326 xmlNodePtr findOrCreateNode(const xmlChar *name, const char *id,
327 bool *bFound);
328 /*! \brief
329 * Helper method for checking a reference data value.
331 * \param[in] name Type of node to find.
332 * \param[in] id Unique identifier of the node (can be NULL, in
333 * which case the next node without an id is matched).
334 * \param[in] value String value of the value to be compared.
335 * \param[out] bFound true if a matchin value was found.
336 * \returns String value for the reference value.
337 * \throws TestException if node creation fails in write mode.
339 * Performs common tasks in checking a reference value:
340 * finding/creating the correct XML node and reading/writing its string
341 * value. Caller is responsible for converting the value to and from
342 * string where necessary and performing the actual comparison.
344 * In read mode, if a value is not found, adds a Google Test failure
345 * and returns an empty string. If the reference value is found,
346 * returns it (\p value is not used in this case).
348 * In write mode, creates the node if it is not found, sets its value
349 * as \p value and returns \p value.
351 std::string processItem(const xmlChar *name, const char *id,
352 const char *value, bool *bFound);
353 //! Convenience wrapper that takes a std::string.
354 std::string processItem(const xmlChar *name, const char *id,
355 const std::string &value, bool *bFound);
356 /*! \brief
357 * Whether the checker should ignore all validation calls.
359 * This is used to ignore any calls within compounds for which
360 * reference data could not be found, such that only one error is
361 * issued for the missing compound, instead of every individual value.
363 bool shouldIgnore() const;
365 //! Default floating-point comparison tolerance.
366 FloatingPointTolerance defaultTolerance_;
367 /*! \brief
368 * Human-readable path to the root node of this checker.
370 * For the root checker, this will be "/", and for each compound, the
371 * id of the compound is added. Used for reporting comparison
372 * mismatches.
374 std::string path_;
375 /*! \brief
376 * Current node under which reference data is searched.
378 * Points to either the root of TestReferenceData::Impl::refDoc_, or to
379 * a compound node.
381 * Can be NULL, in which case this checker does nothing (doesn't even
382 * report errors, see shouldIgnore()).
384 xmlNodePtr currNode_;
385 /*! \brief
386 * Points to a child of \a currNode_ that was last found.
388 * On initialization, is initialized to NULL. After every check, is
389 * updated to point to the node that was used for the check.
390 * Subsequent checks start the search for the matching node on this
391 * node.
393 * Is NULL if \a currNode_ contains no children or if no checks have
394 * yet been made.
395 * Otherwise, always points to a direct child of \a currNode_.
397 xmlNodePtr prevFoundNode_;
398 /*! \brief
399 * Whether the reference data is being written (true) or compared
400 * (false).
402 bool bWrite_;
403 //! `true` if self-testing (enables extra failure messages).
404 bool bSelfTestMode_;
405 /*! \brief
406 * Current number of unnamed elements in a sequence.
408 * It is the index of the next added unnamed element.
410 int seqIndex_;
413 const xmlChar * const TestReferenceChecker::Impl::cBooleanNodeName =
414 (const xmlChar *)"Bool";
415 const xmlChar * const TestReferenceChecker::Impl::cStringNodeName =
416 (const xmlChar *)"String";
417 const xmlChar * const TestReferenceChecker::Impl::cIntegerNodeName =
418 (const xmlChar *)"Int";
419 const xmlChar * const TestReferenceChecker::Impl::cInt64NodeName =
420 (const xmlChar *)"Int64";
421 const xmlChar * const TestReferenceChecker::Impl::cUInt64NodeName =
422 (const xmlChar *)"UInt64";
423 const xmlChar * const TestReferenceChecker::Impl::cRealNodeName =
424 (const xmlChar *)"Real";
425 const xmlChar * const TestReferenceChecker::Impl::cIdAttrName =
426 (const xmlChar *)"Name";
427 const char * const TestReferenceChecker::Impl::cVectorType =
428 "Vector";
429 const char * const TestReferenceChecker::Impl::cSequenceType =
430 "Sequence";
431 const char * const TestReferenceChecker::Impl::cSequenceLengthName =
432 "Length";
435 TestReferenceChecker::Impl::Impl(bool bWrite)
436 : defaultTolerance_(defaultRealTolerance()),
437 currNode_(NULL), prevFoundNode_(NULL), bWrite_(bWrite),
438 bSelfTestMode_(false), seqIndex_(0)
443 TestReferenceChecker::Impl::Impl(const std::string &path, xmlNodePtr rootNode,
444 bool bWrite, bool bSelfTestMode,
445 const FloatingPointTolerance &defaultTolerance)
446 : defaultTolerance_(defaultTolerance), path_(path + "/"),
447 currNode_(rootNode), prevFoundNode_(NULL), bWrite_(bWrite),
448 bSelfTestMode_(bSelfTestMode), seqIndex_(0)
453 std::string
454 TestReferenceChecker::Impl::traceString(const char *id) const
456 return "Checking '" + appendPath(id) + "'";
460 std::string
461 TestReferenceChecker::Impl::appendPath(const char *id) const
463 std::string printId = (id != NULL) ? id : formatString("[%d]", seqIndex_);
464 return path_ + printId;
468 xmlNodePtr
469 TestReferenceChecker::Impl::findNode(const xmlChar *name, const char *id) const
471 if (currNode_ == NULL || currNode_->children == NULL)
473 return NULL;
475 const xmlChar *xmlId = reinterpret_cast<const xmlChar *>(id);
476 xmlNodePtr node = prevFoundNode_;
477 bool bWrap = true;
478 if (node != NULL)
480 if (id == NULL)
482 xmlChar *refId = xmlGetProp(node, cIdAttrName);
483 if (refId == NULL)
485 if (name == NULL || xmlStrcmp(node->name, name) == 0)
487 bWrap = false;
488 node = node->next;
489 if (node == NULL)
491 return NULL;
495 else
497 xmlFree(refId);
501 else
503 node = currNode_->children;
504 bWrap = false;
508 if (name == NULL || xmlStrcmp(node->name, name) == 0)
510 xmlChar *refId = xmlGetProp(node, cIdAttrName);
511 if (xmlId == NULL && refId == NULL)
513 return node;
515 if (refId != NULL)
517 if (xmlId != NULL && xmlStrcmp(refId, xmlId) == 0)
519 xmlFree(refId);
520 return node;
522 xmlFree(refId);
525 node = node->next;
526 if (bWrap && node == NULL)
528 node = currNode_->children;
531 while (node != NULL && node != prevFoundNode_);
532 return NULL;
536 xmlNodePtr
537 TestReferenceChecker::Impl::findOrCreateNode(const xmlChar *name,
538 const char *id,
539 bool *bFound)
541 *bFound = false;
542 xmlNodePtr node = findNode(name, id);
543 if (node != NULL)
545 *bFound = true;
546 prevFoundNode_ = node;
548 if (node == NULL)
550 if (bWrite_)
552 node = xmlNewTextChild(currNode_, NULL, name, NULL);
553 if (node != NULL && id != NULL)
555 const xmlChar *xmlId = reinterpret_cast<const xmlChar *>(id);
556 xmlAttrPtr prop = xmlNewProp(node, cIdAttrName, xmlId);
557 if (prop == NULL)
559 xmlFreeNode(node);
560 node = NULL;
563 if (node == NULL)
565 GMX_THROW(TestException("XML node creation failed"));
567 prevFoundNode_ = node;
569 else
571 ADD_FAILURE() << "Reference data item not found";
574 seqIndex_ = (id == NULL) ? seqIndex_+1 : 0;
576 return node;
580 std::string
581 TestReferenceChecker::Impl::processItem(const xmlChar *name, const char *id,
582 const char *value, bool *bFound)
584 xmlNodePtr node = findOrCreateNode(name, id, bFound);
585 if (node == NULL)
587 return std::string();
589 if (bWrite_ && !*bFound)
591 xmlNodeAddContent(node, reinterpret_cast<const xmlChar *>(value));
592 *bFound = true;
593 return std::string(value);
595 else
597 xmlChar *refXmlValue = xmlNodeGetContent(node);
598 std::string refValue(reinterpret_cast<const char *>(refXmlValue));
599 xmlFree(refXmlValue);
600 return refValue;
605 std::string
606 TestReferenceChecker::Impl::processItem(const xmlChar *name, const char *id,
607 const std::string &value, bool *bFound)
609 return processItem(name, id, value.c_str(), bFound);
613 bool
614 TestReferenceChecker::Impl::shouldIgnore() const
616 return currNode_ == NULL;
620 /********************************************************************
621 * TestReferenceData
624 TestReferenceData::TestReferenceData()
625 : impl_(new Impl(getReferenceDataMode(), false))
630 TestReferenceData::TestReferenceData(ReferenceDataMode mode)
631 : impl_(new Impl(mode, true))
636 TestReferenceData::~TestReferenceData()
641 bool TestReferenceData::isWriteMode() const
643 return impl_->bWrite_;
647 TestReferenceChecker TestReferenceData::rootChecker()
649 if (!isWriteMode() && !impl_->bInUse_ && impl_->refDoc_ == NULL)
651 ADD_FAILURE() << "Reference data file not found: "
652 << impl_->fullFilename_;
654 impl_->bInUse_ = true;
655 if (impl_->refDoc_ == NULL)
657 return TestReferenceChecker(new TestReferenceChecker::Impl(isWriteMode()));
659 xmlNodePtr rootNode = xmlDocGetRootElement(impl_->refDoc_);
660 // TODO: The default tolerance for double-precision builds that explicitly
661 // call checkFloat() may not be ideal.
662 return TestReferenceChecker(
663 new TestReferenceChecker::Impl("", rootNode, isWriteMode(),
664 impl_->bSelfTestMode_,
665 defaultRealTolerance()));
669 /********************************************************************
670 * TestReferenceChecker
673 TestReferenceChecker::TestReferenceChecker(Impl *impl)
674 : impl_(impl)
679 TestReferenceChecker::TestReferenceChecker(const TestReferenceChecker &other)
680 : impl_(new Impl(*other.impl_))
685 TestReferenceChecker &
686 TestReferenceChecker::operator=(const TestReferenceChecker &other)
688 impl_.reset(new Impl(*other.impl_));
689 return *this;
693 TestReferenceChecker::~TestReferenceChecker()
698 bool TestReferenceChecker::isWriteMode() const
700 return impl_->bWrite_;
704 void TestReferenceChecker::setDefaultTolerance(
705 const FloatingPointTolerance &tolerance)
707 impl_->defaultTolerance_ = tolerance;
711 bool TestReferenceChecker::checkPresent(bool bPresent, const char *id)
713 if (isWriteMode() || impl_->shouldIgnore())
715 return bPresent;
717 xmlNodePtr node = impl_->findNode(NULL, id);
718 bool bFound = (node != NULL);
719 if (bFound != bPresent)
721 ADD_FAILURE() << "Mismatch while checking reference data item '"
722 << impl_->appendPath(id) << "'\n"
723 << "Expected: " << (bPresent ? "it is present.\n" : "it is absent.\n")
724 << " Actual: " << (bFound ? "it is present." : "it is absent.");
726 if (bFound && bPresent)
728 impl_->prevFoundNode_ = node;
729 return true;
731 return false;
735 TestReferenceChecker TestReferenceChecker::checkCompound(const char *type, const char *id)
737 SCOPED_TRACE(impl_->traceString(id));
738 if (impl_->shouldIgnore())
740 return TestReferenceChecker(new Impl(isWriteMode()));
742 const xmlChar *xmlNodeName = reinterpret_cast<const xmlChar *>(type);
743 bool bFound;
744 xmlNodePtr newNode = impl_->findOrCreateNode(xmlNodeName, id, &bFound);
745 if (newNode == NULL)
747 return TestReferenceChecker(new Impl(isWriteMode()));
749 return TestReferenceChecker(
750 new Impl(impl_->appendPath(id), newNode, isWriteMode(),
751 impl_->bSelfTestMode_, impl_->defaultTolerance_));
755 void TestReferenceChecker::checkBoolean(bool value, const char *id)
757 if (impl_->shouldIgnore())
759 return;
761 SCOPED_TRACE(impl_->traceString(id));
762 bool bFound = false;
763 const char *strValue = value ? "true" : "false";
764 std::string refStrValue =
765 impl_->processItem(Impl::cBooleanNodeName, id, strValue, &bFound);
766 if (bFound)
768 EXPECT_EQ(refStrValue, strValue);
773 void TestReferenceChecker::checkString(const char *value, const char *id)
775 if (impl_->shouldIgnore())
777 return;
779 SCOPED_TRACE(impl_->traceString(id));
780 bool bFound = false;
781 std::string refStrValue =
782 impl_->processItem(Impl::cStringNodeName, id, value, &bFound);
783 if (bFound)
785 EXPECT_EQ(refStrValue, value);
790 void TestReferenceChecker::checkString(const std::string &value, const char *id)
792 checkString(value.c_str(), id);
796 void TestReferenceChecker::checkStringBlock(const std::string &value,
797 const char *id)
799 if (impl_->shouldIgnore())
801 return;
803 SCOPED_TRACE(impl_->traceString(id));
804 bool bFound;
805 xmlNodePtr node = impl_->findOrCreateNode(Impl::cStringNodeName, id, &bFound);
806 if (node == NULL)
808 return;
810 // An extra newline is written in the beginning to make lines align
811 // in the output xml (otherwise, the first line would be off by the length
812 // of the starting CDATA tag).
813 if (isWriteMode() && !bFound)
815 std::string adjustedValue = "\n" + value;
816 const xmlChar *xmlValue
817 = reinterpret_cast<const xmlChar *>(adjustedValue.c_str());
818 // TODO: Figure out if \r and \r\n can be handled without them changing
819 // to \n in the roundtrip
820 xmlNodePtr cdata
821 = xmlNewCDataBlock(node->doc, xmlValue,
822 static_cast<int>(adjustedValue.length()));
823 xmlAddChild(node, cdata);
825 else
827 xmlNodePtr cdata = node->children;
828 while (cdata != NULL && cdata->type != XML_CDATA_SECTION_NODE)
830 cdata = cdata->next;
832 if (cdata == NULL)
834 ADD_FAILURE() << "Invalid string block element";
835 return;
837 xmlChar *refXmlValue = xmlNodeGetContent(cdata);
838 if (refXmlValue[0] != '\n')
840 ADD_FAILURE() << "Invalid string block element";
841 xmlFree(refXmlValue);
842 return;
844 std::string refValue(reinterpret_cast<const char *>(refXmlValue + 1));
845 xmlFree(refXmlValue);
846 EXPECT_EQ(refValue, value);
851 void TestReferenceChecker::checkInteger(int value, const char *id)
853 if (impl_->shouldIgnore())
855 return;
857 SCOPED_TRACE(impl_->traceString(id));
858 bool bFound = false;
859 std::string strValue = formatString("%d", value);
860 std::string refStrValue =
861 impl_->processItem(Impl::cIntegerNodeName, id, strValue, &bFound);
862 if (bFound)
864 EXPECT_EQ(refStrValue, strValue);
868 void TestReferenceChecker::checkInt64(gmx_int64_t value, const char *id)
870 if (impl_->shouldIgnore())
872 return;
874 SCOPED_TRACE(impl_->traceString(id));
875 bool bFound = false;
876 std::string strValue = formatString("%" GMX_PRId64, value);
877 std::string refStrValue =
878 impl_->processItem(Impl::cInt64NodeName, id, strValue, &bFound);
879 if (bFound)
881 EXPECT_EQ(refStrValue, strValue);
885 void TestReferenceChecker::checkUInt64(gmx_uint64_t value, const char *id)
887 if (impl_->shouldIgnore())
889 return;
891 SCOPED_TRACE(impl_->traceString(id));
892 bool bFound = false;
893 std::string strValue = formatString("%" GMX_PRIu64, value);
894 std::string refStrValue =
895 impl_->processItem(Impl::cUInt64NodeName, id, strValue, &bFound);
896 if (bFound)
898 EXPECT_EQ(refStrValue, strValue);
902 void TestReferenceChecker::checkDouble(double value, const char *id)
904 if (impl_->shouldIgnore())
906 return;
908 SCOPED_TRACE(impl_->traceString(id));
909 bool bFound = false;
910 const int prec = std::numeric_limits<double>::digits10 + 2;
911 std::string strValue = formatString("%.*g", prec, value);
912 std::string refStrValue =
913 impl_->processItem(Impl::cRealNodeName, id, strValue, &bFound);
914 if (bFound)
916 char *endptr;
917 double refValue = std::strtod(refStrValue.c_str(), &endptr);
918 EXPECT_EQ('\0', *endptr);
919 if (impl_->bSelfTestMode_)
921 EXPECT_DOUBLE_EQ_TOL(refValue, value, impl_->defaultTolerance_)
922 << "String value: " << strValue << std::endl
923 << " Ref. string: " << refStrValue;
925 else
927 EXPECT_DOUBLE_EQ_TOL(refValue, value, impl_->defaultTolerance_);
933 void TestReferenceChecker::checkFloat(float value, const char *id)
935 if (impl_->shouldIgnore())
937 return;
939 SCOPED_TRACE(impl_->traceString(id));
940 bool bFound = false;
941 const int prec = std::numeric_limits<float>::digits10 + 2;
942 std::string strValue = formatString("%.*g", prec, value);
943 std::string refStrValue =
944 impl_->processItem(Impl::cRealNodeName, id, strValue, &bFound);
945 if (bFound)
947 char *endptr;
948 float refValue = static_cast<float>(std::strtod(refStrValue.c_str(), &endptr));
949 EXPECT_EQ('\0', *endptr);
950 if (impl_->bSelfTestMode_)
952 EXPECT_FLOAT_EQ_TOL(refValue, value, impl_->defaultTolerance_)
953 << "String value: " << strValue << std::endl
954 << " Ref. string: " << refStrValue;
956 else
958 EXPECT_FLOAT_EQ_TOL(refValue, value, impl_->defaultTolerance_);
964 void TestReferenceChecker::checkReal(float value, const char *id)
966 checkFloat(value, id);
970 void TestReferenceChecker::checkReal(double value, const char *id)
972 checkDouble(value, id);
976 void TestReferenceChecker::checkVector(const int value[3], const char *id)
978 TestReferenceChecker compound(checkCompound(Impl::cVectorType, id));
979 compound.checkInteger(value[0], "X");
980 compound.checkInteger(value[1], "Y");
981 compound.checkInteger(value[2], "Z");
985 void TestReferenceChecker::checkVector(const float value[3], const char *id)
987 TestReferenceChecker compound(checkCompound(Impl::cVectorType, id));
988 compound.checkReal(value[0], "X");
989 compound.checkReal(value[1], "Y");
990 compound.checkReal(value[2], "Z");
994 void TestReferenceChecker::checkVector(const double value[3], const char *id)
996 TestReferenceChecker compound(checkCompound(Impl::cVectorType, id));
997 compound.checkReal(value[0], "X");
998 compound.checkReal(value[1], "Y");
999 compound.checkReal(value[2], "Z");
1003 TestReferenceChecker
1004 TestReferenceChecker::checkSequenceCompound(const char *id, size_t length)
1006 TestReferenceChecker compound(checkCompound(Impl::cSequenceType, id));
1007 compound.checkInteger(static_cast<int>(length), Impl::cSequenceLengthName);
1008 return compound;
1011 } // namespace test
1012 } // namespace gmx