Index: src/libchcore/ConfigNodeContainer.cpp =================================================================== diff -u -r5324d0ca7af614cb066df1f121a7a338c4f7d7ed -rf354b6f39d2a0425c1827906c84cbc1377b8c8d3 --- src/libchcore/ConfigNodeContainer.cpp (.../ConfigNodeContainer.cpp) (revision 5324d0ca7af614cb066df1f121a7a338c4f7d7ed) +++ src/libchcore/ConfigNodeContainer.cpp (.../ConfigNodeContainer.cpp) (revision f354b6f39d2a0425c1827906c84cbc1377b8c8d3) @@ -204,23 +204,51 @@ } } + namespace + { + struct PredIsPrefixedWith + { + private: + PredIsPrefixedWith& operator=(const PredIsPrefixedWith&); + PredIsPrefixedWith(); + + public: + PredIsPrefixedWith(PCTSTR pszPrefix, TRemovedObjects& rRemovedObjects) : m_strPrefix(pszPrefix), m_rRemovedObjects(rRemovedObjects) {} + PredIsPrefixedWith(const PredIsPrefixedWith& rSrc) : m_strPrefix(rSrc.m_strPrefix), m_rRemovedObjects(rSrc.m_rRemovedObjects) {} + + bool operator()(const ConfigNode& rNode) const + { + if(rNode.m_strNodeName.Get().StartsWith(m_strPrefix.c_str())) + { + m_rRemovedObjects.Add(rNode.m_stObjectID); + return true; + } + return false; + } + + TString m_strPrefix; + TRemovedObjects& m_rRemovedObjects; + }; + } + void ConfigNodeContainer::DeleteNode(PCTSTR pszPropName) { boost::unique_lock lock(m_lock); - std::pair pairFnd - = m_mic.equal_range(boost::make_tuple(pszPropName)); + PredIsPrefixedWith pred(pszPropName, m_setRemovedObjects); - if(pairFnd.first == m_mic.end()) - return; - - ConfigNodeContainer::NodeContainer::const_iterator iter = pairFnd.first; - while(iter != m_mic.end() && iter != pairFnd.second) + bool bWasFoundBefore = false; + ConfigNodeContainer::NodeContainer::iterator iterCurrent = m_mic.begin(); + while(iterCurrent != m_mic.end()) { - m_setRemovedObjects.Add(iter->m_stObjectID); + // NOTE: PredIsPrefixedWith registers the object IDs as deleted in m_setRemovedObjects (for change management purposes) + if(pred(*iterCurrent)) + iterCurrent = m_mic.erase(iterCurrent); + else if(bWasFoundBefore) + break; // as the elements are sorted, when we matched something earlier and now we don't - it means that there are no more matching elements + else + ++iterCurrent; } - - m_mic.erase(pairFnd.first, pairFnd.second); } bool ConfigNodeContainer::ExtractNodes(PCTSTR pszNode, ConfigNodeContainer& tNewContainer) const @@ -272,6 +300,8 @@ size_t stPos = strName.Find(_T("]")); if(stPos == std::numeric_limits::max()) THROW_CORE_EXCEPTION(eErr_InvalidData); + if(strName.GetAt(stPos + 1) != _T('.')) + THROW_CORE_EXCEPTION(eErr_InvalidData); size_t stNodeIndex = boost::lexical_cast(strName.Left(stPos)); if(stNodeIndex != stLastIndex) @@ -282,7 +312,8 @@ stLastIndex = stNodeIndex; } - pCurrentContainer->m_mic.insert(ConfigNode(++pCurrentContainer->m_stLastObjectID, strName.Mid(stPos + 1), iter->GetOrder(), iter->m_strValue)); + strName.Delete(0, stPos + 2); // skip "]." at the beginning + pCurrentContainer->m_mic.insert(ConfigNode(++pCurrentContainer->m_stLastObjectID, strName, iter->GetOrder(), iter->m_strValue)); } } @@ -499,6 +530,10 @@ strGroupNode = strNodeName.Left(stBracketPos); TString strSubnodeName = strNodeName.Mid(stSecondBracketPos + 1); + wchar_t chDot = 0; + if(!strSubnodeName.GetAt(0, chDot) || chDot != L'.') + THROW_CORE_EXCEPTION(eErr_InvalidData); + strSubnodeName.Delete(0, 1); size_t stBracketID = boost::lexical_cast(strNodeName.Mid(stBracketPos + 1, stSecondBracketPos - stBracketPos - 1)); if(stBracketID != stLastBracketID) @@ -513,6 +548,7 @@ // same ID - add new element to existing property tree node treeSubnodes.put(strSubnodeName.c_str(), iter->m_strValue.Get()); + stLastBracketID = stBracketID; } else { Index: src/libchcore/Tests/TestsTConfig.cpp =================================================================== diff -u -r5324d0ca7af614cb066df1f121a7a338c4f7d7ed -rf354b6f39d2a0425c1827906c84cbc1377b8c8d3 --- src/libchcore/Tests/TestsTConfig.cpp (.../TestsTConfig.cpp) (revision 5324d0ca7af614cb066df1f121a7a338c4f7d7ed) +++ src/libchcore/Tests/TestsTConfig.cpp (.../TestsTConfig.cpp) (revision f354b6f39d2a0425c1827906c84cbc1377b8c8d3) @@ -4,6 +4,8 @@ #include #include #include "../TConfig.h" +#include "../TStringArray.h" +#include "../TConfigArray.h" using namespace chcore; @@ -77,6 +79,49 @@ std::wstring m_strTempFilePath; }; +class InitializedConfigFixture : public ::testing::Test +{ +protected: + virtual void SetUp() + { + m_strInputXmlString = + L"\ +\ + \ + 30000\ + \ + \ + true\ + <WINDOWS>\\media\\chord.wav\ + <WINDOWS>\\media\\ding.wav\ + \ + \ + c:\\Windows\\System32\ + d:\\Movies\ + x:\\Music\ + s:\\projects\\ch-rw\ + \ + \ + \ + \ + <WINDOWS>\\FirstPath\ + FirstName\ + \ + \ + <WINDOWS>\\SecondPath\ + SecondName\ + \ + \ + \ +"; + + m_cfg.ReadFromString(m_strInputXmlString); + } + + TString m_strInputXmlString; + TConfig m_cfg; +}; + /////////////////////////////////////////////////////////////////////////// // read from/write to file @@ -121,45 +166,11 @@ /////////////////////////////////////////////////////////////////////////// // store in/load from string -TEST(TConfigTests, ReadFromString) +TEST_F(InitializedConfigFixture, ReadFromString) { - std::wstring wstrData = - L"\ -\ - \ - 30000\ - \ - \ - true\ - <WINDOWS>\\media\\chord.wav\ - <WINDOWS>\\media\\ding.wav\ - \ - \ - c:\\Windows\\System32\ - d:\\Movies\ - x:\\Music\ - s:\\projects\\ch-rw\ - \ - \ - \ - \ - <WINDOWS>\\FirstPath\ - FirstName\ - \ - \ - <WINDOWS>\\SecondPath\ - SecondName\ - \ - \ - \ -"; - - TConfig cfg; - cfg.ReadFromString(TString(wstrData.c_str())); - - EXPECT_EQ(true, cfg.GetBool(_T("CHConfig.Core.Notifications.Sounds.Enable"), false)); - EXPECT_EQ(30000, cfg.GetInt(_T("CHConfig.Core.AutosaveInterval"), 0)); - EXPECT_EQ(TString(_T("\\media\\ding.wav")), cfg.GetString(_T("CHConfig.Core.Notifications.Sounds.FinishedSoundPath"), _T(""))); + EXPECT_EQ(true, m_cfg.GetBool(_T("CHConfig.Core.Notifications.Sounds.Enable"), false)); + EXPECT_EQ(30000, m_cfg.GetInt(_T("CHConfig.Core.AutosaveInterval"), 0)); + EXPECT_EQ(TString(_T("\\media\\ding.wav")), m_cfg.GetString(_T("CHConfig.Core.Notifications.Sounds.FinishedSoundPath"), _T(""))); } TEST(TConfigTests, WriteToString) @@ -220,80 +231,424 @@ EXPECT_EQ(strXmlData, strWriteXmlData); } +/////////////////////////////////////////////////////////////////////////// TEST(TConfigTests, GetSetInt) { TConfig cfg; // store data in config - cfg.SetValue(_T("Root.Node.Value1"), 1489); - cfg.SetValue(_T("Root.Node.Value2"), -12987); + cfg.SetValue(_T("Root.Node.Value1"), 2147483647); + cfg.SetValue(_T("Root.Node.Value2"), (-2147483647 - 1)); // check if stored successfully (typed get) - EXPECT_EQ(1489, cfg.GetInt(_T("Root.Node.Value1"))); - EXPECT_EQ(-12987, cfg.GetInt(_T("Root.Node.Value2"))); + EXPECT_EQ(2147483647, cfg.GetInt(_T("Root.Node.Value1"))); + EXPECT_EQ((-2147483647 - 1), cfg.GetInt(_T("Root.Node.Value2"))); // check if stored successfully (GetValue) int iValue = 0; cfg.GetValue(_T("Root.Node.Value1"), iValue); - EXPECT_EQ(1489, iValue); + EXPECT_EQ(2147483647, iValue); cfg.GetValue(_T("Root.Node.Value2"), iValue); - EXPECT_EQ(-12987, iValue); + EXPECT_EQ((-2147483647 - 1), iValue); } TEST(TConfigTests, GetSetIntExport) { TConfig cfg; TString strXmlData(_T("\n\ -1489-12987")); +2147483647-2147483648")); // store in string cfg.ReadFromString(strXmlData); - EXPECT_EQ(1489, cfg.GetInt(_T("Root.Node.Value1"))); - EXPECT_EQ(-12987, cfg.GetInt(_T("Root.Node.Value2"))); + EXPECT_EQ(2147483647, cfg.GetInt(_T("Root.Node.Value1"))); + EXPECT_EQ((-2147483647 - 1), cfg.GetInt(_T("Root.Node.Value2"))); TString strWriteXmlData; cfg.WriteToString(strWriteXmlData); EXPECT_EQ(strXmlData, strWriteXmlData); } +/////////////////////////////////////////////////////////////////////////// TEST(TConfigTests, GetSetUInt) { TConfig cfg; // store data in config cfg.SetValue(_T("Root.Node.Value1"), (unsigned int)1489); - cfg.SetValue(_T("Root.Node.Value2"), (unsigned int)12987); + cfg.SetValue(_T("Root.Node.Value2"), (unsigned int)4294967295); // check if stored successfully (typed get) EXPECT_EQ(1489, cfg.GetUInt(_T("Root.Node.Value1"))); - EXPECT_EQ(12987, cfg.GetUInt(_T("Root.Node.Value2"))); + EXPECT_EQ(4294967295, cfg.GetUInt(_T("Root.Node.Value2"))); // check if stored successfully (GetValue) - int value = 0; + unsigned int value = 0; cfg.GetValue(_T("Root.Node.Value1"), value); EXPECT_EQ(1489, value); cfg.GetValue(_T("Root.Node.Value2"), value); - EXPECT_EQ(12987, value); + EXPECT_EQ(4294967295, value); } TEST(TConfigTests, GetSetUIntExport) { TConfig cfg; TString strXmlData(_T("\n\ -148912987")); +14894294967295")); // store in string cfg.ReadFromString(strXmlData); - EXPECT_EQ(1489, cfg.GetInt(_T("Root.Node.Value1"))); - EXPECT_EQ(12987, cfg.GetInt(_T("Root.Node.Value2"))); + EXPECT_EQ(1489, cfg.GetUInt(_T("Root.Node.Value1"))); + EXPECT_EQ(4294967295, cfg.GetUInt(_T("Root.Node.Value2"))); TString strWriteXmlData; cfg.WriteToString(strWriteXmlData); EXPECT_EQ(strXmlData, strWriteXmlData); } + +/////////////////////////////////////////////////////////////////////////// +TEST(TConfigTests, GetSetLongLong) +{ + TConfig cfg; + + // store data in config + cfg.SetValue(_T("Root.Node.Value1"), (long long)9223372036854775807); + cfg.SetValue(_T("Root.Node.Value2"), (long long)(-9223372036854775807 - 1)); + + // check if stored successfully (typed get) + EXPECT_EQ((long long)9223372036854775807, cfg.GetLongLong(_T("Root.Node.Value1"))); + EXPECT_EQ((long long)(-9223372036854775807 - 1), cfg.GetLongLong(_T("Root.Node.Value2"))); + + // check if stored successfully (GetValue) + long long value = 0; + cfg.GetValue(_T("Root.Node.Value1"), value); + EXPECT_EQ((long long)9223372036854775807, value); + cfg.GetValue(_T("Root.Node.Value2"), value); + EXPECT_EQ((long long)(-9223372036854775807 - 1), value); +} + +TEST(TConfigTests, GetSetLongLongExport) +{ + TConfig cfg; + + TString strXmlData(_T("\n\ +9223372036854775807-9223372036854775808")); + + // store in string + cfg.ReadFromString(strXmlData); + + EXPECT_EQ((long long)9223372036854775807, cfg.GetLongLong(_T("Root.Node.Value1"))); + EXPECT_EQ((long long)(-9223372036854775807 - 1), cfg.GetLongLong(_T("Root.Node.Value2"))); + + TString strWriteXmlData; + cfg.WriteToString(strWriteXmlData); + + EXPECT_EQ(strXmlData, strWriteXmlData); +} + +/////////////////////////////////////////////////////////////////////////// +TEST(TConfigTests, GetSetULongLong) +{ + TConfig cfg; + + // store data in config + cfg.SetValue(_T("Root.Node.Value1"), (unsigned long long)1489); + cfg.SetValue(_T("Root.Node.Value2"), (unsigned long long)18446744073709551615); + + // check if stored successfully (typed get) + EXPECT_EQ((unsigned long long)1489, cfg.GetULongLong(_T("Root.Node.Value1"))); + EXPECT_EQ((unsigned long long)18446744073709551615, cfg.GetULongLong(_T("Root.Node.Value2"))); + + // check if stored successfully (GetValue) + unsigned long long value = 0; + cfg.GetValue(_T("Root.Node.Value1"), value); + EXPECT_EQ((unsigned long long)1489, value); + cfg.GetValue(_T("Root.Node.Value2"), value); + EXPECT_EQ((unsigned long long)18446744073709551615, value); +} + +TEST(TConfigTests, GetSetULongLongExport) +{ + TConfig cfg; + + TString strXmlData(_T("\n\ +148918446744073709551615")); + + // store in string + cfg.ReadFromString(strXmlData); + + EXPECT_EQ((unsigned long long)1489, cfg.GetULongLong(_T("Root.Node.Value1"))); + EXPECT_EQ((unsigned long long)18446744073709551615, cfg.GetULongLong(_T("Root.Node.Value2"))); + + TString strWriteXmlData; + cfg.WriteToString(strWriteXmlData); + + EXPECT_EQ(strXmlData, strWriteXmlData); +} + +/////////////////////////////////////////////////////////////////////////// +TEST(TConfigTests, GetSetDouble) +{ + TConfig cfg; + + // store data in config + cfg.SetValue(_T("Root.Node.Value1"), (double)0.0); + cfg.SetValue(_T("Root.Node.Value2"), 1.7976931348623158e+308); + + // check if stored successfully (typed get) + EXPECT_DOUBLE_EQ(0.0, cfg.GetDouble(_T("Root.Node.Value1"))); + EXPECT_DOUBLE_EQ(1.7976931348623158e+308, cfg.GetDouble(_T("Root.Node.Value2"))); + + // check if stored successfully (GetValue) + double value = 0; + cfg.GetValue(_T("Root.Node.Value1"), value); + EXPECT_DOUBLE_EQ(0.0, value); + cfg.GetValue(_T("Root.Node.Value2"), value); + EXPECT_DOUBLE_EQ(1.7976931348623158e+308, value); +} + +TEST(TConfigTests, GetSetDoubleExport) +{ + TConfig cfg; + + TString strXmlData(_T("\n\ +01.7976931348623158e+308")); + + // store in string + cfg.ReadFromString(strXmlData); + + EXPECT_DOUBLE_EQ(0.0, cfg.GetDouble(_T("Root.Node.Value1"))); + EXPECT_DOUBLE_EQ(1.7976931348623158e+308, cfg.GetDouble(_T("Root.Node.Value2"))); + + TString strWriteXmlData; + cfg.WriteToString(strWriteXmlData); + + EXPECT_EQ(strXmlData, strWriteXmlData); +} + +/////////////////////////////////////////////////////////////////////////// +TEST(TConfigTests, GetSetString) +{ + TConfig cfg; + + // store data in config + cfg.SetValue(_T("Root.Node.Value1"), _T("Some basic string")); + cfg.SetValue(_T("Root.Node.Value2"), L"!@#$%^&*()[]\\/<>,.QWERTYqwerty\x2021"); + + // check if stored successfully (typed get) + EXPECT_EQ(TString(_T("Some basic string")), cfg.GetString(_T("Root.Node.Value1"))); + EXPECT_EQ(TString(L"!@#$%^&*()[]\\/<>,.QWERTYqwerty\x2021"), cfg.GetString(_T("Root.Node.Value2"))); + + // check if stored successfully (GetValue) + TString value; + cfg.GetValue(_T("Root.Node.Value1"), value); + EXPECT_EQ(TString(_T("Some basic string")), value); + cfg.GetValue(_T("Root.Node.Value2"), value); + EXPECT_EQ(TString(L"!@#$%^&*()[]\\/<>,.QWERTYqwerty\x2021"), value); +} + +TEST(TConfigTests, GetSetStringExport) +{ + TConfig cfg; + + TString strXmlData(_T("\n\ +Some basic string!@#$%^&*()[]\\/<>,.QWERTYqwerty\x2021")); + + // store in string + cfg.ReadFromString(strXmlData); + + EXPECT_EQ(TString(_T("Some basic string")), cfg.GetString(_T("Root.Node.Value1"))); + EXPECT_EQ(TString(L"!@#$%^&*()[]\\/<>,.QWERTYqwerty\x2021"), cfg.GetString(_T("Root.Node.Value2"))); + + TString strWriteXmlData; + cfg.WriteToString(strWriteXmlData); + + EXPECT_EQ(strXmlData, strWriteXmlData); +} + +/////////////////////////////////////////////////////////////////////////// +TEST(TConfigTests, GetSetPath) +{ + TConfig cfg; + + // store data in config + cfg.SetValue(_T("Root.Node.Value1"), _T("c:\\Windows\\System32")); + cfg.SetValue(_T("Root.Node.Value2"), _T("\\\\machine\\share\\SomeFile.dat")); + + // check if stored successfully (typed get) + EXPECT_EQ(PathFromString(_T("c:\\Windows\\System32")), cfg.GetPath(_T("Root.Node.Value1"))); + EXPECT_EQ(PathFromString(_T("\\\\machine\\share\\SomeFile.dat")), cfg.GetPath(_T("Root.Node.Value2"))); + + // check if stored successfully (GetValue) + TSmartPath value; + cfg.GetValue(_T("Root.Node.Value1"), value); + EXPECT_EQ(PathFromString(_T("c:\\Windows\\System32")), value); + cfg.GetValue(_T("Root.Node.Value2"), value); + EXPECT_EQ(PathFromString(_T("\\\\machine\\share\\SomeFile.dat")), value); +} + +TEST(TConfigTests, GetSetPathExport) +{ + TConfig cfg; + + TString strXmlData(_T("\n\ +c:\\Windows\\System32\\\\machine\\share\\SomeFile.dat")); + + // store in string + cfg.ReadFromString(strXmlData); + + EXPECT_EQ(PathFromString(_T("c:\\Windows\\System32")), cfg.GetPath(_T("Root.Node.Value1"))); + EXPECT_EQ(PathFromString(_T("\\\\machine\\share\\SomeFile.dat")), cfg.GetPath(_T("Root.Node.Value2"))); + + TString strWriteXmlData; + cfg.WriteToString(strWriteXmlData); + + EXPECT_EQ(strXmlData, strWriteXmlData); +} + +/////////////////////////////////////////////////////////////////////////// +TEST(TConfigTests, GetSetStringArray) +{ + TConfig cfg; + + TStringArray arrString; + arrString.Add(_T("String1")); + arrString.Add(_T("SampleStringPath")); + arrString.Add(_T("!@#$%^&*()")); + arrString.Add(_T("")); + + // store data in config + cfg.SetValue(_T("Root.Node.Values.Node"), arrString); + + // check if stored successfully (typed get) + TStringArray arrRead; + cfg.GetValue(_T("Root.Node.Values.Node"), arrRead); + + EXPECT_EQ(arrString.GetCount(), arrRead.GetCount()); + EXPECT_EQ(arrString.GetAt(0), arrRead.GetAt(0)); + EXPECT_EQ(arrString.GetAt(1), arrRead.GetAt(1)); + EXPECT_EQ(arrString.GetAt(2), arrRead.GetAt(2)); + EXPECT_EQ(arrString.GetAt(3), arrRead.GetAt(3)); +} + +TEST_F(InitializedConfigFixture, GetSetStringArrayImport) +{ + TStringArray arrRead; + m_cfg.GetValue(_T("CHConfig.Core.Notifications.PathList.Path"), arrRead); + + EXPECT_EQ(arrRead.GetCount(), 4); + EXPECT_EQ(TString(_T("c:\\Windows\\System32")), arrRead.GetAt(0)); + EXPECT_EQ(TString(_T("d:\\Movies")), arrRead.GetAt(1)); + EXPECT_EQ(TString(_T("x:\\Music")), arrRead.GetAt(2)); + EXPECT_EQ(TString(_T("s:\\projects\\ch-rw")), arrRead.GetAt(3)); +} + +TEST(TConfigTests, GetSetStringArrayExport) +{ + TConfig cfg; + + TStringArray arrString; + arrString.Add(_T("String1")); + arrString.Add(_T("SampleStringPath")); + arrString.Add(_T("!@#$%^&*()")); + arrString.Add(_T("")); + + // store data in config + cfg.SetValue(_T("Root.Node.Values.Node"), arrString); + + // store in string + TString wstrData; + cfg.WriteToString(wstrData); + + EXPECT_EQ(TString(_T("\n\ +String1SampleStringPath!@#$%^&*()")), wstrData); +} + +/////////////////////////////////////////////////////////////////////////// +TEST_F(InitializedConfigFixture, CompositeObjectsReadWriteString) +{ + TString wstrWithDeletion; + m_cfg.WriteToString(wstrWithDeletion); + + EXPECT_EQ(TString(_T("\n\ +30000\ +FirstName<WINDOWS>\\FirstPathSecondName<WINDOWS>\\SecondPath\ +c:\\Windows\\System32d:\\Moviesx:\\Musics:\\projects\\ch-rw\ +true<WINDOWS>\\media\\chord.wav\ +<WINDOWS>\\media\\ding.wav")), wstrWithDeletion); +} + +/////////////////////////////////////////////////////////////////////////// +TEST_F(InitializedConfigFixture, DeleteNodeTest) +{ + m_cfg.DeleteNode(_T("CHConfig.Core.Notifications")); + + TString wstrWithDeletion; + m_cfg.WriteToString(wstrWithDeletion); + + EXPECT_EQ(TString(_T("\n\ +30000FirstName<WINDOWS>\\FirstPath\ +SecondName<WINDOWS>\\SecondPath")), wstrWithDeletion); +} + +/////////////////////////////////////////////////////////////////////////// +TEST_F(InitializedConfigFixture, ExtractConfig) +{ + TConfig cfgSub; + + m_cfg.ExtractSubConfig(_T("CHConfig.Core.Notifications.Sounds"), cfgSub); + EXPECT_EQ(true, cfgSub.GetBool(_T("Enable"))); + EXPECT_EQ(TString(_T("\\media\\chord.wav")), cfgSub.GetString(_T("ErrorSoundPath"))); + EXPECT_EQ(TString(_T("\\media\\ding.wav")), cfgSub.GetString(_T("FinishedSoundPath"))); +} + +TEST_F(InitializedConfigFixture, ExtractMultipleConfigs) +{ + TConfigArray cfgSubArray; + + m_cfg.ExtractMultiSubConfigs(_T("CHConfig.Core.CompositeObjects.Object"), cfgSubArray); + + EXPECT_EQ(2, cfgSubArray.GetCount()); + + EXPECT_EQ(TString(_T("FirstName")), cfgSubArray.GetAt(0).GetString(_T("Name"))); + EXPECT_EQ(TString(_T("\\FirstPath")), cfgSubArray.GetAt(0).GetString(_T("Path"))); + EXPECT_EQ(TString(_T("SecondName")), cfgSubArray.GetAt(1).GetString(_T("Name"))); + EXPECT_EQ(TString(_T("\\SecondPath")), cfgSubArray.GetAt(1).GetString(_T("Path"))); +} + +TEST(TConfigTests, PutSubConfig) +{ + TConfig mainCfg; + + TConfig cfgSub; + cfgSub.SetValue(_T("Node1"), true); + cfgSub.SetValue(_T("NameNode"), _T("TestNode")); + + mainCfg.PutSubConfig(_T("Root.NodeSet"), cfgSub); + + EXPECT_EQ(true, mainCfg.GetBool(_T("Root.NodeSet.Node1"))); + EXPECT_EQ(TString(_T("TestNode")), mainCfg.GetString(_T("Root.NodeSet.NameNode"))); +} + +TEST(TConfigTests, AddSubConfig) +{ + TConfig mainCfg; + + TConfig cfgSub; + cfgSub.SetValue(_T("Node1"), true); + cfgSub.SetValue(_T("NameNode"), _T("TestNode")); + + mainCfg.AddSubConfig(_T("Root.NodeSet.Node"), cfgSub); + mainCfg.AddSubConfig(_T("Root.NodeSet.Node"), cfgSub); + + TString strXml; + mainCfg.WriteToString(strXml); + + EXPECT_EQ(TString(_T("\n\ +TestNodetrueTestNodetrue")), strXml); +}