2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2011,2012,2013,2014, 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.
37 * Implements classes and functions from refdata.h.
39 * \author Teemu Murtola <teemu.murtola@gmail.com>
40 * \ingroup module_testutils
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"
71 * Global test environment for freeing up libxml2 internal buffers.
73 class TestReferenceDataEnvironment : public ::testing::Environment
76 //! Frees internal buffers allocated by libxml2.
77 virtual void TearDown()
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;
94 ReferenceDataMode getReferenceDataMode()
96 return static_cast<ReferenceDataMode>(g_referenceDataMode);
99 void setReferenceDataMode(ReferenceDataMode mode)
101 g_referenceDataMode = mode;
104 std::string getReferenceDataPath()
106 return TestFileManager::getInputFilePath("refdata");
109 void initReferenceData(Options *options)
111 // Needs to correspond to the enum order in refdata.h.
112 const char *const refDataEnum[] = { "check", "create", "update" };
114 StringOption("ref-data").enumValue(refDataEnum)
116 .storeEnumIndex(&g_referenceDataMode)
117 .description("Operation mode for tests that use reference data"));
118 ::testing::AddGlobalTestEnvironment(new TestReferenceDataEnvironment);
121 /********************************************************************
122 * TestReferenceData::Impl
126 * Private implementation class for TestReferenceData.
128 * \ingroup module_testutils
130 class TestReferenceData::Impl
133 //! String constant for output XML version string.
134 static const xmlChar * const cXmlVersion;
135 //! String constant for XML stylesheet processing instruction name.
136 static const xmlChar * const cXmlStyleSheetNodeName;
137 //! String constant for XML stylesheet reference.
138 static const xmlChar * const cXmlStyleSheetContent;
139 //! String constant for naming the root XML element.
140 static const xmlChar * const cRootNodeName;
142 //! Initializes a checker in the given mode.
143 Impl(ReferenceDataMode mode, bool bSelfTestMode);
146 //! Full path of the reference data file.
147 std::string fullFilename_;
149 * XML document for the reference data.
151 * May be NULL if there was an I/O error in initialization.
155 * Whether the reference data is being written (true) or compared
159 //! `true` if self-testing (enables extra failure messages).
162 * Whether any reference checkers have been created for this data.
167 const xmlChar * const TestReferenceData::Impl::cXmlVersion =
168 (const xmlChar *)"1.0";
169 const xmlChar * const TestReferenceData::Impl::cXmlStyleSheetNodeName =
170 (const xmlChar *)"xml-stylesheet";
171 const xmlChar * const TestReferenceData::Impl::cXmlStyleSheetContent =
172 (const xmlChar *)"type=\"text/xsl\" href=\"referencedata.xsl\"";
173 const xmlChar * const TestReferenceData::Impl::cRootNodeName =
174 (const xmlChar *)"ReferenceData";
177 TestReferenceData::Impl::Impl(ReferenceDataMode mode, bool bSelfTestMode)
178 : refDoc_(NULL), bWrite_(false), bSelfTestMode_(bSelfTestMode), bInUse_(false)
180 std::string dirname = getReferenceDataPath();
181 std::string filename = TestFileManager::getTestSpecificFileName(".xml");
182 fullFilename_ = Path::join(dirname, filename);
185 if (mode != erefdataUpdateAll)
187 FILE *fp = std::fopen(fullFilename_.c_str(), "r");
193 else if (mode == erefdataCompare)
201 // TODO: Error checking
202 refDoc_ = xmlNewDoc(cXmlVersion);
203 xmlNodePtr rootNode = xmlNewDocNode(refDoc_, NULL, cRootNodeName, NULL);
204 xmlDocSetRootElement(refDoc_, rootNode);
205 xmlNodePtr xslNode = xmlNewDocPI(refDoc_, cXmlStyleSheetNodeName,
206 cXmlStyleSheetContent);
207 xmlAddPrevSibling(rootNode, xslNode);
211 refDoc_ = xmlParseFile(fullFilename_.c_str());
214 GMX_THROW(TestException("Reference data not parsed successfully: " + fullFilename_));
216 xmlNodePtr rootNode = xmlDocGetRootElement(refDoc_);
217 if (rootNode == NULL)
220 GMX_THROW(TestException("Reference data is empty: " + fullFilename_));
222 if (xmlStrcmp(rootNode->name, cRootNodeName) != 0)
225 GMX_THROW(TestException("Invalid root node type in " + fullFilename_));
231 TestReferenceData::Impl::~Impl()
233 if (bWrite_ && bInUse_ && refDoc_ != NULL)
235 std::string dirname = getReferenceDataPath();
236 if (!Directory::exists(dirname))
238 if (Directory::create(dirname) != 0)
240 ADD_FAILURE() << "Creation of reference data directory failed for " << dirname;
243 if (xmlSaveFormatFile(fullFilename_.c_str(), refDoc_, 1) == -1)
245 ADD_FAILURE() << "Saving reference data failed for " + fullFilename_;
255 /********************************************************************
256 * TestReferenceChecker::Impl
260 * Private implementation class for TestReferenceChecker.
262 * \ingroup module_testutils
264 class TestReferenceChecker::Impl
267 //! String constant for naming XML elements for boolean values.
268 static const xmlChar * const cBooleanNodeName;
269 //! String constant for naming XML elements for string values.
270 static const xmlChar * const cStringNodeName;
271 //! String constant for naming XML elements for integer values.
272 static const xmlChar * const cIntegerNodeName;
273 //! String constant for naming XML elements for int64 values.
274 static const xmlChar * const cInt64NodeName;
275 //! String constant for naming XML elements for unsigned int64 values.
276 static const xmlChar * const cUInt64NodeName;
277 //! String constant for naming XML elements for floating-point values.
278 static const xmlChar * const cRealNodeName;
279 //! String constant for naming XML attribute for value identifiers.
280 static const xmlChar * const cIdAttrName;
281 //! String constant for naming compounds for vectors.
282 static const char * const cVectorType;
283 //! String constant for naming compounds for sequences.
284 static const char * const cSequenceType;
285 //! String constant for value identifier for sequence length.
286 static const char * const cSequenceLengthName;
288 //! Creates a checker that does nothing.
289 explicit Impl(bool bWrite);
290 //! Creates a checker with a given root node.
291 Impl(const std::string &path, xmlNodePtr rootNode, bool bWrite,
292 bool bSelfTestMode, const FloatingPointTolerance &defaultTolerance);
294 //! Returns a string for SCOPED_TRACE() for checking element \p id.
295 std::string traceString(const char *id) const;
296 //! Returns the path of this checker with \p id appended.
297 std::string appendPath(const char *id) const;
300 * Finds a reference data node.
302 * \param[in] name Type of node to find (can be NULL, in which case
303 * any type is matched).
304 * \param[in] id Unique identifier of the node (can be NULL, in
305 * which case the next node without an id is matched).
306 * \returns Matching node, or NULL if no matching node found.
308 * Searches for a node in the reference data that matches the given
309 * \p name and \p id. Searching starts from the node that follows the
310 * previously matched node (relevant for performance, and if there are
311 * duplicate ids or nodes without ids). Note that the match pointer is
312 * not updated by this method.
314 xmlNodePtr findNode(const xmlChar *name, const char *id) const;
316 * Finds/creates a reference data node to match against.
318 * \param[in] name Type of node to find.
319 * \param[in] id Unique identifier of the node (can be NULL, in
320 * which case the next node without an id is matched).
321 * \param[out] bFound Whether the node was found (false if the node was
322 * created in write mode).
323 * \returns Matching node, or NULL if no matching node found
324 * (NULL is never returned in write mode).
325 * \throws TestException if node creation fails in write mode.
327 * Finds a node using findNode() and updates the match pointer is a
328 * match is found. If a match is not found, the method returns NULL in
329 * read mode and creates a new node in write mode. If the creation
330 * fails in write mode, throws.
332 xmlNodePtr findOrCreateNode(const xmlChar *name, const char *id,
335 * Helper method for checking a reference data value.
337 * \param[in] name Type of node to find.
338 * \param[in] id Unique identifier of the node (can be NULL, in
339 * which case the next node without an id is matched).
340 * \param[in] value String value of the value to be compared.
341 * \param[out] bFound true if a matchin value was found.
342 * \returns String value for the reference value.
343 * \throws TestException if node creation fails in write mode.
345 * Performs common tasks in checking a reference value:
346 * finding/creating the correct XML node and reading/writing its string
347 * value. Caller is responsible for converting the value to and from
348 * string where necessary and performing the actual comparison.
350 * In read mode, if a value is not found, adds a Google Test failure
351 * and returns an empty string. If the reference value is found,
352 * returns it (\p value is not used in this case).
354 * In write mode, creates the node if it is not found, sets its value
355 * as \p value and returns \p value.
357 std::string processItem(const xmlChar *name, const char *id,
358 const char *value, bool *bFound);
359 //! Convenience wrapper that takes a std::string.
360 std::string processItem(const xmlChar *name, const char *id,
361 const std::string &value, bool *bFound);
363 * Whether the checker should ignore all validation calls.
365 * This is used to ignore any calls within compounds for which
366 * reference data could not be found, such that only one error is
367 * issued for the missing compound, instead of every individual value.
369 bool shouldIgnore() const;
371 //! Default floating-point comparison tolerance.
372 FloatingPointTolerance defaultTolerance_;
374 * Human-readable path to the root node of this checker.
376 * For the root checker, this will be "/", and for each compound, the
377 * id of the compound is added. Used for reporting comparison
382 * Current node under which reference data is searched.
384 * Points to either the root of TestReferenceData::Impl::refDoc_, or to
387 * Can be NULL, in which case this checker does nothing (doesn't even
388 * report errors, see shouldIgnore()).
390 xmlNodePtr currNode_;
392 * Points to a child of \a currNode_ that was last found.
394 * On initialization, is initialized to NULL. After every check, is
395 * updated to point to the node that was used for the check.
396 * Subsequent checks start the search for the matching node on this
399 * Is NULL if \a currNode_ contains no children or if no checks have
401 * Otherwise, always points to a direct child of \a currNode_.
403 xmlNodePtr prevFoundNode_;
405 * Whether the reference data is being written (true) or compared
409 //! `true` if self-testing (enables extra failure messages).
412 * Current number of unnamed elements in a sequence.
414 * It is the index of the next added unnamed element.
419 const xmlChar * const TestReferenceChecker::Impl::cBooleanNodeName =
420 (const xmlChar *)"Bool";
421 const xmlChar * const TestReferenceChecker::Impl::cStringNodeName =
422 (const xmlChar *)"String";
423 const xmlChar * const TestReferenceChecker::Impl::cIntegerNodeName =
424 (const xmlChar *)"Int";
425 const xmlChar * const TestReferenceChecker::Impl::cInt64NodeName =
426 (const xmlChar *)"Int64";
427 const xmlChar * const TestReferenceChecker::Impl::cUInt64NodeName =
428 (const xmlChar *)"UInt64";
429 const xmlChar * const TestReferenceChecker::Impl::cRealNodeName =
430 (const xmlChar *)"Real";
431 const xmlChar * const TestReferenceChecker::Impl::cIdAttrName =
432 (const xmlChar *)"Name";
433 const char * const TestReferenceChecker::Impl::cVectorType =
435 const char * const TestReferenceChecker::Impl::cSequenceType =
437 const char * const TestReferenceChecker::Impl::cSequenceLengthName =
441 TestReferenceChecker::Impl::Impl(bool bWrite)
442 : defaultTolerance_(defaultRealTolerance()),
443 currNode_(NULL), prevFoundNode_(NULL), bWrite_(bWrite),
444 bSelfTestMode_(false), seqIndex_(0)
449 TestReferenceChecker::Impl::Impl(const std::string &path, xmlNodePtr rootNode,
450 bool bWrite, bool bSelfTestMode,
451 const FloatingPointTolerance &defaultTolerance)
452 : defaultTolerance_(defaultTolerance), path_(path + "/"),
453 currNode_(rootNode), prevFoundNode_(NULL), bWrite_(bWrite),
454 bSelfTestMode_(bSelfTestMode), seqIndex_(0)
460 TestReferenceChecker::Impl::traceString(const char *id) const
462 return "Checking '" + appendPath(id) + "'";
467 TestReferenceChecker::Impl::appendPath(const char *id) const
469 std::string printId = (id != NULL) ? id : formatString("[%d]", seqIndex_);
470 return path_ + printId;
475 TestReferenceChecker::Impl::findNode(const xmlChar *name, const char *id) const
477 if (currNode_ == NULL || currNode_->children == NULL)
481 const xmlChar *xmlId = reinterpret_cast<const xmlChar *>(id);
482 xmlNodePtr node = prevFoundNode_;
488 xmlChar *refId = xmlGetProp(node, cIdAttrName);
491 if (name == NULL || xmlStrcmp(node->name, name) == 0)
509 node = currNode_->children;
514 if (name == NULL || xmlStrcmp(node->name, name) == 0)
516 xmlChar *refId = xmlGetProp(node, cIdAttrName);
517 if (xmlId == NULL && refId == NULL)
523 if (xmlId != NULL && xmlStrcmp(refId, xmlId) == 0)
532 if (bWrap && node == NULL)
534 node = currNode_->children;
537 while (node != NULL && node != prevFoundNode_);
543 TestReferenceChecker::Impl::findOrCreateNode(const xmlChar *name,
548 xmlNodePtr node = findNode(name, id);
552 prevFoundNode_ = node;
558 node = xmlNewTextChild(currNode_, NULL, name, NULL);
559 if (node != NULL && id != NULL)
561 const xmlChar *xmlId = reinterpret_cast<const xmlChar *>(id);
562 xmlAttrPtr prop = xmlNewProp(node, cIdAttrName, xmlId);
571 GMX_THROW(TestException("XML node creation failed"));
573 prevFoundNode_ = node;
577 ADD_FAILURE() << "Reference data item not found";
580 seqIndex_ = (id == NULL) ? seqIndex_+1 : 0;
587 TestReferenceChecker::Impl::processItem(const xmlChar *name, const char *id,
588 const char *value, bool *bFound)
590 xmlNodePtr node = findOrCreateNode(name, id, bFound);
593 return std::string();
595 if (bWrite_ && !*bFound)
597 xmlNodeAddContent(node, reinterpret_cast<const xmlChar *>(value));
599 return std::string(value);
603 xmlChar *refXmlValue = xmlNodeGetContent(node);
604 std::string refValue(reinterpret_cast<const char *>(refXmlValue));
605 xmlFree(refXmlValue);
612 TestReferenceChecker::Impl::processItem(const xmlChar *name, const char *id,
613 const std::string &value, bool *bFound)
615 return processItem(name, id, value.c_str(), bFound);
620 TestReferenceChecker::Impl::shouldIgnore() const
622 return currNode_ == NULL;
626 /********************************************************************
630 TestReferenceData::TestReferenceData()
631 : impl_(new Impl(getReferenceDataMode(), false))
636 TestReferenceData::TestReferenceData(ReferenceDataMode mode)
637 : impl_(new Impl(mode, true))
642 TestReferenceData::~TestReferenceData()
647 bool TestReferenceData::isWriteMode() const
649 return impl_->bWrite_;
653 TestReferenceChecker TestReferenceData::rootChecker()
655 if (!isWriteMode() && !impl_->bInUse_ && impl_->refDoc_ == NULL)
657 ADD_FAILURE() << "Reference data file not found: "
658 << impl_->fullFilename_;
660 impl_->bInUse_ = true;
661 if (impl_->refDoc_ == NULL)
663 return TestReferenceChecker(new TestReferenceChecker::Impl(isWriteMode()));
665 xmlNodePtr rootNode = xmlDocGetRootElement(impl_->refDoc_);
666 // TODO: The default tolerance for double-precision builds that explicitly
667 // call checkFloat() may not be ideal.
668 return TestReferenceChecker(
669 new TestReferenceChecker::Impl("", rootNode, isWriteMode(),
670 impl_->bSelfTestMode_,
671 defaultRealTolerance()));
675 /********************************************************************
676 * TestReferenceChecker
679 TestReferenceChecker::TestReferenceChecker(Impl *impl)
685 TestReferenceChecker::TestReferenceChecker(const TestReferenceChecker &other)
686 : impl_(new Impl(*other.impl_))
691 TestReferenceChecker &
692 TestReferenceChecker::operator=(const TestReferenceChecker &other)
694 impl_.reset(new Impl(*other.impl_));
699 TestReferenceChecker::~TestReferenceChecker()
704 bool TestReferenceChecker::isWriteMode() const
706 return impl_->bWrite_;
710 void TestReferenceChecker::setDefaultTolerance(
711 const FloatingPointTolerance &tolerance)
713 impl_->defaultTolerance_ = tolerance;
717 bool TestReferenceChecker::checkPresent(bool bPresent, const char *id)
719 if (isWriteMode() || impl_->shouldIgnore())
723 xmlNodePtr node = impl_->findNode(NULL, id);
724 bool bFound = (node != NULL);
725 if (bFound != bPresent)
727 ADD_FAILURE() << "Mismatch while checking reference data item '"
728 << impl_->appendPath(id) << "'\n"
729 << "Expected: " << (bPresent ? "it is present.\n" : "it is absent.\n")
730 << " Actual: " << (bFound ? "it is present." : "it is absent.");
732 if (bFound && bPresent)
734 impl_->prevFoundNode_ = node;
741 TestReferenceChecker TestReferenceChecker::checkCompound(const char *type, const char *id)
743 SCOPED_TRACE(impl_->traceString(id));
744 if (impl_->shouldIgnore())
746 return TestReferenceChecker(new Impl(isWriteMode()));
748 const xmlChar *xmlNodeName = reinterpret_cast<const xmlChar *>(type);
750 xmlNodePtr newNode = impl_->findOrCreateNode(xmlNodeName, id, &bFound);
753 return TestReferenceChecker(new Impl(isWriteMode()));
755 return TestReferenceChecker(
756 new Impl(impl_->appendPath(id), newNode, isWriteMode(),
757 impl_->bSelfTestMode_, impl_->defaultTolerance_));
761 void TestReferenceChecker::checkBoolean(bool value, const char *id)
763 if (impl_->shouldIgnore())
767 SCOPED_TRACE(impl_->traceString(id));
769 const char *strValue = value ? "true" : "false";
770 std::string refStrValue =
771 impl_->processItem(Impl::cBooleanNodeName, id, strValue, &bFound);
774 EXPECT_EQ(refStrValue, strValue);
779 void TestReferenceChecker::checkString(const char *value, const char *id)
781 if (impl_->shouldIgnore())
785 SCOPED_TRACE(impl_->traceString(id));
787 std::string refStrValue =
788 impl_->processItem(Impl::cStringNodeName, id, value, &bFound);
791 EXPECT_EQ(refStrValue, value);
796 void TestReferenceChecker::checkString(const std::string &value, const char *id)
798 checkString(value.c_str(), id);
802 void TestReferenceChecker::checkStringBlock(const std::string &value,
805 if (impl_->shouldIgnore())
809 SCOPED_TRACE(impl_->traceString(id));
811 xmlNodePtr node = impl_->findOrCreateNode(Impl::cStringNodeName, id, &bFound);
816 // An extra newline is written in the beginning to make lines align
817 // in the output xml (otherwise, the first line would be off by the length
818 // of the starting CDATA tag).
819 if (isWriteMode() && !bFound)
821 std::string adjustedValue = "\n" + value;
822 const xmlChar *xmlValue
823 = reinterpret_cast<const xmlChar *>(adjustedValue.c_str());
824 // TODO: Figure out if \r and \r\n can be handled without them changing
825 // to \n in the roundtrip
827 = xmlNewCDataBlock(node->doc, xmlValue,
828 static_cast<int>(adjustedValue.length()));
829 xmlAddChild(node, cdata);
833 xmlNodePtr cdata = node->children;
834 while (cdata != NULL && cdata->type != XML_CDATA_SECTION_NODE)
840 ADD_FAILURE() << "Invalid string block element";
843 xmlChar *refXmlValue = xmlNodeGetContent(cdata);
844 if (refXmlValue[0] != '\n')
846 ADD_FAILURE() << "Invalid string block element";
847 xmlFree(refXmlValue);
850 std::string refValue(reinterpret_cast<const char *>(refXmlValue + 1));
851 xmlFree(refXmlValue);
852 EXPECT_EQ(refValue, value);
857 void TestReferenceChecker::checkInteger(int value, const char *id)
859 if (impl_->shouldIgnore())
863 SCOPED_TRACE(impl_->traceString(id));
865 std::string strValue = formatString("%d", value);
866 std::string refStrValue =
867 impl_->processItem(Impl::cIntegerNodeName, id, strValue, &bFound);
870 EXPECT_EQ(refStrValue, strValue);
874 void TestReferenceChecker::checkInt64(gmx_int64_t value, const char *id)
876 if (impl_->shouldIgnore())
880 SCOPED_TRACE(impl_->traceString(id));
882 std::string strValue = formatString("%" GMX_PRId64, value);
883 std::string refStrValue =
884 impl_->processItem(Impl::cInt64NodeName, id, strValue, &bFound);
887 EXPECT_EQ(refStrValue, strValue);
891 void TestReferenceChecker::checkUInt64(gmx_uint64_t value, const char *id)
893 if (impl_->shouldIgnore())
897 SCOPED_TRACE(impl_->traceString(id));
899 std::string strValue = formatString("%" GMX_PRIu64, value);
900 std::string refStrValue =
901 impl_->processItem(Impl::cUInt64NodeName, id, strValue, &bFound);
904 EXPECT_EQ(refStrValue, strValue);
908 void TestReferenceChecker::checkDouble(double value, const char *id)
910 if (impl_->shouldIgnore())
914 SCOPED_TRACE(impl_->traceString(id));
916 const int prec = std::numeric_limits<double>::digits10 + 2;
917 std::string strValue = formatString("%.*g", prec, value);
918 std::string refStrValue =
919 impl_->processItem(Impl::cRealNodeName, id, strValue, &bFound);
923 double refValue = std::strtod(refStrValue.c_str(), &endptr);
924 EXPECT_EQ('\0', *endptr);
925 if (impl_->bSelfTestMode_)
927 EXPECT_DOUBLE_EQ_TOL(refValue, value, impl_->defaultTolerance_)
928 << "String value: " << strValue << std::endl
929 << " Ref. string: " << refStrValue;
933 EXPECT_DOUBLE_EQ_TOL(refValue, value, impl_->defaultTolerance_);
939 void TestReferenceChecker::checkFloat(float value, const char *id)
941 if (impl_->shouldIgnore())
945 SCOPED_TRACE(impl_->traceString(id));
947 const int prec = std::numeric_limits<float>::digits10 + 2;
948 std::string strValue = formatString("%.*g", prec, value);
949 std::string refStrValue =
950 impl_->processItem(Impl::cRealNodeName, id, strValue, &bFound);
954 float refValue = static_cast<float>(std::strtod(refStrValue.c_str(), &endptr));
955 EXPECT_EQ('\0', *endptr);
956 if (impl_->bSelfTestMode_)
958 EXPECT_FLOAT_EQ_TOL(refValue, value, impl_->defaultTolerance_)
959 << "String value: " << strValue << std::endl
960 << " Ref. string: " << refStrValue;
964 EXPECT_FLOAT_EQ_TOL(refValue, value, impl_->defaultTolerance_);
970 void TestReferenceChecker::checkReal(float value, const char *id)
972 checkFloat(value, id);
976 void TestReferenceChecker::checkReal(double value, const char *id)
978 checkDouble(value, id);
982 void TestReferenceChecker::checkVector(const int value[3], const char *id)
984 TestReferenceChecker compound(checkCompound(Impl::cVectorType, id));
985 compound.checkInteger(value[0], "X");
986 compound.checkInteger(value[1], "Y");
987 compound.checkInteger(value[2], "Z");
991 void TestReferenceChecker::checkVector(const float value[3], const char *id)
993 TestReferenceChecker compound(checkCompound(Impl::cVectorType, id));
994 compound.checkReal(value[0], "X");
995 compound.checkReal(value[1], "Y");
996 compound.checkReal(value[2], "Z");
1000 void TestReferenceChecker::checkVector(const double value[3], const char *id)
1002 TestReferenceChecker compound(checkCompound(Impl::cVectorType, id));
1003 compound.checkReal(value[0], "X");
1004 compound.checkReal(value[1], "Y");
1005 compound.checkReal(value[2], "Z");
1009 TestReferenceChecker
1010 TestReferenceChecker::checkSequenceCompound(const char *id, size_t length)
1012 TestReferenceChecker compound(checkCompound(Impl::cSequenceType, id));
1013 compound.checkInteger(static_cast<int>(length), Impl::cSequenceLengthName);