mirror of
https://github.com/flutter/flutter
synced 2024-10-13 19:52:53 +00:00
980f14e0c5
* implicit-casts:false on flutter_tools * use castStringKeyedMap * address review comments * address review comments * fix issues after rebase
464 lines
18 KiB
Dart
464 lines
18 KiB
Dart
// Copyright 2019 The Chromium 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:file/memory.dart';
|
|
import 'package:flutter_tools/src/base/file_system.dart';
|
|
import 'package:flutter_tools/src/base/io.dart' show ProcessException, ProcessResult;
|
|
import 'package:flutter_tools/src/base/platform.dart';
|
|
import 'package:flutter_tools/src/convert.dart';
|
|
import 'package:flutter_tools/src/windows/visual_studio.dart';
|
|
import 'package:mockito/mockito.dart';
|
|
import 'package:process/process.dart';
|
|
|
|
import '../../src/common.dart';
|
|
import '../../src/context.dart';
|
|
|
|
class MockPlatform extends Mock implements Platform {
|
|
@override
|
|
Map<String, String> environment = <String, String>{};
|
|
}
|
|
class MockProcessManager extends Mock implements ProcessManager {}
|
|
class MockProcessResult extends Mock implements ProcessResult {}
|
|
|
|
void main() {
|
|
const String programFilesPath = r'C:\Program Files (x86)';
|
|
const String visualStudioPath = programFilesPath + r'\Microsoft Visual Studio\2017\Community';
|
|
const String vcvarsPath = visualStudioPath + r'\VC\Auxiliary\Build\vcvars64.bat';
|
|
const String vswherePath = programFilesPath + r'\Microsoft Visual Studio\Installer\vswhere.exe';
|
|
|
|
final MockPlatform windowsPlatform = MockPlatform()
|
|
..environment['PROGRAMFILES(X86)'] = r'C:\Program Files (x86)\';
|
|
MockProcessManager mockProcessManager;
|
|
final MemoryFileSystem memoryFilesystem = MemoryFileSystem(style: FileSystemStyle.windows);
|
|
|
|
// A minimum version of a response where a VS installation was found.
|
|
const Map<String, dynamic> _defaultResponse = <String, dynamic>{
|
|
'installationPath': visualStudioPath,
|
|
'displayName': 'Visual Studio Community 2019',
|
|
'installationVersion': '16.2.29306.81',
|
|
'isRebootRequired': false,
|
|
'isComplete': true,
|
|
'isLaunchable': true,
|
|
'isPrerelease': false,
|
|
'catalog': <String, dynamic>{
|
|
'productDisplayVersion': '16.2.5',
|
|
},
|
|
};
|
|
|
|
// A version of a response that doesn't include certain installation status
|
|
// information that might be missing in older Visual Studio versions.
|
|
const Map<String, dynamic> _missingStatusResponse = <String, dynamic>{
|
|
'installationPath': visualStudioPath,
|
|
'displayName': 'Visual Studio Community 2017',
|
|
'installationVersion': '15.9.28307.665',
|
|
'catalog': <String, dynamic>{
|
|
'productDisplayVersion': '15.9.12',
|
|
},
|
|
};
|
|
|
|
// Arguments for a vswhere query to search for an installation with the required components.
|
|
const List<String> _requiredComponents = <String>[
|
|
'Microsoft.Component.MSBuild',
|
|
'Microsoft.VisualStudio.Component.VC.Tools.x86.x64',
|
|
'Microsoft.VisualStudio.Component.Windows10SDK.17763',
|
|
];
|
|
|
|
// Sets up the mock environment so that searching for Visual Studio with
|
|
// exactly the given required components will provide a result. By default it
|
|
// return a preset installation, but the response can be overridden.
|
|
void setMockVswhereResponse([
|
|
List<String> requiredComponents,
|
|
List<String> additionalArguments,
|
|
Map<String, dynamic> response,
|
|
String responseOverride,
|
|
]) {
|
|
fs.file(vswherePath).createSync(recursive: true);
|
|
fs.file(vcvarsPath).createSync(recursive: true);
|
|
|
|
final MockProcessResult result = MockProcessResult();
|
|
when(result.exitCode).thenReturn(0);
|
|
|
|
final String finalResponse = responseOverride ??
|
|
json.encode(<Map<String, dynamic>>[response]);
|
|
when<String>(result.stdout as String).thenReturn(finalResponse);
|
|
when<String>(result.stderr as String).thenReturn('');
|
|
final List<String> requirementArguments = requiredComponents == null
|
|
? <String>[]
|
|
: <String>['-requires', ...requiredComponents];
|
|
when(mockProcessManager.runSync(
|
|
<String>[
|
|
vswherePath,
|
|
'-format',
|
|
'json',
|
|
'-utf8',
|
|
'-latest',
|
|
...?additionalArguments,
|
|
...?requirementArguments,
|
|
],
|
|
workingDirectory: anyNamed('workingDirectory'),
|
|
environment: anyNamed('environment'),
|
|
)).thenAnswer((Invocation invocation) {
|
|
return result;
|
|
});
|
|
}
|
|
|
|
// Sets whether or not a vswhere query with the required components will
|
|
// return an installation.
|
|
void setMockCompatibleVisualStudioInstallation(Map<String, dynamic>response) {
|
|
setMockVswhereResponse(_requiredComponents, null, response);
|
|
}
|
|
|
|
// Sets whether or not a vswhere query with the required components will
|
|
// return a pre-release installation.
|
|
void setMockPrereleaseVisualStudioInstallation(Map<String, dynamic>response) {
|
|
setMockVswhereResponse(_requiredComponents, <String>['-prerelease'], response);
|
|
}
|
|
|
|
// Sets whether or not a vswhere query searching for 'all' and 'prerelease'
|
|
// versions will return an installation.
|
|
void setMockAnyVisualStudioInstallation(Map<String, dynamic> response) {
|
|
setMockVswhereResponse(null, <String>['-prerelease', '-all'], response);
|
|
}
|
|
|
|
// Set a pre-encoded query result.
|
|
void setMockEncodedAnyVisualStudioInstallation(String response) {
|
|
setMockVswhereResponse(null, <String>['-prerelease', '-all'], null, response);
|
|
}
|
|
|
|
group('Visual Studio', () {
|
|
VisualStudio visualStudio;
|
|
|
|
setUp(() {
|
|
mockProcessManager = MockProcessManager();
|
|
});
|
|
|
|
testUsingContext('isInstalled returns false when vswhere is missing', () {
|
|
when(mockProcessManager.runSync(
|
|
any,
|
|
workingDirectory: anyNamed('workingDirectory'),
|
|
environment: anyNamed('environment'),
|
|
)).thenThrow(const ProcessException('vswhere', <String>[]));
|
|
|
|
visualStudio = VisualStudio();
|
|
expect(visualStudio.isInstalled, false);
|
|
}, overrides: <Type, Generator>{
|
|
FileSystem: () => memoryFilesystem,
|
|
ProcessManager: () => mockProcessManager,
|
|
Platform: () => windowsPlatform,
|
|
});
|
|
|
|
testUsingContext('vcvarsPath returns null when vswhere is missing', () {
|
|
when(mockProcessManager.runSync(
|
|
any,
|
|
workingDirectory: anyNamed('workingDirectory'),
|
|
environment: anyNamed('environment'),
|
|
)).thenThrow(const ProcessException('vswhere', <String>[]));
|
|
|
|
visualStudio = VisualStudio();
|
|
expect(visualStudio.vcvarsPath, isNull);
|
|
}, overrides: <Type, Generator>{
|
|
FileSystem: () => memoryFilesystem,
|
|
ProcessManager: () => mockProcessManager,
|
|
Platform: () => windowsPlatform,
|
|
});
|
|
|
|
testUsingContext('isInstalled returns false when vswhere returns non-zero', () {
|
|
|
|
when(mockProcessManager.runSync(
|
|
any,
|
|
workingDirectory: anyNamed('workingDirectory'),
|
|
environment: anyNamed('environment'),
|
|
)).thenThrow(const ProcessException('vswhere', <String>[]));
|
|
|
|
final MockProcessResult result = MockProcessResult();
|
|
when(result.exitCode).thenReturn(1);
|
|
when(mockProcessManager.runSync(
|
|
any,
|
|
workingDirectory: anyNamed('workingDirectory'),
|
|
environment: anyNamed('environment'),
|
|
)).thenAnswer((Invocation invocation) {
|
|
return result;
|
|
});
|
|
when<String>(result.stdout as String).thenReturn('');
|
|
when<String>(result.stderr as String).thenReturn('');
|
|
|
|
visualStudio = VisualStudio();
|
|
expect(visualStudio.isInstalled, false);
|
|
}, overrides: <Type, Generator>{
|
|
FileSystem: () => memoryFilesystem,
|
|
ProcessManager: () => mockProcessManager,
|
|
Platform: () => windowsPlatform,
|
|
});
|
|
|
|
testUsingContext('VisualStudio getters return the right values if no installation is found', () {
|
|
setMockCompatibleVisualStudioInstallation(null);
|
|
setMockPrereleaseVisualStudioInstallation(null);
|
|
setMockAnyVisualStudioInstallation(null);
|
|
|
|
visualStudio = VisualStudio();
|
|
expect(visualStudio.isInstalled, false);
|
|
expect(visualStudio.hasNecessaryComponents, false);
|
|
expect(visualStudio.isComplete, false);
|
|
expect(visualStudio.isRebootRequired, false);
|
|
expect(visualStudio.isLaunchable, false);
|
|
expect(visualStudio.displayName, null);
|
|
expect(visualStudio.displayVersion, null);
|
|
expect(visualStudio.installLocation, null);
|
|
expect(visualStudio.fullVersion, null);
|
|
}, overrides: <Type, Generator>{
|
|
FileSystem: () => memoryFilesystem,
|
|
ProcessManager: () => mockProcessManager,
|
|
Platform: () => windowsPlatform,
|
|
});
|
|
|
|
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,
|
|
ProcessManager: () => mockProcessManager,
|
|
Platform: () => windowsPlatform,
|
|
});
|
|
|
|
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,
|
|
ProcessManager: () => mockProcessManager,
|
|
Platform: () => windowsPlatform,
|
|
});
|
|
|
|
testUsingContext('isInstalled returns true even with missing status information', () {
|
|
setMockCompatibleVisualStudioInstallation(null);
|
|
setMockPrereleaseVisualStudioInstallation(null);
|
|
setMockAnyVisualStudioInstallation(_missingStatusResponse);
|
|
|
|
visualStudio = VisualStudio();
|
|
expect(visualStudio.isInstalled, true);
|
|
}, overrides: <Type, Generator>{
|
|
FileSystem: () => memoryFilesystem,
|
|
ProcessManager: () => mockProcessManager,
|
|
Platform: () => windowsPlatform,
|
|
});
|
|
|
|
testUsingContext('isInstalled returns true when VS is present but missing components', () {
|
|
setMockCompatibleVisualStudioInstallation(null);
|
|
setMockPrereleaseVisualStudioInstallation(null);
|
|
setMockAnyVisualStudioInstallation(_defaultResponse);
|
|
|
|
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', () {
|
|
setMockCompatibleVisualStudioInstallation(null);
|
|
setMockAnyVisualStudioInstallation(null);
|
|
|
|
final Map<String, dynamic> response = Map<String, dynamic>.from(_defaultResponse)
|
|
..['isPrerelease'] = true;
|
|
setMockPrereleaseVisualStudioInstallation(response);
|
|
|
|
visualStudio = VisualStudio();
|
|
expect(visualStudio.isInstalled, true);
|
|
expect(visualStudio.isPrerelease, true);
|
|
}, overrides: <Type, Generator>{
|
|
FileSystem: () => memoryFilesystem,
|
|
ProcessManager: () => mockProcessManager,
|
|
Platform: () => windowsPlatform,
|
|
});
|
|
|
|
testUsingContext('isComplete returns false when an incomplete installation is found', () {
|
|
setMockCompatibleVisualStudioInstallation(null);
|
|
setMockPrereleaseVisualStudioInstallation(null);
|
|
|
|
final Map<String, dynamic> response = Map<String, dynamic>.from(_defaultResponse)
|
|
..['isComplete'] = false;
|
|
setMockAnyVisualStudioInstallation(response);
|
|
|
|
visualStudio = VisualStudio();
|
|
expect(visualStudio.isInstalled, true);
|
|
expect(visualStudio.isComplete, false);
|
|
}, overrides: <Type, Generator>{
|
|
FileSystem: () => memoryFilesystem,
|
|
ProcessManager: () => mockProcessManager,
|
|
Platform: () => windowsPlatform,
|
|
});
|
|
|
|
testUsingContext('isLaunchable returns false if the installation can\'t be launched', () {
|
|
setMockCompatibleVisualStudioInstallation(null);
|
|
setMockPrereleaseVisualStudioInstallation(null);
|
|
|
|
final Map<String, dynamic> response = Map<String, dynamic>.from(_defaultResponse)
|
|
..['isLaunchable'] = false;
|
|
setMockAnyVisualStudioInstallation(response);
|
|
|
|
visualStudio = VisualStudio();
|
|
expect(visualStudio.isInstalled, true);
|
|
expect(visualStudio.isLaunchable, false);
|
|
}, overrides: <Type, Generator>{
|
|
FileSystem: () => memoryFilesystem,
|
|
ProcessManager: () => mockProcessManager,
|
|
Platform: () => windowsPlatform,
|
|
});
|
|
|
|
testUsingContext('isRebootRequired returns true if the installation needs a reboot', () {
|
|
setMockCompatibleVisualStudioInstallation(null);
|
|
setMockPrereleaseVisualStudioInstallation(null);
|
|
|
|
final Map<String, dynamic> response = Map<String, dynamic>.from(_defaultResponse)
|
|
..['isRebootRequired'] = true;
|
|
setMockAnyVisualStudioInstallation(response);
|
|
|
|
visualStudio = VisualStudio();
|
|
expect(visualStudio.isInstalled, true);
|
|
expect(visualStudio.isRebootRequired, true);
|
|
}, overrides: <Type, Generator>{
|
|
FileSystem: () => memoryFilesystem,
|
|
ProcessManager: () => mockProcessManager,
|
|
Platform: () => windowsPlatform,
|
|
});
|
|
|
|
|
|
testUsingContext('hasNecessaryComponents returns false when VS is present but missing components', () {
|
|
setMockCompatibleVisualStudioInstallation(null);
|
|
setMockPrereleaseVisualStudioInstallation(null);
|
|
setMockAnyVisualStudioInstallation(_defaultResponse);
|
|
|
|
visualStudio = VisualStudio();
|
|
expect(visualStudio.hasNecessaryComponents, false);
|
|
}, overrides: <Type, Generator>{
|
|
FileSystem: () => memoryFilesystem,
|
|
ProcessManager: () => mockProcessManager,
|
|
Platform: () => windowsPlatform,
|
|
});
|
|
|
|
testUsingContext('vcvarsPath returns null when VS is present but missing components', () {
|
|
setMockCompatibleVisualStudioInstallation(null);
|
|
setMockPrereleaseVisualStudioInstallation(null);
|
|
setMockAnyVisualStudioInstallation(_defaultResponse);
|
|
|
|
visualStudio = VisualStudio();
|
|
expect(visualStudio.vcvarsPath, isNull);
|
|
}, overrides: <Type, Generator>{
|
|
FileSystem: () => memoryFilesystem,
|
|
ProcessManager: () => mockProcessManager,
|
|
Platform: () => windowsPlatform,
|
|
});
|
|
|
|
testUsingContext('vcvarsPath returns null when VS is present but with require components but installation is faulty', () {
|
|
final Map<String, dynamic> response = Map<String, dynamic>.from(_defaultResponse)
|
|
..['isRebootRequired'] = true;
|
|
setMockCompatibleVisualStudioInstallation(response);
|
|
setMockPrereleaseVisualStudioInstallation(null);
|
|
|
|
visualStudio = VisualStudio();
|
|
expect(visualStudio.vcvarsPath, isNull);
|
|
}, overrides: <Type, Generator>{
|
|
FileSystem: () => memoryFilesystem,
|
|
ProcessManager: () => mockProcessManager,
|
|
Platform: () => windowsPlatform,
|
|
});
|
|
|
|
testUsingContext('hasNecessaryComponents returns false when VS is present with required components but installation is faulty', () {
|
|
final Map<String, dynamic> response = Map<String, dynamic>.from(_defaultResponse)
|
|
..['isRebootRequired'] = true;
|
|
setMockCompatibleVisualStudioInstallation(response);
|
|
setMockPrereleaseVisualStudioInstallation(null);
|
|
|
|
visualStudio = VisualStudio();
|
|
expect(visualStudio.hasNecessaryComponents, false);
|
|
}, overrides: <Type, Generator>{
|
|
FileSystem: () => memoryFilesystem,
|
|
ProcessManager: () => mockProcessManager,
|
|
Platform: () => windowsPlatform,
|
|
});
|
|
|
|
testUsingContext('VS metadata is available when VS is present, even if missing components', () {
|
|
setMockCompatibleVisualStudioInstallation(null);
|
|
setMockPrereleaseVisualStudioInstallation(null);
|
|
setMockAnyVisualStudioInstallation(_defaultResponse);
|
|
|
|
visualStudio = VisualStudio();
|
|
expect(visualStudio.displayName, equals('Visual Studio Community 2019'));
|
|
expect(visualStudio.displayVersion, equals('16.2.5'));
|
|
expect(visualStudio.installLocation, equals(visualStudioPath));
|
|
expect(visualStudio.fullVersion, equals('16.2.29306.81'));
|
|
}, overrides: <Type, Generator>{
|
|
FileSystem: () => memoryFilesystem,
|
|
ProcessManager: () => mockProcessManager,
|
|
Platform: () => windowsPlatform,
|
|
});
|
|
|
|
testUsingContext('vcvarsPath returns null when VS is present but when vswhere returns invalid JSON', () {
|
|
setMockCompatibleVisualStudioInstallation(null);
|
|
setMockPrereleaseVisualStudioInstallation(null);
|
|
setMockEncodedAnyVisualStudioInstallation('{');
|
|
|
|
visualStudio = VisualStudio();
|
|
expect(visualStudio.vcvarsPath, isNull);
|
|
}, overrides: <Type, Generator>{
|
|
FileSystem: () => memoryFilesystem,
|
|
ProcessManager: () => mockProcessManager,
|
|
Platform: () => windowsPlatform,
|
|
});
|
|
|
|
testUsingContext('Everything returns good values when VS is present with all components', () {
|
|
setMockCompatibleVisualStudioInstallation(_defaultResponse);
|
|
setMockPrereleaseVisualStudioInstallation(null);
|
|
setMockAnyVisualStudioInstallation(null);
|
|
|
|
visualStudio = VisualStudio();
|
|
expect(visualStudio.isInstalled, true);
|
|
expect(visualStudio.hasNecessaryComponents, true);
|
|
expect(visualStudio.vcvarsPath, equals(vcvarsPath));
|
|
}, overrides: <Type, Generator>{
|
|
FileSystem: () => memoryFilesystem,
|
|
ProcessManager: () => mockProcessManager,
|
|
Platform: () => windowsPlatform,
|
|
});
|
|
|
|
testUsingContext('Metadata is for compatible version when latest is missing components', () {
|
|
// 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);
|
|
// Return a different version for queries without the required packages.
|
|
final Map<String, dynamic> incompleteVersionResponse = <String, dynamic>{
|
|
'installationPath': visualStudioPath,
|
|
'displayName': 'Visual Studio Community 2019',
|
|
'installationVersion': '16.1.1.1',
|
|
'catalog': <String, String>{
|
|
'productDisplayVersion': '16.1',
|
|
},
|
|
};
|
|
setMockAnyVisualStudioInstallation(incompleteVersionResponse);
|
|
|
|
visualStudio = VisualStudio();
|
|
expect(visualStudio.displayName, equals('Visual Studio Community 2017'));
|
|
expect(visualStudio.displayVersion, equals('15.9.12'));
|
|
}, overrides: <Type, Generator>{
|
|
FileSystem: () => memoryFilesystem,
|
|
ProcessManager: () => mockProcessManager,
|
|
Platform: () => windowsPlatform,
|
|
});
|
|
});
|
|
}
|