Chromium Code Reviews| Index: remoting/protocol/jingle_messages_unittest.cc | 
| diff --git a/remoting/protocol/jingle_messages_unittest.cc b/remoting/protocol/jingle_messages_unittest.cc | 
| index a72db8636103c769892e8cdfd34a69d434511613..beedc75bc67e1193f64a6a7cdcc6ab4f180898b7 100644 | 
| --- a/remoting/protocol/jingle_messages_unittest.cc | 
| +++ b/remoting/protocol/jingle_messages_unittest.cc | 
| @@ -8,6 +8,7 @@ | 
| #include "base/logging.h" | 
| #include "base/macros.h" | 
| +#include "base/strings/string_util.h" | 
| #include "remoting/protocol/content_description.h" | 
| #include "testing/gmock/include/gmock/gmock.h" | 
| #include "testing/gtest/include/gtest/gtest.h" | 
| @@ -26,6 +27,39 @@ namespace { | 
| const char kXmlNsNs[] = "http://www.w3.org/2000/xmlns/"; | 
| const char kXmlNs[] = "xmlns"; | 
| +bool VerifyXml(const XmlElement* exp, | 
| + const XmlElement* val, | 
| + std::string* error); | 
| + | 
| +bool VerifyXmlChildrenUnordered(const XmlElement* exp, | 
| + const XmlElement* val, | 
| + bool exp_is_expected, | 
| + std::string* error) { | 
| + const XmlElement* exp_child = exp->FirstElement(); | 
| + while (exp_child) { | 
| + const XmlElement* val_child = val->FirstElement(); | 
| + while (val_child) { | 
| + if (VerifyXml(exp_child, val_child, error)) { | 
| + break; | 
| + } | 
| + val_child = val_child->NextElement(); | 
| + } | 
| + if (!val_child) { | 
| + if (error->empty()) { | 
| + if (exp_is_expected) { | 
| + *error = "<" + exp_child->Name().Merged() + "> is expected, " | 
| + "but not found"; | 
| + } else { | 
| + *error = "Unexpected <" + exp_child->Name().Merged() + "> found"; | 
| + } | 
| + } | 
| + return false; | 
| + } | 
| + exp_child = exp_child->NextElement(); | 
| + } | 
| + return true; | 
| +} | 
| + | 
| // Compares two XML blobs and returns true if they are | 
| // equivalent. Otherwise |error| is set to error message that | 
| // specifies the first test. | 
| @@ -72,21 +106,8 @@ bool VerifyXml(const XmlElement* exp, | 
| } | 
| } | 
| - const XmlElement* exp_child = exp->FirstElement(); | 
| - const XmlElement* val_child = val->FirstElement(); | 
| - while (exp_child && val_child) { | 
| - if (!VerifyXml(exp_child, val_child, error)) | 
| - return false; | 
| - exp_child = exp_child->NextElement(); | 
| - val_child = val_child->NextElement(); | 
| - } | 
| - if (exp_child) { | 
| - *error = "<" + exp_child->Name().Merged() + "> is expected, but not found"; | 
| - return false; | 
| - } | 
| - | 
| - if (val_child) { | 
| - *error = "Unexpected <" + val_child->Name().Merged() + "> found"; | 
| + if (!VerifyXmlChildrenUnordered(exp, val, true, error) || | 
| + !VerifyXmlChildrenUnordered(val, exp, false, error)) { | 
| return false; | 
| } | 
| @@ -119,6 +140,7 @@ void ParseFormatAndCompare(const char* message_text, JingleMessage* parsed) { | 
| std::unique_ptr<XmlElement> formatted_message(parsed->ToXml()); | 
| ASSERT_TRUE(formatted_message.get()); | 
| + | 
| EXPECT_TRUE(VerifyXml(source_message.get(), formatted_message.get(), &error)) | 
| << error; | 
| } | 
| @@ -600,5 +622,82 @@ TEST(JingleMessageTest, RemotingErrorCode) { | 
| } | 
| } | 
| +namespace { | 
| + | 
| +void TestPluginMessage(bool insert_before_regular_message) { | 
| 
 
Sergey Ulanov
2016/12/12 23:00:03
I doubt it's useful to test for the case when the
 
Hzj_jie
2016/12/13 00:20:51
I have not found there is a strong sequence requir
 
Sergey Ulanov
2016/12/14 01:31:50
Yes, both formats are valid. My point was that it'
 
Hzj_jie
2016/12/14 20:03:48
Updated.
 
 | 
| + const char* kMessageWithPluginTag = | 
| + "<cli:iq from='user@gmail.com/chromoting016DBB07' " | 
| + "to='user@gmail.com/chromiumsy5C6A652D' type='set' " | 
| + "xmlns:cli='jabber:client'><jingle action='$1' " | 
| + "sid='2227053353' xmlns='urn:xmpp:jingle:1'>$2" | 
| + "<gr:plugin xmlns:gr='google:remoting'>" | 
| + "<gr:sometag>some-message</gr:sometag>" | 
| + "</gr:plugin>$3</jingle></cli:iq>"; | 
| + for (int i = JingleMessage::SESSION_INITIATE; | 
| + i <= JingleMessage::TRANSPORT_INFO; i++) { | 
| + JingleMessage::ActionType action_type = | 
| + static_cast<JingleMessage::ActionType>(i); | 
| + std::vector<std::string> subst = { | 
| 
 
Sergey Ulanov
2016/12/12 23:00:03
subst is not a good name
 
Hzj_jie
2016/12/13 00:20:51
Done.
 
 | 
| + JingleMessage::GetActionName(action_type) | 
| + }; | 
| + if (insert_before_regular_message) { | 
| + subst.emplace_back(); | 
| + } | 
| + if (action_type == JingleMessage::SESSION_INFO) { | 
| + subst.push_back("<test-info>test-message</test-info>"); | 
| + } else if (action_type == JingleMessage::SESSION_TERMINATE) { | 
| + subst.emplace_back(); | 
| + } else if (action_type == JingleMessage::TRANSPORT_INFO) { | 
| 
 
Sergey Ulanov
2016/12/12 23:00:03
I don't think we want to allow plugins for transpo
 
Hzj_jie
2016/12/13 00:20:51
I thought this before, but it would make JingleMes
 
Sergey Ulanov
2016/12/14 01:31:50
It would make JingleMessage very slightly more com
 
Hzj_jie
2016/12/14 20:03:48
I think it can make both JingleMessage and JingleS
 
Sergey Ulanov
2016/12/15 19:18:25
I think complexity comes not only from amount of c
 
Hzj_jie
2016/12/15 22:41:19
IMO how to handle the message is not part of the f
 
 | 
| + subst.push_back( | 
| + "<content name='chromoting' creator='initiator'>" | 
| + "<transport xmlns='google:remoting:webrtc'>" | 
| + "<credentials channel='event' ufrag='tPUyEAmQrEw3y7hi' " | 
| + "password='2iRdhLfawKZC5ydJ'/>" | 
| + "<credentials channel='video' ufrag='EPK3CXo5sTLJSez0' " | 
| + "password='eM0VUfUkZ+1Pyi0M'/>" | 
| + "<candidate name='event' foundation='725747215' " | 
| + "address='172.23.164.186' port='59089' type='local' " | 
| + "protocol='udp' priority='2122194688' generation='0'/>" | 
| + "<candidate name='video' foundation='3623806809' " | 
| + "address='172.23.164.186' port='57040' type='local' " | 
| + "protocol='udp' priority='2122194688' generation='0'/>" | 
| + "</transport>" | 
| + "</content>"); | 
| + } else { | 
| + subst.push_back("<content name='chromoting' creator='initiator'>" | 
| + "<description xmlns='google:remoting'>" | 
| + "<authentication><auth-token>" | 
| + "j7whCMii0Z0AAPwj7whCM/j7whCMii0Z0AAPw=" | 
| + "</auth-token></authentication>" | 
| + "</description>" | 
| + "<transport xmlns='google:remoting:webrtc' />" | 
| + "</content>"); | 
| + } | 
| + if (!insert_before_regular_message) { | 
| + subst.emplace_back(); | 
| + } | 
| + std::string message_str = base::ReplaceStringPlaceholders( | 
| + kMessageWithPluginTag, subst, nullptr); | 
| + | 
| + JingleMessage message; | 
| + ParseFormatAndCompare(message_str.c_str(), &message); | 
| + | 
| + EXPECT_TRUE(message.plugin_message); | 
| + XmlElement expected(QName("google:remoting", "plugin")); | 
| + expected.AddElement(new XmlElement(QName("google:remoting", "sometag"))); | 
| + expected.FirstElement()->SetBodyText("some-message"); | 
| + std::string error; | 
| + EXPECT_TRUE(VerifyXml(&expected, message.plugin_message.get(), &error)) | 
| + << error; | 
| + } | 
| +} | 
| + | 
| +} // namespace | 
| + | 
| +TEST(JingleMessageTest, PluginMessage) { | 
| + TestPluginMessage(false); | 
| + TestPluginMessage(true); | 
| +} | 
| + | 
| } // namespace protocol | 
| } // namespace remoting |