Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

hasStrings Mac #20531

Merged
merged 30 commits into from
Sep 15, 2020
Merged

hasStrings Mac #20531

merged 30 commits into from
Sep 15, 2020

Conversation

justinmc
Copy link
Contributor

@justinmc justinmc commented Aug 15, 2020

Description

Adding the hasStrings method to Mac, similar to #19859.

Related Issues

Depends on flutter/buildroot#399
#19859
flutter/flutter#60145

Tests

I added the following tests:

  • hasStrings returns true after setting a string to the clipboard.
  • hasStrings returns false after clearing the clipboard.

@justinmc justinmc added the Work in progress (WIP) Not ready (yet) for review! label Aug 15, 2020
@justinmc justinmc self-assigned this Aug 15, 2020
@justinmc justinmc marked this pull request as draft August 15, 2020 00:10
@auto-assign auto-assign bot requested a review from iskakaushik August 15, 2020 00:12
@justinmc
Copy link
Contributor Author

What's the status of unit testing on Mac?
I see one unit test, and it doesn't seem to be run by run_tests.py: https://github.com/flutter/engine/blob/master/shell/platform/darwin/macos/framework/Source/FlutterEngineUnittests.mm

@justinmc justinmc changed the title (WIP) hasStrings Mac hasStrings Mac Aug 27, 2020
@justinmc justinmc removed the Work in progress (WIP) Not ready (yet) for review! label Aug 27, 2020
@justinmc justinmc marked this pull request as ready for review August 27, 2020 21:27
@flutter-dashboard
Copy link

It looks like this pull request may not have tests. Please make sure to add tests before merging. If you need an exemption to this rule, contact Hixie on the #hackers channel in Chat.

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing.

Copy link
Member

@gaaclarke gaaclarke left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you forgot to add the FlutterViewControllerTest.mm file?

@justinmc
Copy link
Contributor Author

Whoops, actually I forgot to remove the line referencing it when I was messing around with trying to figure out the Mac unit tests.

Do we actually have functioning unit tests on Mac? If so, how do I run them?

@gaaclarke
Copy link
Member

Do we actually have functioning unit tests on Mac? If so, how do I run them?

Never looked into it. @stuartmorgan would be the person to ask.

@justinmc
Copy link
Contributor Author

Thanks for the pointer! I couldn't figure this out and didn't know who to ask.

@stuartmorgan-g
Copy link
Contributor

stuartmorgan-g commented Aug 28, 2020

The current state of testing for macOS is not good, certainly. @chinmaygarde added that test so could answer questions about it, or I can look next week when I'm not OOO

@justinmc
Copy link
Contributor Author

@stuartmorgan Thanks for the pointer, I was able to get the tests running with help from Chinmay. I will attempt to add the Mac unit tests into run_tests.py in this PR.

For posterity, the way to directly run the Mac unit tests is to compile for Mac, then run:

./out/host_debug_unopt/flutter_desktop_darwin_unittests

@justinmc
Copy link
Contributor Author

@gaaclarke Ready for re-review. I was able to add a test and get the Mac unit tests running as a part of run_tests.py.


namespace flutter::testing {

TEST(FlutterViewControllerTest, MacOSTestTest) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this called MacOSTestTest? The name should describe what the test is covering.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, forgot to update that.

[FlutterMethodCall methodCallWithMethodName:@"Clipboard.hasStrings" arguments:nil];
[viewController handleMethodCall:methodCall result:result];
ASSERT_TRUE(called);
ASSERT_TRUE(value);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suspect the unit tests on the bots are running in a bootstrap context that doesn't have access to the pasteboard server. If that's the case, perhaps the tests should inject a mock NSPasteboard.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any idea how to include OCMock in the Mac tests? I tried including it in this test file and adding it to Build.gn in various places, but I keep getting compiler errors.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same way it's done for iOS? Without knowing what you tried and what exactly didn't work, it's hard to advise further.

@justinmc
Copy link
Contributor Author

justinmc commented Sep 8, 2020

Ah you're right, thanks! Running in profile mode fails with the same error locally.

If you've got any idea how to get this working let me know. The original FlutterEngineUnittests.mm also fails in profile mode.

@stuartmorgan-g
Copy link
Contributor

If you've got any idea how to get this working let me know. The original FlutterEngineUnittests.mm also fails in profile mode.

I'm not familiar with GetFixturesPath() and the associated scaffolding, but from a quick look I don't see any evidence that it's even been used with the iOS embedding either, so it may need non-trivial retooling to create AOT snapshots in the format macOS and iOS expect them; I'd have to dig deeper into it than I have time for at the moment to be sure. I'm also not sure that's a good use of effort at this point since for the desktop embedding tests in general I'd like to move toward stubbing out at the embedder.h layer (although we'll probably want some more full-stack tests for which GetFixturesPath() could still be useful).

