diff --git a/example/tool_base_test_example.dart b/example/tool_base_test_example.dart index 7306614..dd8cdfe 100644 --- a/example/tool_base_test_example.dart +++ b/example/tool_base_test_example.dart @@ -1,7 +1,7 @@ import 'package:test/test.dart'; import 'package:tool_base_test/tool_base_test.dart'; -main() { +void main() { testUsingContext('test in context', () { expect(true, isTrue); }); diff --git a/lib/src/common.dart b/lib/src/common.dart index 9140bc2..06a0120 100644 --- a/lib/src/common.dart +++ b/lib/src/common.dart @@ -4,16 +4,15 @@ import 'dart:async'; -//import 'package:args/command_runner.dart'; -import 'package:tool_base/src/base/common.dart'; -import 'package:tool_base/src/base/file_system.dart'; -import 'package:tool_base/src/base/platform.dart'; -import 'package:tool_base/src/base/process.dart'; //import 'package:tool_base/src/commands/create.dart'; //import 'package:tool_base/src/runner/flutter_command.dart'; //import 'package:tool_base/src/runner/flutter_command_runner.dart'; import 'package:test_api/test_api.dart' as test_package show TypeMatcher; import 'package:test_api/test_api.dart' hide TypeMatcher, isInstanceOf; +//import 'package:args/command_runner.dart'; +import 'package:tool_base/src/base/common.dart'; +import 'package:tool_base/src/base/file_system.dart'; +import 'package:tool_base/src/base/process.dart'; export 'package:test_core/test_core.dart' hide TypeMatcher, isInstanceOf; // Defines a 'package:test' shim. @@ -21,52 +20,6 @@ export 'package:test_core/test_core.dart' hide TypeMatcher, isInstanceOf; // Def // TODO(ianh): Remove this once https://github.com/dart-lang/matcher/issues/98 is fixed Matcher isInstanceOf() => test_package.TypeMatcher(); -void tryToDelete(Directory directory) { - // This should not be necessary, but it turns out that - // on Windows it's common for deletions to fail due to - // bogus (we think) "access denied" errors. - try { - directory.deleteSync(recursive: true); - } on FileSystemException catch (error) { - print('Failed to delete ${directory.path}: $error'); - } -} - -/// Gets the path to the root of the Flutter repository. -/// -/// This will first look for a `FLUTTER_ROOT` environment variable. If the -/// environment variable is set, it will be returned. Otherwise, this will -/// deduce the path from `platform.script`. -String getFlutterRoot() { - if (platform.environment.containsKey('FLUTTER_ROOT')) - return platform.environment['FLUTTER_ROOT']; - - Error invalidScript() => StateError('Invalid script: ${platform.script}'); - - Uri scriptUri; - switch (platform.script.scheme) { - case 'file': - scriptUri = platform.script; - break; - case 'data': - final RegExp flutterTools = RegExp(r'(file://[^"]*[/\\]flutter_tools[/\\][^"]+\.dart)', multiLine: true); - final Match match = flutterTools.firstMatch(Uri.decodeFull(platform.script.path)); - if (match == null) - throw invalidScript(); - scriptUri = Uri.parse(match.group(1)); - break; - default: - throw invalidScript(); - } - - final List parts = fs.path.split(fs.path.fromUri(scriptUri)); - final int toolsIndex = parts.indexOf('flutter_tools'); - if (toolsIndex == -1) - throw invalidScript(); - final String toolsPath = fs.path.joinAll(parts.sublist(0, toolsIndex + 1)); - return fs.path.normalize(fs.path.join(toolsPath, '..', '..')); -} - //CommandRunner createTestCommandRunner([ FlutterCommand command ]) { // final FlutterCommandRunner runner = FlutterCommandRunner(); // if (command != null) @@ -80,17 +33,19 @@ void updateFileModificationTime( DateTime baseTime, int seconds, ) { - final DateTime modificationTime = baseTime.add(Duration(seconds: seconds)); + final modificationTime = baseTime.add(Duration(seconds: seconds)); fs.file(path).setLastModifiedSync(modificationTime); } /// Matcher for functions that throw [ToolExit]. -Matcher throwsToolExit({ int exitCode, Pattern message }) { - Matcher matcher = isToolExit; - if (exitCode != null) +Matcher throwsToolExit({ int? exitCode, Pattern? message }) { + var matcher = isToolExit; + if (exitCode != null) { matcher = allOf(matcher, (ToolExit e) => e.exitCode == exitCode); - if (message != null) + } + if (message != null) { matcher = allOf(matcher, (ToolExit e) => e.message.contains(message)); + } return throwsA(matcher); } diff --git a/lib/src/context.dart b/lib/src/context.dart index 0324967..59cce3e 100644 --- a/lib/src/context.dart +++ b/lib/src/context.dart @@ -5,7 +5,8 @@ import 'dart:async'; import 'dart:io' as io; -//import 'package:tool_base/src/android/android_workflow.dart'; +import 'package:meta/meta.dart'; +import 'package:mockito/mockito.dart'; import 'package:tool_base/src/base/config.dart'; import 'package:tool_base/src/base/context.dart'; import 'package:tool_base/src/base/file_system.dart'; @@ -15,17 +16,8 @@ import 'package:tool_base/src/base/os.dart'; import 'package:tool_base/src/base/terminal.dart'; import 'package:tool_base/src/base/time.dart'; import 'package:tool_base/src/cache.dart'; -//import 'package:tool_base/src/context_runner.dart'; -//import 'package:tool_base/src/device.dart'; -//import 'package:tool_base/src/doctor.dart'; -//import 'package:tool_base/src/ios/plist_parser.dart'; -//import 'package:tool_base/src/ios/simulators.dart'; -//import 'package:tool_base/src/ios/xcodeproj.dart'; -//import 'package:tool_base/src/project.dart'; -import 'package:reporting/reporting.dart'; -//import 'package:tool_base/src/version.dart'; -import 'package:meta/meta.dart'; -import 'package:mockito/mockito.dart'; +import 'package:tool_base/src/flutter.dart'; +import 'package:tool_base_test/src/mocks.dart'; import 'common.dart'; import 'context_runner.dart'; @@ -33,7 +25,7 @@ import 'context_runner.dart'; export 'package:tool_base/src/base/context.dart' show Generator; /// Return the test logger. This assumes that the current Logger is a BufferLogger. -BufferLogger get testLogger => context.get(); +BufferLogger get testLogger => context.get()! as BufferLogger; //FakeDeviceManager get testDeviceManager => context.get(); //FakeDoctor get testDoctor => context.get(); @@ -43,16 +35,16 @@ typedef ContextInitializer = void Function(AppContext testContext); @isTest void testUsingContext( String description, - dynamic testMethod(), { - Timeout timeout, - Map overrides = const {}, + dynamic Function() testMethod, { + Timeout? timeout, + Map? overrides = const {}, bool initializeFlutterRoot = true, - String testOn, - bool skip, // should default to `false`, but https://github.com/dart-lang/test/issues/545 doesn't allow this + String? testOn, + bool? skip, // should default to `false`, but https://github.com/dart-lang/test/issues/545 doesn't allow this }) { // Ensure we don't rely on the default [Config] constructor which will // leak a sticky $HOME/.flutter_settings behind! - Directory configDir; + Directory? configDir; tearDown(() { if (configDir != null) { tryToDelete(configDir); @@ -61,8 +53,8 @@ void testUsingContext( }); Config buildConfig(FileSystem fs) { configDir = fs.systemTempDirectory.createTempSync('flutter_config_dir_test.'); - final File settingsFile = fs.file( - fs.path.join(configDir.path, '.flutter_settings') + final settingsFile = fs.file( + fs.path.join(configDir!.path, '.flutter_settings') ); return Config(settingsFile); } @@ -86,14 +78,13 @@ void testUsingContext( Logger: () => BufferLogger(), OperatingSystemUtils: () => FakeOperatingSystemUtils(), // SimControl: () => MockSimControl(), - Usage: () => FakeUsage(), // XcodeProjectInterpreter: () => FakeXcodeProjectInterpreter(), FileSystem: () => const LocalFileSystemBlockingSetCurrentDirectory(), TimeoutConfiguration: () => const TimeoutConfiguration(), // PlistParser: () => FakePlistParser(), }, body: () { - final String flutterRoot = getFlutterRoot(); + final flutterRoot = getFlutterRoot(); return runZoned>(() { try { return context.run( @@ -128,11 +119,12 @@ void testUsingContext( } void _printBufferedErrors(AppContext testContext) { - if (testContext.get() is BufferLogger) { - final BufferLogger bufferLogger = testContext.get(); - if (bufferLogger.errorText.isNotEmpty) - print(bufferLogger.errorText); - bufferLogger.clear(); + var logger = testContext.get(); + if (logger is BufferLogger) { + if (logger.errorText.isNotEmpty) { + print(logger.errorText); + } + logger.clear(); } } @@ -236,31 +228,31 @@ void _printBufferedErrors(AppContext testContext) { class FakeOperatingSystemUtils implements OperatingSystemUtils { @override - ProcessResult makeExecutable(File file) => null; + ProcessResult makeExecutable(File file) => FakeProcessResult(); @override - void chmod(FileSystemEntity entity, String mode) { } + void chmod(FileSystemEntity entity, String mode) {} @override - File which(String execName) => null; + File which(String execName) => throw 'Not implemented'; @override List whichAll(String execName) => []; @override - File makePipe(String path) => null; + File makePipe(String path) => throw 'Not implemented'; @override - void zip(Directory data, File zipFile) { } + void zip(Directory data, File zipFile) {} @override - void unzip(File file, Directory targetDirectory) { } + void unzip(File file, Directory targetDirectory) {} @override bool verifyZip(File file) => true; @override - void unpack(File gzippedTarFile, Directory targetDirectory) { } + void unpack(File gzippedTarFile, Directory targetDirectory) {} @override bool verifyGzip(File gzippedFile) => true; @@ -277,47 +269,6 @@ class FakeOperatingSystemUtils implements OperatingSystemUtils { //class MockIOSSimulatorUtils extends Mock implements IOSSimulatorUtils {} -class FakeUsage implements Usage { - @override - bool get isFirstRun => false; - - @override - bool get suppressAnalytics => false; - - @override - set suppressAnalytics(bool value) { } - - @override - bool get enabled => true; - - @override - set enabled(bool value) { } - - @override - String get clientId => '00000000-0000-4000-0000-000000000000'; - - @override - void sendCommand(String command, { Map parameters }) { } - - @override - void sendEvent(String category, String parameter, { Map parameters }) { } - - @override - void sendTiming(String category, String variableName, Duration duration, { String label }) { } - - @override - void sendException(dynamic exception) { } - - @override - Stream> get onSend => null; - - @override - Future ensureAnalyticsSent() => Future.value(); - - @override - void printWelcome() { } -} - //class FakeXcodeProjectInterpreter implements XcodeProjectInterpreter { // @override // bool get isInstalled => true; diff --git a/lib/src/context_runner.dart b/lib/src/context_runner.dart index af539e4..8936f0b 100644 --- a/lib/src/context_runner.dart +++ b/lib/src/context_runner.dart @@ -52,13 +52,11 @@ import 'dart:async'; //import 'windows/visual_studio_validator.dart'; //import 'windows/windows_workflow.dart'; -import 'package:process/process.dart'; -import 'package:reporting/reporting.dart'; import 'package:tool_base/tool_base.dart'; Future runInContext( - FutureOr runner(), { - Map overrides, + FutureOr Function() runner, { + Map? overrides, }) async { return await context.run( name: 'global fallbacks', diff --git a/lib/src/mocks.dart b/lib/src/mocks.dart index 1ae2ef2..7ce9880 100644 --- a/lib/src/mocks.dart +++ b/lib/src/mocks.dart @@ -6,27 +6,15 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io' as io show IOSink, ProcessSignal, Stdout, StdoutException; -//import 'package:tool_base/src/android/android_device.dart'; -//import 'package:tool_base/src/android/android_sdk.dart' show AndroidSdk; -//import 'package:tool_base/src/application_package.dart'; +import 'package:mockito/mockito.dart'; +import 'package:process/process.dart'; import 'package:tool_base/src/base/context.dart'; -import 'package:tool_base/src/base/file_system.dart' hide IOSink; import 'package:tool_base/src/base/io.dart'; import 'package:tool_base/src/base/platform.dart'; -//import 'package:tool_base/src/build_info.dart'; -//import 'package:tool_base/src/compile.dart'; -//import 'package:tool_base/src/devfs.dart'; -//import 'package:tool_base/src/device.dart'; -//import 'package:tool_base/src/ios/devices.dart'; -//import 'package:tool_base/src/ios/simulators.dart'; -//import 'package:tool_base/src/project.dart'; -//import 'package:tool_base/src/runner/flutter_command.dart'; -import 'package:mockito/mockito.dart'; -import 'package:process/process.dart'; import 'common.dart'; -final Generator kNoColorTerminalPlatform = () => FakePlatform.fromPlatform(const LocalPlatform())..stdoutSupportsAnsi = false; +final Generator kNoColorTerminalPlatform = () => FakePlatform.fromPlatform(const LocalPlatform()).copyWith(stdoutSupportsAnsi: false); //class MockApplicationPackageStore extends ApplicationPackageStore { // MockApplicationPackageStore() : super( @@ -152,42 +140,76 @@ final Generator kNoColorTerminalPlatform = () => FakePlatform.fromPlatform(const /// A strategy for creating Process objects from a list of commands. typedef ProcessFactory = Process Function(List command); -/// A ProcessManager that starts Processes by delegating to a ProcessFactory. class MockProcessManager extends Mock implements ProcessManager { - ProcessFactory processFactory = (List commands) => MockProcess(); - bool canRunSucceeds = true; - bool runSucceeds = true; - List commands; - - @override - bool canRun(dynamic command, { String workingDirectory }) => canRunSucceeds; @override Future start( - List command, { - String workingDirectory, - Map environment, - bool includeParentEnvironment = true, - bool runInShell = false, + List? command, { + String? workingDirectory, + Map? environment, + bool? includeParentEnvironment, + bool? runInShell, ProcessStartMode mode = ProcessStartMode.normal, - }) { - if (!runSucceeds) { - final String executable = command[0]; - final List arguments = command.length > 1 ? command.sublist(1) : []; - throw ProcessException(executable, arguments); - } - - commands = command; - return Future.value(processFactory(command)); - } + }) => + super.noSuchMethod(Invocation.method(#start, [ + command + ], { + #workingDirectory: workingDirectory, + #environment: environment, + #includeParentEnvironment: includeParentEnvironment, + #runInShell: runInShell, + #mode: mode, + })); + + @override + Future run( + List? command, { + String? workingDirectory, + Map? environment, + bool? includeParentEnvironment, + bool? runInShell, + covariant Encoding? stdoutEncoding = systemEncoding, + covariant Encoding? stderrEncoding = systemEncoding, + }) => + super.noSuchMethod(Invocation.method(#run, [ + command + ], { + #workingDirectory: workingDirectory, + #environment: environment, + #includeParentEnvironment: includeParentEnvironment, + #runInShell: runInShell, + #stdoutEncoding: stdoutEncoding, + #stderrEncoding: stderrEncoding, + })); + + @override + ProcessResult runSync( + List? command, { + String? workingDirectory, + Map? environment, + bool? includeParentEnvironment, + bool? runInShell, + covariant Encoding? stdoutEncoding = systemEncoding, + covariant Encoding? stderrEncoding = systemEncoding, + }) => + super.noSuchMethod(Invocation.method(#runSync, [ + command + ], { + #workingDirectory: workingDirectory, + #environment: environment, + #includeParentEnvironment: includeParentEnvironment, + #runInShell: runInShell, + #stdoutEncoding: stdoutEncoding, + #stderrEncoding: stderrEncoding, + })); } /// A process that exits successfully with no output and ignores all input. class MockProcess extends Mock implements Process { MockProcess({ this.pid = 1, - Future exitCode, - Stream> stdin, + Future? exitCode, + io.IOSink? stdin, this.stdout = const Stream>.empty(), this.stderr = const Stream>.empty(), }) : exitCode = exitCode ?? Future.value(0), @@ -213,8 +235,8 @@ class MockProcess extends Mock implements Process { class FakeProcess implements Process { FakeProcess({ this.pid = 1, - Future exitCode, - Stream> stdin, + Future? exitCode, + io.IOSink? stdin, this.stdout = const Stream>.empty(), this.stderr = const Stream>.empty(), }) : exitCode = exitCode ?? Future.value(0), @@ -246,12 +268,13 @@ class FakeProcess implements Process { class PromptingProcess implements Process { Future showPrompt(String prompt, List outputLines) async { _stdoutController.add(utf8.encode(prompt)); - final List bytesOnStdin = await _stdin.future; + final bytesOnStdin = await _stdin.future; // Echo stdin to stdout. _stdoutController.add(bytesOnStdin); if (bytesOnStdin[0] == utf8.encode('y')[0]) { - for (final String line in outputLines) + for (final line in outputLines) { _stdoutController.add(utf8.encode('$line\n')); + } } await _stdoutController.close(); } @@ -286,8 +309,9 @@ class CompleterIOSink extends MemoryIOSink { @override void add(List data) { - if (!_completer.isCompleted) + if (!_completer.isCompleted) { _completer.complete(data); + } super.add(data); } } @@ -306,7 +330,7 @@ class MemoryIOSink implements IOSink { @override Future addStream(Stream> stream) { - final Completer completer = Completer(); + final completer = Completer(); stream.listen((List data) { add(data); }).onDone(() => completer.complete()); @@ -319,18 +343,18 @@ class MemoryIOSink implements IOSink { } @override - void write(Object obj) { + void write(Object? obj) { add(encoding.encode('$obj')); } @override - void writeln([ Object obj = '' ]) { + void writeln([Object? obj = '']) { add(encoding.encode('$obj\n')); } @override void writeAll(Iterable objects, [ String separator = '' ]) { - bool addSeparator = false; + var addSeparator = false; for (dynamic object in objects) { if (addSeparator) { write(separator); @@ -341,7 +365,7 @@ class MemoryIOSink implements IOSink { } @override - void addError(dynamic error, [ StackTrace stackTrace ]) { + void addError(dynamic error, [StackTrace? stackTrace]) { throw UnimplementedError(); } @@ -359,7 +383,6 @@ class MemoryStdout extends MemoryIOSink implements io.Stdout { @override bool get hasTerminal => _hasTerminal; set hasTerminal(bool value) { - assert(value != null); _hasTerminal = value; } bool _hasTerminal = true; @@ -370,28 +393,29 @@ class MemoryStdout extends MemoryIOSink implements io.Stdout { @override bool get supportsAnsiEscapes => _supportsAnsiEscapes; set supportsAnsiEscapes(bool value) { - assert(value != null); _supportsAnsiEscapes = value; } bool _supportsAnsiEscapes = true; @override int get terminalColumns { - if (_terminalColumns != null) - return _terminalColumns; + if (_terminalColumns != null) { + return _terminalColumns!; + } throw const io.StdoutException('unspecified mock value'); } set terminalColumns(int value) => _terminalColumns = value; - int _terminalColumns; + int? _terminalColumns; @override int get terminalLines { - if (_terminalLines != null) - return _terminalLines; + if (_terminalLines != null) { + return _terminalLines!; + } throw const io.StdoutException('unspecified mock value'); } set terminalLines(int value) => _terminalLines = value; - int _terminalLines; + int? _terminalLines; } /// A Stdio that collects stdout and supports simulated stdin. @@ -516,7 +540,7 @@ class BasicMock { final List messages = []; void expectMessages(List expectedMessages) { - final List actualMessages = List.from(messages); + final actualMessages = List.from(messages); messages.clear(); expect(actualMessages, unorderedEquals(expectedMessages)); } @@ -524,7 +548,7 @@ class BasicMock { bool contains(String match) { print('Checking for `$match` in:'); print(messages); - final bool result = messages.contains(match); + final result = messages.contains(match); messages.clear(); return result; } @@ -616,18 +640,18 @@ class MockStdIn extends Mock implements IOSink { final StringBuffer stdInWrites = StringBuffer(); String getAndClear() { - final String result = stdInWrites.toString(); + final result = stdInWrites.toString(); stdInWrites.clear(); return result; } @override - void write([ Object o = '' ]) { + void write([Object? o]) { stdInWrites.write(o); } @override - void writeln([ Object o = '' ]) { + void writeln([Object? o]) { stdInWrites.writeln(o); } } diff --git a/lib/src/testbed.dart b/lib/src/testbed.dart index f3fa742..1d68f33 100644 --- a/lib/src/testbed.dart +++ b/lib/src/testbed.dart @@ -8,7 +8,6 @@ import 'dart:io'; import 'dart:typed_data'; import 'package:file/memory.dart'; -import 'package:reporting/reporting.dart'; import 'package:tool_base/src/base/context.dart'; import 'package:tool_base/src/base/file_system.dart'; import 'package:tool_base/src/base/io.dart'; @@ -17,10 +16,6 @@ import 'package:tool_base/src/base/os.dart'; import 'package:tool_base/src/base/platform.dart'; import 'package:tool_base/src/base/terminal.dart'; import 'package:tool_base/src/cache.dart'; -//import 'package:tool_base/src/context_runner.dart'; -//import 'package:tool_base/src/features.dart'; -//import 'package:tool_base/src/reporting/reporting.dart'; -//import 'package:tool_base/src/version.dart'; import 'context.dart'; import 'context_runner.dart'; @@ -42,7 +37,7 @@ final Map _testbedDefaults = { /// Manages interaction with the tool injection and runner system. /// /// The Testbed automatically injects reasonable defaults through the context -/// DI system such as a [BufferLogger] and a [MemoryFileSytem]. +/// DI system such as a [BufferLogger] and a [MemoryFileSystem]. /// /// Example: /// @@ -73,19 +68,19 @@ class Testbed { /// `overrides` provides more overrides in addition to the test defaults. /// `setup` may be provided to apply mocks within the tool managed zone, /// including any specified overrides. - Testbed({FutureOr Function() setup, Map overrides}) - : _setup = setup, + Testbed({FutureOr Function()? setup, Map? overrides}) + : _setup = setup, _overrides = overrides; - final FutureOr Function() _setup; - final Map _overrides; + final FutureOr Function()? _setup; + final Map? _overrides; /// Runs `test` within a tool zone. /// /// `overrides` may be used to provide new context values for the single test /// case or override any context values from the setup. - FutureOr run(FutureOr Function() test, {Map overrides}) { - final Map testOverrides = { + FutureOr run(FutureOr Function() test, {Map? overrides}) { + final testOverrides = { ..._testbedDefaults, // Add the initial setUp overrides ...?_overrides, @@ -93,23 +88,23 @@ class Testbed { ...?overrides, }; // Cache the original flutter root to restore after the test case. - final String originalFlutterRoot = Cache.flutterRoot; + final originalFlutterRoot = Cache.flutterRoot; // Track pending timers to verify that they were correctly cleaned up. - final Map timers = {}; + final timers = {}; return HttpOverrides.runZoned(() { - return runInContext(() { - return context.run( + return runInContext(() { + return context.run( name: 'testbed', overrides: testOverrides, zoneSpecification: ZoneSpecification( createTimer: (Zone self, ZoneDelegate parent, Zone zone, Duration duration, void Function() timer) { - final Timer result = parent.createTimer(zone, duration, timer); + final result = parent.createTimer(zone, duration, timer); timers[result] = StackTrace.current; return result; }, createPeriodicTimer: (Zone self, ZoneDelegate parent, Zone zone, Duration period, void Function(Timer) timer) { - final Timer result = parent.createPeriodicTimer(zone, period, timer); + final result = parent.createPeriodicTimer(zone, period, timer); timers[result] = StackTrace.current; return result; } @@ -117,11 +112,11 @@ class Testbed { body: () async { Cache.flutterRoot = ''; if (_setup != null) { - await _setup(); + await _setup!(); } await test(); Cache.flutterRoot = originalFlutterRoot; - for (MapEntry entry in timers.entries) { + for (var entry in timers.entries) { if (entry.key.isActive) { throw StateError('A Timer was active at the end of a test: ${entry.value}'); } @@ -129,10 +124,11 @@ class Testbed { return null; }); }); - }, createHttpClient: (SecurityContext c) => FakeHttpClient()); + }, createHttpClient: (SecurityContext? c) => FakeHttpClient()); } } +/* /// A no-op implementation of [Usage] for testing. class NoOpUsage implements Usage { @override @@ -170,22 +166,23 @@ class NoOpUsage implements Usage { @override void sendTiming(String category, String variableName, Duration duration, { String label }) {} } +*/ class FakeHttpClient implements HttpClient { @override - bool autoUncompress; + bool autoUncompress = true; @override - Duration connectionTimeout; + Duration? connectionTimeout; @override - Duration idleTimeout; + Duration idleTimeout = Duration(seconds: 0); @override - int maxConnectionsPerHost; + int? maxConnectionsPerHost; @override - String userAgent; + String? userAgent; @override void addCredentials( @@ -197,16 +194,17 @@ class FakeHttpClient implements HttpClient { @override set authenticate( - Future Function(Uri url, String scheme, String realm) f) {} + Future Function(Uri url, String scheme, String? realm)? f) {} @override set authenticateProxy( - Future Function(String host, int port, String scheme, String realm) - f) {} + Future Function( + String host, int port, String scheme, String? realm)? + f) {} @override set badCertificateCallback( - bool Function(X509Certificate cert, String host, int port) callback) {} + bool Function(X509Certificate cert, String host, int port)? callback) {} @override void close({bool force = false}) {} @@ -222,7 +220,7 @@ class FakeHttpClient implements HttpClient { } @override - set findProxy(String Function(Uri url) f) {} + set findProxy(String Function(Uri url)? f) {} @override Future get(String host, int port, String path) async { @@ -245,7 +243,8 @@ class FakeHttpClient implements HttpClient { } @override - Future open(String method, String host, int port, String path) async { + Future open( + String method, String host, int port, String path) async { return FakeHttpClientRequest(); } @@ -289,28 +288,28 @@ class FakeHttpClientRequest implements HttpClientRequest { FakeHttpClientRequest(); @override - bool bufferOutput; + bool bufferOutput = true; @override - int contentLength; + int contentLength = -1; @override - Encoding encoding; + late Encoding encoding; @override - bool followRedirects; + late bool followRedirects; @override - int maxRedirects; + late int maxRedirects; @override - bool persistentConnection; + bool persistentConnection = true; @override void add(List data) {} @override - void addError(Object error, [StackTrace stackTrace]) {} + void addError(Object error, [StackTrace? stackTrace]) {} @override Future addStream(Stream> stream) async {} @@ -321,13 +320,13 @@ class FakeHttpClientRequest implements HttpClientRequest { } @override - HttpConnectionInfo get connectionInfo => null; + HttpConnectionInfo? get connectionInfo => null; @override List get cookies => []; @override - Future get done => null; + Future get done => throw 'Fake'; @override Future flush() { @@ -335,38 +334,41 @@ class FakeHttpClientRequest implements HttpClientRequest { } @override - HttpHeaders get headers => null; + HttpHeaders get headers => throw 'Fake'; @override - String get method => null; + String get method => throw 'Fake'; @override - Uri get uri => null; + Uri get uri => throw 'Fake'; @override - void write(Object obj) {} + void write(Object? obj) {} @override - void writeAll(Iterable objects, [String separator = '']) {} + void writeAll(Iterable objects, [String separator = '']) {} @override void writeCharCode(int charCode) {} @override - void writeln([Object obj = '']) {} + void writeln([Object? obj]) {} + + @override + void abort([Object? exception, StackTrace? stackTrace]) {} } class FakeHttpClientResponse implements HttpClientResponse { - final Stream _delegate = Stream.fromIterable(const Iterable.empty()); + final Stream> _delegate = Stream.fromIterable(const Iterable.empty()); @override final HttpHeaders headers = FakeHttpHeaders(); @override - X509Certificate get certificate => null; + X509Certificate get certificate => throw 'Not implemented'; @override - HttpConnectionInfo get connectionInfo => null; + HttpConnectionInfo get connectionInfo => throw 'Not implemented'; @override int get contentLength => 0; @@ -377,7 +379,7 @@ class FakeHttpClientResponse implements HttpClientResponse { } @override - List get cookies => null; + List get cookies => throw 'Not implemented'; @override Future detachSocket() { @@ -388,18 +390,20 @@ class FakeHttpClientResponse implements HttpClientResponse { bool get isRedirect => false; @override - StreamSubscription listen(void Function(Uint8List event) onData, { Function onError, void Function() onDone, bool cancelOnError }) { - return const Stream.empty().listen(onData, onError: onError, onDone: onDone, cancelOnError: cancelOnError); + StreamSubscription listen(void Function(Uint8List event)? onData, + {Function? onError, void Function()? onDone, bool? cancelOnError}) { + return const Stream.empty().listen(onData, + onError: onError, onDone: onDone, cancelOnError: cancelOnError); } @override - bool get persistentConnection => null; + bool get persistentConnection => throw 'Not implemented'; @override - String get reasonPhrase => null; + String get reasonPhrase => throw 'Not implemented'; @override - Future redirect([ String method, Uri url, bool followLoops ]) { + Future redirect([ String? method, Uri? url, bool? followLoops ]) { return Future.error(UnsupportedError('Mocked response')); } @@ -410,25 +414,24 @@ class FakeHttpClientResponse implements HttpClientResponse { int get statusCode => 400; @override - Future any(bool Function(Uint8List element) test) { + Future any(bool Function(List element) test) { return _delegate.any(test); } @override - Stream asBroadcastStream({ - void Function(StreamSubscription subscription) onListen, - void Function(StreamSubscription subscription) onCancel, - }) { + Stream> asBroadcastStream( + {void Function(StreamSubscription> subscription)? onListen, + void Function(StreamSubscription> subscription)? onCancel}) { return _delegate.asBroadcastStream(onListen: onListen, onCancel: onCancel); } @override - Stream asyncExpand(Stream Function(Uint8List event) convert) { + Stream asyncExpand(Stream? Function(List event) convert) { return _delegate.asyncExpand(convert); } @override - Stream asyncMap(FutureOr Function(Uint8List event) convert) { + Stream asyncMap(FutureOr Function(List event) convert) { return _delegate.asyncMap(convert); } @@ -438,60 +441,60 @@ class FakeHttpClientResponse implements HttpClientResponse { } @override - Future contains(Object needle) { + Future contains(Object? needle) { return _delegate.contains(needle); } @override - Stream distinct([bool Function(Uint8List previous, Uint8List next) equals]) { + Stream> distinct([bool Function(List previous, List next)? equals]) { return _delegate.distinct(equals); } @override - Future drain([E futureValue]) { + Future drain([E? futureValue]) { return _delegate.drain(futureValue); } @override - Future elementAt(int index) { + Future> elementAt(int index) { return _delegate.elementAt(index); } @override - Future every(bool Function(Uint8List element) test) { + Future every(bool Function(List element) test) { return _delegate.every(test); } @override - Stream expand(Iterable Function(Uint8List element) convert) { + Stream expand(Iterable Function(List element) convert) { return _delegate.expand(convert); } @override - Future get first => _delegate.first; + Future> get first => _delegate.first; @override - Future firstWhere( - bool Function(Uint8List element) test, { - List Function() orElse, + Future> firstWhere( + bool Function(List) test, { + List Function()? orElse, }) { return _delegate.firstWhere(test, orElse: orElse); } @override - Future fold(S initialValue, S Function(S previous, Uint8List element) combine) { + Future fold(S initialValue, S Function(S previous, List element) combine) { return _delegate.fold(initialValue, combine); } @override - Future forEach(void Function(Uint8List element) action) { + Future forEach(void Function(List element) action) { return _delegate.forEach(action); } @override - Stream handleError( + Stream> handleError( Function onError, { - bool Function(dynamic error) test, + bool Function(dynamic error)? test, }) { return _delegate.handleError(onError, test: test); } @@ -508,12 +511,12 @@ class FakeHttpClientResponse implements HttpClientResponse { } @override - Future get last => _delegate.last; + Future> get last => _delegate.last; @override - Future lastWhere( - bool Function(Uint8List element) test, { - List Function() orElse, + Future> lastWhere( + bool Function(List) test, { + List Function()? orElse, }) { return _delegate.lastWhere(test, orElse: orElse); } @@ -522,63 +525,63 @@ class FakeHttpClientResponse implements HttpClientResponse { Future get length => _delegate.length; @override - Stream map(S Function(Uint8List event) convert) { + Stream map(S Function(List event) convert) { return _delegate.map(convert); } @override - Future pipe(StreamConsumer> streamConsumer) { + Future pipe(StreamConsumer> streamConsumer) { return _delegate.pipe(streamConsumer); } @override - Future reduce(List Function(Uint8List previous, Uint8List element) combine) { + Future> reduce(List Function(List previous, List element) combine) { return _delegate.reduce(combine); } @override - Future get single => _delegate.single; + Future> get single => _delegate.single; @override - Future singleWhere(bool Function(Uint8List element) test, {List Function() orElse}) { + Future> singleWhere(bool Function(List element) test, {List Function()? orElse}) { return _delegate.singleWhere(test, orElse: orElse); } @override - Stream skip(int count) { + Stream> skip(int count) { return _delegate.skip(count); } @override - Stream skipWhile(bool Function(Uint8List element) test) { + Stream> skipWhile(bool Function(List element) test) { return _delegate.skipWhile(test); } @override - Stream take(int count) { + Stream> take(int count) { return _delegate.take(count); } @override - Stream takeWhile(bool Function(Uint8List element) test) { + Stream> takeWhile(bool Function(List element) test) { return _delegate.takeWhile(test); } @override - Stream timeout( + Stream> timeout( Duration timeLimit, { - void Function(EventSink sink) onTimeout, + void Function(EventSink> sink)? onTimeout, }) { return _delegate.timeout(timeLimit, onTimeout: onTimeout); } @override - Future> toList() { + Future>> toList() { return _delegate.toList(); } @override - Future> toSet() { + Future>> toSet() { return _delegate.toSet(); } @@ -588,7 +591,7 @@ class FakeHttpClientResponse implements HttpClientResponse { } @override - Stream where(bool Function(Uint8List event) test) { + Stream> where(bool Function(List event) test) { return _delegate.where(test); } } @@ -599,7 +602,7 @@ class FakeHttpHeaders extends HttpHeaders { List operator [](String name) => []; @override - void add(String name, Object value) { } + void add(String name, Object value, {bool preserveHeaderCase = false}) {} @override void clear() { } @@ -617,10 +620,10 @@ class FakeHttpHeaders extends HttpHeaders { void removeAll(String name) { } @override - void set(String name, Object value) { } + void set(String name, Object value, {bool preserveHeaderCase = false}) {} @override - String value(String name) => null; + String value(String name) => throw 'Not implemented'; } //class FakeFlutterVersion implements FlutterVersion { diff --git a/pubspec.yaml b/pubspec.yaml index 126d2cb..e96afd8 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -5,17 +5,18 @@ description: A starting point for Dart libraries or applications. # author: Maurice McCabe environment: - sdk: '>=2.4.0 <3.0.0' + sdk: '>=2.12.0 <3.0.0' dependencies: - tool_base: ^1.9.5+3 + tool_base: ^2.0.0 # tool_base: # path: ../tool_base - reporting: - git: https://github.com/mmcc007/reporting.git -# path: ../reporting dev_dependencies: pedantic: ^1.7.0 - test: ^1.6.0 - mockito: ^4.1.0 + test: ^1.19.2 + mockito: ^5.0.16 + +dependency_overrides: + tool_base: + path: ../tool_base diff --git a/test/all_tests.dart b/test/all_tests.dart index 51b9c64..e243ca6 100644 --- a/test/all_tests.dart +++ b/test/all_tests.dart @@ -1,7 +1,7 @@ import 'context_test.dart' as context_test; import 'testbed_test.dart' as testbed_test; -main(){ +void main(){ context_test.main(); testbed_test.main(); -} \ No newline at end of file +} diff --git a/test/context_test.dart b/test/context_test.dart index d26e982..d15a519 100644 --- a/test/context_test.dart +++ b/test/context_test.dart @@ -14,7 +14,7 @@ import 'package:tool_base/tool_base.dart'; void main() { group('AppContext', () { group('global getter', () { - bool called; + var called = false; setUp(() { called = false; @@ -27,8 +27,8 @@ void main() { test( 'returns root context in child of root zone if zone was manually created', () { - final Zone rootZone = Zone.current; - final AppContext rootContext = context; + final rootZone = Zone.current; + final rootContext = context; runZoned(() { expect(Zone.current, isNot(rootZone)); expect(Zone.current.parent, rootZone); @@ -39,7 +39,7 @@ void main() { }); test('returns child context after run', () async { - final AppContext rootContext = context; + final rootContext = context; await rootContext.run( name: 'child', body: () { @@ -51,11 +51,11 @@ void main() { }); test('returns grandchild context after nested run', () async { - final AppContext rootContext = context; + final rootContext = context; await rootContext.run( name: 'child', body: () async { - final AppContext childContext = context; + final childContext = context; await childContext.run( name: 'grandchild', body: () { @@ -69,11 +69,11 @@ void main() { }); test('scans up zone hierarchy for first context', () async { - final AppContext rootContext = context; + final rootContext = context; await rootContext.run( name: 'child', body: () { - final AppContext childContext = context; + final childContext = context; runZoned(() { expect(context, isNot(rootContext)); expect(context, same(childContext)); @@ -88,9 +88,9 @@ void main() { group('operator[]', () { test('still finds values if async code runs after body has finished', () async { - final Completer outer = Completer(); - final Completer inner = Completer(); - String value; + final outer = Completer(); + final inner = Completer(); + String? value; await context.run( body: () { outer.future.then((_) { @@ -109,11 +109,11 @@ void main() { }); test('caches generated override values', () async { - int consultationCount = 0; - String value; + var consultationCount = 0; + String? value; await context.run( body: () async { - final StringBuffer buf = StringBuffer(context.get()); + final buf = StringBuffer(context.get()!); buf.write(context.get()); await context.run(body: () { buf.write(context.get()); @@ -132,11 +132,11 @@ void main() { }); test('caches generated fallback values', () async { - int consultationCount = 0; - String value; + var consultationCount = 0; + String? value; await context.run( body: () async { - final StringBuffer buf = StringBuffer(context.get()); + final buf = StringBuffer(context.get()!); buf.write(context.get()); await context.run(body: () { buf.write(context.get()); @@ -155,8 +155,8 @@ void main() { }); test('returns null if generated value is null', () async { - final String value = await context.run( - body: () => context.get(), + final value = await context.run( + body: () => context.get()!, overrides: { String: () => null, }, @@ -165,14 +165,12 @@ void main() { }); test('throws if generator has dependency cycle', () async { - final Future value = context.run( - body: () async { - return context.get(); - }, + final value = context.run( + body: () async => context.get()!, fallbacks: { - int: () => int.parse(context.get()), + int: () => int.parse(context.get()!), String: () => '${context.get()}', - double: () => context.get() * 1.0, + double: () => context.get()! * 1.0, }, ); try { @@ -202,47 +200,43 @@ void main() { }); group('fallbacks', () { - bool called; + var called = false; setUp(() { called = false; }); test('are applied after parent context is consulted', () async { - final String value = await context.run( - body: () { - return context.run( - body: () { - called = true; - return context.get(); - }, - fallbacks: { - String: () => 'child', - }, - ); - }, + final value = await context.run( + body: () => context.run( + body: () { + called = true; + return context.get()!; + }, + fallbacks: { + String: () => 'child', + }, + ), ); expect(called, isTrue); expect(value, 'child'); }); test('are not applied if parent context supplies value', () async { - bool childConsulted = false; - final String value = await context.run( - body: () { - return context.run( - body: () { - called = true; - return context.get(); - }, - fallbacks: { - String: () { - childConsulted = true; - return 'child'; - }, + var childConsulted = false; + final value = await context.run( + body: () => context.run( + body: () { + called = true; + return context.get()!; + }, + fallbacks: { + String: () { + childConsulted = true; + return 'child'; }, - ); - }, + }, + ), fallbacks: { String: () => 'parent', }, @@ -253,10 +247,8 @@ void main() { }); test('may depend on one another', () async { - final String value = await context.run( - body: () { - return context.get(); - }, + final value = await context.run( + body: () => context.get()!, fallbacks: { int: () => 123, String: () => '-${context.get()}-', @@ -268,16 +260,14 @@ void main() { group('overrides', () { test('intercept consultation of parent context', () async { - bool parentConsulted = false; - final String value = await context.run( - body: () { - return context.run( - body: () => context.get(), + var parentConsulted = false; + final value = await context.run( + body: () => context.run( + body: () => context.get()!, overrides: { String: () => 'child', }, - ); - }, + ), fallbacks: { String: () { parentConsulted = true; diff --git a/test/testbed_test.dart b/test/testbed_test.dart index 82146c7..00f686a 100644 --- a/test/testbed_test.dart +++ b/test/testbed_test.dart @@ -3,10 +3,8 @@ // found in the LICENSE file. import 'dart:async'; -import 'dart:io'; import 'package:file/memory.dart'; -import 'package:test/test.dart'; import 'package:tool_base/tool_base.dart'; import 'package:tool_base_test/tool_base_test.dart'; //import 'package:flutter_tools/src/base/context.dart'; @@ -19,9 +17,9 @@ void main() { group('Testbed', () { test('Can provide default interfaces', () async { - final Testbed testbed = Testbed(); + final testbed = Testbed(); - FileSystem localFileSystem; + var localFileSystem = fs; await testbed.run(() { localFileSystem = fs; }); @@ -30,11 +28,11 @@ void main() { }); test('Can provide setup interfaces', () async { - final Testbed testbed = Testbed(overrides: { + final testbed = Testbed(overrides: { A: () => A(), }); - A instance; + A? instance; await testbed.run(() { instance = context.get(); }); @@ -43,11 +41,11 @@ void main() { }); test('Can provide local overrides', () async { - final Testbed testbed = Testbed(overrides: { + final testbed = Testbed(overrides: { A: () => A(), }); - A instance; + A? instance; await testbed.run(() { instance = context.get(); }, overrides: { @@ -58,11 +56,11 @@ void main() { }); test('provides a mocked http client', () async { - final Testbed testbed = Testbed(); + final testbed = Testbed(); await testbed.run(() async { - final HttpClient client = HttpClient(); - final HttpClientRequest request = await client.getUrl(null); - final HttpClientResponse response = await request.close(); + final client = HttpClient(); + final request = await client.getUrl(Uri()); + final response = await request.close(); expect(response.statusCode, HttpStatus.badRequest); expect(response.contentLength, 0); @@ -70,18 +68,18 @@ void main() { }); test('Throws StateError if Timer is left pending', () async { - final Testbed testbed = Testbed(); + final testbed = Testbed(); expect(testbed.run(() async { Timer.periodic(const Duration(seconds: 1), (Timer timer) { }); }), throwsA(isA())); }); - test('Doesnt throw a StateError if Timer is left cleaned up', () async { - final Testbed testbed = Testbed(); + test("Doesn't throw a StateError if Timer is left cleaned up", () async { + final testbed = Testbed(); testbed.run(() async { - final Timer timer = Timer.periodic(const Duration(seconds: 1), (Timer timer) { }); + final timer = Timer.periodic(const Duration(seconds: 1), (Timer timer) { }); timer.cancel(); }); }); diff --git a/tool_base_test.iml b/tool_base_test.iml new file mode 100644 index 0000000..a7a886f --- /dev/null +++ b/tool_base_test.iml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file