1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #if !defined(__has_feature) || !__has_feature(objc_arc)
6 #error "This file requires ARC support."
9 #import "remoting/ios/bridge/client_proxy.h"
11 #import "base/compiler_specific.h"
12 #import "testing/gtest_mac.h"
14 #import "remoting/ios/data_store.h"
15 #import "remoting/ios/bridge/client_proxy_delegate_wrapper.h"
17 @interface ClientProxyDelegateTester : NSObject<ClientProxyDelegate>
18 @property(nonatomic, assign) BOOL isConnected;
19 @property(nonatomic, copy) NSString* statusMessage;
20 @property(nonatomic, copy) NSString* errorMessage;
21 @property(nonatomic, assign) BOOL isPairingSupported;
22 @property(nonatomic, assign) webrtc::DesktopSize size;
23 @property(nonatomic, assign) NSInteger stride;
24 @property(nonatomic, assign) uint8_t* data;
25 @property(nonatomic, assign) std::vector<webrtc::DesktopRect> regions;
26 @property(nonatomic, assign) webrtc::DesktopVector hotspot;
29 @implementation ClientProxyDelegateTester
31 @synthesize isConnected = _isConnected;
32 @synthesize statusMessage = _statusMessage;
33 @synthesize errorMessage = _errorMessage;
34 @synthesize isPairingSupported = _isPairingSupported;
35 @synthesize size = _size;
36 @synthesize stride = _stride;
37 @synthesize data = _data;
38 @synthesize regions = _regions;
39 @synthesize hotspot = _hotspot;
45 - (void)connectionStatus:(NSString*)statusMessage {
46 _statusMessage = statusMessage;
49 - (void)connectionFailed:(NSString*)errorMessage {
50 _errorMessage = errorMessage;
53 - (void)requestHostPin:(BOOL)pairingSupported {
54 _isPairingSupported = pairingSupported;
57 - (void)applyFrame:(const webrtc::DesktopSize&)size
58 stride:(NSInteger)stride
60 regions:(const std::vector<webrtc::DesktopRect>&)regions {
64 _regions.assign(regions.begin(), regions.end());
67 - (void)applyCursor:(const webrtc::DesktopSize&)size
68 hotspot:(const webrtc::DesktopVector&)hotspot
69 cursorData:(uint8_t*)data {
81 NSString* kStatusINITIALIZING = @"Initializing connection";
82 NSString* kStatusCONNECTING = @"Connecting";
83 NSString* kStatusAUTHENTICATED = @"Authenticated";
84 NSString* kStatusCONNECTED = @"Connected";
85 NSString* kStatusFAILED = @"Connection Failed";
86 NSString* kStatusCLOSED = @"Connection closed";
87 NSString* kStatusDEFAULT = @"Unknown connection state";
89 NSString* kErrorPEER_IS_OFFLINE = @"Requested host is offline.";
90 NSString* kErrorSESSION_REJECTED = @"Session was rejected by the host.";
91 NSString* kErrorINCOMPATIBLE_PROTOCOL = @"Incompatible Protocol.";
92 NSString* kErrorAUTHENTICATION_FAILED = @"Authentication Failed.";
93 NSString* kErrorCHANNEL_CONNECTION_ERROR = @"Channel Connection Error";
94 NSString* kErrorSIGNALING_ERROR = @"Signaling Error";
95 NSString* kErrorSIGNALING_TIMEOUT = @"Signaling Timeout";
96 NSString* kErrorHOST_OVERLOAD = @"Host Overload";
97 NSString* kErrorUNKNOWN_ERROR =
98 @"An unknown error has occurred, preventing the session from opening.";
99 NSString* kErrorDEFAULT = @"An unknown error code has occurred.";
101 const webrtc::DesktopSize kFrameSize(100, 100);
103 // Note these are disjoint regions. Testing intersecting regions is beyond the
104 // scope of this test class.
105 const webrtc::DesktopRect kFrameSubRect1 =
106 webrtc::DesktopRect::MakeXYWH(0, 0, 10, 10);
107 const webrtc::DesktopRect kFrameSubRect2 =
108 webrtc::DesktopRect::MakeXYWH(11, 11, 10, 10);
109 const webrtc::DesktopRect kFrameSubRect3 =
110 webrtc::DesktopRect::MakeXYWH(22, 22, 10, 10);
112 const int kCursorHeight = 10;
113 const int kCursorWidth = 20;
114 const int kCursorHotSpotX = 4;
115 const int kCursorHotSpotY = 8;
116 // |kCursorDataLength| is assumed to be evenly divisible by 4
117 const int kCursorDataLength = kCursorHeight * kCursorWidth;
118 const uint32_t kCursorDataPattern = 0xF0E1D2C3;
120 const std::string kHostName = "ClientProxyHostNameTest";
121 const std::string kPairingId = "ClientProxyPairingIdTest";
122 const std::string kPairingSecret = "ClientProxyPairingSecretTest";
126 class ClientProxyTest : public ::testing::Test {
128 virtual void SetUp() OVERRIDE {
129 delegateTester_ = [[ClientProxyDelegateTester alloc] init];
130 clientProxy_.reset(new ClientProxy(
131 [ClientProxyDelegateWrapper wrapDelegate:delegateTester_]));
134 void ResetIsConnected() { delegateTester_.isConnected = false; }
136 void TestConnnectionStatus(protocol::ConnectionToHost::State state,
137 NSString* expectedStatusMsg) {
139 clientProxy_->ReportConnectionStatus(state, protocol::ErrorCode::OK);
140 EXPECT_NSEQ(expectedStatusMsg, delegateTester_.statusMessage);
142 if (state == protocol::ConnectionToHost::State::CONNECTED) {
143 EXPECT_TRUE(delegateTester_.isConnected);
145 EXPECT_FALSE(delegateTester_.isConnected);
148 TestErrorMessages(state, expectedStatusMsg);
151 void TestForError(protocol::ConnectionToHost::State state,
152 protocol::ErrorCode errorCode,
153 NSString* expectedStatusMsg,
154 NSString* expectedErrorMsg) {
156 clientProxy_->ReportConnectionStatus(state, errorCode);
157 EXPECT_FALSE(delegateTester_.isConnected);
158 EXPECT_NSEQ(expectedStatusMsg, delegateTester_.statusMessage);
159 EXPECT_NSEQ(expectedErrorMsg, delegateTester_.errorMessage);
162 void TestErrorMessages(protocol::ConnectionToHost::State state,
163 NSString* expectedStatusMsg) {
165 protocol::ErrorCode::AUTHENTICATION_FAILED,
167 kErrorAUTHENTICATION_FAILED);
169 protocol::ErrorCode::CHANNEL_CONNECTION_ERROR,
171 kErrorCHANNEL_CONNECTION_ERROR);
173 protocol::ErrorCode::HOST_OVERLOAD,
175 kErrorHOST_OVERLOAD);
177 protocol::ErrorCode::INCOMPATIBLE_PROTOCOL,
179 kErrorINCOMPATIBLE_PROTOCOL);
181 protocol::ErrorCode::PEER_IS_OFFLINE,
183 kErrorPEER_IS_OFFLINE);
185 protocol::ErrorCode::SESSION_REJECTED,
187 kErrorSESSION_REJECTED);
189 protocol::ErrorCode::SIGNALING_ERROR,
191 kErrorSIGNALING_ERROR);
193 protocol::ErrorCode::SIGNALING_TIMEOUT,
195 kErrorSIGNALING_TIMEOUT);
197 protocol::ErrorCode::UNKNOWN_ERROR,
199 kErrorUNKNOWN_ERROR);
201 static_cast<protocol::ErrorCode>(999),
206 void ValidateHost(const std::string& hostName,
207 const std::string& pairingId,
208 const std::string& pairingSecret) {
209 DataStore* store = [DataStore sharedStore];
210 NSString* hostNameAsNSString =
211 [NSString stringWithUTF8String:hostName.c_str()];
212 const HostPreferences* host = [store getHostForId:hostNameAsNSString];
214 [store removeHost:host];
217 clientProxy_->CommitPairingCredentials(hostName, pairingId, pairingSecret);
219 host = [store getHostForId:hostNameAsNSString];
221 ASSERT_TRUE(host != nil);
222 ASSERT_STREQ(hostName.c_str(), [host.hostId UTF8String]);
223 ASSERT_STREQ(pairingId.c_str(), [host.pairId UTF8String]);
224 ASSERT_STREQ(pairingSecret.c_str(), [host.pairSecret UTF8String]);
227 scoped_ptr<ClientProxy> clientProxy_;
228 ClientProxyDelegateTester* delegateTester_;
229 ClientProxyDelegateWrapper* delegateWrapper_;
232 TEST_F(ClientProxyTest, ReportConnectionStatusINITIALIZING) {
233 TestConnnectionStatus(protocol::ConnectionToHost::State::INITIALIZING,
234 kStatusINITIALIZING);
237 TEST_F(ClientProxyTest, ReportConnectionStatusCONNECTING) {
238 TestConnnectionStatus(protocol::ConnectionToHost::State::CONNECTING,
242 TEST_F(ClientProxyTest, ReportConnectionStatusAUTHENTICATED) {
243 TestConnnectionStatus(protocol::ConnectionToHost::State::AUTHENTICATED,
244 kStatusAUTHENTICATED);
247 TEST_F(ClientProxyTest, ReportConnectionStatusCONNECTED) {
248 TestConnnectionStatus(protocol::ConnectionToHost::State::CONNECTED,
252 TEST_F(ClientProxyTest, ReportConnectionStatusFAILED) {
253 TestConnnectionStatus(protocol::ConnectionToHost::State::FAILED,
257 TEST_F(ClientProxyTest, ReportConnectionStatusCLOSED) {
258 TestConnnectionStatus(protocol::ConnectionToHost::State::CLOSED,
262 TEST_F(ClientProxyTest, ReportConnectionStatusDEFAULT) {
263 TestConnnectionStatus(static_cast<protocol::ConnectionToHost::State>(999),
267 TEST_F(ClientProxyTest, DisplayAuthenticationPrompt) {
268 clientProxy_->DisplayAuthenticationPrompt(true);
269 ASSERT_TRUE(delegateTester_.isPairingSupported);
270 clientProxy_->DisplayAuthenticationPrompt(false);
271 ASSERT_FALSE(delegateTester_.isPairingSupported);
274 TEST_F(ClientProxyTest, CommitPairingCredentialsBasic) {
275 ValidateHost("", "", "");
278 TEST_F(ClientProxyTest, CommitPairingCredentialsExtended) {
279 ValidateHost(kHostName, kPairingId, kPairingSecret);
282 TEST_F(ClientProxyTest, RedrawCanvasBasic) {
284 webrtc::BasicDesktopFrame frame(webrtc::DesktopSize(1, 1));
285 webrtc::DesktopRegion regions;
286 regions.AddRect(webrtc::DesktopRect::MakeLTRB(0, 0, 1, 1));
288 clientProxy_->RedrawCanvas(webrtc::DesktopSize(1, 1), &frame, regions);
290 ASSERT_TRUE(webrtc::DesktopSize(1, 1).equals(delegateTester_.size));
291 ASSERT_EQ(4, delegateTester_.stride);
292 ASSERT_TRUE(delegateTester_.data != NULL);
293 ASSERT_EQ(1, delegateTester_.regions.size());
294 ASSERT_TRUE(delegateTester_.regions[0].equals(
295 webrtc::DesktopRect::MakeLTRB(0, 0, 1, 1)));
297 TEST_F(ClientProxyTest, RedrawCanvasExtended) {
299 webrtc::BasicDesktopFrame frame(kFrameSize);
300 webrtc::DesktopRegion regions;
301 regions.AddRect(kFrameSubRect1);
302 regions.AddRect(kFrameSubRect2);
303 regions.AddRect(kFrameSubRect3);
305 clientProxy_->RedrawCanvas(kFrameSize, &frame, regions);
307 ASSERT_TRUE(kFrameSize.equals(delegateTester_.size));
308 ASSERT_EQ(kFrameSize.width() * webrtc::DesktopFrame::kBytesPerPixel,
309 delegateTester_.stride);
310 ASSERT_TRUE(delegateTester_.data != NULL);
311 ASSERT_EQ(3, delegateTester_.regions.size());
312 ASSERT_TRUE(delegateTester_.regions[0].equals(kFrameSubRect1));
313 ASSERT_TRUE(delegateTester_.regions[1].equals(kFrameSubRect2));
314 ASSERT_TRUE(delegateTester_.regions[2].equals(kFrameSubRect3));
317 TEST_F(ClientProxyTest, UpdateCursorBasic) {
318 protocol::CursorShapeInfo cursor_proto;
319 cursor_proto.set_width(1);
320 cursor_proto.set_height(1);
321 cursor_proto.set_hotspot_x(0);
322 cursor_proto.set_hotspot_y(0);
325 memset(data, 0xFF, 4);
327 cursor_proto.set_data(data);
329 clientProxy_->UpdateCursorShape(cursor_proto);
331 ASSERT_EQ(1, delegateTester_.size.width());
332 ASSERT_EQ(1, delegateTester_.size.height());
333 ASSERT_EQ(0, delegateTester_.hotspot.x());
334 ASSERT_EQ(0, delegateTester_.hotspot.y());
335 ASSERT_TRUE(delegateTester_.data != NULL);
336 for (int i = 0; i < 4; i++) {
337 ASSERT_EQ(0xFF, delegateTester_.data[i]);
341 TEST_F(ClientProxyTest, UpdateCursorExtended) {
342 protocol::CursorShapeInfo cursor_proto;
343 cursor_proto.set_width(kCursorWidth);
344 cursor_proto.set_height(kCursorHeight);
345 cursor_proto.set_hotspot_x(kCursorHotSpotX);
346 cursor_proto.set_hotspot_y(kCursorHotSpotY);
348 char data[kCursorDataLength];
349 memset_pattern4(data, &kCursorDataPattern, kCursorDataLength);
351 cursor_proto.set_data(data);
353 clientProxy_->UpdateCursorShape(cursor_proto);
355 ASSERT_EQ(kCursorWidth, delegateTester_.size.width());
356 ASSERT_EQ(kCursorHeight, delegateTester_.size.height());
357 ASSERT_EQ(kCursorHotSpotX, delegateTester_.hotspot.x());
358 ASSERT_EQ(kCursorHotSpotY, delegateTester_.hotspot.y());
359 ASSERT_TRUE(delegateTester_.data != NULL);
360 for (int i = 0; i < kCursorDataLength / 4; i++) {
361 ASSERT_TRUE(memcmp(&delegateTester_.data[i * 4], &kCursorDataPattern, 4) ==
366 } // namespace remoting