mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00

This auto-formats all *.dart files in the repository outside of the `engine` subdirectory and enforces that these files stay formatted with a presubmit check. **Reviewers:** Please carefully review all the commits except for the one titled "formatted". The "formatted" commit was auto-generated by running `dev/tools/format.sh -a -f`. The other commits were hand-crafted to prepare the repo for the formatting change. I recommend reviewing the commits one-by-one via the "Commits" tab and avoiding Github's "Files changed" tab as it will likely slow down your browser because of the size of this PR. --------- Co-authored-by: Kate Lovett <katelovett@google.com> Co-authored-by: LongCatIsLooong <31859944+LongCatIsLooong@users.noreply.github.com>
435 lines
15 KiB
Dart
435 lines
15 KiB
Dart
// 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.
|
|
|
|
import 'package:args/command_runner.dart';
|
|
import 'package:file/memory.dart';
|
|
import 'package:flutter_tools/src/base/file_system.dart';
|
|
import 'package:flutter_tools/src/cache.dart';
|
|
import 'package:flutter_tools/src/commands/channel.dart';
|
|
import 'package:flutter_tools/src/globals.dart' as globals;
|
|
import 'package:flutter_tools/src/version.dart';
|
|
|
|
import '../src/common.dart';
|
|
import '../src/context.dart';
|
|
import '../src/fake_process_manager.dart';
|
|
import '../src/fakes.dart' show FakeFlutterVersion;
|
|
import '../src/test_flutter_command_runner.dart';
|
|
|
|
void main() {
|
|
group('channel', () {
|
|
late FakeProcessManager fakeProcessManager;
|
|
|
|
setUp(() {
|
|
fakeProcessManager = FakeProcessManager.empty();
|
|
});
|
|
|
|
setUpAll(() {
|
|
Cache.disableLocking();
|
|
});
|
|
|
|
Future<void> simpleChannelTest(List<String> args) async {
|
|
fakeProcessManager.addCommands(const <FakeCommand>[
|
|
FakeCommand(
|
|
command: <String>['git', 'branch', '-r'],
|
|
stdout:
|
|
' origin/branch-1\n'
|
|
' origin/branch-2\n'
|
|
' origin/master\n'
|
|
' origin/main\n'
|
|
' origin/stable\n'
|
|
' origin/beta',
|
|
),
|
|
]);
|
|
final ChannelCommand command = ChannelCommand();
|
|
final CommandRunner<void> runner = createTestCommandRunner(command);
|
|
await runner.run(args);
|
|
expect(testLogger.errorText, hasLength(0));
|
|
// The bots may return an empty list of channels (network hiccup?)
|
|
// and when run locally the list of branches might be different
|
|
// so we check for the header text rather than any specific channel name.
|
|
expect(testLogger.statusText, containsIgnoringWhitespace('Flutter channels:'));
|
|
}
|
|
|
|
testUsingContext(
|
|
'usage (--help) explains how to use channel',
|
|
() async {
|
|
final ChannelCommand command = ChannelCommand();
|
|
|
|
// Required because otherwise command.usage fails as it is not hooked up.
|
|
createTestCommandRunner(command);
|
|
|
|
// TODO(matanlurey): https://github.com/flutter/flutter/issues/158532
|
|
//
|
|
// <Command>.usage is checked instead of log output because by default
|
|
// every command emits usage directly to stdout (via print) instead of
|
|
// to the interfaces provided. It would be a much larger refactor to
|
|
// change how every command works:
|
|
expect(
|
|
command.usage,
|
|
stringContainsInOrder(<String>[
|
|
'List or switch Flutter channels',
|
|
'Common commands:',
|
|
'List Flutter channels',
|
|
"Switch to Flutter's main channel.",
|
|
]),
|
|
);
|
|
},
|
|
overrides: <Type, Generator>{
|
|
ProcessManager: () => FakeProcessManager.empty(),
|
|
FileSystem: () => MemoryFileSystem.test(),
|
|
},
|
|
);
|
|
|
|
testUsingContext(
|
|
'list',
|
|
() async {
|
|
await simpleChannelTest(<String>['channel']);
|
|
},
|
|
overrides: <Type, Generator>{
|
|
ProcessManager: () => fakeProcessManager,
|
|
FileSystem: () => MemoryFileSystem.test(),
|
|
},
|
|
);
|
|
|
|
testUsingContext(
|
|
'verbose list',
|
|
() async {
|
|
await simpleChannelTest(<String>['channel', '-v']);
|
|
},
|
|
overrides: <Type, Generator>{
|
|
ProcessManager: () => fakeProcessManager,
|
|
FileSystem: () => MemoryFileSystem.test(),
|
|
},
|
|
);
|
|
|
|
testUsingContext(
|
|
'sorted by stability',
|
|
() async {
|
|
final ChannelCommand command = ChannelCommand();
|
|
final CommandRunner<void> runner = createTestCommandRunner(command);
|
|
|
|
fakeProcessManager.addCommand(
|
|
const FakeCommand(
|
|
command: <String>['git', 'branch', '-r'],
|
|
stdout:
|
|
'origin/beta\n'
|
|
'origin/master\n'
|
|
'origin/main\n'
|
|
'origin/stable\n',
|
|
),
|
|
);
|
|
|
|
await runner.run(<String>['channel']);
|
|
expect(fakeProcessManager, hasNoRemainingExpectations);
|
|
expect(testLogger.errorText, hasLength(0));
|
|
expect(
|
|
testLogger.statusText,
|
|
'Flutter channels:\n'
|
|
'* master (latest development branch, for contributors)\n'
|
|
' main (latest development branch, follows master channel)\n'
|
|
' beta (updated monthly, recommended for experienced users)\n'
|
|
' stable (updated quarterly, for new users and for production app releases)\n',
|
|
);
|
|
|
|
// clear buffer for next process
|
|
testLogger.clear();
|
|
|
|
// Extra branches.
|
|
fakeProcessManager.addCommand(
|
|
const FakeCommand(
|
|
command: <String>['git', 'branch', '-r'],
|
|
stdout:
|
|
'origin/beta\n'
|
|
'origin/master\n'
|
|
'origin/dependabot/bundler\n'
|
|
'origin/main\n'
|
|
'origin/v1.4.5-hotfixes\n'
|
|
'origin/stable\n',
|
|
),
|
|
);
|
|
|
|
await runner.run(<String>['channel']);
|
|
expect(fakeProcessManager, hasNoRemainingExpectations);
|
|
expect(testLogger.errorText, hasLength(0));
|
|
expect(
|
|
testLogger.statusText,
|
|
'Flutter channels:\n'
|
|
'* master (latest development branch, for contributors)\n'
|
|
' main (latest development branch, follows master channel)\n'
|
|
' beta (updated monthly, recommended for experienced users)\n'
|
|
' stable (updated quarterly, for new users and for production app releases)\n',
|
|
);
|
|
|
|
// clear buffer for next process
|
|
testLogger.clear();
|
|
|
|
// Missing branches.
|
|
fakeProcessManager.addCommand(
|
|
const FakeCommand(
|
|
command: <String>['git', 'branch', '-r'],
|
|
stdout:
|
|
'origin/master\n'
|
|
'origin/dependabot/bundler\n'
|
|
'origin/v1.4.5-hotfixes\n'
|
|
'origin/stable\n'
|
|
'origin/beta\n',
|
|
),
|
|
);
|
|
|
|
await runner.run(<String>['channel']);
|
|
expect(fakeProcessManager, hasNoRemainingExpectations);
|
|
expect(testLogger.errorText, hasLength(0));
|
|
// check if available official channels are in order of stability
|
|
int prev = -1;
|
|
int next = -1;
|
|
for (final String branch in kOfficialChannels) {
|
|
next = testLogger.statusText.indexOf(branch);
|
|
if (next != -1) {
|
|
expect(prev < next, isTrue);
|
|
prev = next;
|
|
}
|
|
}
|
|
},
|
|
overrides: <Type, Generator>{
|
|
ProcessManager: () => fakeProcessManager,
|
|
FileSystem: () => MemoryFileSystem.test(),
|
|
},
|
|
);
|
|
|
|
testUsingContext(
|
|
'ignores lines with unexpected output',
|
|
() async {
|
|
fakeProcessManager.addCommand(
|
|
const FakeCommand(
|
|
command: <String>['git', 'branch', '-r'],
|
|
stdout:
|
|
'origin/beta\n'
|
|
'origin/stable\n'
|
|
'upstream/beta\n'
|
|
'upstream/stable\n'
|
|
'foo',
|
|
),
|
|
);
|
|
|
|
final ChannelCommand command = ChannelCommand();
|
|
final CommandRunner<void> runner = createTestCommandRunner(command);
|
|
await runner.run(<String>['channel']);
|
|
|
|
expect(fakeProcessManager, hasNoRemainingExpectations);
|
|
expect(testLogger.errorText, hasLength(0));
|
|
expect(
|
|
testLogger.statusText,
|
|
'Flutter channels:\n'
|
|
'* beta (updated monthly, recommended for experienced users)\n'
|
|
' stable (updated quarterly, for new users and for production app releases)\n',
|
|
);
|
|
},
|
|
overrides: <Type, Generator>{
|
|
ProcessManager: () => fakeProcessManager,
|
|
FileSystem: () => MemoryFileSystem.test(),
|
|
FlutterVersion: () => FakeFlutterVersion(branch: 'beta'),
|
|
},
|
|
);
|
|
|
|
testUsingContext(
|
|
'handles custom branches',
|
|
() async {
|
|
fakeProcessManager.addCommand(
|
|
const FakeCommand(
|
|
command: <String>['git', 'branch', '-r'],
|
|
stdout:
|
|
'origin/beta\n'
|
|
'origin/stable\n'
|
|
'origin/foo',
|
|
),
|
|
);
|
|
|
|
final ChannelCommand command = ChannelCommand();
|
|
final CommandRunner<void> runner = createTestCommandRunner(command);
|
|
await runner.run(<String>['channel']);
|
|
|
|
expect(fakeProcessManager, hasNoRemainingExpectations);
|
|
expect(testLogger.errorText, hasLength(0));
|
|
expect(
|
|
testLogger.statusText,
|
|
'Flutter channels:\n'
|
|
' beta (updated monthly, recommended for experienced users)\n'
|
|
' stable (updated quarterly, for new users and for production app releases)\n'
|
|
'* foo\n'
|
|
'\n'
|
|
'Currently not on an official channel.\n',
|
|
);
|
|
},
|
|
overrides: <Type, Generator>{
|
|
ProcessManager: () => fakeProcessManager,
|
|
FileSystem: () => MemoryFileSystem.test(),
|
|
FlutterVersion: () => FakeFlutterVersion(branch: 'foo'),
|
|
},
|
|
);
|
|
|
|
testUsingContext(
|
|
'removes duplicates',
|
|
() async {
|
|
fakeProcessManager.addCommand(
|
|
const FakeCommand(
|
|
command: <String>['git', 'branch', '-r'],
|
|
stdout:
|
|
'origin/beta\n'
|
|
'origin/stable\n'
|
|
'upstream/beta\n'
|
|
'upstream/stable\n',
|
|
),
|
|
);
|
|
|
|
final ChannelCommand command = ChannelCommand();
|
|
final CommandRunner<void> runner = createTestCommandRunner(command);
|
|
await runner.run(<String>['channel']);
|
|
|
|
expect(fakeProcessManager, hasNoRemainingExpectations);
|
|
expect(testLogger.errorText, hasLength(0));
|
|
expect(
|
|
testLogger.statusText,
|
|
'Flutter channels:\n'
|
|
'* beta (updated monthly, recommended for experienced users)\n'
|
|
' stable (updated quarterly, for new users and for production app releases)\n',
|
|
);
|
|
},
|
|
overrides: <Type, Generator>{
|
|
ProcessManager: () => fakeProcessManager,
|
|
FileSystem: () => MemoryFileSystem.test(),
|
|
FlutterVersion: () => FakeFlutterVersion(branch: 'beta'),
|
|
},
|
|
);
|
|
|
|
testUsingContext(
|
|
'can switch channels',
|
|
() async {
|
|
fakeProcessManager.addCommands(const <FakeCommand>[
|
|
FakeCommand(command: <String>['git', 'fetch']),
|
|
FakeCommand(
|
|
command: <String>['git', 'show-ref', '--verify', '--quiet', 'refs/heads/beta'],
|
|
),
|
|
FakeCommand(command: <String>['git', 'checkout', 'beta', '--']),
|
|
FakeCommand(
|
|
command: <String>['bin/flutter', '--no-color', '--no-version-check', 'precache'],
|
|
),
|
|
]);
|
|
|
|
final ChannelCommand command = ChannelCommand();
|
|
final CommandRunner<void> runner = createTestCommandRunner(command);
|
|
await runner.run(<String>['channel', 'beta']);
|
|
|
|
expect(fakeProcessManager, hasNoRemainingExpectations);
|
|
expect(
|
|
testLogger.statusText,
|
|
containsIgnoringWhitespace("Switching to flutter channel 'beta'..."),
|
|
);
|
|
expect(testLogger.errorText, hasLength(0));
|
|
|
|
fakeProcessManager.addCommands(const <FakeCommand>[
|
|
FakeCommand(command: <String>['git', 'fetch']),
|
|
FakeCommand(
|
|
command: <String>['git', 'show-ref', '--verify', '--quiet', 'refs/heads/stable'],
|
|
),
|
|
FakeCommand(command: <String>['git', 'checkout', 'stable', '--']),
|
|
FakeCommand(
|
|
command: <String>['bin/flutter', '--no-color', '--no-version-check', 'precache'],
|
|
),
|
|
]);
|
|
|
|
await runner.run(<String>['channel', 'stable']);
|
|
|
|
expect(fakeProcessManager, hasNoRemainingExpectations);
|
|
},
|
|
overrides: <Type, Generator>{
|
|
FileSystem: () => MemoryFileSystem.test(),
|
|
ProcessManager: () => fakeProcessManager,
|
|
},
|
|
);
|
|
|
|
testUsingContext(
|
|
'switching channels prompts to run flutter upgrade',
|
|
() async {
|
|
fakeProcessManager.addCommands(const <FakeCommand>[
|
|
FakeCommand(command: <String>['git', 'fetch']),
|
|
FakeCommand(
|
|
command: <String>['git', 'show-ref', '--verify', '--quiet', 'refs/heads/beta'],
|
|
),
|
|
FakeCommand(command: <String>['git', 'checkout', 'beta', '--']),
|
|
FakeCommand(
|
|
command: <String>['bin/flutter', '--no-color', '--no-version-check', 'precache'],
|
|
),
|
|
]);
|
|
|
|
final ChannelCommand command = ChannelCommand();
|
|
final CommandRunner<void> runner = createTestCommandRunner(command);
|
|
await runner.run(<String>['channel', 'beta']);
|
|
|
|
expect(
|
|
testLogger.statusText,
|
|
containsIgnoringWhitespace("Successfully switched to flutter channel 'beta'."),
|
|
);
|
|
expect(
|
|
testLogger.statusText,
|
|
containsIgnoringWhitespace(
|
|
"To ensure that you're on the latest build "
|
|
"from this channel, run 'flutter upgrade'",
|
|
),
|
|
);
|
|
expect(testLogger.errorText, hasLength(0));
|
|
expect(fakeProcessManager, hasNoRemainingExpectations);
|
|
},
|
|
overrides: <Type, Generator>{
|
|
FileSystem: () => MemoryFileSystem.test(),
|
|
ProcessManager: () => fakeProcessManager,
|
|
},
|
|
);
|
|
|
|
// This verifies that bug https://github.com/flutter/flutter/issues/21134
|
|
// doesn't return.
|
|
testUsingContext(
|
|
'removes version stamp file when switching channels',
|
|
() async {
|
|
fakeProcessManager.addCommands(const <FakeCommand>[
|
|
FakeCommand(command: <String>['git', 'fetch']),
|
|
FakeCommand(
|
|
command: <String>['git', 'show-ref', '--verify', '--quiet', 'refs/heads/beta'],
|
|
),
|
|
FakeCommand(command: <String>['git', 'checkout', 'beta', '--']),
|
|
FakeCommand(
|
|
command: <String>['bin/flutter', '--no-color', '--no-version-check', 'precache'],
|
|
),
|
|
]);
|
|
|
|
final File versionCheckFile = globals.cache.getStampFileFor(
|
|
VersionCheckStamp.flutterVersionCheckStampFile,
|
|
);
|
|
|
|
/// Create a bogus "leftover" version check file to make sure it gets
|
|
/// removed when the channel changes. The content doesn't matter.
|
|
versionCheckFile.createSync(recursive: true);
|
|
versionCheckFile.writeAsStringSync('''
|
|
{
|
|
"lastTimeVersionWasChecked": "2151-08-29 10:17:30.763802",
|
|
"lastKnownRemoteVersion": "2151-09-26 15:56:19.000Z"
|
|
}
|
|
''');
|
|
|
|
final ChannelCommand command = ChannelCommand();
|
|
final CommandRunner<void> runner = createTestCommandRunner(command);
|
|
await runner.run(<String>['channel', 'beta']);
|
|
|
|
expect(testLogger.statusText, isNot(contains('A new version of Flutter')));
|
|
expect(testLogger.errorText, hasLength(0));
|
|
expect(versionCheckFile.existsSync(), isFalse);
|
|
expect(fakeProcessManager, hasNoRemainingExpectations);
|
|
},
|
|
overrides: <Type, Generator>{
|
|
FileSystem: () => MemoryFileSystem.test(),
|
|
ProcessManager: () => fakeProcessManager,
|
|
},
|
|
);
|
|
});
|
|
}
|