-
Notifications
You must be signed in to change notification settings - Fork 6k
hasStrings Mac #20531
hasStrings Mac #20531
Changes from 22 commits
bb0f4be
97acb46
660092e
ffc7af4
98adfc9
59ad159
084c926
1a22b66
67f0173
6177e74
24d28c8
51280f2
a15798e
878aa78
c2bca18
54301f3
70286fc
6c778fe
b68a594
25385b5
45b81b4
2d0728d
3c9ec6e
a52595d
d14a117
3490d8a
e1566ac
491a585
8c2d240
06a6034
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -173,6 +173,15 @@ - (NSDictionary*)getClipboardData:(NSString*)format; | |
| */ | ||
| - (void)setClipboardData:(NSDictionary*)data; | ||
|
|
||
| /** | ||
| * Returns true iff the clipboard contains nonempty string data. | ||
| * | ||
| * See also: | ||
| * * https://developer.apple.com/documentation/uikit/uipasteboard/1829416-hasstrings, | ||
|
||
| * which is the equivalent method that Flutter utilizes in iOS. | ||
| */ | ||
| - (BOOL)clipboardHasStrings; | ||
|
|
||
| @end | ||
|
|
||
| #pragma mark - FlutterViewController implementation. | ||
|
|
@@ -505,6 +514,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); | ||
| } | ||
|
|
@@ -517,7 +528,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}; | ||
|
|
@@ -526,14 +537,24 @@ - (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 { | ||
| NSDictionary* data = [self getClipboardData:[NSString stringWithFormat:@"%s", kTextPlainFormat]]; | ||
| NSString* string = data[@"text"]; | ||
|
||
| return string.length > 0; | ||
| } | ||
|
|
||
| - (NSPasteboard*)_pasteboard { | ||
| return [NSPasteboard generalPasteboard]; | ||
| } | ||
|
|
||
| #pragma mark - FlutterViewReshapeListener | ||
|
|
||
| /** | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,98 @@ | ||
| // 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/Headers/FlutterViewController.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* 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]); | ||
| __block NSString* clipboardString = @""; | ||
| OCMStub([pasteboardMock setString:[OCMArg any] forType:[OCMArg any]]) | ||
| .andDo(^(NSInvocation* invocation) { | ||
| [invocation getArgument:&clipboardString atIndex:2]; | ||
| }); | ||
| OCMExpect([pasteboardMock stringForType:[OCMArg any]]).andDo(^(NSInvocation* invocation) { | ||
| [invocation setReturnValue:&clipboardString]; | ||
| }); | ||
| id viewControllerMock = OCMPartialMock(viewController); | ||
| OCMStub([viewControllerMock _pasteboard]).andReturn(pasteboardMock); | ||
| return viewControllerMock; | ||
| } | ||
|
|
||
| TEST(FlutterViewControllerTest, HasStringsWhenPasteboardEmpty) { | ||
| id viewControllerMock = mockViewController(); | ||
|
|
||
| // Call setData to make sure that the pasteboard is empty. | ||
|
||
| __block bool calledSetClear = false; | ||
| FlutterResult resultSetClear = ^(id result) { | ||
| calledSetClear = true; | ||
| }; | ||
| FlutterMethodCall* methodCallSetClear = | ||
| [FlutterMethodCall methodCallWithMethodName:@"Clipboard.setData" | ||
| arguments:@{@"text" : [NSNull null]}]; | ||
| [viewControllerMock handleMethodCall:methodCallSetClear result:resultSetClear]; | ||
| ASSERT_TRUE(calledSetClear); | ||
|
|
||
| // 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); | ||
| } | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This test is doing a lot of different things; please make individual tests that are more targeted. You're already using a fake pasteboard, so there's no need to do the entire cycle in a single test.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good call, I split it into two and it's a lot cleaner. |
||
|
|
||
| TEST(FlutterViewControllerTest, HasStringsWhenPasteboardFull) { | ||
| id viewControllerMock = mockViewController(); | ||
|
|
||
| // Call setClipboardData to make sure there's a string on the pasteboard. | ||
|
||
| __block bool calledSet = false; | ||
| FlutterResult resultSet = ^(id result) { | ||
| calledSet = true; | ||
| }; | ||
| FlutterMethodCall* methodCallSet = | ||
| [FlutterMethodCall methodCallWithMethodName:@"Clipboard.setData" | ||
| arguments:@{@"text" : @"some string"}]; | ||
| [viewControllerMock handleMethodCall:methodCallSet result:resultSet]; | ||
| ASSERT_TRUE(calledSet); | ||
|
|
||
| // 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 | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This still needs to be moved to the private header.
Also, a property name should not start with
_; the property and the ivar are distinct.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where exactly should this be moved to? Sorry for my lack of Objective C knowledge. I tried moving this inside the .mm file, but then I couldn't mock it from the test.
👍 About the underscore.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FlutterViewController_Internal.h
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah thanks, I missed that.
Though it seems to also give me errors when the test tries to mock it. I just copied this exactly over to the _Internal header. Is there something else I need to do to make it accessible to the test?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you include that header in the test file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That was it, thanks.