Unverified Commit d2a95ee3 authored by Francisco Magdaleno's avatar Francisco Magdaleno Committed by GitHub

Fix crash on vswhere query on missing installations (#40786)

parent ae529d8b
...@@ -12,7 +12,9 @@ VisualStudioValidator get visualStudioValidator => context.get<VisualStudioValid ...@@ -12,7 +12,9 @@ VisualStudioValidator get visualStudioValidator => context.get<VisualStudioValid
class VisualStudioValidator extends DoctorValidator { class VisualStudioValidator extends DoctorValidator {
const VisualStudioValidator() : super('Visual Studio - develop for Windows'); const VisualStudioValidator() : super('Visual Studio - develop for Windows');
int get majorVersion => int.tryParse(visualStudio.fullVersion.split('.')[0]); int get majorVersion => visualStudio.fullVersion != null
? int.tryParse(visualStudio.fullVersion.split('.')[0])
: null;
@override @override
Future<ValidationResult> validate() async { Future<ValidationResult> validate() async {
......
...@@ -35,20 +35,20 @@ void main() { ...@@ -35,20 +35,20 @@ void main() {
// A minimum version of a response where a VS installation was found. // A minimum version of a response where a VS installation was found.
const Map<String, dynamic> _defaultResponse = <String, dynamic>{ const Map<String, dynamic> _defaultResponse = <String, dynamic>{
'installationPath': visualStudioPath, 'installationPath': visualStudioPath,
'displayName': 'Visual Studio Community 2017', 'displayName': 'Visual Studio Community 2019',
'installationVersion': '15.9.28307.665', 'installationVersion': '16.2.29306.81',
'isRebootRequired': false, 'isRebootRequired': false,
'isComplete': true, 'isComplete': true,
'isLaunchable': true, 'isLaunchable': true,
'isPrerelease': false, 'isPrerelease': false,
'catalog': <String, dynamic>{ 'catalog': <String, dynamic>{
'productDisplayVersion': '15.9.12', 'productDisplayVersion': '16.2.5',
}, }
}; };
// A version of a response that doesn't include certain installation status // A version of a response that doesn't include certain installation status
// information that might be missing in older Visual Studio versions. // information that might be missing in older Visual Studio versions.
const Map<String, dynamic> _oldResponse = <String, dynamic>{ const Map<String, dynamic> _missingStatusResponse = <String, dynamic>{
'installationPath': visualStudioPath, 'installationPath': visualStudioPath,
'displayName': 'Visual Studio Community 2017', 'displayName': 'Visual Studio Community 2017',
'installationVersion': '15.9.28307.665', 'installationVersion': '15.9.28307.665',
...@@ -205,10 +205,32 @@ void main() { ...@@ -205,10 +205,32 @@ void main() {
ProcessManager: () => mockProcessManager, ProcessManager: () => mockProcessManager,
}); });
testUsingContext('necessaryComponentDescriptions suggest the right VS tools on major version 15', () {
visualStudio = VisualStudio();
final String toolsString = visualStudio.necessaryComponentDescriptions(15)[1];
expect(toolsString.contains('v141'), true);
}, overrides: <Type, Generator>{
FileSystem: () => memoryFilesystem,
Platform: () => windowsPlatform,
ProcessManager: () => mockProcessManager,
});
testUsingContext('necessaryComponentDescriptions suggest the right VS tools on major version != 15', () {
visualStudio = VisualStudio();
final String toolsString = visualStudio.necessaryComponentDescriptions(16)[1];
expect(toolsString.contains('v142'), true);
}, overrides: <Type, Generator>{
FileSystem: () => memoryFilesystem,
Platform: () => windowsPlatform,
ProcessManager: () => mockProcessManager,
});
testUsingContext('isInstalled returns true even with missing status information', () { testUsingContext('isInstalled returns true even with missing status information', () {
setMockCompatibleVisualStudioInstallation(null); setMockCompatibleVisualStudioInstallation(null);
setMockPrereleaseVisualStudioInstallation(null); setMockPrereleaseVisualStudioInstallation(null);
setMockAnyVisualStudioInstallation(_oldResponse); setMockAnyVisualStudioInstallation(_missingStatusResponse);
visualStudio = VisualStudio(); visualStudio = VisualStudio();
expect(visualStudio.isInstalled, true); expect(visualStudio.isInstalled, true);
...@@ -360,10 +382,10 @@ void main() { ...@@ -360,10 +382,10 @@ void main() {
setMockAnyVisualStudioInstallation(_defaultResponse); setMockAnyVisualStudioInstallation(_defaultResponse);
visualStudio = VisualStudio(); visualStudio = VisualStudio();
expect(visualStudio.displayName, equals('Visual Studio Community 2017')); expect(visualStudio.displayName, equals('Visual Studio Community 2019'));
expect(visualStudio.displayVersion, equals('15.9.12')); expect(visualStudio.displayVersion, equals('16.2.5'));
expect(visualStudio.installLocation, equals(visualStudioPath)); expect(visualStudio.installLocation, equals(visualStudioPath));
expect(visualStudio.fullVersion, equals('15.9.28307.665')); expect(visualStudio.fullVersion, equals('16.2.29306.81'));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => memoryFilesystem, FileSystem: () => memoryFilesystem,
Platform: () => windowsPlatform, Platform: () => windowsPlatform,
...@@ -386,7 +408,17 @@ void main() { ...@@ -386,7 +408,17 @@ void main() {
}); });
testUsingContext('Metadata is for compatible version when latest is missing components', () { testUsingContext('Metadata is for compatible version when latest is missing components', () {
setMockCompatibleVisualStudioInstallation(_defaultResponse); // Return a different version for queries without the required packages.
final Map<String, dynamic> olderButCompleteVersionResponse = <String, dynamic>{
'installationPath': visualStudioPath,
'displayName': 'Visual Studio Community 2017',
'installationVersion': '15.9.28307.665',
'catalog': <String, dynamic>{
'productDisplayVersion': '15.9.12',
}
};
setMockCompatibleVisualStudioInstallation(olderButCompleteVersionResponse);
setMockPrereleaseVisualStudioInstallation(null); setMockPrereleaseVisualStudioInstallation(null);
// Return a different version for queries without the required packages. // Return a different version for queries without the required packages.
final Map<String, dynamic> incompleteVersionResponse = <String, dynamic>{ final Map<String, dynamic> incompleteVersionResponse = <String, dynamic>{
......
...@@ -19,19 +19,35 @@ void main() { ...@@ -19,19 +19,35 @@ void main() {
setUp(() { setUp(() {
mockVisualStudio = MockVisualStudio(); mockVisualStudio = MockVisualStudio();
// Mock a valid VS installation. // Default values regardless of whether VS is installed or not.
when(mockVisualStudio.workloadDescription).thenReturn('Desktop development');
when(mockVisualStudio.necessaryComponentDescriptions(any)).thenReturn(<String>['A', 'B']);
});
// Assigns default values for a complete VS installation with necessary components.
void _configureMockVisualStudioAsInstalled() {
when(mockVisualStudio.isInstalled).thenReturn(true); when(mockVisualStudio.isInstalled).thenReturn(true);
when(mockVisualStudio.isPrerelease).thenReturn(false); when(mockVisualStudio.isPrerelease).thenReturn(false);
when(mockVisualStudio.isComplete).thenReturn(true); when(mockVisualStudio.isComplete).thenReturn(true);
when(mockVisualStudio.isLaunchable).thenReturn(true); when(mockVisualStudio.isLaunchable).thenReturn(true);
when(mockVisualStudio.isRebootRequired).thenReturn(false); when(mockVisualStudio.isRebootRequired).thenReturn(false);
when(mockVisualStudio.hasNecessaryComponents).thenReturn(true); when(mockVisualStudio.hasNecessaryComponents).thenReturn(true);
when(mockVisualStudio.workloadDescription).thenReturn('Desktop development');
when(mockVisualStudio.necessaryComponentDescriptions(any)).thenReturn(<String>['A', 'B']);
when(mockVisualStudio.fullVersion).thenReturn('15.1'); when(mockVisualStudio.fullVersion).thenReturn('15.1');
}); when(mockVisualStudio.displayName).thenReturn('Visual Studio Community 2019');
}
// Assigns default values for a missing VS installation.
void _configureMockVisualStudioAsNotInstalled() {
when(mockVisualStudio.isInstalled).thenReturn(false);
when(mockVisualStudio.isPrerelease).thenReturn(false);
when(mockVisualStudio.isComplete).thenReturn(false);
when(mockVisualStudio.isLaunchable).thenReturn(false);
when(mockVisualStudio.isRebootRequired).thenReturn(false);
when(mockVisualStudio.hasNecessaryComponents).thenReturn(false);
}
testUsingContext('Emits a message when Visual Studio is a pre-release version', () async { testUsingContext('Emits a message when Visual Studio is a pre-release version', () async {
_configureMockVisualStudioAsInstalled();
when(visualStudio.isPrerelease).thenReturn(true); when(visualStudio.isPrerelease).thenReturn(true);
const VisualStudioValidator validator = VisualStudioValidator(); const VisualStudioValidator validator = VisualStudioValidator();
...@@ -42,16 +58,8 @@ void main() { ...@@ -42,16 +58,8 @@ void main() {
VisualStudio: () => mockVisualStudio, VisualStudio: () => mockVisualStudio,
}); });
testUsingContext('Emits missing status when Visual Studio is not installed', () async {
when(visualStudio.isInstalled).thenReturn(false);
const VisualStudioValidator validator = VisualStudioValidator();
final ValidationResult result = await validator.validate();
expect(result.type, ValidationType.missing);
}, overrides: <Type, Generator>{
VisualStudio: () => mockVisualStudio,
});
testUsingContext('Emits a partial status when Visual Studio installation is incomplete', () async { testUsingContext('Emits a partial status when Visual Studio installation is incomplete', () async {
_configureMockVisualStudioAsInstalled();
when(visualStudio.isComplete).thenReturn(false); when(visualStudio.isComplete).thenReturn(false);
const VisualStudioValidator validator = VisualStudioValidator(); const VisualStudioValidator validator = VisualStudioValidator();
...@@ -64,6 +72,7 @@ void main() { ...@@ -64,6 +72,7 @@ void main() {
}); });
testUsingContext('Emits a partial status when Visual Studio installation needs rebooting', () async { testUsingContext('Emits a partial status when Visual Studio installation needs rebooting', () async {
_configureMockVisualStudioAsInstalled();
when(visualStudio.isRebootRequired).thenReturn(true); when(visualStudio.isRebootRequired).thenReturn(true);
const VisualStudioValidator validator = VisualStudioValidator(); const VisualStudioValidator validator = VisualStudioValidator();
...@@ -76,6 +85,7 @@ void main() { ...@@ -76,6 +85,7 @@ void main() {
}); });
testUsingContext('Emits a partial status when Visual Studio installation is not launchable', () async { testUsingContext('Emits a partial status when Visual Studio installation is not launchable', () async {
_configureMockVisualStudioAsInstalled();
when(visualStudio.isLaunchable).thenReturn(false); when(visualStudio.isLaunchable).thenReturn(false);
const VisualStudioValidator validator = VisualStudioValidator(); const VisualStudioValidator validator = VisualStudioValidator();
...@@ -89,6 +99,7 @@ void main() { ...@@ -89,6 +99,7 @@ void main() {
testUsingContext('Emits partial status when Visual Studio is installed without necessary components', () async { testUsingContext('Emits partial status when Visual Studio is installed without necessary components', () async {
_configureMockVisualStudioAsInstalled();
when(visualStudio.hasNecessaryComponents).thenReturn(false); when(visualStudio.hasNecessaryComponents).thenReturn(false);
const VisualStudioValidator validator = VisualStudioValidator(); const VisualStudioValidator validator = VisualStudioValidator();
final ValidationResult result = await validator.validate(); final ValidationResult result = await validator.validate();
...@@ -98,15 +109,19 @@ void main() { ...@@ -98,15 +109,19 @@ void main() {
}); });
testUsingContext('Emits installed status when Visual Studio is installed with necessary components', () async { testUsingContext('Emits installed status when Visual Studio is installed with necessary components', () async {
_configureMockVisualStudioAsInstalled();
const VisualStudioValidator validator = VisualStudioValidator(); const VisualStudioValidator validator = VisualStudioValidator();
final ValidationResult result = await validator.validate(); final ValidationResult result = await validator.validate();
final ValidationMessage expectedDisplayNameMessage = ValidationMessage(
userMessages.visualStudioVersion(visualStudio.displayName, visualStudio.fullVersion));
expect(result.messages.contains(expectedDisplayNameMessage), true);
expect(result.type, ValidationType.installed); expect(result.type, ValidationType.installed);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
VisualStudio: () => mockVisualStudio, VisualStudio: () => mockVisualStudio,
}); });
testUsingContext('Emits missing status when Visual Studio is not installed', () async { testUsingContext('Emits missing status when Visual Studio is not installed', () async {
when(visualStudio.isInstalled).thenReturn(false); _configureMockVisualStudioAsNotInstalled();
const VisualStudioValidator validator = VisualStudioValidator(); const VisualStudioValidator validator = VisualStudioValidator();
final ValidationResult result = await validator.validate(); final ValidationResult result = await validator.validate();
final ValidationMessage expectedMessage = ValidationMessage.error( final ValidationMessage expectedMessage = ValidationMessage.error(
......
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