// Copyright 2015 The Weave Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/notification/xmpp_iq_stanza_handler.h"

#include <map>
#include <memory>

#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <weave/provider/test/fake_task_runner.h>

#include "src/bind_lambda.h"
#include "src/notification/xml_node.h"
#include "src/notification/xmpp_channel.h"
#include "src/notification/xmpp_stream_parser.h"

using testing::_;

namespace weave {
namespace {

class MockXmppChannelInterface : public XmppChannelInterface {
 public:
  MockXmppChannelInterface() = default;

  MOCK_METHOD1(SendMessage, void(const std::string&));

 private:
  DISALLOW_COPY_AND_ASSIGN(MockXmppChannelInterface);
};

// Simple class that allows to parse XML from string to XmlNode.
class XmlParser : public XmppStreamParser::Delegate {
 public:
  std::unique_ptr<XmlNode> Parse(const std::string& xml) {
    parser_.ParseData(xml);
    return std::move(node_);
  }

 private:
  // Overrides from XmppStreamParser::Delegate.
  void OnStreamStart(const std::string& node_name,
                     std::map<std::string, std::string> attributes) override {
    node_.reset(new XmlNode{node_name, std::move(attributes)});
  }

  void OnStreamEnd(const std::string& node_name) override {}

  void OnStanza(std::unique_ptr<XmlNode> stanza) override {
    node_->AddChild(std::move(stanza));
  }

  std::unique_ptr<XmlNode> node_;
  XmppStreamParser parser_{this};
};

class MockResponseReceiver {
 public:
  MOCK_METHOD2(OnResponse, void(int id, const std::string&));

  IqStanzaHandler::ResponseCallback callback(int id) {
    return base::Bind(&MockResponseReceiver::OnResponseCallback,
                      base::Unretained(this), id);
  }

 private:
  void OnResponseCallback(int id, std::unique_ptr<XmlNode> response) {
    OnResponse(id, response->children().front()->name());
  }
};

}  // anonymous namespace

class IqStanzaHandlerTest : public testing::Test {
 public:
  testing::StrictMock<MockXmppChannelInterface> mock_xmpp_channel_;
  provider::test::FakeTaskRunner task_runner_;
  IqStanzaHandler iq_stanza_handler_{&mock_xmpp_channel_, &task_runner_};
  MockResponseReceiver receiver_;
};

TEST_F(IqStanzaHandlerTest, SendRequest) {
  std::string expected_msg = "<iq id='1' type='set'><body/></iq>";
  EXPECT_CALL(mock_xmpp_channel_, SendMessage(expected_msg)).Times(1);
  iq_stanza_handler_.SendRequest("set", "", "", "<body/>", {}, {});

  expected_msg = "<iq id='2' type='get'><body/></iq>";
  EXPECT_CALL(mock_xmpp_channel_, SendMessage(expected_msg)).Times(1);
  iq_stanza_handler_.SendRequest("get", "", "", "<body/>", {}, {});

  expected_msg = "<iq id='3' type='query' from='foo@bar'><body/></iq>";
  EXPECT_CALL(mock_xmpp_channel_, SendMessage(expected_msg)).Times(1);
  iq_stanza_handler_.SendRequest("query", "foo@bar", "", "<body/>", {}, {});

  expected_msg = "<iq id='4' type='query' to='foo@bar'><body/></iq>";
  EXPECT_CALL(mock_xmpp_channel_, SendMessage(expected_msg)).Times(1);
  iq_stanza_handler_.SendRequest("query", "", "foo@bar", "<body/>", {}, {});

  expected_msg = "<iq id='5' type='query' from='foo@bar' to='baz'><body/></iq>";
  EXPECT_CALL(mock_xmpp_channel_, SendMessage(expected_msg)).Times(1);
  iq_stanza_handler_.SendRequest("query", "foo@bar", "baz", "<body/>", {}, {});
  // This test ignores all the posted callbacks.
}

TEST_F(IqStanzaHandlerTest, UnsupportedIqRequest) {
  // Server IQ requests are not supported for now. Expect an error response.
  std::string expected_msg =
      "<iq id='1' type='error'><error type='modify'>"
      "<feature-not-implemented xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>"
      "</error></iq>";
  EXPECT_CALL(mock_xmpp_channel_, SendMessage(expected_msg)).Times(1);
  auto request = XmlParser{}.Parse("<iq id='1' type='set'><foo/></iq>");
  EXPECT_TRUE(iq_stanza_handler_.HandleIqStanza(std::move(request)));
}

TEST_F(IqStanzaHandlerTest, UnknownResponseId) {
  // No requests with ID=100 have been previously sent.
  auto request = XmlParser{}.Parse("<iq id='100' type='result'><foo/></iq>");
  EXPECT_TRUE(iq_stanza_handler_.HandleIqStanza(std::move(request)));
}

TEST_F(IqStanzaHandlerTest, SequentialResponses) {
  EXPECT_CALL(mock_xmpp_channel_, SendMessage(_)).Times(2);
  iq_stanza_handler_.SendRequest("set", "", "", "<body/>",
                                 receiver_.callback(1), {});
  iq_stanza_handler_.SendRequest("get", "", "", "<body/>",
                                 receiver_.callback(2), {});

  EXPECT_CALL(receiver_, OnResponse(1, "foo"));
  auto request = XmlParser{}.Parse("<iq id='1' type='result'><foo/></iq>");
  EXPECT_TRUE(iq_stanza_handler_.HandleIqStanza(std::move(request)));

  EXPECT_CALL(receiver_, OnResponse(2, "bar"));
  request = XmlParser{}.Parse("<iq id='2' type='result'><bar/></iq>");
  EXPECT_TRUE(iq_stanza_handler_.HandleIqStanza(std::move(request)));

  task_runner_.Run();
}

TEST_F(IqStanzaHandlerTest, OutOfOrderResponses) {
  EXPECT_CALL(mock_xmpp_channel_, SendMessage(_)).Times(2);
  iq_stanza_handler_.SendRequest("set", "", "", "<body/>",
                                 receiver_.callback(1), {});
  iq_stanza_handler_.SendRequest("get", "", "", "<body/>",
                                 receiver_.callback(2), {});

  EXPECT_CALL(receiver_, OnResponse(2, "bar"));
  auto request = XmlParser{}.Parse("<iq id='2' type='result'><bar/></iq>");
  EXPECT_TRUE(iq_stanza_handler_.HandleIqStanza(std::move(request)));

  EXPECT_CALL(receiver_, OnResponse(1, "foo"));
  request = XmlParser{}.Parse("<iq id='1' type='result'><foo/></iq>");
  EXPECT_TRUE(iq_stanza_handler_.HandleIqStanza(std::move(request)));

  task_runner_.Run();
}

TEST_F(IqStanzaHandlerTest, RequestTimeout) {
  bool called = false;
  auto on_timeout = [](bool* called) { *called = true; };

  EXPECT_CALL(mock_xmpp_channel_, SendMessage(_)).Times(1);
  EXPECT_FALSE(called);
  iq_stanza_handler_.SendRequest(
      "set", "", "", "<body/>", {},
      base::Bind(on_timeout, base::Unretained(&called)));
  task_runner_.Run();
  EXPECT_TRUE(called);
}

}  // namespace weave
