Skip to content

Commit d2a95ee

Browse files
Fix crash on vswhere query on missing installations (flutter#40786)
1 parent ae529d8 commit d2a95ee

File tree

3 files changed

+74
-25
lines changed

3 files changed

+74
-25
lines changed

packages/flutter_tools/lib/src/windows/visual_studio_validator.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ VisualStudioValidator get visualStudioValidator => context.get<VisualStudioValid
1212
class VisualStudioValidator extends DoctorValidator {
1313
const VisualStudioValidator() : super('Visual Studio - develop for Windows');
1414

15-
int get majorVersion => int.tryParse(visualStudio.fullVersion.split('.')[0]);
15+
int get majorVersion => visualStudio.fullVersion != null
16+
? int.tryParse(visualStudio.fullVersion.split('.')[0])
17+
: null;
1618

1719
@override
1820
Future<ValidationResult> validate() async {

packages/flutter_tools/test/general.shard/windows/visual_studio_test.dart

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,20 +35,20 @@ void main() {
3535
// A minimum version of a response where a VS installation was found.
3636
const Map<String, dynamic> _defaultResponse = <String, dynamic>{
3737
'installationPath': visualStudioPath,
38-
'displayName': 'Visual Studio Community 2017',
39-
'installationVersion': '15.9.28307.665',
38+
'displayName': 'Visual Studio Community 2019',
39+
'installationVersion': '16.2.29306.81',
4040
'isRebootRequired': false,
4141
'isComplete': true,
4242
'isLaunchable': true,
4343
'isPrerelease': false,
4444
'catalog': <String, dynamic>{
45-
'productDisplayVersion': '15.9.12',
46-
},
45+
'productDisplayVersion': '16.2.5',
46+
}
4747
};
4848

4949
// A version of a response that doesn't include certain installation status
5050
// information that might be missing in older Visual Studio versions.
51-
const Map<String, dynamic> _oldResponse = <String, dynamic>{
51+
const Map<String, dynamic> _missingStatusResponse = <String, dynamic>{
5252
'installationPath': visualStudioPath,
5353
'displayName': 'Visual Studio Community 2017',
5454
'installationVersion': '15.9.28307.665',
@@ -205,10 +205,32 @@ void main() {
205205
ProcessManager: () => mockProcessManager,
206206
});
207207

208+
testUsingContext('necessaryComponentDescriptions suggest the right VS tools on major version 15', () {
209+
210+
visualStudio = VisualStudio();
211+
final String toolsString = visualStudio.necessaryComponentDescriptions(15)[1];
212+
expect(toolsString.contains('v141'), true);
213+
}, overrides: <Type, Generator>{
214+
FileSystem: () => memoryFilesystem,
215+
Platform: () => windowsPlatform,
216+
ProcessManager: () => mockProcessManager,
217+
});
218+
219+
testUsingContext('necessaryComponentDescriptions suggest the right VS tools on major version != 15', () {
220+
221+
visualStudio = VisualStudio();
222+
final String toolsString = visualStudio.necessaryComponentDescriptions(16)[1];
223+
expect(toolsString.contains('v142'), true);
224+
}, overrides: <Type, Generator>{
225+
FileSystem: () => memoryFilesystem,
226+
Platform: () => windowsPlatform,
227+
ProcessManager: () => mockProcessManager,
228+
});
229+
208230
testUsingContext('isInstalled returns true even with missing status information', () {
209231
setMockCompatibleVisualStudioInstallation(null);
210232
setMockPrereleaseVisualStudioInstallation(null);
211-
setMockAnyVisualStudioInstallation(_oldResponse);
233+
setMockAnyVisualStudioInstallation(_missingStatusResponse);
212234

213235
visualStudio = VisualStudio();
214236
expect(visualStudio.isInstalled, true);
@@ -360,10 +382,10 @@ void main() {
360382
setMockAnyVisualStudioInstallation(_defaultResponse);
361383

362384
visualStudio = VisualStudio();
363-
expect(visualStudio.displayName, equals('Visual Studio Community 2017'));
364-
expect(visualStudio.displayVersion, equals('15.9.12'));
385+
expect(visualStudio.displayName, equals('Visual Studio Community 2019'));
386+
expect(visualStudio.displayVersion, equals('16.2.5'));
365387
expect(visualStudio.installLocation, equals(visualStudioPath));
366-
expect(visualStudio.fullVersion, equals('15.9.28307.665'));
388+
expect(visualStudio.fullVersion, equals('16.2.29306.81'));
367389
}, overrides: <Type, Generator>{
368390
FileSystem: () => memoryFilesystem,
369391
Platform: () => windowsPlatform,
@@ -386,7 +408,17 @@ void main() {
386408
});
387409

388410
testUsingContext('Metadata is for compatible version when latest is missing components', () {
389-
setMockCompatibleVisualStudioInstallation(_defaultResponse);
411+
// Return a different version for queries without the required packages.
412+
final Map<String, dynamic> olderButCompleteVersionResponse = <String, dynamic>{
413+
'installationPath': visualStudioPath,
414+
'displayName': 'Visual Studio Community 2017',
415+
'installationVersion': '15.9.28307.665',
416+
'catalog': <String, dynamic>{
417+
'productDisplayVersion': '15.9.12',
418+
}
419+
};
420+
421+
setMockCompatibleVisualStudioInstallation(olderButCompleteVersionResponse);
390422
setMockPrereleaseVisualStudioInstallation(null);
391423
// Return a different version for queries without the required packages.
392424
final Map<String, dynamic> incompleteVersionResponse = <String, dynamic>{

packages/flutter_tools/test/general.shard/windows/visual_studio_validator_test.dart

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,35 @@ void main() {
1919

2020
setUp(() {
2121
mockVisualStudio = MockVisualStudio();
22-
// Mock a valid VS installation.
22+
// Default values regardless of whether VS is installed or not.
23+
when(mockVisualStudio.workloadDescription).thenReturn('Desktop development');
24+
when(mockVisualStudio.necessaryComponentDescriptions(any)).thenReturn(<String>['A', 'B']);
25+
});
26+
27+
// Assigns default values for a complete VS installation with necessary components.
28+
void _configureMockVisualStudioAsInstalled() {
2329
when(mockVisualStudio.isInstalled).thenReturn(true);
2430
when(mockVisualStudio.isPrerelease).thenReturn(false);
2531
when(mockVisualStudio.isComplete).thenReturn(true);
2632
when(mockVisualStudio.isLaunchable).thenReturn(true);
2733
when(mockVisualStudio.isRebootRequired).thenReturn(false);
2834
when(mockVisualStudio.hasNecessaryComponents).thenReturn(true);
29-
when(mockVisualStudio.workloadDescription).thenReturn('Desktop development');
30-
when(mockVisualStudio.necessaryComponentDescriptions(any)).thenReturn(<String>['A', 'B']);
3135
when(mockVisualStudio.fullVersion).thenReturn('15.1');
32-
});
36+
when(mockVisualStudio.displayName).thenReturn('Visual Studio Community 2019');
37+
}
38+
39+
// Assigns default values for a missing VS installation.
40+
void _configureMockVisualStudioAsNotInstalled() {
41+
when(mockVisualStudio.isInstalled).thenReturn(false);
42+
when(mockVisualStudio.isPrerelease).thenReturn(false);
43+
when(mockVisualStudio.isComplete).thenReturn(false);
44+
when(mockVisualStudio.isLaunchable).thenReturn(false);
45+
when(mockVisualStudio.isRebootRequired).thenReturn(false);
46+
when(mockVisualStudio.hasNecessaryComponents).thenReturn(false);
47+
}
3348

3449
testUsingContext('Emits a message when Visual Studio is a pre-release version', () async {
50+
_configureMockVisualStudioAsInstalled();
3551
when(visualStudio.isPrerelease).thenReturn(true);
3652

3753
const VisualStudioValidator validator = VisualStudioValidator();
@@ -42,16 +58,8 @@ void main() {
4258
VisualStudio: () => mockVisualStudio,
4359
});
4460

45-
testUsingContext('Emits missing status when Visual Studio is not installed', () async {
46-
when(visualStudio.isInstalled).thenReturn(false);
47-
const VisualStudioValidator validator = VisualStudioValidator();
48-
final ValidationResult result = await validator.validate();
49-
expect(result.type, ValidationType.missing);
50-
}, overrides: <Type, Generator>{
51-
VisualStudio: () => mockVisualStudio,
52-
});
53-
5461
testUsingContext('Emits a partial status when Visual Studio installation is incomplete', () async {
62+
_configureMockVisualStudioAsInstalled();
5563
when(visualStudio.isComplete).thenReturn(false);
5664

5765
const VisualStudioValidator validator = VisualStudioValidator();
@@ -64,6 +72,7 @@ void main() {
6472
});
6573

6674
testUsingContext('Emits a partial status when Visual Studio installation needs rebooting', () async {
75+
_configureMockVisualStudioAsInstalled();
6776
when(visualStudio.isRebootRequired).thenReturn(true);
6877

6978
const VisualStudioValidator validator = VisualStudioValidator();
@@ -76,6 +85,7 @@ void main() {
7685
});
7786

7887
testUsingContext('Emits a partial status when Visual Studio installation is not launchable', () async {
88+
_configureMockVisualStudioAsInstalled();
7989
when(visualStudio.isLaunchable).thenReturn(false);
8090

8191
const VisualStudioValidator validator = VisualStudioValidator();
@@ -89,6 +99,7 @@ void main() {
8999

90100

91101
testUsingContext('Emits partial status when Visual Studio is installed without necessary components', () async {
102+
_configureMockVisualStudioAsInstalled();
92103
when(visualStudio.hasNecessaryComponents).thenReturn(false);
93104
const VisualStudioValidator validator = VisualStudioValidator();
94105
final ValidationResult result = await validator.validate();
@@ -98,15 +109,19 @@ void main() {
98109
});
99110

100111
testUsingContext('Emits installed status when Visual Studio is installed with necessary components', () async {
112+
_configureMockVisualStudioAsInstalled();
101113
const VisualStudioValidator validator = VisualStudioValidator();
102114
final ValidationResult result = await validator.validate();
115+
final ValidationMessage expectedDisplayNameMessage = ValidationMessage(
116+
userMessages.visualStudioVersion(visualStudio.displayName, visualStudio.fullVersion));
117+
expect(result.messages.contains(expectedDisplayNameMessage), true);
103118
expect(result.type, ValidationType.installed);
104119
}, overrides: <Type, Generator>{
105120
VisualStudio: () => mockVisualStudio,
106121
});
107122

108123
testUsingContext('Emits missing status when Visual Studio is not installed', () async {
109-
when(visualStudio.isInstalled).thenReturn(false);
124+
_configureMockVisualStudioAsNotInstalled();
110125
const VisualStudioValidator validator = VisualStudioValidator();
111126
final ValidationResult result = await validator.validate();
112127
final ValidationMessage expectedMessage = ValidationMessage.error(

0 commit comments

Comments
 (0)