At this point I think the best option for this PR would be to revert the addition of the test binary to run_tests.py. Needing to get it running on CI is a pre-existing issue, and you've added tests (and run them locally) covering your changes that are ready to come online when they are made to work on CI, so the testing situation has still improved incrementally as a result of the PR even if it's not at the ideal outcome yet.

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

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.

Copy link
Contributor Author

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.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FlutterViewController_Internal.h

Copy link
Contributor Author

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?

FlutterViewControllerTest.mm:32:31: error: no known instance method for selector 'pasteboard'

Copy link
Contributor

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?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That was it, thanks.

* Returns true iff the clipboard contains nonempty string data.
*
* See also:
* * https://developer.apple.com/documentation/uikit/uipasteboard/1829416-hasstrings,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess I didn't explain my earlier question very well: what information is this adding that helps understand the method? The description in the comment seems clear and unambiguous; following that link doesn't tell me anything new AFAICT, so why have it?

It also seems odd to document it in terms of another platform's implementation, given than a) we have a lot of platforms, so referring to one of them is pretty arbitrary, b) that implementation is not relevant here since there's no such method on macOS, and c) that anyone who wants to know how it's done on iOS can easily just go look at the iOS source.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good, removed.

@@ -517,7 +528,7 @@ - (void)playSystemSound:(NSString*)soundType {
}

- (NSDictionary*)getClipboardData:(NSString*)format {
NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
NSPasteboard* pasteboard = [self _pasteboard];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer accessing properties with dot syntax: self.pasteboard.

[pasteboard setString:text forType:NSPasteboardTypeString];
}
}

- (BOOL)clipboardHasStrings {
NSDictionary* data = [self getClipboardData:[NSString stringWithFormat:@"%s", kTextPlainFormat]];
NSString* string = data[@"text"];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at this more closely this time: going through a method whose input and output are explicitly designed for the Flutter method channel contract seems like a very convoluted way to check this. Why not just return [self.pasteboard stringForType:NSPasteboardTypeString]].length > 0;?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, done.

TEST(FlutterViewControllerTest, HasStringsWhenPasteboardEmpty) {
id viewControllerMock = mockViewController();

// Call setData to make sure that the pasteboard is empty.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your test controls the fake clipboard; there is no reason to involve Clipboard.setData in the test of Clipboard.hasStrings.

It would be good to have a test of setData, but that should be a separate test.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, now I just set up the mock with some given pasteboard string instead of letting the test call setString.

TEST(FlutterViewControllerTest, HasStringsWhenPasteboardFull) {
id viewControllerMock = mockViewController();

// Call setClipboardData to make sure there's a string on the pasteboard.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same.

@justinmc
Copy link
Contributor Author

justinmc commented Sep 9, 2020

@stuartmorgan That sounds good to me, I've reverted the change to run_tests.py. I'm happy we were able to improve the testing situation a bit even if not quite all the way.

@justinmc
Copy link
Contributor Author

Waiting on #21111 to fix the Mac iOS Engine test.

@justinmc
Copy link
Contributor Author

Finally green 🎉

@stuartmorgan Ready for final review when we're back on Monday.

@justinmc
Copy link
Contributor Author

@stuartmorgan Reminder that this needs a final review when you have a chance.

@justinmc justinmc merged commit 3c9308f into flutter:master Sep 15, 2020
@justinmc justinmc deleted the has-strings-mac branch September 15, 2020 15:40
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Sep 15, 2020
@justinmc justinmc mentioned this pull request Sep 24, 2020
chinmaygarde pushed a commit to chinmaygarde/flutter_buildroot that referenced this pull request May 4, 2021
Gets ocmock set up so that it can be used by the Mac unit tests (in flutter/engine#20531).
@justinmc justinmc mentioned this pull request Jul 27, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants