00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #pragma once
00012
00013 #include "TestToolBox\IEventReceiver.h"
00014 #include "TestToolBox\XmlCheck.h"
00015 #include "TestToolBox\CommonSources\CommonDefinitions.h"
00016
00017 #include "TinyXPath\TinyXml.h"
00018 #pragma warning(push)
00019 #pragma warning(disable:4267)
00020 #pragma warning(disable:4996)
00021 #include "TinyXPath\xpath_static.h"
00022 #pragma warning(pop)
00023
00024 #include <iostream>
00025 #include <iomanip>
00026
00027
00028
00029
00030
00031 #ifdef TTB_NOT_INLINE
00032 #define TTB_INLINE
00033 #else
00034 #define TTB_INLINE inline
00035 #endif
00036
00037
00038
00039
00040
00041
00042 namespace TestToolBox
00043 {
00044
00045 TTB_INLINE XmlCheck::XmlCheck()
00046 : m_pEventReceiver (0)
00047 {
00048 TRCF("XmlCheck::XmlCheck");
00049 TRC(TL_DEBUG, "Constructor");
00050
00051 SetDefaults();
00052
00053 }
00054
00055
00056
00057
00058
00059
00060 TTB_INLINE XmlCheck::~XmlCheck()
00061 {
00062 TRCF("XmlCheck::~XmlCheck");
00063 TRC(TL_DEBUG, "Destructor");
00064
00065 }
00066
00067
00068
00069
00070
00071
00072 TTB_INLINE XmlCheck* TheXmlCheck (void)
00073 {
00074 return XmlCheck::Get();
00075 }
00076
00077
00078 TTB_INLINE XmlCheck* XmlCheck::Get (void)
00079 {
00080 if (!s_pXmlCheck) s_pXmlCheck = new XmlCheck;
00081 return s_pXmlCheck;
00082 }
00083
00084 TTB_INLINE void XmlCheck::Cleanup (void)
00085 {
00086 if (s_pXmlCheck)
00087 {
00088 delete s_pXmlCheck;
00089 s_pXmlCheck = 0;
00090 }
00091 }
00092
00093
00094
00095
00096
00097 TTB_INLINE IEventReceiver* XmlCheck::SetEventReceiver (
00098 IEventReceiver* in_pEventReceiver)
00099 {
00100 IEventReceiver* retVal = m_pEventReceiver;
00101 m_pEventReceiver = in_pEventReceiver;
00102 return retVal;
00103
00104 }
00105
00106
00107
00108
00109
00110
00111 TTB_INLINE void XmlCheck::SetDefaults (void)
00112 {
00113 m_outputMode = CTX_TEST_EVENT;
00114 m_detailedOutput = false;
00115 m_attributesToIgnore.clear();
00116 m_nodesToIgnore.clear();
00117 m_doubleAttributes.clear();
00118 m_doubleNodes.clear();
00119 }
00120
00121
00122
00123
00124
00125
00126 TTB_INLINE void XmlCheck::SetOutputModeForWritingXmlContents (
00127 EventContext in_outputMode)
00128 {
00129 if ( (in_outputMode != CTX_PROT)
00130 && (in_outputMode != CTX_INFO)
00131 && (in_outputMode != CTX_TEST_EVENT))
00132 {
00133 std::ostringstream oss;
00134 oss << "Invalid output mode cannot be set, mode=" << in_outputMode;
00135 if (m_pEventReceiver)
00136 m_pEventReceiver->EventMsg(CTX_ERROR, oss.str().c_str());
00137 }
00138 else
00139 {
00140 m_outputMode = in_outputMode;
00141 }
00142
00143 }
00144
00145
00146
00147
00148
00149
00150 TTB_INLINE void XmlCheck::SetDetailedOutput (
00151 bool in_detailedOutput)
00152 {
00153 m_detailedOutput = in_detailedOutput;
00154
00155 }
00156
00157
00158
00159
00160
00161
00162 TTB_INLINE void XmlCheck::IgnoreAttribute (
00163 std::string const & in_attribute,
00164 bool in_ignore)
00165 {
00166 if (in_ignore)
00167 {
00168 m_attributesToIgnore.insert (in_attribute);
00169 }
00170 else
00171 {
00172 m_attributesToIgnore.erase (in_attribute);
00173 }
00174
00175 }
00176
00177
00178
00179
00180
00181
00182 TTB_INLINE bool XmlCheck::IsAttributeToIgnore (
00183 std::string const & in_attribute) const
00184 {
00185 return m_attributesToIgnore.find(in_attribute) != m_attributesToIgnore.end();
00186
00187 }
00188
00189
00190
00191
00192
00193
00194 TTB_INLINE void XmlCheck::IgnoreNode (
00195 std::string const & in_nodeName,
00196 bool in_ignore)
00197 {
00198 if (in_ignore)
00199 {
00200 m_nodesToIgnore.insert (in_nodeName);
00201 }
00202 else
00203 {
00204 m_nodesToIgnore.erase (in_nodeName);
00205 }
00206
00207 }
00208
00209
00210
00211
00212
00213
00214 TTB_INLINE bool XmlCheck::IsNodeToIgnore (
00215 std::string const & in_nodeName) const
00216 {
00217 return m_nodesToIgnore.find(in_nodeName) != m_nodesToIgnore.end();
00218
00219 }
00220
00221
00222
00223
00224
00225
00226 TTB_INLINE void XmlCheck::UseAsDoubleAttribute (
00227 std::string const & in_attribute,
00228 bool in_useAsDouble,
00229 int in_precision)
00230 {
00231 if (in_useAsDouble)
00232 {
00233 m_doubleAttributes[in_attribute] = in_precision;
00234 }
00235 else
00236 {
00237 m_doubleAttributes.erase (in_attribute);
00238 }
00239
00240 }
00241
00242
00243
00244
00245
00246
00247 TTB_INLINE bool XmlCheck::IsDoubleAttribute (
00248 std::string const & in_attribute) const
00249 {
00250 return m_doubleAttributes.find(in_attribute) != m_doubleAttributes.end();
00251
00252 }
00253
00254
00255
00256
00257
00258
00259 TTB_INLINE int XmlCheck::GetPrecisionOfDoubleAttribute (
00260 std::string const & in_attribute) const
00261 {
00262 int retVal = 0;
00263 std::map<std::string,int>::const_iterator it = m_doubleAttributes.find(in_attribute);
00264 if (it != m_doubleAttributes.end())
00265 {
00266 retVal = it->second;
00267 }
00268 return retVal;
00269
00270 }
00271
00272
00273
00274
00275
00276
00277 TTB_INLINE void XmlCheck::UseAsDoubleNode (
00278 std::string const & in_nodeName,
00279 bool in_useAsDouble,
00280 int in_precision)
00281 {
00282 if (in_useAsDouble)
00283 {
00284 m_doubleNodes[in_nodeName] = in_precision;
00285 }
00286 else
00287 {
00288 m_doubleNodes.erase (in_nodeName);
00289 }
00290
00291 }
00292
00293
00294
00295
00296
00297
00298 TTB_INLINE bool XmlCheck::IsDoubleNode (
00299 std::string const & in_nodeName) const
00300 {
00301 return m_doubleNodes.find(in_nodeName) != m_doubleNodes.end();
00302
00303 }
00304
00305
00306
00307
00308
00309
00310 TTB_INLINE int XmlCheck::GetPrecisionOfDoubleNode (
00311 std::string const & in_nodeName) const
00312 {
00313 int retVal = 0;
00314 std::map<std::string,int>::const_iterator it = m_doubleNodes.find(in_nodeName);
00315 if (it != m_doubleNodes.end())
00316 {
00317 retVal = it->second;
00318 }
00319 return retVal;
00320
00321 }
00322
00323
00324
00325
00326
00327
00328 TTB_INLINE void XmlCheck::CheckNode (
00329 TiXmlNode* in_pNode,
00330 char const * in_file,
00331 long in_lineNum)
00332 {
00333 WriteNode (in_pNode, 0, 0, in_file, in_lineNum);
00334
00335 }
00336
00337
00338
00339
00340
00341
00342 TTB_INLINE void XmlCheck::CheckSubNode (
00343 TiXmlNode* in_pNode,
00344 std::string const & in_xPathExpression_1,
00345 std::string const & in_xPathExpression_2,
00346 std::string const & in_xPathExpression_3,
00347 std::string const & in_xPathExpression_4,
00348 std::string const & in_xPathExpression_5,
00349 char const * in_file,
00350 long in_lineNum)
00351 {
00352 WriteNode (
00353 SubNodeFromXPath(in_pNode, in_xPathExpression_1, in_xPathExpression_2,
00354 in_xPathExpression_3, in_xPathExpression_4, in_xPathExpression_5),
00355 0, 0, in_file, in_lineNum);
00356
00357 }
00358
00359
00360
00361
00362
00363
00364 TTB_INLINE void XmlCheck::CheckSubNodeWithMaxChilds (
00365 int in_maxChilds,
00366 TiXmlNode* in_pNode,
00367 std::string const & in_xPathExpression_1,
00368 std::string const & in_xPathExpression_2,
00369 std::string const & in_xPathExpression_3,
00370 std::string const & in_xPathExpression_4,
00371 std::string const & in_xPathExpression_5,
00372 char const * in_file,
00373 long in_lineNum)
00374 {
00375 WriteNode (
00376 SubNodeFromXPath(in_pNode, in_xPathExpression_1, in_xPathExpression_2,
00377 in_xPathExpression_3, in_xPathExpression_4, in_xPathExpression_5),
00378 0, in_maxChilds, in_file, in_lineNum);
00379
00380 }
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406 TTB_INLINE bool XmlCheck::Compare (
00407 TiXmlNode* in_pNodeA,
00408 TiXmlNode* in_pNodeB,
00409 char const * in_file,
00410 long in_lineNum)
00411 {
00412 std::ostringstream oss;
00413
00414 FormattedContents contA;
00415 WriteNode (in_pNodeA, 0, 0, in_file, in_lineNum, &contA);
00416
00417 FormattedContents contB;
00418 WriteNode (in_pNodeB, 0, 0, in_file, in_lineNum, &contB);
00419
00420
00421 bool differenceFound = false;
00422 FormattedContents::iterator itA = contA.begin();
00423 FormattedContents::iterator itB = contB.begin();
00424 while ( (itA != contA.end())
00425 && (!differenceFound))
00426 {
00427
00428 std::string strA = itA->m_text;
00429 TrimStr(strA);
00430
00431 std::string strB;
00432 if (itB != contB.end())
00433 {
00434 strB = itB->m_text;
00435 TrimStr(strB);
00436 }
00437
00438
00439 if (strA != strB)
00440 {
00441 differenceFound = true;
00442 oss << "Difference detected\n"
00443 << "A: " << strA
00444 << " (line: " << itA->m_row << " col: " << itA->m_col
00445 << ", path: " << itA->m_fullPath << ")"
00446 << std::endl;
00447 if (itB != contB.end())
00448 {
00449 oss << "B: " << strB
00450 << " (line: " << itB->m_row << " col: " << itB->m_col
00451 << ", path: " << itB->m_fullPath << ")";
00452 }
00453 else
00454 {
00455 oss << "B: no data found";
00456 }
00457 }
00458
00459 ++itA;
00460 if (itB != contB.end())
00461 {
00462 ++itB;
00463 }
00464 }
00465
00466
00467 if ( (!differenceFound)
00468 && (itA == contA.end())
00469 && (itB != contB.end()))
00470 {
00471 std::string strB = itB->m_text;
00472 TrimStr(strB);
00473
00474 oss << "Difference detected, B has more data\n"
00475 << "B: " << strB
00476 << " (line: " << itB->m_row << " col: " << itB->m_col << ")";
00477 }
00478
00479 if (differenceFound)
00480 {
00481 m_compareResult = oss.str().c_str();
00482 }
00483 else
00484 {
00485 m_compareResult = "XML-Compare: no differences found";
00486 }
00487
00488 if (m_pEventReceiver)
00489 {
00490 XmlCheck::StringPosition curPos;
00491 while (GetNextLineStr(m_compareResult, curPos))
00492 {
00493 m_pEventReceiver->Event(m_outputMode, curPos.m_lineStr);
00494 }
00495
00496 }
00497
00498 return !differenceFound;
00499
00500 }
00501
00502
00503
00504
00505
00506
00507 TTB_INLINE std::string XmlCheck::GetCompareResult (void) const
00508 {
00509 return m_compareResult;
00510
00511 }
00512
00513
00514
00515
00516
00517
00518
00519 TTB_INLINE std::string XmlCheck::GetFullPath (
00520 TiXmlNode* in_pNode,
00521 std::string const & in_rPathToConcat)
00522 {
00523 std::string fullPath;
00524
00525 if (in_rPathToConcat.empty())
00526 {
00527 fullPath = "/" + in_rPathToConcat;
00528 }
00529
00530 TiXmlNode* pNode = in_pNode;
00531 do
00532 {
00533 fullPath = std::string("/") + pNode->Value() + fullPath;
00534 }
00535 while ((pNode = pNode->Parent())!= 0);
00536
00537 return fullPath;
00538
00539 }
00540
00541
00542
00543
00544
00545
00546 TTB_INLINE TiXmlNode* XmlCheck::SubNodeFromXPath (
00547 TiXmlNode* in_pParentNode,
00548 std::string const & in_xPathExpression_1,
00549 std::string const & in_xPathExpression_2,
00550 std::string const & in_xPathExpression_3,
00551 std::string const & in_xPathExpression_4,
00552 std::string const & in_xPathExpression_5)
00553 {
00554 TiXmlNode * pNode = 0;
00555 pNode = TinyXPath::XNp_xpath_node (in_pParentNode, in_xPathExpression_1.c_str());
00556 if (pNode && !in_xPathExpression_2.empty())
00557 {
00558 pNode = TinyXPath::XNp_xpath_node (pNode, in_xPathExpression_2.c_str());
00559 if (pNode && !in_xPathExpression_3.empty())
00560 {
00561 pNode = TinyXPath::XNp_xpath_node (pNode, in_xPathExpression_3.c_str());
00562 if (pNode && !in_xPathExpression_4.empty())
00563 {
00564 pNode = TinyXPath::XNp_xpath_node (pNode, in_xPathExpression_4.c_str());
00565 if (pNode && !in_xPathExpression_5.empty())
00566 {
00567 pNode = TinyXPath::XNp_xpath_node (pNode, in_xPathExpression_5.c_str());
00568 }
00569 }
00570 }
00571 }
00572 return pNode;
00573
00574 }
00575
00576
00577
00578
00579
00580
00581 TTB_INLINE bool XmlCheck::GetNextLineStr (
00582 std::string const & in_stringWithNewLines,
00583 StringPosition & io_current)
00584 {
00585 if (io_current.m_lastPos == std::string::npos) return false;
00586
00587 io_current.m_curPos = in_stringWithNewLines.find_first_of( '\n', io_current.m_lastPos);
00588 io_current.m_lineStr = in_stringWithNewLines.substr(io_current.m_lastPos,
00589 io_current.m_curPos - io_current.m_lastPos);
00590
00591 if (io_current.m_curPos != std::string::npos)
00592 io_current.m_lastPos = io_current.m_curPos + 1;
00593 else
00594 io_current.m_lastPos = std::string::npos;
00595
00596 return true;
00597
00598 }
00599
00600
00601
00602
00603
00604
00605
00606 TTB_INLINE void XmlCheck::WriteNode(
00607 TiXmlNode* in_pNode,
00608 unsigned int in_indent,
00609 int in_maxChildNodes,
00610 char const * in_file,
00611 long in_lineNum,
00612 FormattedContents* in_pContents)
00613 {
00614 TRCF("XmlCheck::WriteNode");
00615 TRC(TL_DEBUG, "Begin");
00616
00617 if ( !in_pNode ) return;
00618
00619 TiXmlNode* pChild;
00620 int nodeType = in_pNode->Type();
00621
00622 std::ostringstream oss;
00623 oss << IndentStr(in_indent);
00624
00625 bool writeAttributes = false;
00626 switch (nodeType)
00627 {
00628 case TiXmlNode::DOCUMENT:
00629 oss << IfDetailed("Document");
00630 break;
00631
00632 case TiXmlNode::ELEMENT:
00633 oss << IfDetailed("Element: ")<< in_pNode->Value();
00634 writeAttributes = true;
00635 break;
00636
00637 case TiXmlNode::COMMENT:
00638 oss << IfDetailed("Comment: ") << in_pNode->Value();
00639 break;
00640
00641 case TiXmlNode::UNKNOWN:
00642 printf( "Unknown node" );
00643 break;
00644
00645 case TiXmlNode::TEXT:
00646
00647 if (IsDoubleNode(in_pNode->Parent()->Value()))
00648 {
00649 std::istringstream isstr(in_pNode->ToText()->Value());
00650 double doubleVal;
00651 isstr>>doubleVal;
00652 {
00653 oss << std::fixed << std::setprecision(GetPrecisionOfDoubleNode(in_pNode->Parent()->Value())) << doubleVal;
00654 }
00655 }
00656 else
00657 {
00658 oss << IfDetailed("Text: ") << in_pNode->ToText()->Value();
00659 }
00660 break;
00661
00662 case TiXmlNode::DECLARATION:
00663 oss << IfDetailed("Declaration") << " version=" << in_pNode->ToDeclaration()->Version();
00664 break;
00665
00666 default:
00667 oss << "Unexpected";
00668 break;
00669 }
00670
00671 if (m_detailedOutput)
00672 {
00673 oss << " (line: " << in_pNode->Row() << ", col: " << in_pNode->Column()<< ")";
00674 }
00675
00676 if (oss.str().length()>0)
00677 {
00678 if (in_pContents)
00679 {
00680 in_pContents->push_back(TextWithPosInfo(
00681 in_pNode->Row(),in_pNode->Column(), GetFullPath(in_pNode),
00682 oss.str().c_str()));
00683 }
00684 else if (m_pEventReceiver)
00685 {
00686 m_pEventReceiver->EventMsg(m_outputMode, oss.str().c_str());
00687 }
00688 }
00689
00690 if (writeAttributes)
00691 {
00692 WriteAttributes(in_pNode->ToElement(), in_indent+1, in_file, in_lineNum, in_pContents);
00693 }
00694
00695
00696 int numReportedChilds=0;
00697 for ( pChild = in_pNode->FirstChild(); pChild != 0; pChild = pChild->NextSibling())
00698 {
00699 if (IsNodeToIgnore(pChild->Value())) continue;
00700 WriteNode( pChild, nodeType != TiXmlNode::DOCUMENT ? in_indent+1 : in_indent, 0, in_file, in_lineNum, in_pContents );
00701 ++numReportedChilds;
00702 if (in_maxChildNodes && (numReportedChilds >= in_maxChildNodes))
00703 break;
00704 }
00705
00706 TRC(TL_DEBUG, "End");
00707
00708 }
00709
00710
00711
00712
00713
00714
00715 TTB_INLINE void XmlCheck::WriteAttributes(
00716 TiXmlElement* in_pElement,
00717 unsigned int in_indent,
00718 char const * in_file,
00719 long in_lineNum,
00720 FormattedContents* in_pContents)
00721 {
00722 if ( !in_pElement ) return;
00723
00724 TiXmlAttribute* pAttrib=in_pElement->FirstAttribute();
00725 int numAttributes=0;
00726 int intVal;
00727 double doubleVal;
00728
00729
00730 while (pAttrib)
00731 {
00732 if (!IsAttributeToIgnore(pAttrib->Name()))
00733 {
00734 std::ostringstream oss;
00735 oss << IndentStr(in_indent)
00736 << pAttrib->Name() << ": ";
00737 if (IsDoubleAttribute(pAttrib->Name()))
00738 {
00739 if (pAttrib->QueryDoubleValue(&doubleVal)==TIXML_SUCCESS)
00740 {
00741 oss << std::fixed << std::setprecision(GetPrecisionOfDoubleAttribute(pAttrib->Name())) << doubleVal;
00742 }
00743
00744 }
00745 else
00746 {
00747 oss << pAttrib->Value();
00748 if (m_detailedOutput)
00749 {
00750
00751 if (pAttrib->QueryIntValue(&intVal)==TIXML_SUCCESS)
00752 {
00753 oss << ", as int: " << intVal;
00754 }
00755
00756
00757 if (pAttrib->QueryDoubleValue(&doubleVal)==TIXML_SUCCESS)
00758 {
00759 oss << ", as double: " << doubleVal;
00760 }
00761 }
00762 }
00763
00764 if (m_detailedOutput)
00765 {
00766 oss << " (line: " << pAttrib->Row() << ", col: " << pAttrib->Column()<< ")";
00767 }
00768
00769 if (in_pContents)
00770 {
00771 in_pContents->push_back(TextWithPosInfo(
00772 pAttrib->Row(),pAttrib->Column(), GetFullPath(in_pElement, pAttrib->Name()),
00773 oss.str().c_str()));
00774 }
00775 else if (m_pEventReceiver)
00776 {
00777 m_pEventReceiver->EventMsg(m_outputMode, oss.str().c_str());
00778 }
00779
00780 numAttributes++;
00781 }
00782 pAttrib=pAttrib->Next();
00783 }
00784
00785 if (m_detailedOutput && (numAttributes > 0))
00786 {
00787 std::ostringstream oss;
00788 oss << IndentEmptyStr(in_indent) << numAttributes << " attributes";
00789 if (in_pContents)
00790 {
00791 in_pContents->push_back(TextWithPosInfo(
00792 pAttrib->Row(),pAttrib->Column(), GetFullPath(in_pElement, pAttrib->Name()),
00793 oss.str().c_str()));
00794 }
00795 else if (m_pEventReceiver)
00796 {
00797 m_pEventReceiver->EventMsg(m_outputMode, oss.str().c_str());
00798 }
00799 }
00800
00801 }
00802
00803
00804
00805
00806
00807
00808 TTB_INLINE std::string XmlCheck::IfDetailed (std::string const & in_str)
00809 {
00810 return m_detailedOutput ? in_str : "";
00811 }
00812
00813
00814
00815
00816
00817
00818 }
00819
00820