Unverified Commit cb378edc authored by Ian Hickson's avatar Ian Hickson Committed by GitHub

Enable `avoid_print` lint. (#91332)

parent 3c6c2aa5
...@@ -71,8 +71,8 @@ linter: ...@@ -71,8 +71,8 @@ linter:
- avoid_init_to_null - avoid_init_to_null
# - avoid_js_rounded_ints # only useful when targeting JS runtime # - avoid_js_rounded_ints # only useful when targeting JS runtime
- avoid_null_checks_in_equality_operators - avoid_null_checks_in_equality_operators
# - avoid_positional_boolean_parameters # not yet tested # - avoid_positional_boolean_parameters # would have been nice to enable this but by now there's too many places that break it
# - avoid_print # not yet tested - avoid_print
# - avoid_private_typedef_functions # we prefer having typedef (discussion in https://github.com/flutter/flutter/pull/16356) # - avoid_private_typedef_functions # we prefer having typedef (discussion in https://github.com/flutter/flutter/pull/16356)
# - avoid_redundant_argument_values # not yet tested # - avoid_redundant_argument_values # not yet tested
- avoid_relative_lib_imports - avoid_relative_lib_imports
......
include: ../analysis_options.yaml
linter:
rules:
avoid_print: false # We use prints as debugging tools here all the time.
[0-9]+:[0-9]+ [+]0: Local passes non-existent baseline for new test, null expectation *
*No expectations provided by Skia Gold for test: library.flutter.new_golden_test.1. This may be a new test. If this is an unexpected result, check https://flutter-gold.skia.org.
*Validate image output found at flutter/test/library/
[0-9]+:[0-9]+ [+]0 ~1: Local passes non-existent baseline for new test, empty expectation *
*No expectations provided by Skia Gold for test: library.flutter.new_golden_test.2. This may be a new test. If this is an unexpected result, check https://flutter-gold.skia.org.
*Validate image output found at flutter/test/library/
[0-9]+:[0-9]+ [+]0 ~2: All tests skipped. *
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// See also packages/flutter_goldens/test/flutter_goldens_test.dart
import 'dart:typed_data';
import 'package:file/file.dart';
import 'package:file/memory.dart';
import 'package:flutter_goldens/flutter_goldens.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:platform/platform.dart';
// 1x1 colored pixel
const List<int> _kFailPngBytes = <int>[137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0,
13, 73, 72, 68, 82, 0, 0, 0, 1, 0, 0, 0, 1, 8, 6, 0, 0, 0, 31, 21, 196, 137,
0, 0, 0, 13, 73, 68, 65, 84, 120, 1, 99, 249, 207, 240, 255, 63, 0, 7, 18, 3,
2, 164, 147, 160, 197, 0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130];
void main() {
final MemoryFileSystem fs = MemoryFileSystem();
final Directory basedir = fs.directory('flutter/test/library/')
..createSync(recursive: true);
final FakeSkiaGoldClient fakeSkiaClient = FakeSkiaGoldClient()
..expectationForTestValues['flutter.new_golden_test.1'] = '';
final FlutterLocalFileComparator comparator = FlutterLocalFileComparator(
basedir.uri,
fakeSkiaClient,
fs: fs,
platform: FakePlatform(
environment: <String, String>{'FLUTTER_ROOT': '/flutter'},
operatingSystem: 'macos'
),
);
test('Local passes non-existent baseline for new test, null expectation', () async {
expect(
await comparator.compare(
Uint8List.fromList(_kFailPngBytes),
Uri.parse('flutter.new_golden_test.1'),
),
isTrue,
);
});
test('Local passes non-existent baseline for new test, empty expectation', () async {
expect(
await comparator.compare(
Uint8List.fromList(_kFailPngBytes),
Uri.parse('flutter.new_golden_test.2'),
),
isTrue,
);
});
}
// See also packages/flutter_goldens/test/flutter_goldens_test.dart
class FakeSkiaGoldClient extends Fake implements SkiaGoldClient {
Map<String, String> expectationForTestValues = <String, String>{};
Object? getExpectationForTestThrowable;
@override
Future<String> getExpectationForTest(String testName) async {
if (getExpectationForTestThrowable != null) {
throw getExpectationForTestThrowable!;
}
return expectationForTestValues[testName] ?? '';
}
Map<String, List<int>> imageBytesValues = <String, List<int>>{};
@override
Future<List<int>> getImageBytes(String imageHash) async => imageBytesValues[imageHash]!;
Map<String, String> cleanTestNameValues = <String, String>{};
@override
String cleanTestName(String fileName) => cleanTestNameValues[fileName] ?? '';
}
...@@ -8,5 +8,5 @@ import 'package:test/test.dart' hide TypeMatcher, isInstanceOf; ...@@ -8,5 +8,5 @@ import 'package:test/test.dart' hide TypeMatcher, isInstanceOf;
void main() { void main() {
test('working directory is the root of this package', () { test('working directory is the root of this package', () {
expect(Directory.current.path, endsWith('automated_tests')); expect(Directory.current.path, endsWith('automated_tests'));
}); });
} }
...@@ -8,6 +8,8 @@ dependencies: ...@@ -8,6 +8,8 @@ dependencies:
sdk: flutter sdk: flutter
flutter_test: flutter_test:
sdk: flutter sdk: flutter
flutter_goldens:
sdk: flutter
integration_test: integration_test:
sdk: flutter sdk: flutter
test: 1.17.12 test: 1.17.12
......
# Use the analysis options settings from the top level of the repo (not include: ../../analysis_options.yaml
# the ones from above, which include the `public_member_api_docs` rule).
include: ../../../analysis_options.yaml
analyzer: analyzer:
exclude: exclude:
# Ignore protoc generated files # Ignore protoc generated files
- "lib/src/proto/*" - "lib/src/proto/*"
linter: linter:
rules: rules:
avoid_catches_without_on_clauses: true avoid_catches_without_on_clauses: true
......
# Use the analysis options settings from the top level of the repo (not include: ../../analysis_options.yaml
# the ones from above, which include the `public_member_api_docs` rule).
include: ../../../analysis_options.yaml
linter: linter:
rules: rules:
......
include: ../../analysis_options.yaml include: ../analysis_options.yaml
linter: linter:
rules: rules:
......
# Take our settings from the repo's main analysis_options.yaml file, but add include: ../../analysis_options.yaml
# an exclude for the build directory.
include: ../../../analysis_options.yaml
analyzer: analyzer:
exclude: exclude:
......
...@@ -47,7 +47,7 @@ class AutocompleteBasicExample extends StatelessWidget { ...@@ -47,7 +47,7 @@ class AutocompleteBasicExample extends StatelessWidget {
}); });
}, },
onSelected: (String selection) { onSelected: (String selection) {
print('You just selected $selection'); debugPrint('You just selected $selection');
}, },
); );
} }
......
...@@ -79,7 +79,7 @@ class AutocompleteBasicUserExample extends StatelessWidget { ...@@ -79,7 +79,7 @@ class AutocompleteBasicUserExample extends StatelessWidget {
}); });
}, },
onSelected: (User selection) { onSelected: (User selection) {
print('You just selected ${_displayStringForOption(selection)}'); debugPrint('You just selected ${_displayStringForOption(selection)}');
}, },
); );
} }
......
...@@ -35,7 +35,7 @@ class MyStatelessWidget extends StatelessWidget { ...@@ -35,7 +35,7 @@ class MyStatelessWidget extends StatelessWidget {
child: InkWell( child: InkWell(
splashColor: Colors.blue.withAlpha(30), splashColor: Colors.blue.withAlpha(30),
onTap: () { onTap: () {
print('Card tapped.'); debugPrint('Card tapped.');
}, },
child: const SizedBox( child: const SizedBox(
width: 300, width: 300,
......
...@@ -59,7 +59,7 @@ class LinkedLabelCheckbox extends StatelessWidget { ...@@ -59,7 +59,7 @@ class LinkedLabelCheckbox extends StatelessWidget {
), ),
recognizer: TapGestureRecognizer() recognizer: TapGestureRecognizer()
..onTap = () { ..onTap = () {
print('Label has been tapped.'); debugPrint('Label has been tapped.');
}, },
), ),
), ),
......
...@@ -45,7 +45,7 @@ class MyStatelessWidget extends StatelessWidget { ...@@ -45,7 +45,7 @@ class MyStatelessWidget extends StatelessWidget {
), ),
floatingActionButton: FloatingActionButton( floatingActionButton: FloatingActionButton(
onPressed: () { onPressed: () {
print('FAB pressed.'); debugPrint('FAB pressed.');
}, },
tooltip: 'Increment', tooltip: 'Increment',
child: const Icon(Icons.add), child: const Icon(Icons.add),
......
...@@ -34,7 +34,7 @@ class MyStatelessWidget extends StatelessWidget { ...@@ -34,7 +34,7 @@ class MyStatelessWidget extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return OutlinedButton( return OutlinedButton(
onPressed: () { onPressed: () {
print('Received click'); debugPrint('Received click');
}, },
child: const Text('Click Me'), child: const Text('Click Me'),
); );
......
...@@ -64,7 +64,7 @@ class LinkedLabelRadio extends StatelessWidget { ...@@ -64,7 +64,7 @@ class LinkedLabelRadio extends StatelessWidget {
), ),
recognizer: TapGestureRecognizer() recognizer: TapGestureRecognizer()
..onTap = () { ..onTap = () {
print('Label has been tapped.'); debugPrint('Label has been tapped.');
}, },
), ),
), ),
......
...@@ -59,7 +59,7 @@ class LinkedLabelSwitch extends StatelessWidget { ...@@ -59,7 +59,7 @@ class LinkedLabelSwitch extends StatelessWidget {
), ),
recognizer: TapGestureRecognizer() recognizer: TapGestureRecognizer()
..onTap = () { ..onTap = () {
print('Label has been tapped.'); debugPrint('Label has been tapped.');
}, },
), ),
), ),
......
...@@ -54,7 +54,7 @@ class _MyStatefulWidgetState extends State<MyStatefulWidget> { ...@@ -54,7 +54,7 @@ class _MyStatefulWidgetState extends State<MyStatefulWidget> {
constraints: BoxConstraints.tight(const Size(200, 50)), constraints: BoxConstraints.tight(const Size(200, 50)),
child: TextFormField( child: TextFormField(
onSaved: (String? value) { onSaved: (String? value) {
print('Value for field $index saved as "$value"'); debugPrint('Value for field $index saved as "$value"');
}, },
), ),
), ),
......
...@@ -92,13 +92,13 @@ class MyAction extends Action<MyIntent> { ...@@ -92,13 +92,13 @@ class MyAction extends Action<MyIntent> {
@override @override
void addActionListener(ActionListenerCallback listener) { void addActionListener(ActionListenerCallback listener) {
super.addActionListener(listener); super.addActionListener(listener);
print('Action Listener was added'); debugPrint('Action Listener was added');
} }
@override @override
void removeActionListener(ActionListenerCallback listener) { void removeActionListener(ActionListenerCallback listener) {
super.removeActionListener(listener); super.removeActionListener(listener);
print('Action Listener was removed'); debugPrint('Action Listener was removed');
} }
@override @override
......
...@@ -34,7 +34,7 @@ class Model { ...@@ -34,7 +34,7 @@ class Model {
int save() { int save() {
if (isDirty.value) { if (isDirty.value) {
print('Saved Data: ${data.value}'); debugPrint('Saved Data: ${data.value}');
isDirty.value = false; isDirty.value = false;
} }
return data.value; return data.value;
......
...@@ -57,21 +57,21 @@ class _ColorfulButtonState extends State<ColorfulButton> { ...@@ -57,21 +57,21 @@ class _ColorfulButtonState extends State<ColorfulButton> {
KeyEventResult _handleKeyPress(FocusNode node, RawKeyEvent event) { KeyEventResult _handleKeyPress(FocusNode node, RawKeyEvent event) {
if (event is RawKeyDownEvent) { if (event is RawKeyDownEvent) {
print('Focus node ${node.debugLabel} got key event: ${event.logicalKey}'); debugPrint('Focus node ${node.debugLabel} got key event: ${event.logicalKey}');
if (event.logicalKey == LogicalKeyboardKey.keyR) { if (event.logicalKey == LogicalKeyboardKey.keyR) {
print('Changing color to red.'); debugPrint('Changing color to red.');
setState(() { setState(() {
_color = Colors.red; _color = Colors.red;
}); });
return KeyEventResult.handled; return KeyEventResult.handled;
} else if (event.logicalKey == LogicalKeyboardKey.keyG) { } else if (event.logicalKey == LogicalKeyboardKey.keyG) {
print('Changing color to green.'); debugPrint('Changing color to green.');
setState(() { setState(() {
_color = Colors.green; _color = Colors.green;
}); });
return KeyEventResult.handled; return KeyEventResult.handled;
} else if (event.logicalKey == LogicalKeyboardKey.keyB) { } else if (event.logicalKey == LogicalKeyboardKey.keyB) {
print('Changing color to blue.'); debugPrint('Changing color to blue.');
setState(() { setState(() {
_color = Colors.blue; _color = Colors.blue;
}); });
......
...@@ -38,21 +38,21 @@ class _MyStatefulWidgetState extends State<MyStatefulWidget> { ...@@ -38,21 +38,21 @@ class _MyStatefulWidgetState extends State<MyStatefulWidget> {
KeyEventResult _handleKeyPress(FocusNode node, RawKeyEvent event) { KeyEventResult _handleKeyPress(FocusNode node, RawKeyEvent event) {
if (event is RawKeyDownEvent) { if (event is RawKeyDownEvent) {
print('Focus node ${node.debugLabel} got key event: ${event.logicalKey}'); debugPrint('Focus node ${node.debugLabel} got key event: ${event.logicalKey}');
if (event.logicalKey == LogicalKeyboardKey.keyR) { if (event.logicalKey == LogicalKeyboardKey.keyR) {
print('Changing color to red.'); debugPrint('Changing color to red.');
setState(() { setState(() {
_color = Colors.red; _color = Colors.red;
}); });
return KeyEventResult.handled; return KeyEventResult.handled;
} else if (event.logicalKey == LogicalKeyboardKey.keyG) { } else if (event.logicalKey == LogicalKeyboardKey.keyG) {
print('Changing color to green.'); debugPrint('Changing color to green.');
setState(() { setState(() {
_color = Colors.green; _color = Colors.green;
}); });
return KeyEventResult.handled; return KeyEventResult.handled;
} else if (event.logicalKey == LogicalKeyboardKey.keyB) { } else if (event.logicalKey == LogicalKeyboardKey.keyB) {
print('Changing color to blue.'); debugPrint('Changing color to blue.');
setState(() { setState(() {
_color = Colors.blue; _color = Colors.blue;
}); });
......
...@@ -115,7 +115,7 @@ class _MyStatefulWidgetState extends State<MyStatefulWidget> { ...@@ -115,7 +115,7 @@ class _MyStatefulWidgetState extends State<MyStatefulWidget> {
// This button would be not visible, but still focusable from // This button would be not visible, but still focusable from
// the foreground pane without the FocusScope. // the foreground pane without the FocusScope.
ElevatedButton( ElevatedButton(
onPressed: () => print('You pressed the other button!'), onPressed: () => debugPrint('You pressed the other button!'),
child: const Text('ANOTHER BUTTON TO FOCUS'), child: const Text('ANOTHER BUTTON TO FOCUS'),
), ),
DefaultTextStyle( DefaultTextStyle(
......
...@@ -68,7 +68,7 @@ class _OrderedButtonState<T> extends State<OrderedButton<T>> { ...@@ -68,7 +68,7 @@ class _OrderedButtonState<T> extends State<OrderedButton<T>> {
void _handleOnPressed() { void _handleOnPressed() {
focusNode.requestFocus(); focusNode.requestFocus();
print('Button ${widget.name} pressed.'); debugPrint('Button ${widget.name} pressed.');
debugDumpFocusTree(); debugDumpFocusTree();
} }
......
...@@ -40,7 +40,7 @@ class DemoButton extends StatelessWidget { ...@@ -40,7 +40,7 @@ class DemoButton extends StatelessWidget {
final double order; final double order;
void _handleOnPressed() { void _handleOnPressed() {
print('Button $name pressed.'); debugPrint('Button $name pressed.');
debugDumpFocusTree(); debugDumpFocusTree();
} }
......
...@@ -122,10 +122,10 @@ class _IVBuilderExampleState extends State<_IVBuilderExample> { ...@@ -122,10 +122,10 @@ class _IVBuilderExampleState extends State<_IVBuilderExample> {
cellWidth: _cellWidth, cellWidth: _cellWidth,
builder: (BuildContext context, int row, int column) { builder: (BuildContext context, int row, int column) {
if (!_isCellVisible(row, column, viewport)) { if (!_isCellVisible(row, column, viewport)) {
print('removing cell ($row, $column)'); debugPrint('removing cell ($row, $column)');
return Container(height: _cellHeight); return Container(height: _cellHeight);
} }
print('building cell ($row, $column)'); debugPrint('building cell ($row, $column)');
return Container( return Container(
height: _cellHeight, height: _cellHeight,
color: row % 2 + column % 2 == 1 color: row % 2 + column % 2 == 1
......
...@@ -45,9 +45,9 @@ class MyStatelessWidget extends StatelessWidget { ...@@ -45,9 +45,9 @@ class MyStatelessWidget extends StatelessWidget {
body: NotificationListener<ScrollNotification>( body: NotificationListener<ScrollNotification>(
onNotification: (ScrollNotification scrollNotification) { onNotification: (ScrollNotification scrollNotification) {
if (scrollNotification is ScrollStartNotification) { if (scrollNotification is ScrollStartNotification) {
print('Scrolling has started'); debugPrint('Scrolling has started');
} else if (scrollNotification is ScrollEndNotification) { } else if (scrollNotification is ScrollEndNotification) {
print('Scrolling has ended'); debugPrint('Scrolling has ended');
} }
// Return true to cancel the notification bubbling. // Return true to cancel the notification bubbling.
return true; return true;
......
...@@ -98,7 +98,7 @@ Future<void> main() async { ...@@ -98,7 +98,7 @@ Future<void> main() async {
final HttpServer httpServer = final HttpServer httpServer =
await HttpServer.bindSecure('localhost', 0, serverContext); await HttpServer.bindSecure('localhost', 0, serverContext);
final int port = httpServer.port; final int port = httpServer.port;
print('Listening on port $port.'); debugPrint('Listening on port $port.');
// Initializes bindings before using any platform channels. // Initializes bindings before using any platform channels.
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
...@@ -193,7 +193,7 @@ class _MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin { ...@@ -193,7 +193,7 @@ class _MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
).toList(); ).toList();
final DateTime started = DateTime.now(); final DateTime started = DateTime.now();
Future.wait(futures).then((_) { Future.wait(futures).then((_) {
print( debugPrint(
'===image_list=== all loaded in ${DateTime.now().difference(started).inMilliseconds}ms.', '===image_list=== all loaded in ${DateTime.now().difference(started).inMilliseconds}ms.',
); );
}); });
......
...@@ -47,8 +47,8 @@ class Calculator { ...@@ -47,8 +47,8 @@ class Calculator {
final int n = result.length; final int n = result.length;
onResultListener('Decoded $n results'); onResultListener('Decoded $n results');
} catch (e, stack) { } catch (e, stack) {
print('Invalid JSON file: $e'); debugPrint('Invalid JSON file: $e');
print(stack); debugPrint('$stack');
} }
} }
......
...@@ -2,6 +2,10 @@ ...@@ -2,6 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// This file implements debugPrint in terms of print, so avoiding
// calling "print" is sort of a non-starter here...
// ignore_for_file: avoid_print
import 'dart:async'; import 'dart:async';
import 'dart:collection'; import 'dart:collection';
......
...@@ -42,6 +42,7 @@ class FakeTextChannel implements MethodChannel { ...@@ -42,6 +42,7 @@ class FakeTextChannel implements MethodChannel {
void validateOutgoingMethodCalls(List<MethodCall> calls) { void validateOutgoingMethodCalls(List<MethodCall> calls) {
expect(outgoingCalls.length, calls.length); expect(outgoingCalls.length, calls.length);
final StringBuffer output = StringBuffer();
bool hasError = false; bool hasError = false;
for (int i = 0; i < calls.length; i++) { for (int i = 0; i < calls.length; i++) {
final ByteData outgoingData = codec.encodeMethodCall(outgoingCalls[i]); final ByteData outgoingData = codec.encodeMethodCall(outgoingCalls[i]);
...@@ -50,7 +51,7 @@ class FakeTextChannel implements MethodChannel { ...@@ -50,7 +51,7 @@ class FakeTextChannel implements MethodChannel {
final String expectedString = utf8.decode(expectedData.buffer.asUint8List()); final String expectedString = utf8.decode(expectedData.buffer.asUint8List());
if (outgoingString != expectedString) { if (outgoingString != expectedString) {
print( output.writeln(
'Index $i did not match:\n' 'Index $i did not match:\n'
' actual: $outgoingString\n' ' actual: $outgoingString\n'
' expected: $expectedString', ' expected: $expectedString',
...@@ -59,7 +60,7 @@ class FakeTextChannel implements MethodChannel { ...@@ -59,7 +60,7 @@ class FakeTextChannel implements MethodChannel {
} }
} }
if (hasError) { if (hasError) {
fail('Calls did not match.'); fail('Calls did not match:\n$output');
} }
} }
} }
...@@ -26,7 +26,7 @@ void checkTree(WidgetTester tester, List<BoxDecoration> expectedDecorations) { ...@@ -26,7 +26,7 @@ void checkTree(WidgetTester tester, List<BoxDecoration> expectedDecorations) {
} }
expect(child, isNull); expect(child, isNull);
} catch (e) { } catch (e) {
print(renderObject.toStringDeep()); debugPrint(renderObject.toStringDeep());
rethrow; rethrow;
} }
} }
......
...@@ -41,7 +41,7 @@ void checkTree(WidgetTester tester, List<TestParentData> expectedParentData) { ...@@ -41,7 +41,7 @@ void checkTree(WidgetTester tester, List<TestParentData> expectedParentData) {
} }
expect(child, isNull); expect(child, isNull);
} catch (e) { } catch (e) {
print(renderObject.toStringDeep()); debugPrint(renderObject.toStringDeep());
rethrow; rethrow;
} }
} }
......
include: ../analysis_options.yaml
linter:
rules:
avoid_print: false # This is a CLI tool, so printing to the console is fine.
...@@ -50,7 +50,7 @@ class VMServiceFlutterDriver extends FlutterDriver { ...@@ -50,7 +50,7 @@ class VMServiceFlutterDriver extends FlutterDriver {
// TODO(awdavies): Use something other than print. On fuchsia // TODO(awdavies): Use something other than print. On fuchsia
// `stderr`/`stdout` appear to have issues working correctly. // `stderr`/`stdout` appear to have issues working correctly.
driverLog = (String source, String message) { driverLog = (String source, String message) {
print('$source: $message'); print('$source: $message'); // ignore: avoid_print
}; };
fuchsiaModuleTarget ??= Platform.environment['FUCHSIA_MODULE_TARGET']; fuchsiaModuleTarget ??= Platform.environment['FUCHSIA_MODULE_TARGET'];
if (fuchsiaModuleTarget == null) { if (fuchsiaModuleTarget == null) {
......
...@@ -222,11 +222,7 @@ class WebFlutterDriver extends FlutterDriver { ...@@ -222,11 +222,7 @@ class WebFlutterDriver extends FlutterDriver {
class FlutterWebConnection { class FlutterWebConnection {
/// Creates a FlutterWebConnection with WebDriver /// Creates a FlutterWebConnection with WebDriver
/// and whether the WebDriver supports timeline action. /// and whether the WebDriver supports timeline action.
FlutterWebConnection(this._driver, this.supportsTimelineAction) { FlutterWebConnection(this._driver, this.supportsTimelineAction);
_driver.logs.get(async_io.LogType.browser).listen((async_io.LogEntry entry) {
print('[${entry.level}]: ${entry.message}');
});
}
final async_io.WebDriver _driver; final async_io.WebDriver _driver;
......
...@@ -20,7 +20,7 @@ void tryToDelete(Directory directory) { ...@@ -20,7 +20,7 @@ void tryToDelete(Directory directory) {
try { try {
directory.deleteSync(recursive: true); directory.deleteSync(recursive: true);
} on FileSystemException catch (error) { } on FileSystemException catch (error) {
print('Failed to delete ${directory.path}: $error'); driverLog('test', 'Failed to delete ${directory.path}: $error');
} }
} }
......
...@@ -385,9 +385,7 @@ class FlutterSkippingFileComparator extends FlutterGoldenFileComparator { ...@@ -385,9 +385,7 @@ class FlutterSkippingFileComparator extends FlutterGoldenFileComparator {
@override @override
Future<bool> compare(Uint8List imageBytes, Uri golden) async { Future<bool> compare(Uint8List imageBytes, Uri golden) async {
print( markTestSkipped('Skipping "$golden" test: $reason');
'Skipping "$golden" test : $reason'
);
return true; return true;
} }
...@@ -502,8 +500,9 @@ class FlutterLocalFileComparator extends FlutterGoldenFileComparator with LocalC ...@@ -502,8 +500,9 @@ class FlutterLocalFileComparator extends FlutterGoldenFileComparator with LocalC
testExpectation = await skiaClient.getExpectationForTest(testName); testExpectation = await skiaClient.getExpectationForTest(testName);
if (testExpectation == null || testExpectation.isEmpty) { if (testExpectation == null || testExpectation.isEmpty) {
// There is no baseline for this test // There is no baseline for this test.
print('No expectations provided by Skia Gold for test: $golden. ' markTestSkipped(
'No expectations provided by Skia Gold for test: $golden. '
'This may be a new test. If this is an unexpected result, check ' 'This may be a new test. If this is an unexpected result, check '
'https://flutter-gold.skia.org.\n' 'https://flutter-gold.skia.org.\n'
'Validate image output found at $basedir' 'Validate image output found at $basedir'
......
...@@ -8,18 +8,19 @@ ...@@ -8,18 +8,19 @@
// Fails with "flutter test --test-randomize-ordering-seed=123" // Fails with "flutter test --test-randomize-ordering-seed=123"
@Tags(<String>['no-shuffle']) @Tags(<String>['no-shuffle'])
// See also dev/automated_tests/flutter_test/flutter_gold_test.dart
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:core';
import 'dart:io' hide Directory; import 'dart:io' hide Directory;
import 'dart:typed_data'; import 'dart:typed_data';
import 'dart:ui' show hashValues, hashList; import 'dart:ui' show hashValues, hashList;
import 'package:file/file.dart'; import 'package:file/file.dart';
import 'package:file/memory.dart'; import 'package:file/memory.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_goldens/flutter_goldens.dart'; import 'package:flutter_goldens/flutter_goldens.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:meta/meta.dart';
import 'package:platform/platform.dart'; import 'package:platform/platform.dart';
import 'package:process/process.dart'; import 'package:process/process.dart';
...@@ -41,17 +42,6 @@ const List<int> _kFailPngBytes = ...@@ -41,17 +42,6 @@ const List<int> _kFailPngBytes =
120, 1, 99, 249, 207, 240, 255, 63, 0, 7, 18, 3, 2, 164, 147, 160, 197, 0, 120, 1, 99, 249, 207, 240, 255, 63, 0, 7, 18, 3, 2, 164, 147, 160, 197, 0,
0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130]; 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130];
Future<void> testWithOutput(String name, Future<void> Function() body, String expectedOutput) async {
test(name, () async {
final StringBuffer output = StringBuffer();
void _recordPrint(Zone self, ZoneDelegate parent, Zone zone, String line) {
output.write(line);
}
await runZoned<Future<void>>(body, zoneSpecification: ZoneSpecification(print: _recordPrint));
expect(output.toString(), expectedOutput);
});
}
void main() { void main() {
late MemoryFileSystem fs; late MemoryFileSystem fs;
late FakePlatform platform; late FakePlatform platform;
...@@ -569,7 +559,6 @@ void main() { ...@@ -569,7 +559,6 @@ void main() {
const String hash = '55109a4bed52acc780530f7a9aeff6c0'; const String hash = '55109a4bed52acc780530f7a9aeff6c0';
fakeSkiaClient.expectationForTestValues['flutter.golden_test.1'] = hash; fakeSkiaClient.expectationForTestValues['flutter.golden_test.1'] = hash;
fakeSkiaClient.expectationForTestValues['flutter.new_golden_test.1'] = '';
fakeSkiaClient.imageBytesValues[hash] =_kTestPngBytes; fakeSkiaClient.imageBytesValues[hash] =_kTestPngBytes;
fakeSkiaClient.cleanTestNameValues['library.flutter.golden_test.1.png'] = 'flutter.golden_test.1'; fakeSkiaClient.cleanTestNameValues['library.flutter.golden_test.1.png'] = 'flutter.golden_test.1';
}); });
...@@ -584,32 +573,6 @@ void main() { ...@@ -584,32 +573,6 @@ void main() {
); );
}); });
testWithOutput('passes non-existent baseline for new test, null expectation', () async {
expect(
await comparator.compare(
Uint8List.fromList(_kFailPngBytes),
Uri.parse('flutter.new_golden_test.1'),
),
isTrue,
);
}, 'No expectations provided by Skia Gold for test: library.flutter.new_golden_test.1. '
'This may be a new test. If this is an unexpected result, check https://flutter-gold.skia.org.\n'
'Validate image output found at flutter/test/library/'
);
testWithOutput('passes non-existent baseline for new test, empty expectation', () async {
expect(
await comparator.compare(
Uint8List.fromList(_kFailPngBytes),
Uri.parse('flutter.new_golden_test.2'),
),
isTrue,
);
}, 'No expectations provided by Skia Gold for test: library.flutter.new_golden_test.2. '
'This may be a new test. If this is an unexpected result, check https://flutter-gold.skia.org.\n'
'Validate image output found at flutter/test/library/'
);
test('compare properly awaits validation & output before failing.', () async { test('compare properly awaits validation & output before failing.', () async {
final Completer<bool> completer = Completer<bool>(); final Completer<bool> completer = Completer<bool>();
final Future<bool> result = comparator.compare( final Future<bool> result = comparator.compare(
...@@ -713,14 +676,14 @@ class FakeProcessManager extends Fake implements ProcessManager { ...@@ -713,14 +676,14 @@ class FakeProcessManager extends Fake implements ProcessManager {
workingDirectories.add(workingDirectory); workingDirectories.add(workingDirectory);
final ProcessResult? result = processResults[RunInvocation(command.cast<String>(), workingDirectory)]; final ProcessResult? result = processResults[RunInvocation(command.cast<String>(), workingDirectory)];
if (result == null && fallbackProcessResult == null) { if (result == null && fallbackProcessResult == null) {
// Throwing here might gobble up the exception message if a test fails. printOnFailure('ProcessManager.run was called with $command ($workingDirectory) unexpectedly - $processResults.');
print('ProcessManager.run was called with $command ($workingDirectory) unexpectedly - $processResults.');
fail('See above.'); fail('See above.');
} }
return result ?? fallbackProcessResult!; return result ?? fallbackProcessResult!;
} }
} }
// See also dev/automated_tests/flutter_test/flutter_gold_test.dart
class FakeSkiaGoldClient extends Fake implements SkiaGoldClient { class FakeSkiaGoldClient extends Fake implements SkiaGoldClient {
Map<String, String> expectationForTestValues = <String, String>{}; Map<String, String> expectationForTestValues = <String, String>{};
Object? getExpectationForTestThrowable; Object? getExpectationForTestThrowable;
......
...@@ -183,9 +183,10 @@ class SkiaGoldClient { ...@@ -183,9 +183,10 @@ class SkiaGoldClient {
if (result.exitCode != 0) { if (result.exitCode != 0) {
// We do not want to throw for non-zero exit codes here, as an intentional // We do not want to throw for non-zero exit codes here, as an intentional
// change or new golden file test expect non-zero exit codes. Logging here // change or new golden file test expect non-zero exit codes. Logging here
// is meant to inform when an unexpected result occurs. // is meant to help debugging in CI when an unexpected result occurs.
print('goldctl imgtest add stdout: ${result.stdout}'); // See also: https://github.com/flutter/flutter/issues/91285
print('goldctl imgtest add stderr: ${result.stderr}'); print('goldctl imgtest add stdout: ${result.stdout}'); // ignore: avoid_print
print('goldctl imgtest add stderr: ${result.stderr}'); // ignore: avoid_print
} }
return true; return true;
...@@ -301,7 +302,10 @@ class SkiaGoldClient { ...@@ -301,7 +302,10 @@ class SkiaGoldClient {
throw const FormatException('Skia gold expectations do not match expected format.'); throw const FormatException('Skia gold expectations do not match expected format.');
expectation = jsonResponse['digest'] as String?; expectation = jsonResponse['digest'] as String?;
} on FormatException catch (error) { } on FormatException catch (error) {
print( // Ideally we'd use something like package:test's printOnError, but best reliabilty
// in getting logs on CI for now we're just using print.
// See also: https://github.com/flutter/flutter/issues/91285
print( // ignore: avoid_print
'Formatting error detected requesting expectations from Flutter Gold.\n' 'Formatting error detected requesting expectations from Flutter Gold.\n'
'error: $error\n' 'error: $error\n'
'url: $requestForExpectations\n' 'url: $requestForExpectations\n'
......
...@@ -6,6 +6,8 @@ import 'dart:typed_data'; ...@@ -6,6 +6,8 @@ import 'dart:typed_data';
import 'dart:ui'; import 'dart:ui';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
import 'package:test_api/test_api.dart'; // ignore: deprecated_member_use
import '_goldens_io.dart' if (dart.library.html) '_goldens_web.dart' as _goldens; import '_goldens_io.dart' if (dart.library.html) '_goldens_web.dart' as _goldens;
/// Compares image pixels against a golden image file. /// Compares image pixels against a golden image file.
...@@ -268,7 +270,7 @@ class TrivialComparator implements GoldenFileComparator { ...@@ -268,7 +270,7 @@ class TrivialComparator implements GoldenFileComparator {
@override @override
Future<bool> compare(Uint8List imageBytes, Uri golden) { Future<bool> compare(Uint8List imageBytes, Uri golden) {
print('Golden file comparison requested for "$golden"; skipping...'); markTestSkipped('Golden file comparison requested for "$golden"; skipping...');
return Future<bool>.value(true); return Future<bool>.value(true);
} }
...@@ -288,7 +290,7 @@ class _TrivialWebGoldenComparator implements WebGoldenComparator { ...@@ -288,7 +290,7 @@ class _TrivialWebGoldenComparator implements WebGoldenComparator {
@override @override
Future<bool> compare(double width, double height, Uri golden) { Future<bool> compare(double width, double height, Uri golden) {
print('Golden comparison requested for "$golden"; skipping...'); markTestSkipped('Golden comparison requested for "$golden"; skipping...');
return Future<bool>.value(true); return Future<bool>.value(true);
} }
......
...@@ -96,7 +96,7 @@ Future<void> _runLiveTest(Suite suiteConfig, LiveTest liveTest, _Reporter report ...@@ -96,7 +96,7 @@ Future<void> _runLiveTest(Suite suiteConfig, LiveTest liveTest, _Reporter report
Future<void> _runSkippedTest(Suite suiteConfig, Test test, List<Group> parents, _Reporter reporter) async { Future<void> _runSkippedTest(Suite suiteConfig, Test test, List<Group> parents, _Reporter reporter) async {
final LocalTest skipped = LocalTest(test.name, test.metadata, () { }, trace: test.trace); final LocalTest skipped = LocalTest(test.name, test.metadata, () { }, trace: test.trace);
if (skipped.metadata.skipReason != null) { if (skipped.metadata.skipReason != null) {
print('Skip: ${skipped.metadata.skipReason}'); reporter.log('Skip: ${skipped.metadata.skipReason}');
} }
final LiveTest liveTest = skipped.load(suiteConfig); final LiveTest liveTest = skipped.load(suiteConfig);
reporter._onTestStarted(liveTest); reporter._onTestStarted(liveTest);
...@@ -334,7 +334,7 @@ class _Reporter { ...@@ -334,7 +334,7 @@ class _Reporter {
if (message.type == MessageType.skip) { if (message.type == MessageType.skip) {
text = ' $_yellow$text$_noColor'; text = ' $_yellow$text$_noColor';
} }
print(text); log(text);
})); }));
} }
...@@ -351,8 +351,8 @@ class _Reporter { ...@@ -351,8 +351,8 @@ class _Reporter {
return; return;
} }
_progressLine(_description(liveTest), suffix: ' $_bold$_red[E]$_noColor'); _progressLine(_description(liveTest), suffix: ' $_bold$_red[E]$_noColor');
print(_indent(error.toString())); log(_indent(error.toString()));
print(_indent('$stackTrace')); log(_indent('$stackTrace'));
} }
/// A callback called when the engine is finished running tests. /// A callback called when the engine is finished running tests.
...@@ -421,7 +421,7 @@ class _Reporter { ...@@ -421,7 +421,7 @@ class _Reporter {
buffer.write(message); buffer.write(message);
buffer.write(_noColor); buffer.write(_noColor);
print(buffer.toString()); log(buffer.toString());
} }
/// Returns a representation of [duration] as `MM:SS`. /// Returns a representation of [duration] as `MM:SS`.
...@@ -442,6 +442,13 @@ class _Reporter { ...@@ -442,6 +442,13 @@ class _Reporter {
} }
return name; return name;
} }
/// Print the message to the console.
void log(String message) {
// We centralize all the prints in this file through this one method so that
// in principle we can reroute the output easily should we need to.
print(message); // ignore: avoid_print
}
} }
String _indent(String string, { int? size, String? first }) { String _indent(String string, { int? size, String? first }) {
......
...@@ -416,7 +416,7 @@ Future<void> benchmarkWidgets( ...@@ -416,7 +416,7 @@ Future<void> benchmarkWidgets(
assert(() { assert(() {
if (mayRunWithAsserts) if (mayRunWithAsserts)
return true; return true;
print(kDebugWarning); debugPrint(kDebugWarning);
return true; return true;
}()); }());
final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized() as TestWidgetsFlutterBinding; final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized() as TestWidgetsFlutterBinding;
......
# Use the analysis options settings from the top level of the repo (not include: ../analysis_options.yaml
# the ones from above, which include the `public_member_api_docs` rule).
include: ../../analysis_options.yaml
linter: linter:
rules: rules:
avoid_catches_without_on_clauses: true avoid_catches_without_on_clauses: true
curly_braces_in_flow_control_structures: true curly_braces_in_flow_control_structures: true
library_private_types_in_public_api: false # Tool does not have any public API library_private_types_in_public_api: false # Tool does not have any public API.
no_runtimeType_toString: false # We use runtimeType for debugging in the tool.
prefer_relative_imports: true prefer_relative_imports: true
public_member_api_docs: false # Tool does not have any public API.
unawaited_futures: true unawaited_futures: true
include: ../analysis_options.yaml
linter:
rules:
avoid_print: false # These are CLI tools which print as a matter of course.
...@@ -25,6 +25,12 @@ ...@@ -25,6 +25,12 @@
/// about any additional exports that you add to this file, as doing so will /// about any additional exports that you add to this file, as doing so will
/// increase the API surface that we have to test in Flutter tools, and the APIs /// increase the API surface that we have to test in Flutter tools, and the APIs
/// in `dart:io` can sometimes be hard to use in tests. /// in `dart:io` can sometimes be hard to use in tests.
// We allow `print()` in this file as a fallback for writing to the terminal via
// regular stdout/stderr/stdio paths. Everything else in the flutter_tools
// library should route terminal I/O through the [Stdio] class defined below.
// ignore_for_file: avoid_print
import 'dart:async'; import 'dart:async';
import 'dart:io' as io import 'dart:io' as io
show show
......
...@@ -247,6 +247,7 @@ class Cache { ...@@ -247,6 +247,7 @@ class Cache {
} }
} on Exception catch (error) { } on Exception catch (error) {
// There is currently no logger attached since this is computed at startup. // There is currently no logger attached since this is computed at startup.
// ignore: avoid_print
print(userMessages.runnerNoRoot('$error')); print(userMessages.runnerNoRoot('$error'));
} }
return normalize('.'); return normalize('.');
......
...@@ -307,6 +307,7 @@ class DaemonDomain extends Domain { ...@@ -307,6 +307,7 @@ class DaemonDomain extends Domain {
if (message.level == 'status') { if (message.level == 'status') {
// We use `print()` here instead of `stdout.writeln()` in order to // We use `print()` here instead of `stdout.writeln()` in order to
// capture the print output for testing. // capture the print output for testing.
// ignore: avoid_print
print(message.message); print(message.message);
} else if (message.level == 'error') { } else if (message.level == 'error') {
globals.stdio.stderrWrite('${message.message}\n'); globals.stdio.stderrWrite('${message.message}\n');
......
...@@ -96,7 +96,7 @@ class MacOSDevice extends DesktopDevice { ...@@ -96,7 +96,7 @@ class MacOSDevice extends DesktopDevice {
'open', package.applicationBundle(buildMode), 'open', package.applicationBundle(buildMode),
]).then((ProcessResult result) { ]).then((ProcessResult result) {
if (result.exitCode != 0) { if (result.exitCode != 0) {
print('Failed to foreground app; open returned ${result.exitCode}'); _logger.printError('Failed to foreground app; open returned ${result.exitCode}');
} }
}); });
} }
......
...@@ -2668,10 +2668,9 @@ Future<void> _ensureFlutterToolsSnapshot() async { ...@@ -2668,10 +2668,9 @@ Future<void> _ensureFlutterToolsSnapshot() async {
'../../bin/cache/dart-sdk/bin/dart', '../../bin/cache/dart-sdk/bin/dart',
snapshotArgs, snapshotArgs,
); );
if (snapshotResult.exitCode != 0) { printOnFailure('Results of generating snapshot:');
print(snapshotResult.stdout); printOnFailure(snapshotResult.stdout.toString());
print(snapshotResult.stderr); printOnFailure(snapshotResult.stderr.toString());
}
expect(snapshotResult.exitCode, 0); expect(snapshotResult.exitCode, 0);
} }
...@@ -2713,10 +2712,9 @@ Future<void> _analyzeProject(String workingDir, { List<String> expectedFailures ...@@ -2713,10 +2712,9 @@ Future<void> _analyzeProject(String workingDir, { List<String> expectedFailures
workingDirectory: workingDir, workingDirectory: workingDir,
); );
if (expectedFailures.isEmpty) { if (expectedFailures.isEmpty) {
if (exec.exitCode != 0) { printOnFailure('Results of running analyzer:');
print(exec.stdout); printOnFailure(exec.stdout.toString());
print(exec.stderr); printOnFailure(exec.stderr.toString());
}
expect(exec.exitCode, 0); expect(exec.exitCode, 0);
return; return;
} }
...@@ -2770,10 +2768,9 @@ Future<void> _runFlutterTest(Directory workingDir, { String target }) async { ...@@ -2770,10 +2768,9 @@ Future<void> _runFlutterTest(Directory workingDir, { String target }) async {
args, args,
workingDirectory: workingDir.path, workingDirectory: workingDir.path,
); );
if (exec.exitCode != 0) { printOnFailure('Output of running flutter test:');
print(exec.stdout); printOnFailure(exec.stdout.toString());
print(exec.stderr); printOnFailure(exec.stderr.toString());
}
expect(exec.exitCode, 0); expect(exec.exitCode, 0);
} }
......
...@@ -179,7 +179,6 @@ void main() { ...@@ -179,7 +179,6 @@ void main() {
expect(logContents, contains('String: an exception % --')); expect(logContents, contains('String: an exception % --'));
expect(logContents, contains('CrashingFlutterCommand.runCommand')); expect(logContents, contains('CrashingFlutterCommand.runCommand'));
expect(logContents, contains('[✓] Flutter')); expect(logContents, contains('[✓] Flutter'));
print(globals.crashReporter.runtimeType);
final CrashDetails sentDetails = (globals.crashReporter as WaitingCrashReporter)._details; final CrashDetails sentDetails = (globals.crashReporter as WaitingCrashReporter)._details;
expect(sentDetails.command, 'flutter crash'); expect(sentDetails.command, 'flutter crash');
......
...@@ -28,8 +28,9 @@ void main() { ...@@ -28,8 +28,9 @@ void main() {
'--no-color', '--no-color',
...arguments, ...arguments,
], workingDirectory: projectPath); ], workingDirectory: projectPath);
print(result.stdout); printOnFailure('Output of flutter ${arguments.join(" ")}');
print(result.stderr); printOnFailure(result.stdout.toString());
printOnFailure(result.stderr.toString());
expect(result.exitCode, exitCode, reason: 'Expected to exit with non-zero exit code.'); expect(result.exitCode, exitCode, reason: 'Expected to exit with non-zero exit code.');
assertContains(result.stdout.toString(), statusTextContains); assertContains(result.stdout.toString(), statusTextContains);
assertContains(result.stdout.toString(), errorTextContains); assertContains(result.stdout.toString(), errorTextContains);
......
...@@ -31,8 +31,9 @@ void main() { ...@@ -31,8 +31,9 @@ void main() {
'--target-platform=android-arm64' '--target-platform=android-arm64'
], workingDirectory: workingDirectory); ], workingDirectory: workingDirectory);
print(result.stdout); printOnFailure('Output of flutter build apk:');
print(result.stderr); printOnFailure(result.stdout.toString());
printOnFailure(result.stderr.toString());
expect(result.stdout.toString(), contains('app-release.apk (total compressed)')); expect(result.stdout.toString(), contains('app-release.apk (total compressed)'));
final String line = result.stdout.toString() final String line = result.stdout.toString()
...@@ -67,8 +68,9 @@ void main() { ...@@ -67,8 +68,9 @@ void main() {
'--no-codesign', '--no-codesign',
], workingDirectory: workingDirectory); ], workingDirectory: workingDirectory);
print(result.stdout); printOnFailure('Output of flutter build ios:');
print(result.stderr); printOnFailure(result.stdout.toString());
printOnFailure(result.stderr.toString());
expect(result.stdout.toString(), contains('Dart AOT symbols accounted decompressed size')); expect(result.stdout.toString(), contains('Dart AOT symbols accounted decompressed size'));
final String line = result.stdout.toString() final String line = result.stdout.toString()
...@@ -102,8 +104,9 @@ void main() { ...@@ -102,8 +104,9 @@ void main() {
'--enable-macos-desktop', '--enable-macos-desktop',
], workingDirectory: workingDirectory); ], workingDirectory: workingDirectory);
print(configResult.stdout); printOnFailure('Output of flutter config:');
print(configResult.stderr); printOnFailure(configResult.stdout.toString());
printOnFailure(configResult.stderr.toString());
final ProcessResult result = await processManager.run(<String>[ final ProcessResult result = await processManager.run(<String>[
flutterBin, flutterBin,
...@@ -113,8 +116,9 @@ void main() { ...@@ -113,8 +116,9 @@ void main() {
'--code-size-directory=${codeSizeDir.path}', '--code-size-directory=${codeSizeDir.path}',
], workingDirectory: workingDirectory); ], workingDirectory: workingDirectory);
print(result.stdout); printOnFailure('Output of flutter build macos:');
print(result.stderr); printOnFailure(result.stdout.toString());
printOnFailure(result.stderr.toString());
expect(result.stdout.toString(), contains('Dart AOT symbols accounted decompressed size')); expect(result.stdout.toString(), contains('Dart AOT symbols accounted decompressed size'));
final String line = result.stdout.toString() final String line = result.stdout.toString()
...@@ -147,8 +151,9 @@ void main() { ...@@ -147,8 +151,9 @@ void main() {
'--debug', '--debug',
], workingDirectory: fileSystem.path.join(getFlutterRoot(), 'examples', 'hello_world')); ], workingDirectory: fileSystem.path.join(getFlutterRoot(), 'examples', 'hello_world'));
print(result.stdout); printOnFailure('Output of flutter build apk:');
print(result.stderr); printOnFailure(result.stdout.toString());
printOnFailure(result.stderr.toString());
expect(result.stderr.toString(), contains('"--analyze-size" can only be used on release builds')); expect(result.stderr.toString(), contains('"--analyze-size" can only be used on release builds'));
expect(result.exitCode, 1); expect(result.exitCode, 1);
......
...@@ -34,7 +34,7 @@ void main() { ...@@ -34,7 +34,7 @@ void main() {
final Completer<void> sawBackgroundMessage = Completer<void>.sync(); final Completer<void> sawBackgroundMessage = Completer<void>.sync();
final Completer<void> sawNewBackgroundMessage = Completer<void>.sync(); final Completer<void> sawNewBackgroundMessage = Completer<void>.sync();
final StreamSubscription<String> subscription = flutter.stdout.listen((String line) { final StreamSubscription<String> subscription = flutter.stdout.listen((String line) {
print('[LOG]:"$line"'); printOnFailure('[LOG]:"$line"');
if (line.contains('Main thread') && !sawForegroundMessage.isCompleted) { if (line.contains('Main thread') && !sawForegroundMessage.isCompleted) {
sawForegroundMessage.complete(); sawForegroundMessage.complete();
} }
...@@ -68,7 +68,7 @@ void main() { ...@@ -68,7 +68,7 @@ void main() {
final Completer<void> sawBackgroundMessage = Completer<void>.sync(); final Completer<void> sawBackgroundMessage = Completer<void>.sync();
final Completer<void> sawNewBackgroundMessage = Completer<void>.sync(); final Completer<void> sawNewBackgroundMessage = Completer<void>.sync();
final StreamSubscription<String> subscription = flutter.stdout.listen((String line) { final StreamSubscription<String> subscription = flutter.stdout.listen((String line) {
print('[LOG]:"$line"'); printOnFailure('[LOG]:"$line"');
if (line.contains('Isolate thread') && !sawBackgroundMessage.isCompleted) { if (line.contains('Isolate thread') && !sawBackgroundMessage.isCompleted) {
sawBackgroundMessage.complete(); sawBackgroundMessage.complete();
} }
......
...@@ -33,8 +33,9 @@ void main() { ...@@ -33,8 +33,9 @@ void main() {
'--no-codesign', '--no-codesign',
], workingDirectory: workingDirectory); ], workingDirectory: workingDirectory);
print(result.stdout); printOnFailure('Output of flutter build ios:');
print(result.stderr); printOnFailure(result.stdout.toString());
printOnFailure(result.stderr.toString());
expect(result.exitCode, 0); expect(result.exitCode, 0);
......
...@@ -64,11 +64,7 @@ Future<void> main(List<String> args) async { ...@@ -64,11 +64,7 @@ Future<void> main(List<String> args) async {
await cache.lock(); await cache.lock();
process.kill(io.ProcessSignal.sigkill); process.kill(io.ProcessSignal.sigkill);
} finally { } finally {
try { tryToDelete(tempDir);
tempDir.deleteSync(recursive: true);
} on FileSystemException {
// Ignore filesystem exceptions when trying to delete tempdir.
}
Cache.flutterRoot = oldRoot; Cache.flutterRoot = oldRoot;
} }
expect(logger.statusText, isEmpty); expect(logger.statusText, isEmpty);
......
...@@ -26,8 +26,10 @@ void main() { ...@@ -26,8 +26,10 @@ void main() {
'--target-platform', 'android-arm', '--target-platform', 'android-arm',
'--verbose', '--verbose',
], workingDirectory: woringDirectory); ], workingDirectory: woringDirectory);
print(result.stdout);
print(result.stderr); printOnFailure('Output of flutter build apk:');
printOnFailure(result.stdout.toString());
printOnFailure(result.stderr.toString());
expect(result.exitCode, 0); expect(result.exitCode, 0);
......
...@@ -38,11 +38,7 @@ void main() { ...@@ -38,11 +38,7 @@ void main() {
}); });
tearDown(() { tearDown(() {
try { tryToDelete(parentDirectory);
parentDirectory.deleteSync(recursive: true);
} on FileSystemException {
print('Failed to delete test directory');
}
}); });
testWithoutContext('Can upgrade and downgrade a Flutter checkout', () async { testWithoutContext('Can upgrade and downgrade a Flutter checkout', () async {
...@@ -56,7 +52,7 @@ void main() { ...@@ -56,7 +52,7 @@ void main() {
'git', 'config', '--system', 'core.longpaths', 'true', 'git', 'config', '--system', 'core.longpaths', 'true',
]); ]);
print('Step 1 - clone the $_kBranch of flutter into the test directory'); printOnFailure('Step 1 - clone the $_kBranch of flutter into the test directory');
exitCode = await processUtils.stream(<String>[ exitCode = await processUtils.stream(<String>[
'git', 'git',
'clone', 'clone',
...@@ -64,7 +60,7 @@ void main() { ...@@ -64,7 +60,7 @@ void main() {
], workingDirectory: parentDirectory.path, trace: true); ], workingDirectory: parentDirectory.path, trace: true);
expect(exitCode, 0); expect(exitCode, 0);
print('Step 2 - switch to the $_kBranch'); printOnFailure('Step 2 - switch to the $_kBranch');
exitCode = await processUtils.stream(<String>[ exitCode = await processUtils.stream(<String>[
'git', 'git',
'checkout', 'checkout',
...@@ -75,7 +71,7 @@ void main() { ...@@ -75,7 +71,7 @@ void main() {
], workingDirectory: testDirectory.path, trace: true); ], workingDirectory: testDirectory.path, trace: true);
expect(exitCode, 0); expect(exitCode, 0);
print('Step 3 - revert back to $_kInitialVersion'); printOnFailure('Step 3 - revert back to $_kInitialVersion');
exitCode = await processUtils.stream(<String>[ exitCode = await processUtils.stream(<String>[
'git', 'git',
'reset', 'reset',
...@@ -84,7 +80,7 @@ void main() { ...@@ -84,7 +80,7 @@ void main() {
], workingDirectory: testDirectory.path, trace: true); ], workingDirectory: testDirectory.path, trace: true);
expect(exitCode, 0); expect(exitCode, 0);
print('Step 4 - upgrade to the newest $_kBranch'); printOnFailure('Step 4 - upgrade to the newest $_kBranch');
// This should update the persistent tool state with the sha for HEAD // This should update the persistent tool state with the sha for HEAD
exitCode = await processUtils.stream(<String>[ exitCode = await processUtils.stream(<String>[
flutterBin, flutterBin,
...@@ -94,7 +90,7 @@ void main() { ...@@ -94,7 +90,7 @@ void main() {
], workingDirectory: testDirectory.path, trace: true); ], workingDirectory: testDirectory.path, trace: true);
expect(exitCode, 0); expect(exitCode, 0);
print('Step 5 - verify that the version is different'); printOnFailure('Step 5 - verify that the version is different');
final RunResult versionResult = await processUtils.run(<String>[ final RunResult versionResult = await processUtils.run(<String>[
'git', 'git',
'describe', 'describe',
...@@ -104,10 +100,9 @@ void main() { ...@@ -104,10 +100,9 @@ void main() {
'--tags', '--tags',
], workingDirectory: testDirectory.path); ], workingDirectory: testDirectory.path);
expect(versionResult.stdout, isNot(contains(_kInitialVersion))); expect(versionResult.stdout, isNot(contains(_kInitialVersion)));
print('current version is ${versionResult.stdout.trim()}\ninitial was $_kInitialVersion'); printOnFailure('current version is ${versionResult.stdout.trim()}\ninitial was $_kInitialVersion');
print('Step 6 - downgrade back to the initial version'); printOnFailure('Step 6 - downgrade back to the initial version');
// Step 6. Downgrade back to initial version.
exitCode = await processUtils.stream(<String>[ exitCode = await processUtils.stream(<String>[
flutterBin, flutterBin,
'downgrade', 'downgrade',
...@@ -116,8 +111,7 @@ void main() { ...@@ -116,8 +111,7 @@ void main() {
], workingDirectory: testDirectory.path, trace: true); ], workingDirectory: testDirectory.path, trace: true);
expect(exitCode, 0); expect(exitCode, 0);
print('Step 7 - verify downgraded version matches original version'); printOnFailure('Step 7 - verify downgraded version matches original version');
// Step 7. Verify downgraded version matches original version.
final RunResult oldVersionResult = await processUtils.run(<String>[ final RunResult oldVersionResult = await processUtils.run(<String>[
'git', 'git',
'describe', 'describe',
...@@ -127,6 +121,6 @@ void main() { ...@@ -127,6 +121,6 @@ void main() {
'--tags', '--tags',
], workingDirectory: testDirectory.path); ], workingDirectory: testDirectory.path);
expect(oldVersionResult.stdout, contains(_kInitialVersion)); expect(oldVersionResult.stdout, contains(_kInitialVersion));
print('current version is ${oldVersionResult.stdout.trim()}\ninitial was $_kInitialVersion'); printOnFailure('current version is ${oldVersionResult.stdout.trim()}\ninitial was $_kInitialVersion');
}); });
} }
...@@ -36,8 +36,9 @@ void main() { ...@@ -36,8 +36,9 @@ void main() {
fileSystem.path.join(tempDir.path, 'main.dart'), fileSystem.path.join(tempDir.path, 'main.dart'),
]); ]);
print(result.stdout); printOnFailure('Output of dart main.dart:');
print(result.stderr); printOnFailure(result.stdout.toString());
printOnFailure(result.stderr.toString());
expect(result.exitCode, 0); expect(result.exitCode, 0);
}); });
...@@ -55,8 +56,9 @@ void main() { ...@@ -55,8 +56,9 @@ void main() {
fileSystem.path.join(tempDir.path, 'main.dart'), fileSystem.path.join(tempDir.path, 'main.dart'),
]); ]);
print(result.stdout); printOnFailure('Output of dart main.dart:');
print(result.stderr); printOnFailure(result.stdout.toString());
printOnFailure(result.stderr.toString());
expect(result.exitCode, 1); expect(result.exitCode, 1);
}); });
} }
...@@ -67,7 +67,6 @@ String unsafeString = null; ...@@ -67,7 +67,6 @@ String unsafeString = null;
for (final String targetPlatform in targetPlatforms) { for (final String targetPlatform in targetPlatforms) {
testWithoutContext('flutter build $targetPlatform --no-sound-null-safety', () { testWithoutContext('flutter build $targetPlatform --no-sound-null-safety', () {
print(tempDir);
final ProcessResult result = processManager.runSync(<String>[ final ProcessResult result = processManager.runSync(<String>[
flutterBin, flutterBin,
...getLocalEngineArguments(), ...getLocalEngineArguments(),
......
...@@ -138,10 +138,9 @@ Future<void> _ensureFlutterToolsSnapshot() async { ...@@ -138,10 +138,9 @@ Future<void> _ensureFlutterToolsSnapshot() async {
'../../bin/cache/dart-sdk/bin/dart', '../../bin/cache/dart-sdk/bin/dart',
snapshotArgs, snapshotArgs,
); );
if (snapshotResult.exitCode != 0) { printOnFailure('Output of dart ${snapshotArgs.join(" ")}:');
print(snapshotResult.stdout); printOnFailure(snapshotResult.stdout.toString());
print(snapshotResult.stderr); printOnFailure(snapshotResult.stderr.toString());
}
expect(snapshotResult.exitCode, 0); expect(snapshotResult.exitCode, 0);
} }
...@@ -237,9 +236,8 @@ Future<void> _analyzeProject(Directory workingDir) async { ...@@ -237,9 +236,8 @@ Future<void> _analyzeProject(Directory workingDir) async {
args, args,
workingDirectory: workingDir.path, workingDirectory: workingDir.path,
); );
if (exec.exitCode != 0) { printOnFailure('Output of flutter analyze:');
print(exec.stdout); printOnFailure(exec.stdout.toString());
print(exec.stderr); printOnFailure(exec.stderr.toString());
}
expect(exec.exitCode, 0); expect(exec.exitCode, 0);
} }
...@@ -108,8 +108,14 @@ void main() { ...@@ -108,8 +108,14 @@ void main() {
await flutter.resume(); // we start paused so we can set up our TICK 1 listener before the app starts await flutter.resume(); // we start paused so we can set up our TICK 1 listener before the app starts
unawaited(sawTick1.future.timeout( unawaited(sawTick1.future.timeout(
const Duration(seconds: 5), const Duration(seconds: 5),
onTimeout: () { print('The test app is taking longer than expected to print its synchronization line...'); }, onTimeout: () {
// This print is useful for people debugging this test. Normally we would avoid printing in
// a test but this is an exception because it's useful ambient information.
// ignore: avoid_print
print('The test app is taking longer than expected to print its synchronization line...');
},
)); ));
printOnFailure('waiting for synchronization line...');
await sawTick1.future; // after this, app is in steady state await sawTick1.future; // after this, app is in steady state
await flutter.addBreakpoint( await flutter.addBreakpoint(
project.scheduledBreakpointUri, project.scheduledBreakpointUri,
...@@ -126,19 +132,19 @@ void main() { ...@@ -126,19 +132,19 @@ void main() {
); );
bool reloaded = false; bool reloaded = false;
final Future<void> reloadFuture = flutter.hotReload().then((void value) { reloaded = true; }); final Future<void> reloadFuture = flutter.hotReload().then((void value) { reloaded = true; });
print('waiting for pause...'); printOnFailure('waiting for pause...');
isolate = await flutter.waitForPause(); isolate = await flutter.waitForPause();
expect(isolate.pauseEvent.kind, equals(EventKind.kPauseBreakpoint)); expect(isolate.pauseEvent.kind, equals(EventKind.kPauseBreakpoint));
print('waiting for debugger message...'); printOnFailure('waiting for debugger message...');
await sawDebuggerPausedMessage.future; await sawDebuggerPausedMessage.future;
expect(reloaded, isFalse); expect(reloaded, isFalse);
print('waiting for resume...'); printOnFailure('waiting for resume...');
await flutter.resume(); await flutter.resume();
print('waiting for reload future...'); printOnFailure('waiting for reload future...');
await reloadFuture; await reloadFuture;
expect(reloaded, isTrue); expect(reloaded, isTrue);
reloaded = false; reloaded = false;
print('subscription cancel...'); printOnFailure('subscription cancel...');
await subscription.cancel(); await subscription.cancel();
}); });
...@@ -148,7 +154,7 @@ void main() { ...@@ -148,7 +154,7 @@ void main() {
final Completer<void> sawDebuggerPausedMessage2 = Completer<void>(); final Completer<void> sawDebuggerPausedMessage2 = Completer<void>();
final StreamSubscription<String> subscription = flutter.stdout.listen( final StreamSubscription<String> subscription = flutter.stdout.listen(
(String line) { (String line) {
print('[LOG]:"$line"'); printOnFailure('[LOG]:"$line"');
if (line.contains('(((TICK 1)))')) { if (line.contains('(((TICK 1)))')) {
expect(sawTick1.isCompleted, isFalse); expect(sawTick1.isCompleted, isFalse);
sawTick1.complete(); sawTick1.complete();
......
...@@ -47,7 +47,7 @@ void main() { ...@@ -47,7 +47,7 @@ void main() {
onSecondLoad.complete(); onSecondLoad.complete();
} }
}); });
flutter.stdout.listen(print); flutter.stdout.listen(printOnFailure);
await flutter.run(); await flutter.run();
await onFirstLoad.future; await onFirstLoad.future;
...@@ -74,7 +74,7 @@ void main() { ...@@ -74,7 +74,7 @@ void main() {
onSecondLoad.complete(); onSecondLoad.complete();
} }
}); });
flutter.stdout.listen(print); flutter.stdout.listen(printOnFailure);
await flutter.run(); await flutter.run();
await onFirstLoad.future; await onFirstLoad.future;
......
...@@ -29,7 +29,7 @@ void main() { ...@@ -29,7 +29,7 @@ void main() {
'flutter', 'flutter',
); );
final ProcessResult createResult = processManager.runSync(<String>[ processManager.runSync(<String>[
flutterBin, flutterBin,
...getLocalEngineArguments(), ...getLocalEngineArguments(),
'create', 'create',
...@@ -39,7 +39,6 @@ void main() { ...@@ -39,7 +39,6 @@ void main() {
'objc', 'objc',
'hello', 'hello',
], workingDirectory: tempDir.path); ], workingDirectory: tempDir.path);
print(createResult.stdout);
projectRoot = tempDir.childDirectory('hello').path; projectRoot = tempDir.childDirectory('hello').path;
}); });
...@@ -59,7 +58,7 @@ void main() { ...@@ -59,7 +58,7 @@ void main() {
File outputAppFrameworkBinary; File outputAppFrameworkBinary;
setUpAll(() { setUpAll(() {
final ProcessResult buildResult = processManager.runSync(<String>[ processManager.runSync(<String>[
flutterBin, flutterBin,
...getLocalEngineArguments(), ...getLocalEngineArguments(),
'build', 'build',
...@@ -70,7 +69,6 @@ void main() { ...@@ -70,7 +69,6 @@ void main() {
'--obfuscate', '--obfuscate',
'--split-debug-info=foo debug info/', '--split-debug-info=foo debug info/',
], workingDirectory: projectRoot); ], workingDirectory: projectRoot);
print(buildResult.stdout);
buildPath = fileSystem.directory(fileSystem.path.join( buildPath = fileSystem.directory(fileSystem.path.join(
projectRoot, projectRoot,
...@@ -125,7 +123,6 @@ void main() { ...@@ -125,7 +123,6 @@ void main() {
infoPlistPath, infoPlistPath,
], ],
); );
print(bonjourServices.stdout);
final bool bonjourServicesFound = (bonjourServices.stdout as String).contains('_dartobservatory._tcp'); final bool bonjourServicesFound = (bonjourServices.stdout as String).contains('_dartobservatory._tcp');
expect(bonjourServicesFound, buildMode == BuildMode.debug); expect(bonjourServicesFound, buildMode == BuildMode.debug);
...@@ -140,7 +137,6 @@ void main() { ...@@ -140,7 +137,6 @@ void main() {
infoPlistPath, infoPlistPath,
], ],
); );
print(localNetworkUsage.stdout);
final bool localNetworkUsageFound = localNetworkUsage.exitCode == 0; final bool localNetworkUsageFound = localNetworkUsage.exitCode == 0;
expect(localNetworkUsageFound, buildMode == BuildMode.debug); expect(localNetworkUsageFound, buildMode == BuildMode.debug);
}); });
...@@ -155,7 +151,6 @@ void main() { ...@@ -155,7 +151,6 @@ void main() {
'arm64', 'arm64',
], ],
); );
print(symbols.stdout);
final bool aotSymbolsFound = (symbols.stdout as String).contains('_kDartVmSnapshot'); final bool aotSymbolsFound = (symbols.stdout as String).contains('_kDartVmSnapshot');
expect(aotSymbolsFound, buildMode != BuildMode.debug); expect(aotSymbolsFound, buildMode != BuildMode.debug);
}); });
...@@ -197,7 +192,9 @@ void main() { ...@@ -197,7 +192,9 @@ void main() {
// Skip bitcode stripping since we just checked that above. // Skip bitcode stripping since we just checked that above.
}, },
); );
print(xcodeBackendResult.stdout); printOnFailure('Output of xcode_backend.sh:');
printOnFailure(xcodeBackendResult.stdout.toString());
printOnFailure(xcodeBackendResult.stderr.toString());
expect(xcodeBackendResult.exitCode, 0); expect(xcodeBackendResult.exitCode, 0);
expect(outputFlutterFrameworkBinary.existsSync(), isTrue); expect(outputFlutterFrameworkBinary.existsSync(), isTrue);
...@@ -211,7 +208,6 @@ void main() { ...@@ -211,7 +208,6 @@ void main() {
'hello', 'hello',
outputAppFrameworkBinary.path, outputAppFrameworkBinary.path,
]); ]);
print(grepResult.stdout);
expect(grepResult.stdout, isNot(contains('matches'))); expect(grepResult.stdout, isNot(contains('matches')));
}); });
}); });
...@@ -233,7 +229,6 @@ void main() { ...@@ -233,7 +229,6 @@ void main() {
'FLUTTER_XCODE_ONLY_ACTIVE_ARCH': 'NO', 'FLUTTER_XCODE_ONLY_ACTIVE_ARCH': 'NO',
}, },
); );
print(buildSimulator.stdout);
// This test case would fail if arm64 or x86_64 simulators could not build. // This test case would fail if arm64 or x86_64 simulators could not build.
expect(buildSimulator.exitCode, 0); expect(buildSimulator.exitCode, 0);
...@@ -251,7 +246,6 @@ void main() { ...@@ -251,7 +246,6 @@ void main() {
final ProcessResult archs = processManager.runSync( final ProcessResult archs = processManager.runSync(
<String>['file', simulatorAppFrameworkBinary.path], <String>['file', simulatorAppFrameworkBinary.path],
); );
print(archs.stdout);
expect(archs.stdout, contains('Mach-O 64-bit dynamically linked shared library x86_64')); expect(archs.stdout, contains('Mach-O 64-bit dynamically linked shared library x86_64'));
expect(archs.stdout, contains('Mach-O 64-bit dynamically linked shared library arm64')); expect(archs.stdout, contains('Mach-O 64-bit dynamically linked shared library arm64'));
}); });
......
...@@ -53,8 +53,9 @@ void main() { ...@@ -53,8 +53,9 @@ void main() {
]; ];
final ProcessResult result = processManager.runSync(buildCommand, workingDirectory: workingDirectory); final ProcessResult result = processManager.runSync(buildCommand, workingDirectory: workingDirectory);
print(result.stdout); printOnFailure('Output of flutter build macos:');
print(result.stderr); printOnFailure(result.stdout.toString());
printOnFailure(result.stderr.toString());
expect(result.exitCode, 0); expect(result.exitCode, 0);
expect(result.stdout, contains('Running pod install')); expect(result.stdout, contains('Running pod install'));
...@@ -134,8 +135,9 @@ void main() { ...@@ -134,8 +135,9 @@ void main() {
// Build again without cleaning. // Build again without cleaning.
final ProcessResult secondBuild = processManager.runSync(buildCommand, workingDirectory: workingDirectory); final ProcessResult secondBuild = processManager.runSync(buildCommand, workingDirectory: workingDirectory);
print(secondBuild.stdout); printOnFailure('Output of second build:');
print(secondBuild.stderr); printOnFailure(secondBuild.stdout.toString());
printOnFailure(secondBuild.stderr.toString());
expect(secondBuild.exitCode, 0); expect(secondBuild.exitCode, 0);
expect(secondBuild.stdout, isNot(contains('Running pod install'))); expect(secondBuild.stdout, isNot(contains('Running pod install')));
......
...@@ -27,7 +27,7 @@ Future<void> waitForObservatoryMessage(Process process, int port) async { ...@@ -27,7 +27,7 @@ Future<void> waitForObservatoryMessage(Process process, int port) async {
process.stdout process.stdout
.transform(utf8.decoder) .transform(utf8.decoder)
.listen((String line) { .listen((String line) {
print(line); printOnFailure(line);
if (line.contains('An Observatory debugger and profiler on Flutter test device is available at')) { if (line.contains('An Observatory debugger and profiler on Flutter test device is available at')) {
if (line.contains('http://127.0.0.1:$port')) { if (line.contains('http://127.0.0.1:$port')) {
completer.complete(); completer.complete();
...@@ -38,7 +38,7 @@ Future<void> waitForObservatoryMessage(Process process, int port) async { ...@@ -38,7 +38,7 @@ Future<void> waitForObservatoryMessage(Process process, int port) async {
}); });
process.stderr process.stderr
.transform(utf8.decoder) .transform(utf8.decoder)
.listen(print); .listen(printOnFailure);
return completer.future; return completer.future;
} }
......
...@@ -43,6 +43,13 @@ const ProcessManager processManager = LocalProcessManager(); ...@@ -43,6 +43,13 @@ const ProcessManager processManager = LocalProcessManager();
final String flutterRoot = getFlutterRoot(); final String flutterRoot = getFlutterRoot();
final String flutterBin = fileSystem.path.join(flutterRoot, 'bin', 'flutter'); final String flutterBin = fileSystem.path.join(flutterRoot, 'bin', 'flutter');
void debugPrint(String message) {
// This is called to intentionally print debugging output when a test is
// either taking too long or has failed.
// ignore: avoid_print
print(message);
}
typedef LineHandler = String/*?*/ Function(String line); typedef LineHandler = String/*?*/ Function(String line);
abstract class Transition { abstract class Transition {
...@@ -136,7 +143,7 @@ class LogLine { ...@@ -136,7 +143,7 @@ class LogLine {
String toString() => '$stamp $channel: $message'; String toString() => '$stamp $channel: $message';
void printClearly() { void printClearly() {
print('$stamp $channel: ${clarify(message)}'); debugPrint('$stamp $channel: ${clarify(message)}');
} }
static String clarify(String line) { static String clarify(String line) {
...@@ -197,9 +204,9 @@ Future<ProcessTestResult> runFlutter( ...@@ -197,9 +204,9 @@ Future<ProcessTestResult> runFlutter(
int nextTransition = 0; int nextTransition = 0;
void describeStatus() { void describeStatus() {
if (transitions.isNotEmpty) { if (transitions.isNotEmpty) {
print('Expected state transitions:'); debugPrint('Expected state transitions:');
for (int index = 0; index < transitions.length; index += 1) { for (int index = 0; index < transitions.length; index += 1) {
print( debugPrint(
'${index.toString().padLeft(5)} ' '${index.toString().padLeft(5)} '
'${index < nextTransition ? 'ALREADY MATCHED ' : '${index < nextTransition ? 'ALREADY MATCHED ' :
index == nextTransition ? 'NOW WAITING FOR>' : index == nextTransition ? 'NOW WAITING FOR>' :
...@@ -207,9 +214,9 @@ Future<ProcessTestResult> runFlutter( ...@@ -207,9 +214,9 @@ Future<ProcessTestResult> runFlutter(
} }
} }
if (logs.isEmpty) { if (logs.isEmpty) {
print('So far nothing has been logged${ debug ? "" : "; use debug:true to print all output" }.'); debugPrint('So far nothing has been logged${ debug ? "" : "; use debug:true to print all output" }.');
} else { } else {
print('Log${ debug ? "" : " (only contains logged lines; use debug:true to print all output)" }:'); debugPrint('Log${ debug ? "" : " (only contains logged lines; use debug:true to print all output)" }:');
for (final LogLine log in logs) { for (final LogLine log in logs) {
log.printClearly(); log.printClearly();
} }
...@@ -221,12 +228,12 @@ Future<ProcessTestResult> runFlutter( ...@@ -221,12 +228,12 @@ Future<ProcessTestResult> runFlutter(
if (!streamingLogs) { if (!streamingLogs) {
streamingLogs = true; streamingLogs = true;
if (!debug) { if (!debug) {
print('Test is taking a long time (${clock.elapsed.inSeconds} seconds so far).'); debugPrint('Test is taking a long time (${clock.elapsed.inSeconds} seconds so far).');
} }
describeStatus(); describeStatus();
print('(streaming all logs from this point on...)'); debugPrint('(streaming all logs from this point on...)');
} else { } else {
print('(taking a long time...)'); debugPrint('(taking a long time...)');
} }
} }
String stamp() => '[${(clock.elapsed.inMilliseconds / 1000.0).toStringAsFixed(1).padLeft(5, " ")}s]'; String stamp() => '[${(clock.elapsed.inMilliseconds / 1000.0).toStringAsFixed(1).padLeft(5, " ")}s]';
...@@ -240,7 +247,7 @@ Future<ProcessTestResult> runFlutter( ...@@ -240,7 +247,7 @@ Future<ProcessTestResult> runFlutter(
} }
if (nextTransition < transitions.length && transitions[nextTransition].matches(line)) { if (nextTransition < transitions.length && transitions[nextTransition].matches(line)) {
if (streamingLogs) { if (streamingLogs) {
print('(matched ${transitions[nextTransition]})'); debugPrint('(matched ${transitions[nextTransition]})');
} }
if (transitions[nextTransition].logging != null) { if (transitions[nextTransition].logging != null) {
if (!logging && transitions[nextTransition].logging/*!*/) { if (!logging && transitions[nextTransition].logging/*!*/) {
...@@ -249,9 +256,9 @@ Future<ProcessTestResult> runFlutter( ...@@ -249,9 +256,9 @@ Future<ProcessTestResult> runFlutter(
logging = transitions[nextTransition].logging/*!*/; logging = transitions[nextTransition].logging/*!*/;
if (streamingLogs) { if (streamingLogs) {
if (logging) { if (logging) {
print('(enabled logging)'); debugPrint('(enabled logging)');
} else { } else {
print('(disabled logging)'); debugPrint('(disabled logging)');
} }
} }
} }
...@@ -286,8 +293,8 @@ Future<ProcessTestResult> runFlutter( ...@@ -286,8 +293,8 @@ Future<ProcessTestResult> runFlutter(
process.stdout.transform<String>(utf8.decoder).transform<String>(const LineSplitter()).listen(processStdout); process.stdout.transform<String>(utf8.decoder).transform<String>(const LineSplitter()).listen(processStdout);
process.stderr.transform<String>(utf8.decoder).transform<String>(const LineSplitter()).listen(processStderr); process.stderr.transform<String>(utf8.decoder).transform<String>(const LineSplitter()).listen(processStderr);
unawaited(process.exitCode.timeout(expectedMaxDuration, onTimeout: () { // This is a failure timeout, must not be short. unawaited(process.exitCode.timeout(expectedMaxDuration, onTimeout: () { // This is a failure timeout, must not be short.
print('${stamp()} (process is not quitting, trying to send a "q" just in case that helps)'); debugPrint('${stamp()} (process is not quitting, trying to send a "q" just in case that helps)');
print('(a functional test should never reach this point)'); debugPrint('(a functional test should never reach this point)');
final LogLine inLog = LogLine('stdin', stamp(), 'q'); final LogLine inLog = LogLine('stdin', stamp(), 'q');
logs.add(inLog); logs.add(inLog);
if (streamingLogs) { if (streamingLogs) {
...@@ -298,24 +305,24 @@ Future<ProcessTestResult> runFlutter( ...@@ -298,24 +305,24 @@ Future<ProcessTestResult> runFlutter(
}).catchError((Object error) { /* ignore errors here, they will be reported on the next line */ })); }).catchError((Object error) { /* ignore errors here, they will be reported on the next line */ }));
final int exitCode = await process.exitCode; final int exitCode = await process.exitCode;
if (streamingLogs) { if (streamingLogs) {
print('${stamp()} (process terminated with exit code $exitCode)'); debugPrint('${stamp()} (process terminated with exit code $exitCode)');
} }
timeout?.cancel(); timeout?.cancel();
if (nextTransition < transitions.length) { if (nextTransition < transitions.length) {
print('The subprocess terminated before all the expected transitions had been matched.'); debugPrint('The subprocess terminated before all the expected transitions had been matched.');
if (logs.any((LogLine line) => line.couldBeCrash)) { if (logs.any((LogLine line) => line.couldBeCrash)) {
print('The subprocess may in fact have crashed. Check the stderr logs below.'); debugPrint('The subprocess may in fact have crashed. Check the stderr logs below.');
} }
print('The transition that we were hoping to see next but that we never saw was:'); debugPrint('The transition that we were hoping to see next but that we never saw was:');
print('${nextTransition.toString().padLeft(5)} NOW WAITING FOR> ${transitions[nextTransition]}'); debugPrint('${nextTransition.toString().padLeft(5)} NOW WAITING FOR> ${transitions[nextTransition]}');
if (!streamingLogs) { if (!streamingLogs) {
describeStatus(); describeStatus();
print('(process terminated with exit code $exitCode)'); debugPrint('(process terminated with exit code $exitCode)');
} }
throw TestFailure('Missed some expected transitions.'); throw TestFailure('Missed some expected transitions.');
} }
if (streamingLogs) { if (streamingLogs) {
print('${stamp()} (completed execution successfully!)'); debugPrint('${stamp()} (completed execution successfully!)');
} }
return ProcessTestResult(exitCode, logs); return ProcessTestResult(exitCode, logs);
} }
......
...@@ -79,6 +79,10 @@ abstract class FlutterTestDriver { ...@@ -79,6 +79,10 @@ abstract class FlutterTestDriver {
lastTime = time; lastTime = time;
} }
if (_printDebugOutputToStdOut) { if (_printDebugOutputToStdOut) {
// This is the one place in this file that can call print. It is gated by
// _printDebugOutputToStdOut which should not be set to true in CI; it is
// intended only for use in local debugging.
// ignore: avoid_print
print('$time$_logPrefix$line'); print('$time$_logPrefix$line');
} }
} }
......
...@@ -215,6 +215,10 @@ void main() { ...@@ -215,6 +215,10 @@ void main() {
} }
expect(result.exitCode, 0); expect(result.exitCode, 0);
}); });
testWithoutContext('flutter gold skips tests where the expectations are missing', () async {
return _testFile('flutter_gold', automatedTestsDirectory, flutterTestDirectory, exitCode: isZero);
});
} }
Future<void> _testFile( Future<void> _testFile(
......
...@@ -40,6 +40,8 @@ void main() { ...@@ -40,6 +40,8 @@ void main() {
// Regression test for https://github.com/flutter/flutter/issues/79498 // Regression test for https://github.com/flutter/flutter/issues/79498
testWithoutContext('Can connect to the timeline without getting ANR from the application', () async { testWithoutContext('Can connect to the timeline without getting ANR from the application', () async {
final Timer timer = Timer(const Duration(minutes: 5), () { final Timer timer = Timer(const Duration(minutes: 5), () {
// This message is intended to show up in CI logs.
// ignore: avoid_print
print( print(
'Warning: test isolate is still active after 5 minutes. This is likely an ' 'Warning: test isolate is still active after 5 minutes. This is likely an '
'app-not-responding error and not a flake. See https://github.com/flutter/flutter/issues/79498 ' 'app-not-responding error and not a flake. See https://github.com/flutter/flutter/issues/79498 '
......
...@@ -4,5 +4,6 @@ ...@@ -4,5 +4,6 @@
// Not a test file, invoked by `variable_expansion_windows_test.dart`. // Not a test file, invoked by `variable_expansion_windows_test.dart`.
void main(List<String> args) { void main(List<String> args) {
print('args: $args'); // This print is used for communicating with the test host.
print('args: $args'); // ignore: avoid_print
} }
...@@ -27,6 +27,9 @@ void tryToDelete(Directory directory) { ...@@ -27,6 +27,9 @@ void tryToDelete(Directory directory) {
directory.deleteSync(recursive: true); directory.deleteSync(recursive: true);
} }
} on FileSystemException catch (error) { } on FileSystemException catch (error) {
// We print this so that it's visible in the logs, to get an idea of how
// common this problem is, and if any patterns are ever noticed by anyone.
// ignore: avoid_print
print('Failed to delete ${directory.path}: $error'); print('Failed to delete ${directory.path}: $error');
} }
} }
......
...@@ -127,7 +127,7 @@ void testUsingContext( ...@@ -127,7 +127,7 @@ void testUsingContext(
}, },
body: () { body: () {
final String flutterRoot = getFlutterRoot(); final String flutterRoot = getFlutterRoot();
return runZoned<Future<dynamic>>(() { return runZonedGuarded<Future<dynamic>>(() {
try { try {
return context.run<dynamic>( return context.run<dynamic>(
// Apply the overrides to the test context in the zone since their // Apply the overrides to the test context in the zone since their
...@@ -148,9 +148,10 @@ void testUsingContext( ...@@ -148,9 +148,10 @@ void testUsingContext(
_printBufferedErrors(context); _printBufferedErrors(context);
rethrow; rethrow;
} }
}, onError: (Object error, StackTrace stackTrace) { // ignore: deprecated_member_use }, (Object error, StackTrace stackTrace) {
print(error); // When things fail, it's ok to print to the console!
print(stackTrace); print(error); // ignore: avoid_print
print(stackTrace); // ignore: avoid_print
_printBufferedErrors(context); _printBufferedErrors(context);
throw error; throw error;
}); });
...@@ -176,7 +177,9 @@ void _printBufferedErrors(AppContext testContext) { ...@@ -176,7 +177,9 @@ void _printBufferedErrors(AppContext testContext) {
if (testContext.get<Logger>() is BufferLogger) { if (testContext.get<Logger>() is BufferLogger) {
final BufferLogger bufferLogger = testContext.get<Logger>() as BufferLogger; final BufferLogger bufferLogger = testContext.get<Logger>() as BufferLogger;
if (bufferLogger.errorText.isNotEmpty) { if (bufferLogger.errorText.isNotEmpty) {
print(bufferLogger.errorText); // This is where the logger outputting errors is implemented, so it has
// to use `print`.
print(bufferLogger.errorText); // ignore: avoid_print
} }
bufferLogger.clear(); bufferLogger.clear();
} }
......
...@@ -38,7 +38,6 @@ void main() { ...@@ -38,7 +38,6 @@ void main() {
testWithoutContext('newly added code executes during hot restart', () async { testWithoutContext('newly added code executes during hot restart', () async {
final Completer<void> completer = Completer<void>(); final Completer<void> completer = Completer<void>();
final StreamSubscription<String> subscription = flutter.stdout.listen((String line) { final StreamSubscription<String> subscription = flutter.stdout.listen((String line) {
print(line);
if (line.contains('(((((RELOAD WORKED)))))')) { if (line.contains('(((((RELOAD WORKED)))))')) {
completer.complete(); completer.complete();
} }
...@@ -56,7 +55,6 @@ void main() { ...@@ -56,7 +55,6 @@ void main() {
testWithoutContext('newly added code executes during hot restart - canvaskit', () async { testWithoutContext('newly added code executes during hot restart - canvaskit', () async {
final Completer<void> completer = Completer<void>(); final Completer<void> completer = Completer<void>();
final StreamSubscription<String> subscription = flutter.stdout.listen((String line) { final StreamSubscription<String> subscription = flutter.stdout.listen((String line) {
print(line);
if (line.contains('(((((RELOAD WORKED)))))')) { if (line.contains('(((((RELOAD WORKED)))))')) {
completer.complete(); completer.complete();
} }
......
include: ../analysis_options.yaml
linter:
rules:
avoid_print: false # These are CLI tools which print as a matter of course.
...@@ -51,6 +51,7 @@ typedef LoggingFunction = void Function(LogMessage log); ...@@ -51,6 +51,7 @@ typedef LoggingFunction = void Function(LogMessage log);
/// ///
/// Exits with status code 1 if the `log` is [LoggingLevel.severe]. /// Exits with status code 1 if the `log` is [LoggingLevel.severe].
void defaultLoggingFunction(LogMessage log) { void defaultLoggingFunction(LogMessage log) {
// ignore: avoid_print
print('[${log.levelName}]::${log.tag}--${log.time}: ${log.message}'); print('[${log.levelName}]::${log.tag}--${log.time}: ${log.message}');
if (log.level == LoggingLevel.severe) { if (log.level == LoggingLevel.severe) {
exit(1); exit(1);
......
...@@ -64,7 +64,7 @@ class IntegrationTestWidgetsFlutterBinding extends LiveTestWidgetsFlutterBinding ...@@ -64,7 +64,7 @@ class IntegrationTestWidgetsFlutterBinding extends LiveTestWidgetsFlutterBinding
}, },
); );
} on MissingPluginException { } on MissingPluginException {
print(r''' debugPrint(r'''
Warning: integration_test plugin was not detected. Warning: integration_test plugin was not detected.
If you're running the tests with `flutter drive`, please make sure your tests If you're running the tests with `flutter drive`, please make sure your tests
...@@ -391,7 +391,7 @@ https://flutter.dev/docs/testing/integration-tests#testing-on-firebase-test-lab ...@@ -391,7 +391,7 @@ https://flutter.dev/docs/testing/integration-tests#testing-on-firebase-test-lab
count++; count++;
await Future<void>.delayed(const Duration(seconds: 2)); await Future<void>.delayed(const Duration(seconds: 2));
if (count > 20) { if (count > 20) {
print('delayForFrameTimings is taking longer than expected...'); debugPrint('delayForFrameTimings is taking longer than expected...');
} }
} }
} }
......
...@@ -2,6 +2,9 @@ ...@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// This is a CLI library; we use prints as part of the interface.
// ignore_for_file: avoid_print
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
......
...@@ -2,6 +2,9 @@ ...@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// This is a CLI library; we use prints as part of the interface.
// ignore_for_file: avoid_print
import 'dart:async'; import 'dart:async';
import 'dart:io'; import 'dart:io';
......
...@@ -104,7 +104,6 @@ Future<void> main() async { ...@@ -104,7 +104,6 @@ Future<void> main() async {
testWidgets('Test traceAction', (WidgetTester tester) async { testWidgets('Test traceAction', (WidgetTester tester) async {
await integrationBinding.enableTimeline(vmService: fakeVM); await integrationBinding.enableTimeline(vmService: fakeVM);
await integrationBinding.traceAction(() async {}); await integrationBinding.traceAction(() async {});
print(integrationBinding.reportData);
expect(integrationBinding.reportData, isNotNull); expect(integrationBinding.reportData, isNotNull);
expect(integrationBinding.reportData!.containsKey('timeline'), true); expect(integrationBinding.reportData!.containsKey('timeline'), true);
expect( expect(
......
...@@ -10,6 +10,8 @@ import 'package:integration_test/integration_test.dart'; ...@@ -10,6 +10,8 @@ import 'package:integration_test/integration_test.dart';
Future<void> main() async { Future<void> main() async {
final IntegrationTestWidgetsFlutterBinding binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized() as IntegrationTestWidgetsFlutterBinding; final IntegrationTestWidgetsFlutterBinding binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized() as IntegrationTestWidgetsFlutterBinding;
binding.allTestsPassed.future.then((_) { binding.allTestsPassed.future.then((_) {
// We use this print to communicate with ../binding_fail_test.dart
// ignore: avoid_print
print('IntegrationTestWidgetsFlutterBinding test results: ${jsonEncode(binding.results)}'); print('IntegrationTestWidgetsFlutterBinding test results: ${jsonEncode(binding.results)}');
}); });
......
...@@ -10,6 +10,8 @@ import 'package:integration_test/integration_test.dart'; ...@@ -10,6 +10,8 @@ import 'package:integration_test/integration_test.dart';
Future<void> main() async { Future<void> main() async {
final IntegrationTestWidgetsFlutterBinding binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized() as IntegrationTestWidgetsFlutterBinding; final IntegrationTestWidgetsFlutterBinding binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized() as IntegrationTestWidgetsFlutterBinding;
binding.allTestsPassed.future.then((_) { binding.allTestsPassed.future.then((_) {
// We use this print to communicate with ../binding_fail_test.dart
// ignore: avoid_print
print('IntegrationTestWidgetsFlutterBinding test results: ${jsonEncode(binding.results)}'); print('IntegrationTestWidgetsFlutterBinding test results: ${jsonEncode(binding.results)}');
}); });
......
...@@ -10,6 +10,8 @@ import 'package:integration_test/integration_test.dart'; ...@@ -10,6 +10,8 @@ import 'package:integration_test/integration_test.dart';
Future<void> main() async { Future<void> main() async {
final IntegrationTestWidgetsFlutterBinding binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized() as IntegrationTestWidgetsFlutterBinding; final IntegrationTestWidgetsFlutterBinding binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized() as IntegrationTestWidgetsFlutterBinding;
binding.allTestsPassed.future.then((_) { binding.allTestsPassed.future.then((_) {
// We use this print to communicate with ../binding_fail_test.dart
// ignore: avoid_print
print('IntegrationTestWidgetsFlutterBinding test results: ${jsonEncode(binding.results)}'); print('IntegrationTestWidgetsFlutterBinding test results: ${jsonEncode(binding.results)}');
}); });
......
...@@ -10,6 +10,8 @@ import 'package:integration_test/integration_test.dart'; ...@@ -10,6 +10,8 @@ import 'package:integration_test/integration_test.dart';
Future<void> main() async { Future<void> main() async {
final IntegrationTestWidgetsFlutterBinding binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized() as IntegrationTestWidgetsFlutterBinding; final IntegrationTestWidgetsFlutterBinding binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized() as IntegrationTestWidgetsFlutterBinding;
binding.allTestsPassed.future.then((_) { binding.allTestsPassed.future.then((_) {
// We use this print to communicate with ../binding_fail_test.dart
// ignore: avoid_print
print('IntegrationTestWidgetsFlutterBinding test results: ${jsonEncode(binding.results)}'); print('IntegrationTestWidgetsFlutterBinding test results: ${jsonEncode(binding.results)}');
}); });
......
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