blob: fe2a3097ddf33bafa8a32d39e104e55649b0a8fc [file] [log] [blame]
// Copyright 2014 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.
#import "ios/web/web_state/ui/crw_wk_script_message_router.h"
#include "base/mac/scoped_block.h"
#include "base/mac/scoped_nsobject.h"
#include "base/memory/ptr_util.h"
#include "ios/web/public/test/scoped_testing_web_client.h"
#include "ios/web/public/test/test_browser_state.h"
#import "ios/web/public/test/test_web_client.h"
#include "ios/web/public/test/web_test.h"
#import "ios/web/public/web_view_creation_util.h"
#include "third_party/ocmock/OCMock/OCMock.h"
#include "third_party/ocmock/gtest_support.h"
namespace {
// Returns WKScriptMessage mock.
id GetScriptMessageMock(WKWebView* web_view, NSString* name) {
id result = [OCMockObject mockForClass:[WKScriptMessage class]];
[[[result stub] andReturn:web_view] webView];
[[[result stub] andReturn:name] name];
return result;
}
// Test fixture for CRWWKScriptMessageRouter.
class CRWWKScriptMessageRouterTest : public web::WebTest {
public:
CRWWKScriptMessageRouterTest()
: web_client_(base::WrapUnique(new web::WebClient)) {}
protected:
void SetUp() override {
web::WebTest::SetUp();
// Mock WKUserContentController object.
controller_mock_.reset(
[[OCMockObject mockForClass:[WKUserContentController class]] retain]);
[controller_mock_ setExpectationOrderMatters:YES];
// Create testable CRWWKScriptMessageRouter.
router_.reset(static_cast<id<WKScriptMessageHandler>>(
[[CRWWKScriptMessageRouter alloc]
initWithUserContentController:controller_mock_]));
// Prepare test data.
handler1_.reset([^{
} copy]);
handler2_.reset([^{
} copy]);
handler3_.reset([^{
} copy]);
name1_.reset([@"name1" copy]);
name2_.reset([@"name2" copy]);
name3_.reset([@"name3" copy]);
web_view1_.reset(web::CreateWKWebView(CGRectZero, &browser_state_));
web_view2_.reset(web::CreateWKWebView(CGRectZero, &browser_state_));
web_view3_.reset(web::CreateWKWebView(CGRectZero, &browser_state_));
}
void TearDown() override {
EXPECT_OCMOCK_VERIFY(controller_mock_);
web::WebTest::TearDown();
}
// WKUserContentController mock used to create testable router.
base::scoped_nsobject<id> controller_mock_;
// CRWWKScriptMessageRouter set up for testing.
base::scoped_nsobject<id> router_;
// Tests data.
typedef void (^WKScriptMessageHandler)(WKScriptMessage*);
base::mac::ScopedBlock<WKScriptMessageHandler> handler1_;
base::mac::ScopedBlock<WKScriptMessageHandler> handler2_;
base::mac::ScopedBlock<WKScriptMessageHandler> handler3_;
base::scoped_nsobject<NSString> name1_;
base::scoped_nsobject<NSString> name2_;
base::scoped_nsobject<NSString> name3_;
base::scoped_nsobject<WKWebView> web_view1_;
base::scoped_nsobject<WKWebView> web_view2_;
base::scoped_nsobject<WKWebView> web_view3_;
private:
// WebClient and BrowserState for testing.
web::ScopedTestingWebClient web_client_;
web::TestBrowserState browser_state_;
};
// Tests CRWWKScriptMessageRouter designated initializer.
TEST_F(CRWWKScriptMessageRouterTest, Initialization) {
EXPECT_TRUE(router_);
}
// Tests registration/deregistation of message handlers.
TEST_F(CRWWKScriptMessageRouterTest, HandlerRegistration) {
[[controller_mock_ expect] addScriptMessageHandler:router_ name:name1_];
[[controller_mock_ expect] addScriptMessageHandler:router_ name:name2_];
[[controller_mock_ expect] removeScriptMessageHandlerForName:name1_];
[[controller_mock_ expect] removeScriptMessageHandlerForName:name2_];
[router_ setScriptMessageHandler:handler1_ name:name1_ webView:web_view1_];
[router_ setScriptMessageHandler:handler2_ name:name2_ webView:web_view2_];
[router_ setScriptMessageHandler:handler3_ name:name2_ webView:web_view3_];
[router_ removeScriptMessageHandlerForName:name1_ webView:web_view1_];
[router_ removeScriptMessageHandlerForName:name2_ webView:web_view2_];
[router_ removeScriptMessageHandlerForName:name2_ webView:web_view3_];
}
// Tests registration of message handlers. Test ensures that
// WKScriptMessageHandler is not removed if CRWWKScriptMessageRouter has valid
// message handlers.
TEST_F(CRWWKScriptMessageRouterTest, HandlerRegistrationLeak) {
[[controller_mock_ expect] addScriptMessageHandler:router_ name:name1_];
// -removeScriptMessageHandlerForName must not be called.
[router_ setScriptMessageHandler:handler1_ name:name1_ webView:web_view1_];
[router_ setScriptMessageHandler:handler2_ name:name1_ webView:web_view2_];
[router_ removeScriptMessageHandlerForName:name1_ webView:web_view1_];
}
// Tests deregistation of all message handlers.
TEST_F(CRWWKScriptMessageRouterTest, RemoveAllHandlers) {
[[controller_mock_ expect] addScriptMessageHandler:router_ name:name1_];
[[controller_mock_ expect] addScriptMessageHandler:router_ name:name2_];
[[controller_mock_ expect] removeScriptMessageHandlerForName:name2_];
[[controller_mock_ expect] removeScriptMessageHandlerForName:name1_];
[router_ setScriptMessageHandler:handler1_ name:name1_ webView:web_view1_];
[router_ setScriptMessageHandler:handler2_ name:name2_ webView:web_view1_];
[router_ setScriptMessageHandler:handler3_ name:name1_ webView:web_view2_];
[router_ removeAllScriptMessageHandlersForWebView:web_view1_];
[router_ removeAllScriptMessageHandlersForWebView:web_view2_];
}
// Tests deregistation of all message handlers. Test ensures that
// WKScriptMessageHandler is not removed if CRWWKScriptMessageRouter has valid
// message handlers.
TEST_F(CRWWKScriptMessageRouterTest, RemoveAllHandlersLeak) {
[[controller_mock_ expect] addScriptMessageHandler:router_ name:name1_];
[[controller_mock_ expect] addScriptMessageHandler:router_ name:name2_];
[[controller_mock_ expect] addScriptMessageHandler:router_ name:name3_];
[[controller_mock_ expect] removeScriptMessageHandlerForName:name2_];
// -removeScriptMessageHandlerForName:name1_ must not be called.
[router_ setScriptMessageHandler:handler1_ name:name1_ webView:web_view1_];
[router_ setScriptMessageHandler:handler2_ name:name2_ webView:web_view1_];
[router_ setScriptMessageHandler:handler2_ name:name3_ webView:web_view2_];
[router_ setScriptMessageHandler:handler3_ name:name1_ webView:web_view2_];
[router_ removeAllScriptMessageHandlersForWebView:web_view1_];
}
// Tests proper routing of WKScriptMessage object depending on message name and
// web view.
TEST_F(CRWWKScriptMessageRouterTest, Routing) {
// It's expected that messages handlers will be called once and in order.
__block NSInteger last_called_handler = 0;
id message1 = GetScriptMessageMock(web_view1_, name1_);
id handler1 = ^(WKScriptMessage* message) {
EXPECT_EQ(0, last_called_handler);
EXPECT_EQ(message1, message);
last_called_handler = 1;
};
id message2 = GetScriptMessageMock(web_view2_, name2_);
id handler2 = ^(WKScriptMessage* message) {
EXPECT_EQ(1, last_called_handler);
EXPECT_EQ(message2, message);
last_called_handler = 2;
};
id message3 = GetScriptMessageMock(web_view3_, name2_);
id handler3 = ^(WKScriptMessage* message) {
EXPECT_EQ(2, last_called_handler);
EXPECT_EQ(message3, message);
last_called_handler = 3;
};
[[controller_mock_ expect] addScriptMessageHandler:router_ name:name1_];
[[controller_mock_ expect] addScriptMessageHandler:router_ name:name2_];
[router_ setScriptMessageHandler:handler1 name:name1_ webView:web_view1_];
[router_ setScriptMessageHandler:handler2 name:name2_ webView:web_view2_];
[router_ setScriptMessageHandler:handler3 name:name2_ webView:web_view3_];
[router_ userContentController:controller_mock_
didReceiveScriptMessage:message1];
[router_ userContentController:controller_mock_
didReceiveScriptMessage:message2];
[router_ userContentController:controller_mock_
didReceiveScriptMessage:message3];
EXPECT_EQ(3, last_called_handler);
}
} // namespace