Skip to content

Commit

Permalink
hasStrings Mac (#20531)
Browse files Browse the repository at this point in the history
Adds the hasStrings method for Mac, and improves the state of unit testing on Mac.
  • Loading branch information
justinmc committed Sep 15, 2020
1 parent 2a26bfb commit 3c9308f
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 4 deletions.
1 change: 1 addition & 0 deletions ci/licenses_golden/licenses_flutter
Expand Up @@ -1035,6 +1035,7 @@ FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterTextI
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterView.h
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterView.mm
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterViewController_Internal.h
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/fixtures/flutter_desktop_test.dart
FILE: ../../../flutter/shell/platform/darwin/macos/framework/module.modulemap
Expand Down
6 changes: 5 additions & 1 deletion shell/platform/darwin/macos/BUILD.gn
Expand Up @@ -101,7 +101,10 @@ test_fixtures("flutter_desktop_darwin_fixtures") {
executable("flutter_desktop_darwin_unittests") {
testonly = true

sources = [ "framework/Source/FlutterEngineUnittests.mm" ]
sources = [
"framework/Source/FlutterEngineUnittests.mm",
"framework/Source/FlutterViewControllerTest.mm",
]

cflags_objcc = [ "-fobjc-arc" ]

Expand All @@ -114,6 +117,7 @@ executable("flutter_desktop_darwin_unittests") {
"//flutter/testing:dart",
"//flutter/testing:skia",
"//flutter/testing:testing_lib",
"//third_party/ocmock:ocmock",
]
}

Expand Down
Expand Up @@ -173,6 +173,11 @@ - (NSDictionary*)getClipboardData:(NSString*)format;
*/
- (void)setClipboardData:(NSDictionary*)data;

/**
* Returns true iff the clipboard contains nonempty string data.
*/
- (BOOL)clipboardHasStrings;

@end

#pragma mark - FlutterViewController implementation.
Expand Down Expand Up @@ -505,6 +510,8 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
} else if ([call.method isEqualToString:@"Clipboard.setData"]) {
[self setClipboardData:call.arguments];
result(nil);
} else if ([call.method isEqualToString:@"Clipboard.hasStrings"]) {
result(@{@"value" : @([self clipboardHasStrings])});
} else {
result(FlutterMethodNotImplemented);
}
Expand All @@ -517,7 +524,7 @@ - (void)playSystemSound:(NSString*)soundType {
}

- (NSDictionary*)getClipboardData:(NSString*)format {
NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
NSPasteboard* pasteboard = self.pasteboard;
if ([format isEqualToString:@(kTextPlainFormat)]) {
NSString* stringInPasteboard = [pasteboard stringForType:NSPasteboardTypeString];
return stringInPasteboard == nil ? nil : @{@"text" : stringInPasteboard};
Expand All @@ -526,14 +533,22 @@ - (NSDictionary*)getClipboardData:(NSString*)format {
}

- (void)setClipboardData:(NSDictionary*)data {
NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
NSPasteboard* pasteboard = self.pasteboard;
NSString* text = data[@"text"];
[pasteboard clearContents];
if (text && ![text isEqual:[NSNull null]]) {
[pasteboard clearContents];
[pasteboard setString:text forType:NSPasteboardTypeString];
}
}

- (BOOL)clipboardHasStrings {
return [self.pasteboard stringForType:NSPasteboardTypeString].length > 0;
}

- (NSPasteboard*)pasteboard {
return [NSPasteboard generalPasteboard];
}

#pragma mark - FlutterViewReshapeListener

/**
Expand Down
@@ -0,0 +1,75 @@
// Copyright 2013 The Flutter 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 "flutter/shell/platform/darwin/macos/framework/Source/FlutterViewController_Internal.h"

#include "flutter/shell/platform/darwin/macos/framework/Headers/FlutterEngine.h"
#include "flutter/shell/platform/darwin/macos/framework/Source/FlutterDartProject_Internal.h"
#include "flutter/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h"
#include "flutter/testing/testing.h"
#import "third_party/ocmock/Source/OCMock/OCMock.h"

namespace flutter::testing {

// Returns a mock FlutterViewController that is able to work in environments
// without a real pasteboard.
id mockViewController(NSString* pasteboardString) {
NSString* fixtures = @(testing::GetFixturesPath());
FlutterDartProject* project = [[FlutterDartProject alloc]
initWithAssetsPath:fixtures
ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]];
FlutterViewController* viewController = [[FlutterViewController alloc] initWithProject:project];

// Mock pasteboard so that this test will work in environments without a
// real pasteboard.
id pasteboardMock = OCMClassMock([NSPasteboard class]);
OCMExpect([pasteboardMock stringForType:[OCMArg any]]).andDo(^(NSInvocation* invocation) {
NSString* returnValue = pasteboardString.length > 0 ? pasteboardString : nil;
[invocation setReturnValue:&returnValue];
});
id viewControllerMock = OCMPartialMock(viewController);
OCMStub([viewControllerMock pasteboard]).andReturn(pasteboardMock);
return viewControllerMock;
}

TEST(FlutterViewControllerTest, HasStringsWhenPasteboardEmpty) {
// Mock FlutterViewController so that it behaves like the pasteboard is empty.
id viewControllerMock = mockViewController(nil);

// Call hasStrings and expect it to be false.
__block bool calledAfterClear = false;
__block bool valueAfterClear;
FlutterResult resultAfterClear = ^(id result) {
calledAfterClear = true;
NSNumber* valueNumber = [result valueForKey:@"value"];
valueAfterClear = [valueNumber boolValue];
};
FlutterMethodCall* methodCallAfterClear =
[FlutterMethodCall methodCallWithMethodName:@"Clipboard.hasStrings" arguments:nil];
[viewControllerMock handleMethodCall:methodCallAfterClear result:resultAfterClear];
ASSERT_TRUE(calledAfterClear);
ASSERT_FALSE(valueAfterClear);
}

TEST(FlutterViewControllerTest, HasStringsWhenPasteboardFull) {
// Mock FlutterViewController so that it behaves like the pasteboard has a
// valid string.
id viewControllerMock = mockViewController(@"some string");

// Call hasStrings and expect it to be true.
__block bool called = false;
__block bool value;
FlutterResult result = ^(id result) {
called = true;
NSNumber* valueNumber = [result valueForKey:@"value"];
value = [valueNumber boolValue];
};
FlutterMethodCall* methodCall =
[FlutterMethodCall methodCallWithMethodName:@"Clipboard.hasStrings" arguments:nil];
[viewControllerMock handleMethodCall:methodCall result:result];
ASSERT_TRUE(called);
ASSERT_TRUE(value);
}

} // flutter::testing
Expand Up @@ -11,6 +11,11 @@
// The FlutterView for this view controller.
@property(nonatomic, readonly, nullable) FlutterView* flutterView;

/**
* This just returns the NSPasteboard so that it can be mocked in the tests.
*/
@property(nonatomic, readonly, nonnull) NSPasteboard* pasteboard;

/**
* Adds a responder for keyboard events. Key up and key down events are forwarded to all added
* responders.
Expand Down

0 comments on commit 3c9308f

Please sign in to comment.