| // Copyright 2014 The Flutter 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:archive/archive.dart'; |
| import 'package:file/memory.dart'; |
| import 'package:flutter_tools/src/base/file_system.dart'; |
| import 'package:flutter_tools/src/base/platform.dart'; |
| import 'package:flutter_tools/src/base/user_messages.dart'; |
| import 'package:flutter_tools/src/convert.dart'; |
| import 'package:flutter_tools/src/doctor_validator.dart'; |
| import 'package:flutter_tools/src/intellij/intellij_validator.dart'; |
| import 'package:flutter_tools/src/ios/plist_parser.dart'; |
| |
| import '../../src/common.dart'; |
| import '../../src/fake_process_manager.dart'; |
| import '../../src/fakes.dart'; |
| |
| final Platform macPlatform = FakePlatform( |
| operatingSystem: 'macos', |
| environment: <String, String>{'HOME': '/foo/bar'} |
| ); |
| final Platform linuxPlatform = FakePlatform( |
| environment: <String, String>{ |
| 'HOME': '/foo/bar' |
| }, |
| ); |
| final Platform windowsPlatform = FakePlatform( |
| operatingSystem: 'windows', |
| environment: <String, String>{ |
| 'USERPROFILE': r'C:\Users\foo', |
| 'APPDATA': r'C:\Users\foo\AppData\Roaming', |
| 'LOCALAPPDATA': r'C:\Users\foo\AppData\Local' |
| }, |
| ); |
| |
| void main() { |
| testWithoutContext('Intellij validator can parse plugin manifest from plugin JAR', () async { |
| final FileSystem fileSystem = MemoryFileSystem.test(); |
| // Create plugin JAR file for Flutter and Dart plugin. |
| createIntellijFlutterPluginJar('plugins/flutter-intellij.jar', fileSystem); |
| createIntellijDartPluginJar('plugins/Dart/lib/Dart.jar', fileSystem); |
| |
| final ValidationResult result = await IntelliJValidatorTestTarget('', 'path/to/intellij', fileSystem).validate(); |
| expect(result.type, ValidationType.partial); |
| expect(result.statusInfo, 'version test.test.test'); |
| expect(result.messages, const <ValidationMessage>[ |
| ValidationMessage('IntelliJ at path/to/intellij'), |
| ValidationMessage.error('Flutter plugin version 0.1.3 - the recommended minimum version is 16.0.0'), |
| ValidationMessage('Dart plugin version 162.2485'), |
| ValidationMessage('For information about installing plugins, see\n' |
| 'https://flutter.dev/intellij-setup/#installing-the-plugins') |
| ]); |
| }); |
| |
| testWithoutContext('legacy intellij(<2020) plugins check on linux', () async { |
| const String cachePath = '/foo/bar/.IntelliJIdea2019.10/system'; |
| const String installPath = '/foo/bar/.local/share/JetBrains/Toolbox/apps/IDEA-U/ch-1/2019.10.1'; |
| const String pluginPath = '/foo/bar/.IntelliJIdea2019.10/config/plugins'; |
| final FileSystem fileSystem = MemoryFileSystem.test(); |
| |
| final Directory cacheDirectory = fileSystem.directory(cachePath) |
| ..createSync(recursive: true); |
| cacheDirectory |
| .childFile('.home') |
| .writeAsStringSync(installPath, flush: true); |
| final Directory installedDirectory = fileSystem.directory(installPath); |
| installedDirectory.createSync(recursive: true); |
| // Create plugin JAR file for Flutter and Dart plugin. |
| createIntellijFlutterPluginJar('$pluginPath/flutter-intellij/lib/flutter-intellij.jar', fileSystem, version: '50.0'); |
| createIntellijDartPluginJar('$pluginPath/Dart/lib/Dart.jar', fileSystem); |
| |
| final Iterable<DoctorValidator> installed = IntelliJValidatorOnLinux.installed( |
| fileSystem: fileSystem, |
| fileSystemUtils: FileSystemUtils(fileSystem: fileSystem, platform: linuxPlatform), |
| userMessages: UserMessages(), |
| ); |
| expect(1, installed.length); |
| final ValidationResult result = await installed.toList()[0].validate(); |
| expect(ValidationType.installed, result.type); |
| }); |
| |
| testWithoutContext('intellij(2020.1) plugins check on linux (installed via JetBrains ToolBox app)', () async { |
| const String cachePath = '/foo/bar/.cache/JetBrains/IntelliJIdea2020.10'; |
| const String installPath = '/foo/bar/.local/share/JetBrains/Toolbox/apps/IDEA-U/ch-1/2020.10.1'; |
| const String pluginPath = '/foo/bar/.local/share/JetBrains/Toolbox/apps/IDEA-U/ch-1/2020.10.1.plugins'; |
| final FileSystem fileSystem = MemoryFileSystem.test(); |
| |
| final Directory cacheDirectory = fileSystem.directory(cachePath) |
| ..createSync(recursive: true); |
| cacheDirectory |
| .childFile('.home') |
| .writeAsStringSync(installPath, flush: true); |
| final Directory installedDirectory = fileSystem.directory(installPath); |
| installedDirectory.createSync(recursive: true); |
| // Create plugin JAR file for Flutter and Dart plugin. |
| createIntellijFlutterPluginJar('$pluginPath/flutter-intellij/lib/flutter-intellij.jar', fileSystem, version: '50.0'); |
| createIntellijDartPluginJar('$pluginPath/Dart/lib/Dart.jar', fileSystem); |
| |
| final Iterable<DoctorValidator> installed = IntelliJValidatorOnLinux.installed( |
| fileSystem: fileSystem, |
| fileSystemUtils: FileSystemUtils(fileSystem: fileSystem, platform: linuxPlatform), |
| userMessages: UserMessages(), |
| ); |
| expect(1, installed.length); |
| final ValidationResult result = await installed.toList()[0].validate(); |
| expect(ValidationType.installed, result.type); |
| }); |
| |
| testWithoutContext('intellij(>=2020.2) plugins check on linux (installed via JetBrains ToolBox app)', () async { |
| const String cachePath = '/foo/bar/.cache/JetBrains/IntelliJIdea2020.10'; |
| const String installPath = '/foo/bar/.local/share/JetBrains/Toolbox/apps/IDEA-U/ch-1/2020.10.1'; |
| const String pluginPath = '/foo/bar/.local/share/JetBrains/IntelliJIdea2020.10'; |
| final FileSystem fileSystem = MemoryFileSystem.test(); |
| |
| final Directory cacheDirectory = fileSystem.directory(cachePath) |
| ..createSync(recursive: true); |
| cacheDirectory |
| .childFile('.home') |
| .writeAsStringSync(installPath, flush: true); |
| final Directory installedDirectory = fileSystem.directory(installPath); |
| installedDirectory.createSync(recursive: true); |
| // Create plugin JAR file for Flutter and Dart plugin. |
| createIntellijFlutterPluginJar('$pluginPath/flutter-intellij/lib/flutter-intellij.jar', fileSystem, version: '50.0'); |
| createIntellijDartPluginJar('$pluginPath/Dart/lib/Dart.jar', fileSystem); |
| |
| final Iterable<DoctorValidator> installed = IntelliJValidatorOnLinux.installed( |
| fileSystem: fileSystem, |
| fileSystemUtils: FileSystemUtils(fileSystem: fileSystem, platform: linuxPlatform), |
| userMessages: UserMessages(), |
| ); |
| expect(1, installed.length); |
| final ValidationResult result = await installed.toList()[0].validate(); |
| expect(ValidationType.installed, result.type); |
| }); |
| |
| testWithoutContext('intellij(2020.1~) plugins check on linux (installed via tar.gz)', () async { |
| const String cachePath = '/foo/bar/.cache/JetBrains/IdeaIC2020.10'; |
| const String installPath = '/foo/bar/some/dir/ideaIC-2020.10.1/idea-IC-201.0000.00'; |
| const String pluginPath = '/foo/bar/.local/share/JetBrains/IdeaIC2020.10'; |
| final FileSystem fileSystem = MemoryFileSystem.test(); |
| |
| final Directory cacheDirectory = fileSystem.directory(cachePath) |
| ..createSync(recursive: true); |
| cacheDirectory |
| .childFile('.home') |
| .writeAsStringSync(installPath, flush: true); |
| final Directory installedDirectory = fileSystem.directory(installPath); |
| installedDirectory.createSync(recursive: true); |
| // Create plugin JAR file for Flutter and Dart plugin. |
| createIntellijFlutterPluginJar('$pluginPath/flutter-intellij/lib/flutter-intellij.jar', fileSystem, version: '50.0'); |
| createIntellijDartPluginJar('$pluginPath/Dart/lib/Dart.jar', fileSystem); |
| |
| final Iterable<DoctorValidator> installed = IntelliJValidatorOnLinux.installed( |
| fileSystem: fileSystem, |
| fileSystemUtils: FileSystemUtils(fileSystem: fileSystem, platform: linuxPlatform), |
| userMessages: UserMessages(), |
| ); |
| expect(1, installed.length); |
| final ValidationResult result = await installed.toList()[0].validate(); |
| expect(ValidationType.installed, result.type); |
| }); |
| |
| testWithoutContext('legacy intellij(<2020) plugins check on windows', () async { |
| const String cachePath = r'C:\Users\foo\.IntelliJIdea2019.10\system'; |
| const String installPath = r'C:\Program Files\JetBrains\IntelliJ IDEA Ultimate Edition 2019.10.1'; |
| const String pluginPath = r'C:\Users\foo\.IntelliJIdea2019.10\config\plugins'; |
| final FileSystem fileSystem = MemoryFileSystem.test(style: FileSystemStyle.windows); |
| |
| final Directory cacheDirectory = fileSystem.directory(cachePath) |
| ..createSync(recursive: true); |
| cacheDirectory |
| .childFile('.home') |
| .writeAsStringSync(installPath, flush: true); |
| final Directory installedDirectory = fileSystem.directory(installPath); |
| installedDirectory.createSync(recursive: true); |
| createIntellijFlutterPluginJar('$pluginPath/flutter-intellij/lib/flutter-intellij.jar', fileSystem, version: '50.0'); |
| createIntellijDartPluginJar('$pluginPath/Dart/lib/Dart.jar', fileSystem); |
| |
| final Iterable<DoctorValidator> installed = IntelliJValidatorOnWindows.installed( |
| fileSystem: fileSystem, |
| fileSystemUtils: FileSystemUtils(fileSystem: fileSystem, platform: windowsPlatform), |
| platform: windowsPlatform, |
| userMessages: UserMessages(), |
| ); |
| expect(1, installed.length); |
| final ValidationResult result = await installed.toList()[0].validate(); |
| expect(ValidationType.installed, result.type); |
| }); |
| |
| testWithoutContext('intellij(2020.1 ~ 2020.2) plugins check on windows (installed via JetBrains ToolBox app)', () async { |
| const String cachePath = r'C:\Users\foo\AppData\Local\JetBrains\IntelliJIdea2020.10'; |
| const String installPath = r'C:\Users\foo\AppData\Local\JetBrains\Toolbox\apps\IDEA-U\ch-0\201.0000.00'; |
| const String pluginPath = r'C:\Users\foo\AppData\Roaming\JetBrains\IntelliJIdea2020.10\plugins'; |
| final FileSystem fileSystem = MemoryFileSystem.test(style: FileSystemStyle.windows); |
| |
| final Directory cacheDirectory = fileSystem.directory(cachePath) |
| ..createSync(recursive: true); |
| cacheDirectory |
| .childFile('.home') |
| .writeAsStringSync(installPath, flush: true); |
| final Directory installedDirectory = fileSystem.directory(installPath); |
| installedDirectory.createSync(recursive: true); |
| createIntellijFlutterPluginJar(pluginPath + r'\flutter-intellij\lib\flutter-intellij.jar', fileSystem, version: '50.0'); |
| createIntellijDartPluginJar(pluginPath + r'\Dart\lib\Dart.jar', fileSystem); |
| |
| final Iterable<DoctorValidator> installed = IntelliJValidatorOnWindows.installed( |
| fileSystem: fileSystem, |
| fileSystemUtils: FileSystemUtils(fileSystem: fileSystem, platform: windowsPlatform), |
| platform: windowsPlatform, |
| userMessages: UserMessages(), |
| ); |
| expect(1, installed.length); |
| final ValidationResult result = await installed.toList()[0].validate(); |
| expect(ValidationType.installed, result.type); |
| }); |
| |
| testWithoutContext('intellij(>=2020.3) plugins check on windows (installed via JetBrains ToolBox app and plugins)', () async { |
| const String cachePath = r'C:\Users\foo\AppData\Local\JetBrains\IntelliJIdea2020.10'; |
| const String installPath = r'C:\Users\foo\AppData\Local\JetBrains\Toolbox\apps\IDEA-U\ch-0\201.0000.00'; |
| const String pluginPath = r'C:\Users\foo\AppData\Local\JetBrains\Toolbox\apps\IDEA-U\ch-0\201.0000.00.plugins'; |
| final FileSystem fileSystem = MemoryFileSystem.test(style: FileSystemStyle.windows); |
| |
| final Directory cacheDirectory = fileSystem.directory(cachePath) |
| ..createSync(recursive: true); |
| cacheDirectory |
| .childFile('.home') |
| .writeAsStringSync(installPath, flush: true); |
| final Directory installedDirectory = fileSystem.directory(installPath); |
| installedDirectory.createSync(recursive: true); |
| createIntellijFlutterPluginJar(pluginPath + r'\flutter-intellij\lib\flutter-intellij.jar', fileSystem, version: '50.0'); |
| createIntellijDartPluginJar(pluginPath + r'\Dart\lib\Dart.jar', fileSystem); |
| |
| final Iterable<DoctorValidator> installed = IntelliJValidatorOnWindows.installed( |
| fileSystem: fileSystem, |
| fileSystemUtils: FileSystemUtils(fileSystem: fileSystem, platform: windowsPlatform), |
| platform: windowsPlatform, |
| userMessages: UserMessages(), |
| ); |
| expect(1, installed.length); |
| final ValidationResult result = await installed.toList()[0].validate(); |
| expect(ValidationType.installed, result.type); |
| }); |
| |
| testWithoutContext('intellij(2020.1~) plugins check on windows (installed via installer)', () async { |
| const String cachePath = r'C:\Users\foo\AppData\Local\JetBrains\IdeaIC2020.10'; |
| const String installPath = r'C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2020.10.1'; |
| const String pluginPath = r'C:\Users\foo\AppData\Roaming\JetBrains\IdeaIC2020.10\plugins'; |
| final FileSystem fileSystem = MemoryFileSystem.test(style: FileSystemStyle.windows); |
| |
| final Directory cacheDirectory = fileSystem.directory(cachePath) |
| ..createSync(recursive: true); |
| cacheDirectory |
| .childFile('.home') |
| .writeAsStringSync(installPath, flush: true); |
| final Directory installedDirectory = fileSystem.directory(installPath); |
| installedDirectory.createSync(recursive: true); |
| createIntellijFlutterPluginJar(pluginPath + r'\flutter-intellij\lib\flutter-intellij.jar', fileSystem, version: '50.0'); |
| createIntellijDartPluginJar(pluginPath + r'\Dart\lib\Dart.jar', fileSystem); |
| |
| final Iterable<DoctorValidator> installed = IntelliJValidatorOnWindows.installed( |
| fileSystem: fileSystem, |
| fileSystemUtils: FileSystemUtils(fileSystem: fileSystem, platform: windowsPlatform), |
| platform: windowsPlatform, |
| userMessages: UserMessages(), |
| ); |
| expect(1, installed.length); |
| final ValidationResult result = await installed.toList()[0].validate(); |
| expect(ValidationType.installed, result.type); |
| }); |
| |
| testWithoutContext('can locate installations on macOS from Spotlight', () { |
| final FileSystem fileSystem = MemoryFileSystem.test(); |
| final String ceRandomLocation = fileSystem.path.join( |
| '/', |
| 'random', |
| 'IntelliJ CE (stable).app', |
| ); |
| final String ultimateRandomLocation = fileSystem.path.join( |
| '/', |
| 'random', |
| 'IntelliJ UE (stable).app', |
| ); |
| |
| final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[ |
| FakeCommand( |
| command: const <String>[ |
| 'mdfind', |
| 'kMDItemCFBundleIdentifier="com.jetbrains.intellij.ce"', |
| ], |
| stdout: ceRandomLocation, |
| ), |
| FakeCommand( |
| command: const <String>[ |
| 'mdfind', |
| 'kMDItemCFBundleIdentifier="com.jetbrains.intellij*"', |
| ], |
| stdout: '$ultimateRandomLocation\n$ceRandomLocation', |
| ), |
| ]); |
| final Iterable<IntelliJValidatorOnMac> validators = IntelliJValidator.installedValidators( |
| fileSystem: fileSystem, |
| platform: macPlatform, |
| userMessages: UserMessages(), |
| processManager: processManager, |
| plistParser: FakePlistParser(<String, String>{ |
| PlistParser.kCFBundleShortVersionStringKey: '2020.10', |
| }), |
| ).whereType<IntelliJValidatorOnMac>(); |
| expect(validators.length, 2); |
| |
| final IntelliJValidatorOnMac ce = validators.where((IntelliJValidatorOnMac validator) => validator.id == 'IdeaIC').single; |
| expect(ce.title, 'IntelliJ IDEA Community Edition'); |
| expect(ce.installPath, ceRandomLocation); |
| |
| final IntelliJValidatorOnMac ultimate = validators.where((IntelliJValidatorOnMac validator) => validator.id == 'IntelliJIdea').single; |
| expect(ultimate.title, 'IntelliJ IDEA Ultimate Edition'); |
| expect(ultimate.installPath, ultimateRandomLocation); |
| }); |
| |
| testWithoutContext('Intellij plugins path checking on mac', () async { |
| final FileSystem fileSystem = MemoryFileSystem.test(); |
| final Directory pluginsDirectory = fileSystem.directory('/foo/bar/Library/Application Support/JetBrains/TestID2020.10/plugins') |
| ..createSync(recursive: true); |
| final IntelliJValidatorOnMac validator = IntelliJValidatorOnMac( |
| 'Test', |
| 'TestID', |
| '/path/to/app', |
| fileSystem: fileSystem, |
| homeDirPath: '/foo/bar', |
| userMessages: UserMessages(), |
| plistParser: FakePlistParser(<String, String>{ |
| PlistParser.kCFBundleShortVersionStringKey: '2020.10', |
| }) |
| ); |
| |
| expect(validator.plistFile, '/path/to/app/Contents/Info.plist'); |
| expect(validator.pluginsPath, pluginsDirectory.path); |
| }); |
| |
| testWithoutContext('legacy Intellij plugins path checking on mac', () async { |
| final FileSystem fileSystem = MemoryFileSystem.test(); |
| final IntelliJValidatorOnMac validator = IntelliJValidatorOnMac( |
| 'Test', |
| 'TestID', |
| '/foo', |
| fileSystem: fileSystem, |
| homeDirPath: '/foo/bar', |
| userMessages: UserMessages(), |
| plistParser: FakePlistParser(<String, String>{ |
| PlistParser.kCFBundleShortVersionStringKey: '2020.10', |
| }) |
| ); |
| |
| expect(validator.pluginsPath, '/foo/bar/Library/Application Support/TestID2020.10'); |
| }); |
| |
| testWithoutContext('Intellij plugins path checking on mac with JetBrains toolbox override', () async { |
| final FileSystem fileSystem = MemoryFileSystem.test(); |
| final IntelliJValidatorOnMac validator = IntelliJValidatorOnMac( |
| 'Test', |
| 'TestID', |
| '/foo', |
| fileSystem: fileSystem, |
| homeDirPath: '/foo/bar', |
| userMessages: UserMessages(), |
| plistParser: FakePlistParser(<String, String>{ |
| 'JetBrainsToolboxApp': '/path/to/JetBrainsToolboxApp', |
| }) |
| ); |
| |
| expect(validator.pluginsPath, '/path/to/JetBrainsToolboxApp.plugins'); |
| }); |
| } |
| |
| class IntelliJValidatorTestTarget extends IntelliJValidator { |
| IntelliJValidatorTestTarget(super.title, super.installPath, FileSystem fileSystem) |
| : super(fileSystem: fileSystem, userMessages: UserMessages()); |
| |
| @override |
| String get pluginsPath => 'plugins'; |
| |
| @override |
| String get version => 'test.test.test'; |
| } |
| |
| /// A helper to create a Intellij Flutter plugin jar. |
| /// |
| /// These file contents were derived from the META-INF/plugin.xml from an Intellij Flutter |
| /// plugin installation. |
| /// |
| /// The file is located in a plugin JAR, which can be located by looking at the plugin |
| /// path for the Intellij and Android Studio validators. |
| /// |
| /// If more XML contents are needed, prefer modifying these contents over checking |
| /// in another JAR. |
| void createIntellijFlutterPluginJar(String pluginJarPath, FileSystem fileSystem, {String version = '0.1.3'}) { |
| final String intellijFlutterPluginXml = ''' |
| <idea-plugin version="2"> |
| <id>io.flutter</id> |
| <name>Flutter</name> |
| <description>Support for developing Flutter applications.</description> |
| <vendor url="https://github.com/flutter/flutter-intellij">flutter.io</vendor> |
| |
| <category>Custom Languages</category> |
| |
| <version>$version</version> |
| |
| <idea-version since-build="162.1" until-build="163.*"/> |
| </idea-plugin> |
| '''; |
| |
| final List<int> flutterPluginBytes = utf8.encode(intellijFlutterPluginXml); |
| final Archive flutterPlugins = Archive(); |
| flutterPlugins.addFile(ArchiveFile('META-INF/plugin.xml', flutterPluginBytes.length, flutterPluginBytes)); |
| fileSystem.file(pluginJarPath) |
| ..createSync(recursive: true) |
| ..writeAsBytesSync(ZipEncoder().encode(flutterPlugins)!); |
| |
| } |
| |
| /// A helper to create a Intellij Dart plugin jar. |
| /// |
| /// This jar contains META-INF/plugin.xml. |
| /// Its contents were derived from the META-INF/plugin.xml from an Intellij Dart |
| /// plugin installation. |
| /// |
| /// The file is located in a plugin JAR, which can be located by looking at the plugin |
| /// path for the Intellij and Android Studio validators. |
| /// |
| /// If more XML contents are needed, prefer modifying these contents over checking |
| /// in another JAR. |
| void createIntellijDartPluginJar(String pluginJarPath, FileSystem fileSystem) { |
| const String intellijDartPluginXml = r''' |
| <idea-plugin version="2"> |
| <name>Dart</name> |
| <version>162.2485</version> |
| <idea-version since-build="162.1121" until-build="162.*"/> |
| |
| <description>Support for Dart programming language</description> |
| <vendor>JetBrains</vendor> |
| <depends>com.intellij.modules.xml</depends> |
| <depends optional="true" config-file="dartium-debugger-support.xml">JavaScriptDebugger</depends> |
| <depends optional="true" config-file="dart-yaml.xml">org.jetbrains.plugins.yaml</depends> |
| <depends optional="true" config-file="dart-copyright.xml">com.intellij.copyright</depends> |
| <depends optional="true" config-file="dart-coverage.xml">com.intellij.modules.coverage</depends> |
| </idea-plugin> |
| '''; |
| |
| final List<int> dartPluginBytes = utf8.encode(intellijDartPluginXml); |
| final Archive dartPlugins = Archive(); |
| dartPlugins.addFile(ArchiveFile('META-INF/plugin.xml', dartPluginBytes.length, dartPluginBytes)); |
| fileSystem.file(pluginJarPath) |
| ..createSync(recursive: true) |
| ..writeAsBytesSync(ZipEncoder().encode(dartPlugins)!); |
| } |