blob: af72538c4c94ad736640a793640e7a3693c80e8b [file] [log] [blame]
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:io' as io;
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import '../src/common.dart';
import 'test_utils.dart';
const xcodeBackendPath = 'bin/xcode_backend.sh';
const xcodeBackendErrorHeader =
'========================================================================';
// Acceptable $CONFIGURATION/$FLUTTER_BUILD_MODE values should be debug, profile, or release
const unknownConfiguration = <String, String>{'CONFIGURATION': 'Custom'};
// $FLUTTER_BUILD_MODE will override $CONFIGURATION
const unknownFlutterBuildMode = <String, String>{
'FLUTTER_BUILD_MODE': 'Custom',
'CONFIGURATION': 'Debug',
};
void main() {
Future<void> expectXcodeBackendFails(Map<String, String> environment) async {
final ProcessResult result = await Process.run(xcodeBackendPath, <String>[
'build',
], environment: environment);
expect(result.stderr, startsWith(xcodeBackendErrorHeader));
expect(result.exitCode, isNot(0));
}
test('Xcode backend fails with no arguments', () async {
final ProcessResult result = await Process.run(
xcodeBackendPath,
<String>[],
environment: <String, String>{
'SOURCE_ROOT': '../examples/hello_world',
'FLUTTER_ROOT': '../..',
},
);
expect(
result.stderr,
startsWith('error: Your Xcode project is incompatible with this version of Flutter.'),
);
expect(result.exitCode, isNot(0));
}, skip: !io.Platform.isMacOS); // [intended] requires macos toolchain.
test('Xcode backend fails for on unsupported configuration combinations', () async {
await expectXcodeBackendFails(unknownConfiguration);
await expectXcodeBackendFails(unknownFlutterBuildMode);
}, skip: !io.Platform.isMacOS); // [intended] requires macos toolchain.
test('Xcode backend warns when unable to determine platform', () async {
final ProcessResult result = await Process.run(
xcodeBackendPath,
<String>['build', 'asdf'],
environment: <String, String>{'CONFIGURATION': 'Debug', 'ACTION': 'install'},
);
expect(result.stderr, contains('warning: Unrecognized platform: asdf. Defaulting to iOS.'));
expect(result.exitCode, isNot(0));
}, skip: !io.Platform.isMacOS); // [intended] requires macos toolchain.
group('vmService Bonjour service keys', () {
late Directory buildDirectory;
late File infoPlist;
setUp(() {
buildDirectory = globals.fs.systemTempDirectory.createTempSync(
'flutter_tools_xcode_backend_test.',
);
infoPlist = buildDirectory.childFile('Info.plist');
});
test('handles when the Info.plist is missing', () async {
final ProcessResult result = await Process.run(
xcodeBackendPath,
<String>['test_vm_service_bonjour_service'],
environment: <String, String>{
'CONFIGURATION': 'Debug',
'BUILT_PRODUCTS_DIR': buildDirectory.path,
'INFOPLIST_PATH': 'Info.plist',
},
);
expect(result, const ProcessResultMatcher(stdoutPattern: 'Info.plist does not exist.'));
});
const emptyPlist = '''
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
</dict>
</plist>''';
test('does not add keys in Release', () async {
infoPlist.writeAsStringSync(emptyPlist);
final ProcessResult result = await Process.run(
xcodeBackendPath,
<String>['test_vm_service_bonjour_service'],
environment: <String, String>{
'CONFIGURATION': 'Release',
'BUILT_PRODUCTS_DIR': buildDirectory.path,
'INFOPLIST_PATH': 'Info.plist',
},
);
final String actualInfoPlist = infoPlist.readAsStringSync();
expect(actualInfoPlist, isNot(contains('NSBonjourServices')));
expect(actualInfoPlist, isNot(contains('dartVmService')));
expect(actualInfoPlist, isNot(contains('NSLocalNetworkUsageDescription')));
expect(result, const ProcessResultMatcher());
});
for (final buildConfiguration in <String>['Debug', 'Profile']) {
for (final verbose in <bool>[true, false]) {
test(
'add keys in $buildConfiguration under ${verbose ? 'verbose' : 'non-verbose'} mode',
() async {
infoPlist.writeAsStringSync(emptyPlist);
final File pipe = fileSystem.file('/tmp/pipe')..createSync(recursive: true);
final ProcessResult result = await Process.run(
xcodeBackendPath,
<String>['test_vm_service_bonjour_service'],
environment: <String, String>{
'CONFIGURATION': buildConfiguration,
'BUILT_PRODUCTS_DIR': buildDirectory.path,
'INFOPLIST_PATH': 'Info.plist',
if (verbose) 'VERBOSE_SCRIPT_LOGGING': 'YES',
'SCRIPT_OUTPUT_STREAM_FILE': pipe.path,
},
);
final String actualInfoPlist = infoPlist.readAsStringSync();
expect(actualInfoPlist, contains('NSBonjourServices'));
expect(actualInfoPlist, contains('dartVmService'));
expect(actualInfoPlist, contains('NSLocalNetworkUsageDescription'));
// Make sure no Xcode compilation error.
expect(result.stderr, isNot(startsWith('error:')));
const plutilErrorMessage =
'Could not extract value, error: No value at that key path or invalid key path: NSBonjourServices';
expect(pipe.readAsStringSync(), isNot(contains(plutilErrorMessage)));
expect(result.stderr, isNot(contains(plutilErrorMessage)));
if (verbose) {
expect(result.stdout, contains(plutilErrorMessage));
} else {
expect(result.stdout, isNot(contains(plutilErrorMessage)));
}
expect(result, const ProcessResultMatcher());
},
);
}
}
test(
'adds to existing Bonjour services, does not override network usage description',
() async {
infoPlist.writeAsStringSync('''
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSBonjourServices</key>
<array>
<string>_bogus._tcp</string>
</array>
<key>NSLocalNetworkUsageDescription</key>
<string>Don't override this</string>
</dict>
</plist>''');
final ProcessResult result = await Process.run(
xcodeBackendPath,
<String>['test_vm_service_bonjour_service'],
environment: <String, String>{
'CONFIGURATION': 'Debug',
'BUILT_PRODUCTS_DIR': buildDirectory.path,
'INFOPLIST_PATH': 'Info.plist',
},
);
expect(infoPlist.readAsStringSync(), '''
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSBonjourServices</key>
<array>
<string>_dartVmService._tcp</string>
<string>_bogus._tcp</string>
</array>
<key>NSLocalNetworkUsageDescription</key>
<string>Don't override this</string>
</dict>
</plist>
''');
expect(result.stderr, isNot(startsWith('error:')));
expect(result, const ProcessResultMatcher());
},
);
test('does not add bonjour settings when port publication is disabled', () async {
infoPlist.writeAsStringSync('''
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
</dict>
</plist>''');
final ProcessResult result = await Process.run(
xcodeBackendPath,
<String>['test_vm_service_bonjour_service'],
environment: <String, String>{
'CONFIGURATION': 'Debug',
'BUILT_PRODUCTS_DIR': buildDirectory.path,
'INFOPLIST_PATH': 'Info.plist',
'DISABLE_PORT_PUBLICATION': 'YES',
},
);
expect(infoPlist.readAsStringSync().contains('NSBonjourServices'), isFalse);
expect(infoPlist.readAsStringSync().contains('NSLocalNetworkUsageDescription'), isFalse);
expect(result, const ProcessResultMatcher());
});
}, skip: !io.Platform.isMacOS); // [intended] requires macos toolchain.
}