Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
3cb79079
Unverified
Commit
3cb79079
authored
May 08, 2020
by
Ian Hickson
Committed by
GitHub
May 08, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix silent test failure in image cache tests (#56492)
parent
0a4f6cde
Changes
10
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
1011 additions
and
916 deletions
+1011
-916
image_cache.dart
packages/flutter/lib/src/painting/image_cache.dart
+1
-6
image_provider.dart
packages/flutter/lib/src/painting/image_provider.dart
+4
-4
image_cache_clearing_test.dart
...ages/flutter/test/painting/image_cache_clearing_test.dart
+31
-0
image_cache_resize_test.dart
packages/flutter/test/painting/image_cache_resize_test.dart
+49
-50
image_cache_test.dart
packages/flutter/test/painting/image_cache_test.dart
+346
-350
image_provider_and_image_cache_test.dart
...er/test/painting/image_provider_and_image_cache_test.dart
+142
-0
image_provider_network_image_test.dart
...tter/test/painting/image_provider_network_image_test.dart
+224
-0
image_provider_resize_image_test.dart
...utter/test/painting/image_provider_resize_image_test.dart
+134
-0
image_provider_test.dart
packages/flutter/test/painting/image_provider_test.dart
+69
-505
rendering_tester.dart
packages/flutter/test/rendering/rendering_tester.dart
+11
-1
No files found.
packages/flutter/lib/src/painting/image_cache.dart
View file @
3cb79079
...
...
@@ -286,10 +286,9 @@ class ImageCache {
}
}
void
_trackLiveImage
(
Object
key
,
_LiveImage
image
,
{
bool
debugPutOk
=
true
}
)
{
void
_trackLiveImage
(
Object
key
,
_LiveImage
image
)
{
// Avoid adding unnecessary callbacks to the completer.
_liveImages
.
putIfAbsent
(
key
,
()
{
assert
(
debugPutOk
);
// Even if no callers to ImageProvider.resolve have listened to the stream,
// the cache is listening to the stream and will remove itself once the
// image completes to move it from pending to keepAlive.
...
...
@@ -400,10 +399,6 @@ class ImageCache {
imageSize
,
()
=>
_liveImages
.
remove
(
key
),
),
// This should result in a put if `loader()` above executed
// synchronously, in which case syncCall is true and we arrived here
// before we got a chance to track the image otherwise.
debugPutOk:
syncCall
,
);
final
_PendingImage
pendingImage
=
untrackedPendingImage
??
_pendingImages
.
remove
(
key
);
...
...
packages/flutter/lib/src/painting/image_provider.dart
View file @
3cb79079
...
...
@@ -347,10 +347,10 @@ abstract class ImageProvider<T> {
stack:
stack
,
context:
ErrorDescription
(
'while resolving an image'
),
silent:
true
,
// could be a network error or whatnot
informationCollector:
collector
);
},
);
informationCollector:
collector
,
);
},
);
return
stream
;
}
...
...
packages/flutter/test/painting/image_cache_clearing_test.dart
0 → 100644
View file @
3cb79079
// Copyright 2014 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
'dart:async'
;
import
'dart:typed_data'
;
import
'package:flutter/painting.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
import
'../rendering/rendering_tester.dart'
;
import
'image_data.dart'
;
void
main
(
)
{
TestRenderingFlutterBinding
();
test
(
'Clearing images while they
\'
re pending does not crash'
,
()
async
{
final
Uint8List
bytes
=
Uint8List
.
fromList
(
kTransparentImage
);
final
MemoryImage
memoryImage
=
MemoryImage
(
bytes
);
final
ImageStream
stream
=
memoryImage
.
resolve
(
ImageConfiguration
.
empty
);
final
Completer
<
void
>
completer
=
Completer
<
void
>();
FlutterError
.
onError
=
(
FlutterErrorDetails
error
)
{
completer
.
completeError
(
error
.
exception
,
error
.
stack
);
};
stream
.
addListener
(
ImageStreamListener
(
(
ImageInfo
image
,
bool
synchronousCall
)
{
completer
.
complete
();
}
));
imageCache
.
clearLiveImages
();
await
completer
.
future
;
});
}
packages/flutter/test/painting/image_cache_resize_test.dart
View file @
3cb79079
...
...
@@ -9,71 +9,70 @@ import '../rendering/rendering_tester.dart';
import
'mocks_for_image_cache.dart'
;
void
main
(
)
{
TestRenderingFlutterBinding
();
// initializes the imageCache
group
(
ImageCache
,
()
{
tearDown
(()
{
imageCache
.
clear
();
imageCache
.
maximumSize
=
1000
;
imageCache
.
maximumSizeBytes
=
10485760
;
});
TestRenderingFlutterBinding
();
test
(
'Image cache resizing based on count'
,
()
async
{
imageCache
.
maximumSize
=
2
;
tearDown
(()
{
imageCache
.
clear
();
imageCache
.
maximumSize
=
1000
;
imageCache
.
maximumSizeBytes
=
10485760
;
});
test
(
'Image cache resizing based on count'
,
()
async
{
imageCache
.
maximumSize
=
2
;
final
TestImageInfo
a
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
1
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
final
TestImageInfo
b
=
await
extractOneFrame
(
const
TestImageProvider
(
2
,
2
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
final
TestImageInfo
c
=
await
extractOneFrame
(
const
TestImageProvider
(
3
,
3
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
final
TestImageInfo
d
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
4
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
expect
(
a
.
value
,
equals
(
1
));
expect
(
b
.
value
,
equals
(
2
));
expect
(
c
.
value
,
equals
(
3
));
expect
(
d
.
value
,
equals
(
4
));
final
TestImageInfo
a
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
1
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
final
TestImageInfo
b
=
await
extractOneFrame
(
const
TestImageProvider
(
2
,
2
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
final
TestImageInfo
c
=
await
extractOneFrame
(
const
TestImageProvider
(
3
,
3
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
final
TestImageInfo
d
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
4
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
expect
(
a
.
value
,
equals
(
1
));
expect
(
b
.
value
,
equals
(
2
));
expect
(
c
.
value
,
equals
(
3
));
expect
(
d
.
value
,
equals
(
4
));
imageCache
.
maximumSize
=
0
;
imageCache
.
maximumSize
=
0
;
final
TestImageInfo
e
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
5
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
expect
(
e
.
value
,
equals
(
5
));
final
TestImageInfo
e
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
5
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
expect
(
e
.
value
,
equals
(
5
));
final
TestImageInfo
f
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
6
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
expect
(
f
.
value
,
equals
(
6
));
final
TestImageInfo
f
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
6
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
expect
(
f
.
value
,
equals
(
6
));
imageCache
.
maximumSize
=
3
;
imageCache
.
maximumSize
=
3
;
final
TestImageInfo
g
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
7
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
expect
(
g
.
value
,
equals
(
7
));
final
TestImageInfo
g
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
7
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
expect
(
g
.
value
,
equals
(
7
));
final
TestImageInfo
h
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
8
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
expect
(
h
.
value
,
equals
(
7
));
});
final
TestImageInfo
h
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
8
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
expect
(
h
.
value
,
equals
(
7
));
});
test
(
'Image cache resizing based on size'
,
()
async
{
const
TestImage
testImage
=
TestImage
(
width:
8
,
height:
8
);
// 256 B.
imageCache
.
maximumSizeBytes
=
256
*
2
;
test
(
'Image cache resizing based on size'
,
()
async
{
const
TestImage
testImage
=
TestImage
(
width:
8
,
height:
8
);
// 256 B.
imageCache
.
maximumSizeBytes
=
256
*
2
;
final
TestImageInfo
a
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
1
,
image:
testImage
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
final
TestImageInfo
b
=
await
extractOneFrame
(
const
TestImageProvider
(
2
,
2
,
image:
testImage
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
final
TestImageInfo
c
=
await
extractOneFrame
(
const
TestImageProvider
(
3
,
3
,
image:
testImage
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
final
TestImageInfo
d
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
4
,
image:
testImage
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
expect
(
a
.
value
,
equals
(
1
));
expect
(
b
.
value
,
equals
(
2
));
expect
(
c
.
value
,
equals
(
3
));
expect
(
d
.
value
,
equals
(
4
));
final
TestImageInfo
a
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
1
,
image:
testImage
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
final
TestImageInfo
b
=
await
extractOneFrame
(
const
TestImageProvider
(
2
,
2
,
image:
testImage
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
final
TestImageInfo
c
=
await
extractOneFrame
(
const
TestImageProvider
(
3
,
3
,
image:
testImage
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
final
TestImageInfo
d
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
4
,
image:
testImage
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
expect
(
a
.
value
,
equals
(
1
));
expect
(
b
.
value
,
equals
(
2
));
expect
(
c
.
value
,
equals
(
3
));
expect
(
d
.
value
,
equals
(
4
));
imageCache
.
maximumSizeBytes
=
0
;
imageCache
.
maximumSizeBytes
=
0
;
final
TestImageInfo
e
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
5
,
image:
testImage
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
expect
(
e
.
value
,
equals
(
5
));
final
TestImageInfo
e
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
5
,
image:
testImage
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
expect
(
e
.
value
,
equals
(
5
));
final
TestImageInfo
f
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
6
,
image:
testImage
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
expect
(
f
.
value
,
equals
(
6
));
final
TestImageInfo
f
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
6
,
image:
testImage
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
expect
(
f
.
value
,
equals
(
6
));
imageCache
.
maximumSizeBytes
=
256
*
3
;
imageCache
.
maximumSizeBytes
=
256
*
3
;
final
TestImageInfo
g
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
7
,
image:
testImage
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
expect
(
g
.
value
,
equals
(
7
));
final
TestImageInfo
g
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
7
,
image:
testImage
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
expect
(
g
.
value
,
equals
(
7
));
final
TestImageInfo
h
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
8
,
image:
testImage
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
expect
(
h
.
value
,
equals
(
7
));
});
final
TestImageInfo
h
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
8
,
image:
testImage
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
expect
(
h
.
value
,
equals
(
7
));
});
}
packages/flutter/test/painting/image_cache_test.dart
View file @
3cb79079
This diff is collapsed.
Click to expand it.
packages/flutter/test/painting/image_provider_and_image_cache_test.dart
0 → 100644
View file @
3cb79079
// Copyright 2014 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
'dart:async'
;
import
'dart:typed_data'
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/painting.dart'
;
import
'package:flutter/services.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
import
'../rendering/rendering_tester.dart'
;
import
'image_data.dart'
;
import
'mocks_for_image_cache.dart'
;
void
main
(
)
{
TestRenderingFlutterBinding
();
final
DecoderCallback
_basicDecoder
=
(
Uint8List
bytes
,
{
int
cacheWidth
,
int
cacheHeight
})
{
return
PaintingBinding
.
instance
.
instantiateImageCodec
(
bytes
,
cacheWidth:
cacheWidth
,
cacheHeight:
cacheHeight
);
};
FlutterExceptionHandler
oldError
;
setUp
(()
{
oldError
=
FlutterError
.
onError
;
});
tearDown
(()
{
FlutterError
.
onError
=
oldError
;
PaintingBinding
.
instance
.
imageCache
.
clear
();
PaintingBinding
.
instance
.
imageCache
.
clearLiveImages
();
});
tearDown
(()
{
imageCache
.
clear
();
});
test
(
'AssetImageProvider - evicts on failure to load'
,
()
async
{
final
Completer
<
FlutterError
>
error
=
Completer
<
FlutterError
>();
FlutterError
.
onError
=
(
FlutterErrorDetails
details
)
{
error
.
complete
(
details
.
exception
as
FlutterError
);
};
const
ImageProvider
provider
=
ExactAssetImage
(
'does-not-exist'
);
final
Object
key
=
await
provider
.
obtainKey
(
ImageConfiguration
.
empty
);
expect
(
imageCache
.
statusForKey
(
provider
).
untracked
,
true
);
expect
(
imageCache
.
pendingImageCount
,
0
);
provider
.
resolve
(
ImageConfiguration
.
empty
);
expect
(
imageCache
.
statusForKey
(
key
).
pending
,
true
);
expect
(
imageCache
.
pendingImageCount
,
1
);
await
error
.
future
;
expect
(
imageCache
.
statusForKey
(
provider
).
untracked
,
true
);
expect
(
imageCache
.
pendingImageCount
,
0
);
},
skip:
isBrowser
);
// https://github.com/flutter/flutter/issues/56314
test
(
'AssetImageProvider - evicts on null load'
,
()
async
{
final
Completer
<
StateError
>
error
=
Completer
<
StateError
>();
FlutterError
.
onError
=
(
FlutterErrorDetails
details
)
{
error
.
complete
(
details
.
exception
as
StateError
);
};
final
ImageProvider
provider
=
ExactAssetImage
(
'does-not-exist'
,
bundle:
_TestAssetBundle
());
final
Object
key
=
await
provider
.
obtainKey
(
ImageConfiguration
.
empty
);
expect
(
imageCache
.
statusForKey
(
provider
).
untracked
,
true
);
expect
(
imageCache
.
pendingImageCount
,
0
);
provider
.
resolve
(
ImageConfiguration
.
empty
);
expect
(
imageCache
.
statusForKey
(
key
).
pending
,
true
);
expect
(
imageCache
.
pendingImageCount
,
1
);
await
error
.
future
;
expect
(
imageCache
.
statusForKey
(
provider
).
untracked
,
true
);
expect
(
imageCache
.
pendingImageCount
,
0
);
});
test
(
'ImageProvider can evict images'
,
()
async
{
final
Uint8List
bytes
=
Uint8List
.
fromList
(
kTransparentImage
);
final
MemoryImage
imageProvider
=
MemoryImage
(
bytes
);
final
ImageStream
stream
=
imageProvider
.
resolve
(
ImageConfiguration
.
empty
);
final
Completer
<
void
>
completer
=
Completer
<
void
>();
stream
.
addListener
(
ImageStreamListener
((
ImageInfo
info
,
bool
syncCall
)
=>
completer
.
complete
()));
await
completer
.
future
;
expect
(
imageCache
.
currentSize
,
1
);
expect
(
await
MemoryImage
(
bytes
).
evict
(),
true
);
expect
(
imageCache
.
currentSize
,
0
);
});
test
(
'ImageProvider.evict respects the provided ImageCache'
,
()
async
{
final
ImageCache
otherCache
=
ImageCache
();
final
Uint8List
bytes
=
Uint8List
.
fromList
(
kTransparentImage
);
final
MemoryImage
imageProvider
=
MemoryImage
(
bytes
);
final
ImageStreamCompleter
cacheStream
=
otherCache
.
putIfAbsent
(
imageProvider
,
()
=>
imageProvider
.
load
(
imageProvider
,
_basicDecoder
),
);
final
ImageStream
stream
=
imageProvider
.
resolve
(
ImageConfiguration
.
empty
);
final
Completer
<
void
>
completer
=
Completer
<
void
>();
final
Completer
<
void
>
cacheCompleter
=
Completer
<
void
>();
stream
.
addListener
(
ImageStreamListener
((
ImageInfo
info
,
bool
syncCall
)
{
completer
.
complete
();
}));
cacheStream
.
addListener
(
ImageStreamListener
((
ImageInfo
info
,
bool
syncCall
)
{
cacheCompleter
.
complete
();
}));
await
Future
.
wait
(<
Future
<
void
>>[
completer
.
future
,
cacheCompleter
.
future
]);
expect
(
otherCache
.
currentSize
,
1
);
expect
(
imageCache
.
currentSize
,
1
);
expect
(
await
imageProvider
.
evict
(
cache:
otherCache
),
true
);
expect
(
otherCache
.
currentSize
,
0
);
expect
(
imageCache
.
currentSize
,
1
);
});
test
(
'ImageProvider errors can always be caught'
,
()
async
{
final
ErrorImageProvider
imageProvider
=
ErrorImageProvider
();
final
Completer
<
bool
>
caughtError
=
Completer
<
bool
>();
FlutterError
.
onError
=
(
FlutterErrorDetails
details
)
{
caughtError
.
complete
(
false
);
};
final
ImageStream
stream
=
imageProvider
.
resolve
(
ImageConfiguration
.
empty
);
stream
.
addListener
(
ImageStreamListener
((
ImageInfo
info
,
bool
syncCall
)
{
caughtError
.
complete
(
false
);
},
onError:
(
dynamic
error
,
StackTrace
stackTrace
)
{
caughtError
.
complete
(
true
);
}));
expect
(
await
caughtError
.
future
,
true
);
});
}
class
_TestAssetBundle
extends
CachingAssetBundle
{
@override
Future
<
ByteData
>
load
(
String
key
)
async
{
return
null
;
}
}
packages/flutter/test/painting/image_provider_network_image_test.dart
0 → 100644
View file @
3cb79079
// Copyright 2014 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
'dart:async'
;
import
'dart:io'
;
import
'dart:math'
as
math
;
import
'dart:typed_data'
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/painting.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
import
'package:mockito/mockito.dart'
;
import
'../rendering/rendering_tester.dart'
;
import
'image_data.dart'
;
void
main
(
)
{
TestRenderingFlutterBinding
();
final
DecoderCallback
_basicDecoder
=
(
Uint8List
bytes
,
{
int
cacheWidth
,
int
cacheHeight
})
{
return
PaintingBinding
.
instance
.
instantiateImageCodec
(
bytes
,
cacheWidth:
cacheWidth
,
cacheHeight:
cacheHeight
);
};
_MockHttpClient
httpClient
;
setUp
(()
{
httpClient
=
_MockHttpClient
();
debugNetworkImageHttpClientProvider
=
()
=>
httpClient
;
});
tearDown
(()
{
debugNetworkImageHttpClientProvider
=
null
;
PaintingBinding
.
instance
.
imageCache
.
clear
();
PaintingBinding
.
instance
.
imageCache
.
clearLiveImages
();
});
test
(
'Expect thrown exception with statusCode - evicts from cache'
,
()
async
{
final
int
errorStatusCode
=
HttpStatus
.
notFound
;
const
String
requestUrl
=
'foo-url'
;
final
_MockHttpClientRequest
request
=
_MockHttpClientRequest
();
final
_MockHttpClientResponse
response
=
_MockHttpClientResponse
();
when
(
httpClient
.
getUrl
(
any
)).
thenAnswer
((
_
)
=>
Future
<
HttpClientRequest
>.
value
(
request
));
when
(
request
.
close
()).
thenAnswer
((
_
)
=>
Future
<
HttpClientResponse
>.
value
(
response
));
when
(
response
.
statusCode
).
thenReturn
(
errorStatusCode
);
final
Completer
<
dynamic
>
caughtError
=
Completer
<
dynamic
>();
final
ImageProvider
imageProvider
=
NetworkImage
(
nonconst
(
requestUrl
));
expect
(
imageCache
.
pendingImageCount
,
0
);
expect
(
imageCache
.
statusForKey
(
imageProvider
).
untracked
,
true
);
final
ImageStream
result
=
imageProvider
.
resolve
(
ImageConfiguration
.
empty
);
expect
(
imageCache
.
pendingImageCount
,
1
);
expect
(
imageCache
.
statusForKey
(
imageProvider
).
pending
,
true
);
result
.
addListener
(
ImageStreamListener
((
ImageInfo
info
,
bool
syncCall
)
{
},
onError:
(
dynamic
error
,
StackTrace
stackTrace
)
{
caughtError
.
complete
(
error
);
}));
final
dynamic
err
=
await
caughtError
.
future
;
expect
(
imageCache
.
pendingImageCount
,
0
);
expect
(
imageCache
.
statusForKey
(
imageProvider
).
untracked
,
true
);
expect
(
err
,
isA
<
NetworkImageLoadException
>()
.
having
((
NetworkImageLoadException
e
)
=>
e
.
statusCode
,
'statusCode'
,
errorStatusCode
)
.
having
((
NetworkImageLoadException
e
)
=>
e
.
uri
,
'uri'
,
Uri
.
base
.
resolve
(
requestUrl
)),
);
},
skip:
isBrowser
);
// Browser implementation does not use HTTP client but an <img> tag.
test
(
'Disallows null urls'
,
()
{
expect
(()
{
NetworkImage
(
nonconst
(
null
));
},
throwsAssertionError
);
});
test
(
'Uses the HttpClient provided by debugNetworkImageHttpClientProvider if set'
,
()
async
{
when
(
httpClient
.
getUrl
(
any
)).
thenThrow
(
'client1'
);
final
List
<
dynamic
>
capturedErrors
=
<
dynamic
>[];
Future
<
void
>
loadNetworkImage
()
async
{
final
NetworkImage
networkImage
=
NetworkImage
(
nonconst
(
'foo'
));
final
ImageStreamCompleter
completer
=
networkImage
.
load
(
networkImage
,
_basicDecoder
);
completer
.
addListener
(
ImageStreamListener
(
(
ImageInfo
image
,
bool
synchronousCall
)
{
},
onError:
(
dynamic
error
,
StackTrace
stackTrace
)
{
capturedErrors
.
add
(
error
);
},
));
await
Future
<
void
>.
value
();
}
await
loadNetworkImage
();
expect
(
capturedErrors
,
<
dynamic
>[
'client1'
]);
final
_MockHttpClient
client2
=
_MockHttpClient
();
when
(
client2
.
getUrl
(
any
)).
thenThrow
(
'client2'
);
debugNetworkImageHttpClientProvider
=
()
=>
client2
;
await
loadNetworkImage
();
expect
(
capturedErrors
,
<
dynamic
>[
'client1'
,
'client2'
]);
},
skip:
isBrowser
);
// Browser implementation does not use HTTP client but an <img> tag.
test
(
'Propagates http client errors during resolve()'
,
()
async
{
when
(
httpClient
.
getUrl
(
any
)).
thenThrow
(
Error
());
bool
uncaught
=
false
;
final
FlutterExceptionHandler
oldError
=
FlutterError
.
onError
;
await
runZoned
(()
async
{
const
ImageProvider
imageProvider
=
NetworkImage
(
'asdasdasdas'
);
final
Completer
<
bool
>
caughtError
=
Completer
<
bool
>();
FlutterError
.
onError
=
(
FlutterErrorDetails
details
)
{
throw
Error
();
};
final
ImageStream
result
=
imageProvider
.
resolve
(
ImageConfiguration
.
empty
);
result
.
addListener
(
ImageStreamListener
((
ImageInfo
info
,
bool
syncCall
)
{
},
onError:
(
dynamic
error
,
StackTrace
stackTrace
)
{
caughtError
.
complete
(
true
);
}));
expect
(
await
caughtError
.
future
,
true
);
},
zoneSpecification:
ZoneSpecification
(
handleUncaughtError:
(
Zone
zone
,
ZoneDelegate
zoneDelegate
,
Zone
parent
,
Object
error
,
StackTrace
stackTrace
)
{
uncaught
=
true
;
},
));
expect
(
uncaught
,
false
);
FlutterError
.
onError
=
oldError
;
});
test
(
'Notifies listeners of chunk events'
,
()
async
{
const
int
chunkSize
=
8
;
final
List
<
Uint8List
>
chunks
=
<
Uint8List
>[
for
(
int
offset
=
0
;
offset
<
kTransparentImage
.
length
;
offset
+=
chunkSize
)
Uint8List
.
fromList
(
kTransparentImage
.
skip
(
offset
).
take
(
chunkSize
).
toList
()),
];
final
Completer
<
void
>
imageAvailable
=
Completer
<
void
>();
final
_MockHttpClientRequest
request
=
_MockHttpClientRequest
();
final
_MockHttpClientResponse
response
=
_MockHttpClientResponse
();
when
(
httpClient
.
getUrl
(
any
)).
thenAnswer
((
_
)
=>
Future
<
HttpClientRequest
>.
value
(
request
));
when
(
request
.
close
()).
thenAnswer
((
_
)
=>
Future
<
HttpClientResponse
>.
value
(
response
));
when
(
response
.
statusCode
).
thenReturn
(
HttpStatus
.
ok
);
when
(
response
.
contentLength
).
thenReturn
(
kTransparentImage
.
length
);
when
(
response
.
listen
(
any
,
onDone:
anyNamed
(
'onDone'
),
onError:
anyNamed
(
'onError'
),
cancelOnError:
anyNamed
(
'cancelOnError'
),
)).
thenAnswer
((
Invocation
invocation
)
{
final
void
Function
(
List
<
int
>)
onData
=
invocation
.
positionalArguments
[
0
]
as
void
Function
(
List
<
int
>);
final
void
Function
(
Object
)
onError
=
invocation
.
namedArguments
[
#onError
]
as
void
Function
(
Object
);
final
VoidCallback
onDone
=
invocation
.
namedArguments
[
#onDone
]
as
VoidCallback
;
final
bool
cancelOnError
=
invocation
.
namedArguments
[
#cancelOnError
]
as
bool
;
return
Stream
<
Uint8List
>.
fromIterable
(
chunks
).
listen
(
onData
,
onDone:
onDone
,
onError:
onError
,
cancelOnError:
cancelOnError
,
);
});
final
ImageProvider
imageProvider
=
NetworkImage
(
nonconst
(
'foo'
));
final
ImageStream
result
=
imageProvider
.
resolve
(
ImageConfiguration
.
empty
);
final
List
<
ImageChunkEvent
>
events
=
<
ImageChunkEvent
>[];
result
.
addListener
(
ImageStreamListener
(
(
ImageInfo
image
,
bool
synchronousCall
)
{
imageAvailable
.
complete
();
},
onChunk:
(
ImageChunkEvent
event
)
{
events
.
add
(
event
);
},
onError:
(
dynamic
error
,
StackTrace
stackTrace
)
{
imageAvailable
.
completeError
(
error
,
stackTrace
);
},
));
await
imageAvailable
.
future
;
expect
(
events
.
length
,
chunks
.
length
);
for
(
int
i
=
0
;
i
<
events
.
length
;
i
++)
{
expect
(
events
[
i
].
cumulativeBytesLoaded
,
math
.
min
((
i
+
1
)
*
chunkSize
,
kTransparentImage
.
length
));
expect
(
events
[
i
].
expectedTotalBytes
,
kTransparentImage
.
length
);
}
},
skip:
isBrowser
);
// https://github.com/flutter/flutter/issues/56317
test
(
'NetworkImage is evicted from cache on SocketException'
,
()
async
{
final
_MockHttpClient
mockHttpClient
=
_MockHttpClient
();
when
(
mockHttpClient
.
getUrl
(
any
)).
thenAnswer
((
_
)
=>
throw
const
SocketException
(
'test exception'
));
debugNetworkImageHttpClientProvider
=
()
=>
mockHttpClient
;
final
ImageProvider
imageProvider
=
NetworkImage
(
nonconst
(
'testing.url'
));
expect
(
imageCache
.
pendingImageCount
,
0
);
expect
(
imageCache
.
statusForKey
(
imageProvider
).
untracked
,
true
);
final
ImageStream
result
=
imageProvider
.
resolve
(
ImageConfiguration
.
empty
);
expect
(
imageCache
.
pendingImageCount
,
1
);
expect
(
imageCache
.
statusForKey
(
imageProvider
).
pending
,
true
);
final
Completer
<
dynamic
>
caughtError
=
Completer
<
dynamic
>();
result
.
addListener
(
ImageStreamListener
(
(
ImageInfo
info
,
bool
syncCall
)
{},
onError:
(
dynamic
error
,
StackTrace
stackTrace
)
{
caughtError
.
complete
(
error
);
},
));
final
dynamic
err
=
await
caughtError
.
future
;
expect
(
err
,
isA
<
SocketException
>());
expect
(
imageCache
.
pendingImageCount
,
0
);
expect
(
imageCache
.
statusForKey
(
imageProvider
).
untracked
,
true
);
expect
(
imageCache
.
containsKey
(
result
),
isFalse
);
debugNetworkImageHttpClientProvider
=
null
;
},
skip:
isBrowser
);
// Browser does not resolve images this way.
}
class
_MockHttpClient
extends
Mock
implements
HttpClient
{}
class
_MockHttpClientRequest
extends
Mock
implements
HttpClientRequest
{}
class
_MockHttpClientResponse
extends
Mock
implements
HttpClientResponse
{}
packages/flutter/test/painting/image_provider_resize_image_test.dart
0 → 100644
View file @
3cb79079
// Copyright 2014 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
'dart:async'
;
import
'dart:typed_data'
;
import
'package:flutter/painting.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
import
'../rendering/rendering_tester.dart'
;
import
'image_data.dart'
;
void
main
(
)
{
TestRenderingFlutterBinding
();
tearDown
(()
{
PaintingBinding
.
instance
.
imageCache
.
clear
();
PaintingBinding
.
instance
.
imageCache
.
clearLiveImages
();
});
test
(
'ResizeImage resizes to the correct dimensions'
,
()
async
{
final
Uint8List
bytes
=
Uint8List
.
fromList
(
kTransparentImage
);
final
MemoryImage
imageProvider
=
MemoryImage
(
bytes
);
final
Size
rawImageSize
=
await
_resolveAndGetSize
(
imageProvider
);
expect
(
rawImageSize
,
const
Size
(
1
,
1
));
const
Size
resizeDims
=
Size
(
14
,
7
);
final
ResizeImage
resizedImage
=
ResizeImage
(
MemoryImage
(
bytes
),
width:
resizeDims
.
width
.
round
(),
height:
resizeDims
.
height
.
round
());
const
ImageConfiguration
resizeConfig
=
ImageConfiguration
(
size:
resizeDims
);
final
Size
resizedImageSize
=
await
_resolveAndGetSize
(
resizedImage
,
configuration:
resizeConfig
);
expect
(
resizedImageSize
,
resizeDims
);
},
skip:
isBrowser
);
// https://github.com/flutter/flutter/issues/56312
test
(
'ResizeImage does not resize when no size is passed'
,
()
async
{
final
Uint8List
bytes
=
Uint8List
.
fromList
(
kTransparentImage
);
final
MemoryImage
imageProvider
=
MemoryImage
(
bytes
);
final
Size
rawImageSize
=
await
_resolveAndGetSize
(
imageProvider
);
expect
(
rawImageSize
,
const
Size
(
1
,
1
));
// Cannot pass in two null arguments for cache dimensions, so will use the regular
// MemoryImage
final
MemoryImage
resizedImage
=
MemoryImage
(
bytes
);
final
Size
resizedImageSize
=
await
_resolveAndGetSize
(
resizedImage
);
expect
(
resizedImageSize
,
const
Size
(
1
,
1
));
});
test
(
'ResizeImage stores values'
,
()
async
{
final
Uint8List
bytes
=
Uint8List
.
fromList
(
kTransparentImage
);
final
MemoryImage
memoryImage
=
MemoryImage
(
bytes
);
memoryImage
.
resolve
(
ImageConfiguration
.
empty
);
final
ResizeImage
resizeImage
=
ResizeImage
(
memoryImage
,
width:
10
,
height:
20
);
expect
(
resizeImage
.
width
,
10
);
expect
(
resizeImage
.
height
,
20
);
expect
(
resizeImage
.
imageProvider
,
memoryImage
);
expect
(
memoryImage
.
resolve
(
ImageConfiguration
.
empty
)
!=
resizeImage
.
resolve
(
ImageConfiguration
.
empty
),
true
);
});
test
(
'ResizeImage takes one dim'
,
()
async
{
final
Uint8List
bytes
=
Uint8List
.
fromList
(
kTransparentImage
);
final
MemoryImage
memoryImage
=
MemoryImage
(
bytes
);
final
ResizeImage
resizeImage
=
ResizeImage
(
memoryImage
,
width:
10
,
height:
null
);
expect
(
resizeImage
.
width
,
10
);
expect
(
resizeImage
.
height
,
null
);
expect
(
resizeImage
.
imageProvider
,
memoryImage
);
expect
(
memoryImage
.
resolve
(
ImageConfiguration
.
empty
)
!=
resizeImage
.
resolve
(
ImageConfiguration
.
empty
),
true
);
});
test
(
'ResizeImage forms closure'
,
()
async
{
final
Uint8List
bytes
=
Uint8List
.
fromList
(
kTransparentImage
);
final
MemoryImage
memoryImage
=
MemoryImage
(
bytes
);
final
ResizeImage
resizeImage
=
ResizeImage
(
memoryImage
,
width:
123
,
height:
321
);
final
DecoderCallback
decode
=
(
Uint8List
bytes
,
{
int
cacheWidth
,
int
cacheHeight
})
{
expect
(
cacheWidth
,
123
);
expect
(
cacheHeight
,
321
);
return
PaintingBinding
.
instance
.
instantiateImageCodec
(
bytes
,
cacheWidth:
cacheWidth
,
cacheHeight:
cacheHeight
);
};
resizeImage
.
load
(
await
resizeImage
.
obtainKey
(
ImageConfiguration
.
empty
),
decode
);
});
test
(
'ResizeImage handles sync obtainKey'
,
()
async
{
final
Uint8List
bytes
=
Uint8List
.
fromList
(
kTransparentImage
);
final
MemoryImage
memoryImage
=
MemoryImage
(
bytes
);
final
ResizeImage
resizeImage
=
ResizeImage
(
memoryImage
,
width:
123
,
height:
321
);
bool
isAsync
=
false
;
resizeImage
.
obtainKey
(
ImageConfiguration
.
empty
).
then
((
Object
key
)
{
expect
(
isAsync
,
false
);
});
isAsync
=
true
;
expect
(
isAsync
,
true
);
});
test
(
'ResizeImage handles async obtainKey'
,
()
async
{
final
Uint8List
bytes
=
Uint8List
.
fromList
(
kTransparentImage
);
final
_AsyncKeyMemoryImage
memoryImage
=
_AsyncKeyMemoryImage
(
bytes
);
final
ResizeImage
resizeImage
=
ResizeImage
(
memoryImage
,
width:
123
,
height:
321
);
bool
isAsync
=
false
;
resizeImage
.
obtainKey
(
ImageConfiguration
.
empty
).
then
((
Object
key
)
{
expect
(
isAsync
,
true
);
});
isAsync
=
true
;
expect
(
isAsync
,
true
);
});
}
Future
<
Size
>
_resolveAndGetSize
(
ImageProvider
imageProvider
,
{
ImageConfiguration
configuration
=
ImageConfiguration
.
empty
})
async
{
final
ImageStream
stream
=
imageProvider
.
resolve
(
configuration
);
final
Completer
<
Size
>
completer
=
Completer
<
Size
>();
final
ImageStreamListener
listener
=
ImageStreamListener
((
ImageInfo
image
,
bool
synchronousCall
)
{
final
int
height
=
image
.
image
.
height
;
final
int
width
=
image
.
image
.
width
;
completer
.
complete
(
Size
(
width
.
toDouble
(),
height
.
toDouble
()));
}
);
stream
.
addListener
(
listener
);
return
await
completer
.
future
;
}
// This version of MemoryImage guarantees obtainKey returns a future that has not been
// completed synchronously.
class
_AsyncKeyMemoryImage
extends
MemoryImage
{
const
_AsyncKeyMemoryImage
(
Uint8List
bytes
)
:
super
(
bytes
);
@override
Future
<
MemoryImage
>
obtainKey
(
ImageConfiguration
configuration
)
{
return
Future
<
MemoryImage
>(()
=>
this
);
}
}
packages/flutter/test/painting/image_provider_test.dart
View file @
3cb79079
This diff is collapsed.
Click to expand it.
packages/flutter/test/rendering/rendering_tester.dart
View file @
3cb79079
...
...
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'dart:async'
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/gestures.dart'
;
import
'package:flutter/rendering.dart'
;
...
...
@@ -19,7 +21,15 @@ class TestRenderingFlutterBinding extends BindingBase with SchedulerBinding, Ser
/// while drawing the frame. If [onErrors] is null and [FlutterError] caught at least
/// one error, this function fails the test. A test may override [onErrors] and
/// inspect errors using [takeFlutterErrorDetails].
TestRenderingFlutterBinding
({
this
.
onErrors
});
///
/// Errors caught between frames will cause the test to fail unless
/// [FlutterError.onError] has been overridden.
TestRenderingFlutterBinding
({
this
.
onErrors
})
{
FlutterError
.
onError
=
(
FlutterErrorDetails
details
)
{
FlutterError
.
dumpErrorToConsole
(
details
);
Zone
.
current
.
parent
.
handleUncaughtError
(
details
.
exception
,
details
.
stack
);
};
}
final
List
<
FlutterErrorDetails
>
_errors
=
<
FlutterErrorDetails
>[];
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment