// 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 'dart:io' as io; 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/update_excerpts_command.dart'; import 'package:mockito/mockito.dart'; import 'package:test/test.dart'; import 'common/plugin_command_test.mocks.dart'; import 'mocks.dart'; import 'util.dart'; void main() { late FileSystem fileSystem; late Directory packagesDir; late RecordingProcessRunner processRunner; late CommandRunner runner; setUp(() { fileSystem = MemoryFileSystem(); packagesDir = createPackagesDirectory(fileSystem: fileSystem); final MockGitDir gitDir = MockGitDir(); when(gitDir.path).thenReturn(packagesDir.parent.path); processRunner = RecordingProcessRunner(); final UpdateExcerptsCommand command = UpdateExcerptsCommand( packagesDir, processRunner: processRunner, platform: MockPlatform(), gitDir: gitDir, ); runner = CommandRunner( 'update_excerpts_command', 'Test for update_excerpts_command'); runner.addCommand(command); }); test('runs pub get before running scripts', () async { final RepositoryPackage package = createFakePlugin('a_package', packagesDir, extraFiles: [kReadmeExcerptConfigPath]); final Directory example = getExampleDir(package); await runCapturingPrint(runner, ['update-excerpts']); expect( processRunner.recordedCalls, containsAll([ ProcessCall('dart', const ['pub', 'get'], example.path), ProcessCall( 'dart', const [ 'run', 'build_runner', 'build', '--config', 'excerpt', '--output', 'excerpts', '--delete-conflicting-outputs', ], example.path), ])); }); test('runs when config is present', () async { final RepositoryPackage package = createFakePlugin('a_package', packagesDir, extraFiles: [kReadmeExcerptConfigPath]); final Directory example = getExampleDir(package); final List output = await runCapturingPrint(runner, ['update-excerpts']); expect( processRunner.recordedCalls, containsAll([ ProcessCall( 'dart', const [ 'run', 'build_runner', 'build', '--config', 'excerpt', '--output', 'excerpts', '--delete-conflicting-outputs', ], example.path), ProcessCall( 'dart', const [ 'run', 'code_excerpt_updater', '--write-in-place', '--yaml', '--no-escape-ng-interpolation', '../README.md', ], example.path), ])); expect( output, containsAllInOrder([ contains('Ran for 1 package(s)'), ])); }); test('skips when no config is present', () async { createFakePlugin('a_package', packagesDir); final List output = await runCapturingPrint(runner, ['update-excerpts']); expect(processRunner.recordedCalls, isEmpty); expect( output, containsAllInOrder([ contains('Skipped 1 package(s)'), ])); }); test('restores pubspec even if running the script fails', () async { final RepositoryPackage package = createFakePlugin('a_package', packagesDir, extraFiles: [kReadmeExcerptConfigPath]); processRunner.mockProcessesForExecutable['dart'] = [ MockProcess(exitCode: 1), // dart pub get ]; Error? commandError; final List output = await runCapturingPrint( runner, ['update-excerpts'], errorHandler: (Error e) { commandError = e; }); // Check that it's definitely a failure in a step between making the changes // and restoring the original. expect(commandError, isA()); expect( output, containsAllInOrder([ contains('The following packages had errors:'), contains('a_package:\n' ' Unable to get script dependencies') ])); final String examplePubspecContent = package.getExamples().first.pubspecFile.readAsStringSync(); expect(examplePubspecContent, isNot(contains('code_excerpter'))); expect(examplePubspecContent, isNot(contains('code_excerpt_updater'))); }); test('fails if pub get fails', () async { createFakePlugin('a_package', packagesDir, extraFiles: [kReadmeExcerptConfigPath]); processRunner.mockProcessesForExecutable['dart'] = [ MockProcess(exitCode: 1), // dart pub get ]; Error? commandError; final List output = await runCapturingPrint( runner, ['update-excerpts'], errorHandler: (Error e) { commandError = e; }); expect(commandError, isA()); expect( output, containsAllInOrder([ contains('The following packages had errors:'), contains('a_package:\n' ' Unable to get script dependencies') ])); }); test('fails if extraction fails', () async { createFakePlugin('a_package', packagesDir, extraFiles: [kReadmeExcerptConfigPath]); processRunner.mockProcessesForExecutable['dart'] = [ MockProcess(), // dart pub get MockProcess(exitCode: 1), // dart run build_runner ... ]; Error? commandError; final List output = await runCapturingPrint( runner, ['update-excerpts'], errorHandler: (Error e) { commandError = e; }); expect(commandError, isA()); expect( output, containsAllInOrder([ contains('The following packages had errors:'), contains('a_package:\n' ' Unable to extract excerpts') ])); }); test('fails if injection fails', () async { createFakePlugin('a_package', packagesDir, extraFiles: [kReadmeExcerptConfigPath]); processRunner.mockProcessesForExecutable['dart'] = [ MockProcess(), // dart pub get MockProcess(), // dart run build_runner ... MockProcess(exitCode: 1), // dart run code_excerpt_updater ... ]; Error? commandError; final List output = await runCapturingPrint( runner, ['update-excerpts'], errorHandler: (Error e) { commandError = e; }); expect(commandError, isA()); expect( output, containsAllInOrder([ contains('The following packages had errors:'), contains('a_package:\n' ' Unable to inject excerpts') ])); }); test('fails if files are changed with --fail-on-change', () async { createFakePlugin('a_plugin', packagesDir, extraFiles: [kReadmeExcerptConfigPath]); const String changedFilePath = 'packages/a_plugin/linux/foo_plugin.cc'; processRunner.mockProcessesForExecutable['git'] = [ MockProcess(stdout: changedFilePath), ]; Error? commandError; final List output = await runCapturingPrint( runner, ['update-excerpts', '--fail-on-change'], errorHandler: (Error e) { commandError = e; }); expect(commandError, isA()); expect( output, containsAllInOrder([ contains('README.md is out of sync with its source excerpts'), ])); }); test('fails if git ls-files fails', () async { createFakePlugin('a_plugin', packagesDir, extraFiles: [kReadmeExcerptConfigPath]); processRunner.mockProcessesForExecutable['git'] = [ MockProcess(exitCode: 1) ]; Error? commandError; final List output = await runCapturingPrint( runner, ['update-excerpts', '--fail-on-change'], errorHandler: (Error e) { commandError = e; }); expect(commandError, isA()); expect( output, containsAllInOrder([ contains('Unable to determine local file state'), ])); }); }