diff --git a/packages/flutter_tools/lib/src/android/android_studio_validator.dart b/packages/flutter_tools/lib/src/android/android_studio_validator.dart index 6c8e4a82f5..c35ee5ebb7 100644 --- a/packages/flutter_tools/lib/src/android/android_studio_validator.dart +++ b/packages/flutter_tools/lib/src/android/android_studio_validator.dart @@ -16,12 +16,17 @@ const String _androidStudioPreviewTitle = 'Android Studio Preview'; const String _androidStudioPreviewId = 'AndroidStudioPreview'; class AndroidStudioValidator extends DoctorValidator { - AndroidStudioValidator(this._studio, { required FileSystem fileSystem }) - : _fileSystem = fileSystem, + AndroidStudioValidator(this._studio, { + required FileSystem fileSystem, + required UserMessages userMessages, + }) + : _userMessages = userMessages, + _fileSystem = fileSystem, super('Android Studio'); final AndroidStudio _studio; final FileSystem _fileSystem; + final UserMessages _userMessages; static const Map idToTitle = { _androidStudioId: _androidStudioTitle, @@ -35,7 +40,7 @@ class AndroidStudioValidator extends DoctorValidator { NoAndroidStudioValidator(config: config, platform: platform, userMessages: userMessages) else ...studios.map( - (AndroidStudio studio) => AndroidStudioValidator(studio, fileSystem: fileSystem) + (AndroidStudio studio) => AndroidStudioValidator(studio, fileSystem: fileSystem, userMessages: userMessages) ), ]; } @@ -45,11 +50,11 @@ class AndroidStudioValidator extends DoctorValidator { final List messages = []; ValidationType type = ValidationType.missing; - final String? studioVersionText = _studio.version == null - ? null - : userMessages.androidStudioVersion(_studio.version.toString()); + final String studioVersionText = _studio.version == null + ? _userMessages.androidStudioVersion('unknown') + : _userMessages.androidStudioVersion(_studio.version.toString()); messages.add(ValidationMessage( - userMessages.androidStudioLocation(_studio.directory), + _userMessages.androidStudioLocation(_studio.directory), )); if (_studio.pluginsPath != null) { @@ -69,6 +74,10 @@ class AndroidStudioValidator extends DoctorValidator { ); } + if (_studio.version == null) { + messages.add(const ValidationMessage.error('Unable to determine Android Studio version.')); + } + if (_studio.isValid) { type = _hasIssues(messages) ? ValidationType.partial @@ -81,9 +90,9 @@ class AndroidStudioValidator extends DoctorValidator { messages.addAll(_studio.validationMessages.map( (String m) => ValidationMessage.error(m), )); - messages.add(ValidationMessage(userMessages.androidStudioNeedsUpdate)); + messages.add(ValidationMessage(_userMessages.androidStudioNeedsUpdate)); if (_studio.configuredPath != null) { - messages.add(ValidationMessage(userMessages.androidStudioResetDir)); + messages.add(ValidationMessage(_userMessages.androidStudioResetDir)); } } diff --git a/packages/flutter_tools/lib/src/vscode/vscode_validator.dart b/packages/flutter_tools/lib/src/vscode/vscode_validator.dart index d216536231..7c5a7f485f 100644 --- a/packages/flutter_tools/lib/src/vscode/vscode_validator.dart +++ b/packages/flutter_tools/lib/src/vscode/vscode_validator.dart @@ -23,13 +23,20 @@ class VsCodeValidator extends DoctorValidator { @override Future validate() async { - final String? vsCodeVersionText = _vsCode.version == null - ? null + final List validationMessages = + List.from(_vsCode.validationMessages); + + final String vsCodeVersionText = _vsCode.version == null + ? userMessages.vsCodeVersion('unknown') : userMessages.vsCodeVersion(_vsCode.version.toString()); + if (_vsCode.version == null) { + validationMessages.add(const ValidationMessage.error('Unable to determine VS Code version.')); + } + return ValidationResult( ValidationType.success, - _vsCode.validationMessages.toList(), + validationMessages, statusInfo: vsCodeVersionText, ); } diff --git a/packages/flutter_tools/test/general.shard/android/android_studio_validator_test.dart b/packages/flutter_tools/test/general.shard/android/android_studio_validator_test.dart index e06a9f5afb..a969081d38 100644 --- a/packages/flutter_tools/test/general.shard/android/android_studio_validator_test.dart +++ b/packages/flutter_tools/test/general.shard/android/android_studio_validator_test.dart @@ -3,14 +3,17 @@ // found in the LICENSE file. import 'package:file/memory.dart'; +import 'package:flutter_tools/src/android/android_studio.dart'; import 'package:flutter_tools/src/android/android_studio_validator.dart'; import 'package:flutter_tools/src/base/config.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/base/user_messages.dart'; +import 'package:flutter_tools/src/base/version.dart'; import 'package:flutter_tools/src/doctor_validator.dart'; import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:test/fake.dart'; import '../../src/common.dart'; import '../../src/context.dart'; @@ -23,6 +26,7 @@ final Platform linuxPlatform = FakePlatform( ); void main() { + late FileSystem fileSystem; late FakeProcessManager fakeProcessManager; @@ -31,49 +35,76 @@ void main() { fakeProcessManager = FakeProcessManager.empty(); }); - testWithoutContext('NoAndroidStudioValidator shows Android Studio as "not available" when not available.', () async { - final Config config = Config.test(); - final NoAndroidStudioValidator validator = NoAndroidStudioValidator( - config: config, - platform: linuxPlatform, - userMessages: UserMessages(), - ); + group(NoAndroidStudioValidator, () { + testWithoutContext('shows Android Studio as "not available" when not available.', () async { + final Config config = Config.test(); + final NoAndroidStudioValidator validator = NoAndroidStudioValidator( + config: config, + platform: linuxPlatform, + userMessages: UserMessages(), + ); - expect((await validator.validate()).type, equals(ValidationType.notAvailable)); + expect((await validator.validate()).type, equals(ValidationType.notAvailable)); + }); }); - testUsingContext('AndroidStudioValidator gives doctor error on java crash', () async { - fakeProcessManager.addCommand(const FakeCommand( - command: [ - '/opt/android-studio-with-cheese-5.0/jre/bin/java', - '-version', - ], - exception: ProcessException('java', ['-version']), - )); - const String installPath = '/opt/android-studio-with-cheese-5.0'; - const String studioHome = '$home/.AndroidStudioWithCheese5.0'; - const String homeFile = '$studioHome/system/.home'; - globals.fs.directory(installPath).createSync(recursive: true); - globals.fs.file(homeFile).createSync(recursive: true); - globals.fs.file(homeFile).writeAsStringSync(installPath); + group(AndroidStudioValidator, () { + testUsingContext('gives doctor error on java crash', () async { + fakeProcessManager.addCommand(const FakeCommand( + command: [ + '/opt/android-studio-with-cheese-5.0/jre/bin/java', + '-version', + ], + exception: ProcessException('java', ['-version']), + )); + const String installPath = '/opt/android-studio-with-cheese-5.0'; + const String studioHome = '$home/.AndroidStudioWithCheese5.0'; + const String homeFile = '$studioHome/system/.home'; + globals.fs.directory(installPath).createSync(recursive: true); + globals.fs.file(homeFile).createSync(recursive: true); + globals.fs.file(homeFile).writeAsStringSync(installPath); - // This checks that running the validator doesn't throw an unhandled - // exception and that the ProcessException makes it into the error - // message list. - for (final DoctorValidator validator in AndroidStudioValidator.allValidators(globals.config, globals.platform, globals.fs, globals.userMessages)) { + // This checks that running the validator doesn't throw an unhandled + // exception and that the ProcessException makes it into the error + // message list. + for (final DoctorValidator validator in AndroidStudioValidator.allValidators(globals.config, globals.platform, globals.fs, globals.userMessages)) { + final ValidationResult result = await validator.validate(); + expect(result.messages.where((ValidationMessage message) { + return message.isError && message.message.contains('ProcessException'); + }).isNotEmpty, true); + } + expect(fakeProcessManager, hasNoRemainingExpectations); + }, overrides: { + FileSystem: () => fileSystem, + ProcessManager: () => fakeProcessManager, + Platform: () => linuxPlatform, + FileSystemUtils: () => FileSystemUtils( + fileSystem: fileSystem, + platform: linuxPlatform, + ), + }); + + testWithoutContext('warns if version of Android Studio could not be determined', () async { + final AndroidStudio studio = _FakeAndroidStudio(); + final AndroidStudioValidator validator = AndroidStudioValidator(studio, fileSystem: fileSystem, userMessages: UserMessages()); final ValidationResult result = await validator.validate(); - expect(result.messages.where((ValidationMessage message) { - return message.isError && message.message.contains('ProcessException'); - }).isNotEmpty, true); - } - expect(fakeProcessManager, hasNoRemainingExpectations); - }, overrides: { - FileSystem: () => fileSystem, - ProcessManager: () => fakeProcessManager, - Platform: () => linuxPlatform, - FileSystemUtils: () => FileSystemUtils( - fileSystem: fileSystem, - platform: linuxPlatform, - ), + expect(result.messages, contains(const ValidationMessage.error('Unable to determine Android Studio version.'))); + expect(result.statusInfo, 'version unknown'); + }); }); } + +class _FakeAndroidStudio extends Fake implements AndroidStudio { + @override + List get validationMessages => []; + @override + bool get isValid => true; + @override + String? get pluginsPath => null; + @override + String get directory => 'android-studio'; + @override + Version? get version => null; + @override + String get javaPath => 'android-studio/jbr/bin/java'; +} diff --git a/packages/flutter_tools/test/general.shard/vscode/vscode_validator_test.dart b/packages/flutter_tools/test/general.shard/vscode/vscode_validator_test.dart index e80987105b..1be8be8ab5 100644 --- a/packages/flutter_tools/test/general.shard/vscode/vscode_validator_test.dart +++ b/packages/flutter_tools/test/general.shard/vscode/vscode_validator_test.dart @@ -5,10 +5,15 @@ import 'package:file/memory.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/platform.dart'; +import 'package:flutter_tools/src/base/user_messages.dart'; +import 'package:flutter_tools/src/base/version.dart'; +import 'package:flutter_tools/src/doctor_validator.dart'; import 'package:flutter_tools/src/vscode/vscode.dart'; +import 'package:flutter_tools/src/vscode/vscode_validator.dart'; +import 'package:test/fake.dart'; import '../../src/common.dart'; -import '../../src/fake_process_manager.dart'; +import '../../src/context.dart'; void main() { testWithoutContext('VsCode search locations on windows supports an empty environment', () { @@ -20,4 +25,26 @@ void main() { expect(VsCode.allInstalled(fileSystem, platform, FakeProcessManager.any()), isEmpty); }); + + group(VsCodeValidator, () { + testUsingContext('Warns if VS Code version could not be found', () async { + final VsCodeValidator validator = VsCodeValidator(_FakeVsCode()); + final ValidationResult result = await validator.validate(); + expect(result.messages, contains(const ValidationMessage.error('Unable to determine VS Code version.'))); + expect(result.statusInfo, 'version unknown'); + }, overrides: { + UserMessages: () => UserMessages(), + }); + }); +} + +class _FakeVsCode extends Fake implements VsCode { + @override + Iterable get validationMessages => []; + + @override + String get productName => 'VS Code'; + + @override + Version? get version => null; }