mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00

...because otherwise, processes that think they're manipulating your filesystem will be doing crazy things the test is ignoring, leading to (at best) failures and (at worst) flakes or disk corruption.
445 lines
18 KiB
Dart
445 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,
|
|
]) {
|
|
fs.file(vswherePath).createSync(recursive: true);
|
|
fs.file(vcvarsPath).createSync(recursive: true);
|
|
|
|
final MockProcessResult result = MockProcessResult();
|
|
when(result.exitCode).thenReturn(0);
|
|
|
|
final String finalResponse =
|
|
json.encode(<Map<String, dynamic>>[response]);
|
|
when<String>(result.stdout).thenReturn(finalResponse);
|
|
when<String>(result.stderr).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);
|
|
}
|
|
|
|
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).thenReturn('');
|
|
when<String>(result.stderr).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('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,
|
|
});
|
|
});
|
|
}
|