Unify analysis options (#108462)

This commit is contained in:
Michael Goderbauer 2022-07-28 09:07:49 -07:00 committed by GitHub
parent 8a8ed75d3e
commit 10a7c9ba22
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
138 changed files with 1155 additions and 607 deletions

View file

@ -99,7 +99,7 @@ linter:
# - conditional_uri_does_not_exist # not yet tested
# - constant_identifier_names # needs an opt-out https://github.com/dart-lang/linter/issues/204
- control_flow_in_finally
# - curly_braces_in_flow_control_structures # not required by flutter style, but developer-facing code should have this on
- curly_braces_in_flow_control_structures
- depend_on_referenced_packages
- deprecated_consistency
# - diagnostic_describe_all_properties # enabled only at the framework level (packages/flutter/lib)

View file

@ -113,10 +113,11 @@ class ComplexLayoutState extends State<ComplexLayout> {
key: const Key('complex-scroll'), // this key is used by the driver test
controller: ScrollController(), // So that the scroll offset can be tracked
itemBuilder: (BuildContext context, int index) {
if (index.isEven)
if (index.isEven) {
return FancyImageItem(index, key: PageStorageKey<int>(index));
else
} else {
return FancyGalleryItem(index, key: PageStorageKey<int>(index));
}
},
),
),

View file

@ -239,8 +239,9 @@ Map<String, dynamic> scrollSummary(
//
final double absJerk = (scrollOffset[i-1] + scrollOffset[i+1] - 2*scrollOffset[i]).abs();
absJerkAvg += absJerk;
if (absJerk > 0.5)
if (absJerk > 0.5) {
jankyCount += 1;
}
}
// expect(lostFrame < 0.1 * frameTimestamp.length, true);
absJerkAvg /= frameTimestamp.length - lostFrame;

View file

@ -18,8 +18,9 @@ void main() {
});
tearDownAll(() async {
if (driver != null)
if (driver != null) {
driver.close();
}
});
Future<void> testScrollPerf(String listKey, String summaryName) async {

View file

@ -19,8 +19,9 @@ void main() {
});
tearDownAll(() async {
if (driver != null)
if (driver != null) {
driver.close();
}
});
test('initial tree creation', () async {
@ -34,8 +35,9 @@ void main() {
});
final Iterable<TimelineEvent>? semanticsEvents = timeline.events?.where((TimelineEvent event) => event.name == 'SEMANTICS');
if (semanticsEvents?.length != 2)
if (semanticsEvents?.length != 2) {
fail('Expected exactly two "SEMANTICS" events, got ${semanticsEvents?.length}:\n$semanticsEvents');
}
final Duration semanticsTreeCreation = Duration(microseconds: semanticsEvents!.last.timestampMicros! - semanticsEvents.first.timestampMicros!);
final String jsonEncoded = json.encode(<String, dynamic>{'initialSemanticsTreeCreation': semanticsTreeCreation.inMilliseconds});

View file

@ -44,13 +44,16 @@ const int kExitCodeSuccess = 0;
final GetStackPointerCallback getStackPointer = () {
// Makes sure we are running on an Android arm64 device.
if (!io.Platform.isAndroid)
if (!io.Platform.isAndroid) {
throw 'This benchmark test can only be run on Android arm devices.';
}
final io.ProcessResult result = io.Process.runSync('getprop', <String>['ro.product.cpu.abi']);
if (result.exitCode != 0)
if (result.exitCode != 0) {
throw 'Failed to retrieve CPU information.';
if (!result.stdout.toString().contains('armeabi'))
}
if (!result.stdout.toString().contains('armeabi')) {
throw 'This benchmark test can only be run on Android arm devices.';
}
// Creates a block of memory to store the assembly code.
final ffi.Pointer<ffi.Void> region = mmap(ffi.nullptr, kMemorySize, kProtRead | kProtWrite,

View file

@ -159,8 +159,9 @@ class _Tester {
final Stopwatch stopwatch = Stopwatch()..start();
await gesture.moveTo(location, timeStamp: currentTime);
stopwatch.stop();
if (onDataPoint != null)
if (onDataPoint != null) {
onDataPoint(stopwatch.elapsed);
}
await _UntilNextFrame.wait();
}

View file

@ -181,8 +181,9 @@ class _Tester {
final Stopwatch stopwatch = Stopwatch()..start();
await gesture.moveTo(location, timeStamp: currentTime);
stopwatch.stop();
if (onDataPoint != null)
if (onDataPoint != null) {
onDataPoint(stopwatch.elapsed);
}
await _UntilNextFrame.wait();
}

View file

@ -405,8 +405,9 @@ abstract class WidgetRecorder extends Recorder implements FrameRecorder {
if (shouldContinue()) {
PlatformDispatcher.instance.scheduleFrame();
} else {
for (final VoidCallback fn in _didStopCallbacks)
for (final VoidCallback fn in _didStopCallbacks) {
fn();
}
_runCompleter!.complete();
}
}
@ -520,8 +521,9 @@ abstract class WidgetBuildRecorder extends Recorder implements FrameRecorder {
showWidget = !showWidget;
_hostState._setStateTrampoline();
} else {
for (final VoidCallback fn in _didStopCallbacks)
for (final VoidCallback fn in _didStopCallbacks) {
fn();
}
_runCompleter!.complete();
}
}

View file

@ -39,13 +39,14 @@ void main() {
watch.stop();
final int elapsed = watch.elapsedMicroseconds;
final double averagePerIteration = elapsed / iteration;
if (addResult)
if (addResult) {
printer.addResult(
description: '$name ($listenerCount listeners)',
value: averagePerIteration * _kScale,
unit: 'ns per iteration',
name: '$name$listenerCount',
);
}
}
}
@ -65,13 +66,14 @@ void main() {
watch.stop();
final int elapsed = watch.elapsedMicroseconds;
final double averagePerIteration = elapsed / iteration;
if (addResult)
if (addResult) {
printer.addResult(
description: '$name ($listenerCount listeners)',
value: averagePerIteration * _kScale,
unit: 'ns per iteration',
name: '$name$listenerCount',
);
}
}
}
@ -107,13 +109,14 @@ void main() {
watch.stop();
final int elapsed = watch.elapsedMicroseconds;
final double averagePerIteration = elapsed / iteration;
if (addResult)
if (addResult) {
printer.addResult(
description: '$name ($listenerCount listeners)',
value: averagePerIteration * _kScale,
unit: 'ns per iteration',
name: '$name$listenerCount',
);
}
}
}
@ -156,13 +159,14 @@ void main() {
watch.stop();
final int elapsed = watch.elapsedMicroseconds;
final double averagePerIteration = elapsed / iteration;
if (addResult)
if (addResult) {
printer.addResult(
description: '$name ($listenerCount listeners)',
value: averagePerIteration * _kScale,
unit: 'ns per iteration',
name: '$name$listenerCount',
);
}
}
}

View file

