feat: improve error displayed for malformed plist (#3487)
This commit is contained in:
@@ -1,18 +1,39 @@
|
||||
// cspell:words propertylistserialization xcarchives
|
||||
// cspell:words propertylistserialization xcarchives plutil
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:propertylistserialization/propertylistserialization.dart';
|
||||
|
||||
/// Exception thrown when a plist file cannot be parsed.
|
||||
class PlistParseException implements Exception {
|
||||
/// Creates a new [PlistParseException].
|
||||
const PlistParseException({required this.filePath, required this.cause});
|
||||
|
||||
/// The path to the plist file that failed to parse.
|
||||
final String filePath;
|
||||
|
||||
/// The underlying exception that caused the parse failure.
|
||||
final Exception cause;
|
||||
|
||||
@override
|
||||
String toString() =>
|
||||
'Failed to parse $filePath: $cause\n'
|
||||
'Verify the plist is valid by running: plutil -lint $filePath';
|
||||
}
|
||||
|
||||
/// A representation of an Info.plist file.
|
||||
class Plist {
|
||||
/// Creates a new [Plist] from the contents of the provided [file].
|
||||
Plist({required File file}) {
|
||||
properties =
|
||||
PropertyListSerialization.propertyListWithString(
|
||||
file.readAsStringSync(),
|
||||
)
|
||||
as Map<String, Object>;
|
||||
try {
|
||||
properties =
|
||||
PropertyListSerialization.propertyListWithString(
|
||||
file.readAsStringSync(),
|
||||
)
|
||||
as Map<String, Object>;
|
||||
} on PropertyListReadStreamException catch (e) {
|
||||
throw PlistParseException(filePath: file.path, cause: e);
|
||||
}
|
||||
}
|
||||
|
||||
/// This key is a user-visible string for the version of the bundle. The
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
// cspell:words plutil
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:shorebird_cli/src/platform/apple/plist.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
void main() {
|
||||
group('Plist', () {
|
||||
late Directory tempDir;
|
||||
|
||||
setUp(() {
|
||||
tempDir = Directory.systemTemp.createTempSync('plist_test_');
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
tempDir.deleteSync(recursive: true);
|
||||
});
|
||||
|
||||
group('constructor', () {
|
||||
test('throws PlistParseException when plist is malformed', () {
|
||||
final file = File(p.join(tempDir.path, 'Info.plist'))
|
||||
..writeAsStringSync('not valid plist xml');
|
||||
|
||||
expect(
|
||||
() => Plist(file: file),
|
||||
throwsA(
|
||||
isA<PlistParseException>()
|
||||
.having(
|
||||
(e) => e.filePath,
|
||||
'filePath',
|
||||
file.path,
|
||||
)
|
||||
.having(
|
||||
(e) => e.toString(),
|
||||
'toString',
|
||||
allOf(
|
||||
contains('Failed to parse'),
|
||||
contains('plutil -lint'),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
group('versionNumber', () {
|
||||
test('returns version from standard plist', () {
|
||||
final file = File(p.join(tempDir.path, 'Info.plist'))
|
||||
..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>CFBundleShortVersionString</key>
|
||||
<string>1.2.3</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>4</string>
|
||||
</dict>
|
||||
</plist>
|
||||
''');
|
||||
|
||||
expect(Plist(file: file).versionNumber, equals('1.2.3+4'));
|
||||
});
|
||||
|
||||
test('returns version without build number when not present', () {
|
||||
final file = File(p.join(tempDir.path, 'Info.plist'))
|
||||
..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>CFBundleShortVersionString</key>
|
||||
<string>1.0.0</string>
|
||||
</dict>
|
||||
</plist>
|
||||
''');
|
||||
|
||||
expect(Plist(file: file).versionNumber, equals('1.0.0'));
|
||||
});
|
||||
|
||||
test('throws when release version is missing', () {
|
||||
final file = File(p.join(tempDir.path, 'Info.plist'))
|
||||
..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>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
</dict>
|
||||
</plist>
|
||||
''');
|
||||
|
||||
expect(
|
||||
() => Plist(file: file).versionNumber,
|
||||
throwsA(
|
||||
isA<Exception>().having(
|
||||
(e) => e.toString(),
|
||||
'message',
|
||||
contains('Could not determine release version'),
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user