// Copyright 2013 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:args/command_runner.dart'; import 'package:file/file.dart'; import 'package:file/memory.dart'; import 'package:flutter_plugin_tools/src/common/core.dart'; import 'package:flutter_plugin_tools/src/common/plugin_utils.dart'; import 'package:flutter_plugin_tools/src/lint_android_command.dart'; import 'package:test/test.dart'; import 'mocks.dart'; import 'util.dart'; void main() { group('LintAndroidCommand', () { FileSystem fileSystem; late Directory packagesDir; late CommandRunner runner; late MockPlatform mockPlatform; late RecordingProcessRunner processRunner; setUp(() { fileSystem = MemoryFileSystem(); packagesDir = createPackagesDirectory(fileSystem: fileSystem); mockPlatform = MockPlatform(); processRunner = RecordingProcessRunner(); final LintAndroidCommand command = LintAndroidCommand( packagesDir, processRunner: processRunner, platform: mockPlatform, ); runner = CommandRunner( 'lint_android_test', 'Test for $LintAndroidCommand'); runner.addCommand(command); }); test('runs gradle lint', () async { final RepositoryPackage plugin = createFakePlugin('plugin1', packagesDir, extraFiles: [ 'example/android/gradlew', ], platformSupport: { platformAndroid: const PlatformDetails(PlatformSupport.inline) }); final Directory androidDir = plugin.getExamples().first.platformDirectory(FlutterPlatform.android); final List output = await runCapturingPrint(runner, ['lint-android']); expect( processRunner.recordedCalls, orderedEquals([ ProcessCall( androidDir.childFile('gradlew').path, const ['plugin1:lintDebug'], androidDir.path, ), ]), ); expect( output, containsAllInOrder([ contains('Running for plugin1'), contains('No issues found!'), ])); }); test('runs on all examples', () async { final List examples = ['example1', 'example2']; final RepositoryPackage plugin = createFakePlugin('plugin1', packagesDir, examples: examples, extraFiles: [ 'example/example1/android/gradlew', 'example/example2/android/gradlew', ], platformSupport: { platformAndroid: const PlatformDetails(PlatformSupport.inline) }); final Iterable exampleAndroidDirs = plugin.getExamples().map( (RepositoryPackage example) => example.platformDirectory(FlutterPlatform.android)); final List output = await runCapturingPrint(runner, ['lint-android']); expect( processRunner.recordedCalls, orderedEquals([ for (final Directory directory in exampleAndroidDirs) ProcessCall( directory.childFile('gradlew').path, const ['plugin1:lintDebug'], directory.path, ), ]), ); expect( output, containsAllInOrder([ contains('Running for plugin1'), contains('No issues found!'), ])); }); test('runs --config-only build if gradlew is missing', () async { final RepositoryPackage plugin = createFakePlugin('plugin1', packagesDir, platformSupport: { platformAndroid: const PlatformDetails(PlatformSupport.inline) }); final Directory androidDir = plugin.getExamples().first.platformDirectory(FlutterPlatform.android); final List output = await runCapturingPrint(runner, ['lint-android']); expect( processRunner.recordedCalls, orderedEquals([ ProcessCall( getFlutterCommand(mockPlatform), const ['build', 'apk', '--config-only'], plugin.getExamples().first.directory.path, ), ProcessCall( androidDir.childFile('gradlew').path, const ['plugin1:lintDebug'], androidDir.path, ), ]), ); expect( output, containsAllInOrder([ contains('Running for plugin1'), contains('No issues found!'), ])); }); test('fails if gradlew generation fails', () async { createFakePlugin('plugin1', packagesDir, platformSupport: { platformAndroid: const PlatformDetails(PlatformSupport.inline) }); processRunner .mockProcessesForExecutable[getFlutterCommand(mockPlatform)] = [ FakeProcessInfo(MockProcess(exitCode: 1)), ]; Error? commandError; final List output = await runCapturingPrint( runner, ['lint-android'], errorHandler: (Error e) { commandError = e; }); expect(commandError, isA()); expect( output, containsAllInOrder( [ contains('Unable to configure Gradle project'), ], )); }); test('fails if linting finds issues', () async { final RepositoryPackage plugin = createFakePlugin('plugin1', packagesDir, extraFiles: [ 'example/android/gradlew', ], platformSupport: { platformAndroid: const PlatformDetails(PlatformSupport.inline) }); final String gradlewPath = plugin .getExamples() .first .platformDirectory(FlutterPlatform.android) .childFile('gradlew') .path; processRunner.mockProcessesForExecutable[gradlewPath] = [ FakeProcessInfo(MockProcess(exitCode: 1)), ]; Error? commandError; final List output = await runCapturingPrint( runner, ['lint-android'], errorHandler: (Error e) { commandError = e; }); expect(commandError, isA()); expect( output, containsAllInOrder( [ contains('The following packages had errors:'), ], )); }); test('skips non-Android plugins', () async { createFakePlugin('plugin1', packagesDir); final List output = await runCapturingPrint(runner, ['lint-android']); expect( output, containsAllInOrder( [ contains( 'SKIPPING: Plugin does not have an Android implementation.') ], )); }); test('skips non-inline plugins', () async { createFakePlugin('plugin1', packagesDir, platformSupport: { platformAndroid: const PlatformDetails(PlatformSupport.federated) }); final List output = await runCapturingPrint(runner, ['lint-android']); expect( output, containsAllInOrder( [ contains( 'SKIPPING: Plugin does not have an Android implementation.') ], )); }); }); }