@ -32,10 +32,12 @@ void main() {
watch.start();
for (int i = 0; i < _kNumIters; i += 1) {
for (final PointerEvent event in velocityEventData) {
if (event is PointerDownEvent || event is PointerMoveEvent)
if (event is PointerDownEvent || event is PointerMoveEvent) {
tracker.addPosition(event.timeStamp, event.position);
if (event is PointerUpEvent)
}
if (event is PointerUpEvent) {
tracker.getVelocity();
}
}
}
watch.stop();

View file

@ -67,8 +67,9 @@ class StockArrow extends StatelessWidget {
}
Color _colorForPercentChange(double percentChange) {
if (percentChange > 0)
if (percentChange > 0) {
return Colors.green[_colorIndexForPercentChange(percentChange)]!;
}
return Colors.red[_colorIndexForPercentChange(percentChange)]!;
}

View file

@ -85,8 +85,9 @@ class StockHomeState extends State<StockHome> {
}
void _handleStockModeChange(StockMode? value) {
if (widget.updater != null)
if (widget.updater != null) {
widget.updater(widget.configuration.copyWith(stockMode: value));
}
}
void _handleStockMenu(BuildContext context, _StockMenuItem value) {
@ -239,8 +240,9 @@ class StockHomeState extends State<StockHome> {
}
Iterable<Stock> _filterBySearchQuery(Iterable<Stock> stocks) {
if (_searchQuery.text.isEmpty)
if (_searchQuery.text.isEmpty) {
return stocks;
}
final RegExp regexp = RegExp(_searchQuery.text, caseSensitive: false);
return stocks.where((Stock stock) => stock.symbol.contains(regexp));
}

View file

@ -32,8 +32,9 @@ class StockRow extends StatelessWidget {
Widget build(BuildContext context) {
final String lastSale = '\$${stock.lastSale.toStringAsFixed(2)}';
String changeInPrice = '${stock.percentChange.toStringAsFixed(2)}%';
if (stock.percentChange > 0)
if (stock.percentChange > 0) {
changeInPrice = '+$changeInPrice';
}
return InkWell(
key: ValueKey<String>(stock.symbol),
onTap: _getHandler(onPressed),

View file

@ -93,8 +93,9 @@ class StockSettingsState extends State<StockSettings> {
}
void sendUpdates(StockConfiguration value) {
if (widget.updater != null)
if (widget.updater != null) {
widget.updater(value);
}
}
AppBar buildAppBar(BuildContext context) {

View file

@ -21,8 +21,9 @@ class _StockSymbolView extends StatelessWidget {
assert(stock != null);
final String lastSale = '\$${stock.lastSale.toStringAsFixed(2)}';
String changeInPrice = '${stock.percentChange.toStringAsFixed(2)}%';
if (stock.percentChange > 0)
if (stock.percentChange > 0) {
changeInPrice = '+$changeInPrice';
}
final TextStyle headings = Theme.of(context).textTheme.bodyText1!;
return Container(

View file

@ -9,8 +9,9 @@ import 'package:stocks/stock_data.dart' as stock_data;
Element? findElementOfExactWidgetTypeGoingDown(Element node, Type targetType) {
void walker(Element child) {
if (child.widget.runtimeType == targetType)
if (child.widget.runtimeType == targetType) {
throw child;
}
child.visitChildElements(walker);
}
try {

View file

@ -460,12 +460,14 @@ Future<void> verifyDeprecations(String workingDirectory, { int minimumMatches =
for (int lineNumber in linesWithDeprecations) {
try {
final RegExpMatch? startMatch = _deprecationStartPattern.firstMatch(lines[lineNumber]);
if (startMatch == null)
if (startMatch == null) {
throw 'Deprecation notice does not match required pattern.';
}
final String indent = startMatch.namedGroup('indent')!;
lineNumber += 1;
if (lineNumber >= lines.length)
if (lineNumber >= lines.length) {
throw 'Incomplete deprecation notice.';
}
RegExpMatch? versionMatch;
String? message;
do {
@ -477,17 +479,20 @@ Future<void> verifyDeprecations(String workingDirectory, { int minimumMatches =
}
throw 'Deprecation notice does not match required pattern.$possibleReason';
}
if (!lines[lineNumber].startsWith("$indent '"))
if (!lines[lineNumber].startsWith("$indent '")) {
throw 'Unexpected deprecation notice indent.';
}
if (message == null) {
message = messageMatch.namedGroup('message');
final String firstChar = String.fromCharCode(message!.runes.first);
if (firstChar.toUpperCase() != firstChar)
if (firstChar.toUpperCase() != firstChar) {
throw 'Deprecation notice should be a grammatically correct sentence and start with a capital letter; see style guide: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo';
}
}
lineNumber += 1;
if (lineNumber >= lines.length)
if (lineNumber >= lines.length) {
throw 'Incomplete deprecation notice.';
}
versionMatch = _deprecationVersionPattern.firstMatch(lines[lineNumber]);
} while (versionMatch == null);
final int major = int.parse(versionMatch.namedGroup('major')!);
@ -497,20 +502,26 @@ Future<void> verifyDeprecations(String workingDirectory, { int minimumMatches =
// There was a beta release that was mistakenly labeled 3.1.0 without a build.
final bool specialBeta = major == 3 && minor == 1 && patch == 0;
if (!specialBeta && (major > 1 || (major == 1 && minor >= 20))) {
if (!hasBuild)
if (!hasBuild) {
throw 'Deprecation notice does not accurately indicate a beta branch version number; please see https://flutter.dev/docs/development/tools/sdk/releases to find the latest beta build version number.';
}
}
if (!message.endsWith('.') && !message.endsWith('!') && !message.endsWith('?'))
if (!message.endsWith('.') && !message.endsWith('!') && !message.endsWith('?')) {
throw 'Deprecation notice should be a grammatically correct sentence and end with a period.';
if (!lines[lineNumber].startsWith("$indent '"))
}
if (!lines[lineNumber].startsWith("$indent '")) {
throw 'Unexpected deprecation notice indent.';
}
lineNumber += 1;
if (lineNumber >= lines.length)
if (lineNumber >= lines.length) {
throw 'Incomplete deprecation notice.';
if (!lines[lineNumber].contains(_deprecationEndPattern))
}
if (!lines[lineNumber].contains(_deprecationEndPattern)) {
throw 'End of deprecation notice does not match required pattern.';
if (!lines[lineNumber].startsWith('$indent)'))
}
if (!lines[lineNumber].startsWith('$indent)')) {
throw 'Unexpected deprecation notice indent.';
}
} catch (error) {
errors.add('${file.path}:${lineNumber + 1}: $error');
}
@ -569,10 +580,12 @@ Future<int> _verifyNoMissingLicenseForExtension(
final List<String> errors = <String>[];
await for (final File file in _allFiles(workingDirectory, extension, minimumMatches: minimumMatches)) {
final String contents = file.readAsStringSync().replaceAll('\r\n', '\n');
if (contents.isEmpty)
if (contents.isEmpty) {
continue; // let's not go down the /bin/true rabbit hole
if (!contents.startsWith(RegExp(header + licensePattern)))
}
if (!contents.startsWith(RegExp(header + licensePattern))) {
errors.add(file.path);
}
}
// Fail if any errors
if (errors.isNotEmpty) {
@ -679,8 +692,9 @@ Future<void> verifyNoTestImports(String workingDirectory) async {
for (final File file in dartFiles) {
for (final String line in file.readAsLinesSync()) {
final Match? match = _testImportPattern.firstMatch(line);
if (match != null && !_exemptTestImports.contains(match.group(2)))
if (match != null && !_exemptTestImports.contains(match.group(2))) {
errors.add(file.path);
}
}
}
// Fail if any errors
@ -733,8 +747,9 @@ Future<void> verifyNoBadImportsInFlutter(String workingDirectory) async {
for (final String key in dependencyMap.keys) {
for (final String dependency in dependencyMap[key]!) {
if (dependencyMap[dependency] != null)
if (dependencyMap[dependency] != null) {
continue;
}
// Sanity check before performing _deepSearch, to ensure there's no rogue
// dependencies.
final String validFilenames = dependencyMap.keys.map((String name) => '$name.dart').join(', ');
@ -931,8 +946,9 @@ Future<void> verifyNoRuntimeTypeInToString(String workingDirectory) async {
}
}
}
if (problems.isNotEmpty)
if (problems.isNotEmpty) {
exitWithError(problems);
}
}
Future<void> verifyNoTrailingSpaces(String workingDirectory, { int minimumMatches = 4000 }) async {
@ -956,11 +972,13 @@ Future<void> verifyNoTrailingSpaces(String workingDirectory, { int minimumMatche
problems.add('${file.path}:${index + 1}: trailing U+0009 tab character');
}
}
if (lines.isNotEmpty && lines.last == '')
if (lines.isNotEmpty && lines.last == '') {
problems.add('${file.path}:${lines.length}: trailing blank line');
}
}
if (problems.isNotEmpty)
if (problems.isNotEmpty) {
exitWithError(problems);
}
}
String _bullets(String value) => ' * $value';
@ -984,8 +1002,9 @@ Future<void> verifyIssueLinks(String workingDirectory) async {
final Set<String> suggestions = <String>{};
final List<File> files = await _gitFiles(workingDirectory);
for (final File file in files) {
if (path.basename(file.path).endsWith('_test.dart') || path.basename(file.path) == 'analyze.dart')
if (path.basename(file.path).endsWith('_test.dart') || path.basename(file.path) == 'analyze.dart') {
continue; // Skip tests, they're not public-facing.
}
final Uint8List bytes = file.readAsBytesSync();
// We allow invalid UTF-8 here so that binaries don't trip us up.
// There's a separate test in this file that verifies that all text
@ -1087,8 +1106,9 @@ class Hash256 {
@override
bool operator ==(Object other) {
if (other.runtimeType != runtimeType)
if (other.runtimeType != runtimeType) {
return false;
}
return other is Hash256
&& other.a == a
&& other.b == b
@ -1481,8 +1501,9 @@ Future<void> verifyNoBinaries(String workingDirectory, { Set<Hash256>? legacyBin
utf8.decode(bytes);
} on FormatException catch (error) {
final Digest digest = sha256.convert(bytes);
if (!legacyBinaries.contains(Hash256.fromDigest(digest)))
if (!legacyBinaries.contains(Hash256.fromDigest(digest))) {
problems.add('${file.path}:${error.offset}: file is not valid UTF-8');
}
}
}
if (problems.isNotEmpty) {
@ -1506,11 +1527,13 @@ Future<void> verifyNoBinaries(String workingDirectory, { Set<Hash256>? legacyBin
bool _listEquals<T>(List<T> a, List<T> b) {
assert(a != null);
assert(b != null);
if (a.length != b.length)
if (a.length != b.length) {
return false;
}
for (int index = 0; index < a.length; index += 1) {
if (a[index] != b[index])
if (a[index] != b[index]) {
return false;
}
}
return true;
}
@ -1550,38 +1573,51 @@ Stream<File> _allFiles(String workingDirectory, String? extension, { required in
while (pending.isNotEmpty) {
final FileSystemEntity entity = pending.first;
pending.remove(entity);
if (path.extension(entity.path) == '.tmpl')
if (path.extension(entity.path) == '.tmpl') {
continue;
}
if (entity is File) {
if (!gitFileNamesSet.contains(path.canonicalize(entity.absolute.path)))
if (!gitFileNamesSet.contains(path.canonicalize(entity.absolute.path))) {
continue;
if (_isGeneratedPluginRegistrant(entity))
}
if (_isGeneratedPluginRegistrant(entity)) {
continue;
if (path.basename(entity.path) == 'flutter_export_environment.sh')
}
if (path.basename(entity.path) == 'flutter_export_environment.sh') {
continue;
if (path.basename(entity.path) == 'gradlew.bat')
}
if (path.basename(entity.path) == 'gradlew.bat') {
continue;
if (path.basename(entity.path) == '.DS_Store')
}
if (path.basename(entity.path) == '.DS_Store') {
continue;
}
if (extension == null || path.extension(entity.path) == '.$extension') {
matches += 1;
yield entity;
}
} else if (entity is Directory) {
if (File(path.join(entity.path, '.dartignore')).existsSync())
if (File(path.join(entity.path, '.dartignore')).existsSync()) {
continue;
if (path.basename(entity.path) == '.git')
}
if (path.basename(entity.path) == '.git') {
continue;
if (path.basename(entity.path) == '.idea')
}
if (path.basename(entity.path) == '.idea') {
continue;
if (path.basename(entity.path) == '.gradle')
}
if (path.basename(entity.path) == '.gradle') {
continue;
if (path.basename(entity.path) == '.dart_tool')
}
if (path.basename(entity.path) == '.dart_tool') {
continue;
if (path.basename(entity.path) == '.idea')
}
if (path.basename(entity.path) == '.idea') {
continue;
if (path.basename(entity.path) == 'build')
}
if (path.basename(entity.path) == 'build') {
continue;
}
pending.addAll(entity.listSync());
}
}
@ -1830,8 +1866,9 @@ Future<Set<String>> _findFlutterDependencies(String srcPath, List<String> errors
final Set<String> result = <String>{};
for (final String line in file.readAsLinesSync()) {
Match? match = _importPattern.firstMatch(line);
if (match != null)
if (match != null) {
result.add(match.group(2)!);
}
if (checkForMeta) {
match = _importMetaPattern.firstMatch(line);
if (match != null) {
@ -1852,14 +1889,17 @@ Future<Set<String>> _findFlutterDependencies(String srcPath, List<String> errors
}
List<T>? _deepSearch<T>(Map<T, Set<T>> map, T start, [ Set<T>? seen ]) {
if (map[start] == null)
if (map[start] == null) {
return null; // We catch these separately.
}
for (final T key in map[start]!) {
if (key == start)
if (key == start) {
continue; // we catch these separately
if (seen != null && seen.contains(key))
}
if (seen != null && seen.contains(key)) {
return <T>[start, key];
}
final List<T>? result = _deepSearch<T>(
map,
key,
@ -1874,8 +1914,9 @@ List<T>? _deepSearch<T>(Map<T, Set<T>> map, T start, [ Set<T>? seen ]) {
// For example a->b->a, rather than c->a->b->a.
// Since we visit every node, we know the shortest chains are those
// that start and end on the loop.
if (result.first == result.last)
if (result.first == result.last) {
return result;
}
}
}
return null;

View file

@ -396,12 +396,14 @@ class _SnippetChecker {
}
}
}
if (!silent)
if (!silent) {
print('Found ${sections.length} snippet code blocks');
}
for (final _Section section in sections) {
final String path = _writeSection(section).path;
if (sectionMap != null)
if (sectionMap != null) {
sectionMap[path] = section;
}
}
}
@ -448,8 +450,9 @@ class _SnippetChecker {
/// Invokes the analyzer on the given [directory] and returns the stdout.
int _runAnalyzer(Directory directory, {bool silent = true, required List<String> output}) {
if (!silent)
if (!silent) {
print('Starting analysis of code snippets.');
}
_createConfigurationFiles(directory);
final ProcessResult result = Process.runSync(
_flutter,
@ -598,8 +601,9 @@ class _SnippetChecker {
exitCode = 0;
}
if (exitCode == 0) {
if (!silent)
if (!silent) {
print('No analysis errors in snippets!');
}
assert(analysisErrors.isEmpty);
}
return _AnalysisResult(exitCode, analysisErrors);
@ -633,17 +637,19 @@ class _SnippetChecker {
// Each section of the dart code that is either split by a blank line, or with '// ...' is
// treated as a separate code block.
if (block[index] == '' || block[index] == '// ...') {
if (subline == null)
if (subline == null) {
throw _SnippetCheckerException('${_Line(filename: line.filename, line: line.line + index, indent: line.indent)}: '
'Unexpected blank line or "// ..." line near start of subblock in snippet code.');
}
subblocks += 1;
subsections.add(_processBlock(subline, buffer));
buffer.clear();
assert(buffer.isEmpty);
subline = null;
} else if (block[index].startsWith('// ')) {
if (buffer.length > 1) // don't include leading comments
if (buffer.length > 1) {
buffer.add('/${block[index]}'); // so that it doesn't start with "// " and get caught in this again
}
} else {
subline ??= _Line(
code: block[index],

View file

@ -133,10 +133,12 @@ class FlutterCompactFormatter {
originalResult.errorMessage = error;
originalResult.stackTrace = stackTrace;
} else {
if (error != null)
if (error != null) {
stderr.writeln(error);
if (stackTrace != null)
}
if (stackTrace != null) {
stderr.writeln(stackTrace);
}
}
break;
case 'print':

View file

@ -39,12 +39,15 @@ final String engineVersionFile = path.join(flutterRoot, 'bin', 'internal', 'engi
final String flutterPluginsVersionFile = path.join(flutterRoot, 'bin', 'internal', 'flutter_plugins.version');
String get platformFolderName {
if (Platform.isWindows)
if (Platform.isWindows) {
return 'windows-x64';
if (Platform.isMacOS)
}
if (Platform.isMacOS) {
return 'darwin-x64';
if (Platform.isLinux)
}
if (Platform.isLinux) {
return 'linux-x64';
}
throw UnsupportedError('The platform ${Platform.operatingSystem} is not supported by this script.');
}
final String flutterTester = path.join(flutterRoot, 'bin', 'cache', 'artifacts', 'engine', platformFolderName, 'flutter_tester$exe');
@ -187,8 +190,9 @@ Future<void> main(List<String> args) async {
}
}
flutterTestArgs.removeWhere((String arg) => removeArgs.contains(arg));
if (Platform.environment.containsKey(CIRRUS_TASK_NAME))
if (Platform.environment.containsKey(CIRRUS_TASK_NAME)) {
print('Running task: ${Platform.environment[CIRRUS_TASK_NAME]}');
}
print('' * 80);
await selectShard(<String, ShardRunner>{
'add_to_app_life_cycle_tests': _runAddToAppLifeCycleTests,
@ -327,8 +331,9 @@ Future<void> _runTestHarnessTests() async {
// Verify that we correctly generated the version file.
final String? versionError = await verifyVersion(File(path.join(flutterRoot, 'version')));
if (versionError != null)
if (versionError != null) {
exitWithError(<String>[versionError]);
}
}
final String _toolsPath = path.join(flutterRoot, 'packages', 'flutter_tools');
@ -1748,8 +1753,9 @@ Future<void> _runFlutterTest(String workingDirectory, {
];
final bool shouldProcessOutput = useFlutterTestFormatter && !expectFailure && !options.contains('--coverage');
if (shouldProcessOutput)
if (shouldProcessOutput) {
args.add('--machine');
}
if (script != null) {
final String fullScriptPath = path.join(workingDirectory, script);
@ -1757,8 +1763,9 @@ Future<void> _runFlutterTest(String workingDirectory, {
print('${red}Could not find test$reset: $green$fullScriptPath$reset');
print('Working directory: $cyan$workingDirectory$reset');
print('Script: $green$script$reset');
if (!printOutput)
if (!printOutput) {
print('This is one of the tests that does not normally print output.');
}
exit(1);
}
args.add(script);
@ -1782,8 +1789,9 @@ Future<void> _runFlutterTest(String workingDirectory, {
if (outputChecker != null) {
final String? message = outputChecker(result);
if (message != null)
if (message != null) {
exitWithError(<String>[message]);
}
}
return;
}
@ -1862,12 +1870,15 @@ Future<String?> verifyVersion(File file) async {
final RegExp pattern = RegExp(
r'^(\d+)\.(\d+)\.(\d+)((-\d+\.\d+)?\.pre(\.\d+)?)?$');
final String version = await file.readAsString();
if (!file.existsSync())
if (!file.existsSync()) {
return 'The version logic failed to create the Flutter version file.';
if (version == '0.0.0-unknown')
}
if (version == '0.0.0-unknown') {
return 'The version logic failed to determine the Flutter version.';
if (!version.contains(pattern))
}
if (!version.contains(pattern)) {
return 'The version logic generated an invalid version string: "$version".';
}
return null;
}

View file

@ -59,8 +59,9 @@ String get clock {
String prettyPrintDuration(Duration duration) {
String result = '';
final int minutes = duration.inMinutes;
if (minutes > 0)
if (minutes > 0) {
result += '${minutes}min ';
}
final int seconds = duration.inSeconds - minutes * 60;
final int milliseconds = duration.inMilliseconds - (seconds * 1000 + minutes * 60 * 1000);
result += '$seconds.${milliseconds.toString().padLeft(3, "0")}s';

View file

@ -8,6 +8,5 @@ analyzer:
linter:
rules:
avoid_catches_without_on_clauses: true
curly_braces_in_flow_control_structures: true
prefer_relative_imports: true
unawaited_futures: true

View file

@ -31,42 +31,54 @@ class CustomerTest {
test.add(line.substring(5));
} else if (line.startsWith('test.windows=')) {
hasTests = true;
if (Platform.isWindows)
if (Platform.isWindows) {
test.add(line.substring(13));
}
} else if (line.startsWith('test.macos=')) {
hasTests = true;
if (Platform.isMacOS)
if (Platform.isMacOS) {
test.add(line.substring(11));
}
} else if (line.startsWith('test.linux=')) {
hasTests = true;
if (Platform.isLinux)
if (Platform.isLinux) {
test.add(line.substring(11));
}
} else if (line.startsWith('test.posix=')) {
hasTests = true;
if (Platform.isLinux || Platform.isMacOS)
if (Platform.isLinux || Platform.isMacOS) {
test.add(line.substring(11));
}
} else {
throw FormatException('${errorPrefix}Unexpected directive:\n$line');
}
}
if (contacts.isEmpty)
if (contacts.isEmpty) {
throw FormatException('${errorPrefix}No contacts specified. At least one contact e-mail address must be specified.');
for (final String email in contacts) {
if (!email.contains(_email) || email.endsWith('@example.com'))
throw FormatException('${errorPrefix}The following e-mail address appears to be an invalid e-mail address: $email');
}
if (fetch.isEmpty)
for (final String email in contacts) {
if (!email.contains(_email) || email.endsWith('@example.com')) {
throw FormatException('${errorPrefix}The following e-mail address appears to be an invalid e-mail address: $email');
}
}
if (fetch.isEmpty) {
throw FormatException('${errorPrefix}No "fetch" directives specified. Two lines are expected: "git clone https://github.com/USERNAME/REPOSITORY.git tests" and "git -C tests checkout HASH".');
if (fetch.length < 2)
}
if (fetch.length < 2) {
throw FormatException('${errorPrefix}Only one "fetch" directive specified. Two lines are expected: "git clone https://github.com/USERNAME/REPOSITORY.git tests" and "git -C tests checkout HASH".');
if (!fetch[0].contains(_fetch1))
}
if (!fetch[0].contains(_fetch1)) {
throw FormatException('${errorPrefix}First "fetch" directive does not match expected pattern (expected "git clone https://github.com/USERNAME/REPOSITORY.git tests").');
if (!fetch[1].contains(_fetch2))
}
if (!fetch[1].contains(_fetch2)) {
throw FormatException('${errorPrefix}Second "fetch" directive does not match expected pattern (expected "git -C tests checkout HASH").');
if (update.isEmpty)
}
if (update.isEmpty) {
throw FormatException('${errorPrefix}No "update" directives specified. At least one directory must be specified. (It can be "." to just upgrade the root of the repository.)');
if (!hasTests)
}
if (!hasTests) {
throw FormatException('${errorPrefix}No "test" directives specified. At least one command must be specified to run tests.');
}
return CustomerTest._(
List<String>.unmodifiable(contacts),
List<String>.unmodifiable(fetch),

View file

@ -17,8 +17,9 @@ Future<bool> runTests({
int shardIndex = 0,
required List<File> files,
}) async {
if (verbose)
if (verbose) {
print('Starting run_tests.dart...');
}
// Best attempt at evenly splitting tests among the shards
final List<File> shardedFiles = <File>[];
@ -46,18 +47,21 @@ Future<bool> runTests({
} else {
print('Tests:');
}
for (final File file in shardedFiles)
for (final File file in shardedFiles) {
print(file.path);
}
}
print('');
for (final File file in shardedFiles) {
if (verbose)
if (verbose) {
print('Processing ${file.path}...');
}
void printHeader() {
if (!verbose)
if (!verbose) {
print('Processing ${file.path}...');
}
}
void failure(String message) {
@ -82,8 +86,9 @@ Future<bool> runTests({
bool success = true;
final Directory checkout = Directory.systemTemp.createTempSync('flutter_customer_testing.${path.basenameWithoutExtension(file.path)}.');
if (verbose)
if (verbose) {
print('Created temporary directory: ${checkout.path}');
}
try {
assert(instructions.fetch.isNotEmpty);
for (final String fetchCommand in instructions.fetch) {
@ -105,8 +110,9 @@ Future<bool> runTests({
final Directory customerRepo = Directory(path.join(checkout.path, 'tests'));
for (final Directory updateDirectory in instructions.update) {
final Directory resolvedUpdateDirectory = Directory(path.join(customerRepo.path, updateDirectory.path));
if (verbose)
if (verbose) {
print('Updating code in ${resolvedUpdateDirectory.path}...');
}
if (!File(path.join(resolvedUpdateDirectory.path, 'pubspec.yaml')).existsSync()) {
failure('The directory ${updateDirectory.path}, which was specified as an update directory, does not contain a "pubspec.yaml" file.');
success = false;
@ -124,11 +130,13 @@ Future<bool> runTests({
}
}
if (success) {
if (verbose)
if (verbose) {
print('Running tests...');
}
for (int iteration = 0; iteration < repeat; iteration += 1) {
if (verbose && repeat > 1)
if (verbose && repeat > 1) {
print('Round ${iteration + 1} of $repeat.');
}
for (final String testCommand in instructions.tests) {
testCount += 1;
success = await shell(testCommand, customerRepo, verbose: verbose, failedCallback: printHeader);
@ -138,13 +146,15 @@ Future<bool> runTests({
}
}
}
if (verbose && success)
if (verbose && success) {
print('Tests finished.');
}
}
}
} finally {
if (verbose)
if (verbose) {
print('Deleting temporary directory...');
}
try {
checkout.deleteSync(recursive: true);
} on FileSystemException {
@ -155,8 +165,9 @@ Future<bool> runTests({
final String s = instructions.contacts.length == 1 ? '' : 's';
print('Contact$s: ${instructions.contacts.join(", ")}');
}
if (verbose || !success)
if (verbose || !success) {
print('');
}
}
if (failures > 0) {
final String s = failures == 1 ? '' : 's';
@ -170,8 +181,9 @@ Future<bool> runTests({
final RegExp _spaces = RegExp(r' +');
Future<bool> shell(String command, Directory directory, { bool verbose = false, bool silentFailure = false, void Function()? failedCallback }) async {
if (verbose)
if (verbose) {
print('>> $command');
}
Process process;
if (Platform.isWindows) {
process = await Process.start('CMD.EXE', <String>['/S', '/C', command], workingDirectory: directory.path);
@ -183,11 +195,13 @@ Future<bool> shell(String command, Directory directory, { bool verbose = false,
utf8.decoder.bind(process.stdout).transform(const LineSplitter()).listen(verbose ? printLog : output.add);
utf8.decoder.bind(process.stderr).transform(const LineSplitter()).listen(verbose ? printLog : output.add);
final bool success = await process.exitCode == 0;
if (success || silentFailure)
if (success || silentFailure) {
return success;
}
if (!verbose) {
if (failedCallback != null)
if (failedCallback != null) {
failedCallback();
}
print('>> $command');
output.forEach(printLog);
}

View file

@ -92,8 +92,9 @@ Future<bool> run(List<String> arguments) async {
if (help || repeat == null || files.isEmpty || numberShards == null || numberShards <= 0 || shardIndex == null || shardIndex < 0) {
printHelp();
if (verbose) {
if (repeat == null)
if (repeat == null) {
print('Error: Could not parse repeat count ("${parsedArguments['repeat']}")');
}
if (numberShards == null) {
print('Error: Could not parse shards count ("${parsedArguments['shards']}")');
} else if (numberShards < 1) {
@ -121,8 +122,9 @@ Future<bool> run(List<String> arguments) async {
return false;
}
if (files.length < numberShards)
if (files.length < numberShards) {
print('Warning: There are more shards than tests. Some shards will not run any tests.');
}
return runTests(
repeat: repeat,

View file

@ -19,8 +19,9 @@ Future<void> main() async {
section('Find Java');
final String? javaHome = await findJavaHome();
if (javaHome == null)
if (javaHome == null) {
return TaskResult.failure('Could not find Java');
}
print('\nUsing JAVA_HOME=$javaHome');
section('Create project');

View file

@ -19,8 +19,9 @@ Future<void> main() async {
section('Find Java');
final String? javaHome = await findJavaHome();
if (javaHome == null)
if (javaHome == null) {
return TaskResult.failure('Could not find Java');
}
print('\nUsing JAVA_HOME=$javaHome');
final Directory tempDir = Directory.systemTemp.createTempSync('flutter_module_test.');

View file

@ -42,8 +42,9 @@ class BackButtonMemoryTest extends MemoryTest {
prepareForNextMessage('READY');
final String output = await device!.shellEval('am', <String>['start', '-n', '$packageName/$activityName']);
print('adb shell am start: $output');
if (output.contains('Error'))
if (output.contains('Error')) {
fail('unable to launch activity');
}
await receivedNextMessage;
// Wait for the Flutter app to settle (e.g. run GCs).

View file

@ -90,12 +90,15 @@ Future<int> runTest({bool coverage = false, bool noPub = false}) async {
});
final int result = await analysis.exitCode;
clock.stop();
if (result != 0)
if (result != 0) {
throw Exception('flutter test failed with exit code $result');
if (badLines > 0)
}
if (badLines > 0) {
throw Exception('flutter test rendered unexpected output ($badLines bad lines)');
if (step != TestStep.testPassed)
}
if (step != TestStep.testPassed) {
throw Exception('flutter test did not finish (only reached step $step)');
}
print('elapsed time: ${clock.elapsedMilliseconds}ms');
return clock.elapsedMilliseconds;
}

View file

@ -258,19 +258,22 @@ Future<void> main() async {
]);
});
if (result.exitCode == 0)
if (result.exitCode == 0) {
throw failure(
'Gradle did not exit with error as expected', result);
}
String output = '${result.stdout}\n${result.stderr}';
if (output.contains('GradleException') ||
output.contains('Failed to notify') ||
output.contains('at org.gradle'))
output.contains('at org.gradle')) {
throw failure(
'Gradle output should not contain stacktrace', result);
if (!output.contains('Build failed'))
}
if (!output.contains('Build failed')) {
throw failure(
'Gradle output should contain a readable error message',
result);
}
section('flutter build apk on build script with error');
await project.introduceError();
@ -280,18 +283,21 @@ Future<void> main() async {
'--release',
]);
});
if (result.exitCode == 0)
if (result.exitCode == 0) {
throw failure(
'flutter build apk should fail when Gradle does', result);
}
output = '${result.stdout}\n${result.stderr}';
if (!output.contains('Build failed'))
if (!output.contains('Build failed')) {
throw failure(
'flutter build apk output should contain a readable Gradle error message',
result);
if (hasMultipleOccurrences(output, 'Build failed'))
}
if (hasMultipleOccurrences(output, 'Build failed')) {
throw failure(
'flutter build apk should not invoke Gradle repeatedly on error',
result);
}
});
await runProjectTest((FlutterProject project) async {
@ -303,12 +309,14 @@ Future<void> main() async {
'--release',
]);
});
if (result.exitCode == 0)
if (result.exitCode == 0) {
throw failure(
'Gradle did not exit with error as expected', result);
}
final String output = '${result.stdout}\n${result.stderr}';
if (!output.contains('No file or variants found for asset: lib/gallery/example_code.dart.'))
if (!output.contains('No file or variants found for asset: lib/gallery/example_code.dart.')) {
throw failure(output, result);
}
});
return TaskResult.success(null);

View file

@ -23,8 +23,9 @@ Future<void> main() async {
section('Find Java');
final String? javaHome = await findJavaHome();
if (javaHome == null)
if (javaHome == null) {
return TaskResult.failure('Could not find Java');
}
print('\nUsing JAVA_HOME=$javaHome');
section('Create Flutter module project');

View file

@ -26,8 +26,9 @@ Future<void> main() async {
section('Find Java');
final String? javaHome = await findJavaHome();
if (javaHome == null)
if (javaHome == null) {
return TaskResult.failure('Could not find Java');
}
print('\nUsing JAVA_HOME=$javaHome');
section('Create Flutter module project');

View file

@ -66,8 +66,9 @@ void main() {
});
unawaited(run.exitCode.then<void>((int exitCode) { ok = false; }));
await Future.any<dynamic>(<Future<dynamic>>[ ready.future, run.exitCode ]);
if (!ok)
if (!ok) {
throw 'Failed to run test app.';
}
print('drive: starting...');
final Process drive = await startProcess(
path.join(flutterDirectory.path, 'bin', 'flutter'),
@ -90,11 +91,13 @@ void main() {
await flutter('install', options: <String>[
'--uninstall-only',
]);
if (result != 0)
if (result != 0) {
throw 'Failed to drive test app (exit code $result).';
}
result = await run.exitCode;
if (result != 0)
if (result != 0) {
throw 'Received unexpected exit code $result from run process.';
}
});
return TaskResult.success(null);
});

View file

@ -52,8 +52,9 @@ void main() {
});
unawaited(run.exitCode.then<void>((int exitCode) { ok = false; }));
await Future.any<dynamic>(<Future<dynamic>>[ ready.future, run.exitCode ]);
if (!ok)
if (!ok) {
throw 'Failed to run test app.';
}
final VmService client = await vmServiceConnectUri('ws://localhost:$vmServicePort/ws');
final VM vm = await client.getVM();
@ -114,14 +115,16 @@ void main() {
run.stdin.write('q');
final int result = await run.exitCode;
if (result != 0)
if (result != 0) {
throw 'Received unexpected exit code $result from run process.';
}
});
return TaskResult.success(null);
});
}
void expect(bool value) {
if (!value)
if (!value) {
throw 'failed assertion in service extensions test';
}
}

View file

@ -11,7 +11,7 @@ Future<void> main() async {
deviceOperatingSystem = DeviceOperatingSystem.fake;
await task(() async {
final Device device = await devices.workingDevice;
if (device.deviceId == 'FAKE_SUCCESS')
if (device.deviceId == 'FAKE_SUCCESS') {
return TaskResult.success(<String, dynamic>{
'metric1': 42,
'metric2': 123,
@ -20,7 +20,8 @@ Future<void> main() async {
'metric1',
'metric2',
]);
else
} else {
return TaskResult.failure('Failed');
}
});
}

View file

@ -36,35 +36,46 @@ final RegExp dartVersionPattern = RegExp(r'// *@dart *= *(\d+).(\d+)');
final Version firstNullSafeDartVersion = Version(2, 12, 0);
Future<double> findCostsForFile(File file) async {
if (path.extension(file.path) == '.py')
if (path.extension(file.path) == '.py') {
return pythonCost;
}
if (path.extension(file.path) != '.dart' &&
path.extension(file.path) != '.yaml' &&
path.extension(file.path) != '.sh')
path.extension(file.path) != '.sh') {
return 0.0;
}
final bool isTest = file.path.endsWith('_test.dart');
final bool isDart = file.path.endsWith('.dart');
double total = 0.0;
for (final String line in await file.readAsLines()) {
if (line.contains(todoPattern))
if (line.contains(todoPattern)) {
total += todoCost;
if (line.contains(ignorePattern))
}
if (line.contains(ignorePattern)) {
total += ignoreCost;
if (line.contains(ignoreForFilePattern))
}
if (line.contains(ignoreForFilePattern)) {
total += ignoreForFileCost;
if (!isTest && line.contains(asDynamicPattern))
}
if (!isTest && line.contains(asDynamicPattern)) {
total += asDynamicCost;
if (line.contains(deprecationPattern))
}
if (line.contains(deprecationPattern)) {
total += deprecationCost;
if (line.contains(legacyDeprecationPattern))
}
if (line.contains(legacyDeprecationPattern)) {
total += legacyDeprecationCost;
if (isTest && line.contains('skip:') && !line.contains('[intended]'))
}
if (isTest && line.contains('skip:') && !line.contains('[intended]')) {
total += skipCost;
if (isDart && isOptingOutOfNullSafety(line))
}
if (isDart && isOptingOutOfNullSafety(line)) {
total += fileNullSafetyMigrationCost;
}
}
if (path.basename(file.path) == 'pubspec.yaml' && !packageIsNullSafe(file))
if (path.basename(file.path) == 'pubspec.yaml' && !packageIsNullSafe(file)) {
total += packageNullSafetyMigrationCost;
}
return total;
}
@ -89,12 +100,14 @@ bool packageIsNullSafe(File file) {
}
Future<int> findGlobalsForFile(File file) async {
if (path.extension(file.path) != '.dart')
if (path.extension(file.path) != '.dart') {
return 0;
}
int total = 0;
for (final String line in await file.readAsLines()) {
if (line.contains(globalsPattern))
if (line.contains(globalsPattern)) {
total += 1;
}
}
return total;
}
@ -106,11 +119,13 @@ Future<double> findCostsForRepo() async {
workingDirectory: flutterDirectory.path,
);
double total = 0.0;
await for (final String entry in git.stdout.transform<String>(utf8.decoder).transform<String>(const LineSplitter()))
await for (final String entry in git.stdout.transform<String>(utf8.decoder).transform<String>(const LineSplitter())) {
total += await findCostsForFile(File(path.join(flutterDirectory.path, entry)));
}
final int gitExitCode = await git.exitCode;
if (gitExitCode != 0)
if (gitExitCode != 0) {
throw Exception('git exit with unexpected error code $gitExitCode');
}
return total;
}
@ -121,11 +136,13 @@ Future<int> findGlobalsForTool() async {
workingDirectory: flutterDirectory.path,
);
int total = 0;
await for (final String entry in git.stdout.transform<String>(utf8.decoder).transform<String>(const LineSplitter()))
await for (final String entry in git.stdout.transform<String>(utf8.decoder).transform<String>(const LineSplitter())) {
total += await findGlobalsForFile(File(path.join(flutterDirectory.path, entry)));
}
final int gitExitCode = await git.exitCode;
if (gitExitCode != 0)
if (gitExitCode != 0) {
throw Exception('git exit with unexpected error code $gitExitCode');
}
return total;
}
@ -135,8 +152,9 @@ Future<int> countDependencies() async {
options: <String>['--transitive-closure'],
)).split('\n');
final int count = lines.where((String line) => line.contains('->')).length;
if (count < 2) // we'll always have flutter and flutter_test, at least...
if (count < 2) {
throw Exception('"flutter update-packages --transitive-closure" returned bogus output:\n${lines.join("\n")}');
}
return count;
}
@ -146,8 +164,9 @@ Future<int> countConsumerDependencies() async {
options: <String>['--transitive-closure', '--consumer-only'],
)).split('\n');
final int count = lines.where((String line) => line.contains('->')).length;
if (count < 2) // we'll always have flutter and flutter_test, at least...
if (count < 2) {
throw Exception('"flutter update-packages --transitive-closure" returned bogus output:\n${lines.join("\n")}');
}
return count;
}

View file

@ -410,8 +410,9 @@ Future<void> _runGradleTask({
print('stderr:');
print(result.stderr);
}
if (result.exitCode != 0)
if (result.exitCode != 0) {
throw 'Gradle exited with error';
}
}
Future<ProcessResult> _resultOfGradleTask({
@ -422,8 +423,9 @@ Future<ProcessResult> _resultOfGradleTask({
section('Find Java');
final String? javaHome = await findJavaHome();
if (javaHome == null)
if (javaHome == null) {
throw TaskResult.failure('Could not find Java');
}
print('\nUsing JAVA_HOME=$javaHome');

View file

@ -252,8 +252,9 @@ class AndroidDeviceDiscovery implements DeviceDiscovery {
.map<AndroidDevice>((String id) => AndroidDevice(deviceId: id))
.toList();
if (allDevices.isEmpty)
if (allDevices.isEmpty) {
throw const DeviceException('No Android devices detected');
}
if (cpu != null) {
for (final AndroidDevice device in allDevices) {
@ -268,8 +269,9 @@ class AndroidDeviceDiscovery implements DeviceDiscovery {
_workingDevice = allDevices[math.Random().nextInt(allDevices.length)];
}
if (_workingDevice == null)
if (_workingDevice == null) {
throw const DeviceException('Cannot find a suitable Android device');
}
print('Device chosen: $_workingDevice');
}
@ -300,11 +302,13 @@ class AndroidDeviceDiscovery implements DeviceDiscovery {
final List<String> results = <String>[];
for (final String line in output) {
// Skip lines like: * daemon started successfully *
if (line.startsWith('* daemon '))
if (line.startsWith('* daemon ')) {
continue;
}
if (line.startsWith('List of devices'))
if (line.startsWith('List of devices')) {
continue;
}
if (_kDeviceRegex.hasMatch(line)) {
final Match match = _kDeviceRegex.firstMatch(line)!;
@ -551,15 +555,17 @@ class AndroidDevice extends Device {
/// Wake up the device if it is not awake using [togglePower].
@override
Future<void> wakeUp() async {
if (!(await isAwake()))
if (!(await isAwake())) {
await togglePower();
}
}
/// Send the device to sleep mode if it is not asleep using [togglePower].
@override
Future<void> sendToSleep() async {
if (!(await isAsleep()))
if (!(await isAsleep())) {
await togglePower();
}
}
/// Sends `KEYCODE_HOME` (3), which causes the device to go to the home screen.
@ -840,8 +846,9 @@ class IosDeviceDiscovery implements DeviceDiscovery {
.map<IosDevice>((String id) => IosDevice(deviceId: id))
.toList();
if (allDevices.isEmpty)
if (allDevices.isEmpty) {
throw const DeviceException('No iOS devices detected');
}
// TODO(yjbanov): filter out and warn about those with low battery level
_workingDevice = allDevices[math.Random().nextInt(allDevices.length)];
@ -1211,8 +1218,9 @@ String get adbPath {
final String adbPath = path.join(androidHome, 'platform-tools/adb');
if (!canRun(adbPath))
if (!canRun(adbPath)) {
throw DeviceException('adb not found at: $adbPath');
}
return path.absolute(adbPath);
}

View file

@ -46,8 +46,9 @@ bool _isTaskRegistered = false;
/// If no `processManager` is provided, a default [LocalProcessManager] is created
/// for the task.
Future<TaskResult> task(TaskFunction task, { ProcessManager? processManager }) async {
if (_isTaskRegistered)
if (_isTaskRegistered) {
throw StateError('A task is already registered');
}
_isTaskRegistered = true;
processManager ??= const LocalProcessManager();
@ -163,8 +164,9 @@ class _TaskRunner {
}
Future<TaskResult> futureResult = _performTask();
if (taskTimeout != null)
if (taskTimeout != null) {
futureResult = futureResult.timeout(taskTimeout);
}
result = await futureResult;
} finally {
@ -241,8 +243,9 @@ class _TaskRunner {
/// Causes the Dart VM to stay alive until a request to run the task is
/// received via the VM service protocol.
void keepVmAliveUntilTaskRunRequested() {
if (_taskStarted)
if (_taskStarted) {
throw StateError('Task already started.');
}
// Merely creating this port object will cause the VM to stay alive and keep
// the VM service server running until the port is disposed of.
@ -280,8 +283,9 @@ class _TaskRunner {
// are catching errors coming from arbitrary (and untrustworthy) task
// code. Our goal is to convert the failure into a readable message.
// Propagating it further is not useful.
if (!completer.isCompleted)
if (!completer.isCompleted) {
completer.complete(TaskResult.failure(message));
}
});
return completer.future;
}

View file

@ -156,8 +156,9 @@ Future<TaskResult> runTask(
}) async {
final String taskExecutable = 'bin/tasks/$taskName.dart';
if (!file(taskExecutable).existsSync())
if (!file(taskExecutable).existsSync()) {
throw 'Executable Dart file not found: $taskExecutable';
}
final Process runner = await startProcess(
dartBin,
@ -190,8 +191,9 @@ Future<TaskResult> runTask(
.listen((String line) {
if (!uri.isCompleted) {
final Uri? serviceUri = parseServiceUri(line, prefix: RegExp('(Observatory|The Dart VM service is) listening on '));
if (serviceUri != null)
if (serviceUri != null) {
uri.complete(serviceUri);
}
}
if (!silent) {
stdout.writeln('[$taskName] [STDOUT] $line');
@ -255,12 +257,14 @@ Future<ConnectionResult> _connectToRunnerIsolate(Uri vmServiceUri) async {
}
final IsolateRef isolate = vm.isolates!.first;
final Response response = await client.callServiceExtension('ext.cocoonRunnerReady', isolateId: isolate.id);
if (response.json!['response'] != 'ready')
if (response.json!['response'] != 'ready') {
throw 'not ready yet';
}
return ConnectionResult(client, isolate);
} catch (error) {
if (stopwatch.elapsed > const Duration(seconds: 10))
if (stopwatch.elapsed > const Duration(seconds: 10)) {
print('VM service still not ready after ${stopwatch.elapsed}: $error\nContinuing to retry...');
}
await Future<void>.delayed(const Duration(milliseconds: 50));
}
}

View file

@ -126,14 +126,15 @@ void copy(File sourceFile, Directory targetDirectory, {String? name}) {
}
void recursiveCopy(Directory source, Directory target) {
if (!target.existsSync())
if (!target.existsSync()) {
target.createSync();
}
for (final FileSystemEntity entity in source.listSync(followLinks: false)) {
final String name = path.basename(entity.path);
if (entity is Directory && !entity.path.contains('.dart_tool'))
if (entity is Directory && !entity.path.contains('.dart_tool')) {
recursiveCopy(entity, Directory(path.join(target.path, name)));
else if (entity is File) {
} else if (entity is File) {
final File dest = File(path.join(target.path, name));
dest.writeAsBytesSync(entity.readAsBytesSync());
// Preserve executable bit
@ -194,8 +195,9 @@ void section(String title) {
title = '╡ ••• $title ••• ╞';
final String line = '' * math.max((80 - title.length) ~/ 2, 2);
output = '$line$title$line';
if (output.length == 79)
if (output.length == 79) {
output += '';
}
}
print('\n\n$output\n');
}
@ -209,10 +211,12 @@ Future<String> getDartVersion() async {
// Dart VM version: 1.17.0-dev.2.0 (Tue May 3 12:14:52 2016) on "macos_x64"
// to:
// 1.17.0-dev.2.0
if (version.contains('('))
if (version.contains('(')) {
version = version.substring(0, version.indexOf('(')).trim();
if (version.contains(':'))
}
if (version.contains(':')) {
version = version.substring(version.indexOf(':') + 1).trim();
}
return version.replaceAll('"', "'");
}
@ -295,8 +299,9 @@ Future<Process> startProcess(
}
Future<void> forceQuitRunningProcesses() async {
if (_runningProcesses.isEmpty)
if (_runningProcesses.isEmpty) {
return;
}
// Give normally quitting processes a chance to report their exit code.
await Future<void>.delayed(const Duration(seconds: 1));
@ -354,8 +359,9 @@ Future<int> _execute(
);
final int exitCode = await process.exitCode;
if (exitCode != 0 && !canFail)
if (exitCode != 0 && !canFail) {
fail('Executable "$executable" failed with exit code $exitCode.');
}
return exitCode;
}
@ -545,8 +551,9 @@ Future<String?> findJavaHome() async {
'Java binary at: ',
from: await evalFlutter('doctor', options: <String>['-v']),
);
if (hits.isEmpty)
if (hits.isEmpty) {
return null;
}
final String javaBinary = hits.first
.split(': ')
.last;
@ -579,8 +586,9 @@ void cd(dynamic directory) {
throw FileSystemException('Unsupported directory type ${directory.runtimeType}', directory.toString());
}
if (!d.existsSync())
if (!d.existsSync()) {
throw FileSystemException('Cannot cd into directory that does not exist', d.toString());
}
}
Directory get flutterDirectory => Directory.current.parent.parent;
@ -590,15 +598,17 @@ Directory get openpayDirectory => Directory(requireEnvVar('OPENPAY_CHECKOUT_PATH
String requireEnvVar(String name) {
final String? value = Platform.environment[name];
if (value == null)
if (value == null) {
fail('$name environment variable is missing. Quitting.');
}
return value!;
}
T requireConfigProperty<T>(Map<String, dynamic> map, String propertyName) {
if (!map.containsKey(propertyName))
if (!map.containsKey(propertyName)) {
fail('Configuration property not found: $propertyName');
}
final T result = map[propertyName] as T;
return result;
}
@ -634,26 +644,36 @@ void checkNotNull(Object o1,
Object o8 = 1,
Object o9 = 1,
Object o10 = 1]) {
if (o1 == null)
if (o1 == null) {
throw 'o1 is null';
if (o2 == null)
}
if (o2 == null) {
throw 'o2 is null';
if (o3 == null)
}
if (o3 == null) {
throw 'o3 is null';
if (o4 == null)
}
if (o4 == null) {
throw 'o4 is null';
if (o5 == null)
}
if (o5 == null) {
throw 'o5 is null';
if (o6 == null)
}
if (o6 == null) {
throw 'o6 is null';
if (o7 == null)
}
if (o7 == null) {
throw 'o7 is null';
if (o8 == null)
}
if (o8 == null) {
throw 'o8 is null';
if (o9 == null)
}
if (o9 == null) {
throw 'o9 is null';
if (o10 == null)
}
if (o10 == null) {
throw 'o10 is null';
}
}
/// Splits [from] into lines and selects those that contain [pattern].

View file

@ -74,8 +74,9 @@ Future<Map<String, double>> readJsonResults(Process process) {
return;
}
if (jsonStarted && line.contains(jsonPrefix))
if (jsonStarted && line.contains(jsonPrefix)) {
jsonBuf.writeln(line.substring(line.indexOf(jsonPrefix) + jsonPrefix.length));
}
});
process.exitCode.then<void>((int code) async {

View file

@ -288,8 +288,9 @@ TaskFunction createBasicMaterialCompileTest() {
await flutter('create', options: <String>['--template=app', sampleAppName]);
});
if (!sampleDir.existsSync())
if (!sampleDir.existsSync()) {
throw 'Failed to create default Flutter app in ${sampleDir.path}';
}
return CompileTest(sampleDir.path).run();
};
@ -754,8 +755,9 @@ class StartupTest {
final Map<String, dynamic> averageResults = _average(results, iterations);
if (!reportMetrics)
if (!reportMetrics) {
return TaskResult.success(averageResults);
}
return TaskResult.success(averageResults, benchmarkScoreKeys: <String>[
'timeToFirstFrameMicros',
@ -860,8 +862,9 @@ class DevtoolsStartupTest {
device.deviceId,
]);
if (sawLine)
if (sawLine) {
return TaskResult.success(null, benchmarkScoreKeys: <String>[]);
}
return TaskResult.failure('Did not see line "The Flutter DevTools debugger and profiler" in output');
});
}
@ -1401,8 +1404,9 @@ class CompileTest {
// IPAs are created manually, https://flutter.dev/ios-release/
await exec('tar', <String>['-zcf', 'build/app.ipa', appPath]);
releaseSizeInBytes = await file('$cwd/build/app.ipa').length();
if (reportPackageContentSizes)
if (reportPackageContentSizes) {
metrics.addAll(await getSizesFromIosApp(appPath));
}
break;
case DeviceOperatingSystem.android:
case DeviceOperatingSystem.androidArm:
@ -1416,8 +1420,9 @@ class CompileTest {
final String apkPath = '$cwd/build/app/outputs/flutter-apk/app-release.apk';
final File apk = file(apkPath);
releaseSizeInBytes = apk.lengthSync();
if (reportPackageContentSizes)
if (reportPackageContentSizes) {
metrics.addAll(await getSizesFromApk(apkPath));
}
break;
case DeviceOperatingSystem.androidArm64:
options.insert(0, 'apk');
@ -1430,8 +1435,9 @@ class CompileTest {
final String apkPath = '$cwd/build/app/outputs/flutter-apk/app-release.apk';
final File apk = file(apkPath);
releaseSizeInBytes = apk.lengthSync();
if (reportPackageContentSizes)
if (reportPackageContentSizes) {
metrics.addAll(await getSizesFromApk(apkPath));
}
break;
case DeviceOperatingSystem.fake:
throw Exception('Unsupported option for fake devices');
@ -1572,8 +1578,9 @@ class MemoryTest {
final StreamSubscription<String> adb = device!.logcat.listen(
(String data) {
if (data.contains('==== MEMORY BENCHMARK ==== $_nextMessage ===='))
if (data.contains('==== MEMORY BENCHMARK ==== $_nextMessage ====')) {
_receivedNextMessage?.complete();
}
},
);
@ -1764,8 +1771,9 @@ class ReportedDurationTest {
final StreamSubscription<String> adb = device!.logcat.listen(
(String data) {
if (durationPattern.hasMatch(data))
if (durationPattern.hasMatch(data)) {
durationCompleter.complete(int.parse(durationPattern.firstMatch(data)!.group(1)!));
}
},
);
print('launching $project$test on device...');

View file

@ -158,8 +158,9 @@ class CommandArgs {
@override
bool operator==(Object other) {
if (other.runtimeType != CommandArgs)
if (other.runtimeType != CommandArgs) {
return false;
}
return other is CommandArgs
&& other.command == command
&& const ListEquality<String>().equals(other.arguments, arguments)

View file

@ -33,10 +33,11 @@ Future<String> dataHandler(String message) async {
});
completer.complete(json.encode(result));
}
if (SchedulerBinding.instance.hasScheduledFrame)
if (SchedulerBinding.instance.hasScheduledFrame) {
SchedulerBinding.instance.addPostFrameCallback(completeSemantics);
else
} else {
completeSemantics();
}
return completer.future;
}
if (message.contains('setClipboard')) {
@ -48,10 +49,11 @@ Future<String> dataHandler(String message) async {
});
completer.complete('');
}
if (SchedulerBinding.instance.hasScheduledFrame)
if (SchedulerBinding.instance.hasScheduledFrame) {
SchedulerBinding.instance.addPostFrameCallback(completeSetClipboard);
else
} else {
completeSetClipboard();
}
return completer.future;
}
throw UnimplementedError();

View file

@ -187,8 +187,9 @@ class Rect {
@override
bool operator ==(Object other) {
if (other.runtimeType != runtimeType)
if (other.runtimeType != runtimeType) {
return false;
}
return other is Rect
&& other.top == top
&& other.left == left
@ -219,8 +220,9 @@ class Size {
@override
bool operator ==(Object other) {
if (other.runtimeType != runtimeType)
if (other.runtimeType != runtimeType) {
return false;
}
return other is Size
&& other.width == width
&& other.height == height;

View file

@ -201,8 +201,9 @@ class AndroidSemanticsAction {
@override
bool operator ==(Object other) {
if (other.runtimeType != runtimeType)
if (other.runtimeType != runtimeType) {
return false;
}
return other is AndroidSemanticsAction
&& other.id == id;
}

View file

@ -100,53 +100,74 @@ class _AndroidSemanticsMatcher extends Matcher {
@override
Description describe(Description description) {
description.add('AndroidSemanticsNode');
if (text != null)
if (text != null) {
description.add(' with text: $text');
if (contentDescription != null)
}
if (contentDescription != null) {
description.add( 'with contentDescription $contentDescription');
if (className != null)
}
if (className != null) {
description.add(' with className: $className');
if (id != null)
}
if (id != null) {
description.add(' with id: $id');
if (actions != null)
}
if (actions != null) {
description.add(' with actions: $actions');
if (rect != null)
}
if (rect != null) {
description.add(' with rect: $rect');
if (size != null)
}
if (size != null) {
description.add(' with size: $size');
if (isChecked != null)
}
if (isChecked != null) {
description.add(' with flag isChecked: $isChecked');
if (isEditable != null)
}
if (isEditable != null) {
description.add(' with flag isEditable: $isEditable');
if (isEnabled != null)
}
if (isEnabled != null) {
description.add(' with flag isEnabled: $isEnabled');
if (isFocusable != null)
}
if (isFocusable != null) {
description.add(' with flag isFocusable: $isFocusable');
if (isFocused != null)
}
if (isFocused != null) {
description.add(' with flag isFocused: $isFocused');
if (isHeading != null)
}
if (isHeading != null) {
description.add(' with flag isHeading: $isHeading');
if (isPassword != null)
}
if (isPassword != null) {
description.add(' with flag isPassword: $isPassword');
if (isLongClickable != null)
}
if (isLongClickable != null) {
description.add(' with flag isLongClickable: $isLongClickable');
}
return description;
}
@override
bool matches(covariant AndroidSemanticsNode item, Map<Object, Object> matchState) {
if (text != null && text != item.text)
if (text != null && text != item.text) {
return _failWithMessage('Expected text: $text', matchState);
if (contentDescription != null && contentDescription != item.contentDescription)
}
if (contentDescription != null && contentDescription != item.contentDescription) {
return _failWithMessage('Expected contentDescription: $contentDescription', matchState);
if (className != null && className != item.className)
}
if (className != null && className != item.className) {
return _failWithMessage('Expected className: $className', matchState);
if (id != null && id != item.id)
}
if (id != null && id != item.id) {
return _failWithMessage('Expected id: $id', matchState);
if (rect != null && rect != item.getRect())
}
if (rect != null && rect != item.getRect()) {
return _failWithMessage('Expected rect: $rect', matchState);
if (size != null && size != item.getSize())
}
if (size != null && size != item.getSize()) {
return _failWithMessage('Expected size: $size', matchState);
}
if (actions != null) {
final List<AndroidSemanticsAction> itemActions = item.getActions();
if (!unorderedEquals(actions).matches(itemActions, matchState)) {
@ -161,25 +182,34 @@ class _AndroidSemanticsMatcher extends Matcher {
return _failWithMessage('Expected actions: $actionsString\nActual actions: $itemActionsString\nUnexpected: $unexpectedInString\nMissing: $missingInString', matchState);
}
}
if (isChecked != null && isChecked != item.isChecked)
if (isChecked != null && isChecked != item.isChecked) {
return _failWithMessage('Expected isChecked: $isChecked', matchState);
if (isCheckable != null && isCheckable != item.isCheckable)
}
if (isCheckable != null && isCheckable != item.isCheckable) {
return _failWithMessage('Expected isCheckable: $isCheckable', matchState);
if (isEditable != null && isEditable != item.isEditable)
}
if (isEditable != null && isEditable != item.isEditable) {
return _failWithMessage('Expected isEditable: $isEditable', matchState);
if (isEnabled != null && isEnabled != item.isEnabled)
}
if (isEnabled != null && isEnabled != item.isEnabled) {
return _failWithMessage('Expected isEnabled: $isEnabled', matchState);
if (isFocusable != null && isFocusable != item.isFocusable)
}
if (isFocusable != null && isFocusable != item.isFocusable) {
return _failWithMessage('Expected isFocusable: $isFocusable', matchState);
if (isFocused != null && isFocused != item.isFocused)
}
if (isFocused != null && isFocused != item.isFocused) {
return _failWithMessage('Expected isFocused: $isFocused', matchState);
}
// Heading is not available in all Android versions, so match anything if it is not set by the platform
if (isHeading != null && isHeading != item.isHeading && item.isHeading != null)
if (isHeading != null && isHeading != item.isHeading && item.isHeading != null) {
return _failWithMessage('Expected isHeading: $isHeading', matchState);
if (isPassword != null && isPassword != item.isPassword)
}
if (isPassword != null && isPassword != item.isPassword) {
return _failWithMessage('Expected isPassword: $isPassword', matchState);
if (isLongClickable != null && isLongClickable != item.isLongClickable)
}
if (isLongClickable != null && isLongClickable != item.isLongClickable) {
return _failWithMessage('Expected longClickable: $isLongClickable', matchState);
}
return true;
}

View file

@ -47,17 +47,19 @@ void diffActions(StringBuffer diffBuffer, Map<String, dynamic> originalEvent,
final String originalActionName =
getActionName(originalActionMasked, originalEvent['action'] as int);
if (synthesizedActionMasked != originalActionMasked)
if (synthesizedActionMasked != originalActionMasked) {
diffBuffer.write(
'action (expected: $originalActionName actual: $synthesizedActionName) ');
}
if (kPointerActions.contains(originalActionMasked) &&
originalActionMasked == synthesizedActionMasked) {
final int originalPointer = getPointerIdx(originalEvent['action'] as int);
final int synthesizedPointer = getPointerIdx(synthesizedEvent['action'] as int);
if (originalPointer != synthesizedPointer)
if (originalPointer != synthesizedPointer) {
diffBuffer.write(
'pointerIdx (expected: $originalPointer actual: $synthesizedPointer action: $originalActionName ');
}
}
}
@ -123,10 +125,12 @@ void diffMaps(
return;
}
for (final String key in expected.keys) {
if (excludeKeys.contains(key))
if (excludeKeys.contains(key)) {
continue;
if (doublesApproximatelyMatch(expected[key], actual[key]))
}
if (doublesApproximatelyMatch(expected[key], actual[key])) {
continue;
}
if (expected[key] != actual[key]) {
diffBuffer.write(
@ -155,10 +159,11 @@ String getActionName(int actionMasked, int action) {
'BUTTON_PRESS',
'BUTTON_RELEASE',
];
if (actionMasked < actionNames.length)
if (actionMasked < actionNames.length) {
return '${actionNames[actionMasked]}($action)';
else
} else {
return 'ACTION_$actionMasked';
}
}
bool doublesApproximatelyMatch(dynamic a, dynamic b) =>

View file

@ -146,16 +146,19 @@ class MotionEventsBodyState extends State<MotionEventsBody> {
await channel.invokeMethod<void>('stopFlutterViewEvents');
await viewChannel?.invokeMethod<void>('stopTouchEvents');
if (flutterViewEvents.length != embeddedViewEvents.length)
if (flutterViewEvents.length != embeddedViewEvents.length) {
return 'Synthesized ${flutterViewEvents.length} events but the embedded view received ${embeddedViewEvents.length} events';
}
final StringBuffer diff = StringBuffer();
for (int i = 0; i < flutterViewEvents.length; ++i) {
final String currentDiff = diffMotionEvents(flutterViewEvents[i], embeddedViewEvents[i]);
if (currentDiff.isEmpty)
if (currentDiff.isEmpty) {
continue;
if (diff.isNotEmpty)
}
if (diff.isNotEmpty) {
diff.write(', ');
}
diff.write(currentDiff);
}
return diff.toString();
@ -229,8 +232,9 @@ class MotionEventsBodyState extends State<MotionEventsBody> {
case 'onTouch':
final Map<dynamic, dynamic> map = call.arguments as Map<dynamic, dynamic>;
flutterViewEvents.insert(0, map.cast<String, dynamic>());
if (flutterViewEvents.length > kEventsBufferSize)
if (flutterViewEvents.length > kEventsBufferSize) {
flutterViewEvents.removeLast();
}
setState(() {});
break;
}
@ -242,8 +246,9 @@ class MotionEventsBodyState extends State<MotionEventsBody> {
case 'onTouch':
final Map<dynamic, dynamic> map = call.arguments as Map<dynamic, dynamic>;
embeddedViewEvents.insert(0, map.cast<String, dynamic>());
if (embeddedViewEvents.length > kEventsBufferSize)
if (embeddedViewEvents.length > kEventsBufferSize) {
embeddedViewEvents.removeLast();
}
setState(() {});
break;
}
@ -251,9 +256,10 @@ class MotionEventsBodyState extends State<MotionEventsBody> {
}
Widget buildEventTile(BuildContext context, int index) {
if (embeddedViewEvents.length > index)
if (embeddedViewEvents.length > index) {
return TouchEventDiff(
flutterViewEvents[index], embeddedViewEvents[index]);
}
return Text(
'Unmatched event, action: ${flutterViewEvents[index]['action']}');
}

View file

@ -172,10 +172,11 @@ class _TestAppState extends State<TestApp> {
void _executeNextStep() {
setState(() {
if (_step < steps.length)
if (_step < steps.length) {
_result = steps[_step++]();
else
} else {
_result = Future<TestStepResult>.value(TestStepResult.complete);
}
});
}

View file

@ -169,10 +169,11 @@ Future<TestStepResult> _basicMessageToUnknownChannel<T>(
}
String toString(dynamic message) {
if (message is ByteData)
if (message is ByteData) {
return message.buffer
.asUint8List(message.offsetInBytes, message.lengthInBytes)
.toString();
else
} else {
return '$message';
}
}

View file

@ -101,8 +101,9 @@ Future<TestStepResult> resultOfHandshake(
dynamic error,
) async {
assert(message != nothing);
while (received.length < 2)
while (received.length < 2) {
received.add(nothing);
}
TestStatus status;
if (!_deepEquals(messageEcho, message) ||
received.length != 2 ||
@ -127,27 +128,34 @@ Future<TestStepResult> resultOfHandshake(
}
String _toString(dynamic message) {
if (message is ByteData)
if (message is ByteData) {
return message.buffer
.asUint8List(message.offsetInBytes, message.lengthInBytes)
.toString();
else
} else {
return '$message';
}
}
bool _deepEquals(dynamic a, dynamic b) {
if (a == b)
if (a == b) {
return true;
if (a is double && a.isNaN)
}
if (a is double && a.isNaN) {
return b is double && b.isNaN;
if (a is ByteData)
}
if (a is ByteData) {
return b is ByteData && _deepEqualsByteData(a, b);
if (a is List)
}
if (a is List) {
return b is List && _deepEqualsList(a, b);
if (a is Map)
}
if (a is Map) {
return b is Map && _deepEqualsMap(a, b);
if (a is Pair)
}
if (a is Pair) {
return b is Pair && _deepEqualsPair(a, b);
}
return false;
}
@ -159,21 +167,25 @@ bool _deepEqualsByteData(ByteData a, ByteData b) {
}
bool _deepEqualsList(List<dynamic> a, List<dynamic> b) {
if (a.length != b.length)
if (a.length != b.length) {
return false;
}
for (int i = 0; i < a.length; i++) {
if (!_deepEquals(a[i], b[i]))
if (!_deepEquals(a[i], b[i])) {
return false;
}
}
return true;
}
bool _deepEqualsMap(Map<dynamic, dynamic> a, Map<dynamic, dynamic> b) {
if (a.length != b.length)
if (a.length != b.length) {
return false;
}
for (final dynamic key in a.keys) {
if (!b.containsKey(key) || !_deepEquals(a[key], b[key]))
if (!b.containsKey(key) || !_deepEquals(a[key], b[key])) {
return false;
}
}
return true;
}

View file

@ -115,8 +115,9 @@ Press play to produce texture frames.''';
_state = FrameState.initial;
});
} else {
if ((tickCount % (calibrationTickCount ~/ 20)) == 0)
if ((tickCount % (calibrationTickCount ~/ 20)) == 0) {
debugPrint('Calibrating... ${(100.0 * tickCount / calibrationTickCount).floor()}%');
}
}
});
ticker.start();

View file

@ -44,8 +44,9 @@ class _RenderStatusBarPaddingSliver extends RenderSliver {
double _maxHeight;
set maxHeight(double value) {
assert(maxHeight >= 0.0);
if (_maxHeight == value)
if (_maxHeight == value) {
return;
}
_maxHeight = value;
markNeedsLayout();
}
@ -56,8 +57,9 @@ class _RenderStatusBarPaddingSliver extends RenderSliver {
double _scrollFactor;
set scrollFactor(double value) {
assert(scrollFactor >= 1.0);
if (_scrollFactor == value)
if (_scrollFactor == value) {
return;
}
_scrollFactor = value;
markNeedsLayout();
}
@ -390,22 +392,27 @@ class _SnappingScrollPhysics extends ClampingScrollPhysics {
// then snap it there. Similarly if the simulation is headed down past
// midScrollOffset but will not reach zero, then snap it to zero.
final double simulationEnd = simulation.x(double.infinity);
if (simulationEnd >= midScrollOffset)
if (simulationEnd >= midScrollOffset) {
return simulation;
if (dragVelocity > 0.0)
}
if (dragVelocity > 0.0) {
return _toMidScrollOffsetSimulation(offset, dragVelocity);
if (dragVelocity < 0.0)
}
if (dragVelocity < 0.0) {
return _toZeroScrollOffsetSimulation(offset, dragVelocity);
}
} else {
// The user ended the drag with little or no velocity. If they
// didn't leave the offset above midScrollOffset, then
// snap to midScrollOffset if they're more than halfway there,
// otherwise snap to zero.
final double snapThreshold = midScrollOffset / 2.0;
if (offset >= snapThreshold && offset < midScrollOffset)
if (offset >= snapThreshold && offset < midScrollOffset) {
return _toMidScrollOffsetSimulation(offset, dragVelocity);
if (offset > 0.0 && offset < snapThreshold)
}
if (offset > 0.0 && offset < snapThreshold) {
return _toZeroScrollOffsetSimulation(offset, dragVelocity);
}
}
return simulation;
}
@ -439,10 +446,11 @@ class _AnimationDemoHomeState extends State<AnimationDemoHome> {
}
void _handleBackButton(double midScrollOffset) {
if (_scrollController.offset >= midScrollOffset)
if (_scrollController.offset >= midScrollOffset) {
_scrollController.animateTo(0.0, curve: _kScrollCurve, duration: _kScrollDuration);
else
} else {
Navigator.maybePop(context);
}
}
// Only enable paging for the heading when the user has scrolled to midScrollOffset.
@ -478,8 +486,9 @@ class _AnimationDemoHomeState extends State<AnimationDemoHome> {
bool _handlePageNotification(ScrollNotification notification, PageController leader, PageController follower) {
if (notification.depth == 0 && notification is ScrollUpdateNotification) {
selectedIndex.value = leader.page;
if (follower.page != leader.page)
if (follower.page != leader.page) {
follower.position.jumpToWithoutSettling(leader.position.pixels); // ignore: deprecated_member_use
}
}
return false;
}

View file

@ -35,10 +35,12 @@ class FloatToken extends NumberToken {
static double _parse(String stringRep) {
String toParse = stringRep;
if (toParse.startsWith('.'))
if (toParse.startsWith('.')) {
toParse = '0$toParse';
if (toParse.endsWith('.'))
}
if (toParse.endsWith('.')) {
toParse = '${toParse}0';
}
return double.parse(toParse);
}
}
@ -51,8 +53,9 @@ class ResultToken extends NumberToken {
/// floating point number is guaranteed to have at least this many
/// decimal digits of precision.
static num round(num number) {
if (number is int)
if (number is int) {
return number;
}
return double.parse(number.toStringAsPrecision(14));
}
}
@ -330,10 +333,11 @@ class CalcExpression {
// Remove the next number token.
final NumberToken nextNumToken = list.removeAt(0)! as NumberToken;
final num nextNumber = nextNumToken.number;
if (isDivision)
if (isDivision) {
currentValue /= nextNumber;
else
} else {
currentValue *= nextNumber;
}
}
return currentValue;
}

View file

@ -294,23 +294,26 @@ class _BackdropDemoState extends State<BackdropDemo> with SingleTickerProviderSt
// the user must either tap its heading or the backdrop's menu icon.
void _handleDragUpdate(DragUpdateDetails details) {
if (_controller.isAnimating || _controller.status == AnimationStatus.completed)
if (_controller.isAnimating || _controller.status == AnimationStatus.completed) {
return;
}
_controller.value -= details.primaryDelta! / _backdropHeight;
}
void _handleDragEnd(DragEndDetails details) {
if (_controller.isAnimating || _controller.status == AnimationStatus.completed)
if (_controller.isAnimating || _controller.status == AnimationStatus.completed) {
return;
}
final double flingVelocity = details.velocity.pixelsPerSecond.dy / _backdropHeight;
if (flingVelocity < 0.0)
if (flingVelocity < 0.0) {
_controller.fling(velocity: math.max(2.0, -flingVelocity));
else if (flingVelocity > 0.0)
} else if (flingVelocity > 0.0) {
_controller.fling(velocity: math.min(-2.0, -flingVelocity));
else
} else {
_controller.fling(velocity: _controller.value < 0.5 ? -2.0 : 2.0);
}
}
// Stacks a BackdropPanel, which displays the selected category, on top

View file

@ -204,12 +204,15 @@ class _BottomAppBarDemoState extends State<BottomAppBarDemo> {
}
NotchedShape? _selectNotch() {
if (!_showNotch.value!)
if (!_showNotch.value!) {
return null;
if (_fabShape == kCircularFab)
}
if (_fabShape == kCircularFab) {
return const CircularNotchedRectangle();
if (_fabShape == kDiamondFab)
}
if (_fabShape == kDiamondFab) {
return const _DiamondNotchedRectangle();
}
return null;
}
}
@ -452,8 +455,9 @@ class _DiamondNotchedRectangle implements NotchedShape {
@override
Path getOuterPath(Rect host, Rect? guest) {
if (!host.overlaps(guest!))
if (!host.overlaps(guest!)) {
return Path()..addRect(host);
}
assert(guest.width > 0.0);
final Rect intersection = guest.intersect(host);

View file

@ -165,8 +165,9 @@ class _BottomNavigationDemoState extends State<BottomNavigationDemo>
@override
void dispose() {
for (final NavigationIconView view in _navigationViews)
for (final NavigationIconView view in _navigationViews) {
view.controller.dispose();
}
super.dispose();
}

View file

@ -97,8 +97,9 @@ class DessertDataSource extends DataTableSource {
@override
DataRow? getRow(int index) {
assert(index >= 0);
if (index >= _desserts.length)
if (index >= _desserts.length) {
return null;
}
final Dessert dessert = _desserts[index];
return DataRow.byIndex(
index: index,
@ -134,8 +135,9 @@ class DessertDataSource extends DataTableSource {
int get selectedRowCount => _selectedCount;
void _selectAll(bool? checked) {
for (final Dessert dessert in _desserts)
for (final Dessert dessert in _desserts) {
dessert.selected = checked;
}
_selectedCount = checked! ? _desserts.length : 0;
notifyListeners();
}

View file

@ -66,8 +66,9 @@ class _DateTimePicker extends StatelessWidget {
firstDate: DateTime(2015, 8),
lastDate: DateTime(2101),
);
if (picked != null && picked != selectedDate)
if (picked != null && picked != selectedDate) {
selectDate!(picked);
}
}
Future<void> _selectTime(BuildContext context) async {
@ -75,8 +76,9 @@ class _DateTimePicker extends StatelessWidget {
context: context,
initialTime: selectedTime!,
);
if (picked != null && picked != selectedTime)
if (picked != null && picked != selectedTime) {
selectTime!(picked);
}
}
@override

View file

@ -144,10 +144,11 @@ class _DrawerDemoState extends State<DrawerDemo> with TickerProviderStateMixin {
margin: EdgeInsets.zero,
onDetailsPressed: () {
_showDrawerContents = !_showDrawerContents;
if (_showDrawerContents)
if (_showDrawerContents) {
_controller.reverse();
else
} else {
_controller.forward();
}
},
),
MediaQuery.removePadding(

View file

@ -46,8 +46,9 @@ class DateTimeItem extends StatelessWidget {
lastDate: date.add(const Duration(days: 30)),
)
.then((DateTime? value) {
if (value != null)
if (value != null) {
onChanged(DateTime(value.year, value.month, value.day, time.hour, time.minute));
}
});
},
child: Row(
@ -73,8 +74,9 @@ class DateTimeItem extends StatelessWidget {
initialTime: time,
)
.then((TimeOfDay? value) {
if (value != null)
if (value != null) {
onChanged(DateTime(date.year, date.month, date.day, value.hour, value.minute));
}
});
},
child: Row(
@ -109,8 +111,9 @@ class FullScreenDialogDemoState extends State<FullScreenDialogDemo> {
Future<bool> _onWillPop() async {
_saveNeeded = _hasLocation || _hasName || _saveNeeded;
if (!_saveNeeded)
if (!_saveNeeded) {
return true;
}
final ThemeData theme = Theme.of(context);
final TextStyle dialogTextStyle = theme.textTheme.subtitle1!.copyWith(color: theme.textTheme.caption!.color);

View file

@ -118,8 +118,9 @@ class _GridPhotoViewerState extends State<GridPhotoViewer> with SingleTickerProv
void _handleOnScaleEnd(ScaleEndDetails details) {
final double magnitude = details.velocity.pixelsPerSecond.distance;
if (magnitude < _kMinFlingVelocity)
if (magnitude < _kMinFlingVelocity) {
return;
}
final Offset direction = details.velocity.pixelsPerSecond / magnitude;
final double distance = (Offset.zero & context.size!).shortestSide;
_flingAnimation = _controller.drive(Tween<Offset>(

View file

@ -222,10 +222,11 @@ class _LeaveBehindListItem extends StatelessWidget {
key: ObjectKey(item),
direction: dismissDirection,
onDismissed: (DismissDirection direction) {
if (direction == DismissDirection.endToStart)
if (direction == DismissDirection.endToStart) {
_handleArchive();
else
} else {
_handleDelete();
}
},
confirmDismiss: !confirmDismiss ? null : (DismissDirection dismissDirection) async {
switch(dismissDirection) {

View file

@ -224,8 +224,9 @@ class _ListDemoState extends State<ListDemo> {
}
Iterable<Widget> listTiles = items.map<Widget>((String item) => buildListTile(context, item));
if (_showDividers != null)
if (_showDividers != null) {
listTiles = ListTile.divideTiles(context: context, tiles: listTiles);
}
return Scaffold(
key: scaffoldKey,

View file

@ -42,16 +42,18 @@ class MenuDemoState extends State<MenuDemo> {
}
void showMenuSelection(String value) {
if (<String>[_simpleValue1, _simpleValue2, _simpleValue3].contains(value))
if (<String>[_simpleValue1, _simpleValue2, _simpleValue3].contains(value)) {
setState(() => _simpleValue = value);
}
showInSnackBar('You selected: $value');
}
void showCheckedMenuSelections(String value) {
if (_checkedValues.contains(value))
if (_checkedValues.contains(value)) {
_checkedValues.remove(value);
else
} else {
_checkedValues.add(value);
}
showInSnackBar('Checked $_checkedValues');
}

View file

@ -29,8 +29,9 @@ class OverscrollDemoState extends State<OverscrollDemo> {
final Completer<void> completer = Completer<void>();
Timer(const Duration(seconds: 3), () => completer.complete());
return completer.future.then((_) {
if (!mounted)
if (!mounted) {
return;
}
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: const Text('Refresh complete'),
action: SnackBarAction(

View file

@ -13,8 +13,9 @@ class _PageSelector extends StatelessWidget {
void _handleArrowButtonPress(BuildContext context, int delta) {
final TabController controller = DefaultTabController.of(context)!;
if (!controller.indexIsChanging)
if (!controller.indexIsChanging) {
controller.animateTo((controller.index + delta).clamp(0, icons!.length - 1));
}
}
@override

View file

@ -33,10 +33,11 @@ class _ProgressIndicatorDemoState extends State<ProgressIndicatorDemo> with Sing
curve: const Interval(0.0, 0.9, curve: Curves.fastOutSlowIn),
reverseCurve: Curves.fastOutSlowIn,
)..addStatusListener((AnimationStatus status) {
if (status == AnimationStatus.dismissed)
if (status == AnimationStatus.dismissed) {
_controller.forward();
else if (status == AnimationStatus.completed)
} else if (status == AnimationStatus.completed) {
_controller.reverse();
}
});
}

View file

@ -68,8 +68,9 @@ class ScrollableTabsDemoState extends State<ScrollableTabsDemo> with SingleTicke
}
Decoration? getIndicator() {
if (!_customIndicator)
if (!_customIndicator) {
return const UnderlineTabIndicator();
}
switch(_demoStyle) {
case TabsDemoStyle.iconsAndText:

View file

@ -107,8 +107,9 @@ class _TabsFabDemoState extends State<TabsFabDemo> with SingleTickerProviderStat
}
Widget? buildFloatingActionButton(_Page page) {
if (!page.fabDefined)
if (!page.fabDefined) {
return null;
}
if (_extendedButtons) {
return FloatingActionButton.extended(

View file

@ -112,36 +112,42 @@ class TextFormFieldDemoState extends State<TextFormFieldDemo> {
String? _validateName(String? value) {
_formWasEdited = true;
if (value!.isEmpty)
if (value!.isEmpty) {
return 'Name is required.';
}
final RegExp nameExp = RegExp(r'^[A-Za-z ]+$');
if (!nameExp.hasMatch(value))
if (!nameExp.hasMatch(value)) {
return 'Please enter only alphabetical characters.';
}
return null;
}
String? _validatePhoneNumber(String? value) {
_formWasEdited = true;
final RegExp phoneExp = RegExp(r'^\(\d\d\d\) \d\d\d\-\d\d\d\d$');
if (!phoneExp.hasMatch(value!))
if (!phoneExp.hasMatch(value!)) {
return '(###) ###-#### - Enter a US phone number.';
}
return null;
}
String? _validatePassword(String? value) {
_formWasEdited = true;
final FormFieldState<String> passwordField = _passwordFieldKey.currentState!;
if (passwordField.value == null || passwordField.value!.isEmpty)
if (passwordField.value == null || passwordField.value!.isEmpty) {
return 'Please enter a password.';
if (passwordField.value != value)
}
if (passwordField.value != value) {
return "The passwords don't match";
}
return null;
}
Future<bool> _warnUserAboutInvalidData() async {
final FormState? form = _formKey.currentState;
if (form == null || !_formWasEdited || form.validate())
if (form == null || !_formWasEdited || form.validate()) {
return true;
}
final bool? result = await showDialog<bool>(
context: context,
@ -313,30 +319,35 @@ class _UsNumberTextInputFormatter extends TextInputFormatter {
final StringBuffer newText = StringBuffer();
if (newTextLength >= 1) {
newText.write('(');
if (newValue.selection.end >= 1)
if (newValue.selection.end >= 1) {
selectionIndex++;
}
}
if (newTextLength >= 4) {
final String value = newValue.text.substring(0, usedSubstringIndex = 3);
newText.write('$value) ');
if (newValue.selection.end >= 3)
if (newValue.selection.end >= 3) {
selectionIndex += 2;
}
}
if (newTextLength >= 7) {
final String value = newValue.text.substring(3, usedSubstringIndex = 6);
newText.write('$value-');
if (newValue.selection.end >= 6)
if (newValue.selection.end >= 6) {
selectionIndex++;
}
}
if (newTextLength >= 11) {
final String value = newValue.text.substring(6, usedSubstringIndex = 10);
newText.write('$value ');
if (newValue.selection.end >= 10)
if (newValue.selection.end >= 10) {
selectionIndex++;
}
}
// Dump the rest.
if (newTextLength >= usedSubstringIndex)
if (newTextLength >= usedSubstringIndex) {
newText.write(newValue.text.substring(usedSubstringIndex));
}
return TextEditingValue(
text: newText.toString(),
selection: TextSelection.collapsed(offset: selectionIndex),

View file

@ -418,10 +418,11 @@ class _RecipePageState extends State<RecipePage> {
void _toggleFavorite() {
setState(() {
if (_favoriteRecipes.contains(widget.recipe))
if (_favoriteRecipes.contains(widget.recipe)) {
_favoriteRecipes.remove(widget.recipe);
else
} else {
_favoriteRecipes.add(widget.recipe);
}
});
}
}

View file

@ -533,8 +533,9 @@ class ExtraProductsNumber extends StatelessWidget {
}
Widget _buildOverflow(AppStateModel model, BuildContext context) {
if (model.productsInCart.length <= 3)
if (model.productsInCart.length <= 3) {
return Container();
}
final int numOverflowProducts = _calculateOverflow(model);
// Maximum of 99 so padding doesn't get messy.

View file

@ -148,8 +148,9 @@ class VideoPlayPause extends StatefulWidget {
class _VideoPlayPauseState extends State<VideoPlayPause> {
_VideoPlayPauseState() {
listener = () {
if (mounted)
if (mounted) {
setState(() { });
}
};
}

View file

@ -241,16 +241,18 @@ class _BackdropState extends State<Backdrop> with SingleTickerProviderStateMixin
}
void _handleDragEnd(DragEndDetails details) {
if (_controller!.isAnimating || _controller!.status == AnimationStatus.completed)
if (_controller!.isAnimating || _controller!.status == AnimationStatus.completed) {
return;
}
final double flingVelocity = details.velocity.pixelsPerSecond.dy / _backdropHeight;
if (flingVelocity < 0.0)
if (flingVelocity < 0.0) {
_controller!.fling(velocity: math.max(2.0, -flingVelocity));
else if (flingVelocity > 0.0)
} else if (flingVelocity > 0.0) {
_controller!.fling(velocity: math.min(-2.0, -flingVelocity));
else
} else {
_controller!.fling(velocity: _controller!.value < 0.5 ? -2.0 : 2.0);
}
}
void _toggleFrontLayer() {

View file

@ -28,8 +28,9 @@ class ComponentDemoTabData {
@override
bool operator==(Object other) {
if (other.runtimeType != runtimeType)
if (other.runtimeType != runtimeType) {
return false;
}
return other is ComponentDemoTabData
&& other.tabName == tabName
&& other.description == description
@ -67,8 +68,9 @@ class TabbedComponentDemoScaffold extends StatelessWidget {
Future<void> _showApiDocumentation(BuildContext context) async {
final String? url = demos![DefaultTabController.of(context)!.index].documentationUrl;
if (url == null)
if (url == null) {
return;
}
final Uri uri = Uri.parse(url);
if (await canLaunchUrl(uri)) {

View file

@ -19,10 +19,12 @@ class GalleryDemoCategory {
@override
bool operator ==(Object other) {
if (identical(this, other))
if (identical(this, other)) {
return true;
if (other.runtimeType != runtimeType)
}
if (other.runtimeType != runtimeType) {
return false;
}
return other is GalleryDemoCategory
&& other.name == name
&& other.icon == icon;

View file

@ -99,8 +99,9 @@ DropdownButton<String>(
// null indicates the user didn't select a
// new value.
setState(() {
if (newValue != null)
if (newValue != null) {
dropdownValue = newValue;
}
});
},
items: <String>['One', 'Two', 'Free', 'Four']

View file

@ -10,8 +10,9 @@ const String _kEndTag = '// END';
Map<String?, String>? _exampleCode;
Future<String?> getExampleCode(String? tag, AssetBundle bundle) async {
if (_exampleCode == null)
if (_exampleCode == null) {
await _parseExampleCode(bundle);
}
return _exampleCode![tag];
}

View file

@ -57,8 +57,9 @@ class GalleryOptions {
@override
bool operator ==(Object other) {
if (other.runtimeType != runtimeType)
if (other.runtimeType != runtimeType) {
return false;
}
return other is GalleryOptions
&& other.themeMode == themeMode
&& other.textScaleFactor == textScaleFactor
@ -480,8 +481,9 @@ class GalleryOptionsPage extends StatelessWidget {
List<Widget> _enabledDiagnosticItems() {
// Boolean showFoo options with a value of null: don't display
// the showFoo option at all.
if (options == null)
if (options == null) {
return const <Widget>[];
}
return <Widget>[
const Divider(),

View file

@ -13,8 +13,9 @@ class GalleryTextScaleValue {
@override
bool operator ==(Object other) {
if (other.runtimeType != runtimeType)
if (other.runtimeType != runtimeType) {
return false;
}
return other is GalleryTextScaleValue
&& other.scale == scale
&& other.label == label;
@ -47,8 +48,9 @@ class GalleryVisualDensityValue {
@override
bool operator ==(Object other) {
if (other.runtimeType != runtimeType)
if (other.runtimeType != runtimeType) {
return false;
}
return other is GalleryVisualDensityValue
&& other.visualDensity == visualDensity
&& other.label == label;

View file

@ -95,16 +95,18 @@ class DartSyntaxHighlighter extends SyntaxHighlighter {
int currentPosition = 0;
for (final _HighlightSpan span in _spans) {
if (currentPosition != span.start)
if (currentPosition != span.start) {
formattedText.add(TextSpan(text: _src!.substring(currentPosition, span.start)));
}
formattedText.add(TextSpan(style: span.textStyle(_style), text: span.textForSpan(_src!)));
currentPosition = span.end;
}
if (currentPosition != _src!.length)
if (currentPosition != _src!.length) {
formattedText.add(TextSpan(text: _src!.substring(currentPosition, _src!.length)));
}
return TextSpan(style: _style!.baseStyle, children: formattedText);
} else {
@ -149,8 +151,9 @@ class DartSyntaxHighlighter extends SyntaxHighlighter {
endComment,
));
if (eof)
if (eof) {
break;
}
continue;
}
@ -260,17 +263,19 @@ class DartSyntaxHighlighter extends SyntaxHighlighter {
_HighlightType? type;
String word = _scanner.lastMatch![0]!;
if (word.startsWith('_'))
if (word.startsWith('_')) {
word = word.substring(1);
}
if (_keywords.contains(word))
if (_keywords.contains(word)) {
type = _HighlightType.keyword;
else if (_builtInTypes.contains(word))
} else if (_builtInTypes.contains(word)) {
type = _HighlightType.keyword;
else if (_firstLetterIsUpperCase(word))
} else if (_firstLetterIsUpperCase(word)) {
type = _HighlightType.klass;
else if (word.length >= 2 && word.startsWith('k') && _firstLetterIsUpperCase(word.substring(1)))
} else if (word.length >= 2 && word.startsWith('k') && _firstLetterIsUpperCase(word.substring(1))) {
type = _HighlightType.constant;
}
if (type != null) {
_spans.add(_HighlightSpan(
@ -336,21 +341,22 @@ class _HighlightSpan {
}
TextStyle? textStyle(SyntaxHighlighterStyle? style) {
if (type == _HighlightType.number)
if (type == _HighlightType.number) {
return style!.numberStyle;
else if (type == _HighlightType.comment)
} else if (type == _HighlightType.comment) {
return style!.commentStyle;
else if (type == _HighlightType.keyword)
} else if (type == _HighlightType.keyword) {
return style!.keywordStyle;
else if (type == _HighlightType.string)
} else if (type == _HighlightType.string) {
return style!.stringStyle;
else if (type == _HighlightType.punctuation)
} else if (type == _HighlightType.punctuation) {
return style!.punctuationStyle;
else if (type == _HighlightType.klass)
} else if (type == _HighlightType.klass) {
return style!.classStyle;
else if (type == _HighlightType.constant)
} else if (type == _HighlightType.constant) {
return style!.constantStyle;
else
} else {
return style!.baseStyle;
}
}
}

View file

@ -36,8 +36,9 @@ class UpdaterState extends State<Updater> {
final String? updateUrl = await widget.updateUrlFetcher();
final bool? wantsUpdate = await showDialog<bool>(context: context, builder: _buildDialog);
if (wantsUpdate != null && updateUrl != null && wantsUpdate)
if (wantsUpdate != null && updateUrl != null && wantsUpdate) {
launchUrl(Uri.parse(updateUrl));
}
}
Widget _buildDialog(BuildContext context) {

View file

@ -8,8 +8,9 @@ import 'package:flutter_test/flutter_test.dart';
void main() {
final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized();
if (binding is LiveTestWidgetsFlutterBinding)
if (binding is LiveTestWidgetsFlutterBinding) {
binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.fullyLive;
}
// We press the "1" and the "2" buttons and check that the display
// reads "12".

View file

@ -9,8 +9,9 @@ import 'package:flutter_test/flutter_test.dart';
void main() {
final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized();
if (binding is LiveTestWidgetsFlutterBinding)
if (binding is LiveTestWidgetsFlutterBinding) {
binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.fullyLive;
}
testWidgets('Flutter Gallery drawer item test', (WidgetTester tester) async {
bool hasFeedback = false;

View file

@ -8,8 +8,9 @@ import 'package:flutter_test/flutter_test.dart';
void main() {
final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized();
if (binding is LiveTestWidgetsFlutterBinding)
if (binding is LiveTestWidgetsFlutterBinding) {
binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.fullyLive;
}
testWidgets('Flutter gallery button example code displays', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/6147

View file

@ -45,8 +45,9 @@ class TestAssetBundle extends AssetBundle {
@override
Future<String> loadString(String key, { bool cache = true }) async {
if (key == 'lib/gallery/example_code.dart')
if (key == 'lib/gallery/example_code.dart') {
return testCodeFile;
}
return '';
}

View file

@ -51,10 +51,12 @@ Future<void> main() async {
// Verify that _kUnsynchronizedDemos and _kSkippedDemos identify
// demos that actually exist.
final List<String> allDemoTitles = kAllGalleryDemos.map((GalleryDemo demo) => demo.title).toList();
if (!Set<String>.from(allDemoTitles).containsAll(_kUnsynchronizedDemoTitles))
if (!Set<String>.from(allDemoTitles).containsAll(_kUnsynchronizedDemoTitles)) {
fail('Unrecognized demo titles in _kUnsynchronizedDemosTitles: $_kUnsynchronizedDemoTitles');
if (!Set<String>.from(allDemoTitles).containsAll(_kSkippedDemoTitles))
}
if (!Set<String>.from(allDemoTitles).containsAll(_kSkippedDemoTitles)) {
fail('Unrecognized demo names in _kSkippedDemoTitles: $_kSkippedDemoTitles');
}
print('Starting app...');
runApp(const GalleryApp(testMode: true));
@ -66,8 +68,9 @@ Future<void> main() async {
final Finder demoItem = find.text(demo.title);
print('Scrolling to "${demo.title}"...');
await controller.scrollIntoView(demoItem, alignment: 0.5);
if (_kSkippedDemoTitles.contains(demo.title))
if (_kSkippedDemoTitles.contains(demo.title)) {
continue;
}
for (int i = 0; i < 2; i += 1) {
print('Tapping "${demo.title}"...');
await controller.tap(demoItem); // Launch the demo
@ -91,10 +94,12 @@ Future<void> main() async {
final Finder backFinder = find.byElementPredicate(
(Element element) {
final Widget widget = element.widget;
if (widget is Tooltip)
if (widget is Tooltip) {
return widget.message == 'Back';
if (widget is CupertinoNavigationBarBackButton)
}
if (widget is CupertinoNavigationBarBackButton) {
return true;
}
return false;
},
description: 'Material or Cupertino back button',
@ -122,11 +127,13 @@ class _LiveWidgetController extends LiveWidgetController {
/// Runs `finder` repeatedly until it finds one or more [Element]s.
Future<Finder> _waitForElement(Finder finder) async {
if (frameSync)
if (frameSync) {
await _waitUntilFrame(() => binding.transientCallbackCount == 0);
}
await _waitUntilFrame(() => finder.precache());
if (frameSync)
if (frameSync) {
await _waitUntilFrame(() => binding.transientCallbackCount == 0);
}
return finder;
}

View file

@ -8,8 +8,9 @@ import 'package:flutter_test/flutter_test.dart';
void main() {
final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized();
if (binding is LiveTestWidgetsFlutterBinding)
if (binding is LiveTestWidgetsFlutterBinding) {
binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.fullyLive;
}
// Regression test for https://github.com/flutter/flutter/pull/5168
testWidgets('Pesto appbar heroics', (WidgetTester tester) async {

View file

@ -8,8 +8,9 @@ import 'package:flutter_test/flutter_test.dart';
void main() {
final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized();
if (binding is LiveTestWidgetsFlutterBinding)
if (binding is LiveTestWidgetsFlutterBinding) {
binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.fullyLive;
}
testWidgets('Flutter Gallery app simple smoke test', (WidgetTester tester) async {
await tester.pumpWidget(

View file

@ -40,8 +40,9 @@ void reportToStringError(String name, String route, int lineNumber, List<String>
void verifyToStringOutput(String name, String route, String testString) {
int lineNumber = 0;
final List<String> lines = testString.split('\n');
if (!testString.endsWith('\n'))
if (!testString.endsWith('\n')) {
reportToStringError(name, route, lines.length, lines, 'does not end with a line feed');
}
for (final String line in lines) {
lineNumber += 1;
if (line == '' && lineNumber != lines.length) {

View file

@ -12,8 +12,9 @@ Future<String> mockUpdateUrlFetcher() {
void main() {
final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized();
if (binding is LiveTestWidgetsFlutterBinding)
if (binding is LiveTestWidgetsFlutterBinding) {
binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.fullyLive;
}
// Regression test for https://github.com/flutter/flutter/pull/5168
testWidgets('update dialog', (WidgetTester tester) async {

View file

@ -23,8 +23,9 @@ Future<void> runDemos(List<String> demos, WidgetController controller) async {
String? currentDemoCategory;
for (final String demo in demos) {
if (kSkippedDemos.contains(demo))
if (kSkippedDemos.contains(demo)) {
continue;
}
final String demoName = demo.substring(0, demo.indexOf('@'));
final String demoCategory = demo.substring(demo.indexOf('@') + 1);

View file

@ -60,8 +60,9 @@ Future<void> saveDurationsHistogram(List<Map<String, dynamic>> events, String ou
}
// Verify that the durations data is valid.
if (durations.keys.isEmpty)
if (durations.keys.isEmpty) {
throw 'no "Start Transition" timeline events found';
}
final Map<String, int> unexpectedValueCounts = <String, int>{};
durations.forEach((String routeName, List<int> values) {
if (values.length != 2) {
@ -83,8 +84,9 @@ Future<void> saveDurationsHistogram(List<Map<String, dynamic>> events, String ou
while (eventIter.moveNext()) {
final String eventName = eventIter.current['name'] as String;
if (!<String>['Start Transition', 'Frame'].contains(eventName))
if (!<String>['Start Transition', 'Frame'].contains(eventName)) {
continue;
}
final String routeName = eventName == 'Start Transition'
? (eventIter.current['args'] as Map<String, dynamic>)['to'] as String
@ -114,8 +116,9 @@ Future<void> runDemos(List<String> demos, FlutterDriver driver) async {
String? currentDemoCategory;
for (final String demo in demos) {
if (kSkippedDemos.contains(demo))
if (kSkippedDemos.contains(demo)) {
continue;
}
final String demoName = demo.substring(0, demo.indexOf('@'));
final String demoCategory = demo.substring(demo.indexOf('@') + 1);
@ -176,8 +179,9 @@ void main([List<String> args = const <String>[]]) {
// See _handleMessages() in transitions_perf.dart.
_allDemos = List<String>.from(json.decode(await driver.requestData('demoNames')) as List<dynamic>);
if (_allDemos.isEmpty)
if (_allDemos.isEmpty) {
throw 'no demo names found';
}
});
tearDownAll(() async {

View file

@ -46,17 +46,19 @@ void diffActions(StringBuffer diffBuffer, Map<String, dynamic> originalEvent,
final String originalActionName =
getActionName(originalActionMasked, originalEvent['action'] as int);
if (synthesizedActionMasked != originalActionMasked)
if (synthesizedActionMasked != originalActionMasked) {
diffBuffer.write(
'action (expected: $originalActionName actual: $synthesizedActionName) ');
}
if (kPointerActions.contains(originalActionMasked) &&
originalActionMasked == synthesizedActionMasked) {
final int originalPointer = getPointerIdx(originalEvent['action'] as int);
final int synthesizedPointer = getPointerIdx(synthesizedEvent['action'] as int);
if (originalPointer != synthesizedPointer)
if (originalPointer != synthesizedPointer) {
diffBuffer.write(
'pointerIdx (expected: $originalPointer actual: $synthesizedPointer action: $originalActionName ');
}
}
}
@ -122,10 +124,12 @@ void diffMaps(
return;
}
for (final String key in expected.keys) {
if (excludeKeys.contains(key))
if (excludeKeys.contains(key)) {
continue;
if (doublesApproximatelyMatch(expected[key], actual[key]))
}
if (doublesApproximatelyMatch(expected[key], actual[key])) {
continue;
}
if (expected[key] != actual[key]) {
diffBuffer.write(
@ -154,10 +158,11 @@ String getActionName(int actionMasked, int action) {
'BUTTON_PRESS',
'BUTTON_RELEASE',
];
if (actionMasked < actionNames.length)
if (actionMasked < actionNames.length) {
return '${actionNames[actionMasked]}($action)';
else
} else {
return 'ACTION_$actionMasked';
}
}
bool doublesApproximatelyMatch(dynamic a, dynamic b) =>

View file

@ -128,16 +128,19 @@ class MotionEventsBodyState extends State<MotionEventsBody> {
await viewChannel!.invokeMethod<void>('stopTouchEvents');
if (flutterViewEvents.length != embeddedViewEvents.length)
if (flutterViewEvents.length != embeddedViewEvents.length) {
return 'Synthesized ${flutterViewEvents.length} events but the embedded view received ${embeddedViewEvents.length} events';
}
final StringBuffer diff = StringBuffer();
for (int i = 0; i < flutterViewEvents.length; ++i) {
final String currentDiff = diffMotionEvents(flutterViewEvents[i], embeddedViewEvents[i]);
if (currentDiff.isEmpty)
if (currentDiff.isEmpty) {
continue;
if (diff.isNotEmpty)
}
if (diff.isNotEmpty) {
diff.write(', ');
}
diff.write(currentDiff);
}
return diff.toString();
@ -201,8 +204,9 @@ class MotionEventsBodyState extends State<MotionEventsBody> {
case 'onTouch':
final Map<dynamic, dynamic> map = call.arguments as Map<dynamic, dynamic>;
flutterViewEvents.insert(0, map.cast<String, dynamic>());
if (flutterViewEvents.length > kEventsBufferSize)
if (flutterViewEvents.length > kEventsBufferSize) {
flutterViewEvents.removeLast();
}
setState(() {});
break;
}
@ -214,8 +218,9 @@ class MotionEventsBodyState extends State<MotionEventsBody> {
case 'onTouch':
final Map<dynamic, dynamic> map = call.arguments as Map<dynamic, dynamic>;
embeddedViewEvents.insert(0, map.cast<String, dynamic>());
if (embeddedViewEvents.length > kEventsBufferSize)
if (embeddedViewEvents.length > kEventsBufferSize) {
embeddedViewEvents.removeLast();
}
setState(() {});
break;
}
@ -223,9 +228,10 @@ class MotionEventsBodyState extends State<MotionEventsBody> {
}
Widget buildEventTile(BuildContext context, int index) {
if (embeddedViewEvents.length > index)
if (embeddedViewEvents.length > index) {
return TouchEventDiff(
flutterViewEvents[index], embeddedViewEvents[index]);
}
return Text(
'Unmatched event, action: ${flutterViewEvents[index]['action']}');
}

View file

@ -31,10 +31,11 @@ class _TestAppState extends State<TestApp> {
void _executeNextStep() {
setState(() {
if (_step < steps.length)
if (_step < steps.length) {
_result = steps[_step++]();
else
} else {
_result = Future<TestStepResult>.value(TestStepResult.complete);
}
});
}

Some files were not shown because too many files have changed in this diff Show more