From 2b8b80903902dcc220d68e3093b9bbb51f08cd37 Mon Sep 17 00:00:00 2001 From: Nate Bosch Date: Tue, 22 Jul 2025 00:26:32 +0000 Subject: [PATCH 01/11] Require latest analyzer Use the new definition of the `name` field and restrict pub deps to the latest major version. --- pkgs/test/CHANGELOG.md | 4 ++++ pkgs/test/pubspec.yaml | 6 +++--- pkgs/test_api/CHANGELOG.md | 4 ++++ pkgs/test_api/pubspec.yaml | 4 ++-- pkgs/test_core/CHANGELOG.md | 4 ++++ pkgs/test_core/lib/src/runner/parse_metadata.dart | 8 ++------ pkgs/test_core/pubspec.yaml | 6 +++--- 7 files changed, 22 insertions(+), 14 deletions(-) diff --git a/pkgs/test/CHANGELOG.md b/pkgs/test/CHANGELOG.md index f1584dd8f..fde711584 100644 --- a/pkgs/test/CHANGELOG.md +++ b/pkgs/test/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.26.4-wip + +* Restrict to latest version of analyzer package. + ## 1.26.3 * Expand pub constraint to allow the latest `analyzer`. diff --git a/pkgs/test/pubspec.yaml b/pkgs/test/pubspec.yaml index 8c4e81782..70072f2e9 100644 --- a/pkgs/test/pubspec.yaml +++ b/pkgs/test/pubspec.yaml @@ -1,5 +1,5 @@ name: test -version: 1.26.3 +version: 1.26.4-wip description: >- A full featured library for writing and running Dart tests across platforms. repository: https://github.com/dart-lang/test/tree/master/pkgs/test @@ -36,8 +36,8 @@ dependencies: stream_channel: ^2.1.0 # Use an exact version until the test_api and test_core package are stable. - test_api: 0.7.7 - test_core: 0.6.12 + test_api: 0.7.8-wip + test_core: 0.6.13-wip typed_data: ^1.3.0 web_socket_channel: '>=2.0.0 <4.0.0' diff --git a/pkgs/test_api/CHANGELOG.md b/pkgs/test_api/CHANGELOG.md index 36110faa5..4ca3a6675 100644 --- a/pkgs/test_api/CHANGELOG.md +++ b/pkgs/test_api/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.7.9-wip + +* Restrict to latest version of analyzer package. + ## 0.7.7 * Expand pub constraint to allow the latest `analyzer`. diff --git a/pkgs/test_api/pubspec.yaml b/pkgs/test_api/pubspec.yaml index 08640b880..bddeff5e5 100644 --- a/pkgs/test_api/pubspec.yaml +++ b/pkgs/test_api/pubspec.yaml @@ -1,5 +1,5 @@ name: test_api -version: 0.7.7 +version: 0.7.8-wip description: >- The user facing API for structuring Dart tests and checking expectations. repository: https://github.com/dart-lang/test/tree/master/pkgs/test_api @@ -21,7 +21,7 @@ dependencies: term_glyph: ^1.2.0 dev_dependencies: - analyzer: '>=6.0.0 <9.0.0' + analyzer: ^8.0.0 fake_async: ^1.2.0 glob: ^2.0.0 graphs: ^2.0.0 diff --git a/pkgs/test_core/CHANGELOG.md b/pkgs/test_core/CHANGELOG.md index b37a239ae..522756b8a 100644 --- a/pkgs/test_core/CHANGELOG.md +++ b/pkgs/test_core/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.13-wip + +* Restrict to latest version of analyzer package. + ## 0.6.12 * Expand pub constraint to allow the latest `analyzer`. diff --git a/pkgs/test_core/lib/src/runner/parse_metadata.dart b/pkgs/test_core/lib/src/runner/parse_metadata.dart index e1e087376..9aa9681e1 100644 --- a/pkgs/test_core/lib/src/runner/parse_metadata.dart +++ b/pkgs/test_core/lib/src/runner/parse_metadata.dart @@ -214,9 +214,7 @@ class _Parser { Object? skip; for (var expression in expressions) { if (expression is InstanceCreationExpression) { - // Replace name2 with name when bumping min analyzer dependency - // ignore: deprecated_member_use - var className = expression.constructorName.type.name2.lexeme; + var className = expression.constructorName.type.name.lexeme; if (className == 'Timeout') { _assertSingle(timeout, 'Timeout', expression); @@ -350,9 +348,7 @@ class _Parser { String? _findConstructorNameFromInstantiation( InstanceCreationExpression constructor, String className) { - // Replace name2 with name when bumping min analyzer dependency - // ignore: deprecated_member_use - var actualClassName = constructor.constructorName.type.name2.lexeme; + var actualClassName = constructor.constructorName.type.name.lexeme; var constructorName = constructor.constructorName.name?.name; if (actualClassName != className) { diff --git a/pkgs/test_core/pubspec.yaml b/pkgs/test_core/pubspec.yaml index a60c9f3f5..1b2152a9e 100644 --- a/pkgs/test_core/pubspec.yaml +++ b/pkgs/test_core/pubspec.yaml @@ -1,5 +1,5 @@ name: test_core -version: 0.6.12 +version: 0.6.13-wip description: A basic library for writing tests and running them on the VM. repository: https://github.com/dart-lang/test/tree/master/pkgs/test_core issue_tracker: https://github.com/dart-lang/test/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Atest @@ -9,7 +9,7 @@ environment: sdk: ^3.5.0 dependencies: - analyzer: '>=6.0.0 <9.0.0' + analyzer: ^8.0.0 args: ^2.0.0 async: ^2.5.0 boolean_selector: ^2.1.0 @@ -28,7 +28,7 @@ dependencies: stack_trace: ^1.10.0 stream_channel: ^2.1.0 # Use an exact version until the test_api package is stable. - test_api: 0.7.7 + test_api: 0.7.8-wip vm_service: '>=6.0.0 <16.0.0' yaml: ^3.0.0 From 8283504b101ca88aadf4bfa77ddd74b5f71caf79 Mon Sep 17 00:00:00 2001 From: Nate Bosch Date: Tue, 22 Jul 2025 00:29:16 +0000 Subject: [PATCH 02/11] Update to language version 2.7 Use the earliest SDK that will solve against the new analyzer constraints. --- .github/workflows/dart.yml | 358 +++++++++++++++++++++--------------- pkgs/test/pubspec.yaml | 2 +- pkgs/test_core/pubspec.yaml | 2 +- tool/ci.sh | 2 +- 4 files changed, 212 insertions(+), 152 deletions(-) diff --git a/.github/workflows/dart.yml b/.github/workflows/dart.yml index 8097a4b29..9be8841a9 100644 --- a/.github/workflows/dart.yml +++ b/.github/workflows/dart.yml @@ -1,4 +1,4 @@ -# Created with package:mono_repo v6.6.2 +# Created with package:mono_repo v6.6.3 name: Dart CI on: push: @@ -36,7 +36,7 @@ jobs: name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - name: mono_repo self validate - run: dart pub global activate mono_repo 6.6.2 + run: dart pub global activate mono_repo 6.6.3 - name: mono_repo self validate run: dart pub global run mono_repo generate --validate job_002: @@ -87,16 +87,16 @@ jobs: if: "always() && steps.integration_tests_wasm_pub_upgrade.conclusion == 'success'" working-directory: integration_tests/wasm job_003: - name: "analyze_and_format; linux; Dart 3.5.0; PKGS: pkgs/checks, pkgs/matcher, pkgs/test_core; `dart analyze`" + name: "analyze_and_format; linux; Dart 3.5.0; PKGS: pkgs/checks, pkgs/matcher; `dart analyze`" runs-on: ubuntu-latest steps: - name: Cache Pub hosted dependencies uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/checks-pkgs/matcher-pkgs/test_core;commands:analyze_1" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/checks-pkgs/matcher;commands:analyze_1" restore-keys: | - os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/checks-pkgs/matcher-pkgs/test_core + os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/checks-pkgs/matcher os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0 os:ubuntu-latest;pub-cache-hosted os:ubuntu-latest @@ -125,6 +125,27 @@ jobs: run: dart analyze if: "always() && steps.pkgs_matcher_pub_upgrade.conclusion == 'success'" working-directory: pkgs/matcher + job_004: + name: "analyze_and_format; linux; Dart 3.7.0; PKG: pkgs/test_core; `dart analyze`" + runs-on: ubuntu-latest + steps: + - name: Cache Pub hosted dependencies + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 + with: + path: "~/.pub-cache/hosted" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0;packages:pkgs/test_core;commands:analyze_1" + restore-keys: | + os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0;packages:pkgs/test_core + os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0 + os:ubuntu-latest;pub-cache-hosted + os:ubuntu-latest + - name: Setup Dart SDK + uses: dart-lang/setup-dart@e51d8e571e22473a2ddebf0ef8a2123f0ab2c02c + with: + sdk: "3.7.0" + - id: checkout + name: Checkout repository + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - id: pkgs_test_core_pub_upgrade name: pkgs/test_core; dart pub upgrade run: dart pub upgrade @@ -134,7 +155,7 @@ jobs: run: dart analyze if: "always() && steps.pkgs_test_core_pub_upgrade.conclusion == 'success'" working-directory: pkgs/test_core - job_004: + job_005: name: "analyze_and_format; linux; Dart dev; PKGS: integration_tests/regression, integration_tests/spawn_hybrid, integration_tests/wasm, pkgs/checks, pkgs/matcher, pkgs/test, pkgs/test_api, pkgs/test_core; `dart format --output=none --set-exit-if-changed .`, `dart analyze --fatal-infos`" runs-on: ubuntu-latest steps: @@ -259,7 +280,7 @@ jobs: run: dart analyze --fatal-infos if: "always() && steps.pkgs_test_core_pub_upgrade.conclusion == 'success'" working-directory: pkgs/test_core - job_005: + job_006: name: "analyze_and_format; windows; Dart 3.5.0; PKG: integration_tests/wasm; `dart format --output=none --set-exit-if-changed .`, `dart analyze --fatal-infos`" runs-on: windows-latest steps: @@ -283,7 +304,7 @@ jobs: run: dart analyze --fatal-infos if: "always() && steps.integration_tests_wasm_pub_upgrade.conclusion == 'success'" working-directory: integration_tests/wasm - job_006: + job_007: name: "analyze_and_format; windows; Dart dev; PKG: integration_tests/wasm; `dart format --output=none --set-exit-if-changed .`, `dart analyze --fatal-infos`" runs-on: windows-latest steps: @@ -307,7 +328,7 @@ jobs: run: dart analyze --fatal-infos if: "always() && steps.integration_tests_wasm_pub_upgrade.conclusion == 'success'" working-directory: integration_tests/wasm - job_007: + job_008: name: "unit_test; linux; Dart 3.5.0; PKG: integration_tests/regression; `dart test`" runs-on: ubuntu-latest steps: @@ -344,7 +365,8 @@ jobs: - job_004 - job_005 - job_006 - job_008: + - job_007 + job_009: name: "unit_test; linux; Dart 3.5.0; PKG: pkgs/checks; `dart test`" runs-on: ubuntu-latest steps: @@ -381,7 +403,8 @@ jobs: - job_004 - job_005 - job_006 - job_009: + - job_007 + job_010: name: "unit_test; linux; Dart 3.5.0; PKG: pkgs/matcher; `dart test`" runs-on: ubuntu-latest steps: @@ -418,17 +441,18 @@ jobs: - job_004 - job_005 - job_006 - job_010: - name: "unit_test; linux; Dart 3.5.0; PKG: pkgs/test_core; `dart test`" + - job_007 + job_011: + name: "unit_test; linux; Dart 3.5.0; PKG: integration_tests/spawn_hybrid; `dart test -p chrome,vm,node`" runs-on: ubuntu-latest steps: - name: Cache Pub hosted dependencies uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/test_core;commands:command_00" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:integration_tests/spawn_hybrid;commands:test_1" restore-keys: | - os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/test_core + os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:integration_tests/spawn_hybrid os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0 os:ubuntu-latest;pub-cache-hosted os:ubuntu-latest @@ -439,15 +463,15 @@ jobs: - id: checkout name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - - id: pkgs_test_core_pub_upgrade - name: pkgs/test_core; dart pub upgrade + - id: integration_tests_spawn_hybrid_pub_upgrade + name: integration_tests/spawn_hybrid; dart pub upgrade run: dart pub upgrade if: "always() && steps.checkout.conclusion == 'success'" - working-directory: pkgs/test_core - - name: pkgs/test_core; dart test - run: dart test - if: "always() && steps.pkgs_test_core_pub_upgrade.conclusion == 'success'" - working-directory: pkgs/test_core + working-directory: integration_tests/spawn_hybrid + - name: "integration_tests/spawn_hybrid; dart test -p chrome,vm,node" + run: "dart test -p chrome,vm,node" + if: "always() && steps.integration_tests_spawn_hybrid_pub_upgrade.conclusion == 'success'" + working-directory: integration_tests/spawn_hybrid needs: - job_001 - job_002 @@ -455,17 +479,18 @@ jobs: - job_004 - job_005 - job_006 - job_011: - name: "unit_test; linux; Dart 3.5.0; PKG: integration_tests/spawn_hybrid; `dart test -p chrome,vm,node`" + - job_007 + job_012: + name: "unit_test; linux; Dart 3.5.0; PKG: integration_tests/wasm; `dart test --timeout=60s`" runs-on: ubuntu-latest steps: - name: Cache Pub hosted dependencies uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:integration_tests/spawn_hybrid;commands:test_1" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:integration_tests/wasm;commands:test_2" restore-keys: | - os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:integration_tests/spawn_hybrid + os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:integration_tests/wasm os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0 os:ubuntu-latest;pub-cache-hosted os:ubuntu-latest @@ -476,15 +501,15 @@ jobs: - id: checkout name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - - id: integration_tests_spawn_hybrid_pub_upgrade - name: integration_tests/spawn_hybrid; dart pub upgrade + - id: integration_tests_wasm_pub_upgrade + name: integration_tests/wasm; dart pub upgrade run: dart pub upgrade if: "always() && steps.checkout.conclusion == 'success'" - working-directory: integration_tests/spawn_hybrid - - name: "integration_tests/spawn_hybrid; dart test -p chrome,vm,node" - run: "dart test -p chrome,vm,node" - if: "always() && steps.integration_tests_spawn_hybrid_pub_upgrade.conclusion == 'success'" - working-directory: integration_tests/spawn_hybrid + working-directory: integration_tests/wasm + - name: "integration_tests/wasm; dart test --timeout=60s" + run: "dart test --timeout=60s" + if: "always() && steps.integration_tests_wasm_pub_upgrade.conclusion == 'success'" + working-directory: integration_tests/wasm needs: - job_001 - job_002 @@ -492,17 +517,18 @@ jobs: - job_004 - job_005 - job_006 - job_012: - name: "unit_test; linux; Dart 3.5.0; PKG: integration_tests/wasm; `dart test --timeout=60s`" + - job_007 + job_013: + name: "unit_test; linux; Dart 3.5.0; PKG: pkgs/test_api; `dart test --preset travis -x browser`" runs-on: ubuntu-latest steps: - name: Cache Pub hosted dependencies uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:integration_tests/wasm;commands:test_2" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/test_api;commands:command_11" restore-keys: | - os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:integration_tests/wasm + os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/test_api os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0 os:ubuntu-latest;pub-cache-hosted os:ubuntu-latest @@ -513,15 +539,15 @@ jobs: - id: checkout name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - - id: integration_tests_wasm_pub_upgrade - name: integration_tests/wasm; dart pub upgrade + - id: pkgs_test_api_pub_upgrade + name: pkgs/test_api; dart pub upgrade run: dart pub upgrade if: "always() && steps.checkout.conclusion == 'success'" - working-directory: integration_tests/wasm - - name: "integration_tests/wasm; dart test --timeout=60s" - run: "dart test --timeout=60s" - if: "always() && steps.integration_tests_wasm_pub_upgrade.conclusion == 'success'" - working-directory: integration_tests/wasm + working-directory: pkgs/test_api + - name: "pkgs/test_api; dart test --preset travis -x browser" + run: dart test --preset travis -x browser + if: "always() && steps.pkgs_test_api_pub_upgrade.conclusion == 'success'" + working-directory: pkgs/test_api needs: - job_001 - job_002 @@ -529,24 +555,25 @@ jobs: - job_004 - job_005 - job_006 - job_013: - name: "unit_test; linux; Dart 3.5.0; PKG: pkgs/test; `xvfb-run -s \"-screen 0 1024x768x24\" dart test --preset travis --total-shards 5 --shard-index 0`" + - job_007 + job_014: + name: "unit_test; linux; Dart 3.7.0; PKG: pkgs/test; `xvfb-run -s \"-screen 0 1024x768x24\" dart test --preset travis --total-shards 5 --shard-index 0`" runs-on: ubuntu-latest steps: - name: Cache Pub hosted dependencies uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/test;commands:command_01" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0;packages:pkgs/test;commands:command_01" restore-keys: | - os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/test - os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0 + os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0;packages:pkgs/test + os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0 os:ubuntu-latest;pub-cache-hosted os:ubuntu-latest - name: Setup Dart SDK uses: dart-lang/setup-dart@e51d8e571e22473a2ddebf0ef8a2123f0ab2c02c with: - sdk: "3.5.0" + sdk: "3.7.0" - id: checkout name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 @@ -566,24 +593,25 @@ jobs: - job_004 - job_005 - job_006 - job_014: - name: "unit_test; linux; Dart 3.5.0; PKG: pkgs/test; `xvfb-run -s \"-screen 0 1024x768x24\" dart test --preset travis --total-shards 5 --shard-index 1`" + - job_007 + job_015: + name: "unit_test; linux; Dart 3.7.0; PKG: pkgs/test; `xvfb-run -s \"-screen 0 1024x768x24\" dart test --preset travis --total-shards 5 --shard-index 1`" runs-on: ubuntu-latest steps: - name: Cache Pub hosted dependencies uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/test;commands:command_02" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0;packages:pkgs/test;commands:command_02" restore-keys: | - os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/test - os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0 + os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0;packages:pkgs/test + os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0 os:ubuntu-latest;pub-cache-hosted os:ubuntu-latest - name: Setup Dart SDK uses: dart-lang/setup-dart@e51d8e571e22473a2ddebf0ef8a2123f0ab2c02c with: - sdk: "3.5.0" + sdk: "3.7.0" - id: checkout name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 @@ -603,24 +631,25 @@ jobs: - job_004 - job_005 - job_006 - job_015: - name: "unit_test; linux; Dart 3.5.0; PKG: pkgs/test; `xvfb-run -s \"-screen 0 1024x768x24\" dart test --preset travis --total-shards 5 --shard-index 2`" + - job_007 + job_016: + name: "unit_test; linux; Dart 3.7.0; PKG: pkgs/test; `xvfb-run -s \"-screen 0 1024x768x24\" dart test --preset travis --total-shards 5 --shard-index 2`" runs-on: ubuntu-latest steps: - name: Cache Pub hosted dependencies uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/test;commands:command_03" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0;packages:pkgs/test;commands:command_03" restore-keys: | - os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/test - os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0 + os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0;packages:pkgs/test + os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0 os:ubuntu-latest;pub-cache-hosted os:ubuntu-latest - name: Setup Dart SDK uses: dart-lang/setup-dart@e51d8e571e22473a2ddebf0ef8a2123f0ab2c02c with: - sdk: "3.5.0" + sdk: "3.7.0" - id: checkout name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 @@ -640,24 +669,25 @@ jobs: - job_004 - job_005 - job_006 - job_016: - name: "unit_test; linux; Dart 3.5.0; PKG: pkgs/test; `xvfb-run -s \"-screen 0 1024x768x24\" dart test --preset travis --total-shards 5 --shard-index 3`" + - job_007 + job_017: + name: "unit_test; linux; Dart 3.7.0; PKG: pkgs/test; `xvfb-run -s \"-screen 0 1024x768x24\" dart test --preset travis --total-shards 5 --shard-index 3`" runs-on: ubuntu-latest steps: - name: Cache Pub hosted dependencies uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/test;commands:command_04" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0;packages:pkgs/test;commands:command_04" restore-keys: | - os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/test - os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0 + os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0;packages:pkgs/test + os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0 os:ubuntu-latest;pub-cache-hosted os:ubuntu-latest - name: Setup Dart SDK uses: dart-lang/setup-dart@e51d8e571e22473a2ddebf0ef8a2123f0ab2c02c with: - sdk: "3.5.0" + sdk: "3.7.0" - id: checkout name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 @@ -677,24 +707,25 @@ jobs: - job_004 - job_005 - job_006 - job_017: - name: "unit_test; linux; Dart 3.5.0; PKG: pkgs/test; `xvfb-run -s \"-screen 0 1024x768x24\" dart test --preset travis --total-shards 5 --shard-index 4`" + - job_007 + job_018: + name: "unit_test; linux; Dart 3.7.0; PKG: pkgs/test; `xvfb-run -s \"-screen 0 1024x768x24\" dart test --preset travis --total-shards 5 --shard-index 4`" runs-on: ubuntu-latest steps: - name: Cache Pub hosted dependencies uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/test;commands:command_05" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0;packages:pkgs/test;commands:command_05" restore-keys: | - os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/test - os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0 + os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0;packages:pkgs/test + os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0 os:ubuntu-latest;pub-cache-hosted os:ubuntu-latest - name: Setup Dart SDK uses: dart-lang/setup-dart@e51d8e571e22473a2ddebf0ef8a2123f0ab2c02c with: - sdk: "3.5.0" + sdk: "3.7.0" - id: checkout name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 @@ -714,36 +745,37 @@ jobs: - job_004 - job_005 - job_006 - job_018: - name: "unit_test; linux; Dart 3.5.0; PKG: pkgs/test_api; `dart test --preset travis -x browser`" + - job_007 + job_019: + name: "unit_test; linux; Dart 3.7.0; PKG: pkgs/test_core; `dart test`" runs-on: ubuntu-latest steps: - name: Cache Pub hosted dependencies uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/test_api;commands:command_11" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0;packages:pkgs/test_core;commands:command_00" restore-keys: | - os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/test_api - os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0 + os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0;packages:pkgs/test_core + os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0 os:ubuntu-latest;pub-cache-hosted os:ubuntu-latest - name: Setup Dart SDK uses: dart-lang/setup-dart@e51d8e571e22473a2ddebf0ef8a2123f0ab2c02c with: - sdk: "3.5.0" + sdk: "3.7.0" - id: checkout name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - - id: pkgs_test_api_pub_upgrade - name: pkgs/test_api; dart pub upgrade + - id: pkgs_test_core_pub_upgrade + name: pkgs/test_core; dart pub upgrade run: dart pub upgrade if: "always() && steps.checkout.conclusion == 'success'" - working-directory: pkgs/test_api - - name: "pkgs/test_api; dart test --preset travis -x browser" - run: dart test --preset travis -x browser - if: "always() && steps.pkgs_test_api_pub_upgrade.conclusion == 'success'" - working-directory: pkgs/test_api + working-directory: pkgs/test_core + - name: pkgs/test_core; dart test + run: dart test + if: "always() && steps.pkgs_test_core_pub_upgrade.conclusion == 'success'" + working-directory: pkgs/test_core needs: - job_001 - job_002 @@ -751,7 +783,8 @@ jobs: - job_004 - job_005 - job_006 - job_019: + - job_007 + job_020: name: "unit_test; linux; Dart dev; PKG: integration_tests/regression; `dart test`" runs-on: ubuntu-latest steps: @@ -788,7 +821,8 @@ jobs: - job_004 - job_005 - job_006 - job_020: + - job_007 + job_021: name: "unit_test; linux; Dart dev; PKG: pkgs/checks; `dart test`" runs-on: ubuntu-latest steps: @@ -825,7 +859,8 @@ jobs: - job_004 - job_005 - job_006 - job_021: + - job_007 + job_022: name: "unit_test; linux; Dart dev; PKG: pkgs/matcher; `dart test`" runs-on: ubuntu-latest steps: @@ -862,7 +897,8 @@ jobs: - job_004 - job_005 - job_006 - job_022: + - job_007 + job_023: name: "unit_test; linux; Dart dev; PKG: pkgs/test_core; `dart test`" runs-on: ubuntu-latest steps: @@ -899,7 +935,8 @@ jobs: - job_004 - job_005 - job_006 - job_023: + - job_007 + job_024: name: "unit_test; linux; Dart dev; PKG: integration_tests/spawn_hybrid; `dart test -p chrome,vm,node`" runs-on: ubuntu-latest steps: @@ -936,7 +973,8 @@ jobs: - job_004 - job_005 - job_006 - job_024: + - job_007 + job_025: name: "unit_test; linux; Dart dev; PKG: integration_tests/wasm; `dart test --timeout=60s`" runs-on: ubuntu-latest steps: @@ -973,7 +1011,8 @@ jobs: - job_004 - job_005 - job_006 - job_025: + - job_007 + job_026: name: "unit_test; linux; Dart dev; PKG: pkgs/test; `xvfb-run -s \"-screen 0 1024x768x24\" dart test --preset travis --total-shards 5 --shard-index 0`" runs-on: ubuntu-latest steps: @@ -1010,7 +1049,8 @@ jobs: - job_004 - job_005 - job_006 - job_026: + - job_007 + job_027: name: "unit_test; linux; Dart dev; PKG: pkgs/test; `xvfb-run -s \"-screen 0 1024x768x24\" dart test --preset travis --total-shards 5 --shard-index 1`" runs-on: ubuntu-latest steps: @@ -1047,7 +1087,8 @@ jobs: - job_004 - job_005 - job_006 - job_027: + - job_007 + job_028: name: "unit_test; linux; Dart dev; PKG: pkgs/test; `xvfb-run -s \"-screen 0 1024x768x24\" dart test --preset travis --total-shards 5 --shard-index 2`" runs-on: ubuntu-latest steps: @@ -1084,7 +1125,8 @@ jobs: - job_004 - job_005 - job_006 - job_028: + - job_007 + job_029: name: "unit_test; linux; Dart dev; PKG: pkgs/test; `xvfb-run -s \"-screen 0 1024x768x24\" dart test --preset travis --total-shards 5 --shard-index 3`" runs-on: ubuntu-latest steps: @@ -1121,7 +1163,8 @@ jobs: - job_004 - job_005 - job_006 - job_029: + - job_007 + job_030: name: "unit_test; linux; Dart dev; PKG: pkgs/test; `xvfb-run -s \"-screen 0 1024x768x24\" dart test --preset travis --total-shards 5 --shard-index 4`" runs-on: ubuntu-latest steps: @@ -1158,7 +1201,8 @@ jobs: - job_004 - job_005 - job_006 - job_030: + - job_007 + job_031: name: "unit_test; linux; Dart dev; PKG: pkgs/test_api; `dart test --preset travis -x browser`" runs-on: ubuntu-latest steps: @@ -1195,24 +1239,25 @@ jobs: - job_004 - job_005 - job_006 - job_031: - name: "unit_test; osx; Dart 3.5.0; PKG: pkgs/test; `dart test --preset travis --total-shards 5 --shard-index 0`" + - job_007 + job_032: + name: "unit_test; osx; Dart 3.7.0; PKG: pkgs/test; `dart test --preset travis --total-shards 5 --shard-index 0`" runs-on: macos-latest steps: - name: Cache Pub hosted dependencies uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 with: path: "~/.pub-cache/hosted" - key: "os:macos-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/test;commands:command_06" + key: "os:macos-latest;pub-cache-hosted;sdk:3.7.0;packages:pkgs/test;commands:command_06" restore-keys: | - os:macos-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/test - os:macos-latest;pub-cache-hosted;sdk:3.5.0 + os:macos-latest;pub-cache-hosted;sdk:3.7.0;packages:pkgs/test + os:macos-latest;pub-cache-hosted;sdk:3.7.0 os:macos-latest;pub-cache-hosted os:macos-latest - name: Setup Dart SDK uses: dart-lang/setup-dart@e51d8e571e22473a2ddebf0ef8a2123f0ab2c02c with: - sdk: "3.5.0" + sdk: "3.7.0" - id: checkout name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 @@ -1232,24 +1277,25 @@ jobs: - job_004 - job_005 - job_006 - job_032: - name: "unit_test; osx; Dart 3.5.0; PKG: pkgs/test; `dart test --preset travis --total-shards 5 --shard-index 1`" + - job_007 + job_033: + name: "unit_test; osx; Dart 3.7.0; PKG: pkgs/test; `dart test --preset travis --total-shards 5 --shard-index 1`" runs-on: macos-latest steps: - name: Cache Pub hosted dependencies uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 with: path: "~/.pub-cache/hosted" - key: "os:macos-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/test;commands:command_07" + key: "os:macos-latest;pub-cache-hosted;sdk:3.7.0;packages:pkgs/test;commands:command_07" restore-keys: | - os:macos-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/test - os:macos-latest;pub-cache-hosted;sdk:3.5.0 + os:macos-latest;pub-cache-hosted;sdk:3.7.0;packages:pkgs/test + os:macos-latest;pub-cache-hosted;sdk:3.7.0 os:macos-latest;pub-cache-hosted os:macos-latest - name: Setup Dart SDK uses: dart-lang/setup-dart@e51d8e571e22473a2ddebf0ef8a2123f0ab2c02c with: - sdk: "3.5.0" + sdk: "3.7.0" - id: checkout name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 @@ -1269,24 +1315,25 @@ jobs: - job_004 - job_005 - job_006 - job_033: - name: "unit_test; osx; Dart 3.5.0; PKG: pkgs/test; `dart test --preset travis --total-shards 5 --shard-index 2`" + - job_007 + job_034: + name: "unit_test; osx; Dart 3.7.0; PKG: pkgs/test; `dart test --preset travis --total-shards 5 --shard-index 2`" runs-on: macos-latest steps: - name: Cache Pub hosted dependencies uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 with: path: "~/.pub-cache/hosted" - key: "os:macos-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/test;commands:command_08" + key: "os:macos-latest;pub-cache-hosted;sdk:3.7.0;packages:pkgs/test;commands:command_08" restore-keys: | - os:macos-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/test - os:macos-latest;pub-cache-hosted;sdk:3.5.0 + os:macos-latest;pub-cache-hosted;sdk:3.7.0;packages:pkgs/test + os:macos-latest;pub-cache-hosted;sdk:3.7.0 os:macos-latest;pub-cache-hosted os:macos-latest - name: Setup Dart SDK uses: dart-lang/setup-dart@e51d8e571e22473a2ddebf0ef8a2123f0ab2c02c with: - sdk: "3.5.0" + sdk: "3.7.0" - id: checkout name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 @@ -1306,24 +1353,25 @@ jobs: - job_004 - job_005 - job_006 - job_034: - name: "unit_test; osx; Dart 3.5.0; PKG: pkgs/test; `dart test --preset travis --total-shards 5 --shard-index 3`" + - job_007 + job_035: + name: "unit_test; osx; Dart 3.7.0; PKG: pkgs/test; `dart test --preset travis --total-shards 5 --shard-index 3`" runs-on: macos-latest steps: - name: Cache Pub hosted dependencies uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 with: path: "~/.pub-cache/hosted" - key: "os:macos-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/test;commands:command_09" + key: "os:macos-latest;pub-cache-hosted;sdk:3.7.0;packages:pkgs/test;commands:command_09" restore-keys: | - os:macos-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/test - os:macos-latest;pub-cache-hosted;sdk:3.5.0 + os:macos-latest;pub-cache-hosted;sdk:3.7.0;packages:pkgs/test + os:macos-latest;pub-cache-hosted;sdk:3.7.0 os:macos-latest;pub-cache-hosted os:macos-latest - name: Setup Dart SDK uses: dart-lang/setup-dart@e51d8e571e22473a2ddebf0ef8a2123f0ab2c02c with: - sdk: "3.5.0" + sdk: "3.7.0" - id: checkout name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 @@ -1343,24 +1391,25 @@ jobs: - job_004 - job_005 - job_006 - job_035: - name: "unit_test; osx; Dart 3.5.0; PKG: pkgs/test; `dart test --preset travis --total-shards 5 --shard-index 4`" + - job_007 + job_036: + name: "unit_test; osx; Dart 3.7.0; PKG: pkgs/test; `dart test --preset travis --total-shards 5 --shard-index 4`" runs-on: macos-latest steps: - name: Cache Pub hosted dependencies uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 with: path: "~/.pub-cache/hosted" - key: "os:macos-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/test;commands:command_10" + key: "os:macos-latest;pub-cache-hosted;sdk:3.7.0;packages:pkgs/test;commands:command_10" restore-keys: | - os:macos-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/test - os:macos-latest;pub-cache-hosted;sdk:3.5.0 + os:macos-latest;pub-cache-hosted;sdk:3.7.0;packages:pkgs/test + os:macos-latest;pub-cache-hosted;sdk:3.7.0 os:macos-latest;pub-cache-hosted os:macos-latest - name: Setup Dart SDK uses: dart-lang/setup-dart@e51d8e571e22473a2ddebf0ef8a2123f0ab2c02c with: - sdk: "3.5.0" + sdk: "3.7.0" - id: checkout name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 @@ -1380,7 +1429,8 @@ jobs: - job_004 - job_005 - job_006 - job_036: + - job_007 + job_037: name: "unit_test; windows; Dart 3.5.0; PKG: integration_tests/spawn_hybrid; `dart test -p chrome,vm,node`" runs-on: windows-latest steps: @@ -1407,7 +1457,8 @@ jobs: - job_004 - job_005 - job_006 - job_037: + - job_007 + job_038: name: "unit_test; windows; Dart 3.5.0; PKG: integration_tests/wasm; `dart test --timeout=60s`" runs-on: windows-latest steps: @@ -1434,14 +1485,15 @@ jobs: - job_004 - job_005 - job_006 - job_038: - name: "unit_test; windows; Dart 3.5.0; PKG: pkgs/test; `dart test --preset travis --total-shards 5 --shard-index 0`" + - job_007 + job_039: + name: "unit_test; windows; Dart 3.7.0; PKG: pkgs/test; `dart test --preset travis --total-shards 5 --shard-index 0`" runs-on: windows-latest steps: - name: Setup Dart SDK uses: dart-lang/setup-dart@e51d8e571e22473a2ddebf0ef8a2123f0ab2c02c with: - sdk: "3.5.0" + sdk: "3.7.0" - id: checkout name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 @@ -1461,14 +1513,15 @@ jobs: - job_004 - job_005 - job_006 - job_039: - name: "unit_test; windows; Dart 3.5.0; PKG: pkgs/test; `dart test --preset travis --total-shards 5 --shard-index 1`" + - job_007 + job_040: + name: "unit_test; windows; Dart 3.7.0; PKG: pkgs/test; `dart test --preset travis --total-shards 5 --shard-index 1`" runs-on: windows-latest steps: - name: Setup Dart SDK uses: dart-lang/setup-dart@e51d8e571e22473a2ddebf0ef8a2123f0ab2c02c with: - sdk: "3.5.0" + sdk: "3.7.0" - id: checkout name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 @@ -1488,14 +1541,15 @@ jobs: - job_004 - job_005 - job_006 - job_040: - name: "unit_test; windows; Dart 3.5.0; PKG: pkgs/test; `dart test --preset travis --total-shards 5 --shard-index 2`" + - job_007 + job_041: + name: "unit_test; windows; Dart 3.7.0; PKG: pkgs/test; `dart test --preset travis --total-shards 5 --shard-index 2`" runs-on: windows-latest steps: - name: Setup Dart SDK uses: dart-lang/setup-dart@e51d8e571e22473a2ddebf0ef8a2123f0ab2c02c with: - sdk: "3.5.0" + sdk: "3.7.0" - id: checkout name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 @@ -1515,14 +1569,15 @@ jobs: - job_004 - job_005 - job_006 - job_041: - name: "unit_test; windows; Dart 3.5.0; PKG: pkgs/test; `dart test --preset travis --total-shards 5 --shard-index 3`" + - job_007 + job_042: + name: "unit_test; windows; Dart 3.7.0; PKG: pkgs/test; `dart test --preset travis --total-shards 5 --shard-index 3`" runs-on: windows-latest steps: - name: Setup Dart SDK uses: dart-lang/setup-dart@e51d8e571e22473a2ddebf0ef8a2123f0ab2c02c with: - sdk: "3.5.0" + sdk: "3.7.0" - id: checkout name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 @@ -1542,14 +1597,15 @@ jobs: - job_004 - job_005 - job_006 - job_042: - name: "unit_test; windows; Dart 3.5.0; PKG: pkgs/test; `dart test --preset travis --total-shards 5 --shard-index 4`" + - job_007 + job_043: + name: "unit_test; windows; Dart 3.7.0; PKG: pkgs/test; `dart test --preset travis --total-shards 5 --shard-index 4`" runs-on: windows-latest steps: - name: Setup Dart SDK uses: dart-lang/setup-dart@e51d8e571e22473a2ddebf0ef8a2123f0ab2c02c with: - sdk: "3.5.0" + sdk: "3.7.0" - id: checkout name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 @@ -1569,7 +1625,8 @@ jobs: - job_004 - job_005 - job_006 - job_043: + - job_007 + job_044: name: "unit_test; windows; Dart dev; PKG: integration_tests/spawn_hybrid; `dart test -p chrome,vm,node`" runs-on: windows-latest steps: @@ -1596,7 +1653,8 @@ jobs: - job_004 - job_005 - job_006 - job_044: + - job_007 + job_045: name: "unit_test; windows; Dart dev; PKG: integration_tests/wasm; `dart test --timeout=60s`" runs-on: windows-latest steps: @@ -1623,7 +1681,8 @@ jobs: - job_004 - job_005 - job_006 - job_045: + - job_007 + job_046: name: Notify failure runs-on: ubuntu-latest if: "(github.event_name == 'push' || github.event_name == 'schedule') && failure()" @@ -1679,3 +1738,4 @@ jobs: - job_042 - job_043 - job_044 + - job_045 diff --git a/pkgs/test/pubspec.yaml b/pkgs/test/pubspec.yaml index 70072f2e9..0208cbc9d 100644 --- a/pkgs/test/pubspec.yaml +++ b/pkgs/test/pubspec.yaml @@ -7,7 +7,7 @@ issue_tracker: https://github.com/dart-lang/test/issues?q=is%3Aissue+is%3Aopen+l resolution: workspace environment: - sdk: ^3.5.0 + sdk: ^3.7.0 dependencies: analyzer: '>=6.0.0 <9.0.0' diff --git a/pkgs/test_core/pubspec.yaml b/pkgs/test_core/pubspec.yaml index 1b2152a9e..63b67cfcd 100644 --- a/pkgs/test_core/pubspec.yaml +++ b/pkgs/test_core/pubspec.yaml @@ -6,7 +6,7 @@ issue_tracker: https://github.com/dart-lang/test/issues?q=is%3Aissue+is%3Aopen+l resolution: workspace environment: - sdk: ^3.5.0 + sdk: ^3.7.0 dependencies: analyzer: ^8.0.0 diff --git a/tool/ci.sh b/tool/ci.sh index 040c70df8..8b760312f 100755 --- a/tool/ci.sh +++ b/tool/ci.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Created with package:mono_repo v6.6.2 +# Created with package:mono_repo v6.6.3 # Support built in commands on windows out of the box. From 635c9bc82d2dcbf46cf8ea7d07cf89d96203498d Mon Sep 17 00:00:00 2001 From: Nate Bosch Date: Tue, 22 Jul 2025 01:07:50 +0000 Subject: [PATCH 03/11] Missed SDK constraints --- .github/workflows/dart.yml | 246 ++++++++++---------- integration_tests/regression/pubspec.yaml | 2 +- integration_tests/spawn_hybrid/pubspec.yaml | 2 +- integration_tests/wasm/pubspec.yaml | 2 +- pkgs/test_api/pubspec.yaml | 2 +- 5 files changed, 127 insertions(+), 127 deletions(-) diff --git a/.github/workflows/dart.yml b/.github/workflows/dart.yml index 9be8841a9..8f536afa5 100644 --- a/.github/workflows/dart.yml +++ b/.github/workflows/dart.yml @@ -40,16 +40,16 @@ jobs: - name: mono_repo self validate run: dart pub global run mono_repo generate --validate job_002: - name: "analyze_and_format; linux; Dart 3.5.0; PKGS: integration_tests/regression, integration_tests/wasm; `dart format --output=none --set-exit-if-changed .`, `dart analyze --fatal-infos`" + name: "analyze_and_format; linux; Dart 3.5.0; PKGS: pkgs/checks, pkgs/matcher; `dart analyze`" runs-on: ubuntu-latest steps: - name: Cache Pub hosted dependencies uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:integration_tests/regression-integration_tests/wasm;commands:format-analyze_0" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/checks-pkgs/matcher;commands:analyze_1" restore-keys: | - os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:integration_tests/regression-integration_tests/wasm + os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/checks-pkgs/matcher os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0 os:ubuntu-latest;pub-cache-hosted os:ubuntu-latest @@ -60,6 +60,45 @@ jobs: - id: checkout name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + - id: pkgs_checks_pub_upgrade + name: pkgs/checks; dart pub upgrade + run: dart pub upgrade + if: "always() && steps.checkout.conclusion == 'success'" + working-directory: pkgs/checks + - name: pkgs/checks; dart analyze + run: dart analyze + if: "always() && steps.pkgs_checks_pub_upgrade.conclusion == 'success'" + working-directory: pkgs/checks + - id: pkgs_matcher_pub_upgrade + name: pkgs/matcher; dart pub upgrade + run: dart pub upgrade + if: "always() && steps.checkout.conclusion == 'success'" + working-directory: pkgs/matcher + - name: pkgs/matcher; dart analyze + run: dart analyze + if: "always() && steps.pkgs_matcher_pub_upgrade.conclusion == 'success'" + working-directory: pkgs/matcher + job_003: + name: "analyze_and_format; linux; Dart 3.7.0; PKGS: integration_tests/regression, integration_tests/wasm; `dart format --output=none --set-exit-if-changed .`, `dart analyze --fatal-infos`" + runs-on: ubuntu-latest + steps: + - name: Cache Pub hosted dependencies + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 + with: + path: "~/.pub-cache/hosted" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0;packages:integration_tests/regression-integration_tests/wasm;commands:format-analyze_0" + restore-keys: | + os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0;packages:integration_tests/regression-integration_tests/wasm + os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0 + os:ubuntu-latest;pub-cache-hosted + os:ubuntu-latest + - name: Setup Dart SDK + uses: dart-lang/setup-dart@e51d8e571e22473a2ddebf0ef8a2123f0ab2c02c + with: + sdk: "3.7.0" + - id: checkout + name: Checkout repository + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - id: integration_tests_regression_pub_upgrade name: integration_tests/regression; dart pub upgrade run: dart pub upgrade @@ -86,45 +125,6 @@ jobs: run: dart analyze --fatal-infos if: "always() && steps.integration_tests_wasm_pub_upgrade.conclusion == 'success'" working-directory: integration_tests/wasm - job_003: - name: "analyze_and_format; linux; Dart 3.5.0; PKGS: pkgs/checks, pkgs/matcher; `dart analyze`" - runs-on: ubuntu-latest - steps: - - name: Cache Pub hosted dependencies - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 - with: - path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/checks-pkgs/matcher;commands:analyze_1" - restore-keys: | - os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/checks-pkgs/matcher - os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0 - os:ubuntu-latest;pub-cache-hosted - os:ubuntu-latest - - name: Setup Dart SDK - uses: dart-lang/setup-dart@e51d8e571e22473a2ddebf0ef8a2123f0ab2c02c - with: - sdk: "3.5.0" - - id: checkout - name: Checkout repository - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - - id: pkgs_checks_pub_upgrade - name: pkgs/checks; dart pub upgrade - run: dart pub upgrade - if: "always() && steps.checkout.conclusion == 'success'" - working-directory: pkgs/checks - - name: pkgs/checks; dart analyze - run: dart analyze - if: "always() && steps.pkgs_checks_pub_upgrade.conclusion == 'success'" - working-directory: pkgs/checks - - id: pkgs_matcher_pub_upgrade - name: pkgs/matcher; dart pub upgrade - run: dart pub upgrade - if: "always() && steps.checkout.conclusion == 'success'" - working-directory: pkgs/matcher - - name: pkgs/matcher; dart analyze - run: dart analyze - if: "always() && steps.pkgs_matcher_pub_upgrade.conclusion == 'success'" - working-directory: pkgs/matcher job_004: name: "analyze_and_format; linux; Dart 3.7.0; PKG: pkgs/test_core; `dart analyze`" runs-on: ubuntu-latest @@ -281,13 +281,13 @@ jobs: if: "always() && steps.pkgs_test_core_pub_upgrade.conclusion == 'success'" working-directory: pkgs/test_core job_006: - name: "analyze_and_format; windows; Dart 3.5.0; PKG: integration_tests/wasm; `dart format --output=none --set-exit-if-changed .`, `dart analyze --fatal-infos`" + name: "analyze_and_format; windows; Dart 3.7.0; PKG: integration_tests/wasm; `dart format --output=none --set-exit-if-changed .`, `dart analyze --fatal-infos`" runs-on: windows-latest steps: - name: Setup Dart SDK uses: dart-lang/setup-dart@e51d8e571e22473a2ddebf0ef8a2123f0ab2c02c with: - sdk: "3.5.0" + sdk: "3.7.0" - id: checkout name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 @@ -329,16 +329,16 @@ jobs: if: "always() && steps.integration_tests_wasm_pub_upgrade.conclusion == 'success'" working-directory: integration_tests/wasm job_008: - name: "unit_test; linux; Dart 3.5.0; PKG: integration_tests/regression; `dart test`" + name: "unit_test; linux; Dart 3.5.0; PKG: pkgs/checks; `dart test`" runs-on: ubuntu-latest steps: - name: Cache Pub hosted dependencies uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:integration_tests/regression;commands:command_00" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/checks;commands:command_00" restore-keys: | - os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:integration_tests/regression + os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/checks os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0 os:ubuntu-latest;pub-cache-hosted os:ubuntu-latest @@ -349,15 +349,15 @@ jobs: - id: checkout name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - - id: integration_tests_regression_pub_upgrade - name: integration_tests/regression; dart pub upgrade + - id: pkgs_checks_pub_upgrade + name: pkgs/checks; dart pub upgrade run: dart pub upgrade if: "always() && steps.checkout.conclusion == 'success'" - working-directory: integration_tests/regression - - name: integration_tests/regression; dart test + working-directory: pkgs/checks + - name: pkgs/checks; dart test run: dart test - if: "always() && steps.integration_tests_regression_pub_upgrade.conclusion == 'success'" - working-directory: integration_tests/regression + if: "always() && steps.pkgs_checks_pub_upgrade.conclusion == 'success'" + working-directory: pkgs/checks needs: - job_001 - job_002 @@ -367,16 +367,16 @@ jobs: - job_006 - job_007 job_009: - name: "unit_test; linux; Dart 3.5.0; PKG: pkgs/checks; `dart test`" + name: "unit_test; linux; Dart 3.5.0; PKG: pkgs/matcher; `dart test`" runs-on: ubuntu-latest steps: - name: Cache Pub hosted dependencies uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/checks;commands:command_00" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/matcher;commands:command_00" restore-keys: | - os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/checks + os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/matcher os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0 os:ubuntu-latest;pub-cache-hosted os:ubuntu-latest @@ -387,15 +387,15 @@ jobs: - id: checkout name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - - id: pkgs_checks_pub_upgrade - name: pkgs/checks; dart pub upgrade + - id: pkgs_matcher_pub_upgrade + name: pkgs/matcher; dart pub upgrade run: dart pub upgrade if: "always() && steps.checkout.conclusion == 'success'" - working-directory: pkgs/checks - - name: pkgs/checks; dart test + working-directory: pkgs/matcher + - name: pkgs/matcher; dart test run: dart test - if: "always() && steps.pkgs_checks_pub_upgrade.conclusion == 'success'" - working-directory: pkgs/checks + if: "always() && steps.pkgs_matcher_pub_upgrade.conclusion == 'success'" + working-directory: pkgs/matcher needs: - job_001 - job_002 @@ -405,35 +405,35 @@ jobs: - job_006 - job_007 job_010: - name: "unit_test; linux; Dart 3.5.0; PKG: pkgs/matcher; `dart test`" + name: "unit_test; linux; Dart 3.7.0; PKG: integration_tests/regression; `dart test`" runs-on: ubuntu-latest steps: - name: Cache Pub hosted dependencies uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/matcher;commands:command_00" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0;packages:integration_tests/regression;commands:command_00" restore-keys: | - os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/matcher - os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0 + os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0;packages:integration_tests/regression + os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0 os:ubuntu-latest;pub-cache-hosted os:ubuntu-latest - name: Setup Dart SDK uses: dart-lang/setup-dart@e51d8e571e22473a2ddebf0ef8a2123f0ab2c02c with: - sdk: "3.5.0" + sdk: "3.7.0" - id: checkout name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - - id: pkgs_matcher_pub_upgrade - name: pkgs/matcher; dart pub upgrade + - id: integration_tests_regression_pub_upgrade + name: integration_tests/regression; dart pub upgrade run: dart pub upgrade if: "always() && steps.checkout.conclusion == 'success'" - working-directory: pkgs/matcher - - name: pkgs/matcher; dart test + working-directory: integration_tests/regression + - name: integration_tests/regression; dart test run: dart test - if: "always() && steps.pkgs_matcher_pub_upgrade.conclusion == 'success'" - working-directory: pkgs/matcher + if: "always() && steps.integration_tests_regression_pub_upgrade.conclusion == 'success'" + working-directory: integration_tests/regression needs: - job_001 - job_002 @@ -443,35 +443,35 @@ jobs: - job_006 - job_007 job_011: - name: "unit_test; linux; Dart 3.5.0; PKG: integration_tests/spawn_hybrid; `dart test -p chrome,vm,node`" + name: "unit_test; linux; Dart 3.7.0; PKG: pkgs/test_core; `dart test`" runs-on: ubuntu-latest steps: - name: Cache Pub hosted dependencies uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:integration_tests/spawn_hybrid;commands:test_1" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0;packages:pkgs/test_core;commands:command_00" restore-keys: | - os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:integration_tests/spawn_hybrid - os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0 + os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0;packages:pkgs/test_core + os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0 os:ubuntu-latest;pub-cache-hosted os:ubuntu-latest - name: Setup Dart SDK uses: dart-lang/setup-dart@e51d8e571e22473a2ddebf0ef8a2123f0ab2c02c with: - sdk: "3.5.0" + sdk: "3.7.0" - id: checkout name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - - id: integration_tests_spawn_hybrid_pub_upgrade - name: integration_tests/spawn_hybrid; dart pub upgrade + - id: pkgs_test_core_pub_upgrade + name: pkgs/test_core; dart pub upgrade run: dart pub upgrade if: "always() && steps.checkout.conclusion == 'success'" - working-directory: integration_tests/spawn_hybrid - - name: "integration_tests/spawn_hybrid; dart test -p chrome,vm,node" - run: "dart test -p chrome,vm,node" - if: "always() && steps.integration_tests_spawn_hybrid_pub_upgrade.conclusion == 'success'" - working-directory: integration_tests/spawn_hybrid + working-directory: pkgs/test_core + - name: pkgs/test_core; dart test + run: dart test + if: "always() && steps.pkgs_test_core_pub_upgrade.conclusion == 'success'" + working-directory: pkgs/test_core needs: - job_001 - job_002 @@ -481,35 +481,35 @@ jobs: - job_006 - job_007 job_012: - name: "unit_test; linux; Dart 3.5.0; PKG: integration_tests/wasm; `dart test --timeout=60s`" + name: "unit_test; linux; Dart 3.7.0; PKG: integration_tests/spawn_hybrid; `dart test -p chrome,vm,node`" runs-on: ubuntu-latest steps: - name: Cache Pub hosted dependencies uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:integration_tests/wasm;commands:test_2" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0;packages:integration_tests/spawn_hybrid;commands:test_1" restore-keys: | - os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:integration_tests/wasm - os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0 + os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0;packages:integration_tests/spawn_hybrid + os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0 os:ubuntu-latest;pub-cache-hosted os:ubuntu-latest - name: Setup Dart SDK uses: dart-lang/setup-dart@e51d8e571e22473a2ddebf0ef8a2123f0ab2c02c with: - sdk: "3.5.0" + sdk: "3.7.0" - id: checkout name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - - id: integration_tests_wasm_pub_upgrade - name: integration_tests/wasm; dart pub upgrade + - id: integration_tests_spawn_hybrid_pub_upgrade + name: integration_tests/spawn_hybrid; dart pub upgrade run: dart pub upgrade if: "always() && steps.checkout.conclusion == 'success'" - working-directory: integration_tests/wasm - - name: "integration_tests/wasm; dart test --timeout=60s" - run: "dart test --timeout=60s" - if: "always() && steps.integration_tests_wasm_pub_upgrade.conclusion == 'success'" - working-directory: integration_tests/wasm + working-directory: integration_tests/spawn_hybrid + - name: "integration_tests/spawn_hybrid; dart test -p chrome,vm,node" + run: "dart test -p chrome,vm,node" + if: "always() && steps.integration_tests_spawn_hybrid_pub_upgrade.conclusion == 'success'" + working-directory: integration_tests/spawn_hybrid needs: - job_001 - job_002 @@ -519,35 +519,35 @@ jobs: - job_006 - job_007 job_013: - name: "unit_test; linux; Dart 3.5.0; PKG: pkgs/test_api; `dart test --preset travis -x browser`" + name: "unit_test; linux; Dart 3.7.0; PKG: integration_tests/wasm; `dart test --timeout=60s`" runs-on: ubuntu-latest steps: - name: Cache Pub hosted dependencies uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/test_api;commands:command_11" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0;packages:integration_tests/wasm;commands:test_2" restore-keys: | - os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/test_api - os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0 + os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0;packages:integration_tests/wasm + os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0 os:ubuntu-latest;pub-cache-hosted os:ubuntu-latest - name: Setup Dart SDK uses: dart-lang/setup-dart@e51d8e571e22473a2ddebf0ef8a2123f0ab2c02c with: - sdk: "3.5.0" + sdk: "3.7.0" - id: checkout name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - - id: pkgs_test_api_pub_upgrade - name: pkgs/test_api; dart pub upgrade + - id: integration_tests_wasm_pub_upgrade + name: integration_tests/wasm; dart pub upgrade run: dart pub upgrade if: "always() && steps.checkout.conclusion == 'success'" - working-directory: pkgs/test_api - - name: "pkgs/test_api; dart test --preset travis -x browser" - run: dart test --preset travis -x browser - if: "always() && steps.pkgs_test_api_pub_upgrade.conclusion == 'success'" - working-directory: pkgs/test_api + working-directory: integration_tests/wasm + - name: "integration_tests/wasm; dart test --timeout=60s" + run: "dart test --timeout=60s" + if: "always() && steps.integration_tests_wasm_pub_upgrade.conclusion == 'success'" + working-directory: integration_tests/wasm needs: - job_001 - job_002 @@ -747,16 +747,16 @@ jobs: - job_006 - job_007 job_019: - name: "unit_test; linux; Dart 3.7.0; PKG: pkgs/test_core; `dart test`" + name: "unit_test; linux; Dart 3.7.0; PKG: pkgs/test_api; `dart test --preset travis -x browser`" runs-on: ubuntu-latest steps: - name: Cache Pub hosted dependencies uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0;packages:pkgs/test_core;commands:command_00" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0;packages:pkgs/test_api;commands:command_11" restore-keys: | - os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0;packages:pkgs/test_core + os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0;packages:pkgs/test_api os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0 os:ubuntu-latest;pub-cache-hosted os:ubuntu-latest @@ -767,15 +767,15 @@ jobs: - id: checkout name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - - id: pkgs_test_core_pub_upgrade - name: pkgs/test_core; dart pub upgrade + - id: pkgs_test_api_pub_upgrade + name: pkgs/test_api; dart pub upgrade run: dart pub upgrade if: "always() && steps.checkout.conclusion == 'success'" - working-directory: pkgs/test_core - - name: pkgs/test_core; dart test - run: dart test - if: "always() && steps.pkgs_test_core_pub_upgrade.conclusion == 'success'" - working-directory: pkgs/test_core + working-directory: pkgs/test_api + - name: "pkgs/test_api; dart test --preset travis -x browser" + run: dart test --preset travis -x browser + if: "always() && steps.pkgs_test_api_pub_upgrade.conclusion == 'success'" + working-directory: pkgs/test_api needs: - job_001 - job_002 @@ -1431,13 +1431,13 @@ jobs: - job_006 - job_007 job_037: - name: "unit_test; windows; Dart 3.5.0; PKG: integration_tests/spawn_hybrid; `dart test -p chrome,vm,node`" + name: "unit_test; windows; Dart 3.7.0; PKG: integration_tests/spawn_hybrid; `dart test -p chrome,vm,node`" runs-on: windows-latest steps: - name: Setup Dart SDK uses: dart-lang/setup-dart@e51d8e571e22473a2ddebf0ef8a2123f0ab2c02c with: - sdk: "3.5.0" + sdk: "3.7.0" - id: checkout name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 @@ -1459,13 +1459,13 @@ jobs: - job_006 - job_007 job_038: - name: "unit_test; windows; Dart 3.5.0; PKG: integration_tests/wasm; `dart test --timeout=60s`" + name: "unit_test; windows; Dart 3.7.0; PKG: integration_tests/wasm; `dart test --timeout=60s`" runs-on: windows-latest steps: - name: Setup Dart SDK uses: dart-lang/setup-dart@e51d8e571e22473a2ddebf0ef8a2123f0ab2c02c with: - sdk: "3.5.0" + sdk: "3.7.0" - id: checkout name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 diff --git a/integration_tests/regression/pubspec.yaml b/integration_tests/regression/pubspec.yaml index 69871817e..69b240caf 100644 --- a/integration_tests/regression/pubspec.yaml +++ b/integration_tests/regression/pubspec.yaml @@ -1,7 +1,7 @@ name: regression_tests publish_to: none environment: - sdk: ^3.5.0 + sdk: ^3.7.0 resolution: workspace dependencies: test: any diff --git a/integration_tests/spawn_hybrid/pubspec.yaml b/integration_tests/spawn_hybrid/pubspec.yaml index de9e5e9cc..4a3499fe2 100644 --- a/integration_tests/spawn_hybrid/pubspec.yaml +++ b/integration_tests/spawn_hybrid/pubspec.yaml @@ -1,7 +1,7 @@ name: spawn_hybrid publish_to: none environment: - sdk: ^3.5.0 + sdk: ^3.7.0 resolution: workspace dependencies: async: ^2.9.0 diff --git a/integration_tests/wasm/pubspec.yaml b/integration_tests/wasm/pubspec.yaml index 370d8446e..53f7f7ce7 100644 --- a/integration_tests/wasm/pubspec.yaml +++ b/integration_tests/wasm/pubspec.yaml @@ -1,7 +1,7 @@ name: wasm_tests publish_to: none environment: - sdk: ^3.5.0 + sdk: ^3.7.0 resolution: workspace dev_dependencies: test: any diff --git a/pkgs/test_api/pubspec.yaml b/pkgs/test_api/pubspec.yaml index bddeff5e5..169b214d3 100644 --- a/pkgs/test_api/pubspec.yaml +++ b/pkgs/test_api/pubspec.yaml @@ -7,7 +7,7 @@ issue_tracker: https://github.com/dart-lang/test/issues?q=is%3Aissue+is%3Aopen+l resolution: workspace environment: - sdk: ^3.5.0 + sdk: ^3.7.0 dependencies: async: ^2.5.0 From fd3592a33c14b430615db2a4e74db5208d8c1272 Mon Sep 17 00:00:00 2001 From: Nate Bosch Date: Tue, 22 Jul 2025 01:17:06 +0000 Subject: [PATCH 04/11] More packages - does the _whole_ repo need to move? --- .github/workflows/dart.yml | 250 ++++++++++++++----------------------- pkgs/checks/pubspec.yaml | 2 +- pkgs/matcher/pubspec.yaml | 2 +- 3 files changed, 97 insertions(+), 157 deletions(-) diff --git a/.github/workflows/dart.yml b/.github/workflows/dart.yml index 8f536afa5..e0860ff78 100644 --- a/.github/workflows/dart.yml +++ b/.github/workflows/dart.yml @@ -40,45 +40,6 @@ jobs: - name: mono_repo self validate run: dart pub global run mono_repo generate --validate job_002: - name: "analyze_and_format; linux; Dart 3.5.0; PKGS: pkgs/checks, pkgs/matcher; `dart analyze`" - runs-on: ubuntu-latest - steps: - - name: Cache Pub hosted dependencies - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 - with: - path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/checks-pkgs/matcher;commands:analyze_1" - restore-keys: | - os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/checks-pkgs/matcher - os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0 - os:ubuntu-latest;pub-cache-hosted - os:ubuntu-latest - - name: Setup Dart SDK - uses: dart-lang/setup-dart@e51d8e571e22473a2ddebf0ef8a2123f0ab2c02c - with: - sdk: "3.5.0" - - id: checkout - name: Checkout repository - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - - id: pkgs_checks_pub_upgrade - name: pkgs/checks; dart pub upgrade - run: dart pub upgrade - if: "always() && steps.checkout.conclusion == 'success'" - working-directory: pkgs/checks - - name: pkgs/checks; dart analyze - run: dart analyze - if: "always() && steps.pkgs_checks_pub_upgrade.conclusion == 'success'" - working-directory: pkgs/checks - - id: pkgs_matcher_pub_upgrade - name: pkgs/matcher; dart pub upgrade - run: dart pub upgrade - if: "always() && steps.checkout.conclusion == 'success'" - working-directory: pkgs/matcher - - name: pkgs/matcher; dart analyze - run: dart analyze - if: "always() && steps.pkgs_matcher_pub_upgrade.conclusion == 'success'" - working-directory: pkgs/matcher - job_003: name: "analyze_and_format; linux; Dart 3.7.0; PKGS: integration_tests/regression, integration_tests/wasm; `dart format --output=none --set-exit-if-changed .`, `dart analyze --fatal-infos`" runs-on: ubuntu-latest steps: @@ -125,17 +86,17 @@ jobs: run: dart analyze --fatal-infos if: "always() && steps.integration_tests_wasm_pub_upgrade.conclusion == 'success'" working-directory: integration_tests/wasm - job_004: - name: "analyze_and_format; linux; Dart 3.7.0; PKG: pkgs/test_core; `dart analyze`" + job_003: + name: "analyze_and_format; linux; Dart 3.7.0; PKGS: pkgs/checks, pkgs/matcher, pkgs/test_core; `dart analyze`" runs-on: ubuntu-latest steps: - name: Cache Pub hosted dependencies uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0;packages:pkgs/test_core;commands:analyze_1" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0;packages:pkgs/checks-pkgs/matcher-pkgs/test_core;commands:analyze_1" restore-keys: | - os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0;packages:pkgs/test_core + os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0;packages:pkgs/checks-pkgs/matcher-pkgs/test_core os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0 os:ubuntu-latest;pub-cache-hosted os:ubuntu-latest @@ -146,6 +107,24 @@ jobs: - id: checkout name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + - id: pkgs_checks_pub_upgrade + name: pkgs/checks; dart pub upgrade + run: dart pub upgrade + if: "always() && steps.checkout.conclusion == 'success'" + working-directory: pkgs/checks + - name: pkgs/checks; dart analyze + run: dart analyze + if: "always() && steps.pkgs_checks_pub_upgrade.conclusion == 'success'" + working-directory: pkgs/checks + - id: pkgs_matcher_pub_upgrade + name: pkgs/matcher; dart pub upgrade + run: dart pub upgrade + if: "always() && steps.checkout.conclusion == 'success'" + working-directory: pkgs/matcher + - name: pkgs/matcher; dart analyze + run: dart analyze + if: "always() && steps.pkgs_matcher_pub_upgrade.conclusion == 'success'" + working-directory: pkgs/matcher - id: pkgs_test_core_pub_upgrade name: pkgs/test_core; dart pub upgrade run: dart pub upgrade @@ -155,7 +134,7 @@ jobs: run: dart analyze if: "always() && steps.pkgs_test_core_pub_upgrade.conclusion == 'success'" working-directory: pkgs/test_core - job_005: + job_004: name: "analyze_and_format; linux; Dart dev; PKGS: integration_tests/regression, integration_tests/spawn_hybrid, integration_tests/wasm, pkgs/checks, pkgs/matcher, pkgs/test, pkgs/test_api, pkgs/test_core; `dart format --output=none --set-exit-if-changed .`, `dart analyze --fatal-infos`" runs-on: ubuntu-latest steps: @@ -280,7 +259,7 @@ jobs: run: dart analyze --fatal-infos if: "always() && steps.pkgs_test_core_pub_upgrade.conclusion == 'success'" working-directory: pkgs/test_core - job_006: + job_005: name: "analyze_and_format; windows; Dart 3.7.0; PKG: integration_tests/wasm; `dart format --output=none --set-exit-if-changed .`, `dart analyze --fatal-infos`" runs-on: windows-latest steps: @@ -304,7 +283,7 @@ jobs: run: dart analyze --fatal-infos if: "always() && steps.integration_tests_wasm_pub_upgrade.conclusion == 'success'" working-directory: integration_tests/wasm - job_007: + job_006: name: "analyze_and_format; windows; Dart dev; PKG: integration_tests/wasm; `dart format --output=none --set-exit-if-changed .`, `dart analyze --fatal-infos`" runs-on: windows-latest steps: @@ -328,36 +307,36 @@ jobs: run: dart analyze --fatal-infos if: "always() && steps.integration_tests_wasm_pub_upgrade.conclusion == 'success'" working-directory: integration_tests/wasm - job_008: - name: "unit_test; linux; Dart 3.5.0; PKG: pkgs/checks; `dart test`" + job_007: + name: "unit_test; linux; Dart 3.7.0; PKG: integration_tests/regression; `dart test`" runs-on: ubuntu-latest steps: - name: Cache Pub hosted dependencies uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/checks;commands:command_00" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0;packages:integration_tests/regression;commands:command_00" restore-keys: | - os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/checks - os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0 + os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0;packages:integration_tests/regression + os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0 os:ubuntu-latest;pub-cache-hosted os:ubuntu-latest - name: Setup Dart SDK uses: dart-lang/setup-dart@e51d8e571e22473a2ddebf0ef8a2123f0ab2c02c with: - sdk: "3.5.0" + sdk: "3.7.0" - id: checkout name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - - id: pkgs_checks_pub_upgrade - name: pkgs/checks; dart pub upgrade + - id: integration_tests_regression_pub_upgrade + name: integration_tests/regression; dart pub upgrade run: dart pub upgrade if: "always() && steps.checkout.conclusion == 'success'" - working-directory: pkgs/checks - - name: pkgs/checks; dart test + working-directory: integration_tests/regression + - name: integration_tests/regression; dart test run: dart test - if: "always() && steps.pkgs_checks_pub_upgrade.conclusion == 'success'" - working-directory: pkgs/checks + if: "always() && steps.integration_tests_regression_pub_upgrade.conclusion == 'success'" + working-directory: integration_tests/regression needs: - job_001 - job_002 @@ -365,37 +344,36 @@ jobs: - job_004 - job_005 - job_006 - - job_007 - job_009: - name: "unit_test; linux; Dart 3.5.0; PKG: pkgs/matcher; `dart test`" + job_008: + name: "unit_test; linux; Dart 3.7.0; PKG: pkgs/checks; `dart test`" runs-on: ubuntu-latest steps: - name: Cache Pub hosted dependencies uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/matcher;commands:command_00" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0;packages:pkgs/checks;commands:command_00" restore-keys: | - os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0;packages:pkgs/matcher - os:ubuntu-latest;pub-cache-hosted;sdk:3.5.0 + os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0;packages:pkgs/checks + os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0 os:ubuntu-latest;pub-cache-hosted os:ubuntu-latest - name: Setup Dart SDK uses: dart-lang/setup-dart@e51d8e571e22473a2ddebf0ef8a2123f0ab2c02c with: - sdk: "3.5.0" + sdk: "3.7.0" - id: checkout name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - - id: pkgs_matcher_pub_upgrade - name: pkgs/matcher; dart pub upgrade + - id: pkgs_checks_pub_upgrade + name: pkgs/checks; dart pub upgrade run: dart pub upgrade if: "always() && steps.checkout.conclusion == 'success'" - working-directory: pkgs/matcher - - name: pkgs/matcher; dart test + working-directory: pkgs/checks + - name: pkgs/checks; dart test run: dart test - if: "always() && steps.pkgs_matcher_pub_upgrade.conclusion == 'success'" - working-directory: pkgs/matcher + if: "always() && steps.pkgs_checks_pub_upgrade.conclusion == 'success'" + working-directory: pkgs/checks needs: - job_001 - job_002 @@ -403,18 +381,17 @@ jobs: - job_004 - job_005 - job_006 - - job_007 - job_010: - name: "unit_test; linux; Dart 3.7.0; PKG: integration_tests/regression; `dart test`" + job_009: + name: "unit_test; linux; Dart 3.7.0; PKG: pkgs/matcher; `dart test`" runs-on: ubuntu-latest steps: - name: Cache Pub hosted dependencies uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0;packages:integration_tests/regression;commands:command_00" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0;packages:pkgs/matcher;commands:command_00" restore-keys: | - os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0;packages:integration_tests/regression + os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0;packages:pkgs/matcher os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0 os:ubuntu-latest;pub-cache-hosted os:ubuntu-latest @@ -425,15 +402,15 @@ jobs: - id: checkout name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - - id: integration_tests_regression_pub_upgrade - name: integration_tests/regression; dart pub upgrade + - id: pkgs_matcher_pub_upgrade + name: pkgs/matcher; dart pub upgrade run: dart pub upgrade if: "always() && steps.checkout.conclusion == 'success'" - working-directory: integration_tests/regression - - name: integration_tests/regression; dart test + working-directory: pkgs/matcher + - name: pkgs/matcher; dart test run: dart test - if: "always() && steps.integration_tests_regression_pub_upgrade.conclusion == 'success'" - working-directory: integration_tests/regression + if: "always() && steps.pkgs_matcher_pub_upgrade.conclusion == 'success'" + working-directory: pkgs/matcher needs: - job_001 - job_002 @@ -441,8 +418,7 @@ jobs: - job_004 - job_005 - job_006 - - job_007 - job_011: + job_010: name: "unit_test; linux; Dart 3.7.0; PKG: pkgs/test_core; `dart test`" runs-on: ubuntu-latest steps: @@ -479,8 +455,7 @@ jobs: - job_004 - job_005 - job_006 - - job_007 - job_012: + job_011: name: "unit_test; linux; Dart 3.7.0; PKG: integration_tests/spawn_hybrid; `dart test -p chrome,vm,node`" runs-on: ubuntu-latest steps: @@ -517,8 +492,7 @@ jobs: - job_004 - job_005 - job_006 - - job_007 - job_013: + job_012: name: "unit_test; linux; Dart 3.7.0; PKG: integration_tests/wasm; `dart test --timeout=60s`" runs-on: ubuntu-latest steps: @@ -555,8 +529,7 @@ jobs: - job_004 - job_005 - job_006 - - job_007 - job_014: + job_013: name: "unit_test; linux; Dart 3.7.0; PKG: pkgs/test; `xvfb-run -s \"-screen 0 1024x768x24\" dart test --preset travis --total-shards 5 --shard-index 0`" runs-on: ubuntu-latest steps: @@ -593,8 +566,7 @@ jobs: - job_004 - job_005 - job_006 - - job_007 - job_015: + job_014: name: "unit_test; linux; Dart 3.7.0; PKG: pkgs/test; `xvfb-run -s \"-screen 0 1024x768x24\" dart test --preset travis --total-shards 5 --shard-index 1`" runs-on: ubuntu-latest steps: @@ -631,8 +603,7 @@ jobs: - job_004 - job_005 - job_006 - - job_007 - job_016: + job_015: name: "unit_test; linux; Dart 3.7.0; PKG: pkgs/test; `xvfb-run -s \"-screen 0 1024x768x24\" dart test --preset travis --total-shards 5 --shard-index 2`" runs-on: ubuntu-latest steps: @@ -669,8 +640,7 @@ jobs: - job_004 - job_005 - job_006 - - job_007 - job_017: + job_016: name: "unit_test; linux; Dart 3.7.0; PKG: pkgs/test; `xvfb-run -s \"-screen 0 1024x768x24\" dart test --preset travis --total-shards 5 --shard-index 3`" runs-on: ubuntu-latest steps: @@ -707,8 +677,7 @@ jobs: - job_004 - job_005 - job_006 - - job_007 - job_018: + job_017: name: "unit_test; linux; Dart 3.7.0; PKG: pkgs/test; `xvfb-run -s \"-screen 0 1024x768x24\" dart test --preset travis --total-shards 5 --shard-index 4`" runs-on: ubuntu-latest steps: @@ -745,8 +714,7 @@ jobs: - job_004 - job_005 - job_006 - - job_007 - job_019: + job_018: name: "unit_test; linux; Dart 3.7.0; PKG: pkgs/test_api; `dart test --preset travis -x browser`" runs-on: ubuntu-latest steps: @@ -783,8 +751,7 @@ jobs: - job_004 - job_005 - job_006 - - job_007 - job_020: + job_019: name: "unit_test; linux; Dart dev; PKG: integration_tests/regression; `dart test`" runs-on: ubuntu-latest steps: @@ -821,8 +788,7 @@ jobs: - job_004 - job_005 - job_006 - - job_007 - job_021: + job_020: name: "unit_test; linux; Dart dev; PKG: pkgs/checks; `dart test`" runs-on: ubuntu-latest steps: @@ -859,8 +825,7 @@ jobs: - job_004 - job_005 - job_006 - - job_007 - job_022: + job_021: name: "unit_test; linux; Dart dev; PKG: pkgs/matcher; `dart test`" runs-on: ubuntu-latest steps: @@ -897,8 +862,7 @@ jobs: - job_004 - job_005 - job_006 - - job_007 - job_023: + job_022: name: "unit_test; linux; Dart dev; PKG: pkgs/test_core; `dart test`" runs-on: ubuntu-latest steps: @@ -935,8 +899,7 @@ jobs: - job_004 - job_005 - job_006 - - job_007 - job_024: + job_023: name: "unit_test; linux; Dart dev; PKG: integration_tests/spawn_hybrid; `dart test -p chrome,vm,node`" runs-on: ubuntu-latest steps: @@ -973,8 +936,7 @@ jobs: - job_004 - job_005 - job_006 - - job_007 - job_025: + job_024: name: "unit_test; linux; Dart dev; PKG: integration_tests/wasm; `dart test --timeout=60s`" runs-on: ubuntu-latest steps: @@ -1011,8 +973,7 @@ jobs: - job_004 - job_005 - job_006 - - job_007 - job_026: + job_025: name: "unit_test; linux; Dart dev; PKG: pkgs/test; `xvfb-run -s \"-screen 0 1024x768x24\" dart test --preset travis --total-shards 5 --shard-index 0`" runs-on: ubuntu-latest steps: @@ -1049,8 +1010,7 @@ jobs: - job_004 - job_005 - job_006 - - job_007 - job_027: + job_026: name: "unit_test; linux; Dart dev; PKG: pkgs/test; `xvfb-run -s \"-screen 0 1024x768x24\" dart test --preset travis --total-shards 5 --shard-index 1`" runs-on: ubuntu-latest steps: @@ -1087,8 +1047,7 @@ jobs: - job_004 - job_005 - job_006 - - job_007 - job_028: + job_027: name: "unit_test; linux; Dart dev; PKG: pkgs/test; `xvfb-run -s \"-screen 0 1024x768x24\" dart test --preset travis --total-shards 5 --shard-index 2`" runs-on: ubuntu-latest steps: @@ -1125,8 +1084,7 @@ jobs: - job_004 - job_005 - job_006 - - job_007 - job_029: + job_028: name: "unit_test; linux; Dart dev; PKG: pkgs/test; `xvfb-run -s \"-screen 0 1024x768x24\" dart test --preset travis --total-shards 5 --shard-index 3`" runs-on: ubuntu-latest steps: @@ -1163,8 +1121,7 @@ jobs: - job_004 - job_005 - job_006 - - job_007 - job_030: + job_029: name: "unit_test; linux; Dart dev; PKG: pkgs/test; `xvfb-run -s \"-screen 0 1024x768x24\" dart test --preset travis --total-shards 5 --shard-index 4`" runs-on: ubuntu-latest steps: @@ -1201,8 +1158,7 @@ jobs: - job_004 - job_005 - job_006 - - job_007 - job_031: + job_030: name: "unit_test; linux; Dart dev; PKG: pkgs/test_api; `dart test --preset travis -x browser`" runs-on: ubuntu-latest steps: @@ -1239,8 +1195,7 @@ jobs: - job_004 - job_005 - job_006 - - job_007 - job_032: + job_031: name: "unit_test; osx; Dart 3.7.0; PKG: pkgs/test; `dart test --preset travis --total-shards 5 --shard-index 0`" runs-on: macos-latest steps: @@ -1277,8 +1232,7 @@ jobs: - job_004 - job_005 - job_006 - - job_007 - job_033: + job_032: name: "unit_test; osx; Dart 3.7.0; PKG: pkgs/test; `dart test --preset travis --total-shards 5 --shard-index 1`" runs-on: macos-latest steps: @@ -1315,8 +1269,7 @@ jobs: - job_004 - job_005 - job_006 - - job_007 - job_034: + job_033: name: "unit_test; osx; Dart 3.7.0; PKG: pkgs/test; `dart test --preset travis --total-shards 5 --shard-index 2`" runs-on: macos-latest steps: @@ -1353,8 +1306,7 @@ jobs: - job_004 - job_005 - job_006 - - job_007 - job_035: + job_034: name: "unit_test; osx; Dart 3.7.0; PKG: pkgs/test; `dart test --preset travis --total-shards 5 --shard-index 3`" runs-on: macos-latest steps: @@ -1391,8 +1343,7 @@ jobs: - job_004 - job_005 - job_006 - - job_007 - job_036: + job_035: name: "unit_test; osx; Dart 3.7.0; PKG: pkgs/test; `dart test --preset travis --total-shards 5 --shard-index 4`" runs-on: macos-latest steps: @@ -1429,8 +1380,7 @@ jobs: - job_004 - job_005 - job_006 - - job_007 - job_037: + job_036: name: "unit_test; windows; Dart 3.7.0; PKG: integration_tests/spawn_hybrid; `dart test -p chrome,vm,node`" runs-on: windows-latest steps: @@ -1457,8 +1407,7 @@ jobs: - job_004 - job_005 - job_006 - - job_007 - job_038: + job_037: name: "unit_test; windows; Dart 3.7.0; PKG: integration_tests/wasm; `dart test --timeout=60s`" runs-on: windows-latest steps: @@ -1485,8 +1434,7 @@ jobs: - job_004 - job_005 - job_006 - - job_007 - job_039: + job_038: name: "unit_test; windows; Dart 3.7.0; PKG: pkgs/test; `dart test --preset travis --total-shards 5 --shard-index 0`" runs-on: windows-latest steps: @@ -1513,8 +1461,7 @@ jobs: - job_004 - job_005 - job_006 - - job_007 - job_040: + job_039: name: "unit_test; windows; Dart 3.7.0; PKG: pkgs/test; `dart test --preset travis --total-shards 5 --shard-index 1`" runs-on: windows-latest steps: @@ -1541,8 +1488,7 @@ jobs: - job_004 - job_005 - job_006 - - job_007 - job_041: + job_040: name: "unit_test; windows; Dart 3.7.0; PKG: pkgs/test; `dart test --preset travis --total-shards 5 --shard-index 2`" runs-on: windows-latest steps: @@ -1569,8 +1515,7 @@ jobs: - job_004 - job_005 - job_006 - - job_007 - job_042: + job_041: name: "unit_test; windows; Dart 3.7.0; PKG: pkgs/test; `dart test --preset travis --total-shards 5 --shard-index 3`" runs-on: windows-latest steps: @@ -1597,8 +1542,7 @@ jobs: - job_004 - job_005 - job_006 - - job_007 - job_043: + job_042: name: "unit_test; windows; Dart 3.7.0; PKG: pkgs/test; `dart test --preset travis --total-shards 5 --shard-index 4`" runs-on: windows-latest steps: @@ -1625,8 +1569,7 @@ jobs: - job_004 - job_005 - job_006 - - job_007 - job_044: + job_043: name: "unit_test; windows; Dart dev; PKG: integration_tests/spawn_hybrid; `dart test -p chrome,vm,node`" runs-on: windows-latest steps: @@ -1653,8 +1596,7 @@ jobs: - job_004 - job_005 - job_006 - - job_007 - job_045: + job_044: name: "unit_test; windows; Dart dev; PKG: integration_tests/wasm; `dart test --timeout=60s`" runs-on: windows-latest steps: @@ -1681,8 +1623,7 @@ jobs: - job_004 - job_005 - job_006 - - job_007 - job_046: + job_045: name: Notify failure runs-on: ubuntu-latest if: "(github.event_name == 'push' || github.event_name == 'schedule') && failure()" @@ -1738,4 +1679,3 @@ jobs: - job_042 - job_043 - job_044 - - job_045 diff --git a/pkgs/checks/pubspec.yaml b/pkgs/checks/pubspec.yaml index 8a00937e8..afcea29fb 100644 --- a/pkgs/checks/pubspec.yaml +++ b/pkgs/checks/pubspec.yaml @@ -9,7 +9,7 @@ issue_tracker: https://github.com/dart-lang/test/issues?q=is%3Aissue+is%3Aopen+l resolution: workspace environment: - sdk: ^3.5.0 + sdk: ^3.7.0 dependencies: async: ^2.8.0 diff --git a/pkgs/matcher/pubspec.yaml b/pkgs/matcher/pubspec.yaml index 5351a0c02..1699d98fb 100644 --- a/pkgs/matcher/pubspec.yaml +++ b/pkgs/matcher/pubspec.yaml @@ -7,7 +7,7 @@ repository: https://github.com/dart-lang/test/tree/master/pkgs/matcher issue_tracker: https://github.com/dart-lang/test/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Amatcher environment: - sdk: ^3.5.0 + sdk: ^3.7.0 dependencies: async: ^2.10.0 From a68a4f3f38f1adef9c28547affebd45b96cfcbb6 Mon Sep 17 00:00:00 2001 From: Nate Bosch Date: Tue, 22 Jul 2025 20:21:05 +0000 Subject: [PATCH 05/11] Reformat --- .../spawn_hybrid/test/hybrid_test.dart | 225 ++- .../spawn_hybrid/test/hybrid_test_io.dart | 12 +- .../spawn_hybrid/test/subdir/hybrid_test.dart | 7 +- pkgs/checks/example/example.dart | 6 +- pkgs/checks/lib/src/checks.dart | 259 ++-- pkgs/checks/lib/src/collection_equality.dart | 201 ++- pkgs/checks/lib/src/describe.dart | 59 +- pkgs/checks/lib/src/extensions/async.dart | 512 ++++--- pkgs/checks/lib/src/extensions/core.dart | 91 +- pkgs/checks/lib/src/extensions/function.dart | 18 +- pkgs/checks/lib/src/extensions/iterable.dart | 425 +++--- pkgs/checks/lib/src/extensions/map.dart | 99 +- pkgs/checks/lib/src/extensions/string.dart | 173 ++- pkgs/checks/test/context_test.dart | 52 +- pkgs/checks/test/describe_test.dart | 7 +- pkgs/checks/test/extensions/async_test.dart | 480 +++--- .../extensions/collection_equality_test.dart | 241 +-- pkgs/checks/test/extensions/core_test.dart | 107 +- .../checks/test/extensions/function_test.dart | 20 +- .../checks/test/extensions/iterable_test.dart | 270 ++-- pkgs/checks/test/extensions/map_test.dart | 50 +- pkgs/checks/test/extensions/math_test.dart | 65 +- pkgs/checks/test/extensions/string_test.dart | 174 ++- pkgs/checks/test/pretty_print_test.dart | 6 +- pkgs/checks/test/soft_check_test.dart | 22 +- pkgs/checks/test/test_shared.dart | 116 +- pkgs/test/lib/src/bootstrap/browser.dart | 21 +- pkgs/test/lib/src/bootstrap/node.dart | 13 +- pkgs/test/lib/src/runner/browser/browser.dart | 109 +- .../src/runner/browser/browser_manager.dart | 233 +-- pkgs/test/lib/src/runner/browser/chrome.dart | 110 +- .../browser/compilers/compiler_support.dart | 20 +- .../src/runner/browser/compilers/dart2js.dart | 74 +- .../runner/browser/compilers/dart2wasm.dart | 76 +- .../runner/browser/compilers/precompiled.dart | 67 +- .../src/runner/browser/default_settings.dart | 33 +- pkgs/test/lib/src/runner/browser/dom.dart | 54 +- pkgs/test/lib/src/runner/browser/firefox.dart | 24 +- .../src/runner/browser/microsoft_edge.dart | 18 +- .../test/lib/src/runner/browser/platform.dart | 184 ++- .../runner/browser/post_message_channel.dart | 16 +- pkgs/test/lib/src/runner/browser/safari.dart | 16 +- .../lib/src/runner/executable_settings.dart | 105 +- pkgs/test/lib/src/runner/node/platform.dart | 217 ++- .../lib/src/runner/node/socket_channel.dart | 5 +- pkgs/test/lib/src/util/package_map.dart | 11 +- pkgs/test/lib/src/util/path_handler.dart | 5 +- pkgs/test/test/io.dart | 117 +- .../test/test/runner/browser/chrome_test.dart | 55 +- .../test/test/runner/browser/code_server.dart | 26 +- .../runner/browser/compact_reporter_test.dart | 12 +- .../browser/expanded_reporter_test.dart | 26 +- .../test/runner/browser/firefox_test.dart | 35 +- .../test/test/runner/browser/loader_test.dart | 56 +- .../runner/browser/microsoft_edge_test.dart | 30 +- .../test/test/runner/browser/runner_test.dart | 404 +++-- .../test/test/runner/browser/safari_test.dart | 67 +- .../test/runner/compact_reporter_test.dart | 229 ++- .../runner/compiler_runtime_matrix_test.dart | 138 +- pkgs/test/test/runner/compiler_test.dart | 54 +- .../runner/configuration/compiler_test.dart | 44 +- .../configuration/configuration_test.dart | 234 +-- .../configuration/custom_platform_test.dart | 313 ++-- .../configuration/duplicate_names_test.dart | 22 +- .../runner/configuration/global_test.dart | 39 +- .../runner/configuration/include_test.dart | 24 +- .../runner/configuration/platform_test.dart | 264 ++-- .../runner/configuration/presets_test.dart | 423 ++--- .../configuration/randomize_order_test.dart | 206 +-- .../test/runner/configuration/suite_test.dart | 145 +- .../test/runner/configuration/tags_test.dart | 229 +-- .../configuration/top_level_error_test.dart | 256 ++-- .../runner/configuration/top_level_test.dart | 251 +-- pkgs/test/test/runner/coverage_test.dart | 83 +- pkgs/test/test/runner/engine_test.dart | 191 ++- .../test/runner/expanded_reporter_test.dart | 162 +- .../runner/failures_only_reporter_test.dart | 113 +- .../test/runner/github_reporter_test.dart | 138 +- .../test/runner/json_file_reporter_test.dart | 138 +- pkgs/test/test/runner/json_reporter_test.dart | 905 ++++++----- .../test/test/runner/json_reporter_utils.dart | 151 +- pkgs/test/test/runner/line_and_col_test.dart | 153 +- pkgs/test/test/runner/load_suite_test.dart | 150 +- pkgs/test/test/runner/loader_test.dart | 267 ++-- pkgs/test/test/runner/name_test.dart | 117 +- pkgs/test/test/runner/node/runner_test.dart | 179 ++- .../test/test/runner/parse_metadata_test.dart | 219 ++- .../test/runner/pause_after_load_test.dart | 404 +++-- pkgs/test/test/runner/precompiled_test.dart | 175 ++- pkgs/test/test/runner/retry_test.dart | 20 +- pkgs/test/test/runner/runner_test.dart | 334 ++-- pkgs/test/test/runner/shard_test.dart | 148 +- pkgs/test/test/runner/signal_test.dart | 12 +- pkgs/test/test/runner/skip_expect_test.dart | 141 +- pkgs/test/test/runner/tag_test.dart | 124 +- pkgs/test/test/runner/test_chain_test.dart | 39 +- pkgs/test/test/runner/test_on_test.dart | 98 +- pkgs/test/test/runner/timeout_test.dart | 61 +- pkgs/test/test/util/one_off_handler_test.dart | 40 +- pkgs/test/test/util/path_handler_test.dart | 63 +- .../util/string_literal_iterator_test.dart | 29 +- pkgs/test/test/utils.dart | 330 ++-- pkgs/test/tool/host.dart | 128 +- pkgs/test_api/lib/fake.dart | 6 +- pkgs/test_api/lib/hooks.dart | 4 +- pkgs/test_api/lib/hooks_testing.dart | 8 +- pkgs/test_api/lib/src/backend/compiler.dart | 5 +- .../src/backend/configuration/timeout.dart | 20 +- pkgs/test_api/lib/src/backend/declarer.dart | 272 ++-- pkgs/test_api/lib/src/backend/group.dart | 73 +- pkgs/test_api/lib/src/backend/invoker.dart | 178 ++- .../lib/src/backend/live_test_controller.dart | 20 +- pkgs/test_api/lib/src/backend/message.dart | 8 +- pkgs/test_api/lib/src/backend/metadata.dart | 304 ++-- .../lib/src/backend/operating_system.dart | 21 +- .../lib/src/backend/platform_selector.dart | 52 +- .../lib/src/backend/remote_exception.dart | 8 +- .../lib/src/backend/remote_listener.dart | 259 ++-- pkgs/test_api/lib/src/backend/runtime.dart | 134 +- .../src/backend/stack_trace_formatter.dart | 12 +- pkgs/test_api/lib/src/backend/suite.dart | 10 +- .../lib/src/backend/suite_platform.dart | 42 +- .../lib/src/backend/test_location.dart | 13 +- .../lib/src/scaffolding/spawn_hybrid.dart | 66 +- .../lib/src/scaffolding/test_structure.dart | 88 +- pkgs/test_api/lib/src/scaffolding/utils.dart | 11 +- pkgs/test_api/lib/test_api.dart | 6 +- pkgs/test_api/test/backend/declarer_test.dart | 486 +++--- pkgs/test_api/test/backend/invoker_test.dart | 473 +++--- pkgs/test_api/test/backend/metadata_test.dart | 165 +- .../test/frontend/add_tear_down_test.dart | 163 +- .../test/frontend/set_up_all_test.dart | 27 +- .../test/frontend/tear_down_all_test.dart | 36 +- pkgs/test_api/test/frontend/timeout_test.dart | 38 +- .../test/import_restrictions_test.dart | 28 +- pkgs/test_api/test/utils.dart | 53 +- pkgs/test_core/lib/backend.dart | 6 +- pkgs/test_core/lib/scaffolding.dart | 6 +- pkgs/test_core/lib/src/bootstrap/vm.dart | 32 +- pkgs/test_core/lib/src/direct_run.dart | 85 +- pkgs/test_core/lib/src/executable.dart | 51 +- pkgs/test_core/lib/src/runner.dart | 492 +++--- .../lib/src/runner/compiler_pool.dart | 17 +- .../lib/src/runner/compiler_selection.dart | 37 +- .../lib/src/runner/configuration.dart | 1358 +++++++++-------- .../lib/src/runner/configuration/args.dart | 607 +++++--- .../runner/configuration/custom_runtime.dart | 11 +- .../lib/src/runner/configuration/load.dart | 466 ++++-- .../src/runner/configuration/reporters.dart | 107 +- .../configuration/runtime_settings.dart | 2 +- .../lib/src/runner/configuration/utils.dart | 7 +- pkgs/test_core/lib/src/runner/console.dart | 28 +- pkgs/test_core/lib/src/runner/coverage.dart | 13 +- .../lib/src/runner/coverage_stub.dart | 7 +- .../lib/src/runner/dart2js_compiler_pool.dart | 44 +- pkgs/test_core/lib/src/runner/debugger.dart | 66 +- pkgs/test_core/lib/src/runner/engine.dart | 156 +- .../test_core/lib/src/runner/environment.dart | 6 +- .../src/runner/hack_register_platform.dart | 7 +- .../lib/src/runner/hybrid_listener.dart | 125 +- pkgs/test_core/lib/src/runner/live_suite.dart | 10 +- .../lib/src/runner/live_suite_controller.dart | 17 +- pkgs/test_core/lib/src/runner/load_suite.dart | 183 ++- pkgs/test_core/lib/src/runner/loader.dart | 120 +- .../lib/src/runner/parse_metadata.dart | 294 ++-- pkgs/test_core/lib/src/runner/platform.dart | 8 +- .../lib/src/runner/plugin/environment.dart | 6 +- .../src/runner/plugin/platform_helpers.dart | 141 +- .../plugin/remote_platform_helpers.dart | 23 +- .../plugin/shared_platform_helpers.dart | 7 +- .../lib/src/runner/reporter/compact.dart | 139 +- .../lib/src/runner/reporter/expanded.dart | 96 +- .../src/runner/reporter/failures_only.dart | 91 +- .../lib/src/runner/reporter/github.dart | 68 +- .../lib/src/runner/reporter/json.dart | 120 +- .../lib/src/runner/runner_suite.dart | 85 +- .../test_core/lib/src/runner/runner_test.dart | 154 +- .../lib/src/runner/spawn_hybrid.dart | 72 +- pkgs/test_core/lib/src/runner/suite.dart | 419 ++--- pkgs/test_core/lib/src/runner/version.dart | 97 +- .../lib/src/runner/vm/environment.dart | 19 +- .../test_core/lib/src/runner/vm/platform.dart | 262 ++-- .../lib/src/runner/vm/test_compiler.dart | 160 +- .../lib/src/runner/wasm_compiler_pool.dart | 15 +- pkgs/test_core/lib/src/scaffolding.dart | 114 +- pkgs/test_core/lib/src/util/async.dart | 13 +- pkgs/test_core/lib/src/util/dart.dart | 26 +- pkgs/test_core/lib/src/util/io.dart | 104 +- pkgs/test_core/lib/src/util/io_stub.dart | 3 +- pkgs/test_core/lib/src/util/os.dart | 14 +- .../lib/src/util/stack_trace_mapper.dart | 40 +- .../lib/src/util/string_literal_iterator.dart | 3 +- pkgs/test_core/lib/test_core.dart | 6 +- .../test/runner/vm/test_compiler_test.dart | 6 +- 194 files changed, 13923 insertions(+), 9756 deletions(-) diff --git a/integration_tests/spawn_hybrid/test/hybrid_test.dart b/integration_tests/spawn_hybrid/test/hybrid_test.dart index 1493e23f2..3ca222eb6 100644 --- a/integration_tests/spawn_hybrid/test/hybrid_test.dart +++ b/integration_tests/spawn_hybrid/test/hybrid_test.dart @@ -11,37 +11,46 @@ import 'package:test/test.dart'; void main() { group('spawnHybridUri():', () { - test('loads a file in a separate isolate connected via StreamChannel', - () async { - expect(spawnHybridUri('util/emits_numbers.dart').stream.toList(), - completion(equals([1, 2, 3]))); - }); + test( + 'loads a file in a separate isolate connected via StreamChannel', + () async { + expect( + spawnHybridUri('util/emits_numbers.dart').stream.toList(), + completion(equals([1, 2, 3])), + ); + }, + ); test('resolves root-relative URIs relative to the package root', () async { - expect(spawnHybridUri('/test/util/emits_numbers.dart').stream.toList(), - completion(equals([1, 2, 3]))); + expect( + spawnHybridUri('/test/util/emits_numbers.dart').stream.toList(), + completion(equals([1, 2, 3])), + ); }); test('supports Uri objects', () async { expect( - spawnHybridUri(Uri.parse('util/emits_numbers.dart')).stream.toList(), - completion(equals([1, 2, 3]))); + spawnHybridUri(Uri.parse('util/emits_numbers.dart')).stream.toList(), + completion(equals([1, 2, 3])), + ); }); test('supports package: uris referencing the root package', () async { expect( - spawnHybridUri(Uri.parse('package:spawn_hybrid/emits_numbers.dart')) - .stream - .toList(), - completion(equals([1, 2, 3]))); + spawnHybridUri( + Uri.parse('package:spawn_hybrid/emits_numbers.dart'), + ).stream.toList(), + completion(equals([1, 2, 3])), + ); }); test('supports package: uris referencing dependency packages', () async { expect( - spawnHybridUri(Uri.parse('package:other_package/emits_numbers.dart')) - .stream - .toList(), - completion(equals([1, 2, 3]))); + spawnHybridUri( + Uri.parse('package:other_package/emits_numbers.dart'), + ).stream.toList(), + completion(equals([1, 2, 3])), + ); }); test('rejects non-String, non-Uri objects', () { @@ -50,65 +59,83 @@ void main() { test('passes a message to the hybrid isolate', () async { expect( - spawnHybridUri('util/echos_message.dart', message: 123).stream.first, - completion(equals(123))); + spawnHybridUri('util/echos_message.dart', message: 123).stream.first, + completion(equals(123)), + ); expect( - spawnHybridUri('util/echos_message.dart', message: 'wow') - .stream - .first, - completion(equals('wow'))); + spawnHybridUri('util/echos_message.dart', message: 'wow').stream.first, + completion(equals('wow')), + ); }); - test('emits an error from the stream channel if the isolate fails to load', - () { - expect(spawnHybridUri('non existent file').stream.first, - throwsA(isA())); - }); + test( + 'emits an error from the stream channel if the isolate fails to load', + () { + expect( + spawnHybridUri('non existent file').stream.first, + throwsA(isA()), + ); + }, + ); }); group('spawnHybridCode()', () { - test('loads the code in a separate isolate connected via StreamChannel', - () { - expect(spawnHybridCode(''' + test( + 'loads the code in a separate isolate connected via StreamChannel', + () { + expect( + spawnHybridCode(''' import "package:stream_channel/stream_channel.dart"; void hybridMain(StreamChannel channel) { channel.sink..add(1)..add(2)..add(3)..close(); } - ''').stream.toList(), completion(equals([1, 2, 3]))); - }); + ''').stream.toList(), + completion(equals([1, 2, 3])), + ); + }, + ); test('allows a first parameter with type StreamChannel', () { - expect(spawnHybridCode(''' + expect( + spawnHybridCode(''' import "package:stream_channel/stream_channel.dart"; void hybridMain(StreamChannel channel) { channel.sink..add(1)..add(2)..add(null)..close(); } - ''').stream.toList(), completion(equals([1, 2, null]))); + ''').stream.toList(), + completion(equals([1, 2, null])), + ); }); test('gives a good error when the StreamChannel type is not supported', () { expect( - spawnHybridCode(''' + spawnHybridCode(''' import "package:stream_channel/stream_channel.dart"; void hybridMain(StreamChannel channel) { channel.sink..add(1)..add(2)..add(3)..close(); } ''').stream, - emitsError(isA().having( - (e) => e.toString(), - 'toString', - contains( - 'The first parameter to the top-level hybridMain() must be a ' - 'StreamChannel or StreamChannel. More specific ' - 'types such as StreamChannel are not supported.')))); + emitsError( + isA().having( + (e) => e.toString(), + 'toString', + contains( + 'The first parameter to the top-level hybridMain() must be a ' + 'StreamChannel or StreamChannel. More specific ' + 'types such as StreamChannel are not supported.', + ), + ), + ), + ); }); test('can use dart:io even when run from a browser', () async { var path = p.join('test', 'hybrid_test.dart'); - expect(spawnHybridCode(""" + expect( + spawnHybridCode(""" import 'dart:io'; import 'package:stream_channel/stream_channel.dart'; @@ -118,7 +145,9 @@ void main() { ..add(File(r"$path").readAsStringSync()) ..close(); } - """).stream.first, completion(contains('hybrid emits numbers'))); + """).stream.first, + completion(contains('hybrid emits numbers')), + ); }, testOn: 'browser'); test('forwards data from the test to the hybrid isolate', () async { @@ -147,15 +176,20 @@ void main() { } '''; - expect(spawnHybridCode(code, message: [1, 2, 3]).stream.first, - completion(equals([1, 2, 3]))); - expect(spawnHybridCode(code, message: {'a': 'b'}).stream.first, - completion(equals({'a': 'b'}))); + expect( + spawnHybridCode(code, message: [1, 2, 3]).stream.first, + completion(equals([1, 2, 3])), + ); + expect( + spawnHybridCode(code, message: {'a': 'b'}).stream.first, + completion(equals({'a': 'b'})), + ); }); - test('allows the hybrid isolate to send errors across the stream channel', - () { - var channel = spawnHybridCode(''' + test( + 'allows the hybrid isolate to send errors across the stream channel', + () { + var channel = spawnHybridCode(''' import "package:stack_trace/stack_trace.dart"; import "package:stream_channel/stream_channel.dart"; @@ -164,11 +198,15 @@ void main() { } '''); - channel.stream.listen(null, onError: expectAsync2((error, stackTrace) { - expect(error.toString(), equals('oh no!')); - expect(stackTrace.toString(), contains('hybridMain')); - })); - }); + channel.stream.listen( + null, + onError: expectAsync2((error, stackTrace) { + expect(error.toString(), equals('oh no!')); + expect(stackTrace.toString(), contains('hybridMain')); + }), + ); + }, + ); test('sends an unhandled synchronous error across the stream channel', () { var channel = spawnHybridCode(''' @@ -179,10 +217,13 @@ void main() { } '''); - channel.stream.listen(null, onError: expectAsync2((error, stackTrace) { - expect(error.toString(), equals('oh no!')); - expect(stackTrace.toString(), contains('hybridMain')); - })); + channel.stream.listen( + null, + onError: expectAsync2((error, stackTrace) { + expect(error.toString(), equals('oh no!')); + expect(stackTrace.toString(), contains('hybridMain')); + }), + ); }); test('sends an unhandled asynchronous error across the stream channel', () { @@ -198,10 +239,13 @@ void main() { } '''); - channel.stream.listen(null, onError: expectAsync2((error, stackTrace) { - expect(error.toString(), equals('oh no!')); - expect(stackTrace.toString(), contains('hybridMain')); - })); + channel.stream.listen( + null, + onError: expectAsync2((error, stackTrace) { + expect(error.toString(), equals('oh no!')); + expect(stackTrace.toString(), contains('hybridMain')); + }), + ); }); test('deserializes TestFailures as TestFailures', () { @@ -228,20 +272,27 @@ void main() { expect(() => channel.sink.add([].iterator), throwsArgumentError); }); - test('gracefully handles an unserializable message in the browser', - () async { - var channel = spawnHybridCode(''' + test( + 'gracefully handles an unserializable message in the browser', + () async { + var channel = spawnHybridCode(''' import 'package:stream_channel/stream_channel.dart'; void hybridMain(StreamChannel channel) {} '''); - expect(() => channel.sink.add([].iterator), throwsArgumentError); - }, testOn: 'browser'); - - test('gracefully handles an unserializable message in the hybrid isolate', - () { - var channel = spawnHybridCode(''' + expect( + () => channel.sink.add([].iterator), + throwsArgumentError, + ); + }, + testOn: 'browser', + ); + + test( + 'gracefully handles an unserializable message in the hybrid isolate', + () { + var channel = spawnHybridCode(''' import "package:stream_channel/stream_channel.dart"; void hybridMain(StreamChannel channel) { @@ -249,10 +300,14 @@ void main() { } '''); - channel.stream.listen(null, onError: expectAsync1((error) { - expect(error.toString(), contains("can't be JSON-encoded.")); - })); - }); + channel.stream.listen( + null, + onError: expectAsync1((error) { + expect(error.toString(), contains("can't be JSON-encoded.")); + }), + ); + }, + ); test('forwards prints from the hybrid isolate', () { expect(() async { @@ -272,14 +327,17 @@ void main() { // that's imported, URIs don't escape $ by default, and $ isn't allowed in // imports. test('supports a dollar character in the hybrid code', () { - expect(spawnHybridCode(r''' + expect( + spawnHybridCode(r''' import "package:stream_channel/stream_channel.dart"; void hybridMain(StreamChannel channel) { var value = "bar"; channel.sink.add("foo${value}baz"); } - ''').stream.first, completion('foobarbaz')); + ''').stream.first, + completion('foobarbaz'), + ); }); test('closes the channel when the hybrid isolate exits', () { @@ -342,7 +400,8 @@ void main() { }); test('opts in to null safety by default', () async { - expect(spawnHybridCode(''' + expect( + spawnHybridCode(''' import "package:stream_channel/stream_channel.dart"; // Use some null safety syntax @@ -351,7 +410,9 @@ void main() { void hybridMain(StreamChannel channel) { channel.sink..add(1)..add(2)..add(3)..close(); } - ''').stream.toList(), completion(equals([1, 2, 3]))); + ''').stream.toList(), + completion(equals([1, 2, 3])), + ); }); }); } diff --git a/integration_tests/spawn_hybrid/test/hybrid_test_io.dart b/integration_tests/spawn_hybrid/test/hybrid_test_io.dart index 0e454db19..512fc4be6 100644 --- a/integration_tests/spawn_hybrid/test/hybrid_test_io.dart +++ b/integration_tests/spawn_hybrid/test/hybrid_test_io.dart @@ -38,10 +38,12 @@ void main() { test('spawnHybridUri(): supports absolute file: URIs', () async { expect( - spawnHybridUri(p.toUri(p.absolute( - p.relative(p.join('test', 'util', 'emits_numbers.dart'))))) - .stream - .toList(), - completion(equals([1, 2, 3]))); + spawnHybridUri( + p.toUri( + p.absolute(p.relative(p.join('test', 'util', 'emits_numbers.dart'))), + ), + ).stream.toList(), + completion(equals([1, 2, 3])), + ); }); } diff --git a/integration_tests/spawn_hybrid/test/subdir/hybrid_test.dart b/integration_tests/spawn_hybrid/test/subdir/hybrid_test.dart index 088375cf4..9937f27d1 100644 --- a/integration_tests/spawn_hybrid/test/subdir/hybrid_test.dart +++ b/integration_tests/spawn_hybrid/test/subdir/hybrid_test.dart @@ -11,10 +11,9 @@ void main() { group('spawnHybridUri():', () { test('loads uris relative to the test file', () async { expect( - spawnHybridUri(Uri.parse('../util/emits_numbers.dart')) - .stream - .toList(), - completion(equals([1, 2, 3]))); + spawnHybridUri(Uri.parse('../util/emits_numbers.dart')).stream.toList(), + completion(equals([1, 2, 3])), + ); }); }); } diff --git a/pkgs/checks/example/example.dart b/pkgs/checks/example/example.dart index 88bec0b56..98b7f9fa3 100644 --- a/pkgs/checks/example/example.dart +++ b/pkgs/checks/example/example.dart @@ -16,9 +16,9 @@ void main() { final someString = 'abcdefghijklmnopqrstuvwxyz'; check( - because: 'it should contain the beginning, middle and end', - someString, - ) + because: 'it should contain the beginning, middle and end', + someString, + ) ..startsWith('a') ..endsWith('z') ..contains('lmno'); diff --git a/pkgs/checks/lib/src/checks.dart b/pkgs/checks/lib/src/checks.dart index e1e4bcb7e..cc8359fb6 100644 --- a/pkgs/checks/lib/src/checks.dart +++ b/pkgs/checks/lib/src/checks.dart @@ -76,25 +76,31 @@ extension SkipExtension on Subject { /// check(actual).equals(expected); /// ``` @meta.useResult -Subject check(T value, {String? because}) => Subject._(_TestContext._root( - value: _Present(value), - // TODO - switch between "a" and "an" - label: 'a $T', - fail: (f) { - final which = f.rejection.which; - throw TestFailure([ +Subject check(T value, {String? because}) => Subject._( + _TestContext._root( + value: _Present(value), + // TODO - switch between "a" and "an" + label: 'a $T', + fail: (f) { + final which = f.rejection.which; + throw TestFailure( + [ ...prefixFirst('Expected: ', f.detail.expected), ...prefixFirst('Actual: ', f.detail.actual), ...indent( - prefixFirst('Actual: ', f.rejection.actual), f.detail.depth), + prefixFirst('Actual: ', f.rejection.actual), + f.detail.depth, + ), if (which != null && which.isNotEmpty) ...indent(prefixFirst('Which: ', which), f.detail.depth), if (because != null) 'Reason: $because', - ].join('\n')); - }, - allowAsync: true, - allowUnawaited: true, - )); + ].join('\n'), + ); + }, + allowAsync: true, + allowUnawaited: true, + ), +); /// Checks whether [value] satisfies all expectations invoked in [condition], /// without throwing an exception. @@ -106,14 +112,16 @@ Subject check(T value, {String? because}) => Subject._(_TestContext._root( /// runtime error if they are used. CheckFailure? softCheck(T value, Condition condition) { CheckFailure? failure; - final subject = Subject._(_TestContext._root( - value: _Present(value), - fail: (f) { - failure ??= f; - }, - allowAsync: false, - allowUnawaited: false, - )); + final subject = Subject._( + _TestContext._root( + value: _Present(value), + fail: (f) { + failure ??= f; + }, + allowAsync: false, + allowUnawaited: false, + ), + ); condition(subject); return failure; } @@ -128,16 +136,20 @@ CheckFailure? softCheck(T value, Condition condition) { /// In contrast to [softCheck], asynchronous expectations are allowed in /// [condition]. Future softCheckAsync( - T value, AsyncCondition condition) async { + T value, + AsyncCondition condition, +) async { CheckFailure? failure; - final subject = Subject._(_TestContext._root( - value: _Present(value), - fail: (f) { - failure ??= f; - }, - allowAsync: true, - allowUnawaited: false, - )); + final subject = Subject._( + _TestContext._root( + value: _Present(value), + fail: (f) { + failure ??= f; + }, + allowAsync: true, + allowUnawaited: false, + ), + ); await condition(subject); return failure; } @@ -409,7 +421,9 @@ abstract final class Context { /// } /// ``` void expect( - Iterable Function() clause, Rejection? Function(T) predicate); + Iterable Function() clause, + Rejection? Function(T) predicate, + ); /// Expect that [predicate] will not result in a [Rejection] for the checked /// value. @@ -433,8 +447,10 @@ abstract final class Context { /// } /// } /// ``` - Future expectAsync(Iterable Function() clause, - FutureOr Function(T) predicate); + Future expectAsync( + Iterable Function() clause, + FutureOr Function(T) predicate, + ); /// Expect that [predicate] will not invoke the passed callback with a /// [Rejection] at any point. @@ -471,8 +487,10 @@ abstract final class Context { /// }); /// } /// ``` - void expectUnawaited(Iterable Function() clause, - void Function(T, void Function(Rejection)) predicate); + void expectUnawaited( + Iterable Function() clause, + void Function(T, void Function(Rejection)) predicate, + ); /// Extract a property from the value for further checking. /// @@ -511,8 +529,10 @@ abstract final class Context { /// }); /// ``` Subject nest( - Iterable Function() label, Extracted Function(T) extract, - {bool atSameLevel = false}); + Iterable Function() label, + Extracted Function(T) extract, { + bool atSameLevel = false, + }); /// Extract an asynchronous property from the value for further checking. /// @@ -544,9 +564,10 @@ abstract final class Context { /// } /// ``` Future nestAsync( - Iterable Function() label, - FutureOr> Function(T) extract, - AsyncCondition? nestedCondition); + Iterable Function() label, + FutureOr> Function(T) extract, + AsyncCondition? nestedCondition, + ); } /// A property extracted from a value being checked, or a rejection. @@ -559,10 +580,11 @@ final class Extracted { /// /// When a nesting is rejected with an omitted or empty [actual] argument, it /// will be filled in with the [literal] representation of the value. - Extracted.rejection( - {Iterable actual = const [], Iterable? which}) - : _rejection = Rejection(actual: actual, which: which), - _value = null; + Extracted.rejection({ + Iterable actual = const [], + Iterable? which, + }) : _rejection = Rejection(actual: actual, which: which), + _value = null; Extracted.value(T this._value) : _rejection = null; Extracted._(Rejection this._rejection) : _value = null; @@ -573,16 +595,20 @@ final class Extracted { return Extracted.value(transform(_value as T)); } - Extracted _fillActual(Object? actual) => _rejection == null || - _rejection.actual.isNotEmpty - ? this - : Extracted.rejection(actual: literal(actual), which: _rejection.which); + Extracted _fillActual(Object? actual) => + _rejection == null || _rejection.actual.isNotEmpty + ? this + : Extracted.rejection( + actual: literal(actual), + which: _rejection.which, + ); } abstract interface class _Optional { R? apply>(R Function(T) callback); Future>> mapAsync( - FutureOr> Function(T) transform); + FutureOr> Function(T) transform, + ); Extracted<_Optional> map(Extracted Function(T) transform); } @@ -595,7 +621,8 @@ class _Present implements _Optional { @override Future>> mapAsync( - FutureOr> Function(T) transform) async { + FutureOr> Function(T) transform, + ) async { final transformed = await transform(value); return transformed._map(_Present.new); } @@ -611,8 +638,8 @@ class _Absent implements _Optional { @override Future>> mapAsync( - FutureOr> Function(T) transform) async => - Extracted.value(_Absent()); + FutureOr> Function(T) transform, + ) async => Extracted.value(_Absent()); @override Extracted<_Absent> map(FutureOr> Function(T) transform) => @@ -667,60 +694,67 @@ final class _TestContext implements Context, _ClauseDescription { required bool allowAsync, required bool allowUnawaited, String? label, - }) : _value = value, - _label = (() => [label ?? '']), - _fail = fail, - _allowAsync = allowAsync, - _allowUnawaited = allowUnawaited, - _parent = null, - _clauses = [], - _aliases = []; + }) : _value = value, + _label = (() => [label ?? '']), + _fail = fail, + _allowAsync = allowAsync, + _allowUnawaited = allowUnawaited, + _parent = null, + _clauses = [], + _aliases = []; _TestContext._alias(_TestContext original, this._value) - : _parent = original, - _clauses = original._clauses, - _aliases = original._aliases, - _fail = original._fail, - _allowAsync = original._allowAsync, - _allowUnawaited = original._allowUnawaited, - // Never read from an aliased context because they are never present in - // `_clauses`. - _label = _emptyLabel; + : _parent = original, + _clauses = original._clauses, + _aliases = original._aliases, + _fail = original._fail, + _allowAsync = original._allowAsync, + _allowUnawaited = original._allowUnawaited, + // Never read from an aliased context because they are never present in + // `_clauses`. + _label = _emptyLabel; /// Create a context nested under [parent]. /// /// The [_label] callback should not return an empty iterable. _TestContext._child(this._value, this._label, _TestContext parent) - : _parent = parent, - _fail = parent._fail, - _allowAsync = parent._allowAsync, - _allowUnawaited = parent._allowUnawaited, - _clauses = [], - _aliases = []; + : _parent = parent, + _fail = parent._fail, + _allowAsync = parent._allowAsync, + _allowUnawaited = parent._allowUnawaited, + _clauses = [], + _aliases = []; @override void expect( - Iterable Function() clause, Rejection? Function(T) predicate) { + Iterable Function() clause, + Rejection? Function(T) predicate, + ) { _clauses.add(_ExpectationClause(clause)); - final rejection = - _value.apply((actual) => predicate(actual)?._fillActual(actual)); + final rejection = _value.apply( + (actual) => predicate(actual)?._fillActual(actual), + ); if (rejection != null) { _fail(_failure(rejection)); } } @override - Future expectAsync(Iterable Function() clause, - FutureOr Function(T) predicate) async { + Future expectAsync( + Iterable Function() clause, + FutureOr Function(T) predicate, + ) async { if (!_allowAsync) { throw StateError( - 'Async expectations cannot be used on a synchronous subject'); + 'Async expectations cannot be used on a synchronous subject', + ); } _clauses.add(_ExpectationClause(clause)); final outstandingWork = TestHandle.current.markPending(); try { final rejection = await _value.apply( - (actual) async => (await predicate(actual))?._fillActual(actual)); + (actual) async => (await predicate(actual))?._fillActual(actual), + ); if (rejection == null) return; _fail(_failure(rejection)); } finally { @@ -729,8 +763,10 @@ final class _TestContext implements Context, _ClauseDescription { } @override - void expectUnawaited(Iterable Function() clause, - void Function(T actual, void Function(Rejection) reject) predicate) { + void expectUnawaited( + Iterable Function() clause, + void Function(T actual, void Function(Rejection) reject) predicate, + ) { if (!_allowUnawaited) { throw StateError('Late expectations cannot be used for soft checks'); } @@ -742,8 +778,10 @@ final class _TestContext implements Context, _ClauseDescription { @override Subject nest( - Iterable Function() label, Extracted Function(T) extract, - {bool atSameLevel = false}) { + Iterable Function() label, + Extracted Function(T) extract, { + bool atSameLevel = false, + }) { final result = _value.map((actual) => extract(actual)._fillActual(actual)); final rejection = result._rejection; if (rejection != null) { @@ -765,17 +803,20 @@ final class _TestContext implements Context, _ClauseDescription { @override Future nestAsync( - Iterable Function() label, - FutureOr> Function(T) extract, - AsyncCondition? nestedCondition) async { + Iterable Function() label, + FutureOr> Function(T) extract, + AsyncCondition? nestedCondition, + ) async { if (!_allowAsync) { throw StateError( - 'Async expectations cannot be used on a synchronous subject'); + 'Async expectations cannot be used on a synchronous subject', + ); } final outstandingWork = TestHandle.current.markPending(); try { final result = await _value.mapAsync( - (actual) async => (await extract(actual))._fillActual(actual)); + (actual) async => (await extract(actual))._fillActual(actual), + ); final rejection = result._rejection; if (rejection != null) { _clauses.add(_ExpectationClause(label)); @@ -836,34 +877,43 @@ final class _TestContext implements Context, _ClauseDescription { final class _SkippedContext implements Context { @override void expect( - Iterable Function() clause, Rejection? Function(T) predicate) { + Iterable Function() clause, + Rejection? Function(T) predicate, + ) { // no-op } @override - Future expectAsync(Iterable Function() clause, - FutureOr Function(T) predicate) async { + Future expectAsync( + Iterable Function() clause, + FutureOr Function(T) predicate, + ) async { // no-op } @override - void expectUnawaited(Iterable Function() clause, - void Function(T actual, void Function(Rejection) reject) predicate) { + void expectUnawaited( + Iterable Function() clause, + void Function(T actual, void Function(Rejection) reject) predicate, + ) { // no-op } @override Subject nest( - Iterable Function() label, Extracted Function(T p1) extract, - {bool atSameLevel = false}) { + Iterable Function() label, + Extracted Function(T p1) extract, { + bool atSameLevel = false, + }) { return Subject._(_SkippedContext()); } @override Future nestAsync( - Iterable Function() label, - FutureOr> Function(T p1) extract, - AsyncCondition? nestedCondition) async { + Iterable Function() label, + FutureOr> Function(T p1) extract, + AsyncCondition? nestedCondition, + ) async { // no-op } } @@ -1001,9 +1051,10 @@ final class Rejection { /// the output for the failure message. final Iterable? which; - Rejection _fillActual(Object? value) => actual.isNotEmpty - ? this - : Rejection(actual: literal(value), which: which); + Rejection _fillActual(Object? value) => + actual.isNotEmpty + ? this + : Rejection(actual: literal(value), which: which); Rejection({this.actual = const [], this.which}); } diff --git a/pkgs/checks/lib/src/collection_equality.dart b/pkgs/checks/lib/src/collection_equality.dart index da6064a52..6adf4d4fd 100644 --- a/pkgs/checks/lib/src/collection_equality.dart +++ b/pkgs/checks/lib/src/collection_equality.dart @@ -60,7 +60,10 @@ const _maxDepth = 1000; class _ExceededDepthError extends Error {} Iterable? _deepCollectionEquals( - Object actual, Object expected, int depth) { + Object actual, + Object expected, + int depth, +) { assert(actual is Iterable || actual is Map); assert(expected is Iterable || expected is Map); @@ -74,56 +77,88 @@ Iterable? _deepCollectionEquals( Iterable? rejectionWhich; if (currentExpected is Set) { rejectionWhich = _findSetDifference( - currentActual, currentExpected, path, currentDepth); + currentActual, + currentExpected, + path, + currentDepth, + ); } else if (currentExpected is Iterable) { rejectionWhich = _findIterableDifference( - currentActual, currentExpected, path, queue, currentDepth); + currentActual, + currentExpected, + path, + queue, + currentDepth, + ); } else { currentExpected as Map; rejectionWhich = _findMapDifference( - currentActual, currentExpected, path, queue, currentDepth); + currentActual, + currentExpected, + path, + queue, + currentDepth, + ); } if (rejectionWhich != null) return rejectionWhich; } return null; } -List? _findIterableDifference(Object? actual, - Iterable expected, _Path path, Queue<_Search> queue, int depth) { +List? _findIterableDifference( + Object? actual, + Iterable expected, + _Path path, + Queue<_Search> queue, + int depth, +) { if (actual is! Iterable) { return ['${path}is not an Iterable']; } var actualIterator = actual.iterator; var expectedIterator = expected.iterator; - for (var index = 0;; index++) { + for (var index = 0; ; index++) { var actualNext = actualIterator.moveNext(); var expectedNext = expectedIterator.moveNext(); if (!expectedNext && !actualNext) break; if (!expectedNext) { return [ '${path}has more elements than expected', - 'expected an iterable with $index element(s)' + 'expected an iterable with $index element(s)', ]; } if (!actualNext) { return [ '${path}has too few elements', - 'expected an iterable with at least ${index + 1} element(s)' + 'expected an iterable with at least ${index + 1} element(s)', ]; } - final difference = _compareValue(actualIterator.current, - expectedIterator.current, path, index, queue, depth); + final difference = _compareValue( + actualIterator.current, + expectedIterator.current, + path, + index, + queue, + depth, + ); if (difference != null) return difference; } return null; } -List? _compareValue(Object? actualValue, Object? expectedValue, - _Path path, Object? pathAppend, Queue<_Search> queue, int depth) { +List? _compareValue( + Object? actualValue, + Object? expectedValue, + _Path path, + Object? pathAppend, + Queue<_Search> queue, + int depth, +) { if (expectedValue is Iterable || expectedValue is Map) { if (depth + 1 > _maxDepth) throw _ExceededDepthError(); - queue.addLast(_Search( - path.append(pathAppend), actualValue, expectedValue, depth + 1)); + queue.addLast( + _Search(path.append(pathAppend), actualValue, expectedValue, depth + 1), + ); } else if (expectedValue is Condition) { final failure = softCheck(actualValue, expectedValue); if (failure != null) { @@ -131,17 +166,19 @@ List? _compareValue(Object? actualValue, Object? expectedValue, return [ 'has an element ${path.append(pathAppend)}that:', ...indent(failure.detail.actual.skip(1)), - ...indent(prefixFirst('Actual: ', failure.rejection.actual), - failure.detail.depth + 1), + ...indent( + prefixFirst('Actual: ', failure.rejection.actual), + failure.detail.depth + 1, + ), if (which != null) - ...indent(prefixFirst('which ', which), failure.detail.depth + 1) + ...indent(prefixFirst('which ', which), failure.detail.depth + 1), ]; } } else { if (actualValue != expectedValue) { return [ ...prefixFirst('${path.append(pathAppend)}is ', literal(actualValue)), - ...prefixFirst('which does not equal ', literal(expectedValue)) + ...prefixFirst('which does not equal ', literal(expectedValue)), ]; } } @@ -162,7 +199,11 @@ bool _elementMatches(Object? actual, Object? expected, int depth) { } Iterable? _findSetDifference( - Object? actual, Set expected, _Path path, int depth) { + Object? actual, + Set expected, + _Path path, + int depth, +) { if (actual is! Set) { return ['${path}is not a Set']; } @@ -182,16 +223,18 @@ Iterable? _findSetDifference( } Iterable? _findMapDifference( - Object? actual, - Map expected, - _Path path, - Queue<_Search> queue, - int depth) { + Object? actual, + Map expected, + _Path path, + Queue<_Search> queue, + int depth, +) { if (actual is! Map) { return ['${path}is not a Map']; } - if (expected.keys - .any((key) => key is Condition || key is Iterable || key is Map)) { + if (expected.keys.any( + (key) => key is Condition || key is Iterable || key is Map, + )) { return _findAmbiguousMapDifference(actual, expected, path, depth); } else { return _findUnambiguousMapDifference(actual, expected, path, queue, depth); @@ -204,7 +247,7 @@ Iterable _describeEntry(MapEntry entry) { return [ ...key.take(key.length - 1), '${key.last}: ${value.first}', - ...value.skip(1) + ...value.skip(1), ]; } @@ -212,59 +255,72 @@ Iterable _describeEntry(MapEntry entry) { /// when [expected] has only direct key values and there is a 1:1 mapping /// between an expected value and a checked value in the map. Iterable? _findUnambiguousMapDifference( - Map actual, - Map expected, - _Path path, - Queue<_Search> queue, - int depth) { + Map actual, + Map expected, + _Path path, + Queue<_Search> queue, + int depth, +) { for (final entry in expected.entries) { assert(entry.key is! Condition); assert(entry.key is! Iterable); assert(entry.key is! Map); if (!actual.containsKey(entry.key)) { return prefixFirst( - '${path}has no key matching expected entry ', _describeEntry(entry)); + '${path}has no key matching expected entry ', + _describeEntry(entry), + ); } final difference = _compareValue( - actual[entry.key], entry.value, path, entry.key, queue, depth); + actual[entry.key], + entry.value, + path, + entry.key, + queue, + depth, + ); if (difference != null) return difference; } for (final entry in actual.entries) { if (!expected.containsKey(entry.key)) { return prefixFirst( - '${path}has an unexpected key for entry ', _describeEntry(entry)); + '${path}has an unexpected key for entry ', + _describeEntry(entry), + ); } } return null; } -Iterable? _findAmbiguousMapDifference(Map actual, - Map expected, _Path path, int depth) => - unorderedCompare( - actual.entries, - expected.entries, - (actual, expected) => - _elementMatches(actual.key, expected.key, depth) && - _elementMatches(actual.value, expected.value, depth), - (expectedEntry, _, count) => [ - ...prefixFirst( - '${path}has no entry to match ', _describeEntry(expectedEntry)), - if (count > 1) 'or ${count - 1} other entries', - ], - (actualEntry, _, count) => [ - ...prefixFirst( - '${path}has unexpected entry ', _describeEntry(actualEntry)), - if (count > 1) 'and ${count - 1} other unexpected entries', - ], - ); +Iterable? _findAmbiguousMapDifference( + Map actual, + Map expected, + _Path path, + int depth, +) => unorderedCompare( + actual.entries, + expected.entries, + (actual, expected) => + _elementMatches(actual.key, expected.key, depth) && + _elementMatches(actual.value, expected.value, depth), + (expectedEntry, _, count) => [ + ...prefixFirst( + '${path}has no entry to match ', + _describeEntry(expectedEntry), + ), + if (count > 1) 'or ${count - 1} other entries', + ], + (actualEntry, _, count) => [ + ...prefixFirst('${path}has unexpected entry ', _describeEntry(actualEntry)), + if (count > 1) 'and ${count - 1} other unexpected entries', + ], +); class _Path { final _Path? parent; final Object? index; _Path._(this.parent, this.index); - _Path.root() - : parent = null, - index = ''; + _Path.root() : parent = null, index = ''; _Path append(Object? index) => _Path._(this, index); @override @@ -312,11 +368,12 @@ class _Search { /// elements which compare as equal the runtime can reach /// `O((|actual| + |expected|)^2.5)`. Iterable? unorderedCompare( - Iterable actual, - Iterable expected, - bool Function(T, E) elementsEqual, - Iterable Function(E, int index, int count) unmatchedExpected, - Iterable Function(T, int index, int count) unmatchedActual) { + Iterable actual, + Iterable expected, + bool Function(T, E) elementsEqual, + Iterable Function(E, int index, int count) unmatchedExpected, + Iterable Function(T, int index, int count) unmatchedActual, +) { final indexedExpected = expected.toList(); final indexedActual = actual.toList(); final adjacency = >[]; @@ -324,7 +381,7 @@ Iterable? unorderedCompare( final expectedElement = indexedExpected[i]; final pairs = [ for (var j = 0; j < indexedActual.length; j++) - if (elementsEqual(indexedActual[j], expectedElement)) j + if (elementsEqual(indexedActual[j], expectedElement)) j, ]; adjacency.add(pairs); } @@ -332,12 +389,18 @@ Iterable? unorderedCompare( if (unpaired.first.isNotEmpty) { final firstUnmatched = indexedExpected[unpaired.first.first]; return unmatchedExpected( - firstUnmatched, unpaired.first.first, unpaired.first.length); + firstUnmatched, + unpaired.first.first, + unpaired.first.length, + ); } if (unpaired.last.isNotEmpty) { final firstUnmatched = indexedActual[unpaired.last.first]; return unmatchedActual( - firstUnmatched, unpaired.last.first, unpaired.last.length); + firstUnmatched, + unpaired.last.first, + unpaired.last.length, + ); } return null; } @@ -421,11 +484,11 @@ List> _findUnpaired(List> adjacency, int rightVertexCount) { return [ [ for (int i = 0; i < leftLength; i++) - if (leftPairs[i] == rightLength) i + if (leftPairs[i] == rightLength) i, ], [ for (int i = 0; i < rightLength; i++) - if (rightPairs[i] == leftLength) i - ] + if (rightPairs[i] == leftLength) i, + ], ]; } diff --git a/pkgs/checks/lib/src/describe.dart b/pkgs/checks/lib/src/describe.dart index 910e4c3e4..6700af6bc 100644 --- a/pkgs/checks/lib/src/describe.dart +++ b/pkgs/checks/lib/src/describe.dart @@ -20,7 +20,11 @@ const _maxLineLength = 80; const _maxItems = 25; Iterable _prettyPrint( - Object? object, int indentSize, Set seen, bool isTopLevel) { + Object? object, + int indentSize, + Set seen, + bool isTopLevel, +) { if (seen.contains(object)) return ['(recursive)']; seen = seen.union({object}); Iterable prettyPrintNested(Object? child) => @@ -40,26 +44,36 @@ Iterable _prettyPrint( } final elements = object.map(prettyPrintNested).toList(); return _prettyPrintCollection( - open, close, elements, _maxLineLength - indentSize); + open, + close, + elements, + _maxLineLength - indentSize, + ); } else if (object is Map) { - final entries = object.entries.map((entry) { - final key = prettyPrintNested(entry.key); - final value = prettyPrintNested(entry.value); - return [ - ...key.take(key.length - 1), - '${key.last}: ${value.first}', - ...value.skip(1) - ]; - }).toList(); + final entries = + object.entries.map((entry) { + final key = prettyPrintNested(entry.key); + final value = prettyPrintNested(entry.value); + return [ + ...key.take(key.length - 1), + '${key.last}: ${value.first}', + ...value.skip(1), + ]; + }).toList(); return _prettyPrintCollection( - '{', '}', entries, _maxLineLength - indentSize); + '{', + '}', + entries, + _maxLineLength - indentSize, + ); } else if (object is String) { if (object.isEmpty) return ["''"]; - final escaped = const LineSplitter() - .convert(object) - .map(escape) - .map((line) => line.replaceAll("'", r"\'")) - .toList(); + final escaped = + const LineSplitter() + .convert(object) + .map(escape) + .map((line) => line.replaceAll("'", r"\'")) + .toList(); return prefixFirst("'", postfixLast("'", escaped)); } else if (object is Condition) { return ['', describe(object))]; @@ -70,10 +84,14 @@ Iterable _prettyPrint( } Iterable _prettyPrintCollection( - String open, String close, List> elements, int maxLength) { + String open, + String close, + List> elements, + int maxLength, +) { if (elements.length > _maxItems) { const ellipsisElement = [ - ['...'] + ['...'], ]; elements.replaceRange(_maxItems - 1, elements.length, ellipsisElement); } @@ -144,7 +162,8 @@ String escape(String output) { /// A [RegExp] that matches whitespace characters that should be escaped. final _escapeRegExp = RegExp( - '[\\x00-\\x07\\x0E-\\x1F${_escapeMap.keys.map(_hexLiteral).join()}]'); + '[\\x00-\\x07\\x0E-\\x1F${_escapeMap.keys.map(_hexLiteral).join()}]', +); /// A [Map] between whitespace characters and their escape sequences. const _escapeMap = { diff --git a/pkgs/checks/lib/src/extensions/async.dart b/pkgs/checks/lib/src/extensions/async.dart index 9d9e85a47..0a56295ee 100644 --- a/pkgs/checks/lib/src/extensions/async.dart +++ b/pkgs/checks/lib/src/extensions/async.dart @@ -23,12 +23,13 @@ extension FutureChecks on Subject> { try { return Extracted.value(await actual); } catch (e, st) { - return Extracted.rejection(actual: [ - 'a future that completes as an error' - ], which: [ - ...prefixFirst('threw ', postfixLast(' at:', literal(e))), - ...const LineSplitter().convert(st.toString()) - ]); + return Extracted.rejection( + actual: ['a future that completes as an error'], + which: [ + ...prefixFirst('threw ', postfixLast(' at:', literal(e))), + ...const LineSplitter().convert(st.toString()), + ], + ); } }, completionCondition); } @@ -44,17 +45,28 @@ extension FutureChecks on Subject> { /// concrete end point where this condition has definitely succeeded. void doesNotComplete() { context.expectUnawaited(() => ['does not complete'], (actual, reject) { - unawaited(actual.then((r) { - reject(Rejection( - actual: prefixFirst('a future that completed to ', literal(r)))); - }, onError: (Object e, StackTrace st) { - reject(Rejection(actual: [ - 'a future that completed as an error:' - ], which: [ - ...prefixFirst('threw ', literal(e)), - ...const LineSplitter().convert(st.toString()) - ])); - })); + unawaited( + actual.then( + (r) { + reject( + Rejection( + actual: prefixFirst('a future that completed to ', literal(r)), + ), + ); + }, + onError: (Object e, StackTrace st) { + reject( + Rejection( + actual: ['a future that completed as an error:'], + which: [ + ...prefixFirst('threw ', literal(e)), + ...const LineSplitter().convert(st.toString()), + ], + ), + ); + }, + ), + ); }); } @@ -67,26 +79,31 @@ extension FutureChecks on Subject> { /// /// The returned future will complete when the subject future has completed, /// and [errorCondition] has optionally been checked. - Future throws( - [AsyncCondition? errorCondition]) async { + Future throws([ + AsyncCondition? errorCondition, + ]) async { await context.nestAsync( - () => ['completes to an error${E == Object ? '' : ' of type $E'}'], - (actual) async { - try { - return Extracted.rejection( + () => ['completes to an error${E == Object ? '' : ' of type $E'}'], + (actual) async { + try { + return Extracted.rejection( actual: prefixFirst('completed to ', literal(await actual)), - which: ['did not throw']); - } on E catch (e) { - return Extracted.value(e); - } catch (e, st) { - return Extracted.rejection( + which: ['did not throw'], + ); + } on E catch (e) { + return Extracted.value(e); + } catch (e, st) { + return Extracted.rejection( actual: prefixFirst('completed to error ', literal(e)), which: [ 'threw an exception that is not a $E at:', - ...const LineSplitter().convert(st.toString()) - ]); - } - }, errorCondition); + ...const LineSplitter().convert(st.toString()), + ], + ); + } + }, + errorCondition, + ); } } @@ -98,19 +115,20 @@ extension StreamChecks on Subject> { /// Calls [Context.expectAsync] and wraps [predicate] with a transaction. /// /// The transaction is committed if the check passes, or rejected if it fails. - Future _expectAsync(Iterable Function() clause, - FutureOr Function(StreamQueue) predicate) => - context.expectAsync(clause, (actual) async { - final transaction = actual.startTransaction(); - final copy = transaction.newQueue(); - final result = await predicate(copy); - if (result == null) { - transaction.commit(copy); - } else { - transaction.reject(); - } - return result; - }); + Future _expectAsync( + Iterable Function() clause, + FutureOr Function(StreamQueue) predicate, + ) => context.expectAsync(clause, (actual) async { + final transaction = actual.startTransaction(); + final copy = transaction.newQueue(); + final result = await predicate(copy); + if (result == null) { + transaction.commit(copy); + } else { + transaction.reject(); + } + return result; + }); /// Expect that the `Stream` emits a value without first emitting an error. /// @@ -130,19 +148,21 @@ extension StreamChecks on Subject> { await context.nestAsync(() => ['emits a value'], (actual) async { if (!await actual.hasNext) { return Extracted.rejection( - actual: ['a stream'], - which: ['closed without emitting enough values']); + actual: ['a stream'], + which: ['closed without emitting enough values'], + ); } try { await actual.peek; return Extracted.value(await actual.next); } catch (e, st) { return Extracted.rejection( - actual: prefixFirst('a stream with error ', literal(e)), - which: [ - 'emitted an error instead of a value at:', - ...const LineSplitter().convert(st.toString()) - ]); + actual: prefixFirst('a stream with error ', literal(e)), + which: [ + 'emitted an error instead of a value at:', + ...const LineSplitter().convert(st.toString()), + ], + ); } }, emittedCondition); } @@ -162,33 +182,39 @@ extension StreamChecks on Subject> { /// /// The returned future will complete when the stream has emitted, errored, or /// ended, and the [errorCondition] has optionally been checked. - Future emitsError( - [AsyncCondition? errorCondition]) async { + Future emitsError([ + AsyncCondition? errorCondition, + ]) async { await context.nestAsync( - () => ['emits an error${E == Object ? '' : ' of type $E'}'], - (actual) async { - if (!await actual.hasNext) { - return Extracted.rejection( + () => ['emits an error${E == Object ? '' : ' of type $E'}'], + (actual) async { + if (!await actual.hasNext) { + return Extracted.rejection( actual: ['a stream'], - which: ['closed without emitting an expected error']); - } - try { - final value = await actual.peek; - return Extracted.rejection( + which: ['closed without emitting an expected error'], + ); + } + try { + final value = await actual.peek; + return Extracted.rejection( actual: prefixFirst('a stream emitting value ', literal(value)), - which: ['closed without emitting an error']); - } on E catch (e) { - await actual.next.then((_) {}, onError: (_) {}); - return Extracted.value(e); - } catch (e, st) { - return Extracted.rejection( + which: ['closed without emitting an error'], + ); + } on E catch (e) { + await actual.next.then((_) {}, onError: (_) {}); + return Extracted.value(e); + } catch (e, st) { + return Extracted.rejection( actual: prefixFirst('a stream with error ', literal(e)), which: [ 'emitted an error which is not $E at:', - ...const LineSplitter().convert(st.toString()) - ]); - } - }, errorCondition); + ...const LineSplitter().convert(st.toString()), + ], + ); + } + }, + errorCondition, + ); } /// Expects that the `Stream` emits any number of events before emitting an @@ -206,21 +232,24 @@ extension StreamChecks on Subject> { /// events. Future emitsThrough(AsyncCondition condition) async { await _expectAsync( - () => [ - 'emits any values then emits a value that:', - ...describe(condition) - ], (actual) async { - var count = 0; - while (await actual.hasNext) { - if (softCheck(await actual.next, condition) == null) { - return null; + () => [ + 'emits any values then emits a value that:', + ...describe(condition), + ], + (actual) async { + var count = 0; + while (await actual.hasNext) { + if (softCheck(await actual.next, condition) == null) { + return null; + } + count++; } - count++; - } - return Rejection( + return Rejection( actual: ['a stream'], - which: ['ended after emitting $count elements with none matching']); - }); + which: ['ended after emitting $count elements with none matching'], + ); + }, + ); } /// Expects that the stream satisfies each condition in [conditions] serially. @@ -241,41 +270,54 @@ extension StreamChecks on Subject> { /// If this expectation succeeds, consumes as many events from the source /// stream as are consumed by all the conditions. Future inOrder( - Iterable>> conditions) async { + Iterable>> conditions, + ) async { conditions = conditions.toList(); final descriptions = []; await _expectAsync( - () => descriptions.isEmpty - ? ['satisfies ${conditions.length} conditions in order'] - : descriptions, (actual) async { - var satisfiedCount = 0; - for (var condition in conditions) { - descriptions.addAll(await describeAsync(condition)); - final failure = await softCheckAsync(actual, condition); - if (failure != null) { - final which = failure.rejection.which; - return Rejection(actual: [ - 'a stream' - ], which: [ - if (satisfiedCount > 0) 'satisfied $satisfiedCount conditions then', - 'failed to satisfy the condition at index $satisfiedCount', - if (failure.detail.depth > 0) ...[ - 'because it:', - ...indent( - failure.detail.actual.skip(1), failure.detail.depth - 1), - ...indent(prefixFirst('Actual: ', failure.rejection.actual), - failure.detail.depth), - if (which != null) - ...indent(prefixFirst('Which: ', which), failure.detail.depth), - ] else ...[ - if (which != null) ...prefixFirst('because it ', which), - ], - ]); + () => + descriptions.isEmpty + ? ['satisfies ${conditions.length} conditions in order'] + : descriptions, + (actual) async { + var satisfiedCount = 0; + for (var condition in conditions) { + descriptions.addAll(await describeAsync(condition)); + final failure = await softCheckAsync(actual, condition); + if (failure != null) { + final which = failure.rejection.which; + return Rejection( + actual: ['a stream'], + which: [ + if (satisfiedCount > 0) + 'satisfied $satisfiedCount conditions then', + 'failed to satisfy the condition at index $satisfiedCount', + if (failure.detail.depth > 0) ...[ + 'because it:', + ...indent( + failure.detail.actual.skip(1), + failure.detail.depth - 1, + ), + ...indent( + prefixFirst('Actual: ', failure.rejection.actual), + failure.detail.depth, + ), + if (which != null) + ...indent( + prefixFirst('Which: ', which), + failure.detail.depth, + ), + ] else ...[ + if (which != null) ...prefixFirst('because it ', which), + ], + ], + ); + } + satisfiedCount++; } - satisfiedCount++; - } - return null; - }); + return null; + }, + ); } /// Expects that the stream statisfies at least one condition from @@ -287,74 +329,82 @@ extension StreamChecks on Subject> { /// queue as the satisfied condition. If multiple conditions are satisfied, /// chooses the condition which consumed the most events. Future anyOf( - Iterable>> conditions) async { + Iterable>> conditions, + ) async { conditions = conditions.toList(); if (conditions.isEmpty) { throw ArgumentError('conditions may not be empty'); } final descriptions = >[]; await context.expectAsync( - () => descriptions.isEmpty - ? ['satisfies any of ${conditions.length} conditions'] - : [ + () => + descriptions.isEmpty + ? ['satisfies any of ${conditions.length} conditions'] + : [ 'satisfies one of:', for (var i = 0; i < descriptions.length; i++) ...[ ...descriptions[i], - if (i < descriptions.length - 1) 'or,' - ] - ], (actual) async { - final transaction = actual.startTransaction(); - StreamQueue? longestAccepted; - final descriptionFuture = Future.wait(conditions.map(describeAsync)); - final failures = await Future.wait(conditions.map((condition) async { - final copy = transaction.newQueue(); - final failure = await softCheckAsync(copy, condition); - if (failure == null && - (longestAccepted == null || - copy.eventsDispatched > longestAccepted!.eventsDispatched)) { - longestAccepted = copy; + if (i < descriptions.length - 1) 'or,', + ], + ], + (actual) async { + final transaction = actual.startTransaction(); + StreamQueue? longestAccepted; + final descriptionFuture = Future.wait(conditions.map(describeAsync)); + final failures = await Future.wait( + conditions.map((condition) async { + final copy = transaction.newQueue(); + final failure = await softCheckAsync(copy, condition); + if (failure == null && + (longestAccepted == null || + copy.eventsDispatched > + longestAccepted!.eventsDispatched)) { + longestAccepted = copy; + } + return failure; + }), + ); + descriptions.addAll(await descriptionFuture); + if (longestAccepted != null) { + transaction.commit(longestAccepted!); + return null; } - return failure; - })); - descriptions.addAll(await descriptionFuture); - if (longestAccepted != null) { - transaction.commit(longestAccepted!); - return null; - } - transaction.reject(); - Iterable failureDetails(int index, CheckFailure? failure) { - final actual = failure!.rejection.actual; - final which = failure.rejection.which; - final detail = failure.detail; - final failed = 'failed the condition at index $index'; - if (detail.depth > 0) { - return [ - '$failed because it:', - ...indent(detail.actual.skip(1), detail.depth - 1), - ...indent(prefixFirst('Actual: ', actual), detail.depth), - if (which != null) - ...indent(prefixFirst('Which: ', which), detail.depth), - ]; - } else { - return [ - if (which == null) - failed - else ...[ + transaction.reject(); + Iterable failureDetails(int index, CheckFailure? failure) { + final actual = failure!.rejection.actual; + final which = failure.rejection.which; + final detail = failure.detail; + final failed = 'failed the condition at index $index'; + if (detail.depth > 0) { + return [ '$failed because it:', - ...indent(which), - ], - ]; + ...indent(detail.actual.skip(1), detail.depth - 1), + ...indent(prefixFirst('Actual: ', actual), detail.depth), + if (which != null) + ...indent(prefixFirst('Which: ', which), detail.depth), + ]; + } else { + return [ + if (which == null) + failed + else ...[ + '$failed because it:', + ...indent(which), + ], + ]; + } } - } - return Rejection(actual: [ - 'a stream' - ], which: [ - 'failed to satisfy any condition', - for (var i = 0; i < failures.length; i++) - ...failureDetails(i, failures[i]), - ]); - }); + return Rejection( + actual: ['a stream'], + which: [ + 'failed to satisfy any condition', + for (var i = 0; i < failures.length; i++) + ...failureDetails(i, failures[i]), + ], + ); + }, + ); } /// Expects that the stream closes without emitting any event that satisfies @@ -370,22 +420,24 @@ extension StreamChecks on Subject> { /// [condition] until the end of the stream. Future neverEmits(AsyncCondition condition) async { await _expectAsync( - () => ['never emits a value that:', ...describe(condition)], - (actual) async { - var count = 0; - await for (var emitted in actual.rest) { - if (softCheck(emitted, condition) == null) { - return Rejection(actual: [ - 'a stream' - ], which: [ - ...prefixFirst('emitted ', literal(emitted)), - if (count > 0) 'following $count other items' - ]); + () => ['never emits a value that:', ...describe(condition)], + (actual) async { + var count = 0; + await for (var emitted in actual.rest) { + if (softCheck(emitted, condition) == null) { + return Rejection( + actual: ['a stream'], + which: [ + ...prefixFirst('emitted ', literal(emitted)), + if (count > 0) 'following $count other items', + ], + ); + } + count++; } - count++; - } - return null; - }); + return null; + }, + ); } /// Optionally consumes an event that matches [condition] from the stream. @@ -395,20 +447,21 @@ extension StreamChecks on Subject> { /// If a non-matching event is emitted, no events are consumed. /// If a matching event is emitted, that event is consumed. Future mayEmit(AsyncCondition condition) async { - await context - .expectAsync(() => ['may emit a value that:', ...describe(condition)], - (actual) async { - if (!await actual.hasNext) return null; - try { - final value = await actual.peek; - if (softCheck(value, condition) == null) { - await actual.next; + await context.expectAsync( + () => ['may emit a value that:', ...describe(condition)], + (actual) async { + if (!await actual.hasNext) return null; + try { + final value = await actual.peek; + if (softCheck(value, condition) == null) { + await actual.next; + } + } catch (_) { + // Ignore an emitted error - it does not match he event. } - } catch (_) { - // Ignore an emitted error - it does not match he event. - } - return null; - }); + return null; + }, + ); } /// Optionally consumes events that match [condition] from the stream. @@ -420,23 +473,24 @@ extension StreamChecks on Subject> { /// - An error is emitted. /// - The stream closes. Future mayEmitMultiple(AsyncCondition condition) async { - await context - .expectAsync(() => ['may emit a value that:', ...describe(condition)], - (actual) async { - while (await actual.hasNext) { - try { - final value = await actual.peek; - if (softCheck(value, condition) == null) { - await actual.next; - } else { + await context.expectAsync( + () => ['may emit a value that:', ...describe(condition)], + (actual) async { + while (await actual.hasNext) { + try { + final value = await actual.peek; + if (softCheck(value, condition) == null) { + await actual.next; + } else { + return null; + } + } catch (_) { return null; } - } catch (_) { - return null; } - } - return null; - }); + return null; + }, + ); } /// Expects that the stream closes without emitting any events or errors. @@ -448,16 +502,20 @@ extension StreamChecks on Subject> { if (!await actual.hasNext) return null; try { return Rejection( - actual: ['a stream'], - which: prefixFirst( - 'emitted an unexpected value: ', literal(await actual.next))); + actual: ['a stream'], + which: prefixFirst( + 'emitted an unexpected value: ', + literal(await actual.next), + ), + ); } catch (e, st) { - return Rejection(actual: [ - 'a stream' - ], which: [ - ...prefixFirst('emitted an unexpected error: ', literal(e)), - ...const LineSplitter().convert(st.toString()) - ]); + return Rejection( + actual: ['a stream'], + which: [ + ...prefixFirst('emitted an unexpected error: ', literal(e)), + ...const LineSplitter().convert(st.toString()), + ], + ); } }); } @@ -470,7 +528,9 @@ extension WithQueueExtension on Subject> { /// Stream expectations operate on a queue, instead of directly on the stream, /// so that they can support conditional expectations and check multiple /// possibilities from the same point in the stream. - Subject> get withQueue => - context.nest(() => [], (actual) => Extracted.value(StreamQueue(actual)), - atSameLevel: true); + Subject> get withQueue => context.nest( + () => [], + (actual) => Extracted.value(StreamQueue(actual)), + atSameLevel: true, + ); } diff --git a/pkgs/checks/lib/src/extensions/core.dart b/pkgs/checks/lib/src/extensions/core.dart index 957e17519..d1fa6478c 100644 --- a/pkgs/checks/lib/src/extensions/core.dart +++ b/pkgs/checks/lib/src/extensions/core.dart @@ -19,10 +19,12 @@ extension CoreChecks on Subject { try { return Extracted.value(extract(value)); } catch (e, st) { - return Extracted.rejection(which: [ - ...prefixFirst('threw while trying to read $name: ', literal(e)), - ...const LineSplitter().convert(st.toString()) - ]); + return Extracted.rejection( + which: [ + ...prefixFirst('threw while trying to read $name: ', literal(e)), + ...const LineSplitter().convert(st.toString()), + ], + ); } }); } @@ -64,13 +66,14 @@ extension CoreChecks on Subject { /// Asynchronous expectations are not allowed in [conditions]. void anyOf(Iterable> conditions) { context.expect( - () => prefixFirst('matches any condition in ', literal(conditions)), - (actual) { - for (final condition in conditions) { - if (softCheck(actual, condition) == null) return null; - } - return Rejection(which: ['did not match any condition']); - }); + () => prefixFirst('matches any condition in ', literal(conditions)), + (actual) { + for (final condition in conditions) { + if (softCheck(actual, condition) == null) return null; + } + return Rejection(which: ['did not match any condition']); + }, + ); } /// Expects that the value is assignable to type [T]. @@ -95,8 +98,9 @@ extension CoreChecks on Subject { /// Expects that the value is [identical] to [other]. void identicalTo(T other) { - context.expect(() => prefixFirst('is identical to ', literal(other)), - (actual) { + context.expect(() => prefixFirst('is identical to ', literal(other)), ( + actual, + ) { if (identical(actual, other)) return null; return Rejection(which: ['is not identical']); }); @@ -107,18 +111,20 @@ extension BoolChecks on Subject { void isTrue() { context.expect( () => ['is true'], - (actual) => actual - ? null // force coverage - : Rejection(), + (actual) => + actual + ? null // force coverage + : Rejection(), ); } void isFalse() { context.expect( () => ['is false'], - (actual) => !actual - ? null // force coverage - : Rejection(), + (actual) => + !actual + ? null // force coverage + : Rejection(), ); } } @@ -142,30 +148,37 @@ extension NullableChecks on Subject { extension ComparableChecks on Subject> { /// Expects that this value is greater than [other]. void isGreaterThan(T other) { - context.expect(() => prefixFirst('is greater than ', literal(other)), - (actual) { + context.expect(() => prefixFirst('is greater than ', literal(other)), ( + actual, + ) { if (actual.compareTo(other) > 0) return null; return Rejection( - which: prefixFirst('is not greater than ', literal(other))); + which: prefixFirst('is not greater than ', literal(other)), + ); }); } /// Expects that this value is greater than or equal to [other]. void isGreaterOrEqual(T other) { context.expect( - () => prefixFirst('is greater than or equal to ', literal(other)), - (actual) { - if (actual.compareTo(other) >= 0) return null; - return Rejection( - which: - prefixFirst('is not greater than or equal to ', literal(other))); - }); + () => prefixFirst('is greater than or equal to ', literal(other)), + (actual) { + if (actual.compareTo(other) >= 0) return null; + return Rejection( + which: prefixFirst( + 'is not greater than or equal to ', + literal(other), + ), + ); + }, + ); } /// Expects that this value is less than [other]. void isLessThan(T other) { - context.expect(() => prefixFirst('is less than ', literal(other)), - (actual) { + context.expect(() => prefixFirst('is less than ', literal(other)), ( + actual, + ) { if (actual.compareTo(other) < 0) return null; return Rejection(which: prefixFirst('is not less than ', literal(other))); }); @@ -173,12 +186,14 @@ extension ComparableChecks on Subject> { /// Expects that this value is less than or equal to [other]. void isLessOrEqual(T other) { - context - .expect(() => prefixFirst('is less than or equal to ', literal(other)), - (actual) { - if (actual.compareTo(other) <= 0) return null; - return Rejection( - which: prefixFirst('is not less than or equal to ', literal(other))); - }); + context.expect( + () => prefixFirst('is less than or equal to ', literal(other)), + (actual) { + if (actual.compareTo(other) <= 0) return null; + return Rejection( + which: prefixFirst('is not less than or equal to ', literal(other)), + ); + }, + ); } } diff --git a/pkgs/checks/lib/src/extensions/function.dart b/pkgs/checks/lib/src/extensions/function.dart index 300941cc1..c23d4a6ff 100644 --- a/pkgs/checks/lib/src/extensions/function.dart +++ b/pkgs/checks/lib/src/extensions/function.dart @@ -27,8 +27,9 @@ extension FunctionChecks on Subject { } catch (e) { if (e is E) return Extracted.value(e as E); return Extracted.rejection( - actual: prefixFirst('a function that threw error ', literal(e)), - which: ['did not throw an $E']); + actual: prefixFirst('a function that threw error ', literal(e)), + which: ['did not throw an $E'], + ); } }); } @@ -44,12 +45,13 @@ extension FunctionChecks on Subject { try { return Extracted.value(actual()); } catch (e, st) { - return Extracted.rejection(actual: [ - 'a function that throws' - ], which: [ - ...prefixFirst('threw ', literal(e)), - ...st.toString().split('\n') - ]); + return Extracted.rejection( + actual: ['a function that throws'], + which: [ + ...prefixFirst('threw ', literal(e)), + ...st.toString().split('\n'), + ], + ); } }); } diff --git a/pkgs/checks/lib/src/extensions/iterable.dart b/pkgs/checks/lib/src/extensions/iterable.dart index ecfa9c05e..e868f1660 100644 --- a/pkgs/checks/lib/src/extensions/iterable.dart +++ b/pkgs/checks/lib/src/extensions/iterable.dart @@ -11,36 +11,36 @@ extension IterableChecks on Subject> { Subject get length => has((l) => l.length, 'length'); Subject get first => context.nest(() => ['has first element'], (actual) { - final iterator = actual.iterator; - if (!iterator.moveNext()) { - return Extracted.rejection(which: ['has no elements']); - } - return Extracted.value(iterator.current); - }); + final iterator = actual.iterator; + if (!iterator.moveNext()) { + return Extracted.rejection(which: ['has no elements']); + } + return Extracted.value(iterator.current); + }); Subject get last => context.nest(() => ['has last element'], (actual) { - final iterator = actual.iterator; - if (!iterator.moveNext()) { - return Extracted.rejection(which: ['has no elements']); - } - var current = iterator.current; - while (iterator.moveNext()) { - current = iterator.current; - } - return Extracted.value(current); - }); + final iterator = actual.iterator; + if (!iterator.moveNext()) { + return Extracted.rejection(which: ['has no elements']); + } + var current = iterator.current; + while (iterator.moveNext()) { + current = iterator.current; + } + return Extracted.value(current); + }); Subject get single => context.nest(() => ['has single element'], (actual) { - final iterator = actual.iterator; - if (!iterator.moveNext()) { - return Extracted.rejection(which: ['has no elements']); - } - final value = iterator.current; - if (iterator.moveNext()) { - return Extracted.rejection(which: ['has more than one element']); - } - return Extracted.value(value); - }); + final iterator = actual.iterator; + if (!iterator.moveNext()) { + return Extracted.rejection(which: ['has no elements']); + } + final value = iterator.current; + if (iterator.moveNext()) { + return Extracted.rejection(which: ['has more than one element']); + } + return Extracted.value(value); + }); void isEmpty() { context.expect(() => const ['is empty'], (actual) { @@ -59,14 +59,18 @@ extension IterableChecks on Subject> { /// Expects that the iterable contains [element] according to /// [Iterable.contains]. void contains(T element) { - context.expect(() { - return prefixFirst('contains ', literal(element)); - }, (actual) { - if (actual.isEmpty) return Rejection(actual: ['an empty iterable']); - if (actual.contains(element)) return null; - return Rejection( - which: prefixFirst('does not contain ', literal(element))); - }); + context.expect( + () { + return prefixFirst('contains ', literal(element)); + }, + (actual) { + if (actual.isEmpty) return Rejection(actual: ['an empty iterable']); + if (actual.contains(element)) return null; + return Rejection( + which: prefixFirst('does not contain ', literal(element)), + ); + }, + ); } /// Expects that the iterable contains a value matching each expected value @@ -89,32 +93,40 @@ extension IterableChecks on Subject> { /// check([1, 0, 2, 0, 3]) /// .containsInOrder([1, (Subject v) => v.isGreaterThan(1), 3]); /// ``` - @Deprecated('Use `containsEqualInOrder` for expectations with values compared' - ' with `==` or `containsMatchingInOrder` for other expectations') + @Deprecated( + 'Use `containsEqualInOrder` for expectations with values compared' + ' with `==` or `containsMatchingInOrder` for other expectations', + ) void containsInOrder(Iterable elements) { - context.expect(() => prefixFirst('contains, in order: ', literal(elements)), - (actual) { - final expected = elements.toList(); - if (expected.isEmpty) { - throw ArgumentError('expected may not be empty'); - } - var expectedIndex = 0; - for (final element in actual) { - final currentExpected = expected[expectedIndex]; - final matches = currentExpected is Condition - ? softCheck(element, currentExpected) == null - : currentExpected is Condition - ? softCheck(element, currentExpected) == null - : currentExpected == element; - if (matches && ++expectedIndex >= expected.length) return null; - } - return Rejection(which: [ - ...prefixFirst( - 'did not have an element matching the expectation at index ' - '$expectedIndex ', - literal(expected[expectedIndex])), - ]); - }); + context.expect( + () => prefixFirst('contains, in order: ', literal(elements)), + (actual) { + final expected = elements.toList(); + if (expected.isEmpty) { + throw ArgumentError('expected may not be empty'); + } + var expectedIndex = 0; + for (final element in actual) { + final currentExpected = expected[expectedIndex]; + final matches = + currentExpected is Condition + ? softCheck(element, currentExpected) == null + : currentExpected is Condition + ? softCheck(element, currentExpected) == null + : currentExpected == element; + if (matches && ++expectedIndex >= expected.length) return null; + } + return Rejection( + which: [ + ...prefixFirst( + 'did not have an element matching the expectation at index ' + '$expectedIndex ', + literal(expected[expectedIndex]), + ), + ], + ); + }, + ); } /// Expects that the iterable contains a value matching each condition in @@ -130,26 +142,30 @@ extension IterableChecks on Subject> { /// ]); /// ``` void containsMatchingInOrder(Iterable> conditions) { - context - .expect(() => prefixFirst('contains, in order: ', literal(conditions)), - (actual) { - final expected = conditions.toList(); - if (expected.isEmpty) { - throw ArgumentError('expected may not be empty'); - } - var expectedIndex = 0; - for (final element in actual) { - final currentExpected = expected[expectedIndex]; - final matches = softCheck(element, currentExpected) == null; - if (matches && ++expectedIndex >= expected.length) return null; - } - return Rejection(which: [ - ...prefixFirst( - 'did not have an element matching the expectation at index ' - '$expectedIndex ', - literal(expected[expectedIndex])), - ]); - }); + context.expect( + () => prefixFirst('contains, in order: ', literal(conditions)), + (actual) { + final expected = conditions.toList(); + if (expected.isEmpty) { + throw ArgumentError('expected may not be empty'); + } + var expectedIndex = 0; + for (final element in actual) { + final currentExpected = expected[expectedIndex]; + final matches = softCheck(element, currentExpected) == null; + if (matches && ++expectedIndex >= expected.length) return null; + } + return Rejection( + which: [ + ...prefixFirst( + 'did not have an element matching the expectation at index ' + '$expectedIndex ', + literal(expected[expectedIndex]), + ), + ], + ); + }, + ); } /// Expects that the iterable contains a value equals to each expected value @@ -164,44 +180,49 @@ extension IterableChecks on Subject> { /// /// Values, will be compared with the equality operator. void containsEqualInOrder(Iterable elements) { - context.expect(() => prefixFirst('contains, in order: ', literal(elements)), - (actual) { - final expected = elements.toList(); - if (expected.isEmpty) { - throw ArgumentError('expected may not be empty'); - } - var expectedIndex = 0; - for (final element in actual) { - final currentExpected = expected[expectedIndex]; - final matches = currentExpected == element; - if (matches && ++expectedIndex >= expected.length) return null; - } - return Rejection(which: [ - ...prefixFirst( - 'did not have an element equal to the expectation at index ' - '$expectedIndex ', - literal(expected[expectedIndex])), - ]); - }); + context.expect( + () => prefixFirst('contains, in order: ', literal(elements)), + (actual) { + final expected = elements.toList(); + if (expected.isEmpty) { + throw ArgumentError('expected may not be empty'); + } + var expectedIndex = 0; + for (final element in actual) { + final currentExpected = expected[expectedIndex]; + final matches = currentExpected == element; + if (matches && ++expectedIndex >= expected.length) return null; + } + return Rejection( + which: [ + ...prefixFirst( + 'did not have an element equal to the expectation at index ' + '$expectedIndex ', + literal(expected[expectedIndex]), + ), + ], + ); + }, + ); } /// Expects that the iterable contains at least on element such that /// [elementCondition] is satisfied. void any(Condition elementCondition) { - context.expect(() { - final conditionDescription = describe(elementCondition); - assert(conditionDescription.isNotEmpty); - return [ - 'contains a value that:', - ...conditionDescription, - ]; - }, (actual) { - if (actual.isEmpty) return Rejection(actual: ['an empty iterable']); - for (var e in actual) { - if (softCheck(e, elementCondition) == null) return null; - } - return Rejection(which: ['Contains no matching element']); - }); + context.expect( + () { + final conditionDescription = describe(elementCondition); + assert(conditionDescription.isNotEmpty); + return ['contains a value that:', ...conditionDescription]; + }, + (actual) { + if (actual.isEmpty) return Rejection(actual: ['an empty iterable']); + for (var e in actual) { + if (softCheck(e, elementCondition) == null) return null; + } + return Rejection(which: ['Contains no matching element']); + }, + ); } /// Expects there are no elements in the iterable which fail to satisfy @@ -209,44 +230,52 @@ extension IterableChecks on Subject> { /// /// Empty iterables will pass always pass this expectation. void every(Condition elementCondition) { - context.expect(() { - final conditionDescription = describe(elementCondition); - assert(conditionDescription.isNotEmpty); - return [ - 'only has values that:', - ...conditionDescription, - ]; - }, (actual) { - final iterator = actual.iterator; - for (var i = 0; iterator.moveNext(); i++) { - final element = iterator.current; - final failure = softCheck(element, elementCondition); - if (failure == null) continue; - final which = failure.rejection.which; - return Rejection(which: [ - 'has an element at index $i that:', - ...indent(failure.detail.actual.skip(1)), - ...indent(prefixFirst('Actual: ', failure.rejection.actual), - failure.detail.depth + 1), - if (which != null && which.isNotEmpty) - ...indent(prefixFirst('Which: ', which), failure.detail.depth + 1), - ]); - } - return null; - }); + context.expect( + () { + final conditionDescription = describe(elementCondition); + assert(conditionDescription.isNotEmpty); + return ['only has values that:', ...conditionDescription]; + }, + (actual) { + final iterator = actual.iterator; + for (var i = 0; iterator.moveNext(); i++) { + final element = iterator.current; + final failure = softCheck(element, elementCondition); + if (failure == null) continue; + final which = failure.rejection.which; + return Rejection( + which: [ + 'has an element at index $i that:', + ...indent(failure.detail.actual.skip(1)), + ...indent( + prefixFirst('Actual: ', failure.rejection.actual), + failure.detail.depth + 1, + ), + if (which != null && which.isNotEmpty) + ...indent( + prefixFirst('Which: ', which), + failure.detail.depth + 1, + ), + ], + ); + } + return null; + }, + ); } /// Expects that the iterable contains elements that are deeply equal to the /// elements of [expected]. /// /// {@macro deep_collection_equals} - void deepEquals(Iterable expected) => context - .expect(() => prefixFirst('is deeply equal to ', literal(expected)), - (actual) { - final which = deepCollectionEquals(actual, expected); - if (which == null) return null; - return Rejection(which: which); - }); + void deepEquals(Iterable expected) => context.expect( + () => prefixFirst('is deeply equal to ', literal(expected)), + (actual) { + final which = deepCollectionEquals(actual, expected); + if (which == null) return null; + return Rejection(which: which); + }, + ); /// Expects that the iterable contains elements which equal those of /// [expected] in any order. @@ -255,22 +284,26 @@ extension IterableChecks on Subject> { /// worst case where the iterables contain many equal elements, and O(n^2) in /// more typical cases. void unorderedEquals(Iterable expected) { - context.expect(() => prefixFirst('unordered equals ', literal(expected)), - (actual) { + context.expect(() => prefixFirst('unordered equals ', literal(expected)), ( + actual, + ) { final which = unorderedCompare( actual, expected, (actual, expected) => expected == actual, (expected, index, count) => [ ...prefixFirst( - 'has no element equal to the expected element at index ' - '$index: ', - literal(expected)), + 'has no element equal to the expected element at index ' + '$index: ', + literal(expected), + ), if (count > 1) 'or ${count - 1} other elements', ], (actual, index, count) => [ ...prefixFirst( - 'has an unexpected element at index $index: ', literal(actual)), + 'has an unexpected element at index $index: ', + literal(actual), + ), if (count > 1) 'and ${count - 1} other unexpected elements', ], ); @@ -286,8 +319,9 @@ extension IterableChecks on Subject> { /// worst case where conditions match many elements, and O(n^2) in more /// typical cases. void unorderedMatches(Iterable> expected) { - context.expect(() => prefixFirst('unordered matches ', literal(expected)), - (actual) { + context.expect(() => prefixFirst('unordered matches ', literal(expected)), ( + actual, + ) { final which = unorderedCompare( actual, expected, @@ -299,7 +333,9 @@ extension IterableChecks on Subject> { ], (actual, index, count) => [ ...prefixFirst( - 'has an unmatched element at index $index: ', literal(actual)), + 'has an unmatched element at index $index: ', + literal(actual), + ), if (count > 1) 'and ${count - 1} other unmatched elements', ], ); @@ -321,9 +357,11 @@ extension IterableChecks on Subject> { /// without the object, for example with the description 'is less than' the /// full expectation will be: "pairwise is less than $expected" @Deprecated('Use `pairwiseMatches`') - void pairwiseComparesTo(List expected, - Condition Function(S) elementCondition, String description) => - pairwiseMatches(expected, elementCondition, description); + void pairwiseComparesTo( + List expected, + Condition Function(S) elementCondition, + String description, + ) => pairwiseMatches(expected, elementCondition, description); /// Expects that the iterable contains elements that correspond by the /// [elementCondition] exactly to each element in [expected]. @@ -337,36 +375,51 @@ extension IterableChecks on Subject> { /// [description] is used in the Expected clause. It should be a predicate /// without the object, for example with the description 'is less than' the /// full expectation will be: "pairwise is less than $expected" - void pairwiseMatches(List expected, - Condition Function(S) elementCondition, String description) { - context.expect(() { - return prefixFirst('pairwise $description ', literal(expected)); - }, (actual) { - final iterator = actual.iterator; - for (var i = 0; i < expected.length; i++) { - final expectedValue = expected[i]; - if (!iterator.moveNext()) { - return Rejection(which: [ - 'has too few elements, there is no element to match at index $i' - ]); + void pairwiseMatches( + List expected, + Condition Function(S) elementCondition, + String description, + ) { + context.expect( + () { + return prefixFirst('pairwise $description ', literal(expected)); + }, + (actual) { + final iterator = actual.iterator; + for (var i = 0; i < expected.length; i++) { + final expectedValue = expected[i]; + if (!iterator.moveNext()) { + return Rejection( + which: [ + 'has too few elements, there is no element to match at index $i', + ], + ); + } + final actualValue = iterator.current; + final failure = softCheck( + actualValue, + elementCondition(expectedValue), + ); + if (failure == null) continue; + final innerDescription = describe(elementCondition(expectedValue)); + final which = failure.rejection.which; + return Rejection( + which: [ + 'does not have an element at index $i that:', + ...innerDescription, + ...prefixFirst( + 'Actual element at index $i: ', + failure.rejection.actual, + ), + if (which != null) ...prefixFirst('Which: ', which), + ], + ); } - final actualValue = iterator.current; - final failure = softCheck(actualValue, elementCondition(expectedValue)); - if (failure == null) continue; - final innerDescription = describe(elementCondition(expectedValue)); - final which = failure.rejection.which; - return Rejection(which: [ - 'does not have an element at index $i that:', - ...innerDescription, - ...prefixFirst( - 'Actual element at index $i: ', failure.rejection.actual), - if (which != null) ...prefixFirst('Which: ', which), - ]); - } - if (!iterator.moveNext()) return null; - return Rejection(which: [ - 'has too many elements, expected exactly ${expected.length}' - ]); - }); + if (!iterator.moveNext()) return null; + return Rejection( + which: ['has too many elements, expected exactly ${expected.length}'], + ); + }, + ); } } diff --git a/pkgs/checks/lib/src/extensions/map.dart b/pkgs/checks/lib/src/extensions/map.dart index 4fc0fdf9d..8dd68e5d2 100644 --- a/pkgs/checks/lib/src/extensions/map.dart +++ b/pkgs/checks/lib/src/extensions/map.dart @@ -15,13 +15,16 @@ extension MapChecks on Subject> { Subject get length => has((m) => m.length, 'length'); Subject operator [](K key) { return context.nest( - () => prefixFirst('contains a value for ', literal(key)), (actual) { - if (!actual.containsKey(key)) { - return Extracted.rejection( - which: prefixFirst('does not contain the key ', literal(key))); - } - return Extracted.value(actual[key] as V); - }); + () => prefixFirst('contains a value for ', literal(key)), + (actual) { + if (!actual.containsKey(key)) { + return Extracted.rejection( + which: prefixFirst('does not contain the key ', literal(key)), + ); + } + return Extracted.value(actual[key] as V); + }, + ); } void isEmpty() { @@ -43,67 +46,71 @@ extension MapChecks on Subject> { context.expect(() => prefixFirst('contains key ', literal(key)), (actual) { if (actual.containsKey(key)) return null; return Rejection( - which: prefixFirst('does not contain key ', literal(key))); + which: prefixFirst('does not contain key ', literal(key)), + ); }); } /// Expects that the map contains some key such that [keyCondition] is /// satisfied. void containsKeyThat(Condition keyCondition) { - context.expect(() { - final conditionDescription = describe(keyCondition); - assert(conditionDescription.isNotEmpty); - return [ - 'contains a key that:', - ...conditionDescription, - ]; - }, (actual) { - if (actual.isEmpty) return Rejection(actual: ['an empty map']); - for (var k in actual.keys) { - if (softCheck(k, keyCondition) == null) return null; - } - return Rejection(which: ['Contains no matching key']); - }); + context.expect( + () { + final conditionDescription = describe(keyCondition); + assert(conditionDescription.isNotEmpty); + return ['contains a key that:', ...conditionDescription]; + }, + (actual) { + if (actual.isEmpty) return Rejection(actual: ['an empty map']); + for (var k in actual.keys) { + if (softCheck(k, keyCondition) == null) return null; + } + return Rejection(which: ['Contains no matching key']); + }, + ); } /// Expects that the map contains [value] according to [Map.containsValue]. void containsValue(V value) { - context.expect(() => prefixFirst('contains value ', literal(value)), - (actual) { + context.expect(() => prefixFirst('contains value ', literal(value)), ( + actual, + ) { if (actual.containsValue(value)) return null; return Rejection( - which: prefixFirst('does not contain value ', literal(value))); + which: prefixFirst('does not contain value ', literal(value)), + ); }); } /// Expects that the map contains some value such that [valueCondition] is /// satisfied. void containsValueThat(Condition valueCondition) { - context.expect(() { - final conditionDescription = describe(valueCondition); - assert(conditionDescription.isNotEmpty); - return [ - 'contains a value that:', - ...conditionDescription, - ]; - }, (actual) { - if (actual.isEmpty) return Rejection(actual: ['an empty map']); - for (var v in actual.values) { - if (softCheck(v, valueCondition) == null) return null; - } - return Rejection(which: ['Contains no matching value']); - }); + context.expect( + () { + final conditionDescription = describe(valueCondition); + assert(conditionDescription.isNotEmpty); + return ['contains a value that:', ...conditionDescription]; + }, + (actual) { + if (actual.isEmpty) return Rejection(actual: ['an empty map']); + for (var v in actual.values) { + if (softCheck(v, valueCondition) == null) return null; + } + return Rejection(which: ['Contains no matching value']); + }, + ); } /// Expects that the map contains entries that are deeply equal to the entries /// of [expected]. /// /// {@macro deep_collection_equals} - void deepEquals(Map expected) => context - .expect(() => prefixFirst('is deeply equal to ', literal(expected)), - (actual) { - final which = deepCollectionEquals(actual, expected); - if (which == null) return null; - return Rejection(which: which); - }); + void deepEquals(Map expected) => context.expect( + () => prefixFirst('is deeply equal to ', literal(expected)), + (actual) { + final which = deepCollectionEquals(actual, expected); + if (which == null) return null; + return Rejection(which: which); + }, + ); } diff --git a/pkgs/checks/lib/src/extensions/string.dart b/pkgs/checks/lib/src/extensions/string.dart index 84b20f6f5..d449c0b6b 100644 --- a/pkgs/checks/lib/src/extensions/string.dart +++ b/pkgs/checks/lib/src/extensions/string.dart @@ -36,27 +36,21 @@ extension StringChecks on Subject { } void startsWith(Pattern other) { - context.expect( - () => prefixFirst('starts with ', literal(other)), - (actual) { - if (actual.startsWith(other)) return null; - return Rejection( - which: prefixFirst('does not start with ', literal(other)), - ); - }, - ); + context.expect(() => prefixFirst('starts with ', literal(other)), (actual) { + if (actual.startsWith(other)) return null; + return Rejection( + which: prefixFirst('does not start with ', literal(other)), + ); + }); } void endsWith(String other) { - context.expect( - () => prefixFirst('ends with ', literal(other)), - (actual) { - if (actual.endsWith(other)) return null; - return Rejection( - which: prefixFirst('does not end with ', literal(other)), - ); - }, - ); + context.expect(() => prefixFirst('ends with ', literal(other)), (actual) { + if (actual.endsWith(other)) return null; + return Rejection( + which: prefixFirst('does not end with ', literal(other)), + ); + }); } /// Expects that the string matches the pattern [expected]. @@ -72,7 +66,8 @@ extension StringChecks on Subject { context.expect(() => prefixFirst('matches ', literal(expected)), (actual) { if (expected.allMatches(actual).isNotEmpty) return null; return Rejection( - which: prefixFirst('does not match ', literal(expected))); + which: prefixFirst('does not match ', literal(expected)), + ); }); } @@ -83,39 +78,52 @@ extension StringChecks on Subject { /// /// check('abcdefg').containsInOrder(['a','e']); void containsInOrder(Iterable expected) { - context.expect(() => prefixFirst('contains, in order: ', literal(expected)), - (actual) { - var fromIndex = 0; - for (var s in expected) { - var index = actual.indexOf(s, fromIndex); - if (index < 0) { - return Rejection(which: [ - ...prefixFirst( - 'does not have a match for the substring ', literal(s)), - if (fromIndex != 0) - 'following the other matches up to character $fromIndex' - ]); + context.expect( + () => prefixFirst('contains, in order: ', literal(expected)), + (actual) { + var fromIndex = 0; + for (var s in expected) { + var index = actual.indexOf(s, fromIndex); + if (index < 0) { + return Rejection( + which: [ + ...prefixFirst( + 'does not have a match for the substring ', + literal(s), + ), + if (fromIndex != 0) + 'following the other matches up to character $fromIndex', + ], + ); + } + fromIndex = index + s.length; } - fromIndex = index + s.length; - } - return null; - }); + return null; + }, + ); } /// Expects that the `String` contains exactly the same code units as /// [expected]. void equals(String expected) { - context.expect(() => prefixFirst('equals ', literal(expected)), - (actual) => _findDifference(actual, expected)); + context.expect( + () => prefixFirst('equals ', literal(expected)), + (actual) => _findDifference(actual, expected), + ); } /// Expects that the `String` contains the same characters as [expected] if /// both were lower case. void equalsIgnoringCase(String expected) { context.expect( - () => prefixFirst('equals ignoring case ', literal(expected)), - (actual) => _findDifference( - actual.toLowerCase(), expected.toLowerCase(), actual, expected)); + () => prefixFirst('equals ignoring case ', literal(expected)), + (actual) => _findDifference( + actual.toLowerCase(), + expected.toLowerCase(), + actual, + expected, + ), + ); } /// Expects that the `String` contains the same content as [expected], @@ -134,18 +142,27 @@ extension StringChecks on Subject { /// check('he llo world').equalsIgnoringWhitespace('hello world'); void equalsIgnoringWhitespace(String expected) { context.expect( - () => prefixFirst('equals ignoring whitespace ', literal(expected)), - (actual) { - final collapsedActual = _collapseWhitespace(actual); - final collapsedExpected = _collapseWhitespace(expected); - return _findDifference(collapsedActual, collapsedExpected, - collapsedActual, collapsedExpected); - }); + () => prefixFirst('equals ignoring whitespace ', literal(expected)), + (actual) { + final collapsedActual = _collapseWhitespace(actual); + final collapsedExpected = _collapseWhitespace(expected); + return _findDifference( + collapsedActual, + collapsedExpected, + collapsedActual, + collapsedExpected, + ); + }, + ); } } -Rejection? _findDifference(String actual, String expected, - [String? actualDisplay, String? expectedDisplay]) { +Rejection? _findDifference( + String actual, + String expected, [ + String? actualDisplay, + String? expectedDisplay, +]) { if (actual == expected) return null; final escapedActual = escape(actual); final escapedExpected = escape(expected); @@ -165,34 +182,41 @@ Rejection? _findDifference(String actual, String expected, if (expected.isEmpty) { return Rejection(which: ['is not the empty string']); } - return Rejection(which: [ - 'is too long with unexpected trailing characters:', - _trailing(escapedActualDisplay, i) - ]); + return Rejection( + which: [ + 'is too long with unexpected trailing characters:', + _trailing(escapedActualDisplay, i), + ], + ); } else { if (actual.isEmpty) { - return Rejection(actual: [ - 'an empty string' - ], which: [ - 'is missing all expected characters:', - _trailing(escapedExpectedDisplay, 0) - ]); + return Rejection( + actual: ['an empty string'], + which: [ + 'is missing all expected characters:', + _trailing(escapedExpectedDisplay, 0), + ], + ); } - return Rejection(which: [ - 'is too short with missing trailing characters:', - _trailing(escapedExpectedDisplay, i) - ]); + return Rejection( + which: [ + 'is too short with missing trailing characters:', + _trailing(escapedExpectedDisplay, i), + ], + ); } } else { final indentation = ' ' * (i > 10 ? 14 : i); - return Rejection(which: [ - 'differs at offset $i:', - '${_leading(escapedExpectedDisplay, i)}' - '${_trailing(escapedExpectedDisplay, i)}', - '${_leading(escapedActualDisplay, i)}' - '${_trailing(escapedActualDisplay, i)}', - '$indentation^' - ]); + return Rejection( + which: [ + 'differs at offset $i:', + '${_leading(escapedExpectedDisplay, i)}' + '${_trailing(escapedExpectedDisplay, i)}', + '${_leading(escapedActualDisplay, i)}' + '${_trailing(escapedActualDisplay, i)}', + '$indentation^', + ], + ); } } @@ -201,9 +225,10 @@ String _leading(String s, int end) => (end > 10) ? '... ${s.substring(end - 10, end)}' : s.substring(0, end); /// The truncated remainder of [s] starting at the [start] character. -String _trailing(String s, int start) => (start + 10 > s.length) - ? s.substring(start) - : '${s.substring(start, start + 10)} ...'; +String _trailing(String s, int start) => + (start + 10 > s.length) + ? s.substring(start) + : '${s.substring(start, start + 10)} ...'; /// Utility function to collapse whitespace runs to single spaces /// and strip leading/trailing whitespace. diff --git a/pkgs/checks/test/context_test.dart b/pkgs/checks/test/context_test.dart index 820ff8821..a136ce1a1 100644 --- a/pkgs/checks/test/context_test.dart +++ b/pkgs/checks/test/context_test.dart @@ -70,13 +70,17 @@ void main() { test('nestAsync holds test open past async condition', () async { late void Function() callback; final monitor = TestCaseMonitor.start(() { - check(null).context.nestAsync(() => [''], (actual) async { - return Extracted.value(null); - }, (it) async { - final completer = Completer(); - callback = completer.complete; - await completer.future; - }); + check(null).context.nestAsync( + () => [''], + (actual) async { + return Extracted.value(null); + }, + (it) async { + final completer = Completer(); + callback = completer.complete; + await completer.future; + }, + ); }); await pumpEventQueue(); check(monitor).state.equals(State.running); @@ -108,10 +112,11 @@ void main() { late void Function() callback; final monitor = await TestCaseMonitor.run(() { check(null).context.expectUnawaited(() => [''], (actual, reject) { - final completer = Completer() - ..future.then((_) { - reject(Rejection(which: ['foo'])); - }); + final completer = + Completer() + ..future.then((_) { + reject(Rejection(which: ['foo'])); + }); callback = completer.complete; }); }); @@ -130,7 +135,7 @@ void main() { (it) => it .has((e) => e.error, 'error') .isA() - .startsWith('This test failed after it had already completed.') + .startsWith('This test failed after it had already completed.'), ]); }); }); @@ -158,14 +163,23 @@ extension _MonitorChecks on Subject { void didPass() { errors.isEmpty(); state.equals(State.passed); - onError.context.expectUnawaited(() => ['emits no further errors'], - (actual, reject) async { + onError.context.expectUnawaited(() => ['emits no further errors'], ( + actual, + reject, + ) async { await for (var error in actual.rest) { - reject(Rejection(which: [ - ...prefixFirst('threw late error', literal(error.error)), - ...const LineSplitter().convert( - TestHandle.current.formatStackTrace(error.stackTrace).toString()) - ])); + reject( + Rejection( + which: [ + ...prefixFirst('threw late error', literal(error.error)), + ...const LineSplitter().convert( + TestHandle.current + .formatStackTrace(error.stackTrace) + .toString(), + ), + ], + ), + ); } }); } diff --git a/pkgs/checks/test/describe_test.dart b/pkgs/checks/test/describe_test.dart index d117a7b10..c4d318049 100644 --- a/pkgs/checks/test/describe_test.dart +++ b/pkgs/checks/test/describe_test.dart @@ -15,10 +15,9 @@ void main() { check(describe((it) => it.equals(1))).deepEquals([' equals <1>']); }); test('includes nested clauses', () { - check(describe((it) => it.length.equals(1))).deepEquals([ - ' has length that:', - ' equals <1>', - ]); + check( + describe((it) => it.length.equals(1)), + ).deepEquals([' has length that:', ' equals <1>']); }); }); } diff --git a/pkgs/checks/test/extensions/async_test.dart b/pkgs/checks/test/extensions/async_test.dart index 5bfe55062..85b68f8aa 100644 --- a/pkgs/checks/test/extensions/async_test.dart +++ b/pkgs/checks/test/extensions/async_test.dart @@ -26,24 +26,31 @@ void main() { ); }); test('can be described', () async { - await check((Subject it) => it.completes()) - .hasAsyncDescriptionWhich( - (it) => it.deepEquals([' completes to a value'])); - await check((Subject it) => it.completes((it) => it.equals(42))) - .hasAsyncDescriptionWhich((it) => it.deepEquals([ - ' completes to a value that:', - ' equals <42>', - ])); + await check( + (Subject it) => it.completes(), + ).hasAsyncDescriptionWhich( + (it) => it.deepEquals([' completes to a value']), + ); + await check( + (Subject it) => it.completes((it) => it.equals(42)), + ).hasAsyncDescriptionWhich( + (it) => it.deepEquals([ + ' completes to a value that:', + ' equals <42>', + ]), + ); }); }); group('throws', () { test( - 'succeeds for a future that compeletes to an error of the expected type', - () async { - await check(_futureFail()).throws( - (it) => it.has((p0) => p0.message, 'message').isNull()); - }); + 'succeeds for a future that compeletes to an error of the expected type', + () async { + await check(_futureFail()).throws( + (it) => it.has((p0) => p0.message, 'message').isNull(), + ); + }, + ); test('fails for futures that complete to a value', () async { await check(_futureSuccess()).isRejectedByAsync( (it) => it.throws(), @@ -51,24 +58,30 @@ void main() { which: ['did not throw'], ); }); - test('failes for futures that complete to an error of the wrong type', - () async { - await check(_futureFail()).isRejectedByAsync( - (it) => it.throws(), - actual: ['completed to error '], - which: [ - 'threw an exception that is not a StateError at:', - 'fake trace' - ], - ); - }); + test( + 'failes for futures that complete to an error of the wrong type', + () async { + await check(_futureFail()).isRejectedByAsync( + (it) => it.throws(), + actual: ['completed to error '], + which: [ + 'threw an exception that is not a StateError at:', + 'fake trace', + ], + ); + }, + ); test('can be described', () async { - await check((Subject> it) => it.throws()) - .hasAsyncDescriptionWhich( - (it) => it.deepEquals([' completes to an error'])); - await check((Subject> it) => it.throws()) - .hasAsyncDescriptionWhich((it) => - it.deepEquals([' completes to an error of type StateError'])); + await check( + (Subject> it) => it.throws(), + ).hasAsyncDescriptionWhich( + (it) => it.deepEquals([' completes to an error']), + ); + await check( + (Subject> it) => it.throws(), + ).hasAsyncDescriptionWhich( + (it) => it.deepEquals([' completes to an error of type StateError']), + ); }); }); @@ -78,13 +91,16 @@ void main() { }); test('fails for a Future that completes as a value', () async { Object? testFailure; - runZonedGuarded(() { - final completer = Completer(); - check(completer.future).doesNotComplete(); - completer.complete('value'); - }, (e, st) { - testFailure = e; - }); + runZonedGuarded( + () { + final completer = Completer(); + check(completer.future).doesNotComplete(); + completer.complete('value'); + }, + (e, st) { + testFailure = e; + }, + ); await pumpEventQueue(); check(testFailure) .isA() @@ -97,13 +113,19 @@ Actual: a future that completed to 'value\''''); }); test('fails for a Future that completes as an error', () async { Object? testFailure; - runZonedGuarded(() { - final completer = Completer(); - check(completer.future).doesNotComplete(); - completer.completeError('error', StackTrace.fromString('fake trace')); - }, (e, st) { - testFailure = e; - }); + runZonedGuarded( + () { + final completer = Completer(); + check(completer.future).doesNotComplete(); + completer.completeError( + 'error', + StackTrace.fromString('fake trace'), + ); + }, + (e, st) { + testFailure = e; + }, + ); await pumpEventQueue(); check(testFailure) .isA() @@ -117,9 +139,11 @@ Which: threw 'error' fake trace'''); }); test('can be described', () async { - await check((Subject> it) => it.doesNotComplete()) - .hasAsyncDescriptionWhich( - (it) => it.deepEquals([' does not complete'])); + await check( + (Subject> it) => it.doesNotComplete(), + ).hasAsyncDescriptionWhich( + (it) => it.deepEquals([' does not complete']), + ); }); }); }); @@ -144,15 +168,14 @@ fake trace'''); ); }); test('can be described', () async { - await check((Subject> it) => it.emits()) - .hasAsyncDescriptionWhich( - (it) => it.deepEquals([' emits a value'])); - await check((Subject> it) => - it.emits((it) => it.equals(42))) - .hasAsyncDescriptionWhich((it) => it.deepEquals([ - ' emits a value that:', - ' equals <42>', - ])); + await check( + (Subject> it) => it.emits(), + ).hasAsyncDescriptionWhich((it) => it.deepEquals([' emits a value'])); + await check( + (Subject> it) => it.emits((it) => it.equals(42)), + ).hasAsyncDescriptionWhich( + (it) => it.deepEquals([' emits a value that:', ' equals <42>']), + ); }); test('does not consume error', () async { final queue = _countingStream(1, errorAt: 0); @@ -163,17 +186,20 @@ fake trace'''); group('emitsError', () { test('succeeds for a stream that emits an error', () async { - await check(_countingStream(1, errorAt: 0)) - .emitsError(); - }); - test('fails for a stream that closes without emitting an error', - () async { - await check(_countingStream(0)).isRejectedByAsync( - (it) => it.emitsError(), - actual: ['a stream'], - which: ['closed without emitting an expected error'], - ); + await check( + _countingStream(1, errorAt: 0), + ).emitsError(); }); + test( + 'fails for a stream that closes without emitting an error', + () async { + await check(_countingStream(0)).isRejectedByAsync( + (it) => it.emitsError(), + actual: ['a stream'], + which: ['closed without emitting an expected error'], + ); + }, + ); test('fails for a stream that emits value', () async { await check(_countingStream(1)).isRejectedByAsync( (it) => it.emitsError(), @@ -181,30 +207,40 @@ fake trace'''); which: ['closed without emitting an error'], ); }); - test('fails for a stream that emits an error of the incorrect type', - () async { - await check(_countingStream(1, errorAt: 0)).isRejectedByAsync( - (it) => it.emitsError(), - actual: ['a stream with error '], - which: ['emitted an error which is not StateError at:', 'fake trace'], - ); - }); + test( + 'fails for a stream that emits an error of the incorrect type', + () async { + await check(_countingStream(1, errorAt: 0)).isRejectedByAsync( + (it) => it.emitsError(), + actual: ['a stream with error '], + which: [ + 'emitted an error which is not StateError at:', + 'fake trace', + ], + ); + }, + ); test('can be described', () async { - await check((Subject> it) => it.emitsError()) - .hasAsyncDescriptionWhich( - (it) => it.deepEquals([' emits an error'])); await check( - (Subject> it) => it.emitsError()) - .hasAsyncDescriptionWhich( - (it) => it.deepEquals([' emits an error of type StateError'])); - await check((Subject> it) => it - ..emitsError( - (it) => it.has((e) => e.message, 'message').equals('foo'))) - .hasAsyncDescriptionWhich((it) => it.deepEquals([ - ' emits an error of type StateError that:', - ' has message that:', - ' equals \'foo\'' - ])); + (Subject> it) => it.emitsError(), + ).hasAsyncDescriptionWhich((it) => it.deepEquals([' emits an error'])); + await check( + (Subject> it) => it.emitsError(), + ).hasAsyncDescriptionWhich( + (it) => it.deepEquals([' emits an error of type StateError']), + ); + await check( + (Subject> it) => + it..emitsError( + (it) => it.has((e) => e.message, 'message').equals('foo'), + ), + ).hasAsyncDescriptionWhich( + (it) => it.deepEquals([ + ' emits an error of type StateError that:', + ' has message that:', + ' equals \'foo\'', + ]), + ); }); test('uses a transaction', () async { final queue = _countingStream(1); @@ -214,32 +250,40 @@ fake trace'''); }); group('emitsThrough', () { - test('succeeds for a stream that eventuall emits a matching value', - () async { - await check(_countingStream(5)).emitsThrough((it) => it.equals(4)); - }); - test('fails for a stream that closes without emitting a matching value', - () async { - await check(_countingStream(4)).isRejectedByAsync( - (it) => it.emitsThrough((it) => it.equals(5)), - actual: ['a stream'], - which: ['ended after emitting 4 elements with none matching'], - ); - }); + test( + 'succeeds for a stream that eventuall emits a matching value', + () async { + await check(_countingStream(5)).emitsThrough((it) => it.equals(4)); + }, + ); + test( + 'fails for a stream that closes without emitting a matching value', + () async { + await check(_countingStream(4)).isRejectedByAsync( + (it) => it.emitsThrough((it) => it.equals(5)), + actual: ['a stream'], + which: ['ended after emitting 4 elements with none matching'], + ); + }, + ); test('can be described', () async { - await check((Subject> it) => - it.emitsThrough((it) => it.equals(42))) - .hasAsyncDescriptionWhich((it) => it.deepEquals([ - ' emits any values then emits a value that:', - ' equals <42>' - ])); + await check( + (Subject> it) => + it.emitsThrough((it) => it.equals(42)), + ).hasAsyncDescriptionWhich( + (it) => it.deepEquals([ + ' emits any values then emits a value that:', + ' equals <42>', + ]), + ); }); test('uses a transaction', () async { final queue = _countingStream(1); await softCheckAsync( - queue, - (Subject> it) => - it.emitsThrough((it) => it.equals(42))); + queue, + (Subject> it) => + it.emitsThrough((it) => it.equals(42)), + ); await check(queue).emits((it) => it.equals(0)); }); test('consumes events', () async { @@ -264,14 +308,16 @@ fake trace'''); which: [ 'satisfied 1 conditions then', 'failed to satisfy the condition at index 1', - 'because it closed without emitting enough values' + 'because it closed without emitting enough values', ], ); }); test('nestes the report for deep failures', () async { await check(_countingStream(2)).isRejectedByAsync( - (it) => it.inOrder( - [(it) => it.emits(), (it) => it.emits((it) => it.equals(2))]), + (it) => it.inOrder([ + (it) => it.emits(), + (it) => it.emits((it) => it.equals(2)), + ]), actual: ['a stream'], which: [ 'satisfied 1 conditions then', @@ -285,19 +331,21 @@ fake trace'''); }); test('gets described with the number of conditions', () async { await check( - (Subject> it) => it.inOrder([(_) {}, (_) {}])) - .hasAsyncDescriptionWhich( - (it) => it.deepEquals([' satisfies 2 conditions in order'])); + (Subject> it) => it.inOrder([(_) {}, (_) {}]), + ).hasAsyncDescriptionWhich( + (it) => it.deepEquals([' satisfies 2 conditions in order']), + ); }); test('uses a transaction', () async { final queue = _countingStream(3); await softCheckAsync>( - queue, - (it) => it.inOrder([ - (it) => it.emits((it) => it.equals(0)), - (it) => it.emits((it) => it.equals(1)), - (it) => it.emits((it) => it.equals(42)), - ])); + queue, + (it) => it.inOrder([ + (it) => it.emits((it) => it.equals(0)), + (it) => it.emits((it) => it.equals(1)), + (it) => it.emits((it) => it.equals(42)), + ]), + ); await check(queue).inOrder([ (it) => it.emits((it) => it.equals(0)), (it) => it.emits((it) => it.equals(1)), @@ -314,10 +362,11 @@ fake trace'''); group('neverEmits', () { test( - 'succeeds for a stream that closes without emitting a matching value', - () async { - await check(_countingStream(5)).neverEmits((it) => it.equals(5)); - }); + 'succeeds for a stream that closes without emitting a matching value', + () async { + await check(_countingStream(5)).neverEmits((it) => it.equals(5)); + }, + ); test('fails for a stream that emits a matching value', () async { await check(_countingStream(6)).isRejectedByAsync( (it) => it.neverEmits((it) => it.equals(5)), @@ -326,17 +375,20 @@ fake trace'''); ); }); test('can be described', () async { - await check((Subject> it) => - it.neverEmits((it) => it.equals(42))) - .hasAsyncDescriptionWhich((it) => it.deepEquals([ - ' never emits a value that:', - ' equals <42>', - ])); + await check( + (Subject> it) => + it.neverEmits((it) => it.equals(42)), + ).hasAsyncDescriptionWhich( + (it) => + it.deepEquals([' never emits a value that:', ' equals <42>']), + ); }); test('uses a transaction', () async { final queue = _countingStream(2); await softCheckAsync>( - queue, (it) => it.neverEmits((it) => it.equals(1))); + queue, + (it) => it.neverEmits((it) => it.equals(1)), + ); await check(queue).inOrder([ (it) => it.emits((it) => it.equals(0)), (it) => it.emits((it) => it.equals(1)), @@ -350,8 +402,9 @@ fake trace'''); await check(_countingStream(1)).mayEmit((it) => it.equals(0)); }); test('succeeds for a stream that emits an error', () async { - await check(_countingStream(1, errorAt: 0)) - .mayEmit((it) => it.equals(0)); + await check( + _countingStream(1, errorAt: 0), + ).mayEmit((it) => it.equals(0)); }); test('succeeds for a stream that closes', () async { await check(_countingStream(0)).mayEmit((it) => it.equals(42)); @@ -359,21 +412,28 @@ fake trace'''); test('consumes a matching event', () async { final queue = _countingStream(2); await softCheckAsync>( - queue, (it) => it.mayEmit((it) => it.equals(0))); + queue, + (it) => it.mayEmit((it) => it.equals(0)), + ); await check(queue).emits((it) => it.equals(1)); }); test('does not consume a non-matching event', () async { final queue = _countingStream(2); await softCheckAsync>( - queue, (it) => it.mayEmit((it) => it.equals(1))); + queue, + (it) => it.mayEmit((it) => it.equals(1)), + ); await check(queue).emits((it) => it.equals(0)); }); test('does not consume an error', () async { final queue = _countingStream(1, errorAt: 0); await softCheckAsync>( - queue, (it) => it.mayEmit((it) => it.equals(0))); + queue, + (it) => it.mayEmit((it) => it.equals(0)), + ); await check(queue).emitsError( - (it) => it.has((e) => e.message, 'message').equals('Error at 1')); + (it) => it.has((e) => e.message, 'message').equals('Error at 1'), + ); }); }); @@ -382,8 +442,9 @@ fake trace'''); await check(_countingStream(1)).mayEmitMultiple((it) => it.equals(0)); }); test('succeeds for a stream that emits an error', () async { - await check(_countingStream(1, errorAt: 0)) - .mayEmitMultiple((it) => it.equals(0)); + await check( + _countingStream(1, errorAt: 0), + ).mayEmitMultiple((it) => it.equals(0)); }); test('succeeds for a stream that closes', () async { await check(_countingStream(0)).mayEmitMultiple((it) => it.equals(42)); @@ -391,21 +452,28 @@ fake trace'''); test('consumes matching events', () async { final queue = _countingStream(3); await softCheckAsync>( - queue, (it) => it.mayEmitMultiple((it) => it.isLessThan(2))); + queue, + (it) => it.mayEmitMultiple((it) => it.isLessThan(2)), + ); await check(queue).emits((it) => it.equals(2)); }); test('consumes no events if no events match', () async { final queue = _countingStream(2); await softCheckAsync>( - queue, (it) => it.mayEmitMultiple((it) => it.isLessThan(0))); + queue, + (it) => it.mayEmitMultiple((it) => it.isLessThan(0)), + ); await check(queue).emits((it) => it.equals(0)); }); test('does not consume an error', () async { final queue = _countingStream(1, errorAt: 0); await softCheckAsync>( - queue, (it) => it.mayEmitMultiple((it) => it.equals(0))); + queue, + (it) => it.mayEmitMultiple((it) => it.equals(0)), + ); await check(queue).emitsError( - (it) => it.has((e) => e.message, 'message').equals('Error at 1')); + (it) => it.has((e) => e.message, 'message').equals('Error at 1'), + ); }); }); @@ -414,16 +482,20 @@ fake trace'''); await check(_countingStream(0)).isDone(); }); test('fails for a stream that emits a value', () async { - await check(_countingStream(1)).isRejectedByAsync((it) => it.isDone(), - actual: ['a stream'], which: ['emitted an unexpected value: <0>']); + await check(_countingStream(1)).isRejectedByAsync( + (it) => it.isDone(), + actual: ['a stream'], + which: ['emitted an unexpected value: <0>'], + ); }); test('fails for a stream that emits an error', () async { final controller = StreamController(); controller.addError('sad', StackTrace.fromString('fake trace')); await check(StreamQueue(controller.stream)).isRejectedByAsync( - (it) => it.isDone(), - actual: ['a stream'], - which: ['emitted an unexpected error: \'sad\'', 'fake trace']); + (it) => it.isDone(), + actual: ['a stream'], + which: ['emitted an unexpected error: \'sad\'', 'fake trace'], + ); }); test('uses a transaction', () async { final queue = _countingStream(1); @@ -431,8 +503,9 @@ fake trace'''); await check(queue).emits((it) => it.equals(0)); }); test('can be described', () async { - await check((Subject> it) => it.isDone()) - .hasAsyncDescriptionWhich((it) => it.deepEquals([' is done'])); + await check( + (Subject> it) => it.isDone(), + ).hasAsyncDescriptionWhich((it) => it.deepEquals([' is done'])); }); }); @@ -440,66 +513,67 @@ fake trace'''); test('succeeds for a stream that matches one condition', () async { await check(_countingStream(1)).anyOf([ (it) => it.emits((it) => it.equals(42)), - (it) => it.emits((it) => it.equals(0)) + (it) => it.emits((it) => it.equals(0)), ]); }); test('fails for a stream that matches no conditions', () async { await check(_countingStream(0)).isRejectedByAsync( - (it) => it.anyOf([ - (it) => it.emits(), - (it) => it.emitsThrough((it) => it.equals(1)), - ]), - actual: [ - 'a stream' - ], - which: [ - 'failed to satisfy any condition', - 'failed the condition at index 0 because it:', - ' closed without emitting enough values', - 'failed the condition at index 1 because it:', - ' ended after emitting 0 elements with none matching', - ]); + (it) => it.anyOf([ + (it) => it.emits(), + (it) => it.emitsThrough((it) => it.equals(1)), + ]), + actual: ['a stream'], + which: [ + 'failed to satisfy any condition', + 'failed the condition at index 0 because it:', + ' closed without emitting enough values', + 'failed the condition at index 1 because it:', + ' ended after emitting 0 elements with none matching', + ], + ); }); test('includes nested details for nested failures', () async { await check(_countingStream(1)).isRejectedByAsync( - (it) => it.anyOf([ - (it) => it.emits((it) => it.equals(42)), - (it) => it.emitsThrough((it) => it.equals(10)), - ]), - actual: [ - 'a stream' - ], - which: [ - 'failed to satisfy any condition', - 'failed the condition at index 0 because it:', - ' emits a value that:', - ' Actual: <0>', - ' Which: are not equal', - 'failed the condition at index 1 because it:', - ' ended after emitting 1 elements with none matching', - ]); + (it) => it.anyOf([ + (it) => it.emits((it) => it.equals(42)), + (it) => it.emitsThrough((it) => it.equals(10)), + ]), + actual: ['a stream'], + which: [ + 'failed to satisfy any condition', + 'failed the condition at index 0 because it:', + ' emits a value that:', + ' Actual: <0>', + ' Which: are not equal', + 'failed the condition at index 1 because it:', + ' ended after emitting 1 elements with none matching', + ], + ); }); test('gets described with the number of conditions', () async { - await check((Subject> it) => - it..anyOf([(it) => it.emits(), (it) => it.emits()])) - .hasAsyncDescriptionWhich( - (it) => it.deepEquals([' satisfies any of 2 conditions'])); + await check( + (Subject> it) => + it..anyOf([(it) => it.emits(), (it) => it.emits()]), + ).hasAsyncDescriptionWhich( + (it) => it.deepEquals([' satisfies any of 2 conditions']), + ); }); test('uses a transaction', () async { final queue = _countingStream(1); await softCheckAsync>( - queue, - (it) => it.anyOf([ - (it) => it.emits((it) => it.equals(10)), - (it) => it.emitsThrough((it) => it.equals(42)), - ])); + queue, + (it) => it.anyOf([ + (it) => it.emits((it) => it.equals(10)), + (it) => it.emitsThrough((it) => it.equals(42)), + ]), + ); await check(queue).emits((it) => it.equals(0)); }); test('consumes events', () async { final queue = _countingStream(3); await check(queue).anyOf([ (it) => it.emits((it) => it.equals(1)), - (it) => it.emitsThrough((it) => it.equals(1)) + (it) => it.emitsThrough((it) => it.equals(1)), ]); await check(queue).emits((it) => it.equals(2)); }); @@ -519,13 +593,15 @@ Future _futureFail() => Future.error(UnimplementedError(), StackTrace.fromString('fake trace')); StreamQueue _countingStream(int count, {int? errorAt}) => StreamQueue( - Stream.fromIterable( - Iterable.generate(count, (index) { - if (index == errorAt) { - Error.throwWithStackTrace(UnimplementedError('Error at $count'), - StackTrace.fromString('fake trace')); - } - return index; - }), - ), - ); + Stream.fromIterable( + Iterable.generate(count, (index) { + if (index == errorAt) { + Error.throwWithStackTrace( + UnimplementedError('Error at $count'), + StackTrace.fromString('fake trace'), + ); + } + return index; + }), + ), +); diff --git a/pkgs/checks/test/extensions/collection_equality_test.dart b/pkgs/checks/test/extensions/collection_equality_test.dart index 28a10dd98..71e7faf6a 100644 --- a/pkgs/checks/test/extensions/collection_equality_test.dart +++ b/pkgs/checks/test/extensions/collection_equality_test.dart @@ -9,126 +9,159 @@ import 'package:test/scaffolding.dart'; void main() { group('deepCollectionEquals', () { test('allows nested collections with equal elements', () { - check(deepCollectionEquals([ - 'a', - {'b': 1}, - {'c', 'd'}, - [ - ['e'] - ], - ], [ - 'a', - {'b': 1}, - {'c', 'd'}, - [ - ['e'] - ], - ])).isNull(); + check( + deepCollectionEquals( + [ + 'a', + {'b': 1}, + {'c', 'd'}, + [ + ['e'], + ], + ], + [ + 'a', + {'b': 1}, + {'c', 'd'}, + [ + ['e'], + ], + ], + ), + ).isNull(); }); test('allows collections inside sets', () { - check(deepCollectionEquals({ - {'a': 1} - }, { - {'a': 1} - })).isNull(); + check( + deepCollectionEquals( + { + {'a': 1}, + }, + { + {'a': 1}, + }, + ), + ).isNull(); }); test('allows collections as Map keys', () { - check(deepCollectionEquals([ - { - {'a': 1}: {'b': 2} - } - ], [ - { - {'a': 1}: {'b': 2} - } - ])).isNull(); + check( + deepCollectionEquals( + [ + { + {'a': 1}: {'b': 2}, + }, + ], + [ + { + {'a': 1}: {'b': 2}, + }, + ], + ), + ).isNull(); }); test('allows conditions in place of elements in lists', () { - check(deepCollectionEquals([ - 'a', - 'b' - ], [ - (Subject it) => it.isA().which((it) => it - ..startsWith('a') - ..length.isLessThan(2)), - (Subject it) => it.isA().startsWith('b') - ])).isNull(); + check( + deepCollectionEquals( + ['a', 'b'], + [ + (Subject it) => it.isA().which( + (it) => + it + ..startsWith('a') + ..length.isLessThan(2), + ), + (Subject it) => it.isA().startsWith('b'), + ], + ), + ).isNull(); }); test('allows conditions in place of values in maps', () { - check(deepCollectionEquals([ - {'a': 'b'} - ], [ - {'a': (Subject it) => it.isA().startsWith('b')} - ])).isNull(); + check( + deepCollectionEquals( + [ + {'a': 'b'}, + ], + [ + {'a': (Subject it) => it.isA().startsWith('b')}, + ], + ), + ).isNull(); }); test('allows conditions in place of elements in sets', () { - check(deepCollectionEquals({ - 'b', - 'a' - }, { - 'a', - (Subject it) => it.isA().startsWith('b') - })).isNull(); + check( + deepCollectionEquals( + {'b', 'a'}, + {'a', (Subject it) => it.isA().startsWith('b')}, + ), + ).isNull(); }); test('allows conditions in place of keys in maps', () { - check(deepCollectionEquals({ - 'a': 'b' - }, { - (Subject it) => it.isA().startsWith('a'): 'b' - })).isNull(); + check( + deepCollectionEquals( + {'a': 'b'}, + {(Subject it) => it.isA().startsWith('a'): 'b'}, + ), + ).isNull(); }); test('reports non-Set elements', () { - check(deepCollectionEquals([ - ['a'] - ], [ - {'a'} - ])).isNotNull().deepEquals(['at [<0>] is not a Set']); + check( + deepCollectionEquals( + [ + ['a'], + ], + [ + {'a'}, + ], + ), + ).isNotNull().deepEquals(['at [<0>] is not a Set']); }); test('reports long iterables', () { check(deepCollectionEquals([0], [])).isNotNull().deepEquals([ 'has more elements than expected', - 'expected an iterable with 0 element(s)' + 'expected an iterable with 0 element(s)', ]); }); test('reports short iterables', () { check(deepCollectionEquals([], [0])).isNotNull().deepEquals([ 'has too few elements', - 'expected an iterable with at least 1 element(s)' + 'expected an iterable with at least 1 element(s)', ]); }); test('reports unequal elements in iterables', () { - check(deepCollectionEquals([0], [1])) - .isNotNull() - .deepEquals(['at [<0>] is <0>', 'which does not equal <1>']); + check( + deepCollectionEquals([0], [1]), + ).isNotNull().deepEquals(['at [<0>] is <0>', 'which does not equal <1>']); }); test('reports unmet conditions in iterables', () { - check(deepCollectionEquals( - [0], [(Subject it) => it.isA().isGreaterThan(0)])) - .isNotNull() - .deepEquals([ + check( + deepCollectionEquals( + [0], + [(Subject it) => it.isA().isGreaterThan(0)], + ), + ).isNotNull().deepEquals([ 'has an element at [<0>] that:', ' Actual: <0>', - ' which is not greater than <0>' + ' which is not greater than <0>', ]); }); test('reports unmet conditions in map values', () { - check(deepCollectionEquals({ - 'a': 'b' - }, { - 'a': (Subject it) => it.isA().startsWith('a') - })).isNotNull().deepEquals([ + check( + deepCollectionEquals( + {'a': 'b'}, + {'a': (Subject it) => it.isA().startsWith('a')}, + ), + ).isNotNull().deepEquals([ "has an element at ['a'] that:", " Actual: 'b'", " which does not start with 'a'", @@ -136,11 +169,12 @@ void main() { }); test('reports unmet conditions in map keys', () { - check(deepCollectionEquals({ - 'b': 'a' - }, { - (Subject it) => it.isA().startsWith('a'): 'a' - })).isNotNull().deepEquals([ + check( + deepCollectionEquals( + {'b': 'a'}, + {(Subject it) => it.isA().startsWith('a'): 'a'}, + ), + ).isNotNull().deepEquals([ 'has no entry to match : 'a'", @@ -148,15 +182,20 @@ void main() { }); test('maintains paths through maps when the keys are all values', () { - check(deepCollectionEquals({ - 'a': [ - {'b': 'c'} - ] - }, { - 'a': [ - {'b': 'd'} - ] - })).isNotNull().deepEquals([ + check( + deepCollectionEquals( + { + 'a': [ + {'b': 'c'}, + ], + }, + { + 'a': [ + {'b': 'd'}, + ], + }, + ), + ).isNotNull().deepEquals([ "at ['a'][<0>]['b'] is 'c'", "which does not equal 'd'", ]); @@ -165,33 +204,33 @@ void main() { test('reports recursive lists', () { var l = []; l.add(l); - check(deepCollectionEquals(l, l)) - .isNotNull() - .deepEquals(['exceeds the depth limit of 1000']); + check( + deepCollectionEquals(l, l), + ).isNotNull().deepEquals(['exceeds the depth limit of 1000']); }); test('reports recursive sets', () { var s = {}; s.add(s); - check(deepCollectionEquals(s, s)) - .isNotNull() - .deepEquals(['exceeds the depth limit of 1000']); + check( + deepCollectionEquals(s, s), + ).isNotNull().deepEquals(['exceeds the depth limit of 1000']); }); test('reports maps with recursive keys', () { var m = {}; m[m] = 0; - check(deepCollectionEquals(m, m)) - .isNotNull() - .deepEquals(['exceeds the depth limit of 1000']); + check( + deepCollectionEquals(m, m), + ).isNotNull().deepEquals(['exceeds the depth limit of 1000']); }); test('reports maps with recursive values', () { var m = {}; m[0] = m; - check(deepCollectionEquals(m, m)) - .isNotNull() - .deepEquals(['exceeds the depth limit of 1000']); + check( + deepCollectionEquals(m, m), + ).isNotNull().deepEquals(['exceeds the depth limit of 1000']); }); }); } diff --git a/pkgs/checks/test/extensions/core_test.dart b/pkgs/checks/test/extensions/core_test.dart index 2133c3646..33833d547 100644 --- a/pkgs/checks/test/extensions/core_test.dart +++ b/pkgs/checks/test/extensions/core_test.dart @@ -20,14 +20,18 @@ void main() { check(1).has((v) => v.isOdd, 'isOdd').isTrue(); check(null).isRejectedBy( - (it) => it.has((v) { - Error.throwWithStackTrace( - UnimplementedError(), StackTrace.fromString('fake trace')); - }, 'foo').isNotNull(), - which: [ - 'threw while trying to read foo: ', - 'fake trace' - ]); + (it) => + it.has((v) { + Error.throwWithStackTrace( + UnimplementedError(), + StackTrace.fromString('fake trace'), + ); + }, 'foo').isNotNull(), + which: [ + 'threw while trying to read foo: ', + 'fake trace', + ], + ); }); test('which', () { @@ -36,22 +40,26 @@ void main() { test('not', () { check(false).not((it) => it.isTrue()); - check(true).isRejectedBy((it) => it.not((it) => it.isTrue()), which: [ - 'is a value that: ', - ' is true', - ]); + check(true).isRejectedBy( + (it) => it.not((it) => it.isTrue()), + which: ['is a value that: ', ' is true'], + ); }); group('anyOf', () { test('succeeds for happy case', () { - check(-10) - .anyOf([(it) => it.isGreaterThan(1), (it) => it.isLessThan(-1)]); + check( + -10, + ).anyOf([(it) => it.isGreaterThan(1), (it) => it.isLessThan(-1)]); }); test('rejects values that do not satisfy any condition', () { check(0).isRejectedBy( - (it) => it.anyOf( - [(it) => it.isGreaterThan(1), (it) => it.isLessThan(-1)]), - which: ['did not match any condition']); + (it) => it.anyOf([ + (it) => it.isGreaterThan(1), + (it) => it.isLessThan(-1), + ]), + which: ['did not match any condition'], + ); }); }); }); @@ -79,8 +87,9 @@ void main() { test('identical', () { check(1).identicalTo(1); - check(1) - .isRejectedBy((it) => it.identicalTo(2), which: ['is not identical']); + check( + 1, + ).isRejectedBy((it) => it.identicalTo(2), which: ['is not identical']); }); }); group('NullabilityChecks', () { @@ -99,64 +108,76 @@ void main() { group('ComparableChecks on Duration', () { group('isGreaterThan', () { test('succeeds for greater', () { - check(const Duration(seconds: 10)) - .isGreaterThan(const Duration(seconds: 1)); + check( + const Duration(seconds: 10), + ).isGreaterThan(const Duration(seconds: 1)); }); test('fails for equal', () { check(const Duration(seconds: 10)).isRejectedBy( - (it) => it.isGreaterThan(const Duration(seconds: 10)), - which: ['is not greater than <0:00:10.000000>']); + (it) => it.isGreaterThan(const Duration(seconds: 10)), + which: ['is not greater than <0:00:10.000000>'], + ); }); test('fails for less', () { check(const Duration(seconds: 10)).isRejectedBy( - (it) => it.isGreaterThan(const Duration(seconds: 50)), - which: ['is not greater than <0:00:50.000000>']); + (it) => it.isGreaterThan(const Duration(seconds: 50)), + which: ['is not greater than <0:00:50.000000>'], + ); }); }); group('isGreaterOrEqual', () { test('succeeds for greater', () { - check(const Duration(seconds: 10)) - .isGreaterOrEqual(const Duration(seconds: 1)); + check( + const Duration(seconds: 10), + ).isGreaterOrEqual(const Duration(seconds: 1)); }); test('succeeds for equal', () { - check(const Duration(seconds: 10)) - .isGreaterOrEqual(const Duration(seconds: 10)); + check( + const Duration(seconds: 10), + ).isGreaterOrEqual(const Duration(seconds: 10)); }); test('fails for less', () { check(const Duration(seconds: 10)).isRejectedBy( - (it) => it.isGreaterOrEqual(const Duration(seconds: 50)), - which: ['is not greater than or equal to <0:00:50.000000>']); + (it) => it.isGreaterOrEqual(const Duration(seconds: 50)), + which: ['is not greater than or equal to <0:00:50.000000>'], + ); }); }); group('isLessThan', () { test('succeeds for less', () { - check(const Duration(seconds: 1)) - .isLessThan(const Duration(seconds: 10)); + check( + const Duration(seconds: 1), + ).isLessThan(const Duration(seconds: 10)); }); test('fails for equal', () { check(const Duration(seconds: 10)).isRejectedBy( - (it) => it.isLessThan(const Duration(seconds: 10)), - which: ['is not less than <0:00:10.000000>']); + (it) => it.isLessThan(const Duration(seconds: 10)), + which: ['is not less than <0:00:10.000000>'], + ); }); test('fails for greater', () { check(const Duration(seconds: 50)).isRejectedBy( - (it) => it.isLessThan(const Duration(seconds: 10)), - which: ['is not less than <0:00:10.000000>']); + (it) => it.isLessThan(const Duration(seconds: 10)), + which: ['is not less than <0:00:10.000000>'], + ); }); }); group('isLessOrEqual', () { test('succeeds for less', () { - check(const Duration(seconds: 10)) - .isLessOrEqual(const Duration(seconds: 50)); + check( + const Duration(seconds: 10), + ).isLessOrEqual(const Duration(seconds: 50)); }); test('succeeds for equal', () { - check(const Duration(seconds: 10)) - .isLessOrEqual(const Duration(seconds: 10)); + check( + const Duration(seconds: 10), + ).isLessOrEqual(const Duration(seconds: 10)); }); test('fails for greater', () { check(const Duration(seconds: 10)).isRejectedBy( - (it) => it.isLessOrEqual(const Duration(seconds: 1)), - which: ['is not less than or equal to <0:00:01.000000>']); + (it) => it.isLessOrEqual(const Duration(seconds: 1)), + which: ['is not less than or equal to <0:00:01.000000>'], + ); }); }); }); diff --git a/pkgs/checks/test/extensions/function_test.dart b/pkgs/checks/test/extensions/function_test.dart index 034d8fefd..aefba1155 100644 --- a/pkgs/checks/test/extensions/function_test.dart +++ b/pkgs/checks/test/extensions/function_test.dart @@ -14,9 +14,11 @@ void main() { check(() => throw StateError('oops!')).throws(); }); test('fails for functions that return normally', () { - check(() {}).isRejectedBy((it) => it.throws(), - actual: ['a function that returned '], - which: ['did not throw']); + check(() {}).isRejectedBy( + (it) => it.throws(), + actual: ['a function that returned '], + which: ['did not throw'], + ); }); test('fails for functions that throw the wrong type', () { check(() => throw StateError('oops!')).isRejectedBy( @@ -34,10 +36,14 @@ void main() { test('fails for functions that throw', () { check(() { Error.throwWithStackTrace( - StateError('oops!'), StackTrace.fromString('fake trace')); - }).isRejectedBy((it) => it.returnsNormally(), - actual: ['a function that throws'], - which: ['threw ', 'fake trace']); + StateError('oops!'), + StackTrace.fromString('fake trace'), + ); + }).isRejectedBy( + (it) => it.returnsNormally(), + actual: ['a function that throws'], + which: ['threw ', 'fake trace'], + ); }); }); }); diff --git a/pkgs/checks/test/extensions/iterable_test.dart b/pkgs/checks/test/extensions/iterable_test.dart index dafd84d74..672c5b47e 100644 --- a/pkgs/checks/test/extensions/iterable_test.dart +++ b/pkgs/checks/test/extensions/iterable_test.dart @@ -19,8 +19,9 @@ void main() { check(_testIterable).first.equals(0); }); test('rejects empty iterable', () { - check([]) - .isRejectedBy((it) => it.first.equals(0), which: ['has no elements']); + check( + [], + ).isRejectedBy((it) => it.first.equals(0), which: ['has no elements']); }); }); @@ -29,8 +30,9 @@ void main() { check(_testIterable).last.equals(1); }); test('rejects empty iterable', () { - check([]) - .isRejectedBy((it) => it.last.equals(0), which: ['has no elements']); + check( + [], + ).isRejectedBy((it) => it.last.equals(0), which: ['has no elements']); }); }); @@ -39,36 +41,44 @@ void main() { check([42]).single.equals(42); }); test('rejects empty iterable', () { - check([]).isRejectedBy((it) => it.single.equals(0), - which: ['has no elements']); + check( + [], + ).isRejectedBy((it) => it.single.equals(0), which: ['has no elements']); }); test('rejects iterable with too many elements', () { - check(_testIterable).isRejectedBy((it) => it.single.equals(0), - which: ['has more than one element']); + check(_testIterable).isRejectedBy( + (it) => it.single.equals(0), + which: ['has more than one element'], + ); }); }); test('isEmpty', () { check([]).isEmpty(); - check(_testIterable) - .isRejectedBy((it) => it.isEmpty(), which: ['is not empty']); + check( + _testIterable, + ).isRejectedBy((it) => it.isEmpty(), which: ['is not empty']); }); test('isNotEmpty', () { check(_testIterable).isNotEmpty(); - check(const Iterable.empty()) - .isRejectedBy((it) => it.isNotEmpty(), which: ['is empty']); + check( + const Iterable.empty(), + ).isRejectedBy((it) => it.isNotEmpty(), which: ['is empty']); }); test('contains', () { check(_testIterable).contains(0); - check(_testIterable) - .isRejectedBy((it) => it.contains(2), which: ['does not contain <2>']); + check( + _testIterable, + ).isRejectedBy((it) => it.contains(2), which: ['does not contain <2>']); }); test('any', () { check(_testIterable).any((it) => it.equals(1)); - check(_testIterable).isRejectedBy((it) => it.any((it) => it.equals(2)), - which: ['Contains no matching element']); + check(_testIterable).isRejectedBy( + (it) => it.any((it) => it.equals(2)), + which: ['Contains no matching element'], + ); }); group('containsInOrder', () { @@ -76,39 +86,45 @@ void main() { check([0, 1, 0, 2, 0, 3]).containsInOrder([1, 2, 3]); }); test('can use Condition', () { - check([0, 1]).containsInOrder( - [(Subject it) => it.isA().isGreaterThan(0)]); + check([0, 1]).containsInOrder([ + (Subject it) => it.isA().isGreaterThan(0), + ]); }); test('can use Condition', () { check([0, 1]).containsInOrder([(Subject it) => it.isGreaterThan(0)]); }); test('fails for not found elements by equality', () async { - check([0]).isRejectedBy((it) => it.containsInOrder([1]), which: [ - 'did not have an element matching the expectation at index 0 <1>' - ]); + check([0]).isRejectedBy( + (it) => it.containsInOrder([1]), + which: [ + 'did not have an element matching the expectation at index 0 <1>', + ], + ); }); test('fails for not found elements by condition', () async { check([0]).isRejectedBy( - (it) => it.containsInOrder( - [(Subject it) => it.isA().isGreaterThan(0)]), - which: [ - 'did not have an element matching the expectation at index 0 ' - '>' - ]); + (it) => it.containsInOrder([ + (Subject it) => it.isA().isGreaterThan(0), + ]), + which: [ + 'did not have an element matching the expectation at index 0 ' + '>', + ], + ); }); test('can be described', () { - check((Subject it) => it.containsInOrder([1, 2, 3])) - .description - .deepEquals([' contains, in order: [1, 2, 3]']); - check((Subject it) => - it.containsInOrder([1, (Subject it) => it.equals(2)])) - .description - .deepEquals([ + check( + (Subject it) => it.containsInOrder([1, 2, 3]), + ).description.deepEquals([' contains, in order: [1, 2, 3]']); + check( + (Subject it) => + it.containsInOrder([1, (Subject it) => it.equals(2)]), + ).description.deepEquals([ ' contains, in order: [1,', ' >]' + ' equals <2>>]', ]); }); }); @@ -123,19 +139,22 @@ void main() { }); test('fails for not found elements', () async { check([0]).isRejectedBy( - (it) => it.containsMatchingInOrder([(it) => it.isGreaterThan(0)]), - which: [ - 'did not have an element matching the expectation at index 0 ' - '>' - ]); + (it) => it.containsMatchingInOrder([(it) => it.isGreaterThan(0)]), + which: [ + 'did not have an element matching the expectation at index 0 ' + '>', + ], + ); }); test('can be described', () { - check((Subject> it) => it.containsMatchingInOrder([ - (it) => it.isLessThan(2), - (it) => it.isLessThan(3), - (it) => it.isLessThan(4), - ])).description.deepEquals([ + check( + (Subject> it) => it.containsMatchingInOrder([ + (it) => it.isLessThan(2), + (it) => it.isLessThan(3), + (it) => it.isLessThan(4), + ]), + ).description.deepEquals([ ' contains, in order: [>,', ' >]', ]); - check((Subject> it) => it.containsMatchingInOrder( - [(it) => it.equals(1), (it) => it.equals(2)])) - .description - .deepEquals([ + check( + (Subject> it) => it.containsMatchingInOrder([ + (it) => it.equals(1), + (it) => it.equals(2), + ]), + ).description.deepEquals([ ' contains, in order: [>,', ' >]' + ' equals <2>>]', ]); }); }); @@ -160,19 +181,20 @@ void main() { check([0, 1, 0, 2, 0, 3]).containsEqualInOrder([1, 2, 3]); }); test('fails for not found elements', () async { - check([0]).isRejectedBy((it) => it.containsEqualInOrder([1]), which: [ - 'did not have an element equal to the expectation at index 0 <1>' - ]); + check([0]).isRejectedBy( + (it) => it.containsEqualInOrder([1]), + which: [ + 'did not have an element equal to the expectation at index 0 <1>', + ], + ); }); test('can be described', () { - check((Subject> it) => it.containsEqualInOrder([1, 2, 3])) - .description - .deepEquals([' contains, in order: [1, 2, 3]']); - check((Subject> it) => it.containsEqualInOrder([1, 2])) - .description - .deepEquals([ - ' contains, in order: [1, 2]', - ]); + check( + (Subject> it) => it.containsEqualInOrder([1, 2, 3]), + ).description.deepEquals([' contains, in order: [1, 2, 3]']); + check( + (Subject> it) => it.containsEqualInOrder([1, 2]), + ).description.deepEquals([' contains, in order: [1, 2]']); }); }); group('every', () { @@ -181,12 +203,14 @@ void main() { }); test('includes details of first failing element', () async { - check(_testIterable) - .isRejectedBy((it) => it.every((it) => it.isLessThan(0)), which: [ - 'has an element at index 0 that:', - ' Actual: <0>', - ' Which: is not less than <0>', - ]); + check(_testIterable).isRejectedBy( + (it) => it.every((it) => it.isLessThan(0)), + which: [ + 'has an element at index 0 that:', + ' Actual: <0>', + ' Which: is not less than <0>', + ], + ); }); }); @@ -197,79 +221,101 @@ void main() { test('reports unmatched elements', () { check(_testIterable).isRejectedBy( - (it) => it.unorderedEquals(_testIterable.followedBy([42, 100])), - which: [ - 'has no element equal to the expected element at index 2: <42>', - 'or 1 other elements' - ]); + (it) => it.unorderedEquals(_testIterable.followedBy([42, 100])), + which: [ + 'has no element equal to the expected element at index 2: <42>', + 'or 1 other elements', + ], + ); }); test('reports unexpected elements', () { - check(_testIterable.followedBy([42, 100])) - .isRejectedBy((it) => it.unorderedEquals(_testIterable), which: [ - 'has an unexpected element at index 2: <42>', - 'and 1 other unexpected elements' - ]); + check(_testIterable.followedBy([42, 100])).isRejectedBy( + (it) => it.unorderedEquals(_testIterable), + which: [ + 'has an unexpected element at index 2: <42>', + 'and 1 other unexpected elements', + ], + ); }); }); group('unorderedMatches', () { test('success for happy case', () { check(_testIterable).unorderedMatches( - _testIterable.toList().reversed.map((i) => (it) => it.equals(i))); + _testIterable.toList().reversed.map((i) => (it) => it.equals(i)), + ); }); test('reports unmatched elements', () { check(_testIterable).isRejectedBy( - (it) => it.unorderedMatches(_testIterable - .followedBy([42, 100]).map((i) => (it) => it.equals(i))), - which: [ - 'has no element matching the condition at index 2:', - ' equals <42>', - 'or 1 other conditions' - ]); + (it) => it.unorderedMatches( + _testIterable.followedBy([42, 100]).map((i) => (it) => it.equals(i)), + ), + which: [ + 'has no element matching the condition at index 2:', + ' equals <42>', + 'or 1 other conditions', + ], + ); }); test('reports unexpected elements', () { check(_testIterable.followedBy([42, 100])).isRejectedBy( - (it) => it - .unorderedMatches(_testIterable.map((i) => (it) => it.equals(i))), - which: [ - 'has an unmatched element at index 2: <42>', - 'and 1 other unmatched elements' - ]); + (it) => + it.unorderedMatches(_testIterable.map((i) => (it) => it.equals(i))), + which: [ + 'has an unmatched element at index 2: <42>', + 'and 1 other unmatched elements', + ], + ); }); }); group('pairwiseMatches', () { test('succeeds for the happy path', () { - check(_testIterable).pairwiseMatches([1, 2], - (expected) => (it) => it.isLessThan(expected), 'is less than'); + check(_testIterable).pairwiseMatches( + [1, 2], + (expected) => (it) => it.isLessThan(expected), + 'is less than', + ); }); test('fails for mismatched element', () async { check(_testIterable).isRejectedBy( - (it) => it.pairwiseMatches([1, 1], - (expected) => (it) => it.isLessThan(expected), 'is less than'), - which: [ - 'does not have an element at index 1 that:', - ' is less than <1>', - 'Actual element at index 1: <1>', - 'Which: is not less than <1>' - ]); + (it) => it.pairwiseMatches( + [1, 1], + (expected) => (it) => it.isLessThan(expected), + 'is less than', + ), + which: [ + 'does not have an element at index 1 that:', + ' is less than <1>', + 'Actual element at index 1: <1>', + 'Which: is not less than <1>', + ], + ); }); test('fails for too few elements', () { check(_testIterable).isRejectedBy( - (it) => it.pairwiseMatches([1, 2, 3], - (expected) => (it) => it.isLessThan(expected), 'is less than'), - which: [ - 'has too few elements, there is no element to match at index 2' - ]); + (it) => it.pairwiseMatches( + [1, 2, 3], + (expected) => (it) => it.isLessThan(expected), + 'is less than', + ), + which: [ + 'has too few elements, there is no element to match at index 2', + ], + ); }); test('fails for too many elements', () { check(_testIterable).isRejectedBy( - (it) => it.pairwiseMatches([1], - (expected) => (it) => it.isLessThan(expected), 'is less than'), - which: ['has too many elements, expected exactly 1']); + (it) => it.pairwiseMatches( + [1], + (expected) => (it) => it.isLessThan(expected), + 'is less than', + ), + which: ['has too many elements, expected exactly 1'], + ); }); }); } diff --git a/pkgs/checks/test/extensions/map_test.dart b/pkgs/checks/test/extensions/map_test.dart index cb3e3e493..69c87bf98 100644 --- a/pkgs/checks/test/extensions/map_test.dart +++ b/pkgs/checks/test/extensions/map_test.dart @@ -7,10 +7,7 @@ import 'package:test/scaffolding.dart'; import '../test_shared.dart'; -const _testMap = { - 'a': 1, - 'b': 2, -}; +const _testMap = {'a': 1, 'b': 2}; void main() { test('length', () { @@ -18,10 +15,11 @@ void main() { }); test('entries', () { check(_testMap).entries.any( - (it) => it + (it) => + it ..has((p0) => p0.key, 'key').equals('a') ..has((p0) => p0.value, 'value').equals(1), - ); + ); }); test('keys', () { check(_testMap).keys.contains('a'); @@ -35,19 +33,17 @@ void main() { check(_testMap)['a'].equals(1); }); test('fails for a missing key', () { - check(_testMap).isRejectedBy((it) => it['z'], - which: ["does not contain the key 'z'"]); + check( + _testMap, + ).isRejectedBy((it) => it['z'], which: ["does not contain the key 'z'"]); }); test('can be described', () { check((Subject> it) => it['some\nlong\nkey']) .description - .deepEquals([ - " contains a value for 'some", - ' long', - " key'", - ]); - check((Subject> it) => - it['some\nlong\nkey'].equals(1)).description.deepEquals([ + .deepEquals([" contains a value for 'some", ' long', " key'"]); + check( + (Subject> it) => it['some\nlong\nkey'].equals(1), + ).description.deepEquals([ " contains a value for 'some", ' long', " key' that:", @@ -61,8 +57,9 @@ void main() { }); test('isNotEmpty', () { check(_testMap).isNotEmpty(); - check({}) - .isRejectedBy((it) => it.isNotEmpty(), which: ['is not empty']); + check( + {}, + ).isRejectedBy((it) => it.isNotEmpty(), which: ['is not empty']); }); group('containsKey', () { test('succeeds for a key that exists', () { @@ -75,12 +72,9 @@ void main() { ); }); test('can be described', () { - check((Subject> it) => - it.containsKey('some\nlong\nkey')).description.deepEquals([ - " contains key 'some", - ' long', - " key'", - ]); + check( + (Subject> it) => it.containsKey('some\nlong\nkey'), + ).description.deepEquals([" contains key 'some", ' long', " key'"]); }); }); test('containsKeyThat', () { @@ -101,12 +95,10 @@ void main() { ); }); test('can be described', () { - check((Subject> it) => - it.containsValue('some\nlong\nkey')).description.deepEquals([ - " contains value 'some", - ' long', - " key'", - ]); + check( + (Subject> it) => + it.containsValue('some\nlong\nkey'), + ).description.deepEquals([" contains value 'some", ' long', " key'"]); }); }); test('containsValueThat', () { diff --git a/pkgs/checks/test/extensions/math_test.dart b/pkgs/checks/test/extensions/math_test.dart index 0f346d34f..d9c7fc337 100644 --- a/pkgs/checks/test/extensions/math_test.dart +++ b/pkgs/checks/test/extensions/math_test.dart @@ -29,8 +29,9 @@ void main() { check(42.1).isNotNaN(); }); test('fails for NaN', () { - check(double.nan).isRejectedBy((it) => it.isNotNaN(), - which: ['is not a number (NaN)']); + check( + double.nan, + ).isRejectedBy((it) => it.isNotNaN(), which: ['is not a number (NaN)']); }); }); group('isNegative', () { @@ -41,8 +42,9 @@ void main() { check(-0.0).isNegative(); }); test('fails for zero', () { - check(0) - .isRejectedBy((it) => it.isNegative(), which: ['is not negative']); + check( + 0, + ).isRejectedBy((it) => it.isNegative(), which: ['is not negative']); }); }); group('isNotNegative', () { @@ -53,12 +55,14 @@ void main() { check(0).isNotNegative(); }); test('fails for -0.0', () { - check(-0.0) - .isRejectedBy((it) => it.isNotNegative(), which: ['is negative']); + check( + -0.0, + ).isRejectedBy((it) => it.isNotNegative(), which: ['is negative']); }); test('fails for negative numbers', () { - check(-1) - .isRejectedBy((it) => it.isNotNegative(), which: ['is negative']); + check( + -1, + ).isRejectedBy((it) => it.isNotNegative(), which: ['is negative']); }); }); @@ -67,16 +71,19 @@ void main() { check(1).isFinite(); }); test('fails for NaN', () { - check(double.nan) - .isRejectedBy((it) => it.isFinite(), which: ['is not finite']); + check( + double.nan, + ).isRejectedBy((it) => it.isFinite(), which: ['is not finite']); }); test('fails for infinity', () { - check(double.infinity) - .isRejectedBy((it) => it.isFinite(), which: ['is not finite']); + check( + double.infinity, + ).isRejectedBy((it) => it.isFinite(), which: ['is not finite']); }); test('fails for negative infinity', () { - check(double.negativeInfinity) - .isRejectedBy((it) => it.isFinite(), which: ['is not finite']); + check( + double.negativeInfinity, + ).isRejectedBy((it) => it.isFinite(), which: ['is not finite']); }); }); group('isNotFinite', () { @@ -101,12 +108,14 @@ void main() { check(double.negativeInfinity).isInfinite(); }); test('fails for NaN', () { - check(double.nan) - .isRejectedBy((it) => it.isInfinite(), which: ['is not infinite']); + check( + double.nan, + ).isRejectedBy((it) => it.isInfinite(), which: ['is not infinite']); }); test('fails for finite numbers', () { - check(1) - .isRejectedBy((it) => it.isInfinite(), which: ['is not infinite']); + check( + 1, + ).isRejectedBy((it) => it.isInfinite(), which: ['is not infinite']); }); }); @@ -118,12 +127,14 @@ void main() { check(double.nan).isNotInfinite(); }); test('fails for infinity', () { - check(double.infinity) - .isRejectedBy((it) => it.isNotInfinite(), which: ['is infinite']); + check( + double.infinity, + ).isRejectedBy((it) => it.isNotInfinite(), which: ['is infinite']); }); test('fails for negative infinity', () { - check(double.negativeInfinity) - .isRejectedBy((it) => it.isNotInfinite(), which: ['is infinite']); + check( + double.negativeInfinity, + ).isRejectedBy((it) => it.isNotInfinite(), which: ['is infinite']); }); }); group('closeTo', () { @@ -137,12 +148,14 @@ void main() { check(1).isCloseTo(2, 1); }); test('fails for low values', () { - check(1).isRejectedBy((it) => it.isCloseTo(3, 1), - which: ['differs by <2>']); + check( + 1, + ).isRejectedBy((it) => it.isCloseTo(3, 1), which: ['differs by <2>']); }); test('fails for high values', () { - check(5).isRejectedBy((it) => it.isCloseTo(3, 1), - which: ['differs by <2>']); + check( + 5, + ).isRejectedBy((it) => it.isCloseTo(3, 1), which: ['differs by <2>']); }); }); }); diff --git a/pkgs/checks/test/extensions/string_test.dart b/pkgs/checks/test/extensions/string_test.dart index 2b651f1c2..0fbca2d96 100644 --- a/pkgs/checks/test/extensions/string_test.dart +++ b/pkgs/checks/test/extensions/string_test.dart @@ -11,8 +11,10 @@ void main() { group('StringChecks', () { test('contains', () { check('bob').contains('bo'); - check('bob').isRejectedBy((it) => it.contains('kayleb'), - which: ["Does not contain 'kayleb'"]); + check('bob').isRejectedBy( + (it) => it.contains('kayleb'), + which: ["Does not contain 'kayleb'"], + ); }); test('length', () { check('bob').length.equals(3); @@ -27,13 +29,17 @@ void main() { }); test('startsWith', () { check('bob').startsWith('bo'); - check('bob').isRejectedBy((it) => it.startsWith('kayleb'), - which: ["does not start with 'kayleb'"]); + check('bob').isRejectedBy( + (it) => it.startsWith('kayleb'), + which: ["does not start with 'kayleb'"], + ); }); test('endsWith', () { check('bob').endsWith('ob'); - check('bob').isRejectedBy((it) => it.endsWith('kayleb'), - which: ["does not end with 'kayleb'"]); + check('bob').isRejectedBy( + (it) => it.endsWith('kayleb'), + which: ["does not end with 'kayleb'"], + ); }); group('matches', () { @@ -44,22 +50,26 @@ void main() { check(r'\d').matchesPattern(r'\d'); }); test('fails for non-matching regex', () { - check('abc').isRejectedBy((it) => it.matchesPattern(RegExp(r'\d\d\d')), - which: [r'does not match ']); + check('abc').isRejectedBy( + (it) => it.matchesPattern(RegExp(r'\d\d\d')), + which: [r'does not match '], + ); }); test('fails for non-matching string pattern', () { // A string is _not_ converted to a regex, string patterns must match // directly. - check('123').isRejectedBy((it) => it.matchesPattern(r'\d\d\d'), - which: [r"does not match '\\d\\d\\d'"]); + check('123').isRejectedBy( + (it) => it.matchesPattern(r'\d\d\d'), + which: [r"does not match '\\d\\d\\d'"], + ); }); test('can be described', () { check((Subject it) => it.matchesPattern(RegExp(r'\d\d\d'))) .description .deepEquals([r' matches ']); - check((Subject it) => it.matchesPattern('abc')) - .description - .deepEquals([r" matches 'abc'"]); + check( + (Subject it) => it.matchesPattern('abc'), + ).description.deepEquals([r" matches 'abc'"]); }); }); @@ -68,15 +78,19 @@ void main() { check('foo bar baz').containsInOrder(['foo', 'baz']); }); test('reports when first substring is missing', () { - check('baz').isRejectedBy((it) => it.containsInOrder(['foo', 'baz']), - which: ['does not have a match for the substring \'foo\'']); + check('baz').isRejectedBy( + (it) => it.containsInOrder(['foo', 'baz']), + which: ['does not have a match for the substring \'foo\''], + ); }); test('reports when substring is missing following a match', () { - check('foo bar') - .isRejectedBy((it) => it.containsInOrder(['foo', 'baz']), which: [ - 'does not have a match for the substring \'baz\'', - 'following the other matches up to character 3' - ]); + check('foo bar').isRejectedBy( + (it) => it.containsInOrder(['foo', 'baz']), + which: [ + 'does not have a match for the substring \'baz\'', + 'following the other matches up to character 3', + ], + ); }); }); @@ -88,55 +102,68 @@ void main() { check('').equals(''); }); test('reports extra characters for long string', () { - check('foobar').isRejectedBy((it) => it.equals('foo'), - which: ['is too long with unexpected trailing characters:', 'bar']); + check('foobar').isRejectedBy( + (it) => it.equals('foo'), + which: ['is too long with unexpected trailing characters:', 'bar'], + ); }); test('reports extra characters for long string against empty', () { - check('foo').isRejectedBy((it) => it.equals(''), - which: ['is not the empty string']); + check('foo').isRejectedBy( + (it) => it.equals(''), + which: ['is not the empty string'], + ); }); test('reports truncated extra characters for very long string', () { - check('foobar baz more stuff').isRejectedBy((it) => it.equals('foo'), - which: [ - 'is too long with unexpected trailing characters:', - 'bar baz mo ...' - ]); + check('foobar baz more stuff').isRejectedBy( + (it) => it.equals('foo'), + which: [ + 'is too long with unexpected trailing characters:', + 'bar baz mo ...', + ], + ); }); test('reports missing characters for short string', () { - check('foo').isRejectedBy((it) => it.equals('foobar'), - which: ['is too short with missing trailing characters:', 'bar']); + check('foo').isRejectedBy( + (it) => it.equals('foobar'), + which: ['is too short with missing trailing characters:', 'bar'], + ); }); test('reports missing characters for empty string', () { - check('').isRejectedBy((it) => it.equals('foo bar baz'), - actual: ['an empty string'], - which: ['is missing all expected characters:', 'foo bar ba ...']); + check('').isRejectedBy( + (it) => it.equals('foo bar baz'), + actual: ['an empty string'], + which: ['is missing all expected characters:', 'foo bar ba ...'], + ); }); test('reports truncated missing characters for very short string', () { - check('foo').isRejectedBy((it) => it.equals('foobar baz more stuff'), - which: [ - 'is too short with missing trailing characters:', - 'bar baz mo ...' - ]); + check('foo').isRejectedBy( + (it) => it.equals('foobar baz more stuff'), + which: [ + 'is too short with missing trailing characters:', + 'bar baz mo ...', + ], + ); }); test('reports index of different character', () { - check('hit').isRejectedBy((it) => it.equals('hat'), which: [ - 'differs at offset 1:', - 'hat', - 'hit', - ' ^', - ]); - }); - test('reports truncated index of different character in large string', - () { - check('blah blah blah hit blah blah blah').isRejectedBy( + check('hit').isRejectedBy( + (it) => it.equals('hat'), + which: ['differs at offset 1:', 'hat', 'hit', ' ^'], + ); + }); + test( + 'reports truncated index of different character in large string', + () { + check('blah blah blah hit blah blah blah').isRejectedBy( (it) => it.equals('blah blah blah hat blah blah blah'), which: [ 'differs at offset 16:', '... lah blah hat blah bl ...', '... lah blah hit blah bl ...', ' ^', - ]); - }); + ], + ); + }, + ); }); group('equalsIgnoringCase', () { @@ -145,20 +172,22 @@ void main() { check('foo').equalsIgnoringCase('FOO'); }); test('reports original extra characters for long string', () { - check('FOOBAR').isRejectedBy((it) => it.equalsIgnoringCase('foo'), - which: ['is too long with unexpected trailing characters:', 'BAR']); + check('FOOBAR').isRejectedBy( + (it) => it.equalsIgnoringCase('foo'), + which: ['is too long with unexpected trailing characters:', 'BAR'], + ); }); test('reports original missing characters for short string', () { - check('FOO').isRejectedBy((it) => it.equalsIgnoringCase('fooBAR'), - which: ['is too short with missing trailing characters:', 'BAR']); + check('FOO').isRejectedBy( + (it) => it.equalsIgnoringCase('fooBAR'), + which: ['is too short with missing trailing characters:', 'BAR'], + ); }); test('reports index of different character with original characters', () { - check('HiT').isRejectedBy((it) => it.equalsIgnoringCase('hAt'), which: [ - 'differs at offset 1:', - 'hAt', - 'HiT', - ' ^', - ]); + check('HiT').isRejectedBy( + (it) => it.equalsIgnoringCase('hAt'), + which: ['differs at offset 1:', 'hAt', 'HiT', ' ^'], + ); }); }); @@ -174,26 +203,21 @@ void main() { }); test('reports original extra characters for long string', () { check('foo \t bar \n baz').isRejectedBy( - (it) => it.equalsIgnoringWhitespace('foo bar'), - which: [ - 'is too long with unexpected trailing characters:', - ' baz' - ]); + (it) => it.equalsIgnoringWhitespace('foo bar'), + which: ['is too long with unexpected trailing characters:', ' baz'], + ); }); test('reports original missing characters for short string', () { check('foo bar').isRejectedBy( - (it) => it.equalsIgnoringWhitespace('foo bar baz'), - which: ['is too short with missing trailing characters:', ' baz']); + (it) => it.equalsIgnoringWhitespace('foo bar baz'), + which: ['is too short with missing trailing characters:', ' baz'], + ); }); test('reports index of different character with original characters', () { check('x hit x').isRejectedBy( - (it) => it.equalsIgnoringWhitespace('x hat x'), - which: [ - 'differs at offset 3:', - 'x hat x', - 'x hit x', - ' ^', - ]); + (it) => it.equalsIgnoringWhitespace('x hat x'), + which: ['differs at offset 3:', 'x hat x', 'x hit x', ' ^'], + ); }); }); }); diff --git a/pkgs/checks/test/pretty_print_test.dart b/pkgs/checks/test/pretty_print_test.dart index 63f1cc147..6998ab3cb 100644 --- a/pkgs/checks/test/pretty_print_test.dart +++ b/pkgs/checks/test/pretty_print_test.dart @@ -10,8 +10,10 @@ void main() { group('literal', () { group('truncates large collections', () { const maxUntruncatedCollection = 25; - final largeList = - List.generate(maxUntruncatedCollection + 1, (i) => i); + final largeList = List.generate( + maxUntruncatedCollection + 1, + (i) => i, + ); test('in lists', () { check(literal(largeList)).last.equals('...]'); }); diff --git a/pkgs/checks/test/soft_check_test.dart b/pkgs/checks/test/soft_check_test.dart index d919b0db3..ad6bf01ff 100644 --- a/pkgs/checks/test/soft_check_test.dart +++ b/pkgs/checks/test/soft_check_test.dart @@ -11,20 +11,24 @@ void main() { group('softCheck', () { test('returns the first failure', () { check(0).isRejectedBy( - (it) => it - ..isGreaterThan(1) - ..isGreaterThan(2), - which: ['is not greater than <1>']); + (it) => + it + ..isGreaterThan(1) + ..isGreaterThan(2), + which: ['is not greater than <1>'], + ); }); }); group('softCheckAsync', () { test('returns the first failure', () async { await check(Future.value(0)).isRejectedByAsync( - (it) => it - ..completes((it) => it.isGreaterThan(1)) - ..completes((it) => it.isGreaterThan(2)), - actual: ['<0>'], - which: ['is not greater than <1>']); + (it) => + it + ..completes((it) => it.isGreaterThan(1)) + ..completes((it) => it.isGreaterThan(2)), + actual: ['<0>'], + which: ['is not greater than <1>'], + ); }); }); } diff --git a/pkgs/checks/test/test_shared.dart b/pkgs/checks/test/test_shared.dart index 87401cafb..d86ad956a 100644 --- a/pkgs/checks/test/test_shared.dart +++ b/pkgs/checks/test/test_shared.dart @@ -8,23 +8,30 @@ import 'package:checks/checks.dart'; import 'package:checks/context.dart'; extension RejectionChecks on Subject { - void isRejectedBy(Condition condition, - {Iterable? actual, Iterable? which}) { + void isRejectedBy( + Condition condition, { + Iterable? actual, + Iterable? which, + }) { late T actualValue; var didRunCallback = false; final rejection = context.nest( - () => ['does not meet a condition with a Rejection'], (value) { - actualValue = value; - didRunCallback = true; - final failure = softCheck(value, condition); - if (failure == null) { - return Extracted.rejection(which: [ - 'was accepted by the condition checking:', - ...describe(condition) - ]); - } - return Extracted.value(failure.rejection); - }); + () => ['does not meet a condition with a Rejection'], + (value) { + actualValue = value; + didRunCallback = true; + final failure = softCheck(value, condition); + if (failure == null) { + return Extracted.rejection( + which: [ + 'was accepted by the condition checking:', + ...describe(condition), + ], + ); + } + return Extracted.value(failure.rejection); + }, + ); if (didRunCallback) { rejection .has((r) => r.actual, 'actual') @@ -42,40 +49,47 @@ extension RejectionChecks on Subject { } } - Future isRejectedByAsync(Condition condition, - {Iterable? actual, Iterable? which}) async { + Future isRejectedByAsync( + Condition condition, { + Iterable? actual, + Iterable? which, + }) async { late T actualValue; var didRunCallback = false; await context.nestAsync( - () => ['does not meet an async condition with a Rejection'], - (value) async { - actualValue = value; - didRunCallback = true; - final failure = await softCheckAsync(value, condition); - if (failure == null) { - return Extracted.rejection(which: [ - 'was accepted by the condition checking:', - ...await describeAsync(condition) - ]); - } - return Extracted.value(failure.rejection); - }, (rejection) { - if (didRunCallback) { - rejection - .has((r) => r.actual, 'actual') - .deepEquals(actual ?? literal(actualValue)); - } else { - rejection - .has((r) => r.actual, 'actual') - .context - .expect(() => ['is left default'], (_) => null); - } - if (which == null) { - rejection.has((r) => r.which, 'which').isNull(); - } else { - rejection.has((r) => r.which, 'which').isNotNull().deepEquals(which); - } - }); + () => ['does not meet an async condition with a Rejection'], + (value) async { + actualValue = value; + didRunCallback = true; + final failure = await softCheckAsync(value, condition); + if (failure == null) { + return Extracted.rejection( + which: [ + 'was accepted by the condition checking:', + ...await describeAsync(condition), + ], + ); + } + return Extracted.value(failure.rejection); + }, + (rejection) { + if (didRunCallback) { + rejection + .has((r) => r.actual, 'actual') + .deepEquals(actual ?? literal(actualValue)); + } else { + rejection + .has((r) => r.actual, 'actual') + .context + .expect(() => ['is left default'], (_) => null); + } + if (which == null) { + rejection.has((r) => r.which, 'which').isNull(); + } else { + rejection.has((r) => r.which, 'which').isNotNull().deepEquals(which); + } + }, + ); } } @@ -83,10 +97,10 @@ extension ConditionChecks on Subject> { Subject> get description => has((c) => describe(c), 'description'); Future hasAsyncDescriptionWhich( - Condition> descriptionCondition) => - context.nestAsync( - () => ['has description'], - (condition) async => - Extracted.value(await describeAsync(condition)), - descriptionCondition); + Condition> descriptionCondition, + ) => context.nestAsync( + () => ['has description'], + (condition) async => Extracted.value(await describeAsync(condition)), + descriptionCondition, + ); } diff --git a/pkgs/test/lib/src/bootstrap/browser.dart b/pkgs/test/lib/src/bootstrap/browser.dart index 1a66e2b4a..df15489de 100644 --- a/pkgs/test/lib/src/bootstrap/browser.dart +++ b/pkgs/test/lib/src/bootstrap/browser.dart @@ -9,13 +9,18 @@ import 'package:test_core/src/util/stack_trace_mapper.dart'; // ignore: implemen import '../runner/browser/post_message_channel.dart'; /// Bootstraps a browser test to communicate with the test runner. -void internalBootstrapBrowserTest(Function Function() getMain, - {StreamChannel? testChannel}) { - var channel = serializeSuite(getMain, hidePrints: false, - beforeLoad: (suiteChannel) async { - var serialized = await suiteChannel('test.browser.mapper').stream.first; - if (serialized is! Map) return; - setStackTraceMapper(JSStackTraceMapper.deserialize(serialized)!); - }); +void internalBootstrapBrowserTest( + Function Function() getMain, { + StreamChannel? testChannel, +}) { + var channel = serializeSuite( + getMain, + hidePrints: false, + beforeLoad: (suiteChannel) async { + var serialized = await suiteChannel('test.browser.mapper').stream.first; + if (serialized is! Map) return; + setStackTraceMapper(JSStackTraceMapper.deserialize(serialized)!); + }, + ); (testChannel ?? postMessageChannel()).pipe(channel); } diff --git a/pkgs/test/lib/src/bootstrap/node.dart b/pkgs/test/lib/src/bootstrap/node.dart index 21089a47b..943708a9f 100644 --- a/pkgs/test/lib/src/bootstrap/node.dart +++ b/pkgs/test/lib/src/bootstrap/node.dart @@ -9,10 +9,13 @@ import '../runner/node/socket_channel.dart'; /// Bootstraps a browser test to communicate with the test runner. void internalBootstrapNodeTest(Function Function() getMain) { - var channel = serializeSuite(getMain, beforeLoad: (suiteChannel) async { - var serialized = await suiteChannel('test.node.mapper').stream.first; - if (serialized is! Map) return; - setStackTraceMapper(JSStackTraceMapper.deserialize(serialized)!); - }); + var channel = serializeSuite( + getMain, + beforeLoad: (suiteChannel) async { + var serialized = await suiteChannel('test.node.mapper').stream.first; + if (serialized is! Map) return; + setStackTraceMapper(JSStackTraceMapper.deserialize(serialized)!); + }, + ); socketChannel().then((socket) => socket.pipe(channel)); } diff --git a/pkgs/test/lib/src/runner/browser/browser.dart b/pkgs/test/lib/src/runner/browser/browser.dart index b025ea2c5..4d846c8eb 100644 --- a/pkgs/test/lib/src/runner/browser/browser.dart +++ b/pkgs/test/lib/src/runner/browser/browser.dart @@ -57,63 +57,70 @@ abstract class Browser { // Don't return a Future here because there's no need for the caller to wait // for the process to actually start. They should just wait for the HTTP // request instead. - runZonedGuarded(() async { - var process = await startBrowser(); - _processCompleter.complete(process); - - void drainOutput(Stream> stream) { - try { - _ioSubscriptions.add(stream - .transform(utf8.decoder) - .transform(const LineSplitter()) - .listen(output.add, cancelOnError: true)); - } on StateError catch (_) {} - } - - // If we don't drain the stdout and stderr the process can hang. - drainOutput(process.stdout); - drainOutput(process.stderr); - - var exitCode = await process.exitCode; - - // This hack dodges an otherwise intractable race condition. When the user - // presses Control-C, the signal is sent to the browser and the test - // runner at the same time. It's possible for the browser to exit before - // the [Browser.close] is called, which would trigger the error below. - // - // A negative exit code signals that the process exited due to a signal. - // However, it's possible that this signal didn't come from the user's - // Control-C, in which case we do want to throw the error. The only way to - // resolve the ambiguity is to wait a brief amount of time and see if this - // browser is actually closed. - if (!_closed && exitCode < 0) { - await Future.delayed(const Duration(milliseconds: 200)); - } - - if (!_closed && exitCode != 0) { - var outputString = output.join('\n'); - var message = '$name failed with exit code $exitCode.'; - if (outputString.isNotEmpty) { - message += '\nStandard output:\n$outputString'; + runZonedGuarded( + () async { + var process = await startBrowser(); + _processCompleter.complete(process); + + void drainOutput(Stream> stream) { + try { + _ioSubscriptions.add( + stream + .transform(utf8.decoder) + .transform(const LineSplitter()) + .listen(output.add, cancelOnError: true), + ); + } on StateError catch (_) {} } - throw ApplicationException(message); - } + // If we don't drain the stdout and stderr the process can hang. + drainOutput(process.stdout); + drainOutput(process.stderr); + + var exitCode = await process.exitCode; + + // This hack dodges an otherwise intractable race condition. When the user + // presses Control-C, the signal is sent to the browser and the test + // runner at the same time. It's possible for the browser to exit before + // the [Browser.close] is called, which would trigger the error below. + // + // A negative exit code signals that the process exited due to a signal. + // However, it's possible that this signal didn't come from the user's + // Control-C, in which case we do want to throw the error. The only way to + // resolve the ambiguity is to wait a brief amount of time and see if this + // browser is actually closed. + if (!_closed && exitCode < 0) { + await Future.delayed(const Duration(milliseconds: 200)); + } + + if (!_closed && exitCode != 0) { + var outputString = output.join('\n'); + var message = '$name failed with exit code $exitCode.'; + if (outputString.isNotEmpty) { + message += '\nStandard output:\n$outputString'; + } + + throw ApplicationException(message); + } - _onExitCompleter.complete(); - }, (error, stackTrace) { - // Ignore any errors after the browser has been closed. - if (_closed) return; + _onExitCompleter.complete(); + }, + (error, stackTrace) { + // Ignore any errors after the browser has been closed. + if (_closed) return; - // Make sure the process dies even if the error wasn't fatal. - _process.then((process) => process.kill()); + // Make sure the process dies even if the error wasn't fatal. + _process.then((process) => process.kill()); - if (_onExitCompleter.isCompleted) return; - _onExitCompleter.completeError( + if (_onExitCompleter.isCompleted) return; + _onExitCompleter.completeError( ApplicationException( - 'Failed to run $name: ${getErrorMessage(error)}.'), - stackTrace); - }); + 'Failed to run $name: ${getErrorMessage(error)}.', + ), + stackTrace, + ); + }, + ); } /// Kills the browser process. diff --git a/pkgs/test/lib/src/runner/browser/browser_manager.dart b/pkgs/test/lib/src/runner/browser/browser_manager.dart index 409fbb4ca..4b31650bf 100644 --- a/pkgs/test/lib/src/runner/browser/browser_manager.dart +++ b/pkgs/test/lib/src/runner/browser/browser_manager.dart @@ -98,21 +98,22 @@ class BrowserManager { /// Returns the browser manager, or throws an [ApplicationException] if a /// connection fails to be established. static Future start( - Runtime runtime, - Uri url, - Future future, - ExecutableSettings settings, - Configuration configuration) => - _start(runtime, url, future, settings, configuration, 1); + Runtime runtime, + Uri url, + Future future, + ExecutableSettings settings, + Configuration configuration, + ) => _start(runtime, url, future, settings, configuration, 1); static const _maxRetries = 3; static Future _start( - Runtime runtime, - Uri url, - Future future, - ExecutableSettings settings, - Configuration configuration, - int attempt) { + Runtime runtime, + Uri url, + Future future, + ExecutableSettings settings, + Configuration configuration, + int attempt, + ) { var browser = _newBrowser(url, runtime, settings, configuration); var completer = Completer(); @@ -120,46 +121,59 @@ class BrowserManager { // TODO(nweiz): Gracefully handle the browser being killed before the // tests complete. browser.onExit - .then((_) => throw ApplicationException( - '${runtime.name} exited before connecting.')) + .then( + (_) => + throw ApplicationException( + '${runtime.name} exited before connecting.', + ), + ) .onError((error, stackTrace) { - if (!completer.isCompleted) { - completer.completeError(error, stackTrace); - } - }); + if (!completer.isCompleted) { + completer.completeError(error, stackTrace); + } + }); - future.then((webSocket) { - if (completer.isCompleted) return; - completer.complete(BrowserManager._(browser, runtime, webSocket)); - }).onError((Object error, StackTrace stackTrace) { - browser.close(); - if (completer.isCompleted) return; - completer.completeError(error, stackTrace); - }); + future + .then((webSocket) { + if (completer.isCompleted) return; + completer.complete(BrowserManager._(browser, runtime, webSocket)); + }) + .onError((Object error, StackTrace stackTrace) { + browser.close(); + if (completer.isCompleted) return; + completer.completeError(error, stackTrace); + }); - return completer.future.timeout(const Duration(seconds: 30), onTimeout: () { - browser.close(); - if (attempt >= _maxRetries) { - throw ApplicationException( + return completer.future.timeout( + const Duration(seconds: 30), + onTimeout: () { + browser.close(); + if (attempt >= _maxRetries) { + throw ApplicationException( 'Timed out waiting for ${runtime.name} to connect.\n' - 'Browser output: ${browser.output.join('\n')}'); - } - return _start(runtime, url, future, settings, configuration, ++attempt); - }); + 'Browser output: ${browser.output.join('\n')}', + ); + } + return _start(runtime, url, future, settings, configuration, ++attempt); + }, + ); } /// Starts the browser identified by [browser] using [settings] and has it load [url]. /// /// If [debug] is true, starts the browser in debug mode. - static Browser _newBrowser(Uri url, Runtime browser, - ExecutableSettings settings, Configuration configuration) => - switch (browser.root) { - Runtime.chrome => Chrome(url, configuration, settings: settings), - Runtime.firefox => Firefox(url, settings: settings), - Runtime.safari => Safari(url, settings: settings), - Runtime.edge => MicrosoftEdge(url, configuration, settings: settings), - _ => throw ArgumentError('$browser is not a browser.'), - }; + static Browser _newBrowser( + Uri url, + Runtime browser, + ExecutableSettings settings, + Configuration configuration, + ) => switch (browser.root) { + Runtime.chrome => Chrome(url, configuration, settings: settings), + Runtime.firefox => Firefox(url, settings: settings), + Runtime.safari => Safari(url, settings: settings), + Runtime.edge => MicrosoftEdge(url, configuration, settings: settings), + _ => throw ArgumentError('$browser is not a browser.'), + }; /// Creates a new BrowserManager that communicates with [browser] over /// [webSocket]. @@ -174,33 +188,37 @@ class BrowserManager { for (var controller in _controllers) { controller.setDebugging(true); } - }) - ..cancel(); + })..cancel(); // Whenever we get a message, no matter which child channel it's for, we the // know browser is still running code which means the user isn't debugging. _channel = MultiChannel( - webSocket.cast().transform(jsonDocument).changeStream((stream) { - return stream.map((message) { - if (!_closed) _timer.reset(); - for (var controller in _controllers) { - controller.setDebugging(false); - } - - return message; - }); - })); + webSocket.cast().transform(jsonDocument).changeStream((stream) { + return stream.map((message) { + if (!_closed) _timer.reset(); + for (var controller in _controllers) { + controller.setDebugging(false); + } + + return message; + }); + }), + ); _environment = _loadBrowserEnvironment(); _channel.stream.listen( - (message) => _onMessage(message as Map), - onDone: close); + (message) => _onMessage(message as Map), + onDone: close, + ); } /// Loads [_BrowserEnvironment]. Future<_BrowserEnvironment> _loadBrowserEnvironment() async => _BrowserEnvironment( - this, await _browser.remoteDebuggerUrl, _onRestartController.stream); + this, + await _browser.remoteDebuggerUrl, + _onRestartController.stream, + ); /// Tells the browser the load a test suite from the URL [url]. /// @@ -210,15 +228,24 @@ class BrowserManager { /// /// If [mapper] is passed, it's used to map stack traces for errors coming /// from this test suite. - Future load(String path, Uri url, SuiteConfiguration suiteConfig, - Map message, Compiler compiler, - {StackTraceMapper? mapper, Duration? timeout}) async { + Future load( + String path, + Uri url, + SuiteConfiguration suiteConfig, + Map message, + Compiler compiler, { + StackTraceMapper? mapper, + Duration? timeout, + }) async { url = url.replace( - fragment: Uri.encodeFull(jsonEncode({ - 'metadata': suiteConfig.metadata.serialize(), - 'browser': _runtime.identifier, - 'compiler': compiler.serialize(), - }))); + fragment: Uri.encodeFull( + jsonEncode({ + 'metadata': suiteConfig.metadata.serialize(), + 'browser': _runtime.identifier, + 'compiler': compiler.serialize(), + }), + ), + ); var suiteID = _suiteID++; RunnerSuiteController? controller; @@ -232,32 +259,37 @@ class BrowserManager { // case we should unload the iframe. var virtualChannel = _channel.virtualChannel(); var suiteChannelID = virtualChannel.id; - var suiteChannel = virtualChannel - .transformStream(StreamTransformer.fromHandlers(handleDone: (sink) { - closeIframe(); - sink.close(); - })); + var suiteChannel = virtualChannel.transformStream( + StreamTransformer.fromHandlers( + handleDone: (sink) { + closeIframe(); + sink.close(); + }, + ), + ); var suite = _pool.withResource(() async { _channel.sink.add({ 'command': 'loadSuite', 'url': url.toString(), 'id': suiteID, - 'channel': suiteChannelID + 'channel': suiteChannelID, }); try { controller = deserializeSuite( - path, - currentPlatform(_runtime, compiler), - suiteConfig, - await _environment, - suiteChannel.cast(), - message, gatherCoverage: () async { - var browser = _browser; - if (browser is Chrome) return browser.gatherCoverage(); - return {}; - }); + path, + currentPlatform(_runtime, compiler), + suiteConfig, + await _environment, + suiteChannel.cast(), + message, + gatherCoverage: () async { + var browser = _browser; + if (browser is Chrome) return browser.gatherCoverage(); + return {}; + }, + ); controller! .channel('test.browser.mapper') @@ -272,12 +304,16 @@ class BrowserManager { } }); if (timeout != null) { - suite = suite.timeout(timeout, onTimeout: () { - throw LoadException( + suite = suite.timeout( + timeout, + onTimeout: () { + throw LoadException( path, 'Timed out waiting for browser to load test suite. ' - 'Browser output: ${_browser.output.join('\n')}'); - }); + 'Browser output: ${_browser.output.join('\n')}', + ); + }, + ); } return suite; } @@ -286,10 +322,13 @@ class BrowserManager { CancelableOperation _displayPause() { if (_pauseCompleter != null) return _pauseCompleter!.operation; - final pauseCompleter = _pauseCompleter = CancelableCompleter(onCancel: () { - _channel.sink.add({'command': 'resume'}); - _pauseCompleter = null; - }); + final pauseCompleter = + _pauseCompleter = CancelableCompleter( + onCancel: () { + _channel.sink.add({'command': 'resume'}); + _pauseCompleter = null; + }, + ); pauseCompleter.operation.value.whenComplete(() { _pauseCompleter = null; @@ -324,13 +363,13 @@ class BrowserManager { /// Closes the manager and releases any resources it owns, including closing /// the browser. Future close() => _closeMemoizer.runOnce(() { - _closed = true; - _timer.cancel(); - _pauseCompleter?.complete(); - _pauseCompleter = null; - _controllers.clear(); - return _browser.close(); - }); + _closed = true; + _timer.cancel(); + _pauseCompleter?.complete(); + _pauseCompleter = null; + _controllers.clear(); + return _browser.close(); + }); final _closeMemoizer = AsyncMemoizer(); } diff --git a/pkgs/test/lib/src/runner/browser/chrome.dart b/pkgs/test/lib/src/runner/browser/chrome.dart index e7dff7543..8b9937bd4 100644 --- a/pkgs/test/lib/src/runner/browser/chrome.dart +++ b/pkgs/test/lib/src/runner/browser/chrome.dart @@ -38,52 +38,63 @@ class Chrome extends Browser { /// Starts a new instance of Chrome open to the given [url], which may be a /// [Uri] or a [String]. - factory Chrome(Uri url, Configuration configuration, - {ExecutableSettings? settings}) { + factory Chrome( + Uri url, + Configuration configuration, { + ExecutableSettings? settings, + }) { settings ??= defaultSettings[Runtime.chrome]!; var remoteDebuggerCompleter = Completer.sync(); var connectionCompleter = Completer(); var idToUrl = {}; - return Chrome._(() async { - Future tryPort([int? port]) async { - var process = await ChromiumBasedBrowser.chrome.spawn( - url, - configuration, - settings: settings, - additionalArgs: [ - if (port != null) - // Chrome doesn't provide any way of ensuring that this port was - // successfully bound. It produces an error if the binding fails, - // but without a reliable and fast way to tell if it succeeded - // that doesn't provide us much. It's very unlikely that this port - // will fail, though. - '--remote-debugging-port=$port', - ], - ); - - if (port != null) { - remoteDebuggerCompleter.complete( - getRemoteDebuggerUrl(Uri.parse('http://localhost:$port'))); - - connectionCompleter.complete(_connect(process, port, idToUrl, url)); - } else { - remoteDebuggerCompleter.complete(null); + return Chrome._( + () async { + Future tryPort([int? port]) async { + var process = await ChromiumBasedBrowser.chrome.spawn( + url, + configuration, + settings: settings, + additionalArgs: [ + if (port != null) + // Chrome doesn't provide any way of ensuring that this port was + // successfully bound. It produces an error if the binding fails, + // but without a reliable and fast way to tell if it succeeded + // that doesn't provide us much. It's very unlikely that this port + // will fail, though. + '--remote-debugging-port=$port', + ], + ); + + if (port != null) { + remoteDebuggerCompleter.complete( + getRemoteDebuggerUrl(Uri.parse('http://localhost:$port')), + ); + + connectionCompleter.complete(_connect(process, port, idToUrl, url)); + } else { + remoteDebuggerCompleter.complete(null); + } + + return process; } - return process; - } - - if (!configuration.debug) return tryPort(); - return getUnusedPort(tryPort); - }, remoteDebuggerCompleter.future, connectionCompleter.future, idToUrl); + if (!configuration.debug) return tryPort(); + return getUnusedPort(tryPort); + }, + remoteDebuggerCompleter.future, + connectionCompleter.future, + idToUrl, + ); } /// Returns a Dart based hit-map containing coverage report, suitable for use /// with `package:coverage`. Future> gatherCoverage() async { var tabConnection = await _tabConnection; - var response = await tabConnection.debugger.connection - .sendCommand('Profiler.takePreciseCoverage', {}); + var response = await tabConnection.debugger.connection.sendCommand( + 'Profiler.takePreciseCoverage', + {}, + ); var result = (response.result!['result'] as List).cast>(); var httpClient = HttpClient(); @@ -97,8 +108,12 @@ class Chrome extends Browser { return coverage; } - Chrome._(super.startBrowser, this.remoteDebuggerUrl, this._tabConnection, - this._idToUrl); + Chrome._( + super.startBrowser, + this.remoteDebuggerUrl, + this._tabConnection, + this._idToUrl, + ); Future _sourceUriProvider(String sourceUrl, String scriptId) async { var script = _idToUrl[scriptId]; @@ -108,22 +123,27 @@ class Chrome extends Browser { // If the provided sourceUrl is relative, determine the package path. var uri = Uri.parse(script); var path = p.join( - p.joinAll(uri.pathSegments.sublist(1, uri.pathSegments.length - 1)), - sourceUrl); + p.joinAll(uri.pathSegments.sublist(1, uri.pathSegments.length - 1)), + sourceUrl, + ); return path.contains('/packages/') ? Uri(scheme: 'package', path: path.split('/packages/').last) : null; } Future _sourceMapProvider( - String scriptId, HttpClient httpClient) async { + String scriptId, + HttpClient httpClient, + ) async { var script = _idToUrl[scriptId]; if (script == null) return null; return await httpClient.getString('$script.map'); } Future _sourceProvider( - String scriptId, HttpClient httpClient) async { + String scriptId, + HttpClient httpClient, + ) async { var script = _idToUrl[scriptId]; if (script == null) return null; return await httpClient.getString(script); @@ -131,7 +151,11 @@ class Chrome extends Browser { } Future _connect( - Process process, int port, Map idToUrl, Uri url) async { + Process process, + int port, + Map idToUrl, + Uri url, +) async { // Wait for Chrome to be in a ready state. await process.stderr .transform(utf8.decoder) @@ -166,7 +190,9 @@ Future _connect( // Enable coverage collection. await tabConnection.debugger.connection.sendCommand('Profiler.enable', {}); await tabConnection.debugger.connection.sendCommand( - 'Profiler.startPreciseCoverage', {'detailed': true, 'callCount': false}); + 'Profiler.startPreciseCoverage', + {'detailed': true, 'callCount': false}, + ); return tabConnection; } diff --git a/pkgs/test/lib/src/runner/browser/compilers/compiler_support.dart b/pkgs/test/lib/src/runner/browser/compilers/compiler_support.dart index 428098cde..5c0bbe9e6 100644 --- a/pkgs/test/lib/src/runner/browser/compilers/compiler_support.dart +++ b/pkgs/test/lib/src/runner/browser/compilers/compiler_support.dart @@ -33,7 +33,10 @@ abstract class CompilerSupport { /// [dartPath] is the path to the original `.dart` test suite, relative to the /// package root. Future compileSuite( - String dartPath, SuiteConfiguration suiteConfig, SuitePlatform platform); + String dartPath, + SuiteConfiguration suiteConfig, + SuitePlatform platform, + ); /// Retrieves a stack trace mapper for [dartPath] if available. /// @@ -68,8 +71,10 @@ mixin JsHtmlWrapper on CompilerSupport { // Checked during loading phase that there is only one {{testScript}} placeholder. .replaceFirst('{{testScript}}', link) .replaceAll('{{testName}}', testName); - return shelf.Response.ok(processedContents, - headers: {'Content-Type': 'text/html'}); + return shelf.Response.ok( + processedContents, + headers: {'Content-Type': 'text/html'}, + ); } return shelf.Response.notFound('Not found.'); @@ -89,15 +94,18 @@ mixin WasmHtmlWrapper on CompilerSupport { var template = config.customHtmlTemplatePath ?? defaultTemplatePath; var contents = File(template).readAsStringSync(); var jsRuntime = p.basename('$test.browser_test.dart.mjs'); - var wasmData = ''; var processedContents = contents // Checked during loading phase that there is only one {{testScript}} placeholder. .replaceFirst('{{testScript}}', '$link\n$wasmData') .replaceAll('{{testName}}', testName); - return shelf.Response.ok(processedContents, - headers: {'Content-Type': 'text/html'}); + return shelf.Response.ok( + processedContents, + headers: {'Content-Type': 'text/html'}, + ); } return shelf.Response.notFound('Not found.'); diff --git a/pkgs/test/lib/src/runner/browser/compilers/dart2js.dart b/pkgs/test/lib/src/runner/browser/compilers/dart2js.dart index 9ef1f4e1f..f43b70b41 100644 --- a/pkgs/test/lib/src/runner/browser/compilers/dart2js.dart +++ b/pkgs/test/lib/src/runner/browser/compilers/dart2js.dart @@ -74,8 +74,13 @@ class Dart2JsSupport extends CompilerSupport with JsHtmlWrapper { @override Uri get serverUrl => _server.url.resolve('$_secret/'); - Dart2JsSupport._(super.config, super.defaultTemplatePath, this._server, - this._root, String faviconPath) { + Dart2JsSupport._( + super.config, + super.defaultTemplatePath, + this._server, + this._root, + String faviconPath, + ) { var cascade = shelf.Cascade() .add(_webSocketHandler.handler) .add(packagesDirHandler()) @@ -87,10 +92,9 @@ class Dart2JsSupport extends CompilerSupport with JsHtmlWrapper { .addMiddleware(PathHandler.nestedIn(_secret)) .addHandler(cascade.handler); - _server.mount(shelf.Cascade() - .add(createFileHandler(faviconPath)) - .add(pipeline) - .handler); + _server.mount( + shelf.Cascade().add(createFileHandler(faviconPath)).add(pipeline).handler, + ); } static Future start({ @@ -101,12 +105,20 @@ class Dart2JsSupport extends CompilerSupport with JsHtmlWrapper { }) async { var server = shelf_io.IOServer(await HttpMultiServer.loopback(0)); return Dart2JsSupport._( - config, defaultTemplatePath, server, root, faviconPath); + config, + defaultTemplatePath, + server, + root, + faviconPath, + ); } @override Future compileSuite( - String dartPath, SuiteConfiguration suiteConfig, SuitePlatform platform) { + String dartPath, + SuiteConfiguration suiteConfig, + SuitePlatform platform, + ) { return _compileFutures.putIfAbsent(dartPath, () async { var dir = Directory(_compiledDir).createTempSync('test_').path; var jsPath = p.join(dir, '${p.basename(dartPath)}.browser_test.dart.js'); @@ -127,33 +139,44 @@ class Dart2JsSupport extends CompilerSupport with JsHtmlWrapper { await _compilerPool.compile(bootstrapContent, jsPath, suiteConfig); if (_closed) return; - var bootstrapUrl = '${p.toUri(p.relative(dartPath, from: _root)).path}' + var bootstrapUrl = + '${p.toUri(p.relative(dartPath, from: _root)).path}' '.browser_test.dart'; _pathHandler.add(bootstrapUrl, (request) { - return shelf.Response.ok(bootstrapContent, - headers: {'Content-Type': 'application/dart'}); + return shelf.Response.ok( + bootstrapContent, + headers: {'Content-Type': 'application/dart'}, + ); }); - var jsUrl = '${p.toUri(p.relative(dartPath, from: _root)).path}' + var jsUrl = + '${p.toUri(p.relative(dartPath, from: _root)).path}' '.browser_test.dart.js'; _pathHandler.add(jsUrl, (request) { - return shelf.Response.ok(File(jsPath).readAsStringSync(), - headers: {'Content-Type': 'application/javascript'}); + return shelf.Response.ok( + File(jsPath).readAsStringSync(), + headers: {'Content-Type': 'application/javascript'}, + ); }); - var mapUrl = '${p.toUri(p.relative(dartPath, from: _root)).path}' + var mapUrl = + '${p.toUri(p.relative(dartPath, from: _root)).path}' '.browser_test.dart.js.map'; _pathHandler.add(mapUrl, (request) { - return shelf.Response.ok(File('$jsPath.map').readAsStringSync(), - headers: {'Content-Type': 'application/json'}); + return shelf.Response.ok( + File('$jsPath.map').readAsStringSync(), + headers: {'Content-Type': 'application/json'}, + ); }); if (suiteConfig.jsTrace) return; var mapPath = '$jsPath.map'; - _mappers[dartPath] = JSStackTraceMapper(File(mapPath).readAsStringSync(), - mapUrl: p.toUri(mapPath), - sdkRoot: Uri.parse('org-dartlang-sdk:///sdk'), - packageMap: (await currentPackageConfig).toPackageMap()); + _mappers[dartPath] = JSStackTraceMapper( + File(mapPath).readAsStringSync(), + mapUrl: p.toUri(mapPath), + sdkRoot: Uri.parse('org-dartlang-sdk:///sdk'), + packageMap: (await currentPackageConfig).toPackageMap(), + ); }); } @@ -177,10 +200,11 @@ class Dart2JsSupport extends CompilerSupport with JsHtmlWrapper { var completer = Completer.sync(); // Note: the WebSocketChannel type below is needed for compatibility with // package:shelf_web_socket v2. - var path = - _webSocketHandler.create(webSocketHandler((WebSocketChannel ws, _) { - completer.complete(ws); - })); + var path = _webSocketHandler.create( + webSocketHandler((WebSocketChannel ws, _) { + completer.complete(ws); + }), + ); var webSocketUrl = serverUrl.replace(scheme: 'ws').resolve(path); return (webSocketUrl, completer.future); } diff --git a/pkgs/test/lib/src/runner/browser/compilers/dart2wasm.dart b/pkgs/test/lib/src/runner/browser/compilers/dart2wasm.dart index 31ad66152..55a022848 100644 --- a/pkgs/test/lib/src/runner/browser/compilers/dart2wasm.dart +++ b/pkgs/test/lib/src/runner/browser/compilers/dart2wasm.dart @@ -76,8 +76,14 @@ class Dart2WasmSupport extends CompilerSupport with WasmHtmlWrapper { @override Uri get serverUrl => _server.url.resolve('$_secret/'); - Dart2WasmSupport._(super.config, super.defaultTemplatePath, - this._jsRuntimeWrapper, this._server, this._root, String faviconPath) { + Dart2WasmSupport._( + super.config, + super.defaultTemplatePath, + this._jsRuntimeWrapper, + this._server, + this._root, + String faviconPath, + ) { var cascade = shelf.Cascade() .add(_webSocketHandler.handler) .add(packagesDirHandler()) @@ -89,10 +95,9 @@ class Dart2WasmSupport extends CompilerSupport with WasmHtmlWrapper { .addMiddleware(PathHandler.nestedIn(_secret)) .addHandler(cascade.handler); - _server.mount(shelf.Cascade() - .add(createFileHandler(faviconPath)) - .add(pipeline) - .handler); + _server.mount( + shelf.Cascade().add(createFileHandler(faviconPath)).add(pipeline).handler, + ); } static Future start({ @@ -103,18 +108,29 @@ class Dart2WasmSupport extends CompilerSupport with WasmHtmlWrapper { required String faviconPath, }) async { var server = shelf_io.IOServer(await HttpMultiServer.loopback(0)); - return Dart2WasmSupport._(config, defaultTemplatePath, jsRuntimeWrapper, - server, root, faviconPath); + return Dart2WasmSupport._( + config, + defaultTemplatePath, + jsRuntimeWrapper, + server, + root, + faviconPath, + ); } @override Future compileSuite( - String dartPath, SuiteConfiguration suiteConfig, SuitePlatform platform) { + String dartPath, + SuiteConfiguration suiteConfig, + SuitePlatform platform, + ) { return _compileFutures.putIfAbsent(dartPath, () async { var dir = Directory(_compiledDir).createTempSync('test_').path; - var baseCompiledPath = - p.join(dir, '${p.basename(dartPath)}.browser_test.dart'); + var baseCompiledPath = p.join( + dir, + '${p.basename(dartPath)}.browser_test.dart', + ); var baseUrl = '${p.toUri(p.relative(dartPath, from: _root)).path}.browser_test.dart'; var wasmUrl = '$baseUrl.wasm'; @@ -134,30 +150,41 @@ class Dart2WasmSupport extends CompilerSupport with WasmHtmlWrapper { '''; await _compilerPool.compile( - bootstrapContent, baseCompiledPath, suiteConfig); + bootstrapContent, + baseCompiledPath, + suiteConfig, + ); if (_closed) return; var wasmPath = '$baseCompiledPath.wasm'; _pathHandler.add(wasmUrl, (request) { - return shelf.Response.ok(File(wasmPath).readAsBytesSync(), - headers: {'Content-Type': 'application/wasm'}); + return shelf.Response.ok( + File(wasmPath).readAsBytesSync(), + headers: {'Content-Type': 'application/wasm'}, + ); }); _pathHandler.add(jsRuntimeWrapperUrl, (request) { - return shelf.Response.ok(File(_jsRuntimeWrapper).readAsBytesSync(), - headers: {'Content-Type': 'application/javascript'}); + return shelf.Response.ok( + File(_jsRuntimeWrapper).readAsBytesSync(), + headers: {'Content-Type': 'application/javascript'}, + ); }); var jsRuntimePath = '$baseCompiledPath.mjs'; _pathHandler.add(jsRuntimeUrl, (request) { - return shelf.Response.ok(File(jsRuntimePath).readAsBytesSync(), - headers: {'Content-Type': 'application/javascript'}); + return shelf.Response.ok( + File(jsRuntimePath).readAsBytesSync(), + headers: {'Content-Type': 'application/javascript'}, + ); }); var htmlPath = '$baseCompiledPath.html'; _pathHandler.add(htmlUrl, (request) { - return shelf.Response.ok(File(htmlPath).readAsBytesSync(), - headers: {'Content-Type': 'text/html'}); + return shelf.Response.ok( + File(htmlPath).readAsBytesSync(), + headers: {'Content-Type': 'text/html'}, + ); }); }); } @@ -182,10 +209,11 @@ class Dart2WasmSupport extends CompilerSupport with WasmHtmlWrapper { var completer = Completer.sync(); // Note: the WebSocketChannel type below is needed for compatibility with // package:shelf_web_socket v2. - var path = - _webSocketHandler.create(webSocketHandler((WebSocketChannel ws, _) { - completer.complete(ws); - })); + var path = _webSocketHandler.create( + webSocketHandler((WebSocketChannel ws, _) { + completer.complete(ws); + }), + ); var webSocketUrl = serverUrl.replace(scheme: 'ws').resolve(path); return (webSocketUrl, completer.future); } diff --git a/pkgs/test/lib/src/runner/browser/compilers/precompiled.dart b/pkgs/test/lib/src/runner/browser/compilers/precompiled.dart index 9cf44aaf4..71b95e563 100644 --- a/pkgs/test/lib/src/runner/browser/compilers/precompiled.dart +++ b/pkgs/test/lib/src/runner/browser/compilers/precompiled.dart @@ -62,8 +62,13 @@ abstract class PrecompiledSupport extends CompilerSupport { @override Uri get serverUrl => _server.url.resolve('$_secret/'); - PrecompiledSupport._(super.config, super.defaultTemplatePath, this._server, - this._root, String faviconPath) { + PrecompiledSupport._( + super.config, + super.defaultTemplatePath, + this._server, + this._root, + String faviconPath, + ) { var cascade = shelf.Cascade() .add(_webSocketHandler.handler) .add(createStaticHandler(_root, serveFilesOutsidePath: true)) @@ -77,10 +82,9 @@ abstract class PrecompiledSupport extends CompilerSupport { .addMiddleware(PathHandler.nestedIn(_secret)) .addHandler(cascade.handler); - _server.mount(shelf.Cascade() - .add(createFileHandler(faviconPath)) - .add(pipeline) - .handler); + _server.mount( + shelf.Cascade().add(createFileHandler(faviconPath)).add(pipeline).handler, + ); } static Future start({ @@ -94,30 +98,46 @@ abstract class PrecompiledSupport extends CompilerSupport { return switch (compiler) { Compiler.dart2js => JsPrecompiledSupport._( - config, defaultTemplatePath, server, root, faviconPath), + config, + defaultTemplatePath, + server, + root, + faviconPath, + ), Compiler.dart2wasm => WasmPrecompiledSupport._( - config, defaultTemplatePath, server, root, faviconPath), - Compiler.exe || - Compiler.kernel || - Compiler.source => + config, + defaultTemplatePath, + server, + root, + faviconPath, + ), + Compiler.exe || Compiler.kernel || Compiler.source => throw UnsupportedError( - 'The browser platform does not support $compiler'), + 'The browser platform does not support $compiler', + ), }; } /// Compiles [dartPath] using [suiteConfig] for [platform]. @override - Future compileSuite(String dartPath, SuiteConfiguration suiteConfig, - SuitePlatform platform) async { + Future compileSuite( + String dartPath, + SuiteConfiguration suiteConfig, + SuitePlatform platform, + ) async { if (suiteConfig.jsTrace) return; var mapPath = p.join( - suiteConfig.precompiledPath!, '$dartPath.browser_test.dart.js.map'); + suiteConfig.precompiledPath!, + '$dartPath.browser_test.dart.js.map', + ); var mapFile = File(mapPath); if (mapFile.existsSync()) { - _mappers[dartPath] = JSStackTraceMapper(mapFile.readAsStringSync(), - mapUrl: p.toUri(mapPath), - sdkRoot: Uri.parse(r'/packages/$sdk'), - packageMap: (await currentPackageConfig).toPackageMap()); + _mappers[dartPath] = JSStackTraceMapper( + mapFile.readAsStringSync(), + mapUrl: p.toUri(mapPath), + sdkRoot: Uri.parse(r'/packages/$sdk'), + packageMap: (await currentPackageConfig).toPackageMap(), + ); } } @@ -139,10 +159,11 @@ abstract class PrecompiledSupport extends CompilerSupport { var completer = Completer.sync(); // Note: the WebSocketChannel type below is needed for compatibility with // package:shelf_web_socket v2. - var path = - _webSocketHandler.create(webSocketHandler((WebSocketChannel ws, _) { - completer.complete(ws); - })); + var path = _webSocketHandler.create( + webSocketHandler((WebSocketChannel ws, _) { + completer.complete(ws); + }), + ); var webSocketUrl = serverUrl.replace(scheme: 'ws').resolve(path); return (webSocketUrl, completer.future); } diff --git a/pkgs/test/lib/src/runner/browser/default_settings.dart b/pkgs/test/lib/src/runner/browser/default_settings.dart index 312fc1130..6f50fd424 100644 --- a/pkgs/test/lib/src/runner/browser/default_settings.dart +++ b/pkgs/test/lib/src/runner/browser/default_settings.dart @@ -10,11 +10,12 @@ import '../executable_settings.dart'; /// Default settings for starting browser executables. final defaultSettings = UnmodifiableMapView({ Runtime.chrome: ExecutableSettings( - linuxExecutable: 'google-chrome', - macOSExecutable: - '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome', - windowsExecutable: r'Google\Chrome\Application\chrome.exe', - environmentOverride: 'CHROME_EXECUTABLE'), + linuxExecutable: 'google-chrome', + macOSExecutable: + '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome', + windowsExecutable: r'Google\Chrome\Application\chrome.exe', + environmentOverride: 'CHROME_EXECUTABLE', + ), Runtime.edge: ExecutableSettings( linuxExecutable: 'microsoft-edge-stable', windowsExecutable: r'Microsoft\Edge\Application\msedge.exe', @@ -23,15 +24,17 @@ final defaultSettings = UnmodifiableMapView({ environmentOverride: 'MS_EDGE_EXECUTABLE', ), Runtime.firefox: ExecutableSettings( - linuxExecutable: 'firefox', - macOSExecutables: [ - '/Applications/Firefox.app/Contents/MacOS/firefox-bin', - '/Applications/Firefox.app/Contents/MacOS/firefox', - 'firefox', - ], - windowsExecutable: r'Mozilla Firefox\firefox.exe', - environmentOverride: 'FIREFOX_EXECUTABLE'), + linuxExecutable: 'firefox', + macOSExecutables: [ + '/Applications/Firefox.app/Contents/MacOS/firefox-bin', + '/Applications/Firefox.app/Contents/MacOS/firefox', + 'firefox', + ], + windowsExecutable: r'Mozilla Firefox\firefox.exe', + environmentOverride: 'FIREFOX_EXECUTABLE', + ), Runtime.safari: ExecutableSettings( - macOSExecutable: '/Applications/Safari.app/Contents/MacOS/Safari', - environmentOverride: 'SAFARI_EXECUTABLE'), + macOSExecutable: '/Applications/Safari.app/Contents/MacOS/Safari', + environmentOverride: 'SAFARI_EXECUTABLE', + ), }); diff --git a/pkgs/test/lib/src/runner/browser/dom.dart b/pkgs/test/lib/src/runner/browser/dom.dart index fe6a658a4..8bd3e1df5 100644 --- a/pkgs/test/lib/src/runner/browser/dom.dart +++ b/pkgs/test/lib/src/runner/browser/dom.dart @@ -15,19 +15,22 @@ extension type Window(EventTarget _) implements EventTarget { CSSStyleDeclaration? getComputedStyle(Element elt, [String? pseudoElt]) => callMethodVarArgs('getComputedStyle'.toJS, [ - elt, - if (pseudoElt != null) pseudoElt.toJS - ]) as CSSStyleDeclaration?; + elt, + if (pseudoElt != null) pseudoElt.toJS, + ]) + as CSSStyleDeclaration?; external Navigator get navigator; - void postMessage(Object message, String targetOrigin, - [List? messagePorts]) => - callMethodVarArgs('postMessage'.toJS, [ - message.jsify(), - targetOrigin.toJS, - if (messagePorts != null) messagePorts.toJS - ]); + void postMessage( + Object message, + String targetOrigin, [ + List? messagePorts, + ]) => callMethodVarArgs('postMessage'.toJS, [ + message.jsify(), + targetOrigin.toJS, + if (messagePorts != null) messagePorts.toJS, + ]); } @JS('window') @@ -41,9 +44,12 @@ extension type Console(JSObject _) implements JSObject { extension type Document(Node _) implements Node { external Element? querySelector(String selectors); - Element createElement(String name, [Object? options]) => callMethodVarArgs( - 'createElement'.toJS, - [name.toJS, if (options != null) options.jsify()]) as Element; + Element createElement(String name, [Object? options]) => + callMethodVarArgs('createElement'.toJS, [ + name.toJS, + if (options != null) options.jsify(), + ]) + as Element; } extension type HTMLDocument(Document _) implements Document { @@ -80,24 +86,30 @@ extension type Node(EventTarget _) implements EventTarget { } extension type EventTarget(JSObject _) implements JSObject { - void addEventListener(String type, EventListener? listener, - [bool? useCapture]) { + void addEventListener( + String type, + EventListener? listener, [ + bool? useCapture, + ]) { if (listener != null) { callMethodVarArgs('addEventListener'.toJS, [ type.toJS, listener.toJS, - if (useCapture != null) useCapture.toJS + if (useCapture != null) useCapture.toJS, ]); } } - void removeEventListener(String type, EventListener? listener, - [bool? useCapture]) { + void removeEventListener( + String type, + EventListener? listener, [ + bool? useCapture, + ]) { if (listener != null) { callMethodVarArgs('removeEventListener'.toJS, [ type.toJS, listener.toJS, - if (useCapture != null) useCapture.toJS + if (useCapture != null) useCapture.toJS, ]); } } @@ -143,7 +155,9 @@ extension type Location(JSObject _) implements JSObject { extension type MessagePort(EventTarget _) implements EventTarget { void postMessage(Object? message) => callMethodVarArgs( - 'postMessage'.toJS, [if (message != null) message.jsify()]); + 'postMessage'.toJS, + [if (message != null) message.jsify()], + ); external void start(); } diff --git a/pkgs/test/lib/src/runner/browser/firefox.dart b/pkgs/test/lib/src/runner/browser/firefox.dart index 503f103c0..e67fb67ee 100644 --- a/pkgs/test/lib/src/runner/browser/firefox.dart +++ b/pkgs/test/lib/src/runner/browser/firefox.dart @@ -31,26 +31,24 @@ class Firefox extends Browser { final name = 'Firefox'; Firefox(Uri url, {ExecutableSettings? settings}) - : super(() => - _startBrowser(url, settings ?? defaultSettings[Runtime.firefox]!)); + : super( + () => _startBrowser(url, settings ?? defaultSettings[Runtime.firefox]!), + ); /// Starts a new instance of Firefox open to the given [url], which may be a /// [Uri] or a [String]. static Future _startBrowser( - Uri url, ExecutableSettings settings) async { + Uri url, + ExecutableSettings settings, + ) async { var dir = createTempDir(); File(p.join(dir, 'prefs.js')).writeAsStringSync(_preferences); - var process = await Process.start(settings.executable, [ - '--profile', - dir, - url.toString(), - '--no-remote', - ...settings.arguments, - ], environment: { - 'MOZ_CRASHREPORTER_DISABLE': '1', - 'MOZ_AUTOMATION': '1', - }); + var process = await Process.start( + settings.executable, + ['--profile', dir, url.toString(), '--no-remote', ...settings.arguments], + environment: {'MOZ_CRASHREPORTER_DISABLE': '1', 'MOZ_AUTOMATION': '1'}, + ); unawaited(process.exitCode.then((_) => Directory(dir).deleteWithRetry())); diff --git a/pkgs/test/lib/src/runner/browser/microsoft_edge.dart b/pkgs/test/lib/src/runner/browser/microsoft_edge.dart index 08fa8e2aa..d4c0f346a 100644 --- a/pkgs/test/lib/src/runner/browser/microsoft_edge.dart +++ b/pkgs/test/lib/src/runner/browser/microsoft_edge.dart @@ -13,11 +13,15 @@ class MicrosoftEdge extends Browser { @override String get name => 'Edge'; - MicrosoftEdge(Uri url, Configuration configuration, - {ExecutableSettings? settings}) - : super(() => ChromiumBasedBrowser.microsoftEdge.spawn( - url, - configuration, - settings: settings, - )); + MicrosoftEdge( + Uri url, + Configuration configuration, { + ExecutableSettings? settings, + }) : super( + () => ChromiumBasedBrowser.microsoftEdge.spawn( + url, + configuration, + settings: settings, + ), + ); } diff --git a/pkgs/test/lib/src/runner/browser/platform.dart b/pkgs/test/lib/src/runner/browser/platform.dart index da03a3e00..df0d660f9 100644 --- a/pkgs/test/lib/src/runner/browser/platform.dart +++ b/pkgs/test/lib/src/runner/browser/platform.dart @@ -34,14 +34,26 @@ class BrowserPlatform extends PlatformPlugin static Future start({String? root}) async { var packageConfig = await currentPackageConfig; return BrowserPlatform._( - Configuration.current, - p.fromUri(packageConfig.resolve( - Uri.parse('package:test/src/runner/browser/static/favicon.ico'))), - p.fromUri(packageConfig.resolve(Uri.parse( - 'package:test/src/runner/browser/static/default.html.tpl'))), - p.fromUri(packageConfig.resolve(Uri.parse( - 'package:test/src/runner/browser/static/run_wasm_chrome.js'))), - root: root); + Configuration.current, + p.fromUri( + packageConfig.resolve( + Uri.parse('package:test/src/runner/browser/static/favicon.ico'), + ), + ), + p.fromUri( + packageConfig.resolve( + Uri.parse('package:test/src/runner/browser/static/default.html.tpl'), + ), + ), + p.fromUri( + packageConfig.resolve( + Uri.parse( + 'package:test/src/runner/browser/static/run_wasm_chrome.js', + ), + ), + ), + root: root, + ); } /// The test runner configuration. @@ -63,24 +75,27 @@ class BrowserPlatform extends PlatformPlugin _compilerSupport.putIfAbsent(compiler, () { if (_config.suiteDefaults.precompiledPath != null) { return PrecompiledSupport.start( - compiler: compiler, - config: _config, - defaultTemplatePath: _defaultTemplatePath, - root: _config.suiteDefaults.precompiledPath!, - faviconPath: _faviconPath); + compiler: compiler, + config: _config, + defaultTemplatePath: _defaultTemplatePath, + root: _config.suiteDefaults.precompiledPath!, + faviconPath: _faviconPath, + ); } return switch (compiler) { Compiler.dart2js => Dart2JsSupport.start( - config: _config, - defaultTemplatePath: _defaultTemplatePath, - root: _root, - faviconPath: _faviconPath), + config: _config, + defaultTemplatePath: _defaultTemplatePath, + root: _root, + faviconPath: _faviconPath, + ), Compiler.dart2wasm => Dart2WasmSupport.start( - config: _config, - defaultTemplatePath: _defaultTemplatePath, - jsRuntimeWrapper: _jsRuntimeWrapper, - root: _root, - faviconPath: _faviconPath), + config: _config, + defaultTemplatePath: _defaultTemplatePath, + jsRuntimeWrapper: _jsRuntimeWrapper, + root: _root, + faviconPath: _faviconPath, + ), _ => throw StateError('Unexpected compiler $compiler'), }; }); @@ -100,19 +115,23 @@ class BrowserPlatform extends PlatformPlugin /// Settings for invoking each browser. /// /// This starts out with the default settings, which may be overridden by user settings. - final _browserSettings = - Map.from(defaultSettings); + final _browserSettings = Map.from( + defaultSettings, + ); /// The default template for html tests. final String _defaultTemplatePath; final String _faviconPath; - BrowserPlatform._(Configuration config, this._faviconPath, - this._defaultTemplatePath, this._jsRuntimeWrapper, - {String? root}) - : _config = config, - _root = root ?? p.current; + BrowserPlatform._( + Configuration config, + this._faviconPath, + this._defaultTemplatePath, + this._jsRuntimeWrapper, { + String? root, + }) : _config = config, + _root = root ?? p.current; @override ExecutableSettings parsePlatformSettings(YamlMap settings) => @@ -120,8 +139,9 @@ class BrowserPlatform extends PlatformPlugin @override ExecutableSettings mergePlatformSettings( - ExecutableSettings settings1, ExecutableSettings settings2) => - settings1.merge(settings2); + ExecutableSettings settings1, + ExecutableSettings settings2, + ) => settings1.merge(settings2); @override void customizePlatform(Runtime runtime, ExecutableSettings settings) { @@ -136,8 +156,12 @@ class BrowserPlatform extends PlatformPlugin /// This will start a browser to load the suite if one isn't already running. /// Throws an [ArgumentError] if `platform.platform` isn't a browser. @override - Future load(String path, SuitePlatform platform, - SuiteConfiguration suiteConfig, Map message) async { + Future load( + String path, + SuitePlatform platform, + SuiteConfiguration suiteConfig, + Map message, + ) async { var browser = platform.runtime; assert(suiteConfig.runtimes.contains(browser.identifier)); @@ -154,22 +178,27 @@ class BrowserPlatform extends PlatformPlugin p.basename(htmlPathFromTestPath) == p.basename(_config.customHtmlTemplatePath!)) { throw LoadException( - path, - 'template file "${p.basename(_config.customHtmlTemplatePath!)}" cannot be named ' - 'like the test file.'); + path, + 'template file "${p.basename(_config.customHtmlTemplatePath!)}" cannot be named ' + 'like the test file.', + ); } _checkHtmlCorrectness(htmlPathFromTestPath, path); } else if (_config.customHtmlTemplatePath != null) { var htmlTemplatePath = _config.customHtmlTemplatePath!; if (!File(htmlTemplatePath).existsSync()) { throw LoadException( - path, '"$htmlTemplatePath" does not exist or is not readable'); + path, + '"$htmlTemplatePath" does not exist or is not readable', + ); } final templateFileContents = File(htmlTemplatePath).readAsStringSync(); if ('{{testScript}}'.allMatches(templateFileContents).length != 1) { - throw LoadException(path, - '"$htmlTemplatePath" must contain exactly one {{testScript}} placeholder'); + throw LoadException( + path, + '"$htmlTemplatePath" must contain exactly one {{testScript}} placeholder', + ); } _checkHtmlCorrectness(htmlTemplatePath, path); } @@ -178,7 +207,8 @@ class BrowserPlatform extends PlatformPlugin await support.compileSuite(path, suiteConfig, platform); var suiteUrl = support.serverUrl.resolveUri( - p.toUri('${p.withoutExtension(p.relative(path, from: _root))}.html')); + p.toUri('${p.withoutExtension(p.relative(path, from: _root))}.html'), + ); if (_closed) return null; @@ -191,9 +221,14 @@ class BrowserPlatform extends PlatformPlugin timeout = suiteTimeout; } var suite = await browserManager.load( - path, suiteUrl, suiteConfig, message, platform.compiler, - mapper: (await compilerSupport(compiler)).stackTraceMapperForPath(path), - timeout: timeout); + path, + suiteUrl, + suiteConfig, + message, + platform.compiler, + mapper: (await compilerSupport(compiler)).stackTraceMapperForPath(path), + timeout: timeout, + ); if (_closed) return null; return suite; } @@ -201,9 +236,10 @@ class BrowserPlatform extends PlatformPlugin void _checkHtmlCorrectness(String htmlPath, String path) { if (!File(htmlPath).readAsStringSync().contains('packages/test/dart.js')) { throw LoadException( - path, - '"$htmlPath" must contain .'); + path, + '"$htmlPath" must contain .', + ); } } @@ -211,32 +247,44 @@ class BrowserPlatform extends PlatformPlugin /// /// If no browser manager is running yet, starts one. Future _browserManagerFor( - Runtime browser, Compiler compiler) { + Runtime browser, + Compiler compiler, + ) { var managerFuture = _browserManagers[(browser, compiler)]; if (managerFuture != null) return managerFuture; var future = _createBrowserManager(browser, compiler); // Store null values for browsers that error out so we know not to load them // again. - _browserManagers[(browser, compiler)] = - future.then((value) => value).onError((_, __) => null); + _browserManagers[(browser, compiler)] = future + .then((value) => value) + .onError((_, __) => null); return future; } Future _createBrowserManager( - Runtime browser, Compiler compiler) async { + Runtime browser, + Compiler compiler, + ) async { var support = await compilerSupport(compiler); var (webSocketUrl, socketFuture) = support.webSocket; var hostUrl = support.serverUrl .resolve('packages/test/src/runner/browser/static/index.html') - .replace(queryParameters: { - 'managerUrl': webSocketUrl.toString(), - 'debug': _config.debug.toString() - }); + .replace( + queryParameters: { + 'managerUrl': webSocketUrl.toString(), + 'debug': _config.debug.toString(), + }, + ); return BrowserManager.start( - browser, hostUrl, socketFuture, _browserSettings[browser]!, _config); + browser, + hostUrl, + socketFuture, + _browserSettings[browser]!, + _config, + ); } /// Close all the browsers that the server currently has open. @@ -247,11 +295,13 @@ class BrowserPlatform extends PlatformPlugin Future> closeEphemeral() { var managers = _browserManagers.values.toList(); _browserManagers.clear(); - return Future.wait(managers.map((manager) async { - var result = await manager; - if (result == null) return; - await result.close(); - })); + return Future.wait( + managers.map((manager) async { + var result = await manager; + if (result == null) return; + await result.close(); + }), + ); } /// Closes the server and releases all its resources. @@ -259,11 +309,13 @@ class BrowserPlatform extends PlatformPlugin /// Returns a [Future] that completes once the server is closed and its /// resources have been fully released. @override - Future close() async => _closeMemo.runOnce(() => Future.wait([ - for (var browser in _browserManagers.values) - browser.then((b) => b?.close()), - for (var support in _compilerSupport.values) - support.then((s) => s.close()), - ])); + Future close() async => _closeMemo.runOnce( + () => Future.wait([ + for (var browser in _browserManagers.values) + browser.then((b) => b?.close()), + for (var support in _compilerSupport.values) + support.then((s) => s.close()), + ]), + ); final _closeMemo = AsyncMemoizer(); } diff --git a/pkgs/test/lib/src/runner/browser/post_message_channel.dart b/pkgs/test/lib/src/runner/browser/post_message_channel.dart index 229a33cd5..fedf77ea3 100644 --- a/pkgs/test/lib/src/runner/browser/post_message_channel.dart +++ b/pkgs/test/lib/src/runner/browser/post_message_channel.dart @@ -16,16 +16,20 @@ StreamChannel postMessageChannel() { dom.window.console.log('Suite starting, sending channel to host'.toJS); var controller = StreamChannelController(sync: true); var channel = dom.createMessageChannel(); - dom.window.parent - .postMessage('port', dom.window.location.origin, [channel.port2]); - var portSubscription = - dom.Subscription(channel.port1, 'message', (dom.Event event) { + dom.window.parent.postMessage('port', dom.window.location.origin, [ + channel.port2, + ]); + var portSubscription = dom.Subscription(channel.port1, 'message', ( + dom.Event event, + ) { controller.local.sink.add((event as dom.MessageEvent).data); }); channel.port1.start(); - controller.local.stream - .listen(channel.port1.postMessage, onDone: portSubscription.cancel); + controller.local.stream.listen( + channel.port1.postMessage, + onDone: portSubscription.cancel, + ); return controller.foreign; } diff --git a/pkgs/test/lib/src/runner/browser/safari.dart b/pkgs/test/lib/src/runner/browser/safari.dart index 4e97205b6..0ac6d6a07 100644 --- a/pkgs/test/lib/src/runner/browser/safari.dart +++ b/pkgs/test/lib/src/runner/browser/safari.dart @@ -22,13 +22,16 @@ class Safari extends Browser { final name = 'Safari'; Safari(Uri url, {ExecutableSettings? settings}) - : super(() => - _startBrowser(url, settings ?? defaultSettings[Runtime.safari]!)); + : super( + () => _startBrowser(url, settings ?? defaultSettings[Runtime.safari]!), + ); /// Starts a new instance of Safari open to the given [url], which may be a /// [Uri] or a [String]. static Future _startBrowser( - Uri url, ExecutableSettings settings) async { + Uri url, + ExecutableSettings settings, + ) async { var dir = createTempDir(); // Safari will only open files (not general URLs) via the command-line @@ -36,10 +39,13 @@ class Safari extends Browser { // want it to load. var redirect = p.join(dir, 'redirect.html'); File(redirect).writeAsStringSync( - ''); + '', + ); var process = await Process.start( - settings.executable, settings.arguments.toList()..add(redirect)); + settings.executable, + settings.arguments.toList()..add(redirect), + ); unawaited(process.exitCode.then((_) => Directory(dir).deleteWithRetry())); diff --git a/pkgs/test/lib/src/runner/executable_settings.dart b/pkgs/test/lib/src/runner/executable_settings.dart index 904dc5149..71eb54c16 100644 --- a/pkgs/test/lib/src/runner/executable_settings.dart +++ b/pkgs/test/lib/src/runner/executable_settings.dart @@ -56,13 +56,16 @@ class ExecutableSettings { if (File(path).existsSync()) return path; } else { throw ArgumentError( - 'Mac OS executable must be a basename or an absolute path.' - ' Got relative path: $path'); + 'Mac OS executable must be a basename or an absolute path.' + ' Got relative path: $path', + ); } } } - throw ArgumentError('Could not find a command basename or an existing ' - 'path in $_macOSExectuables'); + throw ArgumentError( + 'Could not find a command basename or an existing ' + 'path in $_macOSExectuables', + ); } if (!Platform.isWindows) return _linuxExecutable!; final windowsExecutable = _windowsExecutable!; @@ -74,7 +77,7 @@ class ExecutableSettings { var prefixes = [ Platform.environment['LOCALAPPDATA'], Platform.environment['PROGRAMFILES'], - Platform.environment['PROGRAMFILES(X86)'] + Platform.environment['PROGRAMFILES(X86)'], ]; for (var prefix in prefixes) { @@ -87,8 +90,9 @@ class ExecutableSettings { // If we can't find a path that works, return one that doesn't. This will // cause an "executable not found" error to surface. return p.join( - prefixes.firstWhere((prefix) => prefix != null, orElse: () => '.')!, - _windowsExecutable); + prefixes.firstWhere((prefix) => prefix != null, orElse: () => '.')!, + _windowsExecutable, + ); } /// Whether to invoke the browser in headless mode. @@ -111,7 +115,9 @@ class ExecutableSettings { } } else { throw SourceSpanFormatException( - 'Must be a string.', argumentsNode.span); + 'Must be a string.', + argumentsNode.span, + ); } } @@ -134,11 +140,15 @@ class ExecutableSettings { } else if (executableNode is YamlMap) { linuxExecutable = _getExecutable(executableNode.nodes['linux']); macOSExecutable = _getExecutable(executableNode.nodes['mac_os']); - windowsExecutable = _getExecutable(executableNode.nodes['windows'], - allowRelative: true); + windowsExecutable = _getExecutable( + executableNode.nodes['windows'], + allowRelative: true, + ); } else { throw SourceSpanFormatException( - 'Must be a map or a string.', executableNode.span); + 'Must be a map or a string.', + executableNode.span, + ); } } @@ -150,24 +160,29 @@ class ExecutableSettings { headless = value; } else { throw SourceSpanFormatException( - 'Must be a boolean.', headlessNode.span); + 'Must be a boolean.', + headlessNode.span, + ); } } return ExecutableSettings( - arguments: arguments, - linuxExecutable: linuxExecutable, - macOSExecutable: macOSExecutable, - windowsExecutable: windowsExecutable, - headless: headless); + arguments: arguments, + linuxExecutable: linuxExecutable, + macOSExecutable: macOSExecutable, + windowsExecutable: windowsExecutable, + headless: headless, + ); } /// Asserts that [executableNode] is a string or `null` and returns it. /// /// If [allowRelative] is `false` (the default), asserts that the value isn't /// a relative path. - static String? _getExecutable(YamlNode? executableNode, - {bool allowRelative = false}) { + static String? _getExecutable( + YamlNode? executableNode, { + bool allowRelative = false, + }) { if (executableNode == null || executableNode.value == null) return null; if (executableNode.value is! String) { throw SourceSpanFormatException('Must be a string.', executableNode.span); @@ -187,37 +202,43 @@ class ExecutableSettings { if (p.posix.basename(executable) == executable) return; throw SourceSpanFormatException( - 'Linux and Mac OS executables may not be relative paths.', - executableNode.span); + 'Linux and Mac OS executables may not be relative paths.', + executableNode.span, + ); } - ExecutableSettings( - {Iterable? arguments, - String? linuxExecutable, - String? macOSExecutable, - List? macOSExecutables, - String? windowsExecutable, - String? environmentOverride, - bool? headless}) - : arguments = arguments == null ? const [] : List.unmodifiable(arguments), - _linuxExecutable = linuxExecutable, - _macOSExectuables = - _normalizeMacExecutable(macOSExecutable, macOSExecutables), - _windowsExecutable = windowsExecutable, - _environmentOverride = environmentOverride, - _headless = headless; + ExecutableSettings({ + Iterable? arguments, + String? linuxExecutable, + String? macOSExecutable, + List? macOSExecutables, + String? windowsExecutable, + String? environmentOverride, + bool? headless, + }) : arguments = arguments == null ? const [] : List.unmodifiable(arguments), + _linuxExecutable = linuxExecutable, + _macOSExectuables = _normalizeMacExecutable( + macOSExecutable, + macOSExecutables, + ), + _windowsExecutable = windowsExecutable, + _environmentOverride = environmentOverride, + _headless = headless; /// Merges [this] with [other], with [other]'s settings taking priority. ExecutableSettings merge(ExecutableSettings other) => ExecutableSettings( - arguments: arguments.toList()..addAll(other.arguments), - headless: other._headless ?? _headless, - linuxExecutable: other._linuxExecutable ?? _linuxExecutable, - macOSExecutables: other._macOSExectuables ?? _macOSExectuables, - windowsExecutable: other._windowsExecutable ?? _windowsExecutable); + arguments: arguments.toList()..addAll(other.arguments), + headless: other._headless ?? _headless, + linuxExecutable: other._linuxExecutable ?? _linuxExecutable, + macOSExecutables: other._macOSExectuables ?? _macOSExectuables, + windowsExecutable: other._windowsExecutable ?? _windowsExecutable, + ); } List? _normalizeMacExecutable( - String? singleArgument, List? listArgument) { + String? singleArgument, + List? listArgument, +) { if (listArgument != null) return listArgument; if (singleArgument != null) return [singleArgument]; return null; diff --git a/pkgs/test/lib/src/runner/node/platform.dart b/pkgs/test/lib/src/runner/node/platform.dart index 16cd9c6ee..e3357b853 100644 --- a/pkgs/test/lib/src/runner/node/platform.dart +++ b/pkgs/test/lib/src/runner/node/platform.dart @@ -51,9 +51,10 @@ class NodePlatform extends PlatformPlugin /// it. final _settings = { Runtime.nodeJS: ExecutableSettings( - linuxExecutable: 'node', - macOSExecutable: 'node', - windowsExecutable: 'node.exe') + linuxExecutable: 'node', + macOSExecutable: 'node', + windowsExecutable: 'node.exe', + ), }; NodePlatform() : _config = Configuration.current; @@ -64,8 +65,9 @@ class NodePlatform extends PlatformPlugin @override ExecutableSettings mergePlatformSettings( - ExecutableSettings settings1, ExecutableSettings settings2) => - settings1.merge(settings2); + ExecutableSettings settings1, + ExecutableSettings settings2, + ) => settings1.merge(settings2); @override void customizePlatform(Runtime runtime, ExecutableSettings settings) { @@ -75,17 +77,31 @@ class NodePlatform extends PlatformPlugin } @override - Future load(String path, SuitePlatform platform, - SuiteConfiguration suiteConfig, Map message) async { + Future load( + String path, + SuitePlatform platform, + SuiteConfiguration suiteConfig, + Map message, + ) async { if (platform.compiler != Compiler.dart2js && platform.compiler != Compiler.dart2wasm) { throw StateError( - 'Unsupported compiler for the Node platform ${platform.compiler}.'); + 'Unsupported compiler for the Node platform ${platform.compiler}.', + ); } - var (channel, stackMapper) = - await _loadChannel(path, platform, suiteConfig); - var controller = deserializeSuite(path, platform, suiteConfig, - const PluginEnvironment(), channel, message); + var (channel, stackMapper) = await _loadChannel( + path, + platform, + suiteConfig, + ); + var controller = deserializeSuite( + path, + platform, + suiteConfig, + const PluginEnvironment(), + channel, + message, + ); controller.channel('test.node.mapper').sink.add(stackMapper?.serialize()); @@ -96,13 +112,20 @@ class NodePlatform extends PlatformPlugin /// /// Returns that channel along with a [StackTraceMapper] representing the /// source map for the compiled suite. - Future<(StreamChannel, StackTraceMapper?)> _loadChannel(String path, - SuitePlatform platform, SuiteConfiguration suiteConfig) async { + Future<(StreamChannel, StackTraceMapper?)> _loadChannel( + String path, + SuitePlatform platform, + SuiteConfiguration suiteConfig, + ) async { final servers = await _loopback(); try { - var (process, stackMapper) = - await _spawnProcess(path, platform, suiteConfig, servers.first.port); + var (process, stackMapper) = await _spawnProcess( + path, + platform, + suiteConfig, + servers.first.port, + ); // Forward Node's standard IO to the print handler so it's associated with // the load test. @@ -121,22 +144,36 @@ class NodePlatform extends PlatformPlugin if (socket == null) { throw LoadException( - path, 'Node exited before connecting to the test channel.'); + path, + 'Node exited before connecting to the test channel.', + ); } var channel = StreamChannel(socket.cast>(), socket) .transform(StreamChannelTransformer.fromCodec(utf8)) .transform(_chunksToLines) .transform(jsonDocument) - .transformStream(StreamTransformer.fromHandlers(handleDone: (sink) { - process.kill(); - sink.close(); - })); + .transformStream( + StreamTransformer.fromHandlers( + handleDone: (sink) { + process.kill(); + sink.close(); + }, + ), + ); return (channel, stackMapper); } finally { - unawaited(Future.wait(servers.map((s) => - s.close().then((v) => v).onError((_, __) => null)))); + unawaited( + Future.wait( + servers.map( + (s) => s + .close() + .then((v) => v) + .onError((_, __) => null), + ), + ), + ); } } @@ -145,26 +182,42 @@ class NodePlatform extends PlatformPlugin /// Returns that channel along with a [StackTraceMapper] representing the /// source map for the compiled suite. Future<(Process, StackTraceMapper?)> _spawnProcess( - String path, - SuitePlatform platform, - SuiteConfiguration suiteConfig, - int socketPort) async { + String path, + SuitePlatform platform, + SuiteConfiguration suiteConfig, + int socketPort, + ) async { if (_config.suiteDefaults.precompiledPath != null) { - return _spawnPrecompiledProcess(path, platform.runtime, suiteConfig, - socketPort, _config.suiteDefaults.precompiledPath!); + return _spawnPrecompiledProcess( + path, + platform.runtime, + suiteConfig, + socketPort, + _config.suiteDefaults.precompiledPath!, + ); } else { return switch (platform.compiler) { Compiler.dart2js => _spawnNormalJsProcess( - path, platform.runtime, suiteConfig, socketPort), + path, + platform.runtime, + suiteConfig, + socketPort, + ), Compiler.dart2wasm => _spawnNormalWasmProcess( - path, platform.runtime, suiteConfig, socketPort), + path, + platform.runtime, + suiteConfig, + socketPort, + ), _ => throw StateError('Unsupported compiler ${platform.compiler}'), }; } } Future _entrypointScriptForTest( - String testPath, SuiteConfiguration suiteConfig) async { + String testPath, + SuiteConfiguration suiteConfig, + ) async { return ''' ${suiteConfig.metadata.languageVersionComment ?? await rootPackageLanguageVersionComment} import "package:test/src/bootstrap/node.dart"; @@ -179,8 +232,12 @@ class NodePlatform extends PlatformPlugin /// Compiles [testPath] with dart2js, adds the node preamble, and then spawns /// a Node.js process that loads that Dart test suite. - Future<(Process, StackTraceMapper?)> _spawnNormalJsProcess(String testPath, - Runtime runtime, SuiteConfiguration suiteConfig, int socketPort) async { + Future<(Process, StackTraceMapper?)> _spawnNormalJsProcess( + String testPath, + Runtime runtime, + SuiteConfiguration suiteConfig, + int socketPort, + ) async { var dir = Directory(_compiledDir).createTempSync('test_').path; var jsPath = p.join(dir, '${p.basename(testPath)}.node_test.dart.js'); await _jsCompilers.compile( @@ -193,15 +250,18 @@ class NodePlatform extends PlatformPlugin // compatible. Use the minified version so the source map remains valid. var jsFile = File(jsPath); await jsFile.writeAsString( - preamble.getPreamble(minified: true) + await jsFile.readAsString()); + preamble.getPreamble(minified: true) + await jsFile.readAsString(), + ); StackTraceMapper? mapper; if (!suiteConfig.jsTrace) { var mapPath = '$jsPath.map'; - mapper = JSStackTraceMapper(await File(mapPath).readAsString(), - mapUrl: p.toUri(mapPath), - sdkRoot: Uri.parse('org-dartlang-sdk:///sdk'), - packageMap: (await currentPackageConfig).toPackageMap()); + mapper = JSStackTraceMapper( + await File(mapPath).readAsString(), + mapUrl: p.toUri(mapPath), + sdkRoot: Uri.parse('org-dartlang-sdk:///sdk'), + packageMap: (await currentPackageConfig).toPackageMap(), + ); } return (await _startProcess(runtime, jsPath, socketPort), mapper); @@ -209,8 +269,12 @@ class NodePlatform extends PlatformPlugin /// Compiles [testPath] with dart2wasm, adds a JS entrypoint and then spawns /// a Node.js process loading the compiled test suite. - Future<(Process, StackTraceMapper?)> _spawnNormalWasmProcess(String testPath, - Runtime runtime, SuiteConfiguration suiteConfig, int socketPort) async { + Future<(Process, StackTraceMapper?)> _spawnNormalWasmProcess( + String testPath, + Runtime runtime, + SuiteConfiguration suiteConfig, + int socketPort, + ) async { var dir = Directory(_compiledDir).createTempSync('test_').path; // dart2wasm will emit a .wasm file and a .mjs file responsible for loading // that file. @@ -261,20 +325,25 @@ main(); /// Spawns a Node.js process that loads the Dart test suite at [testPath] /// under [precompiledPath]. Future<(Process, StackTraceMapper?)> _spawnPrecompiledProcess( - String testPath, - Runtime runtime, - SuiteConfiguration suiteConfig, - int socketPort, - String precompiledPath) async { + String testPath, + Runtime runtime, + SuiteConfiguration suiteConfig, + int socketPort, + String precompiledPath, + ) async { StackTraceMapper? mapper; var jsPath = p.join(precompiledPath, '$testPath.node_test.dart.js'); if (!suiteConfig.jsTrace) { var mapPath = '$jsPath.map'; - mapper = JSStackTraceMapper(await File(mapPath).readAsString(), - mapUrl: p.toUri(mapPath), - sdkRoot: Uri.parse('org-dartlang-sdk:///sdk'), - packageMap: (await findPackageConfig(Directory(precompiledPath)))! - .toPackageMap()); + mapper = JSStackTraceMapper( + await File(mapPath).readAsString(), + mapUrl: p.toUri(mapPath), + sdkRoot: Uri.parse('org-dartlang-sdk:///sdk'), + packageMap: + (await findPackageConfig( + Directory(precompiledPath), + ))!.toPackageMap(), + ); } return (await _startProcess(runtime, jsPath, socketPort), mapper); @@ -282,7 +351,10 @@ main(); /// Starts the Node.js process for [runtime] with [jsPath]. Future _startProcess( - Runtime runtime, String jsPath, int socketPort) async { + Runtime runtime, + String jsPath, + int socketPort, + ) async { var settings = _settings[runtime]!; var nodeModules = p.absolute('node_modules'); @@ -291,25 +363,28 @@ main(); try { return await Process.start( - settings.executable, - settings.arguments.toList() - ..add(jsPath) - ..add(socketPort.toString()), - environment: {'NODE_PATH': nodePath}); + settings.executable, + settings.arguments.toList() + ..add(jsPath) + ..add(socketPort.toString()), + environment: {'NODE_PATH': nodePath}, + ); } catch (error, stackTrace) { await Future.error( - ApplicationException( - 'Failed to run ${runtime.name}: ${getErrorMessage(error)}'), - stackTrace); + ApplicationException( + 'Failed to run ${runtime.name}: ${getErrorMessage(error)}', + ), + stackTrace, + ); } } @override Future close() => _closeMemo.runOnce(() async { - await _jsCompilers.close(); - await _wasmCompilers.close(); - await Directory(_compiledDir).deleteWithRetry(); - }); + await _jsCompilers.close(); + await _wasmCompilers.close(); + await Directory(_compiledDir).deleteWithRetry(); + }); final _closeMemo = AsyncMemoizer(); } @@ -324,8 +399,10 @@ Future> _loopback({int remainingRetries = 5}) async { try { // Reuse the IPv4 server's port so that if [port] is 0, both servers use // the same ephemeral port. - var v6Server = - await ServerSocket.bind(InternetAddress.loopbackIPv6, v4Server.port); + var v6Server = await ServerSocket.bind( + InternetAddress.loopbackIPv6, + v4Server.port, + ); return [v4Server, v6Server]; } on SocketException catch (error) { if (error.osError?.errorCode != _addressInUseErrno) rethrow; @@ -375,6 +452,8 @@ final int _addressInUseErrno = () { /// Note that this is only safe for channels whose messages are guaranteed not /// to contain newlines. final _chunksToLines = StreamChannelTransformer( - const LineSplitter(), - StreamSinkTransformer.fromHandlers( - handleData: (data, sink) => sink.add('$data\n'))); + const LineSplitter(), + StreamSinkTransformer.fromHandlers( + handleData: (data, sink) => sink.add('$data\n'), + ), +); diff --git a/pkgs/test/lib/src/runner/node/socket_channel.dart b/pkgs/test/lib/src/runner/node/socket_channel.dart index 95e81de96..6356f3f11 100644 --- a/pkgs/test/lib/src/runner/node/socket_channel.dart +++ b/pkgs/test/lib/src/runner/node/socket_channel.dart @@ -38,6 +38,7 @@ Future> socketChannel() async { ); return StreamChannel.withCloseGuarantee( - socketStream.stream.transform(const LineSplitter()).map(jsonDecode), - socketSink); + socketStream.stream.transform(const LineSplitter()).map(jsonDecode), + socketSink, + ); } diff --git a/pkgs/test/lib/src/util/package_map.dart b/pkgs/test/lib/src/util/package_map.dart index 6b30afaba..12359db0f 100644 --- a/pkgs/test/lib/src/util/package_map.dart +++ b/pkgs/test/lib/src/util/package_map.dart @@ -7,13 +7,14 @@ import 'package:package_config/package_config.dart'; /// Adds methods to convert to a package map on [PackageConfig]. extension PackageMap on PackageConfig { /// A package map exactly matching the current package config - Map toPackageMap() => - {for (var package in packages) package.name: package.packageUriRoot}; + Map toPackageMap() => { + for (var package in packages) package.name: package.packageUriRoot, + }; /// A package map with all the current packages but where the uris are all /// of the form 'packages/${package.name}'. Map toPackagesDirPackageMap() => { - for (var package in packages) - package.name: Uri.parse('packages/${package.name}') - }; + for (var package in packages) + package.name: Uri.parse('packages/${package.name}'), + }; } diff --git a/pkgs/test/lib/src/util/path_handler.dart b/pkgs/test/lib/src/util/path_handler.dart index 10a8c4e43..c246e80b8 100644 --- a/pkgs/test/lib/src/util/path_handler.dart +++ b/pkgs/test/lib/src/util/path_handler.dart @@ -50,8 +50,9 @@ class PathHandler { if (handler == null) return shelf.Response.notFound('Not found.'); - return handler(request.change( - path: p.url.joinAll(components.take(handlerIndex! + 1)))); + return handler( + request.change(path: p.url.joinAll(components.take(handlerIndex! + 1))), + ); } } diff --git a/pkgs/test/test/io.dart b/pkgs/test/test/io.dart index b13f8bdda..3e878fca1 100644 --- a/pkgs/test/test/io.dart +++ b/pkgs/test/test/io.dart @@ -12,9 +12,9 @@ import 'package:test_descriptor/test_descriptor.dart' as d; import 'package:test_process/test_process.dart'; /// The path to the root directory of the `test` package. -final Future packageDir = - Isolate.resolvePackageUri(Uri(scheme: 'package', path: 'test/')) - .then((uri) { +final Future packageDir = Isolate.resolvePackageUri( + Uri(scheme: 'package', path: 'test/'), +).then((uri) { var dir = p.dirname(uri!.path); // If it starts with a `/C:` or other drive letter, remove the leading `/`. if (dir[0] == '/' && dir[2] == ':') dir = dir.substring(1); @@ -22,13 +22,18 @@ final Future packageDir = }); /// The path to the `pub` executable in the current Dart SDK. -final _pubPath = p.absolute(p.join(p.dirname(Platform.resolvedExecutable), - Platform.isWindows ? 'pub.bat' : 'pub')); +final _pubPath = p.absolute( + p.join( + p.dirname(Platform.resolvedExecutable), + Platform.isWindows ? 'pub.bat' : 'pub', + ), +); /// The platform-specific message emitted when a nonexistent file is loaded. -final String noSuchFileMessage = Platform.isWindows - ? 'The system cannot find the file specified.' - : 'No such file or directory'; +final String noSuchFileMessage = + Platform.isWindows + ? 'The system cannot find the file specified.' + : 'No such file or directory'; /// An operating system name that's different than the current operating system. final otherOS = Platform.isWindows ? 'mac-os' : 'windows'; @@ -43,10 +48,13 @@ void expectStderrEquals(TestProcess test, String expected) => /// Expects that the entirety of the line stream [stream] equals [expected]. void _expectStreamEquals(Stream stream, String expected) { - expect((() async { - var lines = await stream.toList(); - expect(lines.join('\n').trim(), equals(expected.trim())); - })(), completes); + expect( + (() async { + var lines = await stream.toList(); + expect(lines.join('\n').trim(), equals(expected.trim())); + })(), + completes, + ); } /// Returns a [StreamMatcher] that asserts that the stream emits strings @@ -78,7 +86,8 @@ Future precompileTestExecutable() async { ]); if (result.exitCode != 0) { throw StateError( - 'Failed to compile test runner:\n${result.stdout}\n${result.stderr}'); + 'Failed to compile test runner:\n${result.stdout}\n${result.stderr}', + ); } addTearDown(() async { @@ -90,19 +99,22 @@ Future precompileTestExecutable() async { /// Runs the test executable with the package root set properly. /// /// You must invoke [precompileTestExecutable] before invoking this function. -Future runTest(Iterable args, - {String? reporter, - String? fileReporter, - int? concurrency, - Map? environment, - bool forwardStdio = false, - String? packageConfig, - Iterable? vmArgs}) async { +Future runTest( + Iterable args, { + String? reporter, + String? fileReporter, + int? concurrency, + Map? environment, + bool forwardStdio = false, + String? packageConfig, + Iterable? vmArgs, +}) async { concurrency ??= 1; var testExecutablePath = _testExecutablePath; if (testExecutablePath == null) { throw StateError( - 'You must call `precompileTestExecutable` before calling `runTest`'); + 'You must call `precompileTestExecutable` before calling `runTest`', + ); } var allArgs = [ @@ -117,42 +129,55 @@ Future runTest(Iterable args, environment ??= {}; environment.putIfAbsent('_DART_TEST_TESTING', () => 'true'); - return await runDart(allArgs, - environment: environment, - description: 'dart bin/test.dart', - forwardStdio: forwardStdio, - packageConfig: packageConfig); + return await runDart( + allArgs, + environment: environment, + description: 'dart bin/test.dart', + forwardStdio: forwardStdio, + packageConfig: packageConfig, + ); } /// Runs Dart. /// /// If [packageConfig] is provided then that is passed for the `--packages` /// arg, otherwise the current isolate config is passed. -Future runDart(Iterable args, - {Map? environment, - String? description, - bool forwardStdio = false, - String? packageConfig}) async { +Future runDart( + Iterable args, { + Map? environment, + String? description, + bool forwardStdio = false, + String? packageConfig, +}) async { var allArgs = [ - ...Platform.executableArguments.where((arg) => - !arg.startsWith('--package-root=') && !arg.startsWith('--packages=')), + ...Platform.executableArguments.where( + (arg) => + !arg.startsWith('--package-root=') && !arg.startsWith('--packages='), + ), '--packages=${packageConfig ?? await Isolate.packageConfig}', - ...args + ...args, ]; return await TestProcess.start( - p.absolute(Platform.resolvedExecutable), allArgs, - workingDirectory: d.sandbox, - environment: environment, - description: description, - forwardStdio: forwardStdio); + p.absolute(Platform.resolvedExecutable), + allArgs, + workingDirectory: d.sandbox, + environment: environment, + description: description, + forwardStdio: forwardStdio, + ); } /// Runs Pub. -Future runPub(Iterable args, - {Map? environment}) { - return TestProcess.start(_pubPath, args, - workingDirectory: d.sandbox, - environment: environment, - description: 'pub ${args.first}'); +Future runPub( + Iterable args, { + Map? environment, +}) { + return TestProcess.start( + _pubPath, + args, + workingDirectory: d.sandbox, + environment: environment, + description: 'pub ${args.first}', + ); } diff --git a/pkgs/test/test/runner/browser/chrome_test.dart b/pkgs/test/test/runner/browser/chrome_test.dart index ffec2279e..8663d2e26 100644 --- a/pkgs/test/test/runner/browser/chrome_test.dart +++ b/pkgs/test/test/runner/browser/chrome_test.dart @@ -18,25 +18,28 @@ import 'code_server.dart'; void main() { setUpAll(precompileTestExecutable); - test('starts Chrome with the given URL', () async { - var server = await CodeServer.start(); + test( + 'starts Chrome with the given URL', + () async { + var server = await CodeServer.start(); - server.handleJavaScript(''' + server.handleJavaScript(''' var webSocket = new WebSocket(window.location.href.replace("http://", "ws://")); webSocket.addEventListener("open", function() { webSocket.send("loaded!"); }); '''); - var webSocket = server.handleWebSocket(); + var webSocket = server.handleWebSocket(); - var chrome = Chrome(server.url, configuration()); - addTearDown(() => chrome.close()); + var chrome = Chrome(server.url, configuration()); + addTearDown(() => chrome.close()); - expect(await (await webSocket).stream.first, equals('loaded!')); - }, - // It's not clear why, but this test in particular seems to time out - // when run in parallel with many other tests. - timeout: const Timeout.factor(2)); + expect(await (await webSocket).stream.first, equals('loaded!')); + }, + // It's not clear why, but this test in particular seems to time out + // when run in parallel with many other tests. + timeout: const Timeout.factor(2), + ); test("a process can be killed synchronously after it's started", () async { var server = await CodeServer.start(); @@ -45,15 +48,23 @@ webSocket.addEventListener("open", function() { }); test('reports an error in onExit', () { - var chrome = Chrome(Uri.https('dart.dev'), configuration(), - settings: ExecutableSettings( - linuxExecutable: '_does_not_exist', - macOSExecutable: '_does_not_exist', - windowsExecutable: '_does_not_exist')); + var chrome = Chrome( + Uri.https('dart.dev'), + configuration(), + settings: ExecutableSettings( + linuxExecutable: '_does_not_exist', + macOSExecutable: '_does_not_exist', + windowsExecutable: '_does_not_exist', + ), + ); expect( - chrome.onExit, - throwsA(isApplicationException( - startsWith('Failed to run Chrome: $noSuchFileMessage')))); + chrome.onExit, + throwsA( + isApplicationException( + startsWith('Failed to run Chrome: $noSuchFileMessage'), + ), + ), + ); }); test('can run successful tests', () async { @@ -92,8 +103,10 @@ void main() { test("success", () {}); } ''').create(); - var test = await runTest(['-p', 'chrome', 'test.dart'], - environment: {'CHROME_EXECUTABLE': '/some/bad/path'}); + var test = await runTest( + ['-p', 'chrome', 'test.dart'], + environment: {'CHROME_EXECUTABLE': '/some/bad/path'}, + ); expect(test.stdout, emitsThrough(contains('Failed to run Chrome:'))); await test.shouldExit(1); }); diff --git a/pkgs/test/test/runner/browser/code_server.dart b/pkgs/test/test/runner/browser/code_server.dart index 1aba5dea5..958b30a00 100644 --- a/pkgs/test/test/runner/browser/code_server.dart +++ b/pkgs/test/test/runner/browser/code_server.dart @@ -39,19 +39,24 @@ class CodeServer { /// HTML page with a script tag that will run [javaScript]. void handleJavaScript(String javaScript) { _handler.expect('GET', '/', (_) { - return shelf.Response.ok(''' + return shelf.Response.ok( + ''' -''', headers: {'content-type': 'text/html'}); +''', + headers: {'content-type': 'text/html'}, + ); }); _handler.expect('GET', '/index.js', (_) { - return shelf.Response.ok(javaScript, - headers: {'content-type': 'application/javascript'}); + return shelf.Response.ok( + javaScript, + headers: {'content-type': 'application/javascript'}, + ); }); } @@ -61,9 +66,13 @@ class CodeServer { var completer = Completer(); // Note: the WebSocketChannel type below is needed for compatibility with // package:shelf_web_socket v2. - _handler.expect('GET', '/', webSocketHandler((WebSocketChannel ws, _) { - completer.complete(ws); - })); + _handler.expect( + 'GET', + '/', + webSocketHandler((WebSocketChannel ws, _) { + completer.complete(ws); + }), + ); return completer.future; } } @@ -105,7 +114,8 @@ class _Handler { try { if (_expectations.isEmpty) { throw TestFailure( - '$description received unexpected request $requestInfo.'); + '$description received unexpected request $requestInfo.', + ); } var expectation = _expectations.removeFirst(); diff --git a/pkgs/test/test/runner/browser/compact_reporter_test.dart b/pkgs/test/test/runner/browser/compact_reporter_test.dart index 753ffa127..267fabe2d 100644 --- a/pkgs/test/test/runner/browser/compact_reporter_test.dart +++ b/pkgs/test/test/runner/browser/compact_reporter_test.dart @@ -25,9 +25,15 @@ void main() { } ''').create(); - var test = await runTest( - ['-p', 'chrome', '-p', 'vm', '-j', '1', 'test.dart'], - reporter: 'compact'); + var test = await runTest([ + '-p', + 'chrome', + '-p', + 'vm', + '-j', + '1', + 'test.dart', + ], reporter: 'compact'); expect(test.stdout, containsInOrder(['[Chrome, Dart2Js]', '[VM, Kernel]'])); await test.shouldExit(0); diff --git a/pkgs/test/test/runner/browser/expanded_reporter_test.dart b/pkgs/test/test/runner/browser/expanded_reporter_test.dart index 875aaba0f..7c9a4d01c 100644 --- a/pkgs/test/test/runner/browser/expanded_reporter_test.dart +++ b/pkgs/test/test/runner/browser/expanded_reporter_test.dart @@ -13,8 +13,10 @@ import '../../io.dart'; void main() { setUpAll(precompileTestExecutable); - test('prints the platform name when running on multiple platforms', () async { - await d.file('test.dart', ''' + test( + 'prints the platform name when running on multiple platforms', + () async { + await d.file('test.dart', ''' import 'dart:async'; import 'package:test/test.dart'; @@ -24,13 +26,15 @@ void main() { } ''').create(); - var test = await runTest([ - '-r', 'expanded', '-p', 'chrome', '-p', 'vm', '-j', '1', // - 'test.dart' - ]); - - expect(test.stdoutStream(), emitsThrough(contains('[VM, Kernel]'))); - expect(test.stdout, emitsThrough(contains('[Chrome, Dart2Js]'))); - await test.shouldExit(0); - }, tags: ['chrome']); + var test = await runTest([ + '-r', 'expanded', '-p', 'chrome', '-p', 'vm', '-j', '1', // + 'test.dart', + ]); + + expect(test.stdoutStream(), emitsThrough(contains('[VM, Kernel]'))); + expect(test.stdout, emitsThrough(contains('[Chrome, Dart2Js]'))); + await test.shouldExit(0); + }, + tags: ['chrome'], + ); } diff --git a/pkgs/test/test/runner/browser/firefox_test.dart b/pkgs/test/test/runner/browser/firefox_test.dart index 864f49c49..cf89f9e97 100644 --- a/pkgs/test/test/runner/browser/firefox_test.dart +++ b/pkgs/test/test/runner/browser/firefox_test.dart @@ -42,15 +42,22 @@ webSocket.addEventListener("open", function() { }); test('reports an error in onExit', () { - var firefox = Firefox(Uri.https('dart.dev'), - settings: ExecutableSettings( - linuxExecutable: '_does_not_exist', - macOSExecutable: '_does_not_exist', - windowsExecutable: '_does_not_exist')); + var firefox = Firefox( + Uri.https('dart.dev'), + settings: ExecutableSettings( + linuxExecutable: '_does_not_exist', + macOSExecutable: '_does_not_exist', + windowsExecutable: '_does_not_exist', + ), + ); expect( - firefox.onExit, - throwsA(isApplicationException( - startsWith('Failed to run Firefox: $noSuchFileMessage')))); + firefox.onExit, + throwsA( + isApplicationException( + startsWith('Failed to run Firefox: $noSuchFileMessage'), + ), + ), + ); }); test('can run successful tests', () async { @@ -89,8 +96,10 @@ void main() { test("success", () {}); } ''').create(); - var test = await runTest(['-p', 'firefox', 'test.dart'], - environment: {'FIREFOX_EXECUTABLE': '/some/bad/path'}); + var test = await runTest( + ['-p', 'firefox', 'test.dart'], + environment: {'FIREFOX_EXECUTABLE': '/some/bad/path'}, + ); expect(test.stdout, emitsThrough(contains('Failed to run Firefox:'))); await test.shouldExit(1); }); @@ -107,8 +116,10 @@ void main() { }); } ''').create(); - var test = await runTest(['-p', 'firefox', 'test.dart'], - environment: {'CHROME_EXECUTABLE': '/some/bad/path'}); + var test = await runTest( + ['-p', 'firefox', 'test.dart'], + environment: {'CHROME_EXECUTABLE': '/some/bad/path'}, + ); expect(test.stdout, emitsThrough(contains('+1: All tests passed!'))); await test.shouldExit(0); }); diff --git a/pkgs/test/test/runner/browser/loader_test.dart b/pkgs/test/test/runner/browser/loader_test.dart index 17cdb9a6b..def00702c 100644 --- a/pkgs/test/test/runner/browser/loader_test.dart +++ b/pkgs/test/test/runner/browser/loader_test.dart @@ -27,8 +27,9 @@ import '../../utils.dart'; late Loader _loader; /// A configuration that loads suites on Chrome. -final _chrome = - SuiteConfiguration.runtimes([RuntimeSelection(Runtime.chrome.identifier)]); +final _chrome = SuiteConfiguration.runtimes([ + RuntimeSelection(Runtime.chrome.identifier), +]); void main() { setUp(() async { @@ -57,9 +58,10 @@ void main() { group('.loadFile()', () { late RunnerSuite suite; setUp(() async { - var suites = await _loader - .loadFile(p.join(d.sandbox, 'a_test.dart'), _chrome) - .toList(); + var suites = + await _loader + .loadFile(p.join(d.sandbox, 'a_test.dart'), _chrome) + .toList(); expect(suites, hasLength(1)); var loadSuite = suites.first; @@ -84,7 +86,7 @@ void main() { expectStates(liveTest, [ const State(Status.running, Result.success), - const State(Status.complete, Result.success) + const State(Status.complete, Result.success), ]); expectErrors(liveTest, []); @@ -119,9 +121,10 @@ Future main() { } '''); - var suites = await _loader - .loadFile(p.join(d.sandbox, 'a_test.dart'), _chrome) - .toList(); + var suites = + await _loader + .loadFile(p.join(d.sandbox, 'a_test.dart'), _chrome) + .toList(); expect(suites, hasLength(1)); var loadSuite = suites.first; var suite = (await loadSuite.getSuite())!; @@ -134,16 +137,18 @@ Future main() { test('loads a suite both in the browser and the VM', () async { var path = p.join(d.sandbox, 'a_test.dart'); - var suites = await _loader - .loadFile( - path, - SuiteConfiguration.runtimes([ - RuntimeSelection(Runtime.vm.identifier), - RuntimeSelection(Runtime.chrome.identifier) - ])) - .asyncMap((loadSuite) => loadSuite.getSuite()) - .cast() - .toList(); + var suites = + await _loader + .loadFile( + path, + SuiteConfiguration.runtimes([ + RuntimeSelection(Runtime.vm.identifier), + RuntimeSelection(Runtime.chrome.identifier), + ]), + ) + .asyncMap((loadSuite) => loadSuite.getSuite()) + .cast() + .toList(); expect(suites[0].platform.runtime, equals(Runtime.vm)); expect(suites[0].platform.compiler, equals(Runtime.vm.defaultCompiler)); expect(suites[0].path, equals(path)); @@ -165,16 +170,19 @@ void main() { print('print within test'); } '''); - var suites = await _loader - .loadFile(p.join(d.sandbox, 'a_test.dart'), _chrome) - .toList(); + var suites = + await _loader + .loadFile(p.join(d.sandbox, 'a_test.dart'), _chrome) + .toList(); expect(suites, hasLength(1)); var loadSuite = suites.first; var liveTest = (loadSuite.group.entries.single as Test).load(loadSuite); // Skip the "Compiled" message from dart2js. - expect(liveTest.onMessage.skip(1).first.then((message) => message.text), - completion(equals('print within test'))); + expect( + liveTest.onMessage.skip(1).first.then((message) => message.text), + completion(equals('print within test')), + ); await liveTest.run(); expectTestPassed(liveTest); }); diff --git a/pkgs/test/test/runner/browser/microsoft_edge_test.dart b/pkgs/test/test/runner/browser/microsoft_edge_test.dart index a48bfd2d4..d3dad90d3 100644 --- a/pkgs/test/test/runner/browser/microsoft_edge_test.dart +++ b/pkgs/test/test/runner/browser/microsoft_edge_test.dart @@ -36,15 +36,23 @@ webSocket.addEventListener("open", function() { }, timeout: const Timeout.factor(2)); test('reports an error in onExit', () { - var edge = MicrosoftEdge(Uri.parse('https://dart.dev'), configuration(), - settings: ExecutableSettings( - linuxExecutable: '_does_not_exist', - macOSExecutable: '_does_not_exist', - windowsExecutable: '_does_not_exist')); + var edge = MicrosoftEdge( + Uri.parse('https://dart.dev'), + configuration(), + settings: ExecutableSettings( + linuxExecutable: '_does_not_exist', + macOSExecutable: '_does_not_exist', + windowsExecutable: '_does_not_exist', + ), + ); expect( - edge.onExit, - throwsA(isApplicationException( - startsWith('Failed to run Edge: $noSuchFileMessage')))); + edge.onExit, + throwsA( + isApplicationException( + startsWith('Failed to run Edge: $noSuchFileMessage'), + ), + ), + ); }); test('can run successful tests', () async { @@ -83,8 +91,10 @@ void main() { test("success", () {}); } ''').create(); - var test = await runTest(['-p', 'edge', 'test.dart'], - environment: {'MS_EDGE_EXECUTABLE': '/some/bad/path'}); + var test = await runTest( + ['-p', 'edge', 'test.dart'], + environment: {'MS_EDGE_EXECUTABLE': '/some/bad/path'}, + ); expect(test.stdout, emitsThrough(contains('Failed to run Edge:'))); await test.shouldExit(1); }); diff --git a/pkgs/test/test/runner/browser/runner_test.dart b/pkgs/test/test/runner/browser/runner_test.dart index c55cbb884..f952e5612 100644 --- a/pkgs/test/test/runner/browser/runner_test.dart +++ b/pkgs/test/test/runner/browser/runner_test.dart @@ -37,12 +37,13 @@ void main() { var test = await runTest(['-p', 'chrome', 'test.dart']); expect( - test.stdout, - containsInOrder([ - 'Error: Compilation failed.', - '-1: loading test.dart [E]', - 'Failed to load "test.dart": dart2js failed.' - ])); + test.stdout, + containsInOrder([ + 'Error: Compilation failed.', + '-1: loading test.dart [E]', + 'Failed to load "test.dart": dart2js failed.', + ]), + ); await test.shouldExit(1); }, tags: 'chrome'); @@ -51,50 +52,64 @@ void main() { var test = await runTest(['-p', 'chrome', 'test.dart']); expect( - test.stdout, - containsInOrder([ - '-1: loading test.dart [E]', - 'Failed to load "test.dart": oh no' - ])); + test.stdout, + containsInOrder([ + '-1: loading test.dart [E]', + 'Failed to load "test.dart": oh no', + ]), + ); await test.shouldExit(1); }, tags: 'chrome'); - test("a test file doesn't have a main defined", () async { - await d.file('test.dart', 'void foo() {}').create(); + test( + "a test file doesn't have a main defined", + () async { + await d.file('test.dart', 'void foo() {}').create(); - var test = await runTest(['-p', 'chrome', 'test.dart']); - expect( + var test = await runTest(['-p', 'chrome', 'test.dart']); + expect( test.stdout, containsInOrder([ '-1: loading test.dart [E]', - 'Failed to load "test.dart": No top-level main() function defined.' - ])); - await test.shouldExit(1); - }, tags: 'chrome', skip: 'https://github.com/dart-lang/test/issues/894'); + 'Failed to load "test.dart": No top-level main() function defined.', + ]), + ); + await test.shouldExit(1); + }, + tags: 'chrome', + skip: 'https://github.com/dart-lang/test/issues/894', + ); - test('a test file has a non-function main', () async { - await d.file('test.dart', 'int main;').create(); + test( + 'a test file has a non-function main', + () async { + await d.file('test.dart', 'int main;').create(); - var test = await runTest(['-p', 'chrome', 'test.dart']); - expect( + var test = await runTest(['-p', 'chrome', 'test.dart']); + expect( test.stdout, containsInOrder([ '-1: loading test.dart [E]', - 'Failed to load "test.dart": Top-level main getter is not a function.' - ])); - await test.shouldExit(1); - }, tags: 'chrome', skip: 'https://github.com/dart-lang/test/issues/894'); + 'Failed to load "test.dart": Top-level main getter is not a function.', + ]), + ); + await test.shouldExit(1); + }, + tags: 'chrome', + skip: 'https://github.com/dart-lang/test/issues/894', + ); test('a test file has a main with arguments', () async { await d.file('test.dart', 'void main(arg) {}').create(); var test = await runTest(['-p', 'chrome', 'test.dart']); expect( - test.stdout, - containsInOrder([ - '-1: loading test.dart [E]', - 'Failed to load "test.dart": Top-level main() function takes arguments.' - ])); + test.stdout, + containsInOrder([ + '-1: loading test.dart [E]', + 'Failed to load "test.dart": Top-level main() function takes arguments.', + ]), + ); await test.shouldExit(1); }, tags: 'chrome'); @@ -111,12 +126,13 @@ void main() { var test = await runTest(['-p', 'chrome', 'test.dart']); expect( - test.stdout, - containsInOrder([ - '-1: loading test.dart [E]', - 'Failed to load "test.dart": "test.html" must contain ' - '.' - ])); + test.stdout, + containsInOrder([ + '-1: loading test.dart [E]', + 'Failed to load "test.dart": "test.html" must contain ' + '.', + ]), + ); await test.shouldExit(1); }, tags: 'chrome'); @@ -133,12 +149,13 @@ void main() { var test = await runTest(['-p', 'chrome', 'test.dart']); expect( - test.stdout, - containsInOrder([ - '-1: loading test.dart [E]', - 'Failed to load "test.dart": Expected exactly 1 ' - ' in test.html, found 0.' - ])); + test.stdout, + containsInOrder([ + '-1: loading test.dart [E]', + 'Failed to load "test.dart": Expected exactly 1 ' + ' in test.html, found 0.', + ]), + ); await test.shouldExit(1); }, tags: 'chrome'); @@ -157,12 +174,13 @@ void main() { var test = await runTest(['-p', 'chrome', 'test.dart']); expect( - test.stdout, - containsInOrder([ - '-1: loading test.dart [E]', - 'Failed to load "test.dart": Expected exactly 1 ' - ' in test.html, found 2.' - ])); + test.stdout, + containsInOrder([ + '-1: loading test.dart [E]', + 'Failed to load "test.dart": Expected exactly 1 ' + ' in test.html, found 2.', + ]), + ); await test.shouldExit(1); }, tags: 'chrome'); @@ -180,12 +198,13 @@ void main() { var test = await runTest(['-p', 'chrome', 'test.dart']); expect( - test.stdout, - containsInOrder([ - '-1: loading test.dart [E]', - 'Failed to load "test.dart": Expected in ' - 'test.html to have an "href" attribute.' - ])); + test.stdout, + containsInOrder([ + '-1: loading test.dart [E]', + 'Failed to load "test.dart": Expected in ' + 'test.html to have an "href" attribute.', + ]), + ); await test.shouldExit(1); }, tags: 'chrome'); @@ -203,20 +222,21 @@ void main() { var test = await runTest(['-p', 'chrome', 'test.dart']); expect( - test.stdout, - containsInOrder([ - '-1: loading test.dart [E]', - 'Failed to load "test.dart": Failed to load script at ' - ])); + test.stdout, + containsInOrder([ + '-1: loading test.dart [E]', + 'Failed to load "test.dart": Failed to load script at ', + ]), + ); await test.shouldExit(1); }, tags: 'chrome'); test( - 'still errors even with a custom HTML template set since it will take precedence', - () async { - await d.file('test.dart', 'void main() {}').create(); + 'still errors even with a custom HTML template set since it will take precedence', + () async { + await d.file('test.dart', 'void main() {}').create(); - await d.file('test.html', ''' + await d.file('test.html', ''' @@ -224,14 +244,16 @@ void main() { ''').create(); - await d - .file( + await d + .file( 'global_test.yaml', - jsonEncode( - {'custom_html_template_path': 'html_template.html.tpl'})) - .create(); + jsonEncode({ + 'custom_html_template_path': 'html_template.html.tpl', + }), + ) + .create(); - await d.file('html_template.html.tpl', ''' + await d.file('html_template.html.tpl', ''' {{testScript}} @@ -243,38 +265,48 @@ void main() { ''').create(); - var test = await runTest(['-p', 'chrome', 'test.dart'], - environment: {'DART_TEST_CONFIG': 'global_test.yaml'}); - expect( + var test = await runTest( + ['-p', 'chrome', 'test.dart'], + environment: {'DART_TEST_CONFIG': 'global_test.yaml'}, + ); + expect( test.stdout, containsInOrder([ '-1: loading test.dart [E]', 'Failed to load "test.dart": "test.html" must contain ' - '.' - ])); - await test.shouldExit(1); - }, tags: 'chrome'); + '.', + ]), + ); + await test.shouldExit(1); + }, + tags: 'chrome', + ); group('with a custom HTML template', () { setUp(() async { await d.file('test.dart', _success).create(); await d .file( - 'global_test.yaml', - jsonEncode( - {'custom_html_template_path': 'html_template.html.tpl'})) + 'global_test.yaml', + jsonEncode({ + 'custom_html_template_path': 'html_template.html.tpl', + }), + ) .create(); }); test('that does not exist', () async { - var test = await runTest(['-p', 'chrome', 'test.dart'], - environment: {'DART_TEST_CONFIG': 'global_test.yaml'}); + var test = await runTest( + ['-p', 'chrome', 'test.dart'], + environment: {'DART_TEST_CONFIG': 'global_test.yaml'}, + ); expect( - test.stdout, - containsInOrder([ - '-1: loading test.dart [E]', - 'Failed to load "test.dart": "html_template.html.tpl" does not exist or is not readable' - ])); + test.stdout, + containsInOrder([ + '-1: loading test.dart [E]', + 'Failed to load "test.dart": "html_template.html.tpl" does not exist or is not readable', + ]), + ); await test.shouldExit(1); }, tags: 'chrome'); @@ -290,14 +322,17 @@ void main() { ''').create(); - var test = await runTest(['-p', 'chrome', 'test.dart'], - environment: {'DART_TEST_CONFIG': 'global_test.yaml'}); + var test = await runTest( + ['-p', 'chrome', 'test.dart'], + environment: {'DART_TEST_CONFIG': 'global_test.yaml'}, + ); expect( - test.stdout, - containsInOrder([ - '-1: loading test.dart [E]', - 'Failed to load "test.dart": "html_template.html.tpl" must contain exactly one {{testScript}} placeholder' - ])); + test.stdout, + containsInOrder([ + '-1: loading test.dart [E]', + 'Failed to load "test.dart": "html_template.html.tpl" must contain exactly one {{testScript}} placeholder', + ]), + ); await test.shouldExit(1); }, tags: 'chrome'); @@ -315,14 +350,17 @@ void main() { ''').create(); - var test = await runTest(['-p', 'chrome', 'test.dart'], - environment: {'DART_TEST_CONFIG': 'global_test.yaml'}); + var test = await runTest( + ['-p', 'chrome', 'test.dart'], + environment: {'DART_TEST_CONFIG': 'global_test.yaml'}, + ); expect( - test.stdout, - containsInOrder([ - '-1: loading test.dart [E]', - 'Failed to load "test.dart": "html_template.html.tpl" must contain exactly one {{testScript}} placeholder' - ])); + test.stdout, + containsInOrder([ + '-1: loading test.dart [E]', + 'Failed to load "test.dart": "html_template.html.tpl" must contain exactly one {{testScript}} placeholder', + ]), + ); await test.shouldExit(1); }, tags: 'chrome'); @@ -335,15 +373,18 @@ void main() { ''').create(); - var test = await runTest(['-p', 'chrome', 'test.dart'], - environment: {'DART_TEST_CONFIG': 'global_test.yaml'}); + var test = await runTest( + ['-p', 'chrome', 'test.dart'], + environment: {'DART_TEST_CONFIG': 'global_test.yaml'}, + ); expect( - test.stdout, - containsInOrder([ - '-1: loading test.dart [E]', - 'Failed to load "test.dart": "html_template.html.tpl" must contain ' - '.' - ])); + test.stdout, + containsInOrder([ + '-1: loading test.dart [E]', + 'Failed to load "test.dart": "html_template.html.tpl" must contain ' + '.', + ]), + ); await test.shouldExit(1); }, tags: 'chrome'); @@ -358,18 +399,23 @@ void main() { ''').create(); await d - .file('global_test_2.yaml', - jsonEncode({'custom_html_template_path': 'test.html'})) + .file( + 'global_test_2.yaml', + jsonEncode({'custom_html_template_path': 'test.html'}), + ) .create(); - var test = await runTest(['-p', 'chrome', 'test.dart'], - environment: {'DART_TEST_CONFIG': 'global_test_2.yaml'}); + var test = await runTest( + ['-p', 'chrome', 'test.dart'], + environment: {'DART_TEST_CONFIG': 'global_test_2.yaml'}, + ); expect( - test.stdout, - containsInOrder([ - '-1: loading test.dart [E]', - 'Failed to load "test.dart": template file "test.html" cannot be named ' - 'like the test file.' - ])); + test.stdout, + containsInOrder([ + '-1: loading test.dart [E]', + 'Failed to load "test.dart": template file "test.html" cannot be named ' + 'like the test file.', + ]), + ); await test.shouldExit(1); }); }); @@ -432,9 +478,11 @@ void main() { setUp(() async { await d .file( - 'global_test.yaml', - jsonEncode( - {'custom_html_template_path': 'html_template.html.tpl'})) + 'global_test.yaml', + jsonEncode({ + 'custom_html_template_path': 'html_template.html.tpl', + }), + ) .create(); await d.file('html_template.html.tpl', ''' @@ -461,8 +509,10 @@ void main() { }); test('on Chrome', () async { - var test = await runTest(['-p', 'chrome', 'test.dart'], - environment: {'DART_TEST_CONFIG': 'global_test.yaml'}); + var test = await runTest( + ['-p', 'chrome', 'test.dart'], + environment: {'DART_TEST_CONFIG': 'global_test.yaml'}, + ); expect(test.stdout, emitsThrough(contains('+1: All tests passed!'))); await test.shouldExit(0); }, tags: 'chrome'); @@ -472,9 +522,11 @@ void main() { setUp(() async { await d .file( - 'global_test.yaml', - jsonEncode( - {'custom_html_template_path': 'html_template.html.tpl'})) + 'global_test.yaml', + jsonEncode({ + 'custom_html_template_path': 'html_template.html.tpl', + }), + ) .create(); await d.file('html_template.html.tpl', ''' @@ -505,8 +557,10 @@ void main() { }); test('on Chrome', () async { - var test = await runTest(['-p', 'chrome', 'test-with-title.dart'], - environment: {'DART_TEST_CONFIG': 'global_test.yaml'}); + var test = await runTest( + ['-p', 'chrome', 'test-with-title.dart'], + environment: {'DART_TEST_CONFIG': 'global_test.yaml'}, + ); expect(test.stdout, emitsThrough(contains('+2: All tests passed!'))); await test.shouldExit(0); }, tags: 'chrome'); @@ -569,9 +623,11 @@ void main() { test('takes precedence over provided HTML template', () async { await d .file( - 'global_test.yaml', - jsonEncode( - {'custom_html_template_path': 'html_template.html.tpl'})) + 'global_test.yaml', + jsonEncode({ + 'custom_html_template_path': 'html_template.html.tpl', + }), + ) .create(); await d.file('html_template.html.tpl', ''' @@ -585,8 +641,10 @@ void main() { ''').create(); - var test = await runTest(['-p', 'chrome', 'test.dart'], - environment: {'DART_TEST_CONFIG': 'global_test.yaml'}); + var test = await runTest( + ['-p', 'chrome', 'test.dart'], + environment: {'DART_TEST_CONFIG': 'global_test.yaml'}, + ); expect(test.stdout, emitsThrough(contains('+1: All tests passed!'))); await test.shouldExit(0); }, tags: 'chrome'); @@ -697,24 +755,34 @@ void main() { await d.file('test.dart', _failure).create(); var test = await runTest(['-p', 'chrome', '--verbose-trace', 'test.dart']); - expect(test.stdout, - containsInOrder([' main.', 'package:test', 'dart:async/zone.dart']), - skip: 'https://github.com/dart-lang/sdk/issues/41949'); + expect( + test.stdout, + containsInOrder([' main.', 'package:test', 'dart:async/zone.dart']), + skip: 'https://github.com/dart-lang/sdk/issues/41949', + ); await test.shouldExit(1); }, tags: 'chrome'); - test("doesn't dartify stack traces for JS-compiled tests with --js-trace", - () async { - await d.file('test.dart', _failure).create(); - - var test = await runTest( - ['-p', 'chrome', '--verbose-trace', '--js-trace', 'test.dart']); - expect(test.stdoutStream(), neverEmits(endsWith(' main.'))); - expect(test.stdoutStream(), neverEmits(contains('package:test'))); - expect(test.stdoutStream(), neverEmits(contains('dart:async/zone.dart'))); - expect(test.stdout, emitsThrough(contains('-1: Some tests failed.'))); - await test.shouldExit(1); - }, tags: 'chrome'); + test( + "doesn't dartify stack traces for JS-compiled tests with --js-trace", + () async { + await d.file('test.dart', _failure).create(); + + var test = await runTest([ + '-p', + 'chrome', + '--verbose-trace', + '--js-trace', + 'test.dart', + ]); + expect(test.stdoutStream(), neverEmits(endsWith(' main.'))); + expect(test.stdoutStream(), neverEmits(contains('package:test'))); + expect(test.stdoutStream(), neverEmits(contains('dart:async/zone.dart'))); + expect(test.stdout, emitsThrough(contains('-1: Some tests failed.'))); + await test.shouldExit(1); + }, + tags: 'chrome', + ); test('respects top-level @Timeout declarations', () async { await d.file('test.dart', ''' @@ -731,9 +799,12 @@ void main() { var test = await runTest(['-p', 'chrome', 'test.dart']); expect( - test.stdout, - containsInOrder( - ['Test timed out after 0 seconds.', '-1: Some tests failed.'])); + test.stdout, + containsInOrder([ + 'Test timed out after 0 seconds.', + '-1: Some tests failed.', + ]), + ); await test.shouldExit(1); }, tags: 'chrome'); @@ -788,9 +859,12 @@ void main() { var test = await runTest(['-p', 'chrome', 'test.dart']); expect( - test.stdout, - containsInOrder( - ['Test timed out after 0 seconds.', '-1: Some tests failed.'])); + test.stdout, + containsInOrder([ + 'Test timed out after 0 seconds.', + '-1: Some tests failed.', + ]), + ); await test.shouldExit(1); }, tags: 'chrome'); @@ -896,9 +970,12 @@ void main() { var test = await runTest(['-p', 'chrome', 'test.dart']); expect( - test.stdout, - containsInOrder( - ['Test timed out after 0 seconds.', '-1: Some tests failed.'])); + test.stdout, + containsInOrder([ + 'Test timed out after 0 seconds.', + '-1: Some tests failed.', + ]), + ); await test.shouldExit(1); }, tags: 'chrome'); @@ -966,12 +1043,9 @@ void main() { var test = await runTest(['-p', 'chrome', 'test.dart']); expect( - test.stdout, - containsInOrder([ - 'Oh no!', - 'deferred.dart', - 'test.dart', - ])); + test.stdout, + containsInOrder(['Oh no!', 'deferred.dart', 'test.dart']), + ); await test.shouldExit(1); }, tags: 'chrome'); }); diff --git a/pkgs/test/test/runner/browser/safari_test.dart b/pkgs/test/test/runner/browser/safari_test.dart index 28f402210..e5212b28e 100644 --- a/pkgs/test/test/runner/browser/safari_test.dart +++ b/pkgs/test/test/runner/browser/safari_test.dart @@ -18,23 +18,26 @@ import 'code_server.dart'; void main() { setUpAll(precompileTestExecutable); - test('starts Safari with the given URL', - skip: 'https://github.com/dart-lang/test/issues/1253', () async { - var server = await CodeServer.start(); + test( + 'starts Safari with the given URL', + skip: 'https://github.com/dart-lang/test/issues/1253', + () async { + var server = await CodeServer.start(); - server.handleJavaScript(''' + server.handleJavaScript(''' var webSocket = new WebSocket(window.location.href.replace("http://", "ws://")); webSocket.addEventListener("open", function() { webSocket.send("loaded!"); }); '''); - var webSocket = server.handleWebSocket(); + var webSocket = server.handleWebSocket(); - var safari = Safari(server.url); - addTearDown(() => safari.close()); + var safari = Safari(server.url); + addTearDown(() => safari.close()); - expect(await (await webSocket).stream.first, equals('loaded!')); - }); + expect(await (await webSocket).stream.first, equals('loaded!')); + }, + ); test("a process can be killed synchronously after it's started", () async { var server = await CodeServer.start(); @@ -44,20 +47,29 @@ webSocket.addEventListener("open", function() { }); test('reports an error in onExit', () { - var safari = Safari(Uri.https('dart.dev'), - settings: ExecutableSettings( - linuxExecutable: '_does_not_exist', - macOSExecutable: '_does_not_exist', - windowsExecutable: '_does_not_exist')); + var safari = Safari( + Uri.https('dart.dev'), + settings: ExecutableSettings( + linuxExecutable: '_does_not_exist', + macOSExecutable: '_does_not_exist', + windowsExecutable: '_does_not_exist', + ), + ); expect( - safari.onExit, - throwsA(isApplicationException( - startsWith('Failed to run Safari: $noSuchFileMessage')))); + safari.onExit, + throwsA( + isApplicationException( + startsWith('Failed to run Safari: $noSuchFileMessage'), + ), + ), + ); }); - test('can run successful tests', - skip: 'https://github.com/dart-lang/test/issues/1253', () async { - await d.file('test.dart', ''' + test( + 'can run successful tests', + skip: 'https://github.com/dart-lang/test/issues/1253', + () async { + await d.file('test.dart', ''' import 'package:test/test.dart'; void main() { @@ -65,10 +77,11 @@ void main() { } ''').create(); - var test = await runTest(['-p', 'safari', 'test.dart']); - expect(test.stdout, emitsThrough(contains('+1: All tests passed!'))); - await test.shouldExit(0); - }); + var test = await runTest(['-p', 'safari', 'test.dart']); + expect(test.stdout, emitsThrough(contains('+1: All tests passed!'))); + await test.shouldExit(0); + }, + ); test('can run failing tests', () async { await d.file('test.dart', ''' @@ -92,8 +105,10 @@ void main() { test("success", () {}); } ''').create(); - var test = await runTest(['-p', 'safari', 'test.dart'], - environment: {'SAFARI_EXECUTABLE': '/some/bad/path'}); + var test = await runTest( + ['-p', 'safari', 'test.dart'], + environment: {'SAFARI_EXECUTABLE': '/some/bad/path'}, + ); expect(test.stdout, emitsThrough(contains('Failed to run Safari:'))); await test.shouldExit(1); }); diff --git a/pkgs/test/test/runner/compact_reporter_test.dart b/pkgs/test/test/runner/compact_reporter_test.dart index c935e026f..842b65531 100644 --- a/pkgs/test/test/runner/compact_reporter_test.dart +++ b/pkgs/test/test/runner/compact_reporter_test.dart @@ -26,10 +26,12 @@ void main() { }); test('runs several successful tests and reports when each completes', () { - return _expectReport(''' + return _expectReport( + ''' test('success 1', () {}); test('success 2', () {}); - test('success 3', () {});''', ''' + test('success 3', () {});''', + ''' +0: loading test.dart +0: success 1 +1: success 1 @@ -37,14 +39,17 @@ void main() { +2: success 2 +2: success 3 +3: success 3 - +3: All tests passed!'''); + +3: All tests passed!''', + ); }); test('runs several failing tests and reports when each fails', () { - return _expectReport(''' + return _expectReport( + ''' test('failure 1', () => throw TestFailure('oh no')); test('failure 2', () => throw TestFailure('oh no')); - test('failure 3', () => throw TestFailure('oh no'));''', ''' + test('failure 3', () => throw TestFailure('oh no'));''', + ''' +0: loading test.dart +0: failure 1 +0 -1: failure 1 [E] @@ -64,7 +69,8 @@ void main() { test.dart 8:33 main. - +0 -3: Some tests failed.'''); + +0 -3: Some tests failed.''', + ); }); test('includes the full stack trace with --verbose-trace', () async { @@ -78,18 +84,22 @@ void main() { } ''').create(); - var test = - await runTest(['--verbose-trace', 'test.dart'], reporter: 'compact'); + var test = await runTest([ + '--verbose-trace', + 'test.dart', + ], reporter: 'compact'); expect(test.stdout, emitsThrough(contains('dart:async'))); await test.shouldExit(1); }); test('runs failing tests along with successful tests', () { - return _expectReport(''' + return _expectReport( + ''' test('failure 1', () => throw TestFailure('oh no')); test('success 1', () {}); test('failure 2', () => throw TestFailure('oh no')); - test('success 2', () {});''', ''' + test('success 2', () {});''', + ''' +0: loading test.dart +0: failure 1 +0 -1: failure 1 [E] @@ -107,11 +117,13 @@ void main() { +1 -2: success 2 +2 -2: success 2 - +2 -2: Some tests failed.'''); + +2 -2: Some tests failed.''', + ); }); test('gracefully handles multiple test failures in a row', () { - return _expectReport(''' + return _expectReport( + ''' // This completer ensures that the test isolate isn't killed until all // errors have been thrown. var completer = Completer(); @@ -121,7 +133,8 @@ void main() { Future.microtask(() => throw 'third error'); Future.microtask(completer.complete); }); - test('wait', () => completer.future);''', ''' + test('wait', () => completer.future);''', + ''' +0: loading test.dart +0: failures +0 -1: failures [E] @@ -146,17 +159,20 @@ void main() { +0 -1: wait +1 -1: wait - +1 -1: Some tests failed.'''); + +1 -1: Some tests failed.''', + ); }); test('prints the full test name before an error', () { - return _expectReport(''' + return _expectReport( + ''' test( 'really gosh dang long test name. Even longer than that. No, yet ' 'longer. Even more. We have to get to at least 200 characters. ' 'I know that seems like a lot, but I believe in you. A little ' 'more... okay, that should do it.', - () => throw TestFailure('oh no'));''', ''' + () => throw TestFailure('oh no'));''', + ''' +0: loading test.dart +0: really ... than that. No, yet longer. Even more. We have to get to at least 200 characters. I know that seems like a lot, but I believe in you. A little more... okay, that should do it. +0 -1: really gosh dang long test name. Even longer than that. No, yet longer. Even more. We have to get to at least 200 characters. I know that seems like a lot, but I believe in you. A little more... okay, that should do it. [E] @@ -164,18 +180,21 @@ void main() { test.dart 11:18 main. - +0 -1: Some tests failed.'''); + +0 -1: Some tests failed.''', + ); }); group('print:', () { test('handles multiple prints', () { - return _expectReport(''' + return _expectReport( + ''' test('test', () { print("one"); print("two"); print("three"); print("four"); - });''', ''' + });''', + ''' +0: loading test.dart +0: test one @@ -184,11 +203,13 @@ void main() { four +1: test - +1: All tests passed!'''); + +1: All tests passed!''', + ); }); test('handles a print after the test completes', () { - return _expectReport(''' + return _expectReport( + ''' // This completer ensures that the test isolate isn't killed until all // prints have happened. var testDone = Completer(); @@ -206,7 +227,8 @@ void main() { test('wait', () { waitStarted.complete(); return testDone.future; - });''', ''' + });''', + ''' +0: loading test.dart +0: test +1: test @@ -218,11 +240,13 @@ void main() { four +2: wait - +2: All tests passed!'''); + +2: All tests passed!''', + ); }); test('interleaves prints and errors', () { - return _expectReport(''' + return _expectReport( + ''' // This completer ensures that the test isolate isn't killed until all // prints have happened. var completer = Completer(); @@ -244,7 +268,8 @@ void main() { throw "first error"; }); - test('wait', () => completer.future);''', ''' + test('wait', () => completer.future);''', + ''' +0: loading test.dart +0: test one @@ -267,49 +292,58 @@ void main() { +0 -1: wait +1 -1: wait - +1 -1: Some tests failed.'''); + +1 -1: Some tests failed.''', + ); }); test('prints the full test name before a print', () { - return _expectReport(''' + return _expectReport( + ''' test( 'really gosh dang long test name. Even longer than that. No, yet ' 'longer. Even more. We have to get to at least 200 ' 'characters. I know that seems like a lot, but I believe in ' 'you. A little more... okay, that should do it.', - () => print('hello'));''', ''' + () => print('hello'));''', + ''' +0: loading test.dart +0: really ... than that. No, yet longer. Even more. We have to get to at least 200 characters. I know that seems like a lot, but I believe in you. A little more... okay, that should do it. +0: really gosh dang long test name. Even longer than that. No, yet longer. Even more. We have to get to at least 200 characters. I know that seems like a lot, but I believe in you. A little more... okay, that should do it. hello +1: really ... than that. No, yet longer. Even more. We have to get to at least 200 characters. I know that seems like a lot, but I believe in you. A little more... okay, that should do it. - +1: All tests passed!'''); + +1: All tests passed!''', + ); }); test("doesn't print a clock update between two prints", () { - return _expectReport(''' + return _expectReport( + ''' test('slow', () async { print('hello'); await Future.delayed(Duration(seconds: 3)); print('goodbye'); - });''', ''' + });''', + ''' +0: loading test.dart +0: slow hello goodbye +1: slow - +1: All tests passed!'''); + +1: All tests passed!''', + ); }); }); group('skip:', () { test('displays skipped tests separately', () { - return _expectReport(''' + return _expectReport( + ''' test('skip 1', () {}, skip: true); test('skip 2', () {}, skip: true); - test('skip 3', () {}, skip: true);''', ''' + test('skip 3', () {}, skip: true);''', + ''' +0: loading test.dart +0: skip 1 +0 ~1: skip 1 @@ -317,16 +351,19 @@ void main() { +0 ~2: skip 2 +0 ~2: skip 3 +0 ~3: skip 3 - +0 ~3: All tests skipped.'''); + +0 ~3: All tests skipped.''', + ); }); test('displays a skipped group', () { - return _expectReport(''' + return _expectReport( + ''' group('skip', () { test('test 1', () {}); test('test 2', () {}); test('test 3', () {}); - }, skip: true);''', ''' + }, skip: true);''', + ''' +0: loading test.dart +0: skip test 1 +0 ~1: skip test 1 @@ -334,15 +371,18 @@ void main() { +0 ~2: skip test 2 +0 ~2: skip test 3 +0 ~3: skip test 3 - +0 ~3: All tests skipped.'''); + +0 ~3: All tests skipped.''', + ); }); test('runs skipped tests along with successful tests', () { - return _expectReport(''' + return _expectReport( + ''' test('skip 1', () {}, skip: true); test('success 1', () {}); test('skip 2', () {}, skip: true); - test('success 2', () {});''', ''' + test('success 2', () {});''', + ''' +0: loading test.dart +0: skip 1 +0 ~1: skip 1 @@ -352,17 +392,20 @@ void main() { +1 ~2: skip 2 +1 ~2: success 2 +2 ~2: success 2 - +2 ~2: All tests passed!'''); + +2 ~2: All tests passed!''', + ); }); test('runs skipped tests along with successful and failing tests', () { - return _expectReport(''' + return _expectReport( + ''' test('failure 1', () => throw TestFailure('oh no')); test('skip 1', () {}, skip: true); test('success 1', () {}); test('failure 2', () => throw TestFailure('oh no')); test('skip 2', () {}, skip: true); - test('success 2', () {});''', ''' + test('success 2', () {});''', + ''' +0: loading test.dart +0: failure 1 +0 -1: failure 1 [E] @@ -384,13 +427,16 @@ void main() { +1 ~2 -2: skip 2 +1 ~2 -2: success 2 +2 ~2 -2: success 2 - +2 ~2 -2: Some tests failed.'''); + +2 ~2 -2: Some tests failed.''', + ); }); test('displays the skip reason if available', () { - return _expectReport(''' + return _expectReport( + ''' test('skip 1', () {}, skip: 'some reason'); - test('skip 2', () {}, skip: 'or another');''', ''' + test('skip 2', () {}, skip: 'or another');''', + ''' +0: loading test.dart +0: skip 1 Skip: some reason @@ -400,25 +446,31 @@ void main() { Skip: or another +0 ~2: skip 2 - +0 ~2: All tests skipped.'''); + +0 ~2: All tests skipped.''', + ); }); test('runs skipped tests with --run-skipped', () { - return _expectReport(''' + return _expectReport( + ''' test('skip 1', () {}, skip: 'some reason'); - test('skip 2', () {}, skip: 'or another');''', ''' + test('skip 2', () {}, skip: 'or another');''', + ''' +0: loading test.dart +0: skip 1 +1: skip 1 +1: skip 2 +2: skip 2 - +2: All tests passed!''', args: ['--run-skipped']); + +2: All tests passed!''', + args: ['--run-skipped'], + ); }); }); test('Directs users to enable stack trace chaining if disabled', () async { await _expectReport( - '''test('failure 1', () => throw TestFailure('oh no'));''', ''' + '''test('failure 1', () => throw TestFailure('oh no'));''', + ''' +0: loading test.dart +0: failure 1 +0 -1: failure 1 [E] @@ -427,17 +479,20 @@ void main() { +0 -1: Some tests failed. Consider enabling the flag chain-stack-traces to receive more detailed exceptions. For example, 'dart test --chain-stack-traces'.''', - chainStackTraces: false); + chainStackTraces: false, + ); }); group('gives non-windows users a way to re-run failed tests', () { final executablePath = p.absolute(Platform.resolvedExecutable); test('with simple names', () { - return _expectReport(''' + return _expectReport( + ''' test('failure', () { expect(1, equals(2)); - });''', ''' + });''', + ''' +0: loading test.dart +0: failure +0 -1: failure [E] @@ -446,14 +501,17 @@ void main() { To run this test again: $executablePath test test.dart -p vm --plain-name 'failure' - +0 -1: Some tests failed.'''); + +0 -1: Some tests failed.''', + ); }); test('escapes names containing single quotes', () { - return _expectReport(''' + return _expectReport( + ''' test("failure with a ' in the name", () { expect(1, equals(2)); - });''', ''' + });''', + ''' +0: loading test.dart +0: failure with a ' in the name +0 -1: failure with a ' in the name [E] @@ -462,7 +520,8 @@ void main() { To run this test again: $executablePath test test.dart -p vm --plain-name 'failure with a '\\'' in the name' - +0 -1: Some tests failed.'''); + +0 -1: Some tests failed.''', + ); }); }, testOn: '!windows'); @@ -470,10 +529,12 @@ void main() { final executablePath = p.absolute(Platform.resolvedExecutable); test('with simple names', () { - return _expectReport(''' + return _expectReport( + ''' test('failure', () { expect(1, equals(2)); - });''', ''' + });''', + ''' +0: loading test.dart +0: failure +0 -1: failure [E] @@ -482,14 +543,17 @@ void main() { To run this test again: $executablePath test test.dart -p vm --plain-name "failure" - +0 -1: Some tests failed.'''); + +0 -1: Some tests failed.''', + ); }); test('escapes names containing double quotes', () { - return _expectReport(''' + return _expectReport( + ''' test('failure with a " in the name', () { expect(1, equals(2)); - });''', ''' + });''', + ''' +0: loading test.dart +0: failure with a " in the name +0 -1: failure with a " in the name [E] @@ -498,13 +562,18 @@ void main() { To run this test again: $executablePath test test.dart -p vm --plain-name "failure with a """ in the name" - +0 -1: Some tests failed.'''); + +0 -1: Some tests failed.''', + ); }); }, testOn: 'windows'); } -Future _expectReport(String tests, String expected, - {List args = const [], bool chainStackTraces = true}) async { +Future _expectReport( + String tests, + String expected, { + List args = const [], + bool chainStackTraces = true, +}) async { await d.file('test.dart', ''' import 'dart:async'; @@ -527,17 +596,23 @@ $tests // Skip the first CR, remove excess trailing whitespace, and trim off // timestamps. String? lastLine; - var actual = stdoutLines.skip(1).map((line) { - if (line.startsWith(' ') || line.isEmpty) return line.trimRight(); - - var trimmed = line.trim().replaceFirst(RegExp('^[0-9]{2}:[0-9]{2} '), ''); - - // Trim identical lines so the test isn't dependent on how fast each test - // runs. - if (trimmed == lastLine) return null; - lastLine = trimmed; - return trimmed; - }).where((line) => line != null); + var actual = stdoutLines + .skip(1) + .map((line) { + if (line.startsWith(' ') || line.isEmpty) return line.trimRight(); + + var trimmed = line.trim().replaceFirst( + RegExp('^[0-9]{2}:[0-9]{2} '), + '', + ); + + // Trim identical lines so the test isn't dependent on how fast each test + // runs. + if (trimmed == lastLine) return null; + lastLine = trimmed; + return trimmed; + }) + .where((line) => line != null); // Un-indent the expected string. var indentation = expected.indexOf(RegExp('[^ ]')); diff --git a/pkgs/test/test/runner/compiler_runtime_matrix_test.dart b/pkgs/test/test/runner/compiler_runtime_matrix_test.dart index 74d880239..312ed428f 100644 --- a/pkgs/test/test/runner/compiler_runtime_matrix_test.dart +++ b/pkgs/test/test/runner/compiler_runtime_matrix_test.dart @@ -37,93 +37,107 @@ void main() { } else if (runtime == Runtime.firefox && Platform.isMacOS) { skipReason = 'https://github.com/dart-lang/test/pull/2276'; } - group('--runtime ${runtime.identifier} --compiler ${compiler.identifier}', - skip: skipReason, () { - final testArgs = [ - 'test.dart', - '-p', - runtime.identifier, - '-c', - compiler.identifier - ]; - - test('can run passing tests', () async { - await d.file('test.dart', _goodTest).create(); - var test = await runTest(testArgs); - - expect(test.stdout, emitsThrough(contains('+1: All tests passed!'))); - await test.shouldExit(0); - }); - - test('fails gracefully for invalid code', () async { - await d.file('test.dart', _compileErrorTest).create(); - var test = await runTest(testArgs); - - expect( + group( + '--runtime ${runtime.identifier} --compiler ${compiler.identifier}', + skip: skipReason, + () { + final testArgs = [ + 'test.dart', + '-p', + runtime.identifier, + '-c', + compiler.identifier, + ]; + + test('can run passing tests', () async { + await d.file('test.dart', _goodTest).create(); + var test = await runTest(testArgs); + + expect( + test.stdout, + emitsThrough(contains('+1: All tests passed!')), + ); + await test.shouldExit(0); + }); + + test('fails gracefully for invalid code', () async { + await d.file('test.dart', _compileErrorTest).create(); + var test = await runTest(testArgs); + + expect( test.stdout, containsInOrder([ "Error: A value of type 'String' can't be assigned to a variable of type 'int'.", "int x = 'hello';", - ])); + ]), + ); - await test.shouldExit(1); - }); + await test.shouldExit(1); + }); - test('fails gracefully for test failures', () async { - await d.file('test.dart', _failingTest).create(); - var test = await runTest(testArgs); + test('fails gracefully for test failures', () async { + await d.file('test.dart', _failingTest).create(); + var test = await runTest(testArgs); - expect( + expect( test.stdout, containsInOrder([ 'Expected: <2>', 'Actual: <1>', 'test.dart 5', '+0 -1: Some tests failed.', - ])); + ]), + ); - await test.shouldExit(1); - }); + await test.shouldExit(1); + }); - test('fails gracefully if a test file throws in main', () async { - await d.file('test.dart', _throwingTest).create(); - var test = await runTest(testArgs); - expect( + test('fails gracefully if a test file throws in main', () async { + await d.file('test.dart', _throwingTest).create(); + var test = await runTest(testArgs); + expect( test.stdout, containsInOrder([ '-1: [${runtime.name}, ${compiler.name}] loading test.dart [E]', - 'Failed to load "test.dart": oh no' - ])); - await test.shouldExit(1); - }); + 'Failed to load "test.dart": oh no', + ]), + ); + await test.shouldExit(1); + }); - test('captures prints', () async { - await d.file('test.dart', _testWithPrints).create(); - var test = await runTest([...testArgs, '-r', 'json']); + test('captures prints', () async { + await d.file('test.dart', _testWithPrints).create(); + var test = await runTest([...testArgs, '-r', 'json']); - expect( + expect( test.stdout, containsInOrder([ '"messageType":"print","message":"hello","type":"print"', - ])); - - await test.shouldExit(0); - }); - - if (runtime.isDartVM) { - test('forwards stdout/stderr', () async { - await d.file('test.dart', _testWithStdOutAndErr).create(); - var test = await runTest(testArgs, reporter: 'silent'); + ]), + ); - expect(test.stdout, emitsThrough('hello')); - expect(test.stderr, emits('world')); await test.shouldExit(0); - }, - skip: Platform.isWindows && compiler == Compiler.exe - ? 'https://github.com/dart-lang/test/issues/2150' - : null); - } - }); + }); + + if (runtime.isDartVM) { + test( + 'forwards stdout/stderr', + () async { + await d.file('test.dart', _testWithStdOutAndErr).create(); + var test = await runTest(testArgs, reporter: 'silent'); + + expect(test.stdout, emitsThrough('hello')); + expect(test.stderr, emits('world')); + await test.shouldExit(0); + }, + skip: + Platform.isWindows && compiler == Compiler.exe + ? 'https://github.com/dart-lang/test/issues/2150' + : null, + ); + } + }, + ); } } } diff --git a/pkgs/test/test/runner/compiler_test.dart b/pkgs/test/test/runner/compiler_test.dart index 5cf7a476d..e3f76f0f9 100644 --- a/pkgs/test/test/runner/compiler_test.dart +++ b/pkgs/test/test/runner/compiler_test.dart @@ -26,20 +26,31 @@ void main() { group('--compiler', () { test( - 'uses the default compiler if none other is specified for the platform', - () async { - var test = - await runTest(['test.dart', '-p', 'chrome,vm', '-c', 'dart2js']); + 'uses the default compiler if none other is specified for the platform', + () async { + var test = await runTest([ + 'test.dart', + '-p', + 'chrome,vm', + '-c', + 'dart2js', + ]); - expect(test.stdout, emitsThrough(contains('[Chrome, Dart2Js]'))); - expect(test.stdout, emitsThrough(contains('[VM, Kernel]'))); - expect(test.stdout, emitsThrough(contains('+2: All tests passed!'))); - await test.shouldExit(0); - }); + expect(test.stdout, emitsThrough(contains('[Chrome, Dart2Js]'))); + expect(test.stdout, emitsThrough(contains('[VM, Kernel]'))); + expect(test.stdout, emitsThrough(contains('+2: All tests passed!'))); + await test.shouldExit(0); + }, + ); test('runs all supported compiler and platform combinations', () async { - var test = await runTest( - ['test.dart', '-p', 'chrome,vm', '-c', 'dart2js,kernel,source']); + var test = await runTest([ + 'test.dart', + '-p', + 'chrome,vm', + '-c', + 'dart2js,kernel,source', + ]); expect(test.stdout, emitsThrough(contains('[Chrome, Dart2Js]'))); expect(test.stdout, emitsThrough(contains('[VM, Kernel]'))); @@ -49,19 +60,28 @@ void main() { }); test('supports platform selectors', () async { - var test = await runTest( - ['test.dart', '-p', 'vm', '-c', 'vm:source,browser:kernel']); + var test = await runTest([ + 'test.dart', + '-p', + 'vm', + '-c', + 'vm:source,browser:kernel', + ]); expect(test.stdout, emitsThrough(contains('[VM, Source]'))); expect(test.stdout, emitsThrough(contains('+1: All tests passed!'))); await test.shouldExit(0); }); - test( - 'will only run a given test once for each compiler, even if there are ' + test('will only run a given test once for each compiler, even if there are ' 'multiple matches', () async { - var test = - await runTest(['test.dart', '-p', 'vm', '-c', 'vm:source,source']); + var test = await runTest([ + 'test.dart', + '-p', + 'vm', + '-c', + 'vm:source,source', + ]); expect(test.stdout, emitsThrough(contains('[VM, Source]'))); expect(test.stdout, emitsThrough(contains('+1: All tests passed!'))); diff --git a/pkgs/test/test/runner/configuration/compiler_test.dart b/pkgs/test/test/runner/configuration/compiler_test.dart index d8f8d33fa..bf11b03e6 100644 --- a/pkgs/test/test/runner/configuration/compiler_test.dart +++ b/pkgs/test/test/runner/configuration/compiler_test.dart @@ -19,10 +19,11 @@ void main() { test('uses specified compilers for supporting platforms', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'compilers': ['source'] - })) + 'dart_test.yaml', + jsonEncode({ + 'compilers': ['source'], + }), + ) .create(); await d.file('test.dart', ''' @@ -35,22 +36,24 @@ void main() { var test = await runTest(['-p', 'chrome,vm', 'test.dart']); expect( - test.stdout, - containsInOrder([ - '+0: [Chrome, Dart2Js]', - '+1: [VM, Source]', - '+2: All tests passed!', - ])); + test.stdout, + containsInOrder([ + '+0: [Chrome, Dart2Js]', + '+1: [VM, Source]', + '+2: All tests passed!', + ]), + ); await test.shouldExit(0); }); test('supports platform selectors with compilers', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'compilers': ['vm:source', 'browser:kernel'] - })) + 'dart_test.yaml', + jsonEncode({ + 'compilers': ['vm:source', 'browser:kernel'], + }), + ) .create(); await d.file('test.dart', ''' @@ -63,12 +66,13 @@ void main() { var test = await runTest(['-p', 'chrome,vm', 'test.dart']); expect( - test.stdout, - containsInOrder([ - '+0: [Chrome, Dart2Js]', - '+1: [VM, Source]', - '+2: All tests passed!', - ])); + test.stdout, + containsInOrder([ + '+0: [Chrome, Dart2Js]', + '+1: [VM, Source]', + '+2: All tests passed!', + ]), + ); await test.shouldExit(0); }); }); diff --git a/pkgs/test/test/runner/configuration/configuration_test.dart b/pkgs/test/test/runner/configuration/configuration_test.dart index 03cc7283c..e475e524e 100644 --- a/pkgs/test/test/runner/configuration/configuration_test.dart +++ b/pkgs/test/test/runner/configuration/configuration_test.dart @@ -34,20 +34,21 @@ void main() { test("if only the old configuration's is defined, uses it", () { var merged = configuration( - help: true, - version: true, - pauseAfterLoad: true, - debug: true, - color: true, - configurationPath: 'special_test.yaml', - reporter: 'json', - fileReporters: {'json': 'out.json'}, - shardIndex: 3, - totalShards: 10, - testRandomizeOrderingSeed: 123, - testSelections: const { - 'bar': {TestSelection()} - }).merge(configuration()); + help: true, + version: true, + pauseAfterLoad: true, + debug: true, + color: true, + configurationPath: 'special_test.yaml', + reporter: 'json', + fileReporters: {'json': 'out.json'}, + shardIndex: 3, + totalShards: 10, + testRandomizeOrderingSeed: 123, + testSelections: const { + 'bar': {TestSelection()}, + }, + ).merge(configuration()); expect(merged.help, isTrue); expect(merged.version, isTrue); @@ -64,7 +65,8 @@ void main() { }); test("if only the new configuration's is defined, uses it", () { - var merged = configuration().merge(configuration( + var merged = configuration().merge( + configuration( help: true, version: true, pauseAfterLoad: true, @@ -77,8 +79,10 @@ void main() { totalShards: 10, testRandomizeOrderingSeed: 123, testSelections: const { - 'bar': {TestSelection()} - })); + 'bar': {TestSelection()}, + }, + ), + ); expect(merged.help, isTrue); expect(merged.version, isTrue); @@ -94,39 +98,40 @@ void main() { expect(merged.testSelections.keys.single, 'bar'); }); - test( - "if the two configurations conflict, uses the new configuration's " + test("if the two configurations conflict, uses the new configuration's " 'values', () { var older = configuration( - help: true, - version: false, - pauseAfterLoad: true, - debug: true, - color: false, - configurationPath: 'special_test.yaml', - reporter: 'json', - fileReporters: {'json': 'old.json'}, - shardIndex: 2, - totalShards: 4, - testRandomizeOrderingSeed: 0, - testSelections: const { - 'bar': {TestSelection()} - }); + help: true, + version: false, + pauseAfterLoad: true, + debug: true, + color: false, + configurationPath: 'special_test.yaml', + reporter: 'json', + fileReporters: {'json': 'old.json'}, + shardIndex: 2, + totalShards: 4, + testRandomizeOrderingSeed: 0, + testSelections: const { + 'bar': {TestSelection()}, + }, + ); var newer = configuration( - help: false, - version: true, - pauseAfterLoad: false, - debug: false, - color: true, - configurationPath: 'test_special.yaml', - reporter: 'compact', - fileReporters: {'json': 'new.json'}, - shardIndex: 3, - totalShards: 10, - testRandomizeOrderingSeed: 123, - testSelections: const { - 'blech': {TestSelection()} - }); + help: false, + version: true, + pauseAfterLoad: false, + debug: false, + color: true, + configurationPath: 'test_special.yaml', + reporter: 'compact', + fileReporters: {'json': 'new.json'}, + shardIndex: 3, + totalShards: 10, + testRandomizeOrderingSeed: 123, + testSelections: const { + 'blech': {TestSelection()}, + }, + ); var merged = older.merge(newer); expect(merged.help, isFalse); @@ -151,33 +156,42 @@ void main() { }); test("if only the old configuration's is defined, uses it", () { - var merged = configuration(chosenPresets: ['baz', 'bang']) - .merge(configuration()); + var merged = configuration( + chosenPresets: ['baz', 'bang'], + ).merge(configuration()); expect(merged.chosenPresets, equals(['baz', 'bang'])); }); test("if only the new configuration's is defined, uses it", () { - var merged = configuration() - .merge(configuration(chosenPresets: ['baz', 'bang'])); + var merged = configuration().merge( + configuration(chosenPresets: ['baz', 'bang']), + ); expect(merged.chosenPresets, equals(['baz', 'bang'])); }); test('if both are defined, unions them', () { - var merged = configuration(chosenPresets: ['baz', 'bang']) - .merge(configuration(chosenPresets: ['qux'])); + var merged = configuration( + chosenPresets: ['baz', 'bang'], + ).merge(configuration(chosenPresets: ['qux'])); expect(merged.chosenPresets, equals(['baz', 'bang', 'qux'])); }); }); group('for presets', () { test('merges each nested configuration', () { - var merged = configuration(presets: { - 'bang': configuration(pauseAfterLoad: true), - 'qux': configuration(color: true) - }).merge(configuration(presets: { - 'qux': configuration(color: false), - 'zap': configuration(help: true) - })); + var merged = configuration( + presets: { + 'bang': configuration(pauseAfterLoad: true), + 'qux': configuration(color: true), + }, + ).merge( + configuration( + presets: { + 'qux': configuration(color: false), + 'zap': configuration(help: true), + }, + ), + ); expect(merged.presets['bang']!.pauseAfterLoad, isTrue); expect(merged.presets['qux']!.color, isFalse); @@ -186,8 +200,9 @@ void main() { test('automatically resolves a matching chosen preset', () { var config = configuration( - presets: {'foo': configuration(color: true)}, - chosenPresets: ['foo']); + presets: {'foo': configuration(color: true)}, + chosenPresets: ['foo'], + ); expect(config.presets, isEmpty); expect(config.chosenPresets, equals(['foo'])); expect(config.knownPresets, equals(['foo'])); @@ -195,25 +210,25 @@ void main() { }); test('resolves a chosen presets in order', () { - var config = configuration(presets: { - 'foo': configuration(color: true), - 'bar': configuration(color: false) - }, chosenPresets: [ - 'foo', - 'bar' - ]); + var config = configuration( + presets: { + 'foo': configuration(color: true), + 'bar': configuration(color: false), + }, + chosenPresets: ['foo', 'bar'], + ); expect(config.presets, isEmpty); expect(config.chosenPresets, equals(['foo', 'bar'])); expect(config.knownPresets, unorderedEquals(['foo', 'bar'])); expect(config.color, isFalse); - config = configuration(presets: { - 'foo': configuration(color: true), - 'bar': configuration(color: false) - }, chosenPresets: [ - 'bar', - 'foo' - ]); + config = configuration( + presets: { + 'foo': configuration(color: true), + 'bar': configuration(color: false), + }, + chosenPresets: ['bar', 'foo'], + ); expect(config.presets, isEmpty); expect(config.chosenPresets, equals(['bar', 'foo'])); expect(config.knownPresets, unorderedEquals(['foo', 'bar'])); @@ -228,8 +243,9 @@ void main() { }); test('resolves presets through merging', () { - var config = configuration(presets: {'foo': configuration(color: true)}) - .merge(configuration(chosenPresets: ['foo'])); + var config = configuration( + presets: {'foo': configuration(color: true)}, + ).merge(configuration(chosenPresets: ['foo'])); expect(config.presets, isEmpty); expect(config.chosenPresets, equals(['foo'])); @@ -239,8 +255,9 @@ void main() { test('preserves known presets through merging', () { var config = configuration( - presets: {'foo': configuration(color: true)}, - chosenPresets: ['foo']).merge(configuration()); + presets: {'foo': configuration(color: true)}, + chosenPresets: ['foo'], + ).merge(configuration()); expect(config.presets, isEmpty); expect(config.chosenPresets, equals(['foo'])); @@ -258,38 +275,51 @@ void main() { test("if only the old configuration's is defined, uses it", () { var merged = configuration( - includeTags: BooleanSelector.parse('foo || bar'), - excludeTags: BooleanSelector.parse('baz || bang')) - .merge(configuration()); + includeTags: BooleanSelector.parse('foo || bar'), + excludeTags: BooleanSelector.parse('baz || bang'), + ).merge(configuration()); expect(merged.includeTags, equals(BooleanSelector.parse('foo || bar'))); expect( - merged.excludeTags, equals(BooleanSelector.parse('baz || bang'))); + merged.excludeTags, + equals(BooleanSelector.parse('baz || bang')), + ); }); test("if only the configuration's is defined, uses it", () { - var merged = configuration().merge(configuration( + var merged = configuration().merge( + configuration( includeTags: BooleanSelector.parse('foo || bar'), - excludeTags: BooleanSelector.parse('baz || bang'))); + excludeTags: BooleanSelector.parse('baz || bang'), + ), + ); expect(merged.includeTags, equals(BooleanSelector.parse('foo || bar'))); expect( - merged.excludeTags, equals(BooleanSelector.parse('baz || bang'))); + merged.excludeTags, + equals(BooleanSelector.parse('baz || bang')), + ); }); test('if both are defined, unions or intersects them', () { var older = configuration( - includeTags: BooleanSelector.parse('foo || bar'), - excludeTags: BooleanSelector.parse('baz || bang')); + includeTags: BooleanSelector.parse('foo || bar'), + excludeTags: BooleanSelector.parse('baz || bang'), + ); var newer = configuration( - includeTags: BooleanSelector.parse('blip'), - excludeTags: BooleanSelector.parse('qux')); + includeTags: BooleanSelector.parse('blip'), + excludeTags: BooleanSelector.parse('qux'), + ); var merged = older.merge(newer); - expect(merged.includeTags, - equals(BooleanSelector.parse('(foo || bar) && blip'))); - expect(merged.excludeTags, - equals(BooleanSelector.parse('(baz || bang) || qux'))); + expect( + merged.includeTags, + equals(BooleanSelector.parse('(foo || bar) && blip')), + ); + expect( + merged.excludeTags, + equals(BooleanSelector.parse('(baz || bang) || qux')), + ); }); }); @@ -300,15 +330,17 @@ void main() { }); test("if only the old configuration's is defined, uses it", () { - var merged = configuration(globalPatterns: ['beep', 'boop']) - .merge(configuration()); + var merged = configuration( + globalPatterns: ['beep', 'boop'], + ).merge(configuration()); expect(merged.globalPatterns, equals(['beep', 'boop'])); }); test("if only the new configuration's is defined, uses it", () { - var merged = configuration() - .merge(configuration(globalPatterns: ['beep', 'boop'])); + var merged = configuration().merge( + configuration(globalPatterns: ['beep', 'boop']), + ); expect(merged.globalPatterns, equals(['beep', 'boop'])); }); @@ -319,7 +351,9 @@ void main() { var merged = older.merge(newer); expect( - merged.globalPatterns, unorderedEquals(['beep', 'boop', 'bonk'])); + merged.globalPatterns, + unorderedEquals(['beep', 'boop', 'bonk']), + ); }); }); }); diff --git a/pkgs/test/test/runner/configuration/custom_platform_test.dart b/pkgs/test/test/runner/configuration/custom_platform_test.dart index ca9ec051d..662acb08d 100644 --- a/pkgs/test/test/runner/configuration/custom_platform_test.dart +++ b/pkgs/test/test/runner/configuration/custom_platform_test.dart @@ -142,8 +142,10 @@ void main() { await d.file('dart_test.yaml', 'override_platforms: 12').create(); var test = await runTest([]); - expect(test.stderr, - containsInOrder(['override_platforms must be a map.', '^^'])); + expect( + test.stderr, + containsInOrder(['override_platforms must be a map.', '^^']), + ); await test.shouldExit(exit_codes.data); }); @@ -153,8 +155,10 @@ void main() { .create(); var test = await runTest([]); - expect(test.stderr, - containsInOrder(['Platform identifier must be a string.', '^^'])); + expect( + test.stderr, + containsInOrder(['Platform identifier must be a string.', '^^']), + ); await test.shouldExit(exit_codes.data); }); @@ -165,12 +169,13 @@ void main() { var test = await runTest([]); expect( - test.stderr, - containsInOrder([ - 'Platform identifier must be an (optionally hyphenated) Dart ' - 'identifier.', - '^^^^^^^' - ])); + test.stderr, + containsInOrder([ + 'Platform identifier must be an (optionally hyphenated) Dart ' + 'identifier.', + '^^^^^^^', + ]), + ); await test.shouldExit(exit_codes.data); }); @@ -181,8 +186,10 @@ void main() { ''').create(); var test = await runTest([]); - expect(test.stderr, - containsInOrder(['Platform definition must be a map.', '^^'])); + expect( + test.stderr, + containsInOrder(['Platform definition must be a map.', '^^']), + ); await test.shouldExit(exit_codes.data); }); @@ -193,8 +200,10 @@ void main() { ''').create(); var test = await runTest([]); - expect(test.stderr, - containsInOrder(['Missing required field "settings".', '^^'])); + expect( + test.stderr, + containsInOrder(['Missing required field "settings".', '^^']), + ); await test.shouldExit(exit_codes.data); }); @@ -218,8 +227,10 @@ void main() { ''').create(); var test = await runTest(['test.dart']); - expect(test.stderr, - containsInOrder(['Unknown platform "chromium".', '^^^^^^'])); + expect( + test.stderr, + containsInOrder(['Unknown platform "chromium".', '^^^^^^']), + ); await test.shouldExit(exit_codes.data); }); @@ -231,8 +242,10 @@ void main() { ''').create(); var test = await runTest(['-p', 'vm', 'test.dart']); - expect(test.stdout, - containsInOrder(['The "vm" platform can\'t be customized.', '^^'])); + expect( + test.stdout, + containsInOrder(['The "vm" platform can\'t be customized.', '^^']), + ); await test.shouldExit(1); }); @@ -246,32 +259,38 @@ void main() { ''').create(); var test = await runTest(['-p', 'chrome', 'test.dart']); - expect(test.stdout, - containsInOrder(['Must be a map or a string.', '^^'])); + expect( + test.stdout, + containsInOrder(['Must be a map or a string.', '^^']), + ); await test.shouldExit(1); }); - test('executable string may not be relative on POSIX', () async { - await d.file('dart_test.yaml', ''' + test( + 'executable string may not be relative on POSIX', + () async { + await d.file('dart_test.yaml', ''' override_platforms: chrome: settings: executable: foo/bar ''').create(); - var test = await runTest(['-p', 'chrome', 'test.dart']); - expect( + var test = await runTest(['-p', 'chrome', 'test.dart']); + expect( test.stdout, containsInOrder([ 'Linux and Mac OS executables may not be relative paths.', - '^^^^^^^' - ])); - await test.shouldExit(1); - }, - // We allow relative executables for Windows so that Windows users - // can set a global executable without having to explicitly write - // `windows:`. - testOn: '!windows'); + '^^^^^^^', + ]), + ); + await test.shouldExit(1); + }, + // We allow relative executables for Windows so that Windows users + // can set a global executable without having to explicitly write + // `windows:`. + testOn: '!windows', + ); test('Linux executable must be a string', () async { await d.file('dart_test.yaml', ''' @@ -298,11 +317,12 @@ void main() { var test = await runTest(['-p', 'chrome', 'test.dart']); expect( - test.stdout, - containsInOrder([ - 'Linux and Mac OS executables may not be relative paths.', - '^^^^^^^' - ])); + test.stdout, + containsInOrder([ + 'Linux and Mac OS executables may not be relative paths.', + '^^^^^^^', + ]), + ); await test.shouldExit(1); }); @@ -331,11 +351,12 @@ void main() { var test = await runTest(['-p', 'chrome', 'test.dart']); expect( - test.stdout, - containsInOrder([ - 'Linux and Mac OS executables may not be relative paths.', - '^^^^^^^' - ])); + test.stdout, + containsInOrder([ + 'Linux and Mac OS executables may not be relative paths.', + '^^^^^^^', + ]), + ); await test.shouldExit(1); }); @@ -363,9 +384,9 @@ void main() { var test = await runTest(['-p', 'chrome', 'test.dart']); expect( - test.stdout, - emitsThrough( - contains('Failed to run Chrome: $noSuchFileMessage'))); + test.stdout, + emitsThrough(contains('Failed to run Chrome: $noSuchFileMessage')), + ); await test.shouldExit(1); }); @@ -379,9 +400,9 @@ void main() { var test = await runTest(['-p', 'node', 'test.dart']); expect( - test.stdout, - emitsThrough( - contains('Failed to run Node.js: $noSuchFileMessage'))); + test.stdout, + emitsThrough(contains('Failed to run Node.js: $noSuchFileMessage')), + ); await test.shouldExit(1); }, tags: 'node'); @@ -395,9 +416,9 @@ void main() { var test = await runTest(['-p', 'chrome', 'test.dart']); expect( - test.stdout, - emitsThrough( - containsInOrder(['Must be a boolean.', '^^^^^^^^^^']))); + test.stdout, + emitsThrough(containsInOrder(['Must be a boolean.', '^^^^^^^^^^'])), + ); await test.shouldExit(1); }); }); @@ -504,8 +525,10 @@ void main() { await d.file('dart_test.yaml', 'define_platforms: 12').create(); var test = await runTest([]); - expect(test.stderr, - containsInOrder(['define_platforms must be a map.', '^^'])); + expect( + test.stderr, + containsInOrder(['define_platforms must be a map.', '^^']), + ); await test.shouldExit(exit_codes.data); }); @@ -513,8 +536,10 @@ void main() { await d.file('dart_test.yaml', 'define_platforms: {12: null}').create(); var test = await runTest([]); - expect(test.stderr, - containsInOrder(['Platform identifier must be a string.', '^^'])); + expect( + test.stderr, + containsInOrder(['Platform identifier must be a string.', '^^']), + ); await test.shouldExit(exit_codes.data); }); @@ -525,12 +550,13 @@ void main() { var test = await runTest([]); expect( - test.stderr, - containsInOrder([ - 'Platform identifier must be an (optionally hyphenated) Dart ' - 'identifier.', - '^^^^^^^' - ])); + test.stderr, + containsInOrder([ + 'Platform identifier must be an (optionally hyphenated) Dart ' + 'identifier.', + '^^^^^^^', + ]), + ); await test.shouldExit(exit_codes.data); }); @@ -541,8 +567,10 @@ void main() { ''').create(); var test = await runTest([]); - expect(test.stderr, - containsInOrder(['Platform definition must be a map.', '^^'])); + expect( + test.stderr, + containsInOrder(['Platform definition must be a map.', '^^']), + ); await test.shouldExit(exit_codes.data); }); @@ -556,9 +584,12 @@ void main() { var test = await runTest([]); expect( - test.stderr, - containsInOrder( - ['Missing required field "name".', 'extends: chrome'])); + test.stderr, + containsInOrder([ + 'Missing required field "name".', + 'extends: chrome', + ]), + ); await test.shouldExit(exit_codes.data); }); @@ -586,9 +617,12 @@ void main() { var test = await runTest([]); expect( - test.stderr, - containsInOrder( - ['Missing required field "extends".', 'name: Chromium'])); + test.stderr, + containsInOrder([ + 'Missing required field "extends".', + 'name: Chromium', + ]), + ); await test.shouldExit(exit_codes.data); }); @@ -602,8 +636,10 @@ void main() { ''').create(); var test = await runTest([]); - expect(test.stderr, - containsInOrder(['Platform parent must be a string.', '^^^^'])); + expect( + test.stderr, + containsInOrder(['Platform parent must be a string.', '^^^^']), + ); await test.shouldExit(exit_codes.data); }); @@ -618,12 +654,13 @@ void main() { var test = await runTest([]); expect( - test.stderr, - containsInOrder([ - 'Platform parent must be an (optionally hyphenated) Dart ' - 'identifier.', - '^^^^^^^' - ])); + test.stderr, + containsInOrder([ + 'Platform parent must be an (optionally hyphenated) Dart ' + 'identifier.', + '^^^^^^^', + ]), + ); await test.shouldExit(exit_codes.data); }); @@ -637,9 +674,12 @@ void main() { var test = await runTest([]); expect( - test.stderr, - containsInOrder( - ['Missing required field "settings".', 'name: Chromium'])); + test.stderr, + containsInOrder([ + 'Missing required field "settings".', + 'name: Chromium', + ]), + ); await test.shouldExit(exit_codes.data); }); @@ -670,12 +710,13 @@ void main() { var test = await runTest([]); expect( - test.stderr, - containsInOrder([ - 'The platform "chrome" already exists. Use override_platforms to ' - 'override it.', - '^^^^^^' - ])); + test.stderr, + containsInOrder([ + 'The platform "chrome" already exists. Use override_platforms to ' + 'override it.', + '^^^^^^', + ]), + ); await test.shouldExit(exit_codes.data); }); @@ -695,9 +736,10 @@ void main() { await test.shouldExit(exit_codes.data); }); - test("the new platform can't extend an uncustomizable platform", - () async { - await d.file('dart_test.yaml', ''' + test( + "the new platform can't extend an uncustomizable platform", + () async { + await d.file('dart_test.yaml', ''' define_platforms: myvm: name: My VM @@ -705,11 +747,14 @@ void main() { settings: {} ''').create(); - var test = await runTest(['-p', 'myvm', 'test.dart']); - expect(test.stdout, - containsInOrder(['The "vm" platform can\'t be customized.', '^^'])); - await test.shouldExit(1); - }); + var test = await runTest(['-p', 'myvm', 'test.dart']); + expect( + test.stdout, + containsInOrder(['The "vm" platform can\'t be customized.', '^^']), + ); + await test.shouldExit(1); + }, + ); group('when overriding browsers', () { test('executable must be a string or map', () async { @@ -723,13 +768,17 @@ void main() { ''').create(); var test = await runTest(['-p', 'chromium', 'test.dart']); - expect(test.stdout, - containsInOrder(['Must be a map or a string.', '^^'])); + expect( + test.stdout, + containsInOrder(['Must be a map or a string.', '^^']), + ); await test.shouldExit(1); }); - test('executable string may not be relative on POSIX', () async { - await d.file('dart_test.yaml', ''' + test( + 'executable string may not be relative on POSIX', + () async { + await d.file('dart_test.yaml', ''' define_platforms: chromium: name: Chromium @@ -738,19 +787,21 @@ void main() { executable: foo/bar ''').create(); - var test = await runTest(['-p', 'chromium', 'test.dart']); - expect( + var test = await runTest(['-p', 'chromium', 'test.dart']); + expect( test.stdout, containsInOrder([ 'Linux and Mac OS executables may not be relative paths.', - '^^^^^^^' - ])); - await test.shouldExit(1); - }, - // We allow relative executables for Windows so that Windows users - // can set a global executable without having to explicitly write - // `windows:`. - testOn: '!windows'); + '^^^^^^^', + ]), + ); + await test.shouldExit(1); + }, + // We allow relative executables for Windows so that Windows users + // can set a global executable without having to explicitly write + // `windows:`. + testOn: '!windows', + ); test('Linux executable must be a string', () async { await d.file('dart_test.yaml', ''' @@ -781,11 +832,12 @@ void main() { var test = await runTest(['-p', 'chromium', 'test.dart']); expect( - test.stdout, - containsInOrder([ - 'Linux and Mac OS executables may not be relative paths.', - '^^^^^^^' - ])); + test.stdout, + containsInOrder([ + 'Linux and Mac OS executables may not be relative paths.', + '^^^^^^^', + ]), + ); await test.shouldExit(1); }); @@ -818,11 +870,12 @@ void main() { var test = await runTest(['-p', 'chromium', 'test.dart']); expect( - test.stdout, - containsInOrder([ - 'Linux and Mac OS executables may not be relative paths.', - '^^^^^^^' - ])); + test.stdout, + containsInOrder([ + 'Linux and Mac OS executables may not be relative paths.', + '^^^^^^^', + ]), + ); await test.shouldExit(1); }); @@ -854,9 +907,9 @@ void main() { var test = await runTest(['-p', 'chromium', 'test.dart']); expect( - test.stdout, - emitsThrough( - contains('Failed to run Chrome: $noSuchFileMessage'))); + test.stdout, + emitsThrough(contains('Failed to run Chrome: $noSuchFileMessage')), + ); await test.shouldExit(1); }); @@ -886,8 +939,10 @@ void main() { ''').create(); var test = await runTest(['-p', 'chromium', 'test.dart']); - expect(test.stdout, - containsInOrder(['Unmatched single quote.', '^^^^^^^^^^'])); + expect( + test.stdout, + containsInOrder(['Unmatched single quote.', '^^^^^^^^^^']), + ); await test.shouldExit(1); }); @@ -903,9 +958,9 @@ void main() { var test = await runTest(['-p', 'chromium', 'test.dart']); expect( - test.stdout, - emitsThrough( - containsInOrder(['Must be a boolean.', '^^^^^^^^^^']))); + test.stdout, + emitsThrough(containsInOrder(['Must be a boolean.', '^^^^^^^^^^'])), + ); await test.shouldExit(1); }); @@ -920,8 +975,10 @@ void main() { ''').create(); var test = await runTest(['-p', 'myfox', 'test.dart']); - expect(test.stdout, - emitsThrough(contains('My Firefox exited before connecting.'))); + expect( + test.stdout, + emitsThrough(contains('My Firefox exited before connecting.')), + ); await test.shouldExit(1); }, tags: 'firefox'); }); diff --git a/pkgs/test/test/runner/configuration/duplicate_names_test.dart b/pkgs/test/test/runner/configuration/duplicate_names_test.dart index 5a02f5232..54c6a552f 100644 --- a/pkgs/test/test/runner/configuration/duplicate_names_test.dart +++ b/pkgs/test/test/runner/configuration/duplicate_names_test.dart @@ -21,8 +21,10 @@ void main() { for (var function in ['group', 'test']) { test('${function}s', () async { await d - .file('dart_test.yaml', - jsonEncode({'allow_duplicate_test_names': false})) + .file( + 'dart_test.yaml', + jsonEncode({'allow_duplicate_test_names': false}), + ) .create(); var testName = 'test'; @@ -38,13 +40,17 @@ void main() { var test = await runTest([ 'test.dart', '--configuration', - p.join(d.sandbox, 'dart_test.yaml') + p.join(d.sandbox, 'dart_test.yaml'), ]); expect( - test.stdout, - emitsThrough(contains( - 'A test with the name "$testName" was already declared.'))); + test.stdout, + emitsThrough( + contains( + 'A test with the name "$testName" was already declared.', + ), + ), + ); await test.shouldExit(1); }); @@ -68,9 +74,7 @@ void main() { } ''').create(); - var test = await runTest( - ['test.dart'], - ); + var test = await runTest(['test.dart']); expect(test.stdout, emitsThrough(contains('All tests passed!'))); diff --git a/pkgs/test/test/runner/configuration/global_test.dart b/pkgs/test/test/runner/configuration/global_test.dart index 98e87416a..2f319e2d1 100644 --- a/pkgs/test/test/runner/configuration/global_test.dart +++ b/pkgs/test/test/runner/configuration/global_test.dart @@ -27,8 +27,10 @@ void main() { } ''').create(); - var test = await runTest(['test.dart'], - environment: {'DART_TEST_CONFIG': 'global_test.yaml'}); + var test = await runTest( + ['test.dart'], + environment: {'DART_TEST_CONFIG': 'global_test.yaml'}, + ); expect(test.stdout, emitsThrough(contains('+1: All tests passed!'))); await test.shouldExit(0); }); @@ -46,8 +48,10 @@ void main() { } ''').create(); - var test = await runTest(['test.dart'], - environment: {'DART_TEST_CONFIG': 'global_test.yaml'}); + var test = await runTest( + ['test.dart'], + environment: {'DART_TEST_CONFIG': 'global_test.yaml'}, + ); expect(test.stdout, emitsThrough(contains('dart:async'))); await test.shouldExit(1); }); @@ -63,8 +67,10 @@ void main() { } ''').create(); - var test = await runTest(['test.dart'], - environment: {'DART_TEST_CONFIG': 'global_test.yaml'}); + var test = await runTest( + ['test.dart'], + environment: {'DART_TEST_CONFIG': 'global_test.yaml'}, + ); expect(test.stdout, emitsThrough(contains('"testStart"'))); await test.shouldExit(0); }); @@ -86,8 +92,10 @@ void main() { } ''').create(); - var test = await runTest(['test.dart'], - environment: {'DART_TEST_CONFIG': 'global_test.yaml'}); + var test = await runTest( + ['test.dart'], + environment: {'DART_TEST_CONFIG': 'global_test.yaml'}, + ); expect(test.stdout, neverEmits(contains('dart:isolate-patch'))); await test.shouldExit(1); }); @@ -109,12 +117,17 @@ void main() { } ''').create(); - var test = await runTest(['test.dart'], - environment: {'DART_TEST_CONFIG': 'global_test.yaml'}); + var test = await runTest( + ['test.dart'], + environment: {'DART_TEST_CONFIG': 'global_test.yaml'}, + ); expect( - test.stderr, - containsInOrder( - ["of global_test.yaml: $field isn't supported here.", '^^'])); + test.stderr, + containsInOrder([ + "of global_test.yaml: $field isn't supported here.", + '^^', + ]), + ); await test.shouldExit(exit_codes.data); }); } diff --git a/pkgs/test/test/runner/configuration/include_test.dart b/pkgs/test/test/runner/configuration/include_test.dart index 5d064cfe9..b47462501 100644 --- a/pkgs/test/test/runner/configuration/include_test.dart +++ b/pkgs/test/test/runner/configuration/include_test.dart @@ -86,11 +86,17 @@ void main() { var path = p.join(d.sandbox, 'repo', 'pkg', 'dart_test.yaml'); expect( - () => Configuration.load(path), - throwsA(allOf( - isFormatException, - predicate((error) => - error.toString().contains("include isn't supported here"))))); + () => Configuration.load(path), + throwsA( + allOf( + isFormatException, + predicate( + (error) => + error.toString().contains("include isn't supported here"), + ), + ), + ), + ); }); test('should allow an include field in a runner config context', () async { @@ -132,9 +138,7 @@ void main() { group('gracefully handles', () { test('a non-string include field', () async { await d.dir('repo', [ - d.dir('pkg', [ - d.file('dart_test.yaml', 'include: 3'), - ]), + d.dir('pkg', [d.file('dart_test.yaml', 'include: 3')]), ]).create(); var path = p.join(d.sandbox, 'repo', 'pkg', 'dart_test.yaml'); @@ -143,9 +147,7 @@ void main() { test('a non-existent included file', () async { await d.dir('repo', [ - d.dir('pkg', [ - d.file('dart_test.yaml', 'include: other_test.yaml'), - ]), + d.dir('pkg', [d.file('dart_test.yaml', 'include: other_test.yaml')]), ]).create(); var path = p.join(d.sandbox, 'repo', 'pkg', 'dart_test.yaml'); diff --git a/pkgs/test/test/runner/configuration/platform_test.dart b/pkgs/test/test/runner/configuration/platform_test.dart index 014c0ed43..9158a878e 100644 --- a/pkgs/test/test/runner/configuration/platform_test.dart +++ b/pkgs/test/test/runner/configuration/platform_test.dart @@ -18,18 +18,21 @@ void main() { setUpAll(precompileTestExecutable); group('on_platform', () { - test('applies platform-specific configuration to matching tests', () async { - await d - .file( + test( + 'applies platform-specific configuration to matching tests', + () async { + await d + .file( 'dart_test.yaml', jsonEncode({ 'on_platform': { - 'chrome': {'timeout': '0s'} - } - })) - .create(); + 'chrome': {'timeout': '0s'}, + }, + }), + ) + .create(); - await d.file('test.dart', ''' + await d.file('test.dart', ''' import 'dart:async'; import 'package:test/test.dart'; @@ -39,23 +42,29 @@ void main() { } ''').create(); - var test = await runTest(['-p', 'chrome,vm', 'test.dart']); - expect( + var test = await runTest(['-p', 'chrome,vm', 'test.dart']); + expect( test.stdout, - containsInOrder( - ['-1: [Chrome, Dart2Js] test [E]', '+1 -1: Some tests failed.'])); - await test.shouldExit(1); - }, tags: ['chrome']); + containsInOrder([ + '-1: [Chrome, Dart2Js] test [E]', + '+1 -1: Some tests failed.', + ]), + ); + await test.shouldExit(1); + }, + tags: ['chrome'], + ); test('supports platform selectors', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'on_platform': { - 'chrome || vm': {'timeout': '0s'} - } - })) + 'dart_test.yaml', + jsonEncode({ + 'on_platform': { + 'chrome || vm': {'timeout': '0s'}, + }, + }), + ) .create(); await d.file('test.dart', ''' @@ -70,12 +79,13 @@ void main() { var test = await runTest(['-p', 'chrome,vm', 'test.dart']); expect( - test.stdout, - containsInOrder([ - '-1: [Chrome, Dart2Js] test [E]', - '-2: [VM, Kernel] test [E]', - '-2: Some tests failed.' - ])); + test.stdout, + containsInOrder([ + '-1: [Chrome, Dart2Js] test [E]', + '-2: [VM, Kernel] test [E]', + '-2: Some tests failed.', + ]), + ); await test.shouldExit(1); }, tags: ['chrome']); @@ -84,37 +94,42 @@ void main() { await d.file('dart_test.yaml', '{"on_platform": {12: null}}').create(); var test = await runTest([]); - expect(test.stderr, - containsInOrder(['on_platform key must be a string', '^^'])); + expect( + test.stderr, + containsInOrder(['on_platform key must be a string', '^^']), + ); await test.shouldExit(exit_codes.data); }); test('rejects an invalid selector', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'on_platform': {'foo bar': null} - })) + 'dart_test.yaml', + jsonEncode({ + 'on_platform': {'foo bar': null}, + }), + ) .create(); var test = await runTest([]); expect( - test.stderr, - containsInOrder([ - 'Invalid on_platform key: Expected end of input.', - '^^^^^^^^^' - ])); + test.stderr, + containsInOrder([ + 'Invalid on_platform key: Expected end of input.', + '^^^^^^^^^', + ]), + ); await test.shouldExit(exit_codes.data); }); test('rejects a selector with an undefined variable', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'on_platform': {'foo': null} - })) + 'dart_test.yaml', + jsonEncode({ + 'on_platform': {'foo': null}, + }), + ) .create(); await d.dir('test').create(); @@ -127,49 +142,58 @@ void main() { test('rejects an invalid map', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'on_platform': {'linux': 12} - })) + 'dart_test.yaml', + jsonEncode({ + 'on_platform': {'linux': 12}, + }), + ) .create(); var test = await runTest([]); - expect(test.stderr, - containsInOrder(['on_platform value must be a map.', '^^'])); + expect( + test.stderr, + containsInOrder(['on_platform value must be a map.', '^^']), + ); await test.shouldExit(exit_codes.data); }); test('rejects an invalid configuration', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'on_platform': { - 'linux': {'timeout': '12p'} - } - })) + 'dart_test.yaml', + jsonEncode({ + 'on_platform': { + 'linux': {'timeout': '12p'}, + }, + }), + ) .create(); var test = await runTest([]); - expect(test.stderr, - containsInOrder(['Invalid timeout: expected unit.', '^^^^^'])); + expect( + test.stderr, + containsInOrder(['Invalid timeout: expected unit.', '^^^^^']), + ); await test.shouldExit(exit_codes.data); }); test('rejects runner configuration', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'on_platform': { - 'linux': {'filename': '*_blorp'} - } - })) + 'dart_test.yaml', + jsonEncode({ + 'on_platform': { + 'linux': {'filename': '*_blorp'}, + }, + }), + ) .create(); var test = await runTest([]); - expect(test.stderr, - containsInOrder(["filename isn't supported here.", '^^^^^^^^^'])); + expect( + test.stderr, + containsInOrder(["filename isn't supported here.", '^^^^^^^^^']), + ); await test.shouldExit(exit_codes.data); }); }); @@ -179,12 +203,13 @@ void main() { test('applies OS-specific configuration on a matching OS', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'on_os': { - currentOS.identifier: {'filename': 'test_*.dart'} - } - })) + 'dart_test.yaml', + jsonEncode({ + 'on_os': { + currentOS.identifier: {'filename': 'test_*.dart'}, + }, + }), + ) .create(); await d.file('foo_test.dart', ''' @@ -205,25 +230,30 @@ void main() { var test = await runTest(['.']); expect( - test.stdout, - containsInOrder( - ['+0: ./test_foo.dart: test_foo', '+1: All tests passed!'])); + test.stdout, + containsInOrder([ + '+0: ./test_foo.dart: test_foo', + '+1: All tests passed!', + ]), + ); await test.shouldExit(0); }); - test("doesn't apply OS-specific configuration on a non-matching OS", - () async { - await d - .file( + test( + "doesn't apply OS-specific configuration on a non-matching OS", + () async { + await d + .file( 'dart_test.yaml', jsonEncode({ 'on_os': { - otherOS: {'filename': 'test_*.dart'} - } - })) - .create(); + otherOS: {'filename': 'test_*.dart'}, + }, + }), + ) + .create(); - await d.file('foo_test.dart', ''' + await d.file('foo_test.dart', ''' import 'package:test/test.dart'; void main() { @@ -231,7 +261,7 @@ void main() { } ''').create(); - await d.file('test_foo.dart', ''' + await d.file('test_foo.dart', ''' import 'package:test/test.dart'; void main() { @@ -239,13 +269,17 @@ void main() { } ''').create(); - var test = await runTest(['.']); - expect( + var test = await runTest(['.']); + expect( test.stdout, - containsInOrder( - ['+0: ./foo_test.dart: foo_test', '+1: All tests passed!'])); - await test.shouldExit(0); - }); + containsInOrder([ + '+0: ./foo_test.dart: foo_test', + '+1: All tests passed!', + ]), + ); + await test.shouldExit(0); + }, + ); group('errors', () { test('rejects an invalid OS type', () async { @@ -253,56 +287,68 @@ void main() { var test = await runTest([]); expect( - test.stderr, containsInOrder(['on_os key must be a string', '^^'])); + test.stderr, + containsInOrder(['on_os key must be a string', '^^']), + ); await test.shouldExit(exit_codes.data); }); test('rejects an unknown OS name', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'on_os': {'foo': null} - })) + 'dart_test.yaml', + jsonEncode({ + 'on_os': {'foo': null}, + }), + ) .create(); var test = await runTest([]); expect( - test.stderr, - containsInOrder( - ['Invalid on_os key: No such operating system.', '^^^^^'])); + test.stderr, + containsInOrder([ + 'Invalid on_os key: No such operating system.', + '^^^^^', + ]), + ); await test.shouldExit(exit_codes.data); }); test('rejects an invalid map', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'on_os': {'linux': 12} - })) + 'dart_test.yaml', + jsonEncode({ + 'on_os': {'linux': 12}, + }), + ) .create(); var test = await runTest([]); expect( - test.stderr, containsInOrder(['on_os value must be a map.', '^^'])); + test.stderr, + containsInOrder(['on_os value must be a map.', '^^']), + ); await test.shouldExit(exit_codes.data); }); test('rejects an invalid configuration', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'on_os': { - 'linux': {'timeout': '12p'} - } - })) + 'dart_test.yaml', + jsonEncode({ + 'on_os': { + 'linux': {'timeout': '12p'}, + }, + }), + ) .create(); var test = await runTest([]); - expect(test.stderr, - containsInOrder(['Invalid timeout: expected unit.', '^^^^^'])); + expect( + test.stderr, + containsInOrder(['Invalid timeout: expected unit.', '^^^^^']), + ); await test.shouldExit(exit_codes.data); }); }); diff --git a/pkgs/test/test/runner/configuration/presets_test.dart b/pkgs/test/test/runner/configuration/presets_test.dart index 193f12ed9..1f46c29cf 100644 --- a/pkgs/test/test/runner/configuration/presets_test.dart +++ b/pkgs/test/test/runner/configuration/presets_test.dart @@ -21,12 +21,13 @@ void main() { test("don't do anything by default", () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'presets': { - 'foo': {'timeout': '0s'} - } - })) + 'dart_test.yaml', + jsonEncode({ + 'presets': { + 'foo': {'timeout': '0s'}, + }, + }), + ) .create(); await d.file('test.dart', ''' @@ -45,12 +46,13 @@ void main() { test('can be selected on the command line', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'presets': { - 'foo': {'timeout': '0s'} - } - })) + 'dart_test.yaml', + jsonEncode({ + 'presets': { + 'foo': {'timeout': '0s'}, + }, + }), + ) .create(); await d.file('test.dart', ''' @@ -64,23 +66,26 @@ void main() { ''').create(); var test = await runTest(['-P', 'foo', 'test.dart']); - expect(test.stdout, - containsInOrder(['-1: test [E]', '-1: Some tests failed.'])); + expect( + test.stdout, + containsInOrder(['-1: test [E]', '-1: Some tests failed.']), + ); await test.shouldExit(1); }); test('multiple presets can be selected', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'presets': { - 'foo': {'timeout': '0s'}, - 'bar': { - 'paths': ['test.dart'] - } - } - })) + 'dart_test.yaml', + jsonEncode({ + 'presets': { + 'foo': {'timeout': '0s'}, + 'bar': { + 'paths': ['test.dart'], + }, + }, + }), + ) .create(); await d.file('test.dart', ''' @@ -94,21 +99,24 @@ void main() { ''').create(); var test = await runTest(['-P', 'foo,bar']); - expect(test.stdout, - containsInOrder(['-1: test [E]', '-1: Some tests failed.'])); + expect( + test.stdout, + containsInOrder(['-1: test [E]', '-1: Some tests failed.']), + ); await test.shouldExit(1); }); test('the latter preset takes precedence', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'presets': { - 'foo': {'timeout': '0s'}, - 'bar': {'timeout': '30s'} - } - })) + 'dart_test.yaml', + jsonEncode({ + 'presets': { + 'foo': {'timeout': '0s'}, + 'bar': {'timeout': '30s'}, + }, + }), + ) .create(); await d.file('test.dart', ''' @@ -124,21 +132,24 @@ void main() { await (await runTest(['-P', 'foo,bar', 'test.dart'])).shouldExit(0); var test = await runTest(['-P', 'bar,foo', 'test.dart']); - expect(test.stdout, - containsInOrder(['-1: test [E]', '-1: Some tests failed.'])); + expect( + test.stdout, + containsInOrder(['-1: test [E]', '-1: Some tests failed.']), + ); await test.shouldExit(1); }); test('a preset takes precedence over the base configuration', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'presets': { - 'foo': {'timeout': '0s'} - }, - 'timeout': '30s' - })) + 'dart_test.yaml', + jsonEncode({ + 'presets': { + 'foo': {'timeout': '0s'}, + }, + 'timeout': '30s', + }), + ) .create(); await d.file('test.dart', ''' @@ -152,19 +163,22 @@ void main() { ''').create(); var test = await runTest(['-P', 'foo', 'test.dart']); - expect(test.stdout, - containsInOrder(['-1: test [E]', '-1: Some tests failed.'])); + expect( + test.stdout, + containsInOrder(['-1: test [E]', '-1: Some tests failed.']), + ); await test.shouldExit(1); await d .file( - 'dart_test.yaml', - jsonEncode({ - 'presets': { - 'foo': {'timeout': '30s'} - }, - 'timeout': '00s' - })) + 'dart_test.yaml', + jsonEncode({ + 'presets': { + 'foo': {'timeout': '30s'}, + }, + 'timeout': '00s', + }), + ) .create(); await (await runTest(['-P', 'foo', 'test.dart'])).shouldExit(0); @@ -173,16 +187,17 @@ void main() { test('a nested preset is activated', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'tags': { - 'foo': { - 'presets': { - 'bar': {'timeout': '0s'} - }, + 'dart_test.yaml', + jsonEncode({ + 'tags': { + 'foo': { + 'presets': { + 'bar': {'timeout': '0s'}, }, - } - })) + }, + }, + }), + ) .create(); await d.file('test.dart', ''' @@ -197,19 +212,22 @@ void main() { ''').create(); var test = await runTest(['-P', 'bar', 'test.dart']); - expect(test.stdout, - containsInOrder(['+0 -1: test 1 [E]', '+1 -1: Some tests failed.'])); + expect( + test.stdout, + containsInOrder(['+0 -1: test 1 [E]', '+1 -1: Some tests failed.']), + ); await test.shouldExit(1); await d .file( - 'dart_test.yaml', - jsonEncode({ - 'presets': { - 'foo': {'timeout': '30s'} - }, - 'timeout': '00s' - })) + 'dart_test.yaml', + jsonEncode({ + 'presets': { + 'foo': {'timeout': '30s'}, + }, + 'timeout': '00s', + }), + ) .create(); await (await runTest(['-P', 'foo', 'test.dart'])).shouldExit(0); @@ -220,13 +238,14 @@ void main() { test('selects a preset', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'presets': { - 'foo': {'timeout': '0s'} - }, - 'add_presets': ['foo'] - })) + 'dart_test.yaml', + jsonEncode({ + 'presets': { + 'foo': {'timeout': '0s'}, + }, + 'add_presets': ['foo'], + }), + ) .create(); await d.file('test.dart', ''' @@ -240,22 +259,25 @@ void main() { ''').create(); var test = await runTest(['test.dart']); - expect(test.stdout, - containsInOrder(['-1: test [E]', '-1: Some tests failed.'])); + expect( + test.stdout, + containsInOrder(['-1: test [E]', '-1: Some tests failed.']), + ); await test.shouldExit(1); }); test('applies presets in selection order', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'presets': { - 'foo': {'timeout': '0s'}, - 'bar': {'timeout': '30s'} - }, - 'add_presets': ['foo', 'bar'] - })) + 'dart_test.yaml', + jsonEncode({ + 'presets': { + 'foo': {'timeout': '0s'}, + 'bar': {'timeout': '30s'}, + }, + 'add_presets': ['foo', 'bar'], + }), + ) .create(); await d.file('test.dart', ''' @@ -272,34 +294,38 @@ void main() { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'presets': { - 'foo': {'timeout': '0s'}, - 'bar': {'timeout': '30s'} - }, - 'add_presets': ['bar', 'foo'] - })) + 'dart_test.yaml', + jsonEncode({ + 'presets': { + 'foo': {'timeout': '0s'}, + 'bar': {'timeout': '30s'}, + }, + 'add_presets': ['bar', 'foo'], + }), + ) .create(); var test = await runTest(['test.dart']); - expect(test.stdout, - containsInOrder(['-1: test [E]', '-1: Some tests failed.'])); + expect( + test.stdout, + containsInOrder(['-1: test [E]', '-1: Some tests failed.']), + ); await test.shouldExit(1); }); test('allows preset inheritance via add_presets', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'presets': { - 'foo': { - 'add_presets': ['bar'] - }, - 'bar': {'timeout': '0s'} - } - })) + 'dart_test.yaml', + jsonEncode({ + 'presets': { + 'foo': { + 'add_presets': ['bar'], + }, + 'bar': {'timeout': '0s'}, + }, + }), + ) .create(); await d.file('test.dart', ''' @@ -313,25 +339,28 @@ void main() { ''').create(); var test = await runTest(['-P', 'foo', 'test.dart']); - expect(test.stdout, - containsInOrder(['+0 -1: test [E]', '-1: Some tests failed.'])); + expect( + test.stdout, + containsInOrder(['+0 -1: test [E]', '-1: Some tests failed.']), + ); await test.shouldExit(1); }); test('allows circular preset inheritance via add_presets', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'presets': { - 'foo': { - 'add_presets': ['bar'] - }, - 'bar': { - 'add_presets': ['foo'] - } - } - })) + 'dart_test.yaml', + jsonEncode({ + 'presets': { + 'foo': { + 'add_presets': ['bar'], + }, + 'bar': { + 'add_presets': ['foo'], + }, + }, + }), + ) .create(); await d.file('test.dart', ''' @@ -354,27 +383,31 @@ void main() { await d.file('dart_test.yaml', '{"presets": {12: null}}').create(); var test = await runTest([]); - expect(test.stderr, - containsInOrder(['presets key must be a string', '^^'])); + expect( + test.stderr, + containsInOrder(['presets key must be a string', '^^']), + ); await test.shouldExit(exit_codes.data); }); test('rejects an invalid preset name', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'presets': {'foo bar': null} - })) + 'dart_test.yaml', + jsonEncode({ + 'presets': {'foo bar': null}, + }), + ) .create(); var test = await runTest([]); expect( - test.stderr, - containsInOrder([ - 'presets key must be an (optionally hyphenated) Dart identifier.', - '^^^^^^^^^' - ])); + test.stderr, + containsInOrder([ + 'presets key must be an (optionally hyphenated) Dart identifier.', + '^^^^^^^^^', + ]), + ); await test.shouldExit(exit_codes.data); }); @@ -389,38 +422,44 @@ void main() { test('rejects an invalid preset configuration', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'presets': { - 'foo': {'timeout': '12p'} - } - })) + 'dart_test.yaml', + jsonEncode({ + 'presets': { + 'foo': {'timeout': '12p'}, + }, + }), + ) .create(); var test = await runTest([]); - expect(test.stderr, - containsInOrder(['Invalid timeout: expected unit', '^^^^'])); + expect( + test.stderr, + containsInOrder(['Invalid timeout: expected unit', '^^^^']), + ); await test.shouldExit(exit_codes.data); }); test('rejects runner configuration in a non-runner context', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'tags': { - 'foo': { - 'presets': { - 'bar': {'filename': '*_blorp.dart'} - } - } - } - })) + 'dart_test.yaml', + jsonEncode({ + 'tags': { + 'foo': { + 'presets': { + 'bar': {'filename': '*_blorp.dart'}, + }, + }, + }, + }), + ) .create(); var test = await runTest([]); - expect(test.stderr, - containsInOrder(["filename isn't supported here.", '^^^^^^^^^^'])); + expect( + test.stderr, + containsInOrder(["filename isn't supported here.", '^^^^^^^^^^']), + ); await test.shouldExit(exit_codes.data); }); @@ -433,36 +472,45 @@ void main() { test('fails if an undefined preset is added', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'add_presets': ['foo', 'bar'] - })) + 'dart_test.yaml', + jsonEncode({ + 'add_presets': ['foo', 'bar'], + }), + ) .create(); var test = await runTest([]); - expect(test.stderr, - emitsThrough(contains('Undefined presets "foo" and "bar".'))); + expect( + test.stderr, + emitsThrough(contains('Undefined presets "foo" and "bar".')), + ); await test.shouldExit(exit_codes.usage); }); - test('fails if an undefined preset is added in a nested context', - () async { - await d - .file( + test( + 'fails if an undefined preset is added in a nested context', + () async { + await d + .file( 'dart_test.yaml', jsonEncode({ 'on_os': { currentOS.identifier: { - 'add_presets': ['bar'] - } - } - })) - .create(); + 'add_presets': ['bar'], + }, + }, + }), + ) + .create(); - var test = await runTest([]); - expect(test.stderr, emitsThrough(contains('Undefined preset "bar".'))); - await test.shouldExit(exit_codes.usage); - }); + var test = await runTest([]); + expect( + test.stderr, + emitsThrough(contains('Undefined preset "bar".')), + ); + await test.shouldExit(exit_codes.usage); + }, + ); }); group('add_presets', () { @@ -472,42 +520,49 @@ void main() { .create(); var test = await runTest(['test.dart']); - expect(test.stderr, - containsInOrder(['add_presets must be a list', '^^^^'])); + expect( + test.stderr, + containsInOrder(['add_presets must be a list', '^^^^']), + ); await test.shouldExit(exit_codes.data); }); test('rejects an invalid preset type', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'add_presets': [12] - })) + 'dart_test.yaml', + jsonEncode({ + 'add_presets': [12], + }), + ) .create(); var test = await runTest(['test.dart']); - expect(test.stderr, - containsInOrder(['Preset name must be a string', '^^'])); + expect( + test.stderr, + containsInOrder(['Preset name must be a string', '^^']), + ); await test.shouldExit(exit_codes.data); }); test('rejects an invalid preset name', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'add_presets': ['foo bar'] - })) + 'dart_test.yaml', + jsonEncode({ + 'add_presets': ['foo bar'], + }), + ) .create(); var test = await runTest(['test.dart']); expect( - test.stderr, - containsInOrder([ - 'Preset name must be an (optionally hyphenated) Dart identifier.', - '^^^^^^^^^' - ])); + test.stderr, + containsInOrder([ + 'Preset name must be an (optionally hyphenated) Dart identifier.', + '^^^^^^^^^', + ]), + ); await test.shouldExit(exit_codes.data); }); }); diff --git a/pkgs/test/test/runner/configuration/randomize_order_test.dart b/pkgs/test/test/runner/configuration/randomize_order_test.dart index 690f54b1f..85338f98c 100644 --- a/pkgs/test/test/runner/configuration/randomize_order_test.dart +++ b/pkgs/test/test/runner/configuration/randomize_order_test.dart @@ -28,60 +28,75 @@ void main() { ''').create(); // Test with a given seed - var test = - await runTest(['test.dart', '--test-randomize-ordering-seed=987654']); + var test = await runTest([ + 'test.dart', + '--test-randomize-ordering-seed=987654', + ]); expect( - test.stdout, - containsInOrder([ - '+0: test 4', - '+1: test 3', - '+2: test 1', - '+3: test 2', - '+4: All tests passed!' - ])); + test.stdout, + containsInOrder([ + '+0: test 4', + '+1: test 3', + '+2: test 1', + '+3: test 2', + '+4: All tests passed!', + ]), + ); await test.shouldExit(0); // Do not shuffle when passed 0 test = await runTest(['test.dart', '--test-randomize-ordering-seed=0']); expect( - test.stdout, - containsInOrder([ - '+0: test 1', - '+1: test 2', - '+2: test 3', - '+3: test 4', - '+4: All tests passed!' - ])); + test.stdout, + containsInOrder([ + '+0: test 1', + '+1: test 2', + '+2: test 3', + '+3: test 4', + '+4: All tests passed!', + ]), + ); await test.shouldExit(0); // Do not shuffle when passed nothing test = await runTest(['test.dart']); expect( - test.stdout, - containsInOrder([ - '+0: test 1', - '+1: test 2', - '+2: test 3', - '+3: test 4', - '+4: All tests passed!' - ])); + test.stdout, + containsInOrder([ + '+0: test 1', + '+1: test 2', + '+2: test 3', + '+3: test 4', + '+4: All tests passed!', + ]), + ); await test.shouldExit(0); // Shuffle when passed random - test = - await runTest(['test.dart', '--test-randomize-ordering-seed=random']); + test = await runTest([ + 'test.dart', + '--test-randomize-ordering-seed=random', + ]); expect( - test.stdout, - emitsInAnyOrder([ - contains('Shuffling test order with --test-randomize-ordering-seed'), - isNot(contains( - 'Shuffling test order with --test-randomize-ordering-seed=0')) - ])); + test.stdout, + emitsInAnyOrder([ + contains('Shuffling test order with --test-randomize-ordering-seed'), + isNot( + contains( + 'Shuffling test order with --test-randomize-ordering-seed=0', + ), + ), + ]), + ); await test.shouldExit(0); // Doesn't log about shuffling with the json reporter - test = await runTest( - ['test.dart', '--test-randomize-ordering-seed=random', '-r', 'json']); + test = await runTest([ + 'test.dart', + '--test-randomize-ordering-seed=random', + '-r', + 'json', + ]); expect(test.stdout, neverEmits(contains('Shuffling test order'))); await test.shouldExit(0); }); @@ -89,12 +104,13 @@ void main() { test('test shuffling can be disabled in dart_test.yml', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'tags': { - 'doNotShuffle': {'allow_test_randomization': false} - } - })) + 'dart_test.yaml', + jsonEncode({ + 'tags': { + 'doNotShuffle': {'allow_test_randomization': false}, + }, + }), + ) .create(); await d.file('test.dart', ''' @@ -109,17 +125,20 @@ void main() { } ''').create(); - var test = - await runTest(['test.dart', '--test-randomize-ordering-seed=987654']); + var test = await runTest([ + 'test.dart', + '--test-randomize-ordering-seed=987654', + ]); expect( - test.stdout, - containsInOrder([ - '+0: test 1', - '+1: test 2', - '+2: test 3', - '+3: test 4', - '+4: All tests passed!' - ])); + test.stdout, + containsInOrder([ + '+0: test 1', + '+1: test 2', + '+2: test 3', + '+3: test 4', + '+4: All tests passed!', + ]), + ); await test.shouldExit(0); }); @@ -146,20 +165,21 @@ void main() { var test = await runTest(['.', '--test-randomize-ordering-seed=12345']); expect( - test.stdout, - emitsInAnyOrder([ - containsInOrder([ - './1_test.dart: test 1.2', - './1_test.dart: test 1.3', - './1_test.dart: test 1.1' - ]), - containsInOrder([ - './2_test.dart: test 2.2', - './2_test.dart: test 2.3', - './2_test.dart: test 2.1' - ]), - contains('+6: All tests passed!') - ])); + test.stdout, + emitsInAnyOrder([ + containsInOrder([ + './1_test.dart: test 1.2', + './1_test.dart: test 1.3', + './1_test.dart: test 1.1', + ]), + containsInOrder([ + './2_test.dart: test 2.2', + './2_test.dart: test 2.3', + './2_test.dart: test 2.1', + ]), + contains('+6: All tests passed!'), + ]), + ); await test.shouldExit(0); }); @@ -184,21 +204,24 @@ void main() { ''').create(); // Test with a given seed - var test = - await runTest(['test.dart', '--test-randomize-ordering-seed=123']); + var test = await runTest([ + 'test.dart', + '--test-randomize-ordering-seed=123', + ]); expect( - test.stdout, - containsInOrder([ - '+0: Group 2 test 2.4', - '+1: Group 2 test 2.2', - '+2: Group 2 test 2.1', - '+3: Group 2 test 2.3', - '+4: Group 1 test 1.4', - '+5: Group 1 test 1.2', - '+6: Group 1 test 1.1', - '+7: Group 1 test 1.3', - '+8: All tests passed!' - ])); + test.stdout, + containsInOrder([ + '+0: Group 2 test 2.4', + '+1: Group 2 test 2.2', + '+2: Group 2 test 2.1', + '+3: Group 2 test 2.3', + '+4: Group 1 test 1.4', + '+5: Group 1 test 1.2', + '+6: Group 1 test 1.1', + '+7: Group 1 test 1.3', + '+8: All tests passed!', + ]), + ); await test.shouldExit(0); }); @@ -218,17 +241,20 @@ void main() { } ''').create(); - var test = - await runTest(['test.dart', '--test-randomize-ordering-seed=123']); + var test = await runTest([ + 'test.dart', + '--test-randomize-ordering-seed=123', + ]); expect( - test.stdout, - containsInOrder([ - '+0: Group 1 test 1.1', - '+1: Group 1 Group 2 test 2.4', - '+2: Group 1 Group 2 test 2.3', - '+3: Group 1 test 1.2', - '+4: All tests passed!' - ])); + test.stdout, + containsInOrder([ + '+0: Group 1 test 1.1', + '+1: Group 1 Group 2 test 2.4', + '+2: Group 1 Group 2 test 2.3', + '+3: Group 1 test 1.2', + '+4: All tests passed!', + ]), + ); await test.shouldExit(0); }); } diff --git a/pkgs/test/test/runner/configuration/suite_test.dart b/pkgs/test/test/runner/configuration/suite_test.dart index 1c2fc62b2..d2336674c 100644 --- a/pkgs/test/test/runner/configuration/suite_test.dart +++ b/pkgs/test/test/runner/configuration/suite_test.dart @@ -28,60 +28,70 @@ void main() { test("if only the old configuration's is defined, uses it", () { var merged = suiteConfiguration( - jsTrace: true, - runSkipped: true, - precompiledPath: '/tmp/js', - runtimes: [RuntimeSelection(Runtime.chrome.identifier)], - compilerSelections: [CompilerSelection.parse('dart2js')]) - .merge(suiteConfiguration()); + jsTrace: true, + runSkipped: true, + precompiledPath: '/tmp/js', + runtimes: [RuntimeSelection(Runtime.chrome.identifier)], + compilerSelections: [CompilerSelection.parse('dart2js')], + ).merge(suiteConfiguration()); expect(merged.jsTrace, isTrue); expect(merged.runSkipped, isTrue); expect(merged.precompiledPath, equals('/tmp/js')); expect(merged.runtimes, equals([Runtime.chrome.identifier])); - expect(merged.compilerSelections, - equals([CompilerSelection.parse('dart2js')])); + expect( + merged.compilerSelections, + equals([CompilerSelection.parse('dart2js')]), + ); }); test("if only the configuration's is defined, uses it", () { - var merged = suiteConfiguration().merge(suiteConfiguration( + var merged = suiteConfiguration().merge( + suiteConfiguration( jsTrace: true, runSkipped: true, precompiledPath: '/tmp/js', runtimes: [RuntimeSelection(Runtime.chrome.identifier)], - compilerSelections: [CompilerSelection.parse('dart2js')])); + compilerSelections: [CompilerSelection.parse('dart2js')], + ), + ); expect(merged.jsTrace, isTrue); expect(merged.runSkipped, isTrue); expect(merged.precompiledPath, equals('/tmp/js')); expect(merged.runtimes, equals([Runtime.chrome.identifier])); - expect(merged.compilerSelections, - equals([CompilerSelection.parse('dart2js')])); + expect( + merged.compilerSelections, + equals([CompilerSelection.parse('dart2js')]), + ); }); - test( - "if the two configurations conflict, uses the configuration's " + test("if the two configurations conflict, uses the configuration's " 'values', () { var older = suiteConfiguration( - jsTrace: false, - runSkipped: true, - precompiledPath: '/tmp/js', - runtimes: [RuntimeSelection(Runtime.chrome.identifier)], - compilerSelections: [CompilerSelection.parse('dart2js')]); + jsTrace: false, + runSkipped: true, + precompiledPath: '/tmp/js', + runtimes: [RuntimeSelection(Runtime.chrome.identifier)], + compilerSelections: [CompilerSelection.parse('dart2js')], + ); var newer = suiteConfiguration( - jsTrace: true, - runSkipped: false, - precompiledPath: '../js', - runtimes: [RuntimeSelection(Runtime.firefox.identifier)], - compilerSelections: [CompilerSelection.parse('source')]); + jsTrace: true, + runSkipped: false, + precompiledPath: '../js', + runtimes: [RuntimeSelection(Runtime.firefox.identifier)], + compilerSelections: [CompilerSelection.parse('source')], + ); var merged = older.merge(newer); expect(merged.jsTrace, isTrue); expect(merged.runSkipped, isFalse); expect(merged.precompiledPath, equals('../js')); expect(merged.runtimes, equals([Runtime.firefox.identifier])); - expect(merged.compilerSelections, - equals([CompilerSelection.parse('source')])); + expect( + merged.compilerSelections, + equals([CompilerSelection.parse('source')]), + ); }); }); @@ -92,14 +102,16 @@ void main() { }); test("if only the old configuration's is defined, uses it", () { - var merged = suiteConfiguration(dart2jsArgs: ['--foo', '--bar']) - .merge(suiteConfiguration()); + var merged = suiteConfiguration( + dart2jsArgs: ['--foo', '--bar'], + ).merge(suiteConfiguration()); expect(merged.dart2jsArgs, equals(['--foo', '--bar'])); }); test("if only the configuration's is defined, uses it", () { - var merged = suiteConfiguration() - .merge(suiteConfiguration(dart2jsArgs: ['--foo', '--bar'])); + var merged = suiteConfiguration().merge( + suiteConfiguration(dart2jsArgs: ['--foo', '--bar']), + ); expect(merged.dart2jsArgs, equals(['--foo', '--bar'])); }); @@ -113,34 +125,57 @@ void main() { group('for config maps', () { test('merges each nested configuration', () { - var merged = suiteConfiguration(tags: { - BooleanSelector.parse('foo'): - suiteConfiguration(precompiledPath: 'path/'), - BooleanSelector.parse('bar'): suiteConfiguration(jsTrace: true) - }, onPlatform: { - PlatformSelector.parse('vm'): - suiteConfiguration(precompiledPath: 'path/'), - PlatformSelector.parse('chrome'): suiteConfiguration(jsTrace: true) - }).merge(suiteConfiguration(tags: { - BooleanSelector.parse('bar'): suiteConfiguration(jsTrace: false), - BooleanSelector.parse('baz'): suiteConfiguration(runSkipped: true) - }, onPlatform: { - PlatformSelector.parse('chrome'): suiteConfiguration(jsTrace: false), - PlatformSelector.parse('firefox'): - suiteConfiguration(runSkipped: true) - })); - - expect(merged.tags[BooleanSelector.parse('foo')]!.precompiledPath, - equals('path/')); + var merged = suiteConfiguration( + tags: { + BooleanSelector.parse('foo'): suiteConfiguration( + precompiledPath: 'path/', + ), + BooleanSelector.parse('bar'): suiteConfiguration(jsTrace: true), + }, + onPlatform: { + PlatformSelector.parse('vm'): suiteConfiguration( + precompiledPath: 'path/', + ), + PlatformSelector.parse('chrome'): suiteConfiguration(jsTrace: true), + }, + ).merge( + suiteConfiguration( + tags: { + BooleanSelector.parse('bar'): suiteConfiguration(jsTrace: false), + BooleanSelector.parse('baz'): suiteConfiguration( + runSkipped: true, + ), + }, + onPlatform: { + PlatformSelector.parse('chrome'): suiteConfiguration( + jsTrace: false, + ), + PlatformSelector.parse('firefox'): suiteConfiguration( + runSkipped: true, + ), + }, + ), + ); + + expect( + merged.tags[BooleanSelector.parse('foo')]!.precompiledPath, + equals('path/'), + ); expect(merged.tags[BooleanSelector.parse('bar')]!.jsTrace, isFalse); expect(merged.tags[BooleanSelector.parse('baz')]!.runSkipped, isTrue); - expect(merged.onPlatform[PlatformSelector.parse('vm')]!.precompiledPath, - 'path/'); - expect(merged.onPlatform[PlatformSelector.parse('chrome')]!.jsTrace, - isFalse); - expect(merged.onPlatform[PlatformSelector.parse('firefox')]!.runSkipped, - isTrue); + expect( + merged.onPlatform[PlatformSelector.parse('vm')]!.precompiledPath, + 'path/', + ); + expect( + merged.onPlatform[PlatformSelector.parse('chrome')]!.jsTrace, + isFalse, + ); + expect( + merged.onPlatform[PlatformSelector.parse('firefox')]!.runSkipped, + isTrue, + ); }); }); }); diff --git a/pkgs/test/test/runner/configuration/tags_test.dart b/pkgs/test/test/runner/configuration/tags_test.dart index bbdb1d1ce..0389a4ec5 100644 --- a/pkgs/test/test/runner/configuration/tags_test.dart +++ b/pkgs/test/test/runner/configuration/tags_test.dart @@ -19,10 +19,11 @@ void main() { test('adds the specified tags', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'add_tags': ['foo', 'bar'] - })) + 'dart_test.yaml', + jsonEncode({ + 'add_tags': ['foo', 'bar'], + }), + ) .create(); await d.file('test.dart', ''' @@ -50,10 +51,11 @@ void main() { test("doesn't warn for tags that exist in the configuration", () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'tags': {'foo': null} - })) + 'dart_test.yaml', + jsonEncode({ + 'tags': {'foo': null}, + }), + ) .create(); await d.file('test.dart', ''' @@ -72,12 +74,13 @@ void main() { test('applies tag-specific configuration only to matching tests', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'tags': { - 'foo': {'timeout': '0s'} - } - })) + 'dart_test.yaml', + jsonEncode({ + 'tags': { + 'foo': {'timeout': '0s'}, + }, + }), + ) .create(); await d.file('test.dart', ''' @@ -92,20 +95,23 @@ void main() { ''').create(); var test = await runTest(['test.dart']); - expect(test.stdout, - containsInOrder(['-1: test 1 [E]', '+1 -1: Some tests failed.'])); + expect( + test.stdout, + containsInOrder(['-1: test 1 [E]', '+1 -1: Some tests failed.']), + ); await test.shouldExit(1); }); test('supports tag selectors', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'tags': { - 'foo && bar': {'timeout': '0s'} - } - })) + 'dart_test.yaml', + jsonEncode({ + 'tags': { + 'foo && bar': {'timeout': '0s'}, + }, + }), + ) .create(); await d.file('test.dart', ''' @@ -122,23 +128,26 @@ void main() { ''').create(); var test = await runTest(['test.dart']); - expect(test.stdout, - containsInOrder(['+2 -1: test 3 [E]', '+2 -1: Some tests failed.'])); + expect( + test.stdout, + containsInOrder(['+2 -1: test 3 [E]', '+2 -1: Some tests failed.']), + ); await test.shouldExit(1); }); test('allows tag inheritance via add_tags', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'tags': { - 'foo': null, - 'bar': { - 'add_tags': ['foo'] - } - } - })) + 'dart_test.yaml', + jsonEncode({ + 'tags': { + 'foo': null, + 'bar': { + 'add_tags': ['foo'], + }, + }, + }), + ) .create(); await d.file('test.dart', ''' @@ -159,12 +168,13 @@ void main() { test('skips tests whose tags are marked as skip', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'tags': { - 'foo': {'skip': 'some reason'} - } - })) + 'dart_test.yaml', + jsonEncode({ + 'tags': { + 'foo': {'skip': 'some reason'}, + }, + }), + ) .create(); await d.file('test.dart', ''' @@ -179,7 +189,9 @@ void main() { var test = await runTest(['test.dart']); expect( - test.stdout, containsInOrder(['some reason', 'All tests skipped.'])); + test.stdout, + containsInOrder(['some reason', 'All tests skipped.']), + ); await test.shouldExit(0); }); }); @@ -202,7 +214,9 @@ void main() { var test = await runTest(['test.dart']); expect( - test.stdout, containsInOrder(['+0: zop', '+1: All tests passed!'])); + test.stdout, + containsInOrder(['+0: zop', '+1: All tests passed!']), + ); await test.shouldExit(0); }); @@ -222,8 +236,10 @@ void main() { ''').create(); var test = await runTest(['test.dart']); - expect(test.stdout, - containsInOrder(['+0: zip', '+1: zap', '+2: All tests passed!'])); + expect( + test.stdout, + containsInOrder(['+0: zip', '+1: zap', '+2: All tests passed!']), + ); await test.shouldExit(0); }); }); @@ -235,24 +251,30 @@ void main() { var test = await runTest([]); expect( - test.stderr, containsInOrder(['tags key must be a string', '^^'])); + test.stderr, + containsInOrder(['tags key must be a string', '^^']), + ); await test.shouldExit(exit_codes.data); }); test('rejects an invalid tag selector', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'tags': {'foo bar': null} - })) + 'dart_test.yaml', + jsonEncode({ + 'tags': {'foo bar': null}, + }), + ) .create(); var test = await runTest([]); expect( - test.stderr, - containsInOrder( - ['Invalid tags key: Expected end of input.', '^^^^^^^^^'])); + test.stderr, + containsInOrder([ + 'Invalid tags key: Expected end of input.', + '^^^^^^^^^', + ]), + ); await test.shouldExit(exit_codes.data); }); @@ -267,34 +289,40 @@ void main() { test('rejects an invalid tag configuration', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'tags': { - 'foo': {'timeout': '12p'} - } - })) + 'dart_test.yaml', + jsonEncode({ + 'tags': { + 'foo': {'timeout': '12p'}, + }, + }), + ) .create(); var test = await runTest([]); - expect(test.stderr, - containsInOrder(['Invalid timeout: expected unit', '^^^^'])); + expect( + test.stderr, + containsInOrder(['Invalid timeout: expected unit', '^^^^']), + ); await test.shouldExit(exit_codes.data); }); test('rejects runner configuration', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'tags': { - 'foo': {'filename': '*_blorp.dart'} - } - })) + 'dart_test.yaml', + jsonEncode({ + 'tags': { + 'foo': {'filename': '*_blorp.dart'}, + }, + }), + ) .create(); var test = await runTest([]); - expect(test.stderr, - containsInOrder(["filename isn't supported here.", '^^^^^^^^^^'])); + expect( + test.stderr, + containsInOrder(["filename isn't supported here.", '^^^^^^^^^^']), + ); await test.shouldExit(exit_codes.data); }); }); @@ -307,41 +335,48 @@ void main() { var test = await runTest(['test.dart']); expect( - test.stderr, containsInOrder(['add_tags must be a list', '^^^^'])); + test.stderr, + containsInOrder(['add_tags must be a list', '^^^^']), + ); await test.shouldExit(exit_codes.data); }); test('rejects an invalid tag type', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'add_tags': [12] - })) + 'dart_test.yaml', + jsonEncode({ + 'add_tags': [12], + }), + ) .create(); var test = await runTest(['test.dart']); expect( - test.stderr, containsInOrder(['Tag name must be a string', '^^'])); + test.stderr, + containsInOrder(['Tag name must be a string', '^^']), + ); await test.shouldExit(exit_codes.data); }); test('rejects an invalid tag name', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'add_tags': ['foo bar'] - })) + 'dart_test.yaml', + jsonEncode({ + 'add_tags': ['foo bar'], + }), + ) .create(); var test = await runTest(['test.dart']); expect( - test.stderr, - containsInOrder([ - 'Tag name must be an (optionally hyphenated) Dart identifier.', - '^^^^^^^^^' - ])); + test.stderr, + containsInOrder([ + 'Tag name must be an (optionally hyphenated) Dart identifier.', + '^^^^^^^^^', + ]), + ); await test.shouldExit(exit_codes.data); }); }); @@ -353,8 +388,10 @@ void main() { .create(); var test = await runTest(['test.dart']); - expect(test.stderr, - containsInOrder(['include_tags must be a string', '^^'])); + expect( + test.stderr, + containsInOrder(['include_tags must be a string', '^^']), + ); await test.shouldExit(exit_codes.data); }); @@ -365,9 +402,12 @@ void main() { var test = await runTest([]); expect( - test.stderr, - containsInOrder( - ['Invalid include_tags: Expected end of input.', '^^^^^^^^^'])); + test.stderr, + containsInOrder([ + 'Invalid include_tags: Expected end of input.', + '^^^^^^^^^', + ]), + ); await test.shouldExit(exit_codes.data); }); }); @@ -379,8 +419,10 @@ void main() { .create(); var test = await runTest(['test.dart']); - expect(test.stderr, - containsInOrder(['exclude_tags must be a string', '^^'])); + expect( + test.stderr, + containsInOrder(['exclude_tags must be a string', '^^']), + ); await test.shouldExit(exit_codes.data); }); @@ -391,9 +433,12 @@ void main() { var test = await runTest([]); expect( - test.stderr, - containsInOrder( - ['Invalid exclude_tags: Expected end of input.', '^^^^^^^^^'])); + test.stderr, + containsInOrder([ + 'Invalid exclude_tags: Expected end of input.', + '^^^^^^^^^', + ]), + ); await test.shouldExit(exit_codes.data); }); }); diff --git a/pkgs/test/test/runner/configuration/top_level_error_test.dart b/pkgs/test/test/runner/configuration/top_level_error_test.dart index 56a717cf0..721d629a4 100644 --- a/pkgs/test/test/runner/configuration/top_level_error_test.dart +++ b/pkgs/test/test/runner/configuration/top_level_error_test.dart @@ -22,58 +22,70 @@ void main() { .create(); var test = await runTest(['test.dart']); - expect(test.stderr, - containsInOrder(['fold_stack_frames must be a map', '^^^^^^'])); + expect( + test.stderr, + containsInOrder(['fold_stack_frames must be a map', '^^^^^^']), + ); await test.shouldExit(exit_codes.data); }); test('rejects multiple fold_stack_frames keys', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'fold_stack_frames': { - 'except': ['blah'], - 'only': ['blah'] - } - })) + 'dart_test.yaml', + jsonEncode({ + 'fold_stack_frames': { + 'except': ['blah'], + 'only': ['blah'], + }, + }), + ) .create(); var test = await runTest(['test.dart']); expect( - test.stderr, - containsInOrder( - ['Can only contain one of "only" or "except".', '^^^^^^'])); + test.stderr, + containsInOrder([ + 'Can only contain one of "only" or "except".', + '^^^^^^', + ]), + ); await test.shouldExit(exit_codes.data); }); test('rejects invalid fold_stack_frames keys', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'fold_stack_frames': {'invalid': 'blah'} - })) + 'dart_test.yaml', + jsonEncode({ + 'fold_stack_frames': {'invalid': 'blah'}, + }), + ) .create(); var test = await runTest(['test.dart']); - expect(test.stderr, - containsInOrder(['Must be "only" or "except".', '^^^^^^'])); + expect( + test.stderr, + containsInOrder(['Must be "only" or "except".', '^^^^^^']), + ); await test.shouldExit(exit_codes.data); }); test('rejects invalid fold_stack_frames values', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'fold_stack_frames': {'only': 'blah'} - })) + 'dart_test.yaml', + jsonEncode({ + 'fold_stack_frames': {'only': 'blah'}, + }), + ) .create(); var test = await runTest(['test.dart']); - expect(test.stderr, - containsInOrder(['Folded packages must be strings', '^^^^^^'])); + expect( + test.stderr, + containsInOrder(['Folded packages must be strings', '^^^^^^']), + ); await test.shouldExit(exit_codes.data); }); @@ -83,8 +95,10 @@ void main() { .create(); var test = await runTest(['test.dart']); - expect(test.stderr, - containsInOrder(['pause_after_load must be a boolean', '^^^^^^'])); + expect( + test.stderr, + containsInOrder(['pause_after_load must be a boolean', '^^^^^^']), + ); await test.shouldExit(exit_codes.data); }); @@ -94,8 +108,10 @@ void main() { .create(); var test = await runTest(['test.dart']); - expect(test.stderr, - containsInOrder(['verbose_trace must be a boolean', '^^^^^^'])); + expect( + test.stderr, + containsInOrder(['verbose_trace must be a boolean', '^^^^^^']), + ); await test.shouldExit(exit_codes.data); }); @@ -105,8 +121,10 @@ void main() { .create(); var test = await runTest(['test.dart']); - expect(test.stderr, - containsInOrder(['chain_stack_traces must be a boolean', '^^^^^^'])); + expect( + test.stderr, + containsInOrder(['chain_stack_traces must be a boolean', '^^^^^^']), + ); await test.shouldExit(exit_codes.data); }); @@ -114,8 +132,10 @@ void main() { await d.file('dart_test.yaml', jsonEncode({'retry': 'flup'})).create(); var test = await runTest(['test.dart']); - expect(test.stderr, - containsInOrder(['retry must be a non-negative int', '^^^^^^'])); + expect( + test.stderr, + containsInOrder(['retry must be a non-negative int', '^^^^^^']), + ); await test.shouldExit(exit_codes.data); }); @@ -123,8 +143,10 @@ void main() { await d.file('dart_test.yaml', jsonEncode({'retry': -1})).create(); var test = await runTest(['test.dart']); - expect(test.stderr, - containsInOrder(['retry must be a non-negative int', '^^'])); + expect( + test.stderr, + containsInOrder(['retry must be a non-negative int', '^^']), + ); await test.shouldExit(exit_codes.data); }); @@ -133,7 +155,9 @@ void main() { var test = await runTest(['test.dart']); expect( - test.stderr, containsInOrder(['js_trace must be a boolean', '^^^^^^'])); + test.stderr, + containsInOrder(['js_trace must be a boolean', '^^^^^^']), + ); await test.shouldExit(exit_codes.data); }); @@ -153,9 +177,9 @@ void main() { var test = await runTest(['test.dart']); expect( - test.stderr, - containsInOrder( - ['Unknown reporter "non-existent"', '^^^^^^^^^^^^^^'])); + test.stderr, + containsInOrder(['Unknown reporter "non-existent"', '^^^^^^^^^^^^^^']), + ); await test.shouldExit(exit_codes.data); }); }); @@ -168,39 +192,45 @@ void main() { var test = await runTest(['test.dart']); expect( - test.stderr, containsInOrder(['file_reporters must be a map', '^^'])); + test.stderr, + containsInOrder(['file_reporters must be a map', '^^']), + ); await test.shouldExit(exit_codes.data); }); test('rejects an invalid value type', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'file_reporters': {'json': 12} - })) + 'dart_test.yaml', + jsonEncode({ + 'file_reporters': {'json': 12}, + }), + ) .create(); var test = await runTest(['test.dart']); - expect(test.stderr, - containsInOrder(['file_reporters value must be a string', '^^'])); + expect( + test.stderr, + containsInOrder(['file_reporters value must be a string', '^^']), + ); await test.shouldExit(exit_codes.data); }); test('rejects an invalid name', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'file_reporters': {'non-existent': 'out'} - })) + 'dart_test.yaml', + jsonEncode({ + 'file_reporters': {'non-existent': 'out'}, + }), + ) .create(); var test = await runTest(['test.dart']); expect( - test.stderr, - containsInOrder( - ['Unknown reporter "non-existent"', '^^^^^^^^^^^^^^'])); + test.stderr, + containsInOrder(['Unknown reporter "non-existent"', '^^^^^^^^^^^^^^']), + ); await test.shouldExit(exit_codes.data); }); }); @@ -210,7 +240,9 @@ void main() { var test = await runTest(['test.dart']); expect( - test.stderr, containsInOrder(['concurrency must be an int', '^^^^^'])); + test.stderr, + containsInOrder(['concurrency must be an int', '^^^^^']), + ); await test.shouldExit(exit_codes.data); }); @@ -227,8 +259,10 @@ void main() { await d.file('dart_test.yaml', jsonEncode({'timeout': '12p'})).create(); var test = await runTest(['test.dart']); - expect(test.stderr, - containsInOrder(['Invalid timeout: expected unit', '^^^^^'])); + expect( + test.stderr, + containsInOrder(['Invalid timeout: expected unit', '^^^^^']), + ); await test.shouldExit(exit_codes.data); }); }); @@ -245,10 +279,11 @@ void main() { test('rejects an invalid member type', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'names': [12] - })) + 'dart_test.yaml', + jsonEncode({ + 'names': [12], + }), + ) .create(); var test = await runTest(['test.dart']); @@ -259,15 +294,18 @@ void main() { test('rejects an invalid RegExp', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'names': ['(foo'] - })) + 'dart_test.yaml', + jsonEncode({ + 'names': ['(foo'], + }), + ) .create(); var test = await runTest(['test.dart']); - expect(test.stderr, - containsInOrder(['Invalid name: Unterminated group', '^^^^^^'])); + expect( + test.stderr, + containsInOrder(['Invalid name: Unterminated group', '^^^^^^']), + ); await test.shouldExit(exit_codes.data); }); }); @@ -280,17 +318,20 @@ void main() { var test = await runTest(['test.dart']); expect( - test.stderr, containsInOrder(['plain_names must be a list', '^^^^'])); + test.stderr, + containsInOrder(['plain_names must be a list', '^^^^']), + ); await test.shouldExit(exit_codes.data); }); test('rejects an invalid member type', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'plain_names': [12] - })) + 'dart_test.yaml', + jsonEncode({ + 'plain_names': [12], + }), + ) .create(); var test = await runTest(['test.dart']); @@ -305,32 +346,38 @@ void main() { var test = await runTest(['test.dart']); expect( - test.stderr, containsInOrder(['platforms must be a list', '^^^^'])); + test.stderr, + containsInOrder(['platforms must be a list', '^^^^']), + ); await test.shouldExit(exit_codes.data); }); test('rejects an invalid member type', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'platforms': [12] - })) + 'dart_test.yaml', + jsonEncode({ + 'platforms': [12], + }), + ) .create(); var test = await runTest(['test.dart']); - expect(test.stderr, - containsInOrder(['Platform name must be a string', '^^'])); + expect( + test.stderr, + containsInOrder(['Platform name must be a string', '^^']), + ); await test.shouldExit(exit_codes.data); }); test('rejects an invalid member name', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'platforms': ['foo'] - })) + 'dart_test.yaml', + jsonEncode({ + 'platforms': ['foo'], + }), + ) .create(); await d.dir('test').create(); @@ -353,10 +400,11 @@ void main() { test('rejects an invalid member type', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'paths': [12] - })) + 'dart_test.yaml', + jsonEncode({ + 'paths': [12], + }), + ) .create(); var test = await runTest(['test.dart']); @@ -367,30 +415,36 @@ void main() { test('rejects an absolute path', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'paths': ['/foo'] - })) + 'dart_test.yaml', + jsonEncode({ + 'paths': ['/foo'], + }), + ) .create(); var test = await runTest(['test.dart']); expect( - test.stderr, containsInOrder(['Paths must be relative.', '^^^^^^'])); + test.stderr, + containsInOrder(['Paths must be relative.', '^^^^^^']), + ); await test.shouldExit(exit_codes.data); }); test('rejects an invalid URI', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'paths': [':invalid'] - })) + 'dart_test.yaml', + jsonEncode({ + 'paths': [':invalid'], + }), + ) .create(); var test = await runTest(['test.dart']); - expect(test.stderr, - containsInOrder(['Invalid path: Invalid empty scheme', '^^^^^^^^'])); + expect( + test.stderr, + containsInOrder(['Invalid path: Invalid empty scheme', '^^^^^^^^']), + ); await test.shouldExit(exit_codes.data); }); }); @@ -401,7 +455,9 @@ void main() { var test = await runTest(['test.dart']); expect( - test.stderr, containsInOrder(['filename must be a string.', '^^'])); + test.stderr, + containsInOrder(['filename must be a string.', '^^']), + ); await test.shouldExit(exit_codes.data); }); @@ -409,8 +465,10 @@ void main() { await d.file('dart_test.yaml', jsonEncode({'filename': '{foo'})).create(); var test = await runTest(['test.dart']); - expect(test.stderr, - containsInOrder(['Invalid filename: expected ",".', '^^^^^^'])); + expect( + test.stderr, + containsInOrder(['Invalid filename: expected ",".', '^^^^^^']), + ); await test.shouldExit(exit_codes.data); }); }); diff --git a/pkgs/test/test/runner/configuration/top_level_test.dart b/pkgs/test/test/runner/configuration/top_level_test.dart index 9c749a46e..815d01f6d 100644 --- a/pkgs/test/test/runner/configuration/top_level_test.dart +++ b/pkgs/test/test/runner/configuration/top_level_test.dart @@ -47,19 +47,23 @@ void main() { } ''').create(); - var test = - await runTest(['--configuration', 'special_test.yaml', 'test.dart']); + var test = await runTest([ + '--configuration', + 'special_test.yaml', + 'test.dart', + ]); expect(test.stdout, emitsThrough(contains('All tests skipped.'))); await test.shouldExit(0); }); - test('pauses the test runner after a suite loads with pause_after_load: true', - () async { - await d - .file('dart_test.yaml', jsonEncode({'pause_after_load': true})) - .create(); + test( + 'pauses the test runner after a suite loads with pause_after_load: true', + () async { + await d + .file('dart_test.yaml', jsonEncode({'pause_after_load': true})) + .create(); - await d.file('test.dart', ''' + await d.file('test.dart', ''' import 'package:test/test.dart'; void main() { @@ -69,9 +73,9 @@ void main() { } ''').create(); - var test = await runTest(['-p', 'chrome', 'test.dart']); - await expectLater(test.stdout, emitsThrough('loaded test!')); - await expectLater( + var test = await runTest(['-p', 'chrome', 'test.dart']); + await expectLater(test.stdout, emitsThrough('loaded test!')); + await expectLater( test.stdout, emitsInOrder([ '', @@ -79,28 +83,38 @@ void main() { The test runner is paused. Open the dev console in Chrome and set breakpoints. Once you're finished, return to this terminal and press Enter. - ''') - ])); - - var nextLineFired = false; - - unawaited(test.stdout.next.then(expectAsync1((line) { - expect(line, contains('+0: success')); - nextLineFired = true; - }))); - - // Wait a little bit to be sure that the tests don't start running without - // our input. - await Future.delayed(const Duration(seconds: 2)); - expect(nextLineFired, isFalse); - - test.stdin.writeln(); - await expectLater( - test.stdout, emitsThrough(contains('+1: All tests passed!'))); - await test.shouldExit(0); - }, tags: 'chrome', onPlatform: const { - 'windows': Skip('https://github.com/dart-lang/test/issues/1613') - }); + '''), + ]), + ); + + var nextLineFired = false; + + unawaited( + test.stdout.next.then( + expectAsync1((line) { + expect(line, contains('+0: success')); + nextLineFired = true; + }), + ), + ); + + // Wait a little bit to be sure that the tests don't start running without + // our input. + await Future.delayed(const Duration(seconds: 2)); + expect(nextLineFired, isFalse); + + test.stdin.writeln(); + await expectLater( + test.stdout, + emitsThrough(contains('+1: All tests passed!')), + ); + await test.shouldExit(0); + }, + tags: 'chrome', + onPlatform: const { + 'windows': Skip('https://github.com/dart-lang/test/issues/1613'), + }, + ); test('runs skipped tests with run_skipped: true', () async { await d.file('dart_test.yaml', jsonEncode({'run_skipped': true})).create(); @@ -137,13 +151,14 @@ void main() { await test.shouldExit(1); }); - test('disables stack trace chaining with chain_stack_traces: false', - () async { - await d - .file('dart_test.yaml', jsonEncode({'chain_stack_traces': false})) - .create(); + test( + 'disables stack trace chaining with chain_stack_traces: false', + () async { + await d + .file('dart_test.yaml', jsonEncode({'chain_stack_traces': false})) + .create(); - await d.file('test.dart', ''' + await d.file('test.dart', ''' import 'dart:async'; import 'package:test/test.dart'; @@ -157,23 +172,26 @@ void main() { } ''').create(); - var test = await runTest(['test.dart']); - expect( + var test = await runTest(['test.dart']); + expect( test.stdout, containsInOrder([ '+0: failure', '+0 -1: failure [E]', 'oh no', 'test.dart 9:15 main.', - ])); - await test.shouldExit(1); - }); + ]), + ); + await test.shouldExit(1); + }, + ); - test("doesn't dartify stack traces for JS-compiled tests with js_trace: true", - () async { - await d.file('dart_test.yaml', jsonEncode({'js_trace': true})).create(); + test( + "doesn't dartify stack traces for JS-compiled tests with js_trace: true", + () async { + await d.file('dart_test.yaml', jsonEncode({'js_trace': true})).create(); - await d.file('test.dart', ''' + await d.file('test.dart', ''' import 'package:test/test.dart'; void main() { @@ -181,13 +199,20 @@ void main() { } ''').create(); - var test = await runTest(['-p', 'chrome', '--verbose-trace', 'test.dart']); - expect(test.stdoutStream(), neverEmits(endsWith(' main.'))); - expect(test.stdoutStream(), neverEmits(contains('package:test'))); - expect(test.stdoutStream(), neverEmits(contains('dart:async/zone.dart'))); - expect(test.stdout, emitsThrough(contains('-1: Some tests failed.'))); - await test.shouldExit(1); - }, tags: 'chrome'); + var test = await runTest([ + '-p', + 'chrome', + '--verbose-trace', + 'test.dart', + ]); + expect(test.stdoutStream(), neverEmits(endsWith(' main.'))); + expect(test.stdoutStream(), neverEmits(contains('package:test'))); + expect(test.stdoutStream(), neverEmits(contains('dart:async/zone.dart'))); + expect(test.stdout, emitsThrough(contains('-1: Some tests failed.'))); + await test.shouldExit(1); + }, + tags: 'chrome', + ); test('retries tests with retry: 1', () async { await d.file('dart_test.yaml', jsonEncode({'retry': 1})).create(); @@ -280,10 +305,12 @@ void main() { var test = await runTest(['test.dart']); expect( - test.stderr, - emits( - "Warning: this package doesn't support running tests on the Dart " - 'VM.')); + test.stderr, + emits( + "Warning: this package doesn't support running tests on the Dart " + 'VM.', + ), + ); expect(test.stdout, emitsThrough(contains('No tests ran.'))); await test.shouldExit(79); }); @@ -301,18 +328,22 @@ void main() { var test = await runTest(['test.dart']); expect( - test.stderr, - emits("Warning: this package doesn't support running tests on " - '${currentOS.name}.')); + test.stderr, + emits( + "Warning: this package doesn't support running tests on " + '${currentOS.name}.', + ), + ); expect(test.stdout, emitsThrough(contains('No tests ran.'))); await test.shouldExit(79); }); - test('warns about browsers in general when no browsers are supported', - () async { - await d.file('dart_test.yaml', jsonEncode({'test_on': 'vm'})).create(); + test( + 'warns about browsers in general when no browsers are supported', + () async { + await d.file('dart_test.yaml', jsonEncode({'test_on': 'vm'})).create(); - await d.file('test.dart', ''' + await d.file('test.dart', ''' import 'package:test/test.dart'; void main() { @@ -320,17 +351,19 @@ void main() { } ''').create(); - var test = await runTest(['-p', 'chrome', 'test.dart']); - expect( + var test = await runTest(['-p', 'chrome', 'test.dart']); + expect( test.stderr, emits( - "Warning: this package doesn't support running tests on browsers.")); - expect(test.stdout, emitsThrough(contains('No tests ran.'))); - await test.shouldExit(79); - }); - - test( - 'warns about specific browsers when specific browsers are ' + "Warning: this package doesn't support running tests on browsers.", + ), + ); + expect(test.stdout, emitsThrough(contains('No tests ran.'))); + await test.shouldExit(79); + }, + ); + + test('warns about specific browsers when specific browsers are ' 'supported', () async { await d .file('dart_test.yaml', jsonEncode({'test_on': 'safari'})) @@ -346,9 +379,12 @@ void main() { var test = await runTest(['-p', 'chrome,firefox', 'test.dart']); expect( - test.stderr, - emits("Warning: this package doesn't support running tests on Chrome " - 'or Firefox.')); + test.stderr, + emits( + "Warning: this package doesn't support running tests on Chrome " + 'or Firefox.', + ), + ); expect(test.stdout, emitsThrough(contains('No tests ran.'))); await test.shouldExit(79); }); @@ -403,19 +439,23 @@ void main() { var test = await runTest(['test.dart']); expect( - test.stdout, - containsInOrder( - ['Test timed out after 0 seconds.', '-1: Some tests failed.'])); + test.stdout, + containsInOrder([ + 'Test timed out after 0 seconds.', + '-1: Some tests failed.', + ]), + ); await test.shouldExit(1); }); test('runs on the specified platforms', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'platforms': ['vm', 'chrome'] - })) + 'dart_test.yaml', + jsonEncode({ + 'platforms': ['vm', 'chrome'], + }), + ) .create(); await d.file('test.dart', ''' @@ -427,8 +467,10 @@ void main() { ''').create(); var test = await runTest(['test.dart']); - expect(test.stdout, - containsInOrder(['[VM, Kernel] success', '[Chrome, Dart2Js] success'])); + expect( + test.stdout, + containsInOrder(['[VM, Kernel] success', '[Chrome, Dart2Js] success']), + ); await test.shouldExit(0); }, tags: 'chrome'); @@ -453,10 +495,11 @@ void main() { test('uses the specified regexp names', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'names': ['z[ia]p', 'a'] - })) + 'dart_test.yaml', + jsonEncode({ + 'names': ['z[ia]p', 'a'], + }), + ) .create(); await d.file('test.dart', ''' @@ -477,10 +520,11 @@ void main() { test('uses the specified plain names', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'names': ['z', 'a'] - })) + 'dart_test.yaml', + jsonEncode({ + 'names': ['z', 'a'], + }), + ) .create(); await d.file('test.dart', ''' @@ -501,10 +545,11 @@ void main() { test('uses the specified paths', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'paths': ['zip', 'zap'] - })) + 'dart_test.yaml', + jsonEncode({ + 'paths': ['zip', 'zap'], + }), + ) .create(); await d.dir('zip', [ @@ -514,7 +559,7 @@ void main() { void main() { test("success", () {}); } - ''') + '''), ]).create(); await d.dir('zap', [ @@ -524,7 +569,7 @@ void main() { void main() { test("success", () {}); } - ''') + '''), ]).create(); await d.dir('zop', [ @@ -534,7 +579,7 @@ void main() { void main() { test("failure", () => throw "oh no"); } - ''') + '''), ]).create(); var test = await runTest([]); @@ -568,7 +613,7 @@ void main() { void main() { test("failure", () => throw "oh no"); } - ''') + '''), ]).create(); var test = await runTest([]); diff --git a/pkgs/test/test/runner/coverage_test.dart b/pkgs/test/test/runner/coverage_test.dart index a49124ba8..e52255924 100644 --- a/pkgs/test/test/runner/coverage_test.dart +++ b/pkgs/test/test/runner/coverage_test.dart @@ -42,8 +42,9 @@ void main() { } ''').create(); - coverageDirectory = - await Directory.systemTemp.createTemp('test_coverage'); + coverageDirectory = await Directory.systemTemp.createTemp( + 'test_coverage', + ); }); tearDown(() async { @@ -51,23 +52,31 @@ void main() { }); test('gathers coverage for VM tests', () async { - var test = - await runTest(['--coverage', coverageDirectory.path, 'test.dart']); + var test = await runTest([ + '--coverage', + coverageDirectory.path, + 'test.dart', + ]); await validateCoverage(test, 'test.dart.vm.json'); }); test('gathers coverage for Chrome tests', () async { - var test = await runTest( - ['--coverage', coverageDirectory.path, 'test.dart', '-p', 'chrome']); + var test = await runTest([ + '--coverage', + coverageDirectory.path, + 'test.dart', + '-p', + 'chrome', + ]); await validateCoverage(test, 'test.dart.chrome.json'); }); test( - 'gathers coverage for Chrome tests when JS files contain unicode characters', - () async { - final sourceMapFileContent = - '{"version":3,"file":"","sources":[],"names":[],"mappings":""}'; - final jsContent = ''' + 'gathers coverage for Chrome tests when JS files contain unicode characters', + () async { + final sourceMapFileContent = + '{"version":3,"file":"","sources":[],"names":[],"mappings":""}'; + final jsContent = ''' (function() { '© ' window.foo = function foo() { @@ -78,10 +87,10 @@ void main() { '© ': '' }); '''; - await d.file('file_with_unicode.js', jsContent).create(); - await d.file('file_with_unicode.js.map', sourceMapFileContent).create(); + await d.file('file_with_unicode.js', jsContent).create(); + await d.file('file_with_unicode.js.map', sourceMapFileContent).create(); - await d.file('js_with_unicode_test.dart', ''' + await d.file('js_with_unicode_test.dart', ''' import 'dart:async'; import 'dart:js_interop'; import 'dart:js_interop_unsafe'; @@ -111,27 +120,33 @@ void main() { } ''').create(); - final jsBytes = utf8.encode(jsContent); - final jsLatin1 = latin1.decode(jsBytes); - final jsUtf8 = utf8.decode(jsBytes); - expect(jsLatin1, isNot(jsUtf8), - reason: 'test setup: should have decoded differently'); - - const functionPattern = 'function foo'; - expect([jsLatin1, jsUtf8], everyElement(contains(functionPattern))); - expect(jsLatin1.indexOf(functionPattern), + final jsBytes = utf8.encode(jsContent); + final jsLatin1 = latin1.decode(jsBytes); + final jsUtf8 = utf8.decode(jsBytes); + expect( + jsLatin1, + isNot(jsUtf8), + reason: 'test setup: should have decoded differently', + ); + + const functionPattern = 'function foo'; + expect([jsLatin1, jsUtf8], everyElement(contains(functionPattern))); + expect( + jsLatin1.indexOf(functionPattern), isNot(jsUtf8.indexOf(functionPattern)), reason: - 'test setup: decoding should have shifted the position of the function'); - - var test = await runTest([ - '--coverage', - coverageDirectory.path, - 'js_with_unicode_test.dart', - '-p', - 'chrome' - ]); - await validateCoverage(test, 'js_with_unicode_test.dart.chrome.json'); - }); + 'test setup: decoding should have shifted the position of the function', + ); + + var test = await runTest([ + '--coverage', + coverageDirectory.path, + 'js_with_unicode_test.dart', + '-p', + 'chrome', + ]); + await validateCoverage(test, 'js_with_unicode_test.dart.chrome.json'); + }, + ); }); } diff --git a/pkgs/test/test/runner/engine_test.dart b/pkgs/test/test/runner/engine_test.dart index 6e8bf3deb..7a0ec344d 100644 --- a/pkgs/test/test/runner/engine_test.dart +++ b/pkgs/test/test/runner/engine_test.dart @@ -19,17 +19,18 @@ void main() { var tests = declare(() { for (var i = 0; i < 4; i++) { test( - 'test ${i + 1}', - expectAsync0(() { - expect(testsRun, equals(i)); - testsRun++; - }, max: 1)); + 'test ${i + 1}', + expectAsync0(() { + expect(testsRun, equals(i)); + testsRun++; + }, max: 1), + ); } }); var engine = Engine.withSuites([ runnerSuite(tests.take(2).asRootGroup()), - runnerSuite(tests.skip(2).asRootGroup()) + runnerSuite(tests.skip(2).asRootGroup()), ]); await engine.run(); @@ -41,20 +42,22 @@ void main() { var tests = declare(() { for (var i = 0; i < 4; i++) { test( - 'test ${i + 1}', - expectAsync0(() { - expect(testsRun, equals(i)); - testsRun++; - }, max: 1)); + 'test ${i + 1}', + expectAsync0(() { + expect(testsRun, equals(i)); + testsRun++; + }, max: 1), + ); } }); var engine = Engine(); expect( - engine.run().then((_) { - expect(testsRun, equals(4)); - }), - completes); + engine.run().then((_) { + expect(testsRun, equals(4)); + }), + completes, + ); engine.suiteSink.add(runnerSuite(tests.asRootGroup())); engine.suiteSink.close(); @@ -75,8 +78,7 @@ void main() { completer.complete(); }); - test( - 'emits each test before it starts running and after the previous test ' + test('emits each test before it starts running and after the previous test ' 'finished', () { var testsRun = 0; var engine = declareEngine(() { @@ -85,15 +87,23 @@ void main() { } }); - engine.onTestStarted.listen(expectAsync1((liveTest) { - // [testsRun] should be one less than the test currently running. - expect(liveTest.test.name, equals('test ${testsRun + 1}')); - - // [Engine.onTestStarted] is guaranteed to fire before the first - // [LiveTest.onStateChange]. - expect(liveTest.onStateChange.first, - completion(equals(const State(Status.running, Result.success)))); - }, count: 3, max: 3)); + engine.onTestStarted.listen( + expectAsync1( + (liveTest) { + // [testsRun] should be one less than the test currently running. + expect(liveTest.test.name, equals('test ${testsRun + 1}')); + + // [Engine.onTestStarted] is guaranteed to fire before the first + // [LiveTest.onStateChange]. + expect( + liveTest.onStateChange.first, + completion(equals(const State(Status.running, Result.success))), + ); + }, + count: 3, + max: 3, + ), + ); return engine.run(); }); @@ -130,18 +140,20 @@ void main() { expect(engine.run(), completion(isFalse)); }); - test('.run() does not run more tests after failure for stopOnFirstFailure', - () async { - var secondTestRan = false; - var engine = declareEngine(() { - test('failure', () => throw 'oh no'); - test('subsequent', () { - secondTestRan = true; - }); - }, stopOnFirstFailure: true); - await expectLater(engine.run(), completion(isFalse)); - expect(secondTestRan, false); - }); + test( + '.run() does not run more tests after failure for stopOnFirstFailure', + () async { + var secondTestRan = false; + var engine = declareEngine(() { + test('failure', () => throw 'oh no'); + test('subsequent', () { + secondTestRan = true; + }); + }, stopOnFirstFailure: true); + await expectLater(engine.run(), completion(isFalse)); + expect(secondTestRan, false); + }, + ); test('.run() may not be called more than once', () { var engine = Engine.withSuites([]); @@ -210,24 +222,37 @@ void main() { var engine = Engine.withSuites([runnerSuite(tests.asRootGroup())]); - engine.onTestStarted.listen(expectAsync1((liveTest) { - expect(liveTest, same(engine.liveTests.single)); - expect(liveTest.test.name, equals(tests.single.name)); - - var i = 0; - liveTest.onStateChange.listen(expectAsync1((state) { - if (i == 0) { - expect(state, equals(const State(Status.running, Result.success))); - } else if (i == 1) { - expect(state, equals(const State(Status.running, Result.skipped))); - } else if (i == 2) { - expect(state, equals(const State(Status.complete, Result.skipped))); - } - i++; - }, count: 3)); - - expect(liveTest.onComplete, completes); - })); + engine.onTestStarted.listen( + expectAsync1((liveTest) { + expect(liveTest, same(engine.liveTests.single)); + expect(liveTest.test.name, equals(tests.single.name)); + + var i = 0; + liveTest.onStateChange.listen( + expectAsync1((state) { + if (i == 0) { + expect( + state, + equals(const State(Status.running, Result.success)), + ); + } else if (i == 1) { + expect( + state, + equals(const State(Status.running, Result.skipped)), + ); + } else if (i == 2) { + expect( + state, + equals(const State(Status.complete, Result.skipped)), + ); + } + i++; + }, count: 3), + ); + + expect(liveTest.onComplete, completes); + }), + ); return engine.run(); }); @@ -279,24 +304,37 @@ void main() { var engine = Engine.withSuites([runnerSuite(entries.asRootGroup())]); - engine.onTestStarted.listen(expectAsync1((liveTest) { - expect(liveTest, same(engine.liveTests.single)); - expect(liveTest.test.name, equals('group test')); - - var i = 0; - liveTest.onStateChange.listen(expectAsync1((state) { - if (i == 0) { - expect(state, equals(const State(Status.running, Result.success))); - } else if (i == 1) { - expect(state, equals(const State(Status.running, Result.skipped))); - } else if (i == 2) { - expect(state, equals(const State(Status.complete, Result.skipped))); - } - i++; - }, count: 3)); - - expect(liveTest.onComplete, completes); - })); + engine.onTestStarted.listen( + expectAsync1((liveTest) { + expect(liveTest, same(engine.liveTests.single)); + expect(liveTest.test.name, equals('group test')); + + var i = 0; + liveTest.onStateChange.listen( + expectAsync1((state) { + if (i == 0) { + expect( + state, + equals(const State(Status.running, Result.success)), + ); + } else if (i == 1) { + expect( + state, + equals(const State(Status.running, Result.skipped)), + ); + } else if (i == 2) { + expect( + state, + equals(const State(Status.complete, Result.skipped)), + ); + } + i++; + }, count: 3), + ); + + expect(liveTest.onComplete, completes); + }), + ); return engine.run(); }); @@ -311,8 +349,9 @@ void main() { var maxTestConcurrency = 0; var testCount = concurrency * 2; - Future updateAndCheckConcurrency( - {bool isLoadSuite = false}) async { + Future updateAndCheckConcurrency({ + bool isLoadSuite = false, + }) async { if (isLoadSuite) { testsLoaded++; maxLoadConcurrency = max(maxLoadConcurrency, testsLoaded); diff --git a/pkgs/test/test/runner/expanded_reporter_test.dart b/pkgs/test/test/runner/expanded_reporter_test.dart index 1c116869a..896de0d25 100644 --- a/pkgs/test/test/runner/expanded_reporter_test.dart +++ b/pkgs/test/test/runner/expanded_reporter_test.dart @@ -24,22 +24,27 @@ void main() { }); test('runs several successful tests and reports when each completes', () { - return _expectReport(''' + return _expectReport( + ''' test('success 1', () {}); test('success 2', () {}); - test('success 3', () {});''', ''' + test('success 3', () {});''', + ''' +0: loading test.dart +0: success 1 +1: success 2 +2: success 3 - +3: All tests passed!'''); + +3: All tests passed!''', + ); }); test('runs several failing tests and reports when each fails', () { - return _expectReport(''' + return _expectReport( + ''' test('failure 1', () => throw TestFailure('oh no')); test('failure 2', () => throw TestFailure('oh no')); - test('failure 3', () => throw TestFailure('oh no'));''', ''' + test('failure 3', () => throw TestFailure('oh no'));''', + ''' +0: loading test.dart +0: failure 1 +0 -1: failure 1 [E] @@ -56,7 +61,8 @@ void main() { oh no test.dart 8:33 main. - +0 -3: Some tests failed.'''); + +0 -3: Some tests failed.''', + ); }); test('includes the full stack trace with --verbose-trace', () async { @@ -76,11 +82,13 @@ void main() { }); test('runs failing tests along with successful tests', () { - return _expectReport(''' + return _expectReport( + ''' test('failure 1', () => throw TestFailure('oh no')); test('success 1', () {}); test('failure 2', () => throw TestFailure('oh no')); - test('success 2', () {});''', ''' + test('success 2', () {});''', + ''' +0: loading test.dart +0: failure 1 +0 -1: failure 1 [E] @@ -94,22 +102,27 @@ void main() { test.dart 8:33 main. +1 -2: success 2 - +2 -2: Some tests failed.'''); + +2 -2: Some tests failed.''', + ); }); test('always prints the full test name', () { - return _expectReport(''' + return _expectReport( + ''' test( 'really gosh dang long test name. Even longer than that. No, yet ' 'longer. A little more... okay, that should do it.', - () {});''', ''' + () {});''', + ''' +0: loading test.dart +0: really gosh dang long test name. Even longer than that. No, yet longer. A little more... okay, that should do it. - +1: All tests passed!'''); + +1: All tests passed!''', + ); }); test('gracefully handles multiple test failures in a row', () { - return _expectReport(''' + return _expectReport( + ''' // This completer ensures that the test isolate isn't killed until all // errors have been thrown. var completer = Completer(); @@ -119,7 +132,8 @@ void main() { Future.microtask(() => throw 'third error'); Future.microtask(completer.complete); }); - test('wait', () => completer.future);''', ''' + test('wait', () => completer.future);''', + ''' +0: loading test.dart +0: failures +0 -1: failures [E] @@ -142,29 +156,34 @@ void main() { test.dart 12:18 main. +0 -1: wait - +1 -1: Some tests failed.'''); + +1 -1: Some tests failed.''', + ); }); group('print:', () { test('handles multiple prints', () { - return _expectReport(''' + return _expectReport( + ''' test('test', () { print("one"); print("two"); print("three"); print("four"); - });''', ''' + });''', + ''' +0: loading test.dart +0: test one two three four - +1: All tests passed!'''); + +1: All tests passed!''', + ); }); test('handles a print after the test completes', () { - return _expectReport(''' + return _expectReport( + ''' // This completer ensures that the test isolate isn't killed until all // prints have happened. var testDone = Completer(); @@ -182,7 +201,8 @@ void main() { test('wait', () { waitStarted.complete(); return testDone.future; - });''', ''' + });''', + ''' +0: loading test.dart +0: test +1: wait @@ -191,11 +211,13 @@ void main() { two three four - +2: All tests passed!'''); + +2: All tests passed!''', + ); }); test('interleaves prints and errors', () { - return _expectReport(''' + return _expectReport( + ''' // This completer ensures that the test isolate isn't killed until all // prints have happened. var completer = Completer(); @@ -217,7 +239,8 @@ void main() { throw "first error"; }); - test('wait', () => completer.future);''', ''' + test('wait', () => completer.future);''', + ''' +0: loading test.dart +0: test one @@ -237,59 +260,71 @@ void main() { five six +0 -1: wait - +1 -1: Some tests failed.'''); + +1 -1: Some tests failed.''', + ); }); }); group('skip:', () { test('displays skipped tests separately', () { - return _expectReport(''' + return _expectReport( + ''' test('skip 1', () {}, skip: true); test('skip 2', () {}, skip: true); - test('skip 3', () {}, skip: true);''', ''' + test('skip 3', () {}, skip: true);''', + ''' +0: loading test.dart +0: skip 1 +0 ~1: skip 2 +0 ~2: skip 3 - +0 ~3: All tests skipped.'''); + +0 ~3: All tests skipped.''', + ); }); test('displays a skipped group', () { - return _expectReport(''' + return _expectReport( + ''' group('skip', () { test('test 1', () {}); test('test 2', () {}); test('test 3', () {}); - }, skip: true);''', ''' + }, skip: true);''', + ''' +0: loading test.dart +0: skip test 1 +0 ~1: skip test 2 +0 ~2: skip test 3 - +0 ~3: All tests skipped.'''); + +0 ~3: All tests skipped.''', + ); }); test('runs skipped tests along with successful tests', () { - return _expectReport(''' + return _expectReport( + ''' test('skip 1', () {}, skip: true); test('success 1', () {}); test('skip 2', () {}, skip: true); - test('success 2', () {});''', ''' + test('success 2', () {});''', + ''' +0: loading test.dart +0: skip 1 +0 ~1: success 1 +1 ~1: skip 2 +1 ~2: success 2 - +2 ~2: All tests passed!'''); + +2 ~2: All tests passed!''', + ); }); test('runs skipped tests along with successful and failing tests', () { - return _expectReport(''' + return _expectReport( + ''' test('failure 1', () => throw TestFailure('oh no')); test('skip 1', () {}, skip: true); test('success 1', () {}); test('failure 2', () => throw TestFailure('oh no')); test('skip 2', () {}, skip: true); - test('success 2', () {});''', ''' + test('success 2', () {});''', + ''' +0: loading test.dart +0: failure 1 +0 -1: failure 1 [E] @@ -305,35 +340,44 @@ void main() { +1 ~1 -2: skip 2 +1 ~2 -2: success 2 - +2 ~2 -2: Some tests failed.'''); + +2 ~2 -2: Some tests failed.''', + ); }); test('displays the skip reason if available', () { - return _expectReport(''' + return _expectReport( + ''' test('skip 1', () {}, skip: 'some reason'); - test('skip 2', () {}, skip: 'or another');''', ''' + test('skip 2', () {}, skip: 'or another');''', + ''' +0: loading test.dart +0: skip 1 Skip: some reason +0 ~1: skip 2 Skip: or another - +0 ~2: All tests skipped.'''); + +0 ~2: All tests skipped.''', + ); }); test('runs skipped tests with --run-skipped', () { - return _expectReport(''' + return _expectReport( + ''' test('skip 1', () {}, skip: 'some reason'); - test('skip 2', () {}, skip: 'or another');''', ''' + test('skip 2', () {}, skip: 'or another');''', + ''' +0: loading test.dart +0: skip 1 +1: skip 2 - +2: All tests passed!''', args: ['--run-skipped']); + +2: All tests passed!''', + args: ['--run-skipped'], + ); }); }); test('Directs users to enable stack trace chaining if disabled', () async { await _expectReport( - '''test('failure 1', () => throw TestFailure('oh no'));''', ''' + '''test('failure 1', () => throw TestFailure('oh no'));''', + ''' +0: loading test.dart +0: failure 1 +0 -1: failure 1 [E] @@ -344,12 +388,17 @@ void main() { Consider enabling the flag chain-stack-traces to receive more detailed exceptions. For example, 'dart test --chain-stack-traces'.''', - chainStackTraces: false); + chainStackTraces: false, + ); }); } -Future _expectReport(String tests, String expected, - {List args = const [], bool chainStackTraces = true}) async { +Future _expectReport( + String tests, + String expected, { + List args = const [], + bool chainStackTraces = true, +}) async { await d.file('test.dart', ''' import 'dart:async'; @@ -370,17 +419,22 @@ $tests var stdoutLines = await test.stdoutStream().toList(); // Remove excess trailing whitespace and trim off timestamps. - var actual = stdoutLines.map((line) { - if (line.startsWith(' ') || line.isEmpty) return line.trimRight(); - return line.trim().replaceFirst(RegExp('^[0-9]{2}:[0-9]{2} '), ''); - }).join('\n'); + var actual = stdoutLines + .map((line) { + if (line.startsWith(' ') || line.isEmpty) return line.trimRight(); + return line.trim().replaceFirst(RegExp('^[0-9]{2}:[0-9]{2} '), ''); + }) + .join('\n'); // Un-indent the expected string. var indentation = expected.indexOf(RegExp('[^ ]')); - expected = expected.split('\n').map((line) { - if (line.isEmpty) return line; - return line.substring(indentation); - }).join('\n'); + expected = expected + .split('\n') + .map((line) { + if (line.isEmpty) return line; + return line.substring(indentation); + }) + .join('\n'); expect(actual, equals(expected)); } diff --git a/pkgs/test/test/runner/failures_only_reporter_test.dart b/pkgs/test/test/runner/failures_only_reporter_test.dart index 3e2690abc..2b56af47d 100644 --- a/pkgs/test/test/runner/failures_only_reporter_test.dart +++ b/pkgs/test/test/runner/failures_only_reporter_test.dart @@ -24,18 +24,23 @@ void main() { }); test('runs several successful tests and reports only at the end', () { - return _expectReport(''' + return _expectReport( + ''' test('success 1', () {}); test('success 2', () {}); - test('success 3', () {});''', ''' - +3: All tests passed!'''); + test('success 3', () {});''', + ''' + +3: All tests passed!''', + ); }); test('runs several failing tests and reports when each fails', () { - return _expectReport(''' + return _expectReport( + ''' test('failure 1', () => throw TestFailure('oh no')); test('failure 2', () => throw TestFailure('oh no')); - test('failure 3', () => throw TestFailure('oh no'));''', ''' + test('failure 3', () => throw TestFailure('oh no'));''', + ''' +0 -1: failure 1 [E] oh no test.dart 6:33 main. @@ -48,7 +53,8 @@ void main() { oh no test.dart 8:33 main. - +0 -3: Some tests failed.'''); + +0 -3: Some tests failed.''', + ); }); test('includes the full stack trace with --verbose-trace', () async { @@ -62,18 +68,22 @@ void main() { } ''').create(); - var test = await runTest(['--verbose-trace', 'test.dart'], - reporter: 'failures-only'); + var test = await runTest([ + '--verbose-trace', + 'test.dart', + ], reporter: 'failures-only'); expect(test.stdout, emitsThrough(contains('dart:async'))); await test.shouldExit(1); }); test('reports only failing tests amid successful tests', () { - return _expectReport(''' + return _expectReport( + ''' test('failure 1', () => throw TestFailure('oh no')); test('success 1', () {}); test('failure 2', () => throw TestFailure('oh no')); - test('success 2', () {});''', ''' + test('success 2', () {});''', + ''' +0 -1: failure 1 [E] oh no test.dart 6:33 main. @@ -82,28 +92,33 @@ void main() { oh no test.dart 8:33 main. - +2 -2: Some tests failed.'''); + +2 -2: Some tests failed.''', + ); }); group('print:', () { test('handles multiple prints', () { - return _expectReport(''' + return _expectReport( + ''' test('test', () { print("one"); print("two"); print("three"); print("four"); - });''', ''' + });''', + ''' +0: test one two three four - +1: All tests passed!'''); + +1: All tests passed!''', + ); }); test('handles a print after the test completes', () { - return _expectReport(''' + return _expectReport( + ''' // This completer ensures that the test isolate isn't killed until all // prints have happened. var testDone = Completer(); @@ -121,17 +136,20 @@ void main() { test('wait', () { waitStarted.complete(); return testDone.future; - });''', ''' + });''', + ''' +1: test one two three four - +2: All tests passed!'''); + +2: All tests passed!''', + ); }); test('interleaves prints and errors', () { - return _expectReport(''' + return _expectReport( + ''' // This completer ensures that the test isolate isn't killed until all // prints have happened. var completer = Completer(); @@ -153,7 +171,8 @@ void main() { throw "first error"; }); - test('wait', () => completer.future);''', ''' + test('wait', () => completer.future);''', + ''' +0: test one two @@ -171,27 +190,33 @@ void main() { five six - +1 -1: Some tests failed.'''); + +1 -1: Some tests failed.''', + ); }); }); group('skip:', () { test('does not emit for skips', () { - return _expectReport(''' + return _expectReport( + ''' test('skip 1', () {}, skip: true); test('skip 2', () {}, skip: true); - test('skip 3', () {}, skip: true);''', ''' - +0 ~3: All tests skipped.'''); + test('skip 3', () {}, skip: true);''', + ''' + +0 ~3: All tests skipped.''', + ); }); test('runs skipped tests along with successful and failing tests', () { - return _expectReport(''' + return _expectReport( + ''' test('failure 1', () => throw TestFailure('oh no')); test('skip 1', () {}, skip: true); test('success 1', () {}); test('failure 2', () => throw TestFailure('oh no')); test('skip 2', () {}, skip: true); - test('success 2', () {});''', ''' + test('success 2', () {});''', + ''' +0 -1: failure 1 [E] oh no test.dart 6:35 main. @@ -200,13 +225,15 @@ void main() { oh no test.dart 9:35 main. - +2 ~2 -2: Some tests failed.'''); + +2 ~2 -2: Some tests failed.''', + ); }); }); test('Directs users to enable stack trace chaining if disabled', () async { await _expectReport( - '''test('failure 1', () => throw TestFailure('oh no'));''', ''' + '''test('failure 1', () => throw TestFailure('oh no'));''', + ''' +0 -1: failure 1 [E] oh no test.dart 6:25 main. @@ -215,12 +242,17 @@ void main() { Consider enabling the flag chain-stack-traces to receive more detailed exceptions. For example, 'dart test --chain-stack-traces'.''', - chainStackTraces: false); + chainStackTraces: false, + ); }); } -Future _expectReport(String tests, String expected, - {List args = const [], bool chainStackTraces = true}) async { +Future _expectReport( + String tests, + String expected, { + List args = const [], + bool chainStackTraces = true, +}) async { await d.file('test.dart', ''' import 'dart:async'; @@ -241,17 +273,22 @@ $tests var stdoutLines = await test.stdoutStream().toList(); // Remove excess trailing whitespace. - var actual = stdoutLines.map((line) { - if (line.startsWith(' ') || line.isEmpty) return line.trimRight(); - return line.trim(); - }).join('\n'); + var actual = stdoutLines + .map((line) { + if (line.startsWith(' ') || line.isEmpty) return line.trimRight(); + return line.trim(); + }) + .join('\n'); // Un-indent the expected string. var indentation = expected.indexOf(RegExp('[^ ]')); - expected = expected.split('\n').map((line) { - if (line.isEmpty) return line; - return line.substring(indentation); - }).join('\n'); + expected = expected + .split('\n') + .map((line) { + if (line.isEmpty) return line; + return line.substring(indentation); + }) + .join('\n'); expect(actual, equals(expected)); } diff --git a/pkgs/test/test/runner/github_reporter_test.dart b/pkgs/test/test/runner/github_reporter_test.dart index db50058ae..f52ceb510 100644 --- a/pkgs/test/test/runner/github_reporter_test.dart +++ b/pkgs/test/test/runner/github_reporter_test.dart @@ -24,33 +24,39 @@ void main() { }); test('runs several successful tests and reports when each completes', () { - return _expectReport(''' + return _expectReport( + ''' test('success 1', () {}); test('success 2', () {}); - test('success 3', () {});''', ''' + test('success 3', () {});''', + ''' ✅ success 1 ✅ success 2 ✅ success 3 - 🎉 3 tests passed.'''); + 🎉 3 tests passed.''', + ); }); test('includes the platform name when multiple platforms are run', () { - return _expectReportLines(''' - test('success 1', () {});''', [ - '✅ [VM, Kernel] success 1', - '✅ [Chrome, Dart2Js] success 1', - '🎉 2 tests passed.', - ], args: [ - '-p', - 'vm,chrome' - ]); + return _expectReportLines( + ''' + test('success 1', () {});''', + [ + '✅ [VM, Kernel] success 1', + '✅ [Chrome, Dart2Js] success 1', + '🎉 2 tests passed.', + ], + args: ['-p', 'vm,chrome'], + ); }); test('runs several failing tests and reports when each fails', () { - return _expectReport(''' + return _expectReport( + ''' test('failure 1', () => throw TestFailure('oh no')); test('failure 2', () => throw TestFailure('oh no')); - test('failure 3', () => throw TestFailure('oh no'));''', ''' + test('failure 3', () => throw TestFailure('oh no'));''', + ''' ::group::❌ failure 1 (failed) oh no test.dart 6:33 main. @@ -63,7 +69,8 @@ void main() { oh no test.dart 8:33 main. ::endgroup:: - ::error::0 tests passed, 3 failed.'''); + ::error::0 tests passed, 3 failed.''', + ); }); test('includes the full stack trace with --verbose-trace', () async { @@ -77,18 +84,22 @@ void main() { } ''').create(); - var test = - await runTest(['--verbose-trace', 'test.dart'], reporter: 'github'); + var test = await runTest([ + '--verbose-trace', + 'test.dart', + ], reporter: 'github'); expect(test.stdout, emitsThrough(contains('dart:async'))); await test.shouldExit(1); }); test('runs failing tests along with successful tests', () { - return _expectReport(''' + return _expectReport( + ''' test('failure 1', () => throw TestFailure('oh no')); test('success 1', () {}); test('failure 2', () => throw TestFailure('oh no')); - test('success 2', () {});''', ''' + test('success 2', () {});''', + ''' ::group::❌ failure 1 (failed) oh no test.dart 6:33 main. @@ -99,7 +110,8 @@ void main() { test.dart 8:33 main. ::endgroup:: ✅ success 2 - ::error::2 tests passed, 2 failed.'''); + ::error::2 tests passed, 2 failed.''', + ); }); test('always prints the full test name', () { @@ -115,7 +127,8 @@ void main() { }); test('gracefully handles multiple test failures in a row', () { - return _expectReport(''' + return _expectReport( + ''' // This completer ensures that the test isolate isn't killed until all // errors have been thrown. var completer = Completer(); @@ -125,7 +138,8 @@ void main() { Future.microtask(() => throw 'third error'); Future.microtask(completer.complete); }); - test('wait', () => completer.future);''', ''' + test('wait', () => completer.future);''', + ''' ::group::❌ failures (failed) first error test.dart 10:34 main.. @@ -135,7 +149,8 @@ void main() { test.dart 12:34 main.. ::endgroup:: ✅ wait - ::error::1 test passed, 1 failed.'''); + ::error::1 test passed, 1 failed.''', + ); }); test('displays failures occuring after a test completes', () { @@ -187,7 +202,8 @@ void main() { }); test('handles a print after the test completes', () { - return _expectReport(''' + return _expectReport( + ''' // This completer ensures that the test isolate isn't killed until all // prints have happened. var testDone = Completer(); @@ -205,63 +221,76 @@ void main() { test('wait', () { waitStarted.complete(); return testDone.future; - });''', ''' + });''', + ''' ✅ test one two three four ✅ wait - 🎉 2 tests passed.'''); + 🎉 2 tests passed.''', + ); }); }); group('skip:', () { test('displays skipped tests', () { - return _expectReport(''' + return _expectReport( + ''' test('skip 1', () {}, skip: true); test('skip 2', () {}, skip: true); - test('skip 3', () {}, skip: true);''', ''' + test('skip 3', () {}, skip: true);''', + ''' ❎ skip 1 (skipped) ❎ skip 2 (skipped) ❎ skip 3 (skipped) - 🎉 0 tests passed, 3 skipped.'''); + 🎉 0 tests passed, 3 skipped.''', + ); }); test('displays a skipped group', () { - return _expectReport(''' + return _expectReport( + ''' group('skip', () { test('test 1', () {}); test('test 2', () {}); test('test 3', () {}); - }, skip: true);''', ''' + }, skip: true);''', + ''' ❎ skip test 1 (skipped) ❎ skip test 2 (skipped) ❎ skip test 3 (skipped) - 🎉 0 tests passed, 3 skipped.'''); + 🎉 0 tests passed, 3 skipped.''', + ); }); test('runs skipped tests along with successful tests', () { - return _expectReport(''' + return _expectReport( + ''' test('skip 1', () {}, skip: true); test('success 1', () {}); test('skip 2', () {}, skip: true); - test('success 2', () {});''', ''' + test('success 2', () {});''', + ''' ❎ skip 1 (skipped) ✅ success 1 ❎ skip 2 (skipped) ✅ success 2 - 🎉 2 tests passed, 2 skipped.'''); + 🎉 2 tests passed, 2 skipped.''', + ); }); test('runs skipped tests along with successful and failing tests', () { - return _expectReport(''' + return _expectReport( + ''' test('failure 1', () => throw TestFailure('oh no')); test('skip 1', () {}, skip: true); test('success 1', () {}); test('failure 2', () => throw TestFailure('oh no')); test('skip 2', () {}, skip: true); - test('success 2', () {});''', ''' + test('success 2', () {});''', + ''' ::group::❌ failure 1 (failed) oh no test.dart 6:35 main. @@ -274,41 +303,50 @@ void main() { ::endgroup:: ❎ skip 2 (skipped) ✅ success 2 - ::error::2 tests passed, 2 failed, 2 skipped.'''); + ::error::2 tests passed, 2 failed, 2 skipped.''', + ); }); test('displays the skip reason if available', () { - return _expectReport(''' + return _expectReport( + ''' test('skip 1', () {}, skip: 'some reason'); - test('skip 2', () {}, skip: 'or another');''', ''' + test('skip 2', () {}, skip: 'or another');''', + ''' ::group::❎ skip 1 (skipped) Skip: some reason ::endgroup:: ::group::❎ skip 2 (skipped) Skip: or another ::endgroup:: - 🎉 0 tests passed, 2 skipped.'''); + 🎉 0 tests passed, 2 skipped.''', + ); }); }); test('loadSuite, setUpAll, and tearDownAll hidden if no content', () { - return _expectReport(''' + return _expectReport( + ''' group('one', () { setUpAll(() {/* nothing to do here */}); tearDownAll(() {/* nothing to do here */}); test('test 1', () {}); - });''', ''' + });''', + ''' ✅ one test 1 - 🎉 1 test passed.'''); + 🎉 1 test passed.''', + ); }); test('setUpAll and tearDownAll show when they have content', () { - return _expectReport(''' + return _expectReport( + ''' group('one', () { setUpAll(() { print('one'); }); tearDownAll(() { print('two'); }); test('test 1', () {}); - });''', ''' + });''', + ''' ::group::✅ one (setUpAll) one ::endgroup:: @@ -316,7 +354,8 @@ void main() { ::group::✅ one (tearDownAll) two ::endgroup:: - 🎉 1 test passed.'''); + 🎉 1 test passed.''', + ); }); } @@ -360,10 +399,7 @@ $tests } ''').create(); - var test = await runTest([ - 'test.dart', - ...args, - ], reporter: 'github'); + var test = await runTest(['test.dart', ...args], reporter: 'github'); await test.shouldExit(); var stdoutLines = await test.stdoutStream().toList(); diff --git a/pkgs/test/test/runner/json_file_reporter_test.dart b/pkgs/test/test/runner/json_file_reporter_test.dart index ce3bd4274..4ec12fe4a 100644 --- a/pkgs/test/test/runner/json_file_reporter_test.dart +++ b/pkgs/test/test/runner/json_file_reporter_test.dart @@ -20,39 +20,46 @@ void main() { setUpAll(precompileTestExecutable); test('runs successful tests with a stdout reporter and file reporter', () { - return _expectReports(''' + return _expectReports( + ''' test('success 1', () {}); test('success 2', () {}); test('success 3', () {}); - ''', ''' + ''', + ''' +0: loading test.dart +0: success 1 +1: success 2 +2: success 3 - +3: All tests passed!''', [ + +3: All tests passed!''', [ - suiteJson(0), - testStartJson(1, 'loading test.dart', groupIDs: []), - testDoneJson(1, hidden: true), + [ + suiteJson(0), + testStartJson(1, 'loading test.dart', groupIDs: []), + testDoneJson(1, hidden: true), + ], + [ + groupJson(2, testCount: 3), + testStartJson(3, 'success 1', line: 6, column: 7), + testDoneJson(3), + testStartJson(4, 'success 2', line: 7, column: 7), + testDoneJson(4), + testStartJson(5, 'success 3', line: 8, column: 7), + testDoneJson(5), + ], ], - [ - groupJson(2, testCount: 3), - testStartJson(3, 'success 1', line: 6, column: 7), - testDoneJson(3), - testStartJson(4, 'success 2', line: 7, column: 7), - testDoneJson(4), - testStartJson(5, 'success 3', line: 8, column: 7), - testDoneJson(5), - ] - ], doneJson()); + doneJson(), + ); }); test('runs failing tests with a stdout reporter and file reporter', () { - return _expectReports(''' + return _expectReports( + ''' test('failure 1', () => throw new TestFailure('oh no')); test('failure 2', () => throw new TestFailure('oh no')); test('failure 3', () => throw new TestFailure('oh no')); - ''', ''' + ''', + ''' +0: loading test.dart +0: failure 1 +0 -1: failure 1 [E] @@ -69,50 +76,58 @@ void main() { oh no test.dart 8:31 main. - +0 -3: Some tests failed.''', [ + +0 -3: Some tests failed.''', [ - suiteJson(0), - testStartJson(1, 'loading test.dart', groupIDs: []), - testDoneJson(1, hidden: true), + [ + suiteJson(0), + testStartJson(1, 'loading test.dart', groupIDs: []), + testDoneJson(1, hidden: true), + ], + [ + groupJson(2, testCount: 3), + testStartJson(3, 'failure 1', line: 6, column: 7), + errorJson(3, 'oh no', isFailure: true), + testDoneJson(3, result: 'failure'), + testStartJson(4, 'failure 2', line: 7, column: 7), + errorJson(4, 'oh no', isFailure: true), + testDoneJson(4, result: 'failure'), + testStartJson(5, 'failure 3', line: 8, column: 7), + errorJson(5, 'oh no', isFailure: true), + testDoneJson(5, result: 'failure'), + ], ], - [ - groupJson(2, testCount: 3), - testStartJson(3, 'failure 1', line: 6, column: 7), - errorJson(3, 'oh no', isFailure: true), - testDoneJson(3, result: 'failure'), - testStartJson(4, 'failure 2', line: 7, column: 7), - errorJson(4, 'oh no', isFailure: true), - testDoneJson(4, result: 'failure'), - testStartJson(5, 'failure 3', line: 8, column: 7), - errorJson(5, 'oh no', isFailure: true), - testDoneJson(5, result: 'failure'), - ] - ], doneJson(success: false)); + doneJson(success: false), + ); }); group('reports an error if --file-reporter', () { test('is not in the form :', () async { var test = await runTest(['--file-reporter=json']); - expect(test.stderr, - emits(contains('option must be in the form :'))); + expect( + test.stderr, + emits(contains('option must be in the form :')), + ); await test.shouldExit(exit_codes.usage); }); test('targets a non-existent reporter', () async { var test = await runTest(['--file-reporter=nope:output.txt']); expect( - test.stderr, emits(contains('"nope" is not a supported reporter'))); + test.stderr, + emits(contains('"nope" is not a supported reporter')), + ); await test.shouldExit(exit_codes.usage); }); }); } Future _expectReports( - String tests, - String stdoutExpected, - List> jsonFileExpected, - Map jsonFileDone, - {List args = const []}) async { + String tests, + String stdoutExpected, + List> jsonFileExpected, + Map jsonFileDone, { + List args = const [], +}) async { await d.file('test.dart', ''' import 'dart:async'; @@ -123,27 +138,34 @@ $tests } ''').create(); - var test = await runTest(['test.dart', '--chain-stack-traces', ...args], - // Write to a file within a dir that doesn't yet exist to verify that the - // file is created recursively. - fileReporter: 'json:reports/tests.json'); + var test = await runTest( + ['test.dart', '--chain-stack-traces', ...args], + // Write to a file within a dir that doesn't yet exist to verify that the + // file is created recursively. + fileReporter: 'json:reports/tests.json', + ); await test.shouldExit(); // ---- stdout reporter verification ---- var stdoutLines = await test.stdoutStream().toList(); // Remove excess trailing whitespace and trim off timestamps. - var actual = stdoutLines.map((line) { - if (line.startsWith(' ') || line.isEmpty) return line.trimRight(); - return line.trim().replaceFirst(RegExp('^[0-9]{2}:[0-9]{2} '), ''); - }).join('\n'); + var actual = stdoutLines + .map((line) { + if (line.startsWith(' ') || line.isEmpty) return line.trimRight(); + return line.trim().replaceFirst(RegExp('^[0-9]{2}:[0-9]{2} '), ''); + }) + .join('\n'); // Un-indent the expected string. var indentation = stdoutExpected.indexOf(RegExp('[^ ]')); - stdoutExpected = stdoutExpected.split('\n').map((line) { - if (line.isEmpty) return line; - return line.substring(indentation); - }).join('\n'); + stdoutExpected = stdoutExpected + .split('\n') + .map((line) { + if (line.isEmpty) return line; + return line.substring(indentation); + }) + .join('\n'); expect(actual, equals(stdoutExpected)); @@ -151,5 +173,9 @@ $tests var fileOutputLines = File(p.join(d.sandbox, 'reports', 'tests.json')).readAsLinesSync(); await expectJsonReport( - fileOutputLines, test.pid, jsonFileExpected, jsonFileDone); + fileOutputLines, + test.pid, + jsonFileExpected, + jsonFileDone, + ); } diff --git a/pkgs/test/test/runner/json_reporter_test.dart b/pkgs/test/test/runner/json_reporter_test.dart index 88c4c1413..580eacfbe 100644 --- a/pkgs/test/test/runner/json_reporter_test.dart +++ b/pkgs/test/test/runner/json_reporter_test.dart @@ -18,52 +18,60 @@ void main() { setUpAll(precompileTestExecutable); test('runs several successful tests and reports when each completes', () { - return _expectReport(''' + return _expectReport( + ''' test('success 1', () {}); test('success 2', () {}); test('success 3', () {}); - ''', [ + ''', [ - suiteJson(0), - testStartJson(1, 'loading test.dart', groupIDs: []), - testDoneJson(1, hidden: true), + [ + suiteJson(0), + testStartJson(1, 'loading test.dart', groupIDs: []), + testDoneJson(1, hidden: true), + ], + [ + groupJson(2, testCount: 3), + testStartJson(3, 'success 1', line: 6, column: 7), + testDoneJson(3), + testStartJson(4, 'success 2', line: 7, column: 7), + testDoneJson(4), + testStartJson(5, 'success 3', line: 8, column: 7), + testDoneJson(5), + ], ], - [ - groupJson(2, testCount: 3), - testStartJson(3, 'success 1', line: 6, column: 7), - testDoneJson(3), - testStartJson(4, 'success 2', line: 7, column: 7), - testDoneJson(4), - testStartJson(5, 'success 3', line: 8, column: 7), - testDoneJson(5), - ] - ], doneJson()); + doneJson(), + ); }); test('runs several failing tests and reports when each fails', () { - return _expectReport(''' + return _expectReport( + ''' test('failure 1', () => throw TestFailure('oh no')); test('failure 2', () => throw TestFailure('oh no')); test('failure 3', () => throw TestFailure('oh no')); - ''', [ + ''', [ - suiteJson(0), - testStartJson(1, 'loading test.dart', groupIDs: []), - testDoneJson(1, hidden: true), + [ + suiteJson(0), + testStartJson(1, 'loading test.dart', groupIDs: []), + testDoneJson(1, hidden: true), + ], + [ + groupJson(2, testCount: 3), + testStartJson(3, 'failure 1', line: 6, column: 7), + errorJson(3, 'oh no', isFailure: true), + testDoneJson(3, result: 'failure'), + testStartJson(4, 'failure 2', line: 7, column: 7), + errorJson(4, 'oh no', isFailure: true), + testDoneJson(4, result: 'failure'), + testStartJson(5, 'failure 3', line: 8, column: 7), + errorJson(5, 'oh no', isFailure: true), + testDoneJson(5, result: 'failure'), + ], ], - [ - groupJson(2, testCount: 3), - testStartJson(3, 'failure 1', line: 6, column: 7), - errorJson(3, 'oh no', isFailure: true), - testDoneJson(3, result: 'failure'), - testStartJson(4, 'failure 2', line: 7, column: 7), - errorJson(4, 'oh no', isFailure: true), - testDoneJson(4, result: 'failure'), - testStartJson(5, 'failure 3', line: 8, column: 7), - errorJson(5, 'oh no', isFailure: true), - testDoneJson(5, result: 'failure'), - ] - ], doneJson(success: false)); + doneJson(success: false), + ); }); test('includes the full stack trace with --verbose-trace', () async { @@ -77,42 +85,49 @@ void main() { } ''').create(); - var test = - await runTest(['--verbose-trace', 'test.dart'], reporter: 'json'); + var test = await runTest([ + '--verbose-trace', + 'test.dart', + ], reporter: 'json'); expect(test.stdout, emitsThrough(contains('dart:async'))); await test.shouldExit(1); }); test('runs failing tests along with successful tests', () { - return _expectReport(''' + return _expectReport( + ''' test('failure 1', () => throw TestFailure('oh no')); test('success 1', () {}); test('failure 2', () => throw TestFailure('oh no')); test('success 2', () {}); - ''', [ + ''', [ - suiteJson(0), - testStartJson(1, 'loading test.dart', groupIDs: []), - testDoneJson(1, hidden: true), + [ + suiteJson(0), + testStartJson(1, 'loading test.dart', groupIDs: []), + testDoneJson(1, hidden: true), + ], + [ + groupJson(2, testCount: 4), + testStartJson(3, 'failure 1', line: 6, column: 7), + errorJson(3, 'oh no', isFailure: true), + testDoneJson(3, result: 'failure'), + testStartJson(4, 'success 1', line: 7, column: 7), + testDoneJson(4), + testStartJson(5, 'failure 2', line: 8, column: 7), + errorJson(5, 'oh no', isFailure: true), + testDoneJson(5, result: 'failure'), + testStartJson(6, 'success 2', line: 9, column: 7), + testDoneJson(6), + ], ], - [ - groupJson(2, testCount: 4), - testStartJson(3, 'failure 1', line: 6, column: 7), - errorJson(3, 'oh no', isFailure: true), - testDoneJson(3, result: 'failure'), - testStartJson(4, 'success 1', line: 7, column: 7), - testDoneJson(4), - testStartJson(5, 'failure 2', line: 8, column: 7), - errorJson(5, 'oh no', isFailure: true), - testDoneJson(5, result: 'failure'), - testStartJson(6, 'success 2', line: 9, column: 7), - testDoneJson(6), - ] - ], doneJson(success: false)); + doneJson(success: false), + ); }); test('gracefully handles multiple test failures in a row', () { - return _expectReport(''' + return _expectReport( + ''' // This completer ensures that the test isolate isn't killed until all // errors have been thrown. var completer = Completer(); @@ -123,27 +138,31 @@ void main() { Future.microtask(completer.complete); }); test('wait', () => completer.future); - ''', [ + ''', [ - suiteJson(0), - testStartJson(1, 'loading test.dart', groupIDs: []), - testDoneJson(1, hidden: true), + [ + suiteJson(0), + testStartJson(1, 'loading test.dart', groupIDs: []), + testDoneJson(1, hidden: true), + ], + [ + groupJson(2, testCount: 2), + testStartJson(3, 'failures', line: 9, column: 7), + errorJson(3, 'first error'), + errorJson(3, 'second error'), + errorJson(3, 'third error'), + testDoneJson(3, result: 'error'), + testStartJson(4, 'wait', line: 15, column: 7), + testDoneJson(4), + ], ], - [ - groupJson(2, testCount: 2), - testStartJson(3, 'failures', line: 9, column: 7), - errorJson(3, 'first error'), - errorJson(3, 'second error'), - errorJson(3, 'third error'), - testDoneJson(3, result: 'error'), - testStartJson(4, 'wait', line: 15, column: 7), - testDoneJson(4), - ] - ], doneJson(success: false)); + doneJson(success: false), + ); }); test('gracefully handles a test failing after completion', () { - return _expectReport(''' + return _expectReport( + ''' // These completers ensure that the first test won't fail until the second // one is running, and that the test isolate isn't killed until all errors // have been thrown. @@ -159,30 +178,35 @@ void main() { waitStarted.complete(); return testDone.future; }); - ''', [ - [ - suiteJson(0), - testStartJson(1, 'loading test.dart', groupIDs: []), - testDoneJson(1, hidden: true), - ], + ''', [ - groupJson(2, testCount: 2), - testStartJson(3, 'failure', line: 11, column: 7), - testDoneJson(3), - testStartJson(4, 'wait', line: 17, column: 7), - errorJson(3, 'oh no'), - errorJson( + [ + suiteJson(0), + testStartJson(1, 'loading test.dart', groupIDs: []), + testDoneJson(1, hidden: true), + ], + [ + groupJson(2, testCount: 2), + testStartJson(3, 'failure', line: 11, column: 7), + testDoneJson(3), + testStartJson(4, 'wait', line: 17, column: 7), + errorJson(3, 'oh no'), + errorJson( 3, 'This test failed after it had already completed.\n' 'Make sure to use a matching library which informs the ' - 'test runner\nof pending async work.'), - testDoneJson(4), - ] - ], doneJson(success: false)); + 'test runner\nof pending async work.', + ), + testDoneJson(4), + ], + ], + doneJson(success: false), + ); }); test('reports each test in its proper groups', () { - return _expectReport(''' + return _expectReport( + ''' group('group 1', () { group('.2', () { group('.3', () { @@ -193,60 +217,89 @@ void main() { test('success1', () {}); test('success2', () {}); }); - ''', [ + ''', [ - suiteJson(0), - testStartJson(1, 'loading test.dart', groupIDs: []), - testDoneJson(1, hidden: true), + [ + suiteJson(0), + testStartJson(1, 'loading test.dart', groupIDs: []), + testDoneJson(1, hidden: true), + ], + [ + groupJson(2, testCount: 3), + groupJson( + 3, + name: 'group 1', + parentID: 2, + testCount: 3, + line: 6, + column: 7, + ), + groupJson(4, name: 'group 1 .2', parentID: 3, line: 7, column: 9), + groupJson(5, name: 'group 1 .2 .3', parentID: 4, line: 8, column: 11), + testStartJson( + 6, + 'group 1 .2 .3 success', + groupIDs: [2, 3, 4, 5], + line: 9, + column: 13, + ), + testDoneJson(6), + testStartJson( + 7, + 'group 1 success1', + groupIDs: [2, 3], + line: 13, + column: 9, + ), + testDoneJson(7), + testStartJson( + 8, + 'group 1 success2', + groupIDs: [2, 3], + line: 14, + column: 9, + ), + testDoneJson(8), + ], ], - [ - groupJson(2, testCount: 3), - groupJson(3, - name: 'group 1', parentID: 2, testCount: 3, line: 6, column: 7), - groupJson(4, name: 'group 1 .2', parentID: 3, line: 7, column: 9), - groupJson(5, name: 'group 1 .2 .3', parentID: 4, line: 8, column: 11), - testStartJson(6, 'group 1 .2 .3 success', - groupIDs: [2, 3, 4, 5], line: 9, column: 13), - testDoneJson(6), - testStartJson(7, 'group 1 success1', - groupIDs: [2, 3], line: 13, column: 9), - testDoneJson(7), - testStartJson(8, 'group 1 success2', - groupIDs: [2, 3], line: 14, column: 9), - testDoneJson(8), - ] - ], doneJson()); + doneJson(), + ); }); group('print:', () { test('handles multiple prints', () { - return _expectReport(''' + return _expectReport( + ''' test('test', () { print("one"); print("two"); print("three"); print("four"); }); - ''', [ + ''', [ - suiteJson(0), - testStartJson(1, 'loading test.dart', groupIDs: []), - testDoneJson(1, hidden: true), + [ + suiteJson(0), + testStartJson(1, 'loading test.dart', groupIDs: []), + testDoneJson(1, hidden: true), + ], + [ + groupJson(2), + testStartJson(3, 'test', line: 6, column: 9), + printJson(3, 'one'), + printJson(3, 'two'), + printJson(3, 'three'), + printJson(3, 'four'), + testDoneJson(3), + ], ], - [ - groupJson(2), - testStartJson(3, 'test', line: 6, column: 9), - printJson(3, 'one'), - printJson(3, 'two'), - printJson(3, 'three'), - printJson(3, 'four'), - testDoneJson(3), - ] - ], doneJson()); + doneJson(), + ); }); test('handles a print after the test completes', () { - return _expectReport(''' + return _expectReport( + ''' // This completer ensures that the test isolate isn't killed until all // prints have happened. var testDone = Completer(); @@ -265,28 +318,32 @@ void main() { waitStarted.complete(); return testDone.future; }); - ''', [ + ''', [ - suiteJson(0), - testStartJson(1, 'loading test.dart', groupIDs: []), - testDoneJson(1, hidden: true), + [ + suiteJson(0), + testStartJson(1, 'loading test.dart', groupIDs: []), + testDoneJson(1, hidden: true), + ], + [ + groupJson(2, testCount: 2), + testStartJson(3, 'test', line: 10, column: 9), + testDoneJson(3), + testStartJson(4, 'wait', line: 20, column: 9), + printJson(3, 'one'), + printJson(3, 'two'), + printJson(3, 'three'), + printJson(3, 'four'), + testDoneJson(4), + ], ], - [ - groupJson(2, testCount: 2), - testStartJson(3, 'test', line: 10, column: 9), - testDoneJson(3), - testStartJson(4, 'wait', line: 20, column: 9), - printJson(3, 'one'), - printJson(3, 'two'), - printJson(3, 'three'), - printJson(3, 'four'), - testDoneJson(4), - ] - ], doneJson()); + doneJson(), + ); }); test('interleaves prints and errors', () { - return _expectReport(''' + return _expectReport( + ''' // This completer ensures that the test isolate isn't killed until all // prints have happened. var completer = Completer(); @@ -309,186 +366,232 @@ void main() { }); test('wait', () => completer.future); - ''', [ + ''', [ - suiteJson(0), - testStartJson(1, 'loading test.dart', groupIDs: []), - testDoneJson(1, hidden: true), + [ + suiteJson(0), + testStartJson(1, 'loading test.dart', groupIDs: []), + testDoneJson(1, hidden: true), + ], + [ + groupJson(2, testCount: 2), + testStartJson(3, 'test', line: 9, column: 9), + printJson(3, 'one'), + printJson(3, 'two'), + errorJson(3, 'first error'), + printJson(3, 'three'), + printJson(3, 'four'), + errorJson(3, 'second error'), + printJson(3, 'five'), + printJson(3, 'six'), + testDoneJson(3, result: 'error'), + testStartJson(4, 'wait', line: 27, column: 9), + testDoneJson(4), + ], ], - [ - groupJson(2, testCount: 2), - testStartJson(3, 'test', line: 9, column: 9), - printJson(3, 'one'), - printJson(3, 'two'), - errorJson(3, 'first error'), - printJson(3, 'three'), - printJson(3, 'four'), - errorJson(3, 'second error'), - printJson(3, 'five'), - printJson(3, 'six'), - testDoneJson(3, result: 'error'), - testStartJson(4, 'wait', line: 27, column: 9), - testDoneJson(4), - ] - ], doneJson(success: false)); + doneJson(success: false), + ); }); }); group('skip:', () { test('reports skipped tests', () { - return _expectReport(''' + return _expectReport( + ''' test('skip 1', () {}, skip: true); test('skip 2', () {}, skip: true); test('skip 3', () {}, skip: true); - ''', [ + ''', [ - suiteJson(0), - testStartJson(1, 'loading test.dart', groupIDs: []), - testDoneJson(1, hidden: true), + [ + suiteJson(0), + testStartJson(1, 'loading test.dart', groupIDs: []), + testDoneJson(1, hidden: true), + ], + [ + groupJson(2, testCount: 3), + testStartJson(3, 'skip 1', skip: true, line: 6, column: 9), + testDoneJson(3, skipped: true), + testStartJson(4, 'skip 2', skip: true, line: 7, column: 9), + testDoneJson(4, skipped: true), + testStartJson(5, 'skip 3', skip: true, line: 8, column: 9), + testDoneJson(5, skipped: true), + ], ], - [ - groupJson(2, testCount: 3), - testStartJson(3, 'skip 1', skip: true, line: 6, column: 9), - testDoneJson(3, skipped: true), - testStartJson(4, 'skip 2', skip: true, line: 7, column: 9), - testDoneJson(4, skipped: true), - testStartJson(5, 'skip 3', skip: true, line: 8, column: 9), - testDoneJson(5, skipped: true), - ] - ], doneJson()); + doneJson(), + ); }); test('reports skipped groups', () { - return _expectReport(''' + return _expectReport( + ''' group('skip', () { test('success 1', () {}); test('success 2', () {}); test('success 3', () {}); }, skip: true); - ''', [ - [ - suiteJson(0), - testStartJson(1, 'loading test.dart', groupIDs: []), - testDoneJson(1, hidden: true), - ], + ''', [ - groupJson(2, testCount: 3), - groupJson(3, + [ + suiteJson(0), + testStartJson(1, 'loading test.dart', groupIDs: []), + testDoneJson(1, hidden: true), + ], + [ + groupJson(2, testCount: 3), + groupJson( + 3, name: 'skip', parentID: 2, skip: true, testCount: 3, line: 6, - column: 9), - testStartJson(4, 'skip success 1', - groupIDs: [2, 3], skip: true, line: 7, column: 11), - testDoneJson(4, skipped: true), - testStartJson(5, 'skip success 2', - groupIDs: [2, 3], skip: true, line: 8, column: 11), - testDoneJson(5, skipped: true), - testStartJson(6, 'skip success 3', - groupIDs: [2, 3], skip: true, line: 9, column: 11), - testDoneJson(6, skipped: true), - ] - ], doneJson()); + column: 9, + ), + testStartJson( + 4, + 'skip success 1', + groupIDs: [2, 3], + skip: true, + line: 7, + column: 11, + ), + testDoneJson(4, skipped: true), + testStartJson( + 5, + 'skip success 2', + groupIDs: [2, 3], + skip: true, + line: 8, + column: 11, + ), + testDoneJson(5, skipped: true), + testStartJson( + 6, + 'skip success 3', + groupIDs: [2, 3], + skip: true, + line: 9, + column: 11, + ), + testDoneJson(6, skipped: true), + ], + ], + doneJson(), + ); }); test('reports the skip reason if available', () { - return _expectReport(''' + return _expectReport( + ''' test('skip 1', () {}, skip: 'some reason'); test('skip 2', () {}, skip: 'or another'); - ''', [ + ''', [ - suiteJson(0), - testStartJson(1, 'loading test.dart', groupIDs: []), - testDoneJson(1, hidden: true), + [ + suiteJson(0), + testStartJson(1, 'loading test.dart', groupIDs: []), + testDoneJson(1, hidden: true), + ], + [ + groupJson(2, testCount: 2), + testStartJson(3, 'skip 1', skip: 'some reason', line: 6, column: 9), + printJson(3, 'Skip: some reason', type: 'skip'), + testDoneJson(3, skipped: true), + testStartJson(4, 'skip 2', skip: 'or another', line: 7, column: 9), + printJson(4, 'Skip: or another', type: 'skip'), + testDoneJson(4, skipped: true), + ], ], - [ - groupJson(2, testCount: 2), - testStartJson(3, 'skip 1', skip: 'some reason', line: 6, column: 9), - printJson(3, 'Skip: some reason', type: 'skip'), - testDoneJson(3, skipped: true), - testStartJson(4, 'skip 2', skip: 'or another', line: 7, column: 9), - printJson(4, 'Skip: or another', type: 'skip'), - testDoneJson(4, skipped: true), - ] - ], doneJson()); + doneJson(), + ); }); test('runs skipped tests with --run-skipped', () { return _expectReport( - ''' + ''' test('skip 1', () {}, skip: 'some reason'); test('skip 2', () {}, skip: 'or another'); ''', + [ [ - [ - suiteJson(0), - testStartJson(1, 'loading test.dart', groupIDs: []), - testDoneJson(1, hidden: true), - ], - [ - groupJson(2, testCount: 2), - testStartJson(3, 'skip 1', line: 6, column: 9), - testDoneJson(3), - testStartJson(4, 'skip 2', line: 7, column: 9), - testDoneJson(4), - ] + suiteJson(0), + testStartJson(1, 'loading test.dart', groupIDs: []), + testDoneJson(1, hidden: true), ], - doneJson(), - args: ['--run-skipped']); + [ + groupJson(2, testCount: 2), + testStartJson(3, 'skip 1', line: 6, column: 9), + testDoneJson(3), + testStartJson(4, 'skip 2', line: 7, column: 9), + testDoneJson(4), + ], + ], + doneJson(), + args: ['--run-skipped'], + ); }); }); group('reports line and column numbers for', () { test('the first call to setUpAll()', () { - return _expectReport(''' + return _expectReport( + ''' setUpAll(() {}); setUpAll(() {}); setUpAll(() {}); test('success', () {}); - ''', [ + ''', [ - suiteJson(0), - testStartJson(1, 'loading test.dart', groupIDs: []), - testDoneJson(1, hidden: true), + [ + suiteJson(0), + testStartJson(1, 'loading test.dart', groupIDs: []), + testDoneJson(1, hidden: true), + ], + [ + groupJson(2, testCount: 1), + testStartJson(3, '(setUpAll)', line: 6, column: 9), + testDoneJson(3, hidden: true), + testStartJson(4, 'success', line: 9, column: 9), + testDoneJson(4), + testStartJson(5, '(tearDownAll)'), + testDoneJson(5, hidden: true), + ], ], - [ - groupJson(2, testCount: 1), - testStartJson(3, '(setUpAll)', line: 6, column: 9), - testDoneJson(3, hidden: true), - testStartJson(4, 'success', line: 9, column: 9), - testDoneJson(4), - testStartJson(5, '(tearDownAll)'), - testDoneJson(5, hidden: true), - ] - ], doneJson()); + doneJson(), + ); }); test('the first call to tearDownAll()', () { - return _expectReport(''' + return _expectReport( + ''' tearDownAll(() {}); tearDownAll(() {}); tearDownAll(() {}); test('success', () {}); - ''', [ + ''', [ - testStartJson(1, 'loading test.dart', groupIDs: []), - testDoneJson(1, hidden: true), + [ + testStartJson(1, 'loading test.dart', groupIDs: []), + testDoneJson(1, hidden: true), + ], + [ + suiteJson(0), + groupJson(2, testCount: 1), + testStartJson(3, 'success', line: 9, column: 9), + testDoneJson(3), + testStartJson(4, '(tearDownAll)', line: 6, column: 9), + testDoneJson(4, hidden: true), + ], ], - [ - suiteJson(0), - groupJson(2, testCount: 1), - testStartJson(3, 'success', line: 9, column: 9), - testDoneJson(3), - testStartJson(4, '(tearDownAll)', line: 6, column: 9), - testDoneJson(4, hidden: true), - ] - ], doneJson()); + doneJson(), + ); }); - test('a test compiled to JS', () { - return _expectReport( + test( + 'a test compiled to JS', + () { + return _expectReport( ''' test('success', () {}); ''', @@ -497,99 +600,118 @@ void main() { suiteJson(0, platform: 'chrome'), testStartJson(1, 'loading test.dart', groupIDs: []), printJson( - 1, - isA().having((s) => s.split('\n'), 'lines', - contains(startsWith('Compiled')))), + 1, + isA().having( + (s) => s.split('\n'), + 'lines', + contains(startsWith('Compiled')), + ), + ), testDoneJson(1, hidden: true), ], [ groupJson(2, testCount: 1), testStartJson(3, 'success', line: 6, column: 9), testDoneJson(3), - ] + ], ], doneJson(), - args: ['-p', 'chrome']); - }, tags: ['chrome'], skip: 'https://github.com/dart-lang/test/issues/872'); + args: ['-p', 'chrome'], + ); + }, + tags: ['chrome'], + skip: 'https://github.com/dart-lang/test/issues/872', + ); test('the root suite from a relative path', () { return _expectReport( - ''' + ''' customTest('success 1', () {}); test('success 2', () {}); ''', + [ [ - [ - suiteJson(0), - testStartJson(1, 'loading test.dart', groupIDs: []), - testDoneJson(1, hidden: true), - ], - [ - groupJson(2, testCount: 2), - testStartJson(3, 'success 1', - line: 3, - column: 60, - url: p.toUri(p.join(d.sandbox, 'common.dart')).toString(), - rootColumn: 7, - rootLine: 7, - rootUrl: p.toUri(p.join(d.sandbox, 'test.dart')).toString()), - testDoneJson(3), - testStartJson(4, 'success 2', line: 8, column: 7), - testDoneJson(4), - ] + suiteJson(0), + testStartJson(1, 'loading test.dart', groupIDs: []), + testDoneJson(1, hidden: true), ], - doneJson(), - externalLibraries: { - 'common.dart': ''' + [ + groupJson(2, testCount: 2), + testStartJson( + 3, + 'success 1', + line: 3, + column: 60, + url: p.toUri(p.join(d.sandbox, 'common.dart')).toString(), + rootColumn: 7, + rootLine: 7, + rootUrl: p.toUri(p.join(d.sandbox, 'test.dart')).toString(), + ), + testDoneJson(3), + testStartJson(4, 'success 2', line: 8, column: 7), + testDoneJson(4), + ], + ], + doneJson(), + externalLibraries: { + 'common.dart': ''' import 'package:test/test.dart'; void customTest(String name, dynamic Function() testFn) => test(name, testFn); ''', - }); + }, + ); }); test('the root suite from an absolute path', () { final path = p.prettyUri(p.join(d.sandbox, 'test.dart')); return _expectReport( - ''' + ''' customTest('success 1', () {}); test('success 2', () {}); ''', - useRelativePath: false, + useRelativePath: false, + [ [ - [ - suiteJson(0, path: equalsIgnoringCase(path)), - testStartJson( - 1, allOf(startsWith('loading '), endsWith('test.dart')), - groupIDs: []), - testDoneJson(1, hidden: true), - ], - [ - groupJson(2, testCount: 2), - testStartJson(3, 'success 1', - line: 3, - column: 60, - url: p.toUri(p.join(d.sandbox, 'common.dart')).toString(), - rootColumn: 7, - rootLine: 7, - rootUrl: p.toUri(p.join(d.sandbox, 'test.dart')).toString()), - testDoneJson(3), - testStartJson(4, 'success 2', line: 8, column: 7), - testDoneJson(4), - ] + suiteJson(0, path: equalsIgnoringCase(path)), + testStartJson( + 1, + allOf(startsWith('loading '), endsWith('test.dart')), + groupIDs: [], + ), + testDoneJson(1, hidden: true), ], - doneJson(), - externalLibraries: { - 'common.dart': ''' + [ + groupJson(2, testCount: 2), + testStartJson( + 3, + 'success 1', + line: 3, + column: 60, + url: p.toUri(p.join(d.sandbox, 'common.dart')).toString(), + rootColumn: 7, + rootLine: 7, + rootUrl: p.toUri(p.join(d.sandbox, 'test.dart')).toString(), + ), + testDoneJson(3), + testStartJson(4, 'success 2', line: 8, column: 7), + testDoneJson(4), + ], + ], + doneJson(), + externalLibraries: { + 'common.dart': ''' import 'package:test/test.dart'; void customTest(String name, dynamic Function() testFn) => test(name, testFn); ''', - }); + }, + ); }); test('groups and tests with custom locations', () { - return _expectReport(''' + return _expectReport( + ''' group('group 1 inferred', () { setUpAll(() {}); test('test 1 inferred', () {}); @@ -600,84 +722,119 @@ void customTest(String name, dynamic Function() testFn) => test(name, testFn); test('test 2 custom', location: TestLocation(Uri.parse('file:///foo/test'), 567, 789), () {}); tearDownAll(location: TestLocation(Uri.parse('file:///foo/tearDownAll'), 890, 901), () {}); }); - ''', [ - [ - suiteJson(0), - testStartJson(1, 'loading test.dart', groupIDs: []), - testDoneJson(1, hidden: true), - ], + ''', [ - groupJson(2, testCount: 2), - groupJson(3, + [ + suiteJson(0), + testStartJson(1, 'loading test.dart', groupIDs: []), + testDoneJson(1, hidden: true), + ], + [ + groupJson(2, testCount: 2), + groupJson( + 3, name: 'group 1 inferred', parentID: 2, line: 6, column: 7, - testCount: 1), - testStartJson(4, 'group 1 inferred (setUpAll)', - groupIDs: [2, 3], line: 7, column: 9), - testDoneJson(4, hidden: true), - testStartJson(5, 'group 1 inferred test 1 inferred', - groupIDs: [2, 3], line: 8, column: 9), - testDoneJson(5), - testStartJson(6, 'group 1 inferred (tearDownAll)', - groupIDs: [2, 3], line: 9, column: 9), - testDoneJson(6, hidden: true), - groupJson(7, + testCount: 1, + ), + testStartJson( + 4, + 'group 1 inferred (setUpAll)', + groupIDs: [2, 3], + line: 7, + column: 9, + ), + testDoneJson(4, hidden: true), + testStartJson( + 5, + 'group 1 inferred test 1 inferred', + groupIDs: [2, 3], + line: 8, + column: 9, + ), + testDoneJson(5), + testStartJson( + 6, + 'group 1 inferred (tearDownAll)', + groupIDs: [2, 3], + line: 9, + column: 9, + ), + testDoneJson(6, hidden: true), + groupJson( + 7, name: 'group 2 custom', parentID: 2, url: 'file:///foo/group', line: 123, column: 234, - testCount: 1), - testStartJson(8, 'group 2 custom (setUpAll)', + testCount: 1, + ), + testStartJson( + 8, + 'group 2 custom (setUpAll)', url: 'file:///foo/setUpAll', groupIDs: [2, 7], line: 345, - column: 456), - testDoneJson(8, hidden: true), - testStartJson(9, 'group 2 custom test 2 custom', + column: 456, + ), + testDoneJson(8, hidden: true), + testStartJson( + 9, + 'group 2 custom test 2 custom', url: 'file:///foo/test', groupIDs: [2, 7], line: 567, - column: 789), - testDoneJson(9), - testStartJson(10, 'group 2 custom (tearDownAll)', + column: 789, + ), + testDoneJson(9), + testStartJson( + 10, + 'group 2 custom (tearDownAll)', url: 'file:///foo/tearDownAll', groupIDs: [2, 7], line: 890, - column: 901), - testDoneJson(10, hidden: true), - ] - ], doneJson()); + column: 901, + ), + testDoneJson(10, hidden: true), + ], + ], + doneJson(), + ); }); }); - test( - "doesn't report line and column information for a test compiled to JS " + test("doesn't report line and column information for a test compiled to JS " 'with --js-trace', () { return _expectReport( - ''' + ''' test('success', () {}); ''', + [ [ - [ - suiteJson(0, platform: 'chrome'), - testStartJson(1, 'loading test.dart', groupIDs: []), - printJson( - 1, - isA().having((s) => s.split('\n'), 'lines', - contains(startsWith('Compiled')))), - testDoneJson(1, hidden: true), - ], - [ - groupJson(2, testCount: 1), - testStartJson(3, 'success'), - testDoneJson(3), - ], + suiteJson(0, platform: 'chrome'), + testStartJson(1, 'loading test.dart', groupIDs: []), + printJson( + 1, + isA().having( + (s) => s.split('\n'), + 'lines', + contains(startsWith('Compiled')), + ), + ), + testDoneJson(1, hidden: true), ], - doneJson(), - args: ['-p', 'chrome', '--js-trace']); + [ + groupJson(2, testCount: 1), + testStartJson(3, 'success'), + testDoneJson(3), + ], + ], + doneJson(), + args: ['-p', 'chrome', '--js-trace'], + ); }, tags: ['chrome']); } @@ -687,11 +844,14 @@ void customTest(String name, dynamic Function() testFn) => test(name, testFn); /// If [externalLibraries] are provided it should be a map of relative file /// paths to contents. All libraries will be added as imports to the test, and /// files will be created for them. -Future _expectReport(String tests, - List> expected, Map done, - {List args = const [], - bool useRelativePath = true, - Map externalLibraries = const {}}) async { +Future _expectReport( + String tests, + List> expected, + Map done, { + List args = const [], + bool useRelativePath = true, + Map externalLibraries = const {}, +}) async { var testContent = StringBuffer(''' import 'dart:async'; @@ -710,8 +870,11 @@ import 'package:test/test.dart'; await d.file('test.dart', testContent.toString()).create(); var testPath = useRelativePath ? 'test.dart' : p.join(d.sandbox, 'test.dart'); - var test = await runTest([testPath, '--chain-stack-traces', ...args], - reporter: 'json'); + var test = await runTest([ + testPath, + '--chain-stack-traces', + ...args, + ], reporter: 'json'); await test.shouldExit(); var stdoutLines = await test.stdoutStream().toList(); diff --git a/pkgs/test/test/runner/json_reporter_utils.dart b/pkgs/test/test/runner/json_reporter_utils.dart index 3c921b005..7416c0a4a 100644 --- a/pkgs/test/test/runner/json_reporter_utils.dart +++ b/pkgs/test/test/runner/json_reporter_utils.dart @@ -15,20 +15,23 @@ import 'package:test_descriptor/test_descriptor.dart' as d; /// Verifies that [outputLines] matches each set of matchers in [expected], /// includes the [testPid] from the test process, and ends with [done]. Future expectJsonReport( - List outputLines, - int testPid, - List> expected, - Map done) async { + List outputLines, + int testPid, + List> expected, + Map done, +) async { // Ensure the output is of the same length, including start, done and all // suites messages. - expect(outputLines, - hasLength(expected.fold(3, (int a, m) => a + m.length))); + expect( + outputLines, + hasLength(expected.fold(3, (int a, m) => a + m.length)), + ); final decoded = [ for (final line in outputLines) (jsonDecode(line) as Map) ..remove('time') - ..remove('stackTrace') + ..remove('stackTrace'), ]; // Should contain all suites message. @@ -55,24 +58,24 @@ Future expectJsonReport( /// all suites. /// /// The [count] defaults to 1. -Map _allSuitesJson({int count = 1}) => - {'type': 'allSuites', 'count': count}; +Map _allSuitesJson({int count = 1}) => { + 'type': 'allSuites', + 'count': count, +}; /// Returns the event emitted by the JSON reporter indicating that a suite has /// begun running. /// /// The [platform] defaults to `'vm'`. /// The [path] defaults to `equals('test.dart')`. -Map suiteJson(int id, - {String platform = 'vm', Matcher? path}) => - { - 'type': 'suite', - 'suite': { - 'id': id, - 'platform': platform, - 'path': path ?? 'test.dart', - } - }; +Map suiteJson( + int id, { + String platform = 'vm', + Matcher? path, +}) => { + 'type': 'suite', + 'suite': {'id': id, 'platform': platform, 'path': path ?? 'test.dart'}, +}; /// Returns the event emitted by the JSON reporter indicating that a group has /// begun running. @@ -83,18 +86,21 @@ Map suiteJson(int id, /// /// The [testCount] parameter indicates the number of tests in the group. It /// defaults to 1. -Map groupJson(int id, - {String? name, - int? suiteID, - int? parentID, - Object? skip, - int? testCount, - String? url, - int? line, - int? column}) { +Map groupJson( + int id, { + String? name, + int? suiteID, + int? parentID, + Object? skip, + int? testCount, + String? url, + int? line, + int? column, +}) { if ((line == null) != (column == null)) { throw ArgumentError( - 'line and column must either both be null or both be passed'); + 'line and column must either both be null or both be passed', + ); } url ??= @@ -110,8 +116,8 @@ Map groupJson(int id, 'testCount': testCount ?? 1, 'line': line, 'column': column, - 'url': url - } + 'url': url, + }, }; } @@ -122,19 +128,23 @@ Map groupJson(int id, /// [skip] is `true`, the test is expected to be marked as skipped without a /// reason. If it's a [String], the test is expected to be marked as skipped /// with that reason. -Map testStartJson(int id, Object /*String|Matcher*/ name, - {int? suiteID, - Iterable? groupIDs, - int? line, - int? column, - String? url, - Object? skip, - int? rootLine, - int? rootColumn, - String? rootUrl}) { +Map testStartJson( + int id, + Object /*String|Matcher*/ name, { + int? suiteID, + Iterable? groupIDs, + int? line, + int? column, + String? url, + Object? skip, + int? rootLine, + int? rootColumn, + String? rootUrl, +}) { if ((line == null) != (column == null)) { throw ArgumentError( - 'line and column must either both be null or both be passed'); + 'line and column must either both be null or both be passed', + ); } url ??= @@ -153,21 +163,23 @@ Map testStartJson(int id, Object /*String|Matcher*/ name, if (rootLine != null) 'root_line': rootLine, if (rootColumn != null) 'root_column': rootColumn, if (rootUrl != null) 'root_url': rootUrl, - } + }, }; } /// Returns the event emitted by the JSON reporter indicating that a test /// printed [message]. -Matcher printJson(int id, dynamic /*String|Matcher*/ message, - {String type = 'print'}) => - allOf( - hasLength(4), - containsPair('type', 'print'), - containsPair('testID', id), - containsPair('message', message), - containsPair('messageType', type), - ); +Matcher printJson( + int id, + dynamic /*String|Matcher*/ message, { + String type = 'print', +}) => allOf( + hasLength(4), + containsPair('type', 'print'), + containsPair('testID', id), + containsPair('message', message), + containsPair('messageType', type), +); /// Returns the event emitted by the JSON reporter indicating that a test /// emitted [error]. @@ -186,25 +198,28 @@ Map errorJson(int id, String error, {bool isFailure = false}) => /// The [hidden] parameter indicates whether the test should not be displayed /// after finishing. The [skipped] parameter indicates whether the test was /// skipped. -Map testDoneJson(int id, - {String result = 'success', - bool hidden = false, - bool skipped = false}) => - { - 'type': 'testDone', - 'testID': id, - 'result': result, - 'hidden': hidden, - 'skipped': skipped - }; +Map testDoneJson( + int id, { + String result = 'success', + bool hidden = false, + bool skipped = false, +}) => { + 'type': 'testDone', + 'testID': id, + 'result': result, + 'hidden': hidden, + 'skipped': skipped, +}; /// Returns the event emitted by the JSON reporter indicating that the entire /// run finished. -Map doneJson({bool success = true}) => - {'type': 'done', 'success': success}; +Map doneJson({bool success = true}) => { + 'type': 'done', + 'success': success, +}; /// Returns the serialized metadata corresponding to [skip]. Map _metadataJson({Object? skip}) => { - 'skip': skip == true || skip is String, - 'skipReason': skip is String ? skip : null - }; + 'skip': skip == true || skip is String, + 'skipReason': skip is String ? skip : null, +}; diff --git a/pkgs/test/test/runner/line_and_col_test.dart b/pkgs/test/test/runner/line_and_col_test.dart index 3241c4f3f..8e1e04a7d 100644 --- a/pkgs/test/test/runner/line_and_col_test.dart +++ b/pkgs/test/test/runner/line_and_col_test.dart @@ -28,10 +28,7 @@ void main() { var test = await runTest(['test.dart?line=6']); - expect( - test.stdout, - emitsThrough(contains('+1: All tests passed!')), - ); + expect(test.stdout, emitsThrough(contains('+1: All tests passed!'))); await test.shouldExit(0); }); @@ -48,10 +45,7 @@ void main() { var test = await runTest(['test.dart?line=4']); - expect( - test.stdout, - emitsThrough(contains('+2: All tests passed!')), - ); + expect(test.stdout, emitsThrough(contains('+2: All tests passed!'))); await test.shouldExit(0); }); @@ -60,8 +54,9 @@ void main() { await d.dir('test').create(); var testFileUri = Uri.file(d.file('test/aaa_test.dart').io.path); var notTestFileUri = Uri.file(d.file('test/bbb.dart').io.path); - var testFilePackageRelativeUri = - Uri.parse('org-dartlang-app:///test/aaa_test.dart'); + var testFilePackageRelativeUri = Uri.parse( + 'org-dartlang-app:///test/aaa_test.dart', + ); await d.file('test/aaa_test.dart', ''' import 'package:test/test.dart'; @@ -84,10 +79,7 @@ void main() { var test = await runTest(['test/aaa_test.dart?line=4']); - expect( - test.stdout, - emitsThrough(contains('+3: All tests passed!')), - ); + expect(test.stdout, emitsThrough(contains('+3: All tests passed!'))); await test.shouldExit(0); }); @@ -108,22 +100,21 @@ void main() { var test = await runTest(['test.dart?line=4']); - expect( - test.stdout, - emitsThrough(contains('+1: All tests passed!')), - ); + expect(test.stdout, emitsThrough(contains('+1: All tests passed!'))); await test.shouldExit(0); }); - test('additionally selects groups with a matching custom location', - () async { - await d.dir('test').create(); - var testFileUri = Uri.file(d.file('test/aaa_test.dart').io.path); - var notTestFileUri = Uri.file(d.file('test/bbb.dart').io.path); - var testFilePackageRelativeUri = - Uri.parse('org-dartlang-app:///test/aaa_test.dart'); - await d.file('test/aaa_test.dart', ''' + test( + 'additionally selects groups with a matching custom location', + () async { + await d.dir('test').create(); + var testFileUri = Uri.file(d.file('test/aaa_test.dart').io.path); + var notTestFileUri = Uri.file(d.file('test/bbb.dart').io.path); + var testFilePackageRelativeUri = Uri.parse( + 'org-dartlang-app:///test/aaa_test.dart', + ); + await d.file('test/aaa_test.dart', ''' import 'package:test/test.dart'; void main() { @@ -153,15 +144,13 @@ void main() { } ''').create(); - var test = await runTest(['test/aaa_test.dart?line=4']); + var test = await runTest(['test/aaa_test.dart?line=4']); - expect( - test.stdout, - emitsThrough(contains('+3: All tests passed!')), - ); + expect(test.stdout, emitsThrough(contains('+3: All tests passed!'))); - await test.shouldExit(0); - }); + await test.shouldExit(0); + }, + ); test('No matching tests', () async { await d.file('test.dart', ''' @@ -174,10 +163,7 @@ void main() { var test = await runTest(['test.dart?line=1']); - expect( - test.stderr, - emitsThrough(contains('No tests were found.')), - ); + expect(test.stderr, emitsThrough(contains('No tests were found.'))); await test.shouldExit(exit_codes.noTestsRan); }); @@ -198,10 +184,7 @@ void main() { var test = await runTest(['test.dart?line=8']); - expect( - test.stdout, - emitsThrough(contains('+1: All tests passed!')), - ); + expect(test.stdout, emitsThrough(contains('+1: All tests passed!'))); await test.shouldExit(0); }); @@ -220,10 +203,7 @@ void main() { var test = await runTest(['test.dart?col=11']); - expect( - test.stdout, - emitsThrough(contains('+1: All tests passed!')), - ); + expect(test.stdout, emitsThrough(contains('+1: All tests passed!'))); await test.shouldExit(0); }); @@ -241,10 +221,7 @@ void main() { var test = await runTest(['test.dart?col=11']); - expect( - test.stdout, - emitsThrough(contains('+2: All tests passed!')), - ); + expect(test.stdout, emitsThrough(contains('+2: All tests passed!'))); await test.shouldExit(0); }); @@ -265,10 +242,7 @@ void main() { var test = await runTest(['test.dart?col=11']); - expect( - test.stdout, - emitsThrough(contains('+1: All tests passed!')), - ); + expect(test.stdout, emitsThrough(contains('+1: All tests passed!'))); await test.shouldExit(0); }); @@ -284,10 +258,7 @@ void main() { var test = await runTest(['test.dart?col=1']); - expect( - test.stderr, - emitsThrough(contains('No tests were found.')), - ); + expect(test.stderr, emitsThrough(contains('No tests were found.'))); await test.shouldExit(exit_codes.noTestsRan); }); @@ -308,19 +279,17 @@ void main() { var test = await runTest(['test.dart?col=13']); - expect( - test.stdout, - emitsThrough(contains('+1: All tests passed!')), - ); + expect(test.stdout, emitsThrough(contains('+1: All tests passed!'))); await test.shouldExit(0); }); }); group('with test.dart?line=&col= query', () { - test('selects test with the matching line and col in the same frame', - () async { - await d.file('test.dart', ''' + test( + 'selects test with the matching line and col in the same frame', + () async { + await d.file('test.dart', ''' import 'package:test/test.dart'; void main() { @@ -332,15 +301,13 @@ void main() { } ''').create(); - var test = await runTest(['test.dart?line=5&col=11']); + var test = await runTest(['test.dart?line=5&col=11']); - expect( - test.stdout, - emitsThrough(contains('+1: All tests passed!')), - ); + expect(test.stdout, emitsThrough(contains('+1: All tests passed!'))); - await test.shouldExit(0); - }); + await test.shouldExit(0); + }, + ); test('selects group with the matching line and col', () async { await d.file('test.dart', ''' @@ -359,10 +326,7 @@ void main() { var test = await runTest(['test.dart?line=4&col=11']); - expect( - test.stdout, - emitsThrough(contains('+2: All tests passed!')), - ); + expect(test.stdout, emitsThrough(contains('+2: All tests passed!'))); await test.shouldExit(0); }); @@ -378,10 +342,7 @@ void main() { var test = await runTest(['test.dart?line=4&col=1']); - expect( - test.stderr, - emitsThrough(contains('No tests were found.')), - ); + expect(test.stderr, emitsThrough(contains('No tests were found.'))); await test.shouldExit(exit_codes.noTestsRan); }); @@ -397,10 +358,7 @@ void main() { var test = await runTest(['test.dart?line=1&col=11']); - expect( - test.stderr, - emitsThrough(contains('No tests were found.')), - ); + expect(test.stderr, emitsThrough(contains('No tests were found.'))); await test.shouldExit(exit_codes.noTestsRan); }); @@ -417,10 +375,7 @@ void main() { var test = await runTest(['test.dart?line=4&col=11', '-p', 'chrome']); - expect( - test.stdout, - emitsThrough(contains('+1: All tests passed!')), - ); + expect(test.stdout, emitsThrough(contains('+1: All tests passed!'))); await test.shouldExit(0); }); @@ -437,18 +392,16 @@ void main() { var test = await runTest(['test.dart?line=4&col=11', '-p', 'node']); - expect( - test.stdout, - emitsThrough(contains('+1: All tests passed!')), - ); + expect(test.stdout, emitsThrough(contains('+1: All tests passed!'))); await test.shouldExit(0); }, retry: 3); }); - test('bundles runs by suite, deduplicates tests that match multiple times', - () async { - await d.file('test.dart', ''' + test( + 'bundles runs by suite, deduplicates tests that match multiple times', + () async { + await d.file('test.dart', ''' import 'package:test/test.dart'; void main() { @@ -457,13 +410,11 @@ void main() { } ''').create(); - var test = await runTest(['test.dart?line=4', 'test.dart?full-name=a']); + var test = await runTest(['test.dart?line=4', 'test.dart?full-name=a']); - expect( - test.stdout, - emitsThrough(contains('+1: All tests passed!')), - ); + expect(test.stdout, emitsThrough(contains('+1: All tests passed!'))); - await test.shouldExit(0); - }); + await test.shouldExit(0); + }, + ); } diff --git a/pkgs/test/test/runner/load_suite_test.dart b/pkgs/test/test/runner/load_suite_test.dart index ab5fc790a..5cfd80b0f 100644 --- a/pkgs/test/test/runner/load_suite_test.dart +++ b/pkgs/test/test/runner/load_suite_test.dart @@ -26,8 +26,12 @@ void main() { }); test('running a load test causes LoadSuite.suite to emit a suite', () async { - var suite = LoadSuite('name', SuiteConfiguration.empty, suitePlatform, - () => Future.value(innerSuite)); + var suite = LoadSuite( + 'name', + SuiteConfiguration.empty, + suitePlatform, + () => Future.value(innerSuite), + ); expect(suite.group.entries, hasLength(1)); expect(suite.suite, completion(equals(innerSuite))); @@ -38,7 +42,11 @@ void main() { test("running a load suite's body may be synchronous", () async { var suite = LoadSuite( - 'name', SuiteConfiguration.empty, suitePlatform, () => innerSuite); + 'name', + SuiteConfiguration.empty, + suitePlatform, + () => innerSuite, + ); expect(suite.group.entries, hasLength(1)); expect(suite.suite, completion(equals(innerSuite))); @@ -49,8 +57,12 @@ void main() { test("a load test doesn't complete until the body returns", () async { var completer = Completer(); - var suite = LoadSuite('name', SuiteConfiguration.empty, suitePlatform, - () => completer.future); + var suite = LoadSuite( + 'name', + SuiteConfiguration.empty, + suitePlatform, + () => completer.future, + ); expect(suite.group.entries, hasLength(1)); var liveTest = (suite.group.entries.single as Test).load(suite); @@ -63,23 +75,34 @@ void main() { expectTestPassed(liveTest); }); - test('a load test forwards errors and completes LoadSuite.suite to null', - () async { - var suite = LoadSuite('name', SuiteConfiguration.empty, suitePlatform, () { - return fail('error'); - }); - expect(suite.group.entries, hasLength(1)); + test( + 'a load test forwards errors and completes LoadSuite.suite to null', + () async { + var suite = LoadSuite( + 'name', + SuiteConfiguration.empty, + suitePlatform, + () { + return fail('error'); + }, + ); + expect(suite.group.entries, hasLength(1)); - expect(suite.suite, completion(isNull)); + expect(suite.suite, completion(isNull)); - var liveTest = (suite.group.entries.single as Test).load(suite); - await liveTest.run(); - expectTestFailed(liveTest, 'error'); - }); + var liveTest = (suite.group.entries.single as Test).load(suite); + await liveTest.run(); + expectTestFailed(liveTest, 'error'); + }, + ); test("a load test completes early if it's closed", () async { - var suite = LoadSuite('name', SuiteConfiguration.empty, suitePlatform, - () => Completer().future); + var suite = LoadSuite( + 'name', + SuiteConfiguration.empty, + suitePlatform, + () => Completer().future, + ); expect(suite.group.entries, hasLength(1)); var liveTest = (suite.group.entries.single as Test).load(suite); @@ -90,48 +113,65 @@ void main() { expect(liveTest.close(), completes); }); - test('forLoadException() creates a suite that completes to a LoadException', - () async { - var exception = LoadException('path', 'error'); - var suite = LoadSuite.forLoadException(exception, SuiteConfiguration.empty); - expect(suite.group.entries, hasLength(1)); + test( + 'forLoadException() creates a suite that completes to a LoadException', + () async { + var exception = LoadException('path', 'error'); + var suite = LoadSuite.forLoadException( + exception, + SuiteConfiguration.empty, + ); + expect(suite.group.entries, hasLength(1)); - expect(suite.suite, completion(isNull)); + expect(suite.suite, completion(isNull)); - var liveTest = (suite.group.entries.single as Test).load(suite); - await liveTest.run(); - expect(liveTest.state.status, equals(Status.complete)); - expect(liveTest.state.result, equals(Result.error)); - expect(liveTest.errors, hasLength(1)); - expect(liveTest.errors.first.error, equals(exception)); - }); - - test('forSuite() creates a load suite that completes to a test suite', - () async { - var suite = LoadSuite.forSuite(innerSuite); - expect(suite.group.entries, hasLength(1)); + var liveTest = (suite.group.entries.single as Test).load(suite); + await liveTest.run(); + expect(liveTest.state.status, equals(Status.complete)); + expect(liveTest.state.result, equals(Result.error)); + expect(liveTest.errors, hasLength(1)); + expect(liveTest.errors.first.error, equals(exception)); + }, + ); + + test( + 'forSuite() creates a load suite that completes to a test suite', + () async { + var suite = LoadSuite.forSuite(innerSuite); + expect(suite.group.entries, hasLength(1)); - expect(suite.suite, completion(equals(innerSuite))); - var liveTest = (suite.group.entries.single as Test).load(suite); - await liveTest.run(); - expectTestPassed(liveTest); - }); + expect(suite.suite, completion(equals(innerSuite))); + var liveTest = (suite.group.entries.single as Test).load(suite); + await liveTest.run(); + expectTestPassed(liveTest); + }, + ); group('changeSuite()', () { test('returns a new load suite with the same properties', () { var suite = LoadSuite( - 'name', SuiteConfiguration.empty, suitePlatform, () => innerSuite); + 'name', + SuiteConfiguration.empty, + suitePlatform, + () => innerSuite, + ); expect(suite.group.entries, hasLength(1)); var newSuite = suite.changeSuite((suite) => suite); expect(newSuite.platform.runtime, equals(Runtime.vm)); - expect(newSuite.group.entries.single.name, - equals(suite.group.entries.single.name)); + expect( + newSuite.group.entries.single.name, + equals(suite.group.entries.single.name), + ); }); test('changes the inner suite', () async { var suite = LoadSuite( - 'name', SuiteConfiguration.empty, suitePlatform, () => innerSuite); + 'name', + SuiteConfiguration.empty, + suitePlatform, + () => innerSuite, + ); expect(suite.group.entries, hasLength(1)); var newInnerSuite = runnerSuite(Group.root([])); @@ -145,12 +185,18 @@ void main() { test("doesn't run change() if the suite is null", () async { var suite = LoadSuite( - 'name', SuiteConfiguration.empty, suitePlatform, () => null); + 'name', + SuiteConfiguration.empty, + suitePlatform, + () => null, + ); expect(suite.group.entries, hasLength(1)); - var newSuite = suite.changeSuite(expectAsync1((_) { - return null; - }, count: 0)); + var newSuite = suite.changeSuite( + expectAsync1((_) { + return null; + }, count: 0), + ); expect(newSuite.suite, completion(isNull)); var liveTest = (suite.group.entries.single as Test).load(suite); @@ -169,7 +215,11 @@ void main() { test('forwards errors to the future', () { var suite = LoadSuite( - 'name', SuiteConfiguration.empty, suitePlatform, () => throw 'error'); + 'name', + SuiteConfiguration.empty, + suitePlatform, + () => throw 'error', + ); expect(suite.group.entries, hasLength(1)); expect(suite.getSuite(), throwsA('error')); diff --git a/pkgs/test/test/runner/loader_test.dart b/pkgs/test/test/runner/loader_test.dart index 8d1d4ada6..8a0977791 100644 --- a/pkgs/test/test/runner/loader_test.dart +++ b/pkgs/test/test/runner/loader_test.dart @@ -49,10 +49,13 @@ void main() { group('with empty configuration', () { setUp(() async { await d.file('a_test.dart', _tests).create(); - var suites = await _loader - .loadFile( - p.join(d.sandbox, 'a_test.dart'), SuiteConfiguration.empty) - .toList(); + var suites = + await _loader + .loadFile( + p.join(d.sandbox, 'a_test.dart'), + SuiteConfiguration.empty, + ) + .toList(); expect(suites, hasLength(1)); var loadSuite = suites.first; suite = (await loadSuite.getSuite())!; @@ -76,7 +79,7 @@ void main() { expectStates(liveTest, [ const State(Status.running, Result.success), - const State(Status.complete, Result.success) + const State(Status.complete, Result.success), ]); expectErrors(liveTest, []); @@ -92,71 +95,100 @@ void main() { group('with compiler selection', () { Future> loadSuitesWithConfig( - SuiteConfiguration suiteConfiguration) async { + SuiteConfiguration suiteConfiguration, + ) async { await d.file('a_test.dart', _tests).create(); return _loader .loadFile(p.join(d.sandbox, 'a_test.dart'), suiteConfiguration) .toList(); } - test('with a single compiler selection, uses the selected compiler', - () async { - var suites = await loadSuitesWithConfig(suiteConfiguration( - compilerSelections: [CompilerSelection.parse('source')])); - expect(suites, hasLength(1)); - var loadSuite = suites.first; - suite = (await loadSuite.getSuite())!; - expect(suite.path, equals(p.join(d.sandbox, 'a_test.dart'))); - expect(suite.platform.runtime, equals(Runtime.vm)); - expect(suite.platform.compiler, equals(Compiler.source)); - }); - - test('with multiple compiler selections, returns a suite for each', - () async { - var suites = await loadSuitesWithConfig(suiteConfiguration( - compilerSelections: [ - CompilerSelection.parse('source'), - CompilerSelection.parse('kernel') - ])); - - expect(suites, hasLength(2)); - var runnerSuites = - await Future.wait([for (var suite in suites) suite.getSuite()]); - expect( + test( + 'with a single compiler selection, uses the selected compiler', + () async { + var suites = await loadSuitesWithConfig( + suiteConfiguration( + compilerSelections: [CompilerSelection.parse('source')], + ), + ); + expect(suites, hasLength(1)); + var loadSuite = suites.first; + suite = (await loadSuite.getSuite())!; + expect(suite.path, equals(p.join(d.sandbox, 'a_test.dart'))); + expect(suite.platform.runtime, equals(Runtime.vm)); + expect(suite.platform.compiler, equals(Compiler.source)); + }, + ); + + test( + 'with multiple compiler selections, returns a suite for each', + () async { + var suites = await loadSuitesWithConfig( + suiteConfiguration( + compilerSelections: [ + CompilerSelection.parse('source'), + CompilerSelection.parse('kernel'), + ], + ), + ); + + expect(suites, hasLength(2)); + var runnerSuites = await Future.wait([ + for (var suite in suites) suite.getSuite(), + ]); + expect( runnerSuites, unorderedEquals([ isA() .having( - (s) => s.platform.runtime, 'The vm runtime', Runtime.vm) - .having((s) => s.platform.compiler, 'The source compiler', - Compiler.source), + (s) => s.platform.runtime, + 'The vm runtime', + Runtime.vm, + ) + .having( + (s) => s.platform.compiler, + 'The source compiler', + Compiler.source, + ), isA() .having( - (s) => s.platform.runtime, 'The vm runtime', Runtime.vm) - .having((s) => s.platform.compiler, 'The kernel compiler', - Compiler.kernel), - ])); - }); - - test('with unsupported compiler selections, uses the default compiler', - () async { - var suites = - await loadSuitesWithConfig(suiteConfiguration(compilerSelections: [ - CompilerSelection.parse('dart2js'), - ])); - expect(suites, hasLength(1)); - var loadSuite = suites.first; - suite = (await loadSuite.getSuite())!; - expect(suite.path, equals(p.join(d.sandbox, 'a_test.dart'))); - expect(suite.platform.runtime, equals(Runtime.vm)); - expect(suite.platform.compiler, equals(Runtime.vm.defaultCompiler)); - }); + (s) => s.platform.runtime, + 'The vm runtime', + Runtime.vm, + ) + .having( + (s) => s.platform.compiler, + 'The kernel compiler', + Compiler.kernel, + ), + ]), + ); + }, + ); + + test( + 'with unsupported compiler selections, uses the default compiler', + () async { + var suites = await loadSuitesWithConfig( + suiteConfiguration( + compilerSelections: [CompilerSelection.parse('dart2js')], + ), + ); + expect(suites, hasLength(1)); + var loadSuite = suites.first; + suite = (await loadSuite.getSuite())!; + expect(suite.path, equals(p.join(d.sandbox, 'a_test.dart'))); + expect(suite.platform.runtime, equals(Runtime.vm)); + expect(suite.platform.compiler, equals(Runtime.vm.defaultCompiler)); + }, + ); test('compiler selections support matching boolean selectors', () async { - var suites = - await loadSuitesWithConfig(suiteConfiguration(compilerSelections: [ - CompilerSelection.parse('vm:source'), - ])); + var suites = await loadSuitesWithConfig( + suiteConfiguration( + compilerSelections: [CompilerSelection.parse('vm:source')], + ), + ); expect(suites, hasLength(1)); var loadSuite = suites.first; suite = (await loadSuite.getSuite())!; @@ -166,17 +198,20 @@ void main() { }); test('compiler selections support unmatched boolean selectors', () async { - var suites = - await loadSuitesWithConfig(suiteConfiguration(compilerSelections: [ - CompilerSelection.parse('browser:source'), - ])); + var suites = await loadSuitesWithConfig( + suiteConfiguration( + compilerSelections: [CompilerSelection.parse('browser:source')], + ), + ); expect(suites, hasLength(1)); var loadSuite = suites.first; suite = (await loadSuite.getSuite())!; expect(suite.path, equals(p.join(d.sandbox, 'a_test.dart'))); expect(suite.platform.runtime, equals(Runtime.vm)); - expect(suite.platform.compiler, - allOf(Runtime.vm.defaultCompiler, isNot(Compiler.source))); + expect( + suite.platform.compiler, + allOf(Runtime.vm.defaultCompiler, isNot(Compiler.source)), + ); }); }); }); @@ -184,14 +219,18 @@ void main() { group('.loadDir()', () { test('ignores non-Dart files', () async { await d.file('a_test.txt', _tests).create(); - expect(_loader.loadDir(d.sandbox, SuiteConfiguration.empty).toList(), - completion(isEmpty)); + expect( + _loader.loadDir(d.sandbox, SuiteConfiguration.empty).toList(), + completion(isEmpty), + ); }); test("ignores files that don't end in _test.dart", () async { await d.file('test.dart', _tests).create(); - expect(_loader.loadDir(d.sandbox, SuiteConfiguration.empty).toList(), - completion(isEmpty)); + expect( + _loader.loadDir(d.sandbox, SuiteConfiguration.empty).toList(), + completion(isEmpty), + ); }); group('with suites loaded from a directory', () { @@ -201,25 +240,28 @@ void main() { await d.file('another_test.dart', _tests).create(); await d.dir('dir', [d.file('sub_test.dart', _tests)]).create(); - suites = await _loader - .loadDir(d.sandbox, SuiteConfiguration.empty) - .asyncMap((loadSuite) async => (await loadSuite.getSuite())!) - .toList(); + suites = + await _loader + .loadDir(d.sandbox, SuiteConfiguration.empty) + .asyncMap((loadSuite) async => (await loadSuite.getSuite())!) + .toList(); }); test('gives those suites the correct paths', () { expect( - suites.map((suite) => suite.path), - unorderedEquals([ - p.join(d.sandbox, 'a_test.dart'), - p.join(d.sandbox, 'another_test.dart'), - p.join(d.sandbox, 'dir', 'sub_test.dart') - ])); + suites.map((suite) => suite.path), + unorderedEquals([ + p.join(d.sandbox, 'a_test.dart'), + p.join(d.sandbox, 'another_test.dart'), + p.join(d.sandbox, 'dir', 'sub_test.dart'), + ]), + ); }); test('can run tests in those suites', () { - var suite = - suites.firstWhere((suite) => suite.path!.contains('a_test')); + var suite = suites.firstWhere( + (suite) => suite.path!.contains('a_test'), + ); var liveTest = (suite.group.entries[1] as RunnerTest).load(suite); expectSingleFailure(liveTest); return liveTest.run().whenComplete(() => liveTest.close()); @@ -233,15 +275,21 @@ void main() { print('print within test'); } ''').create(); - var suites = await _loader - .loadFile(p.join(d.sandbox, 'a_test.dart'), SuiteConfiguration.empty) - .toList(); + var suites = + await _loader + .loadFile( + p.join(d.sandbox, 'a_test.dart'), + SuiteConfiguration.empty, + ) + .toList(); expect(suites, hasLength(1)); var loadSuite = suites.first; var liveTest = (loadSuite.group.entries.single as Test).load(loadSuite); - expect(liveTest.onMessage.first.then((message) => message.text), - completion(equals('print within test'))); + expect( + liveTest.onMessage.first.then((message) => message.text), + completion(equals('print within test')), + ); await liveTest.run(); expectTestPassed(liveTest); }); @@ -259,30 +307,39 @@ void main() { var firstFailureCompleter = Completer(); // After the first load failure we create the missing dependency. - unawaited(firstFailureCompleter.future.then((_) async { - await d.file('hello.dart', ''' + unawaited( + firstFailureCompleter.future.then((_) async { + await d.file('hello.dart', ''' String get message => 'hello'; ''').create(); - })); - - await runZoned(() async { - var suites = await _loader - .loadFile(p.join(d.sandbox, 'a_test.dart'), - suiteConfiguration(retry: numRetries)) - .toList(); - expect(suites, hasLength(1)); - var loadSuite = suites.first; - var suite = (await loadSuite.getSuite())!; - expect(suite.path, equals(p.join(d.sandbox, 'a_test.dart'))); - expect(suite.platform.runtime, equals(Runtime.vm)); - }, zoneSpecification: - ZoneSpecification(print: (_, parent, zone, message) { - if (message.contains('Retrying load of') && - !firstFailureCompleter.isCompleted) { - firstFailureCompleter.complete(null); - } - parent.print(zone, message); - })); + }), + ); + + await runZoned( + () async { + var suites = + await _loader + .loadFile( + p.join(d.sandbox, 'a_test.dart'), + suiteConfiguration(retry: numRetries), + ) + .toList(); + expect(suites, hasLength(1)); + var loadSuite = suites.first; + var suite = (await loadSuite.getSuite())!; + expect(suite.path, equals(p.join(d.sandbox, 'a_test.dart'))); + expect(suite.platform.runtime, equals(Runtime.vm)); + }, + zoneSpecification: ZoneSpecification( + print: (_, parent, zone, message) { + if (message.contains('Retrying load of') && + !firstFailureCompleter.isCompleted) { + firstFailureCompleter.complete(null); + } + parent.print(zone, message); + }, + ), + ); expect(firstFailureCompleter.isCompleted, true); }); diff --git a/pkgs/test/test/runner/name_test.dart b/pkgs/test/test/runner/name_test.dart index bd4dc2138..fc1b578d7 100644 --- a/pkgs/test/test/runner/name_test.dart +++ b/pkgs/test/test/runner/name_test.dart @@ -28,10 +28,7 @@ void main() { var test = await runTest(['test.dart?name=selected']); - expect( - test.stdout, - emitsThrough(contains('+2: All tests passed!')), - ); + expect(test.stdout, emitsThrough(contains('+2: All tests passed!'))); await test.shouldExit(0); }); @@ -49,10 +46,7 @@ void main() { var test = await runTest(['test.dart?name=test [13]']); - expect( - test.stdout, - emitsThrough(contains('+2: All tests passed!')), - ); + expect(test.stdout, emitsThrough(contains('+2: All tests passed!'))); await test.shouldExit(0); }); @@ -76,14 +70,12 @@ void main() { } ''').create(); - var test = await runTest( - ['test.dart?name=selected 1', 'test2.dart?name=selected 2'], - ); + var test = await runTest([ + 'test.dart?name=selected 1', + 'test2.dart?name=selected 2', + ]); - expect( - test.stdout, - emitsThrough(contains('+2: All tests passed!')), - ); + expect(test.stdout, emitsThrough(contains('+2: All tests passed!'))); await test.shouldExit(0); }); @@ -100,10 +92,7 @@ void main() { var test = await runTest(['test.dart?name=selected&name=1']); - expect( - test.stdout, - emitsThrough(contains('+1: All tests passed!')), - ); + expect(test.stdout, emitsThrough(contains('+1: All tests passed!'))); await test.shouldExit(0); }); @@ -124,15 +113,12 @@ void main() { test("selected 1", () {}); test("selected 2", () => throw TestFailure("oh no")); } - ''') + '''), ]).create(); var test = await runTest(['dir?name=selected 1']); - expect( - test.stdout, - emitsThrough(contains('+2: All tests passed!')), - ); + expect(test.stdout, emitsThrough(contains('+2: All tests passed!'))); await test.shouldExit(0); }); @@ -147,10 +133,7 @@ void main() { var test = await runTest(['test.dart?name=no']); - expect( - test.stderr, - emitsThrough(contains('No tests were found.')), - ); + expect(test.stderr, emitsThrough(contains('No tests were found.'))); await test.shouldExit(exit_codes.noTestsRan); }); @@ -161,7 +144,7 @@ void main() { test.stdout, containsInOrder([ '-1: loading file [E]', - ' Failed to load "file": Does not exist.' + ' Failed to load "file": Does not exist.', ]), ); @@ -183,10 +166,7 @@ void main() { var test = await runTest(['test.dart?full-name=selected']); - expect( - test.stdout, - emitsThrough(contains('+1: All tests passed!')), - ); + expect(test.stdout, emitsThrough(contains('+1: All tests passed!'))); await test.shouldExit(0); }); @@ -203,10 +183,7 @@ void main() { var test = await runTest(['test.dart?full-name=test [12]']); - expect( - test.stdout, - emitsThrough(contains('+1: All tests passed!')), - ); + expect(test.stdout, emitsThrough(contains('+1: All tests passed!'))); await test.shouldExit(0); }); @@ -229,14 +206,12 @@ void main() { } ''').create(); - var test = await runTest( - ['test.dart?full-name=selected 1', 'test2.dart?full-name=selected 2'], - ); + var test = await runTest([ + 'test.dart?full-name=selected 1', + 'test2.dart?full-name=selected 2', + ]); - expect( - test.stdout, - emitsThrough(contains('+2: All tests passed!')), - ); + expect(test.stdout, emitsThrough(contains('+2: All tests passed!'))); await test.shouldExit(0); }); @@ -251,10 +226,7 @@ void main() { var test = await runTest(['test.dart?full-name=no match']); - expect( - test.stderr, - emitsThrough(contains('No tests were found.')), - ); + expect(test.stderr, emitsThrough(contains('No tests were found.'))); await test.shouldExit(exit_codes.noTestsRan); }); }); @@ -273,10 +245,7 @@ void main() { var test = await runTest(['--name', '1', 'test.dart?name=selected']); - expect( - test.stdout, - emitsThrough(contains('+1: All tests passed!')), - ); + expect(test.stdout, emitsThrough(contains('+1: All tests passed!'))); await test.shouldExit(0); }); @@ -341,8 +310,13 @@ void main() { } ''').create(); - var test = - await runTest(['--name', 'selected', '--name', '1', 'test.dart']); + var test = await runTest([ + '--name', + 'selected', + '--name', + '1', + 'test.dart', + ]); expect(test.stdout, emitsThrough(contains('+1: All tests passed!'))); await test.shouldExit(0); }); @@ -358,20 +332,21 @@ void main() { var test = await runTest(['--name', 'no match', 'test.dart']); expect( - test.stderr, - emitsThrough( - contains('No tests match regular expression "no match".'))); + test.stderr, + emitsThrough(contains('No tests match regular expression "no match".')), + ); await test.shouldExit(exit_codes.noTestsRan); }); test("doesn't filter out load exceptions", () async { var test = await runTest(['--name', 'name', 'file']); expect( - test.stdout, - containsInOrder([ - '-1: loading file [E]', - ' Failed to load "file": Does not exist.' - ])); + test.stdout, + containsInOrder([ + '-1: loading file [E]', + ' Failed to load "file": Does not exist.', + ]), + ); await test.shouldExit(1); }); }); @@ -420,8 +395,13 @@ void main() { } ''').create(); - var test = await runTest( - ['--plain-name', 'selected', '--plain-name', '1', 'test.dart']); + var test = await runTest([ + '--plain-name', + 'selected', + '--plain-name', + '1', + 'test.dart', + ]); expect(test.stdout, emitsThrough(contains('+1: All tests passed!'))); await test.shouldExit(0); }); @@ -452,8 +432,13 @@ void main() { } ''').create(); - var test = - await runTest(['--name', '.....', '--plain-name', 'e', 'test.dart']); + var test = await runTest([ + '--name', + '.....', + '--plain-name', + 'e', + 'test.dart', + ]); expect(test.stdout, emitsThrough(contains('+2: All tests passed!'))); await test.shouldExit(0); }); diff --git a/pkgs/test/test/runner/node/runner_test.dart b/pkgs/test/test/runner/node/runner_test.dart index ea36b5838..6c1eb7410 100644 --- a/pkgs/test/test/runner/node/runner_test.dart +++ b/pkgs/test/test/runner/node/runner_test.dart @@ -82,12 +82,13 @@ void main() { var test = await runTest(['-p', 'node', 'test.dart']); expect( - test.stdout, - containsInOrder([ - 'Error: Compilation failed.', - '-1: loading test.dart [E]', - 'Failed to load "test.dart": dart2js failed.' - ])); + test.stdout, + containsInOrder([ + 'Error: Compilation failed.', + '-1: loading test.dart [E]', + 'Failed to load "test.dart": dart2js failed.', + ]), + ); await test.shouldExit(1); }); @@ -96,50 +97,62 @@ void main() { var test = await runTest(['-p', 'node', 'test.dart']); expect( - test.stdout, - containsInOrder([ - '-1: loading test.dart [E]', - 'Failed to load "test.dart": oh no' - ])); + test.stdout, + containsInOrder([ + '-1: loading test.dart [E]', + 'Failed to load "test.dart": oh no', + ]), + ); await test.shouldExit(1); }); - test("a test file doesn't have a main defined", () async { - await d.file('test.dart', 'void foo() {}').create(); + test( + "a test file doesn't have a main defined", + () async { + await d.file('test.dart', 'void foo() {}').create(); - var test = await runTest(['-p', 'node', 'test.dart']); - expect( + var test = await runTest(['-p', 'node', 'test.dart']); + expect( test.stdout, containsInOrder([ '-1: loading test.dart [E]', - 'Failed to load "test.dart": No top-level main() function defined.' - ])); - await test.shouldExit(1); - }, skip: 'https://github.com/dart-lang/test/issues/894'); - - test('a test file has a non-function main', () async { - await d.file('test.dart', 'int main;').create(); + 'Failed to load "test.dart": No top-level main() function defined.', + ]), + ); + await test.shouldExit(1); + }, + skip: 'https://github.com/dart-lang/test/issues/894', + ); + + test( + 'a test file has a non-function main', + () async { + await d.file('test.dart', 'int main;').create(); - var test = await runTest(['-p', 'node', 'test.dart']); - expect( + var test = await runTest(['-p', 'node', 'test.dart']); + expect( test.stdout, containsInOrder([ '-1: loading test.dart [E]', - 'Failed to load "test.dart": Top-level main getter is not a function.' - ])); - await test.shouldExit(1); - }, skip: 'https://github.com/dart-lang/test/issues/894'); + 'Failed to load "test.dart": Top-level main getter is not a function.', + ]), + ); + await test.shouldExit(1); + }, + skip: 'https://github.com/dart-lang/test/issues/894', + ); test('a test file has a main with arguments', () async { await d.file('test.dart', 'void main(arg) {}').create(); var test = await runTest(['-p', 'node', 'test.dart']); expect( - test.stdout, - containsInOrder([ - '-1: loading test.dart [E]', - 'Failed to load "test.dart": Top-level main() function takes arguments.' - ])); + test.stdout, + containsInOrder([ + '-1: loading test.dart [E]', + 'Failed to load "test.dart": Top-level main() function takes arguments.', + ]), + ); await test.shouldExit(1); }); }); @@ -164,8 +177,13 @@ void main() { test('compiled with dart2wasm', () async { await d.file('test.dart', _success).create(); - var test = - await runTest(['-p', 'node', '--compiler', 'dart2wasm', 'test.dart']); + var test = await runTest([ + '-p', + 'node', + '--compiler', + 'dart2wasm', + 'test.dart', + ]); expect(test.stdout, emitsThrough(contains('+1: All tests passed!'))); await test.shouldExit(0); @@ -202,14 +220,23 @@ void main() { } ''').create(); - var test = - await runTest(['-p', 'node', '-p', 'vm', '-c', 'dart2js', 'test.dart']); + var test = await runTest([ + '-p', + 'node', + '-p', + 'vm', + '-c', + 'dart2js', + 'test.dart', + ]); expect(test.stdout, emitsThrough(contains('+1 -1: Some tests failed.'))); await test.shouldExit(1); }); - test('runs failing tests that fail only on node (with dart2wasm)', () async { - await d.file('test.dart', ''' + test( + 'runs failing tests that fail only on node (with dart2wasm)', + () async { + await d.file('test.dart', ''' import 'package:path/path.dart' as p; import 'package:test/test.dart'; @@ -222,20 +249,22 @@ void main() { } ''').create(); - var test = await runTest([ - '-p', - 'node', - '-p', - 'vm', - '-c', - 'dart2js', - '-c', - 'dart2wasm', - 'test.dart' - ]); - expect(test.stdout, emitsThrough(contains('+1 -2: Some tests failed.'))); - await test.shouldExit(1); - }, skip: skipBelowMajorNodeVersion(22)); + var test = await runTest([ + '-p', + 'node', + '-p', + 'vm', + '-c', + 'dart2js', + '-c', + 'dart2wasm', + 'test.dart', + ]); + expect(test.stdout, emitsThrough(contains('+1 -2: Some tests failed.'))); + await test.shouldExit(1); + }, + skip: skipBelowMajorNodeVersion(22), + ); test( 'gracefully handles wasm errors on old node versions', @@ -259,7 +288,8 @@ void main() { test.stdout, emitsInOrder([ emitsThrough( - contains('Node exited before connecting to the test channel.')), + contains('Node exited before connecting to the test channel.'), + ), emitsThrough(contains('-1: Some tests failed.')), ]), ); @@ -314,28 +344,37 @@ void main() { await d.file('test.dart', _failure).create(); var test = await runTest(['-p', 'node', '--verbose-trace', 'test.dart']); - expect(test.stdout, - containsInOrder([' main.', 'package:test', 'dart:async/zone.dart']), - skip: 'https://github.com/dart-lang/sdk/issues/41949'); + expect( + test.stdout, + containsInOrder([' main.', 'package:test', 'dart:async/zone.dart']), + skip: 'https://github.com/dart-lang/sdk/issues/41949', + ); await test.shouldExit(1); }); - test("doesn't dartify stack traces for JS-compiled tests with --js-trace", - () async { - await d.file('test.dart', _failure).create(); - - var test = await runTest( - ['-p', 'node', '--verbose-trace', '--js-trace', 'test.dart']); - expect(test.stdoutStream(), neverEmits(endsWith(' main.'))); - expect(test.stdoutStream(), neverEmits(contains('package:test'))); - expect(test.stdoutStream(), neverEmits(contains('dart:async/zone.dart'))); - expect(test.stdout, emitsThrough(contains('-1: Some tests failed.'))); - await test.shouldExit(1); - }); + test( + "doesn't dartify stack traces for JS-compiled tests with --js-trace", + () async { + await d.file('test.dart', _failure).create(); + + var test = await runTest([ + '-p', + 'node', + '--verbose-trace', + '--js-trace', + 'test.dart', + ]); + expect(test.stdoutStream(), neverEmits(endsWith(' main.'))); + expect(test.stdoutStream(), neverEmits(contains('package:test'))); + expect(test.stdoutStream(), neverEmits(contains('dart:async/zone.dart'))); + expect(test.stdout, emitsThrough(contains('-1: Some tests failed.'))); + await test.shouldExit(1); + }, + ); test('supports node_modules in the package directory', () async { await d.dir('node_modules', [ - d.dir('my_module', [d.file('index.js', 'module.exports.value = 12;')]) + d.dir('my_module', [d.file('index.js', 'module.exports.value = 12;')]), ]).create(); await d.file('test.dart', ''' diff --git a/pkgs/test/test/runner/parse_metadata_test.dart b/pkgs/test/test/runner/parse_metadata_test.dart index a8ffa9c7c..113702e51 100644 --- a/pkgs/test/test/runner/parse_metadata_test.dart +++ b/pkgs/test/test/runner/parse_metadata_test.dart @@ -21,48 +21,63 @@ void main() { }); test('ignores irrelevant annotations', () { - var metadata = - parseMetadata(_path, '@Fblthp\n@Fblthp.foo\nlibrary foo;', {}); + var metadata = parseMetadata( + _path, + '@Fblthp\n@Fblthp.foo\nlibrary foo;', + {}, + ); expect(metadata.testOn, equals(PlatformSelector.all)); }); test('parses a prefixed annotation', () { var metadata = parseMetadata( - _path, - "@foo.TestOn('vm')\n" - "import 'package:test/test.dart' as foo;", - {}); - expect(metadata.testOn.evaluate(SuitePlatform(Runtime.vm, compiler: null)), - isTrue); + _path, + "@foo.TestOn('vm')\n" + "import 'package:test/test.dart' as foo;", + {}, + ); expect( - metadata.testOn.evaluate(SuitePlatform(Runtime.chrome, compiler: null)), - isFalse); + metadata.testOn.evaluate(SuitePlatform(Runtime.vm, compiler: null)), + isTrue, + ); + expect( + metadata.testOn.evaluate(SuitePlatform(Runtime.chrome, compiler: null)), + isFalse, + ); }); group('@TestOn:', () { test('parses a valid annotation', () { var metadata = parseMetadata(_path, "@TestOn('vm')\nlibrary foo;", {}); expect( - metadata.testOn.evaluate(SuitePlatform(Runtime.vm, compiler: null)), - isTrue); + metadata.testOn.evaluate(SuitePlatform(Runtime.vm, compiler: null)), + isTrue, + ); expect( - metadata.testOn - .evaluate(SuitePlatform(Runtime.chrome, compiler: null)), - isFalse); + metadata.testOn.evaluate(SuitePlatform(Runtime.chrome, compiler: null)), + isFalse, + ); }); test('ignores a constructor named TestOn', () { - var metadata = - parseMetadata(_path, "@foo.TestOn('foo')\nlibrary foo;", {}); + var metadata = parseMetadata( + _path, + "@foo.TestOn('foo')\nlibrary foo;", + {}, + ); expect(metadata.testOn, equals(PlatformSelector.all)); }); group('throws an error for', () { test('multiple @TestOns', () { expect( - () => parseMetadata( - _path, "@TestOn('foo')\n@TestOn('bar')\nlibrary foo;", {}), - throwsFormatException); + () => parseMetadata( + _path, + "@TestOn('foo')\n@TestOn('bar')\nlibrary foo;", + {}, + ), + throwsFormatException, + ); }); }); }); @@ -80,13 +95,17 @@ void main() { library foo; ''', {}); expect( - metadata.timeout.duration, - equals(const Duration( - hours: 1, - minutes: 2, - seconds: 3, - milliseconds: 4, - microseconds: 5))); + metadata.timeout.duration, + equals( + const Duration( + hours: 1, + minutes: 2, + seconds: 3, + milliseconds: 4, + microseconds: 5, + ), + ), + ); }); test('parses a valid duration omitting const', () { @@ -101,13 +120,17 @@ library foo; library foo; ''', {}); expect( - metadata.timeout.duration, - equals(const Duration( - hours: 1, - minutes: 2, - seconds: 3, - milliseconds: 4, - microseconds: 5))); + metadata.timeout.duration, + equals( + const Duration( + hours: 1, + minutes: 2, + seconds: 3, + milliseconds: 4, + microseconds: 5, + ), + ), + ); }); test('parses a valid duration with an import prefix', () { @@ -121,13 +144,17 @@ library foo; import 'dart:core' as core; ''', {}); expect( - metadata.timeout.duration, - equals(const Duration( - hours: 1, - minutes: 2, - seconds: 3, - milliseconds: 4, - microseconds: 5))); + metadata.timeout.duration, + equals( + const Duration( + hours: 1, + minutes: 2, + seconds: 3, + milliseconds: 4, + microseconds: 5, + ), + ), + ); }); test('parses a valid int factor annotation', () { @@ -166,17 +193,24 @@ library foo; }); test('ignores a constructor named Timeout', () { - var metadata = - parseMetadata(_path, "@foo.Timeout('foo')\nlibrary foo;", {}); + var metadata = parseMetadata( + _path, + "@foo.Timeout('foo')\nlibrary foo;", + {}, + ); expect(metadata.timeout.scaleFactor, equals(1)); }); group('throws an error for', () { test('multiple @Timeouts', () { expect( - () => parseMetadata(_path, - '@Timeout.factor(1)\n@Timeout.factor(2)\nlibrary foo;', {}), - throwsFormatException); + () => parseMetadata( + _path, + '@Timeout.factor(1)\n@Timeout.factor(2)\nlibrary foo;', + {}, + ), + throwsFormatException, + ); }); }); }); @@ -202,9 +236,13 @@ library foo; group('throws an error for', () { test('multiple @Skips', () { expect( - () => parseMetadata( - _path, "@Skip('foo')\n@Skip('bar')\nlibrary foo;", {}), - throwsFormatException); + () => parseMetadata( + _path, + "@Skip('foo')\n@Skip('bar')\nlibrary foo;", + {}, + ), + throwsFormatException, + ); }); }); }); @@ -223,16 +261,24 @@ library foo; group('throws an error for', () { test('multiple @Tags', () { expect( - () => parseMetadata( - _path, "@Tags(['a'])\n@Tags(['b'])\nlibrary foo;", {}), - throwsFormatException); + () => parseMetadata( + _path, + "@Tags(['a'])\n@Tags(['b'])\nlibrary foo;", + {}, + ), + throwsFormatException, + ); }); test('String interpolation', () { expect( - () => parseMetadata( - _path, "@Tags(['\$a'])\nlibrary foo;\nconst a = 'a';", {}), - throwsFormatException); + () => parseMetadata( + _path, + "@Tags(['\$a'])\nlibrary foo;\nconst a = 'a';", + {}, + ), + throwsFormatException, + ); }); }); }); @@ -248,7 +294,9 @@ library foo;''', {}); var key = metadata.onPlatform.keys.first; expect( - key.evaluate(SuitePlatform(Runtime.chrome, compiler: null)), isTrue); + key.evaluate(SuitePlatform(Runtime.chrome, compiler: null)), + isTrue, + ); expect(key.evaluate(SuitePlatform(Runtime.vm, compiler: null)), isFalse); var value = metadata.onPlatform.values.first; expect(value.timeout.scaleFactor, equals(2)); @@ -256,7 +304,9 @@ library foo;''', {}); key = metadata.onPlatform.keys.last; expect(key.evaluate(SuitePlatform(Runtime.vm, compiler: null)), isTrue); expect( - key.evaluate(SuitePlatform(Runtime.chrome, compiler: null)), isFalse); + key.evaluate(SuitePlatform(Runtime.chrome, compiler: null)), + isFalse, + ); value = metadata.onPlatform.values.last; expect(value.skip, isTrue); expect(value.timeout.scaleFactor, equals(3)); @@ -273,7 +323,9 @@ import 'package:test/test.dart' as test; var key = metadata.onPlatform.keys.first; expect( - key.evaluate(SuitePlatform(Runtime.chrome, compiler: null)), isTrue); + key.evaluate(SuitePlatform(Runtime.chrome, compiler: null)), + isTrue, + ); expect(key.evaluate(SuitePlatform(Runtime.vm, compiler: null)), isFalse); var value = metadata.onPlatform.values.first; expect(value.timeout.scaleFactor, equals(2)); @@ -281,45 +333,66 @@ import 'package:test/test.dart' as test; key = metadata.onPlatform.keys.last; expect(key.evaluate(SuitePlatform(Runtime.vm, compiler: null)), isTrue); expect( - key.evaluate(SuitePlatform(Runtime.chrome, compiler: null)), isFalse); + key.evaluate(SuitePlatform(Runtime.chrome, compiler: null)), + isFalse, + ); value = metadata.onPlatform.values.last; expect(value.skip, isTrue); expect(value.timeout.scaleFactor, equals(3)); }); test('ignores a constructor named OnPlatform', () { - var metadata = - parseMetadata(_path, "@foo.OnPlatform('foo')\nlibrary foo;", {}); + var metadata = parseMetadata( + _path, + "@foo.OnPlatform('foo')\nlibrary foo;", + {}, + ); expect(metadata.testOn, equals(PlatformSelector.all)); }); group('throws an error for', () { test('a map with a unparseable key', () { expect( - () => parseMetadata( - _path, "@OnPlatform({'invalid': Skip()})\nlibrary foo;", {}), - throwsFormatException); + () => parseMetadata( + _path, + "@OnPlatform({'invalid': Skip()})\nlibrary foo;", + {}, + ), + throwsFormatException, + ); }); test('a map with an invalid value', () { expect( - () => parseMetadata(_path, - "@OnPlatform({'vm': const TestOn('vm')})\nlibrary foo;", {}), - throwsFormatException); + () => parseMetadata( + _path, + "@OnPlatform({'vm': const TestOn('vm')})\nlibrary foo;", + {}, + ), + throwsFormatException, + ); }); test('a map with an invalid value in a list', () { expect( - () => parseMetadata(_path, - "@OnPlatform({'vm': [const TestOn('vm')]})\nlibrary foo;", {}), - throwsFormatException); + () => parseMetadata( + _path, + "@OnPlatform({'vm': [const TestOn('vm')]})\nlibrary foo;", + {}, + ), + throwsFormatException, + ); }); test('multiple @OnPlatforms', () { expect( - () => parseMetadata( - _path, '@OnPlatform({})\n@OnPlatform({})\nlibrary foo;', {}), - throwsFormatException); + () => parseMetadata( + _path, + '@OnPlatform({})\n@OnPlatform({})\nlibrary foo;', + {}, + ), + throwsFormatException, + ); }); }); }); diff --git a/pkgs/test/test/runner/pause_after_load_test.dart b/pkgs/test/test/runner/pause_after_load_test.dart index faba441ee..8fd205d3e 100644 --- a/pkgs/test/test/runner/pause_after_load_test.dart +++ b/pkgs/test/test/runner/pause_after_load_test.dart @@ -17,9 +17,10 @@ import '../io.dart'; void main() { setUpAll(precompileTestExecutable); - test('pauses the test runner for each file until the user presses enter', - () async { - await d.file('test1.dart', ''' + test( + 'pauses the test runner for each file until the user presses enter', + () async { + await d.file('test1.dart', ''' import 'package:test/test.dart'; void main() { @@ -29,7 +30,7 @@ void main() { } ''').create(); - await d.file('test2.dart', ''' + await d.file('test2.dart', ''' import 'package:test/test.dart'; void main() { @@ -39,55 +40,83 @@ void main() { } ''').create(); - var test = await runTest( - ['--pause-after-load', '-p', 'chrome', 'test1.dart', 'test2.dart']); - await expectLater(test.stdout, emitsThrough('loaded test 1!')); - await expectLater(test.stdout, emitsThrough(equalsIgnoringWhitespace(''' + var test = await runTest([ + '--pause-after-load', + '-p', + 'chrome', + 'test1.dart', + 'test2.dart', + ]); + await expectLater(test.stdout, emitsThrough('loaded test 1!')); + await expectLater( + test.stdout, + emitsThrough( + equalsIgnoringWhitespace(''' The test runner is paused. Open the dev console in Chrome and set breakpoints. Once you're finished, return to this terminal and press Enter. - '''))); - - var nextLineFired = false; - unawaited(test.stdout.next.then(expectAsync1((line) { - expect(line, contains('+0: test1.dart: success')); - nextLineFired = true; - }))); - - // Wait a little bit to be sure that the tests don't start running without - // our input. - await Future.delayed(const Duration(seconds: 2)); - expect(nextLineFired, isFalse); - - test.stdin.writeln(); - - await expectLater(test.stdout, emitsThrough('loaded test 2!')); - await expectLater(test.stdout, emitsThrough(equalsIgnoringWhitespace(''' + '''), + ), + ); + + var nextLineFired = false; + unawaited( + test.stdout.next.then( + expectAsync1((line) { + expect(line, contains('+0: test1.dart: success')); + nextLineFired = true; + }), + ), + ); + + // Wait a little bit to be sure that the tests don't start running without + // our input. + await Future.delayed(const Duration(seconds: 2)); + expect(nextLineFired, isFalse); + + test.stdin.writeln(); + + await expectLater(test.stdout, emitsThrough('loaded test 2!')); + await expectLater( + test.stdout, + emitsThrough( + equalsIgnoringWhitespace(''' The test runner is paused. Open the dev console in Chrome and set breakpoints. Once you're finished, return to this terminal and press Enter. - '''))); - - nextLineFired = false; - unawaited(test.stdout.next.then(expectAsync1((line) { - expect(line, contains('+1: test2.dart: success')); - nextLineFired = true; - }))); - - // Wait a little bit to be sure that the tests don't start running without - // our input. - await Future.delayed(const Duration(seconds: 2)); - expect(nextLineFired, isFalse); - - test.stdin.writeln(); - await expectLater( - test.stdout, emitsThrough(contains('+2: All tests passed!'))); - await test.shouldExit(0); - }, tags: 'chrome'); - - test('pauses the test runner for each platform until the user presses enter', - () async { - await d.file('test.dart', ''' + '''), + ), + ); + + nextLineFired = false; + unawaited( + test.stdout.next.then( + expectAsync1((line) { + expect(line, contains('+1: test2.dart: success')); + nextLineFired = true; + }), + ), + ); + + // Wait a little bit to be sure that the tests don't start running without + // our input. + await Future.delayed(const Duration(seconds: 2)); + expect(nextLineFired, isFalse); + + test.stdin.writeln(); + await expectLater( + test.stdout, + emitsThrough(contains('+2: All tests passed!')), + ); + await test.shouldExit(0); + }, + tags: 'chrome', + ); + + test( + 'pauses the test runner for each platform until the user presses enter', + () async { + await d.file('test.dart', ''' import 'package:test/test.dart'; void main() { @@ -97,86 +126,115 @@ void main() { } ''').create(); - var test = await runTest([ - '--pause-after-load', - '-p', - 'firefox', - '-p', - 'chrome', - '-p', - 'vm', - 'test.dart' - ]); - await expectLater(test.stdout, emitsThrough('loaded test!')); - await expectLater(test.stdout, emitsThrough(equalsIgnoringWhitespace(''' + var test = await runTest([ + '--pause-after-load', + '-p', + 'firefox', + '-p', + 'chrome', + '-p', + 'vm', + 'test.dart', + ]); + await expectLater(test.stdout, emitsThrough('loaded test!')); + await expectLater( + test.stdout, + emitsThrough( + equalsIgnoringWhitespace(''' The test runner is paused. Open the dev console in Firefox and set breakpoints. Once you're finished, return to this terminal and press Enter. - '''))); - - var nextLineFired = false; - unawaited(test.stdout.next.then(expectAsync1((line) { - expect(line, contains('+0: [Firefox, Dart2Js] success')); - nextLineFired = true; - }))); - - // Wait a little bit to be sure that the tests don't start running without - // our input. - await Future.delayed(const Duration(seconds: 2)); - expect(nextLineFired, isFalse); - - test.stdin.writeln(); - - await expectLater(test.stdout, emitsThrough('loaded test!')); - await expectLater( + '''), + ), + ); + + var nextLineFired = false; + unawaited( + test.stdout.next.then( + expectAsync1((line) { + expect(line, contains('+0: [Firefox, Dart2Js] success')); + nextLineFired = true; + }), + ), + ); + + // Wait a little bit to be sure that the tests don't start running without + // our input. + await Future.delayed(const Duration(seconds: 2)); + expect(nextLineFired, isFalse); + + test.stdin.writeln(); + + await expectLater(test.stdout, emitsThrough('loaded test!')); + await expectLater( test.stdout, - emitsThrough(emitsInOrder([ - 'The test runner is paused. Open the dev console in Chrome and set ' - "breakpoints. Once you're finished, return to this terminal and " - 'press Enter.' - ]))); - - nextLineFired = false; - unawaited(test.stdout.next.then(expectAsync1((line) { - expect(line, contains('+1: [Chrome, Dart2Js] success')); - nextLineFired = true; - }))); - - // Wait a little bit to be sure that the tests don't start running without - // our input. - await Future.delayed(const Duration(seconds: 2)); - expect(nextLineFired, isFalse); - - test.stdin.writeln(); - await expectLater(test.stdout, emitsThrough('loaded test!')); - await expectLater( + emitsThrough( + emitsInOrder([ + 'The test runner is paused. Open the dev console in Chrome and set ' + "breakpoints. Once you're finished, return to this terminal and " + 'press Enter.', + ]), + ), + ); + + nextLineFired = false; + unawaited( + test.stdout.next.then( + expectAsync1((line) { + expect(line, contains('+1: [Chrome, Dart2Js] success')); + nextLineFired = true; + }), + ), + ); + + // Wait a little bit to be sure that the tests don't start running without + // our input. + await Future.delayed(const Duration(seconds: 2)); + expect(nextLineFired, isFalse); + + test.stdin.writeln(); + await expectLater(test.stdout, emitsThrough('loaded test!')); + await expectLater( test.stdout, - emitsThrough(emitsInOrder([ - 'The test runner is paused. Open the Observatory and set ' - "breakpoints. Once you're finished, return to this terminal " - 'and press Enter.' - ]))); - - nextLineFired = false; - unawaited(test.stdout.next.then(expectAsync1((line) { - expect(line, contains('+2: [VM, Kernel] success')); - nextLineFired = true; - }))); - - // Wait a little bit to be sure that the tests don't start running without - // our input. - await Future.delayed(const Duration(seconds: 2)); - expect(nextLineFired, isFalse); - - test.stdin.writeln(); - - await expectLater( - test.stdout, emitsThrough(contains('+3: All tests passed!'))); - await test.shouldExit(0); - }, tags: ['firefox', 'chrome', 'vm']); - - test('stops immediately if killed while paused', () async { - await d.file('test.dart', ''' + emitsThrough( + emitsInOrder([ + 'The test runner is paused. Open the Observatory and set ' + "breakpoints. Once you're finished, return to this terminal " + 'and press Enter.', + ]), + ), + ); + + nextLineFired = false; + unawaited( + test.stdout.next.then( + expectAsync1((line) { + expect(line, contains('+2: [VM, Kernel] success')); + nextLineFired = true; + }), + ), + ); + + // Wait a little bit to be sure that the tests don't start running without + // our input. + await Future.delayed(const Duration(seconds: 2)); + expect(nextLineFired, isFalse); + + test.stdin.writeln(); + + await expectLater( + test.stdout, + emitsThrough(contains('+3: All tests passed!')), + ); + await test.shouldExit(0); + }, + tags: ['firefox', 'chrome', 'vm'], + ); + + test( + 'stops immediately if killed while paused', + () async { + await d.file('test.dart', ''' import 'package:test/test.dart'; void main() { @@ -186,19 +244,31 @@ void main() { } ''').create(); - var test = - await runTest(['--pause-after-load', '-p', 'chrome', 'test.dart']); - await expectLater(test.stdout, emitsThrough('loaded test!')); - await expectLater(test.stdout, emitsThrough(equalsIgnoringWhitespace(''' + var test = await runTest([ + '--pause-after-load', + '-p', + 'chrome', + 'test.dart', + ]); + await expectLater(test.stdout, emitsThrough('loaded test!')); + await expectLater( + test.stdout, + emitsThrough( + equalsIgnoringWhitespace(''' The test runner is paused. Open the dev console in Chrome and set breakpoints. Once you're finished, return to this terminal and press Enter. - '''))); - - test.signal(ProcessSignal.sigterm); - await test.shouldExit(); - await expectLater(test.stderr, emitsDone); - }, tags: 'chrome', testOn: '!windows'); + '''), + ), + ); + + test.signal(ProcessSignal.sigterm); + await test.shouldExit(); + await expectLater(test.stderr, emitsDone); + }, + tags: 'chrome', + testOn: '!windows', + ); test('disables timeouts', () async { await d.file('test.dart', ''' @@ -215,20 +285,35 @@ void main() { } ''').create(); - var test = await runTest( - ['--pause-after-load', '-p', 'chrome', '-n', 'success', 'test.dart']); + var test = await runTest([ + '--pause-after-load', + '-p', + 'chrome', + '-n', + 'success', + 'test.dart', + ]); await expectLater(test.stdout, emitsThrough('loaded test 1!')); - await expectLater(test.stdout, emitsThrough(equalsIgnoringWhitespace(''' + await expectLater( + test.stdout, + emitsThrough( + equalsIgnoringWhitespace(''' The test runner is paused. Open the dev console in Chrome and set breakpoints. Once you're finished, return to this terminal and press Enter. - '''))); + '''), + ), + ); var nextLineFired = false; - unawaited(test.stdout.next.then(expectAsync1((line) { - expect(line, contains('+0: success')); - nextLineFired = true; - }))); + unawaited( + test.stdout.next.then( + expectAsync1((line) { + expect(line, contains('+0: success')); + nextLineFired = true; + }), + ), + ); // Wait a little bit to be sure that the tests don't start running without // our input. @@ -237,7 +322,9 @@ void main() { test.stdin.writeln(); await expectLater( - test.stdout, emitsThrough(contains('+1: All tests passed!'))); + test.stdout, + emitsThrough(contains('+1: All tests passed!')), + ); await test.shouldExit(0); }, tags: 'chrome'); @@ -255,20 +342,35 @@ void main() { } ''').create(); - var test = await runTest( - ['--pause-after-load', '-p', 'chrome', '-n', 'success', 'test.dart']); + var test = await runTest([ + '--pause-after-load', + '-p', + 'chrome', + '-n', + 'success', + 'test.dart', + ]); await expectLater(test.stdout, emitsThrough('loaded test 1!')); - await expectLater(test.stdout, emitsThrough(equalsIgnoringWhitespace(''' + await expectLater( + test.stdout, + emitsThrough( + equalsIgnoringWhitespace(''' The test runner is paused. Open the dev console in Chrome and set breakpoints. Once you're finished, return to this terminal and press Enter. - '''))); + '''), + ), + ); var nextLineFired = false; - unawaited(test.stdout.next.then(expectAsync1((line) { - expect(line, contains('+0: success')); - nextLineFired = true; - }))); + unawaited( + test.stdout.next.then( + expectAsync1((line) { + expect(line, contains('+0: success')); + nextLineFired = true; + }), + ), + ); // Wait a little bit to be sure that the tests don't start running without // our input. @@ -277,7 +379,9 @@ void main() { test.stdin.writeln(); await expectLater( - test.stdout, emitsThrough(contains('+1: All tests passed!'))); + test.stdout, + emitsThrough(contains('+1: All tests passed!')), + ); await test.shouldExit(0); }, tags: 'chrome'); } diff --git a/pkgs/test/test/runner/precompiled_test.dart b/pkgs/test/test/runner/precompiled_test.dart index 51dde28b9..717128529 100644 --- a/pkgs/test/test/runner/precompiled_test.dart +++ b/pkgs/test/test/runner/precompiled_test.dart @@ -27,18 +27,22 @@ void main() { await _precompileBrowserTest('test.dart'); }); - test('run a precompiled version of a test rather than recompiling', - () async { - var test = await runTest([ - '-p', - 'chrome', - '--precompiled=precompiled/', - 'test.dart', - ]); - expect(test.stdout, - containsInOrder(['+0: success', '+1: All tests passed!'])); - await test.shouldExit(0); - }); + test( + 'run a precompiled version of a test rather than recompiling', + () async { + var test = await runTest([ + '-p', + 'chrome', + '--precompiled=precompiled/', + 'test.dart', + ]); + expect( + test.stdout, + containsInOrder(['+0: success', '+1: All tests passed!']), + ); + await test.shouldExit(0); + }, + ); test('run two precompiled tests', () async { await _precompileBrowserTest('test_2.dart'); @@ -60,14 +64,15 @@ void main() { '--precompiled=precompiled/', 'test.dart', '-r', - 'json' + 'json', ]); expect( - test.stdout, - containsInOrder([ - '{"testID":3,"result":"success"', - '{"success":true,"type":"done"' - ])); + test.stdout, + containsInOrder([ + '{"testID":3,"result":"success"', + '{"success":true,"type":"done"', + ]), + ); await test.shouldExit(0); }); }, tags: const ['chrome']); @@ -83,43 +88,45 @@ void main() { internalBootstrapNodeTest(() => () => test("success", () { expect(true, isTrue); })); - }''') + }'''), ]).create(); await _writePackagesFile(); var jsPath = p.join(d.sandbox, 'test', 'test.dart.node_test.dart.js'); - var dart2js = await TestProcess.start( - Platform.resolvedExecutable, - [ - 'compile', - 'js', - '--packages=${await Isolate.packageConfig}', - p.join('test', 'test.dart'), - '--out=$jsPath', - ], - workingDirectory: d.sandbox); + var dart2js = await TestProcess.start(Platform.resolvedExecutable, [ + 'compile', + 'js', + '--packages=${await Isolate.packageConfig}', + p.join('test', 'test.dart'), + '--out=$jsPath', + ], workingDirectory: d.sandbox); await dart2js.shouldExit(0); var jsFile = File(jsPath); await jsFile.writeAsString( - preamble.getPreamble(minified: true) + await jsFile.readAsString()); + preamble.getPreamble(minified: true) + await jsFile.readAsString(), + ); await d.dir('test', [d.file('test.dart', 'invalid dart}')]).create(); }); - test('run a precompiled version of a test rather than recompiling', - () async { - var test = await runTest([ - '-p', - 'node', - '--precompiled', - d.sandbox, - p.join('test', 'test.dart') - ]); - expect(test.stdout, - containsInOrder(['+0: success', '+1: All tests passed!'])); - await test.shouldExit(0); - }); + test( + 'run a precompiled version of a test rather than recompiling', + () async { + var test = await runTest([ + '-p', + 'node', + '--precompiled', + d.sandbox, + p.join('test', 'test.dart'), + ]); + expect( + test.stdout, + containsInOrder(['+0: success', '+1: All tests passed!']), + ); + await test.shouldExit(0); + }, + ); test('can use the json reporter', () async { var test = await runTest([ @@ -129,14 +136,15 @@ void main() { d.sandbox, p.join('test', 'test.dart'), '-r', - 'json' + 'json', ]); expect( - test.stdout, - containsInOrder([ - '{"testID":3,"result":"success"', - '{"success":true,"type":"done"' - ])); + test.stdout, + containsInOrder([ + '{"testID":3,"result":"success"', + '{"success":true,"type":"done"', + ]), + ); await test.shouldExit(0); }); }, tags: const ['node']); @@ -165,10 +173,16 @@ void main() { }); test('run in the precompiled directory', () async { - var test = await runTest( - ['-p', 'vm', '--precompiled=${d.sandbox}', 'test/test.dart']); - expect(test.stdout, - containsInOrder(['+0: true is true', '+1: All tests passed!'])); + var test = await runTest([ + '-p', + 'vm', + '--precompiled=${d.sandbox}', + 'test/test.dart', + ]); + expect( + test.stdout, + containsInOrder(['+0: true is true', '+1: All tests passed!']), + ); await test.shouldExit(0); }); @@ -177,7 +191,7 @@ void main() { var snapshotProcess = await runDart([ '--snapshot_kind=script', '--snapshot=test/test.dart.vm_test.vm.app.dill', - 'test/test.dart.vm_test.dart' + 'test/test.dart.vm_test.dart', ]); await snapshotProcess.shouldExit(0); @@ -186,14 +200,21 @@ void main() { var testFile = File(p.join(d.sandbox, 'test', 'test.dart')); expect(await testFile.exists(), isTrue); var originalContent = await testFile.readAsString(); - await testFile - .writeAsString(originalContent.replaceAll('isTrue', 'isFalse')); + await testFile.writeAsString( + originalContent.replaceAll('isTrue', 'isFalse'), + ); // Actually invoke the test with the dill file. - var testProcess = await runTest( - ['-p', 'vm', '--precompiled=${d.sandbox}', 'test/test.dart']); - expect(testProcess.stdout, - containsInOrder(['+0: true is true', '+1: All tests passed!'])); + var testProcess = await runTest([ + '-p', + 'vm', + '--precompiled=${d.sandbox}', + 'test/test.dart', + ]); + expect( + testProcess.stdout, + containsInOrder(['+0: true is true', '+1: All tests passed!']), + ); await testProcess.shouldExit(0); }); @@ -204,14 +225,15 @@ void main() { '--precompiled=${d.sandbox}', 'test/test.dart', '-r', - 'json' + 'json', ]); expect( - test.stdout, - containsInOrder([ - '{"testID":3,"result":"success"', - '{"success":true,"type":"done"' - ])); + test.stdout, + containsInOrder([ + '{"testID":3,"result":"success"', + '{"success":true,"type":"done"', + ]), + ); await test.shouldExit(0); }); }); @@ -244,20 +266,17 @@ Future _precompileBrowserTest(String testPath) async { - ''') + '''), ]).create(); - var dart2js = await TestProcess.start( - Platform.resolvedExecutable, - [ - 'compile', - 'js', - ...Platform.executableArguments, - '--packages=${(await Isolate.packageConfig)!.toFilePath()}', - file.path, - '--out=precompiled/$testPath.browser_test.dart.js' - ], - workingDirectory: d.sandbox); + var dart2js = await TestProcess.start(Platform.resolvedExecutable, [ + 'compile', + 'js', + ...Platform.executableArguments, + '--packages=${(await Isolate.packageConfig)!.toFilePath()}', + file.path, + '--out=precompiled/$testPath.browser_test.dart.js', + ], workingDirectory: d.sandbox); await dart2js.shouldExit(0); await d.file(testPath, 'invalid dart}').create(); diff --git a/pkgs/test/test/runner/retry_test.dart b/pkgs/test/test/runner/retry_test.dart index 0e16fefe9..11c7c9a05 100644 --- a/pkgs/test/test/runner/retry_test.dart +++ b/pkgs/test/test/runner/retry_test.dart @@ -107,9 +107,10 @@ void main() { await test.shouldExit(0); }); - test('tests are not retried after they have already been reported successful', - () async { - await d.file('test.dart', ''' + test( + 'tests are not retried after they have already been reported successful', + () async { + await d.file('test.dart', ''' import 'dart:async'; import 'package:test/test.dart'; @@ -131,13 +132,16 @@ void main() { } ''').create(); - var test = await runTest(['test.dart']); - expect( + var test = await runTest(['test.dart']); + expect( test.stdout, emitsThrough( - contains('This test failed after it had already completed'))); - await test.shouldExit(1); - }); + contains('This test failed after it had already completed'), + ), + ); + await test.shouldExit(1); + }, + ); group('retries tests', () { test('and eventually passes for valid tests', () async { diff --git a/pkgs/test/test/runner/runner_test.dart b/pkgs/test/test/runner/runner_test.dart index 379e2a7f1..4a96ffdb7 100644 --- a/pkgs/test/test/runner/runner_test.dart +++ b/pkgs/test/test/runner/runner_test.dart @@ -121,7 +121,8 @@ Output: (auto-detected by default) '''; -final _runtimes = '[vm (default), chrome, firefox' +final _runtimes = + '[vm (default), chrome, firefox' '${Platform.isMacOS ? ', safari' : ''}' ', edge, node]'; @@ -159,11 +160,12 @@ $_usage'''); test('a non-existent file is passed', () async { var test = await runTest(['file']); expect( - test.stdout, - containsInOrder([ - '-1: loading file [E]', - 'Failed to load "file": Does not exist.' - ])); + test.stdout, + containsInOrder([ + '-1: loading file [E]', + 'Failed to load "file": Does not exist.', + ]), + ); await test.shouldExit(1); }); @@ -181,12 +183,13 @@ $_usage'''); var test = await runTest(['test.dart']); expect( - test.stdout, - containsInOrder([ - 'Failed to load "test.dart":', - "test.dart:1:9: Error: Expected ';' after this.", - 'invalid Dart file' - ])); + test.stdout, + containsInOrder([ + 'Failed to load "test.dart":', + "test.dart:1:9: Error: Expected ';' after this.", + 'invalid Dart file', + ]), + ); await test.shouldExit(1); }); @@ -198,12 +201,13 @@ $_usage'''); var test = await runTest(['test.dart']); expect( - test.stdout, - containsInOrder([ - '-1: loading test.dart [E]', - 'Failed to load "test.dart":', - "test.dart:1:14: Error: Expected ';' after this" - ])); + test.stdout, + containsInOrder([ + '-1: loading test.dart [E]', + 'Failed to load "test.dart":', + "test.dart:1:14: Error: Expected ';' after this", + ]), + ); await test.shouldExit(1); }); @@ -215,13 +219,14 @@ $_usage'''); var test = await runTest(['test.dart']); expect( - test.stdout, - containsInOrder([ - '-1: loading test.dart [E]', - 'Failed to load "test.dart":', - "test.dart:1:8: Error: Expected a declaration, but got ')'", - '@TestOn)', - ])); + test.stdout, + containsInOrder([ + '-1: loading test.dart [E]', + 'Failed to load "test.dart":', + "test.dart:1:8: Error: Expected a declaration, but got ')'", + '@TestOn)', + ]), + ); await test.shouldExit(1); }); @@ -231,14 +236,15 @@ $_usage'''); var test = await runTest(['test.dart']); expect( - test.stdout, - containsInOrder([ - '-1: loading test.dart [E]', - 'Failed to load "test.dart":', - 'Error on line 1, column 10: Undefined variable.', - "@TestOn('zim')", - ' ^^^' - ])); + test.stdout, + containsInOrder([ + '-1: loading test.dart [E]', + 'Failed to load "test.dart":', + 'Error on line 1, column 10: Undefined variable.', + "@TestOn('zim')", + ' ^^^', + ]), + ); await test.shouldExit(1); }); @@ -247,11 +253,12 @@ $_usage'''); var test = await runTest(['test.dart']); expect( - test.stdout, - containsInOrder([ - '-1: loading test.dart [E]', - 'Failed to load "test.dart": oh no' - ])); + test.stdout, + containsInOrder([ + '-1: loading test.dart [E]', + 'Failed to load "test.dart": oh no', + ]), + ); await test.shouldExit(1); }); @@ -259,17 +266,16 @@ $_usage'''); await d.file('test.dart', 'void foo() {}').create(); var test = await runTest(['test.dart']); + expect(test.stdout, emitsThrough(contains('-1: loading test.dart [E]'))); expect( - test.stdout, - emitsThrough( - contains('-1: loading test.dart [E]'), - )); - expect( - test.stdout, - emitsThrough(anyOf([ + test.stdout, + emitsThrough( + anyOf([ contains("Error: Getter not found: 'main'"), contains("Error: Undefined name 'main'"), - ]))); + ]), + ), + ); await test.shouldExit(1); }); @@ -280,8 +286,9 @@ $_usage'''); expect(test.stdout, emitsThrough(contains('-1: loading test.dart [E]'))); expect( - test.stdout, - emitsThrough(anyOf([ + test.stdout, + emitsThrough( + anyOf([ contains( "A value of type 'int' can't be assigned to a variable of type " "'Function'", @@ -290,7 +297,9 @@ $_usage'''); "A value of type 'int' can't be returned from a function with " "return type 'Function'", ), - ]))); + ]), + ), + ); await test.shouldExit(1); }); @@ -300,11 +309,12 @@ $_usage'''); var test = await runTest(['test.dart']); expect( - test.stdout, - containsInOrder([ - '-1: loading test.dart [E]', - 'Failed to load "test.dart": Top-level main() function takes arguments.' - ])); + test.stdout, + containsInOrder([ + '-1: loading test.dart [E]', + 'Failed to load "test.dart": Top-level main() function takes arguments.', + ]), + ); await test.shouldExit(1); }); @@ -313,13 +323,14 @@ $_usage'''); var test = await runTest(['test.dart', 'nonexistent.dart']); expect( - await test.stdoutStream().toList(), - containsAll([ - contains('loading nonexistent.dart [E]'), - contains('Failed to load "nonexistent.dart": Does not exist'), - contains('loading test.dart [E]'), - contains('Failed to load "test.dart"'), - ])); + await test.stdoutStream().toList(), + containsAll([ + contains('loading nonexistent.dart [E]'), + contains('Failed to load "nonexistent.dart": Does not exist'), + contains('loading test.dart [E]'), + contains('Failed to load "test.dart"'), + ]), + ); await test.shouldExit(1); }); @@ -349,10 +360,11 @@ $_usage'''); test('defaulting to the test directory', () async { await d .dir( - 'test', - Iterable.generate(3, (i) { - return d.file('${i}_test.dart', _success); - })) + 'test', + Iterable.generate(3, (i) { + return d.file('${i}_test.dart', _success); + }), + ) .create(); var test = await runTest([]); @@ -400,13 +412,15 @@ $_usage'''); await test.shouldExit(0); }); - test('with platform specific relative paths containing query params', - () async { - await d.dir('foo', [d.file('test.dart', _success)]).create(); - var test = await runTest(['${p.join('foo', 'test.dart')}?line=6']); - expect(test.stdout, emitsThrough(contains('+1: All tests passed!'))); - await test.shouldExit(0); - }); + test( + 'with platform specific relative paths containing query params', + () async { + await d.dir('foo', [d.file('test.dart', _success)]).create(); + var test = await runTest(['${p.join('foo', 'test.dart')}?line=6']); + expect(test.stdout, emitsThrough(contains('+1: All tests passed!'))); + await test.shouldExit(0); + }, + ); }); group('runs successful tests with async setup', () { @@ -451,13 +465,14 @@ $_usage'''); var test = await runTest(['test.dart']); expect( - test.stdout, - containsInOrder([ - '00:00 +0: failure', - '00:00 +0 -1: failure [E]', - 'oh no', - 'test.dart 8:7 main..', - ])); + test.stdout, + containsInOrder([ + '00:00 +0: failure', + '00:00 +0 -1: failure [E]', + 'oh no', + 'test.dart 8:7 main..', + ]), + ); await test.shouldExit(1); }); @@ -482,10 +497,11 @@ $_usage'''); test('defaulting to the test directory', () async { await d .dir( - 'test', - Iterable.generate(3, (i) { - return d.file('${i}_test.dart', _failure); - })) + 'test', + Iterable.generate(3, (i) { + return d.file('${i}_test.dart', _failure); + }), + ) .create(); var test = await runTest([]); @@ -589,9 +605,12 @@ void main() { var test = await runTest(['test.dart']); expect( - test.stdout, - containsInOrder( - ['Test timed out after 0 seconds.', '-1: Some tests failed.'])); + test.stdout, + containsInOrder([ + 'Test timed out after 0 seconds.', + '-1: Some tests failed.', + ]), + ); await test.shouldExit(1); }); @@ -717,9 +736,12 @@ void main() { var test = await runTest(['test.dart']); expect( - test.stdout, - containsInOrder( - ['Test timed out after 0 seconds.', '-1: Some tests failed.'])); + test.stdout, + containsInOrder([ + 'Test timed out after 0 seconds.', + '-1: Some tests failed.', + ]), + ); await test.shouldExit(1); }); @@ -752,10 +774,12 @@ void main() { await test.shouldExit(); }); - group('runs tests successfully more than once when calling runTests', () { - test('defined in a single file', () async { - await d.file('test.dart', _success).create(); - await d.file('runner.dart', ''' + group( + 'runs tests successfully more than once when calling runTests', + () { + test('defined in a single file', () async { + await d.file('test.dart', _success).create(); + await d.file('runner.dart', ''' import 'package:test_core/src/executable.dart' as test; void main(List args) async { @@ -763,35 +787,43 @@ void main(List args) async { await test.runTests(args); test.completeShutdown(); }''').create(); - var test = await runDart([ - 'runner.dart', - '--no-color', - '--reporter', - 'compact', - '--', - 'test.dart', - ], description: 'dart runner.dart -- test.dart'); - expect( + var test = await runDart([ + 'runner.dart', + '--no-color', + '--reporter', + 'compact', + '--', + 'test.dart', + ], description: 'dart runner.dart -- test.dart'); + expect( test.stdout, - emitsThrough(containsInOrder([ - '+0: loading test.dart', - '+0: success', - '+1: success', - 'All tests passed!' - ]))); - expect( + emitsThrough( + containsInOrder([ + '+0: loading test.dart', + '+0: success', + '+1: success', + 'All tests passed!', + ]), + ), + ); + expect( test.stdout, - emitsThrough(containsInOrder([ - '+0: loading test.dart', - '+0: success', - '+1: success', - '+1: All tests passed!', - ]))); - await test.shouldExit(0); - }); - }, onPlatform: const { - 'windows': Skip('https://github.com/dart-lang/test/issues/1615') - }); + emitsThrough( + containsInOrder([ + '+0: loading test.dart', + '+0: success', + '+1: success', + '+1: All tests passed!', + ]), + ), + ); + await test.shouldExit(0); + }); + }, + onPlatform: const { + 'windows': Skip('https://github.com/dart-lang/test/issues/1615'), + }, + ); group('language experiments', () { group('are inherited from the executable arguments', () { @@ -812,19 +844,27 @@ void main() { }); for (var platform in ['vm', 'chrome']) { - test('on the $platform platform', () async { - var test = await runTest(['test.dart', '-p', platform], - vmArgs: ['--enable-experiment=non-nullable']); - - await expectLater(test.stdout, emitsThrough(contains('int x;'))); - await test.shouldExit(1); - - // Test that they can be removed on subsequent runs as well - test = await runTest(['test.dart', '-p', platform]); - await expectLater( - test.stdout, emitsThrough(contains('+1: All tests passed!'))); - await test.shouldExit(0); - }, skip: 'https://github.com/dart-lang/test/issues/1813'); + test( + 'on the $platform platform', + () async { + var test = await runTest( + ['test.dart', '-p', platform], + vmArgs: ['--enable-experiment=non-nullable'], + ); + + await expectLater(test.stdout, emitsThrough(contains('int x;'))); + await test.shouldExit(1); + + // Test that they can be removed on subsequent runs as well + test = await runTest(['test.dart', '-p', platform]); + await expectLater( + test.stdout, + emitsThrough(contains('+1: All tests passed!')), + ); + await test.shouldExit(0); + }, + skip: 'https://github.com/dart-lang/test/issues/1813', + ); } }); }); @@ -856,16 +896,28 @@ void main() { test('on the VM platform', () async { var test = await runTest(['-p', 'vm', 'a_test.dart', 'b_test.dart']); await expectLater( - test.stdout, emitsThrough(contains('+2: All tests passed!'))); + test.stdout, + emitsThrough(contains('+2: All tests passed!')), + ); await test.shouldExit(0); }); - test('on the browser platform', () async { - var test = - await runTest(['-p', 'vm,chrome', 'a_test.dart', 'b_test.dart']); - await expectLater( - test.stdout, emitsThrough(contains('+3: All tests passed!'))); - await test.shouldExit(0); - }, skip: 'https://github.com/dart-lang/test/issues/1803'); + test( + 'on the browser platform', + () async { + var test = await runTest([ + '-p', + 'vm,chrome', + 'a_test.dart', + 'b_test.dart', + ]); + await expectLater( + test.stdout, + emitsThrough(contains('+3: All tests passed!')), + ); + await test.shouldExit(0); + }, + skip: 'https://github.com/dart-lang/test/issues/1803', + ); }); } diff --git a/pkgs/test/test/runner/shard_test.dart b/pkgs/test/test/runner/shard_test.dart index 8d4be8604..b255da9c8 100644 --- a/pkgs/test/test/runner/shard_test.dart +++ b/pkgs/test/test/runner/shard_test.dart @@ -32,39 +32,45 @@ void main() { } ''').create(); - var test = - await runTest(['test.dart', '--shard-index=0', '--total-shards=3']); + var test = await runTest([ + 'test.dart', + '--shard-index=0', + '--total-shards=3', + ]); expect( - test.stdout, - containsInOrder([ - '+0: test 1', - '+1: test 2', - '+2: test 3', - '+3: All tests passed!' - ])); + test.stdout, + containsInOrder([ + '+0: test 1', + '+1: test 2', + '+2: test 3', + '+3: All tests passed!', + ]), + ); await test.shouldExit(0); test = await runTest(['test.dart', '--shard-index=1', '--total-shards=3']); expect( - test.stdout, - containsInOrder([ - '+0: test 4', - '+1: test 5', - '+2: test 6', - '+3: test 7', - '+4: All tests passed!' - ])); + test.stdout, + containsInOrder([ + '+0: test 4', + '+1: test 5', + '+2: test 6', + '+3: test 7', + '+4: All tests passed!', + ]), + ); await test.shouldExit(0); test = await runTest(['test.dart', '--shard-index=2', '--total-shards=3']); expect( - test.stdout, - containsInOrder([ - '+0: test 8', - '+1: test 9', - '+2: test 10', - '+3: All tests passed!' - ])); + test.stdout, + containsInOrder([ + '+0: test 8', + '+1: test 9', + '+2: test 10', + '+3: All tests passed!', + ]), + ); await test.shouldExit(0); }); @@ -91,44 +97,59 @@ void main() { var test = await runTest(['.', '--shard-index=0', '--total-shards=3']); expect( - test.stdout, - emitsInOrder([ - emitsAnyOf([ - containsInOrder( - ['+0: ./1_test.dart: test 1.1', '+1: ./2_test.dart: test 2.1']), - containsInOrder( - ['+0: ./2_test.dart: test 2.1', '+1: ./1_test.dart: test 1.1']) + test.stdout, + emitsInOrder([ + emitsAnyOf([ + containsInOrder([ + '+0: ./1_test.dart: test 1.1', + '+1: ./2_test.dart: test 2.1', ]), - contains('+2: All tests passed!') - ])); + containsInOrder([ + '+0: ./2_test.dart: test 2.1', + '+1: ./1_test.dart: test 1.1', + ]), + ]), + contains('+2: All tests passed!'), + ]), + ); await test.shouldExit(0); test = await runTest(['.', '--shard-index=1', '--total-shards=3']); expect( - test.stdout, - emitsInOrder([ - emitsAnyOf([ - containsInOrder( - ['+0: ./1_test.dart: test 1.2', '+1: ./2_test.dart: test 2.2']), - containsInOrder( - ['+0: ./2_test.dart: test 2.2', '+1: ./1_test.dart: test 1.2']) + test.stdout, + emitsInOrder([ + emitsAnyOf([ + containsInOrder([ + '+0: ./1_test.dart: test 1.2', + '+1: ./2_test.dart: test 2.2', + ]), + containsInOrder([ + '+0: ./2_test.dart: test 2.2', + '+1: ./1_test.dart: test 1.2', ]), - contains('+2: All tests passed!') - ])); + ]), + contains('+2: All tests passed!'), + ]), + ); await test.shouldExit(0); test = await runTest(['.', '--shard-index=2', '--total-shards=3']); expect( - test.stdout, - emitsInOrder([ - emitsAnyOf([ - containsInOrder( - ['+0: ./1_test.dart: test 1.3', '+1: ./2_test.dart: test 2.3']), - containsInOrder( - ['+0: ./2_test.dart: test 2.3', '+1: ./1_test.dart: test 1.3']) + test.stdout, + emitsInOrder([ + emitsAnyOf([ + containsInOrder([ + '+0: ./1_test.dart: test 1.3', + '+1: ./2_test.dart: test 2.3', ]), - contains('+2: All tests passed!') - ])); + containsInOrder([ + '+0: ./2_test.dart: test 2.3', + '+1: ./1_test.dart: test 1.3', + ]), + ]), + contains('+2: All tests passed!'), + ]), + ); await test.shouldExit(0); }); @@ -142,8 +163,11 @@ void main() { } ''').create(); - var test = - await runTest(['test.dart', '--shard-index=1', '--total-shards=3']); + var test = await runTest([ + 'test.dart', + '--shard-index=1', + '--total-shards=3', + ]); expect(test.stdout, emitsThrough('No tests ran.')); await test.shouldExit(79); }); @@ -152,18 +176,18 @@ void main() { test('--shard-index is provided alone', () async { var test = await runTest(['--shard-index=1']); expect( - test.stderr, - emits( - '--shard-index and --total-shards may only be passed together.')); + test.stderr, + emits('--shard-index and --total-shards may only be passed together.'), + ); await test.shouldExit(exit_codes.usage); }); test('--total-shards is provided alone', () async { var test = await runTest(['--total-shards=5']); expect( - test.stderr, - emits( - '--shard-index and --total-shards may only be passed together.')); + test.stderr, + emits('--shard-index and --total-shards may only be passed together.'), + ); await test.shouldExit(exit_codes.usage); }); @@ -175,8 +199,10 @@ void main() { test('--shard-index is equal to --total-shards', () async { var test = await runTest(['--shard-index=5', '--total-shards=5']); - expect(test.stderr, - emits('--shard-index must be less than --total-shards.')); + expect( + test.stderr, + emits('--shard-index must be less than --total-shards.'), + ); await test.shouldExit(exit_codes.usage); }); }); diff --git a/pkgs/test/test/runner/signal_test.dart b/pkgs/test/test/runner/signal_test.dart index d14ee9722..5bda9dd1e 100644 --- a/pkgs/test/test/runner/signal_test.dart +++ b/pkgs/test/test/runner/signal_test.dart @@ -49,7 +49,9 @@ void main() { var test = await _runTest(['-p', 'chrome', 'test.dart']); await expectLater( - test.stdout, emitsThrough(endsWith('loading test.dart'))); + test.stdout, + emitsThrough(endsWith('loading test.dart')), + ); await signalAndQuit(test); expectTempDirEmpty(skip: 'Failing on Travis.'); @@ -221,9 +223,11 @@ void main() { } Future _runTest(List args, {bool forwardStdio = false}) => - runTest(args, - environment: {'_UNITTEST_TEMP_DIR': _tempDir}, - forwardStdio: forwardStdio); + runTest( + args, + environment: {'_UNITTEST_TEMP_DIR': _tempDir}, + forwardStdio: forwardStdio, + ); Future signalAndQuit(TestProcess test) async { test.signal(ProcessSignal.sigterm); diff --git a/pkgs/test/test/runner/skip_expect_test.dart b/pkgs/test/test/runner/skip_expect_test.dart index e22332ce2..756a78f56 100644 --- a/pkgs/test/test/runner/skip_expect_test.dart +++ b/pkgs/test/test/runner/skip_expect_test.dart @@ -40,12 +40,13 @@ void main() { var test = await runTest(['test.dart']); expect( - test.stdout, - containsInOrder([ - '+0: skipped', - ' Skip expect: is failing', - '~1: All tests skipped.' - ])); + test.stdout, + containsInOrder([ + '+0: skipped', + ' Skip expect: is failing', + '~1: All tests skipped.', + ]), + ); await test.shouldExit(0); }); @@ -61,12 +62,13 @@ void main() { var test = await runTest(['test.dart']); expect( - test.stdout, - containsInOrder([ - '+0: skipped', - ' Skip expect (1 is 2).', - '~1: All tests skipped.' - ])); + test.stdout, + containsInOrder([ + '+0: skipped', + ' Skip expect (1 is 2).', + '~1: All tests skipped.', + ]), + ); await test.shouldExit(0); }); @@ -81,12 +83,13 @@ void main() { var test = await runTest(['test.dart']); expect( - test.stdout, - containsInOrder([ - '+0: skipped', - ' Skip expect (<2>).', - '~1: All tests skipped.' - ])); + test.stdout, + containsInOrder([ + '+0: skipped', + ' Skip expect (<2>).', + '~1: All tests skipped.', + ]), + ); await test.shouldExit(0); }); @@ -104,15 +107,16 @@ void main() { var test = await runTest(['test.dart']); expect( - test.stdout, - containsInOrder([ - '+0: failing', - ' Skip expect (<2>).', - '+0 -1: failing [E]', - ' Expected: <2>', - ' Actual: <1>', - '+0 -1: Some tests failed.' - ])); + test.stdout, + containsInOrder([ + '+0: failing', + ' Skip expect (<2>).', + '+0 -1: failing [E]', + ' Expected: <2>', + ' Actual: <1>', + '+0 -1: Some tests failed.', + ]), + ); await test.shouldExit(1); }); }); @@ -131,12 +135,13 @@ void main() { var test = await runTest(['test.dart']); expect( - test.stdout, - containsInOrder([ - '+0: skipped', - ' some reason', - '~1: All tests skipped.', - ])); + test.stdout, + containsInOrder([ + '+0: skipped', + ' some reason', + '~1: All tests skipped.', + ]), + ); await test.shouldExit(0); }); @@ -154,15 +159,16 @@ void main() { var test = await runTest(['test.dart']); expect( - test.stdout, - containsInOrder([ - '+0: failing', - ' some reason', - '+0 -1: failing [E]', - ' Expected: <2>', - ' Actual: <1>', - '+0 -1: Some tests failed.' - ])); + test.stdout, + containsInOrder([ + '+0: failing', + ' some reason', + '+0 -1: failing [E]', + ' Expected: <2>', + ' Actual: <1>', + '+0 -1: Some tests failed.', + ]), + ); await test.shouldExit(1); }); @@ -193,16 +199,17 @@ void main() { var test = await runTest(['test.dart']); expect( - test.stdout, - containsInOrder([ - '+0: skip', - '+1: wait', - '+0 -1: skip', - 'This test was marked as skipped after it had already completed.', - 'Make sure to use a matching library which informs the test runner', - 'of pending async work.', - '+1 -1: Some tests failed.' - ])); + test.stdout, + containsInOrder([ + '+0: skip', + '+1: wait', + '+0 -1: skip', + 'This test was marked as skipped after it had already completed.', + 'Make sure to use a matching library which informs the test runner', + 'of pending async work.', + '+1 -1: Some tests failed.', + ]), + ); await test.shouldExit(1); }); }); @@ -235,16 +242,17 @@ void main() { var test = await runTest(['test.dart']); expect( - test.stdout, - containsInOrder([ - '+0: skip', - '+1: wait', - '+0 -1: skip', - 'This test was marked as skipped after it had already completed.', - 'Make sure to use a matching library which informs the test runner', - 'of pending async work.', - '+1 -1: Some tests failed.' - ])); + test.stdout, + containsInOrder([ + '+0: skip', + '+1: wait', + '+0 -1: skip', + 'This test was marked as skipped after it had already completed.', + 'Make sure to use a matching library which informs the test runner', + 'of pending async work.', + '+1 -1: Some tests failed.', + ]), + ); await test.shouldExit(1); }); @@ -261,9 +269,12 @@ void main() { var test = await runTest(['test.dart']); expect( - test.stdout, - containsInOrder( - ['Invalid argument (skip)', '+0 -1: Some tests failed.'])); + test.stdout, + containsInOrder([ + 'Invalid argument (skip)', + '+0 -1: Some tests failed.', + ]), + ); await test.shouldExit(1); }); }); diff --git a/pkgs/test/test/runner/tag_test.dart b/pkgs/test/test/runner/tag_test.dart index da9dca76f..76ae314ea 100644 --- a/pkgs/test/test/runner/tag_test.dart +++ b/pkgs/test/test/runner/tag_test.dart @@ -199,11 +199,15 @@ void main() { var test = await runTest(['test.dart']); expect( - test.stdout, - emitsThrough(lines( - 'Warning: Tags were used that weren\'t specified in dart_test.yaml.\n' - ' a was used in the test "foo"\n' - ' b was used in the test "foo"'))); + test.stdout, + emitsThrough( + lines( + 'Warning: Tags were used that weren\'t specified in dart_test.yaml.\n' + ' a was used in the test "foo"\n' + ' b was used in the test "foo"', + ), + ), + ); await test.shouldExit(0); }); @@ -219,12 +223,16 @@ void main() { var test = await runTest(['test.dart']); expect( - test.stdout, - emitsThrough(lines( - 'Warning: A tag was used that wasn\'t specified in dart_test.yaml.\n' - ' a was used in:\n' - ' the test "foo"\n' - ' the test "bar"'))); + test.stdout, + emitsThrough( + lines( + 'Warning: A tag was used that wasn\'t specified in dart_test.yaml.\n' + ' a was used in:\n' + ' the test "foo"\n' + ' the test "bar"', + ), + ), + ); await test.shouldExit(0); }); @@ -242,10 +250,14 @@ void main() { var test = await runTest(['test.dart']); expect( - test.stdout, - emitsThrough(lines( - 'Warning: A tag was used that wasn\'t specified in dart_test.yaml.\n' - ' a was used in the group "group"'))); + test.stdout, + emitsThrough( + lines( + 'Warning: A tag was used that wasn\'t specified in dart_test.yaml.\n' + ' a was used in the group "group"', + ), + ), + ); await test.shouldExit(0); }); @@ -262,10 +274,14 @@ void main() { var test = await runTest(['test.dart']); expect( - test.stdout, - emitsThrough(lines( - 'Warning: A tag was used that wasn\'t specified in dart_test.yaml.\n' - ' a was used in the suite itself'))); + test.stdout, + emitsThrough( + lines( + 'Warning: A tag was used that wasn\'t specified in dart_test.yaml.\n' + ' a was used in the suite itself', + ), + ), + ); await test.shouldExit(0); }); @@ -280,10 +296,14 @@ void main() { var test = await runTest(['-p', 'vm,chrome', 'test.dart']); expect( - test.stdout, - emitsThrough(lines( - 'Warning: A tag was used that wasn\'t specified in dart_test.yaml.\n' - ' a was used in the test "foo"'))); + test.stdout, + emitsThrough( + lines( + 'Warning: A tag was used that wasn\'t specified in dart_test.yaml.\n' + ' a was used in the test "foo"', + ), + ), + ); expect(test.stdout, neverEmits(startsWith('Warning:'))); await test.shouldExit(0); }, tags: 'chrome'); @@ -301,10 +321,12 @@ void main() { var test = await runTest(['test.dart']); expect( - test.stdout, - emitsThrough( - ' Failed to load "test.dart": Invalid argument(s): Invalid tag "a ' - 'b". Tags must be (optionally hyphenated) Dart identifiers.')); + test.stdout, + emitsThrough( + ' Failed to load "test.dart": Invalid argument(s): Invalid tag "a ' + 'b". Tags must be (optionally hyphenated) Dart identifiers.', + ), + ); await test.shouldExit(1); }); @@ -321,10 +343,12 @@ void main() { var test = await runTest(['test.dart']); expect( - test.stdout, - emitsThrough( - ' Failed to load "test.dart": Invalid argument(s): Invalid tag "a ' - 'b". Tags must be (optionally hyphenated) Dart identifiers.')); + test.stdout, + emitsThrough( + ' Failed to load "test.dart": Invalid argument(s): Invalid tag "a ' + 'b". Tags must be (optionally hyphenated) Dart identifiers.', + ), + ); await test.shouldExit(1); }); @@ -341,10 +365,15 @@ void main() { var test = await runTest(['test.dart']); expect( - test.stdout, - emitsThrough(lines(' Failed to load "test.dart":\n' - ' Error on line 1, column 22: Invalid tag name. Tags must be ' - '(optionally hyphenated) Dart identifiers.'))); + test.stdout, + emitsThrough( + lines( + ' Failed to load "test.dart":\n' + ' Error on line 1, column 22: Invalid tag name. Tags must be ' + '(optionally hyphenated) Dart identifiers.', + ), + ), + ); await test.shouldExit(1); }); }); @@ -353,18 +382,19 @@ void main() { /// Returns a [StreamMatcher] that asserts that a test emits warnings for [tags] /// in order. StreamMatcher tagWarnings(List tags) => emitsInOrder([ - emitsThrough( - "Warning: ${tags.length == 1 ? 'A tag was' : 'Tags were'} used that " - "${tags.length == 1 ? "wasn't" : "weren't"} specified in " - 'dart_test.yaml.'), - - for (var tag in tags) emitsThrough(startsWith(' $tag was used in')), - - // Consume until the end of the warning block, and assert that it has no - // further tags than the ones we specified. - mayEmitMultiple(isNot(anyOf([contains(' was used in'), isEmpty]))), - isEmpty, - ]); + emitsThrough( + "Warning: ${tags.length == 1 ? 'A tag was' : 'Tags were'} used that " + "${tags.length == 1 ? "wasn't" : "weren't"} specified in " + 'dart_test.yaml.', + ), + + for (var tag in tags) emitsThrough(startsWith(' $tag was used in')), + + // Consume until the end of the warning block, and assert that it has no + // further tags than the ones we specified. + mayEmitMultiple(isNot(anyOf([contains(' was used in'), isEmpty]))), + isEmpty, +]); /// Returns a [StreamMatcher] that matches the lines of [string] in order. StreamMatcher lines(String string) => emitsInOrder(string.split('\n')); diff --git a/pkgs/test/test/runner/test_chain_test.dart b/pkgs/test/test/runner/test_chain_test.dart index ad814de76..f3b882f60 100644 --- a/pkgs/test/test/runner/test_chain_test.dart +++ b/pkgs/test/test/runner/test_chain_test.dart @@ -33,12 +33,13 @@ void main() { test('folds packages contained in the except list', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'fold_stack_frames': { - 'except': ['stream_channel'] - } - })) + 'dart_test.yaml', + jsonEncode({ + 'fold_stack_frames': { + 'except': ['stream_channel'], + }, + }), + ) .create(); var test = await runTest(['test.dart']); expect(test.stdoutStream(), neverEmits(contains('package:stream_channel'))); @@ -55,12 +56,13 @@ void main() { test('folds all packages not contained in the only list', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'fold_stack_frames': { - 'only': ['test'] - } - })) + 'dart_test.yaml', + jsonEncode({ + 'fold_stack_frames': { + 'only': ['test'], + }, + }), + ) .create(); var test = await runTest(['test.dart']); expect(test.stdoutStream(), neverEmits(contains('package:stream_channel'))); @@ -70,12 +72,13 @@ void main() { test('does not fold packages in the only list', () async { await d .file( - 'dart_test.yaml', - jsonEncode({ - 'fold_stack_frames': { - 'only': ['test_api'] - } - })) + 'dart_test.yaml', + jsonEncode({ + 'fold_stack_frames': { + 'only': ['test_api'], + }, + }), + ) .create(); var test = await runTest(['test.dart']); expect(test.stdoutStream(), emitsThrough(contains('package:test_api'))); diff --git a/pkgs/test/test/runner/test_on_test.dart b/pkgs/test/test/runner/test_on_test.dart index f89d92f0a..81744fad4 100644 --- a/pkgs/test/test/runner/test_on_test.dart +++ b/pkgs/test/test/runner/test_on_test.dart @@ -21,14 +21,17 @@ void main() { setUpAll(() async { await precompileTestExecutable(); - currentPackageConfig = - await loadPackageConfigUri((await Isolate.packageConfig)!); + currentPackageConfig = await loadPackageConfigUri( + (await Isolate.packageConfig)!, + ); }); setUp(() async { await d - .file('package_config.json', - jsonEncode(PackageConfig.toJson(currentPackageConfig))) + .file( + 'package_config.json', + jsonEncode(PackageConfig.toJson(currentPackageConfig)), + ) .create(); }); @@ -57,24 +60,37 @@ void main() { await test.shouldExit(0); }); - test("doesn't run a test suite on a non-matching operating system", - () async { - await _writeTestFile('os_test.dart', - suiteTestOn: otherOS, loadable: false); - - var test = await runTest(['os_test.dart']); - expect(test.stdout, emitsThrough(contains('No tests ran.'))); - await test.shouldExit(79); - }); + test( + "doesn't run a test suite on a non-matching operating system", + () async { + await _writeTestFile( + 'os_test.dart', + suiteTestOn: otherOS, + loadable: false, + ); + + var test = await runTest(['os_test.dart']); + expect(test.stdout, emitsThrough(contains('No tests ran.'))); + await test.shouldExit(79); + }, + ); test('only loads matching files when loading as a group', () async { await _writeTestFile('vm_test.dart', suiteTestOn: 'vm'); - await _writeTestFile('browser_test.dart', - suiteTestOn: 'browser', loadable: false); - await _writeTestFile('this_os_test.dart', - suiteTestOn: currentOS.identifier); - await _writeTestFile('other_os_test.dart', - suiteTestOn: otherOS, loadable: false); + await _writeTestFile( + 'browser_test.dart', + suiteTestOn: 'browser', + loadable: false, + ); + await _writeTestFile( + 'this_os_test.dart', + suiteTestOn: currentOS.identifier, + ); + await _writeTestFile( + 'other_os_test.dart', + suiteTestOn: otherOS, + loadable: false, + ); var test = await runTest(['.']); expect(test.stdout, emitsThrough(contains('+2: All tests passed!'))); @@ -152,8 +168,12 @@ void main() { group('with suite, group, and test selectors', () { test('runs the test if all selectors match', () async { - await _writeTestFile('vm_test.dart', - suiteTestOn: '!browser', groupTestOn: '!js', testTestOn: 'vm'); + await _writeTestFile( + 'vm_test.dart', + suiteTestOn: '!browser', + groupTestOn: '!js', + testTestOn: 'vm', + ); var test = await runTest(['vm_test.dart']); expect(test.stdout, emitsThrough(contains('All tests passed!'))); @@ -161,8 +181,12 @@ void main() { }); test("doesn't runs the test if the suite doesn't match", () async { - await _writeTestFile('vm_test.dart', - suiteTestOn: 'browser', groupTestOn: '!js', testTestOn: 'vm'); + await _writeTestFile( + 'vm_test.dart', + suiteTestOn: 'browser', + groupTestOn: '!js', + testTestOn: 'vm', + ); var test = await runTest(['vm_test.dart']); expect(test.stdout, emitsThrough(contains('No tests ran.'))); @@ -170,8 +194,12 @@ void main() { }); test("doesn't runs the test if the group doesn't match", () async { - await _writeTestFile('vm_test.dart', - suiteTestOn: '!browser', groupTestOn: 'browser', testTestOn: 'vm'); + await _writeTestFile( + 'vm_test.dart', + suiteTestOn: '!browser', + groupTestOn: 'browser', + testTestOn: 'vm', + ); var test = await runTest(['vm_test.dart']); expect(test.stdout, emitsThrough(contains('No tests ran.'))); @@ -179,8 +207,12 @@ void main() { }); test("doesn't runs the test if the test doesn't match", () async { - await _writeTestFile('vm_test.dart', - suiteTestOn: '!browser', groupTestOn: '!js', testTestOn: 'browser'); + await _writeTestFile( + 'vm_test.dart', + suiteTestOn: '!browser', + groupTestOn: '!js', + testTestOn: 'browser', + ); var test = await runTest(['vm_test.dart']); expect(test.stdout, emitsThrough(contains('No tests ran.'))); @@ -194,11 +226,13 @@ void main() { /// Each of [suiteTestOn], [groupTestOn], and [testTestOn] is a platform /// selector that's suite-, group-, and test-level respectively. If [loadable] /// is `false`, the test file will be made unloadable on the Dart VM. -Future _writeTestFile(String filename, - {String? suiteTestOn, - String? groupTestOn, - String? testTestOn, - bool loadable = true}) { +Future _writeTestFile( + String filename, { + String? suiteTestOn, + String? groupTestOn, + String? testTestOn, + bool loadable = true, +}) { var buffer = StringBuffer(); if (suiteTestOn != null) buffer.writeln("@TestOn('$suiteTestOn')"); if (!loadable) buffer.writeln("import 'dart:js_interop';"); diff --git a/pkgs/test/test/runner/timeout_test.dart b/pkgs/test/test/runner/timeout_test.dart index 6f4b0e7b9..b4900fadf 100644 --- a/pkgs/test/test/runner/timeout_test.dart +++ b/pkgs/test/test/runner/timeout_test.dart @@ -30,9 +30,12 @@ void main() { var test = await runTest(['test.dart']); expect( - test.stdout, - containsInOrder( - ['Test timed out after 0 seconds.', '-1: Some tests failed.'])); + test.stdout, + containsInOrder([ + 'Test timed out after 0 seconds.', + '-1: Some tests failed.', + ]), + ); await test.shouldExit(1); }); @@ -51,9 +54,12 @@ void main() { var test = await runTest(['--timeout=0s', 'test.dart']); expect( - test.stdout, - containsInOrder( - ['Test timed out after 0 seconds.', '-1: Some tests failed.'])); + test.stdout, + containsInOrder([ + 'Test timed out after 0 seconds.', + '-1: Some tests failed.', + ]), + ); await test.shouldExit(1); }); @@ -76,17 +82,17 @@ void main() { var test = await runTest(['--timeout=400ms', 'test.dart']); expect( - test.stdout, - containsInOrder([ - 'Test timed out after 0.4 seconds.', - 'Test timed out after 0.4 seconds.', - '+1: All tests passed!' - ])); + test.stdout, + containsInOrder([ + 'Test timed out after 0.4 seconds.', + 'Test timed out after 0.4 seconds.', + '+1: All tests passed!', + ]), + ); await test.shouldExit(0); }); - test('the --timeout flag applies on top of the default 30s timeout', - () async { + test('the --timeout flag applies on top of the default 30s timeout', () async { await d.file('test.dart', ''' import 'dart:async'; @@ -107,9 +113,12 @@ void main() { // test to fail. var test = await runTest(['--timeout=0.016x', 'test.dart']); expect( - test.stdout, - containsInOrder( - ['Test timed out after 0.4 seconds.', '-1: Some tests failed.'])); + test.stdout, + containsInOrder([ + 'Test timed out after 0.4 seconds.', + '-1: Some tests failed.', + ]), + ); await test.shouldExit(1); }); @@ -132,9 +141,12 @@ void main() { var test = await runTest(['--timeout=50ms', 'test.dart']); expect( - test.stdout, - containsInOrder( - ['Test timed out after 0 seconds.', '-1: Some tests failed.'])); + test.stdout, + containsInOrder([ + 'Test timed out after 0 seconds.', + '-1: Some tests failed.', + ]), + ); await test.shouldExit(1); }); @@ -157,9 +169,12 @@ void main() { var test = await runTest(['--timeout=50ms', 'test.dart']); expect( - test.stdout, - containsInOrder( - ['Test timed out after 0 seconds.', '-1: Some tests failed.'])); + test.stdout, + containsInOrder([ + 'Test timed out after 0 seconds.', + '-1: Some tests failed.', + ]), + ); await test.shouldExit(1); }); diff --git a/pkgs/test/test/util/one_off_handler_test.dart b/pkgs/test/test/util/one_off_handler_test.dart index c10a7af9a..5263771c1 100644 --- a/pkgs/test/test/util/one_off_handler_test.dart +++ b/pkgs/test/test/util/one_off_handler_test.dart @@ -26,10 +26,12 @@ void main() { }); test('passes a request to a handler only once', () async { - var path = handler.create(expectAsync1((request) { - expect(request.method, equals('GET')); - return shelf.Response.ok('good job!'); - })); + var path = handler.create( + expectAsync1((request) { + expect(request.method, equals('GET')); + return shelf.Response.ok('good job!'); + }), + ); var request = shelf.Request('GET', Uri.parse('http://localhost/$path')); var response = await handle(request); @@ -41,20 +43,26 @@ void main() { }); test('passes requests to the correct handlers', () async { - var path1 = handler.create(expectAsync1((request) { - expect(request.method, equals('GET')); - return shelf.Response.ok('one'); - })); + var path1 = handler.create( + expectAsync1((request) { + expect(request.method, equals('GET')); + return shelf.Response.ok('one'); + }), + ); - var path2 = handler.create(expectAsync1((request) { - expect(request.method, equals('GET')); - return shelf.Response.ok('two'); - })); + var path2 = handler.create( + expectAsync1((request) { + expect(request.method, equals('GET')); + return shelf.Response.ok('two'); + }), + ); - var path3 = handler.create(expectAsync1((request) { - expect(request.method, equals('GET')); - return shelf.Response.ok('three'); - })); + var path3 = handler.create( + expectAsync1((request) { + expect(request.method, equals('GET')); + return shelf.Response.ok('three'); + }), + ); var request = shelf.Request('GET', Uri.parse('http://localhost/$path2')); var response = await handle(request); diff --git a/pkgs/test/test/util/path_handler_test.dart b/pkgs/test/test/util/path_handler_test.dart index 9a5d98bf5..54a31a6ca 100644 --- a/pkgs/test/test/util/path_handler_test.dart +++ b/pkgs/test/test/util/path_handler_test.dart @@ -27,11 +27,14 @@ void main() { test('runs a handler for an exact URL', () async { var request = shelf.Request('GET', Uri.parse('http://localhost/foo')); - handler.add('foo', expectAsync1((request) { - expect(request.handlerPath, equals('/foo')); - expect(request.url.path, isEmpty); - return shelf.Response.ok('good job!'); - })); + handler.add( + 'foo', + expectAsync1((request) { + expect(request.handlerPath, equals('/foo')); + expect(request.url.path, isEmpty); + return shelf.Response.ok('good job!'); + }), + ); var response = await localHandler(request); expect(response.statusCode, equals(200)); @@ -40,11 +43,14 @@ void main() { test('runs a handler for a suffix', () async { var request = shelf.Request('GET', Uri.parse('http://localhost/foo/bar')); - handler.add('foo', expectAsync1((request) { - expect(request.handlerPath, equals('/foo/')); - expect(request.url.path, 'bar'); - return shelf.Response.ok('good job!'); - })); + handler.add( + 'foo', + expectAsync1((request) { + expect(request.handlerPath, equals('/foo/')); + expect(request.url.path, 'bar'); + return shelf.Response.ok('good job!'); + }), + ); var response = await localHandler(request); expect(response.statusCode, equals(200)); @@ -52,24 +58,31 @@ void main() { }); test('runs the longest matching handler', () async { - var request = - shelf.Request('GET', Uri.parse('http://localhost/foo/bar/baz')); + var request = shelf.Request( + 'GET', + Uri.parse('http://localhost/foo/bar/baz'), + ); handler.add( - 'foo', - expectAsync1((_) { - return shelf.Response.notFound('fake'); - }, count: 0)); - handler.add('foo/bar', expectAsync1((request) { - expect(request.handlerPath, equals('/foo/bar/')); - expect(request.url.path, 'baz'); - return shelf.Response.ok('good job!'); - })); + 'foo', + expectAsync1((_) { + return shelf.Response.notFound('fake'); + }, count: 0), + ); + handler.add( + 'foo/bar', + expectAsync1((request) { + expect(request.handlerPath, equals('/foo/bar/')); + expect(request.url.path, 'baz'); + return shelf.Response.ok('good job!'); + }), + ); handler.add( - 'foo/bar/baz/bang', - expectAsync1((_) { - return shelf.Response.notFound('fake'); - }, count: 0)); + 'foo/bar/baz/bang', + expectAsync1((_) { + return shelf.Response.notFound('fake'); + }, count: 0), + ); var response = await localHandler(request); expect(response.statusCode, equals(200)); diff --git a/pkgs/test/test/util/string_literal_iterator_test.dart b/pkgs/test/test/util/string_literal_iterator_test.dart index 03c8e34ef..b80f6d9cf 100644 --- a/pkgs/test/test/util/string_literal_iterator_test.dart +++ b/pkgs/test/test/util/string_literal_iterator_test.dart @@ -186,14 +186,20 @@ void main() { _expectEscape(r'\x7a', 'z'); }); - test('a fixed-length unicode character', - () => _expectEscape(r'\u0062', 'b')); - - test('a short variable-length unicode character', - () => _expectEscape(r'\u{62}', 'b')); - - test('a long variable-length unicode character', - () => _expectEscape(r'\u{000062}', 'b')); + test( + 'a fixed-length unicode character', + () => _expectEscape(r'\u0062', 'b'), + ); + + test( + 'a short variable-length unicode character', + () => _expectEscape(r'\u{62}', 'b'), + ); + + test( + 'a long variable-length unicode character', + () => _expectEscape(r'\u{000062}', 'b'), + ); }); group('throws an ArgumentError for', () { @@ -241,10 +247,9 @@ Matcher _isRune(String char) { /// Parses [dart], which should be a string literal, into a /// [StringLiteralIterator]. StringLiteralIterator _parse(String dart) { - var declaration = parseString(content: 'final str = $dart;') - .unit - .declarations - .single as TopLevelVariableDeclaration; + var declaration = + parseString(content: 'final str = $dart;').unit.declarations.single + as TopLevelVariableDeclaration; var literal = declaration.variables.variables.single.initializer; return StringLiteralIterator(literal as StringLiteral); } diff --git a/pkgs/test/test/utils.dart b/pkgs/test/test/utils.dart index 23d5b7e14..f2d941b88 100644 --- a/pkgs/test/test/utils.dart +++ b/pkgs/test/test/utils.dart @@ -39,34 +39,48 @@ State? _lastState; /// The most recent emitted state is stored in [_lastState]. void expectStates(LiveTest liveTest, Iterable statesIter) { var states = Queue.of(statesIter); - liveTest.onStateChange.listen(expectAsync1((state) { - _lastState = state; - expect(state, equals(states.removeFirst())); - }, count: states.length, max: states.length)); + liveTest.onStateChange.listen( + expectAsync1( + (state) { + _lastState = state; + expect(state, equals(states.removeFirst())); + }, + count: states.length, + max: states.length, + ), + ); } /// Asserts that errors will be emitted via [liveTest.onError] that match /// [validators], in order. void expectErrors( - LiveTest liveTest, Iterable validatorsIter) { + LiveTest liveTest, + Iterable validatorsIter, +) { var validators = Queue.of(validatorsIter); - liveTest.onError.listen(expectAsync1((error) { - validators.removeFirst()(error.error); - }, count: validators.length, max: validators.length)); + liveTest.onError.listen( + expectAsync1( + (error) { + validators.removeFirst()(error.error); + }, + count: validators.length, + max: validators.length, + ), + ); } /// Asserts that [liveTest] will have a single failure with message `"oh no"`. void expectSingleFailure(LiveTest liveTest) { expectStates(liveTest, [ const State(Status.running, Result.success), - const State(Status.complete, Result.failure) + const State(Status.complete, Result.failure), ]); expectErrors(liveTest, [ (error) { expect(_lastState!.status, equals(Status.complete)); expect(error, _isTestFailure('oh no')); - } + }, ]); } @@ -81,8 +95,11 @@ Matcher _isTestFailure(Object message) => const TypeMatcher() /// /// [message] can be a string or a [Matcher]. Matcher isApplicationException(Object message) => - const TypeMatcher() - .having((e) => e.message, 'message', message); + const TypeMatcher().having( + (e) => e.message, + 'message', + message, + ); /// Asserts that [liveTest] has completed and passed. /// @@ -127,10 +144,11 @@ Engine declareEngine( return Engine.withSuites( [ RunnerSuite( - const PluginEnvironment(), - SuiteConfiguration.runSkipped(runSkipped), - declarer.build(), - suitePlatform) + const PluginEnvironment(), + SuiteConfiguration.runSkipped(runSkipped), + declarer.build(), + suitePlatform, + ), ], coverage: coverage, stopOnFirstFailure: stopOnFirstFailure, @@ -139,149 +157,155 @@ Engine declareEngine( /// Returns a [RunnerSuite] with a default environment and configuration. RunnerSuite runnerSuite(Group root) => RunnerSuite( - const PluginEnvironment(), SuiteConfiguration.empty, root, suitePlatform); + const PluginEnvironment(), + SuiteConfiguration.empty, + root, + suitePlatform, +); /// Returns a [LoadSuite] with a default configuration. LoadSuite loadSuite(String name, FutureOr Function() body) => LoadSuite(name, SuiteConfiguration.empty, suitePlatform, body); -SuiteConfiguration suiteConfiguration( - {bool? allowDuplicateTestNames, - bool? allowTestRandomization, - bool? jsTrace, - bool? runSkipped, - Iterable? dart2jsArgs, - String? precompiledPath, - Iterable? compilerSelections, - Iterable? runtimes, - Map? tags, - Map? onPlatform, - bool? ignoreTimeouts, +SuiteConfiguration suiteConfiguration({ + bool? allowDuplicateTestNames, + bool? allowTestRandomization, + bool? jsTrace, + bool? runSkipped, + Iterable? dart2jsArgs, + String? precompiledPath, + Iterable? compilerSelections, + Iterable? runtimes, + Map? tags, + Map? onPlatform, + bool? ignoreTimeouts, - // Test-level configuration - Timeout? timeout, - bool? verboseTrace, - bool? chainStackTraces, - bool? skip, - int? retry, - String? skipReason, - PlatformSelector? testOn, - Iterable? addTags}) => - SuiteConfiguration( - allowDuplicateTestNames: allowDuplicateTestNames, - allowTestRandomization: allowTestRandomization, - jsTrace: jsTrace, - runSkipped: runSkipped, - dart2jsArgs: dart2jsArgs, - precompiledPath: precompiledPath, - compilerSelections: compilerSelections, - runtimes: runtimes, - tags: tags, - onPlatform: onPlatform, - ignoreTimeouts: ignoreTimeouts, - timeout: timeout, - verboseTrace: verboseTrace, - chainStackTraces: chainStackTraces, - skip: skip, - retry: retry, - skipReason: skipReason, - testOn: testOn, - addTags: addTags); + // Test-level configuration + Timeout? timeout, + bool? verboseTrace, + bool? chainStackTraces, + bool? skip, + int? retry, + String? skipReason, + PlatformSelector? testOn, + Iterable? addTags, +}) => SuiteConfiguration( + allowDuplicateTestNames: allowDuplicateTestNames, + allowTestRandomization: allowTestRandomization, + jsTrace: jsTrace, + runSkipped: runSkipped, + dart2jsArgs: dart2jsArgs, + precompiledPath: precompiledPath, + compilerSelections: compilerSelections, + runtimes: runtimes, + tags: tags, + onPlatform: onPlatform, + ignoreTimeouts: ignoreTimeouts, + timeout: timeout, + verboseTrace: verboseTrace, + chainStackTraces: chainStackTraces, + skip: skip, + retry: retry, + skipReason: skipReason, + testOn: testOn, + addTags: addTags, +); -Configuration configuration( - {bool? help, - String? customHtmlTemplatePath, - bool? version, - bool? pauseAfterLoad, - bool? debug, - bool? color, - String? configurationPath, - String? reporter, - Map? fileReporters, - String? coverage, - int? concurrency, - int? shardIndex, - int? totalShards, - Map>? testSelections, - Iterable? foldTraceExcept, - Iterable? foldTraceOnly, - Glob? filename, - Iterable? chosenPresets, - Map? presets, - Map? overrideRuntimes, - Map? defineRuntimes, - bool? noRetry, - bool? ignoreTimeouts, +Configuration configuration({ + bool? help, + String? customHtmlTemplatePath, + bool? version, + bool? pauseAfterLoad, + bool? debug, + bool? color, + String? configurationPath, + String? reporter, + Map? fileReporters, + String? coverage, + int? concurrency, + int? shardIndex, + int? totalShards, + Map>? testSelections, + Iterable? foldTraceExcept, + Iterable? foldTraceOnly, + Glob? filename, + Iterable? chosenPresets, + Map? presets, + Map? overrideRuntimes, + Map? defineRuntimes, + bool? noRetry, + bool? ignoreTimeouts, - // Suite-level configuration - bool? allowDuplicateTestNames, - bool? allowTestRandomization, - bool? jsTrace, - bool? runSkipped, - Iterable? dart2jsArgs, - String? precompiledPath, - Iterable? globalPatterns, - Iterable? compilerSelections, - Iterable? runtimes, - BooleanSelector? includeTags, - BooleanSelector? excludeTags, - Map? tags, - Map? onPlatform, - int? testRandomizeOrderingSeed, + // Suite-level configuration + bool? allowDuplicateTestNames, + bool? allowTestRandomization, + bool? jsTrace, + bool? runSkipped, + Iterable? dart2jsArgs, + String? precompiledPath, + Iterable? globalPatterns, + Iterable? compilerSelections, + Iterable? runtimes, + BooleanSelector? includeTags, + BooleanSelector? excludeTags, + Map? tags, + Map? onPlatform, + int? testRandomizeOrderingSeed, - // Test-level configuration - Timeout? timeout, - bool? verboseTrace, - bool? chainStackTraces, - bool? skip, - int? retry, - String? skipReason, - PlatformSelector? testOn, - Iterable? addTags}) => - Configuration( - help: help, - customHtmlTemplatePath: customHtmlTemplatePath, - version: version, - pauseAfterLoad: pauseAfterLoad, - debug: debug, - color: color, - configurationPath: configurationPath, - reporter: reporter, - fileReporters: fileReporters, - coverage: coverage, - concurrency: concurrency, - shardIndex: shardIndex, - totalShards: totalShards, - testSelections: testSelections, - foldTraceExcept: foldTraceExcept, - foldTraceOnly: foldTraceOnly, - filename: filename, - chosenPresets: chosenPresets, - presets: presets, - overrideRuntimes: overrideRuntimes, - defineRuntimes: defineRuntimes, - noRetry: noRetry, - ignoreTimeouts: ignoreTimeouts, - allowDuplicateTestNames: allowDuplicateTestNames, - allowTestRandomization: allowTestRandomization, - jsTrace: jsTrace, - runSkipped: runSkipped, - dart2jsArgs: dart2jsArgs, - precompiledPath: precompiledPath, - globalPatterns: globalPatterns, - compilerSelections: compilerSelections, - runtimes: runtimes, - includeTags: includeTags, - excludeTags: excludeTags, - tags: tags, - onPlatform: onPlatform, - testRandomizeOrderingSeed: testRandomizeOrderingSeed, - stopOnFirstFailure: false, - timeout: timeout, - verboseTrace: verboseTrace, - chainStackTraces: chainStackTraces, - skip: skip, - retry: retry, - skipReason: skipReason, - testOn: testOn, - addTags: addTags); + // Test-level configuration + Timeout? timeout, + bool? verboseTrace, + bool? chainStackTraces, + bool? skip, + int? retry, + String? skipReason, + PlatformSelector? testOn, + Iterable? addTags, +}) => Configuration( + help: help, + customHtmlTemplatePath: customHtmlTemplatePath, + version: version, + pauseAfterLoad: pauseAfterLoad, + debug: debug, + color: color, + configurationPath: configurationPath, + reporter: reporter, + fileReporters: fileReporters, + coverage: coverage, + concurrency: concurrency, + shardIndex: shardIndex, + totalShards: totalShards, + testSelections: testSelections, + foldTraceExcept: foldTraceExcept, + foldTraceOnly: foldTraceOnly, + filename: filename, + chosenPresets: chosenPresets, + presets: presets, + overrideRuntimes: overrideRuntimes, + defineRuntimes: defineRuntimes, + noRetry: noRetry, + ignoreTimeouts: ignoreTimeouts, + allowDuplicateTestNames: allowDuplicateTestNames, + allowTestRandomization: allowTestRandomization, + jsTrace: jsTrace, + runSkipped: runSkipped, + dart2jsArgs: dart2jsArgs, + precompiledPath: precompiledPath, + globalPatterns: globalPatterns, + compilerSelections: compilerSelections, + runtimes: runtimes, + includeTags: includeTags, + excludeTags: excludeTags, + tags: tags, + onPlatform: onPlatform, + testRandomizeOrderingSeed: testRandomizeOrderingSeed, + stopOnFirstFailure: false, + timeout: timeout, + verboseTrace: verboseTrace, + chainStackTraces: chainStackTraces, + skip: skip, + retry: retry, + skipReason: skipReason, + testOn: testOn, + addTags: addTags, +); diff --git a/pkgs/test/tool/host.dart b/pkgs/test/tool/host.dart index 0cb6a8b99..e95f25230 100644 --- a/pkgs/test/tool/host.dart +++ b/pkgs/test/tool/host.dart @@ -18,10 +18,7 @@ import 'package:test/src/runner/browser/dom.dart' as dom; /// These are exposed so that tools like IDEs can interact with them via remote /// debugging. extension type _JSApi._(JSObject _) implements JSObject { - external factory _JSApi({ - JSFunction resume, - JSFunction restartCurrent, - }); + external factory _JSApi({JSFunction resume, JSFunction restartCurrent}); } /// Sets the top-level `dartTest` object so that it's visible to JS. @@ -95,57 +92,66 @@ void main() { dom.document.body!.classList.add('debug'); } - runZonedGuarded(() { - var serverChannel = _connectToServer(); - serverChannel.stream.listen((message) { - switch (message) { - case { + runZonedGuarded( + () { + var serverChannel = _connectToServer(); + serverChannel.stream.listen((message) { + switch (message) { + case { 'command': 'loadSuite', 'channel': final num channel, 'url': final String url, - 'id': final num id + 'id': final num id, }: - var suiteChannel = serverChannel.virtualChannel(channel.toInt()); - var iframeChannel = _connectToIframe(url, id.toInt()); - suiteChannel.pipe(iframeChannel); - case {'command': 'displayPause'}: - dom.document.body!.classList.add('paused'); - case {'command': 'resume'}: - dom.document.body!.classList.remove('paused'); - case {'command': 'closeSuite', 'id': final id}: - _iframes.remove(id)!.remove(); - _subscriptions.remove(id)?.cancel(); - _domSubscriptions.remove(id)?.cancel(); - default: - dom.window.console - .warn('Unhandled message from test runner: $message'.toJS); - } - }); - - // Send periodic pings to the test runner so it can know when the browser is - // paused for debugging. - Timer.periodic(const Duration(seconds: 1), - (_) => serverChannel.sink.add({'command': 'ping'})); - - var play = dom.document.querySelector('#play'); - play!.addEventListener('click', (_) { - if (!dom.document.body!.classList.contains('paused')) return; - dom.document.body!.classList.remove('paused'); - serverChannel.sink.add({'command': 'resume'}); - }); - - _jsApi = _JSApi( - resume: () { - if (!dom.document.body!.classList.contains('paused')) return; - dom.document.body!.classList.remove('paused'); - serverChannel.sink.add({'command': 'resume'}); - }.toJS, - restartCurrent: () { - serverChannel.sink.add({'command': 'restart'}); - }.toJS); - }, (error, stackTrace) { - dom.window.console.warn('$error\n${Trace.from(stackTrace).terse}'.toJS); - }); + var suiteChannel = serverChannel.virtualChannel(channel.toInt()); + var iframeChannel = _connectToIframe(url, id.toInt()); + suiteChannel.pipe(iframeChannel); + case {'command': 'displayPause'}: + dom.document.body!.classList.add('paused'); + case {'command': 'resume'}: + dom.document.body!.classList.remove('paused'); + case {'command': 'closeSuite', 'id': final id}: + _iframes.remove(id)!.remove(); + _subscriptions.remove(id)?.cancel(); + _domSubscriptions.remove(id)?.cancel(); + default: + dom.window.console.warn( + 'Unhandled message from test runner: $message'.toJS, + ); + } + }); + + // Send periodic pings to the test runner so it can know when the browser is + // paused for debugging. + Timer.periodic( + const Duration(seconds: 1), + (_) => serverChannel.sink.add({'command': 'ping'}), + ); + + var play = dom.document.querySelector('#play'); + play!.addEventListener('click', (_) { + if (!dom.document.body!.classList.contains('paused')) return; + dom.document.body!.classList.remove('paused'); + serverChannel.sink.add({'command': 'resume'}); + }); + + _jsApi = _JSApi( + resume: + () { + if (!dom.document.body!.classList.contains('paused')) return; + dom.document.body!.classList.remove('paused'); + serverChannel.sink.add({'command': 'resume'}); + }.toJS, + restartCurrent: + () { + serverChannel.sink.add({'command': 'restart'}); + }.toJS, + ); + }, + (error, stackTrace) { + dom.window.console.warn('$error\n${Trace.from(stackTrace).terse}'.toJS); + }, + ); } /// Creates a [MultiChannel] connection to the server, using a [WebSocket] as @@ -153,17 +159,20 @@ void main() { MultiChannel _connectToServer() { // The `managerUrl` query parameter contains the WebSocket URL of the remote // [BrowserManager] with which this communicates. - var webSocket = - dom.createWebSocket(_currentUrl.queryParameters['managerUrl']!); + var webSocket = dom.createWebSocket( + _currentUrl.queryParameters['managerUrl']!, + ); var controller = StreamChannelController(sync: true); webSocket.addEventListener('message', (message) { - controller.local.sink - .add(jsonDecode((message as dom.MessageEvent).data as String)); + controller.local.sink.add( + jsonDecode((message as dom.MessageEvent).data as String), + ); }); - controller.local.stream - .listen((message) => webSocket.send(jsonEncode(message).toJS)); + controller.local.stream.listen( + (message) => webSocket.send(jsonEncode(message).toJS), + ); return MultiChannel(controller.foreign); } @@ -193,8 +202,9 @@ StreamChannel _connectToIframe(String url, int id) { var controller = StreamChannelController(sync: true); late dom.Subscription windowSubscription; - windowSubscription = - dom.Subscription(dom.window, 'message', (dom.Event event) { + windowSubscription = dom.Subscription(dom.window, 'message', ( + dom.Event event, + ) { // A message on the Window can theoretically come from any website. It's // very unlikely that a malicious site would care about hacking someone's // unit tests, let alone be able to find the test server while it's diff --git a/pkgs/test_api/lib/fake.dart b/pkgs/test_api/lib/fake.dart index f8b2d8080..18c54119d 100644 --- a/pkgs/test_api/lib/fake.dart +++ b/pkgs/test_api/lib/fake.dart @@ -6,8 +6,10 @@ // do so until Mockito stops implementing its own version of `Fake`, because // there is code in the wild that imports both test_api.dart and Mockito. -@Deprecated('package:test_api is not intended for general use. ' - 'Please use package:test.') +@Deprecated( + 'package:test_api is not intended for general use. ' + 'Please use package:test.', +) library; export 'src/frontend/fake.dart'; diff --git a/pkgs/test_api/lib/hooks.dart b/pkgs/test_api/lib/hooks.dart index 126d3226c..720dc2b2e 100644 --- a/pkgs/test_api/lib/hooks.dart +++ b/pkgs/test_api/lib/hooks.dart @@ -22,7 +22,9 @@ final class TestHandle { final invoker = Invoker.current; if (invoker == null) throw OutsideTestException(); return TestHandle._( - invoker, StackTraceFormatter.current ?? _defaultFormatter); + invoker, + StackTraceFormatter.current ?? _defaultFormatter, + ); } static final _defaultFormatter = StackTraceFormatter(); diff --git a/pkgs/test_api/lib/hooks_testing.dart b/pkgs/test_api/lib/hooks_testing.dart index b0a6154ec..c38e7abc2 100644 --- a/pkgs/test_api/lib/hooks_testing.dart +++ b/pkgs/test_api/lib/hooks_testing.dart @@ -30,7 +30,7 @@ final class TestCaseMonitor { final LiveTest _liveTest; final _done = Completer(); TestCaseMonitor._(FutureOr Function() body) - : _liveTest = _createTest(body); + : _liveTest = _createTest(body); /// Run [body] as a test case and return a [TestCaseMonitor] with the result. /// @@ -124,8 +124,10 @@ LiveTest _createTest(FutureOr Function() body) { } /// A dummy suite platform to use for testing suites. -final _suitePlatform = - SuitePlatform(Runtime.vm, compiler: Runtime.vm.defaultCompiler); +final _suitePlatform = SuitePlatform( + Runtime.vm, + compiler: Runtime.vm.defaultCompiler, +); /// The running and success state of a test monitored by a [TestCaseMonitor]. enum State { diff --git a/pkgs/test_api/lib/src/backend/compiler.dart b/pkgs/test_api/lib/src/backend/compiler.dart index 41c253de3..dc41e92b3 100644 --- a/pkgs/test_api/lib/src/backend/compiler.dart +++ b/pkgs/test_api/lib/src/backend/compiler.dart @@ -41,8 +41,9 @@ enum Compiler { /// [Compiler]. /// /// Note that custom [Compiler] implementations are not supported. - factory Compiler.deserialize(Object serialized) => builtIn - .firstWhere((compiler) => compiler.identifier == serialized as String); + factory Compiler.deserialize(Object serialized) => builtIn.firstWhere( + (compiler) => compiler.identifier == serialized as String, + ); /// Converts [this] into a JSON-safe object that can be converted back to a /// [Compiler] using [Compiler.deserialize]. diff --git a/pkgs/test_api/lib/src/backend/configuration/timeout.dart b/pkgs/test_api/lib/src/backend/configuration/timeout.dart index e51d52011..aa8a9ab2d 100644 --- a/pkgs/test_api/lib/src/backend/configuration/timeout.dart +++ b/pkgs/test_api/lib/src/backend/configuration/timeout.dart @@ -50,9 +50,7 @@ final class Timeout { /// Declares a relative timeout that scales the default. const Timeout.factor(this.scaleFactor) : duration = null; - const Timeout._none() - : scaleFactor = null, - duration = null; + const Timeout._none() : scaleFactor = null, duration = null; /// Parse the timeout from a user-provided string. /// @@ -107,14 +105,14 @@ final class Timeout { /// Returns the number of microseconds in [number] [unit]s. static double _microsecondsFor(double number, String unit) => switch (unit) { - 'd' => number * 24 * 60 * 60 * 1000000, - 'h' => number * 60 * 60 * 1000000, - 'm' => number * 60 * 1000000, - 's' => number * 1000000, - 'ms' => number * 1000, - 'us' => number, - _ => throw ArgumentError('Unknown unit $unit.'), - }; + 'd' => number * 24 * 60 * 60 * 1000000, + 'h' => number * 60 * 60 * 1000000, + 'm' => number * 60 * 1000000, + 's' => number * 1000000, + 'ms' => number * 1000, + 'us' => number, + _ => throw ArgumentError('Unknown unit $unit.'), + }; /// Returns a new [Timeout] that merges [this] with [other]. /// diff --git a/pkgs/test_api/lib/src/backend/declarer.dart b/pkgs/test_api/lib/src/backend/declarer.dart index 4e9818d1e..4551a7d9f 100644 --- a/pkgs/test_api/lib/src/backend/declarer.dart +++ b/pkgs/test_api/lib/src/backend/declarer.dart @@ -161,18 +161,18 @@ class Declarer { bool allowDuplicateTestNames = true, bool isStandalone = false, }) : this._( - null, - null, - metadata ?? Metadata(), - platformVariables ?? const UnmodifiableSetView.empty(), - collectTraces, - null, - null, - noRetry, - fullTestName, - allowDuplicateTestNames ? null : {}, - isStandalone, - ); + null, + null, + metadata ?? Metadata(), + platformVariables ?? const UnmodifiableSetView.empty(), + collectTraces, + null, + null, + noRetry, + fullTestName, + allowDuplicateTestNames ? null : {}, + isStandalone, + ); Declarer._( this._parent, @@ -195,15 +195,18 @@ class Declarer { runZoned(body, zoneValues: {#test.declarer: this}); /// Defines a test case with the given name and body. - void test(String name, dynamic Function() body, - {String? testOn, - Timeout? timeout, - Object? skip, - Map? onPlatform, - Object? tags, - TestLocation? location, - int? retry, - bool solo = false}) { + void test( + String name, + dynamic Function() body, { + String? testOn, + Timeout? timeout, + Object? skip, + Map? onPlatform, + Object? tags, + TestLocation? location, + int? retry, + bool solo = false, + }) { _checkNotBuilt('test'); final fullName = _prefix(name); @@ -212,42 +215,53 @@ class Declarer { } var newMetadata = Metadata.parse( - testOn: testOn, - timeout: timeout, - skip: skip, - onPlatform: onPlatform, - tags: tags, - retry: _noRetry ? 0 : retry); + testOn: testOn, + timeout: timeout, + skip: skip, + onPlatform: onPlatform, + tags: tags, + retry: _noRetry ? 0 : retry, + ); newMetadata.validatePlatformSelectors(_platformVariables); var metadata = _metadata.merge(newMetadata); - _addEntry(LocalTest(fullName, metadata, () async { - var parents = []; - for (Declarer? declarer = this; - declarer != null; - declarer = declarer._parent) { - parents.add(declarer); - } - - // Register all tear-down functions in all declarers. Iterate through - // parents outside-in so that the Invoker gets the functions in the order - // they were declared in source. - for (var declarer in parents.reversed) { - for (var tearDown in declarer._tearDowns) { - Invoker.current!.addTearDown(tearDown); - } - } - - await runZoned(() async { - await _runSetUps(); - await body(); - }, - // Make the declarer visible to running tests so that they'll throw - // useful errors when calling `test()` and `group()` within a test. - zoneValues: {#test.declarer: this}); - }, + _addEntry( + LocalTest( + fullName, + metadata, + () async { + var parents = []; + for ( + Declarer? declarer = this; + declarer != null; + declarer = declarer._parent + ) { + parents.add(declarer); + } + + // Register all tear-down functions in all declarers. Iterate through + // parents outside-in so that the Invoker gets the functions in the order + // they were declared in source. + for (var declarer in parents.reversed) { + for (var tearDown in declarer._tearDowns) { + Invoker.current!.addTearDown(tearDown); + } + } + + await runZoned( + () async { + await _runSetUps(); + await body(); + }, + // Make the declarer visible to running tests so that they'll throw + // useful errors when calling `test()` and `group()` within a test. + zoneValues: {#test.declarer: this}, + ); + }, trace: _collectTraces ? Trace.current(2) : null, location: location, - guarded: false)); + guarded: false, + ), + ); if (solo) { _soloEntries.add(_entries.last); @@ -255,15 +269,18 @@ class Declarer { } /// Creates a group of tests. - void group(String name, void Function() body, - {String? testOn, - Timeout? timeout, - Object? skip, - Map? onPlatform, - Object? tags, - TestLocation? location, - int? retry, - bool solo = false}) { + void group( + String name, + void Function() body, { + String? testOn, + Timeout? timeout, + Object? skip, + Map? onPlatform, + Object? tags, + TestLocation? location, + int? retry, + bool solo = false, + }) { _checkNotBuilt('group'); final fullTestPrefix = _prefix(name); @@ -272,12 +289,13 @@ class Declarer { } var newMetadata = Metadata.parse( - testOn: testOn, - timeout: timeout, - skip: skip, - onPlatform: onPlatform, - tags: tags, - retry: _noRetry ? 0 : retry); + testOn: testOn, + timeout: timeout, + skip: skip, + onPlatform: onPlatform, + tags: tags, + retry: _noRetry ? 0 : retry, + ); newMetadata.validatePlatformSelectors(_platformVariables); var metadata = _metadata.merge(newMetadata); var trace = _collectTraces ? Trace.current(2) : null; @@ -353,23 +371,30 @@ class Declarer { _checkNotBuilt('build'); _built = true; - var entries = _entries.map((entry) { - if (_solo && !_soloEntries.contains(entry)) { - entry = LocalTest( - entry.name, - entry.metadata - .change(skip: true, skipReason: 'does not have "solo"'), - () {}); - } - return entry; - }).toList(); - - return Group(_name ?? '', entries, - metadata: _metadata, - trace: _trace, - location: _location, - setUpAll: _setUpAll, - tearDownAll: _tearDownAll); + var entries = + _entries.map((entry) { + if (_solo && !_soloEntries.contains(entry)) { + entry = LocalTest( + entry.name, + entry.metadata.change( + skip: true, + skipReason: 'does not have "solo"', + ), + () {}, + ); + } + return entry; + }).toList(); + + return Group( + _name ?? '', + entries, + metadata: _metadata, + trace: _trace, + location: _location, + setUpAll: _setUpAll, + tearDownAll: _tearDownAll, + ); } /// Throws a [StateError] if [build] has been called. @@ -377,20 +402,23 @@ class Declarer { /// [name] should be the name of the method being called. void _checkNotBuilt(String name) { if (!_built) return; - final restrictionMessage = _isStandalone - ? 'When running a test as an executable directly ' - '(not as a suite by the test runner), ' - 'tests must be declared in a synchronous block.\n' - 'If async work is required before any tests are run ' - 'use a `setUpAll` callback.\n' - 'If async work cannot be avoided before declaring tests, ' - 'all async events must be complete before declaring the first test.' - : 'If async work is required before any tests are run ' - 'use a `setUpAll` callback.\n' - 'If async work cannot be avoided before declaring tests it must ' - 'all be awaited within the Future returned from `main`.'; - throw StateError("Can't call $name() once tests have begun running.\n" - '$restrictionMessage'); + final restrictionMessage = + _isStandalone + ? 'When running a test as an executable directly ' + '(not as a suite by the test runner), ' + 'tests must be declared in a synchronous block.\n' + 'If async work is required before any tests are run ' + 'use a `setUpAll` callback.\n' + 'If async work cannot be avoided before declaring tests, ' + 'all async events must be complete before declaring the first test.' + : 'If async work is required before any tests are run ' + 'use a `setUpAll` callback.\n' + 'If async work cannot be avoided before declaring tests it must ' + 'all be awaited within the Future returned from `main`.'; + throw StateError( + "Can't call $name() once tests have begun running.\n" + '$restrictionMessage', + ); } /// Run the set-up functions for this and any parent groups. @@ -407,18 +435,22 @@ class Declarer { Test? get _setUpAll { if (_setUpAlls.isEmpty) return null; - return LocalTest(_prefix('(setUpAll)'), _metadata.change(timeout: _timeout), - () { - return runZoned( + return LocalTest( + _prefix('(setUpAll)'), + _metadata.change(timeout: _timeout), + () { + return runZoned( () => Future.forEach(_setUpAlls, (setUp) => setUp()), // Make the declarer visible to running scaffolds so they can add to // the declarer's `tearDownAll()` list. - zoneValues: {#test.declarer: this}); - }, - trace: _setUpAllTrace, - location: _setUpAllLocation, - guarded: false, - isScaffoldAll: true); + zoneValues: {#test.declarer: this}, + ); + }, + trace: _setUpAllTrace, + location: _setUpAllLocation, + guarded: false, + isScaffoldAll: true, + ); } /// Returns a [Test] that runs the callbacks in [_tearDownAll], or `null`. @@ -428,16 +460,21 @@ class Declarer { if (_setUpAlls.isEmpty && _tearDownAlls.isEmpty) return null; return LocalTest( - _prefix('(tearDownAll)'), _metadata.change(timeout: _timeout), () { - return runZoned(() => Invoker.current!.runTearDowns(_tearDownAlls), + _prefix('(tearDownAll)'), + _metadata.change(timeout: _timeout), + () { + return runZoned( + () => Invoker.current!.runTearDowns(_tearDownAlls), // Make the declarer visible to running scaffolds so they can add to // the declarer's `tearDownAll()` list. - zoneValues: {#test.declarer: this}); - }, - trace: _tearDownAllTrace, - location: _tearDownAllLocation, - guarded: false, - isScaffoldAll: true); + zoneValues: {#test.declarer: this}, + ); + }, + trace: _tearDownAllTrace, + location: _tearDownAllLocation, + guarded: false, + isScaffoldAll: true, + ); } void _addEntry(GroupEntry entry) { @@ -455,7 +492,8 @@ class DuplicateTestNameException implements Exception { DuplicateTestNameException(this.name); @override - String toString() => 'A test with the name "$name" was already declared. ' + String toString() => + 'A test with the name "$name" was already declared. ' 'Test cases must have unique names.\n\n' 'See https://github.com/dart-lang/test/blob/master/pkgs/test/doc/' 'configuration.md#allow_test_randomization for info on enabling this.'; diff --git a/pkgs/test_api/lib/src/backend/group.dart b/pkgs/test_api/lib/src/backend/group.dart index 84840dd01..9e1472c1d 100644 --- a/pkgs/test_api/lib/src/backend/group.dart +++ b/pkgs/test_api/lib/src/backend/group.dart @@ -34,7 +34,7 @@ class Group implements GroupEntry { /// Returns a new root-level group. Group.root(Iterable entries, {Metadata? metadata}) - : this('', entries, metadata: metadata); + : this('', entries, metadata: metadata); /// A test to run before all tests in the group. /// @@ -50,20 +50,24 @@ class Group implements GroupEntry { int get testCount { if (_testCount != null) return _testCount!; _testCount = entries.fold( - 0, (count, entry) => count + (entry is Group ? entry.testCount : 1)); + 0, + (count, entry) => count + (entry is Group ? entry.testCount : 1), + ); return _testCount!; } int? _testCount; - Group(this.name, Iterable entries, - {Metadata? metadata, - this.trace, - this.location, - this.setUpAll, - this.tearDownAll}) - : entries = List.unmodifiable(entries), - metadata = metadata ?? Metadata() { + Group( + this.name, + Iterable entries, { + Metadata? metadata, + this.trace, + this.location, + this.setUpAll, + this.tearDownAll, + }) : entries = List.unmodifiable(entries), + metadata = metadata ?? Metadata() { for (var entry in entries) { assert(entry.parent == null); entry.parent = this; @@ -80,37 +84,46 @@ class Group implements GroupEntry { var newMetadata = metadata.forPlatform(platform); var filtered = _map((entry) => entry.forPlatform(platform)); if (filtered.isEmpty && entries.isNotEmpty) return null; - return Group(name, filtered, - metadata: newMetadata, - trace: trace, - location: location, - setUpAll: setUpAll?.forPlatform(platform), - tearDownAll: tearDownAll?.forPlatform(platform)); + return Group( + name, + filtered, + metadata: newMetadata, + trace: trace, + location: location, + setUpAll: setUpAll?.forPlatform(platform), + tearDownAll: tearDownAll?.forPlatform(platform), + ); } @override Group? filter(bool Function(Test) callback) { var filtered = _map((entry) => entry.filter(callback)); if (filtered.isEmpty && entries.isNotEmpty) return null; - return Group(name, filtered, - metadata: metadata, - trace: trace, - location: location, - // Always clone these because they are being re-parented. - setUpAll: setUpAll?.clone(), - tearDownAll: tearDownAll?.clone()); + return Group( + name, + filtered, + metadata: metadata, + trace: trace, + location: location, + // Always clone these because they are being re-parented. + setUpAll: setUpAll?.clone(), + tearDownAll: tearDownAll?.clone(), + ); } @override Group? clone() { var entries = _map((entry) => entry.clone()); - return Group(name, entries, - metadata: metadata, - trace: trace, - location: location, - // Always clone these because they are being re-parented. - setUpAll: setUpAll?.clone(), - tearDownAll: tearDownAll?.clone()); + return Group( + name, + entries, + metadata: metadata, + trace: trace, + location: location, + // Always clone these because they are being re-parented. + setUpAll: setUpAll?.clone(), + tearDownAll: tearDownAll?.clone(), + ); } /// Returns the entries of this group mapped using [callback]. diff --git a/pkgs/test_api/lib/src/backend/invoker.dart b/pkgs/test_api/lib/src/backend/invoker.dart index d4e5b6b65..8f775cf1d 100644 --- a/pkgs/test_api/lib/src/backend/invoker.dart +++ b/pkgs/test_api/lib/src/backend/invoker.dart @@ -50,15 +50,25 @@ class LocalTest extends Test { /// errors that escape that zone cause the test to fail. If it's `false`, it's /// the caller's responsibility to invoke [LiveTest.run] in the context of a /// call to [Invoker.guard]. - LocalTest(this.name, this.metadata, this._body, - {this.trace, - this.location, - bool guarded = true, - this.isScaffoldAll = false}) - : _guarded = guarded; - - LocalTest._(this.name, this.metadata, this._body, this.trace, this.location, - this._guarded, this.isScaffoldAll); + LocalTest( + this.name, + this.metadata, + this._body, { + this.trace, + this.location, + bool guarded = true, + this.isScaffoldAll = false, + }) : _guarded = guarded; + + LocalTest._( + this.name, + this.metadata, + this._body, + this.trace, + this.location, + this._guarded, + this.isScaffoldAll, + ); /// Loads a single runnable instance of this test. @override @@ -70,8 +80,15 @@ class LocalTest extends Test { @override Test? forPlatform(SuitePlatform platform) { if (!metadata.testOn.evaluate(platform)) return null; - return LocalTest._(name, metadata.forPlatform(platform), _body, trace, - location, _guarded, isScaffoldAll); + return LocalTest._( + name, + metadata.forPlatform(platform), + _body, + trace, + location, + _guarded, + isScaffoldAll, + ); } @override @@ -88,7 +105,14 @@ class LocalTest extends Test { @override Test clone() { return LocalTest._( - name, metadata, _body, trace, location, _guarded, isScaffoldAll); + name, + metadata, + _body, + trace, + location, + _guarded, + isScaffoldAll, + ); } } @@ -144,8 +168,10 @@ class Invoker { _AsyncCounter get _outstandingCallbacks { var counter = Zone.current[_counterKey] as _AsyncCounter?; if (counter != null) return counter; - throw StateError("Can't add or remove outstanding callbacks outside " - 'of a test body.'); + throw StateError( + "Can't add or remove outstanding callbacks outside " + 'of a test body.', + ); } /// All the zones created by [_waitForOutstandingCallbacks], in the order they @@ -174,19 +200,22 @@ class Invoker { /// Runs [callback] in a zone where unhandled errors from [LiveTest]s are /// caught and dispatched to the appropriate [Invoker]. - static T? guard(T Function() callback) => - runZoned(callback, zoneSpecification: ZoneSpecification( - // Use [handleUncaughtError] rather than [onError] so we can - // capture [zone] and with it the outstanding callback counter for - // the zone in which [error] was thrown. - handleUncaughtError: (self, _, zone, error, stackTrace) { + static T? guard(T Function() callback) => runZoned( + callback, + zoneSpecification: ZoneSpecification( + // Use [handleUncaughtError] rather than [onError] so we can + // capture [zone] and with it the outstanding callback counter for + // the zone in which [error] was thrown. + handleUncaughtError: (self, _, zone, error, stackTrace) { var invoker = zone[#test.invoker] as Invoker?; if (invoker != null) { self.parent!.run(() => invoker._handleError(zone, error, stackTrace)); } else { self.parent!.handleUncaughtError(error, stackTrace); } - })); + }, + ), + ); /// The timer for tracking timeouts. /// @@ -199,12 +228,19 @@ class Invoker { /// Messages to print if and when this test fails. final _printsOnFailure = []; - Invoker._(Suite suite, LocalTest test, - {Iterable? groups, bool guarded = true}) - : _guarded = guarded { + Invoker._( + Suite suite, + LocalTest test, { + Iterable? groups, + bool guarded = true, + }) : _guarded = guarded { _controller = LiveTestController( - suite, test, _onRun, _onCloseCompleter.complete, - groups: groups); + suite, + test, + _onRun, + _onCloseCompleter.complete, + groups: groups, + ); } /// Runs [callback] after this test completes. @@ -390,11 +426,12 @@ class Invoker { if (liveTest.suite.isLoadSuite) return; _handleError( - zone, - 'This test failed after it had already completed.\n' - 'Make sure to use a matching library which informs the test runner\n' - 'of pending async work.', - stackTrace); + zone, + 'This test failed after it had already completed.\n' + 'Make sure to use a matching library which informs the test runner\n' + 'of pending async work.', + stackTrace, + ); } /// The method that's run when the test is started. @@ -402,44 +439,57 @@ class Invoker { _controller.setState(const State(Status.running, Result.success)); _runCount++; - Chain.capture(() { - _guardIfGuarded(() { - runZoned(() async { - // Run the test asynchronously so that the "running" state change - // has a chance to hit its event handler(s) before the test produces - // an error. If an error is emitted before the first state change is - // handled, we can end up with [onError] callbacks firing before the - // corresponding [onStateChange], which violates the timing - // guarantees. - // - // Use the event loop over the microtask queue to avoid starvation. - await Future(() {}); - - await _waitForOutstandingCallbacks(_test._body); - await _waitForOutstandingCallbacks(() => runTearDowns(_tearDowns)); - - if (_timeoutTimer != null) _timeoutTimer!.cancel(); - - if (liveTest.state.result != Result.success && - _runCount < liveTest.test.metadata.retry + 1) { - _controller.message(Message.print('Retry: ${liveTest.test.name}')); - _onRun(); - return; - } - - _controller.setState(State(Status.complete, liveTest.state.result)); - - _controller.completer.complete(); - }, + Chain.capture( + () { + _guardIfGuarded(() { + runZoned( + () async { + // Run the test asynchronously so that the "running" state change + // has a chance to hit its event handler(s) before the test produces + // an error. If an error is emitted before the first state change is + // handled, we can end up with [onError] callbacks firing before the + // corresponding [onStateChange], which violates the timing + // guarantees. + // + // Use the event loop over the microtask queue to avoid starvation. + await Future(() {}); + + await _waitForOutstandingCallbacks(_test._body); + await _waitForOutstandingCallbacks( + () => runTearDowns(_tearDowns), + ); + + if (_timeoutTimer != null) _timeoutTimer!.cancel(); + + if (liveTest.state.result != Result.success && + _runCount < liveTest.test.metadata.retry + 1) { + _controller.message( + Message.print('Retry: ${liveTest.test.name}'), + ); + _onRun(); + return; + } + + _controller.setState( + State(Status.complete, liveTest.state.result), + ); + + _controller.completer.complete(); + }, zoneValues: { #test.invoker: this, _forceOpenForTearDownKey: false, #runCount: _runCount, }, - zoneSpecification: - ZoneSpecification(print: (_, __, ___, line) => _print(line))); - }); - }, when: liveTest.test.metadata.chainStackTraces, errorZone: false); + zoneSpecification: ZoneSpecification( + print: (_, __, ___, line) => _print(line), + ), + ); + }); + }, + when: liveTest.test.metadata.chainStackTraces, + errorZone: false, + ); } /// Runs [callback], in a [Invoker.guard] context if [_guarded] is `true`. diff --git a/pkgs/test_api/lib/src/backend/live_test_controller.dart b/pkgs/test_api/lib/src/backend/live_test_controller.dart index 956c293c8..830da4108 100644 --- a/pkgs/test_api/lib/src/backend/live_test_controller.dart +++ b/pkgs/test_api/lib/src/backend/live_test_controller.dart @@ -98,9 +98,13 @@ class LiveTestController extends LiveTest { /// /// If [groups] is passed, it's used to populate the list of groups that /// contain this test. Otherwise, `suite.group` is used. - LiveTestController(this.suite, this.test, this._onRun, this._onClose, - {Iterable? groups}) - : groups = groups == null ? [suite.group] : List.unmodifiable(groups); + LiveTestController( + this.suite, + this.test, + this._onRun, + this._onClose, { + Iterable? groups, + }) : groups = groups == null ? [suite.group] : List.unmodifiable(groups); /// Adds an error to the [LiveTest]. /// @@ -111,7 +115,9 @@ class LiveTestController extends LiveTest { if (_isClosed) return; var asyncError = AsyncError( - error, Chain.forTrace(stackTrace ?? StackTrace.fromString(''))); + error, + Chain.forTrace(stackTrace ?? StackTrace.fromString('')), + ); _errors.add(asyncError); _onError.add(asyncError); } @@ -145,8 +151,10 @@ class LiveTestController extends LiveTest { if (_runCalled) { throw StateError('LiveTest.run() may not be called more than once.'); } else if (_isClosed) { - throw StateError('LiveTest.run() may not be called for a closed ' - 'test.'); + throw StateError( + 'LiveTest.run() may not be called for a closed ' + 'test.', + ); } _runCalled = true; diff --git a/pkgs/test_api/lib/src/backend/message.dart b/pkgs/test_api/lib/src/backend/message.dart index a027460ff..fc7a7638b 100644 --- a/pkgs/test_api/lib/src/backend/message.dart +++ b/pkgs/test_api/lib/src/backend/message.dart @@ -29,10 +29,10 @@ class MessageType { final String name; factory MessageType.parse(String name) => switch (name) { - 'print' => MessageType.print, - 'skip' => MessageType.skip, - _ => throw ArgumentError('Invalid message type "$name".'), - }; + 'print' => MessageType.print, + 'skip' => MessageType.skip, + _ => throw ArgumentError('Invalid message type "$name".'), + }; const MessageType._(this.name); diff --git a/pkgs/test_api/lib/src/backend/metadata.dart b/pkgs/test_api/lib/src/backend/metadata.dart index d0663b16a..bc3d38a74 100644 --- a/pkgs/test_api/lib/src/backend/metadata.dart +++ b/pkgs/test_api/lib/src/backend/metadata.dart @@ -74,7 +74,8 @@ final class Metadata { /// Parses a user-provided map into the value for [onPlatform]. static Map _parseOnPlatform( - Map? onPlatform) { + Map? onPlatform, + ) { if (onPlatform == null) return {}; var result = {}; @@ -85,35 +86,45 @@ final class Metadata { } else if (metadata is List) { result[selector] = _parsePlatformOptions(platform, metadata); } else { - throw ArgumentError('Metadata for platform "$platform" must be a ' - 'Timeout, Skip, or List of those; was "$metadata".'); + throw ArgumentError( + 'Metadata for platform "$platform" must be a ' + 'Timeout, Skip, or List of those; was "$metadata".', + ); } }); return result; } static Metadata _parsePlatformOptions( - String platform, List metadata) { + String platform, + List metadata, + ) { Timeout? timeout; dynamic skip; for (var metadatum in metadata) { if (metadatum is Timeout) { if (timeout != null) { - throw ArgumentError('Only a single Timeout may be declared for ' - '"$platform".'); + throw ArgumentError( + 'Only a single Timeout may be declared for ' + '"$platform".', + ); } timeout = metadatum; } else if (metadatum is Skip) { if (skip != null) { - throw ArgumentError('Only a single Skip may be declared for ' - '"$platform".'); + throw ArgumentError( + 'Only a single Skip may be declared for ' + '"$platform".', + ); } skip = metadatum.reason ?? true; } else { - throw ArgumentError('Metadata for platform "$platform" must be a ' - 'Timeout, Skip, or List of those; was "$metadata".'); + throw ArgumentError( + 'Metadata for platform "$platform" must be a ' + 'Timeout, Skip, or List of those; was "$metadata".', + ); } } @@ -128,7 +139,10 @@ final class Metadata { if (tags is String) return {tags}; if (tags is! Iterable) { throw ArgumentError.value( - tags, 'tags', 'must be either a String or an Iterable.'); + tags, + 'tags', + 'must be either a String or an Iterable.', + ); } if (tags.any((tag) => tag is! String)) { @@ -145,31 +159,33 @@ final class Metadata { /// If [forTag] contains metadata that applies to [tags], that metadata is /// included inline in the returned value. The values directly passed to the /// constructor take precedence over tag-specific metadata. - factory Metadata( - {PlatformSelector? testOn, - Timeout? timeout, - bool? skip, - bool? verboseTrace, - bool? chainStackTraces, - int? retry, - String? skipReason, - Iterable? tags, - Map? onPlatform, - Map? forTag, - String? languageVersionComment}) { + factory Metadata({ + PlatformSelector? testOn, + Timeout? timeout, + bool? skip, + bool? verboseTrace, + bool? chainStackTraces, + int? retry, + String? skipReason, + Iterable? tags, + Map? onPlatform, + Map? forTag, + String? languageVersionComment, + }) { // Returns metadata without forTag resolved at all. Metadata unresolved() => Metadata._( - testOn: testOn, - timeout: timeout, - skip: skip, - verboseTrace: verboseTrace, - chainStackTraces: chainStackTraces, - retry: retry, - skipReason: skipReason, - tags: tags, - onPlatform: onPlatform, - forTag: forTag, - languageVersionComment: languageVersionComment); + testOn: testOn, + timeout: timeout, + skip: skip, + verboseTrace: verboseTrace, + chainStackTraces: chainStackTraces, + retry: retry, + skipReason: skipReason, + tags: tags, + onPlatform: onPlatform, + forTag: forTag, + languageVersionComment: languageVersionComment, + ); // If there's no tag-specific metadata, or if none of it applies, just // return the metadata as-is. @@ -205,16 +221,16 @@ final class Metadata { Map? onPlatform, Map? forTag, this.languageVersionComment, - }) : testOn = testOn ?? PlatformSelector.all, - timeout = timeout ?? const Timeout.factor(1), - _skip = skip, - _verboseTrace = verboseTrace, - _chainStackTraces = chainStackTraces, - _retry = retry, - tags = UnmodifiableSetView(tags == null ? {} : tags.toSet()), - onPlatform = - onPlatform == null ? const {} : UnmodifiableMapView(onPlatform), - forTag = forTag == null ? const {} : UnmodifiableMapView(forTag) { + }) : testOn = testOn ?? PlatformSelector.all, + timeout = timeout ?? const Timeout.factor(1), + _skip = skip, + _verboseTrace = verboseTrace, + _chainStackTraces = chainStackTraces, + _retry = retry, + tags = UnmodifiableSetView(tags == null ? {} : tags.toSet()), + onPlatform = + onPlatform == null ? const {} : UnmodifiableMapView(onPlatform), + forTag = forTag == null ? const {} : UnmodifiableMapView(forTag) { if (retry != null) RangeError.checkNotNegative(retry, 'retry'); _validateTags(); } @@ -223,28 +239,29 @@ final class Metadata { /// where applicable. /// /// Throws a [FormatException] if any field is invalid. - Metadata.parse( - {String? testOn, - Timeout? timeout, - dynamic skip, - bool? verboseTrace, - bool? chainStackTraces, - int? retry, - Map? onPlatform, - Object? /* String|Iterable */ tags, - this.languageVersionComment}) - : testOn = testOn == null - ? PlatformSelector.all - : PlatformSelector.parse(testOn), - timeout = timeout ?? const Timeout.factor(1), - _skip = skip == null ? null : skip != false, - _verboseTrace = verboseTrace, - _chainStackTraces = chainStackTraces, - _retry = retry, - skipReason = skip is String ? skip : null, - onPlatform = _parseOnPlatform(onPlatform), - tags = _parseTags(tags), - forTag = const {} { + Metadata.parse({ + String? testOn, + Timeout? timeout, + dynamic skip, + bool? verboseTrace, + bool? chainStackTraces, + int? retry, + Map? onPlatform, + Object? /* String|Iterable */ tags, + this.languageVersionComment, + }) : testOn = + testOn == null + ? PlatformSelector.all + : PlatformSelector.parse(testOn), + timeout = timeout ?? const Timeout.factor(1), + _skip = skip == null ? null : skip != false, + _verboseTrace = verboseTrace, + _chainStackTraces = chainStackTraces, + _retry = retry, + skipReason = skip is String ? skip : null, + onPlatform = _parseOnPlatform(onPlatform), + tags = _parseTags(tags), + forTag = const {} { if (skip != null && skip is! String && skip is! bool) { throw ArgumentError('"skip" must be a String or a bool, was "$skip".'); } @@ -256,26 +273,30 @@ final class Metadata { /// Deserializes the result of [Metadata.serialize] into a new [Metadata]. Metadata.deserialize(Map serialized) - : testOn = serialized['testOn'] == null - ? PlatformSelector.all - : PlatformSelector.parse(serialized['testOn'] as String), - timeout = _deserializeTimeout(serialized['timeout']), - _skip = serialized['skip'] as bool?, - skipReason = serialized['skipReason'] as String?, - _verboseTrace = serialized['verboseTrace'] as bool?, - _chainStackTraces = serialized['chainStackTraces'] as bool?, - _retry = (serialized['retry'] as num?)?.toInt(), - tags = Set.from(serialized['tags'] as Iterable), - onPlatform = { - for (var pair in serialized['onPlatform'] as List) - PlatformSelector.parse(pair.first as String): - Metadata.deserialize(pair.last as Map) - }, - forTag = (serialized['forTag'] as Map).map((key, nested) => MapEntry( - BooleanSelector.parse(key as String), - Metadata.deserialize(nested as Map))), - languageVersionComment = - serialized['languageVersionComment'] as String?; + : testOn = + serialized['testOn'] == null + ? PlatformSelector.all + : PlatformSelector.parse(serialized['testOn'] as String), + timeout = _deserializeTimeout(serialized['timeout']), + _skip = serialized['skip'] as bool?, + skipReason = serialized['skipReason'] as String?, + _verboseTrace = serialized['verboseTrace'] as bool?, + _chainStackTraces = serialized['chainStackTraces'] as bool?, + _retry = (serialized['retry'] as num?)?.toInt(), + tags = Set.from(serialized['tags'] as Iterable), + onPlatform = { + for (var pair in serialized['onPlatform'] as List) + PlatformSelector.parse(pair.first as String): Metadata.deserialize( + pair.last as Map, + ), + }, + forTag = (serialized['forTag'] as Map).map( + (key, nested) => MapEntry( + BooleanSelector.parse(key as String), + Metadata.deserialize(nested as Map), + ), + ), + languageVersionComment = serialized['languageVersionComment'] as String?; /// Deserializes timeout from the format returned by [_serializeTimeout]. static Timeout _deserializeTimeout(Object? serialized) { @@ -283,22 +304,26 @@ final class Metadata { var scaleFactor = (serialized as Map)['scaleFactor']; if (scaleFactor != null) return Timeout.factor(scaleFactor as num); return Timeout( - Duration(microseconds: (serialized['duration'] as num).toInt())); + Duration(microseconds: (serialized['duration'] as num).toInt()), + ); } /// Throws an [ArgumentError] if any tags in [tags] aren't hyphenated /// identifiers. void _validateTags() { - var invalidTags = tags - .where((tag) => !tag.contains(anchoredHyphenatedIdentifier)) - .map((tag) => '"$tag"') - .toList(); + var invalidTags = + tags + .where((tag) => !tag.contains(anchoredHyphenatedIdentifier)) + .map((tag) => '"$tag"') + .toList(); if (invalidTags.isEmpty) return; - throw ArgumentError("Invalid ${pluralize('tag', invalidTags.length)} " - '${toSentence(invalidTags)}. Tags must be (optionally hyphenated) ' - 'Dart identifiers.'); + throw ArgumentError( + "Invalid ${pluralize('tag', invalidTags.length)} " + '${toSentence(invalidTags)}. Tags must be (optionally hyphenated) ' + 'Dart identifiers.', + ); } /// Throws a [FormatException] if any [PlatformSelector]s use any variables @@ -318,34 +343,42 @@ final class Metadata { /// either has a [forTag] metadata for one of the other's tags, that metadata /// is merged as well. Metadata merge(Metadata other) => Metadata( - testOn: testOn.intersection(other.testOn), - timeout: timeout.merge(other.timeout), - skip: other._skip ?? _skip, - skipReason: other.skipReason ?? skipReason, - verboseTrace: other._verboseTrace ?? _verboseTrace, - chainStackTraces: other._chainStackTraces ?? _chainStackTraces, - retry: other._retry ?? _retry, - tags: tags.union(other.tags), - onPlatform: mergeMaps(onPlatform, other.onPlatform, - value: (metadata1, metadata2) => metadata1.merge(metadata2)), - forTag: mergeMaps(forTag, other.forTag, - value: (metadata1, metadata2) => metadata1.merge(metadata2)), - languageVersionComment: - other.languageVersionComment ?? languageVersionComment); + testOn: testOn.intersection(other.testOn), + timeout: timeout.merge(other.timeout), + skip: other._skip ?? _skip, + skipReason: other.skipReason ?? skipReason, + verboseTrace: other._verboseTrace ?? _verboseTrace, + chainStackTraces: other._chainStackTraces ?? _chainStackTraces, + retry: other._retry ?? _retry, + tags: tags.union(other.tags), + onPlatform: mergeMaps( + onPlatform, + other.onPlatform, + value: (metadata1, metadata2) => metadata1.merge(metadata2), + ), + forTag: mergeMaps( + forTag, + other.forTag, + value: (metadata1, metadata2) => metadata1.merge(metadata2), + ), + languageVersionComment: + other.languageVersionComment ?? languageVersionComment, + ); /// Returns a copy of [this] with the given fields changed. - Metadata change( - {PlatformSelector? testOn, - Timeout? timeout, - bool? skip, - bool? verboseTrace, - bool? chainStackTraces, - int? retry, - String? skipReason, - Map? onPlatform, - Set? tags, - Map? forTag, - String? languageVersionComment}) { + Metadata change({ + PlatformSelector? testOn, + Timeout? timeout, + bool? skip, + bool? verboseTrace, + bool? chainStackTraces, + int? retry, + String? skipReason, + Map? onPlatform, + Set? tags, + Map? forTag, + String? languageVersionComment, + }) { testOn ??= this.testOn; timeout ??= this.timeout; skip ??= _skip; @@ -358,17 +391,18 @@ final class Metadata { forTag ??= this.forTag; languageVersionComment ??= this.languageVersionComment; return Metadata( - testOn: testOn, - timeout: timeout, - skip: skip, - verboseTrace: verboseTrace, - chainStackTraces: chainStackTraces, - skipReason: skipReason, - onPlatform: onPlatform, - tags: tags, - forTag: forTag, - retry: retry, - languageVersionComment: languageVersionComment); + testOn: testOn, + timeout: timeout, + skip: skip, + verboseTrace: verboseTrace, + chainStackTraces: chainStackTraces, + skipReason: skipReason, + onPlatform: onPlatform, + tags: tags, + forTag: forTag, + retry: retry, + languageVersionComment: languageVersionComment, + ); } /// Returns a copy of [this] with all platform-specific metadata from @@ -403,8 +437,10 @@ final class Metadata { 'retry': _retry, 'tags': tags.toList(), 'onPlatform': serializedOnPlatform, - 'forTag': forTag.map((selector, metadata) => - MapEntry(selector.toString(), metadata.serialize())), + 'forTag': forTag.map( + (selector, metadata) => + MapEntry(selector.toString(), metadata.serialize()), + ), 'languageVersionComment': languageVersionComment, }; } @@ -414,7 +450,7 @@ final class Metadata { if (timeout == Timeout.none) return 'none'; return { 'duration': timeout.duration?.inMicroseconds, - 'scaleFactor': timeout.scaleFactor + 'scaleFactor': timeout.scaleFactor, }; } } diff --git a/pkgs/test_api/lib/src/backend/operating_system.dart b/pkgs/test_api/lib/src/backend/operating_system.dart index a86c1e7d8..ba82f45d5 100644 --- a/pkgs/test_api/lib/src/backend/operating_system.dart +++ b/pkgs/test_api/lib/src/backend/operating_system.dart @@ -41,22 +41,23 @@ class OperatingSystem { /// Finds an operating system by its name. /// /// If no operating system is found, returns [none]. - static OperatingSystem find(String identifier) => - all.firstWhere((platform) => platform.identifier == identifier, - orElse: () => none); + static OperatingSystem find(String identifier) => all.firstWhere( + (platform) => platform.identifier == identifier, + orElse: () => none, + ); /// Finds an operating system by the return value from `dart:io`'s /// `Platform.operatingSystem`. /// /// If no operating system is found, returns [none]. static OperatingSystem findByIoName(String name) => switch (name) { - 'windows' => windows, - 'macos' => macOS, - 'linux' => linux, - 'android' => android, - 'ios' => iOS, - _ => none, - }; + 'windows' => windows, + 'macos' => macOS, + 'linux' => linux, + 'android' => android, + 'ios' => iOS, + _ => none, + }; /// The human-friendly of the operating system. final String name; diff --git a/pkgs/test_api/lib/src/backend/platform_selector.dart b/pkgs/test_api/lib/src/backend/platform_selector.dart index c65dc8b3f..2143652de 100644 --- a/pkgs/test_api/lib/src/backend/platform_selector.dart +++ b/pkgs/test_api/lib/src/backend/platform_selector.dart @@ -45,9 +45,11 @@ final class PlatformSelector { /// If [span] is passed, it indicates the location of the text for [selector] /// in a larger document. It's used for error reporting. PlatformSelector.parse(String selector, [SourceSpan? span]) - : _inner = - _wrapFormatException(() => BooleanSelector.parse(selector), span), - _span = span; + : _inner = _wrapFormatException( + () => BooleanSelector.parse(selector), + span, + ), + _span = span; const PlatformSelector._(this._inner) : _span = null; @@ -72,30 +74,34 @@ final class PlatformSelector { if (identical(this, all)) return; _wrapFormatException( - () => _inner.validate((name) => + () => _inner.validate( + (name) => _universalValidVariables.contains(name) || - validVariables.contains(name)), - _span); + validVariables.contains(name), + ), + _span, + ); } /// Returns whether the selector matches the given [platform]. - bool evaluate(SuitePlatform platform) => - _inner.evaluate((String variable) => switch (variable) { - _ - when variable == platform.runtime.identifier || - variable == platform.runtime.parent?.identifier || - variable == platform.os.identifier || - variable == platform.compiler.identifier => - true, - 'dart-vm' => platform.runtime.isDartVM, - 'browser' => platform.runtime.isBrowser, - 'js' => platform.compiler.isJS, - 'blink' => platform.runtime.isBlink, - 'posix' => platform.os.isPosix, - 'google' => platform.inGoogle, - 'wasm' => platform.compiler.isWasm, - _ => false, - }); + bool evaluate(SuitePlatform platform) => _inner.evaluate( + (String variable) => switch (variable) { + _ + when variable == platform.runtime.identifier || + variable == platform.runtime.parent?.identifier || + variable == platform.os.identifier || + variable == platform.compiler.identifier => + true, + 'dart-vm' => platform.runtime.isDartVM, + 'browser' => platform.runtime.isBrowser, + 'js' => platform.compiler.isJS, + 'blink' => platform.runtime.isBlink, + 'posix' => platform.os.isPosix, + 'google' => platform.inGoogle, + 'wasm' => platform.compiler.isWasm, + _ => false, + }, + ); /// Returns a new [PlatformSelector] that matches only platforms matched by /// both [this] and [other]. diff --git a/pkgs/test_api/lib/src/backend/remote_exception.dart b/pkgs/test_api/lib/src/backend/remote_exception.dart index 0d705612b..9f5399eaf 100644 --- a/pkgs/test_api/lib/src/backend/remote_exception.dart +++ b/pkgs/test_api/lib/src/backend/remote_exception.dart @@ -48,7 +48,7 @@ final class RemoteException implements Exception { 'type': error.runtimeType.toString(), 'supertype': supertype, 'toString': error.toString(), - 'stackChain': Chain.forTrace(stackTrace).toString() + 'stackChain': Chain.forTrace(stackTrace).toString(), }; } @@ -57,8 +57,10 @@ final class RemoteException implements Exception { /// The returned [AsyncError] is guaranteed to have a [RemoteException] as its /// error and a [Chain] as its stack trace. static AsyncError deserialize(Map serialized) { - return AsyncError(_deserializeException(serialized), - Chain.parse(serialized['stackChain'] as String)); + return AsyncError( + _deserializeException(serialized), + Chain.parse(serialized['stackChain'] as String), + ); } /// Deserializes the exception portion of [serialized]. diff --git a/pkgs/test_api/lib/src/backend/remote_listener.dart b/pkgs/test_api/lib/src/backend/remote_listener.dart index 757720904..389c5e4c6 100644 --- a/pkgs/test_api/lib/src/backend/remote_listener.dart +++ b/pkgs/test_api/lib/src/backend/remote_listener.dart @@ -43,100 +43,122 @@ final class RemoteListener { /// /// If [beforeLoad] is passed, it's called before the tests have been declared /// for this worker. - static StreamChannel start(Function Function() getMain, - {bool hidePrints = true, - Future Function( - StreamChannel Function(String name) suiteChannel)? - beforeLoad}) { + static StreamChannel start( + Function Function() getMain, { + bool hidePrints = true, + Future Function(StreamChannel Function(String name) suiteChannel)? + beforeLoad, + }) { // Synchronous in order to allow `print` output to show up immediately, even // if they are followed by long running synchronous work. - var controller = - StreamChannelController(allowForeignErrors: false, sync: true); + var controller = StreamChannelController( + allowForeignErrors: false, + sync: true, + ); var channel = MultiChannel(controller.local); var verboseChain = true; var printZone = hidePrints ? null : Zone.current; - var spec = ZoneSpecification(print: (_, __, ___, line) { - if (printZone != null) printZone.print(line); - channel.sink.add({'type': 'print', 'line': line}); - }); + var spec = ZoneSpecification( + print: (_, __, ___, line) { + if (printZone != null) printZone.print(line); + channel.sink.add({'type': 'print', 'line': line}); + }, + ); final suiteChannelManager = SuiteChannelManager(); StackTraceFormatter().asCurrent(() { - runZonedGuarded(() async { - Function? main; - try { - main = getMain(); - } on NoSuchMethodError catch (_) { - _sendLoadException(channel, 'No top-level main() function defined.'); - return; - } catch (error, stackTrace) { - _sendError(channel, error, stackTrace, verboseChain); - return; - } - - if (main is! FutureOr Function()) { - _sendLoadException( - channel, 'Top-level main() function takes arguments.'); - return; - } - - var queue = StreamQueue(channel.stream); - var message = await queue.next as Map; - assert(message['type'] == 'initial'); - - queue.rest.cast().listen((message) { - if (message['type'] == 'close') { - controller.local.sink.close(); + runZonedGuarded( + () async { + Function? main; + try { + main = getMain(); + } on NoSuchMethodError catch (_) { + _sendLoadException( + channel, + 'No top-level main() function defined.', + ); + return; + } catch (error, stackTrace) { + _sendError(channel, error, stackTrace, verboseChain); return; } - assert(message['type'] == 'suiteChannel'); - suiteChannelManager.connectIn(message['name'] as String, - channel.virtualChannel((message['id'] as num).toInt())); - }); - - if ((message['asciiGlyphs'] as bool?) ?? false) glyph.ascii = true; - var metadata = Metadata.deserialize(message['metadata'] as Map); - verboseChain = metadata.verboseTrace; - var declarer = Declarer( - metadata: metadata, - platformVariables: Set.from(message['platformVariables'] as Iterable), - collectTraces: message['collectTraces'] as bool, - noRetry: message['noRetry'] as bool, - // TODO: Change to non-nullable https://github.com/dart-lang/test/issues/1591 - allowDuplicateTestNames: - message['allowDuplicateTestNames'] as bool? ?? true, - ); - StackTraceFormatter.current!.configure( - except: _deserializeSet(message['foldTraceExcept'] as List), - only: _deserializeSet(message['foldTraceOnly'] as List)); - - if (beforeLoad != null) { - await beforeLoad(suiteChannelManager.connectOut); - } + if (main is! FutureOr Function()) { + _sendLoadException( + channel, + 'Top-level main() function takes arguments.', + ); + return; + } - await declarer.declare(main); + var queue = StreamQueue(channel.stream); + var message = await queue.next as Map; + assert(message['type'] == 'initial'); + + queue.rest.cast().listen((message) { + if (message['type'] == 'close') { + controller.local.sink.close(); + return; + } + + assert(message['type'] == 'suiteChannel'); + suiteChannelManager.connectIn( + message['name'] as String, + channel.virtualChannel((message['id'] as num).toInt()), + ); + }); + + if ((message['asciiGlyphs'] as bool?) ?? false) glyph.ascii = true; + var metadata = Metadata.deserialize(message['metadata'] as Map); + verboseChain = metadata.verboseTrace; + var declarer = Declarer( + metadata: metadata, + platformVariables: Set.from( + message['platformVariables'] as Iterable, + ), + collectTraces: message['collectTraces'] as bool, + noRetry: message['noRetry'] as bool, + // TODO: Change to non-nullable https://github.com/dart-lang/test/issues/1591 + allowDuplicateTestNames: + message['allowDuplicateTestNames'] as bool? ?? true, + ); + StackTraceFormatter.current!.configure( + except: _deserializeSet(message['foldTraceExcept'] as List), + only: _deserializeSet(message['foldTraceOnly'] as List), + ); - var suite = Suite( - declarer.build(), - SuitePlatform.deserialize(message['platform'] as Object), - path: message['path'] as String, - ignoreTimeouts: message['ignoreTimeouts'] as bool? ?? false, - ); + if (beforeLoad != null) { + await beforeLoad(suiteChannelManager.connectOut); + } - runZoned(() { - Invoker.guard( - () => RemoteListener._(suite, printZone)._listen(channel)); - }, + await declarer.declare(main); + + var suite = Suite( + declarer.build(), + SuitePlatform.deserialize(message['platform'] as Object), + path: message['path'] as String, + ignoreTimeouts: message['ignoreTimeouts'] as bool? ?? false, + ); + + runZoned( + () { + Invoker.guard( + () => RemoteListener._(suite, printZone)._listen(channel), + ); + }, // Make the declarer visible to running tests so that they'll throw // useful errors when calling `test()` and `group()` within a test, // and so they can add to the declarer's `tearDownAll()` list. - zoneValues: {#test.declarer: declarer}); - }, (error, stackTrace) { - _sendError(channel, error, stackTrace, verboseChain); - }, zoneSpecification: spec); + zoneValues: {#test.declarer: declarer}, + ); + }, + (error, stackTrace) { + _sendError(channel, error, stackTrace, verboseChain); + }, + zoneSpecification: spec, + ); }); return controller.foreign; @@ -158,14 +180,21 @@ final class RemoteListener { } /// Sends a message over [channel] indicating an error from user code. - static void _sendError(StreamChannel channel, Object error, - StackTrace stackTrace, bool verboseChain) { + static void _sendError( + StreamChannel channel, + Object error, + StackTrace stackTrace, + bool verboseChain, + ) { channel.sink.add({ 'type': 'error', 'error': RemoteException.serialize( - error, - StackTraceFormatter.current! - .formatStackTrace(stackTrace, verbose: verboseChain)) + error, + StackTraceFormatter.current!.formatStackTrace( + stackTrace, + verbose: verboseChain, + ), + ), }); } @@ -176,7 +205,7 @@ final class RemoteListener { void _listen(MultiChannel channel) { channel.sink.add({ 'type': 'success', - 'root': _serializeGroup(channel, _suite.group, []) + 'root': _serializeGroup(channel, _suite.group, []), }); } @@ -184,26 +213,31 @@ final class RemoteListener { /// /// [parents] lists the groups that contain [group]. Map _serializeGroup( - MultiChannel channel, Group group, Iterable parents) { + MultiChannel channel, + Group group, + Iterable parents, + ) { parents = parents.toList()..add(group); return { 'type': 'group', 'name': group.name, 'metadata': group.metadata.serialize(), - 'trace': group.trace == null - ? null - : StackTraceFormatter.current - ?.formatStackTrace(group.trace!) - .toString() ?? - group.trace?.toString(), + 'trace': + group.trace == null + ? null + : StackTraceFormatter.current + ?.formatStackTrace(group.trace!) + .toString() ?? + group.trace?.toString(), 'location': group.location?.serialize(), 'setUpAll': _serializeTest(channel, group.setUpAll, parents), 'tearDownAll': _serializeTest(channel, group.tearDownAll, parents), - 'entries': group.entries.map((entry) { - return entry is Group - ? _serializeGroup(channel, entry, parents) - : _serializeTest(channel, entry as Test, parents); - }).toList() + 'entries': + group.entries.map((entry) { + return entry is Group + ? _serializeGroup(channel, entry, parents) + : _serializeTest(channel, entry as Test, parents); + }).toList(), }; } @@ -212,28 +246,34 @@ final class RemoteListener { /// [groups] lists the groups that contain [test]. Returns `null` if [test] /// is `null`. Map? _serializeTest( - MultiChannel channel, Test? test, Iterable? groups) { + MultiChannel channel, + Test? test, + Iterable? groups, + ) { if (test == null) return null; var testChannel = channel.virtualChannel(); testChannel.stream.listen((message) { assert(message['command'] == 'run'); - _runLiveTest(test.load(_suite, groups: groups), - channel.virtualChannel((message['channel'] as num).toInt())); + _runLiveTest( + test.load(_suite, groups: groups), + channel.virtualChannel((message['channel'] as num).toInt()), + ); }); return { 'type': 'test', 'name': test.name, 'metadata': test.metadata.serialize(), - 'trace': test.trace == null - ? null - : StackTraceFormatter.current - ?.formatStackTrace(test.trace!) - .toString() ?? - test.trace?.toString(), + 'trace': + test.trace == null + ? null + : StackTraceFormatter.current + ?.formatStackTrace(test.trace!) + .toString() ?? + test.trace?.toString(), 'location': test.location?.serialize(), - 'channel': testChannel.id + 'channel': testChannel.id, }; } @@ -248,7 +288,7 @@ final class RemoteListener { channel.sink.add({ 'type': 'state-change', 'status': state.status.name, - 'result': state.result.name + 'result': state.result.name, }); }); @@ -256,9 +296,12 @@ final class RemoteListener { channel.sink.add({ 'type': 'error', 'error': RemoteException.serialize( - asyncError.error, - StackTraceFormatter.current!.formatStackTrace(asyncError.stackTrace, - verbose: liveTest.test.metadata.verboseTrace)) + asyncError.error, + StackTraceFormatter.current!.formatStackTrace( + asyncError.stackTrace, + verbose: liveTest.test.metadata.verboseTrace, + ), + ), }); }); @@ -267,7 +310,7 @@ final class RemoteListener { channel.sink.add({ 'type': 'message', 'message-type': message.type.name, - 'text': message.text + 'text': message.text, }); }); diff --git a/pkgs/test_api/lib/src/backend/runtime.dart b/pkgs/test_api/lib/src/backend/runtime.dart index ceef2277e..c4db8fa79 100644 --- a/pkgs/test_api/lib/src/backend/runtime.dart +++ b/pkgs/test_api/lib/src/backend/runtime.dart @@ -10,39 +10,61 @@ final class Runtime { // variable tests in test/backend/platform_selector/evaluate_test. /// The command-line Dart VM. - static const Runtime vm = Runtime('VM', 'vm', Compiler.kernel, - [Compiler.kernel, Compiler.source, Compiler.exe], - isDartVM: true); + static const Runtime vm = Runtime('VM', 'vm', Compiler.kernel, [ + Compiler.kernel, + Compiler.source, + Compiler.exe, + ], isDartVM: true); /// Google Chrome. - static const Runtime chrome = Runtime('Chrome', 'chrome', Compiler.dart2js, - [Compiler.dart2js, Compiler.dart2wasm], - isBrowser: true, isBlink: true); + static const Runtime chrome = Runtime( + 'Chrome', + 'chrome', + Compiler.dart2js, + [Compiler.dart2js, Compiler.dart2wasm], + isBrowser: true, + isBlink: true, + ); /// Mozilla Firefox. - static const Runtime firefox = Runtime('Firefox', 'firefox', Compiler.dart2js, - [Compiler.dart2js, Compiler.dart2wasm], - isBrowser: true); + static const Runtime firefox = Runtime( + 'Firefox', + 'firefox', + Compiler.dart2js, + [Compiler.dart2js, Compiler.dart2wasm], + isBrowser: true, + ); /// Apple Safari. - static const Runtime safari = Runtime( - 'Safari', 'safari', Compiler.dart2js, [Compiler.dart2js], - isBrowser: true); + static const Runtime safari = Runtime('Safari', 'safari', Compiler.dart2js, [ + Compiler.dart2js, + ], isBrowser: true); /// Microsoft Internet Explorer. @Deprecated('Internet Explorer is no longer supported') static const Runtime internetExplorer = Runtime( - 'Internet Explorer', 'ie', Compiler.dart2js, [Compiler.dart2js], - isBrowser: true); + 'Internet Explorer', + 'ie', + Compiler.dart2js, + [Compiler.dart2js], + isBrowser: true, + ); /// Microsoft Edge (based on Chromium). static const Runtime edge = Runtime( - 'Microsoft Edge', 'edge', Compiler.dart2js, [Compiler.dart2js], - isBrowser: true, isBlink: true); + 'Microsoft Edge', + 'edge', + Compiler.dart2js, + [Compiler.dart2js], + isBrowser: true, + isBlink: true, + ); /// The command-line Node.js VM. - static const Runtime nodeJS = Runtime('Node.js', 'node', Compiler.dart2js, - [Compiler.dart2js, Compiler.dart2wasm]); + static const Runtime nodeJS = Runtime('Node.js', 'node', Compiler.dart2js, [ + Compiler.dart2js, + Compiler.dart2wasm, + ]); /// The platforms that are supported by the test runner by default. static const List builtIn = [ @@ -92,33 +114,42 @@ final class Runtime { final List supportedCompilers; const Runtime( - this.name, this.identifier, this.defaultCompiler, this.supportedCompilers, - {this.isDartVM = false, - this.isBrowser = false, - this.isBlink = false, - this.isHeadless = false}) - : parent = null; - - Runtime._child(this.name, this.identifier, this.defaultCompiler, - this.supportedCompilers, Runtime this.parent) - : isDartVM = parent.isDartVM, - isBrowser = parent.isBrowser, - isBlink = parent.isBlink, - isHeadless = parent.isHeadless; + this.name, + this.identifier, + this.defaultCompiler, + this.supportedCompilers, { + this.isDartVM = false, + this.isBrowser = false, + this.isBlink = false, + this.isHeadless = false, + }) : parent = null; + + Runtime._child( + this.name, + this.identifier, + this.defaultCompiler, + this.supportedCompilers, + Runtime this.parent, + ) : isDartVM = parent.isDartVM, + isBrowser = parent.isBrowser, + isBlink = parent.isBlink, + isHeadless = parent.isHeadless; /// Converts a JSON-safe representation generated by [serialize] back into a /// [Runtime]. factory Runtime.deserialize(Object serialized) { if (serialized is String) { - return builtIn - .firstWhere((platform) => platform.identifier == serialized); + return builtIn.firstWhere( + (platform) => platform.identifier == serialized, + ); } var map = serialized as Map; var name = map['name'] as String; var identifier = map['identifier'] as String; - var defaultCompiler = - Compiler.deserialize(map['defaultCompiler'] as Object); + var defaultCompiler = Compiler.deserialize( + map['defaultCompiler'] as Object, + ); var supportedCompilers = [ for (var compiler in map['supportedCompilers'] as List) Compiler.deserialize(compiler as Object), @@ -130,15 +161,25 @@ final class Runtime { // a separately-deserialized parent platform. This should be fine, though, // since we only deserialize platforms in the remote execution context // where they're only used to evaluate platform selectors. - return Runtime._child(name, identifier, defaultCompiler, - supportedCompilers, Runtime.deserialize(parent as Object)); + return Runtime._child( + name, + identifier, + defaultCompiler, + supportedCompilers, + Runtime.deserialize(parent as Object), + ); } - return Runtime(name, identifier, defaultCompiler, supportedCompilers, - isDartVM: map['isDartVM'] as bool, - isBrowser: map['isBrowser'] as bool, - isBlink: map['isBlink'] as bool, - isHeadless: map['isHeadless'] as bool); + return Runtime( + name, + identifier, + defaultCompiler, + supportedCompilers, + isDartVM: map['isDartVM'] as bool, + isBrowser: map['isBrowser'] as bool, + isBlink: map['isBlink'] as bool, + isHeadless: map['isHeadless'] as bool, + ); } /// Converts [this] into a JSON-safe object that can be converted back to a @@ -154,7 +195,7 @@ final class Runtime { for (var compiler in supportedCompilers) compiler.serialize(), ], 'identifier': identifier, - 'parent': parent!.serialize() + 'parent': parent!.serialize(), }; } @@ -183,7 +224,12 @@ final class Runtime { Runtime extend(String name, String identifier) { if (parent == null) { return Runtime._child( - name, identifier, defaultCompiler, supportedCompilers, this); + name, + identifier, + defaultCompiler, + supportedCompilers, + this, + ); } throw StateError('A child platform may not be extended.'); } diff --git a/pkgs/test_api/lib/src/backend/stack_trace_formatter.dart b/pkgs/test_api/lib/src/backend/stack_trace_formatter.dart index a495e898a..2696ce8c6 100644 --- a/pkgs/test_api/lib/src/backend/stack_trace_formatter.dart +++ b/pkgs/test_api/lib/src/backend/stack_trace_formatter.dart @@ -47,8 +47,11 @@ final class StackTraceFormatter { /// [except] set indicates packages whose frames should be folded away. If /// [only] is non-empty, it indicates packages whose frames should *not* be /// folded away. - void configure( - {StackTraceMapper? mapper, Set? except, Set? only}) { + void configure({ + StackTraceMapper? mapper, + Set? except, + Set? only, + }) { if (mapper != null) _mapper = mapper; if (except != null) _except = except; if (only != null) _only = only; @@ -63,8 +66,9 @@ final class StackTraceFormatter { Chain formatStackTrace(StackTrace stackTrace, {bool? verbose}) { verbose ??= Invoker.current?.liveTest.test.metadata.verboseTrace ?? false; - var chain = - Chain.forTrace(_mapper?.mapStackTrace(stackTrace) ?? stackTrace); + var chain = Chain.forTrace( + _mapper?.mapStackTrace(stackTrace) ?? stackTrace, + ); if (verbose) return chain; return chain.foldFrames((frame) { diff --git a/pkgs/test_api/lib/src/backend/suite.dart b/pkgs/test_api/lib/src/backend/suite.dart index 910f184b4..5aeee85ff 100644 --- a/pkgs/test_api/lib/src/backend/suite.dart +++ b/pkgs/test_api/lib/src/backend/suite.dart @@ -36,7 +36,7 @@ class Suite { /// /// If [os] is passed without [platform], throws an [ArgumentError]. Suite(Group group, this.platform, {this.ignoreTimeouts = false, this.path}) - : group = _filterGroup(group, platform); + : group = _filterGroup(group, platform); /// Returns [entries] filtered according to [platform] and [os]. /// @@ -54,8 +54,12 @@ class Suite { Suite filter(bool Function(Test) callback) { var filtered = group.filter(callback); filtered ??= Group.root([], metadata: metadata); - return Suite(filtered, platform, - ignoreTimeouts: ignoreTimeouts, path: path); + return Suite( + filtered, + platform, + ignoreTimeouts: ignoreTimeouts, + path: path, + ); } bool get isLoadSuite => false; diff --git a/pkgs/test_api/lib/src/backend/suite_platform.dart b/pkgs/test_api/lib/src/backend/suite_platform.dart index baab6cee1..002eb39e4 100644 --- a/pkgs/test_api/lib/src/backend/suite_platform.dart +++ b/pkgs/test_api/lib/src/backend/suite_platform.dart @@ -31,19 +31,20 @@ final class SuitePlatform { /// /// If [compiler] is `null`, then the default compiler for [runtime] will be /// used. - SuitePlatform(this.runtime, - { - // TODO(https://github.com/dart-lang/test/issues/1935): make required - Compiler? compiler, - this.os = OperatingSystem.none, - this.inGoogle = false}) - : compiler = compiler ?? runtime.defaultCompiler { + SuitePlatform( + this.runtime, { + // TODO(https://github.com/dart-lang/test/issues/1935): make required + Compiler? compiler, + this.os = OperatingSystem.none, + this.inGoogle = false, + }) : compiler = compiler ?? runtime.defaultCompiler { if (runtime.isBrowser && os != OperatingSystem.none) { throw ArgumentError('No OS should be passed for runtime "$runtime".'); } if (!runtime.supportedCompilers.contains(this.compiler)) { throw ArgumentError( - 'The platform $runtime does not support the compiler ${this.compiler}'); + 'The platform $runtime does not support the compiler ${this.compiler}', + ); } } @@ -51,20 +52,23 @@ final class SuitePlatform { /// [SuitePlatform]. factory SuitePlatform.deserialize(Object serialized) { var map = serialized as Map; - return SuitePlatform(Runtime.deserialize(map['runtime'] as Object), - compiler: map.containsKey('compiler') - ? Compiler.deserialize(map['compiler'] as Object) - : null, - os: OperatingSystem.find(map['os'] as String), - inGoogle: map['inGoogle'] as bool); + return SuitePlatform( + Runtime.deserialize(map['runtime'] as Object), + compiler: + map.containsKey('compiler') + ? Compiler.deserialize(map['compiler'] as Object) + : null, + os: OperatingSystem.find(map['os'] as String), + inGoogle: map['inGoogle'] as bool, + ); } /// Converts [this] into a JSON-safe object that can be converted back to a /// [SuitePlatform] using [SuitePlatform.deserialize]. Object serialize() => { - 'runtime': runtime.serialize(), - 'compiler': compiler.serialize(), - 'os': os.identifier, - 'inGoogle': inGoogle - }; + 'runtime': runtime.serialize(), + 'compiler': compiler.serialize(), + 'os': os.identifier, + 'inGoogle': inGoogle, + }; } diff --git a/pkgs/test_api/lib/src/backend/test_location.dart b/pkgs/test_api/lib/src/backend/test_location.dart index 4f16079de..541667d9e 100644 --- a/pkgs/test_api/lib/src/backend/test_location.dart +++ b/pkgs/test_api/lib/src/backend/test_location.dart @@ -16,15 +16,14 @@ class TestLocation { /// This method is also used to provide the location in the JSON reporter when /// a custom location is provided for the test. Map serialize() { - return { - 'url': uri.toString(), - 'line': line, - 'column': column, - }; + return {'url': uri.toString(), 'line': line, 'column': column}; } /// Deserializes the result of [TestLocation.serialize] into a new [TestLocation]. TestLocation.deserialize(Map serialized) - : this(Uri.parse(serialized['url'] as String), serialized['line'] as int, - serialized['column'] as int); + : this( + Uri.parse(serialized['url'] as String), + serialized['line'] as int, + serialized['column'] as int, + ); } diff --git a/pkgs/test_api/lib/src/scaffolding/spawn_hybrid.dart b/pkgs/test_api/lib/src/scaffolding/spawn_hybrid.dart index 7222d5272..bf7e0b591 100644 --- a/pkgs/test_api/lib/src/scaffolding/spawn_hybrid.dart +++ b/pkgs/test_api/lib/src/scaffolding/spawn_hybrid.dart @@ -21,27 +21,33 @@ import 'test_structure.dart' show addTearDown; // package:test will only send a `Map` across this channel, but users of // `hybridMain` can send any json encodeable type. final _transformer = StreamChannelTransformer( - StreamTransformer.fromHandlers(handleData: (message, sink) { - switch (message['type'] as String) { - case 'data': - sink.add(message['data']); - break; + StreamTransformer.fromHandlers( + handleData: (message, sink) { + switch (message['type'] as String) { + case 'data': + sink.add(message['data']); + break; - case 'print': - print(message['line']); - break; + case 'print': + print(message['line']); + break; - case 'error': - var error = RemoteException.deserialize(message['error'] as Map); - sink.addError(error.error, error.stackTrace); - break; - } -}), StreamSinkTransformer.fromHandlers(handleData: (message, sink) { - // This is called synchronously from the user's `Sink.add()` call, so if - // [ensureJsonEncodable] throws here they'll get a helpful stack trace. - ensureJsonEncodable(message); - sink.add(message); -})); + case 'error': + var error = RemoteException.deserialize(message['error'] as Map); + sink.addError(error.error, error.stackTrace); + break; + } + }, + ), + StreamSinkTransformer.fromHandlers( + handleData: (message, sink) { + // This is called synchronously from the user's `Sink.add()` call, so if + // [ensureJsonEncodable] throws here they'll get a helpful stack trace. + ensureJsonEncodable(message); + sink.add(message); + }, + ), +); /// Spawns a VM isolate for the given [uri], which may be a [Uri] or a [String]. /// @@ -143,10 +149,16 @@ StreamChannel spawnHybridUri( /// /// **Note**: If you use this API, be sure to add a dependency on the /// **`stream_channel` package, since you're using its API as well! -StreamChannel spawnHybridCode(String dartCode, - {Object? message, bool stayAlive = false}) { - var uri = Uri.dataFromString(dartCode, - encoding: utf8, mimeType: 'application/dart'); +StreamChannel spawnHybridCode( + String dartCode, { + Object? message, + bool stayAlive = false, +}) { + var uri = Uri.dataFromString( + dartCode, + encoding: utf8, + mimeType: 'application/dart', + ); return _spawn(uri.toString(), message, stayAlive: stayAlive); } @@ -154,8 +166,10 @@ StreamChannel spawnHybridCode(String dartCode, StreamChannel _spawn(String uri, Object? message, {bool stayAlive = false}) { var channel = Zone.current[#test.runner.test_channel] as MultiChannel?; if (channel == null) { - throw UnsupportedError("Can't connect to the test runner.\n" - 'spawnHybridUri() is currently only supported within "dart test".'); + throw UnsupportedError( + "Can't connect to the test runner.\n" + 'spawnHybridUri() is currently only supported within "dart test".', + ); } ensureJsonEncodable(message); @@ -166,7 +180,7 @@ StreamChannel _spawn(String uri, Object? message, {bool stayAlive = false}) { 'type': 'spawn-hybrid-uri', 'url': uri, 'message': message, - 'channel': virtualChannel.id + 'channel': virtualChannel.id, }); if (!stayAlive) { diff --git a/pkgs/test_api/lib/src/scaffolding/test_structure.dart b/pkgs/test_api/lib/src/scaffolding/test_structure.dart index 25b2a852b..5c89a249d 100644 --- a/pkgs/test_api/lib/src/scaffolding/test_structure.dart +++ b/pkgs/test_api/lib/src/scaffolding/test_structure.dart @@ -71,25 +71,31 @@ Declarer get _declarer => Zone.current[#test.declarer] as Declarer; /// avoid this flag if possible and instead use the test runner flag `-n` to /// filter tests by name. @isTest -void test(Object? description, dynamic Function() body, - {String? testOn, - Timeout? timeout, - Object? skip, - Object? tags, - Map? onPlatform, - int? retry, - TestLocation? location, - // TODO(https://github.com/dart-lang/test/issues/2205): Remove deprecated. - @Deprecated('Debug only') @doNotSubmit bool solo = false}) { - _declarer.test(description.toString(), body, - testOn: testOn, - timeout: timeout, - skip: skip, - onPlatform: onPlatform, - tags: tags, - retry: retry, - location: location, - solo: solo); +void test( + Object? description, + dynamic Function() body, { + String? testOn, + Timeout? timeout, + Object? skip, + Object? tags, + Map? onPlatform, + int? retry, + TestLocation? location, + // TODO(https://github.com/dart-lang/test/issues/2205): Remove deprecated. + @Deprecated('Debug only') @doNotSubmit bool solo = false, +}) { + _declarer.test( + description.toString(), + body, + testOn: testOn, + timeout: timeout, + skip: skip, + onPlatform: onPlatform, + tags: tags, + retry: retry, + location: location, + solo: solo, + ); // Force dart2js not to inline this function. We need it to be separate from // `main()` in JS stack traces in order to properly determine the line and @@ -152,25 +158,31 @@ void test(Object? description, dynamic Function() body, /// avoid this flag if possible, and instead use the test runner flag `-n` to /// filter tests by name. @isTestGroup -void group(Object? description, dynamic Function() body, - {String? testOn, - Timeout? timeout, - Object? skip, - Object? tags, - Map? onPlatform, - int? retry, - TestLocation? location, - // TODO(https://github.com/dart-lang/test/issues/2205): Remove deprecated. - @Deprecated('Debug only') @doNotSubmit bool solo = false}) { - _declarer.group(description.toString(), body, - testOn: testOn, - timeout: timeout, - skip: skip, - tags: tags, - onPlatform: onPlatform, - retry: retry, - location: location, - solo: solo); +void group( + Object? description, + dynamic Function() body, { + String? testOn, + Timeout? timeout, + Object? skip, + Object? tags, + Map? onPlatform, + int? retry, + TestLocation? location, + // TODO(https://github.com/dart-lang/test/issues/2205): Remove deprecated. + @Deprecated('Debug only') @doNotSubmit bool solo = false, +}) { + _declarer.group( + description.toString(), + body, + testOn: testOn, + timeout: timeout, + skip: skip, + tags: tags, + onPlatform: onPlatform, + retry: retry, + location: location, + solo: solo, + ); // Force dart2js not to inline this function. We need it to be separate from // `main()` in JS stack traces in order to properly determine the line and diff --git a/pkgs/test_api/lib/src/scaffolding/utils.dart b/pkgs/test_api/lib/src/scaffolding/utils.dart index 134dc497c..a667fed0b 100644 --- a/pkgs/test_api/lib/src/scaffolding/utils.dart +++ b/pkgs/test_api/lib/src/scaffolding/utils.dart @@ -20,8 +20,10 @@ Future pumpEventQueue({int times = 20}) { } /// Registers an exception that was caught for the current test. -void registerException(Object error, - [StackTrace stackTrace = StackTrace.empty]) { +void registerException( + Object error, [ + StackTrace stackTrace = StackTrace.empty, +]) { // This will usually forward directly to [Invoker.current.handleError], but // going through the zone API allows other zones to consistently see errors. Zone.current.handleUncaughtError(error, stackTrace); @@ -47,5 +49,6 @@ void markTestSkipped(String message) => _currentInvoker..skip(message); Invoker get _currentInvoker => Invoker.current ?? (throw StateError( - 'There is no current invoker. Please make sure that you are making the ' - 'call inside a test zone.')); + 'There is no current invoker. Please make sure that you are making the ' + 'call inside a test zone.', + )); diff --git a/pkgs/test_api/lib/test_api.dart b/pkgs/test_api/lib/test_api.dart index 75c15403b..b036d7bff 100644 --- a/pkgs/test_api/lib/test_api.dart +++ b/pkgs/test_api/lib/test_api.dart @@ -2,8 +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. -@Deprecated('package:test_api is not intended for general use. ' - 'Please use package:test.') +@Deprecated( + 'package:test_api is not intended for general use. ' + 'Please use package:test.', +) library; export 'hooks.dart' show TestFailure; diff --git a/pkgs/test_api/test/backend/declarer_test.dart b/pkgs/test_api/test/backend/declarer_test.dart index f095ad046..c3963f77f 100644 --- a/pkgs/test_api/test/backend/declarer_test.dart +++ b/pkgs/test_api/test/backend/declarer_test.dart @@ -65,18 +65,20 @@ void main() { setUp(() => setUpRun = true); test( - 'description 1', - expectAsync0(() { - expect(setUpRun, isTrue); - setUpRun = false; - }, max: 1)); + 'description 1', + expectAsync0(() { + expect(setUpRun, isTrue); + setUpRun = false; + }, max: 1), + ); test( - 'description 2', - expectAsync0(() { - expect(setUpRun, isTrue); - setUpRun = false; - }, max: 1)); + 'description 2', + expectAsync0(() { + expect(setUpRun, isTrue); + setUpRun = false; + }, max: 1), + ); }); await _runTest(tests[0] as Test); @@ -91,10 +93,11 @@ void main() { }); test( - 'description', - expectAsync0(() { - expect(setUpRun, isTrue); - }, max: 1)); + 'description', + expectAsync0(() { + expect(setUpRun, isTrue); + }, max: 1), + ); }); return _runTest(tests.single as Test); @@ -105,29 +108,38 @@ void main() { var secondSetUpRun = false; var thirdSetUpRun = false; var tests = declare(() { - setUp(expectAsync0(() async { - expect(secondSetUpRun, isFalse); - expect(thirdSetUpRun, isFalse); - firstSetUpRun = true; - })); - - setUp(expectAsync0(() async { - expect(firstSetUpRun, isTrue); - expect(thirdSetUpRun, isFalse); - secondSetUpRun = true; - })); - - setUp(expectAsync0(() async { - expect(firstSetUpRun, isTrue); - expect(secondSetUpRun, isTrue); - thirdSetUpRun = true; - })); - - test('description', expectAsync0(() { - expect(firstSetUpRun, isTrue); - expect(secondSetUpRun, isTrue); - expect(thirdSetUpRun, isTrue); - })); + setUp( + expectAsync0(() async { + expect(secondSetUpRun, isFalse); + expect(thirdSetUpRun, isFalse); + firstSetUpRun = true; + }), + ); + + setUp( + expectAsync0(() async { + expect(firstSetUpRun, isTrue); + expect(thirdSetUpRun, isFalse); + secondSetUpRun = true; + }), + ); + + setUp( + expectAsync0(() async { + expect(firstSetUpRun, isTrue); + expect(secondSetUpRun, isTrue); + thirdSetUpRun = true; + }), + ); + + test( + 'description', + expectAsync0(() { + expect(firstSetUpRun, isTrue); + expect(secondSetUpRun, isTrue); + expect(thirdSetUpRun, isTrue); + }), + ); }); await _runTest(tests.single as Test); @@ -142,16 +154,18 @@ void main() { tearDown(() => tearDownRun = true); test( - 'description 1', - expectAsync0(() { - expect(tearDownRun, isFalse); - }, max: 1)); + 'description 1', + expectAsync0(() { + expect(tearDownRun, isFalse); + }, max: 1), + ); test( - 'description 2', - expectAsync0(() { - expect(tearDownRun, isFalse); - }, max: 1)); + 'description 2', + expectAsync0(() { + expect(tearDownRun, isFalse); + }, max: 1), + ); }); await _runTest(tests[0] as Test); @@ -167,12 +181,14 @@ void main() { tearDown(() => tearDownRun = true); test( - 'description 1', - expectAsync0(() { - Invoker.current!.addOutstandingCallback(); - Future(() => throw TestFailure('oh no')) - .whenComplete(Invoker.current!.removeOutstandingCallback); - }, max: 1)); + 'description 1', + expectAsync0(() { + Invoker.current!.addOutstandingCallback(); + Future( + () => throw TestFailure('oh no'), + ).whenComplete(Invoker.current!.removeOutstandingCallback); + }, max: 1), + ); }); await _runTest(tests.single as Test, shouldFail: true); @@ -187,10 +203,11 @@ void main() { }); test( - 'description', - expectAsync0(() { - expect(tearDownRun, isFalse); - }, max: 1)); + 'description', + expectAsync0(() { + expect(tearDownRun, isFalse); + }, max: 1), + ); }); await _runTest(tests.single as Test); @@ -218,26 +235,28 @@ void main() { expect(outstandingCallbackRemovedBeforeTeardown, isTrue); }); - test("isn't run until test body completes after out-of-band error", - () async { - var hasTestFinished = false; - var hasTestFinishedBeforeTeardown = false; - var tests = declare(() { - tearDown(() { - hasTestFinishedBeforeTeardown = hasTestFinished; - }); + test( + "isn't run until test body completes after out-of-band error", + () async { + var hasTestFinished = false; + var hasTestFinishedBeforeTeardown = false; + var tests = declare(() { + tearDown(() { + hasTestFinishedBeforeTeardown = hasTestFinished; + }); - test('description', () { - Future.error('oh no'); - return pumpEventQueue().then((_) { - hasTestFinished = true; + test('description', () { + Future.error('oh no'); + return pumpEventQueue().then((_) { + hasTestFinished = true; + }); }); }); - }); - await _runTest(tests.single as Test, shouldFail: true); - expect(hasTestFinishedBeforeTeardown, isTrue); - }); + await _runTest(tests.single as Test, shouldFail: true); + expect(hasTestFinishedBeforeTeardown, isTrue); + }, + ); test("doesn't complete until there are no outstanding callbacks", () async { var outstandingCallbackRemoved = false; @@ -262,31 +281,38 @@ void main() { var secondTearDownRun = false; var thirdTearDownRun = false; var tests = declare(() { - tearDown(expectAsync0(() async { - expect(secondTearDownRun, isTrue); - expect(thirdTearDownRun, isTrue); - firstTearDownRun = true; - })); - - tearDown(expectAsync0(() async { - expect(firstTearDownRun, isFalse); - expect(thirdTearDownRun, isTrue); - secondTearDownRun = true; - })); - - tearDown(expectAsync0(() async { - expect(firstTearDownRun, isFalse); - expect(secondTearDownRun, isFalse); - thirdTearDownRun = true; - })); + tearDown( + expectAsync0(() async { + expect(secondTearDownRun, isTrue); + expect(thirdTearDownRun, isTrue); + firstTearDownRun = true; + }), + ); + + tearDown( + expectAsync0(() async { + expect(firstTearDownRun, isFalse); + expect(thirdTearDownRun, isTrue); + secondTearDownRun = true; + }), + ); + + tearDown( + expectAsync0(() async { + expect(firstTearDownRun, isFalse); + expect(secondTearDownRun, isFalse); + thirdTearDownRun = true; + }), + ); test( - 'description', - expectAsync0(() { - expect(firstTearDownRun, isFalse); - expect(secondTearDownRun, isFalse); - expect(thirdTearDownRun, isFalse); - }, max: 1)); + 'description', + expectAsync0(() { + expect(firstTearDownRun, isFalse); + expect(secondTearDownRun, isFalse); + expect(thirdTearDownRun, isFalse); + }, max: 1), + ); }); await _runTest(tests.single as Test); @@ -312,9 +338,13 @@ void main() { tearDown(() { final tearDownZone = Zone.current; - expect(tearDownZone.inSameErrorZone(testBodyZone), isTrue, - reason: 'The tear down callback is in a different error zone ' - 'than the test body.'); + expect( + tearDownZone.inSameErrorZone(testBodyZone), + isTrue, + reason: + 'The tear down callback is in a different error zone ' + 'than the test body.', + ); }); test('test', () { @@ -379,12 +409,16 @@ void main() { expect(entries, hasLength(1)); var testGroup = entries.single as Group; - expect(testGroup.metadata.timeout.duration, - equals(const Duration(seconds: 10))); + expect( + testGroup.metadata.timeout.duration, + equals(const Duration(seconds: 10)), + ); expect(testGroup.entries, hasLength(1)); expect(testGroup.entries.single, const TypeMatcher()); - expect(testGroup.entries.single.metadata.timeout.duration, - equals(const Duration(seconds: 20))); + expect( + testGroup.entries.single.metadata.timeout.duration, + equals(const Duration(seconds: 20)), + ); }); test("a test's timeout duration is applied over the group's", () { @@ -396,12 +430,16 @@ void main() { expect(entries, hasLength(1)); var testGroup = entries.single as Group; - expect(testGroup.metadata.timeout.duration, - equals(const Duration(seconds: 10))); + expect( + testGroup.metadata.timeout.duration, + equals(const Duration(seconds: 10)), + ); expect(testGroup.entries, hasLength(1)); expect(testGroup.entries.single, const TypeMatcher()); - expect(testGroup.entries.single.metadata.timeout.duration, - equals(const Duration(seconds: 15))); + expect( + testGroup.entries.single.metadata.timeout.duration, + equals(const Duration(seconds: 15)), + ); }); test('disallows asynchronous groups', () async { @@ -418,19 +456,21 @@ void main() { setUp(() => setUpRun = true); test( - 'description 1', - expectAsync0(() { - expect(setUpRun, isTrue); - setUpRun = false; - }, max: 1)); + 'description 1', + expectAsync0(() { + expect(setUpRun, isTrue); + setUpRun = false; + }, max: 1), + ); }); test( - 'description 2', - expectAsync0(() { - expect(setUpRun, isFalse); - setUpRun = false; - }, max: 1)); + 'description 2', + expectAsync0(() { + expect(setUpRun, isFalse); + setUpRun = false; + }, max: 1), + ); }); await _runTest((entries[0] as Group).entries.single as Test); @@ -442,33 +482,40 @@ void main() { var middleSetUpRun = false; var innerSetUpRun = false; var entries = declare(() { - setUp(expectAsync0(() { - expect(middleSetUpRun, isFalse); - expect(innerSetUpRun, isFalse); - outerSetUpRun = true; - }, max: 1)); + setUp( + expectAsync0(() { + expect(middleSetUpRun, isFalse); + expect(innerSetUpRun, isFalse); + outerSetUpRun = true; + }, max: 1), + ); group('middle', () { - setUp(expectAsync0(() { - expect(outerSetUpRun, isTrue); - expect(innerSetUpRun, isFalse); - middleSetUpRun = true; - }, max: 1)); + setUp( + expectAsync0(() { + expect(outerSetUpRun, isTrue); + expect(innerSetUpRun, isFalse); + middleSetUpRun = true; + }, max: 1), + ); group('inner', () { - setUp(expectAsync0(() { - expect(outerSetUpRun, isTrue); - expect(middleSetUpRun, isTrue); - innerSetUpRun = true; - }, max: 1)); + setUp( + expectAsync0(() { + expect(outerSetUpRun, isTrue); + expect(middleSetUpRun, isTrue); + innerSetUpRun = true; + }, max: 1), + ); test( - 'description', - expectAsync0(() { - expect(outerSetUpRun, isTrue); - expect(middleSetUpRun, isTrue); - expect(innerSetUpRun, isTrue); - }, max: 1)); + 'description', + expectAsync0(() { + expect(outerSetUpRun, isTrue); + expect(middleSetUpRun, isTrue); + expect(innerSetUpRun, isTrue); + }, max: 1), + ); }); }); }); @@ -482,23 +529,28 @@ void main() { var outerSetUpRun = false; var innerSetUpRun = false; var entries = declare(() { - setUp(expectAsync0(() { - expect(innerSetUpRun, isFalse); - return Future(() => outerSetUpRun = true); - }, max: 1)); + setUp( + expectAsync0(() { + expect(innerSetUpRun, isFalse); + return Future(() => outerSetUpRun = true); + }, max: 1), + ); group('inner', () { - setUp(expectAsync0(() { - expect(outerSetUpRun, isTrue); - return Future(() => innerSetUpRun = true); - }, max: 1)); + setUp( + expectAsync0(() { + expect(outerSetUpRun, isTrue); + return Future(() => innerSetUpRun = true); + }, max: 1), + ); test( - 'description', - expectAsync0(() { - expect(outerSetUpRun, isTrue); - expect(innerSetUpRun, isTrue); - }, max: 1)); + 'description', + expectAsync0(() { + expect(outerSetUpRun, isTrue); + expect(innerSetUpRun, isTrue); + }, max: 1), + ); }); }); @@ -521,7 +573,9 @@ void main() { expect(outerGroup.metadata.tags, unorderedEquals(['a'])); expect(innerGroup.metadata.tags, unorderedEquals(['a', 'b', 'c'])); expect( - testWithTags.metadata.tags, unorderedEquals(['a', 'b', 'c', 'd'])); + testWithTags.metadata.tags, + unorderedEquals(['a', 'b', 'c', 'd']), + ); }); test('throws on invalid tags', () { @@ -543,17 +597,19 @@ void main() { tearDown(() => tearDownRun = true); test( - 'description 1', - expectAsync0(() { - expect(tearDownRun, isFalse); - }, max: 1)); + 'description 1', + expectAsync0(() { + expect(tearDownRun, isFalse); + }, max: 1), + ); }); test( - 'description 2', - expectAsync0(() { - expect(tearDownRun, isFalse); - }, max: 1)); + 'description 2', + expectAsync0(() { + expect(tearDownRun, isFalse); + }, max: 1), + ); }); var testGroup = entries[0] as Group; @@ -568,33 +624,40 @@ void main() { var middleTearDownRun = false; var outerTearDownRun = false; var entries = declare(() { - tearDown(expectAsync0(() { - expect(innerTearDownRun, isTrue); - expect(middleTearDownRun, isTrue); - outerTearDownRun = true; - }, max: 1)); + tearDown( + expectAsync0(() { + expect(innerTearDownRun, isTrue); + expect(middleTearDownRun, isTrue); + outerTearDownRun = true; + }, max: 1), + ); group('middle', () { - tearDown(expectAsync0(() { - expect(innerTearDownRun, isTrue); - expect(outerTearDownRun, isFalse); - middleTearDownRun = true; - }, max: 1)); + tearDown( + expectAsync0(() { + expect(innerTearDownRun, isTrue); + expect(outerTearDownRun, isFalse); + middleTearDownRun = true; + }, max: 1), + ); group('inner', () { - tearDown(expectAsync0(() { - expect(outerTearDownRun, isFalse); - expect(middleTearDownRun, isFalse); - innerTearDownRun = true; - }, max: 1)); + tearDown( + expectAsync0(() { + expect(outerTearDownRun, isFalse); + expect(middleTearDownRun, isFalse); + innerTearDownRun = true; + }, max: 1), + ); test( - 'description', - expectAsync0(() { - expect(outerTearDownRun, isFalse); - expect(middleTearDownRun, isFalse); - expect(innerTearDownRun, isFalse); - }, max: 1)); + 'description', + expectAsync0(() { + expect(outerTearDownRun, isFalse); + expect(middleTearDownRun, isFalse); + expect(innerTearDownRun, isFalse); + }, max: 1), + ); }); }); }); @@ -611,23 +674,28 @@ void main() { var outerTearDownRun = false; var innerTearDownRun = false; var entries = declare(() { - tearDown(expectAsync0(() { - expect(innerTearDownRun, isTrue); - return Future(() => outerTearDownRun = true); - }, max: 1)); + tearDown( + expectAsync0(() { + expect(innerTearDownRun, isTrue); + return Future(() => outerTearDownRun = true); + }, max: 1), + ); group('inner', () { - tearDown(expectAsync0(() { - expect(outerTearDownRun, isFalse); - return Future(() => innerTearDownRun = true); - }, max: 1)); + tearDown( + expectAsync0(() { + expect(outerTearDownRun, isFalse); + return Future(() => innerTearDownRun = true); + }, max: 1), + ); test( - 'description', - expectAsync0(() { - expect(outerTearDownRun, isFalse); - expect(innerTearDownRun, isFalse); - }, max: 1)); + 'description', + expectAsync0(() { + expect(outerTearDownRun, isFalse); + expect(innerTearDownRun, isFalse); + }, max: 1), + ); }); }); @@ -650,10 +718,11 @@ void main() { }); test( - 'description', - expectAsync0(() { - expect(outerTearDownRun, isFalse); - }, max: 1)); + 'description', + expectAsync0(() { + expect(outerTearDownRun, isFalse); + }, max: 1), + ); }); }); @@ -667,21 +736,24 @@ void main() { group('duplicate names', () { test('can be enabled', () { expect( - () => declare(() { - test('a', expectAsync0(() {}, count: 0)); - test('a', expectAsync0(() {}, count: 0)); - }, allowDuplicateTestNames: false), - throwsA(isA() - .having((e) => e.name, 'name', 'a'))); + () => declare(() { + test('a', expectAsync0(() {}, count: 0)); + test('a', expectAsync0(() {}, count: 0)); + }, allowDuplicateTestNames: false), + throwsA( + isA().having((e) => e.name, 'name', 'a'), + ), + ); }); test('are allowed by default', () { expect( - declare(() { - test('a', expectAsync0(() {}, count: 0)); - test('a', expectAsync0(() {}, count: 0)); - }).map((e) => e.name), - equals(['a', 'a'])); + declare(() { + test('a', expectAsync0(() {}, count: 0)); + test('a', expectAsync0(() {}, count: 0)); + }).map((e) => e.name), + equals(['a', 'a']), + ); }); }); } diff --git a/pkgs/test_api/test/backend/invoker_test.dart b/pkgs/test_api/test/backend/invoker_test.dart index ef08b387a..60ee57379 100644 --- a/pkgs/test_api/test/backend/invoker_test.dart +++ b/pkgs/test_api/test/backend/invoker_test.dart @@ -39,25 +39,27 @@ void main() { expect(invoker.liveTest, equals(liveTest)); }); - test('returns the current invoker in a test body after the test completes', - () async { - Status? status; - var completer = Completer(); - var liveTest = _localTest(() { - // Use the event loop to wait longer than a microtask for the test to - // complete. - Future(() { - status = Invoker.current!.liveTest.state.status; - completer.complete(Invoker.current); - }); - }).load(suite); - liveTest.onError.listen(expectAsync1((_) {}, count: 0)); - - expect(liveTest.run(), completes); - var invoker = await completer.future; - expect(invoker.liveTest, equals(liveTest)); - expect(status, equals(Status.complete)); - }); + test( + 'returns the current invoker in a test body after the test completes', + () async { + Status? status; + var completer = Completer(); + var liveTest = _localTest(() { + // Use the event loop to wait longer than a microtask for the test to + // complete. + Future(() { + status = Invoker.current!.liveTest.state.status; + completer.complete(Invoker.current); + }); + }).load(suite); + liveTest.onError.listen(expectAsync1((_) {}, count: 0)); + + expect(liveTest.run(), completes); + var invoker = await completer.future; + expect(invoker.liveTest, equals(liveTest)); + expect(status, equals(Status.complete)); + }, + ); }); group('in a successful test,', () { @@ -91,15 +93,21 @@ void main() { liveTest.onError.listen(expectAsync1((_) {}, count: 0)); var first = true; - liveTest.onStateChange.listen(expectAsync1((state) { - if (first) { - expect(state.status, equals(Status.running)); - first = false; - } else { - expect(state.status, equals(Status.complete)); - } - expect(state.result, equals(Result.success)); - }, count: 2, max: 2)); + liveTest.onStateChange.listen( + expectAsync1( + (state) { + if (first) { + expect(state.status, equals(Status.running)); + first = false; + } else { + expect(state.status, equals(Status.complete)); + } + expect(state.result, equals(Result.success)); + }, + count: 2, + max: 2, + ), + ); return liveTest.run(); }); @@ -110,9 +118,12 @@ void main() { testRun = true; }).load(suite); - expect(liveTest.onComplete.then((_) { - expect(testRun, isTrue); - }), completes); + expect( + liveTest.onComplete.then((_) { + expect(testRun, isTrue); + }), + completes, + ); return liveTest.run(); }); @@ -137,61 +148,77 @@ void main() { return liveTest.run(); }); - test('a failure reported asynchronously during the test causes it to fail', - () { - var liveTest = _localTest(() { - Invoker.current!.addOutstandingCallback(); - Future(() => registerException(TestFailure('oh no'))) - .whenComplete(Invoker.current!.removeOutstandingCallback); - }).load(suite); - - expectSingleFailure(liveTest); - return liveTest.run(); - }); - - test('a failure thrown asynchronously during the test causes it to fail', - () { - var liveTest = _localTest(() { - Invoker.current!.addOutstandingCallback(); - Future(() => throw TestFailure('oh no')) - .whenComplete(Invoker.current!.removeOutstandingCallback); - }).load(suite); + test( + 'a failure reported asynchronously during the test causes it to fail', + () { + var liveTest = _localTest(() { + Invoker.current!.addOutstandingCallback(); + Future( + () => registerException(TestFailure('oh no')), + ).whenComplete(Invoker.current!.removeOutstandingCallback); + }).load(suite); - expectSingleFailure(liveTest); - return liveTest.run(); - }); + expectSingleFailure(liveTest); + return liveTest.run(); + }, + ); - test('a failure reported asynchronously after the test causes it to error', - () { - var liveTest = _localTest(() { - Future(() => registerException(TestFailure('oh no'))); - }).load(suite); + test( + 'a failure thrown asynchronously during the test causes it to fail', + () { + var liveTest = _localTest(() { + Invoker.current!.addOutstandingCallback(); + Future( + () => throw TestFailure('oh no'), + ).whenComplete(Invoker.current!.removeOutstandingCallback); + }).load(suite); - expectStates(liveTest, [ - const State(Status.running, Result.success), - const State(Status.complete, Result.success), - const State(Status.complete, Result.failure), - const State(Status.complete, Result.error) - ]); + expectSingleFailure(liveTest); + return liveTest.run(); + }, + ); + + test( + 'a failure reported asynchronously after the test causes it to error', + () { + var liveTest = _localTest(() { + Future(() => registerException(TestFailure('oh no'))); + }).load(suite); + + expectStates(liveTest, [ + const State(Status.running, Result.success), + const State(Status.complete, Result.success), + const State(Status.complete, Result.failure), + const State(Status.complete, Result.error), + ]); - expectErrors(liveTest, [ - (error) { - expect( - lastState, equals(const State(Status.complete, Result.failure))); - expect(error, isTestFailure('oh no')); - }, - (error) { - expect(lastState, equals(const State(Status.complete, Result.error))); - expect( + expectErrors(liveTest, [ + (error) { + expect( + lastState, + equals(const State(Status.complete, Result.failure)), + ); + expect(error, isTestFailure('oh no')); + }, + (error) { + expect( + lastState, + equals(const State(Status.complete, Result.error)), + ); + expect( error, - equals('This test failed after it had already completed.\n' - 'Make sure to use a matching library which informs the ' - 'test runner\nof pending async work.')); - } - ]); + equals( + 'This test failed after it had already completed.\n' + 'Make sure to use a matching library which informs the ' + 'test runner\nof pending async work.', + ), + ); + }, + ]); - return liveTest.run(); - }); + return liveTest.run(); + }, + ); test('multiple asynchronous failures are reported', () { var liveTest = _localTest(() { @@ -199,13 +226,14 @@ void main() { Future(() => throw TestFailure('one')); Future(() => throw TestFailure('two')); Future(() => throw TestFailure('three')); - Future(() => throw TestFailure('four')) - .whenComplete(Invoker.current!.removeOutstandingCallback); + Future( + () => throw TestFailure('four'), + ).whenComplete(Invoker.current!.removeOutstandingCallback); }).load(suite); expectStates(liveTest, [ const State(Status.running, Result.success), - const State(Status.complete, Result.failure) + const State(Status.complete, Result.failure), ]); expectErrors(liveTest, [ @@ -221,7 +249,7 @@ void main() { }, (error) { expect(error, isTestFailure('four')); - } + }, ]); return liveTest.run(); @@ -235,7 +263,7 @@ void main() { expectStates(liveTest, [ const State(Status.running, Result.success), - const State(Status.complete, Result.error) + const State(Status.complete, Result.error), ]); expectErrors(liveTest, [ @@ -245,7 +273,7 @@ void main() { }, (error) { expect(error, isTestFailure('fail')); - } + }, ]); return liveTest.run(); @@ -271,58 +299,72 @@ void main() { return liveTest.run(); }); - test('an error reported asynchronously during the test causes it to error', - () { - var liveTest = _localTest(() { - Invoker.current!.addOutstandingCallback(); - Future(() => registerException('oh no')) - .whenComplete(Invoker.current!.removeOutstandingCallback); - }).load(suite); - - expectSingleError(liveTest); - return liveTest.run(); - }); - - test('an error thrown asynchronously during the test causes it to error', - () { - var liveTest = _localTest(() { - Invoker.current!.addOutstandingCallback(); - Future(() => throw 'oh no') - .whenComplete(Invoker.current!.removeOutstandingCallback); - }).load(suite); + test( + 'an error reported asynchronously during the test causes it to error', + () { + var liveTest = _localTest(() { + Invoker.current!.addOutstandingCallback(); + Future( + () => registerException('oh no'), + ).whenComplete(Invoker.current!.removeOutstandingCallback); + }).load(suite); - expectSingleError(liveTest); - return liveTest.run(); - }); + expectSingleError(liveTest); + return liveTest.run(); + }, + ); - test('an error reported asynchronously after the test causes it to error', - () { - var liveTest = _localTest(() { - Future(() => registerException('oh no')); - }).load(suite); + test( + 'an error thrown asynchronously during the test causes it to error', + () { + var liveTest = _localTest(() { + Invoker.current!.addOutstandingCallback(); + Future( + () => throw 'oh no', + ).whenComplete(Invoker.current!.removeOutstandingCallback); + }).load(suite); - expectStates(liveTest, [ - const State(Status.running, Result.success), - const State(Status.complete, Result.success), - const State(Status.complete, Result.error) - ]); + expectSingleError(liveTest); + return liveTest.run(); + }, + ); + + test( + 'an error reported asynchronously after the test causes it to error', + () { + var liveTest = _localTest(() { + Future(() => registerException('oh no')); + }).load(suite); + + expectStates(liveTest, [ + const State(Status.running, Result.success), + const State(Status.complete, Result.success), + const State(Status.complete, Result.error), + ]); - expectErrors(liveTest, [ - (error) { - expect(lastState, equals(const State(Status.complete, Result.error))); - expect(error, equals('oh no')); - }, - (error) { - expect( + expectErrors(liveTest, [ + (error) { + expect( + lastState, + equals(const State(Status.complete, Result.error)), + ); + expect(error, equals('oh no')); + }, + (error) { + expect( error, - equals('This test failed after it had already completed.\n' - 'Make sure to use a matching library which informs the ' - 'test runner\nof pending async work.')); - } - ]); + equals( + 'This test failed after it had already completed.\n' + 'Make sure to use a matching library which informs the ' + 'test runner\nof pending async work.', + ), + ); + }, + ]); - return liveTest.run(); - }); + return liveTest.run(); + }, + ); test('multiple asynchronous errors are reported', () { var liveTest = _localTest(() { @@ -330,13 +372,14 @@ void main() { Future(() => throw 'one'); Future(() => throw 'two'); Future(() => throw 'three'); - Future(() => throw 'four') - .whenComplete(Invoker.current!.removeOutstandingCallback); + Future( + () => throw 'four', + ).whenComplete(Invoker.current!.removeOutstandingCallback); }).load(suite); expectStates(liveTest, [ const State(Status.running, Result.success), - const State(Status.complete, Result.error) + const State(Status.complete, Result.error), ]); expectErrors(liveTest, [ @@ -352,7 +395,7 @@ void main() { }, (error) { expect(error, equals('four')); - } + }, ]); return liveTest.run(); @@ -367,44 +410,48 @@ void main() { expectStates(liveTest, [ const State(Status.running, Result.success), const State(Status.complete, Result.failure), - const State(Status.complete, Result.error) + const State(Status.complete, Result.error), ]); expectErrors(liveTest, [ (error) { expect( - lastState, equals(const State(Status.complete, Result.failure))); + lastState, + equals(const State(Status.complete, Result.failure)), + ); expect(error, isTestFailure('fail')); }, (error) { expect(lastState, equals(const State(Status.complete, Result.error))); expect(error, equals('error')); - } + }, ]); return liveTest.run(); }); }); - test("a test doesn't complete until there are no outstanding callbacks", - () async { - var outstandingCallbackRemoved = false; - var liveTest = _localTest(() { - Invoker.current!.addOutstandingCallback(); - - // Pump the event queue to make sure the test isn't coincidentally - // completing after the outstanding callback is removed. - pumpEventQueue().then((_) { - outstandingCallbackRemoved = true; - Invoker.current!.removeOutstandingCallback(); - }); - }).load(suite); - - liveTest.onError.listen(expectAsync1((_) {}, count: 0)); - - await liveTest.run(); - expect(outstandingCallbackRemoved, isTrue); - }); + test( + "a test doesn't complete until there are no outstanding callbacks", + () async { + var outstandingCallbackRemoved = false; + var liveTest = _localTest(() { + Invoker.current!.addOutstandingCallback(); + + // Pump the event queue to make sure the test isn't coincidentally + // completing after the outstanding callback is removed. + pumpEventQueue().then((_) { + outstandingCallbackRemoved = true; + Invoker.current!.removeOutstandingCallback(); + }); + }).load(suite); + + liveTest.onError.listen(expectAsync1((_) {}, count: 0)); + + await liveTest.run(); + expect(outstandingCallbackRemoved, isTrue); + }, + ); test("a test's prints are captured and reported", () { expect(() { @@ -414,13 +461,14 @@ void main() { }).load(suite); expect( - liveTest.onMessage.take(2).toList().then((messages) { - expect(messages[0].type, equals(MessageType.print)); - expect(messages[0].text, equals('Hello,')); - expect(messages[1].type, equals(MessageType.print)); - expect(messages[1].text, equals('world!')); - }), - completes); + liveTest.onMessage.take(2).toList().then((messages) { + expect(messages[0].type, equals(MessageType.print)); + expect(messages[0].text, equals('Hello,')); + expect(messages[1].type, equals(MessageType.print)); + expect(messages[1].text, equals('world!')); + }), + completes, + ); return liveTest.run(); }, prints(isEmpty)); @@ -428,24 +476,26 @@ void main() { group('timeout:', () { test('A test can be timed out', () { - var liveTest = _localTest(() { - Invoker.current!.addOutstandingCallback(); - }, - metadata: Metadata( - chainStackTraces: true, - timeout: const Timeout(Duration.zero))) - .load(suite); + var liveTest = _localTest( + () { + Invoker.current!.addOutstandingCallback(); + }, + metadata: Metadata( + chainStackTraces: true, + timeout: const Timeout(Duration.zero), + ), + ).load(suite); expectStates(liveTest, [ const State(Status.running, Result.success), - const State(Status.complete, Result.error) + const State(Status.complete, Result.error), ]); expectErrors(liveTest, [ (error) { expect(lastState!.status, equals(Status.complete)); expect(error, const TypeMatcher()); - } + }, ]); liveTest.run(); @@ -453,17 +503,19 @@ void main() { test('can be ignored', () { suite = Suite(Group.root([]), suitePlatform, ignoreTimeouts: true); - var liveTest = _localTest(() async { - await Future.delayed(const Duration(milliseconds: 10)); - }, - metadata: Metadata( - chainStackTraces: true, - timeout: const Timeout(Duration.zero))) - .load(suite); + var liveTest = _localTest( + () async { + await Future.delayed(const Duration(milliseconds: 10)); + }, + metadata: Metadata( + chainStackTraces: true, + timeout: const Timeout(Duration.zero), + ), + ).load(suite); expectStates(liveTest, [ const State(Status.running, Result.success), - const State(Status.complete, Result.success) + const State(Status.complete, Result.success), ]); liveTest.run(); @@ -480,7 +532,7 @@ void main() { }, () { secondTearDownStarted = true; - } + }, ]); expect(secondTearDownStarted, isTrue); expect(firstTearDownStarted, isTrue); @@ -504,24 +556,29 @@ void main() { expect(secondTearDownStarted, isTrue); }); - test('allows next tear down to run while there are still prior callbacks', - () async { - var firstTearDownAsyncWork = Completer(); - var secondTearDownStarted = false; - unawaited(Invoker.current!.runTearDowns([ - () { - secondTearDownStarted = true; - }, - () { - Invoker.current!.addOutstandingCallback(); - firstTearDownAsyncWork.future - .whenComplete(Invoker.current!.removeOutstandingCallback); - }, - ])); - await pumpEventQueue(); - expect(secondTearDownStarted, isTrue); - firstTearDownAsyncWork.complete(); - }); + test( + 'allows next tear down to run while there are still prior callbacks', + () async { + var firstTearDownAsyncWork = Completer(); + var secondTearDownStarted = false; + unawaited( + Invoker.current!.runTearDowns([ + () { + secondTearDownStarted = true; + }, + () { + Invoker.current!.addOutstandingCallback(); + firstTearDownAsyncWork.future.whenComplete( + Invoker.current!.removeOutstandingCallback, + ); + }, + ]), + ); + await pumpEventQueue(); + expect(secondTearDownStarted, isTrue); + firstTearDownAsyncWork.complete(); + }, + ); test('forwards errors to the enclosing test but does not end it', () async { var liveTest = _localTest(() async { @@ -529,13 +586,13 @@ void main() { await Invoker.current!.runTearDowns([ () { throw 'oh no'; - } + }, ]); }).load(suite); expectStates(liveTest, [ const State(Status.running, Result.success), - const State(Status.complete, Result.error) + const State(Status.complete, Result.error), ]); var isComplete = false; @@ -565,10 +622,12 @@ void main() { }).load(suite); liveTest.onError.listen(expectAsync1((_) {}, count: 1)); - liveTest.onMessage.listen(expectAsync1((message) { - expect(message.type, equals(MessageType.print)); - expect(message.text, equals('only on failure')); - }, count: 1)); + liveTest.onMessage.listen( + expectAsync1((message) { + expect(message.type, equals(MessageType.print)); + expect(message.text, equals('only on failure')); + }, count: 1), + ); await liveTest.run(); }); diff --git a/pkgs/test_api/test/backend/metadata_test.dart b/pkgs/test_api/test/backend/metadata_test.dart index f42a5357b..5c72bb37d 100644 --- a/pkgs/test_api/test/backend/metadata_test.dart +++ b/pkgs/test_api/test/backend/metadata_test.dart @@ -13,7 +13,9 @@ void main() { group('tags', () { test('parses an Iterable', () { expect( - Metadata.parse(tags: ['a', 'b']).tags, unorderedEquals(['a', 'b'])); + Metadata.parse(tags: ['a', 'b']).tags, + unorderedEquals(['a', 'b']), + ); }); test('parses a String', () { @@ -52,8 +54,9 @@ void main() { test("returns the normal metadata if there's no tags", () { var metadata = Metadata( - verboseTrace: true, - forTag: {BooleanSelector.parse('foo'): Metadata(skip: true)}); + verboseTrace: true, + forTag: {BooleanSelector.parse('foo'): Metadata(skip: true)}, + ); expect(metadata.verboseTrace, isTrue); expect(metadata.skip, isFalse); expect(metadata.forTag, contains(BooleanSelector.parse('foo'))); @@ -62,9 +65,10 @@ void main() { test("returns the normal metadata if forTag doesn't match tags", () { var metadata = Metadata( - verboseTrace: true, - tags: ['bar', 'baz'], - forTag: {BooleanSelector.parse('foo'): Metadata(skip: true)}); + verboseTrace: true, + tags: ['bar', 'baz'], + forTag: {BooleanSelector.parse('foo'): Metadata(skip: true)}, + ); expect(metadata.verboseTrace, isTrue); expect(metadata.skip, isFalse); @@ -74,15 +78,15 @@ void main() { }); test('resolves forTags that match tags', () { - var metadata = Metadata(verboseTrace: true, tags: [ - 'foo', - 'bar', - 'baz' - ], forTag: { - BooleanSelector.parse('foo'): Metadata(skip: true), - BooleanSelector.parse('baz'): Metadata(timeout: Timeout.none), - BooleanSelector.parse('qux'): Metadata(skipReason: 'blah') - }); + var metadata = Metadata( + verboseTrace: true, + tags: ['foo', 'bar', 'baz'], + forTag: { + BooleanSelector.parse('foo'): Metadata(skip: true), + BooleanSelector.parse('baz'): Metadata(timeout: Timeout.none), + BooleanSelector.parse('qux'): Metadata(skipReason: 'blah'), + }, + ); expect(metadata.verboseTrace, isTrue); expect(metadata.skip, isTrue); @@ -93,14 +97,17 @@ void main() { }); test('resolves forTags that adds a behavioral tag', () { - var metadata = Metadata(tags: [ - 'foo' - ], forTag: { - BooleanSelector.parse('baz'): Metadata(skip: true), - BooleanSelector.parse('bar'): - Metadata(verboseTrace: true, tags: ['baz']), - BooleanSelector.parse('foo'): Metadata(tags: ['bar']) - }); + var metadata = Metadata( + tags: ['foo'], + forTag: { + BooleanSelector.parse('baz'): Metadata(skip: true), + BooleanSelector.parse('bar'): Metadata( + verboseTrace: true, + tags: ['baz'], + ), + BooleanSelector.parse('foo'): Metadata(tags: ['bar']), + }, + ); expect(metadata.verboseTrace, isTrue); expect(metadata.skip, isTrue); @@ -109,24 +116,25 @@ void main() { }); test('resolves forTags that adds circular tags', () { - var metadata = Metadata(tags: [ - 'foo' - ], forTag: { - BooleanSelector.parse('foo'): Metadata(tags: ['bar']), - BooleanSelector.parse('bar'): Metadata(tags: ['baz']), - BooleanSelector.parse('baz'): Metadata(tags: ['foo']) - }); + var metadata = Metadata( + tags: ['foo'], + forTag: { + BooleanSelector.parse('foo'): Metadata(tags: ['bar']), + BooleanSelector.parse('bar'): Metadata(tags: ['baz']), + BooleanSelector.parse('baz'): Metadata(tags: ['foo']), + }, + ); expect(metadata.tags, unorderedEquals(['foo', 'bar', 'baz'])); expect(metadata.forTag, isEmpty); }); test('base metadata takes precedence over forTags', () { - var metadata = Metadata(verboseTrace: true, tags: [ - 'foo' - ], forTag: { - BooleanSelector.parse('foo'): Metadata(verboseTrace: false) - }); + var metadata = Metadata( + verboseTrace: true, + tags: ['foo'], + forTag: {BooleanSelector.parse('foo'): Metadata(verboseTrace: false)}, + ); expect(metadata.verboseTrace, isTrue); }); @@ -134,14 +142,18 @@ void main() { group('onPlatform', () { test('parses a valid map', () { - var metadata = Metadata.parse(onPlatform: { - 'chrome': const Timeout.factor(2), - 'vm': [const Skip(), const Timeout.factor(3)] - }); + var metadata = Metadata.parse( + onPlatform: { + 'chrome': const Timeout.factor(2), + 'vm': [const Skip(), const Timeout.factor(3)], + }, + ); var key = metadata.onPlatform.keys.first; expect( - key.evaluate(SuitePlatform(Runtime.chrome, compiler: null)), isTrue); + key.evaluate(SuitePlatform(Runtime.chrome, compiler: null)), + isTrue, + ); expect(key.evaluate(SuitePlatform(Runtime.vm, compiler: null)), isFalse); var value = metadata.onPlatform.values.first; expect(value.timeout.scaleFactor, equals(2)); @@ -149,7 +161,9 @@ void main() { key = metadata.onPlatform.keys.last; expect(key.evaluate(SuitePlatform(Runtime.vm, compiler: null)), isTrue); expect( - key.evaluate(SuitePlatform(Runtime.chrome, compiler: null)), isFalse); + key.evaluate(SuitePlatform(Runtime.chrome, compiler: null)), + isFalse, + ); value = metadata.onPlatform.values.last; expect(value.skip, isTrue); expect(value.timeout.scaleFactor, equals(3)); @@ -163,9 +177,11 @@ void main() { test('refuses an invalid value in a list', () { expect(() { - Metadata.parse(onPlatform: { - 'chrome': [const TestOn('chrome')] - }); + Metadata.parse( + onPlatform: { + 'chrome': [const TestOn('chrome')], + }, + ); }, throwsArgumentError); }); @@ -177,25 +193,30 @@ void main() { test('refuses multiple Timeouts', () { expect(() { - Metadata.parse(onPlatform: { - 'chrome': [const Timeout.factor(2), const Timeout.factor(3)] - }); + Metadata.parse( + onPlatform: { + 'chrome': [const Timeout.factor(2), const Timeout.factor(3)], + }, + ); }, throwsArgumentError); }); test('refuses multiple Skips', () { expect(() { - Metadata.parse(onPlatform: { - 'chrome': [const Skip(), const Skip()] - }); + Metadata.parse( + onPlatform: { + 'chrome': [const Skip(), const Skip()], + }, + ); }, throwsArgumentError); }); }); group('validatePlatformSelectors', () { test('succeeds if onPlatform uses valid platforms', () { - Metadata.parse(onPlatform: {'vm || browser': const Skip()}) - .validatePlatformSelectors({'vm'}); + Metadata.parse( + onPlatform: {'vm || browser': const Skip()}, + ).validatePlatformSelectors({'vm'}); }); test('succeeds if testOn uses valid platforms', () { @@ -208,8 +229,9 @@ void main() { test('fails if onPlatform uses an invalid platform', () { expect(() { - Metadata.parse(onPlatform: {'unknown': const Skip()}) - .validatePlatformSelectors({'vm'}); + Metadata.parse( + onPlatform: {'unknown': const Skip()}, + ).validatePlatformSelectors({'vm'}); }, throwsFormatException); }); @@ -229,29 +251,28 @@ void main() { group('change', () { test('preserves all fields if no parameters are passed', () { var metadata = Metadata( - testOn: PlatformSelector.parse('linux'), - timeout: const Timeout.factor(2), - skip: true, - skipReason: 'just because', - verboseTrace: true, - tags: [ - 'foo', - 'bar' - ], - onPlatform: { - PlatformSelector.parse('mac-os'): Metadata(skip: false) - }, - forTag: { - BooleanSelector.parse('slow'): - Metadata(timeout: const Timeout.factor(4)) - }); + testOn: PlatformSelector.parse('linux'), + timeout: const Timeout.factor(2), + skip: true, + skipReason: 'just because', + verboseTrace: true, + tags: ['foo', 'bar'], + onPlatform: {PlatformSelector.parse('mac-os'): Metadata(skip: false)}, + forTag: { + BooleanSelector.parse('slow'): Metadata( + timeout: const Timeout.factor(4), + ), + }, + ); expect(metadata.serialize(), equals(metadata.change().serialize())); }); test('updates a changed field', () { var metadata = Metadata(timeout: const Timeout.factor(2)); - expect(metadata.change(timeout: const Timeout.factor(3)).timeout, - equals(const Timeout.factor(3))); + expect( + metadata.change(timeout: const Timeout.factor(3)).timeout, + equals(const Timeout.factor(3)), + ); }); }); } diff --git a/pkgs/test_api/test/frontend/add_tear_down_test.dart b/pkgs/test_api/test/frontend/add_tear_down_test.dart index de4bb5549..0cf0fe424 100644 --- a/pkgs/test_api/test/frontend/add_tear_down_test.dart +++ b/pkgs/test_api/test/frontend/add_tear_down_test.dart @@ -169,9 +169,13 @@ void main() { addTearDown(() { final tearDownZone = Zone.current; - expect(tearDownZone.inSameErrorZone(testBodyZone), isTrue, - reason: 'The tear down callback is in a different error zone ' - 'than the test body.'); + expect( + tearDownZone.inSameErrorZone(testBodyZone), + isTrue, + reason: + 'The tear down callback is in a different error zone ' + 'than the test body.', + ); }); }); }); @@ -226,9 +230,12 @@ void main() { expect(tearDown2Run, isFalse); expect(tearDown3Run, isFalse); - expect(Future(() { - tearDown1Run = true; - }), completes); + expect( + Future(() { + tearDown1Run = true; + }), + completes, + ); }); addTearDown(() { @@ -236,9 +243,12 @@ void main() { expect(tearDown2Run, isFalse); expect(tearDown3Run, isFalse); - expect(Future(() { - tearDown2Run = true; - }), completes); + expect( + Future(() { + tearDown2Run = true; + }), + completes, + ); }); addTearDown(() { @@ -246,9 +256,12 @@ void main() { expect(tearDown2Run, isFalse); expect(tearDown3Run, isFalse); - expect(Future(() { - tearDown3Run = true; - }), completes); + expect( + Future(() { + tearDown3Run = true; + }), + completes, + ); }); expect(tearDown1Run, isFalse); @@ -291,9 +304,12 @@ void main() { expect(groupTearDownRun, isFalse); expect(testTearDownRun, isFalse); - expect(Future(() { - groupTearDownRun = true; - }), completes); + expect( + Future(() { + groupTearDownRun = true; + }), + completes, + ); }); test('test', () { @@ -301,9 +317,12 @@ void main() { expect(groupTearDownRun, isFalse); expect(testTearDownRun, isFalse); - expect(Future(() { - testTearDownRun = true; - }), completes); + expect( + Future(() { + testTearDownRun = true; + }), + completes, + ); }); expect(groupTearDownRun, isFalse); @@ -336,10 +355,11 @@ void main() { addTearDown(() async { expect(tearDownRun, isFalse); expect( - pumpEventQueue().then((_) { - tearDownRun = true; - }), - completes); + pumpEventQueue().then((_) { + tearDownRun = true; + }), + completes, + ); }); }); @@ -569,9 +589,13 @@ void main() { addTearDown(() { final tearDownZone = Zone.current; - expect(tearDownZone.inSameErrorZone(setUpAllZone), isTrue, - reason: 'The tear down callback is in a different error zone ' - 'than the set up all callback.'); + expect( + tearDownZone.inSameErrorZone(setUpAllZone), + isTrue, + reason: + 'The tear down callback is in a different error zone ' + 'than the set up all callback.', + ); }); }); @@ -634,9 +658,12 @@ void main() { expect(tearDown2Run, isFalse); expect(tearDown3Run, isFalse); - expect(Future(() { - tearDown1Run = true; - }), completes); + expect( + Future(() { + tearDown1Run = true; + }), + completes, + ); }); addTearDown(() { @@ -644,9 +671,12 @@ void main() { expect(tearDown2Run, isFalse); expect(tearDown3Run, isFalse); - expect(Future(() { - tearDown2Run = true; - }), completes); + expect( + Future(() { + tearDown2Run = true; + }), + completes, + ); }); addTearDown(() { @@ -654,9 +684,12 @@ void main() { expect(tearDown2Run, isFalse); expect(tearDown3Run, isFalse); - expect(Future(() { - tearDown3Run = true; - }), completes); + expect( + Future(() { + tearDown3Run = true; + }), + completes, + ); }); }); @@ -702,40 +735,48 @@ void main() { expect(testTearDownRun, isTrue); }); - test("doesn't block additional tearDownAlls on out-of-band async", - () async { - var groupTearDownRun = false; - var testTearDownRun = false; - await expectTestsPass(() { - tearDownAll(() { - expect(groupTearDownRun, isFalse); - expect(testTearDownRun, isFalse); - - expect(Future(() { - groupTearDownRun = true; - }), completes); - }); - - setUpAll(() { - addTearDown(() { + test( + "doesn't block additional tearDownAlls on out-of-band async", + () async { + var groupTearDownRun = false; + var testTearDownRun = false; + await expectTestsPass(() { + tearDownAll(() { expect(groupTearDownRun, isFalse); expect(testTearDownRun, isFalse); - expect(Future(() { - testTearDownRun = true; - }), completes); + expect( + Future(() { + groupTearDownRun = true; + }), + completes, + ); }); - }); - test('test', () { - expect(groupTearDownRun, isFalse); - expect(testTearDownRun, isFalse); + setUpAll(() { + addTearDown(() { + expect(groupTearDownRun, isFalse); + expect(testTearDownRun, isFalse); + + expect( + Future(() { + testTearDownRun = true; + }), + completes, + ); + }); + }); + + test('test', () { + expect(groupTearDownRun, isFalse); + expect(testTearDownRun, isFalse); + }); }); - }); - expect(groupTearDownRun, isTrue); - expect(testTearDownRun, isTrue); - }); + expect(groupTearDownRun, isTrue); + expect(testTearDownRun, isTrue); + }, + ); }); group('with an error', () { diff --git a/pkgs/test_api/test/frontend/set_up_all_test.dart b/pkgs/test_api/test/frontend/set_up_all_test.dart index 60d4dc808..f88550959 100644 --- a/pkgs/test_api/test/frontend/set_up_all_test.dart +++ b/pkgs/test_api/test/frontend/set_up_all_test.dart @@ -169,10 +169,11 @@ void main() { expect(setUpAll3Run, isFalse); expect( - pumpEventQueue().then((_) { - setUpAll1Run = true; - }), - completes); + pumpEventQueue().then((_) { + setUpAll1Run = true; + }), + completes, + ); }); setUpAll(() { @@ -181,10 +182,11 @@ void main() { expect(setUpAll3Run, isFalse); expect( - pumpEventQueue().then((_) { - setUpAll2Run = true; - }), - completes); + pumpEventQueue().then((_) { + setUpAll2Run = true; + }), + completes, + ); }); setUpAll(() { @@ -193,10 +195,11 @@ void main() { expect(setUpAll3Run, isFalse); expect( - pumpEventQueue().then((_) { - setUpAll3Run = true; - }), - completes); + pumpEventQueue().then((_) { + setUpAll3Run = true; + }), + completes, + ); }); test('test', () { diff --git a/pkgs/test_api/test/frontend/tear_down_all_test.dart b/pkgs/test_api/test/frontend/tear_down_all_test.dart index d6d209fd5..ac8460a20 100644 --- a/pkgs/test_api/test/frontend/tear_down_all_test.dart +++ b/pkgs/test_api/test/frontend/tear_down_all_test.dart @@ -185,9 +185,12 @@ void main() { expect(tearDownAll2Run, isFalse); expect(tearDownAll3Run, isFalse); - expect(Future(() { - tearDownAll1Run = true; - }), completes); + expect( + Future(() { + tearDownAll1Run = true; + }), + completes, + ); }); tearDownAll(() { @@ -195,9 +198,12 @@ void main() { expect(tearDownAll2Run, isFalse); expect(tearDownAll3Run, isFalse); - expect(Future(() { - tearDownAll2Run = true; - }), completes); + expect( + Future(() { + tearDownAll2Run = true; + }), + completes, + ); }); tearDownAll(() { @@ -205,9 +211,12 @@ void main() { expect(tearDownAll2Run, isFalse); expect(tearDownAll3Run, isFalse); - expect(Future(() { - tearDownAll3Run = true; - }), completes); + expect( + Future(() { + tearDownAll3Run = true; + }), + completes, + ); }); test('test', () { @@ -244,10 +253,11 @@ void main() { tearDownAll(() async { expect(tearDownAllRun, isFalse); expect( - pumpEventQueue().then((_) { - tearDownAllRun = true; - }), - completes); + pumpEventQueue().then((_) { + tearDownAllRun = true; + }), + completes, + ); }); test('test', () {}); diff --git a/pkgs/test_api/test/frontend/timeout_test.dart b/pkgs/test_api/test/frontend/timeout_test.dart index fdfd61184..42228f6cf 100644 --- a/pkgs/test_api/test/frontend/timeout_test.dart +++ b/pkgs/test_api/test/frontend/timeout_test.dart @@ -41,30 +41,46 @@ void main() { expect(Timeout.parse('2d'), equals(const Timeout(Duration(days: 2)))); expect(Timeout.parse('2h'), equals(const Timeout(Duration(hours: 2)))); expect( - Timeout.parse('2m'), equals(const Timeout(Duration(minutes: 2)))); + Timeout.parse('2m'), + equals(const Timeout(Duration(minutes: 2))), + ); expect( - Timeout.parse('2s'), equals(const Timeout(Duration(seconds: 2)))); - expect(Timeout.parse('2ms'), - equals(const Timeout(Duration(milliseconds: 2)))); - expect(Timeout.parse('2us'), - equals(const Timeout(Duration(microseconds: 2)))); + Timeout.parse('2s'), + equals(const Timeout(Duration(seconds: 2))), + ); + expect( + Timeout.parse('2ms'), + equals(const Timeout(Duration(milliseconds: 2))), + ); + expect( + Timeout.parse('2us'), + equals(const Timeout(Duration(microseconds: 2))), + ); }); test('supports non-integer units', () { - expect(Timeout.parse('2.73d'), - equals(Timeout(const Duration(days: 1) * 2.73))); + expect( + Timeout.parse('2.73d'), + equals(Timeout(const Duration(days: 1) * 2.73)), + ); }); test('supports multiple units', () { expect( - Timeout.parse('1d 2h3m 4s5ms\t6us'), - equals(const Timeout(Duration( + Timeout.parse('1d 2h3m 4s5ms\t6us'), + equals( + const Timeout( + Duration( days: 1, hours: 2, minutes: 3, seconds: 4, milliseconds: 5, - microseconds: 6)))); + microseconds: 6, + ), + ), + ), + ); }); test('rejects invalid input', () { diff --git a/pkgs/test_api/test/import_restrictions_test.dart b/pkgs/test_api/test/import_restrictions_test.dart index 3fd9ffda4..5c7134947 100644 --- a/pkgs/test_api/test/import_restrictions_test.dart +++ b/pkgs/test_api/test/import_restrictions_test.dart @@ -26,13 +26,18 @@ void main() { final entryPoints = [ _testApiLibrary('backend.dart'), ...await _ImportCheck.findEntrypointsUnder( - _testApiLibrary('src/backend')) + _testApiLibrary('src/backend'), + ), ]; - await for (final source - in importCheck.transitiveSamePackageSources(entryPoints)) { + await for (final source in importCheck.transitiveSamePackageSources( + entryPoints, + )) { for (final import in source.imports) { - expect(import.pathSegments.skip(1).take(2), ['src', 'backend'], - reason: 'Invalid import from ${source.uri} : $import'); + expect( + import.pathSegments.skip(1).take(2), + ['src', 'backend'], + reason: 'Invalid import from ${source.uri} : $import', + ); } } }); @@ -88,17 +93,20 @@ class _ImportCheck { final package = entryPoints.first.pathSegments.first; assert(entryPoints.skip(1).every((e) => e.pathSegments.first == package)); return crawlAsync( - entryPoints, - (uri) async => _Source(uri, await _findImports(uri, package)), - (_, source) => source.imports); + entryPoints, + (uri) async => _Source(uri, await _findImports(uri, package)), + (_, source) => source.imports, + ); } Future> _findImports(Uri uri, String restrictToPackage) async { var path = await _pathForUri(uri); var analysisSession = _context.currentSession; var parseResult = analysisSession.getParsedUnit(path) as ParsedUnitResult; - assert(parseResult.content.isNotEmpty, - 'Tried to read an invalid library $uri'); + assert( + parseResult.content.isNotEmpty, + 'Tried to read an invalid library $uri', + ); return parseResult.unit.directives .whereType() .map((d) => d.uri.stringValue!) diff --git a/pkgs/test_api/test/utils.dart b/pkgs/test_api/test/utils.dart index 97058e3ff..8cd94c3d1 100644 --- a/pkgs/test_api/test/utils.dart +++ b/pkgs/test_api/test/utils.dart @@ -17,8 +17,10 @@ import 'package:test_core/src/runner/runner_suite.dart'; import 'package:test_core/src/runner/suite.dart'; /// A dummy suite platform to use for testing suites. -final suitePlatform = - SuitePlatform(Runtime.vm, compiler: Runtime.vm.defaultCompiler); +final suitePlatform = SuitePlatform( + Runtime.vm, + compiler: Runtime.vm.defaultCompiler, +); // The last state change detected via [expectStates]. State? lastState; @@ -28,34 +30,48 @@ State? lastState; /// The most recent emitted state is stored in [_lastState]. void expectStates(LiveTest liveTest, Iterable statesIter) { var states = Queue.of(statesIter); - liveTest.onStateChange.listen(expectAsync1((state) { - lastState = state; - expect(state, equals(states.removeFirst())); - }, count: states.length, max: states.length)); + liveTest.onStateChange.listen( + expectAsync1( + (state) { + lastState = state; + expect(state, equals(states.removeFirst())); + }, + count: states.length, + max: states.length, + ), + ); } /// Asserts that errors will be emitted via [liveTest.onError] that match /// [validators], in order. void expectErrors( - LiveTest liveTest, Iterable validatorsIter) { + LiveTest liveTest, + Iterable validatorsIter, +) { var validators = Queue.of(validatorsIter); - liveTest.onError.listen(expectAsync1((error) { - validators.removeFirst()(error.error); - }, count: validators.length, max: validators.length)); + liveTest.onError.listen( + expectAsync1( + (error) { + validators.removeFirst()(error.error); + }, + count: validators.length, + max: validators.length, + ), + ); } /// Asserts that [liveTest] will have a single failure with message `"oh no"`. void expectSingleFailure(LiveTest liveTest) { expectStates(liveTest, [ const State(Status.running, Result.success), - const State(Status.complete, Result.failure) + const State(Status.complete, Result.failure), ]); expectErrors(liveTest, [ (error) { expect(lastState?.status, equals(Status.complete)); expect(error, isTestFailure('oh no')); - } + }, ]); } @@ -63,14 +79,14 @@ void expectSingleFailure(LiveTest liveTest) { void expectSingleError(LiveTest liveTest) { expectStates(liveTest, [ const State(Status.running, Result.success), - const State(Status.complete, Result.error) + const State(Status.complete, Result.error), ]); expectErrors(liveTest, [ (error) { expect(lastState?.status, equals(Status.complete)); expect(error, equals('oh no')); - } + }, ]); } @@ -138,9 +154,10 @@ Engine declareEngine(void Function() body, {bool runSkipped = false}) { var declarer = Declarer()..declare(body); return Engine.withSuites([ RunnerSuite( - const PluginEnvironment(), - SuiteConfiguration.runSkipped(runSkipped), - declarer.build(), - suitePlatform) + const PluginEnvironment(), + SuiteConfiguration.runSkipped(runSkipped), + declarer.build(), + suitePlatform, + ), ]); } diff --git a/pkgs/test_core/lib/backend.dart b/pkgs/test_core/lib/backend.dart index f5a3b462b..25bb45789 100644 --- a/pkgs/test_core/lib/backend.dart +++ b/pkgs/test_core/lib/backend.dart @@ -2,8 +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. -@Deprecated('package:test_core is not intended for general use. ' - 'Please use package:test.') +@Deprecated( + 'package:test_core is not intended for general use. ' + 'Please use package:test.', +) library; export 'package:test_api/backend.dart' diff --git a/pkgs/test_core/lib/scaffolding.dart b/pkgs/test_core/lib/scaffolding.dart index 90304d280..ddcbdd3b2 100644 --- a/pkgs/test_core/lib/scaffolding.dart +++ b/pkgs/test_core/lib/scaffolding.dart @@ -2,8 +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. -@Deprecated('package:test_core is not intended for general use. ' - 'Please use package:test.') +@Deprecated( + 'package:test_core is not intended for general use. ' + 'Please use package:test.', +) library; export 'src/scaffolding.dart'; diff --git a/pkgs/test_core/lib/src/bootstrap/vm.dart b/pkgs/test_core/lib/src/bootstrap/vm.dart index 05604f120..5e92cbc0e 100644 --- a/pkgs/test_core/lib/src/bootstrap/vm.dart +++ b/pkgs/test_core/lib/src/bootstrap/vm.dart @@ -15,10 +15,11 @@ import '../runner/plugin/shared_platform_helpers.dart'; /// Bootstraps a vm test to communicate with the test runner over an isolate. void internalBootstrapVmTest(Function Function() getMain, SendPort sendPort) { - var platformChannel = - MultiChannel(IsolateChannel.connectSend(sendPort)); - var testControlChannel = platformChannel.virtualChannel() - ..pipe(serializeSuite(getMain)); + var platformChannel = MultiChannel( + IsolateChannel.connectSend(sendPort), + ); + var testControlChannel = + platformChannel.virtualChannel()..pipe(serializeSuite(getMain)); platformChannel.sink.add(testControlChannel.id); platformChannel.stream.forEach((message) { @@ -31,20 +32,25 @@ void internalBootstrapVmTest(Function Function() getMain, SendPort sendPort) { /// Bootstraps a native executable test to communicate with the test runner over /// a socket. void internalBootstrapNativeTest( - Function Function() getMain, List args) async { + Function Function() getMain, + List args, +) async { if (args.length != 2) { throw StateError( - 'Expected exactly two args, a host and a port, but got $args'); + 'Expected exactly two args, a host and a port, but got $args', + ); } var socket = await Socket.connect(args[0], int.parse(args[1])); var platformChannel = MultiChannel(jsonSocketStreamChannel(socket)); - var testControlChannel = platformChannel.virtualChannel() - ..pipe(serializeSuite(getMain)); + var testControlChannel = + platformChannel.virtualChannel()..pipe(serializeSuite(getMain)); platformChannel.sink.add(testControlChannel.id); - unawaited(platformChannel.stream.forEach((message) { - assert(message == 'debug'); - debugger(message: 'Paused by test runner'); - platformChannel.sink.add('done'); - })); + unawaited( + platformChannel.stream.forEach((message) { + assert(message == 'debug'); + debugger(message: 'Paused by test runner'); + platformChannel.sink.add('done'); + }), + ); } diff --git a/pkgs/test_core/lib/src/direct_run.dart b/pkgs/test_core/lib/src/direct_run.dart index c5742579c..56d8151d8 100644 --- a/pkgs/test_core/lib/src/direct_run.dart +++ b/pkgs/test_core/lib/src/direct_run.dart @@ -28,13 +28,16 @@ import 'util/print_sink.dart'; /// Test suite level metadata defined in annotations is not read. No filtering /// is applied except for the filtering defined by `solo` or `skip` arguments to /// `group` and `test`. Returns [true] if all tests passed. -Future directRunTests(FutureOr Function() testMain, - {Reporter Function(Engine)? reporterFactory, - // TODO: Change the default https://github.com/dart-lang/test/issues/1571 - bool allowDuplicateTestNames = true}) => - _directRunTests(testMain, - reporterFactory: reporterFactory, - allowDuplicateTestNames: allowDuplicateTestNames); +Future directRunTests( + FutureOr Function() testMain, { + Reporter Function(Engine)? reporterFactory, + // TODO: Change the default https://github.com/dart-lang/test/issues/1571 + bool allowDuplicateTestNames = true, +}) => _directRunTests( + testMain, + reporterFactory: reporterFactory, + allowDuplicateTestNames: allowDuplicateTestNames, +); /// Runs a single test declared in [testMain] matched by it's full test name. /// @@ -50,39 +53,56 @@ Future directRunTests(FutureOr Function() testMain, /// thrown. If there is more than one test with the name [fullTestName] they /// will both be run, then a [DuplicateTestnameException] will be thrown. Future directRunSingleTest( - FutureOr Function() testMain, String fullTestName, - {Reporter Function(Engine)? reporterFactory}) => - _directRunTests(testMain, - reporterFactory: reporterFactory, - fullTestName: fullTestName, - allowDuplicateTestNames: false); + FutureOr Function() testMain, + String fullTestName, { + Reporter Function(Engine)? reporterFactory, +}) => _directRunTests( + testMain, + reporterFactory: reporterFactory, + fullTestName: fullTestName, + allowDuplicateTestNames: false, +); -Future _directRunTests(FutureOr Function() testMain, - {Reporter Function(Engine)? reporterFactory, - String? fullTestName, - required bool allowDuplicateTestNames}) async { - reporterFactory ??= (engine) => ExpandedReporter.watch(engine, PrintSink(), - color: Configuration.empty.color, printPath: false, printPlatform: false); +Future _directRunTests( + FutureOr Function() testMain, { + Reporter Function(Engine)? reporterFactory, + String? fullTestName, + required bool allowDuplicateTestNames, +}) async { + reporterFactory ??= + (engine) => ExpandedReporter.watch( + engine, + PrintSink(), + color: Configuration.empty.color, + printPath: false, + printPlatform: false, + ); final declarer = Declarer( - fullTestName: fullTestName, - allowDuplicateTestNames: allowDuplicateTestNames); + fullTestName: fullTestName, + allowDuplicateTestNames: allowDuplicateTestNames, + ); await declarer.declare(testMain); final suite = RunnerSuite( - const PluginEnvironment(), - SuiteConfiguration.empty, - declarer.build(), - SuitePlatform(Runtime.vm, compiler: null, os: currentOSGuess), - path: p.prettyUri(Uri.base)); + const PluginEnvironment(), + SuiteConfiguration.empty, + declarer.build(), + SuitePlatform(Runtime.vm, compiler: null, os: currentOSGuess), + path: p.prettyUri(Uri.base), + ); - final engine = Engine() - ..suiteSink.add(suite) - ..suiteSink.close(); + final engine = + Engine() + ..suiteSink.add(suite) + ..suiteSink.close(); reporterFactory(engine); - final success = await runZoned(() => Invoker.guard(engine.run), - zoneValues: {#test.declarer: declarer}) ?? + final success = + await runZoned( + () => Invoker.guard(engine.run), + zoneValues: {#test.declarer: declarer}, + ) ?? false; if (fullTestName != null) { @@ -102,7 +122,8 @@ Future _directRunTests(FutureOr Function() testMain, /// /// Skipped tests are ignored. Future> enumerateTestCases( - FutureOr Function() testMain) async { + FutureOr Function() testMain, +) async { final declarer = Declarer(); await declarer.declare(testMain); diff --git a/pkgs/test_core/lib/src/executable.dart b/pkgs/test_core/lib/src/executable.dart index eeefd161c..0a3dc4409 100644 --- a/pkgs/test_core/lib/src/executable.dart +++ b/pkgs/test_core/lib/src/executable.dart @@ -61,12 +61,16 @@ Future _execute(List args) async { /// Signals will only be captured as long as this has an active subscription. /// Otherwise, they'll be handled by Dart's default signal handler, which /// terminates the program immediately. - final signals = Platform.isWindows - ? ProcessSignal.sigint.watch() - : Platform.isFuchsia // Signals don't exist on Fuchsia. + final signals = + Platform.isWindows + ? ProcessSignal.sigint.watch() + : Platform + .isFuchsia // Signals don't exist on Fuchsia. ? const Stream.empty() - : StreamGroup.merge( - [ProcessSignal.sigterm.watch(), ProcessSignal.sigint.watch()]); + : StreamGroup.merge([ + ProcessSignal.sigterm.watch(), + ProcessSignal.sigint.watch(), + ]); Configuration configuration; try { @@ -96,13 +100,15 @@ Future _execute(List args) async { try { var fileConfiguration = Configuration.empty; if (File(_globalConfigPath).existsSync()) { - fileConfiguration = fileConfiguration - .merge(Configuration.load(_globalConfigPath, global: true)); + fileConfiguration = fileConfiguration.merge( + Configuration.load(_globalConfigPath, global: true), + ); } if (File(configuration.configurationPath).existsSync()) { - fileConfiguration = fileConfiguration - .merge(Configuration.load(configuration.configurationPath)); + fileConfiguration = fileConfiguration.merge( + Configuration.load(configuration.configurationPath), + ); } configuration = fileConfiguration.merge(configuration); @@ -120,20 +126,25 @@ Future _execute(List args) async { return; } - var undefinedPresets = configuration.chosenPresets - .where((preset) => !configuration.knownPresets.contains(preset)) - .toList(); + var undefinedPresets = + configuration.chosenPresets + .where((preset) => !configuration.knownPresets.contains(preset)) + .toList(); if (undefinedPresets.isNotEmpty) { - _printUsage("Undefined ${pluralize('preset', undefinedPresets.length)} " - "${toSentence(undefinedPresets.map((preset) => '"$preset"'))}."); + _printUsage( + "Undefined ${pluralize('preset', undefinedPresets.length)} " + "${toSentence(undefinedPresets.map((preset) => '"$preset"'))}.", + ); exitCode = exit_codes.usage; return; } if (!configuration.explicitPaths && !Directory(configuration.testSelections.keys.single).existsSync()) { - _printUsage('No test files were passed and the default "test/" ' - "directory doesn't exist."); + _printUsage( + 'No test files were passed and the default "test/" ' + "directory doesn't exist.", + ); exitCode = exit_codes.data; return; } @@ -163,9 +174,11 @@ Future _execute(List args) async { } catch (error, stackTrace) { stderr.writeln(getErrorMessage(error)); stderr.writeln(Trace.from(stackTrace).terse); - stderr.writeln('This is an unexpected error. Please file an issue at ' - 'http://github.com/dart-lang/test\n' - 'with the stack trace and instructions for reproducing the error.'); + stderr.writeln( + 'This is an unexpected error. Please file an issue at ' + 'http://github.com/dart-lang/test\n' + 'with the stack trace and instructions for reproducing the error.', + ); exitCode = exit_codes.software; } finally { await runner?.close(); diff --git a/pkgs/test_core/lib/src/runner.dart b/pkgs/test_core/lib/src/runner.dart index af8e9c96d..f8fb1df48 100644 --- a/pkgs/test_core/lib/src/runner.dart +++ b/pkgs/test_core/lib/src/runner.dart @@ -74,33 +74,32 @@ class Runner { /// Creates a new runner based on [configuration]. factory Runner(Configuration config) => config.asCurrent(() { - var engine = Engine( - concurrency: config.concurrency, - coverage: config.coverage, - testRandomizeOrderingSeed: config.testRandomizeOrderingSeed, - stopOnFirstFailure: config.stopOnFirstFailure, - ); + var engine = Engine( + concurrency: config.concurrency, + coverage: config.coverage, + testRandomizeOrderingSeed: config.testRandomizeOrderingSeed, + stopOnFirstFailure: config.stopOnFirstFailure, + ); + + var sinks = []; + Reporter createFileReporter(String reporterName, String filepath) { + final sink = (File(filepath)..createSync(recursive: true)).openWrite(); + sinks.add(sink); + return allReporters[reporterName]!.factory(config, engine, sink); + } - var sinks = []; - Reporter createFileReporter(String reporterName, String filepath) { - final sink = - (File(filepath)..createSync(recursive: true)).openWrite(); - sinks.add(sink); - return allReporters[reporterName]!.factory(config, engine, sink); - } - - return Runner._( - engine, - MultiplexReporter([ - // Standard reporter. - allReporters[config.reporter]!.factory(config, engine, stdout), - // File reporters. - for (var reporter in config.fileReporters.keys) - createFileReporter(reporter, config.fileReporters[reporter]!), - ]), - sinks, - ); - }); + return Runner._( + engine, + MultiplexReporter([ + // Standard reporter. + allReporters[config.reporter]!.factory(config, engine, stdout), + // File reporters. + for (var reporter in config.fileReporters.keys) + createFileReporter(reporter, config.fileReporters[reporter]!), + ]), + sinks, + ); + }); Runner._(this._engine, this._reporter, this._sinks); @@ -109,58 +108,61 @@ class Runner { /// This starts running tests and printing their progress. It returns whether /// or not they ran successfully. Future run() => _config.asCurrent(() async { - if (_closed) { - throw StateError('run() may not be called on a closed Runner.'); - } + if (_closed) { + throw StateError('run() may not be called on a closed Runner.'); + } - _warnForUnsupportedPlatforms(); + _warnForUnsupportedPlatforms(); - var suites = _loadSuites(); + var suites = _loadSuites(); - if (_config.coverage != null) { - await Directory(_config.coverage!).create(recursive: true); - } + if (_config.coverage != null) { + await Directory(_config.coverage!).create(recursive: true); + } - bool? success; - if (_config.pauseAfterLoad) { - success = await _loadThenPause(suites); - } else { - var subscription = - _suiteSubscription = suites.listen(_engine.suiteSink.add); - var results = await Future.wait([ - subscription - .asFuture() - .then((_) => _engine.suiteSink.close()), - _engine.run() - ], eagerError: true); - success = results.last as bool?; - } + bool? success; + if (_config.pauseAfterLoad) { + success = await _loadThenPause(suites); + } else { + var subscription = + _suiteSubscription = suites.listen(_engine.suiteSink.add); + var results = await Future.wait([ + subscription.asFuture().then((_) => _engine.suiteSink.close()), + _engine.run(), + ], eagerError: true); + success = results.last as bool?; + } - if (_closed) return false; + if (_closed) return false; - if (_engine.passed.isEmpty && - _engine.failed.isEmpty && - _engine.skipped.isEmpty) { - if (_config.globalPatterns.isNotEmpty) { - var patterns = toSentence(_config.globalPatterns.map((pattern) => + if (_engine.passed.isEmpty && + _engine.failed.isEmpty && + _engine.skipped.isEmpty) { + if (_config.globalPatterns.isNotEmpty) { + var patterns = toSentence( + _config.globalPatterns.map( + (pattern) => pattern is RegExp ? 'regular expression "${pattern.pattern}"' - : '"$pattern"')); - throw NoTestsFoundException('No tests match $patterns.'); - } else if (_config.includeTags != BooleanSelector.all || - _config.excludeTags != BooleanSelector.none) { - throw NoTestsFoundException( - 'No tests match the requested tag selectors:\n' - ' include: "${_config.includeTags}"\n' - ' exclude: "${_config.excludeTags}"'); - } else { - throw NoTestsFoundException('No tests were found.'); - } - } + : '"$pattern"', + ), + ); + throw NoTestsFoundException('No tests match $patterns.'); + } else if (_config.includeTags != BooleanSelector.all || + _config.excludeTags != BooleanSelector.none) { + throw NoTestsFoundException( + 'No tests match the requested tag selectors:\n' + ' include: "${_config.includeTags}"\n' + ' exclude: "${_config.excludeTags}"', + ); + } else { + throw NoTestsFoundException('No tests were found.'); + } + } - return (success ?? false) && - (_engine.passed.isNotEmpty || _engine.skipped.isNotEmpty); - }); + return (success ?? false) && + (_engine.passed.isNotEmpty || _engine.skipped.isNotEmpty); + }); /// Emits a warning if the user is trying to run on a platform that's /// unsupported for the entire package. @@ -168,11 +170,14 @@ class Runner { var testOn = _config.suiteDefaults.metadata.testOn; if (testOn == PlatformSelector.all) return; - var unsupportedRuntimes = _config.suiteDefaults.runtimes - .map(_loader.findRuntime) - .whereType() - .where((runtime) => !testOn.evaluate(currentPlatform(runtime, null))) - .toList(); + var unsupportedRuntimes = + _config.suiteDefaults.runtimes + .map(_loader.findRuntime) + .whereType() + .where( + (runtime) => !testOn.evaluate(currentPlatform(runtime, null)), + ) + .toList(); if (unsupportedRuntimes.isEmpty) return; @@ -182,16 +187,18 @@ class Runner { // If the user tried to run on one or more unsupported browsers, figure out // whether we should warn about the individual browsers or whether all // browsers are unsupported. - var unsupportedBrowsers = - unsupportedRuntimes.where((platform) => platform.isBrowser); + var unsupportedBrowsers = unsupportedRuntimes.where( + (platform) => platform.isBrowser, + ); if (unsupportedBrowsers.isNotEmpty) { var supportsAnyBrowser = _loader.allRuntimes .where((runtime) => runtime.isBrowser) .any((runtime) => testOn.evaluate(currentPlatform(runtime, null))); if (supportsAnyBrowser) { - unsupportedNames - .addAll(unsupportedBrowsers.map((runtime) => runtime.name)); + unsupportedNames.addAll( + unsupportedBrowsers.map((runtime) => runtime.name), + ); } else { unsupportedNames.add('browsers'); } @@ -200,9 +207,11 @@ class Runner { // If the user tried to run on the VM and it's not supported, figure out if // that's because of the current OS or whether the VM is unsupported. if (unsupportedRuntimes.contains(Runtime.vm)) { - var supportsAnyOS = OperatingSystem.all.any((os) => testOn.evaluate( - SuitePlatform(Runtime.vm, - compiler: null, os: os, inGoogle: inGoogle))); + var supportsAnyOS = OperatingSystem.all.any( + (os) => testOn.evaluate( + SuitePlatform(Runtime.vm, compiler: null, os: os, inGoogle: inGoogle), + ), + ); if (supportsAnyOS) { unsupportedNames.add(currentOS.name); @@ -211,8 +220,10 @@ class Runner { } } - warn("this package doesn't support running tests on " - '${toSentence(unsupportedNames, conjunction: 'or')}.'); + warn( + "this package doesn't support running tests on " + '${toSentence(unsupportedNames, conjunction: 'or')}.', + ); } /// Closes the runner. @@ -221,167 +232,178 @@ class Runner { /// currently-running VM tests, in case they have stuff to clean up on the /// filesystem. Future close() => _closeMemo.runOnce(() async { - Timer? timer; - if (!_engine.isIdle) { - // Wait a bit to print this message, since printing it eagerly looks weird - // if the tests then finish immediately. - timer = Timer(const Duration(seconds: 1), () { - // Pause the reporter while we print to ensure that we don't interfere - // with its output. - _reporter.pause(); - print('Waiting for current test(s) to finish.'); - print('Press Control-C again to terminate immediately.'); - _reporter.resume(); - }); - } + Timer? timer; + if (!_engine.isIdle) { + // Wait a bit to print this message, since printing it eagerly looks weird + // if the tests then finish immediately. + timer = Timer(const Duration(seconds: 1), () { + // Pause the reporter while we print to ensure that we don't interfere + // with its output. + _reporter.pause(); + print('Waiting for current test(s) to finish.'); + print('Press Control-C again to terminate immediately.'); + _reporter.resume(); + }); + } - await _debugOperation?.cancel(); - await _suiteSubscription?.cancel(); + await _debugOperation?.cancel(); + await _suiteSubscription?.cancel(); - _suiteSubscription = null; + _suiteSubscription = null; - // Make sure we close the engine *before* the loader. Otherwise, - // LoadSuites provided by the loader may get into bad states. - // - // We close the loader's browsers while we're closing the engine because - // browser tests don't store any state we care about and we want them to - // shut down without waiting for their tear-downs. - await Future.wait([_loader.closeEphemeral(), _engine.close()]); - timer?.cancel(); - await _loader.close(); + // Make sure we close the engine *before* the loader. Otherwise, + // LoadSuites provided by the loader may get into bad states. + // + // We close the loader's browsers while we're closing the engine because + // browser tests don't store any state we care about and we want them to + // shut down without waiting for their tear-downs. + await Future.wait([_loader.closeEphemeral(), _engine.close()]); + timer?.cancel(); + await _loader.close(); - // Flush any IOSinks created for file reporters. - await Future.wait(_sinks.map((s) => s.flush().then((_) => s.close()))); - _sinks.clear(); - }); + // Flush any IOSinks created for file reporters. + await Future.wait(_sinks.map((s) => s.flush().then((_) => s.close()))); + _sinks.clear(); + }); /// Return a stream of [LoadSuite]s in [_config.testSelections]. /// /// Only tests that match [_config.patterns] will be included in the /// suites once they're loaded. Stream _loadSuites() { - return StreamGroup.merge(_config.testSelections.entries.map((pathEntry) { - final testPath = pathEntry.key; - final testSelections = pathEntry.value; - final suiteConfig = _config.suiteDefaults.selectTests(testSelections); - if (Directory(testPath).existsSync()) { - return _loader.loadDir(testPath, suiteConfig); - } else if (File(testPath).existsSync()) { - return _loader.loadFile(testPath, suiteConfig); - } else { - return Stream.fromIterable([ - LoadSuite.forLoadException( - LoadException(testPath, 'Does not exist.'), - suiteConfig, - ), - ]); - } - })).map((loadSuite) { + return StreamGroup.merge( + _config.testSelections.entries.map((pathEntry) { + final testPath = pathEntry.key; + final testSelections = pathEntry.value; + final suiteConfig = _config.suiteDefaults.selectTests(testSelections); + if (Directory(testPath).existsSync()) { + return _loader.loadDir(testPath, suiteConfig); + } else if (File(testPath).existsSync()) { + return _loader.loadFile(testPath, suiteConfig); + } else { + return Stream.fromIterable([ + LoadSuite.forLoadException( + LoadException(testPath, 'Does not exist.'), + suiteConfig, + ), + ]); + } + }), + ).map((loadSuite) { return loadSuite.changeSuite((suite) { _warnForUnknownTags(suite); - return _shardSuite(suite.filter((test) { - // Skip any tests that don't match all the global patterns. - if (!_config.globalPatterns - .every((pattern) => test.name.contains(pattern))) { - return false; - } - - // If the user provided tags, skip tests that don't match all of them. - if (!_config.includeTags.evaluate(test.metadata.tags.contains)) { - return false; - } - - // Skip tests that do match any tags the user wants to exclude. - if (_config.excludeTags.evaluate(test.metadata.tags.contains)) { - return false; - } - - final testSelections = suite.config.testSelections; - assert(testSelections.isNotEmpty, 'Tests should have been selected'); - return testSelections.any((selection) { - // Skip tests that don't match all the suite specific patterns. - if (!selection.testPatterns - .every((pattern) => test.name.contains(pattern))) { + return _shardSuite( + suite.filter((test) { + // Skip any tests that don't match all the global patterns. + if (!_config.globalPatterns.every( + (pattern) => test.name.contains(pattern), + )) { return false; } - // Skip tests that don't start on `line` or `col` if specified. - var line = selection.line; - var col = selection.col; - if (line == null && col == null) return true; - - var trace = test.trace; - if (trace == null && test.location == null) { - throw StateError( - 'Cannot filter by line/column for this test suite, no stack' - 'trace or location available.'); - } - var path = suite.path; - if (path == null) { - throw StateError( - 'Cannot filter by line/column for this test suite, no suite' - 'path available.'); - } - // The absolute path as it will appear in stack traces. - var suiteUri = File(path).absolute.uri; - var absoluteSuitePath = suiteUri.toFilePath(); - - /// Helper to check if [uri] matches the suite path. - bool matchesUri(Uri uri) { - switch (uri.scheme) { - case 'file': - if (uri.toFilePath() != absoluteSuitePath) { - return false; - } - case 'package': - // It is unlikely that the test case is specified in a - // package: URI. Ignore this case. - return false; - default: - // Now we can assume that the kernel is compiled using - // --filesystem-scheme. - // In this case, because we don't know the --filesystem-root, as - // long as the path matches we assume it is the same file. - if (!suiteUri.path.endsWith(uri.path)) { - return false; - } - } - return true; + // If the user provided tags, skip tests that don't match all of them. + if (!_config.includeTags.evaluate(test.metadata.tags.contains)) { + return false; } - // First check if we're a match for the overridden location for this - // item or any parents. - var current = test as GroupEntry?; - while (current != null) { - if (current.location case var location?) { - if ((line == null || location.line == line) && - (col == null || location.column == col) && - matchesUri(location.uri)) { - return true; - } - } - current = current.parent; + // Skip tests that do match any tags the user wants to exclude. + if (_config.excludeTags.evaluate(test.metadata.tags.contains)) { + return false; } - /// Helper to check if [frame] matches the suite path, line and col. - bool matchLineAndCol(Frame frame) { - if (!matchesUri(frame.uri)) { + final testSelections = suite.config.testSelections; + assert( + testSelections.isNotEmpty, + 'Tests should have been selected', + ); + return testSelections.any((selection) { + // Skip tests that don't match all the suite specific patterns. + if (!selection.testPatterns.every( + (pattern) => test.name.contains(pattern), + )) { return false; } - if (line != null && frame.line != line) { - return false; + // Skip tests that don't start on `line` or `col` if specified. + var line = selection.line; + var col = selection.col; + if (line == null && col == null) return true; + + var trace = test.trace; + if (trace == null && test.location == null) { + throw StateError( + 'Cannot filter by line/column for this test suite, no stack' + 'trace or location available.', + ); } - if (col != null && frame.column != col) { - return false; + var path = suite.path; + if (path == null) { + throw StateError( + 'Cannot filter by line/column for this test suite, no suite' + 'path available.', + ); + } + // The absolute path as it will appear in stack traces. + var suiteUri = File(path).absolute.uri; + var absoluteSuitePath = suiteUri.toFilePath(); + + /// Helper to check if [uri] matches the suite path. + bool matchesUri(Uri uri) { + switch (uri.scheme) { + case 'file': + if (uri.toFilePath() != absoluteSuitePath) { + return false; + } + case 'package': + // It is unlikely that the test case is specified in a + // package: URI. Ignore this case. + return false; + default: + // Now we can assume that the kernel is compiled using + // --filesystem-scheme. + // In this case, because we don't know the --filesystem-root, as + // long as the path matches we assume it is the same file. + if (!suiteUri.path.endsWith(uri.path)) { + return false; + } + } + + return true; + } + + // First check if we're a match for the overridden location for this + // item or any parents. + var current = test as GroupEntry?; + while (current != null) { + if (current.location case var location?) { + if ((line == null || location.line == line) && + (col == null || location.column == col) && + matchesUri(location.uri)) { + return true; + } + } + current = current.parent; + } + + /// Helper to check if [frame] matches the suite path, line and col. + bool matchLineAndCol(Frame frame) { + if (!matchesUri(frame.uri)) { + return false; + } + if (line != null && frame.line != line) { + return false; + } + if (col != null && frame.column != col) { + return false; + } + return true; } - return true; - } - // Check if any frames in the stack trace match. - return trace?.frames.any(matchLineAndCol) ?? false; - }); - })); + // Check if any frames in the stack trace match. + return trace?.frames.any(matchLineAndCol) ?? false; + }); + }), + ); }); }); } @@ -399,12 +421,13 @@ class Runner { var bold = _config.color ? '\u001b[1m' : ''; var noColor = _config.color ? '\u001b[0m' : ''; - var buffer = StringBuffer() - ..write('${yellow}Warning:$noColor ') - ..write(unknownTags.length == 1 ? 'A tag was ' : 'Tags were ') - ..write('used that ') - ..write(unknownTags.length == 1 ? "wasn't " : "weren't ") - ..writeln('specified in dart_test.yaml.'); + var buffer = + StringBuffer() + ..write('${yellow}Warning:$noColor ') + ..write(unknownTags.length == 1 ? 'A tag was ' : 'Tags were ') + ..write('used that ') + ..write(unknownTags.length == 1 ? "wasn't " : "weren't ") + ..writeln('specified in dart_test.yaml.'); unknownTags.forEach((tag, entries) { buffer.write(' $bold$tag$noColor was used in'); @@ -434,8 +457,9 @@ class Runner { void collect(GroupEntry entry) { var newTags = {}; - for (var unknownTag - in entry.metadata.tags.difference(_config.knownTags)) { + for (var unknownTag in entry.metadata.tags.difference( + _config.knownTags, + )) { if (currentTags.contains(unknownTag)) continue; unknownTags.putIfAbsent(unknownTag, () => []).add(entry); newTags.add(unknownTag); @@ -488,14 +512,18 @@ class Runner { /// Loads each suite in [suites] in order, pausing after load for runtimes /// that support debugging. Future _loadThenPause(Stream suites) async { - var subscription = _suiteSubscription = suites.asyncMap((loadSuite) async { - var operation = _debugOperation = debug(_engine, _reporter, loadSuite); - await operation.valueOrCancellation(); - }).listen(null); + var subscription = + _suiteSubscription = suites + .asyncMap((loadSuite) async { + var operation = + _debugOperation = debug(_engine, _reporter, loadSuite); + await operation.valueOrCancellation(); + }) + .listen(null); var results = await Future.wait([ subscription.asFuture().then((_) => _engine.suiteSink.close()), - _engine.run() + _engine.run(), ], eagerError: true); return results.last as bool; } diff --git a/pkgs/test_core/lib/src/runner/compiler_pool.dart b/pkgs/test_core/lib/src/runner/compiler_pool.dart index 52aa238b6..759906e15 100644 --- a/pkgs/test_core/lib/src/runner/compiler_pool.dart +++ b/pkgs/test_core/lib/src/runner/compiler_pool.dart @@ -34,17 +34,22 @@ abstract class CompilerPool { /// /// Should not be overridden. Future compile( - String code, String path, SuiteConfiguration suiteConfig) => - _pool.withResource(() { - if (closed) return null; - return compileInternal(code, path, suiteConfig); - }); + String code, + String path, + SuiteConfiguration suiteConfig, + ) => _pool.withResource(() { + if (closed) return null; + return compileInternal(code, path, suiteConfig); + }); /// The actual function a given compiler pool should implement to compile a /// suite. @protected Future compileInternal( - String code, String path, SuiteConfiguration suiteConfig); + String code, + String path, + SuiteConfiguration suiteConfig, + ); /// Shuts down the compiler pool, invoking `closeInternal` exactly once. /// diff --git a/pkgs/test_core/lib/src/runner/compiler_selection.dart b/pkgs/test_core/lib/src/runner/compiler_selection.dart index 70ab553fc..a5e622dd5 100644 --- a/pkgs/test_core/lib/src/runner/compiler_selection.dart +++ b/pkgs/test_core/lib/src/runner/compiler_selection.dart @@ -19,29 +19,37 @@ class CompilerSelection { /// if specified. Defaults to all platforms where the compiler is supported. final PlatformSelector? platformSelector; - CompilerSelection(String compiler, - {required this.platformSelector, required this.span}) - : compiler = Compiler.builtIn.firstWhere((c) => c.identifier == compiler); + CompilerSelection( + String compiler, { + required this.platformSelector, + required this.span, + }) : compiler = Compiler.builtIn.firstWhere((c) => c.identifier == compiler); factory CompilerSelection.parse(String option, {SourceSpan? parentSpan}) { var parts = option.split(':'); switch (parts.length) { case 1: _checkValidCompiler(option, parentSpan); - return CompilerSelection(option, - platformSelector: null, span: parentSpan); + return CompilerSelection( + option, + platformSelector: null, + span: parentSpan, + ); case 2: var compiler = parts[1]; _checkValidCompiler(compiler, parentSpan); - return CompilerSelection(compiler, - platformSelector: PlatformSelector.parse(parts[0]), - span: parentSpan); + return CompilerSelection( + compiler, + platformSelector: PlatformSelector.parse(parts[0]), + span: parentSpan, + ); default: throw ArgumentError.value( - option, - '--compiler', - 'Must be of the format [:], but got ' - 'more than one `:`.'); + option, + '--compiler', + 'Must be of the format [:], but got ' + 'more than one `:`.', + ); } } @@ -56,6 +64,7 @@ class CompilerSelection { void _checkValidCompiler(String compiler, SourceSpan? span) { if (Compiler.builtIn.any((c) => c.identifier == compiler)) return; throw SourceSpanFormatException( - 'Invalid compiler `$compiler`, must be one of ${Compiler.builtIn.map((c) => c.identifier).join(', ')}', - span); + 'Invalid compiler `$compiler`, must be one of ${Compiler.builtIn.map((c) => c.identifier).join(', ')}', + span, + ); } diff --git a/pkgs/test_core/lib/src/runner/configuration.dart b/pkgs/test_core/lib/src/runner/configuration.dart index 8ba4aa810..9434ed3d4 100644 --- a/pkgs/test_core/lib/src/runner/configuration.dart +++ b/pkgs/test_core/lib/src/runner/configuration.dart @@ -125,7 +125,7 @@ class Configuration { Map> get testSelections => _testSelections ?? const { - 'test': {TestSelection()} + 'test': {TestSelection()}, }; final Map>? _testSelections; @@ -151,7 +151,7 @@ class Configuration { ...includeTags.variables, ...excludeTags.variables, ...suiteDefaults.knownTags, - for (var configuration in presets.values) ...configuration.knownTags + for (var configuration in presets.values) ...configuration.knownTags, }); /// Only run tests whose tags match this selector. @@ -179,9 +179,10 @@ class Configuration { /// All preset names that are known to be valid. /// /// This includes presets that have already been resolved. - Set get knownPresets => _knownPresets ??= UnmodifiableSetView({ + Set get knownPresets => + _knownPresets ??= UnmodifiableSetView({ ...presets.keys, - for (var configuration in presets.values) ...configuration.knownPresets + for (var configuration in presets.values) ...configuration.knownPresets, }); Set? _knownPresets; @@ -242,112 +243,117 @@ class Configuration { /// document. /// /// Throws a [FormatException] if the content is invalid. - factory Configuration.loadFromString(String content, - {bool global = false, Uri? sourceUrl}) => - parse(content, global: global, sourceUrl: sourceUrl); - - factory Configuration( - {required bool? help, - required String? customHtmlTemplatePath, - required bool? version, - required bool? pauseAfterLoad, - required bool? debug, - required bool? color, - required String? configurationPath, - required String? reporter, - required Map? fileReporters, - required String? coverage, - required int? concurrency, - required int? shardIndex, - required int? totalShards, - required Map>? testSelections, - required Iterable? foldTraceExcept, - required Iterable? foldTraceOnly, - required Glob? filename, - required Iterable? chosenPresets, - required Map? presets, - required Map? overrideRuntimes, - required Map? defineRuntimes, - required bool? noRetry, - required int? testRandomizeOrderingSeed, - required bool? stopOnFirstFailure, - - // Suite-level configuration - required bool? allowDuplicateTestNames, - required bool? allowTestRandomization, - required bool? jsTrace, - required bool? runSkipped, - required Iterable? dart2jsArgs, - required String? precompiledPath, - required Iterable? globalPatterns, - required Iterable? compilerSelections, - required Iterable? runtimes, - required BooleanSelector? includeTags, - required BooleanSelector? excludeTags, - required Map? tags, - required Map? onPlatform, - required bool? ignoreTimeouts, - - // Test-level configuration - required Timeout? timeout, - required bool? verboseTrace, - required bool? chainStackTraces, - required bool? skip, - required int? retry, - required String? skipReason, - required PlatformSelector? testOn, - required Iterable? addTags}) { + factory Configuration.loadFromString( + String content, { + bool global = false, + Uri? sourceUrl, + }) => parse(content, global: global, sourceUrl: sourceUrl); + + factory Configuration({ + required bool? help, + required String? customHtmlTemplatePath, + required bool? version, + required bool? pauseAfterLoad, + required bool? debug, + required bool? color, + required String? configurationPath, + required String? reporter, + required Map? fileReporters, + required String? coverage, + required int? concurrency, + required int? shardIndex, + required int? totalShards, + required Map>? testSelections, + required Iterable? foldTraceExcept, + required Iterable? foldTraceOnly, + required Glob? filename, + required Iterable? chosenPresets, + required Map? presets, + required Map? overrideRuntimes, + required Map? defineRuntimes, + required bool? noRetry, + required int? testRandomizeOrderingSeed, + required bool? stopOnFirstFailure, + + // Suite-level configuration + required bool? allowDuplicateTestNames, + required bool? allowTestRandomization, + required bool? jsTrace, + required bool? runSkipped, + required Iterable? dart2jsArgs, + required String? precompiledPath, + required Iterable? globalPatterns, + required Iterable? compilerSelections, + required Iterable? runtimes, + required BooleanSelector? includeTags, + required BooleanSelector? excludeTags, + required Map? tags, + required Map? onPlatform, + required bool? ignoreTimeouts, + + // Test-level configuration + required Timeout? timeout, + required bool? verboseTrace, + required bool? chainStackTraces, + required bool? skip, + required int? retry, + required String? skipReason, + required PlatformSelector? testOn, + required Iterable? addTags, + }) { var chosenPresetSet = chosenPresets?.toSet(); var configuration = Configuration._( - help: help, - customHtmlTemplatePath: customHtmlTemplatePath, - version: version, - pauseAfterLoad: pauseAfterLoad, - debug: debug, - color: color, - configurationPath: configurationPath, - reporter: reporter, - fileReporters: fileReporters, - coverage: coverage, - concurrency: concurrency, - shardIndex: shardIndex, - totalShards: totalShards, - testSelections: testSelections, - foldTraceExcept: foldTraceExcept, - foldTraceOnly: foldTraceOnly, - filename: filename, - chosenPresets: chosenPresetSet, - presets: _withChosenPresets(presets, chosenPresetSet), - overrideRuntimes: overrideRuntimes, - defineRuntimes: defineRuntimes, - noRetry: noRetry, - testRandomizeOrderingSeed: testRandomizeOrderingSeed, - stopOnFirstFailure: stopOnFirstFailure, - includeTags: includeTags, - excludeTags: excludeTags, - globalPatterns: globalPatterns, - suiteDefaults: SuiteConfiguration( - allowDuplicateTestNames: allowDuplicateTestNames, - allowTestRandomization: allowTestRandomization, - jsTrace: jsTrace, - runSkipped: runSkipped, - dart2jsArgs: dart2jsArgs, - precompiledPath: precompiledPath, - compilerSelections: compilerSelections, - runtimes: runtimes, - tags: tags, - onPlatform: onPlatform, - ignoreTimeouts: ignoreTimeouts, - - // Test-level configuration - timeout: timeout, - verboseTrace: verboseTrace, - chainStackTraces: chainStackTraces, - skip: skip, - retry: retry, - skipReason: skipReason, - testOn: testOn, - addTags: addTags)); + help: help, + customHtmlTemplatePath: customHtmlTemplatePath, + version: version, + pauseAfterLoad: pauseAfterLoad, + debug: debug, + color: color, + configurationPath: configurationPath, + reporter: reporter, + fileReporters: fileReporters, + coverage: coverage, + concurrency: concurrency, + shardIndex: shardIndex, + totalShards: totalShards, + testSelections: testSelections, + foldTraceExcept: foldTraceExcept, + foldTraceOnly: foldTraceOnly, + filename: filename, + chosenPresets: chosenPresetSet, + presets: _withChosenPresets(presets, chosenPresetSet), + overrideRuntimes: overrideRuntimes, + defineRuntimes: defineRuntimes, + noRetry: noRetry, + testRandomizeOrderingSeed: testRandomizeOrderingSeed, + stopOnFirstFailure: stopOnFirstFailure, + includeTags: includeTags, + excludeTags: excludeTags, + globalPatterns: globalPatterns, + suiteDefaults: SuiteConfiguration( + allowDuplicateTestNames: allowDuplicateTestNames, + allowTestRandomization: allowTestRandomization, + jsTrace: jsTrace, + runSkipped: runSkipped, + dart2jsArgs: dart2jsArgs, + precompiledPath: precompiledPath, + compilerSelections: compilerSelections, + runtimes: runtimes, + tags: tags, + onPlatform: onPlatform, + ignoreTimeouts: ignoreTimeouts, + + // Test-level configuration + timeout: timeout, + verboseTrace: verboseTrace, + chainStackTraces: chainStackTraces, + skip: skip, + retry: retry, + skipReason: skipReason, + testOn: testOn, + addTags: addTags, + ), + ); return configuration._resolvePresets(); } @@ -355,104 +361,105 @@ class Configuration { /// /// This should only be used in situations where you really only want to /// configure a specific restricted set of options. - factory Configuration._unsafe( - {bool? help, - String? customHtmlTemplatePath, - bool? version, - bool? pauseAfterLoad, - bool? debug, - bool? color, - String? configurationPath, - String? reporter, - Map? fileReporters, - String? coverage, - int? concurrency, - int? shardIndex, - int? totalShards, - Map>? testSelections, - Iterable? foldTraceExcept, - Iterable? foldTraceOnly, - Glob? filename, - Iterable? chosenPresets, - Map? presets, - Map? overrideRuntimes, - Map? defineRuntimes, - bool? noRetry, - int? testRandomizeOrderingSeed, - bool? stopOnFirstFailure, - - // Suite-level configuration - bool? allowDuplicateTestNames, - bool? allowTestRandomization, - bool? jsTrace, - bool? runSkipped, - Iterable? dart2jsArgs, - String? precompiledPath, - Iterable? globalPatterns, - Iterable? compilerSelections, - Iterable? runtimes, - BooleanSelector? includeTags, - BooleanSelector? excludeTags, - Map? tags, - Map? onPlatform, - bool? ignoreTimeouts, - - // Test-level configuration - Timeout? timeout, - bool? verboseTrace, - bool? chainStackTraces, - bool? skip, - int? retry, - String? skipReason, - PlatformSelector? testOn, - Iterable? addTags}) => - Configuration( - help: help, - customHtmlTemplatePath: customHtmlTemplatePath, - version: version, - pauseAfterLoad: pauseAfterLoad, - debug: debug, - color: color, - configurationPath: configurationPath, - reporter: reporter, - fileReporters: fileReporters, - coverage: coverage, - concurrency: concurrency, - shardIndex: shardIndex, - totalShards: totalShards, - testSelections: testSelections, - foldTraceExcept: foldTraceExcept, - foldTraceOnly: foldTraceOnly, - filename: filename, - chosenPresets: chosenPresets, - presets: presets, - overrideRuntimes: overrideRuntimes, - defineRuntimes: defineRuntimes, - noRetry: noRetry, - testRandomizeOrderingSeed: testRandomizeOrderingSeed, - stopOnFirstFailure: stopOnFirstFailure, - allowDuplicateTestNames: allowDuplicateTestNames, - allowTestRandomization: allowTestRandomization, - jsTrace: jsTrace, - runSkipped: runSkipped, - dart2jsArgs: dart2jsArgs, - precompiledPath: precompiledPath, - globalPatterns: globalPatterns, - compilerSelections: compilerSelections, - runtimes: runtimes, - includeTags: includeTags, - excludeTags: excludeTags, - tags: tags, - onPlatform: onPlatform, - ignoreTimeouts: ignoreTimeouts, - timeout: timeout, - verboseTrace: verboseTrace, - chainStackTraces: chainStackTraces, - skip: skip, - retry: retry, - skipReason: skipReason, - testOn: testOn, - addTags: addTags); + factory Configuration._unsafe({ + bool? help, + String? customHtmlTemplatePath, + bool? version, + bool? pauseAfterLoad, + bool? debug, + bool? color, + String? configurationPath, + String? reporter, + Map? fileReporters, + String? coverage, + int? concurrency, + int? shardIndex, + int? totalShards, + Map>? testSelections, + Iterable? foldTraceExcept, + Iterable? foldTraceOnly, + Glob? filename, + Iterable? chosenPresets, + Map? presets, + Map? overrideRuntimes, + Map? defineRuntimes, + bool? noRetry, + int? testRandomizeOrderingSeed, + bool? stopOnFirstFailure, + + // Suite-level configuration + bool? allowDuplicateTestNames, + bool? allowTestRandomization, + bool? jsTrace, + bool? runSkipped, + Iterable? dart2jsArgs, + String? precompiledPath, + Iterable? globalPatterns, + Iterable? compilerSelections, + Iterable? runtimes, + BooleanSelector? includeTags, + BooleanSelector? excludeTags, + Map? tags, + Map? onPlatform, + bool? ignoreTimeouts, + + // Test-level configuration + Timeout? timeout, + bool? verboseTrace, + bool? chainStackTraces, + bool? skip, + int? retry, + String? skipReason, + PlatformSelector? testOn, + Iterable? addTags, + }) => Configuration( + help: help, + customHtmlTemplatePath: customHtmlTemplatePath, + version: version, + pauseAfterLoad: pauseAfterLoad, + debug: debug, + color: color, + configurationPath: configurationPath, + reporter: reporter, + fileReporters: fileReporters, + coverage: coverage, + concurrency: concurrency, + shardIndex: shardIndex, + totalShards: totalShards, + testSelections: testSelections, + foldTraceExcept: foldTraceExcept, + foldTraceOnly: foldTraceOnly, + filename: filename, + chosenPresets: chosenPresets, + presets: presets, + overrideRuntimes: overrideRuntimes, + defineRuntimes: defineRuntimes, + noRetry: noRetry, + testRandomizeOrderingSeed: testRandomizeOrderingSeed, + stopOnFirstFailure: stopOnFirstFailure, + allowDuplicateTestNames: allowDuplicateTestNames, + allowTestRandomization: allowTestRandomization, + jsTrace: jsTrace, + runSkipped: runSkipped, + dart2jsArgs: dart2jsArgs, + precompiledPath: precompiledPath, + globalPatterns: globalPatterns, + compilerSelections: compilerSelections, + runtimes: runtimes, + includeTags: includeTags, + excludeTags: excludeTags, + tags: tags, + onPlatform: onPlatform, + ignoreTimeouts: ignoreTimeouts, + timeout: timeout, + verboseTrace: verboseTrace, + chainStackTraces: chainStackTraces, + skip: skip, + retry: retry, + skipReason: skipReason, + testOn: testOn, + addTags: addTags, + ); /// Suite level configuration allowed in the global test config file. /// @@ -467,55 +474,54 @@ class Configuration { required bool? chainStackTraces, required Iterable? foldTraceExcept, required Iterable? foldTraceOnly, - }) => - Configuration( - foldTraceExcept: foldTraceExcept, - foldTraceOnly: foldTraceOnly, - jsTrace: jsTrace, - timeout: timeout, - verboseTrace: verboseTrace, - chainStackTraces: chainStackTraces, - help: null, - customHtmlTemplatePath: null, - version: null, - pauseAfterLoad: null, - debug: null, - color: null, - configurationPath: null, - reporter: null, - fileReporters: null, - coverage: null, - concurrency: null, - shardIndex: null, - totalShards: null, - testSelections: null, - filename: null, - chosenPresets: null, - presets: presets, - overrideRuntimes: null, - defineRuntimes: null, - noRetry: null, - testRandomizeOrderingSeed: null, - stopOnFirstFailure: null, - ignoreTimeouts: null, - allowDuplicateTestNames: null, - allowTestRandomization: null, - runSkipped: null, - dart2jsArgs: null, - precompiledPath: null, - globalPatterns: null, - compilerSelections: null, - runtimes: null, - includeTags: null, - excludeTags: null, - tags: null, - onPlatform: null, - skip: null, - retry: null, - skipReason: null, - testOn: null, - addTags: null, - ); + }) => Configuration( + foldTraceExcept: foldTraceExcept, + foldTraceOnly: foldTraceOnly, + jsTrace: jsTrace, + timeout: timeout, + verboseTrace: verboseTrace, + chainStackTraces: chainStackTraces, + help: null, + customHtmlTemplatePath: null, + version: null, + pauseAfterLoad: null, + debug: null, + color: null, + configurationPath: null, + reporter: null, + fileReporters: null, + coverage: null, + concurrency: null, + shardIndex: null, + totalShards: null, + testSelections: null, + filename: null, + chosenPresets: null, + presets: presets, + overrideRuntimes: null, + defineRuntimes: null, + noRetry: null, + testRandomizeOrderingSeed: null, + stopOnFirstFailure: null, + ignoreTimeouts: null, + allowDuplicateTestNames: null, + allowTestRandomization: null, + runSkipped: null, + dart2jsArgs: null, + precompiledPath: null, + globalPatterns: null, + compilerSelections: null, + runtimes: null, + includeTags: null, + excludeTags: null, + tags: null, + onPlatform: null, + skip: null, + retry: null, + skipReason: null, + testOn: null, + addTags: null, + ); /// Suite level configuration that is not allowed in the global test /// config file. @@ -531,55 +537,54 @@ class Configuration { required Iterable? addTags, required bool? allowDuplicateTestNames, required bool? allowTestRandomization, - }) => - Configuration( - allowDuplicateTestNames: allowDuplicateTestNames, - allowTestRandomization: allowTestRandomization, - skip: skip, - retry: retry, - skipReason: skipReason, - testOn: testOn, - addTags: addTags, - help: null, - customHtmlTemplatePath: null, - version: null, - pauseAfterLoad: null, - debug: null, - color: null, - configurationPath: null, - reporter: null, - fileReporters: null, - coverage: null, - concurrency: null, - shardIndex: null, - totalShards: null, - testSelections: null, - foldTraceExcept: null, - foldTraceOnly: null, - filename: null, - chosenPresets: null, - presets: null, - overrideRuntimes: null, - defineRuntimes: null, - noRetry: null, - testRandomizeOrderingSeed: null, - stopOnFirstFailure: null, - jsTrace: null, - runSkipped: null, - dart2jsArgs: null, - precompiledPath: null, - globalPatterns: null, - compilerSelections: null, - runtimes: null, - includeTags: null, - excludeTags: null, - tags: null, - onPlatform: null, - ignoreTimeouts: null, - timeout: null, - verboseTrace: null, - chainStackTraces: null, - ); + }) => Configuration( + allowDuplicateTestNames: allowDuplicateTestNames, + allowTestRandomization: allowTestRandomization, + skip: skip, + retry: retry, + skipReason: skipReason, + testOn: testOn, + addTags: addTags, + help: null, + customHtmlTemplatePath: null, + version: null, + pauseAfterLoad: null, + debug: null, + color: null, + configurationPath: null, + reporter: null, + fileReporters: null, + coverage: null, + concurrency: null, + shardIndex: null, + totalShards: null, + testSelections: null, + foldTraceExcept: null, + foldTraceOnly: null, + filename: null, + chosenPresets: null, + presets: null, + overrideRuntimes: null, + defineRuntimes: null, + noRetry: null, + testRandomizeOrderingSeed: null, + stopOnFirstFailure: null, + jsTrace: null, + runSkipped: null, + dart2jsArgs: null, + precompiledPath: null, + globalPatterns: null, + compilerSelections: null, + runtimes: null, + includeTags: null, + excludeTags: null, + tags: null, + onPlatform: null, + ignoreTimeouts: null, + timeout: null, + verboseTrace: null, + chainStackTraces: null, + ); /// Runner configuration that is allowed in the global test config file. /// @@ -589,257 +594,270 @@ class Configuration { /// /// Note that [customHtmlTemplatePath] violates this rule, and really should /// not be configurable globally. - factory Configuration.globalRunner( - {required bool? pauseAfterLoad, - required String? customHtmlTemplatePath, - required bool? runSkipped, - required String? reporter, - required Map? fileReporters, - required int? concurrency, - required Iterable? compilerSelections, - required Iterable? runtimes, - required Iterable? chosenPresets, - required Map? overrideRuntimes}) => - Configuration( - customHtmlTemplatePath: customHtmlTemplatePath, - pauseAfterLoad: pauseAfterLoad, - runSkipped: runSkipped, - reporter: reporter, - fileReporters: fileReporters, - concurrency: concurrency, - compilerSelections: compilerSelections, - runtimes: runtimes, - chosenPresets: chosenPresets, - overrideRuntimes: overrideRuntimes, - help: null, - version: null, - debug: null, - color: null, - configurationPath: null, - coverage: null, - shardIndex: null, - totalShards: null, - testSelections: null, - foldTraceExcept: null, - foldTraceOnly: null, - filename: null, - presets: null, - defineRuntimes: null, - noRetry: null, - testRandomizeOrderingSeed: null, - stopOnFirstFailure: null, - allowDuplicateTestNames: null, - allowTestRandomization: null, - jsTrace: null, - dart2jsArgs: null, - precompiledPath: null, - globalPatterns: null, - includeTags: null, - excludeTags: null, - tags: null, - onPlatform: null, - ignoreTimeouts: null, - timeout: null, - verboseTrace: null, - chainStackTraces: null, - skip: null, - retry: null, - skipReason: null, - testOn: null, - addTags: null, - ); + factory Configuration.globalRunner({ + required bool? pauseAfterLoad, + required String? customHtmlTemplatePath, + required bool? runSkipped, + required String? reporter, + required Map? fileReporters, + required int? concurrency, + required Iterable? compilerSelections, + required Iterable? runtimes, + required Iterable? chosenPresets, + required Map? overrideRuntimes, + }) => Configuration( + customHtmlTemplatePath: customHtmlTemplatePath, + pauseAfterLoad: pauseAfterLoad, + runSkipped: runSkipped, + reporter: reporter, + fileReporters: fileReporters, + concurrency: concurrency, + compilerSelections: compilerSelections, + runtimes: runtimes, + chosenPresets: chosenPresets, + overrideRuntimes: overrideRuntimes, + help: null, + version: null, + debug: null, + color: null, + configurationPath: null, + coverage: null, + shardIndex: null, + totalShards: null, + testSelections: null, + foldTraceExcept: null, + foldTraceOnly: null, + filename: null, + presets: null, + defineRuntimes: null, + noRetry: null, + testRandomizeOrderingSeed: null, + stopOnFirstFailure: null, + allowDuplicateTestNames: null, + allowTestRandomization: null, + jsTrace: null, + dart2jsArgs: null, + precompiledPath: null, + globalPatterns: null, + includeTags: null, + excludeTags: null, + tags: null, + onPlatform: null, + ignoreTimeouts: null, + timeout: null, + verboseTrace: null, + chainStackTraces: null, + skip: null, + retry: null, + skipReason: null, + testOn: null, + addTags: null, + ); /// Runner configuration that is not allowed in the global test config file. /// /// This configuration may alter the pass/fail result of a test run, and thus /// should only be configured per package and not at the global level (global /// config is user specific). - factory Configuration.localRunner( - {required Iterable? globalPatterns, - required Map>? testSelections, - required Glob? filename, - required BooleanSelector? includeTags, - required BooleanSelector? excludeTags, - required Map? defineRuntimes}) => - Configuration( - globalPatterns: globalPatterns, - testSelections: testSelections, - filename: filename, - includeTags: includeTags, - excludeTags: excludeTags, - defineRuntimes: defineRuntimes, - help: null, - customHtmlTemplatePath: null, - version: null, - pauseAfterLoad: null, - debug: null, - color: null, - configurationPath: null, - reporter: null, - fileReporters: null, - coverage: null, - concurrency: null, - shardIndex: null, - totalShards: null, - foldTraceExcept: null, - foldTraceOnly: null, - chosenPresets: null, - presets: null, - overrideRuntimes: null, - noRetry: null, - testRandomizeOrderingSeed: null, - stopOnFirstFailure: null, - allowDuplicateTestNames: null, - allowTestRandomization: null, - jsTrace: null, - runSkipped: null, - dart2jsArgs: null, - precompiledPath: null, - compilerSelections: null, - runtimes: null, - tags: null, - onPlatform: null, - ignoreTimeouts: null, - timeout: null, - verboseTrace: null, - chainStackTraces: null, - skip: null, - retry: null, - skipReason: null, - testOn: null, - addTags: null); + factory Configuration.localRunner({ + required Iterable? globalPatterns, + required Map>? testSelections, + required Glob? filename, + required BooleanSelector? includeTags, + required BooleanSelector? excludeTags, + required Map? defineRuntimes, + }) => Configuration( + globalPatterns: globalPatterns, + testSelections: testSelections, + filename: filename, + includeTags: includeTags, + excludeTags: excludeTags, + defineRuntimes: defineRuntimes, + help: null, + customHtmlTemplatePath: null, + version: null, + pauseAfterLoad: null, + debug: null, + color: null, + configurationPath: null, + reporter: null, + fileReporters: null, + coverage: null, + concurrency: null, + shardIndex: null, + totalShards: null, + foldTraceExcept: null, + foldTraceOnly: null, + chosenPresets: null, + presets: null, + overrideRuntimes: null, + noRetry: null, + testRandomizeOrderingSeed: null, + stopOnFirstFailure: null, + allowDuplicateTestNames: null, + allowTestRandomization: null, + jsTrace: null, + runSkipped: null, + dart2jsArgs: null, + precompiledPath: null, + compilerSelections: null, + runtimes: null, + tags: null, + onPlatform: null, + ignoreTimeouts: null, + timeout: null, + verboseTrace: null, + chainStackTraces: null, + skip: null, + retry: null, + skipReason: null, + testOn: null, + addTags: null, + ); /// A specialized constructor for configuring only `onPlatform`. factory Configuration.onPlatform( - Map onPlatform) => - Configuration._unsafe(onPlatform: onPlatform); + Map onPlatform, + ) => Configuration._unsafe(onPlatform: onPlatform); factory Configuration.tags(Map tags) => Configuration._unsafe(tags: tags); static Map? _withChosenPresets( - Map? map, Set? chosenPresets) { + Map? map, + Set? chosenPresets, + ) { if (map == null || chosenPresets == null) return map; - return map.map((key, config) => MapEntry( + return map.map( + (key, config) => MapEntry( key, - config.change( - chosenPresets: config.chosenPresets.union(chosenPresets)))); + config.change(chosenPresets: config.chosenPresets.union(chosenPresets)), + ), + ); } /// Creates new Configuration. /// /// Unlike [Configuration.new], this assumes [presets] is already resolved. - Configuration._( - {required bool? help, - required this.customHtmlTemplatePath, - required bool? version, - required bool? pauseAfterLoad, - required bool? debug, - required bool? color, - required String? configurationPath, - required String? reporter, - required Map? fileReporters, - required this.coverage, - required int? concurrency, - required this.shardIndex, - required this.totalShards, - required Map>? testSelections, - required Iterable? foldTraceExcept, - required Iterable? foldTraceOnly, - required Glob? filename, - required Iterable? chosenPresets, - required Map? presets, - required Map? overrideRuntimes, - required Map? defineRuntimes, - required bool? noRetry, - required this.testRandomizeOrderingSeed, - required bool? stopOnFirstFailure, - required BooleanSelector? includeTags, - required BooleanSelector? excludeTags, - required Iterable? globalPatterns, - required SuiteConfiguration? suiteDefaults}) - : _help = help, - _version = version, - _pauseAfterLoad = pauseAfterLoad, - _debug = debug, - _color = color, - _configurationPath = configurationPath, - _reporter = reporter, - fileReporters = fileReporters ?? {}, - _concurrency = concurrency, - _testSelections = testSelections == null || testSelections.isEmpty - ? null - : Map.unmodifiable(testSelections), - _foldTraceExcept = _set(foldTraceExcept), - _foldTraceOnly = _set(foldTraceOnly), - _filename = filename, - chosenPresets = UnmodifiableSetView(chosenPresets?.toSet() ?? {}), - presets = _map(presets), - overrideRuntimes = _map(overrideRuntimes), - defineRuntimes = _map(defineRuntimes), - _noRetry = noRetry, - includeTags = includeTags ?? BooleanSelector.all, - excludeTags = excludeTags ?? BooleanSelector.none, - globalPatterns = globalPatterns == null - ? const {} - : UnmodifiableSetView(globalPatterns.toSet()), - _stopOnFirstFailure = stopOnFirstFailure, - suiteDefaults = (() { - var config = suiteDefaults ?? SuiteConfiguration.empty; - if (pauseAfterLoad == true) { - return config.change(ignoreTimeouts: true); - } - return config; - }()) { + Configuration._({ + required bool? help, + required this.customHtmlTemplatePath, + required bool? version, + required bool? pauseAfterLoad, + required bool? debug, + required bool? color, + required String? configurationPath, + required String? reporter, + required Map? fileReporters, + required this.coverage, + required int? concurrency, + required this.shardIndex, + required this.totalShards, + required Map>? testSelections, + required Iterable? foldTraceExcept, + required Iterable? foldTraceOnly, + required Glob? filename, + required Iterable? chosenPresets, + required Map? presets, + required Map? overrideRuntimes, + required Map? defineRuntimes, + required bool? noRetry, + required this.testRandomizeOrderingSeed, + required bool? stopOnFirstFailure, + required BooleanSelector? includeTags, + required BooleanSelector? excludeTags, + required Iterable? globalPatterns, + required SuiteConfiguration? suiteDefaults, + }) : _help = help, + _version = version, + _pauseAfterLoad = pauseAfterLoad, + _debug = debug, + _color = color, + _configurationPath = configurationPath, + _reporter = reporter, + fileReporters = fileReporters ?? {}, + _concurrency = concurrency, + _testSelections = + testSelections == null || testSelections.isEmpty + ? null + : Map.unmodifiable(testSelections), + _foldTraceExcept = _set(foldTraceExcept), + _foldTraceOnly = _set(foldTraceOnly), + _filename = filename, + chosenPresets = UnmodifiableSetView(chosenPresets?.toSet() ?? {}), + presets = _map(presets), + overrideRuntimes = _map(overrideRuntimes), + defineRuntimes = _map(defineRuntimes), + _noRetry = noRetry, + includeTags = includeTags ?? BooleanSelector.all, + excludeTags = excludeTags ?? BooleanSelector.none, + globalPatterns = + globalPatterns == null + ? const {} + : UnmodifiableSetView(globalPatterns.toSet()), + _stopOnFirstFailure = stopOnFirstFailure, + suiteDefaults = (() { + var config = suiteDefaults ?? SuiteConfiguration.empty; + if (pauseAfterLoad == true) { + return config.change(ignoreTimeouts: true); + } + return config; + }()) { if (_filename != null && _filename.context.style != p.style) { throw ArgumentError( - "filename's context must match the current operating system, was " - '${_filename.context.style}.'); + "filename's context must match the current operating system, was " + '${_filename.context.style}.', + ); } if ((shardIndex == null) != (totalShards == null)) { throw ArgumentError( - 'shardIndex and totalShards may only be passed together.'); + 'shardIndex and totalShards may only be passed together.', + ); } else if (shardIndex != null) { RangeError.checkValueInInterval( - shardIndex!, 0, totalShards! - 1, 'shardIndex'); + shardIndex!, + 0, + totalShards! - 1, + 'shardIndex', + ); } } /// Creates a new [Configuration] that takes its configuration from /// [SuiteConfiguration]. factory Configuration.fromSuiteConfiguration( - SuiteConfiguration suiteConfig) => - Configuration._( - suiteDefaults: suiteConfig, - globalPatterns: null, - help: null, - customHtmlTemplatePath: null, - version: null, - pauseAfterLoad: null, - debug: null, - color: null, - configurationPath: null, - reporter: null, - fileReporters: null, - coverage: null, - concurrency: null, - shardIndex: null, - totalShards: null, - testSelections: null, - foldTraceExcept: null, - foldTraceOnly: null, - filename: null, - chosenPresets: null, - presets: null, - overrideRuntimes: null, - defineRuntimes: null, - noRetry: null, - testRandomizeOrderingSeed: null, - stopOnFirstFailure: null, - includeTags: null, - excludeTags: null, - ); + SuiteConfiguration suiteConfig, + ) => Configuration._( + suiteDefaults: suiteConfig, + globalPatterns: null, + help: null, + customHtmlTemplatePath: null, + version: null, + pauseAfterLoad: null, + debug: null, + color: null, + configurationPath: null, + reporter: null, + fileReporters: null, + coverage: null, + concurrency: null, + shardIndex: null, + totalShards: null, + testSelections: null, + foldTraceExcept: null, + foldTraceOnly: null, + filename: null, + chosenPresets: null, + presets: null, + overrideRuntimes: null, + defineRuntimes: null, + noRetry: null, + testRandomizeOrderingSeed: null, + stopOnFirstFailure: null, + includeTags: null, + excludeTags: null, + ); /// Returns a set from [input]. /// @@ -870,11 +888,13 @@ class Configuration { // already need to be verified and resolved to create [allRuntimes]. for (var settings in overrideRuntimes.values) { - if (!allRuntimes - .any((runtime) => runtime.identifier == settings.identifier)) { + if (!allRuntimes.any( + (runtime) => runtime.identifier == settings.identifier, + )) { throw SourceSpanFormatException( - 'Unknown platform "${settings.identifier}".', - settings.identifierSpan); + 'Unknown platform "${settings.identifier}".', + settings.identifierSpan, + ); } } @@ -910,42 +930,49 @@ class Configuration { } var result = Configuration._( - help: other._help ?? _help, - customHtmlTemplatePath: - other.customHtmlTemplatePath ?? customHtmlTemplatePath, - version: other._version ?? _version, - pauseAfterLoad: other._pauseAfterLoad ?? _pauseAfterLoad, - debug: other._debug ?? _debug, - color: other._color ?? _color, - configurationPath: other._configurationPath ?? _configurationPath, - reporter: other._reporter ?? _reporter, - fileReporters: mergeMaps(fileReporters, other.fileReporters), - coverage: other.coverage ?? coverage, - concurrency: other._concurrency ?? _concurrency, - shardIndex: other.shardIndex ?? shardIndex, - totalShards: other.totalShards ?? totalShards, - testSelections: other._testSelections ?? _testSelections, - foldTraceExcept: foldTraceExcept, - foldTraceOnly: foldTraceOnly, - filename: other._filename ?? _filename, - chosenPresets: chosenPresets.union(other.chosenPresets), - presets: _mergeConfigMaps(presets, other.presets), - overrideRuntimes: mergeUnmodifiableMaps( - overrideRuntimes, other.overrideRuntimes, - value: (settings1, settings2) => RuntimeSettings( - settings1.identifier, - settings1.identifierSpan, - [...settings1.settings, ...settings2.settings])), - defineRuntimes: - mergeUnmodifiableMaps(defineRuntimes, other.defineRuntimes), - noRetry: other._noRetry ?? _noRetry, - testRandomizeOrderingSeed: - other.testRandomizeOrderingSeed ?? testRandomizeOrderingSeed, - stopOnFirstFailure: other._stopOnFirstFailure ?? _stopOnFirstFailure, - includeTags: includeTags.intersection(other.includeTags), - excludeTags: excludeTags.union(other.excludeTags), - globalPatterns: globalPatterns.union(other.globalPatterns), - suiteDefaults: suiteDefaults.merge(other.suiteDefaults)); + help: other._help ?? _help, + customHtmlTemplatePath: + other.customHtmlTemplatePath ?? customHtmlTemplatePath, + version: other._version ?? _version, + pauseAfterLoad: other._pauseAfterLoad ?? _pauseAfterLoad, + debug: other._debug ?? _debug, + color: other._color ?? _color, + configurationPath: other._configurationPath ?? _configurationPath, + reporter: other._reporter ?? _reporter, + fileReporters: mergeMaps(fileReporters, other.fileReporters), + coverage: other.coverage ?? coverage, + concurrency: other._concurrency ?? _concurrency, + shardIndex: other.shardIndex ?? shardIndex, + totalShards: other.totalShards ?? totalShards, + testSelections: other._testSelections ?? _testSelections, + foldTraceExcept: foldTraceExcept, + foldTraceOnly: foldTraceOnly, + filename: other._filename ?? _filename, + chosenPresets: chosenPresets.union(other.chosenPresets), + presets: _mergeConfigMaps(presets, other.presets), + overrideRuntimes: mergeUnmodifiableMaps( + overrideRuntimes, + other.overrideRuntimes, + value: + (settings1, settings2) => RuntimeSettings( + settings1.identifier, + settings1.identifierSpan, + [...settings1.settings, ...settings2.settings], + ), + ), + defineRuntimes: mergeUnmodifiableMaps( + defineRuntimes, + other.defineRuntimes, + ), + noRetry: other._noRetry ?? _noRetry, + testRandomizeOrderingSeed: + other.testRandomizeOrderingSeed ?? testRandomizeOrderingSeed, + stopOnFirstFailure: other._stopOnFirstFailure ?? _stopOnFirstFailure, + includeTags: includeTags.intersection(other.includeTags), + excludeTags: excludeTags.union(other.excludeTags), + globalPatterns: globalPatterns.union(other.globalPatterns), + suiteDefaults: suiteDefaults.merge(other.suiteDefaults), + ); result = result._resolvePresets(); // Make sure the merged config preserves any presets that were chosen and @@ -958,100 +985,102 @@ class Configuration { /// /// Note that unlike [merge], this has no merging behavior—the old value is /// always replaced by the new one. - Configuration change( - {bool? help, - String? customHtmlTemplatePath, - bool? version, - bool? pauseAfterLoad, - bool? debug, - bool? color, - String? configurationPath, - String? reporter, - Map? fileReporters, - String? coverage, - int? concurrency, - int? shardIndex, - int? totalShards, - Map>? testSelections, - Iterable? exceptPackages, - Iterable? onlyPackages, - Glob? filename, - Iterable? chosenPresets, - Map? presets, - Map? overrideRuntimes, - Map? defineRuntimes, - bool? noRetry, - int? testRandomizeOrderingSeed, - bool? ignoreTimeouts, - - // Suite-level configuration - bool? allowDuplicateTestNames, - bool? jsTrace, - bool? runSkipped, - Iterable? dart2jsArgs, - String? precompiledPath, - Iterable? runtimes, - BooleanSelector? includeTags, - BooleanSelector? excludeTags, - Map? tags, - Map? onPlatform, - - // Test-level configuration - Timeout? timeout, - bool? verboseTrace, - bool? chainStackTraces, - bool? skip, - String? skipReason, - PlatformSelector? testOn, - Iterable? addTags}) { + Configuration change({ + bool? help, + String? customHtmlTemplatePath, + bool? version, + bool? pauseAfterLoad, + bool? debug, + bool? color, + String? configurationPath, + String? reporter, + Map? fileReporters, + String? coverage, + int? concurrency, + int? shardIndex, + int? totalShards, + Map>? testSelections, + Iterable? exceptPackages, + Iterable? onlyPackages, + Glob? filename, + Iterable? chosenPresets, + Map? presets, + Map? overrideRuntimes, + Map? defineRuntimes, + bool? noRetry, + int? testRandomizeOrderingSeed, + bool? ignoreTimeouts, + + // Suite-level configuration + bool? allowDuplicateTestNames, + bool? jsTrace, + bool? runSkipped, + Iterable? dart2jsArgs, + String? precompiledPath, + Iterable? runtimes, + BooleanSelector? includeTags, + BooleanSelector? excludeTags, + Map? tags, + Map? onPlatform, + + // Test-level configuration + Timeout? timeout, + bool? verboseTrace, + bool? chainStackTraces, + bool? skip, + String? skipReason, + PlatformSelector? testOn, + Iterable? addTags, + }) { var config = Configuration._( - help: help ?? _help, - customHtmlTemplatePath: - customHtmlTemplatePath ?? this.customHtmlTemplatePath, - version: version ?? _version, - pauseAfterLoad: pauseAfterLoad ?? _pauseAfterLoad, - debug: debug ?? _debug, - color: color ?? _color, - configurationPath: configurationPath ?? _configurationPath, - reporter: reporter ?? _reporter, - fileReporters: fileReporters ?? this.fileReporters, - coverage: coverage ?? this.coverage, - concurrency: concurrency ?? _concurrency, - shardIndex: shardIndex ?? this.shardIndex, - totalShards: totalShards ?? this.totalShards, - testSelections: testSelections ?? _testSelections, - foldTraceExcept: exceptPackages ?? _foldTraceExcept, - foldTraceOnly: onlyPackages ?? _foldTraceOnly, - filename: filename ?? _filename, - chosenPresets: chosenPresets ?? this.chosenPresets, - presets: presets ?? this.presets, - overrideRuntimes: overrideRuntimes ?? this.overrideRuntimes, - defineRuntimes: defineRuntimes ?? this.defineRuntimes, - noRetry: noRetry ?? _noRetry, - testRandomizeOrderingSeed: - testRandomizeOrderingSeed ?? this.testRandomizeOrderingSeed, - stopOnFirstFailure: _stopOnFirstFailure, - includeTags: includeTags, - excludeTags: excludeTags, - globalPatterns: globalPatterns, - suiteDefaults: suiteDefaults.change( - allowDuplicateTestNames: allowDuplicateTestNames, - jsTrace: jsTrace, - runSkipped: runSkipped, - dart2jsArgs: dart2jsArgs, - precompiledPath: precompiledPath, - runtimes: runtimes, - tags: tags, - onPlatform: onPlatform, - timeout: timeout, - verboseTrace: verboseTrace, - chainStackTraces: chainStackTraces, - skip: skip, - skipReason: skipReason, - testOn: testOn, - addTags: addTags, - ignoreTimeouts: ignoreTimeouts, - )); + help: help ?? _help, + customHtmlTemplatePath: + customHtmlTemplatePath ?? this.customHtmlTemplatePath, + version: version ?? _version, + pauseAfterLoad: pauseAfterLoad ?? _pauseAfterLoad, + debug: debug ?? _debug, + color: color ?? _color, + configurationPath: configurationPath ?? _configurationPath, + reporter: reporter ?? _reporter, + fileReporters: fileReporters ?? this.fileReporters, + coverage: coverage ?? this.coverage, + concurrency: concurrency ?? _concurrency, + shardIndex: shardIndex ?? this.shardIndex, + totalShards: totalShards ?? this.totalShards, + testSelections: testSelections ?? _testSelections, + foldTraceExcept: exceptPackages ?? _foldTraceExcept, + foldTraceOnly: onlyPackages ?? _foldTraceOnly, + filename: filename ?? _filename, + chosenPresets: chosenPresets ?? this.chosenPresets, + presets: presets ?? this.presets, + overrideRuntimes: overrideRuntimes ?? this.overrideRuntimes, + defineRuntimes: defineRuntimes ?? this.defineRuntimes, + noRetry: noRetry ?? _noRetry, + testRandomizeOrderingSeed: + testRandomizeOrderingSeed ?? this.testRandomizeOrderingSeed, + stopOnFirstFailure: _stopOnFirstFailure, + includeTags: includeTags, + excludeTags: excludeTags, + globalPatterns: globalPatterns, + suiteDefaults: suiteDefaults.change( + allowDuplicateTestNames: allowDuplicateTestNames, + jsTrace: jsTrace, + runSkipped: runSkipped, + dart2jsArgs: dart2jsArgs, + precompiledPath: precompiledPath, + runtimes: runtimes, + tags: tags, + onPlatform: onPlatform, + timeout: timeout, + verboseTrace: verboseTrace, + chainStackTraces: chainStackTraces, + skip: skip, + skipReason: skipReason, + testOn: testOn, + addTags: addTags, + ignoreTimeouts: ignoreTimeouts, + ), + ); return config._resolvePresets(); } @@ -1060,9 +1089,13 @@ class Configuration { /// Any overlapping keys in the maps have their configurations merged in the /// returned map. Map _mergeConfigMaps( - Map map1, Map map2) => - mergeMaps(map1, map2, - value: (config1, config2) => config1.merge(config2)); + Map map1, + Map map2, + ) => mergeMaps( + map1, + map2, + value: (config1, config2) => config1.merge(config2), + ); /// Returns a copy of this [Configuration] with all [chosenPresets] resolved /// against [presets]. @@ -1071,17 +1104,20 @@ class Configuration { var newPresets = Map.from(presets); var merged = chosenPresets.fold( - empty, - (Configuration merged, preset) => - merged.merge(newPresets.remove(preset) ?? Configuration.empty)); + empty, + (Configuration merged, preset) => + merged.merge(newPresets.remove(preset) ?? Configuration.empty), + ); if (merged == empty) return this; var result = change(presets: newPresets).merge(merged); // Make sure the configuration knows about presets that were selected and // thus removed from [newPresets]. - result._knownPresets = - UnmodifiableSetView({...result.knownPresets, ...presets.keys}); + result._knownPresets = UnmodifiableSetView({ + ...result.knownPresets, + ...presets.keys, + }); return result; } diff --git a/pkgs/test_core/lib/src/runner/configuration/args.dart b/pkgs/test_core/lib/src/runner/configuration/args.dart index e981bedc3..b66435be8 100644 --- a/pkgs/test_core/lib/src/runner/configuration/args.dart +++ b/pkgs/test_core/lib/src/runner/configuration/args.dart @@ -18,167 +18,254 @@ import 'reporters.dart'; import 'values.dart'; /// The parser used to parse the command-line arguments. -final ArgParser _parser = (() { - var parser = ArgParser(allowTrailingOptions: true); - - var allRuntimes = Runtime.builtIn.toList()..remove(Runtime.vm); - if (!Platform.isMacOS) allRuntimes.remove(Runtime.safari); - - parser.addFlag('help', - abbr: 'h', negatable: false, help: 'Show this usage information.'); - parser.addFlag('version', - negatable: false, help: 'Show the package:test version.'); - - // Note that defaultsTo declarations here are only for documentation purposes. - // We pass null instead of the default so that it merges properly with the - // config file. - - parser.addSeparator('Selecting Tests:'); - parser.addMultiOption('name', - abbr: 'n', - help: 'A substring of the name of the test to run.\n' - 'Regular expression syntax is supported.\n' - 'If passed multiple times, tests must match all substrings.', - splitCommas: false); - parser.addMultiOption('plain-name', - abbr: 'N', - help: 'A plain-text substring of the name of the test to run.\n' - 'If passed multiple times, tests must match all substrings.', - splitCommas: false); - parser.addMultiOption('tags', - abbr: 't', - help: 'Run only tests with all of the specified tags.\n' - 'Supports boolean selector syntax.'); - parser.addMultiOption('tag', hide: true); - parser.addMultiOption('exclude-tags', - abbr: 'x', - help: "Don't run tests with any of the specified tags.\n" - 'Supports boolean selector syntax.'); - parser.addMultiOption('exclude-tag', hide: true); - parser.addFlag('run-skipped', - help: 'Run skipped tests instead of skipping them.'); - - parser.addSeparator('Running Tests:'); - - // The UI term "platform" corresponds with the implementation term "runtime". - // The [Runtime] class used to be called [TestPlatform], but it was changed to - // avoid conflicting with [SuitePlatform]. We decided not to also change the - // UI to avoid a painful migration. - parser.addMultiOption('platform', - abbr: 'p', - help: 'The platform(s) on which to run the tests.\n' - '[vm (default), ' - '${allRuntimes.map((runtime) => runtime.identifier).join(", ")}].\n' - 'Each platform supports the following compilers:\n' - '${Runtime.vm.supportedCompilersText}\n' - '${allRuntimes.map((r) => r.supportedCompilersText).join('\n')}'); - parser.addMultiOption('compiler', - abbr: 'c', - help: 'The compiler(s) to use to run tests, supported compilers are ' - '[${Compiler.builtIn.map((c) => c.identifier).join(', ')}].\n' - 'Each platform has a default compiler but may support other ' - 'compilers.\n' - 'You can target a compiler to a specific platform using arguments ' - 'of the following form [:].\n' - 'If a platform is specified but no given compiler is supported for ' - 'that platform, then it will use its default compiler.'); - parser.addMultiOption('preset', - abbr: 'P', help: 'The configuration preset(s) to use.'); - parser.addOption('concurrency', - abbr: 'j', - help: 'The number of concurrent test suites run.', - defaultsTo: defaultConcurrency.toString(), - valueHelp: 'threads'); - parser.addOption('total-shards', - help: 'The total number of invocations of the test runner being run.'); - parser.addOption('shard-index', - help: 'The index of this test runner invocation (of --total-shards).'); - parser.addOption('pub-serve', - help: '[Removed] The port of a pub serve instance serving "test/".', - valueHelp: 'port', - hide: true); - parser.addOption('timeout', - help: 'The default test timeout. For example: 15s, 2x, none', - defaultsTo: '30s'); - parser.addFlag('ignore-timeouts', - help: 'Ignore all timeouts (useful if debugging)', negatable: false); - parser.addFlag('pause-after-load', - help: 'Pause for debugging before any tests execute.\n' - 'Implies --concurrency=1, --debug, and --ignore-timeouts.\n' - 'Currently only supported for browser tests.', - negatable: false); - parser.addFlag('debug', - help: 'Run the VM and Chrome tests in debug mode.', negatable: false); - parser.addOption('coverage', - help: 'Gather coverage and output it to the specified directory.\n' - 'Implies --debug.', - valueHelp: 'directory'); - parser.addFlag('chain-stack-traces', - help: 'Use chained stack traces to provide greater exception details\n' - 'especially for asynchronous code. It may be useful to disable\n' - 'to provide improved test performance but at the cost of\n' - 'debuggability.', - defaultsTo: false); - parser.addFlag('no-retry', - help: "Don't rerun tests that have retry set.", - defaultsTo: false, - negatable: false); - parser.addFlag('use-data-isolate-strategy', - help: '**DEPRECATED**: This is now just an alias for --compiler source.', - defaultsTo: false, - hide: true, - negatable: false); - parser.addOption('test-randomize-ordering-seed', - help: 'Use the specified seed to randomize the execution order of test' - ' cases.\n' - 'Must be a 32bit unsigned integer or "random".\n' - 'If "random", pick a random seed to use.\n' - 'If not passed, do not randomize test case execution order.'); - parser.addFlag('fail-fast', - help: 'Stop running tests after the first failure.\n'); - - var reporterDescriptions = { - for (final MapEntry(:key, :value) in allReporters.entries) - key: value.description - }; - - parser.addSeparator('Output:'); - parser.addOption('reporter', - abbr: 'r', - help: 'Set how to print test results.', - defaultsTo: defaultReporter, - allowed: allReporters.keys, - allowedHelp: reporterDescriptions, - valueHelp: 'option'); - parser.addOption('file-reporter', - help: 'Enable an additional reporter writing test results to a file.\n' - 'Should be in the form :, ' - 'Example: "json:reports/tests.json"'); - parser.addFlag('verbose-trace', - negatable: false, help: 'Emit stack traces with core library frames.'); - parser.addFlag('js-trace', - negatable: false, - help: 'Emit raw JavaScript stack traces for browser tests.'); - parser.addFlag('color', - help: 'Use terminal colors.\n(auto-detected by default)'); - - /// The following options are used only by the internal Google test runner. - /// They're hidden and not supported as stable API surface outside Google. - - parser.addOption('configuration', - help: 'The path to the configuration file.', hide: true); - parser.addMultiOption('dart2js-args', - help: 'Extra arguments to pass to dart2js.', hide: true); - - // If we're running test/dir/my_test.dart, we'll look for - // test/dir/my_test.dart.html in the precompiled directory. - parser.addOption('precompiled', - help: 'The path to a mirror of the package directory containing HTML ' - 'that points to precompiled JS.', - hide: true); - - return parser; -})(); +final ArgParser _parser = + (() { + var parser = ArgParser(allowTrailingOptions: true); + + var allRuntimes = Runtime.builtIn.toList()..remove(Runtime.vm); + if (!Platform.isMacOS) allRuntimes.remove(Runtime.safari); + + parser.addFlag( + 'help', + abbr: 'h', + negatable: false, + help: 'Show this usage information.', + ); + parser.addFlag( + 'version', + negatable: false, + help: 'Show the package:test version.', + ); + + // Note that defaultsTo declarations here are only for documentation purposes. + // We pass null instead of the default so that it merges properly with the + // config file. + + parser.addSeparator('Selecting Tests:'); + parser.addMultiOption( + 'name', + abbr: 'n', + help: + 'A substring of the name of the test to run.\n' + 'Regular expression syntax is supported.\n' + 'If passed multiple times, tests must match all substrings.', + splitCommas: false, + ); + parser.addMultiOption( + 'plain-name', + abbr: 'N', + help: + 'A plain-text substring of the name of the test to run.\n' + 'If passed multiple times, tests must match all substrings.', + splitCommas: false, + ); + parser.addMultiOption( + 'tags', + abbr: 't', + help: + 'Run only tests with all of the specified tags.\n' + 'Supports boolean selector syntax.', + ); + parser.addMultiOption('tag', hide: true); + parser.addMultiOption( + 'exclude-tags', + abbr: 'x', + help: + "Don't run tests with any of the specified tags.\n" + 'Supports boolean selector syntax.', + ); + parser.addMultiOption('exclude-tag', hide: true); + parser.addFlag( + 'run-skipped', + help: 'Run skipped tests instead of skipping them.', + ); + + parser.addSeparator('Running Tests:'); + + // The UI term "platform" corresponds with the implementation term "runtime". + // The [Runtime] class used to be called [TestPlatform], but it was changed to + // avoid conflicting with [SuitePlatform]. We decided not to also change the + // UI to avoid a painful migration. + parser.addMultiOption( + 'platform', + abbr: 'p', + help: + 'The platform(s) on which to run the tests.\n' + '[vm (default), ' + '${allRuntimes.map((runtime) => runtime.identifier).join(", ")}].\n' + 'Each platform supports the following compilers:\n' + '${Runtime.vm.supportedCompilersText}\n' + '${allRuntimes.map((r) => r.supportedCompilersText).join('\n')}', + ); + parser.addMultiOption( + 'compiler', + abbr: 'c', + help: + 'The compiler(s) to use to run tests, supported compilers are ' + '[${Compiler.builtIn.map((c) => c.identifier).join(', ')}].\n' + 'Each platform has a default compiler but may support other ' + 'compilers.\n' + 'You can target a compiler to a specific platform using arguments ' + 'of the following form [:].\n' + 'If a platform is specified but no given compiler is supported for ' + 'that platform, then it will use its default compiler.', + ); + parser.addMultiOption( + 'preset', + abbr: 'P', + help: 'The configuration preset(s) to use.', + ); + parser.addOption( + 'concurrency', + abbr: 'j', + help: 'The number of concurrent test suites run.', + defaultsTo: defaultConcurrency.toString(), + valueHelp: 'threads', + ); + parser.addOption( + 'total-shards', + help: 'The total number of invocations of the test runner being run.', + ); + parser.addOption( + 'shard-index', + help: 'The index of this test runner invocation (of --total-shards).', + ); + parser.addOption( + 'pub-serve', + help: '[Removed] The port of a pub serve instance serving "test/".', + valueHelp: 'port', + hide: true, + ); + parser.addOption( + 'timeout', + help: 'The default test timeout. For example: 15s, 2x, none', + defaultsTo: '30s', + ); + parser.addFlag( + 'ignore-timeouts', + help: 'Ignore all timeouts (useful if debugging)', + negatable: false, + ); + parser.addFlag( + 'pause-after-load', + help: + 'Pause for debugging before any tests execute.\n' + 'Implies --concurrency=1, --debug, and --ignore-timeouts.\n' + 'Currently only supported for browser tests.', + negatable: false, + ); + parser.addFlag( + 'debug', + help: 'Run the VM and Chrome tests in debug mode.', + negatable: false, + ); + parser.addOption( + 'coverage', + help: + 'Gather coverage and output it to the specified directory.\n' + 'Implies --debug.', + valueHelp: 'directory', + ); + parser.addFlag( + 'chain-stack-traces', + help: + 'Use chained stack traces to provide greater exception details\n' + 'especially for asynchronous code. It may be useful to disable\n' + 'to provide improved test performance but at the cost of\n' + 'debuggability.', + defaultsTo: false, + ); + parser.addFlag( + 'no-retry', + help: "Don't rerun tests that have retry set.", + defaultsTo: false, + negatable: false, + ); + parser.addFlag( + 'use-data-isolate-strategy', + help: + '**DEPRECATED**: This is now just an alias for --compiler source.', + defaultsTo: false, + hide: true, + negatable: false, + ); + parser.addOption( + 'test-randomize-ordering-seed', + help: + 'Use the specified seed to randomize the execution order of test' + ' cases.\n' + 'Must be a 32bit unsigned integer or "random".\n' + 'If "random", pick a random seed to use.\n' + 'If not passed, do not randomize test case execution order.', + ); + parser.addFlag( + 'fail-fast', + help: 'Stop running tests after the first failure.\n', + ); + + var reporterDescriptions = { + for (final MapEntry(:key, :value) in allReporters.entries) + key: value.description, + }; + + parser.addSeparator('Output:'); + parser.addOption( + 'reporter', + abbr: 'r', + help: 'Set how to print test results.', + defaultsTo: defaultReporter, + allowed: allReporters.keys, + allowedHelp: reporterDescriptions, + valueHelp: 'option', + ); + parser.addOption( + 'file-reporter', + help: + 'Enable an additional reporter writing test results to a file.\n' + 'Should be in the form :, ' + 'Example: "json:reports/tests.json"', + ); + parser.addFlag( + 'verbose-trace', + negatable: false, + help: 'Emit stack traces with core library frames.', + ); + parser.addFlag( + 'js-trace', + negatable: false, + help: 'Emit raw JavaScript stack traces for browser tests.', + ); + parser.addFlag( + 'color', + help: 'Use terminal colors.\n(auto-detected by default)', + ); + + /// The following options are used only by the internal Google test runner. + /// They're hidden and not supported as stable API surface outside Google. + + parser.addOption( + 'configuration', + help: 'The path to the configuration file.', + hide: true, + ); + parser.addMultiOption( + 'dart2js-args', + help: 'Extra arguments to pass to dart2js.', + hide: true, + ); + + // If we're running test/dir/my_test.dart, we'll look for + // test/dir/my_test.dart.html in the precompiled directory. + parser.addOption( + 'precompiled', + help: + 'The path to a mirror of the package directory containing HTML ' + 'that points to precompiled JS.', + hide: true, + ); + + return parser; + })(); /// The usage string for the command-line arguments. String get usage => _parser.usage; @@ -189,7 +276,9 @@ String get usage => _parser.usage; Configuration parse(List args) => _Parser(args).parse(); void _parseTestSelection( - String option, Map> selections) { + String option, + Map> selections, +) { if (Platform.isWindows) { // If given a path that starts with what looks like a drive letter, convert it // into a file scheme URI. We can't parse using `Uri.file` because we do @@ -211,18 +300,22 @@ void _parseTestSelection( ); } final selection = TestSelection( - testPatterns: fullName != null - ? {RegExp('^${RegExp.escape(fullName)}\$')} - : { - if (names != null) - for (var name in names) RegExp(name) - }, + testPatterns: + fullName != null + ? {RegExp('^${RegExp.escape(fullName)}\$')} + : { + if (names != null) + for (var name in names) RegExp(name), + }, line: line == null ? null : int.parse(line), col: col == null ? null : int.parse(col), ); - selections.update(path, (selections) => selections..add(selection), - ifAbsent: () => {selection}); + selections.update( + path, + (selections) => selections..add(selection), + ifAbsent: () => {selection}, + ); } /// A class for parsing an argument list. @@ -244,14 +337,16 @@ class _Parser { ..._readMulti('plain-name'), ]; - var includeTags = {..._readMulti('tags'), ..._readMulti('tag')} - .fold(BooleanSelector.all, (selector, tag) { + var includeTags = { + ..._readMulti('tags'), + ..._readMulti('tag'), + }.fold(BooleanSelector.all, (selector, tag) { return selector.intersection(BooleanSelector.parse(tag)); }); var excludeTags = { ..._readMulti('exclude-tags'), - ..._readMulti('exclude-tag') + ..._readMulti('exclude-tag'), }.fold(BooleanSelector.none, (selector, tag) { return selector.union(BooleanSelector.parse(tag)); }); @@ -260,39 +355,47 @@ class _Parser { var totalShards = _parseOption('total-shards', int.parse); if ((shardIndex == null) != (totalShards == null)) { throw const FormatException( - '--shard-index and --total-shards may only be passed together.'); + '--shard-index and --total-shards may only be passed together.', + ); } else if (shardIndex != null) { if (shardIndex < 0) { throw const FormatException('--shard-index may not be negative.'); } else if (shardIndex >= totalShards!) { throw const FormatException( - '--shard-index must be less than --total-shards.'); + '--shard-index must be less than --total-shards.', + ); } } var reporter = _ifParsed('reporter') as String?; - var testRandomizeOrderingSeed = - _parseOption('test-randomize-ordering-seed', (value) { - var seed = value == 'random' - ? Random().nextInt(4294967295) - : int.parse(value).toUnsigned(32); - - // TODO(#1547): Less hacky way of not breaking the json reporter - if (reporter != 'json') { - print('Shuffling test order with --test-randomize-ordering-seed=$seed'); - } + var testRandomizeOrderingSeed = _parseOption( + 'test-randomize-ordering-seed', + (value) { + var seed = + value == 'random' + ? Random().nextInt(4294967295) + : int.parse(value).toUnsigned(32); + + // TODO(#1547): Less hacky way of not breaking the json reporter + if (reporter != 'json') { + print( + 'Shuffling test order with --test-randomize-ordering-seed=$seed', + ); + } - return seed; - }); + return seed; + }, + ); var color = _ifParsed('color') ?? canUseSpecialChars; var runtimes = _ifParsed>('platform')?.map(RuntimeSelection.new).toList(); - var compilerSelections = _ifParsed>('compiler') - ?.map(CompilerSelection.parse) - .toList(); + var compilerSelections = + _ifParsed>( + 'compiler', + )?.map(CompilerSelection.parse).toList(); if (_ifParsed('use-data-isolate-strategy') == true) { compilerSelections ??= []; compilerSelections.add(CompilerSelection.parse('vm:source')); @@ -310,58 +413,60 @@ class _Parser { if (_options.wasParsed('pub-serve')) { throw ArgumentError( - 'The --pub-serve is no longer supported, if you require it please ' - 'open an issue at https://github.com/dart-lang/test/issues/new.'); + 'The --pub-serve is no longer supported, if you require it please ' + 'open an issue at https://github.com/dart-lang/test/issues/new.', + ); } return Configuration( - help: _ifParsed('help'), - version: _ifParsed('version'), - verboseTrace: _ifParsed('verbose-trace'), - chainStackTraces: _ifParsed('chain-stack-traces'), - jsTrace: _ifParsed('js-trace'), - pauseAfterLoad: _ifParsed('pause-after-load'), - debug: _ifParsed('debug'), - color: color, - configurationPath: _ifParsed('configuration'), - dart2jsArgs: _ifParsed('dart2js-args'), - precompiledPath: _ifParsed('precompiled'), - reporter: reporter, - fileReporters: _parseFileReporterOption(), - coverage: _ifParsed('coverage'), - concurrency: _parseOption('concurrency', int.parse), - shardIndex: shardIndex, - totalShards: totalShards, - timeout: _parseOption('timeout', Timeout.parse), - globalPatterns: patterns, - compilerSelections: compilerSelections, - runtimes: runtimes, - runSkipped: _ifParsed('run-skipped'), - chosenPresets: _ifParsed('preset'), - testSelections: selections, - includeTags: includeTags, - excludeTags: excludeTags, - noRetry: _ifParsed('no-retry'), - testRandomizeOrderingSeed: testRandomizeOrderingSeed, - ignoreTimeouts: _ifParsed('ignore-timeouts'), - stopOnFirstFailure: _ifParsed('fail-fast'), - // Config that isn't supported on the command line - addTags: null, - allowTestRandomization: null, - allowDuplicateTestNames: null, - customHtmlTemplatePath: null, - defineRuntimes: null, - filename: null, - foldTraceExcept: null, - foldTraceOnly: null, - onPlatform: null, - overrideRuntimes: null, - presets: null, - retry: null, - skip: null, - skipReason: null, - testOn: null, - tags: null); + help: _ifParsed('help'), + version: _ifParsed('version'), + verboseTrace: _ifParsed('verbose-trace'), + chainStackTraces: _ifParsed('chain-stack-traces'), + jsTrace: _ifParsed('js-trace'), + pauseAfterLoad: _ifParsed('pause-after-load'), + debug: _ifParsed('debug'), + color: color, + configurationPath: _ifParsed('configuration'), + dart2jsArgs: _ifParsed('dart2js-args'), + precompiledPath: _ifParsed('precompiled'), + reporter: reporter, + fileReporters: _parseFileReporterOption(), + coverage: _ifParsed('coverage'), + concurrency: _parseOption('concurrency', int.parse), + shardIndex: shardIndex, + totalShards: totalShards, + timeout: _parseOption('timeout', Timeout.parse), + globalPatterns: patterns, + compilerSelections: compilerSelections, + runtimes: runtimes, + runSkipped: _ifParsed('run-skipped'), + chosenPresets: _ifParsed('preset'), + testSelections: selections, + includeTags: includeTags, + excludeTags: excludeTags, + noRetry: _ifParsed('no-retry'), + testRandomizeOrderingSeed: testRandomizeOrderingSeed, + ignoreTimeouts: _ifParsed('ignore-timeouts'), + stopOnFirstFailure: _ifParsed('fail-fast'), + // Config that isn't supported on the command line + addTags: null, + allowTestRandomization: null, + allowDuplicateTestNames: null, + customHtmlTemplatePath: null, + defineRuntimes: null, + filename: null, + foldTraceExcept: null, + foldTraceOnly: null, + onPlatform: null, + overrideRuntimes: null, + presets: null, + retry: null, + skip: null, + skipReason: null, + testOn: null, + tags: null, + ); } /// Returns the parsed option for [name], or `null` if none was parsed. @@ -380,16 +485,20 @@ class _Parser { var value = _options[name]; if (value == null) return null; - return _wrapFormatException(value, () => parse(value as String), - optionName: name); + return _wrapFormatException( + value, + () => parse(value as String), + optionName: name, + ); } Map? _parseFileReporterOption() => _parseOption('file-reporter', (value) { if (!value.contains(':')) { throw const FormatException( - 'option must be in the form :, e.g. ' - '"json:reports/tests.json"'); + 'option must be in the form :, e.g. ' + '"json:reports/tests.json"', + ); } final sep = value.indexOf(':'); final reporter = value.substring(0, sep); @@ -401,14 +510,18 @@ class _Parser { /// Runs [parse], and wraps any [FormatException] it throws with additional /// information. - T _wrapFormatException(Object? value, T Function() parse, - {String? optionName}) { + T _wrapFormatException( + Object? value, + T Function() parse, { + String? optionName, + }) { try { return parse(); } on FormatException catch (error) { throw FormatException( - 'Couldn\'t parse ${optionName == null ? '' : '--$optionName '}"$value": ' - '${error.message}'); + 'Couldn\'t parse ${optionName == null ? '' : '--$optionName '}"$value": ' + '${error.message}', + ); } } } diff --git a/pkgs/test_core/lib/src/runner/configuration/custom_runtime.dart b/pkgs/test_core/lib/src/runner/configuration/custom_runtime.dart index d1bd0284d..2ca475bb3 100644 --- a/pkgs/test_core/lib/src/runner/configuration/custom_runtime.dart +++ b/pkgs/test_core/lib/src/runner/configuration/custom_runtime.dart @@ -29,6 +29,13 @@ final class CustomRuntime { /// The user's settings for this runtime. final YamlMap settings; - CustomRuntime(this.name, this.nameSpan, this.identifier, this.identifierSpan, - this.parent, this.parentSpan, this.settings); + CustomRuntime( + this.name, + this.nameSpan, + this.identifier, + this.identifierSpan, + this.parent, + this.parentSpan, + this.settings, + ); } diff --git a/pkgs/test_core/lib/src/runner/configuration/load.dart b/pkgs/test_core/lib/src/runner/configuration/load.dart index 9877db648..fc74fa008 100644 --- a/pkgs/test_core/lib/src/runner/configuration/load.dart +++ b/pkgs/test_core/lib/src/runner/configuration/load.dart @@ -35,8 +35,9 @@ final _identifierRegExp = RegExp(r'[a-zA-Z_]\w*'); /// This allows dot-separated valid Dart identifiers. The dots are there for /// compatibility with Google's internal Dart packages, but they may not be used /// when publishing a package to pub.dev. -final _packageName = - RegExp('^${_identifierRegExp.pattern}(\\.${_identifierRegExp.pattern})*\$'); +final _packageName = RegExp( + '^${_identifierRegExp.pattern}(\\.${_identifierRegExp.pattern})*\$', +); /// Parses configuration from YAML formatted [content]. /// @@ -54,11 +55,17 @@ Configuration parse(String content, {Uri? sourceUrl, bool global = false}) { if (document is! Map) { throw SourceSpanFormatException( - 'The configuration must be a YAML map.', document.span, content); + 'The configuration must be a YAML map.', + document.span, + content, + ); } - var loader = - _ConfigurationLoader(document as YamlMap, content, global: global); + var loader = _ConfigurationLoader( + document as YamlMap, + content, + global: global, + ); return loader.load(); } @@ -78,10 +85,13 @@ class _ConfigurationLoader { /// Whether runner configuration is allowed at this level. final bool _runnerConfig; - _ConfigurationLoader(this._document, this._source, - {bool global = false, bool runnerConfig = true}) - : _global = global, - _runnerConfig = runnerConfig; + _ConfigurationLoader( + this._document, + this._source, { + bool global = false, + bool runnerConfig = true, + }) : _global = global, + _runnerConfig = runnerConfig; /// Loads the configuration in [_document]. Configuration load() => _loadIncludeConfig() @@ -101,13 +111,18 @@ class _ConfigurationLoader { if (includeNode == null) return Configuration.empty; var includePath = _parseNode(includeNode, 'include path', p.fromUri); - var basePath = - p.join(p.dirname(p.fromUri(_document.span.sourceUrl)), includePath); + var basePath = p.join( + p.dirname(p.fromUri(_document.span.sourceUrl)), + includePath, + ); try { return Configuration.load(basePath); } on FileSystemException catch (error) { throw SourceSpanFormatException( - getErrorMessage(error), includeNode.span, _source); + getErrorMessage(error), + includeNode.span, + _source, + ); } } @@ -120,41 +135,60 @@ class _ConfigurationLoader { var timeout = _parseValue('timeout', Timeout.parse); - var onPlatform = _getMap('on_platform', - key: (keyNode) => _parseNode(keyNode, 'on_platform key', - (value) => PlatformSelector.parse(value, keyNode.span)), - value: (valueNode) => - _nestedConfig(valueNode, 'on_platform value', runnerConfig: false)); - - var onOS = _getMap('on_os', - key: (keyNode) { - _validate(keyNode, 'on_os key must be a string.', - (value) => value is String); - - var os = OperatingSystem.find(keyNode.value as String); - if (os != OperatingSystem.none) return os; + var onPlatform = _getMap( + 'on_platform', + key: + (keyNode) => _parseNode( + keyNode, + 'on_platform key', + (value) => PlatformSelector.parse(value, keyNode.span), + ), + value: + (valueNode) => _nestedConfig( + valueNode, + 'on_platform value', + runnerConfig: false, + ), + ); + + var onOS = _getMap( + 'on_os', + key: (keyNode) { + _validate( + keyNode, + 'on_os key must be a string.', + (value) => value is String, + ); - throw SourceSpanFormatException( - 'Invalid on_os key: No such operating system.', - keyNode.span, - _source); - }, - value: (valueNode) => _nestedConfig(valueNode, 'on_os value')); + var os = OperatingSystem.find(keyNode.value as String); + if (os != OperatingSystem.none) return os; - var presets = _getMap('presets', - key: (keyNode) => _parseIdentifierLike(keyNode, 'presets key'), - value: (valueNode) => _nestedConfig(valueNode, 'presets value')); + throw SourceSpanFormatException( + 'Invalid on_os key: No such operating system.', + keyNode.span, + _source, + ); + }, + value: (valueNode) => _nestedConfig(valueNode, 'on_os value'), + ); + + var presets = _getMap( + 'presets', + key: (keyNode) => _parseIdentifierLike(keyNode, 'presets key'), + value: (valueNode) => _nestedConfig(valueNode, 'presets value'), + ); var config = Configuration.globalTest( - verboseTrace: verboseTrace, - jsTrace: jsTrace, - timeout: timeout, - presets: presets, - chainStackTraces: chainStackTraces, - foldTraceExcept: foldStackFrames['except'], - foldTraceOnly: foldStackFrames['only']) - .merge(_extractPresets( - onPlatform, Configuration.onPlatform)); + verboseTrace: verboseTrace, + jsTrace: jsTrace, + timeout: timeout, + presets: presets, + chainStackTraces: chainStackTraces, + foldTraceExcept: foldStackFrames['except'], + foldTraceOnly: foldStackFrames['only'], + ).merge( + _extractPresets(onPlatform, Configuration.onPlatform), + ); var osConfig = onOS[currentOS]; return osConfig == null ? config : config.merge(osConfig); @@ -177,8 +211,11 @@ class _ConfigurationLoader { return Configuration.empty; } - var skipRaw = _getValue('skip', 'boolean or string', - (value) => (value is bool?) || value is String?); + var skipRaw = _getValue( + 'skip', + 'boolean or string', + (value) => (value is bool?) || value is String?, + ); String? skipReason; bool? skip; if (skipRaw is String) { @@ -191,13 +228,17 @@ class _ConfigurationLoader { var testOn = _parsePlatformSelector('test_on'); var addTags = _getList( - 'add_tags', (tagNode) => _parseIdentifierLike(tagNode, 'Tag name')); - - var tags = _getMap('tags', - key: (keyNode) => - _parseNode(keyNode, 'tags key', BooleanSelector.parse), - value: (valueNode) => - _nestedConfig(valueNode, 'tag value', runnerConfig: false)); + 'add_tags', + (tagNode) => _parseIdentifierLike(tagNode, 'Tag name'), + ); + + var tags = _getMap( + 'tags', + key: (keyNode) => _parseNode(keyNode, 'tags key', BooleanSelector.parse), + value: + (valueNode) => + _nestedConfig(valueNode, 'tag value', runnerConfig: false), + ); var retry = _getNonNegativeInt('retry'); @@ -206,14 +247,14 @@ class _ConfigurationLoader { var allowDuplicateTestNames = _getBool('allow_duplicate_test_names'); return Configuration.localTest( - skip: skip, - retry: retry, - skipReason: skipReason, - testOn: testOn, - addTags: addTags, - allowTestRandomization: allowTestRandomization, - allowDuplicateTestNames: allowDuplicateTestNames) - .merge(_extractPresets(tags, Configuration.tags)); + skip: skip, + retry: retry, + skipReason: skipReason, + testOn: testOn, + addTags: addTags, + allowTestRandomization: allowTestRandomization, + allowDuplicateTestNames: allowDuplicateTestNames, + ).merge(_extractPresets(tags, Configuration.tags)); } /// Loads runner configuration that's allowed in the global configuration @@ -244,19 +285,29 @@ class _ConfigurationLoader { _error('Unknown reporter "$reporter".', 'reporter'); } - var fileReporters = _getMap('file_reporters', key: (keyNode) { - _validate(keyNode, 'file_reporters key must be a string', - (value) => value is String); - final reporter = keyNode.value as String; - if (!allReporters.keys.contains(reporter)) { - _error('Unknown reporter "$reporter".', 'file_reporters'); - } - return reporter; - }, value: (valueNode) { - _validate(valueNode, 'file_reporters value must be a string', - (value) => value is String); - return valueNode.value as String; - }); + var fileReporters = _getMap( + 'file_reporters', + key: (keyNode) { + _validate( + keyNode, + 'file_reporters key must be a string', + (value) => value is String, + ); + final reporter = keyNode.value as String; + if (!allReporters.keys.contains(reporter)) { + _error('Unknown reporter "$reporter".', 'file_reporters'); + } + return reporter; + }, + value: (valueNode) { + _validate( + valueNode, + 'file_reporters value must be a string', + (value) => value is String, + ); + return valueNode.value as String; + }, + ); var concurrency = _getInt('concurrency'); @@ -265,37 +316,43 @@ class _ConfigurationLoader { // was changed to avoid conflicting with [SuitePlatform]. We decided not to // also change the UI to avoid a painful migration. var runtimes = _getList( - 'platforms', - (runtimeNode) => RuntimeSelection( - _parseIdentifierLike(runtimeNode, 'Platform name'), - runtimeNode.span)); + 'platforms', + (runtimeNode) => RuntimeSelection( + _parseIdentifierLike(runtimeNode, 'Platform name'), + runtimeNode.span, + ), + ); var compilerSelections = _getList( - 'compilers', - (node) => _parseNode( - node, - 'compiler', - (option) => - CompilerSelection.parse(option, parentSpan: node.span))); - - var chosenPresets = _getList('add_presets', - (presetNode) => _parseIdentifierLike(presetNode, 'Preset name')); + 'compilers', + (node) => _parseNode( + node, + 'compiler', + (option) => CompilerSelection.parse(option, parentSpan: node.span), + ), + ); + + var chosenPresets = _getList( + 'add_presets', + (presetNode) => _parseIdentifierLike(presetNode, 'Preset name'), + ); var overrideRuntimes = _loadOverrideRuntimes(); var customHtmlTemplatePath = _getString('custom_html_template_path'); return Configuration.globalRunner( - pauseAfterLoad: pauseAfterLoad, - customHtmlTemplatePath: customHtmlTemplatePath, - runSkipped: runSkipped, - reporter: reporter, - fileReporters: fileReporters, - concurrency: concurrency, - compilerSelections: compilerSelections, - runtimes: runtimes, - chosenPresets: chosenPresets, - overrideRuntimes: overrideRuntimes); + pauseAfterLoad: pauseAfterLoad, + customHtmlTemplatePath: customHtmlTemplatePath, + runSkipped: runSkipped, + reporter: reporter, + fileReporters: fileReporters, + concurrency: concurrency, + compilerSelections: compilerSelections, + runtimes: runtimes, + chosenPresets: chosenPresets, + overrideRuntimes: overrideRuntimes, + ); } /// Loads the `override_platforms` field. @@ -310,15 +367,19 @@ class _ConfigurationLoader { var yamlNode = identifierNode as YamlNode; var identifier = _parseIdentifierLike(yamlNode, 'Platform identifier'); - _validate(valueNode, 'Platform definition must be a map.', - (value) => value is Map); + _validate( + valueNode, + 'Platform definition must be a map.', + (value) => value is Map, + ); var map = valueNode as YamlMap; var settings = _expect(map, 'settings'); _validate(settings, 'Must be a map.', (value) => value is Map); - runtimes[identifier] = - RuntimeSettings(identifier, yamlNode.span, [settings as YamlMap]); + runtimes[identifier] = RuntimeSettings(identifier, yamlNode.span, [ + settings as YamlMap, + ]); }); return runtimes; } @@ -343,17 +404,24 @@ class _ConfigurationLoader { var patterns = _getList('names', (nameNode) { _validate(nameNode, 'Names must be strings.', (value) => value is String); return _parseNode(nameNode, 'name', RegExp.new); - }) - ..addAll(_getList('plain_names', (nameNode) { + })..addAll( + _getList('plain_names', (nameNode) { _validate( - nameNode, 'Names must be strings.', (value) => value is String); + nameNode, + 'Names must be strings.', + (value) => value is String, + ); return _parseNode(nameNode, 'name', RegExp.new); - })); + }), + ); var paths = _getList('paths', (pathNode) { _validate(pathNode, 'Paths must be strings.', (value) => value is String); - _validate(pathNode, 'Paths must be relative.', - (value) => p.url.isRelative(value as String)); + _validate( + pathNode, + 'Paths must be relative.', + (value) => p.url.isRelative(value as String), + ); return _parseNode(pathNode, 'path', p.fromUri); }); @@ -365,14 +433,15 @@ class _ConfigurationLoader { var defineRuntimes = _loadDefineRuntimes(); return Configuration.localRunner( - globalPatterns: patterns, - testSelections: { - for (var path in paths) path: const {TestSelection()} - }, - filename: filename, - includeTags: includeTags, - excludeTags: excludeTags, - defineRuntimes: defineRuntimes); + globalPatterns: patterns, + testSelections: { + for (var path in paths) path: const {TestSelection()}, + }, + filename: filename, + includeTags: includeTags, + excludeTags: excludeTags, + defineRuntimes: defineRuntimes, + ); } /// Returns a map representation of the `fold_stack_frames` configuration. @@ -382,35 +451,46 @@ class _ConfigurationLoader { /// test [Chain]. Map> _loadFoldedStackFrames() { var foldOptionSet = false; - return _getMap('fold_stack_frames', key: (keyNode) { - _validate(keyNode, 'Must be a string', (value) => value is String); - _validate(keyNode, 'Must be "only" or "except".', - (value) => value == 'only' || value == 'except'); + return _getMap( + 'fold_stack_frames', + key: (keyNode) { + _validate(keyNode, 'Must be a string', (value) => value is String); + _validate( + keyNode, + 'Must be "only" or "except".', + (value) => value == 'only' || value == 'except', + ); - if (foldOptionSet) { - throw SourceSpanFormatException( + if (foldOptionSet) { + throw SourceSpanFormatException( 'Can only contain one of "only" or "except".', keyNode.span, - _source); - } - foldOptionSet = true; - return keyNode.value as String; - }, value: (valueNode) { - _validate( + _source, + ); + } + foldOptionSet = true; + return keyNode.value as String; + }, + value: (valueNode) { + _validate( valueNode, 'Folded packages must be strings.', (valueList) => valueList is YamlList && - valueList.every((value) => value is String)); + valueList.every((value) => value is String), + ); - _validate( + _validate( valueNode, 'Invalid package name.', - (valueList) => (valueList as Iterable) - .every((value) => _packageName.hasMatch(value as String))); - - return List.from(valueNode.value as Iterable); - }); + (valueList) => (valueList as Iterable).every( + (value) => _packageName.hasMatch(value as String), + ), + ); + + return List.from(valueNode.value as Iterable); + }, + ); } /// Loads the `define_platforms` field. @@ -425,8 +505,11 @@ class _ConfigurationLoader { var yamlNode = identifierNode as YamlNode; var identifier = _parseIdentifierLike(yamlNode, 'Platform identifier'); - _validate(valueNode, 'Platform definition must be a map.', - (value) => value is Map); + _validate( + valueNode, + 'Platform definition must be a map.', + (value) => value is Map, + ); var map = valueNode as YamlMap; var nameNode = _expect(map, 'name'); @@ -439,8 +522,15 @@ class _ConfigurationLoader { var settings = _expect(map, 'settings'); _validate(settings, 'Must be a map.', (value) => value is Map); - runtimes[identifier] = CustomRuntime(name, nameNode.span, identifier, - yamlNode.span, parent, parentNode.span, settings as YamlMap); + runtimes[identifier] = CustomRuntime( + name, + nameNode.span, + identifier, + yamlNode.span, + parent, + parentNode.span, + settings as YamlMap, + ); }); return runtimes; } @@ -457,7 +547,10 @@ class _ConfigurationLoader { /// If [typeTest] returns `false` for that value, instead throws an error /// complaining that the field is not a [typeName]. Object? _getValue( - String field, String typeName, bool Function(dynamic) typeTest) { + String field, + String typeName, + bool Function(dynamic) typeTest, + ) { var value = _document[field]; if (value == null || typeTest(value)) return value; _error('$field must be ${a(typeName)}.', field); @@ -470,7 +563,10 @@ class _ConfigurationLoader { /// /// Returns `null` if [field] does not have a node in [_document]. YamlNode? _getNode( - String field, String typeName, bool Function(dynamic) typeTest) { + String field, + String typeName, + bool Function(dynamic) typeTest, + ) { var node = _document.nodes[field]; if (node == null) return null; _validate(node, '$field must be ${a(typeName)}.', typeTest); @@ -484,9 +580,10 @@ class _ConfigurationLoader { /// Asserts that [field] is a non-negative int and returns its value. int? _getNonNegativeInt(String field) => _getValue(field, 'non-negative int', (value) { - if (value == null) return true; - return value is int && value >= 0; - }) as int?; + if (value == null) return true; + return value is int && value >= 0; + }) + as int?; /// Asserts that [field] is a boolean and returns its value. bool? _getBool(String field) => @@ -510,35 +607,49 @@ class _ConfigurationLoader { /// /// Returns a map with the keys and values returned by [key] and [value]. Each /// of these defaults to asserting that the value is a string. - Map _getMap(String field, - {K Function(YamlNode)? key, V Function(YamlNode)? value}) { + Map _getMap( + String field, { + K Function(YamlNode)? key, + V Function(YamlNode)? value, + }) { var node = _getNode(field, 'map', (value) => value is Map) as YamlMap?; if (node == null) return {}; key ??= (keyNode) { _validate( - keyNode, '$field keys must be strings.', (value) => value is String); + keyNode, + '$field keys must be strings.', + (value) => value is String, + ); return keyNode.value as K; }; value ??= (valueNode) { - _validate(valueNode, '$field values must be strings.', - (value) => value is String); + _validate( + valueNode, + '$field values must be strings.', + (value) => value is String, + ); return valueNode.value as V; }; - return node.nodes.map((keyNode, valueNode) => - MapEntry(key!(keyNode as YamlNode), value!(valueNode))); + return node.nodes.map( + (keyNode, valueNode) => + MapEntry(key!(keyNode as YamlNode), value!(valueNode)), + ); } /// Verifies that [node]'s value is an optionally hyphenated Dart identifier, /// and returns it String _parseIdentifierLike(YamlNode node, String name) { _validate(node, '$name must be a string.', (value) => value is String); - _validate(node, '$name must be an (optionally hyphenated) Dart identifier.', - (value) => (value as String).contains(anchoredHyphenatedIdentifier)); + _validate( + node, + '$name must be an (optionally hyphenated) Dart identifier.', + (value) => (value as String).contains(anchoredHyphenatedIdentifier), + ); return node.value as String; } @@ -551,7 +662,10 @@ class _ConfigurationLoader { var node = _document.nodes[field]; if (node == null) return null; return _parseNode( - node, field, (value) => PlatformSelector.parse(value, node.span)); + node, + field, + (value) => PlatformSelector.parse(value, node.span), + ); } /// Asserts that [node] is a string, passes its value to [parse], and returns @@ -566,7 +680,10 @@ class _ConfigurationLoader { return parse(node.value as String); } on FormatException catch (error) { throw SourceSpanFormatException( - 'Invalid $name: ${error.message}', node.span, _source); + 'Invalid $name: ${error.message}', + node.span, + _source, + ); } } @@ -586,13 +703,20 @@ class _ConfigurationLoader { /// [name] is the name of the field, which is used for error-handling. /// [runnerConfig] controls whether runner configuration is allowed in the /// nested configuration. It defaults to [_runnerConfig]. - Configuration _nestedConfig(YamlNode? node, String name, - {bool? runnerConfig}) { + Configuration _nestedConfig( + YamlNode? node, + String name, { + bool? runnerConfig, + }) { if (node == null || node.value == null) return Configuration.empty; _validate(node, '$name must be a map.', (value) => value is Map); - var loader = _ConfigurationLoader(node as YamlMap, _source, - global: _global, runnerConfig: runnerConfig ?? _runnerConfig); + var loader = _ConfigurationLoader( + node as YamlMap, + _source, + global: _global, + runnerConfig: runnerConfig ?? _runnerConfig, + ); return loader.load(); } @@ -605,8 +729,10 @@ class _ConfigurationLoader { /// logic into a parent [Configuration], leaving only maps to /// [SuiteConfiguration]s. The [create] function is used to construct /// [Configuration]s from the resolved maps. - Configuration _extractPresets(Map map, - Configuration Function(Map) create) { + Configuration _extractPresets( + Map map, + Configuration Function(Map) create, + ) { if (map.isEmpty) return Configuration.empty; var base = {}; @@ -632,7 +758,10 @@ class _ConfigurationLoader { if (node != null) return node; throw SourceSpanFormatException( - 'Missing required field "$field".', map.span, _source); + 'Missing required field "$field".', + map.span, + _source, + ); } /// Throws an error if a field named [field] exists at this level. @@ -640,17 +769,20 @@ class _ConfigurationLoader { if (!_document.containsKey(field)) return; throw SourceSpanFormatException( - "$field isn't supported here.", - // We need the key as a [YamlNode] to get its span. - (_document.nodes.keys.firstWhere((key) => key.value == field) - as YamlNode) - .span, - _source); + "$field isn't supported here.", + // We need the key as a [YamlNode] to get its span. + (_document.nodes.keys.firstWhere((key) => key.value == field) as YamlNode) + .span, + _source, + ); } /// Throws a [SourceSpanFormatException] with [message] about [field]. Never _error(String message, String field) { throw SourceSpanFormatException( - message, _document.nodes[field]!.span, _source); + message, + _document.nodes[field]!.span, + _source, + ); } } diff --git a/pkgs/test_core/lib/src/runner/configuration/reporters.dart b/pkgs/test_core/lib/src/runner/configuration/reporters.dart index cc1aadf32..35768ce84 100644 --- a/pkgs/test_core/lib/src/runner/configuration/reporters.dart +++ b/pkgs/test_core/lib/src/runner/configuration/reporters.dart @@ -32,55 +32,82 @@ final UnmodifiableMapView allReporters = final _allReporters = { 'compact': ReporterDetails( - 'A single line, updated continuously.', - (config, engine, sink) => CompactReporter.watch(engine, sink, - color: config.color, - printPath: config.testSelections.length > 1 || - Directory(config.testSelections.keys.single).existsSync(), - printPlatform: config.suiteDefaults.runtimes.length > 1 || - config.suiteDefaults.compilerSelections != null)), + 'A single line, updated continuously.', + (config, engine, sink) => CompactReporter.watch( + engine, + sink, + color: config.color, + printPath: + config.testSelections.length > 1 || + Directory(config.testSelections.keys.single).existsSync(), + printPlatform: + config.suiteDefaults.runtimes.length > 1 || + config.suiteDefaults.compilerSelections != null, + ), + ), 'expanded': ReporterDetails( - 'A separate line for each update.', - (config, engine, sink) => ExpandedReporter.watch(engine, sink, - color: config.color, - printPath: config.testSelections.length > 1 || - Directory(config.testSelections.keys.single).existsSync(), - printPlatform: config.suiteDefaults.runtimes.length > 1 || - config.suiteDefaults.compilerSelections != null)), + 'A separate line for each update.', + (config, engine, sink) => ExpandedReporter.watch( + engine, + sink, + color: config.color, + printPath: + config.testSelections.length > 1 || + Directory(config.testSelections.keys.single).existsSync(), + printPlatform: + config.suiteDefaults.runtimes.length > 1 || + config.suiteDefaults.compilerSelections != null, + ), + ), 'failures-only': ReporterDetails( - 'A separate line for failing tests with no output for passing tests', - (config, engine, sink) => FailuresOnlyReporter.watch(engine, sink, - color: config.color, - printPath: config.testSelections.length > 1 || - Directory(config.testSelections.keys.single).existsSync(), - printPlatform: config.suiteDefaults.runtimes.length > 1 || - config.suiteDefaults.compilerSelections != null)), + 'A separate line for failing tests with no output for passing tests', + (config, engine, sink) => FailuresOnlyReporter.watch( + engine, + sink, + color: config.color, + printPath: + config.testSelections.length > 1 || + Directory(config.testSelections.keys.single).existsSync(), + printPlatform: + config.suiteDefaults.runtimes.length > 1 || + config.suiteDefaults.compilerSelections != null, + ), + ), 'github': ReporterDetails( - 'A custom reporter for GitHub Actions ' - '(the default reporter when running on GitHub Actions).', - (config, engine, sink) => GithubReporter.watch(engine, sink, - printPath: config.testSelections.length > 1 || - Directory(config.testSelections.keys.single).existsSync(), - printPlatform: config.suiteDefaults.runtimes.length > 1 || - config.suiteDefaults.compilerSelections != null)), + 'A custom reporter for GitHub Actions ' + '(the default reporter when running on GitHub Actions).', + (config, engine, sink) => GithubReporter.watch( + engine, + sink, + printPath: + config.testSelections.length > 1 || + Directory(config.testSelections.keys.single).existsSync(), + printPlatform: + config.suiteDefaults.runtimes.length > 1 || + config.suiteDefaults.compilerSelections != null, + ), + ), 'json': ReporterDetails( - 'A machine-readable format (see ' - 'https://dart.dev/go/test-docs/json_reporter.md).', - (config, engine, sink) => - JsonReporter.watch(engine, sink, isDebugRun: config.debug)), + 'A machine-readable format (see ' + 'https://dart.dev/go/test-docs/json_reporter.md).', + (config, engine, sink) => + JsonReporter.watch(engine, sink, isDebugRun: config.debug), + ), 'silent': ReporterDetails( - 'A reporter with no output. ' - 'May be useful when only the exit code is meaningful.', - (config, engine, sink) => SilentReporter()), + 'A reporter with no output. ' + 'May be useful when only the exit code is meaningful.', + (config, engine, sink) => SilentReporter(), + ), }; -final defaultReporter = inTestTests - ? 'expanded' - : inGithubContext +final defaultReporter = + inTestTests + ? 'expanded' + : inGithubContext ? 'github' : canUseSpecialChars - ? 'compact' - : 'expanded'; + ? 'compact' + : 'expanded'; /// **Do not call this function without express permission from the test package /// authors**. diff --git a/pkgs/test_core/lib/src/runner/configuration/runtime_settings.dart b/pkgs/test_core/lib/src/runner/configuration/runtime_settings.dart index e366b4da5..aaa2a4d4f 100644 --- a/pkgs/test_core/lib/src/runner/configuration/runtime_settings.dart +++ b/pkgs/test_core/lib/src/runner/configuration/runtime_settings.dart @@ -22,5 +22,5 @@ final class RuntimeSettings { final List settings; RuntimeSettings(this.identifier, this.identifierSpan, List settings) - : settings = List.unmodifiable(settings); + : settings = List.unmodifiable(settings); } diff --git a/pkgs/test_core/lib/src/runner/configuration/utils.dart b/pkgs/test_core/lib/src/runner/configuration/utils.dart index d47526ca9..d14dbbe7b 100644 --- a/pkgs/test_core/lib/src/runner/configuration/utils.dart +++ b/pkgs/test_core/lib/src/runner/configuration/utils.dart @@ -8,8 +8,11 @@ import 'package:collection/collection.dart'; /// creating a new map unnecessarily. /// /// The return value *may or may not* be unmodifiable. -Map mergeUnmodifiableMaps(Map map1, Map map2, - {V Function(V, V)? value}) { +Map mergeUnmodifiableMaps( + Map map1, + Map map2, { + V Function(V, V)? value, +}) { if (map1.isEmpty) return map2; if (map2.isEmpty) return map1; return mergeMaps(map1, map2, value: value); diff --git a/pkgs/test_core/lib/src/runner/console.dart b/pkgs/test_core/lib/src/runner/console.dart index 3a4d6facf..469489d7e 100644 --- a/pkgs/test_core/lib/src/runner/console.dart +++ b/pkgs/test_core/lib/src/runner/console.dart @@ -37,9 +37,9 @@ class Console { /// /// If [color] is true, this uses Unix terminal colors. Console({bool color = true}) - : _red = color ? '\u001b[31m' : '', - _bold = color ? '\u001b[1m' : '', - _noColor = color ? '\u001b[0m' : '' { + : _red = color ? '\u001b[31m' : '', + _bold = color ? '\u001b[1m' : '', + _noColor = color ? '\u001b[0m' : '' { registerCommand('help', 'Displays this help information.', _displayHelp); } @@ -49,7 +49,10 @@ class Console { /// in the help output. The [body] callback will be called when the user types /// the command. void registerCommand( - String name, String description, FutureOr Function() body) { + String name, + String description, + FutureOr Function() body, + ) { if (_commands.containsKey(name)) { throw ArgumentError('The console already has a command named "$name".'); } @@ -72,8 +75,9 @@ class Console { var command = _commands[commandName]; if (command == null) { stderr.writeln( - '${_red}Unknown command $_bold$commandName$_noColor$_red.' - '$_noColor'); + '${_red}Unknown command $_bold$commandName$_noColor$_red.' + '$_noColor', + ); } else { await command.body(); } @@ -92,8 +96,9 @@ class Console { /// Displays the help info for the console commands. void _displayHelp() { - var maxCommandLength = - _commands.values.map((command) => command.name.length).reduce(math.max); + var maxCommandLength = _commands.values + .map((command) => command.name.length) + .reduce(math.max); for (var command in _commands.values) { var name = command.name.padRight(maxCommandLength + 4); @@ -102,8 +107,5 @@ class Console { } } -typedef _Command = ({ - String name, - String description, - FutureOr Function() body, -}); +typedef _Command = + ({String name, String description, FutureOr Function() body}); diff --git a/pkgs/test_core/lib/src/runner/coverage.dart b/pkgs/test_core/lib/src/runner/coverage.dart index 841bdd72f..fd6086f5b 100644 --- a/pkgs/test_core/lib/src/runner/coverage.dart +++ b/pkgs/test_core/lib/src/runner/coverage.dart @@ -11,12 +11,17 @@ import 'live_suite_controller.dart'; /// Collects coverage and outputs to the [coveragePath] path. Future writeCoverage( - String coveragePath, LiveSuiteController controller) async { + String coveragePath, + LiveSuiteController controller, +) async { var suite = controller.liveSuite.suite; var coverage = await controller.liveSuite.suite.gatherCoverage(); - final outfile = File(p.join(coveragePath, - '${suite.path}.${suite.platform.runtime.name.toLowerCase()}.json')) - ..createSync(recursive: true); + final outfile = File( + p.join( + coveragePath, + '${suite.path}.${suite.platform.runtime.name.toLowerCase()}.json', + ), + )..createSync(recursive: true); final out = outfile.openWrite(); out.write(json.encode(coverage)); await out.flush(); diff --git a/pkgs/test_core/lib/src/runner/coverage_stub.dart b/pkgs/test_core/lib/src/runner/coverage_stub.dart index 64f69c75e..a9b82cbf5 100644 --- a/pkgs/test_core/lib/src/runner/coverage_stub.dart +++ b/pkgs/test_core/lib/src/runner/coverage_stub.dart @@ -5,6 +5,9 @@ import 'live_suite_controller.dart'; Future writeCoverage( - String coveragePath, LiveSuiteController controller) => + String coveragePath, + LiveSuiteController controller, +) => throw UnsupportedError( - 'Coverage is only supported through the test runner.'); + 'Coverage is only supported through the test runner.', + ); diff --git a/pkgs/test_core/lib/src/runner/dart2js_compiler_pool.dart b/pkgs/test_core/lib/src/runner/dart2js_compiler_pool.dart index a13a65aed..5bea2ee39 100644 --- a/pkgs/test_core/lib/src/runner/dart2js_compiler_pool.dart +++ b/pkgs/test_core/lib/src/runner/dart2js_compiler_pool.dart @@ -14,8 +14,9 @@ import 'compiler_pool.dart'; import 'suite.dart'; /// A regular expression matching the first status line printed by dart2js. -final _dart2jsStatus = - RegExp(r'^Dart file \(.*\) compiled to JavaScript: .*\n?'); +final _dart2jsStatus = RegExp( + r'^Dart file \(.*\) compiled to JavaScript: .*\n?', +); /// A pool of `dart2js` instances. /// @@ -29,7 +30,7 @@ class Dart2JsCompilerPool extends CompilerPool { /// Creates a compiler pool that multiple instances of `dart2js` at once. Dart2JsCompilerPool([Iterable? extraArgs]) - : _extraArgs = extraArgs?.toList() ?? const []; + : _extraArgs = extraArgs?.toList() ?? const []; /// Compiles [code] to [path]. /// @@ -39,7 +40,10 @@ class Dart2JsCompilerPool extends CompilerPool { /// *and* all its output has been printed to the command line. @override Future compileInternal( - String code, String path, SuiteConfiguration suiteConfig) { + String code, + String path, + SuiteConfiguration suiteConfig, + ) { return withTempDir((dir) async { var wrapperPath = p.join(dir, 'runInBrowser.dart'); File(wrapperPath).writeAsStringSync(code); @@ -55,7 +59,7 @@ class Dart2JsCompilerPool extends CompilerPool { '--packages=${await packageConfigUri}', '--disable-program-split', ..._extraArgs, - ...suiteConfig.dart2jsArgs + ...suiteConfig.dart2jsArgs, ]; if (config.color) args.add('--enable-diagnostic-colors'); @@ -101,16 +105,16 @@ class Dart2JsCompilerPool extends CompilerPool { final mapUri = p.toUri(mapPath); map.cast>().update( - 'sources', - (sources) => [ - for (var source in sources) - switch (Uri.parse('$root$source')) { - Uri(hasScheme: true) && final uri => uri.toString(), - Uri(:final path) when path.endsWith('/runInBrowser.dart') => '', - final uri => mapUri.resolveUri(uri).toString(), - } - ], - ); + 'sources', + (sources) => [ + for (var source in sources) + switch (Uri.parse('$root$source')) { + Uri(hasScheme: true) && final uri => uri.toString(), + Uri(:final path) when path.endsWith('/runInBrowser.dart') => '', + final uri => mapUri.resolveUri(uri).toString(), + }, + ], + ); File(mapPath).writeAsStringSync(jsonEncode(map)); } @@ -122,9 +126,11 @@ class Dart2JsCompilerPool extends CompilerPool { /// have been killed and all resources released. @override Future closeInternal() async { - await Future.wait(_processes.map((process) async { - process.kill(); - await process.exitCode; - })); + await Future.wait( + _processes.map((process) async { + process.kill(); + await process.exitCode; + }), + ); } } diff --git a/pkgs/test_core/lib/src/runner/debugger.dart b/pkgs/test_core/lib/src/runner/debugger.dart index 5e59d882a..225f4e6e6 100644 --- a/pkgs/test_core/lib/src/runner/debugger.dart +++ b/pkgs/test_core/lib/src/runner/debugger.dart @@ -25,25 +25,33 @@ import 'runner_suite.dart'; /// finished running. If the operation is canceled, the debugger will clean up /// any resources it allocated. CancelableOperation debug( - Engine engine, Reporter reporter, LoadSuite loadSuite) { + Engine engine, + Reporter reporter, + LoadSuite loadSuite, +) { _Debugger? debugger; var canceled = false; - return CancelableOperation.fromFuture(() async { - engine.suiteSink.add(loadSuite.changeSuite((runnerSuite) { - engine.pause(); - return runnerSuite; - })); - - var suite = await loadSuite.suite; - if (canceled || suite == null) return; - - await (debugger = _Debugger(engine, reporter, suite)).run(); - }(), onCancel: () { - canceled = true; - // Make sure the load test finishes so the engine can close. - engine.resume(); - debugger?.close(); - }); + return CancelableOperation.fromFuture( + () async { + engine.suiteSink.add( + loadSuite.changeSuite((runnerSuite) { + engine.pause(); + return runnerSuite; + }), + ); + + var suite = await loadSuite.suite; + if (canceled || suite == null) return; + + await (debugger = _Debugger(engine, reporter, suite)).run(); + }(), + onCancel: () { + canceled = true; + // Make sure the load test finishes so the engine can close. + engine.resume(); + debugger?.close(); + }, + ); } // TODO(nweiz): Test using the console and restarting a test once sdk#25369 is @@ -84,9 +92,12 @@ class _Debugger { bool get _json => _config.reporter == 'json'; _Debugger(this._engine, this._reporter, this._suite) - : _console = Console(color: Configuration.current.color) { - _console.registerCommand('restart', - 'Restart the current test after it finishes running.', _restartTest); + : _console = Console(color: Configuration.current.color) { + _console.registerCommand( + 'restart', + 'Restart the current test after it finishes running.', + _restartTest, + ); _onRestartSubscription = _suite.environment.onRestart.listen((_) { _restartTest(); @@ -161,8 +172,10 @@ class _Debugger { } } - buffer.write("and set breakpoints. Once you're finished, return to " - 'this terminal and press Enter.'); + buffer.write( + "and set breakpoints. Once you're finished, return to " + 'this terminal and press Enter.', + ); print(wordWrap(buffer.toString())); } @@ -170,7 +183,7 @@ class _Debugger { await inCompletionOrder([ _suite.environment.displayPause(), stdinLines.cancelable((queue) => queue.next), - _pauseCompleter.operation + _pauseCompleter.operation, ]).first; } finally { if (!_json) _reporter.resume(); @@ -203,8 +216,11 @@ class _Debugger { var liveTest = _engine.active.single; _engine.restartTest(liveTest); if (!_json) { - print(wordWrap( - 'Will restart "${liveTest.test.name}" once it finishes running.')); + print( + wordWrap( + 'Will restart "${liveTest.test.name}" once it finishes running.', + ), + ); } } diff --git a/pkgs/test_core/lib/src/runner/engine.dart b/pkgs/test_core/lib/src/runner/engine.dart index 4404d1c5c..fa13a2fa4 100644 --- a/pkgs/test_core/lib/src/runner/engine.dart +++ b/pkgs/test_core/lib/src/runner/engine.dart @@ -94,9 +94,11 @@ class Engine { Future get success async { await Future.wait([_group.future, _runPool.done], eagerError: true); if (_closedBeforeDone!) return null; - return liveTests.every((liveTest) => - liveTest.state.result.isPassing && - liveTest.state.status == Status.complete); + return liveTests.every( + (liveTest) => + liveTest.state.result.isPassing && + liveTest.state.status == Status.complete, + ); } /// A group of futures for each test suite. @@ -150,9 +152,12 @@ class Engine { /// [skipped], [failed], and [active]. /// /// [LiveTest.run] must not be called on these tests. - Set get liveTests => - UnionSet.from([passed, skipped, failed, IterableSet(active)], - disjoint: true); + Set get liveTests => UnionSet.from([ + passed, + skipped, + failed, + IterableSet(active), + ], disjoint: true); /// A stream that emits each [LiveTest] as it's about to start running. /// @@ -213,16 +218,18 @@ class Engine { String? coverage, this.testRandomizeOrderingSeed, bool stopOnFirstFailure = false, - }) : _runPool = Pool(concurrency ?? 1), - _stopOnFirstFailure = stopOnFirstFailure, - _coverage = coverage { - _group.future.then((_) { - _onTestStartedGroup.close(); - _onSuiteStartedController.close(); - _closedBeforeDone ??= false; - }).onError((_, __) { - // Don't top-level errors. They'll be thrown via [success] anyway. - }); + }) : _runPool = Pool(concurrency ?? 1), + _stopOnFirstFailure = stopOnFirstFailure, + _coverage = coverage { + _group.future + .then((_) { + _onTestStartedGroup.close(); + _onSuiteStartedController.close(); + _closedBeforeDone ??= false; + }) + .onError((_, __) { + // Don't top-level errors. They'll be thrown via [success] anyway. + }); } /// Creates an [Engine] that will run all tests in [suites]. @@ -232,8 +239,12 @@ class Engine { /// /// [concurrency] controls how many suites are run at once. If [runSkipped] is /// `true`, skipped tests will be run as though they weren't skipped. - factory Engine.withSuites(List suites, - {int? concurrency, String? coverage, bool stopOnFirstFailure = false}) { + factory Engine.withSuites( + List suites, { + int? concurrency, + String? coverage, + bool stopOnFirstFailure = false, + }) { var engine = Engine( concurrency: concurrency, coverage: coverage, @@ -305,16 +316,21 @@ class Engine { /// [parents] is a list of groups that contain [group]. It may be modified, /// but it's guaranteed to be in its original state once this function has /// finished. - Future _runGroup(LiveSuiteController suiteController, Group group, - List parents) async { + Future _runGroup( + LiveSuiteController suiteController, + Group group, + List parents, + ) async { parents.add(group); try { var suiteConfig = suiteController.liveSuite.suite.config; var skipGroup = !suiteConfig.runSkipped && group.metadata.skip; var setUpAllSucceeded = true; if (!skipGroup && group.setUpAll != null) { - var liveTest = group.setUpAll! - .load(suiteController.liveSuite.suite, groups: parents); + var liveTest = group.setUpAll!.load( + suiteController.liveSuite.suite, + groups: parents, + ); await _runLiveTest(suiteController, liveTest, countSuccess: false); setUpAllSucceeded = liveTest.state.result.isPassing; } @@ -337,8 +353,10 @@ class Engine { await _runSkippedTest(suiteController, entry as Test, parents); } else { var test = entry as Test; - await _runLiveTest(suiteController, - test.load(suiteController.liveSuite.suite, groups: parents)); + await _runLiveTest( + suiteController, + test.load(suiteController.liveSuite.suite, groups: parents), + ); } } } @@ -346,8 +364,10 @@ class Engine { // Even if we're closed or setUpAll failed, we want to run all the // teardowns to ensure that any state is properly cleaned up. if (!skipGroup && group.tearDownAll != null) { - var liveTest = group.tearDownAll! - .load(suiteController.liveSuite.suite, groups: parents); + var liveTest = group.tearDownAll!.load( + suiteController.liveSuite.suite, + groups: parents, + ); await _runLiveTest(suiteController, liveTest, countSuccess: false); if (_closed) await liveTest.close(); } @@ -360,8 +380,11 @@ class Engine { /// /// If [countSuccess] is `true` (the default), the test is put into [passed] /// if it succeeds. Otherwise, it's removed from [liveTests] entirely. - Future _runLiveTest(LiveSuiteController suiteController, LiveTest liveTest, - {bool countSuccess = true}) async { + Future _runLiveTest( + LiveSuiteController suiteController, + LiveTest liveTest, { + bool countSuccess = true, + }) async { await _onUnpaused; _active.add(liveTest); @@ -392,8 +415,11 @@ class Engine { } return; } - await _runLiveTest(suiteController, liveTest.copy(), - countSuccess: countSuccess); + await _runLiveTest( + suiteController, + liveTest.copy(), + countSuccess: countSuccess, + ); _restarted.remove(liveTest); } @@ -401,26 +427,40 @@ class Engine { /// /// [suiteController] is the controller for the suite that contains [test]. /// [parents] is a list of groups that contain [test]. - Future _runSkippedTest(LiveSuiteController suiteController, Test test, - List parents) async { + Future _runSkippedTest( + LiveSuiteController suiteController, + Test test, + List parents, + ) async { await _onUnpaused; - var skipped = LocalTest(test.name, test.metadata, () {}, - trace: test.trace, location: test.location); + var skipped = LocalTest( + test.name, + test.metadata, + () {}, + trace: test.trace, + location: test.location, + ); late LiveTestController controller; - controller = - LiveTestController(suiteController.liveSuite.suite, skipped, () { - controller.setState(const State(Status.running, Result.success)); - controller.setState(const State(Status.running, Result.skipped)); - - if (skipped.metadata.skipReason != null) { - controller - .message(Message.skip('Skip: ${skipped.metadata.skipReason}')); - } + controller = LiveTestController( + suiteController.liveSuite.suite, + skipped, + () { + controller.setState(const State(Status.running, Result.success)); + controller.setState(const State(Status.running, Result.skipped)); + + if (skipped.metadata.skipReason != null) { + controller.message( + Message.skip('Skip: ${skipped.metadata.skipReason}'), + ); + } - controller.setState(const State(Status.complete, Result.skipped)); - controller.completer.complete(); - }, () {}, groups: parents); + controller.setState(const State(Status.complete, Result.skipped)); + controller.completer.complete(); + }, + () {}, + groups: parents, + ); return await _runLiveTest(suiteController, controller); } @@ -435,8 +475,10 @@ class Engine { } if (!_active.contains(liveTest)) { - throw StateError("Can't restart inactive test " - '"${liveTest.test.name}".'); + throw StateError( + "Can't restart inactive test " + '"${liveTest.test.name}".', + ); } _restarted.add(liveTest); @@ -476,14 +518,16 @@ class Engine { if (innerSuite == null) return null; var innerController = LiveSuiteController(innerSuite); - unawaited(innerController.liveSuite.onClose.whenComplete(() { - // When the main suite is closed, close the load suite and its test as - // well. This doesn't release any resources, but it does close streams - // which indicates that the load test won't experience an error in the - // future. - liveTest.close(); - controller.close(); - })); + unawaited( + innerController.liveSuite.onClose.whenComplete(() { + // When the main suite is closed, close the load suite and its test as + // well. This doesn't release any resources, but it does close streams + // which indicates that the load test won't experience an error in the + // future. + liveTest.close(); + controller.close(); + }), + ); return innerController; } diff --git a/pkgs/test_core/lib/src/runner/environment.dart b/pkgs/test_core/lib/src/runner/environment.dart index 7fcba66eb..d158a3085 100644 --- a/pkgs/test_core/lib/src/runner/environment.dart +++ b/pkgs/test_core/lib/src/runner/environment.dart @@ -50,6 +50,8 @@ class PluginEnvironment implements Environment { Uri? get remoteDebuggerUrl => null; @override - CancelableOperation displayPause() => throw UnsupportedError( - 'PluginEnvironment.displayPause is not supported.'); + CancelableOperation displayPause() => + throw UnsupportedError( + 'PluginEnvironment.displayPause is not supported.', + ); } diff --git a/pkgs/test_core/lib/src/runner/hack_register_platform.dart b/pkgs/test_core/lib/src/runner/hack_register_platform.dart index f5a618da3..d628a11ab 100644 --- a/pkgs/test_core/lib/src/runner/hack_register_platform.dart +++ b/pkgs/test_core/lib/src/runner/hack_register_platform.dart @@ -13,7 +13,8 @@ import 'platform.dart'; /// **Do not access this outside the test package**. final platformCallbacks = UnmodifiableMapView Function()>( - _platformCallbacks); + _platformCallbacks, + ); final _platformCallbacks = Function()>{}; /// **Do not call this function without express permission from the test package @@ -29,7 +30,9 @@ final _platformCallbacks = Function()>{}; /// /// This overwrites the default plugins for those runtimes. void registerPlatformPlugin( - Iterable runtimes, FutureOr Function() plugin) { + Iterable runtimes, + FutureOr Function() plugin, +) { for (var runtime in runtimes) { _platformCallbacks[runtime] = plugin; } diff --git a/pkgs/test_core/lib/src/runner/hybrid_listener.dart b/pkgs/test_core/lib/src/runner/hybrid_listener.dart index 6a521db3a..1ce09fdb8 100644 --- a/pkgs/test_core/lib/src/runner/hybrid_listener.dart +++ b/pkgs/test_core/lib/src/runner/hybrid_listener.dart @@ -15,13 +15,17 @@ import 'package:test_api/src/utils.dart'; // ignore: implementation_imports /// A sink transformer that wraps data and error events so that errors can be /// decoded after being JSON-serialized. final _transformer = StreamSinkTransformer.fromHandlers( - handleData: (data, sink) { - ensureJsonEncodable(data); - sink.add({'type': 'data', 'data': data}); -}, handleError: (error, stackTrace, sink) { - sink.add( - {'type': 'error', 'error': RemoteException.serialize(error, stackTrace)}); -}); + handleData: (data, sink) { + ensureJsonEncodable(data); + sink.add({'type': 'data', 'data': data}); + }, + handleError: (error, stackTrace, sink) { + sink.add({ + 'type': 'error', + 'error': RemoteException.serialize(error, stackTrace), + }); + }, +); /// Runs the body of a hybrid isolate and communicates its messages, errors, and /// prints to the main isolate. @@ -36,61 +40,72 @@ void listen(Function Function() getMain, List data) { var channel = IsolateChannel.connectSend(data.first as SendPort); var message = data.last; - Chain.capture(() { - runZoned(() { - dynamic /*Function*/ main; - try { - main = getMain(); - } on NoSuchMethodError catch (_) { - _sendError(channel, 'No top-level hybridMain() function defined.'); - return; - } catch (error, stackTrace) { - _sendError(channel, error, stackTrace); - return; - } + Chain.capture( + () { + runZoned( + () { + dynamic /*Function*/ main; + try { + main = getMain(); + } on NoSuchMethodError catch (_) { + _sendError(channel, 'No top-level hybridMain() function defined.'); + return; + } catch (error, stackTrace) { + _sendError(channel, error, stackTrace); + return; + } - if (main is! Function) { - _sendError(channel, 'Top-level hybridMain is not a function.'); - return; - } else if (main is! void Function(StreamChannel) && - main is! void Function(StreamChannel, Never)) { - if (main is void Function(StreamChannel) || - main is void Function(StreamChannel, Never)) { - _sendError( - channel, - 'The first parameter to the top-level hybridMain() must be a ' - 'StreamChannel or StreamChannel. More specific ' - 'types such as StreamChannel are not supported.'); - } else { - _sendError(channel, - 'Top-level hybridMain() function must take one or two arguments.'); - } - return; - } + if (main is! Function) { + _sendError(channel, 'Top-level hybridMain is not a function.'); + return; + } else if (main is! void Function(StreamChannel) && + main is! void Function(StreamChannel, Never)) { + if (main is void Function(StreamChannel) || + main is void Function(StreamChannel, Never)) { + _sendError( + channel, + 'The first parameter to the top-level hybridMain() must be a ' + 'StreamChannel or StreamChannel. More specific ' + 'types such as StreamChannel are not supported.', + ); + } else { + _sendError( + channel, + 'Top-level hybridMain() function must take one or two arguments.', + ); + } + return; + } - // Wrap [channel] before passing it to user code so that we can wrap - // errors and distinguish user data events from control events sent by the - // listener. - var transformedChannel = channel.transformSink(_transformer); - if (main is void Function(StreamChannel)) { - main(transformedChannel); - } else { - main(transformedChannel, message); - } - }, zoneSpecification: ZoneSpecification(print: (_, __, ___, line) { - channel.sink.add({'type': 'print', 'line': line}); - })); - }, onError: (error, stackTrace) async { - _sendError(channel, error, stackTrace); - await channel.sink.close(); - Isolate.current.kill(); - }); + // Wrap [channel] before passing it to user code so that we can wrap + // errors and distinguish user data events from control events sent by the + // listener. + var transformedChannel = channel.transformSink(_transformer); + if (main is void Function(StreamChannel)) { + main(transformedChannel); + } else { + main(transformedChannel, message); + } + }, + zoneSpecification: ZoneSpecification( + print: (_, __, ___, line) { + channel.sink.add({'type': 'print', 'line': line}); + }, + ), + ); + }, + onError: (error, stackTrace) async { + _sendError(channel, error, stackTrace); + await channel.sink.close(); + Isolate.current.kill(); + }, + ); } /// Sends a message over [channel] indicating an error from user code. void _sendError(StreamChannel channel, Object error, [StackTrace? stackTrace]) { channel.sink.add({ 'type': 'error', - 'error': RemoteException.serialize(error, stackTrace ?? Chain.current()) + 'error': RemoteException.serialize(error, stackTrace ?? Chain.current()), }); } diff --git a/pkgs/test_core/lib/src/runner/live_suite.dart b/pkgs/test_core/lib/src/runner/live_suite.dart index 771655d1e..b61163d55 100644 --- a/pkgs/test_core/lib/src/runner/live_suite.dart +++ b/pkgs/test_core/lib/src/runner/live_suite.dart @@ -47,11 +47,11 @@ abstract class LiveSuite { /// This is guaranteed to contain the same tests as the union of [passed], /// [skipped], [failed], and [active]. Set get liveTests => UnionSet.from([ - passed, - skipped, - failed, - if (active != null) {active!} - ]); + passed, + skipped, + failed, + if (active != null) {active!}, + ]); /// A stream that emits each [LiveTest] in this suite as it's about to start /// running. diff --git a/pkgs/test_core/lib/src/runner/live_suite_controller.dart b/pkgs/test_core/lib/src/runner/live_suite_controller.dart index 15bc797f1..89ebc5b90 100644 --- a/pkgs/test_core/lib/src/runner/live_suite_controller.dart +++ b/pkgs/test_core/lib/src/runner/live_suite_controller.dart @@ -74,8 +74,9 @@ class LiveSuiteController { final _onCloseCompleter = Completer(); /// The controller for [LiveSuite.onTestStarted]. - final _onTestStartedController = - StreamController.broadcast(sync: true); + final _onTestStartedController = StreamController.broadcast( + sync: true, + ); /// The set that backs [LiveTest.passed]. final _passed = {}; @@ -144,11 +145,11 @@ class LiveSuiteController { /// Closes the underlying suite. Future close() => _closeMemo.runOnce(() async { - try { - await _suite.close(); - } finally { - _onCloseCompleter.complete(); - } - }); + try { + await _suite.close(); + } finally { + _onCloseCompleter.complete(); + } + }); final _closeMemo = AsyncMemoizer(); } diff --git a/pkgs/test_core/lib/src/runner/load_suite.dart b/pkgs/test_core/lib/src/runner/load_suite.dart index 633739afc..2fe5ae2b1 100644 --- a/pkgs/test_core/lib/src/runner/load_suite.dart +++ b/pkgs/test_core/lib/src/runner/load_suite.dart @@ -82,92 +82,128 @@ class LoadSuite extends Suite implements RunnerSuite { /// /// If the the load test is closed before [body] is complete, it will close /// the suite returned by [body] once it completes. - factory LoadSuite(String name, SuiteConfiguration config, - SuitePlatform platform, FutureOr Function() body, - {String? path}) { + factory LoadSuite( + String name, + SuiteConfiguration config, + SuitePlatform platform, + FutureOr Function() body, { + String? path, + }) { var completer = Completer<({RunnerSuite suite, Zone zone})?>.sync(); - return LoadSuite._(name, config, platform, () { - var invoker = Invoker.current; - invoker!.addOutstandingCallback(); - - unawaited(() async { - RunnerSuite? suite; - try { - suite = await body(); - } catch (_) { + return LoadSuite._( + name, + config, + platform, + () { + var invoker = Invoker.current; + invoker!.addOutstandingCallback(); + + unawaited(() async { + RunnerSuite? suite; + try { + suite = await body(); + } catch (_) { + invoker.removeOutstandingCallback(); + rethrow; + } + if (completer.isCompleted) { + // If the load test has already been closed, close the suite it + // generated. + await suite?.close(); + return; + } + + completer.complete( + suite == null ? null : (suite: suite, zone: Zone.current), + ); invoker.removeOutstandingCallback(); - rethrow; - } - if (completer.isCompleted) { - // If the load test has already been closed, close the suite it - // generated. - await suite?.close(); - return; - } - - completer.complete( - suite == null ? null : (suite: suite, zone: Zone.current)); - invoker.removeOutstandingCallback(); - }()); - - // If the test completes before the body callback, either an out-of-band - // error occurred or the test was canceled. Either way, we return a `null` - // suite. - invoker.liveTest.onComplete.then((_) { - if (!completer.isCompleted) completer.complete(); - }); - - // If the test is forcibly closed, let it complete, since load tests don't - // have timeouts. - invoker.onClose.then((_) => invoker.removeOutstandingCallback()); - }, completer.future, path: path, ignoreTimeouts: config.ignoreTimeouts); + }()); + + // If the test completes before the body callback, either an out-of-band + // error occurred or the test was canceled. Either way, we return a `null` + // suite. + invoker.liveTest.onComplete.then((_) { + if (!completer.isCompleted) completer.complete(); + }); + + // If the test is forcibly closed, let it complete, since load tests don't + // have timeouts. + invoker.onClose.then((_) => invoker.removeOutstandingCallback()); + }, + completer.future, + path: path, + ignoreTimeouts: config.ignoreTimeouts, + ); } /// A utility constructor for a load suite that just throws [exception]. /// /// The suite's name will be based on [exception]'s path. factory LoadSuite.forLoadException( - LoadException exception, SuiteConfiguration? config, - {SuitePlatform? platform, StackTrace? stackTrace}) { + LoadException exception, + SuiteConfiguration? config, { + SuitePlatform? platform, + StackTrace? stackTrace, + }) { stackTrace ??= Trace.current(); return LoadSuite( - 'loading ${exception.path}', - config ?? SuiteConfiguration.empty, - platform ?? currentPlatform(Runtime.vm, null), - () => Future.error(exception, stackTrace), - path: exception.path); + 'loading ${exception.path}', + config ?? SuiteConfiguration.empty, + platform ?? currentPlatform(Runtime.vm, null), + () => Future.error(exception, stackTrace), + path: exception.path, + ); } /// A utility constructor for a load suite that just emits [suite]. factory LoadSuite.forSuite(RunnerSuite suite) { return LoadSuite( - 'loading ${suite.path}', suite.config, suite.platform, () => suite, - path: suite.path); + 'loading ${suite.path}', + suite.config, + suite.platform, + () => suite, + path: suite.path, + ); } - LoadSuite._(String name, this.config, SuitePlatform platform, - void Function() body, this._suiteAndZone, - {required bool ignoreTimeouts, String? path}) - : super( - Group.root( - [LocalTest(name, Metadata(timeout: Timeout(_timeout)), body)]), - platform, - path: path, - ignoreTimeouts: ignoreTimeouts); + LoadSuite._( + String name, + this.config, + SuitePlatform platform, + void Function() body, + this._suiteAndZone, { + required bool ignoreTimeouts, + String? path, + }) : super( + Group.root([ + LocalTest(name, Metadata(timeout: Timeout(_timeout)), body), + ]), + platform, + path: path, + ignoreTimeouts: ignoreTimeouts, + ); /// A constructor used by [changeSuite]. LoadSuite._changeSuite(LoadSuite old, this._suiteAndZone) - : config = old.config, - super(old.group, old.platform, - path: old.path, ignoreTimeouts: old.ignoreTimeouts); + : config = old.config, + super( + old.group, + old.platform, + path: old.path, + ignoreTimeouts: old.ignoreTimeouts, + ); /// A constructor used by [filter]. LoadSuite._filtered(LoadSuite old, Group filtered) - : config = old.config, - _suiteAndZone = old._suiteAndZone, - super(old.group, old.platform, - path: old.path, ignoreTimeouts: old.ignoreTimeouts); + : config = old.config, + _suiteAndZone = old._suiteAndZone, + super( + old.group, + old.platform, + path: old.path, + ignoreTimeouts: old.ignoreTimeouts, + ); /// Creates a new [LoadSuite] that's identical to this one, but that /// transforms [suite] once it's loaded. @@ -176,16 +212,19 @@ class LoadSuite extends Suite implements RunnerSuite { /// within the load test's zone, so any errors or prints it emits will be /// associated with that test. LoadSuite changeSuite(RunnerSuite? Function(RunnerSuite) change) { - return LoadSuite._changeSuite(this, _suiteAndZone.then((pair) { - if (pair == null) return null; - - var (:suite, :zone) = pair; - RunnerSuite? newSuite; - zone.runGuarded(() { - newSuite = change(suite); - }); - return newSuite == null ? null : (suite: newSuite!, zone: zone); - })); + return LoadSuite._changeSuite( + this, + _suiteAndZone.then((pair) { + if (pair == null) return null; + + var (:suite, :zone) = pair; + RunnerSuite? newSuite; + zone.runGuarded(() { + newSuite = change(suite); + }); + return newSuite == null ? null : (suite: newSuite!, zone: zone); + }), + ); } /// Runs the test and returns the suite. diff --git a/pkgs/test_core/lib/src/runner/loader.dart b/pkgs/test_core/lib/src/runner/loader.dart index c37105d22..525ea79d8 100644 --- a/pkgs/test_core/lib/src/runner/loader.dart +++ b/pkgs/test_core/lib/src/runner/loader.dart @@ -80,7 +80,9 @@ class Loader { /// Registers a [PlatformPlugin] for [runtimes]. void _registerPlatformPlugin( - Iterable runtimes, FutureOr Function() plugin) { + Iterable runtimes, + FutureOr Function() plugin, + ) { var memoizer = AsyncMemoizer(); for (var runtime in runtimes) { _platformPlugins[runtime] = memoizer; @@ -94,16 +96,20 @@ class Loader { for (var customRuntime in _config.defineRuntimes.values) { if (_runtimesByIdentifier.containsKey(customRuntime.identifier)) { throw SourceSpanFormatException( - wordWrap( - 'The platform "${customRuntime.identifier}" already exists. ' - 'Use override_platforms to override it.'), - customRuntime.identifierSpan); + wordWrap( + 'The platform "${customRuntime.identifier}" already exists. ' + 'Use override_platforms to override it.', + ), + customRuntime.identifierSpan, + ); } var parent = _runtimesByIdentifier[customRuntime.parent]; if (parent == null) { throw SourceSpanFormatException( - 'Unknown platform.', customRuntime.parentSpan); + 'Unknown platform.', + customRuntime.parentSpan, + ); } var runtime = parent.extend(customRuntime.name, customRuntime.identifier); @@ -139,13 +145,15 @@ class Loader { /// [RunnerSuite]s defined in the file. Stream loadDir(String dir, SuiteConfiguration suiteConfig) { return StreamGroup.merge( - Directory(dir).listSync(recursive: true).map((entry) { - if (entry is! File || !_config.filename.matches(p.basename(entry.path))) { - return const Stream.empty(); - } + Directory(dir).listSync(recursive: true).map((entry) { + if (entry is! File || + !_config.filename.matches(p.basename(entry.path))) { + return const Stream.empty(); + } - return loadFile(entry.path, suiteConfig); - })); + return loadFile(entry.path, suiteConfig); + }), + ); } /// Loads a test suite from the file at [path] according to [suiteConfig]. @@ -155,17 +163,28 @@ class Loader { /// /// This will emit a [LoadException] if the file fails to load. Stream loadFile( - String path, SuiteConfiguration suiteConfig) async* { + String path, + SuiteConfiguration suiteConfig, + ) async* { try { - suiteConfig = suiteConfig.merge(SuiteConfiguration.fromMetadata( + suiteConfig = suiteConfig.merge( + SuiteConfiguration.fromMetadata( parseMetadata( - path, File(path).readAsStringSync(), _runtimeVariables.toSet()))); + path, + File(path).readAsStringSync(), + _runtimeVariables.toSet(), + ), + ), + ); } on ArgumentError catch (_) { // Ignore the analyzer's error, since its formatting is much worse than // the VM's or dart2js's. } on FormatException catch (error, stackTrace) { - yield LoadSuite.forLoadException(LoadException(path, error), suiteConfig, - stackTrace: stackTrace); + yield LoadSuite.forLoadException( + LoadException(path, error), + suiteConfig, + stackTrace: stackTrace, + ); return; } @@ -183,8 +202,9 @@ class Loader { in suiteConfig.compilerSelections ?? []) if (runtime.supportedCompilers.contains(selection.compiler) && (selection.platformSelector == null || - selection.platformSelector! - .evaluate(currentPlatform(runtime, selection.compiler)))) + selection.platformSelector!.evaluate( + currentPlatform(runtime, selection.compiler), + ))) selection.compiler, }; if (compilers.isEmpty) compilers.add(runtime.defaultCompiler); @@ -197,13 +217,17 @@ class Loader { // Don't load a skipped suite. if (platformConfig.metadata.skip && !platformConfig.runSkipped) { - yield LoadSuite.forSuite(RunnerSuite( + yield LoadSuite.forSuite( + RunnerSuite( const PluginEnvironment(), platformConfig, - Group.root([LocalTest('(suite)', platformConfig.metadata, () {})], - metadata: platformConfig.metadata), + Group.root([ + LocalTest('(suite)', platformConfig.metadata, () {}), + ], metadata: platformConfig.metadata), platform, - path: path)); + path: path, + ), + ); continue; } @@ -213,11 +237,13 @@ class Loader { var retriesLeft = suiteConfig.metadata.retry; while (true) { try { - var plugin = - await memo.runOnce(_platformCallbacks[platform.runtime]!); + var plugin = await memo.runOnce( + _platformCallbacks[platform.runtime]!, + ); _customizePlatform(plugin, platform.runtime); - var suite = await plugin.load(path, platform, platformConfig, - {'platformVariables': _runtimeVariables.toList()}); + var suite = await plugin.load(path, platform, platformConfig, { + 'platformVariables': _runtimeVariables.toList(), + }); if (suite != null) _suites.add(suite); return suite; } on Object catch (error, stackTrace) { @@ -268,30 +294,36 @@ class Loader { } throw SourceSpanFormatException( - 'The "$identifier" platform can\'t be customized.', span); + 'The "$identifier" platform can\'t be customized.', + span, + ); } } Future closeEphemeral() async { - await Future.wait(_platformPlugins.values.map((memo) async { - if (!memo.hasRun) return; - await (await memo.future).closeEphemeral(); - })); + await Future.wait( + _platformPlugins.values.map((memo) async { + if (!memo.hasRun) return; + await (await memo.future).closeEphemeral(); + }), + ); } /// Closes the loader and releases all resources allocated by it. Future close() => _closeMemo.runOnce(() async { - await Future.wait([ - Future.wait(_platformPlugins.values.map((memo) async { - if (!memo.hasRun) return; - await (await memo.future).close(); - })), - Future.wait(_suites.map((suite) => suite.close())) - ]); - - _platformPlugins.clear(); - _platformCallbacks.clear(); - _suites.clear(); - }); + await Future.wait([ + Future.wait( + _platformPlugins.values.map((memo) async { + if (!memo.hasRun) return; + await (await memo.future).close(); + }), + ), + Future.wait(_suites.map((suite) => suite.close())), + ]); + + _platformPlugins.clear(); + _platformCallbacks.clear(); + _suites.clear(); + }); final _closeMemo = AsyncMemoizer(); } diff --git a/pkgs/test_core/lib/src/runner/parse_metadata.dart b/pkgs/test_core/lib/src/runner/parse_metadata.dart index 9aa9681e1..4935a462d 100644 --- a/pkgs/test_core/lib/src/runner/parse_metadata.dart +++ b/pkgs/test_core/lib/src/runner/parse_metadata.dart @@ -22,8 +22,10 @@ import '../util/dart.dart'; /// Throws an [AnalysisError] if parsing fails or a [FormatException] if the /// test annotations are incorrect. Metadata parseMetadata( - String path, String contents, Set platformVariables) => - _Parser(path, contents, platformVariables).parse(); + String path, + String contents, + Set platformVariables, +) => _Parser(path, contents, platformVariables).parse(); /// A parser for test suite metadata. class _Parser { @@ -47,24 +49,28 @@ class _Parser { String? _languageVersionComment; _Parser(this._path, this._contents, this._platformVariables) { - var result = - parseString(content: _contents, path: _path, throwIfDiagnostics: false); + var result = parseString( + content: _contents, + path: _path, + throwIfDiagnostics: false, + ); var directives = result.unit.directives; _annotations = directives.isEmpty ? [] : directives.first.metadata; _languageVersionComment = result.unit.languageVersionToken?.value(); // We explicitly *don't* just look for "package:test" imports here, // because it could be re-exported from another library. - _prefixes = directives - .map((directive) { - if (directive is ImportDirective) { - return directive.prefix?.name; - } else { - return null; - } - }) - .whereType() - .toSet(); + _prefixes = + directives + .map((directive) { + if (directive is ImportDirective) { + return directive.prefix?.name; + } else { + return null; + } + }) + .whereType() + .toSet(); } /// Parses the metadata. @@ -77,8 +83,10 @@ class _Parser { int? retry; for (var annotation in _annotations) { - var pair = - _resolveConstructor(annotation.name, annotation.constructorName); + var pair = _resolveConstructor( + annotation.name, + annotation.constructorName, + ); var (name, constructorName) = pair; if (name == 'TestOn') { @@ -102,14 +110,15 @@ class _Parser { } return Metadata( - testOn: testOn, - timeout: timeout, - skip: skip == null ? null : true, - skipReason: skip is String ? skip : null, - onPlatform: onPlatform, - tags: tags, - retry: retry, - languageVersionComment: _languageVersionComment); + testOn: testOn, + timeout: timeout, + skip: skip == null ? null : true, + skipReason: skip is String ? skip : null, + onPlatform: onPlatform, + tags: tags, + retry: retry, + languageVersionComment: _languageVersionComment, + ); } /// Parses a `@TestOn` annotation. @@ -123,9 +132,11 @@ class _Parser { PlatformSelector _parsePlatformSelector(Expression expression) { var literal = _parseString(expression); return _contextualize( - literal, - () => PlatformSelector.parse(literal.stringValue!) - ..validate(_platformVariables)); + literal, + () => + PlatformSelector.parse(literal.stringValue!) + ..validate(_platformVariables), + ); } /// Parses a `@Retry` annotation. @@ -180,15 +191,17 @@ class _Parser { /// /// [annotation] is the annotation. Set _parseTags(Annotation annotation) { - return _parseList(annotation.arguments!.arguments.first) - .map((tagExpression) { + return _parseList(annotation.arguments!.arguments.first).map(( + tagExpression, + ) { var name = _parseString(tagExpression).stringValue!; if (name.contains(anchoredHyphenatedIdentifier)) return name; throw SourceSpanFormatException( - 'Invalid tag name. Tags must be (optionally hyphenated) Dart ' - 'identifiers.', - _spanFor(tagExpression)); + 'Invalid tag name. Tags must be (optionally hyphenated) Dart ' + 'identifiers.', + _spanFor(tagExpression), + ); }).toSet(); } @@ -196,65 +209,76 @@ class _Parser { /// /// [annotation] is the annotation. Map _parseOnPlatform(Annotation annotation) { - return _parseMap(annotation.arguments!.arguments.first, - key: _parsePlatformSelector, value: (value) { - var expressions = []; - if (value is ListLiteral) { - expressions = _parseList(value); - } else if (value is InstanceCreationExpression || - value is PrefixedIdentifier || - value is MethodInvocation) { - expressions = [value]; - } else { - throw SourceSpanFormatException( - 'Expected a Timeout, Skip, or List of those.', _spanFor(value)); - } + return _parseMap( + annotation.arguments!.arguments.first, + key: _parsePlatformSelector, + value: (value) { + var expressions = []; + if (value is ListLiteral) { + expressions = _parseList(value); + } else if (value is InstanceCreationExpression || + value is PrefixedIdentifier || + value is MethodInvocation) { + expressions = [value]; + } else { + throw SourceSpanFormatException( + 'Expected a Timeout, Skip, or List of those.', + _spanFor(value), + ); + } - Timeout? timeout; - Object? skip; - for (var expression in expressions) { - if (expression is InstanceCreationExpression) { - var className = expression.constructorName.type.name.lexeme; + Timeout? timeout; + Object? skip; + for (var expression in expressions) { + if (expression is InstanceCreationExpression) { + var className = expression.constructorName.type.name.lexeme; + + if (className == 'Timeout') { + _assertSingle(timeout, 'Timeout', expression); + timeout = _parseTimeoutConstructor(expression); + continue; + } else if (className == 'Skip') { + _assertSingle(skip, 'Skip', expression); + skip = _parseSkipConstructor(expression); + continue; + } + } else if (expression is PrefixedIdentifier && + expression.prefix.name == 'Timeout') { + if (expression.identifier.name != 'none') { + throw SourceSpanFormatException( + 'Undefined value.', + _spanFor(expression), + ); + } - if (className == 'Timeout') { _assertSingle(timeout, 'Timeout', expression); - timeout = _parseTimeoutConstructor(expression); - continue; - } else if (className == 'Skip') { - _assertSingle(skip, 'Skip', expression); - skip = _parseSkipConstructor(expression); + timeout = Timeout.none; continue; - } - } else if (expression is PrefixedIdentifier && - expression.prefix.name == 'Timeout') { - if (expression.identifier.name != 'none') { - throw SourceSpanFormatException( - 'Undefined value.', _spanFor(expression)); + } else if (expression is MethodInvocation) { + var className = _typeNameFromMethodInvocation(expression, [ + 'Timeout', + 'Skip', + ]); + if (className == 'Timeout') { + _assertSingle(timeout, 'Timeout', expression); + timeout = _parseTimeoutConstructor(expression); + continue; + } else if (className == 'Skip') { + _assertSingle(skip, 'Skip', expression); + skip = _parseSkipConstructor(expression); + continue; + } } - _assertSingle(timeout, 'Timeout', expression); - timeout = Timeout.none; - continue; - } else if (expression is MethodInvocation) { - var className = - _typeNameFromMethodInvocation(expression, ['Timeout', 'Skip']); - if (className == 'Timeout') { - _assertSingle(timeout, 'Timeout', expression); - timeout = _parseTimeoutConstructor(expression); - continue; - } else if (className == 'Skip') { - _assertSingle(skip, 'Skip', expression); - skip = _parseSkipConstructor(expression); - continue; - } + throw SourceSpanFormatException( + 'Expected a Timeout or Skip.', + _spanFor(expression), + ); } - throw SourceSpanFormatException( - 'Expected a Timeout or Skip.', _spanFor(expression)); - } - - return Metadata.parse(timeout: timeout, skip: skip); - }); + return Metadata.parse(timeout: timeout, skip: skip); + }, + ); } /// Parses a `const Duration` expression. @@ -262,24 +286,26 @@ class _Parser { _findConstructorName(expression, 'Duration'); var arguments = _parseArguments(expression); - var values = _parseNamedArguments(arguments) - .map((key, value) => MapEntry(key, _parseInt(value))); + var values = _parseNamedArguments( + arguments, + ).map((key, value) => MapEntry(key, _parseInt(value))); return Duration( - days: values['days'] ?? 0, - hours: values['hours'] ?? 0, - minutes: values['minutes'] ?? 0, - seconds: values['seconds'] ?? 0, - milliseconds: values['milliseconds'] ?? 0, - microseconds: values['microseconds'] ?? 0); + days: values['days'] ?? 0, + hours: values['hours'] ?? 0, + minutes: values['minutes'] ?? 0, + seconds: values['seconds'] ?? 0, + milliseconds: values['milliseconds'] ?? 0, + microseconds: values['microseconds'] ?? 0, + ); } Map _parseNamedArguments( - NodeList arguments) => - { - for (var a in arguments.whereType()) - a.name.label.name: a.expression - }; + NodeList arguments, + ) => { + for (var a in arguments.whereType()) + a.name.label.name: a.expression, + }; /// Asserts that [existing] is null. /// @@ -288,7 +314,9 @@ class _Parser { void _assertSingle(Object? existing, String name, AstNode node) { if (existing == null) return; throw SourceSpanFormatException( - 'Only a single $name may be used.', _spanFor(node)); + 'Only a single $name may be used.', + _spanFor(node), + ); } NodeList _parseArguments(Expression expression) { @@ -299,7 +327,9 @@ class _Parser { return expression.argumentList.arguments; } throw SourceSpanFormatException( - 'Expected an instantiation', _spanFor(expression)); + 'Expected an instantiation', + _spanFor(expression), + ); } /// Resolves a constructor name from its type [identifier] and its @@ -308,7 +338,9 @@ class _Parser { /// Since the parsed file isn't fully resolved, this is necessary to /// disambiguate between prefixed names and named constructors. (String, String?) _resolveConstructor( - Identifier identifier, SimpleIdentifier? constructorName) { + Identifier identifier, + SimpleIdentifier? constructorName, + ) { // The syntax is ambiguous between named constructors and prefixed // annotations, so we need to resolve that ambiguity using the known // prefixes. The analyzer parses "new x.y()" as prefix "x", annotation "y", @@ -322,9 +354,10 @@ class _Parser { className = identifier.prefix.name; namedConstructor = identifier.identifier.name; } else { - className = identifier is PrefixedIdentifier - ? identifier.identifier.name - : identifier.name; + className = + identifier is PrefixedIdentifier + ? identifier.identifier.name + : identifier.name; if (constructorName != null) namedConstructor = constructorName.name; } return (className, namedConstructor); @@ -343,24 +376,32 @@ class _Parser { return _findConstructorNameFromMethod(expression, className); } throw SourceSpanFormatException( - 'Expected a $className.', _spanFor(expression)); + 'Expected a $className.', + _spanFor(expression), + ); } String? _findConstructorNameFromInstantiation( - InstanceCreationExpression constructor, String className) { + InstanceCreationExpression constructor, + String className, + ) { var actualClassName = constructor.constructorName.type.name.lexeme; var constructorName = constructor.constructorName.name?.name; if (actualClassName != className) { throw SourceSpanFormatException( - 'Expected a $className.', _spanFor(constructor)); + 'Expected a $className.', + _spanFor(constructor), + ); } return constructorName; } String? _findConstructorNameFromMethod( - MethodInvocation constructor, String className) { + MethodInvocation constructor, + String className, + ) { var target = constructor.target; if (target != null) { // target could be an import prefix or a different class. Assume that @@ -375,7 +416,9 @@ class _Parser { if (target is PrefixedIdentifier) parsedName = target.identifier.name; if (parsedName != className) { throw SourceSpanFormatException( - 'Expected a $className.', _spanFor(constructor)); + 'Expected a $className.', + _spanFor(constructor), + ); } return constructor.methodName.name; } @@ -383,7 +426,9 @@ class _Parser { // Example `Timeout()` if (constructor.methodName.name != className) { throw SourceSpanFormatException( - 'Expected a $className.', _spanFor(constructor)); + 'Expected a $className.', + _spanFor(constructor), + ); } return null; } @@ -400,7 +445,9 @@ class _Parser { /// a `Baz`even though it is a prefixed instantiation of an `another`, or a /// method invocation on a variable `Baz`, or ... String? _typeNameFromMethodInvocation( - MethodInvocation constructor, List candidates) { + MethodInvocation constructor, + List candidates, + ) { var methodName = constructor.methodName.name; // Examples: `Timeout()`, `test.Timeout()` if (candidates.contains(methodName)) return methodName; @@ -426,8 +473,11 @@ class _Parser { /// /// By default, returns [Expression] keys and values. These can be overridden /// with the [key] and [value] parameters. - Map _parseMap(Expression expression, - {K Function(Expression)? key, V Function(Expression)? value}) { + Map _parseMap( + Expression expression, { + K Function(Expression)? key, + V Function(Expression)? value, + }) { key ??= (expression) => expression as K; value ??= (expression) => expression as V; @@ -441,7 +491,9 @@ class _Parser { map[key(element.key)] = value(element.value); } else { throw SourceSpanFormatException( - 'Expected a map entry.', _spanFor(element)); + 'Expected a map entry.', + _spanFor(element), + ); } } return map; @@ -458,7 +510,9 @@ class _Parser { return list.elements.map((e) { if (e is! Expression) { throw SourceSpanFormatException( - 'Expected only literal elements.', _spanFor(e)); + 'Expected only literal elements.', + _spanFor(e), + ); } return e; }).toList(); @@ -479,7 +533,9 @@ class _Parser { return expression.value!; } throw SourceSpanFormatException( - 'Expected an integer.', _spanFor(expression)); + 'Expected an integer.', + _spanFor(expression), + ); } /// Parses a constant String literal. @@ -488,15 +544,19 @@ class _Parser { return expression; } throw SourceSpanFormatException( - 'Expected a String literal.', _spanFor(expression)); + 'Expected a String literal.', + _spanFor(expression), + ); } /// Creates a [SourceSpan] for [node]. SourceSpan _spanFor(AstNode node) { // Load a SourceFile from scratch here since we're only ever going to emit // one error per file anyway. - return SourceFile.fromString(_contents, url: p.toUri(_path)) - .span(node.offset, node.end); + return SourceFile.fromString( + _contents, + url: p.toUri(_path), + ).span(node.offset, node.end); } /// Runs [fn] and contextualizes any [SourceSpanFormatException]s that occur diff --git a/pkgs/test_core/lib/src/runner/platform.dart b/pkgs/test_core/lib/src/runner/platform.dart index 3048052b6..4cfbaea2d 100644 --- a/pkgs/test_core/lib/src/runner/platform.dart +++ b/pkgs/test_core/lib/src/runner/platform.dart @@ -34,8 +34,12 @@ abstract class PlatformPlugin { /// Subclasses overriding this method must call [deserializeSuite] in /// `platform_helpers.dart` to obtain a [RunnerSuiteController]. They must /// pass the opaque [message] parameter to the [deserializeSuite] call. - Future load(String path, SuitePlatform platform, - SuiteConfiguration suiteConfig, Map message); + Future load( + String path, + SuitePlatform platform, + SuiteConfiguration suiteConfig, + Map message, + ); Future closeEphemeral() async {} diff --git a/pkgs/test_core/lib/src/runner/plugin/environment.dart b/pkgs/test_core/lib/src/runner/plugin/environment.dart index 7558d620e..cfcc74679 100644 --- a/pkgs/test_core/lib/src/runner/plugin/environment.dart +++ b/pkgs/test_core/lib/src/runner/plugin/environment.dart @@ -24,6 +24,8 @@ class PluginEnvironment implements Environment { Uri? get remoteDebuggerUrl => null; @override - CancelableOperation displayPause() => throw UnsupportedError( - 'PluginEnvironment.displayPause is not supported.'); + CancelableOperation displayPause() => + throw UnsupportedError( + 'PluginEnvironment.displayPause is not supported.', + ); } diff --git a/pkgs/test_core/lib/src/runner/plugin/platform_helpers.dart b/pkgs/test_core/lib/src/runner/plugin/platform_helpers.dart index e64ed04dd..7fef47f99 100644 --- a/pkgs/test_core/lib/src/runner/plugin/platform_helpers.dart +++ b/pkgs/test_core/lib/src/runner/plugin/platform_helpers.dart @@ -37,13 +37,14 @@ import '../suite.dart'; /// [gatherCoverage] is a callback which returns a hit-map containing merged /// coverage report suitable for use with `package:coverage`. RunnerSuiteController deserializeSuite( - String path, - SuitePlatform platform, - SuiteConfiguration suiteConfig, - Environment environment, - StreamChannel channel, - Object /*Map*/ message, - {Future> Function()? gatherCoverage}) { + String path, + SuitePlatform platform, + SuiteConfiguration suiteConfig, + Environment environment, + StreamChannel channel, + Object /*Map*/ message, { + Future> Function()? gatherCoverage, +}) { var disconnector = Disconnector(); var suiteChannel = MultiChannel(channel.transform(disconnector)); @@ -53,10 +54,12 @@ RunnerSuiteController deserializeSuite( 'metadata': suiteConfig.metadata.serialize(), 'asciiGlyphs': Platform.isWindows, 'path': path, - 'collectTraces': Configuration.current.reporter == 'json' || + 'collectTraces': + Configuration.current.reporter == 'json' || Configuration.current.fileReporters.containsKey('json') || suiteConfig.testSelections.any( - (selection) => selection.line != null || selection.col != null), + (selection) => selection.line != null || selection.col != null, + ), 'noRetry': Configuration.current.noRetry, 'foldTraceExcept': Configuration.current.foldTraceExcept.toList(), 'foldTraceOnly': Configuration.current.foldTraceOnly.toList(), @@ -82,44 +85,57 @@ RunnerSuiteController deserializeSuite( } suiteChannel.stream.cast>().listen( - (response) { - switch (response['type'] as String) { - case 'print': - print(response['line']); - break; - - case 'loadException': - handleError(LoadException(path, response['message'] as Object), - Trace.current()); - break; - - case 'error': - var asyncError = RemoteException.deserialize( - response['error'] as Map); - handleError( - LoadException(path, asyncError.error), asyncError.stackTrace); - break; - - case 'success': - var deserializer = _Deserializer(suiteChannel); - completer.complete( - deserializer.deserializeGroup(response['root'] as Map)); - break; - } - }, - onError: handleError, - onDone: () { - if (completer.isCompleted) return; - completer.completeError( - LoadException(path, 'Connection closed before test suite loaded.'), - Trace.current()); - }); + (response) { + switch (response['type'] as String) { + case 'print': + print(response['line']); + break; + + case 'loadException': + handleError( + LoadException(path, response['message'] as Object), + Trace.current(), + ); + break; + + case 'error': + var asyncError = RemoteException.deserialize( + response['error'] as Map, + ); + handleError( + LoadException(path, asyncError.error), + asyncError.stackTrace, + ); + break; + + case 'success': + var deserializer = _Deserializer(suiteChannel); + completer.complete( + deserializer.deserializeGroup(response['root'] as Map), + ); + break; + } + }, + onError: handleError, + onDone: () { + if (completer.isCompleted) return; + completer.completeError( + LoadException(path, 'Connection closed before test suite loaded.'), + Trace.current(), + ); + }, + ); return RunnerSuiteController( - environment, suiteConfig, suiteChannel, completer.future, platform, - path: path, - onClose: () => disconnector.disconnect().onError(handleError), - gatherCoverage: gatherCoverage); + environment, + suiteConfig, + suiteChannel, + completer.future, + platform, + path: path, + onClose: () => disconnector.disconnect().onError(handleError), + gatherCoverage: gatherCoverage, + ); } /// A utility class for storing state while deserializing tests. @@ -138,18 +154,22 @@ class _Deserializer { Map map => TestLocation.deserialize(map), _ => null, }; - var entries = (group['entries'] as List).map((entry) { - var map = entry as Map; - if (map['type'] == 'group') return deserializeGroup(map); - return _deserializeTest(map)!; - }).toList(); - - return Group(group['name'] as String, entries, - metadata: metadata, - trace: trace, - location: location, - setUpAll: _deserializeTest(group['setUpAll'] as Map?), - tearDownAll: _deserializeTest(group['tearDownAll'] as Map?)); + var entries = + (group['entries'] as List).map((entry) { + var map = entry as Map; + if (map['type'] == 'group') return deserializeGroup(map); + return _deserializeTest(map)!; + }).toList(); + + return Group( + group['name'] as String, + entries, + metadata: metadata, + trace: trace, + location: location, + setUpAll: _deserializeTest(group['setUpAll'] as Map?), + tearDownAll: _deserializeTest(group['tearDownAll'] as Map?), + ); } /// Deserializes [test] into a concrete [Test] class. @@ -167,6 +187,11 @@ class _Deserializer { }; var testChannel = _channel.virtualChannel((test['channel'] as num).toInt()); return RunnerTest( - test['name'] as String, metadata, trace, location, testChannel); + test['name'] as String, + metadata, + trace, + location, + testChannel, + ); } } diff --git a/pkgs/test_core/lib/src/runner/plugin/remote_platform_helpers.dart b/pkgs/test_core/lib/src/runner/plugin/remote_platform_helpers.dart index 8eb2b76ca..6edc607b0 100644 --- a/pkgs/test_core/lib/src/runner/plugin/remote_platform_helpers.dart +++ b/pkgs/test_core/lib/src/runner/plugin/remote_platform_helpers.dart @@ -24,16 +24,16 @@ import 'package:test_api/backend.dart' /// /// If [beforeLoad] is passed, it's called before the tests have been declared /// for this worker. -StreamChannel serializeSuite(Function Function() getMain, - {bool hidePrints = true, - Future Function( - StreamChannel Function(String name) suiteChannel)? - beforeLoad}) => - RemoteListener.start( - getMain, - hidePrints: hidePrints, - beforeLoad: beforeLoad, - ); +StreamChannel serializeSuite( + Function Function() getMain, { + bool hidePrints = true, + Future Function(StreamChannel Function(String name) suiteChannel)? + beforeLoad, +}) => RemoteListener.start( + getMain, + hidePrints: hidePrints, + beforeLoad: beforeLoad, +); /// Sets the stack trace mapper for the current test suite. /// @@ -44,7 +44,8 @@ void setStackTraceMapper(StackTraceMapper mapper) { var formatter = StackTraceFormatter.current; if (formatter == null) { throw StateError( - 'setStackTraceMapper() may only be called within a test worker.'); + 'setStackTraceMapper() may only be called within a test worker.', + ); } formatter.configure(mapper: mapper); diff --git a/pkgs/test_core/lib/src/runner/plugin/shared_platform_helpers.dart b/pkgs/test_core/lib/src/runner/plugin/shared_platform_helpers.dart index 4fdcf23d1..c1c39cb59 100644 --- a/pkgs/test_core/lib/src/runner/plugin/shared_platform_helpers.dart +++ b/pkgs/test_core/lib/src/runner/plugin/shared_platform_helpers.dart @@ -16,6 +16,9 @@ StreamChannel jsonSocketStreamChannel(Socket socket) => .cast>() .transform(StreamChannelTransformer.fromCodec(utf8)) .transformStream(const LineSplitter()) - .transformSink(StreamSinkTransformer.fromHandlers( - handleData: (original, sink) => sink.add('$original\n'))) + .transformSink( + StreamSinkTransformer.fromHandlers( + handleData: (original, sink) => sink.add('$original\n'), + ), + ) .transform(jsonDocument); diff --git a/pkgs/test_core/lib/src/runner/reporter/compact.dart b/pkgs/test_core/lib/src/runner/reporter/compact.dart index 13ccd1114..3095ede2b 100644 --- a/pkgs/test_core/lib/src/runner/reporter/compact.dart +++ b/pkgs/test_core/lib/src/runner/reporter/compact.dart @@ -118,27 +118,36 @@ class CompactReporter implements Reporter { /// won't. If [printPath] is `true`, this will print the path name as part of /// the test description. Likewise, if [printPlatform] is `true`, this will /// print the platform as part of the test description. - static CompactReporter watch(Engine engine, StringSink sink, - {required bool color, - required bool printPath, - required bool printPlatform}) => - CompactReporter._(engine, sink, - color: color, printPath: printPath, printPlatform: printPlatform); - - CompactReporter._(this._engine, this._sink, - {required bool color, - required bool printPath, - required bool printPlatform}) - : _printPath = printPath, - _printPlatform = printPlatform, - _color = color, - _green = color ? '\u001b[32m' : '', - _red = color ? '\u001b[31m' : '', - _yellow = color ? '\u001b[33m' : '', - _gray = color ? '\u001b[90m' : '', - _cyan = color ? '\u001b[36m' : '', - _bold = color ? '\u001b[1m' : '', - _noColor = color ? '\u001b[0m' : '' { + static CompactReporter watch( + Engine engine, + StringSink sink, { + required bool color, + required bool printPath, + required bool printPlatform, + }) => CompactReporter._( + engine, + sink, + color: color, + printPath: printPath, + printPlatform: printPlatform, + ); + + CompactReporter._( + this._engine, + this._sink, { + required bool color, + required bool printPath, + required bool printPlatform, + }) : _printPath = printPath, + _printPlatform = printPlatform, + _color = color, + _green = color ? '\u001b[32m' : '', + _red = color ? '\u001b[31m' : '', + _yellow = color ? '\u001b[33m' : '', + _gray = color ? '\u001b[90m' : '', + _cyan = color ? '\u001b[36m' : '', + _bold = color ? '\u001b[1m' : '', + _noColor = color ? '\u001b[0m' : '' { _subscriptions.add(_engine.onTestStarted.listen(_onTestStarted)); // Convert the future to a stream so that the subscription can be paused or @@ -191,8 +200,11 @@ class CompactReporter implements Reporter { _stopwatch.start(); // Keep updating the time even when nothing else is happening. - _subscriptions.add(Stream.periodic(const Duration(seconds: 1)) - .listen((_) => _progressLine(_lastProgressMessage ?? ''))); + _subscriptions.add( + Stream.periodic( + const Duration(seconds: 1), + ).listen((_) => _progressLine(_lastProgressMessage ?? '')), + ); } // If this is the first test or suite load to start, print a progress line @@ -204,33 +216,42 @@ class CompactReporter implements Reporter { _progressLine(_description(liveTest)); } - _subscriptions.add(liveTest.onStateChange - .listen((state) => _onStateChange(liveTest, state))); + _subscriptions.add( + liveTest.onStateChange.listen((state) => _onStateChange(liveTest, state)), + ); - _subscriptions.add(liveTest.onError - .listen((error) => _onError(liveTest, error.error, error.stackTrace))); + _subscriptions.add( + liveTest.onError.listen( + (error) => _onError(liveTest, error.error, error.stackTrace), + ), + ); - _subscriptions.add(liveTest.onMessage.listen((message) { - _progressLine(_description(liveTest), truncate: false); - if (!_printedNewline) _sink.writeln(''); - _printedNewline = true; + _subscriptions.add( + liveTest.onMessage.listen((message) { + _progressLine(_description(liveTest), truncate: false); + if (!_printedNewline) _sink.writeln(''); + _printedNewline = true; - var text = message.text; - if (message.type == MessageType.skip) text = ' $_yellow$text$_noColor'; - _sink.writeln(text); - })); + var text = message.text; + if (message.type == MessageType.skip) text = ' $_yellow$text$_noColor'; + _sink.writeln(text); + }), + ); liveTest.onComplete.then((_) { var result = liveTest.state.result; if (result != Result.error && result != Result.failure) return; - var quotedName = Platform.isWindows - ? '"${liveTest.test.name.replaceAll('"', '"""')}"' - : "'${liveTest.test.name.replaceAll("'", r"'\''")}'"; + var quotedName = + Platform.isWindows + ? '"${liveTest.test.name.replaceAll('"', '"""')}"' + : "'${liveTest.test.name.replaceAll("'", r"'\''")}'"; _sink.writeln(''); - _sink.writeln('$_bold${_cyan}To run this test again:$_noColor ' - '${Platform.executable} test ${liveTest.suite.path} ' - '-p ${liveTest.suite.platform.runtime.identifier} ' - '--plain-name $quotedName'); + _sink.writeln( + '$_bold${_cyan}To run this test again:$_noColor ' + '${Platform.executable} test ${liveTest.suite.path} ' + '-p ${liveTest.suite.platform.runtime.identifier} ' + '--plain-name $quotedName', + ); }); } @@ -260,8 +281,11 @@ class CompactReporter implements Reporter { if (liveTest.state.status != Status.complete) return; - _progressLine(_description(liveTest), - truncate: false, suffix: ' $_bold$_red[E]$_noColor'); + _progressLine( + _description(liveTest), + truncate: false, + suffix: ' $_bold$_red[E]$_noColor', + ); if (!_printedNewline) _sink.writeln(''); _printedNewline = true; @@ -311,9 +335,11 @@ class CompactReporter implements Reporter { _sink.writeln(''); } else if (!success) { for (var liveTest in _engine.active) { - _progressLine(_description(liveTest), - truncate: false, - suffix: ' - did not complete $_bold$_red[E]$_noColor'); + _progressLine( + _description(liveTest), + truncate: false, + suffix: ' - did not complete $_bold$_red[E]$_noColor', + ); _sink.writeln(''); } _progressLine('Some tests failed.', color: _red); @@ -329,9 +355,11 @@ class CompactReporter implements Reporter { if (_shouldPrintStackTraceChainingNotice) { _sink ..writeln('') - ..writeln('Consider enabling the flag chain-stack-traces to ' - 'receive more detailed exceptions.\n' - "For example, 'dart test --chain-stack-traces'."); + ..writeln( + 'Consider enabling the flag chain-stack-traces to ' + 'receive more detailed exceptions.\n' + "For example, 'dart test --chain-stack-traces'.", + ); } } @@ -341,8 +369,12 @@ class CompactReporter implements Reporter { /// entire line within [lineLength]. If [color] is passed, it's used as the /// color for [message]. If [suffix] is passed, it's added to the end of /// [message]. - bool _progressLine(String message, - {String? color, bool truncate = true, String? suffix}) { + bool _progressLine( + String message, { + String? color, + bool truncate = true, + String? suffix, + }) { var elapsed = _stopwatch.elapsed.inSeconds; // Print nothing if nothing has changed since the last progress line. @@ -435,7 +467,8 @@ class CompactReporter implements Reporter { } if (_printPlatform) { - name = '[${liveTest.suite.platform.runtime.name}, ' + name = + '[${liveTest.suite.platform.runtime.name}, ' '${liveTest.suite.platform.compiler.name}] $name'; } diff --git a/pkgs/test_core/lib/src/runner/reporter/expanded.dart b/pkgs/test_core/lib/src/runner/reporter/expanded.dart index be2016c5a..cdc1d7e85 100644 --- a/pkgs/test_core/lib/src/runner/reporter/expanded.dart +++ b/pkgs/test_core/lib/src/runner/reporter/expanded.dart @@ -97,26 +97,35 @@ class ExpandedReporter implements Reporter { /// won't. If [printPath] is `true`, this will print the path name as part of /// the test description. Likewise, if [printPlatform] is `true`, this will /// print the platform as part of the test description. - static ExpandedReporter watch(Engine engine, StringSink sink, - {required bool color, - required bool printPath, - required bool printPlatform}) => - ExpandedReporter._(engine, sink, - color: color, printPath: printPath, printPlatform: printPlatform); - - ExpandedReporter._(this._engine, this._sink, - {required bool color, - required bool printPath, - required bool printPlatform}) - : _printPath = printPath, - _printPlatform = printPlatform, - _color = color, - _green = color ? '\u001b[32m' : '', - _red = color ? '\u001b[31m' : '', - _yellow = color ? '\u001b[33m' : '', - _gray = color ? '\u001b[90m' : '', - _bold = color ? '\u001b[1m' : '', - _noColor = color ? '\u001b[0m' : '' { + static ExpandedReporter watch( + Engine engine, + StringSink sink, { + required bool color, + required bool printPath, + required bool printPlatform, + }) => ExpandedReporter._( + engine, + sink, + color: color, + printPath: printPath, + printPlatform: printPlatform, + ); + + ExpandedReporter._( + this._engine, + this._sink, { + required bool color, + required bool printPath, + required bool printPlatform, + }) : _printPath = printPath, + _printPlatform = printPlatform, + _color = color, + _green = color ? '\u001b[32m' : '', + _red = color ? '\u001b[31m' : '', + _yellow = color ? '\u001b[33m' : '', + _gray = color ? '\u001b[90m' : '', + _bold = color ? '\u001b[1m' : '', + _noColor = color ? '\u001b[0m' : '' { _subscriptions.add(_engine.onTestStarted.listen(_onTestStarted)); // Convert the future to a stream so that the subscription can be paused or @@ -166,8 +175,11 @@ class ExpandedReporter implements Reporter { // The engine surfaces load tests when there are no other tests running, // but because the expanded reporter's output is always visible, we don't // emit information about them unless they fail. - _subscriptions.add(liveTest.onStateChange - .listen((state) => _onStateChange(liveTest, state))); + _subscriptions.add( + liveTest.onStateChange.listen( + (state) => _onStateChange(liveTest, state), + ), + ); } else if (_engine.active.isEmpty && _engine.activeSuiteLoads.length == 1 && _engine.activeSuiteLoads.first == liveTest && @@ -177,15 +189,20 @@ class ExpandedReporter implements Reporter { _progressLine(_description(liveTest)); } - _subscriptions.add(liveTest.onError - .listen((error) => _onError(liveTest, error.error, error.stackTrace))); - - _subscriptions.add(liveTest.onMessage.listen((message) { - _progressLine(_description(liveTest)); - var text = message.text; - if (message.type == MessageType.skip) text = ' $_yellow$text$_noColor'; - _sink.writeln(text); - })); + _subscriptions.add( + liveTest.onError.listen( + (error) => _onError(liveTest, error.error, error.stackTrace), + ), + ); + + _subscriptions.add( + liveTest.onMessage.listen((message) { + _progressLine(_description(liveTest)); + var text = message.text; + if (message.type == MessageType.skip) text = ' $_yellow$text$_noColor'; + _sink.writeln(text); + }), + ); } /// A callback called when [liveTest]'s state becomes [state]. @@ -241,8 +258,10 @@ class ExpandedReporter implements Reporter { _sink.writeln('No tests ran.'); } else if (!success) { for (var liveTest in _engine.active) { - _progressLine(_description(liveTest), - suffix: ' - did not complete $_bold$_red[E]$_noColor'); + _progressLine( + _description(liveTest), + suffix: ' - did not complete $_bold$_red[E]$_noColor', + ); } _progressLine('Some tests failed.', color: _red); } else if (_engine.passed.isEmpty) { @@ -254,9 +273,11 @@ class ExpandedReporter implements Reporter { if (_shouldPrintStackTraceChainingNotice) { _sink ..writeln('') - ..writeln('Consider enabling the flag chain-stack-traces to ' - 'receive more detailed exceptions.\n' - "For example, 'dart test --chain-stack-traces'."); + ..writeln( + 'Consider enabling the flag chain-stack-traces to ' + 'receive more detailed exceptions.\n' + "For example, 'dart test --chain-stack-traces'.", + ); } } @@ -336,7 +357,8 @@ class ExpandedReporter implements Reporter { } if (_printPlatform) { - name = '[${liveTest.suite.platform.runtime.name}, ' + name = + '[${liveTest.suite.platform.runtime.name}, ' '${liveTest.suite.platform.compiler.name}] $name'; } diff --git a/pkgs/test_core/lib/src/runner/reporter/failures_only.dart b/pkgs/test_core/lib/src/runner/reporter/failures_only.dart index b6b85e7d1..1549da52b 100644 --- a/pkgs/test_core/lib/src/runner/reporter/failures_only.dart +++ b/pkgs/test_core/lib/src/runner/reporter/failures_only.dart @@ -89,26 +89,35 @@ class FailuresOnlyReporter implements Reporter { /// won't. If [printPath] is `true`, this will print the path name as part of /// the test description. Likewise, if [printPlatform] is `true`, this will /// print the platform as part of the test description. - static FailuresOnlyReporter watch(Engine engine, StringSink sink, - {required bool color, - required bool printPath, - required bool printPlatform}) => - FailuresOnlyReporter._(engine, sink, - color: color, printPath: printPath, printPlatform: printPlatform); - - FailuresOnlyReporter._(this._engine, this._sink, - {required bool color, - required bool printPath, - required bool printPlatform}) - : _printPath = printPath, - _printPlatform = printPlatform, - _color = color, - _green = color ? '\u001b[32m' : '', - _red = color ? '\u001b[31m' : '', - _yellow = color ? '\u001b[33m' : '', - _gray = color ? '\u001b[90m' : '', - _bold = color ? '\u001b[1m' : '', - _noColor = color ? '\u001b[0m' : '' { + static FailuresOnlyReporter watch( + Engine engine, + StringSink sink, { + required bool color, + required bool printPath, + required bool printPlatform, + }) => FailuresOnlyReporter._( + engine, + sink, + color: color, + printPath: printPath, + printPlatform: printPlatform, + ); + + FailuresOnlyReporter._( + this._engine, + this._sink, { + required bool color, + required bool printPath, + required bool printPlatform, + }) : _printPath = printPath, + _printPlatform = printPlatform, + _color = color, + _green = color ? '\u001b[32m' : '', + _red = color ? '\u001b[31m' : '', + _yellow = color ? '\u001b[33m' : '', + _gray = color ? '\u001b[90m' : '', + _bold = color ? '\u001b[1m' : '', + _noColor = color ? '\u001b[0m' : '' { _subscriptions.add(_engine.onTestStarted.listen(_onTestStarted)); // Convert the future to a stream so that the subscription can be paused or @@ -144,16 +153,21 @@ class FailuresOnlyReporter implements Reporter { /// A callback called when the engine begins running [liveTest]. void _onTestStarted(LiveTest liveTest) { - _subscriptions.add(liveTest.onError - .listen((error) => _onError(liveTest, error.error, error.stackTrace))); - - _subscriptions.add(liveTest.onMessage.listen((message) { - // TODO - Should this suppress output? Behave like printOnFailure? - _progressLine(_description(liveTest)); - var text = message.text; - if (message.type == MessageType.skip) text = ' $_yellow$text$_noColor'; - _sink.writeln(text); - })); + _subscriptions.add( + liveTest.onError.listen( + (error) => _onError(liveTest, error.error, error.stackTrace), + ), + ); + + _subscriptions.add( + liveTest.onMessage.listen((message) { + // TODO - Should this suppress output? Behave like printOnFailure? + _progressLine(_description(liveTest)); + var text = message.text; + if (message.type == MessageType.skip) text = ' $_yellow$text$_noColor'; + _sink.writeln(text); + }), + ); } /// A callback called when [liveTest] throws [error]. @@ -198,8 +212,10 @@ class FailuresOnlyReporter implements Reporter { _sink.writeln('No tests ran.'); } else if (!success) { for (var liveTest in _engine.active) { - _progressLine(_description(liveTest), - suffix: ' - did not complete $_bold$_red[E]$_noColor'); + _progressLine( + _description(liveTest), + suffix: ' - did not complete $_bold$_red[E]$_noColor', + ); } _progressLine('Some tests failed.', color: _red); } else if (_engine.passed.isEmpty) { @@ -211,9 +227,11 @@ class FailuresOnlyReporter implements Reporter { if (_shouldPrintStackTraceChainingNotice) { _sink ..writeln('') - ..writeln('Consider enabling the flag chain-stack-traces to ' - 'receive more detailed exceptions.\n' - "For example, 'dart test --chain-stack-traces'."); + ..writeln( + 'Consider enabling the flag chain-stack-traces to ' + 'receive more detailed exceptions.\n' + "For example, 'dart test --chain-stack-traces'.", + ); } } @@ -284,7 +302,8 @@ class FailuresOnlyReporter implements Reporter { } if (_printPlatform) { - name = '[${liveTest.suite.platform.runtime.name}, ' + name = + '[${liveTest.suite.platform.runtime.name}, ' '${liveTest.suite.platform.compiler.name}] $name'; } diff --git a/pkgs/test_core/lib/src/runner/reporter/github.dart b/pkgs/test_core/lib/src/runner/reporter/github.dart index 5249817db..b71ca877e 100644 --- a/pkgs/test_core/lib/src/runner/reporter/github.dart +++ b/pkgs/test_core/lib/src/runner/reporter/github.dart @@ -50,11 +50,14 @@ class GithubReporter implements Reporter { StringSink sink, { required bool printPath, required bool printPlatform, - }) => - GithubReporter._(engine, sink, printPath, printPlatform); + }) => GithubReporter._(engine, sink, printPath, printPlatform); GithubReporter._( - this._engine, this._sink, this._printPath, this._printPlatform) { + this._engine, + this._sink, + this._printPath, + this._printPlatform, + ) { _subscriptions.add(_engine.onTestStarted.listen(_onTestStarted)); _subscriptions.add(_engine.success.asStream().listen(_onDone)); @@ -94,21 +97,27 @@ class GithubReporter implements Reporter { // Convert the future to a stream so that the subscription can be paused or // canceled. _subscriptions.add( - liveTest.onComplete.asStream().listen((_) => _onComplete(liveTest))); + liveTest.onComplete.asStream().listen((_) => _onComplete(liveTest)), + ); - _subscriptions.add(liveTest.onError - .listen((error) => _onError(liveTest, error.error, error.stackTrace))); + _subscriptions.add( + liveTest.onError.listen( + (error) => _onError(liveTest, error.error, error.stackTrace), + ), + ); // Collect messages from tests as they are emitted. - _subscriptions.add(liveTest.onMessage.listen((message) { - if (_completedTests.contains(liveTest)) { - // The test has already completed and it's previous messages were - // written out; ensure this post-completion output is not lost. - _sink.writeln(message.text); - } else { - _testMessages.putIfAbsent(liveTest, () => []).add(message); - } - })); + _subscriptions.add( + liveTest.onMessage.listen((message) { + if (_completedTests.contains(liveTest)) { + // The test has already completed and it's previous messages were + // written out; ensure this post-completion output is not lost. + _sink.writeln(message.text); + } else { + _testMessages.putIfAbsent(liveTest, () => []).add(message); + } + }), + ); } /// A callback called when [liveTest] finishes running. @@ -118,7 +127,8 @@ class GithubReporter implements Reporter { final skipped = test.state.result == Result.skipped; final failed = errors.isNotEmpty; final loadSuite = test.suite is LoadSuite; - final synthetic = loadSuite || + final synthetic = + loadSuite || test.individualName == '(setUpAll)' || test.individualName == '(tearDownAll)'; @@ -134,14 +144,16 @@ class GithubReporter implements Reporter { // For now, we use the same icon for both tests and test-like structures // (loadSuite, setUpAll, tearDownAll). var defaultIcon = synthetic ? _GithubMarkup.passed : _GithubMarkup.passed; - final prefix = failed - ? _GithubMarkup.failed - : skipped + final prefix = + failed + ? _GithubMarkup.failed + : skipped ? _GithubMarkup.skipped : defaultIcon; - final statusSuffix = failed - ? ' (failed)' - : skipped + final statusSuffix = + failed + ? ' (failed)' + : skipped ? ' (skipped)' : ''; @@ -152,7 +164,8 @@ class GithubReporter implements Reporter { } } if (_printPlatform) { - name = '[${test.suite.platform.runtime.name}, ' + name = + '[${test.suite.platform.runtime.name}, ' '${test.suite.platform.compiler.name}] $name'; } if (messages.isEmpty && errors.isEmpty) { @@ -185,7 +198,8 @@ class GithubReporter implements Reporter { } } if (_printPlatform) { - name = '[${test.suite.platform.runtime.name}, ' + name = + '[${test.suite.platform.runtime.name}, ' '${test.suite.platform.compiler.name}] $name'; } @@ -202,8 +216,10 @@ class GithubReporter implements Reporter { _sink.writeln(); final hadFailures = _engine.failed.isNotEmpty; - final message = StringBuffer('${_engine.passed.length} ' - '${pluralize('test', _engine.passed.length)} passed'); + final message = StringBuffer( + '${_engine.passed.length} ' + '${pluralize('test', _engine.passed.length)} passed', + ); if (_engine.failed.isNotEmpty) { message.write(', ${_engine.failed.length} failed'); } diff --git a/pkgs/test_core/lib/src/runner/reporter/json.dart b/pkgs/test_core/lib/src/runner/reporter/json.dart index 9f582eeab..13f834fa8 100644 --- a/pkgs/test_core/lib/src/runner/reporter/json.dart +++ b/pkgs/test_core/lib/src/runner/reporter/json.dart @@ -62,9 +62,11 @@ class JsonReporter implements Reporter { final StringSink _sink; /// Watches the tests run by [engine] and prints their results as JSON. - static JsonReporter watch(Engine engine, StringSink sink, - {required bool isDebugRun}) => - JsonReporter._(engine, sink, isDebugRun); + static JsonReporter watch( + Engine engine, + StringSink sink, { + required bool isDebugRun, + }) => JsonReporter._(engine, sink, isDebugRun); JsonReporter._(this._engine, this._sink, this._isDebugRun) { _subscriptions.add(_engine.onTestStarted.listen(_onTestStarted)); @@ -73,15 +75,23 @@ class JsonReporter implements Reporter { // canceled. _subscriptions.add(_engine.success.asStream().listen(_onDone)); - _subscriptions.add(_engine.onSuiteAdded.listen(null, onDone: () { - _emit('allSuites', { - 'count': _engine.addedSuites.length, - 'time': _stopwatch.elapsed.inMilliseconds - }); - })); - - _emit('start', - {'protocolVersion': '0.1.1', 'runnerVersion': testVersion, 'pid': pid}); + _subscriptions.add( + _engine.onSuiteAdded.listen( + null, + onDone: () { + _emit('allSuites', { + 'count': _engine.addedSuites.length, + 'time': _stopwatch.elapsed.inMilliseconds, + }); + }, + ), + ); + + _emit('start', { + 'protocolVersion': '0.1.1', + 'runnerVersion': testVersion, + 'pid': pid, + }); } @override @@ -126,9 +136,10 @@ class JsonReporter implements Reporter { // Don't emit groups for load suites. They're always empty and they provide // unnecessary clutter. - var groupIDs = liveTest.suite is LoadSuite - ? [] - : _idsForGroups(liveTest.groups, liveTest.suite); + var groupIDs = + liveTest.suite is LoadSuite + ? [] + : _idsForGroups(liveTest.groups, liveTest.suite); var suiteConfig = _configFor(liveTest.suite); var id = _nextID++; @@ -141,29 +152,36 @@ class JsonReporter implements Reporter { 'groupIDs': groupIDs, 'metadata': _serializeMetadata(suiteConfig, liveTest.test.metadata), ..._locationInfo( - suiteConfig, - liveTest.test.trace, - liveTest.test.location, - liveTest.suite.platform, - liveTest.suite.path!), - } + suiteConfig, + liveTest.test.trace, + liveTest.test.location, + liveTest.suite.platform, + liveTest.suite.path!, + ), + }, }); // Convert the future to a stream so that the subscription can be paused or // canceled. _subscriptions.add( - liveTest.onComplete.asStream().listen((_) => _onComplete(liveTest))); + liveTest.onComplete.asStream().listen((_) => _onComplete(liveTest)), + ); - _subscriptions.add(liveTest.onError - .listen((error) => _onError(liveTest, error.error, error.stackTrace))); + _subscriptions.add( + liveTest.onError.listen( + (error) => _onError(liveTest, error.error, error.stackTrace), + ), + ); - _subscriptions.add(liveTest.onMessage.listen((message) { - _emit('print', { - 'testID': id, - 'messageType': message.type.name, - 'message': message.text - }); - })); + _subscriptions.add( + liveTest.onMessage.listen((message) { + _emit('print', { + 'testID': id, + 'messageType': message.type.name, + 'message': message.text, + }); + }), + ); } /// Returns an ID for [suite]. @@ -199,8 +217,8 @@ class JsonReporter implements Reporter { 'suite': { 'id': id, 'platform': suite.platform.runtime.identifier, - 'path': suite.path - } + 'path': suite.path, + }, }); return id; } @@ -229,9 +247,14 @@ class JsonReporter implements Reporter { 'name': group.name, 'metadata': _serializeMetadata(suiteConfig, group.metadata), 'testCount': group.testCount, - ..._locationInfo(suiteConfig, group.trace, group.location, - suite.platform, suite.path!) - } + ..._locationInfo( + suiteConfig, + group.trace, + group.location, + suite.platform, + suite.path!, + ), + }, }); parentID = id; return id; @@ -250,7 +273,7 @@ class JsonReporter implements Reporter { 'testID': _liveTestIDs[liveTest], 'result': _normalizeTestResult(liveTest), 'skipped': liveTest.state.result == Result.skipped, - 'hidden': !_engine.liveTests.contains(liveTest) + 'hidden': !_engine.liveTests.contains(liveTest), }); } @@ -268,7 +291,7 @@ class JsonReporter implements Reporter { 'testID': _liveTestIDs[liveTest], 'error': error.toString(), 'stackTrace': '$stackTrace', - 'isFailure': error is TestFailure + 'isFailure': error is TestFailure, }); } @@ -304,11 +327,12 @@ class JsonReporter implements Reporter { /// or if the [trace] is null or empty, then the line, column, and url will /// all be `null`. Map _locationInfo( - SuiteConfiguration suiteConfig, - Trace? trace, - TestLocation? location, - SuitePlatform platform, - String suitePath) { + SuiteConfiguration suiteConfig, + Trace? trace, + TestLocation? location, + SuitePlatform platform, + String suitePath, + ) { // If this test has a location override, always use that. if (location != null) { return location.serialize(); @@ -320,9 +344,11 @@ class JsonReporter implements Reporter { return {'line': null, 'column': null, 'url': null}; } - var rootFrame = trace?.frames.firstWhereOrNull((frame) => - frame.uri.scheme == 'file' && - p.canonicalize(frame.uri.toFilePath()) == absoluteSuitePath); + var rootFrame = trace?.frames.firstWhereOrNull( + (frame) => + frame.uri.scheme == 'file' && + p.canonicalize(frame.uri.toFilePath()) == absoluteSuitePath, + ); return { 'line': frame.line, 'column': frame.column, @@ -331,7 +357,7 @@ class JsonReporter implements Reporter { 'root_line': rootFrame.line, 'root_column': rootFrame.column, 'root_url': rootFrame.uri.toString(), - } + }, }; } } diff --git a/pkgs/test_core/lib/src/runner/runner_suite.dart b/pkgs/test_core/lib/src/runner/runner_suite.dart index dcceb6b72..f1277134e 100644 --- a/pkgs/test_core/lib/src/runner/runner_suite.dart +++ b/pkgs/test_core/lib/src/runner/runner_suite.dart @@ -46,20 +46,35 @@ class RunnerSuite extends Suite { /// A shortcut constructor for creating a [RunnerSuite] that never goes into /// debugging mode and doesn't support suite channels. - factory RunnerSuite(Environment environment, SuiteConfiguration config, - Group group, SuitePlatform platform, - {String? path, void Function()? onClose}) { - var controller = - RunnerSuiteController._local(environment, config, onClose: onClose); + factory RunnerSuite( + Environment environment, + SuiteConfiguration config, + Group group, + SuitePlatform platform, { + String? path, + void Function()? onClose, + }) { + var controller = RunnerSuiteController._local( + environment, + config, + onClose: onClose, + ); var suite = RunnerSuite._(controller, group, platform, path: path); controller._suite = Future.value(suite); return suite; } - RunnerSuite._(this._controller, Group group, SuitePlatform platform, - {String? path}) - : super(group, platform, - path: path, ignoreTimeouts: _controller._config.ignoreTimeouts); + RunnerSuite._( + this._controller, + Group group, + SuitePlatform platform, { + String? path, + }) : super( + group, + platform, + path: path, + ignoreTimeouts: _controller._config.ignoreTimeouts, + ); @override RunnerSuite filter(bool Function(Test) callback) { @@ -109,25 +124,32 @@ class RunnerSuiteController { /// Collects a hit-map containing merged coverage. final Future> Function()? _gatherCoverage; - RunnerSuiteController(this._environment, this._config, this._suiteChannel, - Future groupFuture, SuitePlatform platform, - {String? path, - void Function()? onClose, - Future> Function()? gatherCoverage}) - : _onClose = onClose, - _gatherCoverage = gatherCoverage { - _suite = groupFuture - .then((group) => RunnerSuite._(this, group, platform, path: path)); + RunnerSuiteController( + this._environment, + this._config, + this._suiteChannel, + Future groupFuture, + SuitePlatform platform, { + String? path, + void Function()? onClose, + Future> Function()? gatherCoverage, + }) : _onClose = onClose, + _gatherCoverage = gatherCoverage { + _suite = groupFuture.then( + (group) => RunnerSuite._(this, group, platform, path: path), + ); } /// Used by [RunnerSuite.new] to create a runner suite that's not loaded from /// an external source. - RunnerSuiteController._local(this._environment, this._config, - {void Function()? onClose, - Future> Function()? gatherCoverage}) - : _suiteChannel = null, - _onClose = onClose, - _gatherCoverage = gatherCoverage; + RunnerSuiteController._local( + this._environment, + this._config, { + void Function()? onClose, + Future> Function()? gatherCoverage, + }) : _suiteChannel = null, + _onClose = onClose, + _gatherCoverage = gatherCoverage; /// Sets whether the suite is paused for debugging. /// @@ -160,16 +182,19 @@ class RunnerSuiteController { } var channel = suiteChannel.virtualChannel(); - suiteChannel.sink - .add({'type': 'suiteChannel', 'name': name, 'id': channel.id}); + suiteChannel.sink.add({ + 'type': 'suiteChannel', + 'name': name, + 'id': channel.id, + }); return channel; } /// The backing function for [suite.close]. Future _close() => _closeMemo.runOnce(() async { - await _onDebuggingController.close(); - var onClose = _onClose; - if (onClose != null) await onClose(); - }); + await _onDebuggingController.close(); + var onClose = _onClose; + if (onClose != null) await onClose(); + }); final _closeMemo = AsyncMemoizer(); } diff --git a/pkgs/test_core/lib/src/runner/runner_test.dart b/pkgs/test_core/lib/src/runner/runner_test.dart index 4819b601c..c76a498ff 100644 --- a/pkgs/test_core/lib/src/runner/runner_test.dart +++ b/pkgs/test_core/lib/src/runner/runner_test.dart @@ -33,73 +33,100 @@ class RunnerTest extends Test { final MultiChannel _channel; RunnerTest( - this.name, this.metadata, this.trace, this.location, this._channel); + this.name, + this.metadata, + this.trace, + this.location, + this._channel, + ); @override LiveTest load(Suite suite, {Iterable? groups}) { late final LiveTestController controller; late final VirtualChannel testChannel; - controller = LiveTestController(suite, this, () { - controller.setState(const State(Status.running, Result.success)); - - testChannel = _channel.virtualChannel(); - _channel.sink.add({'command': 'run', 'channel': testChannel.id}); - - testChannel.stream.listen((message) { - final msg = message as Map; - switch (msg['type'] as String) { - case 'error': - var asyncError = RemoteException.deserialize( - msg['error'] as Map); - var stackTrace = asyncError.stackTrace; - controller.addError(asyncError.error, stackTrace); - break; - - case 'state-change': - controller.setState(State(Status.parse(msg['status'] as String), - Result.parse(msg['result'] as String))); - break; - - case 'message': - controller.message(Message( - MessageType.parse(msg['message-type'] as String), - msg['text'] as String)); - break; - - case 'complete': + controller = LiveTestController( + suite, + this, + () { + controller.setState(const State(Status.running, Result.success)); + + testChannel = _channel.virtualChannel(); + _channel.sink.add({'command': 'run', 'channel': testChannel.id}); + + testChannel.stream.listen( + (message) { + final msg = message as Map; + switch (msg['type'] as String) { + case 'error': + var asyncError = RemoteException.deserialize( + msg['error'] as Map, + ); + var stackTrace = asyncError.stackTrace; + controller.addError(asyncError.error, stackTrace); + break; + + case 'state-change': + controller.setState( + State( + Status.parse(msg['status'] as String), + Result.parse(msg['result'] as String), + ), + ); + break; + + case 'message': + controller.message( + Message( + MessageType.parse(msg['message-type'] as String), + msg['text'] as String, + ), + ); + break; + + case 'complete': + controller.completer.complete(); + break; + + case 'spawn-hybrid-uri': + // When we kill the isolate that the test lives in, that will close + // this virtual channel and cause the spawned isolate to close as + // well. + spawnHybridUri( + msg['url'] as String, + msg['message'], + suite, + ).pipe( + testChannel.virtualChannel((msg['channel'] as num).toInt()), + ); + break; + } + }, + onDone: () { + // When the test channel closes—presumably because the browser + // closed—mark the test as complete no matter what. + if (controller.completer.isCompleted) return; controller.completer.complete(); - break; - - case 'spawn-hybrid-uri': - // When we kill the isolate that the test lives in, that will close - // this virtual channel and cause the spawned isolate to close as - // well. - spawnHybridUri(msg['url'] as String, msg['message'], suite).pipe( - testChannel.virtualChannel((msg['channel'] as num).toInt())); - break; + }, + ); + }, + () { + // If the test has finished running, just disconnect the channel. + if (controller.completer.isCompleted) { + testChannel.sink.close(); + return; } - }, onDone: () { - // When the test channel closes—presumably because the browser - // closed—mark the test as complete no matter what. - if (controller.completer.isCompleted) return; - controller.completer.complete(); - }); - }, () { - // If the test has finished running, just disconnect the channel. - if (controller.completer.isCompleted) { - testChannel.sink.close(); - return; - } - - unawaited(() async { - // If the test is still running, send it a message telling it to shut - // down ASAP. This causes the [Invoker] to eagerly throw exceptions - // whenever the test touches it. - testChannel.sink.add({'command': 'close'}); - await controller.completer.future; - await testChannel.sink.close(); - }()); - }, groups: groups); + + unawaited(() async { + // If the test is still running, send it a message telling it to shut + // down ASAP. This causes the [Invoker] to eagerly throw exceptions + // whenever the test touches it. + testChannel.sink.add({'command': 'close'}); + await controller.completer.future; + await testChannel.sink.close(); + }()); + }, + groups: groups, + ); return controller; } @@ -107,7 +134,12 @@ class RunnerTest extends Test { Test? forPlatform(SuitePlatform platform) { if (!metadata.testOn.evaluate(platform)) return null; return RunnerTest( - name, metadata.forPlatform(platform), trace, location, _channel); + name, + metadata.forPlatform(platform), + trace, + location, + _channel, + ); } @override diff --git a/pkgs/test_core/lib/src/runner/spawn_hybrid.dart b/pkgs/test_core/lib/src/runner/spawn_hybrid.dart index ed236b062..d758948bb 100644 --- a/pkgs/test_core/lib/src/runner/spawn_hybrid.dart +++ b/pkgs/test_core/lib/src/runner/spawn_hybrid.dart @@ -46,8 +46,10 @@ StreamChannel spawnHybridUri(String url, Object? message, Suite suite) { void main(_, List data) => listen(() => lib.hybridMain, data); '''; - var isolate = await dart.runInIsolate(code, [port.sendPort, message], - onExit: onExitPort.sendPort); + var isolate = await dart.runInIsolate(code, [ + port.sendPort, + message, + ], onExit: onExitPort.sendPort); // Ensure that we close [port] and [channel] when the isolate exits. var disconnector = Disconnector(); @@ -59,24 +61,31 @@ StreamChannel spawnHybridUri(String url, Object? message, Suite suite) { return IsolateChannel.connectReceive(port) .transform(disconnector) - .transformSink(StreamSinkTransformer.fromHandlers(handleDone: (sink) { - // If the user closes the stream channel, kill the isolate. - isolate.kill(); - port.close(); - onExitPort.close(); - sink.close(); - })); + .transformSink( + StreamSinkTransformer.fromHandlers( + handleDone: (sink) { + // If the user closes the stream channel, kill the isolate. + isolate.kill(); + port.close(); + onExitPort.close(); + sink.close(); + }, + ), + ); } catch (error, stackTrace) { port.close(); onExitPort.close(); // Make sure any errors in spawning the isolate are forwarded to the test. return StreamChannel( - Stream.fromFuture(Future.value({ + Stream.fromFuture( + Future.value({ 'type': 'error', - 'error': RemoteException.serialize(error, stackTrace) - })), - NullStreamSink()); + 'error': RemoteException.serialize(error, stackTrace), + }), + ), + NullStreamSink(), + ); } }()); } @@ -98,19 +107,25 @@ Future _normalizeUrl(String url, Suite suite) async { // We assume that the current path is the package root. `pub run` // enforces this currently, but at some point it would probably be good // to pass in an explicit root. - return p.url - .join(p.toUri(p.current).toString(), parsedUri.path.substring(1)); + return p.url.join( + p.toUri(p.current).toString(), + parsedUri.path.substring(1), + ); } else { var suitePath = suite.path!; return p.url.join( - p.url.dirname(p.toUri(p.absolute(suitePath)).toString()), - parsedUri.toString()); + p.url.dirname(p.toUri(p.absolute(suitePath)).toString()), + parsedUri.toString(), + ); } case 'package': final resolvedUri = await Isolate.resolvePackageUri(parsedUri); if (resolvedUri == null) { throw ArgumentError.value( - url, 'uri', 'Could not resolve the package URI'); + url, + 'uri', + 'Could not resolve the package URI', + ); } return resolvedUri.toString(); default: @@ -135,9 +150,10 @@ Future _languageVersionCommentFor(String url) async { // Returns the explicit language version comment if one exists. var result = parseString( - content: await _readUri(parsedUri), - path: parsedUri.scheme == 'data' ? null : p.fromUri(parsedUri), - throwIfDiagnostics: false); + content: await _readUri(parsedUri), + path: parsedUri.scheme == 'data' ? null : p.fromUri(parsedUri), + throwIfDiagnostics: false, + ); var languageVersionComment = result.unit.languageVersionToken?.value(); if (languageVersionComment != null) return languageVersionComment.toString(); @@ -160,8 +176,12 @@ Future _languageVersionCommentFor(String url) async { } Future _readUri(Uri uri) async => switch (uri.scheme) { - '' || 'file' => await File.fromUri(uri).readAsString(), - 'data' => uri.data!.contentAsString(), - _ => throw ArgumentError.value(uri, 'uri', - 'Only data and file uris (as well as relative paths) are supported'), - }; + '' || 'file' => await File.fromUri(uri).readAsString(), + 'data' => uri.data!.contentAsString(), + _ => + throw ArgumentError.value( + uri, + 'uri', + 'Only data and file uris (as well as relative paths) are supported', + ), +}; diff --git a/pkgs/test_core/lib/src/runner/suite.dart b/pkgs/test_core/lib/src/runner/suite.dart index b5ee0bea5..e4dbfed2c 100644 --- a/pkgs/test_core/lib/src/runner/suite.dart +++ b/pkgs/test_core/lib/src/runner/suite.dart @@ -45,19 +45,20 @@ final class SuiteConfiguration { /// Using this is slightly more efficient than manually constructing a new /// configuration with no arguments. static final empty = SuiteConfiguration._( - allowDuplicateTestNames: null, - allowTestRandomization: null, - jsTrace: null, - runSkipped: null, - dart2jsArgs: null, - testSelections: const {}, - precompiledPath: null, - runtimes: null, - compilerSelections: null, - tags: null, - onPlatform: null, - metadata: null, - ignoreTimeouts: null); + allowDuplicateTestNames: null, + allowTestRandomization: null, + jsTrace: null, + runSkipped: null, + dart2jsArgs: null, + testSelections: const {}, + precompiledPath: null, + runtimes: null, + compilerSelections: null, + tags: null, + onPlatform: null, + metadata: null, + ignoreTimeouts: null, + ); /// Whether or not duplicate test (or group) names are allowed within the same /// test suite. @@ -108,9 +109,10 @@ final class SuiteConfiguration { final List? compilerSelections; /// The set of runtimes on which to run tests. - List get runtimes => _runtimes == null - ? const ['vm'] - : List.unmodifiable(_runtimes.map((runtime) => runtime.name)); + List get runtimes => + _runtimes == null + ? const ['vm'] + : List.unmodifiable(_runtimes.map((runtime) => runtime.name)); final List? _runtimes; /// Configuration for particular tags. @@ -130,9 +132,11 @@ final class SuiteConfiguration { Metadata get metadata { if (tags.isEmpty && onPlatform.isEmpty) return _metadata; return _metadata.change( - forTag: tags.map((key, config) => MapEntry(key, config.metadata)), - onPlatform: - onPlatform.map((key, config) => MapEntry(key, config.metadata))); + forTag: tags.map((key, config) => MapEntry(key, config.metadata)), + onPlatform: onPlatform.map( + (key, config) => MapEntry(key, config.metadata), + ), + ); } final Metadata _metadata; @@ -149,50 +153,53 @@ final class SuiteConfiguration { final bool? _ignoreTimeouts; bool get ignoreTimeouts => _ignoreTimeouts ?? false; - factory SuiteConfiguration( - {required bool? allowDuplicateTestNames, - required bool? allowTestRandomization, - required bool? jsTrace, - required bool? runSkipped, - required Iterable? dart2jsArgs, - required String? precompiledPath, - required Iterable? compilerSelections, - required Iterable? runtimes, - required Map? tags, - required Map? onPlatform, - required bool? ignoreTimeouts, - - // Test-level configuration - required Timeout? timeout, - required bool? verboseTrace, - required bool? chainStackTraces, - required bool? skip, - required int? retry, - required String? skipReason, - required PlatformSelector? testOn, - required Iterable? addTags}) { + factory SuiteConfiguration({ + required bool? allowDuplicateTestNames, + required bool? allowTestRandomization, + required bool? jsTrace, + required bool? runSkipped, + required Iterable? dart2jsArgs, + required String? precompiledPath, + required Iterable? compilerSelections, + required Iterable? runtimes, + required Map? tags, + required Map? onPlatform, + required bool? ignoreTimeouts, + + // Test-level configuration + required Timeout? timeout, + required bool? verboseTrace, + required bool? chainStackTraces, + required bool? skip, + required int? retry, + required String? skipReason, + required PlatformSelector? testOn, + required Iterable? addTags, + }) { var config = SuiteConfiguration._( - allowDuplicateTestNames: allowDuplicateTestNames, - allowTestRandomization: allowTestRandomization, - jsTrace: jsTrace, - runSkipped: runSkipped, - dart2jsArgs: dart2jsArgs, - testSelections: const {}, - precompiledPath: precompiledPath, - compilerSelections: compilerSelections, - runtimes: runtimes, - tags: tags, - onPlatform: onPlatform, - ignoreTimeouts: ignoreTimeouts, - metadata: Metadata( - timeout: timeout, - verboseTrace: verboseTrace, - chainStackTraces: chainStackTraces, - skip: skip, - retry: retry, - skipReason: skipReason, - testOn: testOn, - tags: addTags)); + allowDuplicateTestNames: allowDuplicateTestNames, + allowTestRandomization: allowTestRandomization, + jsTrace: jsTrace, + runSkipped: runSkipped, + dart2jsArgs: dart2jsArgs, + testSelections: const {}, + precompiledPath: precompiledPath, + compilerSelections: compilerSelections, + runtimes: runtimes, + tags: tags, + onPlatform: onPlatform, + ignoreTimeouts: ignoreTimeouts, + metadata: Metadata( + timeout: timeout, + verboseTrace: verboseTrace, + chainStackTraces: chainStackTraces, + skip: skip, + retry: retry, + skipReason: skipReason, + testOn: testOn, + tags: addTags, + ), + ); return config._resolveTags(); } @@ -200,48 +207,49 @@ final class SuiteConfiguration { /// /// This should only be used in situations where you really only want to /// configure a specific restricted set of options. - factory SuiteConfiguration._unsafe( - {bool? allowDuplicateTestNames, - bool? allowTestRandomization, - bool? jsTrace, - bool? runSkipped, - Iterable? dart2jsArgs, - String? precompiledPath, - Iterable? compilerSelections, - Iterable? runtimes, - Map? tags, - Map? onPlatform, - bool? ignoreTimeouts, - - // Test-level configuration - Timeout? timeout, - bool? verboseTrace, - bool? chainStackTraces, - bool? skip, - int? retry, - String? skipReason, - PlatformSelector? testOn, - Iterable? addTags}) => - SuiteConfiguration( - allowDuplicateTestNames: allowDuplicateTestNames, - allowTestRandomization: allowTestRandomization, - jsTrace: jsTrace, - runSkipped: runSkipped, - dart2jsArgs: dart2jsArgs, - precompiledPath: precompiledPath, - compilerSelections: compilerSelections, - runtimes: runtimes, - tags: tags, - onPlatform: onPlatform, - ignoreTimeouts: ignoreTimeouts, - timeout: timeout, - verboseTrace: verboseTrace, - chainStackTraces: chainStackTraces, - skip: skip, - retry: retry, - skipReason: skipReason, - testOn: testOn, - addTags: addTags); + factory SuiteConfiguration._unsafe({ + bool? allowDuplicateTestNames, + bool? allowTestRandomization, + bool? jsTrace, + bool? runSkipped, + Iterable? dart2jsArgs, + String? precompiledPath, + Iterable? compilerSelections, + Iterable? runtimes, + Map? tags, + Map? onPlatform, + bool? ignoreTimeouts, + + // Test-level configuration + Timeout? timeout, + bool? verboseTrace, + bool? chainStackTraces, + bool? skip, + int? retry, + String? skipReason, + PlatformSelector? testOn, + Iterable? addTags, + }) => SuiteConfiguration( + allowDuplicateTestNames: allowDuplicateTestNames, + allowTestRandomization: allowTestRandomization, + jsTrace: jsTrace, + runSkipped: runSkipped, + dart2jsArgs: dart2jsArgs, + precompiledPath: precompiledPath, + compilerSelections: compilerSelections, + runtimes: runtimes, + tags: tags, + onPlatform: onPlatform, + ignoreTimeouts: ignoreTimeouts, + timeout: timeout, + verboseTrace: verboseTrace, + chainStackTraces: chainStackTraces, + skip: skip, + retry: retry, + skipReason: skipReason, + testOn: testOn, + addTags: addTags, + ); /// A specialized constructor for only configuring the runtimes. factory SuiteConfiguration.runtimes(Iterable runtimes) => @@ -273,26 +281,28 @@ final class SuiteConfiguration { required Map? onPlatform, required Metadata? metadata, required bool? ignoreTimeouts, - }) : _allowDuplicateTestNames = allowDuplicateTestNames, - _allowTestRandomization = allowTestRandomization, - _jsTrace = jsTrace, - _runSkipped = runSkipped, - dart2jsArgs = _list(dart2jsArgs) ?? const [], - _runtimes = _list(runtimes), - compilerSelections = _list(compilerSelections), - tags = _map(tags), - onPlatform = _map(onPlatform), - _ignoreTimeouts = ignoreTimeouts, - _metadata = metadata ?? Metadata.empty; + }) : _allowDuplicateTestNames = allowDuplicateTestNames, + _allowTestRandomization = allowTestRandomization, + _jsTrace = jsTrace, + _runSkipped = runSkipped, + dart2jsArgs = _list(dart2jsArgs) ?? const [], + _runtimes = _list(runtimes), + compilerSelections = _list(compilerSelections), + tags = _map(tags), + onPlatform = _map(onPlatform), + _ignoreTimeouts = ignoreTimeouts, + _metadata = metadata ?? Metadata.empty; /// Creates a new [SuiteConfiguration] that takes its configuration from /// [metadata]. factory SuiteConfiguration.fromMetadata(Metadata metadata) => SuiteConfiguration._( - tags: metadata.forTag.map((key, child) => - MapEntry(key, SuiteConfiguration.fromMetadata(child))), - onPlatform: metadata.onPlatform.map((key, child) => - MapEntry(key, SuiteConfiguration.fromMetadata(child))), + tags: metadata.forTag.map( + (key, child) => MapEntry(key, SuiteConfiguration.fromMetadata(child)), + ), + onPlatform: metadata.onPlatform.map( + (key, child) => MapEntry(key, SuiteConfiguration.fromMetadata(child)), + ), metadata: metadata.change(forTag: {}, onPlatform: {}), allowDuplicateTestNames: null, allowTestRandomization: null, @@ -333,22 +343,23 @@ final class SuiteConfiguration { assert(testSelections.isEmpty || other.testSelections.isEmpty); var config = SuiteConfiguration._( - allowDuplicateTestNames: - other._allowDuplicateTestNames ?? _allowDuplicateTestNames, - allowTestRandomization: - other._allowTestRandomization ?? _allowTestRandomization, - jsTrace: other._jsTrace ?? _jsTrace, - runSkipped: other._runSkipped ?? _runSkipped, - dart2jsArgs: dart2jsArgs.toList()..addAll(other.dart2jsArgs), - testSelections: - testSelections.isEmpty ? other.testSelections : testSelections, - precompiledPath: other.precompiledPath ?? precompiledPath, - compilerSelections: other.compilerSelections ?? compilerSelections, - runtimes: other._runtimes ?? _runtimes, - tags: _mergeConfigMaps(tags, other.tags), - onPlatform: _mergeConfigMaps(onPlatform, other.onPlatform), - ignoreTimeouts: other._ignoreTimeouts ?? _ignoreTimeouts, - metadata: metadata.merge(other.metadata)); + allowDuplicateTestNames: + other._allowDuplicateTestNames ?? _allowDuplicateTestNames, + allowTestRandomization: + other._allowTestRandomization ?? _allowTestRandomization, + jsTrace: other._jsTrace ?? _jsTrace, + runSkipped: other._runSkipped ?? _runSkipped, + dart2jsArgs: dart2jsArgs.toList()..addAll(other.dart2jsArgs), + testSelections: + testSelections.isEmpty ? other.testSelections : testSelections, + precompiledPath: other.precompiledPath ?? precompiledPath, + compilerSelections: other.compilerSelections ?? compilerSelections, + runtimes: other._runtimes ?? _runtimes, + tags: _mergeConfigMaps(tags, other.tags), + onPlatform: _mergeConfigMaps(onPlatform, other.onPlatform), + ignoreTimeouts: other._ignoreTimeouts ?? _ignoreTimeouts, + metadata: metadata.merge(other.metadata), + ); return config._resolveTags(); } @@ -356,52 +367,54 @@ final class SuiteConfiguration { /// /// Note that unlike [merge], this has no merging behavior—the old value is /// always replaced by the new one. - SuiteConfiguration change( - {bool? allowDuplicateTestNames, - bool? allowTestRandomization, - bool? jsTrace, - bool? runSkipped, - Iterable? dart2jsArgs, - String? precompiledPath, - Iterable? compilerSelections, - Iterable? runtimes, - Map? tags, - Map? onPlatform, - bool? ignoreTimeouts, - - // Test-level configuration - Timeout? timeout, - bool? verboseTrace, - bool? chainStackTraces, - bool? skip, - int? retry, - String? skipReason, - PlatformSelector? testOn, - Iterable? addTags}) { + SuiteConfiguration change({ + bool? allowDuplicateTestNames, + bool? allowTestRandomization, + bool? jsTrace, + bool? runSkipped, + Iterable? dart2jsArgs, + String? precompiledPath, + Iterable? compilerSelections, + Iterable? runtimes, + Map? tags, + Map? onPlatform, + bool? ignoreTimeouts, + + // Test-level configuration + Timeout? timeout, + bool? verboseTrace, + bool? chainStackTraces, + bool? skip, + int? retry, + String? skipReason, + PlatformSelector? testOn, + Iterable? addTags, + }) { var config = SuiteConfiguration._( - allowDuplicateTestNames: - allowDuplicateTestNames ?? _allowDuplicateTestNames, - allowTestRandomization: - allowTestRandomization ?? _allowTestRandomization, - jsTrace: jsTrace ?? _jsTrace, - runSkipped: runSkipped ?? _runSkipped, - dart2jsArgs: dart2jsArgs?.toList() ?? this.dart2jsArgs, - testSelections: testSelections, - precompiledPath: precompiledPath ?? this.precompiledPath, - compilerSelections: compilerSelections ?? this.compilerSelections, - runtimes: runtimes ?? _runtimes, - tags: tags ?? this.tags, - onPlatform: onPlatform ?? this.onPlatform, - ignoreTimeouts: ignoreTimeouts ?? _ignoreTimeouts, - metadata: _metadata.change( - timeout: timeout, - verboseTrace: verboseTrace, - chainStackTraces: chainStackTraces, - skip: skip, - retry: retry, - skipReason: skipReason, - testOn: testOn, - tags: addTags?.toSet())); + allowDuplicateTestNames: + allowDuplicateTestNames ?? _allowDuplicateTestNames, + allowTestRandomization: allowTestRandomization ?? _allowTestRandomization, + jsTrace: jsTrace ?? _jsTrace, + runSkipped: runSkipped ?? _runSkipped, + dart2jsArgs: dart2jsArgs?.toList() ?? this.dart2jsArgs, + testSelections: testSelections, + precompiledPath: precompiledPath ?? this.precompiledPath, + compilerSelections: compilerSelections ?? this.compilerSelections, + runtimes: runtimes ?? _runtimes, + tags: tags ?? this.tags, + onPlatform: onPlatform ?? this.onPlatform, + ignoreTimeouts: ignoreTimeouts ?? _ignoreTimeouts, + metadata: _metadata.change( + timeout: timeout, + verboseTrace: verboseTrace, + chainStackTraces: chainStackTraces, + skip: skip, + retry: retry, + skipReason: skipReason, + testOn: testOn, + tags: addTags?.toSet(), + ), + ); return config._resolveTags(); } @@ -416,19 +429,20 @@ final class SuiteConfiguration { assert(this.testSelections.isEmpty); assert(testSelections.isNotEmpty); return SuiteConfiguration._( - testSelections: testSelections, - allowDuplicateTestNames: _allowDuplicateTestNames, - allowTestRandomization: _allowTestRandomization, - jsTrace: _jsTrace, - runSkipped: _runSkipped, - dart2jsArgs: dart2jsArgs, - precompiledPath: precompiledPath, - compilerSelections: compilerSelections, - runtimes: _runtimes, - tags: tags, - onPlatform: onPlatform, - ignoreTimeouts: _ignoreTimeouts, - metadata: _metadata); + testSelections: testSelections, + allowDuplicateTestNames: _allowDuplicateTestNames, + allowTestRandomization: _allowTestRandomization, + jsTrace: _jsTrace, + runSkipped: _runSkipped, + dart2jsArgs: dart2jsArgs, + precompiledPath: precompiledPath, + compilerSelections: compilerSelections, + runtimes: _runtimes, + tags: tags, + onPlatform: onPlatform, + ignoreTimeouts: _ignoreTimeouts, + metadata: _metadata, + ); } /// Throws a [FormatException] if this refers to any undefined runtimes. @@ -440,11 +454,14 @@ final class SuiteConfiguration { var runtimes = _runtimes; if (runtimes != null) { for (var selection in runtimes) { - if (!allRuntimes - .any((runtime) => runtime.identifier == selection.name)) { + if (!allRuntimes.any( + (runtime) => runtime.identifier == selection.name, + )) { if (selection.span != null) { throw SourceSpanFormatException( - 'Unknown platform "${selection.name}".', selection.span); + 'Unknown platform "${selection.name}".', + selection.span, + ); } else { throw FormatException('Unknown platform "${selection.name}".'); } @@ -476,9 +493,13 @@ final class SuiteConfiguration { /// Any overlapping keys in the maps have their configurations merged in the /// returned map. Map _mergeConfigMaps( - Map map1, Map map2) => - mergeMaps(map1, map2, - value: (config1, config2) => config1.merge(config2)); + Map map1, + Map map2, + ) => mergeMaps( + map1, + map2, + value: (config1, config2) => config1.merge(config2), + ); SuiteConfiguration _resolveTags() { // If there's no tag-specific configuration, or if none of it applies, just diff --git a/pkgs/test_core/lib/src/runner/version.dart b/pkgs/test_core/lib/src/runner/version.dart index 3eab242c1..aff679111 100644 --- a/pkgs/test_core/lib/src/runner/version.dart +++ b/pkgs/test_core/lib/src/runner/version.dart @@ -10,51 +10,52 @@ import 'package:yaml/yaml.dart'; /// /// This is a semantic version, optionally followed by a space and additional /// data about its source. -final String? testVersion = (() { - dynamic lockfile; - try { - lockfile = loadYaml(File('pubspec.lock').readAsStringSync()); - } on FormatException catch (_) { - return null; - } on IOException catch (_) { - return null; - } - - if (lockfile is! Map) return null; - var packages = lockfile['packages']; - if (packages is! Map) return null; - var package = packages['test']; - if (package is! Map) return null; - - var source = package['source']; - if (source is! String) return null; - - switch (source) { - case 'hosted': - var version = package['version']; - return (version is String) ? version : null; - - case 'git': - var version = package['version']; - if (version is! String) return null; - var description = package['description']; - if (description is! Map) return null; - var ref = description['resolved-ref']; - if (ref is! String) return null; - - return '$version (${ref.substring(0, 7)})'; - - case 'path': - var version = package['version']; - if (version is! String) return null; - var description = package['description']; - if (description is! Map) return null; - var path = description['path']; - if (path is! String) return null; - - return '$version (from $path)'; - - default: - return null; - } -})(); +final String? testVersion = + (() { + dynamic lockfile; + try { + lockfile = loadYaml(File('pubspec.lock').readAsStringSync()); + } on FormatException catch (_) { + return null; + } on IOException catch (_) { + return null; + } + + if (lockfile is! Map) return null; + var packages = lockfile['packages']; + if (packages is! Map) return null; + var package = packages['test']; + if (package is! Map) return null; + + var source = package['source']; + if (source is! String) return null; + + switch (source) { + case 'hosted': + var version = package['version']; + return (version is String) ? version : null; + + case 'git': + var version = package['version']; + if (version is! String) return null; + var description = package['description']; + if (description is! Map) return null; + var ref = description['resolved-ref']; + if (ref is! String) return null; + + return '$version (${ref.substring(0, 7)})'; + + case 'path': + var version = package['version']; + if (version is! String) return null; + var description = package['description']; + if (description is! Map) return null; + var path = description['path']; + if (path is! String) return null; + + return '$version (from $path)'; + + default: + return null; + } + })(); diff --git a/pkgs/test_core/lib/src/runner/vm/environment.dart b/pkgs/test_core/lib/src/runner/vm/environment.dart index 206570935..609118e25 100644 --- a/pkgs/test_core/lib/src/runner/vm/environment.dart +++ b/pkgs/test_core/lib/src/runner/vm/environment.dart @@ -30,12 +30,19 @@ class VMEnvironment implements Environment { @override CancelableOperation displayPause() { - var completer = - CancelableCompleter(onCancel: () => _client.resume(_isolate.id!)); - - completer.complete(_client.pause(_isolate.id!).then((_) => _client - .onDebugEvent - .firstWhere((event) => event.kind == EventKind.kResume))); + var completer = CancelableCompleter( + onCancel: () => _client.resume(_isolate.id!), + ); + + completer.complete( + _client + .pause(_isolate.id!) + .then( + (_) => _client.onDebugEvent.firstWhere( + (event) => event.kind == EventKind.kResume, + ), + ), + ); return completer.operation; } diff --git a/pkgs/test_core/lib/src/runner/vm/platform.dart b/pkgs/test_core/lib/src/runner/vm/platform.dart index f2586abfb..77e8cba2c 100644 --- a/pkgs/test_core/lib/src/runner/vm/platform.dart +++ b/pkgs/test_core/lib/src/runner/vm/platform.dart @@ -38,13 +38,18 @@ class VMPlatform extends PlatformPlugin { /// The test runner configuration. final _config = Configuration.current; final _compiler = TestCompiler( - p.join(p.current, '.dart_tool', 'test', 'incremental_kernel')); + p.join(p.current, '.dart_tool', 'test', 'incremental_kernel'), + ); final _closeMemo = AsyncMemoizer(); final _tempDir = Directory.systemTemp.createTempSync('dart_test.vm.'); @override - Future load(String path, SuitePlatform platform, - SuiteConfiguration suiteConfig, Map message) async { + Future load( + String path, + SuitePlatform platform, + SuiteConfiguration suiteConfig, + Map message, + ) async { assert(platform.runtime == Runtime.vm); _setupPauseAfterTests(); @@ -56,8 +61,11 @@ class VMPlatform extends PlatformPlugin { var serverSocket = await ServerSocket.bind('localhost', 0); Process process; try { - process = - await _spawnExecutable(path, suiteConfig.metadata, serverSocket); + process = await _spawnExecutable( + path, + suiteConfig.metadata, + serverSocket, + ); } catch (error) { unawaited(serverSocket.close()); rethrow; @@ -72,8 +80,12 @@ class VMPlatform extends PlatformPlugin { } else { var receivePort = ReceivePort(); try { - isolate = await _spawnIsolate(path, receivePort.sendPort, - suiteConfig.metadata, platform.compiler); + isolate = await _spawnIsolate( + path, + receivePort.sendPort, + suiteConfig.metadata, + platform.compiler, + ); if (isolate == null) return null; } catch (error) { receivePort.close(); @@ -91,30 +103,38 @@ class VMPlatform extends PlatformPlugin { // platform to enable pausing after tests for debugging. var outerQueue = StreamQueue(outerChannel.stream); var channelId = (await outerQueue.next) as int; - var channel = outerChannel.virtualChannel(channelId).transformStream( - StreamTransformer.fromHandlers(handleDone: (sink) async { - if (_shouldPauseAfterTests) { - outerChannel.sink.add('debug'); - await outerQueue.next; - } - for (var fn in cleanupCallbacks) { - fn(); - } - unawaited(eventSub?.cancel()); - unawaited(client?.dispose()); - sink.close(); - })); + var channel = outerChannel + .virtualChannel(channelId) + .transformStream( + StreamTransformer.fromHandlers( + handleDone: (sink) async { + if (_shouldPauseAfterTests) { + outerChannel.sink.add('debug'); + await outerQueue.next; + } + for (var fn in cleanupCallbacks) { + fn(); + } + unawaited(eventSub?.cancel()); + unawaited(client?.dispose()); + sink.close(); + }, + ), + ); Environment? environment; IsolateRef? isolateRef; if (_config.debug) { if (platform.compiler == Compiler.exe) { throw UnsupportedError( - 'Unable to debug tests compiled to `exe` (tried to debug $path with ' - 'the `exe` compiler).'); + 'Unable to debug tests compiled to `exe` (tried to debug $path with ' + 'the `exe` compiler).', + ); } - var info = - await Service.controlWebServer(enable: true, silenceOutput: true); + var info = await Service.controlWebServer( + enable: true, + silenceOutput: true, + ); // ignore: deprecated_member_use, Remove when SDK constraint is at 3.2.0 var isolateID = Service.getIsolateID(isolate!)!; @@ -122,13 +142,13 @@ class VMPlatform extends PlatformPlugin { var serverUri = info.serverUri!; client = await vmServiceConnectUri(_wsUriFor(serverUri).toString()); var isolateNumber = int.parse(isolateID.split('/').last); - isolateRef = (await client.getVM()) - .isolates! - .firstWhere((isolate) => isolate.number == isolateNumber.toString()); + isolateRef = (await client.getVM()).isolates!.firstWhere( + (isolate) => isolate.number == isolateNumber.toString(), + ); await client.setName(isolateRef.id!, path); - var libraryRef = (await client.getIsolate(isolateRef.id!)) - .libraries! - .firstWhere((library) => library.uri == libraryPath); + var libraryRef = (await client.getIsolate( + isolateRef.id!, + )).libraries!.firstWhere((library) => library.uri == libraryPath); var url = _observatoryUrlFor(serverUri, isolateRef.id!, libraryRef.id!); environment = VMEnvironment(url, isolateRef, client); } @@ -136,8 +156,14 @@ class VMPlatform extends PlatformPlugin { environment ??= const PluginEnvironment(); var controller = deserializeSuite( - path, platform, suiteConfig, environment, channel.cast(), message, - gatherCoverage: () => _gatherCoverage(environment!)); + path, + platform, + suiteConfig, + environment, + channel.cast(), + message, + gatherCoverage: () => _gatherCoverage(environment!), + ); if (isolateRef != null) { await client!.streamListen('Debug'); @@ -156,32 +182,38 @@ class VMPlatform extends PlatformPlugin { } @override - Future close() => _closeMemo.runOnce(() => Future.wait([ - _compiler.dispose(), - _tempDir.deleteWithRetry(), - ])); + Future close() => _closeMemo.runOnce( + () => Future.wait([_compiler.dispose(), _tempDir.deleteWithRetry()]), + ); /// Compiles [path] to a native executable and spawns it as a process. /// /// Sets up a communication channel as well by passing command line arguments /// for the host and port of [socket]. Future _spawnExecutable( - String path, Metadata suiteMetadata, ServerSocket socket) async { + String path, + Metadata suiteMetadata, + ServerSocket socket, + ) async { if (_config.suiteDefaults.precompiledPath != null) { throw UnsupportedError( - 'Precompiled native executable tests are not supported at this time'); + 'Precompiled native executable tests are not supported at this time', + ); } var executable = await _compileToNative(path, suiteMetadata); - return await Process.start( - executable, [socket.address.host, socket.port.toString()]); + return await Process.start(executable, [ + socket.address.host, + socket.port.toString(), + ]); } /// Compiles [path] to a native executable using `dart compile exe`. Future _compileToNative(String path, Metadata suiteMetadata) async { var bootstrapPath = await _bootstrapNativeTestFile( - path, - suiteMetadata.languageVersionComment ?? - await rootPackageLanguageVersionComment); + path, + suiteMetadata.languageVersionComment ?? + await rootPackageLanguageVersionComment, + ); var output = File(p.setExtension(bootstrapPath, '.exe')); var processResult = await Process.run(Platform.resolvedExecutable, [ 'compile', @@ -207,25 +239,39 @@ stderr: ${processResult.stderr}'''); /// serialized tests over that channel. /// /// Returns `null` if an exception occurs but [close] has already been called. - Future _spawnIsolate(String path, SendPort message, - Metadata suiteMetadata, Compiler compiler) async { + Future _spawnIsolate( + String path, + SendPort message, + Metadata suiteMetadata, + Compiler compiler, + ) async { try { var precompiledPath = _config.suiteDefaults.precompiledPath; if (precompiledPath != null) { return _spawnPrecompiledIsolate( - path, message, precompiledPath, compiler); + path, + message, + precompiledPath, + compiler, + ); } return switch (compiler) { Compiler.kernel => _spawnIsolateWithUri( - await _compileToKernel(path, suiteMetadata), message), + await _compileToKernel(path, suiteMetadata), + message, + ), Compiler.source => _spawnIsolateWithUri( - await _bootstrapIsolateTestFile( - path, - suiteMetadata.languageVersionComment ?? - await rootPackageLanguageVersionComment), - message), - _ => throw StateError( - 'Unsupported compiler $compiler for the VM platform'), + await _bootstrapIsolateTestFile( + path, + suiteMetadata.languageVersionComment ?? + await rootPackageLanguageVersionComment, + ), + message, + ), + _ => + throw StateError( + 'Unsupported compiler $compiler for the VM platform', + ), }; } catch (_) { if (_closeMemo.hasRun) return null; @@ -235,8 +281,10 @@ stderr: ${processResult.stderr}'''); /// Compiles [path] to kernel and returns the uri to the compiled dill. Future _compileToKernel(String path, Metadata suiteMetadata) async { - final response = - await _compiler.compile(await absoluteUri(path), suiteMetadata); + final response = await _compiler.compile( + await absoluteUri(path), + suiteMetadata, + ); var compiledDill = response.kernelOutputUri?.toFilePath(); if (compiledDill == null || response.errorCount > 0) { throw LoadException(path, response.compilerOutput ?? 'unknown error'); @@ -256,19 +304,28 @@ stderr: ${processResult.stderr}'''); ); } - Future _spawnPrecompiledIsolate(String testPath, SendPort message, - String precompiledPath, Compiler compiler) async { - var testUri = - await absoluteUri('${p.join(precompiledPath, testPath)}.vm_test.dart'); + Future _spawnPrecompiledIsolate( + String testPath, + SendPort message, + String precompiledPath, + Compiler compiler, + ) async { + var testUri = await absoluteUri( + '${p.join(precompiledPath, testPath)}.vm_test.dart', + ); testUri = testUri.replace(path: testUri.path.stripDriveLetterLeadingSlash); switch (compiler) { case Compiler.kernel: // Load `.dill` files from their absolute file path. - var dillUri = (await Isolate.resolvePackageUri(testUri.replace( - path: - '${testUri.path.substring(0, testUri.path.length - '.dart'.length)}' - '.vm.app.dill')))!; + var dillUri = + (await Isolate.resolvePackageUri( + testUri.replace( + path: + '${testUri.path.substring(0, testUri.path.length - '.dart'.length)}' + '.vm.app.dill', + ), + ))!; if (await File.fromUri(dillUri).exists()) { testUri = dillUri; } @@ -282,8 +339,9 @@ stderr: ${processResult.stderr}'''); default: throw StateError('Unsupported compiler for the VM platform $compiler.'); } - File? packageConfig = - File(p.join(precompiledPath, '.dart_tool/package_config.json')); + File? packageConfig = File( + p.join(precompiledPath, '.dart_tool/package_config.json'), + ); if (!(await packageConfig.exists())) { packageConfig = File(p.join(precompiledPath, '.packages')); if (!(await packageConfig.exists())) { @@ -305,18 +363,26 @@ stderr: ${processResult.stderr}'''); /// /// Returns the [Uri] to the created file. Future _bootstrapIsolateTestFile( - String testPath, String languageVersionComment) async { - var file = File(p.join( - _tempDir.path, p.setExtension(testPath, '.bootstrap.isolate.dart'))); + String testPath, + String languageVersionComment, + ) async { + var file = File( + p.join( + _tempDir.path, + p.setExtension(testPath, '.bootstrap.isolate.dart'), + ), + ); if (!file.existsSync()) { file ..createSync(recursive: true) - ..writeAsStringSync(testBootstrapContents( - testUri: await absoluteUri(testPath), - languageVersionComment: languageVersionComment, - packageConfigUri: await packageConfigUri, - testType: VmTestType.isolate, - )); + ..writeAsStringSync( + testBootstrapContents( + testUri: await absoluteUri(testPath), + languageVersionComment: languageVersionComment, + packageConfigUri: await packageConfigUri, + testType: VmTestType.isolate, + ), + ); } return file.uri; } @@ -326,37 +392,53 @@ stderr: ${processResult.stderr}'''); /// /// Returns the path to the created file. Future _bootstrapNativeTestFile( - String testPath, String languageVersionComment) async { - var file = File(p.join( - _tempDir.path, p.setExtension(testPath, '.bootstrap.native.dart'))); + String testPath, + String languageVersionComment, + ) async { + var file = File( + p.join(_tempDir.path, p.setExtension(testPath, '.bootstrap.native.dart')), + ); if (!file.existsSync()) { file ..createSync(recursive: true) - ..writeAsStringSync(testBootstrapContents( - testUri: await absoluteUri(testPath), - languageVersionComment: languageVersionComment, - packageConfigUri: await packageConfigUri, - testType: VmTestType.process, - )); + ..writeAsStringSync( + testBootstrapContents( + testUri: await absoluteUri(testPath), + languageVersionComment: languageVersionComment, + packageConfigUri: await packageConfigUri, + testType: VmTestType.process, + ), + ); } return file.path; } } Future> _gatherCoverage(Environment environment) async { - final isolateId = Uri.parse(environment.observatoryUrl!.fragment) - .queryParameters['isolateId']; - return await collect(environment.observatoryUrl!, false, false, false, {}, - isolateIds: {isolateId!}); + final isolateId = + Uri.parse( + environment.observatoryUrl!.fragment, + ).queryParameters['isolateId']; + return await collect( + environment.observatoryUrl!, + false, + false, + false, + {}, + isolateIds: {isolateId!}, + ); } Uri _wsUriFor(Uri observatoryUrl) => observatoryUrl.replace(scheme: 'ws').resolve('ws'); Uri _observatoryUrlFor(Uri base, String isolateId, String id) => base.replace( - fragment: Uri( + fragment: + Uri( path: '/inspect', - queryParameters: {'isolateId': isolateId, 'objectId': id}).toString()); + queryParameters: {'isolateId': isolateId, 'objectId': id}, + ).toString(), +); var _hasRegistered = false; void _setupPauseAfterTests() { diff --git a/pkgs/test_core/lib/src/runner/vm/test_compiler.dart b/pkgs/test_core/lib/src/runner/vm/test_compiler.dart index b2107b6a1..625cab1fd 100644 --- a/pkgs/test_core/lib/src/runner/vm/test_compiler.dart +++ b/pkgs/test_core/lib/src/runner/vm/test_compiler.dart @@ -22,11 +22,16 @@ class CompilationResponse { final int errorCount; final Uri? kernelOutputUri; - const CompilationResponse( - {this.compilerOutput, this.errorCount = 0, this.kernelOutputUri}); + const CompilationResponse({ + this.compilerOutput, + this.errorCount = 0, + this.kernelOutputUri, + }); static const _wasShutdown = CompilationResponse( - errorCount: 1, compilerOutput: 'Compiler no longer active.'); + errorCount: 1, + compilerOutput: 'Compiler no longer active.', + ); } class TestCompiler { @@ -49,19 +54,25 @@ class TestCompiler { /// the tests. Future compile(Uri mainDart, Metadata metadata) async { if (_closeMemo.hasRun) return CompilationResponse._wasShutdown; - var languageVersionComment = metadata.languageVersionComment ?? + var languageVersionComment = + metadata.languageVersionComment ?? await rootPackageLanguageVersionComment; var compiler = _compilerForLanguageVersion.putIfAbsent( + languageVersionComment, + () => _TestCompilerForLanguageVersion( + _dillCachePrefix, languageVersionComment, - () => _TestCompilerForLanguageVersion( - _dillCachePrefix, languageVersionComment)); + ), + ); return compiler.compile(mainDart); } - Future dispose() => _closeMemo.runOnce(() => Future.wait([ - for (var compiler in _compilerForLanguageVersion.values) - compiler.dispose(), - ])); + Future dispose() => _closeMemo.runOnce( + () => Future.wait([ + for (var compiler in _compilerForLanguageVersion.values) + compiler.dispose(), + ]), + ); } class _TestCompilerForLanguageVersion { @@ -70,10 +81,12 @@ class _TestCompilerForLanguageVersion { final String _dillCachePath; FrontendServerClient? _frontendServerClient; final String _languageVersionComment; - late final _outputDill = - File(p.join(_outputDillDirectory.path, 'output.dill')); - final _outputDillDirectory = - Directory.systemTemp.createTempSync('dart_test.kernel.'); + late final _outputDill = File( + p.join(_outputDillDirectory.path, 'output.dill'), + ); + final _outputDillDirectory = Directory.systemTemp.createTempSync( + 'dart_test.kernel.', + ); // Used to create unique file names for final kernel files. int _compileNumber = 0; // The largest incremental dill file we created, will be cached under @@ -81,9 +94,11 @@ class _TestCompilerForLanguageVersion { File? _dillToCache; _TestCompilerForLanguageVersion( - String dillCachePrefix, this._languageVersionComment) - : _dillCachePath = '$dillCachePrefix.' - '${_dillCacheSuffix(_languageVersionComment, enabledExperiments)}'; + String dillCachePrefix, + this._languageVersionComment, + ) : _dillCachePath = + '$dillCachePrefix.' + '${_dillCacheSuffix(_languageVersionComment, enabledExperiments)}'; Future compile(Uri mainUri) => _compilePool.withResource(() => _compile(mainUri)); @@ -93,12 +108,14 @@ class _TestCompilerForLanguageVersion { if (_closeMemo.hasRun) return CompilationResponse._wasShutdown; CompileResult? compilerOutput; final tempFile = File(p.join(_outputDillDirectory.path, 'test.dart')) - ..writeAsStringSync(testBootstrapContents( - testUri: mainUri, - packageConfigUri: await packageConfigUri, - languageVersionComment: _languageVersionComment, - testType: VmTestType.isolate, - )); + ..writeAsStringSync( + testBootstrapContents( + testUri: mainUri, + packageConfigUri: await packageConfigUri, + languageVersionComment: _languageVersionComment, + testType: VmTestType.isolate, + ), + ); final testCache = File(_dillCachePath); try { @@ -108,8 +125,9 @@ class _TestCompilerForLanguageVersion { } compilerOutput = await _createCompiler(tempFile.uri); } else { - compilerOutput = - await _frontendServerClient!.compile([tempFile.uri]); + compilerOutput = await _frontendServerClient!.compile([ + tempFile.uri, + ]); } } catch (e, s) { if (_closeMemo.hasRun) return CompilationResponse._wasShutdown; @@ -123,13 +141,15 @@ class _TestCompilerForLanguageVersion { final outputPath = compilerOutput?.dillOutput; if (outputPath == null) { return CompilationResponse( - compilerOutput: compilerOutput?.compilerOutputLines.join('\n'), - errorCount: compilerOutput?.errorCount ?? 0); + compilerOutput: compilerOutput?.compilerOutputLines.join('\n'), + errorCount: compilerOutput?.errorCount ?? 0, + ); } final outputFile = File(outputPath); - final kernelReadyToRun = - await outputFile.copy('${tempFile.path}_$_compileNumber.dill'); + final kernelReadyToRun = await outputFile.copy( + '${tempFile.path}_$_compileNumber.dill', + ); // Keep the `_dillToCache` file up-to-date and use the size of the // kernel file as an approximation for how many packages are included. // Larger files are preferred, since re-using more packages will reduce the @@ -140,27 +160,31 @@ class _TestCompilerForLanguageVersion { } return CompilationResponse( - compilerOutput: compilerOutput?.compilerOutputLines.join('\n'), - errorCount: compilerOutput?.errorCount ?? 0, - kernelOutputUri: kernelReadyToRun.absolute.uri); + compilerOutput: compilerOutput?.compilerOutputLines.join('\n'), + errorCount: compilerOutput?.errorCount ?? 0, + kernelOutputUri: kernelReadyToRun.absolute.uri, + ); } Future _createCompiler(Uri testUri) async { final platformDill = 'lib/_internal/vm_platform_strong.dill'; - final sdkRoot = - p.relative(p.dirname(p.dirname(Platform.resolvedExecutable))); + final sdkRoot = p.relative( + p.dirname(p.dirname(Platform.resolvedExecutable)), + ); final packageConfigUriAwaited = await packageConfigUri; // If we have native assets for the host os in JIT mode, they are either // in the `.dart_tool/` in the root package or in the pub workspace. Uri? nativeAssetsYaml; - final nativeAssetsYamlRootPackage = - Directory.current.uri.resolve('.dart_tool/native_assets.yaml'); - final nativeAssetsYamlWorkspace = - packageConfigUriAwaited.resolve('native_assets.yaml'); + final nativeAssetsYamlRootPackage = Directory.current.uri.resolve( + '.dart_tool/native_assets.yaml', + ); + final nativeAssetsYamlWorkspace = packageConfigUriAwaited.resolve( + 'native_assets.yaml', + ); for (final potentialNativeAssetsUri in [ nativeAssetsYamlRootPackage, - nativeAssetsYamlWorkspace + nativeAssetsYamlWorkspace, ]) { if (await File.fromUri(potentialNativeAssetsUri).exists()) { nativeAssetsYaml = potentialNativeAssetsUri; @@ -168,42 +192,46 @@ class _TestCompilerForLanguageVersion { } } - var client = _frontendServerClient = await FrontendServerClient.start( - testUri.toString(), - _outputDill.path, - platformDill, - enabledExperiments: enabledExperiments, - sdkRoot: sdkRoot, - packagesJson: packageConfigUriAwaited.toFilePath(), - nativeAssets: nativeAssetsYaml?.toFilePath(), - printIncrementalDependencies: false, - ); + var client = + _frontendServerClient = await FrontendServerClient.start( + testUri.toString(), + _outputDill.path, + platformDill, + enabledExperiments: enabledExperiments, + sdkRoot: sdkRoot, + packagesJson: packageConfigUriAwaited.toFilePath(), + nativeAssets: nativeAssetsYaml?.toFilePath(), + printIncrementalDependencies: false, + ); return client.compile(); } Future dispose() => _closeMemo.runOnce(() async { - await _compilePool.close(); - if (_dillToCache != null) { - var testCache = File(_dillCachePath); - if (!testCache.parent.existsSync()) { - testCache.parent.createSync(recursive: true); - } - _dillToCache!.copySync(_dillCachePath); - } - _frontendServerClient?.kill(); - _frontendServerClient = null; - if (_outputDillDirectory.existsSync()) { - await _outputDillDirectory.deleteWithRetry(); - } - }); + await _compilePool.close(); + if (_dillToCache != null) { + var testCache = File(_dillCachePath); + if (!testCache.parent.existsSync()) { + testCache.parent.createSync(recursive: true); + } + _dillToCache!.copySync(_dillCachePath); + } + _frontendServerClient?.kill(); + _frontendServerClient = null; + if (_outputDillDirectory.existsSync()) { + await _outputDillDirectory.deleteWithRetry(); + } + }); } /// Computes a unique dill cache suffix for each [languageVersionComment] /// and [enabledExperiments] combination. String _dillCacheSuffix( - String languageVersionComment, List enabledExperiments) { - var identifierString = - StringBuffer(languageVersionComment.replaceAll(' ', '')); + String languageVersionComment, + List enabledExperiments, +) { + var identifierString = StringBuffer( + languageVersionComment.replaceAll(' ', ''), + ); for (var experiment in enabledExperiments) { identifierString.writeln(experiment); } diff --git a/pkgs/test_core/lib/src/runner/wasm_compiler_pool.dart b/pkgs/test_core/lib/src/runner/wasm_compiler_pool.dart index c4318f5a2..9993c1d57 100644 --- a/pkgs/test_core/lib/src/runner/wasm_compiler_pool.dart +++ b/pkgs/test_core/lib/src/runner/wasm_compiler_pool.dart @@ -33,7 +33,10 @@ class WasmCompilerPool extends CompilerPool { /// *and* all its output has been printed to the command line. @override Future compileInternal( - String code, String path, SuiteConfiguration suiteConfig) { + String code, + String path, + SuiteConfiguration suiteConfig, + ) { return withTempDir((dir) async { final wrapperPath = p.join(dir, 'main.dart'); File(wrapperPath).writeAsStringSync(code); @@ -88,9 +91,11 @@ class WasmCompilerPool extends CompilerPool { /// have been killed and all resources released. @override Future closeInternal() async { - await Future.wait(_processes.map((process) async { - process.kill(); - await process.exitCode; - })); + await Future.wait( + _processes.map((process) async { + process.kill(); + await process.exitCode; + }), + ); } } diff --git a/pkgs/test_core/lib/src/scaffolding.dart b/pkgs/test_core/lib/src/scaffolding.dart index cb28b6203..bf6d36177 100644 --- a/pkgs/test_core/lib/src/scaffolding.dart +++ b/pkgs/test_core/lib/src/scaffolding.dart @@ -50,20 +50,28 @@ Declarer get _declarer { await pumpEventQueue(); var suite = RunnerSuite( - const PluginEnvironment(), - SuiteConfiguration.empty, - _globalDeclarer!.build(), - SuitePlatform(Runtime.vm, compiler: null, os: currentOSGuess), - path: p.prettyUri(Uri.base)); + const PluginEnvironment(), + SuiteConfiguration.empty, + _globalDeclarer!.build(), + SuitePlatform(Runtime.vm, compiler: null, os: currentOSGuess), + path: p.prettyUri(Uri.base), + ); var engine = Engine(); engine.suiteSink.add(suite); engine.suiteSink.close(); - ExpandedReporter.watch(engine, PrintSink(), - color: true, printPath: false, printPlatform: false); + ExpandedReporter.watch( + engine, + PrintSink(), + color: true, + printPath: false, + printPlatform: false, + ); - var success = await runZoned(() => Invoker.guard(engine.run), - zoneValues: {#test.declarer: _globalDeclarer}); + var success = await runZoned( + () => Invoker.guard(engine.run), + zoneValues: {#test.declarer: _globalDeclarer}, + ); if (success == true) return null; print(''); unawaited(Future.error('Dummy exception to set exit code.')); @@ -133,25 +141,31 @@ Declarer get _declarer { /// avoid this flag if possible and instead use the test runner flag `-n` to /// filter tests by name. @isTest -void test(Object? description, dynamic Function() body, - {String? testOn, - Timeout? timeout, - Object? skip, - Object? tags, - Map? onPlatform, - int? retry, - TestLocation? location, - // TODO(https://github.com/dart-lang/test/issues/2205): Remove deprecated. - @Deprecated('Debug only') @doNotSubmit bool solo = false}) { - _declarer.test(description.toString(), body, - testOn: testOn, - timeout: timeout, - skip: skip, - onPlatform: onPlatform, - tags: tags, - retry: retry, - location: location, - solo: solo); +void test( + Object? description, + dynamic Function() body, { + String? testOn, + Timeout? timeout, + Object? skip, + Object? tags, + Map? onPlatform, + int? retry, + TestLocation? location, + // TODO(https://github.com/dart-lang/test/issues/2205): Remove deprecated. + @Deprecated('Debug only') @doNotSubmit bool solo = false, +}) { + _declarer.test( + description.toString(), + body, + testOn: testOn, + timeout: timeout, + skip: skip, + onPlatform: onPlatform, + tags: tags, + retry: retry, + location: location, + solo: solo, + ); // Force dart2js not to inline this function. We need it to be separate from // `main()` in JS stack traces in order to properly determine the line and @@ -214,25 +228,31 @@ void test(Object? description, dynamic Function() body, /// avoid this flag if possible, and instead use the test runner flag `-n` to /// filter tests by name. @isTestGroup -void group(Object? description, dynamic Function() body, - {String? testOn, - Timeout? timeout, - Object? skip, - Object? tags, - Map? onPlatform, - int? retry, - TestLocation? location, - // TODO(https://github.com/dart-lang/test/issues/2205): Remove deprecated. - @Deprecated('Debug only') @doNotSubmit bool solo = false}) { - _declarer.group(description.toString(), body, - testOn: testOn, - timeout: timeout, - skip: skip, - tags: tags, - onPlatform: onPlatform, - retry: retry, - location: location, - solo: solo); +void group( + Object? description, + dynamic Function() body, { + String? testOn, + Timeout? timeout, + Object? skip, + Object? tags, + Map? onPlatform, + int? retry, + TestLocation? location, + // TODO(https://github.com/dart-lang/test/issues/2205): Remove deprecated. + @Deprecated('Debug only') @doNotSubmit bool solo = false, +}) { + _declarer.group( + description.toString(), + body, + testOn: testOn, + timeout: timeout, + skip: skip, + tags: tags, + onPlatform: onPlatform, + retry: retry, + location: location, + solo: solo, + ); // Force dart2js not to inline this function. We need it to be separate from // `main()` in JS stack traces in order to properly determine the line and diff --git a/pkgs/test_core/lib/src/util/async.dart b/pkgs/test_core/lib/src/util/async.dart index 036d2b1cf..ab56b1d29 100644 --- a/pkgs/test_core/lib/src/util/async.dart +++ b/pkgs/test_core/lib/src/util/async.dart @@ -14,18 +14,19 @@ import 'package:async/async.dart'; Stream inCompletionOrder(Iterable> operations) { var operationSet = operations.toSet(); var controller = StreamController( - sync: true, - onCancel: () => - Future.wait(operationSet.map((operation) => operation.cancel()))); + sync: true, + onCancel: + () => Future.wait(operationSet.map((operation) => operation.cancel())), + ); for (var operation in operationSet) { operation.value .then((value) => controller.add(value)) .onError(controller.addError) .whenComplete(() { - operationSet.remove(operation); - if (operationSet.isEmpty) controller.close(); - }); + operationSet.remove(operation); + if (operationSet.isEmpty) controller.close(); + }); } return controller.stream; diff --git a/pkgs/test_core/lib/src/util/dart.dart b/pkgs/test_core/lib/src/util/dart.dart index 5a1546c47..7f5a2b186 100644 --- a/pkgs/test_core/lib/src/util/dart.dart +++ b/pkgs/test_core/lib/src/util/dart.dart @@ -18,15 +18,18 @@ import 'string_literal_iterator.dart'; /// they will be resolved in the same context as the host isolate. [message] is /// passed to the [main] method of the code being run; the caller is responsible /// for using this to establish communication with the isolate. -Future runInIsolate(String code, Object message, - {SendPort? onExit}) async => - Isolate.spawnUri( - Uri.dataFromString(code, mimeType: 'application/dart', encoding: utf8), - [], - message, - packageConfig: await packageConfigUri, - checked: true, - onExit: onExit); +Future runInIsolate( + String code, + Object message, { + SendPort? onExit, +}) async => Isolate.spawnUri( + Uri.dataFromString(code, mimeType: 'application/dart', encoding: utf8), + [], + message, + packageConfig: await packageConfigUri, + checked: true, + onExit: onExit, +); /// Takes a span whose source is the value of a string that has been parsed from /// a Dart file and returns the corresponding span from within that Dart file. @@ -54,7 +57,10 @@ Future runInIsolate(String code, Object message, /// This will return `null` if [context] contains an invalid string or does not /// contain [span]. SourceSpan? contextualizeSpan( - SourceSpan span, StringLiteral context, SourceFile file) { + SourceSpan span, + StringLiteral context, + SourceFile file, +) { var contextRunes = StringLiteralIterator(context)..moveNext(); for (var i = 0; i < span.start.offset; i++) { diff --git a/pkgs/test_core/lib/src/util/io.dart b/pkgs/test_core/lib/src/util/io.dart index a082dd310..e0c8e275d 100644 --- a/pkgs/test_core/lib/src/util/io.dart +++ b/pkgs/test_core/lib/src/util/io.dart @@ -51,26 +51,31 @@ final currentOS = OperatingSystem.findByIoName(Platform.operatingSystem); /// [OperatingSystem.none]. // TODO: https://github.com/dart-lang/test/issues/2119 - require compiler SuitePlatform currentPlatform(Runtime runtime, [Compiler? compiler]) => - SuitePlatform(runtime, - compiler: compiler, - os: runtime.isBrowser ? OperatingSystem.none : currentOS, - inGoogle: inGoogle); + SuitePlatform( + runtime, + compiler: compiler, + os: runtime.isBrowser ? OperatingSystem.none : currentOS, + inGoogle: inGoogle, + ); /// A transformer that decodes bytes using UTF-8 and splits them on newlines. final lineSplitter = StreamTransformer, String>( - (stream, cancelOnError) => utf8.decoder - .bind(stream) - .transform(const LineSplitter()) - .listen(null, cancelOnError: cancelOnError)); + (stream, cancelOnError) => utf8.decoder + .bind(stream) + .transform(const LineSplitter()) + .listen(null, cancelOnError: cancelOnError), +); /// A queue of lines of standard input. /// /// Also returns an empty stream for Fuchsia since Fuchsia components can't /// access stdin. StreamQueue get stdinLines => - _stdinLines ??= StreamQueue(Platform.isFuchsia - ? const Stream.empty() - : lineSplitter.bind(stdin)); + _stdinLines ??= StreamQueue( + Platform.isFuchsia + ? const Stream.empty() + : lineSplitter.bind(stdin), + ); StreamQueue? _stdinLines; @@ -85,9 +90,10 @@ bool inTestTests = Platform.environment['_DART_TEST_TESTING'] == 'true'; /// /// This is configurable so that the test code can validate that the runner /// cleans up after itself fully. -final _tempDir = Platform.environment.containsKey('_UNITTEST_TEMP_DIR') - ? Platform.environment['_UNITTEST_TEMP_DIR']! - : Directory.systemTemp.path; +final _tempDir = + Platform.environment.containsKey('_UNITTEST_TEMP_DIR') + ? Platform.environment['_UNITTEST_TEMP_DIR']! + : Directory.systemTemp.path; /// Whether or not the current terminal supports ansi escape codes. /// @@ -116,8 +122,9 @@ String createTempDir() => Future withTempDir(Future Function(String) fn) { return Future.sync(() { var tempDir = createTempDir(); - return Future.sync(() => fn(tempDir)) - .whenComplete(() => Directory(tempDir).deleteWithRetry()); + return Future.sync( + () => fn(tempDir), + ).whenComplete(() => Directory(tempDir).deleteWithRetry()); }); } @@ -127,28 +134,31 @@ Future withTempDir(Future Function(String) fn) { /// part of a word's length. It only splits words on spaces, not on other sorts /// of whitespace. String wordWrap(String text) { - return text.split('\n').map((originalLine) { - var buffer = StringBuffer(); - var lengthSoFar = 0; - for (var word in originalLine.split(' ')) { - var wordLength = withoutColors(word).length; - if (wordLength > lineLength) { - if (lengthSoFar != 0) buffer.writeln(); - buffer.writeln(word); - } else if (lengthSoFar == 0) { - buffer.write(word); - lengthSoFar = wordLength; - } else if (lengthSoFar + 1 + wordLength > lineLength) { - buffer.writeln(); - buffer.write(word); - lengthSoFar = wordLength; - } else { - buffer.write(' $word'); - lengthSoFar += 1 + wordLength; - } - } - return buffer.toString(); - }).join('\n'); + return text + .split('\n') + .map((originalLine) { + var buffer = StringBuffer(); + var lengthSoFar = 0; + for (var word in originalLine.split(' ')) { + var wordLength = withoutColors(word).length; + if (wordLength > lineLength) { + if (lengthSoFar != 0) buffer.writeln(); + buffer.writeln(word); + } else if (lengthSoFar == 0) { + buffer.write(word); + lengthSoFar = wordLength; + } else if (lengthSoFar + 1 + wordLength > lineLength) { + buffer.writeln(); + buffer.write(word); + lengthSoFar = wordLength; + } else { + buffer.write(' $word'); + lengthSoFar += 1 + wordLength; + } + } + return buffer.toString(); + }) + .join('\n'); } /// Print a warning containing [message]. @@ -175,7 +185,8 @@ void warn(String message, {bool? color, bool print = false}) { /// This is necessary for ensuring that our port binding isn't flaky for /// applications that don't print out the bound port. Future getUnusedPort( - FutureOr Function(int port) tryPort) async { + FutureOr Function(int port) tryPort, +) async { T? value; await Future.doWhile(() async { value = await tryPort(await getUnsafeUnusedPort()); @@ -196,8 +207,11 @@ Future getUnsafeUnusedPort() async { late int port; if (_maySupportIPv6) { try { - final socket = await ServerSocket.bind(InternetAddress.loopbackIPv6, 0, - v6Only: true); + final socket = await ServerSocket.bind( + InternetAddress.loopbackIPv6, + 0, + v6Only: true, + ); port = socket.port; await socket.close(); } on SocketException { @@ -224,8 +238,9 @@ Future getRemoteDebuggerUrl(Uri base) async { var response = await request.close(); var jsonObject = await json.fuse(utf8).decoder.bind(response).single as List; - return base - .resolve((jsonObject.first as Map)['devtoolsFrontendUrl'] as String); + return base.resolve( + (jsonObject.first as Map)['devtoolsFrontendUrl'] as String, + ); } catch (_) { // If we fail to talk to the remote debugger protocol, give up and return // the raw URL rather than crashing. @@ -244,7 +259,8 @@ extension RetryDelete on FileSystemEntity { if (attempt == 2) rethrow; attempt++; await Future.delayed( - Duration(milliseconds: pow(10, attempt).toInt())); + Duration(milliseconds: pow(10, attempt).toInt()), + ); } } } diff --git a/pkgs/test_core/lib/src/util/io_stub.dart b/pkgs/test_core/lib/src/util/io_stub.dart index 79538770d..e972cc070 100644 --- a/pkgs/test_core/lib/src/util/io_stub.dart +++ b/pkgs/test_core/lib/src/util/io_stub.dart @@ -8,4 +8,5 @@ import 'package:test_api/src/backend/suite_platform.dart'; // ignore: implementa SuitePlatform currentPlatform(Runtime runtime, Compiler? compiler) => throw UnsupportedError( - 'Getting the current platform is only supported where dart:io exists'); + 'Getting the current platform is only supported where dart:io exists', + ); diff --git a/pkgs/test_core/lib/src/util/os.dart b/pkgs/test_core/lib/src/util/os.dart index 3db1608fa..948be98e2 100644 --- a/pkgs/test_core/lib/src/util/os.dart +++ b/pkgs/test_core/lib/src/util/os.dart @@ -22,9 +22,11 @@ final _macOSDirectories = { /// This is useful for running test files directly and skipping tests as /// appropriate. The only OS-specific information we have is the current path, /// which we try to use to figure out the OS. -final OperatingSystem currentOSGuess = (() { - if (p.style == p.Style.url) return OperatingSystem.none; - if (p.style == p.Style.windows) return OperatingSystem.windows; - if (_macOSDirectories.any(p.current.startsWith)) return OperatingSystem.macOS; - return OperatingSystem.linux; -})(); +final OperatingSystem currentOSGuess = + (() { + if (p.style == p.Style.url) return OperatingSystem.none; + if (p.style == p.Style.windows) return OperatingSystem.windows; + if (_macOSDirectories.any(p.current.startsWith)) + return OperatingSystem.macOS; + return OperatingSystem.linux; + })(); diff --git a/pkgs/test_core/lib/src/util/stack_trace_mapper.dart b/pkgs/test_core/lib/src/util/stack_trace_mapper.dart index 9d4248dd4..f232dd061 100644 --- a/pkgs/test_core/lib/src/util/stack_trace_mapper.dart +++ b/pkgs/test_core/lib/src/util/stack_trace_mapper.dart @@ -25,18 +25,25 @@ class JSStackTraceMapper implements StackTraceMapper { /// The URL of the source map. final Uri? _mapUrl; - JSStackTraceMapper(this._mapContents, - {Uri? mapUrl, Map? packageMap, Uri? sdkRoot}) - : _mapUrl = mapUrl, - _packageMap = packageMap, - _sdkRoot = sdkRoot; + JSStackTraceMapper( + this._mapContents, { + Uri? mapUrl, + Map? packageMap, + Uri? sdkRoot, + }) : _mapUrl = mapUrl, + _packageMap = packageMap, + _sdkRoot = sdkRoot; /// Converts [trace] into a Dart stack trace. @override StackTrace mapStackTrace(StackTrace trace) { var mapping = _mapping ??= parseExtended(_mapContents, mapUrl: _mapUrl); - return mapper.mapStackTrace(mapping, trace, - packageMap: _packageMap, sdkRoot: _sdkRoot); + return mapper.mapStackTrace( + mapping, + trace, + packageMap: _packageMap, + sdkRoot: _sdkRoot, + ); } /// Returns a Map representation which is suitable for JSON serialization. @@ -55,18 +62,22 @@ class JSStackTraceMapper implements StackTraceMapper { static StackTraceMapper? deserialize(Map? serialized) { if (serialized == null) return null; var deserialized = _deserializePackageConfigMap( - (serialized['packageConfigMap'] as Map).cast()); + (serialized['packageConfigMap'] as Map).cast(), + ); - return JSStackTraceMapper(serialized['mapContents'] as String, - sdkRoot: Uri.parse(serialized['sdkRoot'] as String), - packageMap: deserialized, - mapUrl: Uri.parse(serialized['mapUrl'] as String)); + return JSStackTraceMapper( + serialized['mapContents'] as String, + sdkRoot: Uri.parse(serialized['sdkRoot'] as String), + packageMap: deserialized, + mapUrl: Uri.parse(serialized['mapUrl'] as String), + ); } /// Converts a [packageConfigMap] into a format suitable for JSON /// serialization. static Map? _serializePackageConfigMap( - Map? packageConfigMap) { + Map? packageConfigMap, + ) { if (packageConfigMap == null) return null; return packageConfigMap.map((key, value) => MapEntry(key, '$value')); } @@ -74,7 +85,8 @@ class JSStackTraceMapper implements StackTraceMapper { /// Converts a serialized package config map into a format suitable for /// the [PackageResolver] static Map? _deserializePackageConfigMap( - Map? serialized) { + Map? serialized, + ) { if (serialized == null) return null; return serialized.map((key, value) => MapEntry(key, Uri.parse(value))); } diff --git a/pkgs/test_core/lib/src/util/string_literal_iterator.dart b/pkgs/test_core/lib/src/util/string_literal_iterator.dart index d58f64a9c..8df3109c8 100644 --- a/pkgs/test_core/lib/src/util/string_literal_iterator.dart +++ b/pkgs/test_core/lib/src/util/string_literal_iterator.dart @@ -116,7 +116,8 @@ class StringLiteralIterator implements Iterator { var start = string.contentsOffset - string.offset; // Compensate for the opening and closing quotes. - var end = start + + var end = + start + string.literal.lexeme.length - 2 * (string.isMultiline ? 3 : 1) - (string.isRaw ? 1 : 0); diff --git a/pkgs/test_core/lib/test_core.dart b/pkgs/test_core/lib/test_core.dart index b1df09da2..0ddbb51f2 100644 --- a/pkgs/test_core/lib/test_core.dart +++ b/pkgs/test_core/lib/test_core.dart @@ -2,8 +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. -@Deprecated('package:test_core is not intended for general use. ' - 'Please use package:test.') +@Deprecated( + 'package:test_core is not intended for general use. ' + 'Please use package:test.', +) library; export 'package:test_api/hooks.dart' show TestFailure; diff --git a/pkgs/test_core/test/runner/vm/test_compiler_test.dart b/pkgs/test_core/test/runner/vm/test_compiler_test.dart index a6e50efe6..b75a8b726 100644 --- a/pkgs/test_core/test/runner/vm/test_compiler_test.dart +++ b/pkgs/test_core/test/runner/vm/test_compiler_test.dart @@ -18,8 +18,10 @@ void main() { testType: VmTestType.isolate, ); final lines = LineSplitter.split(template).map((line) => line.trim()); - expect(lines, - contains("const packageConfigLocation = 'package_config.json';")); + expect( + lines, + contains("const packageConfigLocation = 'package_config.json';"), + ); }); }); } From 1743cef617244a1e2def5b52a640780819262ec0 Mon Sep 17 00:00:00 2001 From: Nate Bosch Date: Tue, 22 Jul 2025 20:24:48 +0000 Subject: [PATCH 06/11] More changelog entries --- pkgs/checks/CHANGELOG.md | 4 ++++ pkgs/checks/pubspec.yaml | 2 +- pkgs/matcher/CHANGELOG.md | 2 +- pkgs/test/CHANGELOG.md | 1 + pkgs/test_api/CHANGELOG.md | 1 + pkgs/test_core/CHANGELOG.md | 1 + 6 files changed, 9 insertions(+), 2 deletions(-) diff --git a/pkgs/checks/CHANGELOG.md b/pkgs/checks/CHANGELOG.md index ddc9cdb48..3aa11d050 100644 --- a/pkgs/checks/CHANGELOG.md +++ b/pkgs/checks/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.3.2-wip + +- Require Dart 3.7 + ## 0.3.1 - Directly compare keys across actual and expected `Map` instances when diff --git a/pkgs/checks/pubspec.yaml b/pkgs/checks/pubspec.yaml index afcea29fb..092c802bf 100644 --- a/pkgs/checks/pubspec.yaml +++ b/pkgs/checks/pubspec.yaml @@ -1,5 +1,5 @@ name: checks -version: 0.3.1 +version: 0.3.2-wip description: >- A framework for checking values against expectations and building custom expectations. diff --git a/pkgs/matcher/CHANGELOG.md b/pkgs/matcher/CHANGELOG.md index 54420762b..18d0d6b54 100644 --- a/pkgs/matcher/CHANGELOG.md +++ b/pkgs/matcher/CHANGELOG.md @@ -2,7 +2,7 @@ * Remove some dynamic invocations. * Add explicit casts from `dynamic` values. -* Require Dart 3.5 +* Require Dart 3.7 * Add `isSorted` and related matchers for iterables. ## 0.12.17 diff --git a/pkgs/test/CHANGELOG.md b/pkgs/test/CHANGELOG.md index fde711584..b0c4e7adf 100644 --- a/pkgs/test/CHANGELOG.md +++ b/pkgs/test/CHANGELOG.md @@ -1,6 +1,7 @@ ## 1.26.4-wip * Restrict to latest version of analyzer package. +- Require Dart 3.7 ## 1.26.3 diff --git a/pkgs/test_api/CHANGELOG.md b/pkgs/test_api/CHANGELOG.md index 4ca3a6675..9e918f12d 100644 --- a/pkgs/test_api/CHANGELOG.md +++ b/pkgs/test_api/CHANGELOG.md @@ -1,6 +1,7 @@ ## 0.7.9-wip * Restrict to latest version of analyzer package. +- Require Dart 3.7 ## 0.7.7 diff --git a/pkgs/test_core/CHANGELOG.md b/pkgs/test_core/CHANGELOG.md index 522756b8a..2126ef1c7 100644 --- a/pkgs/test_core/CHANGELOG.md +++ b/pkgs/test_core/CHANGELOG.md @@ -1,6 +1,7 @@ ## 0.6.13-wip * Restrict to latest version of analyzer package. +* Require Dart 3.7 ## 0.6.12 From a0219ab7ee23b90d2a2ad7c6272a3e801bc90789 Mon Sep 17 00:00:00 2001 From: Nate Bosch Date: Tue, 22 Jul 2025 20:26:11 +0000 Subject: [PATCH 07/11] consistent bullet --- pkgs/test/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/test/CHANGELOG.md b/pkgs/test/CHANGELOG.md index b0c4e7adf..c6e92726d 100644 --- a/pkgs/test/CHANGELOG.md +++ b/pkgs/test/CHANGELOG.md @@ -1,7 +1,7 @@ ## 1.26.4-wip * Restrict to latest version of analyzer package. -- Require Dart 3.7 +* Require Dart 3.7 ## 1.26.3 From f0d4f644e37e4459964fdd45246dccb03b66be1d Mon Sep 17 00:00:00 2001 From: Nate Bosch Date: Tue, 22 Jul 2025 20:27:30 +0000 Subject: [PATCH 08/11] fix test_api changelog version number --- pkgs/test_api/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/test_api/CHANGELOG.md b/pkgs/test_api/CHANGELOG.md index 9e918f12d..0208cbf5d 100644 --- a/pkgs/test_api/CHANGELOG.md +++ b/pkgs/test_api/CHANGELOG.md @@ -1,4 +1,4 @@ -## 0.7.9-wip +## 0.7.8-wip * Restrict to latest version of analyzer package. - Require Dart 3.7 From f40b4a46fa86bf4d039370a104da9ca12f08a105 Mon Sep 17 00:00:00 2001 From: Nate Bosch Date: Wed, 23 Jul 2025 02:07:17 +0000 Subject: [PATCH 09/11] Single character wildcard argument names --- pkgs/test/lib/src/runner/browser/browser.dart | 2 +- pkgs/test/lib/src/runner/browser/platform.dart | 2 +- pkgs/test/lib/src/runner/node/platform.dart | 6 ++---- pkgs/test_api/lib/src/backend/invoker.dart | 2 +- pkgs/test_api/lib/src/backend/remote_listener.dart | 2 +- pkgs/test_core/lib/src/runner/engine.dart | 2 +- pkgs/test_core/lib/src/runner/hybrid_listener.dart | 2 +- pkgs/test_core/lib/src/runner/vm/platform.dart | 2 +- pkgs/test_core/lib/src/util/os.dart | 3 ++- 9 files changed, 11 insertions(+), 12 deletions(-) diff --git a/pkgs/test/lib/src/runner/browser/browser.dart b/pkgs/test/lib/src/runner/browser/browser.dart index 4d846c8eb..f90b3661d 100644 --- a/pkgs/test/lib/src/runner/browser/browser.dart +++ b/pkgs/test/lib/src/runner/browser/browser.dart @@ -140,6 +140,6 @@ abstract class Browser { (await _process).kill(); // Swallow exceptions. The user should explicitly use [onExit] for these. - return onExit.onError((_, __) {}); + return onExit.onError((_, _) {}); } } diff --git a/pkgs/test/lib/src/runner/browser/platform.dart b/pkgs/test/lib/src/runner/browser/platform.dart index df0d660f9..a8f6096fa 100644 --- a/pkgs/test/lib/src/runner/browser/platform.dart +++ b/pkgs/test/lib/src/runner/browser/platform.dart @@ -258,7 +258,7 @@ class BrowserPlatform extends PlatformPlugin // again. _browserManagers[(browser, compiler)] = future .then((value) => value) - .onError((_, __) => null); + .onError((_, _) => null); return future; } diff --git a/pkgs/test/lib/src/runner/node/platform.dart b/pkgs/test/lib/src/runner/node/platform.dart index e3357b853..b8bccd74e 100644 --- a/pkgs/test/lib/src/runner/node/platform.dart +++ b/pkgs/test/lib/src/runner/node/platform.dart @@ -167,10 +167,8 @@ class NodePlatform extends PlatformPlugin unawaited( Future.wait( servers.map( - (s) => s - .close() - .then((v) => v) - .onError((_, __) => null), + (s) => + s.close().then((v) => v).onError((_, _) => null), ), ), ); diff --git a/pkgs/test_api/lib/src/backend/invoker.dart b/pkgs/test_api/lib/src/backend/invoker.dart index 8f775cf1d..8c9a51eab 100644 --- a/pkgs/test_api/lib/src/backend/invoker.dart +++ b/pkgs/test_api/lib/src/backend/invoker.dart @@ -482,7 +482,7 @@ class Invoker { #runCount: _runCount, }, zoneSpecification: ZoneSpecification( - print: (_, __, ___, line) => _print(line), + print: (_, _, _, line) => _print(line), ), ); }); diff --git a/pkgs/test_api/lib/src/backend/remote_listener.dart b/pkgs/test_api/lib/src/backend/remote_listener.dart index 389c5e4c6..eb6fb343e 100644 --- a/pkgs/test_api/lib/src/backend/remote_listener.dart +++ b/pkgs/test_api/lib/src/backend/remote_listener.dart @@ -61,7 +61,7 @@ final class RemoteListener { var printZone = hidePrints ? null : Zone.current; var spec = ZoneSpecification( - print: (_, __, ___, line) { + print: (_, _, _, line) { if (printZone != null) printZone.print(line); channel.sink.add({'type': 'print', 'line': line}); }, diff --git a/pkgs/test_core/lib/src/runner/engine.dart b/pkgs/test_core/lib/src/runner/engine.dart index fa13a2fa4..a506ab58c 100644 --- a/pkgs/test_core/lib/src/runner/engine.dart +++ b/pkgs/test_core/lib/src/runner/engine.dart @@ -227,7 +227,7 @@ class Engine { _onSuiteStartedController.close(); _closedBeforeDone ??= false; }) - .onError((_, __) { + .onError((_, _) { // Don't top-level errors. They'll be thrown via [success] anyway. }); } diff --git a/pkgs/test_core/lib/src/runner/hybrid_listener.dart b/pkgs/test_core/lib/src/runner/hybrid_listener.dart index 1ce09fdb8..dd4091de5 100644 --- a/pkgs/test_core/lib/src/runner/hybrid_listener.dart +++ b/pkgs/test_core/lib/src/runner/hybrid_listener.dart @@ -88,7 +88,7 @@ void listen(Function Function() getMain, List data) { } }, zoneSpecification: ZoneSpecification( - print: (_, __, ___, line) { + print: (_, _, _, line) { channel.sink.add({'type': 'print', 'line': line}); }, ), diff --git a/pkgs/test_core/lib/src/runner/vm/platform.dart b/pkgs/test_core/lib/src/runner/vm/platform.dart index 77e8cba2c..e4de034ce 100644 --- a/pkgs/test_core/lib/src/runner/vm/platform.dart +++ b/pkgs/test_core/lib/src/runner/vm/platform.dart @@ -444,7 +444,7 @@ var _hasRegistered = false; void _setupPauseAfterTests() { if (_hasRegistered) return; _hasRegistered = true; - registerExtension('ext.test.pauseAfterTests', (_, __) async { + registerExtension('ext.test.pauseAfterTests', (_, _) async { _shouldPauseAfterTests = true; return ServiceExtensionResponse.result(jsonEncode({})); }); diff --git a/pkgs/test_core/lib/src/util/os.dart b/pkgs/test_core/lib/src/util/os.dart index 948be98e2..fe389b14c 100644 --- a/pkgs/test_core/lib/src/util/os.dart +++ b/pkgs/test_core/lib/src/util/os.dart @@ -26,7 +26,8 @@ final OperatingSystem currentOSGuess = (() { if (p.style == p.Style.url) return OperatingSystem.none; if (p.style == p.Style.windows) return OperatingSystem.windows; - if (_macOSDirectories.any(p.current.startsWith)) + if (_macOSDirectories.any(p.current.startsWith)) { return OperatingSystem.macOS; + } return OperatingSystem.linux; })(); From e3f7161e4125617d9c01353c4effb41d518e7adc Mon Sep 17 00:00:00 2001 From: Nate Bosch Date: Wed, 23 Jul 2025 02:12:10 +0000 Subject: [PATCH 10/11] Reformat matcher --- pkgs/matcher/lib/mirror_matchers.dart | 18 +- pkgs/matcher/lib/src/core_matchers.dart | 36 +- pkgs/matcher/lib/src/custom_matcher.dart | 40 +- pkgs/matcher/lib/src/description.dart | 6 +- pkgs/matcher/lib/src/equals_matcher.dart | 182 +++-- pkgs/matcher/lib/src/error_matchers.dart | 11 +- .../matcher/lib/src/expect/async_matcher.dart | 24 +- pkgs/matcher/lib/src/expect/expect.dart | 111 ++- pkgs/matcher/lib/src/expect/expect_async.dart | 341 +++++---- .../lib/src/expect/future_matchers.dart | 26 +- pkgs/matcher/lib/src/expect/never_called.dart | 80 ++- .../lib/src/expect/prints_matcher.dart | 19 +- .../lib/src/expect/stream_matcher.dart | 112 +-- .../lib/src/expect/stream_matchers.dart | 131 ++-- .../lib/src/expect/throws_matcher.dart | 18 +- .../lib/src/expect/throws_matchers.dart | 21 +- pkgs/matcher/lib/src/feature_matcher.dart | 23 +- pkgs/matcher/lib/src/having_matcher.dart | 58 +- pkgs/matcher/lib/src/interfaces.dart | 9 +- pkgs/matcher/lib/src/iterable_matchers.dart | 161 +++-- pkgs/matcher/lib/src/map_matchers.dart | 14 +- pkgs/matcher/lib/src/numeric_matchers.dart | 21 +- pkgs/matcher/lib/src/operator_matchers.dart | 63 +- pkgs/matcher/lib/src/order_matchers.dart | 85 ++- pkgs/matcher/lib/src/pretty_print.dart | 13 +- pkgs/matcher/lib/src/string_matchers.dart | 31 +- pkgs/matcher/lib/src/type_matcher.dart | 30 +- pkgs/matcher/lib/src/util.dart | 3 +- pkgs/matcher/test/core_matchers_test.dart | 158 ++-- pkgs/matcher/test/custom_matcher_test.dart | 30 +- pkgs/matcher/test/escape_test.dart | 32 +- pkgs/matcher/test/expect_async_test.dart | 119 ++-- pkgs/matcher/test/expect_test.dart | 18 +- pkgs/matcher/test/having_test.dart | 126 ++-- pkgs/matcher/test/iterable_matchers_test.dart | 672 ++++++++++-------- .../matcher/test/matcher/completion_test.dart | 76 +- pkgs/matcher/test/matcher/prints_test.dart | 197 ++--- pkgs/matcher/test/matcher/throws_test.dart | 249 ++++--- .../test/matcher/throws_type_test.dart | 67 +- pkgs/matcher/test/mirror_matchers_test.dart | 48 +- pkgs/matcher/test/never_called_test.dart | 32 +- pkgs/matcher/test/numeric_matchers_test.dart | 120 ++-- pkgs/matcher/test/operator_matchers_test.dart | 74 +- pkgs/matcher/test/order_matchers_test.dart | 165 +++-- pkgs/matcher/test/pretty_print_test.dart | 291 +++++--- pkgs/matcher/test/stream_matcher_test.dart | 328 +++++---- pkgs/matcher/test/string_matchers_test.dart | 162 +++-- pkgs/matcher/test/type_matcher_test.dart | 7 +- 48 files changed, 2860 insertions(+), 1798 deletions(-) diff --git a/pkgs/matcher/lib/mirror_matchers.dart b/pkgs/matcher/lib/mirror_matchers.dart index cf85e2362..c5125ab47 100644 --- a/pkgs/matcher/lib/mirror_matchers.dart +++ b/pkgs/matcher/lib/mirror_matchers.dart @@ -39,7 +39,7 @@ class _HasProperty extends Matcher { if (!(isInstanceField || isInstanceGetter)) { addStateInfo(matchState, { 'reason': - 'has a member named "$_name", but it is not an instance property' + 'has a member named "$_name", but it is not an instance property', }); return false; } @@ -63,8 +63,12 @@ class _HasProperty extends Matcher { } @override - Description describeMismatch(Object? item, Description mismatchDescription, - Map matchState, bool verbose) { + Description describeMismatch( + Object? item, + Description mismatchDescription, + Map matchState, + bool verbose, + ) { var reason = matchState['reason']; if (reason != null) { mismatchDescription.add(reason as String); @@ -74,8 +78,12 @@ class _HasProperty extends Matcher { .addDescriptionOf(matchState['value']); var innerDescription = StringDescription(); matchState['state'] ??= {}; - _matcher?.describeMismatch(matchState['value'], innerDescription, - matchState['state'] as Map, verbose); + _matcher?.describeMismatch( + matchState['value'], + innerDescription, + matchState['state'] as Map, + verbose, + ); if (innerDescription.length > 0) { mismatchDescription.add(' which ').add(innerDescription.toString()); } diff --git a/pkgs/matcher/lib/src/core_matchers.dart b/pkgs/matcher/lib/src/core_matchers.dart index 936149e2a..7c80804b5 100644 --- a/pkgs/matcher/lib/src/core_matchers.dart +++ b/pkgs/matcher/lib/src/core_matchers.dart @@ -166,8 +166,12 @@ class _ReturnsNormally extends FeatureMatcher { description.add('return normally'); @override - Description describeTypedMismatch(Function item, - Description mismatchDescription, Map matchState, bool verbose) { + Description describeTypedMismatch( + Function item, + Description mismatchDescription, + Map matchState, + bool verbose, + ) { mismatchDescription.add('threw ').addDescriptionOf(matchState['exception']); if (verbose) { mismatchDescription.add(' at ').add(matchState['stack'].toString()); @@ -205,8 +209,12 @@ class _HasLength extends Matcher { description.add('an object with length of ').addDescriptionOf(_matcher); @override - Description describeMismatch(Object? item, Description mismatchDescription, - Map matchState, bool verbose) { + Description describeMismatch( + Object? item, + Description mismatchDescription, + Map matchState, + bool verbose, + ) { try { final length = (item as dynamic).length; return mismatchDescription.add('has length of ').addDescriptionOf(length); @@ -252,8 +260,12 @@ class _Contains extends Matcher { description.add('contains ').addDescriptionOf(_expected); @override - Description describeMismatch(Object? item, Description mismatchDescription, - Map matchState, bool verbose) { + Description describeMismatch( + Object? item, + Description mismatchDescription, + Map matchState, + bool verbose, + ) { if (item is String || item is Iterable || item is Map) { super.describeMismatch(item, mismatchDescription, matchState, verbose); mismatchDescription.add('does not contain ').addDescriptionOf(_expected); @@ -276,7 +288,10 @@ Matcher isIn(Object? expected) { } throw ArgumentError.value( - expected, 'expected', 'Only Iterable, Map, and String are supported.'); + expected, + 'expected', + 'Only Iterable, Map, and String are supported.', + ); } class _In extends FeatureMatcher { @@ -310,9 +325,10 @@ class _In extends FeatureMatcher { /// Using an explicit generict argument allows a passed function literal to have /// an inferred argument type of [T], and values of the wrong type will be /// rejected with an informative message. -Matcher predicate(bool Function(T) f, - [String description = 'satisfies function']) => - _Predicate(f, description); +Matcher predicate( + bool Function(T) f, [ + String description = 'satisfies function', +]) => _Predicate(f, description); class _Predicate extends FeatureMatcher { final bool Function(T) _matcher; diff --git a/pkgs/matcher/lib/src/custom_matcher.dart b/pkgs/matcher/lib/src/custom_matcher.dart index b0f2d6b6b..28f9461d9 100644 --- a/pkgs/matcher/lib/src/custom_matcher.dart +++ b/pkgs/matcher/lib/src/custom_matcher.dart @@ -38,8 +38,10 @@ class CustomMatcher extends Matcher { final Matcher _matcher; CustomMatcher( - this._featureDescription, this._featureName, Object? valueOrMatcher) - : _matcher = wrapMatcher(valueOrMatcher); + this._featureDescription, + this._featureName, + Object? valueOrMatcher, + ) : _matcher = wrapMatcher(valueOrMatcher); /// Override this to extract the interesting feature. Object? featureValueOf(dynamic actual) => actual; @@ -53,14 +55,16 @@ class CustomMatcher extends Matcher { } catch (exception, stack) { addStateInfo(matchState, { 'custom.exception': exception.toString(), - 'custom.stack': Chain.forTrace(stack) - .foldFrames( - (frame) => - frame.package == 'test' || - frame.package == 'stream_channel' || - frame.package == 'matcher', - terse: true) - .toString() + 'custom.stack': + Chain.forTrace(stack) + .foldFrames( + (frame) => + frame.package == 'test' || + frame.package == 'stream_channel' || + frame.package == 'matcher', + terse: true, + ) + .toString(), }); } return false; @@ -71,8 +75,12 @@ class CustomMatcher extends Matcher { description.add(_featureDescription).add(' ').addDescriptionOf(_matcher); @override - Description describeMismatch(Object? item, Description mismatchDescription, - Map matchState, bool verbose) { + Description describeMismatch( + Object? item, + Description mismatchDescription, + Map matchState, + bool verbose, + ) { if (matchState['custom.exception'] != null) { mismatchDescription .add('threw ') @@ -89,8 +97,12 @@ class CustomMatcher extends Matcher { .addDescriptionOf(matchState['custom.feature']); var innerDescription = StringDescription(); - _matcher.describeMismatch(matchState['custom.feature'], innerDescription, - matchState['state'] as Map, verbose); + _matcher.describeMismatch( + matchState['custom.feature'], + innerDescription, + matchState['state'] as Map, + verbose, + ); if (innerDescription.length > 0) { mismatchDescription.add(' which ').add(innerDescription.toString()); diff --git a/pkgs/matcher/lib/src/description.dart b/pkgs/matcher/lib/src/description.dart index 090aada06..6e2835164 100644 --- a/pkgs/matcher/lib/src/description.dart +++ b/pkgs/matcher/lib/src/description.dart @@ -56,7 +56,11 @@ class StringDescription implements Description { /// and [end]. @override Description addAll( - String start, String separator, String end, Iterable list) { + String start, + String separator, + String end, + Iterable list, + ) { var separate = false; add(start); for (var item in list) { diff --git a/pkgs/matcher/lib/src/equals_matcher.dart b/pkgs/matcher/lib/src/equals_matcher.dart index 36b3bf52d..4cb54118c 100644 --- a/pkgs/matcher/lib/src/equals_matcher.dart +++ b/pkgs/matcher/lib/src/equals_matcher.dart @@ -15,9 +15,10 @@ import 'util.dart'; /// For [Iterable]s and [Map]s, this will recursively match the elements. To /// handle cyclic structures a recursion depth [limit] can be provided. The /// default limit is 100. [Set]s will be compared order-independently. -Matcher equals(Object? expected, [int limit = 100]) => expected is String - ? _StringEqualsMatcher(expected) - : _DeepMatcher(expected, limit); +Matcher equals(Object? expected, [int limit = 100]) => + expected is String + ? _StringEqualsMatcher(expected) + : _DeepMatcher(expected, limit); typedef _RecursiveMatcher = _Mismatch? Function(Object?, Object?, String, int); @@ -35,15 +36,20 @@ class _StringEqualsMatcher extends FeatureMatcher { description.addDescriptionOf(_value); @override - Description describeTypedMismatch(String item, - Description mismatchDescription, Map matchState, bool verbose) { + Description describeTypedMismatch( + String item, + Description mismatchDescription, + Map matchState, + bool verbose, + ) { var buff = StringBuffer(); buff.write('is different.'); var escapedItem = escape(item); var escapedValue = escape(_value); - var minLength = escapedItem.length < escapedValue.length - ? escapedItem.length - : escapedValue.length; + var minLength = + escapedItem.length < escapedValue.length + ? escapedItem.length + : escapedValue.length; var start = 0; for (; start < minLength; start++) { if (escapedValue.codeUnitAt(start) != escapedItem.codeUnitAt(start)) { @@ -52,12 +58,16 @@ class _StringEqualsMatcher extends FeatureMatcher { } if (start == minLength) { if (escapedValue.length < escapedItem.length) { - buff.write(' Both strings start the same, but the actual value also' - ' has the following trailing characters: '); + buff.write( + ' Both strings start the same, but the actual value also' + ' has the following trailing characters: ', + ); _writeTrailing(buff, escapedItem, escapedValue.length); } else { - buff.write(' Both strings start the same, but the actual value is' - ' missing the following trailing characters: '); + buff.write( + ' Both strings start the same, but the actual value is' + ' missing the following trailing characters: ', + ); _writeTrailing(buff, escapedValue, escapedItem.length); } } else { @@ -102,12 +112,17 @@ class _DeepMatcher extends Matcher { _DeepMatcher(this._expected, [int limit = 1000]) : _limit = limit; - _Mismatch? _compareIterables(Iterable expected, Object? actual, - _RecursiveMatcher matcher, int depth, String location) { + _Mismatch? _compareIterables( + Iterable expected, + Object? actual, + _RecursiveMatcher matcher, + int depth, + String location, + ) { if (actual is Iterable) { var expectedIterator = expected.iterator; var actualIterator = actual.iterator; - for (var index = 0;; index++) { + for (var index = 0; ; index++) { // Advance in lockstep. var expectedNext = expectedIterator.moveNext(); var actualNext = actualIterator.moveNext(); @@ -125,8 +140,12 @@ class _DeepMatcher extends Matcher { } // Match the elements. - var rp = matcher(expectedIterator.current, actualIterator.current, - newLocation, depth); + var rp = matcher( + expectedIterator.current, + actualIterator.current, + newLocation, + depth, + ); if (rp != null) return rp; } } else { @@ -134,20 +153,28 @@ class _DeepMatcher extends Matcher { } } - _Mismatch? _compareSets(Set expected, Object? actual, - _RecursiveMatcher matcher, int depth, String location) { + _Mismatch? _compareSets( + Set expected, + Object? actual, + _RecursiveMatcher matcher, + int depth, + String location, + ) { if (actual is Iterable) { var other = actual.toSet(); for (var expectedElement in expected) { - if (other.every((actualElement) => - matcher(expectedElement, actualElement, location, depth) != null)) { + if (other.every( + (actualElement) => + matcher(expectedElement, actualElement, location, depth) != null, + )) { return _Mismatch( - location, - actual, - (description, verbose) => description - .add('does not contain ') - .addDescriptionOf(expectedElement)); + location, + actual, + (description, verbose) => description + .add('does not contain ') + .addDescriptionOf(expectedElement), + ); } } @@ -164,7 +191,11 @@ class _DeepMatcher extends Matcher { } _Mismatch? _recursiveMatch( - Object? expected, Object? actual, String location, int depth) { + Object? expected, + Object? actual, + String location, + int depth, + ) { // If the expected value is a matcher, try to match it. if (expected is Matcher) { var matchState = {}; @@ -184,58 +215,79 @@ class _DeepMatcher extends Matcher { } catch (e) { // TODO(gram): Add a test for this case. return _Mismatch( - location, - actual, - (description, verbose) => - description.add('== threw ').addDescriptionOf(e)); + location, + actual, + (description, verbose) => + description.add('== threw ').addDescriptionOf(e), + ); } } if (depth > _limit) { return _Mismatch.simple( - location, actual, 'recursion depth limit exceeded'); + location, + actual, + 'recursion depth limit exceeded', + ); } // If _limit is 1 we can only recurse one level into object. if (depth == 0 || _limit > 1) { if (expected is Set) { return _compareSets( - expected, actual, _recursiveMatch, depth + 1, location); + expected, + actual, + _recursiveMatch, + depth + 1, + location, + ); } else if (expected is Iterable) { return _compareIterables( - expected, actual, _recursiveMatch, depth + 1, location); + expected, + actual, + _recursiveMatch, + depth + 1, + location, + ); } else if (expected is Map) { if (actual is! Map) { return _Mismatch.simple(location, actual, 'expected a map'); } - var err = (expected.length == actual.length) - ? '' - : 'has different length and '; + var err = + (expected.length == actual.length) + ? '' + : 'has different length and '; for (var key in expected.keys) { if (!actual.containsKey(key)) { return _Mismatch( - location, - actual, - (description, verbose) => description - .add('${err}is missing map key ') - .addDescriptionOf(key)); + location, + actual, + (description, verbose) => description + .add('${err}is missing map key ') + .addDescriptionOf(key), + ); } } for (var key in actual.keys) { if (!expected.containsKey(key)) { return _Mismatch( - location, - actual, - (description, verbose) => description - .add('${err}has extra map key ') - .addDescriptionOf(key)); + location, + actual, + (description, verbose) => description + .add('${err}has extra map key ') + .addDescriptionOf(key), + ); } } for (var key in expected.keys) { var rp = _recursiveMatch( - expected[key], actual[key], "$location['$key']", depth + 1); + expected[key], + actual[key], + "$location['$key']", + depth + 1, + ); if (rp != null) return rp; } @@ -246,9 +298,12 @@ class _DeepMatcher extends Matcher { // If we have recursed, show the expected value too; if not, expect() will // show it for us. if (depth > 0) { - return _Mismatch(location, actual, - (description, verbose) => description.addDescriptionOf(expected), - instead: true); + return _Mismatch( + location, + actual, + (description, verbose) => description.addDescriptionOf(expected), + instead: true, + ); } else { return _Mismatch(location, actual, null); } @@ -267,8 +322,12 @@ class _DeepMatcher extends Matcher { description.addDescriptionOf(_expected); @override - Description describeMismatch(Object? item, Description mismatchDescription, - Map matchState, bool verbose) { + Description describeMismatch( + Object? item, + Description mismatchDescription, + Map matchState, + bool verbose, + ) { var mismatch = matchState['mismatch'] as _Mismatch; var describeProblem = mismatch.describeProblem; if (mismatch.location.isNotEmpty) { @@ -278,8 +337,9 @@ class _DeepMatcher extends Matcher { .add(' is ') .addDescriptionOf(mismatch.actual); if (describeProblem != null) { - mismatchDescription - .add(' ${mismatch.instead ? 'instead of' : 'which'} '); + mismatchDescription.add( + ' ${mismatch.instead ? 'instead of' : 'which'} ', + ); describeProblem(mismatchDescription, verbose); } } else { @@ -318,10 +378,14 @@ class _Mismatch { /// `which` (e.g. `at location [2] is which has length of 3`). final bool instead; - _Mismatch(this.location, this.actual, this.describeProblem, - {this.instead = false}); + _Mismatch( + this.location, + this.actual, + this.describeProblem, { + this.instead = false, + }); _Mismatch.simple(this.location, this.actual, String problem) - : describeProblem = ((description, verbose) => description.add(problem)), - instead = false; + : describeProblem = ((description, verbose) => description.add(problem)), + instead = false; } diff --git a/pkgs/matcher/lib/src/error_matchers.dart b/pkgs/matcher/lib/src/error_matchers.dart index 5b6238d98..f7a0f6c1f 100644 --- a/pkgs/matcher/lib/src/error_matchers.dart +++ b/pkgs/matcher/lib/src/error_matchers.dart @@ -17,8 +17,9 @@ const isConcurrentModificationError = /// A matcher for [Error]. @Deprecated( - 'CyclicInitializationError is deprecated and will be removed in Dart 3. ' - 'Use `isA()` instead.') + 'CyclicInitializationError is deprecated and will be removed in Dart 3. ' + 'Use `isA()` instead.', +) const isCyclicInitializationError = TypeMatcher(); /// A matcher for [Exception]. @@ -31,8 +32,10 @@ const isFormatException = TypeMatcher(); const isNoSuchMethodError = TypeMatcher(); /// A matcher for [TypeError]. -@Deprecated('NullThrownError is deprecated and will be removed in Dart 3. ' - 'Use `isA()` instead.') +@Deprecated( + 'NullThrownError is deprecated and will be removed in Dart 3. ' + 'Use `isA()` instead.', +) const isNullThrownError = TypeMatcher(); /// A matcher for [RangeError]. diff --git a/pkgs/matcher/lib/src/expect/async_matcher.dart b/pkgs/matcher/lib/src/expect/async_matcher.dart index 854151d5f..13152456f 100644 --- a/pkgs/matcher/lib/src/expect/async_matcher.dart +++ b/pkgs/matcher/lib/src/expect/async_matcher.dart @@ -37,13 +37,14 @@ abstract class AsyncMatcher extends Matcher { bool matches(dynamic item, Map matchState) { final result = matchAsync(item); expect( - result, - anyOf([ - equals(null), - const TypeMatcher(), - const TypeMatcher() - ]), - reason: 'matchAsync() may only return a String, a Future, or null.'); + result, + anyOf([ + equals(null), + const TypeMatcher(), + const TypeMatcher(), + ]), + reason: 'matchAsync() may only return a String, a Future, or null.', + ); if (result is Future) { final outstandingWork = TestHandle.current.markPending(); @@ -62,7 +63,10 @@ abstract class AsyncMatcher extends Matcher { } @override - Description describeMismatch(dynamic item, Description mismatchDescription, - Map matchState, bool verbose) => - StringDescription(matchState[this] as String); + Description describeMismatch( + dynamic item, + Description mismatchDescription, + Map matchState, + bool verbose, + ) => StringDescription(matchState[this] as String); } diff --git a/pkgs/matcher/lib/src/expect/expect.dart b/pkgs/matcher/lib/src/expect/expect.dart index d8110d68a..f1e0b9192 100644 --- a/pkgs/matcher/lib/src/expect/expect.dart +++ b/pkgs/matcher/lib/src/expect/expect.dart @@ -21,8 +21,14 @@ import 'util/pretty_print.dart'; /// The type used for functions that can be used to build up error reports /// upon failures in [expect]. @Deprecated('Will be removed in 0.13.0.') -typedef ErrorFormatter = String Function(Object? actual, Matcher matcher, - String? reason, Map matchState, bool verbose); +typedef ErrorFormatter = + String Function( + Object? actual, + Matcher matcher, + String? reason, + Map matchState, + bool verbose, + ); /// Assert that [actual] matches [matcher]. /// @@ -48,13 +54,22 @@ typedef ErrorFormatter = String Function(Object? actual, Matcher matcher, /// the test doesn't complete until the matcher has either matched or failed. If /// you want to wait for the matcher to complete before continuing the test, you /// can call [expectLater] instead and `await` the result. -void expect(dynamic actual, dynamic matcher, - {String? reason, - Object? /* String|bool */ skip, - @Deprecated('Will be removed in 0.13.0.') bool verbose = false, - @Deprecated('Will be removed in 0.13.0.') ErrorFormatter? formatter}) { - _expect(actual, matcher, - reason: reason, skip: skip, verbose: verbose, formatter: formatter); +void expect( + dynamic actual, + dynamic matcher, { + String? reason, + Object? /* String|bool */ skip, + @Deprecated('Will be removed in 0.13.0.') bool verbose = false, + @Deprecated('Will be removed in 0.13.0.') ErrorFormatter? formatter, +}) { + _expect( + actual, + matcher, + reason: reason, + skip: skip, + verbose: verbose, + formatter: formatter, + ); } /// Just like [expect], but returns a [Future] that completes when the matcher @@ -68,23 +83,33 @@ void expect(dynamic actual, dynamic matcher, /// /// If the matcher fails asynchronously, that failure is piped to the returned /// future where it can be handled by user code. -Future expectLater(dynamic actual, dynamic matcher, - {String? reason, Object? /* String|bool */ skip}) => - _expect(actual, matcher, reason: reason, skip: skip); +Future expectLater( + dynamic actual, + dynamic matcher, { + String? reason, + Object? /* String|bool */ skip, +}) => _expect(actual, matcher, reason: reason, skip: skip); /// The implementation of [expect] and [expectLater]. -Future _expect(Object? actual, Object? matcher, - {String? reason, - Object? skip, - bool verbose = false, - ErrorFormatter? formatter}) { +Future _expect( + Object? actual, + Object? matcher, { + String? reason, + Object? skip, + bool verbose = false, + ErrorFormatter? formatter, +}) { final test = TestHandle.current; formatter ??= (actual, matcher, reason, matchState, verbose) { var mismatchDescription = StringDescription(); matcher.describeMismatch(actual, mismatchDescription, matchState, verbose); - return formatFailure(matcher, actual, mismatchDescription.toString(), - reason: reason); + return formatFailure( + matcher, + actual, + mismatchDescription.toString(), + reason: reason, + ); }; if (skip != null && skip is! bool && skip is! String) { @@ -111,26 +136,36 @@ Future _expect(Object? actual, Object? matcher, // Avoid async/await so that expect() throws synchronously when possible. var result = matcher.matchAsync(actual); expect( - result, - anyOf([ - equals(null), - const TypeMatcher(), - const TypeMatcher() - ]), - reason: 'matchAsync() may only return a String, a Future, or null.'); + result, + anyOf([ + equals(null), + const TypeMatcher(), + const TypeMatcher(), + ]), + reason: 'matchAsync() may only return a String, a Future, or null.', + ); if (result is String) { fail(formatFailure(matcher, actual, result, reason: reason)); } else if (result is Future) { final outstandingWork = test.markPending(); - return result.then((realResult) { - if (realResult == null) return; - fail(formatFailure(matcher as Matcher, actual, realResult as String, - reason: reason)); - }).whenComplete( - // Always remove this, in case the failure is caught and handled - // gracefully. - outstandingWork.complete); + return result + .then((realResult) { + if (realResult == null) return; + fail( + formatFailure( + matcher as Matcher, + actual, + realResult as String, + reason: reason, + ), + ); + }) + .whenComplete( + // Always remove this, in case the failure is caught and handled + // gracefully. + outstandingWork.complete, + ); } return Future.sync(() {}); @@ -153,8 +188,12 @@ Never fail(String message) => throw TestFailure(message); // The default error formatter. @Deprecated('Will be removed in 0.13.0.') -String formatFailure(Matcher expected, Object? actual, String which, - {String? reason}) { +String formatFailure( + Matcher expected, + Object? actual, + String which, { + String? reason, +}) { var buffer = StringBuffer(); buffer.writeln(indent(prettyPrint(expected), first: 'Expected: ')); buffer.writeln(indent(prettyPrint(actual), first: ' Actual: ')); diff --git a/pkgs/matcher/lib/src/expect/expect_async.dart b/pkgs/matcher/lib/src/expect/expect_async.dart index a659c81bb..0b633a50f 100644 --- a/pkgs/matcher/lib/src/expect/expect_async.dart +++ b/pkgs/matcher/lib/src/expect/expect_async.dart @@ -73,15 +73,20 @@ class _ExpectedFunction { /// If passed, [id] is used as a descriptive name fo the function and [reason] /// as a reason it's expected to be called. If [isDone] is passed, the test /// won't be allowed to complete until it returns `true`. - _ExpectedFunction(Function callback, int minExpected, int maxExpected, - {String? id, String? reason, bool Function()? isDone}) - : _callback = callback, - _minExpectedCalls = minExpected, - _maxExpectedCalls = - (maxExpected == 0 && minExpected > 0) ? minExpected : maxExpected, - _isDone = isDone, - _reason = reason == null ? '' : '\n$reason', - _id = _makeCallbackId(id, callback) { + _ExpectedFunction( + Function callback, + int minExpected, + int maxExpected, { + String? id, + String? reason, + bool Function()? isDone, + }) : _callback = callback, + _minExpectedCalls = minExpected, + _maxExpectedCalls = + (maxExpected == 0 && minExpected > 0) ? minExpected : maxExpected, + _isDone = isDone, + _reason = reason == null ? '' : '\n$reason', + _id = _makeCallbackId(id, callback) { try { _test = TestHandle.current; } on OutsideTestException { @@ -89,8 +94,10 @@ class _ExpectedFunction { } if (maxExpected > 0 && minExpected > maxExpected) { - throw ArgumentError('max ($maxExpected) may not be less than count ' - '($minExpected).'); + throw ArgumentError( + 'max ($maxExpected) may not be less than count ' + '($minExpected).', + ); } if (isDone != null || minExpected > 0) { @@ -138,7 +145,8 @@ class _ExpectedFunction { _outstandingWork?.complete(); throw ArgumentError( - 'The wrapped function has more than 6 required arguments'); + 'The wrapped function has more than 6 required arguments', + ); } // This indirection is critical. It ensures the returned function has an @@ -149,35 +157,35 @@ class _ExpectedFunction { T max2([Object? a0 = placeholder, Object? a1 = placeholder]) => max6(a0, a1); - T max3( - [Object? a0 = placeholder, - Object? a1 = placeholder, - Object? a2 = placeholder]) => - max6(a0, a1, a2); - - T max4( - [Object? a0 = placeholder, - Object? a1 = placeholder, - Object? a2 = placeholder, - Object? a3 = placeholder]) => - max6(a0, a1, a2, a3); - - T max5( - [Object? a0 = placeholder, - Object? a1 = placeholder, - Object? a2 = placeholder, - Object? a3 = placeholder, - Object? a4 = placeholder]) => - max6(a0, a1, a2, a3, a4); - - T max6( - [Object? a0 = placeholder, - Object? a1 = placeholder, - Object? a2 = placeholder, - Object? a3 = placeholder, - Object? a4 = placeholder, - Object? a5 = placeholder]) => - _run([a0, a1, a2, a3, a4, a5].where((a) => a != placeholder)); + T max3([ + Object? a0 = placeholder, + Object? a1 = placeholder, + Object? a2 = placeholder, + ]) => max6(a0, a1, a2); + + T max4([ + Object? a0 = placeholder, + Object? a1 = placeholder, + Object? a2 = placeholder, + Object? a3 = placeholder, + ]) => max6(a0, a1, a2, a3); + + T max5([ + Object? a0 = placeholder, + Object? a1 = placeholder, + Object? a2 = placeholder, + Object? a3 = placeholder, + Object? a4 = placeholder, + ]) => max6(a0, a1, a2, a3, a4); + + T max6([ + Object? a0 = placeholder, + Object? a1 = placeholder, + Object? a2 = placeholder, + Object? a3 = placeholder, + Object? a4 = placeholder, + Object? a5 = placeholder, + ]) => _run([a0, a1, a2, a3, a4, a5].where((a) => a != placeholder)); /// Runs the wrapped function with [args] and returns its return value. T _run(Iterable args) { @@ -188,11 +196,14 @@ class _ExpectedFunction { _actualCalls++; if (_test.shouldBeDone) { throw TestFailure( - 'Callback ${_id}called ($_actualCalls) after test case ' - '${_test.name} had already completed.$_reason'); + 'Callback ${_id}called ($_actualCalls) after test case ' + '${_test.name} had already completed.$_reason', + ); } else if (_maxExpectedCalls >= 0 && _actualCalls > _maxExpectedCalls) { - throw TestFailure('Callback ${_id}called more times than expected ' - '($_maxExpectedCalls).$_reason'); + throw TestFailure( + 'Callback ${_id}called more times than expected ' + '($_maxExpectedCalls).$_reason', + ); } return Function.apply(_callback, args.toList()) as T; @@ -219,10 +230,20 @@ class _ExpectedFunction { /// [expectAsync2], [expectAsync3], [expectAsync4], [expectAsync5], or /// [expectAsync6] instead. @Deprecated('Will be removed in 0.13.0') -Function expectAsync(Function callback, - {int count = 1, int max = 0, String? id, String? reason}) => - _ExpectedFunction(callback, count, max, id: id, reason: reason) - .func; +Function expectAsync( + Function callback, { + int count = 1, + int max = 0, + String? id, + String? reason, +}) => + _ExpectedFunction( + callback, + count, + max, + id: id, + reason: reason, + ).func; /// Informs the framework that the given [callback] of arity 0 is expected to be /// called [count] number of times (by default 1). @@ -245,9 +266,13 @@ Function expectAsync(Function callback, /// This method takes callbacks with zero arguments. See also /// [expectAsync1], [expectAsync2], [expectAsync3], [expectAsync4], /// [expectAsync5], and [expectAsync6] for callbacks with different arity. -Func0 expectAsync0(T Function() callback, - {int count = 1, int max = 0, String? id, String? reason}) => - _ExpectedFunction(callback, count, max, id: id, reason: reason).max0; +Func0 expectAsync0( + T Function() callback, { + int count = 1, + int max = 0, + String? id, + String? reason, +}) => _ExpectedFunction(callback, count, max, id: id, reason: reason).max0; /// Informs the framework that the given [callback] of arity 1 is expected to be /// called [count] number of times (by default 1). @@ -270,9 +295,13 @@ Func0 expectAsync0(T Function() callback, /// This method takes callbacks with one argument. See also /// [expectAsync0], [expectAsync2], [expectAsync3], [expectAsync4], /// [expectAsync5], and [expectAsync6] for callbacks with different arity. -Func1 expectAsync1(T Function(A) callback, - {int count = 1, int max = 0, String? id, String? reason}) => - _ExpectedFunction(callback, count, max, id: id, reason: reason).max1; +Func1 expectAsync1( + T Function(A) callback, { + int count = 1, + int max = 0, + String? id, + String? reason, +}) => _ExpectedFunction(callback, count, max, id: id, reason: reason).max1; /// Informs the framework that the given [callback] of arity 2 is expected to be /// called [count] number of times (by default 1). @@ -295,9 +324,13 @@ Func1 expectAsync1(T Function(A) callback, /// This method takes callbacks with two arguments. See also /// [expectAsync0], [expectAsync1], [expectAsync3], [expectAsync4], /// [expectAsync5], and [expectAsync6] for callbacks with different arity. -Func2 expectAsync2(T Function(A, B) callback, - {int count = 1, int max = 0, String? id, String? reason}) => - _ExpectedFunction(callback, count, max, id: id, reason: reason).max2; +Func2 expectAsync2( + T Function(A, B) callback, { + int count = 1, + int max = 0, + String? id, + String? reason, +}) => _ExpectedFunction(callback, count, max, id: id, reason: reason).max2; /// Informs the framework that the given [callback] of arity 3 is expected to be /// called [count] number of times (by default 1). @@ -320,9 +353,13 @@ Func2 expectAsync2(T Function(A, B) callback, /// This method takes callbacks with three arguments. See also /// [expectAsync0], [expectAsync1], [expectAsync2], [expectAsync4], /// [expectAsync5], and [expectAsync6] for callbacks with different arity. -Func3 expectAsync3(T Function(A, B, C) callback, - {int count = 1, int max = 0, String? id, String? reason}) => - _ExpectedFunction(callback, count, max, id: id, reason: reason).max3; +Func3 expectAsync3( + T Function(A, B, C) callback, { + int count = 1, + int max = 0, + String? id, + String? reason, +}) => _ExpectedFunction(callback, count, max, id: id, reason: reason).max3; /// Informs the framework that the given [callback] of arity 4 is expected to be /// called [count] number of times (by default 1). @@ -346,12 +383,12 @@ Func3 expectAsync3(T Function(A, B, C) callback, /// [expectAsync0], [expectAsync1], [expectAsync2], [expectAsync3], /// [expectAsync5], and [expectAsync6] for callbacks with different arity. Func4 expectAsync4( - T Function(A, B, C, D) callback, - {int count = 1, - int max = 0, - String? id, - String? reason}) => - _ExpectedFunction(callback, count, max, id: id, reason: reason).max4; + T Function(A, B, C, D) callback, { + int count = 1, + int max = 0, + String? id, + String? reason, +}) => _ExpectedFunction(callback, count, max, id: id, reason: reason).max4; /// Informs the framework that the given [callback] of arity 5 is expected to be /// called [count] number of times (by default 1). @@ -375,12 +412,12 @@ Func4 expectAsync4( /// [expectAsync0], [expectAsync1], [expectAsync2], [expectAsync3], /// [expectAsync4], and [expectAsync6] for callbacks with different arity. Func5 expectAsync5( - T Function(A, B, C, D, E) callback, - {int count = 1, - int max = 0, - String? id, - String? reason}) => - _ExpectedFunction(callback, count, max, id: id, reason: reason).max5; + T Function(A, B, C, D, E) callback, { + int count = 1, + int max = 0, + String? id, + String? reason, +}) => _ExpectedFunction(callback, count, max, id: id, reason: reason).max5; /// Informs the framework that the given [callback] of arity 6 is expected to be /// called [count] number of times (by default 1). @@ -404,23 +441,32 @@ Func5 expectAsync5( /// [expectAsync0], [expectAsync1], [expectAsync2], [expectAsync3], /// [expectAsync4], and [expectAsync5] for callbacks with different arity. Func6 expectAsync6( - T Function(A, B, C, D, E, F) callback, - {int count = 1, - int max = 0, - String? id, - String? reason}) => - _ExpectedFunction(callback, count, max, id: id, reason: reason).max6; + T Function(A, B, C, D, E, F) callback, { + int count = 1, + int max = 0, + String? id, + String? reason, +}) => _ExpectedFunction(callback, count, max, id: id, reason: reason).max6; /// This function is deprecated because it doesn't work well with strong mode. /// Use [expectAsyncUntil0], [expectAsyncUntil1], /// [expectAsyncUntil2], [expectAsyncUntil3], [expectAsyncUntil4], /// [expectAsyncUntil5], or [expectAsyncUntil6] instead. @Deprecated('Will be removed in 0.13.0') -Function expectAsyncUntil(Function callback, bool Function() isDone, - {String? id, String? reason}) => - _ExpectedFunction(callback, 0, -1, - id: id, reason: reason, isDone: isDone) - .func; +Function expectAsyncUntil( + Function callback, + bool Function() isDone, { + String? id, + String? reason, +}) => + _ExpectedFunction( + callback, + 0, + -1, + id: id, + reason: reason, + isDone: isDone, + ).func; /// Informs the framework that the given [callback] of arity 0 is expected to be /// called until [isDone] returns true. @@ -439,11 +485,20 @@ Function expectAsyncUntil(Function callback, bool Function() isDone, /// [expectAsyncUntil1], [expectAsyncUntil2], [expectAsyncUntil3], /// [expectAsyncUntil4], [expectAsyncUntil5], and [expectAsyncUntil6] for /// callbacks with different arity. -Func0 expectAsyncUntil0(T Function() callback, bool Function() isDone, - {String? id, String? reason}) => - _ExpectedFunction(callback, 0, -1, - id: id, reason: reason, isDone: isDone) - .max0; +Func0 expectAsyncUntil0( + T Function() callback, + bool Function() isDone, { + String? id, + String? reason, +}) => + _ExpectedFunction( + callback, + 0, + -1, + id: id, + reason: reason, + isDone: isDone, + ).max0; /// Informs the framework that the given [callback] of arity 1 is expected to be /// called until [isDone] returns true. @@ -463,11 +518,19 @@ Func0 expectAsyncUntil0(T Function() callback, bool Function() isDone, /// [expectAsyncUntil4], [expectAsyncUntil5], and [expectAsyncUntil6] for /// callbacks with different arity. Func1 expectAsyncUntil1( - T Function(A) callback, bool Function() isDone, - {String? id, String? reason}) => - _ExpectedFunction(callback, 0, -1, - id: id, reason: reason, isDone: isDone) - .max1; + T Function(A) callback, + bool Function() isDone, { + String? id, + String? reason, +}) => + _ExpectedFunction( + callback, + 0, + -1, + id: id, + reason: reason, + isDone: isDone, + ).max1; /// Informs the framework that the given [callback] of arity 2 is expected to be /// called until [isDone] returns true. @@ -487,11 +550,19 @@ Func1 expectAsyncUntil1( /// [expectAsyncUntil4], [expectAsyncUntil5], and [expectAsyncUntil6] for /// callbacks with different arity. Func2 expectAsyncUntil2( - T Function(A, B) callback, bool Function() isDone, - {String? id, String? reason}) => - _ExpectedFunction(callback, 0, -1, - id: id, reason: reason, isDone: isDone) - .max2; + T Function(A, B) callback, + bool Function() isDone, { + String? id, + String? reason, +}) => + _ExpectedFunction( + callback, + 0, + -1, + id: id, + reason: reason, + isDone: isDone, + ).max2; /// Informs the framework that the given [callback] of arity 3 is expected to be /// called until [isDone] returns true. @@ -511,11 +582,19 @@ Func2 expectAsyncUntil2( /// [expectAsyncUntil4], [expectAsyncUntil5], and [expectAsyncUntil6] for /// callbacks with different arity. Func3 expectAsyncUntil3( - T Function(A, B, C) callback, bool Function() isDone, - {String? id, String? reason}) => - _ExpectedFunction(callback, 0, -1, - id: id, reason: reason, isDone: isDone) - .max3; + T Function(A, B, C) callback, + bool Function() isDone, { + String? id, + String? reason, +}) => + _ExpectedFunction( + callback, + 0, + -1, + id: id, + reason: reason, + isDone: isDone, + ).max3; /// Informs the framework that the given [callback] of arity 4 is expected to be /// called until [isDone] returns true. @@ -535,11 +614,19 @@ Func3 expectAsyncUntil3( /// [expectAsyncUntil3], [expectAsyncUntil5], and [expectAsyncUntil6] for /// callbacks with different arity. Func4 expectAsyncUntil4( - T Function(A, B, C, D) callback, bool Function() isDone, - {String? id, String? reason}) => - _ExpectedFunction(callback, 0, -1, - id: id, reason: reason, isDone: isDone) - .max4; + T Function(A, B, C, D) callback, + bool Function() isDone, { + String? id, + String? reason, +}) => + _ExpectedFunction( + callback, + 0, + -1, + id: id, + reason: reason, + isDone: isDone, + ).max4; /// Informs the framework that the given [callback] of arity 5 is expected to be /// called until [isDone] returns true. @@ -559,11 +646,19 @@ Func4 expectAsyncUntil4( /// [expectAsyncUntil3], [expectAsyncUntil4], and [expectAsyncUntil6] for /// callbacks with different arity. Func5 expectAsyncUntil5( - T Function(A, B, C, D, E) callback, bool Function() isDone, - {String? id, String? reason}) => - _ExpectedFunction(callback, 0, -1, - id: id, reason: reason, isDone: isDone) - .max5; + T Function(A, B, C, D, E) callback, + bool Function() isDone, { + String? id, + String? reason, +}) => + _ExpectedFunction( + callback, + 0, + -1, + id: id, + reason: reason, + isDone: isDone, + ).max5; /// Informs the framework that the given [callback] of arity 6 is expected to be /// called until [isDone] returns true. @@ -583,8 +678,16 @@ Func5 expectAsyncUntil5( /// [expectAsyncUntil3], [expectAsyncUntil4], and [expectAsyncUntil5] for /// callbacks with different arity. Func6 expectAsyncUntil6( - T Function(A, B, C, D, E, F) callback, bool Function() isDone, - {String? id, String? reason}) => - _ExpectedFunction(callback, 0, -1, - id: id, reason: reason, isDone: isDone) - .max6; + T Function(A, B, C, D, E, F) callback, + bool Function() isDone, { + String? id, + String? reason, +}) => + _ExpectedFunction( + callback, + 0, + -1, + id: id, + reason: reason, + isDone: isDone, + ).max6; diff --git a/pkgs/matcher/lib/src/expect/future_matchers.dart b/pkgs/matcher/lib/src/expect/future_matchers.dart index 75655f065..e0697821c 100644 --- a/pkgs/matcher/lib/src/expect/future_matchers.dart +++ b/pkgs/matcher/lib/src/expect/future_matchers.dart @@ -36,9 +36,10 @@ final Matcher completes = const _Completes(null); /// /// To test that a Future completes with an exception, you can use [throws] and /// [throwsA]. -Matcher completion(Object? matcher, - [@Deprecated('this parameter is ignored') String? description]) => - _Completes(wrapMatcher(matcher)); +Matcher completion( + Object? matcher, [ + @Deprecated('this parameter is ignored') String? description, +]) => _Completes(wrapMatcher(matcher)); class _Completes extends AsyncMatcher { final Matcher? _matcher; @@ -60,9 +61,10 @@ class _Completes extends AsyncMatcher { } else { var matchState = {}; if (_matcher.matches(value, matchState)) return null; - result = _matcher - .describeMismatch(value, StringDescription(), matchState, false) - .toString(); + result = + _matcher + .describeMismatch(value, StringDescription(), matchState, false) + .toString(); } var buffer = StringBuffer(); @@ -103,8 +105,10 @@ class _DoesNotComplete extends Matcher { bool matches(Object? item, Map matchState) { if (item is! Future) return false; item.then((value) { - fail('Future was not expected to complete but completed with a value of ' - '$value'); + fail( + 'Future was not expected to complete but completed with a value of ' + '$value', + ); }); expect(pumpEventQueue(), completes); return true; @@ -112,7 +116,11 @@ class _DoesNotComplete extends Matcher { @override Description describeMismatch( - Object? item, Description description, Map matchState, bool verbose) { + Object? item, + Description description, + Map matchState, + bool verbose, + ) { if (item is! Future) return description.add('$item is not a Future'); return description; } diff --git a/pkgs/matcher/lib/src/expect/never_called.dart b/pkgs/matcher/lib/src/expect/never_called.dart index 20b529971..8e970c639 100644 --- a/pkgs/matcher/lib/src/expect/never_called.dart +++ b/pkgs/matcher/lib/src/expect/never_called.dart @@ -24,45 +24,61 @@ import 'util/pretty_print.dart'; /// /// This also ensures that the test doesn't complete until a call to /// [pumpEventQueue] finishes, so that the callback has a chance to be called. -Null Function( - [Object?, - Object?, - Object?, - Object?, - Object?, - Object?, - Object?, - Object?, - Object?, - Object?]) get neverCalled { +Null Function([ + Object?, + Object?, + Object?, + Object?, + Object?, + Object?, + Object?, + Object?, + Object?, + Object?, +]) +get neverCalled { // Make sure the test stays alive long enough to call the function if it's // going to. expect(pumpEventQueue(), completes); var zone = Zone.current; - return ( - [a1 = placeholder, - a2 = placeholder, - a3 = placeholder, - a4 = placeholder, - a5 = placeholder, - a6 = placeholder, - a7 = placeholder, - a8 = placeholder, - a9 = placeholder, - a10 = placeholder]) { - var arguments = [a1, a2, a3, a4, a5, a6, a7, a8, a9, a10] - .where((argument) => argument != placeholder) - .toList(); + return ([ + a1 = placeholder, + a2 = placeholder, + a3 = placeholder, + a4 = placeholder, + a5 = placeholder, + a6 = placeholder, + a7 = placeholder, + a8 = placeholder, + a9 = placeholder, + a10 = placeholder, + ]) { + var arguments = + [ + a1, + a2, + a3, + a4, + a5, + a6, + a7, + a8, + a9, + a10, + ].where((argument) => argument != placeholder).toList(); - var argsText = arguments.isEmpty - ? ' no arguments.' - : ':\n${bullet(arguments.map(prettyPrint))}'; + var argsText = + arguments.isEmpty + ? ' no arguments.' + : ':\n${bullet(arguments.map(prettyPrint))}'; zone.handleUncaughtError( - TestFailure( - 'Callback should never have been called, but it was called with' - '$argsText'), - zone.run(Chain.current)); + TestFailure( + 'Callback should never have been called, but it was called with' + '$argsText', + ), + zone.run(Chain.current), + ); return null; }; } diff --git a/pkgs/matcher/lib/src/expect/prints_matcher.dart b/pkgs/matcher/lib/src/expect/prints_matcher.dart index 495d22c64..3008cc672 100644 --- a/pkgs/matcher/lib/src/expect/prints_matcher.dart +++ b/pkgs/matcher/lib/src/expect/prints_matcher.dart @@ -36,10 +36,14 @@ class _Prints extends AsyncMatcher { if (item is! Object? Function()) return 'was not a unary Function'; var buffer = StringBuffer(); - var result = runZoned(item, - zoneSpecification: ZoneSpecification(print: (_, __, ____, line) { - buffer.writeln(line); - })); + var result = runZoned( + item, + zoneSpecification: ZoneSpecification( + print: (_, __, ____, line) { + buffer.writeln(line); + }, + ), + ); return result is Future ? result.then((_) => _check(buffer.toString())) @@ -56,9 +60,10 @@ class _Prints extends AsyncMatcher { var matchState = {}; if (_matcher.matches(actual, matchState)) return null; - var result = _matcher - .describeMismatch(actual, StringDescription(), matchState, false) - .toString(); + var result = + _matcher + .describeMismatch(actual, StringDescription(), matchState, false) + .toString(); var buffer = StringBuffer(); if (actual.isEmpty) { diff --git a/pkgs/matcher/lib/src/expect/stream_matcher.dart b/pkgs/matcher/lib/src/expect/stream_matcher.dart index 253b6bf43..93b98fe77 100644 --- a/pkgs/matcher/lib/src/expect/stream_matcher.dart +++ b/pkgs/matcher/lib/src/expect/stream_matcher.dart @@ -83,8 +83,10 @@ abstract class StreamMatcher extends Matcher { /// The [description] should be in the subjunctive mood. This means that it /// should be grammatically valid when used after the word "should". For /// example, it might be "emit the right events". - factory StreamMatcher(Future Function(StreamQueue) matchQueue, - String description) = _StreamMatcher; + factory StreamMatcher( + Future Function(StreamQueue) matchQueue, + String description, + ) = _StreamMatcher; /// Tries to match events emitted by [queue]. /// @@ -138,54 +140,64 @@ class _StreamMatcher extends AsyncMatcher implements StreamMatcher { // for an invalid argument type. var transaction = queue.startTransaction(); var copy = transaction.newQueue(); - return matchQueue(copy).then((result) async { - // Accept the transaction if the result is null, indicating that the match - // succeeded. - if (result == null) { - transaction.commit(copy); - return null; - } - - // Get a list of events emitted by the stream so we can emit them as part - // of the error message. - var replay = transaction.newQueue(); - var events = []; - var subscription = Result.captureStreamTransformer - .bind(replay.rest.cast()) - .listen(events.add, onDone: () => events.add(null)); - - // Wait on a timer tick so all buffered events are emitted. - await Future.delayed(Duration.zero); - _unawaited(subscription.cancel()); - - var eventsString = events.map((event) { - if (event == null) { - return 'x Stream closed.'; - } else if (event.isValue) { - return addBullet(event.asValue!.value.toString()); - } else { - var error = event.asError!; - var chain = TestHandle.current.formatStackTrace(error.stackTrace); - var text = '${error.error}\n$chain'; - return indent(text, first: '! '); - } - }).join('\n'); - if (eventsString.isEmpty) eventsString = 'no events'; - - transaction.reject(); - - var buffer = StringBuffer(); - buffer.writeln(indent(eventsString, first: 'emitted ')); - if (result.isNotEmpty) buffer.writeln(indent(result, first: ' which ')); - return buffer.toString().trimRight(); - }, onError: (Object error) { - transaction.reject(); - // ignore: only_throw_errors - throw error; - }).then((result) { - if (shouldCancelQueue) queue.cancel(); - return result; - }); + return matchQueue(copy) + .then( + (result) async { + // Accept the transaction if the result is null, indicating that the match + // succeeded. + if (result == null) { + transaction.commit(copy); + return null; + } + + // Get a list of events emitted by the stream so we can emit them as part + // of the error message. + var replay = transaction.newQueue(); + var events = []; + var subscription = Result.captureStreamTransformer + .bind(replay.rest.cast()) + .listen(events.add, onDone: () => events.add(null)); + + // Wait on a timer tick so all buffered events are emitted. + await Future.delayed(Duration.zero); + _unawaited(subscription.cancel()); + + var eventsString = events + .map((event) { + if (event == null) { + return 'x Stream closed.'; + } else if (event.isValue) { + return addBullet(event.asValue!.value.toString()); + } else { + var error = event.asError!; + var chain = TestHandle.current.formatStackTrace( + error.stackTrace, + ); + var text = '${error.error}\n$chain'; + return indent(text, first: '! '); + } + }) + .join('\n'); + if (eventsString.isEmpty) eventsString = 'no events'; + + transaction.reject(); + + var buffer = StringBuffer(); + buffer.writeln(indent(eventsString, first: 'emitted ')); + if (result.isNotEmpty) + buffer.writeln(indent(result, first: ' which ')); + return buffer.toString().trimRight(); + }, + onError: (Object error) { + transaction.reject(); + // ignore: only_throw_errors + throw error; + }, + ) + .then((result) { + if (shouldCancelQueue) queue.cancel(); + return result; + }); } @override diff --git a/pkgs/matcher/lib/src/expect/stream_matchers.dart b/pkgs/matcher/lib/src/expect/stream_matchers.dart index cff7f9fa2..2e2e494f8 100644 --- a/pkgs/matcher/lib/src/expect/stream_matchers.dart +++ b/pkgs/matcher/lib/src/expect/stream_matchers.dart @@ -14,7 +14,9 @@ import 'util/pretty_print.dart'; /// Returns a [StreamMatcher] that asserts that the stream emits a "done" event. final emitsDone = StreamMatcher( - (queue) async => (await queue.hasNext) ? '' : null, 'be done'); + (queue) async => (await queue.hasNext) ? '' : null, + 'be done', +); /// Returns a [StreamMatcher] for [matcher]. /// @@ -31,21 +33,23 @@ StreamMatcher emits(Object? matcher) { var matcherDescription = wrapped.describe(StringDescription()); - return StreamMatcher((queue) async { - if (!await queue.hasNext) return ''; - - var matchState = {}; - var actual = await queue.next; - if (wrapped.matches(actual, matchState)) return null; - - var mismatchDescription = StringDescription(); - wrapped.describeMismatch(actual, mismatchDescription, matchState, false); - - if (mismatchDescription.length == 0) return ''; - return 'emitted an event that $mismatchDescription'; - }, - // TODO(nweiz): add "should" once matcher#42 is fixed. - 'emit an event that $matcherDescription'); + return StreamMatcher( + (queue) async { + if (!await queue.hasNext) return ''; + + var matchState = {}; + var actual = await queue.next; + if (wrapped.matches(actual, matchState)) return null; + + var mismatchDescription = StringDescription(); + wrapped.describeMismatch(actual, mismatchDescription, matchState, false); + + if (mismatchDescription.length == 0) return ''; + return 'emitted an event that $mismatchDescription'; + }, + // TODO(nweiz): add "should" once matcher#42 is fixed. + 'emit an event that $matcherDescription', + ); } /// Returns a [StreamMatcher] that matches a single error event that matches @@ -56,9 +60,10 @@ StreamMatcher emitsError(Object? matcher) { var throwsMatcher = throwsA(wrapped) as AsyncMatcher; return StreamMatcher( - (queue) => throwsMatcher.matchAsync(queue.next) as Future, - // TODO(nweiz): add "should" once matcher#42 is fixed. - 'emit an error that $matcherDescription'); + (queue) => throwsMatcher.matchAsync(queue.next) as Future, + // TODO(nweiz): add "should" once matcher#42 is fixed. + 'emit an error that $matcherDescription', + ); } /// Returns a [StreamMatcher] that allows (but doesn't require) [matcher] to @@ -70,7 +75,8 @@ StreamMatcher mayEmit(Object? matcher) { var streamMatcher = emits(matcher); return StreamMatcher((queue) async { await queue.withTransaction( - (copy) async => (await streamMatcher.matchQueue(copy)) == null); + (copy) async => (await streamMatcher.matchQueue(copy)) == null, + ); return null; }, 'maybe ${streamMatcher.description}'); } @@ -91,7 +97,8 @@ StreamMatcher emitsAnyOf(Iterable matchers) { } if (streamMatchers.length == 1) return streamMatchers.first; - var description = 'do one of the following:\n' + var description = + 'do one of the following:\n' '${bullet(streamMatchers.map((matcher) => matcher.description))}'; return StreamMatcher((queue) async { @@ -168,7 +175,8 @@ StreamMatcher emitsInOrder(Iterable matchers) { var streamMatchers = matchers.map(emits).toList(); if (streamMatchers.length == 1) return streamMatchers.first; - var description = 'do the following in order:\n' + var description = + 'do the following in order:\n' '${bullet(streamMatchers.map((matcher) => matcher.description))}'; return StreamMatcher((queue) async { @@ -200,11 +208,11 @@ StreamMatcher emitsThrough(Object? matcher) { var failures = []; Future tryHere() => queue.withTransaction((copy) async { - var result = await streamMatcher.matchQueue(copy); - if (result == null) return true; - failures.add(result); - return false; - }); + var result = await streamMatcher.matchQueue(copy); + if (result == null) return true; + failures.add(result); + return false; + }); while (await queue.hasNext) { if (await tryHere()) return null; @@ -217,8 +225,9 @@ StreamMatcher emitsThrough(Object? matcher) { var result = 'never did ${streamMatcher.description}'; - var failureMessages = - bullet(failures.where((failure) => failure.isNotEmpty)); + var failureMessages = bullet( + failures.where((failure) => failure.isNotEmpty), + ); if (failureMessages.isNotEmpty) { result += result.contains('\n') ? '\n' : ' '; result += 'because it:\n$failureMessages'; @@ -312,17 +321,21 @@ Future _tryMatch(StreamQueue queue, StreamMatcher matcher) { StreamMatcher emitsInAnyOrder(Iterable matchers) { var streamMatchers = matchers.map(emits).toSet(); if (streamMatchers.length == 1) return streamMatchers.first; - var description = 'do the following in any order:\n' + var description = + 'do the following in any order:\n' '${bullet(streamMatchers.map((matcher) => matcher.description))}'; return StreamMatcher( - (queue) async => await _tryInAnyOrder(queue, streamMatchers) ? null : '', - description); + (queue) async => await _tryInAnyOrder(queue, streamMatchers) ? null : '', + description, + ); } /// Returns whether [queue] matches [matchers] in any order. Future _tryInAnyOrder( - StreamQueue queue, Set matchers) async { + StreamQueue queue, + Set matchers, +) async { if (matchers.length == 1) { return await matchers.first.matchQueue(queue) == null; } @@ -335,36 +348,38 @@ Future _tryInAnyOrder( Object? firstError; StackTrace? firstStackTrace; - await Future.wait(matchers.map((matcher) async { - var copy = transaction.newQueue(); - try { - if (await matcher.matchQueue(copy) != null) return; - } catch (error, stackTrace) { - if (firstError == null) { - firstError = error; - firstStackTrace = stackTrace; + await Future.wait( + matchers.map((matcher) async { + var copy = transaction.newQueue(); + try { + if (await matcher.matchQueue(copy) != null) return; + } catch (error, stackTrace) { + if (firstError == null) { + firstError = error; + firstStackTrace = stackTrace; + } + return; } - return; - } - var rest = Set.from(matchers); - rest.remove(matcher); + var rest = Set.from(matchers); + rest.remove(matcher); - try { - if (!await _tryInAnyOrder(copy, rest)) return; - } catch (error, stackTrace) { - if (firstError == null) { - firstError = error; - firstStackTrace = stackTrace; + try { + if (!await _tryInAnyOrder(copy, rest)) return; + } catch (error, stackTrace) { + if (firstError == null) { + firstError = error; + firstStackTrace = stackTrace; + } + return; } - return; - } - if (consumedMost == null || - consumedMost!.eventsDispatched < copy.eventsDispatched) { - consumedMost = copy; - } - })); + if (consumedMost == null || + consumedMost!.eventsDispatched < copy.eventsDispatched) { + consumedMost = copy; + } + }), + ); if (consumedMost == null) { transaction.reject(); diff --git a/pkgs/matcher/lib/src/expect/throws_matcher.dart b/pkgs/matcher/lib/src/expect/throws_matcher.dart index 17a8c9e20..022f9fd84 100644 --- a/pkgs/matcher/lib/src/expect/throws_matcher.dart +++ b/pkgs/matcher/lib/src/expect/throws_matcher.dart @@ -96,7 +96,9 @@ class Throws extends AsyncMatcher { /// Matches [future], using try/catch since `onError` doesn't seem to work /// properly in nnbd. Future _matchFuture( - Future future, String messagePrefix) async { + Future future, + String messagePrefix, + ) async { try { var value = await future; return indent(prettyPrint(value), first: messagePrefix); @@ -122,16 +124,20 @@ class Throws extends AsyncMatcher { var matchState = {}; if (_matcher.matches(error, matchState)) return null; - var result = _matcher - .describeMismatch(error, StringDescription(), matchState, false) - .toString(); + var result = + _matcher + .describeMismatch(error, StringDescription(), matchState, false) + .toString(); var buffer = StringBuffer(); buffer.writeln(indent(prettyPrint(error), first: 'threw ')); if (trace != null) { - buffer.writeln(indent( + buffer.writeln( + indent( TestHandle.current.formatStackTrace(trace).toString(), - first: 'stack ')); + first: 'stack ', + ), + ); } if (result.isNotEmpty) buffer.writeln(indent(result, first: 'which ')); return buffer.toString().trimRight(); diff --git a/pkgs/matcher/lib/src/expect/throws_matchers.dart b/pkgs/matcher/lib/src/expect/throws_matchers.dart index 67d35b723..28213e47b 100644 --- a/pkgs/matcher/lib/src/expect/throws_matchers.dart +++ b/pkgs/matcher/lib/src/expect/throws_matchers.dart @@ -17,15 +17,18 @@ const Matcher throwsArgumentError = Throws(isArgumentError); /// A matcher for functions that throw ConcurrentModificationError. /// /// See [throwsA] for objects that this can be matched against. -const Matcher throwsConcurrentModificationError = - Throws(isConcurrentModificationError); +const Matcher throwsConcurrentModificationError = Throws( + isConcurrentModificationError, +); /// A matcher for functions that throw CyclicInitializationError. /// /// See [throwsA] for objects that this can be matched against. -@Deprecated('throwsCyclicInitializationError has been deprecated, because ' - 'the type will longer exists in Dart 3.0. It will now catch any kind of ' - 'error, not only CyclicInitializationError.') +@Deprecated( + 'throwsCyclicInitializationError has been deprecated, because ' + 'the type will longer exists in Dart 3.0. It will now catch any kind of ' + 'error, not only CyclicInitializationError.', +) const Matcher throwsCyclicInitializationError = Throws(TypeMatcher()); /// A matcher for functions that throw Exception. @@ -46,9 +49,11 @@ const Matcher throwsNoSuchMethodError = Throws(isNoSuchMethodError); /// A matcher for functions that throw NullThrownError. /// /// See [throwsA] for objects that this can be matched against. -@Deprecated('throwsNullThrownError has been deprecated, because ' - 'NullThrownError has been replaced with TypeError. ' - 'Use `throwsA(isA())` instead.') +@Deprecated( + 'throwsNullThrownError has been deprecated, because ' + 'NullThrownError has been replaced with TypeError. ' + 'Use `throwsA(isA())` instead.', +) const Matcher throwsNullThrownError = Throws(TypeMatcher()); /// A matcher for functions that throw RangeError. diff --git a/pkgs/matcher/lib/src/feature_matcher.dart b/pkgs/matcher/lib/src/feature_matcher.dart index 1dbe56c38..413e7eb40 100644 --- a/pkgs/matcher/lib/src/feature_matcher.dart +++ b/pkgs/matcher/lib/src/feature_matcher.dart @@ -18,17 +18,28 @@ abstract class FeatureMatcher extends TypeMatcher { bool typedMatches(T item, Map matchState); @override - Description describeMismatch(Object? item, Description mismatchDescription, - Map matchState, bool verbose) { + Description describeMismatch( + Object? item, + Description mismatchDescription, + Map matchState, + bool verbose, + ) { if (item is T) { return describeTypedMismatch( - item, mismatchDescription, matchState, verbose); + item, + mismatchDescription, + matchState, + verbose, + ); } return super.describe(mismatchDescription.add('not an ')); } - Description describeTypedMismatch(T item, Description mismatchDescription, - Map matchState, bool verbose) => - mismatchDescription; + Description describeTypedMismatch( + T item, + Description mismatchDescription, + Map matchState, + bool verbose, + ) => mismatchDescription; } diff --git a/pkgs/matcher/lib/src/having_matcher.dart b/pkgs/matcher/lib/src/having_matcher.dart index 2d2dc3d4f..9cb31318c 100644 --- a/pkgs/matcher/lib/src/having_matcher.dart +++ b/pkgs/matcher/lib/src/having_matcher.dart @@ -13,28 +13,36 @@ class HavingMatcher implements TypeMatcher { final TypeMatcher _parent; final List<_FunctionMatcher> _functionMatchers; - HavingMatcher(this._parent, String description, Object? Function(T) feature, - dynamic matcher) - : _functionMatchers = [ - _FunctionMatcher(description, feature, matcher) - ]; + HavingMatcher( + this._parent, + String description, + Object? Function(T) feature, + dynamic matcher, + ) : _functionMatchers = [_FunctionMatcher(description, feature, matcher)]; HavingMatcher._fromExisting( - this._parent, - String description, - Object? Function(T) feature, - dynamic matcher, - Iterable<_FunctionMatcher>? existing) - : _functionMatchers = [ - ...?existing, - _FunctionMatcher(description, feature, matcher) - ]; + this._parent, + String description, + Object? Function(T) feature, + dynamic matcher, + Iterable<_FunctionMatcher>? existing, + ) : _functionMatchers = [ + ...?existing, + _FunctionMatcher(description, feature, matcher), + ]; @override TypeMatcher having( - Object? Function(T) feature, String description, dynamic matcher) => - HavingMatcher._fromExisting( - _parent, description, feature, matcher, _functionMatchers); + Object? Function(T) feature, + String description, + dynamic matcher, + ) => HavingMatcher._fromExisting( + _parent, + description, + feature, + matcher, + _functionMatchers, + ); @override bool matches(dynamic item, Map matchState) { @@ -48,11 +56,19 @@ class HavingMatcher implements TypeMatcher { } @override - Description describeMismatch(Object? item, Description mismatchDescription, - Map matchState, bool verbose) { + Description describeMismatch( + Object? item, + Description mismatchDescription, + Map matchState, + bool verbose, + ) { var matcher = matchState['matcher'] as Matcher; matcher.describeMismatch( - item, mismatchDescription, matchState['state'] as Map, verbose); + item, + mismatchDescription, + matchState['state'] as Map, + verbose, + ); return mismatchDescription; } @@ -68,7 +84,7 @@ class _FunctionMatcher extends CustomMatcher { final Object? Function(T value) _feature; _FunctionMatcher(String name, this._feature, Object? matcher) - : super('`$name`:', '`$name`', matcher); + : super('`$name`:', '`$name`', matcher); @override Object? featureValueOf(covariant T actual) => _feature(actual); diff --git a/pkgs/matcher/lib/src/interfaces.dart b/pkgs/matcher/lib/src/interfaces.dart index 24527f7b1..7fc700878 100644 --- a/pkgs/matcher/lib/src/interfaces.dart +++ b/pkgs/matcher/lib/src/interfaces.dart @@ -54,7 +54,10 @@ abstract class Matcher { /// A few matchers make use of the [verbose] flag to provide detailed /// information that is not typically included but can be of help in /// diagnosing failures, such as stack traces. - Description describeMismatch(dynamic item, Description mismatchDescription, - Map matchState, bool verbose) => - mismatchDescription; + Description describeMismatch( + dynamic item, + Description mismatchDescription, + Map matchState, + bool verbose, + ) => mismatchDescription; } diff --git a/pkgs/matcher/lib/src/iterable_matchers.dart b/pkgs/matcher/lib/src/iterable_matchers.dart index d9d2db3e2..0fbdb5c87 100644 --- a/pkgs/matcher/lib/src/iterable_matchers.dart +++ b/pkgs/matcher/lib/src/iterable_matchers.dart @@ -36,8 +36,12 @@ class _EveryElement extends _IterableMatcher { description.add('every element(').addDescriptionOf(_matcher).add(')'); @override - Description describeTypedMismatch(dynamic item, - Description mismatchDescription, Map matchState, bool verbose) { + Description describeTypedMismatch( + dynamic item, + Description mismatchDescription, + Map matchState, + bool verbose, + ) { if (matchState['index'] != null) { var index = matchState['index']; var element = matchState['element']; @@ -47,7 +51,11 @@ class _EveryElement extends _IterableMatcher { .add(' which '); var subDescription = StringDescription(); _matcher.describeMismatch( - element, subDescription, matchState['state'] as Map, verbose); + element, + subDescription, + matchState['state'] as Map, + verbose, + ); if (subDescription.length > 0) { mismatchDescription.add(subDescription.toString()); } else { @@ -57,8 +65,12 @@ class _EveryElement extends _IterableMatcher { mismatchDescription.add(' at index $index'); return mismatchDescription; } - return super - .describeMismatch(item, mismatchDescription, matchState, verbose); + return super.describeMismatch( + item, + mismatchDescription, + matchState, + verbose, + ); } } @@ -102,10 +114,18 @@ class _OrderedEquals extends _IterableMatcher { description.add('equals ').addDescriptionOf(_expected).add(' ordered'); @override - Description describeTypedMismatch(Iterable item, - Description mismatchDescription, Map matchState, bool verbose) { + Description describeTypedMismatch( + Iterable item, + Description mismatchDescription, + Map matchState, + bool verbose, + ) { return _matcher.describeMismatch( - item, mismatchDescription, matchState, verbose); + item, + mismatchDescription, + matchState, + verbose, + ); } } @@ -120,8 +140,8 @@ class _UnorderedEquals extends _UnorderedMatches { final List _expectedValues; _UnorderedEquals(Iterable expected) - : _expectedValues = expected.toList(), - super(expected.map(equals)); + : _expectedValues = expected.toList(), + super(expected.map(equals)); @override Description describe(Description description) => description @@ -148,8 +168,8 @@ class _UnorderedMatches extends _IterableMatcher { final bool _allowUnmatchedValues; _UnorderedMatches(Iterable expected, {bool allowUnmatchedValues = false}) - : _expected = expected.map(wrapMatcher).toList(), - _allowUnmatchedValues = allowUnmatchedValues; + : _expected = expected.map(wrapMatcher).toList(), + _allowUnmatchedValues = allowUnmatchedValues; String? _test(List values) { // Check the lengths are the same. @@ -173,9 +193,11 @@ class _UnorderedMatches extends _IterableMatcher { for (var valueIndex = 0; valueIndex < values.length; valueIndex++) { _findPairing(edges, valueIndex, matched); } - for (var matcherIndex = 0; - matcherIndex < _expected.length; - matcherIndex++) { + for ( + var matcherIndex = 0; + matcherIndex < _expected.length; + matcherIndex++ + ) { if (matched[matcherIndex] == null) { final description = StringDescription() .add('has no match for ') @@ -204,9 +226,12 @@ class _UnorderedMatches extends _IterableMatcher { .add(' unordered'); @override - Description describeTypedMismatch(Iterable item, - Description mismatchDescription, Map matchState, bool verbose) => - mismatchDescription.add(_test(item.toList())!); + Description describeTypedMismatch( + Iterable item, + Description mismatchDescription, + Map matchState, + bool verbose, + ) => mismatchDescription.add(_test(item.toList())!); /// Returns `true` if the value at [valueIndex] can be paired with some /// unmatched matcher and updates the state of [matched]. @@ -214,15 +239,22 @@ class _UnorderedMatches extends _IterableMatcher { /// If there is a conflict where multiple values may match the same matcher /// recursively looks for a new place to match the old value. bool _findPairing( - List> edges, int valueIndex, List matched) => - _findPairingInner(edges, valueIndex, matched, {}); + List> edges, + int valueIndex, + List matched, + ) => _findPairingInner(edges, valueIndex, matched, {}); /// Implementation of [_findPairing], tracks [reserved] which are the /// matchers that have been used _during_ this search. - bool _findPairingInner(List> edges, int valueIndex, - List matched, Set reserved) { - final possiblePairings = - edges[valueIndex].where((m) => !reserved.contains(m)); + bool _findPairingInner( + List> edges, + int valueIndex, + List matched, + Set reserved, + ) { + final possiblePairings = edges[valueIndex].where( + (m) => !reserved.contains(m), + ); for (final matcherIndex in possiblePairings) { reserved.add(matcherIndex); final previouslyMatched = matched[matcherIndex]; @@ -243,9 +275,11 @@ class _UnorderedMatches extends _IterableMatcher { /// The [comparator] function, taking an expected and an actual argument, and /// returning whether they match, will be applied to each pair in order. /// [description] should be a meaningful name for the comparator. -Matcher pairwiseCompare(Iterable expected, - bool Function(S, T) comparator, String description) => - _PairwiseCompare(expected, comparator, description); +Matcher pairwiseCompare( + Iterable expected, + bool Function(S, T) comparator, + String description, +) => _PairwiseCompare(expected, comparator, description); typedef _Comparator = bool Function(S a, T b); @@ -264,8 +298,11 @@ class _PairwiseCompare extends _IterableMatcher { for (var e in _expected) { iterator.moveNext(); if (!_comparator(e, iterator.current as T)) { - addStateInfo(matchState, - {'index': i, 'expected': e, 'actual': iterator.current}); + addStateInfo(matchState, { + 'index': i, + 'expected': e, + 'actual': iterator.current, + }); return false; } i++; @@ -278,11 +315,16 @@ class _PairwiseCompare extends _IterableMatcher { description.add('pairwise $_description ').addDescriptionOf(_expected); @override - Description describeTypedMismatch(Iterable item, - Description mismatchDescription, Map matchState, bool verbose) { + Description describeTypedMismatch( + Iterable item, + Description mismatchDescription, + Map matchState, + bool verbose, + ) { if (item.length != _expected.length) { - return mismatchDescription - .add('has length ${item.length} instead of ${_expected.length}'); + return mismatchDescription.add( + 'has length ${item.length} instead of ${_expected.length}', + ); } else { return mismatchDescription .add('has ') @@ -317,8 +359,8 @@ class _ContainsAll extends _UnorderedMatches { final Iterable _unwrappedExpected; _ContainsAll(Iterable expected) - : _unwrappedExpected = expected, - super(expected.map(wrapMatcher), allowUnmatchedValues: true); + : _unwrappedExpected = expected, + super(expected.map(wrapMatcher), allowUnmatchedValues: true); @override Description describe(Description description) => description.add('contains all of ').addDescriptionOf(_unwrappedExpected); @@ -364,9 +406,12 @@ class _ContainsAllInOrder extends _IterableMatcher { .add(')'); @override - Description describeTypedMismatch(Iterable item, - Description mismatchDescription, Map matchState, bool verbose) => - mismatchDescription.add(_test(item, matchState)!); + Description describeTypedMismatch( + Iterable item, + Description mismatchDescription, + Map matchState, + bool verbose, + ) => mismatchDescription.add(_test(item, matchState)!); } /// Matches [Iterable]s where exactly one element matches the expected @@ -410,9 +455,12 @@ class _ContainsOnce extends _IterableMatcher { description.add('contains once(').addDescriptionOf(_expected).add(')'); @override - Description describeTypedMismatch(Iterable item, - Description mismatchDescription, Map matchState, bool verbose) => - mismatchDescription.add(_test(item, matchState)!); + Description describeTypedMismatch( + Iterable item, + Description mismatchDescription, + Map matchState, + bool verbose, + ) => mismatchDescription.add(_test(item, matchState)!); } /// Matches [Iterable]s which are sorted. @@ -436,8 +484,8 @@ class _IsSorted extends _IterableMatcher { final Comparator _compare; _IsSorted(K Function(T) keyOf, Comparator compare) - : _keyOf = keyOf, - _compare = compare; + : _keyOf = keyOf, + _compare = compare; @override bool typedMatches(Iterable item, Map matchState) { @@ -452,7 +500,7 @@ class _IsSorted extends _IterableMatcher { 'index': 0, 'element': previousElement, 'error': e, - 'keyError': true + 'keyError': true, }); return false; } @@ -464,8 +512,12 @@ class _IsSorted extends _IterableMatcher { try { key = _keyOf(element); } catch (e) { - addStateInfo(matchState, - {'index': index, 'element': element, 'error': e, 'keyError': true}); + addStateInfo(matchState, { + 'index': index, + 'element': element, + 'error': e, + 'keyError': true, + }); return false; } @@ -478,14 +530,17 @@ class _IsSorted extends _IterableMatcher { 'first': previousElement, 'second': element, 'error': e, - 'compareError': true + 'compareError': true, }); return false; } if (comparison > 0) { - addStateInfo(matchState, - {'index': index, 'first': previousElement, 'second': element}); + addStateInfo(matchState, { + 'index': index, + 'first': previousElement, + 'second': element, + }); return false; } previousElement = element; @@ -499,8 +554,12 @@ class _IsSorted extends _IterableMatcher { Description describe(Description description) => description.add('is sorted'); @override - Description describeTypedMismatch(Iterable item, - Description mismatchDescription, Map matchState, bool verbose) { + Description describeTypedMismatch( + Iterable item, + Description mismatchDescription, + Map matchState, + bool verbose, + ) { if (matchState.containsKey('error')) { mismatchDescription .add('got error ') diff --git a/pkgs/matcher/lib/src/map_matchers.dart b/pkgs/matcher/lib/src/map_matchers.dart index 9bc9eb5a4..7026c7482 100644 --- a/pkgs/matcher/lib/src/map_matchers.dart +++ b/pkgs/matcher/lib/src/map_matchers.dart @@ -49,8 +49,12 @@ class _ContainsMapping extends Matcher { } @override - Description describeMismatch(Object? item, Description mismatchDescription, - Map matchState, bool verbose) { + Description describeMismatch( + Object? item, + Description mismatchDescription, + Map matchState, + bool verbose, + ) { // ignore: avoid_dynamic_calls if (!((item as dynamic).containsKey(_key) as bool)) { return mismatchDescription @@ -62,7 +66,11 @@ class _ContainsMapping extends Matcher { .addDescriptionOf(_key) .add(' but with value '); _valueMatcher.describeMismatch( - (item as dynamic)[_key], mismatchDescription, matchState, verbose); + (item as dynamic)[_key], + mismatchDescription, + matchState, + verbose, + ); return mismatchDescription; } } diff --git a/pkgs/matcher/lib/src/numeric_matchers.dart b/pkgs/matcher/lib/src/numeric_matchers.dart index a7981609e..22c3d7c5a 100644 --- a/pkgs/matcher/lib/src/numeric_matchers.dart +++ b/pkgs/matcher/lib/src/numeric_matchers.dart @@ -33,7 +33,11 @@ class _IsCloseTo extends FeatureMatcher { @override Description describeTypedMismatch( - num item, Description mismatchDescription, Map matchState, bool verbose) { + num item, + Description mismatchDescription, + Map matchState, + bool verbose, + ) { var diff = item - _value; if (diff < 0) diff = -diff; return mismatchDescription.add(' differs by ').addDescriptionOf(diff); @@ -64,7 +68,11 @@ class _InRange extends FeatureMatcher { final bool _lowMatchValue, _highMatchValue; const _InRange( - this._low, this._high, this._lowMatchValue, this._highMatchValue); + this._low, + this._high, + this._lowMatchValue, + this._highMatchValue, + ); @override bool typedMatches(num value, Map matchState) { @@ -82,8 +90,9 @@ class _InRange extends FeatureMatcher { } @override - Description describe(Description description) => - description.add('be in range from ' - "$_low (${_lowMatchValue ? 'inclusive' : 'exclusive'}) to " - "$_high (${_highMatchValue ? 'inclusive' : 'exclusive'})"); + Description describe(Description description) => description.add( + 'be in range from ' + "$_low (${_lowMatchValue ? 'inclusive' : 'exclusive'}) to " + "$_high (${_highMatchValue ? 'inclusive' : 'exclusive'})", + ); } diff --git a/pkgs/matcher/lib/src/operator_matchers.dart b/pkgs/matcher/lib/src/operator_matchers.dart index 18f953701..8ff253274 100644 --- a/pkgs/matcher/lib/src/operator_matchers.dart +++ b/pkgs/matcher/lib/src/operator_matchers.dart @@ -28,13 +28,15 @@ class _IsNot extends Matcher { /// Instead of passing the matchers separately they can be passed as a single /// List argument. Any argument that is not a matcher is implicitly wrapped in a /// Matcher to check for equality. -Matcher allOf(Object? arg0, - [Object? arg1, - Object? arg2, - Object? arg3, - Object? arg4, - Object? arg5, - Object? arg6]) { +Matcher allOf( + Object? arg0, [ + Object? arg1, + Object? arg2, + Object? arg3, + Object? arg4, + Object? arg5, + Object? arg6, +]) { return _AllOf(_wrapArgs(arg0, arg1, arg2, arg3, arg4, arg5, arg6)); } @@ -55,11 +57,19 @@ class _AllOf extends Matcher { } @override - Description describeMismatch(dynamic item, Description mismatchDescription, - Map matchState, bool verbose) { + Description describeMismatch( + dynamic item, + Description mismatchDescription, + Map matchState, + bool verbose, + ) { var matcher = matchState['matcher'] as Matcher; matcher.describeMismatch( - item, mismatchDescription, matchState['state'] as Map, verbose); + item, + mismatchDescription, + matchState['state'] as Map, + verbose, + ); return mismatchDescription; } @@ -78,13 +88,15 @@ class _AllOf extends Matcher { /// /// Any argument that is not a matcher is implicitly wrapped in a /// Matcher to check for equality. -Matcher anyOf(Object? arg0, - [Object? arg1, - Object? arg2, - Object? arg3, - Object? arg4, - Object? arg5, - Object? arg6]) { +Matcher anyOf( + Object? arg0, [ + Object? arg1, + Object? arg2, + Object? arg3, + Object? arg4, + Object? arg5, + Object? arg6, +]) { return _AnyOf(_wrapArgs(arg0, arg1, arg2, arg3, arg4, arg5, arg6)); } @@ -108,8 +120,15 @@ class _AnyOf extends Matcher { description.addAll('(', ' or ', ')', _matchers); } -List _wrapArgs(Object? arg0, Object? arg1, Object? arg2, Object? arg3, - Object? arg4, Object? arg5, Object? arg6) { +List _wrapArgs( + Object? arg0, + Object? arg1, + Object? arg2, + Object? arg3, + Object? arg4, + Object? arg5, + Object? arg6, +) { Iterable args; if (arg0 is List) { if (arg1 != null || @@ -118,8 +137,10 @@ List _wrapArgs(Object? arg0, Object? arg1, Object? arg2, Object? arg3, arg4 != null || arg5 != null || arg6 != null) { - throw ArgumentError('If arg0 is a List, all other arguments must be' - ' null.'); + throw ArgumentError( + 'If arg0 is a List, all other arguments must be' + ' null.', + ); } args = arg0; diff --git a/pkgs/matcher/lib/src/order_matchers.dart b/pkgs/matcher/lib/src/order_matchers.dart index 7dc9e4f5a..d87c74ac7 100644 --- a/pkgs/matcher/lib/src/order_matchers.dart +++ b/pkgs/matcher/lib/src/order_matchers.dart @@ -12,7 +12,12 @@ Matcher greaterThan(Object value) => /// Returns a matcher which matches if the match argument is greater /// than or equal to the given [value]. Matcher greaterThanOrEqualTo(Object value) => _OrderingMatcher( - value, true, false, true, 'a value greater than or equal to'); + value, + true, + false, + true, + 'a value greater than or equal to', +); /// Returns a matcher which matches if the match argument is less /// than the given [value]. @@ -25,28 +30,62 @@ Matcher lessThanOrEqualTo(Object value) => _OrderingMatcher(value, true, true, false, 'a value less than or equal to'); /// A matcher which matches if the match argument is zero. -const Matcher isZero = - _OrderingMatcher(0, true, false, false, 'a value equal to'); +const Matcher isZero = _OrderingMatcher( + 0, + true, + false, + false, + 'a value equal to', +); /// A matcher which matches if the match argument is non-zero. -const Matcher isNonZero = - _OrderingMatcher(0, false, true, true, 'a value not equal to'); +const Matcher isNonZero = _OrderingMatcher( + 0, + false, + true, + true, + 'a value not equal to', +); /// A matcher which matches if the match argument is positive. -const Matcher isPositive = - _OrderingMatcher(0, false, false, true, 'a positive value', false); +const Matcher isPositive = _OrderingMatcher( + 0, + false, + false, + true, + 'a positive value', + false, +); /// A matcher which matches if the match argument is zero or negative. -const Matcher isNonPositive = - _OrderingMatcher(0, true, true, false, 'a non-positive value', false); +const Matcher isNonPositive = _OrderingMatcher( + 0, + true, + true, + false, + 'a non-positive value', + false, +); /// A matcher which matches if the match argument is negative. -const Matcher isNegative = - _OrderingMatcher(0, false, true, false, 'a negative value', false); +const Matcher isNegative = _OrderingMatcher( + 0, + false, + true, + false, + 'a negative value', + false, +); /// A matcher which matches if the match argument is zero or positive. -const Matcher isNonNegative = - _OrderingMatcher(0, true, false, true, 'a non-negative value', false); +const Matcher isNonNegative = _OrderingMatcher( + 0, + true, + false, + true, + 'a non-negative value', + false, +); // TODO(kevmoo) Note that matchers that use _OrderingComparison only use // `==` and `<` operators to evaluate the match. Or change the matcher. @@ -69,10 +108,14 @@ class _OrderingMatcher extends Matcher { /// Whether to include the expected value in the description final bool _valueInDescription; - const _OrderingMatcher(this._value, this._equalValue, this._lessThanValue, - this._greaterThanValue, this._comparisonDescription, - [bool valueInDescription = true]) - : _valueInDescription = valueInDescription; + const _OrderingMatcher( + this._value, + this._equalValue, + this._lessThanValue, + this._greaterThanValue, + this._comparisonDescription, [ + bool valueInDescription = true, + ]) : _valueInDescription = valueInDescription; @override bool matches(Object? item, Map matchState) { @@ -100,8 +143,12 @@ class _OrderingMatcher extends Matcher { } @override - Description describeMismatch(dynamic item, Description mismatchDescription, - Map matchState, bool verbose) { + Description describeMismatch( + dynamic item, + Description mismatchDescription, + Map matchState, + bool verbose, + ) { mismatchDescription.add('is not '); return describe(mismatchDescription); } diff --git a/pkgs/matcher/lib/src/pretty_print.dart b/pkgs/matcher/lib/src/pretty_print.dart index d9eaaeccf..0abd4a856 100644 --- a/pkgs/matcher/lib/src/pretty_print.dart +++ b/pkgs/matcher/lib/src/pretty_print.dart @@ -17,7 +17,11 @@ import 'util.dart'; /// [maxItems] members or key/value pairs, respectively. String prettyPrint(Object? object, {int? maxLineLength, int? maxItems}) { String prettyPrintImpl( - Object? object, int indent, Set seen, bool top) { + Object? object, + int indent, + Set seen, + bool top, + ) { // If the object is a matcher, use its description. if (object is Matcher) { var description = StringDescription(); @@ -55,9 +59,10 @@ String prettyPrint(Object? object, {int? maxLineLength, int? maxItems}) { }).join(',\n')}\n${_indent(indent)}]'; } else if (object is Map) { // Convert the contents of the map to string representations. - var strings = object.keys.map((key) { - return '${pp(key)}: ${pp(object[key])}'; - }).toList(); + var strings = + object.keys.map((key) { + return '${pp(key)}: ${pp(object[key])}'; + }).toList(); // Truncate the list of strings if it's longer than [maxItems]. if (maxItems != null && strings.length > maxItems) { diff --git a/pkgs/matcher/lib/src/string_matchers.dart b/pkgs/matcher/lib/src/string_matchers.dart index 4e7dda503..009773391 100644 --- a/pkgs/matcher/lib/src/string_matchers.dart +++ b/pkgs/matcher/lib/src/string_matchers.dart @@ -14,8 +14,8 @@ class _IsEqualIgnoringCase extends FeatureMatcher { final String _matchValue; _IsEqualIgnoringCase(String value) - : _value = value, - _matchValue = value.toLowerCase(); + : _value = value, + _matchValue = value.toLowerCase(); @override bool typedMatches(String item, Map matchState) => @@ -50,7 +50,7 @@ class _IsEqualIgnoringWhitespace extends FeatureMatcher { final String _matchValue; _IsEqualIgnoringWhitespace(String value) - : _matchValue = collapseWhitespace(value); + : _matchValue = collapseWhitespace(value); @override bool typedMatches(String item, Map matchState) => @@ -61,8 +61,12 @@ class _IsEqualIgnoringWhitespace extends FeatureMatcher { description.addDescriptionOf(_matchValue).add(' ignoring whitespace'); @override - Description describeTypedMismatch(String item, - Description mismatchDescription, Map matchState, bool verbose) { + Description describeTypedMismatch( + String item, + Description mismatchDescription, + Map matchState, + bool verbose, + ) { return mismatchDescription .add('is ') .addDescriptionOf(collapseWhitespace(item)) @@ -131,7 +135,11 @@ class _StringContainsInOrder extends FeatureMatcher { @override Description describe(Description description) => description.addAll( - 'a string containing ', ', ', ' in order', _substrings); + 'a string containing ', + ', ', + ' in order', + _substrings, + ); } /// Returns a matcher that matches if the match argument is a string and @@ -145,11 +153,12 @@ class _MatchesRegExp extends FeatureMatcher { final RegExp _regexp; _MatchesRegExp(Pattern re) - : _regexp = (re is String) - ? RegExp(re) - : (re is RegExp) - ? re - : throw ArgumentError('matches requires a regexp or string'); + : _regexp = + (re is String) + ? RegExp(re) + : (re is RegExp) + ? re + : throw ArgumentError('matches requires a regexp or string'); @override bool typedMatches(String item, Map matchState) => _regexp.hasMatch(item); diff --git a/pkgs/matcher/lib/src/type_matcher.dart b/pkgs/matcher/lib/src/type_matcher.dart index 9d32b9fba..179509987 100644 --- a/pkgs/matcher/lib/src/type_matcher.dart +++ b/pkgs/matcher/lib/src/type_matcher.dart @@ -59,13 +59,15 @@ class TypeMatcher extends Matcher { /// Create a matcher matches instances of type [T]. /// /// For a fluent API to create TypeMatchers see [isA]. - const TypeMatcher( - [@Deprecated('Provide a type argument to TypeMatcher and omit the name. ' - 'This argument will be removed in the next release.') - String? name]) - : _name = - // ignore: deprecated_member_use_from_same_package - name; + const TypeMatcher([ + @Deprecated( + 'Provide a type argument to TypeMatcher and omit the name. ' + 'This argument will be removed in the next release.', + ) + String? name, + ]) : _name = + // ignore: deprecated_member_use_from_same_package + name; /// Returns a new [TypeMatcher] that validates the existing type as well as /// a specific [feature] of the object with the provided [matcher]. @@ -83,8 +85,10 @@ class TypeMatcher extends Matcher { /// ``` @useResult TypeMatcher having( - Object? Function(T) feature, String description, dynamic matcher) => - HavingMatcher(this, description, feature, matcher); + Object? Function(T) feature, + String description, + dynamic matcher, + ) => HavingMatcher(this, description, feature, matcher); @override Description describe(Description description) { @@ -96,8 +100,12 @@ class TypeMatcher extends Matcher { bool matches(Object? item, Map matchState) => item is T; @override - Description describeMismatch(dynamic item, Description mismatchDescription, - Map matchState, bool verbose) { + Description describeMismatch( + dynamic item, + Description mismatchDescription, + Map matchState, + bool verbose, + ) { var name = _name ?? _stripDynamic(T); return mismatchDescription.add("is not an instance of '$name'"); } diff --git a/pkgs/matcher/lib/src/util.dart b/pkgs/matcher/lib/src/util.dart index 511831ef9..9ef144b20 100644 --- a/pkgs/matcher/lib/src/util.dart +++ b/pkgs/matcher/lib/src/util.dart @@ -19,7 +19,8 @@ const _escapeMap = { /// A [RegExp] that matches whitespace characters that should be escaped. final _escapeRegExp = RegExp( - '[\\x00-\\x07\\x0E-\\x1F${_escapeMap.keys.map(_getHexLiteral).join()}]'); + '[\\x00-\\x07\\x0E-\\x1F${_escapeMap.keys.map(_getHexLiteral).join()}]', +); /// Useful utility for nesting match states. void addStateInfo(Map matchState, Map values) { diff --git a/pkgs/matcher/test/core_matchers_test.dart b/pkgs/matcher/test/core_matchers_test.dart index b20f31ffe..0a764312d 100644 --- a/pkgs/matcher/test/core_matchers_test.dart +++ b/pkgs/matcher/test/core_matchers_test.dart @@ -60,7 +60,10 @@ void main() { var b = {}; shouldPass(a, equals(a)); shouldFail( - a, equals(b), 'Expected: {} Actual: Which: expected a map'); + a, + equals(b), + 'Expected: {} Actual: Which: expected a map', + ); shouldFail(b, equals(a), 'Expected: Actual: {}'); }); @@ -73,17 +76,23 @@ void main() { shouldPass(set2, equals(set1)); shouldPass(numbers, equals(set1)); shouldFail( - [1, 2, 3, 4, 5, 6, 7, 8, 9], - equals(set1), - matches(r'Expected: .*:\[1, 2, 3, 4, 5, 6, 7, 8, 9, 10\]' - r' Actual: \[1, 2, 3, 4, 5, 6, 7, 8, 9\]' - r' Which: does not contain <10>')); + [1, 2, 3, 4, 5, 6, 7, 8, 9], + equals(set1), + matches( + r'Expected: .*:\[1, 2, 3, 4, 5, 6, 7, 8, 9, 10\]' + r' Actual: \[1, 2, 3, 4, 5, 6, 7, 8, 9\]' + r' Which: does not contain <10>', + ), + ); shouldFail( - [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], - equals(set1), - matches(r'Expected: .*:\[1, 2, 3, 4, 5, 6, 7, 8, 9, 10\]' - r' Actual: \[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11\]' - r' Which: larger than expected')); + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], + equals(set1), + matches( + r'Expected: .*:\[1, 2, 3, 4, 5, 6, 7, 8, 9, 10\]' + r' Actual: \[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11\]' + r' Which: larger than expected', + ), + ); }); test('anything', () { @@ -97,13 +106,19 @@ void main() { test('returnsNormally', () { shouldPass(doesNotThrow, returnsNormally); shouldFail( - doesThrow, - returnsNormally, - matches(r'Expected: return normally' - r' Actual: ' - r' Which: threw StateError:')); - shouldFail('not a function', returnsNormally, - contains('not an ')); + doesThrow, + returnsNormally, + matches( + r'Expected: return normally' + r' Actual: ' + r' Which: threw StateError:', + ), + ); + shouldFail( + 'not a function', + returnsNormally, + contains('not an '), + ); }); test('hasLength', () { @@ -113,59 +128,65 @@ void main() { shouldPass(b, hasLength(0)); shouldPass('a', hasLength(1)); shouldFail( - 0, - hasLength(0), - 'Expected: an object with length of <0> ' - 'Actual: <0> ' - 'Which: has no length property'); + 0, + hasLength(0), + 'Expected: an object with length of <0> ' + 'Actual: <0> ' + 'Which: has no length property', + ); b.add(0); shouldPass(b, hasLength(1)); shouldFail( - b, - hasLength(2), - 'Expected: an object with length of <2> ' - 'Actual: [0] ' - 'Which: has length of <1>'); + b, + hasLength(2), + 'Expected: an object with length of <2> ' + 'Actual: [0] ' + 'Which: has length of <1>', + ); b.add(0); shouldFail( - b, - hasLength(1), - 'Expected: an object with length of <1> ' - 'Actual: [0, 0] ' - 'Which: has length of <2>'); + b, + hasLength(1), + 'Expected: an object with length of <1> ' + 'Actual: [0, 0] ' + 'Which: has length of <2>', + ); shouldPass(b, hasLength(2)); }); test('scalar type mismatch', () { shouldFail( - 'error', - equals(5.1), - 'Expected: <5.1> ' - "Actual: 'error'"); + 'error', + equals(5.1), + 'Expected: <5.1> ' + "Actual: 'error'", + ); }); test('nested type mismatch', () { shouldFail( - ['error'], - equals([5.1]), - 'Expected: [5.1] ' - "Actual: ['error'] " - "Which: at location [0] is 'error' instead of <5.1>"); + ['error'], + equals([5.1]), + 'Expected: [5.1] ' + "Actual: ['error'] " + "Which: at location [0] is 'error' instead of <5.1>", + ); }); test('doubly-nested type mismatch', () { shouldFail( - [ - ['error'] - ], - equals([ - [5.1] - ]), - 'Expected: [[5.1]] ' - "Actual: [['error']] " - "Which: at location [0][0] is 'error' instead of <5.1>"); + [ + ['error'], + ], + equals([ + [5.1], + ]), + 'Expected: [[5.1]] ' + "Actual: [['error']] " + "Which: at location [0][0] is 'error' instead of <5.1>", + ); }); test('doubly nested inequality', () { @@ -173,15 +194,16 @@ void main() { ['foo', 'bar'], ['foo'], 3, - [] + [], ]; var expected1 = [ ['foo', 'bar'], ['foo'], 4, - [] + [], ]; - var reason1 = "Expected: [['foo', 'bar'], ['foo'], 4, []] " + var reason1 = + "Expected: [['foo', 'bar'], ['foo'], 4, []] " "Actual: [['foo', 'bar'], ['foo'], 3, []] " 'Which: at location [2] is <3> instead of <4>'; @@ -189,15 +211,16 @@ void main() { ['foo', 'barry'], ['foo'], 4, - [] + [], ]; var expected2 = [ ['foo', 'bar'], ['foo'], 4, - [] + [], ]; - var reason2 = "Expected: [['foo', 'bar'], ['foo'], 4, []] " + var reason2 = + "Expected: [['foo', 'bar'], ['foo'], 4, []] " "Actual: [['foo', 'barry'], ['foo'], 4, []] " "Which: at location [0][1] is 'barry' instead of 'bar'"; @@ -205,15 +228,16 @@ void main() { ['foo', 'bar'], ['foo'], 4, - {'foo': 'bar'} + {'foo': 'bar'}, ]; var expected3 = [ ['foo', 'bar'], ['foo'], 4, - {'foo': 'barry'} + {'foo': 'barry'}, ]; - var reason3 = "Expected: [['foo', 'bar'], ['foo'], 4, {'foo': 'barry'}] " + var reason3 = + "Expected: [['foo', 'bar'], ['foo'], 4, {'foo': 'barry'}] " "Actual: [['foo', 'bar'], ['foo'], 4, {'foo': 'bar'}] " "Which: at location [3]['foo'] is 'bar' instead of 'barry'"; @@ -224,12 +248,18 @@ void main() { group('Predicate Matchers', () { test('isInstanceOf', () { - shouldFail(0, predicate((x) => x is String, 'an instance of String'), - 'Expected: an instance of String Actual: <0>'); + shouldFail( + 0, + predicate((x) => x is String, 'an instance of String'), + 'Expected: an instance of String Actual: <0>', + ); shouldPass('cow', predicate((x) => x is String, 'an instance of String')); - shouldFail(0, predicate((bool x) => x, 'bool value is true'), - endsWith("not an ")); + shouldFail( + 0, + predicate((bool x) => x, 'bool value is true'), + endsWith("not an "), + ); }); }); diff --git a/pkgs/matcher/test/custom_matcher_test.dart b/pkgs/matcher/test/custom_matcher_test.dart index d0a17c9ea..16e2adc49 100644 --- a/pkgs/matcher/test/custom_matcher_test.dart +++ b/pkgs/matcher/test/custom_matcher_test.dart @@ -15,7 +15,7 @@ class _BadCustomMatcher extends CustomMatcher { class _HasPrice extends CustomMatcher { _HasPrice(Object? matcher) - : super('Widget with a price that is', 'price', matcher); + : super('Widget with a price that is', 'price', matcher); @override Object? featureValueOf(Object? actual) => (actual as Widget).price; } @@ -27,22 +27,24 @@ void main() { shouldPass(w, _HasPrice(10)); shouldPass(w, _HasPrice(greaterThan(0))); shouldFail( - w, - _HasPrice(greaterThan(10)), - 'Expected: Widget with a price that is a value greater than <10> ' - "Actual: " - 'Which: has price with value <10> which is not ' - 'a value greater than <10>'); + w, + _HasPrice(greaterThan(10)), + 'Expected: Widget with a price that is a value greater than <10> ' + "Actual: " + 'Which: has price with value <10> which is not ' + 'a value greater than <10>', + ); }); test('Custom Matcher Exception', () { shouldFail( - 'a', - _BadCustomMatcher(), - allOf([ - contains("Expected: feature {1: 'a'} "), - contains("Actual: 'a' "), - contains("Which: threw 'Exception: bang' "), - ])); + 'a', + _BadCustomMatcher(), + allOf([ + contains("Expected: feature {1: 'a'} "), + contains("Actual: 'a' "), + contains("Which: threw 'Exception: bang' "), + ]), + ); }); } diff --git a/pkgs/matcher/test/escape_test.dart b/pkgs/matcher/test/escape_test.dart index c898054e5..955458e07 100644 --- a/pkgs/matcher/test/escape_test.dart +++ b/pkgs/matcher/test/escape_test.dart @@ -20,13 +20,14 @@ void main() { _testEscaping('delete', '\x7F', r'\x7F'); _testEscaping('escape combos', r'\n', r'\\n'); _testEscaping( - 'All characters', - 'A new line\nA charriage return\rA form feed\fA backspace\b' - 'A tab\tA vertical tab\vA slash\\A null byte\x00A control char\x1D' - 'A delete\x7F', - r'A new line\nA charriage return\rA form feed\fA backspace\b' - r'A tab\tA vertical tab\vA slash\\A null byte\x00A control char\x1D' - r'A delete\x7F'); + 'All characters', + 'A new line\nA charriage return\rA form feed\fA backspace\b' + 'A tab\tA vertical tab\vA slash\\A null byte\x00A control char\x1D' + 'A delete\x7F', + r'A new line\nA charriage return\rA form feed\fA backspace\b' + r'A tab\tA vertical tab\vA slash\\A null byte\x00A control char\x1D' + r'A delete\x7F', + ); }); group('unequal strings remain unequal when escaped', () { @@ -40,9 +41,13 @@ void main() { void _testEscaping(String name, String source, String target) { test(name, () { var escaped = escape(source); - expect(escaped == target, isTrue, - reason: 'Expected escaped value: $target\n' - ' Actual escaped value: $escaped'); + expect( + escaped == target, + isTrue, + reason: + 'Expected escaped value: $target\n' + ' Actual escaped value: $escaped', + ); }); } @@ -57,7 +62,10 @@ void _testUnequalStrings(String name, String s1, String s2) { var escapedS2 = escape(s2); // Explicitly not using the equals matcher - expect(escapedS1 != escapedS2, isTrue, - reason: 'Unequal strings, when escaped, should remain unequal.'); + expect( + escapedS1 != escapedS2, + isTrue, + reason: 'Unequal strings, when escaped, should remain unequal.', + ); }); } diff --git a/pkgs/matcher/test/expect_async_test.dart b/pkgs/matcher/test/expect_async_test.dart index 7619893b7..bb00951d7 100644 --- a/pkgs/matcher/test/expect_async_test.dart +++ b/pkgs/matcher/test/expect_async_test.dart @@ -171,13 +171,14 @@ void main() { }); expectTestFailed( - monitor, 'Callback called more times than expected (1).'); + monitor, + 'Callback called more times than expected (1).', + ); }); }); group('with count', () { - test( - "won't allow the test to complete until it's called at least that " + test("won't allow the test to complete until it's called at least that " 'many times', () async { late void Function() callback; final monitor = TestCaseMonitor.start(() { @@ -201,19 +202,23 @@ void main() { expectTestPassed(monitor); }); - test("will throw an error if it's called more than that many times", - () async { - var monitor = await TestCaseMonitor.run(() { - var callback = expectAsync0(() {}, count: 3); - callback(); - callback(); - callback(); - callback(); - }); + test( + "will throw an error if it's called more than that many times", + () async { + var monitor = await TestCaseMonitor.run(() { + var callback = expectAsync0(() {}, count: 3); + callback(); + callback(); + callback(); + callback(); + }); - expectTestFailed( - monitor, 'Callback called more times than expected (3).'); - }); + expectTestFailed( + monitor, + 'Callback called more times than expected (3).', + ); + }, + ); group('0,', () { test("won't block the test's completion", () { @@ -226,7 +231,9 @@ void main() { }); expectTestFailed( - monitor, 'Callback called more times than expected (0).'); + monitor, + 'Callback called more times than expected (0).', + ); }); }); }); @@ -244,19 +251,23 @@ void main() { callback(); }); - test("will throw an error if it's called more than that many times", - () async { - var monitor = await TestCaseMonitor.run(() { - var callback = expectAsync0(() {}, max: 3); - callback(); - callback(); - callback(); - callback(); - }); + test( + "will throw an error if it's called more than that many times", + () async { + var monitor = await TestCaseMonitor.run(() { + var callback = expectAsync0(() {}, max: 3); + callback(); + callback(); + callback(); + callback(); + }); - expectTestFailed( - monitor, 'Callback called more times than expected (3).'); - }); + expectTestFailed( + monitor, + 'Callback called more times than expected (3).', + ); + }, + ); test('-1, will allow the callback to be called any number of times', () { var callback = expectAsync0(() {}, max: -1); @@ -271,31 +282,33 @@ void main() { }); group('expectAsyncUntil()', () { - test("won't allow the test to complete until isDone returns true", - () async { - late TestCaseMonitor monitor; - late Future future; - monitor = TestCaseMonitor.start(() { - var done = false; - var callback = expectAsyncUntil0(() {}, () => done); - - future = () async { - await pumpEventQueue(); - expect(monitor.state, equals(State.running)); - callback(); - await pumpEventQueue(); - expect(monitor.state, equals(State.running)); - done = true; - callback(); - }(); - }); - await monitor.onDone; - - expectTestPassed(monitor); - // Ensure that the outer test doesn't complete until the inner future - // completes. - await future; - }); + test( + "won't allow the test to complete until isDone returns true", + () async { + late TestCaseMonitor monitor; + late Future future; + monitor = TestCaseMonitor.start(() { + var done = false; + var callback = expectAsyncUntil0(() {}, () => done); + + future = () async { + await pumpEventQueue(); + expect(monitor.state, equals(State.running)); + callback(); + await pumpEventQueue(); + expect(monitor.state, equals(State.running)); + done = true; + callback(); + }(); + }); + await monitor.onDone; + + expectTestPassed(monitor); + // Ensure that the outer test doesn't complete until the inner future + // completes. + await future; + }, + ); test("doesn't call isDone until after the callback is called", () { var callbackRun = false; diff --git a/pkgs/matcher/test/expect_test.dart b/pkgs/matcher/test/expect_test.dart index 70ce57945..0203ed76e 100644 --- a/pkgs/matcher/test/expect_test.dart +++ b/pkgs/matcher/test/expect_test.dart @@ -13,20 +13,26 @@ void main() { }); test('contains the expect failure', () { - expect(expectLater(Future.value(true), completion(isFalse)), - throwsA(isTestFailure(anything))); + expect( + expectLater(Future.value(true), completion(isFalse)), + throwsA(isTestFailure(anything)), + ); }); test('contains an async error', () { - expect(expectLater(Future.error('oh no'), completion(isFalse)), - throwsA('oh no')); + expect( + expectLater(Future.error('oh no'), completion(isFalse)), + throwsA('oh no'), + ); }); }); group('an async matcher that fails synchronously', () { test('throws synchronously', () { - expect(() => expect(() {}, throwsA(anything)), - throwsA(isTestFailure(anything))); + expect( + () => expect(() {}, throwsA(anything)), + throwsA(isTestFailure(anything)), + ); }); test('can be used with synchronous operators', () { diff --git a/pkgs/matcher/test/having_test.dart b/pkgs/matcher/test/having_test.dart index 26592cddb..89396ac5d 100644 --- a/pkgs/matcher/test/having_test.dart +++ b/pkgs/matcher/test/having_test.dart @@ -33,42 +33,52 @@ void main() { } expect( - () => shouldThrowRangeError(5), - throwsA(const TypeMatcher() + () => shouldThrowRangeError(5), + throwsA( + const TypeMatcher() .having((e) => e.start, 'start', greaterThanOrEqualTo(10)) - .having((e) => e.end, 'end', lessThanOrEqualTo(20)))); + .having((e) => e.end, 'end', lessThanOrEqualTo(20)), + ), + ); expect( - () => shouldThrowRangeError(5), - throwsA(isRangeError + () => shouldThrowRangeError(5), + throwsA( + isRangeError .having((e) => e.start, 'start', greaterThanOrEqualTo(10)) - .having((e) => e.end, 'end', lessThanOrEqualTo(20)))); + .having((e) => e.end, 'end', lessThanOrEqualTo(20)), + ), + ); }); test('having inside deep matcher', () { shouldFail( - [RangeError.range(-1, 1, 10)], - equals([_rangeMatcher]), - anyOf([ - equalsIgnoringWhitespace( - "Expected: [ < with " - "`message`: contains 'details' and `start`: null and `end`: null> ] " - 'Actual: [RangeError:RangeError: ' - 'Invalid value: Not in inclusive range 1..10: -1] ' - 'Which: at location [0] is RangeError: ' - "which has `message` with value 'Invalid value' " - "which does not contain 'details'"), - equalsIgnoringWhitespace(// Older SDKs - "Expected: [ < with " - "`message`: contains 'details' and `start`: null and `end`: null> ] " - 'Actual: [RangeError:RangeError: ' - 'Invalid value: Not in range 1..10, inclusive: -1] ' - 'Which: at location [0] is RangeError: ' - "which has `message` with value 'Invalid value' " - "which does not contain 'details'") - ])); + [RangeError.range(-1, 1, 10)], + equals([_rangeMatcher]), + anyOf([ + equalsIgnoringWhitespace( + "Expected: [ < with " + "`message`: contains 'details' and `start`: null and `end`: null> ] " + 'Actual: [RangeError:RangeError: ' + 'Invalid value: Not in inclusive range 1..10: -1] ' + 'Which: at location [0] is RangeError: ' + "which has `message` with value 'Invalid value' " + "which does not contain 'details'", + ), + equalsIgnoringWhitespace( + // Older SDKs + "Expected: [ < with " + "`message`: contains 'details' and `start`: null and `end`: null> ] " + 'Actual: [RangeError:RangeError: ' + 'Invalid value: Not in range 1..10, inclusive: -1] ' + 'Which: at location [0] is RangeError: ' + "which has `message` with value 'Invalid value' " + "which does not contain 'details'", + ), + ]), + ); }); group('CustomMatcher copy', () { @@ -78,32 +88,37 @@ void main() { shouldPass(w, _hasPrice(10)); shouldPass(w, _hasPrice(greaterThan(0))); shouldFail( - w, - _hasPrice(greaterThan(10)), - "Expected: with `price`: a value greater than <10> " - "Actual: " - 'Which: has `price` with value <10> which is not ' - 'a value greater than <10>'); + w, + _hasPrice(greaterThan(10)), + "Expected: with `price`: a value greater than <10> " + "Actual: " + 'Which: has `price` with value <10> which is not ' + 'a value greater than <10>', + ); }); test('Custom Matcher Exception', () { shouldFail( - 'a', - _badCustomMatcher(), - allOf([ - contains( - "Expected: with `feature`: {1: 'a'} "), - contains("Actual: 'a'"), - ])); + 'a', + _badCustomMatcher(), + allOf([ + contains( + "Expected: with `feature`: {1: 'a'} ", + ), + contains("Actual: 'a'"), + ]), + ); shouldFail( - Widget(), - _badCustomMatcher(), - allOf([ - contains( - "Expected: with `feature`: {1: 'a'} "), - contains("Actual: "), - contains("Which: threw 'Exception: bang' "), - ])); + Widget(), + _badCustomMatcher(), + allOf([ + contains( + "Expected: with `feature`: {1: 'a'} ", + ), + contains("Actual: "), + contains("Which: threw 'Exception: bang' "), + ]), + ); }); }); } @@ -116,13 +131,18 @@ final _rangeMatcher = isRangeError Matcher _hasPrice(Object matcher) => const TypeMatcher().having((e) => e.price, 'price', matcher); -Matcher _badCustomMatcher() => const TypeMatcher() - .having((e) => throw Exception('bang'), 'feature', {1: 'a'}); +Matcher _badCustomMatcher() => const TypeMatcher().having( + (e) => throw Exception('bang'), + 'feature', + {1: 'a'}, +); class CustomRangeError extends RangeError { CustomRangeError.range( - super.invalidValue, int super.minValue, int super.maxValue) - : super.range(); + super.invalidValue, + int super.minValue, + int super.maxValue, + ) : super.range(); @override String toString() => 'RangeError: Invalid value: details'; diff --git a/pkgs/matcher/test/iterable_matchers_test.dart b/pkgs/matcher/test/iterable_matchers_test.dart index 6a4f3b6df..d66e9f9c4 100644 --- a/pkgs/matcher/test/iterable_matchers_test.dart +++ b/pkgs/matcher/test/iterable_matchers_test.dart @@ -21,29 +21,32 @@ void main() { var d = [1, 2]; shouldPass(d, contains(1)); shouldFail( - d, - contains(0), - 'Expected: contains <0> ' - 'Actual: [1, 2] ' - 'Which: does not contain <0>'); - - shouldFail( - 'String', - contains(42), - "Expected: contains <42> Actual: 'String' " - 'Which: does not contain <42>'); + d, + contains(0), + 'Expected: contains <0> ' + 'Actual: [1, 2] ' + 'Which: does not contain <0>', + ); + + shouldFail( + 'String', + contains(42), + "Expected: contains <42> Actual: 'String' " + 'Which: does not contain <42>', + ); }); test('equals with matcher element', () { var d = ['foo', 'bar']; shouldPass(d, equals(['foo', startsWith('ba')])); shouldFail( - d, - equals(['foo', endsWith('ba')]), - "Expected: ['foo', ] " - "Actual: ['foo', 'bar'] " - "Which: at location [1] is 'bar' which " - "does not match a string ending with 'ba'"); + d, + equals(['foo', endsWith('ba')]), + "Expected: ['foo', ] " + "Actual: ['foo', 'bar'] " + "Which: at location [1] is 'bar' which " + "does not match a string ending with 'ba'", + ); }); test('isIn', () { @@ -59,7 +62,10 @@ void main() { shouldPass('42', isIn('1421')); shouldFail('42', isIn('41'), "Expected: is in '41' Actual: '42'"); shouldFail( - 0, isIn('a string'), endsWith('not an ')); + 0, + isIn('a string'), + endsWith('not an '), + ); // Invalid arg expect(() => isIn(42), throwsArgumentError); @@ -69,59 +75,67 @@ void main() { var d = [1, 2]; var e = [1, 1, 1]; shouldFail( - d, - everyElement(1), - 'Expected: every element(<1>) ' - 'Actual: [1, 2] ' - "Which: has value <2> which doesn't match <1> at index 1"); + d, + everyElement(1), + 'Expected: every element(<1>) ' + 'Actual: [1, 2] ' + "Which: has value <2> which doesn't match <1> at index 1", + ); shouldPass(e, everyElement(1)); - shouldFail('not iterable', everyElement(1), - endsWith('not an ')); + shouldFail( + 'not iterable', + everyElement(1), + endsWith('not an '), + ); }); test('nested everyElement', () { var d = [ ['foo', 'bar'], ['foo'], - [] + [], ]; var e = [ ['foo', 'bar'], ['foo'], 3, - [] + [], ]; shouldPass(d, everyElement(anyOf(isEmpty, contains('foo')))); shouldFail( - d, - everyElement(everyElement(equals('foo'))), - "Expected: every element(every element('foo')) " - "Actual: [['foo', 'bar'], ['foo'], []] " - "Which: has value ['foo', 'bar'] which has value 'bar' " - 'which is different. Expected: foo Actual: bar ^ ' - 'Differ at offset 0 at index 1 at index 0'); - shouldFail( - d, - everyElement(allOf(hasLength(greaterThan(0)), contains('foo'))), - 'Expected: every element((an object with length of a value ' - "greater than <0> and contains 'foo')) " - "Actual: [['foo', 'bar'], ['foo'], []] " - 'Which: has value [] which has length of <0> at index 2'); - shouldFail( - d, - everyElement(allOf(contains('foo'), hasLength(greaterThan(0)))), - "Expected: every element((contains 'foo' and " - 'an object with length of a value greater than <0>)) ' - "Actual: [['foo', 'bar'], ['foo'], []] " - "Which: has value [] which does not contain 'foo' at index 2"); - shouldFail( - e, - everyElement(allOf(contains('foo'), hasLength(greaterThan(0)))), - "Expected: every element((contains 'foo' and an object with " - 'length of a value greater than <0>)) ' - "Actual: [['foo', 'bar'], ['foo'], 3, []] " - 'Which: has value <3> which is not a string, map or iterable ' - 'at index 2'); + d, + everyElement(everyElement(equals('foo'))), + "Expected: every element(every element('foo')) " + "Actual: [['foo', 'bar'], ['foo'], []] " + "Which: has value ['foo', 'bar'] which has value 'bar' " + 'which is different. Expected: foo Actual: bar ^ ' + 'Differ at offset 0 at index 1 at index 0', + ); + shouldFail( + d, + everyElement(allOf(hasLength(greaterThan(0)), contains('foo'))), + 'Expected: every element((an object with length of a value ' + "greater than <0> and contains 'foo')) " + "Actual: [['foo', 'bar'], ['foo'], []] " + 'Which: has value [] which has length of <0> at index 2', + ); + shouldFail( + d, + everyElement(allOf(contains('foo'), hasLength(greaterThan(0)))), + "Expected: every element((contains 'foo' and " + 'an object with length of a value greater than <0>)) ' + "Actual: [['foo', 'bar'], ['foo'], []] " + "Which: has value [] which does not contain 'foo' at index 2", + ); + shouldFail( + e, + everyElement(allOf(contains('foo'), hasLength(greaterThan(0)))), + "Expected: every element((contains 'foo' and an object with " + 'length of a value greater than <0>)) ' + "Actual: [['foo', 'bar'], ['foo'], 3, []] " + 'Which: has value <3> which is not a string, map or iterable ' + 'at index 2', + ); }); test('anyElement', () { @@ -129,9 +143,15 @@ void main() { var e = [1, 1, 1]; shouldPass(d, anyElement(2)); shouldFail( - e, anyElement(2), 'Expected: some element <2> Actual: [1, 1, 1]'); - shouldFail('not an iterable', anyElement(2), - endsWith('not an ')); + e, + anyElement(2), + 'Expected: some element <2> Actual: [1, 1, 1]', + ); + shouldFail( + 'not an iterable', + anyElement(2), + endsWith('not an '), + ); }); test('orderedEquals', () { @@ -139,45 +159,56 @@ void main() { var d = [1, 2]; shouldPass(d, orderedEquals([1, 2])); shouldFail( - d, - orderedEquals([2, 1]), - 'Expected: equals [2, 1] ordered ' - 'Actual: [1, 2] ' - 'Which: at location [0] is <1> instead of <2>'); - shouldFail('not an iterable', orderedEquals([1]), - endsWith('not an ')); + d, + orderedEquals([2, 1]), + 'Expected: equals [2, 1] ordered ' + 'Actual: [1, 2] ' + 'Which: at location [0] is <1> instead of <2>', + ); + shouldFail( + 'not an iterable', + orderedEquals([1]), + endsWith('not an '), + ); }); test('unorderedEquals', () { var d = [1, 2]; shouldPass(d, unorderedEquals([2, 1])); shouldFail( - d, - unorderedEquals([1]), - 'Expected: equals [1] unordered ' - 'Actual: [1, 2] ' - 'Which: has too many elements (2 > 1)'); - shouldFail( - d, - unorderedEquals([3, 2, 1]), - 'Expected: equals [3, 2, 1] unordered ' - 'Actual: [1, 2] ' - 'Which: has too few elements (2 < 3)'); - shouldFail( - d, - unorderedEquals([3, 1]), - 'Expected: equals [3, 1] unordered ' - 'Actual: [1, 2] ' - 'Which: has no match for <3> at index 0'); - shouldFail( - d, - unorderedEquals([3, 4]), - 'Expected: equals [3, 4] unordered ' - 'Actual: [1, 2] ' - 'Which: has no match for <3> at index 0' - ' along with 1 other unmatched'); - shouldFail('not an iterable', unorderedEquals([1]), - endsWith('not an ')); + d, + unorderedEquals([1]), + 'Expected: equals [1] unordered ' + 'Actual: [1, 2] ' + 'Which: has too many elements (2 > 1)', + ); + shouldFail( + d, + unorderedEquals([3, 2, 1]), + 'Expected: equals [3, 2, 1] unordered ' + 'Actual: [1, 2] ' + 'Which: has too few elements (2 < 3)', + ); + shouldFail( + d, + unorderedEquals([3, 1]), + 'Expected: equals [3, 1] unordered ' + 'Actual: [1, 2] ' + 'Which: has no match for <3> at index 0', + ); + shouldFail( + d, + unorderedEquals([3, 4]), + 'Expected: equals [3, 4] unordered ' + 'Actual: [1, 2] ' + 'Which: has no match for <3> at index 0' + ' along with 1 other unmatched', + ); + shouldFail( + 'not an iterable', + unorderedEquals([1]), + endsWith('not an '), + ); }); test('unorderedMatches', () { @@ -190,42 +221,50 @@ void main() { shouldPass([2, 1], unorderedMatches([greaterThan(0), greaterThan(1)])); // Excersize the case where pairings should get "bumped" multiple times shouldPass( - [0, 1, 2, 3, 5, 6], - unorderedMatches([ - greaterThan(1), // 6 - equals(2), // 2 - allOf([lessThan(3), isNot(0)]), // 1 - equals(0), // 0 - predicate((int v) => v.isOdd), // 3 - equals(5), // 5 - ])); - shouldFail( - d, - unorderedMatches([greaterThan(0)]), - 'Expected: matches [a value greater than <0>] unordered ' - 'Actual: [1, 2] ' - 'Which: has too many elements (2 > 1)'); - shouldFail( - d, - unorderedMatches([3, 2, 1]), - 'Expected: matches [<3>, <2>, <1>] unordered ' - 'Actual: [1, 2] ' - 'Which: has too few elements (2 < 3)'); - shouldFail( - d, - unorderedMatches([3, 1]), - 'Expected: matches [<3>, <1>] unordered ' - 'Actual: [1, 2] ' - 'Which: has no match for <3> at index 0'); - shouldFail( - d, - unorderedMatches([greaterThan(3), greaterThan(0)]), - 'Expected: matches [a value greater than <3>, a value greater than ' - '<0>] unordered ' - 'Actual: [1, 2] ' - 'Which: has no match for a value greater than <3> at index 0'); - shouldFail('not an iterable', unorderedMatches([greaterThan(1)]), - endsWith('not an ')); + [0, 1, 2, 3, 5, 6], + unorderedMatches([ + greaterThan(1), // 6 + equals(2), // 2 + allOf([lessThan(3), isNot(0)]), // 1 + equals(0), // 0 + predicate((int v) => v.isOdd), // 3 + equals(5), // 5 + ]), + ); + shouldFail( + d, + unorderedMatches([greaterThan(0)]), + 'Expected: matches [a value greater than <0>] unordered ' + 'Actual: [1, 2] ' + 'Which: has too many elements (2 > 1)', + ); + shouldFail( + d, + unorderedMatches([3, 2, 1]), + 'Expected: matches [<3>, <2>, <1>] unordered ' + 'Actual: [1, 2] ' + 'Which: has too few elements (2 < 3)', + ); + shouldFail( + d, + unorderedMatches([3, 1]), + 'Expected: matches [<3>, <1>] unordered ' + 'Actual: [1, 2] ' + 'Which: has no match for <3> at index 0', + ); + shouldFail( + d, + unorderedMatches([greaterThan(3), greaterThan(0)]), + 'Expected: matches [a value greater than <3>, a value greater than ' + '<0>] unordered ' + 'Actual: [1, 2] ' + 'Which: has no match for a value greater than <3> at index 0', + ); + shouldFail( + 'not an iterable', + unorderedMatches([greaterThan(1)]), + endsWith('not an '), + ); }); test('containsAll', () { @@ -235,26 +274,32 @@ void main() { shouldPass(d, containsAll([greaterThan(0), greaterThan(1)])); shouldPass([2, 1], containsAll([greaterThan(0), greaterThan(1)])); shouldFail( - d, - containsAll([1, 2, 3]), - 'Expected: contains all of [1, 2, 3] ' - 'Actual: [0, 1, 2] ' - 'Which: has no match for <3> at index 2'); - shouldFail( - 1, - containsAll([1]), - 'Expected: contains all of [1] ' - 'Actual: <1> ' - "Which: not an "); - shouldFail( - [-1, 2], - containsAll([greaterThan(0), greaterThan(1)]), - 'Expected: contains all of [>, ' - '>] ' - 'Actual: [-1, 2] ' - 'Which: has no match for a value greater than <1> at index 1'); - shouldFail('not an iterable', containsAll([1, 2, 3]), - endsWith('not an ')); + d, + containsAll([1, 2, 3]), + 'Expected: contains all of [1, 2, 3] ' + 'Actual: [0, 1, 2] ' + 'Which: has no match for <3> at index 2', + ); + shouldFail( + 1, + containsAll([1]), + 'Expected: contains all of [1] ' + 'Actual: <1> ' + "Which: not an ", + ); + shouldFail( + [-1, 2], + containsAll([greaterThan(0), greaterThan(1)]), + 'Expected: contains all of [>, ' + '>] ' + 'Actual: [-1, 2] ' + 'Which: has no match for a value greater than <1> at index 1', + ); + shouldFail( + 'not an iterable', + containsAll([1, 2, 3]), + endsWith('not an '), + ); }); test('containsAllInOrder', () { @@ -262,64 +307,72 @@ void main() { shouldPass(d, containsAllInOrder([1, 2])); shouldPass(d, containsAllInOrder([greaterThan(0), greaterThan(1)])); shouldFail( - d, - containsAllInOrder([2, 1]), - 'Expected: contains in order([2, 1]) ' - 'Actual: [0, 1, 0, 2] ' - 'Which: did not find a value matching <1> following expected prior ' - 'values'); - shouldFail( - d, - containsAllInOrder([greaterThan(1), greaterThan(0)]), - 'Expected: contains in order([>, ' - '>]) ' - 'Actual: [0, 1, 0, 2] ' - 'Which: did not find a value matching a value greater than <0> ' - 'following expected prior values'); - shouldFail( - d, - containsAllInOrder([1, 2, 3]), - 'Expected: contains in order([1, 2, 3]) ' - 'Actual: [0, 1, 0, 2] ' - 'Which: did not find a value matching <3> following expected prior ' - 'values'); - shouldFail( - 1, - containsAllInOrder([1]), - 'Expected: contains in order([1]) ' - 'Actual: <1> ' - "Which: not an "); + d, + containsAllInOrder([2, 1]), + 'Expected: contains in order([2, 1]) ' + 'Actual: [0, 1, 0, 2] ' + 'Which: did not find a value matching <1> following expected prior ' + 'values', + ); + shouldFail( + d, + containsAllInOrder([greaterThan(1), greaterThan(0)]), + 'Expected: contains in order([>, ' + '>]) ' + 'Actual: [0, 1, 0, 2] ' + 'Which: did not find a value matching a value greater than <0> ' + 'following expected prior values', + ); + shouldFail( + d, + containsAllInOrder([1, 2, 3]), + 'Expected: contains in order([1, 2, 3]) ' + 'Actual: [0, 1, 0, 2] ' + 'Which: did not find a value matching <3> following expected prior ' + 'values', + ); + shouldFail( + 1, + containsAllInOrder([1]), + 'Expected: contains in order([1]) ' + 'Actual: <1> ' + "Which: not an ", + ); }); test('containsOnce', () { shouldPass([1, 2, 3, 4], containsOnce(2)); shouldPass([1, 2, 11, 3], containsOnce(greaterThan(10))); shouldFail( - [1, 2, 3, 4], - containsOnce(10), - 'Expected: contains once(<10>) ' - 'Actual: [1, 2, 3, 4] ' - 'Which: did not find a value matching <10>'); - shouldFail( - [1, 2, 3, 4], - containsOnce(greaterThan(10)), - 'Expected: contains once(a value greater than <10>) ' - 'Actual: [1, 2, 3, 4] ' - 'Which: did not find a value matching a value greater than <10>'); - shouldFail( - [1, 2, 1, 2], - containsOnce(2), - 'Expected: contains once(<2>) ' - 'Actual: [1, 2, 1, 2] ' - 'Which: expected only one value matching <2> ' - 'but found multiple: <2>, <2>'); - shouldFail( - [1, 2, 10, 20], - containsOnce(greaterThan(5)), - 'Expected: contains once(a value greater than <5>) ' - 'Actual: [1, 2, 10, 20] ' - 'Which: expected only one value matching a value greater than <5> ' - 'but found multiple: <10>, <20>'); + [1, 2, 3, 4], + containsOnce(10), + 'Expected: contains once(<10>) ' + 'Actual: [1, 2, 3, 4] ' + 'Which: did not find a value matching <10>', + ); + shouldFail( + [1, 2, 3, 4], + containsOnce(greaterThan(10)), + 'Expected: contains once(a value greater than <10>) ' + 'Actual: [1, 2, 3, 4] ' + 'Which: did not find a value matching a value greater than <10>', + ); + shouldFail( + [1, 2, 1, 2], + containsOnce(2), + 'Expected: contains once(<2>) ' + 'Actual: [1, 2, 1, 2] ' + 'Which: expected only one value matching <2> ' + 'but found multiple: <2>, <2>', + ); + shouldFail( + [1, 2, 10, 20], + containsOnce(greaterThan(5)), + 'Expected: contains once(a value greater than <5>) ' + 'Actual: [1, 2, 10, 20] ' + 'Which: expected only one value matching a value greater than <5> ' + 'but found multiple: <10>, <20>', + ); }); test('pairwise compare', () { @@ -327,37 +380,46 @@ void main() { var d = [1, 2, 3]; var e = [1, 4, 9]; shouldFail( - 'x', - pairwiseCompare(e, (int e, int a) => a <= e, 'less than or equal'), - 'Expected: pairwise less than or equal [1, 4, 9] ' - "Actual: 'x' " - "Which: not an "); - shouldFail( - c, - pairwiseCompare(e, (int e, int a) => a <= e, 'less than or equal'), - 'Expected: pairwise less than or equal [1, 4, 9] ' - 'Actual: [1, 2] ' - 'Which: has length 2 instead of 3'); + 'x', + pairwiseCompare(e, (int e, int a) => a <= e, 'less than or equal'), + 'Expected: pairwise less than or equal [1, 4, 9] ' + "Actual: 'x' " + "Which: not an ", + ); + shouldFail( + c, + pairwiseCompare(e, (int e, int a) => a <= e, 'less than or equal'), + 'Expected: pairwise less than or equal [1, 4, 9] ' + 'Actual: [1, 2] ' + 'Which: has length 2 instead of 3', + ); shouldPass( - d, pairwiseCompare(e, (int e, int a) => a <= e, 'less than or equal')); - shouldFail( - d, - pairwiseCompare(e, (int e, int a) => a < e, 'less than'), - 'Expected: pairwise less than [1, 4, 9] ' - 'Actual: [1, 2, 3] ' - 'Which: has <1> which is not less than <1> at index 0'); + d, + pairwiseCompare(e, (int e, int a) => a <= e, 'less than or equal'), + ); + shouldFail( + d, + pairwiseCompare(e, (int e, int a) => a < e, 'less than'), + 'Expected: pairwise less than [1, 4, 9] ' + 'Actual: [1, 2, 3] ' + 'Which: has <1> which is not less than <1> at index 0', + ); shouldPass( - d, pairwiseCompare(e, (int e, int a) => a * a == e, 'square root of')); - shouldFail( - d, - pairwiseCompare(e, (int e, int a) => a + a == e, 'double'), - 'Expected: pairwise double [1, 4, 9] ' - 'Actual: [1, 2, 3] ' - 'Which: has <1> which is not double <1> at index 0'); - shouldFail( - 'not an iterable', - pairwiseCompare(e, (int e, int a) => a + a == e, 'double'), - endsWith('not an ')); + d, + pairwiseCompare(e, (int e, int a) => a * a == e, 'square root of'), + ); + shouldFail( + d, + pairwiseCompare(e, (int e, int a) => a + a == e, 'double'), + 'Expected: pairwise double [1, 4, 9] ' + 'Actual: [1, 2, 3] ' + 'Which: has <1> which is not double <1> at index 0', + ); + shouldFail( + 'not an iterable', + pairwiseCompare(e, (int e, int a) => a + a == e, 'double'), + endsWith('not an '), + ); }); test('isEmpty', () { @@ -365,10 +427,11 @@ void main() { var e = SimpleIterable(1); shouldPass(d, isEmpty); shouldFail( - e, - isEmpty, - 'Expected: empty ' - 'Actual: SimpleIterable:[1]'); + e, + isEmpty, + 'Expected: empty ' + 'Actual: SimpleIterable:[1]', + ); }); test('isNotEmpty', () { @@ -376,21 +439,23 @@ void main() { var e = SimpleIterable(1); shouldPass(e, isNotEmpty); shouldFail( - d, - isNotEmpty, - 'Expected: non-empty ' - 'Actual: SimpleIterable:[]'); + d, + isNotEmpty, + 'Expected: non-empty ' + 'Actual: SimpleIterable:[]', + ); }); test('contains', () { var d = SimpleIterable(3); shouldPass(d, contains(2)); shouldFail( - d, - contains(5), - 'Expected: contains <5> ' - 'Actual: SimpleIterable:[3, 2, 1] ' - 'Which: does not contain <5>'); + d, + contains(5), + 'Expected: contains <5> ' + 'Actual: SimpleIterable:[3, 2, 1] ' + 'Which: does not contain <5>', + ); }); test('isSorted', () { @@ -404,31 +469,35 @@ void main() { shouldPass(sorted, isSorted()); shouldFail( - mismatchAtStart, - isSorted(), - 'Expected: is sorted ' - 'Actual: [8, 4, 15, 16, 23, 42] ' - 'Which: found elements out of order at <0>: <8> and <4>'); - shouldFail( - mismatchInMiddle, - isSorted(), - 'Expected: is sorted ' - 'Actual: [4, 8, 16, 15, 23, 42] ' - 'Which: found elements out of order at <2>: <16> and <15>'); - shouldFail( - mismatchAtEnd, - isSorted(), - 'Expected: is sorted ' - 'Actual: [4, 8, 15, 16, 42, 23] ' - 'Which: found elements out of order at <4>: <42> and <23>'); + mismatchAtStart, + isSorted(), + 'Expected: is sorted ' + 'Actual: [8, 4, 15, 16, 23, 42] ' + 'Which: found elements out of order at <0>: <8> and <4>', + ); + shouldFail( + mismatchInMiddle, + isSorted(), + 'Expected: is sorted ' + 'Actual: [4, 8, 16, 15, 23, 42] ' + 'Which: found elements out of order at <2>: <16> and <15>', + ); + shouldFail( + mismatchAtEnd, + isSorted(), + 'Expected: is sorted ' + 'Actual: [4, 8, 15, 16, 42, 23] ' + 'Which: found elements out of order at <4>: <42> and <23>', + ); shouldPass(singleElement, isSorted()); shouldPass(twoElementsSorted, isSorted()); shouldFail( - twoElementsUnsorted, - isSorted(), - 'Expected: is sorted ' - 'Actual: [143, 42] ' - 'Which: found elements out of order at <0>: <143> and <42>'); + twoElementsUnsorted, + isSorted(), + 'Expected: is sorted ' + 'Actual: [143, 42] ' + 'Which: found elements out of order at <0>: <143> and <42>', + ); }); test('isSortedUsing', () { @@ -441,22 +510,24 @@ void main() { shouldPass(sorted, isSortedUsing((int x, int y) => x - y)); shouldFail( - unsorted, - isSortedUsing((int x, int y) => x - y), - 'Expected: is sorted ' - 'Actual: [1, 3, 2] ' - 'Which: found elements out of order at <1>: <3> and <2>'); + unsorted, + isSortedUsing((int x, int y) => x - y), + 'Expected: is sorted ' + 'Actual: [1, 3, 2] ' + 'Which: found elements out of order at <1>: <3> and <2>', + ); shouldPass(reverseSorted, isSortedUsing((int x, int y) => y - x)); shouldPass(unsorted, isSortedUsing(alwaysEqualCompare)); shouldFail( - sorted, - isSortedUsing(throwingCompare), - 'Expected: is sorted ' - 'Actual: [1, 2, 3] ' - 'Which: got error at <0> ' - 'when comparing <1> and <2>'); + sorted, + isSortedUsing(throwingCompare), + 'Expected: is sorted ' + 'Actual: [1, 2, 3] ' + 'Which: got error at <0> ' + 'when comparing <1> and <2>', + ); }); test('isSortedBy', () { @@ -468,34 +539,41 @@ void main() { shouldPass(sorted, isSortedBy((String s) => s.length)); shouldFail( - unsorted, - isSortedBy((String s) => s.length), - 'Expected: is sorted ' - 'Actual: [\'y\', \'bbbb\', \'aaaa\', \'zz\'] ' - 'Which: found elements out of order at <2>: \'aaaa\' and \'zz\''); + unsorted, + isSortedBy((String s) => s.length), + 'Expected: is sorted ' + 'Actual: [\'y\', \'bbbb\', \'aaaa\', \'zz\'] ' + 'Which: found elements out of order at <2>: \'aaaa\' and \'zz\'', + ); shouldPass( - sortedDueToSameKey, isSortedBy((String s) => s.length)); - - shouldFail( - sorted, - isSortedBy(throwingKey), - 'Expected: is sorted ' - 'Actual: [\'y\', \'zz\', \'bbbb\', \'aaaa\'] ' - 'Which: got error at <0> ' - 'when getting key of \'y\''); + sortedDueToSameKey, + isSortedBy((String s) => s.length), + ); + + shouldFail( + sorted, + isSortedBy(throwingKey), + 'Expected: is sorted ' + 'Actual: [\'y\', \'zz\', \'bbbb\', \'aaaa\'] ' + 'Which: got error at <0> ' + 'when getting key of \'y\'', + ); }); test('isSortedByCompare', () { final sorted = ['aaaa', 'bbbb', 'zz', 'y']; final unsorted = ['y', 'bbbb', 'aaaa', 'zz']; - shouldPass(sorted, - isSortedByCompare((String s) => s.length, (a, b) => b.compareTo(a))); - shouldFail( - unsorted, - isSortedByCompare((String s) => s.length, (a, b) => b.compareTo(a)), - 'Expected: is sorted ' - 'Actual: [\'y\', \'bbbb\', \'aaaa\', \'zz\'] ' - 'Which: found elements out of order at <0>: \'y\' and \'bbbb\''); + shouldPass( + sorted, + isSortedByCompare((String s) => s.length, (a, b) => b.compareTo(a)), + ); + shouldFail( + unsorted, + isSortedByCompare((String s) => s.length, (a, b) => b.compareTo(a)), + 'Expected: is sorted ' + 'Actual: [\'y\', \'bbbb\', \'aaaa\', \'zz\'] ' + 'Which: found elements out of order at <0>: \'y\' and \'bbbb\'', + ); }); } diff --git a/pkgs/matcher/test/matcher/completion_test.dart b/pkgs/matcher/test/matcher/completion_test.dart index ef8288e32..de82eeb0a 100644 --- a/pkgs/matcher/test/matcher/completion_test.dart +++ b/pkgs/matcher/test/matcher/completion_test.dart @@ -32,9 +32,10 @@ void main() { }); expectTestFailed( - monitor, - 'Future was not expected to complete but completed with a value of' - ' null'); + monitor, + 'Future was not expected to complete but completed with a value of' + ' null', + ); }); test('fails when a future completes after the expect', () async { @@ -45,9 +46,10 @@ void main() { }); expectTestFailed( - monitor, - 'Future was not expected to complete but completed with a value of' - ' null'); + monitor, + 'Future was not expected to complete but completed with a value of' + ' null', + ); }); test('fails when a future eventually completes', () async { @@ -60,9 +62,10 @@ void main() { }); expectTestFailed( - monitor, - 'Future was not expected to complete but completed with a value of' - ' null'); + monitor, + 'Future was not expected to complete but completed with a value of' + ' null', + ); }); }); group('[completes]', () { @@ -101,10 +104,11 @@ void main() { }); expectTestFailed( - monitor, - 'Expected: completes successfully\n' - ' Actual: <10>\n' - ' Which: was not a Future\n'); + monitor, + 'Expected: completes successfully\n' + ' Actual: <10>\n' + ' Which: was not a Future\n', + ); }); test('with a successful future', () { @@ -148,10 +152,11 @@ void main() { }); expectTestFailed( - monitor, - 'Expected: completes to a value that <10>\n' - ' Actual: <10>\n' - ' Which: was not a Future\n'); + monitor, + 'Expected: completes to a value that <10>\n' + ' Actual: <10>\n' + ' Which: was not a Future\n', + ); }); test('with an incorrect value', () async { @@ -160,26 +165,33 @@ void main() { }); expectTestFailed( - monitor, - allOf([ - startsWith("Expected: completes to a value that 'b'\n" - ' Actual: <'), - endsWith('>\n' - " Which: emitted 'a'\n" - ' which is different.\n' - ' Expected: b\n' - ' Actual: a\n' - ' ^\n' - ' Differ at offset 0\n') - ])); + monitor, + allOf([ + startsWith( + "Expected: completes to a value that 'b'\n" + ' Actual: <', + ), + endsWith( + '>\n' + " Which: emitted 'a'\n" + ' which is different.\n' + ' Expected: b\n' + ' Actual: a\n' + ' ^\n' + ' Differ at offset 0\n', + ), + ]), + ); }); test("blocks expectLater's Future", () async { var completer = Completer(); var fired = false; - unawaited(expectLater(completer.future, completion(equals(1))).then((_) { - fired = true; - })); + unawaited( + expectLater(completer.future, completion(equals(1))).then((_) { + fired = true; + }), + ); await pumpEventQueue(); expect(fired, isFalse); diff --git a/pkgs/matcher/test/matcher/prints_test.dart b/pkgs/matcher/test/matcher/prints_test.dart index a681413c0..6e63e6689 100644 --- a/pkgs/matcher/test/matcher/prints_test.dart +++ b/pkgs/matcher/test/matcher/prints_test.dart @@ -33,20 +33,25 @@ void main() { }); expectTestFailed( - monitor, - allOf([ - startsWith("Expected: prints 'Goodbye, world!\\n'\n" - " ''\n" - ' Actual: <'), - endsWith('>\n' - " Which: printed 'Hello, world!\\n'\n" - " ''\n" - ' which is different.\n' - ' Expected: Goodbye, w ...\n' - ' Actual: Hello, wor ...\n' - ' ^\n' - ' Differ at offset 0\n') - ])); + monitor, + allOf([ + startsWith( + "Expected: prints 'Goodbye, world!\\n'\n" + " ''\n" + ' Actual: <', + ), + endsWith( + '>\n' + " Which: printed 'Hello, world!\\n'\n" + " ''\n" + ' which is different.\n' + ' Expected: Goodbye, w ...\n' + ' Actual: Hello, wor ...\n' + ' ^\n' + ' Differ at offset 0\n', + ), + ]), + ); }); test('describes a failure with a non-descriptive Matcher nicely', () async { @@ -56,15 +61,20 @@ void main() { }); expectTestFailed( - monitor, - allOf([ - startsWith("Expected: prints contains 'Goodbye'\n" - ' Actual: <'), - endsWith('>\n' - " Which: printed 'Hello, world!\\n'\n" - " ''\n" - ' which does not contain \'Goodbye\'\n') - ])); + monitor, + allOf([ + startsWith( + "Expected: prints contains 'Goodbye'\n" + ' Actual: <', + ), + endsWith( + '>\n' + " Which: printed 'Hello, world!\\n'\n" + " ''\n" + ' which does not contain \'Goodbye\'\n', + ), + ]), + ); }); test('describes a failure with no text nicely', () async { @@ -74,14 +84,19 @@ void main() { }); expectTestFailed( - monitor, - allOf([ - startsWith("Expected: prints contains 'Goodbye'\n" - ' Actual: <'), - endsWith('>\n' - ' Which: printed nothing\n' - ' which does not contain \'Goodbye\'\n') - ])); + monitor, + allOf([ + startsWith( + "Expected: prints contains 'Goodbye'\n" + ' Actual: <', + ), + endsWith( + '>\n' + ' Which: printed nothing\n' + ' which does not contain \'Goodbye\'\n', + ), + ]), + ); }); test('with a non-function', () async { @@ -90,31 +105,37 @@ void main() { }); expectTestFailed( - monitor, - "Expected: prints contains 'Goodbye'\n" - ' Actual: <10>\n' - ' Which: was not a unary Function\n'); + monitor, + "Expected: prints contains 'Goodbye'\n" + ' Actual: <10>\n' + ' Which: was not a unary Function\n', + ); }); }); group('asynchronous', () { test('passes with an expected print', () { - expect(() => Future(() => print('Hello, world!')), - prints('Hello, world!\n')); + expect( + () => Future(() => print('Hello, world!')), + prints('Hello, world!\n'), + ); }); test('combines multiple prints', () { expect( - () => Future(() { - print('Hello'); - print('World!'); - }), - prints('Hello\nWorld!\n')); + () => Future(() { + print('Hello'); + print('World!'); + }), + prints('Hello\nWorld!\n'), + ); }); test('works with a Matcher', () { - expect(() => Future(() => print('Hello, world!')), - prints(contains('Hello'))); + expect( + () => Future(() => print('Hello, world!')), + prints(contains('Hello')), + ); }); test('describes a failure nicely', () async { @@ -124,20 +145,25 @@ void main() { }); expectTestFailed( - monitor, - allOf([ - startsWith("Expected: prints 'Goodbye, world!\\n'\n" - " ''\n" - ' Actual: <'), - contains('>\n' - " Which: printed 'Hello, world!\\n'\n" - " ''\n" - ' which is different.\n' - ' Expected: Goodbye, w ...\n' - ' Actual: Hello, wor ...\n' - ' ^\n' - ' Differ at offset 0') - ])); + monitor, + allOf([ + startsWith( + "Expected: prints 'Goodbye, world!\\n'\n" + " ''\n" + ' Actual: <', + ), + contains( + '>\n' + " Which: printed 'Hello, world!\\n'\n" + " ''\n" + ' which is different.\n' + ' Expected: Goodbye, w ...\n' + ' Actual: Hello, wor ...\n' + ' ^\n' + ' Differ at offset 0', + ), + ]), + ); }); test('describes a failure with a non-descriptive Matcher nicely', () async { @@ -147,14 +173,19 @@ void main() { }); expectTestFailed( - monitor, - allOf([ - startsWith("Expected: prints contains 'Goodbye'\n" - ' Actual: <'), - contains('>\n' - " Which: printed 'Hello, world!\\n'\n" - " ''") - ])); + monitor, + allOf([ + startsWith( + "Expected: prints contains 'Goodbye'\n" + ' Actual: <', + ), + contains( + '>\n' + " Which: printed 'Hello, world!\\n'\n" + " ''", + ), + ]), + ); }); test('describes a failure with no text nicely', () async { @@ -164,13 +195,18 @@ void main() { }); expectTestFailed( - monitor, - allOf([ - startsWith("Expected: prints contains 'Goodbye'\n" - ' Actual: <'), - contains('>\n' - ' Which: printed nothing') - ])); + monitor, + allOf([ + startsWith( + "Expected: prints contains 'Goodbye'\n" + ' Actual: <', + ), + contains( + '>\n' + ' Which: printed nothing', + ), + ]), + ); }); test("won't let the test end until the Future completes", () async { @@ -189,13 +225,14 @@ void main() { var completer = Completer(); var fired = false; - unawaited(expectLater(() { - scheduleMicrotask(() => print('hello!')); - return completer.future; - }, prints('hello!\n')) - .then((_) { - fired = true; - })); + unawaited( + expectLater(() { + scheduleMicrotask(() => print('hello!')); + return completer.future; + }, prints('hello!\n')).then((_) { + fired = true; + }), + ); await pumpEventQueue(); expect(fired, isFalse); diff --git a/pkgs/matcher/test/matcher/throws_test.dart b/pkgs/matcher/test/matcher/throws_test.dart index ff401b0d3..176807497 100644 --- a/pkgs/matcher/test/matcher/throws_test.dart +++ b/pkgs/matcher/test/matcher/throws_test.dart @@ -27,13 +27,18 @@ void main() { }); expectTestFailed( - monitor, - allOf([ - startsWith('Expected: throws\n' - ' Actual: <'), - endsWith('>\n' - ' Which: returned \n') - ])); + monitor, + allOf([ + startsWith( + 'Expected: throws\n' + ' Actual: <', + ), + endsWith( + '>\n' + ' Which: returned \n', + ), + ]), + ); }); test('with a non-function', () async { @@ -43,10 +48,11 @@ void main() { }); expectTestFailed( - monitor, - 'Expected: throws\n' - ' Actual: <10>\n' - ' Which: was not a Function or Future\n'); + monitor, + 'Expected: throws\n' + ' Actual: <10>\n' + ' Which: was not a Function or Future\n', + ); }); }); @@ -56,8 +62,10 @@ void main() { }); test('with a function that throws a matching error', () { - expect(() => throw const FormatException('bad'), - throwsA(isFormatException)); + expect( + () => throw const FormatException('bad'), + throwsA(isFormatException), + ); }); test("with a function that doesn't throw", () async { @@ -67,13 +75,18 @@ void main() { }); expectTestFailed( - monitor, - allOf([ - startsWith("Expected: throws 'oh no'\n" - ' Actual: <'), - endsWith('>\n' - ' Which: returned \n') - ])); + monitor, + allOf([ + startsWith( + "Expected: throws 'oh no'\n" + ' Actual: <', + ), + endsWith( + '>\n' + ' Which: returned \n', + ), + ]), + ); }); test('with a non-function', () async { @@ -82,10 +95,11 @@ void main() { }); expectTestFailed( - monitor, - "Expected: throws 'oh no'\n" - ' Actual: <10>\n' - ' Which: was not a Function or Future\n'); + monitor, + "Expected: throws 'oh no'\n" + ' Actual: <10>\n' + ' Which: was not a Function or Future\n', + ); }); test('with a function that throws the wrong error', () async { @@ -94,19 +108,26 @@ void main() { }); expectTestFailed( - monitor, - allOf([ - startsWith("Expected: throws 'oh no'\n" - ' Actual: <'), - contains('>\n' - " Which: threw 'aw dang'\n" - ' stack'), - endsWith(' which is different.\n' - ' Expected: oh no\n' - ' Actual: aw dang\n' - ' ^\n' - ' Differ at offset 0\n') - ])); + monitor, + allOf([ + startsWith( + "Expected: throws 'oh no'\n" + ' Actual: <', + ), + contains( + '>\n' + " Which: threw 'aw dang'\n" + ' stack', + ), + endsWith( + ' which is different.\n' + ' Expected: oh no\n' + ' Actual: aw dang\n' + ' ^\n' + ' Differ at offset 0\n', + ), + ]), + ); }); }); }); @@ -125,13 +146,18 @@ void main() { }); expectTestFailed( - monitor, - allOf([ - startsWith('Expected: throws\n' - ' Actual: <'), - endsWith('>\n' - ' Which: emitted \n') - ])); + monitor, + allOf([ + startsWith( + 'Expected: throws\n' + ' Actual: <', + ), + endsWith( + '>\n' + ' Which: emitted \n', + ), + ]), + ); }); test('with a closure that returns a Future that throws an error', () { @@ -146,13 +172,18 @@ void main() { }); expectTestFailed( - monitor, - allOf([ - startsWith('Expected: throws\n' - ' Actual: <'), - endsWith('>\n' - ' Which: returned a Future that emitted \n') - ])); + monitor, + allOf([ + startsWith( + 'Expected: throws\n' + ' Actual: <', + ), + endsWith( + '>\n' + ' Which: returned a Future that emitted \n', + ), + ]), + ); }); test("won't let the test end until the Future completes", () async { @@ -177,8 +208,10 @@ void main() { }); test('with a Future that throws a matching error', () { - expect(Future.error(const FormatException('bad')), - throwsA(isFormatException)); + expect( + Future.error(const FormatException('bad')), + throwsA(isFormatException), + ); }); test("with a Future that doesn't throw", () async { @@ -187,13 +220,18 @@ void main() { }); expectTestFailed( - monitor, - allOf([ - startsWith("Expected: throws 'oh no'\n" - ' Actual: <'), - endsWith('>\n' - ' Which: emitted \n') - ])); + monitor, + allOf([ + startsWith( + "Expected: throws 'oh no'\n" + ' Actual: <', + ), + endsWith( + '>\n' + ' Which: emitted \n', + ), + ]), + ); }); test('with a Future that throws the wrong error', () async { @@ -202,20 +240,29 @@ void main() { }); expectTestFailed( - monitor, - allOf([ - startsWith("Expected: throws 'oh no'\n" - ' Actual: <'), - contains('>\n' - " Which: threw 'aw dang'\n") - ])); + monitor, + allOf([ + startsWith( + "Expected: throws 'oh no'\n" + ' Actual: <', + ), + contains( + '>\n' + " Which: threw 'aw dang'\n", + ), + ]), + ); }); - test('with a closure that returns a Future that throws a matching error', - () { - expect(() => Future.error(const FormatException('bad')), - throwsA(isFormatException)); - }); + test( + 'with a closure that returns a Future that throws a matching error', + () { + expect( + () => Future.error(const FormatException('bad')), + throwsA(isFormatException), + ); + }, + ); test("with a closure that returns a Future that doesn't throw", () async { var monitor = await TestCaseMonitor.run(() { @@ -223,30 +270,42 @@ void main() { }); expectTestFailed( - monitor, - allOf([ - startsWith("Expected: throws 'oh no'\n" - ' Actual: <'), - endsWith('>\n' - ' Which: returned a Future that emitted \n') - ])); + monitor, + allOf([ + startsWith( + "Expected: throws 'oh no'\n" + ' Actual: <', + ), + endsWith( + '>\n' + ' Which: returned a Future that emitted \n', + ), + ]), + ); }); - test('with closure that returns a Future that throws the wrong error', - () async { - var monitor = await TestCaseMonitor.run(() { - expect(() => Future.error('aw dang'), throwsA('oh no')); - }); + test( + 'with closure that returns a Future that throws the wrong error', + () async { + var monitor = await TestCaseMonitor.run(() { + expect(() => Future.error('aw dang'), throwsA('oh no')); + }); - expectTestFailed( + expectTestFailed( monitor, allOf([ - startsWith("Expected: throws 'oh no'\n" - ' Actual: <'), - contains('>\n' - " Which: threw 'aw dang'\n") - ])); - }); + startsWith( + "Expected: throws 'oh no'\n" + ' Actual: <', + ), + contains( + '>\n' + " Which: threw 'aw dang'\n", + ), + ]), + ); + }, + ); test("won't let the test end until the Future completes", () async { late void Function() callback; @@ -266,9 +325,11 @@ void main() { test("blocks expectLater's Future", () async { var completer = Completer(); var fired = false; - unawaited(expectLater(completer.future, throwsArgumentError).then((_) { - fired = true; - })); + unawaited( + expectLater(completer.future, throwsArgumentError).then((_) { + fired = true; + }), + ); await pumpEventQueue(); expect(fired, isFalse); diff --git a/pkgs/matcher/test/matcher/throws_type_test.dart b/pkgs/matcher/test/matcher/throws_type_test.dart index 557a73aac..929f38af5 100644 --- a/pkgs/matcher/test/matcher/throws_type_test.dart +++ b/pkgs/matcher/test/matcher/throws_type_test.dart @@ -20,15 +20,19 @@ void main() { expect(() => throw Exception(), throwsArgumentError); }); - expectTestFailed(liveTest, - startsWith("Expected: throws ")); + expectTestFailed( + liveTest, + startsWith("Expected: throws "), + ); }); }); group('[throwsConcurrentModificationError]', () { test('passes when a ConcurrentModificationError is thrown', () { - expect(() => throw ConcurrentModificationError(''), - throwsConcurrentModificationError); + expect( + () => throw ConcurrentModificationError(''), + throwsConcurrentModificationError, + ); }); test('fails when a non-ConcurrentModificationError is thrown', () async { @@ -37,18 +41,21 @@ void main() { }); expectTestFailed( - liveTest, - startsWith( - "Expected: throws ")); + liveTest, + startsWith( + "Expected: throws ", + ), + ); }); }); group('[throwsCyclicInitializationError]', () { test('passes when a CyclicInitializationError is thrown', () { expect( - () => _CyclicInitializationFailure().x, - // ignore: deprecated_member_use_from_same_package - throwsCyclicInitializationError); + () => _CyclicInitializationFailure().x, + // ignore: deprecated_member_use_from_same_package + throwsCyclicInitializationError, + ); }); test('fails when a non-CyclicInitializationError is thrown', () async { @@ -58,7 +65,9 @@ void main() { }); expectTestFailed( - liveTest, startsWith("Expected: throws ")); + liveTest, + startsWith("Expected: throws "), + ); }); }); @@ -73,7 +82,9 @@ void main() { }); expectTestFailed( - liveTest, startsWith("Expected: throws ")); + liveTest, + startsWith("Expected: throws "), + ); }); }); @@ -87,8 +98,10 @@ void main() { expect(() => throw Exception(), throwsFormatException); }); - expectTestFailed(liveTest, - startsWith("Expected: throws ")); + expectTestFailed( + liveTest, + startsWith("Expected: throws "), + ); }); }); @@ -105,8 +118,10 @@ void main() { expect(() => throw Exception(), throwsNoSuchMethodError); }); - expectTestFailed(liveTest, - startsWith("Expected: throws ")); + expectTestFailed( + liveTest, + startsWith("Expected: throws "), + ); }); }); @@ -121,7 +136,9 @@ void main() { }); expectTestFailed( - liveTest, startsWith("Expected: throws ")); + liveTest, + startsWith("Expected: throws "), + ); }); }); @@ -136,7 +153,9 @@ void main() { }); expectTestFailed( - liveTest, startsWith("Expected: throws ")); + liveTest, + startsWith("Expected: throws "), + ); }); }); @@ -150,8 +169,10 @@ void main() { expect(() => throw Exception(), throwsUnimplementedError); }); - expectTestFailed(liveTest, - startsWith("Expected: throws ")); + expectTestFailed( + liveTest, + startsWith("Expected: throws "), + ); }); }); @@ -165,8 +186,10 @@ void main() { expect(() => throw Exception(), throwsUnsupportedError); }); - expectTestFailed(liveTest, - startsWith("Expected: throws ")); + expectTestFailed( + liveTest, + startsWith("Expected: throws "), + ); }); }); } diff --git a/pkgs/matcher/test/mirror_matchers_test.dart b/pkgs/matcher/test/mirror_matchers_test.dart index 18a9e8d29..f6ef15358 100644 --- a/pkgs/matcher/test/mirror_matchers_test.dart +++ b/pkgs/matcher/test/mirror_matchers_test.dart @@ -25,33 +25,37 @@ void main() { var foo = [3]; shouldPass(foo, hasProperty('length', 1)); shouldFail( - foo, - hasProperty('foo'), - 'Expected: has property "foo" ' - 'Actual: [3] ' - 'Which: has no property named "foo"'); + foo, + hasProperty('foo'), + 'Expected: has property "foo" ' + 'Actual: [3] ' + 'Which: has no property named "foo"', + ); shouldFail( - foo, - hasProperty('length', 2), - 'Expected: has property "length" which matches <2> ' - 'Actual: [3] ' - 'Which: has property "length" with value <1>'); + foo, + hasProperty('length', 2), + 'Expected: has property "length" which matches <2> ' + 'Actual: [3] ' + 'Which: has property "length" with value <1>', + ); var c = C(); shouldPass(c, hasProperty('instanceField', 1)); shouldPass(c, hasProperty('instanceGetter', 2)); shouldFail( - c, - hasProperty('staticField'), - 'Expected: has property "staticField" ' - 'Actual: ' - 'Which: has a member named "staticField",' - ' but it is not an instance property'); + c, + hasProperty('staticField'), + 'Expected: has property "staticField" ' + 'Actual: ' + 'Which: has a member named "staticField",' + ' but it is not an instance property', + ); shouldFail( - c, - hasProperty('staticGetter'), - 'Expected: has property "staticGetter" ' - 'Actual: ' - 'Which: has a member named "staticGetter",' - ' but it is not an instance property'); + c, + hasProperty('staticGetter'), + 'Expected: has property "staticGetter" ' + 'Actual: ' + 'Which: has a member named "staticGetter",' + ' but it is not an instance property', + ); }); } diff --git a/pkgs/matcher/test/never_called_test.dart b/pkgs/matcher/test/never_called_test.dart index 39e09daa1..1a079d6de 100644 --- a/pkgs/matcher/test/never_called_test.dart +++ b/pkgs/matcher/test/never_called_test.dart @@ -28,9 +28,10 @@ void main() { }); expectTestFailed( - monitor, - 'Callback should never have been called, but it was called with no ' - 'arguments.'); + monitor, + 'Callback should never have been called, but it was called with no ' + 'arguments.', + ); }); test('pretty-prints arguments', () async { @@ -39,11 +40,12 @@ void main() { }); expectTestFailed( - monitor, - 'Callback should never have been called, but it was called with:\n' - '* <1>\n' - "* 'foo\\n'\n" - " 'bar'"); + monitor, + 'Callback should never have been called, but it was called with:\n' + '* <1>\n' + "* 'foo\\n'\n" + " 'bar'", + ); }); test('keeps the test alive', () async { @@ -52,9 +54,10 @@ void main() { }); expectTestFailed( - monitor, - 'Callback should never have been called, but it was called with:\n' - '* '); + monitor, + 'Callback should never have been called, but it was called with:\n' + '* ', + ); }); test("can't be caught", () async { @@ -67,9 +70,10 @@ void main() { }); expectTestFailed( - monitor, - 'Callback should never have been called, but it was called with ' - 'no arguments.'); + monitor, + 'Callback should never have been called, but it was called with ' + 'no arguments.', + ); }); }); } diff --git a/pkgs/matcher/test/numeric_matchers_test.dart b/pkgs/matcher/test/numeric_matchers_test.dart index 39195889f..49e6cf12d 100644 --- a/pkgs/matcher/test/numeric_matchers_test.dart +++ b/pkgs/matcher/test/numeric_matchers_test.dart @@ -12,87 +12,111 @@ void main() { shouldPass(-1, closeTo(0, 1)); shouldPass(1, closeTo(0, 1)); shouldFail( - 1.001, - closeTo(0, 1), - 'Expected: a numeric value within <1> of <0> ' - 'Actual: <1.001> ' - 'Which: differs by <1.001>'); + 1.001, + closeTo(0, 1), + 'Expected: a numeric value within <1> of <0> ' + 'Actual: <1.001> ' + 'Which: differs by <1.001>', + ); shouldFail( - -1.001, - closeTo(0, 1), - 'Expected: a numeric value within <1> of <0> ' - 'Actual: <-1.001> ' - 'Which: differs by <1.001>'); + -1.001, + closeTo(0, 1), + 'Expected: a numeric value within <1> of <0> ' + 'Actual: <-1.001> ' + 'Which: differs by <1.001>', + ); shouldFail( - 'not a num', closeTo(0, 1), endsWith('not an ')); + 'not a num', + closeTo(0, 1), + endsWith('not an '), + ); }); test('inInclusiveRange', () { shouldFail( - -1, - inInclusiveRange(0, 2), - 'Expected: be in range from 0 (inclusive) to 2 (inclusive) ' - 'Actual: <-1>'); + -1, + inInclusiveRange(0, 2), + 'Expected: be in range from 0 (inclusive) to 2 (inclusive) ' + 'Actual: <-1>', + ); shouldPass(0, inInclusiveRange(0, 2)); shouldPass(1, inInclusiveRange(0, 2)); shouldPass(2, inInclusiveRange(0, 2)); shouldFail( - 3, - inInclusiveRange(0, 2), - 'Expected: be in range from 0 (inclusive) to 2 (inclusive) ' - 'Actual: <3>'); - shouldFail('not a num', inInclusiveRange(0, 1), - endsWith('not an ')); + 3, + inInclusiveRange(0, 2), + 'Expected: be in range from 0 (inclusive) to 2 (inclusive) ' + 'Actual: <3>', + ); + shouldFail( + 'not a num', + inInclusiveRange(0, 1), + endsWith('not an '), + ); }); test('inExclusiveRange', () { shouldFail( - 0, - inExclusiveRange(0, 2), - 'Expected: be in range from 0 (exclusive) to 2 (exclusive) ' - 'Actual: <0>'); + 0, + inExclusiveRange(0, 2), + 'Expected: be in range from 0 (exclusive) to 2 (exclusive) ' + 'Actual: <0>', + ); shouldPass(1, inExclusiveRange(0, 2)); shouldFail( - 2, - inExclusiveRange(0, 2), - 'Expected: be in range from 0 (exclusive) to 2 (exclusive) ' - 'Actual: <2>'); - shouldFail('not a num', inExclusiveRange(0, 1), - endsWith('not an ')); + 2, + inExclusiveRange(0, 2), + 'Expected: be in range from 0 (exclusive) to 2 (exclusive) ' + 'Actual: <2>', + ); + shouldFail( + 'not a num', + inExclusiveRange(0, 1), + endsWith('not an '), + ); }); test('inOpenClosedRange', () { shouldFail( - 0, - inOpenClosedRange(0, 2), - 'Expected: be in range from 0 (exclusive) to 2 (inclusive) ' - 'Actual: <0>'); + 0, + inOpenClosedRange(0, 2), + 'Expected: be in range from 0 (exclusive) to 2 (inclusive) ' + 'Actual: <0>', + ); shouldPass(1, inOpenClosedRange(0, 2)); shouldPass(2, inOpenClosedRange(0, 2)); - shouldFail('not a num', inOpenClosedRange(0, 1), - endsWith('not an ')); + shouldFail( + 'not a num', + inOpenClosedRange(0, 1), + endsWith('not an '), + ); }); test('inClosedOpenRange', () { shouldPass(0, inClosedOpenRange(0, 2)); shouldPass(1, inClosedOpenRange(0, 2)); shouldFail( - 2, - inClosedOpenRange(0, 2), - 'Expected: be in range from 0 (inclusive) to 2 (exclusive) ' - 'Actual: <2>'); - shouldFail('not a num', inClosedOpenRange(0, 1), - endsWith('not an ')); + 2, + inClosedOpenRange(0, 2), + 'Expected: be in range from 0 (inclusive) to 2 (exclusive) ' + 'Actual: <2>', + ); + shouldFail( + 'not a num', + inClosedOpenRange(0, 1), + endsWith('not an '), + ); }); group('NaN', () { test('inInclusiveRange', () { shouldFail( - double.nan, - inExclusiveRange(double.negativeInfinity, double.infinity), - 'Expected: be in range from ' - '-Infinity (exclusive) to Infinity (exclusive) ' - 'Actual: '); + double.nan, + inExclusiveRange(double.negativeInfinity, double.infinity), + 'Expected: be in range from ' + '-Infinity (exclusive) to Infinity (exclusive) ' + 'Actual: ', + ); }); }); } diff --git a/pkgs/matcher/test/operator_matchers_test.dart b/pkgs/matcher/test/operator_matchers_test.dart index 46151e0f6..0597a4b39 100644 --- a/pkgs/matcher/test/operator_matchers_test.dart +++ b/pkgs/matcher/test/operator_matchers_test.dart @@ -11,12 +11,18 @@ void main() { test('anyOf', () { // with a list shouldFail( - 0, anyOf([equals(1), equals(2)]), 'Expected: (<1> or <2>) Actual: <0>'); + 0, + anyOf([equals(1), equals(2)]), + 'Expected: (<1> or <2>) Actual: <0>', + ); shouldPass(1, anyOf([equals(1), equals(2)])); // with individual items shouldFail( - 0, anyOf(equals(1), equals(2)), 'Expected: (<1> or <2>) Actual: <0>'); + 0, + anyOf(equals(1), equals(2)), + 'Expected: (<1> or <2>) Actual: <0>', + ); shouldPass(1, anyOf(equals(1), equals(2))); }); @@ -24,40 +30,60 @@ void main() { // with a list shouldPass(1, allOf([lessThan(10), greaterThan(0)])); shouldFail( - -1, - allOf([lessThan(10), greaterThan(0)]), - 'Expected: (a value less than <10> and a value greater than <0>) ' - 'Actual: <-1> ' - 'Which: is not a value greater than <0>'); + -1, + allOf([lessThan(10), greaterThan(0)]), + 'Expected: (a value less than <10> and a value greater than <0>) ' + 'Actual: <-1> ' + 'Which: is not a value greater than <0>', + ); // with individual items shouldPass(1, allOf(lessThan(10), greaterThan(0))); shouldFail( - -1, - allOf(lessThan(10), greaterThan(0)), - 'Expected: (a value less than <10> and a value greater than <0>) ' - 'Actual: <-1> ' - 'Which: is not a value greater than <0>'); + -1, + allOf(lessThan(10), greaterThan(0)), + 'Expected: (a value less than <10> and a value greater than <0>) ' + 'Actual: <-1> ' + 'Which: is not a value greater than <0>', + ); // with maximum items shouldPass( - 1, - allOf(lessThan(10), lessThan(9), lessThan(8), lessThan(7), lessThan(6), - lessThan(5), lessThan(4))); + 1, + allOf( + lessThan(10), + lessThan(9), + lessThan(8), + lessThan(7), + lessThan(6), + lessThan(5), + lessThan(4), + ), + ); shouldFail( - 4, - allOf(lessThan(10), lessThan(9), lessThan(8), lessThan(7), lessThan(6), - lessThan(5), lessThan(4)), - 'Expected: (a value less than <10> and a value less than <9> and a ' - 'value less than <8> and a value less than <7> and a value less than ' - '<6> and a value less than <5> and a value less than <4>) ' - 'Actual: <4> ' - 'Which: is not a value less than <4>'); + 4, + allOf( + lessThan(10), + lessThan(9), + lessThan(8), + lessThan(7), + lessThan(6), + lessThan(5), + lessThan(4), + ), + 'Expected: (a value less than <10> and a value less than <9> and a ' + 'value less than <8> and a value less than <7> and a value less than ' + '<6> and a value less than <5> and a value less than <4>) ' + 'Actual: <4> ' + 'Which: is not a value less than <4>', + ); }); test('If the first argument is a List, the rest must be null', () { expect(() => allOf([], 5), throwsArgumentError); expect( - () => anyOf([], null, null, null, null, null, 42), throwsArgumentError); + () => anyOf([], null, null, null, null, null, 42), + throwsArgumentError, + ); }); } diff --git a/pkgs/matcher/test/order_matchers_test.dart b/pkgs/matcher/test/order_matchers_test.dart index 8a7c3df6c..61c44ebb4 100644 --- a/pkgs/matcher/test/order_matchers_test.dart +++ b/pkgs/matcher/test/order_matchers_test.dart @@ -10,140 +10,155 @@ void main() { test('greaterThan', () { shouldPass(10, greaterThan(9)); shouldFail( - 9, - greaterThan(10), - 'Expected: a value greater than <10> ' - 'Actual: <9> ' - 'Which: is not a value greater than <10>'); + 9, + greaterThan(10), + 'Expected: a value greater than <10> ' + 'Actual: <9> ' + 'Which: is not a value greater than <10>', + ); }); test('greaterThanOrEqualTo', () { shouldPass(10, greaterThanOrEqualTo(10)); shouldFail( - 9, - greaterThanOrEqualTo(10), - 'Expected: a value greater than or equal to <10> ' - 'Actual: <9> ' - 'Which: is not a value greater than or equal to <10>'); + 9, + greaterThanOrEqualTo(10), + 'Expected: a value greater than or equal to <10> ' + 'Actual: <9> ' + 'Which: is not a value greater than or equal to <10>', + ); }); test('lessThan', () { shouldFail( - 10, - lessThan(9), - 'Expected: a value less than <9> ' - 'Actual: <10> ' - 'Which: is not a value less than <9>'); + 10, + lessThan(9), + 'Expected: a value less than <9> ' + 'Actual: <10> ' + 'Which: is not a value less than <9>', + ); shouldPass(9, lessThan(10)); }); test('lessThanOrEqualTo', () { shouldPass(10, lessThanOrEqualTo(10)); shouldFail( - 11, - lessThanOrEqualTo(10), - 'Expected: a value less than or equal to <10> ' - 'Actual: <11> ' - 'Which: is not a value less than or equal to <10>'); + 11, + lessThanOrEqualTo(10), + 'Expected: a value less than or equal to <10> ' + 'Actual: <11> ' + 'Which: is not a value less than or equal to <10>', + ); }); test('isZero', () { shouldPass(0, isZero); shouldFail( - 1, - isZero, - 'Expected: a value equal to <0> ' - 'Actual: <1> ' - 'Which: is not a value equal to <0>'); + 1, + isZero, + 'Expected: a value equal to <0> ' + 'Actual: <1> ' + 'Which: is not a value equal to <0>', + ); }); test('isNonZero', () { shouldFail( - 0, - isNonZero, - 'Expected: a value not equal to <0> ' - 'Actual: <0> ' - 'Which: is not a value not equal to <0>'); + 0, + isNonZero, + 'Expected: a value not equal to <0> ' + 'Actual: <0> ' + 'Which: is not a value not equal to <0>', + ); shouldPass(1, isNonZero); }); test('isPositive', () { shouldFail( - -1, - isPositive, - 'Expected: a positive value ' - 'Actual: <-1> ' - 'Which: is not a positive value'); + -1, + isPositive, + 'Expected: a positive value ' + 'Actual: <-1> ' + 'Which: is not a positive value', + ); shouldFail( - 0, - isPositive, - 'Expected: a positive value ' - 'Actual: <0> ' - 'Which: is not a positive value'); + 0, + isPositive, + 'Expected: a positive value ' + 'Actual: <0> ' + 'Which: is not a positive value', + ); shouldPass(1, isPositive); }); test('isNegative', () { shouldPass(-1, isNegative); shouldFail( - 0, - isNegative, - 'Expected: a negative value ' - 'Actual: <0> ' - 'Which: is not a negative value'); + 0, + isNegative, + 'Expected: a negative value ' + 'Actual: <0> ' + 'Which: is not a negative value', + ); }); test('isNonPositive', () { shouldPass(-1, isNonPositive); shouldPass(0, isNonPositive); shouldFail( - 1, - isNonPositive, - 'Expected: a non-positive value ' - 'Actual: <1> ' - 'Which: is not a non-positive value'); + 1, + isNonPositive, + 'Expected: a non-positive value ' + 'Actual: <1> ' + 'Which: is not a non-positive value', + ); }); test('isNonNegative', () { shouldPass(1, isNonNegative); shouldPass(0, isNonNegative); shouldFail( - -1, - isNonNegative, - 'Expected: a non-negative value ' - 'Actual: <-1> ' - 'Which: is not a non-negative value'); + -1, + isNonNegative, + 'Expected: a non-negative value ' + 'Actual: <-1> ' + 'Which: is not a non-negative value', + ); }); group('NaN', () { test('greaterThan', () { shouldFail( - double.nan, - greaterThan(10), - 'Expected: a value greater than <10> ' - 'Actual: ' - 'Which: is not a value greater than <10>'); + double.nan, + greaterThan(10), + 'Expected: a value greater than <10> ' + 'Actual: ' + 'Which: is not a value greater than <10>', + ); shouldFail( - 10, - greaterThan(double.nan), - 'Expected: a value greater than ' - 'Actual: <10> ' - 'Which: is not a value greater than '); + 10, + greaterThan(double.nan), + 'Expected: a value greater than ' + 'Actual: <10> ' + 'Which: is not a value greater than ', + ); }); test('lessThanOrEqualTo', () { shouldFail( - double.nan, - lessThanOrEqualTo(10), - 'Expected: a value less than or equal to <10> ' - 'Actual: ' - 'Which: is not a value less than or equal to <10>'); + double.nan, + lessThanOrEqualTo(10), + 'Expected: a value less than or equal to <10> ' + 'Actual: ' + 'Which: is not a value less than or equal to <10>', + ); shouldFail( - 10, - lessThanOrEqualTo(double.nan), - 'Expected: a value less than or equal to ' - 'Actual: <10> ' - 'Which: is not a value less than or equal to '); + 10, + lessThanOrEqualTo(double.nan), + 'Expected: a value less than or equal to ' + 'Actual: <10> ' + 'Which: is not a value less than or equal to ', + ); }); }); } diff --git a/pkgs/matcher/test/pretty_print_test.dart b/pkgs/matcher/test/pretty_print_test.dart index 62f3ab1f2..9f3558726 100644 --- a/pkgs/matcher/test/pretty_print_test.dart +++ b/pkgs/matcher/test/pretty_print_test.dart @@ -41,15 +41,20 @@ void main() { test('containing newlines', () { expect( - prettyPrint('foo\nbar\nbaz'), - equals("'foo\\n'\n" - " 'bar\\n'\n" - " 'baz'")); + prettyPrint('foo\nbar\nbaz'), + equals( + "'foo\\n'\n" + " 'bar\\n'\n" + " 'baz'", + ), + ); }); test('containing escapable characters', () { - expect(prettyPrint("foo\rbar\tbaz'qux\v"), - equals(r"'foo\rbar\tbaz\'qux\v'")); + expect( + prettyPrint("foo\rbar\tbaz'qux\v"), + equals(r"'foo\rbar\tbaz\'qux\v'"), + ); }); }); @@ -60,75 +65,92 @@ void main() { test('containing a multiline string', () { expect( - prettyPrint(['foo', 'bar\nbaz\nbip', 'qux']), - equals('[\n' - " 'foo',\n" - " 'bar\\n'\n" - " 'baz\\n'\n" - " 'bip',\n" - " 'qux'\n" - ']')); + prettyPrint(['foo', 'bar\nbaz\nbip', 'qux']), + equals( + '[\n' + " 'foo',\n" + " 'bar\\n'\n" + " 'baz\\n'\n" + " 'bip',\n" + " 'qux'\n" + ']', + ), + ); }); test('containing a matcher', () { - expect(prettyPrint(['foo', endsWith('qux')]), - equals("['foo', ]")); + expect( + prettyPrint(['foo', endsWith('qux')]), + equals("['foo', ]"), + ); }); test("that's under maxLineLength", () { - expect(prettyPrint([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], maxLineLength: 30), - equals('[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]')); + expect( + prettyPrint([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], maxLineLength: 30), + equals('[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]'), + ); }); test("that's over maxLineLength", () { expect( - prettyPrint([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], maxLineLength: 29), - equals('[\n' - ' 0,\n' - ' 1,\n' - ' 2,\n' - ' 3,\n' - ' 4,\n' - ' 5,\n' - ' 6,\n' - ' 7,\n' - ' 8,\n' - ' 9\n' - ']')); + prettyPrint([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], maxLineLength: 29), + equals( + '[\n' + ' 0,\n' + ' 1,\n' + ' 2,\n' + ' 3,\n' + ' 4,\n' + ' 5,\n' + ' 6,\n' + ' 7,\n' + ' 8,\n' + ' 9\n' + ']', + ), + ); }); test('factors indentation into maxLineLength', () { expect( - prettyPrint([ - 'foo\nbar', - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - ], maxLineLength: 30), - equals('[\n' - " 'foo\\n'\n" - " 'bar',\n" - ' [\n' - ' 0,\n' - ' 1,\n' - ' 2,\n' - ' 3,\n' - ' 4,\n' - ' 5,\n' - ' 6,\n' - ' 7,\n' - ' 8,\n' - ' 9\n' - ' ]\n' - ']')); + prettyPrint([ + 'foo\nbar', + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + ], maxLineLength: 30), + equals( + '[\n' + " 'foo\\n'\n" + " 'bar',\n" + ' [\n' + ' 0,\n' + ' 1,\n' + ' 2,\n' + ' 3,\n' + ' 4,\n' + ' 5,\n' + ' 6,\n' + ' 7,\n' + ' 8,\n' + ' 9\n' + ' ]\n' + ']', + ), + ); }); test("that's under maxItems", () { - expect(prettyPrint([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], maxItems: 10), - equals('[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]')); + expect( + prettyPrint([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], maxItems: 10), + equals('[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]'), + ); }); test("that's over maxItems", () { - expect(prettyPrint([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], maxItems: 9), - equals('[0, 1, 2, 3, 4, 5, 6, 7, ...]')); + expect( + prettyPrint([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], maxItems: 9), + equals('[0, 1, 2, 3, 4, 5, 6, 7, ...]'), + ); }); test("that's recursive", () { @@ -140,120 +162,157 @@ void main() { group('with a map', () { test('containing primitive objects', () { - expect(prettyPrint({'foo': 1, 'bar': true}), - equals("{'foo': 1, 'bar': true}")); + expect( + prettyPrint({'foo': 1, 'bar': true}), + equals("{'foo': 1, 'bar': true}"), + ); }); test('containing a multiline string key', () { expect( - prettyPrint({'foo\nbar': 1, 'bar': true}), - equals('{\n' - " 'foo\\n'\n" - " 'bar': 1,\n" - " 'bar': true\n" - '}')); + prettyPrint({'foo\nbar': 1, 'bar': true}), + equals( + '{\n' + " 'foo\\n'\n" + " 'bar': 1,\n" + " 'bar': true\n" + '}', + ), + ); }); test('containing a multiline string value', () { expect( - prettyPrint({'foo': 'bar\nbaz', 'qux': true}), - equals('{\n' - " 'foo': 'bar\\n'\n" - " 'baz',\n" - " 'qux': true\n" - '}')); + prettyPrint({'foo': 'bar\nbaz', 'qux': true}), + equals( + '{\n' + " 'foo': 'bar\\n'\n" + " 'baz',\n" + " 'qux': true\n" + '}', + ), + ); }); test('containing a multiline string key/value pair', () { expect( - prettyPrint({'foo\nbar': 'baz\nqux'}), - equals('{\n' - " 'foo\\n'\n" - " 'bar': 'baz\\n'\n" - " 'qux'\n" - '}')); + prettyPrint({'foo\nbar': 'baz\nqux'}), + equals( + '{\n' + " 'foo\\n'\n" + " 'bar': 'baz\\n'\n" + " 'qux'\n" + '}', + ), + ); }); test('containing a matcher key', () { - expect(prettyPrint({endsWith('bar'): 'qux'}), - equals("{: 'qux'}")); + expect( + prettyPrint({endsWith('bar'): 'qux'}), + equals("{: 'qux'}"), + ); }); test('containing a matcher value', () { - expect(prettyPrint({'foo': endsWith('qux')}), - equals("{'foo': }")); + expect( + prettyPrint({'foo': endsWith('qux')}), + equals("{'foo': }"), + ); }); test("that's under maxLineLength", () { - expect(prettyPrint({'0': 1, '2': 3, '4': 5, '6': 7}, maxLineLength: 32), - equals("{'0': 1, '2': 3, '4': 5, '6': 7}")); + expect( + prettyPrint({'0': 1, '2': 3, '4': 5, '6': 7}, maxLineLength: 32), + equals("{'0': 1, '2': 3, '4': 5, '6': 7}"), + ); }); test("that's over maxLineLength", () { expect( - prettyPrint({'0': 1, '2': 3, '4': 5, '6': 7}, maxLineLength: 31), - equals('{\n' - " '0': 1,\n" - " '2': 3,\n" - " '4': 5,\n" - " '6': 7\n" - '}')); + prettyPrint({'0': 1, '2': 3, '4': 5, '6': 7}, maxLineLength: 31), + equals( + '{\n' + " '0': 1,\n" + " '2': 3,\n" + " '4': 5,\n" + " '6': 7\n" + '}', + ), + ); }); test('factors indentation into maxLineLength', () { expect( - prettyPrint([ - 'foo\nbar', - {'0': 1, '2': 3, '4': 5, '6': 7} - ], maxLineLength: 32), - equals('[\n' - " 'foo\\n'\n" - " 'bar',\n" - ' {\n' - " '0': 1,\n" - " '2': 3,\n" - " '4': 5,\n" - " '6': 7\n" - ' }\n' - ']')); + prettyPrint([ + 'foo\nbar', + {'0': 1, '2': 3, '4': 5, '6': 7}, + ], maxLineLength: 32), + equals( + '[\n' + " 'foo\\n'\n" + " 'bar',\n" + ' {\n' + " '0': 1,\n" + " '2': 3,\n" + " '4': 5,\n" + " '6': 7\n" + ' }\n' + ']', + ), + ); }); test("that's under maxItems", () { - expect(prettyPrint({'0': 1, '2': 3, '4': 5, '6': 7}, maxItems: 4), - equals("{'0': 1, '2': 3, '4': 5, '6': 7}")); + expect( + prettyPrint({'0': 1, '2': 3, '4': 5, '6': 7}, maxItems: 4), + equals("{'0': 1, '2': 3, '4': 5, '6': 7}"), + ); }); test("that's over maxItems", () { - expect(prettyPrint({'0': 1, '2': 3, '4': 5, '6': 7}, maxItems: 3), - equals("{'0': 1, '2': 3, ...}")); + expect( + prettyPrint({'0': 1, '2': 3, '4': 5, '6': 7}, maxItems: 3), + equals("{'0': 1, '2': 3, ...}"), + ); }); }); group('with an object', () { test('with a default [toString]', () { - expect(prettyPrint(DefaultToString()), - equals("")); + expect( + prettyPrint(DefaultToString()), + equals(""), + ); }); test('with a custom [toString]', () { - expect(prettyPrint(CustomToString()), - equals('CustomToString:')); + expect( + prettyPrint(CustomToString()), + equals('CustomToString:'), + ); }); test('with a custom [toString] and a private name', () { - expect(prettyPrint(_PrivateName()), - equals('_PrivateName:')); + expect( + prettyPrint(_PrivateName()), + equals('_PrivateName:'), + ); }); }); group('with an iterable', () { test("that's not a list", () { - expect(prettyPrint([1, 2, 3, 4].map((n) => n * 2)), - equals('MappedListIterable:[2, 4, 6, 8]')); + expect( + prettyPrint([1, 2, 3, 4].map((n) => n * 2)), + equals('MappedListIterable:[2, 4, 6, 8]'), + ); }); test("that's not a list and has a private name", () { - expect(prettyPrint(_PrivateNameIterable()), - equals('_PrivateNameIterable:[1, 2, 3]')); + expect( + prettyPrint(_PrivateNameIterable()), + equals('_PrivateNameIterable:[1, 2, 3]'), + ); }); }); diff --git a/pkgs/matcher/test/stream_matcher_test.dart b/pkgs/matcher/test/stream_matcher_test.dart index 66e79c6c5..1f9088082 100644 --- a/pkgs/matcher/test/stream_matcher_test.dart +++ b/pkgs/matcher/test/stream_matcher_test.dart @@ -24,7 +24,8 @@ void main() { queue = StreamQueue(Stream.fromIterable([1, 2, 3, 4, 5])); errorStream = Stream.fromFuture(Future.error('oh no!', StackTrace.current)); errorQueue = StreamQueue( - Stream.fromFuture(Future.error('oh no!', StackTrace.current))); + Stream.fromFuture(Future.error('oh no!', StackTrace.current)), + ); }); group('emits()', () { @@ -34,16 +35,21 @@ void main() { test('rejects the first event of a Stream', () { expect( - expectLater(stream, emits(2)), - throwsTestFailure(allOf([ + expectLater(stream, emits(2)), + throwsTestFailure( + allOf([ startsWith('Expected: should emit an event that <2>\n'), - endsWith(' Which: emitted * 1\n' - ' * 2\n' - ' * 3\n' - ' * 4\n' - ' * 5\n' - ' x Stream closed.\n') - ]))); + endsWith( + ' Which: emitted * 1\n' + ' * 2\n' + ' * 3\n' + ' * 4\n' + ' * 5\n' + ' x Stream closed.\n', + ), + ]), + ), + ); }); test('matches and consumes the next event of a StreamQueue', () { @@ -55,27 +61,35 @@ void main() { test('rejects and does not consume the first event of a StreamQueue', () { expect( - expectLater(queue, emits(2)), - throwsTestFailure(allOf([ + expectLater(queue, emits(2)), + throwsTestFailure( + allOf([ startsWith('Expected: should emit an event that <2>\n'), - endsWith(' Which: emitted * 1\n' - ' * 2\n' - ' * 3\n' - ' * 4\n' - ' * 5\n' - ' x Stream closed.\n') - ]))); + endsWith( + ' Which: emitted * 1\n' + ' * 2\n' + ' * 3\n' + ' * 4\n' + ' * 5\n' + ' x Stream closed.\n', + ), + ]), + ), + ); expect(queue, emits(1)); }); test('rejects an empty stream', () { expect( - expectLater(const Stream.empty(), emits(1)), - throwsTestFailure(allOf([ + expectLater(const Stream.empty(), emits(1)), + throwsTestFailure( + allOf([ startsWith('Expected: should emit an event that <1>\n'), - endsWith(' Which: emitted x Stream closed.\n') - ]))); + endsWith(' Which: emitted x Stream closed.\n'), + ]), + ), + ); }); test('forwards a stream error', () { @@ -84,8 +98,10 @@ void main() { test('wraps a normal matcher', () { expect(queue, emits(lessThan(5))); - expect(expectLater(queue, emits(greaterThan(5))), - throwsTestFailure(anything)); + expect( + expectLater(queue, emits(greaterThan(5))), + throwsTestFailure(anything), + ); }); test('returns a StreamMatcher as-is', () { @@ -101,16 +117,21 @@ void main() { test('fails for a stream with events', () { expect( - expectLater(stream, emitsDone), - throwsTestFailure(allOf([ + expectLater(stream, emitsDone), + throwsTestFailure( + allOf([ startsWith('Expected: should be done\n'), - endsWith(' Which: emitted * 1\n' - ' * 2\n' - ' * 3\n' - ' * 4\n' - ' * 5\n' - ' x Stream closed.\n') - ]))); + endsWith( + ' Which: emitted * 1\n' + ' * 2\n' + ' * 3\n' + ' * 4\n' + ' * 5\n' + ' x Stream closed.\n', + ), + ]), + ), + ); }); }); @@ -122,33 +143,45 @@ void main() { test('fails for a non-matching error', () { expect( - expectLater(errorStream, emitsError('oh heck')), - throwsTestFailure(allOf([ + expectLater(errorStream, emitsError('oh heck')), + throwsTestFailure( + allOf([ startsWith("Expected: should emit an error that 'oh heck'\n"), contains(' Which: emitted ! oh no!\n'), - contains(' x Stream closed.\n' - " which threw 'oh no!'\n" - ' stack '), - endsWith(' which is different.\n' - ' Expected: oh heck\n' - ' Actual: oh no!\n' - ' ^\n' - ' Differ at offset 3\n') - ]))); + contains( + ' x Stream closed.\n' + " which threw 'oh no!'\n" + ' stack ', + ), + endsWith( + ' which is different.\n' + ' Expected: oh heck\n' + ' Actual: oh no!\n' + ' ^\n' + ' Differ at offset 3\n', + ), + ]), + ), + ); }); test('fails for a stream with events', () { expect( - expectLater(stream, emitsDone), - throwsTestFailure(allOf([ + expectLater(stream, emitsDone), + throwsTestFailure( + allOf([ startsWith('Expected: should be done\n'), - endsWith(' Which: emitted * 1\n' - ' * 2\n' - ' * 3\n' - ' * 4\n' - ' * 5\n' - ' x Stream closed.\n') - ]))); + endsWith( + ' Which: emitted * 1\n' + ' * 2\n' + ' * 3\n' + ' * 4\n' + ' * 5\n' + ' x Stream closed.\n', + ), + ]), + ), + ); }); }); @@ -172,35 +205,43 @@ void main() { test('consumes as many events as possible', () { expect( - queue, - emitsAnyOf([ - 1, - emitsInOrder([1, 2]), - emitsInOrder([1, 2, 3]) - ])); + queue, + emitsAnyOf([ + 1, + emitsInOrder([1, 2]), + emitsInOrder([1, 2, 3]), + ]), + ); expect(queue, emits(4)); }); test('fails if no matchers match', () { expect( - expectLater(stream, emitsAnyOf([2, 3, 4])), - throwsTestFailure(allOf([ - startsWith('Expected: should do one of the following:\n' - ' * emit an event that <2>\n' - ' * emit an event that <3>\n' - ' * emit an event that <4>\n'), - endsWith(' Which: emitted * 1\n' - ' * 2\n' - ' * 3\n' - ' * 4\n' - ' * 5\n' - ' x Stream closed.\n' - ' which failed all options:\n' - ' * failed to emit an event that <2>\n' - ' * failed to emit an event that <3>\n' - ' * failed to emit an event that <4>\n') - ]))); + expectLater(stream, emitsAnyOf([2, 3, 4])), + throwsTestFailure( + allOf([ + startsWith( + 'Expected: should do one of the following:\n' + ' * emit an event that <2>\n' + ' * emit an event that <3>\n' + ' * emit an event that <4>\n', + ), + endsWith( + ' Which: emitted * 1\n' + ' * 2\n' + ' * 3\n' + ' * 4\n' + ' * 5\n' + ' x Stream closed.\n' + ' which failed all options:\n' + ' * failed to emit an event that <2>\n' + ' * failed to emit an event that <3>\n' + ' * failed to emit an event that <4>\n', + ), + ]), + ), + ); }); test('allows an error if any matcher matches', () { @@ -209,7 +250,9 @@ void main() { test('rethrows an error if no matcher matches', () { expect( - expectLater(errorStream, emitsAnyOf([1, 2, 3])), throwsA('oh no!')); + expectLater(errorStream, emitsAnyOf([1, 2, 3])), + throwsA('oh no!'), + ); }); }); @@ -221,20 +264,27 @@ void main() { test("fails if the matchers don't match in order", () { expect( - expectLater(queue, emitsInOrder([1, 3, 2])), - throwsTestFailure(allOf([ - startsWith('Expected: should do the following in order:\n' - ' * emit an event that <1>\n' - ' * emit an event that <3>\n' - ' * emit an event that <2>\n'), - endsWith(' Which: emitted * 1\n' - ' * 2\n' - ' * 3\n' - ' * 4\n' - ' * 5\n' - ' x Stream closed.\n' - " which didn't emit an event that <3>\n") - ]))); + expectLater(queue, emitsInOrder([1, 3, 2])), + throwsTestFailure( + allOf([ + startsWith( + 'Expected: should do the following in order:\n' + ' * emit an event that <1>\n' + ' * emit an event that <3>\n' + ' * emit an event that <2>\n', + ), + endsWith( + ' Which: emitted * 1\n' + ' * 2\n' + ' * 3\n' + ' * 4\n' + ' * 5\n' + ' x Stream closed.\n' + " which didn't emit an event that <3>\n", + ), + ]), + ), + ); }); }); @@ -251,17 +301,22 @@ void main() { test('fails if the queue never matches the matcher', () { expect( - expectLater(queue, emitsThrough(6)), - throwsTestFailure(allOf([ + expectLater(queue, emitsThrough(6)), + throwsTestFailure( + allOf([ startsWith('Expected: should eventually emit an event that <6>\n'), - endsWith(' Which: emitted * 1\n' - ' * 2\n' - ' * 3\n' - ' * 4\n' - ' * 5\n' - ' x Stream closed.\n' - ' which never did emit an event that <6>\n') - ]))); + endsWith( + ' Which: emitted * 1\n' + ' * 2\n' + ' * 3\n' + ' * 4\n' + ' * 5\n' + ' x Stream closed.\n' + ' which never did emit an event that <6>\n', + ), + ]), + ), + ); }); }); @@ -290,22 +345,29 @@ void main() { test('fails if the event matches', () { expect( - expectLater(stream, neverEmits(4)), - throwsTestFailure(allOf([ + expectLater(stream, neverEmits(4)), + throwsTestFailure( + allOf([ startsWith('Expected: should never emit an event that <4>\n'), - endsWith(' Which: emitted * 1\n' - ' * 2\n' - ' * 3\n' - ' * 4\n' - ' * 5\n' - ' x Stream closed.\n' - ' which after 3 events did emit an event that <4>\n') - ]))); + endsWith( + ' Which: emitted * 1\n' + ' * 2\n' + ' * 3\n' + ' * 4\n' + ' * 5\n' + ' x Stream closed.\n' + ' which after 3 events did emit an event that <4>\n', + ), + ]), + ), + ); }); test('fails if emitsDone matches', () { - expect(expectLater(stream, neverEmits(emitsDone)), - throwsTestFailure(anything)); + expect( + expectLater(stream, neverEmits(emitsDone)), + throwsTestFailure(anything), + ); }); test("doesn't rethrow errors", () { @@ -322,19 +384,26 @@ void main() { test("fails if the events don't match in any order", () { expect( - expectLater(stream, emitsInAnyOrder([4, 1, 2])), - throwsTestFailure(allOf([ - startsWith('Expected: should do the following in any order:\n' - ' * emit an event that <4>\n' - ' * emit an event that <1>\n' - ' * emit an event that <2>\n'), - endsWith(' Which: emitted * 1\n' - ' * 2\n' - ' * 3\n' - ' * 4\n' - ' * 5\n' - ' x Stream closed.\n') - ]))); + expectLater(stream, emitsInAnyOrder([4, 1, 2])), + throwsTestFailure( + allOf([ + startsWith( + 'Expected: should do the following in any order:\n' + ' * emit an event that <4>\n' + ' * emit an event that <1>\n' + ' * emit an event that <2>\n', + ), + endsWith( + ' Which: emitted * 1\n' + ' * 2\n' + ' * 3\n' + ' * 4\n' + ' * 5\n' + ' x Stream closed.\n', + ), + ]), + ), + ); }); test("doesn't rethrow if some ordering matches", () { @@ -343,8 +412,9 @@ void main() { test('rethrows if no ordering matches', () { expect( - expectLater(errorQueue, emitsInAnyOrder([1, emitsError('oh no!')])), - throwsA('oh no!')); + expectLater(errorQueue, emitsInAnyOrder([1, emitsError('oh no!')])), + throwsA('oh no!'), + ); }); }); diff --git a/pkgs/matcher/test/string_matchers_test.dart b/pkgs/matcher/test/string_matchers_test.dart index 082001593..ccff9258f 100644 --- a/pkgs/matcher/test/string_matchers_test.dart +++ b/pkgs/matcher/test/string_matchers_test.dart @@ -9,18 +9,22 @@ import 'test_utils.dart'; void main() { test('Reports mismatches in whitespace and escape sequences', () { - shouldFail('before\nafter', equals('before\\nafter'), - contains('Differ at offset 7')); + shouldFail( + 'before\nafter', + equals('before\\nafter'), + contains('Differ at offset 7'), + ); }); test('Retains outer matcher mismatch text', () { shouldFail( - {'word': 'thing'}, - containsPair('word', equals('notthing')), - allOf([ - contains("contains key 'word' but with value is different"), - contains('Differ at offset 0') - ])); + {'word': 'thing'}, + containsPair('word', equals('notthing')), + allOf([ + contains("contains key 'word' but with value is different"), + contains('Differ at offset 0'), + ]), + ); }); test('collapseWhitespace', () { @@ -39,36 +43,52 @@ void main() { test('isNot(isEmpty)', () { shouldPass('a', isNot(isEmpty)); shouldFail('', isNot(isEmpty), 'Expected: not empty Actual: \'\''); - shouldFail(null, isNot(isEmpty), - startsWith('Expected: not empty Actual: ')); + shouldFail( + null, + isNot(isEmpty), + startsWith('Expected: not empty Actual: '), + ); }); test('isNotEmpty', () { shouldFail('', isNotEmpty, startsWith("Expected: non-empty Actual: ''")); shouldFail( - null, isNotEmpty, startsWith('Expected: non-empty Actual: ')); + null, + isNotEmpty, + startsWith('Expected: non-empty Actual: '), + ); shouldFail(0, isNotEmpty, startsWith('Expected: non-empty Actual: <0>')); shouldPass('a', isNotEmpty); }); test('equalsIgnoringCase', () { shouldPass('hello', equalsIgnoringCase('HELLO')); - shouldFail('hi', equalsIgnoringCase('HELLO'), - "Expected: 'HELLO' ignoring case Actual: 'hi'"); - shouldFail(42, equalsIgnoringCase('HELLO'), - endsWith('not an ')); + shouldFail( + 'hi', + equalsIgnoringCase('HELLO'), + "Expected: 'HELLO' ignoring case Actual: 'hi'", + ); + shouldFail( + 42, + equalsIgnoringCase('HELLO'), + endsWith('not an '), + ); }); test('equalsIgnoringWhitespace', () { shouldPass(' hello world ', equalsIgnoringWhitespace('hello world')); shouldFail( - ' helloworld ', - equalsIgnoringWhitespace('hello world'), - "Expected: 'hello world' ignoring whitespace " - "Actual: ' helloworld ' " - "Which: is 'helloworld' with whitespace compressed"); - shouldFail(42, equalsIgnoringWhitespace('HELLO'), - endsWith('not an ')); + ' helloworld ', + equalsIgnoringWhitespace('hello world'), + "Expected: 'hello world' ignoring whitespace " + "Actual: ' helloworld ' " + "Which: is 'helloworld' with whitespace compressed", + ); + shouldFail( + 42, + equalsIgnoringWhitespace('HELLO'), + endsWith('not an '), + ); }); test('startsWith', () { @@ -76,12 +96,16 @@ void main() { shouldPass('hello', startsWith('hell')); shouldPass('hello', startsWith('hello')); shouldFail( - 'hello', - startsWith('hello '), - "Expected: a string starting with 'hello ' " - "Actual: 'hello'"); + 'hello', + startsWith('hello '), + "Expected: a string starting with 'hello ' " + "Actual: 'hello'", + ); shouldFail( - 42, startsWith('hello '), endsWith('not an ')); + 42, + startsWith('hello '), + endsWith('not an '), + ); }); test('endsWith', () { @@ -89,12 +113,16 @@ void main() { shouldPass('hello', endsWith('lo')); shouldPass('hello', endsWith('hello')); shouldFail( - 'hello', - endsWith(' hello'), - "Expected: a string ending with ' hello' " - "Actual: 'hello'"); + 'hello', + endsWith(' hello'), + "Expected: a string ending with ' hello' " + "Actual: 'hello'", + ); shouldFail( - 42, startsWith('hello '), endsWith('not an ')); + 42, + startsWith('hello '), + endsWith('not an '), + ); }); test('contains', () { @@ -103,8 +131,11 @@ void main() { shouldPass('hello', contains('o')); shouldPass('hello', contains('hell')); shouldPass('hello', contains('hello')); - shouldFail('hello', contains(' '), - "Expected: contains ' ' Actual: 'hello' Which: does not contain ' '"); + shouldFail( + 'hello', + contains(' '), + "Expected: contains ' ' Actual: 'hello' Which: does not contain ' '", + ); }); test('stringContainsInOrder', () { @@ -113,39 +144,58 @@ void main() { shouldPass('goodbye cruel world', stringContainsInOrder(['cruel'])); shouldPass('goodbye cruel world', stringContainsInOrder(['world'])); shouldPass( - 'goodbye cruel world', stringContainsInOrder(['good', 'bye', 'world'])); + 'goodbye cruel world', + stringContainsInOrder(['good', 'bye', 'world']), + ); + shouldPass( + 'goodbye cruel world', + stringContainsInOrder(['goodbye', 'cruel']), + ); shouldPass( - 'goodbye cruel world', stringContainsInOrder(['goodbye', 'cruel'])); + 'goodbye cruel world', + stringContainsInOrder(['cruel', 'world']), + ); shouldPass( - 'goodbye cruel world', stringContainsInOrder(['cruel', 'world'])); - shouldPass('goodbye cruel world', - stringContainsInOrder(['goodbye', 'cruel', 'world'])); + 'goodbye cruel world', + stringContainsInOrder(['goodbye', 'cruel', 'world']), + ); shouldPass( - 'foo', stringContainsInOrder(['f', '', '', '', 'o', '', '', 'o'])); + 'foo', + stringContainsInOrder(['f', '', '', '', 'o', '', '', 'o']), + ); shouldFail( - 'abc', - stringContainsInOrder(['ab', 'bc']), - "Expected: a string containing 'ab', 'bc' in order " - "Actual: 'abc'"); + 'abc', + stringContainsInOrder(['ab', 'bc']), + "Expected: a string containing 'ab', 'bc' in order " + "Actual: 'abc'", + ); shouldFail( - 'hello', - stringContainsInOrder(['hello', 'hello']), - "Expected: a string containing 'hello', 'hello' in order " - "Actual: 'hello'"); + 'hello', + stringContainsInOrder(['hello', 'hello']), + "Expected: a string containing 'hello', 'hello' in order " + "Actual: 'hello'", + ); shouldFail( - 'goodbye cruel world', - stringContainsInOrder(['goo', 'cruel', 'bye']), - "Expected: a string containing 'goo', 'cruel', 'bye' in order " - "Actual: 'goodbye cruel world'"); + 'goodbye cruel world', + stringContainsInOrder(['goo', 'cruel', 'bye']), + "Expected: a string containing 'goo', 'cruel', 'bye' in order " + "Actual: 'goodbye cruel world'", + ); }); test('matches', () { shouldPass('c0d', matches('[a-z][0-9][a-z]')); shouldPass('c0d', matches(RegExp('[a-z][0-9][a-z]'))); - shouldFail('cOd', matches('[a-z][0-9][a-z]'), - "Expected: match '[a-z][0-9][a-z]' Actual: 'cOd'"); - shouldFail(42, matches('[a-z][0-9][a-z]'), - endsWith('not an ')); + shouldFail( + 'cOd', + matches('[a-z][0-9][a-z]'), + "Expected: match '[a-z][0-9][a-z]' Actual: 'cOd'", + ); + shouldFail( + 42, + matches('[a-z][0-9][a-z]'), + endsWith('not an '), + ); }); } diff --git a/pkgs/matcher/test/type_matcher_test.dart b/pkgs/matcher/test/type_matcher_test.dart index e0ca3d877..ed656a341 100644 --- a/pkgs/matcher/test/type_matcher_test.dart +++ b/pkgs/matcher/test/type_matcher_test.dart @@ -21,8 +21,11 @@ void main() { _test(isUnsupportedError, UnsupportedError('oops')); _test(isConcurrentModificationError, ConcurrentModificationError()); _test(isCyclicInitializationError, Error()); - _test(isNoSuchMethodError, null, - name: 'NoSuchMethodError'); + _test( + isNoSuchMethodError, + null, + name: 'NoSuchMethodError', + ); _test(isNullThrownError, TypeError()); group('custom `TypeMatcher`', () { From 0c1feef0e6c1342725bc812c131dbe7508cff2ff Mon Sep 17 00:00:00 2001 From: Nate Bosch Date: Wed, 23 Jul 2025 02:13:20 +0000 Subject: [PATCH 11/11] Fix lints in matcher --- pkgs/matcher/lib/src/expect/prints_matcher.dart | 2 +- pkgs/matcher/lib/src/expect/stream_matcher.dart | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/pkgs/matcher/lib/src/expect/prints_matcher.dart b/pkgs/matcher/lib/src/expect/prints_matcher.dart index 3008cc672..2ffbeb210 100644 --- a/pkgs/matcher/lib/src/expect/prints_matcher.dart +++ b/pkgs/matcher/lib/src/expect/prints_matcher.dart @@ -39,7 +39,7 @@ class _Prints extends AsyncMatcher { var result = runZoned( item, zoneSpecification: ZoneSpecification( - print: (_, __, ____, line) { + print: (_, _, _, line) { buffer.writeln(line); }, ), diff --git a/pkgs/matcher/lib/src/expect/stream_matcher.dart b/pkgs/matcher/lib/src/expect/stream_matcher.dart index 93b98fe77..bd62b315b 100644 --- a/pkgs/matcher/lib/src/expect/stream_matcher.dart +++ b/pkgs/matcher/lib/src/expect/stream_matcher.dart @@ -143,15 +143,15 @@ class _StreamMatcher extends AsyncMatcher implements StreamMatcher { return matchQueue(copy) .then( (result) async { - // Accept the transaction if the result is null, indicating that the match - // succeeded. + // Accept the transaction if the result is null, indicating that the + // match succeeded. if (result == null) { transaction.commit(copy); return null; } - // Get a list of events emitted by the stream so we can emit them as part - // of the error message. + // Get a list of events emitted by the stream so we can emit them as + // part of the error message. var replay = transaction.newQueue(); var events = []; var subscription = Result.captureStreamTransformer @@ -184,8 +184,9 @@ class _StreamMatcher extends AsyncMatcher implements StreamMatcher { var buffer = StringBuffer(); buffer.writeln(indent(eventsString, first: 'emitted ')); - if (result.isNotEmpty) + if (result.isNotEmpty) { buffer.writeln(indent(result, first: ' which ')); + } return buffer.toString().trimRight(); }, onError: (Object error) {