diff --git a/.github/ISSUE_TEMPLATE/test_reflective_loader.md b/.github/ISSUE_TEMPLATE/test_reflective_loader.md new file mode 100644 index 000000000..bde03feb7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/test_reflective_loader.md @@ -0,0 +1,5 @@ +--- +name: "package:test_reflective_loader" +about: "Create a bug or file a feature request against package:test_reflective_loader." +labels: "package:test_reflective_loader" +--- \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/timing.md b/.github/ISSUE_TEMPLATE/timing.md new file mode 100644 index 000000000..38a001578 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/timing.md @@ -0,0 +1,5 @@ +--- +name: "package:timing" +about: "Create a bug or file a feature request against package:timing." +labels: "package:timing" +--- \ No newline at end of file diff --git a/.github/labeler.yml b/.github/labeler.yml index 4c93a3929..87232f5be 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -112,6 +112,14 @@ - changed-files: - any-glob-to-any-file: 'pkgs/term_glyph/**' +'package:test_reflective_loader': + - changed-files: + - any-glob-to-any-file: 'pkgs/test_reflective_loader/**' + +'package:timing': + - changed-files: + - any-glob-to-any-file: 'pkgs/timing/**' + 'package:unified_analytics': - changed-files: - any-glob-to-any-file: 'pkgs/unified_analytics/**' diff --git a/.github/workflows/bazel_worker.yaml b/.github/workflows/bazel_worker.yaml index 0eb06dad7..b448219d1 100644 --- a/.github/workflows/bazel_worker.yaml +++ b/.github/workflows/bazel_worker.yaml @@ -36,6 +36,8 @@ jobs: - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94 with: sdk: ${{ matrix.sdk }} + - run: dart pub get - run: "dart format --output=none --set-exit-if-changed ." + if: ${{ matrix.sdk == 'dev' }} - name: Test run: ./tool/travis.sh diff --git a/.github/workflows/test_reflective_loader.yaml b/.github/workflows/test_reflective_loader.yaml new file mode 100644 index 000000000..975c97049 --- /dev/null +++ b/.github/workflows/test_reflective_loader.yaml @@ -0,0 +1,43 @@ +name: package:test_reflective_loader + +on: + # Run on PRs and pushes to the default branch. + push: + branches: [ main ] + paths: + - '.github/workflows/test_reflective_loader.yaml' + - 'pkgs/test_reflective_loader/**' + pull_request: + branches: [ main ] + paths: + - '.github/workflows/test_reflective_loader.yaml' + - 'pkgs/test_reflective_loader/**' + schedule: + - cron: "0 0 * * 0" + +env: + PUB_ENVIRONMENT: bot.github + +defaults: + run: + working-directory: pkgs/test_reflective_loader/ + +jobs: + build: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + sdk: [dev, 3.1] + + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94 + with: + sdk: ${{ matrix.sdk }} + + - run: dart pub get + - name: dart format + run: dart format --output=none --set-exit-if-changed . + - run: dart analyze --fatal-infos + - run: dart test diff --git a/.github/workflows/timing.yaml b/.github/workflows/timing.yaml new file mode 100644 index 000000000..df77b137e --- /dev/null +++ b/.github/workflows/timing.yaml @@ -0,0 +1,67 @@ +name: package:timing + +on: + # Run on PRs and pushes to the default branch. + push: + branches: [ main ] + paths: + - '.github/workflows/timing.yaml' + - 'pkgs/timing/**' + pull_request: + branches: [ main ] + paths: + - '.github/workflows/timing.yaml' + - 'pkgs/timing/**' + schedule: + - cron: "0 0 * * 0" + +env: + PUB_ENVIRONMENT: bot.github + + +defaults: + run: + working-directory: pkgs/timing/ + +jobs: + # Check code formatting and static analysis on a single OS (linux) + # against Dart dev. + analyze: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + sdk: [3.4, dev] + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94 + with: + sdk: ${{ matrix.sdk }} + - id: install + run: dart pub get + - run: dart format --output=none --set-exit-if-changed . + if: always() && steps.install.outcome == 'success' + - run: dart analyze --fatal-infos + if: always() && steps.install.outcome == 'success' + + # Run tests on a matrix consisting of two dimensions: + # 1. OS: ubuntu-latest, (macos-latest, windows-latest) + # 2. release channel: dev, 2.2.0 + test: + needs: analyze + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + # Add macos-latest and/or windows-latest if relevant for this package. + os: [ubuntu-latest] + sdk: [3.4, dev] + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94 + with: + sdk: ${{ matrix.sdk }} + - id: install + run: dart pub get + - run: dart test --platform vm + if: always() && steps.install.outcome == 'success' diff --git a/README.md b/README.md index fc9fa4b41..ddf2b52db 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,8 @@ don't naturally belong to other topic monorepos (like | [source_span](pkgs/source_span/) | Provides a standard representation for source code locations and spans. | [![package issues](https://img.shields.io/badge/package:source_span-4774bc)](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Asource_span) | [![pub package](https://img.shields.io/pub/v/source_span.svg)](https://pub.dev/packages/source_span) | | [sse](pkgs/sse/) | Provides client and server functionality for setting up bi-directional communication through Server Sent Events (SSE) and corresponding POST requests. | [![package issues](https://img.shields.io/badge/package:sse-4774bc)](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Asse) | [![pub package](https://img.shields.io/pub/v/sse.svg)](https://pub.dev/packages/sse) | | [term_glyph](pkgs/term_glyph/) | Useful Unicode glyphs and ASCII substitutes. | [![package issues](https://img.shields.io/badge/package:term_glyph-4774bc)](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Aterm_glyph) | [![pub package](https://img.shields.io/pub/v/term_glyph.svg)](https://pub.dev/packages/term_glyph) | +| [test_reflective_loader](pkgs/test_reflective_loader/) | Support for discovering tests and test suites using reflection. | [![package issues](https://img.shields.io/badge/package:test_reflective_loader-4774bc)](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Atest_reflective_loader) | [![pub package](https://img.shields.io/pub/v/test_reflective_loader.svg)](https://pub.dev/packages/test_reflective_loader) | +| [timing](pkgs/timing/) | A simple package for tracking the performance of synchronous and asynchronous actions. | [![package issues](https://img.shields.io/badge/package:timing-4774bc)](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Atiming) | [![pub package](https://img.shields.io/pub/v/timing.svg)](https://pub.dev/packages/timing) | | [unified_analytics](pkgs/unified_analytics/) | A package for logging analytics for all Dart and Flutter related tooling to Google Analytics. | [![package issues](https://img.shields.io/badge/package:unified_analytics-4774bc)](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Aunified_analytics) | [![pub package](https://img.shields.io/pub/v/unified_analytics.svg)](https://pub.dev/packages/unified_analytics) | ## Publishing automation diff --git a/pkgs/bazel_worker/benchmark/benchmark.dart b/pkgs/bazel_worker/benchmark/benchmark.dart index 035e2b848..0a0312203 100644 --- a/pkgs/bazel_worker/benchmark/benchmark.dart +++ b/pkgs/bazel_worker/benchmark/benchmark.dart @@ -12,10 +12,7 @@ Future main() async { var path = 'blaze-bin/some/path/to/a/file/that/is/an/input/$i'; workRequest ..arguments.add('--input=$path') - ..inputs.add(Input( - path: '', - digest: List.filled(70, 0x11), - )); + ..inputs.add(Input(path: '', digest: List.filled(70, 0x11))); } // Serialize it. @@ -24,14 +21,20 @@ Future main() async { print('Request has $length requestBytes.'); // Add the length in front base 128 encoded as in the worker protocol. - requestBytes = - Uint8List.fromList(requestBytes.toList()..insertAll(0, _varInt(length))); + requestBytes = Uint8List.fromList( + requestBytes.toList()..insertAll(0, _varInt(length)), + ); // Split into 10000 byte chunks. var lists = []; for (var i = 0; i < requestBytes.length; i += 10000) { - lists.add(Uint8List.sublistView( - requestBytes, i, min(i + 10000, requestBytes.length))); + lists.add( + Uint8List.sublistView( + requestBytes, + i, + min(i + 10000, requestBytes.length), + ), + ); } // Time `AsyncMessageGrouper` and deserialization. diff --git a/pkgs/bazel_worker/e2e_test/bin/async_worker_in_isolate.dart b/pkgs/bazel_worker/e2e_test/bin/async_worker_in_isolate.dart index a94875d57..285b03d2a 100644 --- a/pkgs/bazel_worker/e2e_test/bin/async_worker_in_isolate.dart +++ b/pkgs/bazel_worker/e2e_test/bin/async_worker_in_isolate.dart @@ -17,7 +17,10 @@ import 'package:e2e_test/forwards_to_isolate_async_worker.dart'; Future main(List args, [SendPort? message]) async { var receivePort = ReceivePort(); await Isolate.spawnUri( - Uri.file('async_worker.dart'), [], receivePort.sendPort); + Uri.file('async_worker.dart'), + [], + receivePort.sendPort, + ); var worker = await ForwardsToIsolateAsyncWorker.create(receivePort); await worker.run(); diff --git a/pkgs/bazel_worker/e2e_test/lib/async_worker.dart b/pkgs/bazel_worker/e2e_test/lib/async_worker.dart index d48d87c8d..55f517134 100644 --- a/pkgs/bazel_worker/e2e_test/lib/async_worker.dart +++ b/pkgs/bazel_worker/e2e_test/lib/async_worker.dart @@ -16,9 +16,6 @@ class ExampleAsyncWorker extends AsyncWorkerLoop { @override Future performRequest(WorkRequest request) async { - return WorkResponse( - exitCode: 0, - output: request.arguments.join('\n'), - ); + return WorkResponse(exitCode: 0, output: request.arguments.join('\n')); } } diff --git a/pkgs/bazel_worker/e2e_test/lib/forwards_to_isolate_async_worker.dart b/pkgs/bazel_worker/e2e_test/lib/forwards_to_isolate_async_worker.dart index bb937b220..a4845cf9e 100644 --- a/pkgs/bazel_worker/e2e_test/lib/forwards_to_isolate_async_worker.dart +++ b/pkgs/bazel_worker/e2e_test/lib/forwards_to_isolate_async_worker.dart @@ -13,9 +13,11 @@ class ForwardsToIsolateAsyncWorker extends AsyncWorkerLoop { final IsolateDriverConnection _isolateDriverConnection; static Future create( - ReceivePort receivePort) async { + ReceivePort receivePort, + ) async { return ForwardsToIsolateAsyncWorker( - await IsolateDriverConnection.create(receivePort)); + await IsolateDriverConnection.create(receivePort), + ); } ForwardsToIsolateAsyncWorker(this._isolateDriverConnection); diff --git a/pkgs/bazel_worker/e2e_test/pubspec.yaml b/pkgs/bazel_worker/e2e_test/pubspec.yaml index 56f00cd4c..7eaa89a16 100644 --- a/pkgs/bazel_worker/e2e_test/pubspec.yaml +++ b/pkgs/bazel_worker/e2e_test/pubspec.yaml @@ -10,6 +10,6 @@ dependencies: dev_dependencies: cli_util: ^0.4.2 - dart_flutter_team_lints: ^1.0.0 + dart_flutter_team_lints: ^3.0.0 path: ^1.8.0 test: ^1.16.0 diff --git a/pkgs/bazel_worker/e2e_test/test/e2e_test.dart b/pkgs/bazel_worker/e2e_test/test/e2e_test.dart index caa813a46..6b79b5edb 100644 --- a/pkgs/bazel_worker/e2e_test/test/e2e_test.dart +++ b/pkgs/bazel_worker/e2e_test/test/e2e_test.dart @@ -12,14 +12,18 @@ import 'package:test/test.dart'; void main() { var dart = p.join(sdkPath, 'bin', 'dart'); - runE2eTestForWorker('sync worker', - () => Process.start(dart, [p.join('bin', 'sync_worker.dart')])); - runE2eTestForWorker('async worker', - () => Process.start(dart, [p.join('bin', 'async_worker.dart')])); runE2eTestForWorker( - 'async worker in isolate', - () => - Process.start(dart, [p.join('bin', 'async_worker_in_isolate.dart')])); + 'sync worker', + () => Process.start(dart, [p.join('bin', 'sync_worker.dart')]), + ); + runE2eTestForWorker( + 'async worker', + () => Process.start(dart, [p.join('bin', 'async_worker.dart')]), + ); + runE2eTestForWorker( + 'async worker in isolate', + () => Process.start(dart, [p.join('bin', 'async_worker_in_isolate.dart')]), + ); } void runE2eTestForWorker(String groupName, SpawnWorker spawnWorker) { diff --git a/pkgs/bazel_worker/example/client.dart b/pkgs/bazel_worker/example/client.dart index 7147fcbf0..326bb180b 100644 --- a/pkgs/bazel_worker/example/client.dart +++ b/pkgs/bazel_worker/example/client.dart @@ -5,10 +5,14 @@ import 'package:bazel_worker/driver.dart'; void main() async { var scratchSpace = await Directory.systemTemp.createTemp(); var driver = BazelWorkerDriver( - () => Process.start(Platform.resolvedExecutable, - [Platform.script.resolve('worker.dart').toFilePath()], - workingDirectory: scratchSpace.path), - maxWorkers: 4); + () => Process.start( + Platform.resolvedExecutable, + [ + Platform.script.resolve('worker.dart').toFilePath(), + ], + workingDirectory: scratchSpace.path), + maxWorkers: 4, + ); var response = await driver.doWork(WorkRequest(arguments: ['foo'])); if (response.exitCode != EXIT_CODE_OK) { print('Worker request failed'); diff --git a/pkgs/bazel_worker/lib/src/async_message_grouper.dart b/pkgs/bazel_worker/lib/src/async_message_grouper.dart index e1f0deaef..8fc47780a 100644 --- a/pkgs/bazel_worker/lib/src/async_message_grouper.dart +++ b/pkgs/bazel_worker/lib/src/async_message_grouper.dart @@ -86,13 +86,18 @@ class AsyncMessageGrouper implements MessageGrouper { // Copy as much as possible from the input buffer. Limit is the // smaller of the remaining length to fill in the message and the // remaining length in the buffer. - var lengthToCopy = min(_message.length - _messagePos, - _inputBuffer.length - _inputBufferPos); + var lengthToCopy = min( + _message.length - _messagePos, + _inputBuffer.length - _inputBufferPos, + ); _message.setRange( - _messagePos, - _messagePos + lengthToCopy, - _inputBuffer.sublist( - _inputBufferPos, _inputBufferPos + lengthToCopy)); + _messagePos, + _messagePos + lengthToCopy, + _inputBuffer.sublist( + _inputBufferPos, + _inputBufferPos + lengthToCopy, + ), + ); _messagePos += lengthToCopy; _inputBufferPos += lengthToCopy; diff --git a/pkgs/bazel_worker/lib/src/driver/driver.dart b/pkgs/bazel_worker/lib/src/driver/driver.dart index 4a780208a..06cf0feb1 100644 --- a/pkgs/bazel_worker/lib/src/driver/driver.dart +++ b/pkgs/bazel_worker/lib/src/driver/driver.dart @@ -44,9 +44,12 @@ class BazelWorkerDriver { /// Factory method that spawns a worker process. final SpawnWorker _spawnWorker; - BazelWorkerDriver(this._spawnWorker, - {int? maxIdleWorkers, int? maxWorkers, int? maxRetries}) - : _maxIdleWorkers = maxIdleWorkers ?? 4, + BazelWorkerDriver( + this._spawnWorker, { + int? maxIdleWorkers, + int? maxWorkers, + int? maxRetries, + }) : _maxIdleWorkers = maxIdleWorkers ?? 4, _maxWorkers = maxWorkers ?? 4, _maxRetries = maxRetries ?? 4; @@ -56,8 +59,10 @@ class BazelWorkerDriver { /// [request] has been actually sent to the worker. This allows the caller /// to determine when actual work is being done versus just waiting for an /// available worker. - Future doWork(WorkRequest request, - {void Function(Future)? trackWork}) { + Future doWork( + WorkRequest request, { + void Function(Future)? trackWork, + }) { var attempt = _WorkAttempt(request, trackWork: trackWork); _workQueue.add(attempt); _runWorkQueue(); @@ -69,9 +74,11 @@ class BazelWorkerDriver { for (var worker in _readyWorkers.toList()) { _killWorker(worker); } - await Future.wait(_spawningWorkers.map((worker) async { - _killWorker(await worker); - })); + await Future.wait( + _spawningWorkers.map((worker) async { + _killWorker(await worker); + }), + ); } /// Runs as many items in [_workQueue] as possible given the number of @@ -88,8 +95,10 @@ class BazelWorkerDriver { if (_workQueue.isEmpty) return; if (_numWorkers == _maxWorkers && _idleWorkers.isEmpty) return; if (_numWorkers > _maxWorkers) { - throw StateError('Internal error, created to many workers. Please ' - 'file a bug at https://github.com/dart-lang/bazel_worker/issues/new'); + throw StateError( + 'Internal error, created to many workers. Please ' + 'file a bug at https://github.com/dart-lang/bazel_worker/issues/new', + ); } // At this point we definitely want to run a task, we just need to decide @@ -137,48 +146,51 @@ class BazelWorkerDriver { void _runWorker(Process worker, _WorkAttempt attempt) { var rescheduled = false; - runZonedGuarded(() async { - var connection = _workerConnections[worker]!; + runZonedGuarded( + () async { + var connection = _workerConnections[worker]!; - connection.writeRequest(attempt.request); - var responseFuture = connection.readResponse(); - if (attempt.trackWork != null) { - attempt.trackWork!(responseFuture); - } - var response = await responseFuture; - - // It is possible for us to complete with an error response due to an - // unhandled async error before we get here. - if (!attempt.responseCompleter.isCompleted) { - if (response.exitCode == EXIT_CODE_BROKEN_PIPE) { + connection.writeRequest(attempt.request); + var responseFuture = connection.readResponse(); + if (attempt.trackWork != null) { + attempt.trackWork!(responseFuture); + } + var response = await responseFuture; + + // It is possible for us to complete with an error response due to an + // unhandled async error before we get here. + if (!attempt.responseCompleter.isCompleted) { + if (response.exitCode == EXIT_CODE_BROKEN_PIPE) { + rescheduled = _tryReschedule(attempt); + if (rescheduled) return; + stderr.writeln('Failed to run request ${attempt.request}'); + response = WorkResponse( + exitCode: EXIT_CODE_ERROR, + output: + 'Invalid response from worker, this probably means it wrote ' + 'invalid output or died.', + ); + } + attempt.responseCompleter.complete(response); + _cleanUp(worker); + } + }, + (e, s) { + // Note that we don't need to do additional cleanup here on failures. If + // the worker dies that is already handled in a generic fashion, we just + // need to make sure we complete with a valid response. + if (!attempt.responseCompleter.isCompleted) { rescheduled = _tryReschedule(attempt); if (rescheduled) return; - stderr.writeln('Failed to run request ${attempt.request}'); - response = WorkResponse( + var response = WorkResponse( exitCode: EXIT_CODE_ERROR, - output: - 'Invalid response from worker, this probably means it wrote ' - 'invalid output or died.', + output: 'Error running worker:\n$e\n$s', ); + attempt.responseCompleter.complete(response); + _cleanUp(worker); } - attempt.responseCompleter.complete(response); - _cleanUp(worker); - } - }, (e, s) { - // Note that we don't need to do additional cleanup here on failures. If - // the worker dies that is already handled in a generic fashion, we just - // need to make sure we complete with a valid response. - if (!attempt.responseCompleter.isCompleted) { - rescheduled = _tryReschedule(attempt); - if (rescheduled) return; - var response = WorkResponse( - exitCode: EXIT_CODE_ERROR, - output: 'Error running worker:\n$e\n$s', - ); - attempt.responseCompleter.complete(response); - _cleanUp(worker); - } - }); + }, + ); } /// Performs post-work cleanup for [worker]. diff --git a/pkgs/bazel_worker/lib/src/driver/driver_connection.dart b/pkgs/bazel_worker/lib/src/driver/driver_connection.dart index b419debbc..80d5c98cf 100644 --- a/pkgs/bazel_worker/lib/src/driver/driver_connection.dart +++ b/pkgs/bazel_worker/lib/src/driver/driver_connection.dart @@ -34,13 +34,16 @@ class StdDriverConnection implements DriverConnection { Future get done => _messageGrouper.done; - StdDriverConnection( - {Stream>? inputStream, StreamSink>? outputStream}) - : _messageGrouper = AsyncMessageGrouper(inputStream ?? stdin), + StdDriverConnection({ + Stream>? inputStream, + StreamSink>? outputStream, + }) : _messageGrouper = AsyncMessageGrouper(inputStream ?? stdin), _outputStream = outputStream ?? stdout; factory StdDriverConnection.forWorker(Process worker) => StdDriverConnection( - inputStream: worker.stdout, outputStream: worker.stdin); + inputStream: worker.stdout, + outputStream: worker.stdin, + ); /// Note: This will attempts to recover from invalid proto messages by parsing /// them as strings. This is a common error case for workers (they print a diff --git a/pkgs/bazel_worker/lib/src/utils.dart b/pkgs/bazel_worker/lib/src/utils.dart index 609b4356a..f67bbac1e 100644 --- a/pkgs/bazel_worker/lib/src/utils.dart +++ b/pkgs/bazel_worker/lib/src/utils.dart @@ -13,8 +13,9 @@ List protoToDelimitedBuffer(GeneratedMessage message) { var delimiterBuffer = CodedBufferWriter(); delimiterBuffer.writeInt32NoTag(messageBuffer.lengthInBytes); - var result = - Uint8List(messageBuffer.lengthInBytes + delimiterBuffer.lengthInBytes); + var result = Uint8List( + messageBuffer.lengthInBytes + delimiterBuffer.lengthInBytes, + ); delimiterBuffer.writeTo(result); messageBuffer.writeTo(result, delimiterBuffer.lengthInBytes); diff --git a/pkgs/bazel_worker/lib/src/worker/async_worker_loop.dart b/pkgs/bazel_worker/lib/src/worker/async_worker_loop.dart index 5182b5598..a95d09a1f 100644 --- a/pkgs/bazel_worker/lib/src/worker/async_worker_loop.dart +++ b/pkgs/bazel_worker/lib/src/worker/async_worker_loop.dart @@ -32,20 +32,20 @@ abstract class AsyncWorkerLoop implements WorkerLoop { var request = await connection.readRequest(); if (request == null) break; var printMessages = StringBuffer(); - response = await runZoned(() => performRequest(request), - zoneSpecification: - ZoneSpecification(print: (self, parent, zone, message) { - printMessages.writeln(); - printMessages.write(message); - })); + response = await runZoned( + () => performRequest(request), + zoneSpecification: ZoneSpecification( + print: (self, parent, zone, message) { + printMessages.writeln(); + printMessages.write(message); + }, + ), + ); if (printMessages.isNotEmpty) { response.output = '${response.output}$printMessages'; } } catch (e, s) { - response = WorkResponse( - exitCode: EXIT_CODE_ERROR, - output: '$e\n$s', - ); + response = WorkResponse(exitCode: EXIT_CODE_ERROR, output: '$e\n$s'); } connection.writeResponse(response); diff --git a/pkgs/bazel_worker/lib/src/worker/sync_worker_loop.dart b/pkgs/bazel_worker/lib/src/worker/sync_worker_loop.dart index a8571058c..51da684ab 100644 --- a/pkgs/bazel_worker/lib/src/worker/sync_worker_loop.dart +++ b/pkgs/bazel_worker/lib/src/worker/sync_worker_loop.dart @@ -30,19 +30,20 @@ abstract class SyncWorkerLoop implements WorkerLoop { var request = connection.readRequest(); if (request == null) break; var printMessages = StringBuffer(); - response = runZoned(() => performRequest(request), zoneSpecification: - ZoneSpecification(print: (self, parent, zone, message) { - printMessages.writeln(); - printMessages.write(message); - })); + response = runZoned( + () => performRequest(request), + zoneSpecification: ZoneSpecification( + print: (self, parent, zone, message) { + printMessages.writeln(); + printMessages.write(message); + }, + ), + ); if (printMessages.isNotEmpty) { response.output = '${response.output}$printMessages'; } } catch (e, s) { - response = WorkResponse( - exitCode: EXIT_CODE_ERROR, - output: '$e\n$s', - ); + response = WorkResponse(exitCode: EXIT_CODE_ERROR, output: '$e\n$s'); } connection.writeResponse(response); diff --git a/pkgs/bazel_worker/lib/src/worker/worker_connection.dart b/pkgs/bazel_worker/lib/src/worker/worker_connection.dart index b395316a3..fd5508e4a 100644 --- a/pkgs/bazel_worker/lib/src/worker/worker_connection.dart +++ b/pkgs/bazel_worker/lib/src/worker/worker_connection.dart @@ -29,13 +29,16 @@ abstract class AsyncWorkerConnection implements WorkerConnection { /// Creates a [StdAsyncWorkerConnection] with the specified [inputStream] /// and [outputStream], unless [sendPort] is specified, in which case /// creates a [SendPortAsyncWorkerConnection]. - factory AsyncWorkerConnection( - {Stream>? inputStream, - StreamSink>? outputStream, - SendPort? sendPort}) => + factory AsyncWorkerConnection({ + Stream>? inputStream, + StreamSink>? outputStream, + SendPort? sendPort, + }) => sendPort == null ? StdAsyncWorkerConnection( - inputStream: inputStream, outputStream: outputStream) + inputStream: inputStream, + outputStream: outputStream, + ) : SendPortAsyncWorkerConnection(sendPort); @override @@ -53,9 +56,10 @@ class StdAsyncWorkerConnection implements AsyncWorkerConnection { final AsyncMessageGrouper _messageGrouper; final StreamSink> _outputStream; - StdAsyncWorkerConnection( - {Stream>? inputStream, StreamSink>? outputStream}) - : _messageGrouper = AsyncMessageGrouper(inputStream ?? stdin), + StdAsyncWorkerConnection({ + Stream>? inputStream, + StreamSink>? outputStream, + }) : _messageGrouper = AsyncMessageGrouper(inputStream ?? stdin), _outputStream = outputStream ?? stdout; @override diff --git a/pkgs/bazel_worker/lib/testing.dart b/pkgs/bazel_worker/lib/testing.dart index 3ae4c1f4d..7aefabbd8 100644 --- a/pkgs/bazel_worker/lib/testing.dart +++ b/pkgs/bazel_worker/lib/testing.dart @@ -72,10 +72,18 @@ class TestStdinAsync implements TestStdin { } @override - StreamSubscription listen(void Function(Uint8List bytes)? onData, - {Function? onError, void Function()? onDone, bool? cancelOnError}) { - return _controller.stream.listen(onData, - onError: onError, onDone: onDone, cancelOnError: cancelOnError); + StreamSubscription listen( + void Function(Uint8List bytes)? onData, { + Function? onError, + void Function()? onDone, + bool? cancelOnError, + }) { + return _controller.stream.listen( + onData, + onError: onError, + onDone: onDone, + cancelOnError: cancelOnError, + ); } @override @@ -165,8 +173,9 @@ class TestAsyncWorkerConnection extends StdAsyncWorkerConnection final List responses = []; TestAsyncWorkerConnection( - Stream> inputStream, StreamSink> outputStream) - : super(inputStream: inputStream, outputStream: outputStream); + Stream> inputStream, + StreamSink> outputStream, + ) : super(inputStream: inputStream, outputStream: outputStream); @override void writeResponse(WorkResponse response) { diff --git a/pkgs/bazel_worker/test/driver_test.dart b/pkgs/bazel_worker/test/driver_test.dart index c3978304e..c3db55c66 100644 --- a/pkgs/bazel_worker/test/driver_test.dart +++ b/pkgs/bazel_worker/test/driver_test.dart @@ -23,27 +23,37 @@ void main() { await _doRequests(count: 1); }); - test('can run multiple batches of requests through multiple workers', - () async { - var maxWorkers = 4; - var maxIdleWorkers = 2; - driver = BazelWorkerDriver(MockWorker.spawn, - maxWorkers: maxWorkers, maxIdleWorkers: maxIdleWorkers); - for (var i = 0; i < 10; i++) { - await _doRequests(driver: driver); - expect(MockWorker.liveWorkers.length, maxIdleWorkers); - // No workers should be killed while there is ongoing work, but they - // should be cleaned up once there isn't any more work to do. - expect(MockWorker.deadWorkers.length, - (maxWorkers - maxIdleWorkers) * (i + 1)); - } - }); + test( + 'can run multiple batches of requests through multiple workers', + () async { + var maxWorkers = 4; + var maxIdleWorkers = 2; + driver = BazelWorkerDriver( + MockWorker.spawn, + maxWorkers: maxWorkers, + maxIdleWorkers: maxIdleWorkers, + ); + for (var i = 0; i < 10; i++) { + await _doRequests(driver: driver); + expect(MockWorker.liveWorkers.length, maxIdleWorkers); + // No workers should be killed while there is ongoing work, but they + // should be cleaned up once there isn't any more work to do. + expect( + MockWorker.deadWorkers.length, + (maxWorkers - maxIdleWorkers) * (i + 1), + ); + } + }, + ); test('can run multiple requests through one worker', () async { var maxWorkers = 1; var maxIdleWorkers = 1; - driver = BazelWorkerDriver(MockWorker.spawn, - maxWorkers: maxWorkers, maxIdleWorkers: maxIdleWorkers); + driver = BazelWorkerDriver( + MockWorker.spawn, + maxWorkers: maxWorkers, + maxIdleWorkers: maxIdleWorkers, + ); for (var i = 0; i < 10; i++) { await _doRequests(driver: driver); expect(MockWorker.liveWorkers.length, 1); @@ -52,8 +62,11 @@ void main() { }); test('can run one request through multiple workers', () async { - driver = - BazelWorkerDriver(MockWorker.spawn, maxWorkers: 4, maxIdleWorkers: 4); + driver = BazelWorkerDriver( + MockWorker.spawn, + maxWorkers: 4, + maxIdleWorkers: 4, + ); for (var i = 0; i < 10; i++) { await _doRequests(driver: driver, count: 1); expect(MockWorker.liveWorkers.length, 1); @@ -63,8 +76,11 @@ void main() { test('can run with maxIdleWorkers == 0', () async { var maxWorkers = 4; - driver = BazelWorkerDriver(MockWorker.spawn, - maxWorkers: maxWorkers, maxIdleWorkers: 0); + driver = BazelWorkerDriver( + MockWorker.spawn, + maxWorkers: maxWorkers, + maxIdleWorkers: 0, + ); for (var i = 0; i < 10; i++) { await _doRequests(driver: driver); expect(MockWorker.liveWorkers.length, 0); @@ -77,14 +93,15 @@ void main() { driver = BazelWorkerDriver(MockWorker.spawn, maxWorkers: maxWorkers); var tracking = []; await _doRequests( - driver: driver, - count: 10, - trackWork: (Future response) { - // We should never be tracking more than `maxWorkers` jobs at a time. - expect(tracking.length, lessThan(maxWorkers)); - tracking.add(response); - response.then((_) => tracking.remove(response)); - }); + driver: driver, + count: 10, + trackWork: (Future response) { + // We should never be tracking more than `maxWorkers` jobs at a time. + expect(tracking.length, lessThan(maxWorkers)); + tracking.add(response); + response.then((_) => tracking.remove(response)); + }, + ); }); group('failing workers', () { @@ -93,27 +110,39 @@ void main() { void createDriver({int maxRetries = 2, int numBadWorkers = 2}) { var numSpawned = 0; driver = BazelWorkerDriver( - () async => MockWorker(workerLoopFactory: (MockWorker worker) { - var connection = StdAsyncWorkerConnection( - inputStream: worker._stdinController.stream, - outputStream: worker._stdoutController.sink); - if (numSpawned < numBadWorkers) { - numSpawned++; - return ThrowingMockWorkerLoop( - worker, MockWorker.responseQueue, connection); - } else { - return MockWorkerLoop(MockWorker.responseQueue, - connection: connection); - } - }), - maxRetries: maxRetries); + () async => MockWorker( + workerLoopFactory: (MockWorker worker) { + var connection = StdAsyncWorkerConnection( + inputStream: worker._stdinController.stream, + outputStream: worker._stdoutController.sink, + ); + if (numSpawned < numBadWorkers) { + numSpawned++; + return ThrowingMockWorkerLoop( + worker, + MockWorker.responseQueue, + connection, + ); + } else { + return MockWorkerLoop( + MockWorker.responseQueue, + connection: connection, + ); + } + }, + ), + maxRetries: maxRetries, + ); } test('should retry up to maxRetries times', () async { createDriver(); var expectedResponse = WorkResponse(); - MockWorker.responseQueue.addAll( - [disconnectedResponse, disconnectedResponse, expectedResponse]); + MockWorker.responseQueue.addAll([ + disconnectedResponse, + disconnectedResponse, + expectedResponse, + ]); var actualResponse = await driver!.doWork(WorkRequest()); // The first 2 null responses are thrown away, and we should get the // third one. @@ -125,23 +154,29 @@ void main() { test('should fail if it exceeds maxRetries failures', () async { createDriver(maxRetries: 2, numBadWorkers: 3); - MockWorker.responseQueue.addAll( - [disconnectedResponse, disconnectedResponse, WorkResponse()]); + MockWorker.responseQueue.addAll([ + disconnectedResponse, + disconnectedResponse, + WorkResponse(), + ]); var actualResponse = await driver!.doWork(WorkRequest()); // Should actually get a bad response. expect(actualResponse.exitCode, 15); expect( - actualResponse.output, - 'Invalid response from worker, this probably means it wrote ' - 'invalid output or died.'); + actualResponse.output, + 'Invalid response from worker, this probably means it wrote ' + 'invalid output or died.', + ); expect(MockWorker.deadWorkers.length, 3); }); }); test('handles spawnWorker failures', () async { - driver = BazelWorkerDriver(() async => throw StateError('oh no!'), - maxRetries: 0); + driver = BazelWorkerDriver( + () async => throw StateError('oh no!'), + maxRetries: 0, + ); expect(driver!.doWork(WorkRequest()), throwsA(isA())); }); @@ -156,10 +191,11 @@ void main() { /// Runs [count] of fake work requests through [driver], and asserts that they /// all completed. -Future _doRequests( - {BazelWorkerDriver? driver, - int count = 100, - void Function(Future)? trackWork}) async { +Future _doRequests({ + BazelWorkerDriver? driver, + int count = 100, + void Function(Future)? trackWork, +}) async { // If we create a driver, we need to make sure and terminate it. var terminateDriver = driver == null; driver ??= BazelWorkerDriver(MockWorker.spawn); @@ -167,7 +203,8 @@ Future _doRequests( var responses = List.generate(count, (_) => WorkResponse()); MockWorker.responseQueue.addAll(responses); var actualResponses = await Future.wait( - requests.map((request) => driver!.doWork(request, trackWork: trackWork))); + requests.map((request) => driver!.doWork(request, trackWork: trackWork)), + ); expect(actualResponses, unorderedEquals(responses)); if (terminateDriver) await driver.terminateWorkers(); } @@ -191,9 +228,11 @@ class MockWorkerLoop extends AsyncWorkerLoop { class ThrowingMockWorkerLoop extends MockWorkerLoop { final MockWorker _mockWorker; - ThrowingMockWorkerLoop(this._mockWorker, Queue responseQueue, - AsyncWorkerConnection connection) - : super(responseQueue, connection: connection); + ThrowingMockWorkerLoop( + this._mockWorker, + Queue responseQueue, + AsyncWorkerConnection connection, + ) : super(responseQueue, connection: connection); /// Run the worker loop. The returned [Future] doesn't complete until /// [connection#readRequest] returns `null`. @@ -234,10 +273,13 @@ class MockWorker implements Process { liveWorkers.add(this); var workerLoop = workerLoopFactory != null ? workerLoopFactory(this) - : MockWorkerLoop(responseQueue, + : MockWorkerLoop( + responseQueue, connection: StdAsyncWorkerConnection( - inputStream: _stdinController.stream, - outputStream: _stdoutController.sink)); + inputStream: _stdinController.stream, + outputStream: _stdoutController.sink, + ), + ); workerLoop.run(); } @@ -260,8 +302,10 @@ class MockWorker implements Process { int get pid => throw UnsupportedError('Not needed.'); @override - bool kill( - [ProcessSignal processSignal = ProcessSignal.sigterm, int exitCode = 0]) { + bool kill([ + ProcessSignal processSignal = ProcessSignal.sigterm, + int exitCode = 0, + ]) { if (_killed) return false; () async { await _stdoutController.close(); diff --git a/pkgs/bazel_worker/test/message_grouper_test.dart b/pkgs/bazel_worker/test/message_grouper_test.dart index 475190ed8..fd99911d1 100644 --- a/pkgs/bazel_worker/test/message_grouper_test.dart +++ b/pkgs/bazel_worker/test/message_grouper_test.dart @@ -18,8 +18,10 @@ void main() { }); } -void runTests(TestStdin Function() stdinFactory, - MessageGrouper Function(Stdin) messageGrouperFactory) { +void runTests( + TestStdin Function() stdinFactory, + MessageGrouper Function(Stdin) messageGrouperFactory, +) { late MessageGrouper messageGrouper; late TestStdin stdinStream; @@ -52,16 +54,12 @@ void runTests(TestStdin Function() stdinFactory, }); test('Short message', () async { - await check([ - 5, - 10, - 20, - 30, - 40, - 50 - ], [ - [10, 20, 30, 40, 50] - ]); + await check( + [5, 10, 20, 30, 40, 50], + [ + [10, 20, 30, 40, 50], + ], + ); }); test('Message with 2-byte length', () async { @@ -79,57 +77,44 @@ void runTests(TestStdin Function() stdinFactory, }); test('Multiple messages', () async { - await check([ - 2, - 10, - 20, - 2, - 30, - 40 - ], [ - [10, 20], - [30, 40] - ]); + await check( + [2, 10, 20, 2, 30, 40], + [ + [10, 20], + [30, 40], + ], + ); }); test('Empty message at start', () async { - await check([ - 0, - 2, - 10, - 20 - ], [ - [], - [10, 20] - ]); + await check( + [0, 2, 10, 20], + [ + [], + [10, 20], + ], + ); }); test('Empty message at end', () async { - await check([ - 2, - 10, - 20, - 0 - ], [ - [10, 20], - [] - ]); + await check( + [2, 10, 20, 0], + [ + [10, 20], + [], + ], + ); }); test('Empty message in the middle', () async { - await check([ - 2, - 10, - 20, - 0, - 2, - 30, - 40 - ], [ - [10, 20], - [], - [30, 40] - ]); + await check( + [2, 10, 20, 0, 2, 30, 40], + [ + [10, 20], + [], + [30, 40], + ], + ); }); test('Handles the case when stdin gives an error instead of EOF', () async { diff --git a/pkgs/bazel_worker/test/worker_loop_test.dart b/pkgs/bazel_worker/test/worker_loop_test.dart index 50d21512e..24068b1d8 100644 --- a/pkgs/bazel_worker/test/worker_loop_test.dart +++ b/pkgs/bazel_worker/test/worker_loop_test.dart @@ -11,36 +11,45 @@ import 'package:test/test.dart'; void main() { group('SyncWorkerLoop', () { - runTests(TestStdinSync.new, TestSyncWorkerConnection.new, - TestSyncWorkerLoop.new); + runTests( + TestStdinSync.new, + TestSyncWorkerConnection.new, + TestSyncWorkerLoop.new, + ); }); group('AsyncWorkerLoop', () { - runTests(TestStdinAsync.new, TestAsyncWorkerConnection.new, - TestAsyncWorkerLoop.new); + runTests( + TestStdinAsync.new, + TestAsyncWorkerConnection.new, + TestAsyncWorkerLoop.new, + ); }); group('SyncWorkerLoopWithPrint', () { runTests( - TestStdinSync.new, - TestSyncWorkerConnection.new, - (TestSyncWorkerConnection connection) => - TestSyncWorkerLoop(connection, printMessage: 'Goodbye!')); + TestStdinSync.new, + TestSyncWorkerConnection.new, + (TestSyncWorkerConnection connection) => + TestSyncWorkerLoop(connection, printMessage: 'Goodbye!'), + ); }); group('AsyncWorkerLoopWithPrint', () { runTests( - TestStdinAsync.new, - TestAsyncWorkerConnection.new, - (TestAsyncWorkerConnection connection) => - TestAsyncWorkerLoop(connection, printMessage: 'Goodbye!')); + TestStdinAsync.new, + TestAsyncWorkerConnection.new, + (TestAsyncWorkerConnection connection) => + TestAsyncWorkerLoop(connection, printMessage: 'Goodbye!'), + ); }); } void runTests( - TestStdin Function() stdinFactory, - T Function(Stdin, Stdout) workerConnectionFactory, - TestWorkerLoop Function(T) workerLoopFactory) { + TestStdin Function() stdinFactory, + T Function(Stdin, Stdout) workerConnectionFactory, + TestWorkerLoop Function(T) workerLoopFactory, +) { late TestStdin stdinStream; late TestStdoutStream stdoutStream; late T connection; @@ -63,19 +72,29 @@ void runTests( // Make sure `print` never gets called in the parent zone. var printMessages = []; - await runZoned(() => workerLoop.run(), zoneSpecification: - ZoneSpecification(print: (self, parent, zone, message) { - printMessages.add(message); - })); - expect(printMessages, isEmpty, - reason: 'The worker loop should hide all print calls from the parent ' - 'zone.'); + await runZoned( + () => workerLoop.run(), + zoneSpecification: ZoneSpecification( + print: (self, parent, zone, message) { + printMessages.add(message); + }, + ), + ); + expect( + printMessages, + isEmpty, + reason: 'The worker loop should hide all print calls from the parent ' + 'zone.', + ); expect(connection.responses, hasLength(1)); expect(connection.responses[0], response); if (workerLoop.printMessage != null) { - expect(response.output, endsWith(workerLoop.printMessage!), - reason: 'Print messages should get appended to the response output.'); + expect( + response.output, + endsWith(workerLoop.printMessage!), + reason: 'Print messages should get appended to the response output.', + ); } // Check that a serialized version was written to std out. diff --git a/pkgs/clock/analysis_options.yaml b/pkgs/clock/analysis_options.yaml index 9ee7c2b6a..db6072da7 100644 --- a/pkgs/clock/analysis_options.yaml +++ b/pkgs/clock/analysis_options.yaml @@ -11,4 +11,3 @@ linter: rules: - avoid_private_typedef_functions - avoid_redundant_argument_values - - use_super_parameters diff --git a/pkgs/coverage/analysis_options.yaml b/pkgs/coverage/analysis_options.yaml index 82ce5e0a5..bb1afe05a 100644 --- a/pkgs/coverage/analysis_options.yaml +++ b/pkgs/coverage/analysis_options.yaml @@ -9,14 +9,9 @@ analyzer: linter: rules: - - always_declare_return_types - avoid_slow_async_io - cancel_subscriptions - - comment_references - literal_only_boolean_expressions - prefer_final_locals - sort_constructors_first - sort_unnamed_constructors_first - - test_types_in_equals - - throw_in_finally - - type_annotate_public_apis diff --git a/pkgs/file/CHANGELOG.md b/pkgs/file/CHANGELOG.md index 50c96c49d..3a3969cad 100644 --- a/pkgs/file/CHANGELOG.md +++ b/pkgs/file/CHANGELOG.md @@ -1,3 +1,5 @@ +## 7.0.2-wip + ## 7.0.1 * Update the pubspec repository field to reflect the new package repository. diff --git a/pkgs/file/analysis_options.yaml b/pkgs/file/analysis_options.yaml index 8fbd2e443..d978f811c 100644 --- a/pkgs/file/analysis_options.yaml +++ b/pkgs/file/analysis_options.yaml @@ -1,6 +1 @@ -include: package:lints/recommended.yaml - -analyzer: - errors: - # Allow having TODOs in the code - todo: ignore +include: package:dart_flutter_team_lints/analysis_options.yaml diff --git a/pkgs/file/example/main.dart b/pkgs/file/example/main.dart index 7ca0bc73f..b03b363f0 100644 --- a/pkgs/file/example/main.dart +++ b/pkgs/file/example/main.dart @@ -7,8 +7,8 @@ import 'package:file/memory.dart'; Future main() async { final FileSystem fs = MemoryFileSystem(); - final Directory tmp = await fs.systemTempDirectory.createTemp('example_'); - final File outputFile = tmp.childFile('output'); + final tmp = await fs.systemTempDirectory.createTemp('example_'); + final outputFile = tmp.childFile('output'); await outputFile.writeAsString('Hello world!'); print(outputFile.readAsStringSync()); } diff --git a/pkgs/file/lib/chroot.dart b/pkgs/file/lib/chroot.dart index 56d2bd5d7..6992ad0b4 100644 --- a/pkgs/file/lib/chroot.dart +++ b/pkgs/file/lib/chroot.dart @@ -3,4 +3,6 @@ // BSD-style license that can be found in the LICENSE file. /// A file system that provides a view into _another_ `FileSystem` via a path. +library; + export 'src/backends/chroot.dart'; diff --git a/pkgs/file/lib/file.dart b/pkgs/file/lib/file.dart index cdde9fedd..c2e97b2ee 100644 --- a/pkgs/file/lib/file.dart +++ b/pkgs/file/lib/file.dart @@ -4,5 +4,7 @@ /// Core interfaces containing the abstract `FileSystem` interface definition /// and all associated types used by `FileSystem`. +library; + export 'src/forwarding.dart'; export 'src/interface.dart'; diff --git a/pkgs/file/lib/local.dart b/pkgs/file/lib/local.dart index 74f506e36..5b1e3cd9d 100644 --- a/pkgs/file/lib/local.dart +++ b/pkgs/file/lib/local.dart @@ -4,4 +4,6 @@ /// A local file system implementation. This relies on the use of `dart:io` /// and is thus not suitable for use in the browser. +library; + export 'src/backends/local.dart'; diff --git a/pkgs/file/lib/memory.dart b/pkgs/file/lib/memory.dart index c5705eff9..690b65fa5 100644 --- a/pkgs/file/lib/memory.dart +++ b/pkgs/file/lib/memory.dart @@ -4,5 +4,7 @@ /// An implementation of `FileSystem` that exists entirely in memory with an /// internal representation loosely based on the Filesystem Hierarchy Standard. +library; + export 'src/backends/memory.dart'; export 'src/backends/memory/operations.dart'; diff --git a/pkgs/file/lib/src/backends/chroot.dart b/pkgs/file/lib/src/backends/chroot.dart index 6082e808c..402dbec5b 100644 --- a/pkgs/file/lib/src/backends/chroot.dart +++ b/pkgs/file/lib/src/backends/chroot.dart @@ -2,16 +2,16 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. -library file.src.backends.chroot; - import 'dart:convert'; import 'dart:typed_data'; -import 'package:file/file.dart'; -import 'package:file/src/common.dart' as common; -import 'package:file/src/io.dart' as io; import 'package:path/path.dart' as p; +import '../common.dart' as common; +import '../forwarding.dart'; +import '../interface.dart'; +import '../io.dart' as io; + part 'chroot/chroot_directory.dart'; part 'chroot/chroot_file.dart'; part 'chroot/chroot_file_system.dart'; diff --git a/pkgs/file/lib/src/backends/chroot/chroot_directory.dart b/pkgs/file/lib/src/backends/chroot/chroot_directory.dart index 8fec7b198..e09419384 100644 --- a/pkgs/file/lib/src/backends/chroot/chroot_directory.dart +++ b/pkgs/file/lib/src/backends/chroot/chroot_directory.dart @@ -2,18 +2,18 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. -part of file.src.backends.chroot; +part of '../chroot.dart'; class _ChrootDirectory extends _ChrootFileSystemEntity with ForwardingDirectory, common.DirectoryAddOnsMixin { - _ChrootDirectory(ChrootFileSystem fs, String path) : super(fs, path); + _ChrootDirectory(super.fs, super.path); factory _ChrootDirectory.wrapped( ChrootFileSystem fs, Directory delegate, { bool relative = false, }) { - String localPath = fs._local(delegate.path, relative: relative); + var localPath = fs._local(delegate.path, relative: relative); return _ChrootDirectory(fs, localPath); } @@ -32,7 +32,7 @@ class _ChrootDirectory extends _ChrootFileSystemEntity if (await fileSystem.type(path) != expectedType) { throw common.notADirectory(path); } - FileSystemEntityType type = await fileSystem.type(newPath); + var type = await fileSystem.type(newPath); if (type != FileSystemEntityType.notFound) { if (type != expectedType) { throw common.notADirectory(newPath); @@ -44,7 +44,7 @@ class _ChrootDirectory extends _ChrootFileSystemEntity throw common.directoryNotEmpty(newPath); } } - String target = await fileSystem.link(path).target(); + var target = await fileSystem.link(path).target(); await fileSystem.link(path).delete(); await fileSystem.link(newPath).create(target); return fileSystem.directory(newPath); @@ -60,7 +60,7 @@ class _ChrootDirectory extends _ChrootFileSystemEntity if (fileSystem.typeSync(path) != expectedType) { throw common.notADirectory(path); } - FileSystemEntityType type = fileSystem.typeSync(newPath); + var type = fileSystem.typeSync(newPath); if (type != FileSystemEntityType.notFound) { if (type != expectedType) { throw common.notADirectory(newPath); @@ -72,7 +72,7 @@ class _ChrootDirectory extends _ChrootFileSystemEntity throw common.directoryNotEmpty(newPath); } } - String target = fileSystem.link(path).targetSync(); + var target = fileSystem.link(path).targetSync(); fileSystem.link(path).deleteSync(); fileSystem.link(newPath).createSync(target); return fileSystem.directory(newPath); @@ -97,17 +97,15 @@ class _ChrootDirectory extends _ChrootFileSystemEntity @override Future create({bool recursive = false}) async { if (_isLink) { - switch (await fileSystem.type(path)) { - case FileSystemEntityType.notFound: - throw common.noSuchFileOrDirectory(path); - case FileSystemEntityType.file: - throw common.fileExists(path); - case FileSystemEntityType.directory: + return switch (await fileSystem.type(path)) { + FileSystemEntityType.notFound => + throw common.noSuchFileOrDirectory(path), + FileSystemEntityType.file => throw common.fileExists(path), + FileSystemEntityType.directory => // Nothing to do. - return this; - default: - throw AssertionError(); - } + this, + _ => throw AssertionError() + }; } else { return wrap(await delegate.create(recursive: recursive)); } @@ -137,8 +135,8 @@ class _ChrootDirectory extends _ChrootFileSystemEntity bool recursive = false, bool followLinks = true, }) { - Directory delegate = this.delegate as Directory; - String dirname = delegate.path; + var delegate = this.delegate as Directory; + var dirname = delegate.path; return delegate .list(recursive: recursive, followLinks: followLinks) .map((io.FileSystemEntity entity) => _denormalize(entity, dirname)); @@ -149,8 +147,8 @@ class _ChrootDirectory extends _ChrootFileSystemEntity bool recursive = false, bool followLinks = true, }) { - Directory delegate = this.delegate as Directory; - String dirname = delegate.path; + var delegate = this.delegate as Directory; + var dirname = delegate.path; return delegate .listSync(recursive: recursive, followLinks: followLinks) .map((io.FileSystemEntity entity) => _denormalize(entity, dirname)) @@ -158,9 +156,9 @@ class _ChrootDirectory extends _ChrootFileSystemEntity } FileSystemEntity _denormalize(io.FileSystemEntity entity, String dirname) { - p.Context ctx = fileSystem.path; - String relativePart = ctx.relative(entity.path, from: dirname); - String entityPath = ctx.join(path, relativePart); + var ctx = fileSystem.path; + var relativePart = ctx.relative(entity.path, from: dirname); + var entityPath = ctx.join(path, relativePart); if (entity is io.File) { return _ChrootFile(fileSystem, entityPath); } else if (entity is io.Directory) { diff --git a/pkgs/file/lib/src/backends/chroot/chroot_file.dart b/pkgs/file/lib/src/backends/chroot/chroot_file.dart index 4b67bc1f6..d6c29fcff 100644 --- a/pkgs/file/lib/src/backends/chroot/chroot_file.dart +++ b/pkgs/file/lib/src/backends/chroot/chroot_file.dart @@ -2,20 +2,20 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. -part of file.src.backends.chroot; +part of '../chroot.dart'; typedef _SetupCallback = dynamic Function(); class _ChrootFile extends _ChrootFileSystemEntity with ForwardingFile { - _ChrootFile(ChrootFileSystem fs, String path) : super(fs, path); + _ChrootFile(super.fs, super.path); factory _ChrootFile.wrapped( ChrootFileSystem fs, io.File delegate, { bool relative = false, }) { - String localPath = fs._local(delegate.path, relative: relative); + var localPath = fs._local(delegate.path, relative: relative); return _ChrootFile(fs, localPath); } @@ -126,7 +126,7 @@ class _ChrootFile extends _ChrootFileSystemEntity @override Future create({bool recursive = false, bool exclusive = false}) async { - String path = fileSystem._resolve( + var path = fileSystem._resolve( this.path, followLinks: false, notFound: recursive ? _NotFoundBehavior.mkdir : _NotFoundBehavior.allow, @@ -158,7 +158,7 @@ class _ChrootFile extends _ChrootFileSystemEntity @override void createSync({bool recursive = false, bool exclusive = false}) { - String path = fileSystem._resolve( + var path = fileSystem._resolve( this.path, followLinks: false, notFound: recursive ? _NotFoundBehavior.mkdir : _NotFoundBehavior.allow, diff --git a/pkgs/file/lib/src/backends/chroot/chroot_file_system.dart b/pkgs/file/lib/src/backends/chroot/chroot_file_system.dart index 6889c987b..503821fb4 100644 --- a/pkgs/file/lib/src/backends/chroot/chroot_file_system.dart +++ b/pkgs/file/lib/src/backends/chroot/chroot_file_system.dart @@ -2,7 +2,7 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. -part of file.src.backends.chroot; +part of '../chroot.dart'; const String _thisDir = '.'; const String _parentDir = '..'; @@ -107,7 +107,7 @@ class ChrootFileSystem extends FileSystem { } value = _resolve(value, notFound: _NotFoundBehavior.throwError); - String realPath = _real(value, resolve: false); + var realPath = _real(value, resolve: false); switch (delegate.typeSync(realPath, followLinks: false)) { case FileSystemEntityType.directory: break; @@ -117,7 +117,7 @@ class ChrootFileSystem extends FileSystem { throw common.notADirectory(path as String); } assert(() { - p.Context ctx = delegate.path; + var ctx = delegate.path; return ctx.isAbsolute(value) && value == ctx.canonicalize(value); }()); _cwd = value; @@ -201,7 +201,7 @@ class ChrootFileSystem extends FileSystem { throw _ChrootJailException(); } // TODO(tvolkert): See if _context.relative() works here - String result = realPath.substring(root.length); + var result = realPath.substring(root.length); if (result.isEmpty) { result = _localRoot; } @@ -263,8 +263,8 @@ class ChrootFileSystem extends FileSystem { throw common.noSuchFileOrDirectory(path); } - p.Context ctx = this.path; - String root = _localRoot; + var ctx = this.path; + var root = _localRoot; List parts, ledger; if (ctx.isAbsolute(path)) { parts = ctx.split(path).sublist(1); @@ -277,9 +277,9 @@ class ChrootFileSystem extends FileSystem { } String getCurrentPath() => root + ctx.joinAll(ledger); - Set breadcrumbs = {}; + var breadcrumbs = {}; while (parts.isNotEmpty) { - String segment = parts.removeAt(0); + var segment = parts.removeAt(0); if (segment == _thisDir) { continue; } else if (segment == _parentDir) { @@ -290,8 +290,8 @@ class ChrootFileSystem extends FileSystem { } ledger.add(segment); - String currentPath = getCurrentPath(); - String realPath = _real(currentPath, resolve: false); + var currentPath = getCurrentPath(); + var realPath = _real(currentPath, resolve: false); switch (delegate.typeSync(realPath, followLinks: false)) { case FileSystemEntityType.directory: @@ -333,7 +333,7 @@ class ChrootFileSystem extends FileSystem { if (!breadcrumbs.add(currentPath)) { throw common.tooManyLevelsOfSymbolicLinks(path); } - String target = delegate.link(realPath).targetSync(); + var target = delegate.link(realPath).targetSync(); if (ctx.isAbsolute(target)) { ledger.clear(); parts.insertAll(0, ctx.split(target).sublist(1)); diff --git a/pkgs/file/lib/src/backends/chroot/chroot_file_system_entity.dart b/pkgs/file/lib/src/backends/chroot/chroot_file_system_entity.dart index 8e859ace8..18e37cd02 100644 --- a/pkgs/file/lib/src/backends/chroot/chroot_file_system_entity.dart +++ b/pkgs/file/lib/src/backends/chroot/chroot_file_system_entity.dart @@ -2,7 +2,7 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. -part of file.src.backends.chroot; +part of '../chroot.dart'; abstract class _ChrootFileSystemEntity extends ForwardingFileSystemEntity { @@ -103,7 +103,7 @@ abstract class _ChrootFileSystemEntity delete({bool recursive = false}) async { - String path = fileSystem._resolve(this.path, + var path = fileSystem._resolve(this.path, followLinks: false, notFound: _NotFoundBehavior.throwError); String real(String path) => fileSystem._real(path, resolve: false); @@ -114,7 +114,7 @@ abstract class _ChrootFileSystemEntity fileSystem._real(path, resolve: false); @@ -143,7 +143,7 @@ abstract class _ChrootFileSystemEntity with ForwardingLink { - _ChrootLink(ChrootFileSystem fs, String path) : super(fs, path); + _ChrootLink(super.fs, super.path); factory _ChrootLink.wrapped( ChrootFileSystem fs, io.Link delegate, { bool relative = false, }) { - String localPath = fs._local(delegate.path, relative: relative); + var localPath = fs._local(delegate.path, relative: relative); return _ChrootLink(fs, localPath); } diff --git a/pkgs/file/lib/src/backends/chroot/chroot_random_access_file.dart b/pkgs/file/lib/src/backends/chroot/chroot_random_access_file.dart index 4105ac807..10bbd7035 100644 --- a/pkgs/file/lib/src/backends/chroot/chroot_random_access_file.dart +++ b/pkgs/file/lib/src/backends/chroot/chroot_random_access_file.dart @@ -2,7 +2,7 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. -part of file.src.backends.chroot; +part of '../chroot.dart'; class _ChrootRandomAccessFile with ForwardingRandomAccessFile { _ChrootRandomAccessFile(this.path, this.delegate); diff --git a/pkgs/file/lib/src/backends/local/local_directory.dart b/pkgs/file/lib/src/backends/local/local_directory.dart index e23e68fe0..3e1db6140 100644 --- a/pkgs/file/lib/src/backends/local/local_directory.dart +++ b/pkgs/file/lib/src/backends/local/local_directory.dart @@ -2,10 +2,10 @@ // for details. 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:file/file.dart'; -import 'package:file/src/common.dart' as common; -import 'package:file/src/io.dart' as io; - +import '../../common.dart' as common; +import '../../forwarding.dart'; +import '../../interface.dart'; +import '../../io.dart' as io; import 'local_file_system_entity.dart'; /// [Directory] implementation that forwards all calls to `dart:io`. @@ -13,7 +13,7 @@ class LocalDirectory extends LocalFileSystemEntity with ForwardingDirectory, common.DirectoryAddOnsMixin { /// Instantiates a new [LocalDirectory] tied to the specified file system /// and delegating to the specified [delegate]. - LocalDirectory(FileSystem fs, io.Directory delegate) : super(fs, delegate); + LocalDirectory(super.fs, super.delegate); @override String toString() => "LocalDirectory: '$path'"; diff --git a/pkgs/file/lib/src/backends/local/local_file.dart b/pkgs/file/lib/src/backends/local/local_file.dart index 36293ba51..a4bc10627 100644 --- a/pkgs/file/lib/src/backends/local/local_file.dart +++ b/pkgs/file/lib/src/backends/local/local_file.dart @@ -2,9 +2,9 @@ // for details. 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:file/file.dart'; -import 'package:file/src/io.dart' as io; - +import '../../forwarding.dart'; +import '../../interface.dart'; +import '../../io.dart' as io; import 'local_file_system_entity.dart'; /// [File] implementation that forwards all calls to `dart:io`. @@ -12,7 +12,7 @@ class LocalFile extends LocalFileSystemEntity with ForwardingFile { /// Instantiates a new [LocalFile] tied to the specified file system /// and delegating to the specified [delegate]. - LocalFile(FileSystem fs, io.File delegate) : super(fs, delegate); + LocalFile(super.fs, super.delegate); @override String toString() => "LocalFile: '$path'"; diff --git a/pkgs/file/lib/src/backends/local/local_file_system.dart b/pkgs/file/lib/src/backends/local/local_file_system.dart index 635998e10..7541c370f 100644 --- a/pkgs/file/lib/src/backends/local/local_file_system.dart +++ b/pkgs/file/lib/src/backends/local/local_file_system.dart @@ -2,10 +2,10 @@ // for details. 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:file/src/io.dart' as io; -import 'package:file/file.dart'; import 'package:path/path.dart' as p; +import '../../interface.dart'; +import '../../io.dart' as io; import 'local_directory.dart'; import 'local_file.dart'; import 'local_link.dart'; diff --git a/pkgs/file/lib/src/backends/local/local_file_system_entity.dart b/pkgs/file/lib/src/backends/local/local_file_system_entity.dart index ca4617b01..d0da55975 100644 --- a/pkgs/file/lib/src/backends/local/local_file_system_entity.dart +++ b/pkgs/file/lib/src/backends/local/local_file_system_entity.dart @@ -2,9 +2,9 @@ // for details. 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:file/file.dart'; -import 'package:file/src/io.dart' as io; - +import '../../forwarding.dart'; +import '../../interface.dart'; +import '../../io.dart' as io; import 'local_directory.dart'; import 'local_file.dart'; import 'local_link.dart'; diff --git a/pkgs/file/lib/src/backends/local/local_link.dart b/pkgs/file/lib/src/backends/local/local_link.dart index fc67d5e88..2ce479165 100644 --- a/pkgs/file/lib/src/backends/local/local_link.dart +++ b/pkgs/file/lib/src/backends/local/local_link.dart @@ -2,9 +2,9 @@ // for details. 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:file/file.dart'; -import 'package:file/src/io.dart' as io; - +import '../../forwarding.dart'; +import '../../interface.dart'; +import '../../io.dart' as io; import 'local_file_system_entity.dart'; /// [Link] implementation that forwards all calls to `dart:io`. @@ -12,7 +12,7 @@ class LocalLink extends LocalFileSystemEntity with ForwardingLink { /// Instantiates a new [LocalLink] tied to the specified file system /// and delegating to the specified [delegate]. - LocalLink(FileSystem fs, io.Link delegate) : super(fs, delegate); + LocalLink(super.fs, super.delegate); @override String toString() => "LocalLink: '$path'"; diff --git a/pkgs/file/lib/src/backends/memory/clock.dart b/pkgs/file/lib/src/backends/memory/clock.dart index 98d5434f9..57c1b72cd 100644 --- a/pkgs/file/lib/src/backends/memory/clock.dart +++ b/pkgs/file/lib/src/backends/memory/clock.dart @@ -2,6 +2,8 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// ignore_for_file: comment_references + /// Interface describing clocks used by the [MemoryFileSystem]. /// /// The [MemoryFileSystem] uses a clock to determine the modification times of diff --git a/pkgs/file/lib/src/backends/memory/common.dart b/pkgs/file/lib/src/backends/memory/common.dart index 80e3c3851..eb4ca43d7 100644 --- a/pkgs/file/lib/src/backends/memory/common.dart +++ b/pkgs/file/lib/src/backends/memory/common.dart @@ -2,7 +2,7 @@ // for details. 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:file/src/common.dart' as common; +import '../../common.dart' as common; /// Generates a path to use in error messages. typedef PathGenerator = dynamic Function(); diff --git a/pkgs/file/lib/src/backends/memory/memory_directory.dart b/pkgs/file/lib/src/backends/memory/memory_directory.dart index 95fe54247..e73b96706 100644 --- a/pkgs/file/lib/src/backends/memory/memory_directory.dart +++ b/pkgs/file/lib/src/backends/memory/memory_directory.dart @@ -2,11 +2,11 @@ // for details. 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:file/file.dart'; -import 'package:file/src/common.dart' as common; -import 'package:file/src/io.dart' as io; import 'package:meta/meta.dart'; +import '../../common.dart' as common; +import '../../interface.dart'; +import '../../io.dart' as io; import 'common.dart'; import 'memory_file.dart'; import 'memory_file_system_entity.dart'; @@ -25,8 +25,7 @@ class MemoryDirectory extends MemoryFileSystemEntity with common.DirectoryAddOnsMixin implements Directory { /// Instantiates a new [MemoryDirectory]. - MemoryDirectory(NodeBasedFileSystem fileSystem, String path) - : super(fileSystem, path); + MemoryDirectory(super.fileSystem, super.path); @override io.FileSystemEntityType get expectedType => io.FileSystemEntityType.directory; @@ -52,7 +51,7 @@ class MemoryDirectory extends MemoryFileSystemEntity @override void createSync({bool recursive = false}) { fileSystem.opHandle(path, FileSystemOp.create); - Node? node = internalCreateSync( + var node = internalCreateSync( followTailLink: true, visitLinks: true, createChild: (DirectoryNode parent, bool isFinalSegment) { @@ -75,19 +74,19 @@ class MemoryDirectory extends MemoryFileSystemEntity @override Directory createTempSync([String? prefix]) { prefix = '${prefix ?? ''}rand'; - String fullPath = fileSystem.path.join(path, prefix); - String dirname = fileSystem.path.dirname(fullPath); - String basename = fileSystem.path.basename(fullPath); - DirectoryNode? node = fileSystem.findNode(dirname) as DirectoryNode?; + var fullPath = fileSystem.path.join(path, prefix); + var dirname = fileSystem.path.dirname(fullPath); + var basename = fileSystem.path.basename(fullPath); + var node = fileSystem.findNode(dirname) as DirectoryNode?; checkExists(node, () => dirname); utils.checkIsDir(node!, () => dirname); - int tempCounter = _systemTempCounter[fileSystem] ?? 0; + var tempCounter = _systemTempCounter[fileSystem] ?? 0; String name() => '$basename$tempCounter'; while (node.children.containsKey(name())) { tempCounter++; } _systemTempCounter[fileSystem] = tempCounter; - DirectoryNode tempDir = DirectoryNode(node); + var tempDir = DirectoryNode(node); node.children[name()] = tempDir; return MemoryDirectory(fileSystem, fileSystem.path.join(dirname, name())) ..createSync(); @@ -128,9 +127,9 @@ class MemoryDirectory extends MemoryFileSystemEntity bool recursive = false, bool followLinks = true, }) { - DirectoryNode node = backing as DirectoryNode; - List listing = []; - List<_PendingListTask> tasks = <_PendingListTask>[ + var node = backing as DirectoryNode; + var listing = []; + var tasks = <_PendingListTask>[ _PendingListTask( node, path.endsWith(fileSystem.path.separator) @@ -140,14 +139,14 @@ class MemoryDirectory extends MemoryFileSystemEntity ), ]; while (tasks.isNotEmpty) { - _PendingListTask task = tasks.removeLast(); + var task = tasks.removeLast(); task.dir.children.forEach((String name, Node child) { - Set breadcrumbs = Set.from(task.breadcrumbs); - String childPath = fileSystem.path.join(task.path, name); + var breadcrumbs = Set.from(task.breadcrumbs); + var childPath = fileSystem.path.join(task.path, name); while (followLinks && utils.isLink(child) && breadcrumbs.add(child as LinkNode)) { - Node? referent = child.referentOrNull; + var referent = child.referentOrNull; if (referent != null) { child = referent; } diff --git a/pkgs/file/lib/src/backends/memory/memory_file.dart b/pkgs/file/lib/src/backends/memory/memory_file.dart index ba4faab37..1a8f5f972 100644 --- a/pkgs/file/lib/src/backends/memory/memory_file.dart +++ b/pkgs/file/lib/src/backends/memory/memory_file.dart @@ -7,26 +7,25 @@ import 'dart:convert'; import 'dart:math' as math show min; import 'dart:typed_data'; -import 'package:file/file.dart'; -import 'package:file/src/backends/memory/operations.dart'; -import 'package:file/src/common.dart' as common; -import 'package:file/src/io.dart' as io; import 'package:meta/meta.dart'; +import '../../common.dart' as common; +import '../../interface.dart'; +import '../../io.dart' as io; import 'common.dart'; import 'memory_file_system_entity.dart'; import 'memory_random_access_file.dart'; import 'node.dart'; +import 'operations.dart'; import 'utils.dart' as utils; /// Internal implementation of [File]. class MemoryFile extends MemoryFileSystemEntity implements File { /// Instantiates a new [MemoryFile]. - const MemoryFile(NodeBasedFileSystem fileSystem, String path) - : super(fileSystem, path); + const MemoryFile(super.fileSystem, super.path); FileNode get _resolvedBackingOrCreate { - Node? node = backingOrNull; + var node = backingOrNull; if (node == null) { node = _doCreate(); } else { @@ -61,7 +60,7 @@ class MemoryFile extends MemoryFileSystemEntity implements File { } Node? _doCreate({bool recursive = false}) { - Node? node = internalCreateSync( + var node = internalCreateSync( followTailLink: true, createChild: (DirectoryNode parent, bool isFinalSegment) { if (isFinalSegment) { @@ -88,7 +87,7 @@ class MemoryFile extends MemoryFileSystemEntity implements File { newPath, followTailLink: true, checkType: (Node node) { - FileSystemEntityType actualType = node.stat.type; + var actualType = node.stat.type; if (actualType != expectedType) { throw actualType == FileSystemEntityType.notFound ? common.noSuchFileOrDirectory(path) @@ -103,7 +102,7 @@ class MemoryFile extends MemoryFileSystemEntity implements File { @override File copySync(String newPath) { fileSystem.opHandle(path, FileSystemOp.copy); - FileNode sourceNode = resolvedBacking as FileNode; + var sourceNode = resolvedBacking as FileNode; fileSystem.findNode( newPath, segmentVisitor: ( @@ -116,7 +115,7 @@ class MemoryFile extends MemoryFileSystemEntity implements File { if (currentSegment == finalSegment) { if (child != null) { if (utils.isLink(child)) { - List ledger = []; + var ledger = []; child = utils.resolveLinks(child as LinkNode, () => newPath, ledger: ledger); checkExists(child, () => newPath); @@ -127,7 +126,7 @@ class MemoryFile extends MemoryFileSystemEntity implements File { utils.checkType(expectedType, child.type, () => newPath); parent.children.remove(childName); } - FileNode newNode = FileNode(parent); + var newNode = FileNode(parent); newNode.copyFrom(sourceNode); parent.children[childName] = newNode; } @@ -158,7 +157,7 @@ class MemoryFile extends MemoryFileSystemEntity implements File { @override void setLastAccessedSync(DateTime time) { - FileNode node = resolvedBacking as FileNode; + var node = resolvedBacking as FileNode; node.accessed = time.millisecondsSinceEpoch; } @@ -174,7 +173,7 @@ class MemoryFile extends MemoryFileSystemEntity implements File { @override void setLastModifiedSync(DateTime time) { - FileNode node = resolvedBacking as FileNode; + var node = resolvedBacking as FileNode; node.modified = time.millisecondsSinceEpoch; } @@ -199,8 +198,8 @@ class MemoryFile extends MemoryFileSystemEntity implements File { Stream> openRead([int? start, int? end]) { fileSystem.opHandle(path, FileSystemOp.open); try { - FileNode node = resolvedBacking as FileNode; - Uint8List content = node.content; + var node = resolvedBacking as FileNode; + var content = node.content; if (start != null) { content = end == null ? content.sublist(start) @@ -253,13 +252,13 @@ class MemoryFile extends MemoryFileSystemEntity implements File { @override List readAsLinesSync({Encoding encoding = utf8}) { - String str = readAsStringSync(encoding: encoding); + var str = readAsStringSync(encoding: encoding); if (str.isEmpty) { return []; } - final List lines = str.split('\n'); + final lines = str.split('\n'); if (str.endsWith('\n')) { // A final newline should not create an additional line. lines.removeLast(); @@ -287,7 +286,7 @@ class MemoryFile extends MemoryFileSystemEntity implements File { if (!utils.isWriteMode(mode)) { throw common.badFileDescriptor(path); } - FileNode node = _resolvedBackingOrCreate; + var node = _resolvedBackingOrCreate; _truncateIfNecessary(node, mode); fileSystem.opHandle(path, FileSystemOp.write); node.write(bytes); @@ -349,7 +348,7 @@ class _FileSink implements io.IOSink { deferredException = e; } - Future future = Future.microtask(() { + var future = Future.microtask(() { if (deferredException != null) { throw deferredException; } @@ -387,7 +386,7 @@ class _FileSink implements io.IOSink { @override void writeAll(Iterable objects, [String separator = '']) { - bool firstIter = true; + var firstIter = true; for (dynamic obj in objects) { if (!firstIter) { write(separator); @@ -418,7 +417,7 @@ class _FileSink implements io.IOSink { _streamCompleter = Completer(); stream.listen( - (List data) => _addData(data), + _addData, cancelOnError: true, onError: (Object error, StackTrace stackTrace) { _streamCompleter!.completeError(error, stackTrace); @@ -445,8 +444,7 @@ class _FileSink implements io.IOSink { _isClosed = true; _pendingWrites.then( (_) => _completer.complete(), - onError: (Object error, StackTrace stackTrace) => - _completer.completeError(error, stackTrace), + onError: _completer.completeError, ); } return _completer.future; diff --git a/pkgs/file/lib/src/backends/memory/memory_file_stat.dart b/pkgs/file/lib/src/backends/memory/memory_file_stat.dart index 94f86d155..ce6bedac1 100644 --- a/pkgs/file/lib/src/backends/memory/memory_file_stat.dart +++ b/pkgs/file/lib/src/backends/memory/memory_file_stat.dart @@ -2,7 +2,7 @@ // for details. 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:file/src/io.dart' as io; +import '../../io.dart' as io; /// Internal implementation of [io.FileStat]. class MemoryFileStat implements io.FileStat { @@ -47,8 +47,8 @@ class MemoryFileStat implements io.FileStat { @override String modeString() { - int permissions = mode & 0xFFF; - List codes = const [ + var permissions = mode & 0xFFF; + var codes = const [ '---', '--x', '-w-', @@ -58,7 +58,7 @@ class MemoryFileStat implements io.FileStat { 'rw-', 'rwx', ]; - List result = []; + var result = []; result ..add(codes[(permissions >> 6) & 0x7]) ..add(codes[(permissions >> 3) & 0x7]) diff --git a/pkgs/file/lib/src/backends/memory/memory_file_system.dart b/pkgs/file/lib/src/backends/memory/memory_file_system.dart index f3cdaeede..dd359f049 100644 --- a/pkgs/file/lib/src/backends/memory/memory_file_system.dart +++ b/pkgs/file/lib/src/backends/memory/memory_file_system.dart @@ -2,11 +2,10 @@ // for details. 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:file/file.dart'; -import 'package:file/src/backends/memory/operations.dart'; -import 'package:file/src/io.dart' as io; import 'package:path/path.dart' as p; +import '../../interface.dart'; +import '../../io.dart' as io; import 'clock.dart'; import 'common.dart'; import 'memory_directory.dart'; @@ -14,6 +13,7 @@ import 'memory_file.dart'; import 'memory_file_stat.dart'; import 'memory_link.dart'; import 'node.dart'; +import 'operations.dart'; import 'style.dart'; import 'utils.dart' as utils; @@ -91,7 +91,7 @@ class _MemoryFileSystem extends FileSystem p.Context _context; @override - final Function(String context, FileSystemOp operation) opHandle; + final void Function(String context, FileSystemOp operation) opHandle; @override final Clock clock; @@ -141,7 +141,7 @@ class _MemoryFileSystem extends FileSystem } value = directory(value).resolveSymbolicLinksSync(); - Node? node = findNode(value); + var node = findNode(value); checkExists(node, () => value); utils.checkIsDir(node!, () => value); assert(_context.isAbsolute(value)); @@ -166,9 +166,9 @@ class _MemoryFileSystem extends FileSystem @override bool identicalSync(String path1, String path2) { - Node? node1 = findNode(path1); + var node1 = findNode(path1); checkExists(node1, () => path1); - Node? node2 = findNode(path2); + var node2 = findNode(path2); checkExists(node2, () => path2); return node1 != null && node1 == node2; } @@ -220,14 +220,13 @@ class _MemoryFileSystem extends FileSystem reference ??= _current; } - List parts = path.split(style.separator) - ..removeWhere(utils.isEmpty); - DirectoryNode? directory = reference?.directory; + var parts = path.split(style.separator)..removeWhere(utils.isEmpty); + var directory = reference?.directory; Node? child = directory; - int finalSegment = parts.length - 1; - for (int i = 0; i <= finalSegment; i++) { - String basename = parts[i]; + var finalSegment = parts.length - 1; + for (var i = 0; i <= finalSegment; i++) { + var basename = parts[i]; assert(basename.isNotEmpty); switch (basename) { diff --git a/pkgs/file/lib/src/backends/memory/memory_file_system_entity.dart b/pkgs/file/lib/src/backends/memory/memory_file_system_entity.dart index ad987d71a..1990abcd0 100644 --- a/pkgs/file/lib/src/backends/memory/memory_file_system_entity.dart +++ b/pkgs/file/lib/src/backends/memory/memory_file_system_entity.dart @@ -2,11 +2,11 @@ // for details. 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:file/file.dart'; -import 'package:file/src/common.dart' as common; -import 'package:file/src/io.dart' as io; import 'package:meta/meta.dart'; +import '../../common.dart' as common; +import '../../interface.dart'; +import '../../io.dart' as io; import 'common.dart'; import 'memory_directory.dart'; import 'node.dart'; @@ -60,7 +60,7 @@ abstract class MemoryFileSystemEntity implements FileSystemEntity { /// The type of the node is not guaranteed to match [expectedType]. @protected Node get backing { - Node? node = fileSystem.findNode(path); + var node = fileSystem.findNode(path); checkExists(node, () => path); return node!; } @@ -71,7 +71,7 @@ abstract class MemoryFileSystemEntity implements FileSystemEntity { /// doesn't match, this will throw a [io.FileSystemException]. @protected Node get resolvedBacking { - Node node = backing; + var node = backing; node = utils.isLink(node) ? utils.resolveLinks(node as LinkNode, () => path) : node; @@ -107,14 +107,14 @@ abstract class MemoryFileSystemEntity implements FileSystemEntity { if (path.isEmpty) { throw common.noSuchFileOrDirectory(path); } - List ledger = []; + var ledger = []; if (isAbsolute) { ledger.add(fileSystem.style.drive); } - Node? node = fileSystem.findNode(path, + var node = fileSystem.findNode(path, pathWithSymlinks: ledger, followTailLink: true); checkExists(node, () => path); - String resolved = ledger.join(fileSystem.path.separator); + var resolved = ledger.join(fileSystem.path.separator); if (resolved == fileSystem.style.drive) { resolved = fileSystem.style.root; } else if (!fileSystem.path.isAbsolute(resolved)) { @@ -151,7 +151,7 @@ abstract class MemoryFileSystemEntity implements FileSystemEntity { @override FileSystemEntity get absolute { - String absolutePath = path; + var absolutePath = path; if (!fileSystem.path.isAbsolute(absolutePath)) { absolutePath = fileSystem.path.join(fileSystem.cwd, absolutePath); } @@ -242,7 +242,7 @@ abstract class MemoryFileSystemEntity implements FileSystemEntity { bool followTailLink = false, utils.TypeChecker? checkType, }) { - Node node = backing; + var node = backing; (checkType ?? defaultCheckType)(node); fileSystem.findNode( newPath, @@ -256,7 +256,7 @@ abstract class MemoryFileSystemEntity implements FileSystemEntity { if (currentSegment == finalSegment) { if (child != null) { if (followTailLink) { - FileSystemEntityType childType = child.stat.type; + var childType = child.stat.type; if (childType != FileSystemEntityType.notFound) { utils.checkType(expectedType, child.stat.type, () => newPath); } @@ -289,7 +289,7 @@ abstract class MemoryFileSystemEntity implements FileSystemEntity { utils.TypeChecker? checkType, }) { fileSystem.opHandle(path, FileSystemOp.delete); - Node node = backing; + var node = backing; if (!recursive) { if (node is DirectoryNode && node.children.isNotEmpty) { throw common.directoryNotEmpty(path); diff --git a/pkgs/file/lib/src/backends/memory/memory_link.dart b/pkgs/file/lib/src/backends/memory/memory_link.dart index 7d5afb42f..a599fe8f1 100644 --- a/pkgs/file/lib/src/backends/memory/memory_link.dart +++ b/pkgs/file/lib/src/backends/memory/memory_link.dart @@ -2,11 +2,11 @@ // for details. 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:file/file.dart'; -import 'package:file/src/common.dart' as common; -import 'package:file/src/io.dart' as io; import 'package:meta/meta.dart'; +import '../../common.dart' as common; +import '../../interface.dart'; +import '../../io.dart' as io; import 'memory_file_system_entity.dart'; import 'node.dart'; import 'operations.dart'; @@ -15,8 +15,7 @@ import 'utils.dart' as utils; /// Internal implementation of [Link]. class MemoryLink extends MemoryFileSystemEntity implements Link { /// Instantiates a new [MemoryLink]. - const MemoryLink(NodeBasedFileSystem fileSystem, String path) - : super(fileSystem, path); + const MemoryLink(super.fileSystem, super.path); @override io.FileSystemEntityType get expectedType => io.FileSystemEntityType.link; @@ -50,7 +49,7 @@ class MemoryLink extends MemoryFileSystemEntity implements Link { @override void createSync(String target, {bool recursive = false}) { - bool preexisting = true; + var preexisting = true; fileSystem.opHandle(path, FileSystemOp.create); internalCreateSync( createChild: (DirectoryNode parent, bool isFinalSegment) { @@ -76,7 +75,7 @@ class MemoryLink extends MemoryFileSystemEntity implements Link { @override void updateSync(String target) { - Node node = backing; + var node = backing; utils.checkType(expectedType, node.type, () => path); (node as LinkNode).target = target; } @@ -93,7 +92,7 @@ class MemoryLink extends MemoryFileSystemEntity implements Link { @override String targetSync() { - Node node = backing; + var node = backing; if (node.type != expectedType) { // Note: this may change; https://github.com/dart-lang/sdk/issues/28204 throw common.noSuchFileOrDirectory(path); diff --git a/pkgs/file/lib/src/backends/memory/memory_random_access_file.dart b/pkgs/file/lib/src/backends/memory/memory_random_access_file.dart index d4fe73d18..190f0a137 100644 --- a/pkgs/file/lib/src/backends/memory/memory_random_access_file.dart +++ b/pkgs/file/lib/src/backends/memory/memory_random_access_file.dart @@ -6,10 +6,11 @@ import 'dart:convert'; import 'dart:math' as math show min; import 'dart:typed_data'; -import 'package:file/src/common.dart' as common; -import 'package:file/src/io.dart' as io; - +import '../../common.dart' as common; +import '../../io.dart' as io; +import '../memory.dart' show MemoryFileSystem; import 'memory_file.dart'; +import 'memory_file_system.dart' show MemoryFileSystem; import 'node.dart'; import 'utils.dart' as utils; @@ -106,8 +107,8 @@ class MemoryRandomAccessFile implements io.RandomAccessFile { /// Wraps a synchronous function to make it appear asynchronous. /// /// [_asyncOperationPending], [_checkAsync], and [_asyncWrapper] are used to - /// mimic [RandomAccessFile]'s enforcement that only one asynchronous - /// operation is pending for a [RandomAccessFile] instance. Since + /// mimic [io.RandomAccessFile]'s enforcement that only one asynchronous + /// operation is pending for a [io.RandomAccessFile] instance. Since /// [MemoryFileSystem]-based classes are likely to be used in tests, fidelity /// is important to catch errors that might occur in production. /// @@ -211,7 +212,7 @@ class MemoryRandomAccessFile implements io.RandomAccessFile { _checkReadable('read'); // TODO(jamesderlin): Check for integer overflow. final int end = math.min(_position + bytes, lengthSync()); - final Uint8List copy = _node.content.sublist(_position, end); + final copy = _node.content.sublist(_position, end); _position = end; return copy; } @@ -243,7 +244,7 @@ class MemoryRandomAccessFile implements io.RandomAccessFile { end = RangeError.checkValidRange(start, end, buffer.length); - final int length = lengthSync(); + final length = lengthSync(); int i; for (i = start; i < end && _position < length; i += 1, _position += 1) { buffer[i] = _node.content[_position]; @@ -288,7 +289,7 @@ class MemoryRandomAccessFile implements io.RandomAccessFile { 'truncate failed', path, common.invalidArgument(path).osError); } - final int oldLength = lengthSync(); + final oldLength = lengthSync(); if (length < oldLength) { _node.truncate(length); @@ -329,7 +330,7 @@ class MemoryRandomAccessFile implements io.RandomAccessFile { // [Uint8List] will truncate values to 8-bits automatically, so we don't // need to check [value]. - int length = lengthSync(); + var length = lengthSync(); if (_position >= length) { // If [_position] is out of bounds, [RandomAccessFile] zero-fills the // file. @@ -363,8 +364,8 @@ class MemoryRandomAccessFile implements io.RandomAccessFile { end = RangeError.checkValidRange(start, end, buffer.length); - final int writeByteCount = end - start; - final int endPosition = _position + writeByteCount; + final writeByteCount = end - start; + final endPosition = _position + writeByteCount; if (endPosition > lengthSync()) { truncateSync(endPosition); diff --git a/pkgs/file/lib/src/backends/memory/node.dart b/pkgs/file/lib/src/backends/memory/node.dart index ae4d3f75d..eea72b58c 100644 --- a/pkgs/file/lib/src/backends/memory/node.dart +++ b/pkgs/file/lib/src/backends/memory/node.dart @@ -4,13 +4,12 @@ import 'dart:typed_data'; -import 'package:file/file.dart'; -import 'package:file/src/backends/memory/operations.dart'; -import 'package:file/src/io.dart' as io; - +import '../../interface.dart'; +import '../../io.dart' as io; import 'clock.dart'; import 'common.dart'; import 'memory_file_stat.dart'; +import 'operations.dart'; import 'style.dart'; /// Visitor callback for use with [NodeBasedFileSystem.findNode]. @@ -115,7 +114,7 @@ abstract class Node { /// Reparents this node to live in the specified directory. set parent(DirectoryNode parent) { - DirectoryNode ancestor = parent; + var ancestor = parent; while (!ancestor.isRoot) { if (ancestor == this) { throw const io.FileSystemException( @@ -149,8 +148,8 @@ abstract class Node { /// you call [stat] on them). abstract class RealNode extends Node { /// Constructs a new [RealNode] as a child of the specified [parent]. - RealNode(DirectoryNode? parent) : super(parent) { - int now = clock.now.millisecondsSinceEpoch; + RealNode(super.parent) { + var now = clock.now.millisecondsSinceEpoch; changed = now; modified = now; accessed = now; @@ -195,7 +194,7 @@ abstract class RealNode extends Node { /// Class that represents the backing for an in-memory directory. class DirectoryNode extends RealNode { /// Constructs a new [DirectoryNode] as a child of the specified [parent]. - DirectoryNode(DirectoryNode? parent) : super(parent); + DirectoryNode(super.parent); /// Child nodes, indexed by their basename. final Map children = {}; @@ -237,7 +236,7 @@ class RootNode extends DirectoryNode { /// Class that represents the backing for an in-memory regular file. class FileNode extends RealNode { /// Constructs a new [FileNode] as a child of the specified [parent]. - FileNode(DirectoryNode parent) : super(parent); + FileNode(DirectoryNode super.parent); /// File contents in bytes. Uint8List get content => _content; @@ -251,7 +250,7 @@ class FileNode extends RealNode { /// Appends the specified bytes to the end of this node's [content]. void write(List bytes) { - Uint8List existing = _content; + var existing = _content; _content = Uint8List(existing.length + bytes.length); _content.setRange(0, existing.length, existing); _content.setRange(existing.length, _content.length, bytes); @@ -286,9 +285,7 @@ class FileNode extends RealNode { class LinkNode extends Node { /// Constructs a new [LinkNode] as a child of the specified [parent] and /// linking to the specified [target] path. - LinkNode(DirectoryNode parent, this.target) - : assert(target.isNotEmpty), - super(parent); + LinkNode(DirectoryNode super.parent, this.target) : assert(target.isNotEmpty); /// The path to which this link points. String target; @@ -309,7 +306,7 @@ class LinkNode extends Node { Node? Function(DirectoryNode parent, String childName, Node? child)? tailVisitor, }) { - Node? referent = fs.findNode( + var referent = fs.findNode( target, reference: this, segmentVisitor: ( @@ -349,7 +346,7 @@ class LinkNode extends Node { } _reentrant = true; try { - Node? node = referentOrNull; + var node = referentOrNull; return node == null ? MemoryFileStat.notFound : node.stat; } finally { _reentrant = false; diff --git a/pkgs/file/lib/src/backends/memory/operations.dart b/pkgs/file/lib/src/backends/memory/operations.dart index 9fc7462fc..57d118b11 100644 --- a/pkgs/file/lib/src/backends/memory/operations.dart +++ b/pkgs/file/lib/src/backends/memory/operations.dart @@ -2,6 +2,8 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// ignore_for_file: comment_references + /// A file system operation used by the [MemoryFileSytem] to allow /// tests to insert errors for certain operations. /// @@ -64,23 +66,15 @@ class FileSystemOp { @override String toString() { - switch (_value) { - case 0: - return 'FileSystemOp.read'; - case 1: - return 'FileSystemOp.write'; - case 2: - return 'FileSystemOp.delete'; - case 3: - return 'FileSystemOp.create'; - case 4: - return 'FileSystemOp.open'; - case 5: - return 'FileSystemOp.copy'; - case 6: - return 'FileSystemOp.exists'; - default: - throw StateError('Invalid FileSytemOp type: $this'); - } + return switch (_value) { + 0 => 'FileSystemOp.read', + 1 => 'FileSystemOp.write', + 2 => 'FileSystemOp.delete', + 3 => 'FileSystemOp.create', + 4 => 'FileSystemOp.open', + 5 => 'FileSystemOp.copy', + 6 => 'FileSystemOp.exists', + _ => throw StateError('Invalid FileSytemOp type: $this') + }; } } diff --git a/pkgs/file/lib/src/backends/memory/style.dart b/pkgs/file/lib/src/backends/memory/style.dart index 701c9d05e..f4bd33fb7 100644 --- a/pkgs/file/lib/src/backends/memory/style.dart +++ b/pkgs/file/lib/src/backends/memory/style.dart @@ -2,9 +2,10 @@ // for details. 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:file/file.dart'; import 'package:path/path.dart' as p; +import '../../interface.dart'; + /// Class that represents the path style that a memory file system should /// adopt. /// diff --git a/pkgs/file/lib/src/backends/memory/utils.dart b/pkgs/file/lib/src/backends/memory/utils.dart index eec998038..aa24cfb57 100644 --- a/pkgs/file/lib/src/backends/memory/utils.dart +++ b/pkgs/file/lib/src/backends/memory/utils.dart @@ -2,20 +2,19 @@ // for details. 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:file/file.dart'; -import 'package:file/src/common.dart' as common; -import 'package:file/src/io.dart' as io; - +import '../../common.dart' as common; +import '../../interface.dart'; +import '../../io.dart' as io; import 'common.dart'; import 'node.dart'; -/// Checks if `node.type` returns [io.FileSystemEntityType.FILE]. +/// Checks if `node.type` returns [io.FileSystemEntityType.file]. bool isFile(Node? node) => node?.type == io.FileSystemEntityType.file; -/// Checks if `node.type` returns [io.FileSystemEntityType.DIRECTORY]. +/// Checks if `node.type` returns [io.FileSystemEntityType.directory]. bool isDirectory(Node? node) => node?.type == io.FileSystemEntityType.directory; -/// Checks if `node.type` returns [io.FileSystemEntityType.LINK]. +/// Checks if `node.type` returns [io.FileSystemEntityType.link]. bool isLink(Node? node) => node?.type == io.FileSystemEntityType.link; /// Validator function that is expected to throw a [FileSystemException] if @@ -86,7 +85,7 @@ Node resolveLinks( tailVisitor, }) { // Record a breadcrumb trail to guard against symlink loops. - Set breadcrumbs = {}; + var breadcrumbs = {}; Node node = link; while (isLink(node)) { diff --git a/pkgs/file/lib/src/forwarding/forwarding_directory.dart b/pkgs/file/lib/src/forwarding/forwarding_directory.dart index dba0c8ed6..ad1c548c1 100644 --- a/pkgs/file/lib/src/forwarding/forwarding_directory.dart +++ b/pkgs/file/lib/src/forwarding/forwarding_directory.dart @@ -2,8 +2,9 @@ // for details. 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:file/src/io.dart' as io; -import 'package:file/file.dart'; +import '../forwarding.dart'; +import '../interface.dart'; +import '../io.dart' as io; /// A directory that forwards all methods and properties to a delegate. mixin ForwardingDirectory diff --git a/pkgs/file/lib/src/forwarding/forwarding_file.dart b/pkgs/file/lib/src/forwarding/forwarding_file.dart index 49c211db7..d6cfe3bb7 100644 --- a/pkgs/file/lib/src/forwarding/forwarding_file.dart +++ b/pkgs/file/lib/src/forwarding/forwarding_file.dart @@ -5,8 +5,9 @@ import 'dart:convert'; import 'dart:typed_data'; -import 'package:file/src/io.dart' as io; -import 'package:file/file.dart'; +import '../forwarding.dart'; +import '../interface.dart'; +import '../io.dart' as io; /// A file that forwards all methods and properties to a delegate. mixin ForwardingFile diff --git a/pkgs/file/lib/src/forwarding/forwarding_file_system.dart b/pkgs/file/lib/src/forwarding/forwarding_file_system.dart index d864db94c..885fdb618 100644 --- a/pkgs/file/lib/src/forwarding/forwarding_file_system.dart +++ b/pkgs/file/lib/src/forwarding/forwarding_file_system.dart @@ -2,11 +2,12 @@ // for details. 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:file/src/io.dart' as io; -import 'package:file/file.dart'; import 'package:meta/meta.dart'; import 'package:path/path.dart' as p; +import '../interface.dart'; +import '../io.dart' as io; + /// A file system that forwards all methods and properties to a delegate. abstract class ForwardingFileSystem extends FileSystem { /// Creates a new [ForwardingFileSystem] that forwards all methods and diff --git a/pkgs/file/lib/src/forwarding/forwarding_file_system_entity.dart b/pkgs/file/lib/src/forwarding/forwarding_file_system_entity.dart index 3c41b39b4..1c0628ee4 100644 --- a/pkgs/file/lib/src/forwarding/forwarding_file_system_entity.dart +++ b/pkgs/file/lib/src/forwarding/forwarding_file_system_entity.dart @@ -2,10 +2,11 @@ // for details. 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:file/src/io.dart' as io; -import 'package:file/file.dart'; import 'package:meta/meta.dart'; +import '../interface.dart'; +import '../io.dart' as io; + /// A file system entity that forwards all methods and properties to a delegate. abstract class ForwardingFileSystemEntity implements FileSystemEntity { diff --git a/pkgs/file/lib/src/forwarding/forwarding_link.dart b/pkgs/file/lib/src/forwarding/forwarding_link.dart index 7a60ecbfe..915e710cf 100644 --- a/pkgs/file/lib/src/forwarding/forwarding_link.dart +++ b/pkgs/file/lib/src/forwarding/forwarding_link.dart @@ -2,8 +2,9 @@ // for details. 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:file/src/io.dart' as io; -import 'package:file/file.dart'; +import '../forwarding.dart'; +import '../interface.dart'; +import '../io.dart' as io; /// A link that forwards all methods and properties to a delegate. mixin ForwardingLink diff --git a/pkgs/file/lib/src/forwarding/forwarding_random_access_file.dart b/pkgs/file/lib/src/forwarding/forwarding_random_access_file.dart index 9dd407930..3847b91f4 100644 --- a/pkgs/file/lib/src/forwarding/forwarding_random_access_file.dart +++ b/pkgs/file/lib/src/forwarding/forwarding_random_access_file.dart @@ -5,11 +5,12 @@ import 'dart:convert'; import 'dart:typed_data'; -import 'package:file/src/io.dart' as io; import 'package:meta/meta.dart'; -/// A [RandomAccessFile] implementation that forwards all methods and properties -/// to a delegate. +import '../io.dart' as io; + +/// A [io.RandomAccessFile] implementation that forwards all methods and +/// properties to a delegate. mixin ForwardingRandomAccessFile implements io.RandomAccessFile { /// The entity to which this entity will forward all methods and properties. @protected diff --git a/pkgs/file/lib/src/interface.dart b/pkgs/file/lib/src/interface.dart index 4662e3515..d9b7ed592 100644 --- a/pkgs/file/lib/src/interface.dart +++ b/pkgs/file/lib/src/interface.dart @@ -2,8 +2,6 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. -library file.src.interface; - export 'interface/directory.dart'; export 'interface/error_codes.dart'; export 'interface/file.dart'; diff --git a/pkgs/file/lib/src/interface/error_codes.dart b/pkgs/file/lib/src/interface/error_codes.dart index 8943538cb..4836b5658 100644 --- a/pkgs/file/lib/src/interface/error_codes.dart +++ b/pkgs/file/lib/src/interface/error_codes.dart @@ -168,7 +168,7 @@ class ErrorCodes { static int get EXDEV => _platform((_Codes codes) => codes.exdev); static int _platform(int Function(_Codes codes) getCode) { - _Codes codes = (_platforms[operatingSystem] ?? _platforms['linux'])!; + var codes = (_platforms[operatingSystem] ?? _platforms['linux'])!; return getCode(codes); } } diff --git a/pkgs/file/lib/src/interface/file_system.dart b/pkgs/file/lib/src/interface/file_system.dart index ecc01a801..2d4e4aa3b 100644 --- a/pkgs/file/lib/src/interface/file_system.dart +++ b/pkgs/file/lib/src/interface/file_system.dart @@ -6,7 +6,6 @@ import 'package:meta/meta.dart'; import 'package:path/path.dart' as p; import '../io.dart' as io; - import 'directory.dart'; import 'file.dart'; import 'file_system_entity.dart'; @@ -99,9 +98,9 @@ abstract class FileSystem { bool get isWatchSupported; /// Finds the type of file system object that a [path] points to. Returns - /// a Future that completes with the result. + /// a `Future` that completes with the result. /// - /// [io.FileSystemEntityType.LINK] will only be returned if [followLinks] is + /// [io.FileSystemEntityType.link] will only be returned if [followLinks] is /// `false`, and [path] points to a link /// /// If the [path] does not point to a file system object or an error occurs @@ -111,37 +110,38 @@ abstract class FileSystem { /// Syncronously finds the type of file system object that a [path] points /// to. Returns a [io.FileSystemEntityType]. /// - /// [io.FileSystemEntityType.LINK] will only be returned if [followLinks] is + /// [io.FileSystemEntityType.link] will only be returned if [followLinks] is /// `false`, and [path] points to a link /// /// If the [path] does not point to a file system object or an error occurs /// then [io.FileSystemEntityType.notFound] is returned. io.FileSystemEntityType typeSync(String path, {bool followLinks = true}); - /// Checks if [`type(path)`](type) returns [io.FileSystemEntityType.FILE]. + /// Checks if [`type(path)`](type) returns [io.FileSystemEntityType.file]. Future isFile(String path) async => await type(path) == io.FileSystemEntityType.file; /// Synchronously checks if [`type(path)`](type) returns - /// [io.FileSystemEntityType.FILE]. + /// [io.FileSystemEntityType.file]. bool isFileSync(String path) => typeSync(path) == io.FileSystemEntityType.file; - /// Checks if [`type(path)`](type) returns [io.FileSystemEntityType.DIRECTORY]. + /// Checks if [`type(path)`](type) returns + /// [io.FileSystemEntityType.directory]. Future isDirectory(String path) async => await type(path) == io.FileSystemEntityType.directory; /// Synchronously checks if [`type(path)`](type) returns - /// [io.FileSystemEntityType.DIRECTORY]. + /// [io.FileSystemEntityType.directory]. bool isDirectorySync(String path) => typeSync(path) == io.FileSystemEntityType.directory; - /// Checks if [`type(path)`](type) returns [io.FileSystemEntityType.LINK]. + /// Checks if [`type(path)`](type) returns [io.FileSystemEntityType.link]. Future isLink(String path) async => await type(path, followLinks: false) == io.FileSystemEntityType.link; /// Synchronously checks if [`type(path)`](type) returns - /// [io.FileSystemEntityType.LINK]. + /// [io.FileSystemEntityType.link]. bool isLinkSync(String path) => typeSync(path, followLinks: false) == io.FileSystemEntityType.link; diff --git a/pkgs/file/lib/src/io.dart b/pkgs/file/lib/src/io.dart index 9d57e7869..28c1d6dfa 100644 --- a/pkgs/file/lib/src/io.dart +++ b/pkgs/file/lib/src/io.dart @@ -8,6 +8,8 @@ /// the `file` package. The `file` package re-exports these interfaces (or in /// some cases, implementations of these interfaces by the same name), so this /// file need not be exposes publicly and exists for internal use only. +library; + export 'dart:io' show Directory, diff --git a/pkgs/file/pubspec.yaml b/pkgs/file/pubspec.yaml index 5de5d37c1..0ad65b0d6 100644 --- a/pkgs/file/pubspec.yaml +++ b/pkgs/file/pubspec.yaml @@ -1,5 +1,5 @@ name: file -version: 7.0.1 +version: 7.0.2-wip description: A pluggable, mockable file system abstraction for Dart. repository: https://github.com/dart-lang/tools/tree/main/pkgs/file issue_tracker: https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Afile @@ -12,6 +12,10 @@ dependencies: path: ^1.8.3 dev_dependencies: + dart_flutter_team_lints: ^3.0.0 file_testing: ^3.0.0 - lints: ^2.0.1 test: ^1.23.1 + +dependency_overrides: + file_testing: + path: ../file_testing diff --git a/pkgs/file/test/chroot_test.dart b/pkgs/file/test/chroot_test.dart index 6c34ff200..cf23f4755 100644 --- a/pkgs/file/test/chroot_test.dart +++ b/pkgs/file/test/chroot_test.dart @@ -3,6 +3,8 @@ // BSD-style license that can be found in the LICENSE file. @TestOn('vm') +library; + import 'dart:io' as io; import 'package:file/chroot.dart'; @@ -17,14 +19,15 @@ import 'common_tests.dart'; void main() { group('ChrootFileSystem', () { ChrootFileSystem createMemoryBackedChrootFileSystem() { - MemoryFileSystem fs = MemoryFileSystem(); + var fs = MemoryFileSystem(); fs.directory('/tmp').createSync(); return ChrootFileSystem(fs, '/tmp'); } // TODO(jamesderlin): Make ChrootFile.openSync return a delegating // RandomAccessFile that uses the chroot'd path. - List skipCommon = [ + var skipCommon = [ + // ignore: lines_longer_than_80_chars 'File > open > .* > RandomAccessFile > read > openReadHandleDoesNotChange', 'File > open > .* > RandomAccessFile > openWriteHandleDoesNotChange', ]; @@ -137,6 +140,7 @@ void main() { test('referencesRootEntityForJailbreakPath', () { mem.file('/foo').createSync(); dynamic f = fs.file('../foo'); + // ignore: avoid_dynamic_calls expect(f.delegate.path, '/tmp/foo'); }); }); @@ -151,7 +155,7 @@ void main() { group('copy', () { test('copiesToRootDirectoryIfDestinationIsJailbreakPath', () { - File f = fs.file('/foo')..createSync(); + var f = fs.file('/foo')..createSync(); f.copySync('../bar'); expect(mem.file('/bar'), isNot(exists)); expect(mem.file('/tmp/bar'), exists); diff --git a/pkgs/file/test/common_tests.dart b/pkgs/file/test/common_tests.dart index 6028c7715..491d4f985 100644 --- a/pkgs/file/test/common_tests.dart +++ b/pkgs/file/test/common_tests.dart @@ -3,6 +3,8 @@ // BSD-style license that can be found in the LICENSE file. @TestOn('vm') +library; + import 'dart:async'; import 'dart:convert'; import 'dart:io' as io; @@ -10,8 +12,8 @@ import 'dart:io' as io; import 'package:file/file.dart'; import 'package:file_testing/file_testing.dart'; import 'package:path/path.dart' as p; -import 'package:test/test.dart'; import 'package:test/test.dart' as testpkg show group, setUp, tearDown, test; +import 'package:test/test.dart'; import 'utils.dart'; @@ -54,7 +56,7 @@ void runCommonTests( List skip = const [], FileSystemGenerator? replay, }) { - RootPathGenerator? rootfn = root; + var rootfn = root; group('common', () { late FileSystemGenerator createFs; @@ -62,7 +64,7 @@ void runCommonTests( late List tearDowns; late FileSystem fs; late String root; - List stack = []; + var stack = []; void skipIfNecessary(String description, void Function() callback) { stack.add(description); @@ -105,7 +107,7 @@ void runCommonTests( testpkg.setUp(() async { await Future.forEach(setUps, (SetUpTearDown setUp) => setUp()); await body(); - for (SetUpTearDown tearDown in tearDowns) { + for (var tearDown in tearDowns) { await tearDown(); } createFs = replay; @@ -115,7 +117,7 @@ void runCommonTests( testpkg.test(description, body, skip: skip); testpkg.tearDown(() async { - for (SetUpTearDown tearDown in tearDowns) { + for (var tearDown in tearDowns) { await tearDown(); } }); @@ -126,13 +128,13 @@ void runCommonTests( /// Returns [path] prefixed by the [root] namespace. /// This is only intended for absolute paths. String ns(String path) { - p.Context posix = p.Context(style: p.Style.posix); - List parts = posix.split(path); + var posix = p.Context(style: p.Style.posix); + var parts = posix.split(path); parts[0] = root; path = fs.path.joinAll(parts); - String rootPrefix = fs.path.rootPrefix(path); + var rootPrefix = fs.path.rootPrefix(path); assert(rootPrefix.isNotEmpty); - String result = root == rootPrefix + var result = root == rootPrefix ? path : (path == rootPrefix ? root @@ -160,7 +162,7 @@ void runCommonTests( test('succeedsWithUriArgument', () { fs.directory(ns('/foo')).createSync(); - Uri uri = fs.path.toUri(ns('/foo')); + var uri = fs.path.toUri(ns('/foo')); expect(fs.directory(uri), exists); }); @@ -173,11 +175,11 @@ void runCommonTests( }); // Fails due to - // https://github.com/google/file.dart/issues/112 + // https://github.com/dart-lang/tools/issues/632 test('considersBothSlashesEquivalent', () { fs.directory(r'foo\bar_dir').createSync(recursive: true); expect(fs.directory(r'foo/bar_dir'), exists); - }, skip: 'Fails due to https://github.com/google/file.dart/issues/112'); + }, skip: 'Fails due to https://github.com/dart-lang/tools/issues/632'); }); group('file', () { @@ -191,7 +193,7 @@ void runCommonTests( test('succeedsWithUriArgument', () { fs.file(ns('/foo')).createSync(); - Uri uri = fs.path.toUri(ns('/foo')); + var uri = fs.path.toUri(ns('/foo')); expect(fs.file(uri), exists); }); @@ -204,11 +206,11 @@ void runCommonTests( }); // Fails due to - // https://github.com/google/file.dart/issues/112 + // https://github.com/dart-lang/tools/issues/632 test('considersBothSlashesEquivalent', () { fs.file(r'foo\bar_file').createSync(recursive: true); expect(fs.file(r'foo/bar_file'), exists); - }, skip: 'Fails due to https://github.com/google/file.dart/issues/112'); + }, skip: 'Fails due to https://github.com/dart-lang/tools/issues/632'); }); group('link', () { @@ -223,7 +225,7 @@ void runCommonTests( test('succeedsWithUriArgument', () { fs.file(ns('/foo')).createSync(); fs.link(ns('/bar')).createSync(ns('/foo')); - Uri uri = fs.path.toUri(ns('/bar')); + var uri = fs.path.toUri(ns('/bar')); expect(fs.link(uri), exists); }); @@ -248,7 +250,7 @@ void runCommonTests( group('systemTempDirectory', () { test('existsAsDirectory', () { - Directory tmp = fs.systemTempDirectory; + var tmp = fs.systemTempDirectory; expect(tmp, isDirectory); expect(tmp, exists); }); @@ -318,7 +320,7 @@ void runCommonTests( test('staysAtRootIfSetToParentOfRoot', () { fs.currentDirectory = List.filled(20, '..').join(fs.path.separator); - String cwd = fs.currentDirectory.path; + var cwd = fs.currentDirectory.path; expect(cwd, fs.path.rootPrefix(cwd)); }); @@ -371,36 +373,36 @@ void runCommonTests( group('stat', () { test('isNotFoundForEmptyPath', () { - FileStat stat = fs.statSync(''); + var stat = fs.statSync(''); expect(stat.type, FileSystemEntityType.notFound); }); test('isNotFoundForPathToNonExistentEntityAtTail', () { - FileStat stat = fs.statSync(ns('/foo')); + var stat = fs.statSync(ns('/foo')); expect(stat.type, FileSystemEntityType.notFound); }); test('isNotFoundForPathToNonExistentEntityInTraversal', () { - FileStat stat = fs.statSync(ns('/foo/bar')); + var stat = fs.statSync(ns('/foo/bar')); expect(stat.type, FileSystemEntityType.notFound); }); test('isDirectoryForDirectory', () { fs.directory(ns('/foo')).createSync(); - FileStat stat = fs.statSync(ns('/foo')); + var stat = fs.statSync(ns('/foo')); expect(stat.type, FileSystemEntityType.directory); }); test('isFileForFile', () { fs.file(ns('/foo')).createSync(); - FileStat stat = fs.statSync(ns('/foo')); + var stat = fs.statSync(ns('/foo')); expect(stat.type, FileSystemEntityType.file); }); test('isFileForLinkToFile', () { fs.file(ns('/foo')).createSync(); fs.link(ns('/bar')).createSync(ns('/foo')); - FileStat stat = fs.statSync(ns('/bar')); + var stat = fs.statSync(ns('/bar')); expect(stat.type, FileSystemEntityType.file); }); @@ -408,7 +410,7 @@ void runCommonTests( fs.link(ns('/foo')).createSync(ns('/bar')); fs.link(ns('/bar')).createSync(ns('/baz')); fs.link(ns('/baz')).createSync(ns('/foo')); - FileStat stat = fs.statSync(ns('/foo')); + var stat = fs.statSync(ns('/foo')); expect(stat.type, FileSystemEntityType.notFound); }); }); @@ -454,18 +456,18 @@ void runCommonTests( group('type', () { test('isFileForFile', () { fs.file(ns('/foo')).createSync(); - FileSystemEntityType type = fs.typeSync(ns('/foo')); + var type = fs.typeSync(ns('/foo')); expect(type, FileSystemEntityType.file); }); test('isDirectoryForDirectory', () { fs.directory(ns('/foo')).createSync(); - FileSystemEntityType type = fs.typeSync(ns('/foo')); + var type = fs.typeSync(ns('/foo')); expect(type, FileSystemEntityType.directory); }); test('isDirectoryForAncestorOfRoot', () { - FileSystemEntityType type = fs + var type = fs .typeSync(List.filled(20, '..').join(fs.path.separator)); expect(type, FileSystemEntityType.directory); }); @@ -473,15 +475,14 @@ void runCommonTests( test('isFileForLinkToFileAndFollowLinksTrue', () { fs.file(ns('/foo')).createSync(); fs.link(ns('/bar')).createSync(ns('/foo')); - FileSystemEntityType type = fs.typeSync(ns('/bar')); + var type = fs.typeSync(ns('/bar')); expect(type, FileSystemEntityType.file); }); test('isLinkForLinkToFileAndFollowLinksFalse', () { fs.file(ns('/foo')).createSync(); fs.link(ns('/bar')).createSync(ns('/foo')); - FileSystemEntityType type = - fs.typeSync(ns('/bar'), followLinks: false); + var type = fs.typeSync(ns('/bar'), followLinks: false); expect(type, FileSystemEntityType.link); }); @@ -489,17 +490,17 @@ void runCommonTests( fs.link(ns('/foo')).createSync(ns('/bar')); fs.link(ns('/bar')).createSync(ns('/baz')); fs.link(ns('/baz')).createSync(ns('/foo')); - FileSystemEntityType type = fs.typeSync(ns('/foo')); + var type = fs.typeSync(ns('/foo')); expect(type, FileSystemEntityType.notFound); }); test('isNotFoundForNoEntityAtTail', () { - FileSystemEntityType type = fs.typeSync(ns('/foo')); + var type = fs.typeSync(ns('/foo')); expect(type, FileSystemEntityType.notFound); }); test('isNotFoundForNoDirectoryInTraversal', () { - FileSystemEntityType type = fs.typeSync(ns('/foo/bar/baz')); + var type = fs.typeSync(ns('/foo/bar/baz')); expect(type, FileSystemEntityType.notFound); }); }); @@ -676,8 +677,8 @@ void runCommonTests( }); test('succeedsIfDestinationDoesntExist', () { - Directory src = fs.directory(ns('/foo'))..createSync(); - Directory dest = src.renameSync(ns('/bar')); + var src = fs.directory(ns('/foo'))..createSync(); + var dest = src.renameSync(ns('/bar')); expect(dest.path, ns('/bar')); expect(dest, exists); }); @@ -686,8 +687,8 @@ void runCommonTests( 'succeedsIfDestinationIsEmptyDirectory', () { fs.directory(ns('/bar')).createSync(); - Directory src = fs.directory(ns('/foo'))..createSync(); - Directory dest = src.renameSync(ns('/bar')); + var src = fs.directory(ns('/foo'))..createSync(); + var dest = src.renameSync(ns('/bar')); expect(src, isNot(exists)); expect(dest, exists); }, @@ -697,14 +698,14 @@ void runCommonTests( test('throwsIfDestinationIsFile', () { fs.file(ns('/bar')).createSync(); - Directory src = fs.directory(ns('/foo'))..createSync(); + var src = fs.directory(ns('/foo'))..createSync(); expectFileSystemException(ErrorCodes.ENOTDIR, () { src.renameSync(ns('/bar')); }); }); test('throwsIfDestinationParentFolderDoesntExist', () { - Directory src = fs.directory(ns('/foo'))..createSync(); + var src = fs.directory(ns('/foo'))..createSync(); expectFileSystemException(ErrorCodes.ENOENT, () { src.renameSync(ns('/bar/baz')); }); @@ -712,7 +713,7 @@ void runCommonTests( test('throwsIfDestinationIsNonEmptyDirectory', () { fs.file(ns('/bar/baz')).createSync(recursive: true); - Directory src = fs.directory(ns('/foo'))..createSync(); + var src = fs.directory(ns('/foo'))..createSync(); // The error will be 'Directory not empty' on OS X, but it will be // 'File exists' on Linux. expectFileSystemException( @@ -749,7 +750,7 @@ void runCommonTests( }); test('throwsIfDestinationIsLinkToNotFound', () { - Directory src = fs.directory(ns('/foo'))..createSync(); + var src = fs.directory(ns('/foo'))..createSync(); fs.link(ns('/bar')).createSync(ns('/baz')); expectFileSystemException(ErrorCodes.ENOTDIR, () { src.renameSync(ns('/bar')); @@ -757,7 +758,7 @@ void runCommonTests( }); test('throwsIfDestinationIsLinkToEmptyDirectory', () { - Directory src = fs.directory(ns('/foo'))..createSync(); + var src = fs.directory(ns('/foo'))..createSync(); fs.directory(ns('/bar')).createSync(); fs.link(ns('/baz')).createSync(ns('/bar')); expectFileSystemException(ErrorCodes.ENOTDIR, () { @@ -766,7 +767,7 @@ void runCommonTests( }); test('succeedsIfDestinationIsInDifferentDirectory', () { - Directory src = fs.directory(ns('/foo'))..createSync(); + var src = fs.directory(ns('/foo'))..createSync(); fs.directory(ns('/bar')).createSync(); src.renameSync(ns('/bar/baz')); expect(fs.typeSync(ns('/foo')), FileSystemEntityType.notFound); @@ -790,24 +791,24 @@ void runCommonTests( group('delete', () { test('returnsCovariantType', () async { - Directory dir = fs.directory(ns('/foo'))..createSync(); + var dir = fs.directory(ns('/foo'))..createSync(); expect(await dir.delete(), isDirectory); }); test('succeedsIfEmptyDirectoryExistsAndRecursiveFalse', () { - Directory dir = fs.directory(ns('/foo'))..createSync(); + var dir = fs.directory(ns('/foo'))..createSync(); dir.deleteSync(); expect(dir, isNot(exists)); }); test('succeedsIfEmptyDirectoryExistsAndRecursiveTrue', () { - Directory dir = fs.directory(ns('/foo'))..createSync(); + var dir = fs.directory(ns('/foo'))..createSync(); dir.deleteSync(recursive: true); expect(dir, isNot(exists)); }); test('throwsIfNonEmptyDirectoryExistsAndRecursiveFalse', () { - Directory dir = fs.directory(ns('/foo'))..createSync(); + var dir = fs.directory(ns('/foo'))..createSync(); fs.file(ns('/foo/bar')).createSync(); expectFileSystemException(ErrorCodes.ENOTEMPTY, () { dir.deleteSync(); @@ -815,7 +816,7 @@ void runCommonTests( }); test('succeedsIfNonEmptyDirectoryExistsAndRecursiveTrue', () { - Directory dir = fs.directory(ns('/foo'))..createSync(); + var dir = fs.directory(ns('/foo'))..createSync(); fs.file(ns('/foo/bar')).createSync(); dir.deleteSync(recursive: true); expect(fs.directory(ns('/foo')), isNot(exists)); @@ -997,7 +998,7 @@ void runCommonTests( test('handlesParentAndThisFolderReferences', () { fs.directory(ns('/foo/bar/baz')).createSync(recursive: true); fs.link(ns('/foo/bar/baz/qux')).createSync(fs.path.join('..', '..')); - String resolved = fs + var resolved = fs .directory(ns('/foo/./bar/baz/../baz/qux/bar')) .resolveSymbolicLinksSync(); expect(resolved, ns('/foo/bar')); @@ -1015,7 +1016,7 @@ void runCommonTests( .createSync(fs.path.join('..', '..', 'qux'), recursive: true); fs.link(ns('/qux')).createSync('quux'); fs.link(ns('/quux/quuz')).createSync(ns('/foo'), recursive: true); - String resolved = fs + var resolved = fs .directory(ns('/foo//bar/./baz/quuz/bar/..///bar/baz/')) .resolveSymbolicLinksSync(); expect(resolved, ns('/quux')); @@ -1069,29 +1070,29 @@ void runCommonTests( test('resolvesNameCollisions', () { fs.directory(ns('/foo/bar')).createSync(recursive: true); - Directory tmp = fs.directory(ns('/foo')).createTempSync('bar'); + var tmp = fs.directory(ns('/foo')).createTempSync('bar'); expect(tmp.path, allOf(isNot(ns('/foo/bar')), startsWith(ns('/foo/bar')))); }); test('succeedsWithoutPrefix', () { - Directory dir = fs.directory(ns('/foo'))..createSync(); + var dir = fs.directory(ns('/foo'))..createSync(); expect(dir.createTempSync().path, startsWith(ns('/foo/'))); }); test('succeedsWithPrefix', () { - Directory dir = fs.directory(ns('/foo'))..createSync(); + var dir = fs.directory(ns('/foo'))..createSync(); expect(dir.createTempSync('bar').path, startsWith(ns('/foo/bar'))); }); test('succeedsWithNestedPathPrefixThatExists', () { fs.directory(ns('/foo/bar')).createSync(recursive: true); - Directory tmp = fs.directory(ns('/foo')).createTempSync('bar/baz'); + var tmp = fs.directory(ns('/foo')).createTempSync('bar/baz'); expect(tmp.path, startsWith(ns('/foo/bar/baz'))); }); test('throwsWithNestedPathPrefixThatDoesntExist', () { - Directory dir = fs.directory(ns('/foo'))..createSync(); + var dir = fs.directory(ns('/foo'))..createSync(); expectFileSystemException(ErrorCodes.ENOENT, () { dir.createTempSync('bar/baz'); }); @@ -1123,7 +1124,7 @@ void runCommonTests( }); test('returnsEmptyListForEmptyDirectory', () { - Directory empty = fs.directory(ns('/bar'))..createSync(); + var empty = fs.directory(ns('/bar'))..createSync(); expect(empty.listSync(), isEmpty); }); @@ -1134,7 +1135,7 @@ void runCommonTests( }); test('returnsLinkObjectsIfFollowLinksFalse', () { - List list = dir.listSync(followLinks: false); + var list = dir.listSync(followLinks: false); expect(list, hasLength(3)); expect(list, contains(allOf(isFile, hasPath(ns('/foo/bar'))))); expect(list, contains(allOf(isDirectory, hasPath(ns('/foo/baz'))))); @@ -1142,7 +1143,7 @@ void runCommonTests( }); test('followsLinksIfFollowLinksTrue', () { - List list = dir.listSync(); + var list = dir.listSync(); expect(list, hasLength(3)); expect(list, contains(allOf(isFile, hasPath(ns('/foo/bar'))))); expect(list, contains(allOf(isDirectory, hasPath(ns('/foo/baz'))))); @@ -1189,8 +1190,7 @@ void runCommonTests( test('childEntriesNotNormalized', () { dir = fs.directory(ns('/bar/baz'))..createSync(recursive: true); fs.file(ns('/bar/baz/qux')).createSync(); - List list = - fs.directory(ns('/bar//../bar/./baz')).listSync(); + var list = fs.directory(ns('/bar//../bar/./baz')).listSync(); expect(list, hasLength(1)); expect(list[0], allOf(isFile, hasPath(ns('/bar//../bar/./baz/qux')))); }); @@ -1198,9 +1198,8 @@ void runCommonTests( test('symlinksToNotFoundAlwaysReturnedAsLinks', () { dir = fs.directory(ns('/bar'))..createSync(); fs.link(ns('/bar/baz')).createSync('qux'); - for (bool followLinks in const [true, false]) { - List list = - dir.listSync(followLinks: followLinks); + for (var followLinks in const [true, false]) { + var list = dir.listSync(followLinks: followLinks); expect(list, hasLength(1)); expect(list[0], allOf(isLink, hasPath(ns('/bar/baz')))); } @@ -1208,7 +1207,7 @@ void runCommonTests( }); test('childEntities', () { - Directory dir = fs.directory(ns('/foo'))..createSync(); + var dir = fs.directory(ns('/foo'))..createSync(); dir.childDirectory('bar').createSync(); dir.childFile('baz').createSync(); dir.childLink('qux').createSync('bar'); @@ -1321,22 +1320,22 @@ void runCommonTests( }); test('succeedsIfDestinationDoesntExistAtTail', () { - File src = fs.file(ns('/foo'))..createSync(); - File dest = src.renameSync(ns('/bar')); + var src = fs.file(ns('/foo'))..createSync(); + var dest = src.renameSync(ns('/bar')); expect(fs.file(ns('/foo')), isNot(exists)); expect(fs.file(ns('/bar')), exists); expect(dest.path, ns('/bar')); }); test('throwsIfDestinationDoesntExistViaTraversal', () { - File f = fs.file(ns('/foo'))..createSync(); + var f = fs.file(ns('/foo'))..createSync(); expectFileSystemException(ErrorCodes.ENOENT, () { f.renameSync(ns('/bar/baz')); }); }); test('succeedsIfDestinationExistsAsFile', () { - File f = fs.file(ns('/foo'))..createSync(); + var f = fs.file(ns('/foo'))..createSync(); fs.file(ns('/bar')).createSync(); f.renameSync(ns('/bar')); expect(fs.file(ns('/foo')), isNot(exists)); @@ -1344,7 +1343,7 @@ void runCommonTests( }); test('throwsIfDestinationExistsAsDirectory', () { - File f = fs.file(ns('/foo'))..createSync(); + var f = fs.file(ns('/foo'))..createSync(); fs.directory(ns('/bar')).createSync(); expectFileSystemException(ErrorCodes.EISDIR, () { f.renameSync(ns('/bar')); @@ -1352,7 +1351,7 @@ void runCommonTests( }); test('succeedsIfDestinationExistsAsLinkToFile', () { - File f = fs.file(ns('/foo'))..createSync(); + var f = fs.file(ns('/foo'))..createSync(); fs.file(ns('/bar')).createSync(); fs.link(ns('/baz')).createSync(ns('/bar')); f.renameSync(ns('/baz')); @@ -1364,7 +1363,7 @@ void runCommonTests( }); test('throwsIfDestinationExistsAsLinkToDirectory', () { - File f = fs.file(ns('/foo'))..createSync(); + var f = fs.file(ns('/foo'))..createSync(); fs.directory(ns('/bar')).createSync(); fs.link(ns('/baz')).createSync(ns('/bar')); expectFileSystemException(ErrorCodes.EISDIR, () { @@ -1373,7 +1372,7 @@ void runCommonTests( }); test('succeedsIfDestinationExistsAsLinkToNotFound', () { - File f = fs.file(ns('/foo'))..createSync(); + var f = fs.file(ns('/foo'))..createSync(); fs.link(ns('/bar')).createSync(ns('/baz')); f.renameSync(ns('/bar')); expect(fs.typeSync(ns('/foo')), FileSystemEntityType.notFound); @@ -1429,7 +1428,7 @@ void runCommonTests( }); test('succeedsIfDestinationDoesntExistAtTail', () { - File f = fs.file(ns('/foo')) + var f = fs.file(ns('/foo')) ..createSync() ..writeAsStringSync('foo'); f.copySync(ns('/bar')); @@ -1439,14 +1438,14 @@ void runCommonTests( }); test('throwsIfDestinationDoesntExistViaTraversal', () { - File f = fs.file(ns('/foo'))..createSync(); + var f = fs.file(ns('/foo'))..createSync(); expectFileSystemException(ErrorCodes.ENOENT, () { f.copySync(ns('/bar/baz')); }); }); test('succeedsIfDestinationExistsAsFile', () { - File f = fs.file(ns('/foo')) + var f = fs.file(ns('/foo')) ..createSync() ..writeAsStringSync('foo'); fs.file(ns('/bar')) @@ -1460,7 +1459,7 @@ void runCommonTests( }); test('throwsIfDestinationExistsAsDirectory', () { - File f = fs.file(ns('/foo'))..createSync(); + var f = fs.file(ns('/foo'))..createSync(); fs.directory(ns('/bar')).createSync(); expectFileSystemException(ErrorCodes.EISDIR, () { f.copySync(ns('/bar')); @@ -1468,7 +1467,7 @@ void runCommonTests( }); test('succeedsIfDestinationExistsAsLinkToFile', () { - File f = fs.file(ns('/foo')) + var f = fs.file(ns('/foo')) ..createSync() ..writeAsStringSync('foo'); fs.file(ns('/bar')) @@ -1487,7 +1486,7 @@ void runCommonTests( }, skip: io.Platform.isWindows /* No links on Windows */); test('throwsIfDestinationExistsAsLinkToDirectory', () { - File f = fs.file(ns('/foo'))..createSync(); + var f = fs.file(ns('/foo'))..createSync(); fs.directory(ns('/bar')).createSync(); fs.link(ns('/baz')).createSync(ns('/bar')); expectFileSystemException(ErrorCodes.EISDIR, () { @@ -1525,7 +1524,7 @@ void runCommonTests( }); test('succeedsIfDestinationIsInDifferentDirectoryThanSource', () { - File f = fs.file(ns('/foo/bar')) + var f = fs.file(ns('/foo/bar')) ..createSync(recursive: true) ..writeAsStringSync('foo'); fs.directory(ns('/baz')).createSync(); @@ -1587,12 +1586,12 @@ void runCommonTests( }); test('returnsZeroForNewlyCreatedFile', () { - File f = fs.file(ns('/foo'))..createSync(); + var f = fs.file(ns('/foo'))..createSync(); expect(f.lengthSync(), 0); }); test('writeNBytesReturnsLengthN', () { - File f = fs.file(ns('/foo'))..createSync(); + var f = fs.file(ns('/foo'))..createSync(); f.writeAsBytesSync([1, 2, 3, 4], flush: true); expect(f.lengthSync(), 4); }); @@ -1616,10 +1615,10 @@ void runCommonTests( group('lastAccessed', () { test('isNowForNewlyCreatedFile', () { - DateTime before = downstairs(); - File f = fs.file(ns('/foo'))..createSync(); - DateTime after = ceil(); - DateTime accessed = f.lastAccessedSync(); + var before = downstairs(); + var f = fs.file(ns('/foo'))..createSync(); + var after = ceil(); + var accessed = f.lastAccessedSync(); expect(accessed, isSameOrAfter(before)); expect(accessed, isSameOrBefore(after)); }); @@ -1638,18 +1637,18 @@ void runCommonTests( }); test('succeedsIfExistsAsLinkToFile', () { - DateTime before = downstairs(); + var before = downstairs(); fs.file(ns('/foo')).createSync(); fs.link(ns('/bar')).createSync(ns('/foo')); - DateTime after = ceil(); - DateTime accessed = fs.file(ns('/bar')).lastAccessedSync(); + var after = ceil(); + var accessed = fs.file(ns('/bar')).lastAccessedSync(); expect(accessed, isSameOrAfter(before)); expect(accessed, isSameOrBefore(after)); }); }); group('setLastAccessed', () { - final DateTime time = DateTime(1999); + final time = DateTime(1999); test('throwsIfDoesntExist', () { expectFileSystemException(ErrorCodes.ENOENT, () { @@ -1665,13 +1664,13 @@ void runCommonTests( }); test('succeedsIfExistsAsFile', () { - File f = fs.file(ns('/foo'))..createSync(); + var f = fs.file(ns('/foo'))..createSync(); f.setLastAccessedSync(time); expect(fs.file(ns('/foo')).lastAccessedSync(), time); }); test('succeedsIfExistsAsLinkToFile', () { - File f = fs.file(ns('/foo'))..createSync(); + var f = fs.file(ns('/foo'))..createSync(); fs.link(ns('/bar')).createSync(ns('/foo')); f.setLastAccessedSync(time); expect(fs.file(ns('/bar')).lastAccessedSync(), time); @@ -1680,10 +1679,10 @@ void runCommonTests( group('lastModified', () { test('isNowForNewlyCreatedFile', () { - DateTime before = downstairs(); - File f = fs.file(ns('/foo'))..createSync(); - DateTime after = ceil(); - DateTime modified = f.lastModifiedSync(); + var before = downstairs(); + var f = fs.file(ns('/foo'))..createSync(); + var after = ceil(); + var modified = f.lastModifiedSync(); expect(modified, isSameOrAfter(before)); expect(modified, isSameOrBefore(after)); }); @@ -1702,18 +1701,18 @@ void runCommonTests( }); test('succeedsIfExistsAsLinkToFile', () { - DateTime before = downstairs(); + var before = downstairs(); fs.file(ns('/foo')).createSync(); fs.link(ns('/bar')).createSync(ns('/foo')); - DateTime after = ceil(); - DateTime modified = fs.file(ns('/bar')).lastModifiedSync(); + var after = ceil(); + var modified = fs.file(ns('/bar')).lastModifiedSync(); expect(modified, isSameOrAfter(before)); expect(modified, isSameOrBefore(after)); }); }); group('setLastModified', () { - final DateTime time = DateTime(1999); + final time = DateTime(1999); test('throwsIfDoesntExist', () { expectFileSystemException(ErrorCodes.ENOENT, () { @@ -1729,13 +1728,13 @@ void runCommonTests( }); test('succeedsIfExistsAsFile', () { - File f = fs.file(ns('/foo'))..createSync(); + var f = fs.file(ns('/foo'))..createSync(); f.setLastModifiedSync(time); expect(fs.file(ns('/foo')).lastModifiedSync(), time); }); test('succeedsIfExistsAsLinkToFile', () { - File f = fs.file(ns('/foo'))..createSync(); + var f = fs.file(ns('/foo'))..createSync(); fs.link(ns('/bar')).createSync(ns('/foo')); f.setLastModifiedSync(time); expect(fs.file(ns('/bar')).lastModifiedSync(), time); @@ -1752,7 +1751,7 @@ void runCommonTests( }); } else { test('createsFileIfDoesntExistAtTail', () { - RandomAccessFile raf = fs.file(ns('/bar')).openSync(mode: mode); + var raf = fs.file(ns('/bar')).openSync(mode: mode); raf.closeSync(); expect(fs.file(ns('/bar')), exists); }); @@ -1877,39 +1876,39 @@ void runCommonTests( }); test('readIntoWithBufferLargerThanContent', () { - List buffer = List.filled(1024, 0); - int numRead = raf.readIntoSync(buffer); + var buffer = List.filled(1024, 0); + var numRead = raf.readIntoSync(buffer); expect(numRead, 21); expect(utf8.decode(buffer.sublist(0, 21)), 'pre-existing content\n'); }); test('readIntoWithBufferSmallerThanContent', () { - List buffer = List.filled(10, 0); - int numRead = raf.readIntoSync(buffer); + var buffer = List.filled(10, 0); + var numRead = raf.readIntoSync(buffer); expect(numRead, 10); expect(utf8.decode(buffer), 'pre-existi'); }); test('readIntoWithStart', () { - List buffer = List.filled(10, 0); - int numRead = raf.readIntoSync(buffer, 2); + var buffer = List.filled(10, 0); + var numRead = raf.readIntoSync(buffer, 2); expect(numRead, 8); expect(utf8.decode(buffer.sublist(2)), 'pre-exis'); }); test('readIntoWithStartAndEnd', () { - List buffer = List.filled(10, 0); - int numRead = raf.readIntoSync(buffer, 2, 5); + var buffer = List.filled(10, 0); + var numRead = raf.readIntoSync(buffer, 2, 5); expect(numRead, 3); expect(utf8.decode(buffer.sublist(2, 5)), 'pre'); }); test('openReadHandleDoesNotChange', () { - final String initial = utf8.decode(raf.readSync(4)); + final initial = utf8.decode(raf.readSync(4)); expect(initial, 'pre-'); - final File newFile = f.renameSync(ns('/bar')); - String rest = utf8.decode(raf.readSync(1024)); + final newFile = f.renameSync(ns('/bar')); + var rest = utf8.decode(raf.readSync(1024)); expect(rest, 'existing content\n'); assert(newFile.path != f.path); @@ -1942,13 +1941,13 @@ void runCommonTests( }); } else { test('lengthGrowsAsDataIsWritten', () { - int lengthBefore = f.lengthSync(); + var lengthBefore = f.lengthSync(); raf.writeByteSync(0xFACE); expect(raf.lengthSync(), lengthBefore + 1); }); test('flush', () { - int lengthBefore = f.lengthSync(); + var lengthBefore = f.lengthSync(); raf.writeByteSync(0xFACE); raf.flushSync(); expect(f.lengthSync(), lengthBefore + 1); @@ -2009,10 +2008,10 @@ void runCommonTests( test('openWriteHandleDoesNotChange', () { raf.writeStringSync('Hello '); - final File newFile = f.renameSync(ns('/bar')); + final newFile = f.renameSync(ns('/bar')); raf.writeStringSync('world'); - final String contents = newFile.readAsStringSync(); + final contents = newFile.readAsStringSync(); if (mode == FileMode.write || mode == FileMode.writeOnly) { expect(contents, 'Hello world'); } else { @@ -2067,7 +2066,7 @@ void runCommonTests( }); } else { test('growsAfterWrite', () { - int positionBefore = raf.positionSync(); + var positionBefore = raf.positionSync(); raf.writeStringSync('Hello world'); expect(raf.positionSync(), positionBefore + 11); }); @@ -2165,42 +2164,42 @@ void runCommonTests( group('openRead', () { test('throwsIfDoesntExist', () { - Stream> stream = fs.file(ns('/foo')).openRead(); + var stream = fs.file(ns('/foo')).openRead(); expect(stream.drain(), throwsFileSystemException(ErrorCodes.ENOENT)); }); test('succeedsIfExistsAsFile', () async { - File f = fs.file(ns('/foo'))..createSync(); + var f = fs.file(ns('/foo'))..createSync(); f.writeAsStringSync('Hello world', flush: true); - Stream> stream = f.openRead(); - List> data = await stream.toList(); + var stream = f.openRead(); + var data = await stream.toList(); expect(data, hasLength(1)); expect(utf8.decode(data[0]), 'Hello world'); }); test('throwsIfExistsAsDirectory', () { fs.directory(ns('/foo')).createSync(); - Stream> stream = fs.file(ns('/foo')).openRead(); + var stream = fs.file(ns('/foo')).openRead(); expect(stream.drain(), throwsFileSystemException(ErrorCodes.EISDIR)); }); test('succeedsIfExistsAsLinkToFile', () async { - File f = fs.file(ns('/foo'))..createSync(); + var f = fs.file(ns('/foo'))..createSync(); fs.link(ns('/bar')).createSync(ns('/foo')); f.writeAsStringSync('Hello world', flush: true); - Stream> stream = fs.file(ns('/bar')).openRead(); - List> data = await stream.toList(); + var stream = fs.file(ns('/bar')).openRead(); + var data = await stream.toList(); expect(data, hasLength(1)); expect(utf8.decode(data[0]), 'Hello world'); }); test('respectsStartAndEndParameters', () async { - File f = fs.file(ns('/foo'))..createSync(); + var f = fs.file(ns('/foo'))..createSync(); f.writeAsStringSync('Hello world', flush: true); - Stream> stream = f.openRead(2); - List> data = await stream.toList(); + var stream = f.openRead(2); + var data = await stream.toList(); expect(data, hasLength(1)); expect(utf8.decode(data[0]), 'llo world'); stream = f.openRead(2, 5); @@ -2210,24 +2209,24 @@ void runCommonTests( }); test('throwsIfStartParameterIsNegative', () async { - File f = fs.file(ns('/foo'))..createSync(); - Stream> stream = f.openRead(-2); + var f = fs.file(ns('/foo'))..createSync(); + var stream = f.openRead(-2); expect(stream.drain(), throwsRangeError); }); test('stopsAtEndOfFileIfEndParameterIsPastEndOfFile', () async { - File f = fs.file(ns('/foo'))..createSync(); + var f = fs.file(ns('/foo'))..createSync(); f.writeAsStringSync('Hello world', flush: true); - Stream> stream = f.openRead(2, 1024); - List> data = await stream.toList(); + var stream = f.openRead(2, 1024); + var data = await stream.toList(); expect(data, hasLength(1)); expect(utf8.decode(data[0]), 'llo world'); }); test('providesSingleSubscriptionStream', () async { - File f = fs.file(ns('/foo'))..createSync(); + var f = fs.file(ns('/foo'))..createSync(); f.writeAsStringSync('Hello world', flush: true); - Stream> stream = f.openRead(); + var stream = f.openRead(); expect(stream.isBroadcast, isFalse); await stream.drain(); }); @@ -2237,20 +2236,20 @@ void runCommonTests( // split across multiple chunks in the [Stream]. However, there // doesn't seem to be a good way to determine the chunk size used by // [io.File]. - final List data = List.generate( + final data = List.generate( 1024 * 256, (int index) => index & 0xFF, growable: false, ); - final File f = fs.file(ns('/foo'))..createSync(); + final f = fs.file(ns('/foo'))..createSync(); f.writeAsBytesSync(data, flush: true); - final Stream> stream = f.openRead(); + final stream = f.openRead(); File? newFile; List? initialChunk; - final List remainingChunks = []; + final remainingChunks = []; await for (List chunk in stream) { if (initialChunk == null) { @@ -2276,7 +2275,7 @@ void runCommonTests( test('openReadCompatibleWithUtf8Decoder', () async { const content = 'Hello world!'; - File file = fs.file(ns('/foo')) + var file = fs.file(ns('/foo')) ..createSync() ..writeAsStringSync(content); expect( @@ -2315,8 +2314,8 @@ void runCommonTests( }); test('succeedsIfExistsAsEmptyFile', () async { - File f = fs.file(ns('/foo'))..createSync(); - IOSink sink = f.openWrite(); + var f = fs.file(ns('/foo'))..createSync(); + var sink = f.openWrite(); sink.write('Hello world'); await sink.flush(); await sink.close(); @@ -2326,7 +2325,7 @@ void runCommonTests( test('succeedsIfExistsAsLinkToFile', () async { fs.file(ns('/foo')).createSync(); fs.link(ns('/bar')).createSync(ns('/foo')); - IOSink sink = fs.file(ns('/bar')).openWrite(); + var sink = fs.file(ns('/bar')).openWrite(); sink.write('Hello world'); await sink.flush(); await sink.close(); @@ -2334,9 +2333,9 @@ void runCommonTests( }); test('overwritesContentInWriteMode', () async { - File f = fs.file(ns('/foo'))..createSync(); + var f = fs.file(ns('/foo'))..createSync(); f.writeAsStringSync('Hello'); - IOSink sink = f.openWrite(); + var sink = f.openWrite(); sink.write('Goodbye'); await sink.flush(); await sink.close(); @@ -2344,9 +2343,9 @@ void runCommonTests( }); test('appendsContentInAppendMode', () async { - File f = fs.file(ns('/foo'))..createSync(); + var f = fs.file(ns('/foo'))..createSync(); f.writeAsStringSync('Hello'); - IOSink sink = f.openWrite(mode: FileMode.append); + var sink = f.openWrite(mode: FileMode.append); sink.write('Goodbye'); await sink.flush(); await sink.close(); @@ -2354,12 +2353,12 @@ void runCommonTests( }); test('openWriteHandleDoesNotChange', () async { - File f = fs.file(ns('/foo'))..createSync(); - IOSink sink = f.openWrite(); + var f = fs.file(ns('/foo'))..createSync(); + var sink = f.openWrite(); sink.write('Hello'); await sink.flush(); - final File newFile = f.renameSync(ns('/bar')); + final newFile = f.renameSync(ns('/bar')); sink.write('Goodbye'); await sink.flush(); await sink.close(); @@ -2377,7 +2376,7 @@ void runCommonTests( late bool isSinkClosed; Future closeSink() { - Future future = sink.close(); + var future = sink.close(); isSinkClosed = true; return future; } @@ -2448,13 +2447,13 @@ void runCommonTests( test('ignoresCloseAfterAlreadyClosed', () async { sink.write('Hello world'); - Future f1 = closeSink(); - Future f2 = closeSink(); + var f1 = closeSink(); + var f2 = closeSink(); await Future.wait(>[f1, f2]); }); test('returnsAccurateDoneFuture', () async { - bool done = false; + var done = false; // ignore: unawaited_futures sink.done.then((dynamic _) => done = true); expect(done, isFalse); @@ -2469,7 +2468,7 @@ void runCommonTests( late bool isControllerClosed; Future closeController() { - Future future = controller.close(); + var future = controller.close(); isControllerClosed = true; return future; } @@ -2543,7 +2542,7 @@ void runCommonTests( }); test('succeedsIfExistsAsFile', () { - File f = fs.file(ns('/foo'))..createSync(); + var f = fs.file(ns('/foo'))..createSync(); f.writeAsBytesSync([1, 2, 3, 4]); expect(f.readAsBytesSync(), [1, 2, 3, 4]); }); @@ -2556,12 +2555,12 @@ void runCommonTests( }); test('returnsEmptyListForZeroByteFile', () { - File f = fs.file(ns('/foo'))..createSync(); + var f = fs.file(ns('/foo'))..createSync(); expect(f.readAsBytesSync(), isEmpty); }); test('returns a copy, not a view, of the file content', () { - File f = fs.file(ns('/foo'))..createSync(); + var f = fs.file(ns('/foo'))..createSync(); f.writeAsBytesSync([1, 2, 3, 4]); List result = f.readAsBytesSync(); expect(result, [1, 2, 3, 4]); @@ -2593,7 +2592,7 @@ void runCommonTests( }); test('succeedsIfExistsAsFile', () { - File f = fs.file(ns('/foo'))..createSync(); + var f = fs.file(ns('/foo'))..createSync(); f.writeAsStringSync('Hello world'); expect(f.readAsStringSync(), 'Hello world'); }); @@ -2606,14 +2605,14 @@ void runCommonTests( }); test('returnsEmptyStringForZeroByteFile', () { - File f = fs.file(ns('/foo'))..createSync(); + var f = fs.file(ns('/foo'))..createSync(); expect(f.readAsStringSync(), isEmpty); }); }); group('readAsLines', () { - const String testString = 'Hello world\nHow are you?\nI am fine'; - final List expectedLines = [ + const testString = 'Hello world\nHow are you?\nI am fine'; + final expectedLines = [ 'Hello world', 'How are you?', 'I am fine', @@ -2641,25 +2640,25 @@ void runCommonTests( }); test('succeedsIfExistsAsFile', () { - File f = fs.file(ns('/foo'))..createSync(); + var f = fs.file(ns('/foo'))..createSync(); f.writeAsStringSync(testString); expect(f.readAsLinesSync(), expectedLines); }); test('succeedsIfExistsAsLinkToFile', () { - File f = fs.file(ns('/foo'))..createSync(); + var f = fs.file(ns('/foo'))..createSync(); fs.link(ns('/bar')).createSync(ns('/foo')); f.writeAsStringSync(testString); expect(f.readAsLinesSync(), expectedLines); }); test('returnsEmptyListForZeroByteFile', () { - File f = fs.file(ns('/foo'))..createSync(); + var f = fs.file(ns('/foo'))..createSync(); expect(f.readAsLinesSync(), isEmpty); }); test('isTrailingNewlineAgnostic', () { - File f = fs.file(ns('/foo'))..createSync(); + var f = fs.file(ns('/foo'))..createSync(); f.writeAsStringSync('$testString\n'); expect(f.readAsLinesSync(), expectedLines); @@ -2677,7 +2676,7 @@ void runCommonTests( }); test('createsFileIfDoesntExist', () { - File f = fs.file(ns('/foo')); + var f = fs.file(ns('/foo')); expect(f, isNot(exists)); f.writeAsBytesSync([1, 2, 3, 4]); expect(f, exists); @@ -2699,21 +2698,21 @@ void runCommonTests( }); test('succeedsIfExistsAsLinkToFile', () { - File f = fs.file(ns('/foo'))..createSync(); + var f = fs.file(ns('/foo'))..createSync(); fs.link(ns('/bar')).createSync(ns('/foo')); fs.file(ns('/bar')).writeAsBytesSync([1, 2, 3, 4]); expect(f.readAsBytesSync(), [1, 2, 3, 4]); }); test('throwsIfFileModeRead', () { - File f = fs.file(ns('/foo'))..createSync(); + var f = fs.file(ns('/foo'))..createSync(); expectFileSystemException(ErrorCodes.EBADF, () { f.writeAsBytesSync([1], mode: FileMode.read); }); }); test('overwritesContentIfFileModeWrite', () { - File f = fs.file(ns('/foo'))..createSync(); + var f = fs.file(ns('/foo'))..createSync(); f.writeAsBytesSync([1, 2]); expect(f.readAsBytesSync(), [1, 2]); f.writeAsBytesSync([3, 4]); @@ -2721,7 +2720,7 @@ void runCommonTests( }); test('appendsContentIfFileModeAppend', () { - File f = fs.file(ns('/foo'))..createSync(); + var f = fs.file(ns('/foo'))..createSync(); f.writeAsBytesSync([1, 2], mode: FileMode.append); expect(f.readAsBytesSync(), [1, 2]); f.writeAsBytesSync([3, 4], mode: FileMode.append); @@ -2729,17 +2728,17 @@ void runCommonTests( }); test('acceptsEmptyBytesList', () { - File f = fs.file(ns('/foo'))..createSync(); + var f = fs.file(ns('/foo'))..createSync(); f.writeAsBytesSync([]); expect(f.readAsBytesSync(), []); }); test('updatesLastModifiedTime', () async { - File f = fs.file(ns('/foo'))..createSync(); - DateTime before = f.statSync().modified; + var f = fs.file(ns('/foo'))..createSync(); + var before = f.statSync().modified; await Future.delayed(const Duration(seconds: 2)); f.writeAsBytesSync([1, 2, 3]); - DateTime after = f.statSync().modified; + var after = f.statSync().modified; expect(after, isAfter(before)); }); }); @@ -2750,7 +2749,7 @@ void runCommonTests( }); test('createsFileIfDoesntExist', () { - File f = fs.file(ns('/foo')); + var f = fs.file(ns('/foo')); expect(f, isNot(exists)); f.writeAsStringSync('Hello world'); expect(f, exists); @@ -2772,21 +2771,21 @@ void runCommonTests( }); test('succeedsIfExistsAsLinkToFile', () { - File f = fs.file(ns('/foo'))..createSync(); + var f = fs.file(ns('/foo'))..createSync(); fs.link(ns('/bar')).createSync(ns('/foo')); fs.file(ns('/bar')).writeAsStringSync('Hello world'); expect(f.readAsStringSync(), 'Hello world'); }); test('throwsIfFileModeRead', () { - File f = fs.file(ns('/foo'))..createSync(); + var f = fs.file(ns('/foo'))..createSync(); expectFileSystemException(ErrorCodes.EBADF, () { f.writeAsStringSync('Hello world', mode: FileMode.read); }); }); test('overwritesContentIfFileModeWrite', () { - File f = fs.file(ns('/foo'))..createSync(); + var f = fs.file(ns('/foo'))..createSync(); f.writeAsStringSync('Hello world'); expect(f.readAsStringSync(), 'Hello world'); f.writeAsStringSync('Goodbye cruel world'); @@ -2794,7 +2793,7 @@ void runCommonTests( }); test('appendsContentIfFileModeAppend', () { - File f = fs.file(ns('/foo'))..createSync(); + var f = fs.file(ns('/foo'))..createSync(); f.writeAsStringSync('Hello', mode: FileMode.append); expect(f.readAsStringSync(), 'Hello'); f.writeAsStringSync('Goodbye', mode: FileMode.append); @@ -2802,7 +2801,7 @@ void runCommonTests( }); test('acceptsEmptyString', () { - File f = fs.file(ns('/foo'))..createSync(); + var f = fs.file(ns('/foo'))..createSync(); f.writeAsStringSync(''); expect(f.readAsStringSync(), isEmpty); }); @@ -2847,38 +2846,38 @@ void runCommonTests( group('stat', () { test('isNotFoundIfDoesntExistAtTail', () { - FileStat stat = fs.file(ns('/foo')).statSync(); + var stat = fs.file(ns('/foo')).statSync(); expect(stat.type, FileSystemEntityType.notFound); }); test('isNotFoundIfDoesntExistViaTraversal', () { - FileStat stat = fs.file(ns('/foo/bar')).statSync(); + var stat = fs.file(ns('/foo/bar')).statSync(); expect(stat.type, FileSystemEntityType.notFound); }); test('isDirectoryIfExistsAsDirectory', () { fs.directory(ns('/foo')).createSync(); - FileStat stat = fs.file(ns('/foo')).statSync(); + var stat = fs.file(ns('/foo')).statSync(); expect(stat.type, FileSystemEntityType.directory); }); test('isFileIfExistsAsFile', () { fs.file(ns('/foo')).createSync(); - FileStat stat = fs.file(ns('/foo')).statSync(); + var stat = fs.file(ns('/foo')).statSync(); expect(stat.type, FileSystemEntityType.file); }); test('isFileIfExistsAsLinkToFile', () { fs.file(ns('/foo')).createSync(); fs.link(ns('/bar')).createSync(ns('/foo')); - FileStat stat = fs.file(ns('/bar')).statSync(); + var stat = fs.file(ns('/bar')).statSync(); expect(stat.type, FileSystemEntityType.file); }); }); group('delete', () { test('returnsCovariantType', () async { - File f = fs.file(ns('/foo'))..createSync(); + var f = fs.file(ns('/foo'))..createSync(); expect(await f.delete(), isFile); }); @@ -2953,14 +2952,14 @@ void runCommonTests( group('uri', () { test('whenTargetIsDirectory', () { fs.directory(ns('/foo')).createSync(); - Link l = fs.link(ns('/bar'))..createSync(ns('/foo')); + var l = fs.link(ns('/bar'))..createSync(ns('/foo')); expect(l.uri, fs.path.toUri(ns('/bar'))); expect(fs.link('bar').uri.toString(), 'bar'); }); test('whenTargetIsFile', () { fs.file(ns('/foo')).createSync(); - Link l = fs.link(ns('/bar'))..createSync(ns('/foo')); + var l = fs.link(ns('/bar'))..createSync(ns('/foo')); expect(l.uri, fs.path.toUri(ns('/bar'))); expect(fs.link('bar').uri.toString(), 'bar'); }); @@ -2991,24 +2990,24 @@ void runCommonTests( }); test('isTrueIfTargetIsNotFound', () { - Link l = fs.link(ns('/foo'))..createSync(ns('/bar')); + var l = fs.link(ns('/foo'))..createSync(ns('/bar')); expect(l, exists); }); test('isTrueIfTargetIsFile', () { - Link l = fs.link(ns('/foo'))..createSync(ns('/bar')); + var l = fs.link(ns('/foo'))..createSync(ns('/bar')); fs.file(ns('/bar')).createSync(); expect(l, exists); }); test('isTrueIfTargetIsDirectory', () { - Link l = fs.link(ns('/foo'))..createSync(ns('/bar')); + var l = fs.link(ns('/foo'))..createSync(ns('/bar')); fs.directory(ns('/bar')).createSync(); expect(l, exists); }); test('isTrueIfTargetIsLinkLoop', () { - Link l = fs.link(ns('/foo'))..createSync(ns('/bar')); + var l = fs.link(ns('/foo'))..createSync(ns('/bar')); fs.link(ns('/bar')).createSync(ns('/foo')); expect(l, exists); }); @@ -3038,29 +3037,29 @@ void runCommonTests( }); test('isNotFoundIfTargetNotFoundAtTail', () { - Link l = fs.link(ns('/foo'))..createSync(ns('/bar')); + var l = fs.link(ns('/foo'))..createSync(ns('/bar')); expect(l.statSync().type, FileSystemEntityType.notFound); }); test('isNotFoundIfTargetNotFoundViaTraversal', () { - Link l = fs.link(ns('/foo'))..createSync(ns('/bar/baz')); + var l = fs.link(ns('/foo'))..createSync(ns('/bar/baz')); expect(l.statSync().type, FileSystemEntityType.notFound); }); test('isNotFoundIfTargetIsLinkLoop', () { - Link l = fs.link(ns('/foo'))..createSync(ns('/bar')); + var l = fs.link(ns('/foo'))..createSync(ns('/bar')); fs.link(ns('/bar')).createSync(ns('/foo')); expect(l.statSync().type, FileSystemEntityType.notFound); }); test('isFileIfTargetIsFile', () { - Link l = fs.link(ns('/foo'))..createSync(ns('/bar')); + var l = fs.link(ns('/foo'))..createSync(ns('/bar')); fs.file(ns('/bar')).createSync(); expect(l.statSync().type, FileSystemEntityType.file); }); test('isDirectoryIfTargetIsDirectory', () { - Link l = fs.link(ns('/foo'))..createSync(ns('/bar')); + var l = fs.link(ns('/foo'))..createSync(ns('/bar')); fs.directory(ns('/bar')).createSync(); expect(l.statSync().type, FileSystemEntityType.directory); }); @@ -3068,7 +3067,7 @@ void runCommonTests( group('delete', () { test('returnsCovariantType', () async { - Link link = fs.link(ns('/foo'))..createSync(ns('/bar')); + var link = fs.link(ns('/foo'))..createSync(ns('/bar')); expect(await link.delete(), isLink); }); @@ -3118,7 +3117,7 @@ void runCommonTests( }); test('unlinksIfTargetIsFileAndRecursiveFalse', () { - Link l = fs.link(ns('/foo'))..createSync(ns('/bar')); + var l = fs.link(ns('/foo'))..createSync(ns('/bar')); fs.file(ns('/bar')).createSync(); l.deleteSync(); expect(fs.typeSync(ns('/foo'), followLinks: false), @@ -3128,7 +3127,7 @@ void runCommonTests( }); test('unlinksIfTargetIsFileAndRecursiveTrue', () { - Link l = fs.link(ns('/foo'))..createSync(ns('/bar')); + var l = fs.link(ns('/foo'))..createSync(ns('/bar')); fs.file(ns('/bar')).createSync(); l.deleteSync(recursive: true); expect(fs.typeSync(ns('/foo'), followLinks: false), @@ -3138,7 +3137,7 @@ void runCommonTests( }); test('unlinksIfTargetIsDirectoryAndRecursiveFalse', () { - Link l = fs.link(ns('/foo'))..createSync(ns('/bar')); + var l = fs.link(ns('/foo'))..createSync(ns('/bar')); fs.directory(ns('/bar')).createSync(); l.deleteSync(); expect(fs.typeSync(ns('/foo'), followLinks: false), @@ -3148,7 +3147,7 @@ void runCommonTests( }); test('unlinksIfTargetIsDirectoryAndRecursiveTrue', () { - Link l = fs.link(ns('/foo'))..createSync(ns('/bar')); + var l = fs.link(ns('/foo'))..createSync(ns('/bar')); fs.directory(ns('/bar')).createSync(); l.deleteSync(recursive: true); expect(fs.typeSync(ns('/foo'), followLinks: false), @@ -3158,7 +3157,7 @@ void runCommonTests( }); test('unlinksIfTargetIsLinkLoop', () { - Link l = fs.link(ns('/foo'))..createSync(ns('/bar')); + var l = fs.link(ns('/foo'))..createSync(ns('/bar')); fs.link(ns('/bar')).createSync(ns('/foo')); l.deleteSync(); expect(fs.typeSync(ns('/foo'), followLinks: false), @@ -3178,7 +3177,7 @@ void runCommonTests( }); test('ignoresLinkTarget', () { - Link l = fs.link(ns('/foo/bar')) + var l = fs.link(ns('/foo/bar')) ..createSync(ns('/baz/qux'), recursive: true); expect(l.parent.path, ns('/foo')); }); @@ -3190,7 +3189,7 @@ void runCommonTests( }); test('succeedsIfLinkDoesntExistAtTail', () { - Link l = fs.link(ns('/foo'))..createSync(ns('/bar')); + var l = fs.link(ns('/foo'))..createSync(ns('/bar')); expect(fs.typeSync(ns('/foo'), followLinks: false), FileSystemEntityType.link); expect(l.targetSync(), ns('/bar')); @@ -3203,7 +3202,7 @@ void runCommonTests( }); test('succeedsIfLinkDoesntExistViaTraversalAndRecursiveTrue', () { - Link l = fs.link(ns('/foo/bar'))..createSync('baz', recursive: true); + var l = fs.link(ns('/foo/bar'))..createSync('baz', recursive: true); expect(fs.typeSync(ns('/foo'), followLinks: false), FileSystemEntityType.directory); expect(fs.typeSync(ns('/foo/bar'), followLinks: false), @@ -3242,7 +3241,7 @@ void runCommonTests( group('update', () { test('returnsCovariantType', () async { - Link l = fs.link(ns('/foo'))..createSync(ns('/bar')); + var l = fs.link(ns('/foo'))..createSync(ns('/bar')); expect(await l.update(ns('/baz')), isLink); }); @@ -3336,24 +3335,24 @@ void runCommonTests( }); test('succeedsIfTargetIsNotFound', () { - Link l = fs.link(ns('/foo'))..createSync(ns('/bar')); + var l = fs.link(ns('/foo'))..createSync(ns('/bar')); expect(l.targetSync(), ns('/bar')); }); test('succeedsIfTargetIsFile', () { - Link l = fs.link(ns('/foo'))..createSync(ns('/bar')); + var l = fs.link(ns('/foo'))..createSync(ns('/bar')); fs.file(ns('/bar')).createSync(); expect(l.targetSync(), ns('/bar')); }); test('succeedsIfTargetIsDirectory', () { - Link l = fs.link(ns('/foo'))..createSync(ns('/bar')); + var l = fs.link(ns('/foo'))..createSync(ns('/bar')); fs.directory(ns('/bar')).createSync(); expect(l.targetSync(), ns('/bar')); }); test('succeedsIfTargetIsLinkLoop', () { - Link l = fs.link(ns('/foo'))..createSync(ns('/bar')); + var l = fs.link(ns('/foo'))..createSync(ns('/bar')); fs.link(ns('/bar')).createSync(ns('/foo')); expect(l.targetSync(), ns('/bar')); }); @@ -3393,9 +3392,9 @@ void runCommonTests( }); test('succeedsIfSourceIsLinkToFile', () { - Link l = fs.link(ns('/foo'))..createSync(ns('/bar')); + var l = fs.link(ns('/foo'))..createSync(ns('/bar')); fs.file(ns('/bar')).createSync(); - Link renamed = l.renameSync(ns('/baz')); + var renamed = l.renameSync(ns('/baz')); expect(renamed.path, ns('/baz')); expect(fs.typeSync(ns('/foo'), followLinks: false), FileSystemEntityType.notFound); @@ -3407,8 +3406,8 @@ void runCommonTests( }); test('succeedsIfSourceIsLinkToNotFound', () { - Link l = fs.link(ns('/foo'))..createSync(ns('/bar')); - Link renamed = l.renameSync(ns('/baz')); + var l = fs.link(ns('/foo'))..createSync(ns('/bar')); + var renamed = l.renameSync(ns('/baz')); expect(renamed.path, ns('/baz')); expect(fs.typeSync(ns('/foo'), followLinks: false), FileSystemEntityType.notFound); @@ -3418,9 +3417,9 @@ void runCommonTests( }); test('succeedsIfSourceIsLinkToDirectory', () { - Link l = fs.link(ns('/foo'))..createSync(ns('/bar')); + var l = fs.link(ns('/foo'))..createSync(ns('/bar')); fs.directory(ns('/bar')).createSync(); - Link renamed = l.renameSync(ns('/baz')); + var renamed = l.renameSync(ns('/baz')); expect(renamed.path, ns('/baz')); expect(fs.typeSync(ns('/foo'), followLinks: false), FileSystemEntityType.notFound); @@ -3432,9 +3431,9 @@ void runCommonTests( }); test('succeedsIfSourceIsLinkLoop', () { - Link l = fs.link(ns('/foo'))..createSync(ns('/bar')); + var l = fs.link(ns('/foo'))..createSync(ns('/bar')); fs.link(ns('/bar')).createSync(ns('/foo')); - Link renamed = l.renameSync(ns('/baz')); + var renamed = l.renameSync(ns('/baz')); expect(renamed.path, ns('/baz')); expect(fs.typeSync(ns('/foo'), followLinks: false), FileSystemEntityType.notFound); @@ -3446,22 +3445,22 @@ void runCommonTests( }); test('succeedsIfDestinationDoesntExistAtTail', () { - Link l = fs.link(ns('/foo'))..createSync(ns('/bar')); - Link renamed = l.renameSync(ns('/baz')); + var l = fs.link(ns('/foo'))..createSync(ns('/bar')); + var renamed = l.renameSync(ns('/baz')); expect(renamed.path, ns('/baz')); expect(fs.link(ns('/foo')), isNot(exists)); expect(fs.link(ns('/baz')), exists); }); test('throwsIfDestinationDoesntExistViaTraversal', () { - Link l = fs.link(ns('/foo'))..createSync(ns('/bar')); + var l = fs.link(ns('/foo'))..createSync(ns('/bar')); expectFileSystemException(ErrorCodes.ENOENT, () { l.renameSync(ns('/baz/qux')); }); }); test('throwsIfDestinationExistsAsFile', () { - Link l = fs.link(ns('/foo'))..createSync(ns('/bar')); + var l = fs.link(ns('/foo'))..createSync(ns('/bar')); fs.file(ns('/baz')).createSync(); expectFileSystemException(ErrorCodes.EINVAL, () { l.renameSync(ns('/baz')); @@ -3469,7 +3468,7 @@ void runCommonTests( }); test('throwsIfDestinationExistsAsDirectory', () { - Link l = fs.link(ns('/foo'))..createSync(ns('/bar')); + var l = fs.link(ns('/foo'))..createSync(ns('/bar')); fs.directory(ns('/baz')).createSync(); expectFileSystemException(ErrorCodes.EINVAL, () { l.renameSync(ns('/baz')); @@ -3477,7 +3476,7 @@ void runCommonTests( }); test('succeedsIfDestinationExistsAsLinkToFile', () { - Link l = fs.link(ns('/foo'))..createSync(ns('/bar')); + var l = fs.link(ns('/foo'))..createSync(ns('/bar')); fs.file(ns('/baz')).createSync(); fs.link(ns('/qux')).createSync(ns('/baz')); l.renameSync(ns('/qux')); @@ -3490,7 +3489,7 @@ void runCommonTests( }); test('throwsIfDestinationExistsAsLinkToDirectory', () { - Link l = fs.link(ns('/foo'))..createSync(ns('/bar')); + var l = fs.link(ns('/foo'))..createSync(ns('/bar')); fs.directory(ns('/baz')).createSync(); fs.link(ns('/qux')).createSync(ns('/baz')); l.renameSync(ns('/qux')); @@ -3503,7 +3502,7 @@ void runCommonTests( }); test('succeedsIfDestinationExistsAsLinkToNotFound', () { - Link l = fs.link(ns('/foo'))..createSync(ns('/bar')); + var l = fs.link(ns('/foo'))..createSync(ns('/bar')); fs.link(ns('/baz')).createSync(ns('/qux')); l.renameSync(ns('/baz')); expect(fs.typeSync(ns('/foo')), FileSystemEntityType.notFound); diff --git a/pkgs/file/test/local_test.dart b/pkgs/file/test/local_test.dart index e1618d230..b794ccd7b 100644 --- a/pkgs/file/test/local_test.dart +++ b/pkgs/file/test/local_test.dart @@ -2,7 +2,11 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// ignore_for_file: lines_longer_than_80_chars + @TestOn('vm') +library; + import 'dart:io' as io; import 'package:file/local.dart'; @@ -33,7 +37,7 @@ void main() { setUpAll(() { if (io.Platform.isWindows) { // TODO(tvolkert): Remove once all more serious test failures are fixed - // https://github.com/google/file.dart/issues/56 + // https://github.com/dart-lang/tools/issues/618 ignoreOsErrorCodes = true; } }); @@ -42,7 +46,7 @@ void main() { ignoreOsErrorCodes = false; }); - Map> skipOnPlatform = >{ + var skipOnPlatform = >{ 'windows': [ 'FileSystem > currentDirectory > throwsIfHasNonExistentPathInComplexChain', 'FileSystem > currentDirectory > resolvesLinksIfEncountered', diff --git a/pkgs/file/test/memory_operations_test.dart b/pkgs/file/test/memory_operations_test.dart index 5e27843b5..916707c62 100644 --- a/pkgs/file/test/memory_operations_test.dart +++ b/pkgs/file/test/memory_operations_test.dart @@ -2,22 +2,21 @@ // for details. 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:file/file.dart'; import 'package:file/memory.dart'; import 'package:test/test.dart'; void main() { test('Read operations invoke opHandle', () async { - List contexts = []; - List operations = []; - MemoryFileSystem fs = MemoryFileSystem.test( + var contexts = []; + var operations = []; + var fs = MemoryFileSystem.test( opHandle: (String context, FileSystemOp operation) { if (operation == FileSystemOp.read) { contexts.add(context); operations.add(operation); } }); - final File file = fs.file('test')..createSync(); + final file = fs.file('test')..createSync(); await file.readAsBytes(); file.readAsBytesSync(); @@ -34,16 +33,16 @@ void main() { }); test('Write operations invoke opHandle', () async { - List contexts = []; - List operations = []; - MemoryFileSystem fs = MemoryFileSystem.test( + var contexts = []; + var operations = []; + var fs = MemoryFileSystem.test( opHandle: (String context, FileSystemOp operation) { if (operation == FileSystemOp.write) { contexts.add(context); operations.add(operation); } }); - final File file = fs.file('test')..createSync(); + final file = fs.file('test')..createSync(); await file.writeAsBytes([]); file.writeAsBytesSync([]); @@ -60,18 +59,18 @@ void main() { }); test('Delete operations invoke opHandle', () async { - List contexts = []; - List operations = []; - MemoryFileSystem fs = MemoryFileSystem.test( + var contexts = []; + var operations = []; + var fs = MemoryFileSystem.test( opHandle: (String context, FileSystemOp operation) { if (operation == FileSystemOp.delete) { contexts.add(context); operations.add(operation); } }); - final File file = fs.file('test')..createSync(); - final Directory directory = fs.directory('testDir')..createSync(); - final Link link = fs.link('testLink')..createSync('foo'); + final file = fs.file('test')..createSync(); + final directory = fs.directory('testDir')..createSync(); + final link = fs.link('testLink')..createSync('foo'); await file.delete(); file.createSync(); @@ -98,9 +97,9 @@ void main() { }); test('Create operations invoke opHandle', () async { - List contexts = []; - List operations = []; - MemoryFileSystem fs = MemoryFileSystem.test( + var contexts = []; + var operations = []; + var fs = MemoryFileSystem.test( opHandle: (String context, FileSystemOp operation) { if (operation == FileSystemOp.create) { contexts.add(context); @@ -139,16 +138,16 @@ void main() { }); test('Open operations invoke opHandle', () async { - List contexts = []; - List operations = []; - MemoryFileSystem fs = MemoryFileSystem.test( + var contexts = []; + var operations = []; + var fs = MemoryFileSystem.test( opHandle: (String context, FileSystemOp operation) { if (operation == FileSystemOp.open) { contexts.add(context); operations.add(operation); } }); - final File file = fs.file('test')..createSync(); + final file = fs.file('test')..createSync(); await file.open(); file.openSync(); @@ -165,16 +164,16 @@ void main() { }); test('Copy operations invoke opHandle', () async { - List contexts = []; - List operations = []; - MemoryFileSystem fs = MemoryFileSystem.test( + var contexts = []; + var operations = []; + var fs = MemoryFileSystem.test( opHandle: (String context, FileSystemOp operation) { if (operation == FileSystemOp.copy) { contexts.add(context); operations.add(operation); } }); - final File file = fs.file('test')..createSync(); + final file = fs.file('test')..createSync(); await file.copy('A'); file.copySync('B'); @@ -187,9 +186,9 @@ void main() { }); test('Exists operations invoke opHandle', () async { - List contexts = []; - List operations = []; - MemoryFileSystem fs = MemoryFileSystem.test( + var contexts = []; + var operations = []; + var fs = MemoryFileSystem.test( opHandle: (String context, FileSystemOp operation) { if (operation == FileSystemOp.exists) { contexts.add(context); diff --git a/pkgs/file/test/memory_test.dart b/pkgs/file/test/memory_test.dart index f3b324e6c..ce8675f2e 100644 --- a/pkgs/file/test/memory_test.dart +++ b/pkgs/file/test/memory_test.dart @@ -66,8 +66,7 @@ void main() { }); test('MemoryFileSystem.test', () { - final MemoryFileSystem fs = - MemoryFileSystem.test(); // creates root directory + final fs = MemoryFileSystem.test(); // creates root directory fs.file('/test1.txt').createSync(); // creates file fs.file('/test2.txt').createSync(); // creates file expect(fs.directory('/').statSync().modified, DateTime(2000, 1, 1, 0, 1)); @@ -95,10 +94,10 @@ void main() { }); test('MemoryFile.openSync returns a MemoryRandomAccessFile', () async { - final MemoryFileSystem fs = MemoryFileSystem.test(); + final fs = MemoryFileSystem.test(); final io.File file = fs.file('/test1')..createSync(); - io.RandomAccessFile raf = file.openSync(); + var raf = file.openSync(); try { expect(raf, isA()); } finally { @@ -114,7 +113,7 @@ void main() { }); test('MemoryFileSystem.systemTempDirectory test', () { - final MemoryFileSystem fs = MemoryFileSystem.test(); + final fs = MemoryFileSystem.test(); final io.Directory fooA = fs.systemTempDirectory.createTempSync('foo'); final io.Directory fooB = fs.systemTempDirectory.createTempSync('foo'); @@ -122,7 +121,7 @@ void main() { expect(fooA.path, '/.tmp_rand0/foorand0'); expect(fooB.path, '/.tmp_rand0/foorand1'); - final MemoryFileSystem secondFs = MemoryFileSystem.test(); + final secondFs = MemoryFileSystem.test(); final io.Directory fooAA = secondFs.systemTempDirectory.createTempSync('foo'); @@ -136,16 +135,16 @@ void main() { test('Failed UTF8 decoding in MemoryFileSystem throws a FileSystemException', () { - final MemoryFileSystem fileSystem = MemoryFileSystem.test(); - final File file = fileSystem.file('foo') + final fileSystem = MemoryFileSystem.test(); + final file = fileSystem.file('foo') ..writeAsBytesSync([0xFFFE]); // Invalid UTF8 expect(file.readAsStringSync, throwsA(isA())); }); test('Creating a temporary directory actually creates the directory', () { - final MemoryFileSystem fileSystem = MemoryFileSystem.test(); - final Directory tempDir = fileSystem.currentDirectory.createTempSync('foo'); + final fileSystem = MemoryFileSystem.test(); + final tempDir = fileSystem.currentDirectory.createTempSync('foo'); expect(tempDir.existsSync(), true); }); diff --git a/pkgs/file/test/utils.dart b/pkgs/file/test/utils.dart index 231312fbe..797ec9de5 100644 --- a/pkgs/file/test/utils.dart +++ b/pkgs/file/test/utils.dart @@ -25,7 +25,7 @@ DateTime floor([DateTime? time]) { /// If [time] is not specified, it will default to the current time. DateTime ceil([DateTime? time]) { time ??= DateTime.now(); - int microseconds = (1000 * time.millisecond) + time.microsecond; + var microseconds = (1000 * time.millisecond) + time.microsecond; return (microseconds == 0) ? time // Add just enough milliseconds and microseconds to reach the next second. @@ -78,7 +78,7 @@ abstract class _CompareDateTime extends Matcher { bool verbose, ) { if (item is DateTime) { - Duration diff = item.difference(_time).abs(); + var diff = item.difference(_time).abs(); return description.add('is $mismatchAdjective $_time by $diff'); } else { return description.add('is not a DateTime'); diff --git a/pkgs/file/test/utils_test.dart b/pkgs/file/test/utils_test.dart index 75293bf3c..23788e983 100644 --- a/pkgs/file/test/utils_test.dart +++ b/pkgs/file/test/utils_test.dart @@ -8,9 +8,9 @@ import 'utils.dart'; void main() { test('floorAndCeilProduceExactSecondDateTime', () { - DateTime time = DateTime.fromMicrosecondsSinceEpoch(1001); - DateTime lower = floor(time); - DateTime upper = ceil(time); + var time = DateTime.fromMicrosecondsSinceEpoch(1001); + var lower = floor(time); + var upper = ceil(time); expect(lower.millisecond, 0); expect(upper.millisecond, 0); expect(lower.microsecond, 0); @@ -18,26 +18,26 @@ void main() { }); test('floorAndCeilWorkWithNow', () { - DateTime time = DateTime.now(); - int lower = time.difference(floor(time)).inMicroseconds; - int upper = ceil(time).difference(time).inMicroseconds; + var time = DateTime.now(); + var lower = time.difference(floor(time)).inMicroseconds; + var upper = ceil(time).difference(time).inMicroseconds; expect(lower, lessThan(1000000)); expect(upper, lessThanOrEqualTo(1000000)); }); test('floorAndCeilWorkWithExactSecondDateTime', () { - DateTime time = DateTime.parse('1999-12-31 23:59:59'); - DateTime lower = floor(time); - DateTime upper = ceil(time); + var time = DateTime.parse('1999-12-31 23:59:59'); + var lower = floor(time); + var upper = ceil(time); expect(lower, time); expect(upper, time); }); test('floorAndCeilWorkWithInexactSecondDateTime', () { - DateTime time = DateTime.parse('1999-12-31 23:59:59.500'); - DateTime lower = floor(time); - DateTime upper = ceil(time); - Duration difference = upper.difference(lower); + var time = DateTime.parse('1999-12-31 23:59:59.500'); + var lower = floor(time); + var upper = ceil(time); + var difference = upper.difference(lower); expect(difference.inMicroseconds, 1000000); }); } diff --git a/pkgs/file_testing/CHANGELOG.md b/pkgs/file_testing/CHANGELOG.md index 0af779d87..17039ee16 100644 --- a/pkgs/file_testing/CHANGELOG.md +++ b/pkgs/file_testing/CHANGELOG.md @@ -1,3 +1,8 @@ +## 3.1.0-wip + +* Changed the type of several matchers to `TypeMatcher` which allows cascading + their usage with `.having` and similar. + ## 3.0.2 * Require Dart 3.1. diff --git a/pkgs/file_testing/analysis_options.yaml b/pkgs/file_testing/analysis_options.yaml index 8fbd2e443..d978f811c 100644 --- a/pkgs/file_testing/analysis_options.yaml +++ b/pkgs/file_testing/analysis_options.yaml @@ -1,6 +1 @@ -include: package:lints/recommended.yaml - -analyzer: - errors: - # Allow having TODOs in the code - todo: ignore +include: package:dart_flutter_team_lints/analysis_options.yaml diff --git a/pkgs/file_testing/lib/src/testing/core_matchers.dart b/pkgs/file_testing/lib/src/testing/core_matchers.dart index f58539f19..801209e89 100644 --- a/pkgs/file_testing/lib/src/testing/core_matchers.dart +++ b/pkgs/file_testing/lib/src/testing/core_matchers.dart @@ -2,6 +2,8 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +// ignore_for_file: comment_references + import 'dart:io'; import 'package:test/test.dart'; @@ -9,26 +11,27 @@ import 'package:test/test.dart'; import 'internal.dart'; /// Matcher that successfully matches against any instance of [Directory]. -const Matcher isDirectory = TypeMatcher(); +const isDirectory = TypeMatcher(); /// Matcher that successfully matches against any instance of [File]. -const Matcher isFile = TypeMatcher(); +const isFile = TypeMatcher(); /// Matcher that successfully matches against any instance of [Link]. -const Matcher isLink = TypeMatcher(); +const isLink = TypeMatcher(); /// Matcher that successfully matches against any instance of /// [FileSystemEntity]. -const Matcher isFileSystemEntity = TypeMatcher(); +const isFileSystemEntity = TypeMatcher(); /// Matcher that successfully matches against any instance of [FileStat]. -const Matcher isFileStat = TypeMatcher(); +const isFileStat = TypeMatcher(); /// Returns a [Matcher] that matches [path] against an entity's path. /// /// [path] may be a String, a predicate function, or a [Matcher]. If it is /// a String, it will be wrapped in an equality matcher. -Matcher hasPath(dynamic path) => _HasPath(path); +TypeMatcher hasPath(dynamic path) => + isFileSystemEntity.having((e) => e.path, 'path', path); /// Returns a [Matcher] that successfully matches against an instance of /// [FileSystemException]. @@ -39,7 +42,8 @@ Matcher hasPath(dynamic path) => _HasPath(path); /// [osErrorCode] may be an `int`, a predicate function, or a [Matcher]. If it /// is an `int`, it will be wrapped in an equality matcher. Matcher isFileSystemException([dynamic osErrorCode]) => - _FileSystemException(osErrorCode); + const TypeMatcher().having((e) => e.osError?.errorCode, + 'osError.errorCode', _fileExceptionWrapMatcher(osErrorCode)); /// Returns a matcher that successfully matches against a future or function /// that throws a [FileSystemException]. @@ -67,89 +71,10 @@ void expectFileSystemException(dynamic osErrorCode, void Function() callback) { /// Matcher that successfully matches against a [FileSystemEntity] that /// exists ([FileSystemEntity.existsSync] returns true). -const Matcher exists = _Exists(); - -class _FileSystemException extends Matcher { - _FileSystemException(dynamic osErrorCode) - : _matcher = _wrapMatcher(osErrorCode); - - final Matcher? _matcher; - - static Matcher? _wrapMatcher(dynamic osErrorCode) { - if (osErrorCode == null) { - return null; - } - return ignoreOsErrorCodes ? anything : wrapMatcher(osErrorCode); - } - - @override - bool matches(dynamic item, Map matchState) { - if (item is FileSystemException) { - return _matcher == null || - _matcher!.matches(item.osError?.errorCode, matchState); - } - return false; - } - - @override - Description describe(Description desc) { - if (_matcher == null) { - return desc.add('FileSystemException'); - } else { - desc.add('FileSystemException with osError.errorCode: '); - return _matcher!.describe(desc); - } - } -} - -class _HasPath extends Matcher { - _HasPath(dynamic path) : _matcher = wrapMatcher(path); - - final Matcher _matcher; +final TypeMatcher exists = + isFileSystemEntity.having((e) => e.existsSync(), 'existsSync', true); - @override - bool matches(dynamic item, Map matchState) => - _matcher.matches(item.path, matchState); - - @override - Description describe(Description desc) { - desc.add('has path: '); - return _matcher.describe(desc); - } - - @override - Description describeMismatch( - dynamic item, - Description desc, - Map matchState, - bool verbose, - ) { - desc.add('has path: \'${item.path}\'').add('\n Which: '); - final Description pathDesc = StringDescription(); - _matcher.describeMismatch(item.path, pathDesc, matchState, verbose); - desc.add(pathDesc.toString()); - return desc; - } -} - -class _Exists extends Matcher { - const _Exists(); - - @override - bool matches(dynamic item, Map matchState) => - item is FileSystemEntity && item.existsSync(); - - @override - Description describe(Description description) => - description.add('a file system entity that exists'); - - @override - Description describeMismatch( - dynamic item, - Description description, - Map matchState, - bool verbose, - ) { - return description.add('does not exist'); - } -} +Matcher? _fileExceptionWrapMatcher(dynamic osErrorCode) => + (osErrorCode == null || ignoreOsErrorCodes) + ? anything + : wrapMatcher(osErrorCode); diff --git a/pkgs/file_testing/pubspec.yaml b/pkgs/file_testing/pubspec.yaml index 691efa0e6..895826a39 100644 --- a/pkgs/file_testing/pubspec.yaml +++ b/pkgs/file_testing/pubspec.yaml @@ -1,5 +1,5 @@ name: file_testing -version: 3.0.2 +version: 3.1.0-wip description: Testing utilities for package:file. repository: https://github.com/dart-lang/tools/tree/main/pkgs/file_testing issue_tracker: https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Afile_testing @@ -10,5 +10,5 @@ environment: dependencies: test: ^1.23.1 -dev_dependencies: - lints: ^5.0.0 +dev_dependencies: + dart_flutter_team_lints: ^3.0.0 diff --git a/pkgs/source_maps/CHANGELOG.md b/pkgs/source_maps/CHANGELOG.md index ae7711e57..b06ac72ea 100644 --- a/pkgs/source_maps/CHANGELOG.md +++ b/pkgs/source_maps/CHANGELOG.md @@ -1,3 +1,5 @@ +## 0.10.14-wip + ## 0.10.13 * Require Dart 3.3 diff --git a/pkgs/source_maps/lib/builder.dart b/pkgs/source_maps/lib/builder.dart index 54ba7433f..9043c6326 100644 --- a/pkgs/source_maps/lib/builder.dart +++ b/pkgs/source_maps/lib/builder.dart @@ -3,7 +3,7 @@ // BSD-style license that can be found in the LICENSE file. /// Contains a builder object useful for creating source maps programatically. -library source_maps.builder; +library; // TODO(sigmund): add a builder for multi-section mappings. diff --git a/pkgs/source_maps/lib/parser.dart b/pkgs/source_maps/lib/parser.dart index b699ac728..590dfc682 100644 --- a/pkgs/source_maps/lib/parser.dart +++ b/pkgs/source_maps/lib/parser.dart @@ -3,7 +3,7 @@ // BSD-style license that can be found in the LICENSE file. /// Contains the top-level function to parse source maps version 3. -library source_maps.parser; +library; import 'dart:convert'; diff --git a/pkgs/source_maps/lib/printer.dart b/pkgs/source_maps/lib/printer.dart index 17733cdd3..32523d62f 100644 --- a/pkgs/source_maps/lib/printer.dart +++ b/pkgs/source_maps/lib/printer.dart @@ -3,7 +3,7 @@ // BSD-style license that can be found in the LICENSE file. /// Contains a code printer that generates code by recording the source maps. -library source_maps.printer; +library; import 'package:source_span/source_span.dart'; diff --git a/pkgs/source_maps/lib/refactor.dart b/pkgs/source_maps/lib/refactor.dart index 98e0c9345..a518a0ce4 100644 --- a/pkgs/source_maps/lib/refactor.dart +++ b/pkgs/source_maps/lib/refactor.dart @@ -6,7 +6,7 @@ /// /// [TextEditTransaction] supports making a series of changes to a text buffer. /// [guessIndent] helps to guess the appropriate indentiation for the new code. -library source_maps.refactor; +library; import 'package:source_span/source_span.dart'; diff --git a/pkgs/source_maps/lib/source_maps.dart b/pkgs/source_maps/lib/source_maps.dart index 58f805a3a..244dee7a9 100644 --- a/pkgs/source_maps/lib/source_maps.dart +++ b/pkgs/source_maps/lib/source_maps.dart @@ -24,7 +24,7 @@ /// var mapping = parse(json); /// mapping.spanFor(outputSpan1.line, outputSpan1.column) /// ``` -library source_maps; +library; import 'package:source_span/source_span.dart'; diff --git a/pkgs/source_maps/lib/src/utils.dart b/pkgs/source_maps/lib/src/utils.dart index f70531e95..ba04fbb0f 100644 --- a/pkgs/source_maps/lib/src/utils.dart +++ b/pkgs/source_maps/lib/src/utils.dart @@ -3,7 +3,7 @@ // BSD-style license that can be found in the LICENSE file. /// Utilities that shouldn't be in this package. -library source_maps.utils; +library; /// Find the first entry in a sorted [list] that matches a monotonic predicate. /// Given a result `n`, that all items before `n` will not match, `n` matches, diff --git a/pkgs/source_maps/lib/src/vlq.dart b/pkgs/source_maps/lib/src/vlq.dart index 61b476839..3b0562d82 100644 --- a/pkgs/source_maps/lib/src/vlq.dart +++ b/pkgs/source_maps/lib/src/vlq.dart @@ -10,7 +10,7 @@ /// represented by using the least significant bit of the value as the sign bit. /// /// For more details see the source map [version 3 documentation](https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit?usp=sharing). -library source_maps.src.vlq; +library; import 'dart:math'; diff --git a/pkgs/source_maps/pubspec.yaml b/pkgs/source_maps/pubspec.yaml index 8518fa756..32cbf4fb7 100644 --- a/pkgs/source_maps/pubspec.yaml +++ b/pkgs/source_maps/pubspec.yaml @@ -1,5 +1,5 @@ name: source_maps -version: 0.10.13 +version: 0.10.14-wip description: A library to programmatically manipulate source map files. repository: https://github.com/dart-lang/tools/tree/main/pkgs/source_maps @@ -10,6 +10,6 @@ dependencies: source_span: ^1.8.0 dev_dependencies: - dart_flutter_team_lints: ^2.0.0 + dart_flutter_team_lints: ^3.0.0 term_glyph: ^1.2.0 test: ^1.16.0 diff --git a/pkgs/source_maps/test/common.dart b/pkgs/source_maps/test/common.dart index f6139de47..e225ff5a4 100644 --- a/pkgs/source_maps/test/common.dart +++ b/pkgs/source_maps/test/common.dart @@ -3,7 +3,7 @@ // BSD-style license that can be found in the LICENSE file. /// Common input/output used by builder, parser and end2end tests -library test.common; +library; import 'package:source_maps/source_maps.dart'; import 'package:source_span/source_span.dart'; diff --git a/pkgs/source_maps/test/utils_test.dart b/pkgs/source_maps/test/utils_test.dart index 4abdce298..2516d1e47 100644 --- a/pkgs/source_maps/test/utils_test.dart +++ b/pkgs/source_maps/test/utils_test.dart @@ -3,7 +3,7 @@ // BSD-style license that can be found in the LICENSE file. /// Tests for the binary search utility algorithm. -library test.utils_test; +library; import 'package:source_maps/src/utils.dart'; import 'package:test/test.dart'; diff --git a/pkgs/test_reflective_loader/.gitignore b/pkgs/test_reflective_loader/.gitignore new file mode 100644 index 000000000..2a2c2612b --- /dev/null +++ b/pkgs/test_reflective_loader/.gitignore @@ -0,0 +1,11 @@ +.buildlog +.DS_Store +.idea +.dart_tool/ +.pub/ +.project +.settings/ +build/ +packages +.packages +pubspec.lock diff --git a/pkgs/test_reflective_loader/AUTHORS b/pkgs/test_reflective_loader/AUTHORS new file mode 100644 index 000000000..e8063a8cd --- /dev/null +++ b/pkgs/test_reflective_loader/AUTHORS @@ -0,0 +1,6 @@ +# Below is a list of people and organizations that have contributed +# to the project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. diff --git a/pkgs/test_reflective_loader/CHANGELOG.md b/pkgs/test_reflective_loader/CHANGELOG.md new file mode 100644 index 000000000..803eb0e0c --- /dev/null +++ b/pkgs/test_reflective_loader/CHANGELOG.md @@ -0,0 +1,72 @@ +## 0.2.3 + +- Require Dart `^3.1.0`. +- Move to `dart-lang/tools` monorepo. + +## 0.2.2 + +- Update to package:lints 2.0.0 and move it to a dev dependency. + +## 0.2.1 + +- Use package:lints for analysis. +- Populate the pubspec `repository` field. + +## 0.2.0 + +- Stable null safety release. + +## 0.2.0-nullsafety.0 + +- Migrate to the null safety language feature. + +## 0.1.9 + +- Add `@SkippedTest` annotation and `skip_test` prefix. + +## 0.1.8 + +- Update `FailingTest` to add named parameters `issue` and `reason`. + +## 0.1.7 + +- Update documentation comments. +- Remove `@MirrorsUsed` annotation on `dart:mirrors`. + +## 0.1.6 + +- Make `FailingTest` public, with the URI of the issue that causes + the test to break. + +## 0.1.5 + +- Set max SDK version to `<3.0.0`, and adjust other dependencies. + +## 0.1.3 + +- Fix `@failingTest` to fail when the test passes. + +## 0.1.2 + +- Update the pubspec `dependencies` section to include `package:test` + +## 0.1.1 + +- For `@failingTest` tests, properly handle when the test fails by throwing an + exception in a timer task +- Analyze this package in strong mode + +## 0.1.0 + +- Switched from 'package:unittest' to 'package:test'. +- Since 'package:test' does not define 'solo_test', in order to keep this + functionality, `defineReflectiveSuite` must be used to wrap all + `defineReflectiveTests` invocations. + +## 0.0.4 + +- Added @failingTest, @assertFailingTest and @soloTest annotations. + +## 0.0.1 + +- Initial version diff --git a/pkgs/test_reflective_loader/LICENSE b/pkgs/test_reflective_loader/LICENSE new file mode 100644 index 000000000..633672ab3 --- /dev/null +++ b/pkgs/test_reflective_loader/LICENSE @@ -0,0 +1,27 @@ +Copyright 2015, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/pkgs/test_reflective_loader/README.md b/pkgs/test_reflective_loader/README.md new file mode 100644 index 000000000..9b5a83d4e --- /dev/null +++ b/pkgs/test_reflective_loader/README.md @@ -0,0 +1,28 @@ +[![Build Status](https://github.com/dart-lang/tools/actions/workflows/test_reflective_loader.yaml/badge.svg)](https://github.com/dart-lang/tools/actions/workflows/test_reflective_loader.yaml) +[![pub package](https://img.shields.io/pub/v/test_reflective_loader.svg)](https://pub.dev/packages/test_reflective_loader) +[![package publisher](https://img.shields.io/pub/publisher/test_reflective_loader.svg)](https://pub.dev/packages/test_reflective_loader/publisher) + +Support for discovering tests and test suites using reflection. + +This package follows the xUnit style where each class is a test suite, and each +method with the name prefix `test_` is a single test. + +Methods with names starting with `test_` are run using the `test()` function with +the corresponding name. If the class defines methods `setUp()` or `tearDown()`, +they are executed before / after each test correspondingly, even if the test fails. + +Methods with names starting with `solo_test_` are run using the `solo_test()` function. + +Methods with names starting with `fail_` are expected to fail. + +Methods with names starting with `solo_fail_` are run using the `solo_test()` function +and expected to fail. + +Method returning `Future` class instances are asynchronous, so `tearDown()` is +executed after the returned `Future` completes. + +## Features and bugs + +Please file feature requests and bugs at the [issue tracker][tracker]. + +[tracker]: https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Atest_reflective_loader diff --git a/pkgs/test_reflective_loader/analysis_options.yaml b/pkgs/test_reflective_loader/analysis_options.yaml new file mode 100644 index 000000000..ea6115827 --- /dev/null +++ b/pkgs/test_reflective_loader/analysis_options.yaml @@ -0,0 +1,5 @@ +include: package:dart_flutter_team_lints/analysis_options.yaml + +linter: + rules: + - public_member_api_docs diff --git a/pkgs/test_reflective_loader/lib/test_reflective_loader.dart b/pkgs/test_reflective_loader/lib/test_reflective_loader.dart new file mode 100644 index 000000000..cb69bf3ba --- /dev/null +++ b/pkgs/test_reflective_loader/lib/test_reflective_loader.dart @@ -0,0 +1,354 @@ +// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file +// for details. 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:async'; +import 'dart:mirrors'; + +import 'package:test/test.dart' as test_package; + +/// A marker annotation used to annotate test methods which are expected to fail +/// when asserts are enabled. +const Object assertFailingTest = _AssertFailingTest(); + +/// A marker annotation used to annotate test methods which are expected to +/// fail. +const Object failingTest = FailingTest(); + +/// A marker annotation used to instruct dart2js to keep reflection information +/// for the annotated classes. +const Object reflectiveTest = _ReflectiveTest(); + +/// A marker annotation used to annotate test methods that should be skipped. +const Object skippedTest = SkippedTest(); + +/// A marker annotation used to annotate "solo" groups and tests. +const Object soloTest = _SoloTest(); + +final List<_Group> _currentGroups = <_Group>[]; +int _currentSuiteLevel = 0; +String _currentSuiteName = ''; + +/// Is `true` the application is running in the checked mode. +final bool _isCheckedMode = () { + try { + assert(false); + return false; + } catch (_) { + return true; + } +}(); + +/// Run the [define] function parameter that calls [defineReflectiveTests] to +/// add normal and "solo" tests, and also calls [defineReflectiveSuite] to +/// create embedded suites. If the current suite is the top-level one, perform +/// check for "solo" groups and tests, and run all or only "solo" items. +void defineReflectiveSuite(void Function() define, {String name = ''}) { + var groupName = _currentSuiteName; + _currentSuiteLevel++; + try { + _currentSuiteName = _combineNames(_currentSuiteName, name); + define(); + } finally { + _currentSuiteName = groupName; + _currentSuiteLevel--; + } + _addTestsIfTopLevelSuite(); +} + +/// Runs test methods existing in the given [type]. +/// +/// If there is a "solo" test method in the top-level suite, only "solo" methods +/// are run. +/// +/// If there is a "solo" test type, only its test methods are run. +/// +/// Otherwise all tests methods of all test types are run. +/// +/// Each method is run with a new instance of [type]. +/// So, [type] should have a default constructor. +/// +/// If [type] declares method `setUp`, it methods will be invoked before any +/// test method invocation. +/// +/// If [type] declares method `tearDown`, it will be invoked after any test +/// method invocation. If method returns [Future] to test some asynchronous +/// behavior, then `tearDown` will be invoked in `Future.complete`. +void defineReflectiveTests(Type type) { + var classMirror = reflectClass(type); + if (!classMirror.metadata.any((InstanceMirror annotation) => + annotation.type.reflectedType == _ReflectiveTest)) { + var name = MirrorSystem.getName(classMirror.qualifiedName); + throw Exception('Class $name must have annotation "@reflectiveTest" ' + 'in order to be run by runReflectiveTests.'); + } + + _Group group; + { + var isSolo = _hasAnnotationInstance(classMirror, soloTest); + var className = MirrorSystem.getName(classMirror.simpleName); + group = _Group(isSolo, _combineNames(_currentSuiteName, className)); + _currentGroups.add(group); + } + + classMirror.instanceMembers + .forEach((Symbol symbol, MethodMirror memberMirror) { + // we need only methods + if (!memberMirror.isRegularMethod) { + return; + } + // prepare information about the method + var memberName = MirrorSystem.getName(symbol); + var isSolo = memberName.startsWith('solo_') || + _hasAnnotationInstance(memberMirror, soloTest); + // test_ + if (memberName.startsWith('test_')) { + if (_hasSkippedTestAnnotation(memberMirror)) { + group.addSkippedTest(memberName); + } else { + group.addTest(isSolo, memberName, memberMirror, () { + if (_hasFailingTestAnnotation(memberMirror) || + _isCheckedMode && _hasAssertFailingTestAnnotation(memberMirror)) { + return _runFailingTest(classMirror, symbol); + } else { + return _runTest(classMirror, symbol); + } + }); + } + return; + } + // solo_test_ + if (memberName.startsWith('solo_test_')) { + group.addTest(true, memberName, memberMirror, () { + return _runTest(classMirror, symbol); + }); + } + // fail_test_ + if (memberName.startsWith('fail_')) { + group.addTest(isSolo, memberName, memberMirror, () { + return _runFailingTest(classMirror, symbol); + }); + } + // solo_fail_test_ + if (memberName.startsWith('solo_fail_')) { + group.addTest(true, memberName, memberMirror, () { + return _runFailingTest(classMirror, symbol); + }); + } + // skip_test_ + if (memberName.startsWith('skip_test_')) { + group.addSkippedTest(memberName); + } + }); + + // Support for the case of missing enclosing [defineReflectiveSuite]. + _addTestsIfTopLevelSuite(); +} + +/// If the current suite is the top-level one, add tests to the `test` package. +void _addTestsIfTopLevelSuite() { + if (_currentSuiteLevel == 0) { + void runTests({required bool allGroups, required bool allTests}) { + for (var group in _currentGroups) { + if (allGroups || group.isSolo) { + for (var test in group.tests) { + if (allTests || test.isSolo) { + test_package.test(test.name, test.function, + timeout: test.timeout, skip: test.isSkipped); + } + } + } + } + } + + if (_currentGroups.any((g) => g.hasSoloTest)) { + runTests(allGroups: true, allTests: false); + } else if (_currentGroups.any((g) => g.isSolo)) { + runTests(allGroups: false, allTests: true); + } else { + runTests(allGroups: true, allTests: true); + } + _currentGroups.clear(); + } +} + +/// Return the combination of the [base] and [addition] names. +/// If any other two is `null`, then the other one is returned. +String _combineNames(String base, String addition) { + if (base.isEmpty) { + return addition; + } else if (addition.isEmpty) { + return base; + } else { + return '$base | $addition'; + } +} + +Object? _getAnnotationInstance(DeclarationMirror declaration, Type type) { + for (var annotation in declaration.metadata) { + if ((annotation.reflectee as Object).runtimeType == type) { + return annotation.reflectee; + } + } + return null; +} + +bool _hasAnnotationInstance(DeclarationMirror declaration, Object instance) => + declaration.metadata.any((InstanceMirror annotation) => + identical(annotation.reflectee, instance)); + +bool _hasAssertFailingTestAnnotation(MethodMirror method) => + _hasAnnotationInstance(method, assertFailingTest); + +bool _hasFailingTestAnnotation(MethodMirror method) => + _hasAnnotationInstance(method, failingTest); + +bool _hasSkippedTestAnnotation(MethodMirror method) => + _hasAnnotationInstance(method, skippedTest); + +Future _invokeSymbolIfExists( + InstanceMirror instanceMirror, Symbol symbol) { + Object? invocationResult; + InstanceMirror? closure; + try { + closure = instanceMirror.getField(symbol); + // ignore: avoid_catching_errors + } on NoSuchMethodError { + // ignore + } + + if (closure is ClosureMirror) { + invocationResult = closure.apply([]).reflectee; + } + return Future.value(invocationResult); +} + +/// Run a test that is expected to fail, and confirm that it fails. +/// +/// This properly handles the following cases: +/// - The test fails by throwing an exception +/// - The test returns a future which completes with an error. +/// - An exception is thrown to the zone handler from a timer task. +Future? _runFailingTest(ClassMirror classMirror, Symbol symbol) { + var passed = false; + return runZonedGuarded(() { + // ignore: void_checks + return Future.sync(() => _runTest(classMirror, symbol)).then((_) { + passed = true; + test_package.fail('Test passed - expected to fail.'); + }).catchError((Object e) { + // if passed, and we call fail(), rethrow this exception + if (passed) { + // ignore: only_throw_errors + throw e; + } + // otherwise, an exception is not a failure for _runFailingTest + }); + }, (e, st) { + // if passed, and we call fail(), rethrow this exception + if (passed) { + // ignore: only_throw_errors + throw e; + } + // otherwise, an exception is not a failure for _runFailingTest + }); +} + +Future _runTest(ClassMirror classMirror, Symbol symbol) async { + var instanceMirror = classMirror.newInstance(const Symbol(''), []); + try { + await _invokeSymbolIfExists(instanceMirror, #setUp); + await instanceMirror.invoke(symbol, []).reflectee; + } finally { + await _invokeSymbolIfExists(instanceMirror, #tearDown); + } +} + +typedef _TestFunction = dynamic Function(); + +/// A marker annotation used to annotate test methods which are expected to +/// fail. +class FailingTest { + /// Initialize this annotation with the given arguments. + /// + /// [issue] is a full URI describing the failure and used for tracking. + /// [reason] is a free form textual description. + const FailingTest({String? issue, String? reason}); +} + +/// A marker annotation used to annotate test methods which are skipped. +class SkippedTest { + /// Initialize this annotation with the given arguments. + /// + /// [issue] is a full URI describing the failure and used for tracking. + /// [reason] is a free form textual description. + const SkippedTest({String? issue, String? reason}); +} + +/// A marker annotation used to annotate test methods with additional timeout +/// information. +class TestTimeout { + final test_package.Timeout _timeout; + + /// Initialize this annotation with the given timeout. + const TestTimeout(test_package.Timeout timeout) : _timeout = timeout; +} + +/// A marker annotation used to annotate test methods which are expected to fail +/// when asserts are enabled. +class _AssertFailingTest { + const _AssertFailingTest(); +} + +/// Information about a type based test group. +class _Group { + final bool isSolo; + final String name; + final List<_Test> tests = <_Test>[]; + + _Group(this.isSolo, this.name); + + bool get hasSoloTest => tests.any((test) => test.isSolo); + + void addSkippedTest(String name) { + var fullName = _combineNames(this.name, name); + tests.add(_Test.skipped(isSolo, fullName)); + } + + void addTest(bool isSolo, String name, MethodMirror memberMirror, + _TestFunction function) { + var fullName = _combineNames(this.name, name); + var timeout = + _getAnnotationInstance(memberMirror, TestTimeout) as TestTimeout?; + tests.add(_Test(isSolo, fullName, function, timeout?._timeout)); + } +} + +/// A marker annotation used to instruct dart2js to keep reflection information +/// for the annotated classes. +class _ReflectiveTest { + const _ReflectiveTest(); +} + +/// A marker annotation used to annotate "solo" groups and tests. +class _SoloTest { + const _SoloTest(); +} + +/// Information about a test. +class _Test { + final bool isSolo; + final String name; + final _TestFunction function; + final test_package.Timeout? timeout; + + final bool isSkipped; + + _Test(this.isSolo, this.name, this.function, this.timeout) + : isSkipped = false; + + _Test.skipped(this.isSolo, this.name) + : isSkipped = true, + function = (() {}), + timeout = null; +} diff --git a/pkgs/test_reflective_loader/pubspec.yaml b/pkgs/test_reflective_loader/pubspec.yaml new file mode 100644 index 000000000..569933f23 --- /dev/null +++ b/pkgs/test_reflective_loader/pubspec.yaml @@ -0,0 +1,13 @@ +name: test_reflective_loader +version: 0.2.3 +description: Support for discovering tests and test suites using reflection. +repository: https://github.com/dart-lang/tools/tree/main/pkgs/test_reflective_loader + +environment: + sdk: ^3.1.0 + +dependencies: + test: ^1.16.0 + +dev_dependencies: + dart_flutter_team_lints: ^3.0.0 diff --git a/pkgs/test_reflective_loader/test/test_reflective_loader_test.dart b/pkgs/test_reflective_loader/test/test_reflective_loader_test.dart new file mode 100644 index 000000000..fad98a5a1 --- /dev/null +++ b/pkgs/test_reflective_loader/test/test_reflective_loader_test.dart @@ -0,0 +1,48 @@ +// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +// ignore_for_file: non_constant_identifier_names + +import 'dart:async'; + +import 'package:test/test.dart'; +import 'package:test_reflective_loader/test_reflective_loader.dart'; + +void main() { + defineReflectiveSuite(() { + defineReflectiveTests(TestReflectiveLoaderTest); + }); +} + +@reflectiveTest +class TestReflectiveLoaderTest { + void test_passes() { + expect(true, true); + } + + @failingTest + void test_fails() { + expect(false, true); + } + + @failingTest + void test_fails_throws_sync() { + throw StateError('foo'); + } + + @failingTest + Future test_fails_throws_async() { + return Future.error('foo'); + } + + @skippedTest + void test_fails_but_skipped() { + throw StateError('foo'); + } + + @skippedTest + void test_times_out_but_skipped() { + while (true) {} + } +} diff --git a/pkgs/timing/.gitignore b/pkgs/timing/.gitignore new file mode 100644 index 000000000..1ddf798b7 --- /dev/null +++ b/pkgs/timing/.gitignore @@ -0,0 +1,7 @@ +.packages +/build/ +pubspec.lock + +# Files generated by dart tools +.dart_tool +doc/ diff --git a/pkgs/timing/CHANGELOG.md b/pkgs/timing/CHANGELOG.md new file mode 100644 index 000000000..8cdb8eadc --- /dev/null +++ b/pkgs/timing/CHANGELOG.md @@ -0,0 +1,34 @@ +## 1.0.2 + +- Require Dart `3.4`. +- Move to `dart-lang/tools` monorepo. + +## 1.0.1 + +- Require Dart `2.14`. + +## 1.0.0 + +- Enable null safety. +- Require Dart `2.12`. + +## 0.1.1+3 + +- Allow `package:json_annotation` `'>=1.0.0 <5.0.0'`. + +## 0.1.1+2 + +- Support the latest version of `package:json_annotation`. +- Require Dart 2.2 or later. + +## 0.1.1+1 + +- Support the latest version of `package:json_annotation`. + +## 0.1.1 + +- Add JSON serialization + +## 0.1.0 + +- Initial release diff --git a/pkgs/timing/LICENSE b/pkgs/timing/LICENSE new file mode 100644 index 000000000..9972f6e70 --- /dev/null +++ b/pkgs/timing/LICENSE @@ -0,0 +1,27 @@ +Copyright 2018, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/pkgs/timing/README.md b/pkgs/timing/README.md new file mode 100644 index 000000000..9dab7cc51 --- /dev/null +++ b/pkgs/timing/README.md @@ -0,0 +1,30 @@ +[![Build Status](https://github.com/dart-lang/tools/actions/workflows/timing.yaml/badge.svg)](https://github.com/dart-lang/tools/actions/workflows/timing.yaml) +[![pub package](https://img.shields.io/pub/v/timing.svg)](https://pub.dev/packages/timing) +[![package publisher](https://img.shields.io/pub/publisher/timing.svg)](https://pub.dev/packages/timing/publisher) + +Timing is a simple package for tracking performance of both async and sync actions + +## Usage + +```dart +var tracker = AsyncTimeTracker(); +await tracker.track(() async { + // some async code here +}); + +// Use results +print('${tracker.duration} ${tracker.innerDuration} ${tracker.slices}'); +``` + +## Building + +Use the following command to re-generate `lib/src/timing.g.dart` file: + +```bash +dart pub run build_runner build +``` + +## Publishing automation + +For information about our publishing automation and release process, see +https://github.com/dart-lang/ecosystem/wiki/Publishing-automation. diff --git a/pkgs/timing/analysis_options.yaml b/pkgs/timing/analysis_options.yaml new file mode 100644 index 000000000..396236d68 --- /dev/null +++ b/pkgs/timing/analysis_options.yaml @@ -0,0 +1,2 @@ +# https://dart.dev/tools/analysis#the-analysis-options-file +include: package:dart_flutter_team_lints/analysis_options.yaml diff --git a/pkgs/timing/lib/src/clock.dart b/pkgs/timing/lib/src/clock.dart new file mode 100644 index 000000000..6a9d29509 --- /dev/null +++ b/pkgs/timing/lib/src/clock.dart @@ -0,0 +1,20 @@ +// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file +// for details. 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:async'; + +/// A function that returns the current [DateTime]. +typedef _Clock = DateTime Function(); +DateTime _defaultClock() => DateTime.now(); + +const _zoneKey = #timing_Clock; + +/// Returns the current [DateTime]. +/// +/// May be overridden for tests using [scopeClock]. +DateTime now() => (Zone.current[_zoneKey] as _Clock? ?? _defaultClock)(); + +/// Runs [f], with [clock] scoped whenever [now] is called. +T scopeClock(DateTime Function() clock, T Function() f) => + runZoned(f, zoneValues: {_zoneKey: clock}); diff --git a/pkgs/timing/lib/src/timing.dart b/pkgs/timing/lib/src/timing.dart new file mode 100644 index 000000000..049ba8189 --- /dev/null +++ b/pkgs/timing/lib/src/timing.dart @@ -0,0 +1,338 @@ +// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file +// for details. 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:async'; + +import 'package:json_annotation/json_annotation.dart'; + +import 'clock.dart'; + +part 'timing.g.dart'; + +/// The timings of an operation, including its [startTime], [stopTime], and +/// [duration]. +@JsonSerializable() +class TimeSlice { + /// The total duration of this operation, equivalent to taking the difference + /// between [stopTime] and [startTime]. + Duration get duration => stopTime.difference(startTime); + + final DateTime startTime; + + final DateTime stopTime; + + TimeSlice(this.startTime, this.stopTime); + + factory TimeSlice.fromJson(Map json) => + _$TimeSliceFromJson(json); + + Map toJson() => _$TimeSliceToJson(this); + + @override + String toString() => '($startTime + $duration)'; +} + +/// The timings of an async operation, consist of several sync [slices] and +/// includes total [startTime], [stopTime], and [duration]. +@JsonSerializable() +class TimeSliceGroup implements TimeSlice { + final List slices; + + @override + DateTime get startTime => slices.first.startTime; + + @override + DateTime get stopTime => slices.last.stopTime; + + /// The total duration of this operation, equivalent to taking the difference + /// between [stopTime] and [startTime]. + @override + Duration get duration => stopTime.difference(startTime); + + /// Sum of [duration]s of all [slices]. + /// + /// If some of slices implements [TimeSliceGroup] [innerDuration] will be used + /// to compute sum. + Duration get innerDuration => slices.fold( + Duration.zero, + (duration, slice) => + duration + + (slice is TimeSliceGroup ? slice.innerDuration : slice.duration)); + + TimeSliceGroup(this.slices); + + /// Constructs TimeSliceGroup from JSON representation + factory TimeSliceGroup.fromJson(Map json) => + _$TimeSliceGroupFromJson(json); + + @override + Map toJson() => _$TimeSliceGroupToJson(this); + + @override + String toString() => slices.toString(); +} + +abstract class TimeTracker implements TimeSlice { + /// Whether tracking is active. + /// + /// Tracking is only active after `isStarted` and before `isFinished`. + bool get isTracking; + + /// Whether tracking is finished. + /// + /// Tracker can't be used as [TimeSlice] before it is finished + bool get isFinished; + + /// Whether tracking was started. + /// + /// Equivalent of `isTracking || isFinished` + bool get isStarted; + + T track(T Function() action); +} + +/// Tracks only sync actions +class SyncTimeTracker implements TimeTracker { + /// When this operation started, call [_start] to set this. + @override + DateTime get startTime => _startTime!; + DateTime? _startTime; + + /// When this operation stopped, call [_stop] to set this. + @override + DateTime get stopTime => _stopTime!; + DateTime? _stopTime; + + /// Start tracking this operation, must only be called once, before [_stop]. + void _start() { + assert(_startTime == null && _stopTime == null); + _startTime = now(); + } + + /// Stop tracking this operation, must only be called once, after [_start]. + void _stop() { + assert(_startTime != null && _stopTime == null); + _stopTime = now(); + } + + /// Splits tracker into two slices. + /// + /// Returns new [TimeSlice] started on [startTime] and ended now. Modifies + /// [startTime] of tracker to current time point + /// + /// Don't change state of tracker. Can be called only while [isTracking], and + /// tracker will sill be tracking after call. + TimeSlice _split() { + if (!isTracking) { + throw StateError('Can be only called while tracking'); + } + final splitPoint = now(); + final prevSlice = TimeSlice(_startTime!, splitPoint); + _startTime = splitPoint; + return prevSlice; + } + + @override + T track(T Function() action) { + if (isStarted) { + throw StateError('Can not be tracked twice'); + } + _start(); + try { + return action(); + } finally { + _stop(); + } + } + + @override + bool get isStarted => _startTime != null; + + @override + bool get isTracking => _startTime != null && _stopTime == null; + + @override + bool get isFinished => _startTime != null && _stopTime != null; + + @override + Duration get duration => _stopTime!.difference(_startTime!); + + /// Converts to JSON representation + /// + /// Can't be used before [isFinished] + @override + Map toJson() => _$TimeSliceToJson(this); +} + +/// Async actions returning [Future] will be tracked as single sync time span +/// from the beginning of execution till completion of future +class SimpleAsyncTimeTracker extends SyncTimeTracker { + @override + T track(T Function() action) { + if (isStarted) { + throw StateError('Can not be tracked twice'); + } + T result; + _start(); + try { + result = action(); + } catch (_) { + _stop(); + rethrow; + } + if (result is Future) { + return result.whenComplete(_stop) as T; + } else { + _stop(); + return result; + } + } +} + +/// No-op implementation of [SyncTimeTracker] that does nothing. +class NoOpTimeTracker implements TimeTracker { + static final sharedInstance = NoOpTimeTracker(); + + @override + Duration get duration => + throw UnsupportedError('Unsupported in no-op implementation'); + + @override + DateTime get startTime => + throw UnsupportedError('Unsupported in no-op implementation'); + + @override + DateTime get stopTime => + throw UnsupportedError('Unsupported in no-op implementation'); + + @override + bool get isStarted => + throw UnsupportedError('Unsupported in no-op implementation'); + + @override + bool get isTracking => + throw UnsupportedError('Unsupported in no-op implementation'); + + @override + bool get isFinished => + throw UnsupportedError('Unsupported in no-op implementation'); + + @override + T track(T Function() action) => action(); + + @override + Map toJson() => + throw UnsupportedError('Unsupported in no-op implementation'); +} + +/// Track all async execution as disjoint time [slices] in ascending order. +/// +/// Can [track] both async and sync actions. +/// Can exclude time of tested trackers. +/// +/// If tracked action spawns some dangled async executions behavior is't +/// defined. Tracked might or might not track time of such executions +class AsyncTimeTracker extends TimeSliceGroup implements TimeTracker { + final bool trackNested; + + static const _zoneKey = #timing_AsyncTimeTracker; + + AsyncTimeTracker({this.trackNested = true}) : super([]); + + T _trackSyncSlice(ZoneDelegate parent, Zone zone, T Function() action) { + // Ignore dangling runs after tracker completes + if (isFinished) { + return action(); + } + + final isNestedRun = slices.isNotEmpty && + slices.last is SyncTimeTracker && + (slices.last as SyncTimeTracker).isTracking; + final isExcludedNestedTrack = !trackNested && zone[_zoneKey] != this; + + // Exclude nested sync tracks + if (isNestedRun && isExcludedNestedTrack) { + final timer = slices.last as SyncTimeTracker; + // Split already tracked time into new slice. + // Replace tracker in slices.last with splitted slice, to indicate for + // recursive calls that we not tracking. + slices.last = parent.run(zone, timer._split); + try { + return action(); + } finally { + // Split tracker again and discard slice from nested tracker + parent.run(zone, timer._split); + // Add tracker back to list of slices and continue tracking + slices.add(timer); + } + } + + // Exclude nested async tracks + if (isExcludedNestedTrack) { + return action(); + } + + // Split time slices in nested sync runs + if (isNestedRun) { + return action(); + } + + final timer = SyncTimeTracker(); + slices.add(timer); + + // Pass to parent zone, in case of overwritten clock + return parent.runUnary(zone, timer.track, action); + } + + static final asyncTimeTrackerZoneSpecification = ZoneSpecification( + run: (Zone self, ZoneDelegate parent, Zone zone, R Function() f) { + final tracker = self[_zoneKey] as AsyncTimeTracker; + return tracker._trackSyncSlice(parent, zone, () => parent.run(zone, f)); + }, + runUnary: (Zone self, ZoneDelegate parent, Zone zone, R Function(T) f, + T arg) { + final tracker = self[_zoneKey] as AsyncTimeTracker; + return tracker._trackSyncSlice( + parent, zone, () => parent.runUnary(zone, f, arg)); + }, + runBinary: (Zone self, ZoneDelegate parent, Zone zone, + R Function(T1, T2) f, T1 arg1, T2 arg2) { + final tracker = self[_zoneKey] as AsyncTimeTracker; + return tracker._trackSyncSlice( + parent, zone, () => parent.runBinary(zone, f, arg1, arg2)); + }, + ); + + @override + T track(T Function() action) { + if (isStarted) { + throw StateError('Can not be tracked twice'); + } + _tracking = true; + final result = runZoned(action, + zoneSpecification: asyncTimeTrackerZoneSpecification, + zoneValues: {_zoneKey: this}); + if (result is Future) { + return result + // Break possible sync processing of future completion, so slice + // trackers can be finished + .whenComplete(Future.value) + .whenComplete(() => _tracking = false) as T; + } else { + _tracking = false; + return result; + } + } + + bool? _tracking; + + @override + bool get isStarted => _tracking != null; + + @override + bool get isFinished => _tracking == false; + + @override + bool get isTracking => _tracking == true; +} diff --git a/pkgs/timing/lib/src/timing.g.dart b/pkgs/timing/lib/src/timing.g.dart new file mode 100644 index 000000000..679c082ff --- /dev/null +++ b/pkgs/timing/lib/src/timing.g.dart @@ -0,0 +1,29 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'timing.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +TimeSlice _$TimeSliceFromJson(Map json) => TimeSlice( + DateTime.parse(json['startTime'] as String), + DateTime.parse(json['stopTime'] as String), + ); + +Map _$TimeSliceToJson(TimeSlice instance) => { + 'startTime': instance.startTime.toIso8601String(), + 'stopTime': instance.stopTime.toIso8601String(), + }; + +TimeSliceGroup _$TimeSliceGroupFromJson(Map json) => + TimeSliceGroup( + (json['slices'] as List) + .map((e) => TimeSlice.fromJson(e as Map)) + .toList(), + ); + +Map _$TimeSliceGroupToJson(TimeSliceGroup instance) => + { + 'slices': instance.slices, + }; diff --git a/pkgs/timing/lib/timing.dart b/pkgs/timing/lib/timing.dart new file mode 100644 index 000000000..5cb16d423 --- /dev/null +++ b/pkgs/timing/lib/timing.dart @@ -0,0 +1,13 @@ +// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +export 'src/timing.dart' + show + AsyncTimeTracker, + NoOpTimeTracker, + SimpleAsyncTimeTracker, + SyncTimeTracker, + TimeSlice, + TimeSliceGroup, + TimeTracker; diff --git a/pkgs/timing/pubspec.yaml b/pkgs/timing/pubspec.yaml new file mode 100644 index 000000000..891a8af3d --- /dev/null +++ b/pkgs/timing/pubspec.yaml @@ -0,0 +1,18 @@ +name: timing +version: 1.0.2 +description: >- + A simple package for tracking the performance of synchronous and asynchronous + actions. +repository: https://github.com/dart-lang/tools/tree/main/pkgs/timing + +environment: + sdk: ^3.4.0 + +dependencies: + json_annotation: ^4.9.0 + +dev_dependencies: + build_runner: ^2.0.6 + dart_flutter_team_lints: ^3.0.0 + json_serializable: ^6.0.0 + test: ^1.17.10 diff --git a/pkgs/timing/test/timing_test.dart b/pkgs/timing/test/timing_test.dart new file mode 100644 index 000000000..b5836d9d2 --- /dev/null +++ b/pkgs/timing/test/timing_test.dart @@ -0,0 +1,416 @@ +// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +// ignore_for_file: only_throw_errors, inference_failure_on_instance_creation + +import 'dart:async'; + +import 'package:test/test.dart'; +import 'package:timing/src/clock.dart'; +import 'package:timing/src/timing.dart'; + +void _noop() {} + +void main() { + late DateTime time; + final startTime = DateTime(2017); + DateTime fakeClock() => time; + + late TimeTracker tracker; + late TimeTracker nestedTracker; + + T scopedTrack(T Function() f) => + scopeClock(fakeClock, () => tracker.track(f)); + + setUp(() { + time = startTime; + }); + + void canHandleSync([void Function() additionalExpects = _noop]) { + test('Can track sync code', () { + expect(tracker.isStarted, false); + expect(tracker.isTracking, false); + expect(tracker.isFinished, false); + scopedTrack(() { + expect(tracker.isStarted, true); + expect(tracker.isTracking, true); + expect(tracker.isFinished, false); + time = time.add(const Duration(seconds: 5)); + }); + expect(tracker.isStarted, true); + expect(tracker.isTracking, false); + expect(tracker.isFinished, true); + expect(tracker.startTime, startTime); + expect(tracker.stopTime, time); + expect(tracker.duration, const Duration(seconds: 5)); + additionalExpects(); + }); + + test('Can track handled sync exceptions', () async { + scopedTrack(() { + try { + time = time.add(const Duration(seconds: 4)); + throw 'error'; + } on String { + time = time.add(const Duration(seconds: 1)); + } + }); + expect(tracker.isFinished, true); + expect(tracker.startTime, startTime); + expect(tracker.stopTime, time); + expect(tracker.duration, const Duration(seconds: 5)); + additionalExpects(); + }); + + test('Can track in case of unhandled sync exceptions', () async { + expect( + () => scopedTrack(() { + time = time.add(const Duration(seconds: 5)); + throw 'error'; + }), + throwsA(const TypeMatcher())); + expect(tracker.startTime, startTime); + expect(tracker.stopTime, time); + expect(tracker.duration, const Duration(seconds: 5)); + additionalExpects(); + }); + + test('Can be nested sync', () { + scopedTrack(() { + time = time.add(const Duration(seconds: 1)); + nestedTracker.track(() { + time = time.add(const Duration(seconds: 2)); + }); + time = time.add(const Duration(seconds: 4)); + }); + expect(tracker.isFinished, true); + expect(tracker.startTime, startTime); + expect(tracker.stopTime, time); + expect(tracker.duration, const Duration(seconds: 7)); + expect(nestedTracker.startTime.isAfter(startTime), true); + expect(nestedTracker.stopTime.isBefore(time), true); + expect(nestedTracker.duration, const Duration(seconds: 2)); + additionalExpects(); + }); + } + + void canHandleAsync([void Function() additionalExpects = _noop]) { + test('Can track async code', () async { + expect(tracker.isStarted, false); + expect(tracker.isTracking, false); + expect(tracker.isFinished, false); + await scopedTrack(() => Future(() { + expect(tracker.isStarted, true); + expect(tracker.isTracking, true); + expect(tracker.isFinished, false); + time = time.add(const Duration(seconds: 5)); + })); + expect(tracker.isStarted, true); + expect(tracker.isTracking, false); + expect(tracker.isFinished, true); + expect(tracker.startTime, startTime); + expect(tracker.stopTime, time); + expect(tracker.duration, const Duration(seconds: 5)); + additionalExpects(); + }); + + test('Can track handled async exceptions', () async { + await scopedTrack(() { + time = time.add(const Duration(seconds: 1)); + return Future(() { + time = time.add(const Duration(seconds: 2)); + throw 'error'; + }).then((_) { + time = time.add(const Duration(seconds: 4)); + }).catchError((error, stack) { + time = time.add(const Duration(seconds: 8)); + }); + }); + expect(tracker.isFinished, true); + expect(tracker.startTime, startTime); + expect(tracker.stopTime, time); + expect(tracker.duration, const Duration(seconds: 11)); + additionalExpects(); + }); + + test('Can track in case of unhandled async exceptions', () async { + final future = scopedTrack(() { + time = time.add(const Duration(seconds: 1)); + return Future(() { + time = time.add(const Duration(seconds: 2)); + throw 'error'; + }).then((_) { + time = time.add(const Duration(seconds: 4)); + }); + }); + await expectLater(future, throwsA(const TypeMatcher())); + expect(tracker.isFinished, true); + expect(tracker.startTime, startTime); + expect(tracker.stopTime, time); + expect(tracker.duration, const Duration(seconds: 3)); + additionalExpects(); + }); + + test('Can be nested async', () async { + await scopedTrack(() async { + time = time.add(const Duration(milliseconds: 1)); + await Future.value(); + time = time.add(const Duration(milliseconds: 2)); + await nestedTracker.track(() async { + time = time.add(const Duration(milliseconds: 4)); + await Future.value(); + time = time.add(const Duration(milliseconds: 8)); + await Future.value(); + time = time.add(const Duration(milliseconds: 16)); + }); + time = time.add(const Duration(milliseconds: 32)); + await Future.value(); + time = time.add(const Duration(milliseconds: 64)); + }); + expect(tracker.isFinished, true); + expect(tracker.startTime, startTime); + expect(tracker.stopTime, time); + expect(tracker.duration, const Duration(milliseconds: 127)); + expect(nestedTracker.startTime.isAfter(startTime), true); + expect(nestedTracker.stopTime.isBefore(time), true); + expect(nestedTracker.duration, const Duration(milliseconds: 28)); + additionalExpects(); + }); + } + + group('SyncTimeTracker', () { + setUp(() { + tracker = SyncTimeTracker(); + nestedTracker = SyncTimeTracker(); + }); + + canHandleSync(); + + test('Can not track async code', () async { + await scopedTrack(() => Future(() { + time = time.add(const Duration(seconds: 5)); + })); + expect(tracker.isFinished, true); + expect(tracker.startTime, startTime); + expect(tracker.stopTime, startTime); + expect(tracker.duration, const Duration(seconds: 0)); + }); + }); + + group('AsyncTimeTracker.simple', () { + setUp(() { + tracker = SimpleAsyncTimeTracker(); + nestedTracker = SimpleAsyncTimeTracker(); + }); + + canHandleSync(); + + canHandleAsync(); + + test('Can not distinguish own async code', () async { + final future = scopedTrack(() => Future(() { + time = time.add(const Duration(seconds: 5)); + })); + time = time.add(const Duration(seconds: 10)); + await future; + expect(tracker.isFinished, true); + expect(tracker.startTime, startTime); + expect(tracker.stopTime, time); + expect(tracker.duration, const Duration(seconds: 15)); + }); + }); + + group('AsyncTimeTracker', () { + late AsyncTimeTracker asyncTracker; + late AsyncTimeTracker nestedAsyncTracker; + setUp(() { + tracker = asyncTracker = AsyncTimeTracker(); + nestedTracker = nestedAsyncTracker = AsyncTimeTracker(); + }); + + canHandleSync(() { + expect(asyncTracker.innerDuration, asyncTracker.duration); + expect(asyncTracker.slices.length, 1); + }); + + canHandleAsync(() { + expect(asyncTracker.innerDuration, asyncTracker.duration); + expect(asyncTracker.slices.length, greaterThan(1)); + }); + + test('Can track complex async innerDuration', () async { + final completer = Completer(); + final future = scopedTrack(() async { + time = time.add(const Duration(seconds: 1)); // Tracked sync + await Future.value(); + time = time.add(const Duration(seconds: 2)); // Tracked async + await completer.future; + time = time.add(const Duration(seconds: 4)); // Tracked async, delayed + }).then((_) { + time = time.add(const Duration(seconds: 8)); // Async, after tracking + }); + time = time.add(const Duration(seconds: 16)); // Sync, between slices + + await Future(() { + // Async, between slices + time = time.add(const Duration(seconds: 32)); + completer.complete(); + }); + await future; + expect(asyncTracker.isFinished, true); + expect(asyncTracker.startTime, startTime); + expect(asyncTracker.stopTime.isBefore(time), true); + expect(asyncTracker.duration, const Duration(seconds: 55)); + expect(asyncTracker.innerDuration, const Duration(seconds: 7)); + expect(asyncTracker.slices.length, greaterThan(1)); + }); + + test('Can exclude nested sync', () { + tracker = asyncTracker = AsyncTimeTracker(trackNested: false); + scopedTrack(() { + time = time.add(const Duration(seconds: 1)); + nestedAsyncTracker.track(() { + time = time.add(const Duration(seconds: 2)); + }); + time = time.add(const Duration(seconds: 4)); + }); + expect(asyncTracker.isFinished, true); + expect(asyncTracker.startTime, startTime); + expect(asyncTracker.stopTime, time); + expect(asyncTracker.duration, const Duration(seconds: 7)); + expect(asyncTracker.innerDuration, const Duration(seconds: 5)); + expect(asyncTracker.slices.length, greaterThan(1)); + expect(nestedAsyncTracker.startTime.isAfter(startTime), true); + expect(nestedAsyncTracker.stopTime.isBefore(time), true); + expect(nestedAsyncTracker.duration, const Duration(seconds: 2)); + expect(nestedAsyncTracker.innerDuration, const Duration(seconds: 2)); + expect(nestedAsyncTracker.slices.length, 1); + }); + + test('Can exclude complex nested sync', () { + tracker = asyncTracker = AsyncTimeTracker(trackNested: false); + nestedAsyncTracker = AsyncTimeTracker(trackNested: false); + final nestedAsyncTracker2 = AsyncTimeTracker(trackNested: false); + scopedTrack(() { + time = time.add(const Duration(seconds: 1)); + nestedAsyncTracker.track(() { + time = time.add(const Duration(seconds: 2)); + nestedAsyncTracker2.track(() { + time = time.add(const Duration(seconds: 4)); + }); + time = time.add(const Duration(seconds: 8)); + }); + time = time.add(const Duration(seconds: 16)); + }); + expect(asyncTracker.isFinished, true); + expect(asyncTracker.startTime, startTime); + expect(asyncTracker.stopTime, time); + expect(asyncTracker.duration, const Duration(seconds: 31)); + expect(asyncTracker.innerDuration, const Duration(seconds: 17)); + expect(asyncTracker.slices.length, greaterThan(1)); + expect(nestedAsyncTracker.startTime.isAfter(startTime), true); + expect(nestedAsyncTracker.stopTime.isBefore(time), true); + expect(nestedAsyncTracker.duration, const Duration(seconds: 14)); + expect(nestedAsyncTracker.innerDuration, const Duration(seconds: 10)); + expect(nestedAsyncTracker.slices.length, greaterThan(1)); + expect(nestedAsyncTracker2.startTime.isAfter(startTime), true); + expect(nestedAsyncTracker2.stopTime.isBefore(time), true); + expect(nestedAsyncTracker2.duration, const Duration(seconds: 4)); + expect(nestedAsyncTracker2.innerDuration, const Duration(seconds: 4)); + expect(nestedAsyncTracker2.slices.length, 1); + }); + + test( + 'Can track all on grand-parent level and ' + 'exclude grand-childrens from parent', () { + tracker = asyncTracker = AsyncTimeTracker(trackNested: true); + nestedAsyncTracker = AsyncTimeTracker(trackNested: false); + final nestedAsyncTracker2 = AsyncTimeTracker(); + scopedTrack(() { + time = time.add(const Duration(seconds: 1)); + nestedAsyncTracker.track(() { + time = time.add(const Duration(seconds: 2)); + nestedAsyncTracker2.track(() { + time = time.add(const Duration(seconds: 4)); + }); + time = time.add(const Duration(seconds: 8)); + }); + time = time.add(const Duration(seconds: 16)); + }); + expect(asyncTracker.isFinished, true); + expect(asyncTracker.startTime, startTime); + expect(asyncTracker.stopTime, time); + expect(asyncTracker.duration, const Duration(seconds: 31)); + expect(asyncTracker.innerDuration, const Duration(seconds: 31)); + expect(asyncTracker.slices.length, 1); + expect(nestedAsyncTracker.startTime.isAfter(startTime), true); + expect(nestedAsyncTracker.stopTime.isBefore(time), true); + expect(nestedAsyncTracker.duration, const Duration(seconds: 14)); + expect(nestedAsyncTracker.innerDuration, const Duration(seconds: 10)); + expect(nestedAsyncTracker.slices.length, greaterThan(1)); + expect(nestedAsyncTracker2.startTime.isAfter(startTime), true); + expect(nestedAsyncTracker2.stopTime.isBefore(time), true); + expect(nestedAsyncTracker2.duration, const Duration(seconds: 4)); + expect(nestedAsyncTracker2.innerDuration, const Duration(seconds: 4)); + expect(nestedAsyncTracker2.slices.length, 1); + }); + + test('Can exclude nested async', () async { + tracker = asyncTracker = AsyncTimeTracker(trackNested: false); + await scopedTrack(() async { + time = time.add(const Duration(seconds: 1)); + await nestedAsyncTracker.track(() async { + time = time.add(const Duration(seconds: 2)); + await Future.value(); + time = time.add(const Duration(seconds: 4)); + await Future.value(); + time = time.add(const Duration(seconds: 8)); + }); + time = time.add(const Duration(seconds: 16)); + }); + expect(asyncTracker.isFinished, true); + expect(asyncTracker.startTime, startTime); + expect(asyncTracker.stopTime, time); + expect(asyncTracker.duration, const Duration(seconds: 31)); + expect(asyncTracker.innerDuration, const Duration(seconds: 17)); + expect(asyncTracker.slices.length, greaterThan(1)); + expect(nestedAsyncTracker.startTime.isAfter(startTime), true); + expect(nestedAsyncTracker.stopTime.isBefore(time), true); + expect(nestedAsyncTracker.duration, const Duration(seconds: 14)); + expect(nestedAsyncTracker.innerDuration, const Duration(seconds: 14)); + expect(nestedAsyncTracker.slices.length, greaterThan(1)); + }); + + test('Can handle callbacks in excluded nested async', () async { + tracker = asyncTracker = AsyncTimeTracker(trackNested: false); + await scopedTrack(() async { + time = time.add(const Duration(seconds: 1)); + final completer = Completer(); + final future = completer.future.then((_) { + time = time.add(const Duration(seconds: 2)); + }); + await nestedAsyncTracker.track(() async { + time = time.add(const Duration(seconds: 4)); + await Future.value(); + time = time.add(const Duration(seconds: 8)); + completer.complete(); + await future; + time = time.add(const Duration(seconds: 16)); + }); + time = time.add(const Duration(seconds: 32)); + }); + expect(asyncTracker.isFinished, true); + expect(asyncTracker.startTime, startTime); + expect(asyncTracker.stopTime, time); + expect(asyncTracker.duration, const Duration(seconds: 63)); + expect(asyncTracker.innerDuration, const Duration(seconds: 35)); + expect(asyncTracker.slices.length, greaterThan(1)); + expect(nestedAsyncTracker.startTime.isAfter(startTime), true); + expect(nestedAsyncTracker.stopTime.isBefore(time), true); + expect(nestedAsyncTracker.duration, const Duration(seconds: 30)); + expect(nestedAsyncTracker.innerDuration, const Duration(seconds: 28)); + expect(nestedAsyncTracker.slices.length, greaterThan(1)); + }); + }); +}