From bb0f4beed256923c858c32defd6792dab4d9bdf6 Mon Sep 17 00:00:00 2001 From: Justin McCandless Date: Fri, 14 Aug 2020 15:44:36 -0700 Subject: [PATCH 01/25] hasStrings on mac --- .../framework/Source/FlutterViewController.mm | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm b/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm index b1a6055e28f70..1112618f5387b 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm @@ -173,6 +173,14 @@ - (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 + */ +- (NSDictionary*)clipboardHasStrings; + @end #pragma mark - FlutterViewController implementation. @@ -505,6 +513,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([self clipboardHasStrings]); } else { result(FlutterMethodNotImplemented); } @@ -527,13 +537,24 @@ - (NSDictionary*)getClipboardData:(NSString*)format { - (void)setClipboardData:(NSDictionary*)data { NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; - NSString* text = data[@"text"]; + NSString *text = data[@"text"]; if (text && ![text isEqual:[NSNull null]]) { [pasteboard clearContents]; [pasteboard setString:text forType:NSPasteboardTypeString]; } } +- (NSDictionary*)clipboardHasStrings { + NSDictionary* data = [self getClipboardData:[NSString stringWithFormat:@"%s", kTextPlainFormat]]; + NSString* string = data[@"text"]; + BOOL hasStrings = string.length > 0; + return @{@"value" : @(hasStrings)}; + /* + UIPasteboard* pasteboard = [UIPasteboard generalPasteboard]; + return @{@"value" : @(pasteboard.hasStrings)}; + */ +} + #pragma mark - FlutterViewReshapeListener /** From 97acb46d469500f8bf018336e245bd5d6d496f9b Mon Sep 17 00:00:00 2001 From: Justin McCandless Date: Fri, 14 Aug 2020 17:08:11 -0700 Subject: [PATCH 02/25] WIP test --- ci/licenses_golden/licenses_flutter | 1 + shell/platform/darwin/macos/BUILD.gn | 5 +++- .../Source/FlutterViewControllerTest.mm | 26 +++++++++++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 3264b905c063d..07ceb8c056960 100755 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1027,6 +1027,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 diff --git a/shell/platform/darwin/macos/BUILD.gn b/shell/platform/darwin/macos/BUILD.gn index bacb6af24a1b2..ff129dd3d019e 100644 --- a/shell/platform/darwin/macos/BUILD.gn +++ b/shell/platform/darwin/macos/BUILD.gn @@ -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" ] diff --git a/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm b/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm new file mode 100644 index 0000000000000..3c621b3808c00 --- /dev/null +++ b/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm @@ -0,0 +1,26 @@ +// 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. + +#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" + +namespace flutter::testing { + +// TODO(justinmc): This is just copied from FlutterEngineUnittests. +TEST(FlutterViewControllerTest, MacOSTestTest) { + NSString* fixtures = @(testing::GetFixturesPath()); + FlutterDartProject* project = [[FlutterDartProject alloc] + initWithAssetsPath:fixtures + ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]]; + FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" + project:project + allowHeadlessExecution:true]; + ASSERT_TRUE([engine runWithEntrypoint:@"main"]); + ASSERT_TRUE(engine.running); + [engine shutDownEngine]; +} + +} // flutter::testing From 660092ee186006b790faa07870b77688e48b4ca1 Mon Sep 17 00:00:00 2001 From: Justin McCandless Date: Thu, 27 Aug 2020 14:25:38 -0700 Subject: [PATCH 03/25] Clean up and remove test since unit testing on mac not set up? --- .../framework/Source/FlutterViewController.mm | 6 +---- .../Source/FlutterViewControllerTest.mm | 26 ------------------- 2 files changed, 1 insertion(+), 31 deletions(-) delete mode 100644 shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm diff --git a/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm b/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm index 1112618f5387b..dc63b50c8165a 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm @@ -537,7 +537,7 @@ - (NSDictionary*)getClipboardData:(NSString*)format { - (void)setClipboardData:(NSDictionary*)data { NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; - NSString *text = data[@"text"]; + NSString* text = data[@"text"]; if (text && ![text isEqual:[NSNull null]]) { [pasteboard clearContents]; [pasteboard setString:text forType:NSPasteboardTypeString]; @@ -549,10 +549,6 @@ - (NSDictionary*)clipboardHasStrings { NSString* string = data[@"text"]; BOOL hasStrings = string.length > 0; return @{@"value" : @(hasStrings)}; - /* - UIPasteboard* pasteboard = [UIPasteboard generalPasteboard]; - return @{@"value" : @(pasteboard.hasStrings)}; - */ } #pragma mark - FlutterViewReshapeListener diff --git a/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm b/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm deleted file mode 100644 index 3c621b3808c00..0000000000000 --- a/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm +++ /dev/null @@ -1,26 +0,0 @@ -// 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. - -#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" - -namespace flutter::testing { - -// TODO(justinmc): This is just copied from FlutterEngineUnittests. -TEST(FlutterViewControllerTest, MacOSTestTest) { - NSString* fixtures = @(testing::GetFixturesPath()); - FlutterDartProject* project = [[FlutterDartProject alloc] - initWithAssetsPath:fixtures - ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]]; - FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test" - project:project - allowHeadlessExecution:true]; - ASSERT_TRUE([engine runWithEntrypoint:@"main"]); - ASSERT_TRUE(engine.running); - [engine shutDownEngine]; -} - -} // flutter::testing From ffc7af48cef3608789b948baa9d35e4b75a5db3e Mon Sep 17 00:00:00 2001 From: Justin McCandless Date: Mon, 31 Aug 2020 11:23:17 -0700 Subject: [PATCH 04/25] Test hasStrings --- .../framework/Headers/FlutterViewController.h | 2 + .../Source/FlutterViewControllerTest.mm | 46 +++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm diff --git a/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h b/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h index b32af0ac32644..d3d05959e1002 100644 --- a/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h +++ b/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h @@ -53,4 +53,6 @@ FLUTTER_EXPORT NS_DESIGNATED_INITIALIZER; - (nonnull instancetype)initWithCoder:(nonnull NSCoder*)nibNameOrNil NS_DESIGNATED_INITIALIZER; +- (void)handleMethodCall:(nonnull FlutterMethodCall*)call result:(nonnull FlutterResult)result; + @end diff --git a/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm b/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm new file mode 100644 index 0000000000000..5c3b1b9098ccd --- /dev/null +++ b/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm @@ -0,0 +1,46 @@ +// 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. + +#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" +#import "flutter/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h" +#include "flutter/testing/testing.h" + +namespace flutter::testing { + +TEST(FlutterViewControllerTest, MacOSTestTest) { + NSString* fixtures = @(testing::GetFixturesPath()); + FlutterDartProject* project = [[FlutterDartProject alloc] + initWithAssetsPath:fixtures + ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]]; + FlutterViewController* viewController = [[FlutterViewController alloc] initWithProject:project]; + + // First call setClipboardData to put a string on the pasteboard. + __block bool calledSet = false; + FlutterResult resultSet = ^(id result) { + calledSet = true; + }; + FlutterMethodCall* methodCallSet = + [FlutterMethodCall methodCallWithMethodName:@"Clipboard.setClipboardData" + arguments:@{@"text" : @"some string"}]; + [viewController 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; + value = result[@"value"]; + }; + FlutterMethodCall* methodCall = + [FlutterMethodCall methodCallWithMethodName:@"Clipboard.hasStrings" + arguments:nil]; + [viewController handleMethodCall:methodCall result:result]; + ASSERT_TRUE(called); + ASSERT_TRUE(value); +} + +} // flutter::testing From 98adfc9c15b46006ee89018ac530db776112a387 Mon Sep 17 00:00:00 2001 From: Justin McCandless Date: Mon, 31 Aug 2020 14:04:49 -0700 Subject: [PATCH 05/25] Test hasStrings after clearing the clipboard as well --- .../framework/Source/FlutterViewController.mm | 2 +- .../Source/FlutterViewControllerTest.mm | 31 +++++++++++++++++-- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm b/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm index dc63b50c8165a..1865197e6f6b3 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm @@ -538,8 +538,8 @@ - (NSDictionary*)getClipboardData:(NSString*)format { - (void)setClipboardData:(NSDictionary*)data { NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; NSString* text = data[@"text"]; + [pasteboard clearContents]; if (text && ![text isEqual:[NSNull null]]) { - [pasteboard clearContents]; [pasteboard setString:text forType:NSPasteboardTypeString]; } } diff --git a/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm b/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm index 5c3b1b9098ccd..94687bd1afb32 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm @@ -23,7 +23,7 @@ calledSet = true; }; FlutterMethodCall* methodCallSet = - [FlutterMethodCall methodCallWithMethodName:@"Clipboard.setClipboardData" + [FlutterMethodCall methodCallWithMethodName:@"Clipboard.setData" arguments:@{@"text" : @"some string"}]; [viewController handleMethodCall:methodCallSet result:resultSet]; ASSERT_TRUE(calledSet); @@ -33,7 +33,8 @@ __block bool value; FlutterResult result = ^(id result) { called = true; - value = result[@"value"]; + NSNumber *valueNumber = [result valueForKey:@"value"]; + value = [valueNumber boolValue]; }; FlutterMethodCall* methodCall = [FlutterMethodCall methodCallWithMethodName:@"Clipboard.hasStrings" @@ -41,6 +42,32 @@ [viewController handleMethodCall:methodCall result:result]; ASSERT_TRUE(called); ASSERT_TRUE(value); + + // Now call setData again to clear the pasteboard. + __block bool calledSetClear = false; + FlutterResult resultSetClear = ^(id result) { + calledSetClear = true; + }; + FlutterMethodCall* methodCallSetClear = + [FlutterMethodCall methodCallWithMethodName:@"Clipboard.setData" + arguments:@{@"text" : [NSNull null]}]; + [viewController 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]; + [viewController handleMethodCall:methodCallAfterClear result:resultAfterClear]; + ASSERT_TRUE(calledAfterClear); + ASSERT_FALSE(valueAfterClear); } } // flutter::testing From 59ad15964028ee4d725a4ae20e0f6ee204143c77 Mon Sep 17 00:00:00 2001 From: Justin McCandless Date: Mon, 31 Aug 2020 14:07:35 -0700 Subject: [PATCH 06/25] Run Mac unit tests in run_tests.py --- testing/run_tests.py | 1 + 1 file changed, 1 insertion(+) diff --git a/testing/run_tests.py b/testing/run_tests.py index 002fb6e0fb6c1..5a0bc2c7634fc 100755 --- a/testing/run_tests.py +++ b/testing/run_tests.py @@ -146,6 +146,7 @@ def RunCCTests(build_dir, filter): # These unit-tests are Objective-C and can only run on Darwin. if IsMac(): RunEngineExecutable(build_dir, 'flutter_channels_unittests', filter, shuffle_flags) + RunEngineExecutable(build_dir, 'flutter_desktop_darwin_unittests', filter, shuffle_flags) # https://github.com/flutter/flutter/issues/36296 if IsLinux(): From 084c9266326727cccddda16afa1b752220399a2f Mon Sep 17 00:00:00 2001 From: Justin McCandless Date: Mon, 31 Aug 2020 14:14:41 -0700 Subject: [PATCH 07/25] Formatting --- .../framework/Source/FlutterViewControllerTest.mm | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm b/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm index 94687bd1afb32..38bd0e628a301 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm @@ -3,9 +3,9 @@ // found in the LICENSE file. #include "flutter/shell/platform/darwin/macos/framework/Headers/FlutterEngine.h" +#import "flutter/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h" #include "flutter/shell/platform/darwin/macos/framework/Source/FlutterDartProject_Internal.h" #include "flutter/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h" -#import "flutter/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h" #include "flutter/testing/testing.h" namespace flutter::testing { @@ -33,12 +33,11 @@ __block bool value; FlutterResult result = ^(id result) { called = true; - NSNumber *valueNumber = [result valueForKey:@"value"]; + NSNumber* valueNumber = [result valueForKey:@"value"]; value = [valueNumber boolValue]; }; FlutterMethodCall* methodCall = - [FlutterMethodCall methodCallWithMethodName:@"Clipboard.hasStrings" - arguments:nil]; + [FlutterMethodCall methodCallWithMethodName:@"Clipboard.hasStrings" arguments:nil]; [viewController handleMethodCall:methodCall result:result]; ASSERT_TRUE(called); ASSERT_TRUE(value); @@ -59,12 +58,11 @@ __block bool valueAfterClear; FlutterResult resultAfterClear = ^(id result) { calledAfterClear = true; - NSNumber *valueNumber = [result valueForKey:@"value"]; + NSNumber* valueNumber = [result valueForKey:@"value"]; valueAfterClear = [valueNumber boolValue]; }; FlutterMethodCall* methodCallAfterClear = - [FlutterMethodCall methodCallWithMethodName:@"Clipboard.hasStrings" - arguments:nil]; + [FlutterMethodCall methodCallWithMethodName:@"Clipboard.hasStrings" arguments:nil]; [viewController handleMethodCall:methodCallAfterClear result:resultAfterClear]; ASSERT_TRUE(calledAfterClear); ASSERT_FALSE(valueAfterClear); From 1a22b66e54908d55514222d351f7f72ecd0e1c27 Mon Sep 17 00:00:00 2001 From: Justin McCandless Date: Mon, 31 Aug 2020 14:26:18 -0700 Subject: [PATCH 08/25] Build.gn formatting --- shell/platform/darwin/macos/BUILD.gn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell/platform/darwin/macos/BUILD.gn b/shell/platform/darwin/macos/BUILD.gn index ff129dd3d019e..7c19a694e21f6 100644 --- a/shell/platform/darwin/macos/BUILD.gn +++ b/shell/platform/darwin/macos/BUILD.gn @@ -103,7 +103,7 @@ executable("flutter_desktop_darwin_unittests") { sources = [ "framework/Source/FlutterEngineUnittests.mm", - "framework/Source/FlutterViewControllerTest.mm" + "framework/Source/FlutterViewControllerTest.mm", ] cflags_objcc = [ "-fobjc-arc" ] From 67f0173d9d60cadfe97567cc7e6a090648cbb0e0 Mon Sep 17 00:00:00 2001 From: Justin McCandless Date: Mon, 31 Aug 2020 17:13:28 -0700 Subject: [PATCH 09/25] Test name --- .../darwin/macos/framework/Source/FlutterViewControllerTest.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm b/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm index 38bd0e628a301..dd2bb89af277e 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm @@ -10,7 +10,7 @@ namespace flutter::testing { -TEST(FlutterViewControllerTest, MacOSTestTest) { +TEST(FlutterViewControllerTest, HasStrings) { NSString* fixtures = @(testing::GetFixturesPath()); FlutterDartProject* project = [[FlutterDartProject alloc] initWithAssetsPath:fixtures From 6177e74e218c32c7fc98264a8281b849faa67e4e Mon Sep 17 00:00:00 2001 From: Justin McCandless Date: Wed, 2 Sep 2020 10:11:14 -0700 Subject: [PATCH 10/25] WIP trying to get ocmock to work in Mac --- shell/platform/darwin/macos/BUILD.gn | 1 + .../macos/framework/Source/FlutterViewControllerTest.mm | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/shell/platform/darwin/macos/BUILD.gn b/shell/platform/darwin/macos/BUILD.gn index 7c19a694e21f6..0eb36f594a56a 100644 --- a/shell/platform/darwin/macos/BUILD.gn +++ b/shell/platform/darwin/macos/BUILD.gn @@ -117,6 +117,7 @@ executable("flutter_desktop_darwin_unittests") { "//flutter/testing:dart", "//flutter/testing:skia", "//flutter/testing:testing_lib", + "//third_party/ocmock:ocmock", ] } diff --git a/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm b/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm index dd2bb89af277e..d917e63e40279 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#import "third_party/ocmock/Source/OCMock/OCMock.h" #include "flutter/shell/platform/darwin/macos/framework/Headers/FlutterEngine.h" #import "flutter/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h" #include "flutter/shell/platform/darwin/macos/framework/Source/FlutterDartProject_Internal.h" @@ -17,6 +18,12 @@ ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]]; FlutterViewController* viewController = [[FlutterViewController alloc] initWithProject:project]; + // Mock getPasteboard so that this test will work in environments without a + // real pasteboard. + // TODO(justinmc): Mock pasteboard, once OCMock works here. + id pasteboardMock = OCMClassMock([NSPasteboard class]); + OCMStub([pasteboardMock setString:[OCMArg any] forType:[OCMArg any]]); + // First call setClipboardData to put a string on the pasteboard. __block bool calledSet = false; FlutterResult resultSet = ^(id result) { From 24d28c8f0dc96315ad32add1b2149c490dc0e126 Mon Sep 17 00:00:00 2001 From: Justin McCandless Date: Wed, 2 Sep 2020 17:08:48 -0700 Subject: [PATCH 11/25] Use new ocmock target coming in buildroot PR --- shell/platform/darwin/macos/BUILD.gn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell/platform/darwin/macos/BUILD.gn b/shell/platform/darwin/macos/BUILD.gn index 0eb36f594a56a..41259454ed0f9 100644 --- a/shell/platform/darwin/macos/BUILD.gn +++ b/shell/platform/darwin/macos/BUILD.gn @@ -117,7 +117,7 @@ executable("flutter_desktop_darwin_unittests") { "//flutter/testing:dart", "//flutter/testing:skia", "//flutter/testing:testing_lib", - "//third_party/ocmock:ocmock", + "//third_party/ocmock:ocmock_src", ] } From 51280f22504a2e7151d410f8160ab4d5eecd1a6f Mon Sep 17 00:00:00 2001 From: Justin McCandless Date: Wed, 2 Sep 2020 18:13:19 -0700 Subject: [PATCH 12/25] Mocked pasteboard working --- .../framework/Headers/FlutterViewController.h | 2 ++ .../framework/Source/FlutterViewController.mm | 9 ++++++-- .../Source/FlutterViewControllerTest.mm | 21 +++++++++++++------ 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h b/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h index d3d05959e1002..ecb4b232ad419 100644 --- a/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h +++ b/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h @@ -55,4 +55,6 @@ FLUTTER_EXPORT - (void)handleMethodCall:(nonnull FlutterMethodCall*)call result:(nonnull FlutterResult)result; +- (nonnull NSPasteboard*)getPasteboard; + @end diff --git a/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm b/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm index 1865197e6f6b3..7a0b16494787d 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm @@ -527,7 +527,7 @@ - (void)playSystemSound:(NSString*)soundType { } - (NSDictionary*)getClipboardData:(NSString*)format { - NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; + NSPasteboard* pasteboard = [self getPasteboard]; if ([format isEqualToString:@(kTextPlainFormat)]) { NSString* stringInPasteboard = [pasteboard stringForType:NSPasteboardTypeString]; return stringInPasteboard == nil ? nil : @{@"text" : stringInPasteboard}; @@ -536,7 +536,7 @@ - (NSDictionary*)getClipboardData:(NSString*)format { } - (void)setClipboardData:(NSDictionary*)data { - NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; + NSPasteboard* pasteboard = [self getPasteboard]; NSString* text = data[@"text"]; [pasteboard clearContents]; if (text && ![text isEqual:[NSNull null]]) { @@ -551,6 +551,11 @@ - (NSDictionary*)clipboardHasStrings { return @{@"value" : @(hasStrings)}; } +// This is a separate method to allow mocking the pasteboard in the tests. +- (NSPasteboard*)getPasteboard { + return [NSPasteboard generalPasteboard]; +} + #pragma mark - FlutterViewReshapeListener /** diff --git a/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm b/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm index d917e63e40279..e36ff75d266cd 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm @@ -20,9 +20,18 @@ // Mock getPasteboard so that this test will work in environments without a // real pasteboard. - // TODO(justinmc): Mock pasteboard, once OCMock works here. id pasteboardMock = OCMClassMock([NSPasteboard class]); - OCMStub([pasteboardMock setString:[OCMArg any] forType:[OCMArg any]]); + __block NSString* clipboardString = @""; + void (^setStringMock)(NSInvocation*) = ^(NSInvocation *invocation) { + [invocation getArgument:&clipboardString atIndex:2]; + }; + OCMStub([pasteboardMock setString:[OCMArg any] forType:[OCMArg any]]).andDo(setStringMock); + void (^stringForTypeMock)(NSInvocation*) = ^(NSInvocation *invocation) { + [invocation setReturnValue:&clipboardString]; + }; + OCMExpect([pasteboardMock stringForType:[OCMArg any]]).andDo(stringForTypeMock); + id viewControllerMock = OCMPartialMock(viewController); + OCMStub([viewControllerMock getPasteboard]).andReturn(pasteboardMock); // First call setClipboardData to put a string on the pasteboard. __block bool calledSet = false; @@ -32,7 +41,7 @@ FlutterMethodCall* methodCallSet = [FlutterMethodCall methodCallWithMethodName:@"Clipboard.setData" arguments:@{@"text" : @"some string"}]; - [viewController handleMethodCall:methodCallSet result:resultSet]; + [viewControllerMock handleMethodCall:methodCallSet result:resultSet]; ASSERT_TRUE(calledSet); // Call hasStrings and expect it to be true. @@ -45,7 +54,7 @@ }; FlutterMethodCall* methodCall = [FlutterMethodCall methodCallWithMethodName:@"Clipboard.hasStrings" arguments:nil]; - [viewController handleMethodCall:methodCall result:result]; + [viewControllerMock handleMethodCall:methodCall result:result]; ASSERT_TRUE(called); ASSERT_TRUE(value); @@ -57,7 +66,7 @@ FlutterMethodCall* methodCallSetClear = [FlutterMethodCall methodCallWithMethodName:@"Clipboard.setData" arguments:@{@"text" : [NSNull null]}]; - [viewController handleMethodCall:methodCallSetClear result:resultSetClear]; + [viewControllerMock handleMethodCall:methodCallSetClear result:resultSetClear]; ASSERT_TRUE(calledSetClear); // Call hasStrings and expect it to be false. @@ -70,7 +79,7 @@ }; FlutterMethodCall* methodCallAfterClear = [FlutterMethodCall methodCallWithMethodName:@"Clipboard.hasStrings" arguments:nil]; - [viewController handleMethodCall:methodCallAfterClear result:resultAfterClear]; + [viewControllerMock handleMethodCall:methodCallAfterClear result:resultAfterClear]; ASSERT_TRUE(calledAfterClear); ASSERT_FALSE(valueAfterClear); } From a15798eed8b239556601262ef518c16983f719b5 Mon Sep 17 00:00:00 2001 From: Justin McCandless Date: Thu, 3 Sep 2020 11:26:21 -0700 Subject: [PATCH 13/25] handleMethodCall removed from header and pasteboard moved to property getter --- .../macos/framework/Headers/FlutterViewController.h | 10 ++++++---- .../macos/framework/Source/FlutterViewController.mm | 7 +++---- .../framework/Source/FlutterViewControllerTest.mm | 4 ++-- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h b/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h index ecb4b232ad419..e0734c5b62c33 100644 --- a/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h +++ b/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h @@ -39,6 +39,12 @@ FLUTTER_EXPORT */ @property(nonatomic) FlutterMouseTrackingMode mouseTrackingMode; +/** + * This just returns the NSPasteboard. Using a property allows + * this to be mocked in the tests. +*/ +@property(nonatomic, readonly, nonnull) NSPasteboard* _pasteboard; + /** * Initializes a controller that will run the given project. * @@ -53,8 +59,4 @@ FLUTTER_EXPORT NS_DESIGNATED_INITIALIZER; - (nonnull instancetype)initWithCoder:(nonnull NSCoder*)nibNameOrNil NS_DESIGNATED_INITIALIZER; -- (void)handleMethodCall:(nonnull FlutterMethodCall*)call result:(nonnull FlutterResult)result; - -- (nonnull NSPasteboard*)getPasteboard; - @end diff --git a/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm b/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm index 7a0b16494787d..056a71719da4b 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm @@ -527,7 +527,7 @@ - (void)playSystemSound:(NSString*)soundType { } - (NSDictionary*)getClipboardData:(NSString*)format { - NSPasteboard* pasteboard = [self getPasteboard]; + NSPasteboard* pasteboard = [self _pasteboard]; if ([format isEqualToString:@(kTextPlainFormat)]) { NSString* stringInPasteboard = [pasteboard stringForType:NSPasteboardTypeString]; return stringInPasteboard == nil ? nil : @{@"text" : stringInPasteboard}; @@ -536,7 +536,7 @@ - (NSDictionary*)getClipboardData:(NSString*)format { } - (void)setClipboardData:(NSDictionary*)data { - NSPasteboard* pasteboard = [self getPasteboard]; + NSPasteboard* pasteboard = [self _pasteboard]; NSString* text = data[@"text"]; [pasteboard clearContents]; if (text && ![text isEqual:[NSNull null]]) { @@ -551,8 +551,7 @@ - (NSDictionary*)clipboardHasStrings { return @{@"value" : @(hasStrings)}; } -// This is a separate method to allow mocking the pasteboard in the tests. -- (NSPasteboard*)getPasteboard { +- (NSPasteboard*)_pasteboard { return [NSPasteboard generalPasteboard]; } diff --git a/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm b/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm index e36ff75d266cd..f3776198b2d29 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm @@ -18,7 +18,7 @@ ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]]; FlutterViewController* viewController = [[FlutterViewController alloc] initWithProject:project]; - // Mock getPasteboard so that this test will work in environments without a + // Mock _pasteboard so that this test will work in environments without a // real pasteboard. id pasteboardMock = OCMClassMock([NSPasteboard class]); __block NSString* clipboardString = @""; @@ -31,7 +31,7 @@ }; OCMExpect([pasteboardMock stringForType:[OCMArg any]]).andDo(stringForTypeMock); id viewControllerMock = OCMPartialMock(viewController); - OCMStub([viewControllerMock getPasteboard]).andReturn(pasteboardMock); + OCMStub([viewControllerMock _pasteboard]).andReturn(pasteboardMock); // First call setClipboardData to put a string on the pasteboard. __block bool calledSet = false; From 878aa78cd98a418b13a917552dea0ac1934723bd Mon Sep 17 00:00:00 2001 From: Justin McCandless Date: Thu, 3 Sep 2020 11:38:36 -0700 Subject: [PATCH 14/25] Docs clarification --- .../darwin/macos/framework/Source/FlutterViewController.mm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm b/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm index 056a71719da4b..cb9d2fa3d54c6 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm @@ -177,7 +177,8 @@ - (void)setClipboardData:(NSDictionary*)data; * Returns true iff the clipboard contains nonempty string data. * * See also: - * * https://developer.apple.com/documentation/uikit/uipasteboard/1829416-hasstrings + * * https://developer.apple.com/documentation/uikit/uipasteboard/1829416-hasstrings, + * which is the equivalent method that Flutter utilizes in iOS. */ - (NSDictionary*)clipboardHasStrings; From c2bca18c19faf31b39197df4b6083da70a1706ed Mon Sep 17 00:00:00 2001 From: Justin McCandless Date: Thu, 3 Sep 2020 11:43:52 -0700 Subject: [PATCH 15/25] clipboardHasStrings returns a bool, caller handles dictionary --- .../macos/framework/Source/FlutterViewController.mm | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm b/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm index cb9d2fa3d54c6..aa87583f04d6f 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm @@ -180,7 +180,7 @@ - (void)setClipboardData:(NSDictionary*)data; * * https://developer.apple.com/documentation/uikit/uipasteboard/1829416-hasstrings, * which is the equivalent method that Flutter utilizes in iOS. */ -- (NSDictionary*)clipboardHasStrings; +- (BOOL)clipboardHasStrings; @end @@ -515,7 +515,7 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { [self setClipboardData:call.arguments]; result(nil); } else if ([call.method isEqualToString:@"Clipboard.hasStrings"]) { - result([self clipboardHasStrings]); + result(@{@"value" : @([self clipboardHasStrings])}); } else { result(FlutterMethodNotImplemented); } @@ -545,11 +545,10 @@ - (void)setClipboardData:(NSDictionary*)data { } } -- (NSDictionary*)clipboardHasStrings { +- (BOOL)clipboardHasStrings { NSDictionary* data = [self getClipboardData:[NSString stringWithFormat:@"%s", kTextPlainFormat]]; NSString* string = data[@"text"]; - BOOL hasStrings = string.length > 0; - return @{@"value" : @(hasStrings)}; + return string.length > 0; } - (NSPasteboard*)_pasteboard { From 54301f3b8a5da36fc0e837384e737d055dd98fa9 Mon Sep 17 00:00:00 2001 From: Justin McCandless Date: Thu, 3 Sep 2020 12:07:57 -0700 Subject: [PATCH 16/25] Split tests and some cleanup --- .../Source/FlutterViewControllerTest.mm | 86 ++++++++++++------- 1 file changed, 53 insertions(+), 33 deletions(-) diff --git a/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm b/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm index f3776198b2d29..6e1b7769e7fa3 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm @@ -2,16 +2,17 @@ // 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" + #import "third_party/ocmock/Source/OCMock/OCMock.h" #include "flutter/shell/platform/darwin/macos/framework/Headers/FlutterEngine.h" -#import "flutter/shell/platform/darwin/macos/framework/Headers/FlutterViewController.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" namespace flutter::testing { -TEST(FlutterViewControllerTest, HasStrings) { +TEST(FlutterViewControllerTest, HasStringsWhenPasteboardEmpty) { NSString* fixtures = @(testing::GetFixturesPath()); FlutterDartProject* project = [[FlutterDartProject alloc] initWithAssetsPath:fixtures @@ -22,18 +23,62 @@ // real pasteboard. id pasteboardMock = OCMClassMock([NSPasteboard class]); __block NSString* clipboardString = @""; - void (^setStringMock)(NSInvocation*) = ^(NSInvocation *invocation) { + OCMStub([pasteboardMock setString:[OCMArg any] forType:[OCMArg any]]).andDo(^(NSInvocation *invocation) { [invocation getArgument:&clipboardString atIndex:2]; - }; - OCMStub([pasteboardMock setString:[OCMArg any] forType:[OCMArg any]]).andDo(setStringMock); - void (^stringForTypeMock)(NSInvocation*) = ^(NSInvocation *invocation) { + }); + OCMExpect([pasteboardMock stringForType:[OCMArg any]]).andDo(^(NSInvocation *invocation) { [invocation setReturnValue:&clipboardString]; + }); + id viewControllerMock = OCMPartialMock(viewController); + OCMStub([viewControllerMock _pasteboard]).andReturn(pasteboardMock); + + // 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]; }; - OCMExpect([pasteboardMock stringForType:[OCMArg any]]).andDo(stringForTypeMock); + FlutterMethodCall* methodCallAfterClear = + [FlutterMethodCall methodCallWithMethodName:@"Clipboard.hasStrings" arguments:nil]; + [viewControllerMock handleMethodCall:methodCallAfterClear result:resultAfterClear]; + ASSERT_TRUE(calledAfterClear); + ASSERT_FALSE(valueAfterClear); +} + +TEST(FlutterViewControllerTest, HasStringsWhenPasteboardFull) { + 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); - // First call setClipboardData to put a string on the pasteboard. + // Call setClipboardData to make sure there's a string on the pasteboard. __block bool calledSet = false; FlutterResult resultSet = ^(id result) { calledSet = true; @@ -57,31 +102,6 @@ [viewControllerMock handleMethodCall:methodCall result:result]; ASSERT_TRUE(called); ASSERT_TRUE(value); - - // Now call setData again to clear the pasteboard. - __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); } } // flutter::testing From 70286fc156551dd260616bbe86885e5f17f7e17a Mon Sep 17 00:00:00 2001 From: Justin McCandless Date: Thu, 3 Sep 2020 13:35:37 -0700 Subject: [PATCH 17/25] Deduplicate mocking code --- .../Source/FlutterViewControllerTest.mm | 28 ++++++------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm b/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm index 6e1b7769e7fa3..374a4e88d9cc2 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm @@ -12,7 +12,9 @@ namespace flutter::testing { -TEST(FlutterViewControllerTest, HasStringsWhenPasteboardEmpty) { +// 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 @@ -31,6 +33,11 @@ }); 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; @@ -59,24 +66,7 @@ } TEST(FlutterViewControllerTest, HasStringsWhenPasteboardFull) { - 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); + id viewControllerMock = mockViewController(); // Call setClipboardData to make sure there's a string on the pasteboard. __block bool calledSet = false; From 6c778fe7cd8c8562f46a1ca9ae22ad7110c4fe6b Mon Sep 17 00:00:00 2001 From: Justin McCandless Date: Thu, 3 Sep 2020 13:38:28 -0700 Subject: [PATCH 18/25] Comment cleanup --- .../darwin/macos/framework/Headers/FlutterViewController.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h b/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h index e0734c5b62c33..ea0df5e759300 100644 --- a/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h +++ b/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h @@ -40,8 +40,7 @@ FLUTTER_EXPORT @property(nonatomic) FlutterMouseTrackingMode mouseTrackingMode; /** - * This just returns the NSPasteboard. Using a property allows - * this to be mocked in the tests. + * This just returns the NSPasteboard so that it can be mocked in the tests. */ @property(nonatomic, readonly, nonnull) NSPasteboard* _pasteboard; From b68a594bae196dd6bed162f8eaae8f73fa7ac11f Mon Sep 17 00:00:00 2001 From: Justin McCandless Date: Thu, 3 Sep 2020 13:40:43 -0700 Subject: [PATCH 19/25] Analyzer fixes --- .../macos/framework/Headers/FlutterViewController.h | 2 +- .../framework/Source/FlutterViewControllerTest.mm | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h b/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h index ea0df5e759300..e1fc13708eba4 100644 --- a/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h +++ b/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h @@ -41,7 +41,7 @@ FLUTTER_EXPORT /** * This just returns the NSPasteboard so that it can be mocked in the tests. -*/ + */ @property(nonatomic, readonly, nonnull) NSPasteboard* _pasteboard; /** diff --git a/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm b/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm index 374a4e88d9cc2..eeb4cd0dbfea2 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm @@ -4,11 +4,11 @@ #import "flutter/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h" -#import "third_party/ocmock/Source/OCMock/OCMock.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 { @@ -25,11 +25,12 @@ id mockViewController() { // 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]; + 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); From 45b81b41a9146c74df64a81636a30795e5b5112d Mon Sep 17 00:00:00 2001 From: Justin McCandless Date: Thu, 3 Sep 2020 17:16:20 -0700 Subject: [PATCH 20/25] Reference new buildroot hash after my change to ocmock there --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 2239bb6b620d9..d17f0de35b9ca 100644 --- a/DEPS +++ b/DEPS @@ -105,7 +105,7 @@ allowed_hosts = [ ] deps = { - 'src': 'https://github.com/flutter/buildroot.git' + '@' + 'a6c0959d1ac8cdfe6f9ff87892bc4905a73699fe', + 'src': 'https://github.com/flutter/buildroot.git' + '@' + '940dcf6e85301c049576da58b193cf2d903539a2', # Fuchsia compatibility # From 3c9ec6eab5e050dcebac4d4213482d6d9bd99872 Mon Sep 17 00:00:00 2001 From: Justin McCandless Date: Wed, 9 Sep 2020 09:15:49 -0700 Subject: [PATCH 21/25] _pasteboard -> pasteboard --- .../darwin/macos/framework/Headers/FlutterViewController.h | 2 +- .../darwin/macos/framework/Source/FlutterViewController.mm | 6 +++--- .../macos/framework/Source/FlutterViewControllerTest.mm | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h b/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h index e1fc13708eba4..6bea59c373e44 100644 --- a/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h +++ b/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h @@ -42,7 +42,7 @@ FLUTTER_EXPORT /** * This just returns the NSPasteboard so that it can be mocked in the tests. */ -@property(nonatomic, readonly, nonnull) NSPasteboard* _pasteboard; +@property(nonatomic, readonly, nonnull) NSPasteboard* pasteboard; /** * Initializes a controller that will run the given project. diff --git a/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm b/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm index aa87583f04d6f..14fcfadbb4a5f 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm @@ -528,7 +528,7 @@ - (void)playSystemSound:(NSString*)soundType { } - (NSDictionary*)getClipboardData:(NSString*)format { - NSPasteboard* pasteboard = [self _pasteboard]; + NSPasteboard* pasteboard = self.pasteboard; if ([format isEqualToString:@(kTextPlainFormat)]) { NSString* stringInPasteboard = [pasteboard stringForType:NSPasteboardTypeString]; return stringInPasteboard == nil ? nil : @{@"text" : stringInPasteboard}; @@ -537,7 +537,7 @@ - (NSDictionary*)getClipboardData:(NSString*)format { } - (void)setClipboardData:(NSDictionary*)data { - NSPasteboard* pasteboard = [self _pasteboard]; + NSPasteboard* pasteboard = self.pasteboard; NSString* text = data[@"text"]; [pasteboard clearContents]; if (text && ![text isEqual:[NSNull null]]) { @@ -551,7 +551,7 @@ - (BOOL)clipboardHasStrings { return string.length > 0; } -- (NSPasteboard*)_pasteboard { +- (NSPasteboard*)pasteboard { return [NSPasteboard generalPasteboard]; } diff --git a/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm b/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm index eeb4cd0dbfea2..2a23038246b51 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm @@ -21,7 +21,7 @@ id mockViewController() { ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]]; FlutterViewController* viewController = [[FlutterViewController alloc] initWithProject:project]; - // Mock _pasteboard so that this test will work in environments without a + // Mock pasteboard so that this test will work in environments without a // real pasteboard. id pasteboardMock = OCMClassMock([NSPasteboard class]); __block NSString* clipboardString = @""; @@ -33,7 +33,7 @@ id mockViewController() { [invocation setReturnValue:&clipboardString]; }); id viewControllerMock = OCMPartialMock(viewController); - OCMStub([viewControllerMock _pasteboard]).andReturn(pasteboardMock); + OCMStub([viewControllerMock pasteboard]).andReturn(pasteboardMock); return viewControllerMock; } From a52595dffcbd24e389029452d2e02606b6d3bae0 Mon Sep 17 00:00:00 2001 From: Justin McCandless Date: Wed, 9 Sep 2020 10:00:41 -0700 Subject: [PATCH 22/25] Mock pasteboard value directly instead of mocking setString --- .../framework/Source/FlutterViewController.mm | 8 +--- .../Source/FlutterViewControllerTest.mm | 39 ++++--------------- 2 files changed, 9 insertions(+), 38 deletions(-) diff --git a/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm b/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm index 14fcfadbb4a5f..e30dbc7d9ae3f 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm @@ -175,10 +175,6 @@ - (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; @@ -546,9 +542,7 @@ - (void)setClipboardData:(NSDictionary*)data { } - (BOOL)clipboardHasStrings { - NSDictionary* data = [self getClipboardData:[NSString stringWithFormat:@"%s", kTextPlainFormat]]; - NSString* string = data[@"text"]; - return string.length > 0; + return [self.pasteboard stringForType:NSPasteboardTypeString].length > 0; } - (NSPasteboard*)pasteboard { diff --git a/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm b/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm index 2a23038246b51..db111d827c731 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm @@ -14,7 +14,7 @@ // Returns a mock FlutterViewController that is able to work in environments // without a real pasteboard. -id mockViewController() { +id mockViewController(NSString* pasteboardString) { NSString* fixtures = @(testing::GetFixturesPath()); FlutterDartProject* project = [[FlutterDartProject alloc] initWithAssetsPath:fixtures @@ -24,13 +24,9 @@ id mockViewController() { // 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]; + NSString* returnValue = pasteboardString.length > 0 ? pasteboardString : nil; + [invocation setReturnValue:&returnValue]; }); id viewControllerMock = OCMPartialMock(viewController); OCMStub([viewControllerMock pasteboard]).andReturn(pasteboardMock); @@ -38,18 +34,8 @@ id mockViewController() { } 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); + // 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; @@ -67,18 +53,9 @@ id mockViewController() { } 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); + // 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; From d14a117920b60d54ecbe110e2e6ef3bc087dbdca Mon Sep 17 00:00:00 2001 From: Justin McCandless Date: Wed, 9 Sep 2020 11:35:37 -0700 Subject: [PATCH 23/25] Don't run the mac tests with run_test.py, because they fail in AOT mode --- testing/run_tests.py | 1 - 1 file changed, 1 deletion(-) diff --git a/testing/run_tests.py b/testing/run_tests.py index cfcedd74f7816..a11f91c47b1e8 100755 --- a/testing/run_tests.py +++ b/testing/run_tests.py @@ -147,7 +147,6 @@ def RunCCTests(build_dir, filter): # These unit-tests are Objective-C and can only run on Darwin. if IsMac(): RunEngineExecutable(build_dir, 'flutter_channels_unittests', filter, shuffle_flags) - RunEngineExecutable(build_dir, 'flutter_desktop_darwin_unittests', filter, shuffle_flags) # https://github.com/flutter/flutter/issues/36296 if IsLinux(): From e1566acada6e88c8fafb92f1822cad709b64f73a Mon Sep 17 00:00:00 2001 From: Justin McCandless Date: Thu, 10 Sep 2020 15:51:41 -0700 Subject: [PATCH 24/25] pasteboard in the private header --- .../darwin/macos/framework/Headers/FlutterViewController.h | 5 ----- .../macos/framework/Source/FlutterViewControllerTest.mm | 2 +- .../macos/framework/Source/FlutterViewController_Internal.h | 5 +++++ 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h b/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h index 6bea59c373e44..b32af0ac32644 100644 --- a/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h +++ b/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h @@ -39,11 +39,6 @@ FLUTTER_EXPORT */ @property(nonatomic) FlutterMouseTrackingMode mouseTrackingMode; -/** - * This just returns the NSPasteboard so that it can be mocked in the tests. - */ -@property(nonatomic, readonly, nonnull) NSPasteboard* pasteboard; - /** * Initializes a controller that will run the given project. * diff --git a/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm b/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm index db111d827c731..505a573c045a8 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm @@ -2,7 +2,7 @@ // 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" +#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" diff --git a/shell/platform/darwin/macos/framework/Source/FlutterViewController_Internal.h b/shell/platform/darwin/macos/framework/Source/FlutterViewController_Internal.h index 5edd87c0f71c1..a2202fe9498a9 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterViewController_Internal.h +++ b/shell/platform/darwin/macos/framework/Source/FlutterViewController_Internal.h @@ -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. From 06a603483c98015b8d0657bc96b1c73bc7f2b35c Mon Sep 17 00:00:00 2001 From: Justin McCandless Date: Fri, 11 Sep 2020 17:07:49 -0700 Subject: [PATCH 25/25] Use ocmock now that it has been made to work with mac and ocmock_src is gone --- shell/platform/darwin/macos/BUILD.gn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell/platform/darwin/macos/BUILD.gn b/shell/platform/darwin/macos/BUILD.gn index 41259454ed0f9..0eb36f594a56a 100644 --- a/shell/platform/darwin/macos/BUILD.gn +++ b/shell/platform/darwin/macos/BUILD.gn @@ -117,7 +117,7 @@ executable("flutter_desktop_darwin_unittests") { "//flutter/testing:dart", "//flutter/testing:skia", "//flutter/testing:testing_lib", - "//third_party/ocmock:ocmock_src", + "//third_party/ocmock:ocmock", ] }