// Copyright (c) 2009 The Chromium 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 "config.h"
#include "CString.h"
#include "Document.h"
#include "EventListener.h"
#include "HTMLFrameOwnerElement.h"
#include "PlatformString.h"
#include
#undef LOG
#include "base/file_path.h"
#include "base/string_util.h"
#include "base/values.h"
#include "net/base/net_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webkit/glue/devtools/devtools_mock_rpc.h"
#include "webkit/glue/devtools/devtools_rpc.h"
#include "webkit/glue/devtools/dom_agent_impl.h"
#include "webkit/glue/dom_operations.h"
#include "webkit/glue/glue_util.h"
#include "webkit/glue/webframe.h"
#include "webkit/glue/webframe_impl.h"
#include "webkit/glue/webview.h"
#include "webkit/tools/test_shell/test_shell_test.h"
using WebCore::Document;
using WebCore::Element;
using WebCore::ExceptionCode;
using WebCore::HTMLFrameOwnerElement;
using WebCore::Node;
using WebCore::String;
namespace {
class MockDomAgentDelegate : public DomAgentDelegateStub,
public DevToolsMockRpc {
public:
MockDomAgentDelegate() : DomAgentDelegateStub(NULL) {
set_delegate(this);
}
~MockDomAgentDelegate() {}
};
class DomAgentTests : public TestShellTest {
public:
DomAgentTests() : ec_(0) {}
protected:
// testing::Test
virtual void SetUp() {
TestShellTest::SetUp();
test_shell_->ResetTestController();
GURL file_url = net::FilePathToFileURL(data_dir_);
WebFrame* main_frame = test_shell_->webView()->GetMainFrame();
main_frame->LoadHTMLString("",
file_url);
WebFrameImpl* main_frame_impl = static_cast(main_frame);
document_ = main_frame_impl->frame()->document();
Node* html = document_->documentElement();
body_ = static_cast(html->firstChild());
mock_delegate_.set(new MockDomAgentDelegate());
dom_agent_.set(new DomAgentImpl(mock_delegate_.get()));
dom_agent_->SetDocument(document_.get());
}
virtual void TearDown() {
TestShellTest::TearDown();
dom_agent_.set(NULL);
body_ = NULL;
document_ = NULL;
}
static const int kHtmlElemId = 1;
static const int kBodyElemId = 2;
enum {
kCallIdAny = 0,
kCallId1,
kCallId2,
kCallId3,
kCallId4
};
RefPtr document_;
RefPtr body_;
OwnPtr dom_agent_;
ExceptionCode ec_;
OwnPtr mock_delegate_;
};
// Requests document node and tests that the callback with the serialized
// version is called.
TEST_F(DomAgentTests, GetDocumentElement) {
OwnPtr v(DevToolsRpc::ParseMessage("[1,1,\"HTML\",\"\",[],1]"));
mock_delegate_->SetDocumentElement(*v.get());
mock_delegate_->Replay();
dom_agent_->GetDocumentElement();
mock_delegate_->Verify();
}
// Requests element's children and tests that the callback with the serialized
// version is called.
TEST_F(DomAgentTests, GetChildNodes) {
dom_agent_->GetDocumentElement();
mock_delegate_->Reset();
OwnPtr v(DevToolsRpc::ParseMessage("[[2,1,\"BODY\",\"\",[],0]]"));
mock_delegate_->SetChildNodes(kHtmlElemId, *v.get());
mock_delegate_->DidGetChildNodes(kCallId2);
mock_delegate_->Replay();
dom_agent_->GetChildNodes(kCallId2, kHtmlElemId);
mock_delegate_->Verify();
}
// Tests that "child node inserted" event is being fired.
TEST_F(DomAgentTests, ChildNodeInsertedUnknownParent) {
dom_agent_->GetDocumentElement();
mock_delegate_->Reset();
// There should be no events fired until parent node is known to client.
RefPtr div = document_->createElement("DIV", ec_);
body_->appendChild(div, ec_);
mock_delegate_->Replay();
mock_delegate_->Verify();
}
// Tests that "child node inserted" event is being fired.
TEST_F(DomAgentTests, ChildNodeInsertedKnownParent) {
dom_agent_->GetDocumentElement();
dom_agent_->GetChildNodes(kCallId2, kHtmlElemId);
mock_delegate_->Reset();
// There should be an event fired in case parent node is known to client,
// but the event should not be specific.
mock_delegate_->HasChildrenUpdated(kBodyElemId, true);
mock_delegate_->Replay();
RefPtr div = document_->createElement("DIV", ec_);
body_->appendChild(div, ec_);
mock_delegate_->Verify();
}
// Tests that "child node inserted" event is being fired.
TEST_F(DomAgentTests, ChildNodeInsertedKnownChildren) {
dom_agent_->GetDocumentElement();
dom_agent_->GetChildNodes(kCallId2, kHtmlElemId);
dom_agent_->GetChildNodes(kCallId3, kBodyElemId);
mock_delegate_->Reset();
// There should be an event fired in case parent node is known to client,
// Since children were already requested, event should have all the
// new child data.
OwnPtr v(DevToolsRpc::ParseMessage("[3,1,\"DIV\",\"\",[],0]"));
mock_delegate_->ChildNodeInserted(kBodyElemId, 0, *v.get());
mock_delegate_->Replay();
RefPtr div = document_->createElement("DIV", ec_);
body_->appendChild(div, ec_);
mock_delegate_->Verify();
}
// Tests that "child node inserted" event is being fired.
TEST_F(DomAgentTests, ChildNodePrepend) {
RefPtr div = document_->createElement("DIV", ec_);
body_->appendChild(div, ec_);
dom_agent_->GetDocumentElement();
dom_agent_->GetChildNodes(kCallId2, kHtmlElemId);
dom_agent_->GetChildNodes(kCallId3, kBodyElemId);
mock_delegate_->Reset();
// There should be an event fired in case parent node is known to client,
// Since children were already requested, event should have all the
// new child data.
OwnPtr v(DevToolsRpc::ParseMessage("[4,1,\"DIV\",\"\",[],0]"));
mock_delegate_->ChildNodeInserted(kBodyElemId, 0, *v.get());
mock_delegate_->Replay();
RefPtr new_div = document_->createElement("DIV", ec_);
body_->insertBefore(new_div, div.get(), ec_, false);
mock_delegate_->Verify();
}
// Tests that "child node inserted" event is being fired.
TEST_F(DomAgentTests, ChildNodeAppend) {
RefPtr div = document_->createElement("DIV", ec_);
body_->appendChild(div, ec_);
dom_agent_->GetDocumentElement();
dom_agent_->GetChildNodes(kCallId2, kHtmlElemId);
dom_agent_->GetChildNodes(kCallId3, kBodyElemId);
mock_delegate_->Reset();
// There should be an event fired in case parent node is known to client,
// Since children were already requested, event should have all the
// new child data.
OwnPtr v(DevToolsRpc::ParseMessage("[4,1,\"DIV\",\"\",[],0]"));
mock_delegate_->ChildNodeInserted(kBodyElemId, 3, *v.get());
mock_delegate_->Replay();
RefPtr new_div = document_->createElement("DIV", ec_);
body_->appendChild(new_div, ec_, false);
mock_delegate_->Verify();
}
// Tests that "child node inserted" event is being fired.
TEST_F(DomAgentTests, ChildNodeInsert) {
RefPtr div1 = document_->createElement("DIV", ec_);
body_->appendChild(div1, ec_);
RefPtr div2 = document_->createElement("DIV", ec_);
body_->appendChild(div2, ec_);
dom_agent_->GetDocumentElement();
dom_agent_->GetChildNodes(kCallId2, kHtmlElemId);
dom_agent_->GetChildNodes(kCallId3, kBodyElemId);
mock_delegate_->Reset();
// There should be an event fired in case parent node is known to client,
// Since children were already requested, event should have all the
// new child data.
OwnPtr v(DevToolsRpc::ParseMessage("[5,1,\"DIV\",\"\",[],0]"));
mock_delegate_->ChildNodeInserted(kBodyElemId, 3, *v.get());
mock_delegate_->Replay();
RefPtr new_div = document_->createElement("DIV", ec_);
body_->insertBefore(new_div, div2.get(), ec_, false);
mock_delegate_->Verify();
}
// Tests that "child node inserted" event is being fired.
TEST_F(DomAgentTests, ChildNodeRemovedUnknownParent) {
RefPtr div = document_->createElement("DIV", ec_);
body_->appendChild(div, ec_);
dom_agent_->GetDocumentElement();
mock_delegate_->Reset();
// There should be no events fired until parent node is known to client.
mock_delegate_->Replay();
body_->removeChild(div.get(), ec_);
mock_delegate_->Verify();
}
// Tests that "child node inserted" event is being fired.
TEST_F(DomAgentTests, ChildNodeRemovedKnownParent) {
RefPtr div = document_->createElement("DIV", ec_);
body_->appendChild(div, ec_);
dom_agent_->GetDocumentElement();
dom_agent_->GetChildNodes(kCallId2, kHtmlElemId);
mock_delegate_->Reset();
// There should be an event fired in case parent node is known to client,
// but the event should not be specific.
mock_delegate_->HasChildrenUpdated(kBodyElemId, false);
mock_delegate_->Replay();
body_->removeChild(div.get(), ec_);
mock_delegate_->Verify();
}
// Tests that "child node inserted" event is being fired.
TEST_F(DomAgentTests, ChildNodeRemovedKnownChildren) {
RefPtr div = document_->createElement("DIV", ec_);
body_->appendChild(div, ec_);
dom_agent_->GetDocumentElement();
dom_agent_->GetChildNodes(kCallId2, kHtmlElemId);
dom_agent_->GetChildNodes(kCallId3, kBodyElemId);
mock_delegate_->Reset();
// There should be an event fired in case parent node is known to client,
// Since children were already requested, event should have removed child id.
mock_delegate_->ChildNodeRemoved(kBodyElemId, 3);
mock_delegate_->Replay();
body_->removeChild(div.get(), ec_);
mock_delegate_->Verify();
}
// Tests that "PushNodePathToClient" sends all missing events in path.
TEST_F(DomAgentTests, PushPathToKnownNode) {
RefPtr div1 = document_->createElement("DIV", ec_);
body_->appendChild(div1, ec_);
dom_agent_->GetDocumentElement();
dom_agent_->GetChildNodes(kCallId2, kHtmlElemId);
dom_agent_->GetChildNodes(kCallId3, kBodyElemId);
mock_delegate_->Reset();
// We expect no messages - node is already known.
mock_delegate_->Replay();
int id = dom_agent_->PushNodePathToClient(div1.get());
mock_delegate_->Verify();
EXPECT_EQ(3, id);
}
// Tests that "PushNodePathToClient" sends all missing events in path.
TEST_F(DomAgentTests, PushPathToKnownParent) {
RefPtr div1 = document_->createElement("DIV", ec_);
body_->appendChild(div1, ec_);
dom_agent_->GetDocumentElement();
dom_agent_->GetChildNodes(kCallId2, kHtmlElemId);
mock_delegate_->Reset();
OwnPtr v1(DevToolsRpc::ParseMessage("[[3,1,\"DIV\",\"\",[],0]]"));
mock_delegate_->SetChildNodes(kBodyElemId, *v1.get());
mock_delegate_->Replay();
int id = dom_agent_->PushNodePathToClient(div1.get());
mock_delegate_->Verify();
EXPECT_EQ(3, id);
}
// Tests that "PushNodePathToClient" sends all missing events in path.
TEST_F(DomAgentTests, PushPathToUnknownNode) {
RefPtr div1 = document_->createElement("DIV", ec_);
RefPtr div2 = document_->createElement("DIV", ec_);
RefPtr div3 = document_->createElement("DIV", ec_);
RefPtr div4 = document_->createElement("DIV", ec_);
body_->appendChild(div1, ec_);
div1->appendChild(div2, ec_);
div2->appendChild(div3, ec_);
div3->appendChild(div4, ec_);
dom_agent_->GetDocumentElement();
dom_agent_->GetChildNodes(kCallId2, kHtmlElemId);
mock_delegate_->Reset();
OwnPtr v1(DevToolsRpc::ParseMessage("[[3,1,\"DIV\",\"\",[],1]]"));
OwnPtr v2(DevToolsRpc::ParseMessage("[[4,1,\"DIV\",\"\",[],1]]"));
OwnPtr v3(DevToolsRpc::ParseMessage("[[5,1,\"DIV\",\"\",[],1]]"));
OwnPtr v4(DevToolsRpc::ParseMessage("[[6,1,\"DIV\",\"\",[],0]]"));
mock_delegate_->SetChildNodes(kBodyElemId, *v1.get());
mock_delegate_->SetChildNodes(3, *v2.get());
mock_delegate_->SetChildNodes(4, *v3.get());
mock_delegate_->SetChildNodes(5, *v4.get());
mock_delegate_->Replay();
int id = dom_agent_->PushNodePathToClient(div4.get());
mock_delegate_->Verify();
EXPECT_EQ(6, id);
}
// Tests that "GetChildNodes" crosses frame owner boundaries.
TEST_F(DomAgentTests, GetChildNodesOfFrameOwner) {
RefPtr iframe = document_->createElement("IFRAME", ec_);
body_->appendChild(iframe, ec_);
dom_agent_->GetDocumentElement();
dom_agent_->GetChildNodes(kCallId2, kHtmlElemId);
dom_agent_->GetChildNodes(kCallId3, kBodyElemId);
mock_delegate_->Reset();
// Expecting HTML child with single (body) child.
OwnPtr v(DevToolsRpc::ParseMessage("[[4,1,\"HTML\",\"\",[],1]]"));
mock_delegate_->SetChildNodes(3, *v.get());
mock_delegate_->DidGetChildNodes(kCallId4);
mock_delegate_->Replay();
dom_agent_->GetChildNodes(kCallId4, 3);
mock_delegate_->Verify();
}
// Tests that "PushNodePathToClient" crosses frame owner boundaries.
TEST_F(DomAgentTests, SendPathToNodeOverFrameOwner) {
RefPtr iframe = document_->createElement("IFRAME", ec_);
body_->appendChild(iframe, ec_);
HTMLFrameOwnerElement* frame_owner =
static_cast(iframe.get());
Node* inner_body = frame_owner->contentDocument()->firstChild()->
firstChild();
dom_agent_->GetDocumentElement();
dom_agent_->GetChildNodes(kCallId2, kHtmlElemId);
mock_delegate_->Reset();
OwnPtr v1(DevToolsRpc::ParseMessage("[[3,1,\"IFRAME\",\"\",[],1]]"));
OwnPtr v2(DevToolsRpc::ParseMessage("[[4,1,\"HTML\",\"\",[],1]]"));
OwnPtr v3(DevToolsRpc::ParseMessage("[[5,1,\"BODY\",\"\",[],0]]"));
mock_delegate_->SetChildNodes(2, *v1.get());
mock_delegate_->SetChildNodes(3, *v2.get());
mock_delegate_->SetChildNodes(4, *v3.get());
mock_delegate_->Replay();
dom_agent_->PushNodePathToClient(inner_body);
mock_delegate_->Verify();
}
// Tests that "child node inserted" event is being fired.
TEST_F(DomAgentTests, ChildNodeInsertUnderFrameOwner) {
RefPtr iframe = document_->createElement("IFRAME", ec_);
body_->appendChild(iframe, ec_);
HTMLFrameOwnerElement* frame_owner =
static_cast(iframe.get());
Node* inner_body = frame_owner->contentDocument()->firstChild()->
firstChild();
dom_agent_->GetDocumentElement();
dom_agent_->GetChildNodes(kCallIdAny, kHtmlElemId);
dom_agent_->GetChildNodes(kCallIdAny, kBodyElemId);
dom_agent_->GetChildNodes(kCallIdAny, 3); // IFrame children
dom_agent_->GetChildNodes(kCallIdAny, 4); // IFrame html's children
dom_agent_->GetChildNodes(kCallIdAny, 5); // IFrame body's children
mock_delegate_->Reset();
// There should be an event fired in case parent node is known to client,
// Since children were already requested, event should have all the
// new child data.
OwnPtr v(DevToolsRpc::ParseMessage("[6,1,\"DIV\",\"\",[],0]"));
mock_delegate_->ChildNodeInserted(5, 0, *v.get());
mock_delegate_->Replay();
RefPtr new_div = document_->createElement("DIV", ec_);
inner_body->appendChild(new_div.get(), ec_, false);
mock_delegate_->Verify();
}
} // namespace