| // 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); |
| |
| // 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, String response]) { |
| fs.file(vswherePath).createSync(recursive: true); |
| fs.file(vcvarsPath).createSync(recursive: true); |
| |
| final MockProcessResult result = MockProcessResult(); |
| when(result.exitCode).thenReturn(0); |
| when<String>(result.stdout).thenReturn(response == null |
| ? json.encode(<Map<String, dynamic>>[ |
| <String, dynamic>{ |
| 'installationPath': visualStudioPath, |
| 'displayName': 'Visual Studio Community 2017', |
| 'installationVersion': '15.9.28307.665', |
| 'catalog': <String, String>{ |
| 'productDisplayVersion': '15.9.12', |
| }, |
| } |
| ]) |
| : response); |
| |
| final List<String> requirementArguments = requiredComponents == null |
| ? <String>[] |
| : <String>['-requires', ...requiredComponents]; |
| when(mockProcessManager.runSync(<String>[ |
| vswherePath, |
| '-format', 'json', |
| '-utf8', |
| '-latest', |
| ...?requirementArguments, |
| ])).thenAnswer((Invocation invocation) { |
| return result; |
| }); |
| } |
| |
| // Sets whether or not a vswhere query without components will return an |
| // installation. |
| void setMockIncompleteVisualStudioExists(bool exists) { |
| setMockVswhereResponse(null, exists ? null : '[]'); |
| } |
| |
| // Sets whether or not a vswhere query with the required components will |
| // return an installation. |
| void setMockCompatibleVisualStudioExists(bool exists) { |
| setMockVswhereResponse(<String>[ |
| 'Microsoft.Component.MSBuild', |
| 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64', |
| 'Microsoft.VisualStudio.Component.Windows10SDK.17763', |
| ], exists ? null : '[]'); |
| } |
| |
| group('Visual Studio', () { |
| VisualStudio visualStudio; |
| |
| setUp(() { |
| mockProcessManager = MockProcessManager(); |
| }); |
| |
| testUsingContext('isInstalled returns false when vswhere is missing', () { |
| when(mockProcessManager.runSync(any)) |
| .thenThrow(const ProcessException('vswhere', <String>[])); |
| |
| visualStudio = VisualStudio(); |
| expect(visualStudio.isInstalled, false); |
| }, overrides: <Type, Generator>{ |
| FileSystem: () => memoryFilesystem, |
| Platform: () => windowsPlatform, |
| ProcessManager: () => mockProcessManager, |
| }); |
| |
| testUsingContext('vcvarsPath returns null when vswhere is missing', () { |
| when(mockProcessManager.runSync(any)) |
| .thenThrow(const ProcessException('vswhere', <String>[])); |
| |
| visualStudio = VisualStudio(); |
| expect(visualStudio.vcvarsPath, isNull); |
| }, overrides: <Type, Generator>{ |
| FileSystem: () => memoryFilesystem, |
| Platform: () => windowsPlatform, |
| ProcessManager: () => mockProcessManager, |
| }); |
| |
| testUsingContext('isInstalled returns false when vswhere returns non-zero', () { |
| when(mockProcessManager.runSync(any)) |
| .thenThrow(const ProcessException('vswhere', <String>[])); |
| final MockProcessResult result = MockProcessResult(); |
| when(result.exitCode).thenReturn(1); |
| when(mockProcessManager.runSync(any)).thenAnswer((Invocation invocation) { |
| return result; |
| }); |
| |
| visualStudio = VisualStudio(); |
| expect(visualStudio.isInstalled, false); |
| }, overrides: <Type, Generator>{ |
| FileSystem: () => memoryFilesystem, |
| Platform: () => windowsPlatform, |
| ProcessManager: () => mockProcessManager, |
| }); |
| |
| testUsingContext('isInstalled returns true when VS is present but missing components', () { |
| setMockIncompleteVisualStudioExists(true); |
| setMockCompatibleVisualStudioExists(false); |
| |
| visualStudio = VisualStudio(); |
| expect(visualStudio.isInstalled, true); |
| }, overrides: <Type, Generator>{ |
| FileSystem: () => memoryFilesystem, |
| Platform: () => windowsPlatform, |
| ProcessManager: () => mockProcessManager, |
| }); |
| |
| testUsingContext('hasNecessaryComponents returns false when VS is present but missing components', () { |
| setMockIncompleteVisualStudioExists(true); |
| setMockCompatibleVisualStudioExists(false); |
| |
| visualStudio = VisualStudio(); |
| expect(visualStudio.hasNecessaryComponents, false); |
| }, overrides: <Type, Generator>{ |
| FileSystem: () => memoryFilesystem, |
| Platform: () => windowsPlatform, |
| ProcessManager: () => mockProcessManager, |
| }); |
| |
| testUsingContext('vcvarsPath returns null when VS is present but missing components', () { |
| setMockIncompleteVisualStudioExists(true); |
| setMockCompatibleVisualStudioExists(false); |
| |
| visualStudio = VisualStudio(); |
| expect(visualStudio.vcvarsPath, isNull); |
| }, overrides: <Type, Generator>{ |
| FileSystem: () => memoryFilesystem, |
| Platform: () => windowsPlatform, |
| ProcessManager: () => mockProcessManager, |
| }); |
| |
| testUsingContext('VS metadata is available when VS is present, even if missing components', () { |
| setMockIncompleteVisualStudioExists(true); |
| setMockCompatibleVisualStudioExists(false); |
| |
| visualStudio = VisualStudio(); |
| expect(visualStudio.displayName, equals('Visual Studio Community 2017')); |
| expect(visualStudio.displayVersion, equals('15.9.12')); |
| expect(visualStudio.installLocation, equals(visualStudioPath)); |
| expect(visualStudio.fullVersion, equals('15.9.28307.665')); |
| }, overrides: <Type, Generator>{ |
| FileSystem: () => memoryFilesystem, |
| Platform: () => windowsPlatform, |
| ProcessManager: () => mockProcessManager, |
| }); |
| |
| |
| testUsingContext('isInstalled returns true when VS is present but missing components', () { |
| setMockIncompleteVisualStudioExists(true); |
| setMockCompatibleVisualStudioExists(false); |
| |
| visualStudio = VisualStudio(); |
| expect(visualStudio.isInstalled, true); |
| }, overrides: <Type, Generator>{ |
| FileSystem: () => memoryFilesystem, |
| Platform: () => windowsPlatform, |
| ProcessManager: () => mockProcessManager, |
| }); |
| |
| testUsingContext('Everything returns good values when VS is present with all components', () { |
| setMockCompatibleVisualStudioExists(true); |
| |
| visualStudio = VisualStudio(); |
| expect(visualStudio.isInstalled, true); |
| expect(visualStudio.hasNecessaryComponents, true); |
| expect(visualStudio.vcvarsPath, equals(vcvarsPath)); |
| }, overrides: <Type, Generator>{ |
| FileSystem: () => memoryFilesystem, |
| Platform: () => windowsPlatform, |
| ProcessManager: () => mockProcessManager, |
| }); |
| |
| testUsingContext('Metadata is for compatible version when latest is missing components', () { |
| setMockCompatibleVisualStudioExists(true); |
| // Return a different version for queries without the required packages. |
| final String incompleteVersionResponse = json.encode(<Map<String, dynamic>>[ |
| <String, dynamic>{ |
| 'installationPath': visualStudioPath, |
| 'displayName': 'Visual Studio Community 2019', |
| 'installationVersion': '16.1.1.1', |
| 'catalog': <String, String>{ |
| 'productDisplayVersion': '16.1', |
| }, |
| } |
| ]); |
| setMockVswhereResponse(null, incompleteVersionResponse); |
| |
| visualStudio = VisualStudio(); |
| expect(visualStudio.displayName, equals('Visual Studio Community 2017')); |
| expect(visualStudio.displayVersion, equals('15.9.12')); |
| }, overrides: <Type, Generator>{ |
| FileSystem: () => memoryFilesystem, |
| Platform: () => windowsPlatform, |
| ProcessManager: () => mockProcessManager, |
| }); |
| }); |
| } |