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
56cad89b
Unverified
Commit
56cad89b
authored
Dec 05, 2022
by
Andrew Kolos
Committed by
GitHub
Dec 05, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Speed up first asset load by encoding asset manifest in binary rather than JSON (#113637)
parent
d52e2de5
Changes
14
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
2077 additions
and
919 deletions
+2077
-919
decode_and_parse_asset_manifest.dart
...marks/lib/foundation/decode_and_parse_asset_manifest.dart
+52
-8
example_code_parser_test.dart
..._tests/flutter_gallery/test/example_code_parser_test.dart
+7
-0
image_resolution.dart
packages/flutter/lib/src/painting/image_resolution.dart
+183
-63
asset_bundle.dart
packages/flutter/lib/src/services/asset_bundle.dart
+81
-2
image_resolution_test.dart
packages/flutter/test/painting/image_resolution_test.dart
+79
-19
asset_bundle_test.dart
packages/flutter/test/services/asset_bundle_test.dart
+5
-5
image_resolution_test.dart
packages/flutter/test/widgets/image_resolution_test.dart
+26
-54
asset.dart
packages/flutter_tools/lib/src/asset.dart
+97
-23
pubspec.yaml
packages/flutter_tools/pubspec.yaml
+4
-2
deferred_components_gen_snapshot_validator_test.dart
...roid/deferred_components_gen_snapshot_validator_test.dart
+9
-8
asset_bundle_package_fonts_test.dart
...s/test/general.shard/asset_bundle_package_fonts_test.dart
+3
-2
asset_bundle_package_test.dart
...r_tools/test/general.shard/asset_bundle_package_test.dart
+1082
-488
asset_bundle_test.dart
...s/flutter_tools/test/general.shard/asset_bundle_test.dart
+54
-60
asset_bundle_variant_test.dart
...r_tools/test/general.shard/asset_bundle_variant_test.dart
+395
-185
No files found.
dev/benchmarks/microbenchmarks/lib/foundation/decode_and_parse_asset_manifest.dart
View file @
56cad89b
...
@@ -3,9 +3,9 @@
...
@@ -3,9 +3,9 @@
// found in the LICENSE file.
// found in the LICENSE file.
import
'dart:convert'
;
import
'dart:convert'
;
import
'dart:typed_data'
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/services.dart'
show
PlatformAssetBundle
,
StandardMessageCodec
;
import
'package:flutter/services.dart'
show
PlatformAssetBundle
;
import
'package:flutter/widgets.dart'
;
import
'package:flutter/widgets.dart'
;
import
'../common.dart'
;
import
'../common.dart'
;
...
@@ -18,16 +18,14 @@ void main() async {
...
@@ -18,16 +18,14 @@ void main() async {
final
BenchmarkResultPrinter
printer
=
BenchmarkResultPrinter
();
final
BenchmarkResultPrinter
printer
=
BenchmarkResultPrinter
();
WidgetsFlutterBinding
.
ensureInitialized
();
WidgetsFlutterBinding
.
ensureInitialized
();
final
Stopwatch
watch
=
Stopwatch
();
final
Stopwatch
watch
=
Stopwatch
();
final
PlatformAssetBundle
bundle
=
PlatformAssetBundle
();
final
ByteData
assetManifestBytes
=
await
bundle
.
load
(
'money_asset_manifest.json'
);
final
ByteData
assetManifest
=
await
loadAssetManifest
();
watch
.
start
();
watch
.
start
();
for
(
int
i
=
0
;
i
<
_kNumIterations
;
i
++)
{
for
(
int
i
=
0
;
i
<
_kNumIterations
;
i
++)
{
bundle
.
clear
();
// This is effectively a test.
final
String
json
=
utf8
.
decode
(
assetManifestBytes
.
buffer
.
asUint8List
());
// This is a test, so we don't need to worry about this rule.
// ignore: invalid_use_of_visible_for_testing_member
// ignore: invalid_use_of_visible_for_testing_member
await
AssetImage
.
manifestParser
(
json
);
AssetImage
.
parseAssetManifest
(
assetManifest
);
}
}
watch
.
stop
();
watch
.
stop
();
...
@@ -40,3 +38,49 @@ void main() async {
...
@@ -40,3 +38,49 @@ void main() async {
printer
.
printToStdout
();
printer
.
printToStdout
();
}
}
final
RegExp
_extractRatioRegExp
=
RegExp
(
r'/?(\d+(\.\d*)?)x$'
);
Future
<
ByteData
>
loadAssetManifest
()
async
{
double
parseScale
(
String
key
)
{
final
Uri
assetUri
=
Uri
.
parse
(
key
);
String
directoryPath
=
''
;
if
(
assetUri
.
pathSegments
.
length
>
1
)
{
directoryPath
=
assetUri
.
pathSegments
[
assetUri
.
pathSegments
.
length
-
2
];
}
final
Match
?
match
=
_extractRatioRegExp
.
firstMatch
(
directoryPath
);
if
(
match
!=
null
&&
match
.
groupCount
>
0
)
{
return
double
.
parse
(
match
.
group
(
1
)!);
}
return
1.0
;
}
final
Map
<
String
,
dynamic
>
result
=
<
String
,
dynamic
>{};
final
PlatformAssetBundle
bundle
=
PlatformAssetBundle
();
// For the benchmark, we use the older JSON format and then convert it to the modern binary format.
final
ByteData
jsonAssetManifestBytes
=
await
bundle
.
load
(
'money_asset_manifest.json'
);
final
String
jsonAssetManifest
=
utf8
.
decode
(
jsonAssetManifestBytes
.
buffer
.
asUint8List
());
final
Map
<
String
,
dynamic
>
assetManifest
=
json
.
decode
(
jsonAssetManifest
)
as
Map
<
String
,
dynamic
>;
for
(
final
MapEntry
<
String
,
dynamic
>
manifestEntry
in
assetManifest
.
entries
)
{
final
List
<
dynamic
>
resultVariants
=
<
dynamic
>[];
final
List
<
String
>
entries
=
(
manifestEntry
.
value
as
List
<
dynamic
>).
cast
<
String
>();
for
(
final
String
variant
in
entries
)
{
if
(
variant
==
manifestEntry
.
key
)
{
// With the newer binary format, don't include the main asset in it's
// list of variants. This reduces parsing time at runtime.
continue
;
}
final
Map
<
String
,
dynamic
>
resultVariant
=
<
String
,
dynamic
>{};
final
double
variantDevicePixelRatio
=
parseScale
(
variant
);
resultVariant
[
'asset'
]
=
variant
;
resultVariant
[
'dpr'
]
=
variantDevicePixelRatio
;
resultVariants
.
add
(
resultVariant
);
}
result
[
manifestEntry
.
key
]
=
resultVariants
;
}
return
const
StandardMessageCodec
().
encodeMessage
(
result
)!;
}
dev/integration_tests/flutter_gallery/test/example_code_parser_test.dart
View file @
56cad89b
...
@@ -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/services.dart'
;
import
'package:flutter/services.dart'
;
import
'package:flutter_gallery/gallery/example_code_parser.dart'
;
import
'package:flutter_gallery/gallery/example_code_parser.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
...
@@ -58,4 +60,9 @@ class TestAssetBundle extends AssetBundle {
...
@@ -58,4 +60,9 @@ class TestAssetBundle extends AssetBundle {
@override
@override
String
toString
()
=>
'
$runtimeType
@
$hashCode
()'
;
String
toString
()
=>
'
$runtimeType
@
$hashCode
()'
;
@override
Future
<
T
>
loadStructuredBinaryData
<
T
>(
String
key
,
FutureOr
<
T
>
Function
(
ByteData
data
)
parser
)
async
{
return
parser
(
await
load
(
key
));
}
}
}
packages/flutter/lib/src/painting/image_resolution.dart
View file @
56cad89b
...
@@ -11,7 +11,8 @@ import 'package:flutter/services.dart';
...
@@ -11,7 +11,8 @@ import 'package:flutter/services.dart';
import
'image_provider.dart'
;
import
'image_provider.dart'
;
const
String
_kAssetManifestFileName
=
'AssetManifest.json'
;
const
String
_kLegacyAssetManifestFilename
=
'AssetManifest.json'
;
const
String
_kAssetManifestFilename
=
'AssetManifest.bin'
;
/// A screen with a device-pixel ratio strictly less than this value is
/// A screen with a device-pixel ratio strictly less than this value is
/// considered a low-resolution screen (typically entry-level to mid-range
/// considered a low-resolution screen (typically entry-level to mid-range
...
@@ -284,18 +285,45 @@ class AssetImage extends AssetBundleImageProvider {
...
@@ -284,18 +285,45 @@ class AssetImage extends AssetBundleImageProvider {
Completer
<
AssetBundleImageKey
>?
completer
;
Completer
<
AssetBundleImageKey
>?
completer
;
Future
<
AssetBundleImageKey
>?
result
;
Future
<
AssetBundleImageKey
>?
result
;
chosenBundle
.
loadStructuredData
<
Map
<
String
,
List
<
String
>>?>(
_kAssetManifestFileName
,
manifestParser
).
then
<
void
>(
Future
<
_AssetManifest
>
loadJsonAssetManifest
()
{
(
Map
<
String
,
List
<
String
>>?
manifest
)
{
Future
<
_AssetManifest
>
parseJson
(
String
data
)
{
final
String
chosenName
=
_chooseVariant
(
final
_AssetManifest
parsed
=
_LegacyAssetManifest
.
fromJsonString
(
data
);
return
SynchronousFuture
<
_AssetManifest
>(
parsed
);
}
return
chosenBundle
.
loadStructuredData
(
_kLegacyAssetManifestFilename
,
parseJson
);
}
// TODO(andrewkolos): Once google3 and google-fonts-flutter are migrated
// away from using AssetManifest.json, remove all references to it.
// See https://github.com/flutter/flutter/issues/114913.
Future
<
_AssetManifest
>?
manifest
;
// Since AssetBundle load calls can be synchronous (e.g. in the case of tests),
// it is not sufficient to only use catchError/onError or the onError parameter
// of Future.then--we also have to use a synchronous try/catch. Once google3
// tooling starts producing AssetManifest.bin, this block can be removed.
try
{
manifest
=
chosenBundle
.
loadStructuredBinaryData
(
_kAssetManifestFilename
,
_AssetManifestBin
.
fromStandardMessageCodecMessage
);
}
catch
(
error
)
{
manifest
=
loadJsonAssetManifest
();
}
manifest
// To understand why we use this no-op `then` instead of `catchError`/`onError`,
// see https://github.com/flutter/flutter/issues/115601
.
then
((
_AssetManifest
manifest
)
=>
manifest
,
onError:
(
Object
?
error
,
StackTrace
?
stack
)
=>
loadJsonAssetManifest
())
.
then
((
_AssetManifest
manifest
)
{
final
List
<
_AssetVariant
>
candidateVariants
=
manifest
.
getVariants
(
keyName
);
final
_AssetVariant
chosenVariant
=
_chooseVariant
(
keyName
,
keyName
,
configuration
,
configuration
,
manifest
==
null
?
null
:
manifest
[
keyName
],
candidateVariants
,
)!;
);
final
double
chosenScale
=
_parseScale
(
chosenName
);
final
AssetBundleImageKey
key
=
AssetBundleImageKey
(
final
AssetBundleImageKey
key
=
AssetBundleImageKey
(
bundle:
chosenBundle
,
bundle:
chosenBundle
,
name:
chosen
Name
,
name:
chosen
Variant
.
asset
,
scale:
chosen
Scale
,
scale:
chosen
Variant
.
devicePixelRatio
,
);
);
if
(
completer
!=
null
)
{
if
(
completer
!=
null
)
{
// We already returned from this function, which means we are in the
// We already returned from this function, which means we are in the
...
@@ -309,14 +337,15 @@ class AssetImage extends AssetBundleImageProvider {
...
@@ -309,14 +337,15 @@ class AssetImage extends AssetBundleImageProvider {
// ourselves.
// ourselves.
result
=
SynchronousFuture
<
AssetBundleImageKey
>(
key
);
result
=
SynchronousFuture
<
AssetBundleImageKey
>(
key
);
}
}
},
})
).
catchError
((
Object
error
,
StackTrace
stack
)
{
.
onError
((
Object
error
,
StackTrace
stack
)
{
// We had an error. (This guarantees we weren't called synchronously.)
// We had an error. (This guarantees we weren't called synchronously.)
// Forward the error to the caller.
// Forward the error to the caller.
assert
(
completer
!=
null
);
assert
(
completer
!=
null
);
assert
(
result
==
null
);
assert
(
result
==
null
);
completer
!.
completeError
(
error
,
stack
);
completer
!.
completeError
(
error
,
stack
);
});
});
if
(
result
!=
null
)
{
if
(
result
!=
null
)
{
// The code above ran synchronously, and came up with an answer.
// The code above ran synchronously, and came up with an answer.
// Return the SynchronousFuture that we created above.
// Return the SynchronousFuture that we created above.
...
@@ -328,35 +357,29 @@ class AssetImage extends AssetBundleImageProvider {
...
@@ -328,35 +357,29 @@ class AssetImage extends AssetBundleImageProvider {
return
completer
.
future
;
return
completer
.
future
;
}
}
/// Parses the asset manifest
string into a strongly-typed map
.
/// Parses the asset manifest
's file contents into it's Dart representation
.
@visibleForTesting
@visibleForTesting
static
Future
<
Map
<
String
,
List
<
String
>>?>
manifestParser
(
String
?
jsonData
)
{
// Return type is set to Object?, because the specific type is private.
if
(
jsonData
==
null
)
{
static
Object
?
parseAssetManifest
(
ByteData
bytes
)
{
return
SynchronousFuture
<
Map
<
String
,
List
<
String
>>?>(
null
);
return
_AssetManifestBin
.
fromStandardMessageCodecMessage
(
bytes
);
}
// TODO(ianh): JSON decoding really shouldn't be on the main thread.
final
Map
<
String
,
dynamic
>
parsedJson
=
json
.
decode
(
jsonData
)
as
Map
<
String
,
dynamic
>;
final
Iterable
<
String
>
keys
=
parsedJson
.
keys
;
final
Map
<
String
,
List
<
String
>>
parsedManifest
=
<
String
,
List
<
String
>>
{
for
(
final
String
key
in
keys
)
key:
List
<
String
>.
from
(
parsedJson
[
key
]
as
List
<
dynamic
>),
};
// TODO(ianh): convert that data structure to the right types.
return
SynchronousFuture
<
Map
<
String
,
List
<
String
>>?>(
parsedManifest
);
}
}
String
?
_chooseVariant
(
String
main
,
ImageConfiguration
config
,
List
<
String
>?
candidates
)
{
_AssetVariant
_chooseVariant
(
String
mainAssetKey
,
ImageConfiguration
config
,
List
<
_AssetVariant
>
candidateVariants
)
{
if
(
config
.
devicePixelRatio
==
null
||
candidates
==
null
||
candidates
.
isEmpty
)
{
final
_AssetVariant
mainAsset
=
_AssetVariant
(
asset:
mainAssetKey
,
return
main
;
devicePixelRatio:
_naturalResolution
);
if
(
config
.
devicePixelRatio
==
null
||
candidateVariants
.
isEmpty
)
{
return
mainAsset
;
}
}
// TODO(ianh): Consider moving this parsing logic into _manifestParser.
final
SplayTreeMap
<
double
,
_AssetVariant
>
candidatesByDevicePixelRatio
=
final
SplayTreeMap
<
double
,
String
>
mapping
=
SplayTreeMap
<
double
,
String
>();
SplayTreeMap
<
double
,
_AssetVariant
>();
for
(
final
String
candidate
in
candidate
s
)
{
for
(
final
_AssetVariant
candidate
in
candidateVariant
s
)
{
mapping
[
_parseScale
(
candidate
)
]
=
candidate
;
candidatesByDevicePixelRatio
[
candidate
.
devicePixelRatio
]
=
candidate
;
}
}
candidatesByDevicePixelRatio
.
putIfAbsent
(
_naturalResolution
,
()
=>
mainAsset
);
// TODO(ianh): implement support for config.locale, config.textDirection,
// TODO(ianh): implement support for config.locale, config.textDirection,
// config.size, config.platform (then document this over in the Image.asset
// config.size, config.platform (then document this over in the Image.asset
// docs)
// docs)
return
_findBestVariant
(
mapping
,
config
.
devicePixelRatio
!);
return
_findBestVariant
(
candidatesByDevicePixelRatio
,
config
.
devicePixelRatio
!);
}
}
// Returns the "best" asset variant amongst the available `candidates`.
// Returns the "best" asset variant amongst the available `candidates`.
...
@@ -371,17 +394,17 @@ class AssetImage extends AssetBundleImageProvider {
...
@@ -371,17 +394,17 @@ class AssetImage extends AssetBundleImageProvider {
// lowest key higher than `value`.
// lowest key higher than `value`.
// - If the screen has high device pixel ratio, choose the variant with the
// - If the screen has high device pixel ratio, choose the variant with the
// key nearest to `value`.
// key nearest to `value`.
String
?
_findBestVariant
(
SplayTreeMap
<
double
,
String
>
candidates
,
double
value
)
{
_AssetVariant
_findBestVariant
(
SplayTreeMap
<
double
,
_AssetVariant
>
candidatesByDpr
,
double
value
)
{
if
(
candidates
.
containsKey
(
value
))
{
if
(
candidates
ByDpr
.
containsKey
(
value
))
{
return
candidates
[
value
]!;
return
candidates
ByDpr
[
value
]!;
}
}
final
double
?
lower
=
candidates
.
lastKeyBefore
(
value
);
final
double
?
lower
=
candidates
ByDpr
.
lastKeyBefore
(
value
);
final
double
?
upper
=
candidates
.
firstKeyAfter
(
value
);
final
double
?
upper
=
candidates
ByDpr
.
firstKeyAfter
(
value
);
if
(
lower
==
null
)
{
if
(
lower
==
null
)
{
return
candidates
[
upper
]
;
return
candidates
ByDpr
[
upper
]!
;
}
}
if
(
upper
==
null
)
{
if
(
upper
==
null
)
{
return
candidates
[
lower
]
;
return
candidates
ByDpr
[
lower
]!
;
}
}
// On screens with low device-pixel ratios the artifacts from upscaling
// On screens with low device-pixel ratios the artifacts from upscaling
...
@@ -389,20 +412,116 @@ class AssetImage extends AssetBundleImageProvider {
...
@@ -389,20 +412,116 @@ class AssetImage extends AssetBundleImageProvider {
// ratios because the physical pixels are larger. Choose the higher
// ratios because the physical pixels are larger. Choose the higher
// resolution image in that case instead of the nearest one.
// resolution image in that case instead of the nearest one.
if
(
value
<
_kLowDprLimit
||
value
>
(
lower
+
upper
)
/
2
)
{
if
(
value
<
_kLowDprLimit
||
value
>
(
lower
+
upper
)
/
2
)
{
return
candidates
[
upper
]
;
return
candidates
ByDpr
[
upper
]!
;
}
else
{
}
else
{
return
candidates
[
lower
]
;
return
candidates
ByDpr
[
lower
]!
;
}
}
}
}
@override
bool
operator
==(
Object
other
)
{
if
(
other
.
runtimeType
!=
runtimeType
)
{
return
false
;
}
return
other
is
AssetImage
&&
other
.
keyName
==
keyName
&&
other
.
bundle
==
bundle
;
}
@override
int
get
hashCode
=>
Object
.
hash
(
keyName
,
bundle
);
@override
String
toString
()
=>
'
${objectRuntimeType(this, 'AssetImage')}
(bundle:
$bundle
, name: "
$keyName
")'
;
}
/// Centralizes parsing and typecasting of the contents of the asset manifest file,
/// which is generated by the flutter tool at build time.
abstract
class
_AssetManifest
{
List
<
_AssetVariant
>
getVariants
(
String
key
);
}
/// Parses the binary asset manifest into a data structure that's easier to work with.
///
/// The asset manifest is a map of asset files to a list of objects containing
/// information about variants of that asset.
///
/// The entries with each variant object are:
/// - "asset": the location of this variant to load it from.
/// - "dpr": The device-pixel-ratio that the asset is best-suited for.
///
/// New fields could be added to this object schema to support new asset variation
/// features, such as themes, locale/region support, reading directions, and so on.
class
_AssetManifestBin
implements
_AssetManifest
{
_AssetManifestBin
(
Map
<
Object
?,
Object
?>
standardMessageData
):
_data
=
standardMessageData
;
factory
_AssetManifestBin
.
fromStandardMessageCodecMessage
(
ByteData
message
)
{
final
Object
?
data
=
const
StandardMessageCodec
().
decodeMessage
(
message
);
return
_AssetManifestBin
(
data
!
as
Map
<
Object
?,
Object
?>);
}
final
Map
<
Object
?,
Object
?>
_data
;
final
Map
<
String
,
List
<
_AssetVariant
>>
_typeCastedData
=
<
String
,
List
<
_AssetVariant
>>{};
@override
List
<
_AssetVariant
>
getVariants
(
String
key
)
{
// We lazily delay typecasting to prevent a performance hiccup when parsing
// large asset manifests.
if
(!
_typeCastedData
.
containsKey
(
key
))
{
_typeCastedData
[
key
]
=
((
_data
[
key
]
??
<
Object
?>[])
as
List
<
Object
?>)
.
cast
<
Map
<
Object
?,
Object
?>>()
.
map
(
_AssetVariant
.
fromManifestData
)
.
toList
();
}
return
_typeCastedData
[
key
]!;
}
}
class
_LegacyAssetManifest
implements
_AssetManifest
{
_LegacyAssetManifest
({
required
this
.
manifest
,
});
factory
_LegacyAssetManifest
.
fromJsonString
(
String
jsonString
)
{
List
<
_AssetVariant
>
adaptLegacyVariantList
(
String
mainAsset
,
List
<
String
>
variants
)
{
return
variants
.
map
((
String
variant
)
=>
_AssetVariant
(
asset:
variant
,
devicePixelRatio:
_parseScale
(
mainAsset
,
variant
)))
.
toList
();
}
if
(
jsonString
==
null
)
{
return
_LegacyAssetManifest
(
manifest:
<
String
,
List
<
_AssetVariant
>>{});
}
final
Map
<
String
,
Object
?>
parsedJson
=
json
.
decode
(
jsonString
)
as
Map
<
String
,
dynamic
>;
final
Iterable
<
String
>
keys
=
parsedJson
.
keys
;
final
Map
<
String
,
List
<
String
>>
parsedManifest
=
<
String
,
List
<
String
>>
{
for
(
final
String
key
in
keys
)
key:
List
<
String
>.
from
(
parsedJson
[
key
]!
as
List
<
dynamic
>),
};
final
Map
<
String
,
List
<
_AssetVariant
>>
manifestWithParsedVariants
=
parsedManifest
.
map
((
String
asset
,
List
<
String
>
variants
)
=>
MapEntry
<
String
,
List
<
_AssetVariant
>>(
asset
,
adaptLegacyVariantList
(
asset
,
variants
)));
return
_LegacyAssetManifest
(
manifest:
manifestWithParsedVariants
);
}
final
Map
<
String
,
List
<
_AssetVariant
>>
manifest
;
static
final
RegExp
_extractRatioRegExp
=
RegExp
(
r'/?(\d+(\.\d*)?)x$'
);
static
final
RegExp
_extractRatioRegExp
=
RegExp
(
r'/?(\d+(\.\d*)?)x$'
);
static
const
double
_naturalResolution
=
1.0
;
@override
List
<
_AssetVariant
>
getVariants
(
String
key
)
{
return
manifest
[
key
]
??
const
<
_AssetVariant
>[];
}
double
_parseScale
(
String
key
)
{
static
double
_parseScale
(
String
mainAsset
,
String
variant
)
{
if
(
key
==
assetName
)
{
// The legacy asset manifest includes the main asset within its variant list.
if
(
mainAsset
==
variant
)
{
return
_naturalResolution
;
return
_naturalResolution
;
}
}
final
Uri
assetUri
=
Uri
.
parse
(
key
);
final
Uri
assetUri
=
Uri
.
parse
(
variant
);
String
directoryPath
=
''
;
String
directoryPath
=
''
;
if
(
assetUri
.
pathSegments
.
length
>
1
)
{
if
(
assetUri
.
pathSegments
.
length
>
1
)
{
directoryPath
=
assetUri
.
pathSegments
[
assetUri
.
pathSegments
.
length
-
2
];
directoryPath
=
assetUri
.
pathSegments
[
assetUri
.
pathSegments
.
length
-
2
];
...
@@ -412,22 +531,23 @@ class AssetImage extends AssetBundleImageProvider {
...
@@ -412,22 +531,23 @@ class AssetImage extends AssetBundleImageProvider {
if
(
match
!=
null
&&
match
.
groupCount
>
0
)
{
if
(
match
!=
null
&&
match
.
groupCount
>
0
)
{
return
double
.
parse
(
match
.
group
(
1
)!);
return
double
.
parse
(
match
.
group
(
1
)!);
}
}
return
_naturalResolution
;
// i.e. default to 1.0x
return
_naturalResolution
;
// i.e. default to 1.0x
}
}
}
@override
class
_AssetVariant
{
bool
operator
==(
Object
other
)
{
_AssetVariant
({
if
(
other
.
runtimeType
!=
runtimeType
)
{
required
this
.
asset
,
return
false
;
required
this
.
devicePixelRatio
,
}
});
return
other
is
AssetImage
&&
other
.
keyName
==
keyName
&&
other
.
bundle
==
bundle
;
}
@override
factory
_AssetVariant
.
fromManifestData
(
Object
data
)
{
int
get
hashCode
=>
Object
.
hash
(
keyName
,
bundle
);
final
Map
<
Object
?,
Object
?>
asStructuredData
=
data
as
Map
<
Object
?,
Object
?>;
return
_AssetVariant
(
asset:
asStructuredData
[
'asset'
]!
as
String
,
devicePixelRatio:
asStructuredData
[
'dpr'
]!
as
double
);
}
@override
final
double
devicePixelRatio
;
String
toString
()
=>
'
${objectRuntimeType(this, 'AssetImage')}
(bundle:
$bundle
, name: "
$keyName
")'
;
final
String
asset
;
}
}
packages/flutter/lib/src/services/asset_bundle.dart
View file @
56cad89b
...
@@ -96,12 +96,25 @@ abstract class AssetBundle {
...
@@ -96,12 +96,25 @@ abstract class AssetBundle {
}
}
/// Retrieve a string from the asset bundle, parse it with the given function,
/// Retrieve a string from the asset bundle, parse it with the given function,
/// and return th
e
function's result.
/// and return th
at
function's result.
///
///
/// Implementations may cache the result, so a particular key should only be
/// Implementations may cache the result, so a particular key should only be
/// used with one parser for the lifetime of the asset bundle.
/// used with one parser for the lifetime of the asset bundle.
Future
<
T
>
loadStructuredData
<
T
>(
String
key
,
Future
<
T
>
Function
(
String
value
)
parser
);
Future
<
T
>
loadStructuredData
<
T
>(
String
key
,
Future
<
T
>
Function
(
String
value
)
parser
);
/// Retrieve [ByteData] from the asset bundle, parse it with the given function,
/// and return that function's result.
///
/// Implementations may cache the result, so a particular key should only be
/// used with one parser for the lifetime of the asset bundle.
Future
<
T
>
loadStructuredBinaryData
<
T
>(
String
key
,
FutureOr
<
T
>
Function
(
ByteData
data
)
parser
)
async
{
final
ByteData
data
=
await
load
(
key
);
if
(
data
==
null
)
{
throw
FlutterError
(
'Unable to load asset:
$key
'
);
}
return
parser
(
data
);
}
/// If this is a caching asset bundle, and the given key describes a cached
/// If this is a caching asset bundle, and the given key describes a cached
/// asset, then evict the asset from the cache so that the next time it is
/// asset, then evict the asset from the cache so that the next time it is
/// loaded, the cache will be reread from the asset bundle.
/// loaded, the cache will be reread from the asset bundle.
...
@@ -156,6 +169,18 @@ class NetworkAssetBundle extends AssetBundle {
...
@@ -156,6 +169,18 @@ class NetworkAssetBundle extends AssetBundle {
return
parser
(
await
loadString
(
key
));
return
parser
(
await
loadString
(
key
));
}
}
/// Retrieve [ByteData] from the asset bundle, parse it with the given function,
/// and return the function's result.
///
/// The result is not cached. The parser is run each time the resource is
/// fetched.
@override
Future
<
T
>
loadStructuredBinaryData
<
T
>(
String
key
,
FutureOr
<
T
>
Function
(
ByteData
data
)
parser
)
async
{
assert
(
key
!=
null
);
assert
(
parser
!=
null
);
return
parser
(
await
load
(
key
));
}
// TODO(ianh): Once the underlying network logic learns about caching, we
// TODO(ianh): Once the underlying network logic learns about caching, we
// should implement evict().
// should implement evict().
...
@@ -175,6 +200,7 @@ abstract class CachingAssetBundle extends AssetBundle {
...
@@ -175,6 +200,7 @@ abstract class CachingAssetBundle extends AssetBundle {
// TODO(ianh): Replace this with an intelligent cache, see https://github.com/flutter/flutter/issues/3568
// TODO(ianh): Replace this with an intelligent cache, see https://github.com/flutter/flutter/issues/3568
final
Map
<
String
,
Future
<
String
>>
_stringCache
=
<
String
,
Future
<
String
>>{};
final
Map
<
String
,
Future
<
String
>>
_stringCache
=
<
String
,
Future
<
String
>>{};
final
Map
<
String
,
Future
<
dynamic
>>
_structuredDataCache
=
<
String
,
Future
<
dynamic
>>{};
final
Map
<
String
,
Future
<
dynamic
>>
_structuredDataCache
=
<
String
,
Future
<
dynamic
>>{};
final
Map
<
String
,
Future
<
dynamic
>>
_structuredBinaryDataCache
=
<
String
,
Future
<
dynamic
>>{};
@override
@override
Future
<
String
>
loadString
(
String
key
,
{
bool
cache
=
true
})
{
Future
<
String
>
loadString
(
String
key
,
{
bool
cache
=
true
})
{
...
@@ -225,16 +251,69 @@ abstract class CachingAssetBundle extends AssetBundle {
...
@@ -225,16 +251,69 @@ abstract class CachingAssetBundle extends AssetBundle {
return
completer
.
future
;
return
completer
.
future
;
}
}
/// Retrieve bytedata from the asset bundle, parse it with the given function,
/// and return the function's result.
///
/// The result of parsing the bytedata is cached (the bytedata itself is not).
/// For any given `key`, the `parser` is only run the first time.
///
/// Once the value has been parsed, the future returned by this function for
/// subsequent calls will be a [SynchronousFuture], which resolves its
/// callback synchronously.
@override
Future
<
T
>
loadStructuredBinaryData
<
T
>(
String
key
,
FutureOr
<
T
>
Function
(
ByteData
data
)
parser
)
{
assert
(
key
!=
null
);
assert
(
parser
!=
null
);
if
(
_structuredBinaryDataCache
.
containsKey
(
key
))
{
return
_structuredBinaryDataCache
[
key
]!
as
Future
<
T
>;
}
// load can return a SynchronousFuture in certain cases, like in the
// flutter_test framework. So, we need to support both async and sync flows.
Completer
<
T
>?
completer
;
// For async flow.
SynchronousFuture
<
T
>?
result
;
// For sync flow.
load
(
key
)
.
then
<
T
>(
parser
)
.
then
<
void
>((
T
value
)
{
result
=
SynchronousFuture
<
T
>(
value
);
if
(
completer
!=
null
)
{
// The load and parse operation ran asynchronously. We already returned
// from the loadStructuredBinaryData function and therefore the caller
// was given the future of the completer.
completer
.
complete
(
value
);
}
},
onError:
(
Object
err
,
StackTrace
?
stack
)
{
completer
!.
completeError
(
err
,
stack
);
});
if
(
result
!=
null
)
{
// The above code ran synchronously. We can synchronously return the result.
_structuredBinaryDataCache
[
key
]
=
result
!;
return
result
!;
}
// Since the above code is being run asynchronously and thus hasn't run its
// `then` handler yet, we'll return a completer that will be completed
// when the handler does run.
completer
=
Completer
<
T
>();
_structuredBinaryDataCache
[
key
]
=
completer
.
future
;
return
completer
.
future
;
}
@override
@override
void
evict
(
String
key
)
{
void
evict
(
String
key
)
{
_stringCache
.
remove
(
key
);
_stringCache
.
remove
(
key
);
_structuredDataCache
.
remove
(
key
);
_structuredDataCache
.
remove
(
key
);
_structuredBinaryDataCache
.
remove
(
key
);
}
}
@override
@override
void
clear
()
{
void
clear
()
{
_stringCache
.
clear
();
_stringCache
.
clear
();
_structuredDataCache
.
clear
();
_structuredDataCache
.
clear
();
_structuredBinaryDataCache
.
clear
();
}
}
@override
@override
...
@@ -276,7 +355,7 @@ class PlatformAssetBundle extends CachingAssetBundle {
...
@@ -276,7 +355,7 @@ class PlatformAssetBundle extends CachingAssetBundle {
bool
debugUsePlatformChannel
=
false
;
bool
debugUsePlatformChannel
=
false
;
assert
(()
{
assert
(()
{
// dart:io is safe to use here since we early return for web
// dart:io is safe to use here since we early return for web
// above. If that code is changed, this needs to be g
au
rded on
// above. If that code is changed, this needs to be g
ua
rded on
// web presence. Override how assets are loaded in tests so that
// web presence. Override how assets are loaded in tests so that
// the old loader behavior that allows tests to load assets from
// the old loader behavior that allows tests to load assets from
// the current package using the package prefix.
// the current package using the package prefix.
...
...
packages/flutter/test/painting/image_resolution_test.dart
View file @
56cad89b
...
@@ -13,18 +13,14 @@ import 'package:flutter_test/flutter_test.dart';
...
@@ -13,18 +13,14 @@ import 'package:flutter_test/flutter_test.dart';
class
TestAssetBundle
extends
CachingAssetBundle
{
class
TestAssetBundle
extends
CachingAssetBundle
{
TestAssetBundle
(
this
.
_assetBundleMap
);
TestAssetBundle
(
this
.
_assetBundleMap
);
final
Map
<
String
,
List
<
String
>>
_assetBundleMap
;
final
Map
<
String
,
List
<
Map
<
dynamic
,
dynamic
>
>>
_assetBundleMap
;
Map
<
String
,
int
>
loadCallCount
=
<
String
,
int
>{};
Map
<
String
,
int
>
loadCallCount
=
<
String
,
int
>{};
String
get
_assetBundleContents
{
return
json
.
encode
(
_assetBundleMap
);
}
@override
@override
Future
<
ByteData
>
load
(
String
key
)
async
{
Future
<
ByteData
>
load
(
String
key
)
async
{
if
(
key
==
'AssetManifest.
jso
n'
)
{
if
(
key
==
'AssetManifest.
bi
n'
)
{
return
ByteData
.
view
(
Uint8List
.
fromList
(
const
Utf8Encoder
().
convert
(
_assetBundleContents
)).
buffer
)
;
return
const
StandardMessageCodec
().
encodeMessage
(
_assetBundleMap
)!
;
}
}
loadCallCount
[
key
]
=
loadCallCount
[
key
]
??
0
+
1
;
loadCallCount
[
key
]
=
loadCallCount
[
key
]
??
0
+
1
;
...
@@ -42,12 +38,71 @@ class TestAssetBundle extends CachingAssetBundle {
...
@@ -42,12 +38,71 @@ class TestAssetBundle extends CachingAssetBundle {
}
}
}
}
class
BundleWithoutAssetManifestBin
extends
CachingAssetBundle
{
BundleWithoutAssetManifestBin
(
this
.
_legacyAssetBundleMap
);
final
Map
<
dynamic
,
List
<
String
>>
_legacyAssetBundleMap
;
Map
<
String
,
int
>
loadCallCount
=
<
String
,
int
>{};
@override
Future
<
ByteData
>
load
(
String
key
)
async
{
ByteData
testByteData
(
double
scale
)
=>
ByteData
(
8
)..
setFloat64
(
0
,
scale
);
if
(
key
==
'AssetManifest.bin'
)
{
throw
FlutterError
(
'AssetManifest.bin was not found.'
);
}
if
(
key
==
'AssetManifest.json'
)
{
return
ByteData
.
view
(
Uint8List
.
fromList
(
const
Utf8Encoder
().
convert
(
json
.
encode
(
_legacyAssetBundleMap
))).
buffer
);
}
switch
(
key
)
{
case
'assets/image.png'
:
return
testByteData
(
1.0
);
// see "...with a main asset and a 1.0x asset"
case
'assets/2.0x/image.png'
:
return
testByteData
(
1.5
);
}
throw
FlutterError
(
'Unexpected key:
$key
'
);
}
@override
Future
<
ui
.
ImmutableBuffer
>
loadBuffer
(
String
key
)
async
{
final
ByteData
data
=
await
load
(
key
);
return
ui
.
ImmutableBuffer
.
fromUint8List
(
data
.
buffer
.
asUint8List
());
}
}
void
main
(
)
{
void
main
(
)
{
// TODO(andrewkolos): Once google3 is migrated away from using AssetManifest.json,
// remove all references to it. See https://github.com/flutter/flutter/issues/114913.
test
(
'AssetBundle falls back to using AssetManifest.json if AssetManifest.bin cannot be found.'
,
()
async
{
const
String
assetPath
=
'assets/image.png'
;
final
Map
<
dynamic
,
List
<
String
>>
assetBundleMap
=
<
dynamic
,
List
<
String
>>{};
assetBundleMap
[
assetPath
]
=
<
String
>[];
final
AssetImage
assetImage
=
AssetImage
(
assetPath
,
bundle:
BundleWithoutAssetManifestBin
(
assetBundleMap
));
final
AssetBundleImageKey
key
=
await
assetImage
.
obtainKey
(
ImageConfiguration
.
empty
);
expect
(
key
.
name
,
assetPath
);
expect
(
key
.
scale
,
1.0
);
});
test
(
'When using AssetManifest.json, on a high DPR device, a high dpr variant is selected.'
,
()
async
{
const
String
assetPath
=
'assets/image.png'
;
const
String
asset2xPath
=
'assets/2.0x/image.png'
;
final
Map
<
dynamic
,
List
<
String
>>
assetBundleMap
=
<
dynamic
,
List
<
String
>>{};
assetBundleMap
[
assetPath
]
=
<
String
>[
asset2xPath
];
final
AssetImage
assetImage
=
AssetImage
(
assetPath
,
bundle:
BundleWithoutAssetManifestBin
(
assetBundleMap
));
final
AssetBundleImageKey
key
=
await
assetImage
.
obtainKey
(
const
ImageConfiguration
(
devicePixelRatio:
2.0
));
expect
(
key
.
name
,
asset2xPath
);
expect
(
key
.
scale
,
2.0
);
});
group
(
'1.0 scale device tests'
,
()
{
group
(
'1.0 scale device tests'
,
()
{
void
buildAndTestWithOneAsset
(
String
mainAssetPath
)
{
void
buildAndTestWithOneAsset
(
String
mainAssetPath
)
{
final
Map
<
String
,
List
<
String
>>
assetBundleMap
=
<
String
,
List
<
String
>>{};
final
Map
<
String
,
List
<
Map
<
dynamic
,
dynamic
>>>
assetBundleMap
=
<
String
,
List
<
Map
<
dynamic
,
dynamic
>>>{};
assetBundleMap
[
mainAssetPath
]
=
<
String
>[];
assetBundleMap
[
mainAssetPath
]
=
<
Map
<
dynamic
,
dynamic
>
>[];
final
AssetImage
assetImage
=
AssetImage
(
final
AssetImage
assetImage
=
AssetImage
(
mainAssetPath
,
mainAssetPath
,
...
@@ -93,10 +148,13 @@ void main() {
...
@@ -93,10 +148,13 @@ void main() {
const
String
mainAssetPath
=
'assets/normalFolder/normalFile.png'
;
const
String
mainAssetPath
=
'assets/normalFolder/normalFile.png'
;
const
String
variantPath
=
'assets/normalFolder/3.0x/normalFile.png'
;
const
String
variantPath
=
'assets/normalFolder/3.0x/normalFile.png'
;
final
Map
<
String
,
List
<
String
>>
assetBundleMap
=
final
Map
<
String
,
List
<
Map
<
dynamic
,
dynamic
>
>>
assetBundleMap
=
<
String
,
List
<
String
>>{};
<
String
,
List
<
Map
<
dynamic
,
dynamic
>
>>{};
assetBundleMap
[
mainAssetPath
]
=
<
String
>[
mainAssetPath
,
variantPath
];
final
Map
<
dynamic
,
dynamic
>
mainAssetVariantManifestEntry
=
<
dynamic
,
dynamic
>{};
mainAssetVariantManifestEntry
[
'asset'
]
=
variantPath
;
mainAssetVariantManifestEntry
[
'dpr'
]
=
3.0
;
assetBundleMap
[
mainAssetPath
]
=
<
Map
<
dynamic
,
dynamic
>>[
mainAssetVariantManifestEntry
];
final
TestAssetBundle
testAssetBundle
=
TestAssetBundle
(
assetBundleMap
);
final
TestAssetBundle
testAssetBundle
=
TestAssetBundle
(
assetBundleMap
);
...
@@ -123,10 +181,10 @@ void main() {
...
@@ -123,10 +181,10 @@ void main() {
test
(
'When high-res device and high-res asset not present in bundle then return main variant'
,
()
{
test
(
'When high-res device and high-res asset not present in bundle then return main variant'
,
()
{
const
String
mainAssetPath
=
'assets/normalFolder/normalFile.png'
;
const
String
mainAssetPath
=
'assets/normalFolder/normalFile.png'
;
final
Map
<
String
,
List
<
String
>>
assetBundleMap
=
final
Map
<
String
,
List
<
Map
<
dynamic
,
dynamic
>
>>
assetBundleMap
=
<
String
,
List
<
String
>>{};
<
String
,
List
<
Map
<
dynamic
,
dynamic
>
>>{};
assetBundleMap
[
mainAssetPath
]
=
<
String
>[
mainAssetPath
];
assetBundleMap
[
mainAssetPath
]
=
<
Map
<
dynamic
,
dynamic
>>[
];
final
TestAssetBundle
testAssetBundle
=
TestAssetBundle
(
assetBundleMap
);
final
TestAssetBundle
testAssetBundle
=
TestAssetBundle
(
assetBundleMap
);
...
@@ -156,16 +214,18 @@ void main() {
...
@@ -156,16 +214,18 @@ void main() {
const
String
mainAssetPath
=
'assets/normalFolder/normalFile.png'
;
const
String
mainAssetPath
=
'assets/normalFolder/normalFile.png'
;
const
String
variantPath
=
'assets/normalFolder/3.0x/normalFile.png'
;
const
String
variantPath
=
'assets/normalFolder/3.0x/normalFile.png'
;
void
buildBundleAndTestVariantLogic
(
void
buildBundleAndTestVariantLogic
(
double
deviceRatio
,
double
deviceRatio
,
double
chosenAssetRatio
,
double
chosenAssetRatio
,
String
expectedAssetPath
,
String
expectedAssetPath
,
)
{
)
{
final
Map
<
String
,
List
<
String
>>
assetBundleMap
=
final
Map
<
String
,
List
<
Map
<
dynamic
,
dynamic
>
>>
assetBundleMap
=
<
String
,
List
<
String
>>{};
<
String
,
List
<
Map
<
dynamic
,
dynamic
>
>>{};
assetBundleMap
[
mainAssetPath
]
=
<
String
>[
mainAssetPath
,
variantPath
];
final
Map
<
dynamic
,
dynamic
>
mainAssetVariantManifestEntry
=
<
dynamic
,
dynamic
>{};
mainAssetVariantManifestEntry
[
'asset'
]
=
variantPath
;
mainAssetVariantManifestEntry
[
'dpr'
]
=
3.0
;
assetBundleMap
[
mainAssetPath
]
=
<
Map
<
dynamic
,
dynamic
>>[
mainAssetVariantManifestEntry
];
final
TestAssetBundle
testAssetBundle
=
TestAssetBundle
(
assetBundleMap
);
final
TestAssetBundle
testAssetBundle
=
TestAssetBundle
(
assetBundleMap
);
...
...
packages/flutter/test/services/asset_bundle_test.dart
View file @
56cad89b
...
@@ -9,14 +9,14 @@ import 'package:flutter/painting.dart';
...
@@ -9,14 +9,14 @@ import 'package:flutter/painting.dart';
import
'package:flutter/services.dart'
;
import
'package:flutter/services.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
class
TestAssetBundle
extends
CachingAssetBundle
{
class
_
TestAssetBundle
extends
CachingAssetBundle
{
Map
<
String
,
int
>
loadCallCount
=
<
String
,
int
>{};
Map
<
String
,
int
>
loadCallCount
=
<
String
,
int
>{};
@override
@override
Future
<
ByteData
>
load
(
String
key
)
async
{
Future
<
ByteData
>
load
(
String
key
)
async
{
loadCallCount
[
key
]
=
loadCallCount
[
key
]
??
0
+
1
;
loadCallCount
[
key
]
=
loadCallCount
[
key
]
??
0
+
1
;
if
(
key
==
'AssetManifest.
jso
n'
)
{
if
(
key
==
'AssetManifest.
bi
n'
)
{
return
ByteData
.
view
(
Uint8List
.
fromList
(
const
Utf8Encoder
().
convert
(
'{"one": ["one"]}'
)).
buffer
)
;
return
const
StandardMessageCodec
().
encodeMessage
(
json
.
decode
(
'{"one":[]}'
))!
;
}
}
if
(
key
==
'one'
)
{
if
(
key
==
'one'
)
{
...
@@ -30,7 +30,7 @@ void main() {
...
@@ -30,7 +30,7 @@ void main() {
TestWidgetsFlutterBinding
.
ensureInitialized
();
TestWidgetsFlutterBinding
.
ensureInitialized
();
test
(
'Caching asset bundle test'
,
()
async
{
test
(
'Caching asset bundle test'
,
()
async
{
final
TestAssetBundle
bundle
=
TestAssetBundle
();
final
_TestAssetBundle
bundle
=
_
TestAssetBundle
();
final
ByteData
assetData
=
await
bundle
.
load
(
'one'
);
final
ByteData
assetData
=
await
bundle
.
load
(
'one'
);
expect
(
assetData
.
getInt8
(
0
),
equals
(
49
));
expect
(
assetData
.
getInt8
(
0
),
equals
(
49
));
...
@@ -53,7 +53,7 @@ void main() {
...
@@ -53,7 +53,7 @@ void main() {
test
(
'AssetImage.obtainKey succeeds with ImageConfiguration.empty'
,
()
async
{
test
(
'AssetImage.obtainKey succeeds with ImageConfiguration.empty'
,
()
async
{
// This is a regression test for https://github.com/flutter/flutter/issues/12392
// This is a regression test for https://github.com/flutter/flutter/issues/12392
final
AssetImage
assetImage
=
AssetImage
(
'one'
,
bundle:
TestAssetBundle
());
final
AssetImage
assetImage
=
AssetImage
(
'one'
,
bundle:
_
TestAssetBundle
());
final
AssetBundleImageKey
key
=
await
assetImage
.
obtainKey
(
ImageConfiguration
.
empty
);
final
AssetBundleImageKey
key
=
await
assetImage
.
obtainKey
(
ImageConfiguration
.
empty
);
expect
(
key
.
name
,
'one'
);
expect
(
key
.
name
,
'one'
);
expect
(
key
.
scale
,
1.0
);
expect
(
key
.
scale
,
1.0
);
...
...
packages/flutter/test/widgets/image_resolution_test.dart
View file @
56cad89b
...
@@ -3,6 +3,7 @@
...
@@ -3,6 +3,7 @@
// found in the LICENSE file.
// found in the LICENSE file.
@TestOn
(
'!chrome'
)
@TestOn
(
'!chrome'
)
import
'dart:convert'
;
import
'dart:ui'
as
ui
show
Image
;
import
'dart:ui'
as
ui
show
Image
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/foundation.dart'
;
...
@@ -16,27 +17,32 @@ import '../image_data.dart';
...
@@ -16,27 +17,32 @@ import '../image_data.dart';
ByteData
testByteData
(
double
scale
)
=>
ByteData
(
8
)..
setFloat64
(
0
,
scale
);
ByteData
testByteData
(
double
scale
)
=>
ByteData
(
8
)..
setFloat64
(
0
,
scale
);
double
scaleOf
(
ByteData
data
)
=>
data
.
getFloat64
(
0
);
double
scaleOf
(
ByteData
data
)
=>
data
.
getFloat64
(
0
);
const
String
testManifest
=
'''
final
Map
<
dynamic
,
dynamic
>
testManifest
=
json
.
decode
(
'''
{
{
"assets/image.png" : [
"assets/image.png" : [
"assets/image.png",
{"asset": "assets/1.5x/image.png", "dpr": 1.5},
"assets/1.5x/image.png",
{"asset": "assets/2.0x/image.png", "dpr": 2.0},
"assets/2.0x/image.png",
{"asset": "assets/3.0x/image.png", "dpr": 3.0},
"assets/3.0x/image.png",
{"asset": "assets/4.0x/image.png", "dpr": 4.0}
"assets/4.0x/image.png"
]
]
}
}
'''
;
'''
)
as
Map
<
dynamic
,
dynamic
>
;
class
TestAssetBundle
extends
CachingAssetBundle
{
class
TestAssetBundle
extends
CachingAssetBundle
{
TestAssetBundle
({
this
.
manifest
=
testManifest
});
final
String
manifest
;
TestAssetBundle
({
required
Map
<
dynamic
,
dynamic
>
manifest
})
{
this
.
manifest
=
const
StandardMessageCodec
().
encodeMessage
(
manifest
)!;
}
late
final
ByteData
manifest
;
@override
@override
Future
<
ByteData
>
load
(
String
key
)
{
Future
<
ByteData
>
load
(
String
key
)
{
late
ByteData
data
;
late
ByteData
data
;
switch
(
key
)
{
switch
(
key
)
{
case
'AssetManifest.bin'
:
data
=
manifest
;
break
;
case
'assets/image.png'
:
case
'assets/image.png'
:
data
=
testByteData
(
1.0
);
data
=
testByteData
(
1.0
);
break
;
break
;
...
@@ -59,14 +65,6 @@ class TestAssetBundle extends CachingAssetBundle {
...
@@ -59,14 +65,6 @@ class TestAssetBundle extends CachingAssetBundle {
return
SynchronousFuture
<
ByteData
>(
data
);
return
SynchronousFuture
<
ByteData
>(
data
);
}
}
@override
Future
<
String
>
loadString
(
String
key
,
{
bool
cache
=
true
})
{
if
(
key
==
'AssetManifest.json'
)
{
return
SynchronousFuture
<
String
>(
manifest
);
}
return
SynchronousFuture
<
String
>(
''
);
}
@override
@override
String
toString
()
=>
'
${describeIdentity(this)}
()'
;
String
toString
()
=>
'
${describeIdentity(this)}
()'
;
}
}
...
@@ -106,7 +104,7 @@ Widget buildImageAtRatio(String imageName, Key key, double ratio, bool inferSize
...
@@ -106,7 +104,7 @@ Widget buildImageAtRatio(String imageName, Key key, double ratio, bool inferSize
devicePixelRatio:
ratio
,
devicePixelRatio:
ratio
,
),
),
child:
DefaultAssetBundle
(
child:
DefaultAssetBundle
(
bundle:
bundle
??
TestAssetBundle
(),
bundle:
bundle
??
TestAssetBundle
(
manifest:
testManifest
),
child:
Center
(
child:
Center
(
child:
inferSize
?
child:
inferSize
?
Image
(
Image
(
...
@@ -259,46 +257,21 @@ void main() {
...
@@ -259,46 +257,21 @@ void main() {
expect
(
getRenderImage
(
tester
,
key
).
scale
,
4.0
);
expect
(
getRenderImage
(
tester
,
key
).
scale
,
4.0
);
});
});
testWidgets
(
'Image for device pixel ratio 1.0, with no main asset'
,
(
WidgetTester
tester
)
async
{
const
String
manifest
=
'''
{
"assets/image.png" : [
"assets/1.5x/image.png",
"assets/2.0x/image.png",
"assets/3.0x/image.png",
"assets/4.0x/image.png"
]
}
'''
;
final
AssetBundle
bundle
=
TestAssetBundle
(
manifest:
manifest
);
const
double
ratio
=
1.0
;
Key
key
=
GlobalKey
();
await
pumpTreeToLayout
(
tester
,
buildImageAtRatio
(
image
,
key
,
ratio
,
false
,
images
,
bundle
));
expect
(
getRenderImage
(
tester
,
key
).
size
,
const
Size
(
200.0
,
200.0
));
expect
(
getRenderImage
(
tester
,
key
).
scale
,
1.5
);
key
=
GlobalKey
();
await
pumpTreeToLayout
(
tester
,
buildImageAtRatio
(
image
,
key
,
ratio
,
true
,
images
,
bundle
));
expect
(
getRenderImage
(
tester
,
key
).
size
,
const
Size
(
48.0
,
48.0
));
expect
(
getRenderImage
(
tester
,
key
).
scale
,
1.5
);
});
testWidgets
(
'Image for device pixel ratio 1.0, with a main asset and a 1.0x asset'
,
(
WidgetTester
tester
)
async
{
testWidgets
(
'Image for device pixel ratio 1.0, with a main asset and a 1.0x asset'
,
(
WidgetTester
tester
)
async
{
// If both a main asset and a 1.0x asset are specified, then prefer
// If both a main asset and a 1.0x asset are specified, then prefer
// the 1.0x asset.
// the 1.0x asset.
const
String
manifest
=
'''
final
Map
<
dynamic
,
dynamic
>
manifest
=
json
.
decode
(
'''
{
{
"assets/image.png" : [
"assets/image.png" : [
"assets/image.png",
{"asset": "assets/1.0x/image.png", "dpr":1.0},
"assets/1.0x/image.png",
{"asset": "assets/1.5x/image.png", "dpr":1.5},
"assets/1.5x/image.png",
{"asset": "assets/2.0x/image.png", "dpr":2.0},
"assets/2.0x/image.png",
{"asset": "assets/3.0x/image.png", "dpr":3.0},
"assets/3.0x/image.png",
{"asset": "assets/4.0x/image.png", "dpr":4.0}
"assets/4.0x/image.png"
]
]
}
}
'''
;
'''
)
as
Map
<
dynamic
,
dynamic
>
;
final
AssetBundle
bundle
=
TestAssetBundle
(
manifest:
manifest
);
final
AssetBundle
bundle
=
TestAssetBundle
(
manifest:
manifest
);
const
double
ratio
=
1.0
;
const
double
ratio
=
1.0
;
...
@@ -337,14 +310,13 @@ void main() {
...
@@ -337,14 +310,13 @@ void main() {
// if higher resolution assets are not available we will pick the best
// if higher resolution assets are not available we will pick the best
// available.
// available.
testWidgets
(
'Low-resolution assets'
,
(
WidgetTester
tester
)
async
{
testWidgets
(
'Low-resolution assets'
,
(
WidgetTester
tester
)
async
{
final
AssetBundle
bundle
=
TestAssetBundle
(
manifest:
'''
final
AssetBundle
bundle
=
TestAssetBundle
(
manifest:
json
.
decode
(
'''
{
{
"assets/image.png" : [
"assets/image.png" : [
"assets/image.png",
{"asset": "assets/1.5x/image.png", "dpr": 1.5}
"assets/1.5x/image.png"
]
]
}
}
'''
);
'''
)
as
Map
<
dynamic
,
dynamic
>)
;
Future
<
void
>
testRatio
({
required
double
ratio
,
required
double
expectedScale
})
async
{
Future
<
void
>
testRatio
({
required
double
ratio
,
required
double
expectedScale
})
async
{
Key
key
=
GlobalKey
();
Key
key
=
GlobalKey
();
...
...
packages/flutter_tools/lib/src/asset.dart
View file @
56cad89b
...
@@ -2,8 +2,11 @@
...
@@ -2,8 +2,11 @@
// 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:typed_data'
;
import
'package:meta/meta.dart'
;
import
'package:meta/meta.dart'
;
import
'package:package_config/package_config.dart'
;
import
'package:package_config/package_config.dart'
;
import
'package:standard_message_codec/standard_message_codec.dart'
;
import
'base/context.dart'
;
import
'base/context.dart'
;
import
'base/deferred_component.dart'
;
import
'base/deferred_component.dart'
;
...
@@ -136,6 +139,9 @@ class ManifestAssetBundle implements AssetBundle {
...
@@ -136,6 +139,9 @@ class ManifestAssetBundle implements AssetBundle {
_splitDeferredAssets
=
splitDeferredAssets
,
_splitDeferredAssets
=
splitDeferredAssets
,
_licenseCollector
=
LicenseCollector
(
fileSystem:
fileSystem
);
_licenseCollector
=
LicenseCollector
(
fileSystem:
fileSystem
);
// We assume the main asset is designed for a device pixel ratio of 1.0
static
const
double
_defaultResolution
=
1.0
;
final
Logger
_logger
;
final
Logger
_logger
;
final
FileSystem
_fileSystem
;
final
FileSystem
_fileSystem
;
final
LicenseCollector
_licenseCollector
;
final
LicenseCollector
_licenseCollector
;
...
@@ -161,7 +167,8 @@ class ManifestAssetBundle implements AssetBundle {
...
@@ -161,7 +167,8 @@ class ManifestAssetBundle implements AssetBundle {
DateTime
?
_lastBuildTimestamp
;
DateTime
?
_lastBuildTimestamp
;
static
const
String
_kAssetManifestJson
=
'AssetManifest.json'
;
static
const
String
_kAssetManifestBinFileName
=
'AssetManifest.bin'
;
static
const
String
_kAssetManifestJsonFileName
=
'AssetManifest.json'
;
static
const
String
_kNoticeFile
=
'NOTICES'
;
static
const
String
_kNoticeFile
=
'NOTICES'
;
// Comically, this can't be name with the more common .gz file extension
// Comically, this can't be name with the more common .gz file extension
// because when it's part of an AAR and brought into another APK via gradle,
// because when it's part of an AAR and brought into another APK via gradle,
...
@@ -229,8 +236,13 @@ class ManifestAssetBundle implements AssetBundle {
...
@@ -229,8 +236,13 @@ class ManifestAssetBundle implements AssetBundle {
// device.
// device.
_lastBuildTimestamp
=
DateTime
.
now
();
_lastBuildTimestamp
=
DateTime
.
now
();
if
(
flutterManifest
.
isEmpty
)
{
if
(
flutterManifest
.
isEmpty
)
{
entries
[
_kAssetManifestJson
]
=
DevFSStringContent
(
'{}'
);
entries
[
_kAssetManifestJsonFileName
]
=
DevFSStringContent
(
'{}'
);
entryKinds
[
_kAssetManifestJson
]
=
AssetKind
.
regular
;
entryKinds
[
_kAssetManifestJsonFileName
]
=
AssetKind
.
regular
;
final
ByteData
emptyAssetManifest
=
const
StandardMessageCodec
().
encodeMessage
(<
dynamic
,
dynamic
>{})!;
entries
[
_kAssetManifestBinFileName
]
=
DevFSByteContent
(
emptyAssetManifest
.
buffer
.
asUint8List
(
0
,
emptyAssetManifest
.
lengthInBytes
));
entryKinds
[
_kAssetManifestBinFileName
]
=
AssetKind
.
regular
;
return
0
;
return
0
;
}
}
...
@@ -426,7 +438,11 @@ class ManifestAssetBundle implements AssetBundle {
...
@@ -426,7 +438,11 @@ class ManifestAssetBundle implements AssetBundle {
_wildcardDirectories
[
uri
]
??=
_fileSystem
.
directory
(
uri
);
_wildcardDirectories
[
uri
]
??=
_fileSystem
.
directory
(
uri
);
}
}
final
DevFSStringContent
assetManifest
=
_createAssetManifest
(
assetVariants
,
deferredComponentsAssetVariants
);
final
Map
<
String
,
List
<
String
>>
assetManifest
=
_createAssetManifest
(
assetVariants
,
deferredComponentsAssetVariants
);
final
DevFSStringContent
assetManifestJson
=
DevFSStringContent
(
json
.
encode
(
assetManifest
));
final
DevFSByteContent
assetManifestBinary
=
_createAssetManifestBinary
(
assetManifest
);
final
DevFSStringContent
fontManifest
=
DevFSStringContent
(
json
.
encode
(
fonts
));
final
DevFSStringContent
fontManifest
=
DevFSStringContent
(
json
.
encode
(
fonts
));
final
LicenseResult
licenseResult
=
_licenseCollector
.
obtainLicenses
(
packageConfig
,
additionalLicenseFiles
);
final
LicenseResult
licenseResult
=
_licenseCollector
.
obtainLicenses
(
packageConfig
,
additionalLicenseFiles
);
if
(
licenseResult
.
errorMessages
.
isNotEmpty
)
{
if
(
licenseResult
.
errorMessages
.
isNotEmpty
)
{
...
@@ -450,7 +466,8 @@ class ManifestAssetBundle implements AssetBundle {
...
@@ -450,7 +466,8 @@ class ManifestAssetBundle implements AssetBundle {
_fileSystem
.
file
(
'DOES_NOT_EXIST_RERUN_FOR_WILDCARD
$suffix
'
).
absolute
);
_fileSystem
.
file
(
'DOES_NOT_EXIST_RERUN_FOR_WILDCARD
$suffix
'
).
absolute
);
}
}
_setIfChanged
(
_kAssetManifestJson
,
assetManifest
,
AssetKind
.
regular
);
_setIfChanged
(
_kAssetManifestJsonFileName
,
assetManifestJson
,
AssetKind
.
regular
);
_setIfChanged
(
_kAssetManifestBinFileName
,
assetManifestBinary
,
AssetKind
.
regular
);
_setIfChanged
(
kFontManifestJson
,
fontManifest
,
AssetKind
.
regular
);
_setIfChanged
(
kFontManifestJson
,
fontManifest
,
AssetKind
.
regular
);
_setLicenseIfChanged
(
licenseResult
.
combinedLicenses
,
targetPlatform
);
_setLicenseIfChanged
(
licenseResult
.
combinedLicenses
,
targetPlatform
);
return
0
;
return
0
;
...
@@ -459,17 +476,31 @@ class ManifestAssetBundle implements AssetBundle {
...
@@ -459,17 +476,31 @@ class ManifestAssetBundle implements AssetBundle {
@override
@override
List
<
File
>
additionalDependencies
=
<
File
>[];
List
<
File
>
additionalDependencies
=
<
File
>[];
void
_setIfChanged
(
String
key
,
DevFSStringContent
content
,
AssetKind
assetKind
)
{
void
_setIfChanged
(
String
key
,
DevFSContent
content
,
AssetKind
assetKind
)
{
if
(!
entries
.
containsKey
(
key
))
{
bool
areEqual
(
List
<
int
>
o1
,
List
<
int
>
o2
)
{
entries
[
key
]
=
content
;
if
(
o1
.
length
!=
o2
.
length
)
{
entryKinds
[
key
]
=
assetKind
;
return
false
;
return
;
}
for
(
int
index
=
0
;
index
<
o1
.
length
;
index
++)
{
if
(
o1
[
index
]
!=
o2
[
index
])
{
return
false
;
}
}
return
true
;
}
}
final
DevFSStringContent
?
oldContent
=
entries
[
key
]
as
DevFSStringContent
?;
if
(
oldContent
?.
string
!=
content
.
string
)
{
final
DevFSContent
?
oldContent
=
entries
[
key
];
entries
[
key
]
=
content
;
// In the case that the content is unchanged, we want to avoid an overwrite
entryKinds
[
key
]
=
assetKind
;
// as the isModified property may be reset to true,
if
(
oldContent
is
DevFSByteContent
&&
content
is
DevFSByteContent
&&
areEqual
(
oldContent
.
bytes
,
content
.
bytes
))
{
return
;
}
}
entries
[
key
]
=
content
;
entryKinds
[
key
]
=
assetKind
;
}
}
void
_setLicenseIfChanged
(
void
_setLicenseIfChanged
(
...
@@ -621,14 +652,14 @@ class ManifestAssetBundle implements AssetBundle {
...
@@ -621,14 +652,14 @@ class ManifestAssetBundle implements AssetBundle {
return
deferredComponentsAssetVariants
;
return
deferredComponentsAssetVariants
;
}
}
DevFSStringContent
_createAssetManifest
(
Map
<
String
,
List
<
String
>>
_createAssetManifest
(
Map
<
_Asset
,
List
<
_Asset
>>
assetVariants
,
Map
<
_Asset
,
List
<
_Asset
>>
assetVariants
,
Map
<
String
,
Map
<
_Asset
,
List
<
_Asset
>>>
deferredComponentsAssetVariants
Map
<
String
,
Map
<
_Asset
,
List
<
_Asset
>>>
deferredComponentsAssetVariants
)
{
)
{
final
Map
<
String
,
List
<
String
>>
jsonObjec
t
=
<
String
,
List
<
String
>>{};
final
Map
<
String
,
List
<
String
>>
manifes
t
=
<
String
,
List
<
String
>>{};
final
Map
<
_Asset
,
List
<
String
>>
jsonE
ntries
=
<
_Asset
,
List
<
String
>>{};
final
Map
<
_Asset
,
List
<
String
>>
e
ntries
=
<
_Asset
,
List
<
String
>>{};
assetVariants
.
forEach
((
_Asset
main
,
List
<
_Asset
>
variants
)
{
assetVariants
.
forEach
((
_Asset
main
,
List
<
_Asset
>
variants
)
{
jsonE
ntries
[
main
]
=
<
String
>[
e
ntries
[
main
]
=
<
String
>[
for
(
final
_Asset
variant
in
variants
)
for
(
final
_Asset
variant
in
variants
)
variant
.
entryUri
.
path
,
variant
.
entryUri
.
path
,
];
];
...
@@ -636,26 +667,69 @@ class ManifestAssetBundle implements AssetBundle {
...
@@ -636,26 +667,69 @@ class ManifestAssetBundle implements AssetBundle {
if
(
deferredComponentsAssetVariants
!=
null
)
{
if
(
deferredComponentsAssetVariants
!=
null
)
{
for
(
final
Map
<
_Asset
,
List
<
_Asset
>>
componentAssets
in
deferredComponentsAssetVariants
.
values
)
{
for
(
final
Map
<
_Asset
,
List
<
_Asset
>>
componentAssets
in
deferredComponentsAssetVariants
.
values
)
{
componentAssets
.
forEach
((
_Asset
main
,
List
<
_Asset
>
variants
)
{
componentAssets
.
forEach
((
_Asset
main
,
List
<
_Asset
>
variants
)
{
jsonE
ntries
[
main
]
=
<
String
>[
e
ntries
[
main
]
=
<
String
>[
for
(
final
_Asset
variant
in
variants
)
for
(
final
_Asset
variant
in
variants
)
variant
.
entryUri
.
path
,
variant
.
entryUri
.
path
,
];
];
});
});
}
}
}
}
final
List
<
_Asset
>
sortedKeys
=
jsonE
ntries
.
keys
.
toList
()
final
List
<
_Asset
>
sortedKeys
=
e
ntries
.
keys
.
toList
()
..
sort
((
_Asset
left
,
_Asset
right
)
=>
left
.
entryUri
.
path
.
compareTo
(
right
.
entryUri
.
path
));
..
sort
((
_Asset
left
,
_Asset
right
)
=>
left
.
entryUri
.
path
.
compareTo
(
right
.
entryUri
.
path
));
for
(
final
_Asset
main
in
sortedKeys
)
{
for
(
final
_Asset
main
in
sortedKeys
)
{
final
String
decodedEntryPath
=
Uri
.
decodeFull
(
main
.
entryUri
.
path
);
final
String
decodedEntryPath
=
Uri
.
decodeFull
(
main
.
entryUri
.
path
);
final
List
<
String
>
rawEntryVariantsPaths
=
jsonE
ntries
[
main
]!;
final
List
<
String
>
rawEntryVariantsPaths
=
e
ntries
[
main
]!;
final
List
<
String
>
decodedEntryVariantPaths
=
rawEntryVariantsPaths
final
List
<
String
>
decodedEntryVariantPaths
=
rawEntryVariantsPaths
.
map
((
String
value
)
=>
Uri
.
decodeFull
(
value
))
.
map
((
String
value
)
=>
Uri
.
decodeFull
(
value
))
.
toList
();
.
toList
();
jsonObject
[
decodedEntryPath
]
=
decodedEntryVariantPaths
;
manifest
[
decodedEntryPath
]
=
decodedEntryVariantPaths
;
}
return
manifest
;
}
DevFSByteContent
_createAssetManifestBinary
(
Map
<
String
,
List
<
String
>>
assetManifest
)
{
double
parseScale
(
String
key
)
{
final
Uri
assetUri
=
Uri
.
parse
(
key
);
String
directoryPath
=
''
;
if
(
assetUri
.
pathSegments
.
length
>
1
)
{
directoryPath
=
assetUri
.
pathSegments
[
assetUri
.
pathSegments
.
length
-
2
];
}
final
Match
?
match
=
_extractRatioRegExp
.
firstMatch
(
directoryPath
);
if
(
match
!=
null
&&
match
.
groupCount
>
0
)
{
return
double
.
parse
(
match
.
group
(
1
)!);
}
return
_defaultResolution
;
}
final
Map
<
String
,
dynamic
>
result
=
<
String
,
dynamic
>{};
for
(
final
MapEntry
<
String
,
dynamic
>
manifestEntry
in
assetManifest
.
entries
)
{
final
List
<
dynamic
>
resultVariants
=
<
dynamic
>[];
final
List
<
String
>
entries
=
(
manifestEntry
.
value
as
List
<
dynamic
>).
cast
<
String
>();
for
(
final
String
variant
in
entries
)
{
if
(
variant
==
manifestEntry
.
key
)
{
// With the newer binary format, don't include the main asset in it's
// list of variants. This reduces parsing time at runtime.
continue
;
}
final
Map
<
String
,
dynamic
>
resultVariant
=
<
String
,
dynamic
>{};
final
double
variantDevicePixelRatio
=
parseScale
(
variant
);
resultVariant
[
'asset'
]
=
variant
;
resultVariant
[
'dpr'
]
=
variantDevicePixelRatio
;
resultVariants
.
add
(
resultVariant
);
}
result
[
manifestEntry
.
key
]
=
resultVariants
;
}
}
return
DevFSStringContent
(
json
.
encode
(
jsonObject
));
final
ByteData
message
=
const
StandardMessageCodec
().
encodeMessage
(
result
)!;
return
DevFSByteContent
(
message
.
buffer
.
asUint8List
(
0
,
message
.
lengthInBytes
));
}
}
static
final
RegExp
_extractRatioRegExp
=
RegExp
(
r'/?(\d+(\.\d*)?)x$'
);
/// Prefixes family names and asset paths of fonts included from packages with
/// Prefixes family names and asset paths of fonts included from packages with
/// 'packages/<package_name>'
/// 'packages/<package_name>'
List
<
Font
>
_parsePackageFonts
(
List
<
Font
>
_parsePackageFonts
(
...
...
packages/flutter_tools/pubspec.yaml
View file @
56cad89b
...
@@ -57,6 +57,8 @@ dependencies:
...
@@ -57,6 +57,8 @@ dependencies:
vm_service
:
9.4.0
vm_service
:
9.4.0
standard_message_codec
:
0.0.1+3
_fe_analyzer_shared
:
50.0.0
# THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
_fe_analyzer_shared
:
50.0.0
# THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
analyzer
:
5.2.0
# THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
analyzer
:
5.2.0
# THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
boolean_selector
:
2.1.1
# THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
boolean_selector
:
2.1.1
# THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
...
@@ -88,7 +90,6 @@ dependencies:
...
@@ -88,7 +90,6 @@ dependencies:
watcher
:
1.0.2
# THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
watcher
:
1.0.2
# THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
dev_dependencies
:
dev_dependencies
:
collection
:
1.17.0
file_testing
:
3.0.0
file_testing
:
3.0.0
pubspec_parse
:
1.2.1
pubspec_parse
:
1.2.1
...
@@ -97,9 +98,10 @@ dev_dependencies:
...
@@ -97,9 +98,10 @@ dev_dependencies:
json_annotation
:
4.7.0
# THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
json_annotation
:
4.7.0
# THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
node_preamble
:
2.0.1
# THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
node_preamble
:
2.0.1
# THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
test
:
1.22.0
# THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
test
:
1.22.0
# THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
collection
:
1.17.0
dartdoc
:
dartdoc
:
# Exclude this package from the hosted API docs.
# Exclude this package from the hosted API docs.
nodoc
:
true
nodoc
:
true
# PUBSPEC CHECKSUM:
65eb
# PUBSPEC CHECKSUM:
408d
packages/flutter_tools/test/general.shard/android/deferred_components_gen_snapshot_validator_test.dart
View file @
56cad89b
...
@@ -220,7 +220,7 @@ loading-units-spelled-wrong:
...
@@ -220,7 +220,7 @@ loading-units-spelled-wrong:
expect
(
logger
.
statusText
,
contains
(
'Errors checking the following files:'
));
expect
(
logger
.
statusText
,
contains
(
'Errors checking the following files:'
));
expect
(
logger
.
statusText
,
contains
(
"Invalid loading units yaml file, 'loading-units' entry did not exist."
));
expect
(
logger
.
statusText
,
contains
(
"Invalid loading units yaml file, 'loading-units' entry did not exist."
));
expect
(
logger
.
statusText
.
contains
(
'Previously existing loading units no longer exist:
\n\n
LoadingUnit 2
\n
Libraries:
\n
- lib1
\n
'
),
false
);
expect
(
logger
.
statusText
,
isNot
(
contains
(
'Previously existing loading units no longer exist:
\n\n
LoadingUnit 2
\n
Libraries:
\n
- lib1
\n
'
))
);
});
});
testWithoutContext
(
'loadingUnitCache validator detects malformed file: not a list'
,
()
async
{
testWithoutContext
(
'loadingUnitCache validator detects malformed file: not a list'
,
()
async
{
...
@@ -382,7 +382,7 @@ loading-units:
...
@@ -382,7 +382,7 @@ loading-units:
validator
.
displayResults
();
validator
.
displayResults
();
validator
.
attemptToolExit
();
validator
.
attemptToolExit
();
expect
(
logger
.
statusText
.
contains
(
'Errors checking the following files:'
),
false
);
expect
(
logger
.
statusText
,
isNot
(
contains
(
'Errors checking the following files:'
))
);
});
});
testWithoutContext
(
'androidStringMapping modifies strings file'
,
()
async
{
testWithoutContext
(
'androidStringMapping modifies strings file'
,
()
async
{
...
@@ -448,9 +448,10 @@ loading-units:
...
@@ -448,9 +448,10 @@ loading-units:
.childDirectory('
main
')
.childDirectory('
main
')
.childFile('
AndroidManifest
.
xml
');
.childFile('
AndroidManifest
.
xml
');
expect(manifestOutput.existsSync(), true);
expect(manifestOutput.existsSync(), true);
expect(manifestOutput.readAsStringSync().contains('
<
meta
-
data
android:
name
=
"io.flutter.embedding.engine.deferredcomponents.DeferredComponentManager.loadingUnitMapping"
android:
value
=
"3:component1,2:component2,4:component2"
/>
'), true);
final String manifestOutputString = manifestOutput.readAsStringSync();
expect(manifestOutput.readAsStringSync().contains('
android:
value
=
"invalidmapping"'), false);
expect(manifestOutputString, contains('
<
meta
-
data
android:
name
=
"io.flutter.embedding.engine.deferredcomponents.DeferredComponentManager.loadingUnitMapping"
android:
value
=
"3:component1,2:component2,4:component2"
/>
'));
expect(manifestOutput.readAsStringSync().contains("<!-- Don'
t
delete
the
meta
-
data
below
.
"), true);
expect(manifestOutputString, isNot(contains('
android:
value
=
"invalidmapping"')));
expect(manifestOutputString, contains("<!-- Don'
t
delete
the
meta
-
data
below
.
"));
});
});
testWithoutContext('androidStringMapping adds mapping when no existing mapping', () async {
testWithoutContext('androidStringMapping adds mapping when no existing mapping', () async {
...
@@ -695,8 +696,8 @@ loading-units:
...
@@ -695,8 +696,8 @@ loading-units:
.childDirectory('
main
')
.childDirectory('
main
')
.childFile('
AndroidManifest
.
xml
');
.childFile('
AndroidManifest
.
xml
');
expect(manifestOutput.existsSync(), true);
expect(manifestOutput.existsSync(), true);
expect(manifestOutput.readAsStringSync()
.contains('
<
meta
-
data
android:
name
=
"io.flutter.embedding.engine.deferredcomponents.DeferredComponentManager.loadingUnitMapping"
android:
value
=
"3:component1,2:component2,4:component2"
/>
'), true
);
expect(manifestOutput.readAsStringSync()
, contains('
<
meta
-
data
android:
name
=
"io.flutter.embedding.engine.deferredcomponents.DeferredComponentManager.loadingUnitMapping"
android:
value
=
"3:component1,2:component2,4:component2"
/>
')
);
expect(manifestOutput.readAsStringSync()
.contains(RegExp(r'
android:
value
[
\
s
\
n
]*=[
\
s
\
n
]*
"invalidmapping"')), false
);
expect(manifestOutput.readAsStringSync()
, isNot(contains(RegExp(r'
android:
value
[
\
s
\
n
]*=[
\
s
\
n
]*
"invalidmapping"')))
);
expect(manifestOutput.readAsStringSync()
.contains("<!-- Don'
t
delete
the
meta
-
data
below
.
"), true
);
expect(manifestOutput.readAsStringSync()
, contains("<!-- Don'
t
delete
the
meta
-
data
below
.
")
);
});
});
}
}
packages/flutter_tools/test/general.shard/asset_bundle_package_fonts_test.dart
View file @
56cad89b
...
@@ -111,8 +111,9 @@ $fontsSection
...
@@ -111,8 +111,9 @@ $fontsSection
final
AssetBundle
bundle
=
AssetBundleFactory
.
instance
.
createBundle
();
final
AssetBundle
bundle
=
AssetBundleFactory
.
instance
.
createBundle
();
await
bundle
.
build
(
packagesPath:
'.packages'
);
await
bundle
.
build
(
packagesPath:
'.packages'
);
expect
(
bundle
.
entries
.
length
,
3
);
// LICENSE, AssetManifest, FontManifest
expect
(
bundle
.
entries
.
keys
,
containsAll
(
expect
(
bundle
.
entries
.
containsKey
(
'FontManifest.json'
),
isTrue
);
<
String
>[
'AssetManifest.bin'
,
'AssetManifest.json'
,
'FontManifest.json'
,
'NOTICES.Z'
]
));
},
overrides:
<
Type
,
Generator
>{
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
...
...
packages/flutter_tools/test/general.shard/asset_bundle_package_test.dart
View file @
56cad89b
...
@@ -3,6 +3,7 @@
...
@@ -3,6 +3,7 @@
// found in the LICENSE file.
// found in the LICENSE file.
import
'dart:convert'
;
import
'dart:convert'
;
import
'dart:typed_data'
;
import
'package:file/file.dart'
;
import
'package:file/file.dart'
;
import
'package:file/memory.dart'
;
import
'package:file/memory.dart'
;
...
@@ -11,6 +12,7 @@ import 'package:flutter_tools/src/asset.dart';
...
@@ -11,6 +12,7 @@ import 'package:flutter_tools/src/asset.dart';
import
'package:flutter_tools/src/base/file_system.dart'
;
import
'package:flutter_tools/src/base/file_system.dart'
;
import
'package:flutter_tools/src/globals.dart'
as
globals
;
import
'package:flutter_tools/src/globals.dart'
as
globals
;
import
'package:standard_message_codec/standard_message_codec.dart'
;
import
'../src/common.dart'
;
import
'../src/common.dart'
;
import
'../src/context.dart'
;
import
'../src/context.dart'
;
...
@@ -24,6 +26,7 @@ void main() {
...
@@ -24,6 +26,7 @@ void main() {
// rolls into Flutter.
// rolls into Flutter.
return
path
.
replaceAll
(
'/'
,
globals
.
fs
.
path
.
separator
);
return
path
.
replaceAll
(
'/'
,
globals
.
fs
.
path
.
separator
);
}
}
void
writePubspecFile
(
String
path
,
String
name
,
{
List
<
String
>?
assets
})
{
void
writePubspecFile
(
String
path
,
String
name
,
{
List
<
String
>?
assets
})
{
String
assetsSection
;
String
assetsSection
;
if
(
assets
==
null
)
{
if
(
assets
==
null
)
{
...
@@ -60,37 +63,6 @@ $assetsSection
...
@@ -60,37 +63,6 @@ $assetsSection
..
writeAsStringSync
(
packages
);
..
writeAsStringSync
(
packages
);
}
}
Future
<
void
>
buildAndVerifyAssets
(
List
<
String
>
assets
,
List
<
String
>
packages
,
String
?
expectedAssetManifest
,
{
bool
expectExists
=
true
,
})
async
{
final
AssetBundle
bundle
=
AssetBundleFactory
.
instance
.
createBundle
();
await
bundle
.
build
(
packagesPath:
'.packages'
);
for
(
final
String
packageName
in
packages
)
{
for
(
final
String
asset
in
assets
)
{
final
String
entryKey
=
Uri
.
encodeFull
(
'packages/
$packageName
/
$asset
'
);
expect
(
bundle
.
entries
.
containsKey
(
entryKey
),
expectExists
,
reason:
'Cannot find key on bundle:
$entryKey
'
);
if
(
expectExists
)
{
expect
(
utf8
.
decode
(
await
bundle
.
entries
[
entryKey
]!.
contentsAsBytes
()),
asset
,
);
}
}
}
if
(
expectExists
)
{
expect
(
utf8
.
decode
(
await
bundle
.
entries
[
'AssetManifest.json'
]!.
contentsAsBytes
()),
expectedAssetManifest
,
);
}
}
void
writeAssets
(
String
path
,
List
<
String
>
assets
)
{
void
writeAssets
(
String
path
,
List
<
String
>
assets
)
{
for
(
final
String
asset
in
assets
)
{
for
(
final
String
asset
in
assets
)
{
final
String
fullPath
=
fixPath
(
globals
.
fs
.
path
.
join
(
path
,
asset
));
final
String
fullPath
=
fixPath
(
globals
.
fs
.
path
.
join
(
path
,
asset
));
...
@@ -101,182 +73,391 @@ $assetsSection
...
@@ -101,182 +73,391 @@ $assetsSection
}
}
}
}
late
FileSystem
testFileSystem
;
// TODO(andrewkolos): Delete this group once we stop producing AssetManifest.json
// as part of build.
setUp
(()
async
{
group
(
'Legacy asset manifest (AssetManifest.json)'
,
()
{
testFileSystem
=
MemoryFileSystem
(
Future
<
void
>
buildAndVerifyAssets
(
style:
globals
.
platform
.
isWindows
List
<
String
>
assets
,
?
FileSystemStyle
.
windows
List
<
String
>
packages
,
:
FileSystemStyle
.
posix
,
String
?
expectedAssetManifest
,
{
);
bool
expectExists
=
true
,
testFileSystem
.
currentDirectory
=
testFileSystem
.
systemTempDirectory
.
createTempSync
(
'flutter_asset_bundle_test.'
);
})
async
{
});
group
(
'AssetBundle assets from packages'
,
()
{
testUsingContext
(
'No assets are bundled when the package has no assets'
,
()
async
{
writePubspecFile
(
'pubspec.yaml'
,
'test'
);
writePackagesFile
(
'test_package:p/p/lib/'
);
writePubspecFile
(
'p/p/pubspec.yaml'
,
'test_package'
);
final
AssetBundle
bundle
=
AssetBundleFactory
.
instance
.
createBundle
();
final
AssetBundle
bundle
=
AssetBundleFactory
.
instance
.
createBundle
();
await
bundle
.
build
(
packagesPath:
'.packages'
);
await
bundle
.
build
(
packagesPath:
'.packages'
);
expect
(
bundle
.
entries
.
length
,
3
);
// LICENSE, AssetManifest, FontManifest
const
String
expectedAssetManifest
=
'{}'
;
expect
(
utf8
.
decode
(
await
bundle
.
entries
[
'AssetManifest.json'
]!.
contentsAsBytes
()),
expectedAssetManifest
,
);
expect
(
utf8
.
decode
(
await
bundle
.
entries
[
'FontManifest.json'
]!.
contentsAsBytes
()),
'[]'
,
);
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
testUsingContext
(
'No assets are bundled when the package has an asset that is not listed'
,
()
async
{
writePubspecFile
(
'pubspec.yaml'
,
'test'
);
writePackagesFile
(
'test_package:p/p/lib/'
);
writePubspecFile
(
'p/p/pubspec.yaml'
,
'test_package'
);
final
List
<
String
>
assets
=
<
String
>[
'a/foo'
];
writeAssets
(
'p/p/'
,
assets
);
final
AssetBundle
bundle
=
AssetBundleFactory
.
instance
.
createBundle
();
await
bundle
.
build
(
packagesPath:
'.packages'
);
expect
(
bundle
.
entries
.
length
,
3
);
// LICENSE, AssetManifest, FontManifest
const
String
expectedAssetManifest
=
'{}'
;
expect
(
utf8
.
decode
(
await
bundle
.
entries
[
'AssetManifest.json'
]!.
contentsAsBytes
()),
expectedAssetManifest
,
);
expect
(
utf8
.
decode
(
await
bundle
.
entries
[
'FontManifest.json'
]!.
contentsAsBytes
()),
'[]'
,
);
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
testUsingContext
(
'One asset is bundled when the package has and lists one '
'asset its pubspec'
,
()
async
{
writePubspecFile
(
'pubspec.yaml'
,
'test'
);
writePackagesFile
(
'test_package:p/p/lib/'
);
final
List
<
String
>
assets
=
<
String
>[
'a/foo'
];
writePubspecFile
(
'p/p/pubspec.yaml'
,
'test_package'
,
assets:
assets
,
);
writeAssets
(
'p/p/'
,
assets
);
const
String
expectedAssetManifest
=
'{"packages/test_package/a/foo":'
'["packages/test_package/a/foo"]}'
;
await
buildAndVerifyAssets
(
assets
,
<
String
>[
'test_package'
],
expectedAssetManifest
,
);
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
testUsingContext
(
'One asset is bundled when the package has one asset, '
"listed in the app's pubspec"
,
()
async
{
final
List
<
String
>
assetEntries
=
<
String
>[
'packages/test_package/a/foo'
];
writePubspecFile
(
'pubspec.yaml'
,
'test'
,
assets:
assetEntries
,
);
writePackagesFile
(
'test_package:p/p/lib/'
);
writePubspecFile
(
'p/p/pubspec.yaml'
,
'test_package'
);
final
List
<
String
>
assets
=
<
String
>[
'a/foo'
];
writeAssets
(
'p/p/lib/'
,
assets
);
const
String
expectedAssetManifest
=
'{"packages/test_package/a/foo":'
'["packages/test_package/a/foo"]}'
;
await
buildAndVerifyAssets
(
assets
,
<
String
>[
'test_package'
],
expectedAssetManifest
,
);
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
testUsingContext
(
'One asset and its variant are bundled when the package '
for
(
final
String
packageName
in
packages
)
{
'has an asset and a variant, and lists the asset in its pubspec'
,
()
async
{
for
(
final
String
asset
in
assets
)
{
writePubspecFile
(
'pubspec.yaml'
,
'test'
);
final
String
entryKey
=
Uri
.
encodeFull
(
'packages/
$packageName
/
$asset
'
);
writePackagesFile
(
'test_package:p/p/lib/'
);
expect
(
bundle
.
entries
.
containsKey
(
entryKey
),
expectExists
,
writePubspecFile
(
reason:
'Cannot find key on bundle:
$entryKey
'
);
'p/p/pubspec.yaml'
,
if
(
expectExists
)
{
'test_package'
,
expect
(
assets:
<
String
>[
'a/foo'
,
'a/bar'
],
utf8
.
decode
(
await
bundle
.
entries
[
entryKey
]!.
contentsAsBytes
()),
);
asset
,
);
}
}
}
final
List
<
String
>
assets
=
<
String
>[
'a/foo'
,
'a/2x/foo'
,
'a/bar'
];
if
(
expectExists
)
{
writeAssets
(
'p/p/'
,
assets
);
expect
(
utf8
.
decode
(
await
bundle
.
entries
[
'AssetManifest.json'
]!.
contentsAsBytes
()),
expectedAssetManifest
,
);
}
}
const
String
expectedManifest
=
'{'
late
FileSystem
testFileSystem
;
'"packages/test_package/a/bar":'
'["packages/test_package/a/bar"],'
'"packages/test_package/a/foo":'
'["packages/test_package/a/foo","packages/test_package/a/2x/foo"]'
'}'
;
await
buildAndVerifyAssets
(
setUp
(()
async
{
assets
,
testFileSystem
=
MemoryFileSystem
(
<
String
>[
'test_package'
],
style:
globals
.
platform
.
isWindows
expectedManifest
,
?
FileSystemStyle
.
windows
:
FileSystemStyle
.
posix
,
);
);
},
overrides:
<
Type
,
Generator
>{
testFileSystem
.
currentDirectory
=
testFileSystem
.
systemTempDirectory
.
createTempSync
(
'flutter_asset_bundle_test.'
);
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
});
testUsingContext
(
'One asset and its variant are bundled when the package '
group
(
'AssetBundle assets from packages'
,
()
{
'has an asset and a variant, and the app lists the asset in its pubspec'
,
()
async
{
testUsingContext
(
'No assets are bundled when the package has no assets'
,
()
async
{
writePubspecFile
(
writePubspecFile
(
'pubspec.yaml'
,
'test'
);
'pubspec.yaml'
,
writePackagesFile
(
'test_package:p/p/lib/'
);
'test'
,
writePubspecFile
(
'p/p/pubspec.yaml'
,
'test_package'
);
assets:
<
String
>[
'packages/test_package/a/foo'
],
);
final
AssetBundle
bundle
=
AssetBundleFactory
.
instance
.
createBundle
();
writePackagesFile
(
'test_package:p/p/lib/'
);
await
bundle
.
build
(
packagesPath:
'.packages'
);
writePubspecFile
(
expect
(
bundle
.
entries
.
keys
,
unorderedEquals
(
'p/p/pubspec.yaml'
,
<
String
>[
'AssetManifest.bin'
,
'AssetManifest.json'
,
'FontManifest.json'
,
'NOTICES.Z'
]
'test_package'
,
));
);
const
String
expectedAssetManifest
=
'{}'
;
expect
(
final
List
<
String
>
assets
=
<
String
>[
'a/foo'
,
'a/2x/foo'
];
utf8
.
decode
(
await
bundle
.
entries
[
'AssetManifest.json'
]!.
contentsAsBytes
()),
writeAssets
(
'p/p/lib/'
,
assets
);
expectedAssetManifest
,
);
const
String
expectedManifest
=
'{"packages/test_package/a/foo":'
expect
(
'["packages/test_package/a/foo","packages/test_package/a/2x/foo"]}'
;
utf8
.
decode
(
await
bundle
.
entries
[
'FontManifest.json'
]!.
contentsAsBytes
()),
'[]'
,
await
buildAndVerifyAssets
(
);
assets
,
},
overrides:
<
Type
,
Generator
>{
<
String
>[
'test_package'
],
FileSystem:
()
=>
testFileSystem
,
expectedManifest
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
);
});
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
testUsingContext
(
'No assets are bundled when the package has an asset that is not listed'
,
()
async
{
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
writePubspecFile
(
'pubspec.yaml'
,
'test'
);
writePackagesFile
(
'test_package:p/p/lib/'
);
writePubspecFile
(
'p/p/pubspec.yaml'
,
'test_package'
);
final
List
<
String
>
assets
=
<
String
>[
'a/foo'
];
writeAssets
(
'p/p/'
,
assets
);
final
AssetBundle
bundle
=
AssetBundleFactory
.
instance
.
createBundle
();
await
bundle
.
build
(
packagesPath:
'.packages'
);
expect
(
bundle
.
entries
.
keys
,
unorderedEquals
(
<
String
>[
'AssetManifest.bin'
,
'AssetManifest.json'
,
'FontManifest.json'
,
'NOTICES.Z'
]
));
const
String
expectedAssetManifest
=
'{}'
;
expect
(
utf8
.
decode
(
await
bundle
.
entries
[
'AssetManifest.json'
]!.
contentsAsBytes
()),
expectedAssetManifest
,
);
expect
(
utf8
.
decode
(
await
bundle
.
entries
[
'FontManifest.json'
]!.
contentsAsBytes
()),
'[]'
,
);
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
testUsingContext
(
'One asset is bundled when the package has and lists one '
'asset its pubspec'
,
()
async
{
writePubspecFile
(
'pubspec.yaml'
,
'test'
);
writePackagesFile
(
'test_package:p/p/lib/'
);
final
List
<
String
>
assets
=
<
String
>[
'a/foo'
];
writePubspecFile
(
'p/p/pubspec.yaml'
,
'test_package'
,
assets:
assets
,
);
writeAssets
(
'p/p/'
,
assets
);
const
String
expectedAssetManifest
=
'{"packages/test_package/a/foo":'
'["packages/test_package/a/foo"]}'
;
await
buildAndVerifyAssets
(
assets
,
<
String
>[
'test_package'
],
expectedAssetManifest
,
);
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
testUsingContext
(
'One asset is bundled when the package has one asset, '
"listed in the app's pubspec"
,
()
async
{
final
List
<
String
>
assetEntries
=
<
String
>[
'packages/test_package/a/foo'
];
writePubspecFile
(
'pubspec.yaml'
,
'test'
,
assets:
assetEntries
,
);
writePackagesFile
(
'test_package:p/p/lib/'
);
writePubspecFile
(
'p/p/pubspec.yaml'
,
'test_package'
);
final
List
<
String
>
assets
=
<
String
>[
'a/foo'
];
writeAssets
(
'p/p/lib/'
,
assets
);
const
String
expectedAssetManifest
=
'{"packages/test_package/a/foo":'
'["packages/test_package/a/foo"]}'
;
await
buildAndVerifyAssets
(
assets
,
<
String
>[
'test_package'
],
expectedAssetManifest
,
);
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
testUsingContext
(
'One asset and its variant are bundled when the package '
'has an asset and a variant, and lists the asset in its pubspec'
,
()
async
{
writePubspecFile
(
'pubspec.yaml'
,
'test'
);
writePackagesFile
(
'test_package:p/p/lib/'
);
writePubspecFile
(
'p/p/pubspec.yaml'
,
'test_package'
,
assets:
<
String
>[
'a/foo'
,
'a/bar'
],
);
final
List
<
String
>
assets
=
<
String
>[
'a/foo'
,
'a/2x/foo'
,
'a/bar'
];
writeAssets
(
'p/p/'
,
assets
);
const
String
expectedManifest
=
'{'
'"packages/test_package/a/bar":'
'["packages/test_package/a/bar"],'
'"packages/test_package/a/foo":'
'["packages/test_package/a/foo","packages/test_package/a/2x/foo"]'
'}'
;
await
buildAndVerifyAssets
(
assets
,
<
String
>[
'test_package'
],
expectedManifest
,
);
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
testUsingContext
(
'One asset and its variant are bundled when the package '
'has an asset and a variant, and the app lists the asset in its pubspec'
,
()
async
{
writePubspecFile
(
'pubspec.yaml'
,
'test'
,
assets:
<
String
>[
'packages/test_package/a/foo'
],
);
writePackagesFile
(
'test_package:p/p/lib/'
);
writePubspecFile
(
'p/p/pubspec.yaml'
,
'test_package'
,
);
final
List
<
String
>
assets
=
<
String
>[
'a/foo'
,
'a/2x/foo'
];
writeAssets
(
'p/p/lib/'
,
assets
);
const
String
expectedManifest
=
'{"packages/test_package/a/foo":'
'["packages/test_package/a/foo","packages/test_package/a/2x/foo"]}'
;
await
buildAndVerifyAssets
(
assets
,
<
String
>[
'test_package'
],
expectedManifest
,
);
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
testUsingContext
(
'Two assets are bundled when the package has and lists '
'two assets in its pubspec'
,
()
async
{
writePubspecFile
(
'pubspec.yaml'
,
'test'
);
writePackagesFile
(
'test_package:p/p/lib/'
);
final
List
<
String
>
assets
=
<
String
>[
'a/foo'
,
'a/bar'
];
writePubspecFile
(
'p/p/pubspec.yaml'
,
'test_package'
,
assets:
assets
,
);
writeAssets
(
'p/p/'
,
assets
);
const
String
expectedAssetManifest
=
'{"packages/test_package/a/bar":["packages/test_package/a/bar"],'
'"packages/test_package/a/foo":["packages/test_package/a/foo"]}'
;
await
buildAndVerifyAssets
(
assets
,
<
String
>[
'test_package'
],
expectedAssetManifest
,
);
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
testUsingContext
(
"Two assets are bundled when the package has two assets, listed in the app's pubspec"
,
()
async
{
final
List
<
String
>
assetEntries
=
<
String
>[
'packages/test_package/a/foo'
,
'packages/test_package/a/bar'
,
];
writePubspecFile
(
'pubspec.yaml'
,
'test'
,
assets:
assetEntries
,
);
writePackagesFile
(
'test_package:p/p/lib/'
);
final
List
<
String
>
assets
=
<
String
>[
'a/foo'
,
'a/bar'
];
writePubspecFile
(
'p/p/pubspec.yaml'
,
'test_package'
,
);
writeAssets
(
'p/p/lib/'
,
assets
);
const
String
expectedAssetManifest
=
'{"packages/test_package/a/bar":["packages/test_package/a/bar"],'
'"packages/test_package/a/foo":["packages/test_package/a/foo"]}'
;
await
buildAndVerifyAssets
(
assets
,
<
String
>[
'test_package'
],
expectedAssetManifest
,
);
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
testUsingContext
(
'Two assets are bundled when two packages each have and list an asset their pubspec'
,
()
async
{
writePubspecFile
(
'pubspec.yaml'
,
'test'
,
);
writePackagesFile
(
'test_package:p/p/lib/
\n
test_package2:p2/p/lib/'
);
writePubspecFile
(
'p/p/pubspec.yaml'
,
'test_package'
,
assets:
<
String
>[
'a/foo'
],
);
writePubspecFile
(
'p2/p/pubspec.yaml'
,
'test_package2'
,
assets:
<
String
>[
'a/foo'
],
);
final
List
<
String
>
assets
=
<
String
>[
'a/foo'
,
'a/2x/foo'
];
writeAssets
(
'p/p/'
,
assets
);
writeAssets
(
'p2/p/'
,
assets
);
const
String
expectedAssetManifest
=
'{"packages/test_package/a/foo":'
'["packages/test_package/a/foo","packages/test_package/a/2x/foo"],'
'"packages/test_package2/a/foo":'
'["packages/test_package2/a/foo","packages/test_package2/a/2x/foo"]}'
;
await
buildAndVerifyAssets
(
assets
,
<
String
>[
'test_package'
,
'test_package2'
],
expectedAssetManifest
,
);
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
testUsingContext
(
"Two assets are bundled when two packages each have an asset, listed in the app's pubspec"
,
()
async
{
final
List
<
String
>
assetEntries
=
<
String
>[
'packages/test_package/a/foo'
,
'packages/test_package2/a/foo'
,
];
writePubspecFile
(
'pubspec.yaml'
,
'test'
,
assets:
assetEntries
,
);
writePackagesFile
(
'test_package:p/p/lib/
\n
test_package2:p2/p/lib/'
);
writePubspecFile
(
'p/p/pubspec.yaml'
,
'test_package'
,
);
writePubspecFile
(
'p2/p/pubspec.yaml'
,
'test_package2'
,
);
final
List
<
String
>
assets
=
<
String
>[
'a/foo'
,
'a/2x/foo'
];
writeAssets
(
'p/p/lib/'
,
assets
);
writeAssets
(
'p2/p/lib/'
,
assets
);
const
String
expectedAssetManifest
=
'{"packages/test_package/a/foo":'
'["packages/test_package/a/foo","packages/test_package/a/2x/foo"],'
'"packages/test_package2/a/foo":'
'["packages/test_package2/a/foo","packages/test_package2/a/2x/foo"]}'
;
await
buildAndVerifyAssets
(
assets
,
<
String
>[
'test_package'
,
'test_package2'
],
expectedAssetManifest
,
);
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
testUsingContext
(
'One asset is bundled when the app depends on a package, '
'listing in its pubspec an asset from another package'
,
()
async
{
writePubspecFile
(
'pubspec.yaml'
,
'test'
,
);
writePackagesFile
(
'test_package:p/p/lib/
\n
test_package2:p2/p/lib/'
);
writePubspecFile
(
'p/p/pubspec.yaml'
,
'test_package'
,
assets:
<
String
>[
'packages/test_package2/a/foo'
],
);
writePubspecFile
(
'p2/p/pubspec.yaml'
,
'test_package2'
,
);
final
List
<
String
>
assets
=
<
String
>[
'a/foo'
,
'a/2x/foo'
];
writeAssets
(
'p2/p/lib/'
,
assets
);
const
String
expectedAssetManifest
=
'{"packages/test_package2/a/foo":'
'["packages/test_package2/a/foo","packages/test_package2/a/2x/foo"]}'
;
await
buildAndVerifyAssets
(
assets
,
<
String
>[
'test_package2'
],
expectedAssetManifest
,
);
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
});
});
testUsingContext
(
'Two assets are bundled when the package has and lists '
testUsingContext
(
'Asset paths can contain URL reserved characters'
,
()
async
{
'two assets in its pubspec'
,
()
async
{
writePubspecFile
(
'pubspec.yaml'
,
'test'
);
writePubspecFile
(
'pubspec.yaml'
,
'test'
);
writePackagesFile
(
'test_package:p/p/lib/'
);
writePackagesFile
(
'test_package:p/p/lib/'
);
final
List
<
String
>
assets
=
<
String
>[
'a/foo'
,
'a/
bar
'
];
final
List
<
String
>
assets
=
<
String
>[
'a/foo'
,
'a/
foo [x]
'
];
writePubspecFile
(
writePubspecFile
(
'p/p/pubspec.yaml'
,
'p/p/pubspec.yaml'
,
'test_package'
,
'test_package'
,
...
@@ -285,8 +466,8 @@ $assetsSection
...
@@ -285,8 +466,8 @@ $assetsSection
writeAssets
(
'p/p/'
,
assets
);
writeAssets
(
'p/p/'
,
assets
);
const
String
expectedAssetManifest
=
const
String
expectedAssetManifest
=
'{"packages/test_package/a/
bar":["packages/test_package/a/bar
"],'
'{"packages/test_package/a/
foo":["packages/test_package/a/foo
"],'
'"packages/test_package/a/foo
":["packages/test_package/a/foo
"]}'
;
'"packages/test_package/a/foo
[x]":["packages/test_package/a/foo [x]
"]}'
;
await
buildAndVerifyAssets
(
await
buildAndVerifyAssets
(
assets
,
assets
,
...
@@ -295,283 +476,584 @@ $assetsSection
...
@@ -295,283 +476,584 @@ $assetsSection
);
);
},
overrides:
<
Type
,
Generator
>{
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
});
testUsingContext
(
"Two assets are bundled when the package has two assets, listed in the app's pubspec"
,
()
async
{
group
(
'AssetBundle assets from scanned paths'
,
()
{
final
List
<
String
>
assetEntries
=
<
String
>[
testUsingContext
(
'Two assets are bundled when scanning their directory'
,
()
async
{
'packages/test_package/a/foo'
,
writePubspecFile
(
'pubspec.yaml'
,
'test'
);
'packages/test_package/a/bar'
,
writePackagesFile
(
'test_package:p/p/lib/'
);
];
writePubspecFile
(
final
List
<
String
>
assetsOnDisk
=
<
String
>[
'a/foo'
,
'a/bar'
];
'pubspec.yaml'
,
final
List
<
String
>
assetsOnManifest
=
<
String
>[
'a/'
];
'test'
,
assets:
assetEntries
,
writePubspecFile
(
);
'p/p/pubspec.yaml'
,
writePackagesFile
(
'test_package:p/p/lib/'
);
'test_package'
,
assets:
assetsOnManifest
,
final
List
<
String
>
assets
=
<
String
>[
'a/foo'
,
'a/bar'
];
);
writePubspecFile
(
'p/p/pubspec.yaml'
,
writeAssets
(
'p/p/'
,
assetsOnDisk
);
'test_package'
,
const
String
expectedAssetManifest
=
);
'{"packages/test_package/a/bar":["packages/test_package/a/bar"],'
'"packages/test_package/a/foo":["packages/test_package/a/foo"]}'
;
writeAssets
(
'p/p/lib/'
,
assets
);
const
String
expectedAssetManifest
=
await
buildAndVerifyAssets
(
'{"packages/test_package/a/bar":["packages/test_package/a/bar"],'
assetsOnDisk
,
'"packages/test_package/a/foo":["packages/test_package/a/foo"]}'
;
<
String
>[
'test_package'
],
expectedAssetManifest
,
await
buildAndVerifyAssets
(
);
assets
,
},
overrides:
<
Type
,
Generator
>{
<
String
>[
'test_package'
],
FileSystem:
()
=>
testFileSystem
,
expectedAssetManifest
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
);
});
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
testUsingContext
(
'Two assets are bundled when listing one and scanning second directory'
,
()
async
{
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
writePubspecFile
(
'pubspec.yaml'
,
'test'
);
writePackagesFile
(
'test_package:p/p/lib/'
);
final
List
<
String
>
assetsOnDisk
=
<
String
>[
'a/foo'
,
'abc/bar'
];
final
List
<
String
>
assetOnManifest
=
<
String
>[
'a/foo'
,
'abc/'
];
writePubspecFile
(
'p/p/pubspec.yaml'
,
'test_package'
,
assets:
assetOnManifest
,
);
writeAssets
(
'p/p/'
,
assetsOnDisk
);
const
String
expectedAssetManifest
=
'{"packages/test_package/a/foo":["packages/test_package/a/foo"],'
'"packages/test_package/abc/bar":["packages/test_package/abc/bar"]}'
;
await
buildAndVerifyAssets
(
assetsOnDisk
,
<
String
>[
'test_package'
],
expectedAssetManifest
,
);
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
testUsingContext
(
'One asset is bundled with variant, scanning wrong directory'
,
()
async
{
writePubspecFile
(
'pubspec.yaml'
,
'test'
);
writePackagesFile
(
'test_package:p/p/lib/'
);
final
List
<
String
>
assetsOnDisk
=
<
String
>[
'a/foo'
,
'a/b/foo'
,
'a/bar'
];
final
List
<
String
>
assetOnManifest
=
<
String
>[
'a'
,
'a/bar'
];
// can't list 'a' as asset, should be 'a/'
writePubspecFile
(
'p/p/pubspec.yaml'
,
'test_package'
,
assets:
assetOnManifest
,
);
writeAssets
(
'p/p/'
,
assetsOnDisk
);
final
AssetBundle
bundle
=
AssetBundleFactory
.
instance
.
createBundle
();
await
bundle
.
build
(
packagesPath:
'.packages'
);
expect
(
bundle
.
entries
[
'AssetManifest.bin'
],
isNull
,
reason:
'Invalid pubspec.yaml should not generate AssetManifest.bin'
);
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
});
});
testUsingContext
(
'Two assets are bundled when two packages each have and list an asset their pubspec'
,
()
async
{
group
(
'AssetBundle assets from scanned paths with MemoryFileSystem'
,
()
{
writePubspecFile
(
testUsingContext
(
'One asset is bundled with variant, scanning directory'
,
()
async
{
'pubspec.yaml'
,
writePubspecFile
(
'pubspec.yaml'
,
'test'
);
'test'
,
writePackagesFile
(
'test_package:p/p/lib/'
);
);
writePackagesFile
(
'test_package:p/p/lib/
\n
test_package2:p2/p/lib/'
);
final
List
<
String
>
assetsOnDisk
=
<
String
>[
'a/foo'
,
'a/2x/foo'
];
writePubspecFile
(
final
List
<
String
>
assetOnManifest
=
<
String
>[
'a/'
,];
'p/p/pubspec.yaml'
,
'test_package'
,
writePubspecFile
(
assets:
<
String
>[
'a/foo'
],
'p/p/pubspec.yaml'
,
);
'test_package'
,
writePubspecFile
(
assets:
assetOnManifest
,
'p2/p/pubspec.yaml'
,
);
'test_package2'
,
assets:
<
String
>[
'a/foo'
],
writeAssets
(
'p/p/'
,
assetsOnDisk
);
);
const
String
expectedAssetManifest
=
'{"packages/test_package/a/foo":["packages/test_package/a/foo","packages/test_package/a/2x/foo"]}'
;
final
List
<
String
>
assets
=
<
String
>[
'a/foo'
,
'a/2x/foo'
];
writeAssets
(
'p/p/'
,
assets
);
await
buildAndVerifyAssets
(
writeAssets
(
'p2/p/'
,
assets
);
assetsOnDisk
,
<
String
>[
'test_package'
],
const
String
expectedAssetManifest
=
expectedAssetManifest
,
'{"packages/test_package/a/foo":'
);
'["packages/test_package/a/foo","packages/test_package/a/2x/foo"],'
},
overrides:
<
Type
,
Generator
>{
'"packages/test_package2/a/foo":'
FileSystem:
()
=>
testFileSystem
,
'["packages/test_package2/a/foo","packages/test_package2/a/2x/foo"]}'
;
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
await
buildAndVerifyAssets
(
assets
,
testUsingContext
(
'No asset is bundled with variant, no assets or directories are listed'
,
()
async
{
<
String
>[
'test_package'
,
'test_package2'
],
writePubspecFile
(
'pubspec.yaml'
,
'test'
);
expectedAssetManifest
,
writePackagesFile
(
'test_package:p/p/lib/'
);
);
},
overrides:
<
Type
,
Generator
>{
final
List
<
String
>
assetsOnDisk
=
<
String
>[
'a/foo'
,
'a/2x/foo'
];
FileSystem:
()
=>
testFileSystem
,
final
List
<
String
>
assetOnManifest
=
<
String
>[];
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
writePubspecFile
(
'p/p/pubspec.yaml'
,
testUsingContext
(
"Two assets are bundled when two packages each have an asset, listed in the app's pubspec"
,
()
async
{
'test_package'
,
final
List
<
String
>
assetEntries
=
<
String
>[
assets:
assetOnManifest
,
'packages/test_package/a/foo'
,
);
'packages/test_package2/a/foo'
,
];
writeAssets
(
'p/p/'
,
assetsOnDisk
);
writePubspecFile
(
const
String
expectedAssetManifest
=
'{}'
;
'pubspec.yaml'
,
'test'
,
await
buildAndVerifyAssets
(
assets:
assetEntries
,
assetOnManifest
,
);
<
String
>[
'test_package'
],
writePackagesFile
(
'test_package:p/p/lib/
\n
test_package2:p2/p/lib/'
);
expectedAssetManifest
,
writePubspecFile
(
);
'p/p/pubspec.yaml'
,
},
overrides:
<
Type
,
Generator
>{
'test_package'
,
FileSystem:
()
=>
testFileSystem
,
);
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
writePubspecFile
(
});
'p2/p/pubspec.yaml'
,
'test_package2'
,
testUsingContext
(
'Expect error generating manifest, wrong non-existing directory is listed'
,
()
async
{
);
writePubspecFile
(
'pubspec.yaml'
,
'test'
);
writePackagesFile
(
'test_package:p/p/lib/'
);
final
List
<
String
>
assets
=
<
String
>[
'a/foo'
,
'a/2x/foo'
];
writeAssets
(
'p/p/lib/'
,
assets
);
final
List
<
String
>
assetOnManifest
=
<
String
>[
'c/'
];
writeAssets
(
'p2/p/lib/'
,
assets
);
writePubspecFile
(
const
String
expectedAssetManifest
=
'p/p/pubspec.yaml'
,
'{"packages/test_package/a/foo":'
'test_package'
,
'["packages/test_package/a/foo","packages/test_package/a/2x/foo"],'
assets:
assetOnManifest
,
'"packages/test_package2/a/foo":'
);
'["packages/test_package2/a/foo","packages/test_package2/a/2x/foo"]}'
;
await
buildAndVerifyAssets
(
await
buildAndVerifyAssets
(
assetOnManifest
,
assets
,
<
String
>[
'test_package'
],
<
String
>[
'test_package'
,
'test_package2'
],
null
,
expectedAssetManifest
,
expectExists:
false
,
);
);
},
overrides:
<
Type
,
Generator
>{
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
});
testUsingContext
(
'One asset is bundled when the app depends on a package, '
'listing in its pubspec an asset from another package'
,
()
async
{
writePubspecFile
(
'pubspec.yaml'
,
'test'
,
);
writePackagesFile
(
'test_package:p/p/lib/
\n
test_package2:p2/p/lib/'
);
writePubspecFile
(
'p/p/pubspec.yaml'
,
'test_package'
,
assets:
<
String
>[
'packages/test_package2/a/foo'
],
);
writePubspecFile
(
'p2/p/pubspec.yaml'
,
'test_package2'
,
);
final
List
<
String
>
assets
=
<
String
>[
'a/foo'
,
'a/2x/foo'
];
writeAssets
(
'p2/p/lib/'
,
assets
);
const
String
expectedAssetManifest
=
'{"packages/test_package2/a/foo":'
'["packages/test_package2/a/foo","packages/test_package2/a/2x/foo"]}'
;
await
buildAndVerifyAssets
(
assets
,
<
String
>[
'test_package2'
],
expectedAssetManifest
,
);
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
});
});
});
group
(
'Current asset manifest (AssetManifest.bin)'
,
()
{
Future
<
String
>
extractAssetManifestFromBundleAsJson
(
AssetBundle
bundle
)
async
{
final
List
<
int
>
manifestBytes
=
await
bundle
.
entries
[
'AssetManifest.bin'
]!.
contentsAsBytes
();
return
json
.
encode
(
const
StandardMessageCodec
().
decodeMessage
(
ByteData
.
sublistView
(
Uint8List
.
fromList
(
manifestBytes
))
));
}
testUsingContext
(
'Asset paths can contain URL reserved characters'
,
()
async
{
Future
<
void
>
buildAndVerifyAssets
(
writePubspecFile
(
'pubspec.yaml'
,
'test'
);
List
<
String
>
assets
,
writePackagesFile
(
'test_package:p/p/lib/'
);
List
<
String
>
packages
,
String
?
expectedAssetManifest
,
{
final
List
<
String
>
assets
=
<
String
>[
'a/foo'
,
'a/foo [x]'
];
bool
expectExists
=
true
,
writePubspecFile
(
})
async
{
'p/p/pubspec.yaml'
,
final
AssetBundle
bundle
=
AssetBundleFactory
.
instance
.
createBundle
();
'test_package'
,
await
bundle
.
build
(
packagesPath:
'.packages'
);
assets:
assets
,
);
writeAssets
(
'p/p/'
,
assets
);
const
String
expectedAssetManifest
=
'{"packages/test_package/a/foo":["packages/test_package/a/foo"],'
'"packages/test_package/a/foo [x]":["packages/test_package/a/foo [x]"]}'
;
await
buildAndVerifyAssets
(
assets
,
<
String
>[
'test_package'
],
expectedAssetManifest
,
);
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
group
(
'AssetBundle assets from scanned paths'
,
()
{
testUsingContext
(
'Two assets are bundled when scanning their directory'
,
()
async
{
writePubspecFile
(
'pubspec.yaml'
,
'test'
);
writePackagesFile
(
'test_package:p/p/lib/'
);
final
List
<
String
>
assetsOnDisk
=
<
String
>[
'a/foo'
,
'a/bar'
];
final
List
<
String
>
assetsOnManifest
=
<
String
>[
'a/'
];
writePubspecFile
(
'p/p/pubspec.yaml'
,
'test_package'
,
assets:
assetsOnManifest
,
);
writeAssets
(
'p/p/'
,
assetsOnDisk
);
const
String
expectedAssetManifest
=
'{"packages/test_package/a/bar":["packages/test_package/a/bar"],'
'"packages/test_package/a/foo":["packages/test_package/a/foo"]}'
;
await
buildAndVerifyAssets
(
for
(
final
String
packageName
in
packages
)
{
assetsOnDisk
,
for
(
final
String
asset
in
assets
)
{
<
String
>[
'test_package'
],
final
String
entryKey
=
Uri
.
encodeFull
(
'packages/
$packageName
/
$asset
'
);
expectedAssetManifest
,
expect
(
bundle
.
entries
.
containsKey
(
entryKey
),
expectExists
,
);
reason:
'Cannot find key on bundle:
$entryKey
'
);
},
overrides:
<
Type
,
Generator
>{
if
(
expectExists
)
{
FileSystem:
()
=>
testFileSystem
,
expect
(
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
utf8
.
decode
(
await
bundle
.
entries
[
entryKey
]!.
contentsAsBytes
()),
});
asset
,
);
}
}
}
testUsingContext
(
'Two assets are bundled when listing one and scanning second directory'
,
()
async
{
if
(
expectExists
)
{
writePubspecFile
(
'pubspec.yaml'
,
'test'
);
final
String
actualAssetManifest
=
await
extractAssetManifestFromBundleAsJson
(
bundle
);
writePackagesFile
(
'test_package:p/p/lib/'
);
expect
(
actualAssetManifest
,
expectedAssetManifest
,
);
}
}
final
List
<
String
>
assetsOnDisk
=
<
String
>[
'a/foo'
,
'abc/bar'
];
void
writeAssets
(
String
path
,
List
<
String
>
assets
)
{
final
List
<
String
>
assetOnManifest
=
<
String
>[
'a/foo'
,
'abc/'
];
for
(
final
String
asset
in
assets
)
{
final
String
fullPath
=
fixPath
(
globals
.
fs
.
path
.
join
(
path
,
asset
));
writePubspecFile
(
globals
.
fs
.
file
(
fullPath
)
'p/p/pubspec.yaml'
,
..
createSync
(
recursive:
true
)
'test_package'
,
..
writeAsStringSync
(
asset
);
assets:
assetOnManifest
,
}
);
}
writeAssets
(
'p/p/'
,
assetsOnDisk
);
late
FileSystem
testFileSystem
;
const
String
expectedAssetManifest
=
'{"packages/test_package/a/foo":["packages/test_package/a/foo"],'
'"packages/test_package/abc/bar":["packages/test_package/abc/bar"]}'
;
await
buildAndVerifyAssets
(
setUp
(()
async
{
assetsOnDisk
,
testFileSystem
=
MemoryFileSystem
(
<
String
>[
'test_package'
],
style:
globals
.
platform
.
isWindows
expectedAssetManifest
,
?
FileSystemStyle
.
windows
:
FileSystemStyle
.
posix
,
);
);
},
overrides:
<
Type
,
Generator
>{
testFileSystem
.
currentDirectory
=
testFileSystem
.
systemTempDirectory
.
createTempSync
(
'flutter_asset_bundle_test.'
);
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
});
testUsingContext
(
'One asset is bundled with variant, scanning wrong directory'
,
()
async
{
group
(
'AssetBundle assets from packages'
,
()
{
writePubspecFile
(
'pubspec.yaml'
,
'test'
);
testUsingContext
(
'No assets are bundled when the package has no assets'
,
()
async
{
writePackagesFile
(
'test_package:p/p/lib/'
);
writePubspecFile
(
'pubspec.yaml'
,
'test'
);
writePackagesFile
(
'test_package:p/p/lib/'
);
final
List
<
String
>
assetsOnDisk
=
<
String
>[
'a/foo'
,
'a/b/foo'
,
'a/bar'
];
writePubspecFile
(
'p/p/pubspec.yaml'
,
'test_package'
);
final
List
<
String
>
assetOnManifest
=
<
String
>[
'a'
,
'a/bar'
];
// can't list 'a' as asset, should be 'a/'
final
AssetBundle
bundle
=
AssetBundleFactory
.
instance
.
createBundle
();
writePubspecFile
(
await
bundle
.
build
(
packagesPath:
'.packages'
);
'p/p/pubspec.yaml'
,
expect
(
bundle
.
entries
.
keys
,
unorderedEquals
(
'test_package'
,
<
String
>[
'AssetManifest.bin'
,
'AssetManifest.json'
,
'FontManifest.json'
,
'NOTICES.Z'
]
assets:
assetOnManifest
,
));
);
final
String
actualAssetManifest
=
await
extractAssetManifestFromBundleAsJson
(
bundle
);
const
String
expectedAssetManifest
=
'{}'
;
writeAssets
(
'p/p/'
,
assetsOnDisk
);
expect
(
actualAssetManifest
,
final
AssetBundle
bundle
=
AssetBundleFactory
.
instance
.
createBundle
();
expectedAssetManifest
,
await
bundle
.
build
(
packagesPath:
'.packages'
);
);
expect
(
expect
(
bundle
.
entries
[
'AssetManifest.json'
],
isNull
,
utf8
.
decode
(
await
bundle
.
entries
[
'FontManifest.json'
]!.
contentsAsBytes
()),
reason:
'Invalid pubspec.yaml should not generate AssetManifest.json'
);
'[]'
,
},
overrides:
<
Type
,
Generator
>{
);
FileSystem:
()
=>
testFileSystem
,
},
overrides:
<
Type
,
Generator
>{
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
testUsingContext
(
'No assets are bundled when the package has an asset that is not listed'
,
()
async
{
writePubspecFile
(
'pubspec.yaml'
,
'test'
);
writePackagesFile
(
'test_package:p/p/lib/'
);
writePubspecFile
(
'p/p/pubspec.yaml'
,
'test_package'
);
final
List
<
String
>
assets
=
<
String
>[
'a/foo'
];
writeAssets
(
'p/p/'
,
assets
);
final
AssetBundle
bundle
=
AssetBundleFactory
.
instance
.
createBundle
();
await
bundle
.
build
(
packagesPath:
'.packages'
);
expect
(
bundle
.
entries
.
keys
,
unorderedEquals
(
<
String
>[
'AssetManifest.bin'
,
'AssetManifest.json'
,
'FontManifest.json'
,
'NOTICES.Z'
]
));
final
String
actualAssetManifest
=
await
extractAssetManifestFromBundleAsJson
(
bundle
);
const
String
expectedAssetManifest
=
'{}'
;
expect
(
actualAssetManifest
,
expectedAssetManifest
,
);
expect
(
utf8
.
decode
(
await
bundle
.
entries
[
'FontManifest.json'
]!.
contentsAsBytes
()),
'[]'
,
);
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
testUsingContext
(
'One asset is bundled when the package has and lists one '
'asset its pubspec'
,
()
async
{
writePubspecFile
(
'pubspec.yaml'
,
'test'
);
writePackagesFile
(
'test_package:p/p/lib/'
);
final
List
<
String
>
assets
=
<
String
>[
'a/foo'
];
writePubspecFile
(
'p/p/pubspec.yaml'
,
'test_package'
,
assets:
assets
,
);
writeAssets
(
'p/p/'
,
assets
);
const
String
expectedAssetManifest
=
'{"packages/test_package/a/foo":'
'[]}'
;
await
buildAndVerifyAssets
(
assets
,
<
String
>[
'test_package'
],
expectedAssetManifest
,
);
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
testUsingContext
(
'One asset is bundled when the package has one asset, '
"listed in the app's pubspec"
,
()
async
{
final
List
<
String
>
assetEntries
=
<
String
>[
'packages/test_package/a/foo'
];
writePubspecFile
(
'pubspec.yaml'
,
'test'
,
assets:
assetEntries
,
);
writePackagesFile
(
'test_package:p/p/lib/'
);
writePubspecFile
(
'p/p/pubspec.yaml'
,
'test_package'
);
final
List
<
String
>
assets
=
<
String
>[
'a/foo'
];
writeAssets
(
'p/p/lib/'
,
assets
);
const
String
expectedAssetManifest
=
'{"packages/test_package/a/foo":[]}'
;
await
buildAndVerifyAssets
(
assets
,
<
String
>[
'test_package'
],
expectedAssetManifest
,
);
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
testUsingContext
(
'One asset and its variant are bundled when the package '
'has an asset and a variant, and lists the asset in its pubspec'
,
()
async
{
writePubspecFile
(
'pubspec.yaml'
,
'test'
);
writePackagesFile
(
'test_package:p/p/lib/'
);
writePubspecFile
(
'p/p/pubspec.yaml'
,
'test_package'
,
assets:
<
String
>[
'a/foo'
,
'a/bar'
],
);
final
List
<
String
>
assets
=
<
String
>[
'a/foo'
,
'a/2x/foo'
,
'a/bar'
];
writeAssets
(
'p/p/'
,
assets
);
const
String
expectedManifest
=
'{'
'"packages/test_package/a/bar":[],'
'"packages/test_package/a/foo":['
'{"asset":"packages/test_package/a/2x/foo","dpr":2.0}]'
'}'
;
await
buildAndVerifyAssets
(
assets
,
<
String
>[
'test_package'
],
expectedManifest
,
);
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
testUsingContext
(
'One asset and its variant are bundled when the package '
'has an asset and a variant, and the app lists the asset in its pubspec'
,
()
async
{
writePubspecFile
(
'pubspec.yaml'
,
'test'
,
assets:
<
String
>[
'packages/test_package/a/foo'
],
);
writePackagesFile
(
'test_package:p/p/lib/'
);
writePubspecFile
(
'p/p/pubspec.yaml'
,
'test_package'
,
);
final
List
<
String
>
assets
=
<
String
>[
'a/foo'
,
'a/2x/foo'
];
writeAssets
(
'p/p/lib/'
,
assets
);
const
String
expectedManifest
=
'{"packages/test_package/a/foo":'
'[{"asset":"packages/test_package/a/2x/foo","dpr":2.0}]}'
;
await
buildAndVerifyAssets
(
assets
,
<
String
>[
'test_package'
],
expectedManifest
,
);
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
testUsingContext
(
'Two assets are bundled when the package has and lists '
'two assets in its pubspec'
,
()
async
{
writePubspecFile
(
'pubspec.yaml'
,
'test'
);
writePackagesFile
(
'test_package:p/p/lib/'
);
final
List
<
String
>
assets
=
<
String
>[
'a/foo'
,
'a/bar'
];
writePubspecFile
(
'p/p/pubspec.yaml'
,
'test_package'
,
assets:
assets
,
);
writeAssets
(
'p/p/'
,
assets
);
const
String
expectedAssetManifest
=
'{"packages/test_package/a/bar":[],'
'"packages/test_package/a/foo":[]}'
;
await
buildAndVerifyAssets
(
assets
,
<
String
>[
'test_package'
],
expectedAssetManifest
,
);
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
testUsingContext
(
"Two assets are bundled when the package has two assets, listed in the app's pubspec"
,
()
async
{
final
List
<
String
>
assetEntries
=
<
String
>[
'packages/test_package/a/foo'
,
'packages/test_package/a/bar'
,
];
writePubspecFile
(
'pubspec.yaml'
,
'test'
,
assets:
assetEntries
,
);
writePackagesFile
(
'test_package:p/p/lib/'
);
final
List
<
String
>
assets
=
<
String
>[
'a/foo'
,
'a/bar'
];
writePubspecFile
(
'p/p/pubspec.yaml'
,
'test_package'
,
);
writeAssets
(
'p/p/lib/'
,
assets
);
const
String
expectedAssetManifest
=
'{"packages/test_package/a/bar":[],'
'"packages/test_package/a/foo":[]}'
;
await
buildAndVerifyAssets
(
assets
,
<
String
>[
'test_package'
],
expectedAssetManifest
,
);
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
testUsingContext
(
'Two assets are bundled when two packages each have and list an asset their pubspec'
,
()
async
{
writePubspecFile
(
'pubspec.yaml'
,
'test'
,
);
writePackagesFile
(
'test_package:p/p/lib/
\n
test_package2:p2/p/lib/'
);
writePubspecFile
(
'p/p/pubspec.yaml'
,
'test_package'
,
assets:
<
String
>[
'a/foo'
],
);
writePubspecFile
(
'p2/p/pubspec.yaml'
,
'test_package2'
,
assets:
<
String
>[
'a/foo'
],
);
final
List
<
String
>
assets
=
<
String
>[
'a/foo'
,
'a/2x/foo'
];
writeAssets
(
'p/p/'
,
assets
);
writeAssets
(
'p2/p/'
,
assets
);
const
String
expectedAssetManifest
=
'{"packages/test_package/a/foo":'
'[{"asset":"packages/test_package/a/2x/foo","dpr":2.0}],'
'"packages/test_package2/a/foo":'
'[{"asset":"packages/test_package2/a/2x/foo","dpr":2.0}]}'
;
await
buildAndVerifyAssets
(
assets
,
<
String
>[
'test_package'
,
'test_package2'
],
expectedAssetManifest
,
);
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
testUsingContext
(
"Two assets are bundled when two packages each have an asset, listed in the app's pubspec"
,
()
async
{
final
List
<
String
>
assetEntries
=
<
String
>[
'packages/test_package/a/foo'
,
'packages/test_package2/a/foo'
,
];
writePubspecFile
(
'pubspec.yaml'
,
'test'
,
assets:
assetEntries
,
);
writePackagesFile
(
'test_package:p/p/lib/
\n
test_package2:p2/p/lib/'
);
writePubspecFile
(
'p/p/pubspec.yaml'
,
'test_package'
,
);
writePubspecFile
(
'p2/p/pubspec.yaml'
,
'test_package2'
,
);
final
List
<
String
>
assets
=
<
String
>[
'a/foo'
,
'a/2x/foo'
];
writeAssets
(
'p/p/lib/'
,
assets
);
writeAssets
(
'p2/p/lib/'
,
assets
);
const
String
expectedAssetManifest
=
'{"packages/test_package/a/foo":'
'[{"asset":"packages/test_package/a/2x/foo","dpr":2.0}],'
'"packages/test_package2/a/foo":'
'[{"asset":"packages/test_package2/a/2x/foo","dpr":2.0}]}'
;
await
buildAndVerifyAssets
(
assets
,
<
String
>[
'test_package'
,
'test_package2'
],
expectedAssetManifest
,
);
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
testUsingContext
(
'One asset is bundled when the app depends on a package, '
'listing in its pubspec an asset from another package'
,
()
async
{
writePubspecFile
(
'pubspec.yaml'
,
'test'
,
);
writePackagesFile
(
'test_package:p/p/lib/
\n
test_package2:p2/p/lib/'
);
writePubspecFile
(
'p/p/pubspec.yaml'
,
'test_package'
,
assets:
<
String
>[
'packages/test_package2/a/foo'
],
);
writePubspecFile
(
'p2/p/pubspec.yaml'
,
'test_package2'
,
);
final
List
<
String
>
assets
=
<
String
>[
'a/foo'
,
'a/2x/foo'
];
writeAssets
(
'p2/p/lib/'
,
assets
);
const
String
expectedAssetManifest
=
'{"packages/test_package2/a/foo":'
'[{"asset":"packages/test_package2/a/2x/foo","dpr":2.0}]}'
;
await
buildAndVerifyAssets
(
assets
,
<
String
>[
'test_package2'
],
expectedAssetManifest
,
);
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
});
});
});
group
(
'AssetBundle assets from scanned paths with MemoryFileSystem'
,
()
{
testUsingContext
(
'Asset paths can contain URL reserved characters'
,
()
async
{
testUsingContext
(
'One asset is bundled with variant, scanning directory'
,
()
async
{
writePubspecFile
(
'pubspec.yaml'
,
'test'
);
writePubspecFile
(
'pubspec.yaml'
,
'test'
);
writePackagesFile
(
'test_package:p/p/lib/'
);
writePackagesFile
(
'test_package:p/p/lib/'
);
final
List
<
String
>
assetsOnDisk
=
<
String
>[
'a/foo'
,
'a/2x/foo'
];
final
List
<
String
>
assets
=
<
String
>[
'a/foo'
,
'a/foo [x]'
];
final
List
<
String
>
assetOnManifest
=
<
String
>[
'a/'
,];
writePubspecFile
(
writePubspecFile
(
'p/p/pubspec.yaml'
,
'p/p/pubspec.yaml'
,
'test_package'
,
'test_package'
,
assets:
asset
OnManifest
,
assets:
asset
s
,
);
);
writeAssets
(
'p/p/'
,
assets
OnDisk
);
writeAssets
(
'p/p/'
,
assets
);
const
String
expectedAssetManifest
=
const
String
expectedAssetManifest
=
'{"packages/test_package/a/foo":["packages/test_package/a/foo","packages/test_package/a/2x/foo"]}'
;
'{"packages/test_package/a/foo":[],'
'"packages/test_package/a/foo [x]":[]}'
;
await
buildAndVerifyAssets
(
await
buildAndVerifyAssets
(
assets
OnDisk
,
assets
,
<
String
>[
'test_package'
],
<
String
>[
'test_package'
],
expectedAssetManifest
,
expectedAssetManifest
,
);
);
...
@@ -580,53 +1062,165 @@ $assetsSection
...
@@ -580,53 +1062,165 @@ $assetsSection
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
});
testUsingContext
(
'No asset is bundled with variant, no assets or directories are listed'
,
()
async
{
group
(
'AssetBundle assets from scanned paths'
,
()
{
writePubspecFile
(
'pubspec.yaml'
,
'test'
);
testUsingContext
(
'Two assets are bundled when scanning their directory'
,
()
async
{
writePackagesFile
(
'test_package:p/p/lib/'
);
writePubspecFile
(
'pubspec.yaml'
,
'test'
);
writePackagesFile
(
'test_package:p/p/lib/'
);
final
List
<
String
>
assetsOnDisk
=
<
String
>[
'a/foo'
,
'a/2x/foo'
];
final
List
<
String
>
assetOnManifest
=
<
String
>[];
final
List
<
String
>
assetsOnDisk
=
<
String
>[
'a/foo'
,
'a/bar'
];
final
List
<
String
>
assetsOnManifest
=
<
String
>[
'a/'
];
writePubspecFile
(
'p/p/pubspec.yaml'
,
writePubspecFile
(
'test_package'
,
'p/p/pubspec.yaml'
,
assets:
assetOnManifest
,
'test_package'
,
);
assets:
assetsOnManifest
,
);
writeAssets
(
'p/p/'
,
assetsOnDisk
);
const
String
expectedAssetManifest
=
'{}'
;
writeAssets
(
'p/p/'
,
assetsOnDisk
);
const
String
expectedAssetManifest
=
await
buildAndVerifyAssets
(
'{"packages/test_package/a/bar":[],'
assetOnManifest
,
'"packages/test_package/a/foo":[]}'
;
<
String
>[
'test_package'
],
expectedAssetManifest
,
await
buildAndVerifyAssets
(
);
assetsOnDisk
,
},
overrides:
<
Type
,
Generator
>{
<
String
>[
'test_package'
],
FileSystem:
()
=>
testFileSystem
,
expectedAssetManifest
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
);
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
testUsingContext
(
'Two assets are bundled when listing one and scanning second directory'
,
()
async
{
writePubspecFile
(
'pubspec.yaml'
,
'test'
);
writePackagesFile
(
'test_package:p/p/lib/'
);
final
List
<
String
>
assetsOnDisk
=
<
String
>[
'a/foo'
,
'abc/bar'
];
final
List
<
String
>
assetOnManifest
=
<
String
>[
'a/foo'
,
'abc/'
];
writePubspecFile
(
'p/p/pubspec.yaml'
,
'test_package'
,
assets:
assetOnManifest
,
);
writeAssets
(
'p/p/'
,
assetsOnDisk
);
const
String
expectedAssetManifest
=
'{"packages/test_package/a/foo":[],'
'"packages/test_package/abc/bar":[]}'
;
await
buildAndVerifyAssets
(
assetsOnDisk
,
<
String
>[
'test_package'
],
expectedAssetManifest
,
);
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
testUsingContext
(
'One asset is bundled with variant, scanning wrong directory'
,
()
async
{
writePubspecFile
(
'pubspec.yaml'
,
'test'
);
writePackagesFile
(
'test_package:p/p/lib/'
);
final
List
<
String
>
assetsOnDisk
=
<
String
>[
'a/foo'
,
'a/b/foo'
,
'a/bar'
];
final
List
<
String
>
assetOnManifest
=
<
String
>[
'a'
,
'a/bar'
];
// can't list 'a' as asset, should be 'a/'
writePubspecFile
(
'p/p/pubspec.yaml'
,
'test_package'
,
assets:
assetOnManifest
,
);
writeAssets
(
'p/p/'
,
assetsOnDisk
);
final
AssetBundle
bundle
=
AssetBundleFactory
.
instance
.
createBundle
();
await
bundle
.
build
(
packagesPath:
'.packages'
);
expect
(
bundle
.
entries
[
'AssetManifest.bin'
],
isNull
,
reason:
'Invalid pubspec.yaml should not generate AssetManifest.bin'
);
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
});
});
testUsingContext
(
'Expect error generating manifest, wrong non-existing directory is listed'
,
()
async
{
group
(
'AssetBundle assets from scanned paths with MemoryFileSystem'
,
()
{
writePubspecFile
(
'pubspec.yaml'
,
'test'
);
testUsingContext
(
'One asset is bundled with variant, scanning directory'
,
()
async
{
writePackagesFile
(
'test_package:p/p/lib/'
);
writePubspecFile
(
'pubspec.yaml'
,
'test'
);
writePackagesFile
(
'test_package:p/p/lib/'
);
final
List
<
String
>
assetOnManifest
=
<
String
>[
'c/'
];
final
List
<
String
>
assetsOnDisk
=
<
String
>[
'a/foo'
,
'a/2x/foo'
];
writePubspecFile
(
final
List
<
String
>
assetOnManifest
=
<
String
>[
'a/'
,];
'p/p/pubspec.yaml'
,
'test_package'
,
writePubspecFile
(
assets:
assetOnManifest
,
'p/p/pubspec.yaml'
,
);
'test_package'
,
assets:
assetOnManifest
,
await
buildAndVerifyAssets
(
);
assetOnManifest
,
<
String
>[
'test_package'
],
writeAssets
(
'p/p/'
,
assetsOnDisk
);
null
,
const
String
expectedAssetManifest
=
expectExists:
false
,
'{"packages/test_package/a/foo":[{"asset":"packages/test_package/a/2x/foo","dpr":2.0}]}'
;
);
},
overrides:
<
Type
,
Generator
>{
await
buildAndVerifyAssets
(
FileSystem:
()
=>
testFileSystem
,
assetsOnDisk
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
<
String
>[
'test_package'
],
expectedAssetManifest
,
);
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
testUsingContext
(
'No asset is bundled with variant, no assets or directories are listed'
,
()
async
{
writePubspecFile
(
'pubspec.yaml'
,
'test'
);
writePackagesFile
(
'test_package:p/p/lib/'
);
final
List
<
String
>
assetsOnDisk
=
<
String
>[
'a/foo'
,
'a/2x/foo'
];
final
List
<
String
>
assetOnManifest
=
<
String
>[];
writePubspecFile
(
'p/p/pubspec.yaml'
,
'test_package'
,
assets:
assetOnManifest
,
);
writeAssets
(
'p/p/'
,
assetsOnDisk
);
const
String
expectedAssetManifest
=
'{}'
;
await
buildAndVerifyAssets
(
assetOnManifest
,
<
String
>[
'test_package'
],
expectedAssetManifest
,
);
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
testUsingContext
(
'Expect error generating manifest, wrong non-existing directory is listed'
,
()
async
{
writePubspecFile
(
'pubspec.yaml'
,
'test'
);
writePackagesFile
(
'test_package:p/p/lib/'
);
final
List
<
String
>
assetOnManifest
=
<
String
>[
'c/'
];
writePubspecFile
(
'p/p/pubspec.yaml'
,
'test_package'
,
assets:
assetOnManifest
,
);
await
buildAndVerifyAssets
(
assetOnManifest
,
<
String
>[
'test_package'
],
null
,
expectExists:
false
,
);
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
});
});
});
});
}
}
packages/flutter_tools/test/general.shard/asset_bundle_test.dart
View file @
56cad89b
...
@@ -3,6 +3,7 @@
...
@@ -3,6 +3,7 @@
// found in the LICENSE file.
// found in the LICENSE file.
import
'dart:convert'
;
import
'dart:convert'
;
import
'dart:typed_data'
;
import
'package:file/memory.dart'
;
import
'package:file/memory.dart'
;
import
'package:flutter_tools/src/artifacts.dart'
;
import
'package:flutter_tools/src/artifacts.dart'
;
...
@@ -13,6 +14,7 @@ import 'package:flutter_tools/src/build_info.dart';
...
@@ -13,6 +14,7 @@ import 'package:flutter_tools/src/build_info.dart';
import
'package:flutter_tools/src/bundle_builder.dart'
;
import
'package:flutter_tools/src/bundle_builder.dart'
;
import
'package:flutter_tools/src/devfs.dart'
;
import
'package:flutter_tools/src/devfs.dart'
;
import
'package:flutter_tools/src/globals.dart'
as
globals
;
import
'package:flutter_tools/src/globals.dart'
as
globals
;
import
'package:standard_message_codec/standard_message_codec.dart'
;
import
'../src/common.dart'
;
import
'../src/common.dart'
;
import
'../src/context.dart'
;
import
'../src/context.dart'
;
...
@@ -48,11 +50,16 @@ void main() {
...
@@ -48,11 +50,16 @@ void main() {
final
AssetBundle
bundle
=
AssetBundleFactory
.
instance
.
createBundle
();
final
AssetBundle
bundle
=
AssetBundleFactory
.
instance
.
createBundle
();
await
bundle
.
build
(
packagesPath:
'.packages'
);
await
bundle
.
build
(
packagesPath:
'.packages'
);
expect
(
bundle
.
entries
.
length
,
1
);
expect
(
bundle
.
entries
.
keys
,
unorderedEquals
(<
String
>[
'AssetManifest.json'
,
'AssetManifest.bin'
])
);
const
String
expectedAssetManifest
=
'{}'
;
const
String
expected
Json
AssetManifest
=
'{}'
;
expect
(
expect
(
utf8
.
decode
(
await
bundle
.
entries
[
'AssetManifest.json'
]!.
contentsAsBytes
()),
utf8
.
decode
(
await
bundle
.
entries
[
'AssetManifest.json'
]!.
contentsAsBytes
()),
expectedAssetManifest
,
expectedJsonAssetManifest
,
);
const
String
expectedBinAssetManifest
=
'{}'
;
expect
(
await
_extractBinAssetManifestFromBundleAsJson
(
bundle
),
expectedBinAssetManifest
);
);
},
overrides:
<
Type
,
Generator
>{
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
FileSystem:
()
=>
testFileSystem
,
...
@@ -72,12 +79,8 @@ flutter:
...
@@ -72,12 +79,8 @@ flutter:
'''
);
'''
);
final
AssetBundle
bundle
=
AssetBundleFactory
.
instance
.
createBundle
();
final
AssetBundle
bundle
=
AssetBundleFactory
.
instance
.
createBundle
();
await
bundle
.
build
(
packagesPath:
'.packages'
);
await
bundle
.
build
(
packagesPath:
'.packages'
);
// Expected assets:
expect
(
bundle
.
entries
.
keys
,
unorderedEquals
(<
String
>[
'AssetManifest.json'
,
// - asset manifest
'AssetManifest.bin'
,
'FontManifest.json'
,
'NOTICES.Z'
,
'assets/foo/bar.txt'
]));
// - font manifest
// - license file
// - assets/foo/bar.txt
expect
(
bundle
.
entries
.
length
,
4
);
expect
(
bundle
.
needsBuild
(),
false
);
expect
(
bundle
.
needsBuild
(),
false
);
// Simulate modifying the files by updating the filestat time manually.
// Simulate modifying the files by updating the filestat time manually.
...
@@ -87,13 +90,9 @@ flutter:
...
@@ -87,13 +90,9 @@ flutter:
expect
(
bundle
.
needsBuild
(),
true
);
expect
(
bundle
.
needsBuild
(),
true
);
await
bundle
.
build
(
packagesPath:
'.packages'
);
await
bundle
.
build
(
packagesPath:
'.packages'
);
// Expected assets:
expect
(
bundle
.
entries
.
keys
,
unorderedEquals
(<
String
>[
'AssetManifest.json'
,
// - asset manifest
'AssetManifest.bin'
,
'FontManifest.json'
,
'NOTICES.Z'
,
'assets/foo/bar.txt'
,
// - font manifest
'assets/foo/fizz.txt'
]));
// - license file
// - assets/foo/bar.txt
// - assets/foo/fizz.txt
expect
(
bundle
.
entries
.
length
,
5
);
},
overrides:
<
Type
,
Generator
>{
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
...
@@ -112,12 +111,8 @@ flutter:
...
@@ -112,12 +111,8 @@ flutter:
globals
.
fs
.
file
(
'.packages'
).
createSync
();
globals
.
fs
.
file
(
'.packages'
).
createSync
();
final
AssetBundle
bundle
=
AssetBundleFactory
.
instance
.
createBundle
();
final
AssetBundle
bundle
=
AssetBundleFactory
.
instance
.
createBundle
();
await
bundle
.
build
(
packagesPath:
'.packages'
);
await
bundle
.
build
(
packagesPath:
'.packages'
);
// Expected assets:
expect
(
bundle
.
entries
.
keys
,
unorderedEquals
(<
String
>[
'AssetManifest.json'
,
// - asset manifest
'AssetManifest.bin'
,
'FontManifest.json'
,
'NOTICES.Z'
,
'assets/foo/bar.txt'
]));
// - font manifest
// - license file
// - assets/foo/bar.txt
expect
(
bundle
.
entries
.
length
,
4
);
expect
(
bundle
.
needsBuild
(),
false
);
expect
(
bundle
.
needsBuild
(),
false
);
// Delete the wildcard directory and update pubspec file.
// Delete the wildcard directory and update pubspec file.
...
@@ -138,12 +133,8 @@ name: example''')
...
@@ -138,12 +133,8 @@ name: example''')
// supporting file deletion.
// supporting file deletion.
expect
(
bundle
.
needsBuild
(),
true
);
expect
(
bundle
.
needsBuild
(),
true
);
await
bundle
.
build
(
packagesPath:
'.packages'
);
await
bundle
.
build
(
packagesPath:
'.packages'
);
// Expected assets:
expect
(
bundle
.
entries
.
keys
,
unorderedEquals
(<
String
>[
'AssetManifest.json'
,
// - asset manifest
'AssetManifest.bin'
,
'FontManifest.json'
,
'NOTICES.Z'
,
'assets/foo/bar.txt'
]));
// - font manifest
// - license file
// - assets/foo/bar.txt
expect
(
bundle
.
entries
.
length
,
4
);
},
overrides:
<
Type
,
Generator
>{
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
...
@@ -166,12 +157,8 @@ flutter:
...
@@ -166,12 +157,8 @@ flutter:
globals
.
fs
.
file
(
'.packages'
).
createSync
();
globals
.
fs
.
file
(
'.packages'
).
createSync
();
final
AssetBundle
bundle
=
AssetBundleFactory
.
instance
.
createBundle
();
final
AssetBundle
bundle
=
AssetBundleFactory
.
instance
.
createBundle
();
await
bundle
.
build
(
packagesPath:
'.packages'
);
await
bundle
.
build
(
packagesPath:
'.packages'
);
// Expected assets:
expect
(
bundle
.
entries
.
keys
,
unorderedEquals
(<
String
>[
'AssetManifest.json'
,
// - asset manifest
'AssetManifest.bin'
,
'FontManifest.json'
,
'NOTICES.Z'
,
'assets/foo/bar.txt'
]));
// - font manifest
// - license file
// - assets/foo/bar.txt
expect
(
bundle
.
entries
.
length
,
4
);
expect
(
bundle
.
needsBuild
(),
false
);
expect
(
bundle
.
needsBuild
(),
false
);
},
overrides:
<
Type
,
Generator
>{
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
FileSystem:
()
=>
testFileSystem
,
...
@@ -203,12 +190,8 @@ flutter:
...
@@ -203,12 +190,8 @@ flutter:
splitDeferredAssets:
true
,
splitDeferredAssets:
true
,
).
createBundle
();
).
createBundle
();
await
bundle
.
build
(
packagesPath:
'.packages'
,
deferredComponentsEnabled:
true
);
await
bundle
.
build
(
packagesPath:
'.packages'
,
deferredComponentsEnabled:
true
);
// Expected assets:
expect
(
bundle
.
entries
.
keys
,
unorderedEquals
(<
String
>[
'AssetManifest.json'
,
// - asset manifest
'AssetManifest.bin'
,
'FontManifest.json'
,
'NOTICES.Z'
,
'assets/foo/bar.txt'
]));
// - font manifest
// - license file
// - assets/foo/bar.txt
expect
(
bundle
.
entries
.
length
,
4
);
expect
(
bundle
.
deferredComponentsEntries
.
length
,
1
);
expect
(
bundle
.
deferredComponentsEntries
.
length
,
1
);
expect
(
bundle
.
deferredComponentsEntries
[
'component1'
]!.
length
,
2
);
expect
(
bundle
.
deferredComponentsEntries
[
'component1'
]!.
length
,
2
);
expect
(
bundle
.
needsBuild
(),
false
);
expect
(
bundle
.
needsBuild
(),
false
);
...
@@ -237,12 +220,9 @@ flutter:
...
@@ -237,12 +220,9 @@ flutter:
'''
);
'''
);
final
AssetBundle
bundle
=
AssetBundleFactory
.
instance
.
createBundle
();
final
AssetBundle
bundle
=
AssetBundleFactory
.
instance
.
createBundle
();
await
bundle
.
build
(
packagesPath:
'.packages'
);
await
bundle
.
build
(
packagesPath:
'.packages'
);
// Expected assets:
expect
(
bundle
.
entries
.
keys
,
unorderedEquals
(<
String
>[
'assets/foo/bar.txt'
,
// - asset manifest
'assets/bar/barbie.txt'
,
'assets/wild/dash.txt'
,
'AssetManifest.json'
,
// - font manifest
'AssetManifest.bin'
,
'FontManifest.json'
,
'NOTICES.Z'
]));
// - license file
// - assets/foo/bar.txt
expect
(
bundle
.
entries
.
length
,
6
);
expect
(
bundle
.
deferredComponentsEntries
.
isEmpty
,
true
);
expect
(
bundle
.
deferredComponentsEntries
.
isEmpty
,
true
);
expect
(
bundle
.
needsBuild
(),
false
);
expect
(
bundle
.
needsBuild
(),
false
);
},
overrides:
<
Type
,
Generator
>{
},
overrides:
<
Type
,
Generator
>{
...
@@ -275,14 +255,11 @@ flutter:
...
@@ -275,14 +255,11 @@ flutter:
splitDeferredAssets:
true
,
splitDeferredAssets:
true
,
).
createBundle
();
).
createBundle
();
await
bundle
.
build
(
packagesPath:
'.packages'
,
deferredComponentsEnabled:
true
);
await
bundle
.
build
(
packagesPath:
'.packages'
,
deferredComponentsEnabled:
true
);
// Expected assets:
expect
(
bundle
.
entries
.
keys
,
unorderedEquals
(<
String
>[
'assets/foo/bar.txt'
,
// - asset manifest
'AssetManifest.json'
,
'AssetManifest.bin'
,
'FontManifest.json'
,
'NOTICES.Z'
]));
// - font manifest
expect
(
bundle
.
deferredComponentsEntries
.
keys
,
unorderedEquals
(<
String
>[
'component1'
]));
// - license file
expect
(
bundle
.
deferredComponentsEntries
[
'component1'
]!.
keys
,
// - assets/foo/bar.txt
unorderedEquals
(<
String
>[
'assets/bar/barbie.txt'
,
'assets/wild/dash.txt'
]));
expect
(
bundle
.
entries
.
length
,
4
);
expect
(
bundle
.
deferredComponentsEntries
.
length
,
1
);
expect
(
bundle
.
deferredComponentsEntries
[
'component1'
]!.
length
,
2
);
expect
(
bundle
.
needsBuild
(),
false
);
expect
(
bundle
.
needsBuild
(),
false
);
// Simulate modifying the files by updating the filestat time manually.
// Simulate modifying the files by updating the filestat time manually.
...
@@ -293,9 +270,13 @@ flutter:
...
@@ -293,9 +270,13 @@ flutter:
expect
(
bundle
.
needsBuild
(),
true
);
expect
(
bundle
.
needsBuild
(),
true
);
await
bundle
.
build
(
packagesPath:
'.packages'
,
deferredComponentsEnabled:
true
);
await
bundle
.
build
(
packagesPath:
'.packages'
,
deferredComponentsEnabled:
true
);
expect
(
bundle
.
entries
.
length
,
4
);
expect
(
bundle
.
entries
.
keys
,
unorderedEquals
(<
String
>[
'assets/foo/bar.txt'
,
'AssetManifest.json'
,
'AssetManifest.bin'
,
'FontManifest.json'
,
'NOTICES.Z'
]));
expect
(
bundle
.
deferredComponentsEntries
.
length
,
1
);
expect
(
bundle
.
deferredComponentsEntries
.
length
,
1
);
expect
(
bundle
.
deferredComponentsEntries
[
'component1'
]!.
length
,
3
);
expect
(
bundle
.
deferredComponentsEntries
[
'component1'
]!.
keys
,
unorderedEquals
(<
String
>[
'assets/bar/barbie.txt'
,
'assets/wild/dash.txt'
,
'assets/wild/fizz.txt'
]));
},
overrides:
<
Type
,
Generator
>{
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
...
@@ -335,7 +316,8 @@ assets:
...
@@ -335,7 +316,8 @@ assets:
final
AssetBundle
bundle
=
AssetBundleFactory
.
instance
.
createBundle
();
final
AssetBundle
bundle
=
AssetBundleFactory
.
instance
.
createBundle
();
await
bundle
.
build
(
packagesPath:
'.packages'
);
await
bundle
.
build
(
packagesPath:
'.packages'
);
final
DevFSStringContent
?
assetManifest
=
bundle
.
entries
[
'AssetManifest.json'
]
final
DevFSContent
?
assetManifestBin
=
bundle
.
entries
[
'AssetManifest.bin'
];
final
DevFSStringContent
?
assetManifestJson
=
bundle
.
entries
[
'AssetManifest.json'
]
as
DevFSStringContent
?;
as
DevFSStringContent
?;
final
DevFSStringContent
?
fontManifest
=
bundle
.
entries
[
'FontManifest.json'
]
final
DevFSStringContent
?
fontManifest
=
bundle
.
entries
[
'FontManifest.json'
]
as
DevFSStringContent
?;
as
DevFSStringContent
?;
...
@@ -344,7 +326,8 @@ assets:
...
@@ -344,7 +326,8 @@ assets:
await
bundle
.
build
(
packagesPath:
'.packages'
);
await
bundle
.
build
(
packagesPath:
'.packages'
);
expect
(
assetManifest
,
bundle
.
entries
[
'AssetManifest.json'
]);
expect
(
assetManifestBin
,
bundle
.
entries
[
'AssetManifest.bin'
]);
expect
(
assetManifestJson
,
bundle
.
entries
[
'AssetManifest.json'
]);
expect
(
fontManifest
,
bundle
.
entries
[
'FontManifest.json'
]);
expect
(
fontManifest
,
bundle
.
entries
[
'FontManifest.json'
]);
expect
(
license
,
bundle
.
entries
[
'NOTICES'
]);
expect
(
license
,
bundle
.
entries
[
'NOTICES'
]);
},
overrides:
<
Type
,
Generator
>{
},
overrides:
<
Type
,
Generator
>{
...
@@ -639,7 +622,8 @@ flutter:
...
@@ -639,7 +622,8 @@ flutter:
await
bundle
.
build
(
packagesPath:
'.packages'
);
await
bundle
.
build
(
packagesPath:
'.packages'
);
expect
(
bundle
.
entries
,
hasLength
(
4
));
expect
(
bundle
.
entries
.
keys
,
unorderedEquals
(<
String
>[
'packages/foo/bar/fizz.txt'
,
'AssetManifest.json'
,
'AssetManifest.bin'
,
'FontManifest.json'
,
'NOTICES.Z'
]));
expect
(
bundle
.
needsBuild
(),
false
);
expect
(
bundle
.
needsBuild
(),
false
);
// Does not track dependency's wildcard directories.
// Does not track dependency's wildcard directories.
...
@@ -739,6 +723,7 @@ flutter:
...
@@ -739,6 +723,7 @@ flutter:
expect
(
await
bundle
.
build
(
packagesPath:
'.packages'
),
0
);
expect
(
await
bundle
.
build
(
packagesPath:
'.packages'
),
0
);
expect
((
bundle
.
entries
[
'FontManifest.json'
]!
as
DevFSStringContent
).
string
,
'[]'
);
expect
((
bundle
.
entries
[
'FontManifest.json'
]!
as
DevFSStringContent
).
string
,
'[]'
);
expect
((
bundle
.
entries
[
'AssetManifest.json'
]!
as
DevFSStringContent
).
string
,
'{}'
);
expect
((
bundle
.
entries
[
'AssetManifest.json'
]!
as
DevFSStringContent
).
string
,
'{}'
);
expect
(
await
_extractBinAssetManifestFromBundleAsJson
(
bundle
),
'{}'
);
expect
(
testLogger
.
errorText
,
contains
(
expect
(
testLogger
.
errorText
,
contains
(
'package:foo has `uses-material-design: true` set'
'package:foo has `uses-material-design: true` set'
));
));
...
@@ -774,7 +759,8 @@ flutter:
...
@@ -774,7 +759,8 @@ flutter:
final
AssetBundle
bundle
=
AssetBundleFactory
.
instance
.
createBundle
();
final
AssetBundle
bundle
=
AssetBundleFactory
.
instance
.
createBundle
();
expect
(
await
bundle
.
build
(
packagesPath:
'.packages'
),
0
);
expect
(
await
bundle
.
build
(
packagesPath:
'.packages'
),
0
);
expect
(
bundle
.
entries
.
length
,
4
);
expect
(
bundle
.
entries
.
keys
,
unorderedEquals
(<
String
>[
'assets/foo.txt'
,
'AssetManifest.json'
,
'AssetManifest.bin'
,
'FontManifest.json'
,
'NOTICES.Z'
]));
},
overrides:
<
Type
,
Generator
>{
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
MemoryFileSystem
.
test
(),
FileSystem:
()
=>
MemoryFileSystem
.
test
(),
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
...
@@ -812,9 +798,17 @@ flutter:
...
@@ -812,9 +798,17 @@ flutter:
// The assets from deferred components and regular assets
// The assets from deferred components and regular assets
// are both included in alphabetical order
// are both included in alphabetical order
expect
((
bundle
.
entries
[
'AssetManifest.json'
]!
as
DevFSStringContent
).
string
,
'{"assets/apple.jpg":["assets/apple.jpg"],"assets/bar.jpg":["assets/bar.jpg"],"assets/foo.jpg":["assets/foo.jpg"],"assets/zebra.jpg":["assets/zebra.jpg"]}'
);
expect
((
bundle
.
entries
[
'AssetManifest.json'
]!
as
DevFSStringContent
).
string
,
'{"assets/apple.jpg":["assets/apple.jpg"],"assets/bar.jpg":["assets/bar.jpg"],"assets/foo.jpg":["assets/foo.jpg"],"assets/zebra.jpg":["assets/zebra.jpg"]}'
);
expect
(
await
_extractBinAssetManifestFromBundleAsJson
(
bundle
),
'{"assets/apple.jpg":[],"assets/bar.jpg":[],"assets/foo.jpg":[],"assets/zebra.jpg":[]}'
);
},
overrides:
<
Type
,
Generator
>{
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
MemoryFileSystem
.
test
(),
FileSystem:
()
=>
MemoryFileSystem
.
test
(),
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
Platform:
()
=>
FakePlatform
(),
Platform:
()
=>
FakePlatform
(),
});
});
}
}
Future
<
String
>
_extractBinAssetManifestFromBundleAsJson
(
AssetBundle
bundle
)
async
{
final
List
<
int
>
manifestBytes
=
await
bundle
.
entries
[
'AssetManifest.bin'
]!.
contentsAsBytes
();
return
json
.
encode
(
const
StandardMessageCodec
().
decodeMessage
(
ByteData
.
sublistView
(
Uint8List
.
fromList
(
manifestBytes
))
));
}
packages/flutter_tools/test/general.shard/asset_bundle_variant_test.dart
View file @
56cad89b
...
@@ -3,6 +3,7 @@
...
@@ -3,6 +3,7 @@
// found in the LICENSE file.
// found in the LICENSE file.
import
'dart:convert'
;
import
'dart:convert'
;
import
'dart:typed_data'
;
import
'package:file/file.dart'
;
import
'package:file/file.dart'
;
import
'package:file/memory.dart'
;
import
'package:file/memory.dart'
;
...
@@ -15,209 +16,418 @@ import 'package:flutter_tools/src/base/user_messages.dart';
...
@@ -15,209 +16,418 @@ import 'package:flutter_tools/src/base/user_messages.dart';
import
'package:flutter_tools/src/cache.dart'
;
import
'package:flutter_tools/src/cache.dart'
;
import
'package:flutter_tools/src/project.dart'
;
import
'package:flutter_tools/src/project.dart'
;
import
'package:standard_message_codec/standard_message_codec.dart'
;
import
'../src/common.dart'
;
import
'../src/common.dart'
;
void
main
(
)
{
void
main
(
)
{
Future
<
Map
<
String
,
List
<
String
>>>
extractAssetManifestFromBundle
(
ManifestAssetBundle
bundle
)
async
{
// TODO(andrewkolos): Delete this group once we stop producing AssetManifest.json
final
String
manifestJson
=
utf8
.
decode
(
await
bundle
.
entries
[
'AssetManifest.json'
]!.
contentsAsBytes
());
// as part of build.
final
Map
<
String
,
dynamic
>
parsedJson
=
json
.
decode
(
manifestJson
)
as
Map
<
String
,
dynamic
>;
group
(
'Legacy asset manifest (AssetManifest.json)'
,
()
{
final
Iterable
<
String
>
keys
=
parsedJson
.
keys
;
Future
<
Map
<
String
,
List
<
String
>>>
extractAssetManifestFromBundle
(
ManifestAssetBundle
bundle
)
async
{
final
Map
<
String
,
List
<
String
>>
parsedManifest
=
<
String
,
List
<
String
>>
{
final
String
manifestJson
=
utf8
.
decode
(
await
bundle
.
entries
[
'AssetManifest.json'
]!.
contentsAsBytes
());
for
(
final
String
key
in
keys
)
key:
List
<
String
>.
from
(
parsedJson
[
key
]
as
List
<
dynamic
>),
final
Map
<
String
,
dynamic
>
parsedJson
=
json
.
decode
(
manifestJson
)
as
Map
<
String
,
dynamic
>;
};
final
Iterable
<
String
>
keys
=
parsedJson
.
keys
;
return
parsedManifest
;
final
Map
<
String
,
List
<
String
>>
parsedManifest
=
<
String
,
List
<
String
>>
{
}
for
(
final
String
key
in
keys
)
key:
List
<
String
>.
from
(
parsedJson
[
key
]
as
List
<
dynamic
>),
};
group
(
'AssetBundle asset variants (with Unix-style paths)'
,
()
{
return
parsedManifest
;
late
Platform
platform
;
}
late
FileSystem
fs
;
group
(
'AssetBundle asset variants (with Unix-style paths)'
,
()
{
setUp
(()
{
late
Platform
platform
;
platform
=
FakePlatform
();
late
FileSystem
fs
;
fs
=
MemoryFileSystem
.
test
();
Cache
.
flutterRoot
=
Cache
.
defaultFlutterRoot
(
setUp
(()
{
platform:
platform
,
platform
=
FakePlatform
();
fileSystem:
fs
,
fs
=
MemoryFileSystem
.
test
();
userMessages:
UserMessages
()
Cache
.
flutterRoot
=
Cache
.
defaultFlutterRoot
(
);
platform:
platform
,
fileSystem:
fs
,
fs
.
file
(
'.packages'
).
createSync
();
userMessages:
UserMessages
()
);
fs
.
file
(
'pubspec.yaml'
).
writeAsStringSync
(
'''
fs
.
file
(
'.packages'
).
createSync
();
name: test
dependencies:
fs
.
file
(
'pubspec.yaml'
).
writeAsStringSync
(
'''
name: test
dependencies:
flutter:
sdk: flutter
flutter:
flutter:
sdk: flutter
assets:
flutter:
- assets/
assets:
'''
- assets/
);
'''
});
);
testWithoutContext
(
'Only images in folders named with device pixel ratios (e.g. 2x, 3.0x) should be considered as variants of other images'
,
()
async
{
const
String
image
=
'assets/image.jpg'
;
const
String
image2xVariant
=
'assets/2x/image.jpg'
;
const
String
imageNonVariant
=
'assets/notAVariant/image.jpg'
;
final
List
<
String
>
assets
=
<
String
>[
image
,
image2xVariant
,
imageNonVariant
];
for
(
final
String
asset
in
assets
)
{
final
File
assetFile
=
fs
.
file
(
asset
);
assetFile
.
createSync
(
recursive:
true
);
assetFile
.
writeAsStringSync
(
asset
);
}
final
ManifestAssetBundle
bundle
=
ManifestAssetBundle
(
logger:
BufferLogger
.
test
(),
fileSystem:
fs
,
platform:
platform
,
);
await
bundle
.
build
(
packagesPath:
'.packages'
,
flutterProject:
FlutterProject
.
fromDirectoryTest
(
fs
.
currentDirectory
),
);
final
Map
<
String
,
List
<
String
>>
manifest
=
await
extractAssetManifestFromBundle
(
bundle
);
expect
(
manifest
,
hasLength
(
2
));
expect
(
manifest
[
image
],
equals
(<
String
>[
image
,
image2xVariant
]));
expect
(
manifest
[
imageNonVariant
],
equals
(<
String
>[
imageNonVariant
]));
});
testWithoutContext
(
'Asset directories are recursively searched for assets'
,
()
async
{
const
String
topLevelImage
=
'assets/image.jpg'
;
const
String
secondLevelImage
=
'assets/folder/secondLevel.jpg'
;
const
String
secondLevel2xVariant
=
'assets/folder/2x/secondLevel.jpg'
;
final
List
<
String
>
assets
=
<
String
>[
topLevelImage
,
secondLevelImage
,
secondLevel2xVariant
];
for
(
final
String
asset
in
assets
)
{
final
File
assetFile
=
fs
.
file
(
asset
);
assetFile
.
createSync
(
recursive:
true
);
assetFile
.
writeAsStringSync
(
asset
);
}
final
ManifestAssetBundle
bundle
=
ManifestAssetBundle
(
logger:
BufferLogger
.
test
(),
fileSystem:
fs
,
platform:
platform
,
);
await
bundle
.
build
(
packagesPath:
'.packages'
,
flutterProject:
FlutterProject
.
fromDirectoryTest
(
fs
.
currentDirectory
),
);
final
Map
<
String
,
List
<
String
>>
manifest
=
await
extractAssetManifestFromBundle
(
bundle
);
expect
(
manifest
,
hasLength
(
2
));
expect
(
manifest
[
topLevelImage
],
equals
(<
String
>[
topLevelImage
]));
expect
(
manifest
[
secondLevelImage
],
equals
(<
String
>[
secondLevelImage
,
secondLevel2xVariant
]));
});
testWithoutContext
(
'Asset paths should never be URI-encoded'
,
()
async
{
const
String
image
=
'assets/normalFolder/i have URI-reserved_characters.jpg'
;
const
String
imageVariant
=
'assets/normalFolder/3x/i have URI-reserved_characters.jpg'
;
final
List
<
String
>
assets
=
<
String
>[
image
,
imageVariant
];
for
(
final
String
asset
in
assets
)
{
final
File
assetFile
=
fs
.
file
(
asset
);
assetFile
.
createSync
(
recursive:
true
);
assetFile
.
writeAsStringSync
(
asset
);
}
final
ManifestAssetBundle
bundle
=
ManifestAssetBundle
(
logger:
BufferLogger
.
test
(),
fileSystem:
fs
,
platform:
platform
,
);
await
bundle
.
build
(
packagesPath:
'.packages'
,
flutterProject:
FlutterProject
.
fromDirectoryTest
(
fs
.
currentDirectory
),
);
final
Map
<
String
,
List
<
String
>>
manifest
=
await
extractAssetManifestFromBundle
(
bundle
);
expect
(
manifest
,
hasLength
(
1
));
expect
(
manifest
[
image
],
equals
(<
String
>[
image
,
imageVariant
]));
});
});
});
testWithoutContext
(
'Only images in folders named with device pixel ratios (e.g. 2x, 3.0x) should be considered as variants of other images'
,
()
async
{
const
String
image
=
'assets/image.jpg'
;
const
String
image2xVariant
=
'assets/2x/image.jpg'
;
const
String
imageNonVariant
=
'assets/notAVariant/image.jpg'
;
final
List
<
String
>
assets
=
<
String
>[
image
,
image2xVariant
,
imageNonVariant
];
for
(
final
String
asset
in
assets
)
{
final
File
assetFile
=
fs
.
file
(
asset
);
assetFile
.
createSync
(
recursive:
true
);
assetFile
.
writeAsStringSync
(
asset
);
}
final
ManifestAssetBundle
bundle
=
ManifestAssetBundle
(
logger:
BufferLogger
.
test
(),
fileSystem:
fs
,
platform:
platform
,
);
await
bundle
.
build
(
packagesPath:
'.packages'
,
flutterProject:
FlutterProject
.
fromDirectoryTest
(
fs
.
currentDirectory
),
);
final
Map
<
String
,
List
<
String
>>
manifest
=
await
extractAssetManifestFromBundle
(
bundle
);
expect
(
manifest
,
hasLength
(
2
));
expect
(
manifest
[
image
],
equals
(<
String
>[
image
,
image2xVariant
]));
expect
(
manifest
[
imageNonVariant
],
equals
(<
String
>[
imageNonVariant
]));
});
testWithoutContext
(
'Asset directories are recursively searched for assets'
,
()
async
{
group
(
'AssetBundle asset variants (with Windows-style filepaths)'
,
()
{
const
String
topLevelImage
=
'assets/image.jpg'
;
late
final
Platform
platform
;
const
String
secondLevelImage
=
'assets/folder/secondLevel.jpg'
;
late
final
FileSystem
fs
;
const
String
secondLevel2xVariant
=
'assets/folder/2x/secondLevel.jpg'
;
setUp
(()
{
final
List
<
String
>
assets
=
<
String
>[
platform
=
FakePlatform
(
operatingSystem:
'windows'
);
topLevelImage
,
fs
=
MemoryFileSystem
.
test
(
style:
FileSystemStyle
.
windows
);
secondLevelImage
,
Cache
.
flutterRoot
=
Cache
.
defaultFlutterRoot
(
secondLevel2xVariant
platform:
platform
,
];
fileSystem:
fs
,
userMessages:
UserMessages
()
for
(
final
String
asset
in
assets
)
{
);
final
File
assetFile
=
fs
.
file
(
asset
);
assetFile
.
createSync
(
recursive:
true
);
assetFile
.
writeAsStringSync
(
asset
);
}
final
ManifestAssetBundle
bundle
=
ManifestAssetBundle
(
logger:
BufferLogger
.
test
(),
fileSystem:
fs
,
platform:
platform
,
);
await
bundle
.
build
(
packagesPath:
'.packages'
,
flutterProject:
FlutterProject
.
fromDirectoryTest
(
fs
.
currentDirectory
),
);
final
Map
<
String
,
List
<
String
>>
manifest
=
await
extractAssetManifestFromBundle
(
bundle
);
expect
(
manifest
,
hasLength
(
2
));
expect
(
manifest
[
topLevelImage
],
equals
(<
String
>[
topLevelImage
]));
expect
(
manifest
[
secondLevelImage
],
equals
(<
String
>[
secondLevelImage
,
secondLevel2xVariant
]));
});
testWithoutContext
(
'Asset paths should never be URI-encoded'
,
()
async
{
fs
.
file
(
'.packages'
).
createSync
();
const
String
image
=
'assets/normalFolder/i have URI-reserved_characters.jpg'
;
const
String
imageVariant
=
'assets/normalFolder/3x/i have URI-reserved_characters.jpg'
;
fs
.
file
(
'pubspec.yaml'
).
writeAsStringSync
(
'''
final
List
<
String
>
assets
=
<
String
>[
name: test
image
,
dependencies:
imageVariant
flutter:
];
sdk: flutter
flutter:
for
(
final
String
asset
in
assets
)
{
assets:
final
File
assetFile
=
fs
.
file
(
asset
);
- assets/
assetFile
.
createSync
(
recursive:
true
);
'''
assetFile
.
writeAsStringSync
(
asset
);
);
}
});
final
ManifestAssetBundle
bundle
=
ManifestAssetBundle
(
testWithoutContext
(
'Variant detection works with windows-style filepaths'
,
()
async
{
logger:
BufferLogger
.
test
(),
const
List
<
String
>
assets
=
<
String
>[
fileSystem:
fs
,
r'assets\foo.jpg'
,
platform:
platform
,
r'assets\2x\foo.jpg'
,
);
r'assets\somewhereElse\bar.jpg'
,
r'assets\somewhereElse\2x\bar.jpg'
,
await
bundle
.
build
(
];
packagesPath:
'.packages'
,
flutterProject:
FlutterProject
.
fromDirectoryTest
(
fs
.
currentDirectory
),
for
(
final
String
asset
in
assets
)
{
);
final
File
assetFile
=
fs
.
file
(
asset
);
assetFile
.
createSync
(
recursive:
true
);
final
Map
<
String
,
List
<
String
>>
manifest
=
await
extractAssetManifestFromBundle
(
bundle
);
assetFile
.
writeAsStringSync
(
asset
);
expect
(
manifest
,
hasLength
(
1
));
}
expect
(
manifest
[
image
],
equals
(<
String
>[
image
,
imageVariant
]));
final
ManifestAssetBundle
bundle
=
ManifestAssetBundle
(
logger:
BufferLogger
.
test
(),
fileSystem:
fs
,
platform:
platform
,
);
await
bundle
.
build
(
packagesPath:
'.packages'
,
flutterProject:
FlutterProject
.
fromDirectoryTest
(
fs
.
currentDirectory
),
);
final
Map
<
String
,
List
<
String
>>
manifest
=
await
extractAssetManifestFromBundle
(
bundle
);
expect
(
manifest
,
hasLength
(
2
));
expect
(
manifest
[
'assets/foo.jpg'
],
equals
(<
String
>[
'assets/foo.jpg'
,
'assets/2x/foo.jpg'
]));
expect
(
manifest
[
'assets/somewhereElse/bar.jpg'
],
equals
(<
String
>[
'assets/somewhereElse/bar.jpg'
,
'assets/somewhereElse/2x/bar.jpg'
]));
});
});
});
});
});
group
(
'Current asset manifest (AssetManifest.bin)'
,
()
{
Future
<
String
>
extractAssetManifestFromBundleAsJson
(
ManifestAssetBundle
bundle
)
async
{
final
List
<
int
>
manifestBytes
=
await
bundle
.
entries
[
'AssetManifest.bin'
]!.
contentsAsBytes
();
return
json
.
encode
(
const
StandardMessageCodec
().
decodeMessage
(
ByteData
.
sublistView
(
Uint8List
.
fromList
(
manifestBytes
))
));
}
group
(
'AssetBundle asset variants (with Unix-style paths)'
,
()
{
late
Platform
platform
;
late
FileSystem
fs
;
setUp
(()
{
platform
=
FakePlatform
();
fs
=
MemoryFileSystem
.
test
();
Cache
.
flutterRoot
=
Cache
.
defaultFlutterRoot
(
platform:
platform
,
fileSystem:
fs
,
userMessages:
UserMessages
()
);
fs
.
file
(
'.packages'
).
createSync
();
fs
.
file
(
'pubspec.yaml'
).
writeAsStringSync
(
'''
name: test
dependencies:
flutter:
sdk: flutter
flutter:
assets:
- assets/
'''
);
});
testWithoutContext
(
'Only images in folders named with device pixel ratios (e.g. 2x, 3.0x) should be considered as variants of other images'
,
()
async
{
const
String
image
=
'assets/image.jpg'
;
const
String
image2xVariant
=
'assets/2x/image.jpg'
;
const
String
imageNonVariant
=
'assets/notAVariant/image.jpg'
;
final
List
<
String
>
assets
=
<
String
>[
image
,
image2xVariant
,
imageNonVariant
];
for
(
final
String
asset
in
assets
)
{
final
File
assetFile
=
fs
.
file
(
asset
);
assetFile
.
createSync
(
recursive:
true
);
assetFile
.
writeAsStringSync
(
asset
);
}
final
ManifestAssetBundle
bundle
=
ManifestAssetBundle
(
logger:
BufferLogger
.
test
(),
fileSystem:
fs
,
platform:
platform
,
);
await
bundle
.
build
(
packagesPath:
'.packages'
,
flutterProject:
FlutterProject
.
fromDirectoryTest
(
fs
.
currentDirectory
),
);
const
String
expectedManifest
=
'{"
$image
":[{"asset":"
$image2xVariant
","dpr":2.0}],'
'"
$imageNonVariant
":[]}'
;
final
String
manifest
=
await
extractAssetManifestFromBundleAsJson
(
bundle
);
expect
(
manifest
,
equals
(
expectedManifest
));
});
testWithoutContext
(
'Asset directories are recursively searched for assets'
,
()
async
{
const
String
topLevelImage
=
'assets/image.jpg'
;
const
String
secondLevelImage
=
'assets/folder/secondLevel.jpg'
;
const
String
secondLevel2xVariant
=
'assets/folder/2x/secondLevel.jpg'
;
final
List
<
String
>
assets
=
<
String
>[
topLevelImage
,
secondLevelImage
,
secondLevel2xVariant
];
for
(
final
String
asset
in
assets
)
{
final
File
assetFile
=
fs
.
file
(
asset
);
assetFile
.
createSync
(
recursive:
true
);
assetFile
.
writeAsStringSync
(
asset
);
}
final
ManifestAssetBundle
bundle
=
ManifestAssetBundle
(
logger:
BufferLogger
.
test
(),
fileSystem:
fs
,
platform:
platform
,
);
await
bundle
.
build
(
packagesPath:
'.packages'
,
flutterProject:
FlutterProject
.
fromDirectoryTest
(
fs
.
currentDirectory
),
);
const
String
expectedManifest
=
'{'
'"
$secondLevelImage
":[{"asset":"
$secondLevel2xVariant
","dpr":2.0}],'
'"
$topLevelImage
":[]'
'}'
;
final
String
manifest
=
await
extractAssetManifestFromBundleAsJson
(
bundle
);
expect
(
manifest
,
equals
(
expectedManifest
));
});
testWithoutContext
(
'Asset paths should never be URI-encoded'
,
()
async
{
const
String
image
=
'assets/normalFolder/i have URI-reserved_characters.jpg'
;
const
String
imageVariant
=
'assets/normalFolder/3x/i have URI-reserved_characters.jpg'
;
final
List
<
String
>
assets
=
<
String
>[
image
,
imageVariant
];
for
(
final
String
asset
in
assets
)
{
final
File
assetFile
=
fs
.
file
(
asset
);
assetFile
.
createSync
(
recursive:
true
);
assetFile
.
writeAsStringSync
(
asset
);
}
final
ManifestAssetBundle
bundle
=
ManifestAssetBundle
(
logger:
BufferLogger
.
test
(),
fileSystem:
fs
,
platform:
platform
,
);
await
bundle
.
build
(
packagesPath:
'.packages'
,
flutterProject:
FlutterProject
.
fromDirectoryTest
(
fs
.
currentDirectory
),
);
const
String
expectedManifest
=
'{"
$image
":[{"asset":"
$imageVariant
","dpr":3.0}]}'
;
final
String
manifest
=
await
extractAssetManifestFromBundleAsJson
(
bundle
);
expect
(
manifest
,
equals
(
expectedManifest
));
});
});
group
(
'AssetBundle asset variants (with Windows-style filepaths)'
,
()
{
late
final
Platform
platform
;
late
final
FileSystem
fs
;
setUp
(()
{
group
(
'AssetBundle asset variants (with Windows-style filepaths)'
,
()
{
platform
=
FakePlatform
(
operatingSystem:
'windows'
);
late
final
Platform
platform
;
fs
=
MemoryFileSystem
.
test
(
style:
FileSystemStyle
.
windows
);
late
final
FileSystem
fs
;
Cache
.
flutterRoot
=
Cache
.
defaultFlutterRoot
(
platform:
platform
,
fileSystem:
fs
,
userMessages:
UserMessages
()
);
fs
.
file
(
'.packages'
).
createSync
();
setUp
(()
{
platform
=
FakePlatform
(
operatingSystem:
'windows'
);
fs
=
MemoryFileSystem
.
test
(
style:
FileSystemStyle
.
windows
);
Cache
.
flutterRoot
=
Cache
.
defaultFlutterRoot
(
platform:
platform
,
fileSystem:
fs
,
userMessages:
UserMessages
()
);
fs
.
file
(
'pubspec.yaml'
).
writeAsStringSync
(
fs
.
file
(
'.packages'
).
createSync
();
'''
name: test
dependencies:
flutter:
sdk: flutter
flutter:
assets:
- assets/
'''
);
});
testWithoutContext
(
'Variant detection works with windows-style filepaths'
,
()
async
{
fs
.
file
(
'pubspec.yaml'
).
writeAsStringSync
(
const
List
<
String
>
assets
=
<
String
>[
'''
r'assets\foo.jpg'
,
name: test
r'assets\2x\foo.jpg'
,
dependencies:
r'assets\somewhereElse\bar.jpg'
,
flutter:
r'assets\somewhereElse\2x\bar.jpg'
,
sdk: flutter
];
flutter:
assets:
for
(
final
String
asset
in
assets
)
{
- assets/
final
File
assetFile
=
fs
.
file
(
asset
);
'''
assetFile
.
createSync
(
recursive:
true
);
);
assetFile
.
writeAsStringSync
(
asset
);
});
}
testWithoutContext
(
'Variant detection works with windows-style filepaths'
,
()
async
{
final
ManifestAssetBundle
bundle
=
ManifestAssetBundle
(
const
List
<
String
>
assets
=
<
String
>[
logger:
BufferLogger
.
test
(),
r'assets\foo.jpg'
,
fileSystem:
fs
,
r'assets\2x\foo.jpg'
,
platform:
platform
,
r'assets\somewhereElse\bar.jpg'
,
);
r'assets\somewhereElse\2x\bar.jpg'
,
];
await
bundle
.
build
(
packagesPath:
'.packages'
,
for
(
final
String
asset
in
assets
)
{
flutterProject:
FlutterProject
.
fromDirectoryTest
(
fs
.
currentDirectory
),
final
File
assetFile
=
fs
.
file
(
asset
);
);
assetFile
.
createSync
(
recursive:
true
);
assetFile
.
writeAsStringSync
(
asset
);
final
Map
<
String
,
List
<
String
>>
manifest
=
await
extractAssetManifestFromBundle
(
bundle
);
}
expect
(
manifest
,
hasLength
(
2
));
final
ManifestAssetBundle
bundle
=
ManifestAssetBundle
(
expect
(
manifest
[
'assets/foo.jpg'
],
equals
(<
String
>[
'assets/foo.jpg'
,
'assets/2x/foo.jpg'
]));
logger:
BufferLogger
.
test
(),
expect
(
manifest
[
'assets/somewhereElse/bar.jpg'
],
equals
(<
String
>[
'assets/somewhereElse/bar.jpg'
,
'assets/somewhereElse/2x/bar.jpg'
]));
fileSystem:
fs
,
platform:
platform
,
);
await
bundle
.
build
(
packagesPath:
'.packages'
,
flutterProject:
FlutterProject
.
fromDirectoryTest
(
fs
.
currentDirectory
),
);
const
String
expectedManifest
=
'{"assets/foo.jpg":[{"asset":"assets/2x/foo.jpg","dpr":2.0}],'
'"assets/somewhereElse/bar.jpg":[{"asset":"assets/somewhereElse/2x/bar.jpg","dpr":2.0}]}'
;
final
String
manifest
=
await
extractAssetManifestFromBundleAsJson
(
bundle
);
expect
(
manifest
,
equals
(
expectedManifest
));
});
});
});
});
});
}
}
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