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
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 {
...
@@ -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.
// Avoid adding unnecessary callbacks to the completer.
_liveImages
.
putIfAbsent
(
key
,
()
{
_liveImages
.
putIfAbsent
(
key
,
()
{
assert
(
debugPutOk
);
// Even if no callers to ImageProvider.resolve have listened to the stream,
// 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
// the cache is listening to the stream and will remove itself once the
// image completes to move it from pending to keepAlive.
// image completes to move it from pending to keepAlive.
...
@@ -400,10 +399,6 @@ class ImageCache {
...
@@ -400,10 +399,6 @@ class ImageCache {
imageSize
,
imageSize
,
()
=>
_liveImages
.
remove
(
key
),
()
=>
_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
);
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> {
...
@@ -347,10 +347,10 @@ abstract class ImageProvider<T> {
stack:
stack
,
stack:
stack
,
context:
ErrorDescription
(
'while resolving an image'
),
context:
ErrorDescription
(
'while resolving an image'
),
silent:
true
,
// could be a network error or whatnot
silent:
true
,
// could be a network error or whatnot
informationCollector:
collector
informationCollector:
collector
,
);
);
},
},
);
);
return
stream
;
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';
...
@@ -9,71 +9,70 @@ import '../rendering/rendering_tester.dart';
import
'mocks_for_image_cache.dart'
;
import
'mocks_for_image_cache.dart'
;
void
main
(
)
{
void
main
(
)
{
TestRenderingFlutterBinding
();
// initializes the imageCache
TestRenderingFlutterBinding
();
group
(
ImageCache
,
()
{
tearDown
(()
{
imageCache
.
clear
();
imageCache
.
maximumSize
=
1000
;
imageCache
.
maximumSizeBytes
=
10485760
;
});
test
(
'Image cache resizing based on count'
,
()
async
{
tearDown
(()
{
imageCache
.
maximumSize
=
2
;
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
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
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
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
;
final
TestImageInfo
d
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
4
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
expect
(
a
.
value
,
equals
(
1
));
expect
(
a
.
value
,
equals
(
1
));
expect
(
b
.
value
,
equals
(
2
));
expect
(
b
.
value
,
equals
(
2
));
expect
(
c
.
value
,
equals
(
3
));
expect
(
c
.
value
,
equals
(
3
));
expect
(
d
.
value
,
equals
(
4
));
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
;
final
TestImageInfo
e
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
5
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
expect
(
e
.
value
,
equals
(
5
));
expect
(
e
.
value
,
equals
(
5
));
final
TestImageInfo
f
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
6
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
final
TestImageInfo
f
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
6
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
expect
(
f
.
value
,
equals
(
6
));
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
;
final
TestImageInfo
g
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
7
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
expect
(
g
.
value
,
equals
(
7
));
expect
(
g
.
value
,
equals
(
7
));
final
TestImageInfo
h
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
8
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
final
TestImageInfo
h
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
8
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
expect
(
h
.
value
,
equals
(
7
));
expect
(
h
.
value
,
equals
(
7
));
});
});
test
(
'Image cache resizing based on size'
,
()
async
{
test
(
'Image cache resizing based on size'
,
()
async
{
const
TestImage
testImage
=
TestImage
(
width:
8
,
height:
8
);
// 256 B.
const
TestImage
testImage
=
TestImage
(
width:
8
,
height:
8
);
// 256 B.
imageCache
.
maximumSizeBytes
=
256
*
2
;
imageCache
.
maximumSizeBytes
=
256
*
2
;
final
TestImageInfo
a
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
1
,
image:
testImage
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
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
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
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
;
final
TestImageInfo
d
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
4
,
image:
testImage
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
expect
(
a
.
value
,
equals
(
1
));
expect
(
a
.
value
,
equals
(
1
));
expect
(
b
.
value
,
equals
(
2
));
expect
(
b
.
value
,
equals
(
2
));
expect
(
c
.
value
,
equals
(
3
));
expect
(
c
.
value
,
equals
(
3
));
expect
(
d
.
value
,
equals
(
4
));
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
;
final
TestImageInfo
e
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
5
,
image:
testImage
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
expect
(
e
.
value
,
equals
(
5
));
expect
(
e
.
value
,
equals
(
5
));
final
TestImageInfo
f
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
6
,
image:
testImage
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
final
TestImageInfo
f
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
6
,
image:
testImage
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
expect
(
f
.
value
,
equals
(
6
));
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
;
final
TestImageInfo
g
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
7
,
image:
testImage
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
expect
(
g
.
value
,
equals
(
7
));
expect
(
g
.
value
,
equals
(
7
));
final
TestImageInfo
h
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
8
,
image:
testImage
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
final
TestImageInfo
h
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
8
,
image:
testImage
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
expect
(
h
.
value
,
equals
(
7
));
expect
(
h
.
value
,
equals
(
7
));
});
});
});
}
}
packages/flutter/test/painting/image_cache_test.dart
View file @
3cb79079
...
@@ -9,475 +9,471 @@ import '../rendering/rendering_tester.dart';
...
@@ -9,475 +9,471 @@ import '../rendering/rendering_tester.dart';
import
'mocks_for_image_cache.dart'
;
import
'mocks_for_image_cache.dart'
;
void
main
(
)
{
void
main
(
)
{
group
(
'ImageCache'
,
()
{
TestRenderingFlutterBinding
();
setUpAll
(()
{
TestRenderingFlutterBinding
();
// initializes the imageCache
});
tearDown
(()
{
tearDown
(()
{
imageCache
.
clear
();
imageCache
.
clear
();
imageCache
.
clearLiveImages
();
imageCache
.
clearLiveImages
();
imageCache
.
maximumSize
=
1000
;
imageCache
.
maximumSize
=
1000
;
imageCache
.
maximumSizeBytes
=
10485760
;
imageCache
.
maximumSizeBytes
=
10485760
;
});
});
test
(
'maintains cache size'
,
()
async
{
test
(
'maintains cache size'
,
()
async
{
imageCache
.
maximumSize
=
3
;
imageCache
.
maximumSize
=
3
;
final
TestImageInfo
a
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
1
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
final
TestImageInfo
a
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
1
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
expect
(
a
.
value
,
equals
(
1
));
expect
(
a
.
value
,
equals
(
1
));
final
TestImageInfo
b
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
2
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
final
TestImageInfo
b
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
2
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
expect
(
b
.
value
,
equals
(
1
));
expect
(
b
.
value
,
equals
(
1
));
final
TestImageInfo
c
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
3
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
final
TestImageInfo
c
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
3
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
expect
(
c
.
value
,
equals
(
1
));
expect
(
c
.
value
,
equals
(
1
));
final
TestImageInfo
d
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
4
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
final
TestImageInfo
d
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
4
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
expect
(
d
.
value
,
equals
(
1
));
expect
(
d
.
value
,
equals
(
1
));
final
TestImageInfo
e
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
5
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
final
TestImageInfo
e
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
5
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
expect
(
e
.
value
,
equals
(
1
));
expect
(
e
.
value
,
equals
(
1
));
final
TestImageInfo
f
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
6
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
final
TestImageInfo
f
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
6
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
expect
(
f
.
value
,
equals
(
1
));
expect
(
f
.
value
,
equals
(
1
));
expect
(
f
,
equals
(
a
));
expect
(
f
,
equals
(
a
));
// cache still only has one entry in it: 1(1)
// cache still only has one entry in it: 1(1)
final
TestImageInfo
g
=
await
extractOneFrame
(
const
TestImageProvider
(
2
,
7
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
final
TestImageInfo
g
=
await
extractOneFrame
(
const
TestImageProvider
(
2
,
7
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
expect
(
g
.
value
,
equals
(
7
));
expect
(
g
.
value
,
equals
(
7
));
// cache has two entries in it: 1(1), 2(7)
// cache has two entries in it: 1(1), 2(7)
final
TestImageInfo
h
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
8
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
final
TestImageInfo
h
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
8
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
expect
(
h
.
value
,
equals
(
1
));
expect
(
h
.
value
,
equals
(
1
));
// cache still has two entries in it: 2(7), 1(1)
// cache still has two entries in it: 2(7), 1(1)
final
TestImageInfo
i
=
await
extractOneFrame
(
const
TestImageProvider
(
3
,
9
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
final
TestImageInfo
i
=
await
extractOneFrame
(
const
TestImageProvider
(
3
,
9
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
expect
(
i
.
value
,
equals
(
9
));
expect
(
i
.
value
,
equals
(
9
));
// cache has three entries in it: 2(7), 1(1), 3(9)
// cache has three entries in it: 2(7), 1(1), 3(9)
final
TestImageInfo
j
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
10
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
final
TestImageInfo
j
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
10
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
expect
(
j
.
value
,
equals
(
1
));
expect
(
j
.
value
,
equals
(
1
));
// cache still has three entries in it: 2(7), 3(9), 1(1)
// cache still has three entries in it: 2(7), 3(9), 1(1)
final
TestImageInfo
k
=
await
extractOneFrame
(
const
TestImageProvider
(
4
,
11
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
final
TestImageInfo
k
=
await
extractOneFrame
(
const
TestImageProvider
(
4
,
11
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
expect
(
k
.
value
,
equals
(
11
));
expect
(
k
.
value
,
equals
(
11
));
// cache has three entries: 3(9), 1(1), 4(11)
// cache has three entries: 3(9), 1(1), 4(11)
final
TestImageInfo
l
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
12
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
final
TestImageInfo
l
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
12
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
expect
(
l
.
value
,
equals
(
1
));
expect
(
l
.
value
,
equals
(
1
));
// cache has three entries: 3(9), 4(11), 1(1)
// cache has three entries: 3(9), 4(11), 1(1)
final
TestImageInfo
m
=
await
extractOneFrame
(
const
TestImageProvider
(
2
,
13
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
final
TestImageInfo
m
=
await
extractOneFrame
(
const
TestImageProvider
(
2
,
13
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
expect
(
m
.
value
,
equals
(
13
));
expect
(
m
.
value
,
equals
(
13
));
// cache has three entries: 4(11), 1(1), 2(13)
// cache has three entries: 4(11), 1(1), 2(13)
final
TestImageInfo
n
=
await
extractOneFrame
(
const
TestImageProvider
(
3
,
14
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
final
TestImageInfo
n
=
await
extractOneFrame
(
const
TestImageProvider
(
3
,
14
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
expect
(
n
.
value
,
equals
(
14
));
expect
(
n
.
value
,
equals
(
14
));
// cache has three entries: 1(1), 2(13), 3(14)
// cache has three entries: 1(1), 2(13), 3(14)
final
TestImageInfo
o
=
await
extractOneFrame
(
const
TestImageProvider
(
4
,
15
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
final
TestImageInfo
o
=
await
extractOneFrame
(
const
TestImageProvider
(
4
,
15
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
expect
(
o
.
value
,
equals
(
15
));
expect
(
o
.
value
,
equals
(
15
));
// cache has three entries: 2(13), 3(14), 4(15)
// cache has three entries: 2(13), 3(14), 4(15)
final
TestImageInfo
p
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
16
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
final
TestImageInfo
p
=
await
extractOneFrame
(
const
TestImageProvider
(
1
,
16
).
resolve
(
ImageConfiguration
.
empty
))
as
TestImageInfo
;
expect
(
p
.
value
,
equals
(
16
));
expect
(
p
.
value
,
equals
(
16
));
// cache has three entries: 3(14), 4(15), 1(16)
// cache has three entries: 3(14), 4(15), 1(16)
});
});
test
(
'clear removes all images and resets cache size'
,
()
async
{
test
(
'clear removes all images and resets cache size'
,
()
async
{
const
TestImage
testImage
=
TestImage
(
width:
8
,
height:
8
);
const
TestImage
testImage
=
TestImage
(
width:
8
,
height:
8
);
expect
(
imageCache
.
currentSize
,
0
);
expect
(
imageCache
.
currentSize
,
0
);
expect
(
imageCache
.
currentSizeBytes
,
0
);
expect
(
imageCache
.
currentSizeBytes
,
0
);
await
extractOneFrame
(
const
TestImageProvider
(
1
,
1
,
image:
testImage
).
resolve
(
ImageConfiguration
.
empty
));
await
extractOneFrame
(
const
TestImageProvider
(
1
,
1
,
image:
testImage
).
resolve
(
ImageConfiguration
.
empty
));
await
extractOneFrame
(
const
TestImageProvider
(
2
,
2
,
image:
testImage
).
resolve
(
ImageConfiguration
.
empty
));
await
extractOneFrame
(
const
TestImageProvider
(
2
,
2
,
image:
testImage
).
resolve
(
ImageConfiguration
.
empty
));
expect
(
imageCache
.
currentSize
,
2
);
expect
(
imageCache
.
currentSize
,
2
);
expect
(
imageCache
.
currentSizeBytes
,
256
*
2
);
expect
(
imageCache
.
currentSizeBytes
,
256
*
2
);
imageCache
.
clear
();
imageCache
.
clear
();
expect
(
imageCache
.
currentSize
,
0
);
expect
(
imageCache
.
currentSize
,
0
);
expect
(
imageCache
.
currentSizeBytes
,
0
);
expect
(
imageCache
.
currentSizeBytes
,
0
);
});
});
test
(
'evicts individual images'
,
()
async
{
test
(
'evicts individual images'
,
()
async
{
const
TestImage
testImage
=
TestImage
(
width:
8
,
height:
8
);
const
TestImage
testImage
=
TestImage
(
width:
8
,
height:
8
);
await
extractOneFrame
(
const
TestImageProvider
(
1
,
1
,
image:
testImage
).
resolve
(
ImageConfiguration
.
empty
));
await
extractOneFrame
(
const
TestImageProvider
(
1
,
1
,
image:
testImage
).
resolve
(
ImageConfiguration
.
empty
));
await
extractOneFrame
(
const
TestImageProvider
(
2
,
2
,
image:
testImage
).
resolve
(
ImageConfiguration
.
empty
));
await
extractOneFrame
(
const
TestImageProvider
(
2
,
2
,
image:
testImage
).
resolve
(
ImageConfiguration
.
empty
));
expect
(
imageCache
.
currentSize
,
2
);
expect
(
imageCache
.
currentSize
,
2
);
expect
(
imageCache
.
currentSizeBytes
,
256
*
2
);
expect
(
imageCache
.
currentSizeBytes
,
256
*
2
);
expect
(
imageCache
.
evict
(
1
),
true
);
expect
(
imageCache
.
evict
(
1
),
true
);
expect
(
imageCache
.
currentSize
,
1
);
expect
(
imageCache
.
currentSize
,
1
);
expect
(
imageCache
.
currentSizeBytes
,
256
);
expect
(
imageCache
.
currentSizeBytes
,
256
);
});
});
test
(
'Do not cache large images'
,
()
async
{
test
(
'Do not cache large images'
,
()
async
{
const
TestImage
testImage
=
TestImage
(
width:
8
,
height:
8
);
const
TestImage
testImage
=
TestImage
(
width:
8
,
height:
8
);
imageCache
.
maximumSizeBytes
=
1
;
imageCache
.
maximumSizeBytes
=
1
;
await
extractOneFrame
(
const
TestImageProvider
(
1
,
1
,
image:
testImage
).
resolve
(
ImageConfiguration
.
empty
));
await
extractOneFrame
(
const
TestImageProvider
(
1
,
1
,
image:
testImage
).
resolve
(
ImageConfiguration
.
empty
));
expect
(
imageCache
.
currentSize
,
0
);
expect
(
imageCache
.
currentSize
,
0
);
expect
(
imageCache
.
currentSizeBytes
,
0
);
expect
(
imageCache
.
currentSizeBytes
,
0
);
expect
(
imageCache
.
maximumSizeBytes
,
1
);
expect
(
imageCache
.
maximumSizeBytes
,
1
);
});
});
test
(
'Returns null if an error is caught resolving an image'
,
()
{
test
(
'Returns null if an error is caught resolving an image'
,
()
{
final
ErrorImageProvider
errorImage
=
ErrorImageProvider
();
final
ErrorImageProvider
errorImage
=
ErrorImageProvider
();
expect
(()
=>
imageCache
.
putIfAbsent
(
errorImage
,
()
=>
errorImage
.
load
(
errorImage
,
null
)),
throwsA
(
isA
<
Error
>()));
expect
(()
=>
imageCache
.
putIfAbsent
(
errorImage
,
()
=>
errorImage
.
load
(
errorImage
,
null
)),
throwsA
(
isA
<
Error
>()));
bool
caughtError
=
false
;
bool
caughtError
=
false
;
final
ImageStreamCompleter
result
=
imageCache
.
putIfAbsent
(
errorImage
,
()
=>
errorImage
.
load
(
errorImage
,
null
),
onError:
(
dynamic
error
,
StackTrace
stackTrace
)
{
final
ImageStreamCompleter
result
=
imageCache
.
putIfAbsent
(
errorImage
,
()
=>
errorImage
.
load
(
errorImage
,
null
),
onError:
(
dynamic
error
,
StackTrace
stackTrace
)
{
caughtError
=
true
;
caughtError
=
true
;
});
expect
(
result
,
null
);
expect
(
caughtError
,
true
);
});
});
expect
(
result
,
null
);
expect
(
caughtError
,
true
);
});
test
(
'already pending image is returned when it is put into the cache again'
,
()
async
{
test
(
'already pending image is returned when it is put into the cache again'
,
()
async
{
const
TestImage
testImage
=
TestImage
(
width:
8
,
height:
8
);
const
TestImage
testImage
=
TestImage
(
width:
8
,
height:
8
);
final
TestImageStreamCompleter
completer1
=
TestImageStreamCompleter
();
final
TestImageStreamCompleter
completer1
=
TestImageStreamCompleter
();
final
TestImageStreamCompleter
completer2
=
TestImageStreamCompleter
();
final
TestImageStreamCompleter
completer2
=
TestImageStreamCompleter
();
final
TestImageStreamCompleter
resultingCompleter1
=
imageCache
.
putIfAbsent
(
testImage
,
()
{
final
TestImageStreamCompleter
resultingCompleter1
=
imageCache
.
putIfAbsent
(
testImage
,
()
{
return
completer1
;
return
completer1
;
})
as
TestImageStreamCompleter
;
})
as
TestImageStreamCompleter
;
final
TestImageStreamCompleter
resultingCompleter2
=
imageCache
.
putIfAbsent
(
testImage
,
()
{
final
TestImageStreamCompleter
resultingCompleter2
=
imageCache
.
putIfAbsent
(
testImage
,
()
{
return
completer2
;
return
completer2
;
})
as
TestImageStreamCompleter
;
})
as
TestImageStreamCompleter
;
expect
(
resultingCompleter1
,
completer1
);
expect
(
resultingCompleter1
,
completer1
);
expect
(
resultingCompleter2
,
completer1
);
expect
(
resultingCompleter2
,
completer1
);
});
});
test
(
'pending image is removed when cache is cleared'
,
()
async
{
test
(
'pending image is removed when cache is cleared'
,
()
async
{
const
TestImage
testImage
=
TestImage
(
width:
8
,
height:
8
);
const
TestImage
testImage
=
TestImage
(
width:
8
,
height:
8
);
final
TestImageStreamCompleter
completer1
=
TestImageStreamCompleter
();
final
TestImageStreamCompleter
completer1
=
TestImageStreamCompleter
();
final
TestImageStreamCompleter
completer2
=
TestImageStreamCompleter
();
final
TestImageStreamCompleter
completer2
=
TestImageStreamCompleter
();
final
TestImageStreamCompleter
resultingCompleter1
=
imageCache
.
putIfAbsent
(
testImage
,
()
{
final
TestImageStreamCompleter
resultingCompleter1
=
imageCache
.
putIfAbsent
(
testImage
,
()
{
return
completer1
;
return
completer1
;
})
as
TestImageStreamCompleter
;
})
as
TestImageStreamCompleter
;
expect
(
imageCache
.
statusForKey
(
testImage
).
pending
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
pending
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
live
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
live
,
true
);
imageCache
.
clear
();
imageCache
.
clear
();
expect
(
imageCache
.
statusForKey
(
testImage
).
pending
,
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
pending
,
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
live
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
live
,
true
);
imageCache
.
clearLiveImages
();
imageCache
.
clearLiveImages
();
expect
(
imageCache
.
statusForKey
(
testImage
).
pending
,
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
pending
,
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
live
,
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
live
,
false
);
final
TestImageStreamCompleter
resultingCompleter2
=
imageCache
.
putIfAbsent
(
testImage
,
()
{
final
TestImageStreamCompleter
resultingCompleter2
=
imageCache
.
putIfAbsent
(
testImage
,
()
{
return
completer2
;
return
completer2
;
})
as
TestImageStreamCompleter
;
})
as
TestImageStreamCompleter
;
expect
(
resultingCompleter1
,
completer1
);
expect
(
resultingCompleter1
,
completer1
);
expect
(
resultingCompleter2
,
completer2
);
expect
(
resultingCompleter2
,
completer2
);
});
});
test
(
'pending image is removed when image is evicted'
,
()
async
{
test
(
'pending image is removed when image is evicted'
,
()
async
{
const
TestImage
testImage
=
TestImage
(
width:
8
,
height:
8
);
const
TestImage
testImage
=
TestImage
(
width:
8
,
height:
8
);
final
TestImageStreamCompleter
completer1
=
TestImageStreamCompleter
();
final
TestImageStreamCompleter
completer1
=
TestImageStreamCompleter
();
final
TestImageStreamCompleter
completer2
=
TestImageStreamCompleter
();
final
TestImageStreamCompleter
completer2
=
TestImageStreamCompleter
();
final
TestImageStreamCompleter
resultingCompleter1
=
imageCache
.
putIfAbsent
(
testImage
,
()
{
final
TestImageStreamCompleter
resultingCompleter1
=
imageCache
.
putIfAbsent
(
testImage
,
()
{
return
completer1
;
return
completer1
;
})
as
TestImageStreamCompleter
;
})
as
TestImageStreamCompleter
;
imageCache
.
evict
(
testImage
);
imageCache
.
evict
(
testImage
);
final
TestImageStreamCompleter
resultingCompleter2
=
imageCache
.
putIfAbsent
(
testImage
,
()
{
final
TestImageStreamCompleter
resultingCompleter2
=
imageCache
.
putIfAbsent
(
testImage
,
()
{
return
completer2
;
return
completer2
;
})
as
TestImageStreamCompleter
;
})
as
TestImageStreamCompleter
;
expect
(
resultingCompleter1
,
completer1
);
expect
(
resultingCompleter1
,
completer1
);
expect
(
resultingCompleter2
,
completer2
);
expect
(
resultingCompleter2
,
completer2
);
});
});
test
(
"failed image can successfully be removed from the cache's pending images"
,
()
async
{
test
(
"failed image can successfully be removed from the cache's pending images"
,
()
async
{
const
TestImage
testImage
=
TestImage
(
width:
8
,
height:
8
);
const
TestImage
testImage
=
TestImage
(
width:
8
,
height:
8
);
const
FailingTestImageProvider
(
1
,
1
,
image:
testImage
)
const
FailingTestImageProvider
(
1
,
1
,
image:
testImage
)
.
resolve
(
ImageConfiguration
.
empty
)
.
resolve
(
ImageConfiguration
.
empty
)
.
addListener
(
ImageStreamListener
(
.
addListener
(
ImageStreamListener
(
(
ImageInfo
image
,
bool
synchronousCall
)
{
},
(
ImageInfo
image
,
bool
synchronousCall
)
{
},
onError:
(
dynamic
exception
,
StackTrace
stackTrace
)
{
onError:
(
dynamic
exception
,
StackTrace
stackTrace
)
{
final
bool
evicationResult
=
imageCache
.
evict
(
1
);
final
bool
evicationResult
=
imageCache
.
evict
(
1
);
expect
(
evicationResult
,
isTrue
);
expect
(
evicationResult
,
isTrue
);
},
},
));
));
});
});
test
(
'containsKey - pending'
,
()
async
{
test
(
'containsKey - pending'
,
()
async
{
const
TestImage
testImage
=
TestImage
(
width:
8
,
height:
8
);
const
TestImage
testImage
=
TestImage
(
width:
8
,
height:
8
);
final
TestImageStreamCompleter
completer1
=
TestImageStreamCompleter
();
final
TestImageStreamCompleter
completer1
=
TestImageStreamCompleter
();
final
TestImageStreamCompleter
resultingCompleter1
=
imageCache
.
putIfAbsent
(
testImage
,
()
{
final
TestImageStreamCompleter
resultingCompleter1
=
imageCache
.
putIfAbsent
(
testImage
,
()
{
return
completer1
;
return
completer1
;
})
as
TestImageStreamCompleter
;
})
as
TestImageStreamCompleter
;
expect
(
resultingCompleter1
,
completer1
);
expect
(
resultingCompleter1
,
completer1
);
expect
(
imageCache
.
containsKey
(
testImage
),
true
);
expect
(
imageCache
.
containsKey
(
testImage
),
true
);
});
});
test
(
'containsKey - completed'
,
()
async
{
test
(
'containsKey - completed'
,
()
async
{
const
TestImage
testImage
=
TestImage
(
width:
8
,
height:
8
);
const
TestImage
testImage
=
TestImage
(
width:
8
,
height:
8
);
final
TestImageStreamCompleter
completer1
=
TestImageStreamCompleter
();
final
TestImageStreamCompleter
completer1
=
TestImageStreamCompleter
();
final
TestImageStreamCompleter
resultingCompleter1
=
imageCache
.
putIfAbsent
(
testImage
,
()
{
final
TestImageStreamCompleter
resultingCompleter1
=
imageCache
.
putIfAbsent
(
testImage
,
()
{
return
completer1
;
return
completer1
;
})
as
TestImageStreamCompleter
;
})
as
TestImageStreamCompleter
;
// Mark as complete
// Mark as complete
completer1
.
testSetImage
(
testImage
);
completer1
.
testSetImage
(
testImage
);
expect
(
resultingCompleter1
,
completer1
);
expect
(
resultingCompleter1
,
completer1
);
expect
(
imageCache
.
containsKey
(
testImage
),
true
);
expect
(
imageCache
.
containsKey
(
testImage
),
true
);
});
});
test
(
'putIfAbsent updates LRU properties of a live image'
,
()
async
{
test
(
'putIfAbsent updates LRU properties of a live image'
,
()
async
{
imageCache
.
maximumSize
=
1
;
imageCache
.
maximumSize
=
1
;
const
TestImage
testImage
=
TestImage
(
width:
8
,
height:
8
);
const
TestImage
testImage
=
TestImage
(
width:
8
,
height:
8
);
const
TestImage
testImage2
=
TestImage
(
width:
10
,
height:
10
);
const
TestImage
testImage2
=
TestImage
(
width:
10
,
height:
10
);
final
TestImageStreamCompleter
completer1
=
TestImageStreamCompleter
()..
testSetImage
(
testImage
);
final
TestImageStreamCompleter
completer1
=
TestImageStreamCompleter
()..
testSetImage
(
testImage
);
final
TestImageStreamCompleter
completer2
=
TestImageStreamCompleter
()..
testSetImage
(
testImage2
);
final
TestImageStreamCompleter
completer2
=
TestImageStreamCompleter
()..
testSetImage
(
testImage2
);
completer1
.
addListener
(
ImageStreamListener
((
ImageInfo
info
,
bool
syncCall
)
{}));
completer1
.
addListener
(
ImageStreamListener
((
ImageInfo
info
,
bool
syncCall
)
{}));
final
TestImageStreamCompleter
resultingCompleter1
=
imageCache
.
putIfAbsent
(
testImage
,
()
{
final
TestImageStreamCompleter
resultingCompleter1
=
imageCache
.
putIfAbsent
(
testImage
,
()
{
return
completer1
;
return
completer1
;
})
as
TestImageStreamCompleter
;
})
as
TestImageStreamCompleter
;
expect
(
imageCache
.
statusForKey
(
testImage
).
pending
,
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
pending
,
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
keepAlive
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
keepAlive
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
live
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
live
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage2
).
untracked
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage2
).
untracked
,
true
);
final
TestImageStreamCompleter
resultingCompleter2
=
imageCache
.
putIfAbsent
(
testImage2
,
()
{
final
TestImageStreamCompleter
resultingCompleter2
=
imageCache
.
putIfAbsent
(
testImage2
,
()
{
return
completer2
;
return
completer2
;
})
as
TestImageStreamCompleter
;
})
as
TestImageStreamCompleter
;
expect
(
imageCache
.
statusForKey
(
testImage
).
pending
,
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
pending
,
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
keepAlive
,
false
);
// evicted
expect
(
imageCache
.
statusForKey
(
testImage
).
keepAlive
,
false
);
// evicted
expect
(
imageCache
.
statusForKey
(
testImage
).
live
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
live
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage2
).
pending
,
false
);
expect
(
imageCache
.
statusForKey
(
testImage2
).
pending
,
false
);
expect
(
imageCache
.
statusForKey
(
testImage2
).
keepAlive
,
true
);
// took the LRU spot.
expect
(
imageCache
.
statusForKey
(
testImage2
).
keepAlive
,
true
);
// took the LRU spot.
expect
(
imageCache
.
statusForKey
(
testImage2
).
live
,
false
);
// no listeners
expect
(
imageCache
.
statusForKey
(
testImage2
).
live
,
false
);
// no listeners
expect
(
resultingCompleter1
,
completer1
);
expect
(
resultingCompleter1
,
completer1
);
expect
(
resultingCompleter2
,
completer2
);
expect
(
resultingCompleter2
,
completer2
);
});
});
test
(
'Live image cache avoids leaks of unlistened streams'
,
()
async
{
test
(
'Live image cache avoids leaks of unlistened streams'
,
()
async
{
imageCache
.
maximumSize
=
3
;
imageCache
.
maximumSize
=
3
;
const
TestImageProvider
(
1
,
1
).
resolve
(
ImageConfiguration
.
empty
);
const
TestImageProvider
(
1
,
1
).
resolve
(
ImageConfiguration
.
empty
);
const
TestImageProvider
(
2
,
2
).
resolve
(
ImageConfiguration
.
empty
);
const
TestImageProvider
(
2
,
2
).
resolve
(
ImageConfiguration
.
empty
);
const
TestImageProvider
(
3
,
3
).
resolve
(
ImageConfiguration
.
empty
);
const
TestImageProvider
(
3
,
3
).
resolve
(
ImageConfiguration
.
empty
);
const
TestImageProvider
(
4
,
4
).
resolve
(
ImageConfiguration
.
empty
);
const
TestImageProvider
(
4
,
4
).
resolve
(
ImageConfiguration
.
empty
);
const
TestImageProvider
(
5
,
5
).
resolve
(
ImageConfiguration
.
empty
);
const
TestImageProvider
(
5
,
5
).
resolve
(
ImageConfiguration
.
empty
);
const
TestImageProvider
(
6
,
6
).
resolve
(
ImageConfiguration
.
empty
);
const
TestImageProvider
(
6
,
6
).
resolve
(
ImageConfiguration
.
empty
);
// wait an event loop to let image resolution process.
// wait an event loop to let image resolution process.
await
null
;
await
null
;
expect
(
imageCache
.
currentSize
,
3
);
expect
(
imageCache
.
currentSize
,
3
);
expect
(
imageCache
.
liveImageCount
,
0
);
expect
(
imageCache
.
liveImageCount
,
0
);
});
});
test
(
'Disabled image cache does not leak live images'
,
()
async
{
test
(
'Disabled image cache does not leak live images'
,
()
async
{
imageCache
.
maximumSize
=
0
;
imageCache
.
maximumSize
=
0
;
const
TestImageProvider
(
1
,
1
).
resolve
(
ImageConfiguration
.
empty
);
const
TestImageProvider
(
1
,
1
).
resolve
(
ImageConfiguration
.
empty
);
const
TestImageProvider
(
2
,
2
).
resolve
(
ImageConfiguration
.
empty
);
const
TestImageProvider
(
2
,
2
).
resolve
(
ImageConfiguration
.
empty
);
const
TestImageProvider
(
3
,
3
).
resolve
(
ImageConfiguration
.
empty
);
const
TestImageProvider
(
3
,
3
).
resolve
(
ImageConfiguration
.
empty
);
const
TestImageProvider
(
4
,
4
).
resolve
(
ImageConfiguration
.
empty
);
const
TestImageProvider
(
4
,
4
).
resolve
(
ImageConfiguration
.
empty
);
const
TestImageProvider
(
5
,
5
).
resolve
(
ImageConfiguration
.
empty
);
const
TestImageProvider
(
5
,
5
).
resolve
(
ImageConfiguration
.
empty
);
const
TestImageProvider
(
6
,
6
).
resolve
(
ImageConfiguration
.
empty
);
const
TestImageProvider
(
6
,
6
).
resolve
(
ImageConfiguration
.
empty
);
// wait an event loop to let image resolution process.
// wait an event loop to let image resolution process.
await
null
;
await
null
;
expect
(
imageCache
.
currentSize
,
0
);
expect
(
imageCache
.
currentSize
,
0
);
expect
(
imageCache
.
liveImageCount
,
0
);
expect
(
imageCache
.
liveImageCount
,
0
);
});
});
test
(
'Evicting a pending image clears the live image by default'
,
()
async
{
test
(
'Evicting a pending image clears the live image by default'
,
()
async
{
const
TestImage
testImage
=
TestImage
(
width:
8
,
height:
8
);
const
TestImage
testImage
=
TestImage
(
width:
8
,
height:
8
);
final
TestImageStreamCompleter
completer1
=
TestImageStreamCompleter
();
final
TestImageStreamCompleter
completer1
=
TestImageStreamCompleter
();
imageCache
.
putIfAbsent
(
testImage
,
()
=>
completer1
);
imageCache
.
putIfAbsent
(
testImage
,
()
=>
completer1
);
expect
(
imageCache
.
statusForKey
(
testImage
).
pending
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
pending
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
live
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
live
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
keepAlive
,
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
keepAlive
,
false
);
imageCache
.
evict
(
testImage
);
imageCache
.
evict
(
testImage
);
expect
(
imageCache
.
statusForKey
(
testImage
).
untracked
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
untracked
,
true
);
});
});
test
(
'Evicting a pending image does clear the live image when includeLive is false and only cache listening'
,
()
async
{
test
(
'Evicting a pending image does clear the live image when includeLive is false and only cache listening'
,
()
async
{
const
TestImage
testImage
=
TestImage
(
width:
8
,
height:
8
);
const
TestImage
testImage
=
TestImage
(
width:
8
,
height:
8
);
final
TestImageStreamCompleter
completer1
=
TestImageStreamCompleter
();
final
TestImageStreamCompleter
completer1
=
TestImageStreamCompleter
();
imageCache
.
putIfAbsent
(
testImage
,
()
=>
completer1
);
imageCache
.
putIfAbsent
(
testImage
,
()
=>
completer1
);
expect
(
imageCache
.
statusForKey
(
testImage
).
pending
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
pending
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
live
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
live
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
keepAlive
,
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
keepAlive
,
false
);
imageCache
.
evict
(
testImage
,
includeLive:
false
);
imageCache
.
evict
(
testImage
,
includeLive:
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
pending
,
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
pending
,
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
live
,
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
live
,
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
keepAlive
,
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
keepAlive
,
false
);
});
});
test
(
'Evicting a pending image does clear the live image when includeLive is false and some other listener'
,
()
async
{
test
(
'Evicting a pending image does clear the live image when includeLive is false and some other listener'
,
()
async
{
const
TestImage
testImage
=
TestImage
(
width:
8
,
height:
8
);
const
TestImage
testImage
=
TestImage
(
width:
8
,
height:
8
);
final
TestImageStreamCompleter
completer1
=
TestImageStreamCompleter
();
final
TestImageStreamCompleter
completer1
=
TestImageStreamCompleter
();
imageCache
.
putIfAbsent
(
testImage
,
()
=>
completer1
);
imageCache
.
putIfAbsent
(
testImage
,
()
=>
completer1
);
expect
(
imageCache
.
statusForKey
(
testImage
).
pending
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
pending
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
live
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
live
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
keepAlive
,
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
keepAlive
,
false
);
completer1
.
addListener
(
ImageStreamListener
((
_
,
__
)
{}));
completer1
.
addListener
(
ImageStreamListener
((
_
,
__
)
{}));
imageCache
.
evict
(
testImage
,
includeLive:
false
);
imageCache
.
evict
(
testImage
,
includeLive:
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
pending
,
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
pending
,
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
live
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
live
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
keepAlive
,
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
keepAlive
,
false
);
});
});
test
(
'Evicting a completed image does clear the live image by default'
,
()
async
{
test
(
'Evicting a completed image does clear the live image by default'
,
()
async
{
const
TestImage
testImage
=
TestImage
(
width:
8
,
height:
8
);
const
TestImage
testImage
=
TestImage
(
width:
8
,
height:
8
);
final
TestImageStreamCompleter
completer1
=
TestImageStreamCompleter
()
final
TestImageStreamCompleter
completer1
=
TestImageStreamCompleter
()
..
testSetImage
(
testImage
)
..
testSetImage
(
testImage
)
..
addListener
(
ImageStreamListener
((
ImageInfo
info
,
bool
syncCall
)
{}));
..
addListener
(
ImageStreamListener
((
ImageInfo
info
,
bool
syncCall
)
{}));
imageCache
.
putIfAbsent
(
testImage
,
()
=>
completer1
);
imageCache
.
putIfAbsent
(
testImage
,
()
=>
completer1
);
expect
(
imageCache
.
statusForKey
(
testImage
).
pending
,
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
pending
,
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
live
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
live
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
keepAlive
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
keepAlive
,
true
);
imageCache
.
evict
(
testImage
);
imageCache
.
evict
(
testImage
);
expect
(
imageCache
.
statusForKey
(
testImage
).
untracked
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
untracked
,
true
);
});
});
test
(
'Evicting a completed image does not clear the live image when includeLive is set to false'
,
()
async
{
test
(
'Evicting a completed image does not clear the live image when includeLive is set to false'
,
()
async
{
const
TestImage
testImage
=
TestImage
(
width:
8
,
height:
8
);
const
TestImage
testImage
=
TestImage
(
width:
8
,
height:
8
);
final
TestImageStreamCompleter
completer1
=
TestImageStreamCompleter
()
final
TestImageStreamCompleter
completer1
=
TestImageStreamCompleter
()
..
testSetImage
(
testImage
)
..
testSetImage
(
testImage
)
..
addListener
(
ImageStreamListener
((
ImageInfo
info
,
bool
syncCall
)
{}));
..
addListener
(
ImageStreamListener
((
ImageInfo
info
,
bool
syncCall
)
{}));
imageCache
.
putIfAbsent
(
testImage
,
()
=>
completer1
);
imageCache
.
putIfAbsent
(
testImage
,
()
=>
completer1
);
expect
(
imageCache
.
statusForKey
(
testImage
).
pending
,
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
pending
,
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
live
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
live
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
keepAlive
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
keepAlive
,
true
);
imageCache
.
evict
(
testImage
,
includeLive:
false
);
imageCache
.
evict
(
testImage
,
includeLive:
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
pending
,
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
pending
,
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
live
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
live
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
keepAlive
,
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
keepAlive
,
false
);
});
});
test
(
'Clearing liveImages removes callbacks'
,
()
async
{
test
(
'Clearing liveImages removes callbacks'
,
()
async
{
const
TestImage
testImage
=
TestImage
(
width:
8
,
height:
8
);
const
TestImage
testImage
=
TestImage
(
width:
8
,
height:
8
);
final
ImageStreamListener
listener
=
ImageStreamListener
((
ImageInfo
info
,
bool
syncCall
)
{});
final
ImageStreamListener
listener
=
ImageStreamListener
((
ImageInfo
info
,
bool
syncCall
)
{});
final
TestImageStreamCompleter
completer1
=
TestImageStreamCompleter
()
final
TestImageStreamCompleter
completer1
=
TestImageStreamCompleter
()
..
testSetImage
(
testImage
)
..
testSetImage
(
testImage
)
..
addListener
(
listener
);
..
addListener
(
listener
);
final
TestImageStreamCompleter
completer2
=
TestImageStreamCompleter
()
final
TestImageStreamCompleter
completer2
=
TestImageStreamCompleter
()
..
testSetImage
(
testImage
)
..
testSetImage
(
testImage
)
..
addListener
(
listener
);
..
addListener
(
listener
);
imageCache
.
putIfAbsent
(
testImage
,
()
=>
completer1
);
imageCache
.
putIfAbsent
(
testImage
,
()
=>
completer1
);
expect
(
imageCache
.
statusForKey
(
testImage
).
pending
,
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
pending
,
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
live
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
live
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
keepAlive
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
keepAlive
,
true
);
imageCache
.
clear
();
imageCache
.
clear
();
imageCache
.
clearLiveImages
();
imageCache
.
clearLiveImages
();
expect
(
imageCache
.
statusForKey
(
testImage
).
pending
,
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
pending
,
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
live
,
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
live
,
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
keepAlive
,
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
keepAlive
,
false
);
imageCache
.
putIfAbsent
(
testImage
,
()
=>
completer2
);
imageCache
.
putIfAbsent
(
testImage
,
()
=>
completer2
);
expect
(
imageCache
.
statusForKey
(
testImage
).
pending
,
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
pending
,
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
live
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
live
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
keepAlive
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
keepAlive
,
true
);
completer1
.
removeListener
(
listener
);
completer1
.
removeListener
(
listener
);
expect
(
imageCache
.
statusForKey
(
testImage
).
pending
,
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
pending
,
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
live
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
live
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
keepAlive
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
keepAlive
,
true
);
});
});
test
(
'Live image gets size updated'
,
()
async
{
test
(
'Live image gets size updated'
,
()
async
{
// Add an image to the cache in pending state
// Add an image to the cache in pending state
// Complete it once it is in there as live
// Complete it once it is in there as live
// Evict it but leave the live one.
// Evict it but leave the live one.
// Add it again.
// Add it again.
// If the live image did not track the size properly, the last line of
// If the live image did not track the size properly, the last line of
// this test will fail.
// this test will fail.
const
TestImage
testImage
=
TestImage
(
width:
8
,
height:
8
);
const
TestImage
testImage
=
TestImage
(
width:
8
,
height:
8
);
const
int
testImageSize
=
8
*
8
*
4
;
const
int
testImageSize
=
8
*
8
*
4
;
final
ImageStreamListener
listener
=
ImageStreamListener
((
ImageInfo
info
,
bool
syncCall
)
{});
final
ImageStreamListener
listener
=
ImageStreamListener
((
ImageInfo
info
,
bool
syncCall
)
{});
final
TestImageStreamCompleter
completer1
=
TestImageStreamCompleter
()
final
TestImageStreamCompleter
completer1
=
TestImageStreamCompleter
()
..
addListener
(
listener
);
..
addListener
(
listener
);
imageCache
.
putIfAbsent
(
testImage
,
()
=>
completer1
);
imageCache
.
putIfAbsent
(
testImage
,
()
=>
completer1
);
expect
(
imageCache
.
statusForKey
(
testImage
).
pending
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
pending
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
live
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
live
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
keepAlive
,
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
keepAlive
,
false
);
expect
(
imageCache
.
currentSizeBytes
,
0
);
expect
(
imageCache
.
currentSizeBytes
,
0
);
completer1
.
testSetImage
(
testImage
);
completer1
.
testSetImage
(
testImage
);
expect
(
imageCache
.
statusForKey
(
testImage
).
pending
,
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
pending
,
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
live
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
live
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
keepAlive
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
keepAlive
,
true
);
expect
(
imageCache
.
currentSizeBytes
,
testImageSize
);
expect
(
imageCache
.
currentSizeBytes
,
testImageSize
);
imageCache
.
evict
(
testImage
,
includeLive:
false
);
imageCache
.
evict
(
testImage
,
includeLive:
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
pending
,
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
pending
,
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
live
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
live
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
keepAlive
,
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
keepAlive
,
false
);
expect
(
imageCache
.
currentSizeBytes
,
0
);
expect
(
imageCache
.
currentSizeBytes
,
0
);
imageCache
.
putIfAbsent
(
testImage
,
()
=>
completer1
);
imageCache
.
putIfAbsent
(
testImage
,
()
=>
completer1
);
expect
(
imageCache
.
statusForKey
(
testImage
).
pending
,
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
pending
,
false
);
expect
(
imageCache
.
statusForKey
(
testImage
).
live
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
live
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
keepAlive
,
true
);
expect
(
imageCache
.
statusForKey
(
testImage
).
keepAlive
,
true
);
expect
(
imageCache
.
currentSizeBytes
,
testImageSize
);
expect
(
imageCache
.
currentSizeBytes
,
testImageSize
);
});
});
});
}
}
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
...
@@ -4,29 +4,17 @@
...
@@ -4,29 +4,17 @@
import
'dart:async'
;
import
'dart:async'
;
import
'dart:io'
;
import
'dart:io'
;
import
'dart:math'
as
math
;
import
'dart:typed_data'
;
import
'package:file/memory.dart'
;
import
'package:file/memory.dart'
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/painting.dart'
;
import
'package:flutter/painting.dart'
;
import
'package:flutter/services.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
import
'package:mockito/mockito.dart'
;
import
'../rendering/rendering_tester.dart'
;
import
'../rendering/rendering_tester.dart'
;
import
'image_data.dart'
;
import
'mocks_for_image_cache.dart'
;
import
'mocks_for_image_cache.dart'
;
void
main
(
)
{
void
main
(
)
{
TestRenderingFlutterBinding
();
final
DecoderCallback
basicDecoder
=
(
Uint8List
bytes
,
{
int
cacheWidth
,
int
cacheHeight
})
{
return
PaintingBinding
.
instance
.
instantiateImageCodec
(
bytes
,
cacheWidth:
cacheWidth
,
cacheHeight:
cacheHeight
);
};
setUpAll
(()
{
TestRenderingFlutterBinding
();
// initializes the imageCache
});
FlutterExceptionHandler
oldError
;
FlutterExceptionHandler
oldError
;
setUp
(()
{
setUp
(()
{
...
@@ -39,485 +27,98 @@ void main() {
...
@@ -39,485 +27,98 @@ void main() {
PaintingBinding
.
instance
.
imageCache
.
clearLiveImages
();
PaintingBinding
.
instance
.
imageCache
.
clearLiveImages
();
});
});
group
(
'ImageProvider'
,
()
{
test
(
'obtainKey errors will be caught'
,
()
async
{
group
(
'Image cache'
,
()
{
final
ImageProvider
imageProvider
=
ObtainKeyErrorImageProvider
();
tearDown
(()
{
final
Completer
<
bool
>
caughtError
=
Completer
<
bool
>();
imageCache
.
clear
();
FlutterError
.
onError
=
(
FlutterErrorDetails
details
)
{
});
caughtError
.
complete
(
false
);
};
test
(
'AssetImageProvider - evicts on failure to load'
,
()
async
{
final
ImageStream
stream
=
imageProvider
.
resolve
(
ImageConfiguration
.
empty
);
final
Completer
<
FlutterError
>
error
=
Completer
<
FlutterError
>();
stream
.
addListener
(
ImageStreamListener
((
ImageInfo
info
,
bool
syncCall
)
{
FlutterError
.
onError
=
(
FlutterErrorDetails
details
)
{
caughtError
.
complete
(
false
);
error
.
complete
(
details
.
exception
as
FlutterError
);
},
onError:
(
dynamic
error
,
StackTrace
stackTrace
)
{
};
caughtError
.
complete
(
true
);
}));
const
ImageProvider
provider
=
ExactAssetImage
(
'does-not-exist'
);
expect
(
await
caughtError
.
future
,
true
);
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
);
test
(
'obtainKey errors will be caught - check location'
,
()
async
{
expect
(
imageCache
.
currentSize
,
1
);
final
ImageProvider
imageProvider
=
ObtainKeyErrorImageProvider
();
expect
(
await
imageProvider
.
evict
(
cache:
otherCache
),
true
);
final
Completer
<
bool
>
caughtError
=
Completer
<
bool
>();
expect
(
otherCache
.
currentSize
,
0
);
FlutterError
.
onError
=
(
FlutterErrorDetails
details
)
{
expect
(
imageCache
.
currentSize
,
1
);
caughtError
.
complete
(
true
);
});
};
await
imageProvider
.
obtainCacheStatus
(
configuration:
ImageConfiguration
.
empty
);
test
(
'ImageProvider errors can always be caught'
,
()
async
{
expect
(
await
caughtError
.
future
,
true
);
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
);
});
});
test
(
'obtainKey errors will be caught'
,
()
async
{
test
(
'resolve sync errors will be caught'
,
()
async
{
final
ImageProvider
imageProvider
=
ObtainKeyErrorImageProvider
();
bool
uncaught
=
false
;
final
Zone
testZone
=
Zone
.
current
.
fork
(
specification:
ZoneSpecification
(
handleUncaughtError:
(
Zone
zone
,
ZoneDelegate
zoneDelegate
,
Zone
parent
,
Object
error
,
StackTrace
stackTrace
)
{
uncaught
=
true
;
},
));
await
testZone
.
run
(()
async
{
final
ImageProvider
imageProvider
=
LoadErrorImageProvider
();
final
Completer
<
bool
>
caughtError
=
Completer
<
bool
>();
final
Completer
<
bool
>
caughtError
=
Completer
<
bool
>();
FlutterError
.
onError
=
(
FlutterErrorDetails
details
)
{
FlutterError
.
onError
=
(
FlutterErrorDetails
details
)
{
caughtError
.
complete
(
false
);
throw
Error
(
);
};
};
final
ImageStream
stream
=
imageProvider
.
resolve
(
ImageConfiguration
.
empty
);
final
ImageStream
result
=
imageProvider
.
resolve
(
ImageConfiguration
.
empty
);
stream
.
addListener
(
ImageStreamListener
((
ImageInfo
info
,
bool
syncCall
)
{
result
.
addListener
(
ImageStreamListener
((
ImageInfo
info
,
bool
syncCall
)
{
caughtError
.
complete
(
false
);
},
onError:
(
dynamic
error
,
StackTrace
stackTrace
)
{
},
onError:
(
dynamic
error
,
StackTrace
stackTrace
)
{
caughtError
.
complete
(
true
);
caughtError
.
complete
(
true
);
}));
}));
expect
(
await
caughtError
.
future
,
true
);
expect
(
await
caughtError
.
future
,
true
);
});
});
expect
(
uncaught
,
false
);
});
test
(
'obtainKey errors will be caught - check location'
,
()
async
{
test
(
'resolve errors in the completer will be caught'
,
()
async
{
final
ImageProvider
imageProvider
=
ObtainKeyErrorImageProvider
();
bool
uncaught
=
false
;
final
Zone
testZone
=
Zone
.
current
.
fork
(
specification:
ZoneSpecification
(
handleUncaughtError:
(
Zone
zone
,
ZoneDelegate
zoneDelegate
,
Zone
parent
,
Object
error
,
StackTrace
stackTrace
)
{
uncaught
=
true
;
},
));
await
testZone
.
run
(()
async
{
final
ImageProvider
imageProvider
=
LoadErrorCompleterImageProvider
();
final
Completer
<
bool
>
caughtError
=
Completer
<
bool
>();
final
Completer
<
bool
>
caughtError
=
Completer
<
bool
>();
FlutterError
.
onError
=
(
FlutterErrorDetails
details
)
{
FlutterError
.
onError
=
(
FlutterErrorDetails
details
)
{
caughtError
.
complete
(
true
);
throw
Error
(
);
};
};
await
imageProvider
.
obtainCacheStatus
(
configuration:
ImageConfiguration
.
empty
);
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
);
expect
(
await
caughtError
.
future
,
true
);
});
});
expect
(
uncaught
,
false
);
test
(
'resolve sync errors will be caught'
,
()
async
{
bool
uncaught
=
false
;
final
Zone
testZone
=
Zone
.
current
.
fork
(
specification:
ZoneSpecification
(
handleUncaughtError:
(
Zone
zone
,
ZoneDelegate
zoneDelegate
,
Zone
parent
,
Object
error
,
StackTrace
stackTrace
)
{
uncaught
=
true
;
},
));
await
testZone
.
run
(()
async
{
final
ImageProvider
imageProvider
=
LoadErrorImageProvider
();
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
);
});
expect
(
uncaught
,
false
);
});
test
(
'resolve errors in the completer will be caught'
,
()
async
{
bool
uncaught
=
false
;
final
Zone
testZone
=
Zone
.
current
.
fork
(
specification:
ZoneSpecification
(
handleUncaughtError:
(
Zone
zone
,
ZoneDelegate
zoneDelegate
,
Zone
parent
,
Object
error
,
StackTrace
stackTrace
)
{
uncaught
=
true
;
},
));
await
testZone
.
run
(()
async
{
final
ImageProvider
imageProvider
=
LoadErrorCompleterImageProvider
();
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
);
});
expect
(
uncaught
,
false
);
});
test
(
'File image with empty file throws expected error and evicts from cache'
,
()
async
{
final
Completer
<
StateError
>
error
=
Completer
<
StateError
>();
FlutterError
.
onError
=
(
FlutterErrorDetails
details
)
{
error
.
complete
(
details
.
exception
as
StateError
);
};
final
MemoryFileSystem
fs
=
MemoryFileSystem
();
final
File
file
=
fs
.
file
(
'/empty.png'
)..
createSync
(
recursive:
true
);
final
FileImage
provider
=
FileImage
(
file
);
expect
(
imageCache
.
statusForKey
(
provider
).
untracked
,
true
);
expect
(
imageCache
.
pendingImageCount
,
0
);
provider
.
resolve
(
ImageConfiguration
.
empty
);
expect
(
imageCache
.
statusForKey
(
provider
).
pending
,
true
);
expect
(
imageCache
.
pendingImageCount
,
1
);
expect
(
await
error
.
future
,
isStateError
);
expect
(
imageCache
.
statusForKey
(
provider
).
untracked
,
true
);
expect
(
imageCache
.
pendingImageCount
,
0
);
});
group
(
'NetworkImage'
,
()
{
MockHttpClient
httpClient
;
setUp
(()
{
httpClient
=
MockHttpClient
();
debugNetworkImageHttpClientProvider
=
()
=>
httpClient
;
});
tearDown
(()
{
debugNetworkImageHttpClientProvider
=
null
;
});
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
;
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
);
});
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.
});
});
});
test
(
'ResizeImage resizes to the correct dimensions'
,
()
async
{
test
(
'File image with empty file throws expected error and evicts from cache'
,
()
async
{
final
Uint8List
bytes
=
Uint8List
.
fromList
(
kTransparentImage
);
final
Completer
<
StateError
>
error
=
Completer
<
StateError
>();
final
MemoryImage
imageProvider
=
MemoryImage
(
bytes
);
FlutterError
.
onError
=
(
FlutterErrorDetails
details
)
{
final
Size
rawImageSize
=
await
_resolveAndGetSize
(
imageProvider
);
error
.
complete
(
details
.
exception
as
StateError
);
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
);
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
);
};
};
final
MemoryFileSystem
fs
=
MemoryFileSystem
();
final
File
file
=
fs
.
file
(
'/empty.png'
)..
createSync
(
recursive:
true
);
final
FileImage
provider
=
FileImage
(
file
);
resizeImage
.
load
(
await
resizeImage
.
obtainKey
(
ImageConfiguration
.
empty
),
decode
);
expect
(
imageCache
.
statusForKey
(
provider
).
untracked
,
true
);
});
expect
(
imageCache
.
pendingImageCount
,
0
);
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
;
provider
.
resolve
(
ImageConfiguration
.
empty
);
resizeImage
.
obtainKey
(
ImageConfiguration
.
empty
).
then
((
Object
key
)
{
expect
(
isAsync
,
false
);
});
isAsync
=
true
;
expect
(
isAsync
,
true
);
});
test
(
'ResizeImage handles async obtainKey'
,
()
async
{
expect
(
imageCache
.
statusForKey
(
provider
).
pending
,
true
);
final
Uint8List
bytes
=
Uint8List
.
fromList
(
kTransparentImage
);
expect
(
imageCache
.
pendingImageCount
,
1
);
final
AsyncKeyMemoryImage
memoryImage
=
AsyncKeyMemoryImage
(
bytes
);
final
ResizeImage
resizeImage
=
ResizeImage
(
memoryImage
,
width:
123
,
height:
321
);
bool
isAsync
=
false
;
expect
(
await
error
.
future
,
isStateError
);
resizeImage
.
obtainKey
(
ImageConfiguration
.
empty
).
then
((
Object
key
)
{
expect
(
imageCache
.
statusForKey
(
provider
).
untracked
,
true
);
expect
(
isAsync
,
true
);
expect
(
imageCache
.
pendingImageCount
,
0
);
});
isAsync
=
true
;
expect
(
isAsync
,
true
);
});
});
test
(
'File image with empty file throws expected error (load)'
,
()
async
{
test
(
'File image with empty file throws expected error (load)'
,
()
async
{
...
@@ -534,40 +135,3 @@ void main() {
...
@@ -534,40 +135,3 @@ void main() {
expect
(
await
error
.
future
,
isStateError
);
expect
(
await
error
.
future
,
isStateError
);
});
});
}
}
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
);
}
}
class
MockHttpClient
extends
Mock
implements
HttpClient
{}
class
MockHttpClientRequest
extends
Mock
implements
HttpClientRequest
{}
class
MockHttpClientResponse
extends
Mock
implements
HttpClientResponse
{}
class
TestAssetBundle
extends
CachingAssetBundle
{
@override
Future
<
ByteData
>
load
(
String
key
)
async
{
return
null
;
}
}
packages/flutter/test/rendering/rendering_tester.dart
View file @
3cb79079
...
@@ -2,6 +2,8 @@
...
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// found in the LICENSE file.
import
'dart:async'
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/gestures.dart'
;
import
'package:flutter/gestures.dart'
;
import
'package:flutter/rendering.dart'
;
import
'package:flutter/rendering.dart'
;
...
@@ -19,7 +21,15 @@ class TestRenderingFlutterBinding extends BindingBase with SchedulerBinding, Ser
...
@@ -19,7 +21,15 @@ class TestRenderingFlutterBinding extends BindingBase with SchedulerBinding, Ser
/// while drawing the frame. If [onErrors] is null and [FlutterError] caught at least
/// 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
/// one error, this function fails the test. A test may override [onErrors] and
/// inspect errors using [takeFlutterErrorDetails].
/// 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
>[];
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