Unverified Commit bd940073 authored by Jenn Magder's avatar Jenn Magder Committed by GitHub

Migrate localizations_utils to null safety (#78939)

parent b8041178
...@@ -2,8 +2,6 @@ ...@@ -2,8 +2,6 @@
// 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.
// @dart = 2.8
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import 'package:yaml/yaml.dart'; import 'package:yaml/yaml.dart';
...@@ -22,11 +20,11 @@ int sortFilesByPath (File a, File b) { ...@@ -22,11 +20,11 @@ int sortFilesByPath (File a, File b) {
@immutable @immutable
class LocaleInfo implements Comparable<LocaleInfo> { class LocaleInfo implements Comparable<LocaleInfo> {
const LocaleInfo({ const LocaleInfo({
this.languageCode, required this.languageCode,
this.scriptCode, required this.scriptCode,
this.countryCode, required this.countryCode,
this.length, required this.length,
this.originalString, required this.originalString,
}); });
/// Simple parser. Expects the locale string to be in the form of 'language_script_COUNTRY' /// Simple parser. Expects the locale string to be in the form of 'language_script_COUNTRY'
...@@ -41,8 +39,8 @@ class LocaleInfo implements Comparable<LocaleInfo> { ...@@ -41,8 +39,8 @@ class LocaleInfo implements Comparable<LocaleInfo> {
final List<String> codes = locale.split('_'); // [language, script, country] final List<String> codes = locale.split('_'); // [language, script, country]
assert(codes.isNotEmpty && codes.length < 4); assert(codes.isNotEmpty && codes.length < 4);
final String languageCode = codes[0]; final String languageCode = codes[0];
String scriptCode; String? scriptCode;
String countryCode; String? countryCode;
int length = codes.length; int length = codes.length;
String originalString = locale; String originalString = locale;
if (codes.length == 2) { if (codes.length == 2) {
...@@ -112,8 +110,8 @@ class LocaleInfo implements Comparable<LocaleInfo> { ...@@ -112,8 +110,8 @@ class LocaleInfo implements Comparable<LocaleInfo> {
} }
final String languageCode; final String languageCode;
final String scriptCode; final String? scriptCode;
final String countryCode; final String? countryCode;
final int length; // The number of fields. Ranges from 1-3. final int length; // The number of fields. Ranges from 1-3.
final String originalString; // Original un-parsed locale string. final String originalString; // Original un-parsed locale string.
...@@ -149,7 +147,7 @@ class LocaleInfo implements Comparable<LocaleInfo> { ...@@ -149,7 +147,7 @@ class LocaleInfo implements Comparable<LocaleInfo> {
// See also //master/tools/gen_locale.dart in the engine repo. // See also //master/tools/gen_locale.dart in the engine repo.
Map<String, List<String>> _parseSection(String section) { Map<String, List<String>> _parseSection(String section) {
final Map<String, List<String>> result = <String, List<String>>{}; final Map<String, List<String>> result = <String, List<String>>{};
List<String> lastHeading; late List<String> lastHeading;
for (final String line in section.split('\n')) { for (final String line in section.split('\n')) {
if (line == '') { if (line == '') {
continue; continue;
...@@ -165,7 +163,7 @@ Map<String, List<String>> _parseSection(String section) { ...@@ -165,7 +163,7 @@ Map<String, List<String>> _parseSection(String section) {
final String name = line.substring(0, colon); final String name = line.substring(0, colon);
final String value = line.substring(colon + 2); final String value = line.substring(colon + 2);
lastHeading = result.putIfAbsent(name, () => <String>[]); lastHeading = result.putIfAbsent(name, () => <String>[]);
result[name].add(value); result[name]!.add(value);
} }
return result; return result;
} }
...@@ -184,11 +182,11 @@ void precacheLanguageAndRegionTags() { ...@@ -184,11 +182,11 @@ void precacheLanguageAndRegionTags() {
languageSubtagRegistry.split('%%').skip(1).map<Map<String, List<String>>>(_parseSection).toList(); languageSubtagRegistry.split('%%').skip(1).map<Map<String, List<String>>>(_parseSection).toList();
for (final Map<String, List<String>> section in sections) { for (final Map<String, List<String>> section in sections) {
assert(section.containsKey('Type'), section.toString()); assert(section.containsKey('Type'), section.toString());
final String type = section['Type'].single; final String type = section['Type']!.single;
if (type == 'language' || type == 'region' || type == 'script') { if (type == 'language' || type == 'region' || type == 'script') {
assert(section.containsKey('Subtag') && section.containsKey('Description'), section.toString()); assert(section.containsKey('Subtag') && section.containsKey('Description'), section.toString());
final String subtag = section['Subtag'].single; final String subtag = section['Subtag']!.single;
String description = section['Description'].join(' '); String description = section['Description']!.join(' ');
if (description.startsWith('United ')) { if (description.startsWith('United ')) {
description = 'the $description'; description = 'the $description';
} }
...@@ -220,10 +218,10 @@ String describeLocale(String tag) { ...@@ -220,10 +218,10 @@ String describeLocale(String tag) {
final List<String> subtags = tag.split('_'); final List<String> subtags = tag.split('_');
assert(subtags.isNotEmpty); assert(subtags.isNotEmpty);
assert(_languages.containsKey(subtags[0])); assert(_languages.containsKey(subtags[0]));
final String language = _languages[subtags[0]]; final String language = _languages[subtags[0]]!;
String output = language; String output = language;
String region; String? region;
String script; String? script;
if (subtags.length == 2) { if (subtags.length == 2) {
region = _regions[subtags[1]]; region = _regions[subtags[1]];
script = _scripts[subtags[1]]; script = _scripts[subtags[1]];
...@@ -311,50 +309,50 @@ class LocalizationOptions { ...@@ -311,50 +309,50 @@ class LocalizationOptions {
/// The `--arb-dir` argument. /// The `--arb-dir` argument.
/// ///
/// The directory where all input localization files should reside. /// The directory where all input localization files should reside.
final Uri arbDirectory; final Uri? arbDirectory;
/// The `--template-arb-file` argument. /// The `--template-arb-file` argument.
/// ///
/// This URI is relative to [arbDirectory]. /// This URI is relative to [arbDirectory].
final Uri templateArbFile; final Uri? templateArbFile;
/// The `--output-localization-file` argument. /// The `--output-localization-file` argument.
/// ///
/// This URI is relative to [arbDirectory]. /// This URI is relative to [arbDirectory].
final Uri outputLocalizationsFile; final Uri? outputLocalizationsFile;
/// The `--untranslated-messages-file` argument. /// The `--untranslated-messages-file` argument.
/// ///
/// This URI is relative to [arbDirectory]. /// This URI is relative to [arbDirectory].
final Uri untranslatedMessagesFile; final Uri? untranslatedMessagesFile;
/// The `--header` argument. /// The `--header` argument.
/// ///
/// The header to prepend to the generated Dart localizations. /// The header to prepend to the generated Dart localizations.
final String header; final String? header;
/// The `--output-class` argument. /// The `--output-class` argument.
final String outputClass; final String? outputClass;
/// The `--output-dir` argument. /// The `--output-dir` argument.
/// ///
/// The directory where all output localization files should be generated. /// The directory where all output localization files should be generated.
final Uri outputDirectory; final Uri? outputDirectory;
/// The `--preferred-supported-locales` argument. /// The `--preferred-supported-locales` argument.
final List<String> preferredSupportedLocales; final List<String>? preferredSupportedLocales;
/// The `--header-file` argument. /// The `--header-file` argument.
/// ///
/// A file containing the header to prepend to the generated /// A file containing the header to prepend to the generated
/// Dart localizations. /// Dart localizations.
final Uri headerFile; final Uri? headerFile;
/// The `--use-deferred-loading` argument. /// The `--use-deferred-loading` argument.
/// ///
/// Whether to generate the Dart localization file with locales imported /// Whether to generate the Dart localization file with locales imported
/// as deferred. /// as deferred.
final bool deferredLoading; final bool? deferredLoading;
/// The `--synthetic-package` argument. /// The `--synthetic-package` argument.
/// ///
...@@ -375,8 +373,8 @@ class LocalizationOptions { ...@@ -375,8 +373,8 @@ class LocalizationOptions {
/// [LocalizationOptions] with all fields as `null` if the config file exists /// [LocalizationOptions] with all fields as `null` if the config file exists
/// but is empty. /// but is empty.
LocalizationOptions parseLocalizationsOptions({ LocalizationOptions parseLocalizationsOptions({
@required File file, required File file,
@required Logger logger, required Logger logger,
}) { }) {
final String contents = file.readAsStringSync(); final String contents = file.readAsStringSync();
if (contents.trim().isEmpty) { if (contents.trim().isEmpty) {
...@@ -387,26 +385,25 @@ LocalizationOptions parseLocalizationsOptions({ ...@@ -387,26 +385,25 @@ LocalizationOptions parseLocalizationsOptions({
logger.printError('Expected ${file.path} to contain a map, instead was $yamlNode'); logger.printError('Expected ${file.path} to contain a map, instead was $yamlNode');
throw Exception(); throw Exception();
} }
final YamlMap yamlMap = yamlNode as YamlMap;
return LocalizationOptions( return LocalizationOptions(
arbDirectory: _tryReadUri(yamlMap, 'arb-dir', logger), arbDirectory: _tryReadUri(yamlNode, 'arb-dir', logger),
templateArbFile: _tryReadUri(yamlMap, 'template-arb-file', logger), templateArbFile: _tryReadUri(yamlNode, 'template-arb-file', logger),
outputLocalizationsFile: _tryReadUri(yamlMap, 'output-localization-file', logger), outputLocalizationsFile: _tryReadUri(yamlNode, 'output-localization-file', logger),
untranslatedMessagesFile: _tryReadUri(yamlMap, 'untranslated-messages-file', logger), untranslatedMessagesFile: _tryReadUri(yamlNode, 'untranslated-messages-file', logger),
header: _tryReadString(yamlMap, 'header', logger), header: _tryReadString(yamlNode, 'header', logger),
outputClass: _tryReadString(yamlMap, 'output-class', logger), outputClass: _tryReadString(yamlNode, 'output-class', logger),
outputDirectory: _tryReadUri(yamlMap, 'output-dir', logger), outputDirectory: _tryReadUri(yamlNode, 'output-dir', logger),
preferredSupportedLocales: _tryReadStringList(yamlMap, 'preferred-supported-locales', logger), preferredSupportedLocales: _tryReadStringList(yamlNode, 'preferred-supported-locales', logger),
headerFile: _tryReadUri(yamlMap, 'header-file', logger), headerFile: _tryReadUri(yamlNode, 'header-file', logger),
deferredLoading: _tryReadBool(yamlMap, 'use-deferred-loading', logger), deferredLoading: _tryReadBool(yamlNode, 'use-deferred-loading', logger),
useSyntheticPackage: _tryReadBool(yamlMap, 'synthetic-package', logger) ?? true, useSyntheticPackage: _tryReadBool(yamlNode, 'synthetic-package', logger) ?? true,
areResourceAttributesRequired: _tryReadBool(yamlMap, 'required-resource-attributes', logger) ?? false, areResourceAttributesRequired: _tryReadBool(yamlNode, 'required-resource-attributes', logger) ?? false,
); );
} }
// Try to read a `bool` value or null from `yamlMap`, otherwise throw. // Try to read a `bool` value or null from `yamlMap`, otherwise throw.
bool _tryReadBool(YamlMap yamlMap, String key, Logger logger) { bool? _tryReadBool(YamlMap yamlMap, String key, Logger logger) {
final Object value = yamlMap[key]; final Object? value = yamlMap[key];
if (value == null) { if (value == null) {
return null; return null;
} }
...@@ -414,12 +411,12 @@ bool _tryReadBool(YamlMap yamlMap, String key, Logger logger) { ...@@ -414,12 +411,12 @@ bool _tryReadBool(YamlMap yamlMap, String key, Logger logger) {
logger.printError('Expected "$key" to have a bool value, instead was "$value"'); logger.printError('Expected "$key" to have a bool value, instead was "$value"');
throw Exception(); throw Exception();
} }
return value as bool; return value;
} }
// Try to read a `String` value or null from `yamlMap`, otherwise throw. // Try to read a `String` value or null from `yamlMap`, otherwise throw.
String _tryReadString(YamlMap yamlMap, String key, Logger logger) { String? _tryReadString(YamlMap yamlMap, String key, Logger logger) {
final Object value = yamlMap[key]; final Object? value = yamlMap[key];
if (value == null) { if (value == null) {
return null; return null;
} }
...@@ -427,11 +424,11 @@ String _tryReadString(YamlMap yamlMap, String key, Logger logger) { ...@@ -427,11 +424,11 @@ String _tryReadString(YamlMap yamlMap, String key, Logger logger) {
logger.printError('Expected "$key" to have a String value, instead was "$value"'); logger.printError('Expected "$key" to have a String value, instead was "$value"');
throw Exception(); throw Exception();
} }
return value as String; return value;
} }
List<String> _tryReadStringList(YamlMap yamlMap, String key, Logger logger) { List<String>? _tryReadStringList(YamlMap yamlMap, String key, Logger logger) {
final Object value = yamlMap[key]; final Object? value = yamlMap[key];
if (value == null) { if (value == null) {
return null; return null;
} }
...@@ -446,12 +443,12 @@ List<String> _tryReadStringList(YamlMap yamlMap, String key, Logger logger) { ...@@ -446,12 +443,12 @@ List<String> _tryReadStringList(YamlMap yamlMap, String key, Logger logger) {
} }
// Try to read a valid `Uri` or null from `yamlMap`, otherwise throw. // Try to read a valid `Uri` or null from `yamlMap`, otherwise throw.
Uri _tryReadUri(YamlMap yamlMap, String key, Logger logger) { Uri? _tryReadUri(YamlMap yamlMap, String key, Logger logger) {
final String value = _tryReadString(yamlMap, key, logger); final String? value = _tryReadString(yamlMap, key, logger);
if (value == null) { if (value == null) {
return null; return null;
} }
final Uri uri = Uri.tryParse(value); final Uri? uri = Uri.tryParse(value);
if (uri == null) { if (uri == null) {
logger.printError('"$value" must be a relative file URI'); logger.printError('"$value" must be a relative file URI');
} }
......
...@@ -19,7 +19,7 @@ import '../../../src/context.dart'; ...@@ -19,7 +19,7 @@ import '../../../src/context.dart';
void main() { void main() {
// Verifies that values are correctly passed through the localizations // Verifies that values are correctly passed through the localizations
// target, but does not validate them beyond the serialized data type. // target, but does not validate them beyond the serialized data type.
testUsingContext('generateLocalizations forwards arguments correctly', () async { testWithoutContext('generateLocalizations forwards arguments correctly', () async {
final FileSystem fileSystem = MemoryFileSystem.test(); final FileSystem fileSystem = MemoryFileSystem.test();
final Logger logger = BufferLogger.test(); final Logger logger = BufferLogger.test();
final Directory flutterProjectDirectory = fileSystem final Directory flutterProjectDirectory = fileSystem
...@@ -76,7 +76,7 @@ void main() { ...@@ -76,7 +76,7 @@ void main() {
verify(mockLocalizationsGenerator.writeOutputFiles(logger, isFromYaml: true)).called(1); verify(mockLocalizationsGenerator.writeOutputFiles(logger, isFromYaml: true)).called(1);
}); });
testUsingContext('generateLocalizations throws exception on missing flutter: generate: true flag', () async { testWithoutContext('generateLocalizations throws exception on missing flutter: generate: true flag', () async {
final FileSystem fileSystem = MemoryFileSystem.test(); final FileSystem fileSystem = MemoryFileSystem.test();
final BufferLogger logger = BufferLogger.test(); final BufferLogger logger = BufferLogger.test();
final Directory arbDirectory = fileSystem.directory('arb') final Directory arbDirectory = fileSystem.directory('arb')
......
...@@ -12,15 +12,13 @@ import 'package:yaml/yaml.dart'; ...@@ -12,15 +12,13 @@ import 'package:yaml/yaml.dart';
import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/convert.dart'; import 'package:flutter_tools/src/convert.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:flutter_tools/src/localizations/gen_l10n.dart'; import 'package:flutter_tools/src/localizations/gen_l10n.dart';
import 'package:flutter_tools/src/localizations/gen_l10n_types.dart'; import 'package:flutter_tools/src/localizations/gen_l10n_types.dart';
import 'package:flutter_tools/src/localizations/localizations_utils.dart'; import 'package:flutter_tools/src/localizations/localizations_utils.dart';
import 'package:test/test.dart';
final String defaultL10nPathString = globals.fs.path.join('lib', 'l10n'); import '../src/common.dart';
final String syntheticPackagePath = globals.fs.path.join('.dart_tool', 'flutter_gen'); import '../src/context.dart';
final String syntheticL10nPackagePath = globals.fs.path.join(syntheticPackagePath, 'gen_l10n');
const String defaultTemplateArbFileName = 'app_en.arb'; const String defaultTemplateArbFileName = 'app_en.arb';
const String defaultOutputFileString = 'output-localization-file.dart'; const String defaultOutputFileString = 'output-localization-file.dart';
const String defaultClassNameString = 'AppLocalizations'; const String defaultClassNameString = 'AppLocalizations';
...@@ -71,16 +69,23 @@ void _standardFlutterDirectoryL10nSetup(FileSystem fs) { ...@@ -71,16 +69,23 @@ void _standardFlutterDirectoryL10nSetup(FileSystem fs) {
void main() { void main() {
MemoryFileSystem fs; MemoryFileSystem fs;
String defaultL10nPathString;
String syntheticPackagePath;
String syntheticL10nPackagePath;
setUp(() { setUp(() {
fs = MemoryFileSystem( fs = MemoryFileSystem(
style: Platform.isWindows ? FileSystemStyle.windows : FileSystemStyle.posix style: Platform.isWindows ? FileSystemStyle.windows : FileSystemStyle.posix
); );
defaultL10nPathString = fs.path.join('lib', 'l10n');
syntheticPackagePath = fs.path.join('.dart_tool', 'flutter_gen');
syntheticL10nPackagePath = fs.path.join(syntheticPackagePath, 'gen_l10n');
precacheLanguageAndRegionTags(); precacheLanguageAndRegionTags();
}); });
group('Setters', () { group('Setters', () {
test('setInputDirectory fails if the directory does not exist', () { testWithoutContext('setInputDirectory fails if the directory does not exist', () {
final LocalizationsGenerator generator = LocalizationsGenerator(fs); final LocalizationsGenerator generator = LocalizationsGenerator(fs);
try { try {
generator.setInputDirectory('lib'); generator.setInputDirectory('lib');
...@@ -95,7 +100,7 @@ void main() { ...@@ -95,7 +100,7 @@ void main() {
); );
}); });
test('setInputDirectory fails if input string is null', () { testWithoutContext('setInputDirectory fails if input string is null', () {
_standardFlutterDirectoryL10nSetup(fs); _standardFlutterDirectoryL10nSetup(fs);
final LocalizationsGenerator generator = LocalizationsGenerator(fs); final LocalizationsGenerator generator = LocalizationsGenerator(fs);
try { try {
...@@ -111,7 +116,7 @@ void main() { ...@@ -111,7 +116,7 @@ void main() {
); );
}); });
test( testWithoutContext(
'setOutputDirectory fails if output string is null while not using the ' 'setOutputDirectory fails if output string is null while not using the '
'synthetic package option', 'synthetic package option',
() { () {
...@@ -132,7 +137,7 @@ void main() { ...@@ -132,7 +137,7 @@ void main() {
}, },
); );
test('setTemplateArbFile fails if inputDirectory is null', () { testWithoutContext('setTemplateArbFile fails if inputDirectory is null', () {
final LocalizationsGenerator generator = LocalizationsGenerator(fs); final LocalizationsGenerator generator = LocalizationsGenerator(fs);
try { try {
generator.setTemplateArbFile(defaultTemplateArbFileName); generator.setTemplateArbFile(defaultTemplateArbFileName);
...@@ -147,7 +152,7 @@ void main() { ...@@ -147,7 +152,7 @@ void main() {
); );
}); });
test('setTemplateArbFile fails if templateArbFileName is null', () { testWithoutContext('setTemplateArbFile fails if templateArbFileName is null', () {
_standardFlutterDirectoryL10nSetup(fs); _standardFlutterDirectoryL10nSetup(fs);
final LocalizationsGenerator generator = LocalizationsGenerator(fs); final LocalizationsGenerator generator = LocalizationsGenerator(fs);
try { try {
...@@ -163,7 +168,7 @@ void main() { ...@@ -163,7 +168,7 @@ void main() {
); );
}); });
test('setTemplateArbFile fails if input string is null', () { testWithoutContext('setTemplateArbFile fails if input string is null', () {
_standardFlutterDirectoryL10nSetup(fs); _standardFlutterDirectoryL10nSetup(fs);
final LocalizationsGenerator generator = LocalizationsGenerator(fs); final LocalizationsGenerator generator = LocalizationsGenerator(fs);
try { try {
...@@ -179,7 +184,7 @@ void main() { ...@@ -179,7 +184,7 @@ void main() {
); );
}); });
test('setBaseOutputFile fails if input string is null', () { testWithoutContext('setBaseOutputFile fails if input string is null', () {
_standardFlutterDirectoryL10nSetup(fs); _standardFlutterDirectoryL10nSetup(fs);
final LocalizationsGenerator generator = LocalizationsGenerator(fs); final LocalizationsGenerator generator = LocalizationsGenerator(fs);
try { try {
...@@ -195,7 +200,7 @@ void main() { ...@@ -195,7 +200,7 @@ void main() {
); );
}); });
test('setting className fails if input string is null', () { testWithoutContext('setting className fails if input string is null', () {
_standardFlutterDirectoryL10nSetup(fs); _standardFlutterDirectoryL10nSetup(fs);
final LocalizationsGenerator generator = LocalizationsGenerator(fs); final LocalizationsGenerator generator = LocalizationsGenerator(fs);
try { try {
...@@ -211,7 +216,7 @@ void main() { ...@@ -211,7 +216,7 @@ void main() {
); );
}); });
test('sets absolute path of the target Flutter project', () { testUsingContext('sets absolute path of the target Flutter project', () {
// Set up project directory. // Set up project directory.
final Directory l10nDirectory = fs.currentDirectory final Directory l10nDirectory = fs.currentDirectory
.childDirectory('absolute') .childDirectory('absolute')
...@@ -269,7 +274,7 @@ void main() { ...@@ -269,7 +274,7 @@ void main() {
); );
}); });
test('throws error when directory at absolute path does not exist', () { testWithoutContext('throws error when directory at absolute path does not exist', () {
// Set up project directory. // Set up project directory.
final Directory l10nDirectory = fs.currentDirectory final Directory l10nDirectory = fs.currentDirectory
.childDirectory('lib') .childDirectory('lib')
...@@ -317,7 +322,7 @@ void main() { ...@@ -317,7 +322,7 @@ void main() {
} }
}); });
test('fails on string with spaces', () { testWithoutContext('fails on string with spaces', () {
try { try {
generator.className = 'String with spaces'; generator.className = 'String with spaces';
} on L10nException catch (e) { } on L10nException catch (e) {
...@@ -330,7 +335,7 @@ void main() { ...@@ -330,7 +335,7 @@ void main() {
); );
}); });
test('fails on non-alphanumeric symbols', () { testWithoutContext('fails on non-alphanumeric symbols', () {
try { try {
generator.className = 'TestClass@123'; generator.className = 'TestClass@123';
} on L10nException catch (e) { } on L10nException catch (e) {
...@@ -343,7 +348,7 @@ void main() { ...@@ -343,7 +348,7 @@ void main() {
); );
}); });
test('fails on camel-case', () { testWithoutContext('fails on camel-case', () {
try { try {
generator.className = 'camelCaseClassName'; generator.className = 'camelCaseClassName';
} on L10nException catch (e) { } on L10nException catch (e) {
...@@ -356,7 +361,7 @@ void main() { ...@@ -356,7 +361,7 @@ void main() {
); );
}); });
test('fails when starting with a number', () { testWithoutContext('fails when starting with a number', () {
try { try {
generator.className = '123ClassName'; generator.className = '123ClassName';
} on L10nException catch (e) { } on L10nException catch (e) {
...@@ -371,7 +376,7 @@ void main() { ...@@ -371,7 +376,7 @@ void main() {
}); });
}); });
test('correctly adds a headerString when it is set', () { testUsingContext('correctly adds a headerString when it is set', () {
_standardFlutterDirectoryL10nSetup(fs); _standardFlutterDirectoryL10nSetup(fs);
LocalizationsGenerator generator; LocalizationsGenerator generator;
...@@ -392,7 +397,7 @@ void main() { ...@@ -392,7 +397,7 @@ void main() {
expect(generator.header, '/// Sample header'); expect(generator.header, '/// Sample header');
}); });
test('correctly adds a headerFile when it is set', () { testUsingContext('correctly adds a headerFile when it is set', () {
fs.currentDirectory.childDirectory('lib').childDirectory('l10n') fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
..createSync(recursive: true) ..createSync(recursive: true)
..childFile(defaultTemplateArbFileName).writeAsStringSync(singleMessageArbFileString) ..childFile(defaultTemplateArbFileName).writeAsStringSync(singleMessageArbFileString)
...@@ -417,7 +422,7 @@ void main() { ...@@ -417,7 +422,7 @@ void main() {
expect(generator.header, '/// Sample header in a text file'); expect(generator.header, '/// Sample header in a text file');
}); });
test('sets templateArbFileName with more than one underscore correctly', () { testUsingContext('sets templateArbFileName with more than one underscore correctly', () {
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n') final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
..createSync(recursive: true); ..createSync(recursive: true);
l10nDirectory.childFile('app_localizations_en.arb') l10nDirectory.childFile('app_localizations_en.arb')
...@@ -446,7 +451,7 @@ void main() { ...@@ -446,7 +451,7 @@ void main() {
expect(outputDirectory.childFile('output-localization-file_es.dart').existsSync(), isTrue); expect(outputDirectory.childFile('output-localization-file_es.dart').existsSync(), isTrue);
}); });
test('filenames with invalid locales should not be recognized', () { testUsingContext('filenames with invalid locales should not be recognized', () {
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n') final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
..createSync(recursive: true); ..createSync(recursive: true);
l10nDirectory.childFile('app_localizations_en.arb') l10nDirectory.childFile('app_localizations_en.arb')
...@@ -472,7 +477,7 @@ void main() { ...@@ -472,7 +477,7 @@ void main() {
fail('Using app_en_CA_foo.arb should fail as it is not a valid locale.'); fail('Using app_en_CA_foo.arb should fail as it is not a valid locale.');
}); });
test('correctly creates an untranslated messages file (useSyntheticPackage = true)', () { testUsingContext('correctly creates an untranslated messages file (useSyntheticPackage = true)', () {
fs.currentDirectory.childDirectory('lib').childDirectory('l10n') fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
..createSync(recursive: true) ..createSync(recursive: true)
..childFile(defaultTemplateArbFileName).writeAsStringSync(twoMessageArbFileString) ..childFile(defaultTemplateArbFileName).writeAsStringSync(twoMessageArbFileString)
...@@ -510,7 +515,7 @@ void main() { ...@@ -510,7 +515,7 @@ void main() {
expect(unimplementedOutputString, contains('subtitle')); expect(unimplementedOutputString, contains('subtitle'));
}); });
test('correctly creates an untranslated messages file (useSyntheticPackage = false)', () { testUsingContext('correctly creates an untranslated messages file (useSyntheticPackage = false)', () {
fs.currentDirectory.childDirectory('lib').childDirectory('l10n') fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
..createSync(recursive: true) ..createSync(recursive: true)
..childFile(defaultTemplateArbFileName).writeAsStringSync(twoMessageArbFileString) ..childFile(defaultTemplateArbFileName).writeAsStringSync(twoMessageArbFileString)
...@@ -549,7 +554,7 @@ void main() { ...@@ -549,7 +554,7 @@ void main() {
expect(unimplementedOutputString, contains('subtitle')); expect(unimplementedOutputString, contains('subtitle'));
}); });
test( testUsingContext(
'untranslated messages suggestion is printed when translation is missing: ' 'untranslated messages suggestion is printed when translation is missing: '
'command line message', 'command line message',
() { () {
...@@ -588,7 +593,7 @@ void main() { ...@@ -588,7 +593,7 @@ void main() {
}, },
); );
test( testUsingContext(
'untranslated messages suggestion is printed when translation is missing: ' 'untranslated messages suggestion is printed when translation is missing: '
'l10n.yaml message', 'l10n.yaml message',
() { () {
...@@ -625,7 +630,7 @@ void main() { ...@@ -625,7 +630,7 @@ void main() {
}, },
); );
test( testUsingContext(
'unimplemented messages suggestion is not printed when all messages ' 'unimplemented messages suggestion is not printed when all messages '
'are fully translated', 'are fully translated',
() { () {
...@@ -656,7 +661,7 @@ void main() { ...@@ -656,7 +661,7 @@ void main() {
}, },
); );
test('untranslated messages file included in generated JSON list of outputs', () { testUsingContext('untranslated messages file included in generated JSON list of outputs', () {
_standardFlutterDirectoryL10nSetup(fs); _standardFlutterDirectoryL10nSetup(fs);
LocalizationsGenerator generator; LocalizationsGenerator generator;
...@@ -689,7 +694,7 @@ void main() { ...@@ -689,7 +694,7 @@ void main() {
expect(outputList, contains(contains('unimplemented_message_translations.json'))); expect(outputList, contains(contains('unimplemented_message_translations.json')));
}); });
test( testUsingContext(
'uses inputPathString as outputPathString when the outputPathString is ' 'uses inputPathString as outputPathString when the outputPathString is '
'null while not using the synthetic package option', 'null while not using the synthetic package option',
() { () {
...@@ -719,7 +724,7 @@ void main() { ...@@ -719,7 +724,7 @@ void main() {
}, },
); );
test( testUsingContext(
'correctly generates output files in non-default output directory if it ' 'correctly generates output files in non-default output directory if it '
'already exists while not using the synthetic package option', 'already exists while not using the synthetic package option',
() { () {
...@@ -763,7 +768,7 @@ void main() { ...@@ -763,7 +768,7 @@ void main() {
}, },
); );
test( testUsingContext(
'correctly creates output directory if it does not exist and writes files ' 'correctly creates output directory if it does not exist and writes files '
'in it while not using the synthetic package option', 'in it while not using the synthetic package option',
() { () {
...@@ -795,7 +800,7 @@ void main() { ...@@ -795,7 +800,7 @@ void main() {
}, },
); );
test('creates list of inputs and outputs when file path is specified', () { testUsingContext('creates list of inputs and outputs when file path is specified', () {
_standardFlutterDirectoryL10nSetup(fs); _standardFlutterDirectoryL10nSetup(fs);
LocalizationsGenerator generator; LocalizationsGenerator generator;
...@@ -833,7 +838,7 @@ void main() { ...@@ -833,7 +838,7 @@ void main() {
expect(outputList, contains(fs.path.absolute(syntheticL10nPackagePath, 'output-localization-file_es.dart'))); expect(outputList, contains(fs.path.absolute(syntheticL10nPackagePath, 'output-localization-file_es.dart')));
}); });
test('setting both a headerString and a headerFile should fail', () { testUsingContext('setting both a headerString and a headerFile should fail', () {
fs.currentDirectory.childDirectory('lib').childDirectory('l10n') fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
..createSync(recursive: true) ..createSync(recursive: true)
..childFile(defaultTemplateArbFileName).writeAsStringSync(singleMessageArbFileString) ..childFile(defaultTemplateArbFileName).writeAsStringSync(singleMessageArbFileString)
...@@ -860,7 +865,7 @@ void main() { ...@@ -860,7 +865,7 @@ void main() {
fail('Setting both headerFile and headerString should fail'); fail('Setting both headerFile and headerString should fail');
}); });
test('setting a headerFile that does not exist should fail', () { testUsingContext('setting a headerFile that does not exist should fail', () {
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n') final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
..createSync(recursive: true); ..createSync(recursive: true);
l10nDirectory.childFile(defaultTemplateArbFileName) l10nDirectory.childFile(defaultTemplateArbFileName)
...@@ -889,7 +894,7 @@ void main() { ...@@ -889,7 +894,7 @@ void main() {
fail('Setting headerFile that does not exist should fail'); fail('Setting headerFile that does not exist should fail');
}); });
test('setting useDefferedLoading to null should fail', () { testUsingContext('setting useDefferedLoading to null should fail', () {
_standardFlutterDirectoryL10nSetup(fs); _standardFlutterDirectoryL10nSetup(fs);
LocalizationsGenerator generator; LocalizationsGenerator generator;
...@@ -913,7 +918,7 @@ void main() { ...@@ -913,7 +918,7 @@ void main() {
}); });
group('loadResources', () { group('loadResources', () {
test('correctly initializes supportedLocales and supportedLanguageCodes properties', () { testUsingContext('correctly initializes supportedLocales and supportedLanguageCodes properties', () {
_standardFlutterDirectoryL10nSetup(fs); _standardFlutterDirectoryL10nSetup(fs);
LocalizationsGenerator generator; LocalizationsGenerator generator;
...@@ -935,7 +940,7 @@ void main() { ...@@ -935,7 +940,7 @@ void main() {
expect(generator.supportedLocales.contains(LocaleInfo.fromString('es')), true); expect(generator.supportedLocales.contains(LocaleInfo.fromString('es')), true);
}); });
test('correctly sorts supportedLocales and supportedLanguageCodes alphabetically', () { testUsingContext('correctly sorts supportedLocales and supportedLanguageCodes alphabetically', () {
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n') final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
..createSync(recursive: true); ..createSync(recursive: true);
// Write files in non-alphabetical order so that read performs in that order // Write files in non-alphabetical order so that read performs in that order
...@@ -966,7 +971,7 @@ void main() { ...@@ -966,7 +971,7 @@ void main() {
expect(generator.supportedLocales.elementAt(2), LocaleInfo.fromString('zh')); expect(generator.supportedLocales.elementAt(2), LocaleInfo.fromString('zh'));
}); });
test('adds preferred locales to the top of supportedLocales and supportedLanguageCodes', () { testUsingContext('adds preferred locales to the top of supportedLocales and supportedLanguageCodes', () {
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n') final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
..createSync(recursive: true); ..createSync(recursive: true);
l10nDirectory.childFile('app_en.arb') l10nDirectory.childFile('app_en.arb')
...@@ -998,7 +1003,7 @@ void main() { ...@@ -998,7 +1003,7 @@ void main() {
expect(generator.supportedLocales.elementAt(2), LocaleInfo.fromString('en')); expect(generator.supportedLocales.elementAt(2), LocaleInfo.fromString('en'));
}); });
test( testUsingContext(
'throws an error attempting to add preferred locales ' 'throws an error attempting to add preferred locales '
'when there is no corresponding arb file for that ' 'when there is no corresponding arb file for that '
'locale', 'locale',
...@@ -1040,7 +1045,7 @@ void main() { ...@@ -1040,7 +1045,7 @@ void main() {
}, },
); );
test('correctly sorts arbPathString alphabetically', () { testUsingContext('correctly sorts arbPathString alphabetically', () {
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n') final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
..createSync(recursive: true); ..createSync(recursive: true);
// Write files in non-alphabetical order so that read performs in that order // Write files in non-alphabetical order so that read performs in that order
...@@ -1071,7 +1076,7 @@ void main() { ...@@ -1071,7 +1076,7 @@ void main() {
expect(generator.arbPathStrings.elementAt(2), fs.path.join('lib', 'l10n', 'app_zh.arb')); expect(generator.arbPathStrings.elementAt(2), fs.path.join('lib', 'l10n', 'app_zh.arb'));
}); });
test('correctly parses @@locale property in arb file', () { testUsingContext('correctly parses @@locale property in arb file', () {
const String arbFileWithEnLocale = ''' const String arbFileWithEnLocale = '''
{ {
"@@locale": "en", "@@locale": "en",
...@@ -1116,7 +1121,7 @@ void main() { ...@@ -1116,7 +1121,7 @@ void main() {
expect(generator.supportedLocales.contains(LocaleInfo.fromString('zh')), true); expect(generator.supportedLocales.contains(LocaleInfo.fromString('zh')), true);
}); });
test('correctly requires @@locale property in arb file to match the filename locale suffix', () { testUsingContext('correctly requires @@locale property in arb file to match the filename locale suffix', () {
const String arbFileWithEnLocale = ''' const String arbFileWithEnLocale = '''
{ {
"@@locale": "en", "@@locale": "en",
...@@ -1164,7 +1169,7 @@ void main() { ...@@ -1164,7 +1169,7 @@ void main() {
); );
}); });
test("throws when arb file's locale could not be determined", () { testUsingContext("throws when arb file's locale could not be determined", () {
fs.currentDirectory.childDirectory('lib').childDirectory('l10n') fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
..createSync(recursive: true) ..createSync(recursive: true)
..childFile('app.arb') ..childFile('app.arb')
...@@ -1188,7 +1193,7 @@ void main() { ...@@ -1188,7 +1193,7 @@ void main() {
'should fail' 'should fail'
); );
}); });
test('throws when the same locale is detected more than once', () { testUsingContext('throws when the same locale is detected more than once', () {
const String secondMessageArbFileString = ''' const String secondMessageArbFileString = '''
{ {
"market": "MARKET", "market": "MARKET",
...@@ -1225,7 +1230,7 @@ void main() { ...@@ -1225,7 +1230,7 @@ void main() {
); );
}); });
test('throws when the base locale does not exist', () { testUsingContext('throws when the base locale does not exist', () {
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n') final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
..createSync(recursive: true); ..createSync(recursive: true);
l10nDirectory.childFile('app_en_US.arb') l10nDirectory.childFile('app_en_US.arb')
...@@ -1254,7 +1259,7 @@ void main() { ...@@ -1254,7 +1259,7 @@ void main() {
}); });
group('writeOutputFiles', () { group('writeOutputFiles', () {
test('message without placeholders - should generate code comment with description and template message translation', () { testUsingContext('message without placeholders - should generate code comment with description and template message translation', () {
_standardFlutterDirectoryL10nSetup(fs); _standardFlutterDirectoryL10nSetup(fs);
final LocalizationsGenerator generator = LocalizationsGenerator(fs); final LocalizationsGenerator generator = LocalizationsGenerator(fs);
final BufferLogger testLogger = BufferLogger.test(); final BufferLogger testLogger = BufferLogger.test();
...@@ -1286,7 +1291,7 @@ void main() { ...@@ -1286,7 +1291,7 @@ void main() {
/// **'Title'**''')); /// **'Title'**'''));
}); });
test('template message translation handles newline characters', () { testUsingContext('template message translation handles newline characters', () {
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n') final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
..createSync(recursive: true); ..createSync(recursive: true);
l10nDirectory.childFile(defaultTemplateArbFileName) l10nDirectory.childFile(defaultTemplateArbFileName)
...@@ -1331,7 +1336,7 @@ void main() { ...@@ -1331,7 +1336,7 @@ void main() {
/// **'Title \n of the application'**''')); /// **'Title \n of the application'**'''));
}); });
test('message with placeholders - should generate code comment with description and template message translation', () { testUsingContext('message with placeholders - should generate code comment with description and template message translation', () {
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n') final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
..createSync(recursive: true); ..createSync(recursive: true);
l10nDirectory.childFile(defaultTemplateArbFileName) l10nDirectory.childFile(defaultTemplateArbFileName)
...@@ -1386,7 +1391,7 @@ void main() { ...@@ -1386,7 +1391,7 @@ void main() {
/// **'The price of this item is: \${price}'**''')); /// **'The price of this item is: \${price}'**'''));
}); });
test('should generate a file per language', () { testUsingContext('should generate a file per language', () {
const String singleEnCaMessageArbFileString = ''' const String singleEnCaMessageArbFileString = '''
{ {
"title": "Canadian Title" "title": "Canadian Title"
...@@ -1420,7 +1425,7 @@ void main() { ...@@ -1420,7 +1425,7 @@ void main() {
expect(englishLocalizationsFile, contains('class AppLocalizationsEn extends AppLocalizations')); expect(englishLocalizationsFile, contains('class AppLocalizationsEn extends AppLocalizations'));
}); });
test('language imports are sorted when preferredSupportedLocaleString is given', () { testUsingContext('language imports are sorted when preferredSupportedLocaleString is given', () {
fs.currentDirectory.childDirectory('lib').childDirectory('l10n')..createSync(recursive: true) fs.currentDirectory.childDirectory('lib').childDirectory('l10n')..createSync(recursive: true)
..childFile(defaultTemplateArbFileName).writeAsStringSync(singleMessageArbFileString) ..childFile(defaultTemplateArbFileName).writeAsStringSync(singleMessageArbFileString)
..childFile('app_zh.arb').writeAsStringSync(singleZhMessageArbFileString) ..childFile('app_zh.arb').writeAsStringSync(singleZhMessageArbFileString)
...@@ -1454,7 +1459,7 @@ import 'output-localization-file_zh.dart'; ...@@ -1454,7 +1459,7 @@ import 'output-localization-file_zh.dart';
''')); '''));
}); });
test('imports are deferred and loaded when useDeferredImports are set', () { testUsingContext('imports are deferred and loaded when useDeferredImports are set', () {
fs.currentDirectory.childDirectory('lib').childDirectory('l10n')..createSync(recursive: true) fs.currentDirectory.childDirectory('lib').childDirectory('l10n')..createSync(recursive: true)
..childFile(defaultTemplateArbFileName).writeAsStringSync(singleMessageArbFileString); ..childFile(defaultTemplateArbFileName).writeAsStringSync(singleMessageArbFileString);
...@@ -1484,7 +1489,7 @@ import 'output-localization-file_en.dart' deferred as output-localization-file_e ...@@ -1484,7 +1489,7 @@ import 'output-localization-file_en.dart' deferred as output-localization-file_e
}); });
group('DateTime tests', () { group('DateTime tests', () {
test('throws an exception when improperly formatted date is passed in', () { testUsingContext('throws an exception when improperly formatted date is passed in', () {
const String singleDateMessageArbFileString = ''' const String singleDateMessageArbFileString = '''
{ {
"@@locale": "en", "@@locale": "en",
...@@ -1524,7 +1529,7 @@ import 'output-localization-file_en.dart' deferred as output-localization-file_e ...@@ -1524,7 +1529,7 @@ import 'output-localization-file_en.dart' deferred as output-localization-file_e
fail('Improper date formatting should throw an exception'); fail('Improper date formatting should throw an exception');
}); });
test('throws an exception when no format attribute is passed in', () { testUsingContext('throws an exception when no format attribute is passed in', () {
const String singleDateMessageArbFileString = ''' const String singleDateMessageArbFileString = '''
{ {
"springBegins": "Spring begins on {springStartDate}", "springBegins": "Spring begins on {springStartDate}",
...@@ -1561,7 +1566,7 @@ import 'output-localization-file_en.dart' deferred as output-localization-file_e ...@@ -1561,7 +1566,7 @@ import 'output-localization-file_en.dart' deferred as output-localization-file_e
fail('Improper date formatting should throw an exception'); fail('Improper date formatting should throw an exception');
}); });
test('throws an exception when improperly formatted number is passed in', () { testUsingContext('throws an exception when improperly formatted number is passed in', () {
const String singleDateMessageArbFileString = ''' const String singleDateMessageArbFileString = '''
{ {
"courseCompletion": "You have completed {progress} of the course.", "courseCompletion": "You have completed {progress} of the course.",
...@@ -1603,7 +1608,7 @@ import 'output-localization-file_en.dart' deferred as output-localization-file_e ...@@ -1603,7 +1608,7 @@ import 'output-localization-file_en.dart' deferred as output-localization-file_e
}); });
group('plural messages', () { group('plural messages', () {
test('should throw attempting to generate a plural message without placeholders', () { testUsingContext('should throw attempting to generate a plural message without placeholders', () {
const String pluralMessageWithoutPlaceholdersAttribute = ''' const String pluralMessageWithoutPlaceholdersAttribute = '''
{ {
"helloWorlds": "{count,plural, =0{Hello}=1{Hello World}=2{Hello two worlds}few{Hello {count} worlds}many{Hello all {count} worlds}other{Hello other {count} worlds}}", "helloWorlds": "{count,plural, =0{Hello}=1{Hello World}=2{Hello two worlds}few{Hello {count} worlds}many{Hello all {count} worlds}other{Hello other {count} worlds}}",
...@@ -1635,7 +1640,7 @@ import 'output-localization-file_en.dart' deferred as output-localization-file_e ...@@ -1635,7 +1640,7 @@ import 'output-localization-file_en.dart' deferred as output-localization-file_e
fail('Generating class methods without placeholders should not succeed'); fail('Generating class methods without placeholders should not succeed');
}); });
test('should throw attempting to generate a plural message with an empty placeholders map', () { testUsingContext('should throw attempting to generate a plural message with an empty placeholders map', () {
const String pluralMessageWithEmptyPlaceholdersMap = ''' const String pluralMessageWithEmptyPlaceholdersMap = '''
{ {
"helloWorlds": "{count,plural, =0{Hello}=1{Hello World}=2{Hello two worlds}few{Hello {count} worlds}many{Hello all {count} worlds}other{Hello other {count} worlds}}", "helloWorlds": "{count,plural, =0{Hello}=1{Hello World}=2{Hello two worlds}few{Hello {count} worlds}many{Hello all {count} worlds}other{Hello other {count} worlds}}",
...@@ -1668,7 +1673,7 @@ import 'output-localization-file_en.dart' deferred as output-localization-file_e ...@@ -1668,7 +1673,7 @@ import 'output-localization-file_en.dart' deferred as output-localization-file_e
fail('Generating class methods without placeholders should not succeed'); fail('Generating class methods without placeholders should not succeed');
}); });
test('should throw attempting to generate a plural message with no resource attributes', () { testUsingContext('should throw attempting to generate a plural message with no resource attributes', () {
const String pluralMessageWithoutResourceAttributes = ''' const String pluralMessageWithoutResourceAttributes = '''
{ {
"helloWorlds": "{count,plural, =0{Hello}=1{Hello World}=2{Hello two worlds}few{Hello {count} worlds}many{Hello all {count} worlds}other{Hello other {count} worlds}}" "helloWorlds": "{count,plural, =0{Hello}=1{Hello World}=2{Hello two worlds}few{Hello {count} worlds}many{Hello all {count} worlds}other{Hello other {count} worlds}}"
...@@ -1697,7 +1702,7 @@ import 'output-localization-file_en.dart' deferred as output-localization-file_e ...@@ -1697,7 +1702,7 @@ import 'output-localization-file_en.dart' deferred as output-localization-file_e
fail('Generating plural class method without resource attributes should not succeed'); fail('Generating plural class method without resource attributes should not succeed');
}); });
test('should throw attempting to generate a plural message with incorrect format for placeholders', () { testUsingContext('should throw attempting to generate a plural message with incorrect format for placeholders', () {
const String pluralMessageWithIncorrectPlaceholderFormat = ''' const String pluralMessageWithIncorrectPlaceholderFormat = '''
{ {
"helloWorlds": "{count,plural, =0{Hello}=1{Hello World}=2{Hello two worlds}few{Hello {count} worlds}many{Hello all {count} worlds}other{Hello other {count} worlds}}", "helloWorlds": "{count,plural, =0{Hello}=1{Hello World}=2{Hello two worlds}few{Hello {count} worlds}many{Hello all {count} worlds}other{Hello other {count} worlds}}",
...@@ -1731,7 +1736,7 @@ import 'output-localization-file_en.dart' deferred as output-localization-file_e ...@@ -1731,7 +1736,7 @@ import 'output-localization-file_en.dart' deferred as output-localization-file_e
}); });
}); });
test('intl package import should be omitted in subclass files when no plurals are included', () { testUsingContext('intl package import should be omitted in subclass files when no plurals are included', () {
fs.currentDirectory.childDirectory('lib').childDirectory('l10n')..createSync(recursive: true) fs.currentDirectory.childDirectory('lib').childDirectory('l10n')..createSync(recursive: true)
..childFile(defaultTemplateArbFileName).writeAsStringSync(singleMessageArbFileString) ..childFile(defaultTemplateArbFileName).writeAsStringSync(singleMessageArbFileString)
..childFile('app_es.arb').writeAsStringSync(singleEsMessageArbFileString); ..childFile('app_es.arb').writeAsStringSync(singleEsMessageArbFileString);
...@@ -1757,7 +1762,7 @@ import 'output-localization-file_en.dart' deferred as output-localization-file_e ...@@ -1757,7 +1762,7 @@ import 'output-localization-file_en.dart' deferred as output-localization-file_e
expect(localizationsFile, isNot(contains(intlImportDartCode))); expect(localizationsFile, isNot(contains(intlImportDartCode)));
}); });
test('intl package import should be kept in subclass files when plurals are included', () { testUsingContext('intl package import should be kept in subclass files when plurals are included', () {
const String pluralMessageArb = ''' const String pluralMessageArb = '''
{ {
"helloWorlds": "{count,plural, =0{Hello} =1{Hello World} =2{Hello two worlds} few{Hello {count} worlds} many{Hello all {count} worlds} other{Hello other {count} worlds}}", "helloWorlds": "{count,plural, =0{Hello} =1{Hello World} =2{Hello two worlds} few{Hello {count} worlds} many{Hello all {count} worlds} other{Hello other {count} worlds}}",
...@@ -1801,7 +1806,7 @@ import 'output-localization-file_en.dart' deferred as output-localization-file_e ...@@ -1801,7 +1806,7 @@ import 'output-localization-file_en.dart' deferred as output-localization-file_e
expect(localizationsFile, contains(intlImportDartCode)); expect(localizationsFile, contains(intlImportDartCode));
}); });
test('check for string interpolation rules', () { testUsingContext('check for string interpolation rules', () {
const String enArbCheckList = ''' const String enArbCheckList = '''
{ {
"one": "The number of {one} elapsed is: 44", "one": "The number of {one} elapsed is: 44",
...@@ -1941,7 +1946,7 @@ import 'output-localization-file_en.dart' deferred as output-localization-file_e ...@@ -1941,7 +1946,7 @@ import 'output-localization-file_en.dart' deferred as output-localization-file_e
expect(localizationsFile, contains(r'${nine}')); expect(localizationsFile, contains(r'${nine}'));
}); });
test('check for string interpolation rules - plurals', () { testUsingContext('check for string interpolation rules - plurals', () {
const String enArbCheckList = ''' const String enArbCheckList = '''
{ {
"first": "{count,plural, =0{test {count} test} =1{哈{count}哈} =2{m{count}m} few{_{count}_} many{{count} test} other{{count}m}", "first": "{count,plural, =0{test {count} test} =1{哈{count}哈} =2{m{count}m} few{_{count}_} many{{count} test} other{{count}m}",
...@@ -2006,7 +2011,7 @@ import 'output-localization-file_en.dart' deferred as output-localization-file_e ...@@ -2006,7 +2011,7 @@ import 'output-localization-file_en.dart' deferred as output-localization-file_e
expect(localizationsFile, contains(r' $count')); expect(localizationsFile, contains(r' $count'));
}); });
test( testUsingContext(
'should throw with descriptive error message when failing to parse the ' 'should throw with descriptive error message when failing to parse the '
'arb file', 'arb file',
() { () {
...@@ -2047,7 +2052,7 @@ import 'output-localization-file_en.dart' deferred as output-localization-file_e ...@@ -2047,7 +2052,7 @@ import 'output-localization-file_en.dart' deferred as output-localization-file_e
}, },
); );
test('should throw when resource is missing resource attribute (isResourceAttributeRequired = true)', () { testUsingContext('should throw when resource is missing resource attribute (isResourceAttributeRequired = true)', () {
const String arbFileWithMissingResourceAttribute = ''' const String arbFileWithMissingResourceAttribute = '''
{ {
"title": "Stocks" "title": "Stocks"
...@@ -2081,7 +2086,7 @@ import 'output-localization-file_en.dart' deferred as output-localization-file_e ...@@ -2081,7 +2086,7 @@ import 'output-localization-file_en.dart' deferred as output-localization-file_e
}); });
group('checks for method/getter formatting', () { group('checks for method/getter formatting', () {
test('cannot contain non-alphanumeric symbols', () { testUsingContext('cannot contain non-alphanumeric symbols', () {
const String nonAlphaNumericArbFile = ''' const String nonAlphaNumericArbFile = '''
{ {
"title!!": "Stocks", "title!!": "Stocks",
...@@ -2113,7 +2118,7 @@ import 'output-localization-file_en.dart' deferred as output-localization-file_e ...@@ -2113,7 +2118,7 @@ import 'output-localization-file_en.dart' deferred as output-localization-file_e
fail('should fail due to non-alphanumeric character.'); fail('should fail due to non-alphanumeric character.');
}); });
test('must start with lowercase character', () { testUsingContext('must start with lowercase character', () {
const String nonAlphaNumericArbFile = ''' const String nonAlphaNumericArbFile = '''
{ {
"Title": "Stocks", "Title": "Stocks",
...@@ -2145,7 +2150,7 @@ import 'output-localization-file_en.dart' deferred as output-localization-file_e ...@@ -2145,7 +2150,7 @@ import 'output-localization-file_en.dart' deferred as output-localization-file_e
fail('should fail since key starts with a non-lowercase.'); fail('should fail since key starts with a non-lowercase.');
}); });
test('cannot start with a number', () { testUsingContext('cannot start with a number', () {
const String nonAlphaNumericArbFile = ''' const String nonAlphaNumericArbFile = '''
{ {
"123title": "Stocks", "123title": "Stocks",
...@@ -2178,7 +2183,7 @@ import 'output-localization-file_en.dart' deferred as output-localization-file_e ...@@ -2178,7 +2183,7 @@ import 'output-localization-file_en.dart' deferred as output-localization-file_e
}); });
}); });
test('should generate a valid pubspec.yaml file when using synthetic package if it does not already exist', () { testUsingContext('should generate a valid pubspec.yaml file when using synthetic package if it does not already exist', () {
_standardFlutterDirectoryL10nSetup(fs); _standardFlutterDirectoryL10nSetup(fs);
LocalizationsGenerator generator; LocalizationsGenerator generator;
try { try {
...@@ -2210,7 +2215,7 @@ import 'output-localization-file_en.dart' deferred as output-localization-file_e ...@@ -2210,7 +2215,7 @@ import 'output-localization-file_en.dart' deferred as output-localization-file_e
expect(pubspecDescription, "The Flutter application's synthetic package."); expect(pubspecDescription, "The Flutter application's synthetic package.");
}); });
test('should not overwrite existing pubspec.yaml file when using synthetic package', () { testUsingContext('should not overwrite existing pubspec.yaml file when using synthetic package', () {
_standardFlutterDirectoryL10nSetup(fs); _standardFlutterDirectoryL10nSetup(fs);
final File pubspecFile = fs.file(fs.path.join(syntheticPackagePath, 'pubspec.yaml')) final File pubspecFile = fs.file(fs.path.join(syntheticPackagePath, 'pubspec.yaml'))
..createSync(recursive: true) ..createSync(recursive: true)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment