diff --git a/packages/flutter_tools/lib/src/android/android_studio.dart b/packages/flutter_tools/lib/src/android/android_studio.dart index 3bef6d5c6cb..47e35f13d36 100644 --- a/packages/flutter_tools/lib/src/android/android_studio.dart +++ b/packages/flutter_tools/lib/src/android/android_studio.dart @@ -162,6 +162,9 @@ class AndroidStudio { bool _isValid = false; final List _validationMessages = []; + /// The path of the JDK bundled with Android Studio. + /// + /// This will be null if the bundled JDK could not be found or run. String? get javaPath => _javaPath; bool get isValid => _isValid; @@ -487,16 +490,17 @@ the configured path by running this command: flutter config --android-studio-dir if (globals.platform.isMacOS) { if (version != null && version!.major < 2020) { javaPath = globals.fs.path.join(directory, 'jre', 'jdk', 'Contents', 'Home'); - } else if (version != null && version!.major == 2022) { - javaPath = globals.fs.path.join(directory, 'jbr', 'Contents', 'Home'); - } else { + } else if (version != null && version!.major < 2022) { javaPath = globals.fs.path.join(directory, 'jre', 'Contents', 'Home'); + // See https://github.com/flutter/flutter/issues/125246 for more context. + } else { + javaPath = globals.fs.path.join(directory, 'jbr', 'Contents', 'Home'); } } else { - if (version != null && version!.major == 2022) { - javaPath = globals.fs.path.join(directory, 'jbr'); - } else { + if (version != null && version!.major < 2022) { javaPath = globals.fs.path.join(directory, 'jre'); + } else { + javaPath = globals.fs.path.join(directory, 'jbr'); } } final String javaExecutable = globals.fs.path.join(javaPath, 'bin', 'java'); diff --git a/packages/flutter_tools/test/general.shard/android/android_studio_test.dart b/packages/flutter_tools/test/general.shard/android/android_studio_test.dart index e3090e7274c..4a82d882329 100644 --- a/packages/flutter_tools/test/general.shard/android/android_studio_test.dart +++ b/packages/flutter_tools/test/general.shard/android/android_studio_test.dart @@ -73,14 +73,14 @@ void main() { }, }; - const Map macStudioInfoPlistEAP = { - 'CFBundleGetInfoString': 'Android Studio EAP AI-212.5712.43.2112.8233820, build AI-212.5712.43.2112.8233820. Copyright JetBrains s.r.o., (c) 2000-2022', - 'CFBundleShortVersionString': 'EAP AI-212.5712.43.2112.8233820', - 'CFBundleVersion': 'AI-212.5712.43.2112.8233820', + const Map macStudioInfoPlistEap_2022_3_1_11 = { + 'CFBundleGetInfoString': 'Android Studio EAP AI-223.8836.35.2231.9848316, build AI-223.8836.35.2231.9848316. Copyright JetBrains s.r.o., (c) 2000-2023', + 'CFBundleShortVersionString': 'EAP AI-223.8836.35.2231.9848316', + 'CFBundleVersion': 'AI-223.8836.35.2231.9848316', 'JVMOptions': { 'Properties': { 'idea.vendor.name' : 'Google', - 'idea.paths.selector': 'AndroidStudio2021.2', + 'idea.paths.selector': 'AndroidStudioPreview2022.3', 'idea.platform.prefix': 'AndroidStudio', }, }, @@ -107,30 +107,30 @@ void main() { }); testUsingContext('discovers Android Studio >=4.1 location', () { - final String studioInApplicationPlistFolder = globals.fs.path.join( + final String studioInApplicationPlistFolder = fileSystem.path.join( '/', 'Application', 'Android Studio.app', 'Contents', ); - globals.fs.directory(studioInApplicationPlistFolder).createSync(recursive: true); + fileSystem.directory(studioInApplicationPlistFolder).createSync(recursive: true); - final String plistFilePath = globals.fs.path.join(studioInApplicationPlistFolder, 'Info.plist'); + final String plistFilePath = fileSystem.path.join(studioInApplicationPlistFolder, 'Info.plist'); plistUtils.fileContents[plistFilePath] = macStudioInfoPlist4_1; processManager.addCommand(FakeCommand( command: [ - globals.fs.path.join(studioInApplicationPlistFolder, 'jre', 'jdk', 'Contents', 'Home', 'bin', 'java'), + fileSystem.path.join(studioInApplicationPlistFolder, 'jre', 'jdk', 'Contents', 'Home', 'bin', 'java'), '-version', ], stderr: '123', ) ); final AndroidStudio studio = AndroidStudio.fromMacOSBundle( - globals.fs.directory(studioInApplicationPlistFolder).parent.path, + fileSystem.directory(studioInApplicationPlistFolder).parent.path, )!; expect(studio, isNotNull); - expect(studio.pluginsPath, equals(globals.fs.path.join( + expect(studio.pluginsPath, equals(fileSystem.path.join( homeMac, 'Library', 'Application Support', @@ -149,30 +149,30 @@ void main() { }); testUsingContext('discovers Android Studio >=2020.3 location', () { - final String studioInApplicationPlistFolder = globals.fs.path.join( + final String studioInApplicationPlistFolder = fileSystem.path.join( '/', 'Application', 'Android Studio.app', 'Contents', ); - globals.fs.directory(studioInApplicationPlistFolder).createSync(recursive: true); + fileSystem.directory(studioInApplicationPlistFolder).createSync(recursive: true); - final String plistFilePath = globals.fs.path.join(studioInApplicationPlistFolder, 'Info.plist'); + final String plistFilePath = fileSystem.path.join(studioInApplicationPlistFolder, 'Info.plist'); plistUtils.fileContents[plistFilePath] = macStudioInfoPlist2020_3; processManager.addCommand(FakeCommand( command: [ - globals.fs.path.join(studioInApplicationPlistFolder, 'jre', 'Contents', 'Home', 'bin', 'java'), + fileSystem.path.join(studioInApplicationPlistFolder, 'jre', 'Contents', 'Home', 'bin', 'java'), '-version', ], stderr: '123', ) ); final AndroidStudio studio = AndroidStudio.fromMacOSBundle( - globals.fs.directory(studioInApplicationPlistFolder).parent.path, + fileSystem.directory(studioInApplicationPlistFolder).parent.path, )!; expect(studio, isNotNull); - expect(studio.pluginsPath, equals(globals.fs.path.join( + expect(studio.pluginsPath, equals(fileSystem.path.join( homeMac, 'Library', 'Application Support', @@ -191,30 +191,30 @@ void main() { }); testUsingContext('discovers Android Studio <4.1 location', () { - final String studioInApplicationPlistFolder = globals.fs.path.join( + final String studioInApplicationPlistFolder = fileSystem.path.join( '/', 'Application', 'Android Studio.app', 'Contents', ); - globals.fs.directory(studioInApplicationPlistFolder).createSync(recursive: true); + fileSystem.directory(studioInApplicationPlistFolder).createSync(recursive: true); - final String plistFilePath = globals.fs.path.join(studioInApplicationPlistFolder, 'Info.plist'); + final String plistFilePath = fileSystem.path.join(studioInApplicationPlistFolder, 'Info.plist'); plistUtils.fileContents[plistFilePath] = macStudioInfoPlist3_3; processManager.addCommand(FakeCommand( command: [ - globals.fs.path.join(studioInApplicationPlistFolder, 'jre', 'jdk', 'Contents', 'Home', 'bin', 'java'), + fileSystem.path.join(studioInApplicationPlistFolder, 'jre', 'jdk', 'Contents', 'Home', 'bin', 'java'), '-version', ], stderr: '123', ) ); final AndroidStudio studio = AndroidStudio.fromMacOSBundle( - globals.fs.directory(studioInApplicationPlistFolder).parent.path, + fileSystem.directory(studioInApplicationPlistFolder).parent.path, )!; expect(studio, isNotNull); - expect(studio.pluginsPath, equals(globals.fs.path.join( + expect(studio.pluginsPath, equals(fileSystem.path.join( homeMac, 'Library', 'Application Support', @@ -232,34 +232,34 @@ void main() { }); testUsingContext('discovers Android Studio EAP location', () { - final String studioInApplicationPlistFolder = globals.fs.path.join( + final String studioInApplicationPlistFolder = fileSystem.path.join( '/', 'Application', 'Android Studio with suffix.app', 'Contents', ); - globals.fs.directory(studioInApplicationPlistFolder).createSync(recursive: true); + fileSystem.directory(studioInApplicationPlistFolder).createSync(recursive: true); - final String plistFilePath = globals.fs.path.join(studioInApplicationPlistFolder, 'Info.plist'); - plistUtils.fileContents[plistFilePath] = macStudioInfoPlistEAP; + final String plistFilePath = fileSystem.path.join(studioInApplicationPlistFolder, 'Info.plist'); + plistUtils.fileContents[plistFilePath] = macStudioInfoPlistEap_2022_3_1_11; processManager.addCommand(FakeCommand( command: [ - globals.fs.path.join(studioInApplicationPlistFolder, 'jre', 'Contents', 'Home', 'bin', 'java'), + fileSystem.path.join(studioInApplicationPlistFolder, 'jbr', 'Contents', 'Home', 'bin', 'java'), '-version', ], stderr: '123', ) ); final AndroidStudio studio = AndroidStudio.fromMacOSBundle( - globals.fs.directory(studioInApplicationPlistFolder).parent.path, + fileSystem.directory(studioInApplicationPlistFolder).parent.path, )!; expect(studio, isNotNull); - expect(studio.pluginsPath, equals(globals.fs.path.join( + expect(studio.pluginsPath, equals(fileSystem.path.join( homeMac, 'Library', 'Application Support', - 'AndroidStudio2021.2', + 'AndroidStudioPreview2022.3', ))); expect(studio.validationMessages, ['Java version 123']); }, overrides: { @@ -273,29 +273,29 @@ void main() { }); testUsingContext('does not discover Android Studio with JetBrainsToolboxApp wrapper', () { - final String applicationPlistFolder = globals.fs.path.join( + final String applicationPlistFolder = fileSystem.path.join( '/', 'Applications', 'Android Studio.app', 'Contents', ); - globals.fs.directory(applicationPlistFolder).createSync(recursive: true); + fileSystem.directory(applicationPlistFolder).createSync(recursive: true); - final String applicationsPlistFilePath = globals.fs.path.join(applicationPlistFolder, 'Info.plist'); + final String applicationsPlistFilePath = fileSystem.path.join(applicationPlistFolder, 'Info.plist'); const Map jetbrainsInfoPlist = { 'JetBrainsToolboxApp': 'ignored', }; plistUtils.fileContents[applicationsPlistFilePath] = jetbrainsInfoPlist; - final String homeDirectoryPlistFolder = globals.fs.path.join( - globals.fsUtils.homeDirPath!, + final String homeDirectoryPlistFolder = fileSystem.path.join( + fsUtils.homeDirPath!, 'Applications', 'Android Studio.app', 'Contents', ); - globals.fs.directory(homeDirectoryPlistFolder).createSync(recursive: true); + fileSystem.directory(homeDirectoryPlistFolder).createSync(recursive: true); - final String homeDirectoryPlistFilePath = globals.fs.path.join(homeDirectoryPlistFolder, 'Info.plist'); + final String homeDirectoryPlistFilePath = fileSystem.path.join(homeDirectoryPlistFolder, 'Info.plist'); plistUtils.fileContents[homeDirectoryPlistFilePath] = macStudioInfoPlist2020_3; expect(AndroidStudio.allInstalled().length, 1); @@ -395,26 +395,26 @@ void main() { }); testUsingContext('finds latest valid install', () { - final String applicationPlistFolder = globals.fs.path.join( + final String applicationPlistFolder = fileSystem.path.join( '/', 'Applications', 'Android Studio.app', 'Contents', ); - globals.fs.directory(applicationPlistFolder).createSync(recursive: true); + fileSystem.directory(applicationPlistFolder).createSync(recursive: true); - final String applicationsPlistFilePath = globals.fs.path.join(applicationPlistFolder, 'Info.plist'); + final String applicationsPlistFilePath = fileSystem.path.join(applicationPlistFolder, 'Info.plist'); plistUtils.fileContents[applicationsPlistFilePath] = macStudioInfoPlist3_3; - final String homeDirectoryPlistFolder = globals.fs.path.join( - globals.fsUtils.homeDirPath!, + final String homeDirectoryPlistFolder = fileSystem.path.join( + fsUtils.homeDirPath!, 'Applications', 'Android Studio.app', 'Contents', ); - globals.fs.directory(homeDirectoryPlistFolder).createSync(recursive: true); + fileSystem.directory(homeDirectoryPlistFolder).createSync(recursive: true); - final String homeDirectoryPlistFilePath = globals.fs.path.join(homeDirectoryPlistFolder, 'Info.plist'); + final String homeDirectoryPlistFilePath = fileSystem.path.join(homeDirectoryPlistFolder, 'Info.plist'); plistUtils.fileContents[homeDirectoryPlistFilePath] = macStudioInfoPlist4_1; expect(AndroidStudio.allInstalled().length, 2); @@ -428,21 +428,21 @@ void main() { }); testUsingContext('extracts custom paths for directly downloaded Android Studio', () { - final String studioInApplicationPlistFolder = globals.fs.path.join( + final String studioInApplicationPlistFolder = fileSystem.path.join( '/', 'Application', 'Android Studio.app', 'Contents', ); - globals.fs.directory(studioInApplicationPlistFolder).createSync(recursive: true); + fileSystem.directory(studioInApplicationPlistFolder).createSync(recursive: true); - final String plistFilePath = globals.fs.path.join(studioInApplicationPlistFolder, 'Info.plist'); + final String plistFilePath = fileSystem.path.join(studioInApplicationPlistFolder, 'Info.plist'); plistUtils.fileContents[plistFilePath] = macStudioInfoPlist3_3; final AndroidStudio studio = AndroidStudio.fromMacOSBundle( - globals.fs.directory(studioInApplicationPlistFolder).parent.path, + fileSystem.directory(studioInApplicationPlistFolder).parent.path, )!; expect(studio, isNotNull); - expect(studio.pluginsPath, equals(globals.fs.path.join( + expect(studio.pluginsPath, equals(fileSystem.path.join( homeMac, 'Library', 'Application Support', @@ -459,29 +459,29 @@ void main() { }); testUsingContext('finds Android Studio 2020.3 bundled Java version', () { - final String studioInApplicationPlistFolder = globals.fs.path.join( + final String studioInApplicationPlistFolder = fileSystem.path.join( '/', 'Application', 'Android Studio.app', 'Contents', ); - globals.fs.directory(studioInApplicationPlistFolder).createSync(recursive: true); + fileSystem.directory(studioInApplicationPlistFolder).createSync(recursive: true); - final String plistFilePath = globals.fs.path.join(studioInApplicationPlistFolder, 'Info.plist'); + final String plistFilePath = fileSystem.path.join(studioInApplicationPlistFolder, 'Info.plist'); plistUtils.fileContents[plistFilePath] = macStudioInfoPlist2020_3; processManager.addCommand(FakeCommand( command: [ - globals.fs.path.join(studioInApplicationPlistFolder, 'jre', 'Contents', 'Home', 'bin', 'java'), + fileSystem.path.join(studioInApplicationPlistFolder, 'jre', 'Contents', 'Home', 'bin', 'java'), '-version', ], stderr: '123', ) ); final AndroidStudio studio = AndroidStudio.fromMacOSBundle( - globals.fs.directory(studioInApplicationPlistFolder).parent.path, + fileSystem.directory(studioInApplicationPlistFolder).parent.path, )!; - expect(studio.javaPath, equals(globals.fs.path.join( + expect(studio.javaPath, equals(fileSystem.path.join( studioInApplicationPlistFolder, 'jre', 'Contents', @@ -498,29 +498,29 @@ void main() { }); testUsingContext('finds Android Studio 2022.1 bundled Java version', () { - final String studioInApplicationPlistFolder = globals.fs.path.join( + final String studioInApplicationPlistFolder = fileSystem.path.join( '/', 'Application', 'Android Studio.app', 'Contents', ); - globals.fs.directory(studioInApplicationPlistFolder).createSync(recursive: true); + fileSystem.directory(studioInApplicationPlistFolder).createSync(recursive: true); - final String plistFilePath = globals.fs.path.join(studioInApplicationPlistFolder, 'Info.plist'); + final String plistFilePath = fileSystem.path.join(studioInApplicationPlistFolder, 'Info.plist'); plistUtils.fileContents[plistFilePath] = macStudioInfoPlist2022_1; processManager.addCommand(FakeCommand( command: [ - globals.fs.path.join(studioInApplicationPlistFolder, 'jbr', 'Contents', 'Home', 'bin', 'java'), + fileSystem.path.join(studioInApplicationPlistFolder, 'jbr', 'Contents', 'Home', 'bin', 'java'), '-version', ], stderr: '123', ) ); final AndroidStudio studio = AndroidStudio.fromMacOSBundle( - globals.fs.directory(studioInApplicationPlistFolder).parent.path, + fileSystem.directory(studioInApplicationPlistFolder).parent.path, )!; - expect(studio.javaPath, equals(globals.fs.path.join( + expect(studio.javaPath, equals(fileSystem.path.join( studioInApplicationPlistFolder, 'jbr', 'Contents', @@ -535,6 +535,83 @@ void main() { Platform: () => platform, PlistParser: () => plistUtils, }); + + testUsingContext('finds bundled Java version when Android Studio version is unknown by assuming the latest version', () { + final String studioInApplicationPlistFolder = fileSystem.path.join( + '/', + 'Application', + 'Android Studio.app', + 'Contents', + ); + fileSystem.directory(studioInApplicationPlistFolder).createSync(recursive: true); + + final String plistFilePath = fileSystem.path.join(studioInApplicationPlistFolder, 'Info.plist'); + final Map plistWithoutVersion = Map.from(macStudioInfoPlist2022_1); + plistWithoutVersion['CFBundleShortVersionString'] = ''; + plistUtils.fileContents[plistFilePath] = plistWithoutVersion; + + final String jdkPath = fileSystem.path.join(studioInApplicationPlistFolder, 'jbr', 'Contents', 'Home'); + + processManager.addCommand(FakeCommand( + command: [ + fileSystem.path.join(jdkPath, 'bin', 'java'), + '-version', + ], + stderr: '123', + ) + ); + final AndroidStudio studio = AndroidStudio.fromMacOSBundle( + fileSystem.directory(studioInApplicationPlistFolder).parent.path, + )!; + + expect(studio.version, null); + expect(studio.javaPath, jdkPath); + }, overrides: { + FileSystem: () => fileSystem, + FileSystemUtils: () => fsUtils, + ProcessManager: () => processManager, + Platform: () => platform, + PlistParser: () => plistUtils, + }); + + testUsingContext('when given an Android Studio newer than any known version, finds Java version by assuming latest known Android Studio version', () { + final String studioInApplicationPlistFolder = fileSystem.path.join( + '/', + 'Application', + 'Android Studio.app', + 'Contents', + ); + fileSystem.directory(studioInApplicationPlistFolder).createSync(recursive: true); + + final String plistFilePath = fileSystem.path.join(studioInApplicationPlistFolder, 'Info.plist'); + final Map plistWithoutVersion = Map.from(macStudioInfoPlist2022_1); + plistWithoutVersion['CFBundleShortVersionString'] = '99999.99.99'; + plistUtils.fileContents[plistFilePath] = plistWithoutVersion; + + final String jdkPathFor2022 = fileSystem.path.join(studioInApplicationPlistFolder, 'jbr', 'Contents', 'Home'); + + processManager.addCommand(FakeCommand( + command: [ + fileSystem.path.join(jdkPathFor2022, 'bin', 'java'), + '-version', + ], + stderr: '123', + ) + ); + final AndroidStudio studio = AndroidStudio.fromMacOSBundle( + fileSystem.directory(studioInApplicationPlistFolder).parent.path, + )!; + + expect(studio.version, equals(Version(99999, 99, 99))); + expect(studio.javaPath, jdkPathFor2022); + }, overrides: { + FileSystem: () => fileSystem, + FileSystemUtils: () => fsUtils, + ProcessManager: () => processManager, + Platform: () => platform, + PlistParser: () => plistUtils, + }); + }); group('installation detection on Windows', () { @@ -684,16 +761,57 @@ void main() { FileSystem: () => fileSystem, ProcessManager: () => FakeProcessManager.any(), }); + + testUsingContext('finds bundled Java version when Android Studio version is unknown by assuming the latest version', () { + fileSystem.file(r'C:\Users\Dash\AppData\Local\Google\AndroidStudio\.home') + ..createSync(recursive: true) + ..writeAsStringSync(r'C:\Program Files\AndroidStudio'); + fileSystem.directory(r'C:\Program Files\AndroidStudio') + .createSync(recursive: true); + + fileSystem.file(r'C:\Program Files\AndroidStudio\jbr\bin\java').createSync(recursive: true); + + final AndroidStudio studio = AndroidStudio.allInstalled().single; + + expect(studio.version, null); + expect(studio.javaPath, equals(r'C:\Program Files\AndroidStudio\jbr')); + }, overrides: { + Platform: () => platform, + FileSystem: () => fileSystem, + ProcessManager: () => FakeProcessManager.any(), + }); + + testUsingContext('when given an Android Studio newer than any known version, finds Java version by assuming latest known Android Studio version', () { + fileSystem.file(r'C:\Users\Dash\AppData\Local\Google\AndroidStudio99999.99.99\.home') + ..createSync(recursive: true) + ..writeAsStringSync(r'C:\Program Files\AndroidStudio'); + fileSystem.directory(r'C:\Program Files\AndroidStudio') + .createSync(recursive: true); + + fileSystem.file(r'C:\Program Files\AndroidStudio\jbr\bin\java').createSync(recursive: true); + + final AndroidStudio studio = AndroidStudio.allInstalled().single; + + const String expectedJdkLocationFor2022 = r'C:\Program Files\AndroidStudio\jbr'; + expect(studio.version, equals(Version(99999, 99, 99))); + expect(studio.javaPath, equals(expectedJdkLocationFor2022)); + }, overrides: { + Platform: () => platform, + FileSystem: () => fileSystem, + ProcessManager: () => FakeProcessManager.any(), + }); }); group('installation detection on Linux', () { const String homeLinux = '/home/me'; + late Config config; late FileSystem fileSystem; late FileSystemUtils fsUtils; late Platform platform; setUp(() { + config = Config.test(); platform = FakePlatform( environment: {'HOME': homeLinux}, ); @@ -709,11 +827,11 @@ void main() { '$homeLinux/.AndroidStudio4.0/system/.home'; const String studioInstallPath = '$homeLinux/AndroidStudio'; - globals.fs.file(studioHomeFilePath) + fileSystem.file(studioHomeFilePath) ..createSync(recursive: true) ..writeAsStringSync(studioInstallPath); - globals.fs.directory(studioInstallPath).createSync(); + fileSystem.directory(studioInstallPath).createSync(); final AndroidStudio studio = AndroidStudio.allInstalled().single; @@ -735,11 +853,11 @@ void main() { '$homeLinux/.cache/Google/AndroidStudio4.1/.home'; const String studioInstallPath = '$homeLinux/AndroidStudio'; - globals.fs.file(studioHomeFilePath) + fileSystem.file(studioHomeFilePath) ..createSync(recursive: true) ..writeAsStringSync(studioInstallPath); - globals.fs.directory(studioInstallPath).createSync(); + fileSystem.directory(studioInstallPath).createSync(); final AndroidStudio studio = AndroidStudio.allInstalled().single; @@ -763,12 +881,12 @@ void main() { '$homeLinux/.local/share/JetBrains/Toolbox/apps/AndroidStudio/ch-0/201.7042882'; const String pluginsInstallPath = '$studioInstallPath.plugins'; - globals.fs.file(studioHomeFilePath) + fileSystem.file(studioHomeFilePath) ..createSync(recursive: true) ..writeAsStringSync(studioInstallPath); - globals.fs.directory(studioInstallPath).createSync(recursive: true); - globals.fs.directory(pluginsInstallPath).createSync(); + fileSystem.directory(studioInstallPath).createSync(recursive: true); + fileSystem.directory(pluginsInstallPath).createSync(); final AndroidStudio studio = AndroidStudio.allInstalled().single; @@ -789,11 +907,11 @@ void main() { const String studioHomeFilePath = '$homeLinux/.cache/Google/AndroidStudio2020.3/.home'; const String studioInstallPath = '$homeLinux/AndroidStudio'; - globals.fs.file(studioHomeFilePath) + fileSystem.file(studioHomeFilePath) ..createSync(recursive: true) ..writeAsStringSync(studioInstallPath); - globals.fs.directory(studioInstallPath).createSync(); + fileSystem.directory(studioInstallPath).createSync(); final AndroidStudio studio = AndroidStudio.allInstalled().single; @@ -810,11 +928,11 @@ void main() { '$homeLinux/.cache/Google/AndroidStudio2022.1/.home'; const String studioInstallPath = '$homeLinux/AndroidStudio'; - globals.fs.file(studioHomeFilePath) + fileSystem.file(studioHomeFilePath) ..createSync(recursive: true) ..writeAsStringSync(studioInstallPath); - globals.fs.directory(studioInstallPath).createSync(); + fileSystem.directory(studioInstallPath).createSync(); final AndroidStudio studio = AndroidStudio.allInstalled().single; @@ -826,16 +944,63 @@ void main() { ProcessManager: () => FakeProcessManager.any(), }); + testUsingContext('finds bundled Java version when Android Studio version is unknown by assuming the latest version', () { + const String configuredStudioInstallPath = '$homeLinux/AndroidStudio'; + config.setValue('android-studio-dir', configuredStudioInstallPath); + + fileSystem.directory(configuredStudioInstallPath).createSync(recursive: true); + + fileSystem.directory(configuredStudioInstallPath).createSync(); + + fileSystem.file(fileSystem.path.join(configuredStudioInstallPath, 'jbr', 'bin', 'java')).createSync(recursive: true); + + final AndroidStudio studio = AndroidStudio.allInstalled().single; + + expect(studio.version, null); + expect(studio.javaPath, equals('$configuredStudioInstallPath/jbr')); + }, overrides: { + Config: () => config, + FileSystem: () => fileSystem, + FileSystemUtils: () => fsUtils, + Platform: () => platform, + ProcessManager: () => FakeProcessManager.any(), + }); + + testUsingContext('when given an Android Studio newer than any known version, finds Java version by assuming latest known Android Studio version', () { + const String studioHomeFilePath = + '$homeLinux/.cache/Google/AndroidStudio99999.99.99/.home'; + const String studioInstallPath = '$homeLinux/AndroidStudio'; + + fileSystem.file(studioHomeFilePath) + ..createSync(recursive: true) + ..writeAsStringSync(studioInstallPath); + + fileSystem.directory(studioInstallPath).createSync(); + + final String expectedJdkLocationFor2022 = fileSystem.path.join(studioInstallPath, 'jbr', 'bin', 'java'); + fileSystem.file(expectedJdkLocationFor2022).createSync(recursive: true); + + final AndroidStudio studio = AndroidStudio.allInstalled().single; + + expect(studio.version, equals(Version(99999, 99, 99))); + expect(studio.javaPath, equals('$studioInstallPath/jbr')); + }, overrides: { + FileSystem: () => fileSystem, + FileSystemUtils: () => fsUtils, + Platform: () => platform, + ProcessManager: () => FakeProcessManager.any(), + }); + testUsingContext('pluginsPath extracts custom paths from home dir', () { const String installPath = '/opt/android-studio-with-cheese-5.0'; const String studioHome = '$homeLinux/.AndroidStudioWithCheese5.0'; const String homeFile = '$studioHome/system/.home'; - globals.fs.directory(installPath).createSync(recursive: true); - globals.fs.file(homeFile).createSync(recursive: true); - globals.fs.file(homeFile).writeAsStringSync(installPath); + fileSystem.directory(installPath).createSync(recursive: true); + fileSystem.file(homeFile).createSync(recursive: true); + fileSystem.file(homeFile).writeAsStringSync(installPath); final AndroidStudio studio = - AndroidStudio.fromHomeDot(globals.fs.directory(studioHome))!; + AndroidStudio.fromHomeDot(fileSystem.directory(studioHome))!; expect(studio, isNotNull); expect(studio.pluginsPath, equals('/home/me/.AndroidStudioWithCheese5.0/config/plugins')); @@ -853,10 +1018,12 @@ void main() { }); group('latestValid', () { + late Config config; late Platform platform; late FileSystem fileSystem; setUp(() { + config = Config.test(); platform = FakePlatform( operatingSystem: 'windows', environment: { @@ -957,12 +1124,12 @@ void main() { testUsingContext('always chooses the install configured by --android-studio-dir, even if the install is invalid', () { const String configuredAndroidStudioDir = r'C:\Users\Dash\Desktop\android-studio'; - globals.config.setValue('android-studio-dir', configuredAndroidStudioDir); + config.setValue('android-studio-dir', configuredAndroidStudioDir); // The directory exists, but nothing is inside. fileSystem.directory(configuredAndroidStudioDir).createSync(recursive: true); (globals.processManager as FakeProcessManager).excludedExecutables.add( - fileSystem.path.join(configuredAndroidStudioDir, 'jre', 'bin', 'java'), + fileSystem.path.join(configuredAndroidStudioDir, 'jbr', 'bin', 'java'), ); const List validVersions = [ @@ -988,7 +1155,7 @@ void main() { for (final String javaPath in validJavaPaths) { (globals.processManager as FakeProcessManager).addCommand(FakeCommand( command: [ - globals.fs.path.join(javaPath), + fileSystem.path.join(javaPath), '-version', ], )); @@ -999,7 +1166,7 @@ void main() { expect(chosenInstall.directory, configuredAndroidStudioDir); expect(chosenInstall.isValid, false); }, overrides: { - Config: () => Config.test(), + Config: () => config, FileSystem: () => fileSystem, Platform: () => platform, ProcessManager: () => FakeProcessManager.empty(), @@ -1007,7 +1174,7 @@ void main() { testUsingContext('throws a ToolExit if --android-studio-dir is configured but the directory does not exist', () async { const String configuredAndroidStudioDir = r'C:\Users\Dash\Desktop\android-studio'; - globals.config.setValue('android-studio-dir', configuredAndroidStudioDir); + config.setValue('android-studio-dir', configuredAndroidStudioDir); expect(fileSystem.directory(configuredAndroidStudioDir).existsSync(), false); expect(() => AndroidStudio.latestValid(), throwsA( @@ -1016,7 +1183,7 @@ void main() { ) ); }, overrides: { - Config: () => Config.test(), + Config: () => config, FileSystem: () => fileSystem, Platform: () => platform, ProcessManager: () => FakeProcessManager.any(),