// Copyright 2014 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import 'package:file/memory.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/features.dart'; import 'package:flutter_tools/src/flutter_project_metadata.dart'; import 'package:flutter_tools/src/project.dart'; import '../src/common.dart'; import '../src/context.dart'; import '../src/fakes.dart'; void main() { late FileSystem fileSystem; late BufferLogger logger; late File metadataFile; setUp(() { fileSystem = MemoryFileSystem.test(); logger = BufferLogger.test(); metadataFile = fileSystem.file('.metadata'); }); testWithoutContext('project metadata fields are empty when file does not exist', () { final FlutterProjectMetadata projectMetadata = FlutterProjectMetadata(metadataFile, logger); expect(projectMetadata.projectType, isNull); expect(projectMetadata.versionChannel, isNull); expect(projectMetadata.versionRevision, isNull); expect(logger.traceText, contains('No .metadata file found at .metadata')); }); testWithoutContext('project metadata fields are empty when file is empty', () { metadataFile.createSync(); final FlutterProjectMetadata projectMetadata = FlutterProjectMetadata(metadataFile, logger); expect(projectMetadata.projectType, isNull); expect(projectMetadata.versionChannel, isNull); expect(projectMetadata.versionRevision, isNull); expect(logger.traceText, contains('.metadata file at .metadata was empty or malformed.')); }); testWithoutContext('project metadata fields are empty when file is not valid yaml', () { metadataFile.writeAsStringSync(' channel: @something'); final FlutterProjectMetadata projectMetadata = FlutterProjectMetadata(metadataFile, logger); expect(projectMetadata.projectType, isNull); expect(projectMetadata.versionChannel, isNull); expect(projectMetadata.versionRevision, isNull); expect(logger.traceText, contains('.metadata file at .metadata was empty or malformed.')); }); testWithoutContext('projectType is populated when version is null', () { metadataFile ..createSync() ..writeAsStringSync(''' version: project_type: plugin '''); final FlutterProjectMetadata projectMetadata = FlutterProjectMetadata(metadataFile, logger); expect(projectMetadata.projectType, FlutterTemplateType.plugin); expect(projectMetadata.versionChannel, isNull); expect(projectMetadata.versionRevision, isNull); expect( logger.traceText, contains('The value of key `version` in .metadata was expected to be YamlMap but was Null'), ); }); testWithoutContext('projectType is populated when version is malformed', () { metadataFile ..createSync() ..writeAsStringSync(''' version: STRING INSTEAD OF MAP project_type: plugin '''); final FlutterProjectMetadata projectMetadata = FlutterProjectMetadata(metadataFile, logger); expect(projectMetadata.projectType, FlutterTemplateType.plugin); expect(projectMetadata.versionChannel, isNull); expect(projectMetadata.versionRevision, isNull); expect( logger.traceText, contains('The value of key `version` in .metadata was expected to be YamlMap but was String'), ); }); testWithoutContext('version is populated when projectType is malformed', () { metadataFile ..createSync() ..writeAsStringSync(''' version: revision: b59b226a49391949247e3d6122e34bb001049ae4 channel: stable project_type: {} '''); final FlutterProjectMetadata projectMetadata = FlutterProjectMetadata(metadataFile, logger); expect(projectMetadata.projectType, isNull); expect(projectMetadata.versionChannel, 'stable'); expect(projectMetadata.versionRevision, 'b59b226a49391949247e3d6122e34bb001049ae4'); expect( logger.traceText, contains( 'The value of key `project_type` in .metadata was expected to be String but was YamlMap', ), ); }); testWithoutContext('migrate config is populated when version is malformed', () { metadataFile ..createSync() ..writeAsStringSync(''' version: STRING INSTEAD OF MAP project_type: {} migration: platforms: - platform: root create_revision: abcdefg base_revision: baserevision unmanaged_files: - 'file1' '''); final FlutterProjectMetadata projectMetadata = FlutterProjectMetadata(metadataFile, logger); expect(projectMetadata.projectType, isNull); expect( projectMetadata.migrateConfig.platformConfigs[SupportedPlatform.root]?.createRevision, 'abcdefg', ); expect( projectMetadata.migrateConfig.platformConfigs[SupportedPlatform.root]?.baseRevision, 'baserevision', ); expect(projectMetadata.migrateConfig.unmanagedFiles[0], 'file1'); expect( logger.traceText, contains('The value of key `version` in .metadata was expected to be YamlMap but was String'), ); expect( logger.traceText, contains( 'The value of key `project_type` in .metadata was expected to be String but was YamlMap', ), ); }); testWithoutContext('migrate config is populated when unmanaged_files is malformed', () { metadataFile ..createSync() ..writeAsStringSync(''' version: revision: b59b226a49391949247e3d6122e34bb001049ae4 channel: stable project_type: app migration: platforms: - platform: root create_revision: abcdefg base_revision: baserevision unmanaged_files: {} '''); final FlutterProjectMetadata projectMetadata = FlutterProjectMetadata(metadataFile, logger); expect(projectMetadata.projectType, FlutterTemplateType.app); expect( projectMetadata.migrateConfig.platformConfigs[SupportedPlatform.root]?.createRevision, 'abcdefg', ); expect( projectMetadata.migrateConfig.platformConfigs[SupportedPlatform.root]?.baseRevision, 'baserevision', ); // Tool uses default unmanaged files list when malformed. expect(projectMetadata.migrateConfig.unmanagedFiles[0], 'lib/main.dart'); expect( logger.traceText, contains( 'The value of key `unmanaged_files` in .metadata was expected to be YamlList but was YamlMap', ), ); }); testWithoutContext('platforms is populated with a malformed entry', () { metadataFile ..createSync() ..writeAsStringSync(''' version: revision: b59b226a49391949247e3d6122e34bb001049ae4 channel: stable project_type: app migration: platforms: - platform: root create_revision: abcdefg base_revision: baserevision - platform: android base_revision: baserevision - platform: ios create_revision: abcdefg base_revision: baserevision unmanaged_files: - 'file1' '''); final FlutterProjectMetadata projectMetadata = FlutterProjectMetadata(metadataFile, logger); expect(projectMetadata.projectType, FlutterTemplateType.app); expect( projectMetadata.migrateConfig.platformConfigs[SupportedPlatform.root]?.createRevision, 'abcdefg', ); expect( projectMetadata.migrateConfig.platformConfigs[SupportedPlatform.root]?.baseRevision, 'baserevision', ); expect( projectMetadata.migrateConfig.platformConfigs[SupportedPlatform.ios]?.createRevision, 'abcdefg', ); expect( projectMetadata.migrateConfig.platformConfigs[SupportedPlatform.ios]?.baseRevision, 'baserevision', ); expect( projectMetadata.migrateConfig.platformConfigs.containsKey(SupportedPlatform.android), false, ); expect(projectMetadata.migrateConfig.unmanagedFiles[0], 'file1'); expect(logger.traceText, contains('The key `create_revision` was not found')); }); testUsingContext( 'enabledValues does not contain packageFfi if native-assets not enabled', () { expect( ParsedFlutterTemplateType.enabledValues(featureFlags), isNot(contains(FlutterTemplateType.packageFfi)), ); expect( ParsedFlutterTemplateType.enabledValues(featureFlags), contains(FlutterTemplateType.plugin), ); }, overrides: { // ignore: avoid_redundant_argument_values FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: false), }, ); testUsingContext('enabledValues contains packageFfi if natives-assets enabled', () { expect( ParsedFlutterTemplateType.enabledValues(featureFlags), contains(FlutterTemplateType.packageFfi), ); expect( ParsedFlutterTemplateType.enabledValues(featureFlags), contains(FlutterTemplateType.plugin), ); }); }