Commit 1be332eb authored by stuartmorgan's avatar stuartmorgan Committed by Flutter GitHub Bot

Require Visual Studio 2019 for Windows (#48844)

parent c8832045
...@@ -196,7 +196,11 @@ class UserMessages { ...@@ -196,7 +196,11 @@ class UserMessages {
String visualStudioMissing(String workload, List<String> components) => String visualStudioMissing(String workload, List<String> components) =>
'Visual Studio not installed; this is necessary for Windows development.\n' 'Visual Studio not installed; this is necessary for Windows development.\n'
'Download at https://visualstudio.microsoft.com/downloads/.\n' 'Download at https://visualstudio.microsoft.com/downloads/.\n'
'Please install the "$workload" workload, including following components:\n ${components.join('\n ')}'; 'Please install the "$workload" workload, including the following components:\n ${components.join('\n ')}';
String visualStudioTooOld(String minimumVersion, String workload, List<String> components) =>
'Visual Studio $minimumVersion or later is required.\n'
'Download at https://visualstudio.microsoft.com/downloads/.\n'
'Please install the "$workload" workload, including the following components:\n ${components.join('\n ')}';
String get visualStudioIsPrerelease => 'The current Visual Studio installation is a pre-release version. It may not be ' String get visualStudioIsPrerelease => 'The current Visual Studio installation is a pre-release version. It may not be '
'supported by Flutter yet.'; 'supported by Flutter yet.';
String get visualStudioNotLaunchable => String get visualStudioNotLaunchable =>
......
...@@ -12,20 +12,25 @@ VisualStudio get visualStudio => context.get<VisualStudio>(); ...@@ -12,20 +12,25 @@ VisualStudio get visualStudio => context.get<VisualStudio>();
/// Encapsulates information about the installed copy of Visual Studio, if any. /// Encapsulates information about the installed copy of Visual Studio, if any.
class VisualStudio { class VisualStudio {
/// True if a sufficiently recent version of Visual Studio is installed. /// True if Visual Studio installation was found.
/// ///
/// Versions older than 2017 Update 2 won't be detected, so error messages to /// Versions older than 2017 Update 2 won't be detected, so error messages to
/// users should take into account that [false] may mean that the user may /// users should take into account that [false] may mean that the user may
/// have an old version rather than no installation at all. /// have an old version rather than no installation at all.
bool get isInstalled => _bestVisualStudioDetails.isNotEmpty; bool get isInstalled => _bestVisualStudioDetails.isNotEmpty;
bool get isAtLeastMinimumVersion {
final int installedMajorVersion = _majorVersion;
return installedMajorVersion != null && installedMajorVersion >= _minimumSupportedVersion;
}
/// True if there is a version of Visual Studio with all the components /// True if there is a version of Visual Studio with all the components
/// necessary to build the project. /// necessary to build the project.
bool get hasNecessaryComponents => _usableVisualStudioDetails.isNotEmpty; bool get hasNecessaryComponents => _usableVisualStudioDetails.isNotEmpty;
/// The name of the Visual Studio install. /// The name of the Visual Studio install.
/// ///
/// For instance: "Visual Studio Community 2017". /// For instance: "Visual Studio Community 2019".
String get displayName => _bestVisualStudioDetails[_displayNameKey] as String; String get displayName => _bestVisualStudioDetails[_displayNameKey] as String;
/// The user-friendly version number of the Visual Studio install. /// The user-friendly version number of the Visual Studio install.
...@@ -81,11 +86,18 @@ class VisualStudio { ...@@ -81,11 +86,18 @@ class VisualStudio {
/// The names of the components within the workload that must be installed. /// The names of the components within the workload that must be installed.
/// ///
/// If there is an existing Visual Studio installation, the major version /// The descriptions of some components differ from version to version. When
/// should be provided here, as the descriptions of some components differ /// a supported version is present, the descriptions used will be for that
/// from version to version. /// version.
List<String> necessaryComponentDescriptions([int visualStudioMajorVersion]) { List<String> necessaryComponentDescriptions() {
return _requiredComponents(visualStudioMajorVersion).values.toList(); return _requiredComponents().values.toList();
}
/// The consumer-facing version name of the minumum supported version.
///
/// E.g., for Visual Studio 2019 this returns "2019" rather than "16".
String get minimumVersionDescription {
return '2019';
} }
/// The path to vcvars64.bat, or null if no Visual Studio installation has /// The path to vcvars64.bat, or null if no Visual Studio installation has
...@@ -104,6 +116,9 @@ class VisualStudio { ...@@ -104,6 +116,9 @@ class VisualStudio {
); );
} }
/// The major version of the Visual Studio install, as an integer.
int get _majorVersion => fullVersion != null ? int.tryParse(fullVersion.split('.')[0]) : null;
/// The path to vswhere.exe. /// The path to vswhere.exe.
/// ///
/// vswhere should be installed for VS 2017 Update 2 and later; if it's not /// vswhere should be installed for VS 2017 Update 2 and later; if it's not
...@@ -121,14 +136,18 @@ class VisualStudio { ...@@ -121,14 +136,18 @@ class VisualStudio {
/// ///
/// Maps from component IDs to description in the installer UI. /// Maps from component IDs to description in the installer UI.
/// See https://docs.microsoft.com/en-us/visualstudio/install/workload-and-component-ids /// See https://docs.microsoft.com/en-us/visualstudio/install/workload-and-component-ids
Map<String, String> _requiredComponents([int visualStudioMajorVersion]) { Map<String, String> _requiredComponents([int majorVersion]) {
// The description of the C++ toolchain required by the template. The // The description of the C++ toolchain required by the template. The
// component name is significantly different in different versions. // component name is significantly different in different versions.
// Default to the latest known description, but use a specific string // When a new major version of VS is supported, its toochain description
// if a known older version is requested. // should be added below. It should also be made the default, so that when
String cppToolchainDescription = 'MSVC v142 - VS 2019 C++ x64/x86 build tools'; // there is no installation, the message shows the string that will be
if (visualStudioMajorVersion == 15) { // relevant for the most likely fresh install case).
cppToolchainDescription = 'VC++ 2017 version 15.9 v14.## latest v141 tools'; String cppToolchainDescription;
switch (majorVersion ?? _majorVersion) {
case 16:
default:
cppToolchainDescription = 'MSVC v142 - VS 2019 C++ x64/x86 build tools';
} }
// The 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64' ID is assigned to the latest // The 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64' ID is assigned to the latest
// release of the toolchain, and there can be minor updates within a given version of // release of the toolchain, and there can be minor updates within a given version of
...@@ -147,6 +166,15 @@ class VisualStudio { ...@@ -147,6 +166,15 @@ class VisualStudio {
}; };
} }
/// The minimum supported major version.
static const int _minimumSupportedVersion = 16; // '16' is VS 2019.
/// vswhere argument to specificy the minimum version.
static const String _vswhereMinVersionArgument = '-version';
/// vswhere argument to allow prerelease versions.
static const String _vswherePrereleaseArgument = '-prerelease';
// Keys in a VS details dictionary returned from vswhere. // Keys in a VS details dictionary returned from vswhere.
/// The root directory of the Visual Studio installation. /// The root directory of the Visual Studio installation.
...@@ -174,9 +202,6 @@ class VisualStudio { ...@@ -174,9 +202,6 @@ class VisualStudio {
/// This key is under the 'catalog' entry. /// This key is under the 'catalog' entry.
static const String _catalogDisplayVersionKey = 'productDisplayVersion'; static const String _catalogDisplayVersionKey = 'productDisplayVersion';
/// vswhere argument keys
static const String _prereleaseKey = '-prerelease';
/// Returns the details dictionary for the newest version of Visual Studio /// Returns the details dictionary for the newest version of Visual Studio
/// that includes all of [requiredComponents], if there is one. /// that includes all of [requiredComponents], if there is one.
Map<String, dynamic> _visualStudioDetails( Map<String, dynamic> _visualStudioDetails(
...@@ -235,7 +260,8 @@ class VisualStudio { ...@@ -235,7 +260,8 @@ class VisualStudio {
} }
/// Returns the details dictionary for the latest version of Visual Studio /// Returns the details dictionary for the latest version of Visual Studio
/// that has all required components, or {} if there is no such installation. /// that has all required components and is a supported version, or {} if
/// there is no such installation.
/// ///
/// If no installation is found, the cached VS details are set to an empty map /// If no installation is found, the cached VS details are set to an empty map
/// to avoid repeating vswhere queries that have already not found an installation. /// to avoid repeating vswhere queries that have already not found an installation.
...@@ -244,12 +270,17 @@ class VisualStudio { ...@@ -244,12 +270,17 @@ class VisualStudio {
if (_cachedUsableVisualStudioDetails != null) { if (_cachedUsableVisualStudioDetails != null) {
return _cachedUsableVisualStudioDetails; return _cachedUsableVisualStudioDetails;
} }
Map<String, dynamic> visualStudioDetails = final List<String> minimumVersionArguments = <String>[
_visualStudioDetails(requiredComponents: _requiredComponents().keys); _vswhereMinVersionArgument,
_minimumSupportedVersion.toString(),
];
Map<String, dynamic> visualStudioDetails = _visualStudioDetails(
requiredComponents: _requiredComponents(_minimumSupportedVersion).keys,
additionalArguments: minimumVersionArguments);
// If a stable version is not found, try searching for a pre-release version. // If a stable version is not found, try searching for a pre-release version.
visualStudioDetails ??= _visualStudioDetails( visualStudioDetails ??= _visualStudioDetails(
requiredComponents: _requiredComponents().keys, requiredComponents: _requiredComponents(_minimumSupportedVersion).keys,
additionalArguments: <String>[_prereleaseKey]); additionalArguments: <String>[...minimumVersionArguments, _vswherePrereleaseArgument]);
if (visualStudioDetails != null) { if (visualStudioDetails != null) {
if (installationHasIssues(visualStudioDetails)) { if (installationHasIssues(visualStudioDetails)) {
...@@ -263,16 +294,17 @@ class VisualStudio { ...@@ -263,16 +294,17 @@ class VisualStudio {
} }
/// Returns the details dictionary of the latest version of Visual Studio, /// Returns the details dictionary of the latest version of Visual Studio,
/// regardless of components, or {} if no such installation is found. /// regardless of components and version, or {} if no such installation is
/// found.
/// ///
/// If no installation is found, the cached /// If no installation is found, the cached VS details are set to an empty map
/// VS details are set to an empty map to avoid repeating vswhere queries that /// to avoid repeating vswhere queries that have already not found an
/// have already not found an installation. /// installation.
Map<String, dynamic> _cachedAnyVisualStudioDetails; Map<String, dynamic> _cachedAnyVisualStudioDetails;
Map<String, dynamic> get _anyVisualStudioDetails { Map<String, dynamic> get _anyVisualStudioDetails {
// Search for all types of installations. // Search for all types of installations.
_cachedAnyVisualStudioDetails ??= _visualStudioDetails( _cachedAnyVisualStudioDetails ??= _visualStudioDetails(
additionalArguments: <String>[_prereleaseKey, '-all']); additionalArguments: <String>[_vswherePrereleaseArgument, '-all']);
// Add a sentinel empty value to avoid querying vswhere again. // Add a sentinel empty value to avoid querying vswhere again.
_cachedAnyVisualStudioDetails ??= <String, dynamic>{}; _cachedAnyVisualStudioDetails ??= <String, dynamic>{};
return _cachedAnyVisualStudioDetails; return _cachedAnyVisualStudioDetails;
......
...@@ -12,10 +12,6 @@ VisualStudioValidator get visualStudioValidator => context.get<VisualStudioValid ...@@ -12,10 +12,6 @@ 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 => visualStudio.fullVersion != null
? int.tryParse(visualStudio.fullVersion.split('.')[0])
: null;
@override @override
Future<ValidationResult> validate() async { Future<ValidationResult> validate() async {
final List<ValidationMessage> messages = <ValidationMessage>[]; final List<ValidationMessage> messages = <ValidationMessage>[];
...@@ -39,7 +35,16 @@ class VisualStudioValidator extends DoctorValidator { ...@@ -39,7 +35,16 @@ class VisualStudioValidator extends DoctorValidator {
} }
// Messages for faulty installations. // Messages for faulty installations.
if (visualStudio.isRebootRequired) { if (!visualStudio.isAtLeastMinimumVersion) {
status = ValidationType.partial;
messages.add(ValidationMessage.error(
userMessages.visualStudioTooOld(
visualStudio.minimumVersionDescription,
visualStudio.workloadDescription,
visualStudio.necessaryComponentDescriptions(),
),
));
} else if (visualStudio.isRebootRequired) {
status = ValidationType.partial; status = ValidationType.partial;
messages.add(ValidationMessage.error(userMessages.visualStudioRebootRequired)); messages.add(ValidationMessage.error(userMessages.visualStudioRebootRequired));
} else if (!visualStudio.isComplete) { } else if (!visualStudio.isComplete) {
...@@ -48,12 +53,12 @@ class VisualStudioValidator extends DoctorValidator { ...@@ -48,12 +53,12 @@ class VisualStudioValidator extends DoctorValidator {
} else if (!visualStudio.isLaunchable) { } else if (!visualStudio.isLaunchable) {
status = ValidationType.partial; status = ValidationType.partial;
messages.add(ValidationMessage.error(userMessages.visualStudioNotLaunchable)); messages.add(ValidationMessage.error(userMessages.visualStudioNotLaunchable));
} else if (!visualStudio.hasNecessaryComponents) { } else if (!visualStudio.hasNecessaryComponents) {
status = ValidationType.partial; status = ValidationType.partial;
messages.add(ValidationMessage.error( messages.add(ValidationMessage.error(
userMessages.visualStudioMissingComponents( userMessages.visualStudioMissingComponents(
visualStudio.workloadDescription, visualStudio.workloadDescription,
visualStudio.necessaryComponentDescriptions(majorVersion), visualStudio.necessaryComponentDescriptions(),
), ),
)); ));
} }
...@@ -63,7 +68,7 @@ class VisualStudioValidator extends DoctorValidator { ...@@ -63,7 +68,7 @@ class VisualStudioValidator extends DoctorValidator {
messages.add(ValidationMessage.error( messages.add(ValidationMessage.error(
userMessages.visualStudioMissing( userMessages.visualStudioMissing(
visualStudio.workloadDescription, visualStudio.workloadDescription,
visualStudio.necessaryComponentDescriptions(majorVersion), visualStudio.necessaryComponentDescriptions(),
), ),
)); ));
} }
......
...@@ -48,17 +48,31 @@ void main() { ...@@ -48,17 +48,31 @@ void main() {
}, },
}; };
// A version of a response that doesn't include certain installation status // A response for a VS installation that's too old.
// information that might be missing in older Visual Studio versions. const Map<String, dynamic> _tooOldResponse = <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',
'isRebootRequired': false,
'isComplete': true,
'isLaunchable': true,
'isPrerelease': false,
'catalog': <String, dynamic>{ 'catalog': <String, dynamic>{
'productDisplayVersion': '15.9.12', 'productDisplayVersion': '15.9.12',
}, },
}; };
// A version of a response that doesn't include certain installation status
// information that might be missing in older vswhere.
const Map<String, dynamic> _missingStatusResponse = <String, dynamic>{
'installationPath': visualStudioPath,
'displayName': 'Visual Studio Community 2017',
'installationVersion': '16.4.29609.76',
'catalog': <String, dynamic>{
'productDisplayVersion': '16.4.1',
},
};
// Arguments for a vswhere query to search for an installation with the required components. // Arguments for a vswhere query to search for an installation with the required components.
const List<String> _requiredComponents = <String>[ const List<String> _requiredComponents = <String>[
'Microsoft.Component.MSBuild', 'Microsoft.Component.MSBuild',
...@@ -108,13 +122,13 @@ void main() { ...@@ -108,13 +122,13 @@ void main() {
// Sets whether or not a vswhere query with the required components will // Sets whether or not a vswhere query with the required components will
// return an installation. // return an installation.
void setMockCompatibleVisualStudioInstallation(Map<String, dynamic>response) { void setMockCompatibleVisualStudioInstallation(Map<String, dynamic>response) {
setMockVswhereResponse(_requiredComponents, null, response); setMockVswhereResponse(_requiredComponents, <String>['-version', '16'], response);
} }
// Sets whether or not a vswhere query with the required components will // Sets whether or not a vswhere query with the required components will
// return a pre-release installation. // return a pre-release installation.
void setMockPrereleaseVisualStudioInstallation(Map<String, dynamic>response) { void setMockPrereleaseVisualStudioInstallation(Map<String, dynamic>response) {
setMockVswhereResponse(_requiredComponents, <String>['-prerelease'], response); setMockVswhereResponse(_requiredComponents, <String>['-version', '16', '-prerelease'], response);
} }
// Sets whether or not a vswhere query searching for 'all' and 'prerelease' // Sets whether or not a vswhere query searching for 'all' and 'prerelease'
...@@ -200,6 +214,7 @@ void main() { ...@@ -200,6 +214,7 @@ void main() {
visualStudio = VisualStudio(); visualStudio = VisualStudio();
expect(visualStudio.isInstalled, false); expect(visualStudio.isInstalled, false);
expect(visualStudio.isAtLeastMinimumVersion, false);
expect(visualStudio.hasNecessaryComponents, false); expect(visualStudio.hasNecessaryComponents, false);
expect(visualStudio.isComplete, false); expect(visualStudio.isComplete, false);
expect(visualStudio.isRebootRequired, false); expect(visualStudio.isRebootRequired, false);
...@@ -214,21 +229,25 @@ void main() { ...@@ -214,21 +229,25 @@ void main() {
Platform: () => windowsPlatform, Platform: () => windowsPlatform,
}); });
testUsingContext('necessaryComponentDescriptions suggest the right VS tools on major version 15', () { testUsingContext('necessaryComponentDescriptions suggest the right VS tools on major version 16', () {
setMockCompatibleVisualStudioInstallation(_defaultResponse);
visualStudio = VisualStudio(); visualStudio = VisualStudio();
final String toolsString = visualStudio.necessaryComponentDescriptions(15)[1]; final String toolsString = visualStudio.necessaryComponentDescriptions()[1];
expect(toolsString.contains('v141'), true); expect(toolsString.contains('v142'), true);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => memoryFilesystem, FileSystem: () => memoryFilesystem,
ProcessManager: () => mockProcessManager, ProcessManager: () => mockProcessManager,
Platform: () => windowsPlatform, Platform: () => windowsPlatform,
}); });
testUsingContext('necessaryComponentDescriptions suggest the right VS tools on major version != 15', () { testUsingContext('necessaryComponentDescriptions suggest the right VS tools on an old version', () {
setMockCompatibleVisualStudioInstallation(null);
setMockPrereleaseVisualStudioInstallation(null);
setMockAnyVisualStudioInstallation(_tooOldResponse);
visualStudio = VisualStudio(); visualStudio = VisualStudio();
final String toolsString = visualStudio.necessaryComponentDescriptions(16)[1]; final String toolsString = visualStudio.necessaryComponentDescriptions()[1];
expect(toolsString.contains('v142'), true); expect(toolsString.contains('v142'), true);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => memoryFilesystem, FileSystem: () => memoryFilesystem,
...@@ -262,6 +281,19 @@ void main() { ...@@ -262,6 +281,19 @@ void main() {
Platform: () => windowsPlatform, Platform: () => windowsPlatform,
}); });
testUsingContext('isInstalled returns true when VS is present but too old', () {
setMockCompatibleVisualStudioInstallation(null);
setMockPrereleaseVisualStudioInstallation(null);
setMockAnyVisualStudioInstallation(_tooOldResponse);
visualStudio = VisualStudio();
expect(visualStudio.isInstalled, true);
}, overrides: <Type, Generator>{
FileSystem: () => memoryFilesystem,
ProcessManager: () => mockProcessManager,
Platform: () => windowsPlatform,
});
testUsingContext('isInstalled returns true when a prerelease version of VS is present', () { testUsingContext('isInstalled returns true when a prerelease version of VS is present', () {
setMockCompatibleVisualStudioInstallation(null); setMockCompatibleVisualStudioInstallation(null);
setMockAnyVisualStudioInstallation(null); setMockAnyVisualStudioInstallation(null);
...@@ -279,6 +311,20 @@ void main() { ...@@ -279,6 +311,20 @@ void main() {
Platform: () => windowsPlatform, Platform: () => windowsPlatform,
}); });
testUsingContext('isAtLeastMinimumVersion returns false when the version found is too old', () {
setMockCompatibleVisualStudioInstallation(null);
setMockPrereleaseVisualStudioInstallation(null);
setMockAnyVisualStudioInstallation(_tooOldResponse);
visualStudio = VisualStudio();
expect(visualStudio.isInstalled, true);
expect(visualStudio.isAtLeastMinimumVersion, false);
}, overrides: <Type, Generator>{
FileSystem: () => memoryFilesystem,
ProcessManager: () => mockProcessManager,
Platform: () => windowsPlatform,
});
testUsingContext('isComplete returns false when an incomplete installation is found', () { testUsingContext('isComplete returns false when an incomplete installation is found', () {
setMockCompatibleVisualStudioInstallation(null); setMockCompatibleVisualStudioInstallation(null);
setMockPrereleaseVisualStudioInstallation(null); setMockPrereleaseVisualStudioInstallation(null);
...@@ -421,6 +467,7 @@ void main() { ...@@ -421,6 +467,7 @@ void main() {
visualStudio = VisualStudio(); visualStudio = VisualStudio();
expect(visualStudio.isInstalled, true); expect(visualStudio.isInstalled, true);
expect(visualStudio.isAtLeastMinimumVersion, true);
expect(visualStudio.hasNecessaryComponents, true); expect(visualStudio.hasNecessaryComponents, true);
expect(visualStudio.vcvarsPath, equals(vcvarsPath)); expect(visualStudio.vcvarsPath, equals(vcvarsPath));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
......
...@@ -21,24 +21,40 @@ void main() { ...@@ -21,24 +21,40 @@ void main() {
mockVisualStudio = MockVisualStudio(); mockVisualStudio = MockVisualStudio();
// Default values regardless of whether VS is installed or not. // Default values regardless of whether VS is installed or not.
when(mockVisualStudio.workloadDescription).thenReturn('Desktop development'); when(mockVisualStudio.workloadDescription).thenReturn('Desktop development');
when(mockVisualStudio.necessaryComponentDescriptions(any)).thenReturn(<String>['A', 'B']); when(mockVisualStudio.minimumVersionDescription).thenReturn('2019');
when(mockVisualStudio.necessaryComponentDescriptions()).thenReturn(<String>['A', 'B']);
}); });
// Assigns default values for a complete VS installation with necessary components. // Assigns default values for a complete VS installation with necessary components.
void _configureMockVisualStudioAsInstalled() { void _configureMockVisualStudioAsInstalled() {
when(mockVisualStudio.isInstalled).thenReturn(true); when(mockVisualStudio.isInstalled).thenReturn(true);
when(mockVisualStudio.isAtLeastMinimumVersion).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.fullVersion).thenReturn('15.1'); when(mockVisualStudio.fullVersion).thenReturn('16.2');
when(mockVisualStudio.displayName).thenReturn('Visual Studio Community 2019'); when(mockVisualStudio.displayName).thenReturn('Visual Studio Community 2019');
} }
// Assigns default values for a complete VS installation that is too old.
void _configureMockVisualStudioAsTooOld() {
when(mockVisualStudio.isInstalled).thenReturn(true);
when(mockVisualStudio.isAtLeastMinimumVersion).thenReturn(false);
when(mockVisualStudio.isPrerelease).thenReturn(false);
when(mockVisualStudio.isComplete).thenReturn(true);
when(mockVisualStudio.isLaunchable).thenReturn(true);
when(mockVisualStudio.isRebootRequired).thenReturn(false);
when(mockVisualStudio.hasNecessaryComponents).thenReturn(true);
when(mockVisualStudio.fullVersion).thenReturn('15.1');
when(mockVisualStudio.displayName).thenReturn('Visual Studio Community 2017');
}
// Assigns default values for a missing VS installation. // Assigns default values for a missing VS installation.
void _configureMockVisualStudioAsNotInstalled() { void _configureMockVisualStudioAsNotInstalled() {
when(mockVisualStudio.isInstalled).thenReturn(false); when(mockVisualStudio.isInstalled).thenReturn(false);
when(mockVisualStudio.isAtLeastMinimumVersion).thenReturn(false);
when(mockVisualStudio.isPrerelease).thenReturn(false); when(mockVisualStudio.isPrerelease).thenReturn(false);
when(mockVisualStudio.isComplete).thenReturn(false); when(mockVisualStudio.isComplete).thenReturn(false);
when(mockVisualStudio.isLaunchable).thenReturn(false); when(mockVisualStudio.isLaunchable).thenReturn(false);
...@@ -97,6 +113,23 @@ void main() { ...@@ -97,6 +113,23 @@ void main() {
VisualStudio: () => mockVisualStudio, VisualStudio: () => mockVisualStudio,
}); });
testUsingContext('Emits partial status when Visual Studio is installed but too old', () async {
_configureMockVisualStudioAsTooOld();
const VisualStudioValidator validator = VisualStudioValidator();
final ValidationResult result = await validator.validate();
final ValidationMessage expectedMessage = ValidationMessage.error(
userMessages.visualStudioTooOld(
visualStudio.minimumVersionDescription,
visualStudio.workloadDescription,
visualStudio.necessaryComponentDescriptions(),
),
);
expect(result.messages.contains(expectedMessage), true);
expect(result.type, ValidationType.partial);
}, overrides: <Type, Generator>{
VisualStudio: () => mockVisualStudio,
});
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(); _configureMockVisualStudioAsInstalled();
...@@ -127,7 +160,7 @@ void main() { ...@@ -127,7 +160,7 @@ void main() {
final ValidationMessage expectedMessage = ValidationMessage.error( final ValidationMessage expectedMessage = ValidationMessage.error(
userMessages.visualStudioMissing( userMessages.visualStudioMissing(
visualStudio.workloadDescription, visualStudio.workloadDescription,
visualStudio.necessaryComponentDescriptions(validator.majorVersion), visualStudio.necessaryComponentDescriptions(),
), ),
); );
expect(result.messages.contains(expectedMessage), true); expect(result.messages.contains(expectedMessage), true);
......
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