Files
packages/script/tool/test/lint_podspecs_command_test.dart
stuartmorgan 77460f03f2 [flutter_plugin_tools] Make unit tests pass on Windows (#4149)
The purpose of this PR is to make running all unit tests on Windows pass (vs failing a large portion of the tests as currently happens). This does not mean that the commands actually work when run on Windows, or that Windows support is tested, only that it's possible to actually run the tests themselves. This is prep for actually supporting parts of the tool on Windows in future PRs.

Major changes:
- Make the tests significantly more hermetic:
  - Make almost all tools take a `Platform` constructor argument that can be used to inject a mock platform to control what OS the command acts like it is running on under test.
  - Add a path `Context` object to the base command, whose style matches the `Platform`, and use that almost everywhere instead of the top-level `path` functions.
  - In cases where Posix behavior is always required (such as parsing `git` output), explicitly use the `posix` context object for `path` functions.
- Start laying the groundwork for actual Windows support:
  - Replace all uses of `flutter` as a command with a getter that returns `flutter` or `flutter.bat` as appropriate.
  - For user messages that include relative paths, use a helper that always uses Posix-style relative paths for consistent output.

This bumps the version since quite a few changes have built up, and having a cut point before starting to make more changes to the commands to support Windows seems like a good idea.

Part of https://github.com/flutter/flutter/issues/86113
2021-07-09 19:38:13 -04:00

267 lines
7.7 KiB
Dart

// 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/lint_podspecs_command.dart';
import 'package:test/test.dart';
import 'mocks.dart';
import 'util.dart';
void main() {
group('$LintPodspecsCommand', () {
FileSystem fileSystem;
late Directory packagesDir;
late CommandRunner<void> runner;
late MockPlatform mockPlatform;
late RecordingProcessRunner processRunner;
setUp(() {
fileSystem = MemoryFileSystem(style: FileSystemStyle.posix);
packagesDir = createPackagesDirectory(fileSystem: fileSystem);
mockPlatform = MockPlatform(isMacOS: true);
processRunner = RecordingProcessRunner();
final LintPodspecsCommand command = LintPodspecsCommand(
packagesDir,
processRunner: processRunner,
platform: mockPlatform,
);
runner =
CommandRunner<void>('podspec_test', 'Test for $LintPodspecsCommand');
runner.addCommand(command);
});
test('only runs on macOS', () async {
createFakePlugin('plugin1', packagesDir,
extraFiles: <String>['plugin1.podspec']);
mockPlatform.isMacOS = false;
Error? commandError;
final List<String> output = await runCapturingPrint(
runner, <String>['podspecs'], errorHandler: (Error e) {
commandError = e;
});
expect(commandError, isA<ToolExit>());
expect(
processRunner.recordedCalls,
equals(<ProcessCall>[]),
);
expect(
output,
containsAllInOrder(
<Matcher>[contains('only supported on macOS')],
));
});
test('runs pod lib lint on a podspec', () async {
final Directory plugin1Dir = createFakePlugin(
'plugin1',
packagesDir,
extraFiles: <String>[
'ios/plugin1.podspec',
'bogus.dart', // Ignore non-podspecs.
],
);
processRunner.mockProcessesForExecutable['pod'] = <io.Process>[
MockProcess.succeeding(),
MockProcess.succeeding(),
];
processRunner.resultStdout = 'Foo';
processRunner.resultStderr = 'Bar';
final List<String> output =
await runCapturingPrint(runner, <String>['podspecs']);
expect(
processRunner.recordedCalls,
orderedEquals(<ProcessCall>[
ProcessCall('which', const <String>['pod'], packagesDir.path),
ProcessCall(
'pod',
<String>[
'lib',
'lint',
plugin1Dir
.childDirectory('ios')
.childFile('plugin1.podspec')
.path,
'--configuration=Debug',
'--skip-tests',
'--use-modular-headers',
'--use-libraries'
],
packagesDir.path),
ProcessCall(
'pod',
<String>[
'lib',
'lint',
plugin1Dir
.childDirectory('ios')
.childFile('plugin1.podspec')
.path,
'--configuration=Debug',
'--skip-tests',
'--use-modular-headers',
],
packagesDir.path),
]),
);
expect(output, contains('Linting plugin1.podspec'));
expect(output, contains('Foo'));
expect(output, contains('Bar'));
});
test('allow warnings for podspecs with known warnings', () async {
final Directory plugin1Dir = createFakePlugin('plugin1', packagesDir,
extraFiles: <String>['plugin1.podspec']);
final List<String> output = await runCapturingPrint(
runner, <String>['podspecs', '--ignore-warnings=plugin1']);
expect(
processRunner.recordedCalls,
orderedEquals(<ProcessCall>[
ProcessCall('which', const <String>['pod'], packagesDir.path),
ProcessCall(
'pod',
<String>[
'lib',
'lint',
plugin1Dir.childFile('plugin1.podspec').path,
'--configuration=Debug',
'--skip-tests',
'--use-modular-headers',
'--allow-warnings',
'--use-libraries'
],
packagesDir.path),
ProcessCall(
'pod',
<String>[
'lib',
'lint',
plugin1Dir.childFile('plugin1.podspec').path,
'--configuration=Debug',
'--skip-tests',
'--use-modular-headers',
'--allow-warnings',
],
packagesDir.path),
]),
);
expect(output, contains('Linting plugin1.podspec'));
});
test('fails if pod is missing', () async {
createFakePlugin('plugin1', packagesDir,
extraFiles: <String>['plugin1.podspec']);
// Simulate failure from `which pod`.
processRunner.mockProcessesForExecutable['which'] = <io.Process>[
MockProcess.failing(),
];
Error? commandError;
final List<String> output = await runCapturingPrint(
runner, <String>['podspecs'], errorHandler: (Error e) {
commandError = e;
});
expect(commandError, isA<ToolExit>());
expect(
output,
containsAllInOrder(
<Matcher>[
contains('Unable to find "pod". Make sure it is in your path.'),
],
));
});
test('fails if linting as a framework fails', () async {
createFakePlugin('plugin1', packagesDir,
extraFiles: <String>['plugin1.podspec']);
// Simulate failure from `pod`.
processRunner.mockProcessesForExecutable['pod'] = <io.Process>[
MockProcess.failing(),
];
Error? commandError;
final List<String> output = await runCapturingPrint(
runner, <String>['podspecs'], errorHandler: (Error e) {
commandError = e;
});
expect(commandError, isA<ToolExit>());
expect(
output,
containsAllInOrder(
<Matcher>[
contains('The following packages had errors:'),
contains('plugin1:\n'
' plugin1.podspec')
],
));
});
test('fails if linting as a static library fails', () async {
createFakePlugin('plugin1', packagesDir,
extraFiles: <String>['plugin1.podspec']);
// Simulate failure from the second call to `pod`.
processRunner.mockProcessesForExecutable['pod'] = <io.Process>[
MockProcess.succeeding(),
MockProcess.failing(),
];
Error? commandError;
final List<String> output = await runCapturingPrint(
runner, <String>['podspecs'], errorHandler: (Error e) {
commandError = e;
});
expect(commandError, isA<ToolExit>());
expect(
output,
containsAllInOrder(
<Matcher>[
contains('The following packages had errors:'),
contains('plugin1:\n'
' plugin1.podspec')
],
));
});
test('skips when there are no podspecs', () async {
createFakePlugin('plugin1', packagesDir);
final List<String> output =
await runCapturingPrint(runner, <String>['podspecs']);
expect(
output,
containsAllInOrder(
<Matcher>[contains('SKIPPING: No podspecs.')],
));
});
});
}