Unverified Commit 10a7c9ba authored by Michael Goderbauer's avatar Michael Goderbauer Committed by GitHub

Unify analysis options (#108462)

parent 8a8ed75d
......@@ -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)
......
......@@ -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));
}
},
),
),
......
......@@ -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;
......
......@@ -18,8 +18,9 @@ void main() {
});
tearDownAll(() async {
if (driver != null)
if (driver != null) {
driver.close();
}
});
Future<void> testScrollPerf(String listKey, String summaryName) async {
......
......@@ -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});
......
......@@ -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,
......
......@@ -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();
}
......
......@@ -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();
}
......
......@@ -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();
}
}
......
......@@ -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',
);
}
}
}
......
......@@ -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();
......
......@@ -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)]!;
}
......
......@@ -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));
}
......
......@@ -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),
......
......@@ -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) {
......
......@@ -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(
......
......@@ -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 {
......
This diff is collapsed.
......@@ -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],
......
......@@ -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':
......
......@@ -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;
}
......
......@@ -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';
......
......@@ -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
......@@ -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'))
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)
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),
......
......@@ -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);
}
......
......@@ -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,
......
......@@ -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');
......
......@@ -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.');
......
......@@ -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).
......
......@@ -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;
}
......
......@@ -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);
......
......@@ -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');
......
......@@ -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');
......
......@@ -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);
});
......
......@@ -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';
}
}
......@@ -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');
}
});
}
......@@ -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;
}
......
......@@ -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');
......
......@@ -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);
}
......
......@@ -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;
}
......
......@@ -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));
}
}
......
......@@ -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].
......
......@@ -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 {
......
......@@ -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...');
......
......@@ -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)
......
......@@ -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();
......
......@@ -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;
......
......@@ -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;
}
......
......@@ -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;
}
......
......@@ -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) =>
......
......@@ -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']}');
}
......
......@@ -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);
}
});
}
......
......@@ -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';
}
}
......@@ -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;
}
......
......@@ -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();
......
......@@ -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;
}
......
......@@ -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;
}
......
......@@ -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
......
......@@ -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);
......
......@@ -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();
}
......
......@@ -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();
}
......
......@@ -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
......
......@@ -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(
......
......@@ -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);
......
......@@ -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>(
......
......@@ -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) {
......
......@@ -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,
......
......@@ -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');
}
......
......@@ -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(
......
......@@ -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
......
......@@ -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();
}
});
}
......
......@@ -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:
......
......@@ -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(
......
......@@ -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),
......
......@@ -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);
}
});
}
}
......
......@@ -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.
......
......@@ -148,8 +148,9 @@ class VideoPlayPause extends StatefulWidget {
class _VideoPlayPauseState extends State<VideoPlayPause> {
_VideoPlayPauseState() {
listener = () {
if (mounted)
if (mounted) {
setState(() { });
}
};
}
......
......@@ -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() {
......
......@@ -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)) {
......
......@@ -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;
......
......@@ -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']
......
......@@ -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];
}
......
......@@ -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(),
......
......@@ -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;
......
......@@ -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;
}
}
}
......@@ -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) {
......
......@@ -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".
......
......@@ -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;
......
......@@ -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
......
......@@ -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 '';
}
......
......@@ -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;
}
......
......@@ -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 {
......
......@@ -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(
......
......@@ -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) {
......
......@@ -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 {
......
......@@ -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);
......
......@@ -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 {
......
......@@ -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) =>
......
......@@ -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']}');
}
......
......@@ -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);
}
});
}
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment