diff --git a/.github/labeler.yml b/.github/labeler.yml index b8727694f8..95a9ad7ab3 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -6,7 +6,7 @@ 'package:dwds': - changed-files: - - any-glob-to-any-file: 'dwds/**/*' + - any-glob-to-any-file: 'dwds_webdev_integration_test/**/*' 'package:frontend_server_client': - changed-files: @@ -18,4 +18,4 @@ 'dart-debug-extension': - changed-files: - - any-glob-to-any-file: 'dwds/debug_extension/**/*' + - any-glob-to-any-file: 'debug_extension/**/*' diff --git a/.github/workflows/daily_testing.yml b/.github/workflows/daily_testing.yml index 7d314a705d..0d3d25bfa8 100644 --- a/.github/workflows/daily_testing.yml +++ b/.github/workflows/daily_testing.yml @@ -6,6 +6,9 @@ on: schedule: - cron: "00 14 * * *" # Everyday at 3:00 PM UTC (8:00 AM PST) +permissions: + contents: read + jobs: daily_testing: name: Daily Testing @@ -18,20 +21,20 @@ jobs: - id: checkout name: Checkout repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd - - id: dwds_pub_upgrade - name: dwds; dart pub upgrade + - id: dwds_webdev_integration_test_pub_upgrade + name: dwds_webdev_integration_test; dart pub upgrade run: dart pub upgrade if: "always() && steps.checkout.conclusion == 'success'" - working-directory: dwds - - name: dwds; dart analyze . + working-directory: dwds_webdev_integration_test + - name: dwds_webdev_integration_test; dart analyze . run: dart analyze . - if: "always() && steps.dwds_pub_upgrade.conclusion == 'success'" - working-directory: dwds - - id: dwds_daily_tests - name: "dwds; dart test --tags=daily" + if: "always() && steps.dwds_webdev_integration_test_pub_upgrade.conclusion == 'success'" + working-directory: dwds_webdev_integration_test + - id: dwds_webdev_integration_test_daily_tests + name: "dwds_webdev_integration_test; dart test --tags=daily" run: "dart test --tags=daily" - if: "always() && steps.dwds_pub_upgrade.conclusion == 'success'" - working-directory: dwds + if: "always() && steps.dwds_webdev_integration_test_pub_upgrade.conclusion == 'success'" + working-directory: dwds_webdev_integration_test - id: webdev_pub_upgrade name: webdev; dart pub upgrade run: dart pub upgrade @@ -47,7 +50,7 @@ jobs: if: "always() && steps.webdev_pub_upgrade.conclusion == 'success'" working-directory: webdev - name: "Notify failure" - if: "always() && steps.dwds_daily_tests.conclusion == 'failure' || steps.webdev_daily_tests.conclusion == 'failure'" + if: "always() && (steps.dwds_webdev_integration_test_daily_tests.conclusion == 'failure' || steps.webdev_daily_tests.conclusion == 'failure')" run: | curl -H "Content-Type: application/json" -X POST -d \ "{'text':'Daily Webdev tests failed! ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}'}" \ diff --git a/.github/workflows/dart.yml b/.github/workflows/dart.yml index fc8c20ce2d..7b14f65a3a 100644 --- a/.github/workflows/dart.yml +++ b/.github/workflows/dart.yml @@ -9,9 +9,7 @@ on: - .github/workflows/dart.yml - mono_repo.yaml - "**/mono_pkg.yaml" - - "dwds/**" - - "dwds_test_common/**" - - "dwds_test_common/fixtures/_webdev_smoke/**" + - "dwds_webdev_integration_test/**" - "example/**" - "frontend_server_client/**" - "webdev/**" @@ -21,9 +19,7 @@ on: - .github/workflows/dart.yml - mono_repo.yaml - "**/mono_pkg.yaml" - - "dwds/**" - - "dwds_test_common/**" - - "dwds_test_common/fixtures/_webdev_smoke/**" + - "dwds_webdev_integration_test/**" - "example/**" - "frontend_server_client/**" - "webdev/**" @@ -66,16 +62,16 @@ jobs: - name: mono_repo self validate run: dart pub global run mono_repo generate --validate job_002: - name: "analyzer_and_format; linux; Dart dev; PKG: dwds; `dart format --output=none --set-exit-if-changed .`, `dart analyze --fatal-infos .`, `dart test test/build/ensure_version_test.dart`" + name: "analyzer_and_format; linux; Dart dev; PKGS: dwds_webdev_integration_test, example, frontend_server_client; `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@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:dwds;commands:format-analyze_0-test_0" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:dwds_webdev_integration_test-example-frontend_server_client;commands:format-analyze_0" restore-keys: |- - os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:dwds + os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:dwds_webdev_integration_test-example-frontend_server_client os:ubuntu-latest;pub-cache-hosted;sdk:dev os:ubuntu-latest;pub-cache-hosted os:ubuntu-latest @@ -88,72 +84,19 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd with: persist-credentials: false - - id: dwds_pub_upgrade - name: dwds; dart pub upgrade + - id: dwds_webdev_integration_test_pub_upgrade + name: dwds_webdev_integration_test; dart pub upgrade run: dart pub upgrade if: "always() && steps.checkout.conclusion == 'success'" - working-directory: dwds - - name: "dwds; dart format --output=none --set-exit-if-changed ." + working-directory: dwds_webdev_integration_test + - name: "dwds_webdev_integration_test; dart format --output=none --set-exit-if-changed ." run: "dart format --output=none --set-exit-if-changed ." - if: "always() && steps.dwds_pub_upgrade.conclusion == 'success'" - working-directory: dwds - - name: "dwds; dart analyze --fatal-infos ." + if: "always() && steps.dwds_webdev_integration_test_pub_upgrade.conclusion == 'success'" + working-directory: dwds_webdev_integration_test + - name: "dwds_webdev_integration_test; dart analyze --fatal-infos ." run: dart analyze --fatal-infos . - if: "always() && steps.dwds_pub_upgrade.conclusion == 'success'" - working-directory: dwds - - name: dwds; dart test test/build/ensure_version_test.dart - run: dart test test/build/ensure_version_test.dart - if: "always() && steps.dwds_pub_upgrade.conclusion == 'success'" - working-directory: dwds - job_003: - name: "analyzer_and_format; linux; Dart dev; PKGS: dwds_test_common, dwds_test_common/fixtures/_webdev_smoke, example, frontend_server_client; `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@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 - with: - path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:dwds_test_common-dwds_test_common/fixtures/_webdev_smoke-example-frontend_server_client;commands:format-analyze_0" - restore-keys: |- - os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:dwds_test_common-dwds_test_common/fixtures/_webdev_smoke-example-frontend_server_client - os:ubuntu-latest;pub-cache-hosted;sdk:dev - os:ubuntu-latest;pub-cache-hosted - os:ubuntu-latest - - name: Setup Dart SDK - uses: dart-lang/setup-dart@e51d8e571e22473a2ddebf0ef8a2123f0ab2c02c - with: - sdk: dev - - id: checkout - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd - with: - persist-credentials: false - - id: dwds_test_common_pub_upgrade - name: dwds_test_common; dart pub upgrade - run: dart pub upgrade - if: "always() && steps.checkout.conclusion == 'success'" - working-directory: dwds_test_common - - name: "dwds_test_common; dart format --output=none --set-exit-if-changed ." - run: "dart format --output=none --set-exit-if-changed ." - if: "always() && steps.dwds_test_common_pub_upgrade.conclusion == 'success'" - working-directory: dwds_test_common - - name: "dwds_test_common; dart analyze --fatal-infos ." - run: dart analyze --fatal-infos . - if: "always() && steps.dwds_test_common_pub_upgrade.conclusion == 'success'" - working-directory: dwds_test_common - - id: dwds_test_common_fixtures__webdev_smoke_pub_upgrade - name: dwds_test_common/fixtures/_webdev_smoke; dart pub upgrade - run: dart pub upgrade - if: "always() && steps.checkout.conclusion == 'success'" - working-directory: dwds_test_common/fixtures/_webdev_smoke - - name: "dwds_test_common/fixtures/_webdev_smoke; dart format --output=none --set-exit-if-changed ." - run: "dart format --output=none --set-exit-if-changed ." - if: "always() && steps.dwds_test_common_fixtures__webdev_smoke_pub_upgrade.conclusion == 'success'" - working-directory: dwds_test_common/fixtures/_webdev_smoke - - name: "dwds_test_common/fixtures/_webdev_smoke; dart analyze --fatal-infos ." - run: dart analyze --fatal-infos . - if: "always() && steps.dwds_test_common_fixtures__webdev_smoke_pub_upgrade.conclusion == 'success'" - working-directory: dwds_test_common/fixtures/_webdev_smoke + if: "always() && steps.dwds_webdev_integration_test_pub_upgrade.conclusion == 'success'" + working-directory: dwds_webdev_integration_test - id: example_pub_upgrade name: example; dart pub upgrade run: dart pub upgrade @@ -180,7 +123,7 @@ jobs: run: dart analyze --fatal-infos . if: "always() && steps.frontend_server_client_pub_upgrade.conclusion == 'success'" working-directory: frontend_server_client - job_004: + job_003: name: "analyzer_and_format; linux; Dart dev; PKG: webdev; `dart format --output=none --set-exit-if-changed .`, `dart analyze --fatal-infos .`, `dart test test/build/ensure_build_test.dart`" runs-on: ubuntu-latest steps: @@ -188,7 +131,7 @@ jobs: uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:webdev;commands:format-analyze_0-test_7" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:webdev;commands:format-analyze_0-test_5" restore-keys: |- os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:webdev os:ubuntu-latest;pub-cache-hosted;sdk:dev @@ -220,17 +163,17 @@ jobs: run: dart test test/build/ensure_build_test.dart if: "always() && steps.webdev_pub_upgrade.conclusion == 'success'" working-directory: webdev - job_005: - name: "unit_test; linux; Dart dev; PKG: dwds; `Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &`, `dart test --tags=extension`" + job_004: + name: "unit_test; linux; Dart dev; PKG: dwds_webdev_integration_test; `Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &`, `dart test --tags=extension`" runs-on: ubuntu-latest steps: - name: Cache Pub hosted dependencies uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:dwds;commands:command-test_1" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:dwds_webdev_integration_test;commands:command-test_0" restore-keys: |- - os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:dwds + os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:dwds_webdev_integration_test os:ubuntu-latest;pub-cache-hosted;sdk:dev os:ubuntu-latest;pub-cache-hosted os:ubuntu-latest @@ -243,35 +186,34 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd with: persist-credentials: false - - id: dwds_pub_upgrade - name: dwds; dart pub upgrade + - id: dwds_webdev_integration_test_pub_upgrade + name: dwds_webdev_integration_test; dart pub upgrade run: dart pub upgrade if: "always() && steps.checkout.conclusion == 'success'" - working-directory: dwds - - name: "dwds; Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &" + working-directory: dwds_webdev_integration_test + - name: "dwds_webdev_integration_test; Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &" run: "Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &" - if: "always() && steps.dwds_pub_upgrade.conclusion == 'success'" - working-directory: dwds - - name: "dwds; dart test --tags=extension" + if: "always() && steps.dwds_webdev_integration_test_pub_upgrade.conclusion == 'success'" + working-directory: dwds_webdev_integration_test + - name: "dwds_webdev_integration_test; dart test --tags=extension" run: "dart test --tags=extension" - if: "always() && steps.dwds_pub_upgrade.conclusion == 'success'" - working-directory: dwds + if: "always() && steps.dwds_webdev_integration_test_pub_upgrade.conclusion == 'success'" + working-directory: dwds_webdev_integration_test needs: - job_001 - job_002 - job_003 - - job_004 - job_006: - name: "unit_test; linux; Dart dev; PKG: dwds; `dart test --total-shards 3 --shard-index 0 --exclude-tags=extension`" + job_005: + name: "unit_test; linux; Dart dev; PKG: dwds_webdev_integration_test; `dart test --total-shards 3 --shard-index 0 --exclude-tags=extension`" runs-on: ubuntu-latest steps: - name: Cache Pub hosted dependencies uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:dwds;commands:test_2" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:dwds_webdev_integration_test;commands:test_1" restore-keys: |- - os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:dwds + os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:dwds_webdev_integration_test os:ubuntu-latest;pub-cache-hosted;sdk:dev os:ubuntu-latest;pub-cache-hosted os:ubuntu-latest @@ -284,31 +226,30 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd with: persist-credentials: false - - id: dwds_pub_upgrade - name: dwds; dart pub upgrade + - id: dwds_webdev_integration_test_pub_upgrade + name: dwds_webdev_integration_test; dart pub upgrade run: dart pub upgrade if: "always() && steps.checkout.conclusion == 'success'" - working-directory: dwds - - name: "dwds; dart test --total-shards 3 --shard-index 0 --exclude-tags=extension" + working-directory: dwds_webdev_integration_test + - name: "dwds_webdev_integration_test; dart test --total-shards 3 --shard-index 0 --exclude-tags=extension" run: "dart test --total-shards 3 --shard-index 0 --exclude-tags=extension" - if: "always() && steps.dwds_pub_upgrade.conclusion == 'success'" - working-directory: dwds + if: "always() && steps.dwds_webdev_integration_test_pub_upgrade.conclusion == 'success'" + working-directory: dwds_webdev_integration_test needs: - job_001 - job_002 - job_003 - - job_004 - job_007: - name: "unit_test; linux; Dart dev; PKG: dwds; `dart test --total-shards 3 --shard-index 1 --exclude-tags=extension`" + job_006: + name: "unit_test; linux; Dart dev; PKG: dwds_webdev_integration_test; `dart test --total-shards 3 --shard-index 1 --exclude-tags=extension`" runs-on: ubuntu-latest steps: - name: Cache Pub hosted dependencies uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:dwds;commands:test_3" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:dwds_webdev_integration_test;commands:test_2" restore-keys: |- - os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:dwds + os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:dwds_webdev_integration_test os:ubuntu-latest;pub-cache-hosted;sdk:dev os:ubuntu-latest;pub-cache-hosted os:ubuntu-latest @@ -321,31 +262,30 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd with: persist-credentials: false - - id: dwds_pub_upgrade - name: dwds; dart pub upgrade + - id: dwds_webdev_integration_test_pub_upgrade + name: dwds_webdev_integration_test; dart pub upgrade run: dart pub upgrade if: "always() && steps.checkout.conclusion == 'success'" - working-directory: dwds - - name: "dwds; dart test --total-shards 3 --shard-index 1 --exclude-tags=extension" + working-directory: dwds_webdev_integration_test + - name: "dwds_webdev_integration_test; dart test --total-shards 3 --shard-index 1 --exclude-tags=extension" run: "dart test --total-shards 3 --shard-index 1 --exclude-tags=extension" - if: "always() && steps.dwds_pub_upgrade.conclusion == 'success'" - working-directory: dwds + if: "always() && steps.dwds_webdev_integration_test_pub_upgrade.conclusion == 'success'" + working-directory: dwds_webdev_integration_test needs: - job_001 - job_002 - job_003 - - job_004 - job_008: - name: "unit_test; linux; Dart dev; PKG: dwds; `dart test --total-shards 3 --shard-index 2 --exclude-tags=extension`" + job_007: + name: "unit_test; linux; Dart dev; PKG: dwds_webdev_integration_test; `dart test --total-shards 3 --shard-index 2 --exclude-tags=extension`" runs-on: ubuntu-latest steps: - name: Cache Pub hosted dependencies uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:dwds;commands:test_4" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:dwds_webdev_integration_test;commands:test_3" restore-keys: |- - os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:dwds + os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:dwds_webdev_integration_test os:ubuntu-latest;pub-cache-hosted;sdk:dev os:ubuntu-latest;pub-cache-hosted os:ubuntu-latest @@ -358,62 +298,20 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd with: persist-credentials: false - - id: dwds_pub_upgrade - name: dwds; dart pub upgrade + - id: dwds_webdev_integration_test_pub_upgrade + name: dwds_webdev_integration_test; dart pub upgrade run: dart pub upgrade if: "always() && steps.checkout.conclusion == 'success'" - working-directory: dwds - - name: "dwds; dart test --total-shards 3 --shard-index 2 --exclude-tags=extension" + working-directory: dwds_webdev_integration_test + - name: "dwds_webdev_integration_test; dart test --total-shards 3 --shard-index 2 --exclude-tags=extension" run: "dart test --total-shards 3 --shard-index 2 --exclude-tags=extension" - if: "always() && steps.dwds_pub_upgrade.conclusion == 'success'" - working-directory: dwds + if: "always() && steps.dwds_webdev_integration_test_pub_upgrade.conclusion == 'success'" + working-directory: dwds_webdev_integration_test needs: - job_001 - job_002 - job_003 - - job_004 - job_009: - name: "unit_test; linux; Dart dev; PKG: dwds_test_common; `Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &`, `dart test --exclude-tags=release`" - runs-on: ubuntu-latest - steps: - - name: Cache Pub hosted dependencies - uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 - with: - path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:dwds_test_common;commands:command-test_6" - restore-keys: |- - os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:dwds_test_common - os:ubuntu-latest;pub-cache-hosted;sdk:dev - os:ubuntu-latest;pub-cache-hosted - os:ubuntu-latest - - name: Setup Dart SDK - uses: dart-lang/setup-dart@e51d8e571e22473a2ddebf0ef8a2123f0ab2c02c - with: - sdk: dev - - id: checkout - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd - with: - persist-credentials: false - - id: dwds_test_common_pub_upgrade - name: dwds_test_common; dart pub upgrade - run: dart pub upgrade - if: "always() && steps.checkout.conclusion == 'success'" - working-directory: dwds_test_common - - name: "dwds_test_common; Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &" - run: "Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &" - if: "always() && steps.dwds_test_common_pub_upgrade.conclusion == 'success'" - working-directory: dwds_test_common - - name: "dwds_test_common; dart test --exclude-tags=release" - run: "dart test --exclude-tags=release" - if: "always() && steps.dwds_test_common_pub_upgrade.conclusion == 'success'" - working-directory: dwds_test_common - needs: - - job_001 - - job_002 - - job_003 - - job_004 - job_010: + job_008: name: "unit_test; linux; Dart dev; PKG: frontend_server_client; `dart test -j 1`" runs-on: ubuntu-latest steps: @@ -421,7 +319,7 @@ jobs: uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:frontend_server_client;commands:test_5" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:frontend_server_client;commands:test_4" restore-keys: |- os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:frontend_server_client os:ubuntu-latest;pub-cache-hosted;sdk:dev @@ -449,8 +347,7 @@ jobs: - job_001 - job_002 - job_003 - - job_004 - job_011: + job_009: name: "unit_test; linux; Dart dev; PKG: webdev; `Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &`, `dart test -j 1`" runs-on: ubuntu-latest steps: @@ -458,7 +355,7 @@ jobs: uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:webdev;commands:command-test_5" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:webdev;commands:command-test_4" restore-keys: |- os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:webdev os:ubuntu-latest;pub-cache-hosted;sdk:dev @@ -490,9 +387,8 @@ jobs: - job_001 - job_002 - job_003 - - job_004 - job_012: - name: "unit_test; windows; Dart dev; PKG: dwds; `dart test --tags=extension`" + job_010: + name: "unit_test; windows; Dart dev; PKG: dwds_webdev_integration_test; `dart test --tags=extension`" runs-on: windows-latest steps: - name: Setup Dart SDK @@ -504,22 +400,21 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd with: persist-credentials: false - - id: dwds_pub_upgrade - name: dwds; dart pub upgrade + - id: dwds_webdev_integration_test_pub_upgrade + name: dwds_webdev_integration_test; dart pub upgrade run: dart pub upgrade if: "always() && steps.checkout.conclusion == 'success'" - working-directory: dwds - - name: "dwds; dart test --tags=extension" + working-directory: dwds_webdev_integration_test + - name: "dwds_webdev_integration_test; dart test --tags=extension" run: "dart test --tags=extension" - if: "always() && steps.dwds_pub_upgrade.conclusion == 'success'" - working-directory: dwds + if: "always() && steps.dwds_webdev_integration_test_pub_upgrade.conclusion == 'success'" + working-directory: dwds_webdev_integration_test needs: - job_001 - job_002 - job_003 - - job_004 - job_013: - name: "unit_test; windows; Dart dev; PKG: dwds; `dart test --total-shards 3 --shard-index 0 --exclude-tags=extension`" + job_011: + name: "unit_test; windows; Dart dev; PKG: dwds_webdev_integration_test; `dart test --total-shards 3 --shard-index 0 --exclude-tags=extension`" runs-on: windows-latest steps: - name: Setup Dart SDK @@ -531,22 +426,21 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd with: persist-credentials: false - - id: dwds_pub_upgrade - name: dwds; dart pub upgrade + - id: dwds_webdev_integration_test_pub_upgrade + name: dwds_webdev_integration_test; dart pub upgrade run: dart pub upgrade if: "always() && steps.checkout.conclusion == 'success'" - working-directory: dwds - - name: "dwds; dart test --total-shards 3 --shard-index 0 --exclude-tags=extension" + working-directory: dwds_webdev_integration_test + - name: "dwds_webdev_integration_test; dart test --total-shards 3 --shard-index 0 --exclude-tags=extension" run: "dart test --total-shards 3 --shard-index 0 --exclude-tags=extension" - if: "always() && steps.dwds_pub_upgrade.conclusion == 'success'" - working-directory: dwds + if: "always() && steps.dwds_webdev_integration_test_pub_upgrade.conclusion == 'success'" + working-directory: dwds_webdev_integration_test needs: - job_001 - job_002 - job_003 - - job_004 - job_014: - name: "unit_test; windows; Dart dev; PKG: dwds; `dart test --total-shards 3 --shard-index 1 --exclude-tags=extension`" + job_012: + name: "unit_test; windows; Dart dev; PKG: dwds_webdev_integration_test; `dart test --total-shards 3 --shard-index 1 --exclude-tags=extension`" runs-on: windows-latest steps: - name: Setup Dart SDK @@ -558,22 +452,21 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd with: persist-credentials: false - - id: dwds_pub_upgrade - name: dwds; dart pub upgrade + - id: dwds_webdev_integration_test_pub_upgrade + name: dwds_webdev_integration_test; dart pub upgrade run: dart pub upgrade if: "always() && steps.checkout.conclusion == 'success'" - working-directory: dwds - - name: "dwds; dart test --total-shards 3 --shard-index 1 --exclude-tags=extension" + working-directory: dwds_webdev_integration_test + - name: "dwds_webdev_integration_test; dart test --total-shards 3 --shard-index 1 --exclude-tags=extension" run: "dart test --total-shards 3 --shard-index 1 --exclude-tags=extension" - if: "always() && steps.dwds_pub_upgrade.conclusion == 'success'" - working-directory: dwds + if: "always() && steps.dwds_webdev_integration_test_pub_upgrade.conclusion == 'success'" + working-directory: dwds_webdev_integration_test needs: - job_001 - job_002 - job_003 - - job_004 - job_015: - name: "unit_test; windows; Dart dev; PKG: dwds; `dart test --total-shards 3 --shard-index 2 --exclude-tags=extension`" + job_013: + name: "unit_test; windows; Dart dev; PKG: dwds_webdev_integration_test; `dart test --total-shards 3 --shard-index 2 --exclude-tags=extension`" runs-on: windows-latest steps: - name: Setup Dart SDK @@ -585,48 +478,20 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd with: persist-credentials: false - - id: dwds_pub_upgrade - name: dwds; dart pub upgrade + - id: dwds_webdev_integration_test_pub_upgrade + name: dwds_webdev_integration_test; dart pub upgrade run: dart pub upgrade if: "always() && steps.checkout.conclusion == 'success'" - working-directory: dwds - - name: "dwds; dart test --total-shards 3 --shard-index 2 --exclude-tags=extension" + working-directory: dwds_webdev_integration_test + - name: "dwds_webdev_integration_test; dart test --total-shards 3 --shard-index 2 --exclude-tags=extension" run: "dart test --total-shards 3 --shard-index 2 --exclude-tags=extension" - if: "always() && steps.dwds_pub_upgrade.conclusion == 'success'" - working-directory: dwds - needs: - - job_001 - - job_002 - - job_003 - - job_004 - job_016: - name: "unit_test; windows; Dart dev; PKG: dwds_test_common; `dart test --exclude-tags=release`" - runs-on: windows-latest - steps: - - name: Setup Dart SDK - uses: dart-lang/setup-dart@e51d8e571e22473a2ddebf0ef8a2123f0ab2c02c - with: - sdk: dev - - id: checkout - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd - with: - persist-credentials: false - - id: dwds_test_common_pub_upgrade - name: dwds_test_common; dart pub upgrade - run: dart pub upgrade - if: "always() && steps.checkout.conclusion == 'success'" - working-directory: dwds_test_common - - name: "dwds_test_common; dart test --exclude-tags=release" - run: "dart test --exclude-tags=release" - if: "always() && steps.dwds_test_common_pub_upgrade.conclusion == 'success'" - working-directory: dwds_test_common + if: "always() && steps.dwds_webdev_integration_test_pub_upgrade.conclusion == 'success'" + working-directory: dwds_webdev_integration_test needs: - job_001 - job_002 - job_003 - - job_004 - job_017: + job_014: name: "unit_test; windows; Dart dev; PKG: frontend_server_client; `dart test -j 1`" runs-on: windows-latest steps: @@ -652,8 +517,7 @@ jobs: - job_001 - job_002 - job_003 - - job_004 - job_018: + job_015: name: "unit_test; windows; Dart dev; PKG: webdev; `dart test -j 1`" runs-on: windows-latest steps: @@ -679,9 +543,8 @@ jobs: - job_001 - job_002 - job_003 - - job_004 - job_019: - name: "beta_cron; linux; Dart beta; PKG: dwds; `Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &`, `dart test -j 1`" + job_016: + name: "beta_cron; linux; Dart beta; PKG: dwds_webdev_integration_test; `Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &`, `dart test -j 1`" runs-on: ubuntu-latest if: "github.event_name == 'schedule'" steps: @@ -689,9 +552,9 @@ jobs: uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:beta;packages:dwds;commands:command-test_5" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:beta;packages:dwds_webdev_integration_test;commands:command-test_4" restore-keys: |- - os:ubuntu-latest;pub-cache-hosted;sdk:beta;packages:dwds + os:ubuntu-latest;pub-cache-hosted;sdk:beta;packages:dwds_webdev_integration_test os:ubuntu-latest;pub-cache-hosted;sdk:beta os:ubuntu-latest;pub-cache-hosted os:ubuntu-latest @@ -704,19 +567,19 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd with: persist-credentials: false - - id: dwds_pub_upgrade - name: dwds; dart pub upgrade + - id: dwds_webdev_integration_test_pub_upgrade + name: dwds_webdev_integration_test; dart pub upgrade run: dart pub upgrade if: "always() && steps.checkout.conclusion == 'success'" - working-directory: dwds - - name: "dwds; Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &" + working-directory: dwds_webdev_integration_test + - name: "dwds_webdev_integration_test; Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &" run: "Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &" - if: "always() && steps.dwds_pub_upgrade.conclusion == 'success'" - working-directory: dwds - - name: "dwds; dart test -j 1" + if: "always() && steps.dwds_webdev_integration_test_pub_upgrade.conclusion == 'success'" + working-directory: dwds_webdev_integration_test + - name: "dwds_webdev_integration_test; dart test -j 1" run: dart test -j 1 - if: "always() && steps.dwds_pub_upgrade.conclusion == 'success'" - working-directory: dwds + if: "always() && steps.dwds_webdev_integration_test_pub_upgrade.conclusion == 'success'" + working-directory: dwds_webdev_integration_test needs: - job_001 - job_002 @@ -733,10 +596,7 @@ jobs: - job_013 - job_014 - job_015 - - job_016 - - job_017 - - job_018 - job_020: + job_017: name: "beta_cron; linux; Dart beta; PKG: webdev; `Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &`, `dart test -j 1`" runs-on: ubuntu-latest if: "github.event_name == 'schedule'" @@ -745,7 +605,7 @@ jobs: uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:beta;packages:webdev;commands:command-test_5" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:beta;packages:webdev;commands:command-test_4" restore-keys: |- os:ubuntu-latest;pub-cache-hosted;sdk:beta;packages:webdev os:ubuntu-latest;pub-cache-hosted;sdk:beta @@ -789,11 +649,8 @@ jobs: - job_013 - job_014 - job_015 - - job_016 - - job_017 - - job_018 - job_021: - name: "beta_cron; linux; Dart beta; PKG: dwds; `dart analyze .`" + job_018: + name: "beta_cron; linux; Dart beta; PKG: dwds_webdev_integration_test; `dart analyze .`" runs-on: ubuntu-latest if: "github.event_name == 'schedule'" steps: @@ -801,9 +658,9 @@ jobs: uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:beta;packages:dwds;commands:analyze_1" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:beta;packages:dwds_webdev_integration_test;commands:analyze_1" restore-keys: |- - os:ubuntu-latest;pub-cache-hosted;sdk:beta;packages:dwds + os:ubuntu-latest;pub-cache-hosted;sdk:beta;packages:dwds_webdev_integration_test os:ubuntu-latest;pub-cache-hosted;sdk:beta os:ubuntu-latest;pub-cache-hosted os:ubuntu-latest @@ -816,15 +673,15 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd with: persist-credentials: false - - id: dwds_pub_upgrade - name: dwds; dart pub upgrade + - id: dwds_webdev_integration_test_pub_upgrade + name: dwds_webdev_integration_test; dart pub upgrade run: dart pub upgrade if: "always() && steps.checkout.conclusion == 'success'" - working-directory: dwds - - name: dwds; dart analyze . + working-directory: dwds_webdev_integration_test + - name: dwds_webdev_integration_test; dart analyze . run: dart analyze . - if: "always() && steps.dwds_pub_upgrade.conclusion == 'success'" - working-directory: dwds + if: "always() && steps.dwds_webdev_integration_test_pub_upgrade.conclusion == 'success'" + working-directory: dwds_webdev_integration_test needs: - job_001 - job_002 @@ -841,10 +698,7 @@ jobs: - job_013 - job_014 - job_015 - - job_016 - - job_017 - - job_018 - job_022: + job_019: name: "beta_cron; linux; Dart beta; PKG: webdev; `dart analyze .`" runs-on: ubuntu-latest if: "github.event_name == 'schedule'" @@ -893,11 +747,8 @@ jobs: - job_013 - job_014 - job_015 - - job_016 - - job_017 - - job_018 - job_023: - name: "beta_cron; windows; Dart beta; PKG: dwds; `dart test -j 1`" + job_020: + name: "beta_cron; windows; Dart beta; PKG: dwds_webdev_integration_test; `dart test -j 1`" runs-on: windows-latest if: "github.event_name == 'schedule'" steps: @@ -910,15 +761,15 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd with: persist-credentials: false - - id: dwds_pub_upgrade - name: dwds; dart pub upgrade + - id: dwds_webdev_integration_test_pub_upgrade + name: dwds_webdev_integration_test; dart pub upgrade run: dart pub upgrade if: "always() && steps.checkout.conclusion == 'success'" - working-directory: dwds - - name: "dwds; dart test -j 1" + working-directory: dwds_webdev_integration_test + - name: "dwds_webdev_integration_test; dart test -j 1" run: dart test -j 1 - if: "always() && steps.dwds_pub_upgrade.conclusion == 'success'" - working-directory: dwds + if: "always() && steps.dwds_webdev_integration_test_pub_upgrade.conclusion == 'success'" + working-directory: dwds_webdev_integration_test needs: - job_001 - job_002 @@ -935,10 +786,7 @@ jobs: - job_013 - job_014 - job_015 - - job_016 - - job_017 - - job_018 - job_024: + job_021: name: "beta_cron; windows; Dart beta; PKG: webdev; `dart test -j 1`" runs-on: windows-latest if: "github.event_name == 'schedule'" @@ -977,10 +825,7 @@ jobs: - job_013 - job_014 - job_015 - - job_016 - - job_017 - - job_018 - job_025: + job_022: name: Notify failure runs-on: ubuntu-latest if: "(github.event_name == 'push' || github.event_name == 'schedule') && failure()" @@ -1013,6 +858,3 @@ jobs: - job_019 - job_020 - job_021 - - job_022 - - job_023 - - job_024 diff --git a/.github/workflows/dcm.yml b/.github/workflows/dcm.yml deleted file mode 100644 index 0ff2405f1b..0000000000 --- a/.github/workflows/dcm.yml +++ /dev/null @@ -1,40 +0,0 @@ -# A CI workflow to run the Dart Code Metrics analyzer (https://dcm.dev). - -name: Dart Code Metrics - -on: - pull_request: - types: [synchronize, opened, reopened] - branches: - - dev - -jobs: - dcm: - name: Dart Code Metrics - runs-on: ubuntu-latest - steps: - - name: Install DCM - run: | - sudo apt-get update - wget -qO- https://dcm.dev/pgp-key.public | sudo gpg --dearmor -o /usr/share/keyrings/dcm.gpg - echo 'deb [signed-by=/usr/share/keyrings/dcm.gpg arch=amd64] https://dcm.dev/debian stable main' | sudo tee /etc/apt/sources.list.d/dart_stable.list - sudo apt-get update - sudo apt-get install dcm=1.26.0-1 # To avoid errors add `-1` (build number) to the version - sudo chmod +x /usr/bin/dcm - - name: Setup Dart SDK - uses: dart-lang/setup-dart@e51d8e571e22473a2ddebf0ef8a2123f0ab2c02c - with: - sdk: main - - id: checkout - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd - with: - ref: "${{ github.event.pull_request.head.sha }}" - - id: dwds_pub_upgrade - name: dwds; dart pub upgrade - run: dart pub upgrade - if: "always() && steps.checkout.conclusion == 'success'" - working-directory: dwds - - name: Run DCM on DWDS - run: dcm analyze lib - working-directory: dwds diff --git a/README.md b/README.md index edd4c36e70..0a01b61bf3 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,14 @@ | Package | Description | Version | |---|---|---| -| [dwds](dwds/) | A service that proxies between the Chrome debug protocol and the Dart VM service protocol. | [![pub package](https://img.shields.io/pub/v/dwds.svg)](https://pub.dev/packages/dwds) | | [frontend_server_client](frontend_server_client/) | Client code to start and interact with the frontend_server compiler from the Dart SDK. | [![pub package](https://img.shields.io/pub/v/frontend_server_client.svg)](https://pub.dev/packages/frontend_server_client) | | [webdev](webdev/) | A CLI for Dart web development. Provides an easy and consistent set of features for users and tools to build and deploy web applications with Dart. | [![pub package](https://img.shields.io/pub/v/webdev.svg)](https://pub.dev/packages/webdev) | +`package:dwds` lives in the Dart SDK at +[pkg/dwds](https://github.com/dart-lang/sdk/tree/main/pkg/dwds). +[dwds_webdev_integration_test](dwds_webdev_integration_test/) runs its +integration tests against apps built with `build_runner`. + ## Publishing automation For information about our publishing automation and release process, see diff --git a/dwds/.gitignore b/dwds/.gitignore deleted file mode 100644 index 2c38d1e91d..0000000000 --- a/dwds/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -.local-chromium -.local-chrome -lib/src/injected/client.js diff --git a/dwds/CHANGELOG.md b/dwds/CHANGELOG.md deleted file mode 100644 index 3902973170..0000000000 --- a/dwds/CHANGELOG.md +++ /dev/null @@ -1,1283 +0,0 @@ -## 27.2.0-wip - -- Add `deprecatedJsInterop` to `BuildSettings` and `CompilerOptions`. When it - is set, the expression compiler worker is started with - `--[no-]deprecated-js-interop`. This requires a Dart SDK that supports the - flag. - -## 27.1.4 - -- Fix duplicated browser tabs taking over the original tab's DWDS connection. -- Fix `PersistentWebSocket` throwing unhandled errors when writing to a - connection closed by the server. - -## 27.1.3 - -- Fix WebSocket protocol upgrade to `wss` in the DWDS injected client when served over HTTPS on non-localhost hosts. - -## 27.1.2 - -- Bump the min sdk to 3.13.0-107.0.dev. -- Internal only changes. - -- Allow package_config `3.x.x`. - -## 27.1.1 - -- Fix deserialization errors appearing in the chrome console. - Replace raw map for client ping checks with a proper `PingRequest` class and - update client deserialization handling. - -## 27.1.0 - -- Add `appName` to `DartDevelopmentServiceConfiguration`. - -## 27.0.3 - -- Fix `dartExecutable` not being correctly passed to the DebugService. - -## 27.0.2 - -- Add `dartExecutable` to `DartDevelopmentServiceConfiguration`. - -## 27.0.1 - -- Replace `package:uuid` dependency with internal `Uuid` class for generating version 4 UUIDs. -- Add DDC Library Bundle tests in `dwds/test/integration/instances`. -- Fix WebSocket reconnection hang by ensuring Dart isolate recreation when a new browser client reuses an `AppDebugServices`. -- Don't inject script loads from within DWDS when executing with build_runner + DDC Module Bundles. -- Handle out of order disconnects and reconnects. - - Update dwds to support ignoring disconnects for the SseHandler. This is - useful to prevent incorrect behavior when a disconnect event arrives after - a new connection request. -- Add sourcemap logic fixes to DDC Library Bundle + build_runner execution scheme. -- Update pathing logic for Windows and the DDC Library Bundle module system. -- Fix serialization of `HotRestartRequest` in `AppConnection`. -- Split integration tests across DDC module systems. -- Split additional tests across DDC module systems. -- Fix issue where `DebugConnection` did not complete `onDone` if `WebkitDebugger` fails to reconnect to the debugger after the connection closes. -- Fix `FormatException` in `ExtensionDebugger` by making `ExtensionEvent.fromJson` robust to missing headers and Map-typed params. -- Fix `StateError` in `DwdsInjector` during AOT execution by bundling `client.js` as a statically compiled asset. -- Report errors when an empty reloaded_sources.json is seen in the DDC Library Bundle module system. - -## 27.0.0 - -- Remove `package:built_value`, `package:built_value_generator`, and `package:built_collection` dependencies. -- Remove `serializers.dart` and `data_serializers.dart`. -- Remove `package:built_value` dependency from `ConnectFailure`, `DebugStateChange`, `DevToolsOpener`, `DevToolsUrl`, `IsolateStart`, `IsolateExit`, `DevToolsRequest`, `DevToolsResponse`, `ExtensionRequest`, `ExtensionResponse`, `ExtensionEvent`, and `BatchedEvents`; switch to standard Dart JSON serialization. -- Update `ConnectFailure`, `DebugStateChange`, `DevToolsOpener`, `DevToolsUrl`, `DevToolsRequest`, `DevToolsResponse`, `ExtensionRequest`, `ExtensionResponse`, `ExtensionEvent`, `BatchedEvents` and `DebugInfo` serialization to mimic `built_value`'s list-based format to resolve compatibility issues with the debug extension. -- Remove `build`, `build_daemon`, `build_runner`, `build_version`, `build_web_compilers`, and `pubspec_parse` dependencies, along with `build.yaml` which originally generated `client.js` using `build_runner`. `client.js` is now compiled via `dart compile js` in a new `tool/build.dart` script. -- Throw `RPCError` when providing invalid `pause_isolates_on_start` values to the Chrome Proxy Service. -- Fix deserialization of `HotRestartRequest`, `HotReloadResponse`, `HotRestartResponse`, and `ServiceExtensionResponse` in the `DevHandler`. -- Add and export `BuildRunnerDdcLibraryBundleStrategyProvider`. -- Add support for Build Runner + DDC Module Bundle in test fixtures. -- Unify `assetHandler` and `assetReader` in `BuildRunnerStrategyProviderMixin`. -- Resolve test suite flakiness for port discovery. -- Bump `build_web_compilers` to ^4.4.12. - -## 26.2.5 - -- Remove `package:built_value` dependency from `ErrorResponse` and `RegisterEvent`; switch to standard Dart JSON serialization. -- Adding retries to Chrome Proxy Service connections. - -## 26.2.4 - -- Remove `package:built_value` dependency from `DebugEvent`, `BatchedDebugEvents`, `ConnectRequest`, `RunRequest`, `DebugInfo`, `HotReloadRequest`, `HotReloadResponse`, `HotRestartRequest`, `HotRestartResponse`, `ServiceExtensionRequest`, `ServiceExtensionResponse` and `BuildResult`; switch to standard Dart JSON serialization. -- Adding guards for dwds-injected library loading for Flutter Web. - -## 26.2.3 - -- Bump `build_web_compilers` to ^4.4.1. -- Remove unused `clientFuture` arg from `DwdsVmClient` methods. -- Fix pausing starting of `main` after the hot restart. -- Updating bootstrapper for DDC library bundler module format + Frontend Server. -- Fix setting up breakpoints when handling in-app restarts with attached debugger. -- Fix issue where the web socket connections with the target application and Chrome debugger close when the computer sleeps. -- Fix setting up breakpoints when handling full reloads from attached - debugger / page refreshes. - -## 26.2.2 - -- Fix issue where isolate pause events were not reported correctly when using the web socket proxy service. - -## 26.2.1 - -- Add support for DDS APIs and serving Dart DevTools when no Chrome Debugger is available. - -## 26.2.0 - -- Add support for more service APIs over websocket connections when no Chrome Debugger is available. - -## 26.1.0 - -- `reloadSources` and `hotRestart` now throw an RPC error with `kServerError` code when `NoClientsAvailableException` is caught (no browser clients are connected), allowing tooling to detect and handle this scenario. -- `pause` now does not send a `PauseInterrupted` event in - `WebSocketProxyService` as we didn't actually pause. - -## 26.0.0 - -- Bump SDK constraint to ^3.10.0 -- Added 'scriptUri' parameter to compileExpressionToJs -- Fix an issue in `reloadSources` where a `PauseInterrupted` event was sent. - [#61560](https://github.com/dart-lang/sdk/issues/61560) -- Expose `dtdUri` via `DebugConnection`. - -## 25.1.0 - -- Added `DartDevelopmentServiceConfiguration` to allow for configuring DDS behavior. -- Added support for serving DevTools via DDS. This will become the sole method of serving - DevTools from DWDS in a future major release. -- Deprecated `spawnDds`, `ddsPort`, and `devToolsLauncher` properties in `DebugSettings`. -- Added `ddsConfiguration` to `DebugSettings`. - -## 25.0.4 - -### Bug Fixes: - -- Fix issue where `DebugService: Error serving requestsError: Unsupported operation: Cannot send Null` - would be spammed on the console. - -## 25.0.3 - -### Bug Fixes: - -- Fix issue in hot restart with the web socket where we didn't pass the reloaded - sources path, resulting in a null assertion. - -## 25.0.2 - -### Bug Fixes: - -- Fix issue where DDS would fail to initialize if DWDS already had existing - clients. - -## 25.0.1 - -### Bug Fixes: - -- Fix issue in hot restart where a hot restart with no changes followed by one - with changes, a `Future` was completed again, resulting in a crash. - -## 25.0.0 - -- Implemented hot restart over websockets with multi window support. -- Fix refresh race condition bug by adding an isolate destruction grace period. -- Update a call to the `package:shelf_web_socket` `webSocketHandler()` function. - -**Breaking changes** - -- Remove deprecated parameter `injectDebuggingSupportCode` from `Dwds.start()`. -- Remove all deprecated fields, getters, and parameters - related to the null safety compilation mode. Dart 3 only - supports [sound null safety](https://dart.dev/null-safety). -- Rename `FrontendServerDdcLibraryBundleStrategy.hotReloadSourcesUri` to - `reloadedSourcesUri`. The file that the `Uri` points to should now be updated - for both a hot restart and a hot reload. - -## 24.4.1 - -- Implemented a WebSocket-based communication protocol that provides essential developer tooling (hot reload, service extensions) when Chrome debugger access is unavailable. - [#2605](https://github.com/dart-lang/webdev/issues/2605) -- Added WebSocket-based hot reload and service extension support via new `WebSocketProxyService` class that implements VM service protocol over WebSockets. -- Enhanced `DevHandler` with `useWebSocketConnection` flag to toggle between Chrome-based and WebSocket-based communication protocols. -- Fixed an issue where we didn't wait until all scripts were parsed before - recomputing metadata on a hot reload. - -## 24.4.0 - -- Added support for breakpoint registering on a hot reload with the DDC library bundle format using PausePostRequests. -- `FrontendServerDdcLibraryBundleStrategy.hotReloadSourceUri` is now expected to also provide the reloaded modules. - -## 24.3.11 - -- Changed DWDS to always inject the client and added `useDwdsWebSocketConnection` flag to control communication protocol: when true uses socket-based implementation, when false uses Chrome-based communication protocol. -- Added WebSocket-based hot reload support: `reloadSources` in `ChromeProxyService` and `DevHandler` now handle hot reload requests and responses over WebSockets. -- Refactored the injected client to use a reusable function for handling hot reload requests and responses over WebSockets. -- Added support for breakpoint registering on a hot restart with the DDC library bundle format using PausePostRequests. - -## 24.3.10 - -- Disabled breakpoints on changed files in a hot reload. They currently do not - map to the correct locations or are broken, so disable them for now. - [#60186](https://github.com/dart-lang/sdk/issues/60186) - -## 24.3.9 - -- Renamed DWDS Injector parameter `enableDebuggingSupport` to `injectDebuggingSupportCode` for clearer intent. - -## 24.3.8 - -- Updated DWDS to include a boolean flag that enables debugging support only when set to true. [#60289](https://github.com/dart-lang/sdk/issues/60289) - -## 24.3.7 - -- The registered extension `reassemble` is now no longer called when calling - `reloadSources`. Users should call `reassemble` using `callServiceExtension`. - -- `callServiceExtension` now checks the runtime for the list of registered - service extensions. It also now throws a `RPCError` with - `RPCErrorKind.kMethodNotFound` when a service extension is not found instead - of throwing a JS evaluation error. - -## 24.3.6 - -- Bump minimum sdk version to 3.7.0 -- use 'compile js-dev' instead of directly invoking the ddc snapshot. -- `FrontendServerDdcLibraryBundleStrategy` now takes a `hotReloadSourcesUri` - parameter in order to fetch the file that contains the changed sources and - libraries instead of assuming it exists in the global `window`. - -## 24.3.5 - -- Allow clients to specify the `packageConfigPath` in `LoadStrategy` class and associated providers. - -## 24.3.4 - -- Added support for some debugging APIs with the DDC library bundle format. - [#2566](https://github.com/dart-lang/webdev/issues/2566), [#2573](https://github.com/dart-lang/webdev/issues/2573) -- Added support for hot reload using the DDC library bundle format. - -## 24.3.3 - -- Added support for some debugging APIs with the DDC library bundle format. - [#2563](https://github.com/dart-lang/webdev/issues/2563) -- Update `DCM` version to `1.26.0-1` -- Add support for hot restart using the DDC library bundle format. - -## 24.3.2 - -- Bump `package:dds` to `>=4.2.5 <6.0.0`. - -## 24.3.1 - -- Add support for binding DDS to a custom port. - -## 24.3.0 - -- Update to be forward compatible with changes to `package:shelf_web_socket`. -- Added support for some debugging APIs with the DDC library bundle format. - [#2537](https://github.com/dart-lang/webdev/issues/2537),[#2544](https://github.com/dart-lang/webdev/issues/2544),[#2548](https://github.com/dart-lang/webdev/issues/2548) -- Fix issue where batched expression evals were failing if any subexpression failed. - [#2551](https://github.com/dart-lang/webdev/issues/2551) -- Expose a partial implementation of - `FrontendServerDdcLibraryBundleStrategyProvider`. -- Update `package:vm_service_interface` to '^2.0.1'. - -## 24.2.0 - -- Consolidate `FrontendServerDdcStrategyProvider` and `FrontendServerRequireStrategyProvider` under a shared parent class. - [#2517](https://github.com/dart-lang/webdev/issues/2517) -- Remove `build_daemon_ddc_and_canary_evaluate_test`. - [2512](https://github.com/dart-lang/webdev/issues/2512) -- Replace deprecated JS code `this.__proto__` with `Object.getPrototypeOf(this)`. - [#2500](https://github.com/dart-lang/webdev/pull/2500) -- Migrate injected client code to `package:web`. - [#2491](https://github.com/dart-lang/webdev/pull/2491) -- Deprecated MetadataProvider's, CompilerOptions', SdkConfiguration's & SdkLayout's soundNullSafety. - [#2427](https://github.com/dart-lang/webdev/issues/2427) -- Add load strategy and an unimplemented hot restart strategy for DDC library - bundle format. -- Added `useModuleName` option to `MetadataProvider` to determine whether or not - to use the provided `name` in a `ModuleMetadata`. Metadata provided by DDC - when using the library bundle format does not provide a useful bundle name. -- Migrate to `package:web` v1.1.0. -- Added support for some debugging APIs with the DDC library bundle format. - [#2488](https://github.com/dart-lang/webdev/issues/2488), [#2534](https://github.com/dart-lang/webdev/issues/2534) -- Update `package:vm_service` to '>=14.2.4 <16.0.0'. -- Update `package:vm_service_interface` to '2.0.1'. - -## 24.1.0 - -- Fix bug where debugging clients are not aware of service extensions when connecting to a new web app. - [#2388](https://github.com/dart-lang/webdev/pull/2388) -- Respect the value of `pause_isolates_on_start` during page-refreshes. - [#2431](https://github.com/dart-lang/webdev/pull/2431) -- Fix issue where DAP clients wouldn't resume after a restart. - [#2441](https://github.com/dart-lang/webdev/pull/2441) -- Add implementation for the VM Service's `getFlagList` API. - [#2438](https://github.com/dart-lang/webdev/pull/2438) -- Hide more variables from the local scope when debugging. These variables were synthetically added by the compiler to - support late local variables and don't appear in the original source code. - [#2445](https://github.com/dart-lang/webdev/pull/2445) -- Spawn DDS in a separate process using `dart development-service` instead of launching from `package:dds`. - [#2466](https://github.com/dart-lang/webdev/pull/2466) -- Update package `web_socket_channel: '>=2.2.0 <4.0.0'`. -- Require Dart `^3.4` -- Prepare to update `package:vm_service_interface` constraint to `2.0.0`. - -## 24.0.0 - -- Implement `setFlag` when it is called with `pause_isolates_on_start`. - [#2373](https://github.com/dart-lang/webdev/pull/2373) -- Do not persist breakpoints across hot restarts or page reloads. - [#2371](https://github.com/dart-lang/webdev/pull/2371) -- If `pause_isolates_on_start` is `true`, wait for `resume` to run the app's `main` method. - [#2378](https://github.com/dart-lang/webdev/pull/2378) -- Fix bug where setting breakpoints in a project using macros would fail. - [#2403](https://github.com/dart-lang/webdev/pull/2403) -- Make stack trace calculation resilient against one frame throwing an error. - [#2408](https://github.com/dart-lang/webdev/pull/2408) - -**Breaking changes** - -- Rename `dart_library.js` to `ddc_module_loader.js` to match SDK naming changes. - [#2360](https://github.com/dart-lang/webdev/pull/2360) - -## 23.3.0 - -- Filter out internal type properties from the new DDC type system. - [#2348](https://github.com/dart-lang/webdev/pull/2348) -- Fix errors on displaying getters when debugging in VS Code. - [#2343](https://github.com/dart-lang/webdev/pull/2343) - -## 23.2.0 - -- Send untruncated `dart:developer` logs to debugging clients. - [#2333](https://github.com/dart-lang/webdev/pull/2333) -- Enabling tests that run with the DDC module system and exposing `utilities/ddc_names.dart` - [#2295](https://github.com/dart-lang/webdev/pull/2295) - -## 23.1.1 - -- Loosen `package:vm_service` constraints to allow `>=13.0.0 <15.0.0`. - [#2329](https://github.com/dart-lang/webdev/pull/2329) - -## 23.1.0 - -- Update `package:vm_service` constraints to allow version `14.x.x`. - [#2307](https://github.com/dart-lang/webdev/pull/2307) - -## 23.0.0 - -- Restructure `LoadStrategy` to provide build settings. - [#2270](https://github.com/dart-lang/webdev/pull/2270) -- Add `FrontendServerLegacyStrategyProvider` and update bootstrap generation logic for `LegacyStrategy` - [#2285](https://github.com/dart-lang/webdev/pull/2285) -- Tolerate failures to detect a Dart execution context. - [#2286](https://github.com/dart-lang/webdev/pull/2286) -- Fix a null cast error when debugging a `Class` from VS Code. - [#2303](https://github.com/dart-lang/webdev/pull/2303) -- Update `package:vm_service` constraint to `^14.0.0`. - [#2307](https://github.com/dart-lang/webdev/pull/2307) -- Update `package:vm_service_interface` constraint to `1.0.1`. - [#2307](https://github.com/dart-lang/webdev/pull/2307) - -## 22.1.0 - -- Update `package:vm_service` constraint to `^13.0.0`. - [#2265](https://github.com/dart-lang/webdev/pull/2265) - -## 22.0.0 - -- Update the interface for ChromeProxyService.getSourceReport to match the VM service. - [#2235](https://github.com/dart-lang/webdev/pull/2235) -- Update `package:vm_service` constraint to `^12.0.0`. - [#2248](https://github.com/dart-lang/webdev/pull/2248) - -**Breaking changes** - -- Refactor the parameters to `Dwds.start`. - [#2231](https://github.com/dart-lang/webdev/pull/2231). -- Add a new parameter `workspaceName` to the `ToolConfiguration` passed to `Dwds.start`. - [#2237](https://github.com/dart-lang/webdev/pull/2237) - -## 21.0.0 - -- Update Dart SDK constraint to `>=3.2.0-36.0.dev <4.0.0`. - [#2207](https://github.com/dart-lang/webdev/pull/2207) - -**Breaking changes** - -- Allow clients to specify where to find the package config. - [#2203](https://github.com/dart-lang/webdev/pull/2203). -- Allow clients to specify a way to convert absolute paths to g3-relative paths. - [#2200](https://github.com/dart-lang/webdev/pull/2200) - -## 20.0.1 - -- Update file dependency to `>=6.0.0 < 8.0.0` - [#123260](https://github.com/flutter/flutter/pull/123260#issuecomment-1674001623). - -## 20.0.0 - -- Require clients to specify the `basePath` on `AssetReader`. - [#2160](https://github.com/dart-lang/webdev/pull/2160) -- Update SDK constraint to `>=3.1.0-254.0.dev <4.0.0`. - [#2169](https://github.com/dart-lang/webdev/pull/2169) -- Require min `build_web_compilers` version `4.0.4` - [#2171](https://github.com/dart-lang/webdev/pull/2171) -- Switch to using new debugging API from DDC to support new type system. - [#2159](https://github.com/dart-lang/webdev/pull/2159) -- Fix Flutter crash when calling `resume` when app is not paused. - [#2188](https://github.com/dart-lang/webdev/pull/2188) -- Update file dependency to `7.0.0`. - -## 19.0.2 - -- Fix Flutter crash due to potential null value in `setUpChromeConsoleListener`. - [#2162](https://github.com/dart-lang/webdev/pull/2162) - -## 19.0.1 - -- Do not show async frame errors on evaluation. - [#2073](https://github.com/dart-lang/webdev/pull/2073) -- Refactor code for presenting record instances. - [#2074](https://github.com/dart-lang/webdev/pull/2074) -- Display record types concisely. - [#2070](https://github.com/dart-lang/webdev/pull/2070) -- Display type objects concisely. - [#2103](https://github.com/dart-lang/webdev/pull/2103) -- Support using scope in `ChromeProxyService.evaluateInFrame`. - [#2122](https://github.com/dart-lang/webdev/pull/2122) -- Check for new events more often in batched stream. - [#2123](https://github.com/dart-lang/webdev/pull/2123) -- Map Chrome error on `resume` to the same error returned by the Dart VM. - [#2133](https://github.com/dart-lang/webdev/issues/2133) -- VM service API methods throw type `RPCError`, same as the Dart VM. - [#2144](https://github.com/dart-lang/webdev/pull/2144) - -## 19.0.0 - -- Allow clients to specify the connected app's entrypoint file. - [#2047](https://github.com/dart-lang/webdev/pull/2047) -- Don't include non-instantiated variables in stack frame data. - [#2061](https://github.com/dart-lang/webdev/pull/2061) -- Fix `getObject` failure on record class - [2063](https://github.com/dart-lang/webdev/pull/2063) - -## 18.0.2 - -- Support new DDC temp names for patterns. - [#2042](https://github.com/dart-lang/webdev/pull/2042) -- Make debugger find next dart location when stepping. -[#2043](https://github.com/dart-lang/webdev/pull/2043) - -## 18.0.1 - -- Fix failure to map JS exceptions to dart. - [#2004](https://github.com/dart-lang/webdev/pull/2004) -- Fix for listening to custom streams. - [#2011](https://github.com/dart-lang/webdev/pull/2011) -- Handle unexpected extension debugger disconnect events without crashing the app - [#2021](https://github.com/dart-lang/webdev/pull/2021) -- Support `Set` inspection. - [#2024](https://github.com/dart-lang/webdev/pull/2024) - -## 18.0.0 - -- Cleanup `getObject` code for lists and maps. - - Now works with offset `0` and `null` count. - - Fix failures on edge cases. -- Support records: - - Update SDK constraint to `>=3.0.0-188.0.dev <4.0.0`. - - Update `package:vm_service` constraint to `>=10.1.2 <12.0.0`. - - Update `package:dds` constraint to `^2.7.1`. - - Fill `BoundField.name` for records. - - Display records as a container of fields. -- Remove test-only code from `sdk_configuration.dart`. -- Move shared test-only code to a new `test_common` package. -- Convert unnecessary async code to sync. -- Allow empty scopes in expression evaluation in a frame. - -**Breaking changes** - -- Require `sdkConfigurationProvider` in `ExpressionCompilerService` - constructor. -- Change DWDS parameter `isFlutterApp` from type `bool?` to type - `Future Function()?`. - -## 17.0.0 - -- Include debug information in the event sent from the injected client to the - Dart Debug Extension notifying that the Dart app is ready. -- Fix null cast error on expression evaluations after dwds fails to find class - metadata. -- Include the entire exception description up to the stacktrace in - `mapExceptionStackTrace`. -- Allow enabling experiments in the expression compiler service. -- Pre-warm expression compiler cache to speed up Flutter Inspector loading. -- Display full error on failure to start DDS. -- Fix crash on processing DevTools event when starting DevTools from DevTools - uri. -- Prepare or Dart 3 alpha breaking changes: - - Move weak null safety tests to special branch of `build_web_compilers`. - - Do not pass `--(no)-sound-null-safety` flag to build daemon. -- Add back `ChromeProxyService.setExceptionPauseMode()` without override. -- Make hot restart atomic to prevent races on simultaneous execution. -- Return error on expression evaluation if expression evaluator stopped. -- Update SDK constraint to `>=3.0.0-134.0.dev <4.0.0`. -- Update `package:vm_service` constraint to `>=10.1.0 <12.0.0`. -- Fix expression compiler throwing when weak SDK summary is not found. - -**Breaking changes** - -- Include an optional param to `Dwds.start` to indicate whether it is running - internally or externally. -- Include an optional param to `Dwds.start` to indicate whether it a Flutter - app or not. -- Remove `sdkConfigurationProvider` parameter from `Dwds.start`. -- Remove deprecated `ChromeProxyService.setExceptionPauseMode()`. -- Support dart 3.0-alpha breaking changes: - - Generate missing SDK assets for tests. - - Enable frontend server null safe tests. - - Update `build_web_compilers` constraint to `^4.0.0`. - - Update `build_runner` constraint to `^2.4.0`. - - Support changes in the SDK layout for dart 3.0. - -## 16.0.1 - -- Allow the following API to return `null` and add error handling: - - `LoadStrategy.serverPathForModule` - - `LoadStrategy.sourceMapPathForModule` -- Expression evaluation performance improvement: - - Batch `ChromeProxyService.evaluate()` requests that are close in time and - are executed in the same library and scope. -- Update `package:file` version to `6.13` or greater to handle - https://github.com/dart-lang/sdk/issues/49647. - -## 16.0.0 - -- Fix a hang and report errors on hot reload exceptions from the injected - client. -- Remove `AppInspector.evaluate` code that has been replaced by expression - evaluation using a compiler in all scenarios. -- Fix a bug where evaluation would fail with more than one parameter in the - scope. -- Remove showing un-captured values from the stack during evaluation. -- Refactor code to break most circular dependencies between files. -- Migrate `package:dwds` to null safety. -- Make `ChromeProxyService.getStack` wait for the debugger to perform initial - resume operation. This avoids race conditions on isolate start. -- Make server paths match directory structure - - Allows correct relative source map paths resolution. - - Add `PackageUriMapper` class to allow mapping uris to server paths. -- Update the min SDK constraint to 2.18.0. -- Make DartUri work for `google3:` uris. - -**Breaking changes** - -- Remove no longer used `ExpressionCompilerService.handler`. -- Remove `assetHandler` parameter from `ExpressionCompilerService` constructor. -- Add `packageUriMapper` parameter to the constructor of - `FrontendServerRequireStrategyProvider`. - -## 15.0.0 - -- Port some `dwds` files to null safety. -- Fix failing `frontend_server_evaluate` tests. -- Prevent `flutter_tools` crash when the Dart execution context cannot be found. -- Update method signature of `lookupResolvedPackageUris`. - -## 14.0.3 - -- Make data types null safe. -- Update `package:vm_service` to 8.3.0. -- Convert JavaScript stack traces in uncaught exceptions to Dart stack traces. -- Fix failure to set breakpoints on windows with a base change in index.html. -- Add the `setIsolatePauseMode` method to Chrome Proxy Service. -- Batch extension `Debugger.scriptParsed` events and send batches every 1000ms - to the server. -- Move `batched_stream.dart` into shared utilities. -- Update the method signature for `lookupResolvedPackageUris`. - -## 14.0.2 - -- Update the min SDK constraint to 2.17.0. - -## 14.0.1 - -- Add `libraryFilters` optional parameter to the vm service implementation of - `getSourceReport`. -- Update temp variable detection heuristics so internal JS type objects do not - show in the debugger. - -## 14.0.0 - -- Add column information to breakpoints to allow precise breakpoint placement. -- Split SDK validation methods to allow validation of separate components. -- Remove dependency on `package:_fe_analyzer_shared`. Note: this removes current - incomplete support for resolving `dart:` uris. -- Fix issues discovered when using flutter tools with web server device: - - Remove `dart:web_sql` from the list of SDK libraries as it is no longer - used. - - Fix crash when using flutter tools with web server device. - - Remove clearing all scripts on page load for extension debugger. -- Fix breakpoints not hitting after changing a base in index.html. -- Find best locations for call frames, breakpoints, or expression evaluation. -- Close the SSE connection when a DebugExtension.detached event is received. -- Fix issues discovered when using legacy module system, debug extension, and - JIT modules: - - Improve step-into times by not stepping into library loading code. - - Fix incorrect skip lists due to unsorted locations. - - Fix memory leak in extension debugger by removing stale script IDs. - - Allow mapping JS locations to Dart locations matching other JS lines, to - match the behavior of Chrome DevTools. - - Fix expression evaluation failure if debugger is stopped in the middle of a - variable definition. - -**Breaking changes:** - -- Add `basePath` parameter to `FrontendServerRequireStrategy`. -- Add `loadLibrariesModule` getter to `LoadStrategy` interface. - -## 13.1.0 - -- Update \_fe_analyzer_shared to version ^38.0.0. - -## 13.0.0 - -- Change wording of paused overlay from "Paused in Dart DevTools" to "Paused" -- Allow sending back the Dart DevTools URL from DWDS instead of launching Dart - DevTools, to support embedding Dart DevTools in Chrome DevTools. -- Temporarily disable the paused in debugger overlay. -- Add `SdkConfiguration` and `SdkConfigurationProvider` classes to allow for - lazily created SDK configurations. -- Fix an issue in reporting DevTools stats where the DevTools load time was not - always recorded. -- Add an `ide` query parameter to the Dart DevTools URL for analytics. -- Fix a race where injected client crashed on events send just before hot - restart. -- Remove verbose printing on receiving DevTools events. -- Update `vm_service` version to `^8.2.0`. -- Migrate .packages to package_config.json. -- Update error message on expression evaluation using unloaded libraries. -- Add `screen` field to the `DebuggerReady` event. -- Report `DebuggerReady` events for DevTools embedded into Chrome Devtools. -- Fix missing `CallFrame.url` after update to Chrome 100. - -**Breaking changes:** - -- `Dwds.start` and `ExpressionCompilerService` now take - `sdkConfigurationProvider` argument instead of separate SDK-related file - paths. - -## 12.1.0 - -- Update \_fe_analyzer_shared to version ^34.0.0. - -## 12.0.0 - -- Implement `lookupResolvedPackageUris` and `lookupPackageUris` vm service API. -- Update `vm_service` version to `^8.1.0`. -- Make `ExpressionCompilerService` infer location of `libraries.json` from - `sdkDir` parameter. -- Show an alert in the Dart Debug Extension for a multi-app scenario. -- Fix a bug where `dartEmitDebugEvents` was set as a `String` instead of `bool` - in the injected client. -- Emit a warning instead of crashing on missing `libraries.json`. -- Remove dead code for reading `'dart.developer.registerExtension'` and - `'dart.developer.postEvent'` events from the chrome console. These messages - haven't been written to the console since dwds v11.1.0 and Dart SDK v2.14.0. -- Batch debug events sent from injected client to dwds to relieve network load. -- Update `_fe_analyzer_shared` version to `33.0.0` -- Update the Dart minimum SDK to `>=2.16.0`. - -**Breaking changes:** - -- Add `sdkDir` and `librariesPath` arguments to `Dwds.start` to help file - resolution for sdk uris. -- Add `emitDebugEvents` argument to `Dwds.start` to suppress emitting debug - events from the injected client. -- Replace `sdkRoot` parameter by `sdkDir` in `ExpressionCompilerService`. -- Adds an additional parameter to launch Dart DevTools in the same window as the - connected Dart app. - -## 11.5.1 - -- Update SDK constraint to `>=2.15.0 <3.0.0`. - -## 11.5.0 - -- Support hot restart in a multi-app scenario with legacy modules. - - Rename `$dartHotRestart` in the injected client to `$dartHotRestartDwds`. - - Make `$dartHotRestartDwds` take a `runId`. - - No change in behavior for single applications. - - For a multi-app scenario using legacy modules, this will make all sub-apps - with the same `runId` restart at the same time once. - - Note that multi-app scenario is currently only supported for legacy modules, - used by DDR, and is not yet supported for amd modules that are used by flutter - tools and webdev. - -- Fix chrome detection in iPhone emulation mode in chrome or edge browsers. - -- Reliably find unused port for extension backend http service. - -- Ignore offset / count parameters in getObject if the object has no length. - -- Include static member information for classes. - -## 11.4.0 - -- Fix duplicated scripts returned by `VmService.getScripts` API. -- Handle and log http request serving errors. -- Encode extension url asynchronously. -- Use default constant port for debug service. - - If we fail binding to the port, fall back to previous strategy of finding - unbound ports. -- Add metrics measuring - - DevTools Initial Page Load time - - Various VM API - - Hot restart - - Http request handling exceptions -- Only return scripts included in the library with Library object. -- Add `ext.dwds.sendEvent` service extension to dwds so other tools can send - events to the debugger. Event format: - ``` - { - 'type': '', - 'payload': { - 'screen: '', - 'action: '' - } - } - ``` - Currently supported event values: - ``` - { - 'type: 'DevtoolsEvent', - 'payload': { - 'screen': 'debugger', - 'action': 'pageReady' - } - } - ``` - -## 11.3.0 - -- Update SDK constraint to `>=2.14.0 <3.0.0` -- Depend on `vm_service` version `7.3.0`. - -## 11.2.3 - -- Fix race causing intermittent `Aww, snap` errors on starting debugger with - multiple breakpoints in source. -- Fix needing chrome to be focus in order to wait for the isolate to exit on hot - restart. - -## 11.2.2 - -- Depend on `dds` version `2.1.1`. -- Depend on `vm_service` version `7.2.0`. - -## 11.2.1 - -- Recover from used port errors when starting debug service. -- Update min SDK constraint to `2.13.0`. - -## 11.2.0 - -- Throw `SentinelException` instead of `RPCError` on vm service API on - unrecognized isolate. -- Throw `RPCError` in `getStack` if the application is not paused. -- Recognize `dart:ui` library when debugging flutter apps. -- Fix hang on hot restart when the application has a breakpoint. -- Fix out of memory issue during sending debug event notifications. - -## 11.1.2 - -- Return empty library from `ChromeProxyService.getObject` for libraries present - in metadata but not loaded at runtime. -- Log failures to load kernel during expression evaluation. -- Show lowered final fields using their original dart names. -- Limit simultaneous connections to asset server to prevent broken sockets. -- Fix hangs in hot restart. -- Initial support for passing scope to `ChromeProxyService.evaluate`. -- Require `build_web_compilers` version `3.0.0` so current version of dwds could - be used with SDK stable `2.13.x` versions. - -## 11.1.1 - -- Update versions of `package:sse`, `package:vm_service`, `package:dds`. - -## 11.1.0 - -- Add global functions to the injected client for `dart.developer.postEvent` and - `dart.developer.registerExtension`. -- Register new service extension `ext.dwds.emitEvent` so clients can emit - events. This is intended to be used for analytics. - -## 11.0.2 - -- Implement `_flutter.listViews` extension method in dwds vm client. - -## 11.0.1 - -- Make adding and removing breakpoints match VM behavior: - - Allow adding existing breakpoints. - - Throw `RPCError` when removing non-existent breakpoints. - -## 11.0.0 - -- Do not send `kServiceExtensionAdded` events to subscribers on the terminating - isolate during hot restart. -- Support `vm_service` version `6.2.0`. -- Fix missing sdk libraries in `getObject()` calls. -- Fix incorrect `rootLib` returned by `ChromeProxyService`. -- Fix not working breakpoints in library part files. -- Fix data race in calculating locations for a module. -- Fix uninitialized isolate after hot restart. -- Fix intermittent failure caused by evaluation not waiting for dependencies to - be updated. -- The injected client now posts a top level event when the Dart application is - loaded. This event is intended to be consumed by the Dart Debug Extension. - -**Breaking changes:** - -- `Dwds.start` no longer supports automatically injecting a devtools server. A - `devtoolsLauncher` callback must be provided to support launching devtools. - -## 10.0.1 - -- Support `webkit_inspection_protocol` version `^1.0.0`. - -## 10.0.0 - -- Support `VMService.evaluate` using expression compiler. -- Update min sdk constraint to `>=2.13.0-144.0.dev`. -- Throw `RPCError` on evaluation if the program is not paused. -- Record `ErrorRef` returned by evaluation in analytics. - -**Breaking changes:** - -- Change `ExpressionCompiler.initialize` method to include module format. -- Add `LoadStrategy.moduleFormat` to be used for communicating current module - format to the expression compiler. - -## 9.1.0 - -- Support authentication endpoint for the Dart Debug Extension. -- Support using WebSockets for the injected client by passing - `useSseForInjectedClient: false` to `Dwds.start()`. Unlike SSE, WebSockets do - not currently support keepAlives here (beyond the standard WebSocket pings to - keep the socket alive). - -## 9.0.0 - -- Fix an issue where relative worker paths provided to the - `ExpressionCompilerService` would cause a crash. -- Fix an issue where the injected client connection could be lost while the - application is paused. -- Support keep-alive for debug service connections. -- Depend on the latest `package:sse`. -- Filter out DDC temporary variables from the variable inspection view. -- Add `DwdsEvent`s around stepping and evaluation. -- Send an event to the Dart Debug Extension that contains VM service protocol - URI. -- Depend on `package:vm_service` version `6.1.0+1`. -- Update the `keepAlive` configs to prevent accidental reuse of a connection - after stopping a debug session. -- Support disabling the launching of Dart DevTools through `Alt + d` with - `enableDevtoolsLaunch`. -- Opt all dart files out of null safety for min SDK constraint update. - -**Breaking changes:** - -- `LoadStrategy`s now require a `moduleInfoForEntrypoint`. - -## 8.0.3 - -- Fix an issue where failed hot restarts would hang indefinitely. - -## 8.0.2 - -- Change `ExpressionCompiler` to accept `FutureOr` port configuration. -- Depend on `package:vm_service` version `6.0.1-nullsafety.1`. - -## 8.0.1 - -- Support null safe versions of `package:crypto`, `package:uuid` and - `package:webdriver`. - -## 8.0.0 - -- Improve logging around execution contexts. -- Remove the expression compilation dependency update from the create isolate - critical path. -- Expose new event stream for future use with analytics. -- Update `ExpressionCompiler` to include new `initialize` method which has a - parameter for the null safety mode. -- Update `ExpressionCompilerService` to change how it is instantiated and - implement the new `initialize` method. -- Provide summary module paths to the expression compiler -- Depend on `package:vm_service` version `6.0.1-nullsafety.0`. - -**Breaking changes:** - -- Change `ExpressionCompiler.updateDependencies` method to include module - summary paths - -## 7.1.1 - -- Properly handle `requireJS` errors during hot restarts. -- Fix an issue where Dart frame computation could result in a stack overflow for - highly nested calls. -- Fix an issue where calling add breakpoint in quick succession would corrupt - the internal state. -- Fix expression evaluation failure inside blocks. -- Now log the encoded URI of the debug service to both the terminal and - application console. -- No longer blacklist the Dart SDK as the `skipLists` support serves the same - purpose. -- Fix an issue where running webdev with expression evaluation enabled would - fail to find `libraries.json` file and emit severe error. - -## 7.1.0 - -- Fix a potential null issue while resuming. -- Depend on the latest `package:vm_service`. -- Fix crash in expression evaluation on null isolate. -- Fix incorrect file name detection for full kernel files. -- Add `ExpressionCompilerService.startWithPlatform` API to enable running - expression compiler worker from a given location. -- Support Chrome `skipLists` to improve stepping performance. -- Export `AbsoluteImportUriException`. -- Depend on the latest `package:vm_service` which supports a new `limit` - parameter to `getStack`. - -## 7.0.2 - -- Depend on the latest `package:sse`. -- Add more verbose logging around `hotRestart`, `fullReload` and entrypoint - injection. - -## 7.0.1 - -- Fix an issue where we attempted to find locations for the special - `dart_library` module. - -## 7.0.0 - -- Add support for the Dart Development Service (DDS). Introduces 'single client - mode', which prevents additional direct connections to DWDS when DDS is - connected. -- Update metadata reader version to `2.0.0`. Support reading metadata versions - `2.0.0` and `1.0.0`. -- Support custom hosts and HTTPs traffic in a `ProxyServerAssetReader`. -- Remove heuristics from require strategies and use metadata to look up module - paths. - - Fix issue where upgrading `build_web_compilers` would cause missing module - assets (JavaScript code and source maps). -- Fix issue where open http connections prevent the process for exiting. -- Add `ExpressionCompilationService` class that runs ddc in worker mode to - support expression evaluation for clients that use build systems to build the - code. -- Require at least `devtools` and `devtools_server` version `0.9.2`. -- Require at least `dds` version `1.4.1`. -- Require at least `build_web_compilers` version `2.12.0`. -- Update min sdk constraint to `>=2.10.0`. -- Update `MetadataProvider` to throw an `AbsoluteImportUriException` when - absolute file paths are used in an import uri. - -**Breaking changes:** - -- Change `ExpressionCompiler` to require a new `updateDependencies` method. -- Update a number of `LoadStrategy` APIs to remove heuristics and rely on the - `MetadataProvider`. -- No longer require a `LogWriter` and corresponding `verbose` argument but - instead properly use `package:logger`. -- `FrontendServerRequireStrategyProvider` now requires a `digestProvider`. - -## 6.0.0 - -- Depend on the latest `package:devtools` and `package:devtools_server`. -- Support using WebSockets for the debug backend by passing - `useSseForDebugBackend: false` to `Dwds.start()` -- Ensure we run main on a hot restart request even if no modules were updated. -- Allow reading metadata generated by `dev_compiler` from file to supply module - information to `Dwds`. -- Hide JavaScript type errors when hovering over text in the debugger. -- Fix an issue where reusing a connection could cause a null error. -- Improve the heuristic which filters JS scopes for debugging needs. - -**Breaking Changes:** - -- Require access to the `.ddc_merged_metadata` file. -- Remove deprecated parameter `restoreBreakpoints` as breakpoints are now set by - regex URL and Chrome automatically reestablishes them. - -## 5.0.0 - -- Have unimplemented VM service protocol methods return the RPC error - 'MethodNotFound' / `-32601`. -- Fix an issue where the application main function was called before a hot - restart completed. -- Breaking change `AssetReader` now requires a `metadataContents` - implementation. - -## 4.0.1 - -- Fixed issue where `getSupportedProtocols` would return the wrong protocol. - -## 4.0.0 - -- Pin the `package:vm_service` version to prevent unintended breaks. - -## 3.1.3 - -- Fix an issue where the injected client served under `https` assumed the - corresponding SSE handler was also under `https`. - -## 3.1.2 - -- Gracefully handle multiple injected clients on a single page. -- Update to the latest `package:vm_service` and use more RPCError error codes on - call failures. -- Update the `require_restarter` to rerun main after a hot restart to align with - the legacy strategy. We therefore no longer send a `RunRequest` after a hot - restart. -- Compute only the required top frame for a paused event. -- Change `streamListen` to return an `RPCError` / error code `-32601` for - streams that are not handled. -- Populate information about async Dart frames. -- Populate the `exception` field in debugger pause event when we break as a - result of an exception. -- Prompt users to install the Dart Debug Extension if local debugging does not - work. -- Allow for the injected client to run with CSP enforced. -- Implement the `getMemoryUsage()` call. -- Fix an issue where the injected client could cause a mixed content error. - -## 3.1.1 - -- Change the reported names for isolates to be more terse. -- Implemented the 'PossibleBreakpoints' report kind for `getSourceReport()`. -- Change the returned errors for the unimplemented `getClassList` and - `reloadSources` methods to -32601 ('method does not exist / is not - available'). -- Do not include native JavaScript objects on stack returned from the debugger. - -## 3.1.0 - -- Support Chromium based Edge. -- Depend on latest `package:sse` version `3.5.0`. -- Bypass connection keep-alives when shutting down to avoid delaying process - shutdown. -- Fix an issue where the isolate would incorrectly be destroyed after connection - reuse. - -## 3.0.3 - -- Support the latest version of `package:shelf_packages_handler`. -- Throw a more useful error if during a hot restart there is no active isolate. -- Fix a race condition in which loading module metadata could cause a crash. -- Correct scope detection for expression evaluation -- Silence verbose and recoverable exceptions during expression evaluation -- Return errors from ChromeProxyService.evaluateInFrame as ErrorRef so they are - not shown when hovering over source in the IDE - -## 3.0.2 - -- Fix an issue in JS to Dart location translation in `ExpressionEvaluator`. JS - location returned from Chrome is 0-based, adjusted to 1-based. - -## 3.0.1 - -- Drop dependency on `package_resolver` and use `package_config` instead. -- Bump min sdk constraint to `>=2.7.0`. - -## 3.0.0 - -- Depend on the latest `package:vm_service` version `4.0.0`. - -**Breaking Changes:** - -- Delegate to the `LoadStrategy` for module information: - - moduleId -> serverPath - - serverPath -> moduleId - -## 2.0.1 - -- Fix an issue where we would return prematurely during a `hotRestart`. -- Fix an issue where we would incorrectly fail if a `hotRestart` had to fall - back to a full reload. - -## 2.0.0 - -- Depend on the latest `package:vm_service` version `3.0.0+1`. - -**Breaking Changes:** - -- Now require a `LoadStrategy` to `Dwds.start`. This package defines two - compatible load strategies, `RequireStrategy` and \`LegacyStrategy. -- `Dwds.start` function signature has been changed to accept one more parameter - of new interface type `ExpressionCompiler` to support expression evaluation -- Provide an implementation of the `RequireStrategy` suitable for use with - `package:build_runner`. -- Simplify hot reload logic and no longer provide module level hooks. - -## 1.0.1 - -- Make the `root` optional for the `ProxyServerAssetReader`. - -## 1.0.0 - -- Fix an issue where files imported with relative paths containing `../` may - fail to resolve breakpoint locations. -- Remove dependency on `package:build_daemon`. -- Add `FrontendServerAssetReader` for use with Frontend Server builds. -- Depend on latest `package:sse` for handling client reconnects transparently on - the server. -- Fix an issue where a failure to initiate debugging through the Dart Debug - Extension would cause your development server to crash. -- Fix an issue where trying to launch DevTools in a non-debug enabled Chrome - instance could crash your development server. - -**Breaking Changes:** - -- No longer use the `BuildResult` abstraction from `package:build_daemon` but - require a similar abstraction provided by this package. -- `AssetHandler` has been renamed to `AssetReader` and no longer provides a - generic resource handler. Specific methods for the required resources are now - clearly defined. The new abstraction is now consumed through `dwds.dart`. -- `BuildRunnerAssetHandler` has been renamed to `ProxyServerAssetReader` and is - now consumed through `dwds.dart`. - -## 0.9.0 - -- Expose `middleware` and `handler`. - -**Breaking Change:** The `AssetHandler` will not automatically be added the DWDS -handler cascade. You must now also add the `middleware` to your server's -pipeline. - -## 0.8.5 - -- Always bind to `localhost` for the local debug workflow. -- Fix an issue where breakpoints could cause DevTools to hang. - -## 0.8.4 - -- Support using WebSockets for the debug (VM Service) proxy by passing - `useSseForDebugProxy: false` to `Dwds.start()` - -## 0.8.3 - -- Support nesting Dart applications in iframes. - -## 0.8.2 - -- Add the ability to receive events from the extension in batches. - -## 0.8.1 - -- Depend on the latest `package:built_value`. - -## 0.8.0 - -- Add temporary support for restoring breakpoints. Eventually the Dart VM - protocol will clearly define how breakpoints should be restored. -- Depend on latest `package:sse` to get retry logic. -- Don't spawn DevTools if `serveDevTools` is false. -- `UrlEncoder` will also encode the base URI used by the injected client / Dart - Debug Extension. \*\* Breaking Change \*\* `serveDevTools` is not - automatically considered true if `enableDebugExtension`is true. - -## 0.7.9 - -- Properly wait for hot reload to complete with the legacy module system. -- Fix issue with `getObject` for a class with a generic type. - -## 0.7.8 - -- Support optional argument `urlEncoder` that is used to encode remote URLs for - use with the Dart Debug Extension. - -## 0.7.7 - -- Handle getObject for primitives properly. -- Properly black box scripts if query parameters are provided. - -## 0.7.6 - -- Fix issue with source map logic for the legacy module system. -- Allow setting breakpoints multiple times and just return the old breakpoint. -- Fix a bug with Maps that contain lists of simple types. - -## 0.7.5 - -- The injected client's connection is now based off the request URI. -- Fix an issue where resuming while paused at the start would cause an error. -- Expose the `ChromeDebugException` class for error handling purposes. -- Expose the `AppConnectionException` class for error handling purposes. -- DevTools will now launch immediately and lazily sets up necessary state. -- Properly set `pauseBreakpoints` on `kPauseBreakpoint` events. -- Greatly improves handling of List, Map and IdentityMap instances. -- Lazily parse source maps to improve performance for large applications. - -## 0.7.4 - -- Deobfuscate DDC extension method stack traces. -- Properly get all libraries with the `legacy` module system. - -## 0.7.3 - -- Correctly set `Isolate` state if debugging is initiated after the application - has already started. - -## 0.7.2 - -- Account for root directory path when using `package:` URIs with `DartUri`. - -## 0.7.1 - -- Fix a bug where we would try to create a new isolate even for a failed hot - restart. This created a race condition that would lead to a crash. -- Don't attempt to write a vm service request to a closed connection. - - Instead we log a warning with the attempted request message and return. -- Make all `close` methods more robust by allowing them to be called more than - once and returning the cached future from previous calls. -- Add explicit handling of app not loaded errors when handling chrome pause - events. - -## 0.7.0 - -- `DWDS.start` now requires an `AssetHandler` instead of `applicationPort`, - `assetServerPort` and `applicationTarget`. -- Expose a `BuildRunnerAssetHandler` which proxies request to the asset server - running within build runner. -- Support the Legacy Module strategy through the injected client. -- Support DDK sourcemap URIs. -- Update SDK dependency to minimum of 2.5.0. - -### Bug Fixes: - -- Fix handling of chrome pause events when we have no isolate loaded yet. - -## 0.6.2 - -- Capture any errors that happen when handling SSE requests in the DevHandler - and return an error response to the client code. - - Log error responses in the client to the console. -- Handle empty Chrome exception descriptions. - -## 0.6.1 - -- Add `isolateRef` to `Isolate`s `pauseEvent`s. -- Depend on the latest `package:vm_service`. -- Implements `invoke`. -- Adds support for VM object IDs for things that don't have Chrome object Ids - (e.g. int, double, bool, null). - -## 0.6.0 - -- Add new required parameter `enableDebugging` to `Dwds.start`. If `false` is - provided, debug services will not run. However, reload logic will continue to - work with the injected client. -- Handle injected client SSE errors. -- Handle a race condition when the browser is refreshed in the middle of setting - up the debug services. - -## 0.5.5 - -- Properly set the `pauseEvent` on the `Isolate`. -- Fix a race condition with Hot Restarts where the Isolate was not created in - time for pause events. - -## 0.5.4 - -- Fix issue where certain required fields of VM service protocol objects were - null. -- Properly set the `exceptionPauseMode` on the `Isolate`. -- Depend on the latest `DevTools`. - -## 0.5.3 - -- Fix issue where certain required fields of VM service protocol objects were - null. - -## 0.5.2 - -- Fix issue where certain required fields of VM service protocol objects were - null. -- Properly display `Closure` names in the debug view. - -## 0.5.1 - -- Fix an issue where missing source maps would cause a crash. A warning will now - be logged to the console instead. -- Depend on the latest `package:webkit_inspection_protocol`. - -## 0.5.0 - -- Fix an issue where we source map paths were not normalized. -- Added a check to tests for the variable DWDS_DEBUG_CHROME to run Chrome with a - UI rather than headless. -- Catch unhandled errors in `client.js` and recommend using the - `--no-injected-client` flag for webdev users. -- Add support for an SSE connection with Dart DevTools. -- Rename `wsUri` to `uri` on `DebugConnection` to reflect that the uri may not - be a websocket. -- Depend on latest `package:vm_service`. - -## 0.4.0 - -- Move `data` abstractions from `package:webdev` into `package:dwds`. -- Move debugging related handlers from `package:webdev` into `package:dwds`. -- Move injected client from `package:webdev` into `package:dwds`. -- Create new public entrypoint `dwds.dart`. Existing public API `services.dart` - is now private. - -## 0.3.3 - -- Add support for `getScript` for paused isolates. -- Add support for `onRequest` and `onResponse` listeners for the vm service. - -## 0.3.2 - -- Add support for `scope` in `evaluate` calls. - -## 0.3.1 - -- Improve error reporting for evals, give the full JS eval in the error message - so it can be more easily reproduced. - -## 0.3.0 - -- Change the exposed type on DebugService to VmServiceInterface - -## 0.2.1 - -- Support `setExceptionPauseMode`. - -## 0.2.0 - -- Added custom tokens to the `wsUri` for increased security. - - Treating this as a breaking change because you now must use the `wsUri` - getter to get a valid uri for connecting to the service, when previously - combining the port and host was sufficient. - -## 0.1.0 - -- Initial version diff --git a/dwds/CONTRIBUTING.md b/dwds/CONTRIBUTING.md deleted file mode 100644 index 198fdb47cf..0000000000 --- a/dwds/CONTRIBUTING.md +++ /dev/null @@ -1,196 +0,0 @@ -## Local Development - -### With Flutter tools (recommended) - -1. Fork and download the [Flutter repo](https://github.com/flutter/flutter). - Detailed instructions can be found - [here](https://github.com/flutter/flutter/wiki/Setting-up-the-Framework-development-environment). -1. Add an alias to your `.bashrc`/`.zshrc` for Flutter Tools: - -``` -alias flutter_tools_debug='/YOUR_PATH/flutter/bin/dart --observe /YOUR_PATH/flutter/packages/flutter_tools/bin/flutter_tools.dart' -alias flutter_tools='/YOUR_PATH/flutter/bin/dart /YOUR_PATH/flutter/packages/flutter_tools/bin/flutter_tools.dart' -``` - -> **Explanation:** -> -> - `/PATH_TO_YOUR_FLUTTER_REPO/bin/dart`: This is the path to the Dart SDK that -> Flutter Tools uses -> - `--observe`: This flag specifies we want a Dart DevTools URL for debugging. -> - `/PATH_TO_YOUR_FLUTTER_REPO/packages/flutter_tools/bin/flutter_tools.dart`: -> This is the path to Flutter Tools itself -> -> _More details can be found at the Flutter Tools -> [README](https://github.com/flutter/flutter/blob/master/packages/flutter_tools/README.md)._ - -3. In your Flutter Tools - [`pubspec.yaml`](https://github.com/flutter/flutter/blob/master/packages/flutter_tools/pubspec.yaml), - change the DWDS dependency to point to your local DWDS: - -``` - dwds: - path: /YOUR_PATH/dwds -``` - -Note: This is even easier if you create a `pubspec_overrides.yaml` file in the `flutter_tools` directory, and then git-ignore it. This way you don't have to worry about committing your DWDS override. - -4. Choose a Flutter app to run (such as the - [Flutter Gallery app](https://github.com/flutter/flutter/tree/master/dev/integration_tests/flutter_gallery). -1. From the Flutter app repo, run your local Flutter Tools with alias you - defined in step #2: - -If you want a DevTools URL: - -``` -flutter_tools_debug run -d chrome -``` - -If you don't want a DevTools URL: - -``` -flutter_tools run -d chrome -``` - -Note: `flutter_tools_debug` can be a bit of a pain, because the app starts paused and you have to first open the DevTools URL and resume before you can do anything. Therefore, when you don't need to set breakpoints you should run `flutter_tools` instead of `flutter_tools_debug`. - -6. If running with `flutter_tools_debug`, open up the **first** Dart DevTools URL you see printed: - -``` -... -The Dart VM service is listening on http://127.0.0.1:8181/ajXIPMLq6iI=/ -The Dart DevTools debugger and profiler is available at: http://127.0.0.1:8181/ajXIPMLq6iI=/devtools/#/?uri=ws%3A%2F%2F127.0.0.1%3A8181%2FajXIPMLq6iI%3D%2Fws <== THIS ONE! -Launching lib/main.dart on Chrome in debug mode... -... -``` - -7. The Dart DevTools you open is connected to your Flutter Tools, but because of - the path dependency added in step #3, you can debug your local DWDS as well. - -### With WebDev - -Follow instructions in the `webdev/example` [README](/example/README.md) to run -the example app and connect to DWDS. - -## Changes required when submitting a PR - -- Make sure you update the `CHANGELOG.md` with a description of the change, or use - the 'changelog-not-required' label to mark that the PR doesn't need a `CHANGELOG.md` - entry. -- If DWDS / Webdev was just released, then you will need to update the version - in the `CHANGELOG`, and the `pubspec.yaml` file as well (eg, - https://github.com/dart-lang/webdev/pull/1462) -- For any directories you’ve touched, run `dart run tool/build.dart` to - check in any file that should be built. This will make sure the integration - tests are run against the built files. - -## g3 Rolls - -DWDS is rolled automatically into g3 along with the Dart SDK. For more information, or to learn how to handle breaking changes, see go/roll-dwds. - -## Release steps - -## Step 1: Publish DWDS to pub - -- From the `/tool` directory in the mono-repo root, run: `dart run release.dart -p dwds` -- Submit a PR with those changes (example PR: https://github.com/dart-lang/webdev/pull/1456) -- Once the PR is submitted, go to https://github.com/dart-lang/webdev/releases and create a new - release, eg https://github.com/dart-lang/webdev/releases/tag/dwds-v12.0.0. This should trigger - the auto-publisher. Verify that the package is published. -- From the `/tool` directory in the mono-repo root, run: `dart run release.dart --reset -p dwds -v <>` where the new version tag is the next minor version postfixed with `-wip` ([example PR](https://github.com/dart-lang/webdev/pull/2267/files)) -- Submit a PR with those changes. - -> _Note: To have the right permissions for publishing, you need to be invited to -> the tools.dart.dev. A member of the Dart team should be able to add you at -> https://pub.dev/publishers/tools.dart.dev/admin._ - -## Step 2: Publish Webdev to pub - -> _Note: DWDS is a dependency of Webdev, which is why DWDS must be published -> before Webdev can be published._ - -Follow instructions in the `webdev/webdev` -[CONTRIBUTING](/webdev/CONTRIBUTING.md) to release Webdev. - -## Whenever the Dart SDK is updated - -Whenever Dart SDK is updated to a new major or minor version (~every 2 weeks), -any PR submissions to Webdev are blocked by the min_sdk_test until the Dart min -SDK constraint is updated. Therefore, whenever your PR gets blocked by the test, -you need to: - -1. Create a new PR that updates all the min SDK constraints to the new version, - eg: https://github.com/dart-lang/webdev/pull/1463. -1. From each of the subdirectories (`/dwds`, `/frontend_server_client`, - and `/webdev`) update dependencies with - `dart pub upgrade` -1. Make sure to update the `CHANGELOG` to include the new version number -1. Submit your PR. At this point, you technically will be able to submit the PR - that was blocked, but the point of the test is to make sure that DWDS and - Webdev get released after a Dart stable release. Therefore, follow the steps - above to publish DWDS and Webdev. - -> ### Why is this necessary? -> -> This is so that we don’t need to support older versions of the SDK and test -> against them, therefore every time the Dart SDK is bumped to a new major or -> minor version, DWDS and Webdev’s min Dart SDK constraint needs to be -> changed and DWDS and Webdev have to be released. Since DWDS is dependent on -> DDC and the runtime API, if we had a looser min constraint we would need to -> run tests for all earlier stable releases of the SDK that match the -> constraint, which would have differences in functionality and therefore need -> different tests. - -## Hotfixes - -Sometimes you might need to do a hotfix release of DWDS. An example of why this -might be necessary is if you need to do a hotfix of DWDS into Flutter, but don't -want to release a new version of DWDS with the current untested changes on the -`main` branch. Instead you only want to apply a fix to the current version of -DWDS in Flutter. - -### Instructions: - -1. Create a branch off the release that needs a hotfix: - - a. In the GitHub UI's - [commit history view](https://github.com/dart-lang/webdev/commits/main), - find the commit that prepared the release of DWDS that you would like to - hotfix. - - b. Click on `< >` ("Browse the repository at this point in history"). - - c. At the top-left, you should see the commit hash in a dropdown. Click the - dropdown, and type in a name for your hotfix branch (e.g. - `16.0.2-hotfix-release`). Then select "Create branch `16.0.2-hotfix-release` - from `commit_hash`". - - d. From your local clone of DWDS, run `git fetch upstream`. (_Note: this - assumes you have already configured git to sync your fork with the `upstream` - repository. If you haven't, follow - [these instructions](https://docs.github.com/en/get-started/quickstart/fork-a-repo#configuring-git-to-sync-your-fork-with-the-upstream-repository).)_ - - e. Search for the branch that you just created, e.g. - `git branch -a | grep 16.0.2-hotfix-release` f. Track that branch with - `git checkout --track branch_name` (e.g. - `remotes/upstream/16.0.2-hotfix-release`) - -1. Update the CI tests so that the branch tests against the appropriate Dart - SDKs: - - a. Make the appropriate changes to DWDS' `mono_pkg.yaml` then run - `mono_repo generate`. Submit this change to the branch you created in step - #3, **not** `main`. - -1. Make the fix: - - a. You can now make the change you would like to hotfix. From the GitHub UI, - open a PR to merge your change into the branch you created in step #3, - **not** `main`. See https://github.com/dart-lang/webdev/pull/1867 as an - example. - -1. Once it's merged, you can follow the instructions to - [publish DWDS to pub](#step-2-publish-dwds-to-pub), except instead of pulling - from `main`, pull from the branch your created in step #3. - -1. If necessary, open a cherry-pick request in Flutter to update the version. - See https://github.com/flutter/flutter/issues/118122 for an example. diff --git a/dwds/LICENSE b/dwds/LICENSE deleted file mode 100644 index a0d5f54318..0000000000 --- a/dwds/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright 2019, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/dwds/OWNERS b/dwds/OWNERS deleted file mode 100644 index 77bdf63de2..0000000000 --- a/dwds/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -set noparent -# Dart Development Infrastructure Team -file:/tools/OWNERS_DEV_INFRA \ No newline at end of file diff --git a/dwds/README.md b/dwds/README.md deleted file mode 100644 index b63bd6391f..0000000000 --- a/dwds/README.md +++ /dev/null @@ -1,15 +0,0 @@ -## Dart Web Developer Service - -The Dart Web Developer Service (DWDS) allows developer tools designed to work -with the native Dart VM to also work with Dart Web applications compiled with -[DDC](https://dart.dev/tools/dartdevc), built / served with -[webdev](https://dart.dev/tools/webdev), and run in Chrome. - -`package:dwds` is integrated into `webdev serve` as well as `flutter run`. - -At a basic level, DWDS proxies between: - -- Developer tools that are written against the - [Dart VM Service Protocol](https://github.com/dart-lang/sdk/blob/main/runtime/vm/service/service.md) -- Execution environments that expose the - [Chrome DevTools Protocol](https://chromedevtools.github.io/devtools-protocol) diff --git a/dwds/analysis_options.yaml b/dwds/analysis_options.yaml deleted file mode 100644 index 6853b8e2ed..0000000000 --- a/dwds/analysis_options.yaml +++ /dev/null @@ -1,15 +0,0 @@ -include: package:dart_flutter_team_lints/analysis_options.yaml - -analyzer: - exclude: - # Ignore generated files - - "lib/src/handlers/injected_client_js.dart" - # Ignore integration fixtures to avoid analysis errors from "package:build_daemon". - - "test/integration/fixtures/context.dart" - - "test/integration/fixtures/server.dart" - - "test/integration/fixtures/utilities.dart" - -linter: - rules: - always_use_package_imports: true - prefer_relative_imports: false diff --git a/dwds/lib/asset_reader.dart b/dwds/lib/asset_reader.dart deleted file mode 100644 index 578849f302..0000000000 --- a/dwds/lib/asset_reader.dart +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -export 'src/readers/asset_reader.dart' - show AssetReader, PackageUriMapper, stripLeadingSlashes; diff --git a/dwds/lib/config.dart b/dwds/lib/config.dart deleted file mode 100644 index ddd51b4819..0000000000 --- a/dwds/lib/config.dart +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -export 'src/config/tool_configuration.dart' - show - AppMetadata, - DebugSettings, - DevToolsLauncher, - ToolConfiguration, - UrlEncoder; diff --git a/dwds/lib/dart_web_debug_service.dart b/dwds/lib/dart_web_debug_service.dart deleted file mode 100644 index a3698b71b0..0000000000 --- a/dwds/lib/dart_web_debug_service.dart +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:async'; - -import 'package:dwds/data/build_result.dart'; -import 'package:dwds/src/config/tool_configuration.dart'; -import 'package:dwds/src/connections/app_connection.dart'; -import 'package:dwds/src/connections/debug_connection.dart'; -import 'package:dwds/src/events.dart'; -import 'package:dwds/src/handlers/dev_handler.dart'; -import 'package:dwds/src/handlers/injector.dart'; -import 'package:dwds/src/handlers/socket_connections.dart'; -import 'package:dwds/src/readers/asset_reader.dart'; -import 'package:dwds/src/servers/devtools.dart'; -import 'package:dwds/src/servers/extension_backend.dart'; -import 'package:logging/logging.dart'; -import 'package:shelf/shelf.dart'; -import 'package:sse/server/sse_handler.dart'; -import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'; - -typedef ConnectionProvider = Future Function(); - -/// The Dart Web Debug Service. -class Dwds { - static final _logger = Logger('DWDS'); - final Middleware middleware; - final Handler handler; - final DevTools? _devTools; - final DevHandler _devHandler; - final AssetReader _assetReader; - final bool _enableDebugging; - final bool _useDwdsWebSocketConnection; - - Dwds._( - this.middleware, - this._devTools, - this._devHandler, - this._assetReader, - this._enableDebugging, - this._useDwdsWebSocketConnection, - ) : handler = _devHandler.handler; - - Stream get connectedApps => _devHandler.connectedApps; - - Stream get events => eventStream; - - StreamController get extensionDebugConnections => - _devHandler.extensionDebugConnections; - - Future stop() async { - await _devTools?.close(); - await _devHandler.close(); - await _assetReader.close(); - } - - /// Creates a debug connection for the given app connection. - /// - /// Returns a [DebugConnection] that wraps the appropriate debug services - /// based on the connection type (WebSocket or Chrome-based). - Future debugConnection(AppConnection appConnection) async { - if (!_enableDebugging) throw StateError('Debugging is not enabled.'); - - if (_useDwdsWebSocketConnection) { - return await _devHandler.createDebugConnectionForWebSocket(appConnection); - } else { - return await _devHandler.createDebugConnectionForChrome(appConnection); - } - } - - static Future start({ - required AssetReader assetReader, - required Stream buildResults, - required ConnectionProvider chromeConnection, - required ToolConfiguration toolConfiguration, - bool useDwdsWebSocketConnection = false, - }) async { - globalToolConfiguration = toolConfiguration; - final debugSettings = toolConfiguration.debugSettings; - final appMetadata = toolConfiguration.appMetadata; - DevTools? devTools; - Future? extensionUri; - ExtensionBackend? extensionBackend; - if (debugSettings.enableDebugExtension) { - final handler = debugSettings.useSseForDebugBackend - ? SseSocketHandler( - SseHandler( - Uri.parse('/\$debug'), - // Proxy servers may actively kill long standing connections. - // Allow for clients to reconnect in a short window. Making the - // window too long may cause issues if the user closes a debug - // session and initiates a new one during the keepAlive window. - keepAlive: const Duration(seconds: 5), - ), - ) - : WebSocketSocketHandler(); - - extensionBackend = await ExtensionBackend.start( - handler, - appMetadata.hostname, - ); - extensionUri = Future.value( - Uri( - scheme: debugSettings.useSseForDebugBackend ? 'http' : 'ws', - host: extensionBackend.hostname, - port: extensionBackend.port, - path: r'$debug', - ).toString(), - ); - final urlEncoder = debugSettings.urlEncoder; - if (urlEncoder != null) { - extensionUri = urlEncoder(await extensionUri); - } - } - - // TODO(bkonyi): only allow for serving DevTools via DDS. - // ignore: deprecated_member_use_from_same_package - final devToolsLauncher = debugSettings.devToolsLauncher; - Uri? launchedDevToolsUri; - if (devToolsLauncher != null && - // If DDS is configured to serve DevTools, use its instance. - !debugSettings.ddsConfiguration.serveDevTools) { - devTools = await devToolsLauncher(appMetadata.hostname); - launchedDevToolsUri = Uri( - scheme: 'http', - host: devTools.hostname, - port: devTools.port, - ); - _logger.info('Serving DevTools at $launchedDevToolsUri\n'); - } - - final injected = DwdsInjector(extensionUri: extensionUri); - - final devHandler = DevHandler( - chromeConnection, - buildResults, - devTools, - assetReader, - appMetadata.hostname, - extensionBackend, - debugSettings.urlEncoder, - debugSettings.useSseForDebugProxy, - debugSettings.useSseForInjectedClient, - debugSettings.expressionCompiler, - injected, - DartDevelopmentServiceConfiguration( - // This technically isn't correct, but - // DartDevelopmentServiceConfiguration.enable is true by default, so - // this won't break unmigrated tools. - // ignore: deprecated_member_use_from_same_package - enable: debugSettings.spawnDds && debugSettings.ddsConfiguration.enable, - // ignore: deprecated_member_use_from_same_package - port: debugSettings.ddsPort ?? debugSettings.ddsConfiguration.port, - devToolsServerAddress: - launchedDevToolsUri ?? - debugSettings.ddsConfiguration.devToolsServerAddress, - serveDevTools: debugSettings.ddsConfiguration.serveDevTools, - appName: debugSettings.ddsConfiguration.appName, - dartExecutable: debugSettings.ddsConfiguration.dartExecutable, - ), - debugSettings.launchDevToolsInNewWindow, - useWebSocketConnection: useDwdsWebSocketConnection, - sseIgnoreDisconnect: debugSettings.sseIgnoreDisconnect, - ); - - return Dwds._( - injected.middleware, - devTools, - devHandler, - assetReader, - debugSettings.enableDebugging, - useDwdsWebSocketConnection, - ); - } -} diff --git a/dwds/lib/data/README.md b/dwds/lib/data/README.md deleted file mode 100644 index 17430bf363..0000000000 --- a/dwds/lib/data/README.md +++ /dev/null @@ -1,12 +0,0 @@ -# How to generate data files: - -## Creating a new data file: - -1. Create a new file for your data type in the `/data` directory with the - `.dart` extension -1. Create a class for your data type with `toJson` and `fromJson` methods (see existing files for examples) - -## To update an existing data file: - -1. Make your changes directly to the dart file. - diff --git a/dwds/lib/data/build_result.dart b/dwds/lib/data/build_result.dart deleted file mode 100644 index 0f143922bb..0000000000 --- a/dwds/lib/data/build_result.dart +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -enum BuildStatus { - started, - succeeded, - failed; - - factory BuildStatus.fromJson(String json) { - return BuildStatus.values.firstWhere( - (e) => e.name == json, - orElse: () { - throw ArgumentError('Unknown BuildStatus: $json'); - }, - ); - } - - String toJson() => name; -} - -class BuildResult { - final BuildStatus status; - - BuildResult({required this.status}); - - factory BuildResult.fromJson(Map json) { - return BuildResult(status: BuildStatus.fromJson(json['status'] as String)); - } - - Map toJson() { - return {'status': status.toJson()}; - } - - @override - bool operator ==(Object other) => - identical(this, other) || - other is BuildResult && - runtimeType == other.runtimeType && - status == other.status; - - @override - int get hashCode => status.hashCode; - - @override - String toString() => 'BuildResult(status: $status)'; -} diff --git a/dwds/lib/data/connect_request.dart b/dwds/lib/data/connect_request.dart deleted file mode 100644 index 654a97c7fd..0000000000 --- a/dwds/lib/data/connect_request.dart +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -/// A request to open DevTools. -class ConnectRequest { - /// Identifies a given application, across tabs/windows. - final String appId; - - /// Identifies a given instance of an application, unique per tab/window. - final String instanceId; - - /// The entrypoint for the Dart application. - final String entrypointPath; - - ConnectRequest({ - required this.appId, - required this.instanceId, - required this.entrypointPath, - }); - - Map toJson() => { - 'appId': appId, - 'instanceId': instanceId, - 'entrypointPath': entrypointPath, - }; - - factory ConnectRequest.fromJson(Map json) { - return ConnectRequest( - appId: json['appId'] as String, - instanceId: json['instanceId'] as String, - entrypointPath: json['entrypointPath'] as String, - ); - } -} diff --git a/dwds/lib/data/data_types.dart b/dwds/lib/data/data_types.dart deleted file mode 100644 index 11045478b7..0000000000 --- a/dwds/lib/data/data_types.dart +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'package:dwds/data/utils.dart'; - -class ConnectFailure { - static const type = 'ConnectFailure'; - final int tabId; - final String? reason; - - ConnectFailure({required this.tabId, this.reason}); - - List toJson() => [ - type, - 'tabId', - tabId, - if (reason != null) ...['reason', reason], - ]; - - factory ConnectFailure.fromJson(List jsonList) { - final json = listToMap(jsonList, type: type); - return ConnectFailure( - tabId: json['tabId'] as int, - reason: json['reason'] as String?, - ); - } - - @override - bool operator ==(Object other) => - identical(this, other) || - other is ConnectFailure && - runtimeType == other.runtimeType && - tabId == other.tabId && - reason == other.reason; - - @override - int get hashCode => Object.hash(tabId, reason); - - @override - String toString() => 'ConnectFailure(tabId: $tabId, reason: $reason)'; -} - -class DevToolsOpener { - static const type = 'DevToolsOpener'; - final bool newWindow; - - DevToolsOpener({required this.newWindow}); - - List toJson() => [type, 'newWindow', newWindow]; - - factory DevToolsOpener.fromJson(List jsonList) { - final json = listToMap(jsonList, type: type); - return DevToolsOpener(newWindow: json['newWindow'] as bool); - } - - @override - bool operator ==(Object other) => - identical(this, other) || - other is DevToolsOpener && - runtimeType == other.runtimeType && - newWindow == other.newWindow; - - @override - int get hashCode => newWindow.hashCode; - - @override - String toString() => 'DevToolsOpener(newWindow: $newWindow)'; -} - -class DevToolsUrl { - static const type = 'DevToolsUrl'; - final int tabId; - final String url; - - DevToolsUrl({required this.tabId, required this.url}); - - List toJson() => [type, 'tabId', tabId, 'url', url]; - - factory DevToolsUrl.fromJson(List jsonList) { - final json = listToMap(jsonList, type: type); - return DevToolsUrl(tabId: json['tabId'] as int, url: json['url'] as String); - } - - @override - bool operator ==(Object other) => - identical(this, other) || - other is DevToolsUrl && - runtimeType == other.runtimeType && - tabId == other.tabId && - url == other.url; - - @override - int get hashCode => Object.hash(tabId, url); - - @override - String toString() => 'DevToolsUrl(tabId: $tabId, url: $url)'; -} - -class DebugStateChange { - static const type = 'DebugStateChange'; - static const startDebugging = 'start-debugging'; - static const stopDebugging = 'stop-debugging'; - static const failedToConnect = 'failed-to-connect'; - - final int tabId; - - /// Can only be [startDebugging] or [stopDebugging]. - final String newState; - final String? reason; - - DebugStateChange({required this.tabId, required this.newState, this.reason}); - - List toJson() => [ - type, - 'tabId', - tabId, - 'newState', - newState, - if (reason != null) ...['reason', reason], - ]; - - factory DebugStateChange.fromJson(List jsonList) { - final json = listToMap(jsonList, type: type); - return DebugStateChange( - tabId: json['tabId'] as int, - newState: json['newState'] as String, - reason: json['reason'] as String?, - ); - } - - @override - bool operator ==(Object other) => - identical(this, other) || - other is DebugStateChange && - runtimeType == other.runtimeType && - tabId == other.tabId && - newState == other.newState && - reason == other.reason; - - @override - int get hashCode => Object.hash(tabId, newState, reason); - - @override - String toString() => - 'DebugStateChange(tabId: $tabId, newState: $newState, reason: $reason)'; -} diff --git a/dwds/lib/data/debug_event.dart b/dwds/lib/data/debug_event.dart deleted file mode 100644 index 34f8d96fec..0000000000 --- a/dwds/lib/data/debug_event.dart +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -class DebugEvent { - final String kind; - final String eventData; - final int timestamp; - - DebugEvent({ - required this.kind, - required this.eventData, - required this.timestamp, - }); - - factory DebugEvent.fromJson(Map json) { - return DebugEvent( - kind: json['kind'] as String, - eventData: json['eventData'] as String, - timestamp: json['timestamp'] as int, - ); - } - - Map toJson() { - return {'kind': kind, 'eventData': eventData, 'timestamp': timestamp}; - } - - @override - bool operator ==(Object other) => - identical(this, other) || - other is DebugEvent && - runtimeType == other.runtimeType && - kind == other.kind && - eventData == other.eventData && - timestamp == other.timestamp; - - @override - int get hashCode => Object.hash(kind, eventData, timestamp); - - @override - String toString() => - 'DebugEvent(kind: $kind, eventData: $eventData, timestamp: $timestamp)'; -} - -/// A batched group of events, currently always Debugger.scriptParsed -class BatchedDebugEvents { - final List events; - - BatchedDebugEvents({required this.events}); - - factory BatchedDebugEvents.fromJson(Map json) { - return BatchedDebugEvents( - events: (json['events'] as List) - .map((e) => DebugEvent.fromJson(e as Map)) - .toList(), - ); - } - - Map toJson() { - return {'events': events.map((e) => e.toJson()).toList()}; - } - - @override - bool operator ==(Object other) => - identical(this, other) || - other is BatchedDebugEvents && - runtimeType == other.runtimeType && - _listEquals(events, other.events); - - @override - int get hashCode => Object.hashAll(events); - - @override - String toString() => 'BatchedDebugEvents(events: $events)'; -} - -bool _listEquals(List? a, List? b) { - if (a == null) return b == null; - if (b == null || a.length != b.length) return false; - for (var i = 0; i < a.length; i++) { - if (a[i] != b[i]) return false; - } - return true; -} diff --git a/dwds/lib/data/debug_info.dart b/dwds/lib/data/debug_info.dart deleted file mode 100644 index a22c6d2db4..0000000000 --- a/dwds/lib/data/debug_info.dart +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'package:dwds/data/utils.dart'; - -class DebugInfo { - static const String type = 'DebugInfo'; - - final String? appEntrypointPath; - final String? appId; - final String? appInstanceId; - final String? appOrigin; - final String? appUrl; - final String? authUrl; - final String? dwdsVersion; - final String? extensionUrl; - final bool? isInternalBuild; - final bool? isFlutterApp; - final String? workspaceName; - final String? tabUrl; - final int? tabId; - - const DebugInfo({ - this.appEntrypointPath, - this.appId, - this.appInstanceId, - this.appOrigin, - this.appUrl, - this.authUrl, - this.dwdsVersion, - this.extensionUrl, - this.isInternalBuild, - this.isFlutterApp, - this.workspaceName, - this.tabUrl, - this.tabId, - }); - - /// Mimics built_value serialization for compatibility. - /// - /// Returns a list in the format: - /// ['DebugInfo', 'key1', value1, 'key2', value2, ...] - /// - /// Null values are omitted from the list. - List toJson() => [ - type, - if (appEntrypointPath != null) ...['appEntrypointPath', appEntrypointPath], - if (appId != null) ...['appId', appId], - if (appInstanceId != null) ...['appInstanceId', appInstanceId], - if (appOrigin != null) ...['appOrigin', appOrigin], - if (appUrl != null) ...['appUrl', appUrl], - if (authUrl != null) ...['authUrl', authUrl], - if (dwdsVersion != null) ...['dwdsVersion', dwdsVersion], - if (extensionUrl != null) ...['extensionUrl', extensionUrl], - if (isInternalBuild != null) ...['isInternalBuild', isInternalBuild], - if (isFlutterApp != null) ...['isFlutterApp', isFlutterApp], - if (workspaceName != null) ...['workspaceName', workspaceName], - if (tabUrl != null) ...['tabUrl', tabUrl], - if (tabId != null) ...['tabId', tabId], - ]; - - factory DebugInfo.fromJson(List list) { - final map = listToMap(list, type: type); - - return DebugInfo( - appEntrypointPath: map['appEntrypointPath'] as String?, - appId: map['appId'] as String?, - appInstanceId: map['appInstanceId'] as String?, - appOrigin: map['appOrigin'] as String?, - appUrl: map['appUrl'] as String?, - authUrl: map['authUrl'] as String?, - dwdsVersion: map['dwdsVersion'] as String?, - extensionUrl: map['extensionUrl'] as String?, - isInternalBuild: map['isInternalBuild'] as bool?, - isFlutterApp: map['isFlutterApp'] as bool?, - workspaceName: map['workspaceName'] as String?, - tabUrl: map['tabUrl'] as String?, - tabId: map['tabId'] as int?, - ); - } - - @override - bool operator ==(Object other) => - identical(this, other) || - other is DebugInfo && - runtimeType == other.runtimeType && - appEntrypointPath == other.appEntrypointPath && - appId == other.appId && - appInstanceId == other.appInstanceId && - appOrigin == other.appOrigin && - appUrl == other.appUrl && - authUrl == other.authUrl && - dwdsVersion == other.dwdsVersion && - extensionUrl == other.extensionUrl && - isInternalBuild == other.isInternalBuild && - isFlutterApp == other.isFlutterApp && - workspaceName == other.workspaceName && - tabUrl == other.tabUrl && - tabId == other.tabId; - - @override - int get hashCode => Object.hash( - appEntrypointPath, - appId, - appInstanceId, - appOrigin, - appUrl, - authUrl, - dwdsVersion, - extensionUrl, - isInternalBuild, - isFlutterApp, - workspaceName, - tabUrl, - tabId, - ); - - @override - String toString() { - return 'DebugInfo { ' - 'appEntrypointPath: $appEntrypointPath, ' - 'appId: $appId, ' - 'appInstanceId: $appInstanceId, ' - 'appOrigin: $appOrigin, ' - 'appUrl: $appUrl, ' - 'authUrl: $authUrl, ' - 'dwdsVersion: $dwdsVersion, ' - 'extensionUrl: $extensionUrl, ' - 'isInternalBuild: $isInternalBuild, ' - 'isFlutterApp: $isFlutterApp, ' - 'workspaceName: $workspaceName, ' - 'tabUrl: $tabUrl, ' - 'tabId: $tabId, ' - '}'; - } -} diff --git a/dwds/lib/data/devtools_request.dart b/dwds/lib/data/devtools_request.dart deleted file mode 100644 index 41795f242e..0000000000 --- a/dwds/lib/data/devtools_request.dart +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'package:dwds/data/utils.dart'; - -/// A request to open DevTools. -class DevToolsRequest { - static const type = 'DevToolsRequest'; - - /// Identifies a given application, across tabs/windows. - final String appId; - - /// Identifies a given instance of an application, unique per tab/window. - final String instanceId; - - /// Identifies the context in which evaluations should occur. - /// - /// Defines execution context for the debug service that connects - /// to chrome via the extension debugger. - /// Can be `null` for local debug service, which gets the execution - /// context from the Chrome runtime. - final int? contextId; - - /// Belongs to the tab that requests the DevTools. - /// - /// Defines the tab being debugged for the debug service that connects - /// to chrome via the extension debugger. - /// Can be `null` for local debug service, which finds the tab with the - /// correct `dartAppInstanceId` automatically. - final String? tabUrl; - - /// Designates this as a request to send back the DevTools URI instead of - /// opening DevTools in a new tab or window. - /// - /// Only available on requests coming from the Dart Debug Extension. Is `null` - /// for local debug service. - final bool? uriOnly; - - /// Identifies the client that DWDS is attaching to. - /// - /// This could be Cider, DevTools (as a standalone app), or DevTools (embedded - /// in Chrome DevTools). - final String? client; - - DevToolsRequest({ - required this.appId, - required this.instanceId, - this.contextId, - this.tabUrl, - this.uriOnly, - this.client, - }); - - factory DevToolsRequest.fromJson(List jsonList) { - final json = listToMap(jsonList, type: type); - return DevToolsRequest( - appId: json['appId'] as String, - instanceId: json['instanceId'] as String, - contextId: json['contextId'] as int?, - tabUrl: json['tabUrl'] as String?, - uriOnly: json['uriOnly'] as bool?, - client: json['client'] as String?, - ); - } - - List toJson() { - return [ - type, - 'appId', - appId, - 'instanceId', - instanceId, - if (contextId != null) ...['contextId', contextId], - if (tabUrl != null) ...['tabUrl', tabUrl], - if (uriOnly != null) ...['uriOnly', uriOnly], - if (client != null) ...['client', client], - ]; - } - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - return other is DevToolsRequest && - other.appId == appId && - other.instanceId == instanceId && - other.contextId == contextId && - other.tabUrl == tabUrl && - other.uriOnly == uriOnly && - other.client == client; - } - - @override - int get hashCode => - Object.hash(appId, instanceId, contextId, tabUrl, uriOnly, client); - - @override - String toString() { - return 'DevToolsRequest { ' - 'appId: $appId, ' - 'instanceId: $instanceId, ' - 'contextId: $contextId, ' - 'tabUrl: $tabUrl, ' - 'uriOnly: $uriOnly, ' - 'client: $client, ' - '}'; - } -} - -/// A response to a [DevToolsRequest]. -class DevToolsResponse { - static const type = 'DevToolsResponse'; - final bool success; - final bool promptExtension; - final String? error; - - DevToolsResponse({ - required this.success, - required this.promptExtension, - this.error, - }); - - factory DevToolsResponse.fromJson(List jsonList) { - final json = listToMap(jsonList, type: type); - return DevToolsResponse( - success: json['success'] as bool, - promptExtension: json['promptExtension'] as bool, - error: json['error'] as String?, - ); - } - - List toJson() { - return [ - type, - 'success', - success, - 'promptExtension', - promptExtension, - if (error != null) ...['error', error], - ]; - } - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - return other is DevToolsResponse && - other.success == success && - other.promptExtension == promptExtension && - other.error == error; - } - - @override - int get hashCode => Object.hash(success, promptExtension, error); - - @override - String toString() { - return 'DevToolsResponse { ' - 'success: $success, ' - 'promptExtension: $promptExtension, ' - 'error: $error }'; - } -} diff --git a/dwds/lib/data/error_response.dart b/dwds/lib/data/error_response.dart deleted file mode 100644 index a8224b94c5..0000000000 --- a/dwds/lib/data/error_response.dart +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -class ErrorResponse { - final String error; - final String stackTrace; - - ErrorResponse({required this.error, required this.stackTrace}); - - factory ErrorResponse.fromJson(Map json) { - return ErrorResponse( - error: json['error'] as String, - stackTrace: json['stackTrace'] as String, - ); - } - - Map toJson() { - return {'error': error, 'stackTrace': stackTrace}; - } - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - return other is ErrorResponse && - other.error == error && - other.stackTrace == stackTrace; - } - - @override - int get hashCode => Object.hash(error, stackTrace); - - @override - String toString() => 'ErrorResponse(error: $error, stackTrace: $stackTrace)'; -} diff --git a/dwds/lib/data/extension_request.dart b/dwds/lib/data/extension_request.dart deleted file mode 100644 index cf87d905f1..0000000000 --- a/dwds/lib/data/extension_request.dart +++ /dev/null @@ -1,204 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:convert'; - -import 'package:collection/collection.dart'; -import 'package:dwds/data/utils.dart'; - -const authenticationPath = '\$dwdsExtensionAuthentication'; - -/// A request to run a command in the Dart Debug Extension. -class ExtensionRequest { - static const type = 'ExtensionRequest'; - - /// Used to associate a request with an [ExtensionResponse]. - final int id; - - final String command; - - /// Contains JSON-encoded parameters, if available. - final String? commandParams; - - ExtensionRequest({ - required this.id, - required this.command, - this.commandParams, - }); - - factory ExtensionRequest.fromJson(List jsonList) { - final json = listToMap(jsonList, type: type); - return ExtensionRequest( - id: json['id'] as int, - command: json['command'] as String, - commandParams: json['commandParams'] as String?, - ); - } - - List toJson() { - return [ - type, - 'id', - id, - 'command', - command, - if (commandParams != null) ...['commandParams', commandParams], - ]; - } - - @override - String toString() => - 'ExtensionRequest { id=$id, command=$command, ' - 'commandParams=$commandParams }'; - - @override - bool operator ==(Object other) => - identical(this, other) || - other is ExtensionRequest && - runtimeType == other.runtimeType && - id == other.id && - command == other.command && - commandParams == other.commandParams; - - @override - int get hashCode => Object.hash(id, command, commandParams); -} - -/// A response to an [ExtensionRequest]. -class ExtensionResponse { - static const type = 'ExtensionResponse'; - - /// Used to associate a response with an [ExtensionRequest]. - final int id; - - final bool success; - - /// Contains a JSON-encoded payload. - final String result; - - /// Contains an error, if available. - final String? error; - - ExtensionResponse({ - required this.id, - required this.success, - required this.result, - this.error, - }); - - factory ExtensionResponse.fromJson(List jsonList) { - final json = listToMap(jsonList, type: type); - return ExtensionResponse( - id: json['id'] as int, - success: json['success'] as bool, - result: json['result'] as String, - error: json['error'] as String?, - ); - } - - List toJson() { - return [ - type, - 'id', - id, - 'success', - success, - 'result', - result, - if (error != null) ...['error', error], - ]; - } - - @override - String toString() => - 'ExtensionResponse { id=$id, success=$success, ' - 'result=$result, error=$error }'; - - @override - bool operator ==(Object other) => - identical(this, other) || - other is ExtensionResponse && - runtimeType == other.runtimeType && - id == other.id && - success == other.success && - result == other.result && - error == other.error; - - @override - int get hashCode => Object.hash(id, success, result, error); -} - -/// An event for Dart Debug Extension. -class ExtensionEvent { - static const type = 'ExtensionEvent'; - - /// Contains a JSON-encoded payload. - final String params; - - final String method; - - ExtensionEvent({required this.params, required this.method}); - - factory ExtensionEvent.fromJson(List jsonList) { - final firstElement = jsonList.isEmpty ? null : jsonList.first; - final json = listToMap(jsonList, type: firstElement == type ? type : null); - final params = json['params']; - return ExtensionEvent( - params: params is String ? params : jsonEncode(params), - method: json['method'] as String, - ); - } - - List toJson() { - return [type, 'params', params, 'method', method]; - } - - @override - String toString() => 'ExtensionEvent { params=$params, method=$method }'; - - @override - bool operator ==(Object other) => - identical(this, other) || - other is ExtensionEvent && - runtimeType == other.runtimeType && - params == other.params && - method == other.method; - - @override - int get hashCode => Object.hash(params, method); -} - -/// A batched group of events, currently always Debugger.scriptParsed -class BatchedEvents { - static const type = 'BatchedEvents'; - final List events; - - BatchedEvents({required this.events}); - - factory BatchedEvents.fromJson(List jsonList) { - final json = listToMap(jsonList, type: type); - return BatchedEvents( - events: (json['events'] as List) - .map((e) => ExtensionEvent.fromJson(e as List)) - .toList(), - ); - } - - List toJson() { - return [type, 'events', events.map((e) => e.toJson()).toList()]; - } - - @override - String toString() => 'BatchedEvents { events=$events }'; - - @override - bool operator ==(Object other) => - identical(this, other) || - other is BatchedEvents && - runtimeType == other.runtimeType && - const ListEquality().equals(events, other.events); - - @override - int get hashCode => Object.hashAll(events); -} diff --git a/dwds/lib/data/hot_reload_request.dart b/dwds/lib/data/hot_reload_request.dart deleted file mode 100644 index 048e482a2d..0000000000 --- a/dwds/lib/data/hot_reload_request.dart +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -/// A request to hot reload the application. -class HotReloadRequest { - /// A unique identifier for this request. - final String id; - - HotReloadRequest({required this.id}); - - /// Creates a [HotReloadRequest] from a JSON map. - factory HotReloadRequest.fromJson(Map json) { - return HotReloadRequest(id: json['id'] as String); - } - - /// Converts this [HotReloadRequest] to a JSON map. - Map toJson() => {'id': id}; - - @override - bool operator ==(Object other) => - identical(other, this) || other is HotReloadRequest && id == other.id; - - @override - int get hashCode => id.hashCode; - - @override - String toString() => 'HotReloadRequest(id: $id)'; -} diff --git a/dwds/lib/data/hot_reload_response.dart b/dwds/lib/data/hot_reload_response.dart deleted file mode 100644 index e4fd41776d..0000000000 --- a/dwds/lib/data/hot_reload_response.dart +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -/// A response to a hot reload request. -class HotReloadResponse { - /// The unique identifier matching the request. - final String id; - - /// Whether the hot reload succeeded on the client. - final bool success; - - /// An optional error message if success is false. - final String? errorMessage; - - HotReloadResponse({ - required this.id, - required this.success, - this.errorMessage, - }); - - /// Creates a [HotReloadResponse] from a JSON map. - factory HotReloadResponse.fromJson(Map json) { - return HotReloadResponse( - id: json['id'] as String, - success: json['success'] as bool, - errorMessage: json['error'] as String?, - ); - } - - /// Converts this [HotReloadResponse] to a JSON map. - Map toJson() => { - 'id': id, - 'success': success, - if (errorMessage != null) 'error': errorMessage, - }; - - @override - bool operator ==(Object other) => - identical(other, this) || - other is HotReloadResponse && - id == other.id && - success == other.success && - errorMessage == other.errorMessage; - - @override - int get hashCode => Object.hash(id, success, errorMessage); - - @override - String toString() => - 'HotReloadResponse(id: $id, success: $success, ' - 'errorMessage: $errorMessage)'; -} diff --git a/dwds/lib/data/hot_restart_request.dart b/dwds/lib/data/hot_restart_request.dart deleted file mode 100644 index bd2f9a4329..0000000000 --- a/dwds/lib/data/hot_restart_request.dart +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -/// A request to hot restart the application. -class HotRestartRequest { - /// A unique identifier for this request. - final String id; - - HotRestartRequest({required this.id}); - - /// Creates a [HotRestartRequest] from a JSON map. - factory HotRestartRequest.fromJson(Map json) { - return HotRestartRequest(id: json['id'] as String); - } - - /// Converts this [HotRestartRequest] to a JSON map. - Map toJson() => {'id': id}; - - @override - bool operator ==(Object other) => - identical(other, this) || other is HotRestartRequest && id == other.id; - - @override - int get hashCode => id.hashCode; - - @override - String toString() => 'HotRestartRequest(id: $id)'; -} diff --git a/dwds/lib/data/hot_restart_response.dart b/dwds/lib/data/hot_restart_response.dart deleted file mode 100644 index fd4b86f2db..0000000000 --- a/dwds/lib/data/hot_restart_response.dart +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -/// A response to a hot restart request. -class HotRestartResponse { - /// The unique identifier matching the request. - final String id; - - /// Whether the hot restart succeeded on the client. - final bool success; - - /// An optional error message if success is false. - final String? errorMessage; - - HotRestartResponse({ - required this.id, - required this.success, - this.errorMessage, - }); - - factory HotRestartResponse.fromJson(Map json) => - HotRestartResponse( - id: json['id'] as String, - success: json['success'] as bool, - errorMessage: json['error'] as String?, - ); - - Map toJson() => { - 'id': id, - 'success': success, - if (errorMessage != null) 'error': errorMessage, - }; -} diff --git a/dwds/lib/data/isolate_events.dart b/dwds/lib/data/isolate_events.dart deleted file mode 100644 index 5d8efd37fa..0000000000 --- a/dwds/lib/data/isolate_events.dart +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -/// An event that signifies the main isolate has exited. -class IsolateExit { - IsolateExit(); - - factory IsolateExit.fromJson(Map _) => IsolateExit(); - - Map toJson() => {}; - - @override - String toString() => 'IsolateExit{}'; -} - -/// An event that signifies the main isolate has started. -class IsolateStart { - IsolateStart(); - - factory IsolateStart.fromJson(Map _) => IsolateStart(); - - Map toJson() => {}; - - @override - String toString() => 'IsolateStart{}'; -} diff --git a/dwds/lib/data/ping_request.dart b/dwds/lib/data/ping_request.dart deleted file mode 100644 index 66ee133dd3..0000000000 --- a/dwds/lib/data/ping_request.dart +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -/// A ping request to check client connection. -class PingRequest { - PingRequest(); - - Map toJson() => {}; - - factory PingRequest.fromJson(Map json) { - return PingRequest(); - } - - @override - bool operator ==(Object other) => - identical(this, other) || other is PingRequest; - - @override - int get hashCode => 0; - - @override - String toString() => 'PingRequest'; -} diff --git a/dwds/lib/data/register_event.dart b/dwds/lib/data/register_event.dart deleted file mode 100644 index d0f40e2f5b..0000000000 --- a/dwds/lib/data/register_event.dart +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -class RegisterEvent { - final String eventData; - final int timestamp; - - RegisterEvent({required this.eventData, required this.timestamp}); - - factory RegisterEvent.fromJson(Map json) { - return RegisterEvent( - eventData: json['eventData'] as String, - timestamp: json['timestamp'] as int, - ); - } - - Map toJson() { - return {'eventData': eventData, 'timestamp': timestamp}; - } - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - return other is RegisterEvent && - other.eventData == eventData && - other.timestamp == timestamp; - } - - @override - int get hashCode => Object.hash(eventData, timestamp); - - @override - String toString() => - 'RegisterEvent(eventData: $eventData, timestamp: $timestamp)'; -} diff --git a/dwds/lib/data/run_request.dart b/dwds/lib/data/run_request.dart deleted file mode 100644 index 6865aa4a90..0000000000 --- a/dwds/lib/data/run_request.dart +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -/// A request to run the application's main method. -class RunRequest { - RunRequest(); - - Map toJson() => {}; - - factory RunRequest.fromJson(Map json) { - return RunRequest(); - } -} diff --git a/dwds/lib/data/service_extension_request.dart b/dwds/lib/data/service_extension_request.dart deleted file mode 100644 index dd9e4c2950..0000000000 --- a/dwds/lib/data/service_extension_request.dart +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) 2025, the Dart project authors. All rights reserved. -// Defines the request for service extension calls over WebSocket. - -class ServiceExtensionRequest { - final String id; - final String method; - final Map args; - - ServiceExtensionRequest({ - required this.id, - required this.method, - Map? args, - }) : args = args ?? const {}; - - factory ServiceExtensionRequest.fromArgs({ - required String id, - required String method, - required Map args, - }) => ServiceExtensionRequest(id: id, method: method, args: args); - - factory ServiceExtensionRequest.fromJson(Map json) => - ServiceExtensionRequest( - id: json['id'] as String, - method: json['method'] as String, - args: - (json['args'] as Map?)?.cast() ?? - const {}, - ); - - Map toJson() => {'id': id, 'method': method, 'args': args}; -} diff --git a/dwds/lib/data/service_extension_response.dart b/dwds/lib/data/service_extension_response.dart deleted file mode 100644 index f2013aa721..0000000000 --- a/dwds/lib/data/service_extension_response.dart +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) 2025, the Dart project authors. All rights reserved. -// Defines the response for service extension calls over WebSocket. - -class ServiceExtensionResponse { - final String id; - final bool success; - final Map? result; - final int? errorCode; - final String? errorMessage; - - ServiceExtensionResponse({ - required this.id, - required this.success, - this.result, - this.errorCode, - this.errorMessage, - }); - - factory ServiceExtensionResponse.fromResult({ - required String id, - required bool success, - Map? result, - int? errorCode, - String? errorMessage, - }) => ServiceExtensionResponse( - id: id, - success: success, - result: result, - errorCode: errorCode, - errorMessage: errorMessage, - ); - - factory ServiceExtensionResponse.fromJson(Map json) => - ServiceExtensionResponse( - id: json['id'] as String, - success: json['success'] as bool, - result: (json['result'] as Map?)?.cast(), - errorCode: json['errorCode'] as int?, - errorMessage: json['errorMessage'] as String?, - ); - - Map toJson() => { - 'id': id, - 'success': success, - if (result != null) 'result': result, - if (errorCode != null) 'errorCode': errorCode, - if (errorMessage != null) 'errorMessage': errorMessage, - }; -} diff --git a/dwds/lib/data/utils.dart b/dwds/lib/data/utils.dart deleted file mode 100644 index ff543a47e1..0000000000 --- a/dwds/lib/data/utils.dart +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -/// Converts a list of key-value pairs into a map. -/// -/// The list is expected to be in the format: -/// ['key1', value1, 'key2', value2, ...] -/// -/// Or, if [type] is provided: -/// ['Type', 'key1', value1, 'key2', value2, ...] -/// -/// If [type] is provided, the first element of the list must match [type], -/// and the key-value pairs start from the second element. -Map listToMap(List list, {String? type}) { - var startIndex = 0; - if (type != null) { - if (list.isEmpty || list.first != type) { - throw FormatException('Expected "$type" as first element', list); - } - startIndex = 1; - } - - if ((list.length - startIndex).isOdd) { - throw FormatException( - 'Expected an even number of elements' - '${type != null ? " after $type" : ""}', - list, - ); - } - final map = {}; - var i = startIndex; - while (i < list.length - 1) { - final key = list[i] as String; - final value = list[i + 1]; - map[key] = value; - i += 2; - } - return map; -} diff --git a/dwds/lib/dwds.dart b/dwds/lib/dwds.dart deleted file mode 100644 index 97c735fd8a..0000000000 --- a/dwds/lib/dwds.dart +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -export 'dart_web_debug_service.dart' show ConnectionProvider, Dwds; -export 'src/config/tool_configuration.dart' - show - AppMetadata, - DartDevelopmentServiceConfiguration, - DebugSettings, - DevToolsLauncher, - ToolConfiguration, - UrlEncoder; -export 'src/connections/app_connection.dart' show AppConnection; -export 'src/connections/debug_connection.dart' show DebugConnection; -export 'src/debugging/metadata/provider.dart' - show AbsoluteImportUriException, MetadataProvider; -export 'src/events.dart' show DwdsEvent; -export 'src/handlers/dev_handler.dart' show AppConnectionException; -export 'src/handlers/socket_connections.dart'; -export 'src/loaders/build_runner_strategy_provider.dart' - show - BuildRunnerDdcLibraryBundleStrategyProvider, - BuildRunnerRequireStrategyProvider; -export 'src/loaders/ddc.dart' show DdcStrategy; -export 'src/loaders/frontend_server_strategy_provider.dart' - show - FrontendServerDdcLibraryBundleStrategyProvider, - FrontendServerDdcStrategyProvider, - FrontendServerRequireStrategyProvider; -export 'src/loaders/require.dart' show RequireStrategy; -export 'src/loaders/strategy.dart' - show - BuildSettings, - LoadStrategy, - ReloadConfiguration, - ReloadableLoadStrategy; -export 'src/readers/asset_reader.dart' show AssetReader, PackageUriMapper; -export 'src/readers/frontend_server_asset_reader.dart' - show FrontendServerAssetReader; -export 'src/readers/proxy_server_asset_reader.dart' show ProxyServerAssetReader; -export 'src/servers/devtools.dart'; -export 'src/services/chrome/chrome_debug_exception.dart' - show ChromeDebugException; -export 'src/services/expression_compiler.dart' - show - CompilerOptions, - ExpressionCompilationResult, - ExpressionCompiler, - ModuleInfo; -export 'src/services/expression_compiler_service.dart' - show ExpressionCompilerService; -export 'src/utilities/ddc_names.dart'; -export 'src/utilities/sdk_configuration.dart' - show SdkConfiguration, SdkConfigurationProvider, SdkLayout; diff --git a/dwds/lib/expression_compiler.dart b/dwds/lib/expression_compiler.dart deleted file mode 100644 index d020be8acc..0000000000 --- a/dwds/lib/expression_compiler.dart +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -export 'src/services/expression_compiler.dart' - show - CompilerOptions, - ExpressionCompilationResult, - ExpressionCompiler, - ModuleFormat, - ModuleInfo; diff --git a/dwds/lib/sdk_configuration.dart b/dwds/lib/sdk_configuration.dart deleted file mode 100644 index b4608c7e69..0000000000 --- a/dwds/lib/sdk_configuration.dart +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -export 'src/utilities/sdk_configuration.dart' - show - DefaultSdkConfigurationProvider, - SdkConfiguration, - SdkConfigurationProvider, - SdkLayout; diff --git a/dwds/lib/shared/README.md b/dwds/lib/shared/README.md deleted file mode 100644 index c195ebbb0b..0000000000 --- a/dwds/lib/shared/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# Shared directory - -The files in this directory are shared between DWDS and external packages, -such as the [Dart Debug Extension](https://dart.dev/to/web-debug-extension). diff --git a/dwds/lib/shared/batched_stream.dart b/dwds/lib/shared/batched_stream.dart deleted file mode 100644 index b44ce2c36f..0000000000 --- a/dwds/lib/shared/batched_stream.dart +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:async'; -import 'dart:math'; - -import 'package:async/async.dart'; -import 'package:dwds/src/utilities/shared.dart'; - -/// Stream controller allowing to batch events. -class BatchedStreamController { - static const _defaultBatchDelayMilliseconds = 1000; - - final int _checkDelayMilliseconds; - final int _batchDelayMilliseconds; - - final StreamController _inputController; - late StreamQueue _inputQueue; - - final StreamController> _outputController; - final Completer _completer = Completer(); - - /// Create batched stream controller. - /// - /// Collects events from input [sink] and emits them in batches to the - /// output [stream] every [delay] milliseconds. Keeps the original order. - BatchedStreamController({int delay = _defaultBatchDelayMilliseconds}) - : _batchDelayMilliseconds = delay, - _checkDelayMilliseconds = max(delay ~/ 10, 1), - _inputController = StreamController(), - _outputController = StreamController>() { - _inputQueue = StreamQueue(_inputController.stream); - safeUnawaited(_batchAndSendEvents()); - } - - /// Sink collecting events. - StreamSink get sink => _inputController.sink; - - /// Output stream of batch events. - Stream> get stream => _outputController.stream; - - /// Close the controller. - Future close() { - safeUnawaited(_inputController.close()); - return _completer.future.then((value) => _outputController.close()); - } - - /// Send events to the output in a batch every [_batchDelayMilliseconds]. - Future _batchAndSendEvents() async { - final duration = Duration(milliseconds: _checkDelayMilliseconds); - final buffer = []; - - // Batch events every `_batchDelayMilliseconds`. - // - // Note that events might arrive at random intervals, so collecting - // a predetermined number of events to send in a batch might delay - // the batch indefinitely. Instead, check for new events every - // `_checkDelayMilliseconds` to make sure batches are sent in regular - // intervals. - var lastSendTime = DateTime.now().millisecondsSinceEpoch; - while (await _hasEventOrTimeOut(duration)) { - if (await _hasEventDuring(duration)) { - buffer.add(await _inputQueue.next); - } - - final now = DateTime.now().millisecondsSinceEpoch; - if (now > lastSendTime + _batchDelayMilliseconds) { - lastSendTime = now; - if (buffer.isNotEmpty) { - _outputController.sink.add(List.of(buffer)); - buffer.clear(); - } - } - } - - if (buffer.isNotEmpty) { - _outputController.sink.add(List.of(buffer)); - } - _completer.complete(true); - } - - Future _hasEventOrTimeOut(Duration duration) => - _inputQueue.hasNext.timeout(duration, onTimeout: () => true); - - Future _hasEventDuring(Duration duration) => - _inputQueue.hasNext.timeout(duration, onTimeout: () => false); -} diff --git a/dwds/lib/src/config/tool_configuration.dart b/dwds/lib/src/config/tool_configuration.dart deleted file mode 100644 index 37d0f8396b..0000000000 --- a/dwds/lib/src/config/tool_configuration.dart +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'package:dwds/src/loaders/strategy.dart'; -import 'package:dwds/src/servers/devtools.dart'; -import 'package:dwds/src/services/expression_compiler.dart'; - -/// Configuration about the app, debug settings, and file system. -/// -/// This is set by the code runner and passed to DWDS on start up. -class ToolConfiguration { - final LoadStrategy loadStrategy; - final DebugSettings debugSettings; - final AppMetadata appMetadata; - - const ToolConfiguration({ - required this.loadStrategy, - required this.debugSettings, - required this.appMetadata, - }); -} - -/// The tool configuration for the connected app. -/// -/// TODO(elliette): Consider making this final (would require updating tests -/// that currently depend on changing the configuration between test cases). -late ToolConfiguration _globalToolConfiguration; -set globalToolConfiguration(ToolConfiguration configuration) => - _globalToolConfiguration = configuration; -ToolConfiguration get globalToolConfiguration => _globalToolConfiguration; - -/// Metadata for the connected app. -/// -/// These are set by the code runner and passed to DWDS on start up. -class AppMetadata { - final String hostname; - final bool isInternalBuild; - final String? workspaceName; - final String? codeRunner; - - const AppMetadata({ - this.hostname = 'localhost', - this.isInternalBuild = false, - this.workspaceName, - this.codeRunner, - }); -} - -typedef UrlEncoder = Future Function(String url); - -typedef DevToolsLauncher = Future Function(String hostname); - -class DartDevelopmentServiceConfiguration { - const DartDevelopmentServiceConfiguration({ - this.enable = true, - this.port, - this.serveDevTools = true, - this.devToolsServerAddress, - this.appName, - this.dartExecutable, - }); - - final bool enable; - final int? port; - final bool serveDevTools; - final Uri? devToolsServerAddress; - final String? appName; - final String? dartExecutable; -} - -/// Debug settings for the connected app. -/// -/// These are set by the code runner and passed to DWDS on start up. -class DebugSettings { - final bool enableDebugging; - final bool enableDebugExtension; - final bool useSseForDebugProxy; - final bool useSseForDebugBackend; - final bool useSseForInjectedClient; - - @Deprecated('Use ddsConfiguration instead.') - final bool spawnDds; - @Deprecated('Use ddsConfiguration instead.') - final int? ddsPort; - final bool enableDevToolsLaunch; - final bool launchDevToolsInNewWindow; - final bool emitDebugEvents; - @Deprecated( - 'Use ddsConfigurationInstead. DevTools will eventually only be ' - 'served via DDS.', - ) - final DevToolsLauncher? devToolsLauncher; - final ExpressionCompiler? expressionCompiler; - final UrlEncoder? urlEncoder; - final DartDevelopmentServiceConfiguration ddsConfiguration; - final Duration? sseIgnoreDisconnect; - - const DebugSettings({ - this.enableDebugging = true, - this.enableDebugExtension = false, - this.useSseForDebugProxy = true, - this.useSseForDebugBackend = true, - this.useSseForInjectedClient = true, - @Deprecated('Use ddsConfiguration instead.') this.spawnDds = true, - @Deprecated('Use ddsConfiguration instead.') this.ddsPort, - this.enableDevToolsLaunch = true, - this.launchDevToolsInNewWindow = true, - this.emitDebugEvents = true, - @Deprecated( - 'Use ddsConfigurationInstead. DevTools will eventually only be ' - 'served via DDS.', - ) - this.devToolsLauncher, - this.expressionCompiler, - this.urlEncoder, - this.ddsConfiguration = const DartDevelopmentServiceConfiguration(), - this.sseIgnoreDisconnect, - }); -} diff --git a/dwds/lib/src/connections/app_connection.dart b/dwds/lib/src/connections/app_connection.dart deleted file mode 100644 index 890390477b..0000000000 --- a/dwds/lib/src/connections/app_connection.dart +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:async'; -import 'dart:convert'; - -import 'package:dwds/data/connect_request.dart'; -import 'package:dwds/data/hot_restart_request.dart'; -import 'package:dwds/data/run_request.dart'; -import 'package:dwds/src/handlers/socket_connections.dart'; -import 'package:dwds/src/utilities/shared.dart'; - -/// A connection between the application loaded in the browser and DWDS. -class AppConnection { - /// The initial connection request sent from the application in the browser. - final ConnectRequest request; - final _startedCompleter = Completer(); - final _doneCompleter = Completer(); - final SocketConnection _connection; - final Future _readyToRunMain; - - bool get hasStarted => _startedCompleter.isCompleted; - - AppConnection(this.request, this._connection, this._readyToRunMain) { - safeUnawaited(_connection.sink.done.then((v) => _doneCompleter.complete())); - } - - bool get isInKeepAlivePeriod => _connection.isInKeepAlivePeriod; - void shutDown() => _connection.shutdown(); - bool get isStarted => _startedCompleter.isCompleted; - Future get onStart => _startedCompleter.future; - bool get isDone => _doneCompleter.isCompleted; - Future get onDone => _doneCompleter.future; - - void runMain() { - if (_startedCompleter.isCompleted) { - throw StateError('Main has already started.'); - } - - safeUnawaited(_runMain()); - } - - Future _runMain() async { - await _readyToRunMain; - _connection.sink.add(jsonEncode(['RunRequest', RunRequest().toJson()])); - _startedCompleter.complete(); - } - - /// The request to restart when no debugger attached. - /// - /// In this case, there's no need to block main execution until the debugger - /// resends breakpoints. - void hotRestart(HotRestartRequest request) => - _connection.sink.add(jsonEncode(['HotRestartRequest', request.toJson()])); -} diff --git a/dwds/lib/src/connections/debug_connection.dart b/dwds/lib/src/connections/debug_connection.dart deleted file mode 100644 index 9cc9e24825..0000000000 --- a/dwds/lib/src/connections/debug_connection.dart +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:async'; - -import 'package:dwds/src/services/app_debug_services.dart'; -import 'package:dwds/src/services/chrome/chrome_proxy_service.dart'; -import 'package:vm_service/vm_service.dart'; - -/// A debug connection between the application in the browser and DWDS. -/// -/// Supports debugging your running application through the Dart VM Service -/// Protocol. -class DebugConnection { - final AppDebugServices _appDebugServices; - final _onDoneCompleter = Completer(); - - /// Null until [close] is called. - /// - /// All subsequent calls to [close] will return this future. - Future? _closed; - - DebugConnection(this._appDebugServices) { - // Only setup Chrome-specific close handling if we have a ChromeProxyService - final proxyService = _appDebugServices.proxyService; - if (proxyService is ChromeProxyService) { - proxyService.remoteDebugger.onClose.first.then((_) => close()); - } - } - - /// The port of the host Dart VM Service. - int get port => _appDebugServices.debugService.port; - - /// The endpoint of the Dart VM Service. - String get uri => _appDebugServices.debugService.uri; - - /// The endpoint of the Dart Development Service (DDS). - String? get ddsUri => _appDebugServices.ddsUri?.toString(); - - /// The endpoint of the Dart DevTools instance. - String? get devToolsUri => _appDebugServices.devToolsUri?.toString(); - - /// The endpoint of the Dart Tooling Daemon (DTD). - String? get dtdUri => _appDebugServices.dtdUri?.toString(); - - /// A client of the Dart VM Service with DWDS specific extensions. - VmService get vmService => _appDebugServices.dwdsVmClient.client; - - Future close() => _closed ??= () async { - final proxyService = _appDebugServices.proxyService; - if (proxyService is ChromeProxyService) { - await proxyService.remoteDebugger.close(); - } - await _appDebugServices.close(); - _onDoneCompleter.complete(); - }(); - - Future get onDone => _onDoneCompleter.future; -} - -/// [ChromeProxyService] of a [DebugConnection] for internal use only. -ChromeProxyService fetchChromeProxyService(DebugConnection debugConnection) { - final service = debugConnection._appDebugServices.proxyService; - if (service is ChromeProxyService) { - return service; - } - throw StateError('ChromeProxyService not available in this debug connection'); -} diff --git a/dwds/lib/src/debugging/chrome_inspector.dart b/dwds/lib/src/debugging/chrome_inspector.dart deleted file mode 100644 index ec10b77313..0000000000 --- a/dwds/lib/src/debugging/chrome_inspector.dart +++ /dev/null @@ -1,681 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:math' as math; - -import 'package:dwds/src/config/tool_configuration.dart'; -import 'package:dwds/src/connections/app_connection.dart'; -import 'package:dwds/src/debugging/classes.dart'; -import 'package:dwds/src/debugging/debugger.dart'; -import 'package:dwds/src/debugging/execution_context.dart'; -import 'package:dwds/src/debugging/inspector.dart'; -import 'package:dwds/src/debugging/instance.dart'; -import 'package:dwds/src/debugging/libraries.dart'; -import 'package:dwds/src/debugging/location.dart'; -import 'package:dwds/src/debugging/metadata/provider.dart'; -import 'package:dwds/src/debugging/remote_debugger.dart'; -import 'package:dwds/src/readers/asset_reader.dart'; -import 'package:dwds/src/utilities/conversions.dart'; -import 'package:dwds/src/utilities/dart_uri.dart'; -import 'package:dwds/src/utilities/domain.dart'; -import 'package:dwds/src/utilities/objects.dart'; -import 'package:dwds/src/utilities/server.dart'; -import 'package:dwds/src/utilities/shared.dart'; -import 'package:logging/logging.dart'; -import 'package:vm_service/vm_service.dart'; -import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'; - -/// An inspector for a running Dart application contained in the -/// [WipConnection]. -/// -/// Provides information about currently loaded scripts and objects and support -/// for eval. -class ChromeAppInspector extends AppInspector { - final _logger = Logger('AppInspector'); - - final RemoteDebugger remoteDebugger; - final ExecutionContext _executionContext; - - @override - late final ChromeLibraryHelper libraryHelper = ChromeLibraryHelper(this); - - late ChromeAppClassHelper _classHelper; - late ChromeAppInstanceHelper _instanceHelper; - - final AssetReader _assetReader; - final Locations _locations; - - /// JavaScript expression that evaluates to the Dart stack trace mapper. - static const stackTraceMapperExpression = '\$dartStackTraceUtility.mapper'; - - /// Regex used to extract the message from an exception description. - static final exceptionMessageRegex = RegExp(r'^.*$', multiLine: true); - - /// Regex used to extract a stack trace line from the exception description. - static final stackTraceLineRegex = RegExp(r'^\s*at\s.*$', multiLine: true); - - ChromeAppInspector._( - super.appConnection, - super.isolate, - this.remoteDebugger, - this._assetReader, - this._locations, - super.root, - this._executionContext, - ); - - /// Reset all caches and recompute any mappings. - /// - /// Should be called across hot reloads with a valid [ModifiedModuleReport]. - @override - Future initialize({ModifiedModuleReport? modifiedModuleReport}) async { - await super.initialize(modifiedModuleReport: modifiedModuleReport); - - // TODO(srujzs): We can invalidate these in a smarter way instead of - // reinitializing when doing a hot reload, but these helpers recompute info - // on demand later and therefore are not in the critical path. - _classHelper = ChromeAppClassHelper(this); - _instanceHelper = ChromeAppInstanceHelper(this); - - // Populate the extension RPCs in the isolate. - await getExtensionRpcs(); - } - - static Future create( - AppConnection appConnection, - RemoteDebugger remoteDebugger, - AssetReader assetReader, - Locations locations, - String root, - Debugger debugger, - ExecutionContext executionContext, - ) async { - final id = createId(); - final time = DateTime.now().millisecondsSinceEpoch; - final name = 'main()'; - final isolate = Isolate( - id: id, - number: id, - name: name, - startTime: time, - runnable: true, - pauseOnExit: false, - pauseEvent: Event( - kind: EventKind.kPauseStart, - timestamp: time, - isolate: IsolateRef( - id: id, - name: name, - number: id, - isSystemIsolate: false, - ), - ), - livePorts: 0, - libraries: [], - breakpoints: [], - exceptionPauseMode: debugger.pauseState, - isSystemIsolate: false, - isolateFlags: [], - extensionRPCs: [], - ); - final inspector = ChromeAppInspector._( - appConnection, - isolate, - remoteDebugger, - assetReader, - locations, - root, - executionContext, - ); - - debugger.updateInspector(inspector); - await inspector.initialize(); - return inspector; - } - - /// Returns the ID for the execution context or null if not found. - Future get contextId async { - try { - return await _executionContext.id; - } catch (e, s) { - _logger.severe('Missing execution context ID: ', e, s); - return null; - } - } - - /// Get the value of the field named [fieldName] from [receiver]. - Future loadField(RemoteObject receiver, String fieldName) { - final load = globalToolConfiguration.loadStrategy.dartRuntimeDebugger - .getPropertyJsExpression(fieldName); - return jsCallFunctionOn(receiver, load, []); - } - - /// Call a method by name on [receiver], with arguments [positionalArgs] and - /// [namedArgs]. - Future _invokeMethod( - RemoteObject receiver, - String methodName, [ - List positionalArgs = const [], - Map namedArgs = const {}, - ]) async { - // TODO(alanknight): Support named arguments. - if (namedArgs.isNotEmpty) { - throw UnsupportedError('Named arguments are not yet supported'); - } - // We use the JS pseudo-variable 'arguments' to get the list of all - // arguments. - final send = globalToolConfiguration.loadStrategy.dartRuntimeDebugger - .callInstanceMethodJsExpression(methodName); - final remote = await jsCallFunctionOn(receiver, send, positionalArgs); - return remote; - } - - /// Calls Chrome's Runtime.callFunctionOn method. - /// - /// [evalExpression] should be a JS function definition that can accept - /// [arguments]. - Future jsCallFunctionOn( - RemoteObject receiver, - String evalExpression, - List arguments, { - bool returnByValue = false, - }) async { - final jsArguments = arguments.map(callArgumentFor).toList(); - final response = await remoteDebugger.sendCommand( - 'Runtime.callFunctionOn', - params: { - 'functionDeclaration': evalExpression, - 'arguments': jsArguments, - 'objectId': receiver.objectId, - 'returnByValue': returnByValue, - }, - ); - final result = getResultOrHandleError( - response, - evalContents: evalExpression, - ); - return RemoteObject(result); - } - - /// Calls Chrome's Runtime.callFunctionOn method with a global function. - /// - /// [evalExpression] should be a JS function definition that can accept - /// [arguments]. - Future _jsCallFunction( - String evalExpression, - List arguments, { - bool returnByValue = false, - }) async { - final jsArguments = arguments.map(callArgumentFor).toList(); - final response = await remoteDebugger.sendCommand( - 'Runtime.callFunctionOn', - params: { - 'functionDeclaration': evalExpression, - 'arguments': jsArguments, - 'executionContextId': await contextId, - 'returnByValue': returnByValue, - }, - ); - final result = getResultOrHandleError( - response, - evalContents: evalExpression, - ); - return RemoteObject(result); - } - - /// Invoke the function named [selector] on the object identified by - /// [targetId]. - /// - /// The [targetId] can be the URL of a Dart library, in which case this means - /// invoking a top-level function. The [arguments] are always strings that are - /// Dart object Ids (which can also be Chrome RemoteObject objectIds that are - /// for non-Dart JS objects.) - Future invoke( - String targetId, - String selector, [ - List arguments = const [], - ]) async { - final remoteArguments = arguments - .cast() - .map(remoteObjectFor) - .toList(); - // We special case the Dart library, where invokeMethod won't work because - // it's not really a Dart object. - if (isLibraryId(targetId)) { - final library = await getObject(targetId) as Library; - return await _invokeLibraryFunction(library, selector, remoteArguments); - } else { - return _invokeMethod( - remoteObjectFor(targetId), - selector, - remoteArguments, - ); - } - } - - /// Invoke the function named [selector] from [library] with [arguments]. - Future _invokeLibraryFunction( - Library library, - String selector, - List arguments, - ) { - final libraryUri = library.uri; - if (libraryUri == null) { - throwInvalidParam('invoke', 'library uri is null'); - } - return globalToolConfiguration.loadStrategy.id == 'ddc-library-bundle' - ? _evaluateLibraryMethodWithDdcLibraryBundle( - libraryUri, - selector, - arguments, - ) - : _evaluateInLibrary( - libraryUri, - 'function () { return this.$selector.apply(this, arguments); }', - arguments, - ); - } - - /// Evaluate [expression] by calling Chrome's Runtime.evaluate. - Future jsEvaluate( - String expression, { - bool returnByValue = false, - bool awaitPromise = false, - }) async { - // TODO(alanknight): Support a version with arguments if needed. - final response = await remoteDebugger.sendCommand( - 'Runtime.evaluate', - params: { - 'expression': expression, - 'returnByValue': returnByValue, - 'awaitPromise': awaitPromise, - 'contextId': await contextId, - }, - ); - final result = getResultOrHandleError(response, evalContents: expression); - return RemoteObject(result); - } - - /// Evaluate the JS function with source [jsFunction] in the context of - /// the library identified by [libraryUri] with [arguments]. - Future _evaluateInLibrary( - String libraryUri, - String jsFunction, - List arguments, - ) async { - final findLibraryJsExpression = globalToolConfiguration - .loadStrategy - .dartRuntimeDebugger - .callLibraryMethodJsExpression(libraryUri, jsFunction); - - final remoteLibrary = await jsEvaluate(findLibraryJsExpression); - return jsCallFunctionOn(remoteLibrary, jsFunction, arguments); - } - - /// Evaluates the specified top-level method [methodName] within the library - /// identified by [libraryUri] using the Dart Development Compiler (DDC) - /// library bundle strategy with the given optional [arguments]. - Future _evaluateLibraryMethodWithDdcLibraryBundle( - String libraryUri, - String methodName, [ - List arguments = const [], - ]) { - final expression = globalToolConfiguration.loadStrategy.dartRuntimeDebugger - .callLibraryMethodJsExpression(libraryUri, methodName); - return _jsCallFunction(expression, arguments); - } - - /// Call [function] with objects referred by [argumentIds] as arguments. - Future callFunction( - String function, - Iterable argumentIds, - ) { - final arguments = argumentIds.map(remoteObjectFor).toList(); - return _jsCallFunction(function, arguments); - } - - Future instanceRefFor(Object value) => - _instanceHelper.instanceRefFor(value); - - Future instanceFor(RemoteObject value) => - _instanceHelper.instanceFor(value); - - Future getLibrary(String objectId) async { - final libraryRef = await libraryRefFor(objectId); - if (libraryRef == null) return null; - return libraryHelper.libraryFor(libraryRef); - } - - Future getObject(String objectId, {int? offset, int? count}) async { - try { - final library = await getLibrary(objectId); - if (library != null) { - return library; - } - final clazz = await _classHelper.forObjectId(objectId); - if (clazz != null) { - return clazz; - } - final scriptRef = scriptRefsById[objectId]; - if (scriptRef != null) { - return await _getScript(scriptRef); - } - final instance = await _instanceHelper.instanceFor( - remoteObjectFor(objectId), - offset: offset, - count: count, - ); - if (instance != null) { - return instance; - } - } catch (e, s) { - _logger.fine('getObject $objectId failed', e, s); - rethrow; - } - throw UnsupportedError( - 'Only libraries, instances, classes, and scripts ' - 'are supported for getObject', - ); - } - - Future - /// - /// - /// ``` - String get basePath; - - /// Returns the contents for a source map at the provided server path, or - /// null if the resource does not exist. - Future sourceMapContents(String serverPath); - - /// Returns the contents for a dart source at the provided server path, or - /// null if the resource does not exist. - Future dartSourceContents(String serverPath); - - /// Returns the contents for the merged metadata output at the provided path, - /// or null if the resource does not exist. - Future metadataContents(String serverPath); - - /// Closes connections - Future close(); -} - -class PackageUriMapper { - final _logger = Logger('PackageUriMapper'); - final PackageConfig packageConfig; - final bool useDebuggerModuleNames; - - static Future create( - FileSystem fileSystem, - Uri packageConfigFile, { - bool useDebuggerModuleNames = false, - }) async { - final packageConfig = await loadPackageConfig( - fileSystem.file(packageConfigFile), - ); - return PackageUriMapper( - packageConfig, - useDebuggerModuleNames: useDebuggerModuleNames, - ); - } - - PackageUriMapper(this.packageConfig, {this.useDebuggerModuleNames = false}); - - /// Compute server path for package uri. - /// - /// Note: needs to match `urlForComponentUri` in javascript_bundle.dart - /// in SDK code. - String? packageUriToServerPath(Uri packageUri) { - final defaultServerPath = '/packages/${packageUri.path}'; - if (packageUri.isScheme('package')) { - if (!useDebuggerModuleNames) { - return defaultServerPath; - } - final resolvedUri = packageConfig.resolve(packageUri); - if (resolvedUri == null) { - _logger.severe('Cannot resolve package uri $packageUri'); - return defaultServerPath; - } - final package = packageConfig.packageOf(resolvedUri); - if (package == null) { - _logger.severe('Cannot find package for package uri $packageUri'); - return defaultServerPath; - } - final root = package.root; - final relativeUrl = resolvedUri.toString().replaceFirst('$root', ''); - final relativeRoot = _getRelativeRoot(root); - final ret = relativeRoot == null - ? 'packages/$relativeUrl' - : 'packages/$relativeRoot/$relativeUrl'; - return ret; - } - _logger.severe('Expected package uri, but found $packageUri'); - return null; - } - - /// Compute resolved file uri for a server path. - Uri? serverPathToResolvedUri(String serverPath) { - serverPath = stripLeadingSlashes(serverPath); - final segments = serverPath.split('/'); - if (segments.first == 'packages') { - if (!useDebuggerModuleNames) { - return packageConfig.resolve( - Uri(scheme: 'package', pathSegments: segments.skip(1)), - ); - } - final relativeRoot = segments.skip(1).first; - final relativeUrl = segments.skip(2).join('/'); - final package = packageConfig.packages.firstWhere( - (Package p) => _getRelativeRoot(p.root) == relativeRoot, - ); - final resolvedUri = package.root.resolve(relativeUrl); - - return resolvedUri; - } - _logger.severe('Expected "packages/" path, but found $serverPath'); - return null; - } -} - -String stripLeadingSlashes(String path) { - while (path.startsWith('/') || path.startsWith('\\')) { - path = path.substring(1); - } - return path; -} - -String? _getRelativeRoot(Uri root) => - root.pathSegments.lastWhereOrNull((segment) => segment.isNotEmpty); diff --git a/dwds/lib/src/readers/frontend_server_asset_reader.dart b/dwds/lib/src/readers/frontend_server_asset_reader.dart deleted file mode 100644 index a87b459f3f..0000000000 --- a/dwds/lib/src/readers/frontend_server_asset_reader.dart +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:convert'; -import 'dart:io'; - -import 'package:dwds/src/readers/asset_reader.dart'; -import 'package:logging/logging.dart'; -import 'package:package_config/package_config.dart'; -import 'package:path/path.dart' as p; - -/// A reader for Dart sources and related source maps provided by the Frontend -/// Server. -class FrontendServerAssetReader implements AssetReader { - final _logger = Logger('FrontendServerAssetReader'); - final File _mapOriginal; - final File _mapIncremental; - final File _jsonOriginal; - final File _jsonIncremental; - final String _packageRoot; - final Future _packageConfig; - final String _basePath; - - /// Map of Dart module server path to source map contents. - final _mapContents = {}; - - bool _haveReadOriginals = false; - - /// Creates a [FrontendServerAssetReader]. - /// - /// [outputPath] is the file path to the Frontend Server kernel file e.g. - /// - /// /some/path/main.dart.dill - /// - /// Corresponding `.json` and `.map` files will be read relative to - /// [outputPath]. - /// - /// [_packageRoot] is the path to the directory that contains a - /// `.dart_tool/package_config.json` file for the application. - FrontendServerAssetReader({ - required String outputPath, - required String packageRoot, - String? basePath, - }) : _packageRoot = packageRoot, - _basePath = basePath ?? '', - _mapOriginal = File('$outputPath.map'), - _mapIncremental = File('$outputPath.incremental.map'), - _jsonOriginal = File('$outputPath.json'), - _jsonIncremental = File('$outputPath.incremental.json'), - _packageConfig = loadPackageConfig( - File( - p.absolute(p.join(packageRoot, '.dart_tool/package_config.json')), - ), - ); - - @override - String get basePath => _basePath; - - @override - Future dartSourceContents(String serverPath) async { - if (serverPath.endsWith('.dart')) { - final packageConfig = await _packageConfig; - - Uri? fileUri; - if (serverPath.startsWith('packages/')) { - final packagePath = serverPath.replaceFirst('packages/', 'package:'); - fileUri = packageConfig.resolve(Uri.parse(packagePath)); - } else { - fileUri = p.toUri(p.join(_packageRoot, serverPath)); - } - if (fileUri != null) { - final source = File(fileUri.toFilePath()); - if (source.existsSync()) return source.readAsString(); - } - } - _logger.severe('Cannot find source contents for $serverPath'); - return null; - } - - @override - Future sourceMapContents(String serverPath) async { - if (serverPath.endsWith('lib.js.map')) { - if (!serverPath.startsWith('/')) serverPath = '/$serverPath'; - // Strip the .map, sources are looked up by their js path. - serverPath = p.withoutExtension(serverPath); - if (_mapContents.containsKey(serverPath)) { - return _mapContents[serverPath]; - } - } - _logger.severe('Cannot find source map contents for $serverPath'); - return null; - } - - /// Updates the internal caches by reading the Frontend Server output files. - /// - /// Will only read the incremental files on additional calls. - void updateCaches() { - if (!_haveReadOriginals) { - _updateCaches(_mapOriginal, _jsonOriginal); - _haveReadOriginals = true; - } else { - _updateCaches(_mapIncremental, _jsonIncremental); - } - } - - void _updateCaches(File map, File json) { - if (!(map.existsSync() && json.existsSync())) { - throw StateError('$map and $json do not exist.'); - } - final sourceContents = map.readAsBytesSync(); - final sourceInfo = - jsonDecode(json.readAsStringSync()) as Map; - for (final key in sourceInfo.keys) { - final info = sourceInfo[key] as Map; - final sourcemapOffsets = info['sourcemap'] as List; - _mapContents[key] = utf8.decode( - sourceContents - .getRange(sourcemapOffsets[0] as int, sourcemapOffsets[1] as int) - .toList(), - ); - } - } - - @override - Future metadataContents(String serverPath) { - // TODO(grouma) - Implement the merged metadata reader. - throw UnimplementedError(); - } - - @override - Future close() async {} -} diff --git a/dwds/lib/src/readers/proxy_server_asset_reader.dart b/dwds/lib/src/readers/proxy_server_asset_reader.dart deleted file mode 100644 index 4225ba9bd9..0000000000 --- a/dwds/lib/src/readers/proxy_server_asset_reader.dart +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:convert'; -import 'dart:io'; - -import 'package:dwds/src/readers/asset_reader.dart'; -import 'package:http/http.dart' as http; -import 'package:http/io_client.dart'; -import 'package:logging/logging.dart'; -import 'package:shelf/shelf.dart'; -import 'package:shelf_proxy/shelf_proxy.dart'; - -/// A reader for resources provided by a proxy server. -class ProxyServerAssetReader implements AssetReader { - final _logger = Logger('ProxyServerAssetReader'); - - final Handler _handler; - final http.Client? _client; - - ProxyServerAssetReader._(this._handler, this._client); - - factory ProxyServerAssetReader( - int assetServerPort, { - String root = '', - String host = 'localhost', - bool isHttps = false, - }) { - final scheme = isHttps ? 'https://' : 'http://'; - final inner = HttpClient() - ..maxConnectionsPerHost = 200 - ..idleTimeout = const Duration(seconds: 30) - ..connectionTimeout = const Duration(seconds: 30); - final client = isHttps - ? IOClient(inner..badCertificateCallback = (cert, host, port) => true) - : IOClient(inner); - var url = '$scheme$host:$assetServerPort/'; - if (root.isNotEmpty) url += '$root/'; - final handler = proxyHandler(url, client: client); - return ProxyServerAssetReader._(handler, client); - } - - ProxyServerAssetReader.fromHandler(this._handler) : _client = null; - - @override - String get basePath => ''; - - @override - Future dartSourceContents(String serverPath) => - _readResource(serverPath); - - @override - Future sourceMapContents(String serverPath) => - _readResource(serverPath); - - Future _readResource(String path) async { - // Handlers expect a fully formed HTML URI. The actual hostname and port - // does not matter. - final request = Request( - 'GET', - Uri.parse('http://foo:0000/$path'), - ).change(headers: {'requested-by': 'DWDS'}); - final response = await _handler(request); - - if (response.statusCode != HttpStatus.ok) { - _logger.warning(''' - Failed to load asset at path: $path. - - Status code: ${response.statusCode} - - Headers: - ${const JsonEncoder.withIndent(' ').convert(response.headers)} - '''); - return null; - } else { - return await response.readAsString(); - } - } - - @override - Future metadataContents(String serverPath) => - _readResource(serverPath); - - @override - Future close() async => _client?.close(); -} diff --git a/dwds/lib/src/servers/devtools.dart b/dwds/lib/src/servers/devtools.dart deleted file mode 100644 index c52a07908d..0000000000 --- a/dwds/lib/src/servers/devtools.dart +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:io'; - -/// A server for Dart Devtools. -class DevTools { - final String hostname; - final int port; - final HttpServer _server; - - Uri get uri => Uri(scheme: 'http', host: hostname, port: port); - - /// Null until [close] is called. - /// - /// All subsequent calls to [close] will return this future. - Future? _closed; - - DevTools(this.hostname, this.port, this._server); - - Future close() => _closed ??= _server.close(); -} diff --git a/dwds/lib/src/servers/extension_backend.dart b/dwds/lib/src/servers/extension_backend.dart deleted file mode 100644 index 80152c5cfd..0000000000 --- a/dwds/lib/src/servers/extension_backend.dart +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:io'; - -import 'package:async/async.dart'; -import 'package:dwds/data/extension_request.dart'; -import 'package:dwds/src/events.dart'; -import 'package:dwds/src/handlers/socket_connections.dart'; -import 'package:dwds/src/servers/extension_debugger.dart'; -import 'package:dwds/src/utilities/server.dart'; -import 'package:logging/logging.dart'; -import 'package:shelf/shelf.dart'; - -const authenticationResponse = - 'Dart Debug Authentication Success!\n\n' - 'You can close this tab and launch the Dart Debug Extension again.'; - -/// A backend for the Dart Debug Extension. -/// -/// Sets up an SSE handler to communicate with the extension background. -/// Uses that SSE channel to create an [ExtensionDebugger]. -class ExtensionBackend { - static final _logger = Logger('ExtensionBackend'); - final String hostname; - final int port; - final HttpServer _server; - - /// Null until [close] is called. - /// - /// All subsequent calls to [close] will return this future. - Future? _closed; - - ExtensionBackend._( - SocketHandler socketHandler, - this.hostname, - this.port, - this._server, - ) : connections = socketHandler.connections; - - // Starts the backend on an open port. - static Future start( - SocketHandler socketHandler, - String hostname, - ) async { - var cascade = Cascade(); - cascade = cascade - .add((request) { - if (request.url.path == authenticationPath) { - return Response.ok( - authenticationResponse, - headers: { - if (request.headers.containsKey('origin')) - 'Access-Control-Allow-Origin': request.headers['origin']!, - 'Access-Control-Allow-Credentials': 'true', - }, - ); - } - return Response.notFound(''); - }) - .add(socketHandler.handler); - final server = await startHttpServer(hostname); - serveHttpRequests(server, cascade.handler, (e, s) { - _logger.warning('Error serving requests', e); - emitEvent(DwdsEvent.httpRequestException('ExtensionBackend', '$e:$s')); - }); - return ExtensionBackend._( - socketHandler, - server.address.host, - server.port, - server, - ); - } - - Future close() => _closed ??= _server.close(); - - final StreamQueue connections; - - Future get extensionDebugger async => - ExtensionDebugger(await connections.next); -} diff --git a/dwds/lib/src/servers/extension_debugger.dart b/dwds/lib/src/servers/extension_debugger.dart deleted file mode 100644 index 8240b86cf5..0000000000 --- a/dwds/lib/src/servers/extension_debugger.dart +++ /dev/null @@ -1,395 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:async'; -import 'dart:collection'; -import 'dart:convert'; - -import 'package:dwds/data/devtools_request.dart'; -import 'package:dwds/data/extension_request.dart'; -import 'package:dwds/src/debugging/execution_context.dart'; -import 'package:dwds/src/debugging/remote_debugger.dart'; -import 'package:dwds/src/handlers/socket_connections.dart'; -import 'package:dwds/src/services/chrome/chrome_debug_exception.dart'; -import 'package:logging/logging.dart'; -import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart' - hide StackTrace; - -final _logger = Logger('ExtensionDebugger'); - -/// A remote debugger backed by the Dart Debug Extension with an SSE connection. -class ExtensionDebugger implements RemoteDebugger { - /// A connection between the debugger and the background of - /// Dart Debug Extension - final SocketConnection sseConnection; - - /// A map from id to a completer associated with an [ExtensionRequest] - final _completers = {}; - final _eventStreams = {}; - var _completerId = 0; - - @override - Future Function()? onReconnect; - - /// Null until [close] is called. - /// - /// All subsequent calls to [close] will return this future. - Future? _closed; - - String? instanceId; - ExecutionContext? _executionContext; - - ExecutionContext? get executionContext => _executionContext; - - final _devToolsRequestController = StreamController(); - - Stream get devToolsRequestStream => - _devToolsRequestController.stream; - - final _notificationController = StreamController.broadcast(); - - Stream get onNotification => _notificationController.stream; - - final _closeController = StreamController.broadcast(); - - @override - Stream get onClose => _closeController.stream; - - @override - Stream get onConsoleAPICalled => eventStream( - 'Runtime.consoleAPICalled', - (WipEvent event) => ConsoleAPIEvent(event.json), - ); - - @override - Stream get onExceptionThrown => eventStream( - 'Runtime.exceptionThrown', - (WipEvent event) => ExceptionThrownEvent(event.json), - ); - - final _scripts = {}; - final _scriptIds = {}; - - ExtensionDebugger(this.sseConnection) { - sseConnection.stream.listen( - (data) { - final decoded = jsonDecode(data); - final message = _deserialize(decoded); - if (message is ExtensionResponse) { - final encodedResult = { - 'result': json.decode(message.result), - 'id': message.id, - }; - final completer = _completers[message.id]; - if (completer == null) { - throw StateError('Missing completer.'); - } - // TODO(#988): Call completeError(WipError()) to match the behavior of - // package:webkit_inspection_protocol. - completer.complete(WipResponse(encodedResult)); - } else if (message is ExtensionEvent) { - final map = { - 'method': json.decode(message.method), - 'params': json.decode(message.params), - }; - // Note: package:sse will try to keep the connection alive, even - // after the client has been closed. Therefore the extension sends an - // event to notify DWDS that we should close the connection, instead - // of relying on the done event sent when the client is closed. See - // details: - // https://github.com/dart-lang/webdev/pull/1595#issuecomment-1116773378 - if (map['method'] == 'DebugExtension.detached') { - close(); - } else { - _notificationController.sink.add(WipEvent(map)); - } - } else if (message is BatchedEvents) { - for (final event in message.events) { - final map = { - 'method': json.decode(event.method), - 'params': json.decode(event.params), - }; - _notificationController.sink.add(WipEvent(map)); - } - } else if (message is DevToolsRequest) { - instanceId = message.instanceId; - _executionContext = RemoteDebuggerExecutionContext( - message.contextId, - this, - ); - _devToolsRequestController.sink.add(message); - } - }, - onError: (_) { - close(); - }, - onDone: close, - ); - onScriptParsed.listen((event) { - // Remove stale scripts from cache. - if (event.script.url.isNotEmpty && - _scriptIds.containsKey(event.script.url)) { - _scripts.remove(_scriptIds[event.script.url]); - } - _scripts[event.script.scriptId] = event.script; - _scriptIds[event.script.url] = event.script.scriptId; - }); - // Listens for a page reload. - onGlobalObjectCleared.listen((_) { - _scripts.clear(); - }); - } - - void sendEvent(String method, String params) { - sseConnection.sink.add( - jsonEncode(ExtensionEvent(method: method, params: params)), - ); - } - - /// Sends a [command] with optional [params] to Dart Debug Extension - /// over the SSE connection. - @override - Future sendCommand( - String command, { - Map? params, - }) { - final completer = Completer(); - final id = newId(); - _completers[id] = completer; - try { - sseConnection.sink.add( - jsonEncode( - ExtensionRequest( - id: id, - command: command, - commandParams: jsonEncode(params ?? {}), - ), - ), - ); - // ignore: avoid_catching_errors - } on StateError catch (error, stackTrace) { - if (error.message.contains('Cannot add event after closing')) { - _logger.severe('Socket connection closed. Shutting down debugger.'); - closeWithError(error); - } else { - _logger.severe('Bad state while sending $command.', error, stackTrace); - } - } catch (error, stackTrace) { - _logger.severe( - 'Unknown error while sending $command.', - error, - stackTrace, - ); - } - return completer.future; - } - - int newId() => _completerId++; - - @override - Future close() => _closed ??= () { - _closeController.add({}); - return Future.wait([ - sseConnection.sink.close(), - _notificationController.close(), - _devToolsRequestController.close(), - _closeController.close(), - ]); - }(); - - void closeWithError(Object? error) { - _logger.shout( - 'Closing extension debugger due to error. Restart app for debugging ' - 'functionality', - error, - ); - close(); - } - - @override - Future disable() => sendCommand('Debugger.disable'); - - @override - Future enable() => sendCommand('Debugger.enable'); - - @override - Future getScriptSource(String scriptId) async => - (await sendCommand( - 'Debugger.getScriptSource', - params: {'scriptId': scriptId}, - )).result!['scriptSource'] - as String; - - @override - Future pause() => sendCommand('Debugger.pause'); - - @override - Future resume() => sendCommand('Debugger.resume'); - - @override - Future setPauseOnExceptions(PauseState state) => sendCommand( - 'Debugger.setPauseOnExceptions', - params: {'state': _pauseStateToString(state)}, - ); - - @override - Future removeBreakpoint(String breakpointId) { - return sendCommand( - 'Debugger.removeBreakpoint', - params: {'breakpointId': breakpointId}, - ); - } - - @override - Future stepInto({Map? params}) => - sendCommand('Debugger.stepInto', params: params); - - @override - Future stepOut() => sendCommand('Debugger.stepOut'); - - @override - Future stepOver({Map? params}) => - sendCommand('Debugger.stepOver', params: params); - - @override - Future enablePage() => sendCommand('Page.enable'); - - @override - Future pageReload() => sendCommand('Page.reload'); - - @override - Future evaluate( - String expression, { - bool? returnByValue, - int? contextId, - }) async { - final params = {'expression': expression}; - if (returnByValue != null) { - params['returnByValue'] = returnByValue; - } - if (returnByValue != null) { - params['contextId'] = contextId; - } - final response = await sendCommand('Runtime.evaluate', params: params); - final result = _validateResult(response.result); - return RemoteObject(result['result'] as Map); - } - - @override - Future evaluateOnCallFrame( - String callFrameId, - String expression, - ) async { - final params = { - 'callFrameId': callFrameId, - 'expression': expression, - }; - final response = await sendCommand( - 'Debugger.evaluateOnCallFrame', - params: params, - ); - final result = _validateResult(response.result); - return RemoteObject(result['result'] as Map); - } - - @override - Future> getPossibleBreakpoints( - WipLocation start, - ) async { - final params = {'start': start.toJsonMap()}; - final response = await sendCommand( - 'Debugger.getPossibleBreakpoints', - params: params, - ); - final result = _validateResult(response.result); - final locations = result['locations'] as List; - return List.from( - locations.map((map) => WipBreakLocation(map as Map)), - ); - } - - @override - Stream eventStream(String method, WipEventTransformer transformer) { - return _eventStreams - .putIfAbsent( - method, - () => onNotification - .where((event) => event.method == method) - .map(transformer), - ) - .cast(); - } - - @override - Stream get onGlobalObjectCleared => eventStream( - 'Debugger.globalObjectCleared', - (WipEvent event) => GlobalObjectClearedEvent(event.json), - ); - - @override - Stream get onPaused => eventStream( - 'Debugger.paused', - (WipEvent event) => DebuggerPausedEvent(event.json), - ); - - @override - Stream get onResumed => eventStream( - 'Debugger.resumed', - (WipEvent event) => DebuggerResumedEvent(event.json), - ); - - @override - Stream get onScriptParsed => eventStream( - 'Debugger.scriptParsed', - (WipEvent event) => ScriptParsedEvent(event.json), - ); - - @override - Stream get onTargetCrashed => eventStream( - 'Inspector.targetCrashed', - (WipEvent event) => TargetCrashedEvent(event.json), - ); - - @override - Map get scripts => UnmodifiableMapView(_scripts); - - String _pauseStateToString(PauseState state) { - switch (state) { - case PauseState.all: - return 'all'; - case PauseState.none: - return 'none'; - case PauseState.uncaught: - return 'uncaught'; - } - } - - Map _validateResult(Map? result) { - if (result == null) { - throw ChromeDebugException({'text': 'null result from Chrome Devtools'}); - } - if (result.containsKey('exceptionDetails')) { - throw ChromeDebugException( - result['exceptionDetails'] as Map, - ); - } - return result; - } - - static Object? _deserialize(dynamic decoded) { - if (decoded case ['ExtensionResponse', ...]) { - return ExtensionResponse.fromJson(decoded); - } - if (decoded case ['ExtensionEvent', ...]) { - return ExtensionEvent.fromJson(decoded); - } - if (decoded case ['BatchedEvents', ...]) { - return BatchedEvents.fromJson(decoded); - } - if (decoded case ['DevToolsRequest', ...]) { - return DevToolsRequest.fromJson(decoded); - } - return null; - } -} diff --git a/dwds/lib/src/services/app_debug_services.dart b/dwds/lib/src/services/app_debug_services.dart deleted file mode 100644 index d0b862e58f..0000000000 --- a/dwds/lib/src/services/app_debug_services.dart +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'package:dds/dds_launcher.dart'; -import 'package:dwds/src/dwds_vm_client.dart'; -import 'package:dwds/src/events.dart'; -import 'package:dwds/src/services/debug_service.dart'; -import 'package:dwds/src/services/proxy_service.dart'; - -/// Common interface for debug service containers. -class AppDebugServices< - T extends DebugService, - U extends ProxyService, - V extends DwdsVmClient -> { - final T debugService; - final V dwdsVmClient; - final DartDevelopmentServiceLauncher? _dds; - Uri? get ddsUri => _dds?.wsUri; - Uri? get devToolsUri => _dds?.devToolsUri; - Uri? get dtdUri => _dds?.dtdUri; - final DwdsStats? dwdsStats; - String? connectedInstanceId; - - Future? _closed; - - AppDebugServices({ - required this.debugService, - required this.dwdsVmClient, - required this._dds, - this.dwdsStats, - }); - - ProxyService get proxyService => debugService.proxyService; - - Future close() { - return _closed ??= Future.wait([ - debugService.close(), - dwdsVmClient.close(), - ]); - } -} diff --git a/dwds/lib/src/services/batched_expression_evaluator.dart b/dwds/lib/src/services/batched_expression_evaluator.dart deleted file mode 100644 index 164b04b009..0000000000 --- a/dwds/lib/src/services/batched_expression_evaluator.dart +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:async'; - -import 'package:collection/collection.dart'; -import 'package:dwds/shared/batched_stream.dart'; -import 'package:dwds/src/debugging/chrome_inspector.dart'; -import 'package:dwds/src/debugging/debugger.dart'; -import 'package:dwds/src/debugging/location.dart'; -import 'package:dwds/src/debugging/modules.dart'; -import 'package:dwds/src/services/expression_compiler.dart'; -import 'package:dwds/src/services/expression_evaluator.dart'; -import 'package:dwds/src/utilities/shared.dart'; -import 'package:logging/logging.dart'; -import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'; - -class EvaluateRequest { - final String isolateId; - final String? libraryUri; - final String expression; - final Map? scope; - final completer = Completer(); - - EvaluateRequest(this.isolateId, this.libraryUri, this.expression, this.scope); -} - -class BatchedExpressionEvaluator extends ExpressionEvaluator { - final _logger = Logger('BatchedExpressionEvaluator'); - final ChromeAppInspector _inspector; - final _requestController = BatchedStreamController( - delay: 200, - ); - bool _closed = false; - - BatchedExpressionEvaluator( - String entrypoint, - this._inspector, - Debugger debugger, - Locations locations, - Modules modules, - ExpressionCompiler compiler, - ) : super(entrypoint, _inspector, debugger, locations, modules, compiler) { - _requestController.stream.listen(_processRequest); - } - - @override - void close() { - if (_closed) return; - _logger.fine('Closed'); - _requestController.close(); - _closed = true; - } - - @override - Future evaluateExpression( - String isolateId, - String? libraryUri, - String expression, - Map? scope, - ) async { - if (_closed) { - return createError( - EvaluationErrorKind.internal, - 'Batched expression evaluator closed', - ); - } - final request = EvaluateRequest(isolateId, libraryUri, expression, scope); - _requestController.sink.add(request); - return request.completer.future; - } - - void _processRequest(List requests) { - String? libraryUri; - String? isolateId; - Map? scope; - var currentRequests = []; - - for (final request in requests) { - libraryUri ??= request.libraryUri; - isolateId ??= request.isolateId; - scope ??= request.scope; - - if (libraryUri != request.libraryUri || - isolateId != request.isolateId || - !const MapEquality().equals(scope, request.scope)) { - _logger.fine('New batch due to'); - if (libraryUri != request.libraryUri) { - _logger.fine(' - library uri: $libraryUri != ${request.libraryUri}'); - } - if (isolateId != request.isolateId) { - _logger.fine(' - isolateId: $isolateId != ${request.isolateId}'); - } - if (!const MapEquality().equals(scope, request.scope)) { - _logger.fine(' - scope: $scope != ${request.scope}'); - } - - safeUnawaited(_evaluateBatch(currentRequests)); - currentRequests = []; - libraryUri = request.libraryUri; - isolateId = request.isolateId; - scope = request.scope; - } - currentRequests.add(request); - } - safeUnawaited(_evaluateBatch(currentRequests)); - } - - Future _evaluateBatch(List requests) async { - if (requests.isEmpty) return; - - final first = requests.first; - if (requests.length == 1) { - if (first.completer.isCompleted) return; - return super - .evaluateExpression( - first.isolateId, - first.libraryUri, - first.expression, - first.scope, - ) - .then(requests.first.completer.complete); - } - - final expressions = requests.map((r) => r.expression).join(', '); - final batchedExpression = '[ $expressions ]'; - - _logger.fine('Evaluating batch of expressions $batchedExpression'); - - final list = await super.evaluateExpression( - first.isolateId, - first.libraryUri, - batchedExpression, - first.scope, - ); - - final listId = list.objectId; - if (listId == null) { - for (final request in requests) { - safeUnawaited(_evaluateBatch([request])); - } - return; - } - - for (var i = 0; i < requests.length; i++) { - final request = requests[i]; - if (request.completer.isCompleted) continue; - _logger.fine('Getting result out of a batch for ${request.expression}'); - - safeUnawaited( - _inspector - .getProperties(listId, offset: i, count: 1, length: requests.length) - .then((v) { - final result = v.first.value!; - _logger.fine( - 'Got result out of a batch for ${request.expression}: $result', - ); - request.completer.complete(result); - }), - onError: request.completer.completeError, - ); - } - } -} diff --git a/dwds/lib/src/services/chrome/chrome_debug_exception.dart b/dwds/lib/src/services/chrome/chrome_debug_exception.dart deleted file mode 100644 index 82e377d23e..0000000000 --- a/dwds/lib/src/services/chrome/chrome_debug_exception.dart +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'; - -final class ChromeDebugException extends ExceptionDetails implements Exception { - /// Optional, additional information about the exception. - final Object? additionalDetails; - - /// Optional, the exact contents of the eval that was attempted. - final String? evalContents; - - /// Optional, the stack where exception happened. - @override - late final StackTrace? stackTrace; - - ChromeDebugException( - Map exceptionDetails, { - this.additionalDetails, - this.evalContents, - }) : super(exceptionDetails) { - final json = exceptionDetails['stackTrace']; - stackTrace = json == null ? null : StackTrace(json as Map); - } - - @override - String toString() { - final description = StringBuffer() - ..writeln('Unexpected error from chrome devtools:'); - description.writeln('text: $text'); - if (exception != null) { - description.writeln('exception:'); - description.writeln(' preview: ${exception?.json['preview']}'); - description.writeln(' description: ${exception?.description}'); - description.writeln(' type: ${exception?.type}'); - description.writeln(' value: ${exception?.value}'); - } - if (evalContents != null) { - description.writeln('attempted JS eval: `$evalContents`'); - } - if (additionalDetails != null) { - description.writeln('additional details:\n $additionalDetails'); - } - if (stackTrace != null) { - var trace = stackTrace; - description.writeln('stack trace:'); - while (trace != null) { - for (final frame in trace.printFrames()) { - description.writeln(frame); - } - trace = trace.parent; - } - } - return description.toString(); - } -} diff --git a/dwds/lib/src/services/chrome/chrome_debug_service.dart b/dwds/lib/src/services/chrome/chrome_debug_service.dart deleted file mode 100644 index 6fa2731dd2..0000000000 --- a/dwds/lib/src/services/chrome/chrome_debug_service.dart +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'package:dwds/asset_reader.dart'; -import 'package:dwds/src/config/tool_configuration.dart'; -import 'package:dwds/src/connections/app_connection.dart'; -import 'package:dwds/src/debugging/execution_context.dart'; -import 'package:dwds/src/debugging/remote_debugger.dart'; -import 'package:dwds/src/services/chrome/chrome_proxy_service.dart'; -import 'package:dwds/src/services/debug_service.dart'; -import 'package:dwds/src/services/expression_compiler.dart'; -import 'package:dwds/src/utilities/shared.dart'; -import 'package:meta/meta.dart'; -import 'package:shelf/shelf.dart' as shelf; -import 'package:sse/server/sse_handler.dart'; - -/// A Dart Web Debug Service. -/// -/// Creates a [ChromeProxyService] from an existing Chrome instance. -final class ChromeDebugService extends DebugService { - ChromeDebugService._({ - required super.serverHostname, - required super.useSse, - required super.ddsConfig, - required super.urlEncoder, - }); - - static const _kSseHandlerPath = '\$debugHandler'; - - @protected - @override - Future initialize({ - required ChromeProxyService proxyService, - void Function(Map)? onRequest, - void Function(Map)? onResponse, - }) async { - await super.initialize(proxyService: proxyService); - shelf.Handler handler; - // DDS will always connect to DWDS via web sockets. - if (useSse && !ddsConfig.enable) { - handler = _initializeSSEHandler( - chromeProxyService: proxyService, - onRequest: onRequest, - onResponse: onResponse, - ); - } else { - handler = initializeWebSocketHandler( - proxyService: proxyService, - onRequest: onRequest, - onResponse: onResponse, - ); - } - await serve(handler: handler); - } - - static Future start({ - required String hostname, - required RemoteDebugger remoteDebugger, - required ExecutionContext executionContext, - required AssetReader assetReader, - required AppConnection appConnection, - UrlEncoder? urlEncoder, - void Function(Map)? onRequest, - void Function(Map)? onResponse, - required DartDevelopmentServiceConfiguration ddsConfig, - bool useSse = false, - ExpressionCompiler? expressionCompiler, - }) async { - final debugService = ChromeDebugService._( - serverHostname: hostname, - useSse: useSse, - ddsConfig: ddsConfig, - urlEncoder: urlEncoder, - ); - final chromeProxyService = await ChromeProxyService.create( - remoteDebugger: remoteDebugger, - debugService: debugService, - assetReader: assetReader, - appConnection: appConnection, - executionContext: executionContext, - expressionCompiler: expressionCompiler, - ); - await debugService.initialize( - proxyService: chromeProxyService, - onRequest: onRequest, - onResponse: onResponse, - ); - return debugService; - } - - shelf.Handler _initializeSSEHandler({ - required ChromeProxyService chromeProxyService, - void Function(Map)? onRequest, - void Function(Map)? onResponse, - }) { - final sseHandler = SseHandler( - Uri.parse('/$authToken/$_kSseHandlerPath'), - keepAlive: const Duration(seconds: 5), - ); - final handler = sseHandler.handler; - safeUnawaited(() async { - while (await sseHandler.connections.hasNext) { - final connection = await sseHandler.connections.next; - handleConnection( - connection, - chromeProxyService, - serviceExtensionRegistry, - onRequest: onRequest, - onResponse: onResponse, - ); - } - }()); - return handler; - } -} diff --git a/dwds/lib/src/services/chrome/chrome_proxy_service.dart b/dwds/lib/src/services/chrome/chrome_proxy_service.dart deleted file mode 100644 index ad785f3b01..0000000000 --- a/dwds/lib/src/services/chrome/chrome_proxy_service.dart +++ /dev/null @@ -1,1373 +0,0 @@ -// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:async'; -import 'dart:convert'; -import 'dart:io'; - -import 'package:dwds/data/debug_event.dart'; -import 'package:dwds/data/register_event.dart'; -import 'package:dwds/src/config/tool_configuration.dart'; -import 'package:dwds/src/connections/app_connection.dart'; -import 'package:dwds/src/debugging/chrome_inspector.dart'; -import 'package:dwds/src/debugging/debugger.dart'; -import 'package:dwds/src/debugging/execution_context.dart'; -import 'package:dwds/src/debugging/instance.dart'; -import 'package:dwds/src/debugging/location.dart'; -import 'package:dwds/src/debugging/metadata/provider.dart'; -import 'package:dwds/src/debugging/modules.dart'; -import 'package:dwds/src/debugging/remote_debugger.dart'; -import 'package:dwds/src/debugging/skip_list.dart'; -import 'package:dwds/src/events.dart'; -import 'package:dwds/src/readers/asset_reader.dart'; -import 'package:dwds/src/services/batched_expression_evaluator.dart'; -import 'package:dwds/src/services/chrome/chrome_debug_service.dart'; -import 'package:dwds/src/services/expression_compiler.dart'; -import 'package:dwds/src/services/expression_evaluator.dart'; -import 'package:dwds/src/services/proxy_service.dart'; -import 'package:dwds/src/utilities/dart_uri.dart'; -import 'package:dwds/src/utilities/shared.dart'; -import 'package:logging/logging.dart' hide LogRecord; -import 'package:vm_service/vm_service.dart' hide vmServiceVersion; -import 'package:vm_service_interface/vm_service_interface.dart'; -import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart' - hide StackTrace; - -/// A proxy from the chrome debug protocol to the dart vm service protocol. -final class ChromeProxyService extends ProxyService { - /// Signals when isolate starts. - Future get isStarted => _startedCompleter.future; - Completer _startedCompleter = Completer(); - - /// Signals when expression compiler is ready to evaluate. - Future get isCompilerInitialized => _compilerCompleter.future; - Completer _compilerCompleter = Completer(); - - final RemoteDebugger remoteDebugger; - final ExecutionContext executionContext; - - final AssetReader _assetReader; - - final Locations _locations; - - final SkipLists _skipLists; - - final Modules _modules; - - /// Provides debugger-related functionality. - late final Future debuggerFuture; - - StreamSubscription? _consoleSubscription; - - /// If non-null, a resume event should await the result of this after resuming - /// execution. - /// - /// This is used to complete a hot reload. - Future Function()? _finishHotReloadOnResume; - - final _logger = Logger('ChromeProxyService'); - - final ExpressionCompiler? _compiler; - ExpressionEvaluator? _expressionEvaluator; - - /// Isolate creation should wait until this completer is complete to prevent - /// computing metadata in an invalid state. - /// - /// Starts out completed and is reinitialized and completed when needed. - Completer allowedToCreateIsolate = Completer()..complete(); - - bool terminatingIsolates = false; - - ChromeProxyService._({ - required super.vm, - required super.debugService, - required AssetReader assetReader, - required this.remoteDebugger, - required this._modules, - required this._locations, - required this._skipLists, - required this.executionContext, - required this._compiler, - }) : _assetReader = assetReader, - super(root: assetReader.basePath) { - debuggerFuture = Debugger.create( - remoteDebugger, - streamNotify, - _locations, - _skipLists, - root, - ); - } - - static Future create({ - required RemoteDebugger remoteDebugger, - required ChromeDebugService debugService, - required AssetReader assetReader, - required AppConnection appConnection, - required ExecutionContext executionContext, - required ExpressionCompiler? expressionCompiler, - }) async { - final vm = VM( - name: 'ChromeDebugProxy', - operatingSystem: Platform.operatingSystem, - startTime: DateTime.now().millisecondsSinceEpoch, - version: Platform.version, - isolates: [], - isolateGroups: [], - systemIsolates: [], - systemIsolateGroups: [], - targetCPU: 'Web', - hostCPU: 'DWDS', - architectureBits: -1, - pid: -1, - ); - - final root = assetReader.basePath; - final modules = Modules(root); - final locations = Locations(assetReader, modules, root); - final skipLists = SkipLists(root); - final service = ChromeProxyService._( - vm: vm, - debugService: debugService, - assetReader: assetReader, - remoteDebugger: remoteDebugger, - modules: modules, - locations: locations, - skipLists: skipLists, - executionContext: executionContext, - compiler: expressionCompiler, - ); - await service.createIsolate(appConnection, newConnection: true); - return service; - } - - /// Reinitializes any caches so that they can be recomputed across hot reload. - /// - /// We use the [ModifiedModuleReport] to more efficiently invalidate caches. - Future _reinitializeForHotReload( - Map reloadedModules, - ) async { - final entrypoint = inspector.appConnection.request.entrypointPath; - final modifiedModuleReport = await globalToolConfiguration.loadStrategy - .reinitializeProviderAfterHotReload(entrypoint, reloadedModules); - await _initializeEntrypoint( - entrypoint, - modifiedModuleReport: modifiedModuleReport, - ); - await inspector.initialize(modifiedModuleReport: modifiedModuleReport); - } - - /// Initializes metadata in [Locations], [Modules], and [ExpressionCompiler]. - /// - /// If [modifiedModuleReport] is not null, only removes and reinitializes - /// modified metadata. - Future _initializeEntrypoint( - String entrypoint, { - ModifiedModuleReport? modifiedModuleReport, - }) async { - await _modules.initialize( - entrypoint, - modifiedModuleReport: modifiedModuleReport, - ); - await _locations.initialize( - entrypoint, - modifiedModuleReport: modifiedModuleReport, - ); - await _skipLists.initialize( - entrypoint, - modifiedModuleReport: modifiedModuleReport, - ); - // We do not need to wait for compiler dependencies to be updated as the - // [ExpressionEvaluator] is robust to evaluation requests during updates. - safeUnawaited(_updateCompilerDependencies(entrypoint)); - } - - Future _updateCompilerDependencies(String entrypoint) async { - final loadStrategy = globalToolConfiguration.loadStrategy; - final moduleFormat = loadStrategy.moduleFormat; - final buildSettings = loadStrategy.buildSettings; - - _logger.info('Initializing expression compiler for $entrypoint'); - - final compilerOptions = CompilerOptions( - moduleFormat: ModuleFormat.values.byName(moduleFormat), - canaryFeatures: buildSettings.canaryFeatures, - experiments: buildSettings.experiments, - deprecatedJsInterop: buildSettings.deprecatedJsInterop, - ); - - final compiler = _compiler; - if (compiler != null) { - await compiler.initialize(compilerOptions); - final dependencies = await loadStrategy.moduleInfoForEntrypoint( - entrypoint, - ); - await captureElapsedTime(() async { - final result = await compiler.updateDependencies(dependencies); - // Expression evaluation is ready after dependencies are updated. - if (!_compilerCompleter.isCompleted) _compilerCompleter.complete(); - return result; - }, (result) => DwdsEvent.compilerUpdateDependencies(entrypoint)); - } - } - - Future _prewarmExpressionCompilerCache() async { - // Exit early if the expression evaluation is not enabled. - if (_compiler == null || _expressionEvaluator == null) { - return; - } - // Wait until the inspector is ready. - await isInitialized; - - // Pre-warm the flutter framework module cache in the compiler. - // - // Flutter inspector relies on evaluations in widget_inspector - // library, which is a part of the flutter framework module, to - // produce widget trees, draw the layout explorer, show hover - // cards etc. - // Pre-warming the cache while DevTools is still loading helps - // Flutter Inspector start faster. - final libraryToCache = await inspector.flutterWidgetInspectorLibrary; - if (libraryToCache != null) { - final isolateId = inspector.isolateRef.id; - final libraryId = libraryToCache.id; - if (isolateId != null && libraryId != null) { - _logger.finest( - 'Caching ${libraryToCache.uri} in expression compiler worker', - ); - await evaluate(isolateId, libraryId, 'true'); - } - } - } - - /// Creates a new isolate. - /// - /// Only one isolate at a time is supported, but they should be cleaned up - /// with [destroyIsolate] and recreated with this method there is a hot - /// restart or full page refresh. - /// - /// If [newConnection] is true, this method does not recompute metadata - /// information as the metadata couldn't have changed. - @override - Future createIsolate( - AppConnection appConnection, { - bool newConnection = false, - }) async { - // Inspector is null if the previous isolate is destroyed. - if (isIsolateRunning) { - throw UnsupportedError( - 'Cannot create multiple isolates for the same app', - ); - } - // Wait until we're allowed to create the isolate. This is needed in hot - // restart as scripts may not be parsed yet. - if (!allowedToCreateIsolate.isCompleted) { - _logger.info( - 'Waiting until hot restart is completed before creating ' - 'isolate', - ); - await allowedToCreateIsolate.future; - } - // Waiting for the debugger to be ready before initializing the entrypoint. - // - // Note: moving `await debugger` after the `_initializeEntryPoint` call - // causes `getcwd` system calls to fail. Since that system call is used - // in first `Uri.base` call in the expression compiler service isolate, - // the expression compiler service will fail to start. - // Issue: https://github.com/dart-lang/webdev/issues/1282 - final debugger = await debuggerFuture; - final entrypoint = appConnection.request.entrypointPath; - if (!newConnection) { - await globalToolConfiguration.loadStrategy.trackEntrypoint(entrypoint); - } - await _initializeEntrypoint(entrypoint); - - debugger.notifyPausedAtStart(); - inspector = await ChromeAppInspector.create( - appConnection, - remoteDebugger, - _assetReader, - _locations, - root, - debugger, - executionContext, - ); - - final compiler = _compiler; - _expressionEvaluator = compiler == null - ? null - : BatchedExpressionEvaluator( - entrypoint, - inspector, - debugger, - _locations, - _modules, - compiler, - ); - - safeUnawaited(_prewarmExpressionCompilerCache()); - - safeUnawaited( - appConnection.onStart.then((_) { - debugger.resumeFromStart(); - _startedCompleter.complete(); - }), - ); - - safeUnawaited(appConnection.onDone.then((_) => destroyIsolate())); - - final isolateRef = inspector.isolateRef; - final timestamp = DateTime.now().millisecondsSinceEpoch; - - // Listen for `registerExtension` and `postEvent` calls. - _setUpChromeConsoleListeners(isolateRef); - - vm.isolates?.add(isolateRef); - - streamNotify( - 'Isolate', - Event( - kind: EventKind.kIsolateStart, - timestamp: timestamp, - isolate: isolateRef, - ), - ); - streamNotify( - 'Isolate', - Event( - kind: EventKind.kIsolateRunnable, - timestamp: timestamp, - isolate: isolateRef, - ), - ); - - // TODO: We shouldn't need to fire these events since they exist on the - // isolate, but devtools doesn't recognize extensions after a page refresh - // otherwise. - await sendServiceExtensionRegisteredEvents(); - - // If the new isolate was created as part of a restart, send a - // kPausePostRequest event to notify client that the app is paused so that - // it can resume: - if (hasPendingRestart) { - streamNotify( - 'Debug', - Event( - kind: EventKind.kPausePostRequest, - timestamp: timestamp, - isolate: isolateRef, - ), - ); - } - - // The service is considered initialized when the first isolate is created. - if (!initializedCompleter.isCompleted) initializedCompleter.complete(); - } - - /// Should be called when there is a hot restart or full page refresh. - /// - /// Clears out the [inspector] and all related cached information. - @override - void destroyIsolate() { - _logger.fine('$hashCode Destroying isolate'); - if (!isIsolateRunning) return; - - final isolate = inspector.isolate; - final isolateRef = inspector.isolateRef; - - initializedCompleter = Completer(); - _startedCompleter = Completer(); - _compilerCompleter = Completer(); - streamNotify( - 'Isolate', - Event( - kind: EventKind.kIsolateExit, - timestamp: DateTime.now().millisecondsSinceEpoch, - isolate: isolateRef, - ), - ); - vm.isolates?.removeWhere((ref) => ref.id == isolate.id); - inspector = null; - _expressionEvaluator?.close(); - _consoleSubscription?.cancel(); - _consoleSubscription = null; - } - - /// Removes the breakpoints in the running isolate. - Future disableBreakpoints() async { - if (!isIsolateRunning) return; - final isolate = inspector.isolate; - - final debugger = await debuggerFuture; - await Future.wait([ - for (final breakpoint in isolate.breakpoints ?? []) - debugger.removeBreakpoint(breakpoint.id!), - ]); - } - - @override - Future addBreakpoint( - String isolateId, - String scriptId, - int line, { - int? column, - }) { - return wrapInErrorHandlerAsync( - 'addBreakpoint', - () => _addBreakpoint(isolateId, scriptId, line), - ); - } - - Future _addBreakpoint( - String isolateId, - String scriptId, - int line, { - int? column, - }) async { - await isInitialized; - checkIsolate('addBreakpoint', isolateId); - return (await debuggerFuture).addBreakpoint(scriptId, line, column: column); - } - - @override - Future addBreakpointAtEntry(String isolateId, String functionId) { - return rpcNotSupportedFuture('addBreakpointAtEntry'); - } - - @override - Future addBreakpointWithScriptUri( - String isolateId, - String scriptUri, - int line, { - int? column, - }) => wrapInErrorHandlerAsync( - 'addBreakpointWithScriptUri', - () => - _addBreakpointWithScriptUri(isolateId, scriptUri, line, column: column), - ); - - Future _addBreakpointWithScriptUri( - String isolateId, - String scriptUri, - int line, { - int? column, - }) async { - await isInitialized; - checkIsolate('addBreakpointWithScriptUri', isolateId); - if (Uri.parse(scriptUri).scheme == 'dart') { - // TODO(annagrin): Support setting breakpoints in dart SDK locations. - // Issue: https://github.com/dart-lang/webdev/issues/1584 - throw RPCError( - 'addBreakpoint', - 102, - 'The VM is unable to add a breakpoint ' - 'at the specified line or function: $scriptUri:$line:$column: ' - 'breakpoints in dart SDK locations are not supported yet.', - ); - } - final dartUri = DartUri(scriptUri, root); - final scriptRef = await inspector.scriptRefFor(dartUri.serverPath); - final scriptId = scriptRef?.id; - if (scriptId == null) { - throw RPCError( - 'addBreakpoint', - 102, - 'The VM is unable to add a breakpoint ' - 'at the specified line or function: $scriptUri:$line:$column: ' - 'cannot find script ID for ${dartUri.serverPath}', - ); - } - return (await debuggerFuture).addBreakpoint(scriptId, line, column: column); - } - - @override - Future callServiceExtension( - String method, { - String? isolateId, - Map? args, - }) => wrapInErrorHandlerAsync( - 'callServiceExtension', - () => _callServiceExtension(method, isolateId: isolateId, args: args), - ); - - Future _callServiceExtension( - String method, { - String? isolateId, - Map? args, - }) async { - await isInitialized; - isolateId ??= inspector.isolate.id; - checkIsolate('callServiceExtension', isolateId); - args ??= {}; - final stringArgs = args.map( - (k, v) => MapEntry( - k is String ? k : jsonEncode(k), - v is String ? v : jsonEncode(v), - ), - ); - if (!(await inspector.getExtensionRpcs()).contains(method)) { - throw RPCError( - method, - RPCErrorKind.kMethodNotFound.code, - 'Unknown service method: $method', - ); - } - final expression = globalToolConfiguration.loadStrategy.dartRuntimeDebugger - .invokeExtensionJsExpression(method, jsonEncode(stringArgs)); - final result = await inspector.jsEvaluate(expression, awaitPromise: true); - final decodedResponse = - jsonDecode(result.value as String) as Map; - if (decodedResponse.containsKey('code') && - decodedResponse.containsKey('message') && - decodedResponse.containsKey('data')) { - // ignore: only_throw_errors - throw RPCError( - method, - decodedResponse['code'] as int, - // ignore: avoid-unnecessary-type-casts - decodedResponse['message'] as String, - decodedResponse['data'] as Map, - ); - } else { - return Response()..json = decodedResponse; - } - } - - Future _getEvaluationResult( - String isolateId, - Future Function() evaluation, - String expression, - ) async { - try { - final result = await evaluation(); - if (!isIsolateRunning || isolateId != inspector.isolate.id) { - _logger.fine( - 'Cannot get evaluation result for isolate $isolateId: ' - ' isolate exited.', - ); - return ErrorRef( - kind: 'error', - message: 'Isolate exited', - id: createId(), - ); - } - - // Handle compilation errors, internal errors, - // and reference errors from JavaScript evaluation in chrome. - if (_hasEvaluationError(result.type)) { - if (_hasReportableEvaluationError(result.type)) { - _logger.warning( - 'Failed to evaluate expression \'$expression\': ' - '${result.type}: ${result.value}.', - ); - - _logger.info( - 'Please follow instructions at ' - 'https://github.com/dart-lang/webdev/issues/956 ' - 'to file a bug.', - ); - } - return ErrorRef( - kind: 'error', - message: '${result.type}: ${result.value}', - id: createId(), - ); - } - return await _instanceRef(result); - } on RPCError catch (_) { - rethrow; - } catch (e, s) { - // Handle errors that throw exceptions, such as invalid JavaScript - // generated by the expression evaluator. - _logger.warning('Failed to evaluate expression \'$expression\'. '); - _logger.info( - 'Please follow instructions at ' - 'https://github.com/dart-lang/webdev/issues/956 ' - 'to file a bug.', - ); - _logger.info('$e:$s'); - return ErrorRef(kind: 'error', message: '', id: createId()); - } - } - - bool _hasEvaluationError(String type) => type.contains('Error'); - - // Decides if the error is serious enough to be shown to the user - // to encourage bug reporting. - bool _hasReportableEvaluationError(String type) { - if (!_hasEvaluationError(type)) return false; - - if (type == EvaluationErrorKind.compilation || - type == EvaluationErrorKind.asyncFrame) { - return false; - } - return true; - } - - @override - Future evaluate( - String isolateId, - String targetId, - String expression, { - Map? scope, - // TODO(798) - respect disableBreakpoints. - bool? disableBreakpoints, - - /// Note that `idZoneId` arguments will be ignored. This parameter is only - /// here to make this method is a valid override of - /// [VmServiceInterface.evaluate]. - String? idZoneId, - }) => wrapInErrorHandlerAsync( - 'evaluate', - () => _evaluate(isolateId, targetId, expression, scope: scope), - ); - - Future _evaluate( - String isolateId, - String targetId, - String expression, { - Map? scope, - }) { - // TODO(798) - respect disableBreakpoints. - return captureElapsedTime(() async { - await isInitialized; - final evaluator = _expressionEvaluator; - if (evaluator != null) { - await isCompilerInitialized; - checkIsolate('evaluate', isolateId); - - late Obj object; - try { - object = await inspector.getObject(targetId); - } catch (_) { - return ErrorRef( - kind: 'error', - message: - 'Evaluate is called on an unsupported target:' - '$targetId', - id: createId(), - ); - } - - final library = object is Library ? object : inspector.isolate.rootLib; - - if (object is Instance) { - // Evaluate is called on a target - convert this to a dart - // expression and scope by adding a target variable to the - // expression and the scope, for example: - // - // Library: 'package:hello_world/main.dart' - // Expression: 'hashCode' => 'x.hashCode' - // Scope: {} => { 'x' : targetId } - - final target = _newVariableForScope(scope); - expression = '$target.$expression'; - scope = (scope ?? {})..addAll({target: targetId}); - } - - return await _getEvaluationResult( - isolateId, - () => evaluator.evaluateExpression( - isolateId, - library?.uri, - expression, - scope, - ), - expression, - ); - } - throw RPCError( - 'evaluate', - RPCErrorKind.kInvalidRequest.code, - 'Expression evaluation is not supported for this configuration.', - ); - }, (result) => DwdsEvent.evaluate(expression, result)); - } - - String _newVariableForScope(Map? scope) { - // Find a new variable not in scope. - var candidate = 'x'; - while (scope?.containsKey(candidate) ?? false) { - candidate += '\$1'; - } - return candidate; - } - - @override - Future evaluateInFrame( - String isolateId, - int frameIndex, - String expression, { - Map? scope, - // TODO(798) - respect disableBreakpoints. - bool? disableBreakpoints, - - /// Note that `idZoneId` arguments will be ignored. This parameter is only - /// here to make this method is a valid override of - /// [VmServiceInterface.evaluateInFrame]. - String? idZoneId, - }) => wrapInErrorHandlerAsync( - 'evaluateInFrame', - () => _evaluateInFrame(isolateId, frameIndex, expression, scope: scope), - ); - - Future _evaluateInFrame( - String isolateId, - int frameIndex, - String expression, { - Map? scope, - }) { - // TODO(798) - respect disableBreakpoints. - - return captureElapsedTime(() async { - await isInitialized; - final evaluator = _expressionEvaluator; - if (evaluator != null) { - await isCompilerInitialized; - checkIsolate('evaluateInFrame', isolateId); - - return await _getEvaluationResult( - isolateId, - () => evaluator.evaluateExpressionInFrame( - isolateId, - frameIndex, - expression, - scope, - ), - expression, - ); - } - throw RPCError( - 'evaluateInFrame', - RPCErrorKind.kInvalidRequest.code, - 'Expression evaluation is not supported for this configuration.', - ); - }, (result) => DwdsEvent.evaluateInFrame(expression, result)); - } - - @override - Future getMemoryUsage(String isolateId) => - wrapInErrorHandlerAsync( - 'getMemoryUsage', - () => _getMemoryUsage(isolateId), - ); - - Future _getMemoryUsage(String isolateId) async { - await isInitialized; - checkIsolate('getMemoryUsage', isolateId); - return inspector.getMemoryUsage(); - } - - @override - Future getObject( - String isolateId, - String objectId, { - int? offset, - int? count, - - /// Note that `idZoneId` arguments will be ignored. This parameter is only - /// here to make this method is a valid override of - /// [VmServiceInterface.getObject]. - String? idZoneId, - }) => wrapInErrorHandlerAsync( - 'getObject', - () => _getObject(isolateId, objectId, offset: offset, count: count), - ); - - Future _getObject( - String isolateId, - String objectId, { - int? offset, - int? count, - }) async { - await isInitialized; - checkIsolate('getObject', isolateId); - return inspector.getObject(objectId, offset: offset, count: count); - } - - @override - Future getSourceReport( - String isolateId, - List reports, { - String? scriptId, - // Note: Ignore the following optional parameters. They are here to match - // the VM service interface. - int? tokenPos, - int? endTokenPos, - bool? forceCompile, - bool? reportLines, - List? libraryFilters, - List? librariesAlreadyCompiled, - }) => wrapInErrorHandlerAsync( - 'getSourceReport', - () => _getSourceReport(isolateId, reports, scriptId: scriptId), - ); - - Future _getSourceReport( - String isolateId, - List reports, { - String? scriptId, - }) { - return captureElapsedTime(() async { - await isInitialized; - checkIsolate('getSourceReport', isolateId); - return await inspector.getSourceReport(reports, scriptId: scriptId); - }, (result) => DwdsEvent.getSourceReport()); - } - - /// Returns the current stack. - /// - /// Throws RPCError the corresponding isolate is not paused. - /// - /// The returned stack will contain up to [limit] frames if provided. - @override - Future getStack( - String isolateId, { - int? limit, - - /// Note that `idZoneId` arguments will be ignored. This parameter is only - /// here to make this method is a valid override of - /// [VmServiceInterface.getStack]. - String? idZoneId, - }) => wrapInErrorHandlerAsync( - 'getStack', - () => _getStack(isolateId, limit: limit), - ); - - Future _getStack(String isolateId, {int? limit}) async { - await isInitialized; - await isStarted; - checkIsolate('getStack', isolateId); - return (await debuggerFuture).getStack(limit: limit); - } - - @override - Future invoke( - String isolateId, - String targetId, - String selector, - List argumentIds, { - // TODO(798) - respect disableBreakpoints. - bool? disableBreakpoints, - - /// Note that `idZoneId` arguments will be ignored. This parameter is only - /// here to make this method is a valid override of - /// [VmServiceInterface.invoke]. - String? idZoneId, - }) => wrapInErrorHandlerAsync( - 'invoke', - () => _invoke(isolateId, targetId, selector, argumentIds), - ); - - Future _invoke( - String isolateId, - String targetId, - String selector, - List argumentIds, - ) async { - await isInitialized; - checkIsolate('invoke', isolateId); - final remote = await inspector.invoke(targetId, selector, argumentIds); - return _instanceRef(remote); - } - - @override - Stream onEvent(String streamId) { - return streamControllers.putIfAbsent(streamId, () { - switch (streamId) { - case EventStreams.kExtension: - return StreamController.broadcast(); - case EventStreams.kIsolate: - // TODO: right now we only support the `ServiceExtensionAdded` event - // for the Isolate stream. - return StreamController.broadcast(); - case EventStreams.kVM: - return StreamController.broadcast(); - case EventStreams.kGC: - return StreamController.broadcast(); - case EventStreams.kTimeline: - return StreamController.broadcast(); - case EventStreams.kService: - return StreamController.broadcast(); - case EventStreams.kDebug: - return StreamController.broadcast(); - case EventStreams.kLogging: - return StreamController.broadcast(); - case EventStreams.kStdout: - return _chromeConsoleStreamController( - (e) => _stdoutTypes.contains(e.type), - ); - case EventStreams.kStderr: - return _chromeConsoleStreamController( - (e) => _stderrTypes.contains(e.type), - includeExceptions: true, - ); - default: - throw RPCError( - 'streamListen', - RPCErrorKind.kInvalidParams.code, - 'The stream `$streamId` is not supported on web devices', - ); - } - }).stream; - } - - /// If [internalPause] is true, indicates that this was a pause triggered - /// within DWDS, and therefore a `PauseInterrupted` event is never sent to the - /// VM service event stream. Instead, we just wait for the pause to be - /// completed. - @override - Future pause(String isolateId, {bool internalPause = false}) => - wrapInErrorHandlerAsync( - 'pause', - () => _pause(isolateId, internalPause: internalPause), - ); - - Future _pause( - String isolateId, { - required bool internalPause, - }) async { - await isInitialized; - checkIsolate('pause', isolateId); - return (await debuggerFuture).pause(internalPause: internalPause); - } - - @override - Future reloadSources( - String isolateId, { - bool? force, - bool? pause, - String? rootLibUri, - String? packagesUri, - }) async { - await isInitialized; - checkIsolate('reloadSources', isolateId); - - ReloadReport getFailedReloadReport(String error) => - _ReloadReportWithMetadata(success: false) - ..json = { - 'notices': [ - {'message': error}, - ], - }; - try { - await _performClientSideHotReload(isolateId); - } catch (e) { - _logger.info('Hot reload failed: $e'); - return getFailedReloadReport(e.toString()); - } - _logger.info('Successful hot reload'); - return _ReloadReportWithMetadata(success: true); - } - - /// Performs a client-side hot reload by fetching libraries, handling - /// PausePostRequests, and invoking the reload. - Future _performClientSideHotReload(String isolateId) async { - _logger.info('Attempting a hot reload'); - - final debugger = await debuggerFuture; - final reloadedSrcs = {}; - final computedReloadedSrcs = Completer(); - final parsedAllReloadedSrcs = Completer(); - // Wait until all the reloaded scripts are parsed before we reinitialize - // metadata below. - final parsedScriptsSubscription = debugger.parsedScriptsController.stream - .listen((url) { - computedReloadedSrcs.future.then((_) { - reloadedSrcs.remove(Uri.parse(url).normalizePath().path); - if (reloadedSrcs.isEmpty && !parsedAllReloadedSrcs.isCompleted) { - parsedAllReloadedSrcs.complete(); - } - }); - }); - - // Initiate a hot reload. - _logger.info('Issuing \$dartHotReloadStartDwds request'); - final remoteObject = await inspector.jsEvaluate( - '\$dartHotReloadStartDwds();', - awaitPromise: true, - returnByValue: true, - ); - final reloadedSrcModuleLibraries = (remoteObject.value as List).cast(); - final reloadedModulesToLibraries = >{}; - for (final srcModuleLibrary in reloadedSrcModuleLibraries) { - final srcModuleLibraryCast = srcModuleLibrary.cast(); - reloadedSrcs.add( - Uri.parse(srcModuleLibraryCast['src'] as String).normalizePath().path, - ); - reloadedModulesToLibraries[srcModuleLibraryCast['module'] as String] = - (srcModuleLibraryCast['libraries'] as List).cast(); - } - computedReloadedSrcs.complete(); - if (reloadedSrcs.isNotEmpty) await parsedAllReloadedSrcs.future; - await parsedScriptsSubscription.cancel(); - - if (!pauseIsolatesOnStart) { - // Finish hot reload immediately. - _logger.info('Issuing \$dartHotReloadEndDwds request'); - await inspector.jsEvaluate( - '\$dartHotReloadEndDwds();', - awaitPromise: true, - ); - _logger.info('\$dartHotReloadEndDwds request complete.'); - // TODO(srujzs): Supposedly Dart DevTools uses a kIsolateReload event - // for breakpoints? We should confirm and add tests before sending the - // event. - return; - } - // If `pause_isolates_on_start` is enabled, pause and then the reload - // should finish later after the client removes breakpoints, reregisters - // breakpoints, and resumes. - _finishHotReloadOnResume = () async { - // Client finished setting breakpoints, called resume, and now the - // execution has resumed. Finish the hot reload so we start executing - // the new code instead. - _logger.info('Issuing \$dartHotReloadEndDwds request'); - await inspector.jsEvaluate( - '\$dartHotReloadEndDwds();', - awaitPromise: true, - ); - _logger.info('\$dartHotReloadEndDwds request complete.'); - }; - - // Pause and wait for the pause to occur before managing breakpoints. - await pause(isolateId, internalPause: true); - - await _reinitializeForHotReload(reloadedModulesToLibraries); - - // This lets the client know that we're ready for breakpoint management - // and a resume. - streamNotify( - 'Debug', - Event( - kind: EventKind.kPausePostRequest, - timestamp: DateTime.now().millisecondsSinceEpoch, - isolate: inspector.isolateRef, - ), - ); - } - - @override - Future removeBreakpoint(String isolateId, String breakpointId) => - wrapInErrorHandlerAsync( - 'removeBreakpoint', - () => _removeBreakpoint(isolateId, breakpointId), - ); - - Future _removeBreakpoint( - String isolateId, - String breakpointId, - ) async { - await isInitialized; - checkIsolate('removeBreakpoint', isolateId); - return (await debuggerFuture).removeBreakpoint(breakpointId); - } - - @override - Future resume(String isolateId, {String? step, int? frameIndex}) => - wrapInErrorHandlerAsync( - 'resume', - () => _resume(isolateId, step: step, frameIndex: frameIndex), - ); - - Future _resume( - String isolateId, { - String? step, - int? frameIndex, - }) async { - // If there is a subscriber listening for a resume event after hot-restart, - // then add the event to the stream and skip processing it. - if (resumeAfterRestartEventsController.hasListener) { - resumeAfterRestartEventsController.add(isolateId); - return Success(); - } - - if (inspector.appConnection.isStarted) { - await captureElapsedTime(() async { - await isInitialized; - await isStarted; - checkIsolate('resume', isolateId); - final debugger = await debuggerFuture; - return await debugger.resume(step: step, frameIndex: frameIndex); - }, (result) => DwdsEvent.resume(step)); - } else { - inspector.appConnection.runMain(); - } - // Finish the hot reload if needed. - if (_finishHotReloadOnResume != null) { - await _finishHotReloadOnResume!(); - _finishHotReloadOnResume = null; - } - return Success(); - } - - /// This method is deprecated in vm_service package. - /// - /// TODO(annagrin): remove after dart-code and IntelliJ stop using this API. - /// Issue: https://github.com/dart-lang/webdev/issues/1868 - /// - // ignore: annotate_overrides - Future setExceptionPauseMode( - String isolateId, - /*ExceptionPauseMode*/ - String mode, - ) => setIsolatePauseMode(isolateId, exceptionPauseMode: mode); - - @override - Future setIsolatePauseMode( - String isolateId, { - String? exceptionPauseMode, - // TODO(elliette): Is there a way to respect the shouldPauseOnExit parameter - // in Chrome? - bool? shouldPauseOnExit, - }) => wrapInErrorHandlerAsync( - 'setIsolatePauseMode', - () => - _setIsolatePauseMode(isolateId, exceptionPauseMode: exceptionPauseMode), - ); - - Future _setIsolatePauseMode( - String isolateId, { - String? exceptionPauseMode, - }) async { - await isInitialized; - checkIsolate('setIsolatePauseMode', isolateId); - return (await debuggerFuture).setExceptionPauseMode( - exceptionPauseMode ?? ExceptionPauseMode.kNone, - ); - } - - /// Returns a streamController that listens for console logs from chrome and - /// adds all events passing [filter] to the stream. - StreamController _chromeConsoleStreamController( - bool Function(ConsoleAPIEvent) filter, { - bool includeExceptions = false, - }) { - late StreamController controller; - StreamSubscription? chromeConsoleSubscription; - StreamSubscription? exceptionsSubscription; - - // This is an edge case for this lint apparently - // - // ignore: join_return_with_assignment - controller = StreamController.broadcast( - onCancel: () { - chromeConsoleSubscription?.cancel(); - exceptionsSubscription?.cancel(); - }, - onListen: () { - chromeConsoleSubscription = remoteDebugger.onConsoleAPICalled.listen(( - e, - ) { - if (!isIsolateRunning) return; - final isolateRef = inspector.isolateRef; - if (!filter(e)) return; - final args = e.params?['args'] as List?; - final item = args?[0] as Map?; - final value = '${item?["value"]}\n'; - controller.add( - Event( - kind: EventKind.kWriteEvent, - timestamp: DateTime.now().millisecondsSinceEpoch, - isolate: isolateRef, - ) - ..bytes = base64.encode(utf8.encode(value)) - ..timestamp = e.timestamp.toInt(), - ); - }); - if (includeExceptions) { - exceptionsSubscription = remoteDebugger.onExceptionThrown.listen(( - e, - ) async { - if (!isIsolateRunning) return; - final isolateRef = inspector.isolateRef; - var description = e.exceptionDetails.exception?.description; - if (description != null) { - description = await inspector.mapExceptionStackTrace(description); - } - controller.add( - Event( - kind: EventKind.kWriteEvent, - timestamp: DateTime.now().millisecondsSinceEpoch, - isolate: isolateRef, - )..bytes = base64.encode(utf8.encode(description ?? '')), - ); - }); - } - }, - ); - return controller; - } - - /// Parses the [DebugEvent] and emits a corresponding Dart VM Service - /// protocol [Event]. - @override - void parseDebugEvent(DebugEvent debugEvent) { - if (terminatingIsolates) return; - super.parseDebugEvent(debugEvent); - } - - /// Parses the [RegisterEvent] and emits a corresponding Dart VM Service - /// protocol [Event]. - @override - void parseRegisterEvent(RegisterEvent registerEvent) { - if (terminatingIsolates) return; - super.parseRegisterEvent(registerEvent); - } - - /// Listens for chrome console events and handles the ones we care about. - void _setUpChromeConsoleListeners(IsolateRef isolateRef) { - _consoleSubscription = remoteDebugger.onConsoleAPICalled.listen(( - event, - ) async { - if (terminatingIsolates) return; - if (event.type != 'debug') return; - if (!isIsolateRunning) return; - - final isolate = inspector.isolate; - if (isolateRef.id != isolate.id) return; - - final args = event.args; - final firstArgValue = (args.isNotEmpty ? args[0].value : null) as String?; - switch (firstArgValue) { - case 'dart.developer.inspect': - // All inspected objects should be real objects. - if (event.args[1].type != 'object') break; - - final inspectee = await _instanceRef(event.args[1]); - streamNotify( - EventStreams.kDebug, - Event( - kind: EventKind.kInspect, - timestamp: DateTime.now().millisecondsSinceEpoch, - isolate: isolateRef, - ) - ..inspectee = inspectee - ..timestamp = event.timestamp.toInt(), - ); - break; - case 'dart.developer.log': - await _handleDeveloperLog(isolateRef, event).catchError( - (Object error, StackTrace stackTrace) => _logger.warning( - 'Error handling developer log:', - error, - stackTrace, - ), - ); - break; - default: - break; - } - }); - } - - Future _handleDeveloperLog( - IsolateRef isolateRef, - ConsoleAPIEvent event, - ) async { - final logObject = - (event.params?['args'] as List?)?[1] as Map?; - final objectId = logObject?['objectId'] as String?; - // Always attempt to fetch the full properties instead of relying on - // `RemoteObject.preview` which only has truncated log messages: - // https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#type-RemoteObject - final logParams = objectId != null - ? await _fetchFullLogParams(objectId, logObject: logObject) - : _fetchAbbreviatedLogParams(logObject); - - final logRecord = LogRecord( - message: await _instanceRef(logParams['message']), - loggerName: await _instanceRef(logParams['name']), - level: logParams['level'] != null - ? int.tryParse(logParams['level']!.value.toString()) - : 0, - error: await _instanceRef(logParams['error']), - time: event.timestamp.toInt(), - sequenceNumber: logParams['sequenceNumber'] != null - ? int.tryParse(logParams['sequenceNumber']!.value.toString()) - : 0, - stackTrace: await _instanceRef(logParams['stackTrace']), - zone: await _instanceRef(logParams['zone']), - ); - - streamNotify( - EventStreams.kLogging, - Event( - kind: EventKind.kLogging, - timestamp: DateTime.now().millisecondsSinceEpoch, - isolate: isolateRef, - ) - ..logRecord = logRecord - ..timestamp = event.timestamp.toInt(), - ); - } - - Future> _fetchFullLogParams( - String objectId, { - required Map? logObject, - }) async { - final logParams = {}; - for (final property in await inspector.getProperties(objectId)) { - final name = property.name; - final value = property.value; - if (name != null && value != null) { - logParams[name] = value; - } - } - - // If for some reason we don't get the full log params, then return the - // abbreviated version instead: - if (logParams.isEmpty) { - return _fetchAbbreviatedLogParams(logObject); - } - return logParams; - } - - Map _fetchAbbreviatedLogParams( - Map? logObject, - ) { - final logParams = {}; - final preview = logObject?['preview'] as Map?; - final properties = preview?['properties'] as List?; - for (final dynamic property in properties ?? []) { - if (property is Map && property['name'] != null) { - logParams[property['name'] as String] = RemoteObject(property); - } - } - return logParams; - } - - Future _instanceRef(RemoteObject? obj) async { - final instance = obj == null ? null : await inspector.instanceRefFor(obj); - return instance ?? ChromeAppInstanceHelper.kNullInstanceRef; - } -} - -// The default `ReloadReport`'s `toJson` only emits the type and success of the -// operation. Override it to expose additional possible metadata in the `json`. -// This then gets called in the VM service code that handles request and -// responses. -class _ReloadReportWithMetadata extends ReloadReport { - _ReloadReportWithMetadata({super.success}); - - @override - Map toJson() { - final jsonified = { - 'type': type, - 'success': success ?? false, - }; - // Include any other metadata we may have included in `json`, potentially - // even overriding the above defaults. - for (final jsonKey in super.json?.keys ?? []) { - jsonified[jsonKey] = super.json![jsonKey]; - } - return jsonified; - } -} - -/// The `type`s of [ConsoleAPIEvent]s that are treated as `stderr` logs. -const _stderrTypes = ['error']; - -/// The `type`s of [ConsoleAPIEvent]s that are treated as `stdout` logs. -const _stdoutTypes = ['log', 'info', 'warning']; diff --git a/dwds/lib/src/services/debug_service.dart b/dwds/lib/src/services/debug_service.dart deleted file mode 100644 index 8975167430..0000000000 --- a/dwds/lib/src/services/debug_service.dart +++ /dev/null @@ -1,279 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:async'; -import 'dart:convert'; -import 'dart:io'; -import 'dart:math'; -import 'dart:typed_data'; - -import 'package:dds/dds_launcher.dart'; -import 'package:dwds/src/config/tool_configuration.dart'; -import 'package:dwds/src/events.dart'; -import 'package:dwds/src/services/proxy_service.dart'; -import 'package:dwds/src/utilities/server.dart'; -import 'package:logging/logging.dart'; -import 'package:meta/meta.dart'; -import 'package:shelf/shelf.dart' as shelf; -import 'package:shelf_web_socket/shelf_web_socket.dart'; -import 'package:stream_channel/stream_channel.dart'; -import 'package:vm_service/vm_service.dart'; -import 'package:vm_service_interface/vm_service_interface.dart'; - -bool _acceptNewConnections = true; - -final _clientConnections = {}; -int _clientId = 0; - -Logger _logger = Logger('DebugService'); - -/// Common interface for debug services (Chrome or WebSocket based). -abstract class DebugService { - DebugService({ - required this.serverHostname, - required this.ddsConfig, - required this.urlEncoder, - required this.useSse, - }); - - /// The URI pointing to the VM service implementation hosted by the - /// [DebugService]. - String get uri => _uri.toString(); - - Uri get _uri => _cachedUri ??= () { - final dds = _dds; - if (ddsConfig.enable && dds != null) { - return useSse ? dds.sseUri : dds.wsUri; - } - return useSse - ? Uri( - scheme: 'sse', - host: _server.address.host, - port: _server.port, - path: '$authToken/\$debugHandler', - ) - : Uri( - scheme: 'ws', - host: _server.address.host, - port: _server.port, - path: authToken, - ); - }(); - - Uri? _cachedUri; - String? _ddsUri; - - late final T proxyService; - - final UrlEncoder? urlEncoder; - - late final String authToken = _makeAuthToken(); - final bool useSse; - - Future get encodedUri async { - return _encodedUri ??= await urlEncoder?.call(uri) ?? uri; - } - - String? _encodedUri; - - DartDevelopmentServiceConfiguration ddsConfig; - DartDevelopmentServiceLauncher? _dds; - - final String serverHostname; - late final HttpServer _server; - - String get hostname => _uri.host; - int get port => _uri.port; - - final serviceExtensionRegistry = ServiceExtensionRegistry(); - - /// Null until [close] is called. - /// - /// All subsequent calls to [close] will return this future. - Future? _closed; - - @protected - @mustCallSuper - @mustBeOverridden - // False positive - // ignore: avoid-redundant-async - Future initialize({required T proxyService}) async { - this.proxyService = proxyService; - } - - @protected - Future serve({required shelf.Handler handler}) async { - _server = await startHttpServer(serverHostname, port: 44456); - serveHttpRequests(_server, handler, (e, s) { - _logger.warning('Error serving requests', e); - emitEvent(DwdsEvent.httpRequestException('$runtimeType', '$e:$s')); - }); - } - - /// Closes the debug service and associated resources. - Future close() => _closed ??= Future.wait([ - _server.close(), - if (_dds != null) _dds!.shutdown(), - ]); - - Future startDartDevelopmentService() async { - // Note: DDS can handle both web socket and SSE connections with no - // additional configuration. - final hostname = _server.address.host; - _dds = await DartDevelopmentServiceLauncher.start( - appName: ddsConfig.appName ?? 'Unknown web app', - remoteVmServiceUri: Uri( - scheme: 'http', - host: hostname, - port: _server.port, - path: authToken, - ), - serviceUri: Uri( - scheme: 'http', - host: hostname, - port: ddsConfig.port ?? 0, - ), - devToolsServerAddress: ddsConfig.devToolsServerAddress, - serveDevTools: ddsConfig.serveDevTools, - dartExecutable: ddsConfig.dartExecutable, - ); - return _dds!; - } - - void yieldControlToDDS(String uri) { - // We track the URI of the connected DDS instance seperately instead of - // relying on _dds being non-null as there's no guarantee that DWDS is the - // tool starting DDS. - if (_ddsUri != null) { - // This exception is identical to the one thrown from - // sdk/lib/vmservice/vmservice.dart - throw RPCError( - '_yieldControlToDDS', - RPCErrorKind.kFeatureDisabled.code, - 'A DDS instance is already connected at $_ddsUri.', - {'ddsUri': _ddsUri.toString()}, - ); - } - _acceptNewConnections = false; - _ddsUri = uri; - } - - @protected - shelf.Handler initializeWebSocketHandler({ - required ProxyService proxyService, - void Function(Map)? onRequest, - void Function(Map)? onResponse, - }) { - return _wrapHandler( - webSocketHandler((Object webSocket, String? subprotocol) { - handleConnection( - webSocket as StreamChannel, - proxyService, - serviceExtensionRegistry, - onRequest: onRequest, - onResponse: onResponse, - ); - }), - authToken: authToken, - ); - } - - shelf.Handler _wrapHandler(shelf.Handler innerHandler, {String? authToken}) { - return (shelf.Request request) { - if (!_acceptNewConnections) { - return shelf.Response.forbidden( - 'Cannot connect directly to the VM service as a Dart Development ' - 'Service (DDS) instance has taken control and can be found at ' - '$_ddsUri.', - ); - } - if (authToken != null && request.url.pathSegments.first != authToken) { - return shelf.Response.forbidden('Incorrect auth token'); - } - return innerHandler(request); - }; - } - - @protected - @mustCallSuper - void handleConnection( - StreamChannel channel, - ProxyService proxyService, - ServiceExtensionRegistry serviceExtensionRegistry, { - void Function(Map)? onRequest, - void Function(Map)? onResponse, - }) { - final clientId = _clientId++; - final responseController = StreamController>(); - responseController.stream - .asyncMap((response) async { - // This error indicates a successful invocation to _yieldControlToDDS. - // We don't have a good way to access the list of connected clients - // while also being able to determine which client invoked the RPC - // without some form of client ID. - // - // We can probably do better than this, but it will likely involve - // some refactoring. - if (response case { - 'error': { - 'code': DisconnectNonDartDevelopmentServiceClients.kErrorCode, - }, - }) { - final nonDdsClients = _clientConnections.entries - .where((MapEntry e) => e.key != clientId) - .map((e) => e.value); - await Future.wait([ - for (final client in nonDdsClients) client.sink.close(), - ]); - // Remove the artificial error and return Success. - response.remove('error'); - response['result'] = Success().toJson(); - } - if (onResponse != null) onResponse(response); - return jsonEncode(response); - }) - .listen(channel.sink.add, onError: channel.sink.addError); - final inputStream = channel.stream.map((value) { - if (value is List) { - value = utf8.decode(value); - } else if (value is! String) { - throw StateError( - 'Got value with unexpected type ${value.runtimeType} from web ' - 'socket, expected a List or String.', - ); - } - final request = Map.from( - jsonDecode(value as String) as Map, - ); - if (onRequest != null) onRequest(request); - return request; - }); - VmServerConnection( - inputStream, - responseController.sink, - serviceExtensionRegistry, - proxyService, - ).done.whenComplete(() { - _clientConnections.remove(clientId); - if (!_acceptNewConnections && _clientConnections.isEmpty) { - // DDS has disconnected so we can allow for clients to connect directly - // to DWDS. - _ddsUri = null; - _acceptNewConnections = true; - } - }); - _clientConnections[clientId] = channel; - } - - // Creates a random auth token for more secure connections. - String _makeAuthToken() { - final tokenBytes = 8; - final bytes = Uint8List(tokenBytes); - final random = Random.secure(); - for (var i = 0; i < tokenBytes; i++) { - bytes[i] = random.nextInt(256); - } - return base64Url.encode(bytes); - } -} diff --git a/dwds/lib/src/services/expression_compiler.dart b/dwds/lib/src/services/expression_compiler.dart deleted file mode 100644 index 15e143368a..0000000000 --- a/dwds/lib/src/services/expression_compiler.dart +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -/// Options passed to DDC and the expression compiler. -class CompilerOptions { - final ModuleFormat moduleFormat; - - final bool canaryFeatures; - final List experiments; - - /// Whether the compiler allows the deprecated JS interop libraries, such as - /// `dart:html`. - /// - /// If `null`, no flag is passed and the compiler default is used. - final bool? deprecatedJsInterop; - - CompilerOptions({ - required this.moduleFormat, - required this.canaryFeatures, - required this.experiments, - this.deprecatedJsInterop, - }); -} - -/// Indicates the module system DDC is targeting. -enum ModuleFormat { amd, ddc, es6 } - -/// Result of compilation of dart expression to JavaScript -class ExpressionCompilationResult { - final bool isError; - final String result; - - /// Result of compilation from dart to JavaScript - /// - /// [result] JavaScript expression as String, or error message - /// if compilation has failed - /// [isError] true if compilation has failed, false otherwise - ExpressionCompilationResult(this.result, this.isError); - - @override - String toString() => 'result: $result, isError:$isError'; -} - -/// Interface to provide means of compiling expressions from dart to JavaScript -/// used to implement expression evaluation in any tools using dwds -abstract class ExpressionCompiler { - /// Compiles [expression] in [libraryUri] at [line]:[column] to JavaScript - /// in [moduleName]. - /// - /// Values listed in [jsFrameValues] are substituted for their names in the - /// [expression]. - /// - /// Ensures that all [jsModules] are loaded and accessible inside the - /// expression. - /// - /// Returns [ExpressionCompilationResult] - /// Errors are reported using onDiagnostic function - /// [moduleName] is of the form '/packages/hello_world_main.dart' - /// [jsFrameValues] is a map from js variable name to its primitive value - /// or another variable name, for example - /// { 'x': '1', 'y': 'y', 'o': 'null' } - /// [jsModules] is a map from variable name to the module name, where - /// variable name is the name originally used in JavaScript to contain the - /// module object, for example: - /// { 'dart':'dart_sdk', 'main': '/packages/hello_world_main.dart' } - /// - /// Should wait for the dependencies to update if called during a call to - /// [updateDependencies]. - Future compileExpressionToJs( - String isolateId, - String libraryUri, - String scriptUri, - int line, - int column, - Map jsModules, - Map jsFrameValues, - String moduleName, - String expression, - ); - - /// Trigger (re-)load of kernel files for modules. - /// - /// (Re-)load summaries for changed modules and trigger reload - /// of full dill file for module on first expression evaluation - /// in the module. - /// - /// [modules]: moduleName -> moduleInfo - /// - /// [updateDependencies] is called during isolate creation. - Future updateDependencies(Map modules); - - /// Initializes the compiler with the app build settings. - /// - /// May be called multiple times and always before [updateDependencies]. - Future initialize(CompilerOptions options); -} - -class ModuleInfo { - final String fullDillPath; - final String summaryPath; - - ModuleInfo(this.fullDillPath, this.summaryPath); - - @override - String toString() => '{ $fullDillPath, $summaryPath }'; -} diff --git a/dwds/lib/src/services/expression_compiler_service.dart b/dwds/lib/src/services/expression_compiler_service.dart deleted file mode 100644 index cf5cc12726..0000000000 --- a/dwds/lib/src/services/expression_compiler_service.dart +++ /dev/null @@ -1,313 +0,0 @@ -// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:async'; -import 'dart:isolate'; - -import 'package:async/async.dart'; -import 'package:dwds/src/services/expression_compiler.dart'; -import 'package:dwds/src/utilities/sdk_configuration.dart'; -import 'package:logging/logging.dart'; -import 'package:meta/meta.dart'; - -/// Returns the arguments for the DDC expression compiler worker. -@visibleForTesting -List expressionCompilerWorkerArgs({ - required Uri sdkSummaryUri, - required String address, - required int port, - required CompilerOptions compilerOptions, - required bool verbose, -}) => [ - '--experimental-expression-compiler', - '--dart-sdk-summary', - '$sdkSummaryUri', - '--asset-server-address', - address, - '--asset-server-port', - '$port', - '--module-format', - compilerOptions.moduleFormat.name, - if (verbose) '--verbose', - for (final experiment in compilerOptions.experiments) - '--enable-experiment=$experiment', - if (compilerOptions.canaryFeatures) '--canary', - ?_deprecatedJsInteropArg(compilerOptions.deprecatedJsInterop), -]; - -/// The `--[no-]deprecated-js-interop` argument, or `null` to use the compiler -/// default. -String? _deprecatedJsInteropArg(bool? deprecatedJsInterop) => - switch (deprecatedJsInterop) { - null => null, - true => '--deprecated-js-interop', - false => '--no-deprecated-js-interop', - }; - -class _Compiler { - static final _logger = Logger('ExpressionCompilerService'); - final StreamQueue _responseQueue; - final ReceivePort _receivePort; - final SendPort _sendPort; - - Future? _dependencyUpdate; - - _Compiler._(this._responseQueue, this._receivePort, this._sendPort); - - /// Sends [request] on [_sendPort] and returns the next event from the - /// response stream. - Future> _send(Map request) async { - _sendPort.send(request); - if (!await _responseQueue.hasNext) { - return { - 'succeeded': false, - 'errors': ['compilation worker response stream closed'], - }; - } - final response = await _responseQueue.next; - if (response is! Map) { - return { - 'succeeded': false, - 'errors': ['compilation worker returned invalid response: $response'], - }; - } - return response; - } - - /// Starts expression compilation service. - /// - /// Starts expression compiler worker in an isolate and creates the - /// expression compilation service that communicates to the worker. - /// - /// [sdkConfiguration] describes the locations of SDK files used in - /// expression compilation (summaries, libraries spec, compiler worker - /// snapshot). - /// - /// Performs handshake with the isolate running expression compiler - /// worker to establish communication via send/receive ports, returns - /// the service after the communication is established. - /// - /// Users need to stop the service by calling [stop]. - static Future<_Compiler> start( - String address, - int port, - SdkConfiguration sdkConfiguration, - CompilerOptions compilerOptions, - bool verbose, - ) async { - sdkConfiguration.validateSdkDir(); - sdkConfiguration.validateSummaries(); - - final workerUri = sdkConfiguration.compilerWorkerUri!; - final sdkSummaryUri = sdkConfiguration.sdkSummaryUri!; - - final args = expressionCompilerWorkerArgs( - sdkSummaryUri: sdkSummaryUri, - address: address, - port: port, - compilerOptions: compilerOptions, - verbose: verbose, - ); - - _logger.info('Starting...'); - _logger.finest('$workerUri ${args.join(' ')}'); - - final receivePort = ReceivePort(); - await Isolate.spawnUri( - workerUri, - args, - receivePort.sendPort, - // Note(annagrin): ddc snapshot is generated with no asserts, so we have - // to run it unchecked in case the calling isolate is checked, as it - // happens, for example, when debugging webdev in VSCode or running tests - // using 'dart run' - checked: false, - ); - - final responseQueue = StreamQueue(receivePort); - final sendPort = await responseQueue.next as SendPort; - - final service = _Compiler._(responseQueue, receivePort, sendPort); - - return service; - } - - Future updateDependencies(Map modules) async { - final updateCompleter = Completer(); - _dependencyUpdate = updateCompleter.future; - - _logger.info('Updating dependencies...'); - _logger.finest('Dependencies: $modules'); - - final response = await _send({ - 'command': 'UpdateDeps', - 'inputs': [ - for (final moduleName in modules.keys) - { - 'path': modules[moduleName]!.fullDillPath, - 'summaryPath': modules[moduleName]!.summaryPath, - 'moduleName': moduleName, - }, - ], - }); - final result = (response['succeeded'] as bool?) ?? false; - if (result) { - _logger.info('Updated dependencies.'); - } else { - final errors = response['errors']; - final exception = response['exception']; - final s = response['stackTrace'] as String?; - final stackTrace = s == null ? null : StackTrace.fromString(s); - _logger.severe( - 'Failed to update dependencies: $errors', - exception, - stackTrace, - ); - } - updateCompleter.complete(); - return result; - } - - Future compileExpressionToJs( - String libraryUri, - String scriptUri, - int line, - int column, - Map jsModules, - Map jsFrameValues, - String moduleName, - String expression, - ) async { - _logger.finest('Waiting for dependencies to update'); - if (_dependencyUpdate == null) { - _logger.warning( - 'Dependencies are not updated before compiling expressions', - ); - return ExpressionCompilationResult('', true); - } - - await _dependencyUpdate; - - _logger.finest('Compiling "$expression" at $libraryUri:$line'); - - final response = await _send({ - 'command': 'CompileExpression', - 'expression': expression, - 'line': line, - 'column': column, - 'jsModules': jsModules, - 'jsScope': jsFrameValues, - 'libraryUri': libraryUri, - 'scriptUri': scriptUri, - 'moduleName': moduleName, - }); - - final error = _createErrorMsg(response); - final procedure = (response['compiledProcedure'] as String?) ?? ''; - final succeeded = (response['succeeded'] as bool?) ?? false; - final result = succeeded ? procedure : error; - - if (succeeded) { - _logger.finest('Compiled "$expression" to: $result'); - } else { - _logger.finest('Failed to compile "$expression": $result'); - } - return ExpressionCompilationResult(result, !succeeded); - } - - String _createErrorMsg(Map response) { - final errors = response['errors'] as List?; - if (errors != null && errors.isNotEmpty) return errors.first; - - final e = response['exception']; - final s = response['stackTrace']; - return e != null ? '$e:$s' : ''; - } - - /// Stops the service. - /// - /// Terminates the isolate running expression compiler worker - /// and marks the service as stopped. - void stop() { - _sendPort.send({'command': 'Shutdown'}); - _receivePort.close(); - _logger.info('Stopped.'); - } -} - -/// Service that handles expression compilation requests. -/// -/// Expression compiler service spawns a dartdevc in expression compilation -/// mode in an isolate and communicates with the isolate via send/receive -/// ports. It also handles full dill file read requests from the isolate -/// and redirects them to the asset server. -/// -/// Uses [_address] and [_port] to communicate and to redirect asset -/// requests to the asset server. -/// -/// Configuration created by [sdkConfigurationProvider] describes the -/// locations of SDK files used in expression compilation (summaries, -/// libraries spec, compiler worker snapshot). -/// -/// Users need to stop the service by calling [stop]. -class ExpressionCompilerService implements ExpressionCompiler { - final _compiler = Completer<_Compiler>(); - final String _address; - final FutureOr _port; - final bool _verbose; - - final SdkConfigurationProvider sdkConfigurationProvider; - - ExpressionCompilerService( - this._address, - this._port, { - this._verbose = false, - required this.sdkConfigurationProvider, - }); - - @override - Future compileExpressionToJs( - String isolateId, - String libraryUri, - String scriptUri, - int line, - int column, - Map jsModules, - Map jsFrameValues, - String moduleName, - String expression, - ) async => (await _compiler.future).compileExpressionToJs( - libraryUri, - scriptUri, - line, - column, - jsModules, - jsFrameValues, - moduleName, - expression, - ); - - @override - Future initialize(CompilerOptions options) async { - if (_compiler.isCompleted) return; - - final compiler = await _Compiler.start( - _address, - await _port, - await sdkConfigurationProvider.configuration, - options, - _verbose, - ); - - _compiler.complete(compiler); - } - - @override - Future updateDependencies(Map modules) async => - (await _compiler.future).updateDependencies(modules); - - Future stop() async { - if (_compiler.isCompleted) return (await _compiler.future).stop(); - } -} diff --git a/dwds/lib/src/services/expression_evaluator.dart b/dwds/lib/src/services/expression_evaluator.dart deleted file mode 100644 index 1230b96060..0000000000 --- a/dwds/lib/src/services/expression_evaluator.dart +++ /dev/null @@ -1,566 +0,0 @@ -// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'package:dwds/src/config/tool_configuration.dart'; -import 'package:dwds/src/debugging/chrome_inspector.dart'; -import 'package:dwds/src/debugging/dart_scope.dart'; -import 'package:dwds/src/debugging/debugger.dart'; -import 'package:dwds/src/debugging/location.dart'; -import 'package:dwds/src/debugging/modules.dart'; -import 'package:dwds/src/services/expression_compiler.dart'; -import 'package:dwds/src/services/javascript_builder.dart'; -import 'package:dwds/src/utilities/conversions.dart'; -import 'package:dwds/src/utilities/objects.dart' as chrome; -import 'package:logging/logging.dart'; -import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'; - -class EvaluationErrorKind { - EvaluationErrorKind._(); - - static const compilation = 'CompilationError'; - static const type = 'TypeError'; - static const reference = 'ReferenceError'; - static const internal = 'InternalError'; - static const asyncFrame = 'AsyncFrameError'; - static const invalidInput = 'InvalidInputError'; - static const loadModule = 'LoadModuleError'; -} - -/// ExpressionEvaluator provides functionality to evaluate dart expressions -/// from text user input in the debugger, using chrome remote debugger to -/// collect context for evaluation (scope, types, modules), and using -/// ExpressionCompilerInterface to compile dart expressions to JavaScript. -class ExpressionEvaluator { - final String _entrypoint; - final ChromeAppInspector _inspector; - final Debugger _debugger; - final Locations _locations; - final Modules _modules; - final ExpressionCompiler _compiler; - final _logger = Logger('ExpressionEvaluator'); - bool _closed = false; - - /// Strip synthetic library name from compiler error messages. - static final _syntheticNameFilterRegex = RegExp( - 'org-dartlang-debug:synthetic_debug_expression:.*:.*Error: ', - ); - - /// Find module path from the XHR call network error message received from - /// chrome. - /// - /// Example: - /// NetworkError: Failed to load `http://.com/path/to/module.js?` - static final _loadModuleErrorRegex = RegExp( - r".*Failed to load '.*\.com/(.*\.js).*", - ); - - ExpressionEvaluator( - this._entrypoint, - this._inspector, - this._debugger, - this._locations, - this._modules, - this._compiler, - ); - - /// Create and error with [severity] and [message] - /// - /// [severity] is one of kinds in [EvaluationErrorKind] - RemoteObject createError(String severity, String message) { - return RemoteObject({'type': severity, 'value': message}); - } - - void close() { - _closed = true; - } - - /// Evaluate dart expression inside a given library. - /// - /// Uses ExpressionCompiler interface to compile the expression to - /// JavaScript and sends evaluate requests to chrome to calculate - /// the final result. - /// - /// Returns remote object containing the result of evaluation or error. - /// - /// [isolateId] current isolate ID. - /// [libraryUri] dart library to evaluate the expression in. - /// [expression] dart expression to evaluate. - Future evaluateExpression( - String isolateId, - String? libraryUri, - String expression, - Map? scope, - ) async { - if (_closed) { - return createError( - EvaluationErrorKind.internal, - 'expression evaluator closed.', - ); - } - - scope ??= {}; - - if (expression.isEmpty) { - return createError(EvaluationErrorKind.invalidInput, expression); - } - - if (libraryUri == null) { - return createError(EvaluationErrorKind.invalidInput, 'no library uri'); - } - - final module = await _modules.moduleForLibrary(libraryUri); - if (module == null) { - return createError( - EvaluationErrorKind.internal, - 'no module for $libraryUri', - ); - } - - // Wrap the expression in a lambda so we can call it as a function. - expression = _createDartLambda(expression, scope.keys); - _logger.finest('Evaluating "$expression" at $module'); - - // Compile expression using an expression compiler, such as - // frontend server or expression compiler worker. - final compilationResult = await _compiler.compileExpressionToJs( - isolateId, - libraryUri.toString(), - // Evaluating at "the library level" (and passing line 0 column 0) we'll - // also just pass the library uri as the script uri. - libraryUri.toString(), - 0, - 0, - {}, - {}, - module, - expression, - ); - - final isError = compilationResult.isError; - final jsResult = compilationResult.result; - if (isError) { - return _formatCompilationError(jsResult); - } - - // Strip try/catch incorrectly added by the expression compiler. - final jsCode = _maybeStripTryCatch(jsResult); - - // Send JS expression to chrome to evaluate. - var result = await _callJsFunction(jsCode, scope); - result = await _formatEvaluationError(result); - - _logger.finest('Evaluated "$expression" to "${result.json}"'); - return result; - } - - /// Evaluate dart expression inside a given frame (function). - /// - /// Gets necessary context (types, scope, module names) data from chrome, - /// uses ExpressionCompiler interface to compile the expression to - /// JavaScript, and sends evaluate requests to chrome to calculate the - /// final result. - /// - /// Returns remote object containing the result of evaluation or error. - /// - /// [isolateId] current isolate ID. - /// [frameIndex] JavaScript frame to evaluate the expression in. - /// [expression] dart expression to evaluate. - /// [scope] additional scope to use in the expression as a map from - /// variable names to remote object IDs. - /// - ///////////////////////////////// - /// **Example - without scope** - /// - /// To evaluate a dart expression `e`, we perform the following: - /// - /// 1. compile dart expression `e` to JavaScript expression `jsExpr` - /// using the expression compiler (i.e. frontend server or expression - /// compiler worker). - /// - /// 2. create JavaScript wrapper expression, `jsWrapperExpr`, defined as - /// - /// ```JavaScript - /// try { - /// jsExpr; - /// } catch (error) { - /// error.name + ": " + error.message; - /// } - /// ``` - /// - /// 3. evaluate `JsExpr` using `Debugger.evaluateOnCallFrame` chrome API. - /// - /// ////////////////////////// - /// **Example - with scope** - /// - /// To evaluate a dart expression - /// ```dart - /// this.t + a + x + y - /// ``` - /// in a dart scope that defines `a` and `this`, and additional scope - /// `x, y`, we perform the following: - /// - /// 1. compile dart function - /// - /// ```dart - /// (x, y, a) { return this.t + a + x + y; } - /// ``` - /// - /// to JavaScript function - /// - /// ```jsFunc``` - /// - /// using the expression compiler (i.e. frontend server or expression - /// compiler worker). - /// - /// 2. create JavaScript wrapper function, `jsWrapperFunc`, defined as - /// - /// ```JavaScript - /// function (x, y, a, __t$this) { - /// try { - /// return function (x, y, a) { - /// return jsFunc(x, y, a); - /// }.bind(__t$this)(x, y, a); - /// } catch (error) { - /// return error.name + ": " + error.message; - /// } - /// } - /// ``` - /// - /// 3. collect scope variable object IDs for total scope - /// (original frame scope from WipCallFrame + additional scope passed - /// by the user). - /// - /// 4. call `jsWrapperFunc` using `Runtime.callFunctionOn` chrome API - /// with scope variable object IDs passed as arguments. - Future evaluateExpressionInFrame( - String isolateId, - int frameIndex, - String expression, - Map? scope, - ) async { - scope ??= {}; - - if (expression.isEmpty) { - return createError(EvaluationErrorKind.invalidInput, expression); - } - - // Get JS scope and current JS location. - final jsFrame = _debugger.jsFrameForIndex(frameIndex); - if (jsFrame == null) { - return createError( - EvaluationErrorKind.asyncFrame, - 'Expression evaluation in async frames ' - 'is not supported. No frame with index $frameIndex.', - ); - } - - final functionName = jsFrame.functionName; - final jsLine = jsFrame.location.lineNumber; - final jsScriptId = jsFrame.location.scriptId; - final jsColumn = jsFrame.location.columnNumber; - final frameScope = await _collectLocalFrameScope(jsFrame); - - // Find corresponding dart location and scope. - final url = _debugger.urlForScriptId(jsScriptId); - if (url == null) { - return createError( - EvaluationErrorKind.internal, - 'Cannot find url for JS script: $jsScriptId', - ); - } - final locationMap = await _locations.locationForJs(url, jsLine, jsColumn); - if (locationMap == null) { - return createError( - EvaluationErrorKind.internal, - 'Cannot find Dart location for JS location: ' - 'url: $url, ' - 'function: $functionName, ' - 'line: $jsLine, ' - 'column: $jsColumn', - ); - } - - final dartLocation = locationMap.dartLocation; - final dartSourcePath = dartLocation.uri.serverPath; - final libraryUri = await _modules.libraryForSource(dartSourcePath); - final scriptUri = await _modules.libraryOrPartForSource(dartSourcePath); - if (libraryUri == null) { - return createError( - EvaluationErrorKind.internal, - 'no libraryUri for $dartSourcePath', - ); - } - - final module = await _modules.moduleForLibrary(libraryUri.toString()); - if (module == null) { - return createError( - EvaluationErrorKind.internal, - 'no module for $libraryUri ($dartSourcePath)', - ); - } - - _logger.finest( - 'Evaluating "$expression" at $module, ' - '$libraryUri:${dartLocation.line}:${dartLocation.column} ' - 'or rather $scriptUri:${dartLocation.line}:${dartLocation.column} ' - 'with scope: $scope', - ); - - if (scope.isNotEmpty) { - final totalScope = Map.from(scope)..addAll(frameScope); - expression = _createDartLambda(expression, totalScope.keys); - } - - _logger.finest('Compiling "$expression"'); - - // Compile expression using an expression compiler, such as - // frontend server or expression compiler worker. - // - // TODO(annagrin): map JS locals to dart locals in the expression - // and JS scope before passing them to the dart expression compiler. - // Issue: https://github.com/dart-lang/sdk/issues/40273 - final compilationResult = await _compiler.compileExpressionToJs( - isolateId, - libraryUri.toString(), - scriptUri.toString(), - dartLocation.line, - dartLocation.column, - {}, - frameScope.map((key, value) => MapEntry(key, key)), - module, - expression, - ); - - final isError = compilationResult.isError; - final jsResult = compilationResult.result; - if (isError) { - return _formatCompilationError(jsResult); - } - - // Strip try/catch incorrectly added by the expression compiler. - final jsCode = _maybeStripTryCatch(jsResult); - - // Send JS expression to chrome to evaluate. - var result = scope.isEmpty - ? await _evaluateJsExpressionInFrame(frameIndex, jsCode) - : await _callJsFunctionInFrame(frameIndex, jsCode, scope, frameScope); - - result = await _formatEvaluationError(result); - _logger.finest('Evaluated "$expression" to "${result.json}"'); - return result; - } - - /// Call JavaScript [function] with [scope] on frame [frameIndex]. - /// - /// Wrap the [function] in a lambda that takes scope variables as parameters. - /// Send JS expression to chrome to evaluate in frame with [frameIndex] - /// with the provided [scope]. - /// - /// [frameIndex] is the index of the frame to call the function in. - /// [function] is the JS function to evaluate. - /// [scope] is the additional scope as a map from scope variables to - /// remote object IDs. - /// [frameScope] is the original scope as a map from scope variables - /// to remote object IDs. - Future _callJsFunctionInFrame( - int frameIndex, - String function, - Map scope, - Map frameScope, - ) async { - final totalScope = Map.from(scope)..addAll(frameScope); - final thisObject = await _debugger.evaluateJsOnCallFrameIndex( - frameIndex, - 'this', - ); - - final thisObjectId = thisObject.objectId; - if (thisObjectId != null) { - totalScope['this'] = thisObjectId; - } - - return _callJsFunction(function, totalScope); - } - - /// Call the [function] with [scope] as arguments. - /// - /// Wrap the [function] in a lambda that takes scope variables as parameters. - /// Send JS expression to chrome to evaluate with the provided [scope]. - /// - /// [function] is the JS function to evaluate. - /// [scope] is a map from scope variables to remote object IDs. - Future _callJsFunction( - String function, - Map scope, - ) { - final jsCode = _createEvalFunction(function, scope.keys); - - _logger.finest('Evaluating JS: "$jsCode" with scope: $scope'); - return _inspector.callFunction(jsCode, scope.values); - } - - /// Evaluate JavaScript [expression] on frame [frameIndex]. - /// - /// Wrap the [expression] in a try/catch expression to catch errors. - /// Send JS expression to chrome to evaluate on frame [frameIndex]. - /// - /// [frameIndex] is the index of the frame to call the function in. - /// [expression] is the JS function to evaluate. - Future _evaluateJsExpressionInFrame( - int frameIndex, - String expression, - ) { - final jsCode = _createEvalExpression(expression); - - _logger.finest('Evaluating JS: "$jsCode"'); - return _debugger.evaluateJsOnCallFrameIndex(frameIndex, jsCode); - } - - static String? _getObjectId(RemoteObject? object) => - object?.objectId ?? dartIdFor(object?.value); - - RemoteObject _formatCompilationError(String error) { - // Frontend currently gives a text message including library name - // and function name on compilation error. Strip this information - // since it shows synthetic names that are only used for temporary - // debug library during expression evaluation. - // - // TODO(annagrin): modify frontend to avoid stripping dummy names - // [issue 40449](https://github.com/dart-lang/sdk/issues/40449) - if (error.startsWith('[')) { - error = error.substring(1); - } - if (error.endsWith(']')) { - error = error.substring(0, error.lastIndexOf(']')); - } - if (error.contains('InternalError: ')) { - error = error.replaceAll('InternalError: ', ''); - return createError(EvaluationErrorKind.internal, error); - } - error = error.replaceAll(_syntheticNameFilterRegex, ''); - return createError(EvaluationErrorKind.compilation, error); - } - - Future _formatEvaluationError(RemoteObject result) async { - if (result.type == 'string') { - var error = '${result.value}'; - if (error.startsWith('ReferenceError: ')) { - error = error.replaceFirst('ReferenceError: ', ''); - return createError(EvaluationErrorKind.reference, error); - } else if (error.startsWith('TypeError: ')) { - error = error.replaceFirst('TypeError: ', ''); - return createError(EvaluationErrorKind.type, error); - } else if (error.startsWith('NetworkError: ')) { - var modulePath = _loadModuleErrorRegex.firstMatch(error)?.group(1); - final module = modulePath != null - ? await globalToolConfiguration.loadStrategy.moduleForServerPath( - _entrypoint, - modulePath, - ) - : 'unknown'; - modulePath ??= 'unknown'; - error = - 'Module is not loaded : $module (path: $modulePath). ' - 'Accessing libraries that have not yet been used in the ' - 'application is not supported during expression evaluation.'; - return createError(EvaluationErrorKind.loadModule, error); - } - } - return result; - } - - /// Return local scope as a map from variable names to remote object IDs. - /// - /// [frame] is the current frame index. - Future> _collectLocalFrameScope( - WipCallFrame frame, - ) async { - final scope = {}; - - void collectVariables(Iterable variables) { - for (final p in variables) { - final name = p.name; - final value = p.value; - // TODO: null values represent variables optimized by v8. - // Show that to the user. - if (name != null && value != null && !_isUndefined(value)) { - final objectId = _getObjectId(p.value); - if (objectId != null) { - scope[name] = objectId; - } - } - } - } - - // skip library and main scope - final scopeChain = filterScopes(frame).reversed; - for (final scope in scopeChain) { - final objectId = scope.object.objectId; - if (objectId != null) { - final scopeProperties = await _inspector.getProperties(objectId); - collectVariables(scopeProperties); - } - } - - return scope; - } - - bool _isUndefined(RemoteObject value) => value.type == 'undefined'; - - static String _createDartLambda(String expression, Iterable params) => - '(${params.join(', ')}) { return $expression; }'; - - /// Strip try/catch incorrectly added by the expression compiler. - /// TODO: remove adding try/catch block in expression compiler. - /// https://github.com/dart-lang/webdev/issues/1341, then remove - /// this stripping code. - static String _maybeStripTryCatch(String jsCode) { - // Match the wrapping generated by the expression compiler exactly - // so the matching does not succeed naturally after the wrapping is - // removed: - // - // Expression compiler's wrapping: - // - // '\ntry {' - // '\n ($jsExpression(' - // '\n $args' - // '\n ))' - // '\n} catch (error) {' - // '\n error.name + ": " + error.message;' - // '\n}'; - // - final lines = jsCode.split('\n'); - if (lines.length > 5) { - final tryLines = lines.getRange(0, 2).toList(); - final bodyLines = lines.getRange(2, lines.length - 3); - final catchLines = lines - .getRange(lines.length - 3, lines.length) - .toList(); - if (tryLines[0].isEmpty && - tryLines[1] == 'try {' && - catchLines[0] == '} catch (error) {' && - catchLines[1] == ' error.name + ": " + error.message;' && - catchLines[2] == '}') { - return bodyLines.join('\n'); - } - } - return jsCode; - } - - /// Create JS expression to pass to `Debugger.evaluateOnCallFrame`. - static String _createEvalExpression(String expression) { - final body = expression.split('\n').where((e) => e.isNotEmpty); - - return JsBuilder.createEvalExpression(body); - } - - /// Create JS function to invoke in `Runtime.callFunctionOn`. - static String _createEvalFunction(String function, Iterable params) { - final body = function.split('\n').where((e) => e.isNotEmpty); - - return params.contains('this') - ? JsBuilder.createEvalBoundFunction(body, params) - : JsBuilder.createEvalStaticFunction(body, params); - } -} diff --git a/dwds/lib/src/services/javascript_builder.dart b/dwds/lib/src/services/javascript_builder.dart deleted file mode 100644 index cd02aee91f..0000000000 --- a/dwds/lib/src/services/javascript_builder.dart +++ /dev/null @@ -1,256 +0,0 @@ -// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -/// Efficient JavaScript code builder. -/// -/// Used to create wrapper expressions and functions for expression evaluation. -class JsBuilder { - var _indent = 0; - final _buffer = StringBuffer(); - - String? _built; - String build() => _built ??= _buffer.toString(); - - JsBuilder(); - - void write(String item) { - _buffer.write(item); - } - - void writeLine(String item) { - _buffer.writeln(item); - } - - void writeAll(Iterable items, [String separator = '']) { - _buffer.writeAll(items, separator); - } - - void _writeIndent() { - writeAll([for (var i = 0; i < _indent * 2; i++) ' '], ''); - } - - void writeWithIndent(String item) { - _writeIndent(); - write(item); - } - - void writeLineWithIndent(String line) { - _writeIndent(); - writeLine(line); - } - - void writeMultiLineExpression(Iterable lines) { - var i = 0; - for (final line in lines) { - if (i == 0) { - writeLine(line); - } else if (i < lines.length - 1) { - writeLineWithIndent(line); - } else { - writeWithIndent(line); - } - i++; - } - } - - void increaseIndent() { - _indent++; - } - - void decreaseIndent() { - if (_indent != 0) _indent--; - } - - /// Call the expression built by [build] with [args]. - /// - /// $function($args); - void writeCallExpression(Iterable args, void Function() build) { - build(); - write('('); - writeAll(args, ', '); - write(')'); - } - - /// Wrap the expression built by [build] in try/catch block. - /// - /// try { - /// $expression; - /// } catch (error) { - /// error.name + ": " + error.message; - /// }; - void writeTryCatchExpression(void Function() build) { - writeLineWithIndent('try {'); - - increaseIndent(); - writeWithIndent(''); - build(); - writeLine(''); - decreaseIndent(); - - writeLineWithIndent('} catch (error) {'); - writeLineWithIndent(' error.name + ": " + error.message;'); - writeWithIndent('}'); - } - - /// Wrap the statement built by [build] in try/catch block. - /// - /// try { - /// $statement - /// } catch (error) { - /// return error.name + ": " + error.message; - /// }; - void writeTryCatchStatement(void Function() build) { - writeLineWithIndent('try {'); - - increaseIndent(); - build(); - writeLine(''); - decreaseIndent(); - - writeLineWithIndent('} catch (error) {'); - writeLineWithIndent(' return error.name + ": " + error.message;'); - writeWithIndent('}'); - } - - /// Return the expression built by [build]. - /// - /// return $expression; - void writeReturnStatement(void Function() build) { - writeWithIndent('return '); - build(); - write(';'); - } - - /// Define a function with [params] and body built by [build]. - /// - /// function($args) { - /// $body - /// }; - void writeFunctionDefinition(Iterable params, void Function() build) { - write('function ('); - writeAll(params, ', '); - writeLine(') {'); - - increaseIndent(); - build(); - writeLine(''); - decreaseIndent(); - - writeWithIndent('}'); - } - - /// Bind the function built by [build] to [to]. - /// - /// $function.bind($to) - void writeBindExpression(String to, void Function() build) { - build(); - write('.bind('); - write(to); - write(')'); - } - - /// Create a wrapper expression to evaluate the [body]. - /// - /// Can be used in `Debugger.evaluateOnCallFrame` Chrome API. - /// - /// try { - /// $expression; - /// } catch (error) { - /// error.name + ": " + error.message; - /// } - static String createEvalExpression(Iterable body) => - (JsBuilder().._writeEvalExpression(body)).build(); - - void _writeEvalExpression(Iterable body) { - writeTryCatchExpression(() { - writeMultiLineExpression(body); - write(';'); - }); - } - - /// Create a wrapper function with [params] that calls a static [function]. - /// - /// Can be used in `Runtime.callFunctionOn` Chrome API. - /// - /// function ($params) { - /// try { - /// return $function($params); - /// } catch (error) { - /// return error.name + ": " + error.message; - /// } - /// } - static String createEvalStaticFunction( - Iterable function, - Iterable params, - ) => (JsBuilder().._writeEvalStaticFunction(function, params)).build(); - - void _writeEvalStaticFunction( - Iterable function, - Iterable params, - ) { - writeFunctionDefinition( - params, - () => writeTryCatchStatement( - () => writeReturnStatement( - () => writeCallExpression(params, () { - writeMultiLineExpression(function); - }), - ), - ), - ); - } - - /// Create a wrapper function with [params] that calls a bound [function]. - /// - /// Can be used in `Runtime.callFunctionOn` Chrome API. - /// function ($params, __t$this) { - /// try { - /// return function ($params) { - /// return $function($params); - /// }.bind(__t$this)($params); - /// } catch (error) { - /// return error.name + ": " + error.message; - /// } - /// } - static String createEvalBoundFunction( - Iterable function, - Iterable params, - ) => (JsBuilder().._writeEvalBoundFunction(function, params)).build(); - - void _writeEvalBoundFunction( - Iterable function, - Iterable params, - ) { - final original = 'this'; - final substitute = '__t\$this'; - - final args = params.where((e) => e != original); - final substitutedParams = [ - ...params.where((e) => e != original), - substitute, - ]; - - writeFunctionDefinition( - substitutedParams, - () => writeTryCatchStatement( - () => writeReturnStatement( - () => writeCallExpression( - args, - () => writeBindExpression( - substitute, - () => writeFunctionDefinition( - args, - () => writeReturnStatement( - () => writeCallExpression(args, () { - writeMultiLineExpression(function); - }), - ), - ), - ), - ), - ), - ), - ); - } -} diff --git a/dwds/lib/src/services/proxy_service.dart b/dwds/lib/src/services/proxy_service.dart deleted file mode 100644 index 24b2642c81..0000000000 --- a/dwds/lib/src/services/proxy_service.dart +++ /dev/null @@ -1,674 +0,0 @@ -// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:async'; -import 'dart:convert'; - -import 'package:dwds/data/debug_event.dart'; -import 'package:dwds/data/hot_reload_response.dart'; -import 'package:dwds/data/hot_restart_response.dart'; -import 'package:dwds/data/register_event.dart'; -import 'package:dwds/data/service_extension_response.dart'; -import 'package:dwds/src/connections/app_connection.dart'; -import 'package:dwds/src/debugging/inspector.dart'; -import 'package:dwds/src/events.dart'; -import 'package:dwds/src/services/debug_service.dart'; -import 'package:dwds/src/utilities/dart_uri.dart'; -import 'package:dwds/src/utilities/shared.dart'; -import 'package:meta/meta.dart'; -import 'package:pub_semver/pub_semver.dart' as semver; -import 'package:vm_service/vm_service.dart' as vm_service; -import 'package:vm_service/vm_service.dart'; -import 'package:vm_service_interface/vm_service_interface.dart'; - -// This event is identical to the one sent by the VM service from -// sdk/lib/vmservice/vmservice.dart before existing VM service clients are -// disconnected. -final class DartDevelopmentServiceConnectedEvent extends Event { - DartDevelopmentServiceConnectedEvent({ - required super.timestamp, - required this.uri, - }) : message = - 'A Dart Developer Service instance has connected and this ' - 'direct connection to the VM service will now be closed. ' - 'Please reconnect to the Dart Development Service at $uri.', - super(kind: 'DartDevelopmentServiceConnected'); - - final String message; - final String uri; - - @override - Map toJson() => { - ...super.toJson(), - 'uri': uri, - 'message': message, - }; -} - -final class DisconnectNonDartDevelopmentServiceClients extends RPCError { - DisconnectNonDartDevelopmentServiceClients() - : super('_yieldControlToDDS', kErrorCode); - - // Arbitrary error code that's unlikely to be used elsewhere. - static const kErrorCode = -199328; -} - -/// Abstract base class for VM service proxy implementations. -abstract base class ProxyService - implements VmServiceInterface { - /// Cache of all existing StreamControllers. - /// - /// These are all created through [onEvent]. - final Map> _streamControllers = {}; - - /// Provides variable inspection functionality. - InspectorT get inspector { - if (_inspector == null) { - throw StateError('No running isolate (inspector is not set).'); - } - return _inspector!; - } - - @protected - set inspector(InspectorT? inspector) { - _inspector = inspector; - } - - InspectorT? _inspector; - - /// Determines if there an isolate running currently. - /// - /// [_inspector] is `null` iff the isolate is not running, - /// for example, before the first isolate starts or during - /// a hot restart. - bool get isIsolateRunning => _inspector != null; - - /// The [DebugService] implementation. - final DebugService debugService; - - /// The root `VM` instance. - final vm_service.VM vm; - - /// Signals when isolate is initialized. - Future get isInitialized => initializedCompleter.future; - Completer initializedCompleter = Completer(); - - static const _kPauseIsolatesOnStartFlag = 'pause_isolates_on_start'; - - /// The flags that can be set at runtime via [setFlag] and their respective - /// values. - final Map _currentVmServiceFlags = { - _kPauseIsolatesOnStartFlag: false, - }; - - /// The value of the [_kPauseIsolatesOnStartFlag]. - /// - /// This value can be updated at runtime via [setFlag]. - bool get pauseIsolatesOnStart => - _currentVmServiceFlags[_kPauseIsolatesOnStartFlag] ?? false; - - /// Stream controller for resume events after restart. - final _resumeAfterRestartEventsController = - StreamController.broadcast(); - - /// A global stream of resume events for hot restart. - /// - /// The values in the stream are the isolates IDs for the resume event. - /// - /// IMPORTANT: This should only be listened to during a hot-restart or page - /// refresh. The debugger ignores any resume events as long as there is a - /// subscriber to this stream. - Stream get resumeAfterRestartEventsStream => - _resumeAfterRestartEventsController.stream; - - /// Whether or not the connected app has a pending restart. - bool get hasPendingRestart => _resumeAfterRestartEventsController.hasListener; - - // Protected accessors for subclasses - Map> get streamControllers => - _streamControllers; - StreamController get resumeAfterRestartEventsController => - _resumeAfterRestartEventsController; - Map get currentVmServiceFlags => _currentVmServiceFlags; - - /// The root at which we're serving. - final String root; - - ProxyService({ - required this.vm, - required this.root, - required this.debugService, - }); - - /// Sends events to stream controllers. - void streamNotify(String streamId, vm_service.Event event) { - final controller = _streamControllers[streamId]; - if (controller == null) return; - controller.add(event); - } - - /// Returns a broadcast stream for the given streamId. - @override - Stream onEvent(String streamId) { - return _streamControllers.putIfAbsent(streamId, () { - return StreamController.broadcast(); - }).stream; - } - - @override - Future yieldControlToDDS(String uri) async { - // This will throw an RPCError if there's already an existing DDS instance. - debugService.yieldControlToDDS(uri); - - // Notify existing clients that DDS has connected and they're about to be - // disconnected. - final event = DartDevelopmentServiceConnectedEvent( - timestamp: DateTime.now().millisecondsSinceEpoch, - uri: uri, - ); - streamNotify(EventStreams.kService, event); - - // We throw since we have no other way to control what the response content - // is for this RPC. The debug service will check for this particular - // exception as a signal to close connections to all other clients. - throw DisconnectNonDartDevelopmentServiceClients(); - } - - @override - Future streamListen(String streamId) => - wrapInErrorHandlerAsync('streamListen', () => _streamListen(streamId)); - - Future _streamListen(String streamId) async { - // TODO: This should return an error if the stream is already being listened - // to. - onEvent(streamId); - return vm_service.Success(); - } - - @override - Future streamCancel(String streamId) { - // TODO: We should implement this (as we've already implemented - // streamListen). - return _rpcNotSupportedFuture('streamCancel'); - } - - @override - Future getVM() => wrapInErrorHandlerAsync('getVM', _getVM); - - Future _getVM() { - return captureElapsedTime(() async { - return vm; - }, (result) => DwdsEvent.getVM()); - } - - @override - Future getIsolate(String isolateId) => - wrapInErrorHandlerAsync('getIsolate', () => _getIsolate(isolateId)); - - Future _getIsolate(String isolateId) { - return captureElapsedTime(() async { - await isInitialized; - checkIsolate('getIsolate', isolateId); - return inspector.isolate; - }, (result) => DwdsEvent.getIsolate()); - } - - @override - Future setName(String isolateId, String name) => - wrapInErrorHandlerAsync('setName', () => _setName(isolateId, name)); - - Future _setName(String isolateId, String name) async { - await isInitialized; - checkIsolate('setName', isolateId); - inspector.isolate.name = name; - return Success(); - } - - @override - Future setVMName(String name) => - wrapInErrorHandlerAsync('setVMName', () => _setVMName(name)); - - Future _setVMName(String name) async { - vm.name = name; - streamNotify( - 'VM', - Event( - kind: EventKind.kVMUpdate, - timestamp: DateTime.now().millisecondsSinceEpoch, - // We are not guaranteed to have an isolate at this point in time. - isolate: null, - vm: toVMRef(vm), - ), - ); - return Success(); - } - - @override - Future getFlagList() => - wrapInErrorHandlerAsync('getFlagList', _getFlagList); - - Future _getFlagList() async { - final flags = _currentVmServiceFlags.entries.map( - (entry) => - vm_service.Flag(name: entry.key, valueAsString: '${entry.value}'), - ); - return vm_service.FlagList(flags: flags.toList()); - } - - @override - Future setFlag(String name, String value) => - wrapInErrorHandlerAsync('setFlag', () => _setFlag(name, value)); - - Future _setFlag(String name, String value) async { - if (!_currentVmServiceFlags.containsKey(name)) { - throw vm_service.RPCError( - 'setFlag', - vm_service.RPCErrorKind.kInvalidRequest.code, - 'Cannot set flag "$name" (invalid flag)', - ); - } - - if (value != 'true' && value != 'false') { - throw vm_service.RPCError( - 'setFlag', - vm_service.RPCErrorKind.kInvalidParams.code, - 'Cannot set flag "$name" to "$value" (boolean value expected)', - ); - } - _currentVmServiceFlags[name] = value == 'true'; - return vm_service.Success(); - } - - @override - Future getSupportedProtocols() => - wrapInErrorHandlerAsync('getSupportedProtocols', _getSupportedProtocols); - - Future _getSupportedProtocols() async { - final version = semver.Version.parse(vm_service.vmServiceVersion); - return vm_service.ProtocolList( - protocols: [ - vm_service.Protocol( - protocolName: 'VM Service', - major: version.major, - minor: version.minor, - ), - ], - ); - } - - @override - Future getVersion() => - wrapInErrorHandlerAsync('getVersion', _getVersion); - - Future _getVersion() async { - final version = semver.Version.parse(vm_service.vmServiceVersion); - return vm_service.Version(major: version.major, minor: version.minor); - } - - // Note: Ignore the optional local parameter, when it is set to `true` the - // request is intercepted and handled by DDS. - @override - Future lookupResolvedPackageUris( - String isolateId, - List uris, { - bool? local, - }) => wrapInErrorHandlerAsync( - 'lookupResolvedPackageUris', - () => _lookupResolvedPackageUris(isolateId, uris), - ); - - Future _lookupResolvedPackageUris( - String isolateId, - List uris, - ) async { - await isInitialized; - checkIsolate('lookupResolvedPackageUris', isolateId); - return UriList(uris: uris.map(DartUri.toResolvedUri).toList()); - } - - @override - Future lookupPackageUris(String isolateId, List uris) => - wrapInErrorHandlerAsync( - 'lookupPackageUris', - () => _lookupPackageUris(isolateId, uris), - ); - - Future _lookupPackageUris( - String isolateId, - List uris, - ) async { - await isInitialized; - checkIsolate('lookupPackageUris', isolateId); - return UriList(uris: uris.map(DartUri.toPackageUri).toList()); - } - - @override - Future getScripts(String isolateId) => - wrapInErrorHandlerAsync('getScripts', () => _getScripts(isolateId)); - - Future _getScripts(String isolateId) { - return captureElapsedTime(() async { - await isInitialized; - checkIsolate('getScripts', isolateId); - return inspector.getScripts(); - }, (result) => DwdsEvent.getScripts()); - } - - /// Parses the [BatchedDebugEvents] and emits corresponding Dart VM Service - /// protocol [Event]s. - void parseBatchedDebugEvents(BatchedDebugEvents debugEvents) { - for (final debugEvent in debugEvents.events) { - parseDebugEvent(debugEvent); - } - } - - /// Parses the [DebugEvent] and emits a corresponding Dart VM Service - /// protocol [Event]. - @mustCallSuper - void parseDebugEvent(DebugEvent debugEvent) { - if (!isIsolateRunning) return; - final isolateRef = inspector.isolateRef; - - streamNotify( - EventStreams.kExtension, - Event( - kind: EventKind.kExtension, - timestamp: DateTime.now().millisecondsSinceEpoch, - isolate: isolateRef, - ) - ..extensionKind = debugEvent.kind - ..extensionData = ExtensionData.parse( - jsonDecode(debugEvent.eventData) as Map, - ), - ); - } - - /// Parses the [RegisterEvent] and emits a corresponding Dart VM Service - /// protocol [Event]. - @mustCallSuper - void parseRegisterEvent(RegisterEvent registerEvent) { - if (!isIsolateRunning) return; - - final isolate = inspector.isolate; - final isolateRef = inspector.isolateRef; - final service = registerEvent.eventData; - isolate.extensionRPCs?.add(service); - - streamNotify( - EventStreams.kIsolate, - Event( - kind: EventKind.kServiceExtensionAdded, - timestamp: DateTime.now().millisecondsSinceEpoch, - isolate: isolateRef, - )..extensionRPC = service, - ); - } - - /// Completes hot reload with response from client. - /// - /// Default implementation throws [UnimplementedError]. - /// Override in subclasses that support hot reload completion. - void completeHotReload(HotReloadResponse response) { - throw UnimplementedError('completeHotReload not supported'); - } - - /// Completes hot restart with response from client. - /// - /// Default implementation throws [UnimplementedError]. - /// Override in subclasses that support hot restart completion. - void completeHotRestart(HotRestartResponse response) { - throw UnimplementedError('completeHotRestart not supported'); - } - - /// Completes service extension with response from client. - /// - /// Default implementation throws [UnimplementedError]. - /// Override in subclasses that support service extension completion. - void completeServiceExtension(ServiceExtensionResponse response) { - throw UnimplementedError('completeServiceExtension not supported'); - } - - /// Sends `ServiceExtensionAdded` events for each currently registered - /// service extension. - Future sendServiceExtensionRegisteredEvents() async { - final timestamp = DateTime.now().millisecondsSinceEpoch; - for (final extensionRpc in await inspector.getExtensionRpcs()) { - streamNotify( - 'Isolate', - vm_service.Event( - kind: vm_service.EventKind.kServiceExtensionAdded, - timestamp: timestamp, - isolate: inspector.isolateRef, - )..extensionRPC = extensionRpc, - ); - } - } - - /// Standard RPC error for unsupported methods. - static vm_service.RPCError _rpcNotSupported(String method) { - return vm_service.RPCError( - method, - vm_service.RPCErrorKind.kMethodNotFound.code, - '$method: Not supported on web devices', - ); - } - - /// Standard future error for unsupported methods. - static Future _rpcNotSupportedFuture(String method) { - return Future.error(_rpcNotSupported(method)); - } - - /// Protected accessor for _rpcNotSupportedFuture for subclasses - Future rpcNotSupportedFuture(String method) { - return _rpcNotSupportedFuture(method); - } - - // Default implementations for unsupported methods - @override - Future getAllocationProfile( - String isolateId, { - bool? gc, - bool? reset, - }) { - return _rpcNotSupportedFuture('getAllocationProfile'); - } - - @override - Future getClassList(String isolateId) { - return _rpcNotSupportedFuture('getClassList'); - } - - @override - Future getInstances( - String isolateId, - String classId, - int limit, { - bool? includeImplementers, - bool? includeSubclasses, - String? idZoneId, - }) { - return _rpcNotSupportedFuture('getInstances'); - } - - @override - Future kill(String isolateId) { - return _rpcNotSupportedFuture('kill'); - } - - @override - Future clearVMTimeline() { - return _rpcNotSupportedFuture('clearVMTimeline'); - } - - @override - Future getVMTimeline({ - int? timeOriginMicros, - int? timeExtentMicros, - }) { - return _rpcNotSupportedFuture('getVMTimeline'); - } - - @override - Future getVMTimelineFlags() { - return _rpcNotSupportedFuture('getVMTimelineFlags'); - } - - @override - Future setVMTimelineFlags(List recordedStreams) { - return _rpcNotSupportedFuture('setVMTimelineFlags'); - } - - @override - Future getVMTimelineMicros() { - return _rpcNotSupportedFuture('getVMTimelineMicros'); - } - - @override - Future getInboundReferences( - String isolateId, - String targetId, - int limit, { - String? idZoneId, - }) { - return _rpcNotSupportedFuture('getInboundReferences'); - } - - @override - Future getRetainingPath( - String isolateId, - String targetId, - int limit, { - String? idZoneId, - }) { - return _rpcNotSupportedFuture('getRetainingPath'); - } - - @override - Future requestHeapSnapshot(String isolateId) { - return _rpcNotSupportedFuture('requestHeapSnapshot'); - } - - @override - Future getIsolateGroup(String isolateGroupId) { - return _rpcNotSupportedFuture('getIsolateGroup'); - } - - @override - Future getIsolateGroupMemoryUsage( - String isolateGroupId, - ) { - return _rpcNotSupportedFuture('getIsolateGroupMemoryUsage'); - } - - @override - Future getProcessMemoryUsage() => - _rpcNotSupportedFuture('getProcessMemoryUsage'); - - @override - Future setLibraryDebuggable( - String isolateId, - String libraryId, - bool isDebuggable, - ) { - return rpcNotSupportedFuture('setLibraryDebuggable'); - } - - @override - Future getPorts(String isolateId) => - throw UnimplementedError(); - - @override - Future getAllocationTraces( - String isolateId, { - int? timeOriginMicros, - int? timeExtentMicros, - String? classId, - }) => throw UnimplementedError(); - - @override - Future setTraceClassAllocation( - String isolateId, - String classId, - bool enable, - ) => throw UnimplementedError(); - - @override - Future setBreakpointState( - String isolateId, - String breakpointId, - bool enable, - ) => throw UnimplementedError(); - - @override - Future streamCpuSamplesWithUserTag( - List userTags, - ) => _rpcNotSupportedFuture('streamCpuSamplesWithUserTag'); - - @override - Future getCpuSamples( - String isolateId, - int timeOriginMicros, - int timeExtentMicros, - ) { - return _rpcNotSupportedFuture('getCpuSamples'); - } - - @override - Future clearCpuSamples(String isolateId) { - return _rpcNotSupportedFuture('clearCpuSamples'); - } - - @override - Future registerService(String service, String alias) { - return rpcNotSupportedFuture('registerService'); - } - - /// Creates a new isolate for debugging. - /// - /// Implementations should handle isolate lifecycle management according to - /// their specific debugging mode (Chrome vs WebSocket). - Future createIsolate( - AppConnection appConnection, { - bool newConnection = false, - }); - - /// Destroys the isolate and cleans up debugging state. - /// - /// Implementations should handle cleanup according to their specific - /// debugging mode and connection management strategy. - void destroyIsolate(); - - /// Validate that isolateId matches the current isolate we're connected to and - /// return that isolate. - /// - /// This is useful to call at the beginning of API methods that are passed an - /// isolate id. - @protected - Isolate checkIsolate(String methodName, String? isolateId) { - final currentIsolateId = inspector.isolate.id; - if (currentIsolateId == null) { - throw StateError('No running isolate ID'); - } - if (isolateId != currentIsolateId) { - _throwSentinel( - methodName, - SentinelKind.kCollected, - 'Unrecognized isolateId: $isolateId', - ); - } - return inspector.isolate; - } - - static Never _throwSentinel(String method, String kind, String message) { - final data = {'kind': kind, 'valueAsString': message}; - throw SentinelException.parse(method, data); - } - - /// Prevent DWDS from blocking Dart SDK rolls if changes in package:vm_service - /// are unimplemented in DWDS. - @override - dynamic noSuchMethod(Invocation invocation) { - return super.noSuchMethod(invocation); - } -} diff --git a/dwds/lib/src/services/web_socket/web_socket_debug_service.dart b/dwds/lib/src/services/web_socket/web_socket_debug_service.dart deleted file mode 100644 index 36ab4da3d2..0000000000 --- a/dwds/lib/src/services/web_socket/web_socket_debug_service.dart +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'package:dwds/asset_reader.dart'; -import 'package:dwds/src/config/tool_configuration.dart'; -import 'package:dwds/src/connections/app_connection.dart'; -import 'package:dwds/src/services/debug_service.dart'; -import 'package:dwds/src/services/web_socket/web_socket_proxy_service.dart'; -import 'package:meta/meta.dart'; - -/// Defines callbacks for sending messages to the connected client. -/// Returns the number of clients the request was successfully sent to. -typedef SendClientRequest = int Function(Object request); - -/// WebSocket-based debug service for web debugging. -final class WebSocketDebugService extends DebugService { - WebSocketDebugService._({ - required super.serverHostname, - required super.ddsConfig, - required super.urlEncoder, - }) : super( - // The web socket debug service doesn't support SSE connections. - useSse: false, - ); - - @protected - @override - Future initialize({required WebSocketProxyService proxyService}) async { - await super.initialize(proxyService: proxyService); - await serve( - handler: initializeWebSocketHandler(proxyService: proxyService), - ); - } - - static Future start({ - required String hostname, - required AppConnection appConnection, - required AssetReader assetReader, - required SendClientRequest sendClientRequest, - required DartDevelopmentServiceConfiguration ddsConfig, - UrlEncoder? urlEncoder, - }) async { - final debugService = WebSocketDebugService._( - serverHostname: hostname, - ddsConfig: ddsConfig, - urlEncoder: urlEncoder, - ); - final webSocketProxyService = await WebSocketProxyService.create( - sendClientRequest, - appConnection, - assetReader.basePath, - debugService, - ); - await debugService.initialize(proxyService: webSocketProxyService); - return debugService; - } -} diff --git a/dwds/lib/src/services/web_socket/web_socket_proxy_service.dart b/dwds/lib/src/services/web_socket/web_socket_proxy_service.dart deleted file mode 100644 index 29a00d10fa..0000000000 --- a/dwds/lib/src/services/web_socket/web_socket_proxy_service.dart +++ /dev/null @@ -1,907 +0,0 @@ -// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:async'; -import 'dart:convert'; - -import 'package:dwds/data/hot_reload_request.dart'; -import 'package:dwds/data/hot_reload_response.dart'; -import 'package:dwds/data/hot_restart_request.dart'; -import 'package:dwds/data/hot_restart_response.dart'; -import 'package:dwds/data/ping_request.dart'; -import 'package:dwds/data/service_extension_request.dart'; -import 'package:dwds/data/service_extension_response.dart'; -import 'package:dwds/src/connections/app_connection.dart'; -import 'package:dwds/src/debugging/web_socket_inspector.dart'; -import 'package:dwds/src/services/proxy_service.dart'; -import 'package:dwds/src/services/web_socket/web_socket_debug_service.dart'; -import 'package:dwds/src/utilities/shared.dart'; -import 'package:logging/logging.dart'; -import 'package:vm_service/vm_service.dart' as vm_service; -import 'package:vm_service/vm_service.dart'; - -/// Defines callbacks for sending messages to the connected client. -/// Returns the number of clients the request was successfully sent to. -typedef SendClientRequest = int Function(Object request); - -const _pauseIsolatesOnStartFlag = 'pause_isolates_on_start'; - -/// Grace period before destroying isolate when no clients are detected. -/// This handles the race condition during page refresh where the old connection -/// closes before the new connection is established, preventing premature -/// isolate destruction. -const _isolateDestructionGracePeriod = Duration(seconds: 15); - -/// Error message when no clients are available for hot reload/restart. -const kNoClientsAvailable = 'No clients available.'; - -/// Tracks hot reload responses from multiple browser windows/tabs. -class _HotReloadTracker { - final String requestId; - final Completer completer; - final int expectedResponses; - final List responses = []; - final Timer timeoutTimer; - - _HotReloadTracker({ - required this.requestId, - required this.completer, - required this.expectedResponses, - required this.timeoutTimer, - }); - - bool get gotAllResponses => responses.length >= expectedResponses; - - void addResponse(HotReloadResponse response) { - responses.add(response); - } - - bool get allSuccessful => responses.every((r) => r.success); - - void dispose() { - timeoutTimer.cancel(); - } -} - -/// Tracks hot restart responses from multiple browser windows/tabs. -class _HotRestartTracker { - final String requestId; - final Completer completer; - final int expectedResponses; - final List responses = []; - final Timer timeoutTimer; - - _HotRestartTracker({ - required this.requestId, - required this.completer, - required this.expectedResponses, - required this.timeoutTimer, - }); - - bool get gotAllResponses => responses.length >= expectedResponses; - - void addResponse(HotRestartResponse response) { - responses.add(response); - } - - bool get allSuccessful => responses.every((r) => r.success); - - void dispose() { - timeoutTimer.cancel(); - } -} - -/// Tracks service extension responses from multiple browser windows/tabs. -class _ServiceExtensionTracker { - final String requestId; - final Completer completer; - final int expectedResponses; - final List responses = []; - final Timer timeoutTimer; - - _ServiceExtensionTracker({ - required this.requestId, - required this.completer, - required this.expectedResponses, - required this.timeoutTimer, - }); - - bool get gotAllResponses => responses.length >= expectedResponses; - - void addResponse(ServiceExtensionResponse response) { - responses.add(response); - } - - bool get allSuccessful => responses.every((r) => r.success); - - void dispose() { - timeoutTimer.cancel(); - } -} - -/// Exception thrown when no browser clients are connected to DWDS. -class NoClientsAvailableException implements Exception { - final String message; - - NoClientsAvailableException._(this.message); - - @override - String toString() => 'NoClientsAvailableException: $message'; -} - -/// WebSocket-based VM service proxy for web debugging. -final class WebSocketProxyService extends ProxyService { - final _logger = Logger('WebSocketProxyService'); - - /// Active service extension trackers by request ID. - final _pendingServiceExtensionTrackers = {}; - - /// Sends messages to the client. - final SendClientRequest sendClientRequest; - - /// App connection for this service. - AppConnection appConnection; - - /// Active hot reload trackers by request ID. - final _pendingHotReloads = {}; - - /// Active hot restart trackers by request ID. - final _pendingHotRestarts = {}; - - /// App connection cleanup subscriptions by connection instance ID. - final _appConnectionDoneSubscriptions = >{}; - - /// Active connection count for this service. - int _activeConnectionCount = 0; - - WebSocketProxyService._({ - required this.sendClientRequest, - required super.vm, - required super.root, - required super.debugService, - required this.appConnection, - }); - - static Future create( - SendClientRequest sendClientRequest, - AppConnection appConnection, - String root, - WebSocketDebugService debugService, - ) async { - final vm = vm_service.VM( - name: 'WebSocketDebugProxy', - operatingSystem: 'web', - startTime: DateTime.now().millisecondsSinceEpoch, - version: 'unknown', - isolates: [], - isolateGroups: [], - systemIsolates: [], - systemIsolateGroups: [], - targetCPU: 'Web', - hostCPU: 'DWDS', - architectureBits: -1, - pid: -1, - ); - final service = WebSocketProxyService._( - sendClientRequest: sendClientRequest, - vm: vm, - root: root, - debugService: debugService, - appConnection: appConnection, - ); - safeUnawaited(service.createIsolate(appConnection)); - return service; - } - - /// Creates a new isolate for WebSocket debugging. - @override - Future createIsolate( - AppConnection appConnection, { - bool newConnection = false, - }) async { - // Update app connection - this.appConnection = appConnection; - - // Track this connection - final connectionId = appConnection.request.instanceId; - - // Check if this connection is already being tracked - final isNewConnection = - newConnection || - !_appConnectionDoneSubscriptions.containsKey(connectionId); - - if (isNewConnection) { - _activeConnectionCount++; - _logger.fine( - 'Adding new connection: $connectionId (total: $_activeConnectionCount)', - ); - } else { - _logger.fine( - 'Reconnecting existing connection: $connectionId (total: ' - '$_activeConnectionCount)', - ); - } - - // Auto-cleanup on connection close - final existingSubscription = _appConnectionDoneSubscriptions[connectionId]; - await existingSubscription?.cancel(); - _appConnectionDoneSubscriptions[connectionId] = appConnection.onDone - .asStream() - .listen((_) { - _handleConnectionClosed(connectionId); - }); - - // If we already have a running isolate, just update the connection and - // return - if (isIsolateRunning) { - _logger.fine( - 'Reusing existing isolate ${inspector.isolateRef.id} for connection: ' - '$connectionId', - ); - return; - } - - inspector = await WebSocketAppInspector.create(this, appConnection, root); - - final isolateRef = inspector.isolateRef; - vm.isolates?.add(isolateRef); - final timestamp = DateTime.now().millisecondsSinceEpoch; - - _logger.fine( - 'Created new isolate: ${isolateRef.id} for connection: $connectionId', - ); - - // Send lifecycle events - streamNotify( - vm_service.EventStreams.kIsolate, - vm_service.Event( - kind: vm_service.EventKind.kIsolateStart, - timestamp: timestamp, - isolate: isolateRef, - ), - ); - streamNotify( - vm_service.EventStreams.kIsolate, - vm_service.Event( - kind: vm_service.EventKind.kIsolateRunnable, - timestamp: timestamp, - isolate: isolateRef, - ), - ); - - // Send pause event if enabled - if (pauseIsolatesOnStart) { - final pauseEvent = vm_service.Event( - kind: vm_service.EventKind.kPauseStart, - timestamp: timestamp, - isolate: isolateRef, - ); - inspector.isolate.pauseEvent = pauseEvent; - streamNotify(vm_service.EventStreams.kDebug, pauseEvent); - } - - // Complete initialization after isolate is set up - if (!initializedCompleter.isCompleted) initializedCompleter.complete(); - } - - /// Handles a connection being closed. - void _handleConnectionClosed(String connectionId) { - _logger.fine('Connection closed: $connectionId'); - - // Only decrement if this connection was actually being tracked - if (_appConnectionDoneSubscriptions.containsKey(connectionId)) { - // Remove the subscription for this connection - _appConnectionDoneSubscriptions[connectionId]?.cancel(); - _appConnectionDoneSubscriptions.remove(connectionId); - - // Decrease active connection count - _activeConnectionCount--; - _logger.fine( - 'Removed connection: $connectionId (remaining: ' - '$_activeConnectionCount)', - ); - _logger.fine( - 'Current tracked connections: ' - '${_appConnectionDoneSubscriptions.keys.toList()}', - ); - - // Instead of destroying the isolate immediately, check if there are still - // clients that can receive hot reload requests - if (_activeConnectionCount <= 0) { - // Double-check by asking the sendClientRequest callback how many - // clients are available - final actualClientCount = sendClientRequest(PingRequest()); - _logger.fine( - 'Actual client count from sendClientRequest: $actualClientCount', - ); - - if (actualClientCount == 0) { - _logger.fine( - 'No clients available for hot reload, scheduling isolate ' - 'destruction', - ); - // Add a delay before destroying the isolate to handle page refresh - // race condition - Timer(_isolateDestructionGracePeriod, () { - // Double-check client count again before destroying - final finalClientCount = sendClientRequest(PingRequest()); - if (finalClientCount == 0) { - _logger.fine( - 'Final check confirmed no clients, destroying isolate', - ); - destroyIsolate(); - } else { - _logger.fine( - 'Final check found $finalClientCount clients, keeping isolate ' - 'alive', - ); - _activeConnectionCount = finalClientCount; - } - }); - } else { - _logger.fine( - 'Still have $actualClientCount clients available, keeping isolate ' - 'alive', - ); - // Update our internal counter to match reality - _activeConnectionCount = actualClientCount; - } - } else { - _logger.fine( - 'Still have $_activeConnectionCount active connections, keeping ' - 'isolate alive', - ); - } - } else { - _logger.warning( - 'Attempted to close connection that was not tracked: $connectionId', - ); - } - } - - /// Destroys the isolate and cleans up state. - @override - void destroyIsolate() { - _logger.fine('Destroying isolate'); - - if (!isIsolateRunning) { - _logger.fine('Isolate already destroyed, ignoring'); - return; - } - - // Cancel all connection subscriptions - for (final subscription in _appConnectionDoneSubscriptions.values) { - subscription.cancel(); - } - _appConnectionDoneSubscriptions.clear(); - _activeConnectionCount = 0; - - final isolateRef = inspector.isolateRef; - // Send exit event - streamNotify( - vm_service.EventStreams.kIsolate, - vm_service.Event( - kind: vm_service.EventKind.kIsolateExit, - timestamp: DateTime.now().millisecondsSinceEpoch, - isolate: isolateRef, - ), - ); - - vm.isolates?.removeWhere((ref) => ref.id == isolateRef.id); - - // Reset state - inspector = null; - - if (initializedCompleter.isCompleted) { - initializedCompleter = Completer(); - } - } - - @override - Future setIsolatePauseMode( - String isolateId, { - String? exceptionPauseMode, - bool? shouldPauseOnExit, - }) async { - // Not supported in WebSocket mode - return success for compatibility - return Success(); - } - - @override - Future reloadSources( - String isolateId, { - bool? force, - bool? pause, - String? rootLibUri, - String? packagesUri, - }) async { - _logger.info('Attempting a hot reload'); - try { - await _performWebSocketHotReload(); - _logger.info('Hot reload completed successfully'); - return _ReloadReportWithMetadata(success: true); - } on NoClientsAvailableException catch (e) { - // Throw RPC error with kIsolateCannotReload code when no browser clients - // are connected. - throw vm_service.RPCError( - 'reloadSources', - vm_service.RPCErrorKind.kIsolateCannotReload.code, - 'Hot reload failed: ${e.message}', - ); - } catch (e) { - _logger.warning('Hot reload failed: $e'); - return _ReloadReportWithMetadata(success: false, notices: [e.toString()]); - } - } - - /// Handles hot restart requests. - Future> hotRestart() async { - _logger.info('Attempting a hot restart'); - - try { - await _performWebSocketHotRestart(); - _logger.info('Hot restart completed successfully'); - return {'result': vm_service.Success().toJson()}; - } on NoClientsAvailableException catch (e) { - // Throw RPC error with kIsolateCannotReload code when no browser clients - // are connected. - throw vm_service.RPCError( - 'hotRestart', - vm_service.RPCErrorKind.kIsolateCannotReload.code, - 'Hot restart failed: ${e.message}', - ); - } catch (e) { - _logger.warning('Hot restart failed: $e'); - return { - 'error': { - 'code': vm_service.RPCErrorKind.kInternalError.code, - 'message': 'Hot restart failed: $e', - }, - }; - } - } - - /// Completes hot reload with response from client. - @override - void completeHotReload(HotReloadResponse response) { - final tracker = _pendingHotReloads[response.id]; - - if (tracker == null) { - _logger.warning( - 'Received hot reload response but no pending tracker found (id: ' - '${response.id})', - ); - return; - } - - tracker.addResponse(response); - - if (tracker.gotAllResponses) { - _pendingHotReloads.remove(response.id); - tracker.dispose(); - - if (tracker.allSuccessful) { - tracker.completer.complete(response); - } else { - final failedResponses = tracker.responses.where((r) => !r.success); - final errorMessages = failedResponses - .map((r) => r.errorMessage ?? 'Unknown error') - .join('; '); - tracker.completer.completeError( - 'Hot reload failed in some clients: $errorMessages', - ); - } - } - } - - /// Completes hot restart with response from client. - @override - void completeHotRestart(HotRestartResponse response) { - final tracker = _pendingHotRestarts[response.id]; - - if (tracker == null) { - _logger.warning( - 'Received hot restart response but no pending tracker found (id: ' - '${response.id})', - ); - return; - } - - tracker.addResponse(response); - - if (tracker.gotAllResponses) { - _pendingHotRestarts.remove(response.id); - tracker.dispose(); - - if (tracker.allSuccessful) { - tracker.completer.complete(response); - } else { - final failedResponses = tracker.responses.where((r) => !r.success); - final errorMessages = failedResponses - .map((r) => r.errorMessage ?? 'Unknown error') - .join('; '); - tracker.completer.completeError( - 'Hot restart failed in some clients: $errorMessages', - ); - } - } - } - - /// Performs WebSocket-based hot reload. - Future _performWebSocketHotReload({String? requestId}) async { - final id = requestId ?? createId(); - - // Check if there's already a pending hot reload with this ID - if (_pendingHotReloads.containsKey(id)) { - throw StateError('Hot reload already pending for ID: $id'); - } - - const timeout = Duration(seconds: 10); - _logger.info('Sending HotReloadRequest with ID ($id) to client'); - - // Send the request and get the number of connected clients - final clientCount = await Future.microtask(() { - return sendClientRequest(HotReloadRequest(id: id)); - }); - - if (clientCount == 0) { - _logger.warning(kNoClientsAvailable); - throw NoClientsAvailableException._(kNoClientsAvailable); - } - - // Create tracker for this hot reload request - final completer = Completer(); - final timeoutTimer = Timer(timeout, () { - final tracker = _pendingHotReloads.remove(id); - if (tracker != null) { - tracker.dispose(); - if (!completer.isCompleted) { - completer.completeError( - TimeoutException( - 'Hot reload timed out - received ${tracker.responses.length}/$clientCount responses', - timeout, - ), - ); - } - } - }); - - final tracker = _HotReloadTracker( - requestId: id, - completer: completer, - expectedResponses: clientCount, - timeoutTimer: timeoutTimer, - ); - - _pendingHotReloads[id] = tracker; - - try { - final response = await completer.future; - if (!response.success) { - throw Exception(response.errorMessage ?? 'Client reported failure'); - } - } catch (e) { - // Clean up tracker if still present - final remainingTracker = _pendingHotReloads.remove(id); - remainingTracker?.dispose(); - rethrow; - } - } - - /// Performs WebSocket-based hot restart. - Future _performWebSocketHotRestart({String? requestId}) async { - final id = requestId ?? createId(); - - // Check if there's already a pending hot restart with this ID - if (_pendingHotRestarts.containsKey(id)) { - throw StateError('Hot restart already pending for ID: $id'); - } - - const timeout = Duration(seconds: 15); - _logger.info('Sending HotRestartRequest with ID ($id) to client'); - - // Send the request and get the number of connected clients - final clientCount = await Future.microtask(() { - return sendClientRequest(HotRestartRequest(id: id)); - }); - - if (clientCount == 0) { - _logger.warning(kNoClientsAvailable); - throw NoClientsAvailableException._(kNoClientsAvailable); - } - - // Create tracker for this hot restart request - final completer = Completer(); - final timeoutTimer = Timer(timeout, () { - final tracker = _pendingHotRestarts.remove(id); - if (tracker != null) { - tracker.dispose(); - if (!completer.isCompleted) { - completer.completeError( - TimeoutException( - 'Hot restart timed out - received ${tracker.responses.length}/$clientCount responses', - timeout, - ), - ); - } - } - }); - - final tracker = _HotRestartTracker( - requestId: id, - completer: completer, - expectedResponses: clientCount, - timeoutTimer: timeoutTimer, - ); - - _pendingHotRestarts[id] = tracker; - - try { - final response = await completer.future; - if (!response.success) { - throw Exception(response.errorMessage ?? 'Client reported failure'); - } - } catch (e) { - // Clean up tracker if still present - final remainingTracker = _pendingHotRestarts.remove(id); - remainingTracker?.dispose(); - rethrow; - } - } - - @override - Future callServiceExtension( - String method, { - String? isolateId, - Map? args, - }) => wrapInErrorHandlerAsync( - 'callServiceExtension', - () => _callServiceExtension(method, args: args), - ); - - /// Calls a service extension on the client. - Future _callServiceExtension(String method, {Map? args}) async { - final requestId = createId(); - - // Check if there's already a pending service extension with this ID - if (_pendingServiceExtensionTrackers.containsKey(requestId)) { - throw StateError( - 'Service extension call already pending for ID: $requestId', - ); - } - - args ??= {}; - final request = ServiceExtensionRequest.fromArgs( - id: requestId, - method: method, - // Arguments must be converted to their string representation, otherwise - // we'll encounter a TypeError when trying to cast args to a - // Map in the service extension handler. - args: args.map( - (k, v) => MapEntry( - k is String ? k : jsonEncode(k), - v is String ? v : jsonEncode(v), - ), - ), - ); - - // Send the request and get the number of connected clients - final clientCount = sendClientRequest(request); - - if (clientCount == 0) { - throw StateError('No clients available for service extension'); - } - - // Create tracker for this service extension request - const timeout = Duration(seconds: 10); - final completer = Completer(); - final timeoutTimer = Timer(timeout, () { - final tracker = _pendingServiceExtensionTrackers.remove(requestId); - if (tracker != null) { - tracker.dispose(); - if (!completer.isCompleted) { - completer.completeError( - TimeoutException( - 'Service extension $method timed out - received ${tracker.responses.length}/$clientCount responses', - timeout, - ), - ); - } - } - }); - - final tracker = _ServiceExtensionTracker( - requestId: requestId, - completer: completer, - expectedResponses: clientCount, - timeoutTimer: timeoutTimer, - ); - - _pendingServiceExtensionTrackers[requestId] = tracker; - - try { - final response = await completer.future; - - if (response.errorMessage != null) { - throw RPCError( - method, - response.errorCode ?? RPCErrorKind.kServerError.code, - response.errorMessage!, - ); - } - return Response()..json = response.result; - } catch (e) { - // Clean up tracker if still present - final remainingTracker = _pendingServiceExtensionTrackers.remove( - requestId, - ); - remainingTracker?.dispose(); - rethrow; - } - } - - /// Completes service extension with response. - @override - void completeServiceExtension(ServiceExtensionResponse response) { - final id = response.id; - - final tracker = _pendingServiceExtensionTrackers[id]; - - if (tracker == null) { - _logger.warning( - 'No pending tracker found for service extension (id: $id)', - ); - return; - } - - tracker.addResponse(response); - - if (tracker.gotAllResponses) { - _pendingServiceExtensionTrackers.remove(id); - tracker.dispose(); - - if (tracker.allSuccessful) { - tracker.completer.complete(response); - } else { - final failedResponses = tracker.responses.where((r) => !r.success); - final errorMessages = failedResponses - .map((r) => r.errorMessage ?? 'Unknown error') - .join('; '); - tracker.completer.completeError( - 'Service extension failed in some clients: $errorMessages', - ); - } - } - } - - @override - Future setFlag(String name, String value) => - wrapInErrorHandlerAsync('setFlag', () => _setFlag(name, value)); - - Future _setFlag(String name, String value) async { - if (!currentVmServiceFlags.containsKey(name)) { - return rpcNotSupportedFuture('setFlag'); - } - - assert(value == 'true' || value == 'false'); - final oldValue = currentVmServiceFlags[name]; - currentVmServiceFlags[name] = value == 'true'; - - // Handle pause_isolates_on_start flag changes - if (name == _pauseIsolatesOnStartFlag && - value == 'true' && - oldValue == false) { - // Send pause event for existing isolate if not already paused - if (isIsolateRunning && inspector.isolate.pauseEvent == null) { - final pauseEvent = vm_service.Event( - kind: vm_service.EventKind.kPauseStart, - timestamp: DateTime.now().millisecondsSinceEpoch, - isolate: inspector.isolateRef, - ); - inspector.isolate.pauseEvent = pauseEvent; - streamNotify(vm_service.EventStreams.kDebug, pauseEvent); - } - } - - return Success(); - } - - /// Pauses execution of the isolate. - @override - Future pause(String isolateId) => - // Can't pause with the web socket implementation, so do nothing. - Future.value(Success()); - - /// Resumes execution of the isolate. - @override - Future resume(String isolateId, {String? step, int? frameIndex}) => - wrapInErrorHandlerAsync('resume', () => _resume(isolateId)); - - Future _resume(String isolateId) async { - if (hasPendingRestart && !resumeAfterRestartEventsController.isClosed) { - resumeAfterRestartEventsController.add(isolateId); - } else if (!appConnection.hasStarted) { - appConnection.runMain(); - } - - // Clear pause state and send resume event to notify debugging tools - if (inspector.isolate.pauseEvent != null) { - inspector.isolate.pauseEvent = null; - final resumeEvent = vm_service.Event( - kind: vm_service.EventKind.kResume, - timestamp: DateTime.now().millisecondsSinceEpoch, - isolate: inspector.isolateRef, - ); - streamNotify(vm_service.EventStreams.kDebug, resumeEvent); - } - - return Success(); - } - - @override - Future getFlagList() => - wrapInErrorHandlerAsync('getFlagList', _getFlagList); - - Future _getFlagList() async { - // Return basic flag list for WebSocket mode - return FlagList( - flags: [ - Flag( - name: _pauseIsolatesOnStartFlag, - comment: 'If enabled, isolates are paused on start', - valueAsString: pauseIsolatesOnStart.toString(), - ), - ], - ); - } - - @override - Future getStack( - String isolateId, { - String? idZoneId, - int? limit, - }) => wrapInErrorHandlerAsync('getStack', () => _getStack(isolateId)); - - Future _getStack(String isolateId) async { - if (!isIsolateRunning) { - throw vm_service.RPCError( - 'getStack', - vm_service.RPCErrorKind.kInvalidParams.code, - 'No running isolate found for id: $isolateId', - ); - } - if (inspector.isolateRef.id != isolateId) { - throw vm_service.RPCError( - 'getStack', - vm_service.RPCErrorKind.kInvalidParams.code, - 'Isolate with id $isolateId not found.', - ); - } - - // Return empty stack since we're in WebSocket mode without Chrome debugging - return vm_service.Stack( - frames: [], - asyncCausalFrames: [], - awaiterFrames: [], - ); - } -} - -/// Extended ReloadReport that includes additional metadata in JSON output. -class _ReloadReportWithMetadata extends vm_service.ReloadReport { - final List? notices; - _ReloadReportWithMetadata({super.success, this.notices}); - - @override - Map toJson() { - final jsonified = { - 'type': 'ReloadReport', - 'success': success ?? false, - }; - if (notices != null) { - jsonified['notices'] = notices!.map((e) => {'message': e}).toList(); - } - return jsonified; - } -} diff --git a/dwds/lib/src/sockets.dart b/dwds/lib/src/sockets.dart deleted file mode 100644 index c93e9b789f..0000000000 --- a/dwds/lib/src/sockets.dart +++ /dev/null @@ -1,249 +0,0 @@ -// Copyright 2021 The Dart Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'dart:async'; -import 'dart:typed_data'; - -import 'package:logging/logging.dart'; -import 'package:sse/client/sse_client.dart'; -import 'package:stream_channel/stream_channel.dart'; -import 'package:web_socket/web_socket.dart'; - -abstract class SocketClient { - StreamSink get sink; - Stream get stream; - void close(); -} - -class SseSocketClient extends SocketClient { - final SseClient _client; - SseSocketClient(this._client); - - @override - StreamSink get sink => _client.sink; - - @override - Stream get stream => _client.stream; - - @override - void close() => _client.close(); -} - -class WebSocketClient extends SocketClient { - final StreamChannelMixin _channel; - - WebSocketClient(this._channel); - - @override - StreamSink get sink => _channel.sink; - @override - Stream get stream => _channel.stream.map((dynamic o) => o.toString()); - - @override - void close() => _channel.sink.close(); -} - -typedef ReconnectCallback = FutureOr Function(StreamSink); - -/// A [WebSocket] wrapper that can automatically re-establish a connection -/// when a connection is lost (e.g., upon entering "sleep" mode, flaky network -/// connections, etc.). -class PersistentWebSocket with StreamChannelMixin { - PersistentWebSocket._( - this.uri, - this._ws, { - required this.exponentialBackoffDelayMs, - required this.maxRetryAttempts, - required this.debugName, - this.onReconnect, - this.logger, - }); - - /// Creates a [PersistentWebSocket] instance connected to [uri]. - /// - /// [debugName] is a string included in logs written by this class to provide - /// additional information about the purpose of this connection. - /// - /// [maxRetryAttempts] sets the maximum number of retry attempts that can be - /// made before giving up. - /// - /// [exponentialBackoffDelayMs] is the length of the initial delay before - /// attempting to retry the connection in milliseconds. This delay doubles - /// after each unsuccessful retry attempt. - /// - /// If [logger] is provided, messages will be logged when attempting to - /// re-establish a connection. - /// - /// No retries are attempted when making the initial web socket connection, - /// so callers must be prepared to handle both `SocketException`s and - /// [WebSocketException] thrown if the connection to [uri] fails. - static Future connect( - Uri uri, { - String debugName = kDefaultDebugName, - int maxRetryAttempts = kDefaultMaxRetryAttempts, - int exponentialBackoffDelayMs = kDefaultBackoffDelayMs, - ReconnectCallback? onReconnect, - Logger? logger, - }) { - return WebSocket.connect(uri).then((socket) { - return PersistentWebSocket._( - uri, - socket, - exponentialBackoffDelayMs: exponentialBackoffDelayMs, - maxRetryAttempts: maxRetryAttempts, - logger: logger, - onReconnect: onReconnect, - debugName: debugName, - ); - }); - } - - final Logger? logger; - - static const kDefaultDebugName = 'Unknown'; - - /// The debug name associated with this connection. - /// - /// Useful when trying to identify the context of a given connection. If - /// [logger] is set, this name will be output as part of messages output - /// while attempting to re-establish connections. - final String debugName; - - static const kDefaultMaxRetryAttempts = 3; - - /// The number of retry attempts to make before giving up. - final int maxRetryAttempts; - - static const kDefaultBackoffDelayMs = 100; - - /// The amount of time to wait before attempting to retry the connection. - /// - /// The retry delay is calculated using exponential backoff, where each - /// successive delay before a retry attempt is twice as long as the last - /// delay. - final int exponentialBackoffDelayMs; - - /// Completes when the web socket connection is disposed of. - Future get done => _doneCompleter.future; - final _doneCompleter = Completer(); - - /// The URI used to establish the web socket connection. - final Uri uri; - - ReconnectCallback? onReconnect; - - WebSocket _ws; - - late final _incomingStreamController = StreamController() - ..onListen = _listenWithRetry; - final _outgoingStreamController = StreamController(); - - /// Used to indicate that the web socket was closed after [close] was - /// invoked. - var _closedManually = false; - - void _writeToWebSocket(dynamic data) { - try { - if (data is String) { - _ws.sendText(data); - } else if (data is Uint8List) { - _ws.sendBytes(data); - } else { - throw UnsupportedError('Unexpected data type: ${data.runtimeType}'); - } - } on WebSocketConnectionClosed { - // The underlying connection was closed (e.g., by the server). - // Suppress surfacing an unhandled error by catching here. - // [onReconnect] is responsible for recovering after reconnect. - logger?.fine('$uri ($debugName): connection closed.'); - } - } - - /// Close the web socket connection. - Future close() async { - if (_closedManually) { - return; - } - _closedManually = true; - await _incomingStreamController.close(); - await _outgoingStreamController.close(); - await _ws.close(); - } - - Future _listenWithRetry() async { - var retry = false; - var retryCount = 0; - - _outgoingStreamController.stream.listen(_writeToWebSocket); - - Future attemptRetry(String message) async { - await Future.delayed(Duration(milliseconds: 100 << retryCount)); - retryCount++; - retry = !_closedManually; - if (!_closedManually) { - logger?.info('$message. Retrying ($retryCount / $maxRetryAttempts)'); - } - } - - do { - final wsOnDoneCompleter = Completer(); - - // Check if the connection has been closed during an asynchronous gap. - if (_closedManually) { - break; - } - final retried = retry; - if (retry) { - try { - _ws = await WebSocket.connect(uri); - // Reset the retry counter on a successful reconnection. - retryCount = 0; - } on Exception { - await attemptRetry( - 'Failed to establish connection to $uri ($debugName).', - ); - continue; - } - retry = false; - } - - // If the last web socket connection closed unexpected, try to - // re-establish the connection. - late StreamSubscription eventsSub; - eventsSub = _ws.events.listen((e) async { - switch (e) { - case TextDataReceived(:final text): - _incomingStreamController.sink.add(text); - case BinaryDataReceived(:final data): - _incomingStreamController.sink.add(data); - case CloseReceived(:final code): - if (code == 1006) { - await attemptRetry('Lost connection to $uri ($debugName).'); - await eventsSub.cancel(); - } - wsOnDoneCompleter.complete(); - } - }); - - if (retried) { - await onReconnect?.call(sink); - } - - // Wait for the web socket's onDone handler to run before attempting to - // retry. Waiting on _ws.done can result in a race condition. - await wsOnDoneCompleter.future; - } while (retry && retryCount < maxRetryAttempts); - - _doneCompleter.complete(); - if (!_incomingStreamController.isClosed) { - await _incomingStreamController.sink.close(); - } - } - - @override - StreamSink get sink => _outgoingStreamController.sink; - - @override - Stream get stream => _incomingStreamController.stream.cast(); -} diff --git a/dwds/lib/src/utilities/conversions.dart b/dwds/lib/src/utilities/conversions.dart deleted file mode 100644 index f965c0077a..0000000000 --- a/dwds/lib/src/utilities/conversions.dart +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -/// Functions for converting between the different object references we use. -library; - -import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'; - -/// Convert [argument] to a form usable in WIP evaluation calls. -/// -/// The [argument] should be either a RemoteObject or a simple object that can -/// be passed through the protocol directly. -/// -/// Note that this doesn't agree with the Chrome Protocol type CallArgument - -/// it's just a Map corresponding to a RemoteObject. But this seems to work -/// consistently where the callArgument format doesn't, at least if we're -/// using the `arguments` pseudo-variable in JS instead of passing directly -/// as real arguments. -Map callArgumentFor(Object argument) { - if (argument is RemoteObject) { - return _isPrimitive(argument) - ? _callArgumentForPrimitive(argument.value) - : _callArgumentForRemote(argument); - } else { - return _callArgumentForPrimitive(argument); - } -} - -/// True if [remote] represents a primitive -bool _isPrimitive(RemoteObject remote) { - final id = remote.objectId; - return id == null || isStringId(id) || id.startsWith('objects/'); -} - -/// A List of Chrome RemoteObjects from Dart object Ids [dartIds]. -/// -/// See [remoteObjectFor] for the accepted ID format. -List remoteObjectsFor(Iterable dartIds) { - return dartIds.map(remoteObjectFor).toList(); -} - -/// A Chrome RemoteObject from a Dart object Id [dartId]. -/// -/// We expect [dartId] to be one of the following forms. -/// * Chrome objectId - e.g. '{"injectedScriptId":1,"id":1}' -/// * Our fabricated string Id - e.g. '#StringInstanceRef#actualString' -/// * Dart fabricated IDs - e.g. objects/int-8765 -/// -/// Note that this does NOT accept a Dart library URI, which can be used as an -/// InstanceRef identifier in the protocol. Libraries aren't first class, and -/// must be handled separately. -RemoteObject remoteObjectFor(String dartId) { - final data = {}; - data['objectId'] = dartId; - if (isStringId(dartId)) { - data['type'] = 'string'; - data['value'] = _stringFromDartId(dartId); - } else if (isDoubleId(dartId)) { - data['type'] = 'number'; - data['value'] = _doubleFromDartId(dartId); - } else if (isIntId(dartId)) { - data['type'] = 'number'; - data['value'] = _intFromDartId(dartId); - } else if (isBoolId(dartId)) { - data['type'] = 'boolean'; - data['value'] = _boolFromDartId(dartId); - } else if (dartId == _nullId) { - data['type'] = 'undefined'; - data['value'] = null; - } else { - data['type'] = 'object'; - } - return RemoteObject(data); -} - -/// A Dart object Id appropriate for [argument]. -/// -/// This will work for simple values, RemoteObject, and Maps representations of -/// RemoteObjects. -String dartIdFor(Object? argument) { - if (argument == null) { - return _nullId; - } - if (argument is double) { - return '$_prefixForDoubleIds$argument'; - } - if (argument is int) { - return '$_prefixForIntIds$argument'; - } - if (argument is bool) { - return '$_prefixForBoolIds$argument'; - } - if (argument is String) { - return '$_prefixForStringIds$argument'; - } - if (argument is RemoteObject) { - if (argument.objectId == null) { - throw ArgumentError.value(argument, 'objectId', 'No objectId found'); - } - return argument.objectId!; - } - if (argument is Map) { - final id = argument['objectId'] as String?; - if (id == null) { - throw ArgumentError.value(argument, 'objectId', 'No objectId found'); - } - return id; - } - throw ArgumentError.value(argument, 'objectId', 'No objectId found'); -} - -/// Converts a Dart object Id for a String to the underlying string. -/// -/// If the ID is not for a String, throws ArgumentError. If you don't know what -/// the ID represents, use a more general API like [remoteObjectFor] and if it -/// is a primitive, you can get the value from the resulting [RemoteObject]. -String stringFromDartId(String dartId) { - if (!isStringId(dartId)) { - throw ArgumentError.value( - dartId, - 'dart object ID', - 'Expected a valid ID for a String', - ); - } - return _stringFromDartId(dartId); -} - -/// Is [dartId] an Id for a String. -bool isStringId(String dartId) => dartId.startsWith(_prefixForStringIds); - -/// Is [dartId] an Id for a boolean. -bool isBoolId(String dartId) => dartId.startsWith(_prefixForBoolIds); - -/// Is [dartId] an Id for a int. -bool isIntId(String dartId) => dartId.startsWith(_prefixForIntIds); - -/// Is [dartId] an Id for a double. -bool isDoubleId(String dartId) => dartId.startsWith(_prefixForDoubleIds); - -/// Is [dartId] an Id for a Dart library. -bool isLibraryId(String dartId) => _uriPrefixes.any(dartId.startsWith); - -/// A Map representing a RemoteObject for a primitive object. -Map _callArgumentForPrimitive(Object? primitive) { - return {'type': _jsTypeOf(primitive), 'value': primitive}; -} - -/// A Map representing a RemoteObject from an actual RemoteObject. -Map _callArgumentForRemote(RemoteObject remote) { - return {'type': 'object', 'objectId': remote.objectId}; -} - -/// The JS type name to use in a RemoteObject reference to [object]. -String _jsTypeOf(Object? object) { - if (object == null) return 'undefined'; - if (object is String) return 'string'; - if (object is num) return 'num'; - if (object is bool) return 'bool'; - return 'object'; -} - -/// Prefixes we use to identify if a Dart ID is a library URI. -const _uriPrefixes = ['dart:', 'package:', 'org-dartlang-app:']; - -/// Convert [dartIdForString] to its corresponding String. -String _stringFromDartId(String dartIdForString) => - dartIdForString.substring(_prefixForStringIds.length); - -/// Convert [dartIdForInt] to its corresponding int. -int? _intFromDartId(String dartIdForInt) => - int.tryParse(dartIdForInt.substring(_prefixForIntIds.length)); - -/// Convert [dartIdForDouble] to its corresponding double. -double? _doubleFromDartId(String dartIdForDouble) => - double.tryParse(dartIdForDouble.substring(_prefixForDoubleIds.length)); - -/// Convert [dartIdForBool] to its corresponding boolean. -bool _boolFromDartId(String dartIdForBool) => - dartIdForBool.substring(_prefixForBoolIds.length) == 'true'; - -/// Chrome doesn't give us an objectId for a String. So we use the string -/// as its own ID, with a prefix. -/// -/// This should not be confused with any -/// other object Ids, as those will be Chrome objectIds, which are -/// opaque, but are JSON serialized objects of the form -/// "{\"injectedScriptId\":1,\"id\":1}". -const _prefixForStringIds = '#StringInstanceRef#'; - -/// The prefix the Dart VM uses for ints, followed by a string representation of -/// the number. -const _prefixForIntIds = 'objects/int-'; - -/// The prefix we use for doubles, followed by a string representation of -/// the number. -const _prefixForDoubleIds = 'objects/double-'; - -/// The prefix the Dart VM uses for booleans, followed by 'true' or 'false'. -const _prefixForBoolIds = 'objects/bool-'; - -/// The object id the Dart VM uses for null. -const _nullId = 'objects/null'; diff --git a/dwds/lib/src/utilities/dart_uri.dart b/dwds/lib/src/utilities/dart_uri.dart deleted file mode 100644 index 3c0b6f9484..0000000000 --- a/dwds/lib/src/utilities/dart_uri.dart +++ /dev/null @@ -1,284 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'package:dwds/src/config/tool_configuration.dart'; -import 'package:logging/logging.dart'; -import 'package:package_config/package_config.dart'; -import 'package:path/path.dart' as p; - -/// The URI for a particular Dart file, able to canonicalize from various -/// different representations. -class DartUri { - DartUri._(this.serverPath); - - /// Accepts various forms of URI and can convert between forms. - /// - /// The accepted forms are: - /// - /// - package:packageName/pathUnderLib/file.dart - /// - org-dartlang-app:///prefix/path/file.dart, where prefix is ignored. - /// e.g. org-dartlang-app:example/hello_world/main.dart, - /// - /packages/packageName/foo.dart, the web server form of a package URI, - /// e.g. /packages/path/src/utils.dart - /// - /path/foo.dart or path/foo.dart, e.g. /hello_world/web/main.dart, where - /// path is a web server path and so relative to the directory being - /// served, not to the package. - /// - /// The optional [root] is the directory the app is served from. - factory DartUri(String uri, [String? root]) { - // TODO(annagrin): Support creating DartUris from `dart:` uris. - // Issue: https://github.com/dart-lang/webdev/issues/1584 - if (uri.startsWith('org-dartlang-app:') || uri.startsWith('google3:')) { - return DartUri._fromDartLangUri(uri); - } - if (uri.startsWith('package:')) { - return DartUri._fromPackageUri(uri, root: root); - } - if (uri.startsWith('file:')) { - return DartUri._fromFileUri(uri, root: root); - } - if (uri.startsWith('packages/') || uri.startsWith('/packages/')) { - return DartUri._fromRelativePath(uri, root: root); - } - if (uri.startsWith('/')) { - return DartUri._fromRelativePath(uri); - } - if (uri.startsWith('http:') || uri.startsWith('https:')) { - return DartUri(Uri.parse(uri).path); - } - - throw FormatException('Unsupported URI form: $uri'); - } - - @override - String toString() => 'DartUri: $serverPath'; - - /// Construct from a package: URI - factory DartUri._fromDartLangUri(String uri) { - var serverPath = globalToolConfiguration.loadStrategy.serverPathForAppUri( - uri, - ); - if (serverPath == null) { - _logger.severe('Cannot find server path for $uri'); - serverPath = uri; - } - return DartUri._(serverPath); - } - - /// Construct from a package: URI - factory DartUri._fromPackageUri(String uri, {String? root}) { - var serverPath = globalToolConfiguration.loadStrategy.serverPathForAppUri( - uri, - ); - if (serverPath == null) { - _logger.severe('Cannot find server path for $uri'); - serverPath = uri; - } - return DartUri._fromRelativePath(serverPath, root: root); - } - - /// Construct from a file: URI - factory DartUri._fromFileUri(String uri, {String? root}) { - final libraryName = _resolvedUriToUri[uri]; - if (libraryName != null) return DartUri(libraryName, root); - // This is not one of our recorded libraries. - throw ArgumentError.value(uri, 'uri', 'Unknown library'); - } - - /// Construct from a path, relative to the directory being served. - factory DartUri._fromRelativePath(String uri, {String? root}) { - uri = uri[0] == '.' ? uri.substring(1) : uri; - uri = uri[0] == '/' ? uri.substring(1) : uri; - - if (root != null) { - return DartUri._fromRelativePath(p.url.join(root, uri)); - } - return DartUri._(uri); - } - - /// The canonical web server path part of the URI. - /// - /// This is a relative path, which can be used to fetch the corresponding file - /// from the server. For example, 'hello_world/main.dart' or - /// 'packages/path/src/utils.dart'. - final String serverPath; - - static final _logger = Logger('DartUri'); - - /// The way we resolve file: URLs into package: URLs - static PackageConfig? _packageConfig; - - /// All of the known absolute library paths, indexed by their library URL. - /// - /// Examples: - /// - /// We are assuming that all library uris are coming from - /// https://github.com/dart-lang/sdk/blob/main/runtime/vm/service/service.md#getscripts) - /// and can be translated to their absolute paths and back. - /// - /// dart:html <-> - /// org-dartlang-sdk:///sdk/lib/html/html.dart - /// (not supported, issue: https://github.com/dart-lang/webdev/issues/1457) - /// - /// org-dartlang-app:///example/hello_world/main.dart <-> - /// file:///source/webdev/fixtures/_test/example/hello_world/main.dart, - /// - /// org-dartlang-app:///example/hello_world/part.dart <-> - /// file:///source/webdev/fixtures/_test/example/hello_world/part.dart, - /// - /// package:path/path.dart <-> - /// file:///.pub-cache/hosted/pub.dev/path-1.8.0/lib/path.dart, - /// - /// package:path/src/path_set.dart <-> - /// file:///.pub-cache/hosted/pub.dev/path-1.8.0/lib/src/path_set.dart, - static final Map _uriToResolvedUri = {}; - - /// All of the known libraries, indexed by their absolute file URL. - static final Map _resolvedUriToUri = {}; - - /// Returns a resolved path for a g3-relative URI. - /// - /// This map is empty if not a google3 app. - static final Map _g3RelativeUriToResolvedUri = {}; - - /// Returns package, app, or dart uri for a resolved path. - static String? toPackageUri(String uri) { - final packageUri = _resolvedUriToUri[uri]; - if (packageUri != null) return packageUri; - - // If this is an internal app, then the given uri might - // be relative or absolute google3 uri. - if (globalToolConfiguration.appMetadata.isInternalBuild) { - final resolvedUri = _g3RelativeUriToResolvedUri[uri]; - final g3PackageUri = _resolvedUriToUri[resolvedUri]; - if (g3PackageUri != null) { - return g3PackageUri; - } - - // If the input is an absolute URI (like file:/// or google3:///), - // return it as is, as DWDS can use it directly. - final parsedUri = Uri.tryParse(uri); - if (parsedUri != null && parsedUri.hasAbsolutePath) { - return uri; - } - } - - return null; - } - - /// Returns resolved path for a package, app, or dart uri. - static String? toResolvedUri(String uri) => _uriToResolvedUri[uri]; - - static String _currentDirectory = p.current; - - /// The directory in which we're running. - /// - /// We store this here because for tests we may want to act as if we're - /// running in the directory of a target package, even if the current - /// directory of the tests is actually the main dwds directory. - static String get currentDirectory => _currentDirectory; - - static set currentDirectory(String newDir) { - _currentDirectory = newDir; - _currentDirectoryUri = p.toUri(newDir).toString(); - } - - static String _currentDirectoryUri = p.toUri(currentDirectory).toString(); - - /// The current directory as a file: Uri, saved in a field to avoid - /// re-computing. - static String get currentDirectoryUri => _currentDirectoryUri; - - /// Record library and script uris to enable resolving library and script - /// paths. - static Future initialize() async { - clear(); - await _loadPackageConfig( - p.toUri(globalToolConfiguration.loadStrategy.packageConfigPath), - ); - } - - /// Clear the uri resolution tables. - static void clear() { - _packageConfig = null; - _resolvedUriToUri.clear(); - _uriToResolvedUri.clear(); - _g3RelativeUriToResolvedUri.clear(); - } - - /// Record all of the libraries, indexed by their absolute file: URI. - static void recordAbsoluteUris(Iterable libraryUris) { - for (final uri in libraryUris) { - _recordAbsoluteUri(uri); - if (globalToolConfiguration.appMetadata.isInternalBuild) { - _recordG3RelativeUri(uri); - } - } - } - - static void _recordG3RelativeUri(String libraryUri) { - final absoluteUri = _uriToResolvedUri[libraryUri]; - if (absoluteUri == null) return; - - final g3RelativeUri = globalToolConfiguration.loadStrategy.g3RelativePath( - absoluteUri, - ); - if (g3RelativeUri != null) { - _g3RelativeUriToResolvedUri[g3RelativeUri] = absoluteUri; - } - } - - /// Load the .dart_tool/package_config.json file associated with the running - /// application so we can resolve file URLs into package: URLs appropriately. - static Future _loadPackageConfig(Uri uri) async { - _packageConfig = await loadPackageConfigUri( - uri, - loader: globalToolConfiguration.loadStrategy.packageConfigLoader, - onError: (e) { - _logger.warning('Cannot read packages spec: $uri', e); - }, - ); - } - - /// Record the library represented by package: or org-dartlang-app: uris - /// indexed by absolute file: URI. - static void _recordAbsoluteUri(String libraryUri) { - final uri = Uri.parse(libraryUri); - if (uri.scheme.isEmpty && !uri.path.endsWith('.dart')) { - // ignore non-dart files - return; - } - - String? libraryPath; - switch (uri.scheme) { - case 'dart': - // TODO(annagrin): Support resolving `dart:` uris. - // Issue: https://github.com/dart-lang/webdev/issues/1584 - return; - case 'org-dartlang-app': - case 'google3': - // Both currentDirectoryUri and the libraryUri path should have '/' - // separators, so we can join them as url paths to get the absolute file - // url. - final libraryRoot = globalToolConfiguration.loadStrategy.libraryRoot; - libraryPath = p.url.join( - libraryRoot ?? currentDirectoryUri, - uri.path.substring(1), - ); - break; - case 'package': - libraryPath = _packageConfig?.resolve(uri)?.toString(); - break; - default: - throw ArgumentError.value(libraryUri, 'URI scheme not allowed'); - } - - if (libraryPath != null) { - _uriToResolvedUri[libraryUri] = libraryPath; - _resolvedUriToUri[libraryPath] = libraryUri; - } else { - _logger.fine('Unresolved uri: $uri'); - } - } -} diff --git a/dwds/lib/src/utilities/ddc_names.dart b/dwds/lib/src/utilities/ddc_names.dart deleted file mode 100644 index d9ba2c2fee..0000000000 --- a/dwds/lib/src/utilities/ddc_names.dart +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'package:path/path.dart' as p; - -/// Transforms a path to a valid JS identifier. -/// -/// This logic must be synchronized with [pathToJSIdentifier] in DDC at: -/// pkg/dev_compiler/lib/src/compiler/module_builder.dart -/// -/// For backwards compatibility, if this pattern is changed, -/// dev_compiler_bootstrap.dart must be updated to accept both old and new -/// patterns. -String pathToJSIdentifier(String path) { - path = p.normalize(path); - if (path.startsWith('/') || path.startsWith('\\')) { - path = path.substring(1, path.length); - } - return toJSIdentifier( - path - .replaceAll('\\', '__') - .replaceAll('/', '__') - .replaceAll('..', '__') - .replaceAll('-', '_'), - ); -} - -/// Escape [name] to make it into a valid identifier. -String toJSIdentifier(String name) { - if (name.isEmpty) return r'$'; - - // Escape any invalid characters - StringBuffer? buffer; - for (var i = 0; i < name.length; i++) { - final ch = name[i]; - final needsEscape = ch == r'$' || _invalidCharInIdentifier.hasMatch(ch); - if (needsEscape && buffer == null) { - buffer = StringBuffer(name.substring(0, i)); - } - if (buffer != null) { - buffer.write(needsEscape ? '\$${ch.codeUnits.join("")}' : ch); - } - } - - final result = buffer != null ? '$buffer' : name; - // Ensure the identifier first character is not numeric and that the whole - // identifier is not a keyword. - if (result.startsWith(RegExp('[0-9]')) || invalidVariableName(result)) { - return '\$$result'; - } - return result; -} - -/// Returns true for invalid JS variable names, such as keywords. -/// Also handles invalid variable names in strict mode, like "arguments". -bool invalidVariableName(String keyword, {bool strictMode = true}) { - switch (keyword) { - // http://www.ecma-international.org/ecma-262/6.0/#sec-future-reserved-words - case 'await': - case 'break': - case 'case': - case 'catch': - case 'class': - case 'const': - case 'continue': - case 'debugger': - case 'default': - case 'delete': - case 'do': - case 'else': - case 'enum': - case 'export': - case 'extends': - case 'finally': - case 'for': - case 'function': - case 'if': - case 'import': - case 'in': - case 'instanceof': - case 'let': - case 'new': - case 'return': - case 'super': - case 'switch': - case 'this': - case 'throw': - case 'try': - case 'typeof': - case 'var': - case 'void': - case 'while': - case 'with': - return true; - case 'arguments': - case 'eval': - // http://www.ecma-international.org/ecma-262/6.0/#sec-future-reserved-words - // http://www.ecma-international.org/ecma-262/6.0/#sec-identifiers-static-semantics-early-errors - case 'implements': - case 'interface': - case 'package': - case 'private': - case 'protected': - case 'public': - case 'static': - case 'yield': - return strictMode; - } - return false; -} - -// Invalid characters for identifiers, which would need to be escaped. -final _invalidCharInIdentifier = RegExp(r'[^A-Za-z_$0-9]'); diff --git a/dwds/lib/src/utilities/domain.dart b/dwds/lib/src/utilities/domain.dart deleted file mode 100644 index df8d5281b5..0000000000 --- a/dwds/lib/src/utilities/domain.dart +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'package:vm_service/vm_service.dart'; - -Never throwInvalidParam(String method, String message) { - throw RPCError(method, RPCErrorKind.kInvalidParams.code, message); -} diff --git a/dwds/lib/src/utilities/fix_protocol.dart b/dwds/lib/src/utilities/fix_protocol.dart deleted file mode 100644 index 80922bfb5f..0000000000 --- a/dwds/lib/src/utilities/fix_protocol.dart +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -/// Returns [url] modified if necessary so that, if the current page is served -/// over `https`, then the URL is converted to `https` (or `wss`). -String fixProtocol(String url, {required String windowLocationProtocol}) { - var uri = Uri.parse(url); - if (windowLocationProtocol == 'https:' && - // Chrome allows mixed content on localhost. It is not safe to assume the - // server is also listening on https. - uri.host != 'localhost') { - if (uri.scheme == 'http') { - uri = uri.replace(scheme: 'https'); - } else if (uri.scheme == 'ws') { - uri = uri.replace(scheme: 'wss'); - } - } - return uri.toString(); -} diff --git a/dwds/lib/src/utilities/objects.dart b/dwds/lib/src/utilities/objects.dart deleted file mode 100644 index 86680aec15..0000000000 --- a/dwds/lib/src/utilities/objects.dart +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -/// A library for WebKit mirror objects and support code. -/// -/// These probably should get migrated into -/// `package:webkit_inspection_protocol` over time. -library; - -import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'; - -/// Represents a property of an object. -class Property { - final Map? _map; - - RemoteObject? _remoteObjectValue; - - Property(this._map); - - Map? get map => _map; - - /// The remote object value in unwrapped form. - /// - /// Useful for getting access to properties of particular types of - /// RemoteObject. - Object? get rawValue => _map == null ? null : _map['value']; - - /// Remote object value in case of primitive values or JSON values (if it was - /// requested). (optional) - RemoteObject? get value { - if (_remoteObjectValue != null) return _remoteObjectValue!; - if (_map == null) return null; - if (rawValue == null) return null; - final val = _map['value']; - if (val is RemoteObject) { - _remoteObjectValue = val; - } else { - _remoteObjectValue = RemoteObject(val as Map); - } - return _remoteObjectValue; - } - - /// The name of the property - String? get name { - if (_map == null) return null; - if (rawName == null) return null; - const prefix = 'Symbol('; - var nonSymbol = (rawName!.startsWith(prefix)) - ? rawName!.substring(prefix.length, rawName!.length - 1) - : rawName!; - // Adjust names for late fields: - // '_#MyTestClass#myselfField' -> 'myselfField' - // TODO(annagrin): Use debug symbols to map from dart to JS symbols. - // https://github.com/dart-lang/sdk/issues/40273 - nonSymbol = nonSymbol.split('#').last; - return nonSymbol.split('.').last; - } - - /// The raw name of the property in JS. - /// - /// Will be of the form 'Symbol(_actualName)' for private fields. - String? get rawName { - if (_map == null) return null; - return _map['name'] as String; - } - - @override - String toString() => '$name: $value'; -} diff --git a/dwds/lib/src/utilities/sdk_configuration.dart b/dwds/lib/src/utilities/sdk_configuration.dart deleted file mode 100644 index ead1769d31..0000000000 --- a/dwds/lib/src/utilities/sdk_configuration.dart +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:io'; - -import 'package:file/file.dart'; -import 'package:file/local.dart'; -import 'package:path/path.dart' as p; - -class InvalidSdkConfigurationException implements Exception { - final String? message; - - InvalidSdkConfigurationException([this.message]); - - @override - String toString() { - final message = this.message; - if (message == null) return 'Invalid SDK configuration'; - return 'Invalid SDK configuration: $message'; - } -} - -/// SDK configuration provider interface. -/// -/// Supports lazily populated configurations by allowing to create -/// configuration asynchronously. -abstract class SdkConfigurationProvider { - const SdkConfigurationProvider(); - - Future get configuration; -} - -/// Dart SDK layout. -/// -/// Contains definition of the default SDK layout. -/// We keep all the path constants in one place for ease of update. -class SdkLayout { - static final defaultSdkDirectory = p.dirname( - p.dirname(Platform.resolvedExecutable), - ); - static final SdkLayout defaultSdkLayout = SdkLayout.createDefault( - defaultSdkDirectory, - ); - - final String sdkDirectory; - final String summaryPath; - final String dartdevcSnapshotPath; - - SdkLayout.createDefault(String sdkDirectory) - : this( - sdkDirectory: sdkDirectory, - summaryPath: p.join( - sdkDirectory, - 'lib', - '_internal', - 'ddc_outline.dill', - ), - dartdevcSnapshotPath: p.join( - sdkDirectory, - 'bin', - 'snapshots', - 'dartdevc.dart.snapshot', - ), - ); - - const SdkLayout({ - required this.sdkDirectory, - required this.summaryPath, - required this.dartdevcSnapshotPath, - }); -} - -/// Dart SDK configuration. -/// -/// Provides helpers to convert paths to uris that work on all platforms. -/// -class SdkConfiguration { - static final defaultSdkLayout = SdkLayout.defaultSdkLayout; - static final defaultConfiguration = SdkConfiguration.fromSdkLayout( - SdkLayout.defaultSdkLayout, - ); - - final String? sdkDirectory; - final String? sdkSummaryPath; - final String? compilerWorkerPath; - - const SdkConfiguration({ - this.sdkDirectory, - this.sdkSummaryPath, - this.compilerWorkerPath, - }); - - const SdkConfiguration.empty() : this(); - - SdkConfiguration.fromSdkLayout(SdkLayout sdkLayout) - : this( - sdkDirectory: sdkLayout.sdkDirectory, - sdkSummaryPath: sdkLayout.summaryPath, - compilerWorkerPath: sdkLayout.dartdevcSnapshotPath, - ); - - static Uri? _toUri(String? path) => path == null ? null : p.toUri(path); - static Uri? _toAbsoluteUri(String? path) => - path == null ? null : p.toUri(p.absolute(path)); - - Uri? get sdkDirectoryUri => _toUri(sdkDirectory); - Uri? get sdkSummaryUri => _toUri(sdkSummaryPath); - - /// Note: has to be ///file: Uri to run in an isolate. - Uri? get compilerWorkerUri => _toAbsoluteUri(compilerWorkerPath); - - /// Throws [InvalidSdkConfigurationException] if configuration does not - /// exist on disk. - void validate({FileSystem fileSystem = const LocalFileSystem()}) { - validateSdkDir(fileSystem: fileSystem); - validateSummaries(fileSystem: fileSystem); - validateCompilerWorker(fileSystem: fileSystem); - } - - /// Throws [InvalidSdkConfigurationException] if SDK root does not - /// exist on the disk. - void validateSdkDir({FileSystem fileSystem = const LocalFileSystem()}) { - if (sdkDirectory == null || - !fileSystem.directory(sdkDirectory).existsSync()) { - throw InvalidSdkConfigurationException( - 'Sdk directory $sdkDirectory does not exist', - ); - } - } - - void validateSummaries({FileSystem fileSystem = const LocalFileSystem()}) { - if (sdkSummaryPath == null || - !fileSystem.file(sdkSummaryPath).existsSync()) { - throw InvalidSdkConfigurationException( - 'Sdk summary $sdkSummaryPath does not exist', - ); - } - } - - void validateCompilerWorker({ - FileSystem fileSystem = const LocalFileSystem(), - }) { - if (compilerWorkerPath == null || - !fileSystem.file(compilerWorkerPath).existsSync()) { - throw InvalidSdkConfigurationException( - 'Compiler worker $compilerWorkerPath does not exist', - ); - } - } -} - -class DefaultSdkConfigurationProvider extends SdkConfigurationProvider { - const DefaultSdkConfigurationProvider(); - - @override - Future get configuration async => - SdkConfiguration.defaultConfiguration; -} diff --git a/dwds/lib/src/utilities/server.dart b/dwds/lib/src/utilities/server.dart deleted file mode 100644 index 776f34d596..0000000000 --- a/dwds/lib/src/utilities/server.dart +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:io'; - -import 'package:dwds/src/services/chrome/chrome_debug_exception.dart'; -import 'package:http_multi_server/http_multi_server.dart'; -import 'package:shelf/shelf.dart'; -import 'package:shelf/shelf_io.dart'; -import 'package:stack_trace/stack_trace.dart'; -import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart' - as wip; - -/// Returns a port that is probably, but not definitely, not in use. -/// -/// This has a built-in race condition: another process may bind this port at -/// any time after this call has returned. -Future findUnusedPort() async { - int port; - ServerSocket socket; - try { - socket = await ServerSocket.bind( - InternetAddress.loopbackIPv6, - 0, - v6Only: true, - ); - } on SocketException { - socket = await ServerSocket.bind(InternetAddress.loopbackIPv4, 0); - } - port = socket.port; - await socket.close(); - return port; -} - -/// Finds unused port and binds a new http server to it. -/// -/// Retries a few times to recover from errors due to -/// another thread or process opening the same port. -/// Starts by trying to bind to [port] if specified. -Future startHttpServer(String hostname, {int? port}) async { - HttpServer? httpServer; - final retries = 5; - var i = 0; - var foundPort = port ?? await findUnusedPort(); - while (i < retries) { - i++; - try { - httpServer = await HttpMultiServer.bind(hostname, foundPort); - } on SocketException { - if (i == retries) rethrow; - } - if (httpServer != null || i == retries) return httpServer!; - foundPort = await findUnusedPort(); - await Future.delayed(const Duration(milliseconds: 100)); - } - return httpServer!; -} - -/// Handles [requests] using [handler]. -/// -/// Captures all sync and async stack error traces and passes -/// them to the [onError] handler. -void serveHttpRequests( - Stream requests, - Handler handler, - void Function(Object, StackTrace) onError, -) { - return Chain.capture(() { - serveRequests(requests, handler); - }, onError: onError); -} - -/// Throws an [wip.ExceptionDetails] object if `exceptionDetails` is present on -/// the result. -void handleErrorIfPresent(wip.WipResponse? response, {String? evalContents}) { - final result = response?.result; - if (result == null) return; - if (result.containsKey('exceptionDetails')) { - throw ChromeDebugException( - result['exceptionDetails'] as Map, - evalContents: evalContents, - ); - } -} - -/// Returns result contained in the response. -/// Throws an [wip.ExceptionDetails] object if `exceptionDetails` is present on -/// the result or the result is null. -Map getResultOrHandleError( - wip.WipResponse? response, { - String? evalContents, -}) { - handleErrorIfPresent(response, evalContents: evalContents); - final result = response?.result?['result']; - if (result == null) { - throw ChromeDebugException({ - 'text': 'null result from Chrome Devtools', - }, evalContents: evalContents); - } - return result as Map; -} diff --git a/dwds/lib/src/utilities/shared.dart b/dwds/lib/src/utilities/shared.dart deleted file mode 100644 index ba866644c8..0000000000 --- a/dwds/lib/src/utilities/shared.dart +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:async'; - -import 'package:logging/logging.dart'; -import 'package:vm_service/vm_service.dart'; - -VMRef toVMRef(VM vm) => VMRef(name: vm.name); - -int _nextId = 0; -String createId() { - _nextId++; - return '$_nextId'; -} - -final _logger = Logger('Utilities'); - -void safeUnawaited( - Future future, { - void Function(Object, StackTrace)? onError, -}) { - onError ??= (Object error, StackTrace stackTrace) => - _logger.warning('Error in unawaited Future:', error, stackTrace); - unawaited(future.catchError(onError)); -} - -/// Throws an [RPCError] if the [asyncCallback] has an exception. -/// -/// Only throws a new exception if the original exception type was not -/// [RPCError] or [SentinelException] (the two supported exception types of -/// package:vm_service). -Future wrapInErrorHandlerAsync( - String command, - Future Function() asyncCallback, -) { - return asyncCallback().catchError((Object error) { - return Future.error( - RPCError( - command, - RPCErrorKind.kInternalError.code, - 'Unexpected DWDS error for $command: $error', - ), - ); - }, test: (e) => e is! RPCError && e is! SentinelException); -} diff --git a/dwds/lib/src/utilities/synchronized.dart b/dwds/lib/src/utilities/synchronized.dart deleted file mode 100644 index e318817d02..0000000000 --- a/dwds/lib/src/utilities/synchronized.dart +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:async'; - -import 'package:pool/pool.dart'; - -class AtomicQueue { - final _pool = Pool(1); - - AtomicQueue(); - - // Executes tasks sequentially. - Future run(FutureOr Function() task) => _pool.withResource(task); -} diff --git a/dwds/lib/src/utilities/uuid.dart b/dwds/lib/src/utilities/uuid.dart deleted file mode 100644 index eddc45b6b4..0000000000 --- a/dwds/lib/src/utilities/uuid.dart +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:math'; -import 'dart:typed_data'; - -/// A UUID generator. -/// -/// This is a lightweight replacement for package:uuid, specifically for -/// generating version 4 (random) UUIDs using a cryptographically secure random -/// number generator. -/// -/// See https://datatracker.ietf.org/doc/html/rfc4122#section-4.4 -/// See also https://github.com/daegalus/dart-uuid/blob/main/lib/v4.dart -class Uuid { - static final Random _random = Random.secure(); - - const Uuid(); - - /// Generates a Version 4 (random) UUID. - /// - /// The UUID is formatted as a string: - /// xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx - /// where x is a random hex digit and y is a random hex digit from 8, 9, a, - /// or b. - String v4() { - final bytes = Uint8List(16); - for (var i = 0; i < 16; i++) { - bytes[i] = _random.nextInt(256); - } - - // Set the version number (4) to 0100 - bytes[6] = (bytes[6] & 0x0f) | 0x40; - - // Set the variant (10xx) to 1000 - bytes[8] = (bytes[8] & 0x3f) | 0x80; - - final buf = StringBuffer(); - for (var i = 0; i < 16; i++) { - if (i == 4 || i == 6 || i == 8 || i == 10) { - buf.write('-'); - } - buf.write(_hex[bytes[i]]); - } - return buf.toString(); - } - - /// A pre-computed list of hex strings for all possible byte values (0-255). - /// - /// For example, `_hex[255]` is 'ff'. - static final _hex = List.generate( - 256, - (i) => i.toRadixString(16).padLeft(2, '0'), - ); -} diff --git a/dwds/lib/src/version.dart b/dwds/lib/src/version.dart deleted file mode 100644 index aeec9f16b7..0000000000 --- a/dwds/lib/src/version.dart +++ /dev/null @@ -1,2 +0,0 @@ -// Generated code. Do not modify. -const packageVersion = '27.2.0-wip'; diff --git a/dwds/lib/utilities.dart b/dwds/lib/utilities.dart deleted file mode 100644 index 02e84d8ccd..0000000000 --- a/dwds/lib/utilities.dart +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -export 'src/utilities/ddc_names.dart'; diff --git a/dwds/pubspec.yaml b/dwds/pubspec.yaml deleted file mode 100644 index 04453bf114..0000000000 --- a/dwds/pubspec.yaml +++ /dev/null @@ -1,51 +0,0 @@ -name: dwds -# Every time this changes you need to run `dart run tool/build.dart`. -version: 27.2.0-wip - -description: >- - A service that proxies between the Chrome debug protocol and the Dart VM - service protocol. -repository: https://github.com/dart-lang/webdev/tree/main/dwds -environment: - sdk: ^3.14.0-286.0.dev - -dependencies: - async: ^2.9.0 - collection: ^1.15.0 - crypto: ^3.0.2 - dds: ^5.3.0 - file: ">=6.1.4 <8.0.0" - http: ^1.0.0 - http_multi_server: ^3.2.0 - logging: ^1.0.2 - meta: ^1.9.1 - package_config: '>=2.0.2 <4.0.0' - path: ^1.8.1 - pool: ^1.5.0 - pub_semver: ^2.1.1 - shelf: ^1.3.0 - shelf_proxy: ^1.0.4 - shelf_web_socket: ">=2.0.0 <4.0.0" - source_maps: ^0.10.10 - sse: ^4.2.0 - stack_trace: ^1.10.0 - stream_channel: ^2.1.2 - vm_service: ">=14.2.4 <16.0.0" - vm_service_interface: ^2.0.1 - web_socket: ^1.0.1 - web_socket_channel: ">=2.2.0 <4.0.0" - webkit_inspection_protocol: ^1.0.1 - -dev_dependencies: - args: ^2.7.0 - build_daemon: ^4.1.4 - dart_flutter_team_lints: ^3.5.2 - dwds_test_common: - path: ../dwds_test_common - graphs: ^2.1.0 - io: ^1.0.5 - mime: ^2.0.0 - test: ^1.21.6 - web: ^1.1.0 - webdriver: ^3.0.0 - yaml: ^3.1.3 diff --git a/dwds/test/build/build_script_test.dart b/dwds/test/build/build_script_test.dart deleted file mode 100644 index ced19168a5..0000000000 --- a/dwds/test/build/build_script_test.dart +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:convert'; -import 'dart:io'; - -import 'package:crypto/crypto.dart'; -import 'package:dwds/src/handlers/injected_client_js.dart'; -import 'package:path/path.dart' as p; -import 'package:test/test.dart'; - -import 'test_path_utils.dart'; - -void main() { - group('Committed file integrity tests', () { - test('injected_client_js.dart is in sync with web/client.dart', () async { - final clientDartString = File(await dwdsPath('web/client.dart')) - .readAsStringSync() - .replaceAll('\r\n', '\n'); - final expectedHash = sha256 - .convert(utf8.encode(clientDartString)) - .toString(); - - expect( - clientDartHash, - equals(expectedHash), - reason: - 'The hash of web/client.dart does not match clientDartHash ' - 'in injected_client_js.dart. ' - 'Please run `dart run tool/build.dart` to regenerate the asset.', - ); - }); - - test('injected_client_js.dart has normalized line endings', () { - expect(injectedClientJs.contains('\r'), isFalse); - }); - }); - - group('Build script tests', () { - setUpAll(() async { - // Use Platform.executable to ensure the same Dart SDK is used. Only - // resolve the absolute path if it's a local/relative path. Global - // system commands (no path separators) are passed as-is. - final executable = Platform.executable; - final resolvedExecutable = executable.contains(p.separator) - ? File(executable).absolute.path - : executable; - final result = await Process.run(resolvedExecutable, [ - 'run', - 'tool/build.dart', - ], workingDirectory: await dwdsPackageRoot); - - expect( - result.exitCode, - 0, - reason: 'Build script failed: ${result.stdout}\n${result.stderr}', - ); - }); - - test('generates client.js', () async { - final clientJsFile = File( - await dwdsPath(p.join('lib', 'src', 'injected', 'client.js')), - ); - expect(clientJsFile.existsSync(), isTrue); - expect(clientJsFile.lengthSync(), greaterThan(0)); - }); - - test('generates version.dart', () async { - final versionFile = File( - await dwdsPath(p.join('lib', 'src', 'version.dart')), - ); - expect(versionFile.existsSync(), isTrue); - expect( - versionFile.readAsStringSync(), - contains('const packageVersion ='), - ); - }); - - test('generates injected_client_js.dart', () async { - final injectedFile = File( - await dwdsPath( - p.join('lib', 'src', 'handlers', 'injected_client_js.dart'), - ), - ); - expect(injectedFile.existsSync(), isTrue); - expect(injectedFile.lengthSync(), greaterThan(0)); - }); - - test('injected_client_js.dart matches client.js content', () async { - final clientJsFile = File( - await dwdsPath(p.join('lib', 'src', 'injected', 'client.js')), - ); - final actualClientJs = clientJsFile.readAsStringSync().replaceAll( - '\r\n', - '\n', - ); - - final injectedFile = File( - await dwdsPath( - p.join('lib', 'src', 'handlers', 'injected_client_js.dart'), - ), - ); - final injectedContent = injectedFile.readAsStringSync(); - - final lines = actualClientJs.split('\n'); - final expectedSafeDartString = [ - for (var i = 0; i < lines.length; i++) - jsonEncode(i == lines.length - 1 ? lines[i] : '${lines[i]}\n') - .replaceAll(r'$', r'\$'), - ].join('\n'); - - expect( - injectedContent, - contains('const injectedClientJs = $expectedSafeDartString;'), - ); - }); - }); -} diff --git a/dwds/test/build/ensure_version_test.dart b/dwds/test/build/ensure_version_test.dart deleted file mode 100644 index 1266c6d8fc..0000000000 --- a/dwds/test/build/ensure_version_test.dart +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@TestOn('vm') -library; - -import 'dart:io'; - -import 'package:dwds/src/version.dart'; -import 'package:pub_semver/pub_semver.dart'; -import 'package:test/test.dart'; -import 'package:yaml/yaml.dart'; - -import 'test_path_utils.dart'; - -void main() { - test('dwds lib/src/version.dart matches the pubspec version', () async { - final pubspecPath = await dwdsPath('pubspec.yaml'); - final pubspec = loadYaml(File(pubspecPath).readAsStringSync()) as Map; - expect( - Version.parse(packageVersion), - Version.parse(pubspec['version'] as String), - reason: 'Please run `dart run tool/build.dart` to update the version.', - ); - }); -} diff --git a/dwds/test/build/test_path_utils.dart b/dwds/test/build/test_path_utils.dart deleted file mode 100644 index 5dfb648519..0000000000 --- a/dwds/test/build/test_path_utils.dart +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:isolate'; - -import 'package:path/path.dart' as p; - -/// Returns the path to the `dwds` package root directory. -Future get dwdsPackageRoot async { - final uri = await Isolate.resolvePackageUri( - Uri.parse('package:dwds/dwds.dart'), - ); - if (uri == null) { - throw StateError('Could not resolve package:dwds'); - } - // uri is file:///.../pkg/dwds/lib/dwds.dart - // We need to go up 2 levels to get to pkg/dwds - return p.dirname(p.dirname(uri.toFilePath())); -} - -/// Returns the absolute path to a file or directory relative to the `dwds` -/// package root. -Future dwdsPath(String pathFromDwds) async { - return p.normalize(p.join(await dwdsPackageRoot, pathFromDwds)); -} diff --git a/dwds/test/frontend_server_common/CHANGELOG-legacy.md b/dwds/test/frontend_server_common/CHANGELOG-legacy.md deleted file mode 100644 index b05b83a9f3..0000000000 --- a/dwds/test/frontend_server_common/CHANGELOG-legacy.md +++ /dev/null @@ -1,26 +0,0 @@ -## 0.2.3-wip - -- Update Dart SDK constraint to `^3.10.0`. -- Add bootstrapping code for DDC library bundle format. -- Added scriptUri to compileExpression*Request -- Adding `createReloadedSourceEntry` for sharing reloaded_sources.json entry logic. - -## 0.2.2 - -- Start the frontend server from the AOT snapshot shipped in the Dart SDK. - -## 0.2.1 - -- Doe not pass `-debugger-module-names` flag to the frontend server. - -## 0.2.0 - -- Migrate to null safety - -## 0.1.1 - -- Remove dead code - -## 0.1.0 - -- Initial version diff --git a/dwds/test/frontend_server_common/README.md b/dwds/test/frontend_server_common/README.md deleted file mode 100644 index 61862a5af1..0000000000 --- a/dwds/test/frontend_server_common/README.md +++ /dev/null @@ -1,14 +0,0 @@ -Dart Web Developer Service - -__*Note: Under heavy development.*__ - -This code is an edited copy of flutter code used for setting up frontend server -and components that are needed to communicate to Chrome and dwds: - -- frontend server client -- web runner -- dev fs -- asset server - -This eventually will transform into common code that both flutter and dwds use -for better integration. diff --git a/dwds/test/frontend_server_common/asset_server.dart b/dwds/test/frontend_server_common/asset_server.dart deleted file mode 100644 index ef39ff0b35..0000000000 --- a/dwds/test/frontend_server_common/asset_server.dart +++ /dev/null @@ -1,363 +0,0 @@ -// Copyright 2020 The Dart Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Note: this is a copy from flutter tools, updated to work with dwds tests - -import 'dart:async'; -import 'dart:convert'; -import 'dart:io'; -import 'dart:typed_data'; - -import 'package:dwds/asset_reader.dart'; -import 'package:dwds/config.dart'; -import 'package:dwds_test_common/test_sdk_layout.dart'; -import 'package:file/file.dart'; -import 'package:logging/logging.dart'; -import 'package:mime/mime.dart' as mime; -import 'package:shelf/shelf.dart' as shelf; - -class TestAssetServer implements AssetReader { - late final String _basePath; - final String index; - - final _logger = Logger('TestAssetServer'); - - // Fallback to "application/octet-stream" on null which - // makes no claims as to the structure of the data. - static const String _defaultMimeType = 'application/octet-stream'; - final Uri _projectDirectory; - final FileSystem _fileSystem; - final HttpServer _httpServer; - final Map _files = {}; - final Map _sourceMaps = {}; - final Map _metadata = {}; - late String _mergedMetadata; - final PackageUriMapper _packageUriMapper; - final InternetAddress internetAddress; - final TestSdkLayout _sdkLayout; - - TestAssetServer( - this.index, - this._httpServer, - this._packageUriMapper, - this.internetAddress, - this._projectDirectory, - this._fileSystem, - this._sdkLayout, - ) { - _basePath = _parseBasePathFromIndexHtml(index); - } - - @override - String get basePath => _basePath; - - bool hasFile(String path) => _files.containsKey(path); - Uint8List getFile(String path) => _files[path]!; - - bool hasSourceMap(String path) => _sourceMaps.containsKey(path); - Uint8List getSourceMap(String path) => _sourceMaps[path]!; - - bool hasMetadata(String path) => _metadata.containsKey(path); - Uint8List getMetadata(String path) => _metadata[path]!; - - /// Start the web asset server on a [hostname] and [port]. - /// - /// Unhandled exceptions will throw a exception with the error and stack - /// trace. - static Future start( - String sdkDirectory, - Uri projectDirectory, - FileSystem fileSystem, - String index, - String hostname, - int port, - UrlEncoder? urlTunneler, - PackageUriMapper packageUriMapper, - ) async { - final address = (await InternetAddress.lookup(hostname)).first; - final httpServer = await HttpServer.bind(address, port); - final sdkLayout = TestSdkLayout.createDefault(sdkDirectory); - final server = TestAssetServer( - index, - httpServer, - packageUriMapper, - address, - projectDirectory, - fileSystem, - sdkLayout, - ); - return server; - } - - // handle requests for JavaScript source, dart sources maps, or asset files. - Future handleRequest(shelf.Request request) async { - if (request.method != 'GET') { - // Assets are served via GET only. - return shelf.Response.notFound(''); - } - final requestPath = _stripBasePath(request.url.path, basePath); - if (requestPath == null) { - return shelf.Response.notFound(''); - } - - final headers = {}; - - if (request.url.path.endsWith('.html')) { - final indexFile = _fileSystem.file(_projectDirectory.resolve(index)); - if (indexFile.existsSync()) { - headers[HttpHeaders.contentTypeHeader] = 'text/html'; - headers[HttpHeaders.contentLengthHeader] = indexFile - .lengthSync() - .toString(); - return shelf.Response.ok(indexFile.openRead(), headers: headers); - } - return shelf.Response.notFound(''); - } - - // If this is a JavaScript file, it must be in the in-memory cache. - // Attempt to look up the file by URI. - if (hasFile(requestPath)) { - final List bytes = getFile(requestPath); - headers[HttpHeaders.contentLengthHeader] = bytes.length.toString(); - headers[HttpHeaders.contentTypeHeader] = 'application/javascript'; - return shelf.Response.ok(bytes, headers: headers); - } - // If this is a sourcemap file, then it might be in the in-memory cache. - // Attempt to lookup the file by URI. - if (hasSourceMap(requestPath)) { - final List bytes = getSourceMap(requestPath); - headers[HttpHeaders.contentLengthHeader] = bytes.length.toString(); - headers[HttpHeaders.contentTypeHeader] = 'application/json'; - return shelf.Response.ok(bytes, headers: headers); - } - // If this is a metadata file, then it might be in the in-memory cache. - // Attempt to lookup the file by URI. - if (hasMetadata(requestPath)) { - final List bytes = getMetadata(requestPath); - headers[HttpHeaders.contentLengthHeader] = bytes.length.toString(); - headers[HttpHeaders.contentTypeHeader] = 'application/json'; - return shelf.Response.ok(bytes, headers: headers); - } - - final file = _resolveDartFile(requestPath); - if (!file.existsSync()) { - return shelf.Response.notFound(''); - } - - final length = file.lengthSync(); - // Attempt to determine the file's mime type. if this is not provided some - // browsers will refuse to render images/show video et cetera. If the tool - // cannot determine a mime type, fall back to application/octet-stream. - String? mimeType; - if (length >= 12) { - mimeType = mime.lookupMimeType( - file.path, - headerBytes: await file.openRead(0, 12).first, - ); - } - mimeType ??= _defaultMimeType; - headers[HttpHeaders.contentLengthHeader] = length.toString(); - headers[HttpHeaders.contentTypeHeader] = mimeType; - return shelf.Response.ok(file.openRead(), headers: headers); - } - - /// Tear down the http server running. - @override - Future close() { - return _httpServer.close(); - } - - /// Write a single file into the in-memory cache. - void writeFile(String filePath, String contents) { - _files[filePath] = Uint8List.fromList(utf8.encode(contents)); - } - - /// Update the in-memory asset server with the provided source and manifest - /// files. - /// - /// Returns a list of updated modules. - List write( - File codeFile, - File manifestFile, - File sourcemapFile, - File metadataFile, - ) { - final modules = []; - final codeBytes = codeFile.readAsBytesSync(); - final sourcemapBytes = sourcemapFile.readAsBytesSync(); - final metadataBytes = metadataFile.readAsBytesSync(); - final manifest = _castStringKeyedMap( - json.decode(manifestFile.readAsStringSync()), - ); - for (final filePath in manifest.keys) { - final offsets = _castStringKeyedMap(manifest[filePath]); - final codeOffsets = (offsets['code'] as List).cast(); - final sourcemapOffsets = (offsets['sourcemap'] as List) - .cast(); - final metadataOffsets = (offsets['metadata'] as List) - .cast(); - if (codeOffsets.length != 2 || - sourcemapOffsets.length != 2 || - metadataOffsets.length != 2) { - _logger.severe('Invalid manifest byte offsets: $offsets'); - continue; - } - - final codeStart = codeOffsets[0]; - final codeEnd = codeOffsets[1]; - if (codeStart < 0 || codeEnd > codeBytes.lengthInBytes) { - _logger.severe('Invalid byte index: [$codeStart, $codeEnd]'); - continue; - } - final byteView = Uint8List.view( - codeBytes.buffer, - codeStart, - codeEnd - codeStart, - ); - - final fileName = filePath.startsWith('/') - ? filePath.substring(1) - : filePath; - _files[fileName] = byteView; - - final sourcemapStart = sourcemapOffsets[0]; - final sourcemapEnd = sourcemapOffsets[1]; - if (sourcemapStart < 0 || sourcemapEnd > sourcemapBytes.lengthInBytes) { - _logger.severe('Invalid byte index: [$sourcemapStart, $sourcemapEnd]'); - continue; - } - final sourcemapView = Uint8List.view( - sourcemapBytes.buffer, - sourcemapStart, - sourcemapEnd - sourcemapStart, - ); - _sourceMaps['$fileName.map'] = sourcemapView; - - final metadataStart = metadataOffsets[0]; - final metadataEnd = metadataOffsets[1]; - if (metadataStart < 0 || metadataEnd > metadataBytes.lengthInBytes) { - _logger.severe('Invalid byte index: [$metadataStart, $metadataEnd]'); - continue; - } - final metadataView = Uint8List.view( - metadataBytes.buffer, - metadataStart, - metadataEnd - metadataStart, - ); - _metadata['$fileName.metadata'] = metadataView; - - modules.add(fileName); - } - - _mergedMetadata = _metadata.values - .map((Uint8List encoded) => utf8.decode(encoded)) - .join('\n'); - - return modules; - } - - // Attempt to resolve `path` to a dart file. - File _resolveDartFile(String path) { - // If this is a dart file, it must be on the local file system and is - // likely coming from a source map request. The tool doesn't currently - // consider the case of Dart files as assets. - final dartFile = _fileSystem.file(_projectDirectory.resolve(path)); - if (dartFile.existsSync()) { - return dartFile; - } - - final segments = path.split('/'); - - // The file might have been a package file which is signaled by a - // `/packages//` request. - if (segments.first == 'packages') { - var resolved = _packageUriMapper.serverPathToResolvedUri(path); - if (resolved != null) { - resolved = _projectDirectory.resolveUri(resolved); - } - final packageFile = _fileSystem.file(resolved); - if (packageFile.existsSync()) { - return packageFile; - } - _logger.severe('Package file not found: $path ($packageFile)'); - } - - // Otherwise it must be a Dart SDK source. - final dartSdkParent = _fileSystem.directory(_sdkLayout.sdkDirectory).parent; - final dartSdkFile = _fileSystem.file( - _fileSystem.path.joinAll([dartSdkParent.path, ...segments]), - ); - return dartSdkFile; - } - - @override - Future dartSourceContents(String serverPath) async { - final stripped = _stripBasePath(serverPath, basePath); - if (stripped != null) { - final result = _resolveDartFile(stripped); - if (result.existsSync()) { - return result.readAsString(); - } - } - _logger.severe('Source not found: $serverPath'); - return null; - } - - @override - Future sourceMapContents(String serverPath) async { - final stripped = _stripBasePath(serverPath, basePath); - if (stripped != null) { - if (hasSourceMap(stripped)) { - return utf8.decode(getSourceMap(stripped)); - } - } - _logger.severe('Source map not found: $serverPath'); - return null; - } - - @override - Future metadataContents(String serverPath) async { - final stripped = _stripBasePath(serverPath, basePath); - if (stripped != null) { - if (stripped.endsWith('.ddc_merged_metadata')) { - return _mergedMetadata; - } - if (hasMetadata(stripped)) { - return utf8.decode(getMetadata(stripped)); - } - } - _logger.severe('Metadata not found: $serverPath'); - return null; - } - - String _parseBasePathFromIndexHtml(String index) { - final file = _fileSystem.file(_projectDirectory.resolve(index)); - if (!file.existsSync()) { - throw StateError('Index file $index is not found'); - } - final contents = file.readAsStringSync(); - final matches = RegExp(r'').allMatches(contents); - if (matches.isEmpty) return ''; - return matches.first.group(1) ?? ''; - } - - String? _stripBasePath(String path, String basePath) { - path = stripLeadingSlashes(path); - if (path.startsWith(basePath)) { - path = path.substring(basePath.length); - } else { - // The given path isn't under base path, return null to indicate that. - _logger.severe('Path is not under $basePath: $path'); - return null; - } - return stripLeadingSlashes(path); - } -} - -/// Given a data structure which is a Map of String to dynamic values, return -/// the same structure (`Map`) with the correct runtime types. -Map _castStringKeyedMap(dynamic untyped) { - final map = untyped as Map; - return map.cast(); -} diff --git a/dwds/test/frontend_server_common/bootstrap.dart b/dwds/test/frontend_server_common/bootstrap.dart deleted file mode 100644 index 8efe76ec57..0000000000 --- a/dwds/test/frontend_server_common/bootstrap.dart +++ /dev/null @@ -1,573 +0,0 @@ -// Copyright 2020 The Dart Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'dart:io' show Platform; - -// Note: this is a copy from flutter tools, updated to work with dwds tests - -/// JavaScript snippet to determine the base URL of the current path. -const String _baseUrlScript = ''' -var baseUrl = (function () { - // Attempt to detect --precompiled mode for tests, and set the base url - // appropriately, otherwise set it to '/'. - var pathParts = location.pathname.split("/"); - if (pathParts[0] == "") { - pathParts.shift(); - } - if (pathParts.length > 1 && pathParts[1] == "test") { - return "/" + pathParts.slice(0, 2).join("/") + "/"; - } - // Attempt to detect base url using html tag - // base href should start and end with "/" - if (typeof document !== 'undefined') { - var el = document.getElementsByTagName('base'); - if (el && el[0] && el[0].getAttribute("href") && el[0].getAttribute - ("href").startsWith("/") && el[0].getAttribute("href").endsWith("/")){ - return el[0].getAttribute("href"); - } - } - // return default value - return "/"; -}()); -var _trimmedBaseUrl = baseUrl.endsWith('/') ? baseUrl.substring(0, baseUrl.length - 1) : baseUrl; -var _currentDirectory = window.location.origin + _trimmedBaseUrl; -'''; - -/// Used to load prerequisite scripts such as ddc_module_loader.js -const String _simpleLoaderScript = r''' -window.$dartCreateScript = (function() { - // Find the nonce value. (Note, this is only computed once.) - var scripts = Array.from(document.getElementsByTagName("script")); - var nonce; - scripts.some( - script => (nonce = script.nonce || script.getAttribute("nonce"))); - // If present, return a closure that automatically appends the nonce. - if (nonce) { - return function() { - var script = document.createElement("script"); - script.nonce = nonce; - return script; - }; - } else { - return function() { - return document.createElement("script"); - }; - } -})(); - -// Loads a module [relativeUrl] relative to [root]. -// -// If not specified, [root] defaults to the directory serving the main app. -var forceLoadModule = function (relativeUrl, root) { - var actualRoot = root ?? _currentDirectory; - var trimmedRoot = actualRoot.endsWith('/') ? actualRoot.substring(0, actualRoot.length - 1) : actualRoot; - return new Promise(function(resolve, reject) { - var script = self.$dartCreateScript(); - let policy = { - createScriptURL: function(src) {return src;} - }; - if (self.trustedTypes && self.trustedTypes.createPolicy) { - policy = self.trustedTypes.createPolicy('dartDdcModuleUrl', policy); - } - script.onload = resolve; - script.onerror = reject; - script.src = policy.createScriptURL(trimmedRoot + "/" + relativeUrl); - document.head.appendChild(script); - }); -}; -'''; - -/// The JavaScript bootstrap script to support in-browser hot restart. -/// -/// The [requireUrl] loads our cached RequireJS script file. The [mapperUrl] -/// loads the special Dart stack trace mapper. The [entrypoint] is the -/// actual main.dart file. -/// -/// This file is served when the browser requests "main.dart.js" in debug mode, -/// and is responsible for bootstrapping the RequireJS modules and attaching -/// the hot reload hooks. -String generateBootstrapScript({ - required String requireUrl, - required String mapperUrl, - required String entrypoint, -}) { - return ''' -"use strict"; - -// Attach source mapping. -var mapperEl = document.createElement("script"); -mapperEl.defer = true; -mapperEl.async = false; -mapperEl.src = "$mapperUrl"; -document.head.appendChild(mapperEl); - -// Attach require JS. -var requireEl = document.createElement("script"); -requireEl.defer = true; -requireEl.async = false; -requireEl.src = "$requireUrl"; -// This attribute tells require JS what to load as main (defined below). -requireEl.setAttribute("data-main", "main_module.bootstrap"); -document.head.appendChild(requireEl); -'''; -} - -/// Generate a synthetic main module which captures the application's main -/// method. -/// -/// RE: Object.keys usage in app.main: -/// This attaches the main entrypoint and hot reload functionality to the -/// window. The app module will have a single property which contains the -/// actual application code. The property name is based off of the entrypoint -/// that is generated, for example the file `foo/bar/baz.dart` will generate a -/// property named approximately `foo__bar__baz`. Rather than attempt to guess, -/// we assume the first property of this object is the module. -String generateMainModule({required String entrypoint}) { - return '''/* ENTRYPOINT_EXTENTION_MARKER */ - -// Create the main module loaded below. -define("main_module.bootstrap", ["$entrypoint", "dart_sdk"], function(app, dart_sdk) { - dart_sdk._isolate_helper.startRootIsolate(() => {}, []); - dart_sdk._debugger.registerDevtoolsFormatter(); - let voidToNull = () => (voidToNull = dart_sdk.dart.constFn(dart_sdk.dart.fnType(dart_sdk.core.Null, [dart_sdk.dart.void])))(); - - // See the generateMainModule doc comment. - var child = {}; - child.main = app[Object.keys(app)[0]].main; - - /* MAIN_EXTENSION_MARKER */ - child.main(); -}); -'''; -} - -String generateDDCBootstrapScript({ - required String ddcModuleLoaderUrl, - required String mapperUrl, - required String entrypoint, - required String bootstrapUrl, -}) { - return ''' -$_baseUrlScript -$_simpleLoaderScript - -(function() { - let appName = "$entrypoint"; - - // A uuid that identifies a subapp. - let uuid = "00000000-0000-0000-0000-000000000000"; - - window.postMessage( - {type: "DDC_STATE_CHANGE", state: "initial_load", targetUuid: uuid}, "*"); - - // Load pre-requisite DDC scripts. We intentionally use invalid names to avoid namespace clashes. - let prerequisiteScripts = [ - { - "src": "$ddcModuleLoaderUrl", - "id": "dart_library \x00" - }, - { - "src": "$mapperUrl", - "id": "dart_stack_trace_mapper \x00" - } - ]; - - // Load ddc_module_loader.js to access DDC's module loader API. - let prerequisiteLoads = []; - for (let i = 0; i < prerequisiteScripts.length; i++) { - prerequisiteLoads.push(forceLoadModule(prerequisiteScripts[i].src)); - } - Promise.all(prerequisiteLoads).then((_) => afterPrerequisiteLogic()); - - // Save the current script so we can access it in a closure. - var _currentScript = document.currentScript; - - var afterPrerequisiteLogic = function() { - window.\$dartLoader.rootDirectories.push(_currentDirectory); - let scripts = [ - { - "src": "dart_sdk.js", - "id": "dart_sdk" - }, - { - "src": "$bootstrapUrl", - "id": "data-main" - } - ]; - let loadConfig = new window.\$dartLoader.LoadConfiguration(); - loadConfig.root = _currentDirectory; - loadConfig.bootstrapScript = scripts[scripts.length - 1]; - - if (window.\$dartJITModules) { - loadConfig.loadScriptFn = function(loader) { - // Loads just the entrypoint module and required SDK modules. - let moduleSet = new Set(); - // This cache is populated by ddc_module_loader.js - let libraryCache = JSON.parse(window.localStorage.getItem(`dartLibraryCache:\${appName}`)); - if (libraryCache) { - // TODO(b/165021238) - when should this be invalidated? - moduleSet = new Set(libraryCache["modules"]) - } - loader.addScriptsToQueue(scripts, function(script) { - // Preemptively load the ddc module loader and previously executed modules. - return moduleSet.size == 0 - || script.id.includes("dart_library") - // We preemptively load the stack_trace_mapper module so that we can - // translate JS errors to Dart. - || script.id.includes("stack_trace_mapper") - || moduleSet.has(script.id); - }); - loader.loadEnqueuedModules(); - } - loadConfig.ddcEventForLoadStart = /* LOAD_ENTRYPOINT_MODULES_START */ 4; - loadConfig.ddcEventForLoadedOk = /* LOAD_ENTRYPOINT_MODULES_END_OK */ 5; - loadConfig.ddcEventForLoadedError = /* LOAD_ENTRYPOINT_MODULES_END_ERROR */ 6; - } else { - loadConfig.loadScriptFn = function(loader) { - loader.addScriptsToQueue(scripts, null); - loader.loadEnqueuedModules(); - } - loadConfig.ddcEventForLoadStart = /* LOAD_ALL_MODULES_START */ 1; - loadConfig.ddcEventForLoadedOk = /* LOAD_ALL_MODULES_END_OK */ 2; - loadConfig.ddcEventForLoadedError = /* LOAD_ALL_MODULES_END_ERROR */ 3; - } - - let loader = new window.\$dartLoader.DDCLoader(loadConfig); - - // Record prerequisite scripts' fully resolved URLs. - prerequisiteScripts.forEach(script => loader.registerScript(script)); - - // Note: these variables should only be used in non-multi-app scenarios since - // they can be arbitrarily overridden based on multi-app load order. - window.\$dartLoader.loadConfig = loadConfig; - window.\$dartLoader.loader = loader; - loader.nextAttempt(); - - let currentUri = _currentScript.src; - let fetchEtagsUri; - if (currentUri.indexOf("?") == -1) { - fetchEtagsUri = currentUri + "?fetch-etags=true"; - } else { - fetchEtagsUri = currentUri + "&fetch-etags=true"; - } - - if (!window.\$dartAppNameToMetadata) { - window.\$dartAppNameToMetadata = new Map(); - } - window.\$dartAppNameToMetadata.set(appName, { - currentDirectory: _currentDirectory, - currentUri: currentUri, - fetchEtagsUri: fetchEtagsUri, - }); - - if (!window.\$dartReloadModifiedModules) { - window.\$dartReloadModifiedModules = (function(appName, callback) { - function cb() { - window.postMessage( - { - type: "DDC_STATE_CHANGE", - state: "restart_end", - targetUuid: uuid, - }, - "*"); - callback(); - } - window.postMessage( - { - type: "DDC_STATE_CHANGE", - state: "restart_begin", - targetUuid: uuid, - }, - "*"); - var xhttp = new XMLHttpRequest(); - xhttp.withCredentials = true; - xhttp.onreadystatechange = function() { - // https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/readyState - if (this.readyState == 4 && this.status == 200 || this.status == 304) { - var scripts = JSON.parse(this.responseText); - var numToLoad = 0; - var numLoaded = 0; - for (var i = 0; i < scripts.length; i++) { - var script = scripts[i]; - if (script.id == null) continue; - var src = - window.\$dartAppNameToMetadata.get(appName).currentDirectory + - script.src.toString(); - var oldSrc = window.\$dartLoader.moduleIdToUrl.get(script.id); - // Only compare the search parameters which contain the cache - // busting portion of the uri. The path might be different if the - // script is loaded from a different application on the page. - if (new URL(oldSrc).search == new URL(src).search) continue; - - // We might actually load from a different uri, delete the old one - // just to be sure. - window.\$dartLoader.urlToModuleId.delete(oldSrc); - - window.\$dartLoader.moduleIdToUrl.set(script.id, src); - window.\$dartLoader.urlToModuleId.set(src, script.id); - - if (window.\$dartJITModules) { - // Simply invalidate the import and the corresponding module will - // be lazily loaded. - dart_library.invalidateImport(script.id); - continue; - } else { - numToLoad++; - } - - var el = document.getElementById(script.id); - if (el) el.remove(); - el = window.\$dartCreateScript(); - el.src = policy.createScriptURL(src); - el.async = false; - el.defer = true; - el.id = script.id; - el.onload = function() { - numLoaded++; - if (numToLoad == numLoaded) cb(); - }; - document.head.appendChild(el); - } - // Call `cb` right away if we found no updated scripts. - if (numToLoad == 0) cb(); - } - }; - xhttp.open("GET", - window.\$dartAppNameToMetadata.get(appName).fetchEtagsUri, true); - let sdk = dart_library.import("dart_sdk", appName); - let developer = sdk.developer; - if (developer._extensions.containsKey("ext.flutter.disassemble")) { - developer.invokeExtension("ext.flutter.disassemble", "{}").then(() => { - // TODO(b/204210914): we should really be clearing all statics for all - // apps, but for now we just do it for flutter apps which we recognize - // based on this extension. - sdk.dart.hotRestart(); - xhttp.send(); - }); - } else { - xhttp.send(); - } - }); - } - } -})(); -'''; -} - -String generateDDCMainModule({ - required String entrypoint, - String? exportedMain, -}) { - final exportedMainName = exportedMain ?? entrypoint.split('.')[0]; - return '''/* ENTRYPOINT_EXTENTION_MARKER */ - -(function() { - let appName = "$entrypoint"; - - // A uuid that identifies a subapp. - let uuid = "00000000-0000-0000-0000-000000000000"; - - let dart_sdk = dart_library.import('dart_sdk', appName); - - dart_sdk._debugger.registerDevtoolsFormatter(); - dart_sdk._isolate_helper.startRootIsolate(() => {}, []); - - let child = {}; - child.main = function() { - dart_library.start(appName, uuid, "$entrypoint", "$exportedMainName"); - } - - /* MAIN_EXTENSION_MARKER */ - child.main(); -})(); -'''; -} - -String generateDDCLibraryBundleBootstrapScript({ - required String ddcModuleLoaderUrl, - required String mapperUrl, - required String entrypoint, - required String bootstrapUrl, -}) { - return ''' -$_baseUrlScript -$_simpleLoaderScript - -(function() { - let appName = "org-dartlang-app:/$entrypoint"; - - // Load pre-requisite DDC scripts. We intentionally use invalid names to avoid - // namespace clashes. - let prerequisiteScripts = [ - { - "src": "$ddcModuleLoaderUrl", - "id": "ddc_module_loader \x00" - }, - { - "src": "$mapperUrl", - "id": "dart_stack_trace_mapper \x00" - } - ]; - - // Load ddc_module_loader.js to access DDC's module loader API. - let prerequisiteLoads = []; - for (let i = 0; i < prerequisiteScripts.length; i++) { - prerequisiteLoads.push(forceLoadModule(prerequisiteScripts[i].src)); - } - Promise.all(prerequisiteLoads).then((_) => afterPrerequisiteLogic()); - - // Save the current script so we can access it in a closure. - var _currentScript = document.currentScript; - - // Create a policy if needed to load the files during a hot restart. - let policy = { - createScriptURL: function(src) {return src;} - }; - if (self.trustedTypes && self.trustedTypes.createPolicy) { - policy = self.trustedTypes.createPolicy('dartDdcModuleUrl', policy); - } - - var afterPrerequisiteLogic = function() { - window.\$dartLoader.rootDirectories.push(_currentDirectory); - let scripts = [ - { - "src": "dart_sdk.js", - "id": "dart_sdk" - }, - { - "src": "$bootstrapUrl", - "id": "data-main" - } - ]; - - let loadConfig = new window.\$dartLoader.LoadConfiguration(); - loadConfig.root = _currentDirectory; - - // TODO(srujzs): Verify this is sufficient for Windows. - loadConfig.isWindows = ${Platform.isWindows}; - loadConfig.bootstrapScript = scripts[scripts.length - 1]; - - loadConfig.loadScriptFn = function(loader) { - loader.addScriptsToQueue(scripts, null); - loader.loadEnqueuedModules(); - } - loadConfig.ddcEventForLoadStart = /* LOAD_ALL_MODULES_START */ 1; - loadConfig.ddcEventForLoadedOk = /* LOAD_ALL_MODULES_END_OK */ 2; - loadConfig.ddcEventForLoadedError = /* LOAD_ALL_MODULES_END_ERROR */ 3; - - let loader = new window.\$dartLoader.DDCLoader(loadConfig); - - // Record prerequisite scripts' fully resolved URLs. - prerequisiteScripts.forEach(script => loader.registerScript(script)); - - // Note: these variables should only be used in non-multi-app scenarios - // since they can be arbitrarily overridden based on multi-app load order. - window.\$dartLoader.loadConfig = loadConfig; - window.\$dartLoader.loader = loader; - - // Begin loading libraries - loader.nextAttempt(); - - // Set up stack trace mapper. - if (window.\$dartStackTraceUtility && - !window.\$dartStackTraceUtility.ready) { - window.\$dartStackTraceUtility.ready = true; - window.\$dartStackTraceUtility.setSourceMapProvider(function(url) { - var baseUrl = window.location.protocol + '//' + window.location.host; - url = url.replace(baseUrl + '/', ''); - if (url == 'dart_sdk.js') { - return dartDevEmbedder.debugger.getSourceMap('dart_sdk'); - } - url = url.replace(".lib.js", "").replace(".ddc.js", ""); - return dartDevEmbedder.debugger.getSourceMap(url); - }); - } - - if (!window.\$dartReloadModifiedModules) { - window.\$dartReloadModifiedModules = (function(filesToReload, appName) { - return new Promise(function(resolve) { - function callback() { - resolve(filesToReload); - } - let numToLoad = 0; - let numLoaded = 0; - for (let i = 0; i < filesToReload.length; i++) { - const file = filesToReload[i]; - const module = file.module; - if (module == null) continue; - const src = file.src; - const oldSrc = window.\$dartLoader.moduleIdToUrl.get(module); - - // We might actually load from a different uri, delete the old one - // just to be sure. - window.\$dartLoader.urlToModuleId.delete(oldSrc); - - window.\$dartLoader.moduleIdToUrl.set(module, src); - window.\$dartLoader.urlToModuleId.set(src, module); - - numToLoad++; - - let el = document.getElementById(module); - if (el) el.remove(); - el = window.\$dartCreateScript(); - el.src = policy.createScriptURL(src); - el.async = false; - el.defer = true; - el.id = module; - el.onload = function() { - numLoaded++; - if (numToLoad == numLoaded) callback(); - }; - document.head.appendChild(el); - } - // Call `callback` right away if we found no updated scripts. - if (numToLoad == 0) callback(); - }); - }); - } - }; -})(); -'''; -} - -const String _onLoadEndCallback = r'$onLoadEndCallback'; - -String generateDDCLibraryBundleMainModule({ - required String entrypoint, - required String onLoadEndBootstrap, -}) { - // The typo below in "EXTENTION" is load-bearing, package:build depends on it. - return ''' -/* ENTRYPOINT_EXTENTION_MARKER */ - -(function() { - let appName = "org-dartlang-app:///$entrypoint"; - - dartDevEmbedder.debugger.registerDevtoolsFormatter(); - - // Set up a final script that lets us know when all scripts have been loaded. - // Only then can we call the main method. - let onLoadEndSrc = '$onLoadEndBootstrap'; - window.\$dartLoader.loadConfig.bootstrapScript = { - src: onLoadEndSrc, - id: onLoadEndSrc, - }; - window.\$dartLoader.loadConfig.tryLoadBootstrapScript = true; - // Should be called by $onLoadEndBootstrap once all the scripts have been - // loaded. - window.$_onLoadEndCallback = function() { - let child = {}; - child.main = function() { - dartDevEmbedder.runMain(appName, {}); - } - /* MAIN_EXTENSION_MARKER */ - child.main(); - } -})(); -'''; -} - -String generateDDCLibraryBundleOnLoadEndBootstrap() { - return '''window.$_onLoadEndCallback();'''; -} diff --git a/dwds/test/frontend_server_common/devfs.dart b/dwds/test/frontend_server_common/devfs.dart deleted file mode 100644 index 1f7c018145..0000000000 --- a/dwds/test/frontend_server_common/devfs.dart +++ /dev/null @@ -1,394 +0,0 @@ -// Copyright 2020 The Dart Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Note: this is a copy from flutter tools, updated to work with dwds tests - -import 'dart:convert'; -import 'dart:io'; - -import 'package:dwds/asset_reader.dart'; -import 'package:dwds/config.dart'; -import 'package:dwds/expression_compiler.dart'; -// ignore: implementation_imports -import 'package:dwds/src/debugging/metadata/module_metadata.dart'; -import 'package:dwds/utilities.dart'; -import 'package:dwds_test_common/test_sdk_layout.dart'; -import 'package:file/file.dart'; -import 'package:path/path.dart' as p; - -import 'asset_server.dart'; -import 'bootstrap.dart'; -import 'frontend_server_client.dart'; - -class WebDevFS { - WebDevFS({ - required this.fileSystem, - required this.hostname, - required this.port, - required this.projectDirectory, - required this.packageUriMapper, - required this.index, - this.urlTunneler, - required this.sdkLayout, - required this.compilerOptions, - }); - - final FileSystem fileSystem; - late final TestAssetServer assetServer; - final String hostname; - final int port; - final Uri projectDirectory; - final PackageUriMapper packageUriMapper; - final String index; - final UrlEncoder? urlTunneler; - List sources = []; - DateTime? lastCompiled; - - final TestSdkLayout sdkLayout; - final CompilerOptions compilerOptions; - - Future create() async { - assetServer = await TestAssetServer.start( - sdkLayout.sdkDirectory, - projectDirectory, - fileSystem, - index, - hostname, - port, - urlTunneler, - packageUriMapper, - ); - return Uri.parse('http://$hostname:$port'); - } - - Future dispose() { - return assetServer.close(); - } - - Future update({ - required Uri mainUri, - required String dillOutputPath, - required ResidentCompiler generator, - required List invalidatedFiles, - required bool initialCompile, - required bool fullRestart, - // The uri of the `HttpServer` that handles file requests. - // TODO(srujzs): This should be the same as the uri of the AssetServer to - // align with Flutter tools, but currently is not. Delete when that's fixed. - required Uri? fileServerUri, - }) async { - final mainPath = mainUri.toFilePath(); - final outputDirectory = fileSystem.directory( - fileSystem.file(projectDirectory.resolve(mainPath)).parent.path, - ); - final entryPoint = mainUri.toString(); - - var prefix = ''; - // If base path is not overwritten, use main's subdirectory - // to store all files, so the paths match the requests. - if (assetServer.basePath.isEmpty) { - final directory = p.dirname(entryPoint); - prefix = '$directory/'; - } - - if (initialCompile) { - final ddcModuleLoader = '${prefix}ddc_module_loader.js'; - final require = '${prefix}require.js'; - final stackMapper = '${prefix}stack_trace_mapper.js'; - final main = '${prefix}main.dart.js'; - final bootstrap = '${prefix}main_module.bootstrap.js'; - - assetServer.writeFile( - entryPoint, - fileSystem.file(projectDirectory.resolve(mainPath)).readAsStringSync(), - ); - assetServer.writeFile(stackMapper, stackTraceMapper.readAsStringSync()); - - switch (ddcModuleFormat) { - case ModuleFormat.amd: - assetServer.writeFile(require, requireJS.readAsStringSync()); - assetServer.writeFile( - main, - generateBootstrapScript( - requireUrl: 'require.js', - mapperUrl: 'stack_trace_mapper.js', - entrypoint: entryPoint, - ), - ); - assetServer.writeFile( - bootstrap, - generateMainModule(entrypoint: entryPoint), - ); - break; - case ModuleFormat.ddc: - assetServer.writeFile( - ddcModuleLoader, - ddcModuleLoaderJS.readAsStringSync(), - ); - String bootstrapper; - String mainModule; - if (compilerOptions.canaryFeatures) { - bootstrapper = generateDDCLibraryBundleBootstrapScript( - ddcModuleLoaderUrl: ddcModuleLoader, - mapperUrl: stackMapper, - entrypoint: entryPoint, - bootstrapUrl: bootstrap, - ); - const onLoadEndBootstrap = 'on_load_end_bootstrap.js'; - assetServer.writeFile( - onLoadEndBootstrap, - generateDDCLibraryBundleOnLoadEndBootstrap(), - ); - mainModule = generateDDCLibraryBundleMainModule( - entrypoint: entryPoint, - onLoadEndBootstrap: onLoadEndBootstrap, - ); - } else { - bootstrapper = generateDDCBootstrapScript( - ddcModuleLoaderUrl: ddcModuleLoader, - mapperUrl: stackMapper, - entrypoint: entryPoint, - bootstrapUrl: bootstrap, - ); - - // DDC uses a simple heuristic to determine exported identifier - // names. The module name (entrypoint name here) has its extension - // removed, and special path elements like '/', '\', and '..' are - // replaced with - // '__'. - final exportedMainName = pathToJSIdentifier( - entryPoint.split('.')[0], - ); - mainModule = generateDDCMainModule( - entrypoint: entryPoint, - exportedMain: exportedMainName, - ); - } - assetServer.writeFile(main, bootstrapper); - assetServer.writeFile(bootstrap, mainModule); - break; - default: - throw Exception('Unsupported DDC module format $ddcModuleFormat.'); - } - - assetServer.writeFile('main_module.digests', '{}'); - // Write an empty array of scripts to reload to handle the case where - // a test triggers a hot restart before any other action. - assetServer.writeFile('reloaded_sources.json', '[]'); - - final sdk = dartSdk; - final sdkSourceMap = dartSdkSourcemap; - assetServer.writeFile('dart_sdk.js', sdk.readAsStringSync()); - assetServer.writeFile('dart_sdk.js.map', sdkSourceMap.readAsStringSync()); - generator.reset(); - } - - final compilerOutput = await generator.recompile( - Uri.parse('org-dartlang-app:///$mainUri'), - invalidatedFiles, - outputPath: p.join(dillOutputPath, 'app.dill'), - packageConfig: packageUriMapper.packageConfig, - recompileRestart: fullRestart, - ); - if (compilerOutput == null || compilerOutput.errorCount > 0) { - return UpdateFSReport(success: false); - } - sources = compilerOutput.sources; - lastCompiled = DateTime.now(); - - File codeFile; - File manifestFile; - File sourcemapFile; - File metadataFile; - List modules; - try { - codeFile = outputDirectory.childFile( - '${compilerOutput.outputFilename}.sources', - ); - manifestFile = outputDirectory.childFile( - '${compilerOutput.outputFilename}.json', - ); - sourcemapFile = outputDirectory.childFile( - '${compilerOutput.outputFilename}.map', - ); - metadataFile = outputDirectory.childFile( - '${compilerOutput.outputFilename}.metadata', - ); - modules = assetServer.write( - codeFile, - manifestFile, - sourcemapFile, - metadataFile, - ); - } on FileSystemException catch (err) { - throw Exception('Failed to load recompiled sources:\n$err'); - } - if (ddcModuleFormat == ModuleFormat.ddc && - compilerOptions.canaryFeatures && - !initialCompile) { - writeReloadedSources(modules, fileServerUri!); - } - return UpdateFSReport( - success: true, - syncedBytes: codeFile.lengthSync(), - invalidatedSourcesCount: invalidatedFiles.length, - )..invalidatedModules = modules; - } - - static const String reloadedSourcesFileName = 'reloaded_sources.json'; - - /// Given a list of [modules] that need to be reloaded during a hot restart or - /// hot reload, writes a file that contains a list of objects each with three - /// fields: - /// - /// `src`: A string that corresponds to the file path containing a DDC library - /// bundle. - /// `module`: The name of the library bundle in `src`. - /// `libraries`: An array of strings containing the libraries that were - /// compiled in `src`. - /// - /// For example: - /// ```json - /// [ - /// { - /// "src": "/", - /// "module": "", - /// "libraries": ["", ""], - /// }, - /// ] - /// ``` - /// - /// The path of the output file should stay consistent across the lifetime of - /// the app. - void writeReloadedSources(List modules, Uri fileServerUri) { - final moduleToLibrary = >[]; - for (final module in modules) { - final metadata = ModuleMetadata.fromJson( - json.decode( - utf8.decode(assetServer.getMetadata('$module.metadata').toList()), - ) as Map, - ); - final libraries = metadata.libraries.keys.toList(); - moduleToLibrary.add( - createReloadedSourceEntry( - src: '$fileServerUri/$module', - module: metadata.name, - libraries: libraries, - ), - ); - } - assetServer.writeFile( - reloadedSourcesFileName, - json.encode(moduleToLibrary), - ); - } - - static Map createReloadedSourceEntry({ - required String src, - required String module, - required List libraries, - }) => {'src': src, 'module': module, 'libraries': libraries}; - - File get ddcModuleLoaderJS => - fileSystem.file(sdkLayout.ddcModuleLoaderJsPath); - File get requireJS => fileSystem.file(sdkLayout.requireJsPath); - File get dartSdk => fileSystem.file(switch (ddcModuleFormat) { - ModuleFormat.amd => sdkLayout.amdJsPath, - ModuleFormat.ddc => sdkLayout.ddcJsPath, - _ => throw Exception('Unsupported DDC module format $ddcModuleFormat.'), - }); - File get dartSdkSourcemap => fileSystem.file(switch (ddcModuleFormat) { - ModuleFormat.amd => sdkLayout.amdJsMapPath, - ModuleFormat.ddc => sdkLayout.ddcJsMapPath, - _ => throw Exception('Unsupported DDC module format $ddcModuleFormat.'), - }); - File get stackTraceMapper => fileSystem.file(sdkLayout.stackTraceMapperPath); - ModuleFormat get ddcModuleFormat => compilerOptions.moduleFormat; -} - -class UpdateFSReport { - final bool _success; - final int _invalidatedSourcesCount; - final int _syncedBytes; - - UpdateFSReport({ - this._success = false, - this._invalidatedSourcesCount = 0, - this._syncedBytes = 0, - }); - - bool get success => _success; - int get invalidatedSourcesCount => _invalidatedSourcesCount; - int get syncedBytes => _syncedBytes; - - /// JavaScript modules produced by the incremental compiler in `dartdevc` - /// mode. - /// - /// Only used for JavaScript compilation. - List? invalidatedModules; -} - -/// The result of an invalidation check from [ProjectFileInvalidator]. -class InvalidationResult { - const InvalidationResult({this.uris}); - - final List? uris; -} - -/// The [ProjectFileInvalidator] track the dependencies for a running -/// application to determine when they are dirty. -class ProjectFileInvalidator { - ProjectFileInvalidator({required this._fileSystem}); - - final FileSystem _fileSystem; - - static const String _pubCachePathLinuxAndMac = '.pub-cache'; - static const String _pubCachePathWindows = 'Pub/Cache'; - - Future findInvalidated({ - required DateTime? lastCompiled, - required List urisToMonitor, - required String packagesPath, - }) async { - if (lastCompiled == null) { - // Initial load. - assert(urisToMonitor.isEmpty); - return const InvalidationResult(uris: []); - } - - final urisToScan = [ - // Don't watch pub cache directories to speed things up a little. - for (final Uri uri in urisToMonitor) - if (_isNotInPubCache(uri)) uri, - ]; - final invalidatedFiles = []; - for (final uri in urisToScan) { - // Calling fs.statSync() is more performant than fs.file().statSync(), - // but uri.toFilePath() does not work with MultiRootFileSystem. - final updatedAt = uri.hasScheme && uri.scheme != 'file' - ? _fileSystem.file(uri).statSync().modified - : _fileSystem - .statSync(uri.toFilePath(windows: Platform.isWindows)) - .modified; - if (updatedAt.isAfter(lastCompiled)) { - invalidatedFiles.add(uri); - } - } - // We need to check the .dart_tool/package_config.json file too since it is - // not used in compilation. - final packageFile = _fileSystem.file(packagesPath); - final packageUri = packageFile.uri; - final updatedAt = packageFile.statSync().modified; - if (updatedAt.isAfter(lastCompiled)) { - invalidatedFiles.add(packageUri); - } - - return InvalidationResult(uris: invalidatedFiles); - } - - bool _isNotInPubCache(Uri uri) { - return !(Platform.isWindows && uri.path.contains(_pubCachePathWindows)) && - !uri.path.contains(_pubCachePathLinuxAndMac); - } -} diff --git a/dwds/test/frontend_server_common/frontend_server_client.dart b/dwds/test/frontend_server_common/frontend_server_client.dart deleted file mode 100644 index b2b13c605f..0000000000 --- a/dwds/test/frontend_server_common/frontend_server_client.dart +++ /dev/null @@ -1,728 +0,0 @@ -// Copyright 2020 The Dart Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Note: this is a copy from flutter tools, updated to work with dwds tests - -import 'dart:async'; -import 'dart:convert'; -import 'dart:io'; - -import 'package:dwds/expression_compiler.dart'; -import 'package:dwds_test_common/test_sdk_layout.dart'; -import 'package:logging/logging.dart'; -import 'package:package_config/package_config.dart'; - -import 'utilities.dart'; -import 'uuid.dart'; - -Logger _logger = Logger('FrontendServerClient'); -Logger _serverLogger = Logger('FrontendServer'); - -void defaultConsumer(String message, {StackTrace? stackTrace}) => - stackTrace == null - ? _serverLogger.info(message) - : _serverLogger.severe(message, null, stackTrace); - -typedef CompilerMessageConsumer = void Function( - String message, { - StackTrace stackTrace, -}); - -class CompilerOutput { - const CompilerOutput(this.outputFilename, this.errorCount, this.sources); - - final String outputFilename; - final int errorCount; - final List sources; -} - -enum StdoutState { collectDiagnostic, collectDependencies } - -/// Handles stdin/stdout communication with the frontend server. -class StdoutHandler { - StdoutHandler({required this.consumer}) { - reset(); - } - - final CompilerMessageConsumer consumer; - late Completer compilerOutput; - - final List _sources = []; - - bool _compilerMessageReceived = false; - String? _boundaryKey; - StdoutState _state = StdoutState.collectDiagnostic; - late bool _suppressCompilerMessages; - late bool _expectSources; - bool _badState = false; - - void handler(String message) { - if (message.startsWith('Observatory listening')) { - stderr.writeln(message); - return; - } - if (message.startsWith('Observatory server failed')) { - throw Exception(message); - } - if (_badState) { - return; - } - final kResultPrefix = 'result '; - if (_boundaryKey == null && message.startsWith(kResultPrefix)) { - _boundaryKey = message.substring(kResultPrefix.length); - return; - } - // Invalid state, see commented issue below for more information. - // NB: both the completeError and _badState flags are required to avoid - // filling the console with exceptions. - if (_boundaryKey == null) { - // Throwing a synchronous exception via throwToolExit will fail to cancel - // the stream. Instead use completeError so that the error is returned - // from the awaited future that the compiler consumers are expecting. - compilerOutput.completeError( - 'Frontend server tests encountered an internal problem. ' - 'This can be caused by printing to stdout into the stream that is ' - 'used for communication between frontend server (in sdk) or ' - 'frontend server client (in dwds tests).' - '\n\n' - 'Additional debugging information:\n' - ' StdoutState: $_state\n' - ' compilerMessageReceived: $_compilerMessageReceived\n' - ' message: $message\n' - ' _expectSources: $_expectSources\n' - ' sources: $_sources\n', - ); - // There are several event turns before the tool actually exits from a - // tool exception. Normally, the stream should be cancelled to prevent - // more events from entering the bad state, but because the error - // is coming from handler itself, there is no clean way to pipe this - // through. Instead, we set a flag to prevent more messages from - // registering. - _badState = true; - return; - } - final boundaryKey = _boundaryKey!; - if (message.startsWith(boundaryKey)) { - if (_expectSources) { - if (_state == StdoutState.collectDiagnostic) { - _state = StdoutState.collectDependencies; - return; - } - } - if (message.length <= boundaryKey.length) { - compilerOutput.complete(null); - return; - } - final spaceDelimiter = message.lastIndexOf(' '); - compilerOutput.complete( - CompilerOutput( - message.substring(boundaryKey.length + 1, spaceDelimiter), - int.parse(message.substring(spaceDelimiter + 1).trim()), - _sources, - ), - ); - return; - } - if (_state == StdoutState.collectDiagnostic) { - if (!_suppressCompilerMessages) { - if (_compilerMessageReceived == false) { - consumer('\nCompiler message:'); - _compilerMessageReceived = true; - } - consumer(message); - } - } else { - assert(_state == StdoutState.collectDependencies); - switch (message[0]) { - case '+': - _sources.add(Uri.parse(message.substring(1))); - break; - case '-': - _sources.remove(Uri.parse(message.substring(1))); - break; - default: - _logger.warning('Unexpected prefix for $message uri - ignoring'); - } - } - } - - // This is needed to get ready to process next compilation result output, - // with its own boundary key and new completer. - void reset({ - bool suppressCompilerMessages = false, - bool expectSources = true, - }) { - _boundaryKey = null; - _compilerMessageReceived = false; - compilerOutput = Completer(); - _suppressCompilerMessages = suppressCompilerMessages; - _expectSources = expectSources; - _state = StdoutState.collectDiagnostic; - } -} - -/// Class that allows to serialize compilation requests to the compiler. -abstract class _CompilationRequest { - _CompilationRequest(this.completer); - - Completer completer; - - Future _run(ResidentCompiler compiler); - - Future run(ResidentCompiler compiler) async { - completer.complete(await _run(compiler)); - } -} - -class _RecompileRequest extends _CompilationRequest { - _RecompileRequest( - super.completer, - this.mainUri, - this.invalidatedFiles, - this.outputPath, - this.packageConfig, { - required this.recompileRestart, - }); - - Uri mainUri; - List invalidatedFiles; - String outputPath; - PackageConfig packageConfig; - bool recompileRestart; - - @override - Future _run(ResidentCompiler compiler) async => - compiler._recompile(this); -} - -class _CompileExpressionRequest extends _CompilationRequest { - _CompileExpressionRequest( - super.completer, - this.expression, - this.definitions, - this.typeDefinitions, - this.libraryUri, - this.scriptUri, - this.klass, - this.isStatic, - ); - - String expression; - List definitions; - List typeDefinitions; - String? libraryUri; - String? scriptUri; - String? klass; - bool? isStatic; - - @override - Future _run(ResidentCompiler compiler) async => - compiler._compileExpression(this); -} - -class _CompileExpressionToJsRequest extends _CompilationRequest { - _CompileExpressionToJsRequest( - super.completer, - this.libraryUri, - this.scriptUri, - this.line, - this.column, - this.jsModules, - this.jsFrameValues, - this.moduleName, - this.expression, - ); - - String libraryUri; - String scriptUri; - int line; - int column; - Map jsModules; - Map jsFrameValues; - String moduleName; - String expression; - - @override - Future _run(ResidentCompiler compiler) async => - compiler._compileExpressionToJs(this); -} - -class _RejectRequest extends _CompilationRequest { - _RejectRequest(super.completer); - - @override - Future _run(ResidentCompiler compiler) async => - compiler._reject(); -} - -/// Wrapper around incremental frontend server compiler, that communicates with -/// server via stdin/stdout. -/// -/// The wrapper is intended to stay resident in memory as user changes, reloads, -/// restarts the Flutter app. -class ResidentCompiler { - ResidentCompiler( - this.sdkRoot, { - required this.projectDirectory, - required this.packageConfigFile, - required this.useDebuggerModuleNames, - required this.fileSystemRoots, - required this.fileSystemScheme, - required this.platformDill, - required this.compilerOptions, - required this.sdkLayout, - this.verbose = false, - CompilerMessageConsumer compilerMessageConsumer = defaultConsumer, - }) : _stdoutHandler = StdoutHandler(consumer: compilerMessageConsumer); - - final Uri projectDirectory; - final Uri packageConfigFile; - final bool useDebuggerModuleNames; - final List fileSystemRoots; - final String fileSystemScheme; - final String platformDill; - final TestSdkLayout sdkLayout; - final CompilerOptions compilerOptions; - final bool verbose; - - /// The path to the root of the Dart SDK used to compile. - final String sdkRoot; - - Process? _server; - final StdoutHandler _stdoutHandler; - bool _compileRequestNeedsConfirmation = false; - - final StreamController<_CompilationRequest> _controller = - StreamController<_CompilationRequest>(); - - /// If invoked for the first time, it compiles Dart script identified by - /// [mainUri], [invalidatedFiles] list is ignored. - /// On successive runs [invalidatedFiles] indicates which files need to be - /// recompiled. If [mainUri] is null, previously used [mainUri] entry - /// point that is used for recompilation. - /// Binary file name is returned if compilation was successful, otherwise - /// null is returned. - /// If [recompileRestart] is true, uses the `recompile-restart` instruction - /// instead of `recompile`. - Future recompile( - Uri mainUri, - List invalidatedFiles, { - required String outputPath, - required PackageConfig packageConfig, - required bool recompileRestart, - }) async { - if (!_controller.hasListener) { - _controller.stream.listen(_handleCompilationRequest); - } - - final completer = Completer(); - _controller.add( - _RecompileRequest( - completer, - mainUri, - invalidatedFiles, - outputPath, - packageConfig, - recompileRestart: recompileRestart, - ), - ); - return completer.future; - } - - Future _recompile(_RecompileRequest request) async { - _stdoutHandler.reset(); - - final mainUri = - request.packageConfig.toPackageUri(request.mainUri)?.toString() ?? - _toMultiRootPath(request.mainUri, fileSystemScheme, fileSystemRoots); - - _compileRequestNeedsConfirmation = true; - - if (_server == null) { - return _compile(mainUri, request.outputPath); - } - final server = _server!; - - final inputKey = generateV4UUID(); - final instruction = request.recompileRestart - ? 'recompile-restart' - : 'recompile'; - server.stdin.writeln('$instruction $mainUri $inputKey'); - _logger.info('<- $instruction $mainUri $inputKey'); - for (final fileUri in request.invalidatedFiles) { - String message; - if (fileUri.scheme == 'package') { - message = fileUri.toString(); - } else { - message = - request.packageConfig.toPackageUri(fileUri)?.toString() ?? - _toMultiRootPath(fileUri, fileSystemScheme, fileSystemRoots); - } - server.stdin.writeln(message); - _logger.info(message); - } - server.stdin.writeln(inputKey); - _logger.info('<- $inputKey'); - - return _stdoutHandler.compilerOutput.future; - } - - final List<_CompilationRequest> _compilationQueue = <_CompilationRequest>[]; - - Future _handleCompilationRequest(_CompilationRequest request) async { - final isEmpty = _compilationQueue.isEmpty; - _compilationQueue.add(request); - // Only trigger processing if queue was empty - i.e. no other requests - // are currently being processed. This effectively enforces "one - // compilation request at a time". - if (isEmpty) { - while (_compilationQueue.isNotEmpty) { - final request = _compilationQueue.first; - await request.run(this); - _compilationQueue.removeAt(0); - } - } - } - - Future _compile( - String scriptUri, - String outputFilePath, - ) async { - final frontendServer = sdkLayout.frontendServerSnapshotPath; - final args = [ - frontendServer, - '--sdk-root', - sdkRoot, - '--incremental', - '--target=dartdevc', - '-Ddart.developer.causal_async_stacks=true', - '--output-dill', - outputFilePath, - ...['--packages', '$packageConfigFile'], - for (final root in fileSystemRoots) ...[ - '--filesystem-root', - '$root', - ], - ...['--filesystem-scheme', fileSystemScheme], - ...['--platform', platformDill], - if (useDebuggerModuleNames) '--debugger-module-names', - '--experimental-emit-debug-metadata', - for (final experiment in compilerOptions.experiments) - '--enable-experiment=$experiment', - if (compilerOptions.canaryFeatures) '--dartdevc-canary', - if (verbose) '--verbose', - if (compilerOptions.moduleFormat == ModuleFormat.ddc) - '--dartdevc-module-format=ddc', - ]; - _logger.info(args.join(' ')); - final workingDirectory = projectDirectory.toFilePath(); - _server = await Process.start( - sdkLayout.dartAotRuntimePath, - args, - workingDirectory: workingDirectory, - ); - - final server = _server!; - server.stdout - .transform(utf8.decoder) - .transform(const LineSplitter()) - .listen( - _stdoutHandler.handler, - onDone: () { - // when outputFilename future is not completed, but stdout is closed - // process has died unexpectedly. - if (!_stdoutHandler.compilerOutput.isCompleted) { - _stdoutHandler.compilerOutput.complete(null); - throw Exception('the Dart compiler exited unexpectedly.'); - } - }, - ); - - server.stderr - .transform(utf8.decoder) - .transform(const LineSplitter()) - .listen(_logger.info); - - unawaited( - server.exitCode.then((int code) { - if (code != 0) { - throw Exception('the Dart compiler exited unexpectedly.'); - } - }), - ); - - server.stdin.writeln('compile $scriptUri'); - _logger.info('<- compile $scriptUri'); - - return _stdoutHandler.compilerOutput.future; - } - - /// Compile dart expression to kernel. - Future compileExpression( - String expression, - List definitions, - List typeDefinitions, - String libraryUri, - String scriptUri, - String klass, - bool isStatic, - ) { - if (!_controller.hasListener) { - _controller.stream.listen(_handleCompilationRequest); - } - - final completer = Completer(); - _controller.add( - _CompileExpressionRequest( - completer, - expression, - definitions, - typeDefinitions, - libraryUri, - scriptUri, - klass, - isStatic, - ), - ); - return completer.future; - } - - Future _compileExpression( - _CompileExpressionRequest request, - ) async { - _stdoutHandler.reset(suppressCompilerMessages: true, expectSources: false); - - // 'compile-expression' should be invoked after compiler has been started, - // program was compiled. - if (_server == null) { - return null; - } - final server = _server!; - - final inputKey = generateV4UUID(); - server.stdin.writeln('compile-expression $inputKey'); - server.stdin.writeln(request.expression); - request.definitions.forEach(server.stdin.writeln); - server.stdin.writeln(inputKey); - request.typeDefinitions.forEach(server.stdin.writeln); - server.stdin.writeln(inputKey); - server.stdin.writeln(request.libraryUri ?? ''); - server.stdin.writeln(request.klass ?? ''); - server.stdin.writeln(request.isStatic ?? false); - - return _stdoutHandler.compilerOutput.future; - } - - /// Compiles dart expression to JavaScript. - Future compileExpressionToJs( - String libraryUri, - String scriptUri, - int line, - int column, - Map jsModules, - Map jsFrameValues, - String moduleName, - String expression, - ) { - if (!_controller.hasListener) { - _controller.stream.listen(_handleCompilationRequest); - } - - final completer = Completer(); - _controller.add( - _CompileExpressionToJsRequest( - completer, - libraryUri, - scriptUri, - line, - column, - jsModules, - jsFrameValues, - moduleName, - expression, - ), - ); - return completer.future; - } - - Future _compileExpressionToJs( - _CompileExpressionToJsRequest request, - ) async { - _stdoutHandler.reset( - suppressCompilerMessages: !verbose, - expectSources: false, - ); - - // Compiling an expression should happen after the compiler has been - // started and the program was compiled. - if (_server == null) { - return null; - } - final server = _server!; - - server.stdin.writeln('JSON_INPUT'); - server.stdin.writeln( - json.encode({ - 'type': 'COMPILE_EXPRESSION_JS', - 'data': { - 'expression': request.expression, - 'libraryUri': request.libraryUri, - 'scriptUri': request.scriptUri, - 'line': request.line, - 'column': request.column, - 'jsModules': request.jsModules, - 'jsFrameValues': request.jsFrameValues, - 'moduleName': request.moduleName, - }, - }), - ); - - return _stdoutHandler.compilerOutput.future; - } - - /// Should be invoked when results of compilation are accepted by the client. - /// - /// Either [accept] or [reject] should be called after every [recompile] call. - void accept() { - if (_compileRequestNeedsConfirmation) { - _server!.stdin.writeln('accept'); - _logger.info('<- accept'); - } - _compileRequestNeedsConfirmation = false; - } - - /// Should be invoked when results of compilation are rejected by the client. - /// - /// Either [accept] or [reject] should be called after every [recompile] call. - Future reject() { - if (!_controller.hasListener) { - _controller.stream.listen(_handleCompilationRequest); - } - - final completer = Completer(); - _controller.add(_RejectRequest(completer)); - return completer.future; - } - - Future _reject() { - if (!_compileRequestNeedsConfirmation) { - return Future.value(null); - } - _stdoutHandler.reset(expectSources: false); - _server!.stdin.writeln('reject'); - _logger.info('<- reject'); - _compileRequestNeedsConfirmation = false; - return _stdoutHandler.compilerOutput.future; - } - - /// Should be invoked when frontend server compiler should forget what was - /// accepted previously so that next call to [recompile] produces complete - /// kernel file. - void reset() { - // TODO(annagrin): make sure this works when we support hot restart in - // tests using frontend server - for example, throw an error if the - // server is not available. - _server?.stdin.writeln('reset'); - _logger.info('<- reset'); - } - - Future quit() async { - _server?.stdin.writeln('quit'); - _logger.info('<- quit'); - - if (_server == null) { - return 0; - } - return _server!.exitCode; - } - - /// stop the service normally - Future shutdown() async { - // Server was never successfully created. - if (_server == null) { - return 0; - } - return quit(); - } - - /// kill the service - Future kill() async { - if (_server == null) { - return 0; - } - - final server = _server!; - _logger.info('killing pid ${server.pid}'); - server.kill(); - return server.exitCode; - } -} - -class TestExpressionCompiler implements ExpressionCompiler { - final ResidentCompiler _generator; - TestExpressionCompiler(this._generator); - - @override - Future compileExpressionToJs( - String isolateId, - String libraryUri, - String scriptUri, - int line, - int column, - Map jsModules, - Map jsFrameValues, - String moduleName, - String expression, - ) async { - final compilerOutput = await _generator.compileExpressionToJs( - libraryUri, - scriptUri, - line, - column, - jsModules, - jsFrameValues, - moduleName, - expression, - ); - - if (compilerOutput != null) { - final content = utf8.decode( - localFileSystem.file(compilerOutput.outputFilename).readAsBytesSync(), - ); - return ExpressionCompilationResult( - content, - compilerOutput.errorCount > 0, - ); - } - - throw Exception('Failed to compile $expression'); - } - - @override - Future updateDependencies(Map modules) async => - true; - - @override - Future initialize(CompilerOptions options) async {} -} - -/// Convert a file URI into a multi-root scheme URI if provided, otherwise -/// return unmodified. -String _toMultiRootPath( - Uri fileUri, - String? scheme, - List fileSystemRoots, -) { - if (scheme == null || fileSystemRoots.isEmpty || fileUri.scheme != 'file') { - return fileUri.toString(); - } - final filePath = fileUri.toFilePath(windows: Platform.isWindows); - for (final fileSystemRoot in fileSystemRoots) { - final rootPath = fileSystemRoot.toFilePath(windows: Platform.isWindows); - if (filePath.startsWith(rootPath)) { - return '$scheme:///${filePath.substring(rootPath.length)}'; - } - } - return fileUri.toString(); -} diff --git a/dwds/test/frontend_server_common/resident_runner.dart b/dwds/test/frontend_server_common/resident_runner.dart deleted file mode 100644 index 905d7c61db..0000000000 --- a/dwds/test/frontend_server_common/resident_runner.dart +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright 2020 The Dart Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Note: this is a copy from flutter tools, updated to work with dwds tests, -// and some functionality removed (does not support hot reload yet) - -import 'dart:async'; - -import 'package:dwds/asset_reader.dart'; -import 'package:dwds/config.dart'; -import 'package:dwds/expression_compiler.dart'; -import 'package:dwds_test_common/test_sdk_layout.dart'; -import 'package:file/file.dart'; -import 'package:logging/logging.dart'; - -import 'devfs.dart'; -import 'frontend_server_client.dart'; - -class ResidentWebRunner { - final _logger = Logger('ResidentWebRunner'); - - ResidentWebRunner({ - required this.mainUri, - required this.urlTunneler, - required this.projectDirectory, - required this.packageConfigFile, - required this.packageUriMapper, - required this.fileSystemRoots, - required this.fileSystemScheme, - required this.outputPath, - required this.compilerOptions, - required this.sdkLayout, - bool verbose = false, - }) { - final platformDillUri = Uri.file(sdkLayout.summaryPath); - - generator = ResidentCompiler( - sdkLayout.sdkDirectory, - projectDirectory: projectDirectory, - packageConfigFile: packageConfigFile, - useDebuggerModuleNames: packageUriMapper.useDebuggerModuleNames, - platformDill: '$platformDillUri', - fileSystemRoots: fileSystemRoots, - fileSystemScheme: fileSystemScheme, - compilerOptions: compilerOptions, - sdkLayout: sdkLayout, - verbose: verbose, - ); - expressionCompiler = TestExpressionCompiler(generator); - } - - final UrlEncoder? urlTunneler; - final Uri mainUri; - final Uri projectDirectory; - final Uri packageConfigFile; - final PackageUriMapper packageUriMapper; - final String outputPath; - final List fileSystemRoots; - final String fileSystemScheme; - final CompilerOptions compilerOptions; - final TestSdkLayout sdkLayout; - - late ResidentCompiler generator; - late ExpressionCompiler expressionCompiler; - ProjectFileInvalidator? _projectFileInvalidator; - WebDevFS? devFS; - Uri? uri; - - Future run( - FileSystem fileSystem, { - String? hostname, - required int port, - required String index, - }) async { - _projectFileInvalidator ??= ProjectFileInvalidator(fileSystem: fileSystem); - devFS ??= WebDevFS( - fileSystem: fileSystem, - hostname: hostname ?? 'localhost', - port: port, - projectDirectory: projectDirectory, - packageUriMapper: packageUriMapper, - index: index, - urlTunneler: urlTunneler, - sdkLayout: sdkLayout, - compilerOptions: compilerOptions, - ); - uri ??= await devFS!.create(); - - final report = await _updateDevFS( - initialCompile: true, - fullRestart: false, - fileServerUri: null, - ); - if (!report.success) { - _logger.severe('Failed to compile application.'); - return 1; - } - - generator.accept(); - return 0; - } - - Future rerun({ - required bool fullRestart, - // The uri of the `HttpServer` that handles file requests. - // TODO(srujzs): This should be the same as the uri of the AssetServer to - // align with Flutter tools, but currently is not. Delete when that's fixed. - required Uri fileServerUri, - }) async { - final report = await _updateDevFS( - initialCompile: false, - fullRestart: fullRestart, - fileServerUri: fileServerUri, - ); - if (!report.success) { - _logger.severe('Failed to compile application.'); - return 1; - } - - generator.accept(); - return 0; - } - - Future _updateDevFS({ - required bool initialCompile, - required bool fullRestart, - // The uri of the `TestServer` that handles file requests. - // TODO(srujzs): This should be the same as the uri of the AssetServer to - // align with Flutter tools, but currently is not. Delete when that's fixed. - required Uri? fileServerUri, - }) async { - final invalidationResult = await _projectFileInvalidator!.findInvalidated( - lastCompiled: devFS!.lastCompiled, - urisToMonitor: devFS!.sources, - packagesPath: packageConfigFile.toFilePath(), - ); - final report = await devFS!.update( - mainUri: mainUri, - dillOutputPath: outputPath, - generator: generator, - invalidatedFiles: invalidationResult.uris!, - initialCompile: initialCompile, - fullRestart: fullRestart, - fileServerUri: fileServerUri, - ); - return report; - } - - Future stop() async { - await generator.shutdown(); - await devFS!.dispose(); - } -} diff --git a/dwds/test/frontend_server_common/utilities.dart b/dwds/test/frontend_server_common/utilities.dart deleted file mode 100644 index eddc3b40ac..0000000000 --- a/dwds/test/frontend_server_common/utilities.dart +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'package:file/file.dart' as fs; -import 'package:file/local.dart'; - -const fs.FileSystem localFileSystem = LocalFileSystem(); diff --git a/dwds/test/frontend_server_common/uuid.dart b/dwds/test/frontend_server_common/uuid.dart deleted file mode 100644 index b375a98a1b..0000000000 --- a/dwds/test/frontend_server_common/uuid.dart +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:math' show Random; - -/// A UUID generator. -/// -/// The generated values are 128 bit numbers encoded in a specific string -/// format. -/// -/// Generate a version 4 (random) uuid. This is a uuid scheme that only uses -/// random numbers as the source of the generated uuid. -String generateV4UUID() { - final special = 8 + _random.nextInt(4); - - return '${_bitsDigits(16, 4)}${_bitsDigits(16, 4)}-' - '${_bitsDigits(16, 4)}-' - '4${_bitsDigits(12, 3)}-' - '${_printDigits(special, 1)}${_bitsDigits(12, 3)}-' - '${_bitsDigits(16, 4)}${_bitsDigits(16, 4)}${_bitsDigits(16, 4)}'; -} - -final Random _random = Random(); - -String _bitsDigits(int bitCount, int digitCount) => - _printDigits(_generateBits(bitCount), digitCount); - -int _generateBits(int bitCount) => _random.nextInt(1 << bitCount); - -String _printDigits(int value, int count) => - value.toRadixString(16).padLeft(count, '0'); diff --git a/dwds/test/integration/breakpoint_common.dart b/dwds/test/integration/breakpoint_common.dart deleted file mode 100644 index 88dea2d2a9..0000000000 --- a/dwds/test/integration/breakpoint_common.dart +++ /dev/null @@ -1,248 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'package:dwds_test_common/logging.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; -import 'package:vm_service/vm_service.dart'; -import 'package:vm_service_interface/vm_service_interface.dart'; - -import 'fixtures/context.dart'; -import 'fixtures/project.dart'; -import 'fixtures/utilities.dart'; - -void testBreakpoint({ - required TestSdkConfigurationProvider provider, - required CompilationMode compilationMode, - bool verboseCompiler = false, -}) { - final context = TestContext(TestProject.testPackage(), provider); - - group('shared context', () { - setUpAll(() async { - setCurrentLogWriter(debug: provider.verbose); - await context.setUp( - testSettings: TestSettings( - compilationMode: compilationMode, - verboseCompiler: verboseCompiler, - canaryFeatures: provider.canaryFeatures, - moduleFormat: provider.ddcModuleFormat, - ), - ); - }); - - tearDownAll(() async { - await context.tearDown(); - }); - - group('breakpoint', () { - VM vm; - late Isolate isolate; - late String isolateId; - ScriptList scripts; - late ScriptRef mainScript; - late String mainScriptUri; - late Stream stream; - late VmServiceInterface service; - - setUp(() async { - service = context.service; - setCurrentLogWriter(debug: provider.verbose); - vm = await service.getVM(); - isolate = await service.getIsolate(vm.isolates!.first.id!); - isolateId = isolate.id!; - scripts = await service.getScripts(isolateId); - - await service.streamListen('Debug'); - stream = service.onEvent('Debug'); - - mainScript = scripts.scripts!.firstWhere( - (each) => each.uri!.contains('main.dart'), - ); - mainScriptUri = mainScript.uri!; - }); - - tearDown(() async { - // We must resume execution in case a test left the isolate paused, but - // error 106 is expected if the isolate is already running. - try { - await service.resume(isolateId); - } on RPCError catch (e) { - if (e.code != 106) rethrow; - } - }); - - test('set breakpoint', () async { - final line = await context.findBreakpointLine( - 'printLocal', - isolateId, - mainScript, - ); - final bp = await service.addBreakpointWithScriptUri( - isolateId, - mainScriptUri, - line, - ); - - await stream.firstWhere( - (Event event) => event.kind == EventKind.kPauseBreakpoint, - ); - - expect(bp, isNotNull); - - // Remove breakpoint so it doesn't impact other tests. - await service.removeBreakpoint(isolateId, bp.id!); - }); - - test('set breakpoint again', () async { - final line = await context.findBreakpointLine( - 'printLocal', - isolateId, - mainScript, - ); - final bp = await service.addBreakpointWithScriptUri( - isolateId, - mainScriptUri, - line, - ); - - await stream.firstWhere( - (Event event) => event.kind == EventKind.kPauseBreakpoint, - ); - - expect(bp, isNotNull); - - // Remove breakpoint so it doesn't impact other tests. - await service.removeBreakpoint(isolateId, bp.id!); - }); - - test('set existing breakpoint succeeds', () async { - final line = await context.findBreakpointLine( - 'printLocal', - isolateId, - mainScript, - ); - final bp1 = await service.addBreakpointWithScriptUri( - isolateId, - mainScriptUri, - line, - ); - final bp2 = await service.addBreakpointWithScriptUri( - isolateId, - mainScriptUri, - line, - ); - - expect(bp1, equals(bp2)); - expect(bp1, isNotNull); - - await stream.firstWhere( - (Event event) => event.kind == EventKind.kPauseBreakpoint, - ); - - var currentIsolate = await service.getIsolate(isolateId); - expect(currentIsolate.breakpoints, containsAll([bp1])); - - // Remove breakpoint so it doesn't impact other tests. - await service.removeBreakpoint(isolateId, bp1.id!); - - currentIsolate = await service.getIsolate(isolateId); - expect(currentIsolate.breakpoints, isEmpty); - }); - - test( - 'set breakpoints at the same line simultaneously succeeds', - () async { - final line = await context.findBreakpointLine( - 'printLocal', - isolateId, - mainScript, - ); - final futures = [ - service.addBreakpointWithScriptUri(isolateId, mainScriptUri, line), - service.addBreakpointWithScriptUri(isolateId, mainScriptUri, line), - ]; - - final breakpoints = await Future.wait(futures); - expect(breakpoints[0], equals(breakpoints[1])); - expect(breakpoints[0], isNotNull); - - await stream.firstWhere( - (Event event) => event.kind == EventKind.kPauseBreakpoint, - ); - - var currentIsolate = await service.getIsolate(isolateId); - expect(currentIsolate.breakpoints, containsAll([breakpoints[0]])); - - // Remove breakpoint so it doesn't impact other tests. - await service.removeBreakpoint(isolateId, breakpoints[0].id!); - - currentIsolate = await service.getIsolate(isolateId); - expect(currentIsolate.breakpoints, isEmpty); - }, - ); - - test('remove non-existing breakpoint fails', () async { - final line = await context.findBreakpointLine( - 'printLocal', - isolateId, - mainScript, - ); - final bp = await service.addBreakpointWithScriptUri( - isolateId, - mainScriptUri, - line, - ); - - await stream.firstWhere( - (Event event) => event.kind == EventKind.kPauseBreakpoint, - ); - - var currentIsolate = await service.getIsolate(isolateId); - expect(currentIsolate.breakpoints, containsAll([bp])); - - // Remove breakpoint so it doesn't impact other tests. - await service.removeBreakpoint(isolateId, bp.id!); - await expectLater( - service.removeBreakpoint(isolateId, bp.id!), - throwsRPCError, - ); - - currentIsolate = await service.getIsolate(isolateId); - expect(currentIsolate.breakpoints, isEmpty); - }); - - test('set breakpoint inside a JavaScript line succeeds', () async { - final line = await context.findBreakpointLine( - 'printNestedObjectMultiLine', - isolateId, - mainScript, - ); - final column = 0; - final bp = await service.addBreakpointWithScriptUri( - isolateId, - mainScriptUri, - line, - column: column, - ); - - await stream.firstWhere( - (Event event) => event.kind == EventKind.kPauseBreakpoint, - ); - - expect(bp, isNotNull); - expect( - bp.location, - isA() - .having((loc) => loc.script, 'script', equals(mainScript)) - .having((loc) => loc.line, 'line', equals(line)) - .having((loc) => loc.column, 'column', greaterThan(column)), - ); - - // Remove breakpoint so it doesn't impact other tests. - await service.removeBreakpoint(isolateId, bp.id!); - }); - }); - }); -} diff --git a/dwds/test/integration/callstack_common.dart b/dwds/test/integration/callstack_common.dart deleted file mode 100644 index e0782f6e4e..0000000000 --- a/dwds/test/integration/callstack_common.dart +++ /dev/null @@ -1,327 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'package:dwds_test_common/logging.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; -import 'package:vm_service/vm_service.dart'; -import 'package:vm_service_interface/vm_service_interface.dart'; - -import 'fixtures/context.dart'; -import 'fixtures/project.dart'; -import 'fixtures/utilities.dart'; - -void testCallStack({ - required TestSdkConfigurationProvider provider, - required CompilationMode compilationMode, - bool verboseCompiler = false, -}) { - final project = TestProject.testPackage(); - final context = TestContext(project, provider); - - group('shared context |', () { - setUpAll(() async { - setCurrentLogWriter(debug: provider.verbose); - await context.setUp( - testSettings: TestSettings( - compilationMode: compilationMode, - enableExpressionEvaluation: true, - verboseCompiler: verboseCompiler, - moduleFormat: provider.ddcModuleFormat, - canaryFeatures: provider.canaryFeatures, - ), - ); - }); - - tearDownAll(() async { - await context.tearDown(); - }); - - group('callStack |', () { - late VmServiceInterface service; - VM vm; - late Isolate isolate; - late String isolateId; - ScriptList scripts; - late ScriptRef mainScript; - late ScriptRef testLibraryScript; - late Stream stream; - - setUp(() async { - setCurrentLogWriter(debug: provider.verbose); - service = context.service; - vm = await service.getVM(); - isolate = await service.getIsolate(vm.isolates!.first.id!); - isolateId = isolate.id!; - scripts = await service.getScripts(isolateId); - - await service.streamListen('Debug'); - stream = service.onEvent('Debug'); - - final testPackage = project.packageName; - mainScript = scripts.scripts!.firstWhere( - (each) => each.uri!.contains('main.dart'), - ); - testLibraryScript = scripts.scripts!.firstWhere( - (each) => - each.uri!.contains('package:$testPackage/test_library.dart'), - ); - }); - - tearDown(() async { - try { - await service.resume(isolateId); - } catch (_) {} - }); - - Future onBreakPoint( - BreakpointTestData breakpoint, - Future Function() body, - ) async { - Breakpoint? bp; - try { - final bpId = breakpoint.bpId; - final script = breakpoint.script; - final line = await context.findBreakpointLine( - bpId, - isolateId, - script, - ); - bp = await context.service.addBreakpointWithScriptUri( - isolateId, - script.uri!, - line, - ); - - expect(bp, isNotNull); - expect(bp.location, _matchBpLocation(script, line, 0)); - - await stream.firstWhere( - (Event event) => event.kind == EventKind.kPauseBreakpoint, - ); - - await body(); - } finally { - // Remove breakpoint so it doesn't impact other tests or retries. - if (bp != null) { - await context.service.removeBreakpoint(isolateId, bp.id!); - } - } - } - - Future testCallStack( - List breakpoints, { - int frameIndex = 1, - }) async { - // Find lines the breakpoints are located on. - final lines = await Future.wait( - breakpoints.map( - (frame) => - context.findBreakpointLine(frame.bpId, isolateId, frame.script), - ), - ); - - // Get current stack. - final stack = await service.getStack(isolateId); - - // Verify the stack is correct. - expect(stack.frames!.length, greaterThanOrEqualTo(lines.length)); - final expected = [ - for (var i = 0; i < lines.length; i++) - _matchFrame( - breakpoints[i].script, - breakpoints[i].function, - lines[i], - ), - ]; - expect(stack.frames, containsAll(expected)); - - // Verify that expression evaluation is not failing. - final instance = await service.evaluateInFrame( - isolateId, - frameIndex, - 'true', - ); - expect(instance, isA()); - } - - test('breakpoint succeeds with correct callstack', () async { - // Expected breakpoints on the stack - final breakpoints = [ - BreakpointTestData( - 'printEnclosingObject', - 'printEnclosingObject', - mainScript, - ), - BreakpointTestData( - 'printEnclosingFunctionMultiLine', - 'printNestedObjectsMultiLine', - mainScript, - ), - BreakpointTestData( - 'callPrintEnclosingFunctionMultiLine', - '', - mainScript, - ), - ]; - await onBreakPoint(breakpoints[0], () => testCallStack(breakpoints)); - }); - - test('expression evaluation succeeds on parent frame', () async { - // Expected breakpoints on the stack - final breakpoints = [ - BreakpointTestData( - 'testLibraryClassConstructor', - 'new', - testLibraryScript, - ), - BreakpointTestData( - 'createLibraryObject', - 'printFieldFromLibraryClass', - mainScript, - ), - BreakpointTestData( - 'callPrintFieldFromLibraryClass', - '', - mainScript, - ), - ]; - await onBreakPoint( - breakpoints[0], - () => testCallStack(breakpoints, frameIndex: 2), - ); - }); - - test('breakpoint inside a line gives correct callstack', () async { - // Expected breakpoints on the stack - final breakpoints = [ - BreakpointTestData('newEnclosedClass', 'new', mainScript), - BreakpointTestData( - 'printNestedObjectMultiLine', - 'printNestedObjectsMultiLine', - mainScript, - ), - BreakpointTestData( - 'callPrintEnclosingFunctionMultiLine', - '', - mainScript, - ), - ]; - await onBreakPoint(breakpoints[0], () => testCallStack(breakpoints)); - }); - - test('breakpoint gives correct callstack after step out', () async { - // Expected breakpoints on the stack - final breakpoints = [ - BreakpointTestData('newEnclosedClass', 'new', mainScript), - BreakpointTestData( - 'printEnclosingObjectMultiLine', - 'printNestedObjectsMultiLine', - mainScript, - ), - BreakpointTestData( - 'callPrintEnclosingFunctionMultiLine', - '', - mainScript, - ), - ]; - await onBreakPoint(breakpoints[0], () async { - await service.resume(isolateId, step: 'Out'); - await stream.firstWhere( - (Event event) => event.kind == EventKind.kPauseInterrupted, - ); - return testCallStack([breakpoints[1], breakpoints[2]]); - }); - }); - - test('breakpoint gives correct callstack after step in', () async { - // Expected breakpoints on the stack - final breakpoints = [ - BreakpointTestData('newEnclosedClass', 'new', mainScript), - BreakpointTestData( - 'printNestedObjectMultiLine', - 'printNestedObjectsMultiLine', - mainScript, - ), - BreakpointTestData( - 'callPrintEnclosingFunctionMultiLine', - '', - mainScript, - ), - ]; - await onBreakPoint(breakpoints[1], () async { - await service.resume(isolateId, step: 'Into'); - await stream.firstWhere( - (Event event) => event.kind == EventKind.kPauseInterrupted, - ); - return testCallStack(breakpoints); - }); - }); - - test( - 'breakpoint gives correct callstack after step into chain calls', - () async { - // Expected breakpoints on the stack - final breakpoints = [ - BreakpointTestData( - 'createObjectWithMethod', - 'createObject', - mainScript, - ), - BreakpointTestData( - // This is currently incorrect, should be printObjectMultiLine. - // See issue: https://github.com/dart-lang/sdk/issues/48874 - 'printMultiLine', - 'printObjectMultiLine', - mainScript, - ), - BreakpointTestData( - 'callPrintObjectMultiLine', - '', - mainScript, - ), - ]; - final bp = BreakpointTestData( - 'printMultiLine', - 'printObjectMultiLine', - mainScript, - ); - await onBreakPoint(bp, () async { - await service.resume(isolateId, step: 'Into'); - await stream.firstWhere( - (Event event) => event.kind == EventKind.kPauseInterrupted, - ); - return testCallStack(breakpoints); - }); - }, - ); - }); - }); -} - -Matcher _matchFrame(ScriptRef script, String function, int line) => isA() - .having((frame) => frame.code!.name, 'function', function) - .having( - (frame) => frame.location, - 'location', - _matchFrameLocation(script, line), - ); - -Matcher _matchBpLocation(ScriptRef script, int line, int column) => - isA() - .having((loc) => loc.script, 'script', equals(script)) - .having((loc) => loc.line, 'line', equals(line)) - .having((loc) => loc.column, 'column', greaterThanOrEqualTo(column)); - -Matcher _matchFrameLocation(ScriptRef script, int line) => isA() - .having((loc) => loc.script, 'script', equals(script)) - .having((loc) => loc.line, 'line', equals(line)); - -class BreakpointTestData { - String bpId; - String function; - ScriptRef script; - - BreakpointTestData(this.bpId, this.function, this.script); -} diff --git a/dwds/test/integration/chrome_proxy_service_ddc_library_bundle_test.dart b/dwds/test/integration/chrome_proxy_service_ddc_library_bundle_test.dart deleted file mode 100644 index fa577f8939..0000000000 --- a/dwds/test/integration/chrome_proxy_service_ddc_library_bundle_test.dart +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@TestOn('vm') -@Tags(['daily']) -@Timeout(Duration(minutes: 2)) -library; - -import 'package:dwds/expression_compiler.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; - -import 'common/chrome_proxy_service_common.dart'; -import 'fixtures/context.dart'; - -void main() { - // Enable verbose logging for debugging. - const debug = false; - final canaryFeatures = true; - final moduleFormat = ModuleFormat.ddc; - - group('canary: $canaryFeatures | Frontend Server |', () { - final provider = TestSdkConfigurationProvider( - verbose: debug, - canaryFeatures: canaryFeatures, - ddcModuleFormat: moduleFormat, - ); - final compilationMode = CompilationMode.frontendServer; - tearDownAll(provider.dispose); - - runTests( - provider: provider, - moduleFormat: moduleFormat, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); - - group('canary: $canaryFeatures | Build Daemon |', () { - final provider = TestSdkConfigurationProvider( - verbose: debug, - canaryFeatures: canaryFeatures, - ddcModuleFormat: moduleFormat, - ); - final compilationMode = CompilationMode.buildDaemon; - tearDownAll(provider.dispose); - - runTests( - provider: provider, - moduleFormat: moduleFormat, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); -} diff --git a/dwds/test/integration/circular_evaluate_amd_test.dart b/dwds/test/integration/circular_evaluate_amd_test.dart deleted file mode 100644 index 44d0d5557d..0000000000 --- a/dwds/test/integration/circular_evaluate_amd_test.dart +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@Tags(['daily']) -@TestOn('vm') -@Timeout(Duration(minutes: 5)) -library; - -import 'dart:io'; - -import 'package:dwds/expression_compiler.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; - -import 'evaluate_circular_common.dart'; -import 'fixtures/context.dart'; -import 'fixtures/project.dart'; - -void main() async { - // Enable verbose logging for debugging. - const debug = false; - - final provider = TestSdkConfigurationProvider( - verbose: debug, - ddcModuleFormat: ModuleFormat.amd, - ); - tearDownAll(provider.dispose); - - group('Build Daemon |', () { - testAll(provider: provider, compilationMode: CompilationMode.buildDaemon); - }); - - group('Frontend Server |', () { - group('Context with circular dependencies |', () { - for (final indexBaseMode in IndexBaseMode.values) { - group( - 'with ${indexBaseMode.name} |', - () { - testAll( - provider: provider, - compilationMode: CompilationMode.frontendServer, - indexBaseMode: indexBaseMode, - useDebuggerModuleNames: true, - ); - }, - skip: - // https://github.com/dart-lang/sdk/issues/49277 - indexBaseMode == IndexBaseMode.base && Platform.isWindows, - ); - } - }); - }); -} diff --git a/dwds/test/integration/circular_evaluate_ddc_library_bundle_test.dart b/dwds/test/integration/circular_evaluate_ddc_library_bundle_test.dart deleted file mode 100644 index a45d9fcfe8..0000000000 --- a/dwds/test/integration/circular_evaluate_ddc_library_bundle_test.dart +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@Tags(['daily']) -@TestOn('vm') -@Timeout(Duration(minutes: 5)) -library; - -import 'dart:io'; - -import 'package:dwds/expression_compiler.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; - -import 'evaluate_circular_common.dart'; -import 'fixtures/context.dart'; -import 'fixtures/project.dart'; - -void main() async { - // Enable verbose logging for debugging. - const debug = false; - - final provider = TestSdkConfigurationProvider( - verbose: debug, - ddcModuleFormat: ModuleFormat.ddc, - canaryFeatures: true, - ); - tearDownAll(provider.dispose); - - group('Build Daemon |', () { - testAll(provider: provider, compilationMode: CompilationMode.buildDaemon); - }); - - group('Frontend Server |', () { - group('Context with circular dependencies |', () { - for (final indexBaseMode in IndexBaseMode.values) { - group( - 'with ${indexBaseMode.name} |', - () { - testAll( - provider: provider, - compilationMode: CompilationMode.frontendServer, - indexBaseMode: indexBaseMode, - useDebuggerModuleNames: true, - ); - }, - skip: - // https://github.com/dart-lang/sdk/issues/49277 - indexBaseMode == IndexBaseMode.base && Platform.isWindows, - ); - } - }); - }); -} diff --git a/dwds/test/integration/common/chrome_proxy_service_common.dart b/dwds/test/integration/common/chrome_proxy_service_common.dart deleted file mode 100644 index 306fa02c90..0000000000 --- a/dwds/test/integration/common/chrome_proxy_service_common.dart +++ /dev/null @@ -1,2642 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@TestOn('vm') -@Tags(['daily']) -@Timeout(Duration(minutes: 2)) -library; - -import 'dart:async'; -import 'dart:convert'; -import 'dart:io'; - -import 'package:dwds/expression_compiler.dart'; -import 'package:dwds/src/services/chrome/chrome_proxy_service.dart'; -import 'package:dwds/src/utilities/dart_uri.dart'; -import 'package:dwds/src/utilities/shared.dart'; -import 'package:dwds_test_common/logging.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:http/http.dart' as http; -import 'package:path/path.dart' as path; -import 'package:test/test.dart'; -import 'package:vm_service/vm_service.dart'; -import 'package:vm_service_interface/vm_service_interface.dart'; - -import '../fixtures/context.dart'; -import '../fixtures/project.dart'; -import '../fixtures/utilities.dart'; - -void runTests({ - required TestSdkConfigurationProvider provider, - required ModuleFormat moduleFormat, - required CompilationMode compilationMode, - required bool canaryFeatures, -}) { - final project = TestProject.test; - final context = TestContext(project, provider); - - group('shared context', () { - setUpAll(() async { - setCurrentLogWriter(debug: provider.verbose); - await context.setUp( - testSettings: TestSettings( - enableExpressionEvaluation: true, - verboseCompiler: false, - moduleFormat: provider.ddcModuleFormat, - canaryFeatures: canaryFeatures, - compilationMode: compilationMode, - ), - ); - }); - - tearDownAll(() async { - await context.tearDown(); - }); - - group('breakpoints', () { - late VmServiceInterface service; - VM vm; - late Isolate isolate; - - late ScriptList scripts; - late ScriptRef mainScript; - - setUp(() async { - setCurrentLogWriter(debug: provider.verbose); - service = context.service; - vm = await service.getVM(); - isolate = await service.getIsolate(vm.isolates!.first.id!); - scripts = await service.getScripts(isolate.id!); - mainScript = scripts.scripts!.firstWhere( - (ScriptRef each) => each.uri!.contains('main.dart'), - ); - }); - - test('addBreakpoint', () async { - final line = await context.findBreakpointLine( - 'printHelloWorld', - isolate.id!, - mainScript, - ); - final firstBp = await service.addBreakpoint( - isolate.id!, - mainScript.id!, - line, - ); - expect(firstBp, isNotNull); - expect(firstBp.id, isNotNull); - - final secondBp = await service.addBreakpoint( - isolate.id!, - mainScript.id!, - line, - ); - expect(secondBp, isNotNull); - expect(secondBp.id, isNotNull); - - expect(firstBp.id, equals(secondBp.id)); - - // Remove breakpoint so it doesn't impact other tests. - await service.removeBreakpoint(isolate.id!, firstBp.id!); - }); - - test( - 'addBreakpoint succeeds when sending the same breakpoint twice', - () async { - final line = await context.findBreakpointLine( - 'printHelloWorld', - isolate.id!, - mainScript, - ); - final firstBp = service.addBreakpoint( - isolate.id!, - mainScript.id!, - line, - ); - final secondBp = service.addBreakpoint( - isolate.id!, - mainScript.id!, - line, - ); - - // Remove breakpoint so it doesn't impact other tests. - await service.removeBreakpoint(isolate.id!, (await firstBp).id!); - expect((await firstBp).id, equals((await secondBp).id)); - }, - ); - - test('addBreakpoint in nonsense location throws', () async { - expect( - service.addBreakpoint(isolate.id!, mainScript.id!, 200000), - throwsA(predicate((dynamic e) => e is RPCError && e.code == 102)), - ); - }); - - test('addBreakpoint on a part file', () async { - final partScript = scripts.scripts!.firstWhere( - (script) => script.uri!.contains('part.dart'), - ); - final bp = await service.addBreakpoint(isolate.id!, partScript.id!, 10); - // Remove breakpoint so it doesn't impact other tests. - await service.removeBreakpoint(isolate.id!, bp.id!); - expect(bp.id, isNotNull); - }); - - test('addBreakpointAtEntry', () async { - await expectLater(service.addBreakpointAtEntry('', ''), throwsRPCError); - }); - - test('addBreakpointWithScriptUri', () async { - final line = await context.findBreakpointLine( - 'printHelloWorld', - isolate.id!, - mainScript, - ); - final bp = await service.addBreakpointWithScriptUri( - isolate.id!, - mainScript.uri!, - line, - ); - // Remove breakpoint so it doesn't impact other tests. - await service.removeBreakpoint(isolate.id!, bp.id!); - expect(bp.id, isNotNull); - }); - - test('addBreakpointWithScriptUri absolute file URI', () async { - final test = context.project.absolutePackageDirectory; - final scriptPath = Uri.parse(mainScript.uri!).path.substring(1); - final fullPath = path.join(test, scriptPath); - final fileUri = Uri.file(fullPath); - final line = await context.findBreakpointLine( - 'printHelloWorld', - isolate.id!, - mainScript, - ); - final bp = await service.addBreakpointWithScriptUri( - isolate.id!, - '$fileUri', - line, - ); - // Remove breakpoint so it doesn't impact other tests. - await service.removeBreakpoint(isolate.id!, bp.id!); - expect(bp.id, isNotNull); - }); - - test('removeBreakpoint null arguments', () async { - await expectLater( - service.removeBreakpoint('', ''), - throwsSentinelException, - ); - await expectLater( - service.removeBreakpoint(isolate.id!, ''), - throwsRPCError, - ); - }); - - test("removeBreakpoint that doesn't exist fails", () async { - await expectLater( - service.removeBreakpoint(isolate.id!, '1234'), - throwsRPCError, - ); - }); - - test('add and remove breakpoint', () async { - final line = await context.findBreakpointLine( - 'printHelloWorld', - isolate.id!, - mainScript, - ); - final bp = await service.addBreakpoint( - isolate.id!, - mainScript.id!, - line, - ); - expect(isolate.breakpoints, [bp]); - await service.removeBreakpoint(isolate.id!, bp.id!); - expect(isolate.breakpoints, isEmpty); - }); - }); - - group('callServiceExtension', () { - late ChromeProxyService service; - - setUp(() { - setCurrentLogWriter(debug: provider.verbose); - service = context.service; - }); - - test( - 'success', - () async { - final serviceMethod = 'ext.test.callServiceExtension'; - await context.tabConnection.runtime.evaluate( - 'registerExtension("$serviceMethod");', - ); - - // The non-string keys/values get auto json-encoded to match the vm - // behavior. - final args = { - 'bool': true, - 'list': [1, '2', 3], - 'map': {'foo': 'bar'}, - 'num': 1.0, - 'string': 'hello', - 1: 2, - false: true, - }; - - final result = await service.callServiceExtension( - serviceMethod, - args: args, - ); - expect( - result.json, - args.map( - (k, v) => MapEntry( - k is String ? k : jsonEncode(k), - v is String ? v : jsonEncode(v), - ), - ), - ); - }, - onPlatform: { - 'windows': const Skip( - 'https://github.com/dart-lang/webdev/issues/711', - ), - }, - ); - - test( - 'failure', - () async { - final serviceMethod = 'ext.test.callServiceExtensionWithError'; - await context.tabConnection.runtime.evaluate( - 'registerExtensionWithError("$serviceMethod");', - ); - - final errorDetails = {'intentional': 'error'}; - expect( - service.callServiceExtension( - serviceMethod, - args: {'code': '-32001', 'details': jsonEncode(errorDetails)}, - ), - throwsA( - predicate( - (dynamic error) => - error is RPCError && - error.code == -32001 && - error.details == jsonEncode(errorDetails), - ), - ), - ); - }, - onPlatform: { - 'windows': const Skip( - 'https://github.com/dart-lang/webdev/issues/711', - ), - }, - ); - - test('not found', () async { - final serviceMethod = 'ext.test.missingServiceExtension'; - expect( - service.callServiceExtension(serviceMethod), - throwsA( - predicate( - (dynamic error) => - error is RPCError && - error.code == RPCErrorKind.kMethodNotFound.code, - ), - ), - ); - }); - }); - - group('VMTimeline', () { - late VmServiceInterface service; - - setUp(() { - setCurrentLogWriter(debug: provider.verbose); - service = context.service; - }); - - test('clearVMTimeline', () async { - await expectLater(service.clearVMTimeline(), throwsRPCError); - }); - - test('getVMTimelineMicros', () async { - await expectLater(service.getVMTimelineMicros(), throwsRPCError); - }); - - test('getVMTimeline', () async { - await expectLater(service.getVMTimeline(), throwsRPCError); - }); - - test('getVMTimelineFlags', () async { - await expectLater(service.getVMTimelineFlags(), throwsRPCError); - }); - - test('setVMTimelineFlags', () async { - await expectLater( - service.setVMTimelineFlags([]), - throwsRPCError, - ); - }); - }); - - test('getMemoryUsage', () async { - final service = context.service; - final vm = await service.getVM(); - final isolate = await service.getIsolate(vm.isolates!.first.id!); - - final memoryUsage = await service.getMemoryUsage(isolate.id!); - - expect(memoryUsage.heapUsage, isNotNull); - expect(memoryUsage.heapUsage, greaterThan(0)); - expect(memoryUsage.heapCapacity, greaterThan(0)); - expect(memoryUsage.externalUsage, equals(0)); - }); - - group('evaluate', () { - late VmServiceInterface service; - late Isolate isolate; - LibraryRef? bootstrap; - - setUpAll(() async { - setCurrentLogWriter(debug: provider.verbose); - service = context.service; - final vm = await service.getVM(); - isolate = await service.getIsolate(vm.isolates!.first.id!); - bootstrap = isolate.rootLib; - }); - - group('top level methods', () { - setUp(() { - setCurrentLogWriter(debug: provider.verbose); - }); - - test('can return strings', () async { - expect( - await service.evaluate( - isolate.id!, - bootstrap!.id!, - "helloString('world')", - ), - const TypeMatcher().having( - (instance) => instance.valueAsString, - 'value', - 'world', - ), - ); - }); - - test('can return bools', () async { - expect( - await service.evaluate( - isolate.id!, - bootstrap!.id!, - 'helloBool(true)', - ), - const TypeMatcher().having( - (instance) => instance.valueAsString, - 'valueAsString', - 'true', - ), - ); - expect( - await service.evaluate( - isolate.id!, - bootstrap!.id!, - 'helloBool(false)', - ), - const TypeMatcher().having( - (instance) => instance.valueAsString, - 'valueAsString', - 'false', - ), - ); - }); - - test('can return nums', () async { - expect( - await service.evaluate( - isolate.id!, - bootstrap!.id!, - 'helloNum(42.0)', - ), - const TypeMatcher().having( - (instance) => instance.valueAsString, - 'valueAsString', - '42', - ), - ); - expect( - await service.evaluate( - isolate.id!, - bootstrap!.id!, - 'helloNum(42.2)', - ), - const TypeMatcher().having( - (instance) => instance.valueAsString, - 'valueAsString', - '42.2', - ), - ); - }); - - test('can return objects with ids', () async { - final object = await service.evaluate( - isolate.id!, - bootstrap!.id!, - 'createObject("cool")', - ); - expect( - object, - const TypeMatcher().having( - (instance) => instance.id, - 'id', - isNotNull, - ), - ); - // TODO(jakemac): Add tests for the ClassRef once we create one, - // https://github.com/dart-lang/sdk/issues/36771. - }); - - group('with provided scope', () { - setUp(() { - setCurrentLogWriter(debug: provider.verbose); - }); - - Future createRemoteObject(String message) async { - return await service.evaluate( - isolate.id!, - bootstrap!.id!, - 'createObject("$message")', - ) as InstanceRef; - } - - test('single scope object', () async { - final instance = await createRemoteObject('A'); - final result = await service.evaluate( - isolate.id!, - bootstrap!.id!, - 'messageFor(arg1)', - scope: {'arg1': instance.id!}, - ); - expect( - result, - const TypeMatcher().having( - (instance) => instance.valueAsString, - 'valueAsString', - 'A', - ), - ); - }); - - test('multiple scope objects', () async { - final instance1 = await createRemoteObject('A'); - final instance2 = await createRemoteObject('B'); - final result = await service.evaluate( - isolate.id!, - bootstrap!.id!, - 'messagesCombined(arg1, arg2)', - scope: {'arg1': instance1.id!, 'arg2': instance2.id!}, - ); - expect( - result, - const TypeMatcher().having( - (instance) => instance.valueAsString, - 'valueAsString', - 'AB', - ), - ); - }); - }); - }); - }); - - test('evaluateInFrame', () async { - final service = context.service; - await expectLater( - service.evaluateInFrame('', 0, ''), - throwsSentinelException, - ); - }); - - test('getAllocationProfile', () async { - final service = context.service; - await expectLater(service.getAllocationProfile(''), throwsRPCError); - }); - - test('getClassList', () async { - final service = context.service; - await expectLater(service.getClassList(''), throwsRPCError); - }); - - test('getFlagList', () async { - final service = context.service; - expect(await service.getFlagList(), isA()); - }); - - test('getInstances', () async { - final service = context.service; - await expectLater(service.getInstances('', '', 0), throwsRPCError); - }); - - group('getIsolate', () { - late VmServiceInterface service; - setUp(() { - setCurrentLogWriter(debug: provider.verbose); - service = context.service; - }); - - test('works for existing isolates', () async { - final vm = await service.getVM(); - final result = await service.getIsolate(vm.isolates!.first.id!); - expect(result, const TypeMatcher()); - final isolate = result; - expect(isolate.name, contains('main')); - // TODO: library names change with kernel dart-lang/sdk#36736 - expect(isolate.rootLib!.uri, endsWith('.dart')); - - expect( - isolate.libraries, - containsAll([ - _libRef('package:path/path.dart'), - // TODO: library names change with kernel dart-lang/sdk#36736 - _libRef(endsWith('main.dart')), - ]), - ); - expect(isolate.extensionRPCs, contains('ext.hello_world.existing')); - }); - - test('throws for invalid ids', () async { - expect(service.getIsolate('bad'), throwsSentinelException); - }); - }); - - group('getObject', () { - late ChromeProxyService service; - late Isolate isolate; - LibraryRef? bootstrap; - - Library? rootLibrary; - - setUpAll(() async { - setCurrentLogWriter(debug: provider.verbose); - service = context.service; - final vm = await service.getVM(); - isolate = await service.getIsolate(vm.isolates!.first.id!); - bootstrap = isolate.rootLib; - rootLibrary = - await service.getObject(isolate.id!, bootstrap!.id!) as Library; - }); - - setUp(() { - setCurrentLogWriter(debug: provider.verbose); - }); - - test('root Library', () async { - expect(rootLibrary, isNotNull); - // TODO: library names change with kernel dart-lang/sdk#36736 - expect(rootLibrary!.uri, endsWith('main.dart')); - expect(rootLibrary!.classes, hasLength(1)); - final testClass = rootLibrary!.classes!.first; - expect(testClass.name, 'MyTestClass'); - }); - - test('Library only contains included scripts', () async { - final library = - await service.getObject(isolate.id!, rootLibrary!.id!) as Library; - expect(library.scripts, hasLength(2)); - expect( - library.scripts, - unorderedEquals([ - predicate( - (ScriptRef s) => - s.uri == 'org-dartlang-app:///example/hello_world/main.dart', - ), - predicate( - (ScriptRef s) => - s.uri == 'org-dartlang-app:///example/hello_world/part.dart', - ), - ]), - ); - }); - - test('Can get the same library in parallel', () async { - final futures = [ - service.getObject(isolate.id!, rootLibrary!.id!), - service.getObject(isolate.id!, rootLibrary!.id!), - ]; - final results = await Future.wait(futures); - final library1 = results[0] as Library; - final library2 = results[1] as Library; - expect(library1, equals(library2)); - }); - - test('Classes', () async { - final testClass = await service.getObject( - isolate.id!, - rootLibrary!.classes!.first.id!, - ) as Class; - expect( - testClass.functions, - unorderedEquals([ - predicate((FuncRef f) => f.name == 'staticHello' && f.isStatic!), - predicate((FuncRef f) => f.name == 'hello' && !f.isStatic!), - predicate((FuncRef f) => f.name == 'hashCode' && !f.isStatic!), - predicate((FuncRef f) => f.name == 'runtimeType' && !f.isStatic!), - ]), - ); - expect( - testClass.fields, - unorderedEquals([ - predicate( - (FieldRef f) => - f.name == 'message' && - f.declaredType != null && - !f.isStatic! && - !f.isConst! && - f.isFinal!, - ), - predicate( - (FieldRef f) => - f.name == 'notFinal' && - f.declaredType != null && - !f.isStatic! && - !f.isConst! && - !f.isFinal!, - ), - predicate( - (FieldRef f) => - f.name == 'staticMessage' && - f.declaredType != null && - f.isStatic! && - !f.isConst! && - !f.isFinal!, - ), - ]), - ); - }); - - test('Runtime classes', () async { - final testClass = await service.getObject( - isolate.id!, - 'classes|dart:_runtime|_Type', - ) as Class; - expect(testClass.name, '_Type'); - }); - - test('String', () async { - final worldRef = await service.evaluate( - isolate.id!, - bootstrap!.id!, - "helloString('world')", - ) as InstanceRef; - final world = - await service.getObject(isolate.id!, worldRef.id!) as Instance; - expect(world.valueAsString, 'world'); - }); - - test('Large strings not truncated', () async { - final largeString = await service.evaluate( - isolate.id!, - bootstrap!.id!, - "helloString('${'abcde' * 250}')", - ) as InstanceRef; - expect(largeString.valueAsStringIsTruncated, isNot(isTrue)); - expect(largeString.valueAsString!.length, largeString.length); - expect(largeString.length, 5 * 250); - }); - - test('Lists', () async { - final list = await service.evaluate( - isolate.id!, - bootstrap!.id!, - 'topLevelList', - ) as InstanceRef; - final inst = await service.getObject(isolate.id!, list.id!) as Instance; - expect(inst.length, 1001); - expect(inst.offset, null); - expect(inst.count, null); - expect(inst.elements!.length, 1001); - final fifth = inst.elements![4] as InstanceRef; - expect(fifth.valueAsString, '100'); - final sixth = inst.elements![5] as InstanceRef; - expect(sixth.valueAsString, '5'); - }); - - test('Maps', () async { - final map = await service.evaluate( - isolate.id!, - bootstrap!.id!, - 'topLevelMap', - ) as InstanceRef; - final inst = await service.getObject(isolate.id!, map.id!) as Instance; - expect(inst.length, 1001); - expect(inst.offset, null); - expect(inst.count, null); - expect(inst.associations!.length, 1001); - final fifth = inst.associations![4]; - expect((fifth.key as InstanceRef).valueAsString, '4'); - expect((fifth.value as InstanceRef).valueAsString, '996'); - final sixth = inst.associations![5]; - expect((sixth.key as InstanceRef).valueAsString, '5'); - expect((sixth.value as InstanceRef).valueAsString, '995'); - }); - - test('bool', () async { - final ref = await service.evaluate( - isolate.id!, - bootstrap!.id!, - 'helloBool(true)', - ) as InstanceRef; - final obj = await service.getObject(isolate.id!, ref.id!) as Instance; - expect(obj.kind, InstanceKind.kBool); - expect(obj.classRef!.name, 'Bool'); - expect(obj.valueAsString, 'true'); - }); - - test('num', () async { - final ref = await service.evaluate( - isolate.id!, - bootstrap!.id!, - 'helloNum(42)', - ) as InstanceRef; - final obj = await service.getObject(isolate.id!, ref.id!) as Instance; - expect(obj.kind, InstanceKind.kDouble); - expect(obj.classRef!.name, 'Double'); - expect(obj.valueAsString, '42'); - }); - - test('Scripts', () async { - final scripts = await service.getScripts(isolate.id!); - assert(scripts.scripts!.isNotEmpty); - for (final scriptRef in scripts.scripts!) { - final script = - await service.getObject(isolate.id!, scriptRef.id!) as Script; - final serverPath = DartUri(script.uri!, '').serverPath; - final result = await http.get( - Uri.parse('http://localhost:${context.port}/$serverPath'), - ); - expect(script.source, utf8.decode(result.bodyBytes)); - expect(scriptRef.uri, endsWith('.dart')); - expect(script.tokenPosTable, isNotEmpty); - } - }); - - group('getObject called with offset/count parameters', () { - test('Lists with null offset and count are not truncated', () async { - final list = await service.evaluate( - isolate.id!, - bootstrap!.id!, - 'topLevelList', - ) as InstanceRef; - final inst = await service.getObject( - isolate.id!, - list.id!, - count: null, - offset: null, - ) as Instance; - expect(inst.length, 1001); - expect(inst.offset, null); - expect(inst.count, null); - expect(inst.elements!.length, 1001); - final fifth = inst.elements![4] as InstanceRef; - expect(fifth.valueAsString, '100'); - final sixth = inst.elements![5] as InstanceRef; - expect(sixth.valueAsString, '5'); - }); - - test('Lists with null count are not truncated', () async { - final list = await service.evaluate( - isolate.id!, - bootstrap!.id!, - 'topLevelList', - ) as InstanceRef; - final inst = await service.getObject( - isolate.id!, - list.id!, - count: null, - offset: 0, - ) as Instance; - expect(inst.length, 1001); - expect(inst.offset, 0); - expect(inst.count, null); - expect(inst.elements!.length, 1001); - final fifth = inst.elements![4] as InstanceRef; - expect(fifth.valueAsString, '100'); - final sixth = inst.elements![5] as InstanceRef; - expect(sixth.valueAsString, '5'); - }); - - test('Lists with null count and offset greater than 0 are ' - 'truncated from offset to end of list', () async { - final list = await service.evaluate( - isolate.id!, - bootstrap!.id!, - 'topLevelList', - ) as InstanceRef; - final inst = await service.getObject( - isolate.id!, - list.id!, - count: null, - offset: 1000, - ) as Instance; - expect(inst.length, 1001); - expect(inst.offset, 1000); - expect(inst.count, null); - expect(inst.elements!.length, 1); - final only = inst.elements![0] as InstanceRef; - expect(only.valueAsString, '5'); - }); - - test('Lists with offset/count are truncated', () async { - final list = await service.evaluate( - isolate.id!, - bootstrap!.id!, - 'topLevelList', - ) as InstanceRef; - final inst = await service.getObject( - isolate.id!, - list.id!, - count: 7, - offset: 4, - ) as Instance; - expect(inst.length, 1001); - expect(inst.offset, 4); - expect(inst.count, 7); - expect(inst.elements!.length, 7); - final fifth = inst.elements![0] as InstanceRef; - expect(fifth.valueAsString, '100'); - final sixth = inst.elements![1] as InstanceRef; - expect(sixth.valueAsString, '5'); - }); - - test( - 'Lists are truncated to the end if offset/count runs off the end', - () async { - final list = await service.evaluate( - isolate.id!, - bootstrap!.id!, - 'topLevelList', - ) as InstanceRef; - final inst = await service.getObject( - isolate.id!, - list.id!, - count: 5, - offset: 1000, - ) as Instance; - expect(inst.length, 1001); - expect(inst.offset, 1000); - expect(inst.count, 1); - expect(inst.elements!.length, 1); - final only = inst.elements![0] as InstanceRef; - expect(only.valueAsString, '5'); - }, - ); - - test( - 'Lists are truncated to empty if offset runs off the end', - () async { - final list = await service.evaluate( - isolate.id!, - bootstrap!.id!, - 'topLevelList', - ) as InstanceRef; - final inst = await service.getObject( - isolate.id!, - list.id!, - count: 5, - offset: 1002, - ) as Instance; - expect(inst.elements!.length, 0); - expect(inst.length, 1001); - expect(inst.offset, 1002); - expect(inst.count, 0); - expect(inst.elements!.length, 0); - }, - ); - - test( - 'Lists are truncated to empty with 0 count and null offset', - () async { - final list = await service.evaluate( - isolate.id!, - bootstrap!.id!, - 'topLevelList', - ) as InstanceRef; - final inst = await service.getObject( - isolate.id!, - list.id!, - count: 0, - offset: null, - ) as Instance; - expect(inst.elements!.length, 0); - expect(inst.length, 1001); - expect(inst.offset, null); - expect(inst.count, 0); - expect(inst.elements!.length, 0); - }, - ); - - test('Maps with null offset/count are not truncated', () async { - final map = await service.evaluate( - isolate.id!, - bootstrap!.id!, - 'topLevelMap', - ) as InstanceRef; - final inst = await service.getObject( - isolate.id!, - map.id!, - count: null, - offset: null, - ) as Instance; - expect(inst.length, 1001); - expect(inst.offset, null); - expect(inst.count, null); - expect(inst.associations!.length, 1001); - final fifth = inst.associations![4]; - expect((fifth.key as InstanceRef).valueAsString, '4'); - expect((fifth.value as InstanceRef).valueAsString, '996'); - final sixth = inst.associations![5]; - expect((sixth.key as InstanceRef).valueAsString, '5'); - expect((sixth.value as InstanceRef).valueAsString, '995'); - }); - - test('Maps with null count and offset greater than 0 are ' - 'truncated from offset to end of map', () async { - final map = await service.evaluate( - isolate.id!, - bootstrap!.id!, - 'topLevelMap', - ) as InstanceRef; - final inst = await service.getObject( - isolate.id!, - map.id!, - count: null, - offset: 1000, - ) as Instance; - expect(inst.length, 1001); - expect(inst.offset, 1000); - expect(inst.count, null); - expect(inst.associations!.length, 1); - final only = inst.associations![0]; - expect((only.key as InstanceRef).valueAsString, '1000'); - expect((only.value as InstanceRef).valueAsString, '0'); - }); - - test('Maps with null count are not truncated', () async { - final map = await service.evaluate( - isolate.id!, - bootstrap!.id!, - 'topLevelMap', - ) as InstanceRef; - final inst = await service.getObject( - isolate.id!, - map.id!, - count: null, - offset: 0, - ) as Instance; - expect(inst.length, 1001); - expect(inst.offset, 0); - expect(inst.count, null); - expect(inst.associations!.length, 1001); - final fifth = inst.associations![4]; - expect((fifth.key as InstanceRef).valueAsString, '4'); - expect((fifth.value as InstanceRef).valueAsString, '996'); - final sixth = inst.associations![5]; - expect((sixth.key as InstanceRef).valueAsString, '5'); - expect((sixth.value as InstanceRef).valueAsString, '995'); - }); - - test('Maps with offset/count are truncated', () async { - final map = await service.evaluate( - isolate.id!, - bootstrap!.id!, - 'topLevelMap', - ) as InstanceRef; - final inst = await service.getObject( - isolate.id!, - map.id!, - count: 7, - offset: 4, - ) as Instance; - expect(inst.length, 1001); - expect(inst.offset, 4); - expect(inst.count, 7); - expect(inst.associations!.length, 7); - final fifth = inst.associations![0]; - expect((fifth.key as InstanceRef).valueAsString, '4'); - expect((fifth.value as InstanceRef).valueAsString, '996'); - final sixth = inst.associations![1]; - expect((sixth.key as InstanceRef).valueAsString, '5'); - expect((sixth.value as InstanceRef).valueAsString, '995'); - }); - - test( - 'Maps are truncated to the end if offset/count runs off the end', - () async { - final map = await service.evaluate( - isolate.id!, - bootstrap!.id!, - 'topLevelMap', - ) as InstanceRef; - final inst = await service.getObject( - isolate.id!, - map.id!, - count: 5, - offset: 1000, - ) as Instance; - expect(inst.length, 1001); - expect(inst.offset, 1000); - expect(inst.count, 1); - expect(inst.associations!.length, 1); - final only = inst.associations![0]; - expect((only.key as InstanceRef).valueAsString, '1000'); - expect((only.value as InstanceRef).valueAsString, '0'); - }, - ); - - test( - 'Maps are truncated to empty if offset runs off the end', - () async { - final map = await service.evaluate( - isolate.id!, - bootstrap!.id!, - 'topLevelMap', - ) as InstanceRef; - final inst = await service.getObject( - isolate.id!, - map.id!, - count: 5, - offset: 1002, - ) as Instance; - expect(inst.associations!.length, 0); - expect(inst.length, 1001); - expect(inst.offset, 1002); - expect(inst.count, 0); - expect(inst.associations!.length, 0); - }, - ); - - test('Strings with offset/count are truncated', () async { - final worldRef = await service.evaluate( - isolate.id!, - bootstrap!.id!, - "helloString('world')", - ) as InstanceRef; - final world = await service.getObject( - isolate.id!, - worldRef.id!, - count: 2, - offset: 1, - ) as Instance; - expect(world.valueAsString, 'or'); - expect(world.count, 2); - expect(world.length, 5); - expect(world.offset, 1); - }); - - test( - 'Maps are truncated to empty if offset runs off the end', - () async { - final map = await service.evaluate( - isolate.id!, - bootstrap!.id!, - 'topLevelMap', - ) as InstanceRef; - final inst = await service.getObject( - isolate.id!, - map.id!, - count: 5, - offset: 1002, - ) as Instance; - expect(inst.associations!.length, 0); - expect(inst.length, 1001); - expect(inst.offset, 1002); - expect(inst.count, 0); - expect(inst.associations!.length, 0); - }, - ); - - test( - 'Maps are truncated to empty with 0 count and null offset', - () async { - final map = await service.evaluate( - isolate.id!, - bootstrap!.id!, - 'topLevelMap', - ) as InstanceRef; - final inst = await service.getObject( - isolate.id!, - map.id!, - count: 0, - offset: null, - ) as Instance; - expect(inst.associations!.length, 0); - expect(inst.length, 1001); - expect(inst.offset, null); - expect(inst.count, 0); - expect(inst.associations!.length, 0); - }, - ); - - test( - 'Strings are truncated to the end if offset/count runs off the end', - () async { - final worldRef = await service.evaluate( - isolate.id!, - bootstrap!.id!, - "helloString('world')", - ) as InstanceRef; - final world = await service.getObject( - isolate.id!, - worldRef.id!, - count: 5, - offset: 3, - ) as Instance; - expect(world.valueAsString, 'ld'); - expect(world.count, 2); - expect(world.length, 5); - expect(world.offset, 3); - }, - ); - - test( - 'offset/count parameters greater than zero are ignored for Classes', - () async { - final testClass = await service.getObject( - isolate.id!, - rootLibrary!.classes!.first.id!, - offset: 100, - count: 100, - ) as Class; - expect( - testClass.functions, - unorderedEquals([ - predicate( - (FuncRef f) => f.name == 'staticHello' && f.isStatic!, - ), - predicate((FuncRef f) => f.name == 'hello' && !f.isStatic!), - predicate((FuncRef f) => f.name == 'hashCode' && !f.isStatic!), - predicate( - (FuncRef f) => f.name == 'runtimeType' && !f.isStatic!, - ), - ]), - ); - expect( - testClass.fields, - unorderedEquals([ - predicate( - (FieldRef f) => - f.name == 'message' && - f.declaredType != null && - !f.isStatic! && - !f.isConst! && - f.isFinal!, - ), - predicate( - (FieldRef f) => - f.name == 'notFinal' && - f.declaredType != null && - !f.isStatic! && - !f.isConst! && - !f.isFinal!, - ), - predicate( - (FieldRef f) => - f.name == 'staticMessage' && - f.declaredType != null && - f.isStatic! && - !f.isConst! && - !f.isFinal!, - ), - ]), - ); - }, - ); - - test( - 'offset/count parameters equal to zero are ignored for Classes', - () async { - final testClass = await service.getObject( - isolate.id!, - rootLibrary!.classes!.first.id!, - offset: 0, - count: 0, - ) as Class; - expect( - testClass.functions, - unorderedEquals([ - predicate( - (FuncRef f) => f.name == 'staticHello' && f.isStatic!, - ), - predicate((FuncRef f) => f.name == 'hello' && !f.isStatic!), - predicate((FuncRef f) => f.name == 'hashCode' && !f.isStatic!), - predicate( - (FuncRef f) => f.name == 'runtimeType' && !f.isStatic!, - ), - ]), - ); - expect( - testClass.fields, - unorderedEquals([ - predicate( - (FieldRef f) => - f.name == 'message' && - f.declaredType != null && - !f.isStatic! && - !f.isConst! && - f.isFinal!, - ), - predicate( - (FieldRef f) => - f.name == 'notFinal' && - f.declaredType != null && - !f.isStatic! && - !f.isConst! && - !f.isFinal!, - ), - predicate( - (FieldRef f) => - f.name == 'staticMessage' && - f.declaredType != null && - f.isStatic! && - !f.isConst! && - !f.isFinal!, - ), - ]), - ); - }, - ); - - test('offset/count parameters are ignored for bools', () async { - final ref = await service.evaluate( - isolate.id!, - bootstrap!.id!, - 'helloBool(true)', - ) as InstanceRef; - final obj = await service.getObject( - isolate.id!, - ref.id!, - offset: 100, - count: 100, - ) as Instance; - expect(obj.kind, InstanceKind.kBool); - expect(obj.classRef!.name, 'Bool'); - expect(obj.valueAsString, 'true'); - }); - - test('offset/count parameters are ignored for nums', () async { - final ref = await service.evaluate( - isolate.id!, - bootstrap!.id!, - 'helloNum(42)', - ) as InstanceRef; - final obj = await service.getObject( - isolate.id!, - ref.id!, - offset: 100, - count: 100, - ) as Instance; - expect(obj.kind, InstanceKind.kDouble); - expect(obj.classRef!.name, 'Double'); - expect(obj.valueAsString, '42'); - }); - - test('offset/count parameters are ignored for null', () async { - final ref = await service.evaluate( - isolate.id!, - bootstrap!.id!, - 'helloNum(null)', - ) as InstanceRef; - final obj = await service.getObject( - isolate.id!, - ref.id!, - offset: 100, - count: 100, - ) as Instance; - expect(obj.kind, InstanceKind.kNull); - expect(obj.classRef!.name, 'Null'); - expect(obj.valueAsString, 'null'); - }); - }); - }); - - test('getScripts', () async { - final service = context.service; - final vm = await service.getVM(); - final isolateId = vm.isolates!.first.id!; - final scripts = await service.getScripts(isolateId); - expect(scripts, isNotNull); - expect(scripts.scripts, isNotEmpty); - - final scriptUris = scripts.scripts!.map((s) => s.uri); - - // Contains main script only once. - expect( - scriptUris.where((uri) => uri!.contains('hello_world/main.dart')), - hasLength(1), - ); - - // Contains a known script. - expect(scriptUris, contains('package:path/path.dart')); - - // Contains part files as well. - expect(scriptUris, contains(endsWith('part.dart'))); - expect( - scriptUris, - contains('package:intl/src/date_format_internal.dart'), - ); - }); - - group('getSourceReport', () { - late VmServiceInterface service; - - setUp(() { - setCurrentLogWriter(debug: provider.verbose); - service = context.service; - }); - - test('Coverage report', () async { - final vm = await service.getVM(); - final isolateId = vm.isolates!.first.id!; - - await expectLater( - service.getSourceReport(isolateId, ['Coverage']), - throwsRPCError, - ); - }); - - test('Coverage report', () async { - final vm = await service.getVM(); - final isolateId = vm.isolates!.first.id!; - - await expectLater( - service.getSourceReport( - isolateId, - ['Coverage'], - libraryFilters: ['foo'], - ), - throwsRPCError, - ); - }); - - test('report type not understood', () async { - final vm = await service.getVM(); - final isolateId = vm.isolates!.first.id!; - - await expectLater( - service.getSourceReport(isolateId, ['FooBar']), - throwsRPCError, - ); - }); - - test('PossibleBreakpoints report', () async { - final vm = await service.getVM(); - final isolateId = vm.isolates!.first.id!; - final scripts = await service.getScripts(isolateId); - final mainScript = scripts.scripts!.firstWhere( - (script) => script.uri!.contains('main.dart'), - ); - - final sourceReport = await service.getSourceReport(isolateId, [ - 'PossibleBreakpoints', - ], scriptId: mainScript.id); - - expect(sourceReport.scripts, isNotEmpty); - expect(sourceReport.ranges, isNotEmpty); - - final sourceReportRange = sourceReport.ranges!.first; - expect(sourceReportRange.possibleBreakpoints, isNotEmpty); - }); - }); - - group('Pausing', () { - late VmServiceInterface service; - String? isolateId; - late Stream stream; - ScriptList scripts; - late ScriptRef mainScript; - - setUp(() async { - setCurrentLogWriter(debug: provider.verbose); - service = context.service; - final vm = await service.getVM(); - isolateId = vm.isolates!.first.id; - scripts = await service.getScripts(isolateId!); - await service.streamListen('Debug'); - stream = service.onEvent('Debug'); - mainScript = scripts.scripts!.firstWhere( - (script) => script.uri!.contains('main.dart'), - ); - }); - - test('at breakpoints sets pauseBreakPoints', () async { - final line = await context.findBreakpointLine( - 'callPrintCount', - isolateId!, - mainScript, - ); - final bp = await service.addBreakpoint( - isolateId!, - mainScript.id!, - line, - ); - final event = await stream.firstWhere( - (event) => event.kind == EventKind.kPauseBreakpoint, - ); - final pauseBreakpoints = event.pauseBreakpoints!; - expect(pauseBreakpoints, hasLength(1)); - expect(pauseBreakpoints.first.id, bp.id); - await service.removeBreakpoint(isolateId!, bp.id!); - // Resume execution to not impact other tests. - await service.resume(isolateId!); - }); - - test( - 'resuming throws kIsolateMustBePaused error if not paused', - () async { - await expectLater( - service.resume(isolateId!), - throwsRPCErrorWithCode(RPCErrorKind.kIsolateMustBePaused.code), - ); - }, - ); - }); - - group('Step', () { - late VmServiceInterface service; - String? isolateId; - late Stream stream; - ScriptList scripts; - ScriptRef mainScript; - - setUp(() async { - setCurrentLogWriter(debug: provider.verbose); - service = context.service; - final vm = await service.getVM(); - isolateId = vm.isolates!.first.id; - scripts = await service.getScripts(isolateId!); - await service.streamListen('Debug'); - stream = service.onEvent('Debug'); - mainScript = scripts.scripts!.firstWhere( - (script) => script.uri!.contains('main.dart'), - ); - final line = await context.findBreakpointLine( - 'callPrintCount', - isolateId!, - mainScript, - ); - final bp = await service.addBreakpoint( - isolateId!, - mainScript.id!, - line, - ); - // Wait for breakpoint to trigger. - await stream.firstWhere( - (event) => event.kind == EventKind.kPauseBreakpoint, - ); - await service.removeBreakpoint(isolateId!, bp.id!); - }); - - tearDown(() async { - // Resume execution to not impact other tests. - await service.resume(isolateId!); - }); - - test('Into goes to the next Dart location', () async { - await service.resume(isolateId!, step: 'Into'); - // Wait for the step to actually occur. - await stream.firstWhere( - (event) => event.kind == EventKind.kPauseInterrupted, - ); - final stack = await service.getStack(isolateId!); - expect(stack, isNotNull); - final first = stack.frames!.first; - expect(first.kind, 'Regular'); - expect(first.code!.kind, 'Dart'); - expect(first.code!.name, 'printCount'); - }); - - test('Over goes to the next Dart location', () async { - await service.resume(isolateId!, step: 'Over'); - // Wait for the step to actually occur. - await stream.firstWhere( - (event) => event.kind == EventKind.kPauseInterrupted, - ); - final stack = await service.getStack(isolateId!); - expect(stack, isNotNull); - final first = stack.frames!.first; - expect(first.kind, 'Regular'); - expect(first.code!.kind, 'Dart'); - expect(first.code!.name, ''); - }); - - test('Out goes to the next Dart location', () async { - await service.resume(isolateId!, step: 'Out'); - // Wait for the step to actually occur. - await stream.firstWhere( - (event) => event.kind == EventKind.kPauseInterrupted, - ); - final stack = await service.getStack(isolateId!); - expect(stack, isNotNull); - final first = stack.frames!.first; - expect(first.kind, 'Regular'); - expect(first.code!.kind, 'Dart'); - expect(first.code!.name, ''); - }); - }); - - group('getStack', () { - late VmServiceInterface service; - String? isolateId; - late Stream stream; - ScriptList scripts; - late ScriptRef mainScript; - - setUp(() async { - setCurrentLogWriter(debug: provider.verbose); - service = context.service; - final vm = await service.getVM(); - isolateId = vm.isolates!.first.id; - scripts = await service.getScripts(isolateId!); - await service.streamListen('Debug'); - stream = service.onEvent('Debug'); - mainScript = scripts.scripts!.firstWhere( - (ScriptRef each) => each.uri!.contains('main.dart'), - ); - }); - - test( - 'throws if not paused', - () async { - await expectLater(service.getStack(isolateId!), throwsRPCError); - }, - skip: Platform.isWindows ? true : null, - ); // Issue: https://github.com/dart-lang/webdev/issues/1749 - - /// Support function for pausing and returning the stack at a line. - Future breakAt(String breakpointId, {int? limit}) async { - final line = await context.findBreakpointLine( - breakpointId, - isolateId!, - mainScript, - ); - Breakpoint? bp; - try { - bp = await service.addBreakpoint(isolateId!, mainScript.id!, line); - // Wait for breakpoint to trigger. - await stream.firstWhere( - (event) => event.kind == EventKind.kPauseBreakpoint, - ); - return await service.getStack(isolateId!, limit: limit); - } finally { - // Remove breakpoint and resume so it doesn't impact other tests. - if (bp != null) { - await service.removeBreakpoint(isolateId!, bp.id!); - } - await service.resume(isolateId!); - } - } - - test('returns stack when broken', () async { - final stack = await breakAt('inPrintCount'); - expect(stack, isNotNull); - expect(stack.frames, hasLength(2)); - final first = stack.frames!.first; - expect(first.kind, 'Regular'); - expect(first.code!.kind, 'Dart'); - expect(first.code!.name, 'printCount'); - }); - - test('stack has a variable', () async { - final stack = await breakAt('callPrintCount'); - expect(stack, isNotNull); - expect(stack.frames, hasLength(1)); - final first = stack.frames!.first; - expect(first.kind, 'Regular'); - expect(first.code!.kind, 'Dart'); - expect(first.code!.name, ''); - // TODO: Make this more precise once this case doesn't - // also include all the libraries. - expect(first.vars, hasLength(greaterThanOrEqualTo(1))); - final underscore = first.vars!.firstWhere((v) => v.name == 'timer'); - expect(underscore, isNotNull); - }); - - test('collects async frames', () async { - final stack = await breakAt('asyncCall'); - expect(stack, isNotNull); - expect(stack.frames, hasLength(greaterThan(1))); - - final first = stack.frames!.first; - expect(first.kind, 'Regular'); - expect(first.code!.kind, 'Dart'); - - // We should have an async marker. - final suspensionFrames = stack.frames!.where( - (frame) => frame.kind == FrameKind.kAsyncSuspensionMarker, - ); - expect(suspensionFrames, isNotEmpty); - - // We should have async frames. - final asyncFrames = stack.frames!.where( - (frame) => frame.kind == FrameKind.kAsyncCausal, - ); - expect(asyncFrames, isNotEmpty); - }); - - test( - 'returns the correct number of frames when a limit is provided', - () async { - var stack = await breakAt('asyncCall', limit: 4); - expect(stack, isNotNull); - expect(stack.frames, hasLength(equals(4))); - stack = await breakAt('asyncCall', limit: 2); - expect(stack, isNotNull); - expect(stack.frames, hasLength(equals(2))); - stack = await breakAt('asyncCall'); - expect(stack, isNotNull); - expect(stack.frames, hasLength(equals(5))); - }, - ); - - test('truncated stacks are properly indicated', () async { - var stack = await breakAt('asyncCall', limit: 3); - expect(stack, isNotNull); - expect(stack.truncated, isTrue); - stack = await breakAt('asyncCall'); - expect(stack, isNotNull); - expect(stack.truncated, isFalse); - stack = await breakAt('asyncCall', limit: 20000); - expect(stack, isNotNull); - expect(stack.truncated, isFalse); - }); - - test('break on exceptions with setIsolatePauseMode', () async { - final oldPauseMode = (await service.getIsolate(isolateId!)) - .exceptionPauseMode; - await service.setIsolatePauseMode( - isolateId!, - exceptionPauseMode: ExceptionPauseMode.kAll, - ); - // Wait for pausing to actually propagate. - final event = await stream.firstWhere( - (event) => event.kind == EventKind.kPauseException, - ); - expect(event.exception, isNotNull); - // Check that the exception stack trace has been mapped to Dart source - // files. - expect(event.exception!.valueAsString, contains('main.dart')); - - final stack = await service.getStack(isolateId!); - expect(stack, isNotNull); - - await service.setIsolatePauseMode( - isolateId!, - exceptionPauseMode: oldPauseMode, - ); - await service.resume(isolateId!); - }); - - test('returns non-null stack when paused', () async { - await service.pause(isolateId!); - // Wait for pausing to actually propagate. - await stream.firstWhere( - (event) => event.kind == EventKind.kPauseInterrupted, - ); - expect(await service.getStack(isolateId!), isNotNull); - // Resume the isolate to not impact other tests. - await service.resume(isolateId!); - }); - }); - - test('getVM', () async { - final service = context.service; - final vm = await service.getVM(); - expect(vm.name, isNotNull); - expect(vm.version, Platform.version); - expect(vm.isolates, hasLength(1)); - final isolate = vm.isolates!.first; - expect(isolate.id, isNotNull); - expect(isolate.name, isNotNull); - expect(isolate.number, isNotNull); - }); - - test('getVersion', () async { - final service = context.service; - final version = await service.getVersion(); - expect(version, isNotNull); - expect(version.major, greaterThan(0)); - }); - - group('invoke', () { - late ChromeProxyService service; - VM vm; - late Isolate isolate; - LibraryRef? bootstrap; - late InstanceRef testInstance; - - setUp(() async { - setCurrentLogWriter(debug: provider.verbose); - service = context.service; - vm = await service.getVM(); - isolate = await service.getIsolate(vm.isolates!.first.id!); - bootstrap = isolate.rootLib; - testInstance = await service.evaluate( - isolate.id!, - bootstrap!.id!, - 'myInstance', - ) as InstanceRef; - }); - - test('rootLib', () async { - expect( - bootstrap, - const TypeMatcher().having( - (library) => library.name, - 'name', - 'org-dartlang-app:///example/hello_world/main.dart', - ), - ); - }); - - test('toString()', () async { - final remote = await service.invoke( - isolate.id!, - testInstance.id!, - 'toString', - [], - ); - expect( - remote, - const TypeMatcher().having( - (instance) => instance.valueAsString, - 'toString()', - "Instance of 'MyTestClass'", - ), - ); - }); - - test('hello()', () async { - final remote = await service.invoke( - isolate.id!, - testInstance.id!, - 'hello', - [], - ); - expect( - remote, - const TypeMatcher().having( - (instance) => instance.valueAsString, - 'hello()', - 'world', - ), - ); - }); - - test('helloString', () async { - final remote = await service.invoke( - isolate.id!, - bootstrap!.id!, - 'helloString', - ['#StringInstanceRef#abc'], - ); - expect( - remote, - const TypeMatcher().having( - (instance) => instance.valueAsString, - 'helloString', - 'abc', - ), - ); - expect( - remote, - const TypeMatcher().having( - (instance) => instance.kind, - 'kind', - 'String', - ), - ); - }); - - test('null argument', () async { - final remote = await service.invoke( - isolate.id!, - bootstrap!.id!, - 'helloString', - ['objects/null'], - ); - expect( - remote, - const TypeMatcher().having( - (instance) => instance.valueAsString, - 'helloString', - 'null', - ), - ); - expect( - remote, - const TypeMatcher().having( - (instance) => instance.kind, - 'kind', - 'Null', - ), - ); - }); - - test('helloBool', () async { - final remote = await service.invoke( - isolate.id!, - bootstrap!.id!, - 'helloBool', - ['objects/bool-true'], - ); - expect( - remote, - const TypeMatcher().having( - (instance) => instance.valueAsString, - 'helloBool', - 'true', - ), - ); - expect( - remote, - const TypeMatcher().having( - (instance) => instance.kind, - 'kind', - 'Bool', - ), - ); - }); - - test('helloNum', () async { - final remote = await service.invoke( - isolate.id!, - bootstrap!.id!, - 'helloNum', - ['objects/int-123'], - ); - expect( - remote, - const TypeMatcher().having( - (instance) => instance.valueAsString, - 'helloNum', - '123', - ), - ); - expect( - remote, - const TypeMatcher().having( - (instance) => instance.kind, - 'kind', - 'Double', - ), - ); - }); - - test('two object arguments', () async { - final remote = await service.invoke( - isolate.id!, - bootstrap!.id!, - 'messagesCombined', - [testInstance.id, testInstance.id], - ); - expect( - remote, - const TypeMatcher().having( - (instance) => instance.valueAsString, - 'messagesCombined', - 'worldworld', - ), - ); - expect( - remote, - const TypeMatcher().having( - (instance) => instance.kind, - 'kind', - 'String', - ), - ); - }); - }); - - test('kill', () async { - final service = context.service; - await expectLater(service.kill(''), throwsRPCError); - }); - - test('onEvent', () async { - final service = context.service; - expect(() => service.onEvent(''), throwsRPCError); - }); - - test('pause / resume', () async { - final service = context.service; - await service.streamListen('Debug'); - final stream = service.onEvent('Debug'); - final vm = await service.getVM(); - final isolateId = vm.isolates!.first.id!; - final pauseCompleter = Completer(); - final pauseSub = context.tabConnection.debugger.onPaused.listen((_) { - pauseCompleter.complete(); - }); - final resumeCompleter = Completer(); - final resumeSub = context.tabConnection.debugger.onResumed.listen((_) { - resumeCompleter.complete(); - }); - expect(await service.pause(isolateId), const TypeMatcher()); - await stream.firstWhere( - (event) => event.kind == EventKind.kPauseInterrupted, - ); - expect( - (await service.getIsolate(isolateId)).pauseEvent!.kind, - EventKind.kPauseInterrupted, - ); - await pauseCompleter.future; - expect(await service.resume(isolateId), const TypeMatcher()); - await stream.firstWhere((event) => event.kind == EventKind.kResume); - expect( - (await service.getIsolate(isolateId)).pauseEvent!.kind, - EventKind.kResume, - ); - await resumeCompleter.future; - await pauseSub.cancel(); - await resumeSub.cancel(); - }); - - test('getInboundReferences', () async { - final service = context.service; - await expectLater( - service.getInboundReferences('', '', 0), - throwsRPCError, - ); - }); - - test('getRetainingPath', () async { - final service = context.service; - await expectLater(service.getRetainingPath('', '', 0), throwsRPCError); - }); - - test( - 'lookupResolvedPackageUris converts package and org-dartlang-app uris', - () async { - final service = context.service; - final vm = await service.getVM(); - final isolateId = vm.isolates!.first.id!; - final scriptList = await service.getScripts(isolateId); - - final uris = scriptList.scripts!.map((e) => e.uri!).toList(); - final resolvedUris = await service.lookupResolvedPackageUris( - isolateId, - uris, - ); - - expect( - resolvedUris.uris, - containsAll([ - contains('/_test/example/hello_world/main.dart'), - contains('/lib/path.dart'), - contains('/lib/src/path_set.dart'), - ]), - ); - }, - ); - - test( - 'lookupResolvedPackageUris does not translate non-existent paths', - () async { - final service = context.service; - final vm = await service.getVM(); - final isolateId = vm.isolates!.first.id!; - - final resolvedUris = await service.lookupResolvedPackageUris( - isolateId, - [ - 'package:does/not/exist.dart', - 'dart:does_not_exist', - 'file:///does_not_exist.dart', - ], - ); - expect(resolvedUris.uris, [null, null, null]); - }, - ); - - test('lookupResolvedPackageUris translates dart uris', () async { - final service = context.service; - final vm = await service.getVM(); - final isolateId = vm.isolates!.first.id!; - - final resolvedUris = await service.lookupResolvedPackageUris(isolateId, [ - 'dart:html', - 'dart:async', - ]); - - expect(resolvedUris.uris, [ - 'org-dartlang-sdk:///sdk/lib/html/dart2js/html_dart2js.dart', - 'org-dartlang-sdk:///sdk/lib/async/async.dart', - ]); - }, skip: 'https://github.com/dart-lang/webdev/issues/1584'); - - test( - 'lookupPackageUris finds package and org-dartlang-app paths', - () async { - final service = context.service; - final vm = await service.getVM(); - final isolateId = vm.isolates!.first.id!; - final scriptList = await service.getScripts(isolateId); - - final uris = scriptList.scripts!.map((e) => e.uri!).toList(); - final resolvedUris = await service.lookupResolvedPackageUris( - isolateId, - uris, - ); - - final packageUris = await service.lookupPackageUris( - isolateId, - List.from(resolvedUris.uris!), - ); - expect( - packageUris.uris, - containsAll([ - 'org-dartlang-app:///example/hello_world/main.dart', - 'package:path/path.dart', - 'package:path/src/path_set.dart', - ]), - ); - }, - ); - - test('lookupPackageUris ignores local parameter', () async { - final service = context.service; - final vm = await service.getVM(); - final isolateId = vm.isolates!.first.id!; - final scriptList = await service.getScripts(isolateId); - - final uris = scriptList.scripts!.map((e) => e.uri!).toList(); - final resolvedUrisWithLocal = await service.lookupResolvedPackageUris( - isolateId, - uris, - local: true, - ); - - final packageUrisWithLocal = await service.lookupPackageUris( - isolateId, - List.from(resolvedUrisWithLocal.uris!), - ); - expect( - packageUrisWithLocal.uris, - containsAll([ - 'org-dartlang-app:///example/hello_world/main.dart', - 'package:path/path.dart', - 'package:path/src/path_set.dart', - ]), - ); - - final resolvedUrisWithoutLocal = await service.lookupResolvedPackageUris( - isolateId, - uris, - local: true, - ); - - final packageUrisWithoutLocal = await service.lookupPackageUris( - isolateId, - List.from(resolvedUrisWithoutLocal.uris!), - ); - expect( - packageUrisWithoutLocal.uris, - containsAll([ - 'org-dartlang-app:///example/hello_world/main.dart', - 'package:path/path.dart', - 'package:path/src/path_set.dart', - ]), - ); - }); - - test('lookupPackageUris does not translate non-existent paths', () async { - final service = context.service; - final vm = await service.getVM(); - final isolateId = vm.isolates!.first.id!; - - final resolvedUris = await service.lookupPackageUris(isolateId, [ - 'org-dartlang-sdk:///sdk/does/not/exist.dart', - 'does_not_exist.dart', - 'file:///does_not_exist.dart', - ]); - expect(resolvedUris.uris, [null, null, null]); - }); - - test('lookupPackageUris translates dart uris', () async { - final service = context.service; - final vm = await service.getVM(); - final isolateId = vm.isolates!.first.id!; - - final resolvedUris = await service.lookupPackageUris(isolateId, [ - 'org-dartlang-sdk:///sdk/lib/html/dart2js/html_dart2js.dart', - 'org-dartlang-sdk:///sdk/lib/async/async.dart', - ]); - - expect(resolvedUris.uris, ['dart:html', 'dart:async']); - }, skip: 'https://github.com/dart-lang/webdev/issues/1584'); - - test('registerService', () async { - final service = context.service; - await expectLater( - service.registerService('ext.foo.bar', ''), - throwsRPCError, - ); - }); - - test('setIsolatePauseMode', () async { - final service = context.service; - final vm = await service.getVM(); - final isolateId = vm.isolates!.first.id!; - expect(await service.setIsolatePauseMode(isolateId), _isSuccess); - expect( - await service.setIsolatePauseMode( - isolateId, - exceptionPauseMode: ExceptionPauseMode.kAll, - ), - _isSuccess, - ); - expect( - await service.setIsolatePauseMode( - isolateId, - exceptionPauseMode: ExceptionPauseMode.kUnhandled, - ), - _isSuccess, - ); - // Make sure this is the last one - or future tests might hang. - expect( - await service.setIsolatePauseMode( - isolateId, - exceptionPauseMode: ExceptionPauseMode.kNone, - ), - _isSuccess, - ); - await expectLater( - service.setIsolatePauseMode(isolateId, exceptionPauseMode: 'invalid'), - throwsRPCError, - ); - }); - - test('setFlag', () async { - final service = context.service; - await expectLater(service.setFlag('', ''), throwsRPCError); - }); - - test('setLibraryDebuggable', () async { - final service = context.service; - await expectLater( - service.setLibraryDebuggable('', '', false), - throwsRPCError, - ); - }); - - test('setName', () async { - final service = context.service; - final vm = await service.getVM(); - final isolateId = vm.isolates!.first.id!; - expect(service.setName(isolateId, 'test'), completion(_isSuccess)); - final isolate = await service.getIsolate(isolateId); - expect(isolate.name, 'test'); - }); - - test('setVMName', () async { - final service = context.service; - expect(service.setVMName('foo'), completion(_isSuccess)); - final vm = await service.getVM(); - expect(vm.name, 'foo'); - }); - - test('streamCancel', () async { - final service = context.service; - await expectLater(service.streamCancel(''), throwsRPCError); - }); - - group('setFlag', () { - test('pause_isolates_on_start set to true', () { - final service = context.service; - expect( - service.setFlag('pause_isolates_on_start', 'true'), - completion(_isSuccess), - ); - expect(context.service.pauseIsolatesOnStart, equals(true)); - }); - - test('pause_isolates_on_start set to false', () { - final service = context.service; - expect( - service.setFlag('pause_isolates_on_start', 'false'), - completion(_isSuccess), - ); - expect(context.service.pauseIsolatesOnStart, equals(false)); - }); - - test('pause_isolates_on_start set to invalid value', () { - final service = context.service; - expect( - service.setFlag('pause_isolates_on_start', 'pizza'), - throwsRPCError, - ); - }); - }); - - group('getFlagList', () { - List stringifyFlags(FlagList flagList) { - return flagList.flags - ?.map((flag) => '${flag.name} -> ${flag.valueAsString}') - .toList() ?? - []; - } - - test('returns expected default values', () async { - final service = context.service; - final flagList = await service.getFlagList(); - expect( - stringifyFlags(flagList), - containsAll(['pause_isolates_on_start -> false']), - ); - }); - - test('returns any modified flag values', () async { - final service = context.service; - await service.setFlag('pause_isolates_on_start', 'true'); - final flagList = await service.getFlagList(); - expect( - stringifyFlags(flagList), - containsAll(['pause_isolates_on_start -> true']), - ); - }); - }); - - group('streamListen/onEvent', () { - late ChromeProxyService service; - - group('Debug', () { - late Stream eventStream; - - setUp(() async { - setCurrentLogWriter(debug: provider.verbose); - service = context.service; - expect( - await service.streamListen('Debug'), - const TypeMatcher(), - ); - eventStream = service.onEvent('Debug'); - }); - - test('basic Pause/Resume', () async { - expect(service.streamListen('Debug'), completion(_isSuccess)); - final stream = service.onEvent('Debug'); - safeUnawaited(context.tabConnection.debugger.pause()); - await expectLater( - stream, - emitsThrough( - const TypeMatcher().having( - (e) => e.kind, - 'kind', - EventKind.kPauseInterrupted, - ), - ), - ); - safeUnawaited(context.tabConnection.debugger.resume()); - expect( - eventStream, - emitsThrough( - const TypeMatcher().having( - (e) => e.kind, - 'kind', - EventKind.kResume, - ), - ), - ); - }); - - test('Inspect', () async { - expect( - eventStream, - emitsThrough( - const TypeMatcher() - .having((e) => e.kind, 'kind', EventKind.kInspect) - .having( - (e) => e.inspectee, - 'inspectee', - const TypeMatcher() - .having((instance) => instance.id, 'id', isNotNull) - .having( - (instance) => instance.kind, - 'inspectee.kind', - InstanceKind.kPlainInstance, - ), - ), - ), - ); - await context.tabConnection.runtime.evaluate('inspectInstance()'); - }); - }); - - group('Extension', () { - late VmServiceInterface service; - late Stream eventStream; - - setUp(() async { - setCurrentLogWriter(debug: provider.verbose); - service = context.service; - expect( - await service.streamListen('Extension'), - const TypeMatcher(), - ); - eventStream = service.onEvent('Extension'); - }); - - test('Custom debug event', () async { - final eventKind = 'my.custom.event'; - expect( - eventStream, - emitsThrough( - predicate( - (Event event) => - event.kind == EventKind.kExtension && - event.extensionKind == eventKind && - event.extensionData!.data['example'] == 'data', - ), - ), - ); - await context.tabConnection.runtime.evaluate( - "postEvent('$eventKind');", - ); - }); - - test('Batched debug events from injected client', () async { - final eventKind = EventKind.kExtension; - final extensionKind = 'MyEvent'; - final eventData = 'eventData'; - final delay = const Duration(milliseconds: 2000); - - TypeMatcher eventMatcher(String data) => - const TypeMatcher() - .having((event) => event.kind, 'kind', eventKind) - .having( - (event) => event.extensionKind, - 'extensionKind', - extensionKind, - ) - .having( - (event) => event.extensionData!.data['eventData'], - 'eventData', - data, - ); - - String emitDebugEvent(String data) => - '\$emitDebugEvent("$extensionKind", ' - '\'{"$eventData": "$data"}\');'; - - final size = 2; - final batch1 = List.generate(size, (int i) => 'data$i'); - final batch2 = List.generate(size, (int i) => 'data${size + i}'); - - expect( - eventStream, - emitsInOrder([ - ...batch1.map(eventMatcher), - ...batch2.map(eventMatcher), - ]), - ); - - for (final data in batch1) { - await context.tabConnection.runtime.evaluate(emitDebugEvent(data)); - } - await Future.delayed(delay); - for (final data in batch2) { - await context.tabConnection.runtime.evaluate(emitDebugEvent(data)); - } - }); - }); - - test('GC', () async { - expect(service.streamListen('GC'), completion(_isSuccess)); - }); - - group('Isolate', () { - late Stream isolateEventStream; - - setUp(() async { - expect(await service.streamListen(EventStreams.kIsolate), _isSuccess); - isolateEventStream = service.onEvent(EventStreams.kIsolate); - }); - - test('serviceExtensionAdded', () async { - final extensionMethod = 'ext.foo.bar'; - expect( - isolateEventStream, - emitsThrough( - predicate( - (Event event) => - event.kind == EventKind.kServiceExtensionAdded && - event.extensionRPC == extensionMethod, - ), - ), - ); - await context.tabConnection.runtime.evaluate( - "registerExtension('$extensionMethod');", - ); - }); - - test('lifecycle events', () async { - final vm = await service.getVM(); - final initialIsolateId = vm.isolates!.first.id; - final eventsDone = expectLater( - isolateEventStream, - emitsThrough( - emitsInOrder([ - predicate( - (Event event) => - event.kind == EventKind.kIsolateExit && - event.isolate!.id == initialIsolateId, - ), - predicate( - (Event event) => - event.kind == EventKind.kIsolateStart && - event.isolate!.id != initialIsolateId, - ), - predicate( - (Event event) => - event.kind == EventKind.kIsolateRunnable && - event.isolate!.id != initialIsolateId, - ), - ]), - ), - ); - service.destroyIsolate(); - await service.createIsolate(context.appConnection); - await eventsDone; - expect( - (await service.getVM()).isolates!.first.id, - isNot(initialIsolateId), - ); - }); - - test('RegisterExtension events from injected client', () async { - final eventKind = EventKind.kServiceExtensionAdded; - final extensions = List.generate(10, (index) => 'extension$index'); - - TypeMatcher eventMatcher(String extension) => - const TypeMatcher() - .having((event) => event.kind, 'kind', eventKind) - .having((event) => event.extensionRPC, 'RPC', extension); - - String emitRegisterEvent(String extension) => - "\$emitRegisterEvent('$extension')"; - - expect( - isolateEventStream, - emitsInOrder(extensions.map(eventMatcher)), - ); - for (final extension in extensions) { - await context.tabConnection.runtime.evaluate( - emitRegisterEvent(extension), - ); - } - }); - }); - - test('Timeline', () async { - expect(service.streamListen('Timeline'), completion(_isSuccess)); - }); - - test('Stdout', () async { - expect(service.streamListen('Stdout'), completion(_isSuccess)); - expect( - service.onEvent('Stdout'), - emitsThrough( - predicate( - (Event event) => - event.kind == EventKind.kWriteEvent && - String.fromCharCodes(base64.decode(event.bytes!)) - .contains('hello'), - ), - ), - ); - await context.tabConnection.runtime.evaluate('console.log("hello");'); - }); - - test('Stderr', () async { - expect(service.streamListen('Stderr'), completion(_isSuccess)); - final stderrStream = service.onEvent('Stderr'); - expect( - stderrStream, - emitsThrough( - predicate( - (Event event) => - event.kind == EventKind.kWriteEvent && - String.fromCharCodes(base64.decode(event.bytes!)) - .contains('Error'), - ), - ), - ); - await context.tabConnection.runtime.evaluate('console.error("Error");'); - }); - - test('exception stack trace mapper', () async { - expect(service.streamListen('Stderr'), completion(_isSuccess)); - final stderrStream = service.onEvent('Stderr'); - expect( - stderrStream, - emitsThrough( - predicate( - (Event event) => - event.kind == EventKind.kWriteEvent && - String.fromCharCodes(base64.decode(event.bytes!)) - .contains('main.dart'), - ), - ), - ); - await context.tabConnection.runtime.evaluate( - 'throwUncaughtException();', - ); - }); - - test('VM', () async { - final status = await service.streamListen('VM'); - expect(status, _isSuccess); - final stream = service.onEvent('VM'); - expect( - stream, - emitsThrough( - predicate( - (Event e) => - e.kind == EventKind.kVMUpdate && e.vm!.name == 'test', - ), - ), - ); - await service.setVMName('test'); - }); - - test('custom stream', () { - expect( - () => service.streamListen('aCustomStreamId'), - throwsA( - predicate( - (e) => - (e is RPCError) && e.code == RPCErrorKind.kInvalidParams.code, - ), - ), - ); - }); - }); - - group('Logging |', () { - test('logging stream is registered', () { - final service = context.service; - expect( - service.streamListen(EventStreams.kLogging), - completion(_isSuccess), - ); - }); - - test( - 'dart:developer logs are correctly converted to log records', - () async { - final logStream = context.service.onEvent(EventStreams.kLogging); - final message = 'myMessage'; - - safeUnawaited( - context.tabConnection.runtime.evaluate("sendLog('$message');"), - ); - - final event = await logStream.first; - expect(event.kind, EventKind.kLogging); - - final logRecord = event.logRecord!; - expect(logRecord.message!.valueAsString, message); - expect(logRecord.loggerName!.valueAsString, 'testLogCategory'); - }, - ); - - test('long dart:developer log messages are not truncated', () async { - final logStream = context.service.onEvent(EventStreams.kLogging); - final longMessage = - 'A very long log message that Chrome truncates by default and ' - 'requires users to expand in order to see the entire message.'; - safeUnawaited( - context.tabConnection.runtime.evaluate("sendLog('$longMessage');"), - ); - - final event = await logStream.first; - expect(event.logRecord!.message!.valueAsString, longMessage); - }); - }); - }); -} - -final _isSuccess = isA(); - -TypeMatcher _libRef(Object? uriMatcher) => - isA().having((LibraryRef l) => l.uri, 'uri', uriMatcher); - -void expectEventually(Matcher expectation) {} diff --git a/dwds/test/integration/common/hot_restart_common.dart b/dwds/test/integration/common/hot_restart_common.dart deleted file mode 100644 index 9d0dff7c23..0000000000 --- a/dwds/test/integration/common/hot_restart_common.dart +++ /dev/null @@ -1,658 +0,0 @@ -// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@Tags(['daily']) -@TestOn('vm') -@Timeout(Duration(minutes: 5)) -library; - -import 'dart:async'; - -import 'package:dwds/dwds.dart'; -import 'package:dwds/expression_compiler.dart'; -import 'package:dwds_test_common/logging.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; -import 'package:vm_service/vm_service.dart'; - -import '../fixtures/context.dart'; -import '../fixtures/project.dart'; -import '../fixtures/utilities.dart'; - -const originalString = 'Hello World!'; -const newString = 'Bonjour le monde!'; - -void runTests({ - required TestSdkConfigurationProvider provider, - required ModuleFormat moduleFormat, - required CompilationMode compilationMode, - required bool canaryFeatures, -}) { - final context = TestContext(TestProject.testAppendBody, provider); - - tearDownAll(provider.dispose); - - Future recompile({bool hasEdits = false}) async { - if (compilationMode == CompilationMode.frontendServer) { - await context.recompile(fullRestart: true); - } else { - assert(compilationMode == CompilationMode.buildDaemon); - if (hasEdits) { - // Only gets a new build if there were edits. - await context.waitForSuccessfulBuild(); - } - } - } - - Future makeEditAndRecompile() async { - await context.makeEdits([ - ( - file: context.project.dartEntryFileName, - originalString: originalString, - newString: newString, - ), - ]); - await recompile(hasEdits: true); - } - - // Wait for `expectedStrings` to be printed to the console. - Future waitForLogs(List expectedStrings) async { - final expectations = List.from(expectedStrings); - final completer = Completer(); - final subscription = context.webkitDebugger.onConsoleAPICalled.listen((e) { - final value = e.args.first.value; - if (expectations.contains(value)) { - expectations.remove(value); - if (expectations.isEmpty) { - completer.complete(); - } - } - }); - await completer.future.timeout( - const Duration(minutes: 1), - onTimeout: () { - throw TimeoutException( - 'Failed to find logs: $expectedStrings in console.', - ); - }, - ); - await subscription.cancel(); - } - - group( - 'Injected client with live reload', - () { - group('and with debugging', () { - setUp(() async { - setCurrentLogWriter(debug: provider.verbose); - await context.setUp( - testSettings: TestSettings( - reloadConfiguration: ReloadConfiguration.liveReload, - compilationMode: compilationMode, - moduleFormat: provider.ddcModuleFormat, - canaryFeatures: provider.canaryFeatures, - ), - ); - }); - - tearDown(() async { - await context.tearDown(); - }); - - test('can live reload changes ', () async { - // A full reload should clear the state. - final logFuture = waitForLogs([newString]); - await makeEditAndRecompile(); - await logFuture; - }); - }); - - group('and without debugging', () { - setUp(() async { - setCurrentLogWriter(debug: provider.verbose); - await context.setUp( - testSettings: TestSettings( - reloadConfiguration: ReloadConfiguration.liveReload, - compilationMode: compilationMode, - moduleFormat: provider.ddcModuleFormat, - canaryFeatures: provider.canaryFeatures, - ), - debugSettings: const TestDebugSettings.noDevToolsLaunch().copyWith( - enableDebugging: false, - ), - ); - }); - - tearDown(() async { - await context.tearDown(); - }); - - test('can live reload changes ', () async { - // A full reload should clear the state. - final logFuture = waitForLogs([newString]); - await makeEditAndRecompile(); - await logFuture; - }); - }); - - group('and without debugging using WebSockets', () { - setUp(() async { - setCurrentLogWriter(debug: provider.verbose); - await context.setUp( - testSettings: TestSettings( - reloadConfiguration: ReloadConfiguration.liveReload, - compilationMode: compilationMode, - moduleFormat: provider.ddcModuleFormat, - canaryFeatures: provider.canaryFeatures, - ), - debugSettings: const TestDebugSettings.noDevToolsLaunch().copyWith( - enableDebugging: false, - useSse: false, - ), - ); - }); - - tearDown(() async { - await context.tearDown(); - }); - - test('can live reload changes ', () async { - // A full reload should clear the state. - final logFuture = waitForLogs([newString]); - await makeEditAndRecompile(); - await logFuture; - }); - }); - }, - // `BuildResult`s are only ever emitted when using the build daemon. - skip: compilationMode == CompilationMode.buildDaemon ? null : true, - timeout: const Timeout.factor(2), - ); - - group('Injected client', () { - late VmService fakeClient; - - setUp(() async { - setCurrentLogWriter(debug: provider.verbose); - await context.setUp( - testSettings: TestSettings( - enableExpressionEvaluation: true, - compilationMode: compilationMode, - moduleFormat: provider.ddcModuleFormat, - canaryFeatures: provider.canaryFeatures, - ), - ); - fakeClient = await context.connectFakeClient(); - }); - - tearDown(() async { - await context.tearDown(); - }); - - test('destroys and recreates the isolate during a hot restart', () async { - final client = context.debugConnection.vmService; - await client.streamListen('Isolate'); - await makeEditAndRecompile(); - - final eventsDone = expectLater( - client.onIsolateEvent, - emitsThrough( - emitsInOrder([ - _hasKind(EventKind.kIsolateExit), - _hasKind(EventKind.kIsolateStart), - _hasKind(EventKind.kIsolateRunnable), - ]), - ), - ); - - final hotRestart = context.getRegisteredServiceExtension('hotRestart'); - expect( - await fakeClient.callServiceExtension(hotRestart!), - const TypeMatcher(), - ); - - await eventsDone; - }); - - test('can execute simultaneous hot restarts', () async { - final client = context.debugConnection.vmService; - await client.streamListen('Isolate'); - await makeEditAndRecompile(); - - final eventsDone = expectLater( - client.onIsolateEvent, - emitsThrough( - emitsInOrder([ - _hasKind(EventKind.kIsolateExit), - _hasKind(EventKind.kIsolateStart), - _hasKind(EventKind.kIsolateRunnable), - ]), - ), - ); - - // Execute two hot restart calls in parallel. - final hotRestart = context.getRegisteredServiceExtension('hotRestart'); - final done = Future.wait([ - fakeClient.callServiceExtension(hotRestart!), - fakeClient.callServiceExtension(hotRestart), - ]); - expect(await done, [ - const TypeMatcher(), - const TypeMatcher(), - ]); - - // The debugger is still working. - final vm = await client.getVM(); - final isolateId = vm.isolates!.first.id!; - final isolate = await client.getIsolate(isolateId); - final library = isolate.rootLib!.uri!; - - final result = await client.evaluate(isolateId, library, 'true'); - expect( - result, - isA().having( - (instance) => instance.valueAsString, - 'valueAsString', - 'true', - ), - ); - - await eventsDone; - }); - - test('destroys and recreates the isolate during a page refresh', () async { - final client = context.debugConnection.vmService; - await client.streamListen('Isolate'); - await makeEditAndRecompile(); - - final eventsDone = expectLater( - client.onIsolateEvent, - emitsThrough( - emitsInOrder([ - _hasKind(EventKind.kIsolateExit), - _hasKind(EventKind.kIsolateStart), - _hasKind(EventKind.kIsolateRunnable), - ]), - ), - ); - - await context.webDriver.driver.refresh(); - - await eventsDone; - }); - - test('can hot restart via the service extension', () async { - final client = context.debugConnection.vmService; - await client.streamListen('Isolate'); - await makeEditAndRecompile(); - - final eventsDone = expectLater( - client.onIsolateEvent, - emitsThrough( - emitsInOrder([ - _hasKind(EventKind.kIsolateExit), - _hasKind(EventKind.kIsolateStart), - _hasKind(EventKind.kIsolateRunnable), - ]), - ), - ); - // Main is re-invoked which shouldn't clear the state. - final logFuture = waitForLogs(['$originalString $newString']); - final hotRestart = context.getRegisteredServiceExtension('hotRestart'); - expect( - await fakeClient.callServiceExtension(hotRestart!), - const TypeMatcher(), - ); - - await eventsDone; - await logFuture; - }); - - test('can send events before and after hot restart', () async { - final client = context.debugConnection.vmService; - await client.streamListen('Isolate'); - - // The event just before hot restart might never be received, - // but the injected client continues to work and send events - // after hot restart. - final eventsDone = expectLater( - client.onIsolateEvent, - emitsThrough( - _hasKind(EventKind.kServiceExtensionAdded) - .having((e) => e.extensionRPC, 'service', 'ext.bar'), - ), - ); - - var vm = await client.getVM(); - var isolateId = vm.isolates!.first.id!; - var isolate = await client.getIsolate(isolateId); - var library = isolate.rootLib!.uri!; - - final callback = '(_, __) async => ServiceExtensionResponse.result("")'; - - await client.evaluate( - isolateId, - library, - "registerExtension('ext.foo', $callback)", - ); - - await recompile(); - // Main is re-invoked which shouldn't clear the state. - final logFuture = waitForLogs(['$originalString $originalString']); - final hotRestart = context.getRegisteredServiceExtension('hotRestart'); - expect( - await fakeClient.callServiceExtension(hotRestart!), - const TypeMatcher(), - ); - - vm = await client.getVM(); - isolateId = vm.isolates!.first.id!; - isolate = await client.getIsolate(isolateId); - library = isolate.rootLib!.uri!; - - await client.evaluate( - isolateId, - library, - "registerExtension('ext.bar', $callback)", - ); - - await eventsDone; - await logFuture; - }); - - test('can refresh the page via the fullReload service extension', () async { - final client = context.debugConnection.vmService; - await client.streamListen('Isolate'); - await makeEditAndRecompile(); - - final eventsDone = expectLater( - client.onIsolateEvent, - emitsThrough( - emitsInOrder([ - _hasKind(EventKind.kIsolateExit), - _hasKind(EventKind.kIsolateStart), - _hasKind(EventKind.kIsolateRunnable), - ]), - ), - ); - // Should see only the new text. - final logFuture = waitForLogs([newString]); - final fullReload = context.getRegisteredServiceExtension('fullReload'); - expect( - await fakeClient.callServiceExtension(fullReload!), - isA(), - ); - - await eventsDone; - await logFuture; - }); - - test('can hot restart while paused', () async { - final client = context.debugConnection.vmService; - var vm = await client.getVM(); - var isolateId = vm.isolates!.first.id!; - await client.streamListen('Debug'); - final stream = client.onDebugEvent; - final scriptList = await client.getScripts(isolateId); - final main = scriptList.scripts!.firstWhere( - (script) => script.uri!.contains('main.dart'), - ); - final bpLine = await context.findBreakpointLine( - 'printCount', - isolateId, - main, - ); - await client.addBreakpoint(isolateId, main.id!, bpLine); - await stream.firstWhere( - (event) => event.kind == EventKind.kPauseBreakpoint, - ); - - await makeEditAndRecompile(); - // Main is re-invoked which shouldn't clear the state. - final logFuture = waitForLogs(['$originalString $newString']); - final hotRestart = context.getRegisteredServiceExtension('hotRestart'); - await fakeClient.callServiceExtension(hotRestart!); - await logFuture; - - vm = await client.getVM(); - isolateId = vm.isolates!.first.id!; - final isolate = await client.getIsolate(isolateId); - - // Previous breakpoint should be cleared. - expect(isolate.breakpoints!.isEmpty, isTrue); - }); - - test('can evaluate expressions after hot restart', () async { - final client = context.debugConnection.vmService; - - await recompile(); - final hotRestart = context.getRegisteredServiceExtension('hotRestart'); - await fakeClient.callServiceExtension(hotRestart!); - - final vm = await client.getVM(); - final isolateId = vm.isolates!.first.id!; - final isolate = await client.getIsolate(isolateId); - final library = isolate.rootLib!.uri!; - - // Expression evaluation while running should work. - final result = await client.evaluate(isolateId, library, 'true'); - expect( - result, - isA().having( - (instance) => instance.valueAsString, - 'valueAsString', - 'true', - ), - ); - }); - - test('can hot restart with no changes, hot restart with changes, and ' - 'hot restart again with no changes', () async { - // Empty hot restart. - var logFuture = waitForLogs(['$originalString $originalString']); - await recompile(); - final hotRestart = context.getRegisteredServiceExtension('hotRestart'); - await fakeClient.callServiceExtension(hotRestart!); - await logFuture; - - // Hot restart. - logFuture = waitForLogs(['$originalString $originalString $newString']); - await makeEditAndRecompile(); - await fakeClient.callServiceExtension(hotRestart); - await logFuture; - - // Empty hot restart. - logFuture = waitForLogs([ - '$originalString $originalString $newString $newString', - ]); - await recompile(); - await fakeClient.callServiceExtension(hotRestart); - await logFuture; - }); - }, timeout: const Timeout.factor(2)); - - group( - 'Injected client with hot restart', - () { - group('and with debugging', () { - setUp(() async { - setCurrentLogWriter(debug: provider.verbose); - await context.setUp( - testSettings: TestSettings( - reloadConfiguration: ReloadConfiguration.hotRestart, - compilationMode: compilationMode, - moduleFormat: provider.ddcModuleFormat, - canaryFeatures: provider.canaryFeatures, - ), - ); - }); - - tearDown(() async { - await context.tearDown(); - }); - - test('can hot restart changes ', () async { - // Main is re-invoked which shouldn't clear the state. - final logFutures = waitForLogs([ - '$originalString $newString', - // The ext.flutter.disassemble callback is invoked and waited for. - 'start disassemble', - 'end disassemble', - ]); - await makeEditAndRecompile(); - await logFutures; - }); - - test( - 'fires isolate create/destroy events during hot restart', - () async { - final client = context.debugConnection.vmService; - await client.streamListen('Isolate'); - - final eventsDone = expectLater( - client.onIsolateEvent, - emitsThrough( - emitsInOrder([ - _hasKind(EventKind.kIsolateExit), - _hasKind(EventKind.kIsolateStart), - _hasKind(EventKind.kIsolateRunnable), - ]), - ), - ); - - await makeEditAndRecompile(); - - await eventsDone; - }, - ); - }); - - group('and without debugging', () { - setUp(() async { - setCurrentLogWriter(debug: provider.verbose); - await context.setUp( - testSettings: TestSettings( - reloadConfiguration: ReloadConfiguration.hotRestart, - compilationMode: compilationMode, - moduleFormat: provider.ddcModuleFormat, - canaryFeatures: provider.canaryFeatures, - ), - debugSettings: const TestDebugSettings.noDevToolsLaunch().copyWith( - enableDebugging: false, - ), - ); - }); - - tearDown(() async { - await context.tearDown(); - }); - - test('can hot restart changes ', () async { - // Main is re-invoked which shouldn't clear the state. - final logFutures = waitForLogs([ - '$originalString $newString', - // The ext.flutter.disassemble callback is invoked and waited for. - 'start disassemble', - 'end disassemble', - ]); - await makeEditAndRecompile(); - await logFutures; - }); - }); - }, - // `BuildResult`s are only ever emitted when using the build daemon. - skip: compilationMode == CompilationMode.buildDaemon ? null : true, - timeout: const Timeout.factor(2), - ); - - group('when isolates_paused_on_start is true', () { - late VmService client; - late VmService fakeClient; - - setUp(() async { - setCurrentLogWriter(debug: provider.verbose); - await context.setUp( - testSettings: TestSettings( - enableExpressionEvaluation: true, - compilationMode: compilationMode, - moduleFormat: provider.ddcModuleFormat, - canaryFeatures: provider.canaryFeatures, - ), - ); - client = context.debugConnection.vmService; - fakeClient = await context.connectFakeClient(); - await client.setFlag('pause_isolates_on_start', 'true'); - await client.streamListen('Isolate'); - }); - - tearDown(() async { - await context.tearDown(); - }); - - test( - 'after hot-restart, does not run app until there is a resume event', - () async { - await makeEditAndRecompile(); - - final eventsDone = expectLater( - client.onIsolateEvent, - emitsThrough( - emitsInOrder([ - _hasKind(EventKind.kIsolateExit), - _hasKind(EventKind.kIsolateStart), - _hasKind(EventKind.kIsolateRunnable), - ]), - ), - ); - - // Main is re-invoked which shouldn't clear the state. - final logFuture = waitForLogs(['$originalString $newString']); - final hotRestart = context.getRegisteredServiceExtension('hotRestart'); - expect( - await fakeClient.callServiceExtension(hotRestart!), - const TypeMatcher(), - ); - - await eventsDone; - - final vm = await client.getVM(); - final isolateId = vm.isolates!.first.id!; - await client.resume(isolateId); - - await logFuture; - }, - ); - - test( - 'after page refresh, does not run app until there is a resume event', - () async { - final logFuture = waitForLogs([newString]); - await makeEditAndRecompile(); - await context.webDriver.driver.refresh(); - - final eventsDone = expectLater( - client.onIsolateEvent, - emitsThrough( - emitsInOrder([ - _hasKind(EventKind.kIsolateExit), - _hasKind(EventKind.kIsolateStart), - _hasKind(EventKind.kIsolateRunnable), - ]), - ), - ); - - await eventsDone; - - final vm = await client.getVM(); - final isolateId = vm.isolates!.first.id!; - await client.resume(isolateId); - - await logFuture; - }, - ); - }); -} - -TypeMatcher _hasKind(String kind) => - isA().having((e) => e.kind, 'kind', kind); diff --git a/dwds/test/integration/common/hot_restart_correctness_common.dart b/dwds/test/integration/common/hot_restart_correctness_common.dart deleted file mode 100644 index dc37269678..0000000000 --- a/dwds/test/integration/common/hot_restart_correctness_common.dart +++ /dev/null @@ -1,208 +0,0 @@ -// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@Tags(['daily']) -@TestOn('vm') -@Timeout(Duration(minutes: 5)) -library; - -import 'dart:async'; - -import 'package:dwds/dwds.dart'; -import 'package:dwds/expression_compiler.dart'; -import 'package:dwds_test_common/logging.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; -import 'package:vm_service/vm_service.dart'; - -import '../fixtures/context.dart'; -import '../fixtures/project.dart'; -import '../fixtures/utilities.dart'; - -const originalString = 'variableToModifyToForceRecompile = 23'; -const newString = 'variableToModifyToForceRecompile = 45'; - -const constantSuccessString = 'ConstantEqualitySuccess'; -const constantFailureString = 'ConstantEqualityFailure'; - -void runTests({ - required TestSdkConfigurationProvider provider, - required ModuleFormat moduleFormat, - required CompilationMode compilationMode, - required bool canaryFeatures, -}) { - tearDownAll(provider.dispose); - - final testHotRestart2 = TestProject.testHotRestart2; - final context = TestContext(testHotRestart2, provider); - - Future makeEditAndRecompile() async { - await context.makeEdits([ - ( - file: 'library2.dart', - originalString: originalString, - newString: newString, - ), - ]); - if (compilationMode == CompilationMode.frontendServer) { - await context.recompile(fullRestart: true); - } else { - assert(compilationMode == CompilationMode.buildDaemon); - await context.waitForSuccessfulBuild(propagateToBrowser: true); - } - } - - // Wait for `expectedString` to be printed to the console. - Future waitForLog(String expectedString) async { - final completer = Completer(); - final subscription = context.webkitDebugger.onConsoleAPICalled.listen((e) { - if (e.args.first.value == expectedString) { - completer.complete(); - } - }); - await completer.future.timeout( - const Duration(minutes: 1), - onTimeout: () { - throw TimeoutException( - "Failed to find log: '$expectedString' in console.", - ); - }, - ); - await subscription.cancel(); - } - - group('Injected client', () { - VmService? fakeClient; - - setUp(() async { - setCurrentLogWriter(debug: provider.verbose); - await context.setUp( - testSettings: TestSettings( - enableExpressionEvaluation: true, - compilationMode: compilationMode, - moduleFormat: provider.ddcModuleFormat, - canaryFeatures: provider.canaryFeatures, - ), - ); - - fakeClient = await context.connectFakeClient(); - }); - - tearDown(() async { - await context.tearDown(); - }); - - test('initial state prints the right log', () async { - final client = context.debugConnection.vmService; - - final logFuture = waitForLog( - 'ConstObject(reloadVariable: 23, ConstantEqualitySuccess)', - ); - final vm = await client.getVM(); - final isolate = await client.getIsolate(vm.isolates!.first.id!); - final rootLib = isolate.rootLib; - await client.evaluate(isolate.id!, rootLib!.id!, 'printConst()'); - await logFuture; - }); - - test( - 'properly compares constants after hot restart via the service extension', - () async { - final client = context.debugConnection.vmService; - await client.streamListen('Isolate'); - - await makeEditAndRecompile(); - - final eventsDone = expectLater( - client.onIsolateEvent, - emitsThrough( - emitsInOrder([ - _hasKind(EventKind.kIsolateExit), - _hasKind(EventKind.kIsolateStart), - _hasKind(EventKind.kIsolateRunnable), - ]), - ), - ); - - final logFuture = waitForLog( - 'ConstObject(reloadVariable: 45, ConstantEqualitySuccess)', - ); - final hotRestart = context.getRegisteredServiceExtension('hotRestart'); - expect( - await fakeClient!.callServiceExtension(hotRestart!), - const TypeMatcher(), - ); - - await eventsDone; - await logFuture; - }, - ); - }, timeout: const Timeout.factor(2)); - - group( - 'Injected client with hot restart', - () { - group('and with debugging', () { - setUp(() async { - setCurrentLogWriter(debug: provider.verbose); - await context.setUp( - testSettings: TestSettings( - reloadConfiguration: ReloadConfiguration.hotRestart, - compilationMode: compilationMode, - moduleFormat: provider.ddcModuleFormat, - canaryFeatures: provider.canaryFeatures, - ), - ); - }); - - tearDown(() async { - await context.tearDown(); - }); - - test('properly compares constants after hot restart', () async { - final logFuture = waitForLog( - 'ConstObject(reloadVariable: 45, ConstantEqualitySuccess)', - ); - await makeEditAndRecompile(); - await logFuture; - }); - }); - - group('and without debugging', () { - setUp(() async { - setCurrentLogWriter(debug: provider.verbose); - await context.setUp( - testSettings: TestSettings( - reloadConfiguration: ReloadConfiguration.hotRestart, - compilationMode: compilationMode, - moduleFormat: provider.ddcModuleFormat, - canaryFeatures: provider.canaryFeatures, - ), - debugSettings: const TestDebugSettings.noDevToolsLaunch().copyWith( - enableDebugging: false, - ), - ); - }); - - tearDown(() async { - await context.tearDown(); - }); - - test('properly compares constants after hot restart', () async { - final logFuture = waitForLog( - 'ConstObject(reloadVariable: 45, ConstantEqualitySuccess)', - ); - await makeEditAndRecompile(); - await logFuture; - }); - }); - }, - // `BuildResult`s are only ever emitted when using the build daemon. - skip: compilationMode == CompilationMode.buildDaemon ? null : true, - timeout: const Timeout.factor(2), - ); -} - -TypeMatcher _hasKind(String kind) => - isA().having((e) => e.kind, 'kind', kind); diff --git a/dwds/test/integration/dart_uri_file_uri_test.dart b/dwds/test/integration/dart_uri_file_uri_test.dart deleted file mode 100644 index c06a40cc7d..0000000000 --- a/dwds/test/integration/dart_uri_file_uri_test.dart +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@TestOn('vm') -@Timeout(Duration(minutes: 2)) -library; - -import 'package:dwds/src/utilities/dart_uri.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:path/path.dart' as p; -import 'package:test/test.dart'; - -import 'fixtures/context.dart'; -import 'fixtures/project.dart'; -import 'fixtures/utilities.dart'; - -// This tests converting file Uris into our internal paths. -// -// These tests are separated out because we need a running isolate in order to -// look up packages. -void main() { - final provider = TestSdkConfigurationProvider(); - tearDownAll(provider.dispose); - - final testProject = TestProject.test; - final testPackageProject = TestProject.testPackage(); - - final context = TestContext(testPackageProject, provider); - - for (final compilationMode in CompilationMode.values.where( - (mode) => !mode.usesDdcModulesOnly, - )) { - group('$compilationMode |', () { - for (final useDebuggerModuleNames in [false, true]) { - group('Debugger module names: $useDebuggerModuleNames |', () { - final appServerPath = compilationMode.usesFrontendServer - ? 'web/main.dart' - : 'main.dart'; - - final serverPath = - compilationMode.usesFrontendServer && useDebuggerModuleNames - ? 'packages/${testPackageProject.packageDirectory}/lib/test_library.dart' - : 'packages/${testPackageProject.packageName}/test_library.dart'; - - final anotherServerPath = - compilationMode.usesFrontendServer && useDebuggerModuleNames - ? 'packages/${testProject.packageDirectory}/lib/library.dart' - : 'packages/${testProject.packageName}/library.dart'; - - setUpAll(() async { - await context.setUp( - testSettings: TestSettings( - compilationMode: compilationMode, - useDebuggerModuleNames: useDebuggerModuleNames, - ), - ); - }); - - tearDownAll(() async { - await context.tearDown(); - }); - - test('file path to org-dartlang-app', () { - final webMain = Uri.file( - p.join( - // The directory for the _testPackage package which imports - // _test. - testPackageProject.absolutePackageDirectory, - 'web', - 'main.dart', - ), - ); - final uri = DartUri('$webMain'); - expect(uri.serverPath, appServerPath); - }); - - test('file path to this package', () { - final testPackageLib = Uri.file( - p.join( - testPackageProject.absolutePackageDirectory, - 'lib', - 'test_library.dart', - ), - ); - final uri = DartUri('$testPackageLib'); - expect(uri.serverPath, serverPath); - }); - - test('file path to another package', () { - final testLib = Uri.file( - p.join( - // The directory for the general _test package. This is going to - // be relative to the project in the `TestContext`. - testPackageProject.absolutePackageDirectory, - '..', - testProject.packageDirectory, - 'lib', - 'library.dart', - ), - ); - final dartUri = DartUri('$testLib'); - expect(dartUri.serverPath, anotherServerPath); - }); - }); - } - }); - } -} diff --git a/dwds/test/integration/dart_uri_test.dart b/dwds/test/integration/dart_uri_test.dart deleted file mode 100644 index 9a0d5babdc..0000000000 --- a/dwds/test/integration/dart_uri_test.dart +++ /dev/null @@ -1,212 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@TestOn('vm') -@Timeout(Duration(minutes: 2)) -library; - -import 'package:dwds/src/utilities/dart_uri.dart'; -import 'package:dwds_test_common/logging.dart'; -import 'package:path/path.dart' as p; -import 'package:test/test.dart'; - -import 'fixtures/fakes.dart'; -import 'fixtures/utilities.dart'; - -class TestStrategy extends FakeStrategy { - TestStrategy(super.assetReader); - - @override - String? serverPathForAppUri(String appUrl) { - final appUri = Uri.parse(appUrl); - if (appUri.isScheme('org-dartlang-app')) { - return appUri.path; - } - if (appUri.isScheme('package')) { - return 'packages/${appUri.path}'; - } - if (appUri.isScheme('google3')) { - return appUri.path; - } - return null; - } -} - -class G3TestStrategy extends FakeStrategy { - G3TestStrategy(super.assetReader); - - @override - String? g3RelativePath(String absolutePath) => - 'g3:///${p.split(absolutePath).last}'; -} - -void main() { - group('DartUri', () { - setUpAll(() { - final toolConfiguration = TestToolConfiguration.withLoadStrategy( - loadStrategy: TestStrategy(FakeAssetReader()), - ); - setGlobalsForTesting(toolConfiguration: toolConfiguration); - }); - test('parses package : paths', () { - final uri = DartUri('package:path/path.dart'); - expect(uri.serverPath, 'packages/path/path.dart'); - }); - - test('parses package : paths with root', () { - final uri = DartUri('package:path/path.dart', 'foo/bar/blah'); - expect(uri.serverPath, 'foo/bar/blah/packages/path/path.dart'); - }); - - test('parses org-dartlang-app paths', () { - final uri = DartUri('org-dartlang-app:///blah/main.dart'); - expect(uri.serverPath, '/blah/main.dart'); - }); - - test('parses google3 paths', () { - final uri = DartUri('google3:///blah/main.dart'); - expect(uri.serverPath, '/blah/main.dart'); - }); - - test('parses packages paths', () { - final uri = DartUri('/packages/blah/foo.dart'); - expect(uri.serverPath, 'packages/blah/foo.dart'); - }); - - test('parses http paths', () { - final uri = DartUri('http://localhost:8080/web/main.dart'); - expect(uri.serverPath, 'web/main.dart'); - }); - - group('initialized with empty configuration', () { - setUpAll(() async { - await DartUri.initialize(); - DartUri.recordAbsoluteUris(['dart:io', 'dart:html']); - }); - - tearDownAll(DartUri.clear); - test('cannot resolve uris', () async { - final resolved = DartUri.toResolvedUri('dart:io'); - expect(resolved, isNull); - }); - }); - - group('initialized with current SDK directory', () { - setUpAll(() async { - await DartUri.initialize(); - DartUri.recordAbsoluteUris(['dart:io', 'dart:html']); - }); - - tearDownAll(DartUri.clear); - - test('can resolve uris', () { - final resolved = DartUri.toResolvedUri('dart:io'); - expect(resolved, 'org-dartlang-sdk:///sdk/lib/io/io.dart'); - }, skip: 'https://github.com/dart-lang/webdev/issues/1584'); - - test('can un-resolve uris', () { - final unresolved = DartUri.toPackageUri( - 'org-dartlang-sdk:///sdk/lib/io/io.dart', - ); - expect(unresolved, 'dart:io'); - }, skip: 'https://github.com/dart-lang/webdev/issues/1584'); - }); - - group('initialized with other SDK directory', () { - setUpAll(() async { - await DartUri.initialize(); - DartUri.recordAbsoluteUris(['dart:io', 'dart:html']); - }); - - tearDownAll(() async { - DartUri.clear(); - }); - - test('can resolve uris', () { - final resolved = DartUri.toResolvedUri('dart:io'); - expect(resolved, 'org-dartlang-sdk:///sdk/lib/io/io.dart'); - }, skip: 'https://github.com/dart-lang/webdev/issues/1584'); - - test('can unresolve uris', () { - final unresolved = DartUri.toPackageUri( - 'org-dartlang-sdk:///sdk/lib/io/io.dart', - ); - expect(unresolved, 'dart:io'); - }, skip: 'https://github.com/dart-lang/webdev/issues/1584'); - }); - - group('initialized with other SDK directory with no libraries spec', () { - final logs = []; - - void logWriter( - Object? level, - Object? message, { - String? error, - String? loggerName, - String? stackTrace, - }) { - final errorMessage = error == null ? '' : ':\n$error'; - final stackMessage = stackTrace == null ? '' : ':\n$stackTrace'; - logs.add( - '[$level] $loggerName: $message' - '$errorMessage' - '$stackMessage', - ); - } - - setUpAll(() async { - configureLogWriter(customLogWriter: logWriter); - await DartUri.initialize(); - DartUri.recordAbsoluteUris(['dart:io', 'dart:html']); - }); - - tearDownAll(() async { - DartUri.clear(); - }); - - test('cannot resolve uris', () { - final resolved = DartUri.toResolvedUri('dart:io'); - expect(resolved, null); - }, skip: 'https://github.com/dart-lang/webdev/issues/1584'); - - test('cannot unresolve uris', () { - final unresolved = DartUri.toPackageUri( - 'org-dartlang-sdk:///sdk/lib/io/io.dart', - ); - expect(unresolved, null); - }, skip: 'https://github.com/dart-lang/webdev/issues/1584'); - }); - }); - - group('initialized to handle g3-relative paths', () { - setUpAll(() async { - final toolConfiguration = TestToolConfiguration.withLoadStrategy( - loadStrategy: G3TestStrategy(FakeAssetReader()), - appMetadata: const TestAppMetadata.internalApp(), - ); - setGlobalsForTesting(toolConfiguration: toolConfiguration); - await DartUri.initialize(); - DartUri.recordAbsoluteUris(['package:path/path.dart']); - }); - - tearDownAll(DartUri.clear); - - test('can resolve g3-relative paths', () { - final resolved = DartUri.toPackageUri('g3:///path.dart'); - expect(resolved, 'package:path/path.dart'); - }); - - test('can resolve absolute file paths', () { - final absolute = 'file:///cloud/user/workspace/project/path.dart'; - final resolved = DartUri.toPackageUri(absolute); - expect(resolved, absolute); - }); - - test('can resolve absolute g3 paths', () { - final absolute = 'google3:///cloud/user/workspace/project/path.dart'; - final resolved = DartUri.toPackageUri(absolute); - expect(resolved, absolute); - }); - }); -} diff --git a/dwds/test/integration/dds_port_amd_test.dart b/dwds/test/integration/dds_port_amd_test.dart deleted file mode 100644 index 6fbbf45ec6..0000000000 --- a/dwds/test/integration/dds_port_amd_test.dart +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@TestOn('vm') -@Timeout(Duration(minutes: 2)) -library; - -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; - -import 'dds_port_common.dart'; - -void main() { - final provider = TestSdkConfigurationProvider(); - tearDownAll(provider.dispose); - - testAll(provider: provider); -} diff --git a/dwds/test/integration/dds_port_common.dart b/dwds/test/integration/dds_port_common.dart deleted file mode 100644 index 480f4e2024..0000000000 --- a/dwds/test/integration/dds_port_common.dart +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:io'; - -import 'package:dwds/dwds.dart'; -import 'package:dwds_test_common/logging.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; - -import 'fixtures/context.dart'; -import 'fixtures/project.dart'; -import 'fixtures/utilities.dart'; - -void testAll({required TestSdkConfigurationProvider provider}) { - late TestContext context; - - setUp(() { - setCurrentLogWriter(debug: provider.verbose); - context = TestContext(TestProject.test, provider); - }); - - tearDown(() async { - await context.tearDown(); - }); - - test('DWDS starts DDS with a specified port (deprecated)', () async { - // Find a unused port for the test. - final server = await HttpServer.bind(InternetAddress.loopbackIPv4, 0); - final expectedPort = server.port; - await server.close(); - - await context.setUp( - testSettings: TestSettings( - verboseCompiler: provider.verbose, - moduleFormat: provider.ddcModuleFormat, - canaryFeatures: provider.canaryFeatures, - ), - debugSettings: const TestDebugSettings.noDevToolsLaunch().copyWith( - ddsPort: expectedPort, - ), - ); - expect(Uri.parse(context.debugConnection.ddsUri!).port, expectedPort); - expect(context.debugConnection.dtdUri, isNotNull); - }); - - test('DWDS starts DDS with a specified port', () async { - // Find a unused port for the test. - final server = await HttpServer.bind(InternetAddress.loopbackIPv4, 0); - final expectedPort = server.port; - await server.close(); - - await context.setUp( - testSettings: TestSettings( - verboseCompiler: provider.verbose, - moduleFormat: provider.ddcModuleFormat, - canaryFeatures: provider.canaryFeatures, - ), - debugSettings: const TestDebugSettings.noDevToolsLaunch().copyWith( - ddsConfiguration: DartDevelopmentServiceConfiguration( - port: expectedPort, - ), - ), - ); - expect(Uri.parse(context.debugConnection.ddsUri!).port, expectedPort); - expect(context.debugConnection.dtdUri, isNotNull); - }); -} diff --git a/dwds/test/integration/debug_service_common.dart b/dwds/test/integration/debug_service_common.dart deleted file mode 100644 index 1dd3cce050..0000000000 --- a/dwds/test/integration/debug_service_common.dart +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:io'; - -import 'package:dwds/dwds.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; -import 'package:vm_service/vm_service.dart'; -import 'package:vm_service/vm_service_io.dart'; - -import 'fixtures/context.dart'; -import 'fixtures/project.dart'; -import 'fixtures/utilities.dart'; - -void testAll({required TestSdkConfigurationProvider provider}) { - final context = TestContext(TestProject.test, provider); - - setUpAll(() async { - // Disable DDS as we're testing DWDS behavior. - await context.setUp( - testSettings: TestSettings( - verboseCompiler: provider.verbose, - moduleFormat: provider.ddcModuleFormat, - canaryFeatures: provider.canaryFeatures, - ), - debugSettings: const TestDebugSettings.noDevToolsLaunch().copyWith( - spawnDds: false, - ddsConfiguration: const DartDevelopmentServiceConfiguration( - enable: false, - ), - ), - ); - }); - - tearDownAll(() async { - await context.tearDown(); - }); - - test('Refuses connections without the auth token', () async { - expect( - vmServiceConnectUri('ws://localhost:${context.debugConnection.port}/ws'), - throwsA(isA()), - ); - }); - - test('Accepts connections with the auth token', () async { - expect( - vmServiceConnectUri('${context.debugConnection.uri}/ws') - .then((client) => client.dispose()), - completes, - ); - }); - - test('Refuses additional connections when in single client mode', () async { - final fakeDds = await vmServiceConnectUri( - '${context.debugConnection.uri}/ws', - ); - final result = await fakeDds.callMethod( - '_yieldControlToDDS', - args: {'uri': 'http://localhost:123'}, - ); - expect(result, isA()); - - // While DDS is connected, expect additional connections to fail. - await expectLater( - vmServiceConnectUri('${context.debugConnection.uri}/ws'), - throwsA(isA()), - ); - - // However, once DDS is disconnected, additional clients can connect again. - await fakeDds.dispose(); - expect( - vmServiceConnectUri('${context.debugConnection.uri}/ws') - .then((client) => client.dispose()), - completes, - ); - }); - - test('Refuses to yield to dwds if existing clients found', () async { - final fakeDds = await vmServiceConnectUri( - '${context.debugConnection.uri}/ws', - ); - - // Connect to vm service. - final client = await vmServiceConnectUri( - '${context.debugConnection.uri}/ws', - ); - - final result = await fakeDds.callMethod( - '_yieldControlToDDS', - args: {'uri': 'http://localhost:123'}, - ); - expect(result, isA()); - - // The other VM service client should be closed automatically. - await client.onDone; - await fakeDds.dispose(); - }); -} diff --git a/dwds/test/integration/debugger_test.dart b/dwds/test/integration/debugger_test.dart deleted file mode 100644 index 5786af38ea..0000000000 --- a/dwds/test/integration/debugger_test.dart +++ /dev/null @@ -1,212 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@TestOn('vm') -@Timeout(Duration(minutes: 2)) -library; - -import 'dart:async'; - -import 'package:dwds/src/debugging/debugger.dart'; -import 'package:dwds/src/debugging/frame_computer.dart'; -import 'package:dwds/src/debugging/location.dart'; -import 'package:dwds/src/debugging/skip_list.dart'; -import 'package:logging/logging.dart'; -import 'package:test/test.dart'; -import 'package:vm_service/vm_service.dart' hide LogRecord; -import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart' - show CallFrame, DebuggerPausedEvent, StackTrace, WipCallFrame, WipScript; - -import 'fixtures/debugger_data.dart'; -import 'fixtures/fakes.dart'; -import 'fixtures/utilities.dart'; - -late FakeChromeAppInspector inspector; -late Debugger debugger; -late FakeWebkitDebugger webkitDebugger; -late StreamController pausedController; -late Locations locations; -late SkipLists skipLists; - -class TestStrategy extends FakeStrategy { - TestStrategy(super.assetReader); - - @override - Future moduleForServerPath(String entrypoint, String appUri) async => - 'foo.ddc.js'; - - @override - Future serverPathForModule(String entrypoint, String module) async => - 'foo/ddc'; -} - -final sourceMapContents = - '{"version":3,"sourceRoot":"","sources":["main.dart"],"names":[],' - '"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAUwB,IAAtB,WAAM;AAKJ,' - 'IAHF,4BAAkB,aAAa,SAAC,GAAG;AACb,MAApB,WAAM;AACN,YAAgC,+CAAO,AAAK,oBAAO,' - 'yCAAC,WAAW;IAChE;AAC0D,IAA3D,AAAS,AAAK,0DAAO;AAAe,kBAAO;;;AAEvC,gBAAQ;' - 'AAGV,IAFI,kCAAqC,QAAC;AACX,MAA/B,WAAM,AAAwB,0BAAP,QAAF,AAAE,KAAK,GAAP;' - ';EAEzB","file":"main.ddc.js"}'; - -final sampleSyncFrame = WipCallFrame({ - 'callFrameId': '{"ordinal":0,"injectedScriptId":2}', - 'functionName': '', - 'functionLocation': {'scriptId': '69', 'lineNumber': 88, 'columnNumber': 72}, - 'location': {'scriptId': '69', 'lineNumber': 37, 'columnNumber': 0}, - 'url': '', - 'scopeChain': >[], - 'this': {'type': 'undefined'}, -}); - -final sampleAsyncFrame = CallFrame({ - 'functionName': 'myFunc', - 'url': '', - 'scriptId': '71', - 'lineNumber': 40, - 'columnNumber': 1, -}); - -final Map scripts = { - '69': WipScript({'url': 'http://127.0.0.1:8081/foo.ddc.js'}), - '71': WipScript({'url': 'http://127.0.0.1:8081/bar.ddc.js'}), -}; - -void main() async { - setUpAll(() async { - webkitDebugger = FakeWebkitDebugger(scripts: scripts); - pausedController = StreamController(); - webkitDebugger.onPaused = pausedController.stream; - final toolConfiguration = TestToolConfiguration.withLoadStrategy( - loadStrategy: TestStrategy(FakeAssetReader()), - ); - setGlobalsForTesting(toolConfiguration: toolConfiguration); - final root = 'fakeRoot'; - locations = Locations( - FakeAssetReader(sourceMap: sourceMapContents), - FakeModules(), - root, - ); - await locations.initialize('fake_entrypoint'); - skipLists = SkipLists(root); - debugger = await Debugger.create( - webkitDebugger, - (_, _) {}, - locations, - skipLists, - root, - ); - inspector = FakeChromeAppInspector( - webkitDebugger, - fakeIsolate: simpleIsolate, - ); - debugger.updateInspector(inspector); - }); - - /// Test that we get expected variable values from a hard-coded - /// stack frame. - test('frames 1', () async { - final stackComputer = FrameComputer(debugger, frames1); - final frames = await stackComputer.calculateFrames(); - expect(frames, isNotNull); - expect(frames, isNotEmpty); - - final firstFrameVars = frames[0].vars!; - final frame1Variables = firstFrameVars.map((each) => each.name).toList(); - expect(frame1Variables, ['a', 'b']); - }); - - test('creates async frames', () async { - final stackComputer = FrameComputer( - debugger, - [sampleSyncFrame], - asyncStackTrace: StackTrace({ - 'callFrames': [sampleAsyncFrame.json], - 'parent': StackTrace({ - 'callFrames': [sampleAsyncFrame.json], - }).json, - }), - ); - - final frames = await stackComputer.calculateFrames(); - expect(frames, hasLength(5)); - - expect(frames[0].kind, FrameKind.kRegular); - expect(frames[1].kind, FrameKind.kAsyncSuspensionMarker); - expect(frames[2].kind, FrameKind.kAsyncCausal); - expect(frames[3].kind, FrameKind.kAsyncSuspensionMarker); - expect(frames[4].kind, FrameKind.kAsyncCausal); - }); - - test('elides multiple async frames', () async { - final stackComputer = FrameComputer( - debugger, - [sampleSyncFrame], - asyncStackTrace: StackTrace({ - 'callFrames': [sampleAsyncFrame.json], - 'parent': StackTrace({ - 'callFrames': >[], - 'parent': StackTrace({ - 'callFrames': [sampleAsyncFrame.json], - 'parent': StackTrace({'callFrames': >[]}).json, - }).json, - }).json, - }), - ); - - final frames = await stackComputer.calculateFrames(); - expect(frames, hasLength(5)); - - expect(frames[0].kind, FrameKind.kRegular); - expect(frames[1].kind, FrameKind.kAsyncSuspensionMarker); - expect(frames[2].kind, FrameKind.kAsyncCausal); - expect(frames[3].kind, FrameKind.kAsyncSuspensionMarker); - expect(frames[4].kind, FrameKind.kAsyncCausal); - }); - - setUp(() { - // We need to provide an Isolate so that the code doesn't bail out on a null - // check before it has a chance to throw. - inspector = FakeChromeAppInspector( - webkitDebugger, - fakeIsolate: simpleIsolate, - ); - debugger.updateInspector(inspector); - }); - - group('errors', () { - setUp(() { - // We need to provide an Isolate so that the code doesn't bail out on a - // null check before it has a chance to throw. - inspector = FakeChromeAppInspector( - webkitDebugger, - fakeIsolate: simpleIsolate, - ); - debugger.updateInspector(inspector); - }); - - test('errors in the zone are caught and logged', () async { - // Add a DebuggerPausedEvent with a null parameter to provoke an error. - pausedController.sink.add( - DebuggerPausedEvent({ - 'method': '', - 'params': { - 'reason': 'other', - 'callFrames': [ - {'callFrameId': '', 'functionName': ''}, - ], - }, - }), - ); - expect( - Debugger.logger.onRecord, - emitsThrough( - predicate( - (LogRecord log) => - log.message.contains('Error calculating sync frame'), - ), - ), - ); - }); - }); -} diff --git a/dwds/test/integration/devtools_common.dart b/dwds/test/integration/devtools_common.dart deleted file mode 100644 index 8d8a4e6def..0000000000 --- a/dwds/test/integration/devtools_common.dart +++ /dev/null @@ -1,222 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:io'; - -import 'package:dwds/src/config/tool_configuration.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; -import 'package:vm_service/vm_service.dart'; -// ignore: deprecated_member_use -import 'package:webdriver/io.dart'; - -import 'fixtures/context.dart'; -import 'fixtures/project.dart'; -import 'fixtures/utilities.dart'; - -Future _waitForPageReady(TestContext context) async { - var attempt = 100; - while (attempt-- > 0) { - final content = await context.webDriver.pageSource; - if (content.contains('hello_world')) return; - await Future.delayed(const Duration(milliseconds: 100)); - } - throw StateError('Page never initialized'); -} - -TypeMatcher _hasKind(String kind) => - isA().having((Event e) => e.kind, 'kind', kind); - -void testAll({required TestSdkConfigurationProvider provider}) { - final context = TestContext(TestProject.test, provider); - - for (final serveFromDds in [true, false]) { - group('Injected client with DevTools served from ' - '${serveFromDds ? 'DDS' : 'DevTools Launcher'}', () { - setUp(() async { - await context.setUp( - debugSettings: TestDebugSettings.withDevToolsLaunch( - context, - serveFromDds: serveFromDds, - ), - testSettings: TestSettings( - moduleFormat: provider.ddcModuleFormat, - canaryFeatures: provider.canaryFeatures, - ), - ); - await context.webDriver.driver.keyboard.sendChord([Keyboard.alt, 'd']); - // Wait for DevTools to actually open. - await Future.delayed(const Duration(seconds: 2)); - }); - - tearDown(() async { - await context.tearDown(); - }); - - test('can launch devtools', () async { - final windows = await context.webDriver.windows.toList(); - await context.webDriver.driver.switchTo.window(windows.last); - expect(await context.webDriver.pageSource, contains('flutter-view')); - expect(await context.webDriver.currentUrl, contains('ide=Dwds')); - // TODO(https://github.com/dart-lang/webdev/issues/1888): Re-enable. - }, skip: Platform.isWindows); - - test( - 'can not launch devtools for the same app in multiple tabs', - () async { - final appUrl = await context.webDriver.currentUrl; - // Open a new tab, select it, and navigate to the app - await context.webDriver.driver.execute( - "window.open('$appUrl', '_blank');", - [], - ); - await Future.delayed(const Duration(seconds: 2)); - final newAppWindow = await context.webDriver.windows.last; - await newAppWindow.setAsActive(); - - // Wait for the page to be ready before trying to open DevTools - // again. - await _waitForPageReady(context); - - // Try to open devtools and check for the alert. - await context.webDriver.driver.keyboard.sendChord([ - Keyboard.alt, - 'd', - ]); - await Future.delayed(const Duration(seconds: 2)); - final alert = context.webDriver.driver.switchTo.alert; - expect(alert, isNotNull); - expect( - await alert.text, - contains('This app is already being debugged in a different tab'), - ); - await alert.accept(); - - var windows = await context.webDriver.windows.toList(); - for (final window in windows) { - if (window.id != newAppWindow.id) { - await window.setAsActive(); - await window.close(); - } - } - - await newAppWindow.setAsActive(); - await context.webDriver.driver.keyboard.sendChord([ - Keyboard.alt, - 'd', - ]); - await Future.delayed(const Duration(seconds: 2)); - windows = await context.webDriver.windows.toList(); - final devToolsWindow = windows.firstWhere( - (Window window) => window != newAppWindow, - ); - await devToolsWindow.setAsActive(); - expect(await context.webDriver.pageSource, contains('DevTools')); - }, - skip: 'See https://github.com/dart-lang/webdev/issues/2462', - ); - - test( - 'destroys and recreates the isolate during a page refresh', - () async { - final client = context.debugConnection.vmService; - await client.streamListen('Isolate'); - await context.makeEdits([ - ( - file: context.project.dartEntryFileName, - originalString: 'Hello World!', - newString: 'Bonjour le monde!', - ), - ]); - await context.waitForSuccessfulBuild(propagateToBrowser: true); - - final eventsDone = expectLater( - client.onIsolateEvent, - emitsThrough( - emitsInOrder([ - _hasKind(EventKind.kIsolateExit), - _hasKind(EventKind.kIsolateStart), - _hasKind(EventKind.kIsolateRunnable), - ]), - ), - ); - - await context.webDriver.driver.refresh(); - - await eventsDone; - }, - skip: 'https://github.com/dart-lang/webdev/issues/1888', - ); - }, timeout: const Timeout.factor(2)); - } - - group('Injected client without a DevTools server', () { - setUp(() async { - await context.setUp( - debugSettings: const TestDebugSettings.noDevToolsLaunch().copyWith( - enableDevToolsLaunch: true, - ddsConfiguration: const DartDevelopmentServiceConfiguration( - serveDevTools: false, - ), - ), - testSettings: TestSettings( - moduleFormat: provider.ddcModuleFormat, - canaryFeatures: provider.canaryFeatures, - ), - ); - }); - - tearDown(() async { - await context.tearDown(); - }); - - test('gives a good error if devtools is not served', () async { - // Try to open devtools and check for the alert. - await context.webDriver.driver.keyboard.sendChord([Keyboard.alt, 'd']); - await Future.delayed(const Duration(seconds: 2)); - final alert = context.webDriver.driver.switchTo.alert; - expect(alert, isNotNull); - expect(await alert.text, contains('--debug')); - await alert.accept(); - }); - }); - - group( - 'Injected client with debug extension and without DevTools', - () { - setUp(() async { - await context.setUp( - debugSettings: const TestDebugSettings.noDevToolsLaunch().copyWith( - enableDebugExtension: true, - ), - testSettings: TestSettings( - moduleFormat: provider.ddcModuleFormat, - canaryFeatures: provider.canaryFeatures, - ), - ); - }); - - tearDown(() async { - await context.tearDown(); - }); - - test('gives a good error if devtools is not served', () async { - // Click on extension - await context.extensionConnection.sendCommand('Runtime.evaluate', { - 'expression': 'fakeClick()', - }); - // Try to open devtools and check for the alert. - await context.webDriver.driver.keyboard.sendChord([Keyboard.alt, 'd']); - await Future.delayed(const Duration(seconds: 2)); - final alert = context.webDriver.driver.switchTo.alert; - expect(alert, isNotNull); - expect(await alert.text, contains('--debug')); - await alert.accept(); - }); - }, - tags: ['extension'], - skip: 'https://github.com/dart-lang/webdev/issues/2114', - timeout: const Timeout.factor(2), - ); -} diff --git a/dwds/test/integration/devtools_ddc_library_bundle_test.dart b/dwds/test/integration/devtools_ddc_library_bundle_test.dart deleted file mode 100644 index b6ad5bbaf2..0000000000 --- a/dwds/test/integration/devtools_ddc_library_bundle_test.dart +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@Timeout(Duration(minutes: 5)) -@TestOn('vm') -library; - -import 'package:dwds/expression_compiler.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; - -import 'devtools_common.dart'; - -void main() { - final provider = TestSdkConfigurationProvider( - ddcModuleFormat: ModuleFormat.ddc, - canaryFeatures: true, - ); - tearDownAll(provider.dispose); - - testAll(provider: provider); -} diff --git a/dwds/test/integration/evaluate_amd_test.dart b/dwds/test/integration/evaluate_amd_test.dart deleted file mode 100644 index 5bedc792d9..0000000000 --- a/dwds/test/integration/evaluate_amd_test.dart +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@Tags(['daily']) -@TestOn('vm') -@Timeout(Duration(minutes: 5)) -library; - -import 'dart:io'; - -import 'package:dwds/expression_compiler.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; - -import 'evaluate_common.dart'; -import 'fixtures/context.dart'; -import 'fixtures/project.dart'; - -void main() async { - // Enable verbose logging for debugging. - const debug = false; - - final provider = TestSdkConfigurationProvider( - verbose: debug, - ddcModuleFormat: ModuleFormat.amd, - ); - tearDownAll(provider.dispose); - - group('Build Daemon |', () { - testAll(provider: provider, compilationMode: CompilationMode.buildDaemon); - }); - - group('Frontend Server |', () { - for (final useDebuggerModuleNames in [false, true]) { - group('Debugger module names: $useDebuggerModuleNames |', () { - for (final indexBaseMode in IndexBaseMode.values) { - group( - 'with ${indexBaseMode.name} |', - () { - testAll( - provider: provider, - compilationMode: CompilationMode.frontendServer, - indexBaseMode: indexBaseMode, - useDebuggerModuleNames: useDebuggerModuleNames, - ); - }, - // https://github.com/dart-lang/sdk/issues/49277 - skip: indexBaseMode == IndexBaseMode.base && Platform.isWindows, - ); - } - }); - } - }); -} diff --git a/dwds/test/integration/evaluate_circular_common.dart b/dwds/test/integration/evaluate_circular_common.dart deleted file mode 100644 index 8aa570008c..0000000000 --- a/dwds/test/integration/evaluate_circular_common.dart +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@TestOn('vm') -@Timeout(Duration(minutes: 2)) -library; - -import 'package:dwds_test_common/logging.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; -import 'package:vm_service/vm_service.dart'; -import 'package:vm_service_interface/vm_service_interface.dart'; - -import 'fixtures/context.dart'; -import 'fixtures/project.dart'; -import 'fixtures/utilities.dart'; - -void testAll({ - required TestSdkConfigurationProvider provider, - CompilationMode compilationMode = CompilationMode.buildDaemon, - IndexBaseMode indexBaseMode = IndexBaseMode.noBase, - bool useDebuggerModuleNames = false, -}) { - if (compilationMode == CompilationMode.buildDaemon && - indexBaseMode == IndexBaseMode.base) { - throw StateError( - 'build daemon scenario does not support non-empty base in index file', - ); - } - - final testCircular1 = TestProject.testCircular1; - final testCircular2 = TestProject.testCircular2(baseMode: indexBaseMode); - - final context = TestContext(testCircular2, provider); - - Future onBreakPoint( - String isolate, - ScriptRef script, - String breakPointId, - Future Function() body, - ) async { - Breakpoint? bp; - try { - final line = await context.findBreakpointLine( - breakPointId, - isolate, - script, - ); - bp = await context.service.addBreakpointWithScriptUri( - isolate, - script.uri!, - line, - ); - await body(); - } finally { - // Remove breakpoint so it doesn't impact other tests or retries. - if (bp != null) { - await context.service.removeBreakpoint(isolate, bp.id!); - } - } - } - - group('shared context with evaluation', () { - setUpAll(() async { - setCurrentLogWriter(debug: provider.verbose); - await context.setUp( - testSettings: TestSettings( - compilationMode: compilationMode, - enableExpressionEvaluation: true, - useDebuggerModuleNames: useDebuggerModuleNames, - verboseCompiler: provider.verbose, - canaryFeatures: provider.canaryFeatures, - moduleFormat: provider.ddcModuleFormat, - ), - ); - }); - - tearDownAll(() async { - await context.tearDown(); - }); - - setUp(() => setCurrentLogWriter(debug: provider.verbose)); - - group('evaluateInFrame', () { - late VmServiceInterface service; - VM vm; - late Isolate isolate; - late String isolateId; - ScriptList scripts; - late ScriptRef test1LibraryScript; - late ScriptRef test2LibraryScript; - late Stream stream; - - setUp(() async { - setCurrentLogWriter(debug: provider.verbose); - service = context.service; - vm = await service.getVM(); - isolate = await service.getIsolate(vm.isolates!.first.id!); - isolateId = isolate.id!; - scripts = await service.getScripts(isolateId); - - await service.streamListen('Debug'); - stream = service.onEvent('Debug'); - - final test1 = testCircular1.packageName; - final test2 = testCircular2.packageName; - - test1LibraryScript = scripts.scripts!.firstWhere( - (each) => each.uri!.contains('package:$test1/library1.dart'), - ); - test2LibraryScript = scripts.scripts!.firstWhere( - (each) => each.uri!.contains('package:$test2/library2.dart'), - ); - }); - - tearDown(() async { - await service.resume(isolateId); - }); - - test('evaluate expression in _test_circular1/library', () async { - await onBreakPoint( - isolateId, - test1LibraryScript, - 'Concatenate', - () async { - final event = await stream.firstWhere( - (event) => event.kind == EventKind.kPauseBreakpoint, - ); - - final result = await context.service.evaluateInFrame( - isolateId, - event.topFrame!.index!, - 'a', - ); - - expect( - result, - isA().having( - (instance) => instance.valueAsString, - 'valueAsString', - 'a', - ), - ); - }, - ); - }); - - test('evaluate expression in _test_circular2/library', () async { - await onBreakPoint( - isolateId, - test2LibraryScript, - 'testCircularDependencies', - () async { - final event = await stream.firstWhere( - (event) => event.kind == EventKind.kPauseBreakpoint, - ); - - final result = await context.service.evaluateInFrame( - isolateId, - event.topFrame!.index!, - 'true', - ); - - expect( - result, - isA().having( - (instance) => instance.valueAsString, - 'valueAsString', - 'true', - ), - ); - }, - ); - }); - }); - }); -} diff --git a/dwds/test/integration/evaluate_common.dart b/dwds/test/integration/evaluate_common.dart deleted file mode 100644 index 3e3f8b51c4..0000000000 --- a/dwds/test/integration/evaluate_common.dart +++ /dev/null @@ -1,937 +0,0 @@ -// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@TestOn('vm') -@Timeout(Duration(minutes: 2)) -library; - -import 'dart:async'; - -import 'package:dwds/src/services/expression_evaluator.dart'; -import 'package:dwds_test_common/logging.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:dwds_test_common/utilities.dart' show dartSdkIsAtLeast; -import 'package:test/test.dart'; -import 'package:vm_service/vm_service.dart'; -import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'; - -import 'fixtures/context.dart'; -import 'fixtures/project.dart'; -import 'fixtures/utilities.dart'; - -void testAll({ - required TestSdkConfigurationProvider provider, - CompilationMode compilationMode = CompilationMode.buildDaemon, - IndexBaseMode indexBaseMode = IndexBaseMode.noBase, - bool useDebuggerModuleNames = false, -}) { - if (compilationMode == CompilationMode.buildDaemon && - indexBaseMode == IndexBaseMode.base) { - throw StateError( - 'build daemon scenario does not support non-empty base in index file', - ); - } - - final testProject = TestProject.test; - final testPackageProject = TestProject.testPackage(baseMode: indexBaseMode); - - final context = TestContext(testPackageProject, provider); - - Future onBp( - Stream stream, - String isolate, - ScriptRef script, - String breakPointId, - Future Function(Event event) body, - ) async { - Breakpoint? bp; - try { - final line = await context.findBreakpointLine( - breakPointId, - isolate, - script, - ); - bp = await context.service.addBreakpointWithScriptUri( - isolate, - script.uri!, - line, - ); - final event = await stream.firstWhere( - (Event event) => event.kind == EventKind.kPauseBreakpoint, - ); - await body(event); - } finally { - // Remove breakpoint so it doesn't impact other tests or retries. - if (bp != null) { - await context.service.removeBreakpoint(isolate, bp.id!); - } - } - } - - group('Shared context with evaluation |', () { - setUpAll(() async { - setCurrentLogWriter(debug: provider.verbose); - await context.setUp( - testSettings: TestSettings( - compilationMode: compilationMode, - moduleFormat: provider.ddcModuleFormat, - enableExpressionEvaluation: true, - useDebuggerModuleNames: useDebuggerModuleNames, - verboseCompiler: provider.verbose, - canaryFeatures: provider.canaryFeatures, - ), - ); - }); - - tearDownAll(() async { - await context.tearDown(); - }); - - setUp(() => setCurrentLogWriter(debug: provider.verbose)); - - group('evaluateInFrame |', () { - VM vm; - late Isolate isolate; - late String isolateId; - ScriptList scripts; - late ScriptRef mainScript; - late ScriptRef libraryScript; - late ScriptRef testLibraryScript; - late ScriptRef testLibraryPartScript; - late Stream stream; - late StreamController output; - - setUp(() async { - output = StreamController.broadcast(); - output.stream.listen(provider.verbose ? print : printOnFailure); - - configureLogWriter( - customLogWriter: (level, message, {error, loggerName, stackTrace}) { - final e = error == null ? '' : ': $error'; - final s = stackTrace == null ? '' : ':\n$stackTrace'; - if (!output.isClosed) { - output.add('[$level] $loggerName: $message$e$s'); - } - }, - ); - - vm = await context.service.getVM(); - isolate = await context.service.getIsolate(vm.isolates!.first.id!); - isolateId = isolate.id!; - scripts = await context.service.getScripts(isolateId); - - await context.service.streamListen('Debug'); - stream = context.service.onEvent('Debug'); - - final testPackage = testPackageProject.packageName; - final test = testProject.packageName; - mainScript = scripts.scripts!.firstWhere( - (each) => each.uri!.contains('main.dart'), - ); - testLibraryScript = scripts.scripts!.firstWhere( - (each) => - each.uri!.contains('package:$testPackage/test_library.dart'), - ); - testLibraryPartScript = scripts.scripts!.firstWhere( - (each) => - each.uri!.contains('package:$testPackage/src/test_part.dart'), - ); - libraryScript = scripts.scripts!.firstWhere( - (each) => each.uri!.contains('package:$test/library.dart'), - ); - }); - - tearDown(() async { - await output.close(); - try { - await context.service.resume(isolateId); - } catch (_) {} - }); - - Future onBreakPoint( - ScriptRef script, - String bpId, - Future Function(Event) body, - ) => onBp(stream, isolateId, script, bpId, body); - - Future evaluateInFrame( - int frame, - String expr, { - Map? scope, - }) async => await context.service.evaluateInFrame( - isolateId, - frame, - expr, - scope: scope, - ); - - Future getInstanceRef( - int frame, - String expr, { - Map? scope, - }) async { - final result = await evaluateInFrame(frame, expr, scope: scope); - expect(result, isA()); - return result as InstanceRef; - } - - Future getInstance(InstanceRef ref) async => - await context.service.getObject(isolateId, ref.id!) as Instance; - - test('with scope', () async { - await onBreakPoint(mainScript, 'printFrame1', (Event event) async { - final frame = event.topFrame!.index!; - - final scope = { - 'x1': (await getInstanceRef(frame, '"cat"')).id!, - 'x2': (await getInstanceRef(frame, '2')).id!, - 'x3': (await getInstanceRef(frame, 'MainClass(1,0)')).id!, - }; - - final result = await getInstanceRef( - frame, - '"\$x1\$x2 (\$x3) \$testLibraryValue (\$local1)"', - scope: scope, - ); - - expect(result, matchInstanceRef('cat2 (1, 0) 3 (1)')); - }); - }); - - test('with large scope', () async { - await onBreakPoint(mainScript, 'printLocal', (Event event) async { - const N = 20; - final frame = event.topFrame!.index!; - - final scope = { - for (var i = 0; i < N; i++) - 'x$i': (await getInstanceRef(frame, '$i')).id!, - }; - final expression = [for (var i = 0; i < N; i++) '\$x$i'].join(' '); - final expected = [for (var i = 0; i < N; i++) '$i'].join(' '); - - final result = await evaluateInFrame( - frame, - '"$expression"', - scope: scope, - ); - expect(result, matchInstanceRef(expected)); - }); - }); - - test('with large code scope', () async { - await onBreakPoint(mainScript, 'printLargeScope', (Event event) async { - const xN = 2; - const tN = 20; - final frame = event.topFrame!.index!; - - final scope = { - for (var i = 0; i < xN; i++) - 'x$i': (await getInstanceRef(frame, '$i')).id!, - }; - final expression = [ - for (var i = 0; i < xN; i++) '\$x$i', - for (var i = 0; i < tN; i++) '\$t$i', - ].join(' '); - final expected = [ - for (var i = 0; i < xN; i++) '$i', - for (var i = 0; i < tN; i++) '$i', - ].join(' '); - - final result = await evaluateInFrame( - frame, - '"$expression"', - scope: scope, - ); - expect(result, matchInstanceRef(expected)); - }); - }); - - test('with scope in caller frame', () async { - await onBreakPoint(mainScript, 'printFrame1', (Event event) async { - final frame = event.topFrame!.index! + 1; - - final scope = { - 'x1': (await getInstanceRef(frame, '"cat"')).id!, - 'x2': (await getInstanceRef(frame, '2')).id!, - 'x3': (await getInstanceRef(frame, 'MainClass(1,0)')).id!, - }; - - final result = await getInstanceRef( - frame, - '"\$x1\$x2 (\$x3) \$testLibraryValue (\$local2)"', - scope: scope, - ); - - expect(result, matchInstanceRef('cat2 (1, 0) 3 (2)')); - }); - }); - - test('with scope and this', () async { - await onBreakPoint(mainScript, 'toStringMainClass', ( - Event event, - ) async { - final frame = event.topFrame!.index!; - - final scope = {'x1': (await getInstanceRef(frame, '"cat"')).id!}; - - final result = await getInstanceRef( - frame, - '"\$x1 \${this._field} \${this.field}"', - scope: scope, - ); - - expect(result, matchInstanceRef('cat 1 2')); - }); - }); - - test('extension method scope variables can be evaluated', () async { - await onBreakPoint(mainScript, 'extension', (Event event) async { - final stack = await context.service.getStack(isolateId); - final scope = _getFrameVariables(stack.frames!.first); - for (final p in scope.entries) { - final name = p.key; - final value = p.value as InstanceRef; - final result = await getInstanceRef(event.topFrame!.index!, name!); - - expect(result, matchInstanceRef(value.valueAsString)); - } - }); - }, skip: 'https://github.com/dart-lang/webdev/issues/1371'); - - test('does not crash if class metadata cannot be found', () async { - await onBreakPoint(mainScript, 'printStream', (Event event) async { - final instanceRef = await getInstanceRef( - event.topFrame!.index!, - 'stream', - ); - final instance = await getInstance(instanceRef); - - expect(instance, matchInstanceClassName('_AsBroadcastStream')); - }); - }); - - test('local', () async { - await onBreakPoint(mainScript, 'printLocal', (Event event) async { - final result = await getInstanceRef(event.topFrame!.index!, 'local'); - - expect(result, matchInstanceRef('42')); - }); - }); - - test('Type does not show native JavaScript object fields', () async { - await onBreakPoint(mainScript, 'printLocal', (Event event) async { - final instanceRef = await getInstanceRef( - event.topFrame!.index!, - 'Type', - ); - - // Type - final instance = await getInstance(instanceRef); - for (final field in instance.fields!) { - final name = field.decl!.name; - final fieldInstance = await getInstance(field.value as InstanceRef); - - expect( - fieldInstance, - isA().having( - (i) => i.classRef!.name, - 'Type.$name: classRef.name', - isNot(isIn(['NativeJavaScriptObject', 'JavaScriptObject'])), - ), - ); - } - }); - }); - - test('field', () async { - await onBreakPoint(mainScript, 'printFieldFromLibraryClass', ( - Event event, - ) async { - final result = await getInstanceRef( - event.topFrame!.index!, - 'instance.field', - ); - - expect(result, matchInstanceRef('1')); - }); - }); - - test('private field from another library', () async { - await onBreakPoint(mainScript, 'printFieldFromLibraryClass', ( - Event event, - ) async { - final result = await evaluateInFrame( - event.topFrame!.index!, - 'instance._field', - ); - - if (dartSdkIsAtLeast('3.10.0-140.0.dev')) { - expect(result, matchInstanceRefKind('String')); - expect( - result, - matchInstanceRef(contains("NoSuchMethodError: '_field")), - ); - } else { - expect( - result, - matchErrorRef(contains("The getter '_field' isn't defined")), - ); - } - }); - }); - - test('private field from current library', () async { - await onBreakPoint(mainScript, 'printFieldMain', (Event event) async { - final result = await getInstanceRef( - event.topFrame!.index!, - 'instance._field', - ); - - expect(result, matchInstanceRef('1')); - }); - }); - - test('access instance fields after evaluation', () async { - await onBreakPoint(mainScript, 'printFieldFromLibraryClass', ( - Event event, - ) async { - final instanceRef = await getInstanceRef( - event.topFrame!.index!, - 'instance', - ); - - final instance = await getInstance(instanceRef); - final field = instance.fields!.firstWhere( - (BoundField element) => element.decl!.name == 'field', - ); - - expect(field.value, matchInstanceRef('1')); - }); - }); - - test('global', () async { - await onBreakPoint(mainScript, 'printGlobal', (Event event) async { - final result = await getInstanceRef( - event.topFrame!.index!, - 'testLibraryValue', - ); - - expect(result, matchInstanceRef('3')); - }); - }); - - test('call core function', () async { - await onBreakPoint(mainScript, 'printLocal', (Event event) async { - final result = await getInstanceRef( - event.topFrame!.index!, - 'print(local)', - ); - - expect(result, matchInstanceRef('null')); - }); - }); - - test('call library function with const param', () async { - await onBreakPoint(mainScript, 'printLocal', (Event event) async { - final result = await getInstanceRef( - event.topFrame!.index!, - 'testLibraryFunction(42)', - ); - - expect(result, matchInstanceRef('42')); - }); - }); - - test('call library function with local param', () async { - await onBreakPoint(mainScript, 'printLocal', (Event event) async { - final result = await getInstanceRef( - event.topFrame!.index!, - 'testLibraryFunction(local)', - ); - - expect(result, matchInstanceRef('42')); - }); - }); - - test('call library part function with const param', () async { - await onBreakPoint(mainScript, 'printLocal', (Event event) async { - final result = await getInstanceRef( - event.topFrame!.index!, - 'testLibraryPartFunction(42)', - ); - - expect(result, matchInstanceRef('42')); - }); - }); - - test('call library part function with local param', () async { - await onBreakPoint(mainScript, 'printLocal', (Event event) async { - final result = await getInstanceRef( - event.topFrame!.index!, - 'testLibraryPartFunction(local)', - ); - - expect(result, matchInstanceRef('42')); - }); - }); - - test('loop variable', () async { - await onBreakPoint(mainScript, 'printLoopVariable', ( - Event event, - ) async { - final result = await getInstanceRef(event.topFrame!.index!, 'item'); - - expect(result, matchInstanceRef('1')); - }); - }); - - test('evaluate expression in _test_package/test_library', () async { - await onBreakPoint(testLibraryScript, 'testLibraryFunction', ( - Event event, - ) async { - final result = await getInstanceRef(event.topFrame!.index!, 'formal'); - - expect(result, matchInstanceRef('23')); - }); - }); - - test('evaluate expression in a class constructor in a library', () async { - await onBreakPoint(testLibraryScript, 'testLibraryClassConstructor', ( - Event event, - ) async { - final result = await getInstanceRef( - event.topFrame!.index!, - 'this.field', - ); - - expect(result, matchInstanceRef('1')); - }); - }); - - test( - 'evaluate expression in a class constructor in a library part', - () async { - await onBreakPoint( - testLibraryPartScript, - 'testLibraryPartClassConstructor', - (Event event) async { - final result = await getInstanceRef( - event.topFrame!.index!, - 'this.field', - ); - - expect(result, matchInstanceRef('1')); - }, - ); - }, - ); - - test('evaluate expression in caller frame', () async { - await onBreakPoint(testLibraryScript, 'testLibraryFunction', ( - Event event, - ) async { - final result = await getInstanceRef( - event.topFrame!.index! + 1, - 'local', - ); - - expect(result, matchInstanceRef('23')); - }); - }); - - test('evaluate expression in a library', () async { - await onBreakPoint(libraryScript, 'Concatenate', (Event event) async { - final result = await getInstanceRef(event.topFrame!.index!, 'a'); - - expect(result, matchInstanceRef('Hello')); - }); - }); - - test('compilation error', () async { - await onBreakPoint(mainScript, 'printLocal', (Event event) async { - final error = await evaluateInFrame(event.topFrame!.index!, 'typo'); - - expect( - error, - matchErrorRef(contains(EvaluationErrorKind.compilation)), - ); - }); - }); - - test('async frame error', () async { - final maxAttempts = 100; - - Response? error; - String? breakpointId; - try { - // Pause in client.js directly to force pausing in async code. - breakpointId = await _setBreakpointInInjectedClient( - context.tabConnection.debugger, - ); - - var attempt = 0; - do { - try { - await context.service.resume(isolateId); - } catch (_) {} - - final event = stream.firstWhere( - (Event event) => event.kind == EventKind.kPauseInterrupted, - ); - final frame = (await event).topFrame; - if (frame != null) { - error = await context.service.evaluateInFrame( - isolateId, - frame.index!, - 'true', - ); - } - expect( - attempt, - lessThan(maxAttempts), - reason: - 'Failed to receive and async frame error in $attempt ' - 'attempts', - ); - await Future.delayed(const Duration(milliseconds: 10)); - attempt++; - } while (error is! ErrorRef); - } finally { - if (breakpointId != null) { - await context.tabConnection.debugger.removeBreakpoint(breakpointId); - } - } - - // Verify we receive an error when evaluating - // on async frame. - expect(error, matchErrorRef(contains(EvaluationErrorKind.asyncFrame))); - - // Verify we don't emit errors or warnings - // on async frame evaluations. - output.stream.listen((String event) { - expect(event, isNot(contains('[WARNING]'))); - expect(event, isNot(contains('[SEVERE]'))); - }); - }); - - test('module load error', () async { - await onBreakPoint(mainScript, 'printLocal', (Event event) async { - final error = await evaluateInFrame( - event.topFrame!.index!, - 'd.deferredPrintLocal()', - ); - - expect( - error, - matchErrorRef(contains(EvaluationErrorKind.loadModule)), - ); - }); - }, skip: 'https://github.com/dart-lang/sdk/issues/48587'); - - test('cannot evaluate in unsupported isolate', () async { - await onBreakPoint(mainScript, 'printLocal', (Event event) async { - await expectLater( - context.service.evaluateInFrame( - 'bad', - event.topFrame!.index!, - 'local', - ), - throwsSentinelException, - ); - }); - }); - }); - - group('evaluate |', () { - VM vm; - late Isolate isolate; - late String isolateId; - - setUp(() async { - setCurrentLogWriter(debug: provider.verbose); - final service = context.service; - vm = await service.getVM(); - isolate = await service.getIsolate(vm.isolates!.first.id!); - isolateId = isolate.id!; - - await service.streamListen('Debug'); - }); - - tearDown(() async {}); - - Future evaluate( - String? targetId, - String expr, { - Map? scope, - }) async => await context.service.evaluate( - isolateId, - targetId!, - expr, - scope: scope, - ); - - Future getInstanceRef( - String? targetId, - String expr, { - Map? scope, - }) async { - final result = await evaluate(targetId, expr, scope: scope); - expect(result, isA()); - return result as InstanceRef; - } - - String getRootLibraryId() { - expect(isolate.rootLib, isNotNull); - expect(isolate.rootLib!.id, isNotNull); - return isolate.rootLib!.id!; - } - - test('RecordType getters', () async { - final libraryId = getRootLibraryId(); - - final type = await getInstanceRef(libraryId, '(0,1).runtimeType'); - final result = await getInstanceRef(type.id, 'hashCode'); - - expect(result, matchInstanceRefKind('Double')); - }, skip: 'https://github.com/dart-lang/sdk/issues/54609'); - - test('Object getters', () async { - final libraryId = getRootLibraryId(); - - final type = await getInstanceRef(libraryId, 'Object()'); - final result = await getInstanceRef(type.id, 'hashCode'); - - expect(result, matchInstanceRefKind('Double')); - }); - - test('with scope', () async { - final libraryId = getRootLibraryId(); - - final scope = { - 'x1': (await getInstanceRef(libraryId, '"cat"')).id!, - 'x2': (await getInstanceRef(libraryId, '2')).id!, - 'x3': (await getInstanceRef(libraryId, 'MainClass(1,0)')).id!, - }; - - final result = await getInstanceRef( - libraryId, - '"\$x1\$x2 (\$x3) \$testLibraryValue"', - scope: scope, - ); - - expect(result, matchInstanceRef('cat2 (1, 0) 3')); - }); - - test('with large scope', () async { - final libraryId = getRootLibraryId(); - const N = 2; - - final scope = { - for (var i = 0; i < N; i++) - 'x$i': (await getInstanceRef(libraryId, '$i')).id!, - }; - final expression = [for (var i = 0; i < N; i++) '\$x$i'].join(' '); - final expected = [for (var i = 0; i < N; i++) '$i'].join(' '); - - final result = await getInstanceRef( - libraryId, - '"$expression"', - scope: scope, - ); - expect(result, matchInstanceRef(expected)); - }); - - test('in parallel (in a batch)', () async { - final libraryId = getRootLibraryId(); - - final evaluation1 = getInstanceRef( - libraryId, - 'MainClass(1,0).toString()', - ); - final evaluation2 = getInstanceRef( - libraryId, - 'MainClass(1,1).toString()', - ); - - final results = await Future.wait([evaluation1, evaluation2]); - expect(results[0], matchInstanceRef('1, 0')); - expect(results[1], matchInstanceRef('1, 1')); - }); - - test('in parallel (in a batch) handles errors', () async { - final libraryId = getRootLibraryId(); - final missingLibId = ''; - - final evaluation1 = evaluate(missingLibId, 'MainClass(1,0).toString()'); - final evaluation2 = evaluate(libraryId, 'MainClass(1,1).toString()'); - - final results = await Future.wait([evaluation1, evaluation2]); - expect( - results[0], - matchErrorRef( - contains('Evaluate is called on an unsupported target'), - ), - ); - expect(results[1], matchInstanceRef('1, 1')); - }); - - test('with scope override', () async { - final libraryId = getRootLibraryId(); - - final param = await getInstanceRef(libraryId, 'MainClass(1,0)'); - final result = await getInstanceRef( - libraryId, - 't.toString()', - scope: {'t': param.id!}, - ); - - expect(result, matchInstanceRef('1, 0')); - }); - - test('uses symbol from the same library', () async { - final libraryId = getRootLibraryId(); - - final result = await getInstanceRef( - libraryId, - 'MainClass(1,0).toString()', - ); - - expect(result, matchInstanceRef('1, 0')); - }); - - test('uses symbol from another library', () async { - final libraryId = getRootLibraryId(); - final result = await getInstanceRef( - libraryId, - 'TestLibraryClass(0,1).toString()', - ); - - expect(result, matchInstanceRef('field: 0, _field: 1')); - }); - - test('closure call', () async { - final libraryId = getRootLibraryId(); - final result = await getInstanceRef(libraryId, '(() => 42)()'); - - expect(result, matchInstanceRef('42')); - }); - }); - }, timeout: const Timeout.factor(2)); - - group('shared context with no evaluation |', () { - setUpAll(() async { - setCurrentLogWriter(debug: provider.verbose); - await context.setUp( - testSettings: TestSettings( - compilationMode: compilationMode, - moduleFormat: provider.ddcModuleFormat, - enableExpressionEvaluation: false, - verboseCompiler: provider.verbose, - canaryFeatures: provider.canaryFeatures, - ), - ); - }); - - tearDownAll(() async { - await context.tearDown(); - }); - - setUp(() => setCurrentLogWriter(debug: provider.verbose)); - - group('evaluateInFrame |', () { - VM vm; - late Isolate isolate; - late String isolateId; - ScriptList scripts; - late ScriptRef mainScript; - late Stream stream; - - setUp(() async { - final service = context.service; - vm = await service.getVM(); - isolate = await service.getIsolate(vm.isolates!.first.id!); - isolateId = isolate.id!; - scripts = await service.getScripts(isolateId); - - await service.streamListen('Debug'); - stream = service.onEvent('Debug'); - - mainScript = scripts.scripts!.firstWhere( - (each) => each.uri!.contains('main.dart'), - ); - }); - - tearDown(() async { - await context.service.resume(isolateId); - }); - - test('cannot evaluate expression', () async { - await onBp(stream, isolateId, mainScript, 'printLocal', ( - Event event, - ) async { - await expectLater( - context.service.evaluateInFrame( - isolateId, - event.topFrame!.index!, - 'local', - ), - throwsRPCError, - ); - }); - }); - }); - }); -} - -Map _getFrameVariables(Frame frame) { - return { - for (final variable in frame.vars!) - variable.name: variable.value as InstanceRef?, - }; -} - -Future _setBreakpointInInjectedClient(WipDebugger debugger) async { - final client = 'dwds/src/injected/client.js'; - final clientScript = debugger.scripts.values.firstWhere( - (e) => e.url.contains(client), - ); - final clientSource = await debugger.getScriptSource(clientScript.scriptId); - - final line = clientSource - .split('\n') - .indexWhere((element) => element.contains('convertDartClosureToJS')); - - final result = await debugger.sendCommand( - 'Debugger.setBreakpointByUrl', - params: { - 'urlRegex': '.*$client', - 'lineNumber': line + 4, - 'columnNumber': 0, - }, - ); - final responseMap = result.json['result'] as Map; - return responseMap['breakpointId'] as String; -} - -Matcher matchInstanceRefKind(String kind) => - isA().having((instance) => instance.kind, 'kind', kind); - -Matcher matchInstanceRef(dynamic value) => isA().having( - (instance) => instance.valueAsString, - 'valueAsString', - value, -); - -Matcher matchInstanceClassName(dynamic className) => isA().having( - (instance) => instance.classRef!.name, - 'class name', - className, -); - -Matcher matchInstanceRefClassName(dynamic className) => isA() - .having((instance) => instance.classRef!.name, 'class name', className); - -Matcher matchErrorRef(dynamic message) => - isA().having((instance) => instance.message, 'message', message); diff --git a/dwds/test/integration/evaluate_ddc_library_bundle_test.dart b/dwds/test/integration/evaluate_ddc_library_bundle_test.dart deleted file mode 100644 index e8783c8c8d..0000000000 --- a/dwds/test/integration/evaluate_ddc_library_bundle_test.dart +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@Tags(['daily']) -@TestOn('vm') -@Timeout(Duration(minutes: 5)) -library; - -import 'dart:io'; - -import 'package:dwds/expression_compiler.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; - -import 'evaluate_common.dart'; -import 'fixtures/context.dart'; -import 'fixtures/project.dart'; - -void main() async { - // Enable verbose logging for debugging. - const debug = false; - - group('Canary: true |', () { - final provider = TestSdkConfigurationProvider( - verbose: debug, - ddcModuleFormat: ModuleFormat.ddc, - canaryFeatures: true, - ); - tearDownAll(provider.dispose); - - group('Build Daemon |', () { - testAll(provider: provider, compilationMode: CompilationMode.buildDaemon); - }); - - group('Frontend Server |', () { - for (final useDebuggerModuleNames in [false, true]) { - group('Debugger module names: $useDebuggerModuleNames |', () { - for (final indexBaseMode in IndexBaseMode.values) { - group( - 'with ${indexBaseMode.name} |', - () { - testAll( - provider: provider, - compilationMode: CompilationMode.frontendServer, - indexBaseMode: indexBaseMode, - useDebuggerModuleNames: useDebuggerModuleNames, - ); - }, - // https://github.com/dart-lang/sdk/issues/49277 - skip: indexBaseMode == IndexBaseMode.base && Platform.isWindows - ? 'Skipped on Windows when indexBaseMode is base. See issue: https://github.com/dart-lang/sdk/issues/49277' - : null, - ); - } - }); - } - }); - }); -} diff --git a/dwds/test/integration/evaluate_parts_common.dart b/dwds/test/integration/evaluate_parts_common.dart deleted file mode 100644 index 21c6155435..0000000000 --- a/dwds/test/integration/evaluate_parts_common.dart +++ /dev/null @@ -1,200 +0,0 @@ -// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'package:dwds_test_common/logging.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; -import 'package:vm_service/vm_service.dart'; -import 'package:vm_service_interface/vm_service_interface.dart'; - -import 'fixtures/context.dart'; -import 'fixtures/project.dart'; -import 'fixtures/utilities.dart'; - -void testAll({ - required TestSdkConfigurationProvider provider, - CompilationMode compilationMode = CompilationMode.buildDaemon, - IndexBaseMode indexBaseMode = IndexBaseMode.noBase, - bool useDebuggerModuleNames = false, -}) { - if (compilationMode == CompilationMode.buildDaemon && - indexBaseMode == IndexBaseMode.base) { - throw StateError( - 'build daemon scenario does not support non-empty base in index file', - ); - } - - final testParts = TestProject.testParts(baseMode: indexBaseMode); - - final context = TestContext(testParts, provider); - - Future onBreakPoint( - String isolate, - ScriptRef script, - String breakPointId, - Future Function() body, - ) async { - Breakpoint? bp; - try { - final line = await context.findBreakpointLine( - breakPointId, - isolate, - script, - ); - bp = await context.service.addBreakpointWithScriptUri( - isolate, - script.uri!, - line, - ); - await body(); - } finally { - // Remove breakpoint so it doesn't impact other tests or retries. - if (bp != null) { - await context.service.removeBreakpoint(isolate, bp.id!); - } - } - } - - group('shared context with evaluation - evaluateInFrame', () { - late VmServiceInterface service; - late String isolateId; - late ScriptRef mainScript; - late ScriptRef part1Script; - late ScriptRef part2Script; - late ScriptRef part3Script; - late Stream stream; - - setUp(() async { - setCurrentLogWriter(debug: provider.verbose); - await context.setUp( - testSettings: TestSettings( - compilationMode: compilationMode, - enableExpressionEvaluation: true, - useDebuggerModuleNames: useDebuggerModuleNames, - verboseCompiler: provider.verbose, - canaryFeatures: provider.canaryFeatures, - moduleFormat: provider.ddcModuleFormat, - ), - ); - - service = context.service; - final vm = await service.getVM(); - final isolate = await service.getIsolate(vm.isolates!.first.id!); - isolateId = isolate.id!; - final scripts = await service.getScripts(isolateId); - - ScriptRef findScript(String path) { - return scripts.scripts!.firstWhere((e) => e.uri!.contains(path)); - } - - await service.streamListen(EventStreams.kDebug); - stream = service.onEvent(EventStreams.kDebug); - - final packageName = testParts.packageName; - - mainScript = findScript('package:$packageName/library.dart'); - part1Script = findScript('package:$packageName/part1.dart'); - part2Script = findScript('package:$packageName/part2.dart'); - part3Script = findScript('package:$packageName/part3.dart'); - }); - - tearDown(() async { - await context.tearDown(); - }); - - test('evaluate expression in main library and parts', () async { - // Main library. - await onBreakPoint(isolateId, mainScript, 'Concatenate1', () async { - final event = await stream.firstWhere( - (event) => event.kind == EventKind.kPauseBreakpoint, - ); - - final result = await context.service.evaluateInFrame( - isolateId, - event.topFrame!.index!, - 'a.substring(2, 4)', - ); - - expect( - result, - isA().having( - (instance) => instance.valueAsString, - 'valueAsString', - 'll', - ), - ); - }); - await service.resume(isolateId); - - // Part 1. - await onBreakPoint(isolateId, part1Script, 'Concatenate2', () async { - final event = await stream.firstWhere( - (event) => event.kind == EventKind.kPauseBreakpoint, - ); - - final result = await context.service.evaluateInFrame( - isolateId, - event.topFrame!.index!, - 'a + b + 37', - ); - - expect( - result, - isA().having( - (instance) => instance.valueAsString, - 'valueAsString', - '42', - ), - ); - }); - await service.resume(isolateId); - - // Part 2. - await onBreakPoint(isolateId, part2Script, 'Concatenate3', () async { - final event = await stream.firstWhere( - (event) => event.kind == EventKind.kPauseBreakpoint, - ); - - final result = await context.service.evaluateInFrame( - isolateId, - event.topFrame!.index!, - 'a.length + b + 1', - ); - - expect( - result, - isA().having( - (instance) => instance.valueAsString, - 'valueAsString', - '42.42', - ), - ); - }); - await service.resume(isolateId); - - // Part 3. - await onBreakPoint(isolateId, part3Script, 'Concatenate4', () async { - final event = await stream.firstWhere( - (event) => event.kind == EventKind.kPauseBreakpoint, - ); - - final result = await context.service.evaluateInFrame( - isolateId, - event.topFrame!.index!, - '(List.of(a)..add(b.keys.first)).toString()', - ); - - expect( - result, - isA().having( - (instance) => instance.valueAsString, - 'valueAsString', - '[hello, world, foo]', - ), - ); - }); - await service.resume(isolateId); - }); - }); -} diff --git a/dwds/test/integration/events_amd_test.dart b/dwds/test/integration/events_amd_test.dart deleted file mode 100644 index db87a0df45..0000000000 --- a/dwds/test/integration/events_amd_test.dart +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@Timeout(Duration(minutes: 2)) -library; - -import 'dart:async'; -import 'dart:io'; - -import 'package:dwds/src/events.dart'; -import 'package:dwds/src/utilities/server.dart'; -import 'package:dwds_test_common/logging.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; - -import 'events_common.dart'; -import 'fixtures/context.dart'; - -void main() { - final provider = TestSdkConfigurationProvider(); - tearDownAll(provider.dispose); - - group('serve requests', () { - late HttpServer server; - - setUp(() async { - setCurrentLogWriter(); - server = await startHttpServer('localhost', port: 0); - }); - - tearDown(() async { - await server.close(); - }); - - test('emits HTTP_REQUEST_EXCEPTION event', () async { - Future throwAsyncException() async { - await Future.delayed(const Duration(milliseconds: 100)); - throw Exception('async error'); - } - - // The events stream is a broadcast stream so start listening - // before the action. - final events = expectLater( - pipe(eventStream), - emitsThrough( - matchesEvent(DwdsEventKind.httpRequestException, { - 'server': 'FakeServer', - 'exception': startsWith('Exception: async error'), - }), - ), - ); - - // Start serving requests with a failing handler in an error zone. - serveHttpRequests( - server, - (request) async { - unawaited(throwAsyncException()); - return Future.error('error'); - }, - (e, s) { - emitEvent(DwdsEvent.httpRequestException('FakeServer', '$e:$s')); - }, - ); - - // Send a request. - final client = HttpClient(); - final request = await client.getUrl( - Uri.parse('http://localhost:${server.port}/foo'), - ); - - // Ignore the response. - final response = await request.close(); - await response.drain(); - - // Wait for expected events. - await events; - }); - }); - - group('Frontend Server', () { - testWithDwds( - provider: provider, - compilationMode: CompilationMode.frontendServer, - ); - }); - - group('Build Daemon', () { - testWithDwds( - provider: provider, - compilationMode: CompilationMode.buildDaemon, - ); - }); -} diff --git a/dwds/test/integration/events_common.dart b/dwds/test/integration/events_common.dart deleted file mode 100644 index c8e050d12c..0000000000 --- a/dwds/test/integration/events_common.dart +++ /dev/null @@ -1,507 +0,0 @@ -// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:async'; -import 'dart:io'; - -import 'package:dwds/src/events.dart'; -import 'package:dwds_test_common/logging.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; -import 'package:vm_service/vm_service.dart'; -import 'package:vm_service_interface/vm_service_interface.dart'; -import 'package:webdriver/async_core.dart'; - -import 'fixtures/context.dart'; -import 'fixtures/project.dart'; -import 'fixtures/utilities.dart'; - -void testWithDwds({ - required TestSdkConfigurationProvider provider, - required CompilationMode compilationMode, -}) { - final context = TestContext(TestProject.test, provider); - - group( - 'with dwds', - () { - Future? initialEvents; - late Keyboard keyboard; - late Stream events; - late VmService fakeClient; - - /// Runs [action] and waits for an event matching [eventMatcher]. - Future expectEventDuring( - Matcher eventMatcher, - Future Function() action, { - Timeout? timeout, - }) async { - // The events stream is a broadcast stream so start listening - // before the action. - final events = expectLater( - pipe(context.testServer.dwds.events, timeout: timeout), - emitsThrough(eventMatcher), - ); - final result = await action(); - await events; - return result; - } - - /// Runs [action] and waits for an event matching [eventMatcher]. - Future expectEventsDuring( - List eventMatchers, - Future Function() action, { - Timeout? timeout, - }) async { - // The events stream is a broadcast stream so start listening - // before the action. - final events = eventMatchers.map( - (matcher) => expectLater( - pipe(context.testServer.dwds.events, timeout: timeout), - emitsThrough(matcher), - ), - ); - final result = await action(); - await Future.wait(events); - return result; - } - - setUpAll(() async { - setCurrentLogWriter(debug: provider.verbose); - initialEvents = expectLater( - pipe(eventStream, timeout: const Timeout.factor(5)), - emitsThrough( - matchesEvent(DwdsEventKind.compilerUpdateDependencies, { - if (compilationMode == CompilationMode.frontendServer) - 'entrypoint': 'example/hello_world/main_module.bootstrap.js' - else - 'entrypoint': 'hello_world/main.dart.bootstrap.js', - 'elapsedMilliseconds': isNotNull, - }), - ), - ); - await context.setUp( - testSettings: TestSettings( - compilationMode: compilationMode, - enableExpressionEvaluation: true, - moduleFormat: provider.ddcModuleFormat, - verboseCompiler: provider.verbose, - canaryFeatures: provider.canaryFeatures, - ), - debugSettings: TestDebugSettings.withDevToolsLaunch(context), - ); - keyboard = context.webDriver.driver.keyboard; - events = context.testServer.dwds.events; - fakeClient = await context.connectFakeClient(); - }); - - tearDownAll(() async { - await context.tearDown(); - }); - - test('emits DEBUGGER_READY and DEVTOOLS_LOAD events', () async { - await expectEventsDuring([ - matchesEvent(DwdsEventKind.debuggerReady, { - 'elapsedMilliseconds': isNotNull, - 'screen': equals('debugger'), - }), - matchesEvent(DwdsEventKind.devToolsLoad, { - 'elapsedMilliseconds': isNotNull, - 'screen': equals('debugger'), - }), - ], () => keyboard.sendChord([Keyboard.alt, 'd'])); - }, skip: 'https://github.com/dart-lang/webdev/issues/2394'); - - test('emits DEVTOOLS_LAUNCH event', () async { - await expectEventDuring( - matchesEvent(DwdsEventKind.devtoolsLaunch, {}), - () => keyboard.sendChord([Keyboard.alt, 'd']), - ); - }); - - test('events can be listened to multiple times', () async { - events.listen((_) {}); - events.listen((_) {}); - }); - - test('can emit event through service extension', () async { - final response = await expectEventDuring( - matchesEvent('foo-event', {'data': 1234}), - () => fakeClient.callServiceExtension( - 'ext.dwds.emitEvent', - args: { - 'type': 'foo-event', - 'payload': {'data': 1234}, - }, - ), - ); - expect(response.type, 'Success'); - }); - - group('evaluate', () { - late VmServiceInterface service; - late String isolateId; - late String bootstrapId; - - setUpAll(() async { - setCurrentLogWriter(debug: provider.verbose); - service = context.service; - final vm = await service.getVM(); - final isolate = await service.getIsolate(vm.isolates!.first.id!); - isolateId = isolate.id!; - bootstrapId = isolate.rootLib!.id!; - }); - - setUp(() async { - setCurrentLogWriter(debug: provider.verbose); - }); - - test('emits EVALUATE events on evaluation success', () async { - final expression = "helloString('world')"; - await expectEventDuring( - matchesEvent(DwdsEventKind.evaluate, { - 'expression': expression, - 'success': isTrue, - 'elapsedMilliseconds': isNotNull, - }), - () => service.evaluate(isolateId, bootstrapId, expression), - ); - }); - - test('emits COMPILER_UPDATE_DEPENDENCIES event', () async { - await initialEvents; - }); - - test('emits EVALUATE events on evaluation failure', () async { - final expression = 'some-bad-expression'; - await expectEventDuring( - matchesEvent(DwdsEventKind.evaluate, { - 'expression': expression, - 'success': isFalse, - 'error': isA(), - 'elapsedMilliseconds': isNotNull, - }), - () => service.evaluate(isolateId, bootstrapId, expression), - ); - }); - }); - - group('evaluateInFrame', () { - late VmServiceInterface service; - late String isolateId; - late Stream stream; - late ScriptRef mainScript; - - setUpAll(() async { - setCurrentLogWriter(debug: provider.verbose); - service = context.service; - final vm = await service.getVM(); - - isolateId = vm.isolates!.first.id!; - await service.streamListen('Debug'); - stream = service.onEvent('Debug'); - final scriptList = await service.getScripts(isolateId); - mainScript = scriptList.scripts!.firstWhere( - (script) => script.uri!.contains('main.dart'), - ); - }); - - setUp(() async { - setCurrentLogWriter(debug: provider.verbose); - }); - - test('emits EVALUATE_IN_FRAME events on RPC error', () async { - final expression = 'some-bad-expression'; - await expectEventDuring( - matchesEvent(DwdsEventKind.evaluateInFrame, { - 'expression': expression, - 'success': isFalse, - 'exception': isA().having( - (e) => e.message, - 'message', - contains('program is not paused'), - ), - 'elapsedMilliseconds': isNotNull, - }), - () => service - .evaluateInFrame(isolateId, 0, expression) - .catchError((_) => Future.value(Response())), - ); - }); - - test('emits EVALUATE_IN_FRAME events on evaluation error', () async { - final line = await context.findBreakpointLine( - 'callPrintCount', - isolateId, - mainScript, - ); - final bp = await service.addBreakpoint( - isolateId, - mainScript.id!, - line, - ); - // Wait for breakpoint to trigger. - await stream.firstWhere( - (event) => event.kind == EventKind.kPauseBreakpoint, - ); - - // Evaluation succeeds and return ErrorRef containing compilation - // error, so event is marked as success. - final expression = 'some-bad-expression'; - await expectEventDuring( - matchesEvent(DwdsEventKind.evaluateInFrame, { - 'expression': expression, - 'success': isFalse, - 'error': isA(), - 'elapsedMilliseconds': isNotNull, - }), - () => service - .evaluateInFrame(isolateId, 0, expression) - .catchError((_) => Future.value(Response())), - ); - - await service.removeBreakpoint(isolateId, bp.id!); - await service.resume(isolateId); - }); - - test('emits EVALUATE_IN_FRAME events on evaluation success', () async { - final line = await context.findBreakpointLine( - 'callPrintCount', - isolateId, - mainScript, - ); - final bp = await service.addBreakpoint( - isolateId, - mainScript.id!, - line, - ); - // Wait for breakpoint to trigger. - await stream.firstWhere( - (event) => event.kind == EventKind.kPauseBreakpoint, - ); - - // Evaluation succeeds and return InstanceRef, - // so event is marked as success. - final expression = 'true'; - await expectEventDuring( - matchesEvent(DwdsEventKind.evaluateInFrame, { - 'expression': expression, - 'success': isTrue, - 'elapsedMilliseconds': isNotNull, - }), - () => service - .evaluateInFrame(isolateId, 0, expression) - .catchError((_) => Future.value(Response())), - ); - - await service.removeBreakpoint(isolateId, bp.id!); - await service.resume(isolateId); - }); - }); - - group('getSourceReport', () { - late VmServiceInterface service; - late String isolateId; - late ScriptRef mainScript; - - setUp(() async { - setCurrentLogWriter(debug: provider.verbose); - service = context.service; - final vm = await service.getVM(); - isolateId = vm.isolates!.first.id!; - final scriptList = await service.getScripts(isolateId); - - mainScript = scriptList.scripts!.firstWhere( - (script) => script.uri!.contains('main.dart'), - ); - }); - - test('emits GET_SOURCE_REPORT events', () async { - await expectEventDuring( - matchesEvent(DwdsEventKind.getSourceReport, { - 'elapsedMilliseconds': isNotNull, - }), - () => service.getSourceReport(isolateId, [ - SourceReportKind.kPossibleBreakpoints, - ], scriptId: mainScript.id), - ); - }); - }); - - group('getScripts', () { - late VmServiceInterface service; - late String isolateId; - - setUp(() async { - setCurrentLogWriter(debug: provider.verbose); - service = context.service; - final vm = await service.getVM(); - isolateId = vm.isolates!.first.id!; - }); - - test('emits GET_SCRIPTS events', () async { - await expectEventDuring( - matchesEvent(DwdsEventKind.getScripts, { - 'elapsedMilliseconds': isNotNull, - }), - () => service.getScripts(isolateId), - ); - }); - }); - - group('getIsolate', () { - late VmServiceInterface service; - late String isolateId; - - setUp(() async { - setCurrentLogWriter(debug: provider.verbose); - service = context.service; - final vm = await service.getVM(); - isolateId = vm.isolates!.first.id!; - }); - - test('emits GET_ISOLATE events', () async { - await expectEventDuring( - matchesEvent(DwdsEventKind.getIsolate, { - 'elapsedMilliseconds': isNotNull, - }), - () => service.getIsolate(isolateId), - ); - }); - }); - - group('getVM', () { - setUp(() async { - setCurrentLogWriter(debug: provider.verbose); - }); - - test('emits GET_VM events', () async { - await expectEventDuring( - matchesEvent(DwdsEventKind.getVM, { - 'elapsedMilliseconds': isNotNull, - }), - () => context.service.getVM(), - ); - }); - }); - - group('hotRestart', () { - setUp(() async { - setCurrentLogWriter(debug: provider.verbose); - }); - - test('emits HOT_RESTART event', () async { - final hotRestart = context.getRegisteredServiceExtension( - 'hotRestart', - ); - await expectEventDuring( - matchesEvent(DwdsEventKind.hotRestart, { - 'elapsedMilliseconds': isNotNull, - }), - () => fakeClient.callServiceExtension(hotRestart!), - ); - }); - }); - - group('resume', () { - late VmServiceInterface service; - late String isolateId; - - setUp(() async { - setCurrentLogWriter(debug: provider.verbose); - service = context.service; - final vm = await service.getVM(); - isolateId = vm.isolates!.first.id!; - await service.streamListen('Debug'); - final stream = service.onEvent('Debug'); - final scriptList = await service.getScripts(isolateId); - final mainScript = scriptList.scripts!.firstWhere( - (script) => script.uri!.contains('main.dart'), - ); - final line = await context.findBreakpointLine( - 'callPrintCount', - isolateId, - mainScript, - ); - final bp = await service.addBreakpoint( - isolateId, - mainScript.id!, - line, - ); - // Wait for breakpoint to trigger. - await stream.firstWhere( - (event) => event.kind == EventKind.kPauseBreakpoint, - ); - await service.removeBreakpoint(isolateId, bp.id!); - }); - - tearDown(() async { - // We must resume execution in case a test left the isolate paused, - // but error 106 is expected if the isolate is already running. - try { - await service.resume(isolateId); - } on RPCError catch (e) { - if (e.code != 106) rethrow; - } - }); - - test('emits RESUME events', () async { - await expectEventDuring( - matchesEvent(DwdsEventKind.resume, { - 'step': 'Into', - 'elapsedMilliseconds': isNotNull, - }), - () => service.resume(isolateId, step: 'Into'), - ); - }); - }); - - group('fullReload', () { - setUp(() async { - setCurrentLogWriter(debug: provider.verbose); - }); - - test('emits FULL_RELOAD event', () async { - final fullReload = context.getRegisteredServiceExtension( - 'fullReload', - ); - - await expectEventDuring( - matchesEvent(DwdsEventKind.fullReload, { - 'elapsedMilliseconds': isNotNull, - }), - () => fakeClient.callServiceExtension(fullReload!), - ); - }); - }); - }, - // TODO(elliette): Re-enable (https://github.com/dart-lang/webdev/issues/1852). - skip: Platform.isWindows, - timeout: const Timeout.factor(2), - ); -} - -/// Matches event recursively. -Matcher matchesEvent(String type, Map payload) { - return isA() - .having((e) => e.type, 'type', type) - .having((e) => e.payload.keys, 'payload.keys', payload.keys) - .having((e) => e.payload.values, 'payload.values', payload.values); -} - -/// Pipes the [stream] into a newly created stream. -/// Returns the new stream which is closed on [timeout]. -Stream pipe(Stream stream, {Timeout? timeout}) { - final controller = StreamController(); - final defaultTimeout = const Timeout(Duration(seconds: 20)); - timeout ??= defaultTimeout; - unawaited( - stream - .forEach(controller.add) - .timeout(defaultTimeout.merge(timeout).duration!) - .catchError((_) {}) - .then((value) => controller.close()), - ); - return controller.stream; -} diff --git a/dwds/test/integration/execution_context_test.dart b/dwds/test/integration/execution_context_test.dart deleted file mode 100644 index 5ec431aa0a..0000000000 --- a/dwds/test/integration/execution_context_test.dart +++ /dev/null @@ -1,291 +0,0 @@ -// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@Timeout(Duration(minutes: 2)) -library; - -import 'dart:async'; -import 'dart:convert'; - -import 'package:dwds/data/devtools_request.dart'; -import 'package:dwds/data/extension_request.dart'; -import 'package:dwds/src/debugging/execution_context.dart'; -import 'package:dwds/src/servers/extension_debugger.dart'; -import 'package:dwds_test_common/logging.dart'; -import 'package:test/test.dart'; -import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'; - -import 'fixtures/fakes.dart'; - -void main() async { - const debug = false; - - group('ExecutionContext', () { - setUpAll(() { - setCurrentLogWriter(debug: debug); - }); - - TestDebuggerConnection? debugger; - TestDebuggerConnection getDebugger() => debugger!; - - setUp(() async { - setCurrentLogWriter(debug: debug); - debugger = TestDebuggerConnection(); - }); - - tearDown(() async { - await debugger?.close(); - }); - - test('is created on devtools request', () async { - final debugger = getDebugger(); - await debugger.createDebuggerExecutionContext(TestContextId.dartDefault); - - // Expect the context ID to be set. - expect(await debugger.defaultContextId(), TestContextId.dartDefault); - }); - - test('clears context ID', () async { - final debugger = getDebugger(); - await debugger.createDebuggerExecutionContext(TestContextId.dartDefault); - - debugger.sendContextsClearedEvent(); - - // Expect non-dart context. - expect(await debugger.defaultContextId(), TestContextId.none); - }); - - test('finds dart context ID', () async { - final debugger = getDebugger(); - await debugger.createDebuggerExecutionContext(TestContextId.none); - - debugger.sendContextCreatedEvent(TestContextId.dartNormal); - - // Expect dart context. - expect(await debugger.dartContextId(), TestContextId.dartNormal); - }); - - test('does not find dart context ID if not available', () async { - final debugger = getDebugger(); - await debugger.createDebuggerExecutionContext(TestContextId.none); - - // No context IDs received yet. - expect(await debugger.defaultContextId(), TestContextId.none); - - debugger.sendContextCreatedEvent(TestContextId.dartLate); - - // Expect no dart context. - // This mocks injected client still loading. - expect(await debugger.noContextId(), TestContextId.none); - - // Expect dart context. - // This mocks injected client loading later for previously - // received context ID. - expect(await debugger.dartContextId(), TestContextId.dartLate); - }); - - test('works with stale contexts', () async { - final debugger = getDebugger(); - await debugger.createDebuggerExecutionContext(TestContextId.none); - - debugger.sendContextCreatedEvent(TestContextId.stale); - - // Expect no dart context. - expect(await debugger.noContextId(), TestContextId.none); - - debugger.sendContextsClearedEvent(); - debugger.sendContextCreatedEvent(TestContextId.dartNormal); - - // Expect dart context. - expect(await debugger.dartContextId(), TestContextId.dartNormal); - }); - }); -} - -enum TestContextId { - none, - dartDefault, - dartNormal, - dartLate, - nonDart, - stale; - - factory TestContextId.from(int? value) { - return switch (value) { - null => none, - 0 => dartDefault, - 1 => dartNormal, - 2 => dartLate, - 3 => nonDart, - 4 => stale, - _ => throw StateError('$value is not a TestContextId'), - }; - } - - int? get id { - return switch (this) { - none => null, - dartDefault => 0, - dartNormal => 1, - dartLate => 2, - nonDart => 3, - stale => 4, - }; - } -} - -class TestExtensionDebugger extends ExtensionDebugger { - TestExtensionDebugger(FakeSseConnection super.sseConnection); - - @override - Future sendCommand( - String command, { - Map? params, - }) { - final id = params?['contextId'] as int?; - final response = super.sendCommand(command, params: params); - - /// Mock stale contexts that cause the evaluation to throw. - if (command == 'Runtime.evaluate' && - TestContextId.from(id) == TestContextId.stale) { - throw Exception('Stale execution context'); - } - return response; - } -} - -class TestDebuggerConnection { - late final TestExtensionDebugger extensionDebugger; - late final FakeSseConnection connection; - - int _evaluateRequestId = 0; - - TestDebuggerConnection() { - connection = FakeSseConnection(); - extensionDebugger = TestExtensionDebugger(connection); - } - - /// Create a new execution context in the debugger. - Future createDebuggerExecutionContext(TestContextId contextId) { - _sendDevToolsRequest(contextId: contextId.id); - return _executionContext(); - } - - /// Flush the streams and close debugger connection. - Future close() async { - unawaited(connection.controllerOutgoing.stream.any((e) => false)); - unawaited(extensionDebugger.devToolsRequestStream.any((e) => false)); - - await connection.controllerIncoming.sink.close(); - await connection.controllerOutgoing.sink.close(); - - await extensionDebugger.close(); - } - - /// Return the initial context ID from the DevToolsRequest. - Future defaultContextId() async { - // Give the previous events time to propagate. - await Future.delayed(const Duration(milliseconds: 100)); - return TestContextId.from(await extensionDebugger.executionContext!.id); - } - - /// Mock receiving dart context ID in the execution context. - /// - /// Note: dart context is detected by evaluation of - /// `window.$dartAppInstanceId` in that context returning - /// a non-null value. - Future dartContextId() async { - // Try getting execution id. - final executionContextId = extensionDebugger.executionContext!.id; - - // Give it time to send the evaluate request. - await Future.delayed(const Duration(milliseconds: 100)); - - // Respond to the evaluate request. - _sendEvaluationResponse({ - 'result': {'value': 'dart'}, - }); - - return TestContextId.from(await executionContextId); - } - - /// Mock receiving non-dart context ID in the execution context. - /// - /// Note: dart context is detected by evaluation of - /// `window.$dartAppInstanceId` in that context returning - /// a null value. - Future noContextId() async { - // Try getting execution id. - final executionContextId = extensionDebugger.executionContext!.id; - - // Give it time to send the evaluate request. - await Future.delayed(const Duration(milliseconds: 100)); - - // Respond to the evaluate request. - _sendEvaluationResponse({ - 'result': {'value': null}, - }); - - return TestContextId.from(await executionContextId); - } - - /// Send `Runtime.executionContextsCleared` event to the execution - /// context in the extension debugger. - void sendContextsClearedEvent() { - final extensionEvent = ExtensionEvent( - method: jsonEncode('Runtime.executionContextsCleared'), - params: jsonEncode({}), - ); - connection.controllerIncoming.sink.add(jsonEncode(extensionEvent)); - } - - /// Send `Runtime.executionContextCreated` event to the execution - /// context in the extension debugger. - void sendContextCreatedEvent(TestContextId contextId) { - final extensionEvent = ExtensionEvent( - method: jsonEncode('Runtime.executionContextCreated'), - params: jsonEncode({ - 'context': {'id': '${contextId.id}'}, - }), - ); - connection.controllerIncoming.sink.add(jsonEncode(extensionEvent)); - } - - void _sendEvaluationResponse(Map response) { - // Respond to the evaluate request. - final extensionResponse = ExtensionResponse( - result: jsonEncode(response), - id: _evaluateRequestId++, - success: true, - ); - connection.controllerIncoming.sink.add(jsonEncode(extensionResponse)); - } - - void _sendDevToolsRequest({int? contextId}) { - final devToolsRequest = DevToolsRequest( - contextId: contextId, - appId: 'app', - instanceId: '0', - ); - connection.controllerIncoming.sink.add(jsonEncode(devToolsRequest)); - } - - Future _executionContext() async { - final executionContext = await _waitForExecutionContext().timeout( - const Duration(milliseconds: 100), - onTimeout: () { - expect(fail, 'Timeout getting execution context'); - return null; - }, - ); - expect(executionContext, isNotNull); - } - - Future _waitForExecutionContext() async { - while (extensionDebugger.executionContext == null) { - await Future.delayed(const Duration(milliseconds: 20)); - } - return extensionDebugger.executionContext; - } -} diff --git a/dwds/test/integration/expression_compiler_service_common.dart b/dwds/test/integration/expression_compiler_service_common.dart deleted file mode 100644 index 3b5482eb45..0000000000 --- a/dwds/test/integration/expression_compiler_service_common.dart +++ /dev/null @@ -1,353 +0,0 @@ -// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@TestOn('vm') -@Timeout(Duration(minutes: 2)) -library; - -import 'dart:async'; -import 'dart:convert'; -import 'dart:io'; - -import 'package:dwds/sdk_configuration.dart'; -import 'package:dwds/src/services/expression_compiler.dart'; -import 'package:dwds/src/services/expression_compiler_service.dart'; -import 'package:dwds/src/utilities/server.dart'; -import 'package:dwds_test_common/logging.dart'; -import 'package:logging/logging.dart'; -import 'package:shelf/shelf.dart'; -import 'package:test/test.dart'; - -ExpressionCompilerService get service => _service!; -late ExpressionCompilerService? _service; - -HttpServer get server => _server!; -late HttpServer? _server; - -StreamController get output => _output!; -late StreamController? _output; - -void testAll({required CompilerOptions compilerOptions}) { - group('expression compiler service with fake asset server', () { - final logger = Logger('ExpressionCompilerServiceTest'); - late Directory outputDir; - - Future stop() async { - await _service?.stop(); - await _server?.close(); - await _output?.close(); - _service = null; - _server = null; - _output = null; - } - - setUp(() async { - final systemTempDir = Directory.systemTemp; - outputDir = systemTempDir.createTempSync('foo bar'); - final source = outputDir.uri.resolve('try.dart'); - final packages = outputDir.uri.resolve('package_config.json'); - final kernel = outputDir.uri.resolve('try.full.dill'); - // Expression compiler service does not need any extra assets - // generated in the SDK, so we use the current SDK layout and - // configuration. - final executable = Platform.resolvedExecutable; - // redirect logs for testing - _output = StreamController.broadcast(); - output.stream.listen(printOnFailure); - - configureLogWriter( - customLogWriter: (level, message, {error, loggerName, stackTrace}) { - final e = error == null ? '' : ': $error'; - final s = stackTrace == null ? '' : ':\n$stackTrace'; - output.add('[$level] $loggerName: $message$e$s'); - }, - ); - - // start asset server - _server = await startHttpServer('localhost'); - final port = server.port; - - // start expression compilation service - Response assetHandler(request) => - Response(200, body: File.fromUri(kernel).readAsBytesSync()); - _service = ExpressionCompilerService( - 'localhost', - port, - verbose: false, - sdkConfigurationProvider: const DefaultSdkConfigurationProvider(), - ); - - await service.initialize(compilerOptions); - - // setup asset server - serveHttpRequests(server, assetHandler, (e, s) { - logger.warning('Error serving requests', e, s); - }); - - // generate full dill - File.fromUri(source) - ..createSync() - ..writeAsStringSync('''void main() { - // breakpoint line - }'''); - - File.fromUri(packages) - ..createSync() - ..writeAsStringSync(''' - { - "configVersion": 2, - "packages": [ - { - "name": "try", - "rootUri": "./", - "packageUri": "./" - } - ] - } - '''); - - final args = [ - 'compile', - 'js-dev', - 'try.dart', - '-o', - 'try.js', - '--experimental-output-compiled-kernel', - '--multi-root', - '${outputDir.uri}', - '--multi-root-scheme', - 'org-dartlang-app', - '--packages', - packages.path, - ]; - final process = - await Process.start( - executable, - args, - workingDirectory: outputDir.path, - ).then((p) { - transformToLines(p.stdout).listen(output.add); - transformToLines(p.stderr).listen(output.add); - return p; - }); - expect( - await process.exitCode, - 0, - reason: 'failed running $executable with args $args', - ); - expect( - File.fromUri(kernel).existsSync(), - true, - reason: 'failed to create full dill', - ); - }); - - tearDown(() async { - await stop(); - outputDir.deleteSync(recursive: true); - }); - - test('works with no errors', () async { - expect(output.stream, neverEmits(contains('[SEVERE]'))); - expect( - output.stream, - emitsThrough( - contains( - '[INFO] ExpressionCompilerService: Updating dependencies...', - ), - ), - ); - expect( - output.stream, - emitsThrough( - contains('[INFO] ExpressionCompilerService: Updated dependencies.'), - ), - ); - expect( - output.stream, - emitsThrough( - contains('[FINEST] ExpressionCompilerService: Compiling "true" at'), - ), - ); - expect( - output.stream, - emitsThrough( - contains('[FINEST] ExpressionCompilerService: Compiled "true" to:'), - ), - ); - expect( - output.stream, - emitsThrough(contains('[INFO] ExpressionCompilerService: Stopped.')), - ); - final result = await service.updateDependencies({ - 'try': ModuleInfo('try.full.dill', 'try.dill'), - }); - expect(result, true, reason: 'failed to update dependencies'); - - final compilationResult = await service.compileExpressionToJs( - '0', - 'org-dartlang-app:/try.dart', - 'org-dartlang-app:/try.dart', - 2, - 1, - {}, - {}, - 'try', - 'true', - ); - - expect( - compilationResult, - isA() - .having((r) => r.result, 'result', contains('return true;')) - .having((r) => r.isError, 'isError', false), - ); - - await stop(); - }); - - test('can evaluate multiple expressions', () async { - expect(output.stream, neverEmits(contains('[SEVERE]'))); - expect( - output.stream, - emitsThrough( - contains( - '[INFO] ExpressionCompilerService: Updating dependencies...', - ), - ), - ); - expect( - output.stream, - emitsThrough( - contains('[INFO] ExpressionCompilerService: Updated dependencies.'), - ), - ); - - expect( - output.stream, - emitsThrough(contains('[INFO] ExpressionCompilerService: Stopped.')), - ); - final result = await service.updateDependencies({ - 'try': ModuleInfo('try.full.dill', 'try.dill'), - }); - expect(result, true, reason: 'failed to update dependencies'); - - final compilationResult1 = await service.compileExpressionToJs( - '0', - 'org-dartlang-app:/try.dart', - 'org-dartlang-app:/try.dart', - 2, - 1, - {}, - {}, - 'try', - 'true', - ); - final compilationResult2 = await service.compileExpressionToJs( - '0', - 'org-dartlang-app:/try.dart', - 'org-dartlang-app:/try.dart', - 2, - 1, - {}, - {}, - 'try', - 'false', - ); - - expect( - compilationResult1, - isA() - .having((r) => r.result, 'result', contains('return true;')) - .having((r) => r.isError, 'isError', false), - ); - - expect( - compilationResult2, - isA() - .having((r) => r.result, 'result', contains('return false;')) - .having((r) => r.isError, 'isError', false), - ); - - await stop(); - }); - - test('can compile multiple expressions in parallel', () async { - expect(output.stream, neverEmits(contains('[SEVERE]'))); - expect( - output.stream, - emitsThrough( - contains( - '[INFO] ExpressionCompilerService: Updating dependencies...', - ), - ), - ); - expect( - output.stream, - emitsThrough( - contains('[INFO] ExpressionCompilerService: Updated dependencies.'), - ), - ); - - expect( - output.stream, - emitsThrough(contains('[INFO] ExpressionCompilerService: Stopped.')), - ); - final result = await service.updateDependencies({ - 'try': ModuleInfo('try.full.dill', 'try.dill'), - }); - expect(result, true, reason: 'failed to update dependencies'); - - final compilationResult1 = service.compileExpressionToJs( - '0', - 'org-dartlang-app:/try.dart', - 'org-dartlang-app:/try.dart', - 2, - 1, - {}, - {}, - 'try', - 'true', - ); - final compilationResult2 = service.compileExpressionToJs( - '0', - 'org-dartlang-app:/try.dart', - 'org-dartlang-app:/try.dart', - 2, - 1, - {}, - {}, - 'try', - 'false', - ); - - final results = await Future.wait([ - compilationResult1, - compilationResult2, - ]); - - expect( - results[0], - isA() - .having((r) => r.result, 'result', contains('return true;')) - .having((r) => r.isError, 'isError', false), - ); - - expect( - results[1], - isA() - .having((r) => r.result, 'result', contains('return false;')) - .having((r) => r.isError, 'isError', false), - ); - - await stop(); - }); - }); -} - -Stream transformToLines(Stream> byteStream) { - return byteStream - .transform(utf8.decoder) - .transform(const LineSplitter()); -} diff --git a/dwds/test/integration/expression_compiler_service_ddc_library_bundle_test.dart b/dwds/test/integration/expression_compiler_service_ddc_library_bundle_test.dart deleted file mode 100644 index 53ce3674a1..0000000000 --- a/dwds/test/integration/expression_compiler_service_ddc_library_bundle_test.dart +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@Tags(['daily']) -@TestOn('vm') -@Timeout(Duration(minutes: 2)) -library; - -import 'package:dwds/expression_compiler.dart'; -import 'package:test/test.dart'; - -import 'expression_compiler_service_common.dart'; - -void main() async { - testAll( - compilerOptions: CompilerOptions( - moduleFormat: ModuleFormat.ddc, - canaryFeatures: true, - experiments: const [], - ), - ); -} diff --git a/dwds/test/integration/expression_evaluator_test.dart b/dwds/test/integration/expression_evaluator_test.dart deleted file mode 100644 index 92a0be7316..0000000000 --- a/dwds/test/integration/expression_evaluator_test.dart +++ /dev/null @@ -1,252 +0,0 @@ -// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@TestOn('vm') -@Timeout(Duration(minutes: 2)) -library; - -import 'dart:async'; - -import 'package:dwds/src/debugging/debugger.dart'; -import 'package:dwds/src/debugging/location.dart'; -import 'package:dwds/src/debugging/skip_list.dart'; -import 'package:dwds/src/services/batched_expression_evaluator.dart'; -import 'package:dwds/src/services/expression_evaluator.dart'; -import 'package:dwds/src/utilities/shared.dart'; - -import 'package:test/test.dart'; -import 'package:vm_service/vm_service.dart' hide LogRecord; -import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'; - -import 'fixtures/context.dart'; -import 'fixtures/fakes.dart'; -import 'fixtures/utilities.dart'; - -late ExpressionEvaluator? _evaluator; -late ExpressionEvaluator? _batchedEvaluator; - -void main() async { - group('expression compiler service with fake asset server', () { - Future stop() async { - _evaluator?.close(); - _evaluator = null; - _batchedEvaluator?.close(); - _batchedEvaluator = null; - } - - late StreamController pausedController; - late StreamController debugEventController; - late FakeChromeAppInspector inspector; - setUp(() async { - final assetReader = FakeAssetReader(sourceMap: ''); - final toolConfiguration = TestToolConfiguration.withLoadStrategy( - loadStrategy: FakeStrategy(assetReader), - ); - setGlobalsForTesting(toolConfiguration: toolConfiguration); - final modules = FakeModules(); - - final webkitDebugger = FakeWebkitDebugger(); - pausedController = StreamController(); - debugEventController = StreamController(); - webkitDebugger.onPaused = pausedController.stream; - - final root = 'fakeRoot'; - final entry = 'fake_entrypoint'; - final locations = Locations(assetReader, modules, root); - await locations.initialize(entry); - - final skipLists = SkipLists(root); - final debugger = await Debugger.create( - webkitDebugger, - (_, e) => debugEventController.sink.add(e), - locations, - skipLists, - root, - ); - inspector = FakeChromeAppInspector( - webkitDebugger, - fakeIsolate: simpleIsolate, - ); - debugger.updateInspector(inspector); - - _evaluator = ExpressionEvaluator( - entry, - inspector, - debugger, - locations, - modules, - FakeExpressionCompiler(), - ); - _batchedEvaluator = BatchedExpressionEvaluator( - entry, - inspector, - debugger, - locations, - modules, - FakeExpressionCompiler(), - ); - }); - - tearDown(() async { - await stop(); - }); - - group('evaluator', () { - late ExpressionEvaluator evaluator; - - setUp(() async { - evaluator = _evaluator!; - }); - - test('can evaluate expression', () async { - final result = await evaluator.evaluateExpression( - '1', - 'main.dart', - 'true', - {}, - ); - expect( - result, - const TypeMatcher().having( - (o) => o.value, - 'value', - 'true', - ), - ); - }); - - test('can evaluate expression in frame with null scope', () async { - // Verify that we don't get the internal error. - // More extensive testing of 'evaluateExpressionInFrame' is done in - // evaluation tests for frontend server and build daemon. - await expectLater( - evaluator.evaluateExpressionInFrame('1', 0, 'true', null), - throwsRPCErrorWithMessage( - 'Cannot evaluate on a call frame when the program is not paused', - ), - ); - }); - - test('cannot evaluate expression in async frame ', () async { - // Add a DebuggerPausedEvent with no frames provoke an error. - pausedController.sink.add( - DebuggerPausedEvent({ - 'method': '', - 'params': { - 'reason': 'other', - 'callFrames': >[], - }, - }), - ); - - await debugEventController.stream.firstWhere( - (e) => e.kind == EventKind.kPauseInterrupted, - ); - - // Verify that we get the internal error. - final result = await evaluator.evaluateExpressionInFrame( - '20', - 0, - 'true', - null, - ); - expect( - result, - isA() - .having((o) => o.json['type'], 'type', 'AsyncFrameError') - .having( - (o) => o.json['value'], - 'value', - 'Expression evaluation in async frames is not supported. ' - 'No frame with index 0.', - ), - ); - }); - - test('can evaluate expression in frame with empty scope', () async { - // Verify that we don't get the internal error. - // More extensive testing of 'evaluateExpressionInFrame' is done in - // evaluation tests for frontend server and build daemon. - await expectLater( - evaluator.evaluateExpressionInFrame('1', 0, 'true', {}), - throwsRPCErrorWithMessage( - 'Cannot evaluate on a call frame when the program is not paused', - ), - ); - }); - - test('returns error if closed', () async { - evaluator.close(); - final result = await evaluator.evaluateExpression( - '1', - 'main.dart', - 'true', - {}, - ); - expect( - result, - const TypeMatcher() - .having((o) => o.type, 'type', 'InternalError') - .having((o) => o.value, 'value', contains('evaluator closed')), - ); - }); - }); - - group('batched evaluator', () { - late ExpressionEvaluator evaluator; - - setUp(() async { - evaluator = _batchedEvaluator!; - }); - - test('can evaluate expression', () async { - final result = await evaluator.evaluateExpression( - '1', - 'main.dart', - 'true', - {}, - ); - expect( - result, - const TypeMatcher().having( - (o) => o.value, - 'value', - 'true', - ), - ); - }); - - test('retries failed batched expression', () async { - safeUnawaited( - evaluator.evaluateExpression('2', 'main.dart', 'true', {}), - ); - - await evaluator.evaluateExpression('2', 'main.dart', 'false', {}); - expect(inspector.functionsCalled.length, 3); - expect( - inspector.functionsCalled[0].contains('return [ true, false ];'), - true, - ); - expect(inspector.functionsCalled[1].contains('return true;'), true); - expect(inspector.functionsCalled[2].contains('return false;'), true); - }); - - test('returns error if closed', () async { - evaluator.close(); - final result = await evaluator.evaluateExpression( - '1', - 'main.dart', - 'true', - {}, - ); - expect( - result, - const TypeMatcher() - .having((o) => o.type, 'type', 'InternalError') - .having((o) => o.value, 'value', contains('evaluator closed')), - ); - }); - }); - }); -} diff --git a/dwds/test/integration/extension_backend_test.dart b/dwds/test/integration/extension_backend_test.dart deleted file mode 100644 index 41bdbadd43..0000000000 --- a/dwds/test/integration/extension_backend_test.dart +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@Timeout(Duration(minutes: 2)) -library; - -import 'dart:async'; - -import 'package:async/src/stream_queue.dart'; -import 'package:dwds/data/extension_request.dart'; -import 'package:dwds/src/handlers/socket_connections.dart'; -import 'package:dwds/src/servers/extension_backend.dart'; -import 'package:http/http.dart' as http; -import 'package:shelf/src/request.dart'; -import 'package:shelf/src/response.dart'; -import 'package:test/test.dart'; - -class MockSocketHandler implements SocketHandler { - static const mockResponse = 'Returned from MockSocketHandler'; - @override - StreamQueue get connections => - StreamQueue(const Stream.empty()); - - @override - FutureOr handler(Request request) { - return Response.ok(mockResponse); - } - - @override - void shutdown() {} -} - -void main() { - late ExtensionBackend extensionBackend; - - setUpAll(() async { - extensionBackend = await ExtensionBackend.start( - MockSocketHandler(), - 'localhost', - ); - }); - test('returns success statusCode', () async { - final result = await http.get( - Uri.parse( - 'http://localhost:${extensionBackend.port}/$authenticationPath', - ), - ); - expect(result.statusCode, 200); - }); - - test('returns expected authentication response', () async { - final result = await http.get( - Uri.parse( - 'http://localhost:${extensionBackend.port}/$authenticationPath', - ), - ); - expect(result.body, authenticationResponse); - }); - - test('delegates to the underlying socket handler', () async { - final result = await http.get( - Uri.parse('http://localhost:${extensionBackend.port}/somedummypath'), - ); - expect(result.body, MockSocketHandler.mockResponse); - }); -} diff --git a/dwds/test/integration/extension_debugger_test.dart b/dwds/test/integration/extension_debugger_test.dart deleted file mode 100644 index 024ead4849..0000000000 --- a/dwds/test/integration/extension_debugger_test.dart +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@Timeout(Duration(minutes: 2)) -library; - -import 'dart:async'; -import 'dart:convert'; - -import 'package:dwds/data/devtools_request.dart'; -import 'package:dwds/data/extension_request.dart'; -import 'package:dwds/src/servers/extension_debugger.dart'; -import 'package:test/test.dart'; -import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'; - -import 'fixtures/debugger_data.dart'; -import 'fixtures/fakes.dart'; - -late FakeSseConnection connection; -late ExtensionDebugger extensionDebugger; - -void main() async { - setUp(() async { - connection = FakeSseConnection(); - extensionDebugger = ExtensionDebugger(connection); - }); - - tearDown(() { - connection.controllerIncoming.close(); - connection.controllerOutgoing.close(); - }); - - group('can receive', () { - test('an ExtensionResponse', () async { - final extensionResponse = ExtensionResponse( - id: 0, - success: true, - result: jsonEncode({ - 'result': {'value': 3.14}, - }), - ); - final resultCompleter = Completer(); - unawaited( - extensionDebugger - .sendCommand('Runtime.evaluate', params: {'expression': '\$pi'}) - .then(resultCompleter.complete), - ); - connection.controllerIncoming.sink.add(jsonEncode(extensionResponse)); - final response = await resultCompleter.future; - expect( - (response.result!['result'] as Map)['value'], - 3.14, - ); - }); - - test('an ExtensionEvent', () async { - final extensionEvent = ExtensionEvent( - method: jsonEncode('Debugger.paused'), - params: jsonEncode(frames1Json[0]), - ); - connection.controllerIncoming.sink.add(jsonEncode(extensionEvent)); - final wipEvent = await extensionDebugger.onNotification.first; - expect(wipEvent.method, 'Debugger.paused'); - expect(wipEvent.params, frames1Json[0]); - }); - - test('a BatchedEvents', () async { - final event1 = ExtensionEvent( - method: jsonEncode('Debugger.scriptParsed'), - params: jsonEncode(scriptParsedParams), - ); - final event2 = ExtensionEvent( - method: jsonEncode('Debugger.scriptParsed'), - params: jsonEncode(scriptParsedParams), - ); - final batch = BatchedEvents(events: [event1, event2]); - connection.controllerIncoming.sink.add(jsonEncode(batch)); - final wipEvent = await extensionDebugger.onNotification.first; - expect(wipEvent.method, 'Debugger.scriptParsed'); - expect(wipEvent.params, scriptParsedParams); - }); - - test('a DevToolsRequest', () async { - final devToolsRequest = DevToolsRequest( - appId: '3.14', - instanceId: '6.28', - tabUrl: 'pi/calculus', - ); - connection.controllerIncoming.sink.add(jsonEncode(devToolsRequest)); - final request = await extensionDebugger.devToolsRequestStream.first; - expect(request.tabUrl, 'pi/calculus'); - expect(request.appId, '3.14'); - expect(request.instanceId, '6.28'); - }); - }); - - group('can send', () { - test('a request with empty params', () async { - final extensionRequest = ExtensionRequest( - id: 0, - command: 'Debugger.pause', - commandParams: jsonEncode({}), - ); - unawaited(extensionDebugger.pause()); - final decoded = jsonDecode( - await connection.controllerOutgoing.stream.first, - ); - final request = ExtensionRequest.fromJson(decoded as List); - expect(request, extensionRequest); - }); - - test('a request with some params', () async { - final params = { - 'location': {'scriptId': '555', 'lineNumber': 28}, - }; - final extensionRequest = ExtensionRequest( - id: 0, - command: 'Debugger.setBreakpoint', - commandParams: jsonEncode(params), - ); - unawaited( - extensionDebugger.sendCommand('Debugger.setBreakpoint', params: params), - ); - final decoded = jsonDecode( - await connection.controllerOutgoing.stream.first, - ); - final request = ExtensionRequest.fromJson(decoded as List); - expect(request, extensionRequest); - }); - }); - group('when closed', () { - test('DebugExtension.detached event closes the connection', () async { - final extensionEvent = ExtensionEvent( - method: jsonEncode('DebugExtension.detached'), - params: jsonEncode({}), - ); - - connection.controllerIncoming.sink.add(jsonEncode(extensionEvent)); - // Expect the connection to receive a close event: - expect(await extensionDebugger.onClose.first, isNotNull); - }); - - test( - 'gracefully handles trying to send events after the connection is closed', - () async { - // Close the connection: - final extensionEvent = ExtensionEvent( - method: jsonEncode('DebugExtension.detached'), - params: jsonEncode({}), - ); - connection.controllerIncoming.sink.add(jsonEncode(extensionEvent)); - // Wait for it to be closed: - await extensionDebugger.onClose.first; - // Try to send an event: - Future callToSendCommand() => extensionDebugger.sendCommand( - 'Debugger.setBreakpoint', - params: { - 'location': {'scriptId': '555', 'lineNumber': 28}, - }, - ); - // Should not throw any errors: - expect(callToSendCommand, returnsNormally); - }, - ); - }); -} diff --git a/dwds/test/integration/fixtures/context.dart b/dwds/test/integration/fixtures/context.dart deleted file mode 100644 index 632e7bd798..0000000000 --- a/dwds/test/integration/fixtures/context.dart +++ /dev/null @@ -1,957 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -// @skip_package_deps_validation - -import 'dart:async'; -import 'dart:convert'; -import 'dart:io'; - -import 'package:build_daemon/client.dart'; -import 'package:build_daemon/data/build_status.dart'; -import 'package:build_daemon/data/build_target.dart'; -import 'package:dwds/asset_reader.dart'; -import 'package:dwds/dart_web_debug_service.dart'; -import 'package:dwds/src/connections/app_connection.dart'; -import 'package:dwds/src/connections/debug_connection.dart'; -import 'package:dwds/src/debugging/webkit_debugger.dart'; -import 'package:dwds/src/loaders/build_runner_strategy_provider.dart'; -import 'package:dwds/src/loaders/frontend_server_strategy_provider.dart'; -import 'package:dwds/src/loaders/strategy.dart'; -import 'package:dwds/src/readers/proxy_server_asset_reader.dart'; -import 'package:dwds/src/services/chrome/chrome_proxy_service.dart'; -import 'package:dwds/src/services/expression_compiler.dart'; -import 'package:dwds/src/services/expression_compiler_service.dart'; -import 'package:dwds/src/utilities/dart_uri.dart'; -import 'package:dwds/src/utilities/server.dart'; -import 'package:dwds_test_common/logging.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:dwds_test_common/utilities.dart'; -import 'package:file/local.dart'; -import 'package:http/http.dart'; -import 'package:http/io_client.dart'; -import 'package:logging/logging.dart' as logging; -import 'package:path/path.dart' as p; -import 'package:shelf/shelf.dart' as shelf; -import 'package:shelf/shelf.dart'; -import 'package:shelf_proxy/shelf_proxy.dart'; -import 'package:test/test.dart'; -import 'package:vm_service/vm_service.dart'; -import 'package:vm_service/vm_service_io.dart'; -import 'package:webdriver/async_io.dart'; -import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'; - -import '../../frontend_server_common/devfs.dart'; -import '../../frontend_server_common/resident_runner.dart'; -import 'project.dart'; -import 'server.dart'; -import 'utilities.dart'; - -final _exeExt = Platform.isWindows ? '.exe' : ''; - -const isRPCError = TypeMatcher(); -const isSentinelException = TypeMatcher(); - -final Matcher throwsRPCError = throwsA(isRPCError); -final Matcher throwsSentinelException = throwsA(isSentinelException); - -Matcher isRPCErrorWithMessage(String message) => isA().having( - (RPCError e) => e.message, - 'message', - contains(message), -); -Matcher throwsRPCErrorWithMessage(String message) => - throwsA(isRPCErrorWithMessage(message)); - -Matcher isRPCErrorWithCode(int code) => - isA().having((RPCError e) => e.code, 'code', equals(code)); -Matcher throwsRPCErrorWithCode(int code) => throwsA(isRPCErrorWithCode(code)); - -enum CompilationMode { - buildDaemon(false, true, false), - frontendServer(true, false, false), - buildDaemonAndFrontendServer(true, true, true); - - final bool usesFrontendServer; - final bool usesBuildDaemon; - final bool usesDdcModulesOnly; - - const CompilationMode( - this.usesFrontendServer, - this.usesBuildDaemon, - this.usesDdcModulesOnly, - ); -} - -class TestContext { - final TestProject project; - final TestSdkConfigurationProvider sdkConfigurationProvider; - - String get appUrl => _appUrl!; - late String? _appUrl; - - WipConnection get tabConnection => _tabConnection!; - late WipConnection? _tabConnection; - - TestServer get testServer => _testServer!; - TestServer? _testServer; - - Dwds? get dwds => _testServer?.dwds; - - BuildDaemonClient get daemonClient => _daemonClient!; - BuildDaemonClient? _daemonClient; - - ResidentWebRunner get webRunner => _webRunner!; - ResidentWebRunner? _webRunner; - - WebDriver get webDriver => _webDriver!; - WebDriver? _webDriver; - - Process get chromeDriver => _chromeDriver!; - Process? _chromeDriver; - - WebkitDebugger get webkitDebugger => _webkitDebugger!; - late WebkitDebugger? _webkitDebugger; - - Handler get assetHandler => _assetHandler!; - late Handler? _assetHandler; - - Client get client => _client!; - Client? _client; - - ExpressionCompilerService? ddcService; - - int get port => _port!; - late int? _port; - - Directory get outputDir => _outputDir!; - Directory? _outputDir; - - late WipConnection extensionConnection; - late AppConnection appConnection; - late DebugConnection debugConnection; - - final _logger = logging.Logger('Context'); - - final _serviceNameToMethod = {}; - - late LocalFileSystem frontendServerFileSystem; - - late String _hostname; - - /// Internal VM service. - /// - /// Prefer using [vmService] instead in tests when possible, to include - /// testing of the VmServerConnection (bypassed when using [service]). - ChromeProxyService get service => fetchChromeProxyService(debugConnection); - - /// External VM service. - VmService get vmService => debugConnection.vmService; - - TestContext(this.project, this.sdkConfigurationProvider); - - Future setUp({ - TestSettings testSettings = const TestSettings(), - TestAppMetadata appMetadata = const TestAppMetadata.externalApp(), - TestDebugSettings debugSettings = - const TestDebugSettings.noDevToolsLaunch(), - }) async { - try { - // Build settings to return from load strategy. - final buildSettings = TestBuildSettings( - appEntrypoint: project.dartEntryFilePackageUri, - canaryFeatures: testSettings.canaryFeatures, - isFlutterApp: testSettings.isFlutterApp, - experiments: testSettings.experiments, - ); - - // Make sure configuration was created correctly. - final sdkLayout = sdkConfigurationProvider.sdkLayout; - final configuration = await sdkConfigurationProvider.configuration; - configuration.validate(); - await project.setUp(); - - DartUri.currentDirectory = project.absolutePackageDirectory; - - _logger.info( - 'Serving: ${project.directoryToServe}/${project.filePathToServe}', - ); - _logger.info('Project: ${project.absolutePackageDirectory}'); - _logger.info('Packages: ${project.packageConfigFile}'); - _logger.info('Entry: ${project.dartEntryFilePath}'); - - configureLogWriter(); - - _client = IOClient( - HttpClient() - ..maxConnectionsPerHost = 200 - ..idleTimeout = const Duration(seconds: 30) - ..connectionTimeout = const Duration(seconds: 30), - ); - - final systemTempDir = Directory.systemTemp; - _outputDir = systemTempDir.createTempSync('foo bar'); - - final chromeDriverPort = await findUnusedPort(); - final chromeDriverUrlBase = 'wd/hub'; - try { - _chromeDriver = await Process.start('chromedriver$_exeExt', [ - '--port=$chromeDriverPort', - '--url-base=$chromeDriverUrlBase', - ]); - final stdOutLines = chromeDriver.stdout - .transform(utf8.decoder) - .transform(const LineSplitter()) - .asBroadcastStream(); - - final stdErrLines = chromeDriver.stderr - .transform(utf8.decoder) - .transform(const LineSplitter()) - .asBroadcastStream(); - - // Sometimes ChromeDriver can be slow to startup. - // This was seen on a github actions run: - // > 11:22:59.924700: ChromeDriver stdout: Starting ChromeDriver - // > 139.0.7258.154 ([...]) on port 38107 - // > [...] - // > 11:23:00.237350: ChromeDriver stdout: ChromeDriver was started - // > successfully on port 38107. - // Where in the 300+ ms it took before it was actually ready to accept - // a connection we had tried - and failed - to connect. - // We therefore wait until ChromeDriver reports that it has started - // successfully. - - final chromeDriverStartup = Completer(); - stdOutLines.listen((line) { - if (!chromeDriverStartup.isCompleted && - line.contains('was started successfully')) { - chromeDriverStartup.complete(); - } - _logger.finest('ChromeDriver stdout: $line'); - }); - stdErrLines.listen( - (line) => _logger.warning('ChromeDriver stderr: $line'), - ); - - await chromeDriverStartup.future; - } catch (e) { - throw StateError( - 'Could not start ChromeDriver. Is it installed?\nError: $e', - ); - } - - await Process.run(sdkLayout.dartPath, [ - 'pub', - 'upgrade', - ], workingDirectory: project.absolutePackageDirectory); - - ExpressionCompiler? expressionCompiler; - AssetReader assetReader; - Stream buildResults; - LoadStrategy loadStrategy; - var basePath = ''; - var filePathToServe = project.filePathToServe; - - // Start the HTTP server and save its used port. - final httpServer = await startHttpServer('localhost'); - _port = httpServer.port; - - final reloadedSourcesUri = Uri.parse( - 'http://localhost:$_port/${WebDevFS.reloadedSourcesFileName}', - ); - - switch (testSettings.compilationMode) { - case CompilationMode.buildDaemon: - { - final options = [ - if (testSettings.enableExpressionEvaluation) ...[ - '--define', - 'build_web_compilers|ddc=generate-full-dill=true', - ], - for (final experiment in buildSettings.experiments) - '--enable-experiment=$experiment', - if (buildSettings.canaryFeatures) ...[ - '--define', - 'build_web_compilers|ddc=canary=true', - '--define', - 'build_web_compilers|sdk_js=canary=true', - ], - if (testSettings.moduleFormat == ModuleFormat.ddc) ...[ - '--define', - 'build_web_compilers|ddc=ddc-library-bundle=true', - '--define', - 'build_web_compilers|sdk_js=ddc-library-bundle=true', - '--define', - 'build_web_compilers|entrypoint=ddc-library-bundle=true', - '--define', - 'build_web_compilers|entrypoint_marker=ddc-library-bundle=true', - ], - '--verbose', - ]; - _daemonClient = await connectClient( - sdkLayout.dartPath, - project.absolutePackageDirectory, - options, - (log) { - final record = log.toLogRecord(); - final name = record.loggerName == '' - ? '' - : '${record.loggerName}: '; - _logger.log( - record.level, - '$name${record.message}', - record.error, - record.stackTrace, - ); - }, - ); - daemonClient.registerBuildTarget( - DefaultBuildTarget((b) => b..target = project.directoryToServe), - ); - daemonClient.startBuild(); - - await waitForSuccessfulBuild(); - - final assetServerPort = daemonPort( - project.absolutePackageDirectory, - ); - _assetHandler = _createBuildRunnerProxyHandler(assetServerPort); - if (testSettings.moduleFormat == ModuleFormat.ddc && - buildSettings.canaryFeatures) { - _assetHandler = _handleReloadedSources(_assetHandler!); - } - assetReader = ProxyServerAssetReader( - assetServerPort, - root: project.directoryToServe, - ); - - if (testSettings.enableExpressionEvaluation) { - ddcService = ExpressionCompilerService( - 'localhost', - _port!, - verbose: testSettings.verboseCompiler, - sdkConfigurationProvider: sdkConfigurationProvider, - ); - expressionCompiler = ddcService; - } - - loadStrategy = switch (( - testSettings.moduleFormat, - buildSettings.canaryFeatures, - )) { - (ModuleFormat.ddc, true) => - BuildRunnerDdcLibraryBundleStrategyProvider( - testSettings.reloadConfiguration, - assetReader, - buildSettings, - reloadedSourcesUri: reloadedSourcesUri, - ).strategy, - (ModuleFormat.ddc, false) => throw Exception( - 'Unsupported DDC configuration: build daemon + canary (false) ' - '+ DDC module format ${testSettings.moduleFormat.name}.', - ), - - _ => BuildRunnerRequireStrategyProvider( - testSettings.reloadConfiguration, - assetReader, - buildSettings, - ).strategy, - }; - - buildResults = daemonClient.buildResults; - } - break; - case CompilationMode.frontendServer: - { - filePathToServe = webCompatiblePath([ - project.directoryToServe, - project.filePathToServe, - ]); - - _logger.info('Serving: $filePathToServe'); - - final entry = p.toUri( - p.join(project.webAssetsPath, project.dartEntryFileName), - ); - frontendServerFileSystem = const LocalFileSystem(); - final packageUriMapper = await PackageUriMapper.create( - frontendServerFileSystem, - project.packageConfigFile, - useDebuggerModuleNames: testSettings.useDebuggerModuleNames, - ); - - final compilerOptions = TestCompilerOptions( - experiments: buildSettings.experiments, - canaryFeatures: buildSettings.canaryFeatures, - moduleFormat: testSettings.moduleFormat, - ); - - _webRunner = ResidentWebRunner( - mainUri: entry, - urlTunneler: debugSettings.urlEncoder, - projectDirectory: Directory(project.absolutePackageDirectory).uri, - packageConfigFile: project.packageConfigFile, - packageUriMapper: packageUriMapper, - fileSystemRoots: [ - Directory(project.absolutePackageDirectory).uri, - ], - fileSystemScheme: 'org-dartlang-app', - outputPath: outputDir.path, - compilerOptions: compilerOptions, - sdkLayout: sdkLayout, - verbose: testSettings.verboseCompiler, - ); - - final assetServerPort = await findUnusedPort(); - _hostname = appMetadata.hostname; - await webRunner.run( - frontendServerFileSystem, - hostname: _hostname, - port: assetServerPort, - index: filePathToServe, - ); - - if (testSettings.enableExpressionEvaluation) { - expressionCompiler = webRunner.expressionCompiler; - } - - basePath = webRunner.devFS!.assetServer.basePath; - assetReader = webRunner.devFS!.assetServer; - _assetHandler = webRunner.devFS!.assetServer.handleRequest; - loadStrategy = switch (testSettings.moduleFormat) { - ModuleFormat.amd => FrontendServerRequireStrategyProvider( - testSettings.reloadConfiguration, - assetReader, - packageUriMapper, - () async => {}, - buildSettings, - ).strategy, - ModuleFormat.ddc => - buildSettings.canaryFeatures - ? FrontendServerDdcLibraryBundleStrategyProvider( - testSettings.reloadConfiguration, - assetReader, - packageUriMapper, - () async => {}, - buildSettings, - reloadedSourcesUri: reloadedSourcesUri, - ).strategy - : FrontendServerDdcStrategyProvider( - testSettings.reloadConfiguration, - assetReader, - packageUriMapper, - () async => {}, - buildSettings, - ).strategy, - _ => throw Exception( - 'Unsupported DDC module format ' - '${testSettings.moduleFormat.name}.', - ), - }; - buildResults = const Stream.empty(); - } - break; - case CompilationMode.buildDaemonAndFrontendServer: - { - final options = [ - if (testSettings.enableExpressionEvaluation) ...[ - '--define', - 'build_web_compilers|ddc=generate-full-dill=true', - ], - for (final experiment in buildSettings.experiments) - '--enable-experiment=$experiment', - '--define', - 'build_web_compilers|ddc=canary=true', - '--define', - 'build_web_compilers|sdk_js=canary=true', - '--define', - 'build_web_compilers|sdk_js=web-hot-reload=true', - '--define', - 'build_web_compilers|entrypoint=web-hot-reload=true', - '--define', - 'build_web_compilers|entrypoint_marker=web-hot-reload=true', - '--define', - 'build_web_compilers|entrypoint_marker=web-assets-path=' - '${project.webAssetsPath}', - '--define', - 'build_web_compilers|ddc=web-hot-reload=true', - '--define', - 'build_web_compilers|ddc_modules=web-hot-reload=true', - '--verbose', - ]; - _daemonClient = await connectClient( - sdkLayout.dartPath, - project.absolutePackageDirectory, - options, - (log) { - final record = log.toLogRecord(); - final name = record.loggerName == '' - ? '' - : '${record.loggerName}: '; - _logger.log( - record.level, - '$name${record.message}', - record.error, - record.stackTrace, - ); - }, - ); - daemonClient.registerBuildTarget( - DefaultBuildTarget((b) => b..target = project.directoryToServe), - ); - daemonClient.startBuild(); - - await waitForSuccessfulBuild(); - - final assetServerPort = daemonPort( - project.absolutePackageDirectory, - ); - _assetHandler = _createBuildRunnerProxyHandler(assetServerPort); - if (testSettings.moduleFormat == ModuleFormat.ddc && - buildSettings.canaryFeatures) { - _assetHandler = _handleReloadedSources(_assetHandler!); - } - assetReader = ProxyServerAssetReader( - assetServerPort, - root: project.directoryToServe, - ); - - if (testSettings.enableExpressionEvaluation) { - ddcService = ExpressionCompilerService( - 'localhost', - _port!, - verbose: testSettings.verboseCompiler, - sdkConfigurationProvider: sdkConfigurationProvider, - ); - expressionCompiler = ddcService; - } - frontendServerFileSystem = const LocalFileSystem(); - final packageUriMapper = await PackageUriMapper.create( - frontendServerFileSystem, - project.packageConfigFile, - useDebuggerModuleNames: testSettings.useDebuggerModuleNames, - ); - loadStrategy = switch (( - testSettings.moduleFormat, - buildSettings.canaryFeatures, - )) { - (ModuleFormat.ddc, true) => - FrontendServerDdcLibraryBundleStrategyProvider( - testSettings.reloadConfiguration, - assetReader, - packageUriMapper, - () async => {}, - buildSettings, - injectScriptLoad: false, - reloadedSourcesUri: reloadedSourcesUri, - ).strategy, - _ => throw Exception( - 'Unsupported DDC module format when compiling with Frontend ' - 'Server + build_runner ${testSettings.moduleFormat.name}.', - ), - }; - buildResults = const Stream.empty(); - } - break; - } - - final debugPort = await findUnusedPort(); - if (testSettings.launchChrome) { - // If the environment variable DWDS_DEBUG_CHROME is set to the string - // true then Chrome will be launched with a UI rather than headless. - // If the extension is enabled, then Chrome will be launched with a UI - // since headless Chrome does not support extensions. - final enableDebugExtension = debugSettings.enableDebugExtension; - final headless = - Platform.environment['DWDS_DEBUG_CHROME'] != 'true' && - !enableDebugExtension; - if (enableDebugExtension) { - await _buildDebugExtension(); - } - final capabilities = Capabilities.chrome - ..addAll({ - Capabilities.chromeOptions: { - 'args': [ - // --disable-gpu speeds up the tests that use ChromeDriver when - // they are run on GitHub Actions. - '--disable-gpu', - 'remote-debugging-port=$debugPort', - if (enableDebugExtension) - '--load-extension=debug_extension/prod_build', - if (headless) '--headless', - ], - }, - }); - _webDriver = await createDriver( - spec: WebDriverSpec.JsonWire, - desired: capabilities, - uri: Uri.parse( - 'http://127.0.0.1:$chromeDriverPort/$chromeDriverUrlBase/', - ), - ); - } - - // The debugger tab must be enabled and connected before certain - // listeners in DWDS or `main` is run. - final tabConnectionCompleter = Completer(); - final appConnectionCompleter = Completer(); - final connection = ChromeConnection('localhost', debugPort); - - // TODO(srujzs): In the case of the frontend server, it doesn't make sense - // that we initialize a new HTTP server instead of reusing the one in - // `TestAssetServer`. We should instead use that one to align with Flutter - // tools. - _testServer = await TestServer.start( - debugSettings: debugSettings.copyWith( - expressionCompiler: expressionCompiler, - ), - appMetadata: appMetadata, - port: port, - assetHandler: assetHandler, - assetReader: assetReader, - strategy: loadStrategy, - target: project.directoryToServe, - buildResults: buildResults, - chromeConnection: () async => connection, - httpServer: httpServer, - ); - - _testServer!.dwds.connectedApps.listen((connection) async { - // Ensure that we've established a tab connection before running main. - await tabConnectionCompleter.future; - if (testSettings.autoRun) { - connection.runMain(); - } - - // We may reuse the app connection, so only save it the first time - // it's encountered. - if (!appConnectionCompleter.isCompleted) { - appConnection = connection; - appConnectionCompleter.complete(); - } - }); - - _appUrl = basePath.isEmpty - ? 'http://localhost:$port/$filePathToServe' - : 'http://localhost:$port/$basePath/$filePathToServe'; - - if (testSettings.launchChrome) { - await _webDriver?.get(appUrl); - _tabConnection = await _getTabConnection(connection, appUrl); - tabConnectionCompleter.complete(); - - if (debugSettings.enableDebugExtension) { - final extensionTab = await _fetchDartDebugExtensionTab(connection); - extensionConnection = await extensionTab.connect(); - await extensionConnection.runtime.enable(); - } - - await appConnectionCompleter.future; - if (debugSettings.enableDebugging && !testSettings.waitToDebug) { - await startDebugging(); - } - _webkitDebugger = WebkitDebugger(WipDebugger(tabConnection)); - } else { - // No tab needs to be discovered, so fulfill the relevant completer. - tabConnectionCompleter.complete(); - } - } catch (e, s) { - _logger.severe('Failed to setup the service, $e:$s'); - await tearDown(); - rethrow; - } - } - - /// Creates a VM service connection connected to the debug URI. - /// - /// This can be used to test behavior that should be available to a client - /// connected to DWDS. - Future connectFakeClient() async { - final fakeClient = await vmServiceConnectUri(debugConnection.uri); - - fakeClient.onEvent(EventStreams.kService).listen(_handleServiceEvent); - await fakeClient.streamListen(EventStreams.kService); - - return fakeClient; - } - - /// Returns the service extension method given the [extensionName]. - /// - /// The extension be called by a client created with [connectFakeClient]. - String? getRegisteredServiceExtension(String extensionName) { - if (_serviceNameToMethod.isEmpty) { - throw StateError(''' - No registered service extensions. Did you call connectFakeClient? - '''); - } - - return _serviceNameToMethod[extensionName]; - } - - void _handleServiceEvent(Event e) { - if (e.kind == EventKind.kServiceRegistered) { - final serviceName = e.service!; - _serviceNameToMethod[serviceName] = e.method; - } - } - - Future startDebugging() async { - debugConnection = await testServer.dwds.debugConnection(appConnection); - } - - Future tearDown() async { - await _webRunner?.stop(); - await _webDriver?.quit(closeSession: true); - _chromeDriver?.kill(); - DartUri.currentDirectory = p.current; - await _daemonClient?.close(); - await ddcService?.stop(); - await _testServer?.stop(); - _client?.close(); - await _outputDir?.delete(recursive: true); - stopLogWriter(); - await project.tearDown(); - - // clear the state for next setup - _webDriver = null; - _chromeDriver = null; - _daemonClient = null; - ddcService = null; - _webRunner = null; - _testServer = null; - _client = null; - _outputDir = null; - } - - /// Given a list of edits, use file IO to write them to the file system. - /// - /// If `file` has the same name as the project's entry file name, that file - /// will be edited. Otherwise, it's assumed to be a library file. - // TODO(srujzs): It's possible we may want a library file with the same name - // as the entry file, but this function doesn't allow that. Potentially - // support that. - Future makeEdits(List edits) async { - // `dart:io`'s `stat` on Windows does not have millisecond precision so we - // need to make sure we wait long enough that modifications result in a - // timestamp that is guaranteed to be after the previous compile. - // TODO(https://github.com/dart-lang/sdk/issues/51937): Remove once this bug - // is fixed. - if (Platform.isWindows) { - await Future.delayed(const Duration(seconds: 1)); - } - _reloadedSources.clear(); - for (var (:file, :originalString, :newString) in edits) { - if (file == project.dartEntryFileName) { - file = project.dartEntryFilePath; - } else { - file = project.dartLibFilePath(file); - } - final f = File(file); - final fileContents = f.readAsStringSync(); - f.writeAsStringSync(fileContents.replaceAll(originalString, newString)); - - _updateReloadedSources(file); - } - } - - /// Updates the reloaded_sources.json manifest file for a running test. - /// - /// This logic essentially replicates the build system's naming conventions - /// for DDC's generated code. DWDS itself uses the metadata file, but this - /// isn't available for our test fixtures. - /// Rules: - /// - Entrypoints (served): web/main.dart -> main - /// - Entrypoints (nested): test/hello_world/main.dart -> hello_world/main - /// - Library files: lib/path/to/some_file.dart - /// -> packages/`package`/path/to/some_file - void _updateReloadedSources(String absolutePath) { - final relativePath = p.relative( - absolutePath, - from: project.absolutePackageDirectory, - ); - final relativeUrl = p.toUri(relativePath).path; - - String moduleName; - String libUri; - String srcPath; - - if (relativeUrl.startsWith('lib/')) { - final pathInLib = relativeUrl.substring(4); - moduleName = - 'packages/${project.packageName}/${p.withoutExtension(pathInLib)}'; - libUri = 'package:${project.packageName}/$pathInLib'; - srcPath = moduleName; - } else if (absolutePath == project.dartEntryFilePath) { - moduleName = p.withoutExtension(relativeUrl); - libUri = project.dartEntryFilePackageUri.toString(); - - final servePath = '${project.directoryToServe}/'; - if (relativeUrl.startsWith(servePath)) { - // e.g. web/main.dart -> main - srcPath = p.withoutExtension(relativeUrl.substring(servePath.length)); - } else { - // e.g. example/hello_world/main.dart -> example/hello_world/main - srcPath = moduleName; - } - } else { - throw StateError( - "Unhandled file path in test context's reloaded_sources.json: " - " $absolutePath. Only entrypoints and files in 'lib/' are supported.", - ); - } - - _reloadedSources.add( - WebDevFS.createReloadedSourceEntry( - src: '/$srcPath.ddc.js', - module: moduleName, - libraries: [libUri], - ), - ); - } - - /// Contains contents of the reloaded_sources.json manifest file. - /// - /// Used by the DDC Library Bundle module system to record changed files for - /// hot restart/reload. - final _reloadedSources = >[]; - - void addLibraryFile({required String libFileName, required String contents}) { - final file = File(project.dartLibFilePath(libFileName)); - // Library folder may not exist yet, so create it. - file.createSync(recursive: true); - file.writeAsStringSync(contents); - _updateReloadedSources(file.path); - } - - Handler _createBuildRunnerProxyHandler(int assetServerPort) { - return proxyHandler( - 'http://localhost:$assetServerPort/${project.directoryToServe}/', - client: client, - ); - } - - /// Wraps a handler to serve the reloaded_sources.json file for - /// reloads/restarts in the DDC Library Bundle module system. - Handler _handleReloadedSources(Handler proxy) { - return (request) { - final path = request.url.path; - if (path.endsWith(WebDevFS.reloadedSourcesFileName)) { - return shelf.Response.ok(jsonEncode(_reloadedSources)); - } - return proxy(request); - }; - } - - Future recompile({required bool fullRestart}) async { - await webRunner.rerun( - fullRestart: fullRestart, - fileServerUri: Uri.parse('http://${testServer.host}:${testServer.port}'), - ); - return; - } - - Future waitForSuccessfulBuild({ - Duration? timeout, - bool propagateToBrowser = false, - }) async { - // Wait for the build until the timeout is reached: - await daemonClient.buildResults - .firstWhere( - (BuildResults results) => results.results.any( - (BuildResult result) => result.status == BuildStatus.succeeded, - ), - ) - .timeout(timeout ?? const Duration(seconds: 60)); - - if (propagateToBrowser) { - // Allow change to propagate to the browser. - // Windows, or at least Travis on Windows, seems to need more time. - // TODO: Wait for an explicit finish signal instead of adding this delay. - final delay = Platform.isWindows - ? const Duration(seconds: 5) - : const Duration(seconds: 2); - await Future.delayed(delay); - } - } - - Future _buildDebugExtension() async { - final process = await Process.run('tool/build_extension.sh', [ - 'prod', - ], workingDirectory: absolutePath(pathFromDwds: 'debug_extension')); - print(process.stdout); - } - - Future _getTabConnection( - ChromeConnection connection, - String appUrl, - ) async { - final tab = await connection.getTab( - (t) => t.url == appUrl, - retryFor: const Duration(seconds: 5), - ); - if (tab == null) { - throw StateError( - 'Unable to connect to tab after retrying for 5 seconds.', - ); - } - final tabConnection = await tab.connect(); - await tabConnection.runtime.enable(); - await tabConnection.debugger.enable(); - return tabConnection; - } - - Future _fetchDartDebugExtensionTab( - ChromeConnection connection, - ) async { - const retries = 5; - for (var i = 0; i < retries; i++) { - if (i > 0) { - await Future.delayed(const Duration(milliseconds: 500)); - } - final extensionTabs = (await connection.getTabs()).where((tab) { - return tab.isChromeExtension; - }); - for (final tab in extensionTabs) { - final tabConnection = await tab.connect(); - final response = await tabConnection.runtime.evaluate( - 'window.isDartDebugExtension', - ); - if (response.value == true) { - return tab; - } - } - } - throw StateError('No extension installed.'); - } - - /// Finds the line number in [scriptRef] matching [breakpointId]. - /// - /// A breakpoint ID is found by looking for a line that ends with a comment - /// of exactly this form: `// Breakpoint: `. - /// - /// Throws if it can't find the matching line. - Future findBreakpointLine( - String breakpointId, - String isolateId, - ScriptRef scriptRef, - ) async { - final script = await debugConnection.vmService.getObject( - isolateId, - scriptRef.id!, - ) as Script; - final lines = LineSplitter.split(script.source!).toList(); - final lineNumber = lines.indexWhere( - (l) => l.endsWith('// Breakpoint: $breakpointId'), - ); - if (lineNumber == -1) { - throw StateError( - 'Unable to find breakpoint in ${scriptRef.uri} with id ' - '$breakpointId', - ); - } - return lineNumber + 1; - } -} - -typedef Edit = ({String file, String originalString, String newString}); diff --git a/dwds/test/integration/fixtures/debugger_data.dart b/dwds/test/integration/fixtures/debugger_data.dart deleted file mode 100644 index 04768bcf06..0000000000 --- a/dwds/test/integration/fixtures/debugger_data.dart +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -/// Contains hard-coded test data usable for tests. -library; - -import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'; - -// ignore_for_file: prefer_single_quotes - -/// Stack frames as they would be in a Chrome 'Debugger.paused' event. -/// -/// This is taken from a real run, but truncated to two levels of scope and one -/// level of stack. -List frames1 = frames1Json.map(WipCallFrame.new).toList(); - -List> frames1Json = [ - { - "callFrameId": "{\"ordinal\":0,\"injectedScriptId\":2}", - "functionName": "", - "functionLocation": { - "scriptId": "69", - "lineNumber": 88, - "columnNumber": 72, - }, - "location": {"scriptId": "69", "lineNumber": 37, "columnNumber": 0}, - "url": "http://127.0.0.1:8081/foo.ddc.js", - "scopeChain": [ - { - "type": "local", - "object": { - "type": "object", - "className": "Object", - "description": "Object", - "objectId": "{\"injectedScriptId\":2,\"id\":3}", - }, - "startLocation": { - "scriptId": "69", - "lineNumber": 88, - "columnNumber": 72, - }, - "endLocation": {"scriptId": "69", "lineNumber": 93, "columnNumber": 7}, - }, - { - "type": "closure", - "object": { - "type": "object", - "className": "Object", - "description": "Object", - "objectId": "{\"injectedScriptId\":2,\"id\":4}", - }, - "name": "main", - "startLocation": { - "scriptId": "69", - "lineNumber": 74, - "columnNumber": 48, - }, - "endLocation": {"scriptId": "69", "lineNumber": 100, "columnNumber": 5}, - }, - { - "type": "closure", - "name": "load__some_module", - "object": { - "type": "object", - "className": "Object", - "description": "Object", - "objectId": "{\"injectedScriptId\":2,\"id\":5}", - }, - "startLocation": { - "scriptId": "69", - "lineNumber": 0, - "columnNumber": 29, - }, - "endLocation": {"scriptId": "69", "lineNumber": 126, "columnNumber": 1}, - }, - { - "type": "global", - "object": { - "type": "object", - "className": "Window", - "description": "Window", - "objectId": "{\"injectedScriptId\":2,\"id\":6}", - }, - }, - ], - "this": {"type": "undefined"}, - }, -]; - -/// Data in the form returned from getProperties called twice on successive -/// elements of a scope chain. -/// -/// It has two variables named 'a' and 'b' in the first scope. -List variables1 = [ - WipResponse({ - 'id': 1, - 'result': {'result': >[]}, - }), - WipResponse({ - 'id': 2, - 'result': { - 'result': [ - { - 'name': 'a', - 'value': {'type': 'string', 'value': 'foo'}, - }, - { - 'name': 'b', - 'value': {'type': 'string', 'value': 'bar'}, - }, - ], - }, - }), - WipResponse({ - 'id': 3, - 'result': {'result': >[]}, - }), - // Fake that the SDK is loaded. - WipResponse({ - 'id': 4, - 'result': { - 'result': [ - {'name': 'dart', 'value': null}, - {'name': 'core', 'value': null}, - ], - }, - }), - WipResponse({ - 'id': 5, - 'result': {'result': >[]}, - }), - WipResponse({ - 'id': 6, - 'result': {'result': >[]}, - }), -]; - -/// Sample data for a Debugger.scriptParsed event -Map scriptParsedParams = { - "endColumn": 0, - "endLine": 53, - "executionContextAuxData": { - "frameId": "75DC0B9DAB420DD67036D4560E614998", - "isDefault": true, - "type": "default", - }, - "executionContextId": 7, - "hasSourceURL": false, - "hash": "1b7029ad6e8a77da7fe7c0741479c0394f01b0f9", - "isLiveEdit": false, - "isModule": false, - "length": 2732, - "scriptId": "146", - "sourceMapURL": "main.ddc.js.map", - "startColumn": 0, - "startLine": 0, - "url": "http://localhost:8080/main.ddc.js", -}; diff --git a/dwds/test/integration/fixtures/fakes.dart b/dwds/test/integration/fixtures/fakes.dart deleted file mode 100644 index 0b90d0e163..0000000000 --- a/dwds/test/integration/fixtures/fakes.dart +++ /dev/null @@ -1,485 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:async'; - -import 'package:dwds/asset_reader.dart'; -import 'package:dwds/src/debugging/chrome_inspector.dart'; -import 'package:dwds/src/debugging/dart_runtime_debugger.dart'; -import 'package:dwds/src/debugging/execution_context.dart'; -import 'package:dwds/src/debugging/inspector.dart'; -import 'package:dwds/src/debugging/instance.dart'; -import 'package:dwds/src/debugging/metadata/provider.dart'; -import 'package:dwds/src/debugging/modules.dart'; -import 'package:dwds/src/debugging/remote_debugger.dart'; -import 'package:dwds/src/debugging/webkit_debugger.dart'; -import 'package:dwds/src/handlers/socket_connections.dart'; -import 'package:dwds/src/loaders/require.dart'; -import 'package:dwds/src/loaders/strategy.dart'; -import 'package:dwds/src/services/expression_compiler.dart'; -import 'package:dwds/src/utilities/objects.dart'; -import 'package:shelf/shelf.dart' as shelf; -import 'package:vm_service/vm_service.dart'; - -/// A library of fake/stub implementations of our classes and their supporting -/// classes (e.g. WipConnection) for unit testing. -import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'; - -import 'debugger_data.dart'; -import 'utilities.dart'; - -/// Constructs a trivial Isolate we can use when we need to provide one but -/// don't want go through initialization. -Isolate get simpleIsolate => Isolate( - id: '1', - number: '1', - name: 'fake', - libraries: [], - exceptionPauseMode: 'abc', - breakpoints: [], - pauseOnExit: false, - pauseEvent: null, - startTime: 0, - livePorts: 0, - runnable: false, - isSystemIsolate: false, - isolateFlags: [], -); - -class FakeChromeAppInspector extends FakeInspector - implements ChromeAppInspector { - FakeChromeAppInspector(this._remoteDebugger, {required super.fakeIsolate}); - final WebkitDebugger _remoteDebugger; - - @override - Future callFunction( - String function, - Iterable argumentIds, - ) async { - functionsCalled.add(function); - return RemoteObject({'type': 'string', 'value': 'true'}); - } - - @override - Future instanceRefFor(Object value) async => - ChromeAppInstanceHelper.kNullInstanceRef; - - @override - Future getObject(String objectId, {int? offset, int? count}) async => - Obj.parse({})!; - - @override - Future> getProperties( - String objectId, { - int? offset, - int? count, - int? length, - }) async { - final response = await _remoteDebugger.sendCommand( - 'Runtime.getProperties', - params: {'objectId': objectId, 'ownProperties': true}, - ); - final result = response.result?['result'] as List? ?? []; - return result - .map((Object? each) => Property(each as Map)) - .toList(); - } - - @override - bool isDisplayableObject(Object? object) => true; - - @override - bool isNativeJsError(InstanceRef instanceRef) => false; -} - -class FakeInspector implements AppInspector { - final List functionsCalled = []; - FakeInspector({required this.fakeIsolate}); - - Isolate fakeIsolate; - - @override - Object noSuchMethod(Invocation invocation) { - throw UnsupportedError('This is a fake'); - } - - @override - Future initialize({ModifiedModuleReport? modifiedModuleReport}) async {} - - @override - Future getScripts() async => ScriptList(scripts: []); - - @override - Future scriptRefFor(String uri) async => - ScriptRef(id: 'fake', uri: 'fake://uri'); - - @override - ScriptRef? scriptWithId(String? scriptId) => null; - - @override - Isolate get isolate => fakeIsolate; - - @override - IsolateRef get isolateRef => IsolateRef( - id: fakeIsolate.id, - number: fakeIsolate.number, - name: fakeIsolate.name, - isSystemIsolate: fakeIsolate.isSystemIsolate, - ); -} - -class FakeSseConnection implements SseSocketConnection { - /// A [StreamController] for incoming messages on SSE connection. - final controllerIncoming = StreamController(); - - /// A [StreamController] for outgoing messages on SSE connection. - final controllerOutgoing = StreamController(); - - @override - bool get isInKeepAlivePeriod => false; - - @override - StreamSink get sink => controllerOutgoing.sink; - - @override - Stream get stream => controllerIncoming.stream; - - @override - void shutdown() {} -} - -class FakeModules implements Modules { - final String _library; - final String _module; - final String _path; - - FakeModules({ - this._library = 'main.dart', - this._module = 'main', - this._path = 'web/main.dart', - }); - - @override - Future initialize( - String entrypoint, { - ModifiedModuleReport? modifiedModuleReport, - }) async {} - - @override - Future libraryForSource(String serverPath) async => Uri(path: _library); - - @override - Future libraryOrPartForSource(String serverPath) async => - Uri(path: _library); - - @override - Future moduleForSource(String serverPath) async => _module; - - @override - Future> sourcesForModule(String module) async => {_path}; - - @override - Future> modules() async => {_path: _module}; - - @override - Future moduleForLibrary(String libraryUri) async => _module; - - @override - Future getRuntimeScriptIdForModule( - String entrypoint, - String module, - ) async => null; -} - -class FakeWebkitDebugger implements WebkitDebugger { - final Map? _scripts; - @override - Future disable() async => null; - - @override - Future enable() async => null; - - FakeWebkitDebugger({this._scripts}) { - final buildSettings = TestBuildSettings.dart( - appEntrypoint: Uri.parse('package:fakeapp/main.dart'), - ); - setGlobalsForTesting( - toolConfiguration: TestToolConfiguration.withLoadStrategy( - loadStrategy: RequireStrategy( - ReloadConfiguration.none, - (_) async => {}, - (_) async => {}, - (_, _) async => null, - (MetadataProvider _, String _) async => '', - (MetadataProvider _, String _) async => '', - (String _) => '', - (MetadataProvider _) async => {}, - FakeAssetReader(), - buildSettings, - ), - ), - ); - } - - @override - Stream eventStream(String method, WipEventTransformer transformer) => - Stream.empty(); - - @override - Future getScriptSource(String scriptId) async => ''; - - Stream? get onClosed => null; - - @override - Stream get onGlobalObjectCleared => - const Stream.empty(); - - @override - late Stream onPaused; - - @override - Stream get onResumed => const Stream.empty(); - - @override - Stream get onScriptParsed => const Stream.empty(); - - @override - Stream get onTargetCrashed => const Stream.empty(); - - @override - Future pause() async => fakeWipResponse; - - @override - Future resume() async => fakeWipResponse; - - @override - Map get scripts => _scripts!; - - List results = variables1; - int resultsReturned = 0; - - @override - Future sendCommand( - String command, { - Map? params, - }) async { - // Force the results that we expect for looking up the variables. - if (command == 'Runtime.getProperties') { - return results[resultsReturned++]; - } - return fakeWipResponse; - } - - @override - Future setPauseOnExceptions(PauseState state) async => - fakeWipResponse; - - @override - Future removeBreakpoint(String breakpointId) async => - fakeWipResponse; - - @override - Future stepInto({Map? params}) async => - fakeWipResponse; - - @override - Future stepOut() async => fakeWipResponse; - - @override - Future stepOver({Map? params}) async => - fakeWipResponse; - - @override - Stream get onConsoleAPICalled => const Stream.empty(); - - @override - Stream get onExceptionThrown => const Stream.empty(); - - @override - Future close() async {} - - @override - Stream get onClose => const Stream.empty(); - - @override - Future evaluate( - String expression, { - bool? returnByValue, - int? contextId, - }) async => RemoteObject({}); - - @override - Future evaluateOnCallFrame( - String callFrameId, - String expression, - ) async { - return RemoteObject({}); - } - - @override - Future> getPossibleBreakpoints( - WipLocation start, - ) async => []; - - @override - Future enablePage() async => fakeWipResponse; - - @override - Future pageReload() async => fakeWipResponse; - - @override - Future Function()? onReconnect; -} - -/// Fake execution context that is needed for id only -class FakeExecutionContext extends ExecutionContext { - @override - Future get id async { - return 0; - } - - FakeExecutionContext(); -} - -class FakeStrategy extends LoadStrategy { - final BuildSettings _buildSettings; - - FakeStrategy( - super.assetReader, { - super.packageConfigPath, - BuildSettings? buildSettings, - }) : _buildSettings = - buildSettings ?? - TestBuildSettings.dart( - appEntrypoint: Uri.parse('package:myapp/main.dart'), - ); - - @override - Future bootstrapFor(String entrypoint) async => 'dummy_bootstrap'; - - @override - shelf.Handler get handler => - (request) => (request.url.path == 'someDummyPath') - ? shelf.Response.ok('some dummy response') - : shelf.Response.notFound('someDummyPath'); - - @override - BuildSettings get buildSettings => _buildSettings; - - @override - String get id => 'dummy-id'; - - @override - String get moduleFormat => 'dummy-format'; - - @override - String get loadLibrariesModule => ''; - - @override - String get loadModuleSnippet => ''; - - @override - late final DartRuntimeDebugger dartRuntimeDebugger = DartRuntimeDebugger( - loadStrategy: this, - useLibraryBundleExpression: false, - ); - - @override - ReloadConfiguration get reloadConfiguration => ReloadConfiguration.none; - - @override - String? g3RelativePath(String absolutePath) => null; - - @override - String loadClientSnippet(String clientScript) => 'dummy-load-client-snippet'; - - @override - Future moduleForServerPath( - String entrypoint, - String serverPath, - ) async => ''; - - @override - Future serverPathForModule(String entrypoint, String module) async => - ''; - - @override - Future sourceMapPathForModule( - String entrypoint, - String module, - ) async => ''; - - @override - String? serverPathForAppUri(String appUri) => ''; - - @override - MetadataProvider metadataProviderFor(String entrypoint) => - createProvider(entrypoint, FakeAssetReader()); - - @override - Future> moduleInfoForEntrypoint(String entrypoint) => - throw UnimplementedError(); -} - -class FakeAssetReader implements AssetReader { - String? metadata; - final String? _dartSource; - final String? _sourceMap; - FakeAssetReader({this.metadata, this._dartSource, this._sourceMap}); - - @override - String get basePath => ''; - - @override - Future dartSourceContents(String serverPath) { - return _throwUnimplementedOrReturnContents(_dartSource); - } - - @override - Future metadataContents(String serverPath) { - return _throwUnimplementedOrReturnContents(metadata); - } - - @override - Future sourceMapContents(String serverPath) { - return _throwUnimplementedOrReturnContents(_sourceMap); - } - - @override - Future close() async {} - - Future _throwUnimplementedOrReturnContents(String? contents) async { - if (contents == null) throw UnimplementedError(); - return contents; - } -} - -class FakeExpressionCompiler implements ExpressionCompiler { - @override - Future compileExpressionToJs( - String isolateId, - String libraryUri, - String scriptUri, - int line, - int column, - Map jsModules, - Map jsFrameValues, - String moduleName, - String expression, - ) async => ExpressionCompilationResult(expression, false); - - @override - Future updateDependencies(Map modules) async => - true; - - @override - Future initialize(CompilerOptions options) async {} -} - -final fakeWipResponse = WipResponse({ - 'id': 1, - 'result': {'fake': ''}, -}); - -final fakeFailingWipResponse = WipResponse({'result': 'Error: Bad request'}); diff --git a/dwds/test/integration/fixtures/main.dart.dill.json b/dwds/test/integration/fixtures/main.dart.dill.json deleted file mode 100644 index 751bc10b82..0000000000 --- a/dwds/test/integration/fixtures/main.dart.dill.json +++ /dev/null @@ -1 +0,0 @@ -{"/web/main.dart.lib.js":{"code":[0,2929],"sourcemap":[0,373]},"/packages/webdev_example_app/message.dart.lib.js":{"code":[2929,3844],"sourcemap":[373,568]},"/packages/path/src/path_set.dart.lib.js":{"code":[3844,97029],"sourcemap":[568,24042]},"/packages/path/src/path_exception.dart.lib.js":{"code":[97029,98717],"sourcemap":[24042,24277]},"/packages/path/src/characters.dart.lib.js":{"code":[98717,100285],"sourcemap":[24277,24602]},"/packages/path/src/utils.dart.lib.js":{"code":[100285,102035],"sourcemap":[24602,25191]}} \ No newline at end of file diff --git a/dwds/test/integration/fixtures/main.dart.dill.map b/dwds/test/integration/fixtures/main.dart.dill.map deleted file mode 100644 index 58a3895f1b..0000000000 --- a/dwds/test/integration/fixtures/main.dart.dill.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sourceRoot":"","sources":["main.dart"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAYwB,IAAtB,WAAM;AAKJ,IAHF,4BAAkB,aAAa,SAAC,GAAG;AACb,MAApB,WAAM;AACN,YAAgC,+CAAO,AAAK,oBAAO,uCAAC,WAAW;IAChE;AACkD,IAAnD,AAAS,AAAK,kCAAO,wBAAe,YAAO;AAEvC,gBAAQ;AAGV,IAFI,kCAAqC,QAAC;AACX,MAA/B,WAAM,AAAwB,0BAAP,QAAF,AAAE,KAAK,GAAP;;EAEzB","file":"main.dart.lib.js"}{"version":3,"sourceRoot":"","sources":["message.dart"],"names":[],"mappings":";;;;;;;;;MAEM,eAAO;YAAG,WAAO,SAAS","file":"../../../../../../../../packages/webdev_example_app/message.dart.lib.js"}{"version":3,"sourceRoot":"","sources":["path_set.dart","path_map.dart","style.dart","internal_style.dart","style/windows.dart","style/url.dart","parsed_path.dart","style/posix.dart","context.dart","../path.dart"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mBA6BuC;AACd,MAArB,AAAQ,OAAD,IAAC,OAAR,UAAc,gBAAN;AACR,YAAO,sCACK,SAAC,OAAO;AACd,cAAI,AAAM,KAAD,IAAI,MAAM,MAAO,AAAM,MAAD,IAAI;AACnC,cAAI,AAAM,KAAD,IAAI,MAAM,MAAO;AAC1B,gBAAO,AAAQ,QAAD,QAAQ,KAAK,EAAE,KAAK;+CAE1B,QAAC,QAAS,AAAK,IAAD,IAAI,OAAO,IAAI,AAAQ,OAAD,MAAM,IAAI,+BAC5C,QAAC,QAAc,AAAU,OAAf,IAAI,gBAAc,AAAK,IAAD,IAAI;IACtD;;AAMiC,YAAA,AAAO;IAAQ;;AAE9B,YAAA,AAAO;IAAM;;yBAEf;AAAU,YAAA,AAAO,kBAAI,KAAK;IAAC;;gCAEd;AAAa,YAAA,AAAO,qBAAO,QAAQ;IAAC;;AAE7C,YAAA,AAAO;IAAS;;AAEpB,YAAA,AAAO;IAAO;aAET;AAAU,YAAA,AAAO,uBAAS,KAAK;IAAC;gBAEnB;AAAU,YAAA,AAAO,0BAAY,KAAK;IAAC;eAElC;AAAU,YAAA,AAAO,yBAAW,KAAK;IAAC;iBAEhC;AAAU,YAAA,AAAO,2BAAa,KAAK;IAAC;WAEpD;AAAY,YAAA,AAAO,qBAAO,OAAO;IAAC;WAEpC;AAAU,YAAA,AAAO,qBAAO,KAAK;IAAC;cAEjB;AAAa,YAAA,AAAO,wBAAU,QAAQ;IAAC;gBAEjD;AAAyB,YAAA,AAAO,0BAAY,IAAI;IAAC;cAEvC;AAAa,YAAA,AAAO,wBAAU,QAAQ;IAAC;gBAEjD;AAAyB,YAAA,AAAO,0BAAY,IAAI;IAAC;;2BAEzC;AAAU,YAAA,AAAO,oBAAM,KAAK;IAAC;;AAEpC,YAAA,AAAO;IAAO;;;QA9DlB;IAAmB,eAAE,yBAAQ,OAAO;AAAvD;;EAAwD;kCAQ5B;;QAAkB;IACjC,qBAAE,yBAAQ,OAAO,GAAG,UAAO,KAAK;AAD7C;;EAC8C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBCAH;AACpB,QAArB,AAAQ,OAAD,IAAC,OAAR,UAAc,gBAAN;AACR,cAAO,wDACK,SAAC,OAAO;AACd,gBAAI,AAAM,KAAD,IAAI,MAAM,MAAO,AAAM,MAAD,IAAI;AACnC,gBAAI,AAAM,KAAD,IAAI,MAAM,MAAO;AAC1B,kBAAO,AAAQ,QAAD,QAAQ,KAAK,EAAE,KAAK;iDAE1B,QAAC,QAAS,AAAK,IAAD,IAAI,OAAO,IAAI,AAAQ,OAAD,MAAM,IAAI,+BAC5C,QAAC,QAAc,AAAU,OAAf,IAAI,gBAAc,AAAK,IAAD,IAAI;MACtD;;;UAtBmB;AAAY,uCAAM,4BAAQ,OAAO;;IAAE;2BAQ5B;;UAAkB;AACtC,6CAAM,4BAAQ,OAAO,GAAG,YAAO,KAAK;;IAAE;;;;;;;;;;;ACmB1C,UAAQ,AAAK,yBAAU,QAAQ,MAAa;AAC5C,WAAS,AAAK,AAAK,8BAAS,MAAM,MAAa;AAC/C,UAAI,AAAiB,AAAa,qBAApB,yBAAuB,QAAQ,MAAa;AAC1D,YAAa;IACf;;AAMuB,yCAAe;IAAK;;AAgCtB;IAAI;;;;EAC3B;;;;;;;;;MAxEqB,kBAAK;YAAG;;MAOR,oBAAO;YAAG;;MAQV,gBAAG;YAAG;;MAMN,qBAAQ;YAAG;;;;YCSR;AAChB,mBAAS,gBAAW,IAAI;AAC5B,UAAW,aAAP,MAAM,IAAG,GAAG,MAAO,AAAK,KAAD,aAAW,GAAG,MAAM;AAC/C,uBAAO,oBAAe,IAAI,KAAI,AAAI,IAAA,QAAC,KAAK;IAC1C;sBAW6B;AACvB,qBAAW,AAAQ,mBAAM,IAAI;AAIjC,oBAAI,iBAAY,AAAK,IAAD,cAAY,AAAK,AAAO,IAAR,UAAU,MAAK,AAAS,AAAO,QAAR,OAAK;AAChE,YAAO,8BAAkB,QAAQ;IACnC;mBAOwB,WAAe;AAAc,YAAA,AAAU,UAAD,IAAI,SAAS;;eAMpD,OAAc;AAAU,YAAA,AAAM,MAAD,IAAI,KAAK;;yBAEhC;AAAa,qBAAQ;;qBAEnB;AAAS,iBAAI;;;;;EAC9C;;;;;;;;;;;;;;;;;;;;IClEQ;;;;;;IACA;;;;;;IACA;;;;;;IAIA;;;;;;IACA;;;;;;IACA;;;;;;IACA;;;;;;sBAEwB;AAAS,YAAA,AAAK,KAAD,YAAU;IAAI;gBAEpC;AACjB,YAAA,AAAS,AAAe,SAAhB,WAAmB,AAAS,QAAD;IAAmB;mBAE/B;AACzB,UAAI,AAAK,IAAD,YAAU,MAAO;AACzB,YAAO,YAAC,iBAAY,AAAK,IAAD,cAAY,AAAK,AAAO,IAAR,UAAU;IACpD;eAEsB;UAAY;AAChC,UAAI,AAAK,IAAD,YAAU,MAAO;AACzB,UAAI,AAAK,AAAc,IAAf,cAAY,WAAmB,MAAO;AAC9C,UAAI,AAAK,AAAc,IAAf,cAAY;AAClB,YAAI,AAAK,AAAO,IAAR,UAAU,KAAK,AAAK,IAAD,cAAY,WAAuB,MAAO;AAGjE,oBAAQ,AAAK,IAAD,WAAS,MAAM;AAC/B,YAAI,AAAM,KAAD,GAAG;AAC2B,UAArC,QAAQ,AAAK,IAAD,WAAS,MAAM,AAAM,KAAD,GAAG;AACnC,cAAI,AAAM,KAAD,GAAG,GAAG,MAAO,MAAK;;AAE7B,cAAO,AAAK,KAAD;;AAIb,UAAI,AAAK,AAAO,IAAR,UAAU,GAAG,MAAO;AAE5B,qBAAK,mBAAa,AAAK,IAAD,cAAY,MAAK,MAAO;AAE9C,UAAI,AAAK,IAAD,cAAY,WAAmB,MAAO;AAE9C,qBAAK,iBAAY,AAAK,IAAD,cAAY,MAAK,MAAO;AAC7C,YAAO;IACT;mBAE2B;AAAS,YAAA,AAAiB,iBAAN,IAAI,MAAK;IAAC;oBAE3B;AACxB,mBAAS,gBAAW,IAAI;AAC5B,UAAI,AAAO,MAAD,KAAI,GAAG,MAAO,AAAI,KAAA,QAAC;AAC7B,YAAO;IACT;gBAEuB;AACrB,UAAI,AAAI,GAAD,YAAW,MAAM,AAAI,GAAD,YAAW;AACqB,QAAzD,WAAM,2BAAc,AAAoC,kBAA9B,GAAG;;AAG3B,iBAAO,AAAI,GAAD;AACd,UAAI,AAAI,AAAK,GAAN,UAAS;AAId,YAAI,AAAK,AAAO,IAAR,WAAW,KAAK,AAAK,IAAD,cAAY,kBAAQ,oBAAc,IAAI,EAAE;AACjC,UAAjC,OAAO,AAAK,IAAD,gBAAc,KAAK;;;AAIH,QAA7B,OAAO,AAAsB,kBAAf,AAAI,GAAD,kBAAO,IAAI;;AAE9B,YAAW,0BAAgB,AAAK,IAAD,cAAY,KAAK;IAClD;sBAE6B;AACvB,mBAAoB,6BAAM,IAAI,EAAE;AACpC,UAAI,AAAO,AAAK,MAAN,mBAAiB;AAKrB,wBAAY,AAAO,AAAK,AAAY,MAAlB,cAAY,cAAY,QAAC,QAAS,AAAK,IAAD,KAAI;AAC1B,QAAtC,AAAO,AAAM,MAAP,gBAAc,GAAG,AAAU,SAAD;AAEhC,sBAAI,AAAO,MAAD;AAGY,UAApB,AAAO,AAAM,MAAP,aAAW;;AAGnB,cAAO,wBACK,cAAc,AAAU,SAAD,wBAAsB,AAAO,MAAD;;AAQ/D,sBAAI,AAAO,AAAM,MAAP,+BAAkB,AAAO,MAAD;AACZ,UAApB,AAAO,AAAM,MAAP,aAAW;;AAMiD,QADpE,AAAO,AACF,MADC,gBACM,GAAG,AAAO,AAAK,AAAoB,MAA1B,mBAAiB,KAAK,iBAAe,MAAM;AAEhE,cAAO,wBAAY,sBAAsB,AAAO,MAAD;;IAEnD;mBAEwB,WAAe;AACrC,UAAI,AAAU,SAAD,IAAI,SAAS,EAAE,MAAO;AAGnC,UAAI,AAAU,SAAD,SAAiB,MAAO,AAAU,UAAD;AAC9C,UAAI,AAAU,SAAD,SAAqB,MAAO,AAAU,UAAD;AAIlD,UAAc,cAAV,SAAS,iBAAG,SAAS,iBAAmB,MAAO;AAG/C,uBAAuB,cAAV,SAAS;AAC1B,YAAO,AAAW,AAAgB,WAAjB,UAAoB,AAAW,UAAD;IACjD;eAEuB,OAAc;AACnC,UAAI,AAAU,KAAK,IAAE,KAAK,EAAG,MAAO;AACpC,UAAI,AAAM,KAAD,YAAW,AAAM,KAAD,SAAS,MAAO;AACzC,eAAS,IAAI,GAAG,AAAE,CAAD,GAAG,AAAM,KAAD,SAAS,IAAA,AAAC,CAAA;AACjC,uBAAK,oBAAe,AAAM,KAAD,cAAY,CAAC,GAAG,AAAM,KAAD,cAAY,CAAC;AACzD,gBAAO;;;AAGX,YAAO;IACT;yBAE6B;AAC3B,UAAI,AAAS,QAAD,SAAiB;AAC7B,UAAa,aAAT,QAAQ,QAAiB,MAAO,SAAQ;AAC5C,UAAa,aAAT,QAAQ,QAAiB,MAAO,SAAQ;AAC5C,YAAgB,eAAT,QAAQ;IACjB;qBAE+B;AAAS,YAAA,AAAK,KAAD;IAAc;;;IAnJpD,aAAO;IACP,kBAAY;IACZ;IAIA,yBAAmB,gBAAO;IAC1B,8BAAwB,gBAAO;IAC/B,oBAAc,gBAAO;IACrB,4BAAsB,gBAAO;;EAXrB;;;;;;;;;;;;;;;;;;;;;;;;;MAJV,qBAAa;;;;;;;;;;;;;ICCX;;;;;;IACA;;;;;;IACA;;;;;;IAIA;;;;;;IACA;;;;;;IACA;;;;;;IACA;;;;;;sBAEwB;AAAS,YAAA,AAAK,KAAD,YAAU;IAAI;gBAEpC;AAAa,YAAA,AAAS,SAAD;IAAe;mBAE9B;AACzB,UAAI,AAAK,IAAD,YAAU,MAAO;AAGzB,qBAAK,iBAAY,AAAK,IAAD,cAAY,AAAK,AAAO,IAAR,UAAU,MAAK,MAAO;AAI3D,YAAO,AAAK,AAAgB,KAAjB,YAAU,UAAU,AAAiB,gBAAN,IAAI,MAAK,AAAK,IAAD;IACzD;eAEsB;UAAY;AAChC,UAAI,AAAK,IAAD,YAAU,MAAO;AACzB,oBAAI,iBAAY,AAAK,IAAD,cAAY,MAAK,MAAO;AAE5C,eAAS,IAAI,GAAG,AAAE,CAAD,GAAG,AAAK,IAAD,SAAS,IAAA,AAAC,CAAA;AAC5B,uBAAW,AAAK,IAAD,cAAY,CAAC;AAChC,sBAAI,iBAAY,QAAQ,IAAG,MAAO;AAClC,YAAI,AAAS,QAAD;AACV,cAAI,AAAE,CAAD,KAAI,GAAG,MAAO;AAInB,cAAI,AAAK,IAAD,cAAY,MAAM,AAAE,CAAD,GAAG,IAAI,AAAM,IAAN,AAAE,CAAD,GAAI;AACnC,sBAAQ,AAAK,IAAD,WAAS,KAAK,CAAC;AAC/B,cAAI,AAAM,KAAD,IAAI,GAAG,MAAO,AAAK,KAAD;AAI3B,yBAAK,SAAS,KAAI,AAAK,AAAO,IAAR,UAAU,AAAM,KAAD,GAAG,GAAG,MAAO,MAAK;AACvD,eAAK,AAAK,IAAD,cAAY,YAAY,MAAO,MAAK;AAC7C,yBAAK,oBAAc,IAAI,EAAE,AAAM,KAAD,GAAG,KAAI,MAAO,MAAK;AACjD,gBAAO,AAAK,AAAO,KAAR,YAAW,AAAM,KAAD,GAAG,IAAI,AAAM,KAAD,GAAG,IAAI,AAAM,KAAD,GAAG;;;AAI1D,YAAO;IACT;mBAE2B;AACvB,YAAA,AAAK,AAAW,KAAZ,2BAAe,iBAAY,AAAK,IAAD,cAAY;IAAG;oBAExB;AAAS,2CAAe,IAAI,KAAI,MAAM;IAAI;gBAEjD;AAAQ,YAAI,eAAJ,GAAG;IAAW;sBAEhB;AAAS,YAAI,gBAAM,IAAI;IAAC;sBACxB;AAAS,YAAI,gBAAM,IAAI;IAAC;;;IA9D/C,cAAO;IACP,mBAAY;IACZ;IAIA,0BAAmB,gBAAO;IAC1B,+BAAwB,gBAAO;IAC/B,qBAAc,gBAAO;IACrB,6BAAsB,gBAAO;;EAXzB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ICDI;;;;;;IAMP;;;;;;IAKF;;;;;;IAIQ;;;;;;IAOA;;;;;;;AAIW,YAAA,AAAiB,gCAAC;IAAE;;AAGrB,YAAA,AAAK,cAAG;IAAI;iBAEH,MAAoB;AAE9C,iBAAO,AAAM,KAAD,SAAS,IAAI;AACzB,2BAAiB,AAAM,KAAD,gBAAgB,IAAI;AAC9C,UAAI,IAAI,IAAI,MAAM,AAAkC,OAA3B,AAAK,IAAD,aAAW,AAAK,IAAD;AAGxC,kBAAgB;AAChB,uBAAqB;AAErB,kBAAQ;AAEZ,UAAI,AAAK,IAAD,2BAAe,AAAM,KAAD,aAAa,AAAK,IAAD,cAAY;AAChC,QAAvB,AAAW,UAAD,OAAK,AAAI,IAAA,QAAC;AACX,QAAT,QAAQ;;AAEU,QAAlB,AAAW,UAAD,OAAK;;AAGjB,eAAS,IAAI,KAAK,EAAE,AAAE,CAAD,GAAG,AAAK,IAAD,SAAS,IAAA,AAAC,CAAA;AACpC,sBAAI,AAAM,KAAD,aAAa,AAAK,IAAD,cAAY,CAAC;AACF,UAAnC,AAAM,KAAD,OAAK,AAAK,IAAD,aAAW,KAAK,EAAE,CAAC;AACV,UAAvB,AAAW,UAAD,OAAK,AAAI,IAAA,QAAC,CAAC;AACR,UAAb,QAAQ,AAAE,CAAD,GAAG;;;AAKhB,UAAI,AAAM,KAAD,GAAG,AAAK,IAAD;AACkB,QAAhC,AAAM,KAAD,OAAK,AAAK,IAAD,aAAW,KAAK;AACZ,QAAlB,AAAW,UAAD,OAAK;;AAGjB,YAAkB,+BAAE,KAAK,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,UAAU;IACpE;;AAMM,iBAAO,AAAK;AACe,MAA/B,AAAK,IAAD;AACJ,oBAAI,AAAK,AAAM,IAAP,mBAAgB,MAAO,AAAK,cAAG,OAAO,KAAK;AACnD,YAAO,AAAK,AAAM,KAAP;IACb;;AAEuC,YAAA,AAAiB,gCAAC;IAAE;;AAGvD,YAAiB,WAAjB,AAAM,6BAAe,AAAM,AAAK,sBAAG,MAAM,AAAW,2BAAQ;IAAG;;AAGjE,uBAAO,AAAM,4BAAc,AAAM,AAAK,sBAAG;AACrB,QAAlB,AAAM;AACiB,QAAvB,AAAW;;AAEb,oBAAI,AAAW,+BAAY,AAAU,AAA4B,uBAAT,aAAlB,AAAW,4BAAS,GAAK;IACjE;;UAEqB;AAEf,2BAAiB;AACjB,qBAAmB;AACvB,eAAS,OAAQ;AACf,YAAI,AAAK,IAAD,KAAI,OAAO,AAAK,IAAD,KAAI;cAEpB,KAAI,AAAK,IAAD,KAAI;AAEjB,wBAAI,AAAS,QAAD;AACW,YAArB,AAAS,QAAD;;AAGQ,YAAhB,iBAAA,AAAc,cAAA;;;AAGgD,UAAhE,AAAS,QAAD,iBAAK,YAAY,IAAG,AAAM,4BAAiB,IAAI,IAAI,IAAI;;;AAKnE,qBAAK;AACqD,QAAxD,AAAS,QAAD,aAAW,GAAQ,sBAAO,cAAc,EAAE;;AAIpD,oBAAI,AAAS,QAAD,0BAAa;AACN,QAAjB,AAAS,QAAD,OAAK;;AAIX,0BAAc,wBACd,AAAS,QAAD,WAAS,QAAC,KAAM,AAAM,iDACpB;AAKD,MAJb,AAAc,aAAD,UACT,GACkC,UAAlC,8BAAc,AAAS,QAAD,4BAAe,AAAM,0BAAe,cACpD,AAAM,uBACN;AAEM,MAAhB,aAAQ,QAAQ;AACU,MAA1B,kBAAa,aAAa;AAG1B,UAAI,aAAQ,QAAc,YAAN,YAAe;AACjC,sBAAI,YAAY,GAAE,AAAyB,YAAlB,AAAK;AACG,QAAjC,YAAO,AAAK,uBAAW,KAAK;;AAEJ,MAA1B;IACF;;AAGM,oBAAU;AACd,UAAI,aAAQ,MAAM,AAAQ,AAAW,OAAZ,OAAO;AAChC,eAAS,IAAI,GAAG,AAAE,CAAD,gBAAG,AAAM,sBAAQ,IAAA,AAAC,CAAA;AACL,QAA5B,AAAQ,OAAD,OAAO,AAAU,uBAAC,CAAC;AACH,QAAvB,AAAQ,OAAD,OAAO,AAAK,kBAAC,CAAC;;AAEO,MAA9B,AAAQ,OAAD,OAAO,AAAW;AAEzB,YAAO,AAAQ,QAAD;IAChB;;AAQM,iBAAO,AAAM,uBAAU,QAAC,KAAM,AAAE,CAAD,KAAI,8BAAY,cAAM;AAEzD,UAAI,AAAK,IAAD,IAAI,MAAM,MAAO,uBAAC,IAAI;AAC9B,UAAI,AAAK,IAAD,KAAI,MAAM,MAAO,uBAAC,MAAM;AAE5B,oBAAU,AAAK,IAAD,eAAa;AAI/B,UAAI,AAAQ,OAAD,IAAI,GAAG,MAAO,uBAAC,IAAI,EAAE;AAEhC,YAAO,uBAAC,AAAK,IAAD,aAAW,GAAG,OAAO,GAAG,AAAK,IAAD,aAAW,OAAO;IAC5D;;AAEsB,YAAW,+BAC7B,YAAO,WAAM,qBAAqB,oBAAK,aAAa,oBAAK;IAAY;;wCA1GhE,OAAY,MAAW,gBAAqB,OAAY;IAAxD;IAAY;IAAW;IAAqB;IAAY;;EAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ICjEtE;;;;;;IACA;;;;;;IACA;;;;;;IAIA;;;;;;IACA;;;;;;IACA;;;;;;IACA;;;;;;sBAEwB;AAAS,YAAA,AAAK,KAAD,YAAU;IAAI;gBAEpC;AAAa,YAAA,AAAS,SAAD;IAAe;mBAE9B;AACvB,YAAA,AAAK,AAAW,KAAZ,4BAAgB,iBAAY,AAAK,IAAD,cAAY,AAAK,AAAO,IAAR,UAAU;IAAG;eAE/C;UAAY;AAChC,UAAI,AAAK,IAAD,2BAAe,iBAAY,AAAK,IAAD,cAAY,MAAK,MAAO;AAC/D,YAAO;IACT;mBAE2B;AAAS;IAAK;oBAEX;AAAS;IAAI;gBAEpB;AACrB,UAAI,AAAI,AAAO,GAAR,YAAW,MAAM,AAAI,AAAO,GAAR,YAAW;AACpC,cAAW,0BAAgB,AAAI,GAAD;;AAEyB,MAAzD,WAAM,2BAAc,AAAoC,kBAA9B,GAAG;IAC/B;sBAE6B;AACvB,mBAAoB,6BAAM,IAAI,EAAE;AACpC,oBAAI,AAAO,AAAM,MAAP;AAIqB,QAA7B,AAAO,AAAM,MAAP,gBAAc,sBAAC,IAAI;YACpB,eAAI,AAAO,MAAD;AAGK,QAApB,AAAO,AAAM,MAAP,aAAW;;AAGnB,YAAO,wBAAY,sBAAsB,AAAO,MAAD;IACjD;;;IAhDM,eAAO;IACP,oBAAY;IACZ;IAIA,2BAAmB,gBAAO;IAC1B,gCAAwB,gBAAO;IAC/B,sBAAc,gBAAO;IACrB,8BAAsB;;EAXhB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IC4CQ;;;;;;;UA3BG;UAAc;AACnC,UAAI,AAAQ,OAAD,IAAI;AACb,YAAI,AAAM,KAAD,IAAI;AACQ,UAAnB,UAAY;;AAEC,UAAb,UAAU;;;AAId,UAAI,AAAM,KAAD,IAAI;AACW,QAAtB,QAAc;YACT,MAAU,gCAAN,KAAK;AAEC,QADf,WAAM,2BAAc,iDAChB;;AAGN,YAAe,wBAAQ,gCAAN,KAAK,GAAmB,OAAO;IAClD;;AAiBsB,YAAA,AAAS,oBAAG,OAAO,kBAAa;IAAO;;AAIrC,YAAA,AAAM;IAAS;aAShB,OACX,cACD,cACA,cACA,cACA,cACA;AAEyD,MADlE,yBACI,YAAY,sBAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK;AAIhE,UAAI,AAAM,KAAD,IAAI,kBAAQ,gBAAW,KAAK,iBAAM,oBAAe,KAAK;AAC7D,cAAO,MAAK;;AAGd,YAAO,WAAK,cAAS,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK;IACtE;aAWuB;AAAS,YAAA,AAAa,cAAN,IAAI;IAAU;6BAUd;AACnC,YAAA,AAAa,cAAN,IAAI;IAA0B;YAUnB;AAChB,mBAAS,aAAO,IAAI;AACS,MAAjC,AAAO,MAAD;AACN,oBAAI,AAAO,AAAM,MAAP,mBAAgB,MAAO,AAAO,AAAK,OAAN,SAAS,OAAO,MAAM,AAAO,MAAD;AACnE,UAAI,AAAO,AAAM,AAAO,MAAd,oBAAiB;AACzB,cAAO,AAAO,AAAK,OAAN,SAAS,OAAO,MAAM,AAAO,MAAD;;AAElB,MAAzB,AAAO,AAAM,MAAP;AACwB,MAA9B,AAAO,AAAW,MAAZ;AAC2B,MAAjC,AAAO,MAAD;AACN,YAAc,eAAP,MAAM;IACf;cAewB;AAAS,YAAA,AAAa,cAAN,IAAI;IAAW;eAkB9B;AAAS,YAAA,AAAK,KAAD,aAAW,GAAG,AAAM,sBAAW,IAAI;IAAE;eAcpD;AAAS,YAAuB,cAAvB,AAAM,sBAAW,IAAI,KAAI;IAAC;eAMnC;AAAS,wBAAC,AAAK,gBAAW,IAAI;IAAC;mBAU3B;AAAS,YAAA,AAAM,2BAAe,IAAI;IAAC;SAe3C,OACP,cACD,cACA,cACA,cACA,cACA,cACA;AACL,kBAAgB,sBAClB,KAAK,EACL,KAAK,EACL,KAAK,EACL,KAAK,EACL,KAAK,EACL,KAAK,EACL,KAAK,EACL,KAAK;AAEwB,MAA/B,yBAAiB,QAAQ,KAAK;AAC9B,YAAO,cAAQ,AAAM,KAAD,SAAO,QAAC,QAAS,AAAK,IAAD,IAAI;IAC/C;YAgBgC;AAC1B,mBAAS;AACT,2BAAiB;AACjB,yCAA+B;AAEnC,iBAAiB,AAAM,KAAD,SAAO,QAAC,QAAS,AAAK,IAAD,KAAI;eAAtC;AACP,sBAAI,AAAK,oBAAe,IAAI,MAAK,4BAA4B;AAGvD,uBAAS,aAAO,IAAI;AACpB,qBAAO,AAAO,MAAD;AAE6C,UAD9D,AAAO,MAAD,QACF,AAAK,IAAD,aAAW,GAAG,AAAM,sBAAW,IAAI,cAAa;AACxD,wBAAI,AAAM,0BAAe,AAAO,MAAD;AACS,YAAtC,AAAO,AAAU,MAAX,mBAAY,GAAK,AAAM;;AAEjB,UAAd,AAAO,MAAD;AACyB,UAA/B,AAAO,MAAD,OAAc,cAAP,MAAM;cACd,eAAI,AAAK,gBAAW,IAAI;AAC4B,UAAzD,+BAA+B,WAAC,AAAK,oBAAe,IAAI;AAE1C,UAAd,AAAO,MAAD;AACY,UAAlB,AAAO,MAAD,OAAO,IAAI;;AAEjB,cAAI,AAAK,IAAD,2BAAe,AAAM,6BAAkB,AAAI,IAAA,QAAC;gBAE7C,eAAI,cAAc;AACA,YAAvB,AAAO,MAAD,OAAO;;AAGG,UAAlB,AAAO,MAAD,OAAO,IAAI;;AAKwB,QAA3C,iBAAiB,AAAM,0BAAe,IAAI;;AAG5C,YAAO,AAAO,OAAD;IACf;UAoB0B;AACpB,mBAAS,aAAO,IAAI;AAE6C,MAArE,AAAO,MAAD,SAAS,AAAO,AAAM,AAAiC,MAAxC,eAAa,QAAC,QAAS,AAAK,IAAD;AAChD,UAAI,AAAO,MAAD,SAAS,MAAM,AAAO,AAAM,AAAsB,MAA7B,gBAAc,GAAG,AAAO,MAAD;AACtD,YAAO,AAAO,OAAD;IACf;iBAc2B;AACJ,MAArB,OAAO,cAAS,IAAI;AACpB,uBAAI,YAAe,oCAAY,0BAAoB,IAAI,IAAG,MAAO,KAAI;AAEjE,mBAAS,aAAO,IAAI;AACY,MAApC,AAAO,MAAD,0BAAyB;AAC/B,YAAc,eAAP,MAAM;IACf;cAUwB;AACtB,qBAAK,0BAAoB,IAAI,IAAG,MAAO,KAAI;AAEvC,mBAAS,aAAO,IAAI;AACN,MAAlB,AAAO,MAAD;AACN,YAAc,eAAP,MAAM;IACf;0BAGgC;AAC1B,kBAAQ;AACR,sBAAY,AAAK,IAAD;AAChB;AACA;AAKA,iBAAO,AAAM,sBAAW,IAAI;AAChC,UAAI,IAAI,KAAI;AACE,QAAZ,QAAQ,IAAI;AACU,QAAtB;AAIA,YAAU,YAAN,YAAe;AACjB,mBAAS,IAAI,GAAG,AAAE,CAAD,gBAAG,IAAI,GAAE,IAAA,AAAC,CAAA;AACzB,gBAAI,AAAS,AAAI,SAAJ,QAAC,CAAC,UAAkB,MAAO;;;;AAK9C,eAAS,IAAI,KAAK,EAAI,aAAF,CAAC,iBAAG,AAAU,SAAD,YAAS,IAAC,aAAD,CAAC;AACrC,uBAAW,AAAS,SAAA,QAAC,CAAC;AAC1B,sBAAI,AAAM,uBAAY,QAAQ;AAE5B,cAAU,YAAN,YAAe,yBAAW,AAAS,QAAD,SAAiB,MAAO;AAG9D,cAAI,QAAQ,IAAI,kBAAQ,AAAM,uBAAY,QAAQ,IAAG,MAAO;AAM5D,cAAI,AAAS,QAAD,YACP,AAAiB,gBAAD,IAAI,QACjB,AAAiB,gBAAD,qBAChB,AAAM,uBAAY,gBAAgB;AACxC,kBAAO;;;AAIgB,QAA3B,mBAAmB,QAAQ;AACR,QAAnB,WAAW,QAAQ;;AAIrB,UAAI,AAAS,QAAD,IAAI,MAAM,MAAO;AAG7B,oBAAI,AAAM,uBAAY,QAAQ,IAAG,MAAO;AAGxC,UAAI,AAAS,QAAD,YACP,AAAiB,gBAAD,IAAI,kBACjB,AAAM,uBAAY,gBAAgB,MAClC,AAAiB,gBAAD;AACtB,cAAO;;AAGT,YAAO;IACT;aAkCuB;;UAAc;AAEnC,UAAI,AAAK,IAAD,IAAI,kBAAQ,AAAK,gBAAW,IAAI,IAAG,MAAO,AAAK,gBAAU,IAAI;AAEvB,MAA9C,OAAO,AAAK,IAAD,IAAI,OAAO,eAAU,cAAS,IAAI;AAG7C,oBAAI,AAAK,gBAAW,IAAI,gBAAK,AAAK,gBAAW,IAAI;AAC/C,cAAO,AAAK,gBAAU,IAAI;;AAK5B,oBAAI,AAAK,gBAAW,IAAI,gBAAK,AAAK,oBAAe,IAAI;AACzB,QAA1B,OAAO,AAAK,cAAS,IAAI;;AAK3B,oBAAI,AAAK,gBAAW,IAAI,gBAAK,AAAK,gBAAW,IAAI;AACsB,QAArE,WAAM,qCAAc,AAAgD,yCAApB,IAAI,4BAAS,IAAI;;AAG/D,6BAAa,aAAO,IAAI,GAAG;AAC3B,8BAAa,aAAO,IAAI,GAAG;AAE/B,oBAAI,AAAW,AAAM,UAAP,wBAAqB,AAAW,AAAK,AAAI,UAAV,cAAO,OAAM;AACxD,cAAkB,eAAX,UAAU;;AAOnB,UAAI,AAAW,UAAD,SAAS,AAAW,UAAD,UAC3B,AAAW,AAAK,UAAN,SAAS,QAAQ,AAAW,AAAK,UAAN,SAAS,mBAC3C,AAAM,sBAAW,AAAW,UAAD,OAAO,AAAW,UAAD;AACnD,cAAkB,eAAX,UAAU;;AAInB,uBAAO,AAAW,AAAM,UAAP,kCACb,AAAW,AAAM,UAAP,kCACV,AAAM,sBAAW,AAAW,AAAK,UAAN,cAAO,IAAI,AAAW,AAAK,UAAN,cAAO;AAC7B,QAA5B,AAAW,AAAM,UAAP,kBAAgB;AACO,QAAjC,AAAW,AAAW,UAAZ,uBAAqB;AACH,QAA5B,AAAW,AAAM,UAAP,kBAAgB;AACO,QAAjC,AAAW,AAAW,UAAZ,uBAAqB;;AAMjC,oBAAI,AAAW,AAAM,UAAP,wBAAqB,AAAW,AAAK,AAAI,UAAV,cAAO,OAAM;AACa,QAArE,WAAM,qCAAc,AAAgD,yCAApB,IAAI,4BAAS,IAAI;;AAEM,MAAzE,AAAW,AAAM,UAAP,mBAAiB,GAAQ,sBAAO,AAAW,AAAM,UAAP,iBAAe;AACtC,MAA7B,AAAW,AAAU,UAAX,mBAAY,GAAK;AAE6C,MADxE,AAAW,AACN,UADK,wBACK,GAAQ,sBAAO,AAAW,AAAM,UAAP,iBAAe,AAAM;AAG7D,oBAAI,AAAW,AAAM,UAAP,mBAAgB,MAAO;AAIrC,UAA4B,aAAxB,AAAW,AAAM,UAAP,mBAAgB,KAAK,AAAW,AAAM,AAAK,UAAZ,kBAAe;AAC7B,QAA7B,AAAW,AAAM,UAAP;AAIC,eAHX,AAAW,UAAD;QACN;QACA;QACA,WAAI;;;AAIU,MAApB,AAAW,UAAD,QAAQ;AACmB,MAArC,AAAW,UAAD;AAEV,YAAkB,eAAX,UAAU;IACnB;aAQqB,QAAe;AAChC,YAAiC,aAAjC,wBAAkB,MAAM,EAAE,KAAK,GAAmB;IAAM;WAOzC,OAAc;AAC7B,YAAgC,aAAhC,wBAAkB,KAAK,EAAE,KAAK,GAAmB;IAAK;wBAMnB,QAAe;AAIhD,6BAAmB,gBAAW,MAAM;AACpC,4BAAkB,gBAAW,KAAK;AACtC,oBAAI,gBAAgB,gBAAK,eAAe;AACf,QAAvB,QAAQ,cAAS,KAAK;AACtB,sBAAI,AAAM,0BAAe,MAAM,IAAG,AAAyB,SAAhB,cAAS,MAAM;YACrD,eAAI,eAAe,gBAAK,gBAAgB;AACpB,QAAzB,SAAS,cAAS,MAAM;AACxB,sBAAI,AAAM,0BAAe,KAAK,IAAG,AAAuB,QAAf,cAAS,KAAK;YAClD,eAAI,eAAe,eAAI,gBAAgB;AACxC,kCAAsB,AAAM,0BAAe,KAAK;AAChD,mCAAuB,AAAM,0BAAe,MAAM;AAEtD,sBAAI,mBAAmB,gBAAK,oBAAoB;AACvB,UAAvB,QAAQ,cAAS,KAAK;cACjB,eAAI,oBAAoB,gBAAK,mBAAmB;AAC5B,UAAzB,SAAS,cAAS,MAAM;;;AAIxB,mBAAS,4BAAsB,MAAM,EAAE,KAAK;AAChD,uBAAI,MAAM,EAAkB,qCAAc,MAAO,OAAM;AAEhD;AACP;AAC+C,QAA7C,WAAW,AAAK,cAAS,KAAK,SAAQ,MAAM;;YACpB;AAAxB;AAGA,gBAAqB;;;;AAGvB,qBAAK,AAAK,gBAAW,QAAQ,IAAG,MAAqB;AACrD,UAAI,AAAS,QAAD,KAAI,KAAK,MAAqB;AAC1C,UAAI,AAAS,QAAD,KAAI,MAAM,MAAqB;AAC3C,YAAQ,AAAS,AAAO,AACU,SADlB,WAAW,KACnB,AAAS,QAAD,cAAY,mBACpB,AAAM,uBAAY,AAAS,QAAD,cAAY,OAC1B,kCACA;IACtB;4BAI2C,QAAe;;AAGxD,UAAI,AAAO,MAAD,KAAI,KAAK,AAAW,SAAF;AAExB,6BAAmB,AAAM,sBAAW,MAAM;AAC1C,4BAAkB,AAAM,sBAAW,KAAK;AAQ5C,UAAI,gBAAgB,IAAI,eAAe,EAAE,MAAqB;AAM9D,eAAS,IAAI,GAAG,AAAE,CAAD,gBAAG,gBAAgB,GAAE,IAAA,AAAC,CAAA;AACjC,6BAAiB,AAAO,MAAD,cAAY,CAAC;AACpC,4BAAgB,AAAM,KAAD,cAAY,CAAC;AACtC,uBAAK,AAAM,0BAAe,cAAc,EAAE,aAAa;AACrD,gBAAqB;;;AAOrB;AAGA;AAGA,wBAAc,gBAAgB;AAC9B,uBAAa,eAAe;AAChC,aAAmB,aAAZ,WAAW,IAAG,AAAO,MAAD,WAAsB,aAAX,UAAU,IAAG,AAAM,KAAD;AAClD,6BAAiB,AAAO,MAAD,cAAY,WAAW;AAC9C,4BAAgB,AAAM,KAAD,cAAY,UAAU;AAC/C,sBAAI,AAAM,0BAAe,cAAc,EAAE,aAAa;AACpD,wBAAI,AAAM,uBAAY,cAAc;AACD,YAAjC,sBAAsB,WAAW;;AAGN,UAA7B,eAAe,cAAc;AAChB,UAAb,cAAW,aAAX,WAAW;AACC,UAAZ,aAAU,aAAV,UAAU;AACV;;AAIF,sBAAI,AAAM,uBAAY,cAAc,gBAChC,AAAM,uBAAY,YAAY;AACC,UAAjC,sBAAsB,WAAW;AACpB,UAAb,cAAW,aAAX,WAAW;AACX;cACK,eAAI,AAAM,uBAAY,aAAa,gBACtC,AAAM,uBAAY,YAAY;AACpB,UAAZ,aAAU,aAAV,UAAU;AACV;;AASF,YAAI,AAAe,cAAD,qBAAoB,AAAM,uBAAY,YAAY;AACrD,UAAb,cAAW,aAAX,WAAW;AAIX,cAAI,AAAY,WAAD,KAAI,AAAO,MAAD,SAAS;AACa,UAA/C,iBAAiB,AAAO,MAAD,cAAY,WAAW;AAG9C,wBAAI,AAAM,uBAAY,cAAc;AACD,YAAjC,sBAAsB,WAAW;AACpB,YAAb,cAAW,aAAX,WAAW;AACX;;AAKF,cAAI,AAAe,cAAD;AACH,YAAb,cAAW,aAAX,WAAW;AACX,gBAAI,AAAY,WAAD,KAAI,AAAO,MAAD,qBACrB,AAAM,uBAAY,AAAO,MAAD,cAAY,WAAW;AACjD,oBAAqB;;;;AAU3B,YAAI,AAAc,aAAD,qBAAoB,AAAM,uBAAY,YAAY;AACrD,UAAZ,aAAU,aAAV,UAAU;AACV,cAAI,AAAW,UAAD,KAAI,AAAM,KAAD,SAAS;AACY,UAA5C,gBAAgB,AAAM,KAAD,cAAY,UAAU;AAE3C,wBAAI,AAAM,uBAAY,aAAa;AACrB,YAAZ,aAAU,aAAV,UAAU;AACV;;AAGF,cAAI,AAAc,aAAD;AACH,YAAZ,aAAU,aAAV,UAAU;AACV,gBAAI,AAAW,UAAD,KAAI,AAAM,KAAD,qBACnB,AAAM,uBAAY,AAAM,KAAD,cAAY,UAAU;AAC/C,oBAAqB;;;;AASvB,6BAAiB,qBAAe,KAAK,EAAE,UAAU;AACrD,yBAAI,cAAc,EAAmB;AACnC,gBAAqB;;AAGnB,8BAAkB,qBAAe,MAAM,EAAE,WAAW;AACxD,yBAAI,eAAe,EAAmB;AACpC,gBAAqB;;AAGvB,cAAqB;;AASvB,UAAI,AAAW,UAAD,KAAI,AAAM,KAAD;AACrB,YAAI,AAAY,WAAD,KAAI,AAAO,MAAD,qBACrB,AAAM,uBAAY,AAAO,MAAD,cAAY,WAAW;AAChB,UAAjC,sBAAsB,WAAW;;AAEwB,UAAzD,AAAoB,mBAAD,IAAC,OAApB,sBAAwB,mBAAS,GAAoB,aAAjB,gBAAgB,IAAG,KAAnC;;AAGlB,wBACA,qBAAe,MAAM,GAAsB,KAApB,mBAAmB,QAAnB,OAAwC,aAAjB,gBAAgB,IAAG;AACrE,YAAc,YAAV,SAAS,EAAmB,gCAAQ,MAAqB;AAC7D,cAAiB,aAAV,SAAS,EAAmB,oCACf,qCACA;;AAMlB,sBAAY,qBAAe,KAAK,EAAE,UAAU;AAShD,UAAc,YAAV,SAAS,EAAmB,gCAAQ,MAAqB;AAQ7D,UAAc,YAAV,SAAS,EAAmB;AAC9B,cAAqB;;AASvB,YAAwD,WAAhD,AAAM,uBAAY,AAAM,KAAD,cAAY,UAAU,iBAC7C,AAAM,uBAAY,YAAY,KAClB,+BACA;IACtB;qBAeqC,MAAU;AACzC,kBAAQ;AACR,wBAAc;AACd,cAAI,KAAK;AACb,aAAS,aAAF,CAAC,IAAG,AAAK,IAAD;AAEb,eAAS,aAAF,CAAC,IAAG,AAAK,IAAD,qBAAW,AAAM,uBAAY,AAAK,IAAD,cAAY,CAAC;AACxD,UAAH,IAAC,aAAD,CAAC;;AAIH,YAAI,AAAE,CAAD,KAAI,AAAK,IAAD,SAAS;AAGlB,oBAAQ,CAAC;AACb,eAAS,aAAF,CAAC,IAAG,AAAK,IAAD,sBAAY,AAAM,uBAAY,AAAK,IAAD,cAAY,CAAC;AACzD,UAAH,IAAC,aAAD,CAAC;;AAIH,YAAM,AAAQ,aAAV,CAAC,iBAAG,KAAK,MAAI,KAAK,AAAK,AAAkB,IAAnB,cAAY,KAAK;cAEpC,KAAM,AAAQ,aAAV,CAAC,iBAAG,KAAK,MAAI,KACpB,AAAK,AAAkB,IAAnB,cAAY,KAAK,YACrB,AAAK,AAAsB,IAAvB,cAAkB,aAAN,KAAK,IAAG;AAEnB,UAAP,QAAA,AAAK,KAAA;AAGL,cAAI,AAAM,KAAD,GAAG,GAAG;AAIf,cAAI,AAAM,KAAD,KAAI,GAAG,AAAkB,cAAJ;;AAGvB,UAAP,QAAA,AAAK,KAAA;;AAIP,YAAI,AAAE,CAAD,KAAI,AAAK,IAAD,SAAS;AAGnB,QAAH,IAAC,aAAD,CAAC;;AAGH,UAAI,AAAM,KAAD,GAAG,GAAG,MAAsB;AACrC,UAAI,AAAM,KAAD,KAAI,GAAG,MAAsB;AACtC,UAAI,WAAW,EAAE,MAAsB;AACvC,YAAsB;IACxB;SAMgB;AAGO,MAArB,OAAO,cAAS,IAAI;AAEhB,mBAAS,gBAAU,IAAI;AAC3B,UAAI,MAAM,IAAI,MAAM,MAAO,OAAM;AAE7B,mBAAS,aAAO,IAAI;AACN,MAAlB,AAAO,MAAD;AACN,YAAO,iBAAiB,cAAP,MAAM;IACzB;gBAMqB;AACf,iBAAO;AACP,sBAAY;AACZ,yBAAe;AACnB,eAAS,IAAI,GAAG,AAAE,CAAD,GAAG,AAAK,IAAD,SAAS,IAAA,AAAC,CAAA;AAC5B,uBAAW,AAAM,gCAAqB,AAAK,IAAD,cAAY,CAAC;AAK3D,sBAAI,AAAM,uBAAY,QAAQ;AACT,UAAnB,eAAe;AACf;;AAGF,YAAI,AAAS,QAAD,WAAoB,YAAY;AAQ1C,cAAI,AAAE,AAAI,CAAL,GAAG,MAAK,AAAK,IAAD,SAAS;AAEtB,qBAAO,AAAK,IAAD,cAAY,AAAE,CAAD,GAAG;AAI/B,wBAAI,AAAM,uBAAY,IAAI,IAAG;AAM7B,eAAK,SAAS,IACV,AAAK,IAAD,YACH,AAAE,AAAI,CAAL,GAAG,MAAK,AAAK,IAAD,qBACV,AAAM,uBAAY,AAAK,IAAD,cAAY,AAAE,CAAD,GAAG;AAC5C,kBAAO;;;AAKM,QAAjB,OAAA,AAAK,IAAD,GAAI;AACE,QAAV,OAAA,AAAK,IAAD,GAAI;AACQ,QAAhB,OAAK,CAAL,IAAI,gBAAI,QAAQ;AACI,QAApB,eAAe;AACE,QAAjB,YAAY;;AAEd,YAAO,KAAI;IACb;qBAK+B;AACzB,mBAAS,aAAO,IAAI;AAExB,eAAS,IAAwB,aAApB,AAAO,AAAM,MAAP,mBAAgB,GAAG,AAAE,CAAD,IAAI,GAAG,IAAA,AAAC,CAAA;AAC7C,YAAI,AAAO,AAAK,AAAI,MAAV,cAAO,CAAC;AACiC,UAAjD,AAAO,AAAK,MAAN,cAAO,CAAC,EAAI,AAAO,MAAD;AACxB;;;AAIJ,YAAc,eAAP,MAAM;IACf;iBAa2B,MAAa;AACpC,YAAuB,cAAvB,sBAAiB,IAAI,kBAAI,SAAS;;YAsBvB;AAAQ,YAAA,AAAM,wBAAY,kBAAU,GAAG;IAAE;UAkBvC;AACf,oBAAI,gBAAW,IAAI;AACjB,cAAO,AAAM,8BAAkB,IAAI;;AAEnC,cAAO,AAAM,8BAAkB,UAAK,cAAS,IAAI;;IAErD;cA2BiB;AACX,qBAAW,kBAAU,GAAG;AAC5B,UAAI,AAAS,AAAO,QAAR,YAAW,UAAgB,YAAN,YAAe;AAC9C,cAAgB,eAAT,QAAQ;YACV,KAAI,AAAS,QAAD,YAAW,UAC1B,AAAS,QAAD,YAAW,mBACnB,YAAe;AACjB,cAAgB,eAAT,QAAQ;;AAGb,iBAAO,eAAU,aAAQ,QAAQ;AACjC,gBAAM,cAAS,IAAI;AAKvB,YAAyB,cAAlB,AAAW,WAAL,GAAG,2BAAW,AAAY,WAAN,IAAI,cAAW,IAAI,GAAG,GAAG;IAC5D;aAEyB;AAAS,YAAW,8BAAM,IAAI,EAAE;IAAM;;;IA9+BnD,gBAAiB,gCAAT;IACL,kBAAE;;EAAI;iCAEN,OAAY;IAAZ;IAAY;;EAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAmiCvB;;;;;;;AAIQ;IAAI;;;IAFC;;EAAK;;;;;;;;;MAflB,gCAAS;;;MAIT,6BAAM;;;MAIN,kCAAW;;;MAGX,gCAAS;;;;;;;;;;IA8BT;;;;;;;AAIQ;IAAI;;;IAFA;;EAAK;;;;;;;;;MAlBjB,4BAAM;;;MAKN,2BAAK;;;MAGL,+BAAS;;;MAMT,kCAAY;;;;;AAnmCC,UAAQ;EAAW;yCAuhCjC;AACZ,QAAQ,OAAJ,GAAG,cAAY,MAAW,gBAAM,GAAG;AACvC,QAAQ,YAAJ,GAAG,GAAS,MAAO,IAAG;AAC8C,IAAxE,WAAoB,6BAAM,GAAG,EAAE,OAAO;EACxC;uDAI6B,QAAqB;AAChD,aAAS,IAAI,GAAG,AAAE,CAAD,gBAAG,AAAK,IAAD,YAAS,IAAA,AAAC,CAAA;AAEhC,UAAI,AAAI,AAAI,IAAJ,QAAC,CAAC,KAAK,QAAQ,AAAI,IAAA,QAAC,AAAE,CAAD,GAAG,MAAM,MAAM;AAExC;AACJ,oBAAK,UAAU,AAAK,IAAD,WAAiB,aAAR,OAAO,KAAI,GAAG,UAAO,aAAP,OAAO;AAC/C,YAAI,AAAI,IAAA,QAAS,aAAR,OAAO,IAAG,MAAM,MAAM;;AAI7B,oBAAU;AACW,MAAzB,AAAQ,OAAD,OAAiB,SAAR,MAAM;AAIN,MAHhB,AAAQ,OAAD,OAAO,AACT,AACA,AACA,IAHa,QACR,OAAO,qBACR,QAAC,OAAQ,AAAI,GAAD,IAAI,OAAO,SAAS,AAAQ,gBAAL,GAAG,oCACrC;AACsD,MAAhE,AAAQ,OAAD,OAAO,AAAiD,sBAAtC,AAAE,CAAD,GAAG,KAAE,kCAAqB,CAAC;AACd,MAAvC,WAAM,2BAAc,AAAQ,OAAD;;EAE/B;qCC37BuB,OACP,cACD,cACA,cACA,cACA,cACA;AACX,UAAA,AAAQ,wBAAS,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK;EAAC;qCAU9C;AAAS,UAAA,AAAQ,wBAAS,IAAI;EAAC;qEAUf;AACnC,UAAA,AAAQ,wCAAyB,IAAI;EAAC;mCAqBpB;AAAS,UAAA,AAAQ,uBAAQ,IAAI;EAAC;uCAe5B;AAAS,UAAA,AAAQ,yBAAU,IAAI;EAAC;yCAkB/B;AAAS,UAAA,AAAQ,0BAAW,IAAI;EAAC;yCAcnC;AAAS,UAAA,AAAQ,0BAAW,IAAI;EAAC;yCAMjC;AAAS,UAAA,AAAQ,0BAAW,IAAI;EAAC;iDAU7B;AAAS,UAAA,AAAQ,8BAAe,IAAI;EAAC;6BAe7C,OACH,cACD,cACA,cACA,cACA,cACA,cACA;AACX,UAAA,AAAQ,oBAAK,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK;EAAC;mCAiBxC;AAAU,UAAA,AAAQ,uBAAQ,KAAK;EAAC;+BAuBtC;AAAS,UAAA,AAAQ,qBAAM,IAAI;EAAC;6CAc3B;AAAS,UAAA,AAAQ,4BAAa,IAAI;EAAC;uCAUtC;AAAS,UAAA,AAAQ,yBAAU,IAAI;EAAC;qCA4BjC;QAAc;AACjC,UAAA,AAAQ,wBAAS,IAAI,SAAQ,IAAI;EAAC;qCAOjB,QAAe;AAAU,UAAA,AAAQ,wBAAS,MAAM,EAAE,KAAK;EAAC;iCAO1D,OAAc;AAAU,UAAA,AAAQ,sBAAO,KAAK,EAAE,KAAK;EAAC;6BAOvD;AAAS,UAAA,AAAQ,oBAAK,IAAI;EAAC;qDAKZ;AAAS,UAAA,AAAQ,gCAAiB,IAAI;EAAC;6CAW3C,MAAa;AACpC,UAAA,AAAQ,4BAAa,IAAI,EAAE,SAAS;EAAC;mCAoB1B;AAAQ,UAAA,AAAQ,uBAAQ,GAAG;EAAC;+BAsB1B;AAAS,UAAA,AAAQ,qBAAM,IAAI;EAAC;uCAsB5B;AAAQ,UAAA,AAAQ,yBAAU,GAAG;EAAC;;;AAlY5B,YAAA,AAAQ;IAAK;;AAU1B;AACJ;AACgB,QAAd,MAAU;;;AACV;AACA,cAAI,kBAAY,MAAM,MAAO;AACtB,UAAP;;;;AAKF,UAAQ,YAAJ,GAAG,EAAI,wBAAiB,MAAO;AACd,MAArB,wBAAkB,GAAG;AAErB,UAAmB,YAAT,uBAAkB;AACY,QAAtC,iBAA4B,cAAjB,AAAI,GAAD,SAAS;AACvB,cAAO;;AAEH,mBAAO,AAAI,GAAD;AAGV,wBAAY,AAAK,AAAO,IAAR,UAAU;AAC9B,cAAO,AAAI,AAAY,AAAO,IAAnB,QAAC,SAAS,MAAK,OAAO,AAAI,AAAY,IAAZ,QAAC,SAAS,MAAK;AACW,QAA/D,iBAAW,AAAU,SAAD,KAAI,IAAI,IAAI,GAAG,AAAK,IAAD,aAAW,GAAG,SAAS;AAC9D,cAAO;;IAEX;;AAewB,YAAA,AAAQ;IAAS;;;MAvE3B,WAAK;YAAG,6BAAqB;;MAG7B,aAAO;YAAG,6BAAqB;;MAM/B,SAAG;YAAG,6BAAqB;;MAO3B,aAAO;YAAG;;MA6CpB,qBAAe;;;;MAMZ,cAAQ","file":"../../../../../../../../../../../packages/path/src/path_set.dart.lib.js"}{"version":3,"sourceRoot":"","sources":["path_exception.dart"],"names":[],"mappings":";;;;;;;;;IAOS;;;;;;;AAIc,YAAA,AAAyB,8BAAR;IAAQ;;;IAF3B;;EAAQ","file":"../../../../../../../../../../../packages/path/src/path_exception.dart.lib.js"}{"version":3,"sourceRoot":"","sources":["characters.dart"],"names":[],"mappings":";;;;;;;;MAKM,eAAI;;;MACJ,gBAAK;;;MACL,iBAAM;;;MACN,gBAAK;;;MACL,eAAI;;;MACJ,eAAI;;;MACJ,gBAAK;;;MACL,iBAAM;;;MACN,iBAAM;;;MACN,iBAAM;;;MACN,iBAAM;;;MACN,oBAAS","file":"../../../../../../../../../../../packages/path/src/characters.dart.lib.js"}{"version":3,"sourceRoot":"","sources":["utils.dart"],"names":[],"mappings":";;;;;;;;6CAQsB;AAClB,UAAM,AAAyC,cAA9C,IAAI,WAAyB,aAAL,IAAI,WACvB,aAAL,IAAI,WAAyB,aAAL,IAAI;EAAiB;uCAG/B;AAAS,UAAK,AAAc,cAAnB,IAAI,WAAuB,aAAL,IAAI;EAAc;+CAI1C,MAAU;AAClC,QAAI,AAAK,AAAO,IAAR,UAAgB,aAAN,KAAK,IAAG,GAAG,MAAO;AACpC,mBAAK,mBAAa,AAAK,IAAD,cAAY,KAAK,KAAI,MAAO;AAClD,QAAI,AAAK,IAAD,cAAkB,aAAN,KAAK,IAAG,WAAmB,MAAO;AACtD,QAAI,AAAK,AAAO,IAAR,YAAiB,aAAN,KAAK,IAAG,GAAG,MAAO;AACrC,UAAO,AAAK,AAAsB,KAAvB,cAAkB,aAAN,KAAK,IAAG;EACjC","file":"../../../../../../../../../../../packages/path/src/utils.dart.lib.js"} \ No newline at end of file diff --git a/dwds/test/integration/fixtures/project.dart b/dwds/test/integration/fixtures/project.dart deleted file mode 100644 index 3322800e2a..0000000000 --- a/dwds/test/integration/fixtures/project.dart +++ /dev/null @@ -1,289 +0,0 @@ -// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:io'; - -import 'package:dwds_test_common/utilities.dart'; -import 'package:io/io.dart'; -import 'package:path/path.dart' as p; -import 'package:yaml/yaml.dart'; - -enum IndexBaseMode { noBase, base } - -/// Project definitions from projects defined in webdev/fixtures. -class TestProject { - final String packageName; - final String packageDirectory; - final String webAssetsPath; - final String dartEntryFileName; - final String htmlEntryFileName; - - late Directory _fixturesCopy; - - /// The top level directory in which we run the test server, e.g. - /// "/tmp/_test". - String get absolutePackageDirectory => - p.join(_fixturesCopy.absolute.path, packageDirectory); - - /// The directory to build and serve, e.g. "example". - String get directoryToServe => p.split(webAssetsPath).first; - - /// The path to the HTML file to serve, relative to the [directoryToServe], - /// e.g. "hello_world/index.html". - String get filePathToServe { - final pathParts = p - .split(webAssetsPath) - .where((pathPart) => pathPart != directoryToServe); - return webCompatiblePath([...pathParts, htmlEntryFileName]); - } - - /// The path to the Dart entry file, e.g, - /// "/tmp/_test/example/hello_world/main.dart": - String get dartEntryFilePath => p.joinAll([ - _fixturesCopy.absolute.path, - packageDirectory, - webAssetsPath, - dartEntryFileName, - ]); - - /// The URI for the package_config.json is located in: - /// `/.dart_tool/package_config` - Uri get packageConfigFile => p.toUri( - p.join(absolutePackageDirectory, '.dart_tool', 'package_config.json'), - ); - - /// The package URI of the Dart entry file, e.g, - /// "org-dartlang-app:example/hello_world/main.dart": - Uri get dartEntryFilePackageUri => Uri.parse( - 'org-dartlang-app:///${p.join(webAssetsPath, dartEntryFileName)}', - ); - - TestProject.testPackage({IndexBaseMode baseMode = IndexBaseMode.noBase}) - : this._( - packageName: '_test_package', - packageDirectory: '_test_package', - webAssetsPath: 'web', - dartEntryFileName: 'main.dart', - htmlEntryFileName: baseMode == IndexBaseMode.base - ? 'base_index.html' - : 'index.html', - ); - - static final testCircular1 = TestProject._( - packageName: '_test_circular1', - packageDirectory: '_test_circular1', - webAssetsPath: 'web', - dartEntryFileName: 'main.dart', - htmlEntryFileName: 'index.html', - ); - - TestProject.testCircular2({IndexBaseMode baseMode = IndexBaseMode.noBase}) - : this._( - packageName: '_test_circular2', - packageDirectory: '_test_circular2', - webAssetsPath: 'web', - dartEntryFileName: 'main.dart', - htmlEntryFileName: baseMode == IndexBaseMode.base - ? 'base_index.html' - : 'index.html', - ); - - TestProject.testParts({IndexBaseMode baseMode = IndexBaseMode.noBase}) - : this._( - packageName: '_test_parts', - packageDirectory: '_test_parts', - webAssetsPath: 'web', - dartEntryFileName: 'main.dart', - htmlEntryFileName: baseMode == IndexBaseMode.base - ? 'base_index.html' - : 'index.html', - ); - - static final test = TestProject._( - packageName: '_test', - packageDirectory: '_test', - webAssetsPath: webCompatiblePath(['example', 'hello_world']), - dartEntryFileName: 'main.dart', - htmlEntryFileName: 'index.html', - ); - - static final testScopes = TestProject._( - packageName: '_test', - packageDirectory: '_test', - webAssetsPath: webCompatiblePath(['example', 'scopes']), - dartEntryFileName: 'main.dart', - htmlEntryFileName: 'scopes.html', - ); - - static final testAppendBody = TestProject._( - packageName: '_test', - packageDirectory: '_test', - webAssetsPath: webCompatiblePath(['example', 'append_body']), - dartEntryFileName: 'main.dart', - htmlEntryFileName: 'index.html', - ); - - static final testExperiment = TestProject._( - packageName: '_experiment', - packageDirectory: '_experiment', - webAssetsPath: 'web', - dartEntryFileName: 'main.dart', - htmlEntryFileName: 'index.html', - ); - - static final testDotShorthands = TestProject._( - packageName: '_test_dot_shorthands', - packageDirectory: '_test_dot_shorthands', - webAssetsPath: 'web', - dartEntryFileName: 'main.dart', - htmlEntryFileName: 'index.html', - ); - - static final testHotRestart1 = TestProject._( - packageName: '_test_hot_restart1', - packageDirectory: '_test_hot_restart1', - webAssetsPath: 'web', - dartEntryFileName: 'main.dart', - htmlEntryFileName: 'index.html', - ); - - /// This series of hot restart tests is divided across multiple packages in - /// order to test correctness when only a subset of libraries are updated. - static final testHotRestart2 = TestProject._( - packageName: '_test_hot_restart2', - packageDirectory: '_test_hot_restart2', - webAssetsPath: 'web', - dartEntryFileName: 'main.dart', - htmlEntryFileName: 'index.html', - ); - - static final testHotRestartBreakpoints = TestProject._( - packageName: '_test_hot_restart_breakpoints', - packageDirectory: '_test_hot_restart_breakpoints', - webAssetsPath: 'web', - dartEntryFileName: 'main.dart', - htmlEntryFileName: 'index.html', - ); - - static final testHotReload = TestProject._( - packageName: '_test_hot_reload', - packageDirectory: '_test_hot_reload', - webAssetsPath: 'web', - dartEntryFileName: 'main.dart', - htmlEntryFileName: 'index.html', - ); - - static final testHotReloadBreakpoints = TestProject._( - packageName: '_test_hot_reload_breakpoints', - packageDirectory: '_test_hot_reload_breakpoints', - webAssetsPath: 'web', - dartEntryFileName: 'main.dart', - htmlEntryFileName: 'index.html', - ); - - TestProject._({ - required this.packageName, - required this.packageDirectory, - required this.webAssetsPath, - required this.dartEntryFileName, - required this.htmlEntryFileName, - }); - - static Future _copyPackageAndPathDependenciesIntoTempDirectory( - Directory tempDirectory, - String packageDirectory, - Set copiedPackageDirectories, - ) async { - // There may be cycles in dependencies, so check that we already copied this - // package. - if (copiedPackageDirectories.contains(packageDirectory)) return; - final currentPath = absolutePath(pathFromFixtures: packageDirectory); - final newPath = p.join(tempDirectory.absolute.path, packageDirectory); - Directory(newPath).createSync(); - copyPathSync(currentPath, newPath); - copiedPackageDirectories.add(packageDirectory); - final pubspec = loadYaml( - File(p.join(currentPath, 'pubspec.yaml')).readAsStringSync(), - ) as Map; - final dependencies = pubspec['dependencies'] as Map? ?? {}; - for (final dependency in dependencies.values) { - if (dependency is Map && dependency.containsKey('path')) { - final dependencyDirectory = Directory( - p.normalize(p.join(currentPath, dependency['path'] as String)), - ); - // It may be okay to do some more complicated copying here for path - // dependencies that aren't immediately under `fixtures`, but for now, - // only support those that are. - assert( - dependencyDirectory.parent.path == Directory(currentPath).parent.path, - 'Path dependency of $packageDirectory: ' - '${dependencyDirectory.path} is not an immediate directory in ' - '`fixtures`.', - ); - await _copyPackageAndPathDependenciesIntoTempDirectory( - tempDirectory, - p.basename(dependencyDirectory.path), - copiedPackageDirectories, - ); - } - } - - // Clean up the project. - // Called when we need to rebuild sdk and the app from previous test - // configurations. - await Process.run('dart', [ - 'run', - 'build_runner', - 'clean', - ], workingDirectory: newPath); - } - - Future setUp() async { - // Verify that the web assets path has no starting slash. - assert(!webAssetsPath.startsWith('/')); - // Copy the package into a temporary directory to allow editing of files if - // needed. - final systemTempDir = Directory( - // Resolve symbolic links as build_daemon tests rely on paths matching - // between the client and the daemon. - Directory.systemTemp.resolveSymbolicLinksSync(), - ); - _fixturesCopy = systemTempDir.createTempSync(); - await _copyPackageAndPathDependenciesIntoTempDirectory( - _fixturesCopy, - packageDirectory, - {}, - ); - } - - /// Delete the copy of the project. - Future tearDown() async { - try { - _fixturesCopy.deleteSync(recursive: true); - } on FileSystemException catch (_) { - // On Windows, the build daemon process might still be accessing the - // working directory, so try again with an exponential backoff. - var seconds = 1; - final maxAttempts = 3; - for (var attempt = 0; attempt < maxAttempts; attempt++) { - try { - _fixturesCopy.deleteSync(recursive: true); - break; - } on FileSystemException catch (_) { - await Future.delayed(Duration(seconds: seconds)); - seconds *= 2; - } - } - } - } - - /// The path to the Dart specified file in the 'lib' directory, e.g, - /// "/tmp/_test/lib/library.dart": - String dartLibFilePath(String dartLibFileName) => p.joinAll([ - _fixturesCopy.absolute.path, - packageDirectory, - 'lib', - dartLibFileName, - ]); -} diff --git a/dwds/test/integration/fixtures/server.dart b/dwds/test/integration/fixtures/server.dart deleted file mode 100644 index 29c455d7ae..0000000000 --- a/dwds/test/integration/fixtures/server.dart +++ /dev/null @@ -1,171 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -// @skip_package_deps_validation - -import 'dart:io'; - -import 'package:build_daemon/data/build_status.dart' as daemon; -import 'package:dwds/asset_reader.dart'; -import 'package:dwds/dart_web_debug_service.dart'; -import 'package:dwds/data/build_result.dart'; -import 'package:dwds/src/config/tool_configuration.dart'; -import 'package:dwds/src/loaders/strategy.dart'; -import 'package:dwds/src/utilities/server.dart'; -import 'package:logging/logging.dart'; -import 'package:shelf/shelf.dart'; -import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'; - -Logger _logger = Logger('TestServer'); - -Handler _interceptFavicon(Handler handler) { - return (request) async { - if (request.url.pathSegments.isNotEmpty && - request.url.pathSegments.last == 'favicon.ico') { - return Response.ok(''); - } - return handler(request); - }; -} - -class TestServer { - final HttpServer _server; - final String target; - final Dwds dwds; - final Stream buildResults; - final AssetReader assetReader; - - TestServer._( - this.target, - this._server, - this.dwds, - this.buildResults, - this.assetReader, - ); - - String get host => _server.address.host; - int get port => _server.port; - - Future stop() async { - await dwds.stop(); - await _server.close(force: true); - } - - static Future start({ - required DebugSettings debugSettings, - required AppMetadata appMetadata, - required Handler assetHandler, - required AssetReader assetReader, - required LoadStrategy strategy, - required String target, - required Stream buildResults, - required Future Function() chromeConnection, - int? port, - HttpServer? httpServer, - }) async { - var pipeline = const Pipeline(); - - pipeline = pipeline.addMiddleware(_interceptFavicon); - - final filteredBuildResults = buildResults.asyncMap((results) { - final result = results.results.firstWhere( - (result) => result.target == target, - ); - switch (result.status) { - case daemon.BuildStatus.started: - return BuildResult(status: BuildStatus.started); - case daemon.BuildStatus.failed: - return BuildResult(status: BuildStatus.failed); - case daemon.BuildStatus.succeeded: - return BuildResult(status: BuildStatus.succeeded); - default: - break; - } - throw StateError('Unexpected Daemon build result: $result'); - }); - - final toolConfiguration = ToolConfiguration( - loadStrategy: strategy, - debugSettings: debugSettings, - appMetadata: appMetadata, - ); - - final dwds = await Dwds.start( - assetReader: assetReader, - buildResults: filteredBuildResults, - chromeConnection: chromeConnection, - toolConfiguration: toolConfiguration, - ); - - final server = httpServer ?? await startHttpServer('localhost', port: port); - var cascade = Cascade(); - - cascade = cascade.add(dwds.handler).add(assetHandler); - - serveHttpRequests( - server, - pipeline - .addMiddleware(_logRequests) - .addMiddleware(dwds.middleware) - .addHandler(cascade.handler), - (e, s) { - _logger.warning('Error handling requests', e, s); - }, - ); - - return TestServer._( - target, - server, - dwds, - filteredBuildResults, - assetReader, - ); - } - - /// [Middleware] that logs all requests, inspired by [logRequests]. - static Handler _logRequests(Handler innerHandler) { - return (Request request) async { - final watch = Stopwatch()..start(); - try { - final response = await innerHandler(request); - final logFn = response.statusCode >= 500 - ? _logger.warning - : _logger.finest; - final msg = _requestLabel( - response.statusCode, - request.requestedUri, - request.method, - watch.elapsed, - ); - logFn(msg); - return response; - } catch (error, stackTrace) { - if (error is HijackException) rethrow; - final msg = _requestLabel( - 500, - request.requestedUri, - request.method, - watch.elapsed, - ); - _logger.severe(msg, error, stackTrace); - rethrow; - } - }; - } - - static String _requestLabel( - int statusCode, - Uri requestedUri, - String method, - Duration elapsedTime, - ) { - return '$elapsedTime ' - '$method [$statusCode] ' - '${requestedUri.path}${_formatQuery(requestedUri.query)}'; - } - - static String _formatQuery(String query) { - return query == '' ? '' : '?$query'; - } -} diff --git a/dwds/test/integration/fixtures/utilities.dart b/dwds/test/integration/fixtures/utilities.dart deleted file mode 100644 index 7ca72445b1..0000000000 --- a/dwds/test/integration/fixtures/utilities.dart +++ /dev/null @@ -1,319 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -// @skip_package_deps_validation - -import 'dart:io'; - -import 'package:build_daemon/client.dart'; -import 'package:build_daemon/constants.dart'; -import 'package:build_daemon/data/server_log.dart'; -import 'package:dds/devtools_server.dart'; -import 'package:dwds/src/config/tool_configuration.dart'; -import 'package:dwds/src/loaders/strategy.dart'; -import 'package:dwds/src/servers/devtools.dart'; -import 'package:dwds/src/services/expression_compiler.dart'; - -import 'context.dart'; -import 'fakes.dart'; - -/// Connects to the `build_runner` daemon. -Future connectClient( - String dartPath, - String workingDirectory, - List options, - void Function(ServerLog) logHandler, -) => BuildDaemonClient.connect(workingDirectory, [ - dartPath, - 'run', - 'build_runner', - 'daemon', - ...options, -], logHandler: logHandler); - -/// Returns the port of the daemon asset server. -int daemonPort(String workingDirectory) { - final portFile = File(_assetServerPortFilePath(workingDirectory)); - if (!portFile.existsSync()) { - throw Exception('Unable to read daemon asset port file.'); - } - return int.parse(portFile.readAsStringSync()); -} - -String _assetServerPortFilePath(String workingDirectory) => - '${daemonWorkspace(workingDirectory)}/.asset_server_port'; - -/// Retries a callback function with a delay until the result is the -/// [expectedResult] (if provided) or is not null. -Future retryFn( - T Function() callback, { - int retryCount = 3, - int delayInMs = 1000, - String failureMessage = 'Function did not succeed after retries.', - T? expectedResult, -}) async { - if (retryCount == 0) { - throw Exception(failureMessage); - } - - await Future.delayed(Duration(milliseconds: delayInMs)); - try { - final result = callback(); - if (expectedResult != null && result == expectedResult) return result; - if (expectedResult == null && result != null) return result; - } catch (_) { - // Ignore any exceptions. - } - - return retryFn( - callback, - retryCount: retryCount - 1, - delayInMs: delayInMs, - failureMessage: failureMessage, - ); -} - -/// Retries an asynchronous callback function with a delay until the result is -/// non-null. -Future retryFnAsync( - Future Function() callback, { - int retryCount = 3, - int delayInMs = 1000, - String failureMessage = 'Function did not succeed after retries.', -}) async { - if (retryCount == 0) { - throw Exception(failureMessage); - } - - await Future.delayed(Duration(milliseconds: delayInMs)); - try { - final result = await callback(); - if (result != null) return result; - } catch (_) { - // Ignore any exceptions. - } - - return retryFnAsync( - callback, - retryCount: retryCount - 1, - delayInMs: delayInMs, - failureMessage: failureMessage, - ); -} - -class TestDebugSettings extends DebugSettings { - TestDebugSettings.withDevToolsLaunch( - TestContext context, { - bool serveFromDds = false, - }) : super( - // ignore: deprecated_member_use_from_same_package - devToolsLauncher: serveFromDds - ? null - : (hostname) async { - final server = await DevToolsServer().serveDevTools( - hostname: hostname, - enableStdinCommands: false, - customDevToolsPath: context - .sdkConfigurationProvider - .sdkLayout - .devToolsDirectory, - ); - if (server == null) { - throw StateError('DevTools server could not be started.'); - } - return DevTools(server.address.host, server.port, server); - }, - ddsConfiguration: DartDevelopmentServiceConfiguration( - serveDevTools: serveFromDds, - ), - ); - - const TestDebugSettings.noDevToolsLaunch() - : super(enableDevToolsLaunch: false); - - TestDebugSettings._({ - required super.enableDebugging, - required super.enableDebugExtension, - required super.useSseForDebugBackend, - required super.useSseForDebugProxy, - required super.useSseForInjectedClient, - required super.spawnDds, - required super.ddsPort, - required super.enableDevToolsLaunch, - required super.launchDevToolsInNewWindow, - required super.emitDebugEvents, - required super.devToolsLauncher, - required super.expressionCompiler, - required super.urlEncoder, - required super.ddsConfiguration, - }); - - TestDebugSettings copyWith({ - bool? enableDebugging, - bool? enableDebugExtension, - bool? useSse, - bool? spawnDds, - int? ddsPort, - bool? enableDevToolsLaunch, - bool? launchDevToolsInNewWindow, - bool? emitDebugEvents, - DevToolsLauncher? devToolsLauncher, - ExpressionCompiler? expressionCompiler, - UrlEncoder? urlEncoder, - DartDevelopmentServiceConfiguration? ddsConfiguration, - }) { - return TestDebugSettings._( - enableDebugging: enableDebugging ?? this.enableDebugging, - enableDebugExtension: enableDebugExtension ?? this.enableDebugExtension, - useSseForDebugProxy: useSse ?? useSseForDebugProxy, - useSseForDebugBackend: useSse ?? useSseForDebugBackend, - useSseForInjectedClient: useSse ?? useSseForInjectedClient, - // ignore: deprecated_member_use_from_same_package - spawnDds: spawnDds ?? this.spawnDds, - // ignore: deprecated_member_use_from_same_package - ddsPort: ddsPort ?? this.ddsPort, - enableDevToolsLaunch: enableDevToolsLaunch ?? this.enableDevToolsLaunch, - launchDevToolsInNewWindow: - launchDevToolsInNewWindow ?? this.launchDevToolsInNewWindow, - emitDebugEvents: emitDebugEvents ?? this.emitDebugEvents, - // ignore: deprecated_member_use_from_same_package - devToolsLauncher: devToolsLauncher ?? this.devToolsLauncher, - expressionCompiler: expressionCompiler ?? this.expressionCompiler, - urlEncoder: urlEncoder ?? this.urlEncoder, - ddsConfiguration: ddsConfiguration ?? this.ddsConfiguration, - ); - } -} - -class TestAppMetadata extends AppMetadata { - const TestAppMetadata({ - super.isInternalBuild, - super.workspaceName, - super.hostname = 'localhost', - }); - - TestAppMetadata copyWith({ - bool? isFlutterApp, - bool? isInternalBuild, - String? workspaceName, - String? hostname, - }) => TestAppMetadata( - isInternalBuild: isInternalBuild ?? this.isInternalBuild, - workspaceName: workspaceName ?? this.workspaceName, - hostname: hostname ?? this.hostname, - ); - - const TestAppMetadata.externalApp() : super(isInternalBuild: false); - - const TestAppMetadata.internalApp() : super(isInternalBuild: true); -} - -class TestToolConfiguration extends ToolConfiguration { - TestToolConfiguration.withDefaultLoadStrategy({ - TestAppMetadata super.appMetadata = const TestAppMetadata.externalApp(), - TestDebugSettings super.debugSettings = - const TestDebugSettings.noDevToolsLaunch(), - TestBuildSettings buildSettings = const TestBuildSettings.dart(), - }) : super(loadStrategy: TestStrategy(FakeAssetReader(), buildSettings)); - - TestToolConfiguration.withLoadStrategy({ - TestAppMetadata super.appMetadata = const TestAppMetadata.externalApp(), - TestDebugSettings super.debugSettings = - const TestDebugSettings.noDevToolsLaunch(), - required super.loadStrategy, - }); -} - -void setGlobalsForTesting({ToolConfiguration? toolConfiguration}) { - globalToolConfiguration = - toolConfiguration ?? TestToolConfiguration.withDefaultLoadStrategy(); -} - -void setGlobalsForTestingFromBuild({ - TestBuildSettings buildSettings = const TestBuildSettings.dart(), -}) { - globalToolConfiguration = TestToolConfiguration.withDefaultLoadStrategy( - buildSettings: buildSettings, - ); -} - -class TestStrategy extends FakeStrategy { - TestStrategy(super.assetReader, BuildSettings buildSettings) - : super(buildSettings: buildSettings); - - @override - String serverPathForAppUri(String appUri) { - return 'foo'; - } -} - -/// Settings defining how to run the tests. -class TestSettings { - // Scenario settings. - final ReloadConfiguration reloadConfiguration; - final bool autoRun; - final bool waitToDebug; - final bool enableExpressionEvaluation; - final bool verboseCompiler; - final bool launchChrome; - - // Build settings. - final CompilationMode compilationMode; - final ModuleFormat moduleFormat; - final bool canaryFeatures; - final bool isFlutterApp; - final List experiments; - final bool useDebuggerModuleNames; - - const TestSettings({ - this.reloadConfiguration = ReloadConfiguration.none, - this.autoRun = true, - this.waitToDebug = false, - this.enableExpressionEvaluation = false, - this.verboseCompiler = false, - this.launchChrome = true, - this.compilationMode = CompilationMode.buildDaemon, - this.moduleFormat = ModuleFormat.amd, - this.canaryFeatures = false, - this.isFlutterApp = false, - this.experiments = const [], - this.useDebuggerModuleNames = false, - }); -} - -/// App build settings for tests. -class TestBuildSettings extends BuildSettings { - const TestBuildSettings({ - super.appEntrypoint, - super.canaryFeatures, - super.isFlutterApp, - super.experiments, - }); - - const TestBuildSettings.dart({Uri? appEntrypoint}) - : this(appEntrypoint: appEntrypoint, isFlutterApp: false); - - const TestBuildSettings.flutter({Uri? appEntrypoint}) - : this(appEntrypoint: appEntrypoint, isFlutterApp: true); - - TestBuildSettings copyWith({ - Uri? appEntrypoint, - bool? canaryFeatures, - bool? isFlutterApp, - List? experiments, - }) => TestBuildSettings( - appEntrypoint: appEntrypoint ?? this.appEntrypoint, - canaryFeatures: canaryFeatures ?? this.canaryFeatures, - isFlutterApp: isFlutterApp ?? this.isFlutterApp, - experiments: experiments ?? this.experiments, - ); -} - -class TestCompilerOptions extends CompilerOptions { - TestCompilerOptions({ - required super.canaryFeatures, - super.experiments = const [], - super.moduleFormat = ModuleFormat.amd, - }); -} diff --git a/dwds/test/integration/handlers/asset_handler_common.dart b/dwds/test/integration/handlers/asset_handler_common.dart deleted file mode 100644 index 7f3ba6362f..0000000000 --- a/dwds/test/integration/handlers/asset_handler_common.dart +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'package:dwds_test_common/logging.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:shelf/shelf.dart'; -import 'package:test/test.dart'; - -import '../fixtures/context.dart'; -import '../fixtures/project.dart'; -import '../fixtures/utilities.dart'; - -void testAll({required TestSdkConfigurationProvider provider}) { - group('Asset handler', () { - final context = TestContext(TestProject.test, provider); - - setUpAll(() async { - setCurrentLogWriter(debug: provider.verbose); - await context.setUp( - testSettings: TestSettings( - enableExpressionEvaluation: true, - verboseCompiler: provider.verbose, - moduleFormat: provider.ddcModuleFormat, - canaryFeatures: provider.canaryFeatures, - ), - ); - }); - - tearDownAll(() async { - await context.tearDown(); - }); - - setUp(() => setCurrentLogWriter(debug: provider.verbose)); - - Future readAsString(String path) async { - final request = Request('GET', Uri.parse('http://foo:0000/$path')); - final response = await context.assetHandler(request); - expect(response.statusCode, 200); - final result = await response.readAsString(); - expect( - result, - isNotNull, - reason: 'Failed to read $path: ${response.statusCode}', - ); - } - - Future readAsBytes(String path) async { - final request = Request('GET', Uri.parse('http://foo:0000/$path')); - final response = await context.assetHandler(request); - expect(response.statusCode, 200); - final result = await response.read().toList(); - expect( - result, - isNotNull, - reason: 'Failed to read $path: ${response.statusCode}', - ); - } - - test('can read dill files', () async { - final path = 'hello_world/main.ddc.full.dill'; - await readAsBytes(path); - }); - - test('can read large number of resources simultaneously', () async { - final n = 1000; - final futures = [ - for (var i = 0; i < n; i++) readAsString('hello_world/main.ddc.js.map'), - for (var i = 0; i < n; i++) readAsString('hello_world/main.ddc.js'), - for (var i = 0; i < n; i++) - readAsBytes('hello_world/main.ddc.full.dill'), - ]; - - await expectLater(Future.wait(futures), completes); - }); - }); -} diff --git a/dwds/test/integration/handlers/injector_test.dart b/dwds/test/integration/handlers/injector_test.dart deleted file mode 100644 index b791deaa7c..0000000000 --- a/dwds/test/integration/handlers/injector_test.dart +++ /dev/null @@ -1,415 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@Timeout(Duration(minutes: 2)) -library; - -import 'dart:io'; - -import 'package:dwds/src/handlers/injector.dart'; -import 'package:dwds/src/version.dart'; -import 'package:http/http.dart' as http; -import 'package:shelf/shelf.dart'; -import 'package:shelf/shelf_io.dart' as shelf_io; -import 'package:test/test.dart'; - -import '../fixtures/utilities.dart'; - -void main() { - late HttpServer server; - const entryEtag = 'entry etag'; - const nonEntryEtag = 'some etag'; - - group('Injector test', () { - setUpAll(setGlobalsForTestingFromBuild); - - group('InjectedHandlerWithoutExtension', () { - late DwdsInjector injector; - setUp(() async { - injector = DwdsInjector(); - final pipeline = const Pipeline().addMiddleware(injector.middleware); - server = await shelf_io.serve( - pipeline.addHandler((request) { - if (request.url.path.endsWith(bootstrapJsExtension)) { - return Response.ok( - '$entrypointExtensionMarker\n' - '$mainExtensionMarker\n' - 'app.main.main()', - headers: {HttpHeaders.etagHeader: entryEtag}, - ); - } else if (request.url.path.endsWith('foo.js')) { - return Response.ok( - 'some js', - headers: {HttpHeaders.etagHeader: nonEntryEtag}, - ); - } else { - return Response.notFound('Not found'); - } - }), - 'localhost', - 0, - ); - }); - - tearDown(() async { - await server.close(); - }); - - test('leaves non-entrypoints untouched', () async { - final result = await http.get( - Uri.parse('http://localhost:${server.port}/foo.js'), - ); - expect(result.body, 'some js'); - }); - - test('does not update etags for non-entrypoints', () async { - final result = await http.get( - Uri.parse('http://localhost:${server.port}/foo.js'), - ); - expect(result.headers[HttpHeaders.etagHeader], nonEntryEtag); - }); - - test('replaces main marker with injected client', () async { - final result = await http.get( - Uri.parse( - 'http://localhost:${server.port}/entrypoint$bootstrapJsExtension', - ), - ); - expect(result.body.contains('Injected by dwds'), isTrue); - expect(result.body.contains(mainExtensionMarker), isFalse); - }); - - test('prevents main from being called', () async { - final result = await http.get( - Uri.parse( - 'http://localhost:${server.port}/entrypoint$bootstrapJsExtension', - ), - ); - expect(result.body.contains('window.\$dartRunMain'), isTrue); - }); - - test('updates etags for injected responses', () async { - final result = await http.get( - Uri.parse( - 'http://localhost:${server.port}/entrypoint$bootstrapJsExtension', - ), - ); - expect(result.headers[HttpHeaders.etagHeader], isNot(entryEtag)); - }); - - test('ignores non-js requests', () async { - final result = await http.get( - Uri.parse('http://localhost:${server.port}/main.dart'), - ); - expect(result.body, 'Not found'); - }); - - test('embeds the devHandlerPath', () async { - final result = await http.get( - Uri.parse( - 'http://localhost:${server.port}/entrypoint$bootstrapJsExtension', - ), - ); - expect( - result.body.contains('window.\$dwdsDevHandlerPath = "http://'), - isTrue, - ); - }); - - test('emits a devHandlerPath for each entrypoint', () async { - await http.get( - Uri.parse( - 'http://localhost:${server.port}/foo/entrypoint$bootstrapJsExtension', - ), - ); - await http.get( - Uri.parse( - 'http://localhost:${server.port}/blah/entrypoint$bootstrapJsExtension', - ), - ); - expect( - injector.devHandlerPaths, - emitsInOrder([ - 'http://localhost:${server.port}/foo/\$dwdsSseHandler', - 'http://localhost:${server.port}/blah/\$dwdsSseHandler', - ]), - ); - }); - - test('Does not return 304 when if-none-match etag matches the original ' - 'content etag', () async { - final result = await http.get( - Uri.parse( - 'http://localhost:${server.port}/entrypoint$bootstrapJsExtension', - ), - headers: {HttpHeaders.ifNoneMatchHeader: entryEtag}, - ); - expect(result.statusCode, HttpStatus.ok); - }); - - test( - 'Does return 304 when if-none-match etag matches the modified etag', - () async { - final originalResponse = await http.get( - Uri.parse( - 'http://localhost:${server.port}/entrypoint$bootstrapJsExtension', - ), - ); - - final etagHeader = originalResponse.headers[HttpHeaders.etagHeader]; - expect(etagHeader, isNotNull); - final cachedResponse = await http.get( - Uri.parse( - 'http://localhost:${server.port}/entrypoint$bootstrapJsExtension', - ), - headers: {HttpHeaders.ifNoneMatchHeader: etagHeader!}, - ); - expect(cachedResponse.statusCode, HttpStatus.notModified); - }, - ); - - test('Does not inject the extension backend port', () async { - final result = await http.get( - Uri.parse( - 'http://localhost:${server.port}/entrypoint$bootstrapJsExtension', - ), - ); - expect(result.body.contains('dartExtensionUri'), isFalse); - }); - - test('Has correct DWDS version', () async { - final result = await http.get( - Uri.parse( - 'http://localhost:${server.port}/entrypoint$bootstrapJsExtension', - ), - ); - final expected = r'$dwdsVersion = '; - final index = result.body.indexOf(expected); - expect(index, greaterThan(0)); - final nextBit = result.body.substring(index + expected.length); - final versionPiece = nextBit.split('"')[1]; - expect(versionPiece, packageVersion); - }); - - test('Injects bootstrap', () async { - final result = await http.get( - Uri.parse( - 'http://localhost:${server.port}/entrypoint$bootstrapJsExtension', - ), - ); - expect(result.body.contains('dummy_bootstrap'), isTrue); - }); - - test('Injects load strategy id', () async { - final result = await http.get( - Uri.parse( - 'http://localhost:${server.port}/entrypoint$bootstrapJsExtension', - ), - ); - expect(result.body.contains('dummy-id'), isTrue); - }); - - test('Injects the entrypoint path', () async { - final result = await http.get( - Uri.parse( - 'http://localhost:${server.port}/entrypoint$bootstrapJsExtension', - ), - ); - expect( - result.body.contains( - 'dartEntrypointPath = "entrypoint.bootstrap.js"', - ), - isTrue, - ); - }); - - test('Injects client load snippet', () async { - final result = await http.get( - Uri.parse( - 'http://localhost:${server.port}/entrypoint$bootstrapJsExtension', - ), - ); - expect(result.body.contains('dummy-load-client-snippet'), isTrue); - }); - - test('Injects dwds enable devtools launch configuration', () async { - final result = await http.get( - Uri.parse( - 'http://localhost:${server.port}/entrypoint$bootstrapJsExtension', - ), - ); - expect(result.body.contains('dwdsEnableDevToolsLaunch'), isTrue); - }); - - test('Delegates to strategy handler', () async { - final result = await http.get( - Uri.parse('http://localhost:${server.port}/someDummyPath'), - ); - expect(result.body, equals('some dummy response')); - }); - - test('the injected client contains a global \$emitDebugEvents', () async { - final result = await http.get( - Uri.parse( - 'http://localhost:${server.port}/dwds/src/injected/client.js', - ), - ); - expect(result.body, contains('\$dartEmitDebugEvents')); - }); - - test('the injected client contains a global \$emitDebugEvent', () async { - final result = await http.get( - Uri.parse( - 'http://localhost:${server.port}/dwds/src/injected/client.js', - ), - ); - expect(result.body, contains('\$emitDebugEvent')); - }); - - test( - 'the injected client contains a global \$emitRegisterEvent', - () async { - final result = await http.get( - Uri.parse( - 'http://localhost:${server.port}/dwds/src/injected/client.js', - ), - ); - expect(result.body, contains('\$emitRegisterEvent')); - }, - ); - - test('the injected client contains a global \$isInternalBuild', () async { - final result = await http.get( - Uri.parse( - 'http://localhost:${server.port}/dwds/src/injected/client.js', - ), - ); - expect(result.body, contains('\$isInternalBuild')); - }); - - test('the injected client contains a global \$isFlutterApp', () async { - final result = await http.get( - Uri.parse( - 'http://localhost:${server.port}/dwds/src/injected/client.js', - ), - ); - expect(result.body, contains('\$isFlutterApp')); - }); - - test('serves the injected client', () async { - final result = await http.get( - Uri.parse( - 'http://localhost:${server.port}/dwds/src/injected/client.js', - ), - ); - expect(result.statusCode, HttpStatus.ok); - }); - }); - - group('InjectedHandlerWithoutExtension using WebSockets', () { - late DwdsInjector injector; - setUp(() async { - final toolConfiguration = TestToolConfiguration.withDefaultLoadStrategy( - debugSettings: const TestDebugSettings.noDevToolsLaunch().copyWith( - useSse: false, - ), - ); - setGlobalsForTesting(toolConfiguration: toolConfiguration); - injector = DwdsInjector(); - final pipeline = const Pipeline().addMiddleware(injector.middleware); - server = await shelf_io.serve( - pipeline.addHandler((request) { - if (request.url.path.endsWith(bootstrapJsExtension)) { - return Response.ok( - '$entrypointExtensionMarker\n' - '$mainExtensionMarker\n' - 'app.main.main()', - headers: {HttpHeaders.etagHeader: entryEtag}, - ); - } else if (request.url.path.endsWith('foo.js')) { - return Response.ok( - 'some js', - headers: {HttpHeaders.etagHeader: nonEntryEtag}, - ); - } else { - return Response.notFound('Not found'); - } - }), - 'localhost', - 0, - ); - }); - - tearDown(() async { - await server.close(); - }); - - test('embeds the devHandlerPath', () async { - final result = await http.get( - Uri.parse( - 'http://localhost:${server.port}/entrypoint$bootstrapJsExtension', - ), - ); - expect( - result.body.contains('window.\$dwdsDevHandlerPath = "ws://'), - isTrue, - ); - }); - - test('emits a devHandlerPath for each entrypoint', () async { - await http.get( - Uri.parse( - 'http://localhost:${server.port}/foo/entrypoint$bootstrapJsExtension', - ), - ); - await http.get( - Uri.parse( - 'http://localhost:${server.port}/blah/entrypoint$bootstrapJsExtension', - ), - ); - expect( - injector.devHandlerPaths, - emitsInOrder([ - 'ws://localhost:${server.port}/foo/\$dwdsSseHandler', - 'ws://localhost:${server.port}/blah/\$dwdsSseHandler', - ]), - ); - }); - }); - - group('InjectedHandlerWithExtension', () { - setUp(() async { - final extensionUri = 'http://localhost:4000'; - final pipeline = const Pipeline().addMiddleware( - DwdsInjector(extensionUri: Future.value(extensionUri)).middleware, - ); - server = await shelf_io.serve( - pipeline.addHandler((request) { - return Response.ok( - '$entrypointExtensionMarker\n' - '$mainExtensionMarker\n' - 'app.main.main()', - headers: {HttpHeaders.etagHeader: entryEtag}, - ); - }), - 'localhost', - 0, - ); - }); - - tearDown(() async { - await server.close(); - }); - - test('Injects the extension backend port', () async { - final result = await http.get( - Uri.parse( - 'http://localhost:${server.port}/entrypoint$bootstrapJsExtension', - ), - ); - expect(result.body.contains('dartExtensionUri'), isTrue); - }); - }); - }); -} diff --git a/dwds/test/integration/hot_reload_breakpoints_common.dart b/dwds/test/integration/hot_reload_breakpoints_common.dart deleted file mode 100644 index 276781b3ab..0000000000 --- a/dwds/test/integration/hot_reload_breakpoints_common.dart +++ /dev/null @@ -1,585 +0,0 @@ -// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:async'; - -import 'package:dwds_test_common/logging.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; -import 'package:vm_service/vm_service.dart'; - -import 'fixtures/context.dart'; -import 'fixtures/project.dart'; -import 'fixtures/utilities.dart'; - -void runTests({ - required TestSdkConfigurationProvider provider, - required CompilationMode compilationMode, -}) { - final project = TestProject.testHotReloadBreakpoints; - final context = TestContext(project, provider); - final mainFile = project.dartEntryFileName; - final callLogMarker = 'callLog'; - final capturedStringMarker = 'capturedString'; - - Future makeEditsAndRecompile(List edits) async { - await context.makeEdits(edits); - await context.recompile(fullRestart: true); - } - - group('when pause_isolates_on_start is true', () { - late VmService client; - late Stream stream; - - setUp(() async { - setCurrentLogWriter(debug: provider.verbose); - await context.setUp( - testSettings: TestSettings( - enableExpressionEvaluation: true, - compilationMode: compilationMode, - moduleFormat: provider.ddcModuleFormat, - canaryFeatures: provider.canaryFeatures, - ), - ); - client = await context.connectFakeClient(); - await client.setFlag('pause_isolates_on_start', 'true'); - await client.streamListen(EventStreams.kDebug); - stream = client.onDebugEvent; - }); - - tearDown(() async { - await context.tearDown(); - }); - - Future addBreakpoint({ - required String file, - required String breakpointMarker, - }) async { - final vm = await client.getVM(); - final isolateId = vm.isolates!.first.id!; - final scriptList = await client.getScripts(isolateId); - final scriptRef = scriptList.scripts!.firstWhere( - (script) => script.uri!.contains(file), - ); - final bpLine = await context.findBreakpointLine( - breakpointMarker, - isolateId, - scriptRef, - ); - final breakpointAdded = expectLater( - stream, - emits(_hasKind(EventKind.kBreakpointAdded)), - ); - final breakpoint = await client.addBreakpointWithScriptUri( - isolateId, - scriptRef.uri!, - bpLine, - ); - await breakpointAdded; - return breakpoint; - } - - Future removeBreakpoint(Breakpoint bp) async { - final vm = await client.getVM(); - final isolateId = vm.isolates!.first.id!; - final breakpointRemoved = expectLater( - stream, - emits(_hasKind(EventKind.kBreakpointRemoved)), - ); - await client.removeBreakpoint(isolateId, bp.id!); - await breakpointRemoved; - } - - Future resume() async { - final vm = await client.getVM(); - final isolate = await client.getIsolate(vm.isolates!.first.id!); - await client.resume(isolate.id!); - } - - // Resume the program, and check that at some point it will execute code - // that will print `expectedString` to the console. - Future resumeAndWaitForLog(String expectedString) async { - final completer = Completer(); - final subscription = context.webkitDebugger.onConsoleAPICalled.listen(( - e, - ) { - if (e.args.first.value == expectedString) { - completer.complete(); - } - }); - await resume(); - await completer.future.timeout( - const Duration(minutes: 1), - onTimeout: () { - throw TimeoutException( - "Failed to find log: '$expectedString' in console.", - ); - }, - ); - await subscription.cancel(); - } - - Future> hotReloadAndHandlePausePost( - List<({String file, String breakpointMarker, Breakpoint? bp})> - breakpoints, - ) async { - final breakpointEvents = expectLater( - stream, - emitsInOrder([ - _hasKind(EventKind.kPausePostRequest), - for (final (:bp, breakpointMarker: _, file: _) in breakpoints) ...[ - if (bp != null) _hasKind(EventKind.kBreakpointRemoved), - _hasKind(EventKind.kBreakpointAdded), - ], - _hasKind(EventKind.kResume), - ]), - ); - final waitForPausePost = expectLater( - stream, - emits(_hasKind(EventKind.kPausePostRequest)), - ); - - // Initiate the hot reload by loading the sources into the page. - final vm = await client.getVM(); - final isolate = await client.getIsolate(vm.isolates!.first.id!); - final report = await client.reloadSources(isolate.id!); - expect(report.success, true); - - // Client (e.g. DAP) should listen for this event, remove old breakpoints, - // reregister breakpoints, and then resume. The following lines imitate - // what the client should do. - await waitForPausePost; - final newBreakpoints = []; - for (final (:bp, :breakpointMarker, :file) in breakpoints) { - // This could be a new file, so there's no existing breakpoint to - // remove. - if (bp != null) await removeBreakpoint(bp); - newBreakpoints.add( - await addBreakpoint(file: file, breakpointMarker: breakpointMarker), - ); - } - // The resume should complete hot reload and resume the program. - await resume(); - await breakpointEvents; - return newBreakpoints; - } - - Future callEvaluate() async { - final vm = await client.getVM(); - final isolate = await client.getIsolate(vm.isolates!.first.id!); - final rootLib = isolate.rootLib; - await client.evaluate(isolate.id!, rootLib!.id!, 'evaluate()'); - } - - // Call the method `evaluate` in the program and wait for `expectedString` - // to be printed to the console. - Future callEvaluateAndWaitForLog(String expectedString) async { - final completer = Completer(); - final subscription = context.webkitDebugger.onConsoleAPICalled.listen(( - e, - ) { - if (e.args.first.value == expectedString) { - completer.complete(); - } - }); - final vm = await client.getVM(); - final isolate = await client.getIsolate(vm.isolates!.first.id!); - final rootLib = isolate.rootLib; - await client.evaluate(isolate.id!, rootLib!.id!, 'evaluate()'); - await completer.future.timeout( - const Duration(minutes: 1), - onTimeout: () { - throw TimeoutException( - "Failed to find log: '$expectedString' in console.", - ); - }, - ); - await subscription.cancel(); - } - - Future waitForBreakpoint({bool resumeFirst = false}) => expectLater( - stream, - emitsInOrder([ - if (resumeFirst) _hasKind(EventKind.kResume), - _hasKind(EventKind.kPauseBreakpoint), - ]), - ); - - test('empty hot reload keeps breakpoints', () async { - final genString = 'main gen0'; - - final bp = await addBreakpoint( - file: mainFile, - breakpointMarker: callLogMarker, - ); - - var breakpointFuture = waitForBreakpoint(); - - await callEvaluate(); - - // Should break at `callLog`. - await breakpointFuture; - await resumeAndWaitForLog(genString); - - await context.recompile(fullRestart: false); - - await hotReloadAndHandlePausePost([ - (file: mainFile, breakpointMarker: callLogMarker, bp: bp), - ]); - - breakpointFuture = waitForBreakpoint(); - - await callEvaluate(); - - // Should break at `callLog`. - await breakpointFuture; - await resumeAndWaitForLog(genString); - }); - - test('after edit and hot reload, breakpoint is in new file', () async { - final oldString = 'main gen0'; - final newString = 'main gen1'; - - final bp = await addBreakpoint( - file: mainFile, - breakpointMarker: callLogMarker, - ); - - var breakpointFuture = waitForBreakpoint(); - - await callEvaluate(); - - // Should break at `callLog`. - await breakpointFuture; - await resumeAndWaitForLog(oldString); - - // Modify the string that gets printed. - await makeEditsAndRecompile([ - (file: mainFile, originalString: oldString, newString: newString), - ]); - - await hotReloadAndHandlePausePost([ - (file: mainFile, breakpointMarker: callLogMarker, bp: bp), - ]); - - breakpointFuture = waitForBreakpoint(); - - await callEvaluate(); - - // Should break at `callLog`. - await breakpointFuture; - await resumeAndWaitForLog(newString); - }); - - test('after adding line, hot reload, removing line, and hot reload, ' - 'breakpoint is correct across both hot reloads', () async { - final genLog = 'main gen0'; - - var bp = await addBreakpoint( - file: mainFile, - breakpointMarker: callLogMarker, - ); - - var breakpointFuture = waitForBreakpoint(); - - await callEvaluate(); - - // Should break at `callLog`. - await breakpointFuture; - await resumeAndWaitForLog(genLog); - - // Add an extra log before the existing log. - final extraLog = 'hot reload'; - final oldString = "log('"; - final newString = "log('$extraLog');\n$oldString"; - await makeEditsAndRecompile([ - (file: mainFile, originalString: oldString, newString: newString), - ]); - - bp = (await hotReloadAndHandlePausePost([ - (file: mainFile, breakpointMarker: callLogMarker, bp: bp), - ])).first; - - breakpointFuture = waitForBreakpoint(); - - await callEvaluateAndWaitForLog(extraLog); - - // Should break at `callLog`. - await breakpointFuture; - await resumeAndWaitForLog(genLog); - - // Remove the line we just added. - await makeEditsAndRecompile([ - (file: mainFile, originalString: newString, newString: oldString), - ]); - - await hotReloadAndHandlePausePost([ - (file: mainFile, breakpointMarker: callLogMarker, bp: bp), - ]); - - breakpointFuture = waitForBreakpoint(); - - final consoleLogs = []; - final consoleSubscription = context.webkitDebugger.onConsoleAPICalled - .listen((e) { - consoleLogs.add(e.args.first.value as String); - }); - - await callEvaluate(); - - // Should break at `callLog`. - await breakpointFuture; - expect(consoleLogs.contains(extraLog), false); - await resumeAndWaitForLog(genLog); - await consoleSubscription.cancel(); - }); - - test( - 'after adding file and putting breakpoint in it, breakpoint is correctly ' - 'registered', - () async { - final genLog = 'main gen0'; - - final bp = await addBreakpoint( - file: mainFile, - breakpointMarker: callLogMarker, - ); - - var breakpointFuture = waitForBreakpoint(); - - await callEvaluate(); - - // Should break at `callLog`. - await breakpointFuture; - await resumeAndWaitForLog(genLog); - - // Add a library file, import it, and then refer to it in the log. - final libFile = 'library.dart'; - final libGenLog = 'library gen0'; - final libValueMarker = 'libValue'; - context.addLibraryFile( - libFileName: libFile, - contents: - '''String get libraryValue { - return '$libGenLog'; // Breakpoint: $libValueMarker - }''', - ); - final oldImports = "import 'dart:js_interop';"; - final newImports = - '$oldImports\n' - "import 'package:_test_hot_reload_breakpoints/library.dart';"; - final edits = [ - (file: mainFile, originalString: oldImports, newString: newImports), - ]; - final oldLog = "log('\$mainValue');"; - final newLog = "log('\$libraryValue');"; - edits.add((file: mainFile, originalString: oldLog, newString: newLog)); - await makeEditsAndRecompile(edits); - - await hotReloadAndHandlePausePost([ - (file: mainFile, breakpointMarker: callLogMarker, bp: bp), - (file: libFile, breakpointMarker: libValueMarker, bp: null), - ]); - - breakpointFuture = waitForBreakpoint(); - - await callEvaluate(); - - // Should break at `callLog`. - await breakpointFuture; - - breakpointFuture = waitForBreakpoint(resumeFirst: true); - - await resume(); - // Should break at `libValue`. - await breakpointFuture; - await resumeAndWaitForLog(libGenLog); - }, - ); - - // Test that we wait for all scripts to be parsed first before computing - // location metadata. - test('after adding many files and putting breakpoint in the last one,' - 'breakpoint is correctly registered', () async { - final genLog = 'main gen0'; - - final bp = await addBreakpoint( - file: mainFile, - breakpointMarker: callLogMarker, - ); - - var breakpointFuture = waitForBreakpoint(); - - await callEvaluate(); - - // Should break at `callLog`. - await breakpointFuture; - await resumeAndWaitForLog(genLog); - - // Add library files, import them, but only refer to the last one in main. - final numFiles = 50; - final edits = []; - for (var i = 1; i <= numFiles; i++) { - final libFile = 'library$i.dart'; - context.addLibraryFile( - libFileName: libFile, - contents: - '''String get libraryValue$i { - return 'library$i gen1'; // Breakpoint: libValue$i - }''', - ); - final oldImports = "import 'dart:js_interop';"; - final newImports = - '$oldImports\n' - "import 'package:_test_hot_reload_breakpoints/$libFile';"; - edits.add(( - file: mainFile, - originalString: oldImports, - newString: newImports, - )); - } - final oldLog = "log('\$mainValue');"; - final newLog = "log('\$libraryValue$numFiles');"; - edits.add((file: mainFile, originalString: oldLog, newString: newLog)); - await makeEditsAndRecompile(edits); - - await hotReloadAndHandlePausePost([ - (file: mainFile, breakpointMarker: callLogMarker, bp: bp), - ( - file: 'library$numFiles.dart', - breakpointMarker: 'libValue$numFiles', - bp: null, - ), - ]); - - breakpointFuture = waitForBreakpoint(); - - await callEvaluate(); - - // Should break at `callLog`. - await breakpointFuture; - - breakpointFuture = waitForBreakpoint(resumeFirst: true); - - await resume(); - // Should break at the breakpoint in the last file. - await breakpointFuture; - await resumeAndWaitForLog('library$numFiles gen1'); - }); - - test('breakpoint in captured code is deleted', () async { - var bp = await addBreakpoint( - file: mainFile, - breakpointMarker: capturedStringMarker, - ); - - final oldLog = "log('\$mainValue');"; - final newLog = "log('\${closure()}');"; - await makeEditsAndRecompile([ - (file: mainFile, originalString: oldLog, newString: newLog), - ]); - - bp = (await hotReloadAndHandlePausePost([ - (file: mainFile, breakpointMarker: capturedStringMarker, bp: bp), - ])).first; - - final breakpointFuture = waitForBreakpoint(); - - await callEvaluate(); - - // Should break at `capturedString`. - await breakpointFuture; - final oldCapturedString = 'captured closure gen0'; - // Closure gets evaluated for the first time. - await resumeAndWaitForLog(oldCapturedString); - - final newCapturedString = 'captured closure gen1'; - await makeEditsAndRecompile([ - ( - file: mainFile, - originalString: oldCapturedString, - newString: newCapturedString, - ), - ]); - - await hotReloadAndHandlePausePost([ - (file: mainFile, breakpointMarker: capturedStringMarker, bp: bp), - ]); - - // Breakpoint should not be hit as it's now deleted. We should also see - // the old string still as the closure has not been reevaluated. - await callEvaluateAndWaitForLog(oldCapturedString); - }); - }, timeout: const Timeout.factor(2)); - - group('when pause_isolates_on_start is false', () { - late VmService client; - - setUp(() async { - setCurrentLogWriter(debug: provider.verbose); - await context.setUp( - testSettings: TestSettings( - enableExpressionEvaluation: true, - compilationMode: compilationMode, - moduleFormat: provider.ddcModuleFormat, - canaryFeatures: provider.canaryFeatures, - ), - ); - client = await context.connectFakeClient(); - await client.setFlag('pause_isolates_on_start', 'false'); - }); - - tearDown(() async { - await context.tearDown(); - }); - - // Call the method `evaluate` in the program and wait for `expectedString` - // to be printed to the console. - Future callEvaluateAndWaitForLog(String expectedString) async { - final completer = Completer(); - final subscription = context.webkitDebugger.onConsoleAPICalled.listen(( - e, - ) { - if (e.args.first.value == expectedString) { - completer.complete(); - } - }); - final vm = await client.getVM(); - final isolate = await client.getIsolate(vm.isolates!.first.id!); - final rootLib = isolate.rootLib; - await client.evaluate(isolate.id!, rootLib!.id!, 'evaluate()'); - await completer.future.timeout( - const Duration(minutes: 1), - onTimeout: () { - throw TimeoutException( - "Failed to find log: '$expectedString' in console.", - ); - }, - ); - await subscription.cancel(); - } - - test('no pause when calling reloadSources', () async { - final oldString = 'main gen0'; - final newString = 'main gen1'; - - await callEvaluateAndWaitForLog(oldString); - - // Modify the string that gets printed and hot reload. - await makeEditsAndRecompile([ - (file: mainFile, originalString: oldString, newString: newString), - ]); - final vm = await client.getVM(); - final isolate = await client.getIsolate(vm.isolates!.first.id!); - final report = await client.reloadSources(isolate.id!); - expect(report.success, true); - - // Program should not be paused, so this should execute. - await callEvaluateAndWaitForLog(newString); - }); - }, timeout: const Timeout.factor(2)); -} - -TypeMatcher _hasKind(String kind) => - isA().having((e) => e.kind, 'kind', kind); diff --git a/dwds/test/integration/hot_reload_common.dart b/dwds/test/integration/hot_reload_common.dart deleted file mode 100644 index ebb780ea52..0000000000 --- a/dwds/test/integration/hot_reload_common.dart +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:async'; - -import 'package:dwds_test_common/logging.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; -import 'package:vm_service/vm_service.dart'; - -import 'fixtures/context.dart'; -import 'fixtures/project.dart'; -import 'fixtures/utilities.dart'; - -const originalString = 'Hello World!'; -const newString = 'Bonjour le monde!'; - -void runTests({ - required TestSdkConfigurationProvider provider, - required CompilationMode compilationMode, -}) { - final project = TestProject.testHotReload; - final context = TestContext(project, provider); - - Future recompile() async { - await context.recompile(fullRestart: false); - } - - Future makeEditAndRecompile() async { - await context.makeEdits([ - ( - file: 'library1.dart', - originalString: originalString, - newString: newString, - ), - ]); - await recompile(); - } - - // Call the method `evaluate` in the program and wait for `expectedString` to - // be printed to the console. - Future callEvaluateAndWaitForLog(String expectedString) async { - final client = context.debugConnection.vmService; - final completer = Completer(); - final subscription = context.webkitDebugger.onConsoleAPICalled.listen((e) { - if (e.args.first.value == expectedString) { - completer.complete(); - } - }); - final vm = await client.getVM(); - final isolate = await client.getIsolate(vm.isolates!.first.id!); - final rootLib = isolate.rootLib; - await client.evaluate(isolate.id!, rootLib!.id!, 'evaluate()'); - await completer.future.timeout( - const Duration(minutes: 1), - onTimeout: () { - throw TimeoutException( - "Failed to find log: '$expectedString' in console.", - ); - }, - ); - await subscription.cancel(); - } - - group('Injected client', () { - late VmService fakeClient; - - setUp(() async { - setCurrentLogWriter(debug: provider.verbose); - await context.setUp( - testSettings: TestSettings( - enableExpressionEvaluation: true, - compilationMode: compilationMode, - moduleFormat: provider.ddcModuleFormat, - canaryFeatures: provider.canaryFeatures, - ), - ); - fakeClient = await context.connectFakeClient(); - }); - - tearDown(() async { - await context.tearDown(); - }); - - test('can hot reload', () async { - final client = context.debugConnection.vmService; - - await makeEditAndRecompile(); - final vm = await client.getVM(); - final isolate = await client.getIsolate(vm.isolates!.first.id!); - final report = await fakeClient.reloadSources(isolate.id!); - expect(report.success, true); - - await callEvaluateAndWaitForLog(newString); - }); - - test('can hot reload with no changes, hot reload with changes, and ' - 'hot reload again with no changes', () async { - final client = context.debugConnection.vmService; - - // Empty hot reload. - await recompile(); - final vm = await client.getVM(); - final isolate = await client.getIsolate(vm.isolates!.first.id!); - var report = await fakeClient.reloadSources(isolate.id!); - expect(report.success, true); - - await callEvaluateAndWaitForLog(originalString); - - // Hot reload. - await makeEditAndRecompile(); - report = await fakeClient.reloadSources(isolate.id!); - expect(report.success, true); - - await callEvaluateAndWaitForLog(newString); - - // Empty hot reload. - await recompile(); - report = await fakeClient.reloadSources(isolate.id!); - expect(report.success, true); - - await callEvaluateAndWaitForLog(newString); - }); - }, timeout: const Timeout.factor(2)); -} diff --git a/dwds/test/integration/hot_restart_amd_test.dart b/dwds/test/integration/hot_restart_amd_test.dart deleted file mode 100644 index 8e1bb8320f..0000000000 --- a/dwds/test/integration/hot_restart_amd_test.dart +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@TestOn('vm') -@Tags(['daily']) -@Timeout(Duration(minutes: 2)) -library; - -import 'package:dwds/expression_compiler.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; - -import 'common/hot_restart_common.dart'; -import 'fixtures/context.dart'; - -void main() { - // Enable verbose logging for debugging. - const debug = false; - final canaryFeatures = false; - final moduleFormat = ModuleFormat.amd; - final compilationMode = CompilationMode.buildDaemon; - - final provider = TestSdkConfigurationProvider( - verbose: debug, - canaryFeatures: canaryFeatures, - ddcModuleFormat: moduleFormat, - ); - - runTests( - provider: provider, - moduleFormat: moduleFormat, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); -} diff --git a/dwds/test/integration/hot_restart_breakpoints_common.dart b/dwds/test/integration/hot_restart_breakpoints_common.dart deleted file mode 100644 index e9991c5497..0000000000 --- a/dwds/test/integration/hot_restart_breakpoints_common.dart +++ /dev/null @@ -1,435 +0,0 @@ -// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:async'; - -import 'package:dwds/expression_compiler.dart'; -import 'package:dwds_test_common/logging.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; -import 'package:vm_service/vm_service.dart'; -import 'package:vm_service_interface/vm_service_interface.dart'; -import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'; - -import 'fixtures/context.dart'; -import 'fixtures/project.dart'; -import 'fixtures/utilities.dart'; - -void main() { - // Enable verbose logging for debugging. - const debug = false; - final provider = TestSdkConfigurationProvider( - verbose: debug, - canaryFeatures: true, - ddcModuleFormat: ModuleFormat.ddc, - ); - - tearDownAll(provider.dispose); - - group('Frontend Server', () { - runTests( - provider: provider, - compilationMode: CompilationMode.frontendServer, - ); - }); - - group('Build Daemon', () { - runTests(provider: provider, compilationMode: CompilationMode.buildDaemon); - }); -} - -void runTests({ - required TestSdkConfigurationProvider provider, - required CompilationMode compilationMode, -}) { - final project = TestProject.testHotRestartBreakpoints; - final context = TestContext(project, provider); - final mainFile = project.dartEntryFileName; - final callLogMarker = 'callLog'; - - Future makeEditsAndRecompile(List edits) async { - await context.makeEdits(edits); - if (compilationMode == CompilationMode.frontendServer) { - await context.recompile(fullRestart: true); - } else { - await context.waitForSuccessfulBuild(); - } - } - - group('when pause_isolates_on_start is true', () { - late VmService client; - late VmServiceInterface service; - late Stream stream; - // Fetch the log statements that are sent to console. - final consoleLogs = []; - StreamSubscription? consoleSubscription; - - setUp(() async { - setCurrentLogWriter(debug: provider.verbose); - await context.setUp( - testSettings: TestSettings( - enableExpressionEvaluation: true, - compilationMode: compilationMode, - moduleFormat: provider.ddcModuleFormat, - canaryFeatures: provider.canaryFeatures, - ), - ); - client = await context.connectFakeClient(); - service = context.service; - await client.setFlag('pause_isolates_on_start', 'true'); - await client.streamListen(EventStreams.kIsolate); - await client.streamListen(EventStreams.kDebug); - stream = client.onDebugEvent; - consoleSubscription = context.webkitDebugger.onConsoleAPICalled.listen( - (e) => consoleLogs.add(e.args.first.value as String), - ); - }); - - tearDown(() async { - await consoleSubscription?.cancel(); - consoleLogs.clear(); - await context.tearDown(); - }); - - Future addBreakpoint({ - required String file, - required String breakpointMarker, - }) async { - final vm = await client.getVM(); - final isolateId = vm.isolates!.first.id!; - final scriptList = await client.getScripts(isolateId); - final scriptRef = scriptList.scripts!.firstWhere( - (script) => script.uri!.contains(file), - ); - final bpLine = await context.findBreakpointLine( - breakpointMarker, - isolateId, - scriptRef, - ); - final breakpointAdded = expectLater( - stream, - emits(_hasKind(EventKind.kBreakpointAdded)), - ); - final breakpoint = await client.addBreakpointWithScriptUri( - isolateId, - scriptRef.uri!, - bpLine, - ); - await breakpointAdded; - return breakpoint; - } - - Future resume() async { - final vm = await client.getVM(); - final isolate = await client.getIsolate(vm.isolates!.first.id!); - await client.resume(isolate.id!); - } - - // Resume the program, and check that at some point it will execute code - // that will print `expectedString` to the console. - Future resumeAndWaitForLog(String expectedString) async { - final completer = Completer(); - final subscription = context.webkitDebugger.onConsoleAPICalled.listen(( - e, - ) { - if (e.args.first.value == expectedString) { - completer.complete(); - } - }); - await resume(); - await completer.future.timeout( - const Duration(minutes: 1), - onTimeout: () { - throw TimeoutException( - "Failed to find log: '$expectedString' in console.", - ); - }, - ); - await subscription.cancel(); - } - - Future hotRestartAndHandlePausePost( - List<({String file, String breakpointMarker, bool exists})> breakpoints, - ) async { - final isolateEvents = expectLater( - client.onIsolateEvent, - emitsInOrder([ - _hasKind(EventKind.kIsolateExit), - _hasKind(EventKind.kIsolateStart), - _hasKind(EventKind.kIsolateRunnable), - ]), - ); - final breakpointEvents = expectLater( - stream, - emitsInOrder([ - for (final (:exists, breakpointMarker: _, file: _) - in breakpoints) ...[ - if (exists) _hasKind(EventKind.kBreakpointRemoved), - ], - _hasKind(EventKind.kResume), - _hasKind(EventKind.kPausePostRequest), - for (final _ in breakpoints) ...[ - _hasKind(EventKind.kBreakpointAdded), - ], - ]), - ); - - final waitForPausePost = expectLater( - stream, - emitsThrough(_hasKind(EventKind.kPausePostRequest)), - ); - - final hotRestart = context.getRegisteredServiceExtension('hotRestart'); - expect( - await client.callServiceExtension(hotRestart!), - const TypeMatcher(), - ); - - await isolateEvents; - - // DWDS defers running main after a hot restart until the client (e.g. - // DAP) resumes. Client should listen for this event, remove breakpoints - // (we don't remove them here as DWDS already removes them), and - // reregister breakpoints (which will be registered in the new files), and - // resume. - await waitForPausePost; - // Verify DWDS has already removed the breakpoints at this point. - final vm = await client.getVM(); - final isolate = await service.getIsolate(vm.isolates!.first.id!); - expect(isolate.breakpoints, isEmpty); - for (final (exists: _, :breakpointMarker, :file) in breakpoints) { - await addBreakpoint(file: file, breakpointMarker: breakpointMarker); - } - await resume(); - await breakpointEvents; - } - - Future waitForBreakpoint() => - stream.firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); - - test('empty hot restart keeps breakpoints', () async { - final genString = 'main gen0'; - - await addBreakpoint(file: mainFile, breakpointMarker: callLogMarker); - - final breakpointFuture = waitForBreakpoint(); - - if (compilationMode == CompilationMode.frontendServer) { - await context.recompile(fullRestart: false); - } - - await hotRestartAndHandlePausePost([ - (exists: true, file: mainFile, breakpointMarker: callLogMarker), - ]); - - // Should break at `callLog`. - await breakpointFuture; - await resumeAndWaitForLog(genString); - }); - - test('after edit and hot restart, breakpoint is in new file', () async { - final oldLog = 'main gen0'; - final newLog = 'main gen1'; - - await addBreakpoint(file: mainFile, breakpointMarker: callLogMarker); - - await makeEditsAndRecompile([ - (file: mainFile, originalString: oldLog, newString: newLog), - ]); - - final breakpointFuture = waitForBreakpoint(); - - await hotRestartAndHandlePausePost([ - (exists: true, file: mainFile, breakpointMarker: callLogMarker), - ]); - - // Should break at `callLog`. - await breakpointFuture; - expect(consoleLogs.contains(newLog), false); - await resumeAndWaitForLog(newLog); - }); - - test('after adding line, hot restart, removing line, and hot restart, ' - 'breakpoint is correct across both hot restarts', () async { - final genLog = 'main gen0'; - - await addBreakpoint(file: mainFile, breakpointMarker: callLogMarker); - - // Add an extra log before the existing log. - final extraLog = 'hot reload'; - final oldString = "log('"; - final newString = "log('$extraLog');\n$oldString"; - await makeEditsAndRecompile([ - (file: mainFile, originalString: oldString, newString: newString), - ]); - - var breakpointFuture = waitForBreakpoint(); - - await hotRestartAndHandlePausePost([ - (exists: true, file: mainFile, breakpointMarker: callLogMarker), - ]); - - // Should break at `callLog`. - await breakpointFuture; - expect(consoleLogs.contains(extraLog), true); - expect(consoleLogs.contains(genLog), false); - await resumeAndWaitForLog(genLog); - - consoleLogs.clear(); - - // Remove the line we just added. - await makeEditsAndRecompile([ - (file: mainFile, originalString: newString, newString: oldString), - ]); - - breakpointFuture = waitForBreakpoint(); - - await hotRestartAndHandlePausePost([ - (exists: true, file: mainFile, breakpointMarker: callLogMarker), - ]); - - // Should break at `callLog`. - await breakpointFuture; - expect(consoleLogs.contains(extraLog), false); - expect(consoleLogs.contains(genLog), false); - await resumeAndWaitForLog(genLog); - }); - - test( - 'after adding file and putting breakpoint in it, breakpoint is correctly ' - 'registered', - () async { - final genLog = 'main gen0'; - - await addBreakpoint(file: mainFile, breakpointMarker: callLogMarker); - - // Add a library file, import it, and then refer to it in the log. - final libFile = 'library.dart'; - final libGenLog = 'library gen0'; - final libValueMarker = 'libValue'; - context.addLibraryFile( - libFileName: libFile, - contents: - '''String get libraryValue { - return '$libGenLog'; // Breakpoint: $libValueMarker - }''', - ); - final oldImports = "import 'dart:js_interop';"; - final newImports = - '$oldImports\n' - "import 'package:_test_hot_restart_breakpoints/library.dart';"; - final edits = [ - (file: mainFile, originalString: oldImports, newString: newImports), - ]; - final oldLog = "log('$genLog');"; - final newLog = "log('\$libraryValue');"; - edits.add((file: mainFile, originalString: oldLog, newString: newLog)); - - // Include library file in edits to ensure it's added to - // reloaded_sources.json - edits.add(( - file: libFile, - originalString: 'String get libraryValue', - newString: 'String get libraryValue', - )); - - await makeEditsAndRecompile(edits); - - var breakpointFuture = waitForBreakpoint(); - - await hotRestartAndHandlePausePost([ - (exists: true, file: mainFile, breakpointMarker: callLogMarker), - (exists: false, file: libFile, breakpointMarker: libValueMarker), - ]); - - // Should break at `callLog`. - await breakpointFuture; - expect(consoleLogs.contains(libGenLog), false); - - breakpointFuture = waitForBreakpoint(); - - await resume(); - // Should break at `libValue`. - await breakpointFuture; - expect(consoleLogs.contains(libGenLog), false); - await resumeAndWaitForLog(libGenLog); - }, - ); - - // Test that we wait for all scripts to be parsed first before computing - // location metadata. - test('after adding many files and putting breakpoint in the last one,' - 'breakpoint is correctly registered', () async { - final genLog = 'main gen0'; - - await addBreakpoint(file: mainFile, breakpointMarker: callLogMarker); - - // Add library files, import them, but only refer to the last one in main. - final numFiles = 50; - final edits = []; - for (var i = 1; i <= numFiles; i++) { - final libFile = 'library$i.dart'; - context.addLibraryFile( - libFileName: libFile, - contents: - '''String get libraryValue$i { - return 'library$i gen1'; // Breakpoint: libValue$i - }''', - ); - final oldImports = "import 'dart:js_interop';"; - final newImports = - '$oldImports\n' - "import 'package:_test_hot_restart_breakpoints/$libFile';"; - edits.add(( - file: mainFile, - originalString: oldImports, - newString: newImports, - )); - } - final oldLog = "log('$genLog');"; - final newLog = "log('\$libraryValue$numFiles');"; - edits.add((file: mainFile, originalString: oldLog, newString: newLog)); - - // Include library files in edits to ensure they are added to - // reloaded_sources.json - for (var i = 1; i <= numFiles; i++) { - edits.add(( - file: 'library$i.dart', - originalString: 'String get libraryValue$i', - newString: 'String get libraryValue$i', - )); - } - - await makeEditsAndRecompile(edits); - - var breakpointFuture = waitForBreakpoint(); - - await hotRestartAndHandlePausePost([ - (exists: true, file: mainFile, breakpointMarker: callLogMarker), - ( - exists: false, - file: 'library$numFiles.dart', - breakpointMarker: 'libValue$numFiles', - ), - ]); - - final newGenLog = 'library$numFiles gen1'; - - // Should break at `callLog`. - await breakpointFuture; - expect(consoleLogs.contains(newGenLog), false); - - breakpointFuture = waitForBreakpoint(); - - await resume(); - // Should break at the breakpoint in the last file. - await breakpointFuture; - expect(consoleLogs.contains(newGenLog), false); - await resumeAndWaitForLog(newGenLog); - }); - }); -} - -TypeMatcher _hasKind(String kind) => - isA().having((e) => e.kind, 'kind', kind); diff --git a/dwds/test/integration/hot_restart_correctness_amd_test.dart b/dwds/test/integration/hot_restart_correctness_amd_test.dart deleted file mode 100644 index e034ff3afb..0000000000 --- a/dwds/test/integration/hot_restart_correctness_amd_test.dart +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@TestOn('vm') -@Tags(['daily']) -@Timeout(Duration(minutes: 2)) -library; - -import 'package:dwds/expression_compiler.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; - -import 'common/hot_restart_correctness_common.dart'; -import 'fixtures/context.dart'; - -void main() { - // Enable verbose logging for debugging. - const debug = false; - final canaryFeatures = false; - final moduleFormat = ModuleFormat.amd; - final compilationMode = CompilationMode.buildDaemon; - - final provider = TestSdkConfigurationProvider( - verbose: debug, - canaryFeatures: canaryFeatures, - ddcModuleFormat: moduleFormat, - ); - - runTests( - provider: provider, - moduleFormat: moduleFormat, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); -} diff --git a/dwds/test/integration/inspector_test.dart b/dwds/test/integration/inspector_test.dart deleted file mode 100644 index 0a305b9421..0000000000 --- a/dwds/test/integration/inspector_test.dart +++ /dev/null @@ -1,330 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@TestOn('vm') -@Timeout(Duration(minutes: 2)) -library; - -import 'package:dwds/dwds.dart'; -import 'package:dwds/src/config/tool_configuration.dart'; -import 'package:dwds/src/debugging/chrome_inspector.dart'; -import 'package:dwds/src/utilities/conversions.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; -import 'package:vm_service/vm_service.dart'; -import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'; - -import 'fixtures/context.dart'; -import 'fixtures/project.dart'; - -void main() { - final provider = TestSdkConfigurationProvider(); - tearDownAll(provider.dispose); - - final context = TestContext(TestProject.testScopes, provider); - - late ChromeAppInspector inspector; - - setUpAll(() async { - await context.setUp(); - final service = context.service; - inspector = service.inspector; - }); - - tearDownAll(() async { - await context.tearDown(); - }); - - final url = 'org-dartlang-app:///example/scopes/main.dart'; - - /// A convenient way to get a library variable without boilerplate. - String libraryVariableExpression(String variable) => - '${globalToolConfiguration.loadStrategy.loadModuleSnippet}("dart_sdk").dart.getModuleLibraries("example/scopes/main")["$url"]["$variable"];'; - - Future libraryPublicFinal() => - inspector.jsEvaluate(libraryVariableExpression('libraryPublicFinal')); - - Future libraryPrivate() => - inspector.jsEvaluate(libraryVariableExpression('_libraryPrivate')); - - group('jsEvaluate', () { - test('no error', () async { - await expectLater( - inspector.jsEvaluate('42'), - completion(isA().having((e) => e.value, 'value', 42)), - ); - }); - - test('syntax error', () async { - await expectLater( - () => inspector.jsEvaluate('<'), - throwsA( - isA() - .having((e) => e.text, 'text', 'Uncaught') - .having( - (e) => e.exception?.description, - 'description', - contains('SyntaxError'), - ) - .having((e) => e.stackTrace, 'stackTrace', isNull) - .having((e) => e.evalContents, 'evalContents', '<'), - ), - ); - }); - - test('evaluation error', () async { - await expectLater( - () => inspector.jsEvaluate(''' - (function() { - let foo = (function() { - console.log(boo); - }); - foo(); - })(); - '''), - throwsA( - isA() - .having((e) => e.text, 'text', 'Uncaught') - .having( - (e) => e.exception?.description, - 'description', - contains('ReferenceError'), - ) - .having( - (e) => e.stackTrace?.printFrames()[0], - 'stackTrace', - contains('foo()'), - ) - .having((e) => e.evalContents, 'evalContents', contains('foo')), - ), - ); - }); - }); - - group('mapExceptionStackTrace', () { - test('multi-line exception with a stack trace', () async { - final result = await inspector.mapExceptionStackTrace( - jsMultiLineExceptionWithStackTrace, - ); - expect(result, equals(formattedMultiLineExceptionWithStackTrace)); - }); - - test('multi-line exception without a stack trace', () async { - final result = await inspector.mapExceptionStackTrace( - jsMultiLineExceptionNoStackTrace, - ); - expect(result, equals(formattedMultiLineExceptionNoStackTrace)); - }); - - test('single-line exception with a stack trace', () async { - final result = await inspector.mapExceptionStackTrace( - jsSingleLineExceptionWithStackTrace, - ); - expect(result, equals(formattedSingleLineExceptionWithStackTrace)); - }); - }); - - test('send toString', () async { - final remoteObject = await libraryPublicFinal(); - final toString = await inspector.invoke( - remoteObject.objectId!, - 'toString', - [], - ); - expect(toString.value, 'A test class with message world'); - }); - - group('getObject', () { - test('for class with generic', () async { - final remoteObject = await libraryPublicFinal(); - final instance = - await inspector.getObject(remoteObject.objectId!) as Instance; - final classRef = instance.classRef!; - final clazz = await inspector.getObject(classRef.id!) as Class; - expect(clazz.name, 'MyTestClass'); - }); - }); - - group('loadField', () { - test('for string', () async { - final remoteObject = await libraryPublicFinal(); - final message = await inspector.loadField(remoteObject, 'message'); - expect(message.value, 'world'); - }); - - test('for num', () async { - final remoteObject = await libraryPublicFinal(); - final unchangedCount = await inspector.loadField( - remoteObject, - 'unchangedCount', - ); - expect(unchangedCount.value, 42); - }); - }); - - test('properties', () async { - final remoteObject = await libraryPublicFinal(); - final properties = await inspector.getProperties(remoteObject.objectId!); - final names = properties - .map((p) => p.name) - .where((x) => x != '__proto__') - .toList(); - final expected = [ - '_privateField', - 'abstractField', - 'closure', - 'count', - 'message', - 'myselfField', - 'notFinal', - 'tornOff', - 'unchangedCount', - ]; - names.sort(); - expect(names, expected); - }); - - group('invoke', () { - // We test these here because the test fixture has more complicated members - // to exercise. - - LibraryRef? bootstrapLibrary; - late RemoteObject instance; - late String objectId; - - setUp(() async { - bootstrapLibrary = inspector.isolate.rootLib; - instance = await libraryPublicFinal(); - objectId = instance.objectId!; - }); - - test('expect rootLib to be the main.dart file', () { - expect(inspector.isolate.rootLib?.uri, equals(url)); - }); - - test('invoke top-level private', () async { - final remote = await inspector.invoke( - bootstrapLibrary!.id!, - '_libraryPrivateFunction', - [dartIdFor(2), dartIdFor(3)], - ); - expect( - remote, - const TypeMatcher().having( - (instance) => instance.value, - 'result', - 5, - ), - ); - }); - - test('invoke instance private', () async { - final remote = await inspector.invoke(objectId, 'privateMethod', [ - dartIdFor('some string'), - ]); - expect( - remote, - const TypeMatcher().having( - (instance) => instance.value, - 'result', - 'some string : a private field', - ), - ); - }); - - test('invoke instance method with object parameter', () async { - final remote = await inspector.invoke(objectId, 'equals', [objectId]); - expect( - remote, - const TypeMatcher().having( - (instance) => instance.value, - 'result', - true, - ), - ); - }); - - test('invoke instance method with object parameter 2', () async { - final libraryPrivateList = await libraryPrivate(); - final remote = await inspector.invoke(objectId, 'equals', [ - libraryPrivateList.objectId, - ]); - expect( - remote, - const TypeMatcher().having( - (instance) => instance.value, - 'result', - false, - ), - ); - }); - - test('invoke closure stored in an instance field', () async { - final remote = await inspector.invoke(objectId, 'closure', []); - expect( - remote, - const TypeMatcher().having( - (instance) => instance.value, - 'result', - null, - ), - ); - }); - - test('invoke a torn-off method', () async { - final toString = await inspector.loadField(instance, 'tornOff'); - final result = await inspector.invoke(toString.objectId!, 'call', []); - expect( - result, - const TypeMatcher().having( - (instance) => instance.value, - 'toString', - 'A test class with message world', - ), - ); - }); - }); -} - -final jsMultiLineExceptionWithStackTrace = ''' -Error: Assertion failed: org-dartlang-app:///example/scopes/main.dart:4:11 -false -"THIS IS THE ASSERT MESSAGE" - at Object.assertFailed (org-dartlang-app:///example/scopes/main.dart.js:5297:15) -'''; - -final formattedMultiLineExceptionWithStackTrace = ''' -Error: Assertion failed: org-dartlang-app:///example/scopes/main.dart:4:11 -false -"THIS IS THE ASSERT MESSAGE" -org-dartlang-app:///example/scopes/main.dart.js 5297:15 assertFailed -'''; - -final jsMultiLineExceptionNoStackTrace = ''' -Error: Assertion failed: org-dartlang-app:///example/scopes/main.dart:4:11 -false -"THIS IS THE ASSERT MESSAGE" -'''; - -final formattedMultiLineExceptionNoStackTrace = ''' -Error: Assertion failed: org-dartlang-app:///example/scopes/main.dart:4:11 -false -"THIS IS THE ASSERT MESSAGE" -'''; - -final jsSingleLineExceptionWithStackTrace = ''' -Error: Unexpected null value. - at Object.throw_ [as throw] (http://localhost:63236/dart_sdk.js:5379:11) - at Object.nullCheck (http://localhost:63236/dart_sdk.js:5696:30) - at main (http://localhost:63236/packages/tmpapp/main.dart.lib.js:374:10) - at http://localhost:63236/web_entrypoint.dart.lib.js:41:33 -'''; - -final formattedSingleLineExceptionWithStackTrace = ''' -Error: Unexpected null value. -http://localhost:63236/dart_sdk.js 5379:11 throw_ -http://localhost:63236/dart_sdk.js 5696:30 nullCheck -http://localhost:63236/packages/tmpapp/main.dart.lib.js 374:10 main -http://localhost:63236/web_entrypoint.dart.lib.js 41:33 -'''; diff --git a/dwds/test/integration/instances/class_inspection_amd_test.dart b/dwds/test/integration/instances/class_inspection_amd_test.dart deleted file mode 100644 index dd9102c807..0000000000 --- a/dwds/test/integration/instances/class_inspection_amd_test.dart +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@Tags(['daily']) -@TestOn('vm') -@Timeout(Duration(minutes: 2)) -library; - -import 'package:dwds/expression_compiler.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; - -import '../fixtures/context.dart'; -import 'common/class_inspection_common.dart'; - -void main() { - // Enable verbose logging for debugging. - const debug = false; - - group('canary: false | Build Daemon |', () { - final canaryFeatures = false; - final compilationMode = CompilationMode.buildDaemon; - final provider = TestSdkConfigurationProvider( - verbose: debug, - canaryFeatures: canaryFeatures, - ddcModuleFormat: ModuleFormat.amd, - ); - tearDownAll(provider.dispose); - - runTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); - - group('canary: true | Build Daemon |', () { - final canaryFeatures = true; - final compilationMode = CompilationMode.buildDaemon; - final provider = TestSdkConfigurationProvider( - verbose: debug, - canaryFeatures: canaryFeatures, - ddcModuleFormat: ModuleFormat.amd, - ); - tearDownAll(provider.dispose); - - runTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); - - group('canary: false | Frontend Server |', () { - final canaryFeatures = false; - final compilationMode = CompilationMode.frontendServer; - final provider = TestSdkConfigurationProvider( - verbose: debug, - canaryFeatures: canaryFeatures, - ddcModuleFormat: ModuleFormat.amd, - ); - tearDownAll(provider.dispose); - - runTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); - - group('canary: true | Frontend Server |', () { - final canaryFeatures = true; - final compilationMode = CompilationMode.frontendServer; - final provider = TestSdkConfigurationProvider( - verbose: debug, - canaryFeatures: canaryFeatures, - ddcModuleFormat: ModuleFormat.amd, - ); - tearDownAll(provider.dispose); - - runTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); -} diff --git a/dwds/test/integration/instances/class_inspection_ddc_library_bundle_test.dart b/dwds/test/integration/instances/class_inspection_ddc_library_bundle_test.dart deleted file mode 100644 index 77a97d66cd..0000000000 --- a/dwds/test/integration/instances/class_inspection_ddc_library_bundle_test.dart +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@Tags(['daily']) -@TestOn('vm') -@Timeout(Duration(minutes: 2)) -library; - -import 'package:dwds/expression_compiler.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; - -import '../fixtures/context.dart'; -import 'common/class_inspection_common.dart'; - -void main() { - // Enable verbose logging for debugging. - const debug = false; - - group('canary: true | Frontend Server |', () { - final canaryFeatures = true; - final compilationMode = CompilationMode.frontendServer; - final provider = TestSdkConfigurationProvider( - verbose: debug, - canaryFeatures: canaryFeatures, - ddcModuleFormat: ModuleFormat.ddc, - ); - tearDownAll(provider.dispose); - - runTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); - - group('canary: true | Build Daemon |', () { - final canaryFeatures = true; - final compilationMode = CompilationMode.buildDaemon; - final provider = TestSdkConfigurationProvider( - verbose: debug, - canaryFeatures: canaryFeatures, - ddcModuleFormat: ModuleFormat.ddc, - ); - tearDownAll(provider.dispose); - - runTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); -} diff --git a/dwds/test/integration/instances/common/class_inspection_common.dart b/dwds/test/integration/instances/common/class_inspection_common.dart deleted file mode 100644 index da77bcc776..0000000000 --- a/dwds/test/integration/instances/common/class_inspection_common.dart +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@Tags(['daily']) -@TestOn('vm') -@Timeout(Duration(minutes: 2)) -library; - -import 'package:dwds_test_common/logging.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; -import 'package:vm_service/vm_service.dart'; - -import '../../fixtures/context.dart'; -import '../../fixtures/project.dart'; -import '../../fixtures/utilities.dart'; -import '../common/test_inspector.dart'; - -void runTests({ - required TestSdkConfigurationProvider provider, - required CompilationMode compilationMode, - required bool canaryFeatures, -}) { - final context = TestContext(TestProject.testExperiment, provider); - final testInspector = TestInspector(context); - - late VmService service; - late Stream stream; - late String isolateId; - late ScriptRef mainScript; - - Future onBreakPoint( - String breakPointId, - Future Function(Event) body, - ) => testInspector.onBreakPoint( - stream, - isolateId, - mainScript, - breakPointId, - body, - ); - - Future getObject(String instanceId) => - service.getObject(isolateId, instanceId); - - group('$compilationMode |', () { - setUpAll(() async { - setCurrentLogWriter(debug: provider.verbose); - await context.setUp( - testSettings: TestSettings( - compilationMode: compilationMode, - enableExpressionEvaluation: true, - verboseCompiler: provider.verbose, - experiments: ['dot-shorthands'], - canaryFeatures: canaryFeatures, - moduleFormat: provider.ddcModuleFormat, - ), - ); - service = context.debugConnection.vmService; - - final vm = await service.getVM(); - isolateId = vm.isolates!.first.id!; - final scripts = await service.getScripts(isolateId); - - await service.streamListen('Debug'); - stream = service.onEvent('Debug'); - - mainScript = scripts.scripts!.firstWhere( - (each) => each.uri!.contains('main.dart'), - ); - }); - - tearDownAll(() async { - await context.tearDown(); - }); - - setUp(() => setCurrentLogWriter(debug: provider.verbose)); - tearDown(() => service.resume(isolateId)); - - group('calling getObject for an existent class', () { - test('returns the correct class representation', () async { - await onBreakPoint('testClass1Case1', (Event event) async { - // classes|dart:core|Object_Diagnosticable - final result = await getObject( - 'classes|org-dartlang-app:///web/main.dart|GreeterClass', - ); - final clazz = result as Class?; - expect(clazz!.name, equals('GreeterClass')); - expect( - clazz.fields!.map((field) => field.name), - unorderedEquals(['greeteeName', 'useFrench']), - ); - expect( - clazz.functions!.map((fn) => fn.name), - containsAll(['sayHello', 'greetInEnglish', 'greetInFrench']), - ); - }); - }); - }); - - group('calling getObject for a non-existent class', () { - // TODO(https://github.com/dart-lang/webdev/issues/2297): Ideally we - // should throw an error in this case for the client to catch instead - // of returning an empty class. - test('returns an empty class representation', () async { - await onBreakPoint('testClass1Case1', (Event event) async { - final result = await getObject( - 'classes|dart:core|Object_Diagnosticable', - ); - final clazz = result as Class?; - expect(clazz!.name, equals('Object_Diagnosticable')); - expect(clazz.fields, isEmpty); - expect(clazz.functions, isEmpty); - }); - }); - }); - }); -} diff --git a/dwds/test/integration/instances/common/dot_shorthands_common.dart b/dwds/test/integration/instances/common/dot_shorthands_common.dart deleted file mode 100644 index f37bd6f7f8..0000000000 --- a/dwds/test/integration/instances/common/dot_shorthands_common.dart +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'package:dwds_test_common/logging.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:path/path.dart' show basename; -import 'package:test/test.dart'; -import 'package:vm_service/vm_service.dart'; - -import '../../fixtures/context.dart'; -import '../../fixtures/project.dart'; -import '../../fixtures/utilities.dart'; -import 'test_inspector.dart'; - -void runTests({ - required TestSdkConfigurationProvider provider, - required CompilationMode compilationMode, - required bool canaryFeatures, -}) { - final context = TestContext(TestProject.testDotShorthands, provider); - final testInspector = TestInspector(context); - - late VmService service; - late Stream stream; - late String isolateId; - late ScriptRef mainScript; - - Future onBreakpoint( - String breakPointId, - Future Function(Event) body, - ) => testInspector.onBreakPoint( - stream, - isolateId, - mainScript, - breakPointId, - body, - ); - - Future getInstanceRef(int frame, String expression) => - testInspector.getInstanceRef(isolateId, frame, expression); - - group('$compilationMode | dot shorthands:', () { - setUp(() async { - setCurrentLogWriter(debug: provider.verbose); - await context.setUp( - testSettings: TestSettings( - compilationMode: compilationMode, - enableExpressionEvaluation: true, - verboseCompiler: provider.verbose, - experiments: ['dot-shorthands'], - canaryFeatures: canaryFeatures, - moduleFormat: provider.ddcModuleFormat, - ), - ); - service = context.debugConnection.vmService; - - final vm = await service.getVM(); - isolateId = vm.isolates!.first.id!; - final scripts = await service.getScripts(isolateId); - - await service.streamListen(EventStreams.kDebug); - stream = service.onDebugEvent; - - mainScript = scripts.scripts!.firstWhere( - (each) => each.uri!.contains('main.dart'), - ); - }); - - tearDown(() async { - await context.tearDown(); - }); - - test('expression evaluation', () async { - final bp = onBreakpoint('testDotShorthands', (Event event) async { - final frame = event.topFrame!.index!; - - var instanceRef = await getInstanceRef(frame, '(c = .two).value'); - expect(instanceRef.valueAsString, '2'); - - instanceRef = await getInstanceRef(frame, '(c = .three).value'); - expect(instanceRef.valueAsString, '3'); - - instanceRef = await getInstanceRef(frame, '(c = .four()).value'); - expect(instanceRef.valueAsString, '4'); - - await service.resume(isolateId); - }); - final isolate = await service.getIsolate(isolateId); - await service.evaluate( - isolateId, - isolate.rootLib!.id!, - 'testDotShorthands()', - ); - await bp; - }); - - test('single-stepping', () async { - final bp = onBreakpoint('testDotShorthands', (Event event) async { - final scriptBasename = basename(mainScript.uri!); - - const lineA = 9; - const lineB = 11; - const lineC = 12; - const lineD = 13; - const lineE = 20; - const lineF = 22; - const lineG = 24; - const lineH = 25; - - final expected = [ - '$scriptBasename:$lineE:3', // on 'c' - '$scriptBasename:$lineB:15', // on 'C' - '$scriptBasename:$lineA:10', // on 'v' of 'value' - '$scriptBasename:$lineA:16', // on ';' - '$scriptBasename:$lineB:20', // on '2' - '$scriptBasename:$lineF:3', // on 'c' - '$scriptBasename:$lineC:25', // on 'C' - '$scriptBasename:$lineA:10', // on 'v' of 'value' - '$scriptBasename:$lineA:16', // on ';' - '$scriptBasename:$lineC:27', // on '3' - '$scriptBasename:$lineG:3', // on 'c' - '$scriptBasename:$lineD:22', // on 'C' - '$scriptBasename:$lineA:10', // on 'v' of 'value' - '$scriptBasename:$lineA:16', // on ';' - '$scriptBasename:$lineD:24', // on '4' - '$scriptBasename:$lineH:3', // on 'p' of 'print' - ]; - - final stops = []; - await testInspector.runStepIntoThroughProgramRecordingStops( - isolateId, - stops, - expected.length, - ); - - expect(stops, expected); - - await service.resume(isolateId); - }); - final isolate = await service.getIsolate(isolateId); - await service.evaluate( - isolateId, - isolate.rootLib!.id!, - 'testDotShorthands()', - ); - await bp; - }); - }); -} diff --git a/dwds/test/integration/instances/common/instance_common.dart b/dwds/test/integration/instances/common/instance_common.dart deleted file mode 100644 index 492c49badf..0000000000 --- a/dwds/test/integration/instances/common/instance_common.dart +++ /dev/null @@ -1,513 +0,0 @@ -// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'package:dwds/expression_compiler.dart'; -import 'package:dwds/src/config/tool_configuration.dart'; -import 'package:dwds/src/debugging/chrome_inspector.dart'; -import 'package:dwds_test_common/logging.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; -import 'package:vm_service/vm_service.dart'; -import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'; - -import '../../fixtures/context.dart'; -import '../../fixtures/project.dart'; -import '../../fixtures/utilities.dart'; -import 'test_inspector.dart'; - -void runTypeSystemVerificationTests({ - required TestSdkConfigurationProvider provider, - required CompilationMode compilationMode, - required bool canaryFeatures, -}) { - final project = TestProject.testScopes; - - group('$compilationMode |', () { - final context = TestContext(project, provider); - late ChromeAppInspector inspector; - - setUpAll(() async { - setCurrentLogWriter(debug: provider.verbose); - await context.setUp( - testSettings: TestSettings( - compilationMode: compilationMode, - verboseCompiler: provider.verbose, - canaryFeatures: canaryFeatures, - ), - ); - final chromeProxyService = context.service; - inspector = chromeProxyService.inspector; - }); - - tearDownAll(() async { - await context.tearDown(); - }); - - final url = 'org-dartlang-app:///example/scopes/main.dart'; - - String libraryName(CompilationMode compilationMode) => - compilationMode == CompilationMode.frontendServer - ? 'example/scopes/main.dart' - : 'example/scopes/main'; - - String libraryVariableTypeExpression( - String variable, - CompilationMode compilationMode, - ) => - ''' - (function() { - var dart = ${globalToolConfiguration.loadStrategy.loadModuleSnippet}('dart_sdk').dart; - var libraryName = '${libraryName(compilationMode)}'; - var library = dart.getModuleLibraries(libraryName)['$url']; - var x = library['$variable']; - return dart.getReifiedType(x); - })(); - '''; - - group('compiler', () { - setUp(() => setCurrentLogWriter(debug: provider.verbose)); - - test('uses correct type system', () async { - final remoteObject = await inspector.jsEvaluate( - libraryVariableTypeExpression('libraryPublicFinal', compilationMode), - ); - expect(remoteObject.json['className'], 'dart_rti.Rti.new'); - }); - }); - }); -} - -void runTests({ - required TestSdkConfigurationProvider provider, - required CompilationMode compilationMode, - required bool canaryFeatures, -}) { - final project = TestProject.testScopes; - final context = TestContext(project, provider); - - late ChromeAppInspector inspector; - - group('$compilationMode |', () { - setUpAll(() async { - setCurrentLogWriter(debug: provider.verbose); - await context.setUp( - testSettings: TestSettings( - compilationMode: compilationMode, - verboseCompiler: provider.verbose, - canaryFeatures: canaryFeatures, - moduleFormat: provider.ddcModuleFormat, - ), - ); - final chromeProxyService = context.service; - inspector = chromeProxyService.inspector; - }); - - tearDownAll(() async { - await context.tearDown(); - }); - - final libraryUri = 'org-dartlang-app:///example/scopes/main.dart'; - - String newInterceptorsExpression(String type) => - 'new (require("dart_sdk")._interceptors.$type).new()'; - - final newDartError = 'new (require("dart_sdk").dart).DartError'; - - /// A reference to the the variable `libraryPublicFinal`, an instance of - /// `MyTestClass`. - Future getLibraryPublicFinalRef() => - inspector.invoke(libraryUri, 'getLibraryPublicFinal'); - - /// A reference to the the variable `libraryPublic`, a List of Strings. - Future getLibraryPublicRef() => - inspector.invoke(libraryUri, 'getLibraryPublic'); - - /// A reference to the variable `map`. - Future getMapRef() => inspector.invoke(libraryUri, 'getMap'); - - /// A reference to the variable `identityMap`. - Future getIdentityMapRef() => - inspector.invoke(libraryUri, 'getIdentityMap'); - - /// A reference to the variable `stream`. - Future getStreamRef() => - inspector.invoke(libraryUri, 'getStream'); - - final unsupportedTestMsg = - 'This test is not supported with the DDC Library ' - "Bundle Format because the dartDevEmbedder doesn't let you access " - 'compiled constructors at runtime.'; - - group('instanceRef', () { - setUp(() => setCurrentLogWriter(debug: provider.verbose)); - - test('for a null', () async { - final remoteObject = await getLibraryPublicFinalRef(); - final nullVariable = await inspector.loadField( - remoteObject, - 'notFinal', - ); - final ref = await inspector.instanceRefFor(nullVariable); - expect(ref!.valueAsString, 'null'); - expect(ref.kind, InstanceKind.kNull); - final classRef = ref.classRef!; - expect(classRef.name, 'Null'); - expect(classRef.id, 'classes|dart:core|Null'); - expect(inspector.isDisplayableObject(ref), isTrue); - }); - - test('for a double', () async { - final remoteObject = await getLibraryPublicFinalRef(); - final count = await inspector.loadField(remoteObject, 'count'); - final ref = await inspector.instanceRefFor(count); - // 'count' is incremented by a periodic timer in the application, so we - // can't expect it to be exactly 0. - expect(double.tryParse(ref!.valueAsString!), greaterThanOrEqualTo(0)); - expect(ref.kind, InstanceKind.kDouble); - final classRef = ref.classRef!; - expect(classRef.name, 'Double'); - expect(classRef.id, 'classes|dart:core|Double'); - expect(inspector.isDisplayableObject(ref), isTrue); - }); - - test('for an object', () async { - final remoteObject = await getLibraryPublicFinalRef(); - final count = await inspector.loadField(remoteObject, 'myselfField'); - final ref = await inspector.instanceRefFor(count); - expect(ref!.kind, InstanceKind.kPlainInstance); - final classRef = ref.classRef!; - expect(classRef.name, 'MyTestClass'); - expect( - classRef.id, - 'classes|org-dartlang-app:///example/scopes/main.dart' - '|MyTestClass', - ); - expect(inspector.isDisplayableObject(ref), isTrue); - }); - - test('for a closure', () async { - final remoteObject = await getLibraryPublicFinalRef(); - final properties = await inspector.getProperties( - remoteObject.objectId!, - ); - final closure = properties.firstWhere( - (property) => property.name == 'closure', - ); - final ref = await inspector.instanceRefFor(closure.value!); - final functionName = ref!.closureFunction!.name; - // Older SDKs do not contain function names - if (functionName != 'Closure') { - expect(functionName, 'someFunction'); - } - expect(ref.kind, InstanceKind.kClosure); - expect(inspector.isDisplayableObject(ref), isTrue); - }); - - test('for a list', () async { - final remoteObject = await getLibraryPublicRef(); - final ref = await inspector.instanceRefFor(remoteObject); - expect(ref!.length, greaterThan(0)); - expect(ref.kind, InstanceKind.kList); - expect(ref.classRef!.name, matchListClassName('String')); - expect(inspector.isDisplayableObject(ref), isTrue); - }); - - test('for map', () async { - final remoteObject = await getMapRef(); - final ref = await inspector.instanceRefFor(remoteObject); - expect(ref!.length, 2); - expect(ref.kind, InstanceKind.kMap); - expect(ref.classRef!.name, 'LinkedMap'); - expect(inspector.isDisplayableObject(ref), isTrue); - }); - - test('for an IdentityMap', () async { - final remoteObject = await getIdentityMapRef(); - final ref = await inspector.instanceRefFor(remoteObject); - expect(ref!.length, 2); - expect(ref.kind, InstanceKind.kMap); - expect(ref.classRef!.name, 'IdentityMap'); - expect(inspector.isDisplayableObject(ref), isTrue); - }); - - // Regression test for https://github.com/dart-lang/webdev/issues/2446. - test('for a stream', () async { - final remoteObject = await getStreamRef(); - final ref = await inspector.instanceRefFor(remoteObject); - expect(ref!.kind, InstanceKind.kPlainInstance); - final classRef = ref.classRef!; - expect(classRef.name, '_ControllerStream'); - expect(classRef.id, 'classes|dart:async|_ControllerStream'); - expect(inspector.isDisplayableObject(ref), isTrue); - }); - - test( - 'for a Dart error', - () async { - final remoteObject = await inspector.jsEvaluate(newDartError); - final ref = await inspector.instanceRefFor(remoteObject); - expect(ref!.kind, InstanceKind.kPlainInstance); - expect(ref.classRef!.name, 'NativeError'); - expect(inspector.isDisplayableObject(ref), isFalse); - expect(inspector.isNativeJsError(ref), isTrue); - expect(inspector.isNativeJsObject(ref), isFalse); - }, - skip: - provider.ddcModuleFormat == ModuleFormat.ddc && - canaryFeatures == true - ? unsupportedTestMsg - : null, - ); - - test( - 'for a native JavaScript error', - () async { - final remoteObject = await inspector.jsEvaluate( - newInterceptorsExpression('NativeError'), - ); - final ref = await inspector.instanceRefFor(remoteObject); - expect(ref!.kind, InstanceKind.kPlainInstance); - expect(ref.classRef!.name, 'NativeError'); - expect(inspector.isDisplayableObject(ref), isFalse); - expect(inspector.isNativeJsError(ref), isTrue); - expect(inspector.isNativeJsObject(ref), isFalse); - }, - skip: - provider.ddcModuleFormat == ModuleFormat.ddc && - canaryFeatures == true - ? unsupportedTestMsg - : null, - ); - - test( - 'for a native JavaScript type error', - () async { - final remoteObject = await inspector.jsEvaluate( - newInterceptorsExpression('JSNoSuchMethodError'), - ); - final ref = await inspector.instanceRefFor(remoteObject); - expect(ref!.kind, InstanceKind.kPlainInstance); - expect(ref.classRef!.name, 'JSNoSuchMethodError'); - expect(inspector.isDisplayableObject(ref), isFalse); - expect(inspector.isNativeJsError(ref), isTrue); - expect(inspector.isNativeJsObject(ref), isFalse); - }, - skip: - provider.ddcModuleFormat == ModuleFormat.ddc && - canaryFeatures == true - ? unsupportedTestMsg - : null, - ); - - test( - 'for a native JavaScript object', - () async { - final remoteObject = await inspector.jsEvaluate( - newInterceptorsExpression('LegacyJavaScriptObject'), - ); - final ref = await inspector.instanceRefFor(remoteObject); - expect(ref!.kind, InstanceKind.kPlainInstance); - expect(ref.classRef!.name, 'LegacyJavaScriptObject'); - expect(inspector.isDisplayableObject(ref), isFalse); - expect(inspector.isNativeJsError(ref), isFalse); - expect(inspector.isNativeJsObject(ref), isTrue); - }, - skip: - provider.ddcModuleFormat == ModuleFormat.ddc && - canaryFeatures == true - ? unsupportedTestMsg - : null, - ); - }); - - group('instance', () { - setUp(() => setCurrentLogWriter(debug: provider.verbose)); - test('for an object', () async { - final remoteObject = await getLibraryPublicFinalRef(); - final instance = await inspector.instanceFor(remoteObject); - expect(instance!.kind, InstanceKind.kPlainInstance); - final classRef = instance.classRef!; - expect(classRef, isNotNull); - expect(classRef.name, 'MyTestClass'); - final boundFieldNames = instance.fields! - .map((boundField) => boundField.decl!.name) - .toList(); - expect(boundFieldNames, [ - '_privateField', - 'abstractField', - 'closure', - 'count', - 'message', - 'myselfField', - 'notFinal', - 'tornOff', - 'unchangedCount', - ]); - final fieldNames = instance.fields! - .map((boundField) => boundField.name) - .toList(); - expect(boundFieldNames, fieldNames); - for (final field in instance.fields!) { - expect(field.name, isNotNull); - expect(field.decl!.declaredType, isNotNull); - } - expect(inspector.isDisplayableObject(instance), isTrue); - }); - - test('for closure', () async { - final remoteObject = await getLibraryPublicFinalRef(); - final properties = await inspector.getProperties( - remoteObject.objectId!, - ); - final closure = properties.firstWhere( - (property) => property.name == 'closure', - ); - final instance = await inspector.instanceFor(closure.value!); - expect(instance!.kind, InstanceKind.kClosure); - expect(instance.classRef!.name, 'Closure'); - expect(inspector.isDisplayableObject(instance), isTrue); - }); - - test('for a nested object', () async { - final libraryRemoteObject = await getLibraryPublicFinalRef(); - final fieldRemoteObject = await inspector.loadField( - libraryRemoteObject, - 'myselfField', - ); - final instance = await inspector.instanceFor(fieldRemoteObject); - expect(instance!.kind, InstanceKind.kPlainInstance); - final classRef = instance.classRef!; - expect(classRef, isNotNull); - expect(classRef.name, 'MyTestClass'); - expect(inspector.isDisplayableObject(instance), isTrue); - }); - - test('for a list', () async { - final remote = await getLibraryPublicRef(); - final instance = await inspector.instanceFor(remote); - expect(instance!.kind, InstanceKind.kList); - final classRef = instance.classRef!; - expect(classRef, isNotNull); - expect(classRef.name, matchListClassName('String')); - final first = instance.elements![0] as InstanceRef; - expect(first.valueAsString, 'library'); - expect(inspector.isDisplayableObject(instance), isTrue); - }); - - test('for a map', () async { - final remote = await getMapRef(); - final instance = await inspector.instanceFor(remote); - expect(instance!.kind, InstanceKind.kMap); - final classRef = instance.classRef!; - expect(classRef.name, 'LinkedMap'); - final first = instance.associations![0].value as InstanceRef; - expect(first.kind, InstanceKind.kList); - expect(first.length, 3); - final second = instance.associations![1].value as InstanceRef; - expect(second.kind, InstanceKind.kString); - expect(second.valueAsString, 'something'); - expect(inspector.isDisplayableObject(instance), isTrue); - }); - - test('for an identityMap', () async { - final remote = await getIdentityMapRef(); - final instance = await inspector.instanceFor(remote); - expect(instance!.kind, InstanceKind.kMap); - final classRef = instance.classRef!; - expect(classRef.name, 'IdentityMap'); - final first = instance.associations![0].value as InstanceRef; - expect(first.valueAsString, '1'); - expect(inspector.isDisplayableObject(instance), isTrue); - }); - - // Regression test for https://github.com/dart-lang/webdev/issues/2446. - test('for a stream', () async { - final remote = await getStreamRef(); - final instance = await inspector.instanceFor(remote); - expect(instance!.kind, InstanceKind.kPlainInstance); - final classRef = instance.classRef!; - expect(classRef.name, '_ControllerStream'); - expect(inspector.isDisplayableObject(instance), isTrue); - }); - - test( - 'for a Dart error', - () async { - final remoteObject = await inspector.jsEvaluate(newDartError); - final instance = await inspector.instanceFor(remoteObject); - expect(instance!.kind, InstanceKind.kPlainInstance); - expect(instance.classRef!.name, 'NativeError'); - expect(inspector.isDisplayableObject(instance), isFalse); - expect(inspector.isNativeJsError(instance), isTrue); - expect(inspector.isNativeJsObject(instance), isFalse); - }, - skip: - provider.ddcModuleFormat == ModuleFormat.ddc && - canaryFeatures == true - ? unsupportedTestMsg - : null, - ); - - test( - 'for a native JavaScript error', - () async { - final remoteObject = await inspector.jsEvaluate( - newInterceptorsExpression('NativeError'), - ); - final instance = await inspector.instanceFor(remoteObject); - expect(instance!.kind, InstanceKind.kPlainInstance); - expect(instance.classRef!.name, 'NativeError'); - expect(inspector.isDisplayableObject(instance), isFalse); - expect(inspector.isNativeJsError(instance), isTrue); - expect(inspector.isNativeJsObject(instance), isFalse); - }, - skip: - provider.ddcModuleFormat == ModuleFormat.ddc && - canaryFeatures == true - ? unsupportedTestMsg - : null, - ); - - test( - 'for a native JavaScript type error', - () async { - final remoteObject = await inspector.jsEvaluate( - newInterceptorsExpression('JSNoSuchMethodError'), - ); - final instance = await inspector.instanceFor(remoteObject); - expect(instance!.kind, InstanceKind.kPlainInstance); - expect(instance.classRef!.name, 'JSNoSuchMethodError'); - expect(inspector.isDisplayableObject(instance), isFalse); - expect(inspector.isNativeJsError(instance), isTrue); - expect(inspector.isNativeJsObject(instance), isFalse); - }, - skip: - provider.ddcModuleFormat == ModuleFormat.ddc && - canaryFeatures == true - ? unsupportedTestMsg - : null, - ); - - test( - 'for a native JavaScript object', - () async { - final remoteObject = await inspector.jsEvaluate( - newInterceptorsExpression('LegacyJavaScriptObject'), - ); - final instance = await inspector.instanceFor(remoteObject); - expect(instance!.kind, InstanceKind.kPlainInstance); - expect(instance.classRef!.name, 'LegacyJavaScriptObject'); - expect(inspector.isDisplayableObject(instance), isFalse); - expect(inspector.isNativeJsError(instance), isFalse); - expect(inspector.isNativeJsObject(instance), isTrue); - }, - skip: - provider.ddcModuleFormat == ModuleFormat.ddc && - canaryFeatures == true - ? unsupportedTestMsg - : null, - ); - }); - }); -} diff --git a/dwds/test/integration/instances/common/instance_inspection_common.dart b/dwds/test/integration/instances/common/instance_inspection_common.dart deleted file mode 100644 index 13f91262f1..0000000000 --- a/dwds/test/integration/instances/common/instance_inspection_common.dart +++ /dev/null @@ -1,363 +0,0 @@ -// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'package:dwds_test_common/logging.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; -import 'package:vm_service/vm_service.dart'; - -import '../../fixtures/context.dart'; -import '../../fixtures/project.dart'; -import '../../fixtures/utilities.dart'; -import 'test_inspector.dart'; - -void runTests({ - required TestSdkConfigurationProvider provider, - required CompilationMode compilationMode, - required bool canaryFeatures, -}) { - final project = TestProject.testPackage(); - final context = TestContext(project, provider); - - late VmService service; - late Stream stream; - late String isolateId; - late ScriptRef mainScript; - - final testInspector = TestInspector(context); - - Future onBreakPoint( - String breakPointId, - Future Function(Event) body, - ) => testInspector.onBreakPoint( - stream, - isolateId, - mainScript, - breakPointId, - body, - ); - - Future getInstance(int frame, String expression) => - testInspector.getInstance(isolateId, frame, expression); - - Future getObject(String instanceId) => - service.getObject(isolateId, instanceId); - - Future getInstanceRef(int frame, String expression) => - testInspector.getInstanceRef(isolateId, frame, expression); - - Future> getFields( - InstanceRef instanceRef, { - int? offset, - int? count, - }) => testInspector.getFields( - isolateId, - instanceRef, - offset: offset, - count: count, - ); - - group('$compilationMode |', () { - setUpAll(() async { - setCurrentLogWriter(debug: provider.verbose); - await context.setUp( - testSettings: TestSettings( - compilationMode: compilationMode, - enableExpressionEvaluation: true, - verboseCompiler: provider.verbose, - canaryFeatures: canaryFeatures, - experiments: ['records'], - moduleFormat: provider.ddcModuleFormat, - ), - ); - service = context.debugConnection.vmService; - - final vm = await service.getVM(); - isolateId = vm.isolates!.first.id!; - final scripts = await service.getScripts(isolateId); - - await service.streamListen('Debug'); - stream = service.onEvent('Debug'); - - mainScript = scripts.scripts!.firstWhere( - (each) => each.uri!.contains('main.dart'), - ); - }); - - tearDownAll(context.tearDown); - - setUp(() => setCurrentLogWriter(debug: provider.verbose)); - tearDown(() async { - // We must resume execution in case a test left the isolate paused, but - // error 106 is expected if the isolate is already running. - try { - await service.resume(isolateId); - } on RPCError catch (e) { - if (e.code != 106) rethrow; - } - }); - - group('Library |', () { - test('classes', () async { - const libraryId = 'org-dartlang-app:///web/main.dart'; - final library = await getObject(libraryId); - - expect( - library, - isA().having((l) => l.classes, 'classes', [ - matchClassRef(name: 'MainClass', libraryId: libraryId), - matchClassRef(name: 'EnclosedClass', libraryId: libraryId), - matchClassRef(name: 'ClassWithMethod', libraryId: libraryId), - matchClassRef(name: 'EnclosingClass', libraryId: libraryId), - ]), - ); - }); - }); - - group('Class |', () { - test('name and library', () async { - const libraryId = 'org-dartlang-app:///web/main.dart'; - const className = 'MainClass'; - final cls = await getObject('classes|$libraryId|$className'); - - expect(cls, matchClass(name: className, libraryId: libraryId)); - }); - }); - - group('Object |', () { - test('type and fields', () async { - await onBreakPoint('printFieldMain', (Event event) async { - final frame = event.topFrame!.index!; - final instanceRef = await getInstanceRef(frame, 'instance'); - - final instanceId = instanceRef.id!; - expect( - await getObject(instanceId), - matchPlainInstance( - libraryId: 'org-dartlang-app:///web/main.dart', - type: 'MainClass', - ), - ); - - expect(await getFields(instanceRef), {'_field': 1, 'field': 2}); - - // Offsets and counts are ignored for plain object fields. - - // DevTools calls [VmServiceInterface.getObject] with offset=0 - // and count=0 and expects all fields to be returned. - expect(await getFields(instanceRef, offset: 0, count: 0), { - '_field': 1, - 'field': 2, - }); - expect(await getFields(instanceRef, offset: 0), { - '_field': 1, - 'field': 2, - }); - expect(await getFields(instanceRef, offset: 0, count: 1), { - '_field': 1, - 'field': 2, - }); - expect(await getFields(instanceRef, offset: 1), { - '_field': 1, - 'field': 2, - }); - expect(await getFields(instanceRef, offset: 1, count: 0), { - '_field': 1, - 'field': 2, - }); - expect(await getFields(instanceRef, offset: 1, count: 3), { - '_field': 1, - 'field': 2, - }); - }); - }); - - test('field access', () async { - await onBreakPoint('printFieldMain', (Event event) async { - final frame = event.topFrame!.index!; - expect( - await getInstance(frame, r'instance.field'), - matchPrimitiveInstance(kind: InstanceKind.kDouble, value: 2), - ); - - expect( - await getInstance(frame, r'instance._field'), - matchPrimitiveInstance(kind: InstanceKind.kDouble, value: 1), - ); - }); - }); - }); - - group('List |', () { - test('type and fields', () async { - await onBreakPoint('printList', (Event event) async { - final frame = event.topFrame!.index!; - final instanceRef = await getInstanceRef(frame, 'list'); - - final instanceId = instanceRef.id!; - expect(await getObject(instanceId), matchListInstance(type: 'int')); - - expect(await getFields(instanceRef), {0: 0.0, 1: 1.0, 2: 2.0}); - expect( - await getFields(instanceRef, offset: 1, count: 0), - {}, - ); - expect(await getFields(instanceRef, offset: 0), { - 0: 0.0, - 1: 1.0, - 2: 2.0, - }); - expect(await getFields(instanceRef, offset: 0, count: 1), {0: 0.0}); - expect(await getFields(instanceRef, offset: 1), {0: 1.0, 1: 2.0}); - expect(await getFields(instanceRef, offset: 1, count: 1), {0: 1.0}); - expect(await getFields(instanceRef, offset: 1, count: 3), { - 0: 1.0, - 1: 2.0, - }); - expect( - await getFields(instanceRef, offset: 3, count: 3), - {}, - ); - }); - }); - - test('Element access', () async { - await onBreakPoint('printList', (Event event) async { - final frame = event.topFrame!.index!; - expect( - await getInstance(frame, r'list[0]'), - matchPrimitiveInstance(kind: InstanceKind.kDouble, value: 0), - ); - - expect( - await getInstance(frame, r'list[1]'), - matchPrimitiveInstance(kind: InstanceKind.kDouble, value: 1), - ); - - expect( - await getInstance(frame, r'list[2]'), - matchPrimitiveInstance(kind: InstanceKind.kDouble, value: 2), - ); - }); - }); - }); - - group('Map |', () { - test('type and fields', () async { - await onBreakPoint('printMap', (Event event) async { - final frame = event.topFrame!.index!; - final instanceRef = await getInstanceRef(frame, 'map'); - - final instanceId = instanceRef.id!; - expect( - await getObject(instanceId), - matchMapInstance(type: 'IdentityMap'), - ); - - expect(await getFields(instanceRef), {'a': 1, 'b': 2, 'c': 3}); - - expect( - await getFields(instanceRef, offset: 1, count: 0), - {}, - ); - expect(await getFields(instanceRef, offset: 0), { - 'a': 1, - 'b': 2, - 'c': 3, - }); - expect(await getFields(instanceRef, offset: 0, count: 1), {'a': 1}); - expect(await getFields(instanceRef, offset: 1), {'b': 2, 'c': 3}); - expect(await getFields(instanceRef, offset: 1, count: 1), {'b': 2}); - expect(await getFields(instanceRef, offset: 1, count: 3), { - 'b': 2, - 'c': 3, - }); - expect( - await getFields(instanceRef, offset: 3, count: 3), - {}, - ); - }); - }); - - test('Element access', () async { - await onBreakPoint('printMap', (Event event) async { - final frame = event.topFrame!.index!; - expect( - await getInstance(frame, r"map['a']"), - matchPrimitiveInstance(kind: InstanceKind.kDouble, value: 1), - ); - - expect( - await getInstance(frame, r"map['b']"), - matchPrimitiveInstance(kind: InstanceKind.kDouble, value: 2), - ); - - expect( - await getInstance(frame, r"map['c']"), - matchPrimitiveInstance(kind: InstanceKind.kDouble, value: 3), - ); - }); - }); - }); - - group('Set |', () { - test('type and fields', () async { - await onBreakPoint('printSet', (Event event) async { - final frame = event.topFrame!.index!; - final instanceRef = await getInstanceRef(frame, 'mySet'); - - final instanceId = instanceRef.id!; - expect( - await getObject(instanceId), - matchSetInstance(type: 'LinkedSet'), - ); - - expect(await getFields(instanceRef), { - 0: 1.0, - 1: 4.0, - 2: 5.0, - 3: 7.0, - }); - expect(await getFields(instanceRef, offset: 0), { - 0: 1.0, - 1: 4.0, - 2: 5.0, - 3: 7.0, - }); - expect(await getFields(instanceRef, offset: 1, count: 2), { - 0: 4.0, - 1: 5.0, - }); - expect(await getFields(instanceRef, offset: 2), {0: 5.0, 1: 7.0}); - expect(await getFields(instanceRef, offset: 2, count: 10), { - 0: 5.0, - 1: 7.0, - }); - expect( - await getFields(instanceRef, offset: 1, count: 0), - {}, - ); - expect( - await getFields(instanceRef, offset: 10, count: 2), - {}, - ); - }); - }); - - test('Element access', () async { - await onBreakPoint('printSet', (Event event) async { - final frame = event.topFrame!.index!; - expect( - await getInstance(frame, r'mySet.first'), - matchPrimitiveInstance(kind: InstanceKind.kDouble, value: 1), - ); - expect( - await getInstance(frame, r'mySet.last'), - matchPrimitiveInstance(kind: InstanceKind.kDouble, value: 7), - ); - }); - }); - }); - }); -} diff --git a/dwds/test/integration/instances/common/patterns_inspection_common.dart b/dwds/test/integration/instances/common/patterns_inspection_common.dart deleted file mode 100644 index 8255c56864..0000000000 --- a/dwds/test/integration/instances/common/patterns_inspection_common.dart +++ /dev/null @@ -1,181 +0,0 @@ -// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'package:dwds_test_common/logging.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; -import 'package:vm_service/vm_service.dart'; - -import '../../fixtures/context.dart'; -import '../../fixtures/project.dart'; -import '../../fixtures/utilities.dart'; -import 'test_inspector.dart'; - -void runTests({ - required TestSdkConfigurationProvider provider, - required CompilationMode compilationMode, - required bool canaryFeatures, -}) { - final context = TestContext(TestProject.testExperiment, provider); - final testInspector = TestInspector(context); - - late VmService service; - late Stream stream; - late String isolateId; - late ScriptRef mainScript; - - Future onBreakPoint( - String breakPointId, - Future Function(Event) body, - ) => testInspector.onBreakPoint( - stream, - isolateId, - mainScript, - breakPointId, - body, - ); - - Future getInstanceRef(int frame, String expression) => - testInspector.getInstanceRef(isolateId, frame, expression); - - Future> getFields( - InstanceRef instanceRef, { - int? offset, - int? count, - }) => testInspector.getFields( - isolateId, - instanceRef, - offset: offset, - count: count, - ); - - Future> getFrameVariables(Frame frame) => - testInspector.getFrameVariables(isolateId, frame); - - group('$compilationMode |', () { - setUpAll(() async { - setCurrentLogWriter(debug: provider.verbose); - await context.setUp( - testSettings: TestSettings( - compilationMode: compilationMode, - enableExpressionEvaluation: true, - verboseCompiler: provider.verbose, - experiments: ['dot-shorthands'], - canaryFeatures: canaryFeatures, - moduleFormat: provider.ddcModuleFormat, - ), - ); - service = context.debugConnection.vmService; - - final vm = await service.getVM(); - isolateId = vm.isolates!.first.id!; - final scripts = await service.getScripts(isolateId); - - await service.streamListen('Debug'); - stream = service.onEvent('Debug'); - - mainScript = scripts.scripts!.firstWhere( - (each) => each.uri!.contains('main.dart'), - ); - }); - - tearDownAll(() async { - await context.tearDown(); - }); - - setUp(() => setCurrentLogWriter(debug: provider.verbose)); - tearDown(() => service.resume(isolateId)); - - test('pattern match case 1', () async { - await onBreakPoint('testPatternCase1', (event) async { - final frame = event.topFrame!; - - expect(await getFrameVariables(frame), { - 'obj': matchListInstance(type: 'Object'), - 'a': matchPrimitiveInstance(kind: InstanceKind.kString, value: 'a'), - 'n': matchPrimitiveInstance(kind: InstanceKind.kDouble, value: 1), - }); - }); - }); - - test('pattern match case 2', () async { - await onBreakPoint('testPatternCase2', (event) async { - final frame = event.topFrame!; - - expect(await getFrameVariables(frame), { - 'obj': matchListInstance(type: 'Object'), - // Renamed to avoid shadowing variables from previous case. - 'a\$': matchPrimitiveInstance(kind: InstanceKind.kString, value: 'b'), - 'n\$': matchPrimitiveInstance( - kind: InstanceKind.kDouble, - value: 3.14, - ), - }); - }); - }); - - test('pattern match default case', () async { - await onBreakPoint('testPatternDefault', (event) async { - final frame = event.topFrame!; - final frameIndex = frame.index!; - final instanceRef = await getInstanceRef(frameIndex, 'obj'); - expect(await getFields(instanceRef), {0: 0.0, 1: 1.0}); - - expect(await getFrameVariables(frame), { - 'obj': matchListInstance(type: 'int'), - }); - }); - }); - - test('stepping through pattern match', () async { - await onBreakPoint('callTestPattern1', (Event event) async { - var previousLocation = event.topFrame!.location; - for (final step in [ - // Make sure we step into the callee. - for (var i = 0; i < 4; i++) 'Into', - // Make a few steps inside the callee. - for (var i = 0; i < 4; i++) 'Over', - ]) { - await service.resume(isolateId, step: step); - - event = await stream.firstWhere( - (e) => e.kind == EventKind.kPauseInterrupted, - ); - - if (step == 'Over') { - expect(event.topFrame!.code!.name, 'testPattern'); - } - - final location = event.topFrame!.location; - expect(location, isNot(equals(previousLocation))); - previousLocation = location; - } - }); - }); - - test('before instantiation of pattern-matching variables', () async { - await onBreakPoint('testPattern2Case1', (event) async { - final frame = event.topFrame!; - - expect(await getFrameVariables(frame), { - 'dog': matchPrimitiveInstance(kind: 'String', value: 'Prismo'), - }); - }); - }); - - test('after instantiation of pattern-matching variables', () async { - await onBreakPoint('testPattern2Case2', (event) async { - final frame = event.topFrame!; - - final vars = await getFrameVariables(frame); - expect(vars, { - 'dog': matchPrimitiveInstance(kind: 'String', value: 'Prismo'), - 'cats': matchListInstance(type: 'String'), - 'firstCat': matchPrimitiveInstance(kind: 'String', value: 'Garfield'), - 'secondCat': matchPrimitiveInstance(kind: 'String', value: 'Tom'), - }); - }); - }); - }); -} diff --git a/dwds/test/integration/instances/common/record_inspection_common.dart b/dwds/test/integration/instances/common/record_inspection_common.dart deleted file mode 100644 index ef4c65cd22..0000000000 --- a/dwds/test/integration/instances/common/record_inspection_common.dart +++ /dev/null @@ -1,586 +0,0 @@ -// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'package:dwds_test_common/logging.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; -import 'package:vm_service/vm_service.dart'; - -import '../../fixtures/context.dart'; -import '../../fixtures/project.dart'; -import '../../fixtures/utilities.dart'; -import 'test_inspector.dart'; - -void runTests({ - required TestSdkConfigurationProvider provider, - required CompilationMode compilationMode, - required bool canaryFeatures, -}) { - final context = TestContext(TestProject.testExperiment, provider); - final testInspector = TestInspector(context); - - late VmService service; - late Stream stream; - late String isolateId; - late ScriptRef mainScript; - - Future onBreakPoint( - String breakPointId, - Future Function(Event) body, - ) => testInspector.onBreakPoint( - stream, - isolateId, - mainScript, - breakPointId, - body, - ); - - Future getInstance(int frame, String expression) => - testInspector.getInstance(isolateId, frame, expression); - - Future getObject(String instanceId) => - service.getObject(isolateId, instanceId); - - Future getInstanceRef(int frame, String expression) => - testInspector.getInstanceRef(isolateId, frame, expression); - - Future> getFields( - InstanceRef instanceRef, { - int? offset, - int? count, - int depth = -1, - }) => testInspector.getFields( - isolateId, - instanceRef, - offset: offset, - count: count, - depth: depth, - ); - - group('$compilationMode |', () { - setUpAll(() async { - setCurrentLogWriter(debug: provider.verbose); - await context.setUp( - testSettings: TestSettings( - compilationMode: compilationMode, - enableExpressionEvaluation: true, - verboseCompiler: provider.verbose, - experiments: ['dot-shorthands'], - canaryFeatures: canaryFeatures, - moduleFormat: provider.ddcModuleFormat, - ), - ); - service = context.debugConnection.vmService; - - final vm = await service.getVM(); - isolateId = vm.isolates!.first.id!; - final scripts = await service.getScripts(isolateId); - - await service.streamListen('Debug'); - stream = service.onEvent('Debug'); - - mainScript = scripts.scripts!.firstWhere( - (each) => each.uri!.contains('main.dart'), - ); - }); - - tearDownAll(() async { - await context.tearDown(); - }); - - setUp(() => setCurrentLogWriter(debug: provider.verbose)); - tearDown(() => service.resume(isolateId)); - - test('simple record display', () async { - await onBreakPoint('printSimpleLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - - final instanceRef = await getInstanceRef(frame, 'record'); - final classId = instanceRef.classRef!.id!; - - expect(await getObject(classId), matchRecordClass); - - final stringRef = await getInstanceRef(frame, 'record.toString()'); - final stringRefId = stringRef.id!; - - expect( - await getObject(stringRefId), - matchPrimitiveInstance( - kind: InstanceKind.kString, - value: '(true, 3)', - ), - ); - }); - }); - - test('simple records', () async { - await onBreakPoint('printSimpleLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - final instanceRef = await getInstanceRef(frame, 'record'); - final instanceId = instanceRef.id!; - - expect(instanceRef, matchRecordInstanceRef(length: 2)); - expect(await getObject(instanceId), matchRecordInstance(length: 2)); - - expect(await getFields(instanceRef), {1: true, 2: 3}); - expect(await getFields(instanceRef, offset: 0), {1: true, 2: 3}); - expect(await getFields(instanceRef, offset: 1), {2: 3}); - expect(await getFields(instanceRef, offset: 2), {}); - expect( - await getFields(instanceRef, offset: 0, count: 0), - {}, - ); - expect(await getFields(instanceRef, offset: 0, count: 1), {1: true}); - expect(await getFields(instanceRef, offset: 0, count: 2), { - 1: true, - 2: 3, - }); - expect(await getFields(instanceRef, offset: 0, count: 5), { - 1: true, - 2: 3, - }); - expect( - await getFields(instanceRef, offset: 2, count: 5), - {}, - ); - }); - }); - - test('simple records, field access', () async { - await onBreakPoint('printSimpleLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - expect( - await getInstance(frame, r'record.$1'), - matchPrimitiveInstance(kind: InstanceKind.kBool, value: true), - ); - - expect( - await getInstance(frame, r'record.$2'), - matchPrimitiveInstance(kind: InstanceKind.kDouble, value: 3), - ); - }); - }); - - test('simple records with named fields display', () async { - await onBreakPoint('printSimpleNamedLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - - final instanceRef = await getInstanceRef(frame, 'record'); - final classId = instanceRef.classRef!.id!; - - expect(await getObject(classId), matchRecordClass); - - final stringRef = await getInstanceRef(frame, 'record.toString()'); - final stringId = stringRef.id!; - - expect( - await getObject(stringId), - matchPrimitiveInstance( - kind: InstanceKind.kString, - value: '(true, cat: Vasya)', - ), - ); - }); - }); - - test('simple records with named fields', () async { - await onBreakPoint('printSimpleNamedLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - final instanceRef = await getInstanceRef(frame, 'record'); - - final instanceId = instanceRef.id!; - expect(instanceRef, matchRecordInstanceRef(length: 2)); - expect(await getObject(instanceId), matchRecordInstance(length: 2)); - - expect(await getFields(instanceRef), {1: true, 'cat': 'Vasya'}); - expect(await getFields(instanceRef, offset: 0), { - 1: true, - 'cat': 'Vasya', - }); - expect(await getFields(instanceRef, offset: 1), {'cat': 'Vasya'}); - expect(await getFields(instanceRef, offset: 2), {}); - expect( - await getFields(instanceRef, offset: 0, count: 0), - {}, - ); - expect(await getFields(instanceRef, offset: 0, count: 1), {1: true}); - expect(await getFields(instanceRef, offset: 0, count: 2), { - 1: true, - 'cat': 'Vasya', - }); - expect(await getFields(instanceRef, offset: 0, count: 5), { - 1: true, - 'cat': 'Vasya', - }); - expect( - await getFields(instanceRef, offset: 2, count: 5), - {}, - ); - }); - }); - - test('simple records with named fields, field access', () async { - await onBreakPoint('printSimpleNamedLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - expect( - await getInstance(frame, r'record.$1'), - matchPrimitiveInstance(kind: InstanceKind.kBool, value: true), - ); - - expect( - await getInstance(frame, r'record.cat'), - matchPrimitiveInstance(kind: InstanceKind.kString, value: 'Vasya'), - ); - }); - }); - - test('complex records display', () async { - await onBreakPoint('printComplexLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - - final instanceRef = await getInstanceRef(frame, 'record'); - final classId = instanceRef.classRef!.id!; - - expect(await getObject(classId), matchRecordClass); - - final stringRef = await getInstanceRef(frame, 'record.toString()'); - final stringId = stringRef.id!; - - expect( - await getObject(stringId), - matchPrimitiveInstance( - kind: InstanceKind.kString, - value: '(true, 3, {a: 1, b: 5})', - ), - ); - }); - }); - - test('complex records', () async { - await onBreakPoint('printComplexLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - final instanceRef = await getInstanceRef(frame, 'record'); - - final instanceId = instanceRef.id!; - expect(instanceRef, matchRecordInstanceRef(length: 3)); - expect(await getObject(instanceId), matchRecordInstance(length: 3)); - - expect(await getFields(instanceRef), { - 1: true, - 2: 3, - 3: {'a': 1, 'b': 5}, - }); - expect(await getFields(instanceRef, offset: 0), { - 1: true, - 2: 3, - 3: {'a': 1, 'b': 5}, - }); - expect(await getFields(instanceRef, offset: 1), { - 2: 3, - 3: {'a': 1, 'b': 5}, - }); - expect(await getFields(instanceRef, offset: 1, count: 1), {2: 3}); - expect(await getFields(instanceRef, offset: 1, count: 2), { - 2: 3, - 3: {'a': 1, 'b': 5}, - }); - expect(await getFields(instanceRef, offset: 2), { - 3: {'a': 1, 'b': 5}, - }); - expect(await getFields(instanceRef, offset: 3), {}); - expect( - await getFields(instanceRef, offset: 0, count: 0), - {}, - ); - expect(await getFields(instanceRef, offset: 0, count: 1), {1: true}); - expect(await getFields(instanceRef, offset: 0, count: 2), { - 1: true, - 2: 3, - }); - expect(await getFields(instanceRef, offset: 0, count: 5), { - 1: true, - 2: 3, - 3: {'a': 1, 'b': 5}, - }); - expect( - await getFields(instanceRef, offset: 3, count: 5), - {}, - ); - }); - }); - - test('complex records, field access', () async { - await onBreakPoint('printComplexLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - expect( - await getInstance(frame, r'record.$1'), - matchPrimitiveInstance(kind: InstanceKind.kBool, value: true), - ); - - expect( - await getInstance(frame, r'record.$2'), - matchPrimitiveInstance(kind: InstanceKind.kDouble, value: 3), - ); - - final third = await getInstanceRef(frame, r'record.$3'); - expect(third.kind, InstanceKind.kMap); - expect(await getFields(third), {'a': 1, 'b': 5}); - }); - }); - - test('complex records with named fields display', () async { - await onBreakPoint('printComplexNamedLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - - final instanceRef = await getInstanceRef(frame, 'record'); - final classId = instanceRef.classRef!.id!; - - expect(await getObject(classId), matchRecordClass); - - final stringRef = await getInstanceRef(frame, 'record.toString()'); - final stringId = stringRef.id!; - - expect( - await getObject(stringId), - matchPrimitiveInstance( - kind: InstanceKind.kString, - value: '(true, 3, array: {a: 1, b: 5})', - ), - ); - }); - }); - - test('complex records with named fields', () async { - await onBreakPoint('printComplexNamedLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - final instanceRef = await getInstanceRef(frame, 'record'); - - final instanceId = instanceRef.id!; - expect(instanceRef, matchRecordInstanceRef(length: 3)); - expect(await getObject(instanceId), matchRecordInstance(length: 3)); - - expect(await getFields(instanceRef), { - 1: true, - 2: 3, - 'array': {'a': 1, 'b': 5}, - }); - expect(await getFields(instanceRef, offset: 0), { - 1: true, - 2: 3, - 'array': {'a': 1, 'b': 5}, - }); - expect(await getFields(instanceRef, offset: 1), { - 2: 3, - 'array': {'a': 1, 'b': 5}, - }); - expect(await getFields(instanceRef, offset: 1, count: 1), {2: 3}); - expect(await getFields(instanceRef, offset: 1, count: 2), { - 2: 3, - 'array': {'a': 1, 'b': 5}, - }); - expect(await getFields(instanceRef, offset: 2), { - 'array': {'a': 1, 'b': 5}, - }); - expect(await getFields(instanceRef, offset: 3), {}); - expect( - await getFields(instanceRef, offset: 0, count: 0), - {}, - ); - expect(await getFields(instanceRef, offset: 0, count: 1), {1: true}); - expect(await getFields(instanceRef, offset: 0, count: 2), { - 1: true, - 2: 3, - }); - expect(await getFields(instanceRef, offset: 0, count: 5), { - 1: true, - 2: 3, - 'array': {'a': 1, 'b': 5}, - }); - expect( - await getFields(instanceRef, offset: 3, count: 5), - {}, - ); - }); - }); - - test('complex records with named fields, field access', () async { - await onBreakPoint('printComplexNamedLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - expect( - await getInstance(frame, r'record.$1'), - matchPrimitiveInstance(kind: InstanceKind.kBool, value: true), - ); - - expect( - await getInstance(frame, r'record.$2'), - matchPrimitiveInstance(kind: InstanceKind.kDouble, value: 3), - ); - - final third = await getInstanceRef(frame, r'record.array'); - expect(third.kind, InstanceKind.kMap); - expect(await getFields(third), {'a': 1, 'b': 5}); - }); - }); - - test('nested records display', () async { - await onBreakPoint('printNestedLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - - final instanceRef = await getInstanceRef(frame, 'record'); - final classId = instanceRef.classRef!.id!; - - expect(await getObject(classId), matchRecordClass); - - final stringRef = await getInstanceRef(frame, 'record.toString()'); - final stringId = stringRef.id!; - - expect( - await getObject(stringId), - matchPrimitiveInstance( - kind: InstanceKind.kString, - value: '(true, (false, 5))', - ), - ); - }); - }); - - test('nested records', () async { - await onBreakPoint('printNestedLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - final instanceRef = await getInstanceRef(frame, 'record'); - - final instanceId = instanceRef.id!; - expect(instanceRef, matchRecordInstanceRef(length: 2)); - expect(await getObject(instanceId), matchRecordInstance(length: 2)); - - expect(await getFields(instanceRef), { - 1: true, - 2: {1: false, 2: 5}, - }); - expect(await getFields(instanceRef, offset: 0), { - 1: true, - 2: {1: false, 2: 5}, - }); - expect(await getFields(instanceRef, offset: 1), { - 2: {1: false, 2: 5}, - }); - expect(await getFields(instanceRef, offset: 2), {}); - expect( - await getFields(instanceRef, offset: 0, count: 0), - {}, - ); - expect(await getFields(instanceRef, offset: 0, count: 1), {1: true}); - expect(await getFields(instanceRef, offset: 0, count: 2), { - 1: true, - 2: {1: false, 2: 5}, - }); - expect(await getFields(instanceRef, offset: 0, count: 5), { - 1: true, - 2: {1: false, 2: 5}, - }); - expect( - await getFields(instanceRef, offset: 2, count: 5), - {}, - ); - }); - }); - - test('nested records, field access', () async { - await onBreakPoint('printNestedLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - final instanceRef = await getInstanceRef(frame, r'record.$2'); - - final instanceId = instanceRef.id!; - expect(instanceRef, matchRecordInstanceRef(length: 2)); - expect(await getObject(instanceId), matchRecordInstance(length: 2)); - - expect(await getFields(instanceRef), {1: false, 2: 5}); - expect(await getFields(instanceRef, offset: 0), {1: false, 2: 5}); - }); - }); - - test('nested records with named fields display', () async { - await onBreakPoint('printNestedNamedLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - - final instanceRef = await getInstanceRef(frame, 'record'); - final classId = instanceRef.classRef!.id!; - - expect(await getObject(classId), matchRecordClass); - - final stringRef = await getInstanceRef(frame, 'record.toString()'); - final stringId = stringRef.id!; - - expect( - await getObject(stringId), - matchPrimitiveInstance( - kind: InstanceKind.kString, - value: '(true, inner: (false, 5))', - ), - ); - }); - }); - - test('nested records with named fields', () async { - await onBreakPoint('printNestedNamedLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - final instanceRef = await getInstanceRef(frame, 'record'); - - final instanceId = instanceRef.id!; - expect(instanceRef, matchRecordInstanceRef(length: 2)); - expect(await getObject(instanceId), matchRecordInstance(length: 2)); - - expect(await getFields(instanceRef), { - 1: true, - 'inner': {1: false, 2: 5}, - }); - expect(await getFields(instanceRef, offset: 0), { - 1: true, - 'inner': {1: false, 2: 5}, - }); - expect(await getFields(instanceRef, offset: 1), { - 'inner': {1: false, 2: 5}, - }); - expect(await getFields(instanceRef, offset: 1, count: 1), { - 'inner': {1: false, 2: 5}, - }); - expect(await getFields(instanceRef, offset: 1, count: 2), { - 'inner': {1: false, 2: 5}, - }); - expect(await getFields(instanceRef, offset: 2), {}); - expect( - await getFields(instanceRef, offset: 0, count: 0), - {}, - ); - expect(await getFields(instanceRef, offset: 0, count: 1), {1: true}); - expect(await getFields(instanceRef, offset: 0, count: 2), { - 1: true, - 'inner': {1: false, 2: 5}, - }); - expect(await getFields(instanceRef, offset: 0, count: 5), { - 1: true, - 'inner': {1: false, 2: 5}, - }); - expect( - await getFields(instanceRef, offset: 2, count: 5), - {}, - ); - }); - }); - - test('nested records with named fields, field access', () async { - await onBreakPoint('printNestedNamedLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - final instanceRef = await getInstanceRef(frame, r'record.inner'); - - final instanceId = instanceRef.id!; - expect(instanceRef, matchRecordInstanceRef(length: 2)); - expect(await getObject(instanceId), matchRecordInstance(length: 2)); - - expect(await getFields(instanceRef), {1: false, 2: 5}); - expect(await getFields(instanceRef, offset: 0), {1: false, 2: 5}); - }); - }); - }); -} diff --git a/dwds/test/integration/instances/common/record_type_inspection_common.dart b/dwds/test/integration/instances/common/record_type_inspection_common.dart deleted file mode 100644 index 82eb5c3e03..0000000000 --- a/dwds/test/integration/instances/common/record_type_inspection_common.dart +++ /dev/null @@ -1,435 +0,0 @@ -// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'package:dwds_test_common/logging.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; -import 'package:vm_service/vm_service.dart'; - -import '../../fixtures/context.dart'; -import '../../fixtures/project.dart'; -import '../../fixtures/utilities.dart'; -import 'test_inspector.dart'; - -void runTests({ - required TestSdkConfigurationProvider provider, - required CompilationMode compilationMode, - required bool canaryFeatures, -}) { - final context = TestContext(TestProject.testExperiment, provider); - final testInspector = TestInspector(context); - - late VmService service; - late Stream stream; - late String isolateId; - late ScriptRef mainScript; - - Future onBreakPoint( - String breakPointId, - Future Function(Event) body, - ) => testInspector.onBreakPoint( - stream, - isolateId, - mainScript, - breakPointId, - body, - ); - - Future getObject(String instanceId) => - service.getObject(isolateId, instanceId); - - Future getInstanceRef(int frame, String expression) => - testInspector.getInstanceRef(isolateId, frame, expression); - - Future> getDisplayedFields(InstanceRef ref) => - testInspector.getDisplayedFields(isolateId, ref); - - Future> getDisplayedGetters(InstanceRef ref) => - testInspector.getDisplayedGetters(isolateId, ref); - - Future> getElements(String instanceId) => - testInspector.getElements(isolateId, instanceId); - - final matchDisplayedTypeObjectGetters = { - 'hashCode': matches('[0-9]*'), - 'runtimeType': matchTypeClassName, - }; - - group('$compilationMode |', () { - setUpAll(() async { - setCurrentLogWriter(debug: provider.verbose); - await context.setUp( - testSettings: TestSettings( - compilationMode: compilationMode, - enableExpressionEvaluation: true, - verboseCompiler: provider.verbose, - experiments: ['dot-shorthands'], - canaryFeatures: canaryFeatures, - moduleFormat: provider.ddcModuleFormat, - ), - ); - service = context.debugConnection.vmService; - - final vm = await service.getVM(); - isolateId = vm.isolates!.first.id!; - final scripts = await service.getScripts(isolateId); - - await service.streamListen('Debug'); - stream = service.onEvent('Debug'); - - mainScript = scripts.scripts!.firstWhere( - (each) => each.uri!.contains('main.dart'), - ); - }); - - tearDownAll(() async { - await context.tearDown(); - }); - - setUp(() => setCurrentLogWriter(debug: provider.verbose)); - tearDown(() => service.resume(isolateId)); - - test('simple record type', () async { - await onBreakPoint('printSimpleLocalRecord', (event) async { - final frame = event.topFrame!.index!; - final instanceRef = await getInstanceRef(frame, 'record.runtimeType'); - final instanceId = instanceRef.id!; - - expect(instanceRef, matchRecordTypeInstanceRef(length: 2)); - expect(await getObject(instanceId), matchRecordTypeInstance(length: 2)); - - final classId = instanceRef.classRef!.id!; - expect(await getObject(classId), matchRecordTypeClass); - }); - }); - - test('simple record type elements', () async { - await onBreakPoint('printSimpleLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - final instanceRef = await getInstanceRef(frame, 'record.runtimeType'); - final instanceId = instanceRef.id!; - - expect(await getElements(instanceId), [ - matchTypeInstance('bool'), - matchTypeInstance('int'), - ]); - expect(await getDisplayedFields(instanceRef), {1: 'bool', 2: 'int'}); - }); - }); - - test('simple record type getters', () async { - await onBreakPoint('printSimpleLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - final instanceRef = await getInstanceRef(frame, 'record.runtimeType'); - - expect( - await getDisplayedGetters(instanceRef), - matchDisplayedTypeObjectGetters, - ); - }); - }); - - test('simple record type display', () async { - await onBreakPoint('printSimpleLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - final typeStringRef = await getInstanceRef( - frame, - 'record.runtimeType.toString()', - ); - final typeStringId = typeStringRef.id!; - - expect( - await getObject(typeStringId), - matchPrimitiveInstance( - kind: InstanceKind.kString, - value: '(bool, int)', - ), - ); - }); - }); - - test('complex record type', () async { - await onBreakPoint('printComplexLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - final instanceRef = await getInstanceRef(frame, 'record.runtimeType'); - final instanceId = instanceRef.id!; - - expect(instanceRef, matchRecordTypeInstanceRef(length: 3)); - expect(await getObject(instanceId), matchRecordTypeInstance(length: 3)); - - final classId = instanceRef.classRef!.id!; - expect(await getObject(classId), matchRecordTypeClass); - }); - }); - - test('complex record type elements', () async { - await onBreakPoint('printComplexLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - final instanceRef = await getInstanceRef(frame, 'record.runtimeType'); - final instanceId = instanceRef.id!; - - expect(await getElements(instanceId), [ - matchTypeInstance('bool'), - matchTypeInstance('int'), - matchTypeInstance('IdentityMap'), - ]); - expect(await getDisplayedFields(instanceRef), { - 1: 'bool', - 2: 'int', - 3: 'IdentityMap', - }); - }); - }); - - test('complex record type getters', () async { - await onBreakPoint('printComplexLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - final instanceRef = await getInstanceRef(frame, 'record.runtimeType'); - - expect( - await getDisplayedGetters(instanceRef), - matchDisplayedTypeObjectGetters, - ); - }); - }); - - test('complex record type display', () async { - await onBreakPoint('printComplexLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - final typeStringRef = await getInstanceRef( - frame, - 'record.runtimeType.toString()', - ); - final typeStringId = typeStringRef.id!; - - expect( - await getObject(typeStringId), - matchPrimitiveInstance( - kind: InstanceKind.kString, - value: '(bool, int, IdentityMap)', - ), - ); - }); - }); - - test('complex record type with named fields ', () async { - await onBreakPoint('printComplexNamedLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - final instanceRef = await getInstanceRef(frame, 'record.runtimeType'); - final instanceId = instanceRef.id!; - - expect(instanceRef, matchRecordTypeInstanceRef(length: 3)); - expect(await getObject(instanceId), matchRecordTypeInstance(length: 3)); - - final classId = instanceRef.classRef!.id!; - expect(await getObject(classId), matchRecordTypeClass); - }); - }); - - test('complex record type with named fields elements', () async { - await onBreakPoint('printComplexNamedLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - final instanceRef = await getInstanceRef(frame, 'record.runtimeType'); - final instanceId = instanceRef.id!; - - expect(await getElements(instanceId), [ - matchTypeInstance('bool'), - matchTypeInstance('int'), - matchTypeInstance('IdentityMap'), - ]); - - expect(await getDisplayedFields(instanceRef), { - 1: 'bool', - 2: 'int', - 'array': 'IdentityMap', - }); - }); - }); - - test('complex record type with named fields getters', () async { - await onBreakPoint('printComplexNamedLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - final instanceRef = await getInstanceRef(frame, 'record.runtimeType'); - - expect( - await getDisplayedGetters(instanceRef), - matchDisplayedTypeObjectGetters, - ); - }); - }); - - test('complex record type with named fields display', () async { - await onBreakPoint('printComplexNamedLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - final typeStringRef = await getInstanceRef( - frame, - 'record.runtimeType.toString()', - ); - final typeStringId = typeStringRef.id!; - - expect( - await getObject(typeStringId), - matchPrimitiveInstance( - kind: InstanceKind.kString, - value: '(bool, int, {IdentityMap array})', - ), - ); - }); - }); - - test('nested record type', () async { - await onBreakPoint('printNestedLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - final instanceRef = await getInstanceRef(frame, 'record.runtimeType'); - final instanceId = instanceRef.id!; - - expect(instanceRef, matchRecordTypeInstanceRef(length: 2)); - expect(await getObject(instanceId), matchRecordTypeInstance(length: 2)); - - final classId = instanceRef.classRef!.id!; - expect(await getObject(classId), matchRecordTypeClass); - }); - }); - - test('nested record type elements', () async { - await onBreakPoint('printNestedLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - final instanceRef = await getInstanceRef(frame, 'record.runtimeType'); - final instanceId = instanceRef.id!; - - final elements = await getElements(instanceId); - expect(elements, [ - matchTypeInstance('bool'), - matchRecordTypeInstance(length: 2), - ]); - expect(await getElements(elements[1].id!), [ - matchTypeInstance('bool'), - matchTypeInstance('int'), - ]); - expect(await getDisplayedFields(instanceRef), { - 1: 'bool', - 2: '(bool, int)', - }); - expect(await getDisplayedFields(elements[1]), {1: 'bool', 2: 'int'}); - }); - }); - - test('nested record type getters', () async { - await onBreakPoint('printNestedLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - final instanceRef = await getInstanceRef(frame, 'record.runtimeType'); - final elements = await getElements(instanceRef.id!); - - expect( - await getDisplayedGetters(instanceRef), - matchDisplayedTypeObjectGetters, - ); - expect( - await getDisplayedGetters(elements[1]), - matchDisplayedTypeObjectGetters, - ); - }); - }); - - test('nested record type display', () async { - await onBreakPoint('printNestedLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - final typeStringRef = await getInstanceRef( - frame, - 'record.runtimeType.toString()', - ); - final typeStringId = typeStringRef.id!; - - expect( - await getObject(typeStringId), - matchPrimitiveInstance( - kind: InstanceKind.kString, - value: '(bool, (bool, int))', - ), - ); - }); - }); - - test('nested record type with named fields', () async { - await onBreakPoint('printNestedNamedLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - final instanceRef = await getInstanceRef(frame, 'record.runtimeType'); - final instanceId = instanceRef.id!; - final instance = await getObject(instanceId); - - expect(instanceRef, matchRecordTypeInstanceRef(length: 2)); - expect(instance, matchRecordTypeInstance(length: 2)); - - final classId = instanceRef.classRef!.id!; - expect(await getObject(classId), matchRecordTypeClass); - }); - }); - - test('nested record type with named fields elements', () async { - await onBreakPoint('printNestedNamedLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - final instanceRef = await getInstanceRef(frame, 'record.runtimeType'); - final instanceId = instanceRef.id!; - - final elements = await getElements(instanceId); - expect(elements, [ - matchTypeInstance('bool'), - matchRecordTypeInstance(length: 2), - ]); - expect(await getElements(elements[1].id!), [ - matchTypeInstance('bool'), - matchTypeInstance('int'), - ]); - expect(await getDisplayedFields(instanceRef), { - 1: 'bool', - 'inner': '(bool, int)', - }); - - expect(await getDisplayedFields(elements[1]), {1: 'bool', 2: 'int'}); - }); - }); - - test('nested record type with named fields getters', () async { - await onBreakPoint('printNestedNamedLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - final instanceRef = await getInstanceRef(frame, 'record.runtimeType'); - final elements = await getElements(instanceRef.id!); - - expect( - await getDisplayedGetters(instanceRef), - matchDisplayedTypeObjectGetters, - ); - expect( - await getDisplayedGetters(elements[1]), - matchDisplayedTypeObjectGetters, - ); - }); - }); - - test('nested record type with named fields display', () async { - await onBreakPoint('printNestedNamedLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - final instanceRef = await getInstanceRef(frame, 'record.runtimeType'); - final instance = await getObject(instanceRef.id!); - final typeClassId = instance.classRef!.id!; - - expect(await getObject(typeClassId), matchRecordTypeClass); - - final typeStringRef = await getInstanceRef( - frame, - 'record.runtimeType.toString()', - ); - final typeStringId = typeStringRef.id!; - - expect( - await getObject(typeStringId), - matchPrimitiveInstance( - kind: InstanceKind.kString, - value: '(bool, {(bool, int) inner})', - ), - ); - }); - }); - }); -} diff --git a/dwds/test/integration/instances/common/test_inspector.dart b/dwds/test/integration/instances/common/test_inspector.dart deleted file mode 100644 index 4423659911..0000000000 --- a/dwds/test/integration/instances/common/test_inspector.dart +++ /dev/null @@ -1,454 +0,0 @@ -// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:async' show Completer, StreamSubscription; - -import 'package:path/path.dart' show basename; -import 'package:test/test.dart'; -import 'package:vm_service/vm_service.dart'; - -import '../../fixtures/context.dart'; - -class TestInspector { - TestInspector(this.context); - TestContext context; - - VmService get service => context.debugConnection.vmService; - - Future onBreakPoint( - Stream stream, - String isolateId, - ScriptRef script, - String breakPointId, - Future Function(Event event) body, - ) async { - Breakpoint? bp; - try { - final line = await context.findBreakpointLine( - breakPointId, - isolateId, - script, - ); - bp = await service.addBreakpointWithScriptUri( - isolateId, - script.uri!, - line, - ); - - final event = await stream.firstWhere( - (Event e) => e.kind == EventKind.kPauseBreakpoint, - ); - - await body(event); - } finally { - // Remove breakpoint so it doesn't impact other tests or retries. - if (bp != null) { - await service.removeBreakpoint(isolateId, bp.id!); - } - } - } - - Future> getFields( - String isolateId, - InstanceRef instanceRef, { - int? offset, - int? count, - int depth = -1, - }) async { - final instanceId = instanceRef.id!; - - final result = await service.getObject( - isolateId, - instanceId, - offset: offset, - count: count, - ); - - expect(result, isA()); - final instance = result as Instance; - - expect( - instance.kind, - instanceRef.kind, - reason: - 'object $instanceId with ref kind ${instanceRef.kind} ' - 'has an instance kind ${instance.kind}', - ); - - final fields = instance.fields; - final associations = instance.associations; - final elements = instance.elements; - - Map? fieldRefs; - if (fields != null) { - fieldRefs = _boundFieldsToMap(fields); - } else if (associations != null) { - fieldRefs = _associationsToMap(associations); - } else if (elements != null) { - fieldRefs = _elementsToMap(elements); - } else { - fieldRefs = {}; - } - - if (depth > 0) { - depth--; - } - if (depth == 0) { - return fieldRefs; - } - - final fieldValues = {}; - for (final p in fieldRefs.entries) { - fieldValues[p.key] = - _getValue(p.value) ?? - await getFields(isolateId, p.value, depth: depth); - } - return fieldValues; - } - - Future> getGetters( - String isolateId, - InstanceRef instanceRef, - ) async { - final cls = - await service.getObject(isolateId, instanceRef.classRef!.id!) as Class; - final getters = - cls.functions?.where((f) => f.isGetter ?? false).toList() ?? []; - - final results = await Future.wait([ - for (final getter in getters) - service.evaluate(isolateId, instanceRef.id!, getter.name!), - ]); - - return Map.fromIterables( - getters.map((e) => e.name!), - results.map((e) => e as InstanceRef), - ); - } - - Future getInstanceRef( - String isolateId, - int frame, - String expression, - ) async { - final result = await service.evaluateInFrame(isolateId, frame, expression); - expect(result, isA()); - return result as InstanceRef; - } - - Future getInstance( - String isolateId, - int frame, - String expression, - ) async { - final instanceRef = await getInstanceRef(isolateId, frame, expression); - - expect(instanceRef.id, isNotNull); - final result = await service.getObject(isolateId, instanceRef.id!); - - expect(result, isA()); - return result as Instance; - } - - Future> getFrameVariables( - String isolateId, - Frame frame, - ) async { - final refs = { - for (final variable in frame.vars!) - variable.name!: variable.value as InstanceRef, - }; - final instances = {}; - for (final p in refs.entries) { - instances[p.key] = - await service.getObject(isolateId, p.value.id!) as Instance; - } - return instances; - } - - Future getDisplayedRef( - String isolateId, - String instanceId, - ) async => - await service.invoke(isolateId, instanceId, 'toString', []) - as InstanceRef; - - Future> getDisplayedFields( - String isolateId, - InstanceRef ref, - ) async { - final fieldRefs = - await getFields(isolateId, ref, depth: 1) as Map; - - Future toStringValue(InstanceRef ref) async => - ref.valueAsString ?? - (await getDisplayedRef(isolateId, ref.id!)).valueAsString; - - final fields = await Future.wait(fieldRefs.values.map(toStringValue)); - return Map.fromIterables(fieldRefs.keys, fields); - } - - Future> getDisplayedGetters( - String isolateId, - InstanceRef ref, - ) async { - final fieldRefs = - await getGetters(isolateId, ref) as Map; - - Future toStringValue(InstanceRef ref) async => - ref.valueAsString ?? - (await getDisplayedRef(isolateId, ref.id!)).valueAsString; - - final fields = await Future.wait(fieldRefs.values.map(toStringValue)); - return Map.fromIterables(fieldRefs.keys, fields); - } - - Future> getElements( - String isolateId, - String instanceId, - ) async { - final instance = await service.getObject(isolateId, instanceId) as Instance; - return Future.wait( - instance.fields!.map( - (e) async => - await service.getObject(isolateId, (e.value as InstanceRef).id!) - as Instance, - ), - ); - } - - Future _locationToString( - VmService service, - String isolateId, - SourceLocation location, - ) async { - final script = - await service.getObject(isolateId, location.script!.id!) as Script; - final scriptName = basename(script.uri!); - final tokenPos = location.tokenPos!; - final line = script.getLineNumberFromTokenPos(tokenPos); - final column = script.getColumnNumberFromTokenPos(tokenPos); - return '$scriptName:$line:$column'; - } - - Future runStepIntoThroughProgramRecordingStops( - String isolateId, - - /// A list to which the pause location is added after each single-step. - List recordedStops, - - /// A limit on the number of stops to record. - /// - /// The program will not be resumed after the length of `recordedStops` - /// becomes `numStops`. - int numStops, - ) async { - final completer = Completer(); - - late StreamSubscription subscription; - subscription = service.onDebugEvent.listen((event) async { - if (event.kind == EventKind.kPauseInterrupted) { - final isolate = await service.getIsolate(isolateId); - final frame = isolate.pauseEvent!.topFrame!; - recordedStops.add( - await _locationToString(service, isolateId, frame.location!), - ); - if (recordedStops.length == numStops) { - await subscription.cancel(); - completer.complete(); - } - await service.resume(isolateId, step: StepOption.kInto); - } else if (event.kind == EventKind.kPauseExit) { - await subscription.cancel(); - completer.complete(); - } - }); - await service.resume(isolateId, step: StepOption.kInto); - await completer.future; - } -} - -Map _associationsToMap( - Iterable associations, -) => Map.fromEntries( - associations.map( - (e) => - MapEntry((e.key as InstanceRef).valueAsString!, e.value as InstanceRef), - ), -); - -Map _boundFieldsToMap(Iterable fields) => - Map.fromEntries( - fields - .where((e) => e.name != null) - .map((e) => MapEntry(e.name, e.value as InstanceRef)), - ); - -Map _elementsToMap(List fields) => - Map.fromEntries( - fields - .where((e) => e != null) - .map((e) => MapEntry(fields.indexOf(e), e as InstanceRef)), - ); - -Matcher matchRecordInstanceRef({required int length}) => isA() - .having((e) => e.kind, 'kind', InstanceKind.kRecord) - .having((e) => e.length, 'length', length) - .having((e) => e.classRef!, 'classRef', matchRecordClassRef); - -Matcher matchRecordTypeInstanceRef({required int length}) => isA() - .having((e) => e.kind, 'kind', InstanceKind.kRecordType) - .having((e) => e.length, 'length', length) - .having((e) => e.classRef!, 'classRef', matchRecordTypeClassRef); - -Matcher matchTypeInstanceRef(dynamic name) => isA() - .having((e) => e.kind, 'kind', InstanceKind.kType) - .having((e) => e.name, 'type ref name', name) - .having((e) => e.classRef, 'classRef', matchTypeClassRef); - -Matcher matchPrimitiveInstanceRef({required String kind}) => - isA().having((e) => e.kind, 'kind', kind); - -Matcher matchPrimitiveInstance({ - required String kind, - required dynamic value, -}) => isA() - .having((e) => e.kind, 'kind', kind) - .having(_getValue, 'value', value); - -Matcher matchPlainInstance({required String libraryId, required String type}) => - isA() - .having((e) => e.kind, 'kind', InstanceKind.kPlainInstance) - .having( - (e) => e.classRef, - 'classRef', - matchClassRef(name: type, libraryId: libraryId), - ); - -Matcher matchListInstance({required String type}) => isA() - .having((e) => e.kind, 'kind', InstanceKind.kList) - .having((e) => e.classRef, 'classRef', matchListClassRef(type)); - -Matcher matchMapInstance({required String type}) => isA() - .having((e) => e.kind, 'kind', InstanceKind.kMap) - .having((e) => e.classRef, 'classRef', matchMapClassRef(type)); - -Matcher matchSetInstance({required String type}) => isA() - .having((e) => e.kind, 'kind', InstanceKind.kSet) - .having((e) => e.classRef, 'classRef', matchSetClassRef(type)); - -Matcher matchRecordInstance({required int length}) => isA() - .having((e) => e.kind, 'kind', InstanceKind.kRecord) - .having((e) => e.length, 'length', length) - .having((e) => e.classRef, 'classRef', matchRecordClassRef); - -Matcher matchRecordTypeInstance({required int length}) => isA() - .having((e) => e.kind, 'kind', InstanceKind.kRecordType) - .having((e) => e.length, 'length', length) - .having((e) => e.classRef, 'classRef', matchRecordTypeClassRef); - -Matcher matchTypeStringInstance(dynamic name) => - matchPrimitiveInstance(kind: InstanceKind.kString, value: name); - -Matcher matchTypeInstance(dynamic name) => isA() - .having((e) => e.kind, 'kind', InstanceKind.kType) - .having((e) => e.name, 'type name', name) - .having((e) => e.classRef, 'classRef', matchTypeClassRef); - -Matcher matchRecordClass = matchClass( - name: matchRecordClassName, - libraryId: _dartCoreLibrary, -); -Matcher matchTypeClass = matchClass( - name: matchTypeClassName, - libraryId: _dartCoreLibrary, -); - -/// TODO(annagrin): record type class is reported incorrectly -/// in ddc https://github.com/dart-lang/sdk/issues/54609, -/// remove when fixed. -Matcher matchRecordTypeClass = anyOf( - matchTypeClass, - matchClass(name: matchRecordTypeClassName, libraryId: _dartRuntimeLibrary), -); - -Matcher matchClass({dynamic name, String? libraryId}) => isA() - .having((e) => e.name, 'class name', name) - .having((e) => e.library, 'library', matchLibraryRef(libraryId)); - -Matcher matchRecordClassRef = matchClassRef( - name: matchRecordClassName, - libraryId: _dartCoreLibrary, -); - -/// TODO(annagrin): record type class is reported incorrectly -/// in ddc https://github.com/dart-lang/sdk/issues/54609, -/// remove when fixed. -Matcher matchRecordTypeClassRef = anyOf( - matchTypeClassRef, - matchClassRef(name: matchRecordTypeClassName, libraryId: _dartRuntimeLibrary), -); -Matcher matchTypeClassRef = matchClassRef( - name: matchTypeClassName, - libraryId: _dartCoreLibrary, -); -Matcher matchListClassRef(String type) => matchClassRef( - name: matchListClassName(type), - libraryId: _matchListLibraryName, -); -Matcher matchMapClassRef(String type) => - matchClassRef(name: type, libraryId: _dartJsHelperLibrary); -Matcher matchSetClassRef(String type) => - matchClassRef(name: type, libraryId: _dartJsHelperLibrary); - -Matcher matchClassRef({dynamic name, dynamic libraryId}) => isA() - .having((e) => e.name, 'class ref name', name) - .having((e) => e.library, 'library', matchLibraryRef(libraryId)); - -Matcher matchLibraryRef(dynamic libraryId) => isA() - .having((e) => e.name, 'library name', libraryId) - .having((e) => e.id, 'id', libraryId) - .having((e) => e.uri, 'uri', libraryId); - -Object? _getValue(InstanceRef instanceRef) { - switch (instanceRef.kind) { - case InstanceKind.kBool: - return instanceRef.valueAsString == 'true'; - case InstanceKind.kDouble: - case InstanceKind.kInt: - return double.parse(instanceRef.valueAsString!); - case InstanceKind.kString: - return instanceRef.valueAsString; - default: - return null; - } -} - -final _dartCoreLibrary = 'dart:core'; -final _dartInterceptorsLibrary = 'dart:_interceptors'; -final _dartJsHelperLibrary = 'dart:_js_helper'; -final _dartRuntimeLibrary = 'dart:_runtime'; - -final matchRecordClassName = 'Record'; - -/// Match types for old and new type systems. -/// - Old type system has -/// - for arrays: `dart:_interceptors|List` -/// - for type: `dart:_runtime|_Type`. -/// - New type system has -/// - for arrays: dart:_interceptors|JSArray`, and -/// - for type: `dart:core|Type`. -/// TODO(annagrin): remove old matchers when DDC enables new type system. -/// TODO(annagrin): `matchTypeClassName` is reported incorrectly -/// in ddc https://github.com/dart-lang/sdk/issues/54609, -final matchTypeClassName = anyOf(['Type', '_Type']); -final matchRecordTypeClassName = 'RecordType'; - -Matcher matchListClassName(String elementType) => - anyOf(['JSArray<$elementType>', 'List<$elementType>']); - -final _matchListLibraryName = anyOf([ - _dartInterceptorsLibrary, - _dartCoreLibrary, -]); diff --git a/dwds/test/integration/instances/common/type_inspection_common.dart b/dwds/test/integration/instances/common/type_inspection_common.dart deleted file mode 100644 index cc45462d98..0000000000 --- a/dwds/test/integration/instances/common/type_inspection_common.dart +++ /dev/null @@ -1,347 +0,0 @@ -// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'package:dwds/expression_compiler.dart'; -import 'package:dwds_test_common/logging.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; -import 'package:vm_service/vm_service.dart'; - -import '../../fixtures/context.dart'; -import '../../fixtures/project.dart'; -import '../../fixtures/utilities.dart'; -import 'test_inspector.dart'; - -void runTests({ - required TestSdkConfigurationProvider provider, - required CompilationMode compilationMode, - required bool canaryFeatures, -}) { - final project = TestProject.testExperiment; - final context = TestContext(project, provider); - final testInspector = TestInspector(context); - - late VmService service; - late Stream stream; - late String isolateId; - late ScriptRef mainScript; - - Future onBreakPoint( - String breakPointId, - Future Function(Event) body, - ) => testInspector.onBreakPoint( - stream, - isolateId, - mainScript, - breakPointId, - body, - ); - - Future getObject(String instanceId) => - service.getObject(isolateId, instanceId); - - Future> getDisplayedFields(InstanceRef instanceRef) => - testInspector.getDisplayedFields(isolateId, instanceRef); - - Future> getDisplayedGetters(InstanceRef instanceRef) => - testInspector.getDisplayedGetters(isolateId, instanceRef); - - Future getInstanceRef(int frame, String expression) => - testInspector.getInstanceRef(isolateId, frame, expression); - - Future> getFields( - InstanceRef instanceRef, { - int? offset, - int? count, - int depth = -1, - }) => testInspector.getFields( - isolateId, - instanceRef, - offset: offset, - count: count, - depth: depth, - ); - - Future> getElements(String instanceId) => - testInspector.getElements(isolateId, instanceId); - - final matchTypeObjectFields = { - if (provider.ddcModuleFormat == ModuleFormat.ddc) '_rti': anything, - }; - - final matchDisplayedTypeObjectFields = { - if (provider.ddcModuleFormat == ModuleFormat.ddc) '_rti': anything, - }; - - final matchDisplayedTypeObjectGetters = { - 'hashCode': matches('[0-9]*'), - 'runtimeType': matchTypeClassName, - }; - - group('$compilationMode |', () { - setUpAll(() async { - setCurrentLogWriter(debug: provider.verbose); - await context.setUp( - testSettings: TestSettings( - compilationMode: compilationMode, - enableExpressionEvaluation: true, - verboseCompiler: provider.verbose, - experiments: ['dot-shorthands'], - canaryFeatures: canaryFeatures, - moduleFormat: provider.ddcModuleFormat, - ), - ); - service = context.debugConnection.vmService; - - final vm = await service.getVM(); - isolateId = vm.isolates!.first.id!; - final scripts = await service.getScripts(isolateId); - - await service.streamListen('Debug'); - stream = service.onEvent('Debug'); - - mainScript = scripts.scripts!.firstWhere( - (each) => each.uri!.contains('main.dart'), - ); - }); - - tearDownAll(() async { - await context.tearDown(); - }); - - setUp(() => setCurrentLogWriter(debug: provider.verbose)); - tearDown(() => service.resume(isolateId)); - - test('String type', () async { - await onBreakPoint('printSimpleLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - final instanceRef = await getInstanceRef(frame, "'1'.runtimeType"); - expect(instanceRef, matchTypeInstanceRef('String')); - - final instanceId = instanceRef.id!; - final instance = await getObject(instanceId); - expect(instance, matchTypeInstance('String')); - - final classId = instanceRef.classRef!.id!; - expect(await getObject(classId), matchTypeClass); - expect(await getFields(instanceRef, depth: 1), matchTypeObjectFields); - expect( - await getDisplayedFields(instanceRef), - matchDisplayedTypeObjectFields, - ); - }); - }); - - test('String type getters', () async { - await onBreakPoint('printSimpleLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - final instanceRef = await getInstanceRef(frame, "'1'.runtimeType"); - - expect( - await getDisplayedGetters(instanceRef), - matchDisplayedTypeObjectGetters, - ); - }); - }); - - test('int type', () async { - await onBreakPoint('printSimpleLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - final instanceRef = await getInstanceRef(frame, '1.runtimeType'); - expect(instanceRef, matchTypeInstanceRef('int')); - - final instanceId = instanceRef.id!; - final instance = await getObject(instanceId); - expect(instance, matchTypeInstance('int')); - - final classId = instanceRef.classRef!.id!; - expect(await getObject(classId), matchTypeClass); - expect(await getFields(instanceRef, depth: 1), matchTypeObjectFields); - expect( - await getDisplayedFields(instanceRef), - matchDisplayedTypeObjectFields, - ); - }); - }); - - test('int type getters', () async { - await onBreakPoint('printSimpleLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - final instanceRef = await getInstanceRef(frame, '1.runtimeType'); - - expect( - await getDisplayedGetters(instanceRef), - matchDisplayedTypeObjectGetters, - ); - }); - }); - - test('list type', () async { - await onBreakPoint('printSimpleLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - final instanceRef = await getInstanceRef(frame, '[].runtimeType'); - expect(instanceRef, matchTypeInstanceRef('List')); - - final instanceId = instanceRef.id!; - final instance = await getObject(instanceId); - expect(instance, matchTypeInstance('List')); - - final classId = instanceRef.classRef!.id!; - expect(await getObject(classId), matchTypeClass); - expect(await getFields(instanceRef, depth: 1), matchTypeObjectFields); - expect( - await getDisplayedFields(instanceRef), - matchDisplayedTypeObjectFields, - ); - expect( - await getDisplayedGetters(instanceRef), - matchDisplayedTypeObjectGetters, - ); - }); - }); - - test('map type', () async { - await onBreakPoint('printSimpleLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - final instanceRef = await getInstanceRef( - frame, - '{}.runtimeType', - ); - expect(instanceRef, matchTypeInstanceRef('IdentityMap')); - - final instanceId = instanceRef.id!; - final instance = await getObject(instanceId); - expect(instance, matchTypeInstance('IdentityMap')); - - final classId = instanceRef.classRef!.id!; - expect(await getObject(classId), matchTypeClass); - expect(await getFields(instanceRef, depth: 1), matchTypeObjectFields); - expect( - await getDisplayedFields(instanceRef), - matchDisplayedTypeObjectFields, - ); - }); - }); - - test('map type getters', () async { - await onBreakPoint('printSimpleLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - final instanceRef = await getInstanceRef( - frame, - '{}.runtimeType', - ); - - expect( - await getDisplayedGetters(instanceRef), - matchDisplayedTypeObjectGetters, - ); - }); - }); - - test('set type', () async { - await onBreakPoint('printSimpleLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - final instanceRef = await getInstanceRef(frame, '{}.runtimeType'); - expect(instanceRef, matchTypeInstanceRef('IdentitySet')); - - final instanceId = instanceRef.id!; - final instance = await getObject(instanceId); - expect(instance, matchTypeInstance('IdentitySet')); - - final classId = instanceRef.classRef!.id!; - expect(await getObject(classId), matchTypeClass); - expect(await getFields(instanceRef, depth: 1), matchTypeObjectFields); - expect( - await getDisplayedFields(instanceRef), - matchDisplayedTypeObjectFields, - ); - }); - }); - - test('set type getters', () async { - await onBreakPoint('printSimpleLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - final instanceRef = await getInstanceRef(frame, '{}.runtimeType'); - - expect( - await getDisplayedGetters(instanceRef), - matchDisplayedTypeObjectGetters, - ); - }); - }); - - test('record type', () async { - await onBreakPoint('printSimpleLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - final instanceRef = await getInstanceRef(frame, "(0,'a').runtimeType"); - expect(instanceRef, matchRecordTypeInstanceRef(length: 2)); - - final instanceId = instanceRef.id!; - final instance = await getObject(instanceId); - expect(instance, matchRecordTypeInstance(length: 2)); - expect(await getElements(instanceId), [ - matchTypeInstance('int'), - matchTypeInstance('String'), - ]); - - final classId = instanceRef.classRef!.id!; - expect(await getObject(classId), matchRecordTypeClass); - expect(await getFields(instanceRef, depth: 2), { - 1: matchTypeObjectFields, - 2: matchTypeObjectFields, - }); - expect(await getDisplayedFields(instanceRef), {1: 'int', 2: 'String'}); - }); - }); - - test('record type getters', () async { - await onBreakPoint('printSimpleLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - final instanceRef = await getInstanceRef(frame, "(0,'a').runtimeType"); - - expect( - await getDisplayedGetters(instanceRef), - matchDisplayedTypeObjectGetters, - ); - }); - }); - - test('class type', () async { - await onBreakPoint('printSimpleLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - final instanceRef = await getInstanceRef( - frame, - "Uri.file('').runtimeType", - ); - expect(instanceRef, matchTypeInstanceRef('_Uri')); - - final instanceId = instanceRef.id!; - final instance = await getObject(instanceId); - expect(instance, matchTypeInstance('_Uri')); - final classId = instanceRef.classRef!.id!; - expect(await getObject(classId), matchTypeClass); - expect(await getFields(instanceRef, depth: 1), matchTypeObjectFields); - expect( - await getDisplayedFields(instanceRef), - matchDisplayedTypeObjectFields, - ); - }); - }); - - test('class type getters', () async { - await onBreakPoint('printSimpleLocalRecord', (Event event) async { - final frame = event.topFrame!.index!; - final instanceRef = await getInstanceRef( - frame, - "Uri.file('').runtimeType", - ); - - expect( - await getDisplayedGetters(instanceRef), - matchDisplayedTypeObjectGetters, - ); - }); - }); - }); -} diff --git a/dwds/test/integration/instances/dot_shorthands_amd_test.dart b/dwds/test/integration/instances/dot_shorthands_amd_test.dart deleted file mode 100644 index 7ae4963827..0000000000 --- a/dwds/test/integration/instances/dot_shorthands_amd_test.dart +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@Tags(['daily']) -@TestOn('vm') -@Timeout(Duration(minutes: 2)) -library; - -import 'package:dwds/src/services/expression_compiler.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; - -import '../fixtures/context.dart'; -import 'common/dot_shorthands_common.dart'; - -void main() { - // Enable verbose logging for debugging. - const debug = false; - - group('canary: false | Build Daemon |', () { - final canaryFeatures = false; - final compilationMode = CompilationMode.buildDaemon; - final provider = TestSdkConfigurationProvider( - verbose: debug, - canaryFeatures: canaryFeatures, - ddcModuleFormat: ModuleFormat.amd, - ); - tearDownAll(provider.dispose); - - runTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); - - group('canary: true | Build Daemon |', () { - final canaryFeatures = true; - final compilationMode = CompilationMode.buildDaemon; - final provider = TestSdkConfigurationProvider( - verbose: debug, - canaryFeatures: canaryFeatures, - ddcModuleFormat: ModuleFormat.amd, - ); - tearDownAll(provider.dispose); - - runTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); - - group('canary: false | Frontend Server |', () { - final canaryFeatures = false; - final compilationMode = CompilationMode.frontendServer; - final provider = TestSdkConfigurationProvider( - verbose: debug, - canaryFeatures: canaryFeatures, - ddcModuleFormat: ModuleFormat.amd, - ); - tearDownAll(provider.dispose); - - runTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); - - group('canary: true | Frontend Server |', () { - final canaryFeatures = true; - final compilationMode = CompilationMode.frontendServer; - final provider = TestSdkConfigurationProvider( - verbose: debug, - canaryFeatures: canaryFeatures, - ddcModuleFormat: ModuleFormat.amd, - ); - tearDownAll(provider.dispose); - - runTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); -} diff --git a/dwds/test/integration/instances/dot_shorthands_ddc_library_bundle_test.dart b/dwds/test/integration/instances/dot_shorthands_ddc_library_bundle_test.dart deleted file mode 100644 index 3559490635..0000000000 --- a/dwds/test/integration/instances/dot_shorthands_ddc_library_bundle_test.dart +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@Tags(['daily']) -@TestOn('vm') -@Timeout(Duration(minutes: 2)) -library; - -import 'package:dwds/src/services/expression_compiler.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; - -import '../fixtures/context.dart'; -import 'common/dot_shorthands_common.dart'; - -void main() { - // Enable verbose logging for debugging. - const debug = false; - - group('canary: true | Frontend Server |', () { - final canaryFeatures = true; - final compilationMode = CompilationMode.frontendServer; - final provider = TestSdkConfigurationProvider( - verbose: debug, - canaryFeatures: canaryFeatures, - ddcModuleFormat: ModuleFormat.ddc, - ); - tearDownAll(provider.dispose); - - runTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); - - group('canary: true | Build Daemon |', () { - final canaryFeatures = true; - final compilationMode = CompilationMode.buildDaemon; - final provider = TestSdkConfigurationProvider( - verbose: debug, - canaryFeatures: canaryFeatures, - ddcModuleFormat: ModuleFormat.ddc, - ); - tearDownAll(provider.dispose); - - runTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); -} diff --git a/dwds/test/integration/instances/instance_amd_test.dart b/dwds/test/integration/instances/instance_amd_test.dart deleted file mode 100644 index af28c889cb..0000000000 --- a/dwds/test/integration/instances/instance_amd_test.dart +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@Tags(['daily']) -@Timeout(Duration(minutes: 2)) -library; - -import 'package:dwds/src/services/expression_compiler.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; - -import '../fixtures/context.dart'; -import 'common/instance_common.dart'; - -void main() { - // Enable verbose logging for debugging. - const debug = false; - final moduleFormat = ModuleFormat.amd; - - group('canary: false | Build Daemon |', () { - final canaryFeatures = false; - final compilationMode = CompilationMode.buildDaemon; - final provider = TestSdkConfigurationProvider( - canaryFeatures: canaryFeatures, - verbose: debug, - ddcModuleFormat: moduleFormat, - ); - tearDownAll(provider.dispose); - - runTypeSystemVerificationTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - - runTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); - - group('canary: true | Build Daemon |', () { - final canaryFeatures = true; - final compilationMode = CompilationMode.buildDaemon; - final provider = TestSdkConfigurationProvider( - canaryFeatures: canaryFeatures, - verbose: debug, - ddcModuleFormat: moduleFormat, - ); - tearDownAll(provider.dispose); - - runTypeSystemVerificationTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - - runTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); - - group('canary: false | Frontend Server |', () { - final canaryFeatures = false; - final compilationMode = CompilationMode.frontendServer; - final provider = TestSdkConfigurationProvider( - canaryFeatures: canaryFeatures, - verbose: debug, - ddcModuleFormat: moduleFormat, - ); - tearDownAll(provider.dispose); - - runTypeSystemVerificationTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - - runTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); - - group('canary: true | Frontend Server |', () { - final canaryFeatures = true; - final compilationMode = CompilationMode.frontendServer; - final provider = TestSdkConfigurationProvider( - canaryFeatures: canaryFeatures, - verbose: debug, - ddcModuleFormat: moduleFormat, - ); - tearDownAll(provider.dispose); - - runTypeSystemVerificationTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - - runTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); -} diff --git a/dwds/test/integration/instances/instance_ddc_library_bundle_test.dart b/dwds/test/integration/instances/instance_ddc_library_bundle_test.dart deleted file mode 100644 index 002c71c57e..0000000000 --- a/dwds/test/integration/instances/instance_ddc_library_bundle_test.dart +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@Tags(['daily']) -@Timeout(Duration(minutes: 2)) -library; - -import 'package:dwds/src/services/expression_compiler.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; - -import '../fixtures/context.dart'; -import 'common/instance_common.dart'; - -void main() { - // Enable verbose logging for debugging. - const debug = false; - final canaryFeatures = true; - final moduleFormat = ModuleFormat.ddc; - - group('canary: true | Frontend Server |', () { - final compilationMode = CompilationMode.frontendServer; - final provider = TestSdkConfigurationProvider( - canaryFeatures: canaryFeatures, - verbose: debug, - ddcModuleFormat: moduleFormat, - ); - tearDownAll(provider.dispose); - - runTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); - - group('canary: true | Build Daemon |', () { - final compilationMode = CompilationMode.buildDaemon; - final provider = TestSdkConfigurationProvider( - canaryFeatures: canaryFeatures, - verbose: debug, - ddcModuleFormat: moduleFormat, - ); - tearDownAll(provider.dispose); - - runTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); -} diff --git a/dwds/test/integration/instances/instance_inspection_amd_test.dart b/dwds/test/integration/instances/instance_inspection_amd_test.dart deleted file mode 100644 index 1d526c53f0..0000000000 --- a/dwds/test/integration/instances/instance_inspection_amd_test.dart +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@Tags(['daily']) -@TestOn('vm') -@Timeout(Duration(minutes: 2)) -library; - -import 'package:dwds/src/services/expression_compiler.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; - -import '../fixtures/context.dart'; -import 'common/instance_inspection_common.dart'; - -void main() { - // Enable verbose logging for debugging. - const debug = false; - - group('canary: false | Build Daemon |', () { - final canaryFeatures = false; - final compilationMode = CompilationMode.buildDaemon; - final provider = TestSdkConfigurationProvider( - verbose: debug, - canaryFeatures: canaryFeatures, - ddcModuleFormat: ModuleFormat.amd, - ); - tearDownAll(provider.dispose); - - runTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); - - group('canary: true | Build Daemon |', () { - final canaryFeatures = true; - final compilationMode = CompilationMode.buildDaemon; - final provider = TestSdkConfigurationProvider( - verbose: debug, - canaryFeatures: canaryFeatures, - ddcModuleFormat: ModuleFormat.amd, - ); - tearDownAll(provider.dispose); - - runTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); - - group('canary: false | Frontend Server |', () { - final canaryFeatures = false; - final compilationMode = CompilationMode.frontendServer; - final provider = TestSdkConfigurationProvider( - verbose: debug, - canaryFeatures: canaryFeatures, - ddcModuleFormat: ModuleFormat.amd, - ); - tearDownAll(provider.dispose); - - runTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); - - group('canary: true | Frontend Server |', () { - final canaryFeatures = true; - final compilationMode = CompilationMode.frontendServer; - final provider = TestSdkConfigurationProvider( - verbose: debug, - canaryFeatures: canaryFeatures, - ddcModuleFormat: ModuleFormat.amd, - ); - tearDownAll(provider.dispose); - - runTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); -} diff --git a/dwds/test/integration/instances/patterns_inspection_amd_test.dart b/dwds/test/integration/instances/patterns_inspection_amd_test.dart deleted file mode 100644 index cb52f7307f..0000000000 --- a/dwds/test/integration/instances/patterns_inspection_amd_test.dart +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@Tags(['daily']) -@TestOn('vm') -@Timeout(Duration(minutes: 2)) -library; - -import 'package:dwds/expression_compiler.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; - -import '../fixtures/context.dart'; -import 'common/patterns_inspection_common.dart'; - -void main() { - // Enable verbose logging for debugging. - const debug = false; - - group('canary: false | Build Daemon |', () { - final canaryFeatures = false; - final compilationMode = CompilationMode.buildDaemon; - final provider = TestSdkConfigurationProvider( - verbose: debug, - canaryFeatures: canaryFeatures, - ddcModuleFormat: ModuleFormat.amd, - ); - tearDownAll(provider.dispose); - - runTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); - - group('canary: true | Build Daemon |', () { - final canaryFeatures = true; - final compilationMode = CompilationMode.buildDaemon; - final provider = TestSdkConfigurationProvider( - verbose: debug, - canaryFeatures: canaryFeatures, - ddcModuleFormat: ModuleFormat.amd, - ); - tearDownAll(provider.dispose); - - runTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); - - group('canary: false | Frontend Server |', () { - final canaryFeatures = false; - final compilationMode = CompilationMode.frontendServer; - final provider = TestSdkConfigurationProvider( - verbose: debug, - canaryFeatures: canaryFeatures, - ddcModuleFormat: ModuleFormat.amd, - ); - tearDownAll(provider.dispose); - - runTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); - - group('canary: true | Frontend Server |', () { - final canaryFeatures = true; - final compilationMode = CompilationMode.frontendServer; - final provider = TestSdkConfigurationProvider( - verbose: debug, - canaryFeatures: canaryFeatures, - ddcModuleFormat: ModuleFormat.amd, - ); - tearDownAll(provider.dispose); - - runTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); -} diff --git a/dwds/test/integration/instances/patterns_inspection_ddc_library_bundle_test.dart b/dwds/test/integration/instances/patterns_inspection_ddc_library_bundle_test.dart deleted file mode 100644 index e9a5e0fd96..0000000000 --- a/dwds/test/integration/instances/patterns_inspection_ddc_library_bundle_test.dart +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@Tags(['daily']) -@TestOn('vm') -@Timeout(Duration(minutes: 2)) -library; - -import 'package:dwds/expression_compiler.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; - -import '../fixtures/context.dart'; -import 'common/patterns_inspection_common.dart'; - -void main() { - // Enable verbose logging for debugging. - const debug = false; - - group('canary: true | Frontend Server |', () { - final canaryFeatures = true; - final compilationMode = CompilationMode.frontendServer; - final provider = TestSdkConfigurationProvider( - verbose: debug, - canaryFeatures: canaryFeatures, - ddcModuleFormat: ModuleFormat.ddc, - ); - tearDownAll(provider.dispose); - - runTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); - - group('canary: true | Build Daemon |', () { - final canaryFeatures = true; - final compilationMode = CompilationMode.buildDaemon; - final provider = TestSdkConfigurationProvider( - verbose: debug, - canaryFeatures: canaryFeatures, - ddcModuleFormat: ModuleFormat.ddc, - ); - tearDownAll(provider.dispose); - - runTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); -} diff --git a/dwds/test/integration/instances/record_inspection_amd_test.dart b/dwds/test/integration/instances/record_inspection_amd_test.dart deleted file mode 100644 index 0cd64a97ee..0000000000 --- a/dwds/test/integration/instances/record_inspection_amd_test.dart +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@Tags(['daily']) -@TestOn('vm') -@Timeout(Duration(minutes: 2)) -library; - -import 'package:dwds/src/services/expression_compiler.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; - -import '../fixtures/context.dart'; -import 'common/record_inspection_common.dart'; - -void main() { - // Enable verbose logging for debugging. - const debug = false; - - group('canary: false | Build Daemon |', () { - final canaryFeatures = false; - final compilationMode = CompilationMode.buildDaemon; - final provider = TestSdkConfigurationProvider( - verbose: debug, - canaryFeatures: canaryFeatures, - ddcModuleFormat: ModuleFormat.amd, - ); - tearDownAll(provider.dispose); - - runTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); - - group('canary: true | Build Daemon |', () { - final canaryFeatures = true; - final compilationMode = CompilationMode.buildDaemon; - final provider = TestSdkConfigurationProvider( - verbose: debug, - canaryFeatures: canaryFeatures, - ddcModuleFormat: ModuleFormat.amd, - ); - tearDownAll(provider.dispose); - - runTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); - - group('canary: false | Frontend Server |', () { - final canaryFeatures = false; - final compilationMode = CompilationMode.frontendServer; - final provider = TestSdkConfigurationProvider( - verbose: debug, - canaryFeatures: canaryFeatures, - ddcModuleFormat: ModuleFormat.amd, - ); - tearDownAll(provider.dispose); - - runTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); - - group('canary: true | Frontend Server |', () { - final canaryFeatures = true; - final compilationMode = CompilationMode.frontendServer; - final provider = TestSdkConfigurationProvider( - verbose: debug, - canaryFeatures: canaryFeatures, - ddcModuleFormat: ModuleFormat.amd, - ); - tearDownAll(provider.dispose); - - runTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); -} diff --git a/dwds/test/integration/instances/record_inspection_ddc_library_bundle_test.dart b/dwds/test/integration/instances/record_inspection_ddc_library_bundle_test.dart deleted file mode 100644 index 0201c28224..0000000000 --- a/dwds/test/integration/instances/record_inspection_ddc_library_bundle_test.dart +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@Tags(['daily']) -@TestOn('vm') -@Timeout(Duration(minutes: 2)) -library; - -import 'package:dwds/src/services/expression_compiler.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; - -import '../fixtures/context.dart'; -import 'common/record_inspection_common.dart'; - -void main() { - // Enable verbose logging for debugging. - const debug = false; - final canaryFeatures = true; - - group('canary: true | Frontend Server |', () { - final compilationMode = CompilationMode.frontendServer; - final provider = TestSdkConfigurationProvider( - verbose: debug, - canaryFeatures: canaryFeatures, - ddcModuleFormat: ModuleFormat.ddc, - ); - tearDownAll(provider.dispose); - runTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); - - group('canary: true | Build Daemon |', () { - final compilationMode = CompilationMode.buildDaemon; - final provider = TestSdkConfigurationProvider( - verbose: debug, - canaryFeatures: canaryFeatures, - ddcModuleFormat: ModuleFormat.ddc, - ); - tearDownAll(provider.dispose); - runTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); -} diff --git a/dwds/test/integration/instances/record_type_inspection_amd_test.dart b/dwds/test/integration/instances/record_type_inspection_amd_test.dart deleted file mode 100644 index 618ef53ed1..0000000000 --- a/dwds/test/integration/instances/record_type_inspection_amd_test.dart +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@Tags(['daily']) -@TestOn('vm') -@Timeout(Duration(minutes: 2)) -library; - -import 'package:dwds/src/services/expression_compiler.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; - -import '../fixtures/context.dart'; -import 'common/record_type_inspection_common.dart'; - -void main() { - // Enable verbose logging for debugging. - const debug = false; - - group('canary: false | Build Daemon |', () { - final canaryFeatures = false; - final compilationMode = CompilationMode.buildDaemon; - final provider = TestSdkConfigurationProvider( - verbose: debug, - canaryFeatures: canaryFeatures, - ddcModuleFormat: ModuleFormat.amd, - ); - tearDownAll(provider.dispose); - - runTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); - - group('canary: true | Build Daemon |', () { - final canaryFeatures = true; - final compilationMode = CompilationMode.buildDaemon; - final provider = TestSdkConfigurationProvider( - verbose: debug, - canaryFeatures: canaryFeatures, - ddcModuleFormat: ModuleFormat.amd, - ); - tearDownAll(provider.dispose); - - runTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); - - group('canary: false | Frontend Server |', () { - final canaryFeatures = false; - final compilationMode = CompilationMode.frontendServer; - final provider = TestSdkConfigurationProvider( - verbose: debug, - canaryFeatures: canaryFeatures, - ddcModuleFormat: ModuleFormat.amd, - ); - tearDownAll(provider.dispose); - - runTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); - - group('canary: true | Frontend Server |', () { - final canaryFeatures = true; - final compilationMode = CompilationMode.frontendServer; - final provider = TestSdkConfigurationProvider( - verbose: debug, - canaryFeatures: canaryFeatures, - ddcModuleFormat: ModuleFormat.amd, - ); - tearDownAll(provider.dispose); - - runTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); -} diff --git a/dwds/test/integration/instances/record_type_inspection_ddc_library_bundle_test.dart b/dwds/test/integration/instances/record_type_inspection_ddc_library_bundle_test.dart deleted file mode 100644 index 3832869b73..0000000000 --- a/dwds/test/integration/instances/record_type_inspection_ddc_library_bundle_test.dart +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@Tags(['daily']) -@TestOn('vm') -@Timeout(Duration(minutes: 2)) -library; - -import 'package:dwds/expression_compiler.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; - -import '../fixtures/context.dart'; -import 'common/record_type_inspection_common.dart'; - -void main() { - // Enable verbose logging for debugging. - const debug = false; - final canaryFeatures = true; - - group('canary: true | Frontend Server |', () { - final compilationMode = CompilationMode.frontendServer; - final provider = TestSdkConfigurationProvider( - verbose: debug, - canaryFeatures: canaryFeatures, - ddcModuleFormat: ModuleFormat.ddc, - ); - tearDownAll(provider.dispose); - runTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); - - group('canary: true | Build Daemon |', () { - final compilationMode = CompilationMode.buildDaemon; - final provider = TestSdkConfigurationProvider( - verbose: debug, - canaryFeatures: canaryFeatures, - ddcModuleFormat: ModuleFormat.ddc, - ); - tearDownAll(provider.dispose); - runTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); -} diff --git a/dwds/test/integration/instances/type_inspection_amd_test.dart b/dwds/test/integration/instances/type_inspection_amd_test.dart deleted file mode 100644 index 717952e2b2..0000000000 --- a/dwds/test/integration/instances/type_inspection_amd_test.dart +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@Tags(['daily']) -@TestOn('vm') -@Timeout(Duration(minutes: 2)) -library; - -import 'package:dwds/expression_compiler.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; - -import '../fixtures/context.dart'; -import 'common/type_inspection_common.dart'; - -void main() { - // Enable verbose logging for debugging. - const debug = false; - - group('canary: false | Build Daemon |', () { - final canaryFeatures = false; - final compilationMode = CompilationMode.buildDaemon; - final provider = TestSdkConfigurationProvider( - verbose: debug, - canaryFeatures: canaryFeatures, - ddcModuleFormat: ModuleFormat.amd, - ); - tearDownAll(provider.dispose); - - runTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); - - group('canary: true | Build Daemon |', () { - final canaryFeatures = true; - final compilationMode = CompilationMode.buildDaemon; - final provider = TestSdkConfigurationProvider( - verbose: debug, - canaryFeatures: canaryFeatures, - ddcModuleFormat: ModuleFormat.amd, - ); - tearDownAll(provider.dispose); - - runTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); - - group('canary: false | Frontend Server |', () { - final canaryFeatures = false; - final compilationMode = CompilationMode.frontendServer; - final provider = TestSdkConfigurationProvider( - verbose: debug, - canaryFeatures: canaryFeatures, - ddcModuleFormat: ModuleFormat.amd, - ); - tearDownAll(provider.dispose); - - runTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); - - group('canary: true | Frontend Server |', () { - final canaryFeatures = true; - final compilationMode = CompilationMode.frontendServer; - final provider = TestSdkConfigurationProvider( - verbose: debug, - canaryFeatures: canaryFeatures, - ddcModuleFormat: ModuleFormat.amd, - ); - tearDownAll(provider.dispose); - - runTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); -} diff --git a/dwds/test/integration/instances/type_inspection_ddc_library_bundle_test.dart b/dwds/test/integration/instances/type_inspection_ddc_library_bundle_test.dart deleted file mode 100644 index 3756541e0e..0000000000 --- a/dwds/test/integration/instances/type_inspection_ddc_library_bundle_test.dart +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@Tags(['daily']) -@TestOn('vm') -@Timeout(Duration(minutes: 2)) -library; - -import 'package:dwds/expression_compiler.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; - -import '../fixtures/context.dart'; -import 'common/type_inspection_common.dart'; - -void main() { - // Enable verbose logging for debugging. - const debug = false; - - group('canary: true | Frontend Server |', () { - final canaryFeatures = true; - final compilationMode = CompilationMode.frontendServer; - final provider = TestSdkConfigurationProvider( - verbose: debug, - canaryFeatures: canaryFeatures, - ddcModuleFormat: ModuleFormat.ddc, - ); - tearDownAll(provider.dispose); - - runTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); - - group('canary: true | Build Daemon |', () { - final canaryFeatures = true; - final compilationMode = CompilationMode.buildDaemon; - final provider = TestSdkConfigurationProvider( - verbose: debug, - canaryFeatures: canaryFeatures, - ddcModuleFormat: ModuleFormat.ddc, - ); - tearDownAll(provider.dispose); - - runTests( - provider: provider, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); -} diff --git a/dwds/test/integration/javascript_builder_test.dart b/dwds/test/integration/javascript_builder_test.dart deleted file mode 100644 index ce8bcc3f0b..0000000000 --- a/dwds/test/integration/javascript_builder_test.dart +++ /dev/null @@ -1,191 +0,0 @@ -// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@TestOn('vm') -@Timeout(Duration(minutes: 2)) -library; - -import 'package:dwds/src/services/javascript_builder.dart'; -import 'package:test/test.dart'; - -void main() async { - group('JavaScriptBuilder |', () { - test('write', () async { - expect((JsBuilder()..write('Hello')).build(), 'Hello'); - }); - - test('writeLine', () async { - expect((JsBuilder()..writeLine('Hello')).build(), 'Hello\n'); - }); - - test('writeAll with separator', () async { - expect( - (JsBuilder()..writeAll(['Hello', 'World'], ' ')).build(), - 'Hello World', - ); - }); - - test('writeAll with default separator', () async { - expect((JsBuilder()..writeAll(['Hello', 'World'])).build(), 'HelloWorld'); - }); - - test('writeWithIndent', () async { - expect((JsBuilder()..writeWithIndent('Hello')).build(), 'Hello'); - }); - - test('writeWithIndent', () async { - final jsBuilder = JsBuilder(); - jsBuilder.increaseIndent(); - jsBuilder.writeWithIndent('Hello'); - jsBuilder.decreaseIndent(); - jsBuilder.writeWithIndent('World'); - expect(jsBuilder.build(), ' HelloWorld'); - }); - - test('writeLineWithIndent', () async { - final jsBuilder = JsBuilder(); - jsBuilder.increaseIndent(); - jsBuilder.writeLineWithIndent('Hello'); - jsBuilder.decreaseIndent(); - jsBuilder.writeLineWithIndent('World'); - expect(jsBuilder.build(), ' Hello\nWorld\n'); - }); - - test('writeAllLinesWithIndent', () async { - final jsBuilder = JsBuilder(); - jsBuilder.increaseIndent(); - jsBuilder.writeMultiLineExpression(['Hello', 'World']); - jsBuilder.decreaseIndent(); - jsBuilder.writeMultiLineExpression(['Hello', 'World']); - expect(jsBuilder.build(), 'Hello\n WorldHello\nWorld'); - }); - - test('writeCallExpression', () async { - final jsBuilder = JsBuilder(); - jsBuilder.writeCallExpression(['a1', 'a2'], () => jsBuilder.write('foo')); - expect(jsBuilder.build(), 'foo(a1, a2)'); - }); - - test('writeTryCatchExpression', () async { - final jsBuilder = JsBuilder(); - jsBuilder.writeTryCatchExpression(() => jsBuilder.write('x')); - expect( - jsBuilder.build(), - 'try {\n' - ' x\n' - '} catch (error) {\n' - ' error.name + ": " + error.message;\n' - '}', - ); - }); - - test('writeTryCatchStatement', () async { - final jsBuilder = JsBuilder(); - jsBuilder.writeTryCatchStatement( - () => jsBuilder.writeReturnStatement(() => jsBuilder.write('x')), - ); - expect( - jsBuilder.build(), - 'try {\n' - ' return x;\n' - '} catch (error) {\n' - ' return error.name + ": " + error.message;\n' - '}', - ); - }); - - test('writeReturnStatement', () async { - final jsBuilder = JsBuilder(); - jsBuilder.writeReturnStatement(() => jsBuilder.write('x')); - expect(jsBuilder.build(), 'return x;'); - }); - - test('writeFunctionDefinition', () async { - final jsBuilder = JsBuilder(); - jsBuilder.writeFunctionDefinition( - ['a1', 'a2'], - () => jsBuilder.writeReturnStatement(() => jsBuilder.write('a1 + a2')), - ); - expect( - jsBuilder.build(), - 'function (a1, a2) {\n' - ' return a1 + a2;\n' - '}', - ); - }); - - test('writeBindExpression', () async { - final jsBuilder = JsBuilder(); - jsBuilder.writeBindExpression( - 'x', - () => jsBuilder.writeFunctionDefinition( - [], - () => jsBuilder.writeReturnStatement(() => jsBuilder.write('this.a')), - ), - ); - expect( - jsBuilder.build(), - 'function () {\n' - ' return this.a;\n' - '}.bind(x)', - ); - }); - - test('createEvalExpression', () async { - final expression = JsBuilder.createEvalExpression([ - 'var e = 1;', - 'return e', - ]); - expect( - expression, - 'try {\n' - ' var e = 1;\n' - ' return e;\n' - '} catch (error) {\n' - ' error.name + ": " + error.message;\n' - '}', - ); - }); - - test('createEvalStaticFunction', () async { - final function = JsBuilder.createEvalStaticFunction( - ['function(e, e2) {', ' return e;', '}'], - ['e', 'e2'], - ); - expect( - function, - 'function (e, e2) {\n' - ' try {\n' - ' return function(e, e2) {\n' - ' return e;\n' - ' }(e, e2);\n' - ' } catch (error) {\n' - ' return error.name + ": " + error.message;\n' - ' }\n' - '}', - ); - }); - - test('createEvalBoundFunction', () async { - final function = JsBuilder.createEvalBoundFunction( - ['function(e, e2) {', ' return e;', '}'], - ['e', 'e2'], - ); - expect( - function, - 'function (e, e2, __t\$this) {\n' - ' try {\n' - ' return function (e, e2) {\n' - ' return function(e, e2) {\n' - ' return e;\n' - ' }(e, e2);\n' - ' }.bind(__t\$this)(e, e2);\n' - ' } catch (error) {\n' - ' return error.name + ": " + error.message;\n' - ' }\n' - '}', - ); - }); - }); -} diff --git a/dwds/test/integration/listviews_test.dart b/dwds/test/integration/listviews_test.dart deleted file mode 100644 index a9a63b1310..0000000000 --- a/dwds/test/integration/listviews_test.dart +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@Timeout(Duration(minutes: 2)) -library; - -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; - -import 'fixtures/context.dart'; -import 'fixtures/project.dart'; - -void main() { - final provider = TestSdkConfigurationProvider(); - tearDownAll(provider.dispose); - - final context = TestContext(TestProject.test, provider); - - setUpAll(() async { - await context.setUp(); - }); - - tearDownAll(() async { - await context.tearDown(); - }); - - test('_flutter.listViews', () async { - final serviceMethod = '_flutter.listViews'; - final service = context.debugConnection.vmService; - final vm = await service.getVM(); - final isolates = vm.isolates!; - - final expected = { - 'views': [ - for (final isolate in isolates) - {'id': isolate.id, 'isolate': isolate.toJson()}, - ], - }; - - final result = await service.callServiceExtension(serviceMethod, args: {}); - - expect(result.json, expected); - }); -} diff --git a/dwds/test/integration/load_strategy_test.dart b/dwds/test/integration/load_strategy_test.dart deleted file mode 100644 index 6ca17eba9b..0000000000 --- a/dwds/test/integration/load_strategy_test.dart +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@TestOn('vm') -@Timeout(Duration(minutes: 1)) -library; - -import 'package:dwds/dwds.dart'; -import 'package:dwds/src/config/tool_configuration.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:path/path.dart' as p; -import 'package:test/test.dart'; - -import 'fixtures/context.dart'; -import 'fixtures/fakes.dart'; -import 'fixtures/project.dart'; -import 'fixtures/utilities.dart'; - -void main() { - group('Load Strategy', () { - final project = TestProject.test; - final provider = TestSdkConfigurationProvider(); - tearDownAll(provider.dispose); - - final context = TestContext(project, provider); - - setUpAll(context.setUp); - tearDownAll(context.tearDown); - - group( - 'When the packageConfigLocator does not specify a package config path', - () { - late final strategy = FakeStrategy(FakeAssetReader()); - - test('defaults to "./dart_tool/package_config.json"', () { - expect( - p.split(strategy.packageConfigPath).join('/'), - endsWith('_test/.dart_tool/package_config.json'), - ); - }); - }, - ); - - group('When a custom package config path is specified', () { - late final strategy = FakeStrategy( - FakeAssetReader(), - packageConfigPath: 'custom/package_config/path', - ); - - test('uses the specified package config path', () { - expect( - strategy.packageConfigPath, - equals('custom/package_config/path'), - ); - }); - }); - - group('When default build settings defined', () { - late final strategy = FakeStrategy( - FakeAssetReader(), - buildSettings: const TestBuildSettings.dart(), - ); - - test('uses the default app entrypoint', () { - expect(strategy.buildSettings.appEntrypoint, isNull); - }); - - test('uses the default canary features setting', () { - expect(strategy.buildSettings.canaryFeatures, isFalse); - }); - - test('uses the default flutter app setting', () { - expect(strategy.buildSettings.isFlutterApp, isFalse); - }); - - test('uses the default experiments', () { - expect(strategy.buildSettings.experiments, isEmpty); - }); - }); - - group('When custom build settings defined', () { - final appEntrypoint = Uri.parse('main.dart'); - final canaryFeatures = true; - final isFlutterApp = true; - final experiments = ['records']; - - late final strategy = FakeStrategy( - FakeAssetReader(), - buildSettings: BuildSettings( - appEntrypoint: appEntrypoint, - isFlutterApp: isFlutterApp, - canaryFeatures: canaryFeatures, - experiments: experiments, - ), - ); - - test('uses the specified app entrypoint', () { - expect(strategy.buildSettings.appEntrypoint, appEntrypoint); - }); - - test('uses the specified canary features setting', () { - expect(strategy.buildSettings.canaryFeatures, canaryFeatures); - }); - - test('uses the specified flutter app setting', () { - expect(strategy.buildSettings.isFlutterApp, isFlutterApp); - }); - - test('uses the specified experiments', () { - expect(strategy.buildSettings.experiments, experiments); - }); - }); - - group('Global load strategy with default build settings', () { - test('provides build settings', () { - final loadStrategy = globalToolConfiguration.loadStrategy; - expect( - loadStrategy.buildSettings.appEntrypoint, - project.dartEntryFilePackageUri, - ); - expect(loadStrategy.buildSettings.canaryFeatures, isFalse); - expect(loadStrategy.buildSettings.isFlutterApp, isFalse); - expect(loadStrategy.buildSettings.experiments, isEmpty); - }); - }); - }); - - group('Global load Strategy with custom build settings ', () { - final canaryFeatures = true; - final isFlutterApp = true; - final experiments = ['records']; - - final project = TestProject.test; - final provider = TestSdkConfigurationProvider( - canaryFeatures: canaryFeatures, - ); - tearDownAll(provider.dispose); - - final context = TestContext(project, provider); - - for (final compilationMode in CompilationMode.values.where( - (mode) => !mode.usesDdcModulesOnly, - )) { - group('compiled with ${compilationMode.name}', () { - setUpAll(() async { - await context.setUp( - testSettings: TestSettings( - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - isFlutterApp: isFlutterApp, - experiments: experiments, - ), - ); - }); - - tearDownAll(context.tearDown); - - test('provides custom build settings', () { - final loadStrategy = globalToolConfiguration.loadStrategy; - expect( - loadStrategy.buildSettings.appEntrypoint, - project.dartEntryFilePackageUri, - ); - expect(loadStrategy.buildSettings.canaryFeatures, canaryFeatures); - expect(loadStrategy.buildSettings.isFlutterApp, isFlutterApp); - expect(loadStrategy.buildSettings.experiments, experiments); - }); - }); - } - }); -} diff --git a/dwds/test/integration/location_test.dart b/dwds/test/integration/location_test.dart deleted file mode 100644 index e3a9143204..0000000000 --- a/dwds/test/integration/location_test.dart +++ /dev/null @@ -1,258 +0,0 @@ -// Copyright 2020 The Dart Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -@Timeout(Duration(minutes: 2)) -library; - -import 'package:dwds/src/debugging/location.dart'; -import 'package:dwds/src/utilities/dart_uri.dart'; -import 'package:test/test.dart'; - -import 'fixtures/fakes.dart'; -import 'fixtures/utilities.dart'; - -final sourceMapContents = - '{"version":3,"sourceRoot":"","sources":["main.dart"],"names":[],' - '"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAUwB,IAAtB,WAAM;AAKJ,' - 'IAHF,4BAAkB,aAAa,SAAC,GAAG;AACb,MAApB,WAAM;AACN,YAAgC,+CAAO,AAAK,oBAAO,' - 'yCAAC,WAAW;IAChE;AAC0D,IAA3D,AAAS,AAAK,0DAAO;AAAe,kBAAO;;;AAEvC,gBAAQ;' - 'AAGV,IAFI,kCAAqC,QAAC;AACX,MAA/B,WAAM,AAAwB,0BAAP,QAAF,AAAE,KAAK,GAAP;' - ';EAEzB","file":"main.ddc.js"}'; - -void main() async { - const lines = 100; - const lineLength = 150; - final assetReader = FakeAssetReader(sourceMap: sourceMapContents); - final toolConfiguration = TestToolConfiguration.withLoadStrategy( - loadStrategy: MockLoadStrategy(assetReader), - ); - setGlobalsForTesting(toolConfiguration: toolConfiguration); - final dartUri = DartUri('org-dartlang-app://web/main.dart'); - - final modules = FakeModules(module: _module); - final locations = Locations(assetReader, modules, ''); - await locations.initialize('fake_entrypoint'); - - group('JS locations |', () { - const fakeRuntimeScriptId = '12'; - - group('location |', () { - test('is zero based', () { - final loc = JsLocation.fromZeroBased( - _module, - 0, - 0, - fakeRuntimeScriptId, - ); - expect(loc, _matchJsLocation(0, 0)); - }); - - test('can compare to other location', () { - final loc00 = JsLocation.fromZeroBased( - _module, - 0, - 0, - fakeRuntimeScriptId, - ); - final loc01 = JsLocation.fromZeroBased( - _module, - 0, - 1, - fakeRuntimeScriptId, - ); - final loc10 = JsLocation.fromZeroBased( - _module, - 1, - 0, - fakeRuntimeScriptId, - ); - final loc11 = JsLocation.fromZeroBased( - _module, - 1, - 1, - fakeRuntimeScriptId, - ); - - expect(loc00.compareTo(loc01), isNegative); - expect(loc00.compareTo(loc10), isNegative); - expect(loc00.compareTo(loc10), isNegative); - expect(loc00.compareTo(loc11), isNegative); - - expect(loc00.compareTo(loc00), isZero); - expect(loc11.compareTo(loc00), isPositive); - }); - }); - - group('best location |', () { - test('does not return location for setup code', () async { - final location = await locations.locationForJs(_module, 0, 0); - expect(location, isNull); - }); - - test('prefers precise match', () async { - final location = await locations.locationForJs(_module, 37, 0); - expect(location, _matchLocationForJs(37, 0)); - }); - - test('finds a match in the beginning of the line', () async { - final location = await locations.locationForJs(_module, 39, 4); - expect(location, _matchLocationForJs(39, 0)); - }); - - test('finds a match in the middle of the line', () async { - final location = await locations.locationForJs(_module, 39, 10); - expect(location, _matchLocationForJs(39, 6)); - }); - - test('finds a match on a previous line', () async { - final location = await locations.locationForJs(_module, 44, 0); - expect(location, _matchLocationForJs(43, 18)); - }); - - test( - 'finds a match on a previous line with a closer match after', - () async { - final location = await locations.locationForJs( - _module, - 44, - lineLength - 1, - ); - expect(location, _matchLocationForJs(43, 18)); - }, - ); - - test('finds a match on the last line', () async { - final location = await locations.locationForJs( - _module, - lines - 1, - lineLength - 1, - ); - expect(location, _matchLocationForJs(50, 2)); - }); - - test('finds a match on invalid line', () async { - final location = await locations.locationForJs( - _module, - lines, - lineLength - 1, - ); - expect(location, _matchLocationForJs(50, 2)); - }); - - test('finds a match on invalid column on the same line', () async { - final location = await locations.locationForJs(_module, 50, lineLength); - expect(location, _matchLocationForJs(50, 2)); - }); - - test('finds a match on invalid column on a previous line', () async { - final location = await locations.locationForJs( - _module, - lines - 1, - lineLength, - ); - expect(location, _matchLocationForJs(50, 2)); - }); - }); - }); - - group('Dart locations |', () { - group('location |', () { - test('is one based', () async { - final loc = DartLocation.fromZeroBased(dartUri, 0, 0); - expect(loc, _matchDartLocation(1, 1)); - }); - - test('can compare to other locations', () async { - final loc00 = DartLocation.fromZeroBased(dartUri, 0, 0); - final loc01 = DartLocation.fromZeroBased(dartUri, 0, 1); - final loc10 = DartLocation.fromZeroBased(dartUri, 1, 0); - final loc11 = DartLocation.fromZeroBased(dartUri, 1, 1); - - expect(loc00.compareTo(loc01), isNegative); - expect(loc00.compareTo(loc10), isNegative); - expect(loc00.compareTo(loc10), isNegative); - expect(loc00.compareTo(loc11), isNegative); - - expect(loc00.compareTo(loc00), isZero); - expect(loc11.compareTo(loc00), isPositive); - }); - }); - - group('best location |', () { - test( - 'does not return location for dart lines not mapped to JS', - () async { - final location = await locations.locationForDart(dartUri, 0, 0); - expect(location, isNull); - }, - ); - - test('returns location after on the same line', () async { - final location = await locations.locationForDart(dartUri, 11, 0); - expect(location, _matchLocationForDart(11, 3)); - }); - - test('return null on invalid line', () async { - final location = await locations.locationForDart(dartUri, lines, 0); - expect(location, isNull); - }); - - test('return null on invalid column', () async { - final location = await locations.locationForDart( - dartUri, - lines - 1, - lineLength, - ); - expect(location, isNull); - }); - }); - }); -} - -Matcher _matchLocationForDart(int line, int column) => isA().having( - (l) => l.dartLocation, - 'dartLocation', - _matchDartLocation(line, column), -); - -Matcher _matchLocationForJs(int line, int column) => isA().having( - (l) => l.jsLocation, - 'jsLocation', - _matchJsLocation(line, column), -); - -Matcher _matchDartLocation(int line, int column) => isA() - .having((l) => l.line, 'line', line) - .having((l) => l.column, 'column', column); - -Matcher _matchJsLocation(int line, int column) => isA() - .having((l) => l.line, 'line', line) - .having((l) => l.column, 'column', column); - -const _module = 'packages/module'; -const _serverPath = 'web/main.dart'; -const _sourceMapPath = 'packages/module.js.map'; - -class MockLoadStrategy extends FakeStrategy { - MockLoadStrategy(super.assetReader); - - @override - Future moduleForServerPath( - String entrypoint, - String serverPath, - ) async => _module; - - @override - Future serverPathForModule(String entrypoint, String module) async => - _serverPath; - - @override - Future sourceMapPathForModule( - String entrypoint, - String module, - ) async => _sourceMapPath; - - @override - String serverPathForAppUri(String appUri) => _serverPath; -} diff --git a/dwds/test/integration/metadata/class_test.dart b/dwds/test/integration/metadata/class_test.dart deleted file mode 100644 index d03d307dad..0000000000 --- a/dwds/test/integration/metadata/class_test.dart +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@Timeout(Duration(minutes: 2)) -library; - -import 'package:dwds/src/debugging/metadata/class.dart'; -import 'package:test/test.dart'; - -void main() { - test('Gracefully handles invalid length objects', () async { - ClassMetaData createMetadata(dynamic length) => ClassMetaData( - length: length, - runtimeKind: RuntimeObjectKind.object, - classRef: classRefForUnknown, - ); - - var metadata = createMetadata(null); - expect(metadata.length, isNull); - - metadata = createMetadata({}); - expect(metadata.length, isNull); - - metadata = createMetadata('{}'); - expect(metadata.length, isNull); - - metadata = createMetadata(0); - expect(metadata.length, equals(0)); - }); -} diff --git a/dwds/test/integration/metadata_test.dart b/dwds/test/integration/metadata_test.dart deleted file mode 100644 index 50d12c8e1d..0000000000 --- a/dwds/test/integration/metadata_test.dart +++ /dev/null @@ -1,276 +0,0 @@ -// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@Timeout(Duration(minutes: 2)) -library; - -import 'dart:convert'; - -import 'package:dwds/src/debugging/metadata/module_metadata.dart'; -import 'package:dwds/src/debugging/metadata/provider.dart'; -import 'package:test/test.dart'; - -import 'fixtures/fakes.dart'; -import 'fixtures/utilities.dart'; - -const _emptySourceMetadata = - '{"version":"1.0.0","name":"web/main","closureName":"load__web__main",' - '"sourceMapUri":"foo/web/main.ddc.js.map",' - '"moduleUri":"foo/web/main.ddc.js",' - '"libraries":[{"name":"main",' - '"importUri":"org-dartlang-app:///web/main.dart",' - '"fileUri":"org-dartlang-app:///web/main.dart","partUris":[]}]}\n' - '// intentionally empty: package blah has no dart sources'; - -const _fileUriMetadata = - '{"version":"1.0.0","name":"web/main","closureName":"load__web__main",' - '"sourceMapUri":"foo/web/main.ddc.js.map",' - '"moduleUri":"foo/web/main.ddc.js",' - '"libraries":[{"name":"main",' - '"importUri":"file:/Users/foo/blah/sample/lib/bar.dart",' - '"fileUri":"org-dartlang-app:///web/main.dart","partUris":[]}]}\n' - '// intentionally empty: package blah has no dart sources'; - -void main() { - final toolConfiguration = TestToolConfiguration.withLoadStrategy( - loadStrategy: FakeStrategy(FakeAssetReader()), - ); - setGlobalsForTesting(toolConfiguration: toolConfiguration); - test('can parse metadata with empty sources', () async { - final provider = MetadataProvider( - 'foo.bootstrap.js', - FakeAssetReader(metadata: _emptySourceMetadata), - ); - expect( - await provider.libraries, - contains('org-dartlang-app:///web/main.dart'), - ); - }); - - test('throws on metadata with absolute import uris', () async { - final provider = MetadataProvider( - 'foo.bootstrap.js', - FakeAssetReader(metadata: _fileUriMetadata), - ); - await expectLater( - provider.libraries, - throwsA(const TypeMatcher()), - ); - }); - - test( - 'module name exists if useModuleName and otherwise use module uri', - () async { - final provider = MetadataProvider( - 'foo.bootstrap.js', - FakeAssetReader(metadata: _emptySourceMetadata), - ); - final modulePath = 'foo/web/main.ddc.js'; - final moduleName = 'web/main'; - final module = moduleName; - expect( - await provider.scriptToModule, - predicate>( - (scriptToModule) => - !scriptToModule.values.any((value) => value == modulePath), - ), - ); - expect(await provider.moduleToSourceMap, { - module: 'foo/web/main.ddc.js.map', - }); - expect(await provider.modulePathToModule, {modulePath: module}); - expect(await provider.moduleToModulePath, {module: modulePath}); - expect(await provider.modules, {module}); - }, - ); - - test('creates metadata from json', () async { - const json = { - 'version': '1.0.0', - 'name': 'web/main', - 'closureName': 'load__web__main', - 'sourceMapUri': 'foo/web/main.ddc.js.map', - 'moduleUri': 'foo/web/main.ddc.js', - 'libraries': [ - { - 'name': 'main', - 'importUri': 'org-dartlang-app:///web/main.dart', - 'partUris': ['org-dartlang-app:///web/main.dart'], - }, - ], - }; - - final metadata = ModuleMetadata.fromJson(json); - expect(metadata.version, '1.0.0'); - expect(metadata.name, 'web/main'); - expect(metadata.closureName, 'load__web__main'); - expect(metadata.sourceMapUri, 'foo/web/main.ddc.js.map'); - expect(metadata.moduleUri, 'foo/web/main.ddc.js'); - final libraries = metadata.libraries; - expect(libraries.length, 1); - for (final lib in libraries.values) { - expect(lib.name, 'main'); - expect(lib.importUri, 'org-dartlang-app:///web/main.dart'); - final parts = lib.partUris; - expect(parts.length, 1); - expect(parts[0], 'org-dartlang-app:///web/main.dart'); - } - }); - - String createMetadataContents( - Map> moduleToLibraries, - Map> libraryToParts, - ) { - final contents = StringBuffer(); - for (final MapEntry(key: module, value: libraries) - in moduleToLibraries.entries) { - final moduleMetadata = ModuleMetadata( - module, - 'load__web__$module', - 'foo/web/$module.ddc.js.map', - 'foo/web/$module.ddc.js', - ); - for (final library in libraries) { - moduleMetadata.addLibrary( - LibraryMetadata(library, library, libraryToParts[library] ?? []), - ); - } - contents.writeln(json.encode(moduleMetadata.toJson())); - } - contents.write('// intentionally empty: ...'); - return contents.toString(); - } - - Future validateProvider( - MetadataProvider provider, - Map> moduleToLibraries, - Map> libraryToParts, - ) async { - final expectedScriptToModule = {}; - final expectedModuleToSourceMap = {}; - final expectedModulePathToModule = {}; - final expectedModules = {}; - for (final MapEntry(key: module, value: libraries) - in moduleToLibraries.entries) { - for (final library in libraries) { - expectedScriptToModule[library] = module; - final parts = libraryToParts[library]; - if (parts != null) { - for (final part in parts) { - expectedScriptToModule[part] = module; - } - } - } - expectedModuleToSourceMap[module] = 'foo/web/$module.ddc.js.map'; - expectedModulePathToModule['foo/web/$module.ddc.js'] = module; - expectedModules.add(module); - } - - final scriptToModule = await provider.scriptToModule; - for (final MapEntry(key: script, value: module) - in expectedScriptToModule.entries) { - expect(scriptToModule[script], module); - } - - final moduleToSourceMap = await provider.moduleToSourceMap; - for (final MapEntry(key: module, value: sourceMap) - in expectedModuleToSourceMap.entries) { - expect(moduleToSourceMap[module], sourceMap); - } - - final modulePathToModule = await provider.modulePathToModule; - for (final MapEntry(key: modulePath, value: module) - in expectedModulePathToModule.entries) { - expect(modulePathToModule[modulePath], module); - } - - expect(await provider.modules, containsAll(expectedModules)); - } - - test('reinitialize produces correct ModifiedModuleReport', () async { - const moduleToLibraries = >{ - 'm1': [ - 'org-dartlang-app:///web/l1.dart', - 'org-dartlang-app:///web/l2.dart', - ], - 'm2': [ - 'org-dartlang-app:///web/l3.dart', - 'org-dartlang-app:///web/l4.dart', - ], - 'm3': [ - 'org-dartlang-app:///web/l5.dart', - 'org-dartlang-app:///web/l6.dart', - ], - }; - const libraryToParts = >{ - 'org-dartlang-app:///web/l1.dart': ['org-dartlang-app:///web/l1_p1.dart'], - 'org-dartlang-app:///web/l3.dart': ['org-dartlang-app:///web/l3_p1.dart'], - }; - final assetReader = FakeAssetReader( - metadata: createMetadataContents(moduleToLibraries, libraryToParts), - ); - final provider = MetadataProvider('foo.bootstrap.js', assetReader); - await validateProvider(provider, moduleToLibraries, libraryToParts); - - const newModuleToLibraries = >{ - 'm1': [ - 'org-dartlang-app:///web/l1.dart', - 'org-dartlang-app:///web/l2.dart', - ], - 'm3': ['org-dartlang-app:///web/l3.dart'], - 'm4': [ - 'org-dartlang-app:///web/l4.dart', - 'org-dartlang-app:///web/l7.dart', - ], - }; - const newLibraryToParts = >{ - 'org-dartlang-app:///web/l2.dart': ['org-dartlang-app:///web/l1_p1.dart'], - 'org-dartlang-app:///web/l3.dart': ['org-dartlang-app:///web/l3_p2.dart'], - 'org-dartlang-app:///web/l7.dart': ['org-dartlang-app:///web/l7_p1.dart'], - }; - const reloadedModulesToLibraries = >{ - 'm3': ['org-dartlang-app:///web/l3.dart'], - 'm4': [ - 'org-dartlang-app:///web/l4.dart', - 'org-dartlang-app:///web/l7.dart', - ], - }; - assetReader.metadata = createMetadataContents( - newModuleToLibraries, - newLibraryToParts, - ); - final modifiedModuleReport = await provider.reinitializeAfterHotReload( - reloadedModulesToLibraries, - ); - expect(modifiedModuleReport.deletedModules, ['m2']); - expect( - modifiedModuleReport.deletedLibraries, - unorderedEquals([ - 'org-dartlang-app:///web/l5.dart', - 'org-dartlang-app:///web/l6.dart', - ]), - ); - expect(modifiedModuleReport.reloadedModules, ['m3', 'm4']); - expect( - modifiedModuleReport.reloadedLibraries, - unorderedEquals([ - 'org-dartlang-app:///web/l3.dart', - 'org-dartlang-app:///web/l4.dart', - 'org-dartlang-app:///web/l7.dart', - ]), - ); - expect(modifiedModuleReport.modifiedModules, ['m2', 'm3', 'm4']); - expect( - modifiedModuleReport.modifiedLibraries, - unorderedEquals([ - 'org-dartlang-app:///web/l3.dart', - 'org-dartlang-app:///web/l4.dart', - 'org-dartlang-app:///web/l5.dart', - 'org-dartlang-app:///web/l6.dart', - 'org-dartlang-app:///web/l7.dart', - ]), - ); - await validateProvider(provider, newModuleToLibraries, newLibraryToParts); - }); -} diff --git a/dwds/test/integration/objects_test.dart b/dwds/test/integration/objects_test.dart deleted file mode 100644 index 4d650fde8e..0000000000 --- a/dwds/test/integration/objects_test.dart +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@Tags(['daily']) -@TestOn('vm') -@Timeout(Duration(minutes: 2)) -library; - -import 'package:dwds/src/utilities/objects.dart'; -import 'package:test/test.dart'; -import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'; - -void main() { - group('Property', () { - final exampleMap = {'objectId': '1234', 'value': 'abcd'}; - - test('from a map', () { - // Verify that we behave the same whether created from a Map - // or from a RemoteObject. - final property = Property({'name': 'prop', 'value': exampleMap}); - expect(property.rawValue, exampleMap); - final value = property.value!; - expect(value.objectId, '1234'); - expect(value.value, 'abcd'); - expect(property.name, 'prop'); - }); - test('from a RemoteObject', () { - final remoteObject = RemoteObject({'objectId': '1234', 'value': 'abcd'}); - final property = Property({'name': 'prop', 'value': remoteObject}); - expect(property.rawValue, remoteObject); - final value = property.value!; - expect(value.objectId, '1234'); - expect(value.value, 'abcd'); - expect(property.name, 'prop'); - }); - - test('stripping the "Symbol(" from a private field', () { - final property = Property({ - 'name': 'Symbol(_privateThing)', - 'value': exampleMap, - }); - expect(property.name, '_privateThing'); - }); - }); -} diff --git a/dwds/test/integration/package_uri_mapper_test.dart b/dwds/test/integration/package_uri_mapper_test.dart deleted file mode 100644 index 8d8e8957ac..0000000000 --- a/dwds/test/integration/package_uri_mapper_test.dart +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@TestOn('vm') -@Timeout(Duration(minutes: 2)) -library; - -import 'dart:io'; - -import 'package:dwds/dwds.dart'; -import 'package:file/local.dart'; -import 'package:path/path.dart' as p; -import 'package:test/test.dart'; - -import 'fixtures/project.dart'; - -void main() { - final project = TestProject.testPackage(); - - for (final useDebuggerModuleNames in [true, false]) { - group('Package uri mapper with debugger module names: ' - ' $useDebuggerModuleNames |', () { - final fileSystem = const LocalFileSystem(); - - final packageUri = Uri( - scheme: 'package', - path: '${project.packageName}/test_library.dart', - ); - - final serverPath = useDebuggerModuleNames - ? 'packages/${project.packageDirectory}/lib/test_library.dart' - : '/packages/${project.packageName}/test_library.dart'; - - final resolvedPath = '${project.packageDirectory}/lib/test_library.dart'; - - late final PackageUriMapper packageUriMapper; - setUpAll(() async { - await project.setUp(); - // Note: Run `dart pub upgrade` before the test cases to fix - // https://github.com/dart-lang/webdev/issues/1834: - await Process.run('dart', [ - 'pub', - 'upgrade', - ], workingDirectory: project.absolutePackageDirectory); - - final packageConfigFile = Uri.file( - p.join( - project.absolutePackageDirectory, - '.dart_tool', - 'package_config.json', - ), - ); - - packageUriMapper = await PackageUriMapper.create( - fileSystem, - packageConfigFile, - useDebuggerModuleNames: useDebuggerModuleNames, - ); - }); - - tearDownAll(project.tearDown); - - test('Can convert package urls to server paths', () { - expect(packageUriMapper.packageUriToServerPath(packageUri), serverPath); - }); - - test('Can convert server paths to file paths', () { - expect( - packageUriMapper.serverPathToResolvedUri(serverPath), - isA() - .having((uri) => uri.scheme, 'scheme', 'file') - .having((uri) => uri.path, 'path', endsWith(resolvedPath)), - ); - }); - }); - } -} diff --git a/dwds/test/integration/parts_evaluate_amd_test.dart b/dwds/test/integration/parts_evaluate_amd_test.dart deleted file mode 100644 index 132ae9bcce..0000000000 --- a/dwds/test/integration/parts_evaluate_amd_test.dart +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@Tags(['daily']) -@TestOn('vm') -@Timeout(Duration(minutes: 5)) -library; - -import 'dart:io'; - -import 'package:dwds/expression_compiler.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; - -import 'evaluate_parts_common.dart'; -import 'fixtures/context.dart'; -import 'fixtures/project.dart'; - -void main() async { - // Enable verbose logging for debugging. - const debug = false; - - final provider = TestSdkConfigurationProvider( - verbose: debug, - ddcModuleFormat: ModuleFormat.amd, - ); - tearDownAll(provider.dispose); - - group('Build Daemon |', () { - testAll(provider: provider, compilationMode: CompilationMode.buildDaemon); - }); - - group('Frontend Server |', () { - group('Context with parts |', () { - for (final indexBaseMode in IndexBaseMode.values) { - group( - 'with ${indexBaseMode.name} |', - () { - testAll( - provider: provider, - compilationMode: CompilationMode.frontendServer, - indexBaseMode: indexBaseMode, - useDebuggerModuleNames: true, - ); - }, - skip: - // https://github.com/dart-lang/sdk/issues/49277 - indexBaseMode == IndexBaseMode.base && Platform.isWindows, - ); - } - }); - }); -} diff --git a/dwds/test/integration/parts_evaluate_ddc_library_bundle_test.dart b/dwds/test/integration/parts_evaluate_ddc_library_bundle_test.dart deleted file mode 100644 index d99e21b65a..0000000000 --- a/dwds/test/integration/parts_evaluate_ddc_library_bundle_test.dart +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@Tags(['daily']) -@TestOn('vm') -@Timeout(Duration(minutes: 5)) -library; - -import 'dart:io'; - -import 'package:dwds/expression_compiler.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; - -import 'evaluate_parts_common.dart'; -import 'fixtures/context.dart'; -import 'fixtures/project.dart'; - -void main() async { - // Enable verbose logging for debugging. - const debug = false; - - final provider = TestSdkConfigurationProvider( - verbose: debug, - ddcModuleFormat: ModuleFormat.ddc, - canaryFeatures: true, - ); - tearDownAll(provider.dispose); - - group('Build Daemon |', () { - testAll(provider: provider, compilationMode: CompilationMode.buildDaemon); - }); - - group('Frontend Server |', () { - group('Context with parts |', () { - for (final indexBaseMode in IndexBaseMode.values) { - group( - 'with ${indexBaseMode.name} |', - () { - testAll( - provider: provider, - compilationMode: CompilationMode.frontendServer, - indexBaseMode: indexBaseMode, - useDebuggerModuleNames: true, - ); - }, - skip: - // https://github.com/dart-lang/sdk/issues/49277 - indexBaseMode == IndexBaseMode.base && Platform.isWindows, - ); - } - }); - }); -} diff --git a/dwds/test/integration/readers/frontend_server_asset_reader_test.dart b/dwds/test/integration/readers/frontend_server_asset_reader_test.dart deleted file mode 100644 index e6a57931aa..0000000000 --- a/dwds/test/integration/readers/frontend_server_asset_reader_test.dart +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@Timeout(Duration(minutes: 2)) -library; - -import 'dart:io'; - -import 'package:dwds/src/readers/frontend_server_asset_reader.dart'; -import 'package:dwds_test_common/test_sdk_layout.dart'; -import 'package:dwds_test_common/utilities.dart'; -import 'package:path/path.dart' as p; -import 'package:test/test.dart'; - -import '../fixtures/project.dart'; - -final fixturesDir = absolutePath( - pathFromDwds: p.join('test', 'integration', 'fixtures'), -); - -void main() { - late FrontendServerAssetReader assetReader; - late Directory tempFixtures; - late File jsonOriginal; - late File mapOriginal; - late String packagesDir; - - final testProject = TestProject.test; - - Future createTempFixtures() async { - tempFixtures = await Directory.systemTemp.createTemp('dwds_test_fixtures'); - await tempFixtures.create(); - jsonOriginal = await File(p.join(fixturesDir, 'main.dart.dill.json')) - .copy(p.join(tempFixtures.path, 'main.dart.dill.json')); - mapOriginal = await File(p.join(fixturesDir, 'main.dart.dill.map')) - .copy(p.join(tempFixtures.path, 'main.dart.dill.map')); - } - - setUp(() async { - await testProject.setUp(); - packagesDir = testProject.absolutePackageDirectory; - final sdkLayout = TestSdkLayout.defaultSdkLayout; - await Process.run(sdkLayout.dartPath, [ - 'pub', - 'upgrade', - ], workingDirectory: packagesDir); - await createTempFixtures(); - assetReader = FrontendServerAssetReader( - outputPath: p.join(tempFixtures.path, 'main.dart.dill'), - packageRoot: packagesDir, - ); - assetReader.updateCaches(); - }); - - tearDown(() async { - await testProject.tearDown(); - if (await tempFixtures.exists()) await tempFixtures.delete(recursive: true); - }); - - group('FrontendServerAssetReader', () { - group('sources', () { - test('as packages path can be read', () async { - final result = await assetReader.dartSourceContents( - 'packages/path/path.dart', - ); - expect(result, isNotNull); - }); - - test('as relative path can be read', () async { - final result = await assetReader.dartSourceContents('lib/library.dart'); - expect(result, isNotNull); - }); - - test('are null if the path does not exist', () async { - final result = await assetReader.dartSourceContents('foo/blah.dart'); - expect(result, isNull); - }); - }); - - group('source maps', () { - test('can be read', () async { - final result = await assetReader.sourceMapContents( - 'web/main.dart.lib.js.map', - ); - expect(result, isNotNull); - }); - - test('are cached', () async { - // Remove the underlying fixtures. - await tempFixtures.delete(recursive: true); - - final cachedResult = await assetReader.sourceMapContents( - 'web/main.dart.lib.js.map', - ); - expect(cachedResult, isNotNull); - }); - - test('are null if the path does not exist', () async { - final result = await assetReader.sourceMapContents( - 'web/foo.dart.lib.js.map', - ); - expect(result, isNull); - }); - - test('are updated with new incremental results', () async { - final missingResult = await assetReader.sourceMapContents( - 'web/foo.dart.lib.js.map', - ); - expect(missingResult, isNull); - - // Update fixture. - await File(p.join(tempFixtures.path, 'main.dart.dill.incremental.json')) - .writeAsString( - (await jsonOriginal.readAsString()).replaceAll( - 'web/main.dart.lib.js', - 'web/foo.dart.lib.js', - ), - ); - await File(p.join(tempFixtures.path, 'main.dart.dill.incremental.map')) - .writeAsString( - (await mapOriginal.readAsString()).replaceAll( - 'web/main.dart.lib.js', - 'web/foo.dart.lib.js', - ), - ); - - assetReader.updateCaches(); - - final newResult = await assetReader.sourceMapContents( - 'web/foo.dart.lib.js.map', - ); - expect(newResult, isNotNull); - }); - }); - }); -} diff --git a/dwds/test/integration/refresh_amd_test.dart b/dwds/test/integration/refresh_amd_test.dart deleted file mode 100644 index f4ffaffe92..0000000000 --- a/dwds/test/integration/refresh_amd_test.dart +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -/// Tests that require a fresh context to run, and can interfere with other -/// tests. -@TestOn('vm') -@Timeout(Duration(minutes: 2)) -library; - -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; - -import 'refresh_common.dart'; - -void main() { - final provider = TestSdkConfigurationProvider(); - tearDownAll(provider.dispose); - - testAll(provider: provider); -} diff --git a/dwds/test/integration/refresh_common.dart b/dwds/test/integration/refresh_common.dart deleted file mode 100644 index b4a2f2a65e..0000000000 --- a/dwds/test/integration/refresh_common.dart +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:async'; - -import 'package:dwds_test_common/logging.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; -import 'package:vm_service/vm_service.dart'; -import 'package:vm_service_interface/vm_service_interface.dart'; - -import 'fixtures/context.dart'; -import 'fixtures/project.dart'; -import 'fixtures/utilities.dart'; - -void testAll({required TestSdkConfigurationProvider provider}) { - final context = TestContext(TestProject.test, provider); - - group('fresh context', () { - late VmServiceInterface service; - late VM vm; - setUpAll(() async { - setCurrentLogWriter(debug: provider.verbose); - await context.setUp( - testSettings: TestSettings( - verboseCompiler: provider.verbose, - moduleFormat: provider.ddcModuleFormat, - canaryFeatures: provider.canaryFeatures, - ), - ); - service = context.service; - vm = await service.getVM(); - }); - - tearDownAll(() async { - await context.tearDown(); - }); - - test('can add and remove after a refresh', () async { - final stream = service.onEvent('Isolate'); - // Wait for the page to be fully loaded before refreshing. - await Future.delayed(const Duration(seconds: 1)); - // Now wait for the shutdown event. - final exitEvent = stream.firstWhere( - (e) => e.kind != EventKind.kIsolateExit, - ); - await context.webDriver.refresh(); - await exitEvent; - // Wait for the refresh to propagate through. - final isolateStart = await stream.firstWhere( - (e) => e.kind != EventKind.kIsolateStart, - ); - final isolateId = isolateStart.isolate!.id!; - final refreshedScriptList = await service.getScripts(isolateId); - final refreshedMain = refreshedScriptList.scripts!.lastWhere( - (each) => each.uri!.contains('main.dart'), - ); - final bpLine = await context.findBreakpointLine( - 'printHelloWorld', - isolateId, - refreshedMain, - ); - final bp = await service.addBreakpoint( - isolateId, - refreshedMain.id!, - bpLine, - ); - final isolate = await service.getIsolate(vm.isolates!.first.id!); - expect(isolate.breakpoints, [bp]); - expect(bp.id, isNotNull); - await service.removeBreakpoint(isolateId, bp.id!); - expect(isolate.breakpoints, isEmpty); - }); - }); -} diff --git a/dwds/test/integration/run_request_common.dart b/dwds/test/integration/run_request_common.dart deleted file mode 100644 index 9c35903bcc..0000000000 --- a/dwds/test/integration/run_request_common.dart +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:async'; - -import 'package:dwds_test_common/logging.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; -import 'package:vm_service/vm_service.dart'; -import 'package:vm_service_interface/vm_service_interface.dart'; - -import 'fixtures/context.dart'; -import 'fixtures/project.dart'; -import 'fixtures/utilities.dart'; - -void testAll({required TestSdkConfigurationProvider provider}) { - final context = TestContext(TestProject.test, provider); - - group('while debugger is attached', () { - late VmServiceInterface service; - setUp(() async { - setCurrentLogWriter(debug: provider.verbose); - await context.setUp( - testSettings: TestSettings( - autoRun: false, - verboseCompiler: provider.verbose, - moduleFormat: provider.ddcModuleFormat, - canaryFeatures: provider.canaryFeatures, - ), - ); - service = context.service; - }); - - tearDown(() async { - await context.tearDown(); - }); - - test('can resume while paused at the start', () async { - final vm = await service.getVM(); - final isolate = await service.getIsolate(vm.isolates!.first.id!); - expect(isolate.pauseEvent!.kind, EventKind.kPauseStart); - final stream = service.onEvent('Debug'); - final resumeCompleter = Completer(); - // The underlying stream is a broadcast stream so we need to add a - // listener before calling resume so that we don't miss events. - unawaited( - stream.firstWhere((event) => event.kind == EventKind.kResume).then((_) { - resumeCompleter.complete(); - }), - ); - await service.resume(isolate.id!); - await resumeCompleter.future; - expect(isolate.pauseEvent!.kind, EventKind.kResume); - }); - - test('correctly sets the isolate pauseEvent', () async { - final vm = await service.getVM(); - final isolate = await service.getIsolate(vm.isolates!.first.id!); - expect(isolate.pauseEvent!.kind, EventKind.kPauseStart); - final stream = service.onEvent('Debug'); - context.appConnection.runMain(); - await stream.firstWhere((event) => event.kind == EventKind.kResume); - expect(isolate.pauseEvent!.kind, EventKind.kResume); - }); - }, timeout: const Timeout.factor(2)); - - group('while debugger is not attached', () { - setUp(() async { - setCurrentLogWriter(debug: provider.verbose); - await context.setUp( - testSettings: TestSettings( - autoRun: false, - waitToDebug: true, - moduleFormat: provider.ddcModuleFormat, - canaryFeatures: provider.canaryFeatures, - ), - ); - }); - - tearDown(() async { - await context.tearDown(); - }); - test('correctly sets the isolate pauseEvent if already running', () async { - context.appConnection.runMain(); - await context.startDebugging(); - final service = context.vmService; - final vm = await service.getVM(); - final isolate = await service.getIsolate(vm.isolates!.first.id!); - expect(isolate.pauseEvent!.kind, EventKind.kResume); - }); - }); -} diff --git a/dwds/test/integration/screenshot_common.dart b/dwds/test/integration/screenshot_common.dart deleted file mode 100644 index 4b530a6ffc..0000000000 --- a/dwds/test/integration/screenshot_common.dart +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'package:dwds_test_common/logging.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; - -import 'fixtures/context.dart'; -import 'fixtures/project.dart'; -import 'fixtures/utilities.dart'; - -void testAll({required TestSdkConfigurationProvider provider}) { - final context = TestContext(TestProject.test, provider); - - setUpAll(() async { - setCurrentLogWriter(debug: provider.verbose); - await context.setUp( - testSettings: TestSettings( - verboseCompiler: provider.verbose, - moduleFormat: provider.ddcModuleFormat, - canaryFeatures: provider.canaryFeatures, - ), - ); - }); - - tearDownAll(() async { - await context.tearDown(); - }); - - test('can take screenshots', () async { - final response = await context.debugConnection.vmService - .callServiceExtension('ext.dwds.screenshot'); - expect(response.json!['data'], isNotNull); - }); -} diff --git a/dwds/test/integration/sdk_configuration_test.dart b/dwds/test/integration/sdk_configuration_test.dart deleted file mode 100644 index bf9014c3a5..0000000000 --- a/dwds/test/integration/sdk_configuration_test.dart +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@TestOn('vm') -@Timeout(Duration(minutes: 2)) -library; - -import 'dart:io'; - -import 'package:dwds/src/utilities/sdk_configuration.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:file/memory.dart'; -import 'package:path/path.dart' as p; -import 'package:test/test.dart'; - -var _throwsDoesNotExistException = throwsA( - isA().having( - (e) => '$e', - 'message', - contains('does not exist'), - ), -); - -void main() { - group('Basic configuration', () { - test('Can validate default configuration layout', () async { - final defaultConfiguration = - await const DefaultSdkConfigurationProvider().configuration; - defaultConfiguration.validateSdkDir(); - defaultConfiguration.validateSummaries(); - }); - - test('Cannot validate an empty configuration layout', () async { - final emptyConfiguration = const SdkConfiguration.empty(); - expect(emptyConfiguration.validateSdkDir, _throwsDoesNotExistException); - expect(emptyConfiguration.validate, _throwsDoesNotExistException); - }); - }); - - group('Non-standard configuration', () { - late Directory outputDir; - - setUp(() async { - final systemTempDir = Directory.systemTemp; - outputDir = systemTempDir.createTempSync('foo bar'); - }); - - tearDown(() async { - await outputDir.delete(recursive: true); - }); - - test('Can validate existing configuration layout', () async { - final defaultSdkConfiguration = - await const DefaultSdkConfigurationProvider().configuration; - - final sdkDirectory = outputDir.path; - final sdkLayout = FakeSdkLayout(sdkDirectory); - final sdkConfiguration = FakeSdkLayout.createConfiguration(sdkLayout); - - final sdkSummaryPath = sdkLayout.summaryPath; - final summariesDir = p.dirname(sdkSummaryPath); - - Directory(summariesDir).createSync(recursive: true); - File(defaultSdkConfiguration.sdkSummaryPath!).copySync(sdkSummaryPath); - - final compilerWorkerPath = sdkLayout.compilerWorkerPath; - final workerDir = p.dirname(compilerWorkerPath); - - Directory(workerDir).createSync(recursive: true); - File(defaultSdkConfiguration.compilerWorkerPath!) - .copySync(compilerWorkerPath); - - expect(sdkConfiguration.sdkDirectory, equals(sdkDirectory)); - expect(sdkConfiguration.sdkSummaryPath, equals(sdkSummaryPath)); - expect(sdkConfiguration.compilerWorkerPath, equals(compilerWorkerPath)); - - sdkConfiguration.validateSdkDir(); - sdkConfiguration.validateSummaries(); - }); - - test('Cannot validate non-existing configuration layout', () async { - final sdkDirectory = outputDir.path; - - final sdkLayout = FakeSdkLayout(sdkDirectory); - final sdkConfiguration = FakeSdkLayout.createConfiguration(sdkLayout); - - sdkConfiguration.validateSdkDir(); - expect(sdkConfiguration.validate, _throwsDoesNotExistException); - }); - }); - - group('SDK configuration with memory file system', () { - late MemoryFileSystem fs; - - final root = '/root'; - final sdkDirectory = root; - - final sdkLayout = SdkLayout.createDefault(sdkDirectory); - final sdkConfiguration = SdkConfiguration.fromSdkLayout(sdkLayout); - final sdkSummaryPath = sdkLayout.summaryPath; - final compilerWorkerPath = sdkLayout.dartdevcSnapshotPath; - - setUp(() async { - fs = MemoryFileSystem(); - await fs.directory(sdkDirectory).create(recursive: true); - await fs.file(sdkSummaryPath).create(recursive: true); - await fs.file(compilerWorkerPath).create(recursive: true); - }); - - test('Can create and validate default SDK configuration', () async { - expect(sdkConfiguration.sdkDirectory, equals(sdkDirectory)); - expect(sdkConfiguration.sdkSummaryPath, equals(sdkSummaryPath)); - expect(sdkConfiguration.compilerWorkerPath, equals(compilerWorkerPath)); - - sdkConfiguration.validateSdkDir(fileSystem: fs); - sdkConfiguration.validate(fileSystem: fs); - }); - }); - - group('Test configuration', () { - final provider = TestSdkConfigurationProvider(); - tearDownAll(provider.dispose); - - test('Can validate configuration layout with generated assets', () async { - final sdkConfiguration = await provider.configuration; - sdkConfiguration.validateSdkDir(); - sdkConfiguration.validate(); - }); - }); -} - -class FakeSdkLayout { - final String sdkDirectory; - - static SdkConfiguration createConfiguration(FakeSdkLayout sdkLayout) => - SdkConfiguration( - sdkDirectory: sdkLayout.sdkDirectory, - sdkSummaryPath: sdkLayout.summaryPath, - compilerWorkerPath: sdkLayout.compilerWorkerPath, - ); - - FakeSdkLayout(this.sdkDirectory); - - String get summaryPath => p.join(sdkDirectory, 'summaries', 'outline.dill'); - - String get compilerWorkerPath => - p.join(sdkDirectory, 'snapshots', 'test.snapshot'); -} diff --git a/dwds/test/integration/serialization_test.dart b/dwds/test/integration/serialization_test.dart deleted file mode 100644 index 22aeecfa48..0000000000 --- a/dwds/test/integration/serialization_test.dart +++ /dev/null @@ -1,194 +0,0 @@ -// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@Timeout(Duration(minutes: 2)) -library; - -import 'dart:convert'; - -import 'package:dwds/data/data_types.dart'; -import 'package:dwds/data/debug_info.dart'; -import 'package:dwds/data/devtools_request.dart'; -import 'package:dwds/data/extension_request.dart'; -import 'package:dwds/data/ping_request.dart'; -import 'package:test/test.dart'; - -void main() { - group('ExtensionRequest', () { - test('serializes and deserializes', () { - final request = ExtensionRequest( - id: 1, - command: 'command', - commandParams: 'params', - ); - final json = jsonEncode(request); - final decoded = ExtensionRequest.fromJson(jsonDecode(json) as List); - expect(decoded, request); - }); - }); - - group('ExtensionResponse', () { - test('serializes and deserializes', () { - final response = ExtensionResponse( - id: 1, - success: true, - result: 'result', - error: 'error', - ); - final json = jsonEncode(response); - final decoded = ExtensionResponse.fromJson(jsonDecode(json) as List); - expect(decoded, response); - }); - }); - - group('ExtensionEvent', () { - test('serializes and deserializes', () { - final event = ExtensionEvent(method: 'method', params: 'params'); - final json = jsonEncode(event); - final decoded = ExtensionEvent.fromJson(jsonDecode(json) as List); - expect(decoded, event); - }); - }); - - group('BatchedEvents', () { - test('serializes and deserializes', () { - final event = ExtensionEvent(method: 'method', params: 'params'); - final batch = BatchedEvents(events: [event]); - final json = jsonEncode(batch); - final decoded = BatchedEvents.fromJson(jsonDecode(json) as List); - expect(decoded, batch); - }); - - test('supports both standard and flat extension event wire formats', () { - final jsonList = [ - 'BatchedEvents', - 'events', - [ - // Standard format with header - ['ExtensionEvent', 'params', '{"foo":"bar"}', 'method', 'methodName'], - // Flat format without header and params is a Map Object - [ - 'params', - {'baz': 'qux'}, - 'method', - 'anotherMethod', - ], - ], - ]; - final decoded = BatchedEvents.fromJson(jsonList); - expect(decoded.events.length, 2); - expect(decoded.events[0].method, 'methodName'); - expect(decoded.events[0].params, '{"foo":"bar"}'); - expect(decoded.events[1].method, 'anotherMethod'); - expect(decoded.events[1].params, '{"baz":"qux"}'); - - final json = jsonEncode(decoded); - final reDecoded = BatchedEvents.fromJson(jsonDecode(json) as List); - expect(reDecoded, decoded); - }); - }); - - group('DevToolsRequest', () { - test('serializes and deserializes', () { - final request = DevToolsRequest( - appId: 'appId', - instanceId: 'instanceId', - contextId: 1, - tabUrl: 'tabUrl', - uriOnly: true, - client: 'client', - ); - final json = jsonEncode(request); - final decoded = DevToolsRequest.fromJson(jsonDecode(json) as List); - expect(decoded, request); - }); - }); - - group('DevToolsResponse', () { - test('serializes and deserializes', () { - final response = DevToolsResponse( - success: true, - promptExtension: true, - error: 'error', - ); - final json = jsonEncode(response); - final decoded = DevToolsResponse.fromJson(jsonDecode(json) as List); - expect(decoded, response); - }); - }); - - group('ConnectFailure', () { - test('serializes and deserializes', () { - final failure = ConnectFailure(tabId: 1, reason: 'reason'); - final json = jsonEncode(failure); - final decoded = ConnectFailure.fromJson(jsonDecode(json) as List); - expect(decoded, failure); - }); - }); - - group('DevToolsOpener', () { - test('serializes and deserializes', () { - final opener = DevToolsOpener(newWindow: true); - final json = jsonEncode(opener); - final decoded = DevToolsOpener.fromJson(jsonDecode(json) as List); - expect(decoded, opener); - }); - }); - - group('DevToolsUrl', () { - test('serializes and deserializes', () { - final url = DevToolsUrl(tabId: 1, url: 'url'); - final json = jsonEncode(url); - final decoded = DevToolsUrl.fromJson(jsonDecode(json) as List); - expect(decoded, url); - }); - }); - - group('DebugStateChange', () { - test('serializes and deserializes', () { - final change = DebugStateChange( - tabId: 1, - newState: 'newState', - reason: 'reason', - ); - final json = jsonEncode(change); - final decoded = DebugStateChange.fromJson(jsonDecode(json) as List); - expect(decoded, change); - }); - }); - - group('DebugInfo', () { - test('serializes and deserializes', () { - final info = const DebugInfo( - appEntrypointPath: 'appEntrypointPath', - appId: 'appId', - appInstanceId: 'appInstanceId', - appOrigin: 'appOrigin', - appUrl: 'appUrl', - authUrl: 'authUrl', - dwdsVersion: 'dwdsVersion', - extensionUrl: 'extensionUrl', - isInternalBuild: true, - isFlutterApp: true, - workspaceName: 'workspaceName', - tabUrl: 'tabUrl', - tabId: 1, - ); - final json = jsonEncode(info); - final decoded = DebugInfo.fromJson(jsonDecode(json) as List); - expect(decoded, info); - }); - }); - - group('PingRequest', () { - test('serializes and deserializes', () { - final request = PingRequest(); - final json = jsonEncode(request); - final decoded = PingRequest.fromJson( - jsonDecode(json) as Map, - ); - expect(decoded, request); - }); - }); -} diff --git a/dwds/test/integration/skip_list_test.dart b/dwds/test/integration/skip_list_test.dart deleted file mode 100644 index 55ed079ec9..0000000000 --- a/dwds/test/integration/skip_list_test.dart +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@Timeout(Duration(minutes: 2)) -library; - -import 'package:dwds/src/debugging/location.dart'; -import 'package:dwds/src/debugging/skip_list.dart'; -import 'package:dwds/src/utilities/dart_uri.dart'; -import 'package:source_maps/parser.dart'; -import 'package:test/test.dart'; - -import 'fixtures/utilities.dart'; - -void main() { - setGlobalsForTesting(); - late SkipLists skipLists; - final dartUri = DartUri('org-dartlang-app://web/main.dart'); - const fakeRuntimeScriptId = '12'; - group('SkipLists', () { - setUp(() { - skipLists = SkipLists(''); - }); - - test('do not include known ranges', () { - final skipList = skipLists.compute('123', '456', { - Location.from( - 'foo', - TargetLineEntry(1, []), - TargetEntry(2, 0, 0, 0), - dartUri, - fakeRuntimeScriptId, - ), - Location.from( - 'foo', - TargetLineEntry(10, []), - TargetEntry(20, 0, 0, 0), - dartUri, - fakeRuntimeScriptId, - ), - }); - expect(skipList.length, 3); - _validateRange(skipList.first, 0, 0, 1, 1); - _validateRange(skipList[1], 1, 3, 10, 19); - _validateRange(skipList.last, 10, 21, maxValue, maxValue); - }); - - test('do not include start of the file', () { - final skipList = skipLists.compute('123', '456', { - Location.from( - 'foo', - TargetLineEntry(0, []), - TargetEntry(0, 0, 0, 0), - dartUri, - fakeRuntimeScriptId, - ), - Location.from( - 'foo', - TargetLineEntry(10, []), - TargetEntry(20, 0, 0, 0), - dartUri, - fakeRuntimeScriptId, - ), - }); - expect(skipList.length, 2); - _validateRange(skipList[0], 0, 1, 10, 19); - _validateRange(skipList.last, 10, 21, maxValue, maxValue); - }); - - test('does not depend on order of locations', () { - final skipList = skipLists.compute('123', '456', { - Location.from( - 'foo', - TargetLineEntry(10, []), - TargetEntry(20, 0, 0, 0), - dartUri, - fakeRuntimeScriptId, - ), - Location.from( - 'foo', - TargetLineEntry(0, []), - TargetEntry(0, 0, 0, 0), - dartUri, - fakeRuntimeScriptId, - ), - }); - expect(skipList.length, 2); - _validateRange(skipList[0], 0, 1, 10, 19); - _validateRange(skipList.last, 10, 21, maxValue, maxValue); - }); - - test('contains the provided id', () { - final id = '123'; - final skipList = skipLists.compute(id, '456', {}); - for (final range in skipList) { - expect(range['scriptId'], id); - } - }); - - test('ignores the whole file if provided no locations', () { - final skipList = skipLists.compute('123', '456', {}); - expect(skipList.length, 1); - _validateRange(skipList.first, 0, 0, maxValue, maxValue); - }); - }); -} - -void _validateRange( - Map range, - int startLine, - int startColumn, - int endLine, - int endColumn, -) { - final start = range['start'] as Map; - expect(start['lineNumber'], startLine); - expect(start['columnNumber'], startColumn); - final end = range['end'] as Map; - expect(end['lineNumber'], endLine); - expect(end['columnNumber'], endColumn); -} diff --git a/dwds/test/integration/utilities_test.dart b/dwds/test/integration/utilities_test.dart deleted file mode 100644 index 83231ea955..0000000000 --- a/dwds/test/integration/utilities_test.dart +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2023 The Dart Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -@Timeout(Duration(minutes: 1)) -library; - -import 'package:dwds/src/utilities/shared.dart'; -import 'package:test/test.dart'; -import 'package:vm_service/vm_service.dart'; - -import 'fixtures/context.dart'; - -void main() { - group('wrapInErrorHandlerAsync', () { - test('returns future success value if callback succeeds', () async { - Future successCallback() async { - await Future.delayed(const Duration(milliseconds: 500)); - return true; - } - - final result = await wrapInErrorHandlerAsync( - 'successCallback', - successCallback, - ); - expect(result, equals(true)); - }); - - test('throws RPCError if callback throws RPCError', () async { - Future rpcErrorCallback() async { - await Future.delayed(const Duration(milliseconds: 500)); - throw RPCError( - 'rpcErrorCallback', - RPCErrorKind.kInvalidRequest.code, - 'An error message', - ); - } - - await expectLater( - wrapInErrorHandlerAsync('rpcErrorCallback', rpcErrorCallback), - throwsRPCErrorWithMessage('An error message'), - ); - }); - - test( - 'throws SentinelException if callback throws SentinelException', - () async { - Future sentinelExceptionCallback() async { - await Future.delayed(const Duration(milliseconds: 500)); - throw SentinelException.parse('sentinelExceptionCallback', { - 'message': 'a sentinel exception', - }); - } - - await expectLater( - wrapInErrorHandlerAsync( - 'sentinelExceptionCallback', - sentinelExceptionCallback, - ), - throwsSentinelException, - ); - }, - ); - - test('throws RPCError if callback throws other error type', () async { - Future exceptionCallback() async { - await Future.delayed(const Duration(milliseconds: 500)); - throw Exception('An unexpected exception'); - } - - try { - await wrapInErrorHandlerAsync('exceptionCallback', exceptionCallback); - fail('RPCError not thrown.'); - } catch (error) { - expect( - error, - isRPCErrorWithMessage( - 'Unexpected DWDS error for exceptionCallback: Exception: An ' - 'unexpected exception', - ), - ); - } - }); - }); -} diff --git a/dwds/test/integration/variable_scope_common.dart b/dwds/test/integration/variable_scope_common.dart deleted file mode 100644 index a1191aa21b..0000000000 --- a/dwds/test/integration/variable_scope_common.dart +++ /dev/null @@ -1,293 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:async'; - -import 'package:dwds/src/debugging/dart_scope.dart'; -import 'package:dwds/src/services/chrome/chrome_proxy_service.dart'; -import 'package:dwds_test_common/logging.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; -import 'package:vm_service/vm_service.dart'; - -import 'fixtures/context.dart'; -import 'fixtures/project.dart'; -import 'fixtures/utilities.dart'; - -void testAll({required TestSdkConfigurationProvider provider}) { - final context = TestContext(TestProject.testScopes, provider); - - setUpAll(() async { - setCurrentLogWriter(debug: provider.verbose); - await context.setUp( - testSettings: TestSettings( - verboseCompiler: provider.verbose, - moduleFormat: provider.ddcModuleFormat, - canaryFeatures: provider.canaryFeatures, - ), - ); - }); - - tearDownAll(() async { - await context.tearDown(); - }); - - group('temporary variable regular expression', () { - setUpAll(() => setCurrentLogWriter(debug: provider.verbose)); - test('matches correctly for pre-patterns temporary variables', () { - expect(previousDdcTemporaryVariableRegExp.hasMatch(r't4$'), isTrue); - expect(previousDdcTemporaryVariableRegExp.hasMatch(r't4$0'), isTrue); - expect(previousDdcTemporaryVariableRegExp.hasMatch(r't4$10'), isTrue); - expect(previousDdcTemporaryVariableRegExp.hasMatch(r't4$0'), isTrue); - expect(previousDdcTemporaryVariableRegExp.hasMatch(r't1'), isTrue); - expect(previousDdcTemporaryVariableRegExp.hasMatch(r't10'), isTrue); - expect(previousDdcTemporaryVariableRegExp.hasMatch(r'__t$TL'), isTrue); - expect( - previousDdcTemporaryVariableRegExp.hasMatch(r'__t$StringN'), - isTrue, - ); - expect( - previousDdcTemporaryVariableRegExp.hasMatch( - r'__t$IdentityMapOfString$T', - ), - isTrue, - ); - - expect(previousDdcTemporaryVariableRegExp.hasMatch(r't'), isFalse); - expect(previousDdcTemporaryVariableRegExp.hasMatch(r't10foo'), isFalse); - expect(previousDdcTemporaryVariableRegExp.hasMatch(r't$10foo'), isFalse); - }); - - test('matches correctly for post-patterns temporary variables', () { - expect(ddcTemporaryVariableRegExp.hasMatch(r't$364$'), isTrue); - expect(ddcTemporaryVariableRegExp.hasMatch(r't$364$0'), isTrue); - expect(ddcTemporaryVariableRegExp.hasMatch(r't$364$10'), isTrue); - expect(ddcTemporaryVariableRegExp.hasMatch(r't$364$0'), isTrue); - expect(ddcTemporaryVariableRegExp.hasMatch(r't$361'), isTrue); - expect(ddcTemporaryVariableRegExp.hasMatch(r't$36$350$350'), isTrue); - expect( - ddcTemporaryVariableRegExp.hasMatch(r't$36$350$354$35isSet'), - isTrue, - ); - expect( - ddcTemporaryVariableRegExp.hasMatch(r't$36$35variable$35isSet'), - isTrue, - ); - expect( - ddcTemporaryVariableRegExp.hasMatch(r'synthetic$35variable'), - isTrue, - ); - expect(ddcTemporaryTypeVariableRegExp.hasMatch(r'__t$TL'), isTrue); - expect(ddcTemporaryTypeVariableRegExp.hasMatch(r'__t$StringN'), isTrue); - expect( - ddcTemporaryTypeVariableRegExp.hasMatch(r'__t$IdentityMapOfString$T'), - isTrue, - ); - - expect(ddcTemporaryVariableRegExp.hasMatch(r't'), isFalse); - expect(ddcTemporaryVariableRegExp.hasMatch(r'this'), isFalse); - expect(ddcTemporaryVariableRegExp.hasMatch(r'\$this'), isFalse); - expect(ddcTemporaryVariableRegExp.hasMatch(r't10'), isFalse); - expect(ddcTemporaryVariableRegExp.hasMatch(r't10foo'), isFalse); - expect(ddcTemporaryVariableRegExp.hasMatch(r'ten'), isFalse); - expect(ddcTemporaryVariableRegExp.hasMatch(r'my$3635variable'), isFalse); - }); - }); - - group('variable scope', () { - late ChromeProxyService service; - VM vm; - String? isolateId; - late Stream stream; - ScriptList scripts; - late ScriptRef mainScript; - Stack stack; - - // TODO: Be able to set breakpoints before start/reload so we can exercise - // things that aren't in recurring loops. - - /// Support function for pausing and returning the stack at a line. - Future breakAt(String breakpointId, ScriptRef scriptRef) async { - final lineNumber = await context.findBreakpointLine( - breakpointId, - isolateId!, - scriptRef, - ); - - final bp = await service.addBreakpoint( - isolateId!, - scriptRef.id!, - lineNumber, - ); - // Wait for breakpoint to trigger. - await stream.firstWhere( - (event) => event.kind == EventKind.kPauseBreakpoint, - ); - // Remove breakpoint so it doesn't impact other tests. - await service.removeBreakpoint(isolateId!, bp.id!); - final stack = await service.getStack(isolateId!); - return stack; - } - - Future getInstance(InstanceRef ref) async { - final result = await service.getObject(isolateId!, ref.id!); - expect(result, isA()); - return result as Instance; - } - - void expectDartObject(String variableName, Instance instance) { - expect( - instance, - isA().having( - (instance) => instance.classRef!.name, - '$variableName: classRef.name', - isNot( - isIn(['NativeJavaScriptObject', 'JavaScriptObject', 'NativeError']), - ), - ), - ); - } - - Future expectDartVariables( - Map variables, - ) async { - for (final name in variables.keys) { - final instance = await getInstance(variables[name]!); - expectDartObject(name!, instance); - } - } - - Map getFrameVariables(Frame frame) { - return { - for (final variable in frame.vars!) - variable.name: variable.value as InstanceRef?, - }; - } - - setUpAll(() => setCurrentLogWriter(debug: provider.verbose)); - - setUp(() async { - service = context.service; - vm = await service.getVM(); - isolateId = vm.isolates!.first.id; - scripts = await service.getScripts(isolateId!); - await service.streamListen('Debug'); - stream = service.onEvent('Debug'); - mainScript = scripts.scripts!.firstWhere( - (each) => each.uri!.contains('main.dart'), - ); - }); - - tearDown(() async { - await service.resume(isolateId!); - }); - - test('variables in static function', () async { - stack = await breakAt('staticFunction', mainScript); - final variables = getFrameVariables(stack.frames!.first); - await expectDartVariables(variables); - - final variableNames = variables.keys.toList()..sort(); - expect(variableNames, containsAll(['formal'])); - }); - - test('variables in static async function', () async { - stack = await breakAt('staticAsyncFunction', mainScript); - final variables = getFrameVariables(stack.frames!.first); - await expectDartVariables(variables); - - final variableNames = variables.keys.toList()..sort(); - final variableValues = variableNames - .map((name) => variables[name]?.valueAsString) - .toList(); - expect(variableNames, containsAll(['myLocal', 'value'])); - expect(variableValues, containsAll(['a local value', 'arg1'])); - }); - - test('variables in static async loop function', () async { - stack = await breakAt('staticAsyncLoopFunction', mainScript); - final variables = getFrameVariables(stack.frames!.first); - await expectDartVariables(variables); - - final variableNames = variables.keys.toList()..sort(); - final variableValues = variableNames - .map((name) => variables[name]?.valueAsString) - .toList(); - expect(variableNames, containsAll(['i', 'myLocal', 'value'])); - // Ensure the loop variable, i, is captued correctly. The value from the - // first iteration should be captured by the saved closure. - expect(variableValues, containsAll(['1', 'my local value', 'arg2'])); - }); - - test('variables in function', () async { - stack = await breakAt('nestedFunction', mainScript); - final variables = getFrameVariables(stack.frames!.first); - await expectDartVariables(variables); - - final variableNames = variables.keys.toList()..sort(); - expect( - variableNames, - containsAll([ - 'aClass', - 'another', - 'intLocalInMain', - 'local', - 'localThatsNull', - 'nestedFunction', - 'parameter', - 'testClass', - ]), - ); - }); - - test('variables in closure nested in method', () async { - stack = await breakAt('nestedClosure', mainScript); - final variables = getFrameVariables(stack.frames!.first); - await expectDartVariables(variables); - - final variableNames = variables.keys.toList()..sort(); - expect(variableNames, [ - 'closureLocalInsideMethod', - 'local', - 'parameter', - 'this', - ]); - }); - - test('variables in method', () async { - stack = await breakAt('printMethod', mainScript); - final variables = getFrameVariables(stack.frames!.first); - await expectDartVariables(variables); - - final variableNames = variables.keys.toList()..sort(); - expect(variableNames, ['this']); - }); - - test('variables in extension method', () async { - stack = await breakAt('extension', mainScript); - final variables = getFrameVariables(stack.frames!.first); - await expectDartVariables(variables); - - final variableNames = variables.keys.toList()..sort(); - // Note: '$this' should change to 'this', and 'return' should - // disappear after debug symbols are available. - // https://github.com/dart-lang/webdev/issues/1371 - expect(variableNames, ['\$this', 'ret', 'return']); - }); - - test('evaluateJsOnCallFrame', () async { - stack = await breakAt('nestedFunction', mainScript); - final debugger = await service.debuggerFuture; - final parameter = await debugger.evaluateJsOnCallFrameIndex( - 0, - 'parameter', - ); - expect(parameter.value, matches(RegExp(r'\d+ world'))); - final ticks = await debugger.evaluateJsOnCallFrameIndex(1, 'ticks'); - // We don't know how many ticks there were before we stopped, but it - // should be a positive number. - expect(ticks.value, isPositive); - }); - }); -} diff --git a/dwds/test/integration/web/batched_stream_test.dart b/dwds/test/integration/web/batched_stream_test.dart deleted file mode 100644 index 78e824999e..0000000000 --- a/dwds/test/integration/web/batched_stream_test.dart +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@Retry(0) -@Timeout(Duration(minutes: 2)) -library; - -import 'dart:async'; -import 'dart:io'; - -import 'package:dwds/shared/batched_stream.dart'; -import 'package:test/expect.dart'; -import 'package:test/scaffolding.dart'; - -void main() { - group('Batched stream controller', () { - test( - 'emits batches', - () async { - const size = 100; - const delay = Duration(milliseconds: 1000); - - final batchOne = List.generate(size, (index) => index); - final batchTwo = List.generate(size, (index) => size + index); - - // Setup controller. - final controller = BatchedStreamController(delay: 500); - - // Verify the output. - expect(controller.stream, emitsInOrder([batchOne, batchTwo])); - - // Add input. - final inputController = StreamController(); - final inputAdded = controller.sink.addStream(inputController.stream); - - batchOne.forEach(inputController.sink.add); - await Future.delayed(delay); - batchTwo.forEach(inputController.sink.add); - - await inputController.close(); - await inputAdded; - await controller.close(); - }, - // https://github.com/dart-lang/webdev/issues/2126 - skip: Platform.isWindows, - ); - - test('emits all inputs in order', () async { - const size = 10; - const delay = Duration(milliseconds: 200); - - // Setup controller. - final controller = BatchedStreamController(delay: 500); - - // Setup output listener. - final output = controller.stream.toList(); - - // Add input. - final inputController = StreamController(); - final inputAdded = controller.sink.addStream(inputController.stream); - - final input = List.generate(size, (index) => index); - for (final e in input) { - inputController.sink.add(e); - await Future.delayed(delay); - } - - await inputController.close(); - await inputAdded; - await controller.close(); - - // Verify the output. - final result = await output; - expect(result.length, greaterThan(1)); - - final flattened = []; - result.forEach(flattened.addAll); - expect(flattened, input); - }); - }); -} diff --git a/dwds/test/services/expression_compiler_worker_args_test.dart b/dwds/test/services/expression_compiler_worker_args_test.dart deleted file mode 100644 index 79ff56595a..0000000000 --- a/dwds/test/services/expression_compiler_worker_args_test.dart +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'package:dwds/src/services/expression_compiler.dart'; -import 'package:dwds/src/services/expression_compiler_service.dart'; -import 'package:test/test.dart'; - -void main() { - group('expressionCompilerWorkerArgs', () { - List argsFor({bool? deprecatedJsInterop}) => - expressionCompilerWorkerArgs( - sdkSummaryUri: Uri.file('/sdk/ddc_outline.dill'), - address: 'localhost', - port: 1234, - compilerOptions: CompilerOptions( - moduleFormat: ModuleFormat.ddc, - canaryFeatures: true, - experiments: const ['records'], - deprecatedJsInterop: deprecatedJsInterop, - ), - verbose: false, - ); - - test('passes the compiler options', () { - expect(argsFor(), [ - '--experimental-expression-compiler', - '--dart-sdk-summary', - 'file:///sdk/ddc_outline.dill', - '--asset-server-address', - 'localhost', - '--asset-server-port', - '1234', - '--module-format', - 'ddc', - '--enable-experiment=records', - '--canary', - ]); - }); - - test('does not pass deprecated-js-interop when not configured', () { - expect(argsFor(), isNot(contains(contains('deprecated-js-interop')))); - }); - - test('passes --deprecated-js-interop', () { - final args = argsFor(deprecatedJsInterop: true); - expect(args, contains('--deprecated-js-interop')); - expect(args, isNot(contains('--no-deprecated-js-interop'))); - }); - - test('passes --no-deprecated-js-interop', () { - final args = argsFor(deprecatedJsInterop: false); - expect(args, contains('--no-deprecated-js-interop')); - expect(args, isNot(contains('--deprecated-js-interop'))); - }); - }); -} diff --git a/dwds/test/utilities/fix_protocol_test.dart b/dwds/test/utilities/fix_protocol_test.dart deleted file mode 100644 index 99764f5242..0000000000 --- a/dwds/test/utilities/fix_protocol_test.dart +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'package:dwds/src/utilities/fix_protocol.dart'; -import 'package:test/test.dart'; - -void main() { - group('fixProtocol', () { - group('when window location protocol is https:', () { - const windowProtocol = 'https:'; - - test('upgrades http to https for non-localhost hosts', () { - expect( - fixProtocol( - 'http://example.com/foo/\$dwdsSseHandler', - windowLocationProtocol: windowProtocol, - ), - 'https://example.com/foo/\$dwdsSseHandler', - ); - }); - - test('upgrades ws to wss for non-localhost hosts', () { - expect( - fixProtocol( - 'ws://example.com/foo/\$dwdsSseHandler', - windowLocationProtocol: windowProtocol, - ), - 'wss://example.com/foo/\$dwdsSseHandler', - ); - }); - - test('does not modify http on localhost', () { - expect( - fixProtocol( - 'http://localhost:8080/foo/\$dwdsSseHandler', - windowLocationProtocol: windowProtocol, - ), - 'http://localhost:8080/foo/\$dwdsSseHandler', - ); - }); - - test('does not modify ws on localhost', () { - expect( - fixProtocol( - 'ws://localhost:8080/foo/\$dwdsSseHandler', - windowLocationProtocol: windowProtocol, - ), - 'ws://localhost:8080/foo/\$dwdsSseHandler', - ); - }); - - test('leaves https unchanged for non-localhost hosts', () { - expect( - fixProtocol( - 'https://example.com/foo/\$dwdsSseHandler', - windowLocationProtocol: windowProtocol, - ), - 'https://example.com/foo/\$dwdsSseHandler', - ); - }); - - test('leaves wss unchanged for non-localhost hosts', () { - expect( - fixProtocol( - 'wss://example.com/foo/\$dwdsSseHandler', - windowLocationProtocol: windowProtocol, - ), - 'wss://example.com/foo/\$dwdsSseHandler', - ); - }); - }); - - group('when window location protocol is http:', () { - const windowProtocol = 'http:'; - - test('does not modify http for non-localhost hosts', () { - expect( - fixProtocol( - 'http://example.com/foo/\$dwdsSseHandler', - windowLocationProtocol: windowProtocol, - ), - 'http://example.com/foo/\$dwdsSseHandler', - ); - }); - - test('does not modify ws for non-localhost hosts', () { - expect( - fixProtocol( - 'ws://example.com/foo/\$dwdsSseHandler', - windowLocationProtocol: windowProtocol, - ), - 'ws://example.com/foo/\$dwdsSseHandler', - ); - }); - - test('does not modify http on localhost', () { - expect( - fixProtocol( - 'http://localhost:8080/foo/\$dwdsSseHandler', - windowLocationProtocol: windowProtocol, - ), - 'http://localhost:8080/foo/\$dwdsSseHandler', - ); - }); - - test('does not modify ws on localhost', () { - expect( - fixProtocol( - 'ws://localhost:8080/foo/\$dwdsSseHandler', - windowLocationProtocol: windowProtocol, - ), - 'ws://localhost:8080/foo/\$dwdsSseHandler', - ); - }); - }); - - group('when window location protocol is not https: (e.g. file:)', () { - test('does not modify urls', () { - expect( - fixProtocol( - 'http://example.com/foo', - windowLocationProtocol: 'file:', - ), - 'http://example.com/foo', - ); - expect( - fixProtocol('ws://example.com/foo', windowLocationProtocol: 'file:'), - 'ws://example.com/foo', - ); - }); - }); - }); -} diff --git a/dwds/test/utilities/uuid_test.dart b/dwds/test/utilities/uuid_test.dart deleted file mode 100644 index 51c4216f7f..0000000000 --- a/dwds/test/utilities/uuid_test.dart +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'package:dwds/src/utilities/uuid.dart'; -import 'package:test/test.dart'; - -void main() { - group('Uuid', () { - test('v4 generates valid UUIDs', () { - final uuid = const Uuid(); - final id = uuid.v4(); - expect(id, hasLength(36)); - expect( - id, - matches( - RegExp( - r'^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-' - r'[89ab][0-9a-f]{3}-[0-9a-f]{12}$', - ), - ), - ); - }); - - test('v4 generates unique UUIDs', () { - final uuid = const Uuid(); - final id1 = uuid.v4(); - final id2 = uuid.v4(); - expect(id1, isNot(equals(id2))); - }); - - test('v4 sets version and variant bits correctly', () { - final uuid = const Uuid(); - final id = uuid.v4(); - // Version 4 - expect(id[14], equals('4')); - // Variant 10xx (8, 9, a, b) - expect(id[19], matches(RegExp(r'[89ab]'))); - }); - }); -} diff --git a/dwds/tool/build.dart b/dwds/tool/build.dart deleted file mode 100644 index 4e437aa231..0000000000 --- a/dwds/tool/build.dart +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:convert'; -import 'dart:io'; - -import 'package:crypto/crypto.dart'; - -void main() async { - // 1. Extract the version from pubspec.yaml - final pubspec = File('pubspec.yaml').readAsStringSync(); - final versionMatch = RegExp(r'version: (.*)').firstMatch(pubspec); - final version = versionMatch?.group(1); - if (version == null) { - throw Exception('Failed to find version in pubspec.yaml'); - } - - // 2. Generate lib/src/version.dart - final versionFile = File('lib/src/version.dart'); - versionFile.writeAsStringSync(''' -// Generated code. Do not modify. -const packageVersion = '$version'; -'''); - - // 3. Compile the web client to JavaScript - print('Compiling client.js...'); - final result = await Process.run(Platform.executable, [ - 'compile', - 'js', - '-O1', - '--no-source-maps', - '-o', - 'lib/src/injected/client.js', - 'web/client.dart', - ]); - - if (result.exitCode != 0) { - print('Failed to compile client.js'); - print(result.stdout); - print(result.stderr); - exit(result.exitCode); - } - - print('Compilation successful'); - - // 4. Clean up the generated .deps file - final depsFile = File('lib/src/injected/client.js.deps'); - if (depsFile.existsSync()) { - depsFile.deleteSync(); - } - - // 5. Generate injected_client_js.dart - print('Generating injected_client_js.dart...'); - - final clientDartString = File('web/client.dart') - .readAsStringSync() - .replaceAll('\r\n', '\n'); - final clientDartHash = sha256 - .convert(utf8.encode(clientDartString)) - .toString(); - - final compiledJs = File('lib/src/injected/client.js').readAsStringSync(); - final lines = compiledJs.replaceAll('\r\n', '\n').split('\n'); - - // Escape JS payload line-by-line using jsonEncode for multiline readability, - // ensure newlines are preserved identically, and manually escape the dollar - // sign ($) to avoid Dart interpolation. - final safeDartString = [ - for (var i = 0; i < lines.length; i++) - jsonEncode(i == lines.length - 1 ? lines[i] : '${lines[i]}\n') - .replaceAll(r'$', r'\$'), - ].join('\n'); - - final injectedClientJsFile = File('lib/src/handlers/injected_client_js.dart'); - injectedClientJsFile.writeAsStringSync(''' -// Generated code. Do not modify. -// Emits the transpiled client.js directly into a statically embeddable string. -// dart format off - -const injectedClientJs = $safeDartString; - -const clientDartHash = '$clientDartHash'; -'''); - print('Successfully packed client.js into injected_client_js.dart'); -} diff --git a/dwds/tool/release.dart b/dwds/tool/release.dart deleted file mode 100644 index 30c136edff..0000000000 --- a/dwds/tool/release.dart +++ /dev/null @@ -1,247 +0,0 @@ -// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:io'; - -import 'package:args/args.dart'; - -const _packageOption = 'package'; -const _versionOption = 'version'; -const _resetFlag = 'reset'; -const _skipStableCheckFlag = 'skipStableCheck'; - -final _packageDir = File.fromUri(Platform.script).parent.parent.path; - -/// Note: Must be run from the /tool directory. -/// -/// To prepare DWDS for release: -/// `dart run release.dart -p dwds` -/// -/// To reset DWDS after a release: -/// `dart run release.dart --reset -p dwds -v [[wip version]]` - -void main(List arguments) async { - final parser = ArgParser() - ..addOption( - _packageOption, - abbr: 'p', - allowed: ['dwds'], - defaultsTo: 'dwds', - ) - ..addOption(_versionOption, abbr: 'v') - ..addFlag(_resetFlag, abbr: 'r') - ..addFlag(_skipStableCheckFlag, abbr: 's'); - - final argResults = parser.parse(arguments); - final package = argResults[_packageOption] as String?; - if (package == null) { - _logWarning('Please specify package with -p dwds or --package=dwds'); - return; - } - - final isReset = argResults[_resetFlag] as bool?; - final newVersion = argResults[_versionOption] as String?; - final skipStableCheck = argResults[_skipStableCheckFlag] as bool?; - - int exitCode; - if (isReset == true) { - exitCode = await runReset(newVersion: newVersion); - } else { - exitCode = await runRelease( - newVersion: newVersion, - skipStableCheck: skipStableCheck, - ); - } - if (exitCode != 0) { - _logWarning('Run terminated unexpectedly with exit code: $exitCode'); - } -} - -Future runReset({String? newVersion}) { - // Check that a new wip version has been provided. - final currentVersion = _readVersionFile(); - if (newVersion == null || !newVersion.contains('wip')) { - _logInfo(''' - Please provide the next wip version for dwds, e.g. -v 3.0.1-wip - Current version is $currentVersion. - '''); - return Future.value(1); - } - - // Reset the dependency overrides for the package: - _updateOverrides(includeOverrides: true); - - // Update the version strings in CHANGELOG and pubspec.yaml. - _updateVersionStrings( - currentVersion: currentVersion, - nextVersion: newVersion, - isReset: true, - ); - - // Build the package. - final exitCode = _buildPackage(); - return exitCode; -} - -Future runRelease({String? newVersion, bool? skipStableCheck}) async { - // Check that we are on a stable version of Dart. - if (skipStableCheck != true) { - final checkVersionProcess = await Process.run('dart', ['--version']); - final versionInfo = checkVersionProcess.stdout as String; - if (!versionInfo.contains('stable')) { - _logWarning(''' - Expected to be on stable version of Dart, instead on: - $versionInfo - To skip this check, re-run with --skipStableCheck - '''); - return checkVersionProcess.exitCode; - } - } - - // Remove any dependency overrides for the package: - _logInfo('Removing dependency overrides for dwds.'); - _updateOverrides(includeOverrides: false); - - // Run dart pub upgrade. - _logInfo('Upgrading pub packages for dwds'); - final pubUpgradeProcess = await Process.run('dart', [ - 'pub', - 'upgrade', - ], workingDirectory: _packageDir); - final upgradeErrors = pubUpgradeProcess.stderr as String; - if (upgradeErrors.isNotEmpty) { - _logWarning(upgradeErrors); - return pubUpgradeProcess.exitCode; - } - - // Update the version strings in CHANGELOG and pubspec.yaml. - final currentVersion = _readVersionFile(); - final nextVersion = newVersion ?? _removeWip(currentVersion); - _updateVersionStrings( - currentVersion: currentVersion, - nextVersion: nextVersion, - ); - - // Build the package. - final exitCode = _buildPackage(); - return exitCode; -} - -Future _buildPackage() async { - _logInfo('Building dwds'); - final buildProcess = await Process.run('dart', [ - 'run', - 'tool/build.dart', - ], workingDirectory: _packageDir); - - final buildErrors = buildProcess.stderr as String; - if (buildErrors.isNotEmpty) { - _logWarning(buildErrors); - } - return buildProcess.exitCode; -} - -void _updateOverrides({required bool includeOverrides}) { - final overridesFilePath = '$_packageDir/pubspec_overrides.yaml'; - final noOverridesFilePath = '$_packageDir/ignore_pubspec_overrides.yaml'; - if (includeOverrides) { - _renameFile(currentName: noOverridesFilePath, newName: overridesFilePath); - } else { - _renameFile(currentName: overridesFilePath, newName: noOverridesFilePath); - } -} - -void _renameFile({required String currentName, required String newName}) { - final currentFile = File(currentName); - if (!currentFile.existsSync()) { - _logInfo('Skip renaming $currentName to $newName, file does not exist.'); - return; - } - currentFile.rename(newName); -} - -void _updateVersionStrings({ - required String nextVersion, - required String currentVersion, - bool isReset = false, -}) { - _logInfo('Updating dwds from $currentVersion to $nextVersion'); - final pubspec = File('$_packageDir/pubspec.yaml'); - final changelog = File('$_packageDir/CHANGELOG.md'); - if (isReset) { - _addNewLine(changelog, newLine: '## $nextVersion'); - _replaceInFile(pubspec, query: currentVersion, replaceWith: nextVersion); - } else { - for (final file in [pubspec, changelog]) { - _replaceInFile(file, query: currentVersion, replaceWith: nextVersion); - } - } -} - -void _addNewLine(File file, {required String newLine, int insertAt = 0}) { - final currentLines = file.readAsLinesSync(); - final linesBefore = currentLines.sublist(0, insertAt); - final linesAfter = currentLines.sublist(insertAt); - final newLines = [...linesBefore, newLine, '', ...linesAfter]; - final content = newLines.joinWithNewLine(); - return file.writeAsStringSync(content); -} - -bool _replaceInFile( - File file, { - required String query, - required String replaceWith, -}) { - final newLines = []; - var replaced = false; - for (final line in file.readAsLinesSync()) { - if (line.contains(query)) { - newLines.add(line.replaceAll(query, replaceWith)); - replaced = true; - } else { - newLines.add(line); - } - } - final content = newLines.joinWithNewLine(); - file.writeAsStringSync(content); - return replaced; -} - -String _readVersionFile() { - final versionFile = File('$_packageDir/lib/src/version.dart'); - final lines = versionFile.readAsLinesSync(); - for (final line in lines) { - if (line.startsWith('const packageVersion =')) { - final version = line - .split('=') - .last - .split('') - .where((char) => char != ';' && char != "'" && char != '"') - .join(''); - return version.trim(); - } - } - throw Exception('Could not read version in dwds/lib/src/version.dart'); -} - -String _removeWip(String wipVersion) { - if (!wipVersion.contains('wip')) { - throw Exception('$wipVersion is not a wip version.'); - } - return wipVersion.split('-wip').first; -} - -void _logInfo(String message) { - stdout.writeln(message); -} - -void _logWarning(String warning) { - stderr.writeln(warning); -} - -extension JoinExtension on List { - String joinWithNewLine() { - return '${join('\n')}\n'; - } -} diff --git a/dwds/web/client.dart b/dwds/web/client.dart deleted file mode 100644 index 4676b0674a..0000000000 --- a/dwds/web/client.dart +++ /dev/null @@ -1,695 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:async'; -import 'dart:convert'; -import 'dart:js_interop'; - -import 'package:dwds/data/build_result.dart'; -import 'package:dwds/data/connect_request.dart'; -import 'package:dwds/data/debug_event.dart'; -import 'package:dwds/data/debug_info.dart'; -import 'package:dwds/data/devtools_request.dart'; -import 'package:dwds/data/error_response.dart'; -import 'package:dwds/data/extension_request.dart'; -import 'package:dwds/data/hot_reload_request.dart'; -import 'package:dwds/data/hot_reload_response.dart'; -import 'package:dwds/data/hot_restart_request.dart'; -import 'package:dwds/data/hot_restart_response.dart'; -import 'package:dwds/data/ping_request.dart'; -import 'package:dwds/data/register_event.dart'; -import 'package:dwds/data/run_request.dart'; -import 'package:dwds/data/service_extension_request.dart'; -import 'package:dwds/data/service_extension_response.dart'; -import 'package:dwds/shared/batched_stream.dart'; -import 'package:dwds/src/sockets.dart'; -import 'package:dwds/src/utilities/fix_protocol.dart'; -import 'package:dwds/src/utilities/uuid.dart'; -import 'package:http/browser_client.dart'; -import 'package:sse/client/sse_client.dart'; -import 'package:web/web.dart'; - -import 'reloader/ddc_library_bundle_restarter.dart'; -import 'reloader/ddc_restarter.dart'; -import 'reloader/manager.dart'; -import 'reloader/require_restarter.dart'; -import 'run_main.dart'; -import 'web_utils.dart'; - -const _batchDelayMilliseconds = 1000; - -// GENERATE: -// pub run build_runner build web -Future? main() { - return runZonedGuarded( - () async { - // Set the unique id for this instance of the app. - // Test apps may already have this set. - const dartAppInstanceIdKey = 'dartAppInstanceId'; - if (dartAppInstanceId == null) { - // Check the session storage for the instance id. - // Only reuse [storedInstanceId] on page reload. - // Duplicating a tab clones its session storage, so we want to avoid - // the duplicate taking over the original tab's DWDS connection. - final storedInstanceId = _isPageReload - ? window.sessionStorage.getItem(dartAppInstanceIdKey) - : null; - if (storedInstanceId != null) { - dartAppInstanceId = storedInstanceId; - } else { - dartAppInstanceId = const Uuid().v4(); - window.sessionStorage.setItem( - dartAppInstanceIdKey, - dartAppInstanceId!, - ); - } - } - - final fixedPath = fixProtocol( - dwdsDevHandlerPath, - windowLocationProtocol: window.location.protocol, - ); - final fixedUri = Uri.parse(fixedPath); - final client = fixedUri.isScheme('ws') || fixedUri.isScheme('wss') - ? WebSocketClient( - await PersistentWebSocket.connect( - fixedUri, - onReconnect: initializeConnection, - ), - ) - : SseSocketClient(SseClient(fixedPath, debugKey: 'InjectedClient')); - - final restarter = switch (dartModuleStrategy) { - 'require-js' => await RequireRestarter.create(), - 'ddc-library-bundle' => DdcLibraryBundleRestarter(), - 'ddc' || 'legacy' => DdcRestarter(), - _ => throw StateError('Unknown module strategy: $dartModuleStrategy'), - }; - - final manager = ReloadingManager(client, restarter); - - hotReloadStartJs = () { - return manager.hotReloadStart(hotReloadReloadedSourcesPath).toJS; - }.toJS; - - hotReloadEndJs = () { - return manager.hotReloadEnd().toJS; - }.toJS; - - hotRestartBeginJs = () { - return manager.hotRestartBegin(hotReloadReloadedSourcesPath).toJS; - }.toJS; - - hotRestartEndJs = manager.hotRestartEnd.toJS; - - Completer? readyToRunMainCompleter; - - hotRestartJs = (String runId, [bool? pauseIsolatesOnStart]) { - if (pauseIsolatesOnStart ?? false) { - readyToRunMainCompleter = Completer(); - return manager - .hotRestart( - runId: runId, - readyToRunMain: readyToRunMainCompleter!.future, - reloadedSourcesPath: hotRestartReloadedSourcesPath, - ) - .toJS; - } else { - return manager - .hotRestart( - runId: runId, - reloadedSourcesPath: hotRestartReloadedSourcesPath, - ) - .toJS; - } - }.toJS; - - requestHotRestartJs = (String runId) { - _trySendEvent( - client.sink, - jsonEncode([ - 'HotRestartRequest', - HotRestartRequest(id: runId).toJson(), - ]), - ); - }.toJS; - - readyToRunMainJs = () { - if (readyToRunMainCompleter == null) return; - if (readyToRunMainCompleter!.isCompleted) return; - readyToRunMainCompleter!.complete(); - readyToRunMainCompleter = null; - }.toJS; - - final debugEventController = BatchedStreamController( - delay: _batchDelayMilliseconds, - ); - debugEventController.stream.listen((events) { - if (dartEmitDebugEvents) { - _trySendEvent( - client.sink, - jsonEncode([ - 'BatchedDebugEvents', - BatchedDebugEvents(events: events).toJson(), - ]), - ); - } - }); - - emitDebugEvent = (String kind, String eventData) { - if (dartEmitDebugEvents) { - _trySendEvent( - debugEventController.sink, - DebugEvent( - kind: kind, - eventData: eventData, - timestamp: DateTime.now().millisecondsSinceEpoch, - ), - ); - } - }.toJS; - - emitRegisterEvent = (String eventData) { - _trySendEvent( - client.sink, - jsonEncode([ - 'RegisterEvent', - RegisterEvent( - eventData: eventData, - timestamp: DateTime.now().millisecondsSinceEpoch, - ).toJson(), - ]), - ); - }.toJS; - - launchDevToolsJs = () { - if (!_isChromium) { - window.alert( - 'Dart DevTools is only supported on Chromium based browsers.', - ); - return; - } - _trySendEvent( - client.sink, - jsonEncode( - DevToolsRequest(appId: dartAppId, instanceId: dartAppInstanceId!), - ), - ); - }.toJS; - - var mainRun = false; - client.stream.listen( - (serialized) async { - final event = _deserializeEvent(jsonDecode(serialized)); - if (event is BuildResult) { - if (reloadConfiguration == 'ReloadConfiguration.liveReload') { - manager.reloadPage(); - } else if (reloadConfiguration == - 'ReloadConfiguration.hotRestart') { - if (dartModuleStrategy == 'ddc-library-bundle') { - await manager.hotRestartBegin(hotRestartReloadedSourcesPath!); - manager.hotRestartEnd(); - } else { - await manager.hotRestart( - reloadedSourcesPath: hotRestartReloadedSourcesPath, - ); - } - } else if (reloadConfiguration == 'ReloadConfiguration.hotReload') { - await manager.hotReloadStart(hotReloadReloadedSourcesPath); - await manager.hotReloadEnd(); - } - } else if (event is DevToolsResponse) { - if (!event.success) { - final alert = 'DevTools failed to open with:\n${event.error}'; - if (event.promptExtension && window.confirm(alert)) { - window.open( - 'https://dart.dev/to/web-debug-extension', - '_blank', - ); - } else { - window.alert(alert); - } - } - } else if (event is RunRequest) { - // If main has already been run (e.g., in the situation where we - // lost connection to DWDS and reattached), don't try and run main - // again. - if (!mainRun) { - mainRun = true; - runMain(); - } - } else if (event is ErrorResponse) { - window.reportError( - 'Error from backend:\n\n' - 'Error: ${event.error}\n\n' - 'Stack Trace:\n${event.stackTrace}' - .toJS, - ); - } else if (event is HotReloadRequest) { - await handleWebSocketHotReloadRequest(event, manager, client.sink); - } else if (event is HotRestartRequest) { - await handleWebSocketHotRestartRequest(event, manager, client.sink); - } else if (event is ServiceExtensionRequest) { - await handleServiceExtensionRequest(event, client.sink, manager); - } - }, - onError: (error) { - // An error is propagated on a full page reload as Chrome presumably - // forces the SSE connection to close in a bad state. This does not - // cause any adverse effects so simply swallow this error as to not - // print the misleading unhandled error message. - }, - ); - - if (dwdsEnableDevToolsLaunch) { - window.onKeyDown.listen((Event e) { - if (e.isA()) { - final event = e as KeyboardEvent; - if (const [ - 'd', - 'D', - '∂', // alt-d output on Mac - 'Î', // shift-alt-D output on Mac - ].contains(event.key) && - event.altKey && - !event.ctrlKey && - !event.metaKey) { - event.preventDefault(); - launchDevToolsJs.callAsFunction(); - } - } - }); - } - initializeConnection(client.sink); - }, - (error, stackTrace) { - print(''' -Unhandled error detected in the injected client.js script. - -You can disable this script in webdev by passing --no-injected-client if it -is preventing your app from loading, but note that this will also prevent -all debugging and hot reload/restart functionality from working. - -The original error is below, please file an issue at -https://github.com/dart-lang/webdev/issues/new and attach this output: - -$error -$stackTrace -'''); - }, - ); -} - -void initializeConnection(StreamSink clientSink) { - if (dartModuleStrategy != 'ddc-library-bundle') { - if (_isChromium) { - _sendConnectRequest(clientSink); - } else { - // If not Chromium we just invoke main, devtools aren't supported. - runMain(); - } - } else { - _sendConnectRequest(clientSink); - } - _launchCommunicationWithDebugExtension(); -} - -void _trySendEvent(StreamSink sink, T serialized) { - try { - sink.add(serialized); - // ignore: avoid_catching_errors - } on StateError catch (_) { - // An error is propagated on a full page reload as Chrome presumably - // forces the SSE connection to close in a bad state. - print( - 'Cannot send event $serialized. ' - 'Injected client connection is closed.', - ); - } -} - -/// Deserializes incoming events from the server. -/// Handles wire format ['TypeName', json] for plain Dart types. -Object? _deserializeEvent(dynamic decoded) { - if (decoded case [final String typeName, ...]) { - // For Map-based RPC data types, the second element is the JSON map. - final jsonData = switch (decoded) { - [_, final Map map] => map, - _ => const {}, - }; - - return switch (typeName) { - // List-based RPC data types: - 'DevToolsResponse' => DevToolsResponse.fromJson(decoded), - // Map-based RPC data types: - 'ConnectRequest' => ConnectRequest.fromJson(jsonData), - 'RunRequest' => RunRequest.fromJson(jsonData), - 'HotReloadRequest' => HotReloadRequest.fromJson(jsonData), - 'HotRestartRequest' => HotRestartRequest.fromJson(jsonData), - 'ServiceExtensionRequest' => ServiceExtensionRequest.fromJson(jsonData), - 'BuildResult' => BuildResult.fromJson(jsonData), - 'ErrorResponse' => ErrorResponse.fromJson(jsonData), - 'PingRequest' => PingRequest.fromJson(jsonData), - _ => null, - }; - } - return null; -} - -void _sendConnectRequest(StreamSink clientSink) { - final request = ConnectRequest( - appId: dartAppId, - instanceId: dartAppInstanceId!, - entrypointPath: dartEntrypointPath, - ); - _trySendEvent(clientSink, jsonEncode(['ConnectRequest', request.toJson()])); -} - -void _launchCommunicationWithDebugExtension() { - // Listen for an event from the Dart Debug Extension to authenticate the - // user (sent once the extension receives the dart-app-read event): - _listenForDebugExtensionAuthRequest(); - - // Send the dart-app-ready event along with debug info to the Dart Debug - // Extension so that it can debug the Dart app: - final debugInfoJson = jsonEncode( - DebugInfo( - appEntrypointPath: dartEntrypointPath, - appId: windowContext.$dartAppId, - appInstanceId: dartAppInstanceId, - appOrigin: window.location.origin, - appUrl: window.location.href, - authUrl: _authUrl, - extensionUrl: windowContext.$dartExtensionUri, - isInternalBuild: windowContext.$isInternalBuild, - isFlutterApp: windowContext.$isFlutterApp, - workspaceName: dartWorkspaceName, - ), - ); - _dispatchEvent('dart-app-ready', debugInfoJson); -} - -void _dispatchEvent(String message, String detail) { - final event = CustomEvent(message, CustomEventInit(detail: detail.toJS)); - document.dispatchEvent(event); -} - -void _listenForDebugExtensionAuthRequest() { - window.addEventListener('message', _handleAuthRequest.toJS); -} - -void _handleAuthRequest(Event event) { - final messageEvent = event as MessageEvent; - final data = messageEvent.data; - - if (!data.typeofEquals('string')) return; - if ((data as JSString).toDart != 'dart-auth-request') return; - - // Notify the Dart Debug Extension of authentication status: - if (_authUrl != null) { - _authenticateUser(_authUrl!).then( - (isAuthenticated) => - _dispatchEvent('dart-auth-response', '$isAuthenticated'), - ); - } -} - -Future _authenticateUser(String authUrl) async { - final client = BrowserClient()..withCredentials = true; - final response = await client.get(Uri.parse(authUrl)); - final responseText = response.body; - return responseText.contains('Dart Debug Authentication Success!'); -} - -void _sendResponse( - StreamSink clientSink, - T Function(String, bool, String?) constructor, - String requestId, { - bool success = true, - String? errorMessage, -}) { - final response = constructor(requestId, success, errorMessage); - final encoded = switch (response) { - HotReloadResponse() => ['HotReloadResponse', response.toJson()], - HotRestartResponse() => ['HotRestartResponse', response.toJson()], - _ => throw UnsupportedError('Unknown response type: $response'), - }; - - _trySendEvent(clientSink, jsonEncode(encoded)); -} - -void _sendHotReloadResponse( - StreamSink clientSink, - String requestId, { - bool success = true, - String? errorMessage, -}) { - _sendResponse( - clientSink, - (id, success, errorMessage) => - HotReloadResponse(id: id, success: success, errorMessage: errorMessage), - requestId, - success: success, - errorMessage: errorMessage, - ); -} - -void _sendHotRestartResponse( - StreamSink clientSink, - String requestId, { - bool success = true, - String? errorMessage, -}) { - _sendResponse( - clientSink, - (id, success, errorMessage) => HotRestartResponse( - id: id, - success: success, - errorMessage: errorMessage, - ), - requestId, - success: success, - errorMessage: errorMessage, - ); -} - -void _sendServiceExtensionResponse( - StreamSink clientSink, - String requestId, { - bool success = true, - String? errorMessage, - int? errorCode, - Map? result, -}) { - final response = ServiceExtensionResponse.fromResult( - id: requestId, - success: success, - errorMessage: errorMessage, - errorCode: errorCode, - result: result, - ); - _trySendEvent( - clientSink, - jsonEncode(['ServiceExtensionResponse', response.toJson()]), - ); -} - -Future handleWebSocketHotReloadRequest( - HotReloadRequest event, - ReloadingManager manager, - StreamSink clientSink, -) async { - final requestId = event.id; - try { - await manager.hotReloadStart(hotReloadReloadedSourcesPath); - await manager.hotReloadEnd(); - _sendHotReloadResponse(clientSink, requestId, success: true); - } catch (e) { - _sendHotReloadResponse( - clientSink, - requestId, - success: false, - errorMessage: e.toString(), - ); - } -} - -Future handleWebSocketHotRestartRequest( - HotRestartRequest event, - ReloadingManager manager, - StreamSink clientSink, -) async { - final requestId = event.id; - try { - final runId = const Uuid().v4(); - if (manager.supportsTwoPhaseHotRestart) { - await manager.hotRestartBegin(hotRestartReloadedSourcesPath!); - manager.hotRestartEnd(); - } else { - // TODO(nshahan): Remove after migrating to hotRestartBegin/hotRestartEnd. - // https://github.com/dart-lang/webdev/issues/2826 - await manager.hotRestart( - runId: runId, - reloadedSourcesPath: hotRestartReloadedSourcesPath, - ); - } - _sendHotRestartResponse(clientSink, requestId, success: true); - } catch (e) { - _sendHotRestartResponse( - clientSink, - requestId, - success: false, - errorMessage: e.toString(), - ); - } -} - -Future handleServiceExtensionRequest( - ServiceExtensionRequest request, - StreamSink clientSink, - ReloadingManager manager, -) async { - try { - final result = await manager.handleServiceExtension( - request.method, - request.args, - ); - - if (result != null) { - _sendServiceExtensionResponse( - clientSink, - request.id, - success: true, - result: result, - ); - } else { - // Service extension not supported by this restarter type - _sendServiceExtensionResponse( - clientSink, - request.id, - success: false, - errorMessage: 'Service extension not supported', - errorCode: -32601, // Method not found - ); - } - } catch (e) { - _sendServiceExtensionResponse( - clientSink, - request.id, - success: false, - errorMessage: e.toString(), - ); - } -} - -@JS(r'$dartAppId') -external String get dartAppId; - -@JS(r'$dartAppInstanceId') -external String? get dartAppInstanceId; - -@JS(r'$dwdsDevHandlerPath') -external String get dwdsDevHandlerPath; - -@JS(r'$dartAppInstanceId') -external set dartAppInstanceId(String? id); - -@JS(r'$dartModuleStrategy') -external String get dartModuleStrategy; - -@JS(r'$dartHotReloadStartDwds') -external set hotReloadStartJs(JSFunction cb); - -@JS(r'$dartHotReloadEndDwds') -external set hotReloadEndJs(JSFunction cb); - -@JS(r'$dartHotRestartBeginDwds') -external set hotRestartBeginJs(JSFunction cb); - -@JS(r'$dartHotRestartEndDwds') -external set hotRestartEndJs(JSFunction cb); - -@JS(r'$reloadedSourcesPath') -external String? get _reloadedSourcesPath; - -String? get hotRestartReloadedSourcesPath => _reloadedSourcesPath; - -String get hotReloadReloadedSourcesPath { - final path = _reloadedSourcesPath; - assert( - path != null, - "Expected 'reloadedSourcesPath' to not be null in a hot reload.", - ); - return path!; -} - -/// Debugger-initiated hot restart. -// TODO(nshahan): Remove after migrating to hotRestartBegin/hotRestartEnd. -// https://github.com/dart-lang/webdev/issues/2826 -@JS(r'$dartHotRestartDwds') -external set hotRestartJs(JSFunction cb); - -/// App-initiated hot restart. -/// -/// When there's no debugger attached, the DWDS dev handler sends the request -/// back, and it will be handled by the client stream listener. -@JS(r'$dartRequestHotRestartDwds') -external set requestHotRestartJs(JSFunction cb); - -@JS(r'$dartReadyToRunMain') -external set readyToRunMainJs(JSFunction cb); - -@JS(r'$launchDevTools') -external JSFunction get launchDevToolsJs; - -@JS(r'$launchDevTools') -external set launchDevToolsJs(JSFunction cb); - -@JS(r'$dartReloadConfiguration') -external String get reloadConfiguration; - -@JS(r'$dartEntrypointPath') -external String get dartEntrypointPath; - -@JS(r'$dwdsEnableDevToolsLaunch') -external bool get dwdsEnableDevToolsLaunch; - -@JS(r'$dartEmitDebugEvents') -external bool get dartEmitDebugEvents; - -@JS(r'$emitDebugEvent') -external set emitDebugEvent(JSFunction func); - -@JS(r'$emitRegisterEvent') -external set emitRegisterEvent(JSFunction func); - -@JS(r'$dartWorkspaceName') -external String? get dartWorkspaceName; - -bool get _isChromium => window.navigator.vendor.contains('Google'); - -/// Returns `true` if the current page was loaded by a browser reload. -bool get _isPageReload { - try { - final entries = window.performance.getEntriesByType('navigation').toDart; - if (entries.isEmpty) return false; - return (entries.first as PerformanceNavigationTiming).type == 'reload'; - } catch (_) { - return false; - } -} - -String? get _authUrl { - final extensionUrl = windowContext.$dartExtensionUri; - if (extensionUrl == null) return null; - final authUrl = Uri.parse(extensionUrl).replace(path: authenticationPath); - switch (authUrl.scheme) { - case 'ws': - return authUrl.replace(scheme: 'http').toString(); - case 'wss': - return authUrl.replace(scheme: 'https').toString(); - default: - return authUrl.toString(); - } -} diff --git a/dwds/web/reloader/ddc_library_bundle_restarter.dart b/dwds/web/reloader/ddc_library_bundle_restarter.dart deleted file mode 100644 index 630890bb0c..0000000000 --- a/dwds/web/reloader/ddc_library_bundle_restarter.dart +++ /dev/null @@ -1,205 +0,0 @@ -// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:async'; -import 'dart:convert'; -import 'dart:js_interop'; - -import 'package:dwds/src/utilities/shared.dart'; - -import 'restarter.dart'; - -@JS('dartDevEmbedder') -external _DartDevEmbedder get _dartDevEmbedder; - -extension type _DartDevEmbedder._(JSObject _) implements JSObject { - external _Debugger get debugger; - external JSPromise?> hotRestart([ - JSArray? reloadedSources, - ]); - external JSPromise> hotRestartBegin([ - JSArray? reloadedSources, - ]); - external void hotRestartEnd(); - - external JSPromise hotReload( - JSArray filesToLoad, - JSArray librariesToReload, - ); - external _DartDevEmbedderConfig get config; -} - -extension type _DartDevEmbedderConfig._(JSObject _) implements JSObject { - external JSFunction? capturedMainHandler; - external JSFunction? capturedHotReloadEndHandler; -} - -extension type _Debugger._(JSObject _) implements JSObject { - external JSPromise invokeExtension(String key, String params); - external JSArray get extensionNames; - - Future maybeInvokeFlutterDisassemble() async { - final method = 'ext.flutter.disassemble'; - if (extensionNames.toDart.contains(method.toJS)) { - await invokeExtension(method, '{}').toDart; - } - } - - Future maybeInvokeFlutterReassemble() async { - final method = 'ext.flutter.reassemble'; - if (extensionNames.toDart.contains(method.toJS)) { - await invokeExtension(method, '{}').toDart; - } - } -} - -@JS('XMLHttpRequest') -extension type _XMLHttpRequest._(JSObject _) implements JSObject { - external _XMLHttpRequest(); - external set withCredentials(bool value); - external set onreadystatechange(JSFunction fun); - external void open(String method, String url, bool async); - void get(String url, bool async) => open('GET', url, async); - external void send(); - external int get readyState; - external int get status; - external String get responseText; -} - -extension on JSArray { - external void push(JSString value); -} - -class DdcLibraryBundleRestarter implements Restarter, TwoPhaseRestarter { - JSFunction? _capturedHotReloadEndCallback; - - Future _runMainWhenReady( - Future? readyToRunMain, - JSFunction runMain, - ) async { - if (readyToRunMain != null) { - await readyToRunMain; - } - - runMain.callAsFunction(); - } - - Future> _getSrcModuleLibraries(String reloadedSourcesPath) async { - final completer = Completer(); - final xhr = _XMLHttpRequest(); - xhr.onreadystatechange = () { - // If the request has completed and is OK or unchanged, send the response - // text. Otherwise, we should report an error reading the reloaded - // sources file. - if (xhr.readyState == 4) { - if (xhr.status == 200 || xhr.status == 304) { - completer.complete(xhr.responseText); - } else { - completer.completeError( - 'Failed to fetch reloaded sources at $reloadedSourcesPath.', - ); - } - } - }.toJS; - xhr.get(reloadedSourcesPath, true); - xhr.send(); - final responseText = await completer.future; - - return (json.decode(responseText) as List).cast(); - } - - @override - Future<(bool, JSArray)> restart({ - String? runId, - Future? readyToRunMain, - String? reloadedSourcesPath, - }) async { - assert( - reloadedSourcesPath != null, - "Expected 'reloadedSourcesPath' to not be null in a hot restart.", - ); - await _dartDevEmbedder.debugger.maybeInvokeFlutterDisassemble(); - final mainHandler = (JSFunction runMain) { - _dartDevEmbedder.config.capturedMainHandler = null; - safeUnawaited(_runMainWhenReady(readyToRunMain, runMain)); - }.toJS; - _dartDevEmbedder.config.capturedMainHandler = mainHandler; - final srcModuleLibraries = await _getSrcModuleLibraries( - reloadedSourcesPath!, - ); - await _dartDevEmbedder.hotRestart().toDart; - return (true, srcModuleLibraries.jsify() as JSArray); - } - - @override - Future> hotRestartBegin(String reloadedSourcesPath) async { - await _dartDevEmbedder.debugger.maybeInvokeFlutterDisassemble(); - final srcModuleLibraries = await _getSrcModuleLibraries( - reloadedSourcesPath, - ); - final jsFilesToRequest = srcModuleLibraries.jsify() as JSArray; - final requestedJsFiles = await _dartDevEmbedder - .hotRestartBegin(jsFilesToRequest) - .toDart; - return requestedJsFiles; - } - - @override - void hotRestartEnd() => _dartDevEmbedder.hotRestartEnd(); - - @override - Future> hotReloadStart(String reloadedSourcesPath) async { - final filesToLoad = JSArray(); - final librariesToReload = JSArray(); - final srcModuleLibraries = await _getSrcModuleLibraries( - reloadedSourcesPath, - ); - for (final srcModuleLibrary in srcModuleLibraries) { - final srcModuleLibraryCast = srcModuleLibrary.cast(); - final src = srcModuleLibraryCast['src'] as String; - final libraries = (srcModuleLibraryCast['libraries'] as List) - .cast(); - filesToLoad.push(src.toJS); - for (final library in libraries) { - librariesToReload.push(library.toJS); - } - } - _dartDevEmbedder.config.capturedHotReloadEndHandler = - (JSFunction hotReloadEndCallback) { - _capturedHotReloadEndCallback = hotReloadEndCallback; - }.toJS; - await _dartDevEmbedder.hotReload(filesToLoad, librariesToReload).toDart; - return srcModuleLibraries.jsify() as JSArray; - } - - @override - Future hotReloadEnd() async { - // Requires a previous call to `hotReloadStart`. - _capturedHotReloadEndCallback!.callAsFunction(); - _dartDevEmbedder.config.capturedHotReloadEndHandler = null; - _capturedHotReloadEndCallback = null; - } - - /// Handles service extension requests using the dart dev embedder - Future?> handleServiceExtension( - String method, - Map args, - ) async { - if (method == 'ext.flutter.reassemble') { - await _dartDevEmbedder.debugger.maybeInvokeFlutterReassemble(); - return {'status': 'reassemble invoked'}; - } else if (method == 'getExtensionRpcs') { - final rpcs = _dartDevEmbedder.debugger.extensionNames.toDart - .cast(); - return {'rpcs': rpcs}; - } else { - // For other extension methods, delegate to the debugger - final params = args.isNotEmpty ? jsonEncode(args) : '{}'; - final resultJson = await _dartDevEmbedder.debugger - .invokeExtension(method, params) - .toDart; - return jsonDecode(resultJson.toDart) as Map; - } - } -} diff --git a/dwds/web/reloader/ddc_restarter.dart b/dwds/web/reloader/ddc_restarter.dart deleted file mode 100644 index 696f4e4f81..0000000000 --- a/dwds/web/reloader/ddc_restarter.dart +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:async'; -import 'dart:js_interop'; - -import 'package:web/web.dart'; - -import 'restarter.dart'; - -@JS(r'dart_library') -external DartLibrary dartLibrary; - -extension type DartLibrary._(JSObject _) implements JSObject { - external void reload(ReloadConfiguration configuration); -} - -@anonymous -@JS() -@staticInterop -class ReloadConfiguration { - external factory ReloadConfiguration({ - String? runId, - JSPromise? readyToRunMain, - }); -} - -class DdcRestarter implements Restarter { - @override - Future<(bool, JSArray?)> restart({ - String? runId, - Future? readyToRunMain, - String? reloadedSourcesPath, - }) async { - assert( - reloadedSourcesPath == null, - "'reloadedSourcesPath' should not be used for the DDC module format.", - ); - dartLibrary.reload( - ReloadConfiguration(runId: runId, readyToRunMain: readyToRunMain?.toJS), - ); - final reloadCompleter = Completer(); - final sub = window.onMessage.listen((event) { - final message = event.data?.dartify(); - if (message is Map && - message['type'] == 'DDC_STATE_CHANGE' && - message['state'] == 'restart_end') { - reloadCompleter.complete(true); - } - }); - return ( - await reloadCompleter.future.then((value) { - sub.cancel(); - return value; - }), - null, - ); - } - - @override - Future hotReloadEnd() => throw UnimplementedError( - 'Hot reload is not supported for the DDC module format.', - ); - - @override - Future> hotReloadStart(String reloadedSourcesPath) => - throw UnimplementedError( - 'Hot reload is not supported for the DDC module format.', - ); -} diff --git a/dwds/web/reloader/manager.dart b/dwds/web/reloader/manager.dart deleted file mode 100644 index f1f7ac1544..0000000000 --- a/dwds/web/reloader/manager.dart +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:convert'; -import 'dart:js_interop'; - -import 'package:dwds/data/isolate_events.dart'; -import 'package:dwds/src/sockets.dart'; -import 'package:web/web.dart'; - -import 'ddc_library_bundle_restarter.dart'; -import 'restarter.dart'; - -class ReloadingManager { - final SocketClient _client; - final Restarter _restarter; - - ReloadingManager(this._client, this._restarter); - - /// Attempts to perform a hot restart. - /// - /// [runId] is used to hot restart code in the browser for all apps that - /// - are loaded on the same page - /// - called hotRestart with the same runId - /// - /// The apps are restarted at the same time on the first call. - /// - /// [reloadedSourcesPath] is the path to a JSONified list of maps that - /// represents the sources that were reloaded in this restart and follows the - /// following format: - /// - /// ```json - /// [ - /// { - /// "src": "/", - /// "module": "", - /// "libraries": ["", ""], - /// }, - /// ] - /// ``` - /// - /// `src`: A string that corresponds to the file path containing a DDC library - /// bundle. - /// `module`: The name of the library bundle in `src`. - /// `libraries`: An array of strings containing the libraries that were - /// compiled in `src`. - /// - /// Returns either the JS version of the list of maps from - /// [reloadedSourcesPath] if [reloadedSourcesPath] is non-null and null - /// otherwise. - Future?> hotRestart({ - String? runId, - Future? readyToRunMain, - String? reloadedSourcesPath, - }) async { - _beforeRestart(); - final result = await _restarter.restart( - runId: runId, - readyToRunMain: readyToRunMain, - reloadedSourcesPath: reloadedSourcesPath, - ); - _afterRestart(result.$1); - return result.$2; - } - - bool get supportsTwoPhaseHotRestart => _restarter is TwoPhaseRestarter; - - Future> hotRestartBegin(String reloadedSourcesPath) async { - final requestedSources = await (_restarter as TwoPhaseRestarter) - .hotRestartBegin(reloadedSourcesPath); - // Notify package:dwds that the isolate is exiting and a new isolate will - // be created. - _beforeRestart(); - _afterRestart(true); - return requestedSources; - } - - void hotRestartEnd() { - (_restarter as TwoPhaseRestarter).hotRestartEnd(); - } - - /// After a previous call to [hotReloadStart], completes the hot - /// reload by pushing the libraries into the Dart runtime. - Future hotReloadEnd() async { - await _restarter.hotReloadEnd(); - } - - /// Using [reloadedSourcesPath] as the path to a JSONified list of maps which - /// follows the following format: - /// - /// ```json - /// [ - /// { - /// "src": "/", - /// "module": "", - /// "libraries": ["", ""], - /// }, - /// ] - /// ``` - /// - /// computes the sources and libraries to reload, loads them into the page, - /// and returns a JS version of the list of maps. - /// - /// `src`: A string that corresponds to the file path containing a DDC library - /// bundle. - /// `module`: The name of the library bundle in `src`. - /// `libraries`: An array of strings containing the libraries that were - /// compiled in `src`. - Future> hotReloadStart(String reloadedSourcesPath) => - _restarter.hotReloadStart(reloadedSourcesPath); - - /// Does a hard reload of the application. - void reloadPage() { - window.location.reload(); - } - - /// Handles service extension requests by delegating to the appropriate - /// restarter - Future?> handleServiceExtension( - String method, - Map args, - ) async { - final restarter = _restarter; - if (restarter is DdcLibraryBundleRestarter) { - return await restarter.handleServiceExtension(method, args); - } - // For other restarter types, return null to indicate not supported - return null; - } - - void _afterRestart(bool succeeded) { - if (!succeeded) return; - // Notify package:dwds that the isolate has been created. - // package:dwds will respond with a [RunRequest]. - _client.sink.add(jsonEncode(['IsolateStart', IsolateStart().toJson()])); - } - - void _beforeRestart() { - // Notify package:dwds that the isolate is about to exit. - _client.sink.add(jsonEncode(['IsolateExit', IsolateExit().toJson()])); - } -} diff --git a/dwds/web/reloader/require_restarter.dart b/dwds/web/reloader/require_restarter.dart deleted file mode 100644 index 61ba853035..0000000000 --- a/dwds/web/reloader/require_restarter.dart +++ /dev/null @@ -1,321 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:async'; -import 'dart:collection'; -import 'dart:convert'; -import 'dart:js_interop'; - -import 'package:dwds/src/utilities/shared.dart'; -import 'package:graphs/graphs.dart' as graphs; -import 'package:http/browser_client.dart'; -import 'package:web/web.dart'; - -import '../run_main.dart'; -import '../web_utils.dart'; -import 'restarter.dart'; - -@JS(r'$dartRunMain') -external set dartRunMain(JSFunction func); - -@JS(r'$dartRunMain') -external JSFunction get dartRunMain; - -@JS(r'$requireLoader') -external RequireLoader get requireLoader; - -@anonymous -@JS() -@staticInterop -class RequireLoader {} - -extension RequireLoaderExtension on RequireLoader { - external String get digestsPath; - - external JsMap get moduleParentsGraph; - - external void forceLoadModule( - JSString moduleId, - JSFunction callback, - JSFunction onError, - ); -} - -@anonymous -@JS() -@staticInterop -class Sdk {} - -@anonymous -@JS() -@staticInterop -class SdkDeveloper {} - -@anonymous -@JS() -@staticInterop -class SdkDart {} - -@anonymous -@JS() -@staticInterop -class SdkExt {} - -@anonymous -@JS() -@staticInterop -class MainLibrary {} - -@JS(r'$loadModuleConfig') -external Sdk require(String value); - -Sdk get sdk => require('dart_sdk'); - -extension SdkExtension on Sdk { - external SdkDart get dart; - external SdkDeveloper get developer; -} - -extension SdkDeveloperExtension on SdkDeveloper { - external JSPromise invokeExtension(String key, String params); - external SdkExt get _extensions; - - Future maybeInvokeFlutterDisassemble() async { - final method = 'ext.flutter.disassemble'; - if (_extensions.containsKey(method)) { - await invokeExtension(method, '{}').toDart; - } - } -} - -extension SdkDartExtension on SdkDart { - external void hotRestart(); - external JSObject getModuleLibraries(String? moduleId); - - MainLibrary getMainLibrary(String? moduleId) { - final libraries = getModuleLibraries(moduleId).values; - return libraries.first! as MainLibrary; - } -} - -extension SdkExtExtension on SdkExt { - external bool containsKey(String key); -} - -extension MainLibraryExtension on MainLibrary { - external void main(); -} - -class HotReloadFailedException implements Exception { - final String _s; - - HotReloadFailedException(this._s); - @override - String toString() => "HotReloadFailedException: '$_s'"; -} - -/// Handles hot restart reloading for use with the require module system. -class RequireRestarter implements Restarter { - /// The last known digests of all the modules in the application. - /// - /// This is updated in place during calls to hotRestart. - static late Map _lastKnownDigests; - - final _moduleOrdering = HashMap(); - late SplayTreeSet _dirtyModules; - var _running = Completer()..complete(true); - - int count = 0; - - RequireRestarter._() { - _dirtyModules = SplayTreeSet(_moduleTopologicalCompare); - } - - @override - Future<(bool, JSArray?)> restart({ - String? runId, - Future? readyToRunMain, - String? reloadedSourcesPath, - }) async { - assert( - reloadedSourcesPath == null, - "'reloadedSourcesPath' should not be used for the AMD module format.", - ); - await sdk.developer.maybeInvokeFlutterDisassemble(); - - final newDigests = await _getDigests(); - final modulesToLoad = []; - for (final moduleId in newDigests.keys) { - if (!_lastKnownDigests.containsKey(moduleId)) { - print( - 'Error during script reloading, refreshing the page. \n' - 'Unable to find an existing digest for module: $moduleId.', - ); - _reloadPage(); - } else if (_lastKnownDigests[moduleId] != newDigests[moduleId]) { - _lastKnownDigests[moduleId] = newDigests[moduleId]!; - modulesToLoad.add(moduleId); - } - } - - var result = true; - if (modulesToLoad.isNotEmpty) { - _updateGraph(); - result = await _reload(modulesToLoad); - } - sdk.dart.hotRestart(); - safeUnawaited(_runMainWhenReady(readyToRunMain)); - return (result, null); - } - - @override - Future hotReloadEnd() => throw UnimplementedError( - 'Hot reload is not supported for the AMD module format.', - ); - - @override - Future> hotReloadStart(String reloadedSourcesPath) => - throw UnimplementedError( - 'Hot reload is not supported for the AMD module format.', - ); - - Future _runMainWhenReady(Future? readyToRunMain) async { - if (readyToRunMain != null) { - await readyToRunMain; - } - runMain(); - } - - Iterable _allModules() => requireLoader.moduleParentsGraph.modules; - - Future> _getDigests() async { - final client = BrowserClient(); - final response = await client.get(Uri.parse(requireLoader.digestsPath)); - return (jsonDecode(response.body) as Map).cast(); - } - - Future _initialize() async { - _lastKnownDigests = await _getDigests(); - } - - List _moduleParents(String module) => - requireLoader.moduleParentsGraph.parents(module); - - int _moduleTopologicalCompare(String module1, String module2) { - var topological = 0; - - final order1 = _moduleOrdering[module1]; - final order2 = _moduleOrdering[module2]; - - if (order1 == null || order2 == null) { - final missing = order1 == null ? module1 : module2; - throw HotReloadFailedException( - 'Unable to fetch ordering info for module: $missing', - ); - } - - topological = Comparable.compare( - _moduleOrdering[module2]!, - _moduleOrdering[module1]!, - ); - - if (topological == 0) { - // If modules are in cycle (same strongly connected component) compare - // their string id, to ensure total ordering for SplayTreeSet uniqueness. - topological = module1.compareTo(module2); - } - - return topological; - } - - /// Returns `true` if the reload was fully handled, `false` if it failed - /// explicitly, or `null` for an unhandled reload. - Future _reload(List modules) async { - final dart = sdk.dart; - - // As function is async, it can potentially be called second time while - // first invocation is still running. In this case just mark as dirty and - // wait until loop from the first call will do the work - if (!_running.isCompleted) return await _running.future; - _running = Completer(); - - var reloadedModules = 0; - try { - _dirtyModules.addAll(modules); - String? previousModuleId; - while (_dirtyModules.isNotEmpty) { - final moduleId = _dirtyModules.first; - _dirtyModules.remove(moduleId); - final parentIds = _moduleParents(moduleId); - // Check if this is the root / bootstrap module. - if (parentIds.isEmpty) { - // The bootstrap module is not reloaded but we need to update the - // $dartRunMain reference to the newly loaded child module. - // ignore: unnecessary_lambdas - dartRunMain = () { - dart.getMainLibrary(previousModuleId).main(); - }.toJS; - } else { - ++reloadedModules; - await _reloadModule(moduleId); - parentIds.sort(_moduleTopologicalCompare); - _dirtyModules.addAll(parentIds); - previousModuleId = moduleId; - } - } - print('$reloadedModules module(s) were hot-reloaded.'); - _running.complete(true); - } on HotReloadFailedException catch (e) { - print('Error during script reloading. Firing full page reload. $e'); - _reloadPage(); - _running.complete(false); - } - return _running.future; - } - - Future _reloadModule(String moduleId) { - final completer = Completer(); - final stackTrace = StackTrace.current; - requireLoader.forceLoadModule( - moduleId.toJS, - // Removing the argument type in complete() - // ignore: unnecessary_lambdas - () { - completer.complete(); - }.toJS, - (JsError e) { - completer.completeError( - HotReloadFailedException(e.message), - stackTrace, - ); - }.toJS, - ); - return completer.future; - } - - void _reloadPage() { - window.location.reload(); - } - - void _updateGraph() { - final allModules = _allModules(); - - final stronglyConnectedComponents = graphs.stronglyConnectedComponents( - allModules, - _moduleParents, - ); - _moduleOrdering.clear(); - for (var i = 0; i < stronglyConnectedComponents.length; i++) { - for (final module in stronglyConnectedComponents[i]) { - _moduleOrdering[module] = i; - } - } - } - - static Future create() async { - final reloader = RequireRestarter._(); - await reloader._initialize(); - return reloader; - } -} diff --git a/dwds/web/reloader/restarter.dart b/dwds/web/reloader/restarter.dart deleted file mode 100644 index 1810cca2db..0000000000 --- a/dwds/web/reloader/restarter.dart +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:js_interop'; - -/// A Restarter that supports a hot restart over two phases. -/// -/// The APIs here should be used in place of [Restarter.restart]. -/// -/// This is a temporary interface that is only useful while there are -/// `Restarter`s that don't use the two phase restart. -// TODO(nshahan): Move these members into `Restarter` when all have been -// migrated to the two phase restart. -abstract class TwoPhaseRestarter implements Restarter { - /// Starts a hot restart operation. - /// - /// Passes the [reloadedSourcesPath] through to the `DartDevEmbedder` and - /// bubbles up the returned array of scripts that were actually requested. - Future> hotRestartBegin(String reloadedSourcesPath); - - /// Finishes the hot restart operation that must have been previously started - /// by [hotRestartBegin]. - void hotRestartEnd(); -} - -abstract class Restarter { - /// Attempts to perform a hot restart. - /// - /// [reloadedSourcesPath] is the path to a JSONified list of maps that - /// represents the sources that were reloaded in this restart and follows the - /// following format: - /// - /// ```json - /// [ - /// { - /// "src": "/", - /// "module": "", - /// "libraries": ["", ""], - /// }, - /// ] - /// ``` - /// - /// `src`: A string that corresponds to the file path containing a DDC library - /// bundle. - /// `module`: The name of the library bundle in `src`. - /// `libraries`: An array of strings containing the libraries that were - /// compiled in `src`. - /// - /// Returns a record containing whether the hot restart succeeded and either - /// the JS version of the list of maps from [reloadedSourcesPath] if - /// [reloadedSourcesPath] is non-null and null otherwise. - // TODO(nshahan): Remove after migrating to hotRestartBegin/hotRestartEnd. - // https://github.com/dart-lang/webdev/issues/2826 - Future<(bool, JSArray?)> restart({ - String? runId, - Future? readyToRunMain, - String? reloadedSourcesPath, - }); - - /// After a previous call to [hotReloadStart], completes the hot - /// reload by pushing the libraries into the Dart runtime. - Future hotReloadEnd(); - - /// Using [reloadedSourcesPath] as the path to a JSONified list of maps which - /// follows the following format: - /// - /// ```json - /// [ - /// { - /// "src": "/", - /// "module": "", - /// "libraries": ["", ""], - /// }, - /// ] - /// ``` - /// - /// computes the sources and libraries to reload, loads them into the page, - /// and returns a JS version of the list of maps. - /// - /// `src`: A string that corresponds to the file path containing a DDC library - /// bundle. - /// `module`: The name of the library bundle in `src`. - /// `libraries`: An array of strings containing the libraries that were - /// compiled in `src`. - Future> hotReloadStart(String reloadedSourcesPath); -} diff --git a/dwds/web/run_main.dart b/dwds/web/run_main.dart deleted file mode 100644 index 9ead9dd963..0000000000 --- a/dwds/web/run_main.dart +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:js_interop'; - -import 'package:web/web.dart'; - -// According to the CSP3 spec a nonce must be a valid base64 string. -final _noncePattern = RegExp('^[\\w+/_-]+[=]{0,2}\$'); - -/// Returns CSP nonce, if set for any script tag. -String? _findNonce() { - final elements = window.document.querySelectorAll('script'); - - for (var i = 0; i < elements.length; i++) { - final element = elements.item(i); - final nonceValue = (element as HTMLElement).nonce; - if (_noncePattern.hasMatch(nonceValue)) { - return nonceValue; - } - } - return null; -} - -/// Creates a script that will run properly when strict CSP is enforced. -/// -/// More specifically, the script has the correct `nonce` value set. -final HTMLElement Function() _createScript = (() { - final nonce = _findNonce(); - - if (nonce == null) { - return () => document.createElement('script') as HTMLElement; - } - return () { - final scriptElement = document.createElement('script') as HTMLElement; - return scriptElement..setAttribute('nonce', nonce); - }; -})(); - -/// Runs `window.$dartRunMain()` by injecting a script tag. -/// -/// We do this so that we don't see user exceptions bubble up in our own error -/// handling zone. -void runMain() { - final scriptElement = _createScript() - ..innerHTML = r'window.$dartRunMain();'.toJS; - document.body!.append(scriptElement.jsify()!); - // External tear-offs are not allowed. - // ignore: unnecessary_lambdas - Future.microtask(() => scriptElement.remove()); -} diff --git a/dwds/web/web_utils.dart b/dwds/web/web_utils.dart deleted file mode 100644 index c82c6ed54e..0000000000 --- a/dwds/web/web_utils.dart +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:js_interop'; - -@JS('window') -external WindowContext get windowContext; - -@JS('Error') -@staticInterop -abstract class WindowContext {} - -extension WindowContextExtension on WindowContext { - external bool? get $isInternalBuild; - external bool? get $isFlutterApp; - external String? get $dartAppId; - external String? get $dartExtensionUri; -} - -@JS('Array.from') -external JSArray _jsArrayFrom(JSAny any); - -@JS('Object.values') -external JSArray _jsObjectValues(JSAny any); - -@JS('Error') -@staticInterop -abstract class JsError {} - -extension JsErrorExtension on JsError { - external String get message; - external String get stack; -} - -@JS('Map') -@staticInterop -abstract class JsMap {} - -extension JsMapExtension on JsMap { - external V? get(K key); - external JSObject keys(); -} - -extension JSObjectExtension on JSObject { - Iterable get values => _jsObjectValues(this).toDartIterable(); -} - -extension JSArrayExtension on JSArray { - Iterable toDartIterable() => toDart.map((e) => e.dartify() as T); - - List toDartList() => toDartIterable().toList(); -} - -extension ModuleDependencyGraph on JsMap { - Iterable get modules => _jsArrayFrom(keys()).toDartIterable(); - - List parents(String key) => get(key.toJS)?.toDartList() ?? []; -} diff --git a/dwds_test_common/.dartignore b/dwds_test_common/.dartignore deleted file mode 100644 index fdaa1daf9e..0000000000 --- a/dwds_test_common/.dartignore +++ /dev/null @@ -1,2 +0,0 @@ -# Exclude test fixture packages from Dart tooling -fixtures/ \ No newline at end of file diff --git a/dwds_test_common/LICENSE b/dwds_test_common/LICENSE deleted file mode 100644 index 9035a416a3..0000000000 --- a/dwds_test_common/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright 2026, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/dwds_test_common/OWNERS b/dwds_test_common/OWNERS deleted file mode 100644 index 77bdf63de2..0000000000 --- a/dwds_test_common/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -set noparent -# Dart Development Infrastructure Team -file:/tools/OWNERS_DEV_INFRA \ No newline at end of file diff --git a/dwds_test_common/dart_test.yaml b/dwds_test_common/dart_test.yaml deleted file mode 100644 index 50f61156e5..0000000000 --- a/dwds_test_common/dart_test.yaml +++ /dev/null @@ -1,7 +0,0 @@ -concurrency: 1 -retry: 3 - -tags: - # The release tests are only run from the release_reminder.yml workflow. - # This allows them to be skipped with the `prepare-release` label. - release: diff --git a/dwds_test_common/fixtures/_experiment/pubspec.yaml b/dwds_test_common/fixtures/_experiment/pubspec.yaml deleted file mode 100644 index b1064110b2..0000000000 --- a/dwds_test_common/fixtures/_experiment/pubspec.yaml +++ /dev/null @@ -1,16 +0,0 @@ -name: _experiment -version: 1.0.0 -description: >- - A fake package used for testing experimental language features. -publish_to: none -environment: - sdk: ^3.10.0-0.0.dev - -dependencies: - intl: ^0.17.0 - path: ^1.8.2 - -dev_dependencies: - build_daemon: ^4.1.4 - build_runner: ^2.16.0 - build_web_compilers: ^4.4.12 diff --git a/dwds_test_common/fixtures/_experiment/web/index.html b/dwds_test_common/fixtures/_experiment/web/index.html deleted file mode 100644 index d93440a948..0000000000 --- a/dwds_test_common/fixtures/_experiment/web/index.html +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/dwds_test_common/fixtures/_experiment/web/main.dart b/dwds_test_common/fixtures/_experiment/web/main.dart deleted file mode 100644 index 773fd1a74b..0000000000 --- a/dwds_test_common/fixtures/_experiment/web/main.dart +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -// @dart = 3.9 - -import 'dart:async'; -import 'dart:core'; -import 'dart:js_interop'; - -@JS('document.body.append') -external void append(String text); - -void main() { - // for evaluation - Timer.periodic(const Duration(seconds: 1), (_) { - printSimpleLocalRecord(); - printComplexLocalRecord(); - printNestedLocalRecord(); - printSimpleNamedLocalRecord(); - printComplexNamedLocalRecord(); - printNestedNamedLocalRecord(); - print('Patterns'); // Breakpoint: callTestPattern1 - testPattern(['a', 1]); - testPattern([3.14, 'b']); - testPattern([0, 1]); - testPattern2(); - print('Classes'); - testClass(); - }); - - append('Program is running!'); -} - -void printSimpleLocalRecord() { - final record = (true, 3); - print(record); // Breakpoint: printSimpleLocalRecord -} - -void printSimpleNamedLocalRecord() { - final record = (true, cat: 'Vasya'); - print(record); // Breakpoint: printSimpleNamedLocalRecord -} - -void printComplexLocalRecord() { - final record = (true, 3, {'a': 1, 'b': 5}); - print(record); // Breakpoint: printComplexLocalRecord -} - -void printComplexNamedLocalRecord() { - final record = (true, 3, array: {'a': 1, 'b': 5}); - print(record); // Breakpoint: printComplexNamedLocalRecord -} - -void printNestedLocalRecord() { - final record = (true, (false, 5)); - print(record); // Breakpoint: printNestedLocalRecord -} - -void printNestedNamedLocalRecord() { - final record = (true, inner: (false, 5)); - print(record); // Breakpoint: printNestedNamedLocalRecord -} - -void testClass() { - final greeter = GreeterClass(greeteeName: 'Charlie Brown'); - greeter.sayHello(); -} - -String testPattern(Object obj) { - switch (obj) { - case [final a, final int n] || [final int n, final a] - when n == 1 && a is String: - return a.toString(); // Breakpoint: testPatternCase1 - case [final double n, final a] || [final a, final double n] - when (n - 3.14).abs() < 0.001: - return a.toString(); // Breakpoint: testPatternCase2 - default: - return 'default'; // Breakpoint: testPatternDefault - } -} - -String testPattern2() { - final dog = 'Prismo'; - final cats = ['Garfield', 'Tom']; // Breakpoint: testPattern2Case1 - final [firstCat, secondCat] = cats; - print(firstCat); // Breakpoint: testPattern2Case2 - return '$dog, $firstCat, $secondCat'; -} - -class GreeterClass { - final String greeteeName; - final bool useFrench; - - GreeterClass({this.greeteeName = 'Snoopy', this.useFrench = false}); - - void sayHello() { - useFrench ? greetInFrench() : greetInEnglish(); - } - - void greetInEnglish() { - print('Hello $greeteeName'); // Breakpoint: testClass1Case1 - } - - void greetInFrench() { - print('Bonjour $greeteeName'); - } -} diff --git a/dwds_test_common/fixtures/_test/example/append_body/index.html b/dwds_test_common/fixtures/_test/example/append_body/index.html deleted file mode 100644 index d93440a948..0000000000 --- a/dwds_test_common/fixtures/_test/example/append_body/index.html +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/dwds_test_common/fixtures/_test/example/append_body/main.dart b/dwds_test_common/fixtures/_test/example/append_body/main.dart deleted file mode 100644 index 8a89205d18..0000000000 --- a/dwds_test_common/fixtures/_test/example/append_body/main.dart +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:async'; -import 'dart:developer'; -import 'dart:js_interop'; - -@JS('console.log') -external void log(String _); - -// We use this to test whether a hot restart or a full reload occurred. In the -// former, we should see the old log, but in the latter, we should not. -@JS('\$previousLog') -external String? previousLog; - -void main() { - var count = 0; - // For setting breakpoints. - Timer.periodic(const Duration(seconds: 1), (_) { - print('Count is: ${++count}'); // Breakpoint: printCount - }); - - var logMessage = 'Hello World!'; - // Note that we concatenate instead of logging each one separately to avoid - // possibly mixing up logs with a previous call to `main`. - if (previousLog != null) logMessage = '$previousLog $logMessage'; - log(logMessage); - previousLog = logMessage; - - registerExtension('ext.flutter.disassemble', (_, __) async { - log('start disassemble'); - await Future.delayed(const Duration(seconds: 1)); - log('end disassemble'); - return ServiceExtensionResponse.result('{}'); - }); -} diff --git a/dwds_test_common/fixtures/_test/example/hello_world/index.html b/dwds_test_common/fixtures/_test/example/hello_world/index.html deleted file mode 100644 index 9bd15c874a..0000000000 --- a/dwds_test_common/fixtures/_test/example/hello_world/index.html +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/dwds_test_common/fixtures/_test/example/hello_world/main.dart b/dwds_test_common/fixtures/_test/example/hello_world/main.dart deleted file mode 100644 index b4918d09ba..0000000000 --- a/dwds_test_common/fixtures/_test/example/hello_world/main.dart +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:async'; -import 'dart:collection'; -import 'dart:convert'; -import 'dart:developer'; -// TODO: https://github.com/dart-lang/webdev/issues/2508 -// ignore: deprecated_member_use -import 'dart:html'; -// TODO: https://github.com/dart-lang/webdev/issues/2508 -// ignore: deprecated_member_use -import 'dart:js'; - -import 'package:intl/intl.dart'; -import 'package:path/path.dart' as p; - -part 'part.dart'; - -// Create a series of top level objects for tests in -// dwds/test/chrome_proxy_service_test.dart - -final topLevelList = () { - final l = List.filled(1001, 5); - l[4] = 100; - return l; -}(); - -final topLevelMap = LinkedHashMap.from( - Iterable.generate(1001).toList().reversed.toList().asMap(), -); - -final myInstance = MyTestClass(); - -void main() async { - print(DateFormat()); - // Long running so that we can test the pause / resume behavior. - Timer.periodic(const Duration(seconds: 1), (_) {}); - - print(p.join('Hello', 'World')); // Breakpoint: printHelloWorld - - // long running to test evaluateInFrame - Timer.periodic(const Duration(seconds: 1), (_) { - final local = 42; - print(local); // Breakpoint: printLocal - }); - - context['inspectInstance'] = () { - inspect(myInstance); - }; - - context['postEvent'] = (String kind) { - postEvent(kind, {'example': 'data'}); - }; - - context['registerExtension'] = (String method) { - registerExtension(method, ( - String method, - Map parameters, - ) async { - return ServiceExtensionResponse.result(jsonEncode(parameters)); - }); - }; - - context['registerExtensionWithError'] = (String method) { - registerExtension(method, ( - String method, - Map parameters, - ) async { - return ServiceExtensionResponse.error( - int.parse(parameters['code']!), - parameters['details']!, - ); - }); - }; - - context['sendLog'] = (String message) { - log(message, name: 'testLogCategory'); - }; - - context['throwUncaughtException'] = () { - scheduleMicrotask(() => throw Exception('UncaughtException')); - }; - - Timer.periodic(const Duration(seconds: 1), (timer) { - printCount(); // Breakpoint: callPrintCount - }); - - Timer.periodic(const Duration(seconds: 1), (_) { - asyncCall(); - }); - - Timer.periodic(const Duration(seconds: 1), (_) { - throwsException(); - }); - - // Register one up front before the proxy connects, the isolate should still - // recognize this as an available extension. - registerExtension( - 'ext.hello_world.existing', - (_, __) => Future.value(ServiceExtensionResponse.error(0, '')), - ); - - window.console.debug('Page Ready'); -} - -var count = 0; - -// An easy location to add a breakpoint. -void printCount() { - print('The count is ${++count}'); // Breakpoint: inPrintCount - doSomething(); -} - -void asyncCall() async { - final now = DateTime.now(); - - await Future.delayed(Duration.zero); - - final then = DateTime.now(); // Breakpoint: asyncCall - // ignore: unused_local_variable - final diff = then.difference(now); -} - -void throwsException() { - try { - throw Exception('new exception'); - } catch (e) { - // ignore - } -} - -String helloString(String response) => response; - -bool helloBool(bool response) => response; - -num? helloNum(num? response) => response; - -MyTestClass createObject(String message) => MyTestClass(message: message); - -String messageFor(MyTestClass instance) => instance.message; - -String messagesCombined(MyTestClass a, MyTestClass b) => a.message + b.message; - -class MyTestClass { - final String message; - - String? notFinal; - - static final String staticMessage = 'static'; - - static String staticHello() => 'static hello'; - - MyTestClass({this.message = 'world'}); - - String hello() => message; -} diff --git a/dwds_test_common/fixtures/_test/example/hello_world/part.dart b/dwds_test_common/fixtures/_test/example/hello_world/part.dart deleted file mode 100644 index 8d779753ee..0000000000 --- a/dwds_test_common/fixtures/_test/example/hello_world/part.dart +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of 'main.dart'; - -var blah = 'blah'; - -void doSomething() { - print(blah); -} diff --git a/dwds_test_common/fixtures/_test/example/scopes/main.dart b/dwds_test_common/fixtures/_test/example/scopes/main.dart deleted file mode 100644 index 4b21bd5928..0000000000 --- a/dwds_test_common/fixtures/_test/example/scopes/main.dart +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -/// An example with more complicated scope. -library; - -import 'dart:async'; -import 'dart:collection'; - -final libraryPublicFinal = MyTestClass(); - -final _libraryPrivateFinal = 1; -Object? libraryNull; -var libraryPublic = ['library', 'public', 'variable']; -var notAList = NotReallyAList(); - -var _libraryPrivate = ['library', 'private', 'variable']; - -var identityMap = {}; - -var map = {}; - -final stream = Stream.value(1); - -MyTestClass getLibraryPublicFinal() => libraryPublicFinal; - -List getLibraryPublic() => libraryPublic; - -Map getMap() => map; - -Map getIdentityMap() => identityMap; - -Stream getStream() => stream; - -void staticFunction(int formal) { - print(formal); // Breakpoint: staticFunction -} - -void staticAsyncFunction(String value) async { - // ignore: unused_local_variable - final myLocal = await 'a local value'; - print(value); // Breakpoint: staticAsyncFunction -} - -void staticAsyncLoopFunction(String value) async { - Function? f; - for (var i in [1, 2, 3]) { - print(i); - final myLocal = await 'my local value'; - f ??= () { - print(value); - print(i); - return myLocal; // Breakpoint: staticAsyncLoopFunction - }; - } - f!(); -} - -void main() async { - print('Initial print from scopes app'); - final local = 'local in main'; - final intLocalInMain = 42; - final testClass = MyTestClass(); - Object? localThatsNull; - identityMap['a'] = 1; - identityMap['b'] = 2; - map['a'] = [1, 2, 3]; - map['b'] = 'something'; - notAList.add(7); - - String nestedFunction(T parameter, Object aClass) { - final another = int.tryParse('$parameter'); - return '$local: parameter, $another'; // Breakpoint: nestedFunction - } - - dynamic nestedWithClosure(String banana) { - return () => '$local + $banana'; - } - - Timer.periodic(const Duration(seconds: 1), (Timer t) { - final ticks = t.tick; - // ignore: unused_local_variable, prefer_typing_uninitialized_variables - var closureLocal; - libraryPublicFinal.printCount(); - staticFunction(1); - staticAsyncFunction('arg1'); - staticAsyncLoopFunction('arg2'); - print('ticking... $ticks (the answer is $intLocalInMain)'); - print(nestedFunction('$ticks ${testClass.message}', Timer)); - print(localThatsNull); - print(libraryNull); - final localList = libraryPublic; - print(localList); - localList.add('abc'); - final f = testClass.methodWithVariables(); - print(f('parameter')); - final num = '1234'.someExtensionMethod(); - print('$num'); - }); - - print(_libraryPrivateFinal); - print(_libraryPrivate); - print(nestedFunction(_libraryPrivate.first, Object)); - print(nestedWithClosure(_libraryPrivate.first)()); -} - -String libraryFunction(String arg) { - print('calling a library function with $arg'); - final concat = 'some constant plus $arg plus whatever'; - print(concat); - return concat; -} - -abstract class MyAbstractClass { - String abstractField = 'abstract-field-value'; -} - -class MyTestClass extends MyAbstractClass { - final String message; - - String? notFinal; - - MyTestClass({this.message = 'world'}) { - myselfField = this; - tornOff = toString; - } - - String hello() => message; - - String Function(String) methodWithVariables() { - final local = '$message + something'; - print(local); - return (String parameter) { - // Be sure to use a field from this, so it isn't entirely optimized away. - final closureLocalInsideMethod = '$message/$local/$parameter'; - print(closureLocalInsideMethod); - return closureLocalInsideMethod; // Breakpoint: nestedClosure - }; - } - - //ignore: avoid_returning_this - MyTestClass get myselfGetter => this; - - late final MyTestClass myselfField; - - var count = 0; - // This should never be updated during execution. - var unchangedCount = 42; - - // An easy location to add a breakpoint. - void printCount() { - print('The count is ${++count}'); - libraryFunction('abc'); // Breakpoint: printMethod - } - - final _privateField = 'a private field'; - - // ignore: unused_element - String privateMethod(String s) => '$s : $_privateField'; - - @override - String toString() => 'A test class with message $message'; - - bool equals(Object other) { - if (other is MyTestClass) return message == other.hello(); - return false; - } - - Function closure = someFunction; - - late final String Function() tornOff; -} - -Function? someFunction() => null; - -// ignore: unused_element -int _libraryPrivateFunction(int a, int b) => a + b; - -class NotReallyAList extends ListBase { - final List _internal; - - NotReallyAList() : _internal = []; - - @override - Object? operator [](x) => _internal[x]; - - @override - operator []=(int x, Object? y) => _internal[x] = y; - - @override - int get length => _internal.length; - - @override - set length(x) => _internal.length = x; -} - -extension NumberParsing on String { - int someExtensionMethod() { - final ret = int.parse(this); - return ret; // Breakpoint: extension - } -} diff --git a/dwds_test_common/fixtures/_test/example/scopes/scopes.html b/dwds_test_common/fixtures/_test/example/scopes/scopes.html deleted file mode 100644 index d93440a948..0000000000 --- a/dwds_test_common/fixtures/_test/example/scopes/scopes.html +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/dwds_test_common/fixtures/_test/lib/deferred_library.dart b/dwds_test_common/fixtures/_test/lib/deferred_library.dart deleted file mode 100644 index 71d1c1de8e..0000000000 --- a/dwds_test_common/fixtures/_test/lib/deferred_library.dart +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -/// A library that we can import. -library; - -void deferredPrintLocal() { - print('hello from deferred library'); // Breakpoint: DeferredPrintLocal -} diff --git a/dwds_test_common/fixtures/_test/lib/library.dart b/dwds_test_common/fixtures/_test/lib/library.dart deleted file mode 100644 index c00cf8ae09..0000000000 --- a/dwds_test_common/fixtures/_test/lib/library.dart +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -/// A library that we can import. -library; - -int aVariable = 3; - -String concatenate(String a, String b) { - return '$a$b'; // Breakpoint: Concatenate -} diff --git a/dwds_test_common/fixtures/_test/pubspec.yaml b/dwds_test_common/fixtures/_test/pubspec.yaml deleted file mode 100644 index 3e86a35057..0000000000 --- a/dwds_test_common/fixtures/_test/pubspec.yaml +++ /dev/null @@ -1,17 +0,0 @@ -name: _test -version: 1.0.0 -description: >- - A fake package used for testing. -publish_to: none -environment: - sdk: ^3.10.0-0.0.dev - -dependencies: - intl: ^0.17.0 - path: ^1.8.2 - -dev_dependencies: - build_daemon: ^4.1.4 - build_runner: ^2.16.0 - build_web_compilers: ^4.8.1 - diff --git a/dwds_test_common/fixtures/_test_circular1/lib/library1.dart b/dwds_test_common/fixtures/_test_circular1/lib/library1.dart deleted file mode 100644 index 50449958bf..0000000000 --- a/dwds_test_common/fixtures/_test_circular1/lib/library1.dart +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -/// A library that we can import. -library; - -import 'package:_test_circular2/library2.dart'; - -String concatenate(String a, String b) { - return '$a$b'; // Breakpoint: Concatenate -} - -void printGlobal() { - print(globalValue); -} diff --git a/dwds_test_common/fixtures/_test_circular1/pubspec.yaml b/dwds_test_common/fixtures/_test_circular1/pubspec.yaml deleted file mode 100644 index b81da7fd68..0000000000 --- a/dwds_test_common/fixtures/_test_circular1/pubspec.yaml +++ /dev/null @@ -1,18 +0,0 @@ -name: _test_circular1 -version: 1.0.0 -description: >- - A fake package used for testing imports with circular dependency. -publish_to: none -environment: - sdk: ^3.10.0-0.0.dev - -dependencies: - intl: ^0.17.0 - path: ^1.6.1 - _test_circular2: - path: ../_test_circular2 - -dev_dependencies: - build_daemon: ^4.1.4 - build_runner: ^2.16.0 - build_web_compilers: ^4.4.12 diff --git a/dwds_test_common/fixtures/_test_circular2/lib/library2.dart b/dwds_test_common/fixtures/_test_circular2/lib/library2.dart deleted file mode 100644 index c62a979fb4..0000000000 --- a/dwds_test_common/fixtures/_test_circular2/lib/library2.dart +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'package:_test_circular1/library1.dart'; - -int globalValue = 0; - -void testCircularDependencies() { - print(concatenate('a', 'b')); // Breakpoint: testCircularDependencies -} diff --git a/dwds_test_common/fixtures/_test_circular2/pubspec.yaml b/dwds_test_common/fixtures/_test_circular2/pubspec.yaml deleted file mode 100644 index e814478484..0000000000 --- a/dwds_test_common/fixtures/_test_circular2/pubspec.yaml +++ /dev/null @@ -1,16 +0,0 @@ -name: _test_circular2 -version: 1.0.0 -description: >- - A fake package used for testing imports with circular dependency. -publish_to: none -environment: - sdk: ^3.10.0-0.0.dev - -dependencies: - _test_circular1: - path: ../_test_circular1 - -dev_dependencies: - build_daemon: ^4.1.4 - build_runner: ^2.16.0 - build_web_compilers: ^4.4.12 diff --git a/dwds_test_common/fixtures/_test_circular2/web/base_index.html b/dwds_test_common/fixtures/_test_circular2/web/base_index.html deleted file mode 100644 index affdbcb5ca..0000000000 --- a/dwds_test_common/fixtures/_test_circular2/web/base_index.html +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/dwds_test_common/fixtures/_test_circular2/web/index.html b/dwds_test_common/fixtures/_test_circular2/web/index.html deleted file mode 100644 index d93440a948..0000000000 --- a/dwds_test_common/fixtures/_test_circular2/web/index.html +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/dwds_test_common/fixtures/_test_circular2/web/main.dart b/dwds_test_common/fixtures/_test_circular2/web/main.dart deleted file mode 100644 index 2e5728ae4c..0000000000 --- a/dwds_test_common/fixtures/_test_circular2/web/main.dart +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:async'; -import 'dart:core'; -// TODO: https://github.com/dart-lang/webdev/issues/2508 -// ignore: deprecated_member_use -import 'dart:html'; - -import 'package:_test_circular1/library1.dart'; -import 'package:_test_circular2/library2.dart'; - -void main() { - // For setting breakpoints. - Timer.periodic(const Duration(seconds: 1), (_) { - testCircularDependencies(); - }); - - document.body!.appendText(concatenate('Program', ' is running!')); -} diff --git a/dwds_test_common/fixtures/_test_dot_shorthands/pubspec.yaml b/dwds_test_common/fixtures/_test_dot_shorthands/pubspec.yaml deleted file mode 100644 index bbc2e8bb54..0000000000 --- a/dwds_test_common/fixtures/_test_dot_shorthands/pubspec.yaml +++ /dev/null @@ -1,12 +0,0 @@ -name: _test_dot_shorthands -version: 1.0.0 -description: >- - A fake package used for testing dot shorthands. -publish_to: none -environment: - sdk: ^3.10.0 - -dev_dependencies: - build_daemon: ^4.1.4 - build_runner: ^2.16.0 - build_web_compilers: ^4.4.12 diff --git a/dwds_test_common/fixtures/_test_dot_shorthands/web/index.html b/dwds_test_common/fixtures/_test_dot_shorthands/web/index.html deleted file mode 100644 index d93440a948..0000000000 --- a/dwds_test_common/fixtures/_test_dot_shorthands/web/index.html +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/dwds_test_common/fixtures/_test_dot_shorthands/web/main.dart b/dwds_test_common/fixtures/_test_dot_shorthands/web/main.dart deleted file mode 100644 index bc5f6bb75c..0000000000 --- a/dwds_test_common/fixtures/_test_dot_shorthands/web/main.dart +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -// @dart = 3.10 - -class C { - int value; - C(this.value); // lineA - - static C two = C(2); // lineB - static C get three => C(3); // lineC - static C four() => C(4); // lineD -} - -void testDotShorthands() { - C c = C(1); - print('breakpoint'); // Breakpoint: testDotShorthands - // ignore: experiment_not_enabled - c = .two; // lineE - // ignore: experiment_not_enabled - c = .three; // lineF - // ignore: experiment_not_enabled - c = .four(); // lineG - print(c.value); // lineH -} - -void main() {} diff --git a/dwds_test_common/fixtures/_test_hot_reload/lib/library1.dart b/dwds_test_common/fixtures/_test_hot_reload/lib/library1.dart deleted file mode 100644 index 1daf3d4c3b..0000000000 --- a/dwds_test_common/fixtures/_test_hot_reload/lib/library1.dart +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -String get reloadValue => 'Hello World!'; diff --git a/dwds_test_common/fixtures/_test_hot_reload/pubspec.yaml b/dwds_test_common/fixtures/_test_hot_reload/pubspec.yaml deleted file mode 100644 index 6dc814abea..0000000000 --- a/dwds_test_common/fixtures/_test_hot_reload/pubspec.yaml +++ /dev/null @@ -1,12 +0,0 @@ -name: _test_hot_reload -version: 1.0.0 -description: >- - A fake package used for testing hot reload. -publish_to: none -environment: - sdk: ^3.10.0-0.0.dev - -dev_dependencies: - build_daemon: ^4.1.4 - build_runner: ^2.16.0 - build_web_compilers: ^4.8.1 diff --git a/dwds_test_common/fixtures/_test_hot_reload/web/index.html b/dwds_test_common/fixtures/_test_hot_reload/web/index.html deleted file mode 100644 index d93440a948..0000000000 --- a/dwds_test_common/fixtures/_test_hot_reload/web/index.html +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/dwds_test_common/fixtures/_test_hot_reload/web/main.dart b/dwds_test_common/fixtures/_test_hot_reload/web/main.dart deleted file mode 100644 index a85a43af81..0000000000 --- a/dwds_test_common/fixtures/_test_hot_reload/web/main.dart +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:core'; -import 'dart:js_interop'; - -import 'package:_test_hot_reload/library1.dart'; - -@JS('console.log') -external void log(String _); - -void evaluate() { - log('$reloadValue'); -} - -void main() { - evaluate(); -} diff --git a/dwds_test_common/fixtures/_test_hot_reload_breakpoints/pubspec.yaml b/dwds_test_common/fixtures/_test_hot_reload_breakpoints/pubspec.yaml deleted file mode 100644 index 916f64976a..0000000000 --- a/dwds_test_common/fixtures/_test_hot_reload_breakpoints/pubspec.yaml +++ /dev/null @@ -1,12 +0,0 @@ -name: _test_hot_reload_breakpoints -version: 1.0.0 -description: >- - A fake package used for testing hot reload breakpoints. -publish_to: none -environment: - sdk: ^3.10.0-0.0.dev - -dev_dependencies: - build_daemon: ^4.1.4 - build_runner: ^2.16.0 - build_web_compilers: ^4.8.1 diff --git a/dwds_test_common/fixtures/_test_hot_reload_breakpoints/web/index.html b/dwds_test_common/fixtures/_test_hot_reload_breakpoints/web/index.html deleted file mode 100644 index d93440a948..0000000000 --- a/dwds_test_common/fixtures/_test_hot_reload_breakpoints/web/index.html +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/dwds_test_common/fixtures/_test_hot_reload_breakpoints/web/main.dart b/dwds_test_common/fixtures/_test_hot_reload_breakpoints/web/main.dart deleted file mode 100644 index 2c9baa8d57..0000000000 --- a/dwds_test_common/fixtures/_test_hot_reload_breakpoints/web/main.dart +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:js_interop'; - -@JS('console.log') -external void log(String _); - -String get mainValue => 'main gen0'; - -void evaluate() { - // Use a future instead of directly calling because evaluating this method - // with a breakpoint would never complete otherwise. - Future.delayed(Duration(milliseconds: 10), printToConsole); -} - -void printToConsole() { - log('$mainValue'); // Breakpoint: callLog -} - -final closure = () { - return 'captured closure gen0'; // Breakpoint: capturedString -}; - -void main() {} diff --git a/dwds_test_common/fixtures/_test_hot_restart1/lib/library1.dart b/dwds_test_common/fixtures/_test_hot_restart1/lib/library1.dart deleted file mode 100644 index e2018bfcc6..0000000000 --- a/dwds_test_common/fixtures/_test_hot_restart1/lib/library1.dart +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -class B { - final int x; - const B(this.x); -} - -B get value1 => const B(2); diff --git a/dwds_test_common/fixtures/_test_hot_restart1/pubspec.yaml b/dwds_test_common/fixtures/_test_hot_restart1/pubspec.yaml deleted file mode 100644 index 9acf0a4555..0000000000 --- a/dwds_test_common/fixtures/_test_hot_restart1/pubspec.yaml +++ /dev/null @@ -1,16 +0,0 @@ -name: _test_hot_restart1 -version: 1.0.0 -description: >- - A fake package used for testing hot restart. -publish_to: none -environment: - sdk: ^3.10.0-0.0.dev - -dependencies: - intl: ^0.17.0 - path: ^1.6.1 - -dev_dependencies: - build_daemon: ^4.1.4 - build_runner: ^2.16.0 - build_web_compilers: ^4.4.12 diff --git a/dwds_test_common/fixtures/_test_hot_restart2/lib/library2.dart b/dwds_test_common/fixtures/_test_hot_restart2/lib/library2.dart deleted file mode 100644 index 2e3198f2ce..0000000000 --- a/dwds_test_common/fixtures/_test_hot_restart2/lib/library2.dart +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'package:_test_hot_restart1/library1.dart'; - -int variableToModifyToForceRecompile = 23; -B get value2 => const B(2); diff --git a/dwds_test_common/fixtures/_test_hot_restart2/pubspec.yaml b/dwds_test_common/fixtures/_test_hot_restart2/pubspec.yaml deleted file mode 100644 index 1027a22740..0000000000 --- a/dwds_test_common/fixtures/_test_hot_restart2/pubspec.yaml +++ /dev/null @@ -1,18 +0,0 @@ -name: _test_hot_restart2 -version: 1.0.0 -description: >- - A fake package used for testing hot restart. -publish_to: none -environment: - sdk: ^3.10.0-0.0.dev - -dependencies: - intl: ^0.17.0 - path: ^1.6.1 - _test_hot_restart1: - path: ../_test_hot_restart1 - -dev_dependencies: - build_daemon: ^4.1.4 - build_runner: ^2.16.0 - build_web_compilers: ^4.8.1 diff --git a/dwds_test_common/fixtures/_test_hot_restart2/web/base_index.html b/dwds_test_common/fixtures/_test_hot_restart2/web/base_index.html deleted file mode 100644 index affdbcb5ca..0000000000 --- a/dwds_test_common/fixtures/_test_hot_restart2/web/base_index.html +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/dwds_test_common/fixtures/_test_hot_restart2/web/index.html b/dwds_test_common/fixtures/_test_hot_restart2/web/index.html deleted file mode 100644 index d93440a948..0000000000 --- a/dwds_test_common/fixtures/_test_hot_restart2/web/index.html +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/dwds_test_common/fixtures/_test_hot_restart2/web/main.dart b/dwds_test_common/fixtures/_test_hot_restart2/web/main.dart deleted file mode 100644 index 055bc3d944..0000000000 --- a/dwds_test_common/fixtures/_test_hot_restart2/web/main.dart +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:core'; -import 'dart:js_interop'; - -import 'package:_test_hot_restart1/library1.dart'; -import 'package:_test_hot_restart2/library2.dart'; - -/// Tests for constant semantics across hot restart in DDC. -/// -/// DDC has multiple layers of constant caching. Failing to clear them can -/// result in stale constants being referenced across hot restarts. -/// -/// Cases tested include: -/// 1) Failing to clear all constant caches. -/// An old 'ConstObject' is returned, which fails to reflect the edited -/// 'variableToModifyToForceRecompile'. -/// 2) Clearing constant caches but failing to clear constant containers. -/// Constants in reloaded modules fail to compare with constants in stale -/// constant containers, causing 'ConstantEqualityFailure's. - -@JS('console.log') -external void log(String _); - -class ConstObject { - const ConstObject(); - String get text => - 'ConstObject(' - 'reloadVariable: $variableToModifyToForceRecompile, ' - '${value1 == value2 ? 'ConstantEqualitySuccess' : 'ConstantEqualityFailure'})'; -} - -void printConst() { - log('${const ConstObject().text}'); -} - -void main() { - printConst(); -} diff --git a/dwds_test_common/fixtures/_test_hot_restart_breakpoints/pubspec.yaml b/dwds_test_common/fixtures/_test_hot_restart_breakpoints/pubspec.yaml deleted file mode 100644 index 8bbeb523ef..0000000000 --- a/dwds_test_common/fixtures/_test_hot_restart_breakpoints/pubspec.yaml +++ /dev/null @@ -1,13 +0,0 @@ -name: _test_hot_restart_breakpoints -version: 1.0.0 -description: >- - A fake package used for testing hot restart breakpoints. -publish_to: none -environment: - sdk: ^3.10.0-0.0.dev - -dev_dependencies: - build_daemon: ^4.1.4 - build_runner: ^2.16.0 - build_web_compilers: ^4.8.1 - diff --git a/dwds_test_common/fixtures/_test_hot_restart_breakpoints/web/index.html b/dwds_test_common/fixtures/_test_hot_restart_breakpoints/web/index.html deleted file mode 100644 index d93440a948..0000000000 --- a/dwds_test_common/fixtures/_test_hot_restart_breakpoints/web/index.html +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/dwds_test_common/fixtures/_test_hot_restart_breakpoints/web/main.dart b/dwds_test_common/fixtures/_test_hot_restart_breakpoints/web/main.dart deleted file mode 100644 index fad2e17776..0000000000 --- a/dwds_test_common/fixtures/_test_hot_restart_breakpoints/web/main.dart +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:js_interop'; - -@JS('console.log') -external void log(String _); - -void main() { - log('main gen0'); // Breakpoint: callLog -} diff --git a/dwds_test_common/fixtures/_test_package/lib/src/test_part.dart b/dwds_test_common/fixtures/_test_package/lib/src/test_part.dart deleted file mode 100644 index 5478db2764..0000000000 --- a/dwds_test_common/fixtures/_test_package/lib/src/test_part.dart +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of '../test_library.dart'; - -int testPartLibraryValue = 4; - -int testLibraryPartFunction(int formal) { - return formal; // Breakpoint: testLibraryPartFunction -} - -class TestLibraryPartClass { - final int field; - final int _field; - - TestLibraryPartClass(this.field, this._field) { - print('Constructor'); // Breakpoint: testLibraryPartClassConstructor - } - - @override - String toString() => 'field: $field, _field: $_field'; -} diff --git a/dwds_test_common/fixtures/_test_package/lib/src/version.dart b/dwds_test_common/fixtures/_test_package/lib/src/version.dart deleted file mode 100644 index 526cd53d4d..0000000000 --- a/dwds_test_common/fixtures/_test_package/lib/src/version.dart +++ /dev/null @@ -1,2 +0,0 @@ -// Generated code. Do not modify. -const packageVersion = '1.0.0'; diff --git a/dwds_test_common/fixtures/_test_package/lib/test_library.dart b/dwds_test_common/fixtures/_test_package/lib/test_library.dart deleted file mode 100644 index ac9eb90fa4..0000000000 --- a/dwds_test_common/fixtures/_test_package/lib/test_library.dart +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part 'src/test_part.dart'; - -int testLibraryValue = 3; - -int testLibraryFunction(int formal) { - return formal; // Breakpoint: testLibraryFunction -} - -class TestLibraryClass { - final int field; - final int _field; - TestLibraryClass(this.field, this._field) { - print('Constructor'); // Breakpoint: testLibraryClassConstructor - } - - @override - String toString() => 'field: $field, _field: $_field'; -} diff --git a/dwds_test_common/fixtures/_test_package/pubspec.yaml b/dwds_test_common/fixtures/_test_package/pubspec.yaml deleted file mode 100644 index 97258123ea..0000000000 --- a/dwds_test_common/fixtures/_test_package/pubspec.yaml +++ /dev/null @@ -1,16 +0,0 @@ -name: _test_package -version: 1.0.0 -description: >- - A fake package used for testing imports. Imports _test. -publish_to: none -environment: - sdk: ^3.10.0-0.0.dev - -dependencies: - _test: - path: ../_test - -dev_dependencies: - build_daemon: ^4.1.4 - build_runner: ^2.16.0 - build_web_compilers: ^4.4.12 \ No newline at end of file diff --git a/dwds_test_common/fixtures/_test_package/web/base_index.html b/dwds_test_common/fixtures/_test_package/web/base_index.html deleted file mode 100644 index affdbcb5ca..0000000000 --- a/dwds_test_common/fixtures/_test_package/web/base_index.html +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/dwds_test_common/fixtures/_test_package/web/index.html b/dwds_test_common/fixtures/_test_package/web/index.html deleted file mode 100644 index d93440a948..0000000000 --- a/dwds_test_common/fixtures/_test_package/web/index.html +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/dwds_test_common/fixtures/_test_package/web/main.dart b/dwds_test_common/fixtures/_test_package/web/main.dart deleted file mode 100644 index 04c7084b60..0000000000 --- a/dwds_test_common/fixtures/_test_package/web/main.dart +++ /dev/null @@ -1,256 +0,0 @@ -// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:async'; -import 'dart:convert'; -import 'dart:core'; -import 'dart:developer'; -// TODO: https://github.com/dart-lang/webdev/issues/2508 -// ignore: deprecated_member_use -import 'dart:html'; - -import 'package:_test_package/test_library.dart'; -import 'package:_test/deferred_library.dart' deferred as d; -import 'package:_test/library.dart'; - -extension NumberParsing on String { - int parseInt() { - final ret = int.parse(this); - return ret; // Breakpoint: extension - } -} - -void main() async { - var count = 0; - // For setting breakpoints. - Timer.periodic(const Duration(seconds: 1), (_) { - print('Count is: ${++count}'); - print(testLibraryValue); - print(testPartLibraryValue); - }); - - // for evaluation - var extensionId = 0; - Timer.periodic(const Duration(seconds: 1), (_) async { - await asyncMethod(); - printLocal(); - printFieldFromLibraryClass(); // Breakpoint: callPrintFieldFromLibraryClass - printFieldFromLibraryPartClass(); - printFieldMain(); - printGlobal(); - printFromTestLibrary(); - printFromTestLibraryPart(); - printFromTestPackage(); - printCallExtension(); - printLoopVariable(); - printGeneric(0); - printObjectMultiLine(); // Breakpoint: callPrintObjectMultiLine - printNestedObjectsMultiLine(); // Breakpoint: callPrintEnclosingFunctionMultiLine - printStream(); // Breakpoint: callPrintStream - printList(); - printMap(); - printSet(); - printFrame2(); - printLargeScope(); - // For testing evaluation in async JS frames. - registerUserExtension(extensionId++); - }); - - document.body?.appendText(concatenate('Program', ' is running!')); -} - -void registerUserExtension(int id) async { - registerExtension('ext.extension$id', (_, __) async { - print('Hello World from extension$id'); - return ServiceExtensionResponse.result(json.encode({'success': true})); - }); -} - -Future asyncMethod() async { - printLocal(); - return 0; -} - -void printGeneric(T formal) { - print(formal); -} - -void printLocal() { - final local = 42; - print('Local is: $local'); // Breakpoint: printLocal -} - -void printFieldFromLibraryClass() { - final instance = TestLibraryClass(1, 2); // Breakpoint: createLibraryObject - print('$instance'); // Breakpoint: printFieldFromLibraryClass -} - -void printFieldFromLibraryPartClass() { - final instance = TestLibraryPartClass(1, 2); - print('$instance'); // Breakpoint: printFieldFromLibraryPartClass -} - -void printFieldMain() { - final instance = MainClass(2, 1); - print('$instance'); // Breakpoint: printFieldMain -} - -void printGlobal() { - print(testLibraryValue); // Breakpoint: printGlobal -} - -void printFromTestPackage() { - print(concatenate('Hello', ' World')); -} - -void printFromTestLibrary() { - final local = 23; - print(testLibraryFunction(local)); -} - -void printFromTestLibraryPart() { - final local = 23; - print(testLibraryPartFunction(local)); -} - -void printCallExtension() { - final local = '23'; - print(local.parseInt()); -} - -void printLoopVariable() { - final list = ['1']; - for (var item in list) { - print(item); // Breakpoint: printLoopVariable - } -} - -Future printDeferred() async { - d.deferredPrintLocal(); -} - -void printNestedObjectsMultiLine() { - // dart format off - printEnclosingObject( // Breakpoint: printEnclosingFunctionMultiLine - EnclosingClass( // Breakpoint: printEnclosingObjectMultiLine - EnclosedClass(0), // Breakpoint: printNestedObjectMultiLine - ), - ); - // dart format on -} - -void printObjectMultiLine() { - // dart format off - print( // Breakpoint: printMultiLine - // Breakpoint: Do not remove, will break callstack tests! - createObject() // Breakpoint: printObjectMultiLine - ..initialize(), - ); - // dart format on -} - -void printEnclosingObject(EnclosingClass o) { - print(o); // Breakpoint: printEnclosingObject -} - -void printStream() { - final controller = StreamController(); - final stream = controller.stream.asBroadcastStream(); - final subscription = stream.listen(print); - controller.sink.add(0); - subscription.cancel(); // Breakpoint: printStream -} - -void printList() { - final list = [0, 1, 2]; - print(list); // Breakpoint: printList -} - -void printMap() { - final map = {'a': 1, 'b': 2, 'c': 3}; - print(map); // Breakpoint: printMap -} - -void printSet() { - final mySet = {1, 4, 5, 7}; - print(mySet); // Breakpoint: printSet -} - -ClassWithMethod createObject() { - return ClassWithMethod(0); // Breakpoint: createObjectWithMethod -} - -void printFrame2() { - final local2 = 2; - print(local2); - printFrame1(); -} - -void printFrame1() { - final local1 = 1; - print(local1); // Breakpoint: printFrame1 -} - -void printLargeScope() { - final t0 = 0; - final t1 = 1; - final t2 = 2; - final t3 = 3; - final t4 = 4; - final t5 = 5; - final t6 = 6; - final t7 = 7; - final t8 = 8; - final t9 = 9; - final t10 = 10; - final t11 = 11; - final t12 = 12; - final t13 = 13; - final t14 = 14; - final t15 = 15; - final t16 = 16; - final t17 = 17; - final t18 = 18; - final t19 = 19; - - // dart format off - print('$t0 $t1, $t2, $t3, $t4, $t5, $t6, $t7, $t8, $t9, $t10, ' - '$t11, $t12, $t13, $t14, $t15, $t16, $t17, $t18, $t19'); // Breakpoint: printLargeScope - // dart format on -} - -class MainClass { - final int field; - final int _field; - MainClass(this.field, this._field); // Breakpoint: newMainClass - - @override - String toString() => '$field, $_field'; // Breakpoint: toStringMainClass -} - -class EnclosedClass { - final int _field; - EnclosedClass(this._field); // Breakpoint: newEnclosedClass - - @override - String toString() => '$_field'; -} - -class ClassWithMethod { - final int _field; - ClassWithMethod(this._field); - - void initialize() {} - - @override - String toString() => '$_field'; -} - -class EnclosingClass { - final EnclosedClass _field; - EnclosingClass(this._field); // Breakpoint: newEnclosingClass - - @override - String toString() => '$_field'; -} diff --git a/dwds_test_common/fixtures/_test_parts/lib/library.dart b/dwds_test_common/fixtures/_test_parts/lib/library.dart deleted file mode 100644 index 5dcccc6d9f..0000000000 --- a/dwds_test_common/fixtures/_test_parts/lib/library.dart +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part 'part1.dart'; -part 'part2.dart'; -part 'part3.dart'; - -String concatenate1(String a, String b) { - // Padding........................... - // 'return' is at line 12, column 3, offset 410. - return '$a$b'; // Breakpoint: Concatenate1 -} diff --git a/dwds_test_common/fixtures/_test_parts/lib/part1.dart b/dwds_test_common/fixtures/_test_parts/lib/part1.dart deleted file mode 100644 index ba8524742d..0000000000 --- a/dwds_test_common/fixtures/_test_parts/lib/part1.dart +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of 'library.dart'; - -String concatenate2(int a, int b) { - // Padding............ - // Padding.............. - // Padding.............. - // 'return' is at line 12, column 3, offset 410. - return '$a$b'; // Breakpoint: Concatenate2 -} diff --git a/dwds_test_common/fixtures/_test_parts/lib/part2.dart b/dwds_test_common/fixtures/_test_parts/lib/part2.dart deleted file mode 100644 index 956fcee275..0000000000 --- a/dwds_test_common/fixtures/_test_parts/lib/part2.dart +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of 'library.dart'; - -// Padding.... -// -// -// 'return' below is at line that doesn't exist in the previous files, -// but still at offset 410. -// - -String concatenate3(String a, double b) { - return '$a$b'; // Breakpoint: Concatenate3 -} diff --git a/dwds_test_common/fixtures/_test_parts/lib/part3.dart b/dwds_test_common/fixtures/_test_parts/lib/part3.dart deleted file mode 100644 index f44084ea8d..0000000000 --- a/dwds_test_common/fixtures/_test_parts/lib/part3.dart +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of 'library.dart'; - -// Padding -// Padding -// Padding -// Padding -// Padding -// Padding -// Padding -// Padding -// Padding -// 'return' below is at line that doesn't exist in the other files, -// and at offset that doesn't exist in the other files. - -String concatenate4(List a, Map b) { - return '$a$b'; // Breakpoint: Concatenate4 -} diff --git a/dwds_test_common/fixtures/_test_parts/pubspec.yaml b/dwds_test_common/fixtures/_test_parts/pubspec.yaml deleted file mode 100644 index c3129bf5ef..0000000000 --- a/dwds_test_common/fixtures/_test_parts/pubspec.yaml +++ /dev/null @@ -1,16 +0,0 @@ -name: _test_parts -version: 1.0.0 -description: >- - A fake package used for testing parts. -publish_to: none -environment: - sdk: ^3.2.0 - -dependencies: - intl: ^0.17.0 - path: ^1.6.1 - -dev_dependencies: - build_daemon: ^4.1.4 - build_runner: ^2.16.0 - build_web_compilers: ^4.4.12 diff --git a/dwds_test_common/fixtures/_test_parts/web/base_index.html b/dwds_test_common/fixtures/_test_parts/web/base_index.html deleted file mode 100644 index affdbcb5ca..0000000000 --- a/dwds_test_common/fixtures/_test_parts/web/base_index.html +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/dwds_test_common/fixtures/_test_parts/web/index.html b/dwds_test_common/fixtures/_test_parts/web/index.html deleted file mode 100644 index d93440a948..0000000000 --- a/dwds_test_common/fixtures/_test_parts/web/index.html +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/dwds_test_common/fixtures/_test_parts/web/main.dart b/dwds_test_common/fixtures/_test_parts/web/main.dart deleted file mode 100644 index 4e489d3b5f..0000000000 --- a/dwds_test_common/fixtures/_test_parts/web/main.dart +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:async'; -import 'dart:core'; -// TODO: https://github.com/dart-lang/webdev/issues/2508 -// ignore: deprecated_member_use -import 'dart:html'; - -import 'package:_test_parts/library.dart'; - -void main() { - // For setting breakpoints. - Timer.periodic(const Duration(seconds: 1), (_) { - concatenate1('hello', 'world'); - concatenate2(2, 3); - concatenate3('hello', 36.42); - concatenate4(['hello', 'world'], {'foo': 'bar'}); - }); - - document.body!.appendText(concatenate1('Program', ' is running!')); -} diff --git a/dwds_test_common/fixtures/_webdev_smoke/build.yaml b/dwds_test_common/fixtures/_webdev_smoke/build.yaml deleted file mode 100644 index 5b9378c37f..0000000000 --- a/dwds_test_common/fixtures/_webdev_smoke/build.yaml +++ /dev/null @@ -1,7 +0,0 @@ -global_options: - build_web_compilers:ddc: - options: - canary: false - build_web_compilers:sdk_js: - options: - canary: false diff --git a/dwds_test_common/fixtures/_webdev_smoke/canary_build.yaml b/dwds_test_common/fixtures/_webdev_smoke/canary_build.yaml deleted file mode 100644 index 5b9378c37f..0000000000 --- a/dwds_test_common/fixtures/_webdev_smoke/canary_build.yaml +++ /dev/null @@ -1,7 +0,0 @@ -global_options: - build_web_compilers:ddc: - options: - canary: false - build_web_compilers:sdk_js: - options: - canary: false diff --git a/dwds_test_common/fixtures/_webdev_smoke/localhost+2-key.pem b/dwds_test_common/fixtures/_webdev_smoke/localhost+2-key.pem deleted file mode 100644 index 7bc7c1e266..0000000000 --- a/dwds_test_common/fixtures/_webdev_smoke/localhost+2-key.pem +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDR8FlEhQ8XZctL -mGdx78Z5EInK2mcfU9Nq4oUKkPeiql7Sd3cd3prd+m5MYylL255wAZf8Fdupkko2 -cjQEsU24jUBWVG5q3YqZ+OidFYdxYnPbDhFtzL3Lr2zHGAi+MgqVENUF6ED2O5tU -9U1crceXmXHb3E8Sg+zXX6TMVCS11OH9VQ1ZutM0fFMPZxmfU5aOfd5kuTmTiaOt -OMyymroUPgzRW6UcbLfSdD7KuNFQgHDHiWkr2MtoZffgGM/cOfmCdgE85MdL6kyb -7TUTbAlTSpJNWwygObce7DN7qwM8HocRWSAfH+y3ewbs2NtzG1Az+a/kUBjhvmjT -WFiwDT+1AgMBAAECggEBALkJMXTeHh4OP2+ipVJb9r/P3tMnSornFEl5268jdNAv -f6HbX+a4xCDwUHUNVWGh8XRhQzcRgOllofl5EPYt3AXUoac1hZi1KStqooOJbTZ3 -gwvIy33OXl5/gM2+Fj6k1oTqMAej3FXq1Y69InGUTX4F5b/V3u+/zWlKyHK7mxuT -LIP3/iAxbpST5FB1G7ZPyz5mvzvEQFRiv9ubuMxYg3fzORULtbnnHNAM5jLG3IzZ -9EM/1umaeZu1bg9rGVVgr0l/rWMJSg5u+Z6jcrt9+Oj7hYrMPGHKHXAPhC1gaq+k -tlKHj/mhmJyN0jUXt71UgrsWF3MhrK2W2AlIfxXhIIECgYEA8oaIEOaeNmtDqlH5 -MmU0jd2EcMRnLrlfKs4fKObFoSMqELRB3yJ1u5Yt/wQCCSpN9bhkinR0l4Q7YsAy -4sg5Q3VaA/rUWkVKkv2sD04LbBmpHr5vksPnIPKcfAY3csQ1F5pu9gY6zgzdxBvN -nWEu8tqbUSdC5+0F+tB8IDW+/lUCgYEA3ZpVXmBLvgeZJ8rNjCCeKR5hXMYdFKqC -Yd5KfasTKH7h8a4GWo/mtUsS5UPRRjhrP5mPjdUKBFhSaJtX+k9Hhot58RN20fWR -4Ake4yV/cNFRykD1jsv9JJiPkggnVLVXN91+/EnKJozWv46q6nG44iX+q2w2i9FQ -6lohgwQp2+ECgYEAwKJY+0uiiUkD0woPbJb0emZj5wophvRYgfB80YkTmt0KcYAr -/icp6pjr6e3uDAedKrqOqWa8oQi3/sT45ibxTQKuQBEAkL8O79grzXBJJFDxgujy -SFnwgLwTzXNGoZL1NM1Gq4XhOX8Aut72n7Xsi5tV2MzdmMgsgr8MiK0ICo0CgYBA -h4yMauYjc/r5R2kLgQQNXTdk2JvnRK+q6Bww8/wkMq6AvfhDrtuztyTNdi4ekJdK -ceEHoB3GniGBLJs13JgrabocpVpYUXYlEwLXijfOFmYGy1u2NViFq5dDIvSxCg1X -yzwLI0GmcCSoq1bB5lO8Juw95skLdexmEdDoYfH+gQKBgDgaFlF9lYuKd0HhAxxm -oJ8WBv26FWxR8/UsvUPqI8Mzmb8J1Q22tZEMEVr8bN/HkcL+8DVQ4uh2zx9+rqC0 -aPqJZNgePGpRDhZ/cwA8xsg+Xkou8rrFjpGRuVuG9FvMEexufkHoDc94ppONuwsR -QzjTUxgXdLjtxT95ISwX83Nr ------END PRIVATE KEY----- diff --git a/dwds_test_common/fixtures/_webdev_smoke/localhost+2.pem b/dwds_test_common/fixtures/_webdev_smoke/localhost+2.pem deleted file mode 100644 index a62046b5ee..0000000000 --- a/dwds_test_common/fixtures/_webdev_smoke/localhost+2.pem +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIEgjCCAuqgAwIBAgIQBeTmjjlnyrCQUy06Xx/ybzANBgkqhkiG9w0BAQsFADCB -pTEeMBwGA1UEChMVbWtjZXJ0IGRldmVsb3BtZW50IENBMT0wOwYDVQQLDDRMQVBU -T1AtQUFSSFFPMkxcV2Rlc3RATEFQVE9QLUFBUkhRTzJMIChXYWduZXIgRC4gRi4p -MUQwQgYDVQQDDDtta2NlcnQgTEFQVE9QLUFBUkhRTzJMXFdkZXN0QExBUFRPUC1B -QVJIUU8yTCAoV2FnbmVyIEQuIEYuKTAeFw0yNTAyMTQxNDI2MjFaFw0yNzA1MTQx -NDI2MjFaMGgxJzAlBgNVBAoTHm1rY2VydCBkZXZlbG9wbWVudCBjZXJ0aWZpY2F0 -ZTE9MDsGA1UECww0TEFQVE9QLUFBUkhRTzJMXFdkZXN0QExBUFRPUC1BQVJIUU8y -TCAoV2FnbmVyIEQuIEYuKTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB -ANHwWUSFDxdly0uYZ3HvxnkQicraZx9T02rihQqQ96KqXtJ3dx3emt36bkxjKUvb -nnABl/wV26mSSjZyNASxTbiNQFZUbmrdipn46J0Vh3Fic9sOEW3MvcuvbMcYCL4y -CpUQ1QXoQPY7m1T1TVytx5eZcdvcTxKD7NdfpMxUJLXU4f1VDVm60zR8Uw9nGZ9T -lo593mS5OZOJo604zLKauhQ+DNFbpRxst9J0Psq40VCAcMeJaSvYy2hl9+AYz9w5 -+YJ2ATzkx0vqTJvtNRNsCVNKkk1bDKA5tx7sM3urAzwehxFZIB8f7Ld7BuzY23Mb -UDP5r+RQGOG+aNNYWLANP7UCAwEAAaNqMGgwDgYDVR0PAQH/BAQDAgWgMBMGA1Ud -JQQMMAoGCCsGAQUFBwMBMB8GA1UdIwQYMBaAFLmYo+uZjtNZbL0jyR7XVnK/FICG -MCAGA1UdEQQZMBeCCWxvY2FsaG9zdIcEfwAAAYcEAAAAADANBgkqhkiG9w0BAQsF -AAOCAYEAbUhcggR4p8n/Us+ov8zvI+hBIrDi7GevWQQKrU1Rp2gzHV6glhqGMQ1A -BkGlj56L9O4P02awFZzB/55d2CsufzMD+d4aMKpdIJivwXByg6fJCtPOIprAiGeR -GuE9Q9ceUUJVrTYiy5CZeKTIQp4ZqWu5/wBQ+yvbsvxnzq2ESDpGmCkY6/ToMWmu -5cZPbZcyF7XBybSBdvaMGFsthRpawvQMsGHDZBaVhLn099Hjx2p35jNiM+HqCQXn -NweLYMJx9FZtOYyNJoTj0w97ViaSubz7V9n7LVIxW1QXmDXAk+75Fwq3x+n/tfhe -1BTLEOKvARvRVB6M1EE0z+zeNusHIu/TUMSmGv59OhsQdW5Lp1D0o3JK2mHu6tgP -+v1XRMaTQq73oHqU0oXCtsEdPuoFBNREBDhBOGB5wtFjfniu1zD0cKSDbVslSD5B -LKu9Yi1PzZTWVkaOWQolA6sYwWFLhQbHoyQoNjAJz58VNNtYIMjR6fZ0xTYiPQpJ -4Jh3TJKU ------END CERTIFICATE----- diff --git a/dwds_test_common/fixtures/_webdev_smoke/mono_pkg.yaml b/dwds_test_common/fixtures/_webdev_smoke/mono_pkg.yaml deleted file mode 100644 index 12cfc85246..0000000000 --- a/dwds_test_common/fixtures/_webdev_smoke/mono_pkg.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# See https://pub.dev/packages/mono_repo for details -stages: - - analyzer_and_format: - - group: - - format - - analyze: --fatal-infos . - sdk: dev - -cache: - directories: - - .dart_tool/build - - .dart_tool/pub diff --git a/dwds_test_common/fixtures/_webdev_smoke/pubspec.yaml b/dwds_test_common/fixtures/_webdev_smoke/pubspec.yaml deleted file mode 100644 index 550a1658dc..0000000000 --- a/dwds_test_common/fixtures/_webdev_smoke/pubspec.yaml +++ /dev/null @@ -1,12 +0,0 @@ -name: _webdev_smoke -description: A test fixture for webdev testing. - -publish_to: none - -environment: - sdk: ^3.14.0-286.0.dev - -dev_dependencies: - build_daemon: ^4.1.4 - build_runner: ^2.16.0 - build_web_compilers: ^4.4.12 diff --git a/dwds_test_common/fixtures/_webdev_smoke/web/index.html b/dwds_test_common/fixtures/_webdev_smoke/web/index.html deleted file mode 100644 index 7b69801300..0000000000 --- a/dwds_test_common/fixtures/_webdev_smoke/web/index.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - - webdev example - - - - - - diff --git a/dwds_test_common/fixtures/_webdev_smoke/web/main.dart b/dwds_test_common/fixtures/_webdev_smoke/web/main.dart deleted file mode 100644 index 8e3be28735..0000000000 --- a/dwds_test_common/fixtures/_webdev_smoke/web/main.dart +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:async'; -import 'dart:convert'; -import 'dart:developer'; -// TODO: https://github.com/dart-lang/webdev/issues/2508 -// ignore: deprecated_member_use -import 'dart:html'; - -void main() { - print('Initial Print'); - - registerExtension('ext.print', (_, __) async { - print('Hello World'); - return ServiceExtensionResponse.result(json.encode({'success': true})); - }); - document.body?.append(SpanElement()..text = 'Hello World!!'); - - var count = 0; - Timer.periodic(const Duration(seconds: 1), (_) { - print('Counter is: ${++count}'); // Breakpoint: printCounter - }); -} - -String topLevelMethod() => 'verify this!'; diff --git a/dwds_test_common/fixtures/_webdev_smoke/web/scopes.html b/dwds_test_common/fixtures/_webdev_smoke/web/scopes.html deleted file mode 100644 index 6c33073945..0000000000 --- a/dwds_test_common/fixtures/_webdev_smoke/web/scopes.html +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/dwds_test_common/fixtures/_webdev_smoke/web/scopes_main.dart b/dwds_test_common/fixtures/_webdev_smoke/web/scopes_main.dart deleted file mode 100644 index c1a4e0e286..0000000000 --- a/dwds_test_common/fixtures/_webdev_smoke/web/scopes_main.dart +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -/// An example with more complicated scope. -library; - -import 'dart:async'; -import 'dart:collection'; - -final libraryPublicFinal = MyTestClass(); - -final _libraryPrivateFinal = 1; -Object? libraryNull; -var libraryPublic = ['library', 'public', 'variable']; -var notAList = NotReallyAList(); - -var _libraryPrivate = ['library', 'private', 'variable']; - -var identityMap = {}; - -var map = {}; - -void staticFunction(int formal) { - print(formal); // Breakpoint: staticFunction -} - -void main() async { - print('Initial print from scopes app'); - final local = 'local in main'; - final intLocalInMain = 42; - final testClass = MyTestClass(); - Object? localThatsNull; - identityMap['a'] = 1; - identityMap['b'] = 2; - map['a'] = [1, 2, 3]; - map['b'] = 'something'; - notAList.add(7); - - String nestedFunction(T parameter, Object aClass) { - final another = int.tryParse('$parameter'); - return '$local: parameter, $another'; // Breakpoint: nestedFunction - } - - dynamic nestedWithClosure(String banana) { - return () => '$local + $banana'; - } - - Timer.periodic(const Duration(seconds: 1), (Timer t) { - final ticks = t.tick; - // ignore: unused_local_variable, prefer_typing_uninitialized_variables - var closureLocal; - libraryPublicFinal.printCount(); - staticFunction(1); - print('ticking... $ticks (the answer is $intLocalInMain)'); - print(nestedFunction('$ticks ${testClass.message}', Timer)); - print(localThatsNull); - print(libraryNull); - final localList = libraryPublic; - print(localList); - localList.add('abc'); - final f = testClass.methodWithVariables(); - print(f('parameter')); - }); - - print(_libraryPrivateFinal); - print(_libraryPrivate); - print(nestedFunction(_libraryPrivate.first, Object)); - print(nestedWithClosure(_libraryPrivate.first)()); -} - -String libraryFunction(String arg) { - print('calling a library function with $arg'); - final concat = 'some constant plus $arg plus whatever'; - print(concat); - return concat; -} - -class MyTestClass { - final String message; - - late String notFinal; - - MyTestClass({this.message = 'world'}) { - myselfField = this; - tornOff = toString; - } - - String hello() => message; - - String Function(String) methodWithVariables() { - final local = '$message + something'; - print(local); - return (String parameter) { - // Be sure to use a field from this, so it isn't entirely optimized away. - final closureLocalInsideMethod = '$message/$local/$parameter'; - print(closureLocalInsideMethod); - return closureLocalInsideMethod; // Breakpoint: nestedClosure - }; - } - - //ignore: avoid_returning_this - MyTestClass get myselfGetter => this; - - late MyTestClass myselfField; - - var count = 0; - - // An easy location to add a breakpoint. - void printCount() { - print('The count is ${++count}'); - libraryFunction('abc'); // Breakpoint: printMethod - } - - final _privateField = 'a private field'; - - // ignore: unused_element - String privateMethod(String s) => '$s : $_privateField'; - - @override - String toString() => 'A test class with message $message'; - - bool equals(Object other) { - if (other is MyTestClass) return message == other.hello(); - return false; - } - - Function closure = someFunction; - - late String Function() tornOff; -} - -Function? someFunction() => null; - -// ignore: unused_element -int _libraryPrivateFunction(int a, int b) => a + b; - -class NotReallyAList extends ListBase { - final List _internal; - - NotReallyAList() : _internal = []; - - @override - Object? operator [](x) => _internal[x]; - - @override - operator []=(x, y) => _internal[x] = y as Object?; - - @override - int get length => _internal.length; - - @override - set length(x) => _internal.length = x; -} diff --git a/dwds_test_common/fixtures/analysis_options.yaml b/dwds_test_common/fixtures/analysis_options.yaml deleted file mode 100644 index 064de52e36..0000000000 --- a/dwds_test_common/fixtures/analysis_options.yaml +++ /dev/null @@ -1,6 +0,0 @@ -# This file prevents sub-packages from picking up the parent's analysis options, -# which eliminates package resolution errors during 'dart format'. - -analyzer: - exclude: - - "**" \ No newline at end of file diff --git a/dwds_test_common/lib/logging.dart b/dwds_test_common/lib/logging.dart deleted file mode 100644 index 1d870b0859..0000000000 --- a/dwds_test_common/lib/logging.dart +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:async'; - -import 'package:logging/logging.dart'; -import 'package:test/test.dart'; - -typedef LogWriter = - void Function( - Level level, - String message, { - String? error, - String? loggerName, - String? stackTrace, - }); - -StreamSubscription? _loggerSub; - -/// Redirect the logs for the current zone to emit on failure. -/// -/// If [debug] is false, messages are stored and reported on test failure. -/// If [debug] is true, messages are always printed to the console. -/// -/// Note that the [LogWriter] uses [printOnFailure] that stores the messages -/// on the current zone. As a result, [setCurrentLogWriter] needs to be set -/// in both `setUpAll` and `setUp` to store messages for the same zone as the -/// failure in order to report all stored messages on that failure. -/// -/// For example: -/// -/// // Enable verbose logging for debugging. -/// bool debug = true; -/// -/// group('shared context', () { -/// setUpAll(() async { -/// // Set the logger for the current group. -/// setCurrentLogWriter(debug: debug); -/// ... -/// }); -/// setUp(() async { -/// // Reset the logger for the current test. -/// setCurrentLogWriter(debug: debug); -/// ... -/// }); -/// ... -/// }); -void setCurrentLogWriter({bool debug = false}) => - configureLogWriter(customLogWriter: createLogWriter(debug: debug)); - -/// Configure test log writer. -/// -/// Tests and groups of tests can use this to configure individual -/// log writers on setup. -void configureLogWriter({LogWriter? customLogWriter}) { - _logWriter = customLogWriter ?? _logWriter; - Logger.root.level = Level.ALL; - _loggerSub?.cancel(); - _loggerSub = Logger.root.onRecord.listen((event) { - logWriter( - event.level, - event.message, - error: event.error?.toString(), - loggerName: event.loggerName, - stackTrace: event.stackTrace?.toString(), - ); - }); -} - -void stopLogWriter() { - _loggerSub?.cancel(); - _loggerSub = null; -} - -LogWriter _logWriter = createLogWriter(); - -LogWriter createLogWriter({bool debug = false}) => - (level, message, {String? error, String? loggerName, String? stackTrace}) { - final printFn = debug ? print : printOnFailure; - final errorMessage = error == null ? '' : ':\n$error'; - final stackMessage = stackTrace == null ? '' : ':\n$stackTrace'; - printFn( - '[$level] $loggerName: $message' - '$errorMessage' - '$stackMessage', - ); - }; - -LogWriter get logWriter => _logWriter; diff --git a/dwds_test_common/lib/sdk_asset_generator.dart b/dwds_test_common/lib/sdk_asset_generator.dart deleted file mode 100644 index ea1f06ed01..0000000000 --- a/dwds_test_common/lib/sdk_asset_generator.dart +++ /dev/null @@ -1,185 +0,0 @@ -import 'dart:convert'; -import 'dart:io'; - -import 'package:dwds/expression_compiler.dart'; -import 'package:file/file.dart'; -import 'package:file/local.dart'; -import 'package:logging/logging.dart'; -import 'package:path/path.dart' as p; -import 'test_sdk_layout.dart'; - -/// Generates sdk.js, sdk.map, files. - -class SdkAssetGenerator { - bool _sdkAssetsGenerated = false; - final _logger = Logger('SdkAssetGenerator'); - - final FileSystem fileSystem; - final bool canaryFeatures; - final ModuleFormat ddcModuleFormat; - final bool verbose; - - late final TestSdkLayout sdkLayout; - - SdkAssetGenerator({ - this.fileSystem = const LocalFileSystem(), - required this.sdkLayout, - required this.canaryFeatures, - required this.ddcModuleFormat, - this.verbose = false, - }); - - /// Generate all SDK assets, once for the current executable run. - Future generateSdkAssets() async { - if (!_sdkAssetsGenerated) { - _sdkAssetsGenerated = true; - - // SDK full and outline .dill files are shipped with the SDK, - // but the JavaScript and sourcemaps are generated by other tooling - // i.e. flutter SDK or build_web_compilers. - // Generate missing files for tests if needed. - await _generateSdkJavaScript(canaryFeatures: canaryFeatures); - } - } - - String resolveSdkJsPath({required bool canaryFeatures}) => - switch (ddcModuleFormat) { - ModuleFormat.amd => sdkLayout.amdJsPath, - ModuleFormat.ddc => sdkLayout.ddcJsPath, - _ => throw Exception('Unsupported DDC module format $ddcModuleFormat.'), - }; - - String resolveSdkSourcemapPath({required bool canaryFeatures}) => - switch (ddcModuleFormat) { - ModuleFormat.amd => sdkLayout.amdJsMapPath, - ModuleFormat.ddc => sdkLayout.ddcJsMapPath, - _ => throw Exception('Unsupported DDC module format $ddcModuleFormat.'), - }; - - String resolveSdkJsFilename({required bool canaryFeatures}) => - switch (ddcModuleFormat) { - ModuleFormat.amd => sdkLayout.amdJsFileName, - ModuleFormat.ddc => sdkLayout.ddcJsFileName, - _ => throw Exception('Unsupported DDC module format $ddcModuleFormat.'), - }; - - Future _generateSdkJavaScript({required bool canaryFeatures}) async { - Directory? outputDir; - try { - // Files to copy generated files to. - final outputJsPath = resolveSdkJsPath(canaryFeatures: canaryFeatures); - final outputJsMapPath = resolveSdkSourcemapPath( - canaryFeatures: canaryFeatures, - ); - final outputFullDillPath = sdkLayout.fullDillPath; - - final hasJsAsset = _exists(outputJsPath); - final hasJsMapAsset = _exists(outputJsMapPath); - final hasFullDillAsset = _exists(outputFullDillPath); - final hasAssets = hasFullDillAsset && hasJsAsset && hasJsMapAsset; - - // Files already exist. - if (hasAssets) return; - - // Generate missing files. - outputDir = fileSystem.systemTempDirectory.createTempSync(); - - // Files to generate - final jsPath = p.join( - outputDir.path, - resolveSdkJsFilename(canaryFeatures: canaryFeatures), - ); - final jsMapPath = p.setExtension(jsPath, '.js.map'); - - _logger.info('Generating SDK JavaScript and sourcemap files...'); - - final sdkDirectoryUri = fileSystem.directory(sdkLayout.sdkDirectory).uri; - final args = [ - 'compile', - 'js-dev', - '--compile-sdk', - '--multi-root', - '$sdkDirectoryUri', - '--multi-root-scheme', - 'org-dartlang-sdk', - '--libraries-file', - 'org-dartlang-sdk:///lib/libraries.json', - '--modules', - ddcModuleFormat.name, - 'dart:core', - '-o', - jsPath, - if (canaryFeatures) '--canary', - ]; - - final output = []; - _logger.fine('Executing dart ${args.join(' ')}'); - final process = await Process.start( - sdkLayout.dartPath, - args, - workingDirectory: sdkLayout.sdkDirectory, - ); - - process.stdout - .transform(utf8.decoder) - .transform(const LineSplitter()) - .listen((line) { - _logger.fine(line); - output.add(line); - }); - - process.stderr - .transform(utf8.decoder) - .transform(const LineSplitter()) - .listen((line) { - _logger.warning(line); - output.add(line); - }); - - await process.exitCode.then((int code) { - if (code != 0) { - _logger.warning('Error generating $jsPath: ${output.join('\n')}'); - throw Exception('The Dart compiler exited unexpectedly'); - } - }); - - final outputJsDir = fileSystem.directory(p.dirname(outputJsPath)); - if (!outputJsDir.existsSync()) { - outputJsDir.createSync(recursive: true); - } - await _moveAndValidate(jsPath, outputJsPath); - await _moveAndValidate(jsMapPath, outputJsMapPath); - - _logger.info('Done generating SDK JavaScript and sourcemap files.'); - } catch (e, s) { - _logger.severe( - 'Failed to generate SDK JavaScript and sourcemap files', - e, - s, - ); - rethrow; - } finally { - outputDir?.deleteSync(recursive: true); - } - } - - bool _exists(String path) => fileSystem.file(path).existsSync(); - void _delete(String path) => fileSystem.file(path).deleteSync(); - - Future _moveAndValidate(String from, String to) async { - _logger.fine('Renaming $from to $to'); - - if (!_exists(from)) { - _logger.severe('Failed to generate SDK asset at $to'); - throw Exception('File "$from" does not exist.'); - } - - if (_exists(to)) _delete(to); - await fileSystem.file(from).rename(to); - - if (!_exists(to)) { - _logger.severe('Failed to generate SDK asset at $to'); - throw Exception('File "$to" does not exist.'); - } - } -} diff --git a/dwds_test_common/lib/test_sdk_configuration.dart b/dwds_test_common/lib/test_sdk_configuration.dart deleted file mode 100644 index c6fabc016a..0000000000 --- a/dwds_test_common/lib/test_sdk_configuration.dart +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:io'; - -import 'package:dwds/expression_compiler.dart'; -import 'package:dwds/sdk_configuration.dart'; -import 'package:logging/logging.dart'; - -import 'sdk_asset_generator.dart'; -import 'test_sdk_layout.dart'; - -/// Implementation for SDK configuration for tests that can generate -/// missing assets. -/// -/// - Generate SDK js, source map (normally included in flutter SDK -/// or produced by build). -class TestSdkConfigurationProvider extends SdkConfigurationProvider { - final _logger = Logger('TestSdkConfigurationProvider'); - - final bool verbose; - final bool canaryFeatures; - final ModuleFormat ddcModuleFormat; - late final Directory _sdkDirectory; - SdkConfiguration? _configuration; - - late final TestSdkLayout sdkLayout; - - TestSdkConfigurationProvider({ - this.canaryFeatures = false, - this.verbose = false, - this.ddcModuleFormat = ModuleFormat.amd, - }) { - _sdkDirectory = Directory.systemTemp.createTempSync('sdk_copy'); - sdkLayout = TestSdkLayout.createDefault(_sdkDirectory.path); - } - - @override - Future get configuration async => - _configuration ??= await _create(); - - /// Generate missing assets in the default SDK layout. - /// - /// Creates a copy of the SDK directory where all the missing assets - /// are generated. Tests using this configuration run using the copy - /// sdk layout to make sure the actual SDK is not modified. - Future _create() async { - try { - await copyDirectory( - TestSdkLayout.defaultSdkDirectory, - _sdkDirectory.path, - ); - } catch (e, s) { - _logger.severe('Failed to create SDK directory copy', e, s); - dispose(); - rethrow; - } - - try { - final assetGenerator = SdkAssetGenerator( - sdkLayout: sdkLayout, - canaryFeatures: canaryFeatures, - verbose: verbose, - ddcModuleFormat: ddcModuleFormat, - ); - - await assetGenerator.generateSdkAssets(); - return TestSdkLayout.createConfiguration(sdkLayout); - } catch (e, s) { - _logger.severe('Failed generate missing assets', e, s); - dispose(); - rethrow; - } - } - - void dispose({bool retry = true}) { - try { - if (_sdkDirectory.existsSync()) { - _sdkDirectory.deleteSync(recursive: true); - } - } catch (e, s) { - _logger.warning('Failed delete SDK directory copy', e, s); - if (retry) { - dispose(retry: false); - } - } - } -} diff --git a/dwds_test_common/lib/test_sdk_layout.dart b/dwds_test_common/lib/test_sdk_layout.dart deleted file mode 100644 index c44b08e331..0000000000 --- a/dwds_test_common/lib/test_sdk_layout.dart +++ /dev/null @@ -1,199 +0,0 @@ -// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:io'; - -import 'package:dwds/sdk_configuration.dart'; -import 'package:path/path.dart' as p; - -/// Test Dart SDK layout. -/// -/// Contains definition of the default SDK layout required for tests. -/// We keep all the path constants in one place for ease of update. -class TestSdkLayout { - static final defaultSdkDirectory = SdkLayout.defaultSdkDirectory; - - static TestSdkLayout defaultSdkLayout = TestSdkLayout.createDefault( - defaultSdkDirectory, - ); - - static SdkConfiguration defaultSdkConfiguration = createConfiguration( - defaultSdkLayout, - ); - - factory TestSdkLayout.createDefault(String sdkDirectory) => - TestSdkLayout.createDefaultFromSdkLayout( - SdkLayout.createDefault(sdkDirectory), - ); - - factory TestSdkLayout.createDefaultFromSdkLayout(SdkLayout sdkLayout) => - TestSdkLayout( - sdkDirectory: sdkLayout.sdkDirectory, - summaryPath: p.join( - sdkLayout.sdkDirectory, - 'lib', - '_internal', - 'ddc_outline.dill', - ), - fullDillPath: p.join( - sdkLayout.sdkDirectory, - 'lib', - '_internal', - 'ddc_platform.dill', - ), - amdJsPath: p.join( - sdkLayout.sdkDirectory, - 'lib', - 'dev_compiler', - 'kernel', - 'amd', - 'dart_sdk.js', - ), - amdJsMapPath: p.join( - sdkLayout.sdkDirectory, - 'lib', - 'dev_compiler', - 'kernel', - 'amd', - 'dart_sdk.js.map', - ), - ddcJsPath: p.join( - sdkLayout.sdkDirectory, - 'lib', - 'dev_compiler', - 'kernel', - 'ddc', - 'dart_sdk.js', - ), - ddcJsMapPath: p.join( - sdkLayout.sdkDirectory, - 'lib', - 'dev_compiler', - 'kernel', - 'ddc', - 'dart_sdk.js.map', - ), - ddcModuleLoaderJsPath: p.join( - sdkLayout.sdkDirectory, - 'lib', - 'dev_compiler', - 'ddc', - 'ddc_module_loader.js', - ), - requireJsPath: p.join( - sdkLayout.sdkDirectory, - 'lib', - 'dev_compiler', - 'amd', - 'require.js', - ), - stackTraceMapperPath: p.join( - sdkLayout.sdkDirectory, - 'lib', - 'dev_compiler', - 'web', - 'dart_stack_trace_mapper.js', - ), - dartPath: p.join( - sdkLayout.sdkDirectory, - 'bin', - Platform.isWindows ? 'dart.exe' : 'dart', - ), - dartAotRuntimePath: p.join( - sdkLayout.sdkDirectory, - 'bin', - Platform.isWindows ? 'dartaotruntime.exe' : 'dartaotruntime', - ), - frontendServerSnapshotPath: p.join( - sdkLayout.sdkDirectory, - 'bin', - 'snapshots', - 'frontend_server_aot.dart.snapshot', - ), - dartdevcSnapshotPath: sdkLayout.dartdevcSnapshotPath, - kernelWorkerSnapshotPath: p.join( - sdkLayout.sdkDirectory, - 'bin', - 'snapshots', - 'kernel_worker_aot.dart.snapshot', - ), - devToolsDirectory: p.join( - sdkLayout.sdkDirectory, - 'bin', - 'resources', - 'devtools', - ), - ); - - final String sdkDirectory; - - String get amdJsFileName => p.basename(amdJsPath); - String get amdJsMapFileName => p.basename(amdJsMapPath); - String get ddcJsFileName => p.basename(ddcJsPath); - String get ddcJsMapFileName => p.basename(ddcJsMapPath); - String get summaryFileName => p.basename(summaryPath); - String get fullDillFileName => p.basename(fullDillPath); - - final String amdJsPath; - final String amdJsMapPath; - final String ddcJsPath; - final String ddcJsMapPath; - final String summaryPath; - final String fullDillPath; - - final String ddcModuleLoaderJsPath; - final String requireJsPath; - final String stackTraceMapperPath; - - final String dartPath; - final String dartAotRuntimePath; - final String frontendServerSnapshotPath; - final String dartdevcSnapshotPath; - final String kernelWorkerSnapshotPath; - final String devToolsDirectory; - - const TestSdkLayout({ - required this.sdkDirectory, - required this.amdJsPath, - required this.amdJsMapPath, - required this.ddcJsPath, - required this.ddcJsMapPath, - required this.summaryPath, - required this.fullDillPath, - required this.ddcModuleLoaderJsPath, - required this.requireJsPath, - required this.stackTraceMapperPath, - required this.dartPath, - required this.dartAotRuntimePath, - required this.frontendServerSnapshotPath, - required this.dartdevcSnapshotPath, - required this.kernelWorkerSnapshotPath, - required this.devToolsDirectory, - }); - - /// Creates configuration from sdk layout. - static SdkConfiguration createConfiguration(TestSdkLayout sdkLayout) => - SdkConfiguration( - sdkDirectory: sdkLayout.sdkDirectory, - sdkSummaryPath: sdkLayout.summaryPath, - compilerWorkerPath: sdkLayout.dartdevcSnapshotPath, - ); -} - -// Update modified files. -Future copyDirectory(String from, String to) async { - if (!Directory(from).existsSync()) return; - await Directory(to).create(recursive: true); - - await for (final file in Directory(from).list(followLinks: false)) { - final copyTo = p.join(to, p.relative(file.path, from: from)); - if (file is Directory) { - await copyDirectory(file.path, copyTo); - } else if (file is File) { - await File(file.path).copy(copyTo); - } else if (file is Link) { - await Link(copyTo).create(await file.target(), recursive: true); - } - } -} diff --git a/dwds_test_common/lib/utilities.dart b/dwds_test_common/lib/utilities.dart deleted file mode 100644 index 640cbc3120..0000000000 --- a/dwds_test_common/lib/utilities.dart +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. -import 'dart:convert'; -import 'dart:io'; -import 'dart:isolate'; - -import 'package:path/path.dart' as p; -import 'package:pub_semver/pub_semver.dart'; - -const webdevDirName = 'webdev'; -const dwdsDirName = 'dwds'; -const fixturesDirName = 'fixtures'; - -/// The path to the project root directory, e.g. `webdev/` or `pkg/` in the -/// Dart SDK. -String get projectRootDir { - return p.dirname(_dwdsTestCommonPackageRoot); -} - -/// The path to the DWDS directory in the local machine, e.g. -/// 'webdev/dwds' or 'pkg/dwds'. -String get dwdsPath { - return p.join(projectRootDir, dwdsDirName); -} - -/// The path to the fixtures directory in the local machine, e.g. -/// 'webdev/dwds_test_common/fixtures' or 'pkg/dwds_test_common/fixtures'. -String get fixturesPath { - return p.join(_dwdsTestCommonPackageRoot, fixturesDirName); -} - -/// The path to the webdev/dwds_test_common or pkg/dwds_test_common package -/// root in the local machine, e.g. 'webdev/dwds_test_common' or -/// 'pkg/dwds_test_common'. -String get _dwdsTestCommonPackageRoot { - // Try to resolve any `package:dwds_test_common` file. - final packageUri = Isolate.resolvePackageUriSync( - Uri.parse('package:dwds_test_common/utilities.dart'), - ); - if (packageUri != null) { - // Strip `lib/utilities.dart`. - return p.dirname(p.dirname(packageUri.toFilePath())); - } - // If there's no package config, try to find it from the current dir. - for (var dir = p.current; dir != p.dirname(dir); dir = p.dirname(dir)) { - final file = File(p.join(dir, '.dart_tool', 'package_config.json')); - if (!file.existsSync()) continue; - final config = jsonDecode(file.readAsStringSync()) as Map; - for (final package in config['packages'] as List) { - if (package case { - 'name': 'dwds_test_common', - 'rootUri': final String rootUri, - }) { - return p.fromUri(file.uri.resolve(rootUri)); - } - } - } - throw StateError('Could not find dwds_test_common from ${p.current}.'); -} - -// Creates a path compatible for web. -String webCompatiblePath(List pathParts) { - final context = p.Context(style: p.Style.posix); - return context.joinAll([...pathParts]); -} - -/// Expects one of [pathFromWebdev], [pathFromDwds] or [pathFromFixtures] to -/// be provided. Returns the absolute path in the local machine to that path, -/// e.g. absolutePath(pathFromFixtures: '_test/example') -> -/// '/workstation/webdev/dwds_test_common/fixtures/_test/example' -String absolutePath({ - String? pathFromWebdev, - String? pathFromDwds, - String? pathFromFixtures, -}) { - if (pathFromWebdev != null) { - assert(pathFromDwds == null && pathFromFixtures == null); - return p.normalize(p.join(projectRootDir, pathFromWebdev)); - } - if (pathFromDwds != null) { - assert(pathFromFixtures == null); - return p.normalize(p.join(dwdsPath, pathFromDwds)); - } - if (pathFromFixtures != null) { - assert(pathFromDwds == null && pathFromWebdev == null); - return p.normalize(p.join(fixturesPath, pathFromFixtures)); - } - throw Exception('Expected a path parameter.'); -} - -bool dartSdkIsAtLeast(String sdkVersion) { - final expectedVersion = Version.parse(sdkVersion); - final actualVersion = Version.parse(Platform.version.split(' ')[0]); - return actualVersion >= expectedVersion; -} diff --git a/dwds_test_common/mono_pkg.yaml b/dwds_test_common/mono_pkg.yaml deleted file mode 100644 index 1366dcead6..0000000000 --- a/dwds_test_common/mono_pkg.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# See https://pub.dev/packages/mono_repo for details -stages: - - analyzer_and_format: - - group: - - format - - analyze: --fatal-infos . - sdk: dev - - unit_test: - # Linux tests: - # Note: `Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &` must be - # run first for Linux. - - group: - - command: Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 & - - test: --exclude-tags=release - sdk: dev - os: - - linux - # Windows tests: - - group: - - test: --exclude-tags=release - sdk: dev - os: - - windows diff --git a/dwds_test_common/pubspec.yaml b/dwds_test_common/pubspec.yaml deleted file mode 100644 index e93dd697fe..0000000000 --- a/dwds_test_common/pubspec.yaml +++ /dev/null @@ -1,17 +0,0 @@ -name: dwds_test_common -publish_to: none -description: >- - Common test functionality. -environment: - sdk: ^3.12.0-0 - -dependencies: - dwds: any - file: ">=6.0.0 <8.0.0" - logging: ^1.0.1 - path: ^1.8.1 - pub_semver: ^2.1.1 - test: ^1.21.1 - -dev_dependencies: - dart_flutter_team_lints: ^3.5.2 diff --git a/dwds_test_common/pubspec_overrides.yaml b/dwds_test_common/pubspec_overrides.yaml deleted file mode 100644 index d3d78b8af0..0000000000 --- a/dwds_test_common/pubspec_overrides.yaml +++ /dev/null @@ -1,3 +0,0 @@ -dependency_overrides: - dwds: - path: ../dwds diff --git a/dwds_test_common/test/sdk_asset_generator_test.dart b/dwds_test_common/test/sdk_asset_generator_test.dart deleted file mode 100644 index 7f7563d2ba..0000000000 --- a/dwds_test_common/test/sdk_asset_generator_test.dart +++ /dev/null @@ -1,171 +0,0 @@ -// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@TestOn('vm') -@Timeout(Duration(minutes: 2)) -library; - -import 'dart:io'; - -import 'package:dwds/expression_compiler.dart'; -import 'package:dwds_test_common/logging.dart'; -import 'package:dwds_test_common/sdk_asset_generator.dart'; -import 'package:dwds_test_common/test_sdk_layout.dart'; -import 'package:test/test.dart'; - -void main() { - group('SDK asset generator', () { - const debug = false; - - late Directory tempDir; - late String sdkDirectory; - late String compilerWorkerPath; - - // Missing assets - late String amdSdkJsPath; - late String amdSdkJsMapPath; - late String ddcSdkJsPath; - late String ddcSdkJsMapPath; - - setUp(() async { - setCurrentLogWriter(debug: debug); - tempDir = Directory.systemTemp.createTempSync(); - - sdkDirectory = tempDir.path; - final copySdkLayout = TestSdkLayout.createDefault(sdkDirectory); - - compilerWorkerPath = copySdkLayout.dartdevcSnapshotPath; - - // Copy the SDK directory into a temp directory. - await copyDirectory(TestSdkLayout.defaultSdkDirectory, sdkDirectory); - - // Simulate missing assets. - amdSdkJsPath = copySdkLayout.amdJsPath; - amdSdkJsMapPath = copySdkLayout.amdJsMapPath; - ddcSdkJsPath = copySdkLayout.ddcJsPath; - ddcSdkJsMapPath = copySdkLayout.ddcJsMapPath; - - _deleteIfExists(amdSdkJsPath); - _deleteIfExists(amdSdkJsMapPath); - _deleteIfExists(ddcSdkJsPath); - _deleteIfExists(ddcSdkJsMapPath); - }); - - tearDown(() { - tempDir.deleteSync(recursive: true); - }); - - test( - 'Can generate missing SDK assets and validate SDK configuration for the ' - 'AMD module system', - () async { - final sdkLayout = TestSdkLayout.createDefault(sdkDirectory); - final configuration = TestSdkLayout.createConfiguration(sdkLayout); - - final assetGenerator = SdkAssetGenerator( - sdkLayout: sdkLayout, - verbose: true, - canaryFeatures: false, - ddcModuleFormat: ModuleFormat.amd, - ); - await assetGenerator.generateSdkAssets(); - - // Make sure SDK configuration and asset generator agree on the file - // paths. - expect(configuration.sdkDirectory, equals(sdkDirectory)); - expect(configuration.compilerWorkerPath, equals(compilerWorkerPath)); - - expect(sdkLayout.amdJsPath, equals(amdSdkJsPath)); - expect(sdkLayout.amdJsMapPath, equals(amdSdkJsMapPath)); - - // Validate that configuration files exist. - configuration.validateSdkDir(); - configuration.validate(); - - // Validate all assets exist. - expect(sdkLayout.amdJsPath, _exists); - expect(sdkLayout.amdJsMapPath, _exists); - }, - ); - - test( - 'Can generate missing SDK assets and validate SDK configuration for the ' - 'DDC module system', - () async { - final sdkLayout = TestSdkLayout.createDefault(sdkDirectory); - final configuration = TestSdkLayout.createConfiguration(sdkLayout); - - final assetGenerator = SdkAssetGenerator( - sdkLayout: sdkLayout, - verbose: true, - canaryFeatures: false, - ddcModuleFormat: ModuleFormat.ddc, - ); - await assetGenerator.generateSdkAssets(); - - // Make sure SDK configuration and asset generator agree on the file - // paths. - expect(configuration.sdkDirectory, equals(sdkDirectory)); - expect(configuration.compilerWorkerPath, equals(compilerWorkerPath)); - - expect(sdkLayout.ddcJsPath, equals(ddcSdkJsPath)); - expect(sdkLayout.ddcJsMapPath, equals(ddcSdkJsMapPath)); - - // Validate that configuration files exist. - configuration.validateSdkDir(); - configuration.validate(); - - // Validate all assets exist. - expect(sdkLayout.ddcJsPath, _exists); - expect(sdkLayout.ddcJsMapPath, _exists); - }, - ); - - test( - 'Can generate missing SDK assets with canary features enabled', - () async { - final sdkLayout = TestSdkLayout.createDefault(sdkDirectory); - - final assetGenerator = SdkAssetGenerator( - sdkLayout: sdkLayout, - verbose: true, - canaryFeatures: true, - ddcModuleFormat: ModuleFormat.amd, - ); - await assetGenerator.generateSdkAssets(); - - final sdk = File(amdSdkJsPath).readAsStringSync(); - expect(sdk, contains('canary')); - }, - ); - - test('Can generate missing SDK assets with canary features enabled for the ' - 'DDC module system', () async { - final sdkLayout = TestSdkLayout.createDefault(sdkDirectory); - - final assetGenerator = SdkAssetGenerator( - sdkLayout: sdkLayout, - verbose: true, - canaryFeatures: true, - ddcModuleFormat: ModuleFormat.ddc, - ); - await assetGenerator.generateSdkAssets(); - - final sdk = File(ddcSdkJsPath).readAsStringSync(); - expect(sdk, contains('canary')); - }); - }); -} - -Matcher _exists = predicate( - (String path) => File(path).existsSync(), - 'File exists', -); - -void _deleteIfExists(String path) { - final file = File(path); - if (file.existsSync()) { - file.deleteSync(); - } -} diff --git a/dwds_test_common/test/test_sdk_configuration_test.dart b/dwds_test_common/test/test_sdk_configuration_test.dart deleted file mode 100644 index 3ff5fddf1b..0000000000 --- a/dwds_test_common/test/test_sdk_configuration_test.dart +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -@TestOn('vm') -@Timeout(Duration(minutes: 2)) -library; - -import 'dart:io'; - -import 'package:dwds/expression_compiler.dart'; -import 'package:dwds_test_common/logging.dart'; -import 'package:dwds_test_common/test_sdk_configuration.dart'; -import 'package:test/test.dart'; - -void main() { - const debug = false; - - group('Test SDK configuration provider |', () { - setUpAll(() { - setCurrentLogWriter(debug: debug); - }); - - test('Creates and deletes SDK directory copy', () async { - final provider = TestSdkConfigurationProvider( - verbose: debug, - ddcModuleFormat: ModuleFormat.amd, - ); - final sdkDirectory = provider.sdkLayout.sdkDirectory; - final sdkSummary = provider.sdkLayout.summaryPath; - try { - expect( - sdkDirectory, - _directoryExists, - reason: 'SDK directory should be created', - ); - expect( - sdkSummary, - isNot(_fileExists), - reason: 'SDK summary should not be generated yet.', - ); - - await provider.configuration; - expect( - sdkSummary, - _fileExists, - reason: 'SDK summary should be generated', - ); - } finally { - provider.dispose(); - expect( - sdkDirectory, - isNot(_directoryExists), - reason: 'SDK directory copy should be deleted on dispose', - ); - } - }); - }); - - group('Test SDK configuration | DDC with DDC modules |', () { - setCurrentLogWriter(debug: debug); - final provider = TestSdkConfigurationProvider( - verbose: debug, - ddcModuleFormat: ModuleFormat.ddc, - ); - tearDownAll(provider.dispose); - - test('Can validate configuration with generated assets', () async { - final sdkConfiguration = await provider.configuration; - sdkConfiguration.validateSdkDir(); - sdkConfiguration.validate(); - }); - - test('SDK layout exists', () async { - await provider.configuration; - final sdkLayout = provider.sdkLayout; - - expect(sdkLayout.sdkDirectory, _directoryExists); - expect(sdkLayout.ddcJsPath, _fileExists); - expect(sdkLayout.ddcJsMapPath, _fileExists); - expect(sdkLayout.summaryPath, _fileExists); - expect(sdkLayout.fullDillPath, _fileExists); - - expect(sdkLayout.ddcModuleLoaderJsPath, _fileExists); - expect(sdkLayout.stackTraceMapperPath, _fileExists); - - expect(sdkLayout.dartPath, _fileExists); - expect(sdkLayout.frontendServerSnapshotPath, _fileExists); - expect(sdkLayout.dartdevcSnapshotPath, _fileExists); - expect(sdkLayout.kernelWorkerSnapshotPath, _fileExists); - expect(sdkLayout.devToolsDirectory, _directoryExists); - }); - }); - - group('Test SDK configuration | DDC with AMD modules |', () { - setCurrentLogWriter(debug: debug); - final provider = TestSdkConfigurationProvider( - verbose: debug, - ddcModuleFormat: ModuleFormat.amd, - ); - tearDownAll(provider.dispose); - - test('Can validate configuration with generated assets', () async { - final sdkConfiguration = await provider.configuration; - sdkConfiguration.validateSdkDir(); - sdkConfiguration.validate(); - }); - - test('SDK layout exists', () async { - await provider.configuration; - final sdkLayout = provider.sdkLayout; - - expect(sdkLayout.sdkDirectory, _directoryExists); - expect(sdkLayout.amdJsPath, _fileExists); - expect(sdkLayout.amdJsMapPath, _fileExists); - expect(sdkLayout.summaryPath, _fileExists); - expect(sdkLayout.fullDillPath, _fileExists); - - expect(sdkLayout.requireJsPath, _fileExists); - expect(sdkLayout.stackTraceMapperPath, _fileExists); - - expect(sdkLayout.dartPath, _fileExists); - expect(sdkLayout.dartAotRuntimePath, _fileExists); - expect(sdkLayout.frontendServerSnapshotPath, _fileExists); - expect(sdkLayout.dartdevcSnapshotPath, _fileExists); - expect(sdkLayout.kernelWorkerSnapshotPath, _fileExists); - expect(sdkLayout.devToolsDirectory, _directoryExists); - }); - }); -} - -Matcher _fileExists = predicate( - (String path) => File(path).existsSync(), - 'File exists', -); - -Matcher _directoryExists = predicate( - (String path) => Directory(path).existsSync(), - 'Directory exists', -); diff --git a/dwds_webdev_integration_test/README.md b/dwds_webdev_integration_test/README.md new file mode 100644 index 0000000000..acb1d56ed3 --- /dev/null +++ b/dwds_webdev_integration_test/README.md @@ -0,0 +1,43 @@ +# DWDS webdev integration tests + +This unpublished package runs DWDS integration tests from webdev. Currently it +runs the shared DWDS integration tests against apps that are built and served +by `build_runner` (through the build daemon). + +`package:dwds` and `package:dwds_test_common` live in the Dart SDK +(`pkg/dwds` and `pkg/dwds_test_common`). This package depends on them through +git `dependency_overrides` pointing at the SDK's `main` branch, so these tests +always run against the latest DWDS. + +## Layout + +- `test/integration/fixtures/build_daemon_context.dart`: The + `BuildDaemonTestContext`, the build daemon counterpart of the SDK's + `FrontendServerTestContext`. +- `test/integration/build_daemon/`: Wrappers that run the shared integration + test scenarios defined in `package:dwds_test_common/integration` with the + `BuildDaemonTestContext`. +- `test/integration/`: Tests that don't need a build context. + +## Running the tests + +The tests require Chrome and a matching version of ChromeDriver. By default +they look for `google-chrome` and `chromedriver` on the `PATH`; set the +`CHROME_EXECUTABLE` and `CHROMEDRIVER_PATH` environment variables to use other +binaries. + +```sh +dart pub upgrade +dart test +``` + +To test against local changes to DWDS, point the `dependency_overrides` at your +Dart SDK checkout in a `pubspec_overrides.yaml` file: + +```yaml +dependency_overrides: + dwds: + path: /pkg/dwds + dwds_test_common: + path: /pkg/dwds_test_common +``` diff --git a/dwds_test_common/analysis_options.yaml b/dwds_webdev_integration_test/analysis_options.yaml similarity index 62% rename from dwds_test_common/analysis_options.yaml rename to dwds_webdev_integration_test/analysis_options.yaml index 3faabb59de..420dc7eeae 100644 --- a/dwds_test_common/analysis_options.yaml +++ b/dwds_webdev_integration_test/analysis_options.yaml @@ -1,5 +1,5 @@ include: package:dart_flutter_team_lints/analysis_options.yaml analyzer: - exclude: - - fixtures/** + errors: + implementation_imports: ignore diff --git a/dwds/dart_test.yaml b/dwds_webdev_integration_test/dart_test.yaml similarity index 100% rename from dwds/dart_test.yaml rename to dwds_webdev_integration_test/dart_test.yaml diff --git a/dwds/mono_pkg.yaml b/dwds_webdev_integration_test/mono_pkg.yaml similarity index 96% rename from dwds/mono_pkg.yaml rename to dwds_webdev_integration_test/mono_pkg.yaml index cf4a65ad7e..739237b12b 100644 --- a/dwds/mono_pkg.yaml +++ b/dwds_webdev_integration_test/mono_pkg.yaml @@ -4,7 +4,6 @@ stages: - group: - format - analyze: --fatal-infos . - - test: test/build/ensure_version_test.dart sdk: dev - unit_test: # Linux extension tests: diff --git a/dwds_webdev_integration_test/pubspec.yaml b/dwds_webdev_integration_test/pubspec.yaml new file mode 100644 index 0000000000..7dd7869278 --- /dev/null +++ b/dwds_webdev_integration_test/pubspec.yaml @@ -0,0 +1,34 @@ +name: dwds_webdev_integration_test +publish_to: none +description: >- + DWDS integration tests run from webdev, e.g. the shared DWDS test suites from + the Dart SDK against apps built with build_runner (via the build daemon). +environment: + sdk: ^3.14.0-286.0.dev + +dev_dependencies: + build_daemon: ^4.1.4 + dart_flutter_team_lints: ^3.5.2 + dwds: any + dwds_test_common: any + http: ^1.0.0 + logging: ^1.0.2 + shelf: ^1.3.0 + shelf_proxy: ^1.0.4 + test: ^1.21.6 + vm_service: ">=14.2.4 <16.0.0" + webkit_inspection_protocol: ^1.0.1 + +# DWDS and its shared test suites live in the Dart SDK. Always test against the +# latest versions there. +dependency_overrides: + dwds: + git: + url: https://github.com/dart-lang/sdk.git + ref: main + path: pkg/dwds + dwds_test_common: + git: + url: https://github.com/dart-lang/sdk.git + ref: main + path: pkg/dwds_test_common diff --git a/dwds_webdev_integration_test/test/integration/build_daemon/README.md b/dwds_webdev_integration_test/test/integration/build_daemon/README.md new file mode 100644 index 0000000000..724dfc04c3 --- /dev/null +++ b/dwds_webdev_integration_test/test/integration/build_daemon/README.md @@ -0,0 +1,5 @@ +# Build Daemon Integration Tests + +The tests in this directory are wrappers around the shared integration test scenarios defined in `package:dwds_test_common/integration`. + +They execute the test scenarios defined there using `build_runner` (via the build daemon) as the build client. diff --git a/dwds/test/integration/breakpoint_amd_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/breakpoint_amd_test.dart similarity index 73% rename from dwds/test/integration/breakpoint_amd_test.dart rename to dwds_webdev_integration_test/test/integration/build_daemon/breakpoint_amd_test.dart index c2b1947a16..1cfc68761a 100644 --- a/dwds/test/integration/breakpoint_amd_test.dart +++ b/dwds_webdev_integration_test/test/integration/build_daemon/breakpoint_amd_test.dart @@ -7,11 +7,11 @@ library; import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/breakpoint.dart'; import 'package:dwds_test_common/test_sdk_configuration.dart'; import 'package:test/test.dart'; -import 'breakpoint_common.dart'; -import 'fixtures/context.dart'; +import '../fixtures/build_daemon_context.dart'; void main() { // Enable verbose logging for debugging. @@ -26,14 +26,7 @@ void main() { group('Build Daemon |', () { testBreakpoint( provider: provider, - compilationMode: CompilationMode.buildDaemon, - ); - }); - - group('Frontend Server |', () { - testBreakpoint( - provider: provider, - compilationMode: CompilationMode.frontendServer, + contextFactory: BuildDaemonTestContext.new, ); }); } diff --git a/dwds/test/integration/breakpoint_ddc_library_bundle_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/breakpoint_ddc_library_bundle_test.dart similarity index 74% rename from dwds/test/integration/breakpoint_ddc_library_bundle_test.dart rename to dwds_webdev_integration_test/test/integration/build_daemon/breakpoint_ddc_library_bundle_test.dart index 71b4606d73..42f061455a 100644 --- a/dwds/test/integration/breakpoint_ddc_library_bundle_test.dart +++ b/dwds_webdev_integration_test/test/integration/build_daemon/breakpoint_ddc_library_bundle_test.dart @@ -7,11 +7,11 @@ library; import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/breakpoint.dart'; import 'package:dwds_test_common/test_sdk_configuration.dart'; import 'package:test/test.dart'; -import 'breakpoint_common.dart'; -import 'fixtures/context.dart'; +import '../fixtures/build_daemon_context.dart'; void main() { // Enable verbose logging for debugging. @@ -27,14 +27,7 @@ void main() { group('Build Daemon |', () { testBreakpoint( provider: provider, - compilationMode: CompilationMode.buildDaemon, - ); - }); - - group('Frontend Server |', () { - testBreakpoint( - provider: provider, - compilationMode: CompilationMode.frontendServer, + contextFactory: BuildDaemonTestContext.new, ); }); } diff --git a/dwds/test/integration/callstack_amd_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/callstack_amd_test.dart similarity index 73% rename from dwds/test/integration/callstack_amd_test.dart rename to dwds_webdev_integration_test/test/integration/build_daemon/callstack_amd_test.dart index e511a65e90..ff271f38e8 100644 --- a/dwds/test/integration/callstack_amd_test.dart +++ b/dwds_webdev_integration_test/test/integration/build_daemon/callstack_amd_test.dart @@ -7,11 +7,11 @@ library; import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/callstack.dart'; import 'package:dwds_test_common/test_sdk_configuration.dart'; import 'package:test/test.dart'; -import 'callstack_common.dart'; -import 'fixtures/context.dart'; +import '../fixtures/build_daemon_context.dart'; void main() { // Enable verbose logging for debugging. @@ -26,14 +26,7 @@ void main() { group('Build Daemon |', () { testCallStack( provider: provider, - compilationMode: CompilationMode.buildDaemon, - ); - }); - - group('Frontend Server |', () { - testCallStack( - provider: provider, - compilationMode: CompilationMode.frontendServer, + contextFactory: BuildDaemonTestContext.new, ); }); } diff --git a/dwds/test/integration/callstack_ddc_library_bundle_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/callstack_ddc_library_bundle_test.dart similarity index 74% rename from dwds/test/integration/callstack_ddc_library_bundle_test.dart rename to dwds_webdev_integration_test/test/integration/build_daemon/callstack_ddc_library_bundle_test.dart index 3344150622..4778e87597 100644 --- a/dwds/test/integration/callstack_ddc_library_bundle_test.dart +++ b/dwds_webdev_integration_test/test/integration/build_daemon/callstack_ddc_library_bundle_test.dart @@ -7,11 +7,11 @@ library; import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/callstack.dart'; import 'package:dwds_test_common/test_sdk_configuration.dart'; import 'package:test/test.dart'; -import 'callstack_common.dart'; -import 'fixtures/context.dart'; +import '../fixtures/build_daemon_context.dart'; void main() { // Enable verbose logging for debugging. @@ -27,14 +27,7 @@ void main() { group('Build Daemon |', () { testCallStack( provider: provider, - compilationMode: CompilationMode.buildDaemon, - ); - }); - - group('Frontend Server |', () { - testCallStack( - provider: provider, - compilationMode: CompilationMode.frontendServer, + contextFactory: BuildDaemonTestContext.new, ); }); } diff --git a/dwds/test/integration/chrome_proxy_service_amd_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/chrome_proxy_service_amd_test.dart similarity index 66% rename from dwds/test/integration/chrome_proxy_service_amd_test.dart rename to dwds_webdev_integration_test/test/integration/build_daemon/chrome_proxy_service_amd_test.dart index fef60fc277..571b78f2e7 100644 --- a/dwds/test/integration/chrome_proxy_service_amd_test.dart +++ b/dwds_webdev_integration_test/test/integration/build_daemon/chrome_proxy_service_amd_test.dart @@ -2,38 +2,35 @@ // 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. -@TestOn('vm') @Tags(['daily']) +@TestOn('vm') @Timeout(Duration(minutes: 2)) library; import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/chrome_proxy_service.dart'; import 'package:dwds_test_common/test_sdk_configuration.dart'; import 'package:test/test.dart'; -import 'common/chrome_proxy_service_common.dart'; -import 'fixtures/context.dart'; +import '../fixtures/build_daemon_context.dart'; void main() { // Enable verbose logging for debugging. const debug = false; final canaryFeatures = false; final moduleFormat = ModuleFormat.amd; - final compilationMode = CompilationMode.buildDaemon; - - final provider = TestSdkConfigurationProvider( - verbose: debug, - canaryFeatures: canaryFeatures, - ddcModuleFormat: moduleFormat, - ); - group('canary: $canaryFeatures |', () { + group('canary: $canaryFeatures | Build Daemon |', () { + final provider = TestSdkConfigurationProvider( + verbose: debug, + canaryFeatures: canaryFeatures, + ddcModuleFormat: moduleFormat, + ); tearDownAll(provider.dispose); - runTests( provider: provider, moduleFormat: moduleFormat, - compilationMode: compilationMode, + contextFactory: BuildDaemonTestContext.new, canaryFeatures: canaryFeatures, ); }); diff --git a/dwds/test/integration/instances/instance_inspection_ddc_library_bundle_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/chrome_proxy_service_ddc_library_bundle_test.dart similarity index 57% rename from dwds/test/integration/instances/instance_inspection_ddc_library_bundle_test.dart rename to dwds_webdev_integration_test/test/integration/build_daemon/chrome_proxy_service_ddc_library_bundle_test.dart index 93e375d548..98296e052f 100644 --- a/dwds/test/integration/instances/instance_inspection_ddc_library_bundle_test.dart +++ b/dwds_webdev_integration_test/test/integration/build_daemon/chrome_proxy_service_ddc_library_bundle_test.dart @@ -1,4 +1,4 @@ -// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. @@ -7,30 +7,30 @@ @Timeout(Duration(minutes: 2)) library; -import 'package:dwds/src/services/expression_compiler.dart'; +import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/chrome_proxy_service.dart'; import 'package:dwds_test_common/test_sdk_configuration.dart'; import 'package:test/test.dart'; -import '../fixtures/context.dart'; -import 'common/instance_inspection_common.dart'; +import '../fixtures/build_daemon_context.dart'; void main() { // Enable verbose logging for debugging. const debug = false; + final canaryFeatures = true; + final moduleFormat = ModuleFormat.ddc; - group('canary: true | Frontend Server |', () { - final canaryFeatures = true; - final compilationMode = CompilationMode.frontendServer; + group('canary: $canaryFeatures | Build Daemon |', () { final provider = TestSdkConfigurationProvider( verbose: debug, canaryFeatures: canaryFeatures, - ddcModuleFormat: ModuleFormat.ddc, + ddcModuleFormat: moduleFormat, ); tearDownAll(provider.dispose); - runTests( provider: provider, - compilationMode: compilationMode, + moduleFormat: moduleFormat, + contextFactory: BuildDaemonTestContext.new, canaryFeatures: canaryFeatures, ); }); diff --git a/dwds_webdev_integration_test/test/integration/build_daemon/circular_evaluate/circular_evaluate_amd_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/circular_evaluate/circular_evaluate_amd_test.dart new file mode 100644 index 0000000000..648d113a2a --- /dev/null +++ b/dwds_webdev_integration_test/test/integration/build_daemon/circular_evaluate/circular_evaluate_amd_test.dart @@ -0,0 +1,30 @@ +// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +@Tags(['daily']) +@TestOn('vm') +@Timeout(Duration(minutes: 5)) +library; + +import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/evaluate_circular.dart'; +import 'package:dwds_test_common/test_sdk_configuration.dart'; +import 'package:test/test.dart'; + +import '../../fixtures/build_daemon_context.dart'; + +void main() { + // Enable verbose logging for debugging. + const debug = false; + + final provider = TestSdkConfigurationProvider( + verbose: debug, + ddcModuleFormat: ModuleFormat.amd, + ); + tearDownAll(provider.dispose); + + group('Build Daemon |', () { + testAll(provider: provider, contextFactory: BuildDaemonTestContext.new); + }); +} diff --git a/dwds_webdev_integration_test/test/integration/build_daemon/circular_evaluate/circular_evaluate_ddc_library_bundle_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/circular_evaluate/circular_evaluate_ddc_library_bundle_test.dart new file mode 100644 index 0000000000..c283c5da18 --- /dev/null +++ b/dwds_webdev_integration_test/test/integration/build_daemon/circular_evaluate/circular_evaluate_ddc_library_bundle_test.dart @@ -0,0 +1,31 @@ +// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +@Tags(['daily']) +@TestOn('vm') +@Timeout(Duration(minutes: 5)) +library; + +import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/evaluate_circular.dart'; +import 'package:dwds_test_common/test_sdk_configuration.dart'; +import 'package:test/test.dart'; + +import '../../fixtures/build_daemon_context.dart'; + +void main() { + // Enable verbose logging for debugging. + const debug = false; + + final provider = TestSdkConfigurationProvider( + verbose: debug, + ddcModuleFormat: ModuleFormat.ddc, + canaryFeatures: true, + ); + tearDownAll(provider.dispose); + + group('Build Daemon |', () { + testAll(provider: provider, contextFactory: BuildDaemonTestContext.new); + }); +} diff --git a/dwds_webdev_integration_test/test/integration/build_daemon/dart_uri_file_uri_debugger_module_names_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/dart_uri_file_uri_debugger_module_names_test.dart new file mode 100644 index 0000000000..00d1415558 --- /dev/null +++ b/dwds_webdev_integration_test/test/integration/build_daemon/dart_uri_file_uri_debugger_module_names_test.dart @@ -0,0 +1,25 @@ +// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +@TestOn('vm') +@Timeout(Duration(minutes: 2)) +library; + +import 'package:dwds_test_common/integration/dart_uri_file_uri_debugger_module_names.dart'; +import 'package:dwds_test_common/test_sdk_configuration.dart'; +import 'package:test/test.dart'; + +import '../fixtures/build_daemon_context.dart'; + +void main() { + // Enable verbose logging for debugging. + const debug = false; + + final provider = TestSdkConfigurationProvider(verbose: debug); + tearDownAll(provider.dispose); + + group('Build Daemon |', () { + testAll(provider: provider, contextFactory: BuildDaemonTestContext.new); + }); +} diff --git a/dwds_webdev_integration_test/test/integration/build_daemon/dart_uri_file_uri_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/dart_uri_file_uri_test.dart new file mode 100644 index 0000000000..a5d459500b --- /dev/null +++ b/dwds_webdev_integration_test/test/integration/build_daemon/dart_uri_file_uri_test.dart @@ -0,0 +1,25 @@ +// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +@TestOn('vm') +@Timeout(Duration(minutes: 2)) +library; + +import 'package:dwds_test_common/integration/dart_uri_file_uri.dart'; +import 'package:dwds_test_common/test_sdk_configuration.dart'; +import 'package:test/test.dart'; + +import '../fixtures/build_daemon_context.dart'; + +void main() { + // Enable verbose logging for debugging. + const debug = false; + + final provider = TestSdkConfigurationProvider(verbose: debug); + tearDownAll(provider.dispose); + + group('Build Daemon |', () { + testAll(provider: provider, contextFactory: BuildDaemonTestContext.new); + }); +} diff --git a/dwds_webdev_integration_test/test/integration/build_daemon/dds_port_amd_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/dds_port_amd_test.dart new file mode 100644 index 0000000000..a8c6cda190 --- /dev/null +++ b/dwds_webdev_integration_test/test/integration/build_daemon/dds_port_amd_test.dart @@ -0,0 +1,27 @@ +// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +@TestOn('vm') +@Timeout(Duration(minutes: 2)) +library; + +import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/dds_port.dart'; +import 'package:dwds_test_common/test_sdk_configuration.dart'; +import 'package:test/test.dart'; + +import '../fixtures/build_daemon_context.dart'; + +void main() { + // Enable verbose logging for debugging. + const debug = false; + + final provider = TestSdkConfigurationProvider( + verbose: debug, + ddcModuleFormat: ModuleFormat.amd, + ); + tearDownAll(provider.dispose); + + testAll(provider: provider, contextFactory: BuildDaemonTestContext.new); +} diff --git a/dwds/test/integration/dds_port_ddc_library_bundle_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/dds_port_ddc_library_bundle_test.dart similarity index 75% rename from dwds/test/integration/dds_port_ddc_library_bundle_test.dart rename to dwds_webdev_integration_test/test/integration/build_daemon/dds_port_ddc_library_bundle_test.dart index f8125a3e85..3049f74e52 100644 --- a/dwds/test/integration/dds_port_ddc_library_bundle_test.dart +++ b/dwds_webdev_integration_test/test/integration/build_daemon/dds_port_ddc_library_bundle_test.dart @@ -7,22 +7,22 @@ library; import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/dds_port.dart'; import 'package:dwds_test_common/test_sdk_configuration.dart'; import 'package:test/test.dart'; -import 'dds_port_common.dart'; +import '../fixtures/build_daemon_context.dart'; void main() { // Enable verbose logging for debugging. const debug = false; - final canary = true; final provider = TestSdkConfigurationProvider( verbose: debug, - canaryFeatures: canary, ddcModuleFormat: ModuleFormat.ddc, + canaryFeatures: true, ); tearDownAll(provider.dispose); - testAll(provider: provider); + testAll(provider: provider, contextFactory: BuildDaemonTestContext.new); } diff --git a/dwds_webdev_integration_test/test/integration/build_daemon/debug_service_amd_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/debug_service_amd_test.dart new file mode 100644 index 0000000000..4ab7213977 --- /dev/null +++ b/dwds_webdev_integration_test/test/integration/build_daemon/debug_service_amd_test.dart @@ -0,0 +1,27 @@ +// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +@TestOn('vm') +@Timeout(Duration(minutes: 2)) +library; + +import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/debug_service.dart'; +import 'package:dwds_test_common/test_sdk_configuration.dart'; +import 'package:test/test.dart'; + +import '../fixtures/build_daemon_context.dart'; + +void main() { + // Enable verbose logging for debugging. + const debug = false; + + final provider = TestSdkConfigurationProvider( + verbose: debug, + ddcModuleFormat: ModuleFormat.amd, + ); + tearDownAll(provider.dispose); + + testAll(provider: provider, contextFactory: BuildDaemonTestContext.new); +} diff --git a/dwds/test/integration/screenshot_ddc_library_bundle_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/debug_service_ddc_library_bundle_test.dart similarity index 73% rename from dwds/test/integration/screenshot_ddc_library_bundle_test.dart rename to dwds_webdev_integration_test/test/integration/build_daemon/debug_service_ddc_library_bundle_test.dart index 0fc43cb1b0..25121d458c 100644 --- a/dwds/test/integration/screenshot_ddc_library_bundle_test.dart +++ b/dwds_webdev_integration_test/test/integration/build_daemon/debug_service_ddc_library_bundle_test.dart @@ -2,26 +2,27 @@ // 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. +@TestOn('vm') @Timeout(Duration(minutes: 2)) library; import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/debug_service.dart'; import 'package:dwds_test_common/test_sdk_configuration.dart'; import 'package:test/test.dart'; -import 'screenshot_common.dart'; +import '../fixtures/build_daemon_context.dart'; void main() { // Enable verbose logging for debugging. const debug = false; - final canary = true; final provider = TestSdkConfigurationProvider( verbose: debug, - canaryFeatures: canary, ddcModuleFormat: ModuleFormat.ddc, + canaryFeatures: true, ); tearDownAll(provider.dispose); - testAll(provider: provider); + testAll(provider: provider, contextFactory: BuildDaemonTestContext.new); } diff --git a/dwds/test/integration/devtools_amd_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/devtools_amd_test.dart similarity index 67% rename from dwds/test/integration/devtools_amd_test.dart rename to dwds_webdev_integration_test/test/integration/build_daemon/devtools_amd_test.dart index 1ce6a598fa..5f35e92eb4 100644 --- a/dwds/test/integration/devtools_amd_test.dart +++ b/dwds_webdev_integration_test/test/integration/build_daemon/devtools_amd_test.dart @@ -2,21 +2,26 @@ // 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. -@Timeout(Duration(minutes: 5)) @TestOn('vm') +@Timeout(Duration(minutes: 5)) library; import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/devtools.dart'; import 'package:dwds_test_common/test_sdk_configuration.dart'; import 'package:test/test.dart'; -import 'devtools_common.dart'; +import '../fixtures/build_daemon_context.dart'; void main() { + // Enable verbose logging for debugging. + const debug = false; + final provider = TestSdkConfigurationProvider( + verbose: debug, ddcModuleFormat: ModuleFormat.amd, ); tearDownAll(provider.dispose); - testAll(provider: provider); + testAll(provider: provider, contextFactory: BuildDaemonTestContext.new); } diff --git a/dwds_webdev_integration_test/test/integration/build_daemon/devtools_ddc_library_bundle_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/devtools_ddc_library_bundle_test.dart new file mode 100644 index 0000000000..7fce4ad90f --- /dev/null +++ b/dwds_webdev_integration_test/test/integration/build_daemon/devtools_ddc_library_bundle_test.dart @@ -0,0 +1,28 @@ +// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +@TestOn('vm') +@Timeout(Duration(minutes: 5)) +library; + +import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/devtools.dart'; +import 'package:dwds_test_common/test_sdk_configuration.dart'; +import 'package:test/test.dart'; + +import '../fixtures/build_daemon_context.dart'; + +void main() { + // Enable verbose logging for debugging. + const debug = false; + + final provider = TestSdkConfigurationProvider( + verbose: debug, + ddcModuleFormat: ModuleFormat.ddc, + canaryFeatures: true, + ); + tearDownAll(provider.dispose); + + testAll(provider: provider, contextFactory: BuildDaemonTestContext.new); +} diff --git a/dwds_webdev_integration_test/test/integration/build_daemon/evaluate/evaluate_amd_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/evaluate/evaluate_amd_test.dart new file mode 100644 index 0000000000..b3cb49aacc --- /dev/null +++ b/dwds_webdev_integration_test/test/integration/build_daemon/evaluate/evaluate_amd_test.dart @@ -0,0 +1,30 @@ +// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +@Tags(['daily']) +@TestOn('vm') +@Timeout(Duration(minutes: 5)) +library; + +import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/evaluate.dart'; +import 'package:dwds_test_common/test_sdk_configuration.dart'; +import 'package:test/test.dart'; + +import '../../fixtures/build_daemon_context.dart'; + +void main() { + // Enable verbose logging for debugging. + const debug = false; + + final provider = TestSdkConfigurationProvider( + verbose: debug, + ddcModuleFormat: ModuleFormat.amd, + ); + tearDownAll(provider.dispose); + + group('Build Daemon |', () { + testAll(provider: provider, contextFactory: BuildDaemonTestContext.new); + }); +} diff --git a/dwds/test/integration/hot_reload_breakpoints_ddc_library_bundle_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/evaluate/evaluate_ddc_library_bundle_test.dart similarity index 76% rename from dwds/test/integration/hot_reload_breakpoints_ddc_library_bundle_test.dart rename to dwds_webdev_integration_test/test/integration/build_daemon/evaluate/evaluate_ddc_library_bundle_test.dart index d0494e7400..04a01151f6 100644 --- a/dwds/test/integration/hot_reload_breakpoints_ddc_library_bundle_test.dart +++ b/dwds_webdev_integration_test/test/integration/build_daemon/evaluate/evaluate_ddc_library_bundle_test.dart @@ -8,27 +8,24 @@ library; import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/evaluate.dart'; import 'package:dwds_test_common/test_sdk_configuration.dart'; import 'package:test/test.dart'; -import 'fixtures/context.dart'; -import 'hot_reload_breakpoints_common.dart'; +import '../../fixtures/build_daemon_context.dart'; void main() { // Enable verbose logging for debugging. const debug = false; + final provider = TestSdkConfigurationProvider( verbose: debug, - canaryFeatures: true, ddcModuleFormat: ModuleFormat.ddc, + canaryFeatures: true, ); - tearDownAll(provider.dispose); - group('Frontend Server', () { - runTests( - provider: provider, - compilationMode: CompilationMode.frontendServer, - ); + group('Build Daemon |', () { + testAll(provider: provider, contextFactory: BuildDaemonTestContext.new); }); } diff --git a/dwds_webdev_integration_test/test/integration/build_daemon/events_amd_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/events_amd_test.dart new file mode 100644 index 0000000000..995442abc8 --- /dev/null +++ b/dwds_webdev_integration_test/test/integration/build_daemon/events_amd_test.dart @@ -0,0 +1,32 @@ +// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +@TestOn('vm') +@Timeout(Duration(minutes: 2)) +library; + +import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/events.dart'; +import 'package:dwds_test_common/test_sdk_configuration.dart'; +import 'package:test/test.dart'; + +import '../fixtures/build_daemon_context.dart'; + +void main() { + // Enable verbose logging for debugging. + const debug = false; + + final provider = TestSdkConfigurationProvider( + verbose: debug, + ddcModuleFormat: ModuleFormat.amd, + ); + tearDownAll(provider.dispose); + + group('Build Daemon', () { + testWithDwds( + provider: provider, + contextFactory: BuildDaemonTestContext.new, + ); + }); +} diff --git a/dwds/test/integration/events_ddc_library_bundle_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/events_ddc_library_bundle_test.dart similarity index 70% rename from dwds/test/integration/events_ddc_library_bundle_test.dart rename to dwds_webdev_integration_test/test/integration/build_daemon/events_ddc_library_bundle_test.dart index 4f850e22a6..a7537ee0cd 100644 --- a/dwds/test/integration/events_ddc_library_bundle_test.dart +++ b/dwds_webdev_integration_test/test/integration/build_daemon/events_ddc_library_bundle_test.dart @@ -2,38 +2,32 @@ // 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. +@TestOn('vm') @Timeout(Duration(minutes: 2)) library; import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/events.dart'; import 'package:dwds_test_common/test_sdk_configuration.dart'; import 'package:test/test.dart'; -import 'events_common.dart'; -import 'fixtures/context.dart'; +import '../fixtures/build_daemon_context.dart'; void main() { // Enable verbose logging for debugging. const debug = false; - final canary = true; + final provider = TestSdkConfigurationProvider( verbose: debug, - canaryFeatures: canary, ddcModuleFormat: ModuleFormat.ddc, + canaryFeatures: true, ); tearDownAll(provider.dispose); - group('Frontend Server', () { - testWithDwds( - provider: provider, - compilationMode: CompilationMode.frontendServer, - ); - }); - group('Build Daemon', () { testWithDwds( provider: provider, - compilationMode: CompilationMode.buildDaemon, + contextFactory: BuildDaemonTestContext.new, ); }); } diff --git a/dwds_webdev_integration_test/test/integration/build_daemon/handlers/asset_handler_amd_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/handlers/asset_handler_amd_test.dart new file mode 100644 index 0000000000..9a0bc288fb --- /dev/null +++ b/dwds_webdev_integration_test/test/integration/build_daemon/handlers/asset_handler_amd_test.dart @@ -0,0 +1,27 @@ +// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +@TestOn('vm') +@Timeout(Duration(minutes: 2)) +library; + +import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/asset_handler.dart'; +import 'package:dwds_test_common/test_sdk_configuration.dart'; +import 'package:test/test.dart'; + +import '../../fixtures/build_daemon_context.dart'; + +void main() { + // Enable verbose logging for debugging. + const debug = false; + + final provider = TestSdkConfigurationProvider( + verbose: debug, + ddcModuleFormat: ModuleFormat.amd, + ); + tearDownAll(provider.dispose); + + testAll(provider: provider, contextFactory: BuildDaemonTestContext.new); +} diff --git a/dwds/test/integration/handlers/asset_handler_ddc_library_bundle_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/handlers/asset_handler_ddc_library_bundle_test.dart similarity index 73% rename from dwds/test/integration/handlers/asset_handler_ddc_library_bundle_test.dart rename to dwds_webdev_integration_test/test/integration/build_daemon/handlers/asset_handler_ddc_library_bundle_test.dart index dbfe9835f4..82794a420b 100644 --- a/dwds/test/integration/handlers/asset_handler_ddc_library_bundle_test.dart +++ b/dwds_webdev_integration_test/test/integration/build_daemon/handlers/asset_handler_ddc_library_bundle_test.dart @@ -2,25 +2,27 @@ // 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. +@TestOn('vm') @Timeout(Duration(minutes: 2)) library; import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/asset_handler.dart'; import 'package:dwds_test_common/test_sdk_configuration.dart'; import 'package:test/test.dart'; -import 'asset_handler_common.dart'; +import '../../fixtures/build_daemon_context.dart'; void main() { // Enable verbose logging for debugging. const debug = false; - final canary = true; + final provider = TestSdkConfigurationProvider( verbose: debug, - canaryFeatures: canary, ddcModuleFormat: ModuleFormat.ddc, + canaryFeatures: true, ); tearDownAll(provider.dispose); - testAll(provider: provider); + testAll(provider: provider, contextFactory: BuildDaemonTestContext.new); } diff --git a/dwds_webdev_integration_test/test/integration/build_daemon/hot_restart_amd_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/hot_restart_amd_test.dart new file mode 100644 index 0000000000..52cb6a6705 --- /dev/null +++ b/dwds_webdev_integration_test/test/integration/build_daemon/hot_restart_amd_test.dart @@ -0,0 +1,36 @@ +// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +@Tags(['daily']) +@TestOn('vm') +@Timeout(Duration(minutes: 2)) +library; + +import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/hot_restart.dart'; +import 'package:dwds_test_common/test_sdk_configuration.dart'; +import 'package:test/test.dart'; + +import '../fixtures/build_daemon_context.dart'; + +void main() { + // Enable verbose logging for debugging. + const debug = false; + final canaryFeatures = false; + final moduleFormat = ModuleFormat.amd; + + group('canary: $canaryFeatures | Build Daemon |', () { + final provider = TestSdkConfigurationProvider( + verbose: debug, + canaryFeatures: canaryFeatures, + ddcModuleFormat: moduleFormat, + ); + runTests( + provider: provider, + moduleFormat: moduleFormat, + contextFactory: BuildDaemonTestContext.new, + canaryFeatures: canaryFeatures, + ); + }); +} diff --git a/dwds/test/integration/hot_restart_breakpoints_ddc_library_bundle_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/hot_restart_breakpoints_ddc_library_bundle_test.dart similarity index 70% rename from dwds/test/integration/hot_restart_breakpoints_ddc_library_bundle_test.dart rename to dwds_webdev_integration_test/test/integration/build_daemon/hot_restart_breakpoints_ddc_library_bundle_test.dart index 364a4112d4..b86c5d6a64 100644 --- a/dwds/test/integration/hot_restart_breakpoints_ddc_library_bundle_test.dart +++ b/dwds_webdev_integration_test/test/integration/build_daemon/hot_restart_breakpoints_ddc_library_bundle_test.dart @@ -8,31 +8,24 @@ library; import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/hot_restart_breakpoints.dart'; import 'package:dwds_test_common/test_sdk_configuration.dart'; import 'package:test/test.dart'; -import 'fixtures/context.dart'; -import 'hot_restart_breakpoints_common.dart'; +import '../fixtures/build_daemon_context.dart'; void main() { // Enable verbose logging for debugging. const debug = false; + final provider = TestSdkConfigurationProvider( verbose: debug, - canaryFeatures: true, ddcModuleFormat: ModuleFormat.ddc, + canaryFeatures: true, ); - tearDownAll(provider.dispose); - group('Frontend Server', () { - runTests( - provider: provider, - compilationMode: CompilationMode.frontendServer, - ); - }); - group('Build Daemon', () { - runTests(provider: provider, compilationMode: CompilationMode.buildDaemon); + runTests(provider: provider, contextFactory: BuildDaemonTestContext.new); }); } diff --git a/dwds_webdev_integration_test/test/integration/build_daemon/hot_restart_correctness_amd_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/hot_restart_correctness_amd_test.dart new file mode 100644 index 0000000000..bd3cad2073 --- /dev/null +++ b/dwds_webdev_integration_test/test/integration/build_daemon/hot_restart_correctness_amd_test.dart @@ -0,0 +1,36 @@ +// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +@Tags(['daily']) +@TestOn('vm') +@Timeout(Duration(minutes: 2)) +library; + +import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/hot_restart_correctness.dart'; +import 'package:dwds_test_common/test_sdk_configuration.dart'; +import 'package:test/test.dart'; + +import '../fixtures/build_daemon_context.dart'; + +void main() { + // Enable verbose logging for debugging. + const debug = false; + final canaryFeatures = false; + final moduleFormat = ModuleFormat.amd; + + group('canary: $canaryFeatures | Build Daemon |', () { + final provider = TestSdkConfigurationProvider( + verbose: debug, + canaryFeatures: canaryFeatures, + ddcModuleFormat: moduleFormat, + ); + runTests( + provider: provider, + moduleFormat: moduleFormat, + contextFactory: BuildDaemonTestContext.new, + canaryFeatures: canaryFeatures, + ); + }); +} diff --git a/dwds/test/integration/hot_restart_correctness_ddc_library_bundle_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/hot_restart_correctness_ddc_library_bundle_test.dart similarity index 55% rename from dwds/test/integration/hot_restart_correctness_ddc_library_bundle_test.dart rename to dwds_webdev_integration_test/test/integration/build_daemon/hot_restart_correctness_ddc_library_bundle_test.dart index f5a1f6839f..f125aff91d 100644 --- a/dwds/test/integration/hot_restart_correctness_ddc_library_bundle_test.dart +++ b/dwds_webdev_integration_test/test/integration/build_daemon/hot_restart_correctness_ddc_library_bundle_test.dart @@ -1,18 +1,18 @@ -// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file +// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. -@TestOn('vm') @Tags(['daily']) +@TestOn('vm') @Timeout(Duration(minutes: 2)) library; import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/hot_restart_correctness.dart'; import 'package:dwds_test_common/test_sdk_configuration.dart'; import 'package:test/test.dart'; -import 'common/hot_restart_correctness_common.dart'; -import 'fixtures/context.dart'; +import '../fixtures/build_daemon_context.dart'; void main() { // Enable verbose logging for debugging. @@ -20,32 +20,16 @@ void main() { final canaryFeatures = true; final moduleFormat = ModuleFormat.ddc; - group('canary: $canaryFeatures | Frontend Server |', () { - final provider = TestSdkConfigurationProvider( - verbose: debug, - canaryFeatures: canaryFeatures, - ddcModuleFormat: moduleFormat, - ); - final compilationMode = CompilationMode.frontendServer; - runTests( - provider: provider, - moduleFormat: moduleFormat, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); - group('canary: $canaryFeatures | Build Daemon |', () { final provider = TestSdkConfigurationProvider( verbose: debug, canaryFeatures: canaryFeatures, ddcModuleFormat: moduleFormat, ); - final compilationMode = CompilationMode.buildDaemon; runTests( provider: provider, moduleFormat: moduleFormat, - compilationMode: compilationMode, + contextFactory: BuildDaemonTestContext.new, canaryFeatures: canaryFeatures, ); }); diff --git a/dwds/test/integration/hot_restart_ddc_library_bundle_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/hot_restart_ddc_library_bundle_test.dart similarity index 56% rename from dwds/test/integration/hot_restart_ddc_library_bundle_test.dart rename to dwds_webdev_integration_test/test/integration/build_daemon/hot_restart_ddc_library_bundle_test.dart index dacc2f86e7..1aa9dfa395 100644 --- a/dwds/test/integration/hot_restart_ddc_library_bundle_test.dart +++ b/dwds_webdev_integration_test/test/integration/build_daemon/hot_restart_ddc_library_bundle_test.dart @@ -1,18 +1,18 @@ -// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file +// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. -@TestOn('vm') @Tags(['daily']) +@TestOn('vm') @Timeout(Duration(minutes: 2)) library; import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/hot_restart.dart'; import 'package:dwds_test_common/test_sdk_configuration.dart'; import 'package:test/test.dart'; -import 'common/hot_restart_common.dart'; -import 'fixtures/context.dart'; +import '../fixtures/build_daemon_context.dart'; void main() { // Enable verbose logging for debugging. @@ -20,34 +20,16 @@ void main() { final canaryFeatures = true; final moduleFormat = ModuleFormat.ddc; - group('canary: $canaryFeatures | Frontend Server |', () { - final compilationMode = CompilationMode.frontendServer; - final provider = TestSdkConfigurationProvider( - verbose: debug, - canaryFeatures: canaryFeatures, - ddcModuleFormat: moduleFormat, - ); - - runTests( - provider: provider, - moduleFormat: moduleFormat, - compilationMode: compilationMode, - canaryFeatures: canaryFeatures, - ); - }); - group('canary: $canaryFeatures | Build Daemon |', () { - final compilationMode = CompilationMode.buildDaemon; final provider = TestSdkConfigurationProvider( verbose: debug, canaryFeatures: canaryFeatures, ddcModuleFormat: moduleFormat, ); - runTests( provider: provider, moduleFormat: moduleFormat, - compilationMode: compilationMode, + contextFactory: BuildDaemonTestContext.new, canaryFeatures: canaryFeatures, ); }); diff --git a/dwds/test/integration/debug_service_amd_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/inspector_test.dart similarity index 74% rename from dwds/test/integration/debug_service_amd_test.dart rename to dwds_webdev_integration_test/test/integration/build_daemon/inspector_test.dart index c9b17f24ea..5b24cc3b28 100644 --- a/dwds/test/integration/debug_service_amd_test.dart +++ b/dwds_webdev_integration_test/test/integration/build_daemon/inspector_test.dart @@ -6,16 +6,18 @@ @Timeout(Duration(minutes: 2)) library; +import 'package:dwds_test_common/integration/inspector.dart'; import 'package:dwds_test_common/test_sdk_configuration.dart'; import 'package:test/test.dart'; -import 'debug_service_common.dart'; +import '../fixtures/build_daemon_context.dart'; void main() { // Enable verbose logging for debugging. const debug = false; + final provider = TestSdkConfigurationProvider(verbose: debug); tearDownAll(provider.dispose); - testAll(provider: provider); + runTests(provider: provider, contextFactory: BuildDaemonTestContext.new); } diff --git a/dwds_webdev_integration_test/test/integration/build_daemon/instances/class_inspection_amd_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/instances/class_inspection_amd_test.dart new file mode 100644 index 0000000000..d82aa1e54f --- /dev/null +++ b/dwds_webdev_integration_test/test/integration/build_daemon/instances/class_inspection_amd_test.dart @@ -0,0 +1,37 @@ +// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +@Tags(['daily']) +@TestOn('vm') +@Timeout(Duration(minutes: 2)) +library; + +import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/class_inspection.dart'; +import 'package:dwds_test_common/test_sdk_configuration.dart'; +import 'package:test/test.dart'; + +import '../../fixtures/build_daemon_context.dart'; + +void main() { + // Enable verbose logging for debugging. + const debug = false; + + for (final canaryFeatures in [false, true]) { + group('canary: $canaryFeatures | Build Daemon |', () { + final provider = TestSdkConfigurationProvider( + verbose: debug, + canaryFeatures: canaryFeatures, + ddcModuleFormat: ModuleFormat.amd, + ); + tearDownAll(provider.dispose); + + runTests( + provider: provider, + contextFactory: BuildDaemonTestContext.new, + canaryFeatures: canaryFeatures, + ); + }); + } +} diff --git a/dwds_webdev_integration_test/test/integration/build_daemon/instances/class_inspection_ddc_library_bundle_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/instances/class_inspection_ddc_library_bundle_test.dart new file mode 100644 index 0000000000..72e4242754 --- /dev/null +++ b/dwds_webdev_integration_test/test/integration/build_daemon/instances/class_inspection_ddc_library_bundle_test.dart @@ -0,0 +1,37 @@ +// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +@Tags(['daily']) +@TestOn('vm') +@Timeout(Duration(minutes: 2)) +library; + +import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/class_inspection.dart'; +import 'package:dwds_test_common/test_sdk_configuration.dart'; +import 'package:test/test.dart'; + +import '../../fixtures/build_daemon_context.dart'; + +void main() { + // Enable verbose logging for debugging. + const debug = false; + + for (final canaryFeatures in [true]) { + group('canary: $canaryFeatures | Build Daemon |', () { + final provider = TestSdkConfigurationProvider( + verbose: debug, + canaryFeatures: canaryFeatures, + ddcModuleFormat: ModuleFormat.ddc, + ); + tearDownAll(provider.dispose); + + runTests( + provider: provider, + contextFactory: BuildDaemonTestContext.new, + canaryFeatures: canaryFeatures, + ); + }); + } +} diff --git a/dwds_webdev_integration_test/test/integration/build_daemon/instances/dot_shorthands_amd_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/instances/dot_shorthands_amd_test.dart new file mode 100644 index 0000000000..0602664f56 --- /dev/null +++ b/dwds_webdev_integration_test/test/integration/build_daemon/instances/dot_shorthands_amd_test.dart @@ -0,0 +1,37 @@ +// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +@Tags(['daily']) +@TestOn('vm') +@Timeout(Duration(minutes: 2)) +library; + +import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/dot_shorthands.dart'; +import 'package:dwds_test_common/test_sdk_configuration.dart'; +import 'package:test/test.dart'; + +import '../../fixtures/build_daemon_context.dart'; + +void main() { + // Enable verbose logging for debugging. + const debug = false; + + for (final canaryFeatures in [false, true]) { + group('canary: $canaryFeatures | Build Daemon |', () { + final provider = TestSdkConfigurationProvider( + verbose: debug, + canaryFeatures: canaryFeatures, + ddcModuleFormat: ModuleFormat.amd, + ); + tearDownAll(provider.dispose); + + runTests( + provider: provider, + contextFactory: BuildDaemonTestContext.new, + canaryFeatures: canaryFeatures, + ); + }); + } +} diff --git a/dwds_webdev_integration_test/test/integration/build_daemon/instances/dot_shorthands_ddc_library_bundle_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/instances/dot_shorthands_ddc_library_bundle_test.dart new file mode 100644 index 0000000000..9b3b95446f --- /dev/null +++ b/dwds_webdev_integration_test/test/integration/build_daemon/instances/dot_shorthands_ddc_library_bundle_test.dart @@ -0,0 +1,37 @@ +// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +@Tags(['daily']) +@TestOn('vm') +@Timeout(Duration(minutes: 2)) +library; + +import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/dot_shorthands.dart'; +import 'package:dwds_test_common/test_sdk_configuration.dart'; +import 'package:test/test.dart'; + +import '../../fixtures/build_daemon_context.dart'; + +void main() { + // Enable verbose logging for debugging. + const debug = false; + + for (final canaryFeatures in [true]) { + group('canary: $canaryFeatures | Build Daemon |', () { + final provider = TestSdkConfigurationProvider( + verbose: debug, + canaryFeatures: canaryFeatures, + ddcModuleFormat: ModuleFormat.ddc, + ); + tearDownAll(provider.dispose); + + runTests( + provider: provider, + contextFactory: BuildDaemonTestContext.new, + canaryFeatures: canaryFeatures, + ); + }); + } +} diff --git a/dwds_webdev_integration_test/test/integration/build_daemon/instances/instance_amd_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/instances/instance_amd_test.dart new file mode 100644 index 0000000000..139dd186af --- /dev/null +++ b/dwds_webdev_integration_test/test/integration/build_daemon/instances/instance_amd_test.dart @@ -0,0 +1,42 @@ +// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +@Tags(['daily']) +@TestOn('vm') +@Timeout(Duration(minutes: 2)) +library; + +import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/instance.dart'; +import 'package:dwds_test_common/test_sdk_configuration.dart'; +import 'package:test/test.dart'; + +import '../../fixtures/build_daemon_context.dart'; + +void main() { + // Enable verbose logging for debugging. + const debug = false; + + for (final canaryFeatures in [false, true]) { + group('canary: $canaryFeatures | Build Daemon |', () { + final provider = TestSdkConfigurationProvider( + verbose: debug, + canaryFeatures: canaryFeatures, + ddcModuleFormat: ModuleFormat.amd, + ); + tearDownAll(provider.dispose); + + runTypeSystemVerificationTests( + provider: provider, + contextFactory: BuildDaemonTestContext.new, + canaryFeatures: canaryFeatures, + ); + runTests( + provider: provider, + contextFactory: BuildDaemonTestContext.new, + canaryFeatures: canaryFeatures, + ); + }); + } +} diff --git a/dwds_webdev_integration_test/test/integration/build_daemon/instances/instance_ddc_library_bundle_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/instances/instance_ddc_library_bundle_test.dart new file mode 100644 index 0000000000..df21ef3b57 --- /dev/null +++ b/dwds_webdev_integration_test/test/integration/build_daemon/instances/instance_ddc_library_bundle_test.dart @@ -0,0 +1,37 @@ +// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +@Tags(['daily']) +@TestOn('vm') +@Timeout(Duration(minutes: 2)) +library; + +import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/instance.dart'; +import 'package:dwds_test_common/test_sdk_configuration.dart'; +import 'package:test/test.dart'; + +import '../../fixtures/build_daemon_context.dart'; + +void main() { + // Enable verbose logging for debugging. + const debug = false; + + for (final canaryFeatures in [true]) { + group('canary: $canaryFeatures | Build Daemon |', () { + final provider = TestSdkConfigurationProvider( + verbose: debug, + canaryFeatures: canaryFeatures, + ddcModuleFormat: ModuleFormat.ddc, + ); + tearDownAll(provider.dispose); + + runTests( + provider: provider, + contextFactory: BuildDaemonTestContext.new, + canaryFeatures: canaryFeatures, + ); + }); + } +} diff --git a/dwds_webdev_integration_test/test/integration/build_daemon/instances/instance_inspection_amd_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/instances/instance_inspection_amd_test.dart new file mode 100644 index 0000000000..3ecf865bad --- /dev/null +++ b/dwds_webdev_integration_test/test/integration/build_daemon/instances/instance_inspection_amd_test.dart @@ -0,0 +1,37 @@ +// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +@Tags(['daily']) +@TestOn('vm') +@Timeout(Duration(minutes: 2)) +library; + +import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/instance_inspection.dart'; +import 'package:dwds_test_common/test_sdk_configuration.dart'; +import 'package:test/test.dart'; + +import '../../fixtures/build_daemon_context.dart'; + +void main() { + // Enable verbose logging for debugging. + const debug = false; + + for (final canaryFeatures in [false, true]) { + group('canary: $canaryFeatures | Build Daemon |', () { + final provider = TestSdkConfigurationProvider( + verbose: debug, + canaryFeatures: canaryFeatures, + ddcModuleFormat: ModuleFormat.amd, + ); + tearDownAll(provider.dispose); + + runTests( + provider: provider, + contextFactory: BuildDaemonTestContext.new, + canaryFeatures: canaryFeatures, + ); + }); + } +} diff --git a/dwds_webdev_integration_test/test/integration/build_daemon/instances/patterns_inspection_amd_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/instances/patterns_inspection_amd_test.dart new file mode 100644 index 0000000000..daddea948d --- /dev/null +++ b/dwds_webdev_integration_test/test/integration/build_daemon/instances/patterns_inspection_amd_test.dart @@ -0,0 +1,37 @@ +// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +@Tags(['daily']) +@TestOn('vm') +@Timeout(Duration(minutes: 2)) +library; + +import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/patterns_inspection.dart'; +import 'package:dwds_test_common/test_sdk_configuration.dart'; +import 'package:test/test.dart'; + +import '../../fixtures/build_daemon_context.dart'; + +void main() { + // Enable verbose logging for debugging. + const debug = false; + + for (final canaryFeatures in [false, true]) { + group('canary: $canaryFeatures | Build Daemon |', () { + final provider = TestSdkConfigurationProvider( + verbose: debug, + canaryFeatures: canaryFeatures, + ddcModuleFormat: ModuleFormat.amd, + ); + tearDownAll(provider.dispose); + + runTests( + provider: provider, + contextFactory: BuildDaemonTestContext.new, + canaryFeatures: canaryFeatures, + ); + }); + } +} diff --git a/dwds_webdev_integration_test/test/integration/build_daemon/instances/patterns_inspection_ddc_library_bundle_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/instances/patterns_inspection_ddc_library_bundle_test.dart new file mode 100644 index 0000000000..cdc4ab37ad --- /dev/null +++ b/dwds_webdev_integration_test/test/integration/build_daemon/instances/patterns_inspection_ddc_library_bundle_test.dart @@ -0,0 +1,37 @@ +// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +@Tags(['daily']) +@TestOn('vm') +@Timeout(Duration(minutes: 2)) +library; + +import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/patterns_inspection.dart'; +import 'package:dwds_test_common/test_sdk_configuration.dart'; +import 'package:test/test.dart'; + +import '../../fixtures/build_daemon_context.dart'; + +void main() { + // Enable verbose logging for debugging. + const debug = false; + + for (final canaryFeatures in [true]) { + group('canary: $canaryFeatures | Build Daemon |', () { + final provider = TestSdkConfigurationProvider( + verbose: debug, + canaryFeatures: canaryFeatures, + ddcModuleFormat: ModuleFormat.ddc, + ); + tearDownAll(provider.dispose); + + runTests( + provider: provider, + contextFactory: BuildDaemonTestContext.new, + canaryFeatures: canaryFeatures, + ); + }); + } +} diff --git a/dwds_webdev_integration_test/test/integration/build_daemon/instances/record_inspection_amd_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/instances/record_inspection_amd_test.dart new file mode 100644 index 0000000000..53705d676d --- /dev/null +++ b/dwds_webdev_integration_test/test/integration/build_daemon/instances/record_inspection_amd_test.dart @@ -0,0 +1,37 @@ +// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +@Tags(['daily']) +@TestOn('vm') +@Timeout(Duration(minutes: 2)) +library; + +import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/record_inspection.dart'; +import 'package:dwds_test_common/test_sdk_configuration.dart'; +import 'package:test/test.dart'; + +import '../../fixtures/build_daemon_context.dart'; + +void main() { + // Enable verbose logging for debugging. + const debug = false; + + for (final canaryFeatures in [false, true]) { + group('canary: $canaryFeatures | Build Daemon |', () { + final provider = TestSdkConfigurationProvider( + verbose: debug, + canaryFeatures: canaryFeatures, + ddcModuleFormat: ModuleFormat.amd, + ); + tearDownAll(provider.dispose); + + runTests( + provider: provider, + contextFactory: BuildDaemonTestContext.new, + canaryFeatures: canaryFeatures, + ); + }); + } +} diff --git a/dwds_webdev_integration_test/test/integration/build_daemon/instances/record_inspection_ddc_library_bundle_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/instances/record_inspection_ddc_library_bundle_test.dart new file mode 100644 index 0000000000..db088ddb72 --- /dev/null +++ b/dwds_webdev_integration_test/test/integration/build_daemon/instances/record_inspection_ddc_library_bundle_test.dart @@ -0,0 +1,37 @@ +// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +@Tags(['daily']) +@TestOn('vm') +@Timeout(Duration(minutes: 2)) +library; + +import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/record_inspection.dart'; +import 'package:dwds_test_common/test_sdk_configuration.dart'; +import 'package:test/test.dart'; + +import '../../fixtures/build_daemon_context.dart'; + +void main() { + // Enable verbose logging for debugging. + const debug = false; + + for (final canaryFeatures in [true]) { + group('canary: $canaryFeatures | Build Daemon |', () { + final provider = TestSdkConfigurationProvider( + verbose: debug, + canaryFeatures: canaryFeatures, + ddcModuleFormat: ModuleFormat.ddc, + ); + tearDownAll(provider.dispose); + + runTests( + provider: provider, + contextFactory: BuildDaemonTestContext.new, + canaryFeatures: canaryFeatures, + ); + }); + } +} diff --git a/dwds_webdev_integration_test/test/integration/build_daemon/instances/record_type_inspection_amd_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/instances/record_type_inspection_amd_test.dart new file mode 100644 index 0000000000..bc9e570556 --- /dev/null +++ b/dwds_webdev_integration_test/test/integration/build_daemon/instances/record_type_inspection_amd_test.dart @@ -0,0 +1,37 @@ +// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +@Tags(['daily']) +@TestOn('vm') +@Timeout(Duration(minutes: 2)) +library; + +import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/record_type_inspection.dart'; +import 'package:dwds_test_common/test_sdk_configuration.dart'; +import 'package:test/test.dart'; + +import '../../fixtures/build_daemon_context.dart'; + +void main() { + // Enable verbose logging for debugging. + const debug = false; + + for (final canaryFeatures in [false, true]) { + group('canary: $canaryFeatures | Build Daemon |', () { + final provider = TestSdkConfigurationProvider( + verbose: debug, + canaryFeatures: canaryFeatures, + ddcModuleFormat: ModuleFormat.amd, + ); + tearDownAll(provider.dispose); + + runTests( + provider: provider, + contextFactory: BuildDaemonTestContext.new, + canaryFeatures: canaryFeatures, + ); + }); + } +} diff --git a/dwds_webdev_integration_test/test/integration/build_daemon/instances/record_type_inspection_ddc_library_bundle_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/instances/record_type_inspection_ddc_library_bundle_test.dart new file mode 100644 index 0000000000..5d04764d7a --- /dev/null +++ b/dwds_webdev_integration_test/test/integration/build_daemon/instances/record_type_inspection_ddc_library_bundle_test.dart @@ -0,0 +1,37 @@ +// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +@Tags(['daily']) +@TestOn('vm') +@Timeout(Duration(minutes: 2)) +library; + +import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/record_type_inspection.dart'; +import 'package:dwds_test_common/test_sdk_configuration.dart'; +import 'package:test/test.dart'; + +import '../../fixtures/build_daemon_context.dart'; + +void main() { + // Enable verbose logging for debugging. + const debug = false; + + for (final canaryFeatures in [true]) { + group('canary: $canaryFeatures | Build Daemon |', () { + final provider = TestSdkConfigurationProvider( + verbose: debug, + canaryFeatures: canaryFeatures, + ddcModuleFormat: ModuleFormat.ddc, + ); + tearDownAll(provider.dispose); + + runTests( + provider: provider, + contextFactory: BuildDaemonTestContext.new, + canaryFeatures: canaryFeatures, + ); + }); + } +} diff --git a/dwds_webdev_integration_test/test/integration/build_daemon/instances/type_inspection_amd_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/instances/type_inspection_amd_test.dart new file mode 100644 index 0000000000..a1415485a9 --- /dev/null +++ b/dwds_webdev_integration_test/test/integration/build_daemon/instances/type_inspection_amd_test.dart @@ -0,0 +1,37 @@ +// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +@Tags(['daily']) +@TestOn('vm') +@Timeout(Duration(minutes: 2)) +library; + +import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/type_inspection.dart'; +import 'package:dwds_test_common/test_sdk_configuration.dart'; +import 'package:test/test.dart'; + +import '../../fixtures/build_daemon_context.dart'; + +void main() { + // Enable verbose logging for debugging. + const debug = false; + + for (final canaryFeatures in [false, true]) { + group('canary: $canaryFeatures | Build Daemon |', () { + final provider = TestSdkConfigurationProvider( + verbose: debug, + canaryFeatures: canaryFeatures, + ddcModuleFormat: ModuleFormat.amd, + ); + tearDownAll(provider.dispose); + + runTests( + provider: provider, + contextFactory: BuildDaemonTestContext.new, + canaryFeatures: canaryFeatures, + ); + }); + } +} diff --git a/dwds_webdev_integration_test/test/integration/build_daemon/instances/type_inspection_ddc_library_bundle_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/instances/type_inspection_ddc_library_bundle_test.dart new file mode 100644 index 0000000000..377ef4cefb --- /dev/null +++ b/dwds_webdev_integration_test/test/integration/build_daemon/instances/type_inspection_ddc_library_bundle_test.dart @@ -0,0 +1,37 @@ +// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +@Tags(['daily']) +@TestOn('vm') +@Timeout(Duration(minutes: 2)) +library; + +import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/type_inspection.dart'; +import 'package:dwds_test_common/test_sdk_configuration.dart'; +import 'package:test/test.dart'; + +import '../../fixtures/build_daemon_context.dart'; + +void main() { + // Enable verbose logging for debugging. + const debug = false; + + for (final canaryFeatures in [true]) { + group('canary: $canaryFeatures | Build Daemon |', () { + final provider = TestSdkConfigurationProvider( + verbose: debug, + canaryFeatures: canaryFeatures, + ddcModuleFormat: ModuleFormat.ddc, + ); + tearDownAll(provider.dispose); + + runTests( + provider: provider, + contextFactory: BuildDaemonTestContext.new, + canaryFeatures: canaryFeatures, + ); + }); + } +} diff --git a/dwds/test/integration/variable_scope_amd_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/listviews_test.dart similarity index 65% rename from dwds/test/integration/variable_scope_amd_test.dart rename to dwds_webdev_integration_test/test/integration/build_daemon/listviews_test.dart index f4d562f87a..90e7b14827 100644 --- a/dwds/test/integration/variable_scope_amd_test.dart +++ b/dwds_webdev_integration_test/test/integration/build_daemon/listviews_test.dart @@ -6,17 +6,20 @@ @Timeout(Duration(minutes: 2)) library; +import 'package:dwds_test_common/integration/listviews.dart'; import 'package:dwds_test_common/test_sdk_configuration.dart'; import 'package:test/test.dart'; -import 'variable_scope_common.dart'; +import '../fixtures/build_daemon_context.dart'; void main() { - // set to true for debug logging. + // Enable verbose logging for debugging. const debug = false; final provider = TestSdkConfigurationProvider(verbose: debug); tearDownAll(provider.dispose); - testAll(provider: provider); + group('Build Daemon |', () { + testAll(provider: provider, contextFactory: BuildDaemonTestContext.new); + }); } diff --git a/dwds_webdev_integration_test/test/integration/build_daemon/load_strategy_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/load_strategy_test.dart new file mode 100644 index 0000000000..3123c67cc6 --- /dev/null +++ b/dwds_webdev_integration_test/test/integration/build_daemon/load_strategy_test.dart @@ -0,0 +1,25 @@ +// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +@TestOn('vm') +@Timeout(Duration(minutes: 1)) +library; + +import 'package:dwds_test_common/integration/load_strategy.dart'; +import 'package:dwds_test_common/test_sdk_configuration.dart'; +import 'package:test/test.dart'; + +import '../fixtures/build_daemon_context.dart'; + +void main() { + // Enable verbose logging for debugging. + const debug = false; + + final provider = TestSdkConfigurationProvider(verbose: debug); + tearDownAll(provider.dispose); + + group('Build Daemon |', () { + testAll(provider: provider, contextFactory: BuildDaemonTestContext.new); + }); +} diff --git a/dwds_webdev_integration_test/test/integration/build_daemon/parts_evaluate/parts_evaluate_amd_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/parts_evaluate/parts_evaluate_amd_test.dart new file mode 100644 index 0000000000..0d6341d946 --- /dev/null +++ b/dwds_webdev_integration_test/test/integration/build_daemon/parts_evaluate/parts_evaluate_amd_test.dart @@ -0,0 +1,30 @@ +// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +@Tags(['daily']) +@TestOn('vm') +@Timeout(Duration(minutes: 5)) +library; + +import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/evaluate_parts.dart'; +import 'package:dwds_test_common/test_sdk_configuration.dart'; +import 'package:test/test.dart'; + +import '../../fixtures/build_daemon_context.dart'; + +void main() { + // Enable verbose logging for debugging. + const debug = false; + + final provider = TestSdkConfigurationProvider( + verbose: debug, + ddcModuleFormat: ModuleFormat.amd, + ); + tearDownAll(provider.dispose); + + group('Build Daemon |', () { + testAll(provider: provider, contextFactory: BuildDaemonTestContext.new); + }); +} diff --git a/dwds/test/integration/hot_reload_ddc_library_bundle_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/parts_evaluate/parts_evaluate_ddc_library_bundle_test.dart similarity index 68% rename from dwds/test/integration/hot_reload_ddc_library_bundle_test.dart rename to dwds_webdev_integration_test/test/integration/build_daemon/parts_evaluate/parts_evaluate_ddc_library_bundle_test.dart index ba5923935f..eb08b1556a 100644 --- a/dwds/test/integration/hot_reload_ddc_library_bundle_test.dart +++ b/dwds_webdev_integration_test/test/integration/build_daemon/parts_evaluate/parts_evaluate_ddc_library_bundle_test.dart @@ -1,4 +1,4 @@ -// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file +// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. @@ -8,27 +8,24 @@ library; import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/evaluate_parts.dart'; import 'package:dwds_test_common/test_sdk_configuration.dart'; import 'package:test/test.dart'; -import 'fixtures/context.dart'; -import 'hot_reload_common.dart'; +import '../../fixtures/build_daemon_context.dart'; void main() { // Enable verbose logging for debugging. const debug = false; + final provider = TestSdkConfigurationProvider( verbose: debug, - canaryFeatures: true, ddcModuleFormat: ModuleFormat.ddc, + canaryFeatures: true, ); - tearDownAll(provider.dispose); - group('Frontend Server', () { - runTests( - provider: provider, - compilationMode: CompilationMode.frontendServer, - ); + group('Build Daemon |', () { + testAll(provider: provider, contextFactory: BuildDaemonTestContext.new); }); } diff --git a/dwds/test/integration/readers/proxy_server_asset_reader_amd_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/readers/proxy_server_asset_reader_amd_test.dart similarity index 97% rename from dwds/test/integration/readers/proxy_server_asset_reader_amd_test.dart rename to dwds_webdev_integration_test/test/integration/build_daemon/readers/proxy_server_asset_reader_amd_test.dart index e7d2d05592..1e80b2f023 100644 --- a/dwds/test/integration/readers/proxy_server_asset_reader_amd_test.dart +++ b/dwds_webdev_integration_test/test/integration/build_daemon/readers/proxy_server_asset_reader_amd_test.dart @@ -2,6 +2,7 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +@TestOn('vm') @Timeout(Duration(minutes: 2)) library; diff --git a/dwds/test/integration/readers/proxy_server_asset_reader_common.dart b/dwds_webdev_integration_test/test/integration/build_daemon/readers/proxy_server_asset_reader_common.dart similarity index 87% rename from dwds/test/integration/readers/proxy_server_asset_reader_common.dart rename to dwds_webdev_integration_test/test/integration/build_daemon/readers/proxy_server_asset_reader_common.dart index b1b04f7930..a4c970f024 100644 --- a/dwds/test/integration/readers/proxy_server_asset_reader_common.dart +++ b/dwds_webdev_integration_test/test/integration/build_daemon/readers/proxy_server_asset_reader_common.dart @@ -3,16 +3,16 @@ // BSD-style license that can be found in the LICENSE file. import 'package:dwds/src/readers/proxy_server_asset_reader.dart'; +import 'package:dwds_test_common/fixtures/project.dart'; +import 'package:dwds_test_common/fixtures/utilities.dart'; import 'package:dwds_test_common/test_sdk_configuration.dart'; import 'package:test/test.dart'; -import '../fixtures/context.dart'; -import '../fixtures/project.dart'; -import '../fixtures/utilities.dart'; +import '../../fixtures/build_daemon_context.dart'; void testAll({required TestSdkConfigurationProvider provider}) { group('ProxyServerAssetReader', () { - final context = TestContext(TestProject.test, provider); + final context = BuildDaemonTestContext(TestProject.test, provider); late ProxyServerAssetReader assetReader; setUpAll(() async { diff --git a/dwds/test/integration/readers/proxy_server_asset_reader_ddc_library_bundle_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/readers/proxy_server_asset_reader_ddc_library_bundle_test.dart similarity index 97% rename from dwds/test/integration/readers/proxy_server_asset_reader_ddc_library_bundle_test.dart rename to dwds_webdev_integration_test/test/integration/build_daemon/readers/proxy_server_asset_reader_ddc_library_bundle_test.dart index ee42cfd2d0..1dec0c9c4d 100644 --- a/dwds/test/integration/readers/proxy_server_asset_reader_ddc_library_bundle_test.dart +++ b/dwds_webdev_integration_test/test/integration/build_daemon/readers/proxy_server_asset_reader_ddc_library_bundle_test.dart @@ -2,6 +2,7 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +@TestOn('vm') @Timeout(Duration(minutes: 2)) library; diff --git a/dwds/test/integration/handlers/asset_handler_amd_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/refresh_amd_test.dart similarity index 65% rename from dwds/test/integration/handlers/asset_handler_amd_test.dart rename to dwds_webdev_integration_test/test/integration/build_daemon/refresh_amd_test.dart index c5d84ba150..c56f7c5c89 100644 --- a/dwds/test/integration/handlers/asset_handler_amd_test.dart +++ b/dwds_webdev_integration_test/test/integration/build_daemon/refresh_amd_test.dart @@ -2,20 +2,26 @@ // 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. +@TestOn('vm') @Timeout(Duration(minutes: 2)) library; import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/refresh.dart'; import 'package:dwds_test_common/test_sdk_configuration.dart'; import 'package:test/test.dart'; -import 'asset_handler_common.dart'; +import '../fixtures/build_daemon_context.dart'; void main() { + // Enable verbose logging for debugging. + const debug = false; + final provider = TestSdkConfigurationProvider( + verbose: debug, ddcModuleFormat: ModuleFormat.amd, ); tearDownAll(provider.dispose); - testAll(provider: provider); + testAll(provider: provider, contextFactory: BuildDaemonTestContext.new); } diff --git a/dwds/test/integration/refresh_ddc_library_bundle_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/refresh_ddc_library_bundle_test.dart similarity index 75% rename from dwds/test/integration/refresh_ddc_library_bundle_test.dart rename to dwds_webdev_integration_test/test/integration/build_daemon/refresh_ddc_library_bundle_test.dart index 6820f6421b..df699e90c1 100644 --- a/dwds/test/integration/refresh_ddc_library_bundle_test.dart +++ b/dwds_webdev_integration_test/test/integration/build_daemon/refresh_ddc_library_bundle_test.dart @@ -2,29 +2,27 @@ // 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. -/// Tests that require a fresh context to run, and can interfere with other -/// tests. @TestOn('vm') @Timeout(Duration(minutes: 2)) library; import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/refresh.dart'; import 'package:dwds_test_common/test_sdk_configuration.dart'; import 'package:test/test.dart'; -import 'refresh_common.dart'; +import '../fixtures/build_daemon_context.dart'; void main() { // Enable verbose logging for debugging. const debug = false; - final canary = true; final provider = TestSdkConfigurationProvider( verbose: debug, - canaryFeatures: canary, ddcModuleFormat: ModuleFormat.ddc, + canaryFeatures: true, ); tearDownAll(provider.dispose); - testAll(provider: provider); + testAll(provider: provider, contextFactory: BuildDaemonTestContext.new); } diff --git a/dwds/test/integration/run_request_amd_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/run_request_amd_test.dart similarity index 75% rename from dwds/test/integration/run_request_amd_test.dart rename to dwds_webdev_integration_test/test/integration/build_daemon/run_request_amd_test.dart index 4f1edd356e..5db8b44899 100644 --- a/dwds/test/integration/run_request_amd_test.dart +++ b/dwds_webdev_integration_test/test/integration/build_daemon/run_request_amd_test.dart @@ -2,14 +2,16 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +@TestOn('vm') @Timeout(Duration(minutes: 2)) library; import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/run_request.dart'; import 'package:dwds_test_common/test_sdk_configuration.dart'; import 'package:test/test.dart'; -import 'run_request_common.dart'; +import '../fixtures/build_daemon_context.dart'; void main() { // Enable verbose logging for debugging. @@ -21,5 +23,5 @@ void main() { ); tearDownAll(provider.dispose); - testAll(provider: provider); + testAll(provider: provider, contextFactory: BuildDaemonTestContext.new); } diff --git a/dwds/test/integration/run_request_ddc_library_bundle_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/run_request_ddc_library_bundle_test.dart similarity index 76% rename from dwds/test/integration/run_request_ddc_library_bundle_test.dart rename to dwds_webdev_integration_test/test/integration/build_daemon/run_request_ddc_library_bundle_test.dart index 4e51bb3b5d..76166367dc 100644 --- a/dwds/test/integration/run_request_ddc_library_bundle_test.dart +++ b/dwds_webdev_integration_test/test/integration/build_daemon/run_request_ddc_library_bundle_test.dart @@ -2,14 +2,16 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +@TestOn('vm') @Timeout(Duration(minutes: 2)) library; import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/run_request.dart'; import 'package:dwds_test_common/test_sdk_configuration.dart'; import 'package:test/test.dart'; -import 'run_request_common.dart'; +import '../fixtures/build_daemon_context.dart'; void main() { // Enable verbose logging for debugging. @@ -22,5 +24,5 @@ void main() { ); tearDownAll(provider.dispose); - testAll(provider: provider); + testAll(provider: provider, contextFactory: BuildDaemonTestContext.new); } diff --git a/dwds/test/integration/screenshot_amd_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/screenshot_amd_test.dart similarity index 65% rename from dwds/test/integration/screenshot_amd_test.dart rename to dwds_webdev_integration_test/test/integration/build_daemon/screenshot_amd_test.dart index 771e205bd3..d5aa7b9592 100644 --- a/dwds/test/integration/screenshot_amd_test.dart +++ b/dwds_webdev_integration_test/test/integration/build_daemon/screenshot_amd_test.dart @@ -2,20 +2,26 @@ // 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. +@TestOn('vm') @Timeout(Duration(minutes: 2)) library; import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/screenshot.dart'; import 'package:dwds_test_common/test_sdk_configuration.dart'; import 'package:test/test.dart'; -import 'screenshot_common.dart'; +import '../fixtures/build_daemon_context.dart'; void main() { + // Enable verbose logging for debugging. + const debug = false; + final provider = TestSdkConfigurationProvider( + verbose: debug, ddcModuleFormat: ModuleFormat.amd, ); tearDownAll(provider.dispose); - testAll(provider: provider); + testAll(provider: provider, contextFactory: BuildDaemonTestContext.new); } diff --git a/dwds/test/integration/debug_service_ddc_library_bundle_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/screenshot_ddc_library_bundle_test.dart similarity index 75% rename from dwds/test/integration/debug_service_ddc_library_bundle_test.dart rename to dwds_webdev_integration_test/test/integration/build_daemon/screenshot_ddc_library_bundle_test.dart index 06fe831e68..0d7e69a6b8 100644 --- a/dwds/test/integration/debug_service_ddc_library_bundle_test.dart +++ b/dwds_webdev_integration_test/test/integration/build_daemon/screenshot_ddc_library_bundle_test.dart @@ -7,21 +7,22 @@ library; import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/screenshot.dart'; import 'package:dwds_test_common/test_sdk_configuration.dart'; import 'package:test/test.dart'; -import 'debug_service_common.dart'; +import '../fixtures/build_daemon_context.dart'; void main() { // Enable verbose logging for debugging. const debug = false; - final canary = true; + final provider = TestSdkConfigurationProvider( verbose: debug, - canaryFeatures: canary, ddcModuleFormat: ModuleFormat.ddc, + canaryFeatures: true, ); tearDownAll(provider.dispose); - testAll(provider: provider); + testAll(provider: provider, contextFactory: BuildDaemonTestContext.new); } diff --git a/dwds_webdev_integration_test/test/integration/build_daemon/variable_scope_amd_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/variable_scope_amd_test.dart new file mode 100644 index 0000000000..cd61b46aed --- /dev/null +++ b/dwds_webdev_integration_test/test/integration/build_daemon/variable_scope_amd_test.dart @@ -0,0 +1,27 @@ +// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +@TestOn('vm') +@Timeout(Duration(minutes: 2)) +library; + +import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/variable_scope.dart'; +import 'package:dwds_test_common/test_sdk_configuration.dart'; +import 'package:test/test.dart'; + +import '../fixtures/build_daemon_context.dart'; + +void main() { + // Enable verbose logging for debugging. + const debug = false; + + final provider = TestSdkConfigurationProvider( + verbose: debug, + ddcModuleFormat: ModuleFormat.amd, + ); + tearDownAll(provider.dispose); + + testAll(provider: provider, contextFactory: BuildDaemonTestContext.new); +} diff --git a/dwds/test/integration/variable_scope_ddc_library_bundle_test.dart b/dwds_webdev_integration_test/test/integration/build_daemon/variable_scope_ddc_library_bundle_test.dart similarity index 75% rename from dwds/test/integration/variable_scope_ddc_library_bundle_test.dart rename to dwds_webdev_integration_test/test/integration/build_daemon/variable_scope_ddc_library_bundle_test.dart index e5a4963ef7..0dec68e44a 100644 --- a/dwds/test/integration/variable_scope_ddc_library_bundle_test.dart +++ b/dwds_webdev_integration_test/test/integration/build_daemon/variable_scope_ddc_library_bundle_test.dart @@ -7,22 +7,22 @@ library; import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/variable_scope.dart'; import 'package:dwds_test_common/test_sdk_configuration.dart'; import 'package:test/test.dart'; -import 'variable_scope_common.dart'; +import '../fixtures/build_daemon_context.dart'; void main() { // Enable verbose logging for debugging. const debug = false; - final canary = true; final provider = TestSdkConfigurationProvider( verbose: debug, - canaryFeatures: canary, ddcModuleFormat: ModuleFormat.ddc, + canaryFeatures: true, ); tearDownAll(provider.dispose); - testAll(provider: provider); + testAll(provider: provider, contextFactory: BuildDaemonTestContext.new); } diff --git a/dwds/test/integration/expression_compiler_service_amd_test.dart b/dwds_webdev_integration_test/test/integration/expression_compiler_service_amd_test.dart similarity index 87% rename from dwds/test/integration/expression_compiler_service_amd_test.dart rename to dwds_webdev_integration_test/test/integration/expression_compiler_service_amd_test.dart index 19c8bdc3ae..e4f50a7830 100644 --- a/dwds/test/integration/expression_compiler_service_amd_test.dart +++ b/dwds_webdev_integration_test/test/integration/expression_compiler_service_amd_test.dart @@ -8,10 +8,9 @@ library; import 'package:dwds/expression_compiler.dart'; +import 'package:dwds_test_common/integration/expression_compiler_service.dart'; import 'package:test/test.dart'; -import 'expression_compiler_service_common.dart'; - void main() async { testAll( compilerOptions: CompilerOptions( diff --git a/dwds_webdev_integration_test/test/integration/fixtures/build_daemon_context.dart b/dwds_webdev_integration_test/test/integration/fixtures/build_daemon_context.dart new file mode 100644 index 0000000000..feabb5f0ec --- /dev/null +++ b/dwds_webdev_integration_test/test/integration/fixtures/build_daemon_context.dart @@ -0,0 +1,284 @@ +// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:async'; +import 'dart:io'; + +import 'package:build_daemon/client.dart'; +import 'package:build_daemon/constants.dart'; +import 'package:build_daemon/data/build_status.dart' as daemon; +import 'package:build_daemon/data/build_target.dart'; +import 'package:dwds/asset_reader.dart'; +import 'package:dwds/data/build_result.dart'; +import 'package:dwds/expression_compiler.dart'; +import 'package:dwds/src/loaders/build_runner_strategy_provider.dart'; +import 'package:dwds/src/loaders/strategy.dart'; +import 'package:dwds/src/readers/proxy_server_asset_reader.dart'; +import 'package:dwds/src/services/expression_compiler_service.dart'; +import 'package:dwds_test_common/fixtures/context.dart'; +import 'package:dwds_test_common/fixtures/utilities.dart'; +import 'package:logging/logging.dart' as logging; +import 'package:shelf/shelf.dart'; +import 'package:shelf_proxy/shelf_proxy.dart'; + +/// A [TestContext] that builds and serves the test app with `build_runner`, +/// through the build daemon. +class BuildDaemonTestContext extends TestContext { + BuildDaemonClient? _daemonClient; + ExpressionCompilerService? _expressionCompilerService; + AssetReader? _assetReader; + Handler? _assetHandler; + LoadStrategy? _loadStrategy; + Stream? _buildResults; + + final _logger = logging.Logger('BuildDaemonContext'); + + BuildDaemonTestContext(super.project, super.sdkConfigurationProvider) + : super.protected(); + + @override + String get appUrlPath => project.filePathToServe; + + @override + bool get usesBuildDaemon => true; + + BuildDaemonClient get daemonClient => _daemonClient!; + + @override + AssetReader get assetReader => _assetReader!; + + @override + Handler get assetHandler => _assetHandler!; + + @override + LoadStrategy get loadStrategy => _loadStrategy!; + + @override + ExpressionCompiler? get expressionCompiler => _expressionCompilerService; + + @override + Stream get buildResults => _buildResults!; + + @override + Future modeSetUp( + TestSettings testSettings, + TestDebugSettings debugSettings, + TestAppMetadata appMetadata, + Uri reloadedSourcesUri, + ) async { + final buildSettings = TestBuildSettings( + appEntrypoint: project.dartEntryFilePackageUri, + canaryFeatures: testSettings.canaryFeatures, + isFlutterApp: testSettings.isFlutterApp, + experiments: testSettings.experiments, + ); + + _daemonClient = await _connectDaemonClient(testSettings, buildSettings); + daemonClient + ..registerBuildTarget( + DefaultBuildTarget((b) => b..target = project.directoryToServe), + ) + ..startBuild(); + _buildResults = _toDwdsBuildResults(daemonClient.buildResults); + + await waitForSuccessfulBuild(); + + final assetServerPort = _daemonAssetServerPort(); + _assetHandler = _createAssetHandler( + assetServerPort, + serveReloadedSources: _usesDdcLibraryBundle(testSettings), + ); + _assetReader = ProxyServerAssetReader( + assetServerPort, + root: project.directoryToServe, + ); + + if (testSettings.enableExpressionEvaluation) { + _expressionCompilerService = ExpressionCompilerService( + 'localhost', + port, + verbose: testSettings.verboseCompiler, + sdkConfigurationProvider: sdkConfigurationProvider, + ); + } + + _loadStrategy = _createLoadStrategy( + testSettings, + buildSettings, + reloadedSourcesUri, + ); + } + + @override + Future modeTearDown() async { + await _daemonClient?.close(); + await _expressionCompilerService?.stop(); + _daemonClient = null; + _expressionCompilerService = null; + _assetReader = null; + _assetHandler = null; + _loadStrategy = null; + _buildResults = null; + } + + @override + Future waitForSuccessfulBuild({ + Duration? timeout, + bool propagateToBrowser = false, + bool allowFailure = false, + }) async { + final status = await _targetBuildStatuses(daemonClient.buildResults) + .firstWhere( + (status) => + status == daemon.BuildStatus.succeeded || + (allowFailure && status == daemon.BuildStatus.failed), + ) + .timeout(timeout ?? const Duration(seconds: 60)); + lastBuildFailed = status == daemon.BuildStatus.failed; + + if (propagateToBrowser) { + // Allow change to propagate to the browser. + // Windows, or at least Travis on Windows, seems to need more time. + // TODO: Wait for an explicit finish signal instead of adding this delay. + final delay = Platform.isWindows + ? const Duration(seconds: 5) + : const Duration(seconds: 2); + await Future.delayed(delay); + } + } + + /// Starts a build daemon for the test project and connects to it. + Future _connectDaemonClient( + TestSettings testSettings, + TestBuildSettings buildSettings, + ) => BuildDaemonClient.connect( + project.absolutePackageDirectory, + [ + sdkConfigurationProvider.sdkLayout.dartPath, + 'run', + 'build_runner', + 'daemon', + ..._buildRunnerOptions(testSettings, buildSettings), + ], + logHandler: (log) { + final record = log.toLogRecord(); + final name = record.loggerName == '' ? '' : '${record.loggerName}: '; + _logger.log( + record.level, + '$name${record.message}', + record.error, + record.stackTrace, + ); + }, + ); + + /// The `build_runner daemon` options matching [testSettings]. + List _buildRunnerOptions( + TestSettings testSettings, + TestBuildSettings buildSettings, + ) => [ + if (testSettings.enableExpressionEvaluation) ...[ + '--define', + 'build_web_compilers|ddc=generate-full-dill=true', + ], + for (final experiment in buildSettings.experiments) + '--enable-experiment=$experiment', + if (buildSettings.canaryFeatures) ...[ + '--define', + 'build_web_compilers|ddc=canary=true', + '--define', + 'build_web_compilers|sdk_js=canary=true', + ], + if (testSettings.moduleFormat == ModuleFormat.ddc) ...[ + '--define', + 'build_web_compilers|ddc=ddc-library-bundle=true', + '--define', + 'build_web_compilers|sdk_js=ddc-library-bundle=true', + '--define', + 'build_web_compilers|entrypoint=ddc-library-bundle=true', + '--define', + 'build_web_compilers|entrypoint_marker=ddc-library-bundle=true', + ], + '--verbose', + ]; + + /// Returns the port of the build daemon's asset server. + int _daemonAssetServerPort() { + final portFile = File( + '${daemonWorkspace(project.absolutePackageDirectory)}' + '/.asset_server_port', + ); + if (!portFile.existsSync()) { + throw StateError('Unable to read daemon asset port file.'); + } + return int.parse(portFile.readAsStringSync()); + } + + /// Creates a handler that proxies asset requests to the build daemon's + /// asset server. + /// + /// If [serveReloadedSources] is true, requests for the reloaded sources + /// manifest are served by this context instead. + Handler _createAssetHandler( + int assetServerPort, { + required bool serveReloadedSources, + }) { + final proxy = proxyHandler( + 'http://localhost:$assetServerPort/${project.directoryToServe}/', + client: client, + ); + return serveReloadedSources ? handleReloadedSources(proxy) : proxy; + } + + LoadStrategy _createLoadStrategy( + TestSettings testSettings, + TestBuildSettings buildSettings, + Uri reloadedSourcesUri, + ) => switch ((testSettings.moduleFormat, buildSettings.canaryFeatures)) { + (ModuleFormat.ddc, true) => BuildRunnerDdcLibraryBundleStrategyProvider( + testSettings.reloadConfiguration, + assetReader, + buildSettings, + reloadedSourcesUri: reloadedSourcesUri, + ).strategy, + (ModuleFormat.ddc, false) => throw UnsupportedError( + 'Unsupported DDC configuration: build daemon + canary (false) ' + '+ DDC module format ${testSettings.moduleFormat.name}.', + ), + _ => BuildRunnerRequireStrategyProvider( + testSettings.reloadConfiguration, + assetReader, + buildSettings, + ).strategy, + }; + + /// Converts build daemon results into the [BuildResult]s DWDS expects, + /// keeping only results for the target being served. + Stream _toDwdsBuildResults( + Stream results, + ) => _targetBuildStatuses(results).map( + (status) => switch (status) { + daemon.BuildStatus.started => BuildResult(status: BuildStatus.started), + daemon.BuildStatus.failed => BuildResult(status: BuildStatus.failed), + daemon.BuildStatus.succeeded => BuildResult( + status: BuildStatus.succeeded, + ), + _ => throw StateError('Unexpected daemon build status: $status'), + }, + ); + + /// The build statuses for the target being served. + Stream _targetBuildStatuses( + Stream results, + ) => results.expand( + (results) => [ + for (final result in results.results) + if (result.target == project.directoryToServe) result.status, + ], + ); + + static bool _usesDdcLibraryBundle(TestSettings testSettings) => + testSettings.moduleFormat == ModuleFormat.ddc && + testSettings.canaryFeatures; +} diff --git a/tool/ci.sh b/tool/ci.sh index 7e7595854f..c123be826a 100755 --- a/tool/ci.sh +++ b/tool/ci.sh @@ -80,34 +80,26 @@ for PKG in ${PKGS}; do dart format --output=none --set-exit-if-changed . || EXIT_CODE=$? ;; test_0) - echo 'dart test test/build/ensure_version_test.dart' - dart test test/build/ensure_version_test.dart || EXIT_CODE=$? - ;; - test_1) echo 'dart test --tags=extension' dart test --tags=extension || EXIT_CODE=$? ;; - test_2) + test_1) echo 'dart test --total-shards 3 --shard-index 0 --exclude-tags=extension' dart test --total-shards 3 --shard-index 0 --exclude-tags=extension || EXIT_CODE=$? ;; - test_3) + test_2) echo 'dart test --total-shards 3 --shard-index 1 --exclude-tags=extension' dart test --total-shards 3 --shard-index 1 --exclude-tags=extension || EXIT_CODE=$? ;; - test_4) + test_3) echo 'dart test --total-shards 3 --shard-index 2 --exclude-tags=extension' dart test --total-shards 3 --shard-index 2 --exclude-tags=extension || EXIT_CODE=$? ;; - test_5) + test_4) echo 'dart test -j 1' dart test -j 1 || EXIT_CODE=$? ;; - test_6) - echo 'dart test --exclude-tags=release' - dart test --exclude-tags=release || EXIT_CODE=$? - ;; - test_7) + test_5) echo 'dart test test/build/ensure_build_test.dart' dart test test/build/ensure_build_test.dart || EXIT_CODE=$? ;; diff --git a/webdev/pubspec.yaml b/webdev/pubspec.yaml index 2b82ca2310..7a29a5e5ad 100644 --- a/webdev/pubspec.yaml +++ b/webdev/pubspec.yaml @@ -47,8 +47,8 @@ dev_dependencies: build_verify: ^3.0.0 build_version: ^2.1.1 test: ^1.21.1 - dwds_test_common: - path: ../dwds_test_common + # Overridden below to the copy in the Dart SDK. + dwds_test_common: any test_descriptor: ^2.0.0 test_process: ^2.0.2 webdriver: ^3.0.0 diff --git a/webdev/test/e2e_common.dart b/webdev/test/e2e_common.dart index 51695e160f..9ecc087b5f 100644 --- a/webdev/test/e2e_common.dart +++ b/webdev/test/e2e_common.dart @@ -10,17 +10,14 @@ import 'dart:io'; import 'package:io/io.dart'; import 'package:logging/logging.dart'; -import 'package:path/path.dart' as p; import 'package:pub_semver/pub_semver.dart'; import 'package:test/test.dart'; import 'package:test_descriptor/test_descriptor.dart' as d; -import 'package:test_process/test_process.dart'; import 'package:vm_service/vm_service.dart'; import 'package:vm_service/vm_service_io.dart'; import 'package:webdev/src/logging.dart'; import 'package:webdev/src/pubspec.dart'; import 'package:webdev/src/serve/utils.dart'; -import 'package:webdev/src/util.dart'; import 'package:yaml/yaml.dart'; import 'daemon/utils.dart'; @@ -44,18 +41,7 @@ void e2eTests({required TestRunner testRunner}) { setUpAll(() async { configureLogWriter(debug); await testRunner.setUpAll(); - exampleDirectory = p.absolute( - p.join(p.current, '..', 'dwds_test_common', 'fixtures', '_webdev_smoke'), - ); - - final process = await TestProcess.start( - dartPath, - ['pub', 'upgrade'], - workingDirectory: exampleDirectory, - environment: getPubEnvironment(), - ); - - await process.shouldExit(0); + exampleDirectory = await testRunner.prepareWorkspace(); await d .file('.dart_tool/package_config.json', isNotEmpty) @@ -71,9 +57,13 @@ void e2eTests({required TestRunner testRunner}) { ) as YamlMap; final webdevYaml = loadYaml(await File('pubspec.yaml').readAsString()) as YamlMap; + // The fixture lives in the Dart SDK's dwds_test_common, so its SDK + // constraint isn't kept in lockstep with webdev's. Require that it allows + // every SDK that webdev supports. expect( - smokeYaml['environment']['sdk'], - equals(webdevYaml['environment']['sdk']), + VersionConstraint.parse(smokeYaml['environment']['sdk']) + .allowsAll(VersionConstraint.parse(webdevYaml['environment']['sdk'])), + true, ); expect( buildRunnerConstraint.allowsAny( diff --git a/webdev/test/test_utils.dart b/webdev/test/test_utils.dart index c37cdba223..d03d11a40e 100644 --- a/webdev/test/test_utils.dart +++ b/webdev/test/test_utils.dart @@ -4,6 +4,7 @@ import 'dart:async'; import 'dart:io'; +import 'dart:isolate'; import 'package:dwds/expression_compiler.dart'; import 'package:dwds_test_common/test_sdk_configuration.dart'; @@ -122,9 +123,7 @@ class TestRunner { } Future prepareWorkspace() async { - final originalDirectory = p.absolute( - p.join(p.current, '..', 'dwds_test_common', 'fixtures', '_webdev_smoke'), - ); + final originalDirectory = _webdevSmokeFixturePath(); final tempDir = Directory.systemTemp.createTempSync('webdev_smoke_'); final exampleDirectory = tempDir.path; _copyCleanDirectory(Directory(originalDirectory), tempDir); @@ -167,3 +166,16 @@ Map getPubEnvironment() { return environment; } + +/// The path to the `_webdev_smoke` fixture in `package:dwds_test_common`. +String _webdevSmokeFixturePath() { + final utilitiesUri = Isolate.resolvePackageUriSync( + Uri.parse('package:dwds_test_common/utilities.dart'), + ); + if (utilitiesUri == null) { + throw StateError('Unable to resolve package:dwds_test_common.'); + } + // Strip `lib/utilities.dart`. + final packageRoot = p.dirname(p.dirname(utilitiesUri.toFilePath())); + return p.join(packageRoot, 'fixtures', '_webdev_smoke'); +} diff --git a/webdev/test/tls_common.dart b/webdev/test/tls_common.dart index 6984ae6507..20be68679a 100644 --- a/webdev/test/tls_common.dart +++ b/webdev/test/tls_common.dart @@ -6,10 +6,8 @@ import 'dart:io'; import 'package:collection/collection.dart'; import 'package:logging/logging.dart'; -import 'package:path/path.dart' as p; import 'package:test/test.dart'; import 'package:test_descriptor/test_descriptor.dart' as d; -import 'package:test_process/test_process.dart'; import 'package:webdev/src/logging.dart'; import 'package:webdev/src/serve/utils.dart'; @@ -26,24 +24,7 @@ void tlsTests({required TestRunner testRunner}) { setUpAll(() async { configureLogWriter(debug); await testRunner.setUpAll(); - exampleDirectory = p.absolute( - p.join( - p.current, - '..', - 'dwds_test_common', - 'fixtures', - '_webdev_smoke', - ), - ); - - final process = await TestProcess.start( - 'dart', - ['pub', 'upgrade'], - workingDirectory: exampleDirectory, - environment: getPubEnvironment(), - ); - - await process.shouldExit(0); + exampleDirectory = await testRunner.prepareWorkspace(); await d .file('.dart_tool/package_config.json', isNotEmpty)