flutter_manifest_test.dart 21.9 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5 6
import 'dart:async';

7 8
import 'package:file/file.dart';
import 'package:file/memory.dart';
9
import 'package:flutter_tools/src/base/context.dart';
10
import 'package:flutter_tools/src/base/file_system.dart';
11 12 13
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/flutter_manifest.dart';

14 15 16
import '../src/common.dart';
import '../src/context.dart';
import '../src/pubspec_schema.dart';
17 18 19 20 21 22 23

void main() {
  setUpAll(() {
    Cache.flutterRoot = getFlutterRoot();
  });

  group('FlutterManifest', () {
24
    testUsingContext('is empty when the pubspec.yaml file is empty', () async {
25
      final FlutterManifest flutterManifest = FlutterManifest.createFromString('');
26 27 28 29 30 31 32 33
      expect(flutterManifest.isEmpty, true);
      expect(flutterManifest.appName, '');
      expect(flutterManifest.usesMaterialDesign, false);
      expect(flutterManifest.fontsDescriptor, isEmpty);
      expect(flutterManifest.fonts, isEmpty);
      expect(flutterManifest.assets, isEmpty);
    });

34
    test('has no fonts or assets when the "flutter" section is empty', () async {
35
      const String manifest = '''
36 37 38 39 40
name: test
dependencies:
  flutter:
    sdk: flutter
''';
41
      final FlutterManifest flutterManifest = FlutterManifest.createFromString(manifest);
42
      expect(flutterManifest, isNotNull);
43
      expect(flutterManifest.isEmpty, false);
44 45 46 47 48 49 50 51
      expect(flutterManifest.appName, 'test');
      expect(flutterManifest.usesMaterialDesign, false);
      expect(flutterManifest.fontsDescriptor, isEmpty);
      expect(flutterManifest.fonts, isEmpty);
      expect(flutterManifest.assets, isEmpty);
    });

    test('knows if material design is used', () async {
52
      const String manifest = '''
53 54 55 56 57 58 59
name: test
dependencies:
  flutter:
    sdk: flutter
flutter:
  uses-material-design: true
''';
60
      final FlutterManifest flutterManifest = FlutterManifest.createFromString(manifest);
61 62 63 64
      expect(flutterManifest.usesMaterialDesign, true);
    });

    test('has two assets', () async {
65
      const String manifest = '''
66 67 68 69 70 71 72 73 74 75
name: test
dependencies:
  flutter:
    sdk: flutter
flutter:
  uses-material-design: true
  assets:
    - a/foo
    - a/bar
''';
76
      final FlutterManifest flutterManifest = FlutterManifest.createFromString(manifest);
77 78 79
      expect(flutterManifest.assets.length, 2);
      expect(flutterManifest.assets[0], Uri.parse('a/foo'));
      expect(flutterManifest.assets[1], Uri.parse('a/bar'));
80 81 82
    });

    test('has one font family with one asset', () async {
83
      const String manifest = '''
84 85 86 87 88 89 90 91 92 93 94
name: test
dependencies:
  flutter:
    sdk: flutter
flutter:
  uses-material-design: true
  fonts:
    - family: foo
      fonts:
        - asset: a/bar
''';
95
      final FlutterManifest flutterManifest = FlutterManifest.createFromString(manifest);
96 97
      final dynamic expectedFontsDescriptor = [{'fonts': [{'asset': 'a/bar'}], 'family': 'foo'}]; // ignore: always_specify_types
      expect(flutterManifest.fontsDescriptor, expectedFontsDescriptor);
98 99 100
      final List<Font> fonts = flutterManifest.fonts;
      expect(fonts.length, 1);
      final Font font = fonts[0];
101 102
      final dynamic fooFontDescriptor = {'family': 'foo', 'fonts': [{'asset': 'a/bar'}]}; // ignore: always_specify_types
      expect(font.descriptor, fooFontDescriptor);
103 104 105 106
      expect(font.familyName, 'foo');
      final List<FontAsset> assets = font.fontAssets;
      expect(assets.length, 1);
      final FontAsset fontAsset = assets[0];
107
      expect(fontAsset.assetUri.path, 'a/bar');
108 109 110 111 112
      expect(fontAsset.weight, isNull);
      expect(fontAsset.style, isNull);
    });

    test('has one font family with a simple asset and one with weight', () async {
113
      const String manifest = '''
114 115 116 117 118 119 120 121 122 123 124 125 126
name: test
dependencies:
  flutter:
    sdk: flutter
flutter:
  uses-material-design: true
  fonts:
    - family: foo
      fonts:
        - asset: a/bar
        - asset: a/bar
          weight: 400
''';
127
      final FlutterManifest flutterManifest = FlutterManifest.createFromString(manifest);
128 129
      final dynamic expectedFontsDescriptor = [{'fonts': [{'asset': 'a/bar'}, {'weight': 400, 'asset': 'a/bar'}], 'family': 'foo'}]; // ignore: always_specify_types
      expect(flutterManifest.fontsDescriptor, expectedFontsDescriptor);
130 131 132
      final List<Font> fonts = flutterManifest.fonts;
      expect(fonts.length, 1);
      final Font font = fonts[0];
133 134
      final dynamic fooFontDescriptor = {'family': 'foo', 'fonts': [{'asset': 'a/bar'}, {'weight': 400, 'asset': 'a/bar'}]}; // ignore: always_specify_types
      expect(font.descriptor, fooFontDescriptor);
135 136 137 138
      expect(font.familyName, 'foo');
      final List<FontAsset> assets = font.fontAssets;
      expect(assets.length, 2);
      final FontAsset fontAsset0 = assets[0];
139
      expect(fontAsset0.assetUri.path, 'a/bar');
140 141 142
      expect(fontAsset0.weight, isNull);
      expect(fontAsset0.style, isNull);
      final FontAsset fontAsset1 = assets[1];
143
      expect(fontAsset1.assetUri.path, 'a/bar');
144 145 146 147 148
      expect(fontAsset1.weight, 400);
      expect(fontAsset1.style, isNull);
    });

    test('has one font family with a simple asset and one with weight and style', () async {
149
      const String manifest = '''
150 151 152 153 154 155 156 157 158 159 160 161 162 163
name: test
dependencies:
  flutter:
    sdk: flutter
flutter:
  uses-material-design: true
  fonts:
    - family: foo
      fonts:
        - asset: a/bar
        - asset: a/bar
          weight: 400
          style: italic
''';
164
      final FlutterManifest flutterManifest = FlutterManifest.createFromString(manifest);
165
      final dynamic expectedFontsDescriptor = [{'fonts': [{'asset': 'a/bar'}, {'style': 'italic', 'weight': 400, 'asset': 'a/bar'}], 'family': 'foo'}]; // ignore: always_specify_types
166

167
      expect(flutterManifest.fontsDescriptor, expectedFontsDescriptor);
168 169 170
      final List<Font> fonts = flutterManifest.fonts;
      expect(fonts.length, 1);
      final Font font = fonts[0];
171 172
      final dynamic fooFontDescriptor = {'family': 'foo', 'fonts': [{'asset': 'a/bar'}, {'weight': 400, 'style': 'italic', 'asset': 'a/bar'}]}; // ignore: always_specify_types
      expect(font.descriptor, fooFontDescriptor);
173 174 175 176
      expect(font.familyName, 'foo');
      final List<FontAsset> assets = font.fontAssets;
      expect(assets.length, 2);
      final FontAsset fontAsset0 = assets[0];
177
      expect(fontAsset0.assetUri.path, 'a/bar');
178 179 180
      expect(fontAsset0.weight, isNull);
      expect(fontAsset0.style, isNull);
      final FontAsset fontAsset1 = assets[1];
181
      expect(fontAsset1.assetUri.path, 'a/bar');
182 183 184 185 186
      expect(fontAsset1.weight, 400);
      expect(fontAsset1.style, 'italic');
    });

    test('has two font families, each with one simple asset and one with weight and style', () async {
187
      const String manifest = '''
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
name: test
dependencies:
  flutter:
    sdk: flutter
flutter:
  uses-material-design: true
  fonts:
    - family: foo
      fonts:
        - asset: a/bar
        - asset: a/bar
          weight: 400
          style: italic
    - family: bar
      fonts:
        - asset: a/baz
        - weight: 400
          asset: a/baz
          style: italic
''';
208
      final FlutterManifest flutterManifest = FlutterManifest.createFromString(manifest);
209
      final dynamic expectedFontsDescriptor = <dynamic>[
210 211
        {'fonts': [{'asset': 'a/bar'}, {'style': 'italic', 'weight': 400, 'asset': 'a/bar'}], 'family': 'foo'}, // ignore: always_specify_types
        {'fonts': [{'asset': 'a/baz'}, {'style': 'italic', 'weight': 400, 'asset': 'a/baz'}], 'family': 'bar'}, // ignore: always_specify_types
212 213
      ];
      expect(flutterManifest.fontsDescriptor, expectedFontsDescriptor);
214 215 216 217
      final List<Font> fonts = flutterManifest.fonts;
      expect(fonts.length, 2);

      final Font fooFont = fonts[0];
218 219
      final dynamic fooFontDescriptor = {'family': 'foo', 'fonts': [{'asset': 'a/bar'}, {'weight': 400, 'style': 'italic', 'asset': 'a/bar'}]}; // ignore: always_specify_types
      expect(fooFont.descriptor, fooFontDescriptor);
220 221 222 223
      expect(fooFont.familyName, 'foo');
      final List<FontAsset> fooAassets = fooFont.fontAssets;
      expect(fooAassets.length, 2);
      final FontAsset fooFontAsset0 = fooAassets[0];
224
      expect(fooFontAsset0.assetUri.path, 'a/bar');
225 226 227
      expect(fooFontAsset0.weight, isNull);
      expect(fooFontAsset0.style, isNull);
      final FontAsset fooFontAsset1 = fooAassets[1];
228
      expect(fooFontAsset1.assetUri.path, 'a/bar');
229 230 231 232
      expect(fooFontAsset1.weight, 400);
      expect(fooFontAsset1.style, 'italic');

      final Font barFont = fonts[1];
233
      const String fontDescriptor = '{family: bar, fonts: [{asset: a/baz}, {weight: 400, style: italic, asset: a/baz}]}'; // ignore: always_specify_types
234 235 236 237 238
      expect(barFont.descriptor.toString(), fontDescriptor);
      expect(barFont.familyName, 'bar');
      final List<FontAsset> barAssets = barFont.fontAssets;
      expect(barAssets.length, 2);
      final FontAsset barFontAsset0 = barAssets[0];
239
      expect(barFontAsset0.assetUri.path, 'a/baz');
240 241 242
      expect(barFontAsset0.weight, isNull);
      expect(barFontAsset0.style, isNull);
      final FontAsset barFontAsset1 = barAssets[1];
243
      expect(barFontAsset1.assetUri.path, 'a/baz');
244 245 246 247
      expect(barFontAsset1.weight, 400);
      expect(barFontAsset1.style, 'italic');
    });

Josh Soref's avatar
Josh Soref committed
248
    testUsingContext('has only one of two font families when one declaration is missing the "family" option', () async {
249
      const String manifest = '''
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
name: test
dependencies:
  flutter:
    sdk: flutter
flutter:
  uses-material-design: true
  fonts:
    - family: foo
      fonts:
        - asset: a/bar
        - asset: a/bar
          weight: 400
          style: italic
    - fonts:
        - asset: a/baz
        - asset: a/baz
          weight: 400
          style: italic
''';
269
      final FlutterManifest flutterManifest = FlutterManifest.createFromString(manifest);
270

271 272
      final dynamic expectedFontsDescriptor = [{'fonts': [{'asset': 'a/bar'}, {'style': 'italic', 'weight': 400, 'asset': 'a/bar'}], 'family': 'foo'}]; // ignore: always_specify_types
      expect(flutterManifest.fontsDescriptor, expectedFontsDescriptor);
273 274 275
      final List<Font> fonts = flutterManifest.fonts;
      expect(fonts.length, 1);
      final Font fooFont = fonts[0];
276 277
      final dynamic fooFontDescriptor = {'family': 'foo', 'fonts': [{'asset': 'a/bar'}, {'weight': 400, 'style': 'italic', 'asset': 'a/bar'}]}; // ignore: always_specify_types
      expect(fooFont.descriptor, fooFontDescriptor);
278 279 280 281
      expect(fooFont.familyName, 'foo');
      final List<FontAsset> fooAassets = fooFont.fontAssets;
      expect(fooAassets.length, 2);
      final FontAsset fooFontAsset0 = fooAassets[0];
282
      expect(fooFontAsset0.assetUri.path, 'a/bar');
283 284 285
      expect(fooFontAsset0.weight, isNull);
      expect(fooFontAsset0.style, isNull);
      final FontAsset fooFontAsset1 = fooAassets[1];
286
      expect(fooFontAsset1.assetUri.path, 'a/bar');
287 288 289 290
      expect(fooFontAsset1.weight, 400);
      expect(fooFontAsset1.style, 'italic');
    });

Josh Soref's avatar
Josh Soref committed
291
    testUsingContext('has only one of two font families when one declaration is missing the "fonts" option', () async {
292
      const String manifest = '''
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307
name: test
dependencies:
  flutter:
    sdk: flutter
flutter:
  uses-material-design: true
  fonts:
    - family: foo
      fonts:
        - asset: a/bar
        - asset: a/bar
          weight: 400
          style: italic
    - family: bar
''';
308
      final FlutterManifest flutterManifest = FlutterManifest.createFromString(manifest);
309 310
      final dynamic expectedFontsDescriptor = [{'fonts': [{'asset': 'a/bar'}, {'style': 'italic', 'weight': 400, 'asset': 'a/bar'}], 'family': 'foo'}]; // ignore: always_specify_types
      expect(flutterManifest.fontsDescriptor, expectedFontsDescriptor);
311 312 313
      final List<Font> fonts = flutterManifest.fonts;
      expect(fonts.length, 1);
      final Font fooFont = fonts[0];
314 315
      final dynamic fooFontDescriptor = {'family': 'foo', 'fonts': [{'asset': 'a/bar'}, {'weight': 400, 'style': 'italic', 'asset': 'a/bar'}]}; // ignore: always_specify_types
      expect(fooFont.descriptor, fooFontDescriptor);
316 317 318 319
      expect(fooFont.familyName, 'foo');
      final List<FontAsset> fooAassets = fooFont.fontAssets;
      expect(fooAassets.length, 2);
      final FontAsset fooFontAsset0 = fooAassets[0];
320
      expect(fooFontAsset0.assetUri.path, 'a/bar');
321 322 323
      expect(fooFontAsset0.weight, isNull);
      expect(fooFontAsset0.style, isNull);
      final FontAsset fooFontAsset1 = fooAassets[1];
324
      expect(fooFontAsset1.assetUri.path, 'a/bar');
325 326 327 328 329
      expect(fooFontAsset1.weight, 400);
      expect(fooFontAsset1.style, 'italic');
    });

    testUsingContext('has no font family when declaration is missing the "asset" option', () async {
330
      const String manifest = '''
331 332 333 334 335 336 337 338 339 340 341
name: test
dependencies:
  flutter:
    sdk: flutter
flutter:
  uses-material-design: true
  fonts:
    - family: foo
      fonts:
        - weight: 400
''';
342
      final FlutterManifest flutterManifest = FlutterManifest.createFromString(manifest);
343

344
      expect(flutterManifest.fontsDescriptor, <dynamic>[]);
345 346 347
      final List<Font> fonts = flutterManifest.fonts;
      expect(fonts.length, 0);
    });
348 349 350 351 352 353 354 355 356

    test('allows a blank flutter section', () async {
      const String manifest = '''
name: test
dependencies:
  flutter:
    sdk: flutter
flutter:
''';
357
      final FlutterManifest flutterManifest = FlutterManifest.createFromString(manifest);
358
      expect(flutterManifest.isEmpty, false);
359
      expect(flutterManifest.isModule, false);
360 361
      expect(flutterManifest.isPlugin, false);
      expect(flutterManifest.androidPackage, null);
362
      expect(flutterManifest.usesAndroidX, false);
363 364
    });

365
    test('allows a module declaration', () async {
366 367 368
      const String manifest = '''
name: test
flutter:
369
  module:
370
    androidPackage: com.example
371
    androidX: true
372
''';
373
      final FlutterManifest flutterManifest = FlutterManifest.createFromString(manifest);
374
      expect(flutterManifest.isModule, true);
375
      expect(flutterManifest.androidPackage, 'com.example');
376
      expect(flutterManifest.usesAndroidX, true);
377 378
    });

379
    test('allows a legacy plugin declaration', () async {
380 381 382 383 384 385
      const String manifest = '''
name: test
flutter:
  plugin:
    androidPackage: com.example
''';
386
      final FlutterManifest flutterManifest = FlutterManifest.createFromString(manifest);
387 388
      expect(flutterManifest.isPlugin, true);
      expect(flutterManifest.androidPackage, 'com.example');
389
    });
390 391 392 393 394 395 396 397 398 399 400 401 402 403 404
    test('allows a multi-plat plugin declaration', () async {
      const String manifest = '''
name: test
flutter:
    plugin:
      platforms:
        android:
          package: com.example
          pluginClass: TestPlugin
''';
      final FlutterManifest flutterManifest = FlutterManifest.createFromString(manifest);
      expect(flutterManifest.isPlugin, true);
      expect(flutterManifest.androidPackage, 'com.example');
    });

405 406 407 408 409 410 411 412
    testUsingContext('handles an invalid plugin declaration', () async {
      const String manifest = '''
name: test
flutter:
    plugin:
''';
      final FlutterManifest flutterManifest = FlutterManifest.createFromString(manifest);
      expect(flutterManifest, null);
413
      expect(testLogger.errorText, contains('Expected "plugin" to be an object, but got null'));
414 415
    });

416 417 418 419 420

    Future<void> checkManifestVersion({
      String manifest,
      String expectedAppVersion,
      String expectedBuildName,
421
      String expectedBuildNumber,
422
    }) async {
423
      final FlutterManifest flutterManifest = FlutterManifest.createFromString(manifest);
424 425 426 427 428
      expect(flutterManifest.appVersion, expectedAppVersion);
      expect(flutterManifest.buildName, expectedBuildName);
      expect(flutterManifest.buildNumber, expectedBuildNumber);
    }

429
    test('parses major.minor.patch+build version clause 1', () async {
430 431 432 433 434 435 436 437 438 439 440 441
      const String manifest = '''
name: test
version: 1.0.0+2
dependencies:
  flutter:
    sdk: flutter
flutter:
''';
      await checkManifestVersion(
        manifest: manifest,
        expectedAppVersion: '1.0.0+2',
        expectedBuildName: '1.0.0',
442
        expectedBuildNumber: '2',
443 444 445
      );
    });

446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462
    test('parses major.minor.patch with no build version', () async {
      const String manifest = '''
name: test
version: 0.0.1
dependencies:
  flutter:
    sdk: flutter
flutter:
''';
      await checkManifestVersion(
        manifest: manifest,
        expectedAppVersion: '0.0.1',
        expectedBuildName: '0.0.1',
        expectedBuildNumber: null,
      );
    });

463
    test('parses major.minor.patch+build version clause 2', () async {
464 465
      const String manifest = '''
name: test
466
version: 1.0.0-beta+exp.sha.5114f85
467 468 469 470 471 472 473
dependencies:
  flutter:
    sdk: flutter
flutter:
''';
      await checkManifestVersion(
        manifest: manifest,
474 475 476
        expectedAppVersion: '1.0.0-beta+exp.sha.5114f85',
        expectedBuildName: '1.0.0-beta',
        expectedBuildNumber: 'exp.sha.5114f85',
477 478 479
      );
    });

480
    test('parses major.minor+build version clause', () async {
481 482
      const String manifest = '''
name: test
483
version: 1.0+2
484 485 486 487 488 489 490
dependencies:
  flutter:
    sdk: flutter
flutter:
''';
      await checkManifestVersion(
        manifest: manifest,
491 492 493
        expectedAppVersion: '1.0+2',
        expectedBuildName: '1.0',
        expectedBuildNumber: '2',
494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512
      );
    });

    test('parses empty version clause', () async {
      const String manifest = '''
name: test
version:
dependencies:
  flutter:
    sdk: flutter
flutter:
''';
      await checkManifestVersion(
        manifest: manifest,
        expectedAppVersion: null,
        expectedBuildName: null,
        expectedBuildNumber: null,
      );
    });
513

514 515 516 517 518 519 520 521 522 523 524 525 526 527 528
    test('parses no version clause', () async {
      const String manifest = '''
name: test
dependencies:
  flutter:
    sdk: flutter
flutter:
''';
      await checkManifestVersion(
        manifest: manifest,
        expectedAppVersion: null,
        expectedBuildName: null,
        expectedBuildNumber: null,
      );
    });
529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545

    // Regression test for https://github.com/flutter/flutter/issues/31764
    testUsingContext('Returns proper error when font detail is malformed', () async {
      const String manifest = '''
name: test
dependencies:
  flutter:
    sdk: flutter
flutter:
  fonts:
    - family: foo
      fonts:
        -asset: a/bar
''';
      final FlutterManifest flutterManifest = FlutterManifest.createFromString(manifest);

      expect(flutterManifest, null);
546
      expect(testLogger.errorText, contains('Expected "fonts" to either be null or a list.'));
547
    });
548

549 550 551 552 553 554 555 556 557 558 559 560 561 562 563
    testUsingContext('Returns proper error when font detail is not a list of maps', () async {
      const String manifest = '''
name: test
dependencies:
  flutter:
    sdk: flutter
flutter:
  fonts:
    - family: foo
      fonts:
        - asset
''';
      final FlutterManifest flutterManifest = FlutterManifest.createFromString(manifest);

      expect(flutterManifest, null);
564
      expect(testLogger.errorText, contains('Expected "fonts" to be a list of maps.'));
565 566
    });

567 568 569 570 571 572 573 574 575 576 577 578 579 580 581
    testUsingContext('Returns proper error when font is a map instead of a list', () async {
      const String manifest = '''
name: test
dependencies:
  flutter:
    sdk: flutter
flutter:
  fonts:
    family: foo
    fonts:
      -asset: a/bar
''';
      final FlutterManifest flutterManifest = FlutterManifest.createFromString(manifest);

      expect(flutterManifest, null);
582
      expect(testLogger.errorText, contains('Expected "fonts" to be a list'));
583 584
    });

585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600
    testUsingContext('Returns proper error when second font family is invalid', () async {
      const String manifest = '''
name: test
dependencies:
  flutter:
    sdk: flutter
flutter:
  uses-material-design: true
  fonts:
    - family: foo
      fonts:
        - asset: a/bar
    - string
''';
      final FlutterManifest flutterManifest = FlutterManifest.createFromString(manifest);
      expect(flutterManifest, null);
601
      expect(testLogger.errorText, contains('Expected a map.'));
602
    });
603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618

    testUsingContext('Does not crash on empty entry', () async {
      const String manifest = '''
name: test
dependencies:
  flutter:
    sdk: flutter
flutter:
  uses-material-design: true
  assets:
    - lib/gallery/example_code.dart
    -
''';
      final FlutterManifest flutterManifest = FlutterManifest.createFromString(manifest);
      final List<Uri> assets = flutterManifest.assets;

619
      expect(testLogger.errorText, contains('Asset manifest contains a null or empty uri.'));
620 621
      expect(assets.length, 1);
    });
622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643

    testUsingContext('Special characters in asset URIs', () async {
      const String manifest = '''
name: test
dependencies:
  flutter:
    sdk: flutter
flutter:
  uses-material-design: true
  assets:
    - lib/gallery/abc#xyz
    - lib/gallery/abc?xyz
    - lib/gallery/aaa bbb
''';
      final FlutterManifest flutterManifest = FlutterManifest.createFromString(manifest);
      final List<Uri> assets = flutterManifest.assets;

      expect(assets.length, 3);
      expect(assets[0].path, 'lib/gallery/abc%23xyz');
      expect(assets[1].path, 'lib/gallery/abc%3Fxyz');
      expect(assets[2].path, 'lib/gallery/aaa%20bbb');
    });
644
  });
645 646

  group('FlutterManifest with MemoryFileSystem', () {
647
    Future<void> assertSchemaIsReadable() async {
648 649 650 651 652 653 654 655
      const String manifest = '''
name: test
dependencies:
  flutter:
    sdk: flutter
flutter:
''';

656
      final FlutterManifest flutterManifest = FlutterManifest.createFromString(manifest);
657 658 659
      expect(flutterManifest.isEmpty, false);
    }

660 661 662 663 664
    void testUsingContextAndFs(
      String description,
      FileSystem filesystem,
      dynamic testMethod(),
    ) {
665 666 667 668 669 670 671 672
      testUsingContext(
        description,
        () async {
          writeEmptySchemaFile(filesystem);
          testMethod();
        },
        overrides: <Type, Generator>{
          FileSystem: () => filesystem,
673
          ProcessManager: () => FakeProcessManager.any(),
674
        },
675 676 677
      );
    }

678
    testUsingContext('Validate manifest on original fs', () {
679 680 681
      assertSchemaIsReadable();
    });

682 683 684 685 686 687
    testUsingContextAndFs(
      'Validate manifest on Posix FS',
      MemoryFileSystem(style: FileSystemStyle.posix),
      () {
        assertSchemaIsReadable();
      },
688 689
    );

690 691 692 693 694 695
    testUsingContextAndFs(
      'Validate manifest on Windows FS',
      MemoryFileSystem(style: FileSystemStyle.windows),
      () {
        assertSchemaIsReadable();
      },
696 697 698
    );

  });
699
}