Skip to content

Conversation

@dnfield
Copy link
Contributor

@dnfield dnfield commented Sep 15, 2020

flutter/engine#21057 is going to add some new methods to ui.Image.

Our tests shouldn't break for that.

@flutter-dashboard flutter-dashboard bot added framework flutter/packages/flutter repository. See also f: labels. c: contributor-productivity Team-specific productivity, code health, technical debt. labels Sep 15, 2020
Copy link
Contributor

@jonahwilliams jonahwilliams left a comment

Choose a reason for hiding this comment

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

An alternative would be to add the new methods with an override and an ignore for the override warning.

At any rate, it would be nice to have a bug tracking the removal

@dnfield
Copy link
Contributor Author

dnfield commented Sep 15, 2020

Do we really want to remove these? If we remove them, we cause extra pain/work every time we add a method or member to an interface that is explicitly documented as something that you should not extend or implement :\ I understand why we implement it here (for testing purposes only), but even then using the implemented case in a test can cause a unintended test failure if the fake image actually gets to the C++ side of a test.

@dnfield
Copy link
Contributor Author

dnfield commented Sep 15, 2020

I actually think a better alternative would be to add something to package:flutter_test that produces an image for you with the desired dimensions (perhaps with the desired color as well?).

It should be fairly trivial to use something like decodeImageFromPixels for that. WDYT?

Copy link
Contributor

@jonahwilliams jonahwilliams 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 it depends on the various use cases here. We have the kTransparentImage pattern too but that might not be general enough? If there isn't actually any mocking going on maybe

@goderbauer
Copy link
Member

I didn't check all of them, but the once I looked at looked all the same. Should we maybe only have one TestImage implementation under flutter/test somewhere and reuse that across these tests?

Adding something to flutter_test (or maybe even have that as a private method within flutter/test) to generate a test image also sounds reasonable to me.

@dnfield
Copy link
Contributor Author

dnfield commented Sep 17, 2020

Updated this to completely do away with the TestImage fakes, and just use real images.


final Map<int, ui.Image> _cache = <int, ui.Image>{};

/// Asynchronously creates an arbitrarily sized test image.
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe instead of "arbitrarily sized test image" -> "arbitrarily sized image for testing", since it is just a regular image.

I dunno if async is necessarily important here, since that is implied by the return type.

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

(Cleaned up a little of the rest of the doc too, and saved a file I had fixed but forogtten to save :)


/// Creates an arbitrarily sized image for testing.
///
/// If the [cache] parameter is set to true, the image will be cached. This
Copy link
Contributor

Choose a reason for hiding this comment

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

... for the rest of the test suite (maybe?)

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.

@dnfield
Copy link
Contributor Author

dnfield commented Sep 18, 2020

(fixed up the analysis error for real this time)

@dnfield
Copy link
Contributor Author

dnfield commented Sep 21, 2020

Added a work around for web (see #49244)

int get width => 10;

@override
dynamic noSuchMethod(Invocation invocation) {
Copy link
Member

Choose a reason for hiding this comment

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

Why can the use of this FakeImage not be replaced with the new test image stuff?

void dispose() { }

@override
dynamic noSuchMethod(Invocation invocation) {
Copy link
Member

Choose a reason for hiding this comment

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

Same here and below.

@override
String toString() => '[$width\u00D7$height]';

@override
Copy link
Member

Choose a reason for hiding this comment

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

... and here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Refactored all of these, thanks for catching.

///
/// This method requires real async work, and will not work properly in the
/// [FakeAsync] zones set up by [testWidgets]. Typically, it should be invoked
/// as a setup step before [testWidgets] are run. If needed, it can be invoked
Copy link
Member

Choose a reason for hiding this comment

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

should this link to [setUpAll] / [setUp] as an appropriate place to call this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added links.

}

if (kIsWeb) {
return await _webCreateTestImage(
Copy link
Member

Choose a reason for hiding this comment

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

These are not added to the cache?

Copy link
Member

Choose a reason for hiding this comment

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

Ah, I see, it happens within the method. Maybe for symmetry, pull the caching code out and place it here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Refactored this a bit to clean it up.

/// Creates an arbitrarily sized image for testing.
///
/// If the [cache] parameter is set to true, the image will be cached for the
/// rest of this suite. This should be avoided for images that are used only
Copy link
Member

Choose a reason for hiding this comment

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

I was slightly confused by this telling me to avoid it and the fact that it defaults to true. Maybe add a sentence describing why you usually want caching?

Copy link
Member

Choose a reason for hiding this comment

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

Why do we need the caching at all? Does re-creating the image really cost that much in terms of testing performance?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My thought is that we're going from what is a very fast operation (constructing a fake implementation) to what is now a measurably slower and more memory intensive operation, particularly if the image tested is large.

Most of our test cases use a 10x10 image, completely arbitrarily. Some of them use as big as 200x300. If our CI machines are running slowly, caching that 200x300 could save us something on the order of seconds.

Updated the docs here to explain that.

@goderbauer
Copy link
Member

Looks like its still unhappy on the web?

@dnfield
Copy link
Contributor Author

dnfield commented Sep 21, 2020

Web is still unhappy because Image.toString works differently on web - on VM it does [w x h], on web it isn't overridden.

Copy link
Member

@goderbauer goderbauer left a comment

Choose a reason for hiding this comment

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

LGTM

bool cache = true,
}) => TestAsyncUtils.guard(() async {
assert(width != null && width > 0);
assert(height != null && height > 0);
Copy link
Member

Choose a reason for hiding this comment

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

nit: probably also assert(cache != null);

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


final int cacheKey = hashValues(width, height);
if (cache && _cache.containsKey(cacheKey)) {
return _cache[hashValues(width,height)];
Copy link
Member

Choose a reason for hiding this comment

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

nit: space after ,

Copy link
Member

Choose a reason for hiding this comment

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

Actually, just use cacheKey here instead of recomputing it?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Whups, done.

@fluttergithubbot
Copy link
Contributor

This pull request is not suitable for automatic merging in its current state.

  • The status or check suite Linux web_tests has failed. Please fix the issues identified (or deflake) before re-applying this label.

Copy link
Contributor

@jonahwilliams jonahwilliams left a comment

Choose a reason for hiding this comment

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

LGTM

@dnfield
Copy link
Contributor Author

dnfield commented Sep 22, 2020

I think.. I think I got it this time guys. I think it's going to work. I even ran it locally and everything.

@dnfield
Copy link
Contributor Author

dnfield commented Sep 22, 2020

Tree is green, landing this before it's too late.

@dnfield dnfield merged commit 7eb8447 into flutter:master Sep 22, 2020
@dnfield dnfield deleted the image_impl branch September 22, 2020 18:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

c: contributor-productivity Team-specific productivity, code health, technical debt. framework flutter/packages/flutter repository. See also f: